!2077 提交MySQL兼容性delimiter分割符的功能。
Merge pull request !2077 from slbaiyi/master
This commit is contained in:
@ -43,6 +43,7 @@ extern bool canAddHist;
|
||||
#define DEFAULT_RETRY_TIMES 5
|
||||
#define MAX_RETRY_TIMES 10
|
||||
#define ERRCODE_LENGTH 5
|
||||
#define DELIMITER_LENGTH 16
|
||||
|
||||
#if defined(__LP64__) || defined(__64BIT__)
|
||||
typedef unsigned int GS_UINT32;
|
||||
|
||||
@ -100,6 +100,144 @@ static void SetSessionTimeout(const char* session_timeout)
|
||||
|
||||
PQclear(StRes);
|
||||
}
|
||||
|
||||
static void JudgeEndStateInBFormat(const char* inputLine, bool &is_b_format, char* delimiter_name, bool is_new_lines)
|
||||
{
|
||||
/* Convert inputLine to lowercase */
|
||||
char *inputLine_temp = pg_strdup(inputLine);
|
||||
inputLine_temp = pg_strtolower(inputLine_temp);
|
||||
|
||||
/* Determine whether the command is a delimiter command, and if so, save the result. */
|
||||
static bool is_just_one_check = false;
|
||||
static bool is_just_two_check = false;
|
||||
PGresult* res = NULL ;
|
||||
char *tokenPtr = strstr(inputLine_temp, "delimiter");
|
||||
char *tokenPtr1 = strstr(inputLine_temp, "\\c" );
|
||||
errno_t rc = 0;
|
||||
|
||||
if (!is_just_one_check) {
|
||||
res = PQexec(pset.db, "show sql_compatibility");
|
||||
if (res != NULL && PQresultStatus(res) == PGRES_TUPLES_OK) {
|
||||
is_b_format = strcmp (PQgetvalue(res, 0, 0), "B") == 0;
|
||||
}
|
||||
PQclear(res);
|
||||
res = NULL;
|
||||
is_just_one_check = true;
|
||||
}
|
||||
|
||||
if (tokenPtr1 != NULL) {
|
||||
is_just_one_check = false;
|
||||
}
|
||||
|
||||
if (is_b_format) {
|
||||
if (!is_just_two_check && is_new_lines) {
|
||||
res = PQexec(pset.db, "show delimiter_name");
|
||||
if (res != NULL && PQresultStatus(res) == PGRES_TUPLES_OK) {
|
||||
rc = strcpy_s(delimiter_name, DELIMITER_LENGTH, PQgetvalue(res, 0, 0));
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
}
|
||||
PQclear(res);
|
||||
res = NULL;
|
||||
is_just_two_check = true;
|
||||
}
|
||||
} else if (strcmp(delimiter_name,";") != 0) {
|
||||
rc = strcpy_s(delimiter_name, DELIMITER_LENGTH, ";");
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
}
|
||||
|
||||
if (tokenPtr != NULL || tokenPtr1 != NULL) {
|
||||
is_just_two_check = false;
|
||||
}
|
||||
|
||||
free(inputLine_temp);
|
||||
inputLine_temp =NULL;
|
||||
}
|
||||
|
||||
static bool is_match_delimiter_name(const char* left, const char* right)
|
||||
{
|
||||
if (strlen(left) < strlen(right)) {
|
||||
return false;
|
||||
}
|
||||
while (*right) {
|
||||
if (*left++ != *right++) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
static char* get_correct_str(char*str, const char *delimiter_name, bool is_new_lines)
|
||||
{
|
||||
/* Determine whether it is a delimiter command. */
|
||||
char *str_temp = pg_strdup(str);
|
||||
str_temp = pg_strtolower(str_temp);
|
||||
bool is_delimiter = false;
|
||||
char *token = strstr(str_temp, "delimiter");
|
||||
errno_t rc = 0;
|
||||
if(token != NULL) {
|
||||
is_delimiter = true;
|
||||
char* pos = str_temp;
|
||||
while(pos != token) {
|
||||
if(*pos == ' ') {
|
||||
pos++;
|
||||
} else {
|
||||
is_delimiter = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(is_delimiter) {
|
||||
char* end = pos + strlen("delimiter");
|
||||
if(*end != ' ' && *end != '\0') {
|
||||
is_delimiter = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_new_lines && is_delimiter && strstr(str, delimiter_name) == NULL) {
|
||||
Size slen1 = strlen(str) + strlen(delimiter_name) + DELIMITER_LENGTH;
|
||||
char* result1 = (char *) pg_malloc(slen1);
|
||||
rc = sprintf_s(result1, slen1, "%s %s", str, delimiter_name);
|
||||
securec_check_ss_c(rc, "", "");
|
||||
free(str_temp);
|
||||
str_temp =NULL;
|
||||
return result1;
|
||||
}
|
||||
free(str_temp);
|
||||
str_temp =NULL;
|
||||
|
||||
if (!((*delimiter_name >= 'a' && *delimiter_name <='z') || (*delimiter_name >= 'A' && *delimiter_name <= 'Z'))) {
|
||||
return pg_strdup(str);
|
||||
}
|
||||
Size slen = 2 * strlen(str) + 1;
|
||||
char* result = (char *) pg_malloc(slen + 2);
|
||||
char* temp = result;
|
||||
char* pos;
|
||||
char* end_of_str = str + strlen(str);
|
||||
char special_str = 0;
|
||||
char in;
|
||||
for (pos = str; pos < end_of_str; pos++) {
|
||||
in = *pos;
|
||||
if (!special_str && is_match_delimiter_name(pos , delimiter_name)) {
|
||||
*temp++ =' ';
|
||||
int delimiter_name_length = strlen(delimiter_name);
|
||||
while ( delimiter_name_length > 0 && *pos != '\0') {
|
||||
*temp++ = *pos++;
|
||||
delimiter_name_length--;
|
||||
}
|
||||
pos--;
|
||||
*temp++ = ' ';
|
||||
} else {
|
||||
if (in == special_str) {
|
||||
special_str = 0;
|
||||
} else if (!special_str && (in == '\'' || in == '"' || in == '`')) {
|
||||
special_str = (char)in;
|
||||
}
|
||||
*temp++ = *pos;
|
||||
}
|
||||
}
|
||||
*temp = '\0';
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main processing loop for reading lines of input
|
||||
* and sending them to the backend.
|
||||
@ -142,6 +280,9 @@ int MainLoop(FILE* source, char* querystring)
|
||||
/* Save the stmts and counts info in parallel execute mode. */
|
||||
int query_count = 0;
|
||||
char** query_stmts = NULL;
|
||||
bool is_b_format = false;
|
||||
char delimiter_name[DELIMITER_LENGTH]=";";
|
||||
char *line_temp = NULL;
|
||||
|
||||
errno_t rc = 0;
|
||||
|
||||
@ -318,11 +459,19 @@ int MainLoop(FILE* source, char* querystring)
|
||||
|
||||
/* Setting this will not have effect until next line. */
|
||||
die_on_error = pset.on_error_stop;
|
||||
|
||||
/* Add processing of sql mode and terminator */
|
||||
bool is_new_lines = query_buf->len == 0 ? true : false;
|
||||
JudgeEndStateInBFormat(line, is_b_format, delimiter_name, is_new_lines);
|
||||
/*
|
||||
* Parse line, looking for command separators.
|
||||
*/
|
||||
psql_scan_setup(scan_state, line, (int)strlen(line));
|
||||
if (is_b_format) {
|
||||
line_temp = get_correct_str(line, delimiter_name, is_new_lines);
|
||||
psql_scan_setup(scan_state, line_temp, (int)strlen(line_temp));
|
||||
free(line_temp);
|
||||
} else {
|
||||
psql_scan_setup(scan_state, line, (int)strlen(line));
|
||||
}
|
||||
success = true;
|
||||
line_saved_in_history = false;
|
||||
|
||||
@ -330,7 +479,7 @@ int MainLoop(FILE* source, char* querystring)
|
||||
PsqlScanResult scan_result;
|
||||
promptStatus_t prompt_tmp = prompt_status;
|
||||
|
||||
scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
|
||||
scan_result = psql_scan(scan_state, query_buf, &prompt_tmp,is_b_format,delimiter_name);
|
||||
prompt_status = prompt_tmp;
|
||||
|
||||
if (PQExpBufferBroken(query_buf)) {
|
||||
|
||||
@ -39,7 +39,8 @@ extern void psql_scan_destroy(PsqlScanState state);
|
||||
extern void psql_scan_setup(PsqlScanState state, const char* line, int line_len);
|
||||
extern void psql_scan_finish(PsqlScanState state);
|
||||
|
||||
extern PsqlScanResult psql_scan(PsqlScanState state, PQExpBuffer query_buf, promptStatus_t* prompt);
|
||||
extern PsqlScanResult psql_scan(PsqlScanState state, PQExpBuffer query_buf, promptStatus_t* prompt,
|
||||
bool is_b_format,char* delimiter_name);
|
||||
|
||||
extern void psql_scan_reset(PsqlScanState state);
|
||||
|
||||
|
||||
@ -146,6 +146,8 @@ typedef struct PsqlScanStateData
|
||||
For sql like "Declare foo CURSOR XXX, butt_num is 1.
|
||||
Using this we can judge if the sql is a DECLARE CURSOR stmt */
|
||||
bool include_ora_comment; /* dont igore comment when ture, such as single line comment after function/procedure param */
|
||||
bool is_b_format;
|
||||
char *delimiter_name;
|
||||
} PsqlScanStateData;
|
||||
|
||||
static PsqlScanState cur_state; /* current state while active */
|
||||
@ -196,6 +198,7 @@ static void analyze_state(const char* text,PsqlScanState state);
|
||||
static int upperstrcmp(const char *str1,const char *str2);
|
||||
static GramIdentify keywordRead(const char* text);
|
||||
static bool IsTranscationTokens(char* yytext, char* token);
|
||||
static bool judge_end_state(const char* text);
|
||||
|
||||
#define YY_DECL int yylex(PsqlScanState lex_param)
|
||||
|
||||
@ -656,6 +659,13 @@ other .
|
||||
RESET_XP_STATUS();
|
||||
return LEXRES_SEMI;
|
||||
}
|
||||
|
||||
if (cur_state->is_b_format == true ) {
|
||||
if (strstr(yytext, cur_state->delimiter_name) != NULL && strcmp(";" ,cur_state->delimiter_name) != 0) {
|
||||
RESET_XP_STATUS();
|
||||
return LEXRES_SEMI;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -796,9 +806,13 @@ other .
|
||||
|
||||
";" {
|
||||
ECHO;
|
||||
|
||||
if (lex_param->begin_state == BEGIN_CURSOR ||
|
||||
bool is_end = true;
|
||||
if (cur_state->is_b_format && strcmp(yytext , cur_state->delimiter_name) != 0) {
|
||||
is_end = false;
|
||||
}
|
||||
if ((lex_param->begin_state == BEGIN_CURSOR ||
|
||||
(!lex_param->declare_encountered && cur_state->paren_depth == 0))
|
||||
&& is_end == true)
|
||||
{
|
||||
RESET_XP_STATUS();
|
||||
return LEXRES_SEMI;
|
||||
@ -889,6 +903,13 @@ other .
|
||||
|
||||
{self} {
|
||||
ECHO;
|
||||
if ((lex_param->begin_state == BEGIN_CURSOR ||
|
||||
( !lex_param->declare_encountered && cur_state->paren_depth == 0))
|
||||
&& judge_end_state(yytext))
|
||||
{
|
||||
RESET_XP_STATUS() ;
|
||||
return LEXRES_SEMI;
|
||||
}
|
||||
}
|
||||
|
||||
{operator} {
|
||||
@ -943,6 +964,13 @@ other .
|
||||
yyless(nchars);
|
||||
}
|
||||
ECHO;
|
||||
if ((lex_param->begin_state == BEGIN_CURSOR ||
|
||||
( !lex_param->declare_encountered && cur_state->paren_depth == 0))
|
||||
&& judge_end_state(yytext))
|
||||
{
|
||||
RESET_XP_STATUS() ;
|
||||
return LEXRES_SEMI;
|
||||
}
|
||||
}
|
||||
|
||||
{param} {
|
||||
@ -983,6 +1011,13 @@ other .
|
||||
{identifier} {
|
||||
ECHO;
|
||||
analyze_state(yytext,(PsqlScanStateData*)lex_param);
|
||||
if ((lex_param->begin_state == BEGIN_CURSOR ||
|
||||
( !lex_param->declare_encountered && cur_state->paren_depth == 0))
|
||||
&& judge_end_state(yytext))
|
||||
{
|
||||
RESET_XP_STATUS() ;
|
||||
return LEXRES_SEMI;
|
||||
}
|
||||
}
|
||||
|
||||
{other} {
|
||||
@ -1373,7 +1408,9 @@ psql_scan_setup(PsqlScanState state,
|
||||
PsqlScanResult
|
||||
psql_scan(PsqlScanState state,
|
||||
PQExpBuffer query_buf,
|
||||
promptStatus_t *prompt)
|
||||
promptStatus_t *prompt,
|
||||
bool is_b_format,
|
||||
char* delimiter_name)
|
||||
{
|
||||
PsqlScanResult result;
|
||||
int lexresult;
|
||||
@ -1391,6 +1428,14 @@ psql_scan(PsqlScanState state,
|
||||
yy_switch_to_buffer(state->scanbufhandle);
|
||||
|
||||
BEGIN(state->start_state);
|
||||
state->is_b_format = is_b_format;
|
||||
if (is_b_format) {
|
||||
if (state->delimiter_name) {
|
||||
free(state->delimiter_name);
|
||||
state->delimiter_name = NULL;
|
||||
}
|
||||
state->delimiter_name = pg_strdup(delimiter_name);
|
||||
}
|
||||
|
||||
/* And lex. */
|
||||
lexresult = yylex((PsqlScanStateData*)state);
|
||||
@ -1522,6 +1567,10 @@ psql_scan_finish(PsqlScanState state)
|
||||
free(state->scanbuf);
|
||||
}
|
||||
state->scanbuf = NULL;
|
||||
if (state->delimiter_name) {
|
||||
free(state->delimiter_name);
|
||||
}
|
||||
state->delimiter_name = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1553,6 +1602,11 @@ psql_scan_reset(PsqlScanState state)
|
||||
state->begin_state = BEGIN_UNDEFINED;
|
||||
state->butt_num = 0;
|
||||
state->declare_encountered = false;
|
||||
state->is_b_format = false;
|
||||
if (state->delimiter_name) {
|
||||
free(state->delimiter_name);
|
||||
}
|
||||
state->delimiter_name = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2060,6 +2114,14 @@ static bool IsTranscationTokens(char* yytext, char* token)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool judge_end_state(const char* text)
|
||||
{
|
||||
if (cur_state->is_b_format == true) {
|
||||
return (strcmp(yytext, cur_state->delimiter_name) ==0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* escape_variable --- process :'VARIABLE' or :"VARIABLE"
|
||||
*
|
||||
|
||||
@ -264,6 +264,8 @@ static bool CheckWhetherInColList(char *colname, List *col_list);
|
||||
static int GetFillerColIndex(char *filler_col_name, List *col_list);
|
||||
static void RemoveFillerCol(List *filler_list, List *col_list);
|
||||
static int errstate;
|
||||
|
||||
static void setDelimiterName(core_yyscan_t yyscanner, char*input, VariableSetStmt*n);
|
||||
%}
|
||||
|
||||
%define api.pure
|
||||
@ -372,7 +374,7 @@ static int errstate;
|
||||
CreateWeakPasswordDictionaryStmt DropWeakPasswordDictionaryStmt
|
||||
AlterGlobalConfigStmt DropGlobalConfigStmt
|
||||
CreatePublicationStmt AlterPublicationStmt
|
||||
CreateSubscriptionStmt AlterSubscriptionStmt DropSubscriptionStmt
|
||||
CreateSubscriptionStmt AlterSubscriptionStmt DropSubscriptionStmt DelimiterStmt
|
||||
ShrinkStmt
|
||||
|
||||
/* <DB4AI> */
|
||||
@ -788,8 +790,7 @@ static int errstate;
|
||||
%type <typnam> load_col_data_type
|
||||
%type <ival64> load_col_sequence_item_sart column_sequence_item_step column_sequence_item_sart
|
||||
%type <trgcharacter> trigger_order
|
||||
|
||||
|
||||
%type <str> delimiter_str_name delimiter_str_names
|
||||
/*
|
||||
* Non-keyword token types. These are hard-wired into the "flex" lexer.
|
||||
* They must be listed first so that their numeric codes do not depend on
|
||||
@ -930,6 +931,9 @@ static int errstate;
|
||||
VALID_BEGIN
|
||||
DECLARE_CURSOR ON_UPDATE_TIME
|
||||
START_WITH CONNECT_BY
|
||||
END_OF_INPUT
|
||||
END_OF_INPUT_COLON
|
||||
END_OF_PROC
|
||||
|
||||
/* Precedence: lowest to highest */
|
||||
%nonassoc COMMENT
|
||||
@ -1032,6 +1036,38 @@ stmtmulti: stmtmulti ';' stmt
|
||||
else
|
||||
$$ = $1;
|
||||
}
|
||||
| stmtmulti ';' END_OF_INPUT stmt
|
||||
{
|
||||
if ($4 != NULL)
|
||||
{
|
||||
if (IsA($4, List))
|
||||
{
|
||||
$$ = list_concat($1, (List*)$4);
|
||||
}
|
||||
else
|
||||
{
|
||||
$$ = lappend($1, $4);
|
||||
}
|
||||
}
|
||||
else
|
||||
$$ = $1;
|
||||
}
|
||||
| stmtmulti END_OF_INPUT_COLON stmt
|
||||
{
|
||||
if ($3 != NULL)
|
||||
{
|
||||
if (IsA($3, List))
|
||||
{
|
||||
$$ = list_concat($1, (List*)$3);
|
||||
}
|
||||
else
|
||||
{
|
||||
$$ = lappend($1, $3);
|
||||
}
|
||||
}
|
||||
else
|
||||
$$ = $1;
|
||||
}
|
||||
|
|
||||
{
|
||||
#ifndef ENABLE_MULTIPLE_NODES
|
||||
@ -1249,6 +1285,7 @@ stmt :
|
||||
| ShrinkStmt
|
||||
| /*EMPTY*/
|
||||
{ $$ = NULL; }
|
||||
| DelimiterStmt
|
||||
;
|
||||
|
||||
/*****************************************************************************
|
||||
@ -14399,7 +14436,7 @@ subprogram_body: {
|
||||
tok = YYLEX;
|
||||
|
||||
/* adapt A db's label */
|
||||
if (!(tok == ';' || tok == 0)
|
||||
if (!(tok == ';' || (tok == 0 || tok == END_OF_PROC))
|
||||
&& tok != IF_P
|
||||
&& tok != CASE
|
||||
&& tok != LOOP)
|
||||
@ -14410,7 +14447,7 @@ subprogram_body: {
|
||||
|
||||
if (blocklevel == 1
|
||||
&& (pre_tok == ';' || pre_tok == BEGIN_P)
|
||||
&& (tok == ';' || tok == 0))
|
||||
&& (tok == ';' || (tok == 0 || tok == END_OF_PROC)))
|
||||
{
|
||||
/* Save the end of procedure body. */
|
||||
proc_e = yylloc;
|
||||
@ -25774,6 +25811,43 @@ ColLabel: IDENT { $$ = $1; }
|
||||
}
|
||||
;
|
||||
|
||||
DelimiterStmt: DELIMITER delimiter_str_names END_OF_INPUT
|
||||
{
|
||||
VariableSetStmt *n = makeNode(VariableSetStmt);
|
||||
setDelimiterName(yyscanner, $2, n);
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| DELIMITER delimiter_str_names END_OF_INPUT_COLON
|
||||
{
|
||||
VariableSetStmt *n = makeNode(VariableSetStmt);
|
||||
setDelimiterName(yyscanner, $2, n);
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
|
||||
delimiter_str_names: delimiter_str_names delimiter_str_name
|
||||
{
|
||||
$$ = $1 ;
|
||||
}
|
||||
| delimiter_str_name
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
delimiter_str_name: ColId_or_Sconst
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| all_Op
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| ';'
|
||||
{
|
||||
$$ = ";";
|
||||
}
|
||||
;
|
||||
|
||||
/*
|
||||
* Keyword category lists. Generally, every keyword present in
|
||||
@ -28537,6 +28611,22 @@ static void RemoveFillerCol(List *filler_list, List *col_list)
|
||||
return;
|
||||
}
|
||||
|
||||
static void setDelimiterName(core_yyscan_t yyscanner, char*input, VariableSetStmt*n)
|
||||
{
|
||||
errno_t rc = 0;
|
||||
base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
|
||||
if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) {
|
||||
if (strlen(input) >= DELIMITER_LENGTH) {
|
||||
parser_yyerror("syntax error");
|
||||
}
|
||||
n->is_local = false;
|
||||
n->kind = VAR_SET_VALUE;
|
||||
n->name = "delimiter_name";
|
||||
n->args = list_make1(makeStringConst(input, -1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static FuncCall* MakePriorAsFunc()
|
||||
{
|
||||
List *funcName = list_make1(makeString("prior"));
|
||||
|
||||
@ -155,6 +155,7 @@ int base_yylex(YYSTYPE* lvalp, YYLTYPE* llocp, core_yyscan_t yyscanner)
|
||||
int next_token;
|
||||
core_YYSTYPE cur_yylval;
|
||||
YYLTYPE cur_yylloc;
|
||||
errno_t rc = 0;
|
||||
|
||||
/* Get next token --- we might already have it */
|
||||
if (yyextra->lookahead_num != 0) {
|
||||
@ -166,6 +167,32 @@ int base_yylex(YYSTYPE* lvalp, YYLTYPE* llocp, core_yyscan_t yyscanner)
|
||||
cur_token = core_yylex(&(lvalp->core_yystype), llocp, yyscanner);
|
||||
}
|
||||
|
||||
if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT && yyextra->lookahead_num == 0) {
|
||||
bool is_last_colon;
|
||||
if (cur_token == int(';')) {
|
||||
is_last_colon = true;
|
||||
} else {
|
||||
is_last_colon = false;
|
||||
}
|
||||
if (yyextra->core_yy_extra.is_delimiter_name == true) {
|
||||
if (strcmp(";",u_sess->attr.attr_common.delimiter_name) == 0) {
|
||||
cur_token = END_OF_INPUT_COLON;
|
||||
} else {
|
||||
if (yyextra->core_yy_extra.is_last_colon == false ) {
|
||||
cur_token = END_OF_INPUT_COLON;
|
||||
} else {
|
||||
cur_token = END_OF_INPUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (yyextra->core_yy_extra.is_proc_end == true) {
|
||||
cur_token = END_OF_PROC;
|
||||
}
|
||||
yyextra->core_yy_extra.is_proc_end = false;
|
||||
yyextra->core_yy_extra.is_delimiter_name = false;
|
||||
yyextra->core_yy_extra.is_last_colon = is_last_colon;
|
||||
}
|
||||
|
||||
/* Do we need to look ahead for a possible multiword token? */
|
||||
switch (cur_token) {
|
||||
case NULLS_P:
|
||||
|
||||
@ -93,6 +93,7 @@ static bool is_utf16_surrogate_first(pg_wchar c);
|
||||
static bool is_utf16_surrogate_second(pg_wchar c);
|
||||
static pg_wchar surrogate_pair_to_codepoint(pg_wchar first, pg_wchar second);
|
||||
static void addunicode(pg_wchar c, yyscan_t yyscanner);
|
||||
static void set_is_delimiter_name(char* text, core_yyscan_t yyscanner );
|
||||
|
||||
#define yyerror(msg) scanner_yyerror(msg, yyscanner)
|
||||
|
||||
@ -598,6 +599,7 @@ other .
|
||||
BEGIN(INITIAL);
|
||||
yylval->str = litbuf_udeescape('\\', yyscanner);
|
||||
yyextra->is_hint_str = false;
|
||||
set_is_delimiter_name(yytext,yyscanner);
|
||||
return SCONST;
|
||||
}
|
||||
<xus>{xusstop2} {
|
||||
@ -867,6 +869,7 @@ other .
|
||||
/* reset is_createstmt to parse next sql */
|
||||
yyextra->is_createstmt = false;
|
||||
}
|
||||
set_is_delimiter_name(yytext,yyscanner);
|
||||
}
|
||||
yyextra->is_hint_str = false;
|
||||
return yytext[0];
|
||||
@ -919,6 +922,7 @@ other .
|
||||
}
|
||||
|
||||
SET_YYLLOC();
|
||||
set_is_delimiter_name(yytext,yyscanner);
|
||||
|
||||
if (nchars < (int)yyleng)
|
||||
{
|
||||
@ -1144,6 +1148,7 @@ other .
|
||||
ident = downcase_truncate_identifier(yytext, yyleng, yyextra->warnOnTruncateIdent);
|
||||
yylval->str = ident;
|
||||
yyextra->ident_quoted = false;
|
||||
set_is_delimiter_name(yytext,yyscanner);
|
||||
return IDENT;
|
||||
}
|
||||
|
||||
@ -1339,6 +1344,9 @@ scanner_init(const char *str,
|
||||
/* plpgsql keyword params */
|
||||
yyext->isPlpgsqlKeyWord = false;
|
||||
yyext->plKeywordValue = NULL;
|
||||
yyext->is_delimiter_name = false;
|
||||
yyext->is_last_colon = false;
|
||||
yyext->is_proc_end = false;
|
||||
|
||||
// Added CALL for procedure and function
|
||||
getDynaParamSeq("init", true, true, NULL);
|
||||
@ -1420,6 +1428,24 @@ addlitchar(unsigned char ychar, core_yyscan_t yyscanner)
|
||||
yyextra->literallen += 1;
|
||||
}
|
||||
|
||||
static void set_is_delimiter_name(char* text, core_yyscan_t yyscanner)
|
||||
{
|
||||
if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) {
|
||||
if (strcmp(text,u_sess->attr.attr_common.delimiter_name) == 0 && yyextra->paren_depth == 0 && !yyextra->in_slash_proc_body) {
|
||||
if (strcmp(text,";") != 0) {
|
||||
yyextra->query_string_locationlist = lappend_int(yyextra->query_string_locationlist, *yylloc);
|
||||
yyextra->is_createstmt = false;
|
||||
}
|
||||
yyextra->is_delimiter_name = true;
|
||||
} else {
|
||||
yyextra->is_delimiter_name = false;
|
||||
}
|
||||
if (strcmp(text,u_sess->attr.attr_common.delimiter_name) == 0 && strcmp(text,";") != 0 && yyextra->in_slash_proc_body) {
|
||||
yyextra->is_proc_end = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create a palloc'd copy of literalbuf, adding a trailing null.
|
||||
|
||||
@ -3295,6 +3295,18 @@ static void InitConfigureNamesString()
|
||||
NULL,
|
||||
NULL,
|
||||
show_lcgroup_name},
|
||||
{ {"delimiter_name",
|
||||
PGC_USERSET,
|
||||
NODE_ALL,
|
||||
UNGROUPED,
|
||||
gettext_noop( "Shows delimiter name."),
|
||||
NULL,
|
||||
GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE},
|
||||
&u_sess->attr.attr_common.delimiter_name,
|
||||
";",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL},
|
||||
{{"search_path",
|
||||
PGC_USERSET,
|
||||
NODE_ALL,
|
||||
|
||||
@ -236,6 +236,7 @@ typedef struct knl_session_attr_common {
|
||||
void** extension_session_vars_array;
|
||||
char* threadpool_reset_percent_item;
|
||||
int threadpool_reset_percent_list[2];
|
||||
char* delimiter_name;
|
||||
} knl_session_attr_common;
|
||||
|
||||
#endif /* SRC_INCLUDE_KNL_KNL_SESSION_ATTR_COMMON_H_ */
|
||||
|
||||
@ -49,6 +49,8 @@ typedef union core_YYSTYPE {
|
||||
*/
|
||||
#define YYLTYPE int
|
||||
|
||||
#define DELIMITER_LENGTH 16
|
||||
|
||||
/*
|
||||
* Another important component of the scanner's API is the token code numbers.
|
||||
* However, those are not defined in this file, because bison insists on
|
||||
@ -117,6 +119,9 @@ typedef struct core_yy_extra_type {
|
||||
int func_param_end; /* function and procedure param string end pos,exclude right parenthesis */
|
||||
bool isPlpgsqlKeyWord;
|
||||
const PlpgsqlKeywordValue* plKeywordValue;
|
||||
bool is_delimiter_name;
|
||||
bool is_last_colon;
|
||||
bool is_proc_end;
|
||||
} core_yy_extra_type;
|
||||
|
||||
#ifdef FRONTEND_PARSER
|
||||
|
||||
99
src/test/regress/expected/mysql_delimiter.out
Normal file
99
src/test/regress/expected/mysql_delimiter.out
Normal file
@ -0,0 +1,99 @@
|
||||
-- B db compatibility case
|
||||
drop database if exists my_test;
|
||||
NOTICE: database "my_test" does not exist, skipping
|
||||
create database my_test dbcompatibility 'B';
|
||||
\c my_test
|
||||
--Test default delimiter
|
||||
select 1;
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
--Test delimiter aa
|
||||
delimiter aa;
|
||||
select 1aa
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
select 1aaselect 1;aa
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
select kaa
|
||||
ERROR: column "k" does not exist
|
||||
LINE 1: select k aa
|
||||
^
|
||||
CONTEXT: referenced column: k
|
||||
delimiter ;aa
|
||||
--Test delimiter //
|
||||
delimiter //;
|
||||
select 1//
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
delimiter ;//
|
||||
--Test delimiter length
|
||||
delimiter aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
|
||||
ERROR: syntax error at or near ";"
|
||||
LINE 1: delimiter aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
|
||||
^
|
||||
--Test delimiter %
|
||||
delimiter %;
|
||||
select 1%
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
delimiter ;%
|
||||
--Test delimiter 'Mysql'
|
||||
delimiter 'Mysql';
|
||||
select 1Mysql
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
delimiter ;Mysql
|
||||
--Test other
|
||||
delimiter sds;
|
||||
delimiter aasds
|
||||
select 1aa
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
delimiter ;aa
|
||||
--
|
||||
delimiter asd ss;
|
||||
select 1asd
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
delimiter ;asd
|
||||
delimiter bb
|
||||
delimiter aa
|
||||
select 1aa
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
delimiter ;
|
||||
\c regression
|
||||
drop database my_test;
|
||||
@ -198,6 +198,7 @@ select name,vartype,unit,min_val,max_val from pg_settings where name <> 'qunit_c
|
||||
default_transaction_read_only | bool | | |
|
||||
default_with_oids | bool | | |
|
||||
defer_csn_cleanup_time | integer | ms | 0 | 2147483647
|
||||
delimiter_name | string | | |
|
||||
dfs_partition_directory_length | integer | | 92 | 7999
|
||||
dirty_page_percent_max | real | | 0.1 | 1
|
||||
disable_memory_protect | bool | | |
|
||||
|
||||
@ -984,7 +984,7 @@ test: fdw_audit
|
||||
test: gs_global_config_audit
|
||||
test: detail declare_multiple_variable
|
||||
test: gs_dump_encrypt substr
|
||||
test: composite_datum_record mysql_function b_comments mysql_syntax
|
||||
test: composite_datum_record mysql_function b_comments mysql_syntax mysql_delimiter
|
||||
|
||||
test: join_test_alias alter_ctable_compress
|
||||
test: ignore/ignore_type_transform ignore/ignore_not_null_constraints ignore/ignore_unique_constraints ignore/ignore_no_matched_partition
|
||||
|
||||
51
src/test/regress/sql/mysql_delimiter.sql
Normal file
51
src/test/regress/sql/mysql_delimiter.sql
Normal file
@ -0,0 +1,51 @@
|
||||
-- B db compatibility case
|
||||
drop database if exists my_test;
|
||||
create database my_test dbcompatibility 'B';
|
||||
\c my_test
|
||||
|
||||
--Test default delimiter
|
||||
select 1;
|
||||
|
||||
--Test delimiter aa
|
||||
delimiter aa;
|
||||
select 1aa
|
||||
select 1aaselect 1;aa
|
||||
select kaa
|
||||
delimiter ;aa
|
||||
|
||||
--Test delimiter //
|
||||
delimiter //;
|
||||
select 1//
|
||||
delimiter ;//
|
||||
|
||||
--Test delimiter length
|
||||
delimiter aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
|
||||
|
||||
--Test delimiter %
|
||||
delimiter %;
|
||||
select 1%
|
||||
delimiter ;%
|
||||
|
||||
--Test delimiter 'Mysql'
|
||||
delimiter 'Mysql';
|
||||
select 1Mysql
|
||||
delimiter ;Mysql
|
||||
|
||||
--Test other
|
||||
delimiter sds;
|
||||
delimiter aasds
|
||||
select 1aa
|
||||
delimiter ;aa
|
||||
|
||||
--
|
||||
delimiter asd ss;
|
||||
select 1asd
|
||||
delimiter ;asd
|
||||
|
||||
delimiter bb
|
||||
delimiter aa
|
||||
select 1aa
|
||||
delimiter ;
|
||||
|
||||
\c regression
|
||||
drop database my_test;
|
||||
Reference in New Issue
Block a user