PostgreSQL Source Code  git master
pl_exec.c File Reference
#include "postgres.h"
#include <ctype.h>
#include "access/detoast.h"
#include "access/htup_details.h"
#include "access/transam.h"
#include "access/tupconvert.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "executor/execExpr.h"
#include "executor/spi.h"
#include "executor/spi_priv.h"
#include "funcapi.h"
#include "mb/stringinfo_mb.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/parse_coerce.h"
#include "parser/parse_type.h"
#include "parser/scansup.h"
#include "plpgsql.h"
#include "storage/proc.h"
#include "tcop/tcopprot.h"
#include "tcop/utility.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
Include dependency graph for pl_exec.c:

Go to the source code of this file.

Data Structures

struct  PreparedParamsData
 
struct  SimpleEcontextStackEntry
 
struct  plpgsql_CastHashKey
 
struct  plpgsql_CastHashEntry
 

Macros

#define get_eval_mcontext(estate)   ((estate)->eval_econtext->ecxt_per_tuple_memory)
 
#define eval_mcontext_alloc(estate, sz)   MemoryContextAlloc(get_eval_mcontext(estate), sz)
 
#define eval_mcontext_alloc0(estate, sz)   MemoryContextAllocZero(get_eval_mcontext(estate), sz)
 
#define LOOP_RC_PROCESSING(looplabel, exit_action)
 
#define SET_RAISE_OPTION_TEXT(opt, name)
 

Typedefs

typedef struct SimpleEcontextStackEntry SimpleEcontextStackEntry
 

Functions

static void coerce_function_result_tuple (PLpgSQL_execstate *estate, TupleDesc tupdesc)
 
static void plpgsql_exec_error_callback (void *arg)
 
static void copy_plpgsql_datums (PLpgSQL_execstate *estate, PLpgSQL_function *func)
 
static void plpgsql_fulfill_promise (PLpgSQL_execstate *estate, PLpgSQL_var *var)
 
static MemoryContext get_stmt_mcontext (PLpgSQL_execstate *estate)
 
static void push_stmt_mcontext (PLpgSQL_execstate *estate)
 
static void pop_stmt_mcontext (PLpgSQL_execstate *estate)
 
