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/tstoreReceiver.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  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_toplevel_block (PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
 
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_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)
 
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)
 
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 Datum do_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 ParamListInfo exec_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, ParamListInfo paramLI)
 
static PLpgSQL_variablemake_callstmt_target (PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
 
Datum plpgsql_exec_function (PLpgSQL_function *func, FunctionCallInfo fcinfo, EState *simple_eval_estate, ResourceOwner simple_eval_resowner, ResourceOwner procedure_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 134 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:704
#define ERROR
Definition: elog.h:45
const char * name
Definition: encode.c:515
int errmsg(const char *fmt,...)
Definition: elog.c:915
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1174

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

8477 {
8478  Assert(rec->dtype == PLPGSQL_DTYPE_REC);
8479 
8480  /* Transfer new record object into datum_context */
8481  TransferExpandedRecord(erh, estate->datum_context);
8482 
8483  /* Free the old value ... */
8484  if (rec->erh)
8486 
8487  /* ... and install the new */
8488  rec->erh = erh;
8489 }
PLpgSQL_datum_type dtype
Definition: plpgsql.h:391
ExpandedRecordHeader * erh
Definition: plpgsql.h:414
void DeleteExpandedObject(Datum d)
#define Assert(condition)
Definition: c.h:804
#define TransferExpandedRecord(erh, cxt)
MemoryContext datum_context
Definition: plpgsql.h:1071
#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 8399 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().

8401 {
8402  Assert(var->dtype == PLPGSQL_DTYPE_VAR ||
8403  var->dtype == PLPGSQL_DTYPE_PROMISE);
8404 
8405  /*
8406  * In non-atomic contexts, we do not want to store TOAST pointers in
8407  * variables, because such pointers might become stale after a commit.
8408  * Forcibly detoast in such cases. We don't want to detoast (flatten)
8409  * expanded objects, however; those should be OK across a transaction
8410  * boundary since they're just memory-resident objects. (Elsewhere in
8411  * this module, operations on expanded records likewise need to request
8412  * detoasting of record fields when !estate->atomic. Expanded arrays are
8413  * not a problem since all array entries are always detoasted.)
8414  */
8415  if (!estate->atomic && !isnull && var->datatype->typlen == -1 &&
8417  {
8418  MemoryContext oldcxt;
8419  Datum detoasted;
8420 
8421  /*
8422  * Do the detoasting in the eval_mcontext to avoid long-term leakage
8423  * of whatever memory toast fetching might leak. Then we have to copy
8424  * the detoasted datum to the function's main context, which is a
8425  * pain, but there's little choice.
8426  */
8427  oldcxt = MemoryContextSwitchTo(get_eval_mcontext(estate));
8428  detoasted = PointerGetDatum(detoast_external_attr((struct varlena *) DatumGetPointer(newvalue)));
8429  MemoryContextSwitchTo(oldcxt);
8430  /* Now's a good time to not leak the input value if it's freeable */
8431  if (freeable)
8432  pfree(DatumGetPointer(newvalue));
8433  /* Once we copy the value, it's definitely freeable */
8434  newvalue = datumCopy(detoasted, false, -1);
8435  freeable = true;
8436  /* Can't clean up eval_mcontext here, but it'll happen before long */
8437  }
8438 
8439  /* Free the old value if needed */
8440  if (var->freeval)
8441  {
8443  var->isnull,
8444  var->datatype->typlen))
8446  else
8447  pfree(DatumGetPointer(var->value));
8448  }
8449  /* Assign new value to datum */
8450  var->value = newvalue;
8451  var->isnull = isnull;
8452  var->freeval = freeable;
8453 
8454  /*
8455  * If it's a promise variable, then either we just assigned the promised
8456  * value, or the user explicitly assigned an overriding value. Either
8457  * way, cancel the promise.
8458  */
8460 }
PLpgSQL_promise_type promise
Definition: plpgsql.h:342
#define VARATT_IS_EXTERNAL_NON_EXPANDED(PTR)
Definition: postgres.h:324
PLpgSQL_datum_type dtype
Definition: plpgsql.h:311
#define PointerGetDatum(X)
Definition: postgres.h:556
struct varlena * detoast_external_attr(struct varlena *attr)
Definition: detoast.c:45
PLpgSQL_type * datatype
Definition: plpgsql.h:320
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void pfree(void *pointer)
Definition: mcxt.c:1057
bool freeval
Definition: plpgsql.h:335
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
#define get_eval_mcontext(estate)
Definition: pl_exec.c:130
uintptr_t Datum
Definition: postgres.h:367
Datum value
Definition: plpgsql.h:333
void DeleteExpandedObject(Datum d)
#define Assert(condition)
Definition: c.h:804
#define DatumIsReadWriteExpandedObject(d, isnull, typlen)
#define DatumGetPointer(X)
Definition: postgres.h:549
Definition: c.h:621
int16 typlen
Definition: plpgsql.h:203
bool isnull
Definition: plpgsql.h:334

◆ assign_text_var()

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

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

8467 {
8468  assign_simple_var(estate, var, CStringGetTextDatum(str), false, true);
8469 }
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8399
#define CStringGetTextDatum(s)
Definition: builtins.h:82

◆ 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:970
#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:1197
static TupleDesc deconstruct_composite_datum(Datum value, HeapTupleData *tmptup)
Definition: pl_exec.c:7326
ExpandedObjectHeader hdr
Datum SPI_datumTransfer(Datum value, bool typByVal, int typLen)
Definition: spi.c:1257
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:2602
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:1234
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:804
size_t Size
Definition: c.h:540
#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 7227 of file pl_exec.c.

References i, TupleDescData::natts, and TupleDescAttr.

Referenced by exec_for_query(), and exec_move_row().

7228 {
7229  int i;
7230 
7231  /* Possibly we could allow src_tupdesc to have extra columns? */
7232  if (dst_tupdesc->natts != src_tupdesc->natts)
7233  return false;
7234 
7235  for (i = 0; i < dst_tupdesc->natts; i++)
7236  {
7237  Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
7238  Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
7239 
7240  if (dattr->attisdropped != sattr->attisdropped)
7241  return false;
7242  if (!dattr->attisdropped)
7243  {
7244  /* Normal columns must match by type and typmod */
7245  if (dattr->atttypid != sattr->atttypid ||
7246  (dattr->atttypmod >= 0 &&
7247  dattr->atttypmod != sattr->atttypmod))
7248  return false;
7249  }
7250  else
7251  {
7252  /* Dropped columns are OK as long as length/alignment match */
7253  if (dattr->attlen != sattr->attlen ||
7254  dattr->attalign != sattr->attalign)
7255  return false;
7256  }
7257  }
7258  return true;
7259 }
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
int i

◆ convert_value_to_string()

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

Definition at line 7625 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(), exec_stmt_return_query(), format_expr_params(), and format_preparedparamsdata().

7626 {
7627  char *result;
7628  MemoryContext oldcontext;
7629  Oid typoutput;
7630  bool typIsVarlena;
7631 
7632  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7633  getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
7634  result = OidOutputFunctionCall(typoutput, value);
7635  MemoryContextSwitchTo(oldcontext);
7636 
7637  return result;
7638 }
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2854
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned int Oid
Definition: postgres_ext.h:31
static struct @141 value
#define get_eval_mcontext(estate)
Definition: pl_exec.c:130
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1656

◆ copy_plpgsql_datums()

static void copy_plpgsql_datums ( PLpgSQL_execstate estate,
PLpgSQL_function func 
)
static

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

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

◆ deconstruct_composite_datum()

static TupleDesc deconstruct_composite_datum ( Datum  value,
HeapTupleData tmptup 
)
static

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

7327 {
7328  HeapTupleHeader td;
7329  Oid tupType;
7330  int32 tupTypmod;
7331 
7332  /* Get tuple body (note this could involve detoasting) */
7334 
7335  /* Build a temporary HeapTuple control structure */
7336  tmptup->t_len = HeapTupleHeaderGetDatumLength(td);
7337  ItemPointerSetInvalid(&(tmptup->t_self));
7338  tmptup->t_tableOid = InvalidOid;
7339  tmptup->t_data = td;
7340 
7341  /* Extract rowtype info and find a tupdesc */
7342  tupType = HeapTupleHeaderGetTypeId(td);
7343  tupTypmod = HeapTupleHeaderGetTypMod(td);
7344  return lookup_rowtype_tupdesc(tupType, tupTypmod);
7345 }
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1826
unsigned int Oid
Definition: postgres_ext.h:31
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:295
signed int int32
Definition: c.h:429
HeapTupleHeader t_data
Definition: htup.h:68
static struct @141 value
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:468
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
Oid t_tableOid
Definition: htup.h:66
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:458
#define InvalidOid
Definition: postgres_ext.h:36
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:452

◆ do_cast_value()

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

Definition at line 7678 of file pl_exec.c.

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

Referenced by exec_cast_value().

7682 {
7683  plpgsql_CastHashEntry *cast_entry;
7684 
7685  cast_entry = get_cast_hashentry(estate,
7686  valtype, valtypmod,
7687  reqtype, reqtypmod);
7688  if (cast_entry)
7689  {
7690  ExprContext *econtext = estate->eval_econtext;
7691  MemoryContext oldcontext;
7692 
7693  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7694 
7695  econtext->caseValue_datum = value;
7696  econtext->caseValue_isNull = *isnull;
7697 
7698  cast_entry->cast_in_use = true;
7699 
7700  value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
7701  isnull);
7702 
7703  cast_entry->cast_in_use = false;
7704 
7705  MemoryContextSwitchTo(oldcontext);
7706  }
7707 
7708  return value;
7709 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static struct @141 value
static plpgsql_CastHashEntry * get_cast_hashentry(PLpgSQL_execstate *estate, Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod)
Definition: pl_exec.c:7722
Datum caseValue_datum
Definition: execnodes.h:250
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:292
#define get_eval_mcontext(estate)
Definition: pl_exec.c:130
ExprContext * eval_econtext
Definition: plpgsql.h:1099
bool caseValue_isNull
Definition: execnodes.h:252
ExprState * cast_exprstate
Definition: pl_exec.c:166

◆ exception_matches_conditions()

static bool exception_matches_conditions ( ErrorData edata,
PLpgSQL_condition cond 
)
static

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

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

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

Referenced by exec_stmt_getdiag().

5032 {
5033  text *value;
5034  MemoryContext oldcontext;
5035 
5036  /* Use eval_mcontext for short-lived text value */
5037  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5038  if (str != NULL)
5039  value = cstring_to_text(str);
5040  else
5041  value = cstring_to_text("");
5042  MemoryContextSwitchTo(oldcontext);
5043 
5044  exec_assign_value(estate, target, PointerGetDatum(value), false,
5045  TEXTOID, -1);
5046 }
#define PointerGetDatum(X)
Definition: postgres.h:556
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static struct @141 value
#define get_eval_mcontext(estate)
Definition: pl_exec.c:130
text * cstring_to_text(const char *s)
Definition: varlena.c:189
Definition: c.h:621
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:5058

◆ exec_assign_expr()

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

Definition at line 4986 of file pl_exec.c.

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

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

4988 {
4989  Datum value;
4990  bool isnull;
4991  Oid valtype;
4992  int32 valtypmod;
4993 
4994  /*
4995  * If first time through, create a plan for this expression.
4996  */
4997  if (expr->plan == NULL)
4998  {
4999  /*
5000  * Mark the expression as being an assignment source, if target is a
5001  * simple variable. (This is a bit messy, but it seems cleaner than
5002  * modifying the API of exec_prepare_plan for the purpose. We need to
5003  * stash the target dno into the expr anyway, so that it will be
5004  * available if we have to replan.)
5005  */
5006  if (target->dtype == PLPGSQL_DTYPE_VAR)
5007  expr->target_param = target->dno;
5008  else
5009  expr->target_param = -1; /* should be that already */
5010 
5011  exec_prepare_plan(estate, expr, 0);
5012  }
5013 
5014  value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod);
5015  exec_assign_value(estate, target, value, isnull, valtype, valtypmod);
5016  exec_eval_cleanup(estate);
5017 }
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4110
unsigned int Oid
Definition: postgres_ext.h:31
PLpgSQL_datum_type dtype
Definition: plpgsql.h:277
SPIPlanPtr plan
Definition: plpgsql.h:222
signed int int32
Definition: c.h:429
static struct @141 value
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5662
int target_param
Definition: plpgsql.h:245
uintptr_t Datum
Definition: postgres.h:367
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions)
Definition: pl_exec.c:4131
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:5058

◆ 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 5058 of file pl_exec.c.

References assign_simple_var(), PLpgSQL_execstate::atomic, PLpgSQL_type::atttypmod, PLpgSQL_var::datatype, PLpgSQL_execstate::datum_context, DatumGetPointer, PLpgSQL_execstate::datums, datumTransfer(), PLpgSQL_datum::dtype, elog, ExpandedRecordHeader::er_tupdesc_id, ereport, PLpgSQL_rec::erh, errcode(), errmsg(), ERROR, exec_cast_value(), 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, instantiate_empty_record_variable(), PLpgSQL_var::isnull, PLpgSQL_var::notnull, PLpgSQL_rec::notnull, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, PLPGSQL_PROMISE_NONE, PLpgSQL_var::promise, PLpgSQL_recfield::recparentno, PLpgSQL_recfield::rectupledescid, PLpgSQL_var::refname, PLpgSQL_rec::refname, 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().

