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

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

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

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

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:1196
size_t Size
Definition: c.h:605
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:7394
HeapTupleHeader SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc)
Definition: spi.c:1071
Datum SPI_datumTransfer(Datum value, bool typByVal, int typLen)
Definition: spi.c:1358
void * SPI_palloc(Size size)
Definition: spi.c:1335
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 7295 of file pl_exec.c.

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

7694 {
7695  char *result;
7696  MemoryContext oldcontext;
7697  Oid typoutput;
7698  bool typIsVarlena;
7699 
7700  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7701  getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
7702  result = OidOutputFunctionCall(typoutput, value);
7703  MemoryContextSwitchTo(oldcontext);
7704 
7705  return result;
7706 }
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1763
static struct @155 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:811
#define elog(elevel,...)
Definition: elog.h:224
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 7394 of file pl_exec.c.

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

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

7750 {
7751  plpgsql_CastHashEntry *cast_entry;
7752 
7753  cast_entry = get_cast_hashentry(estate,
7754  valtype, valtypmod,
7755  reqtype, reqtypmod);
7756  if (cast_entry)
7757  {
7758  ExprContext *econtext = estate->eval_econtext;
7759  MemoryContext oldcontext;
7760 
7761  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7762 
7763  econtext->caseValue_datum = value;
7764  econtext->caseValue_isNull = *isnull;
7765 
7766  cast_entry->cast_in_use = true;
7767 
7768  value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
7769  isnull);
7770 
7771  cast_entry->cast_in_use = false;
7772 
7773  MemoryContextSwitchTo(oldcontext);
7774  }
7775 
7776  return value;
7777 }
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:333
static plpgsql_CastHashEntry * get_cast_hashentry(PLpgSQL_execstate *estate, Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod)
Definition: pl_exec.c:7790
bool caseValue_isNull
Definition: execnodes.h:282
Datum caseValue_datum
Definition: execnodes.h:280
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:438
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 5053 of file pl_exec.c.

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

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

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

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

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

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

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

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

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

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

