%{
#include "postgres.h"
#include "knl/knl_variable.h"
#include "nodes/pg_list.h"
#include "nodes/nodes.h"
#include "parser/parse_hint.h"
#include "parser/parser.h"

#include "parser/gramparse.h"

#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wunused-variable"

extern void yyerror(yyscan_t yyscanner, const char *msg);
extern void hint_scanner_yyerror(const char *msg, yyscan_t yyscanner);

static Value *makeStringValue(char *str);

static Value *makeBitStringValue(char *str);

static Value *makeNullValue();

static Value *makeBoolValue(bool state);

static void doNegateFloat(Value *v);
static Value* integerToString(Value *v);

#define YYMALLOC palloc
#define YYFREE   pfree


static double convert_to_numeric(Node *value);

%}

%define api.pure
%expect 0

%parse-param {yyscan_t yyscanner}
%lex-param   {yyscan_t yyscanner}


%union
{
	int		ival;
	char		*str;
	List		*list;
	Node	*node;
}



%type <node> join_hint_item join_order_hint join_method_hint stream_hint row_hint scan_hint skew_hint expr_const
	pred_push_hint pred_push_same_level_hint rewrite_hint gather_hint set_hint plancache_hint guc_value no_expand_hint
	no_gpc_hint
%type <list> relation_list join_hint_list relation_item relation_list_with_p ident_list skew_relist
             column_list_p column_list value_list_p value_list value_list_item value_type value_list_with_bracket
%token <str>	IDENT FCONST SCONST BCONST XCONST
%token <ival>	ICONST

%token <keyword> NestLoop_P MergeJoin_P HashJoin_P No_P Leading_P Rows_P Broadcast_P Redistribute_P BlockName_P
	TableScan_P IndexScan_P IndexOnlyScan_P Skew_P HINT_MULTI_NODE_P NULL_P TRUE_P FALSE_P Predpush_P
	PredpushSameLevel_P Rewrite_P Gather_P Set_P USE_CPLAN_P USE_GPLAN_P ON_P OFF_P No_expand_P SQL_IGNORE_P NO_GPC_P
	CHOOSE_ADAPTIVE_GPLAN_P

%nonassoc	IDENT NULL_P

%%
//yacc syntax start here  
join_hint_list:
	join_hint_item join_hint_list
	{
		$$ = lcons($1, $2);
		u_sess->parser_cxt.hint_list = $$;
	}
	| /*EMPTY*/             { $$ = NIL; }
	;

join_hint_item:
	join_order_hint
	{
		$$ = $1;
	}
	| join_method_hint
	{
		$$ = $1;
	}
	| No_P join_method_hint
	{
		JoinMethodHint *joinHint = (JoinMethodHint *) $2;
		joinHint->negative = true;
		$$ = (Node *) joinHint;
	}
	| stream_hint
	{
		$$ = $1;
	}
	| No_P stream_hint
	{
		StreamHint	*streamHint = (StreamHint *) $2;
		if (streamHint != NULL) {
			streamHint->negative = true;
		}
		$$ = (Node *) streamHint;
	}
	| row_hint
	{
		$$ = $1;
	}
	| BlockName_P '(' IDENT ')'
	{
		BlockNameHint *blockHint = makeNode(BlockNameHint);
		blockHint->base.relnames = list_make1(makeString($3));
		blockHint->base.hint_keyword = HINT_KEYWORD_BLOCKNAME;
		$$ = (Node *) blockHint;
	}
	| scan_hint
	{
		$$ = $1;
	}
	| No_P scan_hint
	{
		ScanMethodHint	*scanHint = (ScanMethodHint *) $2;
		scanHint->negative = true;
		$$ = (Node *) scanHint;
	}
	| skew_hint
	{
		$$ = $1;
	}
	| HINT_MULTI_NODE_P
	{
#ifndef ENABLE_MULTIPLE_NODES
		hint_scanner_yyerror("unsupport distributed hint", yyscanner);
		$$ = NULL;
#else /* ENABLE_MULTIPLE_NODES */
		MultiNodeHint *multi_node_hint = (MultiNodeHint *)makeNode(MultiNodeHint);
		multi_node_hint->multi_node_hint = true;
		$$ = (Node *) multi_node_hint;
#endif /* ENABLE_MULTIPLE_NODES */
	}
    | pred_push_hint
    {
        $$ = $1;
    }
	| pred_push_same_level_hint
    {
        $$ = $1;
    }
	| No_P rewrite_hint
	{
		$$ = $2;
	}
	| gather_hint
	{
		$$ = $1;
	}
	| set_hint
	{
		$$ = $1;
	}
	| plancache_hint
	{
		$$ = $1;
	}
	| no_expand_hint
	{
		$$ = $1;
	}
	| no_gpc_hint
	{
		$$ = $1;
	}
	| SQL_IGNORE_P
	{
		SqlIgnoreHint *sql_ignore_hint = (SqlIgnoreHint *)makeNode(SqlIgnoreHint);
		sql_ignore_hint->sql_ignore_hint = true;
		$$ = (Node *) sql_ignore_hint;
	}