5062 {
5063  switch (target->dtype)
5064  {
5065  case PLPGSQL_DTYPE_VAR:
5066  case PLPGSQL_DTYPE_PROMISE:
5067  {
5068  /*
5069  * Target is a variable
5070  */
5071  PLpgSQL_var *var = (PLpgSQL_var *) target;
5072  Datum newvalue;
5073 
5074  newvalue = exec_cast_value(estate,
5075  value,
5076  &isNull,
5077  valtype,
5078  valtypmod,
5079  var->datatype->typoid,
5080  var->datatype->atttypmod);
5081 
5082  if (isNull && var->notnull)
5083  ereport(ERROR,
5084  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5085  errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
5086  var->refname)));
5087 
5088  /*
5089  * If type is by-reference, copy the new value (which is
5090  * probably in the eval_mcontext) into the procedure's main
5091  * memory context. But if it's a read/write reference to an
5092  * expanded object, no physical copy needs to happen; at most
5093  * we need to reparent the object's memory context.
5094  *
5095  * If it's an array, we force the value to be stored in R/W
5096  * expanded form. This wins if the function later does, say,
5097  * a lot of array subscripting operations on the variable, and
5098  * otherwise might lose. We might need to use a different
5099  * heuristic, but it's too soon to tell. Also, are there
5100  * cases where it'd be useful to force non-array values into
5101  * expanded form?
5102  */
5103  if (!var->datatype->typbyval && !isNull)
5104  {
5105  if (var->datatype->typisarray &&
5107  {
5108  /* array and not already R/W, so apply expand_array */
5109  newvalue = expand_array(newvalue,
5110  estate->datum_context,
5111  NULL);
5112  }
5113  else
5114  {
5115  /* else transfer value if R/W, else just datumCopy */
5116  newvalue = datumTransfer(newvalue,
5117  false,
5118  var->datatype->typlen);
5119  }
5120  }
5121 
5122  /*
5123  * Now free the old value, if any, and assign the new one. But
5124  * skip the assignment if old and new values are the same.
5125  * Note that for expanded objects, this test is necessary and
5126  * cannot reliably be made any earlier; we have to be looking
5127  * at the object's standard R/W pointer to be sure pointer
5128  * equality is meaningful.
5129  *
5130  * Also, if it's a promise variable, we should disarm the
5131  * promise in any case --- otherwise, assigning null to an
5132  * armed promise variable would fail to disarm the promise.
5133  */
5134  if (var->value != newvalue || var->isnull || isNull)
5135  assign_simple_var(estate, var, newvalue, isNull,
5136  (!var->datatype->typbyval && !isNull));
5137  else
5139  break;
5140  }
5141 
5142  case PLPGSQL_DTYPE_ROW:
5143  {
5144  /*
5145  * Target is a row variable
5146  */
5147  PLpgSQL_row *row = (PLpgSQL_row *) target;
5148 
5149  if (isNull)
5150  {
5151  /* If source is null, just assign nulls to the row */
5152  exec_move_row(estate, (PLpgSQL_variable *) row,
5153  NULL, NULL);
5154  }
5155  else
5156  {
5157  /* Source must be of RECORD or composite type */
5158  if (!type_is_rowtype(valtype))
5159  ereport(ERROR,
5160  (errcode(ERRCODE_DATATYPE_MISMATCH),
5161  errmsg("cannot assign non-composite value to a row variable")));
5163  value);
5164  }
5165  break;
5166  }
5167 
5168  case PLPGSQL_DTYPE_REC:
5169  {
5170  /*
5171  * Target is a record variable
5172  */
5173  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
5174 
5175  if (isNull)
5176  {
5177  if (rec->notnull)
5178  ereport(ERROR,
5179  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5180  errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
5181  rec->refname)));
5182 
5183  /* Set variable to a simple NULL */
5184  exec_move_row(estate, (PLpgSQL_variable *) rec,
5185  NULL, NULL);
5186  }
5187  else
5188  {
5189  /* Source must be of RECORD or composite type */
5190  if (!type_is_rowtype(valtype))
5191  ereport(ERROR,
5192  (errcode(ERRCODE_DATATYPE_MISMATCH),
5193  errmsg("cannot assign non-composite value to a record variable")));
5195  value);
5196  }
5197  break;
5198  }
5199 
5201  {
5202  /*
5203  * Target is a field of a record
5204  */
5205  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) target;
5206  PLpgSQL_rec *rec;
5207  ExpandedRecordHeader *erh;
5208 
5209  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5210  erh = rec->erh;
5211 
5212  /*
5213  * If record variable is NULL, instantiate it if it has a
5214  * named composite type, else complain. (This won't change
5215  * the logical state of the record, but if we successfully
5216  * assign below, the unassigned fields will all become NULLs.)
5217  */
5218  if (erh == NULL)
5219  {
5220  instantiate_empty_record_variable(estate, rec);
5221  erh = rec->erh;
5222  }
5223 
5224  /*
5225  * Look up the field's properties if we have not already, or
5226  * if the tuple descriptor ID changed since last time.
5227  */
5228  if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
5229  {
5231  recfield->fieldname,
5232  &recfield->finfo))
5233  ereport(ERROR,
5234  (errcode(ERRCODE_UNDEFINED_COLUMN),
5235  errmsg("record \"%s\" has no field \"%s\"",
5236  rec->refname, recfield->fieldname)));
5237  recfield->rectupledescid = erh->er_tupdesc_id;
5238  }
5239 
5240  /* We don't support assignments to system columns. */
5241  if (recfield->finfo.fnumber <= 0)
5242  ereport(ERROR,
5243  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5244  errmsg("cannot assign to system column \"%s\"",
5245  recfield->fieldname)));
5246 
5247  /* Cast the new value to the right type, if needed. */
5248  value = exec_cast_value(estate,
5249  value,
5250  &isNull,
5251  valtype,
5252  valtypmod,
5253  recfield->finfo.ftypeid,
5254  recfield->finfo.ftypmod);
5255 
5256  /* And assign it. */
5257  expanded_record_set_field(erh, recfield->finfo.fnumber,
5258  value, isNull, !estate->atomic);
5259  break;
5260  }
5261 
5262  default:
5263  elog(ERROR, "unrecognized dtype: %d", target->dtype);
5264  }
5265 }
PLpgSQL_promise_type promise
Definition: plpgsql.h:342
#define expanded_record_set_field(erh, fnumber, newValue, isnull, expand_external)
char * refname
Definition: plpgsql.h:313
bool expanded_record_lookup_field(ExpandedRecordHeader *erh, const char *fieldname, ExpandedRecordFieldInfo *finfo)
PLpgSQL_type * datatype
Definition: plpgsql.h:320
Datum expand_array(Datum arraydatum, MemoryContext parentcontext, ArrayMetaState *metacache)
static void instantiate_empty_record_variable(PLpgSQL_execstate *estate, PLpgSQL_rec *rec)
Definition: pl_exec.c:7590
ExpandedRecordHeader * erh
Definition: plpgsql.h:414
int errcode(int sqlerrcode)
Definition: elog.c:704
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8399
static void exec_move_row_from_datum(PLpgSQL_execstate *estate, PLpgSQL_variable *target, Datum value)
Definition: pl_exec.c:7357
PLpgSQL_datum_type dtype
Definition: plpgsql.h:277
char * refname
Definition: plpgsql.h:393
PLpgSQL_datum ** datums
Definition: plpgsql.h:1069
static struct @141 value
bool notnull
Definition: plpgsql.h:316
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7654
#define ERROR
Definition: elog.h:45
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2602
uint64 rectupledescid
Definition: plpgsql.h:429
bool typbyval
Definition: plpgsql.h:204
bool typisarray
Definition: plpgsql.h:207
uintptr_t Datum
Definition: postgres.h:367
ExpandedRecordFieldInfo finfo
Definition: plpgsql.h:430
Datum value
Definition: plpgsql.h:333
#define ereport(elevel,...)
Definition: elog.h:155
Datum datumTransfer(Datum value, bool typByVal, int typLen)
Definition: datum.c:193
#define DatumGetPointer(X)
Definition: postgres.h:549
MemoryContext datum_context
Definition: plpgsql.h:1071
int errmsg(const char *fmt,...)
Definition: elog.c:915
int32 atttypmod
Definition: plpgsql.h:208
static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
Definition: pl_exec.c:6683
#define elog(elevel,...)
Definition: elog.h:228
#define VARATT_IS_EXTERNAL_EXPANDED_RW(PTR)
Definition: postgres.h:320
#define unlikely(x)
Definition: c.h:273
int16 typlen
Definition: plpgsql.h:203
bool notnull
Definition: plpgsql.h:396
char * fieldname
Definition: plpgsql.h:426
bool isnull
Definition: plpgsql.h:334
Oid typoid
Definition: plpgsql.h:201

◆ exec_cast_value()

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

Definition at line 7654 of file pl_exec.c.

References do_cast_value(), 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().

7658 {
7659  /*
7660  * If the type of the given value isn't what's requested, convert it.
7661  */
7662  if (valtype != reqtype ||
7663  (valtypmod != reqtypmod && reqtypmod != -1))
7664  {
7665  /* We keep the slow path out-of-line. */
7666  value = do_cast_value(estate, value, isnull, valtype, valtypmod,
7667  reqtype, reqtypmod);
7668  }
7669 
7670  return value;
7671 }
static struct @141 value
static Datum do_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7678

◆ exec_check_rw_parameter()

static void exec_check_rw_parameter ( PLpgSQL_expr expr)
static

Definition at line 8113 of file pl_exec.c.

References arg, FuncExpr::args, OpExpr::args, Assert, bms_is_member(), PLpgSQL_expr::expr_rw_param, PLpgSQL_expr::expr_simple_expr, FuncExpr::funcid, get_typsubscript(), IsA, lfirst, OpExpr::opfuncid, PARAM_EXTERN, Param::paramid, Param::paramkind, PLpgSQL_expr::paramnos, SubscriptingRef::refcontainertype, SubscriptingRef::refexpr, and PLpgSQL_expr::target_param.

Referenced by exec_save_simple_expr().

8114 {
8115  int target_dno;
8116  Oid funcid;
8117  List *fargs;
8118  ListCell *lc;
8119 
8120  /* Assume unsafe */
8121  expr->expr_rw_param = NULL;
8122 
8123  /* Done if expression isn't an assignment source */
8124  target_dno = expr->target_param;
8125  if (target_dno < 0)
8126  return;
8127 
8128  /*
8129  * If target variable isn't referenced by expression, no need to look
8130  * further.
8131  */
8132  if (!bms_is_member(target_dno, expr->paramnos))
8133  return;
8134 
8135  /* Shouldn't be here for non-simple expression */
8136  Assert(expr->expr_simple_expr != NULL);
8137 
8138  /*
8139  * Top level of expression must be a simple FuncExpr, OpExpr, or
8140  * SubscriptingRef, else we can't optimize.
8141  */
8142  if (IsA(expr->expr_simple_expr, FuncExpr))
8143  {
8144  FuncExpr *fexpr = (FuncExpr *) expr->expr_simple_expr;
8145 
8146  funcid = fexpr->funcid;
8147  fargs = fexpr->args;
8148  }
8149  else if (IsA(expr->expr_simple_expr, OpExpr))
8150  {
8151  OpExpr *opexpr = (OpExpr *) expr->expr_simple_expr;
8152 
8153  funcid = opexpr->opfuncid;
8154  fargs = opexpr->args;
8155  }
8156  else if (IsA(expr->expr_simple_expr, SubscriptingRef))
8157  {
8158  SubscriptingRef *sbsref = (SubscriptingRef *) expr->expr_simple_expr;
8159 
8160  /* We only trust standard varlena arrays to be safe */
8161  if (get_typsubscript(sbsref->refcontainertype, NULL) !=
8162  F_ARRAY_SUBSCRIPT_HANDLER)
8163  return;
8164 
8165  /* We can optimize the refexpr if it's the target, otherwise not */
8166  if (sbsref->refexpr && IsA(sbsref->refexpr, Param))
8167  {
8168  Param *param = (Param *) sbsref->refexpr;
8169 
8170  if (param->paramkind == PARAM_EXTERN &&
8171  param->paramid == target_dno + 1)
8172  {
8173  /* Found the Param we want to pass as read/write */
8174  expr->expr_rw_param = param;
8175  return;
8176  }
8177  }
8178 
8179  return;
8180  }
8181  else
8182  return;
8183 
8184  /*
8185  * The top-level function must be one that we trust to be "safe".
8186  * Currently we hard-wire the list, but it would be very desirable to
8187  * allow extensions to mark their functions as safe ...
8188  */
8189  if (!(funcid == F_ARRAY_APPEND ||
8190  funcid == F_ARRAY_PREPEND))
8191  return;
8192 
8193  /*
8194  * The target variable (in the form of a Param) must appear as a direct
8195  * argument of the top-level function. References further down in the
8196  * tree can't be optimized; but on the other hand, they don't invalidate
8197  * optimizing the top-level call, since that will be executed last.
8198  */
8199  foreach(lc, fargs)
8200  {
8201  Node *arg = (Node *) lfirst(lc);
8202 
8203  if (arg && IsA(arg, Param))
8204  {
8205  Param *param = (Param *) arg;
8206 
8207  if (param->paramkind == PARAM_EXTERN &&
8208  param->paramid == target_dno + 1)
8209  {
8210  /* Found the Param we want to pass as read/write */
8211  expr->expr_rw_param = param;
8212  return;
8213  }
8214  }
8215  }
8216 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:581
Param * expr_rw_param
Definition: plpgsql.h:246
List * args
Definition: primnodes.h:498
ParamKind paramkind
Definition: primnodes.h:262
Definition: nodes.h:530
unsigned int Oid
Definition: postgres_ext.h:31
Bitmapset * paramnos
Definition: plpgsql.h:223
Oid funcid
Definition: primnodes.h:490
Expr * expr_simple_expr
Definition: plpgsql.h:232
int target_param
Definition: plpgsql.h:245
Oid opfuncid
Definition: primnodes.h:538
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
int paramid
Definition: primnodes.h:263
RegProcedure get_typsubscript(Oid typid, Oid *typelemp)
Definition: lsyscache.c:3044
void * arg
Oid refcontainertype
Definition: primnodes.h:434
Expr * refexpr
Definition: primnodes.h:444
List * args
Definition: primnodes.h:543
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 8580 of file pl_exec.c.

References convert_value_to_string(), SPIParseOpenOptions::cursorOptions, elog, ereport, errcode(), errmsg(), ERROR, exec_eval_cleanup(), exec_eval_expr(), exec_eval_using_params(), get_stmt_mcontext(), MemoryContextReset(), MemoryContextStrdup(), options, SPIParseOpenOptions::params, SPIParseOpenOptions::read_only, PLpgSQL_execstate::readonly_func, SPI_cursor_parse_open(), SPI_result, and SPI_result_code_string().

Referenced by exec_stmt_dynfors(), and exec_stmt_open().

8585 {
8586  Portal portal;
8587  Datum query;
8588  bool isnull;
8589  Oid restype;
8590  int32 restypmod;
8591  char *querystr;
8593  MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
8594 
8595  /*
8596  * Evaluate the string expression after the EXECUTE keyword. Its result is
8597  * the querystring we have to execute.
8598  */
8599  query = exec_eval_expr(estate, dynquery, &isnull, &restype, &restypmod);
8600  if (isnull)
8601  ereport(ERROR,
8602  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
8603  errmsg("query string argument of EXECUTE is null")));
8604 
8605  /* Get the C-String representation */
8606  querystr = convert_value_to_string(estate, query, restype);
8607 
8608  /* copy it into the stmt_mcontext before we clean up */
8609  querystr = MemoryContextStrdup(stmt_mcontext, querystr);
8610 
8611  exec_eval_cleanup(estate);
8612 
8613  /*
8614  * Open an implicit cursor for the query. We use SPI_cursor_parse_open
8615  * even when there are no params, because this avoids making and freeing
8616  * one copy of the plan.
8617  */
8618  memset(&options, 0, sizeof(options));
8619  options.params = exec_eval_using_params(estate, params);
8620  options.cursorOptions = cursorOptions;
8621  options.read_only = estate->readonly_func;
8622 
8623  portal = SPI_cursor_parse_open(portalname, querystr, &options);
8624 
8625  if (portal == NULL)
8626  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
8627  querystr, SPI_result_code_string(SPI_result));
8628 
8629  /* Release transient data */
8630  MemoryContextReset(stmt_mcontext);
8631 
8632  return portal;
8633 }
Portal SPI_cursor_parse_open(const char *name, const char *src, const SPIParseOpenOptions *options)
Definition: spi.c:1429
ParamListInfo params
Definition: spi.h:59
int errcode(int sqlerrcode)
Definition: elog.c:704
static ParamListInfo exec_eval_using_params(PLpgSQL_execstate *estate, List *params)
Definition: pl_exec.c:8498
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:137
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4110
unsigned int Oid
Definition: postgres_ext.h:31
bool read_only
Definition: spi.h:61
signed int int32
Definition: c.h:429
int SPI_result
Definition: spi.c:47
#define ERROR
Definition: elog.h:45
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5662
const char * SPI_result_code_string(int code)
Definition: spi.c:1862
int cursorOptions
Definition: spi.h:60
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1507
static char ** options
uintptr_t Datum
Definition: postgres.h:367
#define ereport(elevel,...)
Definition: elog.h:155
int errmsg(const char *fmt,...)
Definition: elog.c:915
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1174
#define elog(elevel,...)
Definition: elog.h:228
static char * convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
Definition: pl_exec.c:7625