static int exec_stmt_block (PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
 
static int exec_stmts (PLpgSQL_execstate *estate, List *stmts)
 
static int exec_stmt (PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
 
static int exec_stmt_assign (PLpgSQL_execstate *estate, PLpgSQL_stmt_assign *stmt)
 
static int exec_stmt_perform (PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
 
static int exec_stmt_call (PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
 
static int exec_stmt_getdiag (PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
 
static int exec_stmt_if (PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
 
static int exec_stmt_case (PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
 
static int exec_stmt_loop (PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
 
static int exec_stmt_while (PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
 
static int exec_stmt_fori (PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
 
static int exec_stmt_fors (PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
 
static int exec_stmt_forc (PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt)
 
static int exec_stmt_foreach_a (PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt)
 
static int exec_stmt_open (PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
 
static int exec_stmt_fetch (PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
 
static int exec_stmt_close (PLpgSQL_execstate *estate, PLpgSQL_stmt_close *stmt)
 
static int exec_stmt_exit (PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt)
 
static int exec_stmt_return (PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
 
static int exec_stmt_return_next (PLpgSQL_execstate *estate, PLpgSQL_stmt_return_next *stmt)
 
static int exec_stmt_return_query (PLpgSQL_execstate *estate, PLpgSQL_stmt_return_query *stmt)
 
static int exec_stmt_raise (PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 
static int exec_stmt_assert (PLpgSQL_execstate *estate, PLpgSQL_stmt_assert *stmt)
 
static int exec_stmt_execsql (PLpgSQL_execstate *estate, PLpgSQL_stmt_execsql *stmt)
 
static int exec_stmt_dynexecute (PLpgSQL_execstate *estate, PLpgSQL_stmt_dynexecute *stmt)
 
static int exec_stmt_dynfors (PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
 
static int exec_stmt_commit (PLpgSQL_execstate *estate, PLpgSQL_stmt_commit *stmt)
 
static int exec_stmt_rollback (PLpgSQL_execstate *estate, PLpgSQL_stmt_rollback *stmt)
 
static int exec_stmt_set (PLpgSQL_execstate *estate, PLpgSQL_stmt_set *stmt)
 
static void plpgsql_estate_setup (PLpgSQL_execstate *estate, PLpgSQL_function *func, ReturnSetInfo *rsi, EState *simple_eval_estate)
 
static void exec_eval_cleanup (PLpgSQL_execstate *estate)
 
static void exec_prepare_plan (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions, bool keepplan)
 
static void exec_simple_check_plan (PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
 
static void exec_save_simple_expr (PLpgSQL_expr *expr, CachedPlan *cplan)
 
static void exec_check_rw_parameter (PLpgSQL_expr *expr, int target_dno)
 
static bool contains_target_param (Node *node, int *target_dno)
 
static bool exec_eval_simple_expr (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, Datum *result, bool *isNull, Oid *rettype, int32 *rettypmod)
 
static void exec_assign_expr (PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
 
static void exec_assign_c_string (PLpgSQL_execstate *estate, PLpgSQL_datum *target, const char *str)
 
static void exec_assign_value (PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
 
static void exec_eval_datum (PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeid, int32 *typetypmod, Datum *value, bool *isnull)
 
static int exec_eval_integer (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
 
static bool exec_eval_boolean (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
 
static Datum exec_eval_expr (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
 
static int exec_run_select (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
 
static int exec_for_query (PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt, Portal portal, bool prefetch_ok)
 
static ParamListInfo setup_param_list (PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
 
static ParamExternDataplpgsql_param_fetch (ParamListInfo params, int paramid, bool speculative, ParamExternData *workspace)
 
static void plpgsql_param_compile (ParamListInfo params, Param *param, ExprState *state, Datum *resv, bool *resnull)
 
static void plpgsql_param_eval_var (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void plpgsql_param_eval_var_ro (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void plpgsql_param_eval_recfield (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void plpgsql_param_eval_generic (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void plpgsql_param_eval_generic_ro (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void exec_move_row (PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
 
static void revalidate_rectypeid (PLpgSQL_rec *rec)
 
static ExpandedRecordHeadermake_expanded_record_for_rec (PLpgSQL_execstate *estate, PLpgSQL_rec *rec, TupleDesc srctupdesc, ExpandedRecordHeader *srcerh)
 
static void exec_move_row_from_fields (PLpgSQL_execstate *estate, PLpgSQL_variable *target, ExpandedRecordHeader *newerh, Datum *values, bool *nulls, TupleDesc tupdesc)
 
static bool compatible_tupdescs (TupleDesc src_tupdesc, TupleDesc dst_tupdesc)
 
static HeapTuple make_tuple_from_row (PLpgSQL_execstate *estate, PLpgSQL_row *row, TupleDesc tupdesc)
 
static TupleDesc deconstruct_composite_datum (Datum value, HeapTupleData *tmptup)
 
static void exec_move_row_from_datum (PLpgSQL_execstate *estate, PLpgSQL_variable *target, Datum value)
 
static void instantiate_empty_record_variable (PLpgSQL_execstate *estate, PLpgSQL_rec *rec)
 
static char * convert_value_to_string (PLpgSQL_execstate *estate, Datum value, Oid valtype)
 
static Datum exec_cast_value (PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
 
static plpgsql_CastHashEntryget_cast_hashentry (PLpgSQL_execstate *estate, Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod)
 
static void exec_init_tuple_store (PLpgSQL_execstate *estate)
 
static void exec_set_found (PLpgSQL_execstate *estate, bool state)
 
static void plpgsql_create_econtext (PLpgSQL_execstate *estate)
 
static void plpgsql_destroy_econtext (PLpgSQL_execstate *estate)
 
static void assign_simple_var (PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
 
static void assign_text_var (PLpgSQL_execstate *estate, PLpgSQL_var *var, const char *str)
 
static void assign_record_var (PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
 
static PreparedParamsDataexec_eval_using_params (PLpgSQL_execstate *estate, List *params)
 
static Portal exec_dynquery_with_params (PLpgSQL_execstate *estate, PLpgSQL_expr *dynquery, List *params, const char *portalname, int cursorOptions)
 
static char * format_expr_params (PLpgSQL_execstate *estate, const PLpgSQL_expr *expr)
 
static char * format_preparedparamsdata (PLpgSQL_execstate *estate, const PreparedParamsData *ppd)
 
Datum plpgsql_exec_function (PLpgSQL_function *func, FunctionCallInfo fcinfo, EState *simple_eval_estate, bool atomic)
 
HeapTuple plpgsql_exec_trigger (PLpgSQL_function *func, TriggerData *trigdata)
 
void plpgsql_exec_event_trigger (PLpgSQL_function *func, EventTriggerData *trigdata)
 
static bool exception_matches_conditions (ErrorData *edata, PLpgSQL_condition *cond)
 
Oid plpgsql_exec_get_datum_type (PLpgSQL_execstate *estate, PLpgSQL_datum *datum)
 
void plpgsql_exec_get_datum_type_info (PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeId, int32 *typMod, Oid *collation)
 
void plpgsql_xact_cb (XactEvent event, void *arg)
 
void plpgsql_subxact_cb (SubXactEvent event, SubTransactionId mySubid, SubTransactionId parentSubid, void *arg)
 

Variables

static EStateshared_simple_eval_estate = NULL
 
static SimpleEcontextStackEntrysimple_econtext_stack = NULL
 
static MemoryContext shared_cast_context = NULL
 
static HTABshared_cast_hash = NULL
 

Macro Definition Documentation

◆ eval_mcontext_alloc

#define eval_mcontext_alloc (   estate,
  sz 
)    MemoryContextAlloc(get_eval_mcontext(estate), sz)

◆ eval_mcontext_alloc0

#define eval_mcontext_alloc0 (   estate,
  sz 
)    MemoryContextAllocZero(get_eval_mcontext(estate), sz)

Definition at line 124 of file pl_exec.c.

Referenced by exec_stmt_return_next(), and make_tuple_from_row().

◆ get_eval_mcontext

◆ LOOP_RC_PROCESSING

#define LOOP_RC_PROCESSING (   looplabel,
  exit_action 
)

◆ SET_RAISE_OPTION_TEXT

#define SET_RAISE_OPTION_TEXT (   opt,
  name 
)
Value:
do { \
if (opt) \
ereport(ERROR, \
(errcode(ERRCODE_SYNTAX_ERROR), \
errmsg("RAISE option already specified: %s", \
name))); \
opt = MemoryContextStrdup(stmt_mcontext, extval); \
} while (0)
int errcode(int sqlerrcode)
Definition: elog.c:608
#define ERROR
Definition: elog.h:43
const char * name
Definition: encode.c:521
int errmsg(const char *fmt,...)
Definition: elog.c:822
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1173

Definition at line 3604 of file pl_exec.c.

Referenced by exec_stmt_raise().

Typedef Documentation

◆ SimpleEcontextStackEntry

Function Documentation

◆ assign_record_var()

static void assign_record_var ( PLpgSQL_execstate estate,
PLpgSQL_rec rec,
ExpandedRecordHeader erh 
)
static

Definition at line 8401 of file pl_exec.c.

References Assert, PLpgSQL_execstate::datum_context, DeleteExpandedObject(), PLpgSQL_rec::dtype, PLpgSQL_rec::erh, ExpandedRecordGetDatum, PLPGSQL_DTYPE_REC, and TransferExpandedRecord.

Referenced by exec_move_row(), exec_move_row_from_datum(), and exec_move_row_from_fields().

8403 {
8404  Assert(rec->dtype == PLPGSQL_DTYPE_REC);
8405 
8406  /* Transfer new record object into datum_context */
8407  TransferExpandedRecord(erh, estate->datum_context);
8408 
8409  /* Free the old value ... */
8410  if (rec->erh)
8412 
8413  /* ... and install the new */
8414  rec->erh = erh;
8415 }
PLpgSQL_datum_type dtype
Definition: plpgsql.h:372
ExpandedRecordHeader * erh
Definition: plpgsql.h:395
void DeleteExpandedObject(Datum d)
#define Assert(condition)
Definition: c.h:739
#define TransferExpandedRecord(erh, cxt)
MemoryContext datum_context
Definition: plpgsql.h:1074
#define ExpandedRecordGetDatum(erh)

◆ assign_simple_var()

static void assign_simple_var ( PLpgSQL_execstate estate,
PLpgSQL_var var,
Datum  newvalue,
bool  isnull,
bool  freeable 
)
static

Definition at line 8325 of file pl_exec.c.

References Assert, PLpgSQL_execstate::atomic, PLpgSQL_var::datatype, datumCopy(), DatumGetPointer, DatumIsReadWriteExpandedObject, DeleteExpandedObject(), detoast_external_attr(), PLpgSQL_var::dtype, PLpgSQL_var::freeval, get_eval_mcontext, PLpgSQL_var::isnull, MemoryContextSwitchTo(), pfree(), PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_VAR, PLPGSQL_PROMISE_NONE, PointerGetDatum, PLpgSQL_var::promise, PLpgSQL_type::typlen, PLpgSQL_var::value, and VARATT_IS_EXTERNAL_NON_EXPANDED.

Referenced by assign_text_var(), exec_assign_value(), exec_set_found(), exec_stmt_block(), exec_stmt_case(), exec_stmt_forc(), exec_stmt_fori(), plpgsql_exec_function(), and plpgsql_fulfill_promise().

8327 {
8328  Assert(var->dtype == PLPGSQL_DTYPE_VAR ||
8329  var->dtype == PLPGSQL_DTYPE_PROMISE);
8330 
8331  /*
8332  * In non-atomic contexts, we do not want to store TOAST pointers in
8333  * variables, because such pointers might become stale after a commit.
8334  * Forcibly detoast in such cases. We don't want to detoast (flatten)
8335  * expanded objects, however; those should be OK across a transaction
8336  * boundary since they're just memory-resident objects. (Elsewhere in
8337  * this module, operations on expanded records likewise need to request
8338  * detoasting of record fields when !estate->atomic. Expanded arrays are
8339  * not a problem since all array entries are always detoasted.)
8340  */
8341  if (!estate->atomic && !isnull && var->datatype->typlen == -1 &&
8343  {
8344  MemoryContext oldcxt;
8345  Datum detoasted;
8346 
8347  /*
8348  * Do the detoasting in the eval_mcontext to avoid long-term leakage
8349  * of whatever memory toast fetching might leak. Then we have to copy
8350  * the detoasted datum to the function's main context, which is a
8351  * pain, but there's little choice.
8352  */
8353  oldcxt = MemoryContextSwitchTo(get_eval_mcontext(estate));
8354  detoasted = PointerGetDatum(detoast_external_attr((struct varlena *) DatumGetPointer(newvalue)));
8355  MemoryContextSwitchTo(oldcxt);
8356  /* Now's a good time to not leak the input value if it's freeable */
8357  if (freeable)
8358  pfree(DatumGetPointer(newvalue));
8359  /* Once we copy the value, it's definitely freeable */
8360  newvalue = datumCopy(detoasted, false, -1);
8361  freeable = true;
8362  /* Can't clean up eval_mcontext here, but it'll happen before long */
8363  }
8364 
8365  /* Free the old value if needed */
8366  if (var->freeval)
8367  {
8369  var->isnull,
8370  var->datatype->typlen))
8372  else
8373  pfree(DatumGetPointer(var->value));
8374  }
8375  /* Assign new value to datum */
8376  var->value = newvalue;
8377  var->isnull = isnull;
8378  var->freeval = freeable;
8379 
8380  /*
8381  * If it's a promise variable, then either we just assigned the promised
8382  * value, or the user explicitly assigned an overriding value. Either
8383  * way, cancel the promise.
8384  */
8386 }
PLpgSQL_promise_type promise
Definition: plpgsql.h:323
#define VARATT_IS_EXTERNAL_NON_EXPANDED(PTR)
Definition: postgres.h:324
PLpgSQL_datum_type dtype
Definition: plpgsql.h:292
#define PointerGetDatum(X)
Definition: postgres.h:556
struct varlena * detoast_external_attr(struct varlena *attr)
Definition: detoast.c:45
PLpgSQL_type * datatype
Definition: plpgsql.h:301
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void pfree(void *pointer)
Definition: mcxt.c:1056
bool freeval
Definition: plpgsql.h:316
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:130
#define get_eval_mcontext(estate)
Definition: pl_exec.c:120
uintptr_t Datum
Definition: postgres.h:367
Datum value
Definition: plpgsql.h:314
void DeleteExpandedObject(Datum d)
#define Assert(condition)
Definition: c.h:739
#define DatumIsReadWriteExpandedObject(d, isnull, typlen)
#define DatumGetPointer(X)
Definition: postgres.h:549
Definition: c.h:556
int16 typlen
Definition: plpgsql.h:204
bool isnull
Definition: plpgsql.h:315

◆ assign_text_var()

static void assign_text_var ( PLpgSQL_execstate estate,
PLpgSQL_var var,
const char *  str 
)
static

Definition at line 8392 of file pl_exec.c.

References assign_simple_var(), and CStringGetTextDatum.

Referenced by exec_stmt_block(), exec_stmt_forc(), exec_stmt_open(), and plpgsql_fulfill_promise().

8393 {
8394  assign_simple_var(estate, var, CStringGetTextDatum(str), false, true);
8395 }
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8325
#define CStringGetTextDatum(s)
Definition: builtins.h:83

◆ coerce_function_result_tuple()

static void coerce_function_result_tuple ( PLpgSQL_execstate estate,
TupleDesc  tupdesc 
)
static

Definition at line 774 of file pl_exec.c.

References Assert, convert_tuples_by_position(), DatumGetEOHP(), DatumGetPointer, deconstruct_composite_datum(), EOH_flatten_into(), EOH_get_flat_size(), ExpandedRecordHeader::er_decltypeid, ER_MAGIC, ExpandedRecordHeader::er_magic, execute_attr_map_tuple(), expanded_record_get_tupdesc(), expanded_record_get_tuple(), ExpandedRecordIsDomain, gettext_noop, ExpandedRecordHeader::hdr, HeapTupleHeaderSetTypeId, HeapTupleHeaderSetTypMod, PointerGetDatum, ReleaseTupleDesc, PLpgSQL_execstate::rettype, PLpgSQL_execstate::retval, SPI_datumTransfer(), SPI_palloc(), SPI_returntuple(), TupleDescData::tdtypeid, TupleDescData::tdtypmod, type_is_rowtype(), and VARATT_IS_EXTERNAL_EXPANDED.

Referenced by plpgsql_exec_function().

775 {
776  HeapTuple rettup;
777  TupleDesc retdesc;
778  TupleConversionMap *tupmap;
779 
780  /* We assume exec_stmt_return verified that result is composite */
781  Assert(type_is_rowtype(estate->rettype));
782 
783  /* We can special-case expanded records for speed */
785  {
787 
788  Assert(erh->er_magic == ER_MAGIC);
789 
790  /* Extract record's TupleDesc */
791  retdesc = expanded_record_get_tupdesc(erh);
792 
793  /* check rowtype compatibility */
794  tupmap = convert_tuples_by_position(retdesc,
795  tupdesc,
796  gettext_noop("returned record type does not match expected record type"));
797 
798  /* it might need conversion */
799  if (tupmap)
800  {
801  rettup = expanded_record_get_tuple(erh);
802  Assert(rettup);
803  rettup = execute_attr_map_tuple(rettup, tupmap);
804 
805  /*
806  * Copy tuple to upper executor memory, as a tuple Datum. Make
807  * sure it is labeled with the caller-supplied tuple type.
808  */
809  estate->retval = PointerGetDatum(SPI_returntuple(rettup, tupdesc));
810  /* no need to free map, we're about to return anyway */
811  }
812  else if (!(tupdesc->tdtypeid == erh->er_decltypeid ||
813  (tupdesc->tdtypeid == RECORDOID &&
814  !ExpandedRecordIsDomain(erh))))
815  {
816  /*
817  * The expanded record has the right physical tupdesc, but the
818  * wrong type ID. (Typically, the expanded record is RECORDOID
819  * but the function is declared to return a named composite type.
820  * As in exec_move_row_from_datum, we don't allow returning a
821  * composite-domain record from a function declared to return
822  * RECORD.) So we must flatten the record to a tuple datum and
823  * overwrite its type fields with the right thing. spi.c doesn't
824  * provide any easy way to deal with this case, so we end up
825  * duplicating the guts of datumCopy() :-(
826  */
827  Size resultsize;
828  HeapTupleHeader tuphdr;
829 
830  resultsize = EOH_get_flat_size(&erh->hdr);
831  tuphdr = (HeapTupleHeader) SPI_palloc(resultsize);
832  EOH_flatten_into(&erh->hdr, (void *) tuphdr, resultsize);
833  HeapTupleHeaderSetTypeId(tuphdr, tupdesc->tdtypeid);
834  HeapTupleHeaderSetTypMod(tuphdr, tupdesc->tdtypmod);
835  estate->retval = PointerGetDatum(tuphdr);
836  }
837  else
838  {
839  /*
840  * We need only copy result into upper executor memory context.
841  * However, if we have a R/W expanded datum, we can just transfer
842  * its ownership out to the upper executor context.
843  */
844  estate->retval = SPI_datumTransfer(estate->retval,
845  false,
846  -1);
847  }
848  }
849  else
850  {
851  /* Convert composite datum to a HeapTuple and TupleDesc */
852  HeapTupleData tmptup;
853 
854  retdesc = deconstruct_composite_datum(estate->retval, &tmptup);
855  rettup = &tmptup;
856 
857  /* check rowtype compatibility */
858  tupmap = convert_tuples_by_position(retdesc,
859  tupdesc,
860  gettext_noop("returned record type does not match expected record type"));
861 
862  /* it might need conversion */
863  if (tupmap)
864  rettup = execute_attr_map_tuple(rettup, tupmap);
865 
866  /*
867  * Copy tuple to upper executor memory, as a tuple Datum. Make sure
868  * it is labeled with the caller-supplied tuple type.
869  */
870  estate->retval = PointerGetDatum(SPI_returntuple(rettup, tupdesc));
871 
872  /* no need to free map, we're about to return anyway */
873 
874  ReleaseTupleDesc(retdesc);
875  }
876 }
HeapTuple expanded_record_get_tuple(ExpandedRecordHeader *erh)
#define HeapTupleHeaderSetTypeId(tup, typeid)
Definition: htup_details.h:463
HeapTupleHeader SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc)
Definition: spi.c:850
#define VARATT_IS_EXTERNAL_EXPANDED(PTR)
Definition: postgres.h:322
TupleConversionMap * convert_tuples_by_position(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:65
#define PointerGetDatum(X)
Definition: postgres.h:556
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define gettext_noop(x)
Definition: c.h:1148
static TupleDesc deconstruct_composite_datum(Datum value, HeapTupleData *tmptup)
Definition: pl_exec.c:7350
ExpandedObjectHeader hdr
Datum SPI_datumTransfer(Datum value, bool typByVal, int typLen)
Definition: spi.c:1137
int32 tdtypmod
Definition: tupdesc.h:83
Size EOH_get_flat_size(ExpandedObjectHeader *eohptr)
Definition: expandeddatum.c:75
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2433
HeapTuple execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map)
Definition: tupconvert.c:387
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
void * SPI_palloc(Size size)
Definition: spi.c:1114
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29
#define ER_MAGIC
#define HeapTupleHeaderSetTypMod(tup, typmod)
Definition: htup_details.h:473
void EOH_flatten_into(ExpandedObjectHeader *eohptr, void *result, Size allocated_size)
Definition: expandeddatum.c:81
#define Assert(condition)
Definition: c.h:739
size_t Size
Definition: c.h:467
#define DatumGetPointer(X)
Definition: postgres.h:549
Oid tdtypeid
Definition: tupdesc.h:82
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:122
#define ExpandedRecordIsDomain(erh)

◆ compatible_tupdescs()

static bool compatible_tupdescs ( TupleDesc  src_tupdesc,
TupleDesc  dst_tupdesc 
)
static

Definition at line 7251 of file pl_exec.c.

References i, TupleDescData::natts, and TupleDescAttr.

Referenced by exec_for_query(), and exec_move_row().

7252 {
7253  int i;
7254 
7255  /* Possibly we could allow src_tupdesc to have extra columns? */
7256  if (dst_tupdesc->natts != src_tupdesc->natts)
7257  return false;
7258 
7259  for (i = 0; i < dst_tupdesc->natts; i++)
7260  {
7261  Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
7262  Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
7263 
7264  if (dattr->attisdropped != sattr->attisdropped)
7265  return false;
7266  if (!dattr->attisdropped)
7267  {
7268  /* Normal columns must match by type and typmod */
7269  if (dattr->atttypid != sattr->atttypid ||
7270  (dattr->atttypmod >= 0 &&
7271  dattr->atttypmod != sattr->atttypmod))
7272  return false;
7273  }
7274  else
7275  {
7276  /* Dropped columns are OK as long as length/alignment match */
7277  if (dattr->attlen != sattr->attlen ||
7278  dattr->attalign != sattr->attalign)
7279  return false;
7280  }
7281  }
7282  return true;
7283 }
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
int i

◆ contains_target_param()

static bool contains_target_param ( Node node,
int *  target_dno 
)
static

Definition at line 8155 of file pl_exec.c.

References expression_tree_walker(), IsA, PARAM_EXTERN, Param::paramid, and Param::paramkind.

Referenced by exec_check_rw_parameter().

8156 {
8157  if (node == NULL)
8158  return false;
8159  if (IsA(node, Param))
8160  {
8161  Param *param = (Param *) node;
8162 
8163  if (param->paramkind == PARAM_EXTERN &&
8164  param->paramid == *target_dno + 1)
8165  return true;
8166  return false;
8167  }
8169  (void *) target_dno);
8170 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
ParamKind paramkind
Definition: primnodes.h:248
static bool contains_target_param(Node *node, int *target_dno)
Definition: pl_exec.c:8155
int paramid
Definition: primnodes.h:249
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1839

◆ convert_value_to_string()

static char * convert_value_to_string ( PLpgSQL_execstate estate,
Datum  value,
Oid  valtype 
)
static

Definition at line 7649 of file pl_exec.c.

References get_eval_mcontext, getTypeOutputInfo(), MemoryContextSwitchTo(), and OidOutputFunctionCall().

Referenced by exec_dynquery_with_params(), exec_stmt_assert(), exec_stmt_dynexecute(), exec_stmt_raise(), format_expr_params(), and format_preparedparamsdata().

7650 {
7651  char *result;
7652  MemoryContext oldcontext;
7653  Oid typoutput;
7654  bool typIsVarlena;
7655 
7656  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7657  getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
7658  result = OidOutputFunctionCall(typoutput, value);
7659  MemoryContextSwitchTo(oldcontext);
7660 
7661  return result;
7662 }
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2674
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static struct @145 value
unsigned int Oid
Definition: postgres_ext.h:31
#define get_eval_mcontext(estate)
Definition: pl_exec.c:120
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1655

◆ copy_plpgsql_datums()

static void copy_plpgsql_datums ( PLpgSQL_execstate estate,
PLpgSQL_function func 
)
static

Definition at line 1257 of file pl_exec.c.

References Assert, PLpgSQL_function::copiable_size, PLpgSQL_function::datums, PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, elog, ERROR, i, MAXALIGN, PLpgSQL_execstate::ndatums, palloc(), PLPGSQL_DTYPE_ARRAYELEM, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ROW, and PLPGSQL_DTYPE_VAR.

Referenced by plpgsql_exec_event_trigger(), plpgsql_exec_function(), and plpgsql_exec_trigger().

1259 {
1260  int ndatums = estate->ndatums;
1261  PLpgSQL_datum **indatums;
1262  PLpgSQL_datum **outdatums;
1263  char *workspace;
1264  char *ws_next;
1265  int i;
1266 
1267  /* Allocate local datum-pointer array */
1268  estate->datums = (PLpgSQL_datum **)
1269  palloc(sizeof(PLpgSQL_datum *) * ndatums);
1270 
1271  /*
1272  * To reduce palloc overhead, we make a single palloc request for all the
1273  * space needed for locally-instantiated datums.
1274  */
1275  workspace = palloc(func->copiable_size);
1276  ws_next = workspace;
1277 
1278  /* Fill datum-pointer array, copying datums into workspace as needed */
1279  indatums = func->datums;
1280  outdatums = estate->datums;
1281  for (i = 0; i < ndatums; i++)
1282  {
1283  PLpgSQL_datum *indatum = indatums[i];
1284  PLpgSQL_datum *outdatum;
1285 
1286  /* This must agree with plpgsql_finish_datums on what is copiable */
1287  switch (indatum->dtype)
1288  {
1289  case PLPGSQL_DTYPE_VAR:
1290  case PLPGSQL_DTYPE_PROMISE:
1291  outdatum = (PLpgSQL_datum *) ws_next;
1292  memcpy(outdatum, indatum, sizeof(PLpgSQL_var));
1293  ws_next += MAXALIGN(sizeof(PLpgSQL_var));
1294  break;
1295 
1296  case PLPGSQL_DTYPE_REC:
1297  outdatum = (PLpgSQL_datum *) ws_next;
1298  memcpy(outdatum, indatum, sizeof(PLpgSQL_rec));
1299  ws_next += MAXALIGN(sizeof(PLpgSQL_rec));
1300  break;
1301 
1302  case PLPGSQL_DTYPE_ROW:
1305 
1306  /*
1307  * These datum records are read-only at runtime, so no need to
1308  * copy them (well, RECFIELD and ARRAYELEM contain cached
1309  * data, but we'd just as soon centralize the caching anyway).
1310  */
1311  outdatum = indatum;
1312  break;
1313 
1314  default:
1315  elog(ERROR, "unrecognized dtype: %d", indatum->dtype);
1316  outdatum = NULL; /* keep compiler quiet */
1317  break;
1318  }
1319 
1320  outdatums[i] = outdatum;
1321  }
1322 
1323  Assert(ws_next == workspace + func->copiable_size);
1324 }
PLpgSQL_datum ** datums
Definition: plpgsql.h:1021
PLpgSQL_datum_type dtype
Definition: plpgsql.h:258
PLpgSQL_datum ** datums
Definition: plpgsql.h:1072
#define ERROR
Definition: elog.h:43
#define Assert(condition)
Definition: c.h:739
#define MAXALIGN(LEN)
Definition: c.h:692
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:228
int i
Size copiable_size
Definition: plpgsql.h:1022

◆ deconstruct_composite_datum()

static TupleDesc deconstruct_composite_datum ( Datum  value,
HeapTupleData tmptup 
)
static

Definition at line 7350 of file pl_exec.c.

References DatumGetHeapTupleHeader, HeapTupleHeaderGetDatumLength, HeapTupleHeaderGetTypeId, HeapTupleHeaderGetTypMod, InvalidOid, ItemPointerSetInvalid, lookup_rowtype_tupdesc(), HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, and HeapTupleData::t_tableOid.

Referenced by coerce_function_result_tuple(), exec_stmt_return_next(), and plpgsql_exec_trigger().

7351 {
7352  HeapTupleHeader td;
7353  Oid tupType;
7354  int32 tupTypmod;
7355 
7356  /* Get tuple body (note this could involve detoasting) */
7358 
7359  /* Build a temporary HeapTuple control structure */
7360  tmptup->t_len = HeapTupleHeaderGetDatumLength(td);
7361  ItemPointerSetInvalid(&(tmptup->t_self));
7362  tmptup->t_tableOid = InvalidOid;
7363  tmptup->t_data = td;
7364 
7365  /* Extract rowtype info and find a tupdesc */
7366  tupType = HeapTupleHeaderGetTypeId(td);
7367  tupTypmod = HeapTupleHeaderGetTypMod(td);
7368  return lookup_rowtype_tupdesc(tupType, tupTypmod);
7369 }
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1652
static struct @145 value
unsigned int Oid
Definition: postgres_ext.h:31
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:289
signed int int32
Definition: c.h:347
HeapTupleHeader t_data
Definition: htup.h:68
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:468
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
Oid t_tableOid
Definition: htup.h:66
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:458
#define InvalidOid
Definition: postgres_ext.h:36
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:452

◆ exception_matches_conditions()

static bool exception_matches_conditions ( ErrorData edata,
PLpgSQL_condition cond 
)
static

Definition at line 1543 of file pl_exec.c.

References ERRCODE_IS_CATEGORY, ERRCODE_TO_CATEGORY, PLpgSQL_condition::next, ErrorData::sqlerrcode, and PLpgSQL_condition::sqlerrstate.

Referenced by exec_stmt_block().

1544 {
1545  for (; cond != NULL; cond = cond->next)
1546  {
1547  int sqlerrstate = cond->sqlerrstate;
1548 
1549  /*
1550  * OTHERS matches everything *except* query-canceled and
1551  * assert-failure. If you're foolish enough, you can match those
1552  * explicitly.
1553  */
1554  if (sqlerrstate == 0)
1555  {
1556  if (edata->sqlerrcode != ERRCODE_QUERY_CANCELED &&
1557  edata->sqlerrcode != ERRCODE_ASSERT_FAILURE)
1558  return true;
1559  }
1560  /* Exact match? */
1561  else if (edata->sqlerrcode == sqlerrstate)
1562  return true;
1563  /* Category match? */
1564  else if (ERRCODE_IS_CATEGORY(sqlerrstate) &&
1565  ERRCODE_TO_CATEGORY(edata->sqlerrcode) == sqlerrstate)
1566  return true;
1567  }
1568  return false;
1569 }
#define ERRCODE_IS_CATEGORY(ec)
Definition: elog.h:68
int sqlerrcode
Definition: elog.h:391
struct PLpgSQL_condition * next
Definition: plpgsql.h:478
#define ERRCODE_TO_CATEGORY(ec)
Definition: elog.h:67

◆ exec_assign_c_string()

static void exec_assign_c_string ( PLpgSQL_execstate estate,
PLpgSQL_datum target,
const char *  str 
)
static

Definition at line 4926 of file pl_exec.c.

References cstring_to_text(), exec_assign_value(), get_eval_mcontext, MemoryContextSwitchTo(), PointerGetDatum, and value.

Referenced by exec_stmt_getdiag().

4928 {
4929  text *value;
4930  MemoryContext oldcontext;
4931 
4932  /* Use eval_mcontext for short-lived text value */
4933  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
4934  if (str != NULL)
4935  value = cstring_to_text(str);
4936  else
4937  value = cstring_to_text("");
4938  MemoryContextSwitchTo(oldcontext);
4939 
4940  exec_assign_value(estate, target, PointerGetDatum(value), false,
4941  TEXTOID, -1);
4942 }
#define PointerGetDatum(X)
Definition: postgres.h:556
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static struct @145 value
#define get_eval_mcontext(estate)
Definition: pl_exec.c:120
text * cstring_to_text(const char *s)
Definition: varlena.c:171
Definition: c.h:556
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:4954

◆ exec_assign_expr()

static void exec_assign_expr ( PLpgSQL_execstate estate,
PLpgSQL_datum target,
PLpgSQL_expr expr 
)
static

Definition at line 4889 of file pl_exec.c.

References PLpgSQL_datum::dno, PLpgSQL_datum::dtype, exec_assign_value(), exec_check_rw_parameter(), exec_eval_cleanup(), exec_eval_expr(), exec_prepare_plan(), PLpgSQL_expr::plan, PLPGSQL_DTYPE_VAR, and value.

Referenced by exec_stmt_assign(), exec_stmt_block(), and plpgsql_estate_setup().

4891 {
4892  Datum value;
4893  bool isnull;
4894  Oid valtype;
4895  int32 valtypmod;
4896 
4897  /*
4898  * If first time through, create a plan for this expression, and then see
4899  * if we can pass the target variable as a read-write parameter to the
4900  * expression. (This is a bit messy, but it seems cleaner than modifying
4901  * the API of exec_eval_expr for the purpose.)
4902  */
4903  if (expr->plan == NULL)
4904  {
4905  exec_prepare_plan(estate, expr, 0, true);
4906  if (target->dtype == PLPGSQL_DTYPE_VAR)
4907  exec_check_rw_parameter(expr, target->dno);
4908  }
4909 
4910  value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod);
4911  exec_assign_value(estate, target, value, isnull, valtype, valtypmod);
4912  exec_eval_cleanup(estate);
4913 }
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions, bool keepplan)
Definition: pl_exec.c:4038
static void exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno)
Definition: pl_exec.c:8078
static struct @145 value
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4017
unsigned int Oid
Definition: postgres_ext.h:31
PLpgSQL_datum_type dtype
Definition: plpgsql.h:258
SPIPlanPtr plan
Definition: plpgsql.h:222
signed int int32
Definition: c.h:347
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5750
uintptr_t Datum
Definition: postgres.h:367
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:4954

◆ exec_assign_value()

static void exec_assign_value ( PLpgSQL_execstate estate,
PLpgSQL_datum target,
Datum  value,
bool  isNull,
Oid  valtype,
int32  valtypmod 
)
static

Definition at line 4954 of file pl_exec.c.

References array_set_element(), PLpgSQL_arrayelem::arrayparentno, PLpgSQL_arrayelem::arraytyplen, PLpgSQL_arrayelem::arraytypmod, PLpgSQL_arrayelem::arraytypoid, Assert, assign_simple_var(), PLpgSQL_execstate::atomic, PLpgSQL_type::atttypmod, construct_empty_array(), PLpgSQL_var::datatype, PLpgSQL_execstate::datum_context, DatumGetPointer, PLpgSQL_execstate::datums, datumTransfer(), PLpgSQL_datum::dtype, PLpgSQL_arrayelem::elemtypalign, PLpgSQL_arrayelem::elemtypbyval, PLpgSQL_arrayelem::elemtyplen, PLpgSQL_arrayelem::elemtypoid, elog, ExpandedRecordHeader::er_tupdesc_id, ereport, PLpgSQL_rec::erh, errcode(), errmsg(), ERROR, PLpgSQL_execstate::eval_tuptable, exec_cast_value(), exec_eval_datum(), exec_eval_integer(), exec_move_row(), exec_move_row_from_datum(), expand_array(), expanded_record_lookup_field(), expanded_record_set_field, PLpgSQL_recfield::fieldname, PLpgSQL_recfield::finfo, ExpandedRecordFieldInfo::fnumber, ExpandedRecordFieldInfo::ftypeid, ExpandedRecordFieldInfo::ftypmod, get_element_type(), get_eval_mcontext, get_typlen(), get_typlenbyvalalign(), getBaseTypeAndTypmod(), i, instantiate_empty_record_variable(), PLpgSQL_var::isnull, MAXDIM, MemoryContextSwitchTo(), PLpgSQL_var::notnull, PLpgSQL_rec::notnull, OidIsValid, PLpgSQL_arrayelem::parenttypmod, PLpgSQL_arrayelem::parenttypoid, PLPGSQL_DTYPE_ARRAYELEM, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, PLPGSQL_PROMISE_NONE, PointerGetDatum, PLpgSQL_var::promise, PLpgSQL_recfield::recparentno, PLpgSQL_recfield::rectupledescid, PLpgSQL_var::refname, PLpgSQL_rec::refname, SPI_freetuptable(), PLpgSQL_arrayelem::subscript, PLpgSQL_type::typbyval, type_is_rowtype(), PLpgSQL_type::typisarray, PLpgSQL_type::typlen, PLpgSQL_type::typoid, unlikely, PLpgSQL_var::value, and VARATT_IS_EXTERNAL_EXPANDED_RW.

Referenced by exec_assign_c_string(), exec_assign_expr(), exec_move_row_from_fields(), exec_stmt_block(), exec_stmt_case(), exec_stmt_foreach_a(), and exec_stmt_getdiag().

4958 {
4959  switch (target->dtype)
4960  {
4961  case PLPGSQL_DTYPE_VAR:
4962  case PLPGSQL_DTYPE_PROMISE:
4963  {
4964  /*
4965  * Target is a variable
4966  */
4967  PLpgSQL_var *var = (PLpgSQL_var *) target;
4968  Datum newvalue;
4969 
4970  newvalue = exec_cast_value(estate,
4971  value,
4972  &isNull,
4973  valtype,
4974  valtypmod,
4975  var->datatype->typoid,
4976  var->datatype->atttypmod);
4977 
4978  if (isNull && var->notnull)
4979  ereport(ERROR,
4980  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4981  errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
4982  var->refname)));
4983 
4984  /*
4985  * If type is by-reference, copy the new value (which is
4986  * probably in the eval_mcontext) into the procedure's main
4987  * memory context. But if it's a read/write reference to an
4988  * expanded object, no physical copy needs to happen; at most
4989  * we need to reparent the object's memory context.
4990  *
4991  * If it's an array, we force the value to be stored in R/W
4992  * expanded form. This wins if the function later does, say,
4993  * a lot of array subscripting operations on the variable, and
4994  * otherwise might lose. We might need to use a different
4995  * heuristic, but it's too soon to tell. Also, are there
4996  * cases where it'd be useful to force non-array values into
4997  * expanded form?
4998  */
4999  if (!var->datatype->typbyval && !isNull)
5000  {
5001  if (var->datatype->typisarray &&
5003  {
5004  /* array and not already R/W, so apply expand_array */
5005  newvalue = expand_array(newvalue,
5006  estate->datum_context,
5007  NULL);
5008  }
5009  else
5010  {
5011  /* else transfer value if R/W, else just datumCopy */
5012  newvalue = datumTransfer(newvalue,
5013  false,
5014  var->datatype->typlen);
5015  }
5016  }
5017 
5018  /*
5019  * Now free the old value, if any, and assign the new one. But
5020  * skip the assignment if old and new values are the same.
5021  * Note that for expanded objects, this test is necessary and
5022  * cannot reliably be made any earlier; we have to be looking
5023  * at the object's standard R/W pointer to be sure pointer
5024  * equality is meaningful.
5025  *
5026  * Also, if it's a promise variable, we should disarm the
5027  * promise in any case --- otherwise, assigning null to an
5028  * armed promise variable would fail to disarm the promise.
5029  */
5030  if (var->value != newvalue || var->isnull || isNull)
5031  assign_simple_var(estate, var, newvalue, isNull,
5032  (!var->datatype->typbyval && !isNull));
5033  else
5035  break;
5036  }
5037 
5038  case PLPGSQL_DTYPE_ROW:
5039  {
5040  /*
5041  * Target is a row variable
5042  */
5043  PLpgSQL_row *row = (PLpgSQL_row *) target;
5044 
5045  if (isNull)
5046  {
5047  /* If source is null, just assign nulls to the row */
5048  exec_move_row(estate, (PLpgSQL_variable *) row,
5049  NULL, NULL);
5050  }
5051  else
5052  {
5053  /* Source must be of RECORD or composite type */
5054  if (!type_is_rowtype(valtype))
5055  ereport(ERROR,
5056  (errcode(ERRCODE_DATATYPE_MISMATCH),
5057  errmsg("cannot assign non-composite value to a row variable")));
5059  value);
5060  }
5061  break;
5062  }
5063 
5064  case PLPGSQL_DTYPE_REC:
5065  {
5066  /*
5067  * Target is a record variable
5068  */
5069  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
5070 
5071  if (isNull)
5072  {
5073  if (rec->notnull)
5074  ereport(ERROR,
5075  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5076  errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
5077  rec->refname)));
5078 
5079  /* Set variable to a simple NULL */
5080  exec_move_row(estate, (PLpgSQL_variable *) rec,
5081  NULL, NULL);
5082  }
5083  else
5084  {
5085  /* Source must be of RECORD or composite type */
5086  if (!type_is_rowtype(valtype))
5087  ereport(ERROR,
5088  (errcode(ERRCODE_DATATYPE_MISMATCH),
5089  errmsg("cannot assign non-composite value to a record variable")));
5091  value);
5092  }
5093  break;
5094  }
5095 
5097  {
5098  /*
5099  * Target is a field of a record
5100  */
5101  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) target;
5102  PLpgSQL_rec *rec;
5103  ExpandedRecordHeader *erh;
5104 
5105  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5106  erh = rec->erh;
5107 
5108  /*
5109  * If record variable is NULL, instantiate it if it has a
5110  * named composite type, else complain. (This won't change
5111  * the logical state of the record, but if we successfully
5112  * assign below, the unassigned fields will all become NULLs.)
5113  */
5114  if (erh == NULL)
5115  {
5116  instantiate_empty_record_variable(estate, rec);
5117  erh = rec->erh;
5118  }
5119 
5120  /*
5121  * Look up the field's properties if we have not already, or
5122  * if the tuple descriptor ID changed since last time.
5123  */
5124  if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
5125  {
5127  recfield->fieldname,
5128  &recfield->finfo))
5129  ereport(ERROR,
5130  (errcode(ERRCODE_UNDEFINED_COLUMN),
5131  errmsg("record \"%s\" has no field \"%s\"",
5132  rec->refname, recfield->fieldname)));
5133  recfield->rectupledescid = erh->er_tupdesc_id;
5134  }
5135 
5136  /* We don't support assignments to system columns. */
5137  if (recfield->finfo.fnumber <= 0)
5138  ereport(ERROR,
5139  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5140  errmsg("cannot assign to system column \"%s\"",
5141  recfield->fieldname)));
5142 
5143  /* Cast the new value to the right type, if needed. */
5144  value = exec_cast_value(estate,
5145  value,
5146  &isNull,
5147  valtype,
5148  valtypmod,
5149  recfield->finfo.ftypeid,
5150  recfield->finfo.ftypmod);
5151 
5152  /* And assign it. */
5153  expanded_record_set_field(erh, recfield->finfo.fnumber,
5154  value, isNull, !estate->atomic);
5155  break;
5156  }
5157 
5159  {
5160  /*
5161  * Target is an element of an array
5162  */
5163  PLpgSQL_arrayelem *arrayelem;
5164  int nsubscripts;
5165  int i;
5166  PLpgSQL_expr *subscripts[MAXDIM];
5167  int subscriptvals[MAXDIM];
5168  Datum oldarraydatum,
5169  newarraydatum,
5170  coerced_value;
5171  bool oldarrayisnull;
5172  Oid parenttypoid;
5173  int32 parenttypmod;
5174  SPITupleTable *save_eval_tuptable;
5175  MemoryContext oldcontext;
5176 
5177  /*
5178  * We need to do subscript evaluation, which might require
5179  * evaluating general expressions; and the caller might have
5180  * done that too in order to prepare the input Datum. We have
5181  * to save and restore the caller's SPI_execute result, if
5182  * any.
5183  */
5184  save_eval_tuptable = estate->eval_tuptable;
5185  estate->eval_tuptable = NULL;
5186 
5187  /*
5188  * To handle constructs like x[1][2] := something, we have to
5189  * be prepared to deal with a chain of arrayelem datums. Chase
5190  * back to find the base array datum, and save the subscript
5191  * expressions as we go. (We are scanning right to left here,
5192  * but want to evaluate the subscripts left-to-right to
5193  * minimize surprises.) Note that arrayelem is left pointing
5194  * to the leftmost arrayelem datum, where we will cache the
5195  * array element type data.
5196  */
5197  nsubscripts = 0;
5198  do
5199  {
5200  arrayelem = (PLpgSQL_arrayelem *) target;
5201  if (nsubscripts >= MAXDIM)
5202  ereport(ERROR,
5203  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5204  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
5205  nsubscripts + 1, MAXDIM)));
5206  subscripts[nsubscripts++] = arrayelem->subscript;
5207  target = estate->datums[arrayelem->arrayparentno];
5208  } while (target->dtype == PLPGSQL_DTYPE_ARRAYELEM);
5209 
5210  /* Fetch current value of array datum */
5211  exec_eval_datum(estate, target,
5212  &parenttypoid, &parenttypmod,
5213  &oldarraydatum, &oldarrayisnull);
5214 
5215  /* Update cached type data if necessary */
5216  if (arrayelem->parenttypoid != parenttypoid ||
5217  arrayelem->parenttypmod != parenttypmod)
5218  {
5219  Oid arraytypoid;
5220  int32 arraytypmod = parenttypmod;
5221  int16 arraytyplen;
5222  Oid elemtypoid;
5223  int16 elemtyplen;
5224  bool elemtypbyval;
5225  char elemtypalign;
5226 
5227  /* If target is domain over array, reduce to base type */
5228  arraytypoid = getBaseTypeAndTypmod(parenttypoid,
5229  &arraytypmod);
5230 
5231  /* ... and identify the element type */
5232  elemtypoid = get_element_type(arraytypoid);
5233  if (!OidIsValid(elemtypoid))
5234  ereport(ERROR,
5235  (errcode(ERRCODE_DATATYPE_MISMATCH),
5236  errmsg("subscripted object is not an array")));
5237 
5238  /* Collect needed data about the types */
5239  arraytyplen = get_typlen(arraytypoid);
5240 
5241  get_typlenbyvalalign(elemtypoid,
5242  &elemtyplen,
5243  &elemtypbyval,
5244  &elemtypalign);
5245 
5246  /* Now safe to update the cached data */
5247  arrayelem->parenttypoid = parenttypoid;
5248  arrayelem->parenttypmod = parenttypmod;
5249  arrayelem->arraytypoid = arraytypoid;
5250  arrayelem->arraytypmod = arraytypmod;
5251  arrayelem->arraytyplen = arraytyplen;
5252  arrayelem->elemtypoid = elemtypoid;
5253  arrayelem->elemtyplen = elemtyplen;
5254  arrayelem->elemtypbyval = elemtypbyval;
5255  arrayelem->elemtypalign = elemtypalign;
5256  }
5257 
5258  /*
5259  * Evaluate the subscripts, switch into left-to-right order.
5260  * Like the expression built by ExecInitSubscriptingRef(),
5261  * complain if any subscript is null.
5262  */
5263  for (i = 0; i < nsubscripts; i++)
5264  {
5265  bool subisnull;
5266 
5267  subscriptvals[i] =
5268  exec_eval_integer(estate,
5269  subscripts[nsubscripts - 1 - i],
5270  &subisnull);
5271  if (subisnull)
5272  ereport(ERROR,
5273  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5274  errmsg("array subscript in assignment must not be null")));
5275 
5276  /*
5277  * Clean up in case the subscript expression wasn't
5278  * simple. We can't do exec_eval_cleanup, but we can do
5279  * this much (which is safe because the integer subscript
5280  * value is surely pass-by-value), and we must do it in
5281  * case the next subscript expression isn't simple either.
5282  */
5283  if (estate->eval_tuptable != NULL)
5285  estate->eval_tuptable = NULL;
5286  }
5287 
5288  /* Now we can restore caller's SPI_execute result if any. */
5289  Assert(estate->eval_tuptable == NULL);
5290  estate->eval_tuptable = save_eval_tuptable;
5291 
5292  /* Coerce source value to match array element type. */
5293  coerced_value = exec_cast_value(estate,
5294  value,
5295  &isNull,
5296  valtype,
5297  valtypmod,
5298  arrayelem->elemtypoid,
5299  arrayelem->arraytypmod);
5300 
5301  /*
5302  * If the original array is null, cons up an empty array so
5303  * that the assignment can proceed; we'll end with a
5304  * one-element array containing just the assigned-to
5305  * subscript. This only works for varlena arrays, though; for
5306  * fixed-length array types we skip the assignment. We can't
5307  * support assignment of a null entry into a fixed-length
5308  * array, either, so that's a no-op too. This is all ugly but
5309  * corresponds to the current behavior of execExpr*.c.
5310  */
5311  if (arrayelem->arraytyplen > 0 && /* fixed-length array? */
5312  (oldarrayisnull || isNull))
5313  return;
5314 
5315  /* empty array, if any, and newarraydatum are short-lived */
5316  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5317 
5318  if (oldarrayisnull)
5319  oldarraydatum = PointerGetDatum(construct_empty_array(arrayelem->elemtypoid));
5320 
5321  /*
5322  * Build the modified array value.
5323  */
5324  newarraydatum = array_set_element(oldarraydatum,
5325  nsubscripts,
5326  subscriptvals,
5327  coerced_value,
5328  isNull,
5329  arrayelem->arraytyplen,
5330  arrayelem->elemtyplen,
5331  arrayelem->elemtypbyval,
5332  arrayelem->elemtypalign);
5333 
5334  MemoryContextSwitchTo(oldcontext);
5335 
5336  /*
5337  * Assign the new array to the base variable. It's never NULL
5338  * at this point. Note that if the target is a domain,
5339  * coercing the base array type back up to the domain will
5340  * happen within exec_assign_value.
5341  */
5342  exec_assign_value(estate, target,
5343  newarraydatum,
5344  false,
5345  arrayelem->arraytypoid,
5346  arrayelem->arraytypmod);
5347  break;
5348  }
5349 
5350  default:
5351  elog(ERROR, "unrecognized dtype: %d", target->dtype);
5352  }
5353 }
PLpgSQL_promise_type promise
Definition: plpgsql.h:323
signed short int16
Definition: c.h:346
int16 elemtyplen
Definition: plpgsql.h:434
#define expanded_record_set_field(erh, fnumber, newValue, isnull, expand_external)
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2316
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1096
char * refname
Definition: plpgsql.h:294
static void exec_eval_datum(PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeid, int32 *typetypmod, Datum *value, bool *isnull)
Definition: pl_exec.c:5373
bool expanded_record_lookup_field(ExpandedRecordHeader *erh, const char *fieldname, ExpandedRecordFieldInfo *finfo)
#define MAXDIM
Definition: c.h:536
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2526
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2049
#define PointerGetDatum(X)
Definition: postgres.h:556
PLpgSQL_type * datatype
Definition: plpgsql.h:301
Datum expand_array(Datum arraydatum, MemoryContext parentcontext, ArrayMetaState *metacache)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static struct @145 value
static void instantiate_empty_record_variable(PLpgSQL_execstate *estate, PLpgSQL_rec *rec)
Definition: pl_exec.c:7614
ExpandedRecordHeader * erh
Definition: plpgsql.h:395
int errcode(int sqlerrcode)
Definition: elog.c:608
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8325
Datum array_set_element(Datum arraydatum, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:2199
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3410
unsigned int Oid
Definition: postgres_ext.h:31
static void exec_move_row_from_datum(PLpgSQL_execstate *estate, PLpgSQL_variable *target, Datum value)
Definition: pl_exec.c:7381
PLpgSQL_datum_type dtype
Definition: plpgsql.h:258
#define OidIsValid(objectId)
Definition: c.h:645
char * refname
Definition: plpgsql.h:374
signed int int32
Definition: c.h:347
PLpgSQL_datum ** datums
Definition: plpgsql.h:1072
int32 arraytypmod
Definition: plpgsql.h:431
bool notnull
Definition: plpgsql.h:297
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7678
#define ERROR
Definition: elog.h:43
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2433
#define ereport(elevel, rest)
Definition: elog.h:141
uint64 rectupledescid
Definition: plpgsql.h:410
bool typbyval
Definition: plpgsql.h:205
#define get_eval_mcontext(estate)
Definition: pl_exec.c:120
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1162
bool typisarray
Definition: plpgsql.h:208
uintptr_t Datum
Definition: postgres.h:367
static int exec_eval_integer(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
Definition: pl_exec.c:5704
ExpandedRecordFieldInfo finfo
Definition: plpgsql.h:411
int32 parenttypmod
Definition: plpgsql.h:429
Datum value
Definition: plpgsql.h:314
Datum datumTransfer(Datum value, bool typByVal, int typLen)
Definition: datum.c:192
#define Assert(condition)
Definition: c.h:739
int16 arraytyplen
Definition: plpgsql.h:432
#define DatumGetPointer(X)
Definition: postgres.h:549
MemoryContext datum_context
Definition: plpgsql.h:1074
int16 get_typlen(Oid typid)
Definition: lsyscache.c:1975
int errmsg(const char *fmt,...)
Definition: elog.c:822
int32 atttypmod
Definition: plpgsql.h:209
static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
Definition: pl_exec.c:6716
#define elog(elevel,...)
Definition: elog.h:228
int i
PLpgSQL_expr * subscript
Definition: plpgsql.h:424
#define VARATT_IS_EXTERNAL_EXPANDED_RW(PTR)
Definition: postgres.h:320
#define unlikely(x)
Definition: c.h:208
int16 typlen
Definition: plpgsql.h:204
bool notnull
Definition: plpgsql.h:377
char * fieldname
Definition: plpgsql.h:407
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:4954
bool isnull
Definition: plpgsql.h:315
Oid typoid
Definition: plpgsql.h:202

◆ exec_cast_value()

static Datum exec_cast_value ( PLpgSQL_execstate estate,
Datum  value,
bool isnull,
Oid  valtype,
int32  valtypmod,
Oid  reqtype,
int32  reqtypmod 
)
static

Definition at line 7678 of file pl_exec.c.

References ExprContext::caseValue_datum, ExprContext::caseValue_isNull, plpgsql_CastHashEntry::cast_exprstate, plpgsql_CastHashEntry::cast_in_use, PLpgSQL_execstate::eval_econtext, ExecEvalExpr(), get_cast_hashentry(), get_eval_mcontext, MemoryContextSwitchTo(), and value.

Referenced by exec_assign_value(), exec_eval_boolean(), exec_eval_integer(), exec_move_row_from_fields(), exec_stmt_fori(), exec_stmt_return_next(), and plpgsql_exec_function().

7682 {
7683  /*
7684  * If the type of the given value isn't what's requested, convert it.
7685  */
7686  if (valtype != reqtype ||
7687  (valtypmod != reqtypmod && reqtypmod != -1))
7688  {
7689  plpgsql_CastHashEntry *cast_entry;
7690 
7691  cast_entry = get_cast_hashentry(estate,
7692  valtype, valtypmod,
7693  reqtype, reqtypmod);
7694  if (cast_entry)
7695  {
7696  ExprContext *econtext = estate->eval_econtext;
7697  MemoryContext oldcontext;
7698 
7699  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7700 
7701  econtext->caseValue_datum = value;
7702  econtext->caseValue_isNull = *isnull;
7703 
7704  cast_entry->cast_in_use = true;
7705 
7706  value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
7707  isnull);
7708 
7709  cast_entry->cast_in_use = false;
7710 
7711  MemoryContextSwitchTo(oldcontext);
7712  }
7713  }
7714 
7715  return value;
7716 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static struct @145 value
static plpgsql_CastHashEntry * get_cast_hashentry(PLpgSQL_execstate *estate, Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod)
Definition: pl_exec.c:7729
Datum caseValue_datum
Definition: execnodes.h:248
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:285
#define get_eval_mcontext(estate)
Definition: pl_exec.c:120
ExprContext * eval_econtext
Definition: plpgsql.h:1098
bool caseValue_isNull
Definition: execnodes.h:250
ExprState * cast_exprstate
Definition: pl_exec.c:156

◆ exec_check_rw_parameter()

static void exec_check_rw_parameter ( PLpgSQL_expr expr,
int  target_dno 
)
static

Definition at line 8078 of file pl_exec.c.

References arg, FuncExpr::args, OpExpr::args, bms_is_member(), contains_target_param(), PLpgSQL_expr::expr_simple_expr, FuncExpr::funcid, IsA, lfirst, OpExpr::opfuncid, PLpgSQL_expr::paramnos, and PLpgSQL_expr::rwparam.

Referenced by exec_assign_expr(), and exec_eval_simple_expr().

8079 {
8080  Oid funcid;
8081  List *fargs;
8082  ListCell *lc;
8083 
8084  /* Assume unsafe */
8085  expr->rwparam = -1;
8086 
8087  /*
8088  * If the expression isn't simple, there's no point in trying to optimize
8089  * (because the exec_run_select code path will flatten any expanded result
8090  * anyway). Even without that, this seems like a good safety restriction.
8091  */
8092  if (expr->expr_simple_expr == NULL)
8093  return;
8094 
8095  /*
8096  * If target variable isn't referenced by expression, no need to look
8097  * further.
8098  */
8099  if (!bms_is_member(target_dno, expr->paramnos))
8100  return;
8101 
8102  /*
8103  * Top level of expression must be a simple FuncExpr or OpExpr.
8104  */
8105  if (IsA(expr->expr_simple_expr, FuncExpr))
8106  {
8107  FuncExpr *fexpr = (FuncExpr *) expr->expr_simple_expr;
8108 
8109  funcid = fexpr->funcid;
8110  fargs = fexpr->args;
8111  }
8112  else if (IsA(expr->expr_simple_expr, OpExpr))
8113  {
8114  OpExpr *opexpr = (OpExpr *) expr->expr_simple_expr;
8115 
8116  funcid = opexpr->opfuncid;
8117  fargs = opexpr->args;
8118  }
8119  else
8120  return;
8121 
8122  /*
8123  * The top-level function must be one that we trust to be "safe".
8124  * Currently we hard-wire the list, but it would be very desirable to
8125  * allow extensions to mark their functions as safe ...
8126  */
8127  if (!(funcid == F_ARRAY_APPEND ||
8128  funcid == F_ARRAY_PREPEND))
8129  return;
8130 
8131  /*
8132  * The target variable (in the form of a Param) must only appear as a
8133  * direct argument of the top-level function.
8134  */
8135  foreach(lc, fargs)
8136  {
8137  Node *arg = (Node *) lfirst(lc);
8138 
8139  /* A Param is OK, whether it's the target variable or not */
8140  if (arg && IsA(arg, Param))
8141  continue;
8142  /* Otherwise, argument expression must not reference target */
8143  if (contains_target_param(arg, &target_dno))
8144  return;
8145  }
8146 
8147  /* OK, we can pass target as a read-write parameter */
8148  expr->rwparam = target_dno;
8149 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
List * args
Definition: primnodes.h:463
Definition: nodes.h:525
unsigned int Oid
Definition: postgres_ext.h:31
Bitmapset * paramnos
Definition: plpgsql.h:223
Oid funcid
Definition: primnodes.h:455
static bool contains_target_param(Node *node, int *target_dno)
Definition: pl_exec.c:8155
Expr * expr_simple_expr
Definition: plpgsql.h:233
int rwparam
Definition: plpgsql.h:224
Oid opfuncid
Definition: primnodes.h:503
#define lfirst(lc)
Definition: pg_list.h:190
void * arg
List * args
Definition: primnodes.h:508
Definition: pg_list.h:50
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427

◆ exec_dynquery_with_params()

static Portal exec_dynquery_with_params ( PLpgSQL_execstate estate,
PLpgSQL_expr dynquery,
List params,
const char *  portalname,
int  cursorOptions 
)
static

Definition at line 8503 of file pl_exec.c.

References convert_value_to_string(), elog, ereport, errcode(), errmsg(), ERROR, exec_eval_cleanup(), exec_eval_expr(), exec_eval_using_params(), get_stmt_mcontext(), MemoryContextReset(), MemoryContextStrdup(), PreparedParamsData::nargs, PreparedParamsData::nulls, PLpgSQL_execstate::readonly_func, SPI_cursor_open_with_args(), SPI_result, SPI_result_code_string(), PreparedParamsData::types, and PreparedParamsData::values.

Referenced by exec_stmt_dynfors(), exec_stmt_open(), and exec_stmt_return_query().

8508 {
8509  Portal portal;
8510  Datum query;
8511  bool isnull;
8512  Oid restype;
8513  int32 restypmod;
8514  char *querystr;
8515  MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
8516 
8517  /*
8518  * Evaluate the string expression after the EXECUTE keyword. Its result is
8519  * the querystring we have to execute.
8520  */
8521  query = exec_eval_expr(estate, dynquery, &isnull, &restype, &restypmod);
8522  if (isnull)
8523  ereport(ERROR,
8524  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
8525  errmsg("query string argument of EXECUTE is null")));
8526 
8527  /* Get the C-String representation */
8528  querystr = convert_value_to_string(estate, query, restype);
8529 
8530  /* copy it into the stmt_mcontext before we clean up */
8531  querystr = MemoryContextStrdup(stmt_mcontext, querystr);
8532 
8533  exec_eval_cleanup(estate);
8534 
8535  /*
8536  * Open an implicit cursor for the query. We use
8537  * SPI_cursor_open_with_args even when there are no params, because this
8538  * avoids making and freeing one copy of the plan.
8539  */
8540  if (params)
8541  {
8542  PreparedParamsData *ppd;
8543 
8544  ppd = exec_eval_using_params(estate, params);
8545  portal = SPI_cursor_open_with_args(portalname,
8546  querystr,
8547  ppd->nargs, ppd->types,
8548  ppd->values, ppd->nulls,
8549  estate->readonly_func,
8550  cursorOptions);
8551  }
8552  else
8553  {
8554  portal = SPI_cursor_open_with_args(portalname,
8555  querystr,
8556  0, NULL,
8557  NULL, NULL,
8558  estate->readonly_func,
8559  cursorOptions);
8560  }
8561 
8562  if (portal == NULL)
8563  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
8564  querystr, SPI_result_code_string(SPI_result));
8565 
8566  /* Release transient data */
8567  MemoryContextReset(stmt_mcontext);
8568 
8569  return portal;
8570 }
int errcode(int sqlerrcode)
Definition: elog.c:608
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4017
Datum * values
Definition: pl_exec.c:57
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:347
int SPI_result
Definition: spi.c:47
#define ERROR
Definition: elog.h:43
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5750
static PreparedParamsData * exec_eval_using_params(PLpgSQL_execstate *estate, List *params)
Definition: pl_exec.c:8424
const char * SPI_result_code_string(int code)
Definition: spi.c:1705
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1492
#define ereport(elevel, rest)
Definition: elog.h:141
uintptr_t Datum
Definition: postgres.h:367
Portal SPI_cursor_open_with_args(const char *name, const char *src, int nargs, Oid *argtypes, Datum *Values, const char *Nulls, bool read_only, int cursorOptions)
Definition: spi.c:1248
int errmsg(const char *fmt,...)
Definition: elog.c:822
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1173
#define elog(elevel,...)
Definition: elog.h:228
static char * convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
Definition: pl_exec.c:7649

◆ exec_eval_boolean()

static bool exec_eval_boolean ( PLpgSQL_execstate estate,
PLpgSQL_expr expr,
bool isNull 
)
static

Definition at line 5727 of file pl_exec.c.

References DatumGetBool, exec_cast_value(), and exec_eval_expr().

Referenced by exec_stmt_assert(), exec_stmt_case(), exec_stmt_exit(), exec_stmt_if(), and exec_stmt_while().

5730 {
5731  Datum exprdatum;
5732  Oid exprtypeid;
5733  int32 exprtypmod;
5734 
5735  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5736  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5737  exprtypeid, exprtypmod,
5738  BOOLOID, -1);
5739  return DatumGetBool(exprdatum);
5740 }
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:347
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7678
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5750
#define DatumGetBool(X)
Definition: postgres.h:393
uintptr_t Datum
Definition: postgres.h:367

◆ exec_eval_cleanup()

static void exec_eval_cleanup ( PLpgSQL_execstate estate)
static

Definition at line 4017 of file pl_exec.c.

References PLpgSQL_execstate::eval_econtext, PLpgSQL_execstate::eval_tuptable, ResetExprContext, and SPI_freetuptable().

Referenced by exec_assign_expr(), exec_dynquery_with_params(), exec_eval_using_params(), exec_for_query(), exec_run_select(), exec_stmt_assert(), exec_stmt_block(), exec_stmt_call(), exec_stmt_case(), exec_stmt_dynexecute(), exec_stmt_execsql(), exec_stmt_exit(), exec_stmt_fetch(), exec_stmt_forc(), exec_stmt_foreach_a(), exec_stmt_fori(), exec_stmt_getdiag(), exec_stmt_if(), exec_stmt_open(), exec_stmt_perform(), exec_stmt_raise(), exec_stmt_return_next(), exec_stmt_return_query(), exec_stmt_while(), plpgsql_exec_event_trigger(), plpgsql_exec_function(), and plpgsql_exec_trigger().

4018 {
4019  /* Clear result of a full SPI_execute */
4020  if (estate->eval_tuptable != NULL)
4022  estate->eval_tuptable = NULL;
4023 
4024  /*
4025  * Clear result of exec_eval_simple_expr (but keep the econtext). This
4026  * also clears any short-lived allocations done via get_eval_mcontext.
4027  */
4028  if (estate->eval_econtext != NULL)
4030 }
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1096
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1162
ExprContext * eval_econtext
Definition: plpgsql.h:1098
#define ResetExprContext(econtext)
Definition: executor.h:495

◆ exec_eval_datum()

static void exec_eval_datum ( PLpgSQL_execstate estate,
PLpgSQL_datum datum,
Oid typeid,
int32 typetypmod,
Datum value,
bool isnull 
)
static

Definition at line 5373 of file pl_exec.c.

References PLpgSQL_type::atttypmod, BlessTupleDesc(), PLpgSQL_var::datatype, PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, PLpgSQL_var::dtype, elog, ExpandedRecordHeader::er_tupdesc_id, ExpandedRecordHeader::er_typeid, ExpandedRecordHeader::er_typmod, ereport, PLpgSQL_rec::erh, errcode(), errmsg(), ERROR, expanded_record_get_field(), expanded_record_lookup_field(), ExpandedRecordGetDatum, ExpandedRecordIsEmpty, PLpgSQL_recfield::fieldname, PLpgSQL_recfield::finfo, ExpandedRecordFieldInfo::fnumber, ExpandedRecordFieldInfo::ftypeid, ExpandedRecordFieldInfo::ftypmod, get_eval_mcontext, HeapTupleGetDatum, instantiate_empty_record_variable(), PLpgSQL_var::isnull, make_tuple_from_row(), MemoryContextSwitchTo(), PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, plpgsql_fulfill_promise(), PLpgSQL_recfield::recparentno, PLpgSQL_recfield::rectupledescid, PLpgSQL_rec::rectypeid, PLpgSQL_rec::refname, PLpgSQL_row::rowtupdesc, TupleDescData::tdtypeid, TupleDescData::tdtypmod, PLpgSQL_type::typoid, unlikely, and PLpgSQL_var::value.

Referenced by exec_assign_value(), exec_stmt_return(), format_expr_params(), make_tuple_from_row(), plpgsql_param_eval_generic(), plpgsql_param_eval_generic_ro(), and plpgsql_param_fetch().

5379 {
5380  MemoryContext oldcontext;
5381 
5382  switch (datum->dtype)
5383  {
5384  case PLPGSQL_DTYPE_PROMISE:
5385  /* fulfill promise if needed, then handle like regular var */
5386  plpgsql_fulfill_promise(estate, (PLpgSQL_var *) datum);
5387 
5388  /* FALL THRU */
5389 
5390  case PLPGSQL_DTYPE_VAR:
5391  {
5392  PLpgSQL_var *var = (PLpgSQL_var *) datum;
5393 
5394  *typeid = var->datatype->typoid;
5395  *typetypmod = var->datatype->atttypmod;
5396  *value = var->value;
5397  *isnull = var->isnull;
5398  break;
5399  }
5400 
5401  case PLPGSQL_DTYPE_ROW:
5402  {
5403  PLpgSQL_row *row = (PLpgSQL_row *) datum;
5404  HeapTuple tup;
5405 
5406  /* We get here if there are multiple OUT parameters */
5407  if (!row->rowtupdesc) /* should not happen */
5408  elog(ERROR, "row variable has no tupdesc");
5409  /* Make sure we have a valid type/typmod setting */
5410  BlessTupleDesc(row->rowtupdesc);
5411  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5412  tup = make_tuple_from_row(estate, row, row->rowtupdesc);
5413  if (tup == NULL) /* should not happen */
5414  elog(ERROR, "row not compatible with its own tupdesc");
5415  *typeid = row->rowtupdesc->tdtypeid;
5416  *typetypmod = row->rowtupdesc->tdtypmod;
5417  *value = HeapTupleGetDatum(tup);
5418  *isnull = false;
5419  MemoryContextSwitchTo(oldcontext);
5420  break;
5421  }
5422 
5423  case PLPGSQL_DTYPE_REC:
5424  {
5425  PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
5426 
5427  if (rec->erh == NULL)
5428  {
5429  /* Treat uninstantiated record as a simple NULL */
5430  *value = (Datum) 0;
5431  *isnull = true;
5432  /* Report variable's declared type */
5433  *typeid = rec->rectypeid;
5434  *typetypmod = -1;
5435  }
5436  else
5437  {
5438  if (ExpandedRecordIsEmpty(rec->erh))
5439  {
5440  /* Empty record is also a NULL */
5441  *value = (Datum) 0;
5442  *isnull = true;
5443  }
5444  else
5445  {
5446  *value = ExpandedRecordGetDatum(rec->erh);
5447  *isnull = false;
5448  }
5449  if (rec->rectypeid != RECORDOID)
5450  {
5451  /* Report variable's declared type, if not RECORD */
5452  *typeid = rec->rectypeid;
5453  *typetypmod = -1;
5454  }
5455  else
5456  {
5457  /* Report record's actual type if declared RECORD */
5458  *typeid = rec->erh->er_typeid;
5459  *typetypmod = rec->erh->er_typmod;
5460  }
5461  }
5462  break;
5463  }
5464 
5466  {
5467  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
5468  PLpgSQL_rec *rec;
5469  ExpandedRecordHeader *erh;
5470 
5471  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5472  erh = rec->erh;
5473 
5474  /*
5475  * If record variable is NULL, instantiate it if it has a
5476  * named composite type, else complain. (This won't change
5477  * the logical state of the record: it's still NULL.)
5478  */
5479  if (erh == NULL)
5480  {
5481  instantiate_empty_record_variable(estate, rec);
5482  erh = rec->erh;
5483  }
5484 
5485  /*
5486  * Look up the field's properties if we have not already, or
5487  * if the tuple descriptor ID changed since last time.
5488  */
5489  if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
5490  {
5492  recfield->fieldname,
5493  &recfield->finfo))
5494  ereport(ERROR,
5495  (errcode(ERRCODE_UNDEFINED_COLUMN),
5496  errmsg("record \"%s\" has no field \"%s\"",
5497  rec->refname, recfield->fieldname)));
5498  recfield->rectupledescid = erh->er_tupdesc_id;
5499  }
5500 
5501  /* Report type data. */
5502  *typeid = recfield->finfo.ftypeid;
5503  *typetypmod = recfield->finfo.ftypmod;
5504 
5505  /* And fetch the field value. */
5507  recfield->finfo.fnumber,
5508  isnull);
5509  break;
5510  }
5511 
5512  default:
5513  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
5514  }
5515 }
static HeapTuple make_tuple_from_row(PLpgSQL_execstate *estate, PLpgSQL_row *row, TupleDesc tupdesc)
Definition: pl_exec.c:7295
#define ExpandedRecordIsEmpty(erh)
bool expanded_record_lookup_field(ExpandedRecordHeader *erh, const char *fieldname, ExpandedRecordFieldInfo *finfo)
static Datum expanded_record_get_field(ExpandedRecordHeader *erh, int fnumber, bool *isnull)
PLpgSQL_type * datatype
Definition: plpgsql.h:301
static void plpgsql_fulfill_promise(PLpgSQL_execstate *estate, PLpgSQL_var *var)
Definition: pl_exec.c:1332
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static struct @145 value
static void instantiate_empty_record_variable(PLpgSQL_execstate *estate, PLpgSQL_rec *rec)
Definition: pl_exec.c:7614
ExpandedRecordHeader * erh
Definition: plpgsql.h:395
int errcode(int sqlerrcode)
Definition: elog.c:608
PLpgSQL_datum_type dtype
Definition: plpgsql.h:258
char * refname
Definition: plpgsql.h:374
PLpgSQL_datum ** datums
Definition: plpgsql.h:1072
#define ERROR
Definition: elog.h:43
int32 tdtypmod
Definition: tupdesc.h:83
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2052
#define ereport(elevel, rest)
Definition: elog.h:141
uint64 rectupledescid
Definition: plpgsql.h:410
#define get_eval_mcontext(estate)
Definition: pl_exec.c:120
uintptr_t Datum
Definition: postgres.h:367
ExpandedRecordFieldInfo finfo
Definition: plpgsql.h:411
Datum value
Definition: plpgsql.h:314
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:220
Oid tdtypeid
Definition: tupdesc.h:82
int errmsg(const char *fmt,...)
Definition: elog.c:822
int32 atttypmod
Definition: plpgsql.h:209
#define elog(elevel,...)
Definition: elog.h:228
TupleDesc rowtupdesc
Definition: plpgsql.h:360
#define unlikely(x)
Definition: c.h:208
Oid rectypeid
Definition: plpgsql.h:388
#define ExpandedRecordGetDatum(erh)
char * fieldname
Definition: plpgsql.h:407
bool isnull
Definition: plpgsql.h:315
Oid typoid
Definition: plpgsql.h:202

◆ exec_eval_expr()

static Datum exec_eval_expr ( PLpgSQL_execstate estate,
PLpgSQL_expr expr,
bool isNull,
Oid rettype,
int32 rettypmod 
)
static

Definition at line 5750 of file pl_exec.c.

References CURSOR_OPT_PARALLEL_OK, ereport, errcode(), errmsg(), errmsg_plural(), ERROR, PLpgSQL_execstate::eval_processed, PLpgSQL_execstate::eval_tuptable, exec_eval_simple_expr(), exec_prepare_plan(), exec_run_select(), TupleDescData::natts, PLpgSQL_expr::plan, PLpgSQL_expr::query, SPI_getbinval(), SPI_OK_SELECT, SPITupleTable::tupdesc, TupleDescAttr, and SPITupleTable::vals.

Referenced by exec_assign_expr(), exec_dynquery_with_params(), exec_eval_boolean(), exec_eval_integer(), exec_eval_using_params(), exec_stmt_assert(), exec_stmt_case(), exec_stmt_dynexecute(), exec_stmt_foreach_a(), exec_stmt_fori(), exec_stmt_raise(), exec_stmt_return(), and exec_stmt_return_next().

5755 {
5756  Datum result = 0;
5757  int rc;
5758  Form_pg_attribute attr;
5759 
5760  /*
5761  * If first time through, create a plan for this expression.
5762  */
5763  if (expr->plan == NULL)
5764  exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK, true);
5765 
5766  /*
5767  * If this is a simple expression, bypass SPI and use the executor
5768  * directly
5769  */
5770  if (exec_eval_simple_expr(estate, expr,
5771  &result, isNull, rettype, rettypmod))
5772  return result;
5773 
5774  /*
5775  * Else do it the hard way via exec_run_select
5776  */
5777  rc = exec_run_select(estate, expr, 2, NULL);
5778  if (rc != SPI_OK_SELECT)
5779  ereport(ERROR,
5780  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5781  errmsg("query \"%s\" did not return data", expr->query)));
5782 
5783  /*
5784  * Check that the expression returns exactly one column...
5785  */
5786  if (estate->eval_tuptable->tupdesc->natts != 1)
5787  ereport(ERROR,
5788  (errcode(ERRCODE_SYNTAX_ERROR),
5789  errmsg_plural("query \"%s\" returned %d column",
5790  "query \"%s\" returned %d columns",
5791  estate->eval_tuptable->tupdesc->natts,
5792  expr->query,
5793  estate->eval_tuptable->tupdesc->natts)));
5794 
5795  /*
5796  * ... and get the column's datatype.
5797  */
5798  attr = TupleDescAttr(estate->eval_tuptable->tupdesc, 0);
5799  *rettype = attr->atttypid;
5800  *rettypmod = attr->atttypmod;
5801 
5802  /*
5803  * If there are no rows selected, the result is a NULL of that type.
5804  */
5805  if (estate->eval_processed == 0)
5806  {
5807  *isNull = true;
5808  return (Datum) 0;
5809  }
5810 
5811  /*
5812  * Check that the expression returned no more than one row.
5813  */
5814  if (estate->eval_processed != 1)
5815  ereport(ERROR,
5816  (errcode(ERRCODE_CARDINALITY_VIOLATION),
5817  errmsg("query \"%s\" returned more than one row",
5818  expr->query)));
5819 
5820  /*
5821  * Return the single result Datum.
5822  */
5823  return SPI_getbinval(estate->eval_tuptable->vals[0],
5824  estate->eval_tuptable->tupdesc, 1, isNull);
5825 }
char * query
Definition: plpgsql.h:221
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions, bool keepplan)
Definition: pl_exec.c:4038
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1096
uint64 eval_processed
Definition: plpgsql.h:1097
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:932
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
int errcode(int sqlerrcode)
Definition: elog.c:608
HeapTuple * vals
Definition: spi.h:26
SPIPlanPtr plan
Definition: plpgsql.h:222
#define ERROR
Definition: elog.h:43
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition: spi.c:1028
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define ereport(elevel, rest)
Definition: elog.h:141
uintptr_t Datum
Definition: postgres.h:367
TupleDesc tupdesc
Definition: spi.h:25
#define SPI_OK_SELECT
Definition: spi.h:57
static int exec_run_select(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
Definition: pl_exec.c:5833
static bool exec_eval_simple_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, Datum *result, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:6070
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2692
int errmsg(const char *fmt,...)
Definition: elog.c:822

◆ exec_eval_integer()

static int exec_eval_integer ( PLpgSQL_execstate estate,
PLpgSQL_expr expr,
bool isNull 
)
static

Definition at line 5704 of file pl_exec.c.

References DatumGetInt32, exec_cast_value(), and exec_eval_expr().

Referenced by exec_assign_value(), and exec_stmt_fetch().

5707 {
5708  Datum exprdatum;
5709  Oid exprtypeid;
5710  int32 exprtypmod;
5711 
5712  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5713  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5714  exprtypeid, exprtypmod,
5715  INT4OID, -1);
5716  return DatumGetInt32(exprdatum);
5717 }
#define DatumGetInt32(X)
Definition: postgres.h:472
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:347
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7678
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5750
uintptr_t Datum
Definition: postgres.h:367

◆ exec_eval_simple_expr()

static bool exec_eval_simple_expr ( PLpgSQL_execstate estate,
PLpgSQL_expr expr,
Datum result,
bool isNull,
Oid rettype,
int32 rettypmod 
)
static

Definition at line 6070 of file pl_exec.c.

References Assert, CommandCounterIncrement(), ExprContext::ecxt_param_list_info, EState::es_query_cxt, PLpgSQL_execstate::eval_econtext, exec_check_rw_parameter(), exec_save_simple_expr(), ExecEvalExpr(), ExecInitExprWithParams(), PLpgSQL_expr::expr_simple_expr, PLpgSQL_expr::expr_simple_generation, PLpgSQL_expr::expr_simple_in_use, PLpgSQL_expr::expr_simple_lxid, PLpgSQL_expr::expr_simple_mutable, PLpgSQL_expr::expr_simple_state, PLpgSQL_expr::expr_simple_type, PLpgSQL_expr::expr_simple_typmod, CachedPlan::generation, get_eval_mcontext, GetTransactionSnapshot(), PGPROC::lxid, MemoryContextSwitchTo(), MyProc, PLpgSQL_execstate::paramLI, ParamListInfoData::parserSetupArg, PLpgSQL_expr::plan, PopActiveSnapshot(), PushActiveSnapshot(), PLpgSQL_execstate::readonly_func, ReleaseCachedPlan(), PLpgSQL_expr::rwparam, setup_param_list(), PLpgSQL_execstate::simple_eval_estate, and SPI_plan_get_cached_plan().

Referenced by exec_eval_expr().

6076 {
6077  ExprContext *econtext = estate->eval_econtext;
6078  LocalTransactionId curlxid = MyProc->lxid;
6079  CachedPlan *cplan;
6080  void *save_setup_arg;
6081  bool need_snapshot;
6082  MemoryContext oldcontext;
6083 
6084  /*
6085  * Forget it if expression wasn't simple before.
6086  */
6087  if (expr->expr_simple_expr == NULL)
6088  return false;
6089 
6090  /*
6091  * If expression is in use in current xact, don't touch it.
6092  */
6093  if (expr->expr_simple_in_use && expr->expr_simple_lxid == curlxid)
6094  return false;
6095 
6096  /*
6097  * Revalidate cached plan, so that we will notice if it became stale. (We
6098  * need to hold a refcount while using the plan, anyway.) If replanning
6099  * is needed, do that work in the eval_mcontext.
6100  */
6101  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6102  cplan = SPI_plan_get_cached_plan(expr->plan);
6103  MemoryContextSwitchTo(oldcontext);
6104 
6105  /*
6106  * We can't get a failure here, because the number of CachedPlanSources in
6107  * the SPI plan can't change from what exec_simple_check_plan saw; it's a
6108  * property of the raw parsetree generated from the query text.
6109  */
6110  Assert(cplan != NULL);
6111 
6112  /* If it got replanned, update our copy of the simple expression */
6113  if (cplan->generation != expr->expr_simple_generation)
6114  {
6115  exec_save_simple_expr(expr, cplan);
6116  /* better recheck r/w safety, as it could change due to inlining */
6117  if (expr->rwparam >= 0)
6118  exec_check_rw_parameter(expr, expr->rwparam);
6119  }
6120 
6121  /*
6122  * Pass back previously-determined result type.
6123  */
6124  *rettype = expr->expr_simple_type;
6125  *rettypmod = expr->expr_simple_typmod;
6126 
6127  /*
6128  * Set up ParamListInfo to pass to executor. For safety, save and restore
6129  * estate->paramLI->parserSetupArg around our use of the param list.
6130  */
6131  save_setup_arg = estate->paramLI->parserSetupArg;
6132 
6133  econtext->ecxt_param_list_info = setup_param_list(estate, expr);
6134 
6135  /*
6136  * Prepare the expression for execution, if it's not been done already in
6137  * the current transaction. (This will be forced to happen if we called
6138  * exec_save_simple_expr above.)
6139  */
6140  if (expr->expr_simple_lxid != curlxid)
6141  {
6142  oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
6143  expr->expr_simple_state =
6145  econtext->ecxt_param_list_info);
6146  expr->expr_simple_in_use = false;
6147  expr->expr_simple_lxid = curlxid;
6148  MemoryContextSwitchTo(oldcontext);
6149  }
6150 
6151  /*
6152  * We have to do some of the things SPI_execute_plan would do, in
6153  * particular push a new snapshot so that stable functions within the
6154  * expression can see updates made so far by our own function. However,
6155  * we can skip doing that (and just invoke the expression with the same
6156  * snapshot passed to our function) in some cases, which is useful because
6157  * it's quite expensive relative to the cost of a simple expression. We
6158  * can skip it if the expression contains no stable or volatile functions;
6159  * immutable functions shouldn't need to see our updates. Also, if this
6160  * is a read-only function, we haven't made any updates so again it's okay
6161  * to skip.
6162  */
6163  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6164  need_snapshot = (expr->expr_simple_mutable && !estate->readonly_func);
6165  if (need_snapshot)
6166  {
6169  }
6170 
6171  /*
6172  * Mark expression as busy for the duration of the ExecEvalExpr call.
6173  */
6174  expr->expr_simple_in_use = true;
6175 
6176  /*
6177  * Finally we can call the executor to evaluate the expression
6178  */
6179  *result = ExecEvalExpr(expr->expr_simple_state,
6180  econtext,
6181  isNull);
6182 
6183  /* Assorted cleanup */
6184  expr->expr_simple_in_use = false;
6185 
6186  econtext->ecxt_param_list_info = NULL;
6187 
6188  estate->paramLI->parserSetupArg = save_setup_arg;
6189 
6190  if (need_snapshot)
6192 
6193  MemoryContextSwitchTo(oldcontext);
6194 
6195  /*
6196  * Now we can release our refcount on the cached plan.
6197  */
6198  ReleaseCachedPlan(cplan, true);
6199 
6200  /*
6201  * That's it.
6202  */
6203  return true;
6204 }
int expr_simple_generation
Definition: plpgsql.h:234
void * parserSetupArg
Definition: params.h:117
static void exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno)
Definition: pl_exec.c:8078
PGPROC * MyProc
Definition: proc.c:67
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void PopActiveSnapshot(void)
Definition: snapmgr.c:814
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:306
static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
Definition: pl_exec.c:7989
SPIPlanPtr plan
Definition: plpgsql.h:222
CachedPlan * SPI_plan_get_cached_plan(SPIPlanPtr plan)
Definition: spi.c:1798
MemoryContext es_query_cxt
Definition: execnodes.h:549
ParamListInfo paramLI
Definition: plpgsql.h:1082
EState * simple_eval_estate
Definition: plpgsql.h:1085
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:735
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:285
ExprState * ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
Definition: execExpr.c:158
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1259
Expr * expr_simple_expr
Definition: plpgsql.h:233
uint32 LocalTransactionId
Definition: c.h:516
static ParamListInfo setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:6223
int rwparam
Definition: plpgsql.h:224
#define get_eval_mcontext(estate)
Definition: pl_exec.c:120
ExprState * expr_simple_state
Definition: plpgsql.h:245
bool expr_simple_mutable
Definition: plpgsql.h:237
void CommandCounterIncrement(void)
Definition: xact.c:1005
LocalTransactionId expr_simple_lxid
Definition: plpgsql.h:247
#define Assert(condition)
Definition: c.h:739
ExprContext * eval_econtext
Definition: plpgsql.h:1098
int generation
Definition: plancache.h:154
int32 expr_simple_typmod
Definition: plpgsql.h:236
bool expr_simple_in_use
Definition: plpgsql.h:246
ParamListInfo ecxt_param_list_info
Definition: execnodes.h:235
Oid expr_simple_type
Definition: plpgsql.h:235
LocalTransactionId lxid
Definition: proc.h:106

◆ exec_eval_using_params()

static PreparedParamsData * exec_eval_using_params ( PLpgSQL_execstate estate,
List params 
)
static

Definition at line 8424 of file pl_exec.c.

References CStringGetTextDatum, datumCopy(), DatumGetCString, exec_eval_cleanup(), exec_eval_expr(), get_stmt_mcontext(), get_typlenbyval(), i, lfirst, list_length(), MemoryContextAlloc(), MemoryContextSwitchTo(), PreparedParamsData::nargs, PreparedParamsData::nulls, PreparedParamsData::types, and PreparedParamsData::values.

Referenced by exec_dynquery_with_params(), and exec_stmt_dynexecute().

8425 {
8426  PreparedParamsData *ppd;
8427  MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
8428  int nargs;
8429  int i;
8430  ListCell *lc;
8431 
8432  ppd = (PreparedParamsData *)
8433  MemoryContextAlloc(stmt_mcontext, sizeof(PreparedParamsData));
8434  nargs = list_length(params);
8435 
8436  ppd->nargs = nargs;
8437  ppd->types = (Oid *)
8438  MemoryContextAlloc(stmt_mcontext, nargs * sizeof(Oid));
8439  ppd->values = (Datum *)
8440  MemoryContextAlloc(stmt_mcontext, nargs * sizeof(Datum));
8441  ppd->nulls = (char *)
8442  MemoryContextAlloc(stmt_mcontext, nargs * sizeof(char));
8443 
8444  i = 0;
8445  foreach(lc, params)
8446  {
8447  PLpgSQL_expr *param = (PLpgSQL_expr *) lfirst(lc);
8448  bool isnull;
8449  int32 ppdtypmod;
8450  MemoryContext oldcontext;
8451 
8452  ppd->values[i] = exec_eval_expr(estate, param,
8453  &isnull,
8454  &ppd->types[i],
8455  &ppdtypmod);
8456  ppd->nulls[i] = isnull ? 'n' : ' ';
8457 
8458  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8459 
8460  if (ppd->types[i] == UNKNOWNOID)
8461  {
8462  /*
8463  * Treat 'unknown' parameters as text, since that's what most
8464  * people would expect. SPI_execute_with_args can coerce unknown
8465  * constants in a more intelligent way, but not unknown Params.
8466  * This code also takes care of copying into the right context.
8467  * Note we assume 'unknown' has the representation of C-string.
8468  */
8469  ppd->types[i] = TEXTOID;
8470  if (!isnull)
8472  }
8473  /* pass-by-ref non null values must be copied into stmt_mcontext */
8474  else if (!isnull)
8475  {
8476  int16 typLen;
8477  bool typByVal;
8478 
8479  get_typlenbyval(ppd->types[i], &typLen, &typByVal);
8480  if (!typByVal)
8481  ppd->values[i] = datumCopy(ppd->values[i], typByVal, typLen);
8482  }
8483 
8484  MemoryContextSwitchTo(oldcontext);
8485 
8486  exec_eval_cleanup(estate);
8487 
8488  i++;
8489  }
8490 
8491  return ppd;
8492 }
signed short int16
Definition: c.h:346
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4017
Datum * values
Definition: pl_exec.c:57
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:347
#define DatumGetCString(X)
Definition: postgres.h:566
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5750
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1492
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:130
uintptr_t Datum
Definition: postgres.h:367
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2029
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
int i
#define CStringGetTextDatum(s)
Definition: builtins.h:83

◆ exec_for_query()

static int exec_for_query ( PLpgSQL_execstate estate,
PLpgSQL_stmt_forq stmt,
Portal  portal,
bool  prefetch_ok 
)
static

Definition at line 5897 of file pl_exec.c.

References PLpgSQL_execstate::atomic, PLpgSQL_stmt_forq::body, compatible_tupdescs(), PLpgSQL_execstate::datums, PLpgSQL_variable::dno, PLpgSQL_variable::dtype, ExpandedRecordHeader::er_tupdesc_id, PLpgSQL_rec::erh, exec_eval_cleanup(), exec_move_row(), exec_set_found(), exec_stmts(), expanded_record_get_tupdesc(), expanded_record_set_tuple(), i, INVALID_TUPLEDESC_IDENTIFIER, PLpgSQL_stmt_forq::label, LOOP_RC_PROCESSING, PinPortal(), PLPGSQL_DTYPE_REC, PLPGSQL_RC_OK, PLpgSQL_rec::rectypeid, SPI_cursor_fetch(), SPI_freetuptable(), SPI_processed, SPI_tuptable, TupleDescData::tdtypeid, SPITupleTable::tupdesc, UnpinPortal(), SPITupleTable::vals, and PLpgSQL_stmt_forq::var.

Referenced by exec_stmt_dynfors(), exec_stmt_forc(), and exec_stmt_fors().

5899 {
5900  PLpgSQL_variable *var;
5901  SPITupleTable *tuptab;
5902  bool found = false;
5903  int rc = PLPGSQL_RC_OK;
5904  uint64 previous_id = INVALID_TUPLEDESC_IDENTIFIER;
5905  bool tupdescs_match = true;
5906  uint64 n;
5907 
5908  /* Fetch loop variable's datum entry */
5909  var = (PLpgSQL_variable *) estate->datums[stmt->var->dno];
5910 
5911  /*
5912  * Make sure the portal doesn't get closed by the user statements we
5913  * execute.
5914  */
5915  PinPortal(portal);
5916 
5917  /*
5918  * Fetch the initial tuple(s). If prefetching is allowed then we grab a
5919  * few more rows to avoid multiple trips through executor startup
5920  * overhead.
5921  */
5922  SPI_cursor_fetch(portal, true, prefetch_ok ? 10 : 1);
5923  tuptab = SPI_tuptable;
5924  n = SPI_processed;
5925 
5926  /*
5927  * If the query didn't return any rows, set the target to NULL and fall
5928  * through with found = false.
5929  */
5930  if (n == 0)
5931  {
5932  exec_move_row(estate, var, NULL, tuptab->tupdesc);
5933  exec_eval_cleanup(estate);
5934  }
5935  else
5936  found = true; /* processed at least one tuple */
5937 
5938  /*
5939  * Now do the loop
5940  */
5941  while (n > 0)
5942  {
5943  uint64 i;
5944 
5945  for (i = 0; i < n; i++)
5946  {
5947  /*
5948  * Assign the tuple to the target. Here, because we know that all
5949  * loop iterations should be assigning the same tupdesc, we can
5950  * optimize away repeated creations of expanded records with
5951  * identical tupdescs. Testing for changes of er_tupdesc_id is
5952  * reliable even if the loop body contains assignments that
5953  * replace the target's value entirely, because it's assigned from
5954  * a process-global counter. The case where the tupdescs don't
5955  * match could possibly be handled more efficiently than this
5956  * coding does, but it's not clear extra effort is worthwhile.
5957  */
5958  if (var->dtype == PLPGSQL_DTYPE_REC)
5959  {
5960  PLpgSQL_rec *rec = (PLpgSQL_rec *) var;
5961 
5962  if (rec->erh &&
5963  rec->erh->er_tupdesc_id == previous_id &&
5964  tupdescs_match)
5965  {
5966  /* Only need to assign a new tuple value */
5967  expanded_record_set_tuple(rec->erh, tuptab->vals[i],
5968  true, !estate->atomic);
5969  }
5970  else
5971  {
5972  /*
5973  * First time through, or var's tupdesc changed in loop,
5974  * or we have to do it the hard way because type coercion
5975  * is needed.
5976  */
5977  exec_move_row(estate, var,
5978  tuptab->vals[i], tuptab->tupdesc);
5979 
5980  /*
5981  * Check to see if physical assignment is OK next time.
5982  * Once the tupdesc comparison has failed once, we don't
5983  * bother rechecking in subsequent loop iterations.
5984  */
5985  if (tupdescs_match)
5986  {
5987  tupdescs_match =
5988  (rec->rectypeid == RECORDOID ||
5989  rec->rectypeid == tuptab->tupdesc->tdtypeid ||
5990  compatible_tupdescs(tuptab->tupdesc,
5992  }
5993  previous_id = rec->erh->er_tupdesc_id;
5994  }
5995  }
5996  else
5997  exec_move_row(estate, var, tuptab->vals[i], tuptab->tupdesc);
5998 
5999  exec_eval_cleanup(estate);
6000 
6001  /*
6002  * Execute the statements
6003  */
6004  rc = exec_stmts(estate, stmt->body);
6005 
6006  LOOP_RC_PROCESSING(stmt->label, goto loop_exit);
6007  }
6008 
6009  SPI_freetuptable(tuptab);
6010 
6011  /*
6012  * Fetch more tuples. If prefetching is allowed, grab 50 at a time.
6013  */
6014  SPI_cursor_fetch(portal, true, prefetch_ok ? 50 : 1);
6015  tuptab = SPI_tuptable;
6016  n = SPI_processed;
6017  }
6018 
6019 loop_exit:
6020 
6021  /*
6022  * Release last group of tuples (if any)
6023  */
6024  SPI_freetuptable(tuptab);
6025 
6026  UnpinPortal(portal);
6027 
6028  /*
6029  * Set the FOUND variable to indicate the result of executing the loop
6030  * (namely, whether we looped one or more times). This must be set last so
6031  * that it does not interfere with the value of the FOUND variable inside
6032  * the loop processing itself.
6033  */
6034  exec_set_found(estate, found);
6035 
6036  return rc;
6037 }
void UnpinPortal(Portal portal)
Definition: portalmem.c:377
void expanded_record_set_tuple(ExpandedRecordHeader *erh, HeapTuple tuple, bool copy, bool expand_external)
SPITupleTable * SPI_tuptable
Definition: spi.c:46
ExpandedRecordHeader * erh
Definition: plpgsql.h:395
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4017
HeapTuple * vals
Definition: spi.h:26
#define INVALID_TUPLEDESC_IDENTIFIER
Definition: typcache.h:146
uint64 SPI_processed
Definition: spi.c:45
PLpgSQL_datum ** datums
Definition: plpgsql.h:1072
void PinPortal(Portal portal)
Definition: portalmem.c:368
#define LOOP_RC_PROCESSING(looplabel, exit_action)
Definition: pl_exec.c:187
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1162
static bool compatible_tupdescs(TupleDesc src_tupdesc, TupleDesc dst_tupdesc)
Definition: pl_exec.c:7251
TupleDesc tupdesc
Definition: spi.h:25
PLpgSQL_datum_type dtype
Definition: plpgsql.h:270
PLpgSQL_variable * var
Definition: plpgsql.h:708
static void exec_set_found(PLpgSQL_execstate *estate, bool state)
Definition: pl_exec.c:8177
Oid tdtypeid
Definition: tupdesc.h:82
static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
Definition: pl_exec.c:6716
int i
void SPI_cursor_fetch(Portal portal, bool forward, long count)
Definition: spi.c:1539
Oid rectypeid
Definition: plpgsql.h:388
static int exec_stmts(PLpgSQL_execstate *estate, List *stmts)
Definition: pl_exec.c:1903

◆ exec_init_tuple_store()

static void exec_init_tuple_store ( PLpgSQL_execstate estate)
static

Definition at line 3567 of file pl_exec.c.

References ReturnSetInfo::allowedModes, CurrentResourceOwner, ereport, errcode(), errmsg(), ERROR, ReturnSetInfo::expectedDesc, IsA, MemoryContextSwitchTo(), PLpgSQL_execstate::rsi, SFRM_Materialize, SFRM_Materialize_Random, PLpgSQL_execstate::tuple_store, PLpgSQL_execstate::tuple_store_cxt, PLpgSQL_execstate::tuple_store_desc, PLpgSQL_execstate::tuple_store_owner, tuplestore_begin_heap(), and work_mem.

Referenced by exec_stmt_return_next(), and exec_stmt_return_query().

3568 {
3569  ReturnSetInfo *rsi = estate->rsi;
3570  MemoryContext oldcxt;
3571  ResourceOwner oldowner;
3572 
3573  /*
3574  * Check caller can handle a set result in the way we want
3575  */
3576  if (!rsi || !IsA(rsi, ReturnSetInfo) ||
3577  (rsi->allowedModes & SFRM_Materialize) == 0 ||
3578  rsi->expectedDesc == NULL)
3579  ereport(ERROR,
3580  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3581  errmsg("set-valued function called in context that cannot accept a set")));
3582 
3583  /*
3584  * Switch to the right memory context and resource owner for storing the
3585  * tuplestore for return set. If we're within a subtransaction opened for
3586  * an exception-block, for example, we must still create the tuplestore in
3587  * the resource owner that was active when this function was entered, and
3588  * not in the subtransaction resource owner.
3589  */
3590  oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
3591  oldowner = CurrentResourceOwner;
3593 
3594  estate->tuple_store =
3596  false, work_mem);
3597 
3598  CurrentResourceOwner = oldowner;
3599  MemoryContextSwitchTo(oldcxt);
3600 
3601  estate->tuple_store_desc = rsi->expectedDesc;
3602 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
ResourceOwner tuple_store_owner
Definition: plpgsql.h:1060
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:608
TupleDesc expectedDesc
Definition: execnodes.h:301
TupleDesc tuple_store_desc
Definition: plpgsql.h:1058
#define ERROR
Definition: elog.h:43
MemoryContext tuple_store_cxt
Definition: plpgsql.h:1059
ReturnSetInfo * rsi
Definition: plpgsql.h:1061
#define ereport(elevel, rest)
Definition: elog.h:141
Tuplestorestate * tuple_store
Definition: plpgsql.h:1057
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
int work_mem
Definition: globals.c:121
int allowedModes
Definition: execnodes.h:302
int errmsg(const char *fmt,...)
Definition: elog.c:822

◆ exec_move_row()

static void exec_move_row ( PLpgSQL_execstate estate,
PLpgSQL_variable target,
HeapTuple  tup,
TupleDesc  tupdesc 
)
static

Definition at line 6716 of file pl_exec.c.

References assign_record_var(), PLpgSQL_execstate::atomic, compatible_tupdescs(), PLpgSQL_rec::datatype, deconstruct_expanded_record(), DeleteExpandedObject(), PLpgSQL_variable::dtype, PLpgSQL_rec::erh, eval_mcontext_alloc, exec_move_row_from_fields(), expanded_record_get_tupdesc(), expanded_record_set_tuple(), ExpandedRecordGetDatum, heap_deform_tuple(), HeapTupleIsValid, lengthof, make_expanded_record_for_rec(), TupleDescData::natts, PLPGSQL_DTYPE_REC, PLpgSQL_rec::rectypeid, TupleDescData::tdtypeid, PLpgSQL_type::typtype, and values.

Referenced by exec_assign_value(), exec_for_query(), exec_move_row_from_datum(), exec_stmt_block(), exec_stmt_call(), exec_stmt_dynexecute(), exec_stmt_execsql(), exec_stmt_fetch(), and plpgsql_exec_function().

6719 {
6720  ExpandedRecordHeader *newerh = NULL;
6721 
6722  /*
6723  * If target is RECORD, we may be able to avoid field-by-field processing.
6724  */
6725  if (target->dtype == PLPGSQL_DTYPE_REC)
6726  {
6727  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
6728 
6729  /*
6730  * If we have no source tupdesc, just set the record variable to NULL.
6731  * (If we have a source tupdesc but not a tuple, we'll set the
6732  * variable to a row of nulls, instead. This is odd perhaps, but
6733  * backwards compatible.)
6734  */
6735  if (tupdesc == NULL)
6736  {
6737  if (rec->datatype &&
6738  rec->datatype->typtype == TYPTYPE_DOMAIN)
6739  {
6740  /*
6741  * If it's a composite domain, NULL might not be a legal
6742  * value, so we instead need to make an empty expanded record
6743  * and ensure that domain type checking gets done. If there
6744  * is already an expanded record, piggyback on its lookups.
6745  */
6746  newerh = make_expanded_record_for_rec(estate, rec,
6747  NULL, rec->erh);
6748  expanded_record_set_tuple(newerh, NULL, false, false);
6749  assign_record_var(estate, rec, newerh);
6750  }
6751  else
6752  {
6753  /* Just clear it to NULL */
6754  if (rec->erh)
6756  rec->erh = NULL;
6757  }
6758  return;
6759  }
6760 
6761  /*
6762  * Build a new expanded record with appropriate tupdesc.
6763  */
6764  newerh = make_expanded_record_for_rec(estate, rec, tupdesc, NULL);
6765 
6766  /*
6767  * If the rowtypes match, or if we have no tuple anyway, we can
6768  * complete the assignment without field-by-field processing.
6769  *
6770  * The tests here are ordered more or less in order of cheapness. We
6771  * can easily detect it will work if the target is declared RECORD or
6772  * has the same typeid as the source. But when assigning from a query
6773  * result, it's common to have a source tupdesc that's labeled RECORD
6774  * but is actually physically compatible with a named-composite-type
6775  * target, so it's worth spending extra cycles to check for that.
6776  */
6777  if (rec->rectypeid == RECORDOID ||
6778  rec->rectypeid == tupdesc->tdtypeid ||
6779  !HeapTupleIsValid(tup) ||
6781  {
6782  if (!HeapTupleIsValid(tup))
6783  {
6784  /* No data, so force the record into all-nulls state */
6786  }
6787  else
6788  {
6789  /* No coercion is needed, so just assign the row value */
6790  expanded_record_set_tuple(newerh, tup, true, !estate->atomic);
6791  }
6792 
6793  /* Complete the assignment */
6794  assign_record_var(estate, rec, newerh);
6795 
6796  return;
6797  }
6798  }
6799 
6800  /*
6801  * Otherwise, deconstruct the tuple and do field-by-field assignment,
6802  * using exec_move_row_from_fields.
6803  */
6804  if (tupdesc && HeapTupleIsValid(tup))
6805  {
6806  int td_natts = tupdesc->natts;
6807  Datum *values;
6808  bool *nulls;
6809  Datum values_local[64];
6810  bool nulls_local[64];
6811 
6812  /*
6813  * Need workspace arrays. If td_natts is small enough, use local
6814  * arrays to save doing a palloc. Even if it's not small, we can
6815  * allocate both the Datum and isnull arrays in one palloc chunk.
6816  */
6817  if (td_natts <= lengthof(values_local))
6818  {
6819  values = values_local;
6820  nulls = nulls_local;
6821  }
6822  else
6823  {
6824  char *chunk;
6825 
6826  chunk = eval_mcontext_alloc(estate,
6827  td_natts * (sizeof(Datum) + sizeof(bool)));
6828  values = (Datum *) chunk;
6829  nulls = (bool *) (chunk + td_natts * sizeof(Datum));
6830  }
6831 
6832  heap_deform_tuple(tup, tupdesc, values, nulls);
6833 
6834  exec_move_row_from_fields(estate, target, newerh,
6835  values, nulls, tupdesc);
6836  }
6837  else
6838  {
6839  /*
6840  * Assign all-nulls.
6841  */
6842  exec_move_row_from_fields(estate, target, newerh,
6843  NULL, NULL, NULL);
6844  }
6845 }
PLpgSQL_type * datatype
Definition: plpgsql.h:387
static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
Definition: pl_exec.c:8401
void expanded_record_set_tuple(ExpandedRecordHeader *erh, HeapTuple tuple, bool copy, bool expand_external)
ExpandedRecordHeader * erh
Definition: plpgsql.h:395
static void exec_move_row_from_fields(PLpgSQL_execstate *estate, PLpgSQL_variable *target, ExpandedRecordHeader *newerh, Datum *values, bool *nulls, TupleDesc tupdesc)
Definition: pl_exec.c:6985
#define lengthof(array)
Definition: c.h:669
static ExpandedRecordHeader * make_expanded_record_for_rec(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, TupleDesc srctupdesc, ExpandedRecordHeader *srcerh)
Definition: pl_exec.c:6922
#define eval_mcontext_alloc(estate, sz)
Definition: pl_exec.c:122
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
uintptr_t Datum
Definition: postgres.h:367
static bool compatible_tupdescs(TupleDesc src_tupdesc, TupleDesc dst_tupdesc)
Definition: pl_exec.c:7251
void DeleteExpandedObject(Datum d)
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
PLpgSQL_datum_type dtype
Definition: plpgsql.h:270
char typtype
Definition: plpgsql.h:206
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1249
static Datum values[MAXATTR]
Definition: bootstrap.c:167
Oid tdtypeid
Definition: tupdesc.h:82
Oid rectypeid
Definition: plpgsql.h:388
#define ExpandedRecordGetDatum(erh)
void deconstruct_expanded_record(ExpandedRecordHeader *erh)

◆ exec_move_row_from_datum()

static void exec_move_row_from_datum ( PLpgSQL_execstate estate,
PLpgSQL_variable target,
Datum  value 
)
static

Definition at line 7381 of file pl_exec.c.

References Assert, assign_record_var(), PLpgSQL_execstate::atomic, DatumGetEOHP(), DatumGetHeapTupleHeader, DatumGetPointer, deconstruct_expanded_record(), ExpandedRecordHeader::dnulls, PLpgSQL_variable::dtype, ExpandedRecordHeader::dvalues, ExpandedRecordHeader::er_decltypeid, ER_FLAG_FVALUE_VALID, ER_MAGIC, ExpandedRecordHeader::er_magic, ExpandedRecordHeader::er_typeid, ExpandedRecordHeader::er_typmod, PLpgSQL_rec::erh, exec_move_row(), exec_move_row_from_fields(), expanded_record_get_tupdesc(), expanded_record_set_tuple(), ExpandedRecordIsDomain, ExpandedRecordIsEmpty, ExpandedRecordHeader::flags, ExpandedRecordHeader::fvalue, get_eval_mcontext, HeapTupleHeaderGetDatumLength, HeapTupleHeaderGetTypeId, HeapTupleHeaderGetTypMod, InvalidOid, ItemPointerSetInvalid, lookup_rowtype_tupdesc(), make_expanded_record_for_rec(), make_expanded_record_from_typeid(), MemoryContextSwitchTo(), PLPGSQL_DTYPE_REC, PLpgSQL_rec::rectypeid, ReleaseTupleDesc, revalidate_rectypeid(), HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, VARATT_IS_EXTERNAL_EXPANDED, and VARATT_IS_EXTERNAL_EXPANDED_RW.

Referenced by exec_assign_value(), and plpgsql_exec_function().

7384 {
7385  /* Check to see if source is an expanded record */
7387  {
7389  ExpandedRecordHeader *newerh = NULL;
7390 
7391  Assert(erh->er_magic == ER_MAGIC);
7392 
7393  /* These cases apply if the target is record not row... */
7394  if (target->dtype == PLPGSQL_DTYPE_REC)
7395  {
7396  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7397 
7398  /*
7399  * If it's the same record already stored in the variable, do
7400  * nothing. This would happen only in silly cases like "r := r",
7401  * but we need some check to avoid possibly freeing the variable's
7402  * live value below. Note that this applies even if what we have
7403  * is a R/O pointer.
7404  */
7405  if (erh == rec->erh)
7406  return;
7407 
7408  /*
7409  * Make sure rec->rectypeid is up-to-date before using it.
7410  */
7411  revalidate_rectypeid(rec);
7412 
7413  /*
7414  * If we have a R/W pointer, we're allowed to just commandeer
7415  * ownership of the expanded record. If it's of the right type to
7416  * put into the record variable, do that. (Note we don't accept
7417  * an expanded record of a composite-domain type as a RECORD
7418  * value. We'll treat it as the base composite type instead;
7419  * compare logic in make_expanded_record_for_rec.)
7420  */
7422  (rec->rectypeid == erh->er_decltypeid ||
7423  (rec->rectypeid == RECORDOID &&
7424  !ExpandedRecordIsDomain(erh))))
7425  {
7426  assign_record_var(estate, rec, erh);
7427  return;
7428  }
7429 
7430  /*
7431  * If we already have an expanded record object in the target
7432  * variable, and the source record contains a valid tuple
7433  * representation with the right rowtype, then we can skip making
7434  * a new expanded record and just assign the tuple with
7435  * expanded_record_set_tuple. (We can't do the equivalent if we
7436  * have to do field-by-field assignment, since that wouldn't be
7437  * atomic if there's an error.) We consider that there's a
7438  * rowtype match only if it's the same named composite type or
7439  * same registered rowtype; checking for matches of anonymous
7440  * rowtypes would be more expensive than this is worth.
7441  */
7442  if (rec->erh &&
7443  (erh->flags & ER_FLAG_FVALUE_VALID) &&
7444  erh->er_typeid == rec->erh->er_typeid &&
7445  (erh->er_typeid != RECORDOID ||
7446  (erh->er_typmod == rec->erh->er_typmod &&
7447  erh->er_typmod >= 0)))
7448  {
7450  true, !estate->atomic);
7451  return;
7452  }
7453 
7454  /*
7455  * Otherwise we're gonna need a new expanded record object. Make
7456  * it here in hopes of piggybacking on the source object's
7457  * previous typcache lookup.
7458  */
7459  newerh = make_expanded_record_for_rec(estate, rec, NULL, erh);
7460 
7461  /*
7462  * If the expanded record contains a valid tuple representation,
7463  * and we don't need rowtype conversion, then just copying the
7464  * tuple is probably faster than field-by-field processing. (This
7465  * isn't duplicative of the previous check, since here we will
7466  * catch the case where the record variable was previously empty.)
7467  */
7468  if ((erh->flags & ER_FLAG_FVALUE_VALID) &&
7469  (rec->rectypeid == RECORDOID ||
7470  rec->rectypeid == erh->er_typeid))
7471  {
7472  expanded_record_set_tuple(newerh, erh->fvalue,
7473  true, !estate->atomic);
7474  assign_record_var(estate, rec, newerh);
7475  return;
7476  }
7477 
7478  /*
7479  * Need to special-case empty source record, else code below would
7480  * leak newerh.
7481  */
7482  if (ExpandedRecordIsEmpty(erh))
7483  {
7484  /* Set newerh to a row of NULLs */
7486  assign_record_var(estate, rec, newerh);
7487  return;
7488  }
7489  } /* end of record-target-only cases */
7490 
7491  /*
7492  * If the source expanded record is empty, we should treat that like a
7493  * NULL tuple value. (We're unlikely to see such a case, but we must
7494  * check this; deconstruct_expanded_record would cause a change of
7495  * logical state, which is not OK.)
7496  */
7497  if (ExpandedRecordIsEmpty(erh))
7498  {
7499  exec_move_row(estate, target, NULL,
7501  return;
7502  }
7503 
7504  /*
7505  * Otherwise, ensure that the source record is deconstructed, and
7506  * assign from its field values.
7507  */
7509  exec_move_row_from_fields(estate, target, newerh,
7510  erh->dvalues, erh->dnulls,
7512  }
7513  else
7514  {
7515  /*
7516  * Nope, we've got a plain composite Datum. Deconstruct it; but we
7517  * don't use deconstruct_composite_datum(), because we may be able to
7518  * skip calling lookup_rowtype_tupdesc().
7519  */
7520  HeapTupleHeader td;
7521  HeapTupleData tmptup;
7522  Oid tupType;
7523  int32 tupTypmod;
7524  TupleDesc tupdesc;
7525  MemoryContext oldcontext;
7526 
7527  /* Ensure that any detoasted data winds up in the eval_mcontext */
7528  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7529  /* Get tuple body (note this could involve detoasting) */
7531  MemoryContextSwitchTo(oldcontext);
7532 
7533  /* Build a temporary HeapTuple control structure */
7534  tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
7535  ItemPointerSetInvalid(&(tmptup.t_self));
7536  tmptup.t_tableOid = InvalidOid;
7537  tmptup.t_data = td;
7538 
7539  /* Extract rowtype info */
7540  tupType = HeapTupleHeaderGetTypeId(td);
7541  tupTypmod = HeapTupleHeaderGetTypMod(td);
7542 
7543  /* Now, if the target is record not row, maybe we can optimize ... */
7544  if (target->dtype == PLPGSQL_DTYPE_REC)
7545  {
7546  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7547 
7548  /*
7549  * If we already have an expanded record object in the target
7550  * variable, and the source datum has a matching rowtype, then we
7551  * can skip making a new expanded record and just assign the tuple
7552  * with expanded_record_set_tuple. We consider that there's a
7553  * rowtype match only if it's the same named composite type or
7554  * same registered rowtype. (Checking to reject an anonymous
7555  * rowtype here should be redundant, but let's be safe.)
7556  */
7557  if (rec->erh &&
7558  tupType == rec->erh->er_typeid &&
7559  (tupType != RECORDOID ||
7560  (tupTypmod == rec->erh->er_typmod &&
7561  tupTypmod >= 0)))
7562  {
7563  expanded_record_set_tuple(rec->erh, &tmptup,
7564  true, !estate->atomic);
7565  return;
7566  }
7567 
7568  /*
7569  * If the source datum has a rowtype compatible with the target
7570  * variable, just build a new expanded record and assign the tuple
7571  * into it. Using make_expanded_record_from_typeid() here saves
7572  * one typcache lookup compared to the code below.
7573  */
7574  if (rec->rectypeid == RECORDOID || rec->rectypeid == tupType)
7575  {
7576  ExpandedRecordHeader *newerh;
7577  MemoryContext mcontext = get_eval_mcontext(estate);
7578 
7579  newerh = make_expanded_record_from_typeid(tupType, tupTypmod,
7580  mcontext);
7581  expanded_record_set_tuple(newerh, &tmptup,
7582  true, !estate->atomic);
7583  assign_record_var(estate, rec, newerh);
7584  return;
7585  }
7586 
7587  /*
7588  * Otherwise, we're going to need conversion, so fall through to
7589  * do it the hard way.
7590  */
7591  }
7592 
7593  /*
7594  * ROW target, or unoptimizable RECORD target, so we have to expend a
7595  * lookup to obtain the source datum's tupdesc.
7596  */
7597  tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
7598 
7599  /* Do the move */
7600  exec_move_row(estate, target, &tmptup, tupdesc);
7601 
7602  /* Release tupdesc usage count */
7603  ReleaseTupleDesc(tupdesc);
7604  }
7605 }
#define ER_FLAG_FVALUE_VALID
ExpandedRecordHeader * make_expanded_record_from_typeid(Oid type_id, int32 typmod, MemoryContext parentcontext)
#define ExpandedRecordIsEmpty(erh)
#define VARATT_IS_EXTERNAL_EXPANDED(PTR)
Definition: postgres.h:322
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1652
static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
Definition: pl_exec.c:8401
void expanded_record_set_tuple(ExpandedRecordHeader *erh, HeapTuple tuple, bool copy, bool expand_external)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static struct @145 value
ExpandedRecordHeader * erh
Definition: plpgsql.h:395
static void exec_move_row_from_fields(PLpgSQL_execstate *estate, PLpgSQL_variable *target, ExpandedRecordHeader *newerh, Datum *values, bool *nulls, TupleDesc tupdesc)
Definition: pl_exec.c:6985
unsigned int Oid
Definition: postgres_ext.h:31
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:289
signed int int32
Definition: c.h:347
HeapTupleHeader t_data
Definition: htup.h:68
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:468
static ExpandedRecordHeader * make_expanded_record_for_rec(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, TupleDesc srctupdesc, ExpandedRecordHeader *srcerh)
Definition: pl_exec.c:6922
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
Oid t_tableOid
Definition: htup.h:66
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29
#define get_eval_mcontext(estate)
Definition: pl_exec.c:120
#define ER_MAGIC
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:458
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:739
PLpgSQL_datum_type dtype
Definition: plpgsql.h:270
#define DatumGetPointer(X)
Definition: postgres.h:549
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
Definition: pl_exec.c:6716
static void revalidate_rectypeid(PLpgSQL_rec *rec)
Definition: pl_exec.c:6851
#define VARATT_IS_EXTERNAL_EXPANDED_RW(PTR)
Definition: postgres.h:320
Oid rectypeid
Definition: plpgsql.h:388
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:122
#define ExpandedRecordIsDomain(erh)
void deconstruct_expanded_record(ExpandedRecordHeader *erh)
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:452

◆ exec_move_row_from_fields()

static void exec_move_row_from_fields ( PLpgSQL_execstate estate,
PLpgSQL_variable target,
ExpandedRecordHeader newerh,
Datum values,
bool nulls,
TupleDesc  tupdesc 
)
static

Definition at line 6985 of file pl_exec.c.

References Assert, assign_record_var(), PLpgSQL_execstate::atomic, PLpgSQL_execstate::datums, PLpgSQL_variable::dtype, elog, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, eval_mcontext_alloc, exec_assign_value(), exec_cast_value(), expanded_record_get_tupdesc(), expanded_record_set_fields(), lengthof, TupleDescData::natts, PLpgSQL_row::nfields, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_ROW, plpgsql_extra_errors, plpgsql_extra_warnings, PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT, TupleDescAttr, value, PLpgSQL_row::varnos, and WARNING.

Referenced by exec_move_row(), and exec_move_row_from_datum().

6990 {
6991  int td_natts = tupdesc ? tupdesc->natts : 0;
6992  int fnum;
6993  int anum;
6994  int strict_multiassignment_level = 0;
6995 
6996  /*
6997  * The extra check strict strict_multi_assignment can be active, only when
6998  * input tupdesc is specified.
6999  */
7000  if (tupdesc != NULL)
7001  {
7003  strict_multiassignment_level = ERROR;
7004  else if (plpgsql_extra_warnings & PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT)
7005  strict_multiassignment_level = WARNING;
7006  }
7007 
7008  /* Handle RECORD-target case */
7009  if (target->dtype == PLPGSQL_DTYPE_REC)
7010  {
7011  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7012  TupleDesc var_tupdesc;
7013  Datum newvalues_local[64];
7014  bool newnulls_local[64];
7015 
7016  Assert(newerh != NULL); /* caller must have built new object */
7017 
7018  var_tupdesc = expanded_record_get_tupdesc(newerh);
7019 
7020  /*
7021  * Coerce field values if needed. This might involve dealing with
7022  * different sets of dropped columns and/or coercing individual column
7023  * types. That's sort of a pain, but historically plpgsql has allowed
7024  * it, so we preserve the behavior. However, it's worth a quick check
7025  * to see if the tupdescs are identical. (Since expandedrecord.c
7026  * prefers to use refcounted tupdescs from the typcache, expanded
7027  * records with the same rowtype will have pointer-equal tupdescs.)
7028  */
7029  if (var_tupdesc != tupdesc)
7030  {
7031  int vtd_natts = var_tupdesc->natts;
7032  Datum *newvalues;
7033  bool *newnulls;
7034 
7035  /*
7036  * Need workspace arrays. If vtd_natts is small enough, use local
7037  * arrays to save doing a palloc. Even if it's not small, we can
7038  * allocate both the Datum and isnull arrays in one palloc chunk.
7039  */
7040  if (vtd_natts <= lengthof(newvalues_local))
7041  {
7042  newvalues = newvalues_local;
7043  newnulls = newnulls_local;
7044  }
7045  else
7046  {
7047  char *chunk;
7048 
7049  chunk = eval_mcontext_alloc(estate,
7050  vtd_natts * (sizeof(Datum) + sizeof(bool)));
7051  newvalues = (Datum *) chunk;
7052  newnulls = (bool *) (chunk + vtd_natts * sizeof(Datum));
7053  }
7054 
7055  /* Walk over destination columns */
7056  anum = 0;
7057  for (fnum = 0; fnum < vtd_natts; fnum++)
7058  {
7059  Form_pg_attribute attr = TupleDescAttr(var_tupdesc, fnum);
7060  Datum value;
7061  bool isnull;
7062  Oid valtype;
7063  int32 valtypmod;
7064 
7065  if (attr->attisdropped)
7066  {
7067  /* expanded_record_set_fields should ignore this column */
7068  continue; /* skip dropped column in record */
7069  }
7070 
7071  while (anum < td_natts &&
7072  TupleDescAttr(tupdesc, anum)->attisdropped)
7073  anum++; /* skip dropped column in tuple */
7074 
7075  if (anum < td_natts)
7076  {
7077  value = values[anum];
7078  isnull = nulls[anum];
7079  valtype = TupleDescAttr(tupdesc, anum)->atttypid;
7080  valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
7081  anum++;
7082  }
7083  else
7084  {
7085  /* no source for destination column */
7086  value = (Datum) 0;
7087  isnull = true;
7088  valtype = UNKNOWNOID;
7089  valtypmod = -1;
7090 
7091  /* When source value is missing */
7092  if (strict_multiassignment_level)
7093  ereport(strict_multiassignment_level,
7094  (errcode(ERRCODE_DATATYPE_MISMATCH),
7095  errmsg("number of source and target fields in assignment does not match"),
7096  /* translator: %s represents a name of an extra check */
7097  errdetail("%s check of %s is active.",
7098  "strict_multi_assignment",
7099  strict_multiassignment_level == ERROR ? "extra_errors" :
7100  "extra_warnings"),
7101  errhint("Make sure the query returns the exact list of columns.")));
7102  }
7103 
7104  /* Cast the new value to the right type, if needed. */
7105  newvalues[fnum] = exec_cast_value(estate,
7106  value,
7107  &isnull,
7108  valtype,
7109  valtypmod,
7110  attr->atttypid,
7111  attr->atttypmod);
7112  newnulls[fnum] = isnull;
7113  }
7114 
7115  /*
7116  * When strict_multiassignment extra check is active, then ensure
7117  * there are no unassigned source attributes.
7118  */
7119  if (strict_multiassignment_level && anum < td_natts)
7120  {
7121  /* skip dropped columns in the source descriptor */
7122  while (anum < td_natts &&
7123  TupleDescAttr(tupdesc, anum)->attisdropped)
7124  anum++;
7125 
7126  if (anum < td_natts)
7127  ereport(strict_multiassignment_level,
7128  (errcode(ERRCODE_DATATYPE_MISMATCH),
7129  errmsg("number of source and target fields in assignment does not match"),
7130  /* translator: %s represents a name of an extra check */
7131  errdetail("%s check of %s is active.",
7132  "strict_multi_assignment",
7133  strict_multiassignment_level == ERROR ? "extra_errors" :
7134  "extra_warnings"),
7135  errhint("Make sure the query returns the exact list of columns.")));
7136  }
7137 
7138  values = newvalues;
7139  nulls = newnulls;
7140  }
7141 
7142  /* Insert the coerced field values into the new expanded record */
7143  expanded_record_set_fields(newerh, values, nulls, !estate->atomic);
7144 
7145  /* Complete the assignment */
7146  assign_record_var(estate, rec, newerh);
7147 
7148  return;
7149  }
7150 
7151  /* newerh should not have been passed in non-RECORD cases */
7152  Assert(newerh == NULL);
7153 
7154  /*
7155  * For a row, we assign the individual field values to the variables the
7156  * row points to.
7157  *
7158  * NOTE: both this code and the record code above silently ignore extra
7159  * columns in the source and assume NULL for missing columns. This is
7160  * pretty dubious but it's the historical behavior.
7161  *
7162  * If we have no input data at all, we'll assign NULL to all columns of
7163  * the row variable.
7164  */
7165  if (target->dtype == PLPGSQL_DTYPE_ROW)
7166  {
7167  PLpgSQL_row *row = (PLpgSQL_row *) target;
7168 
7169  anum = 0;
7170  for (fnum = 0; fnum < row->nfields; fnum++)
7171  {
7172  PLpgSQL_var *var;
7173  Datum value;
7174  bool isnull;
7175  Oid valtype;
7176  int32 valtypmod;
7177 
7178  var = (PLpgSQL_var *) (estate->datums[row->varnos[fnum]]);
7179 
7180  while (anum < td_natts &&
7181  TupleDescAttr(tupdesc, anum)->attisdropped)
7182  anum++; /* skip dropped column in tuple */
7183 
7184  if (anum < td_natts)
7185  {
7186  value = values[anum];
7187  isnull = nulls[anum];
7188  valtype = TupleDescAttr(tupdesc, anum)->atttypid;
7189  valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
7190  anum++;
7191  }
7192  else
7193  {
7194  /* no source for destination column */
7195  value = (Datum) 0;
7196  isnull = true;
7197  valtype = UNKNOWNOID;
7198  valtypmod = -1;
7199 
7200  if (strict_multiassignment_level)
7201  ereport(strict_multiassignment_level,
7202  (errcode(ERRCODE_DATATYPE_MISMATCH),
7203  errmsg("number of source and target fields in assignment does not match"),
7204  /* translator: %s represents a name of an extra check */
7205  errdetail("%s check of %s is active.",
7206  "strict_multi_assignment",
7207  strict_multiassignment_level == ERROR ? "extra_errors" :
7208  "extra_warnings"),
7209  errhint("Make sure the query returns the exact list of columns.")));
7210  }
7211 
7212  exec_assign_value(estate, (PLpgSQL_datum *) var,
7213  value, isnull, valtype, valtypmod);
7214  }
7215 
7216  /*
7217  * When strict_multiassignment extra check is active, ensure there are
7218  * no unassigned source attributes.
7219  */
7220  if (strict_multiassignment_level && anum < td_natts)
7221  {
7222  while (anum < td_natts &&
7223  TupleDescAttr(tupdesc, anum)->attisdropped)
7224  anum++; /* skip dropped column in tuple */
7225 
7226  if (anum < td_natts)
7227  ereport(strict_multiassignment_level,
7228  (errcode(ERRCODE_DATATYPE_MISMATCH),
7229  errmsg("number of source and target fields in assignment does not match"),
7230  /* translator: %s represents a name of an extra check */
7231  errdetail("%s check of %s is active.",
7232  "strict_multi_assignment",
7233  strict_multiassignment_level == ERROR ? "extra_errors" :
7234  "extra_warnings"),
7235  errhint("Make sure the query returns the exact list of columns.")));
7236  }
7237 
7238  return;
7239  }
7240 
7241  elog(ERROR, "unsupported target type: %d", target->dtype);
7242 }
int errhint(const char *fmt,...)
Definition: elog.c:1069
static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
Definition: pl_exec.c:8401
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT
Definition: plpgsql.h:1198
static struct @145 value
int plpgsql_extra_errors
Definition: pl_handler.c:53
int errcode(int sqlerrcode)
Definition: elog.c:608
void expanded_record_set_fields(ExpandedRecordHeader *erh, const Datum *newValues, const bool *isnulls, bool expand_external)
#define lengthof(array)
Definition: c.h:669
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:347
PLpgSQL_datum ** datums
Definition: plpgsql.h:1072
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7678
#define ERROR
Definition: elog.h:43
#define eval_mcontext_alloc(estate, sz)
Definition: pl_exec.c:122
int plpgsql_extra_warnings
Definition: pl_handler.c:52
int errdetail(const char *fmt,...)
Definition: elog.c:955
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define ereport(elevel, rest)
Definition: elog.h:141
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
int * varnos
Definition: plpgsql.h:364
#define WARNING
Definition: elog.h:40
uintptr_t Datum
Definition: postgres.h:367
#define Assert(condition)
Definition: c.h:739
int nfields
Definition: plpgsql.h:362
PLpgSQL_datum_type dtype
Definition: plpgsql.h:270
static Datum values[MAXATTR]
Definition: bootstrap.c:167
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:4954

◆ exec_prepare_plan()

static void exec_prepare_plan ( PLpgSQL_execstate estate,
PLpgSQL_expr expr,
int  cursorOptions,
bool  keepplan 
)
static

Definition at line 4038 of file pl_exec.c.

References elog, ERROR, exec_simple_check_plan(), PLpgSQL_expr::func, PLpgSQL_execstate::func, plpgsql_parser_setup(), PLpgSQL_expr::query, SPI_keepplan(), SPI_prepare_params(), SPI_result, and SPI_result_code_string().

Referenced by exec_assign_expr(), exec_eval_expr(), exec_run_select(), exec_stmt_call(), exec_stmt_execsql(), exec_stmt_forc(), exec_stmt_open(), and exec_stmt_set().

4041 {
4042  SPIPlanPtr plan;
4043 
4044  /*
4045  * The grammar can't conveniently set expr->func while building the parse
4046  * tree, so make sure it's set before parser hooks need it.
4047  */
4048  expr->func = estate->func;
4049 
4050  /*
4051  * Generate and save the plan
4052  */
4053  plan = SPI_prepare_params(expr->query,
4055  (void *) expr,
4056  cursorOptions);
4057  if (plan == NULL)
4058  elog(ERROR, "SPI_prepare_params failed for \"%s\": %s",
4060  if (keepplan)
4061  SPI_keepplan(plan);
4062  expr->plan = plan;
4063 
4064  /* Check to see if it's a simple expression */
4065  exec_simple_check_plan(estate, expr);
4066 
4067  /*
4068  * Mark expression as not using a read-write param. exec_assign_value has
4069  * to take steps to override this if appropriate; that seems cleaner than
4070  * adding parameters to all other callers.
4071  */
4072  expr->rwparam = -1;
4073 }
char * query
Definition: plpgsql.h:221
PLpgSQL_function * func
Definition: plpgsql.h:1037
static void exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:7890
SPIPlanPtr plan
Definition: plpgsql.h:222
int SPI_result
Definition: spi.c:47
#define ERROR
Definition: elog.h:43
const char * SPI_result_code_string(int code)
Definition: spi.c:1705
void(* ParserSetupHook)(struct ParseState *pstate, void *arg)
Definition: params.h:108
void plpgsql_parser_setup(struct ParseState *pstate, PLpgSQL_expr *expr)
Definition: pl_comp.c:1072
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:752
int rwparam
Definition: plpgsql.h:224
struct PLpgSQL_function * func
Definition: plpgsql.h:227
#define elog(elevel,...)
Definition: elog.h:228
SPIPlanPtr SPI_prepare_params(const char *src, ParserSetupHook parserSetup, void *parserSetupArg, int cursorOptions)
Definition: spi.c:715

◆ exec_run_select()

static int exec_run_select ( PLpgSQL_execstate estate,
PLpgSQL_expr expr,
long  maxtuples,
Portal portalP 
)
static

Definition at line 5833 of file pl_exec.c.

References Assert, CURSOR_OPT_PARALLEL_OK, elog, ereport, errcode(), errmsg(), ERROR, PLpgSQL_execstate::eval_processed, PLpgSQL_execstate::eval_tuptable, exec_eval_cleanup(), exec_prepare_plan(), PLpgSQL_expr::plan, PLpgSQL_expr::query, PLpgSQL_execstate::readonly_func, setup_param_list(), SPI_cursor_open_with_paramlist(), SPI_execute_plan_with_paramlist(), SPI_OK_CURSOR, SPI_OK_SELECT, SPI_processed, SPI_result, SPI_result_code_string(), and SPI_tuptable.

Referenced by exec_eval_expr(), exec_stmt_fors(), exec_stmt_perform(), and exec_stmt_return_query().

5835 {
5836  ParamListInfo paramLI;
5837  int rc;
5838 
5839  /*
5840  * On the first call for this expression generate the plan.
5841  *
5842  * If we don't need to return a portal, then we're just going to execute
5843  * the query once, which means it's OK to use a parallel plan, even if the
5844  * number of rows being fetched is limited. If we do need to return a
5845  * portal, the caller might do cursor operations, which parallel query
5846  * can't support.
5847  */
5848  if (expr->plan == NULL)
5849  exec_prepare_plan(estate, expr,
5850  portalP == NULL ? CURSOR_OPT_PARALLEL_OK : 0, true);
5851 
5852  /*
5853  * Set up ParamListInfo to pass to executor
5854  */
5855  paramLI = setup_param_list(estate, expr);
5856 
5857  /*
5858  * If a portal was requested, put the query and paramlist into the portal
5859  */
5860  if (portalP != NULL)
5861  {
5862  *portalP = SPI_cursor_open_with_paramlist(NULL, expr->plan,
5863  paramLI,
5864  estate->readonly_func);
5865  if (*portalP == NULL)
5866  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
5868  exec_eval_cleanup(estate);
5869  return SPI_OK_CURSOR;
5870  }
5871 
5872  /*
5873  * Execute the query
5874  */
5875  rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
5876  estate->readonly_func, maxtuples);
5877  if (rc != SPI_OK_SELECT)
5878  ereport(ERROR,
5879  (errcode(ERRCODE_SYNTAX_ERROR),
5880  errmsg("query \"%s\" is not a SELECT", expr->query)));
5881 
5882  /* Save query results for eventual cleanup */
5883  Assert(estate->eval_tuptable == NULL);
5884  estate->eval_tuptable = SPI_tuptable;
5885  estate->eval_processed = SPI_processed;
5886 
5887  return rc;
5888 }
char * query
Definition: plpgsql.h:221
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions, bool keepplan)
Definition: pl_exec.c:4038
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1096
uint64 eval_processed
Definition: plpgsql.h:1097
Portal SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan, ParamListInfo params, bool read_only)
Definition: spi.c:1300
SPITupleTable * SPI_tuptable
Definition: spi.c:46
int errcode(int sqlerrcode)
Definition: elog.c:608
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4017
#define SPI_OK_CURSOR
Definition: spi.h:62
uint64 SPI_processed
Definition: spi.c:45
SPIPlanPtr plan
Definition: plpgsql.h:222
int SPI_result
Definition: spi.c:47
#define ERROR
Definition: elog.h:43
int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params, bool read_only, long tcount)
Definition: spi.c:565
const char * SPI_result_code_string(int code)
Definition: spi.c:1705
static ParamListInfo setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:6223
#define ereport(elevel, rest)
Definition: elog.h:141
#define SPI_OK_SELECT
Definition: spi.h:57
#define Assert(condition)
Definition: c.h:739
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2692
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228

◆ exec_save_simple_expr()

static void exec_save_simple_expr ( PLpgSQL_expr expr,
CachedPlan cplan 
)
static

Definition at line 7989 of file pl_exec.c.

References Assert, castNode, CMD_SELECT, PlannedStmt::commandType, contain_mutable_functions(), elog, ERROR, PLpgSQL_expr::expr_simple_expr, PLpgSQL_expr::expr_simple_generation, PLpgSQL_expr::expr_simple_in_use, PLpgSQL_expr::expr_simple_lxid, PLpgSQL_expr::expr_simple_mutable, PLpgSQL_expr::expr_simple_state, PLpgSQL_expr::expr_simple_type, PLpgSQL_expr::expr_simple_typmod, exprType(), exprTypmod(), CachedPlan::generation, Plan::initPlan, InvalidLocalTransactionId, IsA, Plan::lefttree, linitial, linitial_node, list_length(), nodeTag, OUTER_VAR, PlannedStmt::planTree, Plan::qual, Plan::righttree, CachedPlan::stmt_list, and Plan::targetlist.

Referenced by exec_eval_simple_expr(), and exec_simple_check_plan().

7990 {
7991  PlannedStmt *stmt;
7992  Plan *plan;
7993  Expr *tle_expr;
7994 
7995  /*
7996  * Given the checks that exec_simple_check_plan did, none of the Asserts
7997  * here should ever fail.
7998  */
7999 
8000  /* Extract the single PlannedStmt */
8001  Assert(list_length(cplan->stmt_list) == 1);
8002  stmt = linitial_node(PlannedStmt, cplan->stmt_list);
8003  Assert(stmt->commandType == CMD_SELECT);
8004 
8005  /*
8006  * Ordinarily, the plan node should be a simple Result. However, if
8007  * force_parallel_mode is on, the planner might've stuck a Gather node
8008  * atop that. The simplest way to deal with this is to look through the
8009  * Gather node. The Gather node's tlist would normally contain a Var
8010  * referencing the child node's output, but it could also be a Param, or
8011  * it could be a Const that setrefs.c copied as-is.
8012  */
8013  plan = stmt->planTree;
8014  for (;;)
8015  {
8016  /* Extract the single tlist expression */
8017  Assert(list_length(plan->targetlist) == 1);
8018  tle_expr = castNode(TargetEntry, linitial(plan->targetlist))->expr;
8019 
8020  if (IsA(plan, Result))
8021  {
8022  Assert(plan->lefttree == NULL &&
8023  plan->righttree == NULL &&
8024  plan->initPlan == NULL &&
8025  plan->qual == NULL &&
8026  ((Result *) plan)->resconstantqual == NULL);
8027  break;
8028  }
8029  else if (IsA(plan, Gather))
8030  {
8031  Assert(plan->lefttree != NULL &&
8032  plan->righttree == NULL &&
8033  plan->initPlan == NULL &&
8034  plan->qual == NULL);
8035  /* If setrefs.c copied up a Const, no need to look further */
8036  if (IsA(tle_expr, Const))
8037  break;
8038  /* Otherwise, it had better be a Param or an outer Var */
8039  Assert(IsA(tle_expr, Param) ||(IsA(tle_expr, Var) &&
8040  ((Var *) tle_expr)->varno == OUTER_VAR));
8041  /* Descend to the child node */
8042  plan = plan->lefttree;
8043  }
8044  else
8045  elog(ERROR, "unexpected plan node type: %d",
8046  (int) nodeTag(plan));
8047  }
8048 
8049  /*
8050  * Save the simple expression, and initialize state to "not valid in
8051  * current transaction".
8052  */
8053  expr->expr_simple_expr = tle_expr;
8054  expr->expr_simple_generation = cplan->generation;
8055  expr->expr_simple_state = NULL;
8056  expr->expr_simple_in_use = false;
8058  /* Also stash away the expression result type */
8059  expr->expr_simple_type = exprType((Node *) tle_expr);
8060  expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
8061  /* We also want to remember if it is immutable or not */
8062  expr->expr_simple_mutable = contain_mutable_functions((Node *) tle_expr);
8063 }
int expr_simple_generation
Definition: plpgsql.h:234
List * qual
Definition: plannodes.h:141
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:275
Definition: nodes.h:525
Definition: primnodes.h:167
#define linitial_node(type, l)
Definition: pg_list.h:198
struct Plan * planTree
Definition: plannodes.h:64
struct Plan * righttree
Definition: plannodes.h:143
#define linitial(l)
Definition: pg_list.h:195
#define ERROR
Definition: elog.h:43
Expr * expr_simple_expr
Definition: plpgsql.h:233
ExprState * expr_simple_state
Definition: plpgsql.h:245
bool expr_simple_mutable
Definition: plpgsql.h:237
CmdType commandType
Definition: plannodes.h:46
LocalTransactionId expr_simple_lxid
Definition: plpgsql.h:247
#define Assert(condition)
Definition: c.h:739
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
int generation
Definition: plancache.h:154
static int list_length(const List *l)
Definition: pg_list.h:169
struct Plan * lefttree
Definition: plannodes.h:142
#define nodeTag(nodeptr)
Definition: nodes.h:530
List * targetlist
Definition: plannodes.h:140
int32 expr_simple_typmod
Definition: plpgsql.h:236
List * initPlan
Definition: plannodes.h:144
#define elog(elevel,...)
Definition: elog.h:228
#define InvalidLocalTransactionId
Definition: lock.h:68
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:645
List * stmt_list
Definition: plancache.h:146
bool expr_simple_in_use
Definition: plpgsql.h:246
#define OUTER_VAR
Definition: primnodes.h:158
Oid expr_simple_type
Definition: plpgsql.h:235

◆ exec_set_found()

static void exec_set_found ( PLpgSQL_execstate estate,
bool  state 
)
static

Definition at line 8177 of file pl_exec.c.

References assign_simple_var(), BoolGetDatum, PLpgSQL_execstate::datums, and PLpgSQL_execstate::found_varno.

Referenced by exec_for_query(), exec_stmt_execsql(), exec_stmt_fetch(), exec_stmt_foreach_a(), exec_stmt_fori(), exec_stmt_perform(), exec_stmt_return_query(), plpgsql_exec_function(), and plpgsql_exec_trigger().

8178 {
8179  PLpgSQL_var *var;
8180 
8181  var = (PLpgSQL_var *) (estate->datums[estate->found_varno]);
8182  assign_simple_var(estate, var, BoolGetDatum(state), false, false);
8183 }
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8325
PLpgSQL_datum ** datums
Definition: plpgsql.h:1072
#define BoolGetDatum(X)
Definition: postgres.h:402
Definition: regguts.h:298

◆ exec_simple_check_plan()

static void exec_simple_check_plan ( PLpgSQL_execstate estate,
PLpgSQL_expr expr 
)
static

Definition at line 7890 of file pl_exec.c.

References Assert, CMD_SELECT, Query::commandType, Query::cteList, Query::distinctClause, exec_save_simple_expr(), PLpgSQL_expr::expr_simple_expr, FromExpr::fromlist, get_eval_mcontext, Query::groupClause, Query::groupingSets, Query::hasAggs, Query::hasSubLinks, Query::hasTargetSRFs, Query::hasWindowFuncs, Query::havingQual, IsA, Query::jointree, Query::limitCount, Query::limitOffset, linitial, list_length(), MemoryContextSwitchTo(), NIL, PLpgSQL_expr::plan, FromExpr::quals, CachedPlanSource::query_list, ReleaseCachedPlan(), Query::rtable, Query::setOperations, Query::sortClause, SPI_plan_get_cached_plan(), SPI_plan_get_plan_sources(), Query::targetList, and Query::windowClause.

Referenced by exec_prepare_plan().

7891 {
7892  List *plansources;
7893  CachedPlanSource *plansource;
7894  Query *query;
7895  CachedPlan *cplan;
7896  MemoryContext oldcontext;
7897 
7898  /*
7899  * Initialize to "not simple".
7900  */
7901  expr->expr_simple_expr = NULL;
7902 
7903  /*
7904  * Check the analyzed-and-rewritten form of the query to see if we will be
7905  * able to treat it as a simple expression. Since this function is only
7906  * called immediately after creating the CachedPlanSource, we need not
7907  * worry about the query being stale.
7908  */
7909 
7910  /*
7911  * We can only test queries that resulted in exactly one CachedPlanSource
7912  */
7913  plansources = SPI_plan_get_plan_sources(expr->plan);
7914  if (list_length(plansources) != 1)
7915  return;
7916  plansource = (CachedPlanSource *) linitial(plansources);
7917 
7918  /*
7919  * 1. There must be one single querytree.
7920  */
7921  if (list_length(plansource->query_list) != 1)
7922  return;
7923  query = (Query *) linitial(plansource->query_list);
7924 
7925  /*
7926  * 2. It must be a plain SELECT query without any input tables
7927  */
7928  if (!IsA(query, Query))
7929  return;
7930  if (query->commandType != CMD_SELECT)
7931  return;
7932  if (query->rtable != NIL)
7933  return;
7934 
7935  /*
7936  * 3. Can't have any subplans, aggregates, qual clauses either. (These
7937  * tests should generally match what inline_function() checks before
7938  * inlining a SQL function; otherwise, inlining could change our
7939  * conclusion about whether an expression is simple, which we don't want.)
7940  */
7941  if (query->hasAggs ||
7942  query->hasWindowFuncs ||
7943  query->hasTargetSRFs ||
7944  query->hasSubLinks ||
7945  query->cteList ||
7946  query->jointree->fromlist ||
7947  query->jointree->quals ||
7948  query->groupClause ||
7949  query->groupingSets ||
7950  query->havingQual ||
7951  query->windowClause ||
7952  query->distinctClause ||
7953  query->sortClause ||
7954  query->limitOffset ||
7955  query->limitCount ||
7956  query->setOperations)
7957  return;
7958 
7959  /*
7960  * 4. The query must have a single attribute as result
7961  */
7962  if (list_length(query->targetList) != 1)
7963  return;
7964 
7965  /*
7966  * OK, we can treat it as a simple plan.
7967  *
7968  * Get the generic plan for the query. If replanning is needed, do that
7969  * work in the eval_mcontext.
7970  */
7971  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7972  cplan = SPI_plan_get_cached_plan(expr->plan);
7973  MemoryContextSwitchTo(oldcontext);
7974 
7975  /* Can't fail, because we checked for a single CachedPlanSource above */
7976  Assert(cplan != NULL);
7977 
7978  /* Share the remaining work with replan code path */
7979  exec_save_simple_expr(expr, cplan);
7980 
7981  /* Release our plan refcount */
7982  ReleaseCachedPlan(cplan, true);
7983 }
Node * limitOffset
Definition: parsenodes.h:160
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
List * sortClause
Definition: parsenodes.h:158
FromExpr * jointree
Definition: parsenodes.h:138
bool hasAggs
Definition: parsenodes.h:125
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
List * groupingSets
Definition: parsenodes.h:150
List * fromlist
Definition: primnodes.h:1496
Node * quals
Definition: primnodes.h:1497
static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
Definition: pl_exec.c:7989
SPIPlanPtr plan
Definition: plpgsql.h:222
List * windowClause
Definition: parsenodes.h:154
List * targetList
Definition: parsenodes.h:140
CachedPlan * SPI_plan_get_cached_plan(SPIPlanPtr plan)
Definition: spi.c:1798
#define linitial(l)
Definition: pg_list.h:195
List * rtable
Definition: parsenodes.h:137
List * distinctClause
Definition: parsenodes.h:156
Node * limitCount
Definition: parsenodes.h:161
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1259
Expr * expr_simple_expr
Definition: plpgsql.h:233
#define get_eval_mcontext(estate)
Definition: pl_exec.c:120
CmdType commandType
Definition: parsenodes.h:112
bool hasTargetSRFs
Definition: parsenodes.h:127
#define Assert(condition)
Definition: c.h:739
bool hasWindowFuncs
Definition: parsenodes.h:126
static int list_length(const List *l)
Definition: pg_list.h:169
List * cteList
Definition: parsenodes.h:135
Node * setOperations
Definition: parsenodes.h:165
List * groupClause
Definition: parsenodes.h:148
bool hasSubLinks
Definition: parsenodes.h:128
List * SPI_plan_get_plan_sources(SPIPlanPtr plan)
Definition: spi.c:1782
List * query_list
Definition: plancache.h:108
Node * havingQual
Definition: parsenodes.h:152
Definition: pg_list.h:50

◆ exec_stmt()

static int exec_stmt ( PLpgSQL_execstate estate,
PLpgSQL_stmt stmt 
)
static

Definition at line 1937 of file pl_exec.c.

References CHECK_FOR_INTERRUPTS, PLpgSQL_stmt::cmd_type, PLpgSQL_stmt_set::cmd_type, elog, PLpgSQL_execstate::err_stmt, ERROR, exec_stmt_assert(), exec_stmt_assign(), exec_stmt_block(), exec_stmt_call(), exec_stmt_case(), exec_stmt_close(), exec_stmt_commit(), exec_stmt_dynexecute(), exec_stmt_dynfors(), exec_stmt_execsql(), exec_stmt_exit(), exec_stmt_fetch(), exec_stmt_forc(), exec_stmt_foreach_a(), exec_stmt_fori(), exec_stmt_fors(), exec_stmt_getdiag(), exec_stmt_if(), exec_stmt_loop(), exec_stmt_open(), exec_stmt_perform(), exec_stmt_raise(), exec_stmt_return(), exec_stmt_return_next(), exec_stmt_return_query(), exec_stmt_rollback(), exec_stmt_set(), exec_stmt_while(), plpgsql_plugin_ptr, PLPGSQL_STMT_ASSERT, PLPGSQL_STMT_ASSIGN, PLPGSQL_STMT_BLOCK, PLPGSQL_STMT_CALL, PLPGSQL_STMT_CASE, PLPGSQL_STMT_CLOSE, PLPGSQL_STMT_COMMIT, PLPGSQL_STMT_DYNEXECUTE, PLPGSQL_STMT_DYNFORS, PLPGSQL_STMT_EXECSQL, PLPGSQL_STMT_EXIT, PLPGSQL_STMT_FETCH, PLPGSQL_STMT_FORC, PLPGSQL_STMT_FOREACH_A, PLPGSQL_STMT_FORI, PLPGSQL_STMT_FORS, PLPGSQL_STMT_GETDIAG, PLPGSQL_STMT_IF, PLPGSQL_STMT_LOOP, PLPGSQL_STMT_OPEN, PLPGSQL_STMT_PERFORM, PLPGSQL_STMT_RAISE, PLPGSQL_STMT_RETURN, PLPGSQL_STMT_RETURN_NEXT, PLPGSQL_STMT_RETURN_QUERY, PLPGSQL_STMT_ROLLBACK, PLPGSQL_STMT_SET, PLPGSQL_STMT_WHILE, PLpgSQL_plugin::stmt_beg, and PLpgSQL_plugin::stmt_end.

Referenced by exec_stmts(), plpgsql_exec_event_trigger(), plpgsql_exec_function(), and plpgsql_exec_trigger().

1938 {
1939  PLpgSQL_stmt *save_estmt;
1940  int rc = -1;
1941 
1942  save_estmt = estate->err_stmt;
1943  estate->err_stmt = stmt;
1944 
1945  /* Let the plugin know that we are about to execute this statement */
1946  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
1947  ((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt);
1948 
1950 
1951  switch (stmt->cmd_type)
1952  {
1953  case PLPGSQL_STMT_BLOCK:
1954  rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt);
1955  break;
1956 
1957  case PLPGSQL_STMT_ASSIGN:
1958  rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
1959  break;
1960 
1961  case PLPGSQL_STMT_PERFORM:
1962  rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt);
1963  break;
1964 
1965  case PLPGSQL_STMT_CALL:
1966  rc = exec_stmt_call(estate, (PLpgSQL_stmt_call *) stmt);
1967  break;
1968 
1969  case PLPGSQL_STMT_GETDIAG:
1970  rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt);
1971  break;
1972 
1973  case PLPGSQL_STMT_IF:
1974  rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);
1975  break;
1976 
1977  case PLPGSQL_STMT_CASE:
1978  rc = exec_stmt_case(estate, (PLpgSQL_stmt_case *) stmt);
1979  break;
1980 
1981  case PLPGSQL_STMT_LOOP:
1982  rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt);
1983  break;
1984 
1985  case PLPGSQL_STMT_WHILE:
1986  rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt);
1987  break;
1988 
1989  case PLPGSQL_STMT_FORI:
1990  rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt);
1991  break;
1992 
1993  case PLPGSQL_STMT_FORS:
1994  rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt);
1995  break;
1996 
1997  case PLPGSQL_STMT_FORC:
1998  rc = exec_stmt_forc(estate, (PLpgSQL_stmt_forc *) stmt);
1999  break;
2000 
2002  rc = exec_stmt_foreach_a(estate, (PLpgSQL_stmt_foreach_a *) stmt);
2003  break;
2004 
2005  case PLPGSQL_STMT_EXIT:
2006  rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt);
2007  break;
2008 
2009  case PLPGSQL_STMT_RETURN:
2010  rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt);
2011  break;
2012 
2014  rc = exec_stmt_return_next(estate, (PLpgSQL_stmt_return_next *) stmt);
2015  break;
2016 
2018  rc = exec_stmt_return_query(estate, (PLpgSQL_stmt_return_query *) stmt);
2019  break;
2020 
2021  case PLPGSQL_STMT_RAISE:
2022  rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt);
2023  break;
2024 
2025  case PLPGSQL_STMT_ASSERT:
2026  rc = exec_stmt_assert(estate, (PLpgSQL_stmt_assert *) stmt);
2027  break;
2028 
2029  case PLPGSQL_STMT_EXECSQL:
2030  rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt);
2031  break;
2032 
2034  rc = exec_stmt_dynexecute(estate, (PLpgSQL_stmt_dynexecute *) stmt);
2035  break;
2036 
2037  case PLPGSQL_STMT_DYNFORS:
2038  rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt);
2039  break;
2040 
2041  case PLPGSQL_STMT_OPEN:
2042  rc = exec_stmt_open(estate, (PLpgSQL_stmt_open *) stmt);
2043  break;
2044 
2045  case PLPGSQL_STMT_FETCH:
2046  rc = exec_stmt_fetch(estate, (PLpgSQL_stmt_fetch *) stmt);
2047  break;
2048 
2049  case PLPGSQL_STMT_CLOSE:
2050  rc = exec_stmt_close(estate, (PLpgSQL_stmt_close *) stmt);
2051  break;
2052 
2053  case PLPGSQL_STMT_COMMIT:
2054  rc = exec_stmt_commit(estate, (PLpgSQL_stmt_commit *) stmt);
2055  break;
2056 
2057  case PLPGSQL_STMT_ROLLBACK:
2058  rc = exec_stmt_rollback(estate, (PLpgSQL_stmt_rollback *) stmt);
2059  break;
2060 
2061  case PLPGSQL_STMT_SET:
2062  rc = exec_stmt_set(estate, (PLpgSQL_stmt_set *) stmt);
2063  break;
2064 
2065  default:
2066  estate->err_stmt = save_estmt;
2067  elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
2068  }
2069 
2070  /* Let the plugin know that we have finished executing this statement */
2071  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
2072  ((*plpgsql_plugin_ptr)->stmt_end) (estate, stmt);
2073 
2074  estate->err_stmt = save_estmt;
2075 
2076  return rc;
2077 }
static int exec_stmt_set(PLpgSQL_execstate *estate, PLpgSQL_stmt_set *stmt)
Definition: pl_exec.c:4864
static int exec_stmt_execsql(PLpgSQL_execstate *estate, PLpgSQL_stmt_execsql *stmt)
Definition: pl_exec.c:4084
static int exec_stmt_case(PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
Definition: pl_exec.c:2492
PLpgSQL_stmt * err_stmt
Definition: plpgsql.h:1101
static int exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
Definition: pl_exec.c:2117
static int exec_stmt_return_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_return_query *stmt)
Definition: pl_exec.c:3490
static int exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt)
Definition: pl_exec.c:2940
static int exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
Definition: pl_exec.c:4527
static int exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
Definition: pl_exec.c:4500
static int exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
Definition: pl_exec.c:2579
static int exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
Definition: pl_exec.c:2775
static int exec_stmt_assign(PLpgSQL_execstate *estate, PLpgSQL_stmt_assign *stmt)
Definition: pl_exec.c:2086
#define ERROR
Definition: elog.h:43
static int exec_stmt_rollback(PLpgSQL_execstate *estate, PLpgSQL_stmt_rollback *stmt)
Definition: pl_exec.c:4839
static int exec_stmt_assert(PLpgSQL_execstate *estate, PLpgSQL_stmt_assert *stmt)
Definition: pl_exec.c:3830
static int exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
Definition: pl_exec.c:3619
static int exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
Definition: pl_exec.c:2632
static int exec_stmt_dynexecute(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynexecute *stmt)
Definition: pl_exec.c:4310
PLpgSQL_plugin ** plpgsql_plugin_ptr
Definition: pl_handler.c:56
static int exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
Definition: pl_exec.c:2352
static int exec_stmt_exit(PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt)
Definition: pl_exec.c:3096
static int exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
Definition: pl_exec.c:3129
static int exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
Definition: pl_exec.c:2601
static int exec_stmt_commit(PLpgSQL_execstate *estate, PLpgSQL_stmt_commit *stmt)
Definition: pl_exec.c:4817
static int exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
Definition: pl_exec.c:4683
static int exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
Definition: pl_exec.c:1577
static int exec_stmt_return_next(PLpgSQL_execstate *estate, PLpgSQL_stmt_return_next *stmt)
Definition: pl_exec.c:3272
static int exec_stmt_close(PLpgSQL_execstate *estate, PLpgSQL_stmt_close *stmt)
Definition: pl_exec.c:4774
#define elog(elevel,...)
Definition: elog.h:228
static int exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
Definition: pl_exec.c:2462
static int exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
Definition: pl_exec.c:2102
PLpgSQL_stmt_type cmd_type
Definition: plpgsql.h:460
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
void(* stmt_end)(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
Definition: plpgsql.h:1144
void(* stmt_beg)(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
Definition: plpgsql.h:1143
static int exec_stmt_forc(PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt)
Definition: pl_exec.c:2804

◆ exec_stmt_assert()

static int exec_stmt_assert ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assert stmt 
)
static

Definition at line 3830 of file pl_exec.c.

References PLpgSQL_stmt_assert::cond, convert_value_to_string(), ereport, errcode(), errmsg(), errmsg_internal(), ERROR, exec_eval_boolean(), exec_eval_cleanup(), exec_eval_expr(), PLpgSQL_stmt_assert::message, plpgsql_check_asserts, PLPGSQL_RC_OK, val, and value.

Referenced by exec_stmt().

3831 {
3832  bool value;
3833  bool isnull;
3834 
3835  /* do nothing when asserts are not enabled */
3836  if (!plpgsql_check_asserts)
3837  return PLPGSQL_RC_OK;
3838 
3839  value = exec_eval_boolean(estate, stmt->cond, &isnull);
3840  exec_eval_cleanup(estate);
3841 
3842  if (isnull || !value)
3843  {
3844  char *message = NULL;
3845 
3846  if (stmt->message != NULL)
3847  {
3848  Datum val;
3849  Oid typeid;
3850  int32 typmod;
3851 
3852  val = exec_eval_expr(estate, stmt->message,
3853  &isnull, &typeid, &typmod);
3854  if (!isnull)
3855  message = convert_value_to_string(estate, val, typeid);
3856  /* we mustn't do exec_eval_cleanup here */
3857  }
3858 
3859  ereport(ERROR,
3860  (errcode(ERRCODE_ASSERT_FAILURE),
3861  message ? errmsg_internal("%s", message) :
3862  errmsg("assertion failed")));
3863  }
3864 
3865  return PLPGSQL_RC_OK;
3866 }
static struct @145 value
int errcode(int sqlerrcode)
Definition: elog.c:608
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4017
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:347
#define ERROR
Definition: elog.h:43
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5750
PLpgSQL_expr * message
Definition: plpgsql.h:901
static bool exec_eval_boolean(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
Definition: pl_exec.c:5727
#define ereport(elevel, rest)
Definition: elog.h:141
uintptr_t Datum
Definition: postgres.h:367
int errmsg_internal(const char *fmt,...)
Definition: elog.c:909
int errmsg(const char *fmt,...)
Definition: elog.c:822
static char * convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
Definition: pl_exec.c:7649
PLpgSQL_expr * cond
Definition: plpgsql.h:900
bool plpgsql_check_asserts
Definition: pl_handler.c:48
long val
Definition: informix.c:664

◆ exec_stmt_assign()

static int exec_stmt_assign ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assign stmt 
)
static

Definition at line 2086 of file pl_exec.c.

References Assert, PLpgSQL_execstate::datums, exec_assign_expr(), PLpgSQL_stmt_assign::expr, PLPGSQL_RC_OK, and PLpgSQL_stmt_assign::varno.

Referenced by exec_stmt().

2087 {
2088  Assert(stmt->varno >= 0);
2089 
2090  exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);
2091 
2092  return PLPGSQL_RC_OK;
2093 }
PLpgSQL_datum ** datums
Definition: plpgsql.h:1072
static void exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
Definition: pl_exec.c:4889
#define Assert(condition)
Definition: c.h:739
PLpgSQL_expr * expr
Definition: plpgsql.h:525

