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

Go to the source code of this file.

Data Structures

struct  SimpleEcontextStackEntry
 
struct  plpgsql_CastHashKey
 
struct  plpgsql_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 133 of file pl_exec.c.

◆ eval_mcontext_alloc0

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

Definition at line 135 of file pl_exec.c.

◆ get_eval_mcontext

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

Definition at line 131 of file pl_exec.c.

◆ LOOP_RC_PROCESSING

#define LOOP_RC_PROCESSING (   looplabel,
  exit_action 
)

Definition at line 208 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 3712 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 8631 of file pl_exec.c.

8633 {
8634  Assert(rec->dtype == PLPGSQL_DTYPE_REC);
8635 
8636  /* Transfer new record object into datum_context */
8637  TransferExpandedRecord(erh, estate->datum_context);
8638 
8639  /* Free the old value ... */
8640  if (rec->erh)
8642 
8643  /* ... and install the new */
8644  rec->erh = erh;
8645 }
#define Assert(condition)
Definition: c.h:849
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 8555 of file pl_exec.c.

8557 {
8558  Assert(var->dtype == PLPGSQL_DTYPE_VAR ||
8559  var->dtype == PLPGSQL_DTYPE_PROMISE);
8560 
8561  /*
8562  * In non-atomic contexts, we do not want to store TOAST pointers in
8563  * variables, because such pointers might become stale after a commit.
8564  * Forcibly detoast in such cases. We don't want to detoast (flatten)
8565  * expanded objects, however; those should be OK across a transaction
8566  * boundary since they're just memory-resident objects. (Elsewhere in
8567  * this module, operations on expanded records likewise need to request
8568  * detoasting of record fields when !estate->atomic. Expanded arrays are
8569  * not a problem since all array entries are always detoasted.)
8570  */
8571  if (!estate->atomic && !isnull && var->datatype->typlen == -1 &&
8573  {
8574  MemoryContext oldcxt;
8575  Datum detoasted;
8576 
8577  /*
8578  * Do the detoasting in the eval_mcontext to avoid long-term leakage
8579  * of whatever memory toast fetching might leak. Then we have to copy
8580  * the detoasted datum to the function's main context, which is a
8581  * pain, but there's little choice.
8582  */
8583  oldcxt = MemoryContextSwitchTo(get_eval_mcontext(estate));
8584  detoasted = PointerGetDatum(detoast_external_attr((struct varlena *) DatumGetPointer(newvalue)));
8585  MemoryContextSwitchTo(oldcxt);
8586  /* Now's a good time to not leak the input value if it's freeable */
8587  if (freeable)
8588  pfree(DatumGetPointer(newvalue));
8589  /* Once we copy the value, it's definitely freeable */
8590  newvalue = datumCopy(detoasted, false, -1);
8591  freeable = true;
8592  /* Can't clean up eval_mcontext here, but it'll happen before long */
8593  }
8594 
8595  /* Free the old value if needed */
8596  if (var->freeval)
8597  {
8599  var->isnull,
8600  var->datatype->typlen))
8602  else
8603  pfree(DatumGetPointer(var->value));
8604  }
8605  /* Assign new value to datum */
8606  var->value = newvalue;
8607  var->isnull = isnull;
8608  var->freeval = freeable;
8609 
8610  /*
8611  * If it's a promise variable, then either we just assigned the promised
8612  * value, or the user explicitly assigned an overriding value. Either
8613  * way, cancel the promise.
8614  */
8616 }
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:131
@ 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:678
#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 8622 of file pl_exec.c.

8623 {
8624  assign_simple_var(estate, var, CStringGetTextDatum(str), false, true);
8625 }
#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:8555

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

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

7298 {
7299  int i;
7300 
7301  /* Possibly we could allow src_tupdesc to have extra columns? */
7302  if (dst_tupdesc->natts != src_tupdesc->natts)
7303  return false;
7304 
7305  for (i = 0; i < dst_tupdesc->natts; i++)
7306  {
7307  Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
7308  Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
7309 
7310  if (dattr->attisdropped != sattr->attisdropped)
7311  return false;
7312  if (!dattr->attisdropped)
7313  {
7314  /* Normal columns must match by type and typmod */
7315  if (dattr->atttypid != sattr->atttypid ||
7316  (dattr->atttypmod >= 0 &&
7317  dattr->atttypmod != sattr->atttypmod))
7318  return false;
7319  }
7320  else
7321  {
7322  /* Dropped columns are OK as long as length/alignment match */
7323  if (dattr->attlen != sattr->attlen ||
7324  dattr->attalign != sattr->attalign)
7325  return false;
7326  }
7327  }
7328  return true;
7329 }
int i
Definition: isn.c:73
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 7695 of file pl_exec.c.

7696 {
7697  char *result;
7698  MemoryContext oldcontext;
7699  Oid typoutput;
7700  bool typIsVarlena;
7701 
7702  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7703  getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
7704  result = OidOutputFunctionCall(typoutput, value);
7705  MemoryContextSwitchTo(oldcontext);
7706 
7707  return result;
7708 }
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1763
static struct @157 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 1298 of file pl_exec.c.

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

7397 {
7398  HeapTupleHeader td;
7399  Oid tupType;
7400  int32 tupTypmod;
7401 
7402  /* Get tuple body (note this could involve detoasting) */
7404 
7405  /* Build a temporary HeapTuple control structure */
7406  tmptup->t_len = HeapTupleHeaderGetDatumLength(td);
7407  ItemPointerSetInvalid(&(tmptup->t_self));
7408  tmptup->t_tableOid = InvalidOid;
7409  tmptup->t_data = td;
7410 
7411  /* Extract rowtype info and find a tupdesc */
7412  tupType = HeapTupleHeaderGetTypeId(td);
7413  tupTypmod = HeapTupleHeaderGetTypMod(td);
7414  return lookup_rowtype_tupdesc(tupType, tupTypmod);
7415 }
signed int int32
Definition: c.h:496
#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:1850

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

7752 {
7753  plpgsql_CastHashEntry *cast_entry;
7754 
7755  cast_entry = get_cast_hashentry(estate,
7756  valtype, valtypmod,
7757  reqtype, reqtypmod);
7758  if (cast_entry)
7759  {
7760  ExprContext *econtext = estate->eval_econtext;
7761  MemoryContext oldcontext;
7762 
7763  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7764 
7765  econtext->caseValue_datum = value;
7766  econtext->caseValue_isNull = *isnull;
7767 
7768  cast_entry->cast_in_use = true;
7769 
7770  value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
7771  isnull);
7772 
7773  cast_entry->cast_in_use = false;
7774 
7775  MemoryContextSwitchTo(oldcontext);
7776  }
7777 
7778  return value;
7779 }
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:7792
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:177

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

