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/pquery.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 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 135 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:698
#define ERROR
Definition: elog.h:46
const char * name
Definition: encode.c:515
int errmsg(const char *fmt,...)
Definition: elog.c:909
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1286

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

8463 {
8464  Assert(rec->dtype == PLPGSQL_DTYPE_REC);
8465 
8466  /* Transfer new record object into datum_context */
8467  TransferExpandedRecord(erh, estate->datum_context);
8468 
8469  /* Free the old value ... */
8470  if (rec->erh)
8472 
8473  /* ... and install the new */
8474  rec->erh = erh;
8475 }
PLpgSQL_datum_type dtype
Definition: plpgsql.h:390
ExpandedRecordHeader * erh
Definition: plpgsql.h:413
void DeleteExpandedObject(Datum d)
#define Assert(condition)
Definition: c.h:804
#define TransferExpandedRecord(erh, cxt)
MemoryContext datum_context
Definition: plpgsql.h:1059
#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 8385 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().

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

◆ assign_text_var()

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

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

8453 {
8454  assign_simple_var(estate, var, CStringGetTextDatum(str), false, true);
8455 }
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8385
#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 795 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().

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

References i, TupleDescData::natts, and TupleDescAttr.

Referenced by exec_for_query(), and exec_move_row().

7209 {
7210  int i;
7211 
7212  /* Possibly we could allow src_tupdesc to have extra columns? */
7213  if (dst_tupdesc->natts != src_tupdesc->natts)
7214  return false;
7215 
7216  for (i = 0; i < dst_tupdesc->natts; i++)
7217  {
7218  Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
7219  Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
7220 
7221  if (dattr->attisdropped != sattr->attisdropped)
7222  return false;
7223  if (!dattr->attisdropped)
7224  {
7225  /* Normal columns must match by type and typmod */
7226  if (dattr->atttypid != sattr->atttypid ||
7227  (dattr->atttypmod >= 0 &&
7228  dattr->atttypmod != sattr->atttypmod))
7229  return false;
7230  }
7231  else
7232  {
7233  /* Dropped columns are OK as long as length/alignment match */
7234  if (dattr->attlen != sattr->attlen ||
7235  dattr->attalign != sattr->attalign)
7236  return false;
7237  }
7238  }
7239  return true;
7240 }
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
int i

◆ convert_value_to_string()

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

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

7607 {
7608  char *result;
7609  MemoryContext oldcontext;
7610  Oid typoutput;
7611  bool typIsVarlena;
7612 
7613  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7614  getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
7615  result = OidOutputFunctionCall(typoutput, value);
7616  MemoryContextSwitchTo(oldcontext);
7617 
7618  return result;
7619 }
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
#define get_eval_mcontext(estate)
Definition: pl_exec.c:131
static struct @143 value
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1653

◆ copy_plpgsql_datums()

static void copy_plpgsql_datums ( PLpgSQL_execstate estate,
PLpgSQL_function func 
)
static

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

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

◆ deconstruct_composite_datum()

static TupleDesc deconstruct_composite_datum ( Datum  value,
HeapTupleData tmptup 
)
static

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

7308 {
7309  HeapTupleHeader td;
7310  Oid tupType;
7311  int32 tupTypmod;
7312 
7313  /* Get tuple body (note this could involve detoasting) */
7315 
7316  /* Build a temporary HeapTuple control structure */
7317  tmptup->t_len = HeapTupleHeaderGetDatumLength(td);
7318  ItemPointerSetInvalid(&(tmptup->t_self));
7319  tmptup->t_tableOid = InvalidOid;
7320  tmptup->t_data = td;
7321 
7322  /* Extract rowtype info and find a tupdesc */
7323  tupType = HeapTupleHeaderGetTypeId(td);
7324  tupTypmod = HeapTupleHeaderGetTypMod(td);
7325  return lookup_rowtype_tupdesc(tupType, tupTypmod);
7326 }
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1824
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
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:467
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:457
#define InvalidOid
Definition: postgres_ext.h:36
static struct @143 value
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:451

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

7663 {
7664  plpgsql_CastHashEntry *cast_entry;
7665 
7666  cast_entry = get_cast_hashentry(estate,
7667  valtype, valtypmod,
7668  reqtype, reqtypmod);
7669  if (cast_entry)
7670  {
7671  ExprContext *econtext = estate->eval_econtext;
7672  MemoryContext oldcontext;
7673 
7674  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7675 
7676  econtext->caseValue_datum = value;
7677  econtext->caseValue_isNull = *isnull;
7678 
7679  cast_entry->cast_in_use = true;
7680 
7681  value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
7682  isnull);
7683 
7684  cast_entry->cast_in_use = false;
7685 
7686  MemoryContextSwitchTo(oldcontext);
7687  }
7688 
7689  return value;
7690 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static plpgsql_CastHashEntry * get_cast_hashentry(PLpgSQL_execstate *estate, Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod)
Definition: pl_exec.c:7703
Datum caseValue_datum
Definition: execnodes.h:251
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:316
#define get_eval_mcontext(estate)
Definition: pl_exec.c:131
static struct @143 value
ExprContext * eval_econtext
Definition: plpgsql.h:1087
bool caseValue_isNull
Definition: execnodes.h:253
ExprState * cast_exprstate
Definition: pl_exec.c:167

◆ exception_matches_conditions()

static bool exception_matches_conditions ( ErrorData edata,
PLpgSQL_condition cond 
)
static

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

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

◆ exec_assign_c_string()

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

Definition at line 4984 of file pl_exec.c.

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

Referenced by exec_stmt_getdiag().

4986 {
4987  text *value;
4988  MemoryContext oldcontext;
4989 
4990  /* Use eval_mcontext for short-lived text value */
4991  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
4992  if (str != NULL)
4993  value = cstring_to_text(str);
4994  else
4995  value = cstring_to_text("");
4996  MemoryContextSwitchTo(oldcontext);
4997 
4998  exec_assign_value(estate, target, PointerGetDatum(value), false,
4999  TEXTOID, -1);
5000 }
#define PointerGetDatum(X)
Definition: postgres.h:600
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define get_eval_mcontext(estate)
Definition: pl_exec.c:131
static struct @143 value
text * cstring_to_text(const char *s)
Definition: varlena.c:190
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:5012

◆ exec_assign_expr()

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

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

4942 {
4943  Datum value;
4944  bool isnull;
4945  Oid valtype;
4946  int32 valtypmod;
4947 
4948  /*
4949  * If first time through, create a plan for this expression.
4950  */
4951  if (expr->plan == NULL)
4952  {
4953  /*
4954  * Mark the expression as being an assignment source, if target is a
4955  * simple variable. (This is a bit messy, but it seems cleaner than
4956  * modifying the API of exec_prepare_plan for the purpose. We need to
4957  * stash the target dno into the expr anyway, so that it will be
4958  * available if we have to replan.)
4959  */
4960  if (target->dtype == PLPGSQL_DTYPE_VAR)
4961  expr->target_param = target->dno;
4962  else
4963  expr->target_param = -1; /* should be that already */
4964 
4965  exec_prepare_plan(estate, expr, 0);
4966  }
4967 
4968  value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod);
4969  exec_assign_value(estate, target, value, isnull, valtype, valtypmod);
4970  exec_eval_cleanup(estate);
4971 }
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4076
unsigned int Oid
Definition: postgres_ext.h:31
PLpgSQL_datum_type dtype
Definition: plpgsql.h:276
SPIPlanPtr plan
Definition: plpgsql.h:221
signed int int32
Definition: c.h:429
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5616
int target_param
Definition: plpgsql.h:244
uintptr_t Datum
Definition: postgres.h:411
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions)
Definition: pl_exec.c:4113
static struct @143 value
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:5012

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