◆ exec_stmt_block()

static int exec_stmt_block ( PLpgSQL_execstate estate,
PLpgSQL_stmt_block block 
)
static

Definition at line 1577 of file pl_exec.c.

References PLpgSQL_exception::action, Assert, assign_simple_var(), assign_text_var(), BeginInternalSubTransaction(), PLpgSQL_stmt_block::body, PLpgSQL_exception::conditions, CopyErrorData(), PLpgSQL_execstate::cur_error, CurrentMemoryContext, CurrentResourceOwner, PLpgSQL_var::datatype, PLpgSQL_execstate::datums, datumTransfer(), PLpgSQL_var::default_val, PLpgSQL_rec::default_val, PLpgSQL_datum::dtype, elog, PLpgSQL_execstate::err_text, ERROR, PLpgSQL_execstate::eval_econtext, PLpgSQL_execstate::eval_tuptable, PLpgSQL_exception_block::exc_list, exception_matches_conditions(), PLpgSQL_stmt_block::exceptions, exec_assign_expr(), exec_assign_value(), exec_eval_cleanup(), exec_move_row(), exec_stmts(), PLpgSQL_execstate::exitlabel, FlushErrorState(), get_stmt_mcontext(), get_typlenbyval(), gettext_noop, i, PLpgSQL_stmt_block::initvarnos, PLpgSQL_stmt_block::label, lfirst, MemoryContextDeleteChildren(), MemoryContextReset(), MemoryContextSwitchTo(), ErrorData::message, PLpgSQL_stmt_block::n_initvars, PLpgSQL_variable::notnull, PG_CATCH, PG_END_TRY, PG_TRY, plpgsql_create_econtext(), PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_VAR, PLPGSQL_RC_CONTINUE, PLPGSQL_RC_EXIT, PLPGSQL_RC_OK, PLPGSQL_RC_RETURN, pop_stmt_mcontext(), ReleaseCurrentSubTransaction(), ReThrowError(), PLpgSQL_execstate::retisnull, PLpgSQL_execstate::retisset, PLpgSQL_execstate::rettype, PLpgSQL_execstate::retval, RollbackAndReleaseCurrentSubTransaction(), ErrorData::sqlerrcode, PLpgSQL_exception_block::sqlerrm_varno, PLpgSQL_exception_block::sqlstate_varno, PLpgSQL_execstate::stmt_mcontext, PLpgSQL_execstate::stmt_mcontext_parent, PLpgSQL_type::typtype, and unpack_sql_state().