1584 {
1585  for (; cond != NULL; cond = cond->next)
1586  {
1587  int sqlerrstate = cond->sqlerrstate;
1588 
1589  /*
1590  * OTHERS matches everything *except* query-canceled and
1591  * assert-failure. If you're foolish enough, you can match those
1592  * explicitly.
1593  */
1594  if (sqlerrstate == 0)
1595  {
1596  if (edata->sqlerrcode != ERRCODE_QUERY_CANCELED &&
1597  edata->sqlerrcode != ERRCODE_ASSERT_FAILURE)
1598  return true;
1599  }
1600  /* Exact match? */
1601  else if (edata->sqlerrcode == sqlerrstate)
1602  return true;
1603  /* Category match? */
1604  else if (ERRCODE_IS_CATEGORY(sqlerrstate) &&
1605  ERRCODE_TO_CATEGORY(edata->sqlerrcode) == sqlerrstate)
1606  return true;
1607  }
1608  return false;
1609 }
#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 5055 of file pl_exec.c.

5057 {
5058  text *value;
5059  MemoryContext oldcontext;
5060 
5061  /* Use eval_mcontext for short-lived text value */
5062  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5063  if (str != NULL)
5065  else
5066  value = cstring_to_text("");
5067  MemoryContextSwitchTo(oldcontext);
5068 
5069  exec_assign_value(estate, target, PointerGetDatum(value), false,
5070  TEXTOID, -1);
5071 }
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:5083
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 5011 of file pl_exec.c.

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

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

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

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

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

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

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

5667 {
5668  Datum exprdatum;
5669  Oid exprtypeid;
5670  int32 exprtypmod;
5671 
5672  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5673  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5674  exprtypeid, exprtypmod,
5675  BOOLOID, -1);
5676  return DatumGetBool(exprdatum);
5677 }
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 4138 of file pl_exec.c.

4139 {
4140  /* Clear result of a full SPI_execute */
4141  if (estate->eval_tuptable != NULL)
4143  estate->eval_tuptable = NULL;
4144 
4145  /*
4146  * Clear result of exec_eval_simple_expr (but keep the econtext). This
4147  * also clears any short-lived allocations done via get_eval_mcontext.
4148  */
4149  if (estate->eval_econtext != NULL)
4151 }
#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 5310 of file pl_exec.c.

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

5692 {
5693  Datum result = 0;
5694  int rc;
5695  Form_pg_attribute attr;
5696 
5697  /*
5698  * If first time through, create a plan for this expression.
5699  */
5700  if (expr->plan == NULL)
5702 
5703  /*
5704  * If this is a simple expression, bypass SPI and use the executor
5705  * directly
5706  */
5707  if (exec_eval_simple_expr(estate, expr,
5708  &result, isNull, rettype, rettypmod))
5709  return result;
5710 
5711  /*
5712  * Else do it the hard way via exec_run_select
5713  */
5714  rc = exec_run_select(estate, expr, 2, NULL);
5715  if (rc != SPI_OK_SELECT)
5716  ereport(ERROR,
5717  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5718  errmsg("query did not return data"),
5719  errcontext("query: %s", expr->query)));
5720 
5721  /*
5722  * Check that the expression returns exactly one column...
5723  */
5724  if (estate->eval_tuptable->tupdesc->natts != 1)
5725  ereport(ERROR,
5726  (errcode(ERRCODE_SYNTAX_ERROR),
5727  errmsg_plural("query returned %d column",
5728  "query returned %d columns",
5729  estate->eval_tuptable->tupdesc->natts,
5730  estate->eval_tuptable->tupdesc->natts),
5731  errcontext("query: %s", expr->query)));
5732 
5733  /*
5734  * ... and get the column's datatype.
5735  */
5736  attr = TupleDescAttr(estate->eval_tuptable->tupdesc, 0);
5737  *rettype = attr->atttypid;
5738  *rettypmod = attr->atttypmod;
5739 
5740  /*
5741  * If there are no rows selected, the result is a NULL of that type.
5742  */
5743  if (estate->eval_processed == 0)
5744  {
5745  *isNull = true;
5746  return (Datum) 0;
5747  }
5748 
5749  /*
5750  * Check that the expression returned no more than one row.
5751  */
5752  if (estate->eval_processed != 1)
5753  ereport(ERROR,
5754  (errcode(ERRCODE_CARDINALITY_VIOLATION),
5755  errmsg("query returned more than one row"),
5756  errcontext("query: %s", expr->query)));
5757 
5758  /*
5759  * Return the single result Datum.
5760  */
5761  return SPI_getbinval(estate->eval_tuptable->vals[0],
5762  estate->eval_tuptable->tupdesc, 1, isNull);
5763 }
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:3307
static bool exec_eval_simple_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, Datum *result, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:6037
static int exec_run_select(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
Definition: pl_exec.c:5771
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 5641 of file pl_exec.c.

5644 {
5645  Datum exprdatum;
5646  Oid exprtypeid;
5647  int32 exprtypmod;
5648 
5649  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5650  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5651  exprtypeid, exprtypmod,
5652  INT4OID, -1);
5653  return DatumGetInt32(exprdatum);
5654 }
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 6037 of file pl_exec.c.

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

8655 {
8656  ParamListInfo paramLI;
8657  int nargs;
8658  MemoryContext stmt_mcontext;
8659  MemoryContext oldcontext;
8660  int i;
8661  ListCell *lc;
8662 
8663  /* Fast path for no parameters: we can just return NULL */
8664  if (params == NIL)
8665  return NULL;
8666 
8667  nargs = list_length(params);
8668  stmt_mcontext = get_stmt_mcontext(estate);
8669  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8670  paramLI = makeParamList(nargs);
8671  MemoryContextSwitchTo(oldcontext);
8672 
8673  i = 0;
8674  foreach(lc, params)
8675  {
8676  PLpgSQL_expr *param = (PLpgSQL_expr *) lfirst(lc);
8677  ParamExternData *prm = &paramLI->params[i];
8678  int32 ppdtypmod;
8679 
8680  /*
8681  * Always mark params as const, since we only use the result with
8682  * one-shot plans.
8683  */
8684  prm->pflags = PARAM_FLAG_CONST;
8685 
8686  prm->value = exec_eval_expr(estate, param,
8687  &prm->isnull,
8688  &prm->ptype,
8689  &ppdtypmod);
8690 
8691  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8692 
8693  if (prm->ptype == UNKNOWNOID)
8694  {
8695  /*
8696  * Treat 'unknown' parameters as text, since that's what most
8697  * people would expect. The SPI functions can coerce unknown
8698  * constants in a more intelligent way, but not unknown Params.
8699  * This code also takes care of copying into the right context.
8700  * Note we assume 'unknown' has the representation of C-string.
8701  */
8702  prm->ptype = TEXTOID;
8703  if (!prm->isnull)
8705  }
8706  /* pass-by-ref non null values must be copied into stmt_mcontext */
8707  else if (!prm->isnull)
8708  {
8709  int16 typLen;
8710  bool typByVal;
8711 
8712  get_typlenbyval(prm->ptype, &typLen, &typByVal);
8713  if (!typByVal)
8714  prm->value = datumCopy(prm->value, typByVal, typLen);
8715  }
8716 
8717  MemoryContextSwitchTo(oldcontext);
8718 
8719  exec_eval_cleanup(estate);
8720 
8721  i++;
8722  }
8723 
8724  return paramLI;
8725 }
signed short int16
Definition: c.h:495
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 5855 of file pl_exec.c.

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