5016 {
5017  switch (target->dtype)
5018  {
5019  case PLPGSQL_DTYPE_VAR:
5020  case PLPGSQL_DTYPE_PROMISE:
5021  {
5022  /*
5023  * Target is a variable
5024  */
5025  PLpgSQL_var *var = (PLpgSQL_var *) target;
5026  Datum newvalue;
5027 
5028  newvalue = exec_cast_value(estate,
5029  value,
5030  &isNull,
5031  valtype,
5032  valtypmod,
5033  var->datatype->typoid,
5034  var->datatype->atttypmod);
5035 
5036  if (isNull && var->notnull)
5037  ereport(ERROR,
5038  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5039  errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
5040  var->refname)));
5041 
5042  /*
5043  * If type is by-reference, copy the new value (which is
5044  * probably in the eval_mcontext) into the procedure's main
5045  * memory context. But if it's a read/write reference to an
5046  * expanded object, no physical copy needs to happen; at most
5047  * we need to reparent the object's memory context.
5048  *
5049  * If it's an array, we force the value to be stored in R/W
5050  * expanded form. This wins if the function later does, say,
5051  * a lot of array subscripting operations on the variable, and
5052  * otherwise might lose. We might need to use a different
5053  * heuristic, but it's too soon to tell. Also, are there
5054  * cases where it'd be useful to force non-array values into
5055  * expanded form?
5056  */
5057  if (!var->datatype->typbyval && !isNull)
5058  {
5059  if (var->datatype->typisarray &&
5061  {
5062  /* array and not already R/W, so apply expand_array */
5063  newvalue = expand_array(newvalue,
5064  estate->datum_context,
5065  NULL);
5066  }
5067  else
5068  {
5069  /* else transfer value if R/W, else just datumCopy */
5070  newvalue = datumTransfer(newvalue,
5071  false,
5072  var->datatype->typlen);
5073  }
5074  }
5075 
5076  /*
5077  * Now free the old value, if any, and assign the new one. But
5078  * skip the assignment if old and new values are the same.
5079  * Note that for expanded objects, this test is necessary and
5080  * cannot reliably be made any earlier; we have to be looking
5081  * at the object's standard R/W pointer to be sure pointer
5082  * equality is meaningful.
5083  *
5084  * Also, if it's a promise variable, we should disarm the
5085  * promise in any case --- otherwise, assigning null to an
5086  * armed promise variable would fail to disarm the promise.
5087  */
5088  if (var->value != newvalue || var->isnull || isNull)
5089  assign_simple_var(estate, var, newvalue, isNull,
5090  (!var->datatype->typbyval && !isNull));
5091  else
5093  break;
5094  }
5095 
5096  case PLPGSQL_DTYPE_ROW:
5097  {
5098  /*
5099  * Target is a row variable
5100  */
5101  PLpgSQL_row *row = (PLpgSQL_row *) target;
5102 
5103  if (isNull)
5104  {
5105  /* If source is null, just assign nulls to the row */
5106  exec_move_row(estate, (PLpgSQL_variable *) row,
5107  NULL, NULL);
5108  }
5109  else
5110  {
5111  /* Source must be of RECORD or composite type */
5112  if (!type_is_rowtype(valtype))
5113  ereport(ERROR,
5114  (errcode(ERRCODE_DATATYPE_MISMATCH),
5115  errmsg("cannot assign non-composite value to a row variable")));
5117  value);
5118  }
5119  break;
5120  }
5121 
5122  case PLPGSQL_DTYPE_REC:
5123  {
5124  /*
5125  * Target is a record variable
5126  */
5127  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
5128 
5129  if (isNull)
5130  {
5131  if (rec->notnull)
5132  ereport(ERROR,
5133  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5134  errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
5135  rec->refname)));
5136 
5137  /* Set variable to a simple NULL */
5138  exec_move_row(estate, (PLpgSQL_variable *) rec,
5139  NULL, NULL);
5140  }
5141  else
5142  {
5143  /* Source must be of RECORD or composite type */
5144  if (!type_is_rowtype(valtype))
5145  ereport(ERROR,
5146  (errcode(ERRCODE_DATATYPE_MISMATCH),
5147  errmsg("cannot assign non-composite value to a record variable")));
5149  value);
5150  }
5151  break;
5152  }
5153 
5155  {
5156  /*
5157  * Target is a field of a record
5158  */
5159  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) target;
5160  PLpgSQL_rec *rec;
5161  ExpandedRecordHeader *erh;
5162 
5163  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5164  erh = rec->erh;
5165 
5166  /*
5167  * If record variable is NULL, instantiate it if it has a
5168  * named composite type, else complain. (This won't change
5169  * the logical state of the record, but if we successfully
5170  * assign below, the unassigned fields will all become NULLs.)
5171  */
5172  if (erh == NULL)
5173  {
5174  instantiate_empty_record_variable(estate, rec);
5175  erh = rec->erh;
5176  }
5177 
5178  /*
5179  * Look up the field's properties if we have not already, or
5180  * if the tuple descriptor ID changed since last time.
5181  */
5182  if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
5183  {
5185  recfield->fieldname,
5186  &recfield->finfo))
5187  ereport(ERROR,
5188  (errcode(ERRCODE_UNDEFINED_COLUMN),
5189  errmsg("record \"%s\" has no field \"%s\"",
5190  rec->refname, recfield->fieldname)));
5191  recfield->rectupledescid = erh->er_tupdesc_id;
5192  }
5193 
5194  /* We don't support assignments to system columns. */
5195  if (recfield->finfo.fnumber <= 0)
5196  ereport(ERROR,
5197  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5198  errmsg("cannot assign to system column \"%s\"",
5199  recfield->fieldname)));
5200 
5201  /* Cast the new value to the right type, if needed. */
5202  value = exec_cast_value(estate,
5203  value,
5204  &isNull,
5205  valtype,
5206  valtypmod,
5207  recfield->finfo.ftypeid,
5208  recfield->finfo.ftypmod);
5209 
5210  /* And assign it. */
5211  expanded_record_set_field(erh, recfield->finfo.fnumber,
5212  value, isNull, !estate->atomic);
5213  break;
5214  }
5215 
5216  default:
5217  elog(ERROR, "unrecognized dtype: %d", target->dtype);
5218  }
5219 }
PLpgSQL_promise_type promise
Definition: plpgsql.h:341
#define expanded_record_set_field(erh, fnumber, newValue, isnull, expand_external)
char * refname
Definition: plpgsql.h:312
bool expanded_record_lookup_field(ExpandedRecordHeader *erh, const char *fieldname, ExpandedRecordFieldInfo *finfo)
PLpgSQL_type * datatype
Definition: plpgsql.h:319
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:7571
ExpandedRecordHeader * erh
Definition: plpgsql.h:413
int errcode(int sqlerrcode)
Definition: elog.c:698
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8385
static void exec_move_row_from_datum(PLpgSQL_execstate *estate, PLpgSQL_variable *target, Datum value)
Definition: pl_exec.c:7338
PLpgSQL_datum_type dtype
Definition: plpgsql.h:276
char * refname
Definition: plpgsql.h:392
PLpgSQL_datum ** datums
Definition: plpgsql.h:1057
bool notnull
Definition: plpgsql.h:315
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7635
#define ERROR
Definition: elog.h:46
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2602
uint64 rectupledescid
Definition: plpgsql.h:428
bool typbyval
Definition: plpgsql.h:203
bool typisarray
Definition: plpgsql.h:206
uintptr_t Datum
Definition: postgres.h:411
ExpandedRecordFieldInfo finfo
Definition: plpgsql.h:429
Datum value
Definition: plpgsql.h:332
static struct @143 value
#define ereport(elevel,...)
Definition: elog.h:157
Datum datumTransfer(Datum value, bool typByVal, int typLen)
Definition: datum.c:193
#define DatumGetPointer(X)
Definition: postgres.h:593
MemoryContext datum_context
Definition: plpgsql.h:1059
int errmsg(const char *fmt,...)
Definition: elog.c:909
int32 atttypmod
Definition: plpgsql.h:207
static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
Definition: pl_exec.c:6664
#define elog(elevel,...)
Definition: elog.h:232
#define VARATT_IS_EXTERNAL_EXPANDED_RW(PTR)
Definition: postgres.h:333
#define unlikely(x)
Definition: c.h:273
int16 typlen
Definition: plpgsql.h:202
bool notnull
Definition: plpgsql.h:395
char * fieldname
Definition: plpgsql.h:425
bool isnull
Definition: plpgsql.h:333
Oid typoid
Definition: plpgsql.h:200

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

7639 {
7640  /*
7641  * If the type of the given value isn't what's requested, convert it.
7642  */
7643  if (valtype != reqtype ||
7644  (valtypmod != reqtypmod && reqtypmod != -1))
7645  {
7646  /* We keep the slow path out-of-line. */
7647  value = do_cast_value(estate, value, isnull, valtype, valtypmod,
7648  reqtype, reqtypmod);
7649  }
7650 
7651  return value;
7652 }
static Datum do_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7659
static struct @143 value

◆ exec_check_rw_parameter()

static void exec_check_rw_parameter ( PLpgSQL_expr expr)
static

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

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