◆ exec_eval_boolean()

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

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

5642 {
5643  Datum exprdatum;
5644  Oid exprtypeid;
5645  int32 exprtypmod;
5646 
5647  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5648  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5649  exprtypeid, exprtypmod,
5650  BOOLOID, -1);
5651  return DatumGetBool(exprdatum);
5652 }
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:429
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7654
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5662
#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 4110 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().

4111 {
4112  /* Clear result of a full SPI_execute */
4113  if (estate->eval_tuptable != NULL)
4115  estate->eval_tuptable = NULL;
4116 
4117  /*
4118  * Clear result of exec_eval_simple_expr (but keep the econtext). This
4119  * also clears any short-lived allocations done via get_eval_mcontext.
4120  */
4121  if (estate->eval_econtext != NULL)
4123 }
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1097
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1282
ExprContext * eval_econtext
Definition: plpgsql.h:1099
#define ResetExprContext(econtext)
Definition: executor.h:503

◆ 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 5285 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_stmt_return(), format_expr_params(), make_tuple_from_row(), plpgsql_param_eval_generic(), plpgsql_param_eval_generic_ro(), and plpgsql_param_fetch().

5291 {
5292  MemoryContext oldcontext;
5293 
5294  switch (datum->dtype)
5295  {
5296  case PLPGSQL_DTYPE_PROMISE:
5297  /* fulfill promise if needed, then handle like regular var */
5298  plpgsql_fulfill_promise(estate, (PLpgSQL_var *) datum);
5299 
5300  /* FALL THRU */
5301 
5302  case PLPGSQL_DTYPE_VAR:
5303  {
5304  PLpgSQL_var *var = (PLpgSQL_var *) datum;
5305 
5306  *typeid = var->datatype->typoid;
5307  *typetypmod = var->datatype->atttypmod;
5308  *value = var->value;
5309  *isnull = var->isnull;
5310  break;
5311  }
5312 
5313  case PLPGSQL_DTYPE_ROW:
5314  {
5315  PLpgSQL_row *row = (PLpgSQL_row *) datum;
5316  HeapTuple tup;
5317 
5318  /* We get here if there are multiple OUT parameters */
5319  if (!row->rowtupdesc) /* should not happen */
5320  elog(ERROR, "row variable has no tupdesc");
5321  /* Make sure we have a valid type/typmod setting */
5322  BlessTupleDesc(row->rowtupdesc);
5323  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5324  tup = make_tuple_from_row(estate, row, row->rowtupdesc);
5325  if (tup == NULL) /* should not happen */
5326  elog(ERROR, "row not compatible with its own tupdesc");
5327  *typeid = row->rowtupdesc->tdtypeid;
5328  *typetypmod = row->rowtupdesc->tdtypmod;
5329  *value = HeapTupleGetDatum(tup);
5330  *isnull = false;
5331  MemoryContextSwitchTo(oldcontext);
5332  break;
5333  }
5334 
5335  case PLPGSQL_DTYPE_REC:
5336  {
5337  PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
5338 
5339  if (rec->erh == NULL)
5340  {
5341  /* Treat uninstantiated record as a simple NULL */
5342  *value = (Datum) 0;
5343  *isnull = true;
5344  /* Report variable's declared type */
5345  *typeid = rec->rectypeid;
5346  *typetypmod = -1;
5347  }
5348  else
5349  {
5350  if (ExpandedRecordIsEmpty(rec->erh))
5351  {
5352  /* Empty record is also a NULL */
5353  *value = (Datum) 0;
5354  *isnull = true;
5355  }
5356  else
5357  {
5358  *value = ExpandedRecordGetDatum(rec->erh);
5359  *isnull = false;
5360  }
5361  if (rec->rectypeid != RECORDOID)
5362  {
5363  /* Report variable's declared type, if not RECORD */
5364  *typeid = rec->rectypeid;
5365  *typetypmod = -1;
5366  }
5367  else
5368  {
5369  /* Report record's actual type if declared RECORD */
5370  *typeid = rec->erh->er_typeid;
5371  *typetypmod = rec->erh->er_typmod;
5372  }
5373  }
5374  break;
5375  }
5376 
5378  {
5379  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
5380  PLpgSQL_rec *rec;
5381  ExpandedRecordHeader *erh;
5382 
5383  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5384  erh = rec->erh;
5385 
5386  /*
5387  * If record variable is NULL, instantiate it if it has a
5388  * named composite type, else complain. (This won't change
5389  * the logical state of the record: it's still NULL.)
5390  */
5391  if (erh == NULL)
5392  {
5393  instantiate_empty_record_variable(estate, rec);
5394  erh = rec->erh;
5395  }
5396 
5397  /*
5398  * Look up the field's properties if we have not already, or
5399  * if the tuple descriptor ID changed since last time.
5400  */
5401  if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
5402  {
5404  recfield->fieldname,
5405  &recfield->finfo))
5406  ereport(ERROR,
5407  (errcode(ERRCODE_UNDEFINED_COLUMN),
5408  errmsg("record \"%s\" has no field \"%s\"",
5409  rec->refname, recfield->fieldname)));
5410  recfield->rectupledescid = erh->er_tupdesc_id;
5411  }
5412 
5413  /* Report type data. */
5414  *typeid = recfield->finfo.ftypeid;
5415  *typetypmod = recfield->finfo.ftypmod;
5416 
5417  /* And fetch the field value. */
5419  recfield->finfo.fnumber,
5420  isnull);
5421  break;
5422  }
5423 
5424  default:
5425  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
5426  }
5427 }
static HeapTuple make_tuple_from_row(PLpgSQL_execstate *estate, PLpgSQL_row *row, TupleDesc tupdesc)
Definition: pl_exec.c:7271
#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:320
static void plpgsql_fulfill_promise(PLpgSQL_execstate *estate, PLpgSQL_var *var)
Definition: pl_exec.c:1347
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:7590
ExpandedRecordHeader * erh
Definition: plpgsql.h:414
int errcode(int sqlerrcode)
Definition: elog.c:704
PLpgSQL_datum_type dtype
Definition: plpgsql.h:277
char * refname
Definition: plpgsql.h:393
PLpgSQL_datum ** datums
Definition: plpgsql.h:1069
static struct @141 value
#define ERROR
Definition: elog.h:45
int32 tdtypmod
Definition: tupdesc.h:83
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2052
uint64 rectupledescid
Definition: plpgsql.h:429
#define get_eval_mcontext(estate)
Definition: pl_exec.c:130
uintptr_t Datum
Definition: postgres.h:367
ExpandedRecordFieldInfo finfo
Definition: plpgsql.h:430
Datum value
Definition: plpgsql.h:333
#define ereport(elevel,...)
Definition: elog.h:155
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:221
Oid tdtypeid
Definition: tupdesc.h:82
int errmsg(const char *fmt,...)
Definition: elog.c:915
int32 atttypmod
Definition: plpgsql.h:208
#define elog(elevel,...)
Definition: elog.h:228
TupleDesc rowtupdesc
Definition: plpgsql.h:379
#define unlikely(x)
Definition: c.h:273
Oid rectypeid
Definition: plpgsql.h:407
#define ExpandedRecordGetDatum(erh)
char * fieldname
Definition: plpgsql.h:426
bool isnull
Definition: plpgsql.h:334
Oid typoid
Definition: plpgsql.h:201

◆ exec_eval_expr()

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

Definition at line 5662 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(), exec_stmt_return_next(), and exec_stmt_return_query().

5667 {
5668  Datum result = 0;
5669  int rc;
5670  Form_pg_attribute attr;
5671 
5672  /*
5673  * If first time through, create a plan for this expression.
5674  */
5675  if (expr->plan == NULL)
5677 
5678  /*
5679  * If this is a simple expression, bypass SPI and use the executor
5680  * directly
5681  */
5682  if (exec_eval_simple_expr(estate, expr,
5683  &result, isNull, rettype, rettypmod))
5684  return result;
5685 
5686  /*
5687  * Else do it the hard way via exec_run_select
5688  */
5689  rc = exec_run_select(estate, expr, 2, NULL);
5690  if (rc != SPI_OK_SELECT)
5691  ereport(ERROR,
5692  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5693  errmsg("query \"%s\" did not return data", expr->query)));
5694 
5695  /*
5696  * Check that the expression returns exactly one column...
5697  */
5698  if (estate->eval_tuptable->tupdesc->natts != 1)
5699  ereport(ERROR,
5700  (errcode(ERRCODE_SYNTAX_ERROR),
5701  errmsg_plural("query \"%s\" returned %d column",
5702  "query \"%s\" returned %d columns",
5703  estate->eval_tuptable->tupdesc->natts,
5704  expr->query,
5705  estate->eval_tuptable->tupdesc->natts)));
5706 
5707  /*
5708  * ... and get the column's datatype.
5709  */
5710  attr = TupleDescAttr(estate->eval_tuptable->tupdesc, 0);
5711  *rettype = attr->atttypid;
5712  *rettypmod = attr->atttypmod;
5713 
5714  /*
5715  * If there are no rows selected, the result is a NULL of that type.
5716  */
5717  if (estate->eval_processed == 0)
5718  {
5719  *isNull = true;
5720  return (Datum) 0;
5721  }
5722 
5723  /*
5724  * Check that the expression returned no more than one row.
5725  */
5726  if (estate->eval_processed != 1)
5727  ereport(ERROR,
5728  (errcode(ERRCODE_CARDINALITY_VIOLATION),
5729  errmsg("query \"%s\" returned more than one row",
5730  expr->query)));
5731 
5732  /*
5733  * Return the single result Datum.
5734  */
5735  return SPI_getbinval(estate->eval_tuptable->vals[0],
5736  estate->eval_tuptable->tupdesc, 1, isNull);
5737 }
char * query
Definition: plpgsql.h:220
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1097
uint64 eval_processed
Definition: plpgsql.h:1098
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1025
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
int errcode(int sqlerrcode)
Definition: elog.c:704
HeapTuple * vals
Definition: spi.h:26
SPIPlanPtr plan
Definition: plpgsql.h:222
#define ERROR
Definition: elog.h:45
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition: spi.c:1148
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
uintptr_t Datum
Definition: postgres.h:367
TupleDesc tupdesc
Definition: spi.h:25
#define SPI_OK_SELECT
Definition: spi.h:85
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions)
Definition: pl_exec.c:4131
#define ereport(elevel,...)
Definition: elog.h:155
static int exec_run_select(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
Definition: pl_exec.c:5745
static bool exec_eval_simple_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, Datum *result, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5980
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2759
int errmsg(const char *fmt,...)
Definition: elog.c:915

◆ exec_eval_integer()

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

Definition at line 5616 of file pl_exec.c.

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

Referenced by exec_stmt_fetch().

5619 {
5620  Datum exprdatum;
5621  Oid exprtypeid;
5622  int32 exprtypmod;
5623 
5624  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5625  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5626  exprtypeid, exprtypmod,
5627  INT4OID, -1);
5628  return DatumGetInt32(exprdatum);
5629 }
#define DatumGetInt32(X)
Definition: postgres.h:472
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:429
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7654
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5662
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 5980 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_save_simple_expr(), ExecEvalExpr(), ExecInitExprWithParams(), PLpgSQL_expr::expr_rw_param, 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_execstate::simple_eval_estate, PLpgSQL_execstate::simple_eval_resowner, SPI_plan_get_cached_plan(), and unlikely.

