]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Add option list to CHECKPOINT command.
authorNathan Bossart <nathan@postgresql.org>
Fri, 11 Jul 2025 16:51:25 +0000 (11:51 -0500)
committerNathan Bossart <nathan@postgresql.org>
Fri, 11 Jul 2025 16:51:25 +0000 (11:51 -0500)
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

doc/src/sgml/ref/checkpoint.sgml
src/backend/parser/gram.y
src/backend/postmaster/checkpointer.c
src/backend/tcop/utility.c
src/bin/psql/tab-complete.in.c
src/include/nodes/parsenodes.h
src/include/postmaster/bgwriter.h
src/test/regress/expected/stats.out
src/test/regress/sql/stats.sql

index 10a433e47570b127209734b18ab352850e6232b1..fad5e982d03643849ca05b9737cd8bde1421a571 100644 (file)
@@ -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>
 
@@ -58,6 +60,13 @@ CHECKPOINT
   </para>
  </refsect1>
 
+ <refsect1>
+  <title>Parameters</title>
+
+  <para>
+  </para>
+ </refsect1>
+
  <refsect1>
   <title>Compatibility</title>
 
index 70a0d832a119c69962c83e99727d0bce24dee110..73345bb3c7045cdbaf0670e211ae14c8ee4d6f9c 100644 (file)
@@ -2034,6 +2034,13 @@ CheckPointStmt:
 
                                        $$ = (Node *) n;
                                }
+                       | CHECKPOINT '(' utility_option_list ')'
+                               {
+                                       CheckPointStmt *n = makeNode(CheckPointStmt);
+
+                                       $$ = (Node *) n;
+                                       n->options = $3;
+                               }
                ;
 
 
index 0d8696bfb5e3a2cdad3cb5cf6fbaef72b082e6e7..dc01f2382f18af43c116355d2412942fbadb66c8 100644 (file)
@@ -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"
@@ -976,6 +978,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
index a628da4b145ea0565fd0bc061768449e3cf2e43d..4c1faf5575c4d203904b3fe987857472840ae934 100644 (file)
@@ -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;
 
                        /*
index 5ba45a0bcb3afd88e8f5e21540d95c90dfe35ed5..089fe367d9f3bc15acb05480aa1ed624840349e9 100644 (file)
@@ -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,
index 28e2e8dc0fdaaaa0d54ad1a79a4bd6faa440de3a..86a236bd58b1abde2f7c053295777fac68ace651 100644 (file)
@@ -4047,6 +4047,7 @@ typedef struct RefreshMatViewStmt
 typedef struct CheckPointStmt
 {
        NodeTag         type;
+       List       *options;            /* list of DefElem nodes */
 } CheckPointStmt;
 
 /* ----------------------
index 800ecbfd13b318be381d73806ff1c94250a30b4e..97001f4e7f622eb1e97ad3373851ab5a7d6201df 100644 (file)
@@ -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);
 
index 776f1ad0e53477be1bea320609639d58773aef76..9b865ae5f6cc7c2ca0014d1d67be5a43832dd73a 100644 (file)
@@ -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;
index 232ab8db8fa8b210628471b5a3a52e96b9ab946c..97b50926aa67c45638edc388861e7b50074ff9b9 100644 (file)
@@ -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;