8571 {
8572  Portal portal;
8573  Datum query;
8574  bool isnull;
8575  Oid restype;
8576  int32 restypmod;
8577  char *querystr;
8579  MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
8580 
8581  /*
8582  * Evaluate the string expression after the EXECUTE keyword. Its result is
8583  * the querystring we have to execute.
8584  */
8585  query = exec_eval_expr(estate, dynquery, &isnull, &restype, &restypmod);
8586  if (isnull)
8587  ereport(ERROR,
8588  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
8589  errmsg("query string argument of EXECUTE is null")));
8590 
8591  /* Get the C-String representation */
8592  querystr = convert_value_to_string(estate, query, restype);
8593 
8594  /* copy it into the stmt_mcontext before we clean up */
8595  querystr = MemoryContextStrdup(stmt_mcontext, querystr);
8596 
8597  exec_eval_cleanup(estate);
8598 
8599  /*
8600  * Open an implicit cursor for the query. We use SPI_cursor_parse_open
8601  * even when there are no params, because this avoids making and freeing
8602  * one copy of the plan.
8603  */
8604  memset(&options, 0, sizeof(options));
8605  options.params = exec_eval_using_params(estate, params);
8606  options.cursorOptions = cursorOptions;
8607  options.read_only = estate->readonly_func;
8608 
8609  portal = SPI_cursor_parse_open(portalname, querystr, &options);
8610 
8611  if (portal == NULL)
8612  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
8613  querystr, SPI_result_code_string(SPI_result));
8614 
8615  /* Release transient data */
8616  MemoryContextReset(stmt_mcontext);
8617 
8618  return portal;
8619 }
Portal SPI_cursor_parse_open(const char *name, const char *src, const SPIParseOpenOptions *options)
Definition: spi.c:1428
ParamListInfo params
Definition: spi.h:59
int errcode(int sqlerrcode)
Definition: elog.c:698
static ParamListInfo exec_eval_using_params(PLpgSQL_execstate *estate, List *params)
Definition: pl_exec.c:8484
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:143
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4076
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:46
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5616
const char * SPI_result_code_string(int code)
Definition: spi.c:1861
int cursorOptions
Definition: spi.h:60
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1506
static char ** options
uintptr_t Datum
Definition: postgres.h:411
#define ereport(elevel,...)
Definition: elog.h:157
int errmsg(const char *fmt,...)
Definition: elog.c:909
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1286
#define elog(elevel,...)
Definition: elog.h:232
static char * convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
Definition: pl_exec.c:7606

◆ exec_eval_boolean()

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

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

5596 {
5597  Datum exprdatum;
5598  Oid exprtypeid;
5599  int32 exprtypmod;
5600 
5601  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5602  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5603  exprtypeid, exprtypmod,
5604  BOOLOID, -1);
5605  return DatumGetBool(exprdatum);
5606 }
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:7635
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5616
#define DatumGetBool(X)
Definition: postgres.h:437
uintptr_t Datum
Definition: postgres.h:411

◆ exec_eval_cleanup()

static void exec_eval_cleanup ( PLpgSQL_execstate estate)
static

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

4077 {
4078  /* Clear result of a full SPI_execute */
4079  if (estate->eval_tuptable != NULL)
4081  estate->eval_tuptable = NULL;
4082 
4083  /*
4084  * Clear result of exec_eval_simple_expr (but keep the econtext). This
4085  * also clears any short-lived allocations done via get_eval_mcontext.
4086  */
4087  if (estate->eval_econtext != NULL)
4089 }
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1085
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1281
ExprContext * eval_econtext
Definition: plpgsql.h:1087
#define ResetExprContext(econtext)
Definition: executor.h:527

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

5245 {
5246  MemoryContext oldcontext;
5247 
5248  switch (datum->dtype)
5249  {
5250  case PLPGSQL_DTYPE_PROMISE:
5251  /* fulfill promise if needed, then handle like regular var */
5252  plpgsql_fulfill_promise(estate, (PLpgSQL_var *) datum);
5253 
5254  /* FALL THRU */
5255 
5256  case PLPGSQL_DTYPE_VAR:
5257  {
5258  PLpgSQL_var *var = (PLpgSQL_var *) datum;
5259 
5260  *typeid = var->datatype->typoid;
5261  *typetypmod = var->datatype->atttypmod;
5262  *value = var->value;
5263  *isnull = var->isnull;
5264  break;
5265  }
5266 
5267  case PLPGSQL_DTYPE_ROW:
5268  {
5269  PLpgSQL_row *row = (PLpgSQL_row *) datum;
5270  HeapTuple tup;
5271 
5272  /* We get here if there are multiple OUT parameters */
5273  if (!row->rowtupdesc) /* should not happen */
5274  elog(ERROR, "row variable has no tupdesc");
5275  /* Make sure we have a valid type/typmod setting */
5276  BlessTupleDesc(row->rowtupdesc);
5277  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5278  tup = make_tuple_from_row(estate, row, row->rowtupdesc);
5279  if (tup == NULL) /* should not happen */
5280  elog(ERROR, "row not compatible with its own tupdesc");
5281  *typeid = row->rowtupdesc->tdtypeid;
5282  *typetypmod = row->rowtupdesc->tdtypmod;
5283  *value = HeapTupleGetDatum(tup);
5284  *isnull = false;
5285  MemoryContextSwitchTo(oldcontext);
5286  break;
5287  }
5288 
5289  case PLPGSQL_DTYPE_REC:
5290  {
5291  PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
5292 
5293  if (rec->erh == NULL)
5294  {
5295  /* Treat uninstantiated record as a simple NULL */
5296  *value = (Datum) 0;
5297  *isnull = true;
5298  /* Report variable's declared type */
5299  *typeid = rec->rectypeid;
5300  *typetypmod = -1;
5301  }
5302  else
5303  {
5304  if (ExpandedRecordIsEmpty(rec->erh))
5305  {
5306  /* Empty record is also a NULL */
5307  *value = (Datum) 0;
5308  *isnull = true;
5309  }
5310  else
5311  {
5312  *value = ExpandedRecordGetDatum(rec->erh);
5313  *isnull = false;
5314  }
5315  if (rec->rectypeid != RECORDOID)
5316  {
5317  /* Report variable's declared type, if not RECORD */
5318  *typeid = rec->rectypeid;
5319  *typetypmod = -1;
5320  }
5321  else
5322  {
5323  /* Report record's actual type if declared RECORD */
5324  *typeid = rec->erh->er_typeid;
5325  *typetypmod = rec->erh->er_typmod;
5326  }
5327  }
5328  break;
5329  }
5330 
5332  {
5333  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
5334  PLpgSQL_rec *rec;
5335  ExpandedRecordHeader *erh;
5336 
5337  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5338  erh = rec->erh;
5339 
5340  /*
5341  * If record variable is NULL, instantiate it if it has a
5342  * named composite type, else complain. (This won't change
5343  * the logical state of the record: it's still NULL.)
5344  */
5345  if (erh == NULL)
5346  {
5347  instantiate_empty_record_variable(estate, rec);
5348  erh = rec->erh;
5349  }
5350 
5351  /*
5352  * Look up the field's properties if we have not already, or
5353  * if the tuple descriptor ID changed since last time.
5354  */
5355  if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
5356  {
5358  recfield->fieldname,
5359  &recfield->finfo))
5360  ereport(ERROR,
5361  (errcode(ERRCODE_UNDEFINED_COLUMN),
5362  errmsg("record \"%s\" has no field \"%s\"",
5363  rec->refname, recfield->fieldname)));
5364  recfield->rectupledescid = erh->er_tupdesc_id;
5365  }
5366 
5367  /* Report type data. */
5368  *typeid = recfield->finfo.ftypeid;
5369  *typetypmod = recfield->finfo.ftypmod;
5370 
5371  /* And fetch the field value. */
5373  recfield->finfo.fnumber,
5374  isnull);
5375  break;
5376  }
5377 
5378  default:
5379  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
5380  }
5381 }
static HeapTuple make_tuple_from_row(PLpgSQL_execstate *estate, PLpgSQL_row *row, TupleDesc tupdesc)
Definition: pl_exec.c:7252
#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:319
static void plpgsql_fulfill_promise(PLpgSQL_execstate *estate, PLpgSQL_var *var)
Definition: pl_exec.c:1346
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:7571
ExpandedRecordHeader * erh
Definition: plpgsql.h:413
int errcode(int sqlerrcode)
Definition: elog.c:698
PLpgSQL_datum_type dtype
Definition: plpgsql.h:276
char * refname
Definition: plpgsql.h:392
PLpgSQL_datum ** datums
Definition: plpgsql.h:1057
#define ERROR
Definition: elog.h:46
int32 tdtypmod
Definition: tupdesc.h:83
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2082
uint64 rectupledescid
Definition: plpgsql.h:428
#define get_eval_mcontext(estate)
Definition: pl_exec.c:131
uintptr_t Datum
Definition: postgres.h:411
ExpandedRecordFieldInfo finfo
Definition: plpgsql.h:429
Datum value
Definition: plpgsql.h:332
static struct @143 value
#define ereport(elevel,...)
Definition: elog.h:157
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:220
Oid tdtypeid
Definition: tupdesc.h:82
int errmsg(const char *fmt,...)
Definition: elog.c:909
int32 atttypmod
Definition: plpgsql.h:207
#define elog(elevel,...)
Definition: elog.h:232
TupleDesc rowtupdesc
Definition: plpgsql.h:378
#define unlikely(x)
Definition: c.h:273
Oid rectypeid
Definition: plpgsql.h:406
#define ExpandedRecordGetDatum(erh)
char * fieldname
Definition: plpgsql.h:425
bool isnull
Definition: plpgsql.h:333
Oid typoid
Definition: plpgsql.h:200