Referenced by exec_eval_expr().

5986 {
5987  ExprContext *econtext = estate->eval_econtext;
5988  LocalTransactionId curlxid = MyProc->lxid;
5989  ParamListInfo paramLI;
5990  void *save_setup_arg;
5991  bool need_snapshot;
5992  MemoryContext oldcontext;
5993 
5994  /*
5995  * Forget it if expression wasn't simple before.
5996  */
5997  if (expr->expr_simple_expr == NULL)
5998  return false;
5999 
6000  /*
6001  * If expression is in use in current xact, don't touch it.
6002  */
6003  if (unlikely(expr->expr_simple_in_use) &&
6004  expr->expr_simple_lxid == curlxid)
6005  return false;
6006 
6007  /*
6008  * Check to see if the cached plan has been invalidated. If not, and this
6009  * is the first use in the current transaction, save a plan refcount in
6010  * the simple-expression resowner.
6011  */
6013  expr->expr_simple_plan,
6014  (expr->expr_simple_plan_lxid != curlxid ?
6015  estate->simple_eval_resowner : NULL))))
6016  {
6017  /*
6018  * It's still good, so just remember that we have a refcount on the
6019  * plan in the current transaction. (If we already had one, this
6020  * assignment is a no-op.)
6021  */
6022  expr->expr_simple_plan_lxid = curlxid;
6023  }
6024  else
6025  {
6026  /* Need to replan */
6027  CachedPlan *cplan;
6028 
6029  /*
6030  * If we have a valid refcount on some previous version of the plan,
6031  * release it, so we don't leak plans intra-transaction.
6032  */
6033  if (expr->expr_simple_plan_lxid == curlxid)
6034  {
6036  estate->simple_eval_resowner);
6037  expr->expr_simple_plan = NULL;
6039  }
6040 
6041  /* Do the replanning work in the eval_mcontext */
6042  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6043  cplan = SPI_plan_get_cached_plan(expr->plan);
6044  MemoryContextSwitchTo(oldcontext);
6045 
6046  /*
6047  * We can't get a failure here, because the number of
6048  * CachedPlanSources in the SPI plan can't change from what
6049  * exec_simple_check_plan saw; it's a property of the raw parsetree
6050  * generated from the query text.
6051  */
6052  Assert(cplan != NULL);
6053 
6054  /*
6055  * This test probably can't fail either, but if it does, cope by
6056  * declaring the plan to be non-simple. On success, we'll acquire a
6057  * refcount on the new plan, stored in simple_eval_resowner.
6058  */
6060  cplan,
6061  estate->simple_eval_resowner))
6062  {
6063  /* Remember that we have the refcount */
6064  expr->expr_simple_plan = cplan;
6065  expr->expr_simple_plan_lxid = curlxid;
6066  }
6067  else
6068  {
6069  /* Release SPI_plan_get_cached_plan's refcount */
6071  /* Mark expression as non-simple, and fail */
6072  expr->expr_simple_expr = NULL;
6073  expr->expr_rw_param = NULL;
6074  return false;
6075  }
6076 
6077  /*
6078  * SPI_plan_get_cached_plan acquired a plan refcount stored in the
6079  * active resowner. We don't need that anymore, so release it.
6080  */
6082 
6083  /* Extract desired scalar expression from cached plan */
6084  exec_save_simple_expr(expr, cplan);
6085  }
6086 
6087  /*
6088  * Pass back previously-determined result type.
6089  */
6090  *rettype = expr->expr_simple_type;
6091  *rettypmod = expr->expr_simple_typmod;
6092 
6093  /*
6094  * Set up ParamListInfo to pass to executor. For safety, save and restore
6095  * estate->paramLI->parserSetupArg around our use of the param list.
6096  */
6097  paramLI = estate->paramLI;
6098  save_setup_arg = paramLI->parserSetupArg;
6099 
6100  /*
6101  * We can skip using setup_param_list() in favor of just doing this
6102  * unconditionally, because there's no need for the optimization of
6103  * possibly setting ecxt_param_list_info to NULL; we've already forced use
6104  * of a generic plan.
6105  */
6106  paramLI->parserSetupArg = (void *) expr;
6107  econtext->ecxt_param_list_info = paramLI;
6108 
6109  /*
6110  * Prepare the expression for execution, if it's not been done already in
6111  * the current transaction. (This will be forced to happen if we called
6112  * exec_save_simple_expr above.)
6113  */
6114  if (unlikely(expr->expr_simple_lxid != curlxid))
6115  {
6116  oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
6117  expr->expr_simple_state =
6119  econtext->ecxt_param_list_info);
6120  expr->expr_simple_in_use = false;
6121  expr->expr_simple_lxid = curlxid;
6122  MemoryContextSwitchTo(oldcontext);
6123  }
6124 
6125  /*
6126  * We have to do some of the things SPI_execute_plan would do, in
6127  * particular push a new snapshot so that stable functions within the
6128  * expression can see updates made so far by our own function. However,
6129  * we can skip doing that (and just invoke the expression with the same
6130  * snapshot passed to our function) in some cases, which is useful because
6131  * it's quite expensive relative to the cost of a simple expression. We
6132  * can skip it if the expression contains no stable or volatile functions;
6133  * immutable functions shouldn't need to see our updates. Also, if this
6134  * is a read-only function, we haven't made any updates so again it's okay
6135  * to skip.
6136  */
6137  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6138  need_snapshot = (expr->expr_simple_mutable && !estate->readonly_func);
6139  if (need_snapshot)
6140  {
6143  }
6144 
6145  /*
6146  * Mark expression as busy for the duration of the ExecEvalExpr call.
6147  */
6148  expr->expr_simple_in_use = true;
6149 
6150  /*
6151  * Finally we can call the executor to evaluate the expression
6152  */
6153  *result = ExecEvalExpr(expr->expr_simple_state,
6154  econtext,
6155  isNull);
6156 
6157  /* Assorted cleanup */
6158  expr->expr_simple_in_use = false;
6159 
6160  econtext->ecxt_param_list_info = NULL;
6161 
6162  paramLI->parserSetupArg = save_setup_arg;
6163 
6164  if (need_snapshot)
6166 
6167  MemoryContextSwitchTo(oldcontext);
6168 
6169  /*
6170  * That's it.
6171  */
6172  return true;
6173 }
#define likely(x)
Definition: c.h:272
void * parserSetupArg
Definition: params.h:117
Param * expr_rw_param
Definition: plpgsql.h:246
ResourceOwner simple_eval_resowner
Definition: plpgsql.h:1083
PGPROC * MyProc
Definition: proc.c:68
ResourceOwner CurrentResourceOwner
Definition: resowner.c:144
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1264
void PopActiveSnapshot(void)
Definition: snapmgr.c:759
bool CachedPlanIsSimplyValid(CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1424
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:250
static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
Definition: pl_exec.c:8006
SPIPlanPtr plan
Definition: plpgsql.h:222
CachedPlan * SPI_plan_get_cached_plan(SPIPlanPtr plan)
Definition: spi.c:1958
MemoryContext es_query_cxt
Definition: execnodes.h:572
ParamListInfo paramLI
Definition: plpgsql.h:1079
CachedPlanSource * expr_simple_plansource
Definition: plpgsql.h:254
EState * simple_eval_estate
Definition: plpgsql.h:1082
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:680
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:292
ExprState * ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
Definition: execExpr.c:160
Expr * expr_simple_expr
Definition: plpgsql.h:232
uint32 LocalTransactionId
Definition: c.h:589
bool CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1309
#define get_eval_mcontext(estate)
Definition: pl_exec.c:130
ExprState * expr_simple_state
Definition: plpgsql.h:264
bool expr_simple_mutable
Definition: plpgsql.h:235
CachedPlan * expr_simple_plan
Definition: plpgsql.h:255
void CommandCounterIncrement(void)
Definition: xact.c:1021
LocalTransactionId expr_simple_lxid
Definition: plpgsql.h:266
#define Assert(condition)
Definition: c.h:804
ExprContext * eval_econtext
Definition: plpgsql.h:1099
int32 expr_simple_typmod
Definition: plpgsql.h:234
#define InvalidLocalTransactionId
Definition: lock.h:69
#define unlikely(x)
Definition: c.h:273
LocalTransactionId expr_simple_plan_lxid
Definition: plpgsql.h:256
bool expr_simple_in_use
Definition: plpgsql.h:265
ParamListInfo ecxt_param_list_info
Definition: execnodes.h:237
Oid expr_simple_type
Definition: plpgsql.h:233
LocalTransactionId lxid
Definition: proc.h:143

◆ exec_eval_using_params()

static ParamListInfo exec_eval_using_params ( PLpgSQL_execstate estate,
List params 
)
static

Definition at line 8498 of file pl_exec.c.

References CStringGetTextDatum, datumCopy(), DatumGetCString, exec_eval_cleanup(), exec_eval_expr(), get_stmt_mcontext(), get_typlenbyval(), i, ParamExternData::isnull, lfirst, list_length(), makeParamList(), MemoryContextSwitchTo(), NIL, PARAM_FLAG_CONST, ParamListInfoData::params, ParamExternData::pflags, ParamExternData::ptype, and ParamExternData::value.

Referenced by exec_dynquery_with_params(), exec_stmt_dynexecute(), and exec_stmt_return_query().

8499 {
8500  ParamListInfo paramLI;
8501  int nargs;
8502  MemoryContext stmt_mcontext;
8503  MemoryContext oldcontext;
8504  int i;
8505  ListCell *lc;
8506 
8507  /* Fast path for no parameters: we can just return NULL */
8508  if (params == NIL)
8509  return NULL;
8510 
8511  nargs = list_length(params);
8512  stmt_mcontext = get_stmt_mcontext(estate);
8513  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8514  paramLI = makeParamList(nargs);
8515  MemoryContextSwitchTo(oldcontext);
8516 
8517  i = 0;
8518  foreach(lc, params)
8519  {
8520  PLpgSQL_expr *param = (PLpgSQL_expr *) lfirst(lc);
8521  ParamExternData *prm = &paramLI->params[i];
8522  int32 ppdtypmod;
8523 
8524  /*
8525  * Always mark params as const, since we only use the result with
8526  * one-shot plans.
8527  */
8528  prm->pflags = PARAM_FLAG_CONST;
8529 
8530  prm->value = exec_eval_expr(estate, param,
8531  &prm->isnull,
8532  &prm->ptype,
8533  &ppdtypmod);
8534 
8535  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8536 
8537  if (prm->ptype == UNKNOWNOID)
8538  {
8539  /*
8540  * Treat 'unknown' parameters as text, since that's what most
8541  * people would expect. The SPI functions can coerce unknown
8542  * constants in a more intelligent way, but not unknown Params.
8543  * This code also takes care of copying into the right context.
8544  * Note we assume 'unknown' has the representation of C-string.
8545  */
8546  prm->ptype = TEXTOID;
8547  if (!prm->isnull)
8549  }
8550  /* pass-by-ref non null values must be copied into stmt_mcontext */
8551  else if (!prm->isnull)
8552  {
8553  int16 typLen;
8554  bool typByVal;
8555 
8556  get_typlenbyval(prm->ptype, &typLen, &typByVal);
8557  if (!typByVal)
8558  prm->value = datumCopy(prm->value, typByVal, typLen);
8559  }
8560 
8561  MemoryContextSwitchTo(oldcontext);
8562 
8563  exec_eval_cleanup(estate);
8564 
8565  i++;
8566  }
8567 
8568  return paramLI;
8569 }
signed short int16
Definition: c.h:428
ParamExternData params[FLEXIBLE_ARRAY_MEMBER]
Definition: params.h:125
#define NIL
Definition: pg_list.h:65
Datum value
Definition: params.h:92
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4110
ParamListInfo makeParamList(int numParams)
Definition: params.c:44
signed int int32
Definition: c.h:429
#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:5662
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1507
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
#define lfirst(lc)
Definition: pg_list.h:169
uint16 pflags
Definition: params.h:94
static int list_length(const List *l)
Definition: pg_list.h:149
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2198
int i
#define CStringGetTextDatum(s)
Definition: builtins.h:82
bool isnull
Definition: params.h:93
#define PARAM_FLAG_CONST
Definition: params.h:88

◆ exec_for_query()

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

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

5811 {
5812  PLpgSQL_variable *var;
5813  SPITupleTable *tuptab;
5814  bool found = false;
5815  int rc = PLPGSQL_RC_OK;
5816  uint64 previous_id = INVALID_TUPLEDESC_IDENTIFIER;
5817  bool tupdescs_match = true;
5818  uint64 n;
5819 
5820  /* Fetch loop variable's datum entry */
5821  var = (PLpgSQL_variable *) estate->datums[stmt->var->dno];
5822 
5823  /*
5824  * Make sure the portal doesn't get closed by the user statements we
5825  * execute.
5826  */
5827  PinPortal(portal);
5828 
5829  /*
5830  * Fetch the initial tuple(s). If prefetching is allowed then we grab a
5831  * few more rows to avoid multiple trips through executor startup
5832  * overhead.
5833  */
5834  SPI_cursor_fetch(portal, true, prefetch_ok ? 10 : 1);
5835  tuptab = SPI_tuptable;
5836  n = SPI_processed;
5837 
5838  /*
5839  * If the query didn't return any rows, set the target to NULL and fall
5840  * through with found = false.
5841  */
5842  if (n == 0)
5843  {
5844  exec_move_row(estate, var, NULL, tuptab->tupdesc);
5845  exec_eval_cleanup(estate);
5846  }
5847  else
5848  found = true; /* processed at least one tuple */
5849 
5850  /*
5851  * Now do the loop
5852  */
5853  while (n > 0)
5854  {
5855  uint64 i;
5856 
5857  for (i = 0; i < n; i++)
5858  {
5859  /*
5860  * Assign the tuple to the target. Here, because we know that all
5861  * loop iterations should be assigning the same tupdesc, we can
5862  * optimize away repeated creations of expanded records with
5863  * identical tupdescs. Testing for changes of er_tupdesc_id is
5864  * reliable even if the loop body contains assignments that
5865  * replace the target's value entirely, because it's assigned from
5866  * a process-global counter. The case where the tupdescs don't
5867  * match could possibly be handled more efficiently than this
5868  * coding does, but it's not clear extra effort is worthwhile.
5869  */
5870  if (var->dtype == PLPGSQL_DTYPE_REC)
5871  {
5872  PLpgSQL_rec *rec = (PLpgSQL_rec *) var;
5873 
5874  if (rec->erh &&
5875  rec->erh->er_tupdesc_id == previous_id &&
5876  tupdescs_match)
5877  {
5878  /* Only need to assign a new tuple value */
5879  expanded_record_set_tuple(rec->erh, tuptab->vals[i],
5880  true, !estate->atomic);
5881  }
5882  else
5883  {
5884  /*
5885  * First time through, or var's tupdesc changed in loop,
5886  * or we have to do it the hard way because type coercion
5887  * is needed.
5888  */
5889  exec_move_row(estate, var,
5890  tuptab->vals[i], tuptab->tupdesc);
5891 
5892  /*
5893  * Check to see if physical assignment is OK next time.
5894  * Once the tupdesc comparison has failed once, we don't
5895  * bother rechecking in subsequent loop iterations.
5896  */
5897  if (tupdescs_match)
5898  {
5899  tupdescs_match =
5900  (rec->rectypeid == RECORDOID ||
5901  rec->rectypeid == tuptab->tupdesc->tdtypeid ||
5902  compatible_tupdescs(tuptab->tupdesc,
5904  }
5905  previous_id = rec->erh->er_tupdesc_id;
5906  }
5907  }
5908  else
5909  exec_move_row(estate, var, tuptab->vals[i], tuptab->tupdesc);
5910 
5911  exec_eval_cleanup(estate);
5912 
5913  /*
5914  * Execute the statements
5915  */
5916  rc = exec_stmts(estate, stmt->body);
5917 
5918  LOOP_RC_PROCESSING(stmt->label, goto loop_exit);
5919  }
5920 
5921  SPI_freetuptable(tuptab);
5922 
5923  /*
5924  * Fetch more tuples. If prefetching is allowed, grab 50 at a time.
5925  */
5926  SPI_cursor_fetch(portal, true, prefetch_ok ? 50 : 1);
5927  tuptab = SPI_tuptable;
5928  n = SPI_processed;
5929  }
5930 
5931 loop_exit:
5932 
5933  /*
5934  * Release last group of tuples (if any)
5935  */
5936  SPI_freetuptable(tuptab);
5937 
5938  UnpinPortal(portal);
5939 
5940  /*
5941  * Set the FOUND variable to indicate the result of executing the loop
5942  * (namely, whether we looped one or more times). This must be set last so
5943  * that it does not interfere with the value of the FOUND variable inside
5944  * the loop processing itself.
5945  */
5946  exec_set_found(estate, found);
5947 
5948  return rc;
5949 }
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:414
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4110
HeapTuple * vals
Definition: spi.h:26
#define INVALID_TUPLEDESC_IDENTIFIER
Definition: typcache.h:155
uint64 SPI_processed
Definition: spi.c:45
PLpgSQL_datum ** datums
Definition: plpgsql.h:1069
void PinPortal(Portal portal)
Definition: portalmem.c:370
#define LOOP_RC_PROCESSING(looplabel, exit_action)
Definition: pl_exec.c:197
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1282
static bool compatible_tupdescs(TupleDesc src_tupdesc, TupleDesc dst_tupdesc)
Definition: pl_exec.c:7227
TupleDesc tupdesc
Definition: spi.h:25
PLpgSQL_datum_type dtype
Definition: plpgsql.h:289
PLpgSQL_variable * var
Definition: plpgsql.h:703
static void exec_set_found(PLpgSQL_execstate *estate, bool state)
Definition: pl_exec.c:8223
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:6683
int i
void SPI_cursor_fetch(Portal portal, bool forward, long count)
Definition: spi.c:1696
Oid rectypeid
Definition: plpgsql.h:407
static int exec_stmts(PLpgSQL_execstate *estate, List *stmts)
Definition: pl_exec.c:1952

◆ exec_init_tuple_store()

static void exec_init_tuple_store ( PLpgSQL_execstate estate)
static

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

3657 {
3658  ReturnSetInfo *rsi = estate->rsi;
3659  MemoryContext oldcxt;
3660  ResourceOwner oldowner;
3661 
3662  /*
3663  * Check caller can handle a set result in the way we want
3664  */
3665  if (!rsi || !IsA(rsi, ReturnSetInfo) ||
3666  (rsi->allowedModes & SFRM_Materialize) == 0 ||
3667  rsi->expectedDesc == NULL)
3668  ereport(ERROR,
3669  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3670  errmsg("set-valued function called in context that cannot accept a set")));
3671 
3672  /*
3673  * Switch to the right memory context and resource owner for storing the
3674  * tuplestore for return set. If we're within a subtransaction opened for
3675  * an exception-block, for example, we must still create the tuplestore in
3676  * the resource owner that was active when this function was entered, and
3677  * not in the subtransaction resource owner.
3678  */
3679  oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
3680  oldowner = CurrentResourceOwner;
3682 
3683  estate->tuple_store =
3685  false, work_mem);
3686 
3687  CurrentResourceOwner = oldowner;
3688  MemoryContextSwitchTo(oldcxt);
3689 
3690  estate->tuple_store_desc = rsi->expectedDesc;
3691 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:581
ResourceOwner tuple_store_owner
Definition: plpgsql.h:1057
ResourceOwner CurrentResourceOwner
Definition: resowner.c:144
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:704
TupleDesc expectedDesc
Definition: execnodes.h:303
TupleDesc tuple_store_desc
Definition: plpgsql.h:1055
#define ERROR
Definition: elog.h:45
MemoryContext tuple_store_cxt
Definition: plpgsql.h:1056
ReturnSetInfo * rsi
Definition: plpgsql.h:1058
Tuplestorestate * tuple_store
Definition: plpgsql.h:1054
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
int work_mem
Definition: globals.c:122
#define ereport(elevel,...)
Definition: elog.h:155
int allowedModes
Definition: execnodes.h:304
int errmsg(const char *fmt,...)
Definition: elog.c:915

◆ exec_move_row()

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

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

6686 {
6687  ExpandedRecordHeader *newerh = NULL;
6688 
6689  /*
6690  * If target is RECORD, we may be able to avoid field-by-field processing.
6691  */
6692  if (target->dtype == PLPGSQL_DTYPE_REC)
6693  {
6694  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
6695 
6696  /*
6697  * If we have no source tupdesc, just set the record variable to NULL.
6698  * (If we have a source tupdesc but not a tuple, we'll set the
6699  * variable to a row of nulls, instead. This is odd perhaps, but
6700  * backwards compatible.)
6701  */
6702  if (tupdesc == NULL)
6703  {
6704  if (rec->datatype &&
6705  rec->datatype->typtype == TYPTYPE_DOMAIN)
6706  {
6707  /*
6708  * If it's a composite domain, NULL might not be a legal
6709  * value, so we instead need to make an empty expanded record
6710  * and ensure that domain type checking gets done. If there
6711  * is already an expanded record, piggyback on its lookups.
6712  */
6713  newerh = make_expanded_record_for_rec(estate, rec,
6714  NULL, rec->erh);
6715  expanded_record_set_tuple(newerh, NULL, false, false);
6716  assign_record_var(estate, rec, newerh);
6717  }
6718  else
6719  {
6720  /* Just clear it to NULL */
6721  if (rec->erh)
6723  rec->erh = NULL;
6724  }
6725  return;
6726  }
6727 
6728  /*
6729  * Build a new expanded record with appropriate tupdesc.
6730  */
6731  newerh = make_expanded_record_for_rec(estate, rec, tupdesc, NULL);
6732 
6733  /*
6734  * If the rowtypes match, or if we have no tuple anyway, we can
6735  * complete the assignment without field-by-field processing.
6736  *
6737  * The tests here are ordered more or less in order of cheapness. We
6738  * can easily detect it will work if the target is declared RECORD or
6739  * has the same typeid as the source. But when assigning from a query
6740  * result, it's common to have a source tupdesc that's labeled RECORD
6741  * but is actually physically compatible with a named-composite-type
6742  * target, so it's worth spending extra cycles to check for that.
6743  */
6744  if (rec->rectypeid == RECORDOID ||
6745  rec->rectypeid == tupdesc->tdtypeid ||
6746  !HeapTupleIsValid(tup) ||
6748  {
6749  if (!HeapTupleIsValid(tup))
6750  {
6751  /* No data, so force the record into all-nulls state */
6753  }
6754  else
6755  {
6756  /* No coercion is needed, so just assign the row value */
6757  expanded_record_set_tuple(newerh, tup, true, !estate->atomic);
6758  }
6759 
6760  /* Complete the assignment */
6761  assign_record_var(estate, rec, newerh);
6762 
6763  return;
6764  }
6765  }
6766 
6767  /*
6768  * Otherwise, deconstruct the tuple and do field-by-field assignment,
6769  * using exec_move_row_from_fields.
6770  */
6771  if (tupdesc && HeapTupleIsValid(tup))
6772  {
6773  int td_natts = tupdesc->natts;
6774  Datum *values;
6775  bool *nulls;
6776  Datum values_local[64];
6777  bool nulls_local[64];
6778 
6779  /*
6780  * Need workspace arrays. If td_natts is small enough, use local
6781  * arrays to save doing a palloc. Even if it's not small, we can
6782  * allocate both the Datum and isnull arrays in one palloc chunk.
6783  */
6784  if (td_natts <= lengthof(values_local))
6785  {
6786  values = values_local;
6787  nulls = nulls_local;
6788  }
6789  else
6790  {
6791  char *chunk;
6792 
6793  chunk = eval_mcontext_alloc(estate,
6794  td_natts * (sizeof(Datum) + sizeof(bool)));
6795  values = (Datum *) chunk;
6796  nulls = (bool *) (chunk + td_natts * sizeof(Datum));
6797  }
6798 
6799  heap_deform_tuple(tup, tupdesc, values, nulls);
6800 
6801  exec_move_row_from_fields(estate, target, newerh,
6802  values, nulls, tupdesc);
6803  }
6804  else
6805  {
6806  /*
6807  * Assign all-nulls.
6808  */
6809  exec_move_row_from_fields(estate, target, newerh,
6810  NULL, NULL, NULL);
6811  }
6812 }
PLpgSQL_type * datatype
Definition: plpgsql.h:406
static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
Definition: pl_exec.c:8475
void expanded_record_set_tuple(ExpandedRecordHeader *erh, HeapTuple tuple, bool copy, bool expand_external)
ExpandedRecordHeader * erh
Definition: plpgsql.h:414
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:6961
#define lengthof(array)
Definition: c.h:734
static ExpandedRecordHeader * make_expanded_record_for_rec(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, TupleDesc srctupdesc, ExpandedRecordHeader *srcerh)
Definition: pl_exec.c:6898
#define eval_mcontext_alloc(estate, sz)
Definition: pl_exec.c:132
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:7227
void DeleteExpandedObject(Datum d)
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
PLpgSQL_datum_type dtype
Definition: plpgsql.h:289
char typtype
Definition: plpgsql.h:205
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1249
static Datum values[MAXATTR]
Definition: bootstrap.c:165
Oid tdtypeid
Definition: tupdesc.h:82
Oid rectypeid
Definition: plpgsql.h:407
#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 7357 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().

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

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

◆ exec_prepare_plan()

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

Definition at line 4131 of file pl_exec.c.

References SPIPrepareOptions::cursorOptions, elog, ERROR, exec_simple_check_plan(), PLpgSQL_expr::func, PLpgSQL_execstate::func, options, SPIPrepareOptions::parseMode, PLpgSQL_expr::parseMode, SPIPrepareOptions::parserSetup, SPIPrepareOptions::parserSetupArg, PLpgSQL_expr::plan, plpgsql_parser_setup(), PLpgSQL_expr::query, SPI_keepplan(), SPI_prepare_extended(), 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(), exec_stmt_return_query(), and exec_stmt_set().

4133 {
4134  SPIPlanPtr plan;
4136 
4137  /*
4138  * The grammar can't conveniently set expr->func while building the parse
4139  * tree, so make sure it's set before parser hooks need it.
4140  */
4141  expr->func = estate->func;
4142 
4143  /*
4144  * Generate and save the plan
4145  */
4146  memset(&options, 0, sizeof(options));
4148  options.parserSetupArg = (void *) expr;
4149  options.parseMode = expr->parseMode;
4150  options.cursorOptions = cursorOptions;
4151  plan = SPI_prepare_extended(expr->query, &options);
4152  if (plan == NULL)
4153  elog(ERROR, "SPI_prepare_extended failed for \"%s\": %s",
4155 
4156  SPI_keepplan(plan);
4157  expr->plan = plan;
4158 
4159  /* Check to see if it's a simple expression */
4160  exec_simple_check_plan(estate, expr);
4161 }
char * query
Definition: plpgsql.h:220
SPIPlanPtr SPI_prepare_extended(const char *src, const SPIPrepareOptions *options)
Definition: spi.c:798
PLpgSQL_function * func
Definition: plpgsql.h:1034
static void exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:7888
SPIPlanPtr plan
Definition: plpgsql.h:222
int SPI_result
Definition: spi.c:47
#define ERROR
Definition: elog.h:45
const char * SPI_result_code_string(int code)
Definition: spi.c:1862
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:1080
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:872
ParserSetupHook parserSetup
Definition: spi.h:39
static char ** options
int cursorOptions
Definition: spi.h:42
struct PLpgSQL_function * func
Definition: plpgsql.h:226
RawParseMode parseMode
Definition: plpgsql.h:221
#define elog(elevel,...)
Definition: elog.h:228
void * parserSetupArg
Definition: spi.h:40
RawParseMode parseMode
Definition: spi.h:41

◆ exec_run_select()

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

Definition at line 5745 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(), and exec_stmt_perform().

5747 {
5748  ParamListInfo paramLI;
5749  int rc;
5750 
5751  /*
5752  * On the first call for this expression generate the plan.
5753  *
5754  * If we don't need to return a portal, then we're just going to execute
5755  * the query once, which means it's OK to use a parallel plan, even if the
5756  * number of rows being fetched is limited. If we do need to return a
5757  * portal, the caller might do cursor operations, which parallel query
5758  * can't support.
5759  */
5760  if (expr->plan == NULL)
5761  exec_prepare_plan(estate, expr,
5762  portalP == NULL ? CURSOR_OPT_PARALLEL_OK : 0);
5763 
5764  /*
5765  * Set up ParamListInfo to pass to executor
5766  */
5767  paramLI = setup_param_list(estate, expr);
5768 
5769  /*
5770  * If a portal was requested, put the query and paramlist into the portal
5771  */
5772  if (portalP != NULL)
5773  {
5774  *portalP = SPI_cursor_open_with_paramlist(NULL, expr->plan,
5775  paramLI,
5776  estate->readonly_func);
5777  if (*portalP == NULL)
5778  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
5780  exec_eval_cleanup(estate);
5781  return SPI_OK_CURSOR;
5782  }
5783 
5784  /*
5785  * Execute the query
5786  */
5787  rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
5788  estate->readonly_func, maxtuples);
5789  if (rc != SPI_OK_SELECT)
5790  ereport(ERROR,
5791  (errcode(ERRCODE_SYNTAX_ERROR),
5792  errmsg("query \"%s\" is not a SELECT", expr->query)));
5793 
5794  /* Save query results for eventual cleanup */
5795  Assert(estate->eval_tuptable == NULL);
5796  estate->eval_tuptable = SPI_tuptable;
5797  estate->eval_processed = SPI_processed;
5798 
5799  return rc;
5800 }
char * query
Definition: plpgsql.h:220
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1097
uint64 eval_processed
Definition: plpgsql.h:1098
Portal SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan, ParamListInfo params, bool read_only)
Definition: spi.c:1421
SPITupleTable * SPI_tuptable
Definition: spi.c:46
int errcode(int sqlerrcode)
Definition: elog.c:704
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4110
#define SPI_OK_CURSOR
Definition: spi.h:90
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:45
int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params, bool read_only, long tcount)
Definition: spi.c:640
const char * SPI_result_code_string(int code)
Definition: spi.c:1862
static ParamListInfo setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:6192
#define SPI_OK_SELECT
Definition: spi.h:85
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions)
Definition: pl_exec.c:4131
#define ereport(elevel,...)
Definition: elog.h:155
#define Assert(condition)
Definition: c.h:804
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2759
int errmsg(const char *fmt,...)
Definition: elog.c:915
#define elog(elevel,...)
Definition: elog.h:228

