Add ignore keyword feature.
This commit is contained in:
@ -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|
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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];
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
29
src/test/regress/expected/ignore_keyword_list.out
Executable file
29
src/test/regress/expected/ignore_keyword_list.out
Executable file
@ -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;
|
||||
@ -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
|
||||
test: cgin_select ignore_keyword_list
|
||||
test: gin_select
|
||||
|
||||
11
src/test/regress/sql/ignore_keyword_list.sql
Executable file
11
src/test/regress/sql/ignore_keyword_list.sql
Executable file
@ -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;
|
||||
Reference in New Issue
Block a user