Skip to content

Commit

Permalink
[pgmoneta#5] SQL: CHECKPOINT
Browse files Browse the repository at this point in the history
  • Loading branch information
GuChad369 committed Jun 4, 2024
1 parent 5628ab1 commit 8774e89
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 19 deletions.
24 changes: 23 additions & 1 deletion cmake/FindPsqlDevel.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,41 @@
# postgresql-server-devel Support
#

find_program(PG_CONFIG pg_config)

if (NOT PG_CONFIG)
message(FATAL_ERROR "pg_config executable not found. Ensure PostgreSQL is installed and pg_config is in your PATH.")
endif()

# Use pg_config to get the include and library directories
execute_process(COMMAND ${PG_CONFIG} --includedir
OUTPUT_VARIABLE PSQLDEVEL_INCLUDE_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE)

execute_process(COMMAND ${PG_CONFIG} --libdir
OUTPUT_VARIABLE PSQLDEVEL_LIBRARY_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE)

find_path(PSQLDEVEL_INCLUDE_DIR
NAMES libpq-fe.h
PATH_SUFFIXES postgresql
PATHS ${PSQLDEVEL_INCLUDE_DIR}
)

find_library(PSQLDEVEL_LIBRARY
NAMES pq
PATHS ${PSQLDEVEL_LIBRARY_DIR}
)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(PsqlDevel DEFAULT_MSG
PSQLDEVEL_INCLUDE_DIR PSQLDEVEL_LIBRARY)

if (PSQLDEVEL_INCLUDE_DIR AND PSQLDEVEL_LIBRARY)
set(PSQLDEVEL_FOUND TRUE)
else()
set(PSQLDEVEL_FOUND FALSE)
endif()

if (PSQLDEVEL_FOUND)
set(PSQLDEVEL_INCLUDE_DIRS ${PSQLDEVEL_INCLUDE_DIR})
set(PSQLDEVEL_LIBRARIES ${PSQLDEVEL_LIBRARY})
Expand Down
9 changes: 5 additions & 4 deletions doc/manual/user-03-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@

## Security

After you create the extension `pgmoneta_ext` using the `postgres` role, you can test all functions as shown below. Some functions may require superuser privileges (For the column `Superuser`, the value is `true`), so if you log in with a role without superuser privileges, the function will return `false`. If you have superuser privileges, it will work as desired.
After you create the extension `pgmoneta_ext` using the `postgres` role, you can test all functions as shown below. Some functions may require specific privileges (For the column `Privilege`), so if you log in with a role without the specific privileges, the function will return `false`. If you have the specific privileges, it will work as desired.

## Extension functions

| Function | Superuser | Description |
| Function | Privilege | Description |
|-----------------------------|-----------|--------------------------------------------------------|
| `pgmoneta_ext_version()` | false | Return the version number of `pgmoneta_ext` as a Datum.|
| `pgmoneta_ext_switch_wal()` | true | A function for switching to a new WAL file. |
| `pgmoneta_ext_version()` | Default | Return the version number of `pgmoneta_ext` as a Datum.|
| `pgmoneta_ext_switch_wal()` | SUPERUSER | A function for switching to a new WAL file. |
| `pgmoneta_ext_checkpoint()` | SUPERUSER <br>pg_checkpoint | A function which forces a checkpoint. <br>This function can only be executed by a `SUPERUSER` in PostgreSQL 13/14, but can also be executed by `pg_checkpoint` in PostgreSQL 15+. <br>You can use the SQL command `GRANT pg_checkpoint TO repl;` to assign the role in PostgreSQL 15+.|
7 changes: 7 additions & 0 deletions sql/pgmoneta_ext--0.1.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,11 @@ CREATE FUNCTION pgmoneta_ext_switch_wal(OUT success bool,
)
RETURNS record
AS 'MODULE_PATHNAME'
LANGUAGE C STRICT;

CREATE FUNCTION pgmoneta_ext_checkpoint(OUT success bool,
OUT value text
)
RETURNS record
AS 'MODULE_PATHNAME'
LANGUAGE C STRICT;
16 changes: 13 additions & 3 deletions src/include/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,24 @@ extern "C" {
#include "fmgr.h"

/* system */
#include <stdbool.h>

/**
* Check if the role has superuser privileges.
* @param roleid The current role's ID
* @return 0 upon success, otherwise 1
* @return The result
*/
int
pgmoneta_ext_check_privilege(Oid roleid);
bool
pgmoneta_ext_check_superuser(Oid roleid);

/**
* Check if the role has specific role.
* @param roleid The current role's ID
* @param rolename Specific role name
* @return The result
*/
bool
pgmoneta_ext_check_role(Oid roleid, const char* rolename);

#ifdef __cplusplus
}
Expand Down
68 changes: 64 additions & 4 deletions src/pgmoneta_ext/lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
*
*/

/* pgmoneta */
/* pgmoneta_ext */
#include <pgmoneta_ext.h>
#include <utils.h>

Expand All @@ -52,6 +52,7 @@ PG_MODULE_MAGIC;

PG_FUNCTION_INFO_V1(pgmoneta_ext_version);
PG_FUNCTION_INFO_V1(pgmoneta_ext_switch_wal);
PG_FUNCTION_INFO_V1(pgmoneta_ext_checkpoint);

Datum
pgmoneta_ext_version(PG_FUNCTION_ARGS)
Expand All @@ -78,15 +79,15 @@ pgmoneta_ext_switch_wal(PG_FUNCTION_ARGS)
XLogRecPtr recptr;
bool nulls[2];
char str_res[1024];
int is_superuser;
bool is_superuser;

memset(nulls, 0, sizeof(nulls));

roleid = GetUserId();

is_superuser = pgmoneta_ext_check_privilege(roleid);
is_superuser = pgmoneta_ext_check_superuser(roleid);

if (!is_superuser)
if (is_superuser)
{
// Request to switch WAL with mark_unimportant set to false.
recptr = RequestXLogSwitch(false);
Expand Down Expand Up @@ -114,5 +115,64 @@ pgmoneta_ext_switch_wal(PG_FUNCTION_ARGS)
tuple = heap_form_tuple(tupdesc, values, nulls);
result = HeapTupleGetDatum(tuple);

PG_RETURN_DATUM(result);
}

#ifndef RequestCheckpoint
extern void RequestCheckpoint(int flags);
#endif

Datum
pgmoneta_ext_checkpoint(PG_FUNCTION_ARGS)
{
Datum values[2];
Datum result;
HeapTuple tuple;
Oid roleid;
TupleDesc tupdesc;
bool nulls[2];
bool is_superuser;
bool is_pg_checkpoint;
char cp[1024];

memset(nulls, 0, sizeof(nulls));
memset(&cp, 0, sizeof(cp));
is_superuser = false;
is_pg_checkpoint = false;

roleid = GetUserId();
is_superuser = pgmoneta_ext_check_superuser(roleid);

#if PG_VERSION_NUM >= 150000
is_pg_checkpoint = pgmoneta_ext_check_role(roleid, "pg_checkpoint");
#endif

if (is_superuser || is_pg_checkpoint)
{
// Perform the checkpoint
RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_WAIT | CHECKPOINT_FORCE);

values[0] = BoolGetDatum(true);
snprintf(&cp[0], sizeof(cp), "%s", "CHECKPOINT");
values[1] = CStringGetTextDatum(cp);
}
else
{
ereport(LOG, errmsg_internal("pgmoneta_ext_checkpoint: Current role is not a superuser"));

values[0] = BoolGetDatum(false);
nulls[1] = true;
}

// Create a tuple descriptor for our result type
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
{
ereport(ERROR, errmsg_internal("pgmoneta_ext_checkpoint: Return type must be a row type"));
}

// Build the result tuple
tuple = heap_form_tuple(tupdesc, values, nulls);
result = HeapTupleGetDatum(tuple);

PG_RETURN_DATUM(result);
}
56 changes: 49 additions & 7 deletions src/pgmoneta_ext/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,33 +27,37 @@
*
*/

