Skip to content

Commit 3ef5e76

Browse files
committed
refactor: use C APIs on alter_owner instead of SPI
The code is shorter and there's less room for error.
1 parent 62adaf6 commit 3ef5e76

File tree

4 files changed

+57
-61
lines changed

4 files changed

+57
-61
lines changed

src/pg_prelude.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@
1010
#include <catalog/pg_authid.h>
1111
#include <catalog/pg_proc.h>
1212
#include <commands/defrem.h>
13+
#include <commands/publicationcmds.h>
14+
#include <commands/defrem.h>
15+
#include <commands/event_trigger.h>
1316
#include <executor/spi.h>
1417
#include <fmgr.h>
1518
#include <miscadmin.h>
1619
#include <nodes/makefuncs.h>
1720
#include <nodes/pg_list.h>
21+
#include <nodes/value.h>
1822
#include <parser/parse_func.h>
1923
#include <tcop/utility.h>
2024
#include <tsearch/ts_locale.h>

src/supautils.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -553,10 +553,9 @@ static void supautils_hook(PROCESS_UTILITY_PARAMS) {
553553
run_process_utility_hook(prev_hook);
554554

555555
CreateFdwStmt *stmt = (CreateFdwStmt *)utility_stmt;
556-
const char *current_role_name = GetUserNameFromId(current_user_id, false);
557556

558557
// Change FDW owner to the current role (which is a privileged role)
559-
alter_owner(stmt->fdwname, current_role_name, ALT_FDW);
558+
alter_owner(stmt->fdwname, current_user_id, ALT_FDW);
560559

561560
if (!already_switched_to_superuser) {
562561
switch_to_original_role();
@@ -584,10 +583,9 @@ static void supautils_hook(PROCESS_UTILITY_PARAMS) {
584583
run_process_utility_hook(prev_hook);
585584

586585
CreatePublicationStmt *stmt = (CreatePublicationStmt *)utility_stmt;
587-
const char *current_role_name = GetUserNameFromId(current_user_id, false);
588586

589587
// Change publication owner to the current role (which is a privileged role)
590-
alter_owner(stmt->pubname, current_role_name, ALT_PUB);
588+
alter_owner(stmt->pubname, current_user_id, ALT_PUB);
591589

592590
if (!already_switched_to_superuser) {
593591
switch_to_original_role();
@@ -846,7 +844,6 @@ static void supautils_hook(PROCESS_UTILITY_PARAMS) {
846844
const Oid current_user_id = GetUserId();
847845

848846
CreateEventTrigStmt *stmt = (CreateEventTrigStmt *)utility_stmt;
849-
const char *current_role_name = GetUserNameFromId(current_user_id, false);
850847

851848
bool current_user_is_super = superuser_arg(current_user_id);
852849
func_attrs fattrs = get_function_attrs((func_search){FO_SEARCH_NAME, {stmt->funcname}});
@@ -855,14 +852,14 @@ static void supautils_hook(PROCESS_UTILITY_PARAMS) {
855852
if(!current_user_is_super && function_is_owned_by_super){
856853
ereport(ERROR, (
857854
errmsg("Non-superuser owned event trigger must execute a non-superuser owned function")
858-
, errdetail("The current user \"%s\" is not a superuser and the function \"%s\" is owned by a superuser", current_role_name, NameListToString(stmt->funcname))
855+
, errdetail("The current user \"%s\" is not a superuser and the function \"%s\" is owned by a superuser", GetUserNameFromId(current_user_id, false), NameListToString(stmt->funcname))
859856
));
860857
}
861858

862859
if(current_user_is_super && !function_is_owned_by_super){
863860
ereport(ERROR, (
864861
errmsg("Superuser owned event trigger must execute a superuser owned function")
865-
, errdetail("The current user \"%s\" is a superuser and the function \"%s\" is owned by a non-superuser", current_role_name, NameListToString(stmt->funcname))
862+
, errdetail("The current user \"%s\" is a superuser and the function \"%s\" is owned by a non-superuser", GetUserNameFromId(current_user_id, false), NameListToString(stmt->funcname))
866863
));
867864
}
868865

@@ -872,7 +869,7 @@ static void supautils_hook(PROCESS_UTILITY_PARAMS) {
872869

873870
if (!current_user_is_super)
874871
// Change event trigger owner to the current role (which is a privileged role)
875-
alter_owner(stmt->trigname, current_role_name, ALT_EVTRIG);
872+
alter_owner(stmt->trigname, current_user_id, ALT_EVTRIG);
876873

877874
if (!already_switched_to_superuser) {
878875
switch_to_original_role();

src/utils.c

Lines changed: 47 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -81,67 +81,62 @@ bool remove_ending_wildcard(char *elem) {
8181
return wildcard_removed;
8282
}
8383

84+
static void alter_role_super(const char* rolename, bool make_super){
85+
RoleSpec *rolespec = makeNode(RoleSpec);
86+
rolespec->roletype = ROLESPEC_CSTRING;
87+
rolespec->rolename = pstrdup(rolename);
88+
rolespec->location = -1;
89+
90+
AlterRoleStmt *alter_stmt = makeNode(AlterRoleStmt);
91+
alter_stmt->role = rolespec;
92+
93+
alter_stmt->options = list_make1(
94+
makeDefElem("superuser", (Node *) makeInteger(make_super), -1) // using makeInteger because makeBoolean is not available on pg <= 14
95+
);
96+
97+
#if PG15_GTE
98+
AlterRole(NULL, alter_stmt);
99+
#else
100+
AlterRole(alter_stmt);
101+
#endif
102+
103+
CommandCounterIncrement();
104+
}
105+
84106
// Changes the OWNER of a database object.
85107
// Some objects (e.g. foreign data wrappers) can only be owned by superusers, so this switches to superuser accordingly and then goes backs to non-super.
86-
void alter_owner(const char *obj_name, const char *role_name, altered_obj_type obj_type){
108+
void alter_owner(const char *obj_name, Oid role_oid, altered_obj_type obj_type){
109+
switch(obj_type){
110+
case ALT_FDW:{
111+
char* role_name = GetUserNameFromId(role_oid, false);
112+
alter_role_super(role_name, true);
87113

88-
// static allocations to avoid dynamic palloc
89-
static const char sql_fdw_template[] =
90-
"alter role \"%s\" superuser;\n"
91-
"alter foreign data wrapper \"%s\" owner to \"%s\";\n"
92-
"alter role \"%s\" nosuperuser;\n";
114+
AlterForeignDataWrapperOwner(obj_name, role_oid);
115+
CommandCounterIncrement();
93116

94-
static const char sql_evtrig_template[] =
95-
"alter role \"%s\" superuser;\n"
96-
"alter event trigger \"%s\" owner to \"%s\";\n"
97-
"alter role \"%s\" nosuperuser;\n";
117+
alter_role_super(role_name, false);
98118

99-
static const char sql_sub_template[] =
100-
"alter publication \"%s\" owner to \"%s\";\n";
119+
break;
120+
}
101121

102-
// max sql length for above templates
103-
static const size_t max_sql_len
104-
= sizeof (sql_fdw_template) // the fdw template is the largest one
105-
+ 4 * NAMEDATALEN; // the max size of the 4 identifiers on the fdw template
122+
case ALT_PUB:
106123

107-
char sql[max_sql_len];
124+
AlterPublicationOwner(obj_name, role_oid);
125+
CommandCounterIncrement();
108126

109-
switch(obj_type){
110-
case ALT_FDW:
111-
snprintf(sql,
112-
max_sql_len,
113-
sql_fdw_template,
114-
role_name,
115-
obj_name,
116-
role_name,
117-
role_name);
118-
break;
119-
case ALT_PUB:
120-
snprintf(sql,
121-
max_sql_len,
122-
sql_sub_template,
123-
obj_name,
124-
role_name);
125-
break;
126-
case ALT_EVTRIG:
127-
snprintf(sql,
128-
max_sql_len,
129-
sql_evtrig_template,
130-
role_name,
131-
obj_name,
132-
role_name,
133-
role_name);
134-
break;
135-
}
127+
break;
136128

137-
PushActiveSnapshot(GetTransactionSnapshot());
138-
SPI_connect();
129+
case ALT_EVTRIG:{
130+
char* role_name = GetUserNameFromId(role_oid, false);
139131

140-
int rc = SPI_execute(sql, false, 0);
141-
if (rc != SPI_OK_UTILITY) {
142-
elog(ERROR, "SPI_execute failed with error code %d", rc);
143-
}
132+
alter_role_super(role_name, true);
133+
134+
AlterEventTriggerOwner(obj_name, role_oid);
135+
CommandCounterIncrement();
136+
137+
alter_role_super(role_name, false);
144138

145-
SPI_finish();
146-
PopActiveSnapshot();
139+
break;
140+
}
141+
}
147142
}

src/utils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ typedef enum {
107107

108108
extern void alter_owner(
109109
const char *obj_name,
110-
const char *role_name,
110+
Oid role_oid,
111111
altered_obj_type obj_type
112112
);
113113

0 commit comments

Comments
 (0)