gather_hint:
	Gather_P '(' IDENT ')'
	{
#ifndef ENABLE_MULTIPLE_NODES
		hint_scanner_yyerror("unsupport distributed hint", yyscanner);
		$$ = NULL;
#else /* ENABLE_MULTIPLE_NODES */
		GatherHint *gatherHint = makeNode(GatherHint);
		gatherHint->base.hint_keyword = HINT_KEYWORD_GATHER;
		gatherHint->base.state = HINT_STATE_NOTUSED;
		if (pg_strcasecmp($3, "REL") == 0) {
			gatherHint->source = HINT_GATHER_REL;
		} else if (pg_strcasecmp($3, "JOIN") == 0) {
			gatherHint->source = HINT_GATHER_JOIN;
		} else if (pg_strcasecmp($3, "ALL") == 0) {
			gatherHint->source = HINT_GATHER_ALL;
		} else {
			gatherHint->source = HINT_GATHER_UNKNOWN;
		}
		$$ = (Node *) gatherHint;
#endif /* ENABLE_MULTIPLE_NODES */
	}

no_gpc_hint:
	NO_GPC_P
	{
		NoGPCHint *noGPCHint = makeNode(NoGPCHint);
		noGPCHint->base.hint_keyword = HINT_KEYWORD_NO_GPC;
		noGPCHint->base.state = HINT_STATE_NOTUSED;
		$$ = (Node *) noGPCHint;
	}

no_expand_hint:
	No_expand_P
	{
		NoExpandHint *noExpandHint = makeNode(NoExpandHint);
		noExpandHint->base.hint_keyword = HINT_KEYWORD_NO_EXPAND;
		noExpandHint->base.state = HINT_STATE_NOTUSED;
		$$ = (Node *) noExpandHint;
	}

guc_value:
	IDENT				{ $$ = (Node*)makeStringValue($1); }
	| SCONST			{ $$ = (Node*)makeStringValue($1); }
	| TRUE_P			{ $$ = (Node*)makeBoolValue(TRUE); }
	| FALSE_P			{ $$ = (Node*)makeBoolValue(FALSE); }
	| ON_P				{ $$ = (Node*)makeBoolValue(TRUE); }
	| OFF_P				{ $$ = (Node*)makeBoolValue(FALSE); }
	| ICONST			{ $$ = (Node*)makeInteger($1); }
	| '+' ICONST		{ $$ = (Node*)makeInteger($2); }
	| '-' ICONST		{ $$ = (Node*)makeInteger(-$2); }
	| FCONST			{ $$ = (Node*)makeFloat($1); }
	| '+' FCONST		{ $$ = (Node*)makeFloat($2); }
	| '-' FCONST
	{
		Value *fvalue = makeFloat($2);
		doNegateFloat(fvalue);
		$$ = (Node*)fvalue;
	}
	;

set_hint:
	Set_P '(' IDENT guc_value ')'
	{
		char* name = $3;
		if (!check_set_hint_in_white_list(name)) {
			ereport(WARNING, (errmsg("SetHint is invalid. Parameter [%s] is not in whitelist.", name)));
			$$ = NULL;
		} else {
			Value* guc_val = NULL;
			if (IsA($4, Integer)) {
				guc_val = integerToString((Value*)$4);
			} else {
				guc_val = (Value*)$4;
			}
			SetHint *setHint = makeNode(SetHint);
			setHint->base.hint_keyword = HINT_KEYWORD_SET;
			setHint->base.state = HINT_STATE_NOTUSED;
			setHint->name = name;
			setHint->value = strVal(guc_val);
			$$ = (Node *) setHint;
		}
	}
	|
	Set_P '(' Rewrite_P guc_value ')'
	{
		char* name = "rewrite_rule";
		Value* guc_val = NULL;
		if (IsA($4, Integer)) {
			guc_val = integerToString((Value*)$4);
		} else {
			guc_val = (Value*)$4;
		}
		SetHint *setHint = makeNode(SetHint);
		setHint->base.hint_keyword = HINT_KEYWORD_SET;
		setHint->base.state = HINT_STATE_NOTUSED;
		setHint->name = name;
		setHint->value = strVal(guc_val);
		$$ = (Node *) setHint;
	}

