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/cmdtag.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, ResourceOwner simple_eval_resowner)
 
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, ResourceOwner simple_eval_resowner, 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 ResourceOwner shared_simple_eval_resowner = 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 142 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:610
#define ERROR
Definition: elog.h:43
const char * name
Definition: encode.c:555
int errmsg(const char *fmt,...)
Definition: elog.c:824
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1173

Definition at line 3627 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 8556 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().

8558 {
8559  Assert(rec->dtype == PLPGSQL_DTYPE_REC);
8560 
8561  /* Transfer new record object into datum_context */
8562  TransferExpandedRecord(erh, estate->datum_context);
8563 
8564  /* Free the old value ... */
8565  if (rec->erh)
8567 
8568  /* ... and install the new */
8569  rec->erh = erh;
8570 }
PLpgSQL_datum_type dtype
Definition: plpgsql.h:381
ExpandedRecordHeader * erh
Definition: plpgsql.h:404
void DeleteExpandedObject(Datum d)
#define Assert(condition)
Definition: c.h:738
#define TransferExpandedRecord(erh, cxt)
MemoryContext datum_context
Definition: plpgsql.h:1084
#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 8480 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().

8482 {
8483  Assert(var->dtype == PLPGSQL_DTYPE_VAR ||
8484  var->dtype == PLPGSQL_DTYPE_PROMISE);
8485 
8486  /*
8487  * In non-atomic contexts, we do not want to store TOAST pointers in
8488  * variables, because such pointers might become stale after a commit.
8489  * Forcibly detoast in such cases. We don't want to detoast (flatten)
8490  * expanded objects, however; those should be OK across a transaction
8491  * boundary since they're just memory-resident objects. (Elsewhere in
8492  * this module, operations on expanded records likewise need to request
8493  * detoasting of record fields when !estate->atomic. Expanded arrays are
8494  * not a problem since all array entries are always detoasted.)
8495  */
8496  if (!estate->atomic && !isnull && var->datatype->typlen == -1 &&
8498  {
8499  MemoryContext oldcxt;
8500  Datum detoasted;
8501 
8502  /*
8503  * Do the detoasting in the eval_mcontext to avoid long-term leakage
8504  * of whatever memory toast fetching might leak. Then we have to copy
8505  * the detoasted datum to the function's main context, which is a
8506  * pain, but there's little choice.
8507  */
8508  oldcxt = MemoryContextSwitchTo(get_eval_mcontext(estate));
8509  detoasted = PointerGetDatum(detoast_external_attr((struct varlena *) DatumGetPointer(newvalue)));
8510  MemoryContextSwitchTo(oldcxt);
8511  /* Now's a good time to not leak the input value if it's freeable */
8512  if (freeable)
8513  pfree(DatumGetPointer(newvalue));
8514  /* Once we copy the value, it's definitely freeable */
8515  newvalue = datumCopy(detoasted, false, -1);
8516  freeable = true;
8517  /* Can't clean up eval_mcontext here, but it'll happen before long */
8518  }
8519 
8520  /* Free the old value if needed */
8521  if (var->freeval)
8522  {
8524  var->isnull,
8525  var->datatype->typlen))
8527  else
8528  pfree(DatumGetPointer(var->value));
8529  }
8530  /* Assign new value to datum */
8531  var->value = newvalue;
8532  var->isnull = isnull;
8533  var->freeval = freeable;
8534 
8535  /*
8536  * If it's a promise variable, then either we just assigned the promised
8537  * value, or the user explicitly assigned an overriding value. Either
8538  * way, cancel the promise.
8539  */
8541 }
PLpgSQL_promise_type promise
Definition: plpgsql.h:332
#define VARATT_IS_EXTERNAL_NON_EXPANDED(PTR)
Definition: postgres.h:324
PLpgSQL_datum_type dtype
Definition: plpgsql.h:301
#define PointerGetDatum(X)
Definition: postgres.h:556
struct varlena * detoast_external_attr(struct varlena *attr)
Definition: detoast.c:44
PLpgSQL_type * datatype
Definition: plpgsql.h:310
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void pfree(void *pointer)
Definition: mcxt.c:1056
bool freeval
Definition: plpgsql.h:325
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
#define get_eval_mcontext(estate)
Definition: pl_exec.c:138
uintptr_t Datum
Definition: postgres.h:367
Datum value
Definition: plpgsql.h:323
void DeleteExpandedObject(Datum d)
#define Assert(condition)
Definition: c.h:738
#define DatumIsReadWriteExpandedObject(d, isnull, typlen)
#define DatumGetPointer(X)
Definition: postgres.h:549
Definition: c.h:555
int16 typlen
Definition: plpgsql.h:204
bool isnull
Definition: plpgsql.h:324

◆ assign_text_var()

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

Definition at line 8547 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().

8548 {
8549  assign_simple_var(estate, var, CStringGetTextDatum(str), false, true);
8550 }
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8480
#define CStringGetTextDatum(s)
Definition: builtins.h:87

◆ coerce_function_result_tuple()

static void coerce_function_result_tuple ( PLpgSQL_execstate estate,
TupleDesc  tupdesc 
)
static

Definition at line 796 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().

797 {
798  HeapTuple rettup;
799  TupleDesc retdesc;
800  TupleConversionMap *tupmap;
801 
802  /* We assume exec_stmt_return verified that result is composite */
803  Assert(type_is_rowtype(estate->rettype));
804 
805  /* We can special-case expanded records for speed */
807  {
809 
810  Assert(erh->er_magic == ER_MAGIC);
811 
812  /* Extract record's TupleDesc */
813  retdesc = expanded_record_get_tupdesc(erh);
814 
815  /* check rowtype compatibility */
816  tupmap = convert_tuples_by_position(retdesc,
817  tupdesc,
818  gettext_noop("returned record type does not match expected record type"));
819 
820  /* it might need conversion */
821  if (tupmap)
822  {
823  rettup = expanded_record_get_tuple(erh);
824  Assert(rettup);
825  rettup = execute_attr_map_tuple(rettup, tupmap);
826 
827  /*
828  * Copy tuple to upper executor memory, as a tuple Datum. Make
829  * sure it is labeled with the caller-supplied tuple type.
830  */
831  estate->retval = PointerGetDatum(SPI_returntuple(rettup, tupdesc));
832  /* no need to free map, we're about to return anyway */
833  }
834  else if (!(tupdesc->tdtypeid == erh->er_decltypeid ||
835  (tupdesc->tdtypeid == RECORDOID &&
836  !ExpandedRecordIsDomain(erh))))
837  {
838  /*
839  * The expanded record has the right physical tupdesc, but the
840  * wrong type ID. (Typically, the expanded record is RECORDOID
841  * but the function is declared to return a named composite type.
842  * As in exec_move_row_from_datum, we don't allow returning a
843  * composite-domain record from a function declared to return
844  * RECORD.) So we must flatten the record to a tuple datum and
845  * overwrite its type fields with the right thing. spi.c doesn't
846  * provide any easy way to deal with this case, so we end up
847  * duplicating the guts of datumCopy() :-(
848  */
849  Size resultsize;
850  HeapTupleHeader tuphdr;
851 
852  resultsize = EOH_get_flat_size(&erh->hdr);
853  tuphdr = (HeapTupleHeader) SPI_palloc(resultsize);
854  EOH_flatten_into(&erh->hdr, (void *) tuphdr, resultsize);
855  HeapTupleHeaderSetTypeId(tuphdr, tupdesc->tdtypeid);
856  HeapTupleHeaderSetTypMod(tuphdr, tupdesc->tdtypmod);
857  estate->retval = PointerGetDatum(tuphdr);
858  }
859  else
860  {
861  /*
862  * We need only copy result into upper executor memory context.
863  * However, if we have a R/W expanded datum, we can just transfer
864  * its ownership out to the upper executor context.
865  */
866  estate->retval = SPI_datumTransfer(estate->retval,
867  false,
868  -1);
869  }
870  }
871  else
872  {
873  /* Convert composite datum to a HeapTuple and TupleDesc */
874  HeapTupleData tmptup;
875 
876  retdesc = deconstruct_composite_datum(estate->retval, &tmptup);
877  rettup = &tmptup;
878 
879  /* check rowtype compatibility */
880  tupmap = convert_tuples_by_position(retdesc,
881  tupdesc,
882  gettext_noop("returned record type does not match expected record type"));
883 
884  /* it might need conversion */
885  if (tupmap)
886  rettup = execute_attr_map_tuple(rettup, tupmap);
887 
888  /*
889  * Copy tuple to upper executor memory, as a tuple Datum. Make sure
890  * it is labeled with the caller-supplied tuple type.
891  */
892  estate->retval = PointerGetDatum(SPI_returntuple(rettup, tupdesc));
893 
894  /* no need to free map, we're about to return anyway */
895 
896  ReleaseTupleDesc(retdesc);
897  }
898 }
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:59
#define PointerGetDatum(X)
Definition: postgres.h:556
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define gettext_noop(x)
Definition: c.h:1160
static TupleDesc deconstruct_composite_datum(Datum value, HeapTupleData *tmptup)
Definition: pl_exec.c:7460
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:2543
HeapTuple execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map)
Definition: tupconvert.c:139
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:738
size_t Size
Definition: c.h:466
#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 7361 of file pl_exec.c.

References i, TupleDescData::natts, and TupleDescAttr.

Referenced by exec_for_query(), and exec_move_row().

7362 {
7363  int i;
7364 
7365  /* Possibly we could allow src_tupdesc to have extra columns? */
7366  if (dst_tupdesc->natts != src_tupdesc->natts)
7367  return false;
7368 
7369  for (i = 0; i < dst_tupdesc->natts; i++)
7370  {
7371  Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
7372  Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
7373 
7374  if (dattr->attisdropped != sattr->attisdropped)
7375  return false;
7376  if (!dattr->attisdropped)
7377  {
7378  /* Normal columns must match by type and typmod */
7379  if (dattr->atttypid != sattr->atttypid ||
7380  (dattr->atttypmod >= 0 &&
7381  dattr->atttypmod != sattr->atttypmod))
7382  return false;
7383  }
7384  else
7385  {
7386  /* Dropped columns are OK as long as length/alignment match */
7387  if (dattr->attlen != sattr->attlen ||
7388  dattr->attalign != sattr->attalign)
7389  return false;
7390  }
7391  }
7392  return true;
7393 }
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
int i

◆ contains_target_param()

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

Definition at line 8282 of file pl_exec.c.

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

Referenced by exec_check_rw_parameter().

8283 {
8284  if (node == NULL)
8285  return false;
8286  if (IsA(node, Param))
8287  {
8288  Param *param = (Param *) node;
8289 
8290  if (param->paramkind == PARAM_EXTERN &&
8291  param->paramid == *target_dno + 1)
8292  return true;
8293  return false;
8294  }
8296  (void *) target_dno);
8297 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
ParamKind paramkind
Definition: primnodes.h:262
static bool contains_target_param(Node *node, int *target_dno)
Definition: pl_exec.c:8282
int paramid
Definition: primnodes.h:263
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 7759 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().

7760 {
7761  char *result;
7762  MemoryContext oldcontext;
7763  Oid typoutput;
7764  bool typIsVarlena;
7765 
7766  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7767  getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
7768  result = OidOutputFunctionCall(typoutput, value);
7769  MemoryContextSwitchTo(oldcontext);
7770 
7771  return result;
7772 }
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2784
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned int Oid
Definition: postgres_ext.h:31
#define get_eval_mcontext(estate)
Definition: pl_exec.c:138
static struct @143 value
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1657

◆ copy_plpgsql_datums()

static void copy_plpgsql_datums ( PLpgSQL_execstate estate,
PLpgSQL_function func 
)
static

Definition at line 1279 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().

1281 {
1282  int ndatums = estate->ndatums;
1283  PLpgSQL_datum **indatums;
1284  PLpgSQL_datum **outdatums;
1285  char *workspace;
1286  char *ws_next;
1287  int i;
1288 
1289  /* Allocate local datum-pointer array */
1290  estate->datums = (PLpgSQL_datum **)
1291  palloc(sizeof(PLpgSQL_datum *) * ndatums);
1292 
1293  /*
1294  * To reduce palloc overhead, we make a single palloc request for all the
1295  * space needed for locally-instantiated datums.
1296  */
1297  workspace = palloc(func->copiable_size);
1298  ws_next = workspace;
1299 
1300  /* Fill datum-pointer array, copying datums into workspace as needed */
1301  indatums = func->datums;
1302  outdatums = estate->datums;
1303  for (i = 0; i < ndatums; i++)
1304  {
1305  PLpgSQL_datum *indatum = indatums[i];
1306  PLpgSQL_datum *outdatum;
1307 
1308  /* This must agree with plpgsql_finish_datums on what is copiable */
1309  switch (indatum->dtype)
1310  {
1311  case PLPGSQL_DTYPE_VAR:
1312  case PLPGSQL_DTYPE_PROMISE:
1313  outdatum = (PLpgSQL_datum *) ws_next;
1314  memcpy(outdatum, indatum, sizeof(PLpgSQL_var));
1315  ws_next += MAXALIGN(sizeof(PLpgSQL_var));
1316  break;
1317 
1318  case PLPGSQL_DTYPE_REC:
1319  outdatum = (PLpgSQL_datum *) ws_next;
1320  memcpy(outdatum, indatum, sizeof(PLpgSQL_rec));
1321  ws_next += MAXALIGN(sizeof(PLpgSQL_rec));
1322  break;
1323 
1324  case PLPGSQL_DTYPE_ROW:
1327 
1328  /*
1329  * These datum records are read-only at runtime, so no need to
1330  * copy them (well, RECFIELD and ARRAYELEM contain cached
1331  * data, but we'd just as soon centralize the caching anyway).
1332  */
1333  outdatum = indatum;
1334  break;
1335 
1336  default:
1337  elog(ERROR, "unrecognized dtype: %d", indatum->dtype);
1338  outdatum = NULL; /* keep compiler quiet */
1339  break;
1340  }
1341 
1342  outdatums[i] = outdatum;
1343  }
1344 
1345  Assert(ws_next == workspace + func->copiable_size);
1346 }
PLpgSQL_datum ** datums
Definition: plpgsql.h:1031
PLpgSQL_datum_type dtype
Definition: plpgsql.h:267
PLpgSQL_datum ** datums
Definition: plpgsql.h:1082
#define ERROR
Definition: elog.h:43
#define Assert(condition)
Definition: c.h:738
#define MAXALIGN(LEN)
Definition: c.h:691
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:214
int i
Size copiable_size
Definition: plpgsql.h:1032

◆ deconstruct_composite_datum()

static TupleDesc deconstruct_composite_datum ( Datum  value,
HeapTupleData tmptup 
)
static

Definition at line 7460 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().

7461 {
7462  HeapTupleHeader td;
7463  Oid tupType;
7464  int32 tupTypmod;
7465 
7466  /* Get tuple body (note this could involve detoasting) */
7468 
7469  /* Build a temporary HeapTuple control structure */
7470  tmptup->t_len = HeapTupleHeaderGetDatumLength(td);
7471  ItemPointerSetInvalid(&(tmptup->t_self));
7472  tmptup->t_tableOid = InvalidOid;
7473  tmptup->t_data = td;
7474 
7475  /* Extract rowtype info and find a tupdesc */
7476  tupType = HeapTupleHeaderGetTypeId(td);
7477  tupTypmod = HeapTupleHeaderGetTypMod(td);
7478  return lookup_rowtype_tupdesc(tupType, tupTypmod);
7479 }
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1710
unsigned int Oid
Definition: postgres_ext.h:31
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:294
signed int int32
Definition: c.h:355
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
static struct @143 value
#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 1565 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().