4138 {
4139  /* Clear result of a full SPI_execute */
4140  if (estate->eval_tuptable != NULL)
4142  estate->eval_tuptable = NULL;
4143 
4144  /*
4145  * Clear result of exec_eval_simple_expr (but keep the econtext). This
4146  * also clears any short-lived allocations done via get_eval_mcontext.
4147  */
4148  if (estate->eval_econtext != NULL)
4150 }
#define ResetExprContext(econtext)
Definition: executor.h:544
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1383
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 5308 of file pl_exec.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4176 {
4177  SPIPlanPtr plan;
4179 
4180  /*
4181  * The grammar can't conveniently set expr->func while building the parse
4182  * tree, so make sure it's set before parser hooks need it.
4183  */
4184  expr->func = estate->func;
4185 
4186  /*
4187  * Generate and save the plan
4188  */
4189  memset(&options, 0, sizeof(options));
4191  options.parserSetupArg = (void *) expr;
4192  options.parseMode = expr->parseMode;
4193  options.cursorOptions = cursorOptions;
4195  if (plan == NULL)
4196  elog(ERROR, "SPI_prepare_extended failed for \"%s\": %s",
4198 
4199  SPI_keepplan(plan);
4200  expr->plan = plan;
4201 
4202  /* Check to see if it's a simple expression */
4203  exec_simple_check_plan(estate, expr);
4204 }
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:7981
SPIPlanPtr SPI_prepare_extended(const char *src, const SPIPrepareOptions *options)
Definition: spi.c:899
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:973
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 5769 of file pl_exec.c.

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

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

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

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

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

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

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:1934
void FlushErrorState(void)
Definition: elog.c:1850
char * unpack_sql_state(int sql_state)
Definition: elog.c:3149
ErrorData * CopyErrorData(void)
Definition: elog.c:1729
#define PG_TRY(...)
Definition: elog.h:370
#define PG_END_TRY(...)
Definition: elog.h:395
#define PG_CATCH(...)
Definition: elog.h:380
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:8393
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:8620
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:439
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:4681
void RollbackAndReleaseCurrentSubTransaction(void)
Definition: xact.c:4783
void ReleaseCurrentSubTransaction(void)
Definition: xact.c:4755

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:708
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 2543 of file pl_exec.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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:2826
static int exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
Definition: pl_exec.c:4828
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:4962
static int exec_stmt_forc(PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt)
Definition: pl_exec.c:2855
static int exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt)
Definition: pl_exec.c:2995
static int exec_stmt_rollback(PLpgSQL_execstate *estate, PLpgSQL_stmt_rollback *stmt)
Definition: pl_exec.c:4986
static int exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
Definition: pl_exec.c:3184
static int exec_stmt_exit(PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt)
Definition: pl_exec.c:3151
static int exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
Definition: pl_exec.c:3726
static int exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
Definition: pl_exec.c:2630
static int exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
Definition: pl_exec.c:4663
static int exec_stmt_dynexecute(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynexecute *stmt)
Definition: pl_exec.c:4446
static int exec_stmt_assert(PLpgSQL_execstate *estate, PLpgSQL_stmt_assert *stmt)
Definition: pl_exec.c:3937
static int exec_stmt_return_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_return_query *stmt)
Definition: pl_exec.c:3545
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:2683
static int exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
Definition: pl_exec.c:2513
static int exec_stmt_case(PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
Definition: pl_exec.c:2543
static int exec_stmt_return_next(PLpgSQL_execstate *estate, PLpgSQL_stmt_return_next *stmt)
Definition: pl_exec.c:3327
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:4636
static int exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
Definition: pl_exec.c:2397
static int exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
Definition: pl_exec.c:2652
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:4919
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 8795 of file pl_exec.c.

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

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

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

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

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

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  List *plansources;
2280  CachedPlanSource *plansource;
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
2298  */
2299  plansources = SPI_plan_get_plan_sources(expr->plan);
2300  if (list_length(plansources) != 1)
2301  elog(ERROR, "query for CALL statement is not a CallStmt");
2302  plansource = (CachedPlanSource *) linitial(plansources);
2303  if (list_length(plansource->query_list) != 1)
2304  elog(ERROR, "query for CALL statement is not a CallStmt");
2306  plansource->query_list)->utilityStmt;
2307  if (stmt == NULL || !IsA(stmt, CallStmt))
2308  elog(ERROR, "query for CALL statement is not a CallStmt");
2309 
2310  funcexpr = stmt->funcexpr;
2311 
2312  func_tuple = SearchSysCache1(PROCOID,
2313  ObjectIdGetDatum(funcexpr->funcid));
2314  if (!HeapTupleIsValid(func_tuple))
2315  elog(ERROR, "cache lookup failed for function %u",
2316  funcexpr->funcid);
2317 
2318  /*
2319  * Get the argument names and modes, so that we can deliver on-point error
2320  * messages when something is wrong.
2321  */
2322  numargs = get_func_arg_info(func_tuple, &argtypes, &argnames, &argmodes);
2323 
2324  ReleaseSysCache(func_tuple);
2325 
2326  /*
2327  * Begin constructing row Datum; keep it in fn_cxt so it's adequately
2328  * long-lived.
2329  */
2330  MemoryContextSwitchTo(estate->func->fn_cxt);
2331 
2332  row = (PLpgSQL_row *) palloc0(sizeof(PLpgSQL_row));
2333  row->dtype = PLPGSQL_DTYPE_ROW;
2334  row->refname = "(unnamed row)";
2335  row->lineno = -1;
2336  row->varnos = (int *) palloc(numargs * sizeof(int));
2337 
2339 
2340  /*
2341  * Examine procedure's argument list. Each output arg position should be
2342  * an unadorned plpgsql variable (Datum), which we can insert into the row
2343  * Datum.
2344  */
2345  nfields = 0;
2346  for (i = 0; i < numargs; i++)
2347  {
2348  if (argmodes &&
2349  (argmodes[i] == PROARGMODE_INOUT ||
2350  argmodes[i] == PROARGMODE_OUT))
2351  {
2352  Node *n = list_nth(stmt->outargs, nfields);
2353 
2354  if (IsA(n, Param))
2355  {
2356  Param *param = (Param *) n;
2357  int dno;
2358 
2359  /* paramid is offset by 1 (see make_datum_param()) */
2360  dno = param->paramid - 1;
2361  /* must check assignability now, because grammar can't */
2362  exec_check_assignable(estate, dno);
2363  row->varnos[nfields++] = dno;
2364  }
2365  else
2366  {
2367  /* report error using parameter name, if available */
2368  if (argnames && argnames[i] && argnames[i][0])
2369  ereport(ERROR,
2370  (errcode(ERRCODE_SYNTAX_ERROR),
2371  errmsg("procedure parameter \"%s\" is an output parameter but corresponding argument is not writable",
2372  argnames[i])));
2373  else
2374  ereport(ERROR,
2375  (errcode(ERRCODE_SYNTAX_ERROR),
2376  errmsg("procedure parameter %d is an output parameter but corresponding argument is not writable",
2377  i + 1)));
2378  }
2379  }
2380  }
2381 
2382  Assert(nfields == list_length(stmt->outargs));
2383 
2384  row->nfields = nfields;
2385 
2386  MemoryContextSwitchTo(oldcontext);
2387 
2388  return (PLpgSQL_variable *) row;
2389 }
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
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218