plancache_hint:
	USE_CPLAN_P
	{
		PlanCacheHint *planCacheHint = makeNode(PlanCacheHint);
		planCacheHint->base.hint_keyword = HINT_KEYWORD_CPLAN;
		planCacheHint->base.state = HINT_STATE_NOTUSED;
		planCacheHint->chooseCustomPlan = true;
        planCacheHint->method = CHOOSE_NONE_GPLAN;

		$$ = (Node *) planCacheHint;
	}
	| USE_GPLAN_P
	{
		PlanCacheHint *planCacheHint = makeNode(PlanCacheHint);
		planCacheHint->base.hint_keyword = HINT_KEYWORD_GPLAN;
		planCacheHint->base.state = HINT_STATE_NOTUSED;
		planCacheHint->chooseCustomPlan = false;
        planCacheHint->method = CHOOSE_DEFAULT_GPLAN;

		$$ = (Node *) planCacheHint;
	}
    | CHOOSE_ADAPTIVE_GPLAN_P
    {
        PlanCacheHint *planCacheHint = makeNode(PlanCacheHint);
		planCacheHint->base.hint_keyword = HINT_KEYWORD_CHOOSE_ADAPTIVE_GPLAN;
		planCacheHint->base.state = HINT_STATE_NOTUSED;
		planCacheHint->chooseCustomPlan = false;
        planCacheHint->method = CHOOSE_ADAPTIVE_GPLAN;

		$$ = (Node *) planCacheHint;
    }


rewrite_hint:
	Rewrite_P '(' ident_list ')'
	{
		RewriteHint *rewriteHint = makeNode(RewriteHint);
		rewriteHint->param_names = $3;
		rewriteHint->param_bits = 0;
		rewriteHint->base.hint_keyword = HINT_KEYWORD_REWRITE;
		$$ = (Node *) rewriteHint;
	}

pred_push_hint:
    Predpush_P '(' ident_list ')'
    {
        PredpushHint *predpushHint = makeNode(PredpushHint);
        predpushHint->base.relnames = $3;
        predpushHint->base.hint_keyword = HINT_KEYWORD_PREDPUSH;
        predpushHint->base.state = HINT_STATE_NOTUSED;
        predpushHint->dest_name = NULL;
        predpushHint->dest_id = 0;
        predpushHint->candidates = NULL;
        predpushHint->negative = false;
        $$ = (Node *) predpushHint;
    }
    |
    Predpush_P '(' ident_list ',' IDENT ')'
    {
        PredpushHint *predpushHint = makeNode(PredpushHint);
        predpushHint->base.relnames = $3;
        predpushHint->base.hint_keyword = HINT_KEYWORD_PREDPUSH;
        predpushHint->base.state = HINT_STATE_NOTUSED;
        predpushHint->dest_name = $5;
        predpushHint->dest_id = 0;
        predpushHint->candidates = NULL;
        predpushHint->negative = false;
        $$ = (Node *) predpushHint;
    }
    |
    No_P Predpush_P
    {
        PredpushHint *predpushHint = makeNode(PredpushHint);
        predpushHint->base.relnames = NULL;
        predpushHint->base.hint_keyword = HINT_KEYWORD_PREDPUSH;
        predpushHint->base.state = HINT_STATE_NOTUSED;
        predpushHint->dest_name = NULL;
        predpushHint->dest_id = 0;
        predpushHint->candidates = NULL;
        predpushHint->negative = true;
        $$ = (Node *) predpushHint;
    }

pred_push_same_level_hint:
	PredpushSameLevel_P '(' ident_list ',' IDENT ')'
    {
        PredpushSameLevelHint *predpushSameLevelHint = makeNode(PredpushSameLevelHint);
        predpushSameLevelHint->base.relnames = $3;
        predpushSameLevelHint->base.hint_keyword = HINT_KEYWORD_PREDPUSH_SAME_LEVEL;
        predpushSameLevelHint->base.state = HINT_STATE_NOTUSED;
        predpushSameLevelHint->dest_name = $5;
        predpushSameLevelHint->dest_id = 0;
        predpushSameLevelHint->candidates = NULL;
        predpushSameLevelHint->negative = false;
        $$ = (Node *) predpushSameLevelHint;
    }