1566 {
1567  for (; cond != NULL; cond = cond->next)
1568  {
1569  int sqlerrstate = cond->sqlerrstate;
1570 
1571  /*
1572  * OTHERS matches everything *except* query-canceled and
1573  * assert-failure. If you're foolish enough, you can match those
1574  * explicitly.
1575  */
1576  if (sqlerrstate == 0)
1577  {
1578  if (edata->sqlerrcode != ERRCODE_QUERY_CANCELED &&
1579  edata->sqlerrcode != ERRCODE_ASSERT_FAILURE)
1580  return true;
1581  }
1582  /* Exact match? */
1583  else if (edata->sqlerrcode == sqlerrstate)
1584  return true;
1585  /* Category match? */
1586  else if (ERRCODE_IS_CATEGORY(sqlerrstate) &&
1587  ERRCODE_TO_CATEGORY(edata->sqlerrcode) == sqlerrstate)
1588  return true;
1589  }
1590  return false;
1591 }
#define ERRCODE_IS_CATEGORY(ec)
Definition: elog.h:68
int sqlerrcode
Definition: elog.h:364
struct PLpgSQL_condition * next
Definition: plpgsql.h:487
#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 4964 of file pl_exec.c.

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

Referenced by exec_stmt_getdiag().

4966 {
4967  text *value;
4968  MemoryContext oldcontext;
4969 
4970  /* Use eval_mcontext for short-lived text value */
4971  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
4972  if (str != NULL)
4973  value = cstring_to_text(str);
4974  else
4975  value = cstring_to_text("");
4976  MemoryContextSwitchTo(oldcontext);
4977 
4978  exec_assign_value(estate, target, PointerGetDatum(value), false,
4979  TEXTOID, -1);
4980 }
#define PointerGetDatum(X)
Definition: postgres.h:556
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define get_eval_mcontext(estate)
Definition: pl_exec.c:138
static struct @143 value
text * cstring_to_text(const char *s)
Definition: varlena.c:172
Definition: c.h:555
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:4992

◆ exec_assign_expr()

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

Definition at line 4927 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().

4929 {
4930  Datum value;
4931  bool isnull;
4932  Oid valtype;
4933  int32 valtypmod;
4934 
4935  /*
4936  * If first time through, create a plan for this expression, and then see
4937  * if we can pass the target variable as a read-write parameter to the
4938  * expression. (This is a bit messy, but it seems cleaner than modifying
4939  * the API of exec_eval_expr for the purpose.)
4940  */
4941  if (expr->plan == NULL)
4942  {
4943  exec_prepare_plan(estate, expr, 0, true);
4944  if (target->dtype == PLPGSQL_DTYPE_VAR)
4945  exec_check_rw_parameter(expr, target->dno);
4946  }
4947 
4948  value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod);
4949  exec_assign_value(estate, target, value, isnull, valtype, valtypmod);
4950  exec_eval_cleanup(estate);
4951 }
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions, bool keepplan)
Definition: pl_exec.c:4067
static void exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno)
Definition: pl_exec.c:8205
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4046
unsigned int Oid
Definition: postgres_ext.h:31
PLpgSQL_datum_type dtype
Definition: plpgsql.h:267
SPIPlanPtr plan
Definition: plpgsql.h:222
signed int int32
Definition: c.h:355
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5788
uintptr_t Datum
Definition: postgres.h:367
static struct @143 value
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:4992

◆ 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 4992 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().

4996 {
4997  switch (target->dtype)
4998  {
4999  case PLPGSQL_DTYPE_VAR:
5000  case PLPGSQL_DTYPE_PROMISE:
5001  {
5002  /*
5003  * Target is a variable
5004  */
5005  PLpgSQL_var *var = (PLpgSQL_var *) target;
5006  Datum newvalue;
5007 
5008  newvalue = exec_cast_value(estate,
5009  value,
5010  &isNull,
5011  valtype,
5012  valtypmod,
5013  var->datatype->typoid,
5014  var->datatype->atttypmod);
5015 
5016  if (isNull && var->notnull)
5017  ereport(ERROR,
5018  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5019  errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
5020  var->refname)));
5021 
5022  /*
5023  * If type is by-reference, copy the new value (which is
5024  * probably in the eval_mcontext) into the procedure's main
5025  * memory context. But if it's a read/write reference to an
5026  * expanded object, no physical copy needs to happen; at most
5027  * we need to reparent the object's memory context.
5028  *
5029  * If it's an array, we force the value to be stored in R/W
5030  * expanded form. This wins if the function later does, say,
5031  * a lot of array subscripting operations on the variable, and
5032  * otherwise might lose. We might need to use a different
5033  * heuristic, but it's too soon to tell. Also, are there
5034  * cases where it'd be useful to force non-array values into
5035  * expanded form?
5036  */
5037  if (!var->datatype->typbyval && !isNull)
5038  {
5039  if (var->datatype->typisarray &&
5041  {
5042  /* array and not already R/W, so apply expand_array */
5043  newvalue = expand_array(newvalue,
5044  estate->datum_context,
5045  NULL);
5046  }
5047  else
5048  {
5049  /* else transfer value if R/W, else just datumCopy */
5050  newvalue = datumTransfer(newvalue,
5051  false,
5052  var->datatype->typlen);
5053  }
5054  }
5055 
5056  /*
5057  * Now free the old value, if any, and assign the new one. But
5058  * skip the assignment if old and new values are the same.
5059  * Note that for expanded objects, this test is necessary and
5060  * cannot reliably be made any earlier; we have to be looking
5061  * at the object's standard R/W pointer to be sure pointer
5062  * equality is meaningful.
5063  *
5064  * Also, if it's a promise variable, we should disarm the
5065  * promise in any case --- otherwise, assigning null to an
5066  * armed promise variable would fail to disarm the promise.
5067  */
5068  if (var->value != newvalue || var->isnull || isNull)
5069  assign_simple_var(estate, var, newvalue, isNull,
5070  (!var->datatype->typbyval && !isNull));
5071  else
5073  break;
5074  }
5075 
5076  case PLPGSQL_DTYPE_ROW:
5077  {
5078  /*
5079  * Target is a row variable
5080  */
5081  PLpgSQL_row *row = (PLpgSQL_row *) target;
5082 
5083  if (isNull)
5084  {
5085  /* If source is null, just assign nulls to the row */
5086  exec_move_row(estate, (PLpgSQL_variable *) row,
5087  NULL, NULL);
5088  }
5089  else
5090  {
5091  /* Source must be of RECORD or composite type */
5092  if (!type_is_rowtype(valtype))
5093  ereport(ERROR,
5094  (errcode(ERRCODE_DATATYPE_MISMATCH),
5095  errmsg("cannot assign non-composite value to a row variable")));
5097  value);
5098  }
5099  break;
5100  }
5101 
5102  case PLPGSQL_DTYPE_REC:
5103  {
5104  /*
5105  * Target is a record variable
5106  */
5107  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
5108 
5109  if (isNull)
5110  {
5111  if (rec->notnull)
5112  ereport(ERROR,
5113  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5114  errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
5115  rec->refname)));
5116 
5117  /* Set variable to a simple NULL */
5118  exec_move_row(estate, (PLpgSQL_variable *) rec,
5119  NULL, NULL);
5120  }
5121  else
5122  {
5123  /* Source must be of RECORD or composite type */
5124  if (!type_is_rowtype(valtype))
5125  ereport(ERROR,
5126  (errcode(ERRCODE_DATATYPE_MISMATCH),
5127  errmsg("cannot assign non-composite value to a record variable")));
5129  value);
5130  }
5131  break;
5132  }
5133 
5135  {
5136  /*
5137  * Target is a field of a record
5138  */
5139  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) target;
5140  PLpgSQL_rec *rec;
5141  ExpandedRecordHeader *erh;
5142 
5143  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5144  erh = rec->erh;
5145 
5146  /*
5147  * If record variable is NULL, instantiate it if it has a
5148  * named composite type, else complain. (This won't change
5149  * the logical state of the record, but if we successfully
5150  * assign below, the unassigned fields will all become NULLs.)
5151  */
5152  if (erh == NULL)
5153  {
5154  instantiate_empty_record_variable(estate, rec);
5155  erh = rec->erh;
5156  }
5157 
5158  /*
5159  * Look up the field's properties if we have not already, or
5160  * if the tuple descriptor ID changed since last time.
5161  */
5162  if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
5163  {
5165  recfield->fieldname,
5166  &recfield->finfo))
5167  ereport(ERROR,
5168  (errcode(ERRCODE_UNDEFINED_COLUMN),
5169  errmsg("record \"%s\" has no field \"%s\"",
5170  rec->refname, recfield->fieldname)));
5171  recfield->rectupledescid = erh->er_tupdesc_id;
5172  }
5173 
5174  /* We don't support assignments to system columns. */
5175  if (recfield->finfo.fnumber <= 0)
5176  ereport(ERROR,
5177  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5178  errmsg("cannot assign to system column \"%s\"",
5179  recfield->fieldname)));
5180 
5181  /* Cast the new value to the right type, if needed. */
5182  value = exec_cast_value(estate,
5183  value,
5184  &isNull,
5185  valtype,
5186  valtypmod,
5187  recfield->finfo.ftypeid,
5188  recfield->finfo.ftypmod);
5189 
5190  /* And assign it. */
5191  expanded_record_set_field(erh, recfield->finfo.fnumber,
5192  value, isNull, !estate->atomic);
5193  break;
5194  }
5195 
5197  {
5198  /*
5199  * Target is an element of an array
5200  */
5201  PLpgSQL_arrayelem *arrayelem;
5202  int nsubscripts;
5203  int i;
5204  PLpgSQL_expr *subscripts[MAXDIM];
5205  int subscriptvals[MAXDIM];
5206  Datum oldarraydatum,
5207  newarraydatum,
5208  coerced_value;
5209  bool oldarrayisnull;
5210  Oid parenttypoid;
5211  int32 parenttypmod;
5212  SPITupleTable *save_eval_tuptable;
5213  MemoryContext oldcontext;
5214 
5215  /*
5216  * We need to do subscript evaluation, which might require
5217  * evaluating general expressions; and the caller might have
5218  * done that too in order to prepare the input Datum. We have
5219  * to save and restore the caller's SPI_execute result, if
5220  * any.
5221  */
5222  save_eval_tuptable = estate->eval_tuptable;
5223  estate->eval_tuptable = NULL;
5224 
5225  /*
5226  * To handle constructs like x[1][2] := something, we have to
5227  * be prepared to deal with a chain of arrayelem datums. Chase
5228  * back to find the base array datum, and save the subscript
5229  * expressions as we go. (We are scanning right to left here,
5230  * but want to evaluate the subscripts left-to-right to
5231  * minimize surprises.) Note that arrayelem is left pointing
5232  * to the leftmost arrayelem datum, where we will cache the
5233  * array element type data.
5234  */
5235  nsubscripts = 0;
5236  do
5237  {
5238  arrayelem = (PLpgSQL_arrayelem *) target;
5239  if (nsubscripts >= MAXDIM)
5240  ereport(ERROR,
5241  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5242  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
5243  nsubscripts + 1, MAXDIM)));
5244  subscripts[nsubscripts++] = arrayelem->subscript;
5245  target = estate->datums[arrayelem->arrayparentno];
5246  } while (target->dtype == PLPGSQL_DTYPE_ARRAYELEM);
5247 
5248  /* Fetch current value of array datum */
5249  exec_eval_datum(estate, target,
5250  &parenttypoid, &parenttypmod,
5251  &oldarraydatum, &oldarrayisnull);
5252 
5253  /* Update cached type data if necessary */
5254  if (arrayelem->parenttypoid != parenttypoid ||
5255  arrayelem->parenttypmod != parenttypmod)
5256  {
5257  Oid arraytypoid;
5258  int32 arraytypmod = parenttypmod;
5259  int16 arraytyplen;
5260  Oid elemtypoid;
5261  int16 elemtyplen;
5262  bool elemtypbyval;
5263  char elemtypalign;
5264 
5265  /* If target is domain over array, reduce to base type */
5266  arraytypoid = getBaseTypeAndTypmod(parenttypoid,
5267  &arraytypmod);
5268 
5269  /* ... and identify the element type */
5270  elemtypoid = get_element_type(arraytypoid);
5271  if (!OidIsValid(elemtypoid))
5272  ereport(ERROR,
5273  (errcode(ERRCODE_DATATYPE_MISMATCH),
5274  errmsg("subscripted object is not an array")));
5275 
5276  /* Collect needed data about the types */
5277  arraytyplen = get_typlen(arraytypoid);
5278 
5279  get_typlenbyvalalign(elemtypoid,
5280  &elemtyplen,
5281  &elemtypbyval,
5282  &elemtypalign);
5283 
5284  /* Now safe to update the cached data */
5285  arrayelem->parenttypoid = parenttypoid;
5286  arrayelem->parenttypmod = parenttypmod;
5287  arrayelem->arraytypoid = arraytypoid;
5288  arrayelem->arraytypmod = arraytypmod;
5289  arrayelem->arraytyplen = arraytyplen;
5290  arrayelem->elemtypoid = elemtypoid;
5291  arrayelem->elemtyplen = elemtyplen;
5292  arrayelem->elemtypbyval = elemtypbyval;
5293  arrayelem->elemtypalign = elemtypalign;
5294  }
5295 
5296  /*
5297  * Evaluate the subscripts, switch into left-to-right order.
5298  * Like the expression built by ExecInitSubscriptingRef(),
5299  * complain if any subscript is null.
5300  */
5301  for (i = 0; i < nsubscripts; i++)
5302  {
5303  bool subisnull;
5304 
5305  subscriptvals[i] =
5306  exec_eval_integer(estate,
5307  subscripts[nsubscripts - 1 - i],
5308  &subisnull);
5309  if (subisnull)
5310  ereport(ERROR,
5311  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5312  errmsg("array subscript in assignment must not be null")));
5313 
5314  /*
5315  * Clean up in case the subscript expression wasn't
5316  * simple. We can't do exec_eval_cleanup, but we can do
5317  * this much (which is safe because the integer subscript
5318  * value is surely pass-by-value), and we must do it in
5319  * case the next subscript expression isn't simple either.
5320  */
5321  if (estate->eval_tuptable != NULL)
5323  estate->eval_tuptable = NULL;
5324  }
5325 
5326  /* Now we can restore caller's SPI_execute result if any. */
5327  Assert(estate->eval_tuptable == NULL);
5328  estate->eval_tuptable = save_eval_tuptable;
5329 
5330  /* Coerce source value to match array element type. */
5331  coerced_value = exec_cast_value(estate,
5332  value,
5333  &isNull,
5334  valtype,
5335  valtypmod,
5336  arrayelem->elemtypoid,
5337  arrayelem->arraytypmod);
5338 
5339  /*
5340  * If the original array is null, cons up an empty array so
5341  * that the assignment can proceed; we'll end with a
5342  * one-element array containing just the assigned-to
5343  * subscript. This only works for varlena arrays, though; for
5344  * fixed-length array types we skip the assignment. We can't
5345  * support assignment of a null entry into a fixed-length
5346  * array, either, so that's a no-op too. This is all ugly but
5347  * corresponds to the current behavior of execExpr*.c.
5348  */
5349  if (arrayelem->arraytyplen > 0 && /* fixed-length array? */
5350  (oldarrayisnull || isNull))
5351  return;
5352 
5353  /* empty array, if any, and newarraydatum are short-lived */
5354  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5355 
5356  if (oldarrayisnull)
5357  oldarraydatum = PointerGetDatum(construct_empty_array(arrayelem->elemtypoid));
5358 
5359  /*
5360  * Build the modified array value.
5361  */
5362  newarraydatum = array_set_element(oldarraydatum,
5363  nsubscripts,
5364  subscriptvals,
5365  coerced_value,
5366  isNull,
5367  arrayelem->arraytyplen,
5368  arrayelem->elemtyplen,
5369  arrayelem->elemtypbyval,
5370  arrayelem->elemtypalign);
5371 
5372  MemoryContextSwitchTo(oldcontext);
5373 
5374  /*
5375  * Assign the new array to the base variable. It's never NULL
5376  * at this point. Note that if the target is a domain,
5377  * coercing the base array type back up to the domain will
5378  * happen within exec_assign_value.
5379  */
5380  exec_assign_value(estate, target,
5381  newarraydatum,
5382  false,
5383  arrayelem->arraytypoid,
5384  arrayelem->arraytypmod);
5385  break;
5386  }
5387 
5388  default:
5389  elog(ERROR, "unrecognized dtype: %d", target->dtype);
5390  }
5391 }
PLpgSQL_promise_type promise
Definition: plpgsql.h:332
signed short int16
Definition: c.h:354
int16 elemtyplen
Definition: plpgsql.h:443
#define expanded_record_set_field(erh, fnumber, newValue, isnull, expand_external)
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2426
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1107
char * refname
Definition: plpgsql.h:303
static void exec_eval_datum(PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeid, int32 *typetypmod, Datum *value, bool *isnull)
Definition: pl_exec.c:5411
bool expanded_record_lookup_field(ExpandedRecordHeader *erh, const char *fieldname, ExpandedRecordFieldInfo *finfo)
#define MAXDIM
Definition: c.h:535
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2636
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2159
#define PointerGetDatum(X)
Definition: postgres.h:556
PLpgSQL_type * datatype
Definition: plpgsql.h:310
Datum expand_array(Datum arraydatum, MemoryContext parentcontext, ArrayMetaState *metacache)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void instantiate_empty_record_variable(PLpgSQL_execstate *estate, PLpgSQL_rec *rec)
Definition: pl_exec.c:7724
ExpandedRecordHeader * erh
Definition: plpgsql.h:404
int errcode(int sqlerrcode)
Definition: elog.c:610
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8480
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:2200
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3411
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:7491
PLpgSQL_datum_type dtype
Definition: plpgsql.h:267
#define OidIsValid(objectId)
Definition: c.h:644
char * refname
Definition: plpgsql.h:383
signed int int32
Definition: c.h:355
PLpgSQL_datum ** datums
Definition: plpgsql.h:1082
int32 arraytypmod
Definition: plpgsql.h:440
bool notnull
Definition: plpgsql.h:306
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7788
#define ERROR
Definition: elog.h:43
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2543
uint64 rectupledescid
Definition: plpgsql.h:419
bool typbyval
Definition: plpgsql.h:205
#define get_eval_mcontext(estate)
Definition: pl_exec.c:138
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:5742
ExpandedRecordFieldInfo finfo
Definition: plpgsql.h:420
int32 parenttypmod
Definition: plpgsql.h:438
Datum value
Definition: plpgsql.h:323
static struct @143 value
#define ereport(elevel,...)
Definition: elog.h:144
Datum datumTransfer(Datum value, bool typByVal, int typLen)
Definition: datum.c:193
#define Assert(condition)
Definition: c.h:738
int16 arraytyplen
Definition: plpgsql.h:441
#define DatumGetPointer(X)
Definition: postgres.h:549
MemoryContext datum_context
Definition: plpgsql.h:1084
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2085
int errmsg(const char *fmt,...)
Definition: elog.c:824
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:6817
#define elog(elevel,...)
Definition: elog.h:214
int i
PLpgSQL_expr * subscript
Definition: plpgsql.h:433
#define VARATT_IS_EXTERNAL_EXPANDED_RW(PTR)
Definition: postgres.h:320
#define unlikely(x)
Definition: c.h:206
int16 typlen
Definition: plpgsql.h:204
bool notnull
Definition: plpgsql.h:386
char * fieldname
Definition: plpgsql.h:416
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:4992
bool isnull
Definition: plpgsql.h:324
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 7788 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().

