diff --git a/src/bin/gs_guc/cluster_guc.conf b/src/bin/gs_guc/cluster_guc.conf index fb2e7f87c..937b3c2e5 100755 --- a/src/bin/gs_guc/cluster_guc.conf +++ b/src/bin/gs_guc/cluster_guc.conf @@ -92,6 +92,7 @@ bbox_dump_count|int|1,20|NULL|NULL| bbox_dump_path|string|0,0|NULL|NULL| b_format_behavior_compat_options|string|0,0|NULL|NULL| behavior_compat_options|string|0,0|NULL|NULL| +disable_keyword_options|string|0,0|NULL|NULL| plsql_compile_check_options|string|0,0|NULL|NULL| bgwriter_delay|int|10,10000|ms|NULL| bgwriter_lru_maxpages|int|0,1000|NULL|NULL| diff --git a/src/common/backend/parser/parser.cpp b/src/common/backend/parser/parser.cpp index 2e698cf19..97afc0f7f 100644 --- a/src/common/backend/parser/parser.cpp +++ b/src/common/backend/parser/parser.cpp @@ -25,6 +25,7 @@ #include "parser/gramparse.h" #include "parser/parser.h" +#include "utils/guc.h" extern void resetOperatorPlusFlag(); @@ -799,3 +800,42 @@ char** get_next_snippet( return query_string_single; } + +const struct ignore_keyword_opt_data ignore_keywords[] = { + {"interval", INTERVAL} +}; +#define INGORE_KEYWORDS_LEN (sizeof(ignore_keywords) / sizeof(struct ignore_keyword_opt_data)) + +/* + * @Description: Avoid hooks, privides public interface, this can select ignore_keywords_list based on database + * compatibility to find ignore_keywords. + * @Param [IN] item: keyword + * @return token: token value for import item in ignore_keywords_list, if not in ignore_keywords_list, reutrn -1. + */ +int16 semtc_get_ignore_keyword_token(const char *item) +{ + const struct ignore_keyword_opt_data *ignore_keywords_list = ignore_keywords; + int ignore_keywords_length = (int)INGORE_KEYWORDS_LEN; + + for (int i = 0; i < ignore_keywords_length; i++) { + if (strcmp(item, ignore_keywords_list[i].option_name) == 0) { + return ignore_keywords_list[i].token; + } + } + return -1; +} + +bool semtc_is_token_in_ignore_keyword_list(int token, bool isPlpgsqlKeyword) +{ + ListCell *cell = NULL; + List *keyword_list = isPlpgsqlKeyword ? NULL : u_sess->utils_cxt.ignore_keyword_list; + foreach(cell, keyword_list) + { + int ignore_token = lfirst_int(cell); + if (token == ignore_token) { + return true; + } + } + return false; +} + diff --git a/src/common/backend/parser/scan.l b/src/common/backend/parser/scan.l index 3818200df..69b378c11 100755 --- a/src/common/backend/parser/scan.l +++ b/src/common/backend/parser/scan.l @@ -1128,8 +1128,9 @@ other . yyextra->is_hint_str = false; bool isPlpgsqlKeyword = yyextra->isPlpgsqlKeyWord; - - if (kwnum >= 0) + bool need_ignore = (!isPlpgsqlKeyword && kwnum >= 0) ? + semtc_is_token_in_ignore_keyword_list(yyextra->keyword_tokens[kwnum], false) : false; + if (kwnum >= 0 && !need_ignore) { yylval->keyword = GetScanKeyword(kwnum, yyextra->keywordlist); uint16 token = yyextra->keyword_tokens[kwnum]; diff --git a/src/common/backend/utils/misc/guc/guc_sql.cpp b/src/common/backend/utils/misc/guc/guc_sql.cpp index 2c1ed1eb1..2d5c88797 100755 --- a/src/common/backend/utils/misc/guc/guc_sql.cpp +++ b/src/common/backend/utils/misc/guc/guc_sql.cpp @@ -192,6 +192,8 @@ static bool check_snapshot_separator(char** newval, void** extra, GucSource sour static bool check_sql_ignore_strategy(char** newval, void** extra, GucSource source); static void assign_sql_ignore_strategy(const char* newval, void* extra); static void strategy_assign_vector_targetlist(int newval, void* extra); +static bool check_disable_keyword_options(char **newval, void **extra, GucSource source); +static void assign_disable_keyword_options(const char *newval, void *extra); static void InitSqlConfigureNamesBool(); static void InitSqlConfigureNamesInt(); @@ -2893,6 +2895,18 @@ static void InitSqlConfigureNamesString() check_behavior_compat_options, assign_behavior_compat_options, NULL}, + {{"disable_keyword_options", + PGC_USERSET, + NODE_ALL, + COMPAT_OPTIONS, + gettext_noop("compatibility keyword options"), + NULL, + GUC_LIST_INPUT | GUC_REPORT}, + &u_sess->attr.attr_sql.disable_keyword_string, + "", + check_disable_keyword_options, + assign_disable_keyword_options, + NULL}, {{"plsql_compile_check_options", PGC_USERSET, NODE_SINGLENODE, @@ -3665,6 +3679,73 @@ static void assign_behavior_compat_options(const char* newval, void* extra) u_sess->utils_cxt.behavior_compat_flags = result; } +static bool check_disable_keyword_options(char **newval, void **extra, GucSource source) +{ + char *rawstring = NULL; + List *elemlist = NULL; + ListCell *cell = NULL; + + /* Need a modifiable copy of string */ + rawstring = pstrdup(*newval); + /* Parse string into list of identifiers */ + if (!SplitIdentifierString(rawstring, ',', &elemlist)) { + /* syntax error in list */ + GUC_check_errdetail("invalid paramater for disable keyword information."); + pfree(rawstring); + list_free(elemlist); + + return false; + } + MemoryContext old_context = MemoryContextSwitchTo(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB)); + foreach(cell, elemlist) + { + const char *item = (const char *)lfirst(cell); + int token = semtc_get_ignore_keyword_token(item); + if (token < 0) { + GUC_check_errdetail("invalid disable keyword \"%s\"", item); + MemoryContextSwitchTo(old_context); + pfree(rawstring); + list_free(elemlist); + return false; + } + } + MemoryContextSwitchTo(old_context); + + pfree(rawstring); + list_free(elemlist); + + return true; +} + +static void assign_disable_keyword_options(const char *newval, void *extra) +{ + char *rawstring = NULL; + List *elemlist = NULL; + ListCell *cell = NULL; + List* result = NULL; + + rawstring = pstrdup(newval); + (void)SplitIdentifierString(rawstring, ',', &elemlist); + + list_free_ext(u_sess->utils_cxt.ignore_keyword_list); + MemoryContext old_context = MemoryContextSwitchTo(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB)); + foreach(cell, elemlist) + { + const char *item = (const char *)lfirst(cell); + + int token = semtc_get_ignore_keyword_token(item); + if (token >= 0) { + result = lappend_int(result, token); + } + } + MemoryContextSwitchTo(old_context); + + pfree(rawstring); + list_free(elemlist); + + u_sess->utils_cxt.ignore_keyword_list = result; +} + /* * check_behavior_compat_options: GUC check_hook for behavior compat options */ diff --git a/src/gausskernel/process/threadpool/knl_session.cpp b/src/gausskernel/process/threadpool/knl_session.cpp index 6390a1c9f..82abc762a 100755 --- a/src/gausskernel/process/threadpool/knl_session.cpp +++ b/src/gausskernel/process/threadpool/knl_session.cpp @@ -478,6 +478,7 @@ static void knl_u_utils_init(knl_u_utils_context* utils_cxt) utils_cxt->spi_printtupDR = (DestReceiver*)palloc0(sizeof(DestReceiver)); InitSpiPrinttupDR(utils_cxt->spi_printtupDR); + utils_cxt->ignore_keyword_list = NIL; } static void knl_u_security_init(knl_u_security_context* sec_cxt) { diff --git a/src/include/knl/knl_guc/knl_session_attr_sql.h b/src/include/knl/knl_guc/knl_session_attr_sql.h index ee24c2666..35a5b44b1 100644 --- a/src/include/knl/knl_guc/knl_session_attr_sql.h +++ b/src/include/knl/knl_guc/knl_session_attr_sql.h @@ -196,6 +196,7 @@ typedef struct knl_session_attr_sql { char* b_format_behavior_compat_string; char* behavior_compat_string; char* plsql_compile_behavior_compat_string; + char* disable_keyword_string; char* connection_info; char* retry_errcode_list; char* sql_ignore_strategy_string; diff --git a/src/include/knl/knl_session.h b/src/include/knl/knl_session.h index 36b4f5d2a..fccddde5d 100644 --- a/src/include/knl/knl_session.h +++ b/src/include/knl/knl_session.h @@ -696,6 +696,7 @@ typedef struct knl_u_utils_context { /* var in tsrank.cpp */ float tsrankWs[TSRANK_WEIGHTS_LEN]; + List* ignore_keyword_list; } knl_u_utils_context; typedef struct knl_u_security_context { diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index dacf02821..14e823061 100755 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -153,6 +153,11 @@ struct config_enum_entry { bool hidden; }; +struct ignore_keyword_opt_data { + const char* option_name; + uint16 token; +}; + /* * Signatures for per-variable check/assign/show hook functions */ @@ -555,6 +560,8 @@ extern char* SetVariableExprGetConfigOption(SetVariableExpr* set); #ifdef ENABLE_MULTIPLE_NODES extern const char* show_nodegroup_mode(void); #endif +extern int16 semtc_get_ignore_keyword_token(const char* item); +bool semtc_is_token_in_ignore_keyword_list(int token, bool isPlpgsqlKeyword = false); extern THR_LOCAL GucContext currentGucContext; diff --git a/src/test/regress/expected/ignore_keyword_list.out b/src/test/regress/expected/ignore_keyword_list.out new file mode 100755 index 000000000..3445064cf --- /dev/null +++ b/src/test/regress/expected/ignore_keyword_list.out @@ -0,0 +1,29 @@ +create schema ignore_keyword_list; +set current_schema to 'ignore_keyword_list'; +select 1 interval; --error +ERROR: syntax error at or near "interval" +LINE 1: select 1 interval; + ^ +set disable_keyword_options = 'interval'; +select 1 interval; --ok + interval +---------- + 1 +(1 row) + +set disable_keyword_options = 'intervalxx'; +ERROR: invalid value for parameter "disable_keyword_options": "intervalxx" +DETAIL: invalid disable keyword "intervalxx" +set disable_keyword_options = 'interval,interval'; +select 1 interval; --ok + interval +---------- + 1 +(1 row) + +reset disable_keyword_options; +select 1 interval; --error +ERROR: syntax error at or near "interval" +LINE 1: select 1 interval; + ^ +drop schema ignore_keyword_list cascade; diff --git a/src/test/regress/parallel_schedule0A b/src/test/regress/parallel_schedule0A index 73ce45049..3d958c40a 100644 --- a/src/test/regress/parallel_schedule0A +++ b/src/test/regress/parallel_schedule0A @@ -478,5 +478,5 @@ test: alter_table_modify alter_table_modify_ustore alter_table_modify_ltt alter_ test: accept_empty_str not_accept_empty_str pg_empty_str accept_empty_copy not_accept_empty_copy #test: gin/cgin -test: cgin_select -test: gin_select \ No newline at end of file +test: cgin_select ignore_keyword_list +test: gin_select diff --git a/src/test/regress/sql/ignore_keyword_list.sql b/src/test/regress/sql/ignore_keyword_list.sql new file mode 100755 index 000000000..3271f0385 --- /dev/null +++ b/src/test/regress/sql/ignore_keyword_list.sql @@ -0,0 +1,11 @@ +create schema ignore_keyword_list; +set current_schema to 'ignore_keyword_list'; +select 1 interval; --error +set disable_keyword_options = 'interval'; +select 1 interval; --ok +set disable_keyword_options = 'intervalxx'; +set disable_keyword_options = 'interval,interval'; +select 1 interval; --ok +reset disable_keyword_options; +select 1 interval; --error +drop schema ignore_keyword_list cascade; \ No newline at end of file