join_order_hint:
	Leading_P '(' relation_list_with_p ')'
	{
		LeadingHint *leadingHint = makeNode(LeadingHint);
		leadingHint->base.relnames = $3;
		leadingHint->join_order_hint = true;
		leadingHint->base.hint_keyword = HINT_KEYWORD_LEADING;
		$$ = (Node *) leadingHint;
	}
	| Leading_P relation_list_with_p
	{
		LeadingHint *leadingHint = makeNode(LeadingHint);
		leadingHint->base.relnames = $2;
		leadingHint->base.hint_keyword = HINT_KEYWORD_LEADING;
		$$ = (Node *) leadingHint;
	}
	;

join_method_hint:
	NestLoop_P '(' ident_list ')'
	{
		JoinMethodHint *joinHint = makeNode(JoinMethodHint);
		joinHint->base.relnames = $3;
		joinHint->base.hint_keyword = HINT_KEYWORD_NESTLOOP;
		joinHint->base.state = HINT_STATE_NOTUSED;
		joinHint->joinrelids = NULL;
		joinHint->inner_joinrelids = NULL;

		$$ = (Node*)joinHint;
	}
	| MergeJoin_P '(' ident_list ')'
	{
		JoinMethodHint *joinHint = makeNode(JoinMethodHint);
		joinHint->base.relnames = $3;
		joinHint->base.hint_keyword = HINT_KEYWORD_MERGEJOIN;
		joinHint->base.state = HINT_STATE_NOTUSED;
		joinHint->joinrelids = NULL;
		joinHint->inner_joinrelids = NULL;

		$$ = (Node*)joinHint;
	}
	| HashJoin_P '(' ident_list ')'
	{
		JoinMethodHint *joinHint = makeNode(JoinMethodHint);
		joinHint->base.relnames = $3;
		joinHint->base.hint_keyword = HINT_KEYWORD_HASHJOIN;
		joinHint->base.state = HINT_STATE_NOTUSED;
		joinHint->joinrelids = NULL;
		joinHint->inner_joinrelids = NULL;

		$$ = (Node*)joinHint;
	}
	;

stream_hint:
	Broadcast_P '(' ident_list ')'
	{
#ifndef ENABLE_MULTIPLE_NODES
		hint_scanner_yyerror("unsupport distributed hint", yyscanner);
		$$ = NULL;
#else /* ENABLE_MULTIPLE_NODES */
		StreamHint *streamHint = makeNode(StreamHint);
		streamHint->base.relnames = $3;
		streamHint->base.hint_keyword = HINT_KEYWORD_BROADCAST;
		streamHint->stream_type = STREAM_BROADCAST;

		$$ = (Node*)streamHint;
#endif /* ENABLE_MULTIPLE_NODES */
	}
	| Redistribute_P '(' ident_list ')'
	{
#ifndef ENABLE_MULTIPLE_NODES
		hint_scanner_yyerror("unsupport distributed hint", yyscanner);
		$$ = NULL;
#else /* ENABLE_MULTIPLE_NODES */
		StreamHint *streamHint = makeNode(StreamHint);
		streamHint->base.relnames = $3;
		streamHint->base.hint_keyword = HINT_KEYWORD_REDISTRIBUTE;
		streamHint->stream_type = STREAM_REDISTRIBUTE;

		$$ = (Node*)streamHint;
#endif /* ENABLE_MULTIPLE_NODES */
	}
	;