7792 {
7793  /*
7794  * If the type of the given value isn't what's requested, convert it.
7795  */
7796  if (valtype != reqtype ||
7797  (valtypmod != reqtypmod && reqtypmod != -1))
7798  {
7799  plpgsql_CastHashEntry *cast_entry;
7800 
7801  cast_entry = get_cast_hashentry(estate,
7802  valtype, valtypmod,
7803  reqtype, reqtypmod);
7804  if (cast_entry)
7805  {
7806  ExprContext *econtext = estate->eval_econtext;
7807  MemoryContext oldcontext;
7808 
7809  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7810 
7811  econtext->caseValue_datum = value;
7812  econtext->caseValue_isNull = *isnull;
7813 
7814  cast_entry->cast_in_use = true;
7815 
7816  value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
7817  isnull);
7818 
7819  cast_entry->cast_in_use = false;
7820 
7821  MemoryContextSwitchTo(oldcontext);
7822  }
7823  }
7824 
7825  return value;
7826 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static plpgsql_CastHashEntry * get_cast_hashentry(PLpgSQL_execstate *estate, Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod)
Definition: pl_exec.c:7839
Datum caseValue_datum
Definition: execnodes.h:251
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:290
#define get_eval_mcontext(estate)
Definition: pl_exec.c:138
static struct @143 value
ExprContext * eval_econtext
Definition: plpgsql.h:1109
bool caseValue_isNull
Definition: execnodes.h:253
ExprState * cast_exprstate
Definition: pl_exec.c:174

◆ exec_check_rw_parameter()

static void exec_check_rw_parameter ( PLpgSQL_expr expr,
int  target_dno 
)
static

Definition at line 8205 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().

8206 {
8207  Oid funcid;
8208  List *fargs;
8209  ListCell *lc;
8210 
8211  /* Assume unsafe */
8212  expr->rwparam = -1;
8213 
8214  /*
8215  * If the expression isn't simple, there's no point in trying to optimize
8216  * (because the exec_run_select code path will flatten any expanded result
8217  * anyway). Even without that, this seems like a good safety restriction.
8218  */
8219  if (expr->expr_simple_expr == NULL)
8220  return;
8221 
8222  /*
8223  * If target variable isn't referenced by expression, no need to look
8224  * further.
8225  */
8226  if (!bms_is_member(target_dno, expr->paramnos))
8227  return;
8228 
8229  /*
8230  * Top level of expression must be a simple FuncExpr or OpExpr.
8231  */
8232  if (IsA(expr->expr_simple_expr, FuncExpr))
8233  {
8234  FuncExpr *fexpr = (FuncExpr *) expr->expr_simple_expr;
8235 
8236  funcid = fexpr->funcid;
8237  fargs = fexpr->args;
8238  }
8239  else if (IsA(expr->expr_simple_expr, OpExpr))
8240  {
8241  OpExpr *opexpr = (OpExpr *) expr->expr_simple_expr;
8242 
8243  funcid = opexpr->opfuncid;
8244  fargs = opexpr->args;
8245  }
8246  else
8247  return;
8248 
8249  /*
8250  * The top-level function must be one that we trust to be "safe".
8251  * Currently we hard-wire the list, but it would be very desirable to
8252  * allow extensions to mark their functions as safe ...
8253  */
8254  if (!(funcid == F_ARRAY_APPEND ||
8255  funcid == F_ARRAY_PREPEND))
8256  return;
8257 
8258  /*
8259  * The target variable (in the form of a Param) must only appear as a
8260  * direct argument of the top-level function.
8261  */
8262  foreach(lc, fargs)
8263  {
8264  Node *arg = (Node *) lfirst(lc);
8265 
8266  /* A Param is OK, whether it's the target variable or not */
8267  if (arg && IsA(arg, Param))
8268  continue;
8269  /* Otherwise, argument expression must not reference target */
8270  if (contains_target_param(arg, &target_dno))
8271  return;
8272  }
8273 
8274  /* OK, we can pass target as a read-write parameter */
8275  expr->rwparam = target_dno;
8276 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
List * args
Definition: primnodes.h:477
Definition: nodes.h:529
unsigned int Oid
Definition: postgres_ext.h:31
Bitmapset * paramnos
Definition: plpgsql.h:223
Oid funcid
Definition: primnodes.h:469
static bool contains_target_param(Node *node, int *target_dno)
Definition: pl_exec.c:8282
Expr * expr_simple_expr
Definition: plpgsql.h:233
int rwparam
Definition: plpgsql.h:224
Oid opfuncid
Definition: primnodes.h:517
#define lfirst(lc)
Definition: pg_list.h:190
void * arg
List * args
Definition: primnodes.h:522
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 8658 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().

8663 {
8664  Portal portal;
8665  Datum query;
8666  bool isnull;
8667  Oid restype;
8668  int32 restypmod;
8669  char *querystr;
8670  MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
8671 
8672  /*
8673  * Evaluate the string expression after the EXECUTE keyword. Its result is
8674  * the querystring we have to execute.
8675  */
8676  query = exec_eval_expr(estate, dynquery, &isnull, &restype, &restypmod);
8677  if (isnull)
8678  ereport(ERROR,
8679  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
8680  errmsg("query string argument of EXECUTE is null")));
8681 
8682  /* Get the C-String representation */
8683  querystr = convert_value_to_string(estate, query, restype);
8684 
8685  /* copy it into the stmt_mcontext before we clean up */
8686  querystr = MemoryContextStrdup(stmt_mcontext, querystr);
8687 
8688  exec_eval_cleanup(estate);
8689 
8690  /*
8691  * Open an implicit cursor for the query. We use
8692  * SPI_cursor_open_with_args even when there are no params, because this
8693  * avoids making and freeing one copy of the plan.
8694  */
8695  if (params)
8696  {
8697  PreparedParamsData *ppd;
8698 
8699  ppd = exec_eval_using_params(estate, params);
8700  portal = SPI_cursor_open_with_args(portalname,
8701  querystr,
8702  ppd->nargs, ppd->types,
8703  ppd->values, ppd->nulls,
8704  estate->readonly_func,
8705  cursorOptions);
8706  }
8707  else
8708  {
8709  portal = SPI_cursor_open_with_args(portalname,
8710  querystr,
8711  0, NULL,
8712  NULL, NULL,
8713  estate->readonly_func,
8714  cursorOptions);
8715  }
8716 
8717  if (portal == NULL)
8718  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
8719  querystr, SPI_result_code_string(SPI_result));
8720 
8721  /* Release transient data */
8722  MemoryContextReset(stmt_mcontext);
8723 
8724  return portal;
8725 }
int errcode(int sqlerrcode)
Definition: elog.c:610
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4046
Datum * values
Definition: pl_exec.c:58
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:355
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:5788
static PreparedParamsData * exec_eval_using_params(PLpgSQL_execstate *estate, List *params)
Definition: pl_exec.c:8579
const char * SPI_result_code_string(int code)
Definition: spi.c:1699
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1514
uintptr_t Datum
Definition: postgres.h:367
#define ereport(elevel,...)
Definition: elog.h:144
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:824
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1173
#define elog(elevel,...)
Definition: elog.h:214
static char * convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
Definition: pl_exec.c:7759

◆ exec_eval_boolean()

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

Definition at line 5765 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().

5768 {
5769  Datum exprdatum;
5770  Oid exprtypeid;
5771  int32 exprtypmod;
5772 
5773  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5774  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5775  exprtypeid, exprtypmod,
5776  BOOLOID, -1);
5777  return DatumGetBool(exprdatum);
5778 }
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:355
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7788
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5788
#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 4046 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().

4047 {
4048  /* Clear result of a full SPI_execute */
4049  if (estate->eval_tuptable != NULL)
4051  estate->eval_tuptable = NULL;
4052 
4053  /*
4054  * Clear result of exec_eval_simple_expr (but keep the econtext). This
4055  * also clears any short-lived allocations done via get_eval_mcontext.
4056  */
4057  if (estate->eval_econtext != NULL)
4059 }
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1107
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1162
ExprContext * eval_econtext
Definition: plpgsql.h:1109
#define ResetExprContext(econtext)
Definition: executor.h:501

◆ 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 5411 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().

5417 {
5418  MemoryContext oldcontext;
5419 
5420  switch (datum->dtype)
5421  {
5422  case PLPGSQL_DTYPE_PROMISE:
5423  /* fulfill promise if needed, then handle like regular var */
5424  plpgsql_fulfill_promise(estate, (PLpgSQL_var *) datum);
5425 
5426  /* FALL THRU */
5427 
5428  case PLPGSQL_DTYPE_VAR:
5429  {
5430  PLpgSQL_var *var = (PLpgSQL_var *) datum;
5431 
5432  *typeid = var->datatype->typoid;
5433  *typetypmod = var->datatype->atttypmod;
5434  *value = var->value;
5435  *isnull = var->isnull;
5436  break;
5437  }
5438 
5439  case PLPGSQL_DTYPE_ROW:
5440  {
5441  PLpgSQL_row *row = (PLpgSQL_row *) datum;
5442  HeapTuple tup;
5443 
5444  /* We get here if there are multiple OUT parameters */
5445  if (!row->rowtupdesc) /* should not happen */
5446  elog(ERROR, "row variable has no tupdesc");
5447  /* Make sure we have a valid type/typmod setting */
5448  BlessTupleDesc(row->rowtupdesc);
5449  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5450  tup = make_tuple_from_row(estate, row, row->rowtupdesc);
5451  if (tup == NULL) /* should not happen */
5452  elog(ERROR, "row not compatible with its own tupdesc");
5453  *typeid = row->rowtupdesc->tdtypeid;
5454  *typetypmod = row->rowtupdesc->tdtypmod;
5455  *value = HeapTupleGetDatum(tup);
5456  *isnull = false;
5457  MemoryContextSwitchTo(oldcontext);
5458  break;
5459  }
5460 
5461  case PLPGSQL_DTYPE_REC:
5462  {
5463  PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
5464 
5465  if (rec->erh == NULL)
5466  {
5467  /* Treat uninstantiated record as a simple NULL */
5468  *value = (Datum) 0;
5469  *isnull = true;
5470  /* Report variable's declared type */
5471  *typeid = rec->rectypeid;
5472  *typetypmod = -1;
5473  }
5474  else
5475  {
5476  if (ExpandedRecordIsEmpty(rec->erh))
5477  {
5478  /* Empty record is also a NULL */
5479  *value = (Datum) 0;
5480  *isnull = true;
5481  }
5482  else
5483  {
5484  *value = ExpandedRecordGetDatum(rec->erh);
5485  *isnull = false;
5486  }
5487  if (rec->rectypeid != RECORDOID)
5488  {
5489  /* Report variable's declared type, if not RECORD */
5490  *typeid = rec->rectypeid;
5491  *typetypmod = -1;
5492  }
5493  else
5494  {
5495  /* Report record's actual type if declared RECORD */
5496  *typeid = rec->erh->er_typeid;
5497  *typetypmod = rec->erh->er_typmod;
5498  }
5499  }
5500  break;
5501  }
5502 
5504  {
5505  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
5506  PLpgSQL_rec *rec;
5507  ExpandedRecordHeader *erh;
5508 
5509  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5510  erh = rec->erh;
5511 
5512  /*
5513  * If record variable is NULL, instantiate it if it has a
5514  * named composite type, else complain. (This won't change
5515  * the logical state of the record: it's still NULL.)
5516  */
5517  if (erh == NULL)
5518  {
5519  instantiate_empty_record_variable(estate, rec);
5520  erh = rec->erh;
5521  }
5522 
5523  /*
5524  * Look up the field's properties if we have not already, or
5525  * if the tuple descriptor ID changed since last time.
5526  */
5527  if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
5528  {
5530  recfield->fieldname,
5531  &recfield->finfo))
5532  ereport(ERROR,
5533  (errcode(ERRCODE_UNDEFINED_COLUMN),
5534  errmsg("record \"%s\" has no field \"%s\"",
5535  rec->refname, recfield->fieldname)));
5536  recfield->rectupledescid = erh->er_tupdesc_id;
5537  }
5538 
5539  /* Report type data. */
5540  *typeid = recfield->finfo.ftypeid;
5541  *typetypmod = recfield->finfo.ftypmod;
5542 
5543  /* And fetch the field value. */
5545  recfield->finfo.fnumber,
5546  isnull);
5547  break;
5548  }
5549 
5550  default:
5551  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
5552  }
5553 }
static HeapTuple make_tuple_from_row(PLpgSQL_execstate *estate, PLpgSQL_row *row, TupleDesc tupdesc)
Definition: pl_exec.c:7405
#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:310
static void plpgsql_fulfill_promise(PLpgSQL_execstate *estate, PLpgSQL_var *var)
Definition: pl_exec.c:1354
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void instantiate_empty_record_variable(PLpgSQL_execstate *estate, PLpgSQL_rec *rec)
Definition: pl_exec.c:7724
ExpandedRecordHeader * erh
Definition: plpgsql.h:404
int errcode(int sqlerrcode)
Definition: elog.c:610
PLpgSQL_datum_type dtype
Definition: plpgsql.h:267
char * refname
Definition: plpgsql.h:383
PLpgSQL_datum ** datums
Definition: plpgsql.h:1082
#define ERROR
Definition: elog.h:43
int32 tdtypmod
Definition: tupdesc.h:83
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2052
uint64 rectupledescid
Definition: plpgsql.h:419
#define get_eval_mcontext(estate)
Definition: pl_exec.c:138
uintptr_t Datum
Definition: postgres.h:367
ExpandedRecordFieldInfo finfo
Definition: plpgsql.h:420
Datum value
Definition: plpgsql.h:323
static struct @143 value
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:220
Oid tdtypeid
Definition: tupdesc.h:82
int errmsg(const char *fmt,...)
Definition: elog.c:824
int32 atttypmod
Definition: plpgsql.h:209
#define elog(elevel,...)
Definition: elog.h:214
TupleDesc rowtupdesc
Definition: plpgsql.h:369
#define unlikely(x)
Definition: c.h:206
Oid rectypeid
Definition: plpgsql.h:397
#define ExpandedRecordGetDatum(erh)
char * fieldname
Definition: plpgsql.h:416
bool isnull
Definition: plpgsql.h:324
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 5788 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().