Referenced by exec_stmt().

1578 {
1579  volatile int rc = -1;
1580  int i;
1581 
1582  /*
1583  * First initialize all variables declared in this block
1584  */
1585  estate->err_text = gettext_noop("during statement block local variable initialization");
1586 
1587  for (i = 0; i < block->n_initvars; i++)
1588  {
1589  int n = block->initvarnos[i];
1590  PLpgSQL_datum *datum = estate->datums[n];
1591 
1592  /*
1593  * The set of dtypes handled here must match plpgsql_add_initdatums().
1594  *
1595  * Note that we currently don't support promise datums within blocks,
1596  * only at a function's outermost scope, so we needn't handle those
1597  * here.
1598  */
1599  switch (datum->dtype)
1600  {
1601  case PLPGSQL_DTYPE_VAR:
1602  {
1603  PLpgSQL_var *var = (PLpgSQL_var *) datum;
1604 
1605  /*
1606  * Free any old value, in case re-entering block, and
1607  * initialize to NULL
1608  */
1609  assign_simple_var(estate, var, (Datum) 0, true, false);
1610 
1611  if (var->default_val == NULL)
1612  {
1613  /*
1614  * If needed, give the datatype a chance to reject
1615  * NULLs, by assigning a NULL to the variable. We
1616  * claim the value is of type UNKNOWN, not the var's
1617  * datatype, else coercion will be skipped.
1618  */
1619  if (var->datatype->typtype == TYPTYPE_DOMAIN)
1620  exec_assign_value(estate,
1621  (PLpgSQL_datum *) var,
1622  (Datum) 0,
1623  true,
1624  UNKNOWNOID,
1625  -1);
1626 
1627  /* parser should have rejected NOT NULL */
1628  Assert(!var->notnull);
1629  }
1630  else
1631  {
1632  exec_assign_expr(estate, (PLpgSQL_datum *) var,
1633  var->default_val);
1634  }
1635  }
1636  break;
1637 
1638  case PLPGSQL_DTYPE_REC:
1639  {
1640  PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
1641 
1642  /*
1643  * Deletion of any existing object will be handled during
1644  * the assignments below, and in some cases it's more
1645  * efficient for us not to get rid of it beforehand.
1646  */
1647  if (rec->default_val == NULL)
1648  {
1649  /*
1650  * If needed, give the datatype a chance to reject
1651  * NULLs, by assigning a NULL to the variable.
1652  */
1653  exec_move_row(estate, (PLpgSQL_variable *) rec,
1654  NULL, NULL);
1655 
1656  /* parser should have rejected NOT NULL */
1657  Assert(!rec->notnull);
1658  }
1659  else
1660  {
1661  exec_assign_expr(estate, (PLpgSQL_datum *) rec,
1662  rec->default_val);
1663  }
1664  }
1665  break;
1666 
1667  default:
1668  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
1669  }
1670  }
1671 
1672  if (block->exceptions)
1673  {
1674  /*
1675  * Execute the statements in the block's body inside a sub-transaction
1676  */
1677  MemoryContext oldcontext = CurrentMemoryContext;
1679  ExprContext *old_eval_econtext = estate->eval_econtext;
1680  ErrorData *save_cur_error = estate->cur_error;
1681  MemoryContext stmt_mcontext;
1682 
1683  estate->err_text = gettext_noop("during statement block entry");
1684 
1685  /*
1686  * We will need a stmt_mcontext to hold the error data if an error
1687  * occurs. It seems best to force it to exist before entering the
1688  * subtransaction, so that we reduce the risk of out-of-memory during
1689  * error recovery, and because this greatly simplifies restoring the
1690  * stmt_mcontext stack to the correct state after an error. We can
1691  * ameliorate the cost of this by allowing the called statements to
1692  * use this mcontext too; so we don't push it down here.
1693  */
1694  stmt_mcontext = get_stmt_mcontext(estate);
1695 
1697  /* Want to run statements inside function's memory context */
1698  MemoryContextSwitchTo(oldcontext);
1699 
1700  PG_TRY();
1701  {
1702  /*
1703  * We need to run the block's statements with a new eval_econtext
1704  * that belongs to the current subtransaction; if we try to use
1705  * the outer econtext then ExprContext shutdown callbacks will be
1706  * called at the wrong times.
1707  */
1708  plpgsql_create_econtext(estate);
1709 
1710  estate->err_text = NULL;
1711 
1712  /* Run the block's statements */
1713  rc = exec_stmts(estate, block->body);
1714 
1715  estate->err_text = gettext_noop("during statement block exit");
1716 
1717  /*
1718  * If the block ended with RETURN, we may need to copy the return
1719  * value out of the subtransaction eval_context. We can avoid a
1720  * physical copy if the value happens to be a R/W expanded object.
1721  */
1722  if (rc == PLPGSQL_RC_RETURN &&
1723  !estate->retisset &&
1724  !estate->retisnull)
1725  {
1726  int16 resTypLen;
1727  bool resTypByVal;
1728 
1729  get_typlenbyval(estate->rettype, &resTypLen, &resTypByVal);
1730  estate->retval = datumTransfer(estate->retval,
1731  resTypByVal, resTypLen);
1732  }
1733 
1734  /* Commit the inner transaction, return to outer xact context */
1736  MemoryContextSwitchTo(oldcontext);
1737  CurrentResourceOwner = oldowner;
1738 
1739  /* Assert that the stmt_mcontext stack is unchanged */
1740  Assert(stmt_mcontext == estate->stmt_mcontext);
1741 
1742  /*
1743  * Revert to outer eval_econtext. (The inner one was
1744  * automatically cleaned up during subxact exit.)
1745  */
1746  estate->eval_econtext = old_eval_econtext;
1747  }
1748  PG_CATCH();
1749  {
1750  ErrorData *edata;
1751  ListCell *e;
1752 
1753  estate->err_text = gettext_noop("during exception cleanup");
1754 
1755  /* Save error info in our stmt_mcontext */
1756  MemoryContextSwitchTo(stmt_mcontext);
1757  edata = CopyErrorData();
1758  FlushErrorState();
1759 
1760  /* Abort the inner transaction */
1762  MemoryContextSwitchTo(oldcontext);
1763  CurrentResourceOwner = oldowner;
1764 
1765  /*
1766  * Set up the stmt_mcontext stack as though we had restored our
1767  * previous state and then done push_stmt_mcontext(). The push is
1768  * needed so that statements in the exception handler won't
1769  * clobber the error data that's in our stmt_mcontext.
1770  */
1771  estate->stmt_mcontext_parent = stmt_mcontext;
1772  estate->stmt_mcontext = NULL;
1773 
1774  /*
1775  * Now we can delete any nested stmt_mcontexts that might have
1776  * been created as children of ours. (Note: we do not immediately
1777  * release any statement-lifespan data that might have been left
1778  * behind in stmt_mcontext itself. We could attempt that by doing
1779  * a MemoryContextReset on it before collecting the error data
1780  * above, but it seems too risky to do any significant amount of
1781  * work before collecting the error.)
1782  */
1783  MemoryContextDeleteChildren(stmt_mcontext);
1784 
1785  /* Revert to outer eval_econtext */
1786  estate->eval_econtext = old_eval_econtext;
1787 
1788  /*
1789  * Must clean up the econtext too. However, any tuple table made
1790  * in the subxact will have been thrown away by SPI during subxact
1791  * abort, so we don't need to (and mustn't try to) free the
1792  * eval_tuptable.
1793  */
1794  estate->eval_tuptable = NULL;
1795  exec_eval_cleanup(estate);
1796 
1797  /* Look for a matching exception handler */
1798  foreach(e, block->exceptions->exc_list)
1799  {
1800  PLpgSQL_exception *exception = (PLpgSQL_exception *) lfirst(e);
1801 
1802  if (exception_matches_conditions(edata, exception->conditions))
1803  {
1804  /*
1805  * Initialize the magic SQLSTATE and SQLERRM variables for
1806  * the exception block; this also frees values from any
1807  * prior use of the same exception. We needn't do this
1808  * until we have found a matching exception.
1809  */
1810  PLpgSQL_var *state_var;
1811  PLpgSQL_var *errm_var;
1812 
1813  state_var = (PLpgSQL_var *)
1814  estate->datums[block->exceptions->sqlstate_varno];
1815  errm_var = (PLpgSQL_var *)
1816  estate->datums[block->exceptions->sqlerrm_varno];
1817 
1818  assign_text_var(estate, state_var,
1819  unpack_sql_state(edata->sqlerrcode));
1820  assign_text_var(estate, errm_var, edata->message);
1821 
1822  /*
1823  * Also set up cur_error so the error data is accessible
1824  * inside the handler.
1825  */
1826  estate->cur_error = edata;
1827 
1828  estate->err_text = NULL;
1829 
1830  rc = exec_stmts(estate, exception->action);
1831 
1832  break;
1833  }
1834  }
1835 
1836  /*
1837  * Restore previous state of cur_error, whether or not we executed
1838  * a handler. This is needed in case an error got thrown from
1839  * some inner block's exception handler.
1840  */
1841  estate->cur_error = save_cur_error;
1842 
1843  /* If no match found, re-throw the error */
1844  if (e == NULL)
1845  ReThrowError(edata);
1846 
1847  /* Restore stmt_mcontext stack and release the error data */
1848  pop_stmt_mcontext(estate);
1849  MemoryContextReset(stmt_mcontext);
1850  }
1851  PG_END_TRY();
1852 
1853  Assert(save_cur_error == estate->cur_error);
1854  }
1855  else
1856  {
1857  /*
1858  * Just execute the statements in the block's body
1859  */
1860  estate->err_text = NULL;
1861 
1862  rc = exec_stmts(estate, block->body);
1863  }
1864 
1865  estate->err_text = NULL;
1866 
1867  /*
1868  * Handle the return code. This is intentionally different from
1869  * LOOP_RC_PROCESSING(): CONTINUE never matches a block, and EXIT matches
1870  * a block only if there is a label match.
1871  */
1872  switch (rc)
1873  {
1874  case PLPGSQL_RC_OK:
1875  case PLPGSQL_RC_RETURN:
1876  case PLPGSQL_RC_CONTINUE:
1877  return rc;
1878