◆ exec_save_simple_expr()

static void exec_save_simple_expr ( PLpgSQL_expr expr,
CachedPlan cplan 
)
static

Definition at line 8006 of file pl_exec.c.

References Assert, castNode, CMD_SELECT, PlannedStmt::commandType, contain_mutable_functions(), elog, ERROR, exec_check_rw_parameter(), 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().

8007 {
8008  PlannedStmt *stmt;
8009  Plan *plan;
8010  Expr *tle_expr;
8011 
8012  /*
8013  * Given the checks that exec_simple_check_plan did, none of the Asserts
8014  * here should ever fail.
8015  */
8016 
8017  /* Extract the single PlannedStmt */
8018  Assert(list_length(cplan->stmt_list) == 1);
8019  stmt = linitial_node(PlannedStmt, cplan->stmt_list);
8020  Assert(stmt->commandType == CMD_SELECT);
8021 
8022  /*
8023  * Ordinarily, the plan node should be a simple Result. However, if
8024  * force_parallel_mode is on, the planner might've stuck a Gather node
8025  * atop that. The simplest way to deal with this is to look through the
8026  * Gather node. The Gather node's tlist would normally contain a Var
8027  * referencing the child node's output, but it could also be a Param, or
8028  * it could be a Const that setrefs.c copied as-is.
8029  */
8030  plan = stmt->planTree;
8031  for (;;)
8032  {
8033  /* Extract the single tlist expression */
8034  Assert(list_length(plan->targetlist) == 1);
8035  tle_expr = castNode(TargetEntry, linitial(plan->targetlist))->expr;
8036 
8037  if (IsA(plan, Result))
8038  {
8039  Assert(plan->lefttree == NULL &&
8040  plan->righttree == NULL &&
8041  plan->initPlan == NULL &&
8042  plan->qual == NULL &&
8043  ((Result *) plan)->resconstantqual == NULL);
8044  break;
8045  }
8046  else if (IsA(plan, Gather))
8047  {
8048  Assert(plan->lefttree != NULL &&
8049  plan->righttree == NULL &&
8050  plan->initPlan == NULL &&
8051  plan->qual == NULL);
8052  /* If setrefs.c copied up a Const, no need to look further */
8053  if (IsA(tle_expr, Const))
8054  break;
8055  /* Otherwise, it had better be a Param or an outer Var */
8056  Assert(IsA(tle_expr, Param) || (IsA(tle_expr, Var) &&
8057  ((Var *) tle_expr)->varno == OUTER_VAR));
8058  /* Descend to the child node */
8059  plan = plan->lefttree;
8060  }
8061  else
8062  elog(ERROR, "unexpected plan node type: %d",
8063  (int) nodeTag(plan));
8064  }
8065 
8066  /*
8067  * Save the simple expression, and initialize state to "not valid in
8068  * current transaction".
8069  */
8070  expr->expr_simple_expr = tle_expr;
8071  expr->expr_simple_state = NULL;
8072  expr->expr_simple_in_use = false;
8074  /* Also stash away the expression result type */
8075  expr->expr_simple_type = exprType((Node *) tle_expr);
8076  expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
8077  /* We also want to remember if it is immutable or not */
8078  expr->expr_simple_mutable = contain_mutable_functions((Node *) tle_expr);
8079 
8080  /*
8081  * Lastly, check to see if there's a possibility of optimizing a
8082  * read/write parameter.
8083  */
8085 }
List * qual
Definition: plannodes.h:137
#define IsA(nodeptr, _type_)
Definition: nodes.h:581
#define castNode(_type_, nodeptr)
Definition: nodes.h:599
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:267
Definition: nodes.h:530
Definition: primnodes.h:181
#define linitial_node(type, l)
Definition: pg_list.h:177
struct Plan * planTree
Definition: plannodes.h:64
struct Plan * righttree
Definition: plannodes.h:139
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:45
Expr * expr_simple_expr
Definition: plpgsql.h:232
ExprState * expr_simple_state
Definition: plpgsql.h:264
bool expr_simple_mutable
Definition: plpgsql.h:235
CmdType commandType
Definition: plannodes.h:46
LocalTransactionId expr_simple_lxid
Definition: plpgsql.h:266
static void exec_check_rw_parameter(PLpgSQL_expr *expr)
Definition: pl_exec.c:8113
#define Assert(condition)
Definition: c.h:804
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
static int list_length(const List *l)
Definition: pg_list.h:149
struct Plan * lefttree
Definition: plannodes.h:138
#define nodeTag(nodeptr)
Definition: nodes.h:535
List * targetlist
Definition: plannodes.h:136
int32 expr_simple_typmod
Definition: plpgsql.h:234
List * initPlan
Definition: plannodes.h:140
#define elog(elevel,...)
Definition: elog.h:228
#define InvalidLocalTransactionId
Definition: lock.h:69
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:358
List * stmt_list
Definition: plancache.h:150
bool expr_simple_in_use
Definition: plpgsql.h:265
#define OUTER_VAR
Definition: primnodes.h:172
Oid expr_simple_type
Definition: plpgsql.h:233