5793 {
5794  Datum result = 0;
5795  int rc;
5796  Form_pg_attribute attr;
5797 
5798  /*
5799  * If first time through, create a plan for this expression.
5800  */
5801  if (expr->plan == NULL)
5802  exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK, true);
5803 
5804  /*
5805  * If this is a simple expression, bypass SPI and use the executor
5806  * directly
5807  */
5808  if (exec_eval_simple_expr(estate, expr,
5809  &result, isNull, rettype, rettypmod))
5810  return result;
5811 
5812  /*
5813  * Else do it the hard way via exec_run_select
5814  */
5815  rc = exec_run_select(estate, expr, 2, NULL);
5816  if (rc != SPI_OK_SELECT)
5817  ereport(ERROR,
5818  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5819  errmsg("query \"%s\" did not return data", expr->query)));
5820 
5821  /*
5822  * Check that the expression returns exactly one column...
5823  */
5824  if (estate->eval_tuptable->tupdesc->natts != 1)
5825  ereport(ERROR,
5826  (errcode(ERRCODE_SYNTAX_ERROR),
5827  errmsg_plural("query \"%s\" returned %d column",
5828  "query \"%s\" returned %d columns",
5829  estate->eval_tuptable->tupdesc->natts,
5830  expr->query,
5831  estate->eval_tuptable->tupdesc->natts)));
5832 
5833  /*
5834  * ... and get the column's datatype.
5835  */
5836  attr = TupleDescAttr(estate->eval_tuptable->tupdesc, 0);
5837  *rettype = attr->atttypid;
5838  *rettypmod = attr->atttypmod;
5839 
5840  /*
5841  * If there are no rows selected, the result is a NULL of that type.
5842  */
5843  if (estate->eval_processed == 0)
5844  {
5845  *isNull = true;
5846  return (Datum) 0;
5847  }
5848 
5849  /*
5850  * Check that the expression returned no more than one row.
5851  */
5852  if (estate->eval_processed != 1)
5853  ereport(ERROR,
5854  (errcode(ERRCODE_CARDINALITY_VIOLATION),
5855  errmsg("query \"%s\" returned more than one row",
5856  expr->query)));
5857 
5858  /*
5859  * Return the single result Datum.
5860  */
5861  return SPI_getbinval(estate->eval_tuptable->vals[0],
5862  estate->eval_tuptable->tupdesc, 1, isNull);
5863 }
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:4067
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1107
uint64 eval_processed
Definition: plpgsql.h:1108
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:934
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
int errcode(int sqlerrcode)
Definition: elog.c:610
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:193
uintptr_t Datum
Definition: postgres.h:367
TupleDesc tupdesc
Definition: spi.h:25
#define SPI_OK_SELECT
Definition: spi.h:57
#define ereport(elevel,...)
Definition: elog.h:144
static int exec_run_select(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
Definition: pl_exec.c:5871
static bool exec_eval_simple_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, Datum *result, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:6106
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2715
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ exec_eval_integer()

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

Definition at line 5742 of file pl_exec.c.

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

Referenced by exec_assign_value(), and exec_stmt_fetch().

5745 {
5746  Datum exprdatum;
5747  Oid exprtypeid;
5748  int32 exprtypmod;
5749 
5750  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5751  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5752  exprtypeid, exprtypmod,
5753  INT4OID, -1);
5754  return DatumGetInt32(exprdatum);
5755 }
#define DatumGetInt32(X)
Definition: postgres.h:472
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:355
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7788
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5788
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 6106 of file pl_exec.c.

References Assert, CachedPlanAllowsSimpleValidityCheck(), CachedPlanIsSimplyValid(), CommandCounterIncrement(), CurrentResourceOwner, 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_in_use, PLpgSQL_expr::expr_simple_lxid, PLpgSQL_expr::expr_simple_mutable, PLpgSQL_expr::expr_simple_plan, PLpgSQL_expr::expr_simple_plan_lxid, PLpgSQL_expr::expr_simple_plansource, PLpgSQL_expr::expr_simple_state, PLpgSQL_expr::expr_simple_type, PLpgSQL_expr::expr_simple_typmod, get_eval_mcontext, GetTransactionSnapshot(), InvalidLocalTransactionId, likely, PGPROC::lxid, MemoryContextSwitchTo(), MyProc, PLpgSQL_execstate::paramLI, ParamListInfoData::parserSetupArg, PLpgSQL_expr::plan, PopActiveSnapshot(), PushActiveSnapshot(), PLpgSQL_execstate::readonly_func, ReleaseCachedPlan(), PLpgSQL_expr::rwparam, PLpgSQL_execstate::simple_eval_estate, PLpgSQL_execstate::simple_eval_resowner, SPI_plan_get_cached_plan(), and unlikely.

Referenced by exec_eval_expr().

