diff --git a/src/common/backend/nodes/copyfuncs.cpp b/src/common/backend/nodes/copyfuncs.cpp index ed00b8bf..b59d404e 100644 --- a/src/common/backend/nodes/copyfuncs.cpp +++ b/src/common/backend/nodes/copyfuncs.cpp @@ -5713,6 +5713,13 @@ static BloomFilterSet* _copyBloomFilterSet(const BloomFilterSet* from) return newnode; } +static ShutdownStmt* _copyShutdownStmt(const ShutdownStmt* from) +{ + ShutdownStmt* newnode = makeNode(ShutdownStmt); + COPY_STRING_FIELD(mode); + return newnode; +} + /* * copyObject * @@ -6766,6 +6773,11 @@ void* copyObject(const void* from) case T_DropDirectoryStmt: retval = _copyDropDirectoryStmt((DropDirectoryStmt*)from); break; + + /* shutdown */ + case T_ShutdownStmt: + retval = _copyShutdownStmt((ShutdownStmt*)from); + break; default: ereport(ERROR, (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("unrecognized node type: %d", (int)nodeTag(from)))); diff --git a/src/common/backend/nodes/equalfuncs.cpp b/src/common/backend/nodes/equalfuncs.cpp index 26fc7d68..11c00244 100755 --- a/src/common/backend/nodes/equalfuncs.cpp +++ b/src/common/backend/nodes/equalfuncs.cpp @@ -2690,6 +2690,12 @@ static bool _equalGroupingId(const GroupingId* a, const GroupingId* b) return true; } +static bool _equalShutDown(const ShutdownStmt* a, const ShutdownStmt* b) +{ + COMPARE_STRING_FIELD(mode); + return true; +} + /* * equal * returns whether two nodes are equal @@ -3298,6 +3304,9 @@ bool equal(const void* a, const void* b) case T_AlterTSConfigurationStmt: retval = _equalAlterTSConfigurationStmt((AlterTSConfigurationStmt*)a, (AlterTSConfigurationStmt*)b); break; + case T_ShutdownStmt: + retval = _equalShutDown((ShutdownStmt*)a, (ShutdownStmt*)b); + break; case T_A_Expr: retval = _equalAExpr((A_Expr*)a, (A_Expr*)b); diff --git a/src/common/backend/nodes/nodes.cpp b/src/common/backend/nodes/nodes.cpp index 65b3a38d..98d84cd0 100755 --- a/src/common/backend/nodes/nodes.cpp +++ b/src/common/backend/nodes/nodes.cpp @@ -381,6 +381,7 @@ static const TagStr g_tagStrArr[] = {{T_Invalid, "Invalid"}, {T_DropDirectoryStmt, "DropDirectoryStmt"}, {T_CreateRlsPolicyStmt, "CreateRlsPolicyStmt"}, {T_AlterRlsPolicyStmt, "AlterRlsPolicyStmt"}, + {T_ShutdownStmt, "ShutdownStmt"}, {T_A_Expr, "A_Expr"}, {T_ColumnRef, "ColumnRef"}, {T_ParamRef, "ParamRef"}, diff --git a/src/common/backend/parser/gram.y b/src/common/backend/parser/gram.y index 7b3ef93c..3e17a8ce 100755 --- a/src/common/backend/parser/gram.y +++ b/src/common/backend/parser/gram.y @@ -273,7 +273,7 @@ static void ParseUpdateMultiSet(List *set_target_list, SelectStmt *stmt, core_yy RuleActionStmt RuleActionStmtOrEmpty RuleStmt SecLabelStmt SelectStmt TransactionStmt TruncateStmt CallFuncStmt UnlistenStmt UpdateStmt VacuumStmt - VariableResetStmt VariableSetStmt VariableShowStmt VerifyStmt + VariableResetStmt VariableSetStmt VariableShowStmt VerifyStmt ShutdownStmt ViewStmt CheckPointStmt CreateConversionStmt DeallocateStmt PrepareStmt ExecuteStmt DropOwnedStmt ReassignOwnedStmt @@ -684,7 +684,7 @@ static void ParseUpdateMultiSet(List *set_target_list, SelectStmt *stmt, core_yy ROW ROWS RULE SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES - SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHIPPABLE SHOW + SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHIPPABLE SHOW SHUTDOWN SIMILAR SIMPLE SIZE SMALLDATETIME SMALLDATETIME_FORMAT_P SMALLINT SNAPSHOT SOME SOURCE_P SPACE SPILL SPLIT STABLE STANDALONE_P START STATEMENT STATEMENT_ID STATISTICS STDIN STDOUT STORAGE STORE_P STRICT_P STRIP_P SUBSTRING SYMMETRIC SYNONYM SYSDATE SYSID SYSTEM_P SYS_REFCURSOR @@ -976,6 +976,7 @@ stmt : | RuleStmt | SecLabelStmt | SelectStmt + | ShutdownStmt | TransactionStmt | TruncateStmt | UnlistenStmt @@ -2074,6 +2075,25 @@ constraints_set_mode: | IMMEDIATE { $$ = FALSE; } ; +/***************************************************************************** + * + * SHUTDOWN STATEMENT + * + *****************************************************************************/ +ShutdownStmt: + SHUTDOWN + { + ShutdownStmt *n = makeNode(ShutdownStmt); + n->mode = NULL; + $$ = (Node *) n; + } + | SHUTDOWN var_name + { + ShutdownStmt *n = makeNode(ShutdownStmt); + n->mode = $2; + $$ = (Node *) n; + } + ; /* * Checkpoint statement @@ -17842,6 +17862,7 @@ unreserved_keyword: | SHARE | SHIPPABLE | SHOW + | SHUTDOWN | SIMPLE | SIZE | SMALLDATETIME_FORMAT_P diff --git a/src/gausskernel/optimizer/commands/Makefile b/src/gausskernel/optimizer/commands/Makefile index d607e71c..d916b45b 100644 --- a/src/gausskernel/optimizer/commands/Makefile +++ b/src/gausskernel/optimizer/commands/Makefile @@ -24,6 +24,6 @@ OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \ portalcmds.o prepare.o proclang.o \ schemacmds.o seclabel.o sec_rls_cmds.o sequence.o tablecmds.o tablespace.o trigger.o \ tsearchcmds.o typecmds.o user.o vacuum.o vacuumlazy.o \ - variable.o verify.o view.o gds_stream.o obs_stream.o formatter.o datasourcecmds.o directory.o + variable.o verify.o view.o gds_stream.o obs_stream.o formatter.o datasourcecmds.o directory.o shutdown.o include $(top_srcdir)/src/gausskernel/common.mk diff --git a/src/gausskernel/optimizer/commands/shutdown.cpp b/src/gausskernel/optimizer/commands/shutdown.cpp new file mode 100644 index 00000000..90272d45 --- /dev/null +++ b/src/gausskernel/optimizer/commands/shutdown.cpp @@ -0,0 +1,45 @@ +/* ------------------------------------------------------------------------- + * + * shutdown.cpp + * do shutdown command + * + * Copyright (c) 2020 Huawei Technologies Co.,Ltd. + * + * IDENTIFICATION + * src/gausskernel/optimizer/commands/shutdown.cpp + * + * ------------------------------------------------------------------------- + */ + +#include "postgres.h" +#include "knl/knl_variable.h" +#include "miscadmin.h" +#include "commands/shutdown.h" + +void DoShutdown(ShutdownStmt* stmt) +{ + if (!superuser()) { + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("Only system admin can shutdown database.")))); + } + + int signal; + char* shutdown_mode = stmt->mode; + + if (shutdown_mode == NULL || strcmp(shutdown_mode, "fast") == 0) { + signal = SIGINT; + } else if (strcmp(shutdown_mode, "smart") == 0) { + signal = SIGTERM; + } else if (strcmp(shutdown_mode, "immediate") == 0) { + signal = SIGQUIT; + } else { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unknow parameter: %s\nshutdown only support fast, smart and immediate mode.\n", shutdown_mode))); + } + + if (gs_signal_send(PostmasterPid, signal)) { + ereport(WARNING, + (errmsg("Failed to send %s shutdown signal to postmaster.", shutdown_mode))); + } +} diff --git a/src/gausskernel/process/tcop/utility.cpp b/src/gausskernel/process/tcop/utility.cpp index b3d58ae6..0ffb60db 100755 --- a/src/gausskernel/process/tcop/utility.cpp +++ b/src/gausskernel/process/tcop/utility.cpp @@ -54,6 +54,7 @@ #include "commands/seclabel.h" #include "commands/sec_rls_cmds.h" #include "commands/sequence.h" +#include "commands/shutdown.h" #include "commands/tablecmds.h" #include "commands/tablespace.h" #include "commands/directory.h" @@ -4911,6 +4912,11 @@ void standard_ProcessUtility(Node* parse_tree, const char* query_string, ParamLi GetPGVariable(n->name, dest); } break; + case T_ShutdownStmt: { + ShutdownStmt* n = (ShutdownStmt*)parse_tree; + + DoShutdown(n); + } break; case T_DiscardStmt: #ifdef PGXC @@ -7517,6 +7523,9 @@ const char* CreateCommandTag(Node* parse_tree) case T_DropDirectoryStmt: tag = "DROP DIRECTORY"; break; + case T_ShutdownStmt: + tag = "SHUTDOWN"; + break; default: elog(WARNING, "unrecognized node type: %d", (int)nodeTag(parse_tree)); @@ -8235,6 +8244,10 @@ LogStmtLevel GetCommandLogLevel(Node* parse_tree) lev = LOGSTMT_DDL; break; + case T_ShutdownStmt: + lev = LOGSTMT_ALL; + break; + default: elog(WARNING, "unrecognized node type: %d", (int)nodeTag(parse_tree)); lev = LOGSTMT_ALL; diff --git a/src/include/commands/shutdown.h b/src/include/commands/shutdown.h new file mode 100644 index 00000000..0630e379 --- /dev/null +++ b/src/include/commands/shutdown.h @@ -0,0 +1,19 @@ +/* ------------------------------------------------------------------------- + * + * shutdown.h + * prototypes for shutdown.cpp + * + * Copyright (c) 2020 Huawei Technologies Co.,Ltd. + * + * src/include/commands/shutdown.h + * + * ------------------------------------------------------------------------- + */ +#ifndef SHUTDOWN_H +#define SHUTDOWN_H + +#include "nodes/parsenodes.h" + +extern void DoShutdown(ShutdownStmt* stmt); + +#endif /* SHUTDOWN_H */ diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 09d6bb2d..1be58883 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -389,6 +389,7 @@ typedef enum NodeTag { T_AlterSeqStmt, T_VariableSetStmt, T_VariableShowStmt, + T_ShutdownStmt, T_DiscardStmt, T_CreateTrigStmt, T_CreatePLangStmt, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 0c14db9a..9205bcfb 100755 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1768,6 +1768,15 @@ typedef struct VariableShowStmt { char* name; } VariableShowStmt; +/* ---------------------- + * Shutdown Statement + * ---------------------- + */ +typedef struct ShutdownStmt { + NodeTag type; + char* mode; +} ShutdownStmt; + /* * definition of a range partition. * range partition pattern: PARTITION [partitionName] LESS THAN [boundary] diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 3644ecba..d1cea3cf 100755 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -453,6 +453,7 @@ PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD) PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD) PG_KEYWORD("shippable", SHIPPABLE, UNRESERVED_KEYWORD) PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD) +PG_KEYWORD("shutdown", SHUTDOWN, UNRESERVED_KEYWORD) PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD) PG_KEYWORD("size", SIZE, UNRESERVED_KEYWORD) diff --git a/src/test/regress/expected/shutdown.out b/src/test/regress/expected/shutdown.out new file mode 100644 index 00000000..7fa10017 --- /dev/null +++ b/src/test/regress/expected/shutdown.out @@ -0,0 +1,20 @@ +DROP ROLE IF EXISTS shutdown_test; +NOTICE: role "shutdown_test" does not exist, skipping +CREATE USER shutdown_test WITH PASSWORD 'Shutdown@123'; +SET SESSION AUTHORIZATION shutdown_test PASSWORD 'Shutdown@123'; +shutdown; +ERROR: Only system admin can shutdown database. +shutdown invalid_str; +ERROR: Only system admin can shutdown database. +shutdown fast; +ERROR: Only system admin can shutdown database. +shutdown smart; +ERROR: Only system admin can shutdown database. +shutdown immediate; +ERROR: Only system admin can shutdown database. +\c +DROP USER shutdown_test; +shutdown invalid_str; +ERROR: unknow parameter: invalid_str +shutdown only support fast, smart and immediate mode. + diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index 0b34b570..43fe1c22 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -70,6 +70,7 @@ test: hw_procedure_define hw_anonymous_block hw_procedure test: hw_grant_all hw_dynamic_sql hw_func_return_out #test: hw_show_tabledef test: hw_package_function +test: shutdown #show plan test: plan_hint diff --git a/src/test/regress/parallel_schedule4 b/src/test/regress/parallel_schedule4 index 8730e691..a4b5d562 100644 --- a/src/test/regress/parallel_schedule4 +++ b/src/test/regress/parallel_schedule4 @@ -18,3 +18,4 @@ test: hw_procedure_define hw_anonymous_block hw_procedure test: hw_grant_all hw_dynamic_sql hw_func_return_out #test: hw_show_tabledef test: hw_package_function +test: shutdown diff --git a/src/test/regress/sql/shutdown.sql b/src/test/regress/sql/shutdown.sql new file mode 100644 index 00000000..e1ff576d --- /dev/null +++ b/src/test/regress/sql/shutdown.sql @@ -0,0 +1,17 @@ +DROP ROLE IF EXISTS shutdown_test; + +CREATE USER shutdown_test WITH PASSWORD 'Shutdown@123'; + +SET SESSION AUTHORIZATION shutdown_test PASSWORD 'Shutdown@123'; + +shutdown; +shutdown invalid_str; +shutdown fast; +shutdown smart; +shutdown immediate; + +\c + +DROP USER shutdown_test; + +shutdown invalid_str;