/* pgmoneta */
/* pgmoneta_ext */
#include <utils.h>

/* PostgreSQL */
#include "access/htup_details.h"
#include "catalog/pg_authid.h"
#include "miscadmin.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/elog.h"
#include "utils/errcodes.h"
#include "utils/relcache.h"
#include "utils/syscache.h"

/* system */
#include <stdbool.h>

int
pgmoneta_ext_check_privilege(Oid roleid)
bool
pgmoneta_ext_check_superuser(Oid roleid)
{
bool is_superuser;
HeapTuple roletuple;
Form_pg_authid roleform;

is_superuser = false;

// Fetch the role's tuple from pg_authid
roletuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
if (!HeapTupleIsValid(roletuple))
{
ereport(ERROR, errmsg_internal("pgmoneta_ext_switch_wal: Role with OID %u does not exist", roleid));
return 1;
ereport(ERROR, errmsg_internal("pgmoneta_ext_check_superuser: Role with OID %u does not exist", roleid));
return false;
}

// Get the role's superuser attribute
Expand All @@ -64,5 +68,43 @@ pgmoneta_ext_check_privilege(Oid roleid)
// Release the role tuple
ReleaseSysCache(roletuple);

return !is_superuser;
return is_superuser;
}

bool
pgmoneta_ext_check_role(Oid roleid, const char* rolename)
{
bool is_success;
HeapTuple roletuple;
List* role_oids;
ListCell* cell;

is_success = false;

roletuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
if (!HeapTupleIsValid(roletuple))
{
ereport(ERROR, errmsg_internal("pgmoneta_ext_check_role: Role with OID %u does not exist", roleid));
return false;
}

// Get role OIDs of a given role name
Oid role_oid = get_role_oid(rolename, false);
role_oids = list_make1_oid(role_oid);

// Check if the role has the specific privilege
foreach (cell, role_oids)
{
Oid checkpoint_role_oid = lfirst_oid(cell);
if (is_member_of_role(roleid, checkpoint_role_oid))
{
is_success = true;
break;
}
}

ReleaseSysCache(roletuple);
list_free(role_oids);

return is_success;
}

0 comments on commit 8774e89

Please sign in to comment.