◆ exec_set_found()

static void exec_set_found ( PLpgSQL_execstate estate,
bool  state 
)
static

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

8224 {
8225  PLpgSQL_var *var;
8226 
8227  var = (PLpgSQL_var *) (estate->datums[estate->found_varno]);
8228  assign_simple_var(estate, var, BoolGetDatum(state), false, false);
8229 }
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8399
PLpgSQL_datum ** datums
Definition: plpgsql.h:1069
#define BoolGetDatum(X)
Definition: postgres.h:402
Definition: regguts.h:317

◆ exec_simple_check_plan()

static void exec_simple_check_plan ( PLpgSQL_execstate estate,
PLpgSQL_expr expr 
)
static

Definition at line 7888 of file pl_exec.c.

References Assert, CachedPlanAllowsSimpleValidityCheck(), CMD_SELECT, Query::commandType, Query::cteList, CurrentResourceOwner, Query::distinctClause, exec_save_simple_expr(), PLpgSQL_expr::expr_rw_param, 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().

7889 {
7890  List *plansources;
7891  CachedPlanSource *plansource;
7892  Query *query;
7893  CachedPlan *cplan;
7894  MemoryContext oldcontext;
7895 
7896  /*
7897  * Initialize to "not simple".
7898  */
7899  expr->expr_simple_expr = NULL;
7900  expr->expr_rw_param = NULL;
7901 
7902  /*
7903  * Check the analyzed-and-rewritten form of the query to see if we will be
7904  * able to treat it as a simple expression. Since this function is only
7905  * called immediately after creating the CachedPlanSource, we need not
7906  * worry about the query being stale.
7907  */
7908 
7909  /*
7910  * We can only test queries that resulted in exactly one CachedPlanSource
7911  */
7912  plansources = SPI_plan_get_plan_sources(expr->plan);
7913  if (list_length(plansources) != 1)
7914  return;
7915  plansource = (CachedPlanSource *) linitial(plansources);
7916 
7917  /*
7918  * 1. There must be one single querytree.
7919  */
7920  if (list_length(plansource->query_list) != 1)
7921  return;
7922  query = (Query *) linitial(plansource->query_list);
7923 
7924  /*
7925  * 2. It must be a plain SELECT query without any input tables
7926  */
7927  if (!IsA(query, Query))
7928  return;
7929  if (query->commandType != CMD_SELECT)
7930  return;
7931  if (query->rtable != NIL)
7932  return;
7933 
7934  /*
7935  * 3. Can't have any subplans, aggregates, qual clauses either. (These
7936  * tests should generally match what inline_function() checks before
7937  * inlining a SQL function; otherwise, inlining could change our
7938  * conclusion about whether an expression is simple, which we don't want.)
7939  */
7940  if (query->hasAggs ||
7941  query->hasWindowFuncs ||
7942  query->hasTargetSRFs ||
7943  query->hasSubLinks ||
7944  query->cteList ||
7945  query->jointree->fromlist ||
7946  query->jointree->quals ||
7947  query->groupClause ||
7948  query->groupingSets ||
7949  query->havingQual ||
7950  query->windowClause ||
7951  query->distinctClause ||
7952  query->sortClause ||
7953  query->limitOffset ||
7954  query->limitCount ||
7955  query->setOperations)
7956  return;
7957 
7958  /*
7959  * 4. The query must have a single attribute as result
7960  */
7961  if (list_length(query->targetList) != 1)
7962  return;
7963 
7964  /*
7965  * OK, we can treat it as a simple plan.
7966  *
7967  * Get the generic plan for the query. If replanning is needed, do that
7968  * work in the eval_mcontext.
7969  */
7970  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7971  cplan = SPI_plan_get_cached_plan(expr->plan);
7972  MemoryContextSwitchTo(oldcontext);
7973 
7974  /* Can't fail, because we checked for a single CachedPlanSource above */
7975  Assert(cplan != NULL);
7976 
7977  /*
7978  * Verify that plancache.c thinks the plan is simple enough to use
7979  * CachedPlanIsSimplyValid. Given the restrictions above, it's unlikely
7980  * that this could fail, but if it does, just treat plan as not simple. On
7981  * success, save a refcount on the plan in the simple-expression resowner.
7982  */
7983  if (CachedPlanAllowsSimpleValidityCheck(plansource, cplan,
7984  estate->simple_eval_resowner))
7985  {
7986  /* Remember that we have the refcount */
7987  expr->expr_simple_plansource = plansource;
7988  expr->expr_simple_plan = cplan;
7990 
7991  /* Share the remaining work with the replan code path */
7992  exec_save_simple_expr(expr, cplan);
7993  }
7994 
7995  /*
7996  * Release the plan refcount obtained by SPI_plan_get_cached_plan. (This
7997  * refcount is held by the wrong resowner, so we can't just repurpose it.)
7998  */
8000 }
Node * limitOffset
Definition: parsenodes.h:160
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:581
List * sortClause
Definition: parsenodes.h:158
Param * expr_rw_param
Definition: plpgsql.h:246
ResourceOwner simple_eval_resowner
Definition: plpgsql.h:1083
FromExpr * jointree
Definition: parsenodes.h:138
PGPROC * MyProc
Definition: proc.c:68
ResourceOwner CurrentResourceOwner
Definition: resowner.c:144
bool hasAggs
Definition: parsenodes.h:125
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
List * groupingSets
Definition: parsenodes.h:150
void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1264
List * fromlist
Definition: primnodes.h:1534
Node * quals
Definition: primnodes.h:1535
static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
Definition: pl_exec.c:8006
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:1958
#define linitial(l)
Definition: pg_list.h:174
List * rtable
Definition: parsenodes.h:137
List * distinctClause
Definition: parsenodes.h:156
CachedPlanSource * expr_simple_plansource
Definition: plpgsql.h:254
Node * limitCount
Definition: parsenodes.h:161
Expr * expr_simple_expr
Definition: plpgsql.h:232
bool CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1309
#define get_eval_mcontext(estate)
Definition: pl_exec.c:130
CachedPlan * expr_simple_plan
Definition: plpgsql.h:255
CmdType commandType
Definition: parsenodes.h:112
bool hasTargetSRFs
Definition: parsenodes.h:127
#define Assert(condition)
Definition: c.h:804
bool hasWindowFuncs
Definition: parsenodes.h:126
static int list_length(const List *l)
Definition: pg_list.h:149
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:1939
List * query_list
Definition: plancache.h:111
LocalTransactionId expr_simple_plan_lxid
Definition: plpgsql.h:256
Node * havingQual
Definition: parsenodes.h:152
Definition: pg_list.h:50
LocalTransactionId lxid
Definition: proc.h:143