3672 {
3673  ReturnSetInfo *rsi = estate->rsi;
3674  MemoryContext oldcxt;
3675  ResourceOwner oldowner;
3676 
3677  /*
3678  * Check caller can handle a set result in the way we want
3679  */
3680  if (!rsi || !IsA(rsi, ReturnSetInfo))
3681  ereport(ERROR,
3682  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3683  errmsg("set-valued function called in context that cannot accept a set")));
3684 
3685  if (!(rsi->allowedModes & SFRM_Materialize) ||
3686  rsi->expectedDesc == NULL)
3687  ereport(ERROR,
3688  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3689  errmsg("materialize mode required, but it is not allowed in this context")));
3690 
3691  /*
3692  * Switch to the right memory context and resource owner for storing the
3693  * tuplestore for return set. If we're within a subtransaction opened for
3694  * an exception-block, for example, we must still create the tuplestore in
3695  * the resource owner that was active when this function was entered, and
3696  * not in the subtransaction resource owner.
3697  */
3698  oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
3699  oldowner = CurrentResourceOwner;
3701 
3702  estate->tuple_store =
3704  false, work_mem);
3705 
3706  CurrentResourceOwner = oldowner;
3707  MemoryContextSwitchTo(oldcxt);
3708 
3709  estate->tuple_store_desc = rsi->expectedDesc;
3710 }
@ 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 8054 of file pl_exec.c.

8055 {
8056  List *plansources;
8057  CachedPlanSource *plansource;
8058  Query *query;
8059 
8060  /*
8061  * We can only test queries that resulted in exactly one CachedPlanSource.
8062  */
8063  plansources = SPI_plan_get_plan_sources(expr->plan);
8064  if (list_length(plansources) != 1)
8065  return false;
8066  plansource = (CachedPlanSource *) linitial(plansources);
8067 
8068  /*
8069  * 1. There must be one single querytree.
8070  */
8071  if (list_length(plansource->query_list) != 1)
8072  return false;
8073  query = (Query *) linitial(plansource->query_list);
8074 
8075  /*
8076  * 2. It must be a plain SELECT query without any input tables.
8077  */
8078  if (!IsA(query, Query))
8079  return false;
8080  if (query->commandType != CMD_SELECT)
8081  return false;
8082  if (query->rtable != NIL)
8083  return false;
8084 
8085  /*
8086  * 3. Can't have any subplans, aggregates, qual clauses either. (These
8087  * tests should generally match what inline_function() checks before
8088  * inlining a SQL function; otherwise, inlining could change our
8089  * conclusion about whether an expression is simple, which we don't want.)
8090  */
8091  if (query->hasAggs ||
8092  query->hasWindowFuncs ||
8093  query->hasTargetSRFs ||
8094  query->hasSubLinks ||
8095  query->cteList ||
8096  query->jointree->fromlist ||
8097  query->jointree->quals ||
8098  query->groupClause ||
8099  query->groupingSets ||
8100  query->havingQual ||
8101  query->windowClause ||
8102  query->distinctClause ||
8103  query->sortClause ||
8104  query->limitOffset ||
8105  query->limitCount ||
8106  query->setOperations)
8107  return false;
8108 
8109  /*
8110  * 4. The query must have a single attribute as result.
8111  */
8112  if (list_length(query->targetList) != 1)
8113  return false;
8114 
8115  /*
8116  * OK, we can treat it as a simple plan.
8117  */
8118  return true;
8119 }
@ 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 6753 of file pl_exec.c.

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

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

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

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

4177 {
4178  SPIPlanPtr plan;
4180 
4181  /*
4182  * The grammar can't conveniently set expr->func while building the parse
4183  * tree, so make sure it's set before parser hooks need it.
4184  */
4185  expr->func = estate->func;
4186 
4187  /*
4188  * Generate and save the plan
4189  */
4190  memset(&options, 0, sizeof(options));
4192  options.parserSetupArg = (void *) expr;
4193  options.parseMode = expr->parseMode;
4194  options.cursorOptions = cursorOptions;
4196  if (plan == NULL)
4197  elog(ERROR, "SPI_prepare_extended failed for \"%s\": %s",
4199 
4200  SPI_keepplan(plan);
4201  expr->plan = plan;
4202 
4203  /* Check to see if it's a simple expression */
4204  exec_simple_check_plan(estate, expr);
4205 }
void(* ParserSetupHook)(struct ParseState *pstate, void *arg)
Definition: params.h:108
#define plan(x)
Definition: pg_regress.c:162
void plpgsql_parser_setup(struct ParseState *pstate, PLpgSQL_expr *expr)
Definition: pl_comp.c:1077
static void exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:7983
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 5771 of file pl_exec.c.

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

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

8380 {
8381  PLpgSQL_var *var;
8382 
8383  var = (PLpgSQL_var *) (estate->datums[estate->found_varno]);
8384  assign_simple_var(estate, var, BoolGetDatum(state), false, false);
8385 }
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 7983 of file pl_exec.c.

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

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

3939 {
3940  bool value;
3941  bool isnull;
3942 
3943  /* do nothing when asserts are not enabled */
3944  if (!plpgsql_check_asserts)
3945  return PLPGSQL_RC_OK;
3946 
3947  value = exec_eval_boolean(estate, stmt->cond, &isnull);
3948  exec_eval_cleanup(estate);
3949 
3950  if (isnull || !value)
3951  {
3952  char *message = NULL;
3953 
3954  if (stmt->message != NULL)
3955  {
3956  Datum val;
3957  Oid typeid;
3958  int32 typmod;
3959 
3960  val = exec_eval_expr(estate, stmt->message,
3961  &isnull, &typeid, &typmod);
3962  if (!isnull)
3963  message = convert_value_to_string(estate, val, typeid);
3964  /* we mustn't do exec_eval_cleanup here */
3965  }
3966 
3967  ereport(ERROR,
3968  (errcode(ERRCODE_ASSERT_FAILURE),
3969  message ? errmsg_internal("%s", message) :
3970  errmsg("assertion failed")));
3971  }
3972 
3973  return PLPGSQL_RC_OK;
3974 }
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:5664
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 2152 of file pl_exec.c.

2153 {
2154  Assert(stmt->varno >= 0);
2155 
2156  exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);
2157 
2158  return PLPGSQL_RC_OK;
2159 }
static void exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
Definition: pl_exec.c:5011

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

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

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

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

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