6112 {
6113  ExprContext *econtext = estate->eval_econtext;
6114  LocalTransactionId curlxid = MyProc->lxid;
6115  ParamListInfo paramLI;
6116  void *save_setup_arg;
6117  bool need_snapshot;
6118  MemoryContext oldcontext;
6119 
6120  /*
6121  * Forget it if expression wasn't simple before.
6122  */
6123  if (expr->expr_simple_expr == NULL)
6124  return false;
6125 
6126  /*
6127  * If expression is in use in current xact, don't touch it.
6128  */
6129  if (unlikely(expr->expr_simple_in_use) &&
6130  expr->expr_simple_lxid == curlxid)
6131  return false;
6132 
6133  /*
6134  * Check to see if the cached plan has been invalidated. If not, and this
6135  * is the first use in the current transaction, save a plan refcount in
6136  * the simple-expression resowner.
6137  */
6139  expr->expr_simple_plan,
6140  (expr->expr_simple_plan_lxid != curlxid ?
6141  estate->simple_eval_resowner : NULL))))
6142  {
6143  /*
6144  * It's still good, so just remember that we have a refcount on the
6145  * plan in the current transaction. (If we already had one, this
6146  * assignment is a no-op.)
6147  */
6148  expr->expr_simple_plan_lxid = curlxid;
6149  }
6150  else
6151  {
6152  /* Need to replan */
6153  CachedPlan *cplan;
6154 
6155  /*
6156  * If we have a valid refcount on some previous version of the plan,
6157  * release it, so we don't leak plans intra-transaction.
6158  */
6159  if (expr->expr_simple_plan_lxid == curlxid)
6160  {
6161  ResourceOwner saveResourceOwner = CurrentResourceOwner;
6162 
6164  ReleaseCachedPlan(expr->expr_simple_plan, true);
6165  CurrentResourceOwner = saveResourceOwner;
6166  expr->expr_simple_plan = NULL;
6168  }
6169 
6170  /* Do the replanning work in the eval_mcontext */
6171  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6172  cplan = SPI_plan_get_cached_plan(expr->plan);
6173  MemoryContextSwitchTo(oldcontext);
6174 
6175  /*
6176  * We can't get a failure here, because the number of
6177  * CachedPlanSources in the SPI plan can't change from what
6178  * exec_simple_check_plan saw; it's a property of the raw parsetree
6179  * generated from the query text.
6180  */
6181  Assert(cplan != NULL);
6182 
6183  /*
6184  * This test probably can't fail either, but if it does, cope by
6185  * declaring the plan to be non-simple. On success, we'll acquire a
6186  * refcount on the new plan, stored in simple_eval_resowner.
6187  */
6189  cplan,
6190  estate->simple_eval_resowner))
6191  {
6192  /* Remember that we have the refcount */
6193  expr->expr_simple_plan = cplan;
6194  expr->expr_simple_plan_lxid = curlxid;
6195  }
6196  else
6197  {
6198  /* Release SPI_plan_get_cached_plan's refcount */
6199  ReleaseCachedPlan(cplan, true);
6200  /* Mark expression as non-simple, and fail */
6201  expr->expr_simple_expr = NULL;
6202  return false;
6203  }
6204 
6205  /*
6206  * SPI_plan_get_cached_plan acquired a plan refcount stored in the
6207  * active resowner. We don't need that anymore, so release it.
6208  */
6209  ReleaseCachedPlan(cplan, true);
6210 
6211  /* Extract desired scalar expression from cached plan */
6212  exec_save_simple_expr(expr, cplan);
6213 
6214  /* better recheck r/w safety, as it could change due to inlining */
6215  if (expr->rwparam >= 0)
6216  exec_check_rw_parameter(expr, expr->rwparam);
6217  }
6218 
6219  /*
6220  * Pass back previously-determined result type.
6221  */
6222  *rettype = expr->expr_simple_type;
6223  *rettypmod = expr->expr_simple_typmod;
6224 
6225  /*
6226  * Set up ParamListInfo to pass to executor. For safety, save and restore
6227  * estate->paramLI->parserSetupArg around our use of the param list.
6228  */
6229  paramLI = estate->paramLI;
6230  save_setup_arg = paramLI->parserSetupArg;
6231 
6232  /*
6233  * We can skip using setup_param_list() in favor of just doing this
6234  * unconditionally, because there's no need for the optimization of
6235  * possibly setting ecxt_param_list_info to NULL; we've already forced use
6236  * of a generic plan.
6237  */
6238  paramLI->parserSetupArg = (void *) expr;
6239  econtext->ecxt_param_list_info = paramLI;
6240 
6241  /*
6242  * Prepare the expression for execution, if it's not been done already in
6243  * the current transaction. (This will be forced to happen if we called
6244  * exec_save_simple_expr above.)
6245  */
6246  if (unlikely(expr->expr_simple_lxid != curlxid))
6247  {
6248  oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
6249  expr->expr_simple_state =
6251  econtext->ecxt_param_list_info);
6252  expr->expr_simple_in_use = false;
6253  expr->expr_simple_lxid = curlxid;
6254  MemoryContextSwitchTo(oldcontext);
6255  }
6256 
6257  /*
6258  * We have to do some of the things SPI_execute_plan would do, in
6259  * particular push a new snapshot so that stable functions within the
6260  * expression can see updates made so far by our own function. However,
6261  * we can skip doing that (and just invoke the expression with the same
6262  * snapshot passed to our function) in some cases, which is useful because
6263  * it's quite expensive relative to the cost of a simple expression. We
6264  * can skip it if the expression contains no stable or volatile functions;
6265  * immutable functions shouldn't need to see our updates. Also, if this
6266  * is a read-only function, we haven't made any updates so again it's okay
6267  * to skip.
6268  */
6269  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6270  need_snapshot = (expr->expr_simple_mutable && !estate->readonly_func);
6271  if (need_snapshot)
6272  {
6275  }
6276 
6277  /*
6278  * Mark expression as busy for the duration of the ExecEvalExpr call.
6279  */
6280  expr->expr_simple_in_use = true;
6281 
6282  /*
6283  * Finally we can call the executor to evaluate the expression
6284  */
6285  *result = ExecEvalExpr(expr->expr_simple_state,
6286  econtext,
6287  isNull);
6288 
6289  /* Assorted cleanup */
6290  expr->expr_simple_in_use = false;
6291 
6292  econtext->ecxt_param_list_info = NULL;
6293 
6294  paramLI->parserSetupArg = save_setup_arg;
6295 
6296  if (need_snapshot)
6298 
6299  MemoryContextSwitchTo(oldcontext);
6300 
6301  /*
6302  * That's it.
6303  */
6304  return true;
6305 }
#define likely(x)
Definition: c.h:205
void * parserSetupArg
Definition: params.h:117
static void exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno)
Definition: pl_exec.c:8205
ResourceOwner simple_eval_resowner
Definition: plpgsql.h:1096
PGPROC * MyProc
Definition: proc.c:67
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void PopActiveSnapshot(void)
Definition: snapmgr.c:814
bool CachedPlanIsSimplyValid(CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1420
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:306
static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
Definition: pl_exec.c:8117
SPIPlanPtr plan
Definition: plpgsql.h:222
CachedPlan * SPI_plan_get_cached_plan(SPIPlanPtr plan)
Definition: spi.c:1792
MemoryContext es_query_cxt
Definition: execnodes.h:555
ParamListInfo paramLI
Definition: plpgsql.h:1092
CachedPlanSource * expr_simple_plansource
Definition: plpgsql.h:244
EState * simple_eval_estate
Definition: plpgsql.h:1095
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:735
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:290
ExprState * ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
Definition: execExpr.c:160
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1260
Expr * expr_simple_expr
Definition: plpgsql.h:233
uint32 LocalTransactionId
Definition: c.h:515
bool CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1305
int rwparam
Definition: plpgsql.h:224
#define get_eval_mcontext(estate)
Definition: pl_exec.c:138
ExprState * expr_simple_state
Definition: plpgsql.h:254
bool expr_simple_mutable
Definition: plpgsql.h:236
CachedPlan * expr_simple_plan
Definition: plpgsql.h:245
void CommandCounterIncrement(void)
Definition: xact.c:1006
LocalTransactionId expr_simple_lxid
Definition: plpgsql.h:256
#define Assert(condition)
Definition: c.h:738
ExprContext * eval_econtext
Definition: plpgsql.h:1109
int32 expr_simple_typmod
Definition: plpgsql.h:235
#define InvalidLocalTransactionId
Definition: lock.h:68
#define unlikely(x)
Definition: c.h:206
LocalTransactionId expr_simple_plan_lxid
Definition: plpgsql.h:246
bool expr_simple_in_use
Definition: plpgsql.h:255
ParamListInfo ecxt_param_list_info
Definition: execnodes.h:238
Oid expr_simple_type
Definition: plpgsql.h:234
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 8579 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().

8580 {
8581  PreparedParamsData *ppd;
8582  MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
8583  int nargs;
8584  int i;
8585  ListCell *lc;
8586 
8587  ppd = (PreparedParamsData *)
8588  MemoryContextAlloc(stmt_mcontext, sizeof(PreparedParamsData));
8589  nargs = list_length(params);
8590 
8591  ppd->nargs = nargs;
8592  ppd->types = (Oid *)
8593  MemoryContextAlloc(stmt_mcontext, nargs * sizeof(Oid));
8594  ppd->values = (Datum *)
8595  MemoryContextAlloc(stmt_mcontext, nargs * sizeof(Datum));
8596  ppd->nulls = (char *)
8597  MemoryContextAlloc(stmt_mcontext, nargs * sizeof(char));
8598 
8599  i = 0;
8600  foreach(lc, params)
8601  {
8602  PLpgSQL_expr *param = (PLpgSQL_expr *) lfirst(lc);
8603  bool isnull;
8604  int32 ppdtypmod;
8605  MemoryContext oldcontext;
8606 
8607  ppd->values[i] = exec_eval_expr(estate, param,
8608  &isnull,
8609  &ppd->types[i],
8610  &ppdtypmod);
8611  ppd->nulls[i] = isnull ? 'n' : ' ';
8612 
8613  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8614 
8615  if (ppd->types[i] == UNKNOWNOID)
8616  {
8617  /*
8618  * Treat 'unknown' parameters as text, since that's what most
8619  * people would expect. SPI_execute_with_args can coerce unknown
8620  * constants in a more intelligent way, but not unknown Params.
8621  * This code also takes care of copying into the right context.
8622  * Note we assume 'unknown' has the representation of C-string.
8623  */
8624  ppd->types[i] = TEXTOID;
8625  if (!isnull)
8627  }
8628  /* pass-by-ref non null values must be copied into stmt_mcontext */
8629  else if (!isnull)
8630  {
8631  int16 typLen;
8632  bool typByVal;
8633 
8634  get_typlenbyval(ppd->types[i], &typLen, &typByVal);
8635  if (!typByVal)
8636  ppd->values[i] = datumCopy(ppd->values[i], typByVal, typLen);
8637  }
8638 
8639  MemoryContextSwitchTo(oldcontext);
8640 
8641  exec_eval_cleanup(estate);
8642 
8643  i++;
8644  }
8645 
8646  return ppd;
8647 }
signed short int16
Definition: c.h:354
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4046
Datum * values
Definition: pl_exec.c:58
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:355
#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:5788
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1514
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
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:2139
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
int i
#define CStringGetTextDatum(s)
Definition: builtins.h:87

◆ exec_for_query()

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

Definition at line 5935 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().

5937 {
5938  PLpgSQL_variable *var;
5939  SPITupleTable *tuptab;
5940  bool found = false;
5941  int rc = PLPGSQL_RC_OK;
5942  uint64 previous_id = INVALID_TUPLEDESC_IDENTIFIER;
5943  bool tupdescs_match = true;
5944  uint64 n;
5945 
5946  /* Fetch loop variable's datum entry */
5947  var = (PLpgSQL_variable *) estate->datums[stmt->var->dno];
5948 
5949  /*
5950  * Make sure the portal doesn't get closed by the user statements we
5951  * execute.
5952  */
5953  PinPortal(portal);
5954 
5955  /*
5956  * Fetch the initial tuple(s). If prefetching is allowed then we grab a
5957  * few more rows to avoid multiple trips through executor startup
5958  * overhead.
5959  */
5960  SPI_cursor_fetch(portal, true, prefetch_ok ? 10 : 1);
5961  tuptab = SPI_tuptable;
5962  n = SPI_processed;
5963 
5964  /*
5965  * If the query didn't return any rows, set the target to NULL and fall
5966  * through with found = false.
5967  */
5968  if (n == 0)
5969  {
5970  exec_move_row(estate, var, NULL, tuptab->tupdesc);
5971  exec_eval_cleanup(estate);
5972  }
5973  else
5974  found = true; /* processed at least one tuple */
5975 
5976  /*
5977  * Now do the loop
5978  */
5979  while (n > 0)
5980  {
5981  uint64 i;
5982 
5983  for (i = 0; i < n; i++)
5984  {
5985  /*
5986  * Assign the tuple to the target. Here, because we know that all
5987  * loop iterations should be assigning the same tupdesc, we can
5988  * optimize away repeated creations of expanded records with
5989  * identical tupdescs. Testing for changes of er_tupdesc_id is
5990  * reliable even if the loop body contains assignments that
5991  * replace the target's value entirely, because it's assigned from
5992  * a process-global counter. The case where the tupdescs don't
5993  * match could possibly be handled more efficiently than this
5994  * coding does, but it's not clear extra effort is worthwhile.
5995  */
5996  if (var->dtype == PLPGSQL_DTYPE_REC)
5997  {
5998  PLpgSQL_rec *rec = (PLpgSQL_rec *) var;
5999 
6000  if (rec->erh &&
6001  rec->erh->er_tupdesc_id == previous_id &&
6002  tupdescs_match)
6003  {
6004  /* Only need to assign a new tuple value */
6005  expanded_record_set_tuple(rec->erh, tuptab->vals[i],
6006  true, !estate->atomic);
6007  }
6008  else
6009  {
6010  /*
6011  * First time through, or var's tupdesc changed in loop,
6012  * or we have to do it the hard way because type coercion
6013  * is needed.
6014  */
6015  exec_move_row(estate, var,
6016  tuptab->vals[i], tuptab->tupdesc);
6017 
6018  /*
6019  * Check to see if physical assignment is OK next time.
6020  * Once the tupdesc comparison has failed once, we don't
6021  * bother rechecking in subsequent loop iterations.
6022  */
6023  if (tupdescs_match)
6024  {
6025  tupdescs_match =
6026  (rec->rectypeid == RECORDOID ||
6027  rec->rectypeid == tuptab->tupdesc->tdtypeid ||
6028  compatible_tupdescs(tuptab->tupdesc,
6030  }
6031  previous_id = rec->erh->er_tupdesc_id;
6032  }
6033  }
6034  else
6035  exec_move_row(estate, var, tuptab->vals[i], tuptab->tupdesc);
6036 
6037  exec_eval_cleanup(estate);
6038 
6039  /*
6040  * Execute the statements
6041  */
6042  rc = exec_stmts(estate, stmt->body);
6043 
6044  LOOP_RC_PROCESSING(stmt->label, goto loop_exit);
6045  }
6046 
6047  SPI_freetuptable(tuptab);
6048 
6049  /*
6050  * Fetch more tuples. If prefetching is allowed, grab 50 at a time.
6051  */
6052  SPI_cursor_fetch(portal, true, prefetch_ok ? 50 : 1);
6053  tuptab = SPI_tuptable;
6054  n = SPI_processed;
6055  }
6056 
6057 loop_exit:
6058 
6059  /*
6060  * Release last group of tuples (if any)
6061  */
6062  SPI_freetuptable(tuptab);
6063 
6064  UnpinPortal(portal);
6065 
6066  /*
6067  * Set the FOUND variable to indicate the result of executing the loop
6068  * (namely, whether we looped one or more times). This must be set last so
6069  * that it does not interfere with the value of the FOUND variable inside
6070  * the loop processing itself.
6071  */
6072  exec_set_found(estate, found);
6073 
6074  return rc;
6075 }
void UnpinPortal(Portal portal)
Definition: portalmem.c:379
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:404
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4046
HeapTuple * vals
Definition: spi.h:26
#define INVALID_TUPLEDESC_IDENTIFIER
Definition: typcache.h:148
uint64 SPI_processed
Definition: spi.c:45
PLpgSQL_datum ** datums
Definition: plpgsql.h:1082
void PinPortal(Portal portal)
Definition: portalmem.c:370
#define LOOP_RC_PROCESSING(looplabel, exit_action)
Definition: pl_exec.c:205
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:7361
TupleDesc tupdesc
Definition: spi.h:25
PLpgSQL_datum_type dtype
Definition: plpgsql.h:279
PLpgSQL_variable * var
Definition: plpgsql.h:717
static void exec_set_found(PLpgSQL_execstate *estate, bool state)
Definition: pl_exec.c:8304
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:6817
int i
void SPI_cursor_fetch(Portal portal, bool forward, long count)
Definition: spi.c:1533
Oid rectypeid
Definition: plpgsql.h:397
static int exec_stmts(PLpgSQL_execstate *estate, List *stmts)
Definition: pl_exec.c:1925

◆ exec_init_tuple_store()

static void exec_init_tuple_store ( PLpgSQL_execstate estate)
static

Definition at line 3590 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().

3591 {
3592  ReturnSetInfo *rsi = estate->rsi;
3593  MemoryContext oldcxt;
3594  ResourceOwner oldowner;
3595 
3596  /*
3597  * Check caller can handle a set result in the way we want
3598  */
3599  if (!rsi || !IsA(rsi, ReturnSetInfo) ||
3600  (rsi->allowedModes & SFRM_Materialize) == 0 ||
3601  rsi->expectedDesc == NULL)
3602  ereport(ERROR,
3603  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3604  errmsg("set-valued function called in context that cannot accept a set")));
3605 
3606  /*
3607  * Switch to the right memory context and resource owner for storing the
3608  * tuplestore for return set. If we're within a subtransaction opened for
3609  * an exception-block, for example, we must still create the tuplestore in
3610  * the resource owner that was active when this function was entered, and
3611  * not in the subtransaction resource owner.
3612  */
3613  oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
3614  oldowner = CurrentResourceOwner;
3616 
3617  estate->tuple_store =
3619  false, work_mem);
3620 
3621  CurrentResourceOwner = oldowner;
3622  MemoryContextSwitchTo(oldcxt);
3623 
3624  estate->tuple_store_desc = rsi->expectedDesc;
3625 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
ResourceOwner tuple_store_owner
Definition: plpgsql.h:1070
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:610
TupleDesc expectedDesc
Definition: execnodes.h:304
TupleDesc tuple_store_desc
Definition: plpgsql.h:1068
#define ERROR
Definition: elog.h:43
MemoryContext tuple_store_cxt
Definition: plpgsql.h:1069
ReturnSetInfo * rsi
Definition: plpgsql.h:1071
Tuplestorestate * tuple_store
Definition: plpgsql.h:1067
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
int work_mem
Definition: globals.c:121
#define ereport(elevel,...)
Definition: elog.h:144
int allowedModes
Definition: execnodes.h:305
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ exec_move_row()

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

Definition at line 6817 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().

6820 {
6821  ExpandedRecordHeader *newerh = NULL;
6822 
6823  /*
6824  * If target is RECORD, we may be able to avoid field-by-field processing.
6825  */
6826  if (target->dtype == PLPGSQL_DTYPE_REC)
6827  {
6828  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
6829 
6830  /*
6831  * If we have no source tupdesc, just set the record variable to NULL.
6832  * (If we have a source tupdesc but not a tuple, we'll set the
6833  * variable to a row of nulls, instead. This is odd perhaps, but
6834  * backwards compatible.)
6835  */
6836  if (tupdesc == NULL)
6837  {
6838  if (rec->datatype &&
6839  rec->datatype->typtype == TYPTYPE_DOMAIN)
6840  {
6841  /*
6842  * If it's a composite domain, NULL might not be a legal
6843  * value, so we instead need to make an empty expanded record
6844  * and ensure that domain type checking gets done. If there
6845  * is already an expanded record, piggyback on its lookups.
6846  */
6847  newerh = make_expanded_record_for_rec(estate, rec,
6848  NULL, rec->erh);
6849  expanded_record_set_tuple(newerh, NULL, false, false);
6850  assign_record_var(estate, rec, newerh);
6851  }
6852  else
6853  {
6854  /* Just clear it to NULL */
6855  if (rec->erh)
6857  rec->erh = NULL;
6858  }
6859  return;
6860  }
6861 
6862  /*
6863  * Build a new expanded record with appropriate tupdesc.
6864  */
6865  newerh = make_expanded_record_for_rec(estate, rec, tupdesc, NULL);
6866 
6867  /*
6868  * If the rowtypes match, or if we have no tuple anyway, we can
6869  * complete the assignment without field-by-field processing.
6870  *
6871  * The tests here are ordered more or less in order of cheapness. We
6872  * can easily detect it will work if the target is declared RECORD or
6873  * has the same typeid as the source. But when assigning from a query
6874  * result, it's common to have a source tupdesc that's labeled RECORD
6875  * but is actually physically compatible with a named-composite-type
6876  * target, so it's worth spending extra cycles to check for that.
6877  */
6878  if (rec->rectypeid == RECORDOID ||
6879  rec->rectypeid == tupdesc->tdtypeid ||
6880  !HeapTupleIsValid(tup) ||
6882  {
6883  if (!HeapTupleIsValid(tup))
6884  {
6885  /* No data, so force the record into all-nulls state */
6887  }
6888  else
6889  {
6890  /* No coercion is needed, so just assign the row value */
6891  expanded_record_set_tuple(newerh, tup, true, !estate->atomic);
6892  }
6893 
6894  /* Complete the assignment */
6895  assign_record_var(estate, rec, newerh);
6896 
6897  return;
6898  }
6899  }
6900 
6901  /*
6902  * Otherwise, deconstruct the tuple and do field-by-field assignment,
6903  * using exec_move_row_from_fields.
6904  */
6905  if (tupdesc && HeapTupleIsValid(tup))
6906  {
6907  int td_natts = tupdesc->natts;
6908  Datum *values;
6909  bool *nulls;
6910  Datum values_local[64];
6911  bool nulls_local[64];
6912 
6913  /*
6914  * Need workspace arrays. If td_natts is small enough, use local
6915  * arrays to save doing a palloc. Even if it's not small, we can
6916  * allocate both the Datum and isnull arrays in one palloc chunk.
6917  */
6918  if (td_natts <= lengthof(values_local))
6919  {
6920  values = values_local;
6921  nulls = nulls_local;
6922  }
6923  else
6924  {
6925  char *chunk;
6926 
6927  chunk = eval_mcontext_alloc(estate,
6928  td_natts * (sizeof(Datum) + sizeof(bool)));
6929  values = (Datum *) chunk;
6930  nulls = (bool *) (chunk + td_natts * sizeof(Datum));
6931  }
6932 
6933  heap_deform_tuple(tup, tupdesc, values, nulls);
6934 
6935  exec_move_row_from_fields(estate, target, newerh,
6936  values, nulls, tupdesc);
6937  }
6938  else
6939  {
6940  /*
6941  * Assign all-nulls.
6942  */
6943  exec_move_row_from_fields(estate, target, newerh,
6944  NULL, NULL, NULL);
6945  }
6946 }
PLpgSQL_type * datatype
Definition: plpgsql.h:396
static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
Definition: pl_exec.c:8556
void expanded_record_set_tuple(ExpandedRecordHeader *erh, HeapTuple tuple, bool copy, bool expand_external)
ExpandedRecordHeader * erh
Definition: plpgsql.h:404
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:7095
#define lengthof(array)
Definition: c.h:668
static ExpandedRecordHeader * make_expanded_record_for_rec(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, TupleDesc srctupdesc, ExpandedRecordHeader *srcerh)
Definition: pl_exec.c:7032
#define eval_mcontext_alloc(estate, sz)
Definition: pl_exec.c:140
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:7361
void DeleteExpandedObject(Datum d)
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
PLpgSQL_datum_type dtype
Definition: plpgsql.h:279
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:397
#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 7491 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().

7494 {
7495  /* Check to see if source is an expanded record */
7497  {
7499  ExpandedRecordHeader *newerh = NULL;
7500 
7501  Assert(erh->er_magic == ER_MAGIC);
7502 
7503  /* These cases apply if the target is record not row... */
7504  if (target->dtype == PLPGSQL_DTYPE_REC)
7505  {
7506  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7507 
7508  /*
7509  * If it's the same record already stored in the variable, do
7510  * nothing. This would happen only in silly cases like "r := r",
7511  * but we need some check to avoid possibly freeing the variable's
7512  * live value below. Note that this applies even if what we have
7513  * is a R/O pointer.
7514  */
7515  if (erh == rec->erh)
7516  return;
7517 
7518  /*
7519  * Make sure rec->rectypeid is up-to-date before using it.
7520  */
7521  revalidate_rectypeid(rec);
7522 
7523  /*
7524  * If we have a R/W pointer, we're allowed to just commandeer
7525  * ownership of the expanded record. If it's of the right type to
7526  * put into the record variable, do that. (Note we don't accept
7527  * an expanded record of a composite-domain type as a RECORD
7528  * value. We'll treat it as the base composite type instead;
7529  * compare logic in make_expanded_record_for_rec.)
7530  */
7532  (rec->rectypeid == erh->er_decltypeid ||
7533  (rec->rectypeid == RECORDOID &&
7534  !ExpandedRecordIsDomain(erh))))
7535  {
7536  assign_record_var(estate, rec, erh);
7537  return;
7538  }
7539 
7540  /*
7541  * If we already have an expanded record object in the target
7542  * variable, and the source record contains a valid tuple
7543  * representation with the right rowtype, then we can skip making
7544  * a new expanded record and just assign the tuple with
7545  * expanded_record_set_tuple. (We can't do the equivalent if we
7546  * have to do field-by-field assignment, since that wouldn't be
7547  * atomic if there's an error.) We consider that there's a
7548  * rowtype match only if it's the same named composite type or
7549  * same registered rowtype; checking for matches of anonymous
7550  * rowtypes would be more expensive than this is worth.
7551  */
7552  if (rec->erh &&
7553  (erh->flags & ER_FLAG_FVALUE_VALID) &&
7554  erh->er_typeid == rec->erh->er_typeid &&
7555  (erh->er_typeid != RECORDOID ||
7556  (erh->er_typmod == rec->erh->er_typmod &&
7557  erh->er_typmod >= 0)))
7558  {
7560  true, !estate->atomic);
7561  return;
7562  }
7563 
7564  /*
7565  * Otherwise we're gonna need a new expanded record object. Make
7566  * it here in hopes of piggybacking on the source object's
7567  * previous typcache lookup.
7568  */
7569  newerh = make_expanded_record_for_rec(estate, rec, NULL, erh);
7570 
7571  /*
7572  * If the expanded record contains a valid tuple representation,
7573  * and we don't need rowtype conversion, then just copying the
7574  * tuple is probably faster than field-by-field processing. (This
7575  * isn't duplicative of the previous check, since here we will
7576  * catch the case where the record variable was previously empty.)
7577  */
7578  if ((erh->flags & ER_FLAG_FVALUE_VALID) &&
7579  (rec->rectypeid == RECORDOID ||
7580  rec->rectypeid == erh->er_typeid))
7581  {
7582  expanded_record_set_tuple(newerh, erh->fvalue,
7583  true, !estate->atomic);
7584  assign_record_var(estate, rec, newerh);
7585  return;
7586  }
7587 
7588  /*
7589  * Need to special-case empty source record, else code below would
7590  * leak newerh.
7591  */
7592  if (ExpandedRecordIsEmpty(erh))
7593  {
7594  /* Set newerh to a row of NULLs */
7596  assign_record_var(estate, rec, newerh);
7597  return;
7598  }
7599  } /* end of record-target-only cases */
7600 
7601  /*
7602  * If the source expanded record is empty, we should treat that like a
7603  * NULL tuple value. (We're unlikely to see such a case, but we must
7604  * check this; deconstruct_expanded_record would cause a change of
7605  * logical state, which is not OK.)
7606  */
7607  if (ExpandedRecordIsEmpty(erh))
7608  {
7609  exec_move_row(estate, target, NULL,
7611  return;
7612  }
7613 
7614  /*
7615  * Otherwise, ensure that the source record is deconstructed, and
7616  * assign from its field values.
7617  */
7619  exec_move_row_from_fields(estate, target, newerh,
7620  erh->dvalues, erh->dnulls,
7622  }
7623  else
7624  {
7625  /*
7626  * Nope, we've got a plain composite Datum. Deconstruct it; but we
7627  * don't use deconstruct_composite_datum(), because we may be able to
7628  * skip calling lookup_rowtype_tupdesc().
7629  */
7630  HeapTupleHeader td;
7631  HeapTupleData tmptup;
7632  Oid tupType;
7633  int32 tupTypmod;
7634  TupleDesc tupdesc;
7635  MemoryContext oldcontext;
7636 
7637  /* Ensure that any detoasted data winds up in the eval_mcontext */
7638  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7639  /* Get tuple body (note this could involve detoasting) */
7641  MemoryContextSwitchTo(oldcontext);
7642 
7643  /* Build a temporary HeapTuple control structure */
7644  tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
7645  ItemPointerSetInvalid(&(tmptup.t_self));
7646  tmptup.t_tableOid = InvalidOid;
7647  tmptup.t_data = td;
7648 
7649  /* Extract rowtype info */
7650  tupType = HeapTupleHeaderGetTypeId(td);
7651  tupTypmod = HeapTupleHeaderGetTypMod(td);
7652 
7653  /* Now, if the target is record not row, maybe we can optimize ... */
7654  if (target->dtype == PLPGSQL_DTYPE_REC)
7655  {
7656  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7657 
7658  /*
7659  * If we already have an expanded record object in the target
7660  * variable, and the source datum has a matching rowtype, then we
7661  * can skip making a new expanded record and just assign the tuple
7662  * with expanded_record_set_tuple. We consider that there's a
7663  * rowtype match only if it's the same named composite type or
7664  * same registered rowtype. (Checking to reject an anonymous
7665  * rowtype here should be redundant, but let's be safe.)
7666  */
7667  if (rec->erh &&
7668  tupType == rec->erh->er_typeid &&
7669  (tupType != RECORDOID ||
7670  (tupTypmod == rec->erh->er_typmod &&
7671  tupTypmod >= 0)))
7672  {
7673  expanded_record_set_tuple(rec->erh, &tmptup,
7674  true, !estate->atomic);
7675  return;
7676  }
7677 
7678  /*
7679  * If the source datum has a rowtype compatible with the target
7680  * variable, just build a new expanded record and assign the tuple
7681  * into it. Using make_expanded_record_from_typeid() here saves
7682  * one typcache lookup compared to the code below.
7683  */
7684  if (rec->rectypeid == RECORDOID || rec->rectypeid == tupType)
7685  {
7686  ExpandedRecordHeader *newerh;
7687  MemoryContext mcontext = get_eval_mcontext(estate);
7688 
7689  newerh = make_expanded_record_from_typeid(tupType, tupTypmod,
7690  mcontext);
7691  expanded_record_set_tuple(newerh, &tmptup,
7692  true, !estate->atomic);
7693  assign_record_var(estate, rec, newerh);
7694  return;
7695  }
7696 
7697  /*
7698  * Otherwise, we're going to need conversion, so fall through to
7699  * do it the hard way.
7700  */
7701  }
7702 
7703  /*
7704  * ROW target, or unoptimizable RECORD target, so we have to expend a
7705  * lookup to obtain the source datum's tupdesc.
7706  */
7707  tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
7708 
7709  /* Do the move */
7710  exec_move_row(estate, target, &tmptup, tupdesc);
7711 
7712  /* Release tupdesc usage count */
7713  ReleaseTupleDesc(tupdesc);
7714  }
7715 }
#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:1710
static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
Definition: pl_exec.c:8556
void expanded_record_set_tuple(ExpandedRecordHeader *erh, HeapTuple tuple, bool copy, bool expand_external)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
ExpandedRecordHeader * erh
Definition: plpgsql.h:404
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:7095
unsigned int Oid
Definition: postgres_ext.h:31
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:294
signed int int32
Definition: c.h:355
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:7032
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:138
#define ER_MAGIC
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:458
#define InvalidOid
Definition: postgres_ext.h:36
static struct @143 value
#define Assert(condition)
Definition: c.h:738
PLpgSQL_datum_type dtype
Definition: plpgsql.h:279
#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:6817
static void revalidate_rectypeid(PLpgSQL_rec *rec)
Definition: pl_exec.c:6952
#define VARATT_IS_EXTERNAL_EXPANDED_RW(PTR)
Definition: postgres.h:320
Oid rectypeid
Definition: plpgsql.h:397
#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 7095 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().

7100 {
7101  int td_natts = tupdesc ? tupdesc->natts : 0;
7102  int fnum;
7103  int anum;
7104  int strict_multiassignment_level = 0;
7105 
7106  /*
7107  * The extra check strict strict_multi_assignment can be active, only when
7108  * input tupdesc is specified.
7109  */
7110  if (tupdesc != NULL)
7111  {
7113  strict_multiassignment_level = ERROR;
7114  else if (plpgsql_extra_warnings & PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT)
7115  strict_multiassignment_level = WARNING;
7116  }
7117 
7118  /* Handle RECORD-target case */
7119  if (target->dtype == PLPGSQL_DTYPE_REC)
7120  {
7121  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7122  TupleDesc var_tupdesc;
7123  Datum newvalues_local[64];
7124  bool newnulls_local[64];
7125 
7126  Assert(newerh != NULL); /* caller must have built new object */
7127 
7128  var_tupdesc = expanded_record_get_tupdesc(newerh);
7129 
7130  /*
7131  * Coerce field values if needed. This might involve dealing with
7132  * different sets of dropped columns and/or coercing individual column
7133  * types. That's sort of a pain, but historically plpgsql has allowed
7134  * it, so we preserve the behavior. However, it's worth a quick check
7135  * to see if the tupdescs are identical. (Since expandedrecord.c
7136  * prefers to use refcounted tupdescs from the typcache, expanded
7137  * records with the same rowtype will have pointer-equal tupdescs.)
7138  */
7139  if (var_tupdesc != tupdesc)
7140  {
7141  int vtd_natts = var_tupdesc->natts;
7142  Datum *newvalues;
7143  bool *newnulls;
7144 
7145  /*
7146  * Need workspace arrays. If vtd_natts is small enough, use local
7147  * arrays to save doing a palloc. Even if it's not small, we can
7148  * allocate both the Datum and isnull arrays in one palloc chunk.
7149  */
7150  if (vtd_natts <= lengthof(newvalues_local))
7151  {
7152  newvalues = newvalues_local;
7153  newnulls = newnulls_local;
7154  }
7155  else
7156  {
7157  char *chunk;
7158 
7159  chunk = eval_mcontext_alloc(estate,
7160  vtd_natts * (sizeof(Datum) + sizeof(bool)));
7161  newvalues = (Datum *) chunk;
7162  newnulls = (bool *) (chunk + vtd_natts * sizeof(Datum));
7163  }
7164 
7165  /* Walk over destination columns */
7166  anum = 0;
7167  for (fnum = 0; fnum < vtd_natts; fnum++)
7168  {
7169  Form_pg_attribute attr = TupleDescAttr(var_tupdesc, fnum);
7170  Datum value;
7171  bool isnull;
7172  Oid valtype;
7173  int32 valtypmod;
7174 
7175  if (attr->attisdropped)
7176  {
7177  /* expanded_record_set_fields should ignore this column */
7178  continue; /* skip dropped column in record */
7179  }
7180 
7181  while (anum < td_natts &&
7182  TupleDescAttr(tupdesc, anum)->attisdropped)
7183  anum++; /* skip dropped column in tuple */
7184 
7185  if (anum < td_natts)
7186  {
7187  value = values[anum];
7188  isnull = nulls[anum];
7189  valtype = TupleDescAttr(tupdesc, anum)->atttypid;
7190  valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
7191  anum++;
7192  }
7193  else
7194  {
7195  /* no source for destination column */
7196  value = (Datum) 0;
7197  isnull = true;
7198  valtype = UNKNOWNOID;
7199  valtypmod = -1;
7200 
7201  /* When source value is missing */
7202  if (strict_multiassignment_level)
7203  ereport(strict_multiassignment_level,
7204  (errcode(ERRCODE_DATATYPE_MISMATCH),
7205  errmsg("number of source and target fields in assignment does not match"),
7206  /* translator: %s represents a name of an extra check */
7207  errdetail("%s check of %s is active.",
7208  "strict_multi_assignment",
7209  strict_multiassignment_level == ERROR ? "extra_errors" :
7210  "extra_warnings"),
7211  errhint("Make sure the query returns the exact list of columns.")));
7212  }
7213 
7214  /* Cast the new value to the right type, if needed. */
7215  newvalues[fnum] = exec_cast_value(estate,
7216  value,
7217  &isnull,
7218  valtype,
7219  valtypmod,
7220  attr->atttypid,
7221  attr->atttypmod);
7222  newnulls[fnum] = isnull;
7223  }
7224 
7225  /*
7226  * When strict_multiassignment extra check is active, then ensure
7227  * there are no unassigned source attributes.
7228  */
7229  if (strict_multiassignment_level && anum < td_natts)
7230  {
7231  /* skip dropped columns in the source descriptor */
7232  while (anum < td_natts &&
7233  TupleDescAttr(tupdesc, anum)->attisdropped)
7234  anum++;
7235 
7236  if (anum < td_natts)
7237  ereport(strict_multiassignment_level,
7238  (errcode(ERRCODE_DATATYPE_MISMATCH),
7239  errmsg("number of source and target fields in assignment does not match"),
7240  /* translator: %s represents a name of an extra check */
7241  errdetail("%s check of %s is active.",
7242  "strict_multi_assignment",
7243  strict_multiassignment_level == ERROR ? "extra_errors" :
7244  "extra_warnings"),
7245  errhint("Make sure the query returns the exact list of columns.")));
7246  }
7247 
7248  values = newvalues;
7249  nulls = newnulls;
7250  }
7251 
7252  /* Insert the coerced field values into the new expanded record */
7253  expanded_record_set_fields(newerh, values, nulls, !estate->atomic);
7254 
7255  /* Complete the assignment */
7256  assign_record_var(estate, rec, newerh);
7257 
7258  return;
7259  }
7260 
7261  /* newerh should not have been passed in non-RECORD cases */
7262  Assert(newerh == NULL);
7263 
7264  /*
7265  * For a row, we assign the individual field values to the variables the
7266  * row points to.
7267  *
7268  * NOTE: both this code and the record code above silently ignore extra
7269  * columns in the source and assume NULL for missing columns. This is
7270  * pretty dubious but it's the historical behavior.
7271  *
7272  * If we have no input data at all, we'll assign NULL to all columns of
7273  * the row variable.
7274  */
7275  if (target->dtype == PLPGSQL_DTYPE_ROW)
7276  {
7277  PLpgSQL_row *row = (PLpgSQL_row *) target;
7278 
7279  anum = 0;
7280  for (fnum = 0; fnum < row->nfields; fnum++)
7281  {
7282  PLpgSQL_var *var;
7283  Datum value;
7284  bool isnull;
7285  Oid valtype;
7286  int32 valtypmod;
7287 
7288  var = (PLpgSQL_var *) (estate->datums[row->varnos[fnum]]);
7289 
7290  while (anum < td_natts &&
7291  TupleDescAttr(tupdesc, anum)->attisdropped)
7292  anum++; /* skip dropped column in tuple */
7293 
7294  if (anum < td_natts)
7295  {
7296  value = values[anum];
7297  isnull = nulls[anum];
7298  valtype = TupleDescAttr(tupdesc, anum)->atttypid;
7299  valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
7300  anum++;
7301  }
7302  else
7303  {
7304  /* no source for destination column */
7305  value = (Datum) 0;
7306  isnull = true;
7307  valtype = UNKNOWNOID;
7308  valtypmod = -1;
7309 
7310  if (strict_multiassignment_level)
7311  ereport(strict_multiassignment_level,
7312  (errcode(ERRCODE_DATATYPE_MISMATCH),
7313  errmsg("number of source and target fields in assignment does not match"),
7314  /* translator: %s represents a name of an extra check */
7315  errdetail("%s check of %s is active.",
7316  "strict_multi_assignment",
7317  strict_multiassignment_level == ERROR ? "extra_errors" :
7318  "extra_warnings"),
7319  errhint("Make sure the query returns the exact list of columns.")));
7320  }
7321 
7322  exec_assign_value(estate, (PLpgSQL_datum *) var,
7323  value, isnull, valtype, valtypmod);
7324  }
7325 
7326  /*
7327  * When strict_multiassignment extra check is active, ensure there are
7328  * no unassigned source attributes.
7329  */
7330  if (strict_multiassignment_level && anum < td_natts)
7331  {
7332  while (anum < td_natts &&
7333  TupleDescAttr(tupdesc, anum)->attisdropped)
7334  anum++; /* skip dropped column in tuple */
7335 
7336  if (anum < td_natts)
7337  ereport(strict_multiassignment_level,
7338  (errcode(ERRCODE_DATATYPE_MISMATCH),
7339  errmsg("number of source and target fields in assignment does not match"),
7340  /* translator: %s represents a name of an extra check */
7341  errdetail("%s check of %s is active.",
7342  "strict_multi_assignment",
7343  strict_multiassignment_level == ERROR ? "extra_errors" :
7344  "extra_warnings"),
7345  errhint("Make sure the query returns the exact list of columns.")));
7346  }
7347 
7348  return;
7349  }
7350 
7351  elog(ERROR, "unsupported target type: %d", target->dtype);
7352 }
int errhint(const char *fmt,...)
Definition: elog.c:1071
static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
Definition: pl_exec.c:8556
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT
Definition: plpgsql.h:1209
int plpgsql_extra_errors
Definition: pl_handler.c:53
int errcode(int sqlerrcode)
Definition: elog.c:610
void expanded_record_set_fields(ExpandedRecordHeader *erh, const Datum *newValues, const bool *isnulls, bool expand_external)
#define lengthof(array)
Definition: c.h:668
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:355
PLpgSQL_datum ** datums
Definition: plpgsql.h:1082
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7788
#define ERROR
Definition: elog.h:43
#define eval_mcontext_alloc(estate, sz)
Definition: pl_exec.c:140
int plpgsql_extra_warnings
Definition: pl_handler.c:52
int errdetail(const char *fmt,...)
Definition: elog.c:957
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
int * varnos
Definition: plpgsql.h:373
#define WARNING
Definition: elog.h:40
uintptr_t Datum
Definition: postgres.h:367
static struct @143 value
#define ereport(elevel,...)
Definition: elog.h:144
#define Assert(condition)
Definition: c.h:738
int nfields
Definition: plpgsql.h:371
PLpgSQL_datum_type dtype
Definition: plpgsql.h:279
static Datum values[MAXATTR]
Definition: bootstrap.c:167
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:4992

◆ exec_prepare_plan()

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

Definition at line 4067 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().

4070 {
4071  SPIPlanPtr plan;
4072 
4073  /*
4074  * The grammar can't conveniently set expr->func while building the parse
4075  * tree, so make sure it's set before parser hooks need it.
4076  */
4077  expr->func = estate->func;
4078 
4079  /*
4080  * Generate and save the plan
4081  */
4082  plan = SPI_prepare_params(expr->query,
4084  (void *) expr,
4085  cursorOptions);
4086  if (plan == NULL)
4087  elog(ERROR, "SPI_prepare_params failed for \"%s\": %s",
4089  if (keepplan)
4090  SPI_keepplan(plan);
4091  expr->plan = plan;
4092 
4093  /* Check to see if it's a simple expression */
4094  exec_simple_check_plan(estate, expr);
4095 
4096  /*
4097  * Mark expression as not using a read-write param. exec_assign_value has
4098  * to take steps to override this if appropriate; that seems cleaner than
4099  * adding parameters to all other callers.
4100  */
4101  expr->rwparam = -1;
4102 }
char * query
Definition: plpgsql.h:221
PLpgSQL_function * func
Definition: plpgsql.h:1047
static void exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:8000
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:1699
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:1074
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:214
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 5871 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().

5873 {
5874  ParamListInfo paramLI;
5875  int rc;
5876 
5877  /*
5878  * On the first call for this expression generate the plan.
5879  *
5880  * If we don't need to return a portal, then we're just going to execute
5881  * the query once, which means it's OK to use a parallel plan, even if the
5882  * number of rows being fetched is limited. If we do need to return a
5883  * portal, the caller might do cursor operations, which parallel query
5884  * can't support.
5885  */
5886  if (expr->plan == NULL)
5887  exec_prepare_plan(estate, expr,
5888  portalP == NULL ? CURSOR_OPT_PARALLEL_OK : 0, true);
5889 
5890  /*
5891  * Set up ParamListInfo to pass to executor
5892  */
5893  paramLI = setup_param_list(estate, expr);
5894 
5895  /*
5896  * If a portal was requested, put the query and paramlist into the portal
5897  */
5898  if (portalP != NULL)
5899  {
5900  *portalP = SPI_cursor_open_with_paramlist(NULL, expr->plan,
5901  paramLI,
5902  estate->readonly_func);
5903  if (*portalP == NULL)
5904  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
5906  exec_eval_cleanup(estate);
5907  return SPI_OK_CURSOR;
5908  }
5909 
5910  /*
5911  * Execute the query
5912  */
5913  rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
5914  estate->readonly_func, maxtuples);
5915  if (rc != SPI_OK_SELECT)
5916  ereport(ERROR,
5917  (errcode(ERRCODE_SYNTAX_ERROR),
5918  errmsg("query \"%s\" is not a SELECT", expr->query)));
5919 
5920  /* Save query results for eventual cleanup */
5921  Assert(estate->eval_tuptable == NULL);
5922  estate->eval_tuptable = SPI_tuptable;
5923  estate->eval_processed = SPI_processed;
5924 
5925  return rc;
5926 }
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:4067
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1107
uint64 eval_processed
Definition: plpgsql.h:1108
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:610
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4046
#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:1699
static ParamListInfo setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:6324
#define SPI_OK_SELECT
Definition: spi.h:57
#define ereport(elevel,...)
Definition: elog.h:144
#define Assert(condition)
Definition: c.h:738
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2715
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214

◆ exec_save_simple_expr()

static void exec_save_simple_expr ( PLpgSQL_expr expr,
CachedPlan cplan 
)
static

Definition at line 8117 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_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(), 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().

8118 {
8119  PlannedStmt *stmt;
8120  Plan *plan;
8121  Expr *tle_expr;
8122 
8123  /*
8124  * Given the checks that exec_simple_check_plan did, none of the Asserts
8125  * here should ever fail.
8126  */
8127 
8128  /* Extract the single PlannedStmt */
8129  Assert(list_length(cplan->stmt_list) == 1);
8130  stmt = linitial_node(PlannedStmt, cplan->stmt_list);
8131  Assert(stmt->commandType == CMD_SELECT);
8132 
8133  /*
8134  * Ordinarily, the plan node should be a simple Result. However, if
8135  * force_parallel_mode is on, the planner might've stuck a Gather node
8136  * atop that. The simplest way to deal with this is to look through the
8137  * Gather node. The Gather node's tlist would normally contain a Var
8138  * referencing the child node's output, but it could also be a Param, or
8139  * it could be a Const that setrefs.c copied as-is.
8140  */
8141  plan = stmt->planTree;
8142  for (;;)
8143  {
8144  /* Extract the single tlist expression */
8145  Assert(list_length(plan->targetlist) == 1);
8146  tle_expr = castNode(TargetEntry, linitial(plan->targetlist))->expr;
8147 
8148  if (IsA(plan, Result))
8149  {
8150  Assert(plan->lefttree == NULL &&
8151  plan->righttree == NULL &&
8152  plan->initPlan == NULL &&
8153  plan->qual == NULL &&
8154  ((Result *) plan)->resconstantqual == NULL);
8155  break;
8156  }
8157  else if (IsA(plan, Gather))
8158  {
8159  Assert(plan->lefttree != NULL &&
8160  plan->righttree == NULL &&
8161  plan->initPlan == NULL &&
8162  plan->qual == NULL);
8163  /* If setrefs.c copied up a Const, no need to look further */
8164  if (IsA(tle_expr, Const))
8165  break;
8166  /* Otherwise, it had better be a Param or an outer Var */
8167  Assert(IsA(tle_expr, Param) || (IsA(tle_expr, Var) &&
8168  ((Var *) tle_expr)->varno == OUTER_VAR));
8169  /* Descend to the child node */
8170  plan = plan->lefttree;
8171  }
8172  else
8173  elog(ERROR, "unexpected plan node type: %d",
8174  (int) nodeTag(plan));
8175  }
8176 
8177  /*
8178  * Save the simple expression, and initialize state to "not valid in
8179  * current transaction".
8180  */
8181  expr->expr_simple_expr = tle_expr;
8182  expr->expr_simple_state = NULL;
8183  expr->expr_simple_in_use = false;
8185  /* Also stash away the expression result type */
8186  expr->expr_simple_type = exprType((Node *) tle_expr);
8187  expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
8188  /* We also want to remember if it is immutable or not */
8189  expr->expr_simple_mutable = contain_mutable_functions((Node *) tle_expr);
8190 }
List * qual
Definition: plannodes.h:143
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
#define castNode(_type_, nodeptr)
Definition: nodes.h:598
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:275
Definition: nodes.h:529
Definition: primnodes.h:181
#define linitial_node(type, l)
Definition: pg_list.h:198
struct Plan * planTree
Definition: plannodes.h:64
struct Plan * righttree
Definition: plannodes.h:145
#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:254
bool expr_simple_mutable
Definition: plpgsql.h:236
CmdType commandType
Definition: plannodes.h:46
LocalTransactionId expr_simple_lxid
Definition: plpgsql.h:256
#define Assert(condition)
Definition: c.h:738
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
static int list_length(const List *l)
Definition: pg_list.h:169
struct Plan * lefttree
Definition: plannodes.h:144
#define nodeTag(nodeptr)
Definition: nodes.h:534
List * targetlist
Definition: plannodes.h:142
int32 expr_simple_typmod
Definition: plpgsql.h:235
List * initPlan
Definition: plannodes.h:146
#define elog(elevel,...)
Definition: elog.h:214
#define InvalidLocalTransactionId
Definition: lock.h:68
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:647
List * stmt_list
Definition: plancache.h:149
bool expr_simple_in_use
Definition: plpgsql.h:255
#define OUTER_VAR
Definition: primnodes.h:172
Oid expr_simple_type
Definition: plpgsql.h:234

◆ exec_set_found()

static void exec_set_found ( PLpgSQL_execstate estate,
bool  state 
)
static

Definition at line 8304 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().

8305 {
8306  PLpgSQL_var *var;
8307 
8308  var = (PLpgSQL_var *) (estate->datums[estate->found_varno]);
8309  assign_simple_var(estate, var, BoolGetDatum(state), false, false);
8310 }
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8480
PLpgSQL_datum ** datums
Definition: plpgsql.h:1082
#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 8000 of file pl_exec.c.

References Assert, CachedPlanAllowsSimpleValidityCheck(), CMD_SELECT, Query::commandType, Query::cteList, Query::distinctClause, exec_save_simple_expr(), PLpgSQL_expr::expr_simple_expr, PLpgSQL_expr::expr_simple_plan, PLpgSQL_expr::expr_simple_plan_lxid, PLpgSQL_expr::expr_simple_plansource, 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(), PGPROC::lxid, MemoryContextSwitchTo(), MyProc, NIL, PLpgSQL_expr::plan, FromExpr::quals, CachedPlanSource::query_list, ReleaseCachedPlan(), Query::rtable, Query::setOperations, PLpgSQL_execstate::simple_eval_resowner, Query::sortClause, SPI_plan_get_cached_plan(), SPI_plan_get_plan_sources(), Query::targetList, and Query::windowClause.

Referenced by exec_prepare_plan().

8001 {
8002  List *plansources;
8003  CachedPlanSource *plansource;
8004  Query *query;
8005  CachedPlan *cplan;
8006  MemoryContext oldcontext;
8007 
8008  /*
8009  * Initialize to "not simple".
8010  */
8011  expr->expr_simple_expr = NULL;
8012 
8013  /*
8014  * Check the analyzed-and-rewritten form of the query to see if we will be
8015  * able to treat it as a simple expression. Since this function is only
8016  * called immediately after creating the CachedPlanSource, we need not
8017  * worry about the query being stale.
8018  */
8019 
8020  /*
8021  * We can only test queries that resulted in exactly one CachedPlanSource
8022  */
8023  plansources = SPI_plan_get_plan_sources(expr->plan);
8024  if (list_length(plansources) != 1)
8025  return;
8026  plansource = (CachedPlanSource *) linitial(plansources);
8027 
8028  /*
8029  * 1. There must be one single querytree.
8030  */
8031  if (list_length(plansource->query_list) != 1)
8032  return;
8033  query = (Query *) linitial(plansource->query_list);
8034 
8035  /*
8036  * 2. It must be a plain SELECT query without any input tables
8037  */
8038  if (!IsA(query, Query))
8039  return;
8040  if (query->commandType != CMD_SELECT)
8041  return;
8042  if (query->rtable != NIL)
8043  return;
8044 
8045  /*
8046  * 3. Can't have any subplans, aggregates, qual clauses either. (These
8047  * tests should generally match what inline_function() checks before
8048  * inlining a SQL function; otherwise, inlining could change our
8049  * conclusion about whether an expression is simple, which we don't want.)
8050  */
8051  if (query->hasAggs ||
8052  query->hasWindowFuncs ||
8053  query->hasTargetSRFs ||
8054  query->hasSubLinks ||
8055  query->cteList ||
8056  query->jointree->fromlist ||
8057  query->jointree->quals ||
8058  query->groupClause ||
8059  query->groupingSets ||
8060  query->havingQual ||
8061  query->windowClause ||
8062  query->distinctClause ||
8063  query->sortClause ||
8064  query->limitOffset ||
8065  query->limitCount ||
8066  query->setOperations)
8067  return;
8068 
8069  /*
8070  * 4. The query must have a single attribute as result
8071  */
8072  if (list_length(query->targetList) != 1)
8073  return;
8074 
8075  /*
8076  * OK, we can treat it as a simple plan.
8077  *
8078  * Get the generic plan for the query. If replanning is needed, do that
8079  * work in the eval_mcontext.
8080  */
8081  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
8082  cplan = SPI_plan_get_cached_plan(expr->plan);
8083  MemoryContextSwitchTo(oldcontext);
8084 
8085  /* Can't fail, because we checked for a single CachedPlanSource above */
8086  Assert(cplan != NULL);
8087 
8088  /*
8089  * Verify that plancache.c thinks the plan is simple enough to use
8090  * CachedPlanIsSimplyValid. Given the restrictions above, it's unlikely
8091  * that this could fail, but if it does, just treat plan as not simple. On
8092  * success, save a refcount on the plan in the simple-expression resowner.
8093  */
8094  if (CachedPlanAllowsSimpleValidityCheck(plansource, cplan,
8095  estate->simple_eval_resowner))
8096  {
8097  /* Remember that we have the refcount */
8098  expr->expr_simple_plansource = plansource;
8099  expr->expr_simple_plan = cplan;
8101 
8102  /* Share the remaining work with the replan code path */
8103  exec_save_simple_expr(expr, cplan);
8104  }
8105 
8106  /*
8107  * Release the plan refcount obtained by SPI_plan_get_cached_plan. (This
8108  * refcount is held by the wrong resowner, so we can't just repurpose it.)
8109  */
8110  ReleaseCachedPlan(cplan, true);
8111 }
Node * limitOffset
Definition: parsenodes.h:160
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
List * sortClause
Definition: parsenodes.h:158
ResourceOwner simple_eval_resowner
Definition: plpgsql.h:1096
FromExpr * jointree
Definition: parsenodes.h:138
PGPROC * MyProc
Definition: proc.c:67
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:1510
Node * quals
Definition: primnodes.h:1511
static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
Definition: pl_exec.c:8117
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:1792
#define linitial(l)
Definition: pg_list.h:195
List * rtable
Definition: parsenodes.h:137
List * distinctClause
Definition: parsenodes.h:156
CachedPlanSource * expr_simple_plansource
Definition: plpgsql.h:244
Node * limitCount
Definition: parsenodes.h:161
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1260
Expr * expr_simple_expr
Definition: plpgsql.h:233
bool CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1305
#define get_eval_mcontext(estate)
Definition: pl_exec.c:138
CachedPlan * expr_simple_plan
Definition: plpgsql.h:245
CmdType commandType
Definition: parsenodes.h:112
bool hasTargetSRFs
Definition: parsenodes.h:127
#define Assert(condition)
Definition: c.h:738
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:166
List * groupClause
Definition: parsenodes.h:148
bool hasSubLinks
Definition: parsenodes.h:128
List * SPI_plan_get_plan_sources(SPIPlanPtr plan)
Definition: spi.c:1776
List * query_list
Definition: plancache.h:111
LocalTransactionId expr_simple_plan_lxid
Definition: plpgsql.h:246
Node * havingQual
Definition: parsenodes.h:152
Definition: pg_list.h:50
LocalTransactionId lxid
Definition: proc.h:106

◆ exec_stmt()

static int exec_stmt ( PLpgSQL_execstate estate,
PLpgSQL_stmt stmt 
)
static

Definition at line 1959 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().

1960 {
1961  PLpgSQL_stmt *save_estmt;
1962  int rc = -1;
1963 
1964  save_estmt = estate->err_stmt;
1965  estate->err_stmt = stmt;
1966 
1967  /* Let the plugin know that we are about to execute this statement */
1968  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
1969  ((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt);
1970 
1972 
1973  switch (stmt->cmd_type)
1974  {
1975  case PLPGSQL_STMT_BLOCK:
1976  rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt);
1977  break;
1978 
1979  case PLPGSQL_STMT_ASSIGN:
1980  rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
1981  break;
1982 
1983  case PLPGSQL_STMT_PERFORM:
1984  rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt);
1985  break;
1986 
1987  case PLPGSQL_STMT_CALL:
1988  rc = exec_stmt_call(estate, (PLpgSQL_stmt_call *) stmt);
1989  break;
1990 
1991  case PLPGSQL_STMT_GETDIAG:
1992  rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt);
1993  break;
1994 
1995  case PLPGSQL_STMT_IF:
1996  rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);
1997  break;
1998 
1999  case PLPGSQL_STMT_CASE:
2000  rc = exec_stmt_case(estate, (PLpgSQL_stmt_case *) stmt);
2001  break;
2002 
2003  case PLPGSQL_STMT_LOOP:
2004  rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt);
2005  break;
2006 
2007  case PLPGSQL_STMT_WHILE:
2008  rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt);
2009  break;
2010 
2011  case PLPGSQL_STMT_FORI:
2012  rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt);
2013  break;
2014 
2015  case PLPGSQL_STMT_FORS:
2016  rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt);
2017  break;
2018 
2019  case PLPGSQL_STMT_FORC:
2020  rc = exec_stmt_forc(estate, (PLpgSQL_stmt_forc *) stmt);
2021  break;
2022 
2024  rc = exec_stmt_foreach_a(estate, (PLpgSQL_stmt_foreach_a *) stmt);
2025  break;
2026 
2027  case PLPGSQL_STMT_EXIT:
2028  rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt);
2029  break;
2030 
2031  case PLPGSQL_STMT_RETURN:
2032  rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt);
2033  break;
2034 
2036  rc = exec_stmt_return_next(estate, (PLpgSQL_stmt_return_next *) stmt);
2037  break;
2038 
2040  rc = exec_stmt_return_query(estate, (PLpgSQL_stmt_return_query *) stmt);
2041  break;
2042 
2043  case PLPGSQL_STMT_RAISE:
2044  rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt);
2045  break;
2046 
2047  case PLPGSQL_STMT_ASSERT:
2048  rc = exec_stmt_assert(estate, (PLpgSQL_stmt_assert *) stmt);
2049  break;
2050 
2051  case PLPGSQL_STMT_EXECSQL:
2052  rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt);
2053  break;
2054 
2056  rc = exec_stmt_dynexecute(estate, (PLpgSQL_stmt_dynexecute *) stmt);
2057  break;
2058 
2059  case PLPGSQL_STMT_DYNFORS:
2060  rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt);
2061  break;
2062 
2063  case PLPGSQL_STMT_OPEN:
2064  rc = exec_stmt_open(estate, (PLpgSQL_stmt_open *) stmt);
2065  break;
2066 
2067  case PLPGSQL_STMT_FETCH:
2068  rc = exec_stmt_fetch(estate, (PLpgSQL_stmt_fetch *) stmt);
2069  break;
2070 
2071  case PLPGSQL_STMT_CLOSE:
2072  rc = exec_stmt_close(estate, (PLpgSQL_stmt_close *) stmt);
2073  break;
2074 
2075  case PLPGSQL_STMT_COMMIT:
2076  rc = exec_stmt_commit(estate, (PLpgSQL_stmt_commit *) stmt);
2077  break;
2078 
2079  case PLPGSQL_STMT_ROLLBACK:
2080  rc = exec_stmt_rollback(estate, (PLpgSQL_stmt_rollback *) stmt);
2081  break;
2082 
2083  case PLPGSQL_STMT_SET:
2084  rc = exec_stmt_set(estate, (PLpgSQL_stmt_set *) stmt);
2085  break;
2086 
2087  default:
2088  estate->err_stmt = save_estmt;
2089  elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
2090  }
2091 
2092  /* Let the plugin know that we have finished executing this statement */
2093  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
2094  ((*plpgsql_plugin_ptr)->stmt_end) (estate, stmt);
2095 
2096  estate->err_stmt = save_estmt;
2097 
2098  return rc;
2099 }
static int exec_stmt_set(PLpgSQL_execstate *estate, PLpgSQL_stmt_set *stmt)
Definition: pl_exec.c:4902
static int exec_stmt_execsql(PLpgSQL_execstate *estate, PLpgSQL_stmt_execsql *stmt)
Definition: pl_exec.c:4113
static int exec_stmt_case(PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
Definition: pl_exec.c:2515
PLpgSQL_stmt * err_stmt
Definition: plpgsql.h:1112
static int exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
Definition: pl_exec.c:2139
static int exec_stmt_return_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_return_query *stmt)
Definition: pl_exec.c:3513
static int exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt)
Definition: pl_exec.c:2963
static int exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
Definition: pl_exec.c:4555
static int exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
Definition: pl_exec.c:4528
static int exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
Definition: pl_exec.c:2602
static int exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
Definition: pl_exec.c:2798
static int exec_stmt_assign(PLpgSQL_execstate *estate, PLpgSQL_stmt_assign *stmt)
Definition: pl_exec.c:2108
#define ERROR
Definition: elog.h:43
static int exec_stmt_rollback(PLpgSQL_execstate *estate, PLpgSQL_stmt_rollback *stmt)
Definition: pl_exec.c:4872
static int exec_stmt_assert(PLpgSQL_execstate *estate, PLpgSQL_stmt_assert *stmt)
Definition: pl_exec.c:3853
static int exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
Definition: pl_exec.c:3642
static int exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
Definition: pl_exec.c:2655
static int exec_stmt_dynexecute(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynexecute *stmt)
Definition: pl_exec.c:4338
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:2375
static int exec_stmt_exit(PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt)
Definition: pl_exec.c:3119
static int exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
Definition: pl_exec.c:3152
static int exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
Definition: pl_exec.c:2624
static int exec_stmt_commit(PLpgSQL_execstate *estate, PLpgSQL_stmt_commit *stmt)
Definition: pl_exec.c:4845
static int exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
Definition: pl_exec.c:4711
static int exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
Definition: pl_exec.c:1599
static int exec_stmt_return_next(PLpgSQL_execstate *estate, PLpgSQL_stmt_return_next *stmt)
Definition: pl_exec.c:3295
static int exec_stmt_close(PLpgSQL_execstate *estate, PLpgSQL_stmt_close *stmt)
Definition: pl_exec.c:4802
#define elog(elevel,...)
Definition: elog.h:214
static int exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
Definition: pl_exec.c:2485
static int exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
Definition: pl_exec.c:2124
PLpgSQL_stmt_type cmd_type
Definition: plpgsql.h:469
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
void(* stmt_end)(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
Definition: plpgsql.h:1155
void(* stmt_beg)(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
Definition: plpgsql.h:1154
static int exec_stmt_forc(PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt)
Definition: pl_exec.c:2827

◆ exec_stmt_assert()

static int exec_stmt_assert ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assert stmt 
)
static

Definition at line 3853 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().

3854 {
3855  bool value;
3856  bool isnull;
3857 
3858  /* do nothing when asserts are not enabled */
3859  if (!plpgsql_check_asserts)
3860  return PLPGSQL_RC_OK;
3861 
3862  value = exec_eval_boolean(estate, stmt->cond, &isnull);
3863  exec_eval_cleanup(estate);
3864 
3865  if (isnull || !value)
3866  {
3867  char *message = NULL;
3868 
3869  if (stmt->message != NULL)
3870  {
3871  Datum val;
3872  Oid typeid;
3873  int32 typmod;
3874 
3875  val = exec_eval_expr(estate, stmt->message,
3876  &isnull, &typeid, &typmod);
3877  if (!isnull)
3878  message = convert_value_to_string(estate, val, typeid);
3879  /* we mustn't do exec_eval_cleanup here */
3880  }
3881 
3882  ereport(ERROR,
3883  (errcode(ERRCODE_ASSERT_FAILURE),
3884  message ? errmsg_internal("%s", message) :
3885  errmsg("assertion failed")));
3886  }
3887 
3888  return PLPGSQL_RC_OK;
3889 }
int errcode(int sqlerrcode)
Definition: elog.c:610
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4046
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:355
#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:5788
PLpgSQL_expr * message
Definition: plpgsql.h:910
static bool exec_eval_boolean(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
Definition: pl_exec.c:5765
uintptr_t Datum
Definition: postgres.h:367
static struct @143 value
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg_internal(const char *fmt,...)
Definition: elog.c:911
int errmsg(const char *fmt,...)
Definition: elog.c:824
static char * convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
Definition: pl_exec.c:7759
PLpgSQL_expr * cond
Definition: plpgsql.h:909
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 2108 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().

2109 {
2110  Assert(stmt->varno >= 0);
2111 
2112  exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);
2113 
2114  return PLPGSQL_RC_OK;
2115 }
PLpgSQL_datum ** datums
Definition: plpgsql.h:1082
static void exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
Definition: pl_exec.c:4927
#define Assert(condition)
Definition: c.h:738
PLpgSQL_expr * expr
Definition: plpgsql.h:534

◆ exec_stmt_block()

static int exec_stmt_block ( PLpgSQL_execstate estate,
PLpgSQL_stmt_block block 
)
static

Definition at line 1599 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().

1600 {
1601  volatile int rc = -1;
1602  int i;
1603 
1604  /*
1605  * First initialize all variables declared in this block
1606  */
1607  estate->err_text = gettext_noop("during statement block local variable initialization");
1608 
1609  for (i = 0; i < block->n_initvars; i++)
1610  {
1611  int n = block->initvarnos[i];
1612  PLpgSQL_datum *datum = estate->datums[n];
1613 
1614  /*
1615  * The set of dtypes handled here must match plpgsql_add_initdatums().
1616  *
1617  * Note that we currently don't support promise datums within blocks,
1618  * only at a function's outermost scope, so we needn't handle those
1619  * here.
1620  */
1621  switch (datum->dtype)
1622  {
1623  case PLPGSQL_DTYPE_VAR:
1624  {
1625  PLpgSQL_var *var = (PLpgSQL_var *) datum;
1626 
1627  /*
1628  * Free any old value, in case re-entering block, and
1629  * initialize to NULL
1630  */
1631  assign_simple_var(estate, var, (Datum) 0, true, false);
1632 
1633  if (var->default_val == NULL)
1634  {
1635  /*
1636  * If needed, give the datatype a chance to reject
1637  * NULLs, by assigning a NULL to the variable. We
1638  * claim the value is of type UNKNOWN, not the var's
1639  * datatype, else coercion will be skipped.
1640  */
1641  if (var->datatype->typtype == TYPTYPE_DOMAIN)
1642  exec_assign_value(estate,
1643  (PLpgSQL_datum *) var,
1644  (Datum) 0,
1645  true,
1646  UNKNOWNOID,
1647  -1);
1648 
1649  /* parser should have rejected NOT NULL */
1650  Assert(!var->notnull);
1651  }
1652  else
1653  {
1654  exec_assign_expr(estate, (PLpgSQL_datum *) var,
1655  var->default_val);
1656  }
1657  }
1658  break;
1659 
1660  case PLPGSQL_DTYPE_REC:
1661  {
1662  PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
1663 
1664  /*
1665  * Deletion of any existing object will be handled during
1666  * the assignments below, and in some cases it's more
1667  * efficient for us not to get rid of it beforehand.
1668  */
1669  if (rec->default_val == NULL)
1670  {
1671  /*
1672  * If needed, give the datatype a chance to reject
1673  * NULLs, by assigning a NULL to the variable.
1674  */
1675  exec_move_row(estate, (PLpgSQL_variable *) rec,
1676  NULL, NULL);
1677 
1678  /* parser should have rejected NOT NULL */
1679  Assert(!rec->notnull);
1680  }
1681  else
1682  {
1683  exec_assign_expr(estate, (PLpgSQL_datum *) rec,
1684  rec->default_val);
1685  }
1686  }
1687  break;
1688 
1689  default:
1690  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
1691  }
1692  }
1693 
1694  if (block->exceptions)
1695  {
1696  /*
1697  * Execute the statements in the block's body inside a sub-transaction
1698  */
1699  MemoryContext oldcontext = CurrentMemoryContext;
1701  ExprContext *old_eval_econtext = estate->eval_econtext;
1702  ErrorData *save_cur_error = estate->cur_error;
1703  MemoryContext stmt_mcontext;
1704 
1705  estate->err_text = gettext_noop("during statement block entry");
1706 
1707  /*
1708  * We will need a stmt_mcontext to hold the error data if an error
1709  * occurs. It seems best to force it to exist before entering the
1710  * subtransaction, so that we reduce the risk of out-of-memory during
1711  * error recovery, and because this greatly simplifies restoring the
1712  * stmt_mcontext stack to the correct state after an error. We can
1713  * ameliorate the cost of this by allowing the called statements to
1714  * use this mcontext too; so we don't push it down here.
1715  */
1716  stmt_mcontext = get_stmt_mcontext(estate);
1717 
1719  /* Want to run statements inside function's memory context */
1720  MemoryContextSwitchTo(oldcontext);
1721 
1722  PG_TRY();
1723  {
1724  /*
1725  * We need to run the block's statements with a new eval_econtext
1726  * that belongs to the current subtransaction; if we try to use
1727  * the outer econtext then ExprContext shutdown callbacks will be
1728  * called at the wrong times.
1729  */
1730  plpgsql_create_econtext(estate);
1731 
1732  estate->err_text = NULL;
1733 
1734  /* Run the block's statements */
1735  rc = exec_stmts(estate, block->body);
1736 
1737  estate->err_text = gettext_noop("during statement block exit");
1738 
1739  /*
1740  * If the block ended with RETURN, we may need to copy the return
1741  * value out of the subtransaction eval_context. We can avoid a
1742  * physical copy if the value happens to be a R/W expanded object.
1743  */
1744  if (rc == PLPGSQL_RC_RETURN &&
1745  !estate->retisset &&
1746  !estate->retisnull)
1747  {
1748  int16 resTypLen;
1749  bool resTypByVal;
1750 
1751  get_typlenbyval(estate->rettype, &resTypLen, &resTypByVal);
1752  estate->retval = datumTransfer(estate->retval,
1753  resTypByVal, resTypLen);
1754  }
1755 
1756  /* Commit the inner transaction, return to outer xact context */
1758  MemoryContextSwitchTo(oldcontext);
1759  CurrentResourceOwner = oldowner;
1760 
1761  /* Assert that the stmt_mcontext stack is unchanged */
1762  Assert(stmt_mcontext == estate->stmt_mcontext);
1763 
1764  /*
1765  * Revert to outer eval_econtext. (The inner one was
1766  * automatically cleaned up during subxact exit.)
1767  */
1768  estate->eval_econtext = old_eval_econtext;
1769  }
1770  PG_CATCH();
1771  {
1772  ErrorData *edata;
1773  ListCell *e;
1774 
1775  estate->err_text = gettext_noop("during exception cleanup");