diff options
-rw-r--r-- | src/pl/plpgsql/src/pl_exec.c | 27 | ||||
-rw-r--r-- | src/pl/plpgsql/src/pl_gram.y | 65 | ||||
-rw-r--r-- | src/pl/plpgsql/src/plpgsql.h | 31 |
3 files changed, 62 insertions, 61 deletions
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 35cda55cf9c..fec1811ae10 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -4175,12 +4175,6 @@ exec_prepare_plan(PLpgSQL_execstate *estate, SPIPrepareOptions options; /* - * The grammar can't conveniently set expr->func while building the parse - * tree, so make sure it's set before parser hooks need it. - */ - expr->func = estate->func; - - /* * Generate and save the plan */ memset(&options, 0, sizeof(options)); @@ -5016,21 +5010,7 @@ exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, * If first time through, create a plan for this expression. */ if (expr->plan == NULL) - { - /* - * Mark the expression as being an assignment source, if target is a - * simple variable. (This is a bit messy, but it seems cleaner than - * modifying the API of exec_prepare_plan for the purpose. We need to - * stash the target dno into the expr anyway, so that it will be - * available if we have to replan.) - */ - if (target->dtype == PLPGSQL_DTYPE_VAR) - expr->target_param = target->dno; - else - expr->target_param = -1; /* should be that already */ - exec_prepare_plan(estate, expr, 0); - } value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod); exec_assign_value(estate, target, value, isnull, valtype, valtypmod); @@ -6282,13 +6262,6 @@ setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr) * that they are interrupting an active use of parameters. */ paramLI->parserSetupArg = expr; - - /* - * Also make sure this is set before parser hooks need it. There is - * no need to save and restore, since the value is always correct once - * set. (Should be set already, but let's be sure.) - */ - expr->func = estate->func; } else { diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index 64d2c362bf9..f55aefb1008 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -61,6 +61,10 @@ static bool tok_is_keyword(int token, union YYSTYPE *lval, static void word_is_not_variable(PLword *word, int location, yyscan_t yyscanner); static void cword_is_not_variable(PLcword *cword, int location, yyscan_t yyscanner); static void current_token_is_not_variable(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); +static PLpgSQL_expr *make_plpgsql_expr(const char *query, + RawParseMode parsemode); +static void mark_expr_as_assignment_source(PLpgSQL_expr *expr, + PLpgSQL_datum *target); static PLpgSQL_expr *read_sql_construct(int until, int until2, int until3, @@ -536,6 +540,10 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull errmsg("variable \"%s\" must have a default value, since it's declared NOT NULL", var->refname), parser_errposition(@5))); + + if (var->default_val != NULL) + mark_expr_as_assignment_source(var->default_val, + (PLpgSQL_datum *) var); } | decl_varname K_ALIAS K_FOR decl_aliasitem ';' { @@ -996,6 +1004,7 @@ stmt_assign : T_DATUM false, true, NULL, NULL, &yylval, &yylloc, yyscanner); + mark_expr_as_assignment_source(new->expr, $1.datum); $$ = (PLpgSQL_stmt *) new; } @@ -2651,6 +2660,38 @@ current_token_is_not_variable(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yysca yyerror(yyllocp, NULL, yyscanner, "syntax error"); } +/* Convenience routine to construct a PLpgSQL_expr struct */ +static PLpgSQL_expr * +make_plpgsql_expr(const char *query, + RawParseMode parsemode) +{ + PLpgSQL_expr *expr = palloc0(sizeof(PLpgSQL_expr)); + + expr->query = pstrdup(query); + expr->parseMode = parsemode; + expr->func = plpgsql_curr_compile; + expr->ns = plpgsql_ns_top(); + /* might get changed later during parsing: */ + expr->target_param = -1; + /* other fields are left as zeroes until first execution */ + return expr; +} + +/* Mark a PLpgSQL_expr as being the source of an assignment to target */ +static void +mark_expr_as_assignment_source(PLpgSQL_expr *expr, PLpgSQL_datum *target) +{ + /* + * Mark the expression as being an assignment source, if target is a + * simple variable. We don't currently support optimized assignments to + * other DTYPEs, so no need to mark in other cases. + */ + if (target->dtype == PLPGSQL_DTYPE_VAR) + expr->target_param = target->dno; + else + expr->target_param = -1; /* should be that already */ +} + /* Convenience routine to read an expression with one possible terminator */ static PLpgSQL_expr * read_sql_expression(int until, const char *expected, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) @@ -2794,13 +2835,7 @@ read_sql_construct(int until, */ plpgsql_append_source_text(&ds, startlocation, endlocation, yyscanner); - expr = palloc0(sizeof(PLpgSQL_expr)); - expr->query = pstrdup(ds.data); - expr->parseMode = parsemode; - expr->plan = NULL; - expr->paramnos = NULL; - expr->target_param = -1; - expr->ns = plpgsql_ns_top(); + expr = make_plpgsql_expr(ds.data, parsemode); pfree(ds.data); if (valid_sql) @@ -3122,13 +3157,7 @@ make_execsql_stmt(int firsttoken, int location, PLword *word, YYSTYPE *yylvalp, while (ds.len > 0 && scanner_isspace(ds.data[ds.len - 1])) ds.data[--ds.len] = '\0'; - expr = palloc0(sizeof(PLpgSQL_expr)); - expr->query = pstrdup(ds.data); - expr->parseMode = RAW_PARSE_DEFAULT; - expr->plan = NULL; - expr->paramnos = NULL; - expr->target_param = -1; - expr->ns = plpgsql_ns_top(); + expr = make_plpgsql_expr(ds.data, RAW_PARSE_DEFAULT); pfree(ds.data); check_sql_expr(expr->query, expr->parseMode, location, yyscanner); @@ -4006,13 +4035,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until, YYSTYPE *yylvalp, YYLTYPE *yyll appendStringInfoString(&ds, ", "); } - expr = palloc0(sizeof(PLpgSQL_expr)); - expr->query = pstrdup(ds.data); - expr->parseMode = RAW_PARSE_PLPGSQL_EXPR; - expr->plan = NULL; - expr->paramnos = NULL; - expr->target_param = -1; - expr->ns = plpgsql_ns_top(); + expr = make_plpgsql_expr(ds.data, RAW_PARSE_PLPGSQL_EXPR); pfree(ds.data); /* Next we'd better find the until token */ diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index 441df5354e2..b0052167eef 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -219,14 +219,22 @@ typedef struct PLpgSQL_expr { char *query; /* query string, verbatim from function body */ RawParseMode parseMode; /* raw_parser() mode to use */ - SPIPlanPtr plan; /* plan, or NULL if not made yet */ - Bitmapset *paramnos; /* all dnos referenced by this query */ + struct PLpgSQL_function *func; /* function containing this expr */ + struct PLpgSQL_nsitem *ns; /* namespace chain visible to this expr */ - /* function containing this expr (not set until we first parse query) */ - struct PLpgSQL_function *func; + /* + * These fields are used to help optimize assignments to expanded-datum + * variables. If this expression is the source of an assignment to a + * simple variable, target_param holds that variable's dno (else it's -1). + */ + int target_param; /* dno of assign target, or -1 if none */ - /* namespace chain visible to this expr */ - struct PLpgSQL_nsitem *ns; + /* + * Fields above are set during plpgsql parsing. Remaining fields are left + * as zeroes/NULLs until we first parse/plan the query. + */ + SPIPlanPtr plan; /* plan, or NULL if not made yet */ + Bitmapset *paramnos; /* all dnos referenced by this query */ /* fields for "simple expression" fast-path execution: */ Expr *expr_simple_expr; /* NULL means not a simple expr */ @@ -235,14 +243,11 @@ typedef struct PLpgSQL_expr bool expr_simple_mutable; /* true if simple expr is mutable */ /* - * These fields are used to optimize assignments to expanded-datum - * variables. If this expression is the source of an assignment to a - * simple variable, target_param holds that variable's dno; else it's -1. - * If we match a Param within expr_simple_expr to such a variable, that - * Param's address is stored in expr_rw_param; then expression code - * generation will allow the value for that Param to be passed read/write. + * If we match a Param within expr_simple_expr to the variable identified + * by target_param, that Param's address is stored in expr_rw_param; then + * expression code generation will allow the value for that Param to be + * passed as a read/write expanded-object pointer. */ - int target_param; /* dno of assign target, or -1 if none */ Param *expr_rw_param; /* read/write Param within expr, if any */ /* |