4922 {
4923  PLpgSQL_var *curvar;
4924  Portal portal;
4925  char *curname;
4926  MemoryContext oldcontext;
4927 
4928  /* ----------
4929  * Get the portal of the cursor by name
4930  * ----------
4931  */
4932  curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
4933  if (curvar->isnull)
4934  ereport(ERROR,
4935  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4936  errmsg("cursor variable \"%s\" is null", curvar->refname)));
4937 
4938  /* Use eval_mcontext for short-lived string */
4939  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
4940  curname = TextDatumGetCString(curvar->value);
4941  MemoryContextSwitchTo(oldcontext);
4942 
4943  portal = SPI_cursor_find(curname);
4944  if (portal == NULL)
4945  ereport(ERROR,
4946  (errcode(ERRCODE_UNDEFINED_CURSOR),
4947  errmsg("cursor \"%s\" does not exist", curname)));
4948 
4949  /* ----------
4950  * And close it.
4951  * ----------
4952  */
4953  SPI_cursor_close(portal);
4954 
4955  return PLPGSQL_RC_OK;
4956 }
#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 4964 of file pl_exec.c.

4965 {
4966  if (stmt->chain)
4968  else
4969  SPI_commit();
4970 
4971  /*
4972  * We need to build new simple-expression infrastructure, since the old
4973  * data structures are gone.
4974  */
4975  estate->simple_eval_estate = NULL;
4976  estate->simple_eval_resowner = NULL;
4977  plpgsql_create_econtext(estate);
4978 
4979  return PLPGSQL_RC_OK;
4980 }
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 4448 of file pl_exec.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