◆ exec_eval_expr()

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

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

5621 {
5622  Datum result = 0;
5623  int rc;
5624  Form_pg_attribute attr;
5625 
5626  /*
5627  * If first time through, create a plan for this expression.
5628  */
5629  if (expr->plan == NULL)
5631 
5632  /*
5633  * If this is a simple expression, bypass SPI and use the executor
5634  * directly
5635  */
5636  if (exec_eval_simple_expr(estate, expr,
5637  &result, isNull, rettype, rettypmod))
5638  return result;
5639 
5640  /*
5641  * Else do it the hard way via exec_run_select
5642  */
5643  rc = exec_run_select(estate, expr, 2, NULL);
5644  if (rc != SPI_OK_SELECT)
5645  ereport(ERROR,
5646  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5647  errmsg("query \"%s\" did not return data", expr->query)));
5648 
5649  /*
5650  * Check that the expression returns exactly one column...
5651  */
5652  if (estate->eval_tuptable->tupdesc->natts != 1)
5653  ereport(ERROR,
5654  (errcode(ERRCODE_SYNTAX_ERROR),
5655  errmsg_plural("query \"%s\" returned %d column",
5656  "query \"%s\" returned %d columns",
5657  estate->eval_tuptable->tupdesc->natts,
5658  expr->query,
5659  estate->eval_tuptable->tupdesc->natts)));
5660 
5661  /*
5662  * ... and get the column's datatype.
5663  */
5664  attr = TupleDescAttr(estate->eval_tuptable->tupdesc, 0);
5665  *rettype = attr->atttypid;
5666  *rettypmod = attr->atttypmod;
5667 
5668  /*
5669  * If there are no rows selected, the result is a NULL of that type.
5670  */
5671  if (estate->eval_processed == 0)
5672  {
5673  *isNull = true;
5674  return (Datum) 0;
5675  }
5676 
5677  /*
5678  * Check that the expression returned no more than one row.
5679  */
5680  if (estate->eval_processed != 1)
5681  ereport(ERROR,
5682  (errcode(ERRCODE_CARDINALITY_VIOLATION),
5683  errmsg("query \"%s\" returned more than one row",
5684  expr->query)));
5685 
5686  /*
5687  * Return the single result Datum.
5688  */
5689  return SPI_getbinval(estate->eval_tuptable->vals[0],
5690  estate->eval_tuptable->tupdesc, 1, isNull);
5691 }
char * query
Definition: plpgsql.h:219
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1085
uint64 eval_processed
Definition: plpgsql.h:1086
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1019
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
int errcode(int sqlerrcode)
Definition: elog.c:698
HeapTuple * vals
Definition: spi.h:26
SPIPlanPtr plan
Definition: plpgsql.h:221
#define ERROR
Definition: elog.h:46
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition: spi.c:1147
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
uintptr_t Datum
Definition: postgres.h:411
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:4113
#define ereport(elevel,...)
Definition: elog.h:157
static int exec_run_select(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
Definition: pl_exec.c:5699
static bool exec_eval_simple_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, Datum *result, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5952
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2815
int errmsg(const char *fmt,...)
Definition: elog.c:909

◆ exec_eval_integer()

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

Definition at line 5570 of file pl_exec.c.

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

Referenced by exec_stmt_fetch().

5573 {
5574  Datum exprdatum;
5575  Oid exprtypeid;
5576  int32 exprtypmod;
5577 
5578  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5579  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5580  exprtypeid, exprtypmod,
5581  INT4OID, -1);
5582  return DatumGetInt32(exprdatum);
5583 }
#define DatumGetInt32(X)
Definition: postgres.h:516
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:7635
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5616
uintptr_t Datum
Definition: postgres.h:411

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

References Assert, CachedPlanAllowsSimpleValidityCheck(), CachedPlanIsSimplyValid(), CommandCounterIncrement(), CurrentResourceOwner, ExprContext::ecxt_param_list_info, EnsurePortalSnapshotExists(), 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().

5958 {
5959  ExprContext *econtext = estate->eval_econtext;
5960  LocalTransactionId curlxid = MyProc->lxid;
5961  ParamListInfo paramLI;
5962  void *save_setup_arg;
5963  bool need_snapshot;
5964  MemoryContext oldcontext;
5965 
5966  /*
5967  * Forget it if expression wasn't simple before.
5968  */
5969  if (expr->expr_simple_expr == NULL)
5970  return false;
5971 
5972  /*
5973  * If expression is in use in current xact, don't touch it.
5974  */
5975  if (unlikely(expr->expr_simple_in_use) &&
5976  expr->expr_simple_lxid == curlxid)
5977  return false;
5978 
5979  /*
5980  * Ensure that there's a portal-level snapshot, in case this simple
5981  * expression is the first thing evaluated after a COMMIT or ROLLBACK.
5982  * We'd have to do this anyway before executing the expression, so we
5983  * might as well do it now to ensure that any possible replanning doesn't
5984  * need to take a new snapshot.
5985  */
5987 
5988  /*
5989  * Check to see if the cached plan has been invalidated. If not, and this
5990  * is the first use in the current transaction, save a plan refcount in
5991  * the simple-expression resowner.
5992  */
5994  expr->expr_simple_plan,
5995  (expr->expr_simple_plan_lxid != curlxid ?
5996  estate->simple_eval_resowner : NULL))))
5997  {
5998  /*
5999  * It's still good, so just remember that we have a refcount on the
6000  * plan in the current transaction. (If we already had one, this
6001  * assignment is a no-op.)
6002  */
6003  expr->expr_simple_plan_lxid = curlxid;
6004  }
6005  else
6006  {
6007  /* Need to replan */
6008  CachedPlan *cplan;
6009 
6010  /*
6011  * If we have a valid refcount on some previous version of the plan,
6012  * release it, so we don't leak plans intra-transaction.
6013  */
6014  if (expr->expr_simple_plan_lxid == curlxid)
6015  {
6017  estate->simple_eval_resowner);
6018  expr->expr_simple_plan = NULL;
6020  }
6021 
6022  /* Do the replanning work in the eval_mcontext */
6023  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6024  cplan = SPI_plan_get_cached_plan(expr->plan);
6025  MemoryContextSwitchTo(oldcontext);
6026 
6027  /*
6028  * We can't get a failure here, because the number of
6029  * CachedPlanSources in the SPI plan can't change from what
6030  * exec_simple_check_plan saw; it's a property of the raw parsetree
6031  * generated from the query text.
6032  */
6033  Assert(cplan != NULL);
6034 
6035  /*
6036  * This test probably can't fail either, but if it does, cope by
6037  * declaring the plan to be non-simple. On success, we'll acquire a
6038  * refcount on the new plan, stored in simple_eval_resowner.
6039  */
6041  cplan,
6042  estate->simple_eval_resowner))
6043  {
6044  /* Remember that we have the refcount */
6045  expr->expr_simple_plan = cplan;
6046  expr->expr_simple_plan_lxid = curlxid;
6047  }
6048  else
6049  {
6050  /* Release SPI_plan_get_cached_plan's refcount */
6052  /* Mark expression as non-simple, and fail */
6053  expr->expr_simple_expr = NULL;
6054  expr->expr_rw_param = NULL;
6055  return false;
6056  }
6057 
6058  /*
6059  * SPI_plan_get_cached_plan acquired a plan refcount stored in the
6060  * active resowner. We don't need that anymore, so release it.
6061  */
6063 
6064  /* Extract desired scalar expression from cached plan */
6065  exec_save_simple_expr(expr, cplan);
6066  }
6067 
6068  /*
6069  * Pass back previously-determined result type.
6070  */
6071  *rettype = expr->expr_simple_type;
6072  *rettypmod = expr->expr_simple_typmod;
6073 
6074  /*
6075  * Set up ParamListInfo to pass to executor. For safety, save and restore
6076  * estate->paramLI->parserSetupArg around our use of the param list.
6077  */
6078  paramLI = estate->paramLI;
6079  save_setup_arg = paramLI->parserSetupArg;
6080 
6081  /*
6082  * We can skip using setup_param_list() in favor of just doing this
6083  * unconditionally, because there's no need for the optimization of
6084  * possibly setting ecxt_param_list_info to NULL; we've already forced use
6085  * of a generic plan.
6086  */
6087  paramLI->parserSetupArg = (void *) expr;
6088  econtext->ecxt_param_list_info = paramLI;
6089 
6090  /*
6091  * Prepare the expression for execution, if it's not been done already in
6092  * the current transaction. (This will be forced to happen if we called
6093  * exec_save_simple_expr above.)
6094  */
6095  if (unlikely(expr->expr_simple_lxid != curlxid))
6096  {
6097  oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
6098  expr->expr_simple_state =
6100  econtext->ecxt_param_list_info);
6101  expr->expr_simple_in_use = false;
6102  expr->expr_simple_lxid = curlxid;
6103  MemoryContextSwitchTo(oldcontext);
6104  }
6105 
6106  /*
6107  * We have to do some of the things SPI_execute_plan would do, in
6108  * particular push a new snapshot so that stable functions within the
6109  * expression can see updates made so far by our own function. However,
6110  * we can skip doing that (and just invoke the expression with the same
6111  * snapshot passed to our function) in some cases, which is useful because
6112  * it's quite expensive relative to the cost of a simple expression. We
6113  * can skip it if the expression contains no stable or volatile functions;
6114  * immutable functions shouldn't need to see our updates. Also, if this
6115  * is a read-only function, we haven't made any updates so again it's okay
6116  * to skip.
6117  */
6118  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6119  need_snapshot = (expr->expr_simple_mutable && !estate->readonly_func);
6120  if (need_snapshot)
6121  {
6124  }
6125 
6126  /*
6127  * Mark expression as busy for the duration of the ExecEvalExpr call.
6128  */
6129  expr->expr_simple_in_use = true;
6130 
6131  /*
6132  * Finally we can call the executor to evaluate the expression
6133  */
6134  *result = ExecEvalExpr(expr->expr_simple_state,
6135  econtext,
6136  isNull);
6137 
6138  /* Assorted cleanup */
6139  expr->expr_simple_in_use = false;
6140 
6141  econtext->ecxt_param_list_info = NULL;
6142 
6143  paramLI->parserSetupArg = save_setup_arg;
6144 
6145  if (need_snapshot)
6147 
6148  MemoryContextSwitchTo(oldcontext);
6149 
6150  /*
6151  * That's it.
6152  */
6153  return true;
6154 }
#define likely(x)
Definition: c.h:272
void * parserSetupArg
Definition: params.h:117
Param * expr_rw_param
Definition: plpgsql.h:245
ResourceOwner simple_eval_resowner
Definition: plpgsql.h:1071
PGPROC * MyProc
Definition: proc.c:68
void EnsurePortalSnapshotExists(void)
Definition: pquery.c:1747
ResourceOwner CurrentResourceOwner
Definition: resowner.c:146
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:7992
SPIPlanPtr plan
Definition: plpgsql.h:221
CachedPlan * SPI_plan_get_cached_plan(SPIPlanPtr plan)
Definition: spi.c:1957
MemoryContext es_query_cxt
Definition: execnodes.h:600
ParamListInfo paramLI
Definition: plpgsql.h:1067
CachedPlanSource * expr_simple_plansource
Definition: plpgsql.h:253
EState * simple_eval_estate
Definition: plpgsql.h:1070
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:680
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:316
ExprState * ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
Definition: execExpr.c:160
Expr * expr_simple_expr
Definition: plpgsql.h:231
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:131
ExprState * expr_simple_state
Definition: plpgsql.h:263
bool expr_simple_mutable
Definition: plpgsql.h:234
CachedPlan * expr_simple_plan
Definition: plpgsql.h:254
void CommandCounterIncrement(void)
Definition: xact.c:1021
LocalTransactionId expr_simple_lxid
Definition: plpgsql.h:265
#define Assert(condition)
Definition: c.h:804
ExprContext * eval_econtext
Definition: plpgsql.h:1087
int32 expr_simple_typmod
Definition: plpgsql.h:233
#define InvalidLocalTransactionId
Definition: lock.h:69
#define unlikely(x)
Definition: c.h:273
LocalTransactionId expr_simple_plan_lxid
Definition: plpgsql.h:255
bool expr_simple_in_use
Definition: plpgsql.h:264
ParamListInfo ecxt_param_list_info
Definition: execnodes.h:238
Oid expr_simple_type
Definition: plpgsql.h:232
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 8484 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().

