PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
pl_exec.c File Reference
#include "postgres.h"
#include <ctype.h>
#include "access/detoast.h"
#include "access/htup_details.h"
#include "access/tupconvert.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.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 "plpgsql.h"
#include "storage/proc.h"
#include "tcop/cmdtag.h"
#include "tcop/pquery.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_CastExprHashEntry
 
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 bool exec_is_simple_query (PLpgSQL_expr *expr)
 
static void exec_save_simple_expr (PLpgSQL_expr *expr, CachedPlan *cplan)
 
static void exec_check_rw_parameter (PLpgSQL_expr *expr)
 
static void exec_check_assignable (PLpgSQL_execstate *estate, int dno)
 
static bool exec_eval_simple_expr (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, Datum *result, bool *isNull, Oid *rettype, int32 *rettypmod)
 
static void exec_assign_expr (PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
 
static void exec_assign_c_string (PLpgSQL_execstate *estate, PLpgSQL_datum *target, const char *str)
 
static void exec_assign_value (PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
 
static void exec_eval_datum (PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeid, int32 *typetypmod, Datum *value, bool *isnull)
 
static int exec_eval_integer (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
 
static bool exec_eval_boolean (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
 
static Datum exec_eval_expr (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
 
static int exec_run_select (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
 
static int exec_for_query (PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt, Portal portal, bool prefetch_ok)
 
static ParamListInfo setup_param_list (PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
 
static ParamExternDataplpgsql_param_fetch (ParamListInfo params, int paramid, bool speculative, ParamExternData *prm)
 
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 HTABcast_expr_hash = NULL
 
static HTABshared_cast_hash = NULL
 

Macro Definition Documentation

◆ eval_mcontext_alloc

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

Definition at line 128 of file pl_exec.c.

◆ eval_mcontext_alloc0

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

Definition at line 130 of file pl_exec.c.

◆ get_eval_mcontext

#define get_eval_mcontext (   estate)     ((estate)->eval_econtext->ecxt_per_tuple_memory)

Definition at line 126 of file pl_exec.c.

◆ LOOP_RC_PROCESSING

#define LOOP_RC_PROCESSING (   looplabel,
  exit_action 
)

Definition at line 203 of file pl_exec.c.

◆ 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:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1683
const char * name

Definition at line 3708 of file pl_exec.c.

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

8629 {
8630  Assert(rec->dtype == PLPGSQL_DTYPE_REC);
8631 
8632  /* Transfer new record object into datum_context */
8633  TransferExpandedRecord(erh, estate->datum_context);
8634 
8635  /* Free the old value ... */
8636  if (rec->erh)
8638 
8639  /* ... and install the new */
8640  rec->erh = erh;
8641 }
#define Assert(condition)
Definition: c.h:863
void DeleteExpandedObject(Datum d)
static Datum ExpandedRecordGetDatum(const ExpandedRecordHeader *erh)
#define TransferExpandedRecord(erh, cxt)
@ PLPGSQL_DTYPE_REC
Definition: plpgsql.h:65
MemoryContext datum_context
Definition: plpgsql.h:1060
ExpandedRecordHeader * erh
Definition: plpgsql.h:414
PLpgSQL_datum_type dtype
Definition: plpgsql.h:391

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

◆ assign_simple_var()

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

Definition at line 8551 of file pl_exec.c.

8553 {
8554  Assert(var->dtype == PLPGSQL_DTYPE_VAR ||
8555  var->dtype == PLPGSQL_DTYPE_PROMISE);
8556 
8557  /*
8558  * In non-atomic contexts, we do not want to store TOAST pointers in
8559  * variables, because such pointers might become stale after a commit.
8560  * Forcibly detoast in such cases. We don't want to detoast (flatten)
8561  * expanded objects, however; those should be OK across a transaction
8562  * boundary since they're just memory-resident objects. (Elsewhere in
8563  * this module, operations on expanded records likewise need to request
8564  * detoasting of record fields when !estate->atomic. Expanded arrays are
8565  * not a problem since all array entries are always detoasted.)
8566  */
8567  if (!estate->atomic && !isnull && var->datatype->typlen == -1 &&
8569  {
8570  MemoryContext oldcxt;
8571  Datum detoasted;
8572 
8573  /*
8574  * Do the detoasting in the eval_mcontext to avoid long-term leakage
8575  * of whatever memory toast fetching might leak. Then we have to copy
8576  * the detoasted datum to the function's main context, which is a
8577  * pain, but there's little choice.
8578  */
8579  oldcxt = MemoryContextSwitchTo(get_eval_mcontext(estate));
8580  detoasted = PointerGetDatum(detoast_external_attr((struct varlena *) DatumGetPointer(newvalue)));
8581  MemoryContextSwitchTo(oldcxt);
8582  /* Now's a good time to not leak the input value if it's freeable */
8583  if (freeable)
8584  pfree(DatumGetPointer(newvalue));
8585  /* Once we copy the value, it's definitely freeable */
8586  newvalue = datumCopy(detoasted, false, -1);
8587  freeable = true;
8588  /* Can't clean up eval_mcontext here, but it'll happen before long */
8589  }
8590 
8591  /* Free the old value if needed */
8592  if (var->freeval)
8593  {
8595  var->isnull,
8596  var->datatype->typlen))
8598  else
8599  pfree(DatumGetPointer(var->value));
8600  }
8601  /* Assign new value to datum */
8602  var->value = newvalue;
8603  var->isnull = isnull;
8604  var->freeval = freeable;
8605 
8606  /*
8607  * If it's a promise variable, then either we just assigned the promised
8608  * value, or the user explicitly assigned an overriding value. Either
8609  * way, cancel the promise.
8610  */
8612 }
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
struct varlena * detoast_external_attr(struct varlena *attr)
Definition: detoast.c:45
#define DatumIsReadWriteExpandedObject(d, isnull, typlen)
void pfree(void *pointer)
Definition: mcxt.c:1521
#define get_eval_mcontext(estate)
Definition: pl_exec.c:126
@ PLPGSQL_PROMISE_NONE
Definition: plpgsql.h:75
@ PLPGSQL_DTYPE_PROMISE
Definition: plpgsql.h:67
@ PLPGSQL_DTYPE_VAR
Definition: plpgsql.h:63
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
MemoryContextSwitchTo(old_ctx)
int16 typlen
Definition: plpgsql.h:203
PLpgSQL_promise_type promise
Definition: plpgsql.h:342
PLpgSQL_datum_type dtype
Definition: plpgsql.h:311
bool freeval
Definition: plpgsql.h:335
bool isnull
Definition: plpgsql.h:334
PLpgSQL_type * datatype
Definition: plpgsql.h:320
Datum value
Definition: plpgsql.h:333
Definition: c.h:692
#define VARATT_IS_EXTERNAL_NON_EXPANDED(PTR)
Definition: varatt.h:300

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

◆ assign_text_var()

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

Definition at line 8618 of file pl_exec.c.

8619 {
8620  assign_simple_var(estate, var, CStringGetTextDatum(str), false, true);
8621 }
#define CStringGetTextDatum(s)
Definition: builtins.h:97
const char * str
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8551

References assign_simple_var(), CStringGetTextDatum, and str.

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

◆ coerce_function_result_tuple()

static void coerce_function_result_tuple ( PLpgSQL_execstate estate,
TupleDesc  tupdesc 
)
static

Definition at line 808 of file pl_exec.c.

809 {
810  HeapTuple rettup;
811  TupleDesc retdesc;
812  TupleConversionMap *tupmap;
813 
814  /* We assume exec_stmt_return verified that result is composite */
815  Assert(type_is_rowtype(estate->rettype));
816 
817  /* We can special-case expanded records for speed */
819  {
821 
822  Assert(erh->er_magic == ER_MAGIC);
823 
824  /* Extract record's TupleDesc */
825  retdesc = expanded_record_get_tupdesc(erh);
826 
827  /* check rowtype compatibility */
828  tupmap = convert_tuples_by_position(retdesc,
829  tupdesc,
830  gettext_noop("returned record type does not match expected record type"));
831 
832  /* it might need conversion */
833  if (tupmap)
834  {
835  rettup = expanded_record_get_tuple(erh);
836  Assert(rettup);
837  rettup = execute_attr_map_tuple(rettup, tupmap);
838 
839  /*
840  * Copy tuple to upper executor memory, as a tuple Datum. Make
841  * sure it is labeled with the caller-supplied tuple type.
842  */
843  estate->retval = PointerGetDatum(SPI_returntuple(rettup, tupdesc));
844  /* no need to free map, we're about to return anyway */
845  }
846  else if (!(tupdesc->tdtypeid == erh->er_decltypeid ||
847  (tupdesc->tdtypeid == RECORDOID &&
848  !ExpandedRecordIsDomain(erh))))
849  {
850  /*
851  * The expanded record has the right physical tupdesc, but the
852  * wrong type ID. (Typically, the expanded record is RECORDOID
853  * but the function is declared to return a named composite type.
854  * As in exec_move_row_from_datum, we don't allow returning a
855  * composite-domain record from a function declared to return
856  * RECORD.) So we must flatten the record to a tuple datum and
857  * overwrite its type fields with the right thing. spi.c doesn't
858  * provide any easy way to deal with this case, so we end up
859  * duplicating the guts of datumCopy() :-(
860  */
861  Size resultsize;
862  HeapTupleHeader tuphdr;
863 
864  resultsize = EOH_get_flat_size(&erh->hdr);
865  tuphdr = (HeapTupleHeader) SPI_palloc(resultsize);
866  EOH_flatten_into(&erh->hdr, (void *) tuphdr, resultsize);
867  HeapTupleHeaderSetTypeId(tuphdr, tupdesc->tdtypeid);
868  HeapTupleHeaderSetTypMod(tuphdr, tupdesc->tdtypmod);
869  estate->retval = PointerGetDatum(tuphdr);
870  }
871  else
872  {
873  /*
874  * We need only copy result into upper executor memory context.
875  * However, if we have a R/W expanded datum, we can just transfer
876  * its ownership out to the upper executor context.
877  */
878  estate->retval = SPI_datumTransfer(estate->retval,
879  false,
880  -1);
881  }
882  }
883  else
884  {
885  /* Convert composite datum to a HeapTuple and TupleDesc */
886  HeapTupleData tmptup;
887 
888  retdesc = deconstruct_composite_datum(estate->retval, &tmptup);
889  rettup = &tmptup;
890 
891  /* check rowtype compatibility */
892  tupmap = convert_tuples_by_position(retdesc,
893  tupdesc,
894  gettext_noop("returned record type does not match expected record type"));
895 
896  /* it might need conversion */
897  if (tupmap)
898  rettup = execute_attr_map_tuple(rettup, tupmap);
899 
900  /*
901  * Copy tuple to upper executor memory, as a tuple Datum. Make sure
902  * it is labeled with the caller-supplied tuple type.
903  */
904  estate->retval = PointerGetDatum(SPI_returntuple(rettup, tupdesc));
905 
906  /* no need to free map, we're about to return anyway */
907 
908  ReleaseTupleDesc(retdesc);
909  }
910 }
#define gettext_noop(x)
Definition: c.h:1201
size_t Size
Definition: c.h:610
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29
void EOH_flatten_into(ExpandedObjectHeader *eohptr, void *result, Size allocated_size)
Definition: expandeddatum.c:81
Size EOH_get_flat_size(ExpandedObjectHeader *eohptr)
Definition: expandeddatum.c:75
HeapTuple expanded_record_get_tuple(ExpandedRecordHeader *erh)
#define ER_MAGIC
#define ExpandedRecordIsDomain(erh)
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define HeapTupleHeaderSetTypMod(tup, typmod)
Definition: htup_details.h:471
#define HeapTupleHeaderSetTypeId(tup, typeid)
Definition: htup_details.h:461
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2655
static TupleDesc deconstruct_composite_datum(Datum value, HeapTupleData *tmptup)
Definition: pl_exec.c:7392
HeapTupleHeader SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc)
Definition: spi.c:1074
Datum SPI_datumTransfer(Datum value, bool typByVal, int typLen)
Definition: spi.c:1361
void * SPI_palloc(Size size)
Definition: spi.c:1338
ExpandedObjectHeader hdr
int32 tdtypmod
Definition: tupdesc.h:83
Oid tdtypeid
Definition: tupdesc.h:82
TupleConversionMap * convert_tuples_by_position(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:59
HeapTuple execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map)
Definition: tupconvert.c:154
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:122
#define VARATT_IS_EXTERNAL_EXPANDED(PTR)
Definition: varatt.h:298

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

◆ compatible_tupdescs()

static bool compatible_tupdescs ( TupleDesc  src_tupdesc,
TupleDesc  dst_tupdesc 
)
static

Definition at line 7293 of file pl_exec.c.

7294 {
7295  int i;
7296 
7297  /* Possibly we could allow src_tupdesc to have extra columns? */
7298  if (dst_tupdesc->natts != src_tupdesc->natts)
7299  return false;
7300 
7301  for (i = 0; i < dst_tupdesc->natts; i++)
7302  {
7303  Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
7304  Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
7305 
7306  if (dattr->attisdropped != sattr->attisdropped)
7307  return false;
7308  if (!dattr->attisdropped)
7309  {
7310  /* Normal columns must match by type and typmod */
7311  if (dattr->atttypid != sattr->atttypid ||
7312  (dattr->atttypmod >= 0 &&
7313  dattr->atttypmod != sattr->atttypmod))
7314  return false;
7315  }
7316  else
7317  {
7318  /* Dropped columns are OK as long as length/alignment match */
7319  if (dattr->attlen != sattr->attlen ||
7320  dattr->attalign != sattr->attalign)
7321  return false;
7322  }
7323  }
7324  return true;
7325 }
int i
Definition: isn.c:72
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References i, TupleDescData::natts, and TupleDescAttr.

Referenced by exec_for_query(), and exec_move_row().

◆ convert_value_to_string()

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

Definition at line 7691 of file pl_exec.c.

7692 {
7693  char *result;
7694  MemoryContext oldcontext;
7695  Oid typoutput;
7696  bool typIsVarlena;
7697 
7698  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7699  getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
7700  result = OidOutputFunctionCall(typoutput, value);
7701  MemoryContextSwitchTo(oldcontext);
7702 
7703  return result;
7704 }
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1763
static struct @160 value
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2907
unsigned int Oid
Definition: postgres_ext.h:31

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

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

◆ copy_plpgsql_datums()

static void copy_plpgsql_datums ( PLpgSQL_execstate estate,
PLpgSQL_function func 
)
static

Definition at line 1294 of file pl_exec.c.

1296 {
1297  int ndatums = estate->ndatums;
1298  PLpgSQL_datum **indatums;
1299  PLpgSQL_datum **outdatums;
1300  char *workspace;
1301  char *ws_next;
1302  int i;
1303 
1304  /* Allocate local datum-pointer array */
1305  estate->datums = (PLpgSQL_datum **)
1306  palloc(sizeof(PLpgSQL_datum *) * ndatums);
1307 
1308  /*
1309  * To reduce palloc overhead, we make a single palloc request for all the
1310  * space needed for locally-instantiated datums.
1311  */
1312  workspace = palloc(func->copiable_size);
1313  ws_next = workspace;
1314 
1315  /* Fill datum-pointer array, copying datums into workspace as needed */
1316  indatums = func->datums;
1317  outdatums = estate->datums;
1318  for (i = 0; i < ndatums; i++)
1319  {
1320  PLpgSQL_datum *indatum = indatums[i];
1321  PLpgSQL_datum *outdatum;
1322 
1323  /* This must agree with plpgsql_finish_datums on what is copiable */
1324  switch (indatum->dtype)
1325  {
1326  case PLPGSQL_DTYPE_VAR:
1327  case PLPGSQL_DTYPE_PROMISE:
1328  outdatum = (PLpgSQL_datum *) ws_next;
1329  memcpy(outdatum, indatum, sizeof(PLpgSQL_var));
1330  ws_next += MAXALIGN(sizeof(PLpgSQL_var));
1331  break;
1332 
1333  case PLPGSQL_DTYPE_REC:
1334  outdatum = (PLpgSQL_datum *) ws_next;
1335  memcpy(outdatum, indatum, sizeof(PLpgSQL_rec));
1336  ws_next += MAXALIGN(sizeof(PLpgSQL_rec));
1337  break;
1338 
1339  case PLPGSQL_DTYPE_ROW:
1341 
1342  /*
1343  * These datum records are read-only at runtime, so no need to
1344  * copy them (well, RECFIELD contains cached data, but we'd
1345  * just as soon centralize the caching anyway).
1346  */
1347  outdatum = indatum;
1348  break;
1349 
1350  default:
1351  elog(ERROR, "unrecognized dtype: %d", indatum->dtype);
1352  outdatum = NULL; /* keep compiler quiet */
1353  break;
1354  }
1355 
1356  outdatums[i] = outdatum;
1357  }
1358 
1359  Assert(ws_next == workspace + func->copiable_size);
1360 }
#define MAXALIGN(LEN)
Definition: c.h:816
#define elog(elevel,...)
Definition: elog.h:225
void * palloc(Size size)
Definition: mcxt.c:1317
@ PLPGSQL_DTYPE_ROW
Definition: plpgsql.h:64
@ PLPGSQL_DTYPE_RECFIELD
Definition: plpgsql.h:66
PLpgSQL_datum_type dtype
Definition: plpgsql.h:277
PLpgSQL_datum ** datums
Definition: plpgsql.h:1058
Size copiable_size
Definition: plpgsql.h:1004
PLpgSQL_datum ** datums
Definition: plpgsql.h:1003

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

◆ deconstruct_composite_datum()

static TupleDesc deconstruct_composite_datum ( Datum  value,
HeapTupleData tmptup 
)
static

Definition at line 7392 of file pl_exec.c.

7393 {
7394  HeapTupleHeader td;
7395  Oid tupType;
7396  int32 tupTypmod;
7397 
7398  /* Get tuple body (note this could involve detoasting) */
7400 
7401  /* Build a temporary HeapTuple control structure */
7402  tmptup->t_len = HeapTupleHeaderGetDatumLength(td);
7403  ItemPointerSetInvalid(&(tmptup->t_self));
7404  tmptup->t_tableOid = InvalidOid;
7405  tmptup->t_data = td;
7406 
7407  /* Extract rowtype info and find a tupdesc */
7408  tupType = HeapTupleHeaderGetTypeId(td);
7409  tupTypmod = HeapTupleHeaderGetTypMod(td);
7410  return lookup_rowtype_tupdesc(tupType, tupTypmod);
7411 }
signed int int32
Definition: c.h:508
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:295
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:466
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:456
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:450
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition: itemptr.h:184
#define InvalidOid
Definition: postgres_ext.h:36
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
HeapTupleHeader t_data
Definition: htup.h:68
Oid t_tableOid
Definition: htup.h:66
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1920

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

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

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

7748 {
7749  plpgsql_CastHashEntry *cast_entry;
7750 
7751  cast_entry = get_cast_hashentry(estate,
7752  valtype, valtypmod,
7753  reqtype, reqtypmod);
7754  if (cast_entry)
7755  {
7756  ExprContext *econtext = estate->eval_econtext;
7757  MemoryContext oldcontext;
7758 
7759  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7760 
7761  econtext->caseValue_datum = value;
7762  econtext->caseValue_isNull = *isnull;
7763 
7764  cast_entry->cast_in_use = true;
7765 
7766  value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
7767  isnull);
7768 
7769  cast_entry->cast_in_use = false;
7770 
7771  MemoryContextSwitchTo(oldcontext);
7772  }
7773 
7774  return value;
7775 }
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:344
static plpgsql_CastHashEntry * get_cast_hashentry(PLpgSQL_execstate *estate, Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod)
Definition: pl_exec.c:7788
bool caseValue_isNull
Definition: execnodes.h:285
Datum caseValue_datum
Definition: execnodes.h:283
ExprContext * eval_econtext
Definition: plpgsql.h:1087
ExprState * cast_exprstate
Definition: pl_exec.c:172

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

◆ exception_matches_conditions()

static bool exception_matches_conditions ( ErrorData edata,
PLpgSQL_condition cond 
)
static

Definition at line 1579 of file pl_exec.c.

1580 {
1581  for (; cond != NULL; cond = cond->next)
1582  {
1583  int sqlerrstate = cond->sqlerrstate;
1584 
1585  /*
1586  * OTHERS matches everything *except* query-canceled and
1587  * assert-failure. If you're foolish enough, you can match those
1588  * explicitly.
1589  */
1590  if (sqlerrstate == 0)
1591  {
1592  if (edata->sqlerrcode != ERRCODE_QUERY_CANCELED &&
1593  edata->sqlerrcode != ERRCODE_ASSERT_FAILURE)
1594  return true;
1595  }
1596  /* Exact match? */
1597  else if (edata->sqlerrcode == sqlerrstate)
1598  return true;
1599  /* Category match? */
1600  else if (ERRCODE_IS_CATEGORY(sqlerrstate) &&
1601  ERRCODE_TO_CATEGORY(edata->sqlerrcode) == sqlerrstate)
1602  return true;
1603  }
1604  return false;
1605 }
#define ERRCODE_IS_CATEGORY(ec)
Definition: elog.h:62
#define ERRCODE_TO_CATEGORY(ec)
Definition: elog.h:61
int sqlerrcode
Definition: elog.h:439
struct PLpgSQL_condition * next
Definition: plpgsql.h:473

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

Referenced by exec_stmt_block().

◆ exec_assign_c_string()

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

Definition at line 5051 of file pl_exec.c.

5053 {
5054  text *value;
5055  MemoryContext oldcontext;
5056 
5057  /* Use eval_mcontext for short-lived text value */
5058  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5059  if (str != NULL)
5061  else
5062  value = cstring_to_text("");
5063  MemoryContextSwitchTo(oldcontext);
5064 
5065  exec_assign_value(estate, target, PointerGetDatum(value), false,
5066  TEXTOID, -1);
5067 }
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:5079
text * cstring_to_text(const char *s)
Definition: varlena.c:184

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

Referenced by exec_stmt_getdiag().

◆ exec_assign_expr()

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

Definition at line 5007 of file pl_exec.c.

5009 {
5010  Datum value;
5011  bool isnull;
5012  Oid valtype;
5013  int32 valtypmod;
5014 
5015  /*
5016  * If first time through, create a plan for this expression.
5017  */
5018  if (expr->plan == NULL)
5019  {
5020  /*
5021  * Mark the expression as being an assignment source, if target is a
5022  * simple variable. (This is a bit messy, but it seems cleaner than
5023  * modifying the API of exec_prepare_plan for the purpose. We need to
5024  * stash the target dno into the expr anyway, so that it will be
5025  * available if we have to replan.)
5026  */
5027  if (target->dtype == PLPGSQL_DTYPE_VAR)
5028  expr->target_param = target->dno;
5029  else
5030  expr->target_param = -1; /* should be that already */
5031 
5032  exec_prepare_plan(estate, expr, 0);
5033  }
5034 
5035  value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod);
5036  exec_assign_value(estate, target, value, isnull, valtype, valtypmod);
5037  exec_eval_cleanup(estate);
5038 }
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4134
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions)
Definition: pl_exec.c:4171
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5683
int target_param
Definition: plpgsql.h:245
SPIPlanPtr plan
Definition: plpgsql.h:222

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

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

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

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, value, 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(), exec_stmt_getdiag(), and plpgsql_estate_setup().

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

7724 {
7725  /*
7726  * If the type of the given value isn't what's requested, convert it.
7727  */
7728  if (valtype != reqtype ||
7729  (valtypmod != reqtypmod && reqtypmod != -1))
7730  {
7731  /* We keep the slow path out-of-line. */
7732  value = do_cast_value(estate, value, isnull, valtype, valtypmod,
7733  reqtype, reqtypmod);
7734  }
7735 
7736  return value;
7737 }
static Datum do_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7744

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(), plpgsql_estate_setup(), and plpgsql_exec_function().

◆ exec_check_assignable()

static void exec_check_assignable ( PLpgSQL_execstate estate,
int  dno 
)
static

Definition at line 8339 of file pl_exec.c.

8340 {
8341  PLpgSQL_datum *datum;
8342 
8343  Assert(dno >= 0 && dno < estate->ndatums);
8344  datum = estate->datums[dno];
8345  switch (datum->dtype)
8346  {
8347  case PLPGSQL_DTYPE_VAR:
8348  case PLPGSQL_DTYPE_PROMISE:
8349  case PLPGSQL_DTYPE_REC:
8350  if (((PLpgSQL_variable *) datum)->isconst)
8351  ereport(ERROR,
8352  (errcode(ERRCODE_ERROR_IN_ASSIGNMENT),
8353  errmsg("variable \"%s\" is declared CONSTANT",
8354  ((PLpgSQL_variable *) datum)->refname)));
8355  break;
8356  case PLPGSQL_DTYPE_ROW:
8357  /* always assignable; member vars were checked at compile time */
8358  break;
8360  /* assignable if parent record is */
8361  exec_check_assignable(estate,
8362  ((PLpgSQL_recfield *) datum)->recparentno);
8363  break;
8364  default:
8365  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
8366  break;
8367  }
8368 }
static void exec_check_assignable(PLpgSQL_execstate *estate, int dno)
Definition: pl_exec.c:8339
PLpgSQL_datum_type dtype
Definition: plpgsql.h:289

References Assert, PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, PLpgSQL_variable::dtype, elog, ereport, errcode(), errmsg(), ERROR, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ROW, and PLPGSQL_DTYPE_VAR.

Referenced by exec_stmt_forc(), exec_stmt_open(), and make_callstmt_target().

◆ exec_check_rw_parameter()

static void exec_check_rw_parameter ( PLpgSQL_expr expr)
static

Definition at line 8228 of file pl_exec.c.

8229 {
8230  int target_dno;
8231  Oid funcid;
8232  List *fargs;
8233  ListCell *lc;
8234 
8235  /* Assume unsafe */
8236  expr->expr_rw_param = NULL;
8237 
8238  /* Done if expression isn't an assignment source */
8239  target_dno = expr->target_param;
8240  if (target_dno < 0)
8241  return;
8242 
8243  /*
8244  * If target variable isn't referenced by expression, no need to look
8245  * further.
8246  */
8247  if (!bms_is_member(target_dno, expr->paramnos))
8248  return;
8249 
8250  /* Shouldn't be here for non-simple expression */
8251  Assert(expr->expr_simple_expr != NULL);
8252 
8253  /*
8254  * Top level of expression must be a simple FuncExpr, OpExpr, or
8255  * SubscriptingRef, else we can't optimize.
8256  */
8257  if (IsA(expr->expr_simple_expr, FuncExpr))
8258  {
8259  FuncExpr *fexpr = (FuncExpr *) expr->expr_simple_expr;
8260 
8261  funcid = fexpr->funcid;
8262  fargs = fexpr->args;
8263  }
8264  else if (IsA(expr->expr_simple_expr, OpExpr))
8265  {
8266  OpExpr *opexpr = (OpExpr *) expr->expr_simple_expr;
8267 
8268  funcid = opexpr->opfuncid;
8269  fargs = opexpr->args;
8270  }
8271  else if (IsA(expr->expr_simple_expr, SubscriptingRef))
8272  {
8273  SubscriptingRef *sbsref = (SubscriptingRef *) expr->expr_simple_expr;
8274 
8275  /* We only trust standard varlena arrays to be safe */
8276  if (get_typsubscript(sbsref->refcontainertype, NULL) !=
8277  F_ARRAY_SUBSCRIPT_HANDLER)
8278  return;
8279 
8280  /* We can optimize the refexpr if it's the target, otherwise not */
8281  if (sbsref->refexpr && IsA(sbsref->refexpr, Param))
8282  {
8283  Param *param = (Param *) sbsref->refexpr;
8284 
8285  if (param->paramkind == PARAM_EXTERN &&
8286  param->paramid == target_dno + 1)
8287  {
8288  /* Found the Param we want to pass as read/write */
8289  expr->expr_rw_param = param;
8290  return;
8291  }
8292  }
8293 
8294  return;
8295  }
8296  else
8297  return;
8298 
8299  /*
8300  * The top-level function must be one that we trust to be "safe".
8301  * Currently we hard-wire the list, but it would be very desirable to
8302  * allow extensions to mark their functions as safe ...
8303  */
8304  if (!(funcid == F_ARRAY_APPEND ||
8305  funcid == F_ARRAY_PREPEND))
8306  return;
8307 
8308  /*
8309  * The target variable (in the form of a Param) must appear as a direct
8310  * argument of the top-level function. References further down in the
8311  * tree can't be optimized; but on the other hand, they don't invalidate
8312  * optimizing the top-level call, since that will be executed last.
8313  */
8314  foreach(lc, fargs)
8315  {
8316  Node *arg = (Node *) lfirst(lc);
8317 
8318  if (arg && IsA(arg, Param))
8319  {
8320  Param *param = (Param *) arg;
8321 
8322  if (param->paramkind == PARAM_EXTERN &&
8323  param->paramid == target_dno + 1)
8324  {
8325  /* Found the Param we want to pass as read/write */
8326  expr->expr_rw_param = param;
8327  return;
8328  }
8329  }
8330  }
8331 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
RegProcedure get_typsubscript(Oid typid, Oid *typelemp)
Definition: lsyscache.c:3097
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
void * arg
#define lfirst(lc)
Definition: pg_list.h:172
@ PARAM_EXTERN
Definition: primnodes.h:367
Oid funcid
Definition: primnodes.h:750
List * args
Definition: primnodes.h:768
Definition: pg_list.h:54
Definition: nodes.h:129
List * args
Definition: primnodes.h:836
Expr * expr_simple_expr
Definition: plpgsql.h:232
Bitmapset * paramnos
Definition: plpgsql.h:223
Param * expr_rw_param
Definition: plpgsql.h:246
int paramid
Definition: primnodes.h:377
ParamKind paramkind
Definition: primnodes.h:376
Expr * refexpr
Definition: primnodes.h:701

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

Referenced by exec_save_simple_expr().

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

8737 {
8738  Portal portal;
8739  Datum query;
8740  bool isnull;
8741  Oid restype;
8742  int32 restypmod;
8743  char *querystr;
8745  MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
8746 
8747  /*
8748  * Evaluate the string expression after the EXECUTE keyword. Its result is
8749  * the querystring we have to execute.
8750  */
8751  query = exec_eval_expr(estate, dynquery, &isnull, &restype, &restypmod);
8752  if (isnull)
8753  ereport(ERROR,
8754  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
8755  errmsg("query string argument of EXECUTE is null")));
8756 
8757  /* Get the C-String representation */
8758  querystr = convert_value_to_string(estate, query, restype);
8759 
8760  /* copy it into the stmt_mcontext before we clean up */
8761  querystr = MemoryContextStrdup(stmt_mcontext, querystr);
8762 
8763  exec_eval_cleanup(estate);
8764 
8765  /*
8766  * Open an implicit cursor for the query. We use SPI_cursor_parse_open
8767  * even when there are no params, because this avoids making and freeing
8768  * one copy of the plan.
8769  */
8770  memset(&options, 0, sizeof(options));
8771  options.params = exec_eval_using_params(estate, params);
8772  options.cursorOptions = cursorOptions;
8773  options.read_only = estate->readonly_func;
8774 
8775  portal = SPI_cursor_parse_open(portalname, querystr, &options);
8776 
8777  if (portal == NULL)
8778  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
8779  querystr, SPI_result_code_string(SPI_result));
8780 
8781  /* Release transient data */
8782  MemoryContextReset(stmt_mcontext);
8783 
8784  return portal;
8785 }
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
static char ** options
static char * convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
Definition: pl_exec.c:7691
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1528
static ParamListInfo exec_eval_using_params(PLpgSQL_execstate *estate, List *params)
Definition: pl_exec.c:8650
int SPI_result
Definition: spi.c:46
const char * SPI_result_code_string(int code)
Definition: spi.c:1972
Portal SPI_cursor_parse_open(const char *name, const char *src, const SPIParseOpenOptions *options)
Definition: spi.c:1533

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

Referenced by exec_stmt_dynfors(), and exec_stmt_open().

◆ exec_eval_boolean()

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

Definition at line 5660 of file pl_exec.c.

5663 {
5664  Datum exprdatum;
5665  Oid exprtypeid;
5666  int32 exprtypmod;
5667 
5668  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5669  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5670  exprtypeid, exprtypmod,
5671  BOOLOID, -1);
5672  return DatumGetBool(exprdatum);
5673 }
static bool DatumGetBool(Datum X)
Definition: postgres.h:90

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

◆ exec_eval_cleanup()

static void exec_eval_cleanup ( PLpgSQL_execstate estate)
static

Definition at line 4134 of file pl_exec.c.

4135 {
4136  /* Clear result of a full SPI_execute */
4137  if (estate->eval_tuptable != NULL)
4139  estate->eval_tuptable = NULL;
4140 
4141  /*
4142  * Clear result of exec_eval_simple_expr (but keep the econtext). This
4143  * also clears any short-lived allocations done via get_eval_mcontext.
4144  */
4145  if (estate->eval_econtext != NULL)
4147 }
#define ResetExprContext(econtext)
Definition: executor.h:555
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1386
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1085

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

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

5312 {
5313  MemoryContext oldcontext;
5314 
5315  switch (datum->dtype)
5316  {
5317  case PLPGSQL_DTYPE_PROMISE:
5318  /* fulfill promise if needed, then handle like regular var */
5319  plpgsql_fulfill_promise(estate, (PLpgSQL_var *) datum);
5320 
5321  /* FALL THRU */
5322 
5323  case PLPGSQL_DTYPE_VAR:
5324  {
5325  PLpgSQL_var *var = (PLpgSQL_var *) datum;
5326 
5327  *typeid = var->datatype->typoid;
5328  *typetypmod = var->datatype->atttypmod;
5329  *value = var->value;
5330  *isnull = var->isnull;
5331  break;
5332  }
5333 
5334  case PLPGSQL_DTYPE_ROW:
5335  {
5336  PLpgSQL_row *row = (PLpgSQL_row *) datum;
5337  HeapTuple tup;
5338 
5339  /* We get here if there are multiple OUT parameters */
5340  if (!row->rowtupdesc) /* should not happen */
5341  elog(ERROR, "row variable has no tupdesc");
5342  /* Make sure we have a valid type/typmod setting */
5343  BlessTupleDesc(row->rowtupdesc);
5344  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5345  tup = make_tuple_from_row(estate, row, row->rowtupdesc);
5346  if (tup == NULL) /* should not happen */
5347  elog(ERROR, "row not compatible with its own tupdesc");
5348  *typeid = row->rowtupdesc->tdtypeid;
5349  *typetypmod = row->rowtupdesc->tdtypmod;
5350  *value = HeapTupleGetDatum(tup);
5351  *isnull = false;
5352  MemoryContextSwitchTo(oldcontext);
5353  break;
5354  }
5355 
5356  case PLPGSQL_DTYPE_REC:
5357  {
5358  PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
5359 
5360  if (rec->erh == NULL)
5361  {
5362  /* Treat uninstantiated record as a simple NULL */
5363  *value = (Datum) 0;
5364  *isnull = true;
5365  /* Report variable's declared type */
5366  *typeid = rec->rectypeid;
5367  *typetypmod = -1;
5368  }
5369  else
5370  {
5371  if (ExpandedRecordIsEmpty(rec->erh))
5372  {
5373  /* Empty record is also a NULL */
5374  *value = (Datum) 0;
5375  *isnull = true;
5376  }
5377  else
5378  {
5379  *value = ExpandedRecordGetDatum(rec->erh);
5380  *isnull = false;
5381  }
5382  if (rec->rectypeid != RECORDOID)
5383  {
5384  /* Report variable's declared type, if not RECORD */
5385  *typeid = rec->rectypeid;
5386  *typetypmod = -1;
5387  }
5388  else
5389  {
5390  /* Report record's actual type if declared RECORD */
5391  *typeid = rec->erh->er_typeid;
5392  *typetypmod = rec->erh->er_typmod;
5393  }
5394  }
5395  break;
5396  }
5397 
5399  {
5400  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
5401  PLpgSQL_rec *rec;
5402  ExpandedRecordHeader *erh;
5403 
5404  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5405  erh = rec->erh;
5406 
5407  /*
5408  * If record variable is NULL, instantiate it if it has a
5409  * named composite type, else complain. (This won't change
5410  * the logical state of the record: it's still NULL.)
5411  */
5412  if (erh == NULL)
5413  {
5414  instantiate_empty_record_variable(estate, rec);
5415  erh = rec->erh;
5416  }
5417 
5418  /*
5419  * Look up the field's properties if we have not already, or
5420  * if the tuple descriptor ID changed since last time.
5421  */
5422  if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
5423  {
5425  recfield->fieldname,
5426  &recfield->finfo))
5427  ereport(ERROR,
5428  (errcode(ERRCODE_UNDEFINED_COLUMN),
5429  errmsg("record \"%s\" has no field \"%s\"",
5430  rec->refname, recfield->fieldname)));
5431  recfield->rectupledescid = erh->er_tupdesc_id;
5432  }
5433 
5434  /* Report type data. */
5435  *typeid = recfield->finfo.ftypeid;
5436  *typetypmod = recfield->finfo.ftypmod;
5437 
5438  /* And fetch the field value. */
5440  recfield->finfo.fnumber,
5441  isnull);
5442  break;
5443  }
5444 
5445  default:
5446  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
5447  }
5448 }
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2158
#define ExpandedRecordIsEmpty(erh)
static Datum expanded_record_get_field(ExpandedRecordHeader *erh, int fnumber, bool *isnull)
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
static void plpgsql_fulfill_promise(PLpgSQL_execstate *estate, PLpgSQL_var *var)
Definition: pl_exec.c:1368
static HeapTuple make_tuple_from_row(PLpgSQL_execstate *estate, PLpgSQL_row *row, TupleDesc tupdesc)
Definition: pl_exec.c:7337
Oid rectypeid
Definition: plpgsql.h:407
TupleDesc rowtupdesc
Definition: plpgsql.h:379

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, value, and PLpgSQL_var::value.

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

◆ exec_eval_expr()

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

Definition at line 5683 of file pl_exec.c.

5688 {
5689  Datum result = 0;
5690  int rc;
5691  Form_pg_attribute attr;
5692 
5693  /*
5694  * If first time through, create a plan for this expression.
5695  */
5696  if (expr->plan == NULL)
5698 
5699  /*
5700  * If this is a simple expression, bypass SPI and use the executor
5701  * directly
5702  */
5703  if (exec_eval_simple_expr(estate, expr,
5704  &result, isNull, rettype, rettypmod))
5705  return result;
5706 
5707  /*
5708  * Else do it the hard way via exec_run_select
5709  */
5710  rc = exec_run_select(estate, expr, 2, NULL);
5711  if (rc != SPI_OK_SELECT)
5712  ereport(ERROR,
5713  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5714  errmsg("query did not return data"),
5715  errcontext("query: %s", expr->query)));
5716 
5717  /*
5718  * Check that the expression returns exactly one column...
5719  */
5720  if (estate->eval_tuptable->tupdesc->natts != 1)
5721  ereport(ERROR,
5722  (errcode(ERRCODE_SYNTAX_ERROR),
5723  errmsg_plural("query returned %d column",
5724  "query returned %d columns",
5725  estate->eval_tuptable->tupdesc->natts,
5726  estate->eval_tuptable->tupdesc->natts),
5727  errcontext("query: %s", expr->query)));
5728 
5729  /*
5730  * ... and get the column's datatype.
5731  */
5732  attr = TupleDescAttr(estate->eval_tuptable->tupdesc, 0);
5733  *rettype = attr->atttypid;
5734  *rettypmod = attr->atttypmod;
5735 
5736  /*
5737  * If there are no rows selected, the result is a NULL of that type.
5738  */
5739  if (estate->eval_processed == 0)
5740  {
5741  *isNull = true;
5742  return (Datum) 0;
5743  }
5744 
5745  /*
5746  * Check that the expression returned no more than one row.
5747  */
5748  if (estate->eval_processed != 1)
5749  ereport(ERROR,
5750  (errcode(ERRCODE_CARDINALITY_VIOLATION),
5751  errmsg("query returned more than one row"),
5752  errcontext("query: %s", expr->query)));
5753 
5754  /*
5755  * Return the single result Datum.
5756  */
5757  return SPI_getbinval(estate->eval_tuptable->vals[0],
5758  estate->eval_tuptable->tupdesc, 1, isNull);
5759 }
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1180
#define errcontext
Definition: elog.h:196
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:3317
static bool exec_eval_simple_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, Datum *result, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:6033
static int exec_run_select(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
Definition: pl_exec.c:5767
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition: spi.c:1252
#define SPI_OK_SELECT
Definition: spi.h:86
uint64 eval_processed
Definition: plpgsql.h:1086
char * query
Definition: plpgsql.h:220
TupleDesc tupdesc
Definition: spi.h:25
HeapTuple * vals
Definition: spi.h:26

References CURSOR_OPT_PARALLEL_OK, ereport, errcode(), errcontext, 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().

◆ exec_eval_integer()

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

Definition at line 5637 of file pl_exec.c.

5640 {
5641  Datum exprdatum;
5642  Oid exprtypeid;
5643  int32 exprtypmod;
5644 
5645  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5646  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5647  exprtypeid, exprtypmod,
5648  INT4OID, -1);
5649  return DatumGetInt32(exprdatum);
5650 }
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:202

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

Referenced by exec_stmt_fetch().

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

6039 {
6040  ExprContext *econtext = estate->eval_econtext;
6041  LocalTransactionId curlxid = MyProc->vxid.lxid;
6042  ParamListInfo paramLI;
6043  void *save_setup_arg;
6044  bool need_snapshot;
6045  MemoryContext oldcontext;
6046 
6047  /*
6048  * Forget it if expression wasn't simple before.
6049  */
6050  if (expr->expr_simple_expr == NULL)
6051  return false;
6052 
6053  /*
6054  * If expression is in use in current xact, don't touch it.
6055  */
6056  if (unlikely(expr->expr_simple_in_use) &&
6057  expr->expr_simple_lxid == curlxid)
6058  return false;
6059 
6060  /*
6061  * Ensure that there's a portal-level snapshot, in case this simple
6062  * expression is the first thing evaluated after a COMMIT or ROLLBACK.
6063  * We'd have to do this anyway before executing the expression, so we
6064  * might as well do it now to ensure that any possible replanning doesn't
6065  * need to take a new snapshot.
6066  */
6068 
6069  /*
6070  * Check to see if the cached plan has been invalidated. If not, and this
6071  * is the first use in the current transaction, save a plan refcount in
6072  * the simple-expression resowner.
6073  */
6075  expr->expr_simple_plan,
6076  (expr->expr_simple_plan_lxid != curlxid ?
6077  estate->simple_eval_resowner : NULL))))
6078  {
6079  /*
6080  * It's still good, so just remember that we have a refcount on the
6081  * plan in the current transaction. (If we already had one, this
6082  * assignment is a no-op.)
6083  */
6084  expr->expr_simple_plan_lxid = curlxid;
6085  }
6086  else
6087  {
6088  /* Need to replan */
6089  CachedPlan *cplan;
6090 
6091  /*
6092  * If we have a valid refcount on some previous version of the plan,
6093  * release it, so we don't leak plans intra-transaction.
6094  */
6095  if (expr->expr_simple_plan_lxid == curlxid)
6097  estate->simple_eval_resowner);
6098 
6099  /*
6100  * Reset to "not simple" to leave sane state (with no dangling
6101  * pointers) in case we fail while replanning. expr_simple_plansource
6102  * can be left alone however, as that cannot move.
6103  */
6104  expr->expr_simple_expr = NULL;
6105  expr->expr_rw_param = NULL;
6106  expr->expr_simple_plan = NULL;
6108 
6109  /* Do the replanning work in the eval_mcontext */
6110  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6111  cplan = SPI_plan_get_cached_plan(expr->plan);
6112  MemoryContextSwitchTo(oldcontext);
6113 
6114  /*
6115  * We can't get a failure here, because the number of
6116  * CachedPlanSources in the SPI plan can't change from what
6117  * exec_simple_check_plan saw; it's a property of the raw parsetree
6118  * generated from the query text.
6119  */
6120  Assert(cplan != NULL);
6121 
6122  /*
6123  * Recheck exec_is_simple_query, which could now report false in
6124  * edge-case scenarios such as a non-SRF having been replaced with a
6125  * SRF. Also recheck CachedPlanAllowsSimpleValidityCheck, just to be
6126  * sure. If either test fails, cope by declaring the plan to be
6127  * non-simple. On success, we'll acquire a refcount on the new plan,
6128  * stored in simple_eval_resowner.
6129  */
6130  if (exec_is_simple_query(expr) &&
6132  cplan,
6133  estate->simple_eval_resowner))
6134  {
6135  /* Remember that we have the refcount */
6136  expr->expr_simple_plan = cplan;
6137  expr->expr_simple_plan_lxid = curlxid;
6138  }
6139  else
6140  {
6141  /* Release SPI_plan_get_cached_plan's refcount */
6143  return false;
6144  }
6145 
6146  /*
6147  * SPI_plan_get_cached_plan acquired a plan refcount stored in the
6148  * active resowner. We don't need that anymore, so release it.
6149  */
6151 
6152  /* Extract desired scalar expression from cached plan */
6153  exec_save_simple_expr(expr, cplan);
6154  }
6155 
6156  /*
6157  * Pass back previously-determined result type.
6158  */
6159  *rettype = expr->expr_simple_type;
6160  *rettypmod = expr->expr_simple_typmod;
6161 
6162  /*
6163  * Set up ParamListInfo to pass to executor. For safety, save and restore
6164  * estate->paramLI->parserSetupArg around our use of the param list.
6165  */
6166  paramLI = estate->paramLI;
6167  save_setup_arg = paramLI->parserSetupArg;
6168 
6169  /*
6170  * We can skip using setup_param_list() in favor of just doing this
6171  * unconditionally, because there's no need for the optimization of
6172  * possibly setting ecxt_param_list_info to NULL; we've already forced use
6173  * of a generic plan.
6174  */
6175  paramLI->parserSetupArg = (void *) expr;
6176  econtext->ecxt_param_list_info = paramLI;
6177 
6178  /*
6179  * Prepare the expression for execution, if it's not been done already in
6180  * the current transaction. (This will be forced to happen if we called
6181  * exec_save_simple_expr above.)
6182  */
6183  if (unlikely(expr->expr_simple_lxid != curlxid))
6184  {
6185  oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
6186  expr->expr_simple_state =
6188  econtext->ecxt_param_list_info);
6189  expr->expr_simple_in_use = false;
6190  expr->expr_simple_lxid = curlxid;
6191  MemoryContextSwitchTo(oldcontext);
6192  }
6193 
6194  /*
6195  * We have to do some of the things SPI_execute_plan would do, in
6196  * particular push a new snapshot so that stable functions within the
6197  * expression can see updates made so far by our own function. However,
6198  * we can skip doing that (and just invoke the expression with the same
6199  * snapshot passed to our function) in some cases, which is useful because
6200  * it's quite expensive relative to the cost of a simple expression. We
6201  * can skip it if the expression contains no stable or volatile functions;
6202  * immutable functions shouldn't need to see our updates. Also, if this
6203  * is a read-only function, we haven't made any updates so again it's okay
6204  * to skip.
6205  */
6206  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6207  need_snapshot = (expr->expr_simple_mutable && !estate->readonly_func);
6208  if (need_snapshot)
6209  {
6212  }
6213 
6214  /*
6215  * Mark expression as busy for the duration of the ExecEvalExpr call.
6216  */
6217  expr->expr_simple_in_use = true;
6218 
6219  /*
6220  * Finally we can call the executor to evaluate the expression
6221  */
6222  *result = ExecEvalExpr(expr->expr_simple_state,
6223  econtext,
6224  isNull);
6225 
6226  /* Assorted cleanup */
6227  expr->expr_simple_in_use = false;
6228 
6229  econtext->ecxt_param_list_info = NULL;
6230 
6231  paramLI->parserSetupArg = save_setup_arg;
6232 
6233  if (need_snapshot)
6235 
6236  MemoryContextSwitchTo(oldcontext);
6237 
6238  /*
6239  * That's it.
6240  */
6241  return true;
6242 }
#define likely(x)
Definition: c.h:325
uint32 LocalTransactionId
Definition: c.h:659
ExprState * ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
Definition: execExpr.c:175
#define InvalidLocalTransactionId
Definition: lock.h:65
static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
Definition: pl_exec.c:8121
static bool exec_is_simple_query(PLpgSQL_expr *expr)
Definition: pl_exec.c:8050
bool CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1336
bool CachedPlanIsSimplyValid(CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1451
void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1291
void EnsurePortalSnapshotExists(void)
Definition: pquery.c:1780
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:216
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:648
void PopActiveSnapshot(void)
Definition: snapmgr.c:743
CachedPlan * SPI_plan_get_cached_plan(SPIPlanPtr plan)
Definition: spi.c:2076
PGPROC * MyProc
Definition: proc.c:66
MemoryContext es_query_cxt
Definition: execnodes.h:675
ParamListInfo ecxt_param_list_info
Definition: execnodes.h:270
LocalTransactionId lxid
Definition: proc.h:200
struct PGPROC::@122 vxid
EState * simple_eval_estate
Definition: plpgsql.h:1071
ParamListInfo paramLI
Definition: plpgsql.h:1068
ResourceOwner simple_eval_resowner
Definition: plpgsql.h:1072
CachedPlanSource * expr_simple_plansource
Definition: plpgsql.h:254
CachedPlan * expr_simple_plan
Definition: plpgsql.h:255
Oid expr_simple_type
Definition: plpgsql.h:233
ExprState * expr_simple_state
Definition: plpgsql.h:264
bool expr_simple_mutable
Definition: plpgsql.h:235
bool expr_simple_in_use
Definition: plpgsql.h:265
LocalTransactionId expr_simple_plan_lxid
Definition: plpgsql.h:256
LocalTransactionId expr_simple_lxid
Definition: plpgsql.h:266
int32 expr_simple_typmod
Definition: plpgsql.h:234
void * parserSetupArg
Definition: params.h:117
void CommandCounterIncrement(void)
Definition: xact.c:1099

References Assert, CachedPlanAllowsSimpleValidityCheck(), CachedPlanIsSimplyValid(), CommandCounterIncrement(), CurrentResourceOwner, ExprContext::ecxt_param_list_info, EnsurePortalSnapshotExists(), EState::es_query_cxt, PLpgSQL_execstate::eval_econtext, exec_is_simple_query(), 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(), unlikely, and PGPROC::vxid.

Referenced by exec_eval_expr().

◆ exec_eval_using_params()

static ParamListInfo exec_eval_using_params ( PLpgSQL_execstate estate,
List params 
)
static

Definition at line 8650 of file pl_exec.c.

8651 {
8652  ParamListInfo paramLI;
8653  int nargs;
8654  MemoryContext stmt_mcontext;
8655  MemoryContext oldcontext;
8656  int i;
8657  ListCell *lc;
8658 
8659  /* Fast path for no parameters: we can just return NULL */
8660  if (params == NIL)
8661  return NULL;
8662 
8663  nargs = list_length(params);
8664  stmt_mcontext = get_stmt_mcontext(estate);
8665  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8666  paramLI = makeParamList(nargs);
8667  MemoryContextSwitchTo(oldcontext);
8668 
8669  i = 0;
8670  foreach(lc, params)
8671  {
8672  PLpgSQL_expr *param = (PLpgSQL_expr *) lfirst(lc);
8673  ParamExternData *prm = &paramLI->params[i];
8674  int32 ppdtypmod;
8675 
8676  /*
8677  * Always mark params as const, since we only use the result with
8678  * one-shot plans.
8679  */
8680  prm->pflags = PARAM_FLAG_CONST;
8681 
8682  prm->value = exec_eval_expr(estate, param,
8683  &prm->isnull,
8684  &prm->ptype,
8685  &ppdtypmod);
8686 
8687  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8688 
8689  if (prm->ptype == UNKNOWNOID)
8690  {
8691  /*
8692  * Treat 'unknown' parameters as text, since that's what most
8693  * people would expect. The SPI functions can coerce unknown
8694  * constants in a more intelligent way, but not unknown Params.
8695  * This code also takes care of copying into the right context.
8696  * Note we assume 'unknown' has the representation of C-string.
8697  */
8698  prm->ptype = TEXTOID;
8699  if (!prm->isnull)
8701  }
8702  /* pass-by-ref non null values must be copied into stmt_mcontext */
8703  else if (!prm->isnull)
8704  {
8705  int16 typLen;
8706  bool typByVal;
8707 
8708  get_typlenbyval(prm->ptype, &typLen, &typByVal);
8709  if (!typByVal)
8710  prm->value = datumCopy(prm->value, typByVal, typLen);
8711  }
8712 
8713  MemoryContextSwitchTo(oldcontext);
8714 
8715  exec_eval_cleanup(estate);
8716 
8717  i++;
8718  }
8719 
8720  return paramLI;
8721 }
signed short int16
Definition: c.h:507
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2251
ParamListInfo makeParamList(int numParams)
Definition: params.c:44
#define PARAM_FLAG_CONST
Definition: params.h:88
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
static char * DatumGetCString(Datum X)
Definition: postgres.h:335
bool isnull
Definition: params.h:93
uint16 pflags
Definition: params.h:94
Datum value
Definition: params.h:92
ParamExternData params[FLEXIBLE_ARRAY_MEMBER]
Definition: params.h:125

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

◆ exec_for_query()

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

Definition at line 5851 of file pl_exec.c.

5853 {
5854  PLpgSQL_variable *var;
5855  SPITupleTable *tuptab;
5856  bool found = false;
5857  int rc = PLPGSQL_RC_OK;
5858  uint64 previous_id = INVALID_TUPLEDESC_IDENTIFIER;
5859  bool tupdescs_match = true;
5860  uint64 n;
5861 
5862  /* Fetch loop variable's datum entry */
5863  var = (PLpgSQL_variable *) estate->datums[stmt->var->dno];
5864 
5865  /*
5866  * Make sure the portal doesn't get closed by the user statements we
5867  * execute.
5868  */
5869  PinPortal(portal);
5870 
5871  /*
5872  * In a non-atomic context, we dare not prefetch, even if it would
5873  * otherwise be safe. Aside from any semantic hazards that that might
5874  * create, if we prefetch toasted data and then the user commits the
5875  * transaction, the toast references could turn into dangling pointers.
5876  * (Rows we haven't yet fetched from the cursor are safe, because the
5877  * PersistHoldablePortal mechanism handles this scenario.)
5878  */
5879  if (!estate->atomic)
5880  prefetch_ok = false;
5881 
5882  /*
5883  * Fetch the initial tuple(s). If prefetching is allowed then we grab a
5884  * few more rows to avoid multiple trips through executor startup
5885  * overhead.
5886  */
5887  SPI_cursor_fetch(portal, true, prefetch_ok ? 10 : 1);
5888  tuptab = SPI_tuptable;
5889  n = SPI_processed;
5890 
5891  /*
5892  * If the query didn't return any rows, set the target to NULL and fall
5893  * through with found = false.
5894  */
5895  if (n == 0)
5896  {
5897  exec_move_row(estate, var, NULL, tuptab->tupdesc);
5898  exec_eval_cleanup(estate);
5899  }
5900  else
5901  found = true; /* processed at least one tuple */
5902 
5903  /*
5904  * Now do the loop
5905  */
5906  while (n > 0)
5907  {
5908  uint64 i;
5909 
5910  for (i = 0; i < n; i++)
5911  {
5912  /*
5913  * Assign the tuple to the target. Here, because we know that all
5914  * loop iterations should be assigning the same tupdesc, we can
5915  * optimize away repeated creations of expanded records with
5916  * identical tupdescs. Testing for changes of er_tupdesc_id is
5917  * reliable even if the loop body contains assignments that
5918  * replace the target's value entirely, because it's assigned from
5919  * a process-global counter. The case where the tupdescs don't
5920  * match could possibly be handled more efficiently than this
5921  * coding does, but it's not clear extra effort is worthwhile.
5922  */
5923  if (var->dtype == PLPGSQL_DTYPE_REC)
5924  {
5925  PLpgSQL_rec *rec = (PLpgSQL_rec *) var;
5926 
5927  if (rec->erh &&
5928  rec->erh->er_tupdesc_id == previous_id &&
5929  tupdescs_match)
5930  {
5931  /* Only need to assign a new tuple value */
5932  expanded_record_set_tuple(rec->erh, tuptab->vals[i],
5933  true, !estate->atomic);
5934  }
5935  else
5936  {
5937  /*
5938  * First time through, or var's tupdesc changed in loop,
5939  * or we have to do it the hard way because type coercion
5940  * is needed.
5941  */
5942  exec_move_row(estate, var,
5943  tuptab->vals[i], tuptab->tupdesc);
5944 
5945  /*
5946  * Check to see if physical assignment is OK next time.
5947  * Once the tupdesc comparison has failed once, we don't
5948  * bother rechecking in subsequent loop iterations.
5949  */
5950  if (tupdescs_match)
5951  {
5952  tupdescs_match =
5953  (rec->rectypeid == RECORDOID ||
5954  rec->rectypeid == tuptab->tupdesc->tdtypeid ||
5955  compatible_tupdescs(tuptab->tupdesc,
5957  }
5958  previous_id = rec->erh->er_tupdesc_id;
5959  }
5960  }
5961  else
5962  exec_move_row(estate, var, tuptab->vals[i], tuptab->tupdesc);
5963 
5964  exec_eval_cleanup(estate);
5965 
5966  /*
5967  * Execute the statements
5968  */
5969  rc = exec_stmts(estate, stmt->body);
5970 
5971  LOOP_RC_PROCESSING(stmt->label, goto loop_exit);
5972  }
5973 
5974  SPI_freetuptable(tuptab);
5975 
5976  /*
5977  * Fetch more tuples. If prefetching is allowed, grab 50 at a time.
5978  */
5979  SPI_cursor_fetch(portal, true, prefetch_ok ? 50 : 1);
5980  tuptab = SPI_tuptable;
5981  n = SPI_processed;
5982  }
5983 
5984 loop_exit:
5985 
5986  /*
5987  * Release last group of tuples (if any)
5988  */
5989  SPI_freetuptable(tuptab);
5990 
5991  UnpinPortal(portal);
5992 
5993  /*
5994  * Set the FOUND variable to indicate the result of executing the loop
5995  * (namely, whether we looped one or more times). This must be set last so
5996  * that it does not interfere with the value of the FOUND variable inside
5997  * the loop processing itself.
5998  */
5999  exec_set_found(estate, found);
6000 
6001  return rc;
6002 }
void expanded_record_set_tuple(ExpandedRecordHeader *erh, HeapTuple tuple, bool copy, bool expand_external)
#define stmt
Definition: indent_codes.h:59
#define LOOP_RC_PROCESSING(looplabel, exit_action)
Definition: pl_exec.c:203
static int exec_stmts(PLpgSQL_execstate *estate, List *stmts)
Definition: pl_exec.c:1980
static void exec_set_found(PLpgSQL_execstate *estate, bool state)
Definition: pl_exec.c:8375
static bool compatible_tupdescs(TupleDesc src_tupdesc, TupleDesc dst_tupdesc)
Definition: pl_exec.c:7293
@ PLPGSQL_RC_OK
Definition: plpgsql.h:138
void PinPortal(Portal portal)
Definition: portalmem.c:371
void UnpinPortal(Portal portal)
Definition: portalmem.c:380
uint64 SPI_processed
Definition: spi.c:44
SPITupleTable * SPI_tuptable
Definition: spi.c:45
void SPI_cursor_fetch(Portal portal, bool forward, long count)
Definition: spi.c:1806
#define INVALID_TUPLEDESC_IDENTIFIER
Definition: typcache.h:156

References PLpgSQL_execstate::atomic, compatible_tupdescs(), PLpgSQL_execstate::datums, 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, LOOP_RC_PROCESSING, PinPortal(), PLPGSQL_DTYPE_REC, PLPGSQL_RC_OK, PLpgSQL_rec::rectypeid, SPI_cursor_fetch(), SPI_freetuptable(), SPI_processed, SPI_tuptable, stmt, TupleDescData::tdtypeid, SPITupleTable::tupdesc, UnpinPortal(), and SPITupleTable::vals.

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

◆ exec_init_tuple_store()

static void exec_init_tuple_store ( PLpgSQL_execstate estate)
static

Definition at line 3667 of file pl_exec.c.

3668 {
3669  ReturnSetInfo *rsi = estate->rsi;
3670  MemoryContext oldcxt;
3671  ResourceOwner oldowner;
3672 
3673  /*
3674  * Check caller can handle a set result in the way we want
3675  */
3676  if (!rsi || !IsA(rsi, ReturnSetInfo))
3677  ereport(ERROR,
3678  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3679  errmsg("set-valued function called in context that cannot accept a set")));
3680 
3681  if (!(rsi->allowedModes & SFRM_Materialize) ||
3682  rsi->expectedDesc == NULL)
3683  ereport(ERROR,
3684  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3685  errmsg("materialize mode required, but it is not allowed in this context")));
3686 
3687  /*
3688  * Switch to the right memory context and resource owner for storing the
3689  * tuplestore for return set. If we're within a subtransaction opened for
3690  * an exception-block, for example, we must still create the tuplestore in
3691  * the resource owner that was active when this function was entered, and
3692  * not in the subtransaction resource owner.
3693  */
3694  oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
3695  oldowner = CurrentResourceOwner;
3697 
3698  estate->tuple_store =
3700  false, work_mem);
3701 
3702  CurrentResourceOwner = oldowner;
3703  MemoryContextSwitchTo(oldcxt);
3704 
3705  estate->tuple_store_desc = rsi->expectedDesc;
3706 }
@ SFRM_Materialize_Random
Definition: execnodes.h:321
@ SFRM_Materialize
Definition: execnodes.h:320
int work_mem
Definition: globals.c:130
Tuplestorestate * tuple_store
Definition: plpgsql.h:1043
MemoryContext tuple_store_cxt
Definition: plpgsql.h:1045
TupleDesc tuple_store_desc
Definition: plpgsql.h:1044
ReturnSetInfo * rsi
Definition: plpgsql.h:1047
ResourceOwner tuple_store_owner
Definition: plpgsql.h:1046
TupleDesc expectedDesc
Definition: execnodes.h:336
int allowedModes
Definition: execnodes.h:337
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:330

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

◆ exec_is_simple_query()

static bool exec_is_simple_query ( PLpgSQL_expr expr)
static

Definition at line 8050 of file pl_exec.c.

8051 {
8052  List *plansources;
8053  CachedPlanSource *plansource;
8054  Query *query;
8055 
8056  /*
8057  * We can only test queries that resulted in exactly one CachedPlanSource.
8058  */
8059  plansources = SPI_plan_get_plan_sources(expr->plan);
8060  if (list_length(plansources) != 1)
8061  return false;
8062  plansource = (CachedPlanSource *) linitial(plansources);
8063 
8064  /*
8065  * 1. There must be one single querytree.
8066  */
8067  if (list_length(plansource->query_list) != 1)
8068  return false;
8069  query = (Query *) linitial(plansource->query_list);
8070 
8071  /*
8072  * 2. It must be a plain SELECT query without any input tables.
8073  */
8074  if (!IsA(query, Query))
8075  return false;
8076  if (query->commandType != CMD_SELECT)
8077  return false;
8078  if (query->rtable != NIL)
8079  return false;
8080 
8081  /*
8082  * 3. Can't have any subplans, aggregates, qual clauses either. (These
8083  * tests should generally match what inline_function() checks before
8084  * inlining a SQL function; otherwise, inlining could change our
8085  * conclusion about whether an expression is simple, which we don't want.)
8086  */
8087  if (query->hasAggs ||
8088  query->hasWindowFuncs ||
8089  query->hasTargetSRFs ||
8090  query->hasSubLinks ||
8091  query->cteList ||
8092  query->jointree->fromlist ||
8093  query->jointree->quals ||
8094  query->groupClause ||
8095  query->groupingSets ||
8096  query->havingQual ||
8097  query->windowClause ||
8098  query->distinctClause ||
8099  query->sortClause ||
8100  query->limitOffset ||
8101  query->limitCount ||
8102  query->setOperations)
8103  return false;
8104 
8105  /*
8106  * 4. The query must have a single attribute as result.
8107  */
8108  if (list_length(query->targetList) != 1)
8109  return false;
8110 
8111  /*
8112  * OK, we can treat it as a simple plan.
8113  */
8114  return true;
8115 }
@ CMD_SELECT
Definition: nodes.h:265
#define linitial(l)
Definition: pg_list.h:178
List * SPI_plan_get_plan_sources(SPIPlanPtr plan)
Definition: spi.c:2057
List * query_list
Definition: plancache.h:111
Node * quals
Definition: primnodes.h:2309
List * fromlist
Definition: primnodes.h:2308
Node * limitCount
Definition: parsenodes.h:216
FromExpr * jointree
Definition: parsenodes.h:177
Node * setOperations
Definition: parsenodes.h:221
List * cteList
Definition: parsenodes.h:168
List * groupClause
Definition: parsenodes.h:202
Node * havingQual
Definition: parsenodes.h:207
List * rtable
Definition: parsenodes.h:170
Node * limitOffset
Definition: parsenodes.h:215
CmdType commandType
Definition: parsenodes.h:121
List * windowClause
Definition: parsenodes.h:209
List * targetList
Definition: parsenodes.h:193
List * groupingSets
Definition: parsenodes.h:205
List * distinctClause
Definition: parsenodes.h:211
List * sortClause
Definition: parsenodes.h:213

References CMD_SELECT, Query::commandType, Query::cteList, Query::distinctClause, FromExpr::fromlist, Query::groupClause, Query::groupingSets, Query::havingQual, IsA, Query::jointree, Query::limitCount, Query::limitOffset, linitial, list_length(), NIL, PLpgSQL_expr::plan, FromExpr::quals, CachedPlanSource::query_list, Query::rtable, Query::setOperations, Query::sortClause, SPI_plan_get_plan_sources(), Query::targetList, and Query::windowClause.

Referenced by exec_eval_simple_expr(), and exec_simple_check_plan().

◆ exec_move_row()

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

Definition at line 6749 of file pl_exec.c.

6752 {
6753  ExpandedRecordHeader *newerh = NULL;
6754 
6755  /*
6756  * If target is RECORD, we may be able to avoid field-by-field processing.
6757  */
6758  if (target->dtype == PLPGSQL_DTYPE_REC)
6759  {
6760  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
6761 
6762  /*
6763  * If we have no source tupdesc, just set the record variable to NULL.
6764  * (If we have a source tupdesc but not a tuple, we'll set the
6765  * variable to a row of nulls, instead. This is odd perhaps, but
6766  * backwards compatible.)
6767  */
6768  if (tupdesc == NULL)
6769  {
6770  if (rec->datatype &&
6771  rec->datatype->typtype == TYPTYPE_DOMAIN)
6772  {
6773  /*
6774  * If it's a composite domain, NULL might not be a legal
6775  * value, so we instead need to make an empty expanded record
6776  * and ensure that domain type checking gets done. If there
6777  * is already an expanded record, piggyback on its lookups.
6778  */
6779  newerh = make_expanded_record_for_rec(estate, rec,
6780  NULL, rec->erh);
6781  expanded_record_set_tuple(newerh, NULL, false, false);
6782  assign_record_var(estate, rec, newerh);
6783  }
6784  else
6785  {
6786  /* Just clear it to NULL */
6787  if (rec->erh)
6789  rec->erh = NULL;
6790  }
6791  return;
6792  }
6793 
6794  /*
6795  * Build a new expanded record with appropriate tupdesc.
6796  */
6797  newerh = make_expanded_record_for_rec(estate, rec, tupdesc, NULL);
6798 
6799  /*
6800  * If the rowtypes match, or if we have no tuple anyway, we can
6801  * complete the assignment without field-by-field processing.
6802  *
6803  * The tests here are ordered more or less in order of cheapness. We
6804  * can easily detect it will work if the target is declared RECORD or
6805  * has the same typeid as the source. But when assigning from a query
6806  * result, it's common to have a source tupdesc that's labeled RECORD
6807  * but is actually physically compatible with a named-composite-type
6808  * target, so it's worth spending extra cycles to check for that.
6809  */
6810  if (rec->rectypeid == RECORDOID ||
6811  rec->rectypeid == tupdesc->tdtypeid ||
6812  !HeapTupleIsValid(tup) ||
6814  {
6815  if (!HeapTupleIsValid(tup))
6816  {
6817  /* No data, so force the record into all-nulls state */
6819  }
6820  else
6821  {
6822  /* No coercion is needed, so just assign the row value */
6823  expanded_record_set_tuple(newerh, tup, true, !estate->atomic);
6824  }
6825 
6826  /* Complete the assignment */
6827  assign_record_var(estate, rec, newerh);
6828 
6829  return;
6830  }
6831  }
6832 
6833  /*
6834  * Otherwise, deconstruct the tuple and do field-by-field assignment,
6835  * using exec_move_row_from_fields.
6836  */
6837  if (tupdesc && HeapTupleIsValid(tup))
6838  {
6839  int td_natts = tupdesc->natts;
6840  Datum *values;
6841  bool *nulls;
6842  Datum values_local[64];
6843  bool nulls_local[64];
6844 
6845  /*
6846  * Need workspace arrays. If td_natts is small enough, use local
6847  * arrays to save doing a palloc. Even if it's not small, we can
6848  * allocate both the Datum and isnull arrays in one palloc chunk.
6849  */
6850  if (td_natts <= lengthof(values_local))
6851  {
6852  values = values_local;
6853  nulls = nulls_local;
6854  }
6855  else
6856  {
6857  char *chunk;
6858 
6859  chunk = eval_mcontext_alloc(estate,
6860  td_natts * (sizeof(Datum) + sizeof(bool)));
6861  values = (Datum *) chunk;
6862  nulls = (bool *) (chunk + td_natts * sizeof(Datum));
6863  }
6864 
6865  heap_deform_tuple(tup, tupdesc, values, nulls);
6866 
6867  exec_move_row_from_fields(estate, target, newerh,
6868  values, nulls, tupdesc);
6869  }
6870  else
6871  {
6872  /*
6873  * Assign all-nulls.
6874  */
6875  exec_move_row_from_fields(estate, target, newerh,
6876  NULL, NULL, NULL);
6877  }
6878 }
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define lengthof(array)
Definition: c.h:793
void deconstruct_expanded_record(ExpandedRecordHeader *erh)
uint64 chunk
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1345
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define eval_mcontext_alloc(estate, sz)
Definition: pl_exec.c:128
static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
Definition: pl_exec.c:8627
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:7027
static ExpandedRecordHeader * make_expanded_record_for_rec(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, TupleDesc srctupdesc, ExpandedRecordHeader *srcerh)
Definition: pl_exec.c:6964
PLpgSQL_type * datatype
Definition: plpgsql.h:406
char typtype
Definition: plpgsql.h:205

References assign_record_var(), PLpgSQL_execstate::atomic, chunk, 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().

◆ exec_move_row_from_datum()

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

Definition at line 7423 of file pl_exec.c.

7426 {
7427  /* Check to see if source is an expanded record */
7429  {
7431  ExpandedRecordHeader *newerh = NULL;
7432 
7433  Assert(erh->er_magic == ER_MAGIC);
7434 
7435  /* These cases apply if the target is record not row... */
7436  if (target->dtype == PLPGSQL_DTYPE_REC)
7437  {
7438  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7439 
7440  /*
7441  * If it's the same record already stored in the variable, do
7442  * nothing. This would happen only in silly cases like "r := r",
7443  * but we need some check to avoid possibly freeing the variable's
7444  * live value below. Note that this applies even if what we have
7445  * is a R/O pointer.
7446  */
7447  if (erh == rec->erh)
7448  return;
7449 
7450  /*
7451  * Make sure rec->rectypeid is up-to-date before using it.
7452  */
7453  revalidate_rectypeid(rec);
7454 
7455  /*
7456  * If we have a R/W pointer, we're allowed to just commandeer
7457  * ownership of the expanded record. If it's of the right type to
7458  * put into the record variable, do that. (Note we don't accept
7459  * an expanded record of a composite-domain type as a RECORD
7460  * value. We'll treat it as the base composite type instead;
7461  * compare logic in make_expanded_record_for_rec.)
7462  */
7464  (rec->rectypeid == erh->er_decltypeid ||
7465  (rec->rectypeid == RECORDOID &&
7466  !ExpandedRecordIsDomain(erh))))
7467  {
7468  assign_record_var(estate, rec, erh);
7469  return;
7470  }
7471 
7472  /*
7473  * If we already have an expanded record object in the target
7474  * variable, and the source record contains a valid tuple
7475  * representation with the right rowtype, then we can skip making
7476  * a new expanded record and just assign the tuple with
7477  * expanded_record_set_tuple. (We can't do the equivalent if we
7478  * have to do field-by-field assignment, since that wouldn't be
7479  * atomic if there's an error.) We consider that there's a
7480  * rowtype match only if it's the same named composite type or
7481  * same registered rowtype; checking for matches of anonymous
7482  * rowtypes would be more expensive than this is worth.
7483  */
7484  if (rec->erh &&
7485  (erh->flags & ER_FLAG_FVALUE_VALID) &&
7486  erh->er_typeid == rec->erh->er_typeid &&
7487  (erh->er_typeid != RECORDOID ||
7488  (erh->er_typmod == rec->erh->er_typmod &&
7489  erh->er_typmod >= 0)))
7490  {
7492  true, !estate->atomic);
7493  return;
7494  }
7495 
7496  /*
7497  * Otherwise we're gonna need a new expanded record object. Make
7498  * it here in hopes of piggybacking on the source object's
7499  * previous typcache lookup.
7500  */
7501  newerh = make_expanded_record_for_rec(estate, rec, NULL, erh);
7502 
7503  /*
7504  * If the expanded record contains a valid tuple representation,
7505  * and we don't need rowtype conversion, then just copying the
7506  * tuple is probably faster than field-by-field processing. (This
7507  * isn't duplicative of the previous check, since here we will
7508  * catch the case where the record variable was previously empty.)
7509  */
7510  if ((erh->flags & ER_FLAG_FVALUE_VALID) &&
7511  (rec->rectypeid == RECORDOID ||
7512  rec->rectypeid == erh->er_typeid))
7513  {
7514  expanded_record_set_tuple(newerh, erh->fvalue,
7515  true, !estate->atomic);
7516  assign_record_var(estate, rec, newerh);
7517  return;
7518  }
7519 
7520  /*
7521  * Need to special-case empty source record, else code below would
7522  * leak newerh.
7523  */
7524  if (ExpandedRecordIsEmpty(erh))
7525  {
7526  /* Set newerh to a row of NULLs */
7528  assign_record_var(estate, rec, newerh);
7529  return;
7530  }
7531  } /* end of record-target-only cases */
7532 
7533  /*
7534  * If the source expanded record is empty, we should treat that like a
7535  * NULL tuple value. (We're unlikely to see such a case, but we must
7536  * check this; deconstruct_expanded_record would cause a change of
7537  * logical state, which is not OK.)
7538  */
7539  if (ExpandedRecordIsEmpty(erh))
7540  {
7541  exec_move_row(estate, target, NULL,
7543  return;
7544  }
7545 
7546  /*
7547  * Otherwise, ensure that the source record is deconstructed, and
7548  * assign from its field values.
7549  */
7551  exec_move_row_from_fields(estate, target, newerh,
7552  erh->dvalues, erh->dnulls,
7554  }
7555  else
7556  {
7557  /*
7558  * Nope, we've got a plain composite Datum. Deconstruct it; but we
7559  * don't use deconstruct_composite_datum(), because we may be able to
7560  * skip calling lookup_rowtype_tupdesc().
7561  */
7562  HeapTupleHeader td;
7563  HeapTupleData tmptup;
7564  Oid tupType;
7565  int32 tupTypmod;
7566  TupleDesc tupdesc;
7567  MemoryContext oldcontext;
7568 
7569  /* Ensure that any detoasted data winds up in the eval_mcontext */
7570  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7571  /* Get tuple body (note this could involve detoasting) */
7573  MemoryContextSwitchTo(oldcontext);
7574 
7575  /* Build a temporary HeapTuple control structure */
7576  tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
7577  ItemPointerSetInvalid(&(tmptup.t_self));
7578  tmptup.t_tableOid = InvalidOid;
7579  tmptup.t_data = td;
7580 
7581  /* Extract rowtype info */
7582  tupType = HeapTupleHeaderGetTypeId(td);
7583  tupTypmod = HeapTupleHeaderGetTypMod(td);
7584 
7585  /* Now, if the target is record not row, maybe we can optimize ... */
7586  if (target->dtype == PLPGSQL_DTYPE_REC)
7587  {
7588  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7589 
7590  /*
7591  * If we already have an expanded record object in the target
7592  * variable, and the source datum has a matching rowtype, then we
7593  * can skip making a new expanded record and just assign the tuple
7594  * with expanded_record_set_tuple. We consider that there's a
7595  * rowtype match only if it's the same named composite type or
7596  * same registered rowtype. (Checking to reject an anonymous
7597  * rowtype here should be redundant, but let's be safe.)
7598  */
7599  if (rec->erh &&
7600  tupType == rec->erh->er_typeid &&
7601  (tupType != RECORDOID ||
7602  (tupTypmod == rec->erh->er_typmod &&
7603  tupTypmod >= 0)))
7604  {
7605  expanded_record_set_tuple(rec->erh, &tmptup,
7606  true, !estate->atomic);
7607  return;
7608  }
7609 
7610  /*
7611  * If the source datum has a rowtype compatible with the target
7612  * variable, just build a new expanded record and assign the tuple
7613  * into it. Using make_expanded_record_from_typeid() here saves
7614  * one typcache lookup compared to the code below.
7615  */
7616  if (rec->rectypeid == RECORDOID || rec->rectypeid == tupType)
7617  {
7618  ExpandedRecordHeader *newerh;
7619  MemoryContext mcontext = get_eval_mcontext(estate);
7620 
7621  newerh = make_expanded_record_from_typeid(tupType, tupTypmod,
7622  mcontext);
7623  expanded_record_set_tuple(newerh, &tmptup,
7624  true, !estate->atomic);
7625  assign_record_var(estate, rec, newerh);
7626  return;
7627  }
7628 
7629  /*
7630  * Otherwise, we're going to need conversion, so fall through to
7631  * do it the hard way.
7632  */
7633  }
7634 
7635  /*
7636  * ROW target, or unoptimizable RECORD target, so we have to expend a
7637  * lookup to obtain the source datum's tupdesc.
7638  */
7639  tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
7640 
7641  /* Do the move */
7642  exec_move_row(estate, target, &tmptup, tupdesc);
7643 
7644  /* Release tupdesc usage count */
7645  ReleaseTupleDesc(tupdesc);
7646  }
7647 }
ExpandedRecordHeader * make_expanded_record_from_typeid(Oid type_id, int32 typmod, MemoryContext parentcontext)
#define ER_FLAG_FVALUE_VALID
static void revalidate_rectypeid(PLpgSQL_rec *rec)
Definition: pl_exec.c:6884

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, value, VARATT_IS_EXTERNAL_EXPANDED, and VARATT_IS_EXTERNAL_EXPANDED_RW.

Referenced by exec_assign_value(), and plpgsql_exec_function().

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

7032 {
7033  int td_natts = tupdesc ? tupdesc->natts : 0;
7034  int fnum;
7035  int anum;
7036  int strict_multiassignment_level = 0;
7037 
7038  /*
7039  * The extra check strict strict_multi_assignment can be active, only when
7040  * input tupdesc is specified.
7041  */
7042  if (tupdesc != NULL)
7043  {
7045  strict_multiassignment_level = ERROR;
7047  strict_multiassignment_level = WARNING;
7048  }
7049 
7050  /* Handle RECORD-target case */
7051  if (target->dtype == PLPGSQL_DTYPE_REC)
7052  {
7053  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7054  TupleDesc var_tupdesc;
7055  Datum newvalues_local[64];
7056  bool newnulls_local[64];
7057 
7058  Assert(newerh != NULL); /* caller must have built new object */
7059 
7060  var_tupdesc = expanded_record_get_tupdesc(newerh);
7061 
7062  /*
7063  * Coerce field values if needed. This might involve dealing with
7064  * different sets of dropped columns and/or coercing individual column
7065  * types. That's sort of a pain, but historically plpgsql has allowed
7066  * it, so we preserve the behavior. However, it's worth a quick check
7067  * to see if the tupdescs are identical. (Since expandedrecord.c
7068  * prefers to use refcounted tupdescs from the typcache, expanded
7069  * records with the same rowtype will have pointer-equal tupdescs.)
7070  */
7071  if (var_tupdesc != tupdesc)
7072  {
7073  int vtd_natts = var_tupdesc->natts;
7074  Datum *newvalues;
7075  bool *newnulls;
7076 
7077  /*
7078  * Need workspace arrays. If vtd_natts is small enough, use local
7079  * arrays to save doing a palloc. Even if it's not small, we can
7080  * allocate both the Datum and isnull arrays in one palloc chunk.
7081  */
7082  if (vtd_natts <= lengthof(newvalues_local))
7083  {
7084  newvalues = newvalues_local;
7085  newnulls = newnulls_local;
7086  }
7087  else
7088  {
7089  char *chunk;
7090 
7091  chunk = eval_mcontext_alloc(estate,
7092  vtd_natts * (sizeof(Datum) + sizeof(bool)));
7093  newvalues = (Datum *) chunk;
7094  newnulls = (bool *) (chunk + vtd_natts * sizeof(Datum));
7095  }
7096 
7097  /* Walk over destination columns */
7098  anum = 0;
7099  for (fnum = 0; fnum < vtd_natts; fnum++)
7100  {
7101  Form_pg_attribute attr = TupleDescAttr(var_tupdesc, fnum);
7102  Datum value;
7103  bool isnull;
7104  Oid valtype;
7105  int32 valtypmod;
7106 
7107  if (attr->attisdropped)
7108  {
7109  /* expanded_record_set_fields should ignore this column */
7110  continue; /* skip dropped column in record */
7111  }
7112 
7113  while (anum < td_natts &&
7114  TupleDescAttr(tupdesc, anum)->attisdropped)
7115  anum++; /* skip dropped column in tuple */
7116 
7117  if (anum < td_natts)
7118  {
7119  value = values[anum];
7120  isnull = nulls[anum];
7121  valtype = TupleDescAttr(tupdesc, anum)->atttypid;
7122  valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
7123  anum++;
7124  }
7125  else
7126  {
7127  /* no source for destination column */
7128  value = (Datum) 0;
7129  isnull = true;
7130  valtype = UNKNOWNOID;
7131  valtypmod = -1;
7132 
7133  /* When source value is missing */
7134  if (strict_multiassignment_level)
7135  ereport(strict_multiassignment_level,
7136  (errcode(ERRCODE_DATATYPE_MISMATCH),
7137  errmsg("number of source and target fields in assignment does not match"),
7138  /* translator: %s represents a name of an extra check */
7139  errdetail("%s check of %s is active.",
7140  "strict_multi_assignment",
7141  strict_multiassignment_level == ERROR ? "extra_errors" :
7142  "extra_warnings"),
7143  errhint("Make sure the query returns the exact list of columns.")));
7144  }
7145 
7146  /* Cast the new value to the right type, if needed. */
7147  newvalues[fnum] = exec_cast_value(estate,
7148  value,
7149  &isnull,
7150  valtype,
7151  valtypmod,
7152  attr->atttypid,
7153  attr->atttypmod);
7154  newnulls[fnum] = isnull;
7155  }
7156 
7157  /*
7158  * When strict_multiassignment extra check is active, then ensure
7159  * there are no unassigned source attributes.
7160  */
7161  if (strict_multiassignment_level && anum < td_natts)
7162  {
7163  /* skip dropped columns in the source descriptor */
7164  while (anum < td_natts &&
7165  TupleDescAttr(tupdesc, anum)->attisdropped)
7166  anum++;
7167 
7168  if (anum < td_natts)
7169  ereport(strict_multiassignment_level,
7170  (errcode(ERRCODE_DATATYPE_MISMATCH),
7171  errmsg("number of source and target fields in assignment does not match"),
7172  /* translator: %s represents a name of an extra check */
7173  errdetail("%s check of %s is active.",
7174  "strict_multi_assignment",
7175  strict_multiassignment_level == ERROR ? "extra_errors" :
7176  "extra_warnings"),
7177  errhint("Make sure the query returns the exact list of columns.")));
7178  }
7179 
7180  values = newvalues;
7181  nulls = newnulls;
7182  }
7183 
7184  /* Insert the coerced field values into the new expanded record */
7185  expanded_record_set_fields(newerh, values, nulls, !estate->atomic);
7186 
7187  /* Complete the assignment */
7188  assign_record_var(estate, rec, newerh);
7189 
7190  return;
7191  }
7192 
7193  /* newerh should not have been passed in non-RECORD cases */
7194  Assert(newerh == NULL);
7195 
7196  /*
7197  * For a row, we assign the individual field values to the variables the
7198  * row points to.
7199  *
7200  * NOTE: both this code and the record code above silently ignore extra
7201  * columns in the source and assume NULL for missing columns. This is
7202  * pretty dubious but it's the historical behavior.
7203  *
7204  * If we have no input data at all, we'll assign NULL to all columns of
7205  * the row variable.
7206  */
7207  if (target->dtype == PLPGSQL_DTYPE_ROW)
7208  {
7209  PLpgSQL_row *row = (PLpgSQL_row *) target;
7210 
7211  anum = 0;
7212  for (fnum = 0; fnum < row->nfields; fnum++)
7213  {
7214  PLpgSQL_var *var;
7215  Datum value;
7216  bool isnull;
7217  Oid valtype;
7218  int32 valtypmod;
7219 
7220  var = (PLpgSQL_var *) (estate->datums[row->varnos[fnum]]);
7221 
7222  while (anum < td_natts &&
7223  TupleDescAttr(tupdesc, anum)->attisdropped)
7224  anum++; /* skip dropped column in tuple */
7225 
7226  if (anum < td_natts)
7227  {
7228  value = values[anum];
7229  isnull = nulls[anum];
7230  valtype = TupleDescAttr(tupdesc, anum)->atttypid;
7231  valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
7232  anum++;
7233  }
7234  else
7235  {
7236  /* no source for destination column */
7237  value = (Datum) 0;
7238  isnull = true;
7239  valtype = UNKNOWNOID;
7240  valtypmod = -1;
7241 
7242  if (strict_multiassignment_level)
7243  ereport(strict_multiassignment_level,
7244  (errcode(ERRCODE_DATATYPE_MISMATCH),
7245  errmsg("number of source and target fields in assignment does not match"),
7246  /* translator: %s represents a name of an extra check */
7247  errdetail("%s check of %s is active.",
7248  "strict_multi_assignment",
7249  strict_multiassignment_level == ERROR ? "extra_errors" :
7250  "extra_warnings"),
7251  errhint("Make sure the query returns the exact list of columns.")));
7252  }
7253 
7254  exec_assign_value(estate, (PLpgSQL_datum *) var,
7255  value, isnull, valtype, valtypmod);
7256  }
7257 
7258  /*
7259  * When strict_multiassignment extra check is active, ensure there are
7260  * no unassigned source attributes.
7261  */
7262  if (strict_multiassignment_level && anum < td_natts)
7263  {
7264  while (anum < td_natts &&
7265  TupleDescAttr(tupdesc, anum)->attisdropped)
7266  anum++; /* skip dropped column in tuple */
7267 
7268  if (anum < td_natts)
7269  ereport(strict_multiassignment_level,
7270  (errcode(ERRCODE_DATATYPE_MISMATCH),
7271  errmsg("number of source and target fields in assignment does not match"),
7272  /* translator: %s represents a name of an extra check */
7273  errdetail("%s check of %s is active.",
7274  "strict_multi_assignment",
7275  strict_multiassignment_level == ERROR ? "extra_errors" :
7276  "extra_warnings"),
7277  errhint("Make sure the query returns the exact list of columns.")));
7278  }
7279 
7280  return;
7281  }
7282 
7283  elog(ERROR, "unsupported target type: %d", target->dtype);
7284 }
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errhint(const char *fmt,...)
Definition: elog.c:1317
#define WARNING
Definition: elog.h:36
void expanded_record_set_fields(ExpandedRecordHeader *erh, const Datum *newValues, const bool *isnulls, bool expand_external)
int plpgsql_extra_warnings
Definition: pl_handler.c:52
int plpgsql_extra_errors
Definition: pl_handler.c:53
#define PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT
Definition: plpgsql.h:1206
int * varnos
Definition: plpgsql.h:383
int nfields
Definition: plpgsql.h:381

References Assert, assign_record_var(), PLpgSQL_execstate::atomic, chunk, 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, values, PLpgSQL_row::varnos, and WARNING.

Referenced by exec_move_row(), and exec_move_row_from_datum().

◆ exec_prepare_plan()

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

Definition at line 4171 of file pl_exec.c.

4173 {
4174  SPIPlanPtr plan;
4176 
4177  /*
4178  * The grammar can't conveniently set expr->func while building the parse
4179  * tree, so make sure it's set before parser hooks need it.
4180  */
4181  expr->func = estate->func;
4182 
4183  /*
4184  * Generate and save the plan
4185  */
4186  memset(&options, 0, sizeof(options));
4188  options.parserSetupArg = (void *) expr;
4189  options.parseMode = expr->parseMode;
4190  options.cursorOptions = cursorOptions;
4192  if (plan == NULL)
4193  elog(ERROR, "SPI_prepare_extended failed for \"%s\": %s",
4195 
4196  SPI_keepplan(plan);
4197  expr->plan = plan;
4198 
4199  /* Check to see if it's a simple expression */
4200  exec_simple_check_plan(estate, expr);
4201 }
void(* ParserSetupHook)(struct ParseState *pstate, void *arg)
Definition: params.h:108
#define plan(x)
Definition: pg_regress.c:161
void plpgsql_parser_setup(struct ParseState *pstate, PLpgSQL_expr *expr)
Definition: pl_comp.c:1076
static void exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:7979
SPIPlanPtr SPI_prepare_extended(const char *src, const SPIPrepareOptions *options)
Definition: spi.c:902
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:976
PLpgSQL_function * func
Definition: plpgsql.h:1023
RawParseMode parseMode
Definition: plpgsql.h:221
struct PLpgSQL_function * func
Definition: plpgsql.h:226

References elog, ERROR, exec_simple_check_plan(), PLpgSQL_expr::func, PLpgSQL_execstate::func, options, PLpgSQL_expr::parseMode, PLpgSQL_expr::plan, 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().

◆ exec_run_select()

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

Definition at line 5767 of file pl_exec.c.

5769 {
5770  ParamListInfo paramLI;
5771  int rc;
5772 
5773  /*
5774  * On the first call for this expression generate the plan.
5775  *
5776  * If we don't need to return a portal, then we're just going to execute
5777  * the query immediately, which means it's OK to use a parallel plan, even
5778  * if the number of rows being fetched is limited. If we do need to
5779  * return a portal (i.e., this is for a FOR loop), the user's code might
5780  * invoke additional operations inside the FOR loop, making parallel query
5781  * unsafe. In any case, we don't expect any cursor operations to be done,
5782  * so specify NO_SCROLL for efficiency and semantic safety.
5783  */
5784  if (expr->plan == NULL)
5785  {
5786  int cursorOptions = CURSOR_OPT_NO_SCROLL;
5787 
5788  if (portalP == NULL)
5789  cursorOptions |= CURSOR_OPT_PARALLEL_OK;
5790  exec_prepare_plan(estate, expr, cursorOptions);
5791  }
5792 
5793  /*
5794  * Set up ParamListInfo to pass to executor
5795  */
5796  paramLI = setup_param_list(estate, expr);
5797 
5798  /*
5799  * If a portal was requested, put the query and paramlist into the portal
5800  */
5801  if (portalP != NULL)
5802  {
5803  *portalP = SPI_cursor_open_with_paramlist(NULL, expr->plan,
5804  paramLI,
5805  estate->readonly_func);
5806  if (*portalP == NULL)
5807  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
5809  exec_eval_cleanup(estate);
5810  return SPI_OK_CURSOR;
5811  }
5812 
5813  /*
5814  * Execute the query
5815  */
5816  rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
5817  estate->readonly_func, maxtuples);
5818  if (rc != SPI_OK_SELECT)
5819  {
5820  /*
5821  * SELECT INTO deserves a special error message, because "query is not
5822  * a SELECT" is not very helpful in that case.
5823  */
5824  if (rc == SPI_OK_SELINTO)
5825  ereport(ERROR,
5826  (errcode(ERRCODE_SYNTAX_ERROR),
5827  errmsg("query is SELECT INTO, but it should be plain SELECT"),
5828  errcontext("query: %s", expr->query)));
5829  else
5830  ereport(ERROR,
5831  (errcode(ERRCODE_SYNTAX_ERROR),
5832  errmsg("query is not a SELECT"),
5833  errcontext("query: %s", expr->query)));
5834  }
5835 
5836  /* Save query results for eventual cleanup */
5837  Assert(estate->eval_tuptable == NULL);
5838  estate->eval_tuptable = SPI_tuptable;
5839  estate->eval_processed = SPI_processed;
5840 
5841  return rc;
5842 }
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:3309
static ParamListInfo setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:6261
int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params, bool read_only, long tcount)
Definition: spi.c:733
Portal SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan, ParamListInfo params, bool read_only)
Definition: spi.c:1525
#define SPI_OK_CURSOR
Definition: spi.h:91
#define SPI_OK_SELINTO
Definition: spi.h:87

References Assert, CURSOR_OPT_NO_SCROLL, CURSOR_OPT_PARALLEL_OK, elog, ereport, errcode(), errcontext, 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_OK_SELINTO, SPI_processed, SPI_result, SPI_result_code_string(), and SPI_tuptable.

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

◆ exec_save_simple_expr()

static void exec_save_simple_expr ( PLpgSQL_expr expr,
CachedPlan cplan 
)
static

Definition at line 8121 of file pl_exec.c.

8122 {
8123  PlannedStmt *stmt;
8124  Plan *plan;
8125  Expr *tle_expr;
8126 
8127  /*
8128  * Given the checks that exec_simple_check_plan did, none of the Asserts
8129  * here should ever fail.
8130  */
8131 
8132  /* Extract the single PlannedStmt */
8133  Assert(list_length(cplan->stmt_list) == 1);
8135  Assert(stmt->commandType == CMD_SELECT);
8136 
8137  /*
8138  * Ordinarily, the plan node should be a simple Result. However, if
8139  * debug_parallel_query is on, the planner might've stuck a Gather node
8140  * atop that. The simplest way to deal with this is to look through the
8141  * Gather node. The Gather node's tlist would normally contain a Var
8142  * referencing the child node's output, but it could also be a Param, or
8143  * it could be a Const that setrefs.c copied as-is.
8144  */
8145  plan = stmt->planTree;
8146  for (;;)
8147  {
8148  /* Extract the single tlist expression */
8149  Assert(list_length(plan->targetlist) == 1);
8150  tle_expr = linitial_node(TargetEntry, plan->targetlist)->expr;
8151 
8152  if (IsA(plan, Result))
8153  {
8154  Assert(plan->lefttree == NULL &&
8155  plan->righttree == NULL &&
8156  plan->initPlan == NULL &&
8157  plan->qual == NULL &&
8158  ((Result *) plan)->resconstantqual == NULL);
8159  break;
8160  }
8161  else if (IsA(plan, Gather))
8162  {
8163  Assert(plan->lefttree != NULL &&
8164  plan->righttree == NULL &&
8165  plan->initPlan == NULL &&
8166  plan->qual == NULL);
8167  /* If setrefs.c copied up a Const, no need to look further */
8168  if (IsA(tle_expr, Const))
8169  break;
8170  /* Otherwise, it had better be a Param or an outer Var */
8171  Assert(IsA(tle_expr, Param) || (IsA(tle_expr, Var) &&
8172  ((Var *) tle_expr)->varno == OUTER_VAR));
8173  /* Descend to the child node */
8174  plan = plan->lefttree;
8175  }
8176  else
8177  elog(ERROR, "unexpected plan node type: %d",
8178  (int) nodeTag(plan));
8179  }
8180 
8181  /*
8182  * Save the simple expression, and initialize state to "not valid in
8183  * current transaction".
8184  */
8185  expr->expr_simple_expr = tle_expr;
8186  expr->expr_simple_state = NULL;
8187  expr->expr_simple_in_use = false;
8189  /* Also stash away the expression result type */
8190  expr->expr_simple_type = exprType((Node *) tle_expr);
8191  expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
8192  /* We also want to remember if it is immutable or not */
8193  expr->expr_simple_mutable = contain_mutable_functions((Node *) tle_expr);
8194 
8195  /*
8196  * Lastly, check to see if there's a possibility of optimizing a
8197  * read/write parameter.
8198  */
8200 }
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:370
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:298
#define nodeTag(nodeptr)
Definition: nodes.h:133
#define linitial_node(type, l)
Definition: pg_list.h:181
static void exec_check_rw_parameter(PLpgSQL_expr *expr)
Definition: pl_exec.c:8228
#define OUTER_VAR
Definition: primnodes.h:237
List * stmt_list
Definition: plancache.h:150
Definition: primnodes.h:248

References Assert, CMD_SELECT, 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(), InvalidLocalTransactionId, IsA, linitial_node, list_length(), nodeTag, OUTER_VAR, plan, stmt, and CachedPlan::stmt_list.

Referenced by exec_eval_simple_expr(), and exec_simple_check_plan().

◆ exec_set_found()

static void exec_set_found ( PLpgSQL_execstate estate,
bool  state 
)
static

Definition at line 8375 of file pl_exec.c.

8376 {
8377  PLpgSQL_var *var;
8378 
8379  var = (PLpgSQL_var *) (estate->datums[estate->found_varno]);
8380  assign_simple_var(estate, var, BoolGetDatum(state), false, false);
8381 }
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
Definition: regguts.h:323

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

◆ exec_simple_check_plan()

static void exec_simple_check_plan ( PLpgSQL_execstate estate,
PLpgSQL_expr expr 
)
static

Definition at line 7979 of file pl_exec.c.

7980 {
7981  List *plansources;
7982  CachedPlanSource *plansource;
7983  CachedPlan *cplan;
7984  MemoryContext oldcontext;
7985 
7986  /*
7987  * Initialize to "not simple".
7988  */
7989  expr->expr_simple_expr = NULL;
7990  expr->expr_rw_param = NULL;
7991 
7992  /*
7993  * Check the analyzed-and-rewritten form of the query to see if we will be
7994  * able to treat it as a simple expression. Since this function is only
7995  * called immediately after creating the CachedPlanSource, we need not
7996  * worry about the query being stale.
7997  */
7998  if (!exec_is_simple_query(expr))
7999  return;
8000 
8001  /* exec_is_simple_query verified that there's just one CachedPlanSource */
8002  plansources = SPI_plan_get_plan_sources(expr->plan);
8003  plansource = (CachedPlanSource *) linitial(plansources);
8004 
8005  /*
8006  * Get the generic plan for the query. If replanning is needed, do that
8007  * work in the eval_mcontext. (Note that replanning could throw an error,
8008  * in which case the expr is left marked "not simple", which is fine.)
8009  */
8010  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
8011  cplan = SPI_plan_get_cached_plan(expr->plan);
8012  MemoryContextSwitchTo(oldcontext);
8013 
8014  /* Can't fail, because we checked for a single CachedPlanSource above */
8015  Assert(cplan != NULL);
8016 
8017  /*
8018  * Verify that plancache.c thinks the plan is simple enough to use
8019  * CachedPlanIsSimplyValid. Given the restrictions above, it's unlikely
8020  * that this could fail, but if it does, just treat plan as not simple. On
8021  * success, save a refcount on the plan in the simple-expression resowner.
8022  */
8023  if (CachedPlanAllowsSimpleValidityCheck(plansource, cplan,
8024  estate->simple_eval_resowner))
8025  {
8026  /* Remember that we have the refcount */
8027  expr->expr_simple_plansource = plansource;
8028  expr->expr_simple_plan = cplan;
8030 
8031  /* Share the remaining work with the replan code path */
8032  exec_save_simple_expr(expr, cplan);
8033  }
8034 
8035  /*
8036  * Release the plan refcount obtained by SPI_plan_get_cached_plan. (This
8037  * refcount is held by the wrong resowner, so we can't just repurpose it.)
8038  */
8040 }

References Assert, CachedPlanAllowsSimpleValidityCheck(), CurrentResourceOwner, exec_is_simple_query(), 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, get_eval_mcontext, linitial, PGPROC::lxid, MemoryContextSwitchTo(), MyProc, PLpgSQL_expr::plan, ReleaseCachedPlan(), PLpgSQL_execstate::simple_eval_resowner, SPI_plan_get_cached_plan(), SPI_plan_get_plan_sources(), and PGPROC::vxid.

Referenced by exec_prepare_plan().

◆ exec_stmt_assert()

static int exec_stmt_assert ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assert stmt 
)
static

Definition at line 3934 of file pl_exec.c.

3935 {
3936  bool value;
3937  bool isnull;
3938 
3939  /* do nothing when asserts are not enabled */
3940  if (!plpgsql_check_asserts)
3941  return PLPGSQL_RC_OK;
3942 
3943  value = exec_eval_boolean(estate, stmt->cond, &isnull);
3944  exec_eval_cleanup(estate);
3945 
3946  if (isnull || !value)
3947  {
3948  char *message = NULL;
3949 
3950  if (stmt->message != NULL)
3951  {
3952  Datum val;
3953  Oid typeid;
3954  int32 typmod;
3955 
3956  val = exec_eval_expr(estate, stmt->message,
3957  &isnull, &typeid, &typmod);
3958  if (!isnull)
3959  message = convert_value_to_string(estate, val, typeid);
3960  /* we mustn't do exec_eval_cleanup here */
3961  }
3962 
3963  ereport(ERROR,
3964  (errcode(ERRCODE_ASSERT_FAILURE),
3965  message ? errmsg_internal("%s", message) :
3966  errmsg("assertion failed")));
3967  }
3968 
3969  return PLPGSQL_RC_OK;
3970 }
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
long val
Definition: informix.c:689
static bool exec_eval_boolean(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
Definition: pl_exec.c:5660
bool plpgsql_check_asserts
Definition: pl_handler.c:48

References convert_value_to_string(), ereport, errcode(), errmsg(), errmsg_internal(), ERROR, exec_eval_boolean(), exec_eval_cleanup(), exec_eval_expr(), plpgsql_check_asserts, PLPGSQL_RC_OK, stmt, val, and value.

Referenced by exec_stmts().

◆ exec_stmt_assign()

static int exec_stmt_assign ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assign stmt 
)
static

Definition at line 2148 of file pl_exec.c.

2149 {
2150  Assert(stmt->varno >= 0);
2151 
2152  exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);
2153 
2154  return PLPGSQL_RC_OK;
2155 }
static void exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
Definition: pl_exec.c:5007

References Assert, PLpgSQL_execstate::datums, exec_assign_expr(), PLPGSQL_RC_OK, and stmt.

Referenced by exec_stmts().

◆ exec_stmt_block()

static int exec_stmt_block ( PLpgSQL_execstate estate,
PLpgSQL_stmt_block block 
)
static

Definition at line 1647 of file pl_exec.c.

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

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, PLpgSQL_execstate::err_var, 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().

◆ exec_stmt_call()

static int exec_stmt_call ( PLpgSQL_execstate estate,
PLpgSQL_stmt_call stmt 
)
static

Definition at line 2181 of file pl_exec.c.

2182 {
2183  PLpgSQL_expr *expr = stmt->expr;
2184  LocalTransactionId before_lxid;
2185  LocalTransactionId after_lxid;
2186  ParamListInfo paramLI;
2188  int rc;
2189 
2190  /*
2191  * Make a plan if we don't have one already.
2192  */
2193  if (expr->plan == NULL)
2194  exec_prepare_plan(estate, expr, 0);
2195 
2196  /*
2197  * A CALL or DO can never be a simple expression.
2198  */
2199  Assert(!expr->expr_simple_expr);
2200 
2201  /*
2202  * Also construct a DTYPE_ROW datum representing the plpgsql variables
2203  * associated with the procedure's output arguments. Then we can use
2204  * exec_move_row() to do the assignments.
2205  */
2206  if (stmt->is_call && stmt->target == NULL)
2207  stmt->target = make_callstmt_target(estate, expr);
2208 
2209  paramLI = setup_param_list(estate, expr);
2210 
2211  before_lxid = MyProc->vxid.lxid;
2212 
2213  /*
2214  * If we have a procedure-lifespan resowner, use that to hold the refcount
2215  * for the plan. This avoids refcount leakage complaints if the called
2216  * procedure ends the current transaction.
2217  *
2218  * Also, tell SPI to allow non-atomic execution.
2219  */
2220  memset(&options, 0, sizeof(options));
2221  options.params = paramLI;
2222  options.read_only = estate->readonly_func;
2223  options.allow_nonatomic = true;
2224  options.owner = estate->procedure_resowner;
2225 
2226  rc = SPI_execute_plan_extended(expr->plan, &options);
2227 
2228  if (rc < 0)
2229  elog(ERROR, "SPI_execute_plan_extended failed executing query \"%s\": %s",
2230  expr->query, SPI_result_code_string(rc));
2231 
2232  after_lxid = MyProc->vxid.lxid;
2233 
2234  if (before_lxid != after_lxid)
2235  {
2236  /*
2237  * If we are in a new transaction after the call, we need to build new
2238  * simple-expression infrastructure.
2239  */
2240  estate->simple_eval_estate = NULL;
2241  estate->simple_eval_resowner = NULL;
2242  plpgsql_create_econtext(estate);
2243  }
2244 
2245  /*
2246  * Check result rowcount; if there's one row, assign procedure's output
2247  * values back to the appropriate variables.
2248  */
2249  if (SPI_processed == 1)
2250  {
2251  SPITupleTable *tuptab = SPI_tuptable;
2252 
2253  if (!stmt->is_call)
2254  elog(ERROR, "DO statement returned a row");
2255 
2256  exec_move_row(estate, stmt->target, tuptab->vals[0], tuptab->tupdesc);
2257  }
2258  else if (SPI_processed > 1)
2259  elog(ERROR, "procedure call returned more than one row");
2260 
2261  exec_eval_cleanup(estate);
2263 
2264  return PLPGSQL_RC_OK;
2265 }
static PLpgSQL_variable * make_callstmt_target(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:2273
int SPI_execute_plan_extended(SPIPlanPtr plan, const SPIExecuteOptions *options)
Definition: spi.c:711
ResourceOwner procedure_resowner
Definition: plpgsql.h:1075

References Assert, elog, ERROR, exec_eval_cleanup(), exec_move_row(), exec_prepare_plan(), PLpgSQL_expr::expr_simple_expr, PGPROC::lxid, make_callstmt_target(), MyProc, options, PLpgSQL_expr::plan, plpgsql_create_econtext(), PLPGSQL_RC_OK, PLpgSQL_execstate::procedure_resowner, PLpgSQL_expr::query, 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, stmt, SPITupleTable::tupdesc, SPITupleTable::vals, and PGPROC::vxid.

Referenced by exec_stmts().

◆ exec_stmt_case()

static int exec_stmt_case ( PLpgSQL_execstate estate,
PLpgSQL_stmt_case stmt 
)
static

Definition at line 2540 of file pl_exec.c.

2541 {
2542  PLpgSQL_var *t_var = NULL;
2543  bool isnull;
2544  ListCell *l;
2545 
2546  if (stmt->t_expr != NULL)
2547  {
2548  /* simple case */
2549  Datum t_val;
2550  Oid t_typoid;
2551  int32 t_typmod;
2552 
2553  t_val = exec_eval_expr(estate, stmt->t_expr,
2554  &isnull, &t_typoid, &t_typmod);
2555 
2556  t_var = (PLpgSQL_var *) estate->datums[stmt->t_varno];
2557 
2558  /*
2559  * When expected datatype is different from real, change it. Note that
2560  * what we're modifying here is an execution copy of the datum, so
2561  * this doesn't affect the originally stored function parse tree. (In
2562  * theory, if the expression datatype keeps changing during execution,
2563  * this could cause a function-lifespan memory leak. Doesn't seem
2564  * worth worrying about though.)
2565  */
2566  if (t_var->datatype->typoid != t_typoid ||
2567  t_var->datatype->atttypmod != t_typmod)
2568  t_var->datatype = plpgsql_build_datatype(t_typoid,
2569  t_typmod,
2570  estate->func->fn_input_collation,
2571  NULL);
2572 
2573  /* now we can assign to the variable */
2574  exec_assign_value(estate,
2575  (PLpgSQL_datum *) t_var,
2576  t_val,
2577  isnull,
2578  t_typoid,
2579  t_typmod);
2580 
2581  exec_eval_cleanup(estate);
2582  }
2583 
2584  /* Now search for a successful WHEN clause */
2585  foreach(l, stmt->case_when_list)
2586  {
2588  bool value;
2589 
2590  value = exec_eval_boolean(estate, cwt->expr, &isnull);
2591  exec_eval_cleanup(estate);
2592  if (!isnull && value)
2593  {
2594  /* Found it */
2595 
2596  /* We can now discard any value we had for the temp variable */
2597  if (t_var != NULL)
2598  assign_simple_var(estate, t_var, (Datum) 0, true, false);
2599 
2600  /* Evaluate the statement(s), and we're done */
2601  return exec_stmts(estate, cwt->stmts);
2602  }
2603  }
2604 
2605  /* We can now discard any value we had for the temp variable */
2606  if (t_var != NULL)
2607  assign_simple_var(estate, t_var, (Datum) 0, true, false);
2608 
2609  /* SQL2003 mandates this error if there was no ELSE clause */
2610  if (!stmt->have_else)
2611  ereport(ERROR,
2612  (errcode(ERRCODE_CASE_NOT_FOUND),
2613  errmsg("case not found"),
2614  errhint("CASE statement is missing ELSE part.")));
2615 
2616  /* Evaluate the ELSE statements, and we're done */
2617  return exec_stmts(estate, stmt->else_stmts);
2618 }
PLpgSQL_type * plpgsql_build_datatype(Oid typeOid, int32 typmod, Oid collation, TypeName *origtypname)
Definition: pl_comp.c:2043
PLpgSQL_expr * expr
Definition: plpgsql.h:635
Oid fn_input_collation
Definition: plpgsql.h:973

References assign_simple_var(), PLpgSQL_type::atttypmod, PLpgSQL_var::datatype, PLpgSQL_execstate::datums, 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, if(), lfirst, plpgsql_build_datatype(), stmt, PLpgSQL_case_when::stmts, PLpgSQL_type::typoid, and value.

Referenced by exec_stmts().

◆ exec_stmt_close()

static int exec_stmt_close ( PLpgSQL_execstate estate,
PLpgSQL_stmt_close stmt 
)
static

Definition at line 4917 of file pl_exec.c.

4918 {
4919  PLpgSQL_var *curvar;
4920  Portal portal;
4921  char *curname;
4922  MemoryContext oldcontext;
4923 
4924  /* ----------
4925  * Get the portal of the cursor by name
4926  * ----------
4927  */
4928  curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
4929  if (curvar->isnull)
4930  ereport(ERROR,
4931  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4932  errmsg("cursor variable \"%s\" is null", curvar->refname)));
4933 
4934  /* Use eval_mcontext for short-lived string */
4935  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
4936  curname = TextDatumGetCString(curvar->value);
4937  MemoryContextSwitchTo(oldcontext);
4938 
4939  portal = SPI_cursor_find(curname);
4940  if (portal == NULL)
4941  ereport(ERROR,
4942  (errcode(ERRCODE_UNDEFINED_CURSOR),
4943  errmsg("cursor \"%s\" does not exist", curname)));
4944 
4945  /* ----------
4946  * And close it.
4947  * ----------
4948  */
4949  SPI_cursor_close(portal);
4950 
4951  return PLPGSQL_RC_OK;
4952 }
#define TextDatumGetCString(d)
Definition: builtins.h:98
Portal SPI_cursor_find(const char *name)
Definition: spi.c:1794
void SPI_cursor_close(Portal portal)
Definition: spi.c:1862

References PLpgSQL_execstate::datums, ereport, errcode(), errmsg(), ERROR, get_eval_mcontext, PLpgSQL_var::isnull, MemoryContextSwitchTo(), PLPGSQL_RC_OK, PLpgSQL_var::refname, SPI_cursor_close(), SPI_cursor_find(), stmt, TextDatumGetCString, and PLpgSQL_var::value.

Referenced by exec_stmts().

◆ exec_stmt_commit()

static int exec_stmt_commit ( PLpgSQL_execstate estate,
PLpgSQL_stmt_commit stmt 
)
static

Definition at line 4960 of file pl_exec.c.

4961 {
4962  if (stmt->chain)
4964  else
4965  SPI_commit();
4966 
4967  /*
4968  * We need to build new simple-expression infrastructure, since the old
4969  * data structures are gone.
4970  */
4971  estate->simple_eval_estate = NULL;
4972  estate->simple_eval_resowner = NULL;
4973  plpgsql_create_econtext(estate);
4974 
4975  return PLPGSQL_RC_OK;
4976 }
void SPI_commit(void)
Definition: spi.c:320
void SPI_commit_and_chain(void)
Definition: spi.c:326

References plpgsql_create_econtext(), PLPGSQL_RC_OK, PLpgSQL_execstate::simple_eval_estate, PLpgSQL_execstate::simple_eval_resowner, SPI_commit(), SPI_commit_and_chain(), and stmt.

Referenced by exec_stmts().

◆ exec_stmt_dynexecute()

static int exec_stmt_dynexecute ( PLpgSQL_execstate estate,
PLpgSQL_stmt_dynexecute stmt 
)
static

Definition at line 4444 of file pl_exec.c.

4446 {
4447  Datum query;
4448  bool isnull;
4449  Oid restype;
4450  int32 restypmod;
4451  char *querystr;
4452  int exec_res;
4453  ParamListInfo paramLI;
4455  MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
4456 
4457  /*
4458  * First we evaluate the string expression after the EXECUTE keyword. Its
4459  * result is the querystring we have to execute.
4460  */
4461  query = exec_eval_expr(estate, stmt->query, &isnull, &restype, &restypmod);
4462  if (isnull)
4463  ereport(ERROR,
4464  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4465  errmsg("query string argument of EXECUTE is null")));
4466 
4467  /* Get the C-String representation */
4468  querystr = convert_value_to_string(estate, query, restype);
4469 
4470  /* copy it into the stmt_mcontext before we clean up */
4471  querystr = MemoryContextStrdup(stmt_mcontext, querystr);
4472 
4473  exec_eval_cleanup(estate);
4474 
4475  /*
4476  * Execute the query without preparing a saved plan.
4477  */
4478  paramLI = exec_eval_using_params(estate, stmt->params);
4479 
4480  memset(&options, 0, sizeof(options));
4481  options.params = paramLI;
4482  options.read_only = estate->readonly_func;
4483 
4484  exec_res = SPI_execute_extended(querystr, &options);
4485 
4486  switch (exec_res)
4487  {
4488  case SPI_OK_SELECT:
4489  case SPI_OK_INSERT:
4490  case SPI_OK_UPDATE:
4491  case SPI_OK_DELETE:
4492  case SPI_OK_MERGE:
4497  case SPI_OK_UTILITY:
4498  case SPI_OK_REWRITTEN:
4499  break;
4500 
4501  case 0:
4502 
4503  /*
4504  * Also allow a zero return, which implies the querystring
4505  * contained no commands.
4506  */
4507  break;
4508 
4509  case SPI_OK_SELINTO:
4510 
4511  /*
4512  * We want to disallow SELECT INTO for now, because its behavior
4513  * is not consistent with SELECT INTO in a normal plpgsql context.
4514  * (We need to reimplement EXECUTE to parse the string as a
4515  * plpgsql command, not just feed it to SPI_execute.) This is not
4516  * a functional limitation because CREATE TABLE AS is allowed.
4517  */
4518  ereport(ERROR,
4519  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4520  errmsg("EXECUTE of SELECT ... INTO is not implemented"),
4521  errhint("You might want to use EXECUTE ... INTO or EXECUTE CREATE TABLE ... AS instead.")));
4522  break;
4523 
4524  /* Some SPI errors deserve specific error messages */
4525  case SPI_ERROR_COPY:
4526  ereport(ERROR,
4527  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4528  errmsg("cannot COPY to/from client in PL/pgSQL")));
4529  break;
4530 
4531  case SPI_ERROR_TRANSACTION:
4532  ereport(ERROR,
4533  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4534  errmsg("EXECUTE of transaction commands is not implemented")));
4535  break;
4536 
4537  default:
4538  elog(ERROR, "SPI_execute_extended failed executing query \"%s\": %s",
4539  querystr, SPI_result_code_string(exec_res));
4540  break;
4541  }
4542 
4543  /* Save result info for GET DIAGNOSTICS */
4544  estate->eval_processed = SPI_processed;
4545 
4546  /* Process INTO if present */
4547  if (stmt->into)
4548  {
4549  SPITupleTable *tuptab = SPI_tuptable;
4550  uint64 n = SPI_processed;
4551  PLpgSQL_variable *target;
4552 
4553  /* If the statement did not return a tuple table, complain */
4554  if (tuptab == NULL)
4555  ereport(ERROR,
4556  (errcode(ERRCODE_SYNTAX_ERROR),
4557  errmsg("INTO used with a command that cannot return data")));
4558 
4559  /* Fetch target's datum entry */
4560  target = (PLpgSQL_variable *) estate->datums[stmt->target->dno];
4561 
4562  /*
4563  * If SELECT ... INTO specified STRICT, and the query didn't find
4564  * exactly one row, throw an error. If STRICT was not specified, then
4565  * allow the query to find any number of rows.
4566  */
4567  if (n == 0)
4568  {
4569  if (stmt->strict)
4570  {
4571  char *errdetail;
4572 
4573  if (estate->func->print_strict_params)
4574  errdetail = format_preparedparamsdata(estate, paramLI);
4575  else
4576  errdetail = NULL;
4577 
4578  ereport(ERROR,
4579  (errcode(ERRCODE_NO_DATA_FOUND),
4580  errmsg("query returned no rows"),
4581  errdetail ? errdetail_internal("parameters: %s", errdetail) : 0));
4582  }
4583  /* set the target to NULL(s) */
4584  exec_move_row(estate, target, NULL, tuptab->tupdesc);
4585  }
4586  else
4587  {
4588  if (n > 1 && stmt->strict)
4589  {
4590  char *errdetail;
4591 
4592  if (estate->func->print_strict_params)
4593  errdetail = format_preparedparamsdata(estate, paramLI);
4594  else
4595  errdetail = NULL;
4596 
4597  ereport(ERROR,
4598  (errcode(ERRCODE_TOO_MANY_ROWS),
4599  errmsg("query returned more than one row"),
4600  errdetail ? errdetail_internal("parameters: %s", errdetail) : 0));
4601  }
4602 
4603  /* Put the first result row into the target */
4604  exec_move_row(estate, target, tuptab->vals[0], tuptab->tupdesc);
4605  }
4606  /* clean up after exec_move_row() */
4607  exec_eval_cleanup(estate);
4608  }
4609  else
4610  {
4611  /*
4612  * It might be a good idea to raise an error if the query returned
4613  * tuples that are being ignored, but historically we have not done
4614  * that.
4615  */
4616  }
4617 
4618  /* Release any result from SPI_execute, as well as transient data */
4620  MemoryContextReset(stmt_mcontext);
4621 
4622  return PLPGSQL_RC_OK;
4623 }
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1230
static char * format_preparedparamsdata(PLpgSQL_execstate *estate, ParamListInfo paramLI)
Definition: pl_exec.c:8850
int SPI_execute_extended(const char *src, const SPIExecuteOptions *options)
Definition: spi.c:637
#define SPI_ERROR_TRANSACTION
Definition: spi.h:75
#define SPI_OK_UTILITY
Definition: spi.h:85
#define SPI_OK_REWRITTEN
Definition: spi.h:95
#define SPI_OK_INSERT
Definition: spi.h:88
#define SPI_OK_UPDATE
Definition: spi.h:90
#define SPI_OK_MERGE
Definition: spi.h:99
#define SPI_OK_UPDATE_RETURNING
Definition: spi.h:94
#define SPI_OK_DELETE
Definition: spi.h:89
#define SPI_OK_INSERT_RETURNING
Definition: spi.h:92
#define SPI_ERROR_COPY
Definition: spi.h:69
#define SPI_OK_DELETE_RETURNING
Definition: spi.h:93
#define SPI_OK_MERGE_RETURNING
Definition: spi.h:100
bool print_strict_params
Definition: plpgsql.h:995

References convert_value_to_string(), PLpgSQL_execstate::datums, elog, ereport, errcode(), errdetail(), errdetail_internal(), errhint(), errmsg(), ERROR, PLpgSQL_execstate::eval_processed, exec_eval_cleanup(), exec_eval_expr(), exec_eval_using_params(), exec_move_row(), format_preparedparamsdata(), PLpgSQL_execstate::func, get_stmt_mcontext(), if(), MemoryContextReset(), MemoryContextStrdup(), options, PLPGSQL_RC_OK, PLpgSQL_function::print_strict_params, PLpgSQL_execstate::readonly_func, SPI_ERROR_COPY, SPI_ERROR_TRANSACTION, SPI_execute_extended(), SPI_freetuptable(), SPI_OK_DELETE, SPI_OK_DELETE_RETURNING, SPI_OK_INSERT, SPI_OK_INSERT_RETURNING, SPI_OK_MERGE, SPI_OK_MERGE_RETURNING, SPI_OK_REWRITTEN, SPI_OK_SELECT, SPI_OK_SELINTO, SPI_OK_UPDATE, SPI_OK_UPDATE_RETURNING, SPI_OK_UTILITY, SPI_processed, SPI_result_code_string(), SPI_tuptable, stmt, SPITupleTable::tupdesc, and SPITupleTable::vals.

Referenced by exec_stmts().

◆ exec_stmt_dynfors()

static int exec_stmt_dynfors ( PLpgSQL_execstate estate,
PLpgSQL_stmt_dynfors stmt 
)
static

Definition at line 4634 of file pl_exec.c.

4635 {
4636  Portal portal;
4637  int rc;
4638 
4639  portal = exec_dynquery_with_params(estate, stmt->query, stmt->params,
4640  NULL, CURSOR_OPT_NO_SCROLL);
4641 
4642  /*
4643  * Execute the loop
4644  */
4645  rc = exec_for_query(estate, (PLpgSQL_stmt_forq *) stmt, portal, true);
4646 
4647  /*
4648  * Close the implicit cursor
4649  */
4650  SPI_cursor_close(portal);
4651 
4652  return rc;
4653 }
static int exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt, Portal portal, bool prefetch_ok)
Definition: pl_exec.c:5851
static Portal exec_dynquery_with_params(PLpgSQL_execstate *estate, PLpgSQL_expr *dynquery, List *params, const char *portalname, int cursorOptions)
Definition: pl_exec.c:8732

References CURSOR_OPT_NO_SCROLL, exec_dynquery_with_params(), exec_for_query(), SPI_cursor_close(), and stmt.

Referenced by exec_stmts().

◆ exec_stmt_execsql()

static int exec_stmt_execsql ( PLpgSQL_execstate estate,
PLpgSQL_stmt_execsql stmt 
)
static

Definition at line 4212 of file pl_exec.c.

4214 {
4215  ParamListInfo paramLI;
4216  long tcount;
4217  int rc;
4218  PLpgSQL_expr *expr = stmt->sqlstmt;
4219  int too_many_rows_level = 0;
4220 
4222  too_many_rows_level = ERROR;
4224  too_many_rows_level = WARNING;
4225 
4226  /*
4227  * On the first call for this statement generate the plan, and detect
4228  * whether the statement is INSERT/UPDATE/DELETE/MERGE
4229  */
4230  if (expr->plan == NULL)
4232 
4233  if (!stmt->mod_stmt_set)
4234  {
4235  ListCell *l;
4236 
4237  stmt->mod_stmt = false;
4238  foreach(l, SPI_plan_get_plan_sources(expr->plan))
4239  {
4240  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(l);
4241 
4242  /*
4243  * We could look at the raw_parse_tree, but it seems simpler to
4244  * check the command tag. Note we should *not* look at the Query
4245  * tree(s), since those are the result of rewriting and could be
4246  * stale, or could have been transmogrified into something else
4247  * entirely.
4248  */
4249  if (plansource->commandTag == CMDTAG_INSERT ||
4250  plansource->commandTag == CMDTAG_UPDATE ||
4251  plansource->commandTag == CMDTAG_DELETE ||
4252  plansource->commandTag == CMDTAG_MERGE)
4253  {
4254  stmt->mod_stmt = true;
4255  break;
4256  }
4257  }
4258  stmt->mod_stmt_set = true;
4259  }
4260 
4261  /*
4262  * Set up ParamListInfo to pass to executor
4263  */
4264  paramLI = setup_param_list(estate, expr);
4265 
4266  /*
4267  * If we have INTO, then we only need one row back ... but if we have INTO
4268  * STRICT or extra check too_many_rows, ask for two rows, so that we can
4269  * verify the statement returns only one. INSERT/UPDATE/DELETE/MERGE are
4270  * always treated strictly. Without INTO, just run the statement to
4271  * completion (tcount = 0).
4272  *
4273  * We could just ask for two rows always when using INTO, but there are
4274  * some cases where demanding the extra row costs significant time, eg by
4275  * forcing completion of a sequential scan. So don't do it unless we need
4276  * to enforce strictness.
4277  */
4278  if (stmt->into)
4279  {
4280  if (stmt->strict || stmt->mod_stmt || too_many_rows_level)
4281  tcount = 2;
4282  else
4283  tcount = 1;
4284  }
4285  else
4286  tcount = 0;
4287 
4288  /*
4289  * Execute the plan
4290  */
4291  rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
4292  estate->readonly_func, tcount);
4293 
4294  /*
4295  * Check for error, and set FOUND if appropriate (for historical reasons
4296  * we set FOUND only for certain query types). Also Assert that we
4297  * identified the statement type the same as SPI did.
4298  */
4299  switch (rc)
4300  {
4301  case SPI_OK_SELECT:
4302  Assert(!stmt->mod_stmt);
4303  exec_set_found(estate, (SPI_processed != 0));
4304  break;
4305 
4306  case SPI_OK_INSERT:
4307  case SPI_OK_UPDATE:
4308  case SPI_OK_DELETE:
4309  case SPI_OK_MERGE:
4314  Assert(stmt->mod_stmt);
4315  exec_set_found(estate, (SPI_processed != 0));
4316  break;
4317 
4318  case SPI_OK_SELINTO:
4319  case SPI_OK_UTILITY:
4320  Assert(!stmt->mod_stmt);
4321  break;
4322 
4323  case SPI_OK_REWRITTEN:
4324 
4325  /*
4326  * The command was rewritten into another kind of command. It's
4327  * not clear what FOUND would mean in that case (and SPI doesn't
4328  * return the row count either), so just set it to false. Note
4329  * that we can't assert anything about mod_stmt here.
4330  */
4331  exec_set_found(estate, false);
4332  break;
4333 
4334  /* Some SPI errors deserve specific error messages */
4335  case SPI_ERROR_COPY:
4336  ereport(ERROR,
4337  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4338  errmsg("cannot COPY to/from client in PL/pgSQL")));
4339  break;
4340 
4341  case SPI_ERROR_TRANSACTION:
4342  ereport(ERROR,
4343  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4344  errmsg("unsupported transaction command in PL/pgSQL")));
4345  break;
4346 
4347  default:
4348  elog(ERROR, "SPI_execute_plan_with_paramlist failed executing query \"%s\": %s",
4349  expr->query, SPI_result_code_string(rc));
4350  break;
4351  }
4352 
4353  /* All variants should save result info for GET DIAGNOSTICS */
4354  estate->eval_processed = SPI_processed;
4355 
4356  /* Process INTO if present */
4357  if (stmt->into)
4358  {
4359  SPITupleTable *tuptab = SPI_tuptable;
4360  uint64 n = SPI_processed;
4361  PLpgSQL_variable *target;
4362 
4363  /* If the statement did not return a tuple table, complain */
4364  if (tuptab == NULL)
4365  ereport(ERROR,
4366  (errcode(ERRCODE_SYNTAX_ERROR),
4367  errmsg("INTO used with a command that cannot return data")));
4368 
4369  /* Fetch target's datum entry */
4370  target = (PLpgSQL_variable *) estate->datums[stmt->target->dno];
4371 
4372  /*
4373  * If SELECT ... INTO specified STRICT, and the query didn't find
4374  * exactly one row, throw an error. If STRICT was not specified, then
4375  * allow the query to find any number of rows.
4376  */
4377  if (n == 0)
4378  {
4379  if (stmt->strict)
4380  {
4381  char *errdetail;
4382 
4383  if (estate->func->print_strict_params)
4384  errdetail = format_expr_params(estate, expr);
4385  else
4386  errdetail = NULL;
4387 
4388  ereport(ERROR,
4389  (errcode(ERRCODE_NO_DATA_FOUND),
4390  errmsg("query returned no rows"),
4391  errdetail ? errdetail_internal("parameters: %s", errdetail) : 0));
4392  }
4393  /* set the target to NULL(s) */
4394  exec_move_row(estate, target, NULL, tuptab->tupdesc);
4395  }
4396  else
4397  {
4398  if (n > 1 && (stmt->strict || stmt->mod_stmt || too_many_rows_level))
4399  {
4400  char *errdetail;
4401  int errlevel;
4402 
4403  if (estate->func->print_strict_params)
4404  errdetail = format_expr_params(estate, expr);
4405  else
4406  errdetail = NULL;
4407 
4408  errlevel = (stmt->strict || stmt->mod_stmt) ? ERROR : too_many_rows_level;
4409 
4410  ereport(errlevel,
4411  (errcode(ERRCODE_TOO_MANY_ROWS),
4412  errmsg("query returned more than one row"),
4413  errdetail ? errdetail_internal("parameters: %s", errdetail) : 0,
4414  errhint("Make sure the query returns a single row, or use LIMIT 1.")));
4415  }
4416  /* Put the first result row into the target */
4417  exec_move_row(estate, target, tuptab->vals[0], tuptab->tupdesc);
4418  }
4419 
4420  /* Clean up */
4421  exec_eval_cleanup(estate);
4423  }
4424  else
4425  {
4426  /* If the statement returned a tuple table, complain */
4427  if (SPI_tuptable != NULL)
4428  ereport(ERROR,
4429  (errcode(ERRCODE_SYNTAX_ERROR),
4430  errmsg("query has no destination for result data"),
4431  (rc == SPI_OK_SELECT) ? errhint("If you want to discard the results of a SELECT, use PERFORM instead.") : 0));
4432  }
4433 
4434  return PLPGSQL_RC_OK;
4435 }
static char * format_expr_params(PLpgSQL_execstate *estate, const PLpgSQL_expr *expr)
Definition: pl_exec.c:8793
#define PLPGSQL_XCHECK_TOOMANYROWS
Definition: plpgsql.h:1205
CommandTag commandTag
Definition: plancache.h:101

References Assert, CachedPlanSource::commandTag, CURSOR_OPT_PARALLEL_OK, PLpgSQL_execstate::datums, elog, ereport, errcode(), errdetail(), errdetail_internal(), errhint(), errmsg(), ERROR, PLpgSQL_execstate::eval_processed, exec_eval_cleanup(), exec_move_row(), exec_prepare_plan(), exec_set_found(), format_expr_params(), PLpgSQL_execstate::func, if(), lfirst, PLpgSQL_expr::plan, plpgsql_extra_errors, plpgsql_extra_warnings, PLPGSQL_RC_OK, PLPGSQL_XCHECK_TOOMANYROWS, PLpgSQL_function::print_strict_params, PLpgSQL_expr::query, PLpgSQL_execstate::readonly_func, setup_param_list(), SPI_ERROR_COPY, SPI_ERROR_TRANSACTION, SPI_execute_plan_with_paramlist(), SPI_freetuptable(), SPI_OK_DELETE, SPI_OK_DELETE_RETURNING, SPI_OK_INSERT, SPI_OK_INSERT_RETURNING, SPI_OK_MERGE, SPI_OK_MERGE_RETURNING, SPI_OK_REWRITTEN, SPI_OK_SELECT, SPI_OK_SELINTO, SPI_OK_UPDATE, SPI_OK_UPDATE_RETURNING, SPI_OK_UTILITY, SPI_plan_get_plan_sources(), SPI_processed, SPI_result_code_string(), SPI_tuptable, stmt, SPITupleTable::tupdesc, SPITupleTable::vals, and WARNING.

Referenced by exec_stmt_forc(), exec_stmt_open(), and exec_stmts().

◆ exec_stmt_exit()

static int exec_stmt_exit ( PLpgSQL_execstate estate,
PLpgSQL_stmt_exit stmt 
)
static

Definition at line 3148 of file pl_exec.c.

3149 {
3150  /*
3151  * If the exit / continue has a condition, evaluate it
3152  */
3153  if (stmt->cond != NULL)
3154  {
3155  bool value;
3156  bool isnull;
3157 
3158  value = exec_eval_boolean(estate, stmt->cond, &isnull);
3159  exec_eval_cleanup(estate);
3160  if (isnull || value == false)
3161  return PLPGSQL_RC_OK;
3162  }
3163 
3164  estate->exitlabel = stmt->label;
3165  if (stmt->is_exit)
3166  return PLPGSQL_RC_EXIT;
3167  else
3168  return PLPGSQL_RC_CONTINUE;
3169 }

References exec_eval_boolean(), exec_eval_cleanup(), PLpgSQL_execstate::exitlabel, PLPGSQL_RC_CONTINUE, PLPGSQL_RC_EXIT, PLPGSQL_RC_OK, stmt, and value.

Referenced by exec_stmts().

◆ exec_stmt_fetch()

static int exec_stmt_fetch ( PLpgSQL_execstate estate,
PLpgSQL_stmt_fetch stmt 
)
static

Definition at line 4826 of file pl_exec.c.

4827 {
4828  PLpgSQL_var *curvar;
4829  long how_many = stmt->how_many;
4830  SPITupleTable *tuptab;
4831  Portal portal;
4832  char *curname;
4833  uint64 n;
4834  MemoryContext oldcontext;
4835 
4836  /* ----------
4837  * Get the portal of the cursor by name
4838  * ----------
4839  */
4840  curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
4841  if (curvar->isnull)
4842  ereport(ERROR,
4843  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4844  errmsg("cursor variable \"%s\" is null", curvar->refname)));
4845 
4846  /* Use eval_mcontext for short-lived string */
4847  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
4848  curname = TextDatumGetCString(curvar->value);
4849  MemoryContextSwitchTo(oldcontext);
4850 
4851  portal = SPI_cursor_find(curname);
4852  if (portal == NULL)
4853  ereport(ERROR,
4854  (errcode(ERRCODE_UNDEFINED_CURSOR),
4855  errmsg("cursor \"%s\" does not exist", curname)));
4856 
4857  /* Calculate position for FETCH_RELATIVE or FETCH_ABSOLUTE */
4858  if (stmt->expr)
4859  {
4860  bool isnull;
4861 
4862  /* XXX should be doing this in LONG not INT width */
4863  how_many = exec_eval_integer(estate, stmt->expr, &isnull);
4864 
4865  if (isnull)
4866  ereport(ERROR,
4867  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4868  errmsg("relative or absolute cursor position is null")));
4869 
4870  exec_eval_cleanup(estate);
4871  }
4872 
4873  if (!stmt->is_move)
4874  {
4875  PLpgSQL_variable *target;
4876 
4877  /* ----------
4878  * Fetch 1 tuple from the cursor
4879  * ----------
4880  */
4881  SPI_scroll_cursor_fetch(portal, stmt->direction, how_many);
4882  tuptab = SPI_tuptable;
4883  n = SPI_processed;
4884 
4885  /* ----------
4886  * Set the target appropriately.
4887  * ----------
4888  */
4889  target = (PLpgSQL_variable *) estate->datums[stmt->target->dno];
4890  if (n == 0)
4891  exec_move_row(estate, target, NULL, tuptab->tupdesc);
4892  else
4893  exec_move_row(estate, target, tuptab->vals[0], tuptab->tupdesc);
4894 
4895  exec_eval_cleanup(estate);
4896  SPI_freetuptable(tuptab);
4897  }
4898  else
4899  {
4900  /* Move the cursor */
4901  SPI_scroll_cursor_move(portal, stmt->direction, how_many);
4902  n = SPI_processed;
4903  }
4904 
4905  /* Set the ROW_COUNT and the global FOUND variable appropriately. */
4906  estate->eval_processed = n;
4907  exec_set_found(estate, n != 0);
4908 
4909  return PLPGSQL_RC_OK;
4910 }
static int exec_eval_integer(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
Definition: pl_exec.c:5637
void SPI_scroll_cursor_move(Portal portal, FetchDirection direction, long count)
Definition: spi.c:1850
void SPI_scroll_cursor_fetch(Portal portal, FetchDirection direction, long count)
Definition: spi.c:1835

References PLpgSQL_execstate::datums, ereport, errcode(), errmsg(), ERROR, PLpgSQL_execstate::eval_processed, exec_eval_cleanup(), exec_eval_integer(), exec_move_row(), exec_set_found(), get_eval_mcontext, if(), PLpgSQL_var::isnull, MemoryContextSwitchTo(), PLPGSQL_RC_OK, PLpgSQL_var::refname, SPI_cursor_find(), SPI_freetuptable(), SPI_processed, SPI_scroll_cursor_fetch(), SPI_scroll_cursor_move(), SPI_tuptable, stmt, TextDatumGetCString, SPITupleTable::tupdesc, SPITupleTable::vals, and PLpgSQL_var::value.

Referenced by exec_stmts().

◆ exec_stmt_forc()

static int exec_stmt_forc ( PLpgSQL_execstate estate,
PLpgSQL_stmt_forc stmt 
)
static

Definition at line 2852 of file pl_exec.c.

2853 {
2854  PLpgSQL_var *curvar;
2855  MemoryContext stmt_mcontext = NULL;
2856  char *curname = NULL;
2857  PLpgSQL_expr *query;
2858  ParamListInfo paramLI;
2859  Portal portal;
2860  int rc;
2861 
2862  /* ----------
2863  * Get the cursor variable and if it has an assigned name, check
2864  * that it's not in use currently.
2865  * ----------
2866  */
2867  curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
2868  if (!curvar->isnull)
2869  {
2870  MemoryContext oldcontext;
2871 
2872  /* We only need stmt_mcontext to hold the cursor name string */
2873  stmt_mcontext = get_stmt_mcontext(estate);
2874  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
2875  curname = TextDatumGetCString(curvar->value);
2876  MemoryContextSwitchTo(oldcontext);
2877 
2878  if (SPI_cursor_find(curname) != NULL)
2879  ereport(ERROR,
2880  (errcode(ERRCODE_DUPLICATE_CURSOR),
2881  errmsg("cursor \"%s\" already in use", curname)));
2882  }
2883 
2884  /* ----------
2885  * Open the cursor just like an OPEN command
2886  *
2887  * Note: parser should already have checked that statement supplies
2888  * args iff cursor needs them, but we check again to be safe.
2889  * ----------
2890  */
2891  if (stmt->argquery != NULL)
2892  {
2893  /* ----------
2894  * OPEN CURSOR with args. We fake a SELECT ... INTO ...
2895  * statement to evaluate the args and put 'em into the
2896  * internal row.
2897  * ----------
2898  */
2899  PLpgSQL_stmt_execsql set_args;
2900 
2901  if (curvar->cursor_explicit_argrow < 0)
2902  ereport(ERROR,
2903  (errcode(ERRCODE_SYNTAX_ERROR),
2904  errmsg("arguments given for cursor without arguments")));
2905 
2906  memset(&set_args, 0, sizeof(set_args));
2907  set_args.cmd_type = PLPGSQL_STMT_EXECSQL;
2908  set_args.lineno = stmt->lineno;
2909  set_args.sqlstmt = stmt->argquery;
2910  set_args.into = true;
2911  /* XXX historically this has not been STRICT */
2912  set_args.target = (PLpgSQL_variable *)
2913  (estate->datums[curvar->cursor_explicit_argrow]);
2914 
2915  if (exec_stmt_execsql(estate, &set_args) != PLPGSQL_RC_OK)
2916  elog(ERROR, "open cursor failed during argument processing");
2917  }
2918  else
2919  {
2920  if (curvar->cursor_explicit_argrow >= 0)
2921  ereport(ERROR,
2922  (errcode(ERRCODE_SYNTAX_ERROR),
2923  errmsg("arguments required for cursor")));
2924  }
2925 
2926  query = curvar->cursor_explicit_expr;
2927  Assert(query);
2928 
2929  if (query->plan == NULL)
2930  exec_prepare_plan(estate, query, curvar->cursor_options);
2931 
2932  /*
2933  * Set up ParamListInfo for this query
2934  */
2935  paramLI = setup_param_list(estate, query);
2936 
2937  /*
2938  * Open the cursor (the paramlist will get copied into the portal)
2939  */
2940  portal = SPI_cursor_open_with_paramlist(curname, query->plan,
2941  paramLI,
2942  estate->readonly_func);
2943  if (portal == NULL)
2944  elog(ERROR, "could not open cursor: %s",
2946 
2947  /*
2948  * If cursor variable was NULL, store the generated portal name in it,
2949  * after verifying it's okay to assign to.
2950  */
2951  if (curname == NULL)
2952  {
2953  exec_check_assignable(estate, stmt->curvar);
2954  assign_text_var(estate, curvar, portal->name);
2955  }
2956 
2957  /*
2958  * Clean up before entering exec_for_query
2959  */
2960  exec_eval_cleanup(estate);
2961  if (stmt_mcontext)
2962  MemoryContextReset(stmt_mcontext);
2963 
2964  /*
2965  * Execute the loop. We can't prefetch because the cursor is accessible
2966  * to the user, for instance via UPDATE WHERE CURRENT OF within the loop.
2967  */
2968  rc = exec_for_query(estate, (PLpgSQL_stmt_forq *) stmt, portal, false);
2969 
2970  /* ----------
2971  * Close portal, and restore cursor variable if it was initially NULL.
2972  * ----------
2973  */
2974  SPI_cursor_close(portal);
2975 
2976  if (curname == NULL)
2977  assign_simple_var(estate, curvar, (Datum) 0, true, false);
2978 
2979  return rc;
2980 }
static int exec_stmt_execsql(PLpgSQL_execstate *estate, PLpgSQL_stmt_execsql *stmt)
Definition: pl_exec.c:4212
@ PLPGSQL_STMT_EXECSQL
Definition: plpgsql.h:120
PLpgSQL_variable * target
Definition: plpgsql.h:901
PLpgSQL_expr * sqlstmt
Definition: plpgsql.h:896
PLpgSQL_stmt_type cmd_type
Definition: plpgsql.h:893
int cursor_explicit_argrow
Definition: plpgsql.h:328
int cursor_options
Definition: plpgsql.h:329
PLpgSQL_expr * cursor_explicit_expr
Definition: plpgsql.h:327
const char * name
Definition: portal.h:118

References Assert, assign_simple_var(), assign_text_var(), PLpgSQL_stmt_execsql::cmd_type, PLpgSQL_var::cursor_explicit_argrow, PLpgSQL_var::cursor_explicit_expr, PLpgSQL_var::cursor_options, PLpgSQL_execstate::datums, elog, ereport, errcode(), errmsg(), ERROR, exec_check_assignable(), exec_eval_cleanup(), exec_for_query(), exec_prepare_plan(), exec_stmt_execsql(), get_stmt_mcontext(), PLpgSQL_stmt_execsql::into, PLpgSQL_var::isnull, PLpgSQL_stmt_execsql::lineno, MemoryContextReset(), MemoryContextSwitchTo(), PortalData::name, PLpgSQL_expr::plan, PLPGSQL_RC_OK, PLPGSQL_STMT_EXECSQL, PLpgSQL_execstate::readonly_func, setup_param_list(), SPI_cursor_close(), SPI_cursor_find(), SPI_cursor_open_with_paramlist(), SPI_result, SPI_result_code_string(), PLpgSQL_stmt_execsql::sqlstmt, stmt, PLpgSQL_stmt_execsql::target, TextDatumGetCString, and PLpgSQL_var::value.

Referenced by exec_stmts().

◆ exec_stmt_foreach_a()

static int exec_stmt_foreach_a ( PLpgSQL_execstate estate,
PLpgSQL_stmt_foreach_a stmt 
)
static

Definition at line 2992 of file pl_exec.c.

2993 {
2994  ArrayType *arr;
2995  Oid arrtype;
2996  int32 arrtypmod;
2997  PLpgSQL_datum *loop_var;
2998  Oid loop_var_elem_type;
2999  bool found = false;
3000  int rc = PLPGSQL_RC_OK;
3001  MemoryContext stmt_mcontext;
3002  MemoryContext oldcontext;
3004  Oid iterator_result_type;
3005  int32 iterator_result_typmod;
3006  Datum value;
3007  bool isnull;
3008 
3009  /* get the value of the array expression */
3010  value = exec_eval_expr(estate, stmt->expr, &isnull, &arrtype, &arrtypmod);
3011  if (isnull)
3012  ereport(ERROR,
3013  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
3014  errmsg("FOREACH expression must not be null")));
3015 
3016  /*
3017  * Do as much as possible of the code below in stmt_mcontext, to avoid any
3018  * leaks from called subroutines. We need a private stmt_mcontext since
3019  * we'll be calling arbitrary statement code.
3020  */
3021  stmt_mcontext = get_stmt_mcontext(estate);
3022  push_stmt_mcontext(estate);
3023  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
3024 
3025  /* check the type of the expression - must be an array */
3026  if (!OidIsValid(get_element_type(arrtype)))
3027  ereport(ERROR,
3028  (errcode(ERRCODE_DATATYPE_MISMATCH),
3029  errmsg("FOREACH expression must yield an array, not type %s",
3030  format_type_be(arrtype))));
3031 
3032  /*
3033  * We must copy the array into stmt_mcontext, else it will disappear in
3034  * exec_eval_cleanup. This is annoying, but cleanup will certainly happen
3035  * while running the loop body, so we have little choice.
3036  */
3038 
3039  /* Clean up any leftover temporary memory */
3040  exec_eval_cleanup(estate);
3041 
3042  /* Slice dimension must be less than or equal to array dimension */
3043  if (stmt->slice < 0 || stmt->slice > ARR_NDIM(arr))
3044  ereport(ERROR,
3045  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
3046  errmsg("slice dimension (%d) is out of the valid range 0..%d",
3047  stmt->slice, ARR_NDIM(arr))));
3048 
3049  /* Set up the loop variable and see if it is of an array type */
3050  loop_var = estate->datums[stmt->varno];
3051  if (loop_var->dtype == PLPGSQL_DTYPE_REC ||
3052  loop_var->dtype == PLPGSQL_DTYPE_ROW)
3053  {
3054  /*
3055  * Record/row variable is certainly not of array type, and might not
3056  * be initialized at all yet, so don't try to get its type
3057  */
3058  loop_var_elem_type = InvalidOid;
3059  }
3060  else
3061  loop_var_elem_type = get_element_type(plpgsql_exec_get_datum_type(estate,
3062  loop_var));
3063 
3064  /*
3065  * Sanity-check the loop variable type. We don't try very hard here, and
3066  * should not be too picky since it's possible that exec_assign_value can
3067  * coerce values of different types. But it seems worthwhile to complain
3068  * if the array-ness of the loop variable is not right.
3069  */
3070  if (stmt->slice > 0 && loop_var_elem_type == InvalidOid)
3071  ereport(ERROR,
3072  (errcode(ERRCODE_DATATYPE_MISMATCH),
3073  errmsg("FOREACH ... SLICE loop variable must be of an array type")));
3074  if (stmt->slice == 0 && loop_var_elem_type != InvalidOid)
3075  ereport(ERROR,
3076  (errcode(ERRCODE_DATATYPE_MISMATCH),
3077  errmsg("FOREACH loop variable must not be of an array type")));
3078 
3079  /* Create an iterator to step through the array */
3080  array_iterator = array_create_iterator(arr, stmt->slice, NULL);
3081 
3082  /* Identify iterator result type */
3083  if (stmt->slice > 0)
3084  {
3085  /* When slicing, nominal type of result is same as array type */
3086  iterator_result_type = arrtype;
3087  iterator_result_typmod = arrtypmod;
3088  }
3089  else
3090  {
3091  /* Without slicing, results are individual array elements */
3092  iterator_result_type = ARR_ELEMTYPE(arr);
3093  iterator_result_typmod = arrtypmod;
3094  }
3095 
3096  /* Iterate over the array elements or slices */
3097  while (array_iterate(array_iterator, &value, &isnull))
3098  {
3099  found = true; /* looped at least once */
3100 
3101  /* exec_assign_value and exec_stmts must run in the main context */
3102  MemoryContextSwitchTo(oldcontext);
3103 
3104  /* Assign current element/slice to the loop variable */
3105  exec_assign_value(estate, loop_var, value, isnull,
3106  iterator_result_type, iterator_result_typmod);
3107 
3108  /* In slice case, value is temporary; must free it to avoid leakage */
3109  if (stmt->slice > 0)
3111 
3112  /*
3113  * Execute the statements
3114  */
3115  rc = exec_stmts(estate, stmt->body);
3116 
3117  LOOP_RC_PROCESSING(stmt->label, break);
3118 
3119  MemoryContextSwitchTo(stmt_mcontext);
3120  }
3121 
3122  /* Restore memory context state */
3123  MemoryContextSwitchTo(oldcontext);
3124  pop_stmt_mcontext(estate);
3125 
3126  /* Release temporary memory, including the array value */
3127  MemoryContextReset(stmt_mcontext);
3128 
3129  /*
3130  * Set the FOUND variable to indicate the result of executing the loop
3131  * (namely, whether we looped one or more times). This must be set here so
3132  * that it does not interfere with the value of the FOUND variable inside
3133  * the loop processing itself.
3134  */
3135  exec_set_found(estate, found);
3136 
3137  return rc;
3138 }
static bool array_iterator(ArrayType *la, PGCALL2 callback, void *param, ltree **found)
Definition: _ltree_op.c:38
#define DatumGetArrayTypePCopy(X)
Definition: array.h:262
#define ARR_NDIM(a)
Definition: array.h:290
#define ARR_ELEMTYPE(a)
Definition: array.h:292
bool array_iterate(ArrayIterator iterator, Datum *value, bool *isnull)
Definition: arrayfuncs.c:4676
ArrayIterator array_create_iterator(ArrayType *arr, int slice_ndim, ArrayMetaState *mstate)
Definition: arrayfuncs.c:4597
#define OidIsValid(objectId)
Definition: c.h:780
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2759
static void push_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1547
Oid plpgsql_exec_get_datum_type(PLpgSQL_execstate *estate, PLpgSQL_datum *datum)
Definition: pl_exec.c:5457

References ARR_ELEMTYPE, ARR_NDIM, array_create_iterator(), array_iterate(), array_iterator(), DatumGetArrayTypePCopy, DatumGetPointer(), PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, ereport, errcode(), errmsg(), ERROR, exec_assign_value(), exec_eval_cleanup(), exec_eval_expr(), exec_set_found(), exec_stmts(), format_type_be(), get_element_type(), get_stmt_mcontext(), InvalidOid, LOOP_RC_PROCESSING, MemoryContextReset(), MemoryContextSwitchTo(), OidIsValid, pfree(), PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_ROW, plpgsql_exec_get_datum_type(), PLPGSQL_RC_OK, pop_stmt_mcontext(), push_stmt_mcontext(), stmt, and value.

Referenced by exec_stmts().

◆ exec_stmt_fori()

static int exec_stmt_fori ( PLpgSQL_execstate estate,
PLpgSQL_stmt_fori stmt 
)
static

Definition at line 2680 of file pl_exec.c.

2681 {
2682  PLpgSQL_var *var;
2683  Datum value;
2684  bool isnull;
2685  Oid valtype;
2686  int32 valtypmod;
2687  int32 loop_value;
2688  int32 end_value;
2689  int32 step_value;
2690  bool found = false;
2691  int rc = PLPGSQL_RC_OK;
2692 
2693  var = (PLpgSQL_var *) (estate->datums[stmt->var->dno]);
2694 
2695  /*
2696  * Get the value of the lower bound
2697  */
2698  value = exec_eval_expr(estate, stmt->lower,
2699  &isnull, &valtype, &valtypmod);
2700  value = exec_cast_value(estate, value, &isnull,
2701  valtype, valtypmod,
2702  var->datatype->typoid,
2703  var->datatype->atttypmod);
2704  if (isnull)
2705  ereport(ERROR,
2706  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
2707  errmsg("lower bound of FOR loop cannot be null")));
2708  loop_value = DatumGetInt32(value);
2709  exec_eval_cleanup(estate);
2710 
2711  /*
2712  * Get the value of the upper bound
2713  */
2714  value = exec_eval_expr(estate, stmt->upper,
2715  &isnull, &valtype, &valtypmod);
2716  value = exec_cast_value(estate, value, &isnull,
2717  valtype, valtypmod,
2718  var->datatype->typoid,
2719  var->datatype->atttypmod);
2720  if (isnull)
2721  ereport(ERROR,
2722  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
2723  errmsg("upper bound of FOR loop cannot be null")));
2724  end_value = DatumGetInt32(value);
2725  exec_eval_cleanup(estate);
2726 
2727  /*
2728  * Get the step value
2729  */
2730  if (stmt->step)
2731  {
2732  value = exec_eval_expr(estate, stmt->step,
2733  &isnull, &valtype, &valtypmod);
2734  value = exec_cast_value(estate, value, &isnull,
2735  valtype, valtypmod,
2736  var->datatype->typoid,
2737  var->datatype->atttypmod);
2738  if (isnull)
2739  ereport(ERROR,
2740  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
2741  errmsg("BY value of FOR loop cannot be null")));
2742  step_value = DatumGetInt32(value);
2743  exec_eval_cleanup(estate);
2744  if (step_value <= 0)
2745  ereport(ERROR,
2746  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2747  errmsg("BY value of FOR loop must be greater than zero")));
2748  }
2749  else
2750  step_value = 1;
2751 
2752  /*
2753  * Now do the loop
2754  */
2755  for (;;)
2756  {
2757  /*
2758  * Check against upper bound
2759  */
2760  if (stmt->reverse)
2761  {
2762  if (loop_value < end_value)
2763  break;
2764  }
2765  else
2766  {
2767  if (loop_value > end_value)
2768  break;
2769  }
2770 
2771  found = true; /* looped at least once */
2772 
2773  /*
2774  * Assign current value to loop var
2775  */
2776  assign_simple_var(estate, var, Int32GetDatum(loop_value), false, false);
2777 
2778  /*
2779  * Execute the statements
2780  */
2781  rc = exec_stmts(estate, stmt->body);
2782 
2783  LOOP_RC_PROCESSING(stmt->label, break);
2784 
2785  /*
2786  * Increase/decrease loop value, unless it would overflow, in which
2787  * case exit the loop.
2788  */
2789  if (stmt->reverse)
2790  {
2791  if (loop_value < (PG_INT32_MIN + step_value))
2792  break;
2793  loop_value -= step_value;
2794  }
2795  else
2796  {
2797  if (loop_value > (PG_INT32_MAX - step_value))
2798  break;
2799  loop_value += step_value;
2800  }
2801  }
2802 
2803  /*
2804  * Set the FOUND variable to indicate the result of executing the loop
2805  * (namely, whether we looped one or more times). This must be set here so
2806  * that it does not interfere with the value of the FOUND variable inside
2807  * the loop processing itself.
2808  */
2809  exec_set_found(estate, found);
2810 
2811  return rc;
2812 }
#define PG_INT32_MAX
Definition: c.h:594
#define PG_INT32_MIN
Definition: c.h:593
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212

References assign_simple_var(), PLpgSQL_type::atttypmod, PLpgSQL_var::datatype, DatumGetInt32(), PLpgSQL_execstate::datums, ereport, errcode(), errmsg(), ERROR, exec_cast_value(), exec_eval_cleanup(), exec_eval_expr(), exec_set_found(), exec_stmts(), Int32GetDatum(), LOOP_RC_PROCESSING, PG_INT32_MAX, PG_INT32_MIN, PLPGSQL_RC_OK, stmt, PLpgSQL_type::typoid, and value.

Referenced by exec_stmts().

◆ exec_stmt_fors()

static int exec_stmt_fors ( PLpgSQL_execstate estate,
PLpgSQL_stmt_fors stmt 
)
static

Definition at line 2823 of file pl_exec.c.

2824 {
2825  Portal portal;
2826  int rc;
2827 
2828  /*
2829  * Open the implicit cursor for the statement using exec_run_select
2830  */
2831  exec_run_select(estate, stmt->query, 0, &portal);
2832 
2833  /*
2834  * Execute the loop
2835  */
2836  rc = exec_for_query(estate, (PLpgSQL_stmt_forq *) stmt, portal, true);
2837 
2838  /*
2839  * Close the implicit cursor
2840  */
2841  SPI_cursor_close(portal);
2842 
2843  return rc;
2844 }

References exec_for_query(), exec_run_select(), SPI_cursor_close(), and stmt.

Referenced by exec_stmts().

◆ exec_stmt_getdiag()

static int exec_stmt_getdiag ( PLpgSQL_execstate estate,
PLpgSQL_stmt_getdiag stmt 
)
static

Definition at line 2394 of file pl_exec.c.

2395 {
2396  ListCell *lc;
2397 
2398  /*
2399  * GET STACKED DIAGNOSTICS is only valid inside an exception handler.
2400  *
2401  * Note: we trust the grammar to have disallowed the relevant item kinds
2402  * if not is_stacked, otherwise we'd dump core below.
2403  */
2404  if (stmt->is_stacked && estate->cur_error == NULL)
2405  ereport(ERROR,
2406  (errcode(ERRCODE_STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER),
2407  errmsg("GET STACKED DIAGNOSTICS cannot be used outside an exception handler")));
2408 
2409  foreach(lc, stmt->diag_items)
2410  {
2411  PLpgSQL_diag_item *diag_item = (PLpgSQL_diag_item *) lfirst(lc);
2412  PLpgSQL_datum *var = estate->datums[diag_item->target];
2413 
2414  switch (diag_item->kind)
2415  {
2417  exec_assign_value(estate, var,
2418  UInt64GetDatum(estate->eval_processed),
2419  false, INT8OID, -1);
2420  break;
2421 
2423  exec_assign_value(estate, var,
2424  ObjectIdGetDatum(estate->func->fn_oid),
2425  false, OIDOID, -1);
2426  break;
2427 
2429  exec_assign_c_string(estate, var,
2430  estate->cur_error->context);
2431  break;
2432 
2434  exec_assign_c_string(estate, var,
2435  estate->cur_error->detail);
2436  break;
2437 
2439  exec_assign_c_string(estate, var,
2440  estate->cur_error->hint);
2441  break;
2442 
2444  exec_assign_c_string(estate, var,
2446  break;
2447 
2449  exec_assign_c_string(estate, var,
2450  estate->cur_error->column_name);
2451  break;
2452 
2454  exec_assign_c_string(estate, var,
2455  estate->cur_error->constraint_name);
2456  break;
2457 
2459  exec_assign_c_string(estate, var,
2460  estate->cur_error->datatype_name);
2461  break;
2462 
2464  exec_assign_c_string(estate, var,
2465  estate->cur_error->message);
2466  break;
2467 
2469  exec_assign_c_string(estate, var,
2470  estate->cur_error->table_name);
2471  break;
2472 
2474  exec_assign_c_string(estate, var,
2475  estate->cur_error->schema_name);
2476  break;
2477 
2479  {
2480  char *contextstackstr;
2481  MemoryContext oldcontext;
2482 
2483  /* Use eval_mcontext for short-lived string */
2484  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
2485  contextstackstr = GetErrorContextStack();
2486  MemoryContextSwitchTo(oldcontext);
2487 
2488  exec_assign_c_string(estate, var, contextstackstr);
2489  }
2490  break;
2491 
2492  default:
2493  elog(ERROR, "unrecognized diagnostic item kind: %d",
2494  diag_item->kind);
2495  }
2496  }
2497 
2498  exec_eval_cleanup(estate);
2499 
2500  return PLPGSQL_RC_OK;
2501 }
char * GetErrorContextStack(void)
Definition: elog.c:2059
static void exec_assign_c_string(PLpgSQL_execstate *estate, PLpgSQL_datum *target, const char *str)
Definition: pl_exec.c:5051
@ PLPGSQL_GETDIAG_ERROR_DETAIL
Definition: plpgsql.h:153
@ PLPGSQL_GETDIAG_SCHEMA_NAME
Definition: plpgsql.h:161
@ PLPGSQL_GETDIAG_MESSAGE_TEXT
Definition: plpgsql.h:159
@ PLPGSQL_GETDIAG_DATATYPE_NAME
Definition: plpgsql.h:158
@ PLPGSQL_GETDIAG_TABLE_NAME
Definition: plpgsql.h:160
@ PLPGSQL_GETDIAG_CONSTRAINT_NAME
Definition: plpgsql.h:157
@ PLPGSQL_GETDIAG_COLUMN_NAME
Definition: plpgsql.h:156
@ PLPGSQL_GETDIAG_ROW_COUNT
Definition: plpgsql.h:149
@ PLPGSQL_GETDIAG_RETURNED_SQLSTATE
Definition: plpgsql.h:155
@ PLPGSQL_GETDIAG_CONTEXT
Definition: plpgsql.h:151
@ PLPGSQL_GETDIAG_ERROR_HINT
Definition: plpgsql.h:154
@ PLPGSQL_GETDIAG_ERROR_CONTEXT
Definition: plpgsql.h:152
@ PLPGSQL_GETDIAG_ROUTINE_OID
Definition: plpgsql.h:150
static Datum UInt64GetDatum(uint64 X)
Definition: postgres.h:436
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
char * schema_name
Definition: elog.h:447
char * context
Definition: elog.h:444
char * datatype_name
Definition: elog.h:450
char * detail
Definition: elog.h:441
char * table_name
Definition: elog.h:448
char * hint
Definition: elog.h:443
char * constraint_name
Definition: elog.h:451
char * column_name
Definition: elog.h:449
PLpgSQL_getdiag_kind kind
Definition: plpgsql.h:574

References ErrorData::column_name, ErrorData::constraint_name, ErrorData::context, PLpgSQL_execstate::cur_error, ErrorData::datatype_name, PLpgSQL_execstate::datums, ErrorData::detail, elog, ereport, errcode(), errmsg(), ERROR, PLpgSQL_execstate::eval_processed, exec_assign_c_string(), exec_assign_value(), exec_eval_cleanup(), PLpgSQL_function::fn_oid, PLpgSQL_execstate::func, get_eval_mcontext, GetErrorContextStack(), ErrorData::hint, PLpgSQL_diag_item::kind, lfirst, MemoryContextSwitchTo(), ErrorData::message, ObjectIdGetDatum(), PLPGSQL_GETDIAG_COLUMN_NAME, PLPGSQL_GETDIAG_CONSTRAINT_NAME, PLPGSQL_GETDIAG_CONTEXT, PLPGSQL_GETDIAG_DATATYPE_NAME, PLPGSQL_GETDIAG_ERROR_CONTEXT, PLPGSQL_GETDIAG_ERROR_DETAIL, PLPGSQL_GETDIAG_ERROR_HINT, PLPGSQL_GETDIAG_MESSAGE_TEXT, PLPGSQL_GETDIAG_RETURNED_SQLSTATE, PLPGSQL_GETDIAG_ROUTINE_OID, PLPGSQL_GETDIAG_ROW_COUNT, PLPGSQL_GETDIAG_SCHEMA_NAME, PLPGSQL_GETDIAG_TABLE_NAME, PLPGSQL_RC_OK, ErrorData::schema_name, ErrorData::sqlerrcode, stmt, ErrorData::table_name, PLpgSQL_diag_item::target, UInt64GetDatum(), and unpack_sql_state().

Referenced by exec_stmts().

◆ exec_stmt_if()

static int exec_stmt_if ( PLpgSQL_execstate estate,
PLpgSQL_stmt_if stmt 
)
static

Definition at line 2510 of file pl_exec.c.

2511 {
2512  bool value;
2513  bool isnull;
2514  ListCell *lc;
2515 
2516  value = exec_eval_boolean(estate, stmt->cond, &isnull);
2517  exec_eval_cleanup(estate);
2518  if (!isnull && value)
2519  return exec_stmts(estate, stmt->then_body);
2520 
2521  foreach(lc, stmt->elsif_list)
2522  {
2523  PLpgSQL_if_elsif *elif = (PLpgSQL_if_elsif *) lfirst(lc);
2524 
2525  value = exec_eval_boolean(estate, elif->cond, &isnull);
2526  exec_eval_cleanup(estate);
2527  if (!isnull && value)
2528  return exec_stmts(estate, elif->stmts);
2529  }
2530 
2531  return exec_stmts(estate, stmt->else_body);
2532 }
PLpgSQL_expr * cond
Definition: plpgsql.h:610
List * stmts
Definition: plpgsql.h:611

References PLpgSQL_if_elsif::cond, exec_eval_boolean(), exec_eval_cleanup(), exec_stmts(), lfirst, stmt, PLpgSQL_if_elsif::stmts, and value.

Referenced by exec_stmts().

◆ exec_stmt_loop()

static int exec_stmt_loop ( PLpgSQL_execstate estate,
PLpgSQL_stmt_loop stmt 
)
static

Definition at line 2627 of file pl_exec.c.

2628 {
2629  int rc = PLPGSQL_RC_OK;
2630 
2631  for (;;)
2632  {
2633  rc = exec_stmts(estate, stmt->body);
2634 
2635  LOOP_RC_PROCESSING(stmt->label, break);
2636  }
2637 
2638  return rc;
2639 }

References exec_stmts(), LOOP_RC_PROCESSING, PLPGSQL_RC_OK, and stmt.

Referenced by exec_stmts().

◆ exec_stmt_open()

static int exec_stmt_open ( PLpgSQL_execstate estate,
PLpgSQL_stmt_open stmt 
)
static

Definition at line 4661 of file pl_exec.c.

4662 {
4663  PLpgSQL_var *curvar;
4664  MemoryContext stmt_mcontext = NULL;
4665  char *curname = NULL;
4666  PLpgSQL_expr *query;
4667  Portal portal;
4668  ParamListInfo paramLI;
4669 
4670  /* ----------
4671  * Get the cursor variable and if it has an assigned name, check
4672  * that it's not in use currently.
4673  * ----------
4674  */
4675  curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
4676  if (!curvar->isnull)
4677  {
4678  MemoryContext oldcontext;
4679 
4680  /* We only need stmt_mcontext to hold the cursor name string */
4681  stmt_mcontext = get_stmt_mcontext(estate);
4682  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
4683  curname = TextDatumGetCString(curvar->value);
4684  MemoryContextSwitchTo(oldcontext);
4685 
4686  if (SPI_cursor_find(curname) != NULL)
4687  ereport(ERROR,
4688  (errcode(ERRCODE_DUPLICATE_CURSOR),
4689  errmsg("cursor \"%s\" already in use", curname)));
4690  }
4691 
4692  /* ----------
4693  * Process the OPEN according to it's type.
4694  * ----------
4695  */
4696  if (stmt->query != NULL)
4697  {
4698  /* ----------
4699  * This is an OPEN refcursor FOR SELECT ...
4700  *
4701  * We just make sure the query is planned. The real work is
4702  * done downstairs.
4703  * ----------
4704  */
4705  query = stmt->query;
4706  if (query->plan == NULL)
4707  exec_prepare_plan(estate, query, stmt->cursor_options);
4708  }
4709  else if (stmt->dynquery != NULL)
4710  {
4711  /* ----------
4712  * This is an OPEN refcursor FOR EXECUTE ...
4713  * ----------
4714  */
4715  portal = exec_dynquery_with_params(estate,
4716  stmt->dynquery,
4717  stmt->params,
4718  curname,
4719  stmt->cursor_options);
4720 
4721  /*
4722  * If cursor variable was NULL, store the generated portal name in it,
4723  * after verifying it's okay to assign to.
4724  *
4725  * Note: exec_dynquery_with_params already reset the stmt_mcontext, so
4726  * curname is a dangling pointer here; but testing it for nullness is
4727  * OK.
4728  */
4729  if (curname == NULL)
4730  {
4731  exec_check_assignable(estate, stmt->curvar);
4732  assign_text_var(estate, curvar, portal->name);
4733  }
4734 
4735  return PLPGSQL_RC_OK;
4736  }
4737  else
4738  {
4739  /* ----------
4740  * This is an OPEN cursor
4741  *
4742  * Note: parser should already have checked that statement supplies
4743  * args iff cursor needs them, but we check again to be safe.
4744  * ----------
4745  */
4746  if (stmt->argquery != NULL)
4747  {
4748  /* ----------
4749  * OPEN CURSOR with args. We fake a SELECT ... INTO ...
4750  * statement to evaluate the args and put 'em into the
4751  * internal row.
4752  * ----------
4753  */
4754  PLpgSQL_stmt_execsql set_args;
4755 
4756  if (curvar->cursor_explicit_argrow < 0)
4757  ereport(ERROR,
4758  (errcode(ERRCODE_SYNTAX_ERROR),
4759  errmsg("arguments given for cursor without arguments")));
4760 
4761  memset(&set_args, 0, sizeof(set_args));
4762  set_args.cmd_type = PLPGSQL_STMT_EXECSQL;
4763  set_args.lineno = stmt->lineno;
4764  set_args.sqlstmt = stmt->argquery;
4765  set_args.into = true;
4766  /* XXX historically this has not been STRICT */
4767  set_args.target = (PLpgSQL_variable *)
4768  (estate->datums[curvar->cursor_explicit_argrow]);
4769 
4770  if (exec_stmt_execsql(estate, &set_args) != PLPGSQL_RC_OK)
4771  elog(ERROR, "open cursor failed during argument processing");
4772  }
4773  else
4774  {
4775  if (curvar->cursor_explicit_argrow >= 0)
4776  ereport(ERROR,
4777  (errcode(ERRCODE_SYNTAX_ERROR),
4778  errmsg("arguments required for cursor")));
4779  }
4780 
4781  query = curvar->cursor_explicit_expr;
4782  if (query->plan == NULL)
4783  exec_prepare_plan(estate, query, curvar->cursor_options);
4784  }
4785 
4786  /*
4787  * Set up ParamListInfo for this query
4788  */
4789  paramLI = setup_param_list(estate, query);
4790 
4791  /*
4792  * Open the cursor (the paramlist will get copied into the portal)
4793  */
4794  portal = SPI_cursor_open_with_paramlist(curname, query->plan,
4795  paramLI,
4796  estate->readonly_func);
4797  if (portal == NULL)
4798  elog(ERROR, "could not open cursor: %s",
4800 
4801  /*
4802  * If cursor variable was NULL, store the generated portal name in it,
4803  * after verifying it's okay to assign to.
4804  */
4805  if (curname == NULL)
4806  {
4807  exec_check_assignable(estate, stmt->curvar);
4808  assign_text_var(estate, curvar, portal->name);
4809  }
4810 
4811  /* If we had any transient data, clean it up */
4812  exec_eval_cleanup(estate);
4813  if (stmt_mcontext)
4814  MemoryContextReset(stmt_mcontext);
4815 
4816  return PLPGSQL_RC_OK;
4817 }

References assign_text_var(), PLpgSQL_stmt_execsql::cmd_type, PLpgSQL_var::cursor_explicit_argrow, PLpgSQL_var::cursor_explicit_expr, PLpgSQL_var::cursor_options, PLpgSQL_execstate::datums, elog, ereport, errcode(), errmsg(), ERROR, exec_check_assignable(), exec_dynquery_with_params(), exec_eval_cleanup(), exec_prepare_plan(), exec_stmt_execsql(), get_stmt_mcontext(), PLpgSQL_stmt_execsql::into, PLpgSQL_var::isnull, PLpgSQL_stmt_execsql::lineno, MemoryContextReset(), MemoryContextSwitchTo(), PortalData::name, PLpgSQL_expr::plan, PLPGSQL_RC_OK, PLPGSQL_STMT_EXECSQL, PLpgSQL_execstate::readonly_func, setup_param_list(), SPI_cursor_find(), SPI_cursor_open_with_paramlist(), SPI_result, SPI_result_code_string(), PLpgSQL_stmt_execsql::sqlstmt, stmt, PLpgSQL_stmt_execsql::target, TextDatumGetCString, and PLpgSQL_var::value.

Referenced by exec_stmts().

◆ exec_stmt_perform()

static int exec_stmt_perform ( PLpgSQL_execstate estate,
PLpgSQL_stmt_perform stmt 
)
static

Definition at line 2164 of file pl_exec.c.

2165 {
2166  PLpgSQL_expr *expr = stmt->expr;
2167 
2168  (void) exec_run_select(estate, expr, 0, NULL);
2169  exec_set_found(estate, (estate->eval_processed != 0));
2170  exec_eval_cleanup(estate);
2171 
2172  return PLPGSQL_RC_OK;
2173 }

References PLpgSQL_execstate::eval_processed, exec_eval_cleanup(), exec_run_select(), exec_set_found(), PLPGSQL_RC_OK, and stmt.

Referenced by exec_stmts().

◆ exec_stmt_raise()

static int exec_stmt_raise ( PLpgSQL_execstate estate,
PLpgSQL_stmt_raise stmt 
)
static

Definition at line 3723 of file pl_exec.c.

3724 {
3725  int err_code = 0;
3726  char *condname = NULL;
3727  char *err_message = NULL;
3728  char *err_detail = NULL;
3729  char *err_hint = NULL;
3730  char *err_column = NULL;
3731  char *err_constraint = NULL;
3732  char *err_datatype = NULL;
3733  char *err_table = NULL;
3734  char *err_schema = NULL;
3735  MemoryContext stmt_mcontext;
3736  ListCell *lc;
3737 
3738  /* RAISE with no parameters: re-throw current exception */
3739  if (stmt->condname == NULL && stmt->message == NULL &&
3740  stmt->options == NIL)
3741  {
3742  if (estate->cur_error != NULL)
3743  ReThrowError(estate->cur_error);
3744  /* oops, we're not inside a handler */
3745  ereport(ERROR,
3746  (errcode(ERRCODE_STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER),
3747  errmsg("RAISE without parameters cannot be used outside an exception handler")));
3748  }
3749 
3750  /* We'll need to accumulate the various strings in stmt_mcontext */
3751  stmt_mcontext = get_stmt_mcontext(estate);
3752 
3753  if (stmt->condname)
3754  {
3755  err_code = plpgsql_recognize_err_condition(stmt->condname, true);
3756  condname = MemoryContextStrdup(stmt_mcontext, stmt->condname);
3757  }
3758 
3759  if (stmt->message)
3760  {
3761  StringInfoData ds;
3762  ListCell *current_param;
3763  char *cp;
3764  MemoryContext oldcontext;
3765 
3766  /* build string in stmt_mcontext */
3767  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
3768  initStringInfo(&ds);
3769  MemoryContextSwitchTo(oldcontext);
3770 
3771  current_param = list_head(stmt->params);
3772 
3773  for (cp = stmt->message; *cp; cp++)
3774  {
3775  /*
3776  * Occurrences of a single % are replaced by the next parameter's
3777  * external representation. Double %'s are converted to one %.
3778  */
3779  if (cp[0] == '%')
3780  {
3781  Oid paramtypeid;
3782  int32 paramtypmod;
3783  Datum paramvalue;
3784  bool paramisnull;
3785  char *extval;
3786 
3787  if (cp[1] == '%')
3788  {
3789  appendStringInfoChar(&ds, '%');
3790  cp++;
3791  continue;
3792  }
3793 
3794  /* should have been checked at compile time */
3795  if (current_param == NULL)
3796  elog(ERROR, "unexpected RAISE parameter list length");
3797 
3798  paramvalue = exec_eval_expr(estate,
3799  (PLpgSQL_expr *) lfirst(current_param),
3800  &paramisnull,
3801  &paramtypeid,
3802  &paramtypmod);
3803 
3804  if (paramisnull)
3805  extval = "<NULL>";
3806  else
3807  extval = convert_value_to_string(estate,
3808  paramvalue,
3809  paramtypeid);
3810  appendStringInfoString(&ds, extval);
3811  current_param = lnext(stmt->params, current_param);
3812  exec_eval_cleanup(estate);
3813  }
3814  else
3815  appendStringInfoChar(&ds, cp[0]);
3816  }
3817 
3818  /* should have been checked at compile time */
3819  if (current_param != NULL)
3820  elog(ERROR, "unexpected RAISE parameter list length");
3821 
3822  err_message = ds.data;
3823  }
3824 
3825  foreach(lc, stmt->options)
3826  {
3828  Datum optionvalue;
3829  bool optionisnull;
3830  Oid optiontypeid;
3831  int32 optiontypmod;
3832  char *extval;
3833 
3834  optionvalue = exec_eval_expr(estate, opt->expr,
3835  &optionisnull,
3836  &optiontypeid,
3837  &optiontypmod);
3838  if (optionisnull)
3839  ereport(ERROR,
3840  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
3841  errmsg("RAISE statement option cannot be null")));
3842 
3843  extval = convert_value_to_string(estate, optionvalue, optiontypeid);
3844 
3845  switch (opt->opt_type)
3846  {
3848  if (err_code)
3849  ereport(ERROR,
3850  (errcode(ERRCODE_SYNTAX_ERROR),
3851  errmsg("RAISE option already specified: %s",
3852  "ERRCODE")));
3853  err_code = plpgsql_recognize_err_condition(extval, true);
3854  condname = MemoryContextStrdup(stmt_mcontext, extval);
3855  break;
3857  SET_RAISE_OPTION_TEXT(err_message, "MESSAGE");
3858  break;
3860  SET_RAISE_OPTION_TEXT(err_detail, "DETAIL");
3861  break;
3863  SET_RAISE_OPTION_TEXT(err_hint, "HINT");
3864  break;
3866  SET_RAISE_OPTION_TEXT(err_column, "COLUMN");
3867  break;
3869  SET_RAISE_OPTION_TEXT(err_constraint, "CONSTRAINT");
3870  break;
3872  SET_RAISE_OPTION_TEXT(err_datatype, "DATATYPE");
3873  break;
3875  SET_RAISE_OPTION_TEXT(err_table, "TABLE");
3876  break;
3878  SET_RAISE_OPTION_TEXT(err_schema, "SCHEMA");
3879  break;
3880  default:
3881  elog(ERROR, "unrecognized raise option: %d", opt->opt_type);
3882  }
3883 
3884  exec_eval_cleanup(estate);
3885  }
3886 
3887  /* Default code if nothing specified */
3888  if (err_code == 0 && stmt->elog_level >= ERROR)
3889  err_code = ERRCODE_RAISE_EXCEPTION;
3890 
3891  /* Default error message if nothing specified */
3892  if (err_message == NULL)
3893  {
3894  if (condname)
3895  {
3896  err_message = condname;
3897  condname = NULL;
3898  }
3899  else
3900  err_message = MemoryContextStrdup(stmt_mcontext,
3901  unpack_sql_state(err_code));
3902  }
3903 
3904  /*
3905  * Throw the error (may or may not come back)
3906  */
3907  ereport(stmt->elog_level,
3908  (err_code ? errcode(err_code) : 0,
3909  errmsg_internal("%s", err_message),
3910  (err_detail != NULL) ? errdetail_internal("%s", err_detail) : 0,
3911  (err_hint != NULL) ? errhint("%s", err_hint) : 0,
3912  (err_column != NULL) ?
3913  err_generic_string(PG_DIAG_COLUMN_NAME, err_column) : 0,
3914  (err_constraint != NULL) ?
3915  err_generic_string(PG_DIAG_CONSTRAINT_NAME, err_constraint) : 0,
3916  (err_datatype != NULL) ?
3917  err_generic_string(PG_DIAG_DATATYPE_NAME, err_datatype) : 0,
3918  (err_table != NULL) ?
3919  err_generic_string(PG_DIAG_TABLE_NAME, err_table) : 0,
3920  (err_schema != NULL) ?
3921  err_generic_string(PG_DIAG_SCHEMA_NAME, err_schema) : 0));
3922 
3923  /* Clean up transient strings */
3924  MemoryContextReset(stmt_mcontext);
3925 
3926  return PLPGSQL_RC_OK;
3927 }
int err_generic_string(int field, const char *str)
Definition: elog.c:1512
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
int plpgsql_recognize_err_condition(const char *condname, bool allow_sqlstate)
Definition: pl_comp.c:2208
#define SET_RAISE_OPTION_TEXT(opt, name)
Definition: pl_exec.c:3708
@ PLPGSQL_RAISEOPTION_COLUMN
Definition: plpgsql.h:173
@ PLPGSQL_RAISEOPTION_TABLE
Definition: plpgsql.h:176
@ PLPGSQL_RAISEOPTION_SCHEMA
Definition: plpgsql.h:177
@ PLPGSQL_RAISEOPTION_CONSTRAINT
Definition: plpgsql.h:174
@ PLPGSQL_RAISEOPTION_DETAIL
Definition: plpgsql.h:171
@ PLPGSQL_RAISEOPTION_MESSAGE
Definition: plpgsql.h:170
@ PLPGSQL_RAISEOPTION_HINT
Definition: plpgsql.h:172
@ PLPGSQL_RAISEOPTION_ERRCODE
Definition: plpgsql.h:169
@ PLPGSQL_RAISEOPTION_DATATYPE
Definition: plpgsql.h:175
#define PG_DIAG_SCHEMA_NAME
Definition: postgres_ext.h:64
#define PG_DIAG_CONSTRAINT_NAME
Definition: postgres_ext.h:68
#define PG_DIAG_DATATYPE_NAME
Definition: postgres_ext.h:67
#define PG_DIAG_TABLE_NAME
Definition: postgres_ext.h:65
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:66
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:179
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:191
void initStringInfo(StringInfo str)
Definition: stringinfo.c:56
PLpgSQL_raise_option_type opt_type
Definition: plpgsql.h:872
PLpgSQL_expr * expr
Definition: plpgsql.h:873

References appendStringInfoChar(), appendStringInfoString(), convert_value_to_string(), PLpgSQL_execstate::cur_error, StringInfoData::data, elog, ereport, err_generic_string(), errcode(), errdetail_internal(), errhint(), errmsg(), errmsg_internal(), ERROR, exec_eval_cleanup(), exec_eval_expr(), PLpgSQL_raise_option::expr, get_stmt_mcontext(), initStringInfo(), lfirst, list_head(), lnext(), MemoryContextReset(), MemoryContextStrdup(), MemoryContextSwitchTo(), NIL, PLpgSQL_raise_option::opt_type, PG_DIAG_COLUMN_NAME, PG_DIAG_CONSTRAINT_NAME, PG_DIAG_DATATYPE_NAME, PG_DIAG_SCHEMA_NAME, PG_DIAG_TABLE_NAME, PLPGSQL_RAISEOPTION_COLUMN, PLPGSQL_RAISEOPTION_CONSTRAINT, PLPGSQL_RAISEOPTION_DATATYPE, PLPGSQL_RAISEOPTION_DETAIL, PLPGSQL_RAISEOPTION_ERRCODE, PLPGSQL_RAISEOPTION_HINT, PLPGSQL_RAISEOPTION_MESSAGE, PLPGSQL_RAISEOPTION_SCHEMA, PLPGSQL_RAISEOPTION_TABLE, PLPGSQL_RC_OK, plpgsql_recognize_err_condition(), ReThrowError(), SET_RAISE_OPTION_TEXT, stmt, and unpack_sql_state().

Referenced by exec_stmts().

◆ exec_stmt_return()

static int exec_stmt_return ( PLpgSQL_execstate estate,
PLpgSQL_stmt_return stmt 
)
static

Definition at line 3181 of file pl_exec.c.

3182 {
3183  /*
3184  * If processing a set-returning PL/pgSQL function, the final RETURN
3185  * indicates that the function is finished producing tuples. The rest of
3186  * the work will be done at the top level.
3187  */
3188  if (estate->retisset)
3189  return PLPGSQL_RC_RETURN;
3190 
3191  /* initialize for null result */
3192  estate->retval = (Datum) 0;
3193  estate->retisnull = true;
3194  estate->rettype = InvalidOid;
3195 
3196  /*
3197  * Special case path when the RETURN expression is a simple variable
3198  * reference; in particular, this path is always taken in functions with
3199  * one or more OUT parameters.
3200  *
3201  * This special case is especially efficient for returning variables that
3202  * have R/W expanded values: we can put the R/W pointer directly into
3203  * estate->retval, leading to transferring the value to the caller's
3204  * context cheaply. If we went through exec_eval_expr we'd end up with a
3205  * R/O pointer. It's okay to skip MakeExpandedObjectReadOnly here since
3206  * we know we won't need the variable's value within the function anymore.
3207  */
3208  if (stmt->retvarno >= 0)
3209  {
3210  PLpgSQL_datum *retvar = estate->datums[stmt->retvarno];
3211 
3212  switch (retvar->dtype)
3213  {
3214  case PLPGSQL_DTYPE_PROMISE:
3215  /* fulfill promise if needed, then handle like regular var */
3216  plpgsql_fulfill_promise(estate, (PLpgSQL_var *) retvar);
3217 
3218  /* FALL THRU */
3219 
3220  case PLPGSQL_DTYPE_VAR:
3221  {
3222  PLpgSQL_var *var = (PLpgSQL_var *) retvar;
3223 
3224  estate->retval = var->value;
3225  estate->retisnull = var->isnull;
3226  estate->rettype = var->datatype->typoid;
3227 
3228  /*
3229  * A PLpgSQL_var could not be of composite type, so
3230  * conversion must fail if retistuple. We throw a custom
3231  * error mainly for consistency with historical behavior.
3232  * For the same reason, we don't throw error if the result
3233  * is NULL. (Note that plpgsql_exec_trigger assumes that
3234  * any non-null result has been verified to be composite.)
3235  */
3236  if (estate->retistuple && !estate->retisnull)
3237  ereport(ERROR,
3238  (errcode(ERRCODE_DATATYPE_MISMATCH),
3239  errmsg("cannot return non-composite value from function returning composite type")));
3240  }
3241  break;
3242 
3243  case PLPGSQL_DTYPE_REC:
3244  {
3245  PLpgSQL_rec *rec = (PLpgSQL_rec *) retvar;
3246 
3247  /* If record is empty, we return NULL not a row of nulls */
3248  if (rec->erh && !ExpandedRecordIsEmpty(rec->erh))
3249  {
3250  estate->retval = ExpandedRecordGetDatum(rec->erh);
3251  estate->retisnull = false;
3252  estate->rettype = rec->rectypeid;
3253  }
3254  }
3255  break;
3256 
3257  case PLPGSQL_DTYPE_ROW:
3258  {
3259  PLpgSQL_row *row = (PLpgSQL_row *) retvar;
3260  int32 rettypmod;
3261 
3262  /* We get here if there are multiple OUT parameters */
3263  exec_eval_datum(estate,
3264  (PLpgSQL_datum *) row,
3265  &estate->rettype,
3266  &rettypmod,
3267  &estate->retval,
3268  &estate->retisnull);
3269  }
3270  break;
3271 
3272  default:
3273  elog(ERROR, "unrecognized dtype: %d", retvar->dtype);
3274  }
3275 
3276  return PLPGSQL_RC_RETURN;
3277  }
3278 
3279  if (stmt->expr != NULL)
3280  {
3281  int32 rettypmod;
3282 
3283  estate->retval = exec_eval_expr(estate, stmt->expr,
3284  &(estate->retisnull),
3285  &(estate->rettype),
3286  &rettypmod);
3287 
3288  /*
3289  * As in the DTYPE_VAR case above, throw a custom error if a non-null,
3290  * non-composite value is returned in a function returning tuple.
3291  */
3292  if (estate->retistuple && !estate->retisnull &&
3293  !type_is_rowtype(estate->rettype))
3294  ereport(ERROR,
3295  (errcode(ERRCODE_DATATYPE_MISMATCH),
3296  errmsg("cannot return non-composite value from function returning composite type")));
3297 
3298  return PLPGSQL_RC_RETURN;
3299  }
3300 
3301  /*
3302  * Special hack for function returning VOID: instead of NULL, return a
3303  * non-null VOID value. This is of dubious importance but is kept for
3304  * backwards compatibility. We don't do it for procedures, though.
3305  */
3306  if (estate->fn_rettype == VOIDOID &&
3307  estate->func->fn_prokind != PROKIND_PROCEDURE)
3308  {
3309  estate->retval = (Datum) 0;
3310  estate->retisnull = false;
3311  estate->rettype = VOIDOID;
3312  }
3313 
3314  return PLPGSQL_RC_RETURN;
3315 }
static void exec_eval_datum(PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeid, int32 *typetypmod, Datum *value, bool *isnull)
Definition: pl_exec.c:5306

References PLpgSQL_var::datatype, PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, PLpgSQL_var::dtype, elog, ereport, PLpgSQL_rec::erh, errcode(), errmsg(), ERROR, exec_eval_datum(), exec_eval_expr(), ExpandedRecordGetDatum(), ExpandedRecordIsEmpty, PLpgSQL_function::fn_prokind, PLpgSQL_execstate::fn_rettype, PLpgSQL_execstate::func, InvalidOid, PLpgSQL_var::isnull, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, plpgsql_fulfill_promise(), PLPGSQL_RC_RETURN, PLpgSQL_rec::rectypeid, PLpgSQL_execstate::retisnull, PLpgSQL_execstate::retisset, PLpgSQL_execstate::retistuple, PLpgSQL_execstate::rettype, PLpgSQL_execstate::retval, stmt, type_is_rowtype(), PLpgSQL_type::typoid, and PLpgSQL_var::value.

Referenced by exec_stmts().

◆ exec_stmt_return_next()

static int exec_stmt_return_next ( PLpgSQL_execstate estate,
PLpgSQL_stmt_return_next stmt 
)
static

Definition at line 3324 of file pl_exec.c.

3326 {
3327  TupleDesc tupdesc;
3328  int natts;
3329  HeapTuple tuple;
3330  MemoryContext oldcontext;
3331 
3332  if (!estate->retisset)
3333  ereport(ERROR,
3334  (errcode(ERRCODE_SYNTAX_ERROR),
3335  errmsg("cannot use RETURN NEXT in a non-SETOF function")));
3336 
3337  if (estate->tuple_store == NULL)
3338  exec_init_tuple_store(estate);
3339 
3340  /* tuple_store_desc will be filled by exec_init_tuple_store */
3341  tupdesc = estate->tuple_store_desc;
3342  natts = tupdesc->natts;
3343 
3344  /*
3345  * Special case path when the RETURN NEXT expression is a simple variable
3346  * reference; in particular, this path is always taken in functions with
3347  * one or more OUT parameters.
3348  *
3349  * Unlike exec_stmt_return, there's no special win here for R/W expanded
3350  * values, since they'll have to get flattened to go into the tuplestore.
3351  * Indeed, we'd better make them R/O to avoid any risk of the casting step
3352  * changing them in-place.
3353  */
3354  if (stmt->retvarno >= 0)
3355  {
3356  PLpgSQL_datum *retvar = estate->datums[stmt->retvarno];
3357 
3358  switch (retvar->dtype)
3359  {
3360  case PLPGSQL_DTYPE_PROMISE:
3361  /* fulfill promise if needed, then handle like regular var */
3362  plpgsql_fulfill_promise(estate, (PLpgSQL_var *) retvar);
3363 
3364  /* FALL THRU */
3365 
3366  case PLPGSQL_DTYPE_VAR:
3367  {
3368  PLpgSQL_var *var = (PLpgSQL_var *) retvar;
3369  Datum retval = var->value;
3370  bool isNull = var->isnull;
3371  Form_pg_attribute attr = TupleDescAttr(tupdesc, 0);
3372 
3373  if (natts != 1)
3374  ereport(ERROR,
3375  (errcode(ERRCODE_DATATYPE_MISMATCH),
3376  errmsg("wrong result type supplied in RETURN NEXT")));
3377 
3378  /* let's be very paranoid about the cast step */
3379  retval = MakeExpandedObjectReadOnly(retval,
3380  isNull,
3381  var->datatype->typlen);
3382 
3383  /* coerce type if needed */
3384  retval = exec_cast_value(estate,
3385  retval,
3386  &isNull,
3387  var->datatype->typoid,
3388  var->datatype->atttypmod,
3389  attr->atttypid,
3390  attr->atttypmod);
3391 
3392  tuplestore_putvalues(estate->tuple_store, tupdesc,
3393  &retval, &isNull);
3394  }
3395  break;
3396 
3397  case PLPGSQL_DTYPE_REC:
3398  {
3399  PLpgSQL_rec *rec = (PLpgSQL_rec *) retvar;
3400  TupleDesc rec_tupdesc;
3401  TupleConversionMap *tupmap;
3402 
3403  /* If rec is null, try to convert it to a row of nulls */
3404  if (rec->erh == NULL)
3405  instantiate_empty_record_variable(estate, rec);
3406  if (ExpandedRecordIsEmpty(rec->erh))
3408 
3409  /* Use eval_mcontext for tuple conversion work */
3410  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
3411  rec_tupdesc = expanded_record_get_tupdesc(rec->erh);
3412  tupmap = convert_tuples_by_position(rec_tupdesc,
3413  tupdesc,
3414  gettext_noop("wrong record type supplied in RETURN NEXT"));
3415  tuple = expanded_record_get_tuple(rec->erh);
3416  if (tupmap)
3417  tuple = execute_attr_map_tuple(tuple, tupmap);
3418  tuplestore_puttuple(estate->tuple_store, tuple);
3419  MemoryContextSwitchTo(oldcontext);
3420  }
3421  break;
3422 
3423  case PLPGSQL_DTYPE_ROW:
3424  {
3425  PLpgSQL_row *row = (PLpgSQL_row *) retvar;
3426 
3427  /* We get here if there are multiple OUT parameters */
3428 
3429  /* Use eval_mcontext for tuple conversion work */
3430  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
3431  tuple = make_tuple_from_row(estate, row, tupdesc);
3432  if (tuple == NULL) /* should not happen */
3433  ereport(ERROR,
3434  (errcode(ERRCODE_DATATYPE_MISMATCH),
3435  errmsg("wrong record type supplied in RETURN NEXT")));
3436  tuplestore_puttuple(estate->tuple_store, tuple);
3437  MemoryContextSwitchTo(oldcontext);
3438  }
3439  break;
3440 
3441  default:
3442  elog(ERROR, "unrecognized dtype: %d", retvar->dtype);
3443  break;
3444  }
3445  }
3446  else if (stmt->expr)
3447  {
3448  Datum retval;
3449  bool isNull;
3450  Oid rettype;
3451  int32 rettypmod;
3452 
3453  retval = exec_eval_expr(estate,
3454  stmt->expr,
3455  &isNull,
3456  &rettype,
3457  &rettypmod);
3458 
3459  if (estate->retistuple)
3460  {
3461  /* Expression should be of RECORD or composite type */
3462  if (!isNull)
3463  {
3464  HeapTupleData tmptup;
3465  TupleDesc retvaldesc;
3466  TupleConversionMap *tupmap;
3467 
3468  if (!type_is_rowtype(rettype))
3469  ereport(ERROR,
3470  (errcode(ERRCODE_DATATYPE_MISMATCH),
3471  errmsg("cannot return non-composite value from function returning composite type")));
3472 
3473  /* Use eval_mcontext for tuple conversion work */
3474  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
3475  retvaldesc = deconstruct_composite_datum(retval, &tmptup);
3476  tuple = &tmptup;
3477  tupmap = convert_tuples_by_position(retvaldesc, tupdesc,
3478  gettext_noop("returned record type does not match expected record type"));
3479  if (tupmap)
3480  tuple = execute_attr_map_tuple(tuple, tupmap);
3481  tuplestore_puttuple(estate->tuple_store, tuple);
3482  ReleaseTupleDesc(retvaldesc);
3483  MemoryContextSwitchTo(oldcontext);
3484  }
3485  else
3486  {
3487  /* Composite NULL --- store a row of nulls */
3488  Datum *nulldatums;
3489  bool *nullflags;
3490 
3491  nulldatums = (Datum *)
3492  eval_mcontext_alloc0(estate, natts * sizeof(Datum));
3493  nullflags = (bool *)
3494  eval_mcontext_alloc(estate, natts * sizeof(bool));
3495  memset(nullflags, true, natts * sizeof(bool));
3496  tuplestore_putvalues(estate->tuple_store, tupdesc,
3497  nulldatums, nullflags);
3498  }
3499  }
3500  else
3501  {
3502  Form_pg_attribute attr = TupleDescAttr(tupdesc, 0);
3503 
3504  /* Simple scalar result */
3505  if (natts != 1)
3506  ereport(ERROR,
3507  (errcode(ERRCODE_DATATYPE_MISMATCH),
3508  errmsg("wrong result type supplied in RETURN NEXT")));
3509 
3510  /* coerce type if needed */
3511  retval = exec_cast_value(estate,
3512  retval,
3513  &isNull,
3514  rettype,
3515  rettypmod,
3516  attr->atttypid,
3517  attr->atttypmod);
3518 
3519  tuplestore_putvalues(estate->tuple_store, tupdesc,
3520  &retval, &isNull);
3521  }
3522  }
3523  else
3524  {
3525  ereport(ERROR,
3526  (errcode(ERRCODE_SYNTAX_ERROR),
3527  errmsg("RETURN NEXT must have a parameter")));
3528  }
3529 
3530  exec_eval_cleanup(estate);
3531 
3532  return PLPGSQL_RC_OK;
3533 }
#define MakeExpandedObjectReadOnly(d, isnull, typlen)
static void exec_init_tuple_store(PLpgSQL_execstate *estate)
Definition: pl_exec.c:3667
#define eval_mcontext_alloc0(estate, sz)
Definition: pl_exec.c:130
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:784
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition: tuplestore.c:764

References PLpgSQL_type::atttypmod, convert_tuples_by_position(), PLpgSQL_var::datatype, PLpgSQL_execstate::datums, deconstruct_composite_datum(), deconstruct_expanded_record(), PLpgSQL_datum::dtype, PLpgSQL_var::dtype, elog, ereport, PLpgSQL_rec::erh, errcode(), errmsg(), ERROR, eval_mcontext_alloc, eval_mcontext_alloc0, exec_cast_value(), exec_eval_cleanup(), exec_eval_expr(), exec_init_tuple_store(), execute_attr_map_tuple(), expanded_record_get_tupdesc(), expanded_record_get_tuple(), ExpandedRecordIsEmpty, get_eval_mcontext, gettext_noop, instantiate_empty_record_variable(), PLpgSQL_var::isnull, make_tuple_from_row(), MakeExpandedObjectReadOnly, MemoryContextSwitchTo(), TupleDescData::natts, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, plpgsql_fulfill_promise(), PLPGSQL_RC_OK, ReleaseTupleDesc, PLpgSQL_execstate::retisset, PLpgSQL_execstate::retistuple, stmt, PLpgSQL_execstate::tuple_store, PLpgSQL_execstate::tuple_store_desc, TupleDescAttr, tuplestore_puttuple(), tuplestore_putvalues(), type_is_rowtype(), PLpgSQL_type::typlen, PLpgSQL_type::typoid, and PLpgSQL_var::value.

Referenced by exec_stmts().

◆ exec_stmt_return_query()

static int exec_stmt_return_query ( PLpgSQL_execstate estate,
PLpgSQL_stmt_return_query stmt 
)
static

Definition at line 3542 of file pl_exec.c.

3544 {
3545  int64 tcount;
3546  DestReceiver *treceiver;
3547  int rc;
3548  uint64 processed;
3549  MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
3550  MemoryContext oldcontext;
3551 
3552  if (!estate->retisset)
3553  ereport(ERROR,
3554  (errcode(ERRCODE_SYNTAX_ERROR),
3555  errmsg("cannot use RETURN QUERY in a non-SETOF function")));
3556 
3557  if (estate->tuple_store == NULL)
3558  exec_init_tuple_store(estate);
3559  /* There might be some tuples in the tuplestore already */
3560  tcount = tuplestore_tuple_count(estate->tuple_store);
3561 
3562  /*
3563  * Set up DestReceiver to transfer results directly to tuplestore,
3564  * converting rowtype if necessary. DestReceiver lives in mcontext.
3565  */
3566  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
3567  treceiver = CreateDestReceiver(DestTuplestore);
3569  estate->tuple_store,
3570  estate->tuple_store_cxt,
3571  false,
3572  estate->tuple_store_desc,
3573  gettext_noop("structure of query does not match function result type"));
3574  MemoryContextSwitchTo(oldcontext);
3575 
3576  if (stmt->query != NULL)
3577  {
3578  /* static query */
3579  PLpgSQL_expr *expr = stmt->query;
3580  ParamListInfo paramLI;
3582 
3583  /*
3584  * On the first call for this expression generate the plan.
3585  */
3586  if (expr->plan == NULL)
3588 
3589  /*
3590  * Set up ParamListInfo to pass to executor
3591  */
3592  paramLI = setup_param_list(estate, expr);
3593 
3594  /*
3595  * Execute the query
3596  */
3597  memset(&options, 0, sizeof(options));
3598  options.params = paramLI;
3599  options.read_only = estate->readonly_func;
3600  options.must_return_tuples = true;
3601  options.dest = treceiver;
3602 
3603  rc = SPI_execute_plan_extended(expr->plan, &options);
3604  if (rc < 0)
3605  elog(ERROR, "SPI_execute_plan_extended failed executing query \"%s\": %s",
3606  expr->query, SPI_result_code_string(rc));
3607  }
3608  else
3609  {
3610  /* RETURN QUERY EXECUTE */
3611  Datum query;
3612  bool isnull;
3613  Oid restype;
3614  int32 restypmod;
3615  char *querystr;
3617 
3618  /*
3619  * Evaluate the string expression after the EXECUTE keyword. Its
3620  * result is the querystring we have to execute.
3621  */
3622  Assert(stmt->dynquery != NULL);
3623  query = exec_eval_expr(estate, stmt->dynquery,
3624  &isnull, &restype, &restypmod);
3625  if (isnull)
3626  ereport(ERROR,
3627  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
3628  errmsg("query string argument of EXECUTE is null")));
3629 
3630  /* Get the C-String representation */
3631  querystr = convert_value_to_string(estate, query, restype);
3632 
3633  /* copy it into the stmt_mcontext before we clean up */
3634  querystr = MemoryContextStrdup(stmt_mcontext, querystr);
3635 
3636  exec_eval_cleanup(estate);
3637 
3638  /* Execute query, passing params if necessary */
3639  memset(&options, 0, sizeof(options));
3640  options.params = exec_eval_using_params(estate,
3641  stmt->params);
3642  options.read_only = estate->readonly_func;
3643  options.must_return_tuples = true;
3644  options.dest = treceiver;
3645 
3646  rc = SPI_execute_extended(querystr, &options);
3647  if (rc < 0)
3648  elog(ERROR, "SPI_execute_extended failed executing query \"%s\": %s",
3649  querystr, SPI_result_code_string(rc));
3650  }
3651 
3652  /* Clean up */
3653  treceiver->rDestroy(treceiver);
3654  exec_eval_cleanup(estate);
3655  MemoryContextReset(stmt_mcontext);
3656 
3657  /* Count how many tuples we got */
3658  processed = tuplestore_tuple_count(estate->tuple_store) - tcount;
3659 
3660  estate->eval_processed = processed;
3661  exec_set_found(estate, processed != 0);
3662 
3663  return PLPGSQL_RC_OK;
3664 }
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:113
@ DestTuplestore
Definition: dest.h:93
void(* rDestroy)(DestReceiver *self)
Definition: dest.h:126
void SetTuplestoreDestReceiverParams(DestReceiver *self, Tuplestorestate *tStore, MemoryContext tContext, bool detoast, TupleDesc target_tupdesc, const char *map_failure_msg)
int64 tuplestore_tuple_count(Tuplestorestate *state)
Definition: tuplestore.c:580

References Assert, convert_value_to_string(), CreateDestReceiver(), CURSOR_OPT_PARALLEL_OK, DestTuplestore, elog, ereport, errcode(), errmsg(), ERROR, PLpgSQL_execstate::eval_processed, exec_eval_cleanup(), exec_eval_expr(), exec_eval_using_params(), exec_init_tuple_store(), exec_prepare_plan(), exec_set_found(), get_stmt_mcontext(), gettext_noop, MemoryContextReset(), MemoryContextStrdup(), MemoryContextSwitchTo(), options, PLpgSQL_expr::plan, PLPGSQL_RC_OK, PLpgSQL_expr::query, _DestReceiver::rDestroy, PLpgSQL_execstate::readonly_func, PLpgSQL_execstate::retisset, SetTuplestoreDestReceiverParams(), setup_param_list(), SPI_execute_extended(), SPI_execute_plan_extended(), SPI_result_code_string(), stmt, PLpgSQL_execstate::tuple_store, PLpgSQL_execstate::tuple_store_cxt, PLpgSQL_execstate::tuple_store_desc, and tuplestore_tuple_count().

Referenced by exec_stmts().

◆ exec_stmt_rollback()

static int exec_stmt_rollback ( PLpgSQL_execstate estate,
PLpgSQL_stmt_rollback stmt 
)
static

Definition at line 4984 of file pl_exec.c.

4985 {
4986  if (stmt->chain)
4988  else
4989  SPI_rollback();
4990 
4991  /*
4992  * We need to build new simple-expression infrastructure, since the old
4993  * data structures are gone.
4994  */
4995  estate->simple_eval_estate = NULL;
4996  estate->simple_eval_resowner = NULL;
4997  plpgsql_create_econtext(estate);
4998 
4999  return PLPGSQL_RC_OK;
5000 }
void SPI_rollback_and_chain(void)
Definition: spi.c:419
void SPI_rollback(void)
Definition: spi.c:413

References plpgsql_create_econtext(), PLPGSQL_RC_OK, PLpgSQL_execstate::simple_eval_estate, PLpgSQL_execstate::simple_eval_resowner, SPI_rollback(), SPI_rollback_and_chain(), and stmt.

Referenced by exec_stmts().

◆ exec_stmt_while()

static int exec_stmt_while ( PLpgSQL_execstate estate,
PLpgSQL_stmt_while stmt 
)
static

Definition at line 2649 of file pl_exec.c.

2650 {
2651  int rc = PLPGSQL_RC_OK;
2652 
2653  for (;;)
2654  {
2655  bool value;
2656  bool isnull;
2657 
2658  value = exec_eval_boolean(estate, stmt->cond, &isnull);
2659  exec_eval_cleanup(estate);
2660 
2661  if (isnull || !value)
2662  break;
2663 
2664  rc = exec_stmts(estate, stmt->body);
2665 
2666  LOOP_RC_PROCESSING(stmt->label, break);
2667  }
2668 
2669  return rc;
2670 }

References exec_eval_boolean(), exec_eval_cleanup(), exec_stmts(), LOOP_RC_PROCESSING, PLPGSQL_RC_OK, stmt, and value.

Referenced by exec_stmts().

◆ exec_stmts()

static int exec_stmts ( PLpgSQL_execstate estate,
List stmts 
)
static

Definition at line 1980 of file pl_exec.c.

1981 {
1982  PLpgSQL_stmt *save_estmt = estate->err_stmt;
1983  ListCell *s;
1984 
1985  if (stmts == NIL)
1986  {
1987  /*
1988  * Ensure we do a CHECK_FOR_INTERRUPTS() even though there is no
1989  * statement. This prevents hangup in a tight loop if, for instance,
1990  * there is a LOOP construct with an empty body.
1991  */
1993  return PLPGSQL_RC_OK;
1994  }
1995 
1996  foreach(s, stmts)
1997  {
1999  int rc;
2000 
2001  estate->err_stmt = stmt;
2002 
2003  /* Let the plugin know that we are about to execute this statement */
2004  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
2005  ((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt);
2006 
2008 
2009  switch (stmt->cmd_type)
2010  {
2011  case PLPGSQL_STMT_BLOCK:
2012  rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt);
2013  break;
2014 
2015  case PLPGSQL_STMT_ASSIGN:
2016  rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
2017  break;
2018 
2019  case PLPGSQL_STMT_PERFORM:
2020  rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt);
2021  break;
2022 
2023  case PLPGSQL_STMT_CALL:
2024  rc = exec_stmt_call(estate, (PLpgSQL_stmt_call *) stmt);
2025  break;
2026 
2027  case PLPGSQL_STMT_GETDIAG:
2028  rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt);
2029  break;
2030 
2031  case PLPGSQL_STMT_IF:
2032  rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);
2033  break;
2034 
2035  case PLPGSQL_STMT_CASE:
2036  rc = exec_stmt_case(estate, (PLpgSQL_stmt_case *) stmt);
2037  break;
2038 
2039  case PLPGSQL_STMT_LOOP:
2040  rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt);
2041  break;
2042 
2043  case PLPGSQL_STMT_WHILE:
2044  rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt);
2045  break;
2046 
2047  case PLPGSQL_STMT_FORI:
2048  rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt);
2049  break;
2050 
2051  case PLPGSQL_STMT_FORS:
2052  rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt);
2053  break;
2054 
2055  case PLPGSQL_STMT_FORC:
2056  rc = exec_stmt_forc(estate, (PLpgSQL_stmt_forc *) stmt);
2057  break;
2058 
2061  break;
2062 
2063  case PLPGSQL_STMT_EXIT:
2064  rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt);
2065  break;
2066 
2067  case PLPGSQL_STMT_RETURN:
2068  rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt);
2069  break;
2070 
2073  break;
2074 
2077  break;
2078 
2079  case PLPGSQL_STMT_RAISE:
2080  rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt);
2081  break;
2082 
2083  case PLPGSQL_STMT_ASSERT:
2084  rc = exec_stmt_assert(estate, (PLpgSQL_stmt_assert *) stmt);
2085  break;
2086 
2087  case PLPGSQL_STMT_EXECSQL:
2088  rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt);
2089  break;
2090 
2093  break;
2094 
2095  case PLPGSQL_STMT_DYNFORS:
2096  rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt);
2097  break;
2098 
2099  case PLPGSQL_STMT_OPEN:
2100  rc = exec_stmt_open(estate, (PLpgSQL_stmt_open *) stmt);
2101  break;
2102 
2103  case PLPGSQL_STMT_FETCH:
2104  rc = exec_stmt_fetch(estate, (PLpgSQL_stmt_fetch *) stmt);
2105  break;
2106 
2107  case PLPGSQL_STMT_CLOSE:
2108  rc = exec_stmt_close(estate, (PLpgSQL_stmt_close *) stmt);
2109  break;
2110 
2111  case PLPGSQL_STMT_COMMIT:
2112  rc = exec_stmt_commit(estate, (PLpgSQL_stmt_commit *) stmt);
2113  break;
2114 
2115  case PLPGSQL_STMT_ROLLBACK:
2116  rc = exec_stmt_rollback(estate, (PLpgSQL_stmt_rollback *) stmt);
2117  break;
2118 
2119  default:
2120  /* point err_stmt to parent, since this one seems corrupt */
2121  estate->err_stmt = save_estmt;
2122  elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
2123  rc = -1; /* keep compiler quiet */
2124  }
2125 
2126  /* Let the plugin know that we have finished executing this statement */
2127  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
2128  ((*plpgsql_plugin_ptr)->stmt_end) (estate, stmt);
2129 
2130  if (rc != PLPGSQL_RC_OK)
2131  {
2132  estate->err_stmt = save_estmt;
2133  return rc;
2134  }
2135  } /* end of loop over statements */
2136 
2137  estate->err_stmt = save_estmt;
2138  return PLPGSQL_RC_OK;
2139 }
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
static int exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
Definition: pl_exec.c:2823
static int exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
Definition: pl_exec.c:4826
static int exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
Definition: pl_exec.c:1647
static int exec_stmt_commit(PLpgSQL_execstate *estate, PLpgSQL_stmt_commit *stmt)
Definition: pl_exec.c:4960
static int exec_stmt_forc(PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt)
Definition: pl_exec.c:2852
static int exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt)
Definition: pl_exec.c:2992
static int exec_stmt_rollback(PLpgSQL_execstate *estate, PLpgSQL_stmt_rollback *stmt)
Definition: pl_exec.c:4984
static int exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
Definition: pl_exec.c:3181
static int exec_stmt_exit(PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt)
Definition: pl_exec.c:3148
static int exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
Definition: pl_exec.c:3723
static int exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
Definition: pl_exec.c:2627
static int exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
Definition: pl_exec.c:4661
static int exec_stmt_dynexecute(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynexecute *stmt)
Definition: pl_exec.c:4444
static int exec_stmt_assert(PLpgSQL_execstate *estate, PLpgSQL_stmt_assert *stmt)
Definition: pl_exec.c:3934
static int exec_stmt_return_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_return_query *stmt)
Definition: pl_exec.c:3542
static int exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
Definition: pl_exec.c:2181
static int exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
Definition: pl_exec.c:2680
static int exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
Definition: pl_exec.c:2510
static int exec_stmt_case(PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
Definition: pl_exec.c:2540
static int exec_stmt_return_next(PLpgSQL_execstate *estate, PLpgSQL_stmt_return_next *stmt)
Definition: pl_exec.c:3324
static int exec_stmt_assign(PLpgSQL_execstate *estate, PLpgSQL_stmt_assign *stmt)
Definition: pl_exec.c:2148
static int exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
Definition: pl_exec.c:4634
static int exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
Definition: pl_exec.c:2394
static int exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
Definition: pl_exec.c:2649
static int exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
Definition: pl_exec.c:2164
static int exec_stmt_close(PLpgSQL_execstate *estate, PLpgSQL_stmt_close *stmt)
Definition: pl_exec.c:4917
PLpgSQL_plugin ** plpgsql_plugin_ptr
Definition: pl_handler.c:56
@ PLPGSQL_STMT_DYNFORS
Definition: plpgsql.h:122
@ PLPGSQL_STMT_FORI
Definition: plpgsql.h:110
@ PLPGSQL_STMT_FETCH
Definition: plpgsql.h:125
@ PLPGSQL_STMT_CASE
Definition: plpgsql.h:107
@ PLPGSQL_STMT_OPEN
Definition: plpgsql.h:124
@ PLPGSQL_STMT_ROLLBACK
Definition: plpgsql.h:130
@ PLPGSQL_STMT_COMMIT
Definition: plpgsql.h:129
@ PLPGSQL_STMT_RETURN_QUERY
Definition: plpgsql.h:117
@ PLPGSQL_STMT_RETURN
Definition: plpgsql.h:115
@ PLPGSQL_STMT_CLOSE
Definition: plpgsql.h:126
@ PLPGSQL_STMT_WHILE
Definition: plpgsql.h:109
@ PLPGSQL_STMT_BLOCK
Definition: plpgsql.h:104
@ PLPGSQL_STMT_FORS
Definition: plpgsql.h:111
@ PLPGSQL_STMT_FORC
Definition: plpgsql.h:112
@ PLPGSQL_STMT_IF
Definition: plpgsql.h:106
@ PLPGSQL_STMT_PERFORM
Definition: plpgsql.h:127
@ PLPGSQL_STMT_LOOP
Definition: plpgsql.h:108
@ PLPGSQL_STMT_ASSERT
Definition: plpgsql.h:119
@ PLPGSQL_STMT_FOREACH_A
Definition: plpgsql.h:113
@ PLPGSQL_STMT_GETDIAG
Definition: plpgsql.h:123
@ PLPGSQL_STMT_RETURN_NEXT
Definition: plpgsql.h:116
@ PLPGSQL_STMT_ASSIGN
Definition: plpgsql.h:105
@ PLPGSQL_STMT_EXIT
Definition: plpgsql.h:114
@ PLPGSQL_STMT_RAISE
Definition: plpgsql.h:118
@ PLPGSQL_STMT_CALL
Definition: plpgsql.h:128
@ PLPGSQL_STMT_DYNEXECUTE
Definition: plpgsql.h:121
PLpgSQL_stmt * err_stmt
Definition: plpgsql.h:1090
void(* stmt_end)(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
Definition: plpgsql.h:1140
void(* stmt_beg)(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
Definition: plpgsql.h:1139

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

Referenced by exec_for_query(), exec_stmt_block(), exec_stmt_case(), exec_stmt_foreach_a(), exec_stmt_fori(), exec_stmt_if(), exec_stmt_loop(), and exec_stmt_while().

◆ exec_toplevel_block()

static int exec_toplevel_block ( PLpgSQL_execstate estate,
PLpgSQL_stmt_block block 
)
static

Definition at line 1618 of file pl_exec.c.

1619 {
1620  int rc;
1621 
1622  estate->err_stmt = (PLpgSQL_stmt *) block;
1623 
1624  /* Let the plugin know that we are about to execute this statement */
1625  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
1626  ((*plpgsql_plugin_ptr)->stmt_beg) (estate, (PLpgSQL_stmt *) block);
1627 
1629 
1630  rc = exec_stmt_block(estate, block);
1631 
1632  /* Let the plugin know that we have finished executing this statement */
1633  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
1634  ((*plpgsql_plugin_ptr)->stmt_end) (estate, (PLpgSQL_stmt *) block);
1635 
1636  estate->err_stmt = NULL;
1637 
1638  return rc;
1639 }

References CHECK_FOR_INTERRUPTS, PLpgSQL_execstate::err_stmt, exec_stmt_block(), plpgsql_plugin_ptr, PLpgSQL_plugin::stmt_beg, and PLpgSQL_plugin::stmt_end.

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

◆ format_expr_params()

static char * format_expr_params ( PLpgSQL_execstate estate,
const PLpgSQL_expr expr 
)
static

Definition at line 8793 of file pl_exec.c.

8795 {
8796  int paramno;
8797  int dno;
8798  StringInfoData paramstr;
8799  MemoryContext oldcontext;
8800 
8801  if (!expr->paramnos)
8802  return NULL;
8803 
8804  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
8805 
8806  initStringInfo(&paramstr);
8807  paramno = 0;
8808  dno = -1;
8809  while ((dno = bms_next_member(expr->paramnos, dno)) >= 0)
8810  {
8811  Datum paramdatum;
8812  Oid paramtypeid;
8813  bool paramisnull;
8814  int32 paramtypmod;
8815  PLpgSQL_var *curvar;
8816 
8817  curvar = (PLpgSQL_var *) estate->datums[dno];
8818 
8819  exec_eval_datum(estate, (PLpgSQL_datum *) curvar,
8820  &paramtypeid, &paramtypmod,
8821  &paramdatum, &paramisnull);
8822 
8823  appendStringInfo(&paramstr, "%s%s = ",
8824  paramno > 0 ? ", " : "",
8825  curvar->refname);
8826 
8827  if (paramisnull)
8828  appendStringInfoString(&paramstr, "NULL");
8829  else
8830  appendStringInfoStringQuoted(&paramstr,
8831  convert_value_to_string(estate,
8832  paramdatum,
8833  paramtypeid),
8834  -1);
8835 
8836  paramno++;
8837  }
8838 
8839  MemoryContextSwitchTo(oldcontext);
8840 
8841  return paramstr.data;
8842 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:94
void appendStringInfoStringQuoted(StringInfo str, const char *s, int maxlen)
Definition: stringinfo_mb.c:34

References appendStringInfo(), appendStringInfoString(), appendStringInfoStringQuoted(), bms_next_member(), convert_value_to_string(), StringInfoData::data, PLpgSQL_execstate::datums, exec_eval_datum(), get_eval_mcontext, initStringInfo(), MemoryContextSwitchTo(), PLpgSQL_expr::paramnos, and PLpgSQL_var::refname.

Referenced by exec_stmt_execsql().

◆ format_preparedparamsdata()

static char * format_preparedparamsdata ( PLpgSQL_execstate estate,
ParamListInfo  paramLI 
)
static

Definition at line 8850 of file pl_exec.c.

8852 {
8853  int paramno;
8854  StringInfoData paramstr;
8855  MemoryContext oldcontext;
8856 
8857  if (!paramLI)
8858  return NULL;
8859 
8860  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
8861 
8862  initStringInfo(&paramstr);
8863  for (paramno = 0; paramno < paramLI->numParams; paramno++)
8864  {
8865  ParamExternData *prm = &paramLI->params[paramno];
8866 
8867  /*
8868  * Note: for now, this is only used on ParamListInfos produced by
8869  * exec_eval_using_params(), so we don't worry about invoking the
8870  * paramFetch hook or skipping unused parameters.
8871  */
8872  appendStringInfo(&paramstr, "%s$%d = ",
8873  paramno > 0 ? ", " : "",
8874  paramno + 1);
8875 
8876  if (prm->isnull)
8877  appendStringInfoString(&paramstr, "NULL");
8878  else
8879  appendStringInfoStringQuoted(&paramstr,
8880  convert_value_to_string(estate,
8881  prm->value,
8882  prm->ptype),
8883  -1);
8884  }
8885 
8886  MemoryContextSwitchTo(oldcontext);
8887 
8888  return paramstr.data;
8889 }

References appendStringInfo(), appendStringInfoString(), appendStringInfoStringQuoted(), convert_value_to_string(), StringInfoData::data, get_eval_mcontext, initStringInfo(), ParamExternData::isnull, MemoryContextSwitchTo(), ParamListInfoData::numParams, ParamListInfoData::params, ParamExternData::ptype, and ParamExternData::value.

Referenced by exec_stmt_dynexecute().

◆ get_cast_hashentry()

static plpgsql_CastHashEntry * get_cast_hashentry ( PLpgSQL_execstate estate,
Oid  srctype,
int32  srctypmod,
Oid  dsttype,
int32  dsttypmod 
)
static

Definition at line 7788 of file pl_exec.c.

7791 {
7792  plpgsql_CastHashKey cast_key;
7793  plpgsql_CastHashEntry *cast_entry;
7794  plpgsql_CastExprHashEntry *expr_entry;
7795  bool found;
7796  LocalTransactionId curlxid;
7797  MemoryContext oldcontext;
7798 
7799  /* Look for existing entry */
7800  cast_key.srctype = srctype;
7801  cast_key.dsttype = dsttype;
7802  cast_key.srctypmod = srctypmod;
7803  cast_key.dsttypmod = dsttypmod;
7804  cast_entry = (plpgsql_CastHashEntry *) hash_search(estate->cast_hash,
7805  &cast_key,
7806  HASH_ENTER, &found);
7807  if (!found) /* initialize if new entry */
7808  {
7809  /* We need a second lookup to see if a cast_expr_hash entry exists */
7811  &cast_key,
7812  HASH_ENTER,
7813  &found);
7814  if (!found) /* initialize if new expr entry */
7815  expr_entry->cast_cexpr = NULL;
7816 
7817  cast_entry->cast_centry = expr_entry;
7818  cast_entry->cast_exprstate = NULL;
7819  cast_entry->cast_in_use = false;
7820  cast_entry->cast_lxid = InvalidLocalTransactionId;
7821  }
7822  else
7823  {
7824  /* Use always-valid link to avoid a second hash lookup */
7825  expr_entry = cast_entry->cast_centry;
7826  }
7827 
7828  if (expr_entry->cast_cexpr == NULL ||
7829  !expr_entry->cast_cexpr->is_valid)
7830  {
7831  /*
7832  * We've not looked up this coercion before, or we have but the cached
7833  * expression has been invalidated.
7834  */
7835  Node *cast_expr;
7836  CachedExpression *cast_cexpr;
7837  CaseTestExpr *placeholder;
7838 
7839  /*
7840  * Drop old cached expression if there is one.
7841  */
7842  if (expr_entry->cast_cexpr)
7843  {
7844  FreeCachedExpression(expr_entry->cast_cexpr);
7845  expr_entry->cast_cexpr = NULL;
7846  }
7847 
7848  /*
7849  * Since we could easily fail (no such coercion), construct a
7850  * temporary coercion expression tree in the short-lived
7851  * eval_mcontext, then if successful save it as a CachedExpression.
7852  */
7853  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7854 
7855  /*
7856  * We use a CaseTestExpr as the base of the coercion tree, since it's
7857  * very cheap to insert the source value for that.
7858  */
7859  placeholder = makeNode(CaseTestExpr);
7860  placeholder->typeId = srctype;
7861  placeholder->typeMod = srctypmod;
7862  placeholder->collation = get_typcollation(srctype);
7863 
7864  /*
7865  * Apply coercion. We use the special coercion context
7866  * COERCION_PLPGSQL to match plpgsql's historical behavior, namely
7867  * that any cast not available at ASSIGNMENT level will be implemented
7868  * as an I/O coercion. (It's somewhat dubious that we prefer I/O
7869  * coercion over cast pathways that exist at EXPLICIT level. Changing
7870  * that would cause assorted minor behavioral differences though, and
7871  * a user who wants the explicit-cast behavior can always write an
7872  * explicit cast.)
7873  *
7874  * If source type is UNKNOWN, coerce_to_target_type will fail (it only
7875  * expects to see that for Const input nodes), so don't call it; we'll
7876  * apply CoerceViaIO instead. Likewise, it doesn't currently work for
7877  * coercing RECORD to some other type, so skip for that too.
7878  */
7879  if (srctype == UNKNOWNOID || srctype == RECORDOID)
7880  cast_expr = NULL;
7881  else
7882  cast_expr = coerce_to_target_type(NULL,
7883  (Node *) placeholder, srctype,
7884  dsttype, dsttypmod,
7887  -1);
7888 
7889  /*
7890  * If there's no cast path according to the parser, fall back to using
7891  * an I/O coercion; this is semantically dubious but matches plpgsql's
7892  * historical behavior. We would need something of the sort for
7893  * UNKNOWN literals in any case. (This is probably now only reachable
7894  * in the case where srctype is UNKNOWN/RECORD.)
7895  */
7896  if (cast_expr == NULL)
7897  {
7898  CoerceViaIO *iocoerce = makeNode(CoerceViaIO);
7899 
7900  iocoerce->arg = (Expr *) placeholder;
7901  iocoerce->resulttype = dsttype;
7902  iocoerce->resultcollid = InvalidOid;
7903  iocoerce->coerceformat = COERCE_IMPLICIT_CAST;
7904  iocoerce->location = -1;
7905  cast_expr = (Node *) iocoerce;
7906  if (dsttypmod != -1)
7907  cast_expr = coerce_to_target_type(NULL,
7908  cast_expr, dsttype,
7909  dsttype, dsttypmod,
7912  -1);
7913  }
7914 
7915  /* Note: we don't bother labeling the expression tree with collation */
7916 
7917  /* Plan the expression and build a CachedExpression */
7918  cast_cexpr = GetCachedExpression(cast_expr);
7919  cast_expr = cast_cexpr->expr;
7920 
7921  /* Detect whether we have a no-op (RelabelType) coercion */
7922  if (IsA(cast_expr, RelabelType) &&
7923  ((RelabelType *) cast_expr)->arg == (Expr *) placeholder)
7924  cast_expr = NULL;
7925 
7926  /* Now we can fill in the expression hashtable entry. */
7927  expr_entry->cast_cexpr = cast_cexpr;
7928  expr_entry->cast_expr = (Expr *) cast_expr;
7929 
7930  /* Be sure to reset the exprstate hashtable entry, too. */
7931  cast_entry->cast_exprstate = NULL;
7932  cast_entry->cast_in_use = false;
7933  cast_entry->cast_lxid = InvalidLocalTransactionId;
7934 
7935  MemoryContextSwitchTo(oldcontext);
7936  }
7937 
7938  /* Done if we have determined that this is a no-op cast. */
7939  if (expr_entry->cast_expr == NULL)
7940  return NULL;
7941 
7942  /*
7943  * Prepare the expression for execution, if it's not been done already in
7944  * the current transaction; also, if it's marked busy in the current
7945  * transaction, abandon that expression tree and build a new one, so as to
7946  * avoid potential problems with recursive cast expressions and failed
7947  * executions. (We will leak some memory intra-transaction if that
7948  * happens a lot, but we don't expect it to.) It's okay to update the
7949  * hash table with the new tree because all plpgsql functions within a
7950  * given transaction share the same simple_eval_estate. (Well, regular
7951  * functions do; DO blocks have private simple_eval_estates, and private
7952  * cast hash tables to go with them.)
7953  */
7954  curlxid = MyProc->vxid.lxid;
7955  if (cast_entry->cast_lxid != curlxid || cast_entry->cast_in_use)
7956  {
7957  oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
7958  cast_entry->cast_exprstate = ExecInitExpr(expr_entry->cast_expr, NULL);
7959  cast_entry->cast_in_use = false;
7960  cast_entry->cast_lxid = curlxid;
7961  MemoryContextSwitchTo(oldcontext);
7962  }
7963 
7964  return cast_entry;
7965 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:138
@ HASH_ENTER
Definition: hsearch.h:114
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3056
#define makeNode(_type_)
Definition: nodes.h:155
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
static HTAB * cast_expr_hash
Definition: pl_exec.c:177
void FreeCachedExpression(CachedExpression *cexpr)
Definition: plancache.c:1734
CachedExpression * GetCachedExpression(Node *expr)
Definition: plancache.c:1677
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:736
@ COERCION_PLPGSQL
Definition: primnodes.h:716
@ COERCION_ASSIGNMENT
Definition: primnodes.h:715
Expr * arg
Definition: primnodes.h:1207
ParseLoc location
Definition: primnodes.h:1214
Oid resulttype
Definition: primnodes.h:1208
HTAB * cast_hash
Definition: plpgsql.h:1078
CachedExpression * cast_cexpr
Definition: pl_exec.c:164
LocalTransactionId cast_lxid
Definition: pl_exec.c:174
plpgsql_CastExprHashEntry * cast_centry
Definition: pl_exec.c:170

References arg, CoerceViaIO::arg, plpgsql_CastHashEntry::cast_centry, plpgsql_CastExprHashEntry::cast_cexpr, plpgsql_CastExprHashEntry::cast_expr, cast_expr_hash, plpgsql_CastHashEntry::cast_exprstate, PLpgSQL_execstate::cast_hash, plpgsql_CastHashEntry::cast_in_use, plpgsql_CastHashEntry::cast_lxid, COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, COERCION_PLPGSQL, plpgsql_CastHashKey::dsttype, plpgsql_CastHashKey::dsttypmod, EState::es_query_cxt, ExecInitExpr(), CachedExpression::expr, FreeCachedExpression(), get_eval_mcontext, get_typcollation(), GetCachedExpression(), HASH_ENTER, hash_search(), InvalidLocalTransactionId, InvalidOid, CachedExpression::is_valid, IsA, CoerceViaIO::location, PGPROC::lxid, makeNode, MemoryContextSwitchTo(), MyProc, CoerceViaIO::resulttype, PLpgSQL_execstate::simple_eval_estate, plpgsql_CastHashKey::srctype, plpgsql_CastHashKey::srctypmod, CaseTestExpr::typeId, and PGPROC::vxid.

Referenced by do_cast_value().

◆ get_stmt_mcontext()

static MemoryContext get_stmt_mcontext ( PLpgSQL_execstate estate)
static

Definition at line 1528 of file pl_exec.c.

1529 {
1530  if (estate->stmt_mcontext == NULL)
1531  {
1532  estate->stmt_mcontext =
1534  "PLpgSQL per-statement data",
1536  }
1537  return estate->stmt_mcontext;
1538 }
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, PLpgSQL_execstate::stmt_mcontext, and PLpgSQL_execstate::stmt_mcontext_parent.

Referenced by exec_dynquery_with_params(), exec_eval_using_params(), exec_stmt_block(), exec_stmt_dynexecute(), exec_stmt_forc(), exec_stmt_foreach_a(), exec_stmt_open(), exec_stmt_raise(), and exec_stmt_return_query().

◆ instantiate_empty_record_variable()

static void instantiate_empty_record_variable ( PLpgSQL_execstate estate,
PLpgSQL_rec rec 
)
static

Definition at line 7656 of file pl_exec.c.

7657 {
7658  Assert(rec->erh == NULL); /* else caller error */
7659 
7660  /* If declared type is RECORD, we can't instantiate */
7661  if (rec->rectypeid == RECORDOID)
7662  ereport(ERROR,
7663  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7664  errmsg("record \"%s\" is not assigned yet", rec->refname),
7665  errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
7666 
7667  /* Make sure rec->rectypeid is up-to-date before using it */
7668  revalidate_rectypeid(rec);
7669 
7670  /* OK, do it */
7672  estate->datum_context);
7673 }

References Assert, PLpgSQL_execstate::datum_context, ereport, PLpgSQL_rec::erh, errcode(), errdetail(), errmsg(), ERROR, make_expanded_record_from_typeid(), PLpgSQL_rec::rectypeid, PLpgSQL_rec::refname, and revalidate_rectypeid().

Referenced by exec_assign_value(), exec_eval_datum(), exec_stmt_return_next(), plpgsql_exec_get_datum_type(), plpgsql_exec_get_datum_type_info(), and plpgsql_param_eval_recfield().

◆ make_callstmt_target()

static PLpgSQL_variable * make_callstmt_target ( PLpgSQL_execstate estate,
PLpgSQL_expr expr 
)
static

Definition at line 2273 of file pl_exec.c.

2274 {
2275  CachedPlan *cplan;
2276  PlannedStmt *pstmt;
2277  CallStmt *stmt;
2278  FuncExpr *funcexpr;
2279  HeapTuple func_tuple;
2280  Oid *argtypes;
2281  char **argnames;
2282  char *argmodes;
2283  int numargs;
2284  MemoryContext oldcontext;
2285  PLpgSQL_row *row;
2286  int nfields;
2287  int i;
2288 
2289  /* Use eval_mcontext for any cruft accumulated here */
2290  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
2291 
2292  /*
2293  * Get the parsed CallStmt, and look up the called procedure. We use
2294  * SPI_plan_get_cached_plan to cover the edge case where expr->plan is
2295  * already stale and needs to be updated.
2296  */
2297  cplan = SPI_plan_get_cached_plan(expr->plan);
2298  if (cplan == NULL || list_length(cplan->stmt_list) != 1)
2299  elog(ERROR, "query for CALL statement is not a CallStmt");
2300  pstmt = linitial_node(PlannedStmt, cplan->stmt_list);
2301  stmt = (CallStmt *) pstmt->utilityStmt;
2302  if (stmt == NULL || !IsA(stmt, CallStmt))
2303  elog(ERROR, "query for CALL statement is not a CallStmt");
2304 
2305  funcexpr = stmt->funcexpr;
2306 
2307  func_tuple = SearchSysCache1(PROCOID,
2308  ObjectIdGetDatum(funcexpr->funcid));
2309  if (!HeapTupleIsValid(func_tuple))
2310  elog(ERROR, "cache lookup failed for function %u",
2311  funcexpr->funcid);
2312 
2313  /*
2314  * Get the argument names and modes, so that we can deliver on-point error
2315  * messages when something is wrong.
2316  */
2317  numargs = get_func_arg_info(func_tuple, &argtypes, &argnames, &argmodes);
2318 
2319  ReleaseSysCache(func_tuple);
2320 
2321  /*
2322  * Begin constructing row Datum; keep it in fn_cxt so it's adequately
2323  * long-lived.
2324  */
2325  MemoryContextSwitchTo(estate->func->fn_cxt);
2326 
2327  row = (PLpgSQL_row *) palloc0(sizeof(PLpgSQL_row));
2328  row->dtype = PLPGSQL_DTYPE_ROW;
2329  row->refname = "(unnamed row)";
2330  row->lineno = -1;
2331  row->varnos = (int *) palloc(numargs * sizeof(int));
2332 
2334 
2335  /*
2336  * Examine procedure's argument list. Each output arg position should be
2337  * an unadorned plpgsql variable (Datum), which we can insert into the row
2338  * Datum.
2339  */
2340  nfields = 0;
2341  for (i = 0; i < numargs; i++)
2342  {
2343  if (argmodes &&
2344  (argmodes[i] == PROARGMODE_INOUT ||
2345  argmodes[i] == PROARGMODE_OUT))
2346  {
2347  Node *n = list_nth(stmt->outargs, nfields);
2348 
2349  if (IsA(n, Param))
2350  {
2351  Param *param = (Param *) n;
2352  int dno;
2353 
2354  /* paramid is offset by 1 (see make_datum_param()) */
2355  dno = param->paramid - 1;
2356  /* must check assignability now, because grammar can't */
2357  exec_check_assignable(estate, dno);
2358  row->varnos[nfields++] = dno;
2359  }
2360  else
2361  {
2362  /* report error using parameter name, if available */
2363  if (argnames && argnames[i] && argnames[i][0])
2364  ereport(ERROR,
2365  (errcode(ERRCODE_SYNTAX_ERROR),
2366  errmsg("procedure parameter \"%s\" is an output parameter but corresponding argument is not writable",
2367  argnames[i])));
2368  else
2369  ereport(ERROR,
2370  (errcode(ERRCODE_SYNTAX_ERROR),
2371  errmsg("procedure parameter %d is an output parameter but corresponding argument is not writable",
2372  i + 1)));
2373  }
2374  }
2375  }
2376 
2377  Assert(nfields == list_length(stmt->outargs));
2378 
2379  row->nfields = nfields;
2380 
2382 
2383  MemoryContextSwitchTo(oldcontext);
2384 
2385  return (PLpgSQL_variable *) row;
2386 }
int get_func_arg_info(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
Definition: funcapi.c:1379
void * palloc0(Size size)
Definition: mcxt.c:1347
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
MemoryContext fn_cxt
Definition: plpgsql.h:975
int lineno
Definition: plpgsql.h:368
PLpgSQL_datum_type dtype
Definition: plpgsql.h:365
char * refname
Definition: plpgsql.h:367
Node * utilityStmt
Definition: plannodes.h:95
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

References Assert, CurrentResourceOwner, PLpgSQL_row::dtype, elog, ereport, errcode(), errmsg(), ERROR, exec_check_assignable(), PLpgSQL_function::fn_cxt, PLpgSQL_execstate::func, FuncExpr::funcid, get_eval_mcontext, get_func_arg_info(), HeapTupleIsValid, i, if(), IsA, PLpgSQL_row::lineno, linitial_node, list_length(), list_nth(), MemoryContextSwitchTo(), PLpgSQL_row::nfields, ObjectIdGetDatum(), palloc(), palloc0(), Param::paramid, PLpgSQL_expr::plan, PLPGSQL_DTYPE_ROW, PLpgSQL_row::refname, ReleaseCachedPlan(), ReleaseSysCache(), SearchSysCache1(), SPI_plan_get_cached_plan(), stmt, CachedPlan::stmt_list, PlannedStmt::utilityStmt, and PLpgSQL_row::varnos.

Referenced by exec_stmt_call().

◆ make_expanded_record_for_rec()

static ExpandedRecordHeader * make_expanded_record_for_rec ( PLpgSQL_execstate estate,
PLpgSQL_rec rec,
TupleDesc  srctupdesc,
ExpandedRecordHeader srcerh 
)
static

Definition at line 6964 of file pl_exec.c.

6968 {
6969  ExpandedRecordHeader *newerh;
6970  MemoryContext mcontext = get_eval_mcontext(estate);
6971 
6972  if (rec->rectypeid != RECORDOID)
6973  {
6974  /*
6975  * Make sure rec->rectypeid is up-to-date before using it.
6976  */
6977  revalidate_rectypeid(rec);
6978 
6979  /*
6980  * New record must be of desired type, but maybe srcerh has already
6981  * done all the same lookups.
6982  */
6983  if (srcerh && rec->rectypeid == srcerh->er_decltypeid)
6984  newerh = make_expanded_record_from_exprecord(srcerh,
6985  mcontext);
6986  else
6987  newerh = make_expanded_record_from_typeid(rec->rectypeid, -1,
6988  mcontext);
6989  }
6990  else
6991  {
6992  /*
6993  * We'll adopt the input tupdesc. We can still use
6994  * make_expanded_record_from_exprecord, if srcerh isn't a composite
6995  * domain. (If it is, we effectively adopt its base type.)
6996  */
6997  if (srcerh && !ExpandedRecordIsDomain(srcerh))
6998  newerh = make_expanded_record_from_exprecord(srcerh,
6999  mcontext);
7000  else
7001  {
7002  if (!srctupdesc)
7003  srctupdesc = expanded_record_get_tupdesc(srcerh);
7004  newerh = make_expanded_record_from_tupdesc(srctupdesc,
7005  mcontext);
7006  }
7007  }
7008 
7009  return newerh;
7010 }
ExpandedRecordHeader * make_expanded_record_from_tupdesc(TupleDesc tupdesc, MemoryContext parentcontext)
ExpandedRecordHeader * make_expanded_record_from_exprecord(ExpandedRecordHeader *olderh, MemoryContext parentcontext)

References ExpandedRecordHeader::er_decltypeid, expanded_record_get_tupdesc(), ExpandedRecordIsDomain, get_eval_mcontext, make_expanded_record_from_exprecord(), make_expanded_record_from_tupdesc(), make_expanded_record_from_typeid(), PLpgSQL_rec::rectypeid, and revalidate_rectypeid().

Referenced by exec_move_row(), and exec_move_row_from_datum().

◆ make_tuple_from_row()

static HeapTuple make_tuple_from_row ( PLpgSQL_execstate estate,
PLpgSQL_row row,
TupleDesc  tupdesc 
)
static

Definition at line 7337 of file pl_exec.c.

7340 {
7341  int natts = tupdesc->natts;
7342  HeapTuple tuple;
7343  Datum *dvalues;
7344  bool *nulls;
7345  int i;
7346 
7347  if (natts != row->nfields)
7348  return NULL;
7349 
7350  dvalues = (Datum *) eval_mcontext_alloc0(estate, natts * sizeof(Datum));
7351  nulls = (bool *) eval_mcontext_alloc(estate, natts * sizeof(bool));
7352 
7353  for (i = 0; i < natts; i++)
7354  {
7355  Oid fieldtypeid;
7356  int32 fieldtypmod;
7357 
7358  if (TupleDescAttr(tupdesc, i)->attisdropped)
7359  {
7360  nulls[i] = true; /* leave the column as null */
7361  continue;
7362  }
7363 
7364  exec_eval_datum(estate, estate->datums[row->varnos[i]],
7365  &fieldtypeid, &fieldtypmod,
7366  &dvalues[i], &nulls[i]);
7367  if (fieldtypeid != TupleDescAttr(tupdesc, i)->atttypid)
7368  return NULL;
7369  /* XXX should we insist on typmod match, too? */
7370  }
7371 
7372  tuple = heap_form_tuple(tupdesc, dvalues, nulls);
7373 
7374  return tuple;
7375 }
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116

References PLpgSQL_execstate::datums, eval_mcontext_alloc, eval_mcontext_alloc0, exec_eval_datum(), heap_form_tuple(), i, TupleDescData::natts, PLpgSQL_row::nfields, TupleDescAttr, and PLpgSQL_row::varnos.

Referenced by exec_eval_datum(), and exec_stmt_return_next().

◆ plpgsql_create_econtext()

static void plpgsql_create_econtext ( PLpgSQL_execstate estate)
static

Definition at line 8391 of file pl_exec.c.

8392 {
8393  SimpleEcontextStackEntry *entry;
8394 
8395  /*
8396  * Create an EState for evaluation of simple expressions, if there's not
8397  * one already in the current transaction. The EState is made a child of
8398  * TopTransactionContext so it will have the right lifespan.
8399  *
8400  * Note that this path is never taken when beginning a DO block; the
8401  * required EState was already made by plpgsql_inline_handler. However,
8402  * if the DO block executes COMMIT or ROLLBACK, then we'll come here and
8403  * make a shared EState to use for the rest of the DO block. That's OK;
8404  * see the comments for shared_simple_eval_estate. (Note also that a DO
8405  * block will continue to use its private cast hash table for the rest of
8406  * the block. That's okay for now, but it might cause problems someday.)
8407  */
8408  if (estate->simple_eval_estate == NULL)
8409  {
8410  MemoryContext oldcontext;
8411 
8412  if (shared_simple_eval_estate == NULL)
8413  {
8416  MemoryContextSwitchTo(oldcontext);
8417  }
8419  }
8420 
8421  /*
8422  * Likewise for the simple-expression resource owner.
8423  */
8424  if (estate->simple_eval_resowner == NULL)
8425  {
8426  if (shared_simple_eval_resowner == NULL)
8429  "PL/pgSQL simple expressions");
8431  }
8432 
8433  /*
8434  * Create a child econtext for the current function.
8435  */
8437 
8438  /*
8439  * Make a stack entry so we can clean up the econtext at subxact end.
8440  * Stack entries are kept in TopTransactionContext for simplicity.
8441  */
8442  entry = (SimpleEcontextStackEntry *)
8444  sizeof(SimpleEcontextStackEntry));
8445 
8446  entry->stack_econtext = estate->eval_econtext;
8448 
8449  entry->next = simple_econtext_stack;
8450  simple_econtext_stack = entry;
8451 }
EState * CreateExecutorState(void)
Definition: execUtils.c:88
ExprContext * CreateExprContext(EState *estate)
Definition: execUtils.c:306
MemoryContext TopTransactionContext
Definition: mcxt.c:154
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
static ResourceOwner shared_simple_eval_resowner
Definition: pl_exec.c:101
static EState * shared_simple_eval_estate
Definition: pl_exec.c:90
static SimpleEcontextStackEntry * simple_econtext_stack
Definition: pl_exec.c:91
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:167
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition: resowner.c:413
struct SimpleEcontextStackEntry * next
Definition: pl_exec.c:87
ExprContext * stack_econtext
Definition: pl_exec.c:85
SubTransactionId xact_subxid
Definition: pl_exec.c:86
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:790

References CreateExecutorState(), CreateExprContext(), PLpgSQL_execstate::eval_econtext, GetCurrentSubTransactionId(), MemoryContextAlloc(), MemoryContextSwitchTo(), SimpleEcontextStackEntry::next, ResourceOwnerCreate(), shared_simple_eval_estate, shared_simple_eval_resowner, simple_econtext_stack, PLpgSQL_execstate::simple_eval_estate, PLpgSQL_execstate::simple_eval_resowner, SimpleEcontextStackEntry::stack_econtext, TopTransactionContext, TopTransactionResourceOwner, and SimpleEcontextStackEntry::xact_subxid.

Referenced by exec_stmt_block(), exec_stmt_call(), exec_stmt_commit(), exec_stmt_rollback(), and plpgsql_estate_setup().

◆ plpgsql_destroy_econtext()

static void plpgsql_destroy_econtext ( PLpgSQL_execstate estate)
static

Definition at line 8460 of file pl_exec.c.

8461 {
8463 
8464  Assert(simple_econtext_stack != NULL);
8466 
8470 
8471  FreeExprContext(estate->eval_econtext, true);
8472  estate->eval_econtext = NULL;
8473 }
static int32 next
Definition: blutils.c:219
void FreeExprContext(ExprContext *econtext, bool isCommit)
Definition: execUtils.c:416

References Assert, PLpgSQL_execstate::eval_econtext, FreeExprContext(), next, SimpleEcontextStackEntry::next, pfree(), simple_econtext_stack, and SimpleEcontextStackEntry::stack_econtext.

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

◆ plpgsql_estate_setup()

static void plpgsql_estate_setup ( PLpgSQL_execstate estate,
PLpgSQL_function func,
ReturnSetInfo rsi,
EState simple_eval_estate,
ResourceOwner  simple_eval_resowner 
)
static

Definition at line 3977 of file pl_exec.c.

3982 {
3983  HASHCTL ctl;
3984 
3985  /* this link will be restored at exit from plpgsql_call_handler */
3986  func->cur_estate = estate;
3987 
3988  estate->func = func;
3989  estate->trigdata = NULL;
3990  estate->evtrigdata = NULL;
3991 
3992  estate->retval = (Datum) 0;
3993  estate->retisnull = true;
3994  estate->rettype = InvalidOid;
3995 
3996  estate->fn_rettype = func->fn_rettype;
3997  estate->retistuple = func->fn_retistuple;
3998  estate->retisset = func->fn_retset;
3999 
4000  estate->readonly_func = func->fn_readonly;
4001  estate->atomic = true;
4002 
4003  estate->exitlabel = NULL;
4004  estate->cur_error = NULL;
4005 
4006  estate->tuple_store = NULL;
4007  estate->tuple_store_desc = NULL;
4008  if (rsi)
4009  {
4012  }
4013  else
4014  {
4015  estate->tuple_store_cxt = NULL;
4016  estate->tuple_store_owner = NULL;
4017  }
4018  estate->rsi = rsi;
4019 
4020  estate->found_varno = func->found_varno;
4021  estate->ndatums = func->ndatums;
4022  estate->datums = NULL;
4023  /* the datums array will be filled by copy_plpgsql_datums() */
4025 
4026  /* initialize our ParamListInfo with appropriate hook functions */
4027  estate->paramLI = makeParamList(0);
4029  estate->paramLI->paramFetchArg = (void *) estate;
4031  estate->paramLI->paramCompileArg = NULL; /* not needed */
4033  estate->paramLI->parserSetupArg = NULL; /* filled during use */
4034  estate->paramLI->numParams = estate->ndatums;
4035 
4036  /* Create the session-wide cast-expression hash if we didn't already */
4037  if (cast_expr_hash == NULL)
4038  {
4039  ctl.keysize = sizeof(plpgsql_CastHashKey);
4040  ctl.entrysize = sizeof(plpgsql_CastExprHashEntry);
4041  cast_expr_hash = hash_create("PLpgSQL cast expressions",
4042  16, /* start small and extend */
4043  &ctl,
4044  HASH_ELEM | HASH_BLOBS);
4045  }
4046 
4047  /* set up for use of appropriate simple-expression EState and cast hash */
4048  if (simple_eval_estate)
4049  {
4050  estate->simple_eval_estate = simple_eval_estate;
4051  /* Private cast hash just lives in function's main context */
4052  ctl.keysize = sizeof(plpgsql_CastHashKey);
4053  ctl.entrysize = sizeof(plpgsql_CastHashEntry);
4054  ctl.hcxt = CurrentMemoryContext;
4055  estate->cast_hash = hash_create("PLpgSQL private cast cache",
4056  16, /* start small and extend */
4057  &ctl,
4059  }
4060  else
4061  {
4063  /* Create the session-wide cast-info hash table if we didn't already */
4064  if (shared_cast_hash == NULL)
4065  {
4066  ctl.keysize = sizeof(plpgsql_CastHashKey);
4067  ctl.entrysize = sizeof(plpgsql_CastHashEntry);
4068  shared_cast_hash = hash_create("PLpgSQL cast cache",
4069  16, /* start small and extend */
4070  &ctl,
4071  HASH_ELEM | HASH_BLOBS);
4072  }
4073  estate->cast_hash = shared_cast_hash;
4074  }
4075  /* likewise for the simple-expression resource owner */
4076  if (simple_eval_resowner)
4077  estate->simple_eval_resowner = simple_eval_resowner;
4078  else
4080 
4081  /* if there's a procedure resowner, it'll be filled in later */
4082  estate->procedure_resowner = NULL;
4083 
4084  /*
4085  * We start with no stmt_mcontext; one will be created only if needed.
4086  * That context will be a direct child of the function's main execution
4087  * context. Additional stmt_mcontexts might be created as children of it.
4088  */
4089  estate->stmt_mcontext = NULL;
4091 
4092  estate->eval_tuptable = NULL;
4093  estate->eval_processed = 0;
4094  estate->eval_econtext = NULL;
4095 
4096  estate->err_stmt = NULL;
4097  estate->err_var = NULL;
4098  estate->err_text = NULL;
4099 
4100  estate->plugin_info = NULL;
4101 
4102  /*
4103  * Create an EState and ExprContext for evaluation of simple expressions.
4104  */
4105  plpgsql_create_econtext(estate);
4106 
4107  /*
4108  * Let the plugin, if any, see this function before we initialize local
4109  * PL/pgSQL variables. Note that we also give the plugin a few function
4110  * pointers, so it can call back into PL/pgSQL for doing things like
4111  * variable assignments and stack traces.
4112  */
4113  if (*plpgsql_plugin_ptr)
4114  {
4115  (*plpgsql_plugin_ptr)->error_callback = plpgsql_exec_error_callback;
4116  (*plpgsql_plugin_ptr)->assign_expr = exec_assign_expr;
4117  (*plpgsql_plugin_ptr)->assign_value = exec_assign_value;
4118  (*plpgsql_plugin_ptr)->eval_datum = exec_eval_datum;
4119  (*plpgsql_plugin_ptr)->cast_value = exec_cast_value;
4120 
4121  if ((*plpgsql_plugin_ptr)->func_setup)
4122  ((*plpgsql_plugin_ptr)->func_setup) (estate, func);
4123  }
4124 }
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
static ParamExternData * plpgsql_param_fetch(ParamListInfo params, int paramid, bool speculative, ParamExternData *prm)
Definition: pl_exec.c:6316
static HTAB * shared_cast_hash
Definition: pl_exec.c:178
static void plpgsql_exec_error_callback(void *arg)
Definition: pl_exec.c:1227
static void plpgsql_param_compile(ParamListInfo params, Param *param, ExprState *state, Datum *resv, bool *resnull)
Definition: pl_exec.c:6443
tree ctl
Definition: radixtree.h:1853
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:265
TriggerData * trigdata
Definition: plpgsql.h:1025
EventTriggerData * evtrigdata
Definition: plpgsql.h:1026
void * plugin_info
Definition: plpgsql.h:1094
bool fn_readonly
Definition: plpgsql.h:983
bool fn_retistuple
Definition: plpgsql.h:980
struct PLpgSQL_execstate * cur_estate
Definition: plpgsql.h:1014
ParserSetupHook parserSetup
Definition: params.h:116
ParamCompileHook paramCompile
Definition: params.h:114
void * paramCompileArg
Definition: params.h:115
ParamFetchHook paramFetch
Definition: params.h:112
void * paramFetchArg
Definition: params.h:113
ExprContext * econtext
Definition: execnodes.h:335

References PLpgSQL_execstate::atomic, cast_expr_hash, PLpgSQL_execstate::cast_hash, ctl, PLpgSQL_execstate::cur_error, PLpgSQL_function::cur_estate, CurrentMemoryContext, CurrentResourceOwner, PLpgSQL_execstate::datum_context, PLpgSQL_execstate::datums, ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, PLpgSQL_execstate::err_stmt, PLpgSQL_execstate::err_text, PLpgSQL_execstate::err_var, PLpgSQL_execstate::eval_econtext, PLpgSQL_execstate::eval_processed, PLpgSQL_execstate::eval_tuptable, PLpgSQL_execstate::evtrigdata, exec_assign_expr(), exec_assign_value(), exec_cast_value(), exec_eval_datum(), PLpgSQL_execstate::exitlabel, PLpgSQL_function::fn_readonly, PLpgSQL_function::fn_retistuple, PLpgSQL_function::fn_retset, PLpgSQL_function::fn_rettype, PLpgSQL_execstate::fn_rettype, PLpgSQL_function::found_varno, PLpgSQL_execstate::found_varno, PLpgSQL_execstate::func, HASH_BLOBS, HASH_CONTEXT, hash_create(), HASH_ELEM, InvalidOid, makeParamList(), PLpgSQL_function::ndatums, PLpgSQL_execstate::ndatums, ParamListInfoData::numParams, ParamListInfoData::paramCompile, ParamListInfoData::paramCompileArg, ParamListInfoData::paramFetch, ParamListInfoData::paramFetchArg, PLpgSQL_execstate::paramLI, ParamListInfoData::parserSetup, ParamListInfoData::parserSetupArg, plpgsql_create_econtext(), plpgsql_exec_error_callback(), plpgsql_param_compile(), plpgsql_param_fetch(), plpgsql_parser_setup(), plpgsql_plugin_ptr, PLpgSQL_execstate::plugin_info, PLpgSQL_execstate::procedure_resowner, PLpgSQL_execstate::readonly_func, PLpgSQL_execstate::retisnull, PLpgSQL_execstate::retisset, PLpgSQL_execstate::retistuple, PLpgSQL_execstate::rettype, PLpgSQL_execstate::retval, PLpgSQL_execstate::rsi, shared_cast_hash, shared_simple_eval_estate, shared_simple_eval_resowner, PLpgSQL_execstate::simple_eval_estate, PLpgSQL_execstate::simple_eval_resowner, PLpgSQL_execstate::stmt_mcontext, PLpgSQL_execstate::stmt_mcontext_parent, PLpgSQL_execstate::trigdata, PLpgSQL_execstate::tuple_store, PLpgSQL_execstate::tuple_store_cxt, PLpgSQL_execstate::tuple_store_desc, and PLpgSQL_execstate::tuple_store_owner.

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

◆ plpgsql_exec_error_callback()

static void plpgsql_exec_error_callback ( void *  arg)
static

Definition at line 1227 of file pl_exec.c.

1228 {
1229  PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;
1230  int err_lineno;
1231 
1232  /*
1233  * If err_var is set, report the variable's declaration line number.
1234  * Otherwise, if err_stmt is set, report the err_stmt's line number. When
1235  * err_stmt is not set, we're in function entry/exit, or some such place
1236  * not attached to a specific line number.
1237  */
1238  if (estate->err_var != NULL)
1239  err_lineno = estate->err_var->lineno;
1240  else if (estate->err_stmt != NULL)
1241  err_lineno = estate->err_stmt->lineno;
1242  else
1243  err_lineno = 0;
1244 
1245  if (estate->err_text != NULL)
1246  {
1247  /*
1248  * We don't expend the cycles to run gettext() on err_text unless we
1249  * actually need it. Therefore, places that set up err_text should
1250  * use gettext_noop() to ensure the strings get recorded in the
1251  * message dictionary.
1252  */
1253  if (err_lineno > 0)
1254  {
1255  /*
1256  * translator: last %s is a phrase such as "during statement block
1257  * local variable initialization"
1258  */
1259  errcontext("PL/pgSQL function %s line %d %s",
1260  estate->func->fn_signature,
1261  err_lineno,
1262  _(estate->err_text));
1263  }
1264  else
1265  {
1266  /*
1267  * translator: last %s is a phrase such as "while storing call
1268  * arguments into local variables"
1269  */
1270  errcontext("PL/pgSQL function %s %s",
1271  estate->func->fn_signature,
1272  _(estate->err_text));
1273  }
1274  }
1275  else if (estate->err_stmt != NULL && err_lineno > 0)
1276  {
1277  /* translator: last %s is a plpgsql statement type name */
1278  errcontext("PL/pgSQL function %s line %d at %s",
1279  estate->func->fn_signature,
1280  err_lineno,
1281  plpgsql_stmt_typename(estate->err_stmt));
1282  }
1283  else
1284  errcontext("PL/pgSQL function %s",
1285  estate->func->fn_signature);
1286 }
#define _(x)
Definition: elog.c:90
const char * plpgsql_stmt_typename(PLpgSQL_stmt *stmt)
Definition: pl_funcs.c:232
char * fn_signature
Definition: plpgsql.h:968
int lineno
Definition: plpgsql.h:456

References _, arg, PLpgSQL_execstate::err_stmt, PLpgSQL_execstate::err_text, PLpgSQL_execstate::err_var, errcontext, PLpgSQL_function::fn_signature, PLpgSQL_execstate::func, PLpgSQL_variable::lineno, PLpgSQL_stmt::lineno, and plpgsql_stmt_typename().

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

◆ plpgsql_exec_event_trigger()

void plpgsql_exec_event_trigger ( PLpgSQL_function func,
EventTriggerData trigdata 
)

Definition at line 1159 of file pl_exec.c.

1160 {
1161  PLpgSQL_execstate estate;
1162  ErrorContextCallback plerrcontext;
1163  int rc;
1164 
1165  /*
1166  * Setup the execution state
1167  */
1168  plpgsql_estate_setup(&estate, func, NULL, NULL, NULL);
1169  estate.evtrigdata = trigdata;
1170 
1171  /*
1172  * Setup error traceback support for ereport()
1173  */
1174  plerrcontext.callback = plpgsql_exec_error_callback;
1175  plerrcontext.arg = &estate;
1176  plerrcontext.previous = error_context_stack;
1177  error_context_stack = &plerrcontext;
1178 
1179  /*
1180  * Make local execution copies of all the datums
1181  */
1182  estate.err_text = gettext_noop("during initialization of execution state");
1183  copy_plpgsql_datums(&estate, func);
1184 
1185  /*
1186  * Let the instrumentation plugin peek at this function
1187  */
1188  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_beg)
1189  ((*plpgsql_plugin_ptr)->func_beg) (&estate, func);
1190 
1191  /*
1192  * Now call the toplevel block of statements
1193  */
1194  estate.err_text = NULL;
1195  rc = exec_toplevel_block(&estate, func->action);
1196  if (rc != PLPGSQL_RC_RETURN)
1197  {
1198  estate.err_text = NULL;
1199  ereport(ERROR,
1200  (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
1201  errmsg("control reached end of trigger procedure without RETURN")));
1202  }
1203 
1204  estate.err_text = gettext_noop("during function exit");
1205 
1206  /*
1207  * Let the instrumentation plugin peek at this function
1208  */
1209  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_end)
1210  ((*plpgsql_plugin_ptr)->func_end) (&estate, func);
1211 
1212  /* Clean up any leftover temporary memory */
1213  plpgsql_destroy_econtext(&estate);
1214  exec_eval_cleanup(&estate);
1215  /* stmt_mcontext will be destroyed when function's main context is */
1216 
1217  /*
1218  * Pop the error context stack
1219  */
1220  error_context_stack = plerrcontext.previous;
1221 }
ErrorContextCallback * error_context_stack
Definition: elog.c:94
static void plpgsql_estate_setup(PLpgSQL_execstate *estate, PLpgSQL_function *func, ReturnSetInfo *rsi, EState *simple_eval_estate, ResourceOwner simple_eval_resowner)
Definition: pl_exec.c:3977
static int exec_toplevel_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
Definition: pl_exec.c:1618
static void plpgsql_destroy_econtext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:8460
static void copy_plpgsql_datums(PLpgSQL_execstate *estate, PLpgSQL_function *func)
Definition: pl_exec.c:1294
struct ErrorContextCallback * previous
Definition: elog.h:296
void(* callback)(void *arg)
Definition: elog.h:297
PLpgSQL_stmt_block * action
Definition: plpgsql.h:1007
void(* func_beg)(PLpgSQL_execstate *estate, PLpgSQL_function *func)
Definition: plpgsql.h:1137
void(* func_end)(PLpgSQL_execstate *estate, PLpgSQL_function *func)
Definition: plpgsql.h:1138

References PLpgSQL_function::action, ErrorContextCallback::arg, ErrorContextCallback::callback, copy_plpgsql_datums(), ereport, PLpgSQL_execstate::err_text, errcode(), errmsg(), ERROR, error_context_stack, PLpgSQL_execstate::evtrigdata, exec_eval_cleanup(), exec_toplevel_block(), PLpgSQL_plugin::func_beg, PLpgSQL_plugin::func_end, gettext_noop, plpgsql_destroy_econtext(), plpgsql_estate_setup(), plpgsql_exec_error_callback(), plpgsql_plugin_ptr, PLPGSQL_RC_RETURN, and ErrorContextCallback::previous.

Referenced by plpgsql_call_handler().

◆ plpgsql_exec_function()

Datum plpgsql_exec_function ( PLpgSQL_function func,
FunctionCallInfo  fcinfo,
EState simple_eval_estate,
ResourceOwner  simple_eval_resowner,
ResourceOwner  procedure_resowner,
bool  atomic 
)

Definition at line 477 of file pl_exec.c.

482 {
483  PLpgSQL_execstate estate;
484  ErrorContextCallback plerrcontext;
485  int i;
486  int rc;
487 
488  /*
489  * Setup the execution state
490  */
491  plpgsql_estate_setup(&estate, func, (ReturnSetInfo *) fcinfo->resultinfo,
492  simple_eval_estate, simple_eval_resowner);
493  estate.procedure_resowner = procedure_resowner;
494  estate.atomic = atomic;
495 
496  /*
497  * Setup error traceback support for ereport()
498  */
499  plerrcontext.callback = plpgsql_exec_error_callback;
500  plerrcontext.arg = &estate;
501  plerrcontext.previous = error_context_stack;
502  error_context_stack = &plerrcontext;
503 
504  /*
505  * Make local execution copies of all the datums
506  */
507  estate.err_text = gettext_noop("during initialization of execution state");
508  copy_plpgsql_datums(&estate, func);
509 
510  /*
511  * Store the actual call argument values into the appropriate variables
512  */
513  estate.err_text = gettext_noop("while storing call arguments into local variables");
514  for (i = 0; i < func->fn_nargs; i++)
515  {
516  int n = func->fn_argvarnos[i];
517 
518  switch (estate.datums[n]->dtype)
519  {
520  case PLPGSQL_DTYPE_VAR:
521  {
522  PLpgSQL_var *var = (PLpgSQL_var *) estate.datums[n];
523 
524  assign_simple_var(&estate, var,
525  fcinfo->args[i].value,
526  fcinfo->args[i].isnull,
527  false);
528 
529  /*
530  * If it's a varlena type, check to see if we received a
531  * R/W expanded-object pointer. If so, we can commandeer
532  * the object rather than having to copy it. If passed a
533  * R/O expanded pointer, just keep it as the value of the
534  * variable for the moment. (We can change it to R/W if
535  * the variable gets modified, but that may very well
536  * never happen.)
537  *
538  * Also, force any flat array value to be stored in
539  * expanded form in our local variable, in hopes of
540  * improving efficiency of uses of the variable. (This is
541  * a hack, really: why only arrays? Need more thought
542  * about which cases are likely to win. See also
543  * typisarray-specific heuristic in exec_assign_value.)
544  */
545  if (!var->isnull && var->datatype->typlen == -1)
546  {
548  {
549  /* take ownership of R/W object */
550  assign_simple_var(&estate, var,
552  estate.datum_context),
553  false,
554  true);
555  }
557  {
558  /* R/O pointer, keep it as-is until assigned to */
559  }
560  else if (var->datatype->typisarray)
561  {
562  /* flat array, so force to expanded form */
563  assign_simple_var(&estate, var,
564  expand_array(var->value,
565  estate.datum_context,
566  NULL),
567  false,
568  true);
569  }
570  }
571  }
572  break;
573 
574  case PLPGSQL_DTYPE_REC:
575  {
576  PLpgSQL_rec *rec = (PLpgSQL_rec *) estate.datums[n];
577 
578  if (!fcinfo->args[i].isnull)
579  {
580  /* Assign row value from composite datum */
581  exec_move_row_from_datum(&estate,
582  (PLpgSQL_variable *) rec,
583  fcinfo->args[i].value);
584  }
585  else
586  {
587  /* If arg is null, set variable to null */
588  exec_move_row(&estate, (PLpgSQL_variable *) rec,
589  NULL, NULL);
590  }
591  /* clean up after exec_move_row() */
592  exec_eval_cleanup(&estate);
593  }
594  break;
595 
596  default:
597  /* Anything else should not be an argument variable */
598  elog(ERROR, "unrecognized dtype: %d", func->datums[i]->dtype);
599  }
600  }
601 
602  estate.err_text = gettext_noop("during function entry");
603 
604  /*
605  * Set the magic variable FOUND to false
606  */
607  exec_set_found(&estate, false);
608 
609  /*
610  * Let the instrumentation plugin peek at this function
611  */
612  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_beg)
613  ((*plpgsql_plugin_ptr)->func_beg) (&estate, func);
614 
615  /*
616  * Now call the toplevel block of statements
617  */
618  estate.err_text = NULL;
619  rc = exec_toplevel_block(&estate, func->action);
620  if (rc != PLPGSQL_RC_RETURN)
621  {
622  estate.err_text = NULL;
623  ereport(ERROR,
624  (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
625  errmsg("control reached end of function without RETURN")));
626  }
627 
628  /*
629  * We got a return value - process it
630  */
631  estate.err_text = gettext_noop("while casting return value to function's return type");
632 
633  fcinfo->isnull = estate.retisnull;
634 
635  if (estate.retisset)
636  {
637  ReturnSetInfo *rsi = estate.rsi;
638 
639  /* Check caller can handle a set result */
640  if (!rsi || !IsA(rsi, ReturnSetInfo))
641  ereport(ERROR,
642  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
643  errmsg("set-valued function called in context that cannot accept a set")));
644 
645  if (!(rsi->allowedModes & SFRM_Materialize))
646  ereport(ERROR,
647  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
648  errmsg("materialize mode required, but it is not allowed in this context")));
649 
651 
652  /* If we produced any tuples, send back the result */
653  if (estate.tuple_store)
654  {
655  MemoryContext oldcxt;
656 
657  rsi->setResult = estate.tuple_store;
658  oldcxt = MemoryContextSwitchTo(estate.tuple_store_cxt);
660  MemoryContextSwitchTo(oldcxt);
661  }
662  estate.retval = (Datum) 0;
663  fcinfo->isnull = true;
664  }
665  else if (!estate.retisnull)
666  {
667  /*
668  * Cast result value to function's declared result type, and copy it
669  * out to the upper executor memory context. We must treat tuple
670  * results specially in order to deal with cases like rowtypes
671  * involving dropped columns.
672  */
673  if (estate.retistuple)
674  {
675  /* Don't need coercion if rowtype is known to match */
676  if (func->fn_rettype == estate.rettype &&
677  func->fn_rettype != RECORDOID)
678  {
679  /*
680  * Copy the tuple result into upper executor memory context.
681  * However, if we have a R/W expanded datum, we can just
682  * transfer its ownership out to the upper context.
683  */
684  estate.retval = SPI_datumTransfer(estate.retval,
685  false,
686  -1);
687  }
688  else
689  {
690  /*
691  * Need to look up the expected result type. XXX would be
692  * better to cache the tupdesc instead of repeating
693  * get_call_result_type(), but the only easy place to save it
694  * is in the PLpgSQL_function struct, and that's too
695  * long-lived: composite types could change during the
696  * existence of a PLpgSQL_function.
697  */
698  Oid resultTypeId;
699  TupleDesc tupdesc;
700 
701  switch (get_call_result_type(fcinfo, &resultTypeId, &tupdesc))
702  {
703  case TYPEFUNC_COMPOSITE:
704  /* got the expected result rowtype, now coerce it */
705  coerce_function_result_tuple(&estate, tupdesc);
706  break;
708  /* got the expected result rowtype, now coerce it */
709  coerce_function_result_tuple(&estate, tupdesc);
710  /* and check domain constraints */
711  /* XXX allowing caching here would be good, too */
712  domain_check(estate.retval, false, resultTypeId,
713  NULL, NULL);
714  break;
715  case TYPEFUNC_RECORD:
716 
717  /*
718  * Failed to determine actual type of RECORD. We
719  * could raise an error here, but what this means in
720  * practice is that the caller is expecting any old
721  * generic rowtype, so we don't really need to be
722  * restrictive. Pass back the generated result as-is.
723  */
724  estate.retval = SPI_datumTransfer(estate.retval,
725  false,
726  -1);
727  break;
728  default:
729  /* shouldn't get here if retistuple is true ... */
730  elog(ERROR, "return type must be a row type");
731  break;
732  }
733  }
734  }
735  else
736  {
737  /* Scalar case: use exec_cast_value */
738  estate.retval = exec_cast_value(&estate,
739  estate.retval,
740  &fcinfo->isnull,
741  estate.rettype,
742  -1,
743  func->fn_rettype,
744  -1);
745 
746  /*
747  * If the function's return type isn't by value, copy the value
748  * into upper executor memory context. However, if we have a R/W
749  * expanded datum, we can just transfer its ownership out to the
750  * upper executor context.
751  */
752  if (!fcinfo->isnull && !func->fn_retbyval)
753  estate.retval = SPI_datumTransfer(estate.retval,
754  false,
755  func->fn_rettyplen);
756  }
757  }
758  else
759  {
760  /*
761  * We're returning a NULL, which normally requires no conversion work
762  * regardless of datatypes. But, if we are casting it to a domain
763  * return type, we'd better check that the domain's constraints pass.
764  */
765  if (func->fn_retisdomain)
766  estate.retval = exec_cast_value(&estate,
767  estate.retval,
768  &fcinfo->isnull,
769  estate.rettype,
770  -1,
771  func->fn_rettype,
772  -1);
773  }
774 
775  estate.err_text = gettext_noop("during function exit");
776 
777  /*
778  * Let the instrumentation plugin peek at this function
779  */
780  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_end)
781  ((*plpgsql_plugin_ptr)->func_end) (&estate, func);
782 
783  /* Clean up any leftover temporary memory */
784  plpgsql_destroy_econtext(&estate);
785  exec_eval_cleanup(&estate);
786  /* stmt_mcontext will be destroyed when function's main context is */
787 
788  /*
789  * Pop the error context stack
790  */
791  error_context_stack = plerrcontext.previous;
792 
793  /*
794  * Return the function's result
795  */
796  return estate.retval;
797 }
void domain_check(Datum value, bool isnull, Oid domainType, void **extra, MemoryContext mcxt)
Definition: domains.c:346
Datum TransferExpandedObject(Datum d, MemoryContext new_parent)
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
@ TYPEFUNC_RECORD
Definition: funcapi.h:151
@ TYPEFUNC_COMPOSITE_DOMAIN
Definition: funcapi.h:150
static void coerce_function_result_tuple(PLpgSQL_execstate *estate, TupleDesc tupdesc)
Definition: pl_exec.c:808
fmNodePtr resultinfo
Definition: fmgr.h:89
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
Datum value
Definition: postgres.h:75
bool isnull
Definition: postgres.h:77
bool fn_retbyval
Definition: plpgsql.h:979
bool fn_retisdomain
Definition: plpgsql.h:981
int fn_argvarnos[FUNC_MAX_ARGS]
Definition: plpgsql.h:987
SetFunctionReturnMode returnMode
Definition: execnodes.h:339
TupleDesc setDesc
Definition: execnodes.h:343
Tuplestorestate * setResult
Definition: execnodes.h:342
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:133
#define VARATT_IS_EXTERNAL_EXPANDED_RO(PTR)
Definition: varatt.h:294

References PLpgSQL_function::action, ReturnSetInfo::allowedModes, ErrorContextCallback::arg, FunctionCallInfoBaseData::args, assign_simple_var(), PLpgSQL_execstate::atomic, ErrorContextCallback::callback, coerce_function_result_tuple(), copy_plpgsql_datums(), CreateTupleDescCopy(), PLpgSQL_var::datatype, PLpgSQL_execstate::datum_context, DatumGetPointer(), PLpgSQL_function::datums, PLpgSQL_execstate::datums, domain_check(), PLpgSQL_datum::dtype, elog, ereport, PLpgSQL_execstate::err_text, errcode(), errmsg(), ERROR, error_context_stack, exec_cast_value(), exec_eval_cleanup(), exec_move_row(), exec_move_row_from_datum(), exec_set_found(), exec_toplevel_block(), expand_array(), PLpgSQL_function::fn_argvarnos, PLpgSQL_function::fn_nargs, PLpgSQL_function::fn_retbyval, PLpgSQL_function::fn_retisdomain, PLpgSQL_function::fn_rettype, PLpgSQL_function::fn_rettyplen, PLpgSQL_plugin::func_beg, PLpgSQL_plugin::func_end, get_call_result_type(), gettext_noop, i, if(), IsA, FunctionCallInfoBaseData::isnull, NullableDatum::isnull, PLpgSQL_var::isnull, MemoryContextSwitchTo(), plpgsql_destroy_econtext(), PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_VAR, plpgsql_estate_setup(), plpgsql_exec_error_callback(), plpgsql_plugin_ptr, PLPGSQL_RC_RETURN, ErrorContextCallback::previous, PLpgSQL_execstate::procedure_resowner, FunctionCallInfoBaseData::resultinfo, PLpgSQL_execstate::retisnull, PLpgSQL_execstate::retisset, PLpgSQL_execstate::retistuple, PLpgSQL_execstate::rettype, ReturnSetInfo::returnMode, PLpgSQL_execstate::retval, PLpgSQL_execstate::rsi, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize, SPI_datumTransfer(), TransferExpandedObject(), PLpgSQL_execstate::tuple_store, PLpgSQL_execstate::tuple_store_cxt, PLpgSQL_execstate::tuple_store_desc, TYPEFUNC_COMPOSITE, TYPEFUNC_COMPOSITE_DOMAIN, TYPEFUNC_RECORD, PLpgSQL_type::typisarray, PLpgSQL_type::typlen, NullableDatum::value, PLpgSQL_var::value, VARATT_IS_EXTERNAL_EXPANDED_RO, and VARATT_IS_EXTERNAL_EXPANDED_RW.

Referenced by plpgsql_call_handler(), and plpgsql_inline_handler().

◆ plpgsql_exec_get_datum_type()

Oid plpgsql_exec_get_datum_type ( PLpgSQL_execstate estate,
PLpgSQL_datum datum 
)

Definition at line 5457 of file pl_exec.c.

5459 {
5460  Oid typeid;
5461 
5462  switch (datum->dtype)
5463  {
5464  case PLPGSQL_DTYPE_VAR:
5465  case PLPGSQL_DTYPE_PROMISE:
5466  {
5467  PLpgSQL_var *var = (PLpgSQL_var *) datum;
5468 
5469  typeid = var->datatype->typoid;
5470  break;
5471  }
5472 
5473  case PLPGSQL_DTYPE_REC:
5474  {
5475  PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
5476 
5477  if (rec->erh == NULL || rec->rectypeid != RECORDOID)
5478  {
5479  /* Report variable's declared type */
5480  typeid = rec->rectypeid;
5481  }
5482  else
5483  {
5484  /* Report record's actual type if declared RECORD */
5485  typeid = rec->erh->er_typeid;
5486  }
5487  break;
5488  }
5489 
5491  {
5492  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
5493  PLpgSQL_rec *rec;
5494 
5495  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5496 
5497  /*
5498  * If record variable is NULL, instantiate it if it has a
5499  * named composite type, else complain. (This won't change
5500  * the logical state of the record: it's still NULL.)
5501  */
5502  if (rec->erh == NULL)
5503  instantiate_empty_record_variable(estate, rec);
5504 
5505  /*
5506  * Look up the field's properties if we have not already, or
5507  * if the tuple descriptor ID changed since last time.
5508  */
5509  if (unlikely(recfield->rectupledescid != rec->erh->er_tupdesc_id))
5510  {
5512  recfield->fieldname,
5513  &recfield->finfo))
5514  ereport(ERROR,
5515  (errcode(ERRCODE_UNDEFINED_COLUMN),
5516  errmsg("record \"%s\" has no field \"%s\"",
5517  rec->refname, recfield->fieldname)));
5518  recfield->rectupledescid = rec->erh->er_tupdesc_id;
5519  }
5520 
5521  typeid = recfield->finfo.ftypeid;
5522  break;
5523  }
5524 
5525  default:
5526  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
5527  typeid = InvalidOid; /* keep compiler quiet */
5528  break;
5529  }
5530 
5531  return typeid;
5532 }

References PLpgSQL_var::datatype, PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, elog, ExpandedRecordHeader::er_tupdesc_id, ExpandedRecordHeader::er_typeid, ereport, PLpgSQL_rec::erh, errcode(), errmsg(), ERROR, expanded_record_lookup_field(), PLpgSQL_recfield::fieldname, PLpgSQL_recfield::finfo, ExpandedRecordFieldInfo::ftypeid, instantiate_empty_record_variable(), InvalidOid, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_VAR, PLpgSQL_recfield::recparentno, PLpgSQL_recfield::rectupledescid, PLpgSQL_rec::rectypeid, PLpgSQL_rec::refname, PLpgSQL_type::typoid, and unlikely.

Referenced by exec_stmt_foreach_a().

◆ plpgsql_exec_get_datum_type_info()

void plpgsql_exec_get_datum_type_info ( PLpgSQL_execstate estate,
PLpgSQL_datum datum,
Oid typeId,
int32 typMod,
Oid collation 
)

Definition at line 5542 of file pl_exec.c.

5545 {
5546  switch (datum->dtype)
5547  {
5548  case PLPGSQL_DTYPE_VAR:
5549  case PLPGSQL_DTYPE_PROMISE:
5550  {
5551  PLpgSQL_var *var = (PLpgSQL_var *) datum;
5552 
5553  *typeId = var->datatype->typoid;
5554  *typMod = var->datatype->atttypmod;
5555  *collation = var->datatype->collation;
5556  break;
5557  }
5558 
5559  case PLPGSQL_DTYPE_REC:
5560  {
5561  PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
5562 
5563  if (rec->erh == NULL || rec->rectypeid != RECORDOID)
5564  {
5565  /* Report variable's declared type */
5566  *typeId = rec->rectypeid;
5567  *typMod = -1;
5568  }
5569  else
5570  {
5571  /* Report record's actual type if declared RECORD */
5572  *typeId = rec->erh->er_typeid;
5573  /* do NOT return the mutable typmod of a RECORD variable */
5574  *typMod = -1;
5575  }
5576  /* composite types are never collatable */
5577  *collation = InvalidOid;
5578  break;
5579  }
5580 
5582  {
5583  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
5584  PLpgSQL_rec *rec;
5585 
5586  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5587 
5588  /*
5589  * If record variable is NULL, instantiate it if it has a
5590  * named composite type, else complain. (This won't change
5591  * the logical state of the record: it's still NULL.)
5592  */
5593  if (rec->erh == NULL)
5594  instantiate_empty_record_variable(estate, rec);
5595 
5596  /*
5597  * Look up the field's properties if we have not already, or
5598  * if the tuple descriptor ID changed since last time.
5599  */
5600  if (unlikely(recfield->rectupledescid != rec->erh->er_tupdesc_id))
5601  {
5603  recfield->fieldname,
5604  &recfield->finfo))
5605  ereport(ERROR,
5606  (errcode(ERRCODE_UNDEFINED_COLUMN),
5607  errmsg("record \"%s\" has no field \"%s\"",
5608  rec->refname, recfield->fieldname)));
5609  recfield->rectupledescid = rec->erh->er_tupdesc_id;
5610  }
5611 
5612  *typeId = recfield->finfo.ftypeid;
5613  *typMod = recfield->finfo.ftypmod;
5614  *collation = recfield->finfo.fcollation;
5615  break;
5616  }
5617 
5618  default:
5619  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
5620  *typeId = InvalidOid; /* keep compiler quiet */
5621  *typMod = -1;
5622  *collation = InvalidOid;
5623  break;
5624  }
5625 }
Oid collation
Definition: plpgsql.h:206

References PLpgSQL_type::atttypmod, PLpgSQL_type::collation, PLpgSQL_var::datatype, PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, elog, ExpandedRecordHeader::er_tupdesc_id, ExpandedRecordHeader::er_typeid, ereport, PLpgSQL_rec::erh, errcode(), errmsg(), ERROR, expanded_record_lookup_field(), ExpandedRecordFieldInfo::fcollation, PLpgSQL_recfield::fieldname, PLpgSQL_recfield::finfo, ExpandedRecordFieldInfo::ftypeid, ExpandedRecordFieldInfo::ftypmod, instantiate_empty_record_variable(), InvalidOid, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_VAR, PLpgSQL_recfield::recparentno, PLpgSQL_recfield::rectupledescid, PLpgSQL_rec::rectypeid, PLpgSQL_rec::refname, PLpgSQL_type::typoid, and unlikely.

Referenced by make_datum_param().

◆ plpgsql_exec_trigger()

HeapTuple plpgsql_exec_trigger ( PLpgSQL_function func,
TriggerData trigdata 
)

Definition at line 919 of file pl_exec.c.

921 {
922  PLpgSQL_execstate estate;
923  ErrorContextCallback plerrcontext;
924  int rc;
925  TupleDesc tupdesc;
926  PLpgSQL_rec *rec_new,
927  *rec_old;
928  HeapTuple rettup;
929 
930  /*
931  * Setup the execution state
932  */
933  plpgsql_estate_setup(&estate, func, NULL, NULL, NULL);
934  estate.trigdata = trigdata;
935 
936  /*
937  * Setup error traceback support for ereport()
938  */
939  plerrcontext.callback = plpgsql_exec_error_callback;
940  plerrcontext.arg = &estate;
941  plerrcontext.previous = error_context_stack;
942  error_context_stack = &plerrcontext;
943 
944  /*
945  * Make local execution copies of all the datums
946  */
947  estate.err_text = gettext_noop("during initialization of execution state");
948  copy_plpgsql_datums(&estate, func);
949 
950  /*
951  * Put the OLD and NEW tuples into record variables
952  *
953  * We set up expanded records for both variables even though only one may
954  * have a value. This allows record references to succeed in functions
955  * that are used for multiple trigger types. For example, we might have a
956  * test like "if (TG_OP = 'INSERT' and NEW.foo = 'xyz')", which should
957  * work regardless of the current trigger type. If a value is actually
958  * fetched from an unsupplied tuple, it will read as NULL.
959  */
960  tupdesc = RelationGetDescr(trigdata->tg_relation);
961 
962  rec_new = (PLpgSQL_rec *) (estate.datums[func->new_varno]);
963  rec_old = (PLpgSQL_rec *) (estate.datums[func->old_varno]);
964 
965  rec_new->erh = make_expanded_record_from_tupdesc(tupdesc,
966  estate.datum_context);
967  rec_old->erh = make_expanded_record_from_exprecord(rec_new->erh,
968  estate.datum_context);
969 
970  if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
971  {
972  /*
973  * Per-statement triggers don't use OLD/NEW variables
974  */
975  }
976  else if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
977  {
978  expanded_record_set_tuple(rec_new->erh, trigdata->tg_trigtuple,
979  false, false);
980  }
981  else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
982  {
983  expanded_record_set_tuple(rec_new->erh, trigdata->tg_newtuple,
984  false, false);
985  expanded_record_set_tuple(rec_old->erh, trigdata->tg_trigtuple,
986  false, false);
987 
988  /*
989  * In BEFORE trigger, stored generated columns are not computed yet,
990  * so make them null in the NEW row. (Only needed in UPDATE branch;
991  * in the INSERT case, they are already null, but in UPDATE, the field
992  * still contains the old value.) Alternatively, we could construct a
993  * whole new row structure without the generated columns, but this way
994  * seems more efficient and potentially less confusing.
995  */
996  if (tupdesc->constr && tupdesc->constr->has_generated_stored &&
997  TRIGGER_FIRED_BEFORE(trigdata->tg_event))
998  {
999  for (int i = 0; i < tupdesc->natts; i++)
1000  if (TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED)
1002  i + 1,
1003  (Datum) 0,
1004  true, /* isnull */
1005  false, false);
1006  }
1007  }
1008  else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
1009  {
1010  expanded_record_set_tuple(rec_old->erh, trigdata->tg_trigtuple,
1011  false, false);
1012  }
1013  else
1014  elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, or UPDATE");
1015 
1016  /* Make transition tables visible to this SPI connection */
1017  rc = SPI_register_trigger_data(trigdata);
1018  Assert(rc >= 0);
1019 
1020  estate.err_text = gettext_noop("during function entry");
1021 
1022  /*
1023  * Set the magic variable FOUND to false
1024  */
1025  exec_set_found(&estate, false);
1026 
1027  /*
1028  * Let the instrumentation plugin peek at this function
1029  */
1030  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_beg)
1031  ((*plpgsql_plugin_ptr)->func_beg) (&estate, func);
1032 
1033  /*
1034  * Now call the toplevel block of statements
1035  */
1036  estate.err_text = NULL;
1037  rc = exec_toplevel_block(&estate, func->action);
1038  if (rc != PLPGSQL_RC_RETURN)
1039  {
1040  estate.err_text = NULL;
1041  ereport(ERROR,
1042  (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
1043  errmsg("control reached end of trigger procedure without RETURN")));
1044  }
1045 
1046  estate.err_text = gettext_noop("during function exit");
1047 
1048  if (estate.retisset)
1049  ereport(ERROR,
1050  (errcode(ERRCODE_DATATYPE_MISMATCH),
1051  errmsg("trigger procedure cannot return a set")));
1052 
1053  /*
1054  * Check that the returned tuple structure has the same attributes, the
1055  * relation that fired the trigger has. A per-statement trigger always
1056  * needs to return NULL, so we ignore any return value the function itself
1057  * produces (XXX: is this a good idea?)
1058  *
1059  * XXX This way it is possible, that the trigger returns a tuple where
1060  * attributes don't have the correct atttypmod's length. It's up to the
1061  * trigger's programmer to ensure that this doesn't happen. Jan
1062  */
1063  if (estate.retisnull || !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
1064  rettup = NULL;
1065  else
1066  {
1067  TupleDesc retdesc;
1068  TupleConversionMap *tupmap;
1069 
1070  /* We assume exec_stmt_return verified that result is composite */
1071  Assert(type_is_rowtype(estate.rettype));
1072 
1073  /* We can special-case expanded records for speed */
1075  {
1077 
1078  Assert(erh->er_magic == ER_MAGIC);
1079 
1080  /* Extract HeapTuple and TupleDesc */
1081  rettup = expanded_record_get_tuple(erh);
1082  Assert(rettup);
1083  retdesc = expanded_record_get_tupdesc(erh);
1084 
1085  if (retdesc != RelationGetDescr(trigdata->tg_relation))
1086  {
1087  /* check rowtype compatibility */
1088  tupmap = convert_tuples_by_position(retdesc,
1089  RelationGetDescr(trigdata->tg_relation),
1090  gettext_noop("returned row structure does not match the structure of the triggering table"));
1091  /* it might need conversion */
1092  if (tupmap)
1093  rettup = execute_attr_map_tuple(rettup, tupmap);
1094  /* no need to free map, we're about to return anyway */
1095  }
1096 
1097  /*
1098  * Copy tuple to upper executor memory. But if user just did
1099  * "return new" or "return old" without changing anything, there's
1100  * no need to copy; we can return the original tuple (which will
1101  * save a few cycles in trigger.c as well as here).
1102  */
1103  if (rettup != trigdata->tg_newtuple &&
1104  rettup != trigdata->tg_trigtuple)
1105  rettup = SPI_copytuple(rettup);
1106  }
1107  else
1108  {
1109  /* Convert composite datum to a HeapTuple and TupleDesc */
1110  HeapTupleData tmptup;
1111 
1112  retdesc = deconstruct_composite_datum(estate.retval, &tmptup);
1113  rettup = &tmptup;
1114 
1115  /* check rowtype compatibility */
1116  tupmap = convert_tuples_by_position(retdesc,
1117  RelationGetDescr(trigdata->tg_relation),
1118  gettext_noop("returned row structure does not match the structure of the triggering table"));
1119  /* it might need conversion */
1120  if (tupmap)
1121  rettup = execute_attr_map_tuple(rettup, tupmap);
1122 
1123  ReleaseTupleDesc(retdesc);
1124  /* no need to free map, we're about to return anyway */
1125 
1126  /* Copy tuple to upper executor memory */
1127  rettup = SPI_copytuple(rettup);
1128  }
1129  }
1130 
1131  /*
1132  * Let the instrumentation plugin peek at this function
1133  */
1134  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_end)
1135  ((*plpgsql_plugin_ptr)->func_end) (&estate, func);
1136 
1137  /* Clean up any leftover temporary memory */
1138  plpgsql_destroy_econtext(&estate);
1139  exec_eval_cleanup(&estate);
1140  /* stmt_mcontext will be destroyed when function's main context is */
1141 
1142  /*
1143  * Pop the error context stack
1144  */
1145  error_context_stack = plerrcontext.previous;
1146 
1147  /*
1148  * Return the trigger's result
1149  */
1150  return rettup;
1151 }
void expanded_record_set_field_internal(ExpandedRecordHeader *erh, int fnumber, Datum newValue, bool isnull, bool expand_external, bool check_constraints)
#define RelationGetDescr(relation)
Definition: rel.h:531
int SPI_register_trigger_data(TriggerData *tdata)
Definition: spi.c:3364
HeapTuple SPI_copytuple(HeapTuple tuple)
Definition: spi.c:1047
Relation tg_relation
Definition: trigger.h:35
TriggerEvent tg_event
Definition: trigger.h:34
HeapTuple tg_newtuple
Definition: trigger.h:37
HeapTuple tg_trigtuple
Definition: trigger.h:36
bool has_generated_stored
Definition: tupdesc.h:45
TupleConstr * constr
Definition: tupdesc.h:85
#define TRIGGER_FIRED_BY_DELETE(event)
Definition: trigger.h:113
#define TRIGGER_FIRED_BEFORE(event)
Definition: trigger.h:128
#define TRIGGER_FIRED_FOR_ROW(event)
Definition: trigger.h:122
#define TRIGGER_FIRED_BY_INSERT(event)
Definition: trigger.h:110
#define TRIGGER_FIRED_BY_UPDATE(event)
Definition: trigger.h:116

References PLpgSQL_function::action, ErrorContextCallback::arg, Assert, ErrorContextCallback::callback, TupleDescData::constr, convert_tuples_by_position(), copy_plpgsql_datums(), PLpgSQL_execstate::datum_context, DatumGetEOHP(), DatumGetPointer(), PLpgSQL_execstate::datums, deconstruct_composite_datum(), elog, ER_MAGIC, ExpandedRecordHeader::er_magic, ereport, PLpgSQL_rec::erh, PLpgSQL_execstate::err_text, errcode(), errmsg(), ERROR, error_context_stack, exec_eval_cleanup(), exec_set_found(), exec_toplevel_block(), execute_attr_map_tuple(), expanded_record_get_tupdesc(), expanded_record_get_tuple(), expanded_record_set_field_internal(), expanded_record_set_tuple(), PLpgSQL_plugin::func_beg, PLpgSQL_plugin::func_end, gettext_noop, TupleConstr::has_generated_stored, i, make_expanded_record_from_exprecord(), make_expanded_record_from_tupdesc(), TupleDescData::natts, PLpgSQL_function::new_varno, PLpgSQL_function::old_varno, plpgsql_destroy_econtext(), plpgsql_estate_setup(), plpgsql_exec_error_callback(), plpgsql_plugin_ptr, PLPGSQL_RC_RETURN, ErrorContextCallback::previous, RelationGetDescr, ReleaseTupleDesc, PLpgSQL_execstate::retisnull, PLpgSQL_execstate::retisset, PLpgSQL_execstate::rettype, PLpgSQL_execstate::retval, SPI_copytuple(), SPI_register_trigger_data(), TriggerData::tg_event, TriggerData::tg_newtuple, TriggerData::tg_relation, TriggerData::tg_trigtuple, PLpgSQL_execstate::trigdata, TRIGGER_FIRED_BEFORE, TRIGGER_FIRED_BY_DELETE, TRIGGER_FIRED_BY_INSERT, TRIGGER_FIRED_BY_UPDATE, TRIGGER_FIRED_FOR_ROW, TupleDescAttr, type_is_rowtype(), and VARATT_IS_EXTERNAL_EXPANDED.

Referenced by plpgsql_call_handler().

◆ plpgsql_fulfill_promise()

static void plpgsql_fulfill_promise ( PLpgSQL_execstate estate,
PLpgSQL_var var 
)
static

Definition at line 1368 of file pl_exec.c.

1370 {
1371  MemoryContext oldcontext;
1372 
1373  if (var->promise == PLPGSQL_PROMISE_NONE)
1374  return; /* nothing to do */
1375 
1376  /*
1377  * This will typically be invoked in a short-lived context such as the
1378  * mcontext. We must create variable values in the estate's datum
1379  * context. This quick-and-dirty solution risks leaking some additional
1380  * cruft there, but since any one promise is honored at most once per
1381  * function call, it's probably not worth being more careful.
1382  */
1383  oldcontext = MemoryContextSwitchTo(estate->datum_context);
1384 
1385  switch (var->promise)
1386  {
1388  if (estate->trigdata == NULL)
1389  elog(ERROR, "trigger promise is not in a trigger function");
1390  assign_simple_var(estate, var,
1393  false, true);
1394  break;
1395 
1397  if (estate->trigdata == NULL)
1398  elog(ERROR, "trigger promise is not in a trigger function");
1399  if (TRIGGER_FIRED_BEFORE(estate->trigdata->tg_event))
1400  assign_text_var(estate, var, "BEFORE");
1401  else if (TRIGGER_FIRED_AFTER(estate->trigdata->tg_event))
1402  assign_text_var(estate, var, "AFTER");
1403  else if (TRIGGER_FIRED_INSTEAD(estate->trigdata->tg_event))
1404  assign_text_var(estate, var, "INSTEAD OF");
1405  else
1406  elog(ERROR, "unrecognized trigger execution time: not BEFORE, AFTER, or INSTEAD OF");
1407  break;
1408 
1410  if (estate->trigdata == NULL)
1411  elog(ERROR, "trigger promise is not in a trigger function");
1412  if (TRIGGER_FIRED_FOR_ROW(estate->trigdata->tg_event))
1413  assign_text_var(estate, var, "ROW");
1414  else if (TRIGGER_FIRED_FOR_STATEMENT(estate->trigdata->tg_event))
1415  assign_text_var(estate, var, "STATEMENT");
1416  else
1417  elog(ERROR, "unrecognized trigger event type: not ROW or STATEMENT");
1418  break;
1419 
1420  case PLPGSQL_PROMISE_TG_OP:
1421  if (estate->trigdata == NULL)
1422  elog(ERROR, "trigger promise is not in a trigger function");
1424  assign_text_var(estate, var, "INSERT");
1425  else if (TRIGGER_FIRED_BY_UPDATE(estate->trigdata->tg_event))
1426  assign_text_var(estate, var, "UPDATE");
1427  else if (TRIGGER_FIRED_BY_DELETE(estate->trigdata->tg_event))
1428  assign_text_var(estate, var, "DELETE");
1429  else if (TRIGGER_FIRED_BY_TRUNCATE(estate->trigdata->tg_event))
1430  assign_text_var(estate, var, "TRUNCATE");
1431  else
1432  elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, UPDATE, or TRUNCATE");
1433  break;
1434 
1436  if (estate->trigdata == NULL)
1437  elog(ERROR, "trigger promise is not in a trigger function");
1438  assign_simple_var(estate, var,
1440  false, false);
1441  break;
1442 
1444  if (estate->trigdata == NULL)
1445  elog(ERROR, "trigger promise is not in a trigger function");
1446  assign_simple_var(estate, var,
1449  false, true);
1450  break;
1451 
1453  if (estate->trigdata == NULL)
1454  elog(ERROR, "trigger promise is not in a trigger function");
1455  assign_simple_var(estate, var,
1458  false, true);
1459  break;
1460 
1462  if (estate->trigdata == NULL)
1463  elog(ERROR, "trigger promise is not in a trigger function");
1464  assign_simple_var(estate, var,
1466  false, false);
1467  break;
1468 
1470  if (estate->trigdata == NULL)
1471  elog(ERROR, "trigger promise is not in a trigger function");
1472  if (estate->trigdata->tg_trigger->tgnargs > 0)
1473  {
1474  /*
1475  * For historical reasons, tg_argv[] subscripts start at zero
1476  * not one. So we can't use construct_array().
1477  */
1478  int nelems = estate->trigdata->tg_trigger->tgnargs;
1479  Datum *elems;
1480  int dims[1];
1481  int lbs[1];
1482  int i;
1483 
1484  elems = palloc(sizeof(Datum) * nelems);
1485  for (i = 0; i < nelems; i++)
1486  elems[i] = CStringGetTextDatum(estate->trigdata->tg_trigger->tgargs[i]);
1487  dims[0] = nelems;
1488  lbs[0] = 0;
1489 
1490  assign_simple_var(estate, var,
1491  PointerGetDatum(construct_md_array(elems, NULL,
1492  1, dims, lbs,
1493  TEXTOID,
1494  -1, false, TYPALIGN_INT)),
1495  false, true);
1496  }
1497  else
1498  {
1499  assign_simple_var(estate, var, (Datum) 0, true, false);
1500  }
1501  break;
1502 
1504  if (estate->evtrigdata == NULL)
1505  elog(ERROR, "event trigger promise is not in an event trigger function");
1506  assign_text_var(estate, var, estate->evtrigdata->event);
1507  break;
1508 
1510  if (estate->evtrigdata == NULL)
1511  elog(ERROR, "event trigger promise is not in an event trigger function");
1512  assign_text_var(estate, var, GetCommandTagName(estate->evtrigdata->tag));
1513  break;
1514 
1515  default:
1516  elog(ERROR, "unrecognized promise type: %d", var->promise);
1517  }
1518 
1519  MemoryContextSwitchTo(oldcontext);
1520 }
ArrayType * construct_md_array(Datum *elems, bool *nulls, int ndims, int *dims, int *lbs, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3494
const char * GetCommandTagName(CommandTag commandTag)
Definition: cmdtag.c:47
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:641
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
@ PLPGSQL_PROMISE_TG_RELID
Definition: plpgsql.h:80
@ PLPGSQL_PROMISE_TG_WHEN
Definition: plpgsql.h:77
@ PLPGSQL_PROMISE_TG_ARGV
Definition: plpgsql.h:84
@ PLPGSQL_PROMISE_TG_TABLE_SCHEMA
Definition: plpgsql.h:82
@ PLPGSQL_PROMISE_TG_EVENT
Definition: plpgsql.h:85
@ PLPGSQL_PROMISE_TG_TABLE_NAME
Definition: plpgsql.h:81
@ PLPGSQL_PROMISE_TG_TAG
Definition: plpgsql.h:86
@ PLPGSQL_PROMISE_TG_OP
Definition: plpgsql.h:79
@ PLPGSQL_PROMISE_TG_LEVEL
Definition: plpgsql.h:78
@ PLPGSQL_PROMISE_TG_NARGS
Definition: plpgsql.h:83
@ PLPGSQL_PROMISE_TG_NAME
Definition: plpgsql.h:76
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RelationGetNamespace(relation)
Definition: rel.h:546
CommandTag tag
Definition: event_trigger.h:29
const char * event
Definition: event_trigger.h:27
Oid rd_id
Definition: rel.h:113
Trigger * tg_trigger
Definition: trigger.h:38
char * tgname
Definition: reltrigger.h:27
int16 tgnargs
Definition: reltrigger.h:38
char ** tgargs
Definition: reltrigger.h:41
#define TRIGGER_FIRED_FOR_STATEMENT(event)
Definition: trigger.h:125
#define TRIGGER_FIRED_AFTER(event)
Definition: trigger.h:131
#define TRIGGER_FIRED_BY_TRUNCATE(event)
Definition: trigger.h:119
#define TRIGGER_FIRED_INSTEAD(event)
Definition: trigger.h:134

References assign_simple_var(), assign_text_var(), construct_md_array(), CStringGetDatum(), CStringGetTextDatum, PLpgSQL_execstate::datum_context, DirectFunctionCall1, elog, ERROR, EventTriggerData::event, PLpgSQL_execstate::evtrigdata, get_namespace_name(), GetCommandTagName(), i, Int16GetDatum(), MemoryContextSwitchTo(), namein(), ObjectIdGetDatum(), palloc(), PLPGSQL_PROMISE_NONE, PLPGSQL_PROMISE_TG_ARGV, PLPGSQL_PROMISE_TG_EVENT, PLPGSQL_PROMISE_TG_LEVEL, PLPGSQL_PROMISE_TG_NAME, PLPGSQL_PROMISE_TG_NARGS, PLPGSQL_PROMISE_TG_OP, PLPGSQL_PROMISE_TG_RELID, PLPGSQL_PROMISE_TG_TABLE_NAME, PLPGSQL_PROMISE_TG_TABLE_SCHEMA, PLPGSQL_PROMISE_TG_TAG, PLPGSQL_PROMISE_TG_WHEN, PointerGetDatum(), PLpgSQL_var::promise, RelationData::rd_id, RelationGetNamespace, RelationGetRelationName, EventTriggerData::tag, TriggerData::tg_event, TriggerData::tg_relation, TriggerData::tg_trigger, Trigger::tgargs, Trigger::tgname, Trigger::tgnargs, PLpgSQL_execstate::trigdata, TRIGGER_FIRED_AFTER, TRIGGER_FIRED_BEFORE, TRIGGER_FIRED_BY_DELETE, TRIGGER_FIRED_BY_INSERT, TRIGGER_FIRED_BY_TRUNCATE, TRIGGER_FIRED_BY_UPDATE, TRIGGER_FIRED_FOR_ROW, TRIGGER_FIRED_FOR_STATEMENT, and TRIGGER_FIRED_INSTEAD.

Referenced by exec_eval_datum(), exec_stmt_return(), and exec_stmt_return_next().

◆ plpgsql_param_compile()

static void plpgsql_param_compile ( ParamListInfo  params,
Param param,
ExprState state,
Datum resv,
bool resnull 
)
static

Definition at line 6443 of file pl_exec.c.

6446 {
6447  PLpgSQL_execstate *estate;
6448  PLpgSQL_expr *expr;
6449  int dno;
6450  PLpgSQL_datum *datum;
6451  ExprEvalStep scratch;
6452 
6453  /* fetch back the hook data */
6454  estate = (PLpgSQL_execstate *) params->paramFetchArg;
6455  expr = (PLpgSQL_expr *) params->parserSetupArg;
6456 
6457  /* paramid's are 1-based, but dnos are 0-based */
6458  dno = param->paramid - 1;
6459  Assert(dno >= 0 && dno < estate->ndatums);
6460 
6461  /* now we can access the target datum */
6462  datum = estate->datums[dno];
6463 
6464  scratch.opcode = EEOP_PARAM_CALLBACK;
6465  scratch.resvalue = resv;
6466  scratch.resnull = resnull;
6467 
6468  /*
6469  * Select appropriate eval function. It seems worth special-casing
6470  * DTYPE_VAR and DTYPE_RECFIELD for performance. Also, we can determine
6471  * in advance whether MakeExpandedObjectReadOnly() will be required.
6472  * Currently, only VAR/PROMISE and REC datums could contain read/write
6473  * expanded objects.
6474  */
6475  if (datum->dtype == PLPGSQL_DTYPE_VAR)
6476  {
6477  if (param != expr->expr_rw_param &&
6478  ((PLpgSQL_var *) datum)->datatype->typlen == -1)
6479  scratch.d.cparam.paramfunc = plpgsql_param_eval_var_ro;
6480  else
6481  scratch.d.cparam.paramfunc = plpgsql_param_eval_var;
6482  }
6483  else if (datum->dtype == PLPGSQL_DTYPE_RECFIELD)
6484  scratch.d.cparam.paramfunc = plpgsql_param_eval_recfield;
6485  else if (datum->dtype == PLPGSQL_DTYPE_PROMISE)
6486  {
6487  if (param != expr->expr_rw_param &&
6488  ((PLpgSQL_var *) datum)->datatype->typlen == -1)
6489  scratch.d.cparam.paramfunc = plpgsql_param_eval_generic_ro;
6490  else
6491  scratch.d.cparam.paramfunc = plpgsql_param_eval_generic;
6492  }
6493  else if (datum->dtype == PLPGSQL_DTYPE_REC &&
6494  param != expr->expr_rw_param)
6495  scratch.d.cparam.paramfunc = plpgsql_param_eval_generic_ro;
6496  else
6497  scratch.d.cparam.paramfunc = plpgsql_param_eval_generic;
6498 
6499  /*
6500  * Note: it's tempting to use paramarg to store the estate pointer and
6501  * thereby save an indirection or two in the eval functions. But that
6502  * doesn't work because the compiled expression might be used with
6503  * different estates for the same PL/pgSQL function.
6504  */
6505  scratch.d.cparam.paramarg = NULL;
6506  scratch.d.cparam.paramid = param->paramid;
6507  scratch.d.cparam.paramtype = param->paramtype;
6508  ExprEvalPushStep(state, &scratch);
6509 }
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2592
@ EEOP_PARAM_CALLBACK
Definition: execExpr.h:162
static void plpgsql_param_eval_var_ro(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: pl_exec.c:6550
static void plpgsql_param_eval_recfield(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: pl_exec.c:6587
static void plpgsql_param_eval_generic_ro(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: pl_exec.c:6699
static void plpgsql_param_eval_generic(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: pl_exec.c:6659
static void plpgsql_param_eval_var(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: pl_exec.c:6518
intptr_t opcode
Definition: execExpr.h:290
Datum * resvalue
Definition: execExpr.h:293
union ExprEvalStep::@55 d
struct ExprEvalStep::@55::@68 cparam
bool * resnull
Definition: execExpr.h:294
Oid paramtype
Definition: primnodes.h:378

References Assert, ExprEvalStep::cparam, ExprEvalStep::d, PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, EEOP_PARAM_CALLBACK, PLpgSQL_expr::expr_rw_param, ExprEvalPushStep(), ExprEvalStep::opcode, ParamListInfoData::paramFetchArg, Param::paramid, Param::paramtype, ParamListInfoData::parserSetupArg, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_VAR, plpgsql_param_eval_generic(), plpgsql_param_eval_generic_ro(), plpgsql_param_eval_recfield(), plpgsql_param_eval_var(), plpgsql_param_eval_var_ro(), ExprEvalStep::resnull, and ExprEvalStep::resvalue.

Referenced by plpgsql_estate_setup().

◆ plpgsql_param_eval_generic()

static void plpgsql_param_eval_generic ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 6659 of file pl_exec.c.

6661 {
6662  ParamListInfo params;
6663  PLpgSQL_execstate *estate;
6664  int dno = op->d.cparam.paramid - 1;
6665  PLpgSQL_datum *datum;
6666  Oid datumtype;
6667  int32 datumtypmod;
6668 
6669  /* fetch back the hook data */
6670  params = econtext->ecxt_param_list_info;
6671  estate = (PLpgSQL_execstate *) params->paramFetchArg;
6672  Assert(dno >= 0 && dno < estate->ndatums);
6673 
6674  /* now we can access the target datum */
6675  datum = estate->datums[dno];
6676 
6677  /* fetch datum's value */
6678  exec_eval_datum(estate, datum,
6679  &datumtype, &datumtypmod,
6680  op->resvalue, op->resnull);
6681 
6682  /* safety check -- needed for, eg, record fields */
6683  if (unlikely(datumtype != op->d.cparam.paramtype))
6684  ereport(ERROR,
6685  (errcode(ERRCODE_DATATYPE_MISMATCH),
6686  errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
6687  op->d.cparam.paramid,
6688  format_type_be(datumtype),
6689  format_type_be(op->d.cparam.paramtype))));
6690 }

References Assert, ExprEvalStep::cparam, ExprEvalStep::d, PLpgSQL_execstate::datums, ExprContext::ecxt_param_list_info, ereport, errcode(), errmsg(), ERROR, exec_eval_datum(), format_type_be(), ParamListInfoData::paramFetchArg, ExprEvalStep::resnull, ExprEvalStep::resvalue, and unlikely.

Referenced by plpgsql_param_compile().

◆ plpgsql_param_eval_generic_ro()

static void plpgsql_param_eval_generic_ro ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 6699 of file pl_exec.c.

6701 {
6702  ParamListInfo params;
6703  PLpgSQL_execstate *estate;
6704  int dno = op->d.cparam.paramid - 1;
6705  PLpgSQL_datum *datum;
6706  Oid datumtype;
6707  int32 datumtypmod;
6708 
6709  /* fetch back the hook data */
6710  params = econtext->ecxt_param_list_info;
6711  estate = (PLpgSQL_execstate *) params->paramFetchArg;
6712  Assert(dno >= 0 && dno < estate->ndatums);
6713 
6714  /* now we can access the target datum */
6715  datum = estate->datums[dno];
6716 
6717  /* fetch datum's value */
6718  exec_eval_datum(estate, datum,
6719  &datumtype, &datumtypmod,
6720  op->resvalue, op->resnull);
6721 
6722  /* safety check -- needed for, eg, record fields */
6723  if (unlikely(datumtype != op->d.cparam.paramtype))
6724  ereport(ERROR,
6725  (errcode(ERRCODE_DATATYPE_MISMATCH),
6726  errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
6727  op->d.cparam.paramid,
6728  format_type_be(datumtype),
6729  format_type_be(op->d.cparam.paramtype))));
6730 
6731  /* force the value to read-only */
6733  *op->resnull,
6734  -1);
6735 }

References Assert, ExprEvalStep::cparam, ExprEvalStep::d, PLpgSQL_execstate::datums, ExprContext::ecxt_param_list_info, ereport, errcode(), errmsg(), ERROR, exec_eval_datum(), format_type_be(), MakeExpandedObjectReadOnly, ParamListInfoData::paramFetchArg, ExprEvalStep::resnull, ExprEvalStep::resvalue, and unlikely.

Referenced by plpgsql_param_compile().

◆ plpgsql_param_eval_recfield()

static void plpgsql_param_eval_recfield ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 6587 of file pl_exec.c.

6589 {
6590  ParamListInfo params;
6591  PLpgSQL_execstate *estate;
6592  int dno = op->d.cparam.paramid - 1;
6593  PLpgSQL_recfield *recfield;
6594  PLpgSQL_rec *rec;
6595  ExpandedRecordHeader *erh;
6596 
6597  /* fetch back the hook data */
6598  params = econtext->ecxt_param_list_info;
6599  estate = (PLpgSQL_execstate *) params->paramFetchArg;
6600  Assert(dno >= 0 && dno < estate->ndatums);
6601 
6602  /* now we can access the target datum */
6603  recfield = (PLpgSQL_recfield *) estate->datums[dno];
6604  Assert(recfield->dtype == PLPGSQL_DTYPE_RECFIELD);
6605 
6606  /* inline the relevant part of exec_eval_datum */
6607  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
6608  erh = rec->erh;
6609 
6610  /*
6611  * If record variable is NULL, instantiate it if it has a named composite
6612  * type, else complain. (This won't change the logical state of the
6613  * record: it's still NULL.)
6614  */
6615  if (erh == NULL)
6616  {
6617  instantiate_empty_record_variable(estate, rec);
6618  erh = rec->erh;
6619  }
6620 
6621  /*
6622  * Look up the field's properties if we have not already, or if the tuple
6623  * descriptor ID changed since last time.
6624  */
6625  if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
6626  {
6628  recfield->fieldname,
6629  &recfield->finfo))
6630  ereport(ERROR,
6631  (errcode(ERRCODE_UNDEFINED_COLUMN),
6632  errmsg("record \"%s\" has no field \"%s\"",
6633  rec->refname, recfield->fieldname)));
6634  recfield->rectupledescid = erh->er_tupdesc_id;
6635  }
6636 
6637  /* OK to fetch the field value. */
6639  recfield->finfo.fnumber,
6640  op->resnull);
6641 
6642  /* safety check -- needed for, eg, record fields */
6643  if (unlikely(recfield->finfo.ftypeid != op->d.cparam.paramtype))
6644  ereport(ERROR,
6645  (errcode(ERRCODE_DATATYPE_MISMATCH),
6646  errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
6647  op->d.cparam.paramid,
6648  format_type_be(recfield->finfo.ftypeid),
6649  format_type_be(op->d.cparam.paramtype))));
6650 }
PLpgSQL_datum_type dtype
Definition: plpgsql.h:422

References Assert, ExprEvalStep::cparam, ExprEvalStep::d, PLpgSQL_execstate::datums, PLpgSQL_recfield::dtype, ExprContext::ecxt_param_list_info, ExpandedRecordHeader::er_tupdesc_id, ereport, PLpgSQL_rec::erh, errcode(), errmsg(), ERROR, expanded_record_get_field(), expanded_record_lookup_field(), PLpgSQL_recfield::fieldname, PLpgSQL_recfield::finfo, ExpandedRecordFieldInfo::fnumber, format_type_be(), ExpandedRecordFieldInfo::ftypeid, instantiate_empty_record_variable(), ParamListInfoData::paramFetchArg, PLPGSQL_DTYPE_RECFIELD, PLpgSQL_recfield::recparentno, PLpgSQL_recfield::rectupledescid, PLpgSQL_rec::refname, ExprEvalStep::resnull, ExprEvalStep::resvalue, and unlikely.

Referenced by plpgsql_param_compile().

◆ plpgsql_param_eval_var()

static void plpgsql_param_eval_var ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 6518 of file pl_exec.c.

6520 {
6521  ParamListInfo params;
6522  PLpgSQL_execstate *estate;
6523  int dno = op->d.cparam.paramid - 1;
6524  PLpgSQL_var *var;
6525 
6526  /* fetch back the hook data */
6527  params = econtext->ecxt_param_list_info;
6528  estate = (PLpgSQL_execstate *) params->paramFetchArg;
6529  Assert(dno >= 0 && dno < estate->ndatums);
6530 
6531  /* now we can access the target datum */
6532  var = (PLpgSQL_var *) estate->datums[dno];
6533  Assert(var->dtype == PLPGSQL_DTYPE_VAR);
6534 
6535  /* inlined version of exec_eval_datum() */
6536  *op->resvalue = var->value;
6537  *op->resnull = var->isnull;
6538 
6539  /* safety check -- an assertion should be sufficient */
6540  Assert(var->datatype->typoid == op->d.cparam.paramtype);
6541 }

References Assert, ExprEvalStep::cparam, ExprEvalStep::d, PLpgSQL_var::datatype, PLpgSQL_execstate::datums, PLpgSQL_var::dtype, ExprContext::ecxt_param_list_info, PLpgSQL_var::isnull, ParamListInfoData::paramFetchArg, PLPGSQL_DTYPE_VAR, ExprEvalStep::resnull, ExprEvalStep::resvalue, PLpgSQL_type::typoid, and PLpgSQL_var::value.

Referenced by plpgsql_param_compile().

◆ plpgsql_param_eval_var_ro()

static void plpgsql_param_eval_var_ro ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 6550 of file pl_exec.c.

6552 {
6553  ParamListInfo params;
6554  PLpgSQL_execstate *estate;
6555  int dno = op->d.cparam.paramid - 1;
6556  PLpgSQL_var *var;
6557 
6558  /* fetch back the hook data */
6559  params = econtext->ecxt_param_list_info;
6560  estate = (PLpgSQL_execstate *) params->paramFetchArg;
6561  Assert(dno >= 0 && dno < estate->ndatums);
6562 
6563  /* now we can access the target datum */
6564  var = (PLpgSQL_var *) estate->datums[dno];
6565  Assert(var->dtype == PLPGSQL_DTYPE_VAR);
6566 
6567  /*
6568  * Inlined version of exec_eval_datum() ... and while we're at it, force
6569  * expanded datums to read-only.
6570  */
6572  var->isnull,
6573  -1);
6574  *op->resnull = var->isnull;
6575 
6576  /* safety check -- an assertion should be sufficient */
6577  Assert(var->datatype->typoid == op->d.cparam.paramtype);
6578 }

References Assert, ExprEvalStep::cparam, ExprEvalStep::d, PLpgSQL_var::datatype, PLpgSQL_execstate::datums, PLpgSQL_var::dtype, ExprContext::ecxt_param_list_info, PLpgSQL_var::isnull, MakeExpandedObjectReadOnly, ParamListInfoData::paramFetchArg, PLPGSQL_DTYPE_VAR, ExprEvalStep::resnull, ExprEvalStep::resvalue, PLpgSQL_type::typoid, and PLpgSQL_var::value.

Referenced by plpgsql_param_compile().

◆ plpgsql_param_fetch()

static ParamExternData * plpgsql_param_fetch ( ParamListInfo  params,
int  paramid,
bool  speculative,
ParamExternData prm 
)
static

Definition at line 6316 of file pl_exec.c.

6319 {
6320  int dno;
6321  PLpgSQL_execstate *estate;
6322  PLpgSQL_expr *expr;
6323  PLpgSQL_datum *datum;
6324  bool ok = true;
6325  int32 prmtypmod;
6326 
6327  /* paramid's are 1-based, but dnos are 0-based */
6328  dno = paramid - 1;
6329  Assert(dno >= 0 && dno < params->numParams);
6330 
6331  /* fetch back the hook data */
6332  estate = (PLpgSQL_execstate *) params->paramFetchArg;
6333  expr = (PLpgSQL_expr *) params->parserSetupArg;
6334  Assert(params->numParams == estate->ndatums);
6335 
6336  /* now we can access the target datum */
6337  datum = estate->datums[dno];
6338 
6339  /*
6340  * Since copyParamList() or SerializeParamList() will try to materialize
6341  * every single parameter slot, it's important to return a dummy param
6342  * when asked for a datum that's not supposed to be used by this SQL
6343  * expression. Otherwise we risk failures in exec_eval_datum(), or
6344  * copying a lot more data than necessary.
6345  */
6346  if (!bms_is_member(dno, expr->paramnos))
6347  ok = false;
6348 
6349  /*
6350  * If the access is speculative, we prefer to return no data rather than
6351  * to fail in exec_eval_datum(). Check the likely failure cases.
6352  */
6353  else if (speculative)
6354  {
6355  switch (datum->dtype)
6356  {
6357  case PLPGSQL_DTYPE_VAR:
6358  case PLPGSQL_DTYPE_PROMISE:
6359  /* always safe */
6360  break;
6361 
6362  case PLPGSQL_DTYPE_ROW:
6363  /* should be safe in all interesting cases */
6364  break;
6365 
6366  case PLPGSQL_DTYPE_REC:
6367  /* always safe (might return NULL, that's fine) */
6368  break;
6369 
6371  {
6372  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
6373  PLpgSQL_rec *rec;
6374 
6375  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
6376 
6377  /*
6378  * If record variable is NULL, don't risk anything.
6379  */
6380  if (rec->erh == NULL)
6381  ok = false;
6382 
6383  /*
6384  * Look up the field's properties if we have not already,
6385  * or if the tuple descriptor ID changed since last time.
6386  */
6387  else if (unlikely(recfield->rectupledescid != rec->erh->er_tupdesc_id))
6388  {
6390  recfield->fieldname,
6391  &recfield->finfo))
6392  recfield->rectupledescid = rec->erh->er_tupdesc_id;
6393  else
6394  ok = false;
6395  }
6396  break;
6397  }
6398 
6399  default:
6400  ok = false;
6401  break;
6402  }
6403  }
6404 
6405  /* Return "no such parameter" if not ok */
6406  if (!ok)
6407  {
6408  prm->value = (Datum) 0;
6409  prm->isnull = true;
6410  prm->pflags = 0;
6411  prm->ptype = InvalidOid;
6412  return prm;
6413  }
6414 
6415  /* OK, evaluate the value and store into the return struct */
6416  exec_eval_datum(estate, datum,
6417  &prm->ptype, &prmtypmod,
6418  &prm->value, &prm->isnull);
6419  /* We can always mark params as "const" for executor's purposes */
6420  prm->pflags = PARAM_FLAG_CONST;
6421 
6422  /*
6423  * If it's a read/write expanded datum, convert reference to read-only.
6424  * (There's little point in trying to optimize read/write parameters,
6425  * given the cases in which this function is used.)
6426  */
6427  if (datum->dtype == PLPGSQL_DTYPE_VAR)
6429  prm->isnull,
6430  ((PLpgSQL_var *) datum)->datatype->typlen);
6431  else if (datum->dtype == PLPGSQL_DTYPE_REC)
6433  prm->isnull,
6434  -1);
6435 
6436  return prm;
6437 }

References Assert, bms_is_member(), PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, ExpandedRecordHeader::er_tupdesc_id, PLpgSQL_rec::erh, exec_eval_datum(), expanded_record_lookup_field(), PLpgSQL_recfield::fieldname, PLpgSQL_recfield::finfo, InvalidOid, ParamExternData::isnull, MakeExpandedObjectReadOnly, PLpgSQL_execstate::ndatums, ParamListInfoData::numParams, PARAM_FLAG_CONST, ParamListInfoData::paramFetchArg, PLpgSQL_expr::paramnos, ParamListInfoData::parserSetupArg, ParamExternData::pflags, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, ParamExternData::ptype, PLpgSQL_recfield::recparentno, PLpgSQL_recfield::rectupledescid, unlikely, and ParamExternData::value.

Referenced by plpgsql_estate_setup().

◆ plpgsql_subxact_cb()

void plpgsql_subxact_cb ( SubXactEvent  event,
SubTransactionId  mySubid,
SubTransactionId  parentSubid,
void *  arg 
)

◆ plpgsql_xact_cb()

void plpgsql_xact_cb ( XactEvent  event,
void *  arg 
)

Definition at line 8482 of file pl_exec.c.

8483 {
8484  /*
8485  * If we are doing a clean transaction shutdown, free the EState and tell
8486  * the resowner to release whatever plancache references it has, so that
8487  * all remaining resources will be released correctly. (We don't need to
8488  * actually delete the resowner here; deletion of the
8489  * TopTransactionResourceOwner will take care of that.)
8490  *
8491  * In an abort, we expect the regular abort recovery procedures to release
8492  * everything of interest, so just clear our pointers.
8493  */
8494  if (event == XACT_EVENT_COMMIT ||
8495  event == XACT_EVENT_PARALLEL_COMMIT ||
8496  event == XACT_EVENT_PREPARE)
8497  {
8498  simple_econtext_stack = NULL;
8499 
8506  }
8507  else if (event == XACT_EVENT_ABORT ||
8508  event == XACT_EVENT_PARALLEL_ABORT)
8509  {
8510  simple_econtext_stack = NULL;
8513  }
8514 }
void FreeExecutorState(EState *estate)
Definition: execUtils.c:191
void ReleaseAllPlanCacheRefsInOwner(ResourceOwner owner)
Definition: plancache.c:2234
@ XACT_EVENT_COMMIT
Definition: xact.h:128
@ XACT_EVENT_PARALLEL_COMMIT
Definition: xact.h:129
@ XACT_EVENT_ABORT
Definition: xact.h:130
@ XACT_EVENT_PARALLEL_ABORT
Definition: xact.h:131
@ XACT_EVENT_PREPARE
Definition: xact.h:132

References FreeExecutorState(), ReleaseAllPlanCacheRefsInOwner(), shared_simple_eval_estate, shared_simple_eval_resowner, simple_econtext_stack, XACT_EVENT_ABORT, XACT_EVENT_COMMIT, XACT_EVENT_PARALLEL_ABORT, XACT_EVENT_PARALLEL_COMMIT, and XACT_EVENT_PREPARE.

Referenced by _PG_init().

◆ pop_stmt_mcontext()

static void pop_stmt_mcontext ( PLpgSQL_execstate estate)
static

Definition at line 1566 of file pl_exec.c.

1567 {
1568  /* We need only pop the stack */
1569  estate->stmt_mcontext = estate->stmt_mcontext_parent;
1571 }
MemoryContext MemoryContextGetParent(MemoryContext context)
Definition: mcxt.c:731

References MemoryContextGetParent(), PLpgSQL_execstate::stmt_mcontext, and PLpgSQL_execstate::stmt_mcontext_parent.

Referenced by exec_stmt_block(), and exec_stmt_foreach_a().

◆ push_stmt_mcontext()

static void push_stmt_mcontext ( PLpgSQL_execstate estate)
static

Definition at line 1547 of file pl_exec.c.

1548 {
1549  /* Should have done get_stmt_mcontext() first */
1550  Assert(estate->stmt_mcontext != NULL);
1551  /* Assert we've not messed up the stack linkage */
1553  /* Push it down to become the parent of any nested stmt mcontext */
1554  estate->stmt_mcontext_parent = estate->stmt_mcontext;
1555  /* And make it not available for use directly */
1556  estate->stmt_mcontext = NULL;
1557 }

References Assert, MemoryContextGetParent(), PLpgSQL_execstate::stmt_mcontext, and PLpgSQL_execstate::stmt_mcontext_parent.

Referenced by exec_stmt_foreach_a().

◆ revalidate_rectypeid()

static void revalidate_rectypeid ( PLpgSQL_rec rec)
static

Definition at line 6884 of file pl_exec.c.

6885 {
6886  PLpgSQL_type *typ = rec->datatype;
6887  TypeCacheEntry *typentry;
6888 
6889  if (rec->rectypeid == RECORDOID)
6890  return; /* it's RECORD, so nothing to do */
6891  Assert(typ != NULL);
6892  if (typ->tcache &&
6893  typ->tcache->tupDesc_identifier == typ->tupdesc_id)
6894  {
6895  /*
6896  * Although *typ is known up-to-date, it's possible that rectypeid
6897  * isn't, because *rec is cloned during each function startup from a
6898  * copy that we don't have a good way to update. Hence, forcibly fix
6899  * rectypeid before returning.
6900  */
6901  rec->rectypeid = typ->typoid;
6902  return;
6903  }
6904 
6905  /*
6906  * typcache entry has suffered invalidation, so re-look-up the type name
6907  * if possible, and then recheck the type OID. If we don't have a
6908  * TypeName, then we just have to soldier on with the OID we've got.
6909  */
6910  if (typ->origtypname != NULL)
6911  {
6912  /* this bit should match parse_datatype() in pl_gram.y */
6913  typenameTypeIdAndMod(NULL, typ->origtypname,
6914  &typ->typoid,
6915  &typ->atttypmod);
6916  }
6917 
6918  /* this bit should match build_datatype() in pl_comp.c */
6919  typentry = lookup_type_cache(typ->typoid,
6922  if (typentry->typtype == TYPTYPE_DOMAIN)
6923  typentry = lookup_type_cache(typentry->domainBaseType,
6925  if (typentry->tupDesc == NULL)
6926  {
6927  /*
6928  * If we get here, user tried to replace a composite type with a
6929  * non-composite one. We're not gonna support that.
6930  */
6931  ereport(ERROR,
6932  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6933  errmsg("type %s is not composite",
6934  format_type_be(typ->typoid))));
6935  }
6936 
6937  /*
6938  * Update tcache and tupdesc_id. Since we don't support changing to a
6939  * non-composite type, none of the rest of *typ needs to change.
6940  */
6941  typ->tcache = typentry;
6942  typ->tupdesc_id = typentry->tupDesc_identifier;
6943 
6944  /*
6945  * Update *rec, too. (We'll deal with subsidiary RECFIELDs as needed.)
6946  */
6947  rec->rectypeid = typ->typoid;
6948 }
void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName, Oid *typeid_p, int32 *typmod_p)
Definition: parse_type.c:310
TypeName * origtypname
Definition: plpgsql.h:210
TypeCacheEntry * tcache
Definition: plpgsql.h:211
uint64 tupdesc_id
Definition: plpgsql.h:212
uint64 tupDesc_identifier
Definition: typcache.h:90
char typtype
Definition: typcache.h:43
TupleDesc tupDesc
Definition: typcache.h:89
Oid domainBaseType
Definition: typcache.h:114
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:386
#define TYPECACHE_TUPDESC
Definition: typcache.h:145
#define TYPECACHE_DOMAIN_BASE_INFO
Definition: typcache.h:149

References Assert, PLpgSQL_type::atttypmod, PLpgSQL_rec::datatype, TypeCacheEntry::domainBaseType, ereport, errcode(), errmsg(), ERROR, format_type_be(), lookup_type_cache(), PLpgSQL_type::origtypname, PLpgSQL_rec::rectypeid, PLpgSQL_type::tcache, TypeCacheEntry::tupDesc, PLpgSQL_type::tupdesc_id, TypeCacheEntry::tupDesc_identifier, TYPECACHE_DOMAIN_BASE_INFO, TYPECACHE_TUPDESC, typenameTypeIdAndMod(), PLpgSQL_type::typoid, and TypeCacheEntry::typtype.

Referenced by exec_move_row_from_datum(), instantiate_empty_record_variable(), and make_expanded_record_for_rec().

◆ setup_param_list()

static ParamListInfo setup_param_list ( PLpgSQL_execstate estate,
PLpgSQL_expr expr 
)
static

Definition at line 6261 of file pl_exec.c.

6262 {
6263  ParamListInfo paramLI;
6264 
6265  /*
6266  * We must have created the SPIPlan already (hence, query text has been
6267  * parsed/analyzed at least once); else we cannot rely on expr->paramnos.
6268  */
6269  Assert(expr->plan != NULL);
6270 
6271  /*
6272  * We only need a ParamListInfo if the expression has parameters.
6273  */
6274  if (!bms_is_empty(expr->paramnos))
6275  {
6276  /* Use the common ParamListInfo */
6277  paramLI = estate->paramLI;
6278 
6279  /*
6280  * Set up link to active expr where the hook functions can find it.
6281  * Callers must save and restore parserSetupArg if there is any chance
6282  * that they are interrupting an active use of parameters.
6283  */
6284  paramLI->parserSetupArg = (void *) expr;
6285 
6286  /*
6287  * Also make sure this is set before parser hooks need it. There is
6288  * no need to save and restore, since the value is always correct once
6289  * set. (Should be set already, but let's be sure.)
6290  */
6291  expr->func = estate->func;
6292  }
6293  else
6294  {
6295  /*
6296  * Expression requires no parameters. Be sure we represent this case
6297  * as a NULL ParamListInfo, so that plancache.c knows there is no
6298  * point in a custom plan.
6299  */
6300  paramLI = NULL;
6301  }
6302  return paramLI;
6303 }
#define bms_is_empty(a)
Definition: bitmapset.h:118

References Assert, bms_is_empty, PLpgSQL_expr::func, PLpgSQL_execstate::func, PLpgSQL_execstate::paramLI, PLpgSQL_expr::paramnos, ParamListInfoData::parserSetupArg, and PLpgSQL_expr::plan.

Referenced by exec_run_select(), exec_stmt_call(), exec_stmt_execsql(), exec_stmt_forc(), exec_stmt_open(), and exec_stmt_return_query().

Variable Documentation

◆ cast_expr_hash

HTAB* cast_expr_hash = NULL
static

Definition at line 177 of file pl_exec.c.

Referenced by get_cast_hashentry(), and plpgsql_estate_setup().

◆ shared_cast_hash

HTAB* shared_cast_hash = NULL
static

Definition at line 178 of file pl_exec.c.

Referenced by plpgsql_estate_setup().

◆ shared_simple_eval_estate

EState* shared_simple_eval_estate = NULL
static

Definition at line 90 of file pl_exec.c.

Referenced by plpgsql_create_econtext(), plpgsql_estate_setup(), and plpgsql_xact_cb().

◆ shared_simple_eval_resowner

ResourceOwner shared_simple_eval_resowner = NULL
static

Definition at line 101 of file pl_exec.c.

Referenced by plpgsql_create_econtext(), plpgsql_estate_setup(), and plpgsql_xact_cb().

◆ simple_econtext_stack

SimpleEcontextStackEntry* simple_econtext_stack = NULL
static