From 36ef69d49a45a07507d8bb04683be9c1f00f144b Mon Sep 17 00:00:00 2001 From: gentle_hu Date: Wed, 12 Aug 2020 00:29:42 +0800 Subject: [PATCH 1/2] add: AlterSystemSet --- src/common/backend/nodes/copyfuncs.cpp | 11 + src/common/backend/nodes/equalfuncs.cpp | 9 + src/common/backend/parser/gram.y | 81 ++- src/common/backend/utils/misc/guc.cpp | 531 ++++++++++++++---- src/gausskernel/process/tcop/auditfuncs.cpp | 4 + src/gausskernel/process/tcop/utility.cpp | 13 + src/include/nodes/nodes.h | 1 + src/include/nodes/parsenodes.h | 9 + src/include/parser/kwlist.h | 2 + src/include/utils/guc.h | 1 + .../regress/expected/alter_system_set.out | 406 +++++++++++++ src/test/regress/parallel_schedule | 1 + src/test/regress/parallel_schedule1 | 3 +- src/test/regress/sql/alter_system_set.sql | 149 +++++ 14 files changed, 1070 insertions(+), 151 deletions(-) create mode 100644 src/test/regress/expected/alter_system_set.out create mode 100644 src/test/regress/sql/alter_system_set.sql diff --git a/src/common/backend/nodes/copyfuncs.cpp b/src/common/backend/nodes/copyfuncs.cpp index da6068bb09..a15d12d3c4 100644 --- a/src/common/backend/nodes/copyfuncs.cpp +++ b/src/common/backend/nodes/copyfuncs.cpp @@ -87,6 +87,7 @@ static void CopyMemInfoFields(const OpMemInfo* from, OpMemInfo* newnode); static ReplicaIdentityStmt* _copyReplicaIdentityStmt(const ReplicaIdentityStmt* from); +static AlterSystemStmt* _copyAlterSystemStmt(const AlterSystemStmt * from); static void CopyCursorFields(const Cursor_Data* from, Cursor_Data* newnode); /* **************************************************************** @@ -6401,6 +6402,9 @@ void* copyObject(const void* from) case T_ReplicaIdentityStmt: retval = _copyReplicaIdentityStmt((ReplicaIdentityStmt*)from); break; + case T_AlterSystemStmt: + retval = _copyAlterSystemStmt((AlterSystemStmt*)from); + break; case T_CreateSeqStmt: retval = _copyCreateSeqStmt((CreateSeqStmt*)from); break; @@ -6827,6 +6831,13 @@ static ReplicaIdentityStmt* _copyReplicaIdentityStmt(const ReplicaIdentityStmt* return newnode; } +static AlterSystemStmt* _copyAlterSystemStmt(const AlterSystemStmt * from) +{ + AlterSystemStmt* newnode = makeNode(AlterSystemStmt); + COPY_NODE_FIELD(setstmt); + return newnode; +} + /* * CopyCursorFields - * copy Cursor_Data structure from "from" node to "newnode" diff --git a/src/common/backend/nodes/equalfuncs.cpp b/src/common/backend/nodes/equalfuncs.cpp index 9cc4f26951..bbbf0f57d5 100755 --- a/src/common/backend/nodes/equalfuncs.cpp +++ b/src/common/backend/nodes/equalfuncs.cpp @@ -1567,6 +1567,12 @@ static bool _equalReplicaIdentityStmt(const ReplicaIdentityStmt* a, const Replic return true; } +static bool _equalAlterSystemStmt(const AlterSystemStmt * a, const AlterSystemStmt * b) +{ + COMPARE_NODE_FIELD(setstmt); + return true; +} + static bool _equalCreateSeqStmt(const CreateSeqStmt* a, const CreateSeqStmt* b) { COMPARE_NODE_FIELD(sequence); @@ -3130,6 +3136,9 @@ bool equal(const void* a, const void* b) case T_ReplicaIdentityStmt: retval = _equalReplicaIdentityStmt((ReplicaIdentityStmt*)a, (ReplicaIdentityStmt*)b); break; + case T_AlterSystemStmt: + retval = _equalAlterSystemStmt((AlterSystemStmt*)a, (AlterSystemStmt*)b); + break; case T_AlterSeqStmt: retval = _equalAlterSeqStmt((AlterSeqStmt*)a, (AlterSeqStmt*)b); break; diff --git a/src/common/backend/parser/gram.y b/src/common/backend/parser/gram.y index 653930a3f0..0d7e16b5e5 100755 --- a/src/common/backend/parser/gram.y +++ b/src/common/backend/parser/gram.y @@ -165,7 +165,6 @@ static void processCASbits(int cas_bits, int location, const char *constrType, bool *deferrable, bool *initdeferred, bool *not_valid, bool *no_inherit, core_yyscan_t yyscanner); static Expr *makeNodeDecodeCondtion(Expr* firstCond,Expr* secondCond); -static void is_kill_session(List *actionlist); static List *make_action_func(List *arguments); static List *get_func_args(char *sid); static char *pg_strsep(char **stringp, const char *delim); @@ -451,7 +450,7 @@ static void ParseUpdateMultiSet(List *set_target_list, SelectStmt *stmt, core_yy %type merge_insert merge_update -%type set_rest set_rest_more SetResetClause FunctionSetResetClause +%type generic_set set_rest set_rest_more SetResetClause FunctionSetResetClause %type TableElement TypedTableElement ConstraintElem TableFuncElement ForeignTableElement @@ -637,7 +636,7 @@ static void ParseUpdateMultiSet(List *set_target_list, SelectStmt *stmt, core_yy /* PGXC_BEGIN */ DICTIONARY DIRECT DIRECTORY DISABLE_P DISCARD DISTINCT DISTRIBUTE DISTRIBUTION DO DOCUMENT_P DOMAIN_P DOUBLE_P /* PGXC_END */ - DROP DUPLICATE + DROP DUPLICATE DISCONNECT EACH ELASTIC ELSE ENABLE_P ENCODING ENCRYPTED END_P ENFORCED ENUM_P ERRORS ESCAPE EOL ESCAPING EVERY EXCEPT EXCHANGE EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN @@ -657,7 +656,7 @@ static void ParseUpdateMultiSet(List *set_target_list, SelectStmt *stmt, core_yy JOIN - KEY + KEY KILL LABEL LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING LEAKPROOF LEAST LESS LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP @@ -1507,17 +1506,19 @@ AlterSessionStmt: /* "alter system" */ /***************************************************************************** * - * Alter SYSTEM (kill a session) + * Alter SYSTEM + * (1. kill a session by "select pg_terminate_backend(pid)", so it only needs a SelectStmt node.) + * (2. disconnect a session. unsupported currently.) + * (3. set system parameter to, this is used to change configuration parameters persistently.) * *****************************************************************************/ AlterSystemStmt: - ALTER SYSTEM_P name_list SESSION Sconst altersys_option + ALTER SYSTEM_P KILL SESSION Sconst altersys_option { SelectStmt *n = NULL; List *pid = NULL; - is_kill_session($3); pid = get_func_args($5); n = makeNode(SelectStmt); @@ -1531,7 +1532,22 @@ AlterSystemStmt: n->windowClause = NIL; $$ = (Node *)n; } + + | ALTER SYSTEM_P DISCONNECT SESSION Sconst altersys_option + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("unsupported action \"DISCONNECT\" for statement \" alter system \""))); + } + + | ALTER SYSTEM_P SET generic_set + { + AlterSystemStmt *n = makeNode(AlterSystemStmt); + n->setstmt = $4; + $$ = (Node *)n; + } ; + altersys_option: IMMEDIATE {/* empty */} | {/* empty */} @@ -1666,7 +1682,7 @@ set_rest: | set_rest_more ; -set_rest_more: /* Generic SET syntaxes: */ +generic_set: var_name TO var_list { VariableSetStmt *n = makeNode(VariableSetStmt); @@ -1751,6 +1767,13 @@ set_rest_more: /* Generic SET syntaxes: */ n->name = "current_schema"; $$ = n; } + ; + +set_rest_more: /* Generic SET syntaxes: */ + generic_set + { + $$ = $1; + } | var_name FROM CURRENT_P { VariableSetStmt *n = makeNode(VariableSetStmt); @@ -11398,7 +11421,6 @@ DropdbStmt: DROP DATABASE database_name } ; - /***************************************************************************** * * Manipulate a domain @@ -17671,6 +17693,7 @@ unreserved_keyword: | DIRECTORY | DISABLE_P | DISCARD + | DISCONNECT /* PGXC_BEGIN */ | DISTRIBUTE | DISTRIBUTION @@ -17742,6 +17765,7 @@ unreserved_keyword: | ISNULL | ISOLATION | KEY + | KILL | LABEL | LANGUAGE | LARGE_P @@ -18858,45 +18882,6 @@ makeNodeDecodeCondtion(Expr* firstCond,Expr* secondCond) return (Expr*)c; } -// check weather is an action of "kill session" -// unsupported action "disconnect" -static void -is_kill_session(List *actionlist) -{ - char *actionopt = NULL; - ListCell *lc = NULL; - - if (1 != actionlist->length) - { - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("undefined or invalid action for statement \" alter system \""))); - return; - } - - lc = list_head(actionlist); - actionopt = ((Value *)(lfirst(lc)))->val.str; - - if (!pg_strcasecmp(actionopt, "KILL")) - return; - else if (!pg_strcasecmp(actionopt, "DISCONNECT")) - { - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("unsupported action \"%s\" for statement \" alter system \"", - actionopt))); - return; - } - else - { - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("undefined action \"%s\" for statement \" alter system \"", - actionopt))); - return; - } -} - // make function infomation to kill the session // make "ResTarget" for invoking function "pg_terminate_backend", // only the first cell of arguments is effective, it is treated as pid diff --git a/src/common/backend/utils/misc/guc.cpp b/src/common/backend/utils/misc/guc.cpp index 698f03ceeb..f3623bfcdb 100644 --- a/src/common/backend/utils/misc/guc.cpp +++ b/src/common/backend/utils/misc/guc.cpp @@ -483,6 +483,8 @@ static const char* show_unix_socket_permissions(void); static const char* show_log_file_mode(void); static char* config_enum_get_options( struct config_enum* record, const char* prefix, const char* suffix, const char* separator); +static bool validate_conf_option(struct config_generic * record, const char *name, const char *value, + GucSource source, int elevel, bool freemem, void *newval, void **newextra); /* Database Security: Support password complexity */ static bool check_int_parameter(int* newval, void** extra, GucSource source); @@ -11885,6 +11887,7 @@ static void show_guc_config_option(const char* name, DestReceiver* dest); static void show_all_guc_config(DestReceiver* dest); static char* _show_option(struct config_generic* record, bool use_units); static bool validate_option_array_item(const char* name, const char* value, bool skip_if_no_permissions); +static void replace_config_value(char** optlines, char* name, char* value, config_type vartype); /* * Some infrastructure for checking malloc/strdup/realloc calls @@ -14324,6 +14327,202 @@ static char* config_enum_get_options( return retstr.data; } +/* + * Validates configuration parameter and value, by calling check hook functions + * depending on record's vartype. It validates if the parameter + * value given is in range of expected predefined value for that parameter. + * + * freemem - true indicates memory for newval and newextra will be + * freed in this function, false indicates it will be freed + * by caller. + * Return value: + * true : the value is valid + * false: the name or value is invalid + */ +bool validate_conf_option(struct config_generic * record, const char *name, const char *value, GucSource source, + int elevel, bool freemem, void *newvalue, void **newextra) +{ + Assert(value != NULL); + + /* + * Validate the value for the passed record, to ensure it is in expected range. + */ + switch (record->vartype) + { + case PGC_BOOL: + { + struct config_bool *conf = (struct config_bool *) record; + bool tmpnewval; + bool* newval = (newvalue == NULL ? &tmpnewval : (bool*)newvalue); + + if (!parse_bool(value, newval)) { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("parameter \"%s\" requires a Boolean value", name))); + return false; + } + + if (!call_bool_check_hook(conf, newval, newextra, source, elevel)) + return false; + + if (*newextra && freemem) + pfree(*newextra); + } + break; + case PGC_INT: + { + struct config_int *conf = (struct config_int *) record; + int tmpnewval; + int* newval = (newvalue == NULL ? &tmpnewval : (int*)newvalue); + const char *hintmsg = NULL; + + if (!parse_int(value, newval, conf->gen.flags, &hintmsg)) { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": \"%s\"", + name, value), hintmsg ? errhint("%s", _(hintmsg)) : 0)); + return false; + } + + if (*newval < conf->min || *newval > conf->max) { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("%d is outside the valid range for parameter \"%s\" (%d .. %d)", + *newval, name, conf->min, conf->max))); + return false; + } + + if (!call_int_check_hook(conf, newval, newextra, source, elevel)) + return false; + + if (*newextra && freemem) + pfree(*newextra); + } + break; + case PGC_INT64: + { + struct config_int64* conf = (struct config_int64*)record; + int64 tmpnewval; + int64* newval = (newvalue == NULL ? &tmpnewval : (int64*)newvalue); + const char* hintmsg = NULL; + + if (!parse_int64(value, newval, &hintmsg)) { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("parameter \"%s\" requires a numeric value", name))); + return false; + } + + if (*newval < conf->min || *newval > conf->max) { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("%ld is outside the valid range for parameter \"%s\" (%ld .. %ld)", + *newval, name, conf->min, conf->max))); + return false; + } + + if (!call_int64_check_hook(conf, newval, newextra, source, elevel)) + return false; + + if (*newextra && freemem) + pfree(newextra); + } + break; + case PGC_REAL: + { + struct config_real *conf = (struct config_real *) record; + double tmpnewval; + double* newval = (newvalue == NULL ? &tmpnewval : (double*)newvalue); + + if (!parse_real(value, newval)) { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("parameter \"%s\" requires a numeric value", name))); + return false; + } + + if (*newval < conf->min || *newval > conf->max) { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("%g is outside the valid range for parameter \"%s\" (%g .. %g)", + *newval, name, conf->min, conf->max))); + return false; + } + + if (!call_real_check_hook(conf, newval, newextra, source, elevel)) + return false; + + if (*newextra && freemem) + pfree(*newextra); + } + break; + case PGC_STRING: + { + struct config_string *conf = (struct config_string *) record; + char* tmpnewval = NULL; + char** newval = newvalue == NULL ? &tmpnewval : (char**)newvalue; + + /* The value passed by the caller could be transient, so we always strdup it. */ + *newval = guc_strdup(elevel, value); + if (*newval == NULL) + return false; + + /* The only built-in "parsing" check we have is to apply truncation if GUC_IS_NAME. */ + if (conf->gen.flags & GUC_IS_NAME) + truncate_identifier(*newval, strlen(*newval), true); + + if (!call_string_check_hook(conf, newval, newextra, source, elevel)) { + pfree(*newval); + return false; + } + + /* Free the malloc'd data if any */ + if (freemem) { + if (*newval != NULL) + pfree(*newval); + if (*newextra != NULL) + pfree(*newextra); + } + } + break; + case PGC_ENUM: + { + struct config_enum *conf = (struct config_enum *) record; + int tmpnewval; + int* newval = (newvalue == NULL ? &tmpnewval : (int*)newvalue); + + if (!config_enum_lookup_by_name(conf, value, newval)) { + char* hintmsg; + + hintmsg = config_enum_get_options(conf, "Available values: ", ".", ", "); + + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": \"%s\"", name, value), + hintmsg ? errhint("%s", _(hintmsg)) : 0)); + + if (hintmsg != NULL) + pfree(hintmsg); + return false; + } + if (!call_enum_check_hook(conf, newval, newextra, source, LOG)) + return false; + + if (*newextra && freemem) + pfree(*newextra); + } + break; + default: + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_ATTRIBUTE), + errmsg("unknow guc variable type: %d", record->vartype))); + } + break; + } + return true; +} + void SetThreadLocalGUC(knl_session_context* session) { default_statistics_target = session->attr.attr_sql.default_statistics_target; @@ -14590,14 +14789,7 @@ int set_config_option(const char* name, const char* value, GucContext context, G void* newextra = NULL; if (value != NULL) { - if (!parse_bool(value, &newval)) { - ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("parameter \"%s\" requires a Boolean value", name))); - return 0; - } - - if (!call_bool_check_hook(conf, &newval, &newextra, source, elevel)) { + if (!validate_conf_option(record, name, value, source, elevel, false, &newval, &newextra)) { return 0; } } else if (source == PGC_S_DEFAULT) { @@ -14681,27 +14873,7 @@ int set_config_option(const char* name, const char* value, GucContext context, G void* newextra = NULL; if (value != NULL) { - const char* hintmsg = NULL; - - if (!parse_int(value, &newval, conf->gen.flags, &hintmsg)) { - ereport(elevel, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid value for parameter \"%s\": \"%s\"", name, value), - hintmsg ? errhint("%s", _(hintmsg)) : 0)); - return 0; - } - - if (newval < conf->min || newval > conf->max) { - ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("%d is outside the valid range for parameter \"%s\" (%d .. %d)", - newval, - name, - conf->min, - conf->max))); - return 0; - } - - if (!call_int_check_hook(conf, &newval, &newextra, source, elevel)) { + if (!validate_conf_option(record, name, value, source, elevel, false, &newval, &newextra)) { return 0; } } else if (source == PGC_S_DEFAULT) { @@ -14780,26 +14952,7 @@ int set_config_option(const char* name, const char* value, GucContext context, G void* newextra = NULL; if (value != NULL) { - const char* hintmsg = NULL; - if (!parse_int64(value, &newval, &hintmsg)) { - ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("parameter \"%s\" requires a numeric value", name))); - return 0; - } - - if (newval < conf->min || newval > conf->max) { - ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("%ld is outside the valid range for parameter \"%s\" (%ld .. %ld)", - newval, - name, - conf->min, - conf->max))); - return 0; - } - - if (!call_int64_check_hook(conf, &newval, &newextra, source, elevel)) { + if (!validate_conf_option(record, name, value, source, elevel, false, &newval, &newextra)) { return 0; } } else if (source == PGC_S_DEFAULT) { @@ -14872,25 +15025,7 @@ int set_config_option(const char* name, const char* value, GucContext context, G void* newextra = NULL; if (value != NULL) { - if (!parse_real(value, &newval)) { - ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("parameter \"%s\" requires a numeric value", name))); - return 0; - } - - if (newval < conf->min || newval > conf->max) { - ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("%g is outside the valid range for parameter \"%s\" (%g .. %g)", - newval, - name, - conf->min, - conf->max))); - return 0; - } - - if (!call_real_check_hook(conf, &newval, &newextra, source, elevel)) { + if (!validate_conf_option(record, name, value, source, elevel, false, &newval, &newextra)) { return 0; } } else if (source == PGC_S_DEFAULT) { @@ -14978,14 +15113,6 @@ int set_config_option(const char* name, const char* value, GucContext context, G } if (value != NULL) { - /* - * The value passed by the caller could be transient, so - * we always strdup it. - */ - newval = guc_strdup(elevel, value); - if (newval == NULL) { - return 0; - } // when \parallel in gsql is on, we use "set search_path to pg_temp_XXX" // to tell new started parallel postgres which temp namespace should use. @@ -15016,16 +15143,7 @@ int set_config_option(const char* name, const char* value, GucContext context, G return 1; } - /* - * The only built-in "parsing" check we have is to apply - * truncation if GUC_IS_NAME. - */ - if (conf->gen.flags & GUC_IS_NAME) { - truncate_identifier(newval, strlen(newval), true); - } - - if (!call_string_check_hook(conf, &newval, &newextra, source, elevel)) { - pfree(newval); + if (!validate_conf_option(record, name, value, source, elevel, false, &newval, &newextra)) { return 0; } } else if (source == PGC_S_DEFAULT) { @@ -15119,20 +15237,7 @@ int set_config_option(const char* name, const char* value, GucContext context, G void* newextra = NULL; if (value != NULL) { - if (!config_enum_lookup_by_name(conf, value, &newval)) { - char* hintmsg = NULL; - hintmsg = config_enum_get_options(conf, "Available values: ", ".", ", "); - ereport(elevel, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid value for parameter \"%s\": \"%s\"", name, value), - hintmsg ? errhint("%s", _(hintmsg)) : 0)); - - if (hintmsg != NULL) { - pfree(hintmsg); - } - return 0; - } - - if (!call_enum_check_hook(conf, &newval, &newextra, source, elevel)) { + if (!validate_conf_option(record, name, value, source, elevel, false, &newval, &newextra)) { return 0; } } else if (source == PGC_S_DEFAULT) { @@ -15500,6 +15605,228 @@ static char* flatten_set_variable_args(const char* name, List* args) return buf.data; } +/* + * This function takes list of all configuration parameters in + * postgresql.conf and parameter to be updated as input arguments and + * replace the updated configuration parameter value in a list. If the + * parameter to be updated is new then it is appended to the list of + * parameters. + */ +static void replace_config_value(char** optlines, char* name, char* value, config_type vartype) +{ + Assert(optlines != NULL); + + int index = 0; + int optvalue_off = 0; + int optvalue_len = 0; + char* newline = (char*)pg_malloc(MAX_PARAM_LEN); + int rc = 0; + + switch (vartype) { + case PGC_BOOL: + case PGC_INT: + case PGC_INT64: + case PGC_REAL: + case PGC_ENUM: + rc = snprintf_s(newline, MAX_PARAM_LEN, MAX_PARAM_LEN - 1, "%s = %s\n", name, value); + break; + case PGC_STRING: + rc = snprintf_s(newline, MAX_PARAM_LEN, MAX_PARAM_LEN - 1, "%s = '%s'\n", name, value); + break; + } + securec_check_ss(rc, "\0", "\0"); + + index = find_guc_option(optlines, name, NULL, NULL, &optvalue_off, &optvalue_len); + + /* add or replace */ + if (index == INVALID_LINES_IDX) { + /* find the first NULL point reserved. */ + for (index = 0; optlines[index] != NULL; index++); + + } else { + /* copy comment to newline and pfree old line */ + rc = strncpy_s(newline + rc - 1, MAX_PARAM_LEN - rc, + optlines[index] + optvalue_off + optvalue_len, MAX_PARAM_LEN - rc - 1); + securec_check(rc, "\0", "\0"); + pfree(optlines[index]); + } + + optlines[index] = newline; +} + +/* + * Persist the configuration parameter value. + * + * This function takes all previous configuration parameters + * set by ALTER SYSTEM command and the currently set ones + * and write them all to the automatic configuration file. + * + * The configuration parameters are written to a temporary + * file then renamed to the final name. The template for the + * temporary file is postgresql.auto.conf.temp. + * + * An LWLock is used to serialize writing to the same file. + * + * In case of an error, we leave the original automatic + * configuration file (postgresql.auto.conf) intact. + */ +void AlterSystemSetConfigFile(AlterSystemStmt * altersysstmt) +{ +#define GUCCONF_FILE "postgresql.conf" +#define GUCCONF_FILE_BAK "postgresql.conf.bak" +#define GUCCONF_FILE_BAK_BAK "postgresql.conf.bak_bak" +#define GUCCONF_FILE_LOCK "postgresql.conf.lock" + + char *name = NULL; + char *value = NULL; + struct config_generic *record = NULL; + char ConfFileName[MAXPGPATH]; + char ConfTmpFileName[MAXPGPATH]; + char ConfTmpBakFileName[MAXPGPATH]; + char ConfLockFileName[MAXPGPATH]; + struct stat st; + void *newextra = NULL; + ConfFileLock filelock = {NULL, 0}; + errno_t rc; + ErrCode ret; + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + (errmsg("must be superuser to execute ALTER SYSTEM SET command")))); + + /* + * Validate the name and arguments [value1, value2 ... ]. + */ + name = altersysstmt->setstmt->name; + switch (altersysstmt->setstmt->kind) { + case VAR_SET_VALUE: + value = ExtractSetVariableArgs(altersysstmt->setstmt); + break; + + case VAR_SET_DEFAULT: + ereport(ERROR, + (errcode(ERRCODE_OPERATE_NOT_SUPPORTED), + (errmsg("ALTER SYSTEM SET does not support 'set to default'.")))); + value = NULL; + break; + default: + elog(ERROR, "unrecognized ALTER SYSTEM SET stmt type: %d", + altersysstmt->setstmt->kind); + break; + } + + record = find_option(name, false, LOG); + if (record == NULL) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("unrecognized configuration parameter \"%s\"", name))); + + if ((record->context != PGC_POSTMASTER && record->context != PGC_SIGHUP && record->context != PGC_BACKEND) || + record->flags & GUC_DISALLOW_IN_FILE) + ereport(ERROR, + (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), + errmsg("unsupport parameter: %s\n" + "ALTER SYSTEM SET only support POSTMASTER-level, SIGHUP-level and BACKEND-level guc variable,\n" + "and it must be allowed to set in postgresql.conf.", name))); + + if (!validate_conf_option(record, name, value, PGC_S_FILE, ERROR, true, NULL, &newextra)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": \"%s\"", name, value))); + + + rc = snprintf_s(ConfFileName, MAXPGPATH, MAXPGPATH - 1, "%s/%s", t_thrd.proc_cxt.DataDir, GUCCONF_FILE); + securec_check_ss(rc, "\0", "\0"); + rc = snprintf_s(ConfTmpFileName, MAXPGPATH, MAXPGPATH - 1, "%s/%s", t_thrd.proc_cxt.DataDir, GUCCONF_FILE_BAK); + securec_check_ss(rc, "\0", "\0"); + rc = snprintf_s(ConfLockFileName, MAXPGPATH, MAXPGPATH - 1, "%s/%s", t_thrd.proc_cxt.DataDir, GUCCONF_FILE_LOCK); + securec_check_ss(rc, "\0", "\0"); + rc = snprintf_s(ConfTmpBakFileName, MAXPGPATH, MAXPGPATH - 1, + "%s/%s", t_thrd.proc_cxt.DataDir, GUCCONF_FILE_BAK_BAK); + securec_check_ss(rc, "\0", "\0"); + + /* + * one backend is allowed to operate on postgresql.conf.bak file, to + * ensure that we need to update the contents of the file with + * AutoFileLock. To ensure crash safety, first the contents are written to + * temporary file and then rename it to postgresql.auto.conf. In case + * there exists a temp file from previous crash, that can be reused. + */ + char** opt_lines = NULL; + if (stat(ConfFileName, &st) == 0 && get_file_lock(ConfLockFileName, &filelock) == CODE_OK) { + opt_lines = read_guc_file(ConfFileName); + } else { + ereport(ERROR, + (errcode(ERRCODE_FILE_READ_FAILED), + errmsg("File does not exits or it is being used.Can not open file: %s.", ConfFileName))); + } + + /* + * replace with new value if the configuration parameter already + * exists OR add it as a new cofiguration parameter in the file. + */ + replace_config_value(opt_lines, name, value, record->vartype); + ret = write_guc_file(ConfTmpFileName, opt_lines); + release_opt_lines(opt_lines); + if (ret != CODE_OK) { + release_file_lock(&filelock); + ereport(ERROR, + (errcode(ERRCODE_FILE_WRITE_FAILED), + errmsg("write %s failed: %s.", ConfTmpFileName, gs_strerror(ret)))); + } + + /* we should leave postgresql.conf.bak like gs_guc */ + opt_lines = read_guc_file(ConfTmpFileName); + ret = write_guc_file(ConfTmpBakFileName, opt_lines); + release_opt_lines(opt_lines); + opt_lines = NULL; + if (ret != CODE_OK) { + release_file_lock(&filelock); + ereport(ERROR, + (errcode(ERRCODE_FILE_WRITE_FAILED), + errmsg("write %s failed: %s.", ConfTmpBakFileName, gs_strerror(ret)))); + } + + /* + * As the rename is atomic operation, if any problem occurs after this + * at max it can loose the parameters set by last ALTER SYSTEM SET + * command. + */ + if (rename(ConfTmpBakFileName, ConfFileName) < 0) { + release_file_lock(&filelock); + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not rename file \"%s\" to \"%s\"", ConfTmpFileName, ConfFileName))); + } + + release_file_lock(&filelock); + + /* + * send signal to postmaster to reload postgresql.conf, POSTMASTER-level variable + * takes effect only after restarting the database, but we still need to send the + * signal so that we can send the postgresql.conf to standby node. + */ + if (gs_signal_send(PostmasterPid, SIGHUP)) { + ereport(WARNING, (errmsg("Failed to send signal to postmaster to reload guc config file."))); + return; + } + + /* print notice message */ + switch (record->context) { + case PGC_POSTMASTER: + ereport(NOTICE, + (errmsg("please restart the database for the POSTMASTER level parameter to take effect."))); + break; + case PGC_BACKEND: + ereport(NOTICE, + (errmsg("please reconnect the database for the BACKEND level parameter to take effect."))); + break; + default: + break; + } + } + /* * SET command */ @@ -20066,7 +20393,7 @@ char** read_guc_file(const char* path) } /* set up the result and the line buffer */ - result = (char**)pg_malloc((nlines + 1) * sizeof(char*)); + result = (char**)pg_malloc((nlines + 2) * sizeof(char*)); // Reserve one extra for alter system set. buffer = (char*)pg_malloc(maxlength + 1); /* now reprocess the file and store the lines */ @@ -20078,7 +20405,7 @@ char** read_guc_file(const char* path) } (void)fclose(infile); pfree(buffer); - result[nlines] = NULL; + result[nlines] = result[nlines + 1] = NULL; return result; } diff --git a/src/gausskernel/process/tcop/auditfuncs.cpp b/src/gausskernel/process/tcop/auditfuncs.cpp index 9d9f3b4939..aea67be732 100644 --- a/src/gausskernel/process/tcop/auditfuncs.cpp +++ b/src/gausskernel/process/tcop/auditfuncs.cpp @@ -1313,6 +1313,10 @@ static void pgaudit_ProcessUtility(Node* parsetree, const char* queryString, Par VariableSetStmt* variablesetstmt = (VariableSetStmt*)(parsetree); pgaudit_process_set_parameter(variablesetstmt->name, queryString); } break; + case T_AlterSystemStmt: { + AlterSystemStmt* altersystemstmt = (AlterSystemStmt*)(parsetree); + pgaudit_process_set_parameter(altersystemstmt->setstmt->name, queryString); + } break; case T_CreateDataSourceStmt: { CreateDataSourceStmt* createdatasourcestmt = (CreateDataSourceStmt*)(parsetree); pgaudit_ddl_datasource(createdatasourcestmt->srcname, queryString); diff --git a/src/gausskernel/process/tcop/utility.cpp b/src/gausskernel/process/tcop/utility.cpp index 51026a4212..35ca4c7638 100644 --- a/src/gausskernel/process/tcop/utility.cpp +++ b/src/gausskernel/process/tcop/utility.cpp @@ -4787,6 +4787,11 @@ void standard_ProcessUtility(Node* parse_tree, const char* query_string, ParamLi ExecCreateTableAs((CreateTableAsStmt*)parse_tree, query_string, params, completion_tag); break; + case T_AlterSystemStmt: + PreventTransactionChain(is_top_level, "ALTER SYSTEM SET"); + AlterSystemSetConfigFile((AlterSystemStmt*)parse_tree); + break; + case T_VariableSetStmt: ExecSetVariableStmt((VariableSetStmt*)parse_tree); #ifdef PGXC @@ -7175,6 +7180,10 @@ const char* CreateCommandTag(Node* parse_tree) tag = "CREATE TABLE AS"; break; + case T_AlterSystemStmt: + tag = "ALTER SYSTEM SET"; + break; + case T_VariableSetStmt: switch (((VariableSetStmt*)parse_tree)->kind) { case VAR_SET_VALUE: @@ -8020,6 +8029,10 @@ LogStmtLevel GetCommandLogLevel(Node* parse_tree) lev = LOGSTMT_DDL; break; + case T_AlterSystemStmt: + lev = LOGSTMT_DDL; + break; + case T_VariableSetStmt: lev = LOGSTMT_ALL; break; diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index a94b7bcdbc..067fe7c962 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -452,6 +452,7 @@ typedef enum NodeTag { T_DropDirectoryStmt, T_CreateRlsPolicyStmt, T_AlterRlsPolicyStmt, + T_AlterSystemStmt, /* * TAGS FOR PARSE TREE NODES (parsenodes.h) diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 9205bcfbf7..ea707833e0 100755 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2901,6 +2901,15 @@ typedef struct DropdbStmt { bool missing_ok; /* skip error if db is missing? */ } DropdbStmt; +/* ---------------------- + * Alter System Statement + * ---------------------- + */ +typedef struct AlterSystemStmt { + NodeTag type; + VariableSetStmt *setstmt; /* SET subcommand */ +} AlterSystemStmt; + /* ---------------------- * Cluster Statement (support pbrown's cluster index implementation) * ---------------------- diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 44fb5e3883..b41bbc9991 100755 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -162,6 +162,7 @@ PG_KEYWORD("direct", DIRECT, UNRESERVED_KEYWORD) PG_KEYWORD("directory", DIRECTORY, UNRESERVED_KEYWORD) PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD) PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD) +PG_KEYWORD("disconnect", DISCONNECT, UNRESERVED_KEYWORD) PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD) #ifdef PGXC PG_KEYWORD("distribute", DISTRIBUTE, UNRESERVED_KEYWORD) @@ -269,6 +270,7 @@ PG_KEYWORD("isnull", ISNULL, UNRESERVED_KEYWORD) PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD) PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD) +PG_KEYWORD("kill", KILL, UNRESERVED_KEYWORD) PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD) PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD) PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD) diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 61177a702b..14640be878 100755 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -245,6 +245,7 @@ extern bool parse_int64(const char* value, int64* result, const char** hintmsg); extern bool parse_real(const char* value, double* result); extern int set_config_option(const char* name, const char* value, GucContext context, GucSource source, GucAction action, bool changeVal, int elevel, bool isReload = false); +extern void AlterSystemSetConfigFile(AlterSystemStmt * setstmt); extern char* GetConfigOptionByName(const char* name, const char** varname); extern void GetConfigOptionByNum(int varnum, const char** values, bool* noshow); extern int GetNumConfigOptions(void); diff --git a/src/test/regress/expected/alter_system_set.out b/src/test/regress/expected/alter_system_set.out new file mode 100644 index 0000000000..4380095875 --- /dev/null +++ b/src/test/regress/expected/alter_system_set.out @@ -0,0 +1,406 @@ +---------------------------------------------------------- +-- The common user should not have the permission. +--------------------------------------------------------- +DROP ROLE IF EXISTS alter_system_testuser; +NOTICE: role "alter_system_testuser" does not exist, skipping +CREATE USER alter_system_testuser PASSWORD 'test@1233'; +SET SESSION AUTHORIZATION alter_system_testuser PASSWORD 'test@1233'; +show use_workload_manager; + use_workload_manager +---------------------- + on +(1 row) + +ALTER SYSTEM SET use_workload_manager to off; +ERROR: must be superuser to execute ALTER SYSTEM SET command +show io_limits; + io_limits +----------- + 0 +(1 row) + +ALTER SYSTEM SET io_limits to 100; +ERROR: must be superuser to execute ALTER SYSTEM SET command +select pg_sleep(1); -- wait to reload postgres.conf file + pg_sleep +---------- + +(1 row) + +show use_workload_manager; + use_workload_manager +---------------------- + on +(1 row) + +show io_limits; + io_limits +----------- + 0 +(1 row) + +\c +DROP user alter_system_testuser; +------------------------------------------------------- +-- clear pg_query_audit for the last test +------------------------------------------------------- +show audit_enabled; + audit_enabled +--------------- + on +(1 row) + +show audit_set_parameter; + audit_set_parameter +--------------------- + 1 +(1 row) + +show audit_user_violation; + audit_user_violation +---------------------- + 1 +(1 row) + +SELECT pg_delete_audit('2000-01-01 ','9999-01-01'); + pg_delete_audit +----------------- + +(1 row) + +-------------------------------------------------------- +-- for POSTMASTER GUC +-------------------------------------------------------- +SHOW enable_thread_pool; + enable_thread_pool +-------------------- + on +(1 row) + +ALTER SYSTEM SET enable_thread_pool to off; +NOTICE: please restart the database for the POSTMASTER level parameter to take effect. +ALTER SYSTEM SET enable_thread_pool to on; +NOTICE: please restart the database for the POSTMASTER level parameter to take effect. +------------------------------------------------------ +-- for SIGHUP GUC +------------------------------------------------------ +-- change +SHOW password_lock_time; + password_lock_time +-------------------- + 1 +(1 row) + +ALTER SYSTEM SET password_lock_time to 1.1; +SHOW autovacuum; + autovacuum +------------ + on +(1 row) + +ALTER SYSTEM SET autovacuum to off; +SHOW log_destination; + log_destination +----------------- + stderr +(1 row) + +ALTER SYSTEM SET log_destination to 'stderr,csvlog'; +SHOW autovacuum_mode; + autovacuum_mode +----------------- + mix +(1 row) + +ALTER SYSTEM SET autovacuum_mode to 'analyze'; +SHOW parctl_min_cost; + parctl_min_cost +----------------- + 100000 +(1 row) + +ALTER SYSTEM SET parctl_min_cost TO 1000; +select pg_sleep(2); -- wait to reload postgres.conf file + pg_sleep +---------- + +(1 row) + +-- check result and change back. +SHOW password_lock_time; + password_lock_time +-------------------- + 1.1 +(1 row) + +ALTER SYSTEM SET password_lock_time to 1; +SHOW autovacuum; + autovacuum +------------ + off +(1 row) + +ALTER SYSTEM SET autovacuum to on; +SHOW log_destination; + log_destination +----------------- + stderr,csvlog +(1 row) + +ALTER SYSTEM SET log_destination to 'stderr'; +SHOW autovacuum_mode; + autovacuum_mode +----------------- + analyze +(1 row) + +ALTER SYSTEM SET autovacuum_mode to mix; +SHOW parctl_min_cost; + parctl_min_cost +----------------- + 1000 +(1 row) + +ALTER SYSTEM SET parctl_min_cost TO 100000; +select pg_sleep(2); -- wait to reload postgres.conf file + pg_sleep +---------- + +(1 row) + +SHOW password_lock_time; + password_lock_time +-------------------- + 1 +(1 row) + +SHOW autovacuum; + autovacuum +------------ + on +(1 row) + +SHOW log_destination; + log_destination +----------------- + stderr +(1 row) + +SHOW autovacuum_mode; + autovacuum_mode +----------------- + mix +(1 row) + +SHOW parctl_min_cost; + parctl_min_cost +----------------- + 100000 +(1 row) + +-- some err case +ALTER SYSTEM SET password_lock_time to true; +ERROR: parameter "password_lock_time" requires a numeric value +ALTER SYSTEM SET autovacuum to 'lalala'; +ERROR: parameter "autovacuum" requires a Boolean value +ALTER SYSTEM SET log_destination to 'abcdefg'; +ERROR: invalid value for parameter "log_destination": "abcdefg" +DETAIL: Unrecognized key word: "abcdefg". +ALTER SYSTEM SET autovacuum_mode to 123; +ERROR: invalid value for parameter "autovacuum_mode": "123" +HINT: Available values: analyze, vacuum, mix, none. +ALTER SYSTEM SET autovacuum_mode to lalala; +ERROR: invalid value for parameter "autovacuum_mode": "lalala" +HINT: Available values: analyze, vacuum, mix, none. +ALTER SYSTEM SET parctl_min_cost TO -100; +ERROR: -100 is outside the valid range for parameter "parctl_min_cost" (-1 .. 2147483647) +ALTER SYSTEM SET parctl_min_cost TO 1.1; +ERROR: invalid value for parameter "parctl_min_cost": "1.1" +select pg_sleep(2); -- wait to reload postgres.conf file + pg_sleep +---------- + +(1 row) + +SHOW password_lock_time; + password_lock_time +-------------------- + 1 +(1 row) + +SHOW autovacuum; + autovacuum +------------ + on +(1 row) + +SHOW log_destination; + log_destination +----------------- + stderr +(1 row) + +SHOW autovacuum_mode; + autovacuum_mode +----------------- + mix +(1 row) + +SHOW parctl_min_cost; + parctl_min_cost +----------------- + 100000 +(1 row) + +------------------------------------------------------ +-- FOR BACKEND GUC +------------------------------------------------------ +show ignore_system_indexes; + ignore_system_indexes +----------------------- + off +(1 row) + +ALTER SYSTEM SET ignore_system_indexes TO on; +NOTICE: please reconnect the database for the BACKEND level parameter to take effect. +show ignore_system_indexes; + ignore_system_indexes +----------------------- + off +(1 row) + +ALTER SYSTEM SET ignore_system_indexes TO off; +NOTICE: please reconnect the database for the BACKEND level parameter to take effect. +show ignore_system_indexes; + ignore_system_indexes +----------------------- + off +(1 row) + +---------------------------------------------------- +-- for USERSET GUC +---------------------------------------------------- +show io_limits; + io_limits +----------- + 0 +(1 row) + +ALTER SYSTEM SET io_limits to 100; +ERROR: unsupport parameter: io_limits +ALTER SYSTEM SET only support POSTMASTER-level, SIGHUP-level and BACKEND-level guc variable, +and it must be allowed to set in postgresql.conf. +show io_limits; + io_limits +----------- + 0 +(1 row) + +ALTER SYSTEM SET io_limits to 0; +ERROR: unsupport parameter: io_limits +ALTER SYSTEM SET only support POSTMASTER-level, SIGHUP-level and BACKEND-level guc variable, +and it must be allowed to set in postgresql.conf. +show io_limits; + io_limits +----------- + 0 +(1 row) + +----------------------------------------------------- +-- for SUSET GUC +---------------------------------------------------- +show autoanalyze; + autoanalyze +------------- + off +(1 row) + +ALTER SYSTEM SET autoanalyze to on; +ERROR: unsupport parameter: autoanalyze +ALTER SYSTEM SET only support POSTMASTER-level, SIGHUP-level and BACKEND-level guc variable, +and it must be allowed to set in postgresql.conf. +show autoanalyze; + autoanalyze +------------- + off +(1 row) + +ALTER SYSTEM SET autoanalyze to off; +ERROR: unsupport parameter: autoanalyze +ALTER SYSTEM SET only support POSTMASTER-level, SIGHUP-level and BACKEND-level guc variable, +and it must be allowed to set in postgresql.conf. +show autoanalyze; + autoanalyze +------------- + off +(1 row) + +----------------------------------------------------- +-- UNSUPPORT SET TO DEFAULT +----------------------------------------------------- +SHOW parctl_min_cost; + parctl_min_cost +----------------- + 100000 +(1 row) + +ALTER SYSTEM SET parctl_min_cost TO 1000; +ALTER SYSTEM SET parctl_min_cost TO default; +ERROR: ALTER SYSTEM SET does not support 'set to default'. +select pg_sleep(1); + pg_sleep +---------- + +(1 row) + +SHOW parctl_min_cost; + parctl_min_cost +----------------- + 1000 +(1 row) + +ALTER SYSTEM SET parctl_min_cost TO 100000; +------------------------------------------------------- +-- can not in a transaction +------------------------------------------------------- +BEGIN; +SHOW autovacuum; + autovacuum +------------ + on +(1 row) + +ALTER SYSTEM SET autovacuum to off; +ERROR: ALTER SYSTEM SET cannot run inside a transaction block +SHOW autovacuum; +ERROR: current transaction is aborted, commands ignored until end of transaction block +ALTER SYSTEM SET autovacuum to on; +ERROR: current transaction is aborted, commands ignored until end of transaction block +SHOW autovacuum; +ERROR: current transaction is aborted, commands ignored until end of transaction block +END; +------------------------------------------------------- +-- shoule be audited. +------------------------------------------------------ +SELECT type,result,userid,database,client_conninfo,object_name,detail_info FROM pg_query_audit('2000-01-01 08:00:00','9999-01-01 08:00:00'); + type | result | userid | database | client_conninfo | object_name | detail_info +----------------+--------+--------+------------+-----------------+-----------------------+------------------------------------------------------ + internal_event | ok | 10 | regression | gsql@[local] | null | SELECT pg_delete_audit('2000-01-01 ','9999-01-01'); + set_parameter | ok | 10 | regression | gsql@[local] | enable_thread_pool | ALTER SYSTEM SET enable_thread_pool to off; + set_parameter | ok | 10 | regression | gsql@[local] | enable_thread_pool | ALTER SYSTEM SET enable_thread_pool to on; + set_parameter | ok | 10 | regression | gsql@[local] | password_lock_time | ALTER SYSTEM SET password_lock_time to 1.1; + set_parameter | ok | 10 | regression | gsql@[local] | autovacuum | ALTER SYSTEM SET autovacuum to off; + set_parameter | ok | 10 | regression | gsql@[local] | log_destination | ALTER SYSTEM SET log_destination to 'stderr,csvlog'; + set_parameter | ok | 10 | regression | gsql@[local] | autovacuum_mode | ALTER SYSTEM SET autovacuum_mode to 'analyze'; + set_parameter | ok | 10 | regression | gsql@[local] | parctl_min_cost | ALTER SYSTEM SET parctl_min_cost TO 1000; + set_parameter | ok | 10 | regression | gsql@[local] | password_lock_time | ALTER SYSTEM SET password_lock_time to 1; + set_parameter | ok | 10 | regression | gsql@[local] | autovacuum | ALTER SYSTEM SET autovacuum to on; + set_parameter | ok | 10 | regression | gsql@[local] | log_destination | ALTER SYSTEM SET log_destination to 'stderr'; + set_parameter | ok | 10 | regression | gsql@[local] | autovacuum_mode | ALTER SYSTEM SET autovacuum_mode to mix; + set_parameter | ok | 10 | regression | gsql@[local] | parctl_min_cost | ALTER SYSTEM SET parctl_min_cost TO 100000; + set_parameter | ok | 10 | regression | gsql@[local] | ignore_system_indexes | ALTER SYSTEM SET ignore_system_indexes TO on; + set_parameter | ok | 10 | regression | gsql@[local] | ignore_system_indexes | ALTER SYSTEM SET ignore_system_indexes TO off; + set_parameter | ok | 10 | regression | gsql@[local] | parctl_min_cost | ALTER SYSTEM SET parctl_min_cost TO 1000; + set_parameter | ok | 10 | regression | gsql@[local] | parctl_min_cost | ALTER SYSTEM SET parctl_min_cost TO 100000; +(17 rows) + diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index 55404c2684..7b1f380687 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -25,6 +25,7 @@ test: create_view1 create_view2 create_view3 create_view4 create_view5 int8 test: select test: misc test: stats +test: alter_system_set #dispatch from 13 test: function diff --git a/src/test/regress/parallel_schedule1 b/src/test/regress/parallel_schedule1 index 3c781cb987..c3912981b0 100644 --- a/src/test/regress/parallel_schedule1 +++ b/src/test/regress/parallel_schedule1 @@ -21,4 +21,5 @@ test: create_view1 create_view2 create_view3 create_view4 create_view5 int8 #dupliacated select int8 test: select test: misc -test: stats \ No newline at end of file +test: stats +test: alter_system_set diff --git a/src/test/regress/sql/alter_system_set.sql b/src/test/regress/sql/alter_system_set.sql new file mode 100644 index 0000000000..7ebf9eefd0 --- /dev/null +++ b/src/test/regress/sql/alter_system_set.sql @@ -0,0 +1,149 @@ +---------------------------------------------------------- +-- The common user should not have the permission. +--------------------------------------------------------- + +DROP ROLE IF EXISTS alter_system_testuser; +CREATE USER alter_system_testuser PASSWORD 'test@1233'; + +SET SESSION AUTHORIZATION alter_system_testuser PASSWORD 'test@1233'; +show use_workload_manager; +ALTER SYSTEM SET use_workload_manager to off; +show io_limits; +ALTER SYSTEM SET io_limits to 100; +select pg_sleep(1); -- wait to reload postgres.conf file +show use_workload_manager; +show io_limits; + +\c +DROP user alter_system_testuser; + +------------------------------------------------------- +-- clear pg_query_audit for the last test +------------------------------------------------------- +show audit_enabled; +show audit_set_parameter; +show audit_user_violation; +SELECT pg_delete_audit('2000-01-01 ','9999-01-01'); + + +-------------------------------------------------------- +-- for POSTMASTER GUC +-------------------------------------------------------- +SHOW enable_thread_pool; +ALTER SYSTEM SET enable_thread_pool to off; +ALTER SYSTEM SET enable_thread_pool to on; + +------------------------------------------------------ +-- for SIGHUP GUC +------------------------------------------------------ +-- change +SHOW password_lock_time; +ALTER SYSTEM SET password_lock_time to 1.1; +SHOW autovacuum; +ALTER SYSTEM SET autovacuum to off; +SHOW log_destination; +ALTER SYSTEM SET log_destination to 'stderr,csvlog'; +SHOW autovacuum_mode; +ALTER SYSTEM SET autovacuum_mode to 'analyze'; +SHOW parctl_min_cost; +ALTER SYSTEM SET parctl_min_cost TO 1000; + + +select pg_sleep(2); -- wait to reload postgres.conf file + + +-- check result and change back. +SHOW password_lock_time; +ALTER SYSTEM SET password_lock_time to 1; +SHOW autovacuum; +ALTER SYSTEM SET autovacuum to on; +SHOW log_destination; +ALTER SYSTEM SET log_destination to 'stderr'; +SHOW autovacuum_mode; +ALTER SYSTEM SET autovacuum_mode to mix; +SHOW parctl_min_cost; +ALTER SYSTEM SET parctl_min_cost TO 100000; + +select pg_sleep(2); -- wait to reload postgres.conf file + +SHOW password_lock_time; +SHOW autovacuum; +SHOW log_destination; +SHOW autovacuum_mode; +SHOW parctl_min_cost; + + + +-- some err case +ALTER SYSTEM SET password_lock_time to true; +ALTER SYSTEM SET autovacuum to 'lalala'; +ALTER SYSTEM SET log_destination to 'abcdefg'; +ALTER SYSTEM SET autovacuum_mode to 123; +ALTER SYSTEM SET autovacuum_mode to lalala; +ALTER SYSTEM SET parctl_min_cost TO -100; +ALTER SYSTEM SET parctl_min_cost TO 1.1; + +select pg_sleep(2); -- wait to reload postgres.conf file + +SHOW password_lock_time; +SHOW autovacuum; +SHOW log_destination; +SHOW autovacuum_mode; +SHOW parctl_min_cost; + +------------------------------------------------------ +-- FOR BACKEND GUC +------------------------------------------------------ +show ignore_system_indexes; +ALTER SYSTEM SET ignore_system_indexes TO on; +show ignore_system_indexes; +ALTER SYSTEM SET ignore_system_indexes TO off; +show ignore_system_indexes; + + +---------------------------------------------------- +-- for USERSET GUC +---------------------------------------------------- +show io_limits; +ALTER SYSTEM SET io_limits to 100; +show io_limits; +ALTER SYSTEM SET io_limits to 0; +show io_limits; + + +----------------------------------------------------- +-- for SUSET GUC +---------------------------------------------------- +show autoanalyze; +ALTER SYSTEM SET autoanalyze to on; +show autoanalyze; +ALTER SYSTEM SET autoanalyze to off; +show autoanalyze; + + +----------------------------------------------------- +-- UNSUPPORT SET TO DEFAULT +----------------------------------------------------- +SHOW parctl_min_cost; +ALTER SYSTEM SET parctl_min_cost TO 1000; +ALTER SYSTEM SET parctl_min_cost TO default; +select pg_sleep(1); +SHOW parctl_min_cost; +ALTER SYSTEM SET parctl_min_cost TO 100000; + +------------------------------------------------------- +-- can not in a transaction +------------------------------------------------------- +BEGIN; +SHOW autovacuum; +ALTER SYSTEM SET autovacuum to off; +SHOW autovacuum; +ALTER SYSTEM SET autovacuum to on; +SHOW autovacuum; +END; + +------------------------------------------------------- +-- shoule be audited. +------------------------------------------------------ +SELECT type,result,userid,database,client_conninfo,object_name,detail_info FROM pg_query_audit('2000-01-01 08:00:00','9999-01-01 08:00:00'); + -- Gitee From 32f2735a38dbf186e8259f42524cecf5c65e4548 Mon Sep 17 00:00:00 2001 From: gentle_hu Date: Wed, 12 Aug 2020 22:49:27 +0800 Subject: [PATCH 2/2] modify test case to fix CI --- src/test/regress/expected/alter_system_set.out | 8 ++++---- src/test/regress/sql/alter_system_set.sql | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/regress/expected/alter_system_set.out b/src/test/regress/expected/alter_system_set.out index 4380095875..2e776a2312 100644 --- a/src/test/regress/expected/alter_system_set.out +++ b/src/test/regress/expected/alter_system_set.out @@ -74,13 +74,13 @@ SELECT pg_delete_audit('2000-01-01 ','9999-01-01'); SHOW enable_thread_pool; enable_thread_pool -------------------- - on + off (1 row) -ALTER SYSTEM SET enable_thread_pool to off; -NOTICE: please restart the database for the POSTMASTER level parameter to take effect. ALTER SYSTEM SET enable_thread_pool to on; NOTICE: please restart the database for the POSTMASTER level parameter to take effect. +ALTER SYSTEM SET enable_thread_pool to off; +NOTICE: please restart the database for the POSTMASTER level parameter to take effect. ------------------------------------------------------ -- for SIGHUP GUC ------------------------------------------------------ @@ -386,8 +386,8 @@ SELECT type,result,userid,database,client_conninfo,object_name,detail_info FROM type | result | userid | database | client_conninfo | object_name | detail_info ----------------+--------+--------+------------+-----------------+-----------------------+------------------------------------------------------ internal_event | ok | 10 | regression | gsql@[local] | null | SELECT pg_delete_audit('2000-01-01 ','9999-01-01'); - set_parameter | ok | 10 | regression | gsql@[local] | enable_thread_pool | ALTER SYSTEM SET enable_thread_pool to off; set_parameter | ok | 10 | regression | gsql@[local] | enable_thread_pool | ALTER SYSTEM SET enable_thread_pool to on; + set_parameter | ok | 10 | regression | gsql@[local] | enable_thread_pool | ALTER SYSTEM SET enable_thread_pool to off; set_parameter | ok | 10 | regression | gsql@[local] | password_lock_time | ALTER SYSTEM SET password_lock_time to 1.1; set_parameter | ok | 10 | regression | gsql@[local] | autovacuum | ALTER SYSTEM SET autovacuum to off; set_parameter | ok | 10 | regression | gsql@[local] | log_destination | ALTER SYSTEM SET log_destination to 'stderr,csvlog'; diff --git a/src/test/regress/sql/alter_system_set.sql b/src/test/regress/sql/alter_system_set.sql index 7ebf9eefd0..6fc0608c71 100644 --- a/src/test/regress/sql/alter_system_set.sql +++ b/src/test/regress/sql/alter_system_set.sql @@ -30,8 +30,8 @@ SELECT pg_delete_audit('2000-01-01 ','9999-01-01'); -- for POSTMASTER GUC -------------------------------------------------------- SHOW enable_thread_pool; -ALTER SYSTEM SET enable_thread_pool to off; ALTER SYSTEM SET enable_thread_pool to on; +ALTER SYSTEM SET enable_thread_pool to off; ------------------------------------------------------ -- for SIGHUP GUC -- Gitee