8485 {
8486  ParamListInfo paramLI;
8487  int nargs;
8488  MemoryContext stmt_mcontext;
8489  MemoryContext oldcontext;
8490  int i;
8491  ListCell *lc;
8492 
8493  /* Fast path for no parameters: we can just return NULL */
8494  if (params == NIL)
8495  return NULL;
8496 
8497  nargs = list_length(params);
8498  stmt_mcontext = get_stmt_mcontext(estate);
8499  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8500  paramLI = makeParamList(nargs);
8501  MemoryContextSwitchTo(oldcontext);
8502 
8503  i = 0;
8504  foreach(lc, params)
8505  {
8506  PLpgSQL_expr *param = (PLpgSQL_expr *) lfirst(lc);
8507  ParamExternData *prm = &paramLI->params[i];
8508  int32 ppdtypmod;
8509 
8510  /*
8511  * Always mark params as const, since we only use the result with
8512  * one-shot plans.
8513  */
8514  prm->pflags = PARAM_FLAG_CONST;
8515 
8516  prm->value = exec_eval_expr(estate, param,
8517  &prm->isnull,
8518  &prm->ptype,
8519  &ppdtypmod);
8520 
8521  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8522 
8523  if (prm->ptype == UNKNOWNOID)
8524  {
8525  /*
8526  * Treat 'unknown' parameters as text, since that's what most
8527  * people would expect. The SPI functions can coerce unknown
8528  * constants in a more intelligent way, but not unknown Params.
8529  * This code also takes care of copying into the right context.
8530  * Note we assume 'unknown' has the representation of C-string.
8531  */
8532  prm->ptype = TEXTOID;
8533  if (!prm->isnull)
8535  }
8536  /* pass-by-ref non null values must be copied into stmt_mcontext */
8537  else if (!prm->isnull)
8538  {
8539  int16 typLen;
8540  bool typByVal;
8541 
8542  get_typlenbyval(prm->ptype, &typLen, &typByVal);
8543  if (!typByVal)
8544  prm->value = datumCopy(prm->value, typByVal, typLen);
8545  }
8546 
8547  MemoryContextSwitchTo(oldcontext);
8548 
8549  exec_eval_cleanup(estate);
8550 
8551  i++;
8552  }
8553 
8554  return paramLI;
8555 }
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:4076
ParamListInfo makeParamList(int numParams)
Definition: params.c:44
signed int int32
Definition: c.h:429
#define DatumGetCString(X)
Definition: postgres.h:610
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5616
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1506
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 5770 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().