row_hint:
	Rows_P '(' ident_list '#' expr_const ')'
	{
		RowsHint *rowHint = makeNode(RowsHint);
		rowHint->base.relnames = $3;
		rowHint->base.hint_keyword = HINT_KEYWORD_ROWS;
		rowHint->value_type = RVT_ABSOLUTE;
		rowHint->rows = convert_to_numeric($5);
		if (IsA($5, Float))
			rowHint->rows_str = strVal($5);

		$$ = (Node *) rowHint;
	}
	| Rows_P '(' ident_list '+' expr_const ')'
	{
		RowsHint *rowHint = makeNode(RowsHint);
		rowHint->base.relnames = $3;
		rowHint->base.hint_keyword = HINT_KEYWORD_ROWS;
		rowHint->value_type = RVT_ADD;
		rowHint->rows = convert_to_numeric($5);
		if (IsA($5, Float))
			rowHint->rows_str = strVal($5);

		$$ = (Node *) rowHint;
	}
	| Rows_P '(' ident_list '-' expr_const ')'
	{
		RowsHint *rowHint = makeNode(RowsHint);
		rowHint->base.relnames = $3;
		rowHint->base.hint_keyword = HINT_KEYWORD_ROWS;
		rowHint->value_type = RVT_SUB;
		rowHint->rows = convert_to_numeric($5);
		if (IsA($5, Float))
			rowHint->rows_str = strVal($5);

		$$ = (Node *) rowHint;
	}
	| Rows_P '(' ident_list '*' expr_const ')'
	{
		RowsHint *rowHint = makeNode(RowsHint);
		rowHint->base.relnames = $3;
		rowHint->base.hint_keyword = HINT_KEYWORD_ROWS;
		rowHint->value_type = RVT_MULTI;
		rowHint->rows = convert_to_numeric($5);
		if (IsA($5, Float))
			rowHint->rows_str = strVal($5);

		$$ = (Node *) rowHint;
	}
	;

scan_hint:
	TableScan_P '(' IDENT ')'
	{
		ScanMethodHint	*scanHint = makeNode(ScanMethodHint);
		scanHint->base.relnames = list_make1(makeString($3));
		scanHint->base.hint_keyword = HINT_KEYWORD_TABLESCAN;
		scanHint->base.state = HINT_STATE_NOTUSED;
		$$ = (Node *) scanHint;
	}
	|
	IndexScan_P '(' ident_list ')'
	{
		ScanMethodHint	*scanHint = makeNode(ScanMethodHint);
		scanHint->base.relnames = list_make1(linitial($3));
		scanHint->base.hint_keyword = HINT_KEYWORD_INDEXSCAN;
		scanHint->base.state = HINT_STATE_NOTUSED;
		scanHint->indexlist = list_delete_first($3);
		$$ = (Node *) scanHint;
	}
	|
	IndexOnlyScan_P '(' ident_list ')'
	{
		ScanMethodHint	*scanHint = makeNode(ScanMethodHint);
		scanHint->base.relnames = list_make1(linitial($3));
		scanHint->base.hint_keyword = HINT_KEYWORD_INDEXONLYSCAN;
		scanHint->base.state = HINT_STATE_NOTUSED;
		scanHint->indexlist = list_delete_first($3);
		$$ = (Node *) scanHint;
	}
	;

skew_hint:
	Skew_P '(' skew_relist column_list_p value_list_p ')'
	{
#ifndef ENABLE_MULTIPLE_NODES
		hint_scanner_yyerror("unsupport distributed hint", yyscanner);
		$$ = NULL;
#else /* ENABLE_MULTIPLE_NODES */
		SkewHint	*skewHint = makeNode(SkewHint);
		skewHint->base.relnames = $3;
		skewHint->base.hint_keyword = HINT_KEYWORD_SKEW;
		skewHint->base.state = HINT_STATE_NOTUSED;
		skewHint->column_list = $4;
		skewHint->value_list = $5;
		$$ = (Node *) skewHint;
#endif /* ENABLE_MULTIPLE_NODES */
	}
	|
	Skew_P '(' skew_relist column_list_p ')'
	{
#ifndef ENABLE_MULTIPLE_NODES
		hint_scanner_yyerror("unsupport distributed hint", yyscanner);
		$$ = NULL;
#else /* ENABLE_MULTIPLE_NODES */
		SkewHint	*skewHint = makeNode(SkewHint);
		skewHint->base.relnames = $3;
		skewHint->base.hint_keyword = HINT_KEYWORD_SKEW;
		skewHint->base.state = HINT_STATE_NOTUSED;
		skewHint->column_list = $4;
		skewHint->value_list = NIL;
		$$ = (Node *) skewHint;
#endif /* ENABLE_MULTIPLE_NODES */
	}
	;

relation_list_with_p:
	'(' relation_list ')'           { $$ = $2; }
	;

relation_item:
	IDENT                           { $$ = list_make1(makeString($1)); }
	| relation_list_with_p          { $$ = list_make1($1); }
	;

relation_list:
	relation_item relation_item       { $$ = list_concat($1, $2); }
	| relation_list relation_item       { $$ = list_concat($1, $2); }
	;