◆ exec_stmt_assert()

static int exec_stmt_assert ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assert stmt 
)
static

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

3920 {
3921  bool value;
3922  bool isnull;
3923 
3924  /* do nothing when asserts are not enabled */
3925  if (!plpgsql_check_asserts)
3926  return PLPGSQL_RC_OK;
3927 
3928  value = exec_eval_boolean(estate, stmt->cond, &isnull);
3929  exec_eval_cleanup(estate);
3930 
3931  if (isnull || !value)
3932  {
3933  char *message = NULL;
3934 
3935  if (stmt->message != NULL)
3936  {
3937  Datum val;
3938  Oid typeid;
3939  int32 typmod;
3940 
3941  val = exec_eval_expr(estate, stmt->message,
3942  &isnull, &typeid, &typmod);
3943  if (!isnull)
3944  message = convert_value_to_string(estate, val, typeid);
3945  /* we mustn't do exec_eval_cleanup here */
3946  }
3947 
3948  ereport(ERROR,
3949  (errcode(ERRCODE_ASSERT_FAILURE),
3950  message ? errmsg_internal("%s", message) :
3951  errmsg("assertion failed")));
3952  }
3953 
3954  return PLPGSQL_RC_OK;
3955 }
int errcode(int sqlerrcode)
Definition: elog.c:704
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4110
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:429
static struct @141 value
#define ERROR
Definition: elog.h:45
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5662
PLpgSQL_expr * message
Definition: plpgsql.h:896
static bool exec_eval_boolean(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
Definition: pl_exec.c:5639
uintptr_t Datum
Definition: postgres.h:367
#define ereport(elevel,...)
Definition: elog.h:155
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1002
int errmsg(const char *fmt,...)
Definition: elog.c:915
static char * convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
Definition: pl_exec.c:7625
PLpgSQL_expr * cond
Definition: plpgsql.h:895
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 2124 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_stmts().

2125 {
2126  Assert(stmt->varno >= 0);
2127 
2128  exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);
2129 
2130  return PLPGSQL_RC_OK;
2131 }
PLpgSQL_datum ** datums
Definition: plpgsql.h:1069
static void exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
Definition: pl_exec.c:4986
#define Assert(condition)
Definition: c.h:804
PLpgSQL_expr * expr
Definition: plpgsql.h:520

◆ exec_stmt_block()

static int exec_stmt_block ( PLpgSQL_execstate estate,
PLpgSQL_stmt_block block 
)
static

Definition at line 1626 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_stmts(), and exec_toplevel_block().

1627 {
1628  volatile int rc = -1;
1629  int i;
1630 
1631  /*
1632  * First initialize all variables declared in this block
1633  */
1634  estate->err_text = gettext_noop("during statement block local variable initialization");
1635 
1636  for (i = 0; i < block->n_initvars; i++)
1637  {
1638  int n = block->initvarnos[i];
1639  PLpgSQL_datum *datum = estate->datums[n];
1640 
1641  /*
1642  * The set of dtypes handled here must match plpgsql_add_initdatums().
1643  *
1644  * Note that we currently don't support promise datums within blocks,
1645  * only at a function's outermost scope, so we needn't handle those
1646  * here.
1647  */
1648  switch (datum->dtype)
1649  {
1650  case PLPGSQL_DTYPE_VAR:
1651  {
1652  PLpgSQL_var *var = (PLpgSQL_var *) datum;
1653 
1654  /*
1655  * Free any old value, in case re-entering block, and
1656  * initialize to NULL
1657  */
1658  assign_simple_var(estate, var, (Datum) 0, true, false);
1659 
1660  if (var->default_val == NULL)
1661  {
1662  /*
1663  * If needed, give the datatype a chance to reject
1664  * NULLs, by assigning a NULL to the variable. We
1665  * claim the value is of type UNKNOWN, not the var's
1666  * datatype, else coercion will be skipped.
1667  */
1668  if (var->datatype->typtype == TYPTYPE_DOMAIN)
1669  exec_assign_value(estate,
1670  (PLpgSQL_datum *) var,
1671  (Datum) 0,
1672  true,
1673  UNKNOWNOID,
1674  -1);
1675 
1676  /* parser should have rejected NOT NULL */
1677  Assert(!var->notnull);
1678  }
1679  else
1680  {
1681  exec_assign_expr(estate, (PLpgSQL_datum *) var,
1682  var->default_val);
1683  }
1684  }
1685  break;
1686 
1687  case PLPGSQL_DTYPE_REC:
1688  {
1689  PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
1690 
1691  /*
1692  * Deletion of any existing object will be handled during
1693  * the assignments below, and in some cases it's more
1694  * efficient for us not to get rid of it beforehand.
1695  */
1696  if (rec->default_val == NULL)
1697  {
1698  /*
1699  * If needed, give the datatype a chance to reject
1700  * NULLs, by assigning a NULL to the variable.
1701  */
1702  exec_move_row(estate, (PLpgSQL_variable *) rec,
1703  NULL, NULL);
1704 
1705  /* parser should have rejected NOT NULL */
1706  Assert(!rec->notnull);
1707  }
1708  else
1709  {
1710  exec_assign_expr(estate, (PLpgSQL_datum *) rec,
1711  rec->default_val);
1712  }
1713  }
1714  break;
1715 
1716  default:
1717  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
1718  }
1719  }
1720 
1721  if (block->exceptions)
1722  {
1723  /*
1724  * Execute the statements in the block's body inside a sub-transaction
1725  */
1726  MemoryContext oldcontext = CurrentMemoryContext;
1728  ExprContext *old_eval_econtext = estate->eval_econtext;
1729  ErrorData *save_cur_error = estate->cur_error;
1730  MemoryContext stmt_mcontext;
1731 
1732  estate->err_text = gettext_noop("during statement block entry");
1733 
1734  /*
1735  * We will need a stmt_mcontext to hold the error data if an error
1736  * occurs. It seems best to force it to exist before entering the
1737  * subtransaction, so that we reduce the risk of out-of-memory during
1738  * error recovery, and because this greatly simplifies restoring the
1739  * stmt_mcontext stack to the correct state after an error. We can
1740  * ameliorate the cost of this by allowing the called statements to
1741  * use this mcontext too; so we don't push it down here.
1742  */
1743  stmt_mcontext = get_stmt_mcontext(estate);
1744 
1746  /* Want to run statements inside function's memory context */
1747  MemoryContextSwitchTo(oldcontext);
1748 
1749  PG_TRY();
1750  {
1751  /*
1752  * We need to run the block's statements with a new eval_econtext
1753  * that belongs to the current subtransaction; if we try to use
1754  * the outer econtext then ExprContext shutdown callbacks will be
1755  * called at the wrong times.
1756  */
1757  plpgsql_create_econtext(estate);
1758 
1759  estate->err_text = NULL;
1760 
1761  /* Run the block's statements */
1762  rc = exec_stmts(estate, block->body);
1763 
1764  estate->err_text = gettext_noop("during statement block exit");
1765 
1766  /*
1767  * If the block ended with RETURN, we may need to copy the return
1768  * value out of the subtransaction eval_context. We can avoid a
1769  * physical copy if the value happens to be a R/W expanded object.
1770  */
1771  if (rc == PLPGSQL_RC_RETURN &&
1772  !estate->retisset &&
1773  !estate->retisnull)
1774  {
1775  int16 resTypLen;
1776  bool resTypByVal;
1777 
1778  get_typlenbyval(estate->rettype, &resTypLen, &resTypByVal);
1779  estate->retval = datumTransfer(estate->retval,
1780  resTypByVal, resTypLen);
1781  }
1782 
1783  /* Commit the inner transaction, return to outer xact context */
1785  MemoryContextSwitchTo(oldcontext);
1786  CurrentResourceOwner = oldowner;
1787 
1788  /* Assert that the stmt_mcontext stack is unchanged */
1789  Assert(stmt_mcontext == estate->stmt_mcontext);
1790 
1791  /*
1792  * Revert to outer eval_econtext. (The inner one was
1793  * automatically cleaned up during subxact exit.)
1794  */
1795  estate->eval_econtext = old_eval_econtext;
1796  }
1797  PG_CATCH();
1798  {
1799  ErrorData *edata;
1800  ListCell *e;
1801 
1802  estate->err_text = gettext_noop("during exception cleanup");
1803 
1804  /* Save error info in our stmt_mcontext */
1805  MemoryContextSwitchTo(stmt_mcontext);
1806  edata = CopyErrorData();
1807  FlushErrorState();
1808 
1809  /* Abort the inner transaction */
1811  MemoryContextSwitchTo(oldcontext);
1812  CurrentResourceOwner = oldowner;
1813 
1814  /*
1815  * Set up the stmt_mcontext stack as though we had restored our
1816  * previous state and then done push_stmt_mcontext(). The push is
1817  * needed so that statements in the exception handler won't
1818  * clobber the error data that's in our stmt_mcontext.
1819  */
1820  estate->stmt_mcontext_parent = stmt_mcontext;
1821  estate->stmt_mcontext = NULL;
1822 
1823  /*
1824  * Now we can delete any nested stmt_mcontexts that might have
1825  * been created as children of ours. (Note: we do not immediately
1826  * release any statement-lifespan data that might have been left
1827  * behind in stmt_mcontext itself. We could attempt that by doing
1828  * a MemoryContextReset on it before collecting the error data
1829  * above, but it seems too risky to do any significant amount of
1830  * work before collecting the error.)
1831  */
1832  MemoryContextDeleteChildren(stmt_mcontext);
1833 
1834  /* Revert to outer eval_econtext */
1835  estate->eval_econtext = old_eval_econtext;
1836 
1837  /*
1838  * Must clean up the econtext too. However, any tuple table made
1839  * in the subxact will have been thrown away by SPI during subxact
1840  * abort, so we don't need to (and mustn't try to) free the
1841  * eval_tuptable.
1842  */
1843  estate->eval_tuptable = NULL;
1844  exec_eval_cleanup(estate);
1845 
1846  /* Look for a matching exception handler */
1847  foreach(e, block->exceptions->exc_list)
1848  {
1849  PLpgSQL_exception *exception = (PLpgSQL_exception *) lfirst(e);
1850 
1851  if (exception_matches_conditions(edata, exception->conditions))
1852  {
1853  /*
1854  * Initialize the magic SQLSTATE and SQLERRM variables for
1855  * the exception block; this also frees values from any
1856  * prior use of the same exception. We needn't do this
1857  * until we have found a matching exception.
1858  */
1859  PLpgSQL_var *state_var;
1860  PLpgSQL_var *errm_var;
1861 
1862  state_var = (PLpgSQL_var *)
1863  estate->datums[block->exceptions->sqlstate_varno];
1864  errm_var = (PLpgSQL_var *)
1865  estate->datums[block->exceptions->sqlerrm_varno];
1866 
1867  assign_text_var(estate, state_var,
1868  unpack_sql_state(edata->sqlerrcode));
1869  assign_text_var(estate, errm_var, edata->message);
1870 
1871  /*
1872  * Also set up cur_error so the error data is accessible
1873  * inside the handler.
1874  */
1875  estate->cur_error = edata;
1876 
1877  estate->err_text = NULL;
1878 
1879  rc = exec_stmts(estate, exception->action);
1880 
1881  break;
1882  }
1883  }
1884 
1885  /*
1886  * Restore previous state of cur_error, whether or not we executed
1887  * a handler. This is needed in case an error got thrown from
1888  * some inner block's exception handler.
1889  */
1890  estate->cur_error = save_cur_error;
1891 
1892  /* If no match found, re-throw the error */
1893  if (e == NULL)
1894  ReThrowError(edata);
1895 
1896  /* Restore stmt_mcontext stack and release the error data */
1897  pop_stmt_mcontext(estate);
1898  MemoryContextReset(stmt_mcontext);
1899  }
1900  PG_END_TRY();
1901 
1902  Assert(save_cur_error == estate->cur_error);
1903  }
1904  else
1905  {
1906  /*
1907  * Just execute the statements in the block's body
1908  */
1909  estate->err_text = NULL;
1910 
1911  rc = exec_stmts(estate, block->body);
1912  }
1913 
1914  estate->err_text = NULL;
1915 
1916  /*
1917  * Handle the return code. This is intentionally different from
1918  * LOOP_RC_PROCESSING(): CONTINUE never matches a block, and EXIT matches
1919  * a block only if there is a label match.
1920  */
1921  switch (rc)
1922  {
1923  case PLPGSQL_RC_OK:
1924  case PLPGSQL_RC_RETURN:
1925  case PLPGSQL_RC_CONTINUE:
1926  return rc;
1927 
1928  case PLPGSQL_RC_EXIT:
1929  if (estate->exitlabel == NULL)
1930  return PLPGSQL_RC_EXIT;
1931  if (block->label == NULL)
1932  return PLPGSQL_RC_EXIT;
1933  if (strcmp(block->label, estate->exitlabel) != 0)
1934  return PLPGSQL_RC_EXIT;
1935  estate->exitlabel = NULL;
1936  return PLPGSQL_RC_OK;
1937 
1938  default:
1939  elog(ERROR, "unrecognized rc: %d", rc);
1940  }
1941 
1942  return PLPGSQL_RC_OK;
1943 }
signed short int16
Definition: c.h:428
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1097
int sqlerrcode
Definition: elog.h:378
ErrorData * CopyErrorData(void)
Definition: elog.c:1565
ResourceOwner CurrentResourceOwner
Definition: resowner.c:144
void ReleaseCurrentSubTransaction(void)
Definition: xact.c:4478
char * unpack_sql_state(int sql_state)
Definition: elog.c:2979
PLpgSQL_type * datatype
Definition: plpgsql.h:320
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define gettext_noop(x)
Definition: c.h:1197
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8399
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:137
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4110
PLpgSQL_datum_type dtype
Definition: plpgsql.h:277
void FlushErrorState(void)
Definition: elog.c:1659
PLpgSQL_datum ** datums
Definition: plpgsql.h:1069
static void exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
Definition: pl_exec.c:4986
#define ERROR
Definition: elog.h:45
PLpgSQL_expr * default_val
Definition: plpgsql.h:317
void RollbackAndReleaseCurrentSubTransaction(void)
Definition: xact.c:4512
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1507
static bool exception_matches_conditions(ErrorData *edata, PLpgSQL_condition *cond)
Definition: pl_exec.c:1558
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:257
ErrorData * cur_error
Definition: plpgsql.h:1052
MemoryContext stmt_mcontext_parent
Definition: plpgsql.h:1094
uintptr_t Datum
Definition: postgres.h:367
const char * err_text
Definition: plpgsql.h:1103
PLpgSQL_condition * conditions
Definition: plpgsql.h:492
Datum datumTransfer(Datum value, bool typByVal, int typLen)
Definition: datum.c:193
#define PG_CATCH()
Definition: elog.h:319
static void assign_text_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, const char *str)
Definition: pl_exec.c:8466
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
PLpgSQL_exception_block * exceptions
Definition: plpgsql.h:508
void BeginInternalSubTransaction(const char *name)
Definition: xact.c:4407
ExprContext * eval_econtext
Definition: plpgsql.h:1099
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2198
char typtype
Definition: plpgsql.h:205
e
Definition: preproc-init.c:82
static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
Definition: pl_exec.c:6683
#define elog(elevel,...)
Definition: elog.h:228
int i
static void plpgsql_create_econtext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:8239
MemoryContext stmt_mcontext
Definition: plpgsql.h:1093
static void pop_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1545
char * exitlabel
Definition: plpgsql.h:1050
#define PG_TRY()
Definition: elog.h:309
PLpgSQL_expr * default_val
Definition: plpgsql.h:397
bool notnull
Definition: plpgsql.h:396
#define PG_END_TRY()
Definition: elog.h:334
void ReThrowError(ErrorData *edata)
Definition: elog.c:1743
char * message
Definition: elog.h:379
static int exec_stmts(PLpgSQL_execstate *estate, List *stmts)
Definition: pl_exec.c:1952
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:5058