5772 {
5773  PLpgSQL_variable *var;
5774  SPITupleTable *tuptab;
5775  bool found = false;
5776  int rc = PLPGSQL_RC_OK;
5777  uint64 previous_id = INVALID_TUPLEDESC_IDENTIFIER;
5778  bool tupdescs_match = true;
5779  uint64 n;
5780 
5781  /* Fetch loop variable's datum entry */
5782  var = (PLpgSQL_variable *) estate->datums[stmt->var->dno];
5783 
5784  /*
5785  * Make sure the portal doesn't get closed by the user statements we
5786  * execute.
5787  */
5788  PinPortal(portal);
5789 
5790  /*
5791  * In a non-atomic context, we dare not prefetch, even if it would
5792  * otherwise be safe. Aside from any semantic hazards that that might
5793  * create, if we prefetch toasted data and then the user commits the
5794  * transaction, the toast references could turn into dangling pointers.
5795  * (Rows we haven't yet fetched from the cursor are safe, because the
5796  * PersistHoldablePortal mechanism handles this scenario.)
5797  */
5798  if (!estate->atomic)
5799  prefetch_ok = false;
5800 
5801  /*
5802  * Fetch the initial tuple(s). If prefetching is allowed then we grab a
5803  * few more rows to avoid multiple trips through executor startup
5804  * overhead.
5805  */
5806  SPI_cursor_fetch(portal, true, prefetch_ok ? 10 : 1);
5807  tuptab = SPI_tuptable;
5808  n = SPI_processed;
5809 
5810  /*
5811  * If the query didn't return any rows, set the target to NULL and fall
5812  * through with found = false.
5813  */
5814  if (n == 0)
5815  {
5816  exec_move_row(estate, var, NULL, tuptab->tupdesc);
5817  exec_eval_cleanup(estate);
5818  }
5819  else
5820  found = true; /* processed at least one tuple */
5821 
5822  /*
5823  * Now do the loop
5824  */
5825  while (n > 0)
5826  {
5827  uint64 i;
5828 
5829  for (i = 0; i < n; i++)
5830  {
5831  /*
5832  * Assign the tuple to the target. Here, because we know that all
5833  * loop iterations should be assigning the same tupdesc, we can
5834  * optimize away repeated creations of expanded records with
5835  * identical tupdescs. Testing for changes of er_tupdesc_id is
5836  * reliable even if the loop body contains assignments that
5837  * replace the target's value entirely, because it's assigned from
5838  * a process-global counter. The case where the tupdescs don't
5839  * match could possibly be handled more efficiently than this
5840  * coding does, but it's not clear extra effort is worthwhile.
5841  */
5842  if (var->dtype == PLPGSQL_DTYPE_REC)
5843  {
5844  PLpgSQL_rec *rec = (PLpgSQL_rec *) var;
5845 
5846  if (rec->erh &&
5847  rec->erh->er_tupdesc_id == previous_id &&
5848  tupdescs_match)
5849  {
5850  /* Only need to assign a new tuple value */
5851  expanded_record_set_tuple(rec->erh, tuptab->vals[i],
5852  true, !estate->atomic);
5853  }
5854  else
5855  {
5856  /*
5857  * First time through, or var's tupdesc changed in loop,
5858  * or we have to do it the hard way because type coercion
5859  * is needed.
5860  */
5861  exec_move_row(estate, var,
5862  tuptab->vals[i], tuptab->tupdesc);
5863 
5864  /*
5865  * Check to see if physical assignment is OK next time.
5866  * Once the tupdesc comparison has failed once, we don't
5867  * bother rechecking in subsequent loop iterations.
5868  */
5869  if (tupdescs_match)
5870  {
5871  tupdescs_match =
5872  (rec->rectypeid == RECORDOID ||
5873  rec->rectypeid == tuptab->tupdesc->tdtypeid ||
5874  compatible_tupdescs(tuptab->tupdesc,
5876  }
5877  previous_id = rec->erh->er_tupdesc_id;
5878  }
5879  }
5880  else
5881  exec_move_row(estate, var, tuptab->vals[i], tuptab->tupdesc);
5882 
5883  exec_eval_cleanup(estate);
5884 
5885  /*
5886  * Execute the statements
5887  */
5888  rc = exec_stmts(estate, stmt->body);
5889 
5890  LOOP_RC_PROCESSING(stmt->label, goto loop_exit);
5891  }
5892 
5893  SPI_freetuptable(tuptab);
5894 
5895  /*
5896  * Fetch more tuples. If prefetching is allowed, grab 50 at a time.
5897  */
5898  SPI_cursor_fetch(portal, true, prefetch_ok ? 50 : 1);
5899  tuptab = SPI_tuptable;
5900  n = SPI_processed;
5901  }
5902 
5903 loop_exit:
5904 
5905  /*
5906  * Release last group of tuples (if any)
5907  */
5908  SPI_freetuptable(tuptab);
5909 
5910  UnpinPortal(portal);
5911 
5912  /*
5913  * Set the FOUND variable to indicate the result of executing the loop
5914  * (namely, whether we looped one or more times). This must be set last so
5915  * that it does not interfere with the value of the FOUND variable inside
5916  * the loop processing itself.
5917  */
5918  exec_set_found(estate, found);
5919 
5920  return rc;
5921 }
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:413
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4076
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:1057
void PinPortal(Portal portal)
Definition: portalmem.c:370
#define LOOP_RC_PROCESSING(looplabel, exit_action)
Definition: pl_exec.c:198
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1281
static bool compatible_tupdescs(TupleDesc src_tupdesc, TupleDesc dst_tupdesc)
Definition: pl_exec.c:7208
TupleDesc tupdesc
Definition: spi.h:25
PLpgSQL_datum_type dtype
Definition: plpgsql.h:288
PLpgSQL_variable * var
Definition: plpgsql.h:691
static void exec_set_found(PLpgSQL_execstate *estate, bool state)
Definition: pl_exec.c:8209
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:6664
int i
void SPI_cursor_fetch(Portal portal, bool forward, long count)
Definition: spi.c:1695
Oid rectypeid
Definition: plpgsql.h:406
static int exec_stmts(PLpgSQL_execstate *estate, List *stmts)
Definition: pl_exec.c:1951

◆ exec_init_tuple_store()

static void exec_init_tuple_store ( PLpgSQL_execstate estate)
static

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

3623 {
3624  ReturnSetInfo *rsi = estate->rsi;
3625  MemoryContext oldcxt;
3626  ResourceOwner oldowner;
3627 
3628  /*
3629  * Check caller can handle a set result in the way we want
3630  */
3631  if (!rsi || !IsA(rsi, ReturnSetInfo) ||
3632  (rsi->allowedModes & SFRM_Materialize) == 0 ||
3633  rsi->expectedDesc == NULL)
3634  ereport(ERROR,
3635  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3636  errmsg("set-valued function called in context that cannot accept a set")));
3637 
3638  /*
3639  * Switch to the right memory context and resource owner for storing the
3640  * tuplestore for return set. If we're within a subtransaction opened for
3641  * an exception-block, for example, we must still create the tuplestore in
3642  * the resource owner that was active when this function was entered, and
3643  * not in the subtransaction resource owner.
3644  */
3645  oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
3646  oldowner = CurrentResourceOwner;
3648 
3649  estate->tuple_store =
3651  false, work_mem);
3652 
3653  CurrentResourceOwner = oldowner;
3654  MemoryContextSwitchTo(oldcxt);
3655 
3656  estate->tuple_store_desc = rsi->expectedDesc;
3657 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
ResourceOwner tuple_store_owner
Definition: plpgsql.h:1045
ResourceOwner CurrentResourceOwner
Definition: resowner.c:146
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:698
TupleDesc expectedDesc
Definition: execnodes.h:304
TupleDesc tuple_store_desc
Definition: plpgsql.h:1043
#define ERROR
Definition: elog.h:46
MemoryContext tuple_store_cxt
Definition: plpgsql.h:1044
ReturnSetInfo * rsi
Definition: plpgsql.h:1046
Tuplestorestate * tuple_store
Definition: plpgsql.h:1042
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
int work_mem
Definition: globals.c:124
#define ereport(elevel,...)
Definition: elog.h:157
int allowedModes
Definition: execnodes.h:305
int errmsg(const char *fmt,...)
Definition: elog.c:909

◆ exec_move_row()

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

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

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

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

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

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

◆ exec_prepare_plan()

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

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

4115 {
4116  SPIPlanPtr plan;
4118 
4119  /*
4120  * The grammar can't conveniently set expr->func while building the parse
4121  * tree, so make sure it's set before parser hooks need it.
4122  */
4123  expr->func = estate->func;
4124 
4125  /*
4126  * Generate and save the plan
4127  */
4128  memset(&options, 0, sizeof(options));
4130  options.parserSetupArg = (void *) expr;
4131  options.parseMode = expr->parseMode;
4132  options.cursorOptions = cursorOptions;
4133  plan = SPI_prepare_extended(expr->query, &options);
4134  if (plan == NULL)
4135  elog(ERROR, "SPI_prepare_extended failed for \"%s\": %s",
4137 
4138  SPI_keepplan(plan);
4139  expr->plan = plan;
4140 
4141  /* Check to see if it's a simple expression */
4142  exec_simple_check_plan(estate, expr);
4143 }
char * query
Definition: plpgsql.h:219
SPIPlanPtr SPI_prepare_extended(const char *src, const SPIPrepareOptions *options)
Definition: spi.c:797
PLpgSQL_function * func
Definition: plpgsql.h:1022
static void exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:7873
SPIPlanPtr plan
Definition: plpgsql.h:221
int SPI_result
Definition: spi.c:47
#define ERROR
Definition: elog.h:46
const char * SPI_result_code_string(int code)
Definition: spi.c:1861
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:1079
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:871
ParserSetupHook parserSetup
Definition: spi.h:39
static char ** options
int cursorOptions
Definition: spi.h:42
struct PLpgSQL_function * func
Definition: plpgsql.h:225
RawParseMode parseMode
Definition: plpgsql.h:220
#define elog(elevel,...)
Definition: elog.h:232
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 5699 of file pl_exec.c.

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

5701 {
5702  ParamListInfo paramLI;
5703  int rc;
5704 
5705  /*
5706  * On the first call for this expression generate the plan.
5707  *
5708  * If we don't need to return a portal, then we're just going to execute
5709  * the query immediately, which means it's OK to use a parallel plan, even
5710  * if the number of rows being fetched is limited. If we do need to
5711  * return a portal (i.e., this is for a FOR loop), the user's code might
5712  * invoke additional operations inside the FOR loop, making parallel query
5713  * unsafe. In any case, we don't expect any cursor operations to be done,
5714  * so specify NO_SCROLL for efficiency and semantic safety.
5715  */
5716  if (expr->plan == NULL)
5717  {
5718  int cursorOptions = CURSOR_OPT_NO_SCROLL;
5719 
5720  if (portalP == NULL)
5721  cursorOptions |= CURSOR_OPT_PARALLEL_OK;
5722  exec_prepare_plan(estate, expr, cursorOptions);
5723  }
5724 
5725  /*
5726  * Set up ParamListInfo to pass to executor
5727  */
5728  paramLI = setup_param_list(estate, expr);
5729 
5730  /*
5731  * If a portal was requested, put the query and paramlist into the portal
5732  */
5733  if (portalP != NULL)
5734  {
5735  *portalP = SPI_cursor_open_with_paramlist(NULL, expr->plan,
5736  paramLI,
5737  estate->readonly_func);
5738  if (*portalP == NULL)
5739  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
5741  exec_eval_cleanup(estate);
5742  return SPI_OK_CURSOR;
5743  }
5744 
5745  /*
5746  * Execute the query
5747  */
5748  rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
5749  estate->readonly_func, maxtuples);
5750  if (rc != SPI_OK_SELECT)
5751  ereport(ERROR,
5752  (errcode(ERRCODE_SYNTAX_ERROR),
5753  errmsg("query \"%s\" is not a SELECT", expr->query)));
5754 
5755  /* Save query results for eventual cleanup */
5756  Assert(estate->eval_tuptable == NULL);
5757  estate->eval_tuptable = SPI_tuptable;
5758  estate->eval_processed = SPI_processed;
5759 
5760  return rc;
5761 }
char * query
Definition: plpgsql.h:219
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1085
uint64 eval_processed
Definition: plpgsql.h:1086
Portal SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan, ParamListInfo params, bool read_only)
Definition: spi.c:1420
SPITupleTable * SPI_tuptable
Definition: spi.c:46
int errcode(int sqlerrcode)
Definition: elog.c:698
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4076
#define SPI_OK_CURSOR
Definition: spi.h:90
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2807
uint64 SPI_processed
Definition: spi.c:45
SPIPlanPtr plan
Definition: plpgsql.h:221
int SPI_result
Definition: spi.c:47
#define ERROR
Definition: elog.h:46
int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params, bool read_only, long tcount)
Definition: spi.c:639
const char * SPI_result_code_string(int code)
Definition: spi.c:1861
static ParamListInfo setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:6173
#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:4113
#define ereport(elevel,...)
Definition: elog.h:157
#define Assert(condition)
Definition: c.h:804
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2815
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232