References Assert, 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, IsA, PLpgSQL_row::lineno, linitial, linitial_node, list_length(), list_nth(), MemoryContextSwitchTo(), PLpgSQL_row::nfields, ObjectIdGetDatum(), palloc(), palloc0(), Param::paramid, PLpgSQL_expr::plan, PLPGSQL_DTYPE_ROW, CachedPlanSource::query_list, PLpgSQL_row::refname, ReleaseSysCache(), SearchSysCache1(), SPI_plan_get_plan_sources(), stmt, 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 6966 of file pl_exec.c.

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

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

8394 {
8395  SimpleEcontextStackEntry *entry;
8396 
8397  /*
8398  * Create an EState for evaluation of simple expressions, if there's not
8399  * one already in the current transaction. The EState is made a child of
8400  * TopTransactionContext so it will have the right lifespan.
8401  *
8402  * Note that this path is never taken when beginning a DO block; the
8403  * required EState was already made by plpgsql_inline_handler. However,
8404  * if the DO block executes COMMIT or ROLLBACK, then we'll come here and
8405  * make a shared EState to use for the rest of the DO block. That's OK;
8406  * see the comments for shared_simple_eval_estate. (Note also that a DO
8407  * block will continue to use its private cast hash table for the rest of
8408  * the block. That's okay for now, but it might cause problems someday.)
8409  */
8410  if (estate->simple_eval_estate == NULL)
8411  {
8412  MemoryContext oldcontext;
8413 
8414  if (shared_simple_eval_estate == NULL)
8415  {
8418  MemoryContextSwitchTo(oldcontext);
8419  }
8421  }
8422 
8423  /*
8424  * Likewise for the simple-expression resource owner.
8425  */
8426  if (estate->simple_eval_resowner == NULL)
8427  {
8428  if (shared_simple_eval_resowner == NULL)
8431  "PL/pgSQL simple expressions");
8433  }
8434 
8435  /*
8436  * Create a child econtext for the current function.
8437  */
8439 
8440  /*
8441  * Make a stack entry so we can clean up the econtext at subxact end.
8442  * Stack entries are kept in TopTransactionContext for simplicity.
8443  */
8444  entry = (SimpleEcontextStackEntry *)
8446  sizeof(SimpleEcontextStackEntry));
8447 
8448  entry->stack_econtext = estate->eval_econtext;
8450 
8451  entry->next = simple_econtext_stack;
8452  simple_econtext_stack = entry;
8453 }
EState * CreateExecutorState(void)
Definition: execUtils.c:88
ExprContext * CreateExprContext(EState *estate)
Definition: execUtils.c:304
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:789

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

8463 {
8465 
8466  Assert(simple_econtext_stack != NULL);
8468 
8472 
8473  FreeExprContext(estate->eval_econtext, true);
8474  estate->eval_econtext = NULL;
8475 }
static int32 next
Definition: blutils.c:221
void FreeExprContext(ExprContext *econtext, bool isCommit)
Definition: execUtils.c:414

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

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

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:3980
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:8462
static void copy_plpgsql_datums(PLpgSQL_execstate *estate, PLpgSQL_function *func)
Definition: pl_exec.c:1298
struct ErrorContextCallback * previous
Definition: elog.h:295
void(* callback)(void *arg)
Definition: elog.h:296
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:336
TupleDesc setDesc
Definition: execnodes.h:340
Tuplestorestate * setResult
Definition: execnodes.h:339
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 5459 of file pl_exec.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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