◆ exec_stmt_call()

static int exec_stmt_call ( PLpgSQL_execstate estate,
PLpgSQL_stmt_call stmt 
)
static

Definition at line 2157 of file pl_exec.c.

References Assert, elog, ERROR, exec_eval_cleanup(), exec_move_row(), exec_prepare_plan(), PLpgSQL_stmt_call::expr, PLpgSQL_expr::expr_simple_expr, GetTransactionSnapshot(), PLpgSQL_stmt_call::is_call, PGPROC::lxid, make_callstmt_target(), MyProc, SPIExecuteOptions::no_snapshots, options, SPIExecuteOptions::owner, SPIExecuteOptions::params, PLpgSQL_expr::plan, plpgsql_create_econtext(), PLPGSQL_RC_OK, PopActiveSnapshot(), PLpgSQL_execstate::procedure_resowner, PushActiveSnapshot(), PLpgSQL_expr::query, SPIExecuteOptions::read_only, PLpgSQL_execstate::readonly_func, setup_param_list(), PLpgSQL_execstate::simple_eval_estate, PLpgSQL_execstate::simple_eval_resowner, SPI_execute_plan_extended(), SPI_freetuptable(), SPI_processed, SPI_result_code_string(), SPI_tuptable, PLpgSQL_stmt_call::target, SPITupleTable::tupdesc, and SPITupleTable::vals.

Referenced by exec_stmts().

2158 {
2159  PLpgSQL_expr *expr = stmt->expr;
2160  LocalTransactionId before_lxid;
2161  LocalTransactionId after_lxid;
2162  bool pushed_active_snap = false;
2163  ParamListInfo paramLI;
2165  int rc;
2166 
2167  /*
2168  * Make a plan if we don't have one already.
2169  */
2170  if (expr->plan == NULL)
2171  {
2172  exec_prepare_plan(estate, expr, 0);
2173 
2174  /*
2175  * A CALL or DO can never be a simple expression.
2176  */
2177  Assert(!expr->expr_simple_expr);
2178 
2179  /*
2180  * Also construct a DTYPE_ROW datum representing the plpgsql variables
2181  * associated with the procedure's output arguments. Then we can use
2182  * exec_move_row() to do the assignments.
2183  */
2184  if (stmt->is_call)
2185  stmt->target = make_callstmt_target(estate, expr);
2186  }
2187 
2188  paramLI = setup_param_list(estate, expr);
2189 
2190  before_lxid = MyProc->lxid;
2191 
2192  /*
2193  * The procedure call could end transactions, which would upset the
2194  * snapshot management in SPI_execute*, so handle snapshots here instead.
2195  * Set a snapshot only for non-read-only procedures, similar to SPI
2196  * behavior.
2197  */
2198  if (!estate->readonly_func)
2199  {
2201  pushed_active_snap = true;
2202  }
2203 
2204  /*
2205  * If we have a procedure-lifespan resowner, use that to hold the refcount
2206  * for the plan. This avoids refcount leakage complaints if the called
2207  * procedure ends the current transaction.
2208  */
2209  memset(&options, 0, sizeof(options));
2210  options.params = paramLI;
2211  options.read_only = estate->readonly_func;
2212  options.no_snapshots = true; /* disable SPI's snapshot management */
2213  options.owner = estate->procedure_resowner;
2214 
2215  rc = SPI_execute_plan_extended(expr->plan, &options);
2216 
2217  if (rc < 0)
2218  elog(ERROR, "SPI_execute_plan_extended failed executing query \"%s\": %s",
2219  expr->query, SPI_result_code_string(rc));
2220 
2221  after_lxid = MyProc->lxid;
2222 
2223  if (before_lxid == after_lxid)
2224  {
2225  /*
2226  * If we are still in the same transaction after the call, pop the
2227  * snapshot that we might have pushed. (If it's a new transaction,
2228  * then all the snapshots are gone already.)
2229  */
2230  if (pushed_active_snap)
2232  }
2233  else
2234  {
2235  /*
2236  * If we are in a new transaction after the call, we need to build new
2237  * simple-expression infrastructure.
2238  */
2239  estate->simple_eval_estate = NULL;
2240  estate->simple_eval_resowner = NULL;
2241  plpgsql_create_econtext(estate);
2242  }
2243 
2244  /*
2245  * Check result rowcount; if there's one row, assign procedure's output
2246  * values back to the appropriate variables.
2247  */
2248  if (SPI_processed == 1)
2249  {
2250  SPITupleTable *tuptab = SPI_tuptable;
2251 
2252  if (!stmt->is_call)
2253  elog(ERROR, "DO statement returned a row");
2254 
2255  exec_move_row(estate, stmt->target, tuptab->vals[0], tuptab->tupdesc);
2256  }
2257  else if (SPI_processed > 1)
2258  elog(ERROR, "procedure call returned more than one row");
2259 
2260  exec_eval_cleanup(estate);
2262 
2263  return PLPGSQL_RC_OK;
2264 }
char * query
Definition: plpgsql.h:220
ResourceOwner simple_eval_resowner
Definition: plpgsql.h:1083
PGPROC * MyProc
Definition: proc.c:68
SPITupleTable * SPI_tuptable
Definition: spi.c:46
void PopActiveSnapshot(void)
Definition: snapmgr.c:759
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4110
int SPI_execute_plan_extended(SPIPlanPtr plan, const SPIExecuteOptions *options)
Definition: spi.c:616
HeapTuple * vals
Definition: spi.h:26
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:250
uint64 SPI_processed
Definition: spi.c:45
SPIPlanPtr plan
Definition: plpgsql.h:222
#define ERROR
Definition: elog.h:45
EState * simple_eval_estate
Definition: plpgsql.h:1082
const char * SPI_result_code_string(int code)
Definition: spi.c:1862
ResourceOwner owner
Definition: spi.h:53
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:680
bool no_snapshots
Definition: spi.h:50
ResourceOwner procedure_resowner
Definition: plpgsql.h:1086
Expr * expr_simple_expr
Definition: plpgsql.h:232
uint32 LocalTransactionId
Definition: c.h:589
static ParamListInfo setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:6192
ParamListInfo params
Definition: spi.h:48
bool read_only
Definition: spi.h:49
static char ** options
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1282
PLpgSQL_expr * expr
Definition: plpgsql.h:542
TupleDesc tupdesc
Definition: spi.h:25
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions)
Definition: pl_exec.c:4131
#define Assert(condition)
Definition: c.h:804
PLpgSQL_variable * target
Definition: plpgsql.h:544
static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
Definition: pl_exec.c:6683
#define elog(elevel,...)
Definition: elog.h:228
static void plpgsql_create_econtext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:8239
static PLpgSQL_variable * make_callstmt_target(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:2272
LocalTransactionId lxid
Definition: proc.h:143

◆ exec_stmt_case()

static int exec_stmt_case ( PLpgSQL_execstate estate,
PLpgSQL_stmt_case stmt 
)
static

Definition at line 2534 of file pl_exec.c.

References assign_simple_var(), PLpgSQL_type::atttypmod, PLpgSQL_stmt_case::case_when_list, PLpgSQL_var::datatype, PLpgSQL_execstate::datums, PLpgSQL_stmt_case::else_stmts, ereport, errcode(), errhint(), errmsg(), ERROR, exec_assign_value(), exec_eval_boolean(), exec_eval_cleanup(), exec_eval_expr(), exec_stmts(), PLpgSQL_case_when::expr, PLpgSQL_function::fn_input_collation, PLpgSQL_execstate::func, PLpgSQL_stmt_case::have_else, lfirst, plpgsql_build_datatype(), PLpgSQL_case_when::stmts, PLpgSQL_stmt_case::t_expr, PLpgSQL_stmt_case::t_varno, PLpgSQL_type::typoid, and value.

Referenced by exec_stmts().

2535 {
2536  PLpgSQL_var *t_var = NULL;
2537  bool isnull;
2538  ListCell *l;
2539 
2540  if (stmt->t_expr != NULL)
2541  {
2542  /* simple case */
2543  Datum t_val;
2544  Oid t_typoid;
2545  int32 t_typmod;
2546 
2547  t_val = exec_eval_expr(estate, stmt->t_expr,
2548  &isnull, &t_typoid, &t_typmod);
2549 
2550  t_var = (PLpgSQL_var *) estate->datums[stmt->t_varno];
2551 
2552  /*
2553  * When expected datatype is different from real, change it. Note that
2554  * what we're modifying here is an execution copy of the datum, so
2555  * this doesn't affect the originally stored function parse tree. (In
2556  * theory, if the expression datatype keeps changing during execution,
2557  * this could cause a function-lifespan memory leak. Doesn't seem
2558  * worth worrying about though.)
2559  */
2560  if (t_var->datatype->typoid != t_typoid ||
2561  t_var->datatype->atttypmod != t_typmod)
2562  t_var->datatype = plpgsql_build_datatype(t_typoid,
2563  t_typmod,
2564  estate->func->fn_input_collation,
2565  NULL);
2566 
2567  /* now we can assign to the variable */
2568  exec_assign_value(estate,
2569  (PLpgSQL_datum *) t_var,
2570  t_val,
2571  isnull,
2572  t_typoid,
2573  t_typmod);
2574 
2575  exec_eval_cleanup(estate);
2576  }
2577 
2578  /* Now search for a successful WHEN clause */
2579  foreach(l, stmt->case_when_list)
2580  {
2582  bool value;
2583 
2584  value = exec_eval_boolean(estate, cwt->expr, &isnull);
2585  exec_eval_cleanup(estate);
2586  if (!isnull && value)
2587  {
2588  /* Found it */
2589 
2590  /* We can now discard any value we had for the temp variable */
2591  if (t_var != NULL)
2592  assign_simple_var(estate, t_var, (Datum) 0, true, false);
2593 
2594  /* Evaluate the statement(s), and we're done */
2595  return exec_stmts(estate, cwt->stmts);
2596  }
2597  }
2598 
2599  /* We can now discard any value we had for the temp variable */
2600  if (t_var != NULL)
2601  assign_simple_var(estate, t_var, (Datum) 0, true, false);
2602 
2603