◆ exec_save_simple_expr()

static void exec_save_simple_expr ( PLpgSQL_expr expr,
CachedPlan cplan 
)
static

Definition at line 7992 of file pl_exec.c.

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

7993 {
7994  PlannedStmt *stmt;
7995  Plan *plan;
7996  Expr *tle_expr;
7997 
7998  /*
7999  * Given the checks that exec_simple_check_plan did, none of the Asserts
8000  * here should ever fail.
8001  */
8002 
8003  /* Extract the single PlannedStmt */
8004  Assert(list_length(cplan->stmt_list) == 1);
8005  stmt = linitial_node(PlannedStmt, cplan->stmt_list);
8006  Assert(stmt->commandType == CMD_SELECT);
8007 
8008  /*
8009  * Ordinarily, the plan node should be a simple Result. However, if
8010  * force_parallel_mode is on, the planner might've stuck a Gather node
8011  * atop that. The simplest way to deal with this is to look through the
8012  * Gather node. The Gather node's tlist would normally contain a Var
8013  * referencing the child node's output, but it could also be a Param, or
8014  * it could be a Const that setrefs.c copied as-is.
8015  */
8016  plan = stmt->planTree;
8017  for (;;)
8018  {
8019  /* Extract the single tlist expression */
8020  Assert(list_length(plan->targetlist) == 1);
8021  tle_expr = linitial_node(TargetEntry, plan->targetlist)->expr;
8022 
8023  if (IsA(plan, Result))
8024  {
8025  Assert(plan->lefttree == NULL &&
8026  plan->righttree == NULL &&
8027  plan->initPlan == NULL &&
8028  plan->qual == NULL &&
8029  ((Result *) plan)->resconstantqual == NULL);
8030  break;
8031  }
8032  else if (IsA(plan, Gather))
8033  {
8034  Assert(plan->lefttree != NULL &&
8035  plan->righttree == NULL &&
8036  plan->initPlan == NULL &&
8037  plan->qual == NULL);
8038  /* If setrefs.c copied up a Const, no need to look further */
8039  if (IsA(tle_expr, Const))
8040  break;
8041  /* Otherwise, it had better be a Param or an outer Var */
8042  Assert(IsA(tle_expr, Param) || (IsA(tle_expr, Var) &&
8043  ((Var *) tle_expr)->varno == OUTER_VAR));
8044  /* Descend to the child node */
8045  plan = plan->lefttree;
8046  }
8047  else
8048  elog(ERROR, "unexpected plan node type: %d",
8049  (int) nodeTag(plan));
8050  }
8051 
8052  /*
8053  * Save the simple expression, and initialize state to "not valid in
8054  * current transaction".
8055  */
8056  expr->expr_simple_expr = tle_expr;
8057  expr->expr_simple_state = NULL;
8058  expr->expr_simple_in_use = false;
8060  /* Also stash away the expression result type */
8061  expr->expr_simple_type = exprType((Node *) tle_expr);
8062  expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
8063  /* We also want to remember if it is immutable or not */
8064  expr->expr_simple_mutable = contain_mutable_functions((Node *) tle_expr);
8065 
8066  /*
8067  * Lastly, check to see if there's a possibility of optimizing a
8068  * read/write parameter.
8069  */
8071 }
List * qual
Definition: plannodes.h:142
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:267
Definition: nodes.h:539
Definition: primnodes.h:186
#define linitial_node(type, l)
Definition: pg_list.h:177
struct Plan * planTree
Definition: plannodes.h:64
struct Plan * righttree
Definition: plannodes.h:144
#define ERROR
Definition: elog.h:46
Expr * expr_simple_expr
Definition: plpgsql.h:231
ExprState * expr_simple_state
Definition: plpgsql.h:263
bool expr_simple_mutable
Definition: plpgsql.h:234
CmdType commandType
Definition: plannodes.h:46
LocalTransactionId expr_simple_lxid
Definition: plpgsql.h:265
static void exec_check_rw_parameter(PLpgSQL_expr *expr)
Definition: pl_exec.c:8099
#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:143
#define nodeTag(nodeptr)
Definition: nodes.h:544
List * targetlist
Definition: plannodes.h:141
int32 expr_simple_typmod
Definition: plpgsql.h:233
List * initPlan
Definition: plannodes.h:145
#define elog(elevel,...)
Definition: elog.h:232
#define InvalidLocalTransactionId
Definition: lock.h:69
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:362
List * stmt_list
Definition: plancache.h:150
bool expr_simple_in_use
Definition: plpgsql.h:264
#define OUTER_VAR
Definition: primnodes.h:176
Oid expr_simple_type
Definition: plpgsql.h:232

◆ exec_set_found()

static void exec_set_found ( PLpgSQL_execstate estate,
bool  state 
)
static

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

8210 {
8211  PLpgSQL_var *var;
8212 
8213  var = (PLpgSQL_var *) (estate->datums[estate->found_varno]);
8214  assign_simple_var(estate, var, BoolGetDatum(state), false, false);
8215 }
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8385
PLpgSQL_datum ** datums
Definition: plpgsql.h:1057
#define BoolGetDatum(X)
Definition: postgres.h:446
Definition: regguts.h:317

◆ exec_simple_check_plan()

static void exec_simple_check_plan ( PLpgSQL_execstate estate,
PLpgSQL_expr expr 
)
static

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

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

3886 {
3887  bool value;
3888  bool isnull;
3889 
3890  /* do nothing when asserts are not enabled */
3891  if (!plpgsql_check_asserts)
3892  return PLPGSQL_RC_OK;
3893 
3894  value = exec_eval_boolean(estate, stmt->cond, &isnull);
3895  exec_eval_cleanup(estate);
3896 
3897  if (isnull || !value)
3898  {
3899  char *message = NULL;
3900 
3901  if (stmt->message != NULL)
3902  {
3903  Datum val;
3904  Oid typeid;
3905  int32 typmod;
3906 
3907  val = exec_eval_expr(estate, stmt->message,
3908  &isnull, &typeid, &typmod);
3909  if (!isnull)
3910  message = convert_value_to_string(estate, val, typeid);
3911  /* we mustn't do exec_eval_cleanup here */
3912  }
3913 
3914  ereport(ERROR,
3915  (errcode(ERRCODE_ASSERT_FAILURE),
3916  message ? errmsg_internal("%s", message) :
3917  errmsg("assertion failed")));
3918  }
3919 
3920  return PLPGSQL_RC_OK;
3921 }
int errcode(int sqlerrcode)
Definition: elog.c:698
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4076
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:429
#define ERROR
Definition: elog.h:46
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5616
PLpgSQL_expr * message
Definition: plpgsql.h:884
static bool exec_eval_boolean(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
Definition: pl_exec.c:5593
uintptr_t Datum
Definition: postgres.h:411
static struct @143 value
#define ereport(elevel,...)
Definition: elog.h:157
int errmsg_internal(const char *fmt,...)
Definition: elog.c:996
int errmsg(const char *fmt,...)
Definition: elog.c:909
static char * convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
Definition: pl_exec.c:7606
PLpgSQL_expr * cond
Definition: plpgsql.h:883
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 2119 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().

2120 {
2121  Assert(stmt->varno >= 0);
2122 
2123  exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);
2124 
2125  return PLPGSQL_RC_OK;
2126 }
PLpgSQL_datum ** datums
Definition: plpgsql.h:1057
static void exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
Definition: pl_exec.c:4940
#define Assert(condition)
Definition: c.h:804
PLpgSQL_expr * expr
Definition: plpgsql.h:519