ident_list:
	IDENT				{ $$ = list_make1(makeString($1)); }
	| ident_list IDENT		{ $$ = lappend($1, makeString($2)); }
	;

expr_const:
	ICONST				{ $$ = (Node *) makeInteger($1); }
	| FCONST			{ $$ = (Node *) makeFloat($1); }
	;	

skew_relist:
	IDENT					{ $$ = list_make1(makeString($1)); }
	|'(' ident_list ')'		{ $$ = $2; }
	;

column_list_p:
	'(' column_list ')'	{ $$ = $2; }
	;

column_list:
	IDENT					{ $$ = list_make1(makeString($1)); }
	| column_list IDENT		{ $$ = lappend($1, makeString($2)); }
	;

value_list_p:
	'(' value_list ')'     { $$ = $2; }
	;

value_list:
	value_list_item				   { $$ = $1; }
	| value_list_with_bracket      { $$ = $1; }
	;

value_list_with_bracket:
	value_list_p		{ $$ = $1; }
	| value_list_with_bracket value_list_p   { $$ = list_concat($1, $2); }
	;

value_list_item:
	value_type			{ $$ = $1; }
	| value_list_item value_type		{$$ = list_concat($1, $2); }
	;

value_type:
	ICONST				{ $$ = list_make1(makeInteger($1)); }
	| FCONST			{ $$ = list_make1(makeFloat($1)); }
	| SCONST			{ $$ = list_make1(makeStringValue($1)); } /* specially process for null value. */
	| BCONST 			{ $$ = list_make1(makeBitStringValue($1)); } /* for bit string litera*/
	| XCONST 			{ $$ = list_make1(makeString($1)); }  /* hexadecimal numeric string*/
	| NULL_P			{ $$ = list_make1(makeNullValue()); }
	| TRUE_P			{ $$ = list_make1(makeBoolValue(TRUE)); } /* for boolean type, we save as string with type T_String. */
	| FALSE_P			{ $$ = list_make1(makeBoolValue(FALSE)); }
	;
%%

void
 yyerror(yyscan_t yyscanner, const char *msg)
{
	hint_scanner_yyerror(msg, yyscanner);
	return;
}

static double
convert_to_numeric(Node *value)
{
	double	d = 0;
	Value	*vvalue = (Value *) value;

	switch(nodeTag(vvalue))
	{
		case T_Integer:
			d = intVal(vvalue);
			break;
		case T_Float:
			d = floatVal(vvalue);
			break;
		default:
			break;
	}

	return d;
}

static Value *
makeStringValue(char *str)
{
	Value	   *val = makeNode(Value);

	if (u_sess->attr.attr_sql.sql_compatibility == A_FORMAT)
	{
		if (NULL == str || (0 == strlen(str) && !ACCEPT_EMPTY_STR))
		{
			val->type = T_Null;
			val->val.str = str;
		}
		else
		{
			val->type = T_String;
			val->val.str = str;
		}
	}
	else
	{
		val->type = T_String;
		val->val.str = str;
	}

	return val;
}

static Value *
makeBitStringValue(char *str)
{
	Value	*val = makeNode(Value);

	val->type = T_BitString;
	val->val.str = str;

	return val;
}

static Value *
makeNullValue()
{
	Value	*val = makeNode(Value);

	val->type = T_Null;

	return val;

}

static Value *
makeBoolValue(bool state)
{
	Value	*val = makeNode(Value);
	val->type = T_String;
	val->val.str = (char *)(state ? "t" : "f");

	return val;
}

static void
doNegateFloat(Value *v)
{
	char   *oldval = v->val.str;
	Assert(IsA(v, Float));
	if (*oldval == '+')
		oldval++;
	if (*oldval == '-')
		v->val.str = oldval + 1;	/* just strip the '-' */
	else
	{
		char   *newval = (char *) palloc(strlen(oldval) + 2);

		*newval = '-';
		strcpy(newval + 1, oldval);
		v->val.str = newval;
	}
}

static Value* integerToString(Value *v)
{
    Assert(IsA(v, Integer));
    long num = intVal(v);
    const int max_len_long_type = 11;
    char* str = (char*)palloc0(sizeof(char) * (max_len_long_type + 1));
    errno_t rc = sprintf_s(str, max_len_long_type + 1, "%ld", num);
    securec_check_ss(rc, "\0", "\0");
	Value* ret = makeString(str);
    pfree(v);
    return ret;
}

#include "hint_scan.inc"