summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Bossart2025-07-11 16:51:25 +0000
committerNathan Bossart2025-07-11 16:51:25 +0000
commita4f126516e688736bfed332b44a0c221b8dc118a (patch)
treeb921beb43ae0acd7a8ce510896e2c6d1b06fd831
parentbb938e2c3c7a955090f8b68b5bf75d064f6a36a0 (diff)
Add option list to CHECKPOINT command.
This commit adds the boilerplate code for supporting a list of options in CHECKPOINT commands. No actual options are supported yet, but follow-up commits will add support for MODE and FLUSH_UNLOGGED. While at it, this commit refactors the code for executing CHECKPOINT commands to its own function since it's about to become significantly larger. Author: Christoph Berg <myon@debian.org> Reviewed-by: Fujii Masao <masao.fujii@oss.nttdata.com> Discussion: https://postgr.es/m/aDnaKTEf-0dLiEfz%40msg.df7cb.de
-rw-r--r--doc/src/sgml/ref/checkpoint.sgml11
-rw-r--r--src/backend/parser/gram.y7
-rw-r--r--src/backend/postmaster/checkpointer.c31
-rw-r--r--src/backend/tcop/utility.c12
-rw-r--r--src/bin/psql/tab-complete.in.c3
-rw-r--r--src/include/nodes/parsenodes.h1
-rw-r--r--src/include/postmaster/bgwriter.h2
-rw-r--r--src/test/regress/expected/stats.out6
-rw-r--r--src/test/regress/sql/stats.sql3
9 files changed, 64 insertions, 12 deletions
diff --git a/doc/src/sgml/ref/checkpoint.sgml b/doc/src/sgml/ref/checkpoint.sgml
index 10a433e4757..fad5e982d03 100644
--- a/doc/src/sgml/ref/checkpoint.sgml
+++ b/doc/src/sgml/ref/checkpoint.sgml
@@ -21,7 +21,9 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
-CHECKPOINT
+CHECKPOINT [ ( option [, ...] ) ]
+
+<phrase>where <replaceable class="parameter">option</replaceable> can be one of:</phrase>
</synopsis>
</refsynopsisdiv>
@@ -59,6 +61,13 @@ CHECKPOINT
</refsect1>
<refsect1>
+ <title>Parameters</title>
+
+ <para>
+ </para>
+ </refsect1>
+
+ <refsect1>
<title>Compatibility</title>
<para>
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 70a0d832a11..73345bb3c70 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -2034,6 +2034,13 @@ CheckPointStmt:
$$ = (Node *) n;
}
+ | CHECKPOINT '(' utility_option_list ')'
+ {
+ CheckPointStmt *n = makeNode(CheckPointStmt);
+
+ $$ = (Node *) n;
+ n->options = $3;
+ }
;
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index 0d8696bfb5e..dc01f2382f1 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -42,6 +42,7 @@
#include "access/xlog.h"
#include "access/xlog_internal.h"
#include "access/xlogrecovery.h"
+#include "catalog/pg_authid.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "pgstat.h"
@@ -61,6 +62,7 @@
#include "storage/shmem.h"
#include "storage/smgr.h"
#include "storage/spin.h"
+#include "utils/acl.h"
#include "utils/guc.h"
#include "utils/memutils.h"
#include "utils/resowner.h"
@@ -977,6 +979,35 @@ CheckpointerShmemInit(void)
}
/*
+ * ExecCheckpoint
+ * Primary entry point for manual CHECKPOINT commands
+ *
+ * This is mainly a wrapper for RequestCheckpoint().
+ */
+void
+ExecCheckpoint(ParseState *pstate, CheckPointStmt *stmt)
+{
+ foreach_ptr(DefElem, opt, stmt->options)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("unrecognized CHECKPOINT option \"%s\"", opt->defname),
+ parser_errposition(pstate, opt->location)));
+
+ if (!has_privs_of_role(GetUserId(), ROLE_PG_CHECKPOINT))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ /* translator: %s is name of an SQL command (e.g., CHECKPOINT) */
+ errmsg("permission denied to execute %s command",
+ "CHECKPOINT"),
+ errdetail("Only roles with privileges of the \"%s\" role may execute this command.",
+ "pg_checkpoint")));
+
+ RequestCheckpoint(CHECKPOINT_WAIT |
+ CHECKPOINT_FAST |
+ (RecoveryInProgress() ? 0 : CHECKPOINT_FORCE));
+}
+
+/*
* RequestCheckpoint
* Called in backend processes to request a checkpoint
*
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index a628da4b145..4c1faf5575c 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -943,17 +943,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
break;
case T_CheckPointStmt:
- if (!has_privs_of_role(GetUserId(), ROLE_PG_CHECKPOINT))
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- /* translator: %s is name of a SQL command, eg CHECKPOINT */
- errmsg("permission denied to execute %s command",
- "CHECKPOINT"),
- errdetail("Only roles with privileges of the \"%s\" role may execute this command.",
- "pg_checkpoint")));
-
- RequestCheckpoint(CHECKPOINT_FAST | CHECKPOINT_WAIT |
- (RecoveryInProgress() ? 0 : CHECKPOINT_FORCE));
+ ExecCheckpoint(pstate, (CheckPointStmt *) parsetree);
break;
/*
diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c
index 5ba45a0bcb3..089fe367d9f 100644
--- a/src/bin/psql/tab-complete.in.c
+++ b/src/bin/psql/tab-complete.in.c
@@ -3153,6 +3153,9 @@ match_previous_words(int pattern_id,
COMPLETE_WITH_VERSIONED_SCHEMA_QUERY(Query_for_list_of_procedures);
else if (Matches("CALL", MatchAny))
COMPLETE_WITH("(");
+/* CHECKPOINT */
+ else if (Matches("CHECKPOINT"))
+ COMPLETE_WITH("(");
/* CLOSE */
else if (Matches("CLOSE"))
COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_cursors,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 28e2e8dc0fd..86a236bd58b 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -4047,6 +4047,7 @@ typedef struct RefreshMatViewStmt
typedef struct CheckPointStmt
{
NodeTag type;
+ List *options; /* list of DefElem nodes */
} CheckPointStmt;
/* ----------------------
diff --git a/src/include/postmaster/bgwriter.h b/src/include/postmaster/bgwriter.h
index 800ecbfd13b..97001f4e7f6 100644
--- a/src/include/postmaster/bgwriter.h
+++ b/src/include/postmaster/bgwriter.h
@@ -15,6 +15,7 @@
#ifndef _BGWRITER_H
#define _BGWRITER_H
+#include "parser/parse_node.h"
#include "storage/block.h"
#include "storage/relfilelocator.h"
#include "storage/smgr.h"
@@ -30,6 +31,7 @@ extern PGDLLIMPORT double CheckPointCompletionTarget;
pg_noreturn extern void BackgroundWriterMain(const void *startup_data, size_t startup_data_len);
pg_noreturn extern void CheckpointerMain(const void *startup_data, size_t startup_data_len);
+extern void ExecCheckpoint(ParseState *pstate, CheckPointStmt *stmt);
extern void RequestCheckpoint(int flags);
extern void CheckpointWriteDelay(int flags, double progress);
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index 776f1ad0e53..9b865ae5f6c 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -926,6 +926,12 @@ DROP TABLE test_stats_temp;
-- Checkpoint twice: The checkpointer reports stats after reporting completion
-- of the checkpoint. But after a second checkpoint we'll see at least the
-- results of the first.
+--
+-- While at it, test checkpoint options.
+CHECKPOINT (WRONG);
+ERROR: unrecognized CHECKPOINT option "wrong"
+LINE 1: CHECKPOINT (WRONG);
+ ^
CHECKPOINT;
CHECKPOINT;
SELECT num_requested > :rqst_ckpts_before FROM pg_stat_checkpointer;
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index 232ab8db8fa..97b50926aa6 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -439,6 +439,9 @@ DROP TABLE test_stats_temp;
-- Checkpoint twice: The checkpointer reports stats after reporting completion
-- of the checkpoint. But after a second checkpoint we'll see at least the
-- results of the first.
+--
+-- While at it, test checkpoint options.
+CHECKPOINT (WRONG);
CHECKPOINT;
CHECKPOINT;