◆ exec_stmt_block()

static int exec_stmt_block ( PLpgSQL_execstate estate,
PLpgSQL_stmt_block block 
)
static

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

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

◆ exec_stmt_call()

static int exec_stmt_call ( PLpgSQL_execstate estate,
PLpgSQL_stmt_call stmt 
)
static

Definition at line 2152 of file pl_exec.c.

References SPIExecuteOptions::allow_nonatomic, Assert, elog, ERROR, exec_eval_cleanup(), exec_move_row(), exec_prepare_plan(), PLpgSQL_stmt_call::expr, PLpgSQL_expr::expr_simple_expr, PLpgSQL_stmt_call::is_call, PGPROC::lxid, make_callstmt_target(), MyProc, options, SPIExecuteOptions::owner, SPIExecuteOptions::params, PLpgSQL_expr::plan, plpgsql_create_econtext(), PLPGSQL_RC_OK, PLpgSQL_execstate::procedure_resowner, 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().

2153 {
2154  PLpgSQL_expr *expr = stmt->expr;
2155  LocalTransactionId before_lxid;
2156  LocalTransactionId after_lxid;
2157  ParamListInfo paramLI;
2159  int rc;
2160 
2161  /*
2162  * Make a plan if we don't have one already.
2163  */
2164  if (expr->plan == NULL)
2165  exec_prepare_plan(estate, expr, 0);
2166 
2167  /*
2168  * A CALL or DO can never be a simple expression.
2169  */
2170  Assert(!expr->expr_simple_expr);
2171 
2172  /*
2173  * Also construct a DTYPE_ROW datum representing the plpgsql variables
2174  * associated with the procedure's output arguments. Then we can use
2175  * exec_move_row() to do the assignments.
2176  */
2177  if (stmt->is_call && stmt->target == NULL)
2178  stmt->target = make_callstmt_target(estate, expr);
2179 
2180  paramLI = setup_param_list(estate, expr);
2181 
2182  before_lxid = MyProc->lxid;
2183 
2184  /*
2185  * If we have a procedure-lifespan resowner, use that to hold the refcount
2186  * for the plan. This avoids refcount leakage complaints if the called
2187  * procedure ends the current transaction.
2188  *
2189  * Also, tell SPI to allow non-atomic execution.
2190  */
2191  memset(&options, 0, sizeof(options));
2192  options.params = paramLI;
2193  options.read_only = estate->readonly_func;
2194  options.allow_nonatomic = true;
2195  options.owner = estate->procedure_resowner;
2196 
2197  rc = SPI_execute_plan_extended(expr->plan, &options);
2198 
2199  if (rc < 0)
2200  elog(ERROR, "SPI_execute_plan_extended failed executing query \"%s\": %s",
2201  expr->query, SPI_result_code_string(rc));
2202 
2203  after_lxid = MyProc->lxid;
2204 
2205  if (before_lxid != after_lxid)
2206  {
2207  /*
2208  * If we are in a new transaction after the call, we need to build new
2209  * simple-expression infrastructure.
2210  */
2211  estate->simple_eval_estate = NULL;
2212  estate->simple_eval_resowner = NULL;
2213  plpgsql_create_econtext(estate);
2214  }
2215 
2216  /*
2217  * Check result rowcount; if there's one row, assign procedure's output
2218  * values back to the appropriate variables.
2219  */
2220  if (SPI_processed == 1)
2221  {
2222  SPITupleTable *tuptab = SPI_tuptable;
2223 
2224  if (!stmt->is_call)
2225  elog(ERROR, "DO statement returned a row");
2226 
2227  exec_move_row(estate, stmt->target, tuptab->vals[0], tuptab->tupdesc);
2228  }
2229  else if (SPI_processed > 1)
2230  elog(ERROR, "procedure call returned more than one row");
2231 
2232  exec_eval_cleanup(estate);
2234 
2235  return PLPGSQL_RC_OK;
2236 }
char * query
Definition: plpgsql.h:219
ResourceOwner simple_eval_resowner
Definition: plpgsql.h:1071
PGPROC * MyProc
Definition: proc.c:68
SPITupleTable * SPI_tuptable
Definition: spi.c:46
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4076
int SPI_execute_plan_extended(SPIPlanPtr plan, const SPIExecuteOptions *options)
Definition: spi.c:615
HeapTuple * vals
Definition: spi.h:26
uint64 SPI_processed
Definition: spi.c:45
SPIPlanPtr plan
Definition: plpgsql.h:221
#define ERROR
Definition: elog.h:46
EState * simple_eval_estate
Definition: plpgsql.h:1070
const char * SPI_result_code_string(int code)
Definition: spi.c:1861
ResourceOwner owner
Definition: spi.h:53
ResourceOwner procedure_resowner
Definition: plpgsql.h:1074
Expr * expr_simple_expr
Definition: plpgsql.h:231
uint32 LocalTransactionId
Definition: c.h:589
static ParamListInfo setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:6173
ParamListInfo params
Definition: spi.h:48
bool read_only
Definition: spi.h:49
static char ** options
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1281
PLpgSQL_expr * expr
Definition: plpgsql.h:541
bool allow_nonatomic
Definition: spi.h:50
TupleDesc tupdesc
Definition: spi.h:25
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions)
Definition: pl_exec.c:4113
#define Assert(condition)
Definition: c.h:804
PLpgSQL_variable * target
Definition: plpgsql.h:543
static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
Definition: pl_exec.c:6664
#define elog(elevel,...)
Definition: elog.h:232
static void plpgsql_create_econtext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:8225
static PLpgSQL_variable * make_callstmt_target(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:2244
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 2500 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().

2501 {
2502  PLpgSQL_var *t_var = NULL;
2503  bool isnull;
2504  ListCell *l;
2505 
2506  if (stmt->t_expr != NULL)
2507  {
2508  /* simple case */
2509  Datum t_val;
2510  Oid t_typoid;
2511  int32 t_typmod;
2512 
2513  t_val = exec_eval_expr(estate, stmt->t_expr,
2514  &isnull, &t_typoid, &t_typmod);
2515 
2516  t_var = (PLpgSQL_var *) estate->datums[stmt->t_varno];
2517 
2518  /*
2519  * When expected datatype is different from real, change it. Note that
2520  * what we're modifying here is an execution copy of the datum, so
2521  * this doesn't affect the originally stored function parse tree. (In
2522  * theory, if the expression datatype keeps changing during execution,
2523  * this could cause a function-lifespan memory leak. Doesn't seem
2524  * worth worrying about though.)
2525  */
2526  if (t_var->datatype->typoid != t_typoid ||
2527  t_var->datatype->atttypmod != t_typmod)
2528  t_var->datatype = plpgsql_build_datatype(t_typoid,
2529  t_typmod,
2530  estate->func->fn_input_collation,
2531  NULL);
2532 
2533  /* now we can assign to the variable */
2534  exec_assign_value(estate,
2535  (PLpgSQL_datum *) t_var,
2536  t_val,
2537  isnull,
2538  t_typoid,
2539  t_typmod);
2540 
2541  exec_eval_cleanup(estate);
2542  }
2543 
2544  /* Now search for a successful WHEN clause */
2545  foreach(l, stmt->case_when_list)
2546  {
2548  bool value;
2549 
2550  value = exec_eval_boolean(estate, cwt->expr, &isnull);
2551  exec_eval_cleanup(estate);
2552  if (!isnull && value)
2553  {
2554  /* Found it */
2555 
2556  /* We can now discard any value we had for the temp variable */
2557  if (t_var != NULL)
2558  assign_simple_var(estate, t_var, (Datum) 0, true, false);
2559 
2560  /* Evaluate the statement(s), and we're done */
2561  return exec_stmts(estate, cwt->stmts);
2562  }
2563  }
2564 
2565  /* We can now discard any value we had for the temp variable */
2566  if (t_var != NULL)
2567  assign_simple_var(estate, t_var, (Datum) 0, true, false);
2568 
2569  /* SQL2003 mandates this error if there was no ELSE clause */
2570  if (!stmt->have_else)