2399 {
2400  ListCell *lc;
2401 
2402  /*
2403  * GET STACKED DIAGNOSTICS is only valid inside an exception handler.
2404  *
2405  * Note: we trust the grammar to have disallowed the relevant item kinds
2406  * if not is_stacked, otherwise we'd dump core below.
2407  */
2408  if (stmt->is_stacked && estate->cur_error == NULL)
2409  ereport(ERROR,
2410  (errcode(ERRCODE_STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER),
2411  errmsg("GET STACKED DIAGNOSTICS cannot be used outside an exception handler")));
2412 
2413  foreach(lc, stmt->diag_items)
2414  {
2415  PLpgSQL_diag_item *diag_item = (PLpgSQL_diag_item *) lfirst(lc);
2416  PLpgSQL_datum *var = estate->datums[diag_item->target];
2417 
2418  switch (diag_item->kind)
2419  {
2421  exec_assign_value(estate, var,
2422  UInt64GetDatum(estate->eval_processed),
2423  false, INT8OID, -1);
2424  break;
2425 
2427  exec_assign_value(estate, var,
2428  ObjectIdGetDatum(estate->func->fn_oid),
2429  false, OIDOID, -1);
2430  break;
2431 
2433  exec_assign_c_string(estate, var,
2434  estate->cur_error->context);
2435  break;
2436 
2438  exec_assign_c_string(estate, var,
2439  estate->cur_error->detail);
2440  break;
2441 
2443  exec_assign_c_string(estate, var,
2444  estate->cur_error->hint);
2445  break;
2446 
2448  exec_assign_c_string(estate, var,
2450  break;
2451 
2453  exec_assign_c_string(estate, var,
2454  estate->cur_error->column_name);
2455  break;
2456 
2458  exec_assign_c_string(estate, var,
2459  estate->cur_error->constraint_name);
2460  break;
2461 
2463  exec_assign_c_string(estate, var,
2464  estate->cur_error->datatype_name);
2465  break;
2466 
2468  exec_assign_c_string(estate, var,
2469  estate->cur_error->message);
2470  break;
2471 
2473  exec_assign_c_string(estate, var,
2474  estate->cur_error->table_name);
2475  break;
2476 
2478  exec_assign_c_string(estate, var,
2479  estate->cur_error->schema_name);
2480  break;
2481 
2483  {
2484  char *contextstackstr;
2485  MemoryContext oldcontext;
2486 
2487  /* Use eval_mcontext for short-lived string */
2488  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
2489  contextstackstr = GetErrorContextStack();
2490  MemoryContextSwitchTo(oldcontext);
2491 
2492  exec_assign_c_string(estate, var, contextstackstr);
2493  }
2494  break;
2495 
2496  default:
2497  elog(ERROR, "unrecognized diagnostic item kind: %d",
2498  diag_item->kind);
2499  }
2500  }
2501 
2502  exec_eval_cleanup(estate);
2503 
2504  return PLPGSQL_RC_OK;
2505 }
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:5055
@ 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 2514 of file pl_exec.c.

2515 {
2516  bool value;
2517  bool isnull;
2518  ListCell *lc;
2519 
2520  value = exec_eval_boolean(estate, stmt->cond, &isnull);
2521  exec_eval_cleanup(estate);
2522  if (!isnull && value)
2523  return exec_stmts(estate, stmt->then_body);
2524 
2525  foreach(lc, stmt->elsif_list)
2526  {
2527  PLpgSQL_if_elsif *elif = (PLpgSQL_if_elsif *) lfirst(lc);
2528 
2529  value = exec_eval_boolean(estate, elif->cond, &isnull);
2530  exec_eval_cleanup(estate);
2531  if (!isnull && value)
2532  return exec_stmts(estate, elif->stmts);
2533  }
2534 
2535  return exec_stmts(estate, stmt->else_body);
2536 }
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 2631 of file pl_exec.c.

2632 {
2633  int rc = PLPGSQL_RC_OK;
2634 
2635  for (;;)
2636  {
2637  rc = exec_stmts(estate, stmt->body);
2638 
2639  LOOP_RC_PROCESSING(stmt->label, break);
2640  }
2641 
2642  return rc;
2643 }

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

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

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

2169 {
2170  PLpgSQL_expr *expr = stmt->expr;
2171 
2172  (void) exec_run_select(estate, expr, 0, NULL);
2173  exec_set_found(estate, (estate->eval_processed != 0));
2174  exec_eval_cleanup(estate);
2175 
2176  return PLPGSQL_RC_OK;
2177 }

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

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

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

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

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

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

4989 {
4990  if (stmt->chain)
4992  else
4993  SPI_rollback();
4994 
4995  /*
4996  * We need to build new simple-expression infrastructure, since the old
4997  * data structures are gone.
4998  */
4999  estate->simple_eval_estate = NULL;
5000  estate->simple_eval_resowner = NULL;
5001  plpgsql_create_econtext(estate);
5002 
5003  return PLPGSQL_RC_OK;
5004 }
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 2653 of file pl_exec.c.

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

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

1985 {
1986  PLpgSQL_stmt *save_estmt = estate->err_stmt;
1987  ListCell *s;
1988 
1989  if (stmts == NIL)
1990  {
1991  /*
1992  * Ensure we do a CHECK_FOR_INTERRUPTS() even though there is no
1993  * statement. This prevents hangup in a tight loop if, for instance,
1994  * there is a LOOP construct with an empty body.
1995  */
1997  return PLPGSQL_RC_OK;
1998  }
1999 
2000  foreach(s, stmts)
2001  {
2003  int rc;
2004 
2005  estate->err_stmt = stmt;
2006 
2007  /* Let the plugin know that we are about to execute this statement */
2008  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
2009  ((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt);
2010 
2012 
2013  switch (stmt->cmd_type)
2014  {
2015  case PLPGSQL_STMT_BLOCK:
2016  rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt);
2017  break;
2018 
2019  case PLPGSQL_STMT_ASSIGN:
2020  rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
2021  break;
2022 
2023  case PLPGSQL_STMT_PERFORM:
2024  rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt);
2025  break;
2026 
2027  case PLPGSQL_STMT_CALL:
2028  rc = exec_stmt_call(estate, (PLpgSQL_stmt_call *) stmt);
2029  break;
2030 
2031  case PLPGSQL_STMT_GETDIAG:
2032  rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt);
2033  break;
2034 
2035  case PLPGSQL_STMT_IF:
2036  rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);
2037  break;
2038 
2039  case PLPGSQL_STMT_CASE:
2040  rc = exec_stmt_case(estate, (PLpgSQL_stmt_case *) stmt);
2041  break;
2042 
2043  case PLPGSQL_STMT_LOOP:
2044  rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt);
2045  break;
2046 
2047  case PLPGSQL_STMT_WHILE:
2048  rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt);
2049  break;
2050 
2051  case PLPGSQL_STMT_FORI:
2052  rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt);
2053  break;
2054 
2055  case PLPGSQL_STMT_FORS:
2056  rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt);
2057  break;
2058 
2059  case PLPGSQL_STMT_FORC:
2060  rc = exec_stmt_forc(estate, (PLpgSQL_stmt_forc *) stmt);
2061  break;
2062 
2065  break;
2066 
2067  case PLPGSQL_STMT_EXIT:
2068  rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt);
2069  break;
2070 
2071  case PLPGSQL_STMT_RETURN:
2072  rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt);
2073  break;
2074 
2077  break;
2078 
2081  break;
2082 
2083  case PLPGSQL_STMT_RAISE:
2084  rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt);
2085  break;
2086 
2087  case PLPGSQL_STMT_ASSERT:
2088  rc = exec_stmt_assert(estate, (PLpgSQL_stmt_assert *) stmt);
2089  break;
2090 
2091  case PLPGSQL_STMT_EXECSQL:
2092  rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt);
2093  break;
2094 
2097  break;
2098 
2099  case PLPGSQL_STMT_DYNFORS:
2100  rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt);
2101  break;
2102 
2103  case PLPGSQL_STMT_OPEN:
2104  rc = exec_stmt_open(estate, (PLpgSQL_stmt_open *) stmt);
2105  break;
2106 
2107  case PLPGSQL_STMT_FETCH:
2108  rc = exec_stmt_fetch(estate, (PLpgSQL_stmt_fetch *) stmt);
2109  break;
2110 
2111  case PLPGSQL_STMT_CLOSE:
2112  rc = exec_stmt_close(estate, (PLpgSQL_stmt_close *) stmt);
2113  break;
2114 
2115  case PLPGSQL_STMT_COMMIT:
2116  rc = exec_stmt_commit(estate, (PLpgSQL_stmt_commit *) stmt);
2117  break;
2118 
2119  case PLPGSQL_STMT_ROLLBACK:
2120  rc = exec_stmt_rollback(estate, (PLpgSQL_stmt_rollback *) stmt);
2121  break;
2122 
2123  default:
2124  /* point err_stmt to parent, since this one seems corrupt */
2125  estate->err_stmt = save_estmt;
2126  elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
2127  rc = -1; /* keep compiler quiet */
2128  }
2129 
2130  /* Let the plugin know that we have finished executing this statement */
2131  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
2132  ((*plpgsql_plugin_ptr)->stmt_end) (estate, stmt);
2133 
2134  if (rc != PLPGSQL_RC_OK)
2135  {
2136  estate->err_stmt = save_estmt;
2137  return rc;
2138  }
2139  } /* end of loop over statements */
2140 
2141  estate->err_stmt = save_estmt;
2142  return PLPGSQL_RC_OK;
2143 }
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
static int exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
Definition: pl_exec.c:2827
static int exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
Definition: pl_exec.c:4830
static int exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
Definition: pl_exec.c:1651
static int exec_stmt_commit(PLpgSQL_execstate *estate, PLpgSQL_stmt_commit *stmt)
Definition: pl_exec.c:4964
static int exec_stmt_forc(PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt)
Definition: pl_exec.c:2856
static int exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt)
Definition: pl_exec.c:2996
static int exec_stmt_rollback(PLpgSQL_execstate *estate, PLpgSQL_stmt_rollback *stmt)
Definition: pl_exec.c:4988
static int exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
Definition: pl_exec.c:3185
static int exec_stmt_exit(PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt)
Definition: pl_exec.c:3152
static int exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
Definition: pl_exec.c:3727
static int exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
Definition: pl_exec.c:2631
static int exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
Definition: pl_exec.c:4665
static int exec_stmt_dynexecute(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynexecute *stmt)
Definition: pl_exec.c:4448
static int exec_stmt_assert(PLpgSQL_execstate *estate, PLpgSQL_stmt_assert *stmt)
Definition: pl_exec.c:3938
static int exec_stmt_return_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_return_query *stmt)
Definition: pl_exec.c:3546
static int exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
Definition: pl_exec.c:2185
static int exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
Definition: pl_exec.c:2684
static int exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
Definition: pl_exec.c:2514
static int exec_stmt_case(PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
Definition: pl_exec.c:2544
static int exec_stmt_return_next(PLpgSQL_execstate *estate, PLpgSQL_stmt_return_next *stmt)
Definition: pl_exec.c:3328
static int exec_stmt_assign(PLpgSQL_execstate *estate, PLpgSQL_stmt_assign *stmt)
Definition: pl_exec.c:2152
static int exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
Definition: pl_exec.c:4638
static int exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
Definition: pl_exec.c:2398
static int exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
Definition: pl_exec.c:2653
static int exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
Definition: pl_exec.c:2168
static int exec_stmt_close(PLpgSQL_execstate *estate, PLpgSQL_stmt_close *stmt)
Definition: pl_exec.c:4921
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 1622 of file pl_exec.c.

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

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

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

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

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

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

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

1533 {
1534  if (estate->stmt_mcontext == NULL)
1535  {
1536  estate->stmt_mcontext =
1538  "PLpgSQL per-statement data",
1540  }
1541  return estate->stmt_mcontext;
1542 }
#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 7660 of file pl_exec.c.

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

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

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

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

7344 {
7345  int natts = tupdesc->natts;
7346  HeapTuple tuple;
7347  Datum *dvalues;
7348  bool *nulls;
7349  int i;
7350 
7351  if (natts != row->nfields)
7352  return NULL;
7353 
7354  dvalues = (Datum *) eval_mcontext_alloc0(estate, natts * sizeof(Datum));
7355  nulls = (bool *) eval_mcontext_alloc(estate, natts * sizeof(bool));
7356 
7357  for (i = 0; i < natts; i++)
7358  {
7359  Oid fieldtypeid;
7360  int32 fieldtypmod;
7361 
7362  if (TupleDescAttr(tupdesc, i)->attisdropped)
7363  {
7364  nulls[i] = true; /* leave the column as null */
7365  continue;
7366  }
7367 
7368  exec_eval_datum(estate, estate->datums[row->varnos[i]],
7369  &fieldtypeid, &fieldtypmod,
7370  &dvalues[i], &nulls[i]);
7371  if (fieldtypeid != TupleDescAttr(tupdesc, i)->atttypid)
7372  return NULL;
7373  /* XXX should we insist on typmod match, too? */
7374  }
7375 
7376  tuple = heap_form_tuple(tupdesc, dvalues, nulls);
7377 
7378  return tuple;
7379 }
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 8395 of file pl_exec.c.

8396 {
8397  SimpleEcontextStackEntry *entry;
8398 
8399  /*
8400  * Create an EState for evaluation of simple expressions, if there's not
8401  * one already in the current transaction. The EState is made a child of
8402  * TopTransactionContext so it will have the right lifespan.
8403  *
8404  * Note that this path is never taken when beginning a DO block; the
8405  * required EState was already made by plpgsql_inline_handler. However,
8406  * if the DO block executes COMMIT or ROLLBACK, then we'll come here and
8407  * make a shared EState to use for the rest of the DO block. That's OK;
8408  * see the comments for shared_simple_eval_estate. (Note also that a DO
8409  * block will continue to use its private cast hash table for the rest of
8410  * the block. That's okay for now, but it might cause problems someday.)
8411  */
8412  if (estate->simple_eval_estate == NULL)
8413  {
8414  MemoryContext oldcontext;
8415 
8416  if (shared_simple_eval_estate == NULL)
8417  {
8420  MemoryContextSwitchTo(oldcontext);
8421  }
8423  }
8424 
8425  /*
8426  * Likewise for the simple-expression resource owner.
8427  */
8428  if (estate->simple_eval_resowner == NULL)
8429  {
8430  if (shared_simple_eval_resowner == NULL)
8433  "PL/pgSQL simple expressions");
8435  }
8436 
8437  /*
8438  * Create a child econtext for the current function.
8439  */
8441 
8442  /*
8443  * Make a stack entry so we can clean up the econtext at subxact end.
8444  * Stack entries are kept in TopTransactionContext for simplicity.
8445  */
8446  entry = (SimpleEcontextStackEntry *)
8448  sizeof(SimpleEcontextStackEntry));
8449 
8450  entry->stack_econtext = estate->eval_econtext;
8452 
8453  entry->next = simple_econtext_stack;
8454  simple_econtext_stack = entry;
8455 }
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:106
static EState * shared_simple_eval_estate
Definition: pl_exec.c:95
static SimpleEcontextStackEntry * simple_econtext_stack
Definition: pl_exec.c:96
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:167
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition: resowner.c:413
struct SimpleEcontextStackEntry * next
Definition: pl_exec.c:92
ExprContext * stack_econtext
Definition: pl_exec.c:90
SubTransactionId xact_subxid
Definition: pl_exec.c:91
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 8464 of file pl_exec.c.

8465 {
8467 
8468  Assert(simple_econtext_stack != NULL);
8470 
8474 
8475  FreeExprContext(estate->eval_econtext, true);
8476  estate->eval_econtext = NULL;
8477 }
static int32 next
Definition: blutils.c:222
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 3981 of file pl_exec.c.

3986 {
3987  HASHCTL ctl;
3988 
3989  /* this link will be restored at exit from plpgsql_call_handler */
3990  func->cur_estate = estate;
3991 
3992  estate->func = func;
3993  estate->trigdata = NULL;
3994  estate->evtrigdata = NULL;
3995 
3996  estate->retval = (Datum) 0;
3997  estate->retisnull = true;
3998  estate->rettype = InvalidOid;
3999 
4000  estate->fn_rettype = func->fn_rettype;
4001  estate->retistuple = func->fn_retistuple;
4002  estate->retisset = func->fn_retset;
4003 
4004  estate->readonly_func = func->fn_readonly;
4005  estate->atomic = true;
4006 
4007  estate->exitlabel = NULL;
4008  estate->cur_error = NULL;
4009 
4010  estate->tuple_store = NULL;
4011  estate->tuple_store_desc = NULL;
4012  if (rsi)
4013  {
4016  }
4017  else
4018  {
4019  estate->tuple_store_cxt = NULL;
4020  estate->tuple_store_owner = NULL;
4021  }
4022  estate->rsi = rsi;
4023 
4024  estate->found_varno = func->found_varno;
4025  estate->ndatums = func->ndatums;
4026  estate->datums = NULL;
4027  /* the datums array will be filled by copy_plpgsql_datums() */
4029 
4030  /* initialize our ParamListInfo with appropriate hook functions */
4031  estate->paramLI = makeParamList(0);
4033  estate->paramLI->paramFetchArg = (void *) estate;
4035  estate->paramLI->paramCompileArg = NULL; /* not needed */
4037  estate->paramLI->parserSetupArg = NULL; /* filled during use */
4038  estate->paramLI->numParams = estate->ndatums;
4039 
4040  /* Create the session-wide cast-expression hash if we didn't already */
4041  if (cast_expr_hash == NULL)
4042  {
4043  ctl.keysize = sizeof(plpgsql_CastHashKey);
4044  ctl.entrysize = sizeof(plpgsql_CastExprHashEntry);
4045  cast_expr_hash = hash_create("PLpgSQL cast expressions",
4046  16, /* start small and extend */
4047  &ctl,
4048  HASH_ELEM | HASH_BLOBS);
4049  }
4050 
4051  /* set up for use of appropriate simple-expression EState and cast hash */
4052  if (simple_eval_estate)
4053  {
4054  estate->simple_eval_estate = simple_eval_estate;
4055  /* Private cast hash just lives in function's main context */
4056  ctl.keysize = sizeof(plpgsql_CastHashKey);
4057  ctl.entrysize = sizeof(plpgsql_CastHashEntry);
4058  ctl.hcxt = CurrentMemoryContext;
4059  estate->cast_hash = hash_create("PLpgSQL private cast cache",
4060  16, /* start small and extend */
4061  &ctl,
4063  }
4064  else
4065  {
4067  /* Create the session-wide cast-info hash table if we didn't already */
4068  if (shared_cast_hash == NULL)
4069  {
4070  ctl.keysize = sizeof(plpgsql_CastHashKey);
4071  ctl.entrysize = sizeof(plpgsql_CastHashEntry);
4072  shared_cast_hash = hash_create("PLpgSQL cast cache",
4073  16, /* start small and extend */
4074  &ctl,
4075  HASH_ELEM | HASH_BLOBS);
4076  }
4077  estate->cast_hash = shared_cast_hash;
4078  }
4079  /* likewise for the simple-expression resource owner */
4080  if (simple_eval_resowner)
4081  estate->simple_eval_resowner = simple_eval_resowner;
4082  else
4084 
4085  /* if there's a procedure resowner, it'll be filled in later */
4086  estate->procedure_resowner = NULL;
4087 
4088  /*
4089  * We start with no stmt_mcontext; one will be created only if needed.
4090  * That context will be a direct child of the function's main execution
4091  * context. Additional stmt_mcontexts might be created as children of it.
4092  */
4093  estate->stmt_mcontext = NULL;
4095 
4096  estate->eval_tuptable = NULL;
4097  estate->eval_processed = 0;
4098  estate->eval_econtext = NULL;
4099 
4100  estate->err_stmt = NULL;
4101  estate->err_var = NULL;
4102  estate->err_text = NULL;
4103 
4104  estate->plugin_info = NULL;
4105 
4106  /*
4107  * Create an EState and ExprContext for evaluation of simple expressions.
4108  */
4109  plpgsql_create_econtext(estate);
4110 
4111  /*
4112  * Let the plugin, if any, see this function before we initialize local
4113  * PL/pgSQL variables. Note that we also give the plugin a few function
4114  * pointers, so it can call back into PL/pgSQL for doing things like
4115  * variable assignments and stack traces.
4116  */
4117  if (*plpgsql_plugin_ptr)
4118  {
4119  (*plpgsql_plugin_ptr)->error_callback = plpgsql_exec_error_callback;
4120  (*plpgsql_plugin_ptr)->assign_expr = exec_assign_expr;
4121  (*plpgsql_plugin_ptr)->assign_value = exec_assign_value;
4122  (*plpgsql_plugin_ptr)->eval_datum = exec_eval_datum;
4123  (*plpgsql_plugin_ptr)->cast_value = exec_cast_value;
4124 
4125  if ((*plpgsql_plugin_ptr)->func_setup)
4126  ((*plpgsql_plugin_ptr)->func_setup) (estate, func);
4127  }
4128 }
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:6320
static HTAB * shared_cast_hash
Definition: pl_exec.c:183
static void plpgsql_exec_error_callback(void *arg)
Definition: pl_exec.c:1231
static void plpgsql_param_compile(ParamListInfo params, Param *param, ExprState *state, Datum *resv, bool *resnull)
Definition: pl_exec.c:6447
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 1231 of file pl_exec.c.

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

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

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

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

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

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

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

1374 {
1375  MemoryContext oldcontext;
1376 
1377  if (var->promise == PLPGSQL_PROMISE_NONE)
1378  return; /* nothing to do */
1379 
1380  /*
1381  * This will typically be invoked in a short-lived context such as the
1382  * mcontext. We must create variable values in the estate's datum
1383  * context. This quick-and-dirty solution risks leaking some additional
1384  * cruft there, but since any one promise is honored at most once per
1385  * function call, it's probably not worth being more careful.
1386  */
1387  oldcontext = MemoryContextSwitchTo(estate->datum_context);
1388 
1389  switch (var->promise)
1390  {
1392  if (estate->trigdata == NULL)
1393  elog(ERROR, "trigger promise is not in a trigger function");
1394  assign_simple_var(estate, var,
1397  false, true);
1398  break;
1399 
1401  if (estate->trigdata == NULL)
1402  elog(ERROR, "trigger promise is not in a trigger function");
1403  if (TRIGGER_FIRED_BEFORE(estate->trigdata->tg_event))
1404  assign_text_var(estate, var, "BEFORE");
1405  else if (TRIGGER_FIRED_AFTER(estate->trigdata->tg_event))
1406  assign_text_var(estate, var, "AFTER");
1407  else if (TRIGGER_FIRED_INSTEAD(estate->trigdata->tg_event))
1408  assign_text_var(estate, var, "INSTEAD OF");
1409  else
1410  elog(ERROR, "unrecognized trigger execution time: not BEFORE, AFTER, or INSTEAD OF");
1411  break;
1412 
1414  if (estate->trigdata == NULL)
1415  elog(ERROR, "trigger promise is not in a trigger function");
1416  if (TRIGGER_FIRED_FOR_ROW(estate->trigdata->tg_event))
1417  assign_text_var(estate, var, "ROW");
1418  else if (TRIGGER_FIRED_FOR_STATEMENT(estate->trigdata->tg_event))
1419  assign_text_var(estate, var, "STATEMENT");
1420  else
1421  elog(ERROR, "unrecognized trigger event type: not ROW or STATEMENT");
1422  break;
1423 
1424  case PLPGSQL_PROMISE_TG_OP:
1425  if (estate->trigdata == NULL)
1426  elog(ERROR, "trigger promise is not in a trigger function");
1428  assign_text_var(estate, var, "INSERT");
1429  else if (TRIGGER_FIRED_BY_UPDATE(estate->trigdata->tg_event))
1430  assign_text_var(estate, var, "UPDATE");
1431  else if (TRIGGER_FIRED_BY_DELETE(estate->trigdata->tg_event))
1432  assign_text_var(estate, var, "DELETE");
1433  else if (TRIGGER_FIRED_BY_TRUNCATE(estate->trigdata->tg_event))
1434  assign_text_var(estate, var, "TRUNCATE");
1435  else
1436  elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, UPDATE, or TRUNCATE");
1437  break;
1438 
1440  if (estate->trigdata == NULL)
1441  elog(ERROR, "trigger promise is not in a trigger function");
1442  assign_simple_var(estate, var,
1444  false, false);
1445  break;
1446 
1448  if (estate->trigdata == NULL)
1449  elog(ERROR, "trigger promise is not in a trigger function");
1450  assign_simple_var(estate, var,
1453  false, true);
1454  break;
1455 
1457  if (estate->trigdata == NULL)
1458  elog(ERROR, "trigger promise is not in a trigger function");
1459  assign_simple_var(estate, var,
1462  false, true);
1463  break;
1464 
1466  if (estate->trigdata == NULL)
1467  elog(ERROR, "trigger promise is not in a trigger function");
1468  assign_simple_var(estate, var,
1470  false, false);
1471  break;
1472 
1474  if (estate->trigdata == NULL)
1475  elog(ERROR, "trigger promise is not in a trigger function");
1476  if (estate->trigdata->tg_trigger->tgnargs > 0)
1477  {
1478  /*
1479  * For historical reasons, tg_argv[] subscripts start at zero
1480  * not one. So we can't use construct_array().
1481  */
1482  int nelems = estate->trigdata->tg_trigger->tgnargs;
1483  Datum *elems;
1484  int dims[1];
1485  int lbs[1];
1486  int i;
1487 
1488  elems = palloc(sizeof(Datum) * nelems);
1489  for (i = 0; i < nelems; i++)
1490  elems[i] = CStringGetTextDatum(estate->trigdata->tg_trigger->tgargs[i]);
1491  dims[0] = nelems;
1492  lbs[0] = 0;
1493 
1494  assign_simple_var(estate, var,
1495  PointerGetDatum(construct_md_array(elems, NULL,
1496  1, dims, lbs,
1497  TEXTOID,
1498  -1, false, TYPALIGN_INT)),
1499  false, true);
1500  }
1501  else
1502  {
1503  assign_simple_var(estate, var, (Datum) 0, true, false);
1504  }
1505  break;
1506 
1508  if (estate->evtrigdata == NULL)
1509  elog(ERROR, "event trigger promise is not in an event trigger function");
1510  assign_text_var(estate, var, estate->evtrigdata->event);
1511  break;
1512 
1514  if (estate->evtrigdata == NULL)
1515  elog(ERROR, "event trigger promise is not in an event trigger function");
1516  assign_text_var(estate, var, GetCommandTagName(estate->evtrigdata->tag));
1517  break;
1518 
1519  default:
1520  elog(ERROR, "unrecognized promise type: %d", var->promise);
1521  }
1522 
1523  MemoryContextSwitchTo(oldcontext);
1524 }
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 6447 of file pl_exec.c.

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

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

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

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

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

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

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

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

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

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

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

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

8487 {
8488  /*
8489  * If we are doing a clean transaction shutdown, free the EState and tell
8490  * the resowner to release whatever plancache references it has, so that
8491  * all remaining resources will be released correctly. (We don't need to
8492  * actually delete the resowner here; deletion of the
8493  * TopTransactionResourceOwner will take care of that.)
8494  *
8495  * In an abort, we expect the regular abort recovery procedures to release
8496  * everything of interest, so just clear our pointers.
8497  */
8498  if (event == XACT_EVENT_COMMIT ||
8499  event == XACT_EVENT_PARALLEL_COMMIT ||
8500  event == XACT_EVENT_PREPARE)
8501  {
8502  simple_econtext_stack = NULL;
8503 
8510  }
8511  else if (event == XACT_EVENT_ABORT ||
8512  event == XACT_EVENT_PARALLEL_ABORT)
8513  {
8514  simple_econtext_stack = NULL;
8517  }
8518 }
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 1570 of file pl_exec.c.

1571 {
1572  /* We need only pop the stack */
1573  estate->stmt_mcontext = estate->stmt_mcontext_parent;
1575 }
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 1551 of file pl_exec.c.

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

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

6889 {
6890  PLpgSQL_type *typ = rec->datatype;
6891  TypeCacheEntry *typentry;
6892 
6893  if (rec->rectypeid == RECORDOID)
6894  return; /* it's RECORD, so nothing to do */
6895  Assert(typ != NULL);
6896  if (typ->tcache &&
6897  typ->tcache->tupDesc_identifier == typ->tupdesc_id)
6898  {
6899  /*
6900  * Although *typ is known up-to-date, it's possible that rectypeid
6901  * isn't, because *rec is cloned during each function startup from a
6902  * copy that we don't have a good way to update. Hence, forcibly fix
6903  * rectypeid before returning.
6904  */
6905  rec->rectypeid = typ->typoid;
6906  return;
6907  }
6908 
6909  /*
6910  * typcache entry has suffered invalidation, so re-look-up the type name
6911  * if possible, and then recheck the type OID. If we don't have a
6912  * TypeName, then we just have to soldier on with the OID we've got.
6913  */
6914  if (typ->origtypname != NULL)
6915  {
6916  /* this bit should match parse_datatype() in pl_gram.y */
6917  typenameTypeIdAndMod(NULL, typ->origtypname,
6918  &typ->typoid,
6919  &typ->atttypmod);
6920  }
6921 
6922  /* this bit should match build_datatype() in pl_comp.c */
6923  typentry = lookup_type_cache(typ->typoid,
6926  if (typentry->typtype == TYPTYPE_DOMAIN)
6927  typentry = lookup_type_cache(typentry->domainBaseType,
6929  if (typentry->tupDesc == NULL)
6930  {
6931  /*
6932  * If we get here, user tried to replace a composite type with a
6933  * non-composite one. We're not gonna support that.
6934  */
6935  ereport(ERROR,
6936  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6937  errmsg("type %s is not composite",
6938  format_type_be(typ->typoid))));
6939  }
6940 
6941  /*
6942  * Update tcache and tupdesc_id. Since we don't support changing to a
6943  * non-composite type, none of the rest of *typ needs to change.
6944  */
6945  typ->tcache = typentry;
6946  typ->tupdesc_id = typentry->tupDesc_identifier;
6947 
6948  /*
6949  * Update *rec, too. (We'll deal with subsidiary RECFIELDs as needed.)
6950  */
6951  rec->rectypeid = typ->typoid;
6952 }
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:356
#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 6265 of file pl_exec.c.

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

Referenced by plpgsql_estate_setup().

◆ shared_simple_eval_estate

EState* shared_simple_eval_estate = NULL
static

Definition at line 95 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 106 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