ne 7. 2. 2021 v 19:09 odesÃlatel Pavel Stehule <[email protected]>
napsal:
> Hi
>
> fresh rebase
>
only rebase
Regards
Pavel
> Regards
>
> Pavel
>
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 78b593d12c..1048343c21 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -4066,6 +4066,8 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
{
(*plpgsql_plugin_ptr)->error_callback = plpgsql_exec_error_callback;
(*plpgsql_plugin_ptr)->assign_expr = exec_assign_expr;
+ (*plpgsql_plugin_ptr)->eval_datum = exec_eval_datum;
+ (*plpgsql_plugin_ptr)->cast_value = do_cast_value;
if ((*plpgsql_plugin_ptr)->func_setup)
((*plpgsql_plugin_ptr)->func_setup) (estate, func);
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y
index 3fcca43b90..b10c988851 100644
--- a/src/pl/plpgsql/src/pl_gram.y
+++ b/src/pl/plpgsql/src/pl_gram.y
@@ -415,6 +415,7 @@ pl_block : decl_sect K_BEGIN proc_sect exception_sect K_END opt_label
new->cmd_type = PLPGSQL_STMT_BLOCK;
new->lineno = plpgsql_location_to_lineno(@2);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->label = $1.label;
new->n_initvars = $1.n_initvars;
new->initvarnos = $1.initvarnos;
@@ -907,7 +908,8 @@ stmt_perform : K_PERFORM
new = palloc0(sizeof(PLpgSQL_stmt_perform));
new->cmd_type = PLPGSQL_STMT_PERFORM;
new->lineno = plpgsql_location_to_lineno(@1);
- new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
plpgsql_push_back_token(K_PERFORM);
/*
@@ -943,6 +945,7 @@ stmt_call : K_CALL
new->cmd_type = PLPGSQL_STMT_CALL;
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
plpgsql_push_back_token(K_CALL);
new->expr = read_sql_stmt();
new->is_call = true;
@@ -962,6 +965,7 @@ stmt_call : K_CALL
new->cmd_type = PLPGSQL_STMT_CALL;
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
plpgsql_push_back_token(K_DO);
new->expr = read_sql_stmt();
new->is_call = false;
@@ -1000,7 +1004,8 @@ stmt_assign : T_DATUM
new = palloc0(sizeof(PLpgSQL_stmt_assign));
new->cmd_type = PLPGSQL_STMT_ASSIGN;
new->lineno = plpgsql_location_to_lineno(@1);
- new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->varno = $1.datum->dno;
/* Push back the head name to include it in the stmt */
plpgsql_push_back_token(T_DATUM);
@@ -1022,6 +1027,7 @@ stmt_getdiag : K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';'
new->cmd_type = PLPGSQL_STMT_GETDIAG;
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->is_stacked = $2;
new->diag_items = $4;
@@ -1194,6 +1200,7 @@ stmt_if : K_IF expr_until_then proc_sect stmt_elsifs stmt_else K_END K_IF ';'
new->cmd_type = PLPGSQL_STMT_IF;
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->cond = $2;
new->then_body = $3;
new->elsif_list = $4;
@@ -1299,6 +1306,7 @@ stmt_loop : opt_loop_label K_LOOP loop_body
new->cmd_type = PLPGSQL_STMT_LOOP;
new->lineno = plpgsql_location_to_lineno(@2);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->label = $1;
new->body = $3.stmts;
@@ -1317,6 +1325,7 @@ stmt_while : opt_loop_label K_WHILE expr_until_loop loop_body
new->cmd_type = PLPGSQL_STMT_WHILE;
new->lineno = plpgsql_location_to_lineno(@2);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->label = $1;
new->cond = $3;
new->body = $4.stmts;
@@ -1381,6 +1390,7 @@ for_control : for_variable K_IN
new = palloc0(sizeof(PLpgSQL_stmt_dynfors));
new->cmd_type = PLPGSQL_STMT_DYNFORS;
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
if ($1.row)
{
new->var = (PLpgSQL_variable *) $1.row;
@@ -1427,6 +1437,7 @@ for_control : for_variable K_IN
new = (PLpgSQL_stmt_forc *) palloc0(sizeof(PLpgSQL_stmt_forc));
new->cmd_type = PLPGSQL_STMT_FORC;
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->curvar = cursor->dno;
/* Should have had a single variable name */
@@ -1547,6 +1558,7 @@ for_control : for_variable K_IN
new = palloc0(sizeof(PLpgSQL_stmt_fori));
new->cmd_type = PLPGSQL_STMT_FORI;
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->var = fvar;
new->reverse = reverse;
new->lower = expr1;
@@ -1575,6 +1587,7 @@ for_control : for_variable K_IN
new = palloc0(sizeof(PLpgSQL_stmt_fors));
new->cmd_type = PLPGSQL_STMT_FORS;
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
if ($1.row)
{
new->var = (PLpgSQL_variable *) $1.row;
@@ -1676,6 +1689,7 @@ stmt_foreach_a : opt_loop_label K_FOREACH for_variable foreach_slice K_IN K_ARRA
new->cmd_type = PLPGSQL_STMT_FOREACH_A;
new->lineno = plpgsql_location_to_lineno(@2);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->label = $1;
new->slice = $4;
new->expr = $7;
@@ -1723,6 +1737,7 @@ stmt_exit : exit_type opt_label opt_exitcond
new = palloc0(sizeof(PLpgSQL_stmt_exit));
new->cmd_type = PLPGSQL_STMT_EXIT;
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->is_exit = $1;
new->lineno = plpgsql_location_to_lineno(@1);
new->label = $2;
@@ -1815,6 +1830,7 @@ stmt_raise : K_RAISE
new->cmd_type = PLPGSQL_STMT_RAISE;
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->elog_level = ERROR; /* default */
new->condname = NULL;
new->message = NULL;
@@ -1960,6 +1976,7 @@ stmt_assert : K_ASSERT
new->cmd_type = PLPGSQL_STMT_ASSERT;
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->cond = read_sql_expression2(',', ';',
", or ;",
@@ -2040,6 +2057,7 @@ stmt_dynexecute : K_EXECUTE
new->cmd_type = PLPGSQL_STMT_DYNEXECUTE;
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->query = expr;
new->into = false;
new->strict = false;
@@ -2097,6 +2115,7 @@ stmt_open : K_OPEN cursor_variable
new->cmd_type = PLPGSQL_STMT_OPEN;
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->curvar = $2->dno;
new->cursor_options = CURSOR_OPT_FAST_PLAN;
@@ -2222,6 +2241,7 @@ stmt_close : K_CLOSE cursor_variable ';'
new->cmd_type = PLPGSQL_STMT_CLOSE;
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->curvar = $2->dno;
$$ = (PLpgSQL_stmt *)new;
@@ -2243,6 +2263,7 @@ stmt_commit : K_COMMIT opt_transaction_chain ';'
new->cmd_type = PLPGSQL_STMT_COMMIT;
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->chain = $2;
$$ = (PLpgSQL_stmt *)new;
@@ -2257,6 +2278,7 @@ stmt_rollback : K_ROLLBACK opt_transaction_chain ';'
new->cmd_type = PLPGSQL_STMT_ROLLBACK;
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->chain = $2;
$$ = (PLpgSQL_stmt *)new;
@@ -2269,7 +2291,6 @@ opt_transaction_chain:
| /* EMPTY */ { $$ = false; }
;
-
cursor_variable : T_DATUM
{
/*
@@ -3047,6 +3068,7 @@ make_execsql_stmt(int firsttoken, int location)
execsql->cmd_type = PLPGSQL_STMT_EXECSQL;
execsql->lineno = plpgsql_location_to_lineno(location);
execsql->stmtid = ++plpgsql_curr_compile->nstatements;
+ execsql->ns = plpgsql_ns_top();
execsql->sqlstmt = expr;
execsql->into = have_into;
execsql->strict = have_strict;
@@ -3073,6 +3095,7 @@ read_fetch_direction(void)
fetch = (PLpgSQL_stmt_fetch *) palloc0(sizeof(PLpgSQL_stmt_fetch));
fetch->cmd_type = PLPGSQL_STMT_FETCH;
fetch->stmtid = ++plpgsql_curr_compile->nstatements;
+ fetch->ns = plpgsql_ns_top();
/* set direction defaults: */
fetch->direction = FETCH_FORWARD;
fetch->how_many = 1;
@@ -3226,6 +3249,7 @@ make_return_stmt(int location)
new->cmd_type = PLPGSQL_STMT_RETURN;
new->lineno = plpgsql_location_to_lineno(location);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->expr = NULL;
new->retvarno = -1;
@@ -3314,6 +3338,7 @@ make_return_next_stmt(int location)
new->cmd_type = PLPGSQL_STMT_RETURN_NEXT;
new->lineno = plpgsql_location_to_lineno(location);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->expr = NULL;
new->retvarno = -1;
@@ -3378,6 +3403,7 @@ make_return_query_stmt(int location)
new->cmd_type = PLPGSQL_STMT_RETURN_QUERY;
new->lineno = plpgsql_location_to_lineno(location);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
/* check for RETURN QUERY EXECUTE */
if ((tok = yylex()) != K_EXECUTE)
@@ -4042,6 +4068,7 @@ make_case(int location, PLpgSQL_expr *t_expr,
new->cmd_type = PLPGSQL_STMT_CASE;
new->lineno = plpgsql_location_to_lineno(location);
new->stmtid = ++plpgsql_curr_compile->nstatements;
+ new->ns = plpgsql_ns_top();
new->t_expr = t_expr;
new->t_varno = 0;
new->case_when_list = case_when_list;
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index fcbfcd678b..2675e0a645 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -460,6 +460,9 @@ typedef struct PLpgSQL_stmt
* per-statement metrics.
*/
unsigned int stmtid;
+
+ /* namespace chain visible to this statement */
+ PLpgSQL_nsitem *ns;
} PLpgSQL_stmt;
/*
@@ -500,6 +503,7 @@ typedef struct PLpgSQL_stmt_block
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
char *label;
List *body; /* List of statements */
int n_initvars; /* Length of initvarnos[] */
@@ -515,6 +519,7 @@ typedef struct PLpgSQL_stmt_assign
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
int varno;
PLpgSQL_expr *expr;
} PLpgSQL_stmt_assign;
@@ -527,6 +532,7 @@ typedef struct PLpgSQL_stmt_perform
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
PLpgSQL_expr *expr;
} PLpgSQL_stmt_perform;
@@ -538,6 +544,7 @@ typedef struct PLpgSQL_stmt_call
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
PLpgSQL_expr *expr;
bool is_call;
PLpgSQL_variable *target;
@@ -551,6 +558,7 @@ typedef struct PLpgSQL_stmt_commit
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
bool chain;
} PLpgSQL_stmt_commit;
@@ -562,6 +570,7 @@ typedef struct PLpgSQL_stmt_rollback
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
bool chain;
} PLpgSQL_stmt_rollback;
@@ -582,6 +591,7 @@ typedef struct PLpgSQL_stmt_getdiag
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
bool is_stacked; /* STACKED or CURRENT diagnostics area? */
List *diag_items; /* List of PLpgSQL_diag_item */
} PLpgSQL_stmt_getdiag;
@@ -594,6 +604,7 @@ typedef struct PLpgSQL_stmt_if
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
PLpgSQL_expr *cond; /* boolean expression for THEN */
List *then_body; /* List of statements */
List *elsif_list; /* List of PLpgSQL_if_elsif structs */
@@ -618,6 +629,7 @@ typedef struct PLpgSQL_stmt_case
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
PLpgSQL_expr *t_expr; /* test expression, or NULL if none */
int t_varno; /* var to store test expression value into */
List *case_when_list; /* List of PLpgSQL_case_when structs */
@@ -643,6 +655,7 @@ typedef struct PLpgSQL_stmt_loop
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
char *label;
List *body; /* List of statements */
} PLpgSQL_stmt_loop;
@@ -655,6 +668,7 @@ typedef struct PLpgSQL_stmt_while
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
char *label;
PLpgSQL_expr *cond;
List *body; /* List of statements */
@@ -668,6 +682,7 @@ typedef struct PLpgSQL_stmt_fori
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
char *label;
PLpgSQL_var *var;
PLpgSQL_expr *lower;
@@ -687,6 +702,7 @@ typedef struct PLpgSQL_stmt_forq
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
char *label;
PLpgSQL_variable *var; /* Loop variable (record or row) */
List *body; /* List of statements */
@@ -700,6 +716,7 @@ typedef struct PLpgSQL_stmt_fors
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
char *label;
PLpgSQL_variable *var; /* Loop variable (record or row) */
List *body; /* List of statements */
@@ -715,6 +732,7 @@ typedef struct PLpgSQL_stmt_forc
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
char *label;
PLpgSQL_variable *var; /* Loop variable (record or row) */
List *body; /* List of statements */
@@ -731,6 +749,7 @@ typedef struct PLpgSQL_stmt_dynfors
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
char *label;
PLpgSQL_variable *var; /* Loop variable (record or row) */
List *body; /* List of statements */
@@ -747,6 +766,7 @@ typedef struct PLpgSQL_stmt_foreach_a
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
char *label;
int varno; /* loop target variable */
int slice; /* slice dimension, or 0 */
@@ -762,6 +782,7 @@ typedef struct PLpgSQL_stmt_open
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
int curvar;
int cursor_options;
PLpgSQL_expr *argquery;
@@ -778,6 +799,7 @@ typedef struct PLpgSQL_stmt_fetch
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
PLpgSQL_variable *target; /* target (record or row) */
int curvar; /* cursor variable to fetch from */
FetchDirection direction; /* fetch direction */
@@ -795,6 +817,7 @@ typedef struct PLpgSQL_stmt_close
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
int curvar;
} PLpgSQL_stmt_close;
@@ -806,6 +829,7 @@ typedef struct PLpgSQL_stmt_exit
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
bool is_exit; /* Is this an exit or a continue? */
char *label; /* NULL if it's an unlabeled EXIT/CONTINUE */
PLpgSQL_expr *cond;
@@ -819,6 +843,7 @@ typedef struct PLpgSQL_stmt_return
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
PLpgSQL_expr *expr;
int retvarno;
} PLpgSQL_stmt_return;
@@ -831,6 +856,7 @@ typedef struct PLpgSQL_stmt_return_next
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
PLpgSQL_expr *expr;
int retvarno;
} PLpgSQL_stmt_return_next;
@@ -843,6 +869,7 @@ typedef struct PLpgSQL_stmt_return_query
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
PLpgSQL_expr *query; /* if static query */
PLpgSQL_expr *dynquery; /* if dynamic query (RETURN QUERY EXECUTE) */
List *params; /* USING arguments for dynamic query */
@@ -856,6 +883,7 @@ typedef struct PLpgSQL_stmt_raise
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
int elog_level;
char *condname; /* condition name, SQLSTATE, or NULL */
char *message; /* old-style message format literal, or NULL */
@@ -880,6 +908,7 @@ typedef struct PLpgSQL_stmt_assert
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
PLpgSQL_expr *cond;
PLpgSQL_expr *message;
} PLpgSQL_stmt_assert;
@@ -892,6 +921,7 @@ typedef struct PLpgSQL_stmt_execsql
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
PLpgSQL_expr *sqlstmt;
bool mod_stmt; /* is the stmt INSERT/UPDATE/DELETE? Note:
* mod_stmt is set when we plan the query */
@@ -908,6 +938,7 @@ typedef struct PLpgSQL_stmt_dynexecute
PLpgSQL_stmt_type cmd_type;
int lineno;
unsigned int stmtid;
+ PLpgSQL_nsitem *ns;
PLpgSQL_expr *query; /* string expression */
bool into; /* INTO supplied? */
bool strict; /* INTO STRICT flag */
@@ -1120,8 +1151,11 @@ typedef struct PLpgSQL_execstate
*
* Also, immediately before any call to func_setup, PL/pgSQL fills in the
* error_callback and assign_expr fields with pointers to its own
- * plpgsql_exec_error_callback and exec_assign_expr functions. This is
- * a somewhat ad-hoc expedient to simplify life for debugger plugins.
+ * plpgsql_exec_error_callback and exec_assign_expr functions. eval_datum
+ * is assigned to function exec_eval_datum, and cast_value to function
+ * do_cast_value. With last two functions is easy to get content of
+ * any PLpgSQL_datum in any expected type. This is a somewhat ad-hoc
+ * expedient to simplify life for debugger plugins.
*/
typedef struct PLpgSQL_plugin
{
@@ -1136,6 +1170,13 @@ typedef struct PLpgSQL_plugin
void (*error_callback) (void *arg);
void (*assign_expr) (PLpgSQL_execstate *estate, PLpgSQL_datum *target,
PLpgSQL_expr *expr);
+ void (*eval_datum) (PLpgSQL_execstate *estate, PLpgSQL_datum *datum,
+ Oid *typeid, int32 *typetypmod, Datum *value,
+ bool *isnull);
+ Datum (*cast_value) (PLpgSQL_execstate *estate,
+ Datum value, bool *isnull,
+ Oid valtype, int32 valtypmod,
+ Oid reqtype, int32 reqtypmod);
} PLpgSQL_plugin;
/*