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/spi_priv.h"
#include "executor/tstoreReceiver.h"
#include "funcapi.h"
#include "mb/stringinfo_mb.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/parse_coerce.h"
#include "parser/parse_type.h"
#include "parser/scansup.h"
#include "plpgsql.h"
#include "storage/proc.h"
#include "tcop/cmdtag.h"
#include "tcop/tcopprot.h"
#include "tcop/utility.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
Include dependency graph for pl_exec.c:

Go to the source code of this file.

Data Structures

struct  SimpleEcontextStackEntry
 
struct  plpgsql_CastHashKey
 
struct  plpgsql_CastHashEntry
 

Macros

#define get_eval_mcontext(estate)   ((estate)->eval_econtext->ecxt_per_tuple_memory)
 
#define eval_mcontext_alloc(estate, sz)   MemoryContextAlloc(get_eval_mcontext(estate), sz)
 
#define eval_mcontext_alloc0(estate, sz)   MemoryContextAllocZero(get_eval_mcontext(estate), sz)
 
#define LOOP_RC_PROCESSING(looplabel, exit_action)
 
#define SET_RAISE_OPTION_TEXT(opt, name)
 

Typedefs

typedef struct SimpleEcontextStackEntry SimpleEcontextStackEntry
 

Functions

static void coerce_function_result_tuple (PLpgSQL_execstate *estate, TupleDesc tupdesc)
 
static void plpgsql_exec_error_callback (void *arg)
 
static void copy_plpgsql_datums (PLpgSQL_execstate *estate, PLpgSQL_function *func)
 
static void plpgsql_fulfill_promise (PLpgSQL_execstate *estate, PLpgSQL_var *var)
 
static MemoryContext get_stmt_mcontext (PLpgSQL_execstate *estate)
 
static void push_stmt_mcontext (PLpgSQL_execstate *estate)
 
static void pop_stmt_mcontext (PLpgSQL_execstate *estate)
 
static int exec_toplevel_block (PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
 
static int exec_stmt_block (PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
 
static int exec_stmts (PLpgSQL_execstate *estate, List *stmts)
 
static int exec_stmt_assign (PLpgSQL_execstate *estate, PLpgSQL_stmt_assign *stmt)
 
static int exec_stmt_perform (PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
 
static int exec_stmt_call (PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
 
static int exec_stmt_getdiag (PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
 
static int exec_stmt_if (PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
 
static int exec_stmt_case (PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
 
static int exec_stmt_loop (PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
 
static int exec_stmt_while (PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
 
static int exec_stmt_fori (PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
 
static int exec_stmt_fors (PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
 
static int exec_stmt_forc (PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt)
 
static int exec_stmt_foreach_a (PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt)
 
static int exec_stmt_open (PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
 
static int exec_stmt_fetch (PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
 
static int exec_stmt_close (PLpgSQL_execstate *estate, PLpgSQL_stmt_close *stmt)
 
static int exec_stmt_exit (PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt)
 
static int exec_stmt_return (PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
 
static int exec_stmt_return_next (PLpgSQL_execstate *estate, PLpgSQL_stmt_return_next *stmt)
 
static int exec_stmt_return_query (PLpgSQL_execstate *estate, PLpgSQL_stmt_return_query *stmt)
 
static int exec_stmt_raise (PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 
static int exec_stmt_assert (PLpgSQL_execstate *estate, PLpgSQL_stmt_assert *stmt)
 
static int exec_stmt_execsql (PLpgSQL_execstate *estate, PLpgSQL_stmt_execsql *stmt)
 
static int exec_stmt_dynexecute (PLpgSQL_execstate *estate, PLpgSQL_stmt_dynexecute *stmt)
 
static int exec_stmt_dynfors (PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
 
static int exec_stmt_commit (PLpgSQL_execstate *estate, PLpgSQL_stmt_commit *stmt)
 
static int exec_stmt_rollback (PLpgSQL_execstate *estate, PLpgSQL_stmt_rollback *stmt)
 
static int exec_stmt_set (PLpgSQL_execstate *estate, PLpgSQL_stmt_set *stmt)
 
static void plpgsql_estate_setup (PLpgSQL_execstate *estate, PLpgSQL_function *func, ReturnSetInfo *rsi, EState *simple_eval_estate, ResourceOwner simple_eval_resowner)
 
static void exec_eval_cleanup (PLpgSQL_execstate *estate)
 
static void exec_prepare_plan (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions, bool keepplan)
 
static void exec_simple_check_plan (PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
 
static void exec_save_simple_expr (PLpgSQL_expr *expr, CachedPlan *cplan)
 
static void exec_check_rw_parameter (PLpgSQL_expr *expr, int target_dno)
 
static bool contains_target_param (Node *node, int *target_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 *workspace)
 
static void plpgsql_param_compile (ParamListInfo params, Param *param, ExprState *state, Datum *resv, bool *resnull)
 
static void plpgsql_param_eval_var (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void plpgsql_param_eval_var_ro (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void plpgsql_param_eval_recfield (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void plpgsql_param_eval_generic (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void plpgsql_param_eval_generic_ro (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void exec_move_row (PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
 
static void revalidate_rectypeid (PLpgSQL_rec *rec)
 
static ExpandedRecordHeadermake_expanded_record_for_rec (PLpgSQL_execstate *estate, PLpgSQL_rec *rec, TupleDesc srctupdesc, ExpandedRecordHeader *srcerh)
 
static void exec_move_row_from_fields (PLpgSQL_execstate *estate, PLpgSQL_variable *target, ExpandedRecordHeader *newerh, Datum *values, bool *nulls, TupleDesc tupdesc)
 
static bool compatible_tupdescs (TupleDesc src_tupdesc, TupleDesc dst_tupdesc)
 
static HeapTuple make_tuple_from_row (PLpgSQL_execstate *estate, PLpgSQL_row *row, TupleDesc tupdesc)
 
static TupleDesc deconstruct_composite_datum (Datum value, HeapTupleData *tmptup)
 
static void exec_move_row_from_datum (PLpgSQL_execstate *estate, PLpgSQL_variable *target, Datum value)
 
static void instantiate_empty_record_variable (PLpgSQL_execstate *estate, PLpgSQL_rec *rec)
 
static char * convert_value_to_string (PLpgSQL_execstate *estate, Datum value, Oid valtype)
 
static Datum exec_cast_value (PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
 
static Datum do_cast_value (PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
 
static plpgsql_CastHashEntryget_cast_hashentry (PLpgSQL_execstate *estate, Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod)
 
static void exec_init_tuple_store (PLpgSQL_execstate *estate)
 
static void exec_set_found (PLpgSQL_execstate *estate, bool state)
 
static void plpgsql_create_econtext (PLpgSQL_execstate *estate)
 
static void plpgsql_destroy_econtext (PLpgSQL_execstate *estate)
 
static void assign_simple_var (PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
 
static void assign_text_var (PLpgSQL_execstate *estate, PLpgSQL_var *var, const char *str)
 
static void assign_record_var (PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
 
static ParamListInfo exec_eval_using_params (PLpgSQL_execstate *estate, List *params)
 
static Portal exec_dynquery_with_params (PLpgSQL_execstate *estate, PLpgSQL_expr *dynquery, List *params, const char *portalname, int cursorOptions)
 
static char * format_expr_params (PLpgSQL_execstate *estate, const PLpgSQL_expr *expr)
 
static char * format_preparedparamsdata (PLpgSQL_execstate *estate, ParamListInfo paramLI)
 
Datum plpgsql_exec_function (PLpgSQL_function *func, FunctionCallInfo fcinfo, EState *simple_eval_estate, ResourceOwner simple_eval_resowner, bool atomic)
 
HeapTuple plpgsql_exec_trigger (PLpgSQL_function *func, TriggerData *trigdata)
 
void plpgsql_exec_event_trigger (PLpgSQL_function *func, EventTriggerData *trigdata)
 
static bool exception_matches_conditions (ErrorData *edata, PLpgSQL_condition *cond)
 
Oid plpgsql_exec_get_datum_type (PLpgSQL_execstate *estate, PLpgSQL_datum *datum)
 
void plpgsql_exec_get_datum_type_info (PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeId, int32 *typMod, Oid *collation)
 
void plpgsql_xact_cb (XactEvent event, void *arg)
 
void plpgsql_subxact_cb (SubXactEvent event, SubTransactionId mySubid, SubTransactionId parentSubid, void *arg)
 

Variables

static EStateshared_simple_eval_estate = NULL
 
static SimpleEcontextStackEntrysimple_econtext_stack = NULL
 
static ResourceOwner shared_simple_eval_resowner = NULL
 
static MemoryContext shared_cast_context = NULL
 
static HTABshared_cast_hash = NULL
 

Macro Definition Documentation

◆ eval_mcontext_alloc

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

◆ eval_mcontext_alloc0

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

Definition at line 135 of file pl_exec.c.

Referenced by exec_stmt_return_next(), and make_tuple_from_row().

◆ get_eval_mcontext

◆ LOOP_RC_PROCESSING

#define LOOP_RC_PROCESSING (   looplabel,
  exit_action 
)

◆ SET_RAISE_OPTION_TEXT

#define SET_RAISE_OPTION_TEXT (   opt,
  name 
)
Value:
do { \
if (opt) \
ereport(ERROR, \
(errcode(ERRCODE_SYNTAX_ERROR), \
errmsg("RAISE option already specified: %s", \
name))); \
opt = MemoryContextStrdup(stmt_mcontext, extval); \
} while (0)
int errcode(int sqlerrcode)
Definition: elog.c:610
#define ERROR
Definition: elog.h:43
const char * name
Definition: encode.c:561
int errmsg(const char *fmt,...)
Definition: elog.c:824
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1173

Definition at line 3679 of file pl_exec.c.

Referenced by exec_stmt_raise().

Typedef Documentation

◆ SimpleEcontextStackEntry

Function Documentation

◆ assign_record_var()

static void assign_record_var ( PLpgSQL_execstate estate,
PLpgSQL_rec rec,
ExpandedRecordHeader erh 
)
static

Definition at line 8618 of file pl_exec.c.

References Assert, PLpgSQL_execstate::datum_context, DeleteExpandedObject(), PLpgSQL_rec::dtype, PLpgSQL_rec::erh, ExpandedRecordGetDatum, PLPGSQL_DTYPE_REC, and TransferExpandedRecord.

Referenced by exec_move_row(), exec_move_row_from_datum(), and exec_move_row_from_fields().

8620 {
8621  Assert(rec->dtype == PLPGSQL_DTYPE_REC);
8622 
8623  /* Transfer new record object into datum_context */
8624  TransferExpandedRecord(erh, estate->datum_context);
8625 
8626  /* Free the old value ... */
8627  if (rec->erh)
8629 
8630  /* ... and install the new */
8631  rec->erh = erh;
8632 }
PLpgSQL_datum_type dtype
Definition: plpgsql.h:381
ExpandedRecordHeader * erh
Definition: plpgsql.h:404
void DeleteExpandedObject(Datum d)
#define Assert(condition)
Definition: c.h:745
#define TransferExpandedRecord(erh, cxt)
MemoryContext datum_context
Definition: plpgsql.h:1084
#define ExpandedRecordGetDatum(erh)

◆ assign_simple_var()

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

Definition at line 8542 of file pl_exec.c.

References Assert, PLpgSQL_execstate::atomic, PLpgSQL_var::datatype, datumCopy(), DatumGetPointer, DatumIsReadWriteExpandedObject, DeleteExpandedObject(), detoast_external_attr(), PLpgSQL_var::dtype, PLpgSQL_var::freeval, get_eval_mcontext, PLpgSQL_var::isnull, MemoryContextSwitchTo(), pfree(), PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_VAR, PLPGSQL_PROMISE_NONE, PointerGetDatum, PLpgSQL_var::promise, PLpgSQL_type::typlen, PLpgSQL_var::value, and VARATT_IS_EXTERNAL_NON_EXPANDED.

Referenced by assign_text_var(), exec_assign_value(), exec_set_found(), exec_stmt_block(), exec_stmt_case(), exec_stmt_forc(), exec_stmt_fori(), plpgsql_exec_function(), and plpgsql_fulfill_promise().

8544 {
8545  Assert(var->dtype == PLPGSQL_DTYPE_VAR ||
8546  var->dtype == PLPGSQL_DTYPE_PROMISE);
8547 
8548  /*
8549  * In non-atomic contexts, we do not want to store TOAST pointers in
8550  * variables, because such pointers might become stale after a commit.
8551  * Forcibly detoast in such cases. We don't want to detoast (flatten)
8552  * expanded objects, however; those should be OK across a transaction
8553  * boundary since they're just memory-resident objects. (Elsewhere in
8554  * this module, operations on expanded records likewise need to request
8555  * detoasting of record fields when !estate->atomic. Expanded arrays are
8556  * not a problem since all array entries are always detoasted.)
8557  */
8558  if (!estate->atomic && !isnull && var->datatype->typlen == -1 &&
8560  {
8561  MemoryContext oldcxt;
8562  Datum detoasted;
8563 
8564  /*
8565  * Do the detoasting in the eval_mcontext to avoid long-term leakage
8566  * of whatever memory toast fetching might leak. Then we have to copy
8567  * the detoasted datum to the function's main context, which is a
8568  * pain, but there's little choice.
8569  */
8570  oldcxt = MemoryContextSwitchTo(get_eval_mcontext(estate));
8571  detoasted = PointerGetDatum(detoast_external_attr((struct varlena *) DatumGetPointer(newvalue)));
8572  MemoryContextSwitchTo(oldcxt);
8573  /* Now's a good time to not leak the input value if it's freeable */
8574  if (freeable)
8575  pfree(DatumGetPointer(newvalue));
8576  /* Once we copy the value, it's definitely freeable */
8577  newvalue = datumCopy(detoasted, false, -1);
8578  freeable = true;
8579  /* Can't clean up eval_mcontext here, but it'll happen before long */
8580  }
8581 
8582  /* Free the old value if needed */
8583  if (var->freeval)
8584  {
8586  var->isnull,
8587  var->datatype->typlen))
8589  else
8590  pfree(DatumGetPointer(var->value));
8591  }
8592  /* Assign new value to datum */
8593  var->value = newvalue;
8594  var->isnull = isnull;
8595  var->freeval = freeable;
8596 
8597  /*
8598  * If it's a promise variable, then either we just assigned the promised
8599  * value, or the user explicitly assigned an overriding value. Either
8600  * way, cancel the promise.
8601  */
8603 }
PLpgSQL_promise_type promise
Definition: plpgsql.h:332
#define VARATT_IS_EXTERNAL_NON_EXPANDED(PTR)
Definition: postgres.h:324
PLpgSQL_datum_type dtype
Definition: plpgsql.h:301
#define PointerGetDatum(X)
Definition: postgres.h:556
struct varlena * detoast_external_attr(struct varlena *attr)
Definition: detoast.c:44
PLpgSQL_type * datatype
Definition: plpgsql.h:310
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void pfree(void *pointer)
Definition: mcxt.c:1056
bool freeval
Definition: plpgsql.h:325
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
#define get_eval_mcontext(estate)
Definition: pl_exec.c:131
uintptr_t Datum
Definition: postgres.h:367
Datum value
Definition: plpgsql.h:323
void DeleteExpandedObject(Datum d)
#define Assert(condition)
Definition: c.h:745
#define DatumIsReadWriteExpandedObject(d, isnull, typlen)
#define DatumGetPointer(X)
Definition: postgres.h:549
Definition: c.h:562
int16 typlen
Definition: plpgsql.h:204
bool isnull
Definition: plpgsql.h:324

◆ assign_text_var()

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

Definition at line 8609 of file pl_exec.c.

References assign_simple_var(), and CStringGetTextDatum.

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

8610 {
8611  assign_simple_var(estate, var, CStringGetTextDatum(str), false, true);
8612 }
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8542
#define CStringGetTextDatum(s)
Definition: builtins.h:86

◆ coerce_function_result_tuple()

static void coerce_function_result_tuple ( PLpgSQL_execstate estate,
TupleDesc  tupdesc 
)
static

Definition at line 790 of file pl_exec.c.

References Assert, convert_tuples_by_position(), DatumGetEOHP(), DatumGetPointer, deconstruct_composite_datum(), EOH_flatten_into(), EOH_get_flat_size(), ExpandedRecordHeader::er_decltypeid, ER_MAGIC, ExpandedRecordHeader::er_magic, execute_attr_map_tuple(), expanded_record_get_tupdesc(), expanded_record_get_tuple(), ExpandedRecordIsDomain, gettext_noop, ExpandedRecordHeader::hdr, HeapTupleHeaderSetTypeId, HeapTupleHeaderSetTypMod, PointerGetDatum, ReleaseTupleDesc, PLpgSQL_execstate::rettype, PLpgSQL_execstate::retval, SPI_datumTransfer(), SPI_palloc(), SPI_returntuple(), TupleDescData::tdtypeid, TupleDescData::tdtypmod, type_is_rowtype(), and VARATT_IS_EXTERNAL_EXPANDED.

Referenced by plpgsql_exec_function().

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

◆ compatible_tupdescs()

static bool compatible_tupdescs ( TupleDesc  src_tupdesc,
TupleDesc  dst_tupdesc 
)
static

Definition at line 7406 of file pl_exec.c.

References i, TupleDescData::natts, and TupleDescAttr.

Referenced by exec_for_query(), and exec_move_row().

7407 {
7408  int i;
7409 
7410  /* Possibly we could allow src_tupdesc to have extra columns? */
7411  if (dst_tupdesc->natts != src_tupdesc->natts)
7412  return false;
7413 
7414  for (i = 0; i < dst_tupdesc->natts; i++)
7415  {
7416  Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
7417  Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
7418 
7419  if (dattr->attisdropped != sattr->attisdropped)
7420  return false;
7421  if (!dattr->attisdropped)
7422  {
7423  /* Normal columns must match by type and typmod */
7424  if (dattr->atttypid != sattr->atttypid ||
7425  (dattr->atttypmod >= 0 &&
7426  dattr->atttypmod != sattr->atttypmod))
7427  return false;
7428  }
7429  else
7430  {
7431  /* Dropped columns are OK as long as length/alignment match */
7432  if (dattr->attlen != sattr->attlen ||
7433  dattr->attalign != sattr->attalign)
7434  return false;
7435  }
7436  }
7437  return true;
7438 }
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
int i

◆ contains_target_param()

static bool contains_target_param ( Node node,
int *  target_dno 
)
static

Definition at line 8344 of file pl_exec.c.

References expression_tree_walker(), IsA, PARAM_EXTERN, Param::paramid, and Param::paramkind.

Referenced by exec_check_rw_parameter().

8345 {
8346  if (node == NULL)
8347  return false;
8348  if (IsA(node, Param))
8349  {
8350  Param *param = (Param *) node;
8351 
8352  if (param->paramkind == PARAM_EXTERN &&
8353  param->paramid == *target_dno + 1)
8354  return true;
8355  return false;
8356  }
8358  (void *) target_dno);
8359 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
ParamKind paramkind
Definition: primnodes.h:262
static bool contains_target_param(Node *node, int *target_dno)
Definition: pl_exec.c:8344
int paramid
Definition: primnodes.h:263
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1839

◆ convert_value_to_string()

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

Definition at line 7804 of file pl_exec.c.

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

Referenced by exec_dynquery_with_params(), exec_stmt_assert(), exec_stmt_dynexecute(), exec_stmt_raise(), exec_stmt_return_query(), format_expr_params(), and format_preparedparamsdata().

7805 {
7806  char *result;
7807  MemoryContext oldcontext;
7808  Oid typoutput;
7809  bool typIsVarlena;
7810 
7811  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7812  getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
7813  result = OidOutputFunctionCall(typoutput, value);
7814  MemoryContextSwitchTo(oldcontext);
7815 
7816  return result;
7817 }
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2784
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned int Oid
Definition: postgres_ext.h:31
#define get_eval_mcontext(estate)
Definition: pl_exec.c:131
static struct @143 value
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1657

◆ copy_plpgsql_datums()

static void copy_plpgsql_datums ( PLpgSQL_execstate estate,
PLpgSQL_function func 
)
static

Definition at line 1267 of file pl_exec.c.

References Assert, PLpgSQL_function::copiable_size, PLpgSQL_function::datums, PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, elog, ERROR, i, MAXALIGN, PLpgSQL_execstate::ndatums, palloc(), PLPGSQL_DTYPE_ARRAYELEM, 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().

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

◆ deconstruct_composite_datum()

static TupleDesc deconstruct_composite_datum ( Datum  value,
HeapTupleData tmptup 
)
static

Definition at line 7505 of file pl_exec.c.

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

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

7506 {
7507  HeapTupleHeader td;
7508  Oid tupType;
7509  int32 tupTypmod;
7510 
7511  /* Get tuple body (note this could involve detoasting) */
7513 
7514  /* Build a temporary HeapTuple control structure */
7515  tmptup->t_len = HeapTupleHeaderGetDatumLength(td);
7516  ItemPointerSetInvalid(&(tmptup->t_self));
7517  tmptup->t_tableOid = InvalidOid;
7518  tmptup->t_data = td;
7519 
7520  /* Extract rowtype info and find a tupdesc */
7521  tupType = HeapTupleHeaderGetTypeId(td);
7522  tupTypmod = HeapTupleHeaderGetTypMod(td);
7523  return lookup_rowtype_tupdesc(tupType, tupTypmod);
7524 }
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1710
unsigned int Oid
Definition: postgres_ext.h:31
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:294
signed int int32
Definition: c.h:362
HeapTupleHeader t_data
Definition: htup.h:68
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:468
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
Oid t_tableOid
Definition: htup.h:66
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:458
#define InvalidOid
Definition: postgres_ext.h:36
static struct @143 value
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:452

◆ do_cast_value()

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

Definition at line 7857 of file pl_exec.c.

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

Referenced by exec_cast_value().

7861 {
7862  plpgsql_CastHashEntry *cast_entry;
7863 
7864  cast_entry = get_cast_hashentry(estate,
7865  valtype, valtypmod,
7866  reqtype, reqtypmod);
7867  if (cast_entry)
7868  {
7869  ExprContext *econtext = estate->eval_econtext;
7870  MemoryContext oldcontext;
7871 
7872  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7873 
7874  econtext->caseValue_datum = value;
7875  econtext->caseValue_isNull = *isnull;
7876 
7877  cast_entry->cast_in_use = true;
7878 
7879  value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
7880  isnull);
7881 
7882  cast_entry->cast_in_use = false;
7883 
7884  MemoryContextSwitchTo(oldcontext);
7885  }
7886 
7887  return value;
7888 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static plpgsql_CastHashEntry * get_cast_hashentry(PLpgSQL_execstate *estate, Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod)
Definition: pl_exec.c:7901
Datum caseValue_datum
Definition: execnodes.h:251
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:290
#define get_eval_mcontext(estate)
Definition: pl_exec.c:131
static struct @143 value
ExprContext * eval_econtext
Definition: plpgsql.h:1109
bool caseValue_isNull
Definition: execnodes.h:253
ExprState * cast_exprstate
Definition: pl_exec.c:167

◆ exception_matches_conditions()

static bool exception_matches_conditions ( ErrorData edata,
PLpgSQL_condition cond 
)
static

Definition at line 1553 of file pl_exec.c.

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

Referenced by exec_stmt_block().

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

◆ exec_assign_c_string()

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

Definition at line 5009 of file pl_exec.c.

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

Referenced by exec_stmt_getdiag().

5011 {
5012  text *value;
5013  MemoryContext oldcontext;
5014 
5015  /* Use eval_mcontext for short-lived text value */
5016  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5017  if (str != NULL)
5018  value = cstring_to_text(str);
5019  else
5020  value = cstring_to_text("");
5021  MemoryContextSwitchTo(oldcontext);
5022 
5023  exec_assign_value(estate, target, PointerGetDatum(value), false,
5024  TEXTOID, -1);
5025 }
#define PointerGetDatum(X)
Definition: postgres.h:556
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define get_eval_mcontext(estate)
Definition: pl_exec.c:131
static struct @143 value
text * cstring_to_text(const char *s)
Definition: varlena.c:172
Definition: c.h:562
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:5037

◆ exec_assign_expr()

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

Definition at line 4972 of file pl_exec.c.

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

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

4974 {
4975  Datum value;
4976  bool isnull;
4977  Oid valtype;
4978  int32 valtypmod;
4979 
4980  /*
4981  * If first time through, create a plan for this expression, and then see
4982  * if we can pass the target variable as a read-write parameter to the
4983  * expression. (This is a bit messy, but it seems cleaner than modifying
4984  * the API of exec_eval_expr for the purpose.)
4985  */
4986  if (expr->plan == NULL)
4987  {
4988  exec_prepare_plan(estate, expr, 0, true);
4989  if (target->dtype == PLPGSQL_DTYPE_VAR)
4990  exec_check_rw_parameter(expr, target->dno);
4991  }
4992 
4993  value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod);
4994  exec_assign_value(estate, target, value, isnull, valtype, valtypmod);
4995  exec_eval_cleanup(estate);
4996 }
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions, bool keepplan)
Definition: pl_exec.c:4119
static void exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno)
Definition: pl_exec.c:8267
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4098
unsigned int Oid
Definition: postgres_ext.h:31
PLpgSQL_datum_type dtype
Definition: plpgsql.h:267
SPIPlanPtr plan
Definition: plpgsql.h:222
signed int int32
Definition: c.h:362
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5833
uintptr_t Datum
Definition: postgres.h:367
static struct @143 value
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:5037

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

References array_set_element(), PLpgSQL_arrayelem::arrayparentno, PLpgSQL_arrayelem::arraytyplen, PLpgSQL_arrayelem::arraytypmod, PLpgSQL_arrayelem::arraytypoid, Assert, assign_simple_var(), PLpgSQL_execstate::atomic, PLpgSQL_type::atttypmod, construct_empty_array(), PLpgSQL_var::datatype, PLpgSQL_execstate::datum_context, DatumGetPointer, PLpgSQL_execstate::datums, datumTransfer(), PLpgSQL_datum::dtype, PLpgSQL_arrayelem::elemtypalign, PLpgSQL_arrayelem::elemtypbyval, PLpgSQL_arrayelem::elemtyplen, PLpgSQL_arrayelem::elemtypoid, elog, ExpandedRecordHeader::er_tupdesc_id, ereport, PLpgSQL_rec::erh, errcode(), errmsg(), ERROR, PLpgSQL_execstate::eval_tuptable, exec_cast_value(), exec_eval_datum(), exec_eval_integer(), 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, get_element_type(), get_eval_mcontext, get_typlen(), get_typlenbyvalalign(), getBaseTypeAndTypmod(), i, instantiate_empty_record_variable(), PLpgSQL_var::isnull, MAXDIM, MemoryContextSwitchTo(), PLpgSQL_var::notnull, PLpgSQL_rec::notnull, OidIsValid, PLpgSQL_arrayelem::parenttypmod, PLpgSQL_arrayelem::parenttypoid, PLPGSQL_DTYPE_ARRAYELEM, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, PLPGSQL_PROMISE_NONE, PointerGetDatum, PLpgSQL_var::promise, PLpgSQL_recfield::recparentno, PLpgSQL_recfield::rectupledescid, PLpgSQL_var::refname, PLpgSQL_rec::refname, SPI_freetuptable(), PLpgSQL_arrayelem::subscript, PLpgSQL_type::typbyval, type_is_rowtype(), PLpgSQL_type::typisarray, PLpgSQL_type::typlen, PLpgSQL_type::typoid, unlikely, PLpgSQL_var::value, and VARATT_IS_EXTERNAL_EXPANDED_RW.

Referenced by exec_assign_c_string(), exec_assign_expr(), exec_move_row_from_fields(), exec_stmt_block(), exec_stmt_case(), exec_stmt_foreach_a(), and exec_stmt_getdiag().

5041 {
5042  switch (target->dtype)
5043  {
5044  case PLPGSQL_DTYPE_VAR:
5045  case PLPGSQL_DTYPE_PROMISE:
5046  {
5047  /*
5048  * Target is a variable
5049  */
5050  PLpgSQL_var *var = (PLpgSQL_var *) target;
5051  Datum newvalue;
5052 
5053  newvalue = exec_cast_value(estate,
5054  value,
5055  &isNull,
5056  valtype,
5057  valtypmod,
5058  var->datatype->typoid,
5059  var->datatype->atttypmod);
5060 
5061  if (isNull && var->notnull)
5062  ereport(ERROR,
5063  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5064  errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
5065  var->refname)));
5066 
5067  /*
5068  * If type is by-reference, copy the new value (which is
5069  * probably in the eval_mcontext) into the procedure's main
5070  * memory context. But if it's a read/write reference to an
5071  * expanded object, no physical copy needs to happen; at most
5072  * we need to reparent the object's memory context.
5073  *
5074  * If it's an array, we force the value to be stored in R/W
5075  * expanded form. This wins if the function later does, say,
5076  * a lot of array subscripting operations on the variable, and
5077  * otherwise might lose. We might need to use a different
5078  * heuristic, but it's too soon to tell. Also, are there
5079  * cases where it'd be useful to force non-array values into
5080  * expanded form?
5081  */
5082  if (!var->datatype->typbyval && !isNull)
5083  {
5084  if (var->datatype->typisarray &&
5086  {
5087  /* array and not already R/W, so apply expand_array */
5088  newvalue = expand_array(newvalue,
5089  estate->datum_context,
5090  NULL);
5091  }
5092  else
5093  {
5094  /* else transfer value if R/W, else just datumCopy */
5095  newvalue = datumTransfer(newvalue,
5096  false,
5097  var->datatype->typlen);
5098  }
5099  }
5100 
5101  /*
5102  * Now free the old value, if any, and assign the new one. But
5103  * skip the assignment if old and new values are the same.
5104  * Note that for expanded objects, this test is necessary and
5105  * cannot reliably be made any earlier; we have to be looking
5106  * at the object's standard R/W pointer to be sure pointer
5107  * equality is meaningful.
5108  *
5109  * Also, if it's a promise variable, we should disarm the
5110  * promise in any case --- otherwise, assigning null to an
5111  * armed promise variable would fail to disarm the promise.
5112  */
5113  if (var->value != newvalue || var->isnull || isNull)
5114  assign_simple_var(estate, var, newvalue, isNull,
5115  (!var->datatype->typbyval && !isNull));
5116  else
5118  break;
5119  }
5120 
5121  case PLPGSQL_DTYPE_ROW:
5122  {
5123  /*
5124  * Target is a row variable
5125  */
5126  PLpgSQL_row *row = (PLpgSQL_row *) target;
5127 
5128  if (isNull)
5129  {
5130  /* If source is null, just assign nulls to the row */
5131  exec_move_row(estate, (PLpgSQL_variable *) row,
5132  NULL, NULL);
5133  }
5134  else
5135  {
5136  /* Source must be of RECORD or composite type */
5137  if (!type_is_rowtype(valtype))
5138  ereport(ERROR,
5139  (errcode(ERRCODE_DATATYPE_MISMATCH),
5140  errmsg("cannot assign non-composite value to a row variable")));
5142  value);
5143  }
5144  break;
5145  }
5146 
5147  case PLPGSQL_DTYPE_REC:
5148  {
5149  /*
5150  * Target is a record variable
5151  */
5152  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
5153 
5154  if (isNull)
5155  {
5156  if (rec->notnull)
5157  ereport(ERROR,
5158  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5159  errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
5160  rec->refname)));
5161 
5162  /* Set variable to a simple NULL */
5163  exec_move_row(estate, (PLpgSQL_variable *) rec,
5164  NULL, NULL);
5165  }
5166  else
5167  {
5168  /* Source must be of RECORD or composite type */
5169  if (!type_is_rowtype(valtype))
5170  ereport(ERROR,
5171  (errcode(ERRCODE_DATATYPE_MISMATCH),
5172  errmsg("cannot assign non-composite value to a record variable")));
5174  value);
5175  }
5176  break;
5177  }
5178 
5180  {
5181  /*
5182  * Target is a field of a record
5183  */
5184  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) target;
5185  PLpgSQL_rec *rec;
5186  ExpandedRecordHeader *erh;
5187 
5188  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5189  erh = rec->erh;
5190 
5191  /*
5192  * If record variable is NULL, instantiate it if it has a
5193  * named composite type, else complain. (This won't change
5194  * the logical state of the record, but if we successfully
5195  * assign below, the unassigned fields will all become NULLs.)
5196  */
5197  if (erh == NULL)
5198  {
5199  instantiate_empty_record_variable(estate, rec);
5200  erh = rec->erh;
5201  }
5202 
5203  /*
5204  * Look up the field's properties if we have not already, or
5205  * if the tuple descriptor ID changed since last time.
5206  */
5207  if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
5208  {
5210  recfield->fieldname,
5211  &recfield->finfo))
5212  ereport(ERROR,
5213  (errcode(ERRCODE_UNDEFINED_COLUMN),
5214  errmsg("record \"%s\" has no field \"%s\"",
5215  rec->refname, recfield->fieldname)));
5216  recfield->rectupledescid = erh->er_tupdesc_id;
5217  }
5218 
5219  /* We don't support assignments to system columns. */
5220  if (recfield->finfo.fnumber <= 0)
5221  ereport(ERROR,
5222  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5223  errmsg("cannot assign to system column \"%s\"",
5224  recfield->fieldname)));
5225 
5226  /* Cast the new value to the right type, if needed. */
5227  value = exec_cast_value(estate,
5228  value,
5229  &isNull,
5230  valtype,
5231  valtypmod,
5232  recfield->finfo.ftypeid,
5233  recfield->finfo.ftypmod);
5234 
5235  /* And assign it. */
5236  expanded_record_set_field(erh, recfield->finfo.fnumber,
5237  value, isNull, !estate->atomic);
5238  break;
5239  }
5240 
5242  {
5243  /*
5244  * Target is an element of an array
5245  */
5246  PLpgSQL_arrayelem *arrayelem;
5247  int nsubscripts;
5248  int i;
5249  PLpgSQL_expr *subscripts[MAXDIM];
5250  int subscriptvals[MAXDIM];
5251  Datum oldarraydatum,
5252  newarraydatum,
5253  coerced_value;
5254  bool oldarrayisnull;
5255  Oid parenttypoid;
5256  int32 parenttypmod;
5257  SPITupleTable *save_eval_tuptable;
5258  MemoryContext oldcontext;
5259 
5260  /*
5261  * We need to do subscript evaluation, which might require
5262  * evaluating general expressions; and the caller might have
5263  * done that too in order to prepare the input Datum. We have
5264  * to save and restore the caller's SPI_execute result, if
5265  * any.
5266  */
5267  save_eval_tuptable = estate->eval_tuptable;
5268  estate->eval_tuptable = NULL;
5269 
5270  /*
5271  * To handle constructs like x[1][2] := something, we have to
5272  * be prepared to deal with a chain of arrayelem datums. Chase
5273  * back to find the base array datum, and save the subscript
5274  * expressions as we go. (We are scanning right to left here,
5275  * but want to evaluate the subscripts left-to-right to
5276  * minimize surprises.) Note that arrayelem is left pointing
5277  * to the leftmost arrayelem datum, where we will cache the
5278  * array element type data.
5279  */
5280  nsubscripts = 0;
5281  do
5282  {
5283  arrayelem = (PLpgSQL_arrayelem *) target;
5284  if (nsubscripts >= MAXDIM)
5285  ereport(ERROR,
5286  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5287  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
5288  nsubscripts + 1, MAXDIM)));
5289  subscripts[nsubscripts++] = arrayelem->subscript;
5290  target = estate->datums[arrayelem->arrayparentno];
5291  } while (target->dtype == PLPGSQL_DTYPE_ARRAYELEM);
5292 
5293  /* Fetch current value of array datum */
5294  exec_eval_datum(estate, target,
5295  &parenttypoid, &parenttypmod,
5296  &oldarraydatum, &oldarrayisnull);
5297 
5298  /* Update cached type data if necessary */
5299  if (arrayelem->parenttypoid != parenttypoid ||
5300  arrayelem->parenttypmod != parenttypmod)
5301  {
5302  Oid arraytypoid;
5303  int32 arraytypmod = parenttypmod;
5304  int16 arraytyplen;
5305  Oid elemtypoid;
5306  int16 elemtyplen;
5307  bool elemtypbyval;
5308  char elemtypalign;
5309 
5310  /* If target is domain over array, reduce to base type */
5311  arraytypoid = getBaseTypeAndTypmod(parenttypoid,
5312  &arraytypmod);
5313 
5314  /* ... and identify the element type */
5315  elemtypoid = get_element_type(arraytypoid);
5316  if (!OidIsValid(elemtypoid))
5317  ereport(ERROR,
5318  (errcode(ERRCODE_DATATYPE_MISMATCH),
5319  errmsg("subscripted object is not an array")));
5320 
5321  /* Collect needed data about the types */
5322  arraytyplen = get_typlen(arraytypoid);
5323 
5324  get_typlenbyvalalign(elemtypoid,
5325  &elemtyplen,
5326  &elemtypbyval,
5327  &elemtypalign);
5328 
5329  /* Now safe to update the cached data */
5330  arrayelem->parenttypoid = parenttypoid;
5331  arrayelem->parenttypmod = parenttypmod;
5332  arrayelem->arraytypoid = arraytypoid;
5333  arrayelem->arraytypmod = arraytypmod;
5334  arrayelem->arraytyplen = arraytyplen;
5335  arrayelem->elemtypoid = elemtypoid;
5336  arrayelem->elemtyplen = elemtyplen;
5337  arrayelem->elemtypbyval = elemtypbyval;
5338  arrayelem->elemtypalign = elemtypalign;
5339  }
5340 
5341  /*
5342  * Evaluate the subscripts, switch into left-to-right order.
5343  * Like the expression built by ExecInitSubscriptingRef(),
5344  * complain if any subscript is null.
5345  */
5346  for (i = 0; i < nsubscripts; i++)
5347  {
5348  bool subisnull;
5349 
5350  subscriptvals[i] =
5351  exec_eval_integer(estate,
5352  subscripts[nsubscripts - 1 - i],
5353  &subisnull);
5354  if (subisnull)
5355  ereport(ERROR,
5356  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5357  errmsg("array subscript in assignment must not be null")));
5358 
5359  /*
5360  * Clean up in case the subscript expression wasn't
5361  * simple. We can't do exec_eval_cleanup, but we can do
5362  * this much (which is safe because the integer subscript
5363  * value is surely pass-by-value), and we must do it in
5364  * case the next subscript expression isn't simple either.
5365  */
5366  if (estate->eval_tuptable != NULL)
5368  estate->eval_tuptable = NULL;
5369  }
5370 
5371  /* Now we can restore caller's SPI_execute result if any. */
5372  Assert(estate->eval_tuptable == NULL);
5373  estate->eval_tuptable = save_eval_tuptable;
5374 
5375  /* Coerce source value to match array element type. */
5376  coerced_value = exec_cast_value(estate,
5377  value,
5378  &isNull,
5379  valtype,
5380  valtypmod,
5381  arrayelem->elemtypoid,
5382  arrayelem->arraytypmod);
5383 
5384  /*
5385  * If the original array is null, cons up an empty array so
5386  * that the assignment can proceed; we'll end with a
5387  * one-element array containing just the assigned-to
5388  * subscript. This only works for varlena arrays, though; for
5389  * fixed-length array types we skip the assignment. We can't
5390  * support assignment of a null entry into a fixed-length
5391  * array, either, so that's a no-op too. This is all ugly but
5392  * corresponds to the current behavior of execExpr*.c.
5393  */
5394  if (arrayelem->arraytyplen > 0 && /* fixed-length array? */
5395  (oldarrayisnull || isNull))
5396  return;
5397 
5398  /* empty array, if any, and newarraydatum are short-lived */
5399  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5400 
5401  if (oldarrayisnull)
5402  oldarraydatum = PointerGetDatum(construct_empty_array(arrayelem->elemtypoid));
5403 
5404  /*
5405  * Build the modified array value.
5406  */
5407  newarraydatum = array_set_element(oldarraydatum,
5408  nsubscripts,
5409  subscriptvals,
5410  coerced_value,
5411  isNull,
5412  arrayelem->arraytyplen,
5413  arrayelem->elemtyplen,
5414  arrayelem->elemtypbyval,
5415  arrayelem->elemtypalign);
5416 
5417  MemoryContextSwitchTo(oldcontext);
5418 
5419  /*
5420  * Assign the new array to the base variable. It's never NULL
5421  * at this point. Note that if the target is a domain,
5422  * coercing the base array type back up to the domain will
5423  * happen within exec_assign_value.
5424  */
5425  exec_assign_value(estate, target,
5426  newarraydatum,
5427  false,
5428  arrayelem->arraytypoid,
5429  arrayelem->arraytypmod);
5430  break;
5431  }
5432 
5433  default:
5434  elog(ERROR, "unrecognized dtype: %d", target->dtype);
5435  }
5436 }
PLpgSQL_promise_type promise
Definition: plpgsql.h:332
signed short int16
Definition: c.h:361
int16 elemtyplen
Definition: plpgsql.h:443
#define expanded_record_set_field(erh, fnumber, newValue, isnull, expand_external)
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2426
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1107
char * refname
Definition: plpgsql.h:303
static void exec_eval_datum(PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeid, int32 *typetypmod, Datum *value, bool *isnull)
Definition: pl_exec.c:5456
bool expanded_record_lookup_field(ExpandedRecordHeader *erh, const char *fieldname, ExpandedRecordFieldInfo *finfo)
#define MAXDIM
Definition: c.h:542
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2636
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2159
#define PointerGetDatum(X)
Definition: postgres.h:556
PLpgSQL_type * datatype
Definition: plpgsql.h:310
Datum expand_array(Datum arraydatum, MemoryContext parentcontext, ArrayMetaState *metacache)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void instantiate_empty_record_variable(PLpgSQL_execstate *estate, PLpgSQL_rec *rec)
Definition: pl_exec.c:7769
ExpandedRecordHeader * erh
Definition: plpgsql.h:404
int errcode(int sqlerrcode)
Definition: elog.c:610
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8542
Datum array_set_element(Datum arraydatum, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:2221
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3432
unsigned int Oid
Definition: postgres_ext.h:31
static void exec_move_row_from_datum(PLpgSQL_execstate *estate, PLpgSQL_variable *target, Datum value)
Definition: pl_exec.c:7536
PLpgSQL_datum_type dtype
Definition: plpgsql.h:267
#define OidIsValid(objectId)
Definition: c.h:651
char * refname
Definition: plpgsql.h:383
signed int int32
Definition: c.h:362
PLpgSQL_datum ** datums
Definition: plpgsql.h:1082
int32 arraytypmod
Definition: plpgsql.h:440
bool notnull
Definition: plpgsql.h:306
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7833
#define ERROR
Definition: elog.h:43
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2543
uint64 rectupledescid
Definition: plpgsql.h:419
bool typbyval
Definition: plpgsql.h:205
#define get_eval_mcontext(estate)
Definition: pl_exec.c:131
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1235
bool typisarray
Definition: plpgsql.h:208
uintptr_t Datum
Definition: postgres.h:367
static int exec_eval_integer(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
Definition: pl_exec.c:5787
ExpandedRecordFieldInfo finfo
Definition: plpgsql.h:420
int32 parenttypmod
Definition: plpgsql.h:438
Datum value
Definition: plpgsql.h:323
static struct @143 value
#define ereport(elevel,...)
Definition: elog.h:144
Datum datumTransfer(Datum value, bool typByVal, int typLen)
Definition: datum.c:193
#define Assert(condition)
Definition: c.h:745
int16 arraytyplen
Definition: plpgsql.h:441
#define DatumGetPointer(X)
Definition: postgres.h:549
MemoryContext datum_context
Definition: plpgsql.h:1084
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2085
int errmsg(const char *fmt,...)
Definition: elog.c:824
int32 atttypmod
Definition: plpgsql.h:209
static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
Definition: pl_exec.c:6862
#define elog(elevel,...)
Definition: elog.h:214
int i
PLpgSQL_expr * subscript
Definition: plpgsql.h:433
#define VARATT_IS_EXTERNAL_EXPANDED_RW(PTR)
Definition: postgres.h:320
#define unlikely(x)
Definition: c.h:206
int16 typlen
Definition: plpgsql.h:204
bool notnull
Definition: plpgsql.h:386
char * fieldname
Definition: plpgsql.h:416
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:5037
bool isnull
Definition: plpgsql.h:324
Oid typoid
Definition: plpgsql.h:202

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

References do_cast_value(), and value.

Referenced by exec_assign_value(), exec_eval_boolean(), exec_eval_integer(), exec_move_row_from_fields(), exec_stmt_fori(), exec_stmt_return_next(), and plpgsql_exec_function().

7837 {
7838  /*
7839  * If the type of the given value isn't what's requested, convert it.
7840  */
7841  if (valtype != reqtype ||
7842  (valtypmod != reqtypmod && reqtypmod != -1))
7843  {
7844  /* We keep the slow path out-of-line. */
7845  value = do_cast_value(estate, value, isnull, valtype, valtypmod,
7846  reqtype, reqtypmod);
7847  }
7848 
7849  return value;
7850 }
static Datum do_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7857
static struct @143 value

◆ exec_check_rw_parameter()

static void exec_check_rw_parameter ( PLpgSQL_expr expr,
int  target_dno 
)
static

Definition at line 8267 of file pl_exec.c.

References arg, FuncExpr::args, OpExpr::args, bms_is_member(), contains_target_param(), PLpgSQL_expr::expr_simple_expr, FuncExpr::funcid, IsA, lfirst, OpExpr::opfuncid, PLpgSQL_expr::paramnos, and PLpgSQL_expr::rwparam.

Referenced by exec_assign_expr(), and exec_eval_simple_expr().

8268 {
8269  Oid funcid;
8270  List *fargs;
8271  ListCell *lc;
8272 
8273  /* Assume unsafe */
8274  expr->rwparam = -1;
8275 
8276  /*
8277  * If the expression isn't simple, there's no point in trying to optimize
8278  * (because the exec_run_select code path will flatten any expanded result
8279  * anyway). Even without that, this seems like a good safety restriction.
8280  */
8281  if (expr->expr_simple_expr == NULL)
8282  return;
8283 
8284  /*
8285  * If target variable isn't referenced by expression, no need to look
8286  * further.
8287  */
8288  if (!bms_is_member(target_dno, expr->paramnos))
8289  return;
8290 
8291  /*
8292  * Top level of expression must be a simple FuncExpr or OpExpr.
8293  */
8294  if (IsA(expr->expr_simple_expr, FuncExpr))
8295  {
8296  FuncExpr *fexpr = (FuncExpr *) expr->expr_simple_expr;
8297 
8298  funcid = fexpr->funcid;
8299  fargs = fexpr->args;
8300  }
8301  else if (IsA(expr->expr_simple_expr, OpExpr))
8302  {
8303  OpExpr *opexpr = (OpExpr *) expr->expr_simple_expr;
8304 
8305  funcid = opexpr->opfuncid;
8306  fargs = opexpr->args;
8307  }
8308  else
8309  return;
8310 
8311  /*
8312  * The top-level function must be one that we trust to be "safe".
8313  * Currently we hard-wire the list, but it would be very desirable to
8314  * allow extensions to mark their functions as safe ...
8315  */
8316  if (!(funcid == F_ARRAY_APPEND ||
8317  funcid == F_ARRAY_PREPEND))
8318  return;
8319 
8320  /*
8321  * The target variable (in the form of a Param) must only appear as a
8322  * direct argument of the top-level function.
8323  */
8324  foreach(lc, fargs)
8325  {
8326  Node *arg = (Node *) lfirst(lc);
8327 
8328  /* A Param is OK, whether it's the target variable or not */
8329  if (arg && IsA(arg, Param))
8330  continue;
8331  /* Otherwise, argument expression must not reference target */
8332  if (contains_target_param(arg, &target_dno))
8333  return;
8334  }
8335 
8336  /* OK, we can pass target as a read-write parameter */
8337  expr->rwparam = target_dno;
8338 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
List * args
Definition: primnodes.h:477
Definition: nodes.h:529
unsigned int Oid
Definition: postgres_ext.h:31
Bitmapset * paramnos
Definition: plpgsql.h:223
Oid funcid
Definition: primnodes.h:469
static bool contains_target_param(Node *node, int *target_dno)
Definition: pl_exec.c:8344
Expr * expr_simple_expr
Definition: plpgsql.h:233
int rwparam
Definition: plpgsql.h:224
Oid opfuncid
Definition: primnodes.h:517
#define lfirst(lc)
Definition: pg_list.h:190
void * arg
List * args
Definition: primnodes.h:522
Definition: pg_list.h:50
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427

◆ exec_dynquery_with_params()

static Portal exec_dynquery_with_params ( PLpgSQL_execstate estate,
PLpgSQL_expr dynquery,
List params,
const char *  portalname,
int  cursorOptions 
)
static

Definition at line 8723 of file pl_exec.c.

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(), PLpgSQL_execstate::readonly_func, SPI_cursor_parse_open_with_paramlist(), SPI_result, and SPI_result_code_string().

Referenced by exec_stmt_dynfors(), and exec_stmt_open().

8728 {
8729  Portal portal;
8730  Datum query;
8731  bool isnull;
8732  Oid restype;
8733  int32 restypmod;
8734  char *querystr;
8735  MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
8736 
8737  /*
8738  * Evaluate the string expression after the EXECUTE keyword. Its result is
8739  * the querystring we have to execute.
8740  */
8741  query = exec_eval_expr(estate, dynquery, &isnull, &restype, &restypmod);
8742  if (isnull)
8743  ereport(ERROR,
8744  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
8745  errmsg("query string argument of EXECUTE is null")));
8746 
8747  /* Get the C-String representation */
8748  querystr = convert_value_to_string(estate, query, restype);
8749 
8750  /* copy it into the stmt_mcontext before we clean up */
8751  querystr = MemoryContextStrdup(stmt_mcontext, querystr);
8752 
8753  exec_eval_cleanup(estate);
8754 
8755  /*
8756  * Open an implicit cursor for the query. We use
8757  * SPI_cursor_parse_open_with_paramlist even when there are no params,
8758  * because this avoids making and freeing one copy of the plan.
8759  */
8760  portal = SPI_cursor_parse_open_with_paramlist(portalname,
8761  querystr,
8762  exec_eval_using_params(estate,
8763  params),
8764  estate->readonly_func,
8765  cursorOptions);
8766 
8767  if (portal == NULL)
8768  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
8769  querystr, SPI_result_code_string(SPI_result));
8770 
8771  /* Release transient data */
8772  MemoryContextReset(stmt_mcontext);
8773 
8774  return portal;
8775 }
int errcode(int sqlerrcode)
Definition: elog.c:610
static ParamListInfo exec_eval_using_params(PLpgSQL_execstate *estate, List *params)
Definition: pl_exec.c:8641
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4098
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:362
int SPI_result
Definition: spi.c:47
#define ERROR
Definition: elog.h:43
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5833
const char * SPI_result_code_string(int code)
Definition: spi.c:1815
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1502
uintptr_t Datum
Definition: postgres.h:367
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:824
Portal SPI_cursor_parse_open_with_paramlist(const char *name, const char *src, ParamListInfo params, bool read_only, int cursorOptions)
Definition: spi.c:1386
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1173
#define elog(elevel,...)
Definition: elog.h:214
static char * convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
Definition: pl_exec.c:7804

◆ exec_eval_boolean()

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

Definition at line 5810 of file pl_exec.c.

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

Referenced by exec_stmt_assert(), exec_stmt_case(), exec_stmt_exit(), exec_stmt_if(), and exec_stmt_while().

5813 {
5814  Datum exprdatum;
5815  Oid exprtypeid;
5816  int32 exprtypmod;
5817 
5818  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5819  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5820  exprtypeid, exprtypmod,
5821  BOOLOID, -1);
5822  return DatumGetBool(exprdatum);
5823 }
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:362
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7833
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5833
#define DatumGetBool(X)
Definition: postgres.h:393
uintptr_t Datum
Definition: postgres.h:367

◆ exec_eval_cleanup()

static void exec_eval_cleanup ( PLpgSQL_execstate estate)
static

Definition at line 4098 of file pl_exec.c.

References PLpgSQL_execstate::eval_econtext, PLpgSQL_execstate::eval_tuptable, ResetExprContext, and SPI_freetuptable().

Referenced by exec_assign_expr(), exec_dynquery_with_params(), exec_eval_using_params(), exec_for_query(), exec_run_select(), exec_stmt_assert(), exec_stmt_block(), exec_stmt_call(), exec_stmt_case(), exec_stmt_dynexecute(), exec_stmt_execsql(), exec_stmt_exit(), exec_stmt_fetch(), exec_stmt_forc(), exec_stmt_foreach_a(), exec_stmt_fori(), exec_stmt_getdiag(), exec_stmt_if(), exec_stmt_open(), exec_stmt_perform(), exec_stmt_raise(), exec_stmt_return_next(), exec_stmt_return_query(), exec_stmt_while(), plpgsql_exec_event_trigger(), plpgsql_exec_function(), and plpgsql_exec_trigger().

4099 {
4100  /* Clear result of a full SPI_execute */
4101  if (estate->eval_tuptable != NULL)
4103  estate->eval_tuptable = NULL;
4104 
4105  /*
4106  * Clear result of exec_eval_simple_expr (but keep the econtext). This
4107  * also clears any short-lived allocations done via get_eval_mcontext.
4108  */
4109  if (estate->eval_econtext != NULL)
4111 }
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1107
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1235
ExprContext * eval_econtext
Definition: plpgsql.h:1109
#define ResetExprContext(econtext)
Definition: executor.h:501

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

References PLpgSQL_type::atttypmod, BlessTupleDesc(), PLpgSQL_var::datatype, PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, PLpgSQL_var::dtype, elog, ExpandedRecordHeader::er_tupdesc_id, ExpandedRecordHeader::er_typeid, ExpandedRecordHeader::er_typmod, ereport, PLpgSQL_rec::erh, errcode(), errmsg(), ERROR, expanded_record_get_field(), expanded_record_lookup_field(), ExpandedRecordGetDatum, ExpandedRecordIsEmpty, PLpgSQL_recfield::fieldname, PLpgSQL_recfield::finfo, ExpandedRecordFieldInfo::fnumber, ExpandedRecordFieldInfo::ftypeid, ExpandedRecordFieldInfo::ftypmod, get_eval_mcontext, HeapTupleGetDatum, instantiate_empty_record_variable(), PLpgSQL_var::isnull, make_tuple_from_row(), MemoryContextSwitchTo(), PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, plpgsql_fulfill_promise(), PLpgSQL_recfield::recparentno, PLpgSQL_recfield::rectupledescid, PLpgSQL_rec::rectypeid, PLpgSQL_rec::refname, PLpgSQL_row::rowtupdesc, TupleDescData::tdtypeid, TupleDescData::tdtypmod, PLpgSQL_type::typoid, unlikely, and PLpgSQL_var::value.

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

5462 {
5463  MemoryContext oldcontext;
5464 
5465  switch (datum->dtype)
5466  {
5467  case PLPGSQL_DTYPE_PROMISE:
5468  /* fulfill promise if needed, then handle like regular var */
5469  plpgsql_fulfill_promise(estate, (PLpgSQL_var *) datum);
5470 
5471  /* FALL THRU */
5472 
5473  case PLPGSQL_DTYPE_VAR:
5474  {
5475  PLpgSQL_var *var = (PLpgSQL_var *) datum;
5476 
5477  *typeid = var->datatype->typoid;
5478  *typetypmod = var->datatype->atttypmod;
5479  *value = var->value;
5480  *isnull = var->isnull;
5481  break;
5482  }
5483 
5484  case PLPGSQL_DTYPE_ROW:
5485  {
5486  PLpgSQL_row *row = (PLpgSQL_row *) datum;
5487  HeapTuple tup;
5488 
5489  /* We get here if there are multiple OUT parameters */
5490  if (!row->rowtupdesc) /* should not happen */
5491  elog(ERROR, "row variable has no tupdesc");
5492  /* Make sure we have a valid type/typmod setting */
5493  BlessTupleDesc(row->rowtupdesc);
5494  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5495  tup = make_tuple_from_row(estate, row, row->rowtupdesc);
5496  if (tup == NULL) /* should not happen */
5497  elog(ERROR, "row not compatible with its own tupdesc");
5498  *typeid = row->rowtupdesc->tdtypeid;
5499  *typetypmod = row->rowtupdesc->tdtypmod;
5500  *value = HeapTupleGetDatum(tup);
5501  *isnull = false;
5502  MemoryContextSwitchTo(oldcontext);
5503  break;
5504  }
5505 
5506  case PLPGSQL_DTYPE_REC:
5507  {
5508  PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
5509 
5510  if (rec->erh == NULL)
5511  {
5512  /* Treat uninstantiated record as a simple NULL */
5513  *value = (Datum) 0;
5514  *isnull = true;
5515  /* Report variable's declared type */
5516  *typeid = rec->rectypeid;
5517  *typetypmod = -1;
5518  }
5519  else
5520  {
5521  if (ExpandedRecordIsEmpty(rec->erh))
5522  {
5523  /* Empty record is also a NULL */
5524  *value = (Datum) 0;
5525  *isnull = true;
5526  }
5527  else
5528  {
5529  *value = ExpandedRecordGetDatum(rec->erh);
5530  *isnull = false;
5531  }
5532  if (rec->rectypeid != RECORDOID)
5533  {
5534  /* Report variable's declared type, if not RECORD */
5535  *typeid = rec->rectypeid;
5536  *typetypmod = -1;
5537  }
5538  else
5539  {
5540  /* Report record's actual type if declared RECORD */
5541  *typeid = rec->erh->er_typeid;
5542  *typetypmod = rec->erh->er_typmod;
5543  }
5544  }
5545  break;
5546  }
5547 
5549  {
5550  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
5551  PLpgSQL_rec *rec;
5552  ExpandedRecordHeader *erh;
5553 
5554  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5555  erh = rec->erh;
5556 
5557  /*
5558  * If record variable is NULL, instantiate it if it has a
5559  * named composite type, else complain. (This won't change
5560  * the logical state of the record: it's still NULL.)
5561  */
5562  if (erh == NULL)
5563  {
5564  instantiate_empty_record_variable(estate, rec);
5565  erh = rec->erh;
5566  }
5567 
5568  /*
5569  * Look up the field's properties if we have not already, or
5570  * if the tuple descriptor ID changed since last time.
5571  */
5572  if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
5573  {
5575  recfield->fieldname,
5576  &recfield->finfo))
5577  ereport(ERROR,
5578  (errcode(ERRCODE_UNDEFINED_COLUMN),
5579  errmsg("record \"%s\" has no field \"%s\"",
5580  rec->refname, recfield->fieldname)));
5581  recfield->rectupledescid = erh->er_tupdesc_id;
5582  }
5583 
5584  /* Report type data. */
5585  *typeid = recfield->finfo.ftypeid;
5586  *typetypmod = recfield->finfo.ftypmod;
5587 
5588  /* And fetch the field value. */
5590  recfield->finfo.fnumber,
5591  isnull);
5592  break;
5593  }
5594 
5595  default:
5596  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
5597  }
5598 }
static HeapTuple make_tuple_from_row(PLpgSQL_execstate *estate, PLpgSQL_row *row, TupleDesc tupdesc)
Definition: pl_exec.c:7450
#define ExpandedRecordIsEmpty(erh)
bool expanded_record_lookup_field(ExpandedRecordHeader *erh, const char *fieldname, ExpandedRecordFieldInfo *finfo)
static Datum expanded_record_get_field(ExpandedRecordHeader *erh, int fnumber, bool *isnull)
PLpgSQL_type * datatype
Definition: plpgsql.h:310
static void plpgsql_fulfill_promise(PLpgSQL_execstate *estate, PLpgSQL_var *var)
Definition: pl_exec.c:1342
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void instantiate_empty_record_variable(PLpgSQL_execstate *estate, PLpgSQL_rec *rec)
Definition: pl_exec.c:7769
ExpandedRecordHeader * erh
Definition: plpgsql.h:404
int errcode(int sqlerrcode)
Definition: elog.c:610
PLpgSQL_datum_type dtype
Definition: plpgsql.h:267
char * refname
Definition: plpgsql.h:383
PLpgSQL_datum ** datums
Definition: plpgsql.h:1082
#define ERROR
Definition: elog.h:43
int32 tdtypmod
Definition: tupdesc.h:83
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2052
uint64 rectupledescid
Definition: plpgsql.h:419
#define get_eval_mcontext(estate)
Definition: pl_exec.c:131
uintptr_t Datum
Definition: postgres.h:367
ExpandedRecordFieldInfo finfo
Definition: plpgsql.h:420
Datum value
Definition: plpgsql.h:323
static struct @143 value
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:220
Oid tdtypeid
Definition: tupdesc.h:82
int errmsg(const char *fmt,...)
Definition: elog.c:824
int32 atttypmod
Definition: plpgsql.h:209
#define elog(elevel,...)
Definition: elog.h:214
TupleDesc rowtupdesc
Definition: plpgsql.h:369
#define unlikely(x)
Definition: c.h:206
Oid rectypeid
Definition: plpgsql.h:397
#define ExpandedRecordGetDatum(erh)
char * fieldname
Definition: plpgsql.h:416
bool isnull
Definition: plpgsql.h:324
Oid typoid
Definition: plpgsql.h:202

◆ exec_eval_expr()

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

Definition at line 5833 of file pl_exec.c.

References CURSOR_OPT_PARALLEL_OK, ereport, errcode(), errmsg(), errmsg_plural(), ERROR, PLpgSQL_execstate::eval_processed, PLpgSQL_execstate::eval_tuptable, exec_eval_simple_expr(), exec_prepare_plan(), exec_run_select(), TupleDescData::natts, PLpgSQL_expr::plan, PLpgSQL_expr::query, SPI_getbinval(), SPI_OK_SELECT, SPITupleTable::tupdesc, TupleDescAttr, and SPITupleTable::vals.

Referenced by exec_assign_expr(), exec_dynquery_with_params(), exec_eval_boolean(), exec_eval_integer(), exec_eval_using_params(), exec_stmt_assert(), exec_stmt_case(), exec_stmt_dynexecute(), exec_stmt_foreach_a(), exec_stmt_fori(), exec_stmt_raise(), exec_stmt_return(), exec_stmt_return_next(), and exec_stmt_return_query().

5838 {
5839  Datum result = 0;
5840  int rc;
5841  Form_pg_attribute attr;
5842 
5843  /*
5844  * If first time through, create a plan for this expression.
5845  */
5846  if (expr->plan == NULL)
5847  exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK, true);
5848 
5849  /*
5850  * If this is a simple expression, bypass SPI and use the executor
5851  * directly
5852  */
5853  if (exec_eval_simple_expr(estate, expr,
5854  &result, isNull, rettype, rettypmod))
5855  return result;
5856 
5857  /*
5858  * Else do it the hard way via exec_run_select
5859  */
5860  rc = exec_run_select(estate, expr, 2, NULL);
5861  if (rc != SPI_OK_SELECT)
5862  ereport(ERROR,
5863  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5864  errmsg("query \"%s\" did not return data", expr->query)));
5865 
5866  /*
5867  * Check that the expression returns exactly one column...
5868  */
5869  if (estate->eval_tuptable->tupdesc->natts != 1)
5870  ereport(ERROR,
5871  (errcode(ERRCODE_SYNTAX_ERROR),
5872  errmsg_plural("query \"%s\" returned %d column",
5873  "query \"%s\" returned %d columns",
5874  estate->eval_tuptable->tupdesc->natts,
5875  expr->query,
5876  estate->eval_tuptable->tupdesc->natts)));
5877 
5878  /*
5879  * ... and get the column's datatype.
5880  */
5881  attr = TupleDescAttr(estate->eval_tuptable->tupdesc, 0);
5882  *rettype = attr->atttypid;
5883  *rettypmod = attr->atttypmod;
5884 
5885  /*
5886  * If there are no rows selected, the result is a NULL of that type.
5887  */
5888  if (estate->eval_processed == 0)
5889  {
5890  *isNull = true;
5891  return (Datum) 0;
5892  }
5893 
5894  /*
5895  * Check that the expression returned no more than one row.
5896  */
5897  if (estate->eval_processed != 1)
5898  ereport(ERROR,
5899  (errcode(ERRCODE_CARDINALITY_VIOLATION),
5900  errmsg("query \"%s\" returned more than one row",
5901  expr->query)));
5902 
5903  /*
5904  * Return the single result Datum.
5905  */
5906  return SPI_getbinval(estate->eval_tuptable->vals[0],
5907  estate->eval_tuptable->tupdesc, 1, isNull);
5908 }
char * query
Definition: plpgsql.h:221
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions, bool keepplan)
Definition: pl_exec.c:4119
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1107
uint64 eval_processed
Definition: plpgsql.h:1108
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:934
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
int errcode(int sqlerrcode)
Definition: elog.c:610
HeapTuple * vals
Definition: spi.h:26
SPIPlanPtr plan
Definition: plpgsql.h:222
#define ERROR
Definition: elog.h:43
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition: spi.c:1101
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
uintptr_t Datum
Definition: postgres.h:367
TupleDesc tupdesc
Definition: spi.h:25
#define SPI_OK_SELECT
Definition: spi.h:57
#define ereport(elevel,...)
Definition: elog.h:144
static int exec_run_select(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
Definition: pl_exec.c:5916
static bool exec_eval_simple_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, Datum *result, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:6151
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2715
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ exec_eval_integer()

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

Definition at line 5787 of file pl_exec.c.

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

Referenced by exec_assign_value(), and exec_stmt_fetch().

5790 {
5791  Datum exprdatum;
5792  Oid exprtypeid;
5793  int32 exprtypmod;
5794 
5795  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5796  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5797  exprtypeid, exprtypmod,
5798  INT4OID, -1);
5799  return DatumGetInt32(exprdatum);
5800 }
#define DatumGetInt32(X)
Definition: postgres.h:472
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:362
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7833
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5833
uintptr_t Datum
Definition: postgres.h:367

◆ exec_eval_simple_expr()

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

Definition at line 6151 of file pl_exec.c.

References Assert, CachedPlanAllowsSimpleValidityCheck(), CachedPlanIsSimplyValid(), CommandCounterIncrement(), CurrentResourceOwner, ExprContext::ecxt_param_list_info, EState::es_query_cxt, PLpgSQL_execstate::eval_econtext, exec_check_rw_parameter(), exec_save_simple_expr(), ExecEvalExpr(), ExecInitExprWithParams(), 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_expr::rwparam, PLpgSQL_execstate::simple_eval_estate, PLpgSQL_execstate::simple_eval_resowner, SPI_plan_get_cached_plan(), and unlikely.

Referenced by exec_eval_expr().

6157 {
6158  ExprContext *econtext = estate->eval_econtext;
6159  LocalTransactionId curlxid = MyProc->lxid;
6160  ParamListInfo paramLI;
6161  void *save_setup_arg;
6162  bool need_snapshot;
6163  MemoryContext oldcontext;
6164 
6165  /*
6166  * Forget it if expression wasn't simple before.
6167  */
6168  if (expr->expr_simple_expr == NULL)
6169  return false;
6170 
6171  /*
6172  * If expression is in use in current xact, don't touch it.
6173  */
6174  if (unlikely(expr->expr_simple_in_use) &&
6175  expr->expr_simple_lxid == curlxid)
6176  return false;
6177 
6178  /*
6179  * Check to see if the cached plan has been invalidated. If not, and this
6180  * is the first use in the current transaction, save a plan refcount in
6181  * the simple-expression resowner.
6182  */
6184  expr->expr_simple_plan,
6185  (expr->expr_simple_plan_lxid != curlxid ?
6186  estate->simple_eval_resowner : NULL))))
6187  {
6188  /*
6189  * It's still good, so just remember that we have a refcount on the
6190  * plan in the current transaction. (If we already had one, this
6191  * assignment is a no-op.)
6192  */
6193  expr->expr_simple_plan_lxid = curlxid;
6194  }
6195  else
6196  {
6197  /* Need to replan */
6198  CachedPlan *cplan;
6199 
6200  /*
6201  * If we have a valid refcount on some previous version of the plan,
6202  * release it, so we don't leak plans intra-transaction.
6203  */
6204  if (expr->expr_simple_plan_lxid == curlxid)
6205  {
6206  ResourceOwner saveResourceOwner = CurrentResourceOwner;
6207 
6209  ReleaseCachedPlan(expr->expr_simple_plan, true);
6210  CurrentResourceOwner = saveResourceOwner;
6211  expr->expr_simple_plan = NULL;
6213  }
6214 
6215  /* Do the replanning work in the eval_mcontext */
6216  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6217  cplan = SPI_plan_get_cached_plan(expr->plan);
6218  MemoryContextSwitchTo(oldcontext);
6219 
6220  /*
6221  * We can't get a failure here, because the number of
6222  * CachedPlanSources in the SPI plan can't change from what
6223  * exec_simple_check_plan saw; it's a property of the raw parsetree
6224  * generated from the query text.
6225  */
6226  Assert(cplan != NULL);
6227 
6228  /*
6229  * This test probably can't fail either, but if it does, cope by
6230  * declaring the plan to be non-simple. On success, we'll acquire a
6231  * refcount on the new plan, stored in simple_eval_resowner.
6232  */
6234  cplan,
6235  estate->simple_eval_resowner))
6236  {
6237  /* Remember that we have the refcount */
6238  expr->expr_simple_plan = cplan;
6239  expr->expr_simple_plan_lxid = curlxid;
6240  }
6241  else
6242  {
6243  /* Release SPI_plan_get_cached_plan's refcount */
6244  ReleaseCachedPlan(cplan, true);
6245  /* Mark expression as non-simple, and fail */
6246  expr->expr_simple_expr = NULL;
6247  return false;
6248  }
6249 
6250  /*
6251  * SPI_plan_get_cached_plan acquired a plan refcount stored in the
6252  * active resowner. We don't need that anymore, so release it.
6253  */
6254  ReleaseCachedPlan(cplan, true);
6255 
6256  /* Extract desired scalar expression from cached plan */
6257  exec_save_simple_expr(expr, cplan);
6258 
6259  /* better recheck r/w safety, as it could change due to inlining */
6260  if (expr->rwparam >= 0)
6261  exec_check_rw_parameter(expr, expr->rwparam);
6262  }
6263 
6264  /*
6265  * Pass back previously-determined result type.
6266  */
6267  *rettype = expr->expr_simple_type;
6268  *rettypmod = expr->expr_simple_typmod;
6269 
6270  /*
6271  * Set up ParamListInfo to pass to executor. For safety, save and restore
6272  * estate->paramLI->parserSetupArg around our use of the param list.
6273  */
6274  paramLI = estate->paramLI;
6275  save_setup_arg = paramLI->parserSetupArg;
6276 
6277  /*
6278  * We can skip using setup_param_list() in favor of just doing this
6279  * unconditionally, because there's no need for the optimization of
6280  * possibly setting ecxt_param_list_info to NULL; we've already forced use
6281  * of a generic plan.
6282  */
6283  paramLI->parserSetupArg = (void *) expr;
6284  econtext->ecxt_param_list_info = paramLI;
6285 
6286  /*
6287  * Prepare the expression for execution, if it's not been done already in
6288  * the current transaction. (This will be forced to happen if we called
6289  * exec_save_simple_expr above.)
6290  */
6291  if (unlikely(expr->expr_simple_lxid != curlxid))
6292  {
6293  oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
6294  expr->expr_simple_state =
6296  econtext->ecxt_param_list_info);
6297  expr->expr_simple_in_use = false;
6298  expr->expr_simple_lxid = curlxid;
6299  MemoryContextSwitchTo(oldcontext);
6300  }
6301 
6302  /*
6303  * We have to do some of the things SPI_execute_plan would do, in
6304  * particular push a new snapshot so that stable functions within the
6305  * expression can see updates made so far by our own function. However,
6306  * we can skip doing that (and just invoke the expression with the same
6307  * snapshot passed to our function) in some cases, which is useful because
6308  * it's quite expensive relative to the cost of a simple expression. We
6309  * can skip it if the expression contains no stable or volatile functions;
6310  * immutable functions shouldn't need to see our updates. Also, if this
6311  * is a read-only function, we haven't made any updates so again it's okay
6312  * to skip.
6313  */
6314  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6315  need_snapshot = (expr->expr_simple_mutable && !estate->readonly_func);
6316  if (need_snapshot)
6317  {
6320  }
6321 
6322  /*
6323  * Mark expression as busy for the duration of the ExecEvalExpr call.
6324  */
6325  expr->expr_simple_in_use = true;
6326 
6327  /*
6328  * Finally we can call the executor to evaluate the expression
6329  */
6330  *result = ExecEvalExpr(expr->expr_simple_state,
6331  econtext,
6332  isNull);
6333 
6334  /* Assorted cleanup */
6335  expr->expr_simple_in_use = false;
6336 
6337  econtext->ecxt_param_list_info = NULL;
6338 
6339  paramLI->parserSetupArg = save_setup_arg;
6340 
6341  if (need_snapshot)
6343 
6344  MemoryContextSwitchTo(oldcontext);
6345 
6346  /*
6347  * That's it.
6348  */
6349  return true;
6350 }
#define likely(x)
Definition: c.h:205
void * parserSetupArg
Definition: params.h:117
static void exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno)
Definition: pl_exec.c:8267
ResourceOwner simple_eval_resowner
Definition: plpgsql.h:1096
PGPROC * MyProc
Definition: proc.c:67
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void PopActiveSnapshot(void)
Definition: snapmgr.c:814
bool CachedPlanIsSimplyValid(CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1424
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:306
static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
Definition: pl_exec.c:8179
SPIPlanPtr plan
Definition: plpgsql.h:222
CachedPlan * SPI_plan_get_cached_plan(SPIPlanPtr plan)
Definition: spi.c:1908
MemoryContext es_query_cxt
Definition: execnodes.h:555
ParamListInfo paramLI
Definition: plpgsql.h:1092
CachedPlanSource * expr_simple_plansource
Definition: plpgsql.h:244
EState * simple_eval_estate
Definition: plpgsql.h:1095
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:735
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:290
ExprState * ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
Definition: execExpr.c:160
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1264
Expr * expr_simple_expr
Definition: plpgsql.h:233
uint32 LocalTransactionId
Definition: c.h:522
bool CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1309
int rwparam
Definition: plpgsql.h:224
#define get_eval_mcontext(estate)
Definition: pl_exec.c:131
ExprState * expr_simple_state
Definition: plpgsql.h:254
bool expr_simple_mutable
Definition: plpgsql.h:236
CachedPlan * expr_simple_plan
Definition: plpgsql.h:245
void CommandCounterIncrement(void)
Definition: xact.c:1021
LocalTransactionId expr_simple_lxid
Definition: plpgsql.h:256
#define Assert(condition)
Definition: c.h:745
ExprContext * eval_econtext
Definition: plpgsql.h:1109
int32 expr_simple_typmod
Definition: plpgsql.h:235
#define InvalidLocalTransactionId
Definition: lock.h:68
#define unlikely(x)
Definition: c.h:206
LocalTransactionId expr_simple_plan_lxid
Definition: plpgsql.h:246
bool expr_simple_in_use
Definition: plpgsql.h:255
ParamListInfo ecxt_param_list_info
Definition: execnodes.h:238
Oid expr_simple_type
Definition: plpgsql.h:234
LocalTransactionId lxid
Definition: proc.h:112

◆ exec_eval_using_params()

static ParamListInfo exec_eval_using_params ( PLpgSQL_execstate estate,
List params 
)
static

Definition at line 8641 of file pl_exec.c.

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

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

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

◆ exec_for_query()

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

Definition at line 5980 of file pl_exec.c.

References PLpgSQL_execstate::atomic, PLpgSQL_stmt_forq::body, compatible_tupdescs(), PLpgSQL_execstate::datums, PLpgSQL_variable::dno, PLpgSQL_variable::dtype, ExpandedRecordHeader::er_tupdesc_id, PLpgSQL_rec::erh, exec_eval_cleanup(), exec_move_row(), exec_set_found(), exec_stmts(), expanded_record_get_tupdesc(), expanded_record_set_tuple(), i, INVALID_TUPLEDESC_IDENTIFIER, PLpgSQL_stmt_forq::label, LOOP_RC_PROCESSING, PinPortal(), PLPGSQL_DTYPE_REC, PLPGSQL_RC_OK, PLpgSQL_rec::rectypeid, SPI_cursor_fetch(), SPI_freetuptable(), SPI_processed, SPI_tuptable, TupleDescData::tdtypeid, SPITupleTable::tupdesc, UnpinPortal(), SPITupleTable::vals, and PLpgSQL_stmt_forq::var.

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

5982 {
5983  PLpgSQL_variable *var;
5984  SPITupleTable *tuptab;
5985  bool found = false;
5986  int rc = PLPGSQL_RC_OK;
5987  uint64 previous_id = INVALID_TUPLEDESC_IDENTIFIER;
5988  bool tupdescs_match = true;
5989  uint64 n;
5990 
5991  /* Fetch loop variable's datum entry */
5992  var = (PLpgSQL_variable *) estate->datums[stmt->var->dno];
5993 
5994  /*
5995  * Make sure the portal doesn't get closed by the user statements we
5996  * execute.
5997  */
5998  PinPortal(portal);
5999 
6000  /*
6001  * Fetch the initial tuple(s). If prefetching is allowed then we grab a
6002  * few more rows to avoid multiple trips through executor startup
6003  * overhead.
6004  */
6005  SPI_cursor_fetch(portal, true, prefetch_ok ? 10 : 1);
6006  tuptab = SPI_tuptable;
6007  n = SPI_processed;
6008 
6009  /*
6010  * If the query didn't return any rows, set the target to NULL and fall
6011  * through with found = false.
6012  */
6013  if (n == 0)
6014  {
6015  exec_move_row(estate, var, NULL, tuptab->tupdesc);
6016  exec_eval_cleanup(estate);
6017  }
6018  else
6019  found = true; /* processed at least one tuple */
6020 
6021  /*
6022  * Now do the loop
6023  */
6024  while (n > 0)
6025  {
6026  uint64 i;
6027 
6028  for (i = 0; i < n; i++)
6029  {
6030  /*
6031  * Assign the tuple to the target. Here, because we know that all
6032  * loop iterations should be assigning the same tupdesc, we can
6033  * optimize away repeated creations of expanded records with
6034  * identical tupdescs. Testing for changes of er_tupdesc_id is
6035  * reliable even if the loop body contains assignments that
6036  * replace the target's value entirely, because it's assigned from
6037  * a process-global counter. The case where the tupdescs don't
6038  * match could possibly be handled more efficiently than this
6039  * coding does, but it's not clear extra effort is worthwhile.
6040  */
6041  if (var->dtype == PLPGSQL_DTYPE_REC)
6042  {
6043  PLpgSQL_rec *rec = (PLpgSQL_rec *) var;
6044 
6045  if (rec->erh &&
6046  rec->erh->er_tupdesc_id == previous_id &&
6047  tupdescs_match)
6048  {
6049  /* Only need to assign a new tuple value */
6050  expanded_record_set_tuple(rec->erh, tuptab->vals[i],
6051  true, !estate->atomic);
6052  }
6053  else
6054  {
6055  /*
6056  * First time through, or var's tupdesc changed in loop,
6057  * or we have to do it the hard way because type coercion
6058  * is needed.
6059  */
6060  exec_move_row(estate, var,
6061  tuptab->vals[i], tuptab->tupdesc);
6062 
6063  /*
6064  * Check to see if physical assignment is OK next time.
6065  * Once the tupdesc comparison has failed once, we don't
6066  * bother rechecking in subsequent loop iterations.
6067  */
6068  if (tupdescs_match)
6069  {
6070  tupdescs_match =
6071  (rec->rectypeid == RECORDOID ||
6072  rec->rectypeid == tuptab->tupdesc->tdtypeid ||
6073  compatible_tupdescs(tuptab->tupdesc,
6075  }
6076  previous_id = rec->erh->er_tupdesc_id;
6077  }
6078  }
6079  else
6080  exec_move_row(estate, var, tuptab->vals[i], tuptab->tupdesc);
6081 
6082  exec_eval_cleanup(estate);
6083 
6084  /*
6085  * Execute the statements
6086  */
6087  rc = exec_stmts(estate, stmt->body);
6088 
6089  LOOP_RC_PROCESSING(stmt->label, goto loop_exit);
6090  }
6091 
6092  SPI_freetuptable(tuptab);
6093 
6094  /*
6095  * Fetch more tuples. If prefetching is allowed, grab 50 at a time.
6096  */
6097  SPI_cursor_fetch(portal, true, prefetch_ok ? 50 : 1);
6098  tuptab = SPI_tuptable;
6099  n = SPI_processed;
6100  }
6101 
6102 loop_exit:
6103 
6104  /*
6105  * Release last group of tuples (if any)
6106  */
6107  SPI_freetuptable(tuptab);
6108 
6109  UnpinPortal(portal);
6110 
6111  /*
6112  * Set the FOUND variable to indicate the result of executing the loop
6113  * (namely, whether we looped one or more times). This must be set last so
6114  * that it does not interfere with the value of the FOUND variable inside
6115  * the loop processing itself.
6116  */
6117  exec_set_found(estate, found);
6118 
6119  return rc;
6120 }
void UnpinPortal(Portal portal)
Definition: portalmem.c:379
void expanded_record_set_tuple(ExpandedRecordHeader *erh, HeapTuple tuple, bool copy, bool expand_external)
SPITupleTable * SPI_tuptable
Definition: spi.c:46
ExpandedRecordHeader * erh
Definition: plpgsql.h:404
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4098
HeapTuple * vals
Definition: spi.h:26
#define INVALID_TUPLEDESC_IDENTIFIER
Definition: typcache.h:148
uint64 SPI_processed
Definition: spi.c:45
PLpgSQL_datum ** datums
Definition: plpgsql.h:1082
void PinPortal(Portal portal)
Definition: portalmem.c:370
#define LOOP_RC_PROCESSING(looplabel, exit_action)
Definition: pl_exec.c:198
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1235
static bool compatible_tupdescs(TupleDesc src_tupdesc, TupleDesc dst_tupdesc)
Definition: pl_exec.c:7406
TupleDesc tupdesc
Definition: spi.h:25
PLpgSQL_datum_type dtype
Definition: plpgsql.h:279
PLpgSQL_variable * var
Definition: plpgsql.h:717
static void exec_set_found(PLpgSQL_execstate *estate, bool state)
Definition: pl_exec.c:8366
Oid tdtypeid
Definition: tupdesc.h:82
static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
Definition: pl_exec.c:6862
int i
void SPI_cursor_fetch(Portal portal, bool forward, long count)
Definition: spi.c:1649
Oid rectypeid
Definition: plpgsql.h:397
static int exec_stmts(PLpgSQL_execstate *estate, List *stmts)
Definition: pl_exec.c:1947

◆ exec_init_tuple_store()

static void exec_init_tuple_store ( PLpgSQL_execstate estate)
static

Definition at line 3642 of file pl_exec.c.

References ReturnSetInfo::allowedModes, CurrentResourceOwner, ereport, errcode(), errmsg(), ERROR, ReturnSetInfo::expectedDesc, IsA, MemoryContextSwitchTo(), PLpgSQL_execstate::rsi, SFRM_Materialize, SFRM_Materialize_Random, PLpgSQL_execstate::tuple_store, PLpgSQL_execstate::tuple_store_cxt, PLpgSQL_execstate::tuple_store_desc, PLpgSQL_execstate::tuple_store_owner, tuplestore_begin_heap(), and work_mem.

Referenced by exec_stmt_return_next(), and exec_stmt_return_query().

3643 {
3644  ReturnSetInfo *rsi = estate->rsi;
3645  MemoryContext oldcxt;
3646  ResourceOwner oldowner;
3647 
3648  /*
3649  * Check caller can handle a set result in the way we want
3650  */
3651  if (!rsi || !IsA(rsi, ReturnSetInfo) ||
3652  (rsi->allowedModes & SFRM_Materialize) == 0 ||
3653  rsi->expectedDesc == NULL)
3654  ereport(ERROR,
3655  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3656  errmsg("set-valued function called in context that cannot accept a set")));
3657 
3658  /*
3659  * Switch to the right memory context and resource owner for storing the
3660  * tuplestore for return set. If we're within a subtransaction opened for
3661  * an exception-block, for example, we must still create the tuplestore in
3662  * the resource owner that was active when this function was entered, and
3663  * not in the subtransaction resource owner.
3664  */
3665  oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
3666  oldowner = CurrentResourceOwner;
3668 
3669  estate->tuple_store =
3671  false, work_mem);
3672 
3673  CurrentResourceOwner = oldowner;
3674  MemoryContextSwitchTo(oldcxt);
3675 
3676  estate->tuple_store_desc = rsi->expectedDesc;
3677 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
ResourceOwner tuple_store_owner
Definition: plpgsql.h:1070
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:610
TupleDesc expectedDesc
Definition: execnodes.h:304
TupleDesc tuple_store_desc
Definition: plpgsql.h:1068
#define ERROR
Definition: elog.h:43
MemoryContext tuple_store_cxt
Definition: plpgsql.h:1069
ReturnSetInfo * rsi
Definition: plpgsql.h:1071
Tuplestorestate * tuple_store
Definition: plpgsql.h:1067
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
int work_mem
Definition: globals.c:121
#define ereport(elevel,...)
Definition: elog.h:144
int allowedModes
Definition: execnodes.h:305
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ exec_move_row()

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

Definition at line 6862 of file pl_exec.c.

References assign_record_var(), PLpgSQL_execstate::atomic, compatible_tupdescs(), PLpgSQL_rec::datatype, deconstruct_expanded_record(), DeleteExpandedObject(), PLpgSQL_variable::dtype, PLpgSQL_rec::erh, eval_mcontext_alloc, exec_move_row_from_fields(), expanded_record_get_tupdesc(), expanded_record_set_tuple(), ExpandedRecordGetDatum, heap_deform_tuple(), HeapTupleIsValid, lengthof, make_expanded_record_for_rec(), TupleDescData::natts, PLPGSQL_DTYPE_REC, PLpgSQL_rec::rectypeid, TupleDescData::tdtypeid, PLpgSQL_type::typtype, and values.

Referenced by exec_assign_value(), exec_for_query(), exec_move_row_from_datum(), exec_stmt_block(), exec_stmt_call(), exec_stmt_dynexecute(), exec_stmt_execsql(), exec_stmt_fetch(), and plpgsql_exec_function().

6865 {
6866  ExpandedRecordHeader *newerh = NULL;
6867 
6868  /*
6869  * If target is RECORD, we may be able to avoid field-by-field processing.
6870  */
6871  if (target->dtype == PLPGSQL_DTYPE_REC)
6872  {
6873  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
6874 
6875  /*
6876  * If we have no source tupdesc, just set the record variable to NULL.
6877  * (If we have a source tupdesc but not a tuple, we'll set the
6878  * variable to a row of nulls, instead. This is odd perhaps, but
6879  * backwards compatible.)
6880  */
6881  if (tupdesc == NULL)
6882  {
6883  if (rec->datatype &&
6884  rec->datatype->typtype == TYPTYPE_DOMAIN)
6885  {
6886  /*
6887  * If it's a composite domain, NULL might not be a legal
6888  * value, so we instead need to make an empty expanded record
6889  * and ensure that domain type checking gets done. If there
6890  * is already an expanded record, piggyback on its lookups.
6891  */
6892  newerh = make_expanded_record_for_rec(estate, rec,
6893  NULL, rec->erh);
6894  expanded_record_set_tuple(newerh, NULL, false, false);
6895  assign_record_var(estate, rec, newerh);
6896  }
6897  else
6898  {
6899  /* Just clear it to NULL */
6900  if (rec->erh)
6902  rec->erh = NULL;
6903  }
6904  return;
6905  }
6906 
6907  /*
6908  * Build a new expanded record with appropriate tupdesc.
6909  */
6910  newerh = make_expanded_record_for_rec(estate, rec, tupdesc, NULL);
6911 
6912  /*
6913  * If the rowtypes match, or if we have no tuple anyway, we can
6914  * complete the assignment without field-by-field processing.
6915  *
6916  * The tests here are ordered more or less in order of cheapness. We
6917  * can easily detect it will work if the target is declared RECORD or
6918  * has the same typeid as the source. But when assigning from a query
6919  * result, it's common to have a source tupdesc that's labeled RECORD
6920  * but is actually physically compatible with a named-composite-type
6921  * target, so it's worth spending extra cycles to check for that.
6922  */
6923  if (rec->rectypeid == RECORDOID ||
6924  rec->rectypeid == tupdesc->tdtypeid ||
6925  !HeapTupleIsValid(tup) ||
6927  {
6928  if (!HeapTupleIsValid(tup))
6929  {
6930  /* No data, so force the record into all-nulls state */
6932  }
6933  else
6934  {
6935  /* No coercion is needed, so just assign the row value */
6936  expanded_record_set_tuple(newerh, tup, true, !estate->atomic);
6937  }
6938 
6939  /* Complete the assignment */
6940  assign_record_var(estate, rec, newerh);
6941 
6942  return;
6943  }
6944  }
6945 
6946  /*
6947  * Otherwise, deconstruct the tuple and do field-by-field assignment,
6948  * using exec_move_row_from_fields.
6949  */
6950  if (tupdesc && HeapTupleIsValid(tup))
6951  {
6952  int td_natts = tupdesc->natts;
6953  Datum *values;
6954  bool *nulls;
6955  Datum values_local[64];
6956  bool nulls_local[64];
6957 
6958  /*
6959  * Need workspace arrays. If td_natts is small enough, use local
6960  * arrays to save doing a palloc. Even if it's not small, we can
6961  * allocate both the Datum and isnull arrays in one palloc chunk.
6962  */
6963  if (td_natts <= lengthof(values_local))
6964  {
6965  values = values_local;
6966  nulls = nulls_local;
6967  }
6968  else
6969  {
6970  char *chunk;
6971 
6972  chunk = eval_mcontext_alloc(estate,
6973  td_natts * (sizeof(Datum) + sizeof(bool)));
6974  values = (Datum *) chunk;
6975  nulls = (bool *) (chunk + td_natts * sizeof(Datum));
6976  }
6977 
6978  heap_deform_tuple(tup, tupdesc, values, nulls);
6979 
6980  exec_move_row_from_fields(estate, target, newerh,
6981  values, nulls, tupdesc);
6982  }
6983  else
6984  {
6985  /*
6986  * Assign all-nulls.
6987  */
6988  exec_move_row_from_fields(estate, target, newerh,
6989  NULL, NULL, NULL);
6990  }
6991 }
PLpgSQL_type * datatype
Definition: plpgsql.h:396
static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
Definition: pl_exec.c:8618
void expanded_record_set_tuple(ExpandedRecordHeader *erh, HeapTuple tuple, bool copy, bool expand_external)
ExpandedRecordHeader * erh
Definition: plpgsql.h:404
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:7140
#define lengthof(array)
Definition: c.h:675
static ExpandedRecordHeader * make_expanded_record_for_rec(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, TupleDesc srctupdesc, ExpandedRecordHeader *srcerh)
Definition: pl_exec.c:7077
#define eval_mcontext_alloc(estate, sz)
Definition: pl_exec.c:133
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
uintptr_t Datum
Definition: postgres.h:367
static bool compatible_tupdescs(TupleDesc src_tupdesc, TupleDesc dst_tupdesc)
Definition: pl_exec.c:7406
void DeleteExpandedObject(Datum d)
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
PLpgSQL_datum_type dtype
Definition: plpgsql.h:279
char typtype
Definition: plpgsql.h:206
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1249
static Datum values[MAXATTR]
Definition: bootstrap.c:167
Oid tdtypeid
Definition: tupdesc.h:82
Oid rectypeid
Definition: plpgsql.h:397
#define ExpandedRecordGetDatum(erh)
void deconstruct_expanded_record(ExpandedRecordHeader *erh)

◆ exec_move_row_from_datum()

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

Definition at line 7536 of file pl_exec.c.

References Assert, assign_record_var(), PLpgSQL_execstate::atomic, DatumGetEOHP(), DatumGetHeapTupleHeader, DatumGetPointer, deconstruct_expanded_record(), ExpandedRecordHeader::dnulls, PLpgSQL_variable::dtype, ExpandedRecordHeader::dvalues, ExpandedRecordHeader::er_decltypeid, ER_FLAG_FVALUE_VALID, ER_MAGIC, ExpandedRecordHeader::er_magic, ExpandedRecordHeader::er_typeid, ExpandedRecordHeader::er_typmod, PLpgSQL_rec::erh, exec_move_row(), exec_move_row_from_fields(), expanded_record_get_tupdesc(), expanded_record_set_tuple(), ExpandedRecordIsDomain, ExpandedRecordIsEmpty, ExpandedRecordHeader::flags, ExpandedRecordHeader::fvalue, get_eval_mcontext, HeapTupleHeaderGetDatumLength, HeapTupleHeaderGetTypeId, HeapTupleHeaderGetTypMod, InvalidOid, ItemPointerSetInvalid, lookup_rowtype_tupdesc(), make_expanded_record_for_rec(), make_expanded_record_from_typeid(), MemoryContextSwitchTo(), PLPGSQL_DTYPE_REC, PLpgSQL_rec::rectypeid, ReleaseTupleDesc, revalidate_rectypeid(), HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, VARATT_IS_EXTERNAL_EXPANDED, and VARATT_IS_EXTERNAL_EXPANDED_RW.

Referenced by exec_assign_value(), and plpgsql_exec_function().

7539 {
7540  /* Check to see if source is an expanded record */
7542  {
7544  ExpandedRecordHeader *newerh = NULL;
7545 
7546  Assert(erh->er_magic == ER_MAGIC);
7547 
7548  /* These cases apply if the target is record not row... */
7549  if (target->dtype == PLPGSQL_DTYPE_REC)
7550  {
7551  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7552 
7553  /*
7554  * If it's the same record already stored in the variable, do
7555  * nothing. This would happen only in silly cases like "r := r",
7556  * but we need some check to avoid possibly freeing the variable's
7557  * live value below. Note that this applies even if what we have
7558  * is a R/O pointer.
7559  */
7560  if (erh == rec->erh)
7561  return;
7562 
7563  /*
7564  * Make sure rec->rectypeid is up-to-date before using it.
7565  */
7566  revalidate_rectypeid(rec);
7567 
7568  /*
7569  * If we have a R/W pointer, we're allowed to just commandeer
7570  * ownership of the expanded record. If it's of the right type to
7571  * put into the record variable, do that. (Note we don't accept
7572  * an expanded record of a composite-domain type as a RECORD
7573  * value. We'll treat it as the base composite type instead;
7574  * compare logic in make_expanded_record_for_rec.)
7575  */
7577  (rec->rectypeid == erh->er_decltypeid ||
7578  (rec->rectypeid == RECORDOID &&
7579  !ExpandedRecordIsDomain(erh))))
7580  {
7581  assign_record_var(estate, rec, erh);
7582  return;
7583  }
7584 
7585  /*
7586  * If we already have an expanded record object in the target
7587  * variable, and the source record contains a valid tuple
7588  * representation with the right rowtype, then we can skip making
7589  * a new expanded record and just assign the tuple with
7590  * expanded_record_set_tuple. (We can't do the equivalent if we
7591  * have to do field-by-field assignment, since that wouldn't be
7592  * atomic if there's an error.) We consider that there's a
7593  * rowtype match only if it's the same named composite type or
7594  * same registered rowtype; checking for matches of anonymous
7595  * rowtypes would be more expensive than this is worth.
7596  */
7597  if (rec->erh &&
7598  (erh->flags & ER_FLAG_FVALUE_VALID) &&
7599  erh->er_typeid == rec->erh->er_typeid &&
7600  (erh->er_typeid != RECORDOID ||
7601  (erh->er_typmod == rec->erh->er_typmod &&
7602  erh->er_typmod >= 0)))
7603  {
7605  true, !estate->atomic);
7606  return;
7607  }
7608 
7609  /*
7610  * Otherwise we're gonna need a new expanded record object. Make
7611  * it here in hopes of piggybacking on the source object's
7612  * previous typcache lookup.
7613  */
7614  newerh = make_expanded_record_for_rec(estate, rec, NULL, erh);
7615 
7616  /*
7617  * If the expanded record contains a valid tuple representation,
7618  * and we don't need rowtype conversion, then just copying the
7619  * tuple is probably faster than field-by-field processing. (This
7620  * isn't duplicative of the previous check, since here we will
7621  * catch the case where the record variable was previously empty.)
7622  */
7623  if ((erh->flags & ER_FLAG_FVALUE_VALID) &&
7624  (rec->rectypeid == RECORDOID ||
7625  rec->rectypeid == erh->er_typeid))
7626  {
7627  expanded_record_set_tuple(newerh, erh->fvalue,
7628  true, !estate->atomic);
7629  assign_record_var(estate, rec, newerh);
7630  return;
7631  }
7632 
7633  /*
7634  * Need to special-case empty source record, else code below would
7635  * leak newerh.
7636  */
7637  if (ExpandedRecordIsEmpty(erh))
7638  {
7639  /* Set newerh to a row of NULLs */
7641  assign_record_var(estate, rec, newerh);
7642  return;
7643  }
7644  } /* end of record-target-only cases */
7645 
7646  /*
7647  * If the source expanded record is empty, we should treat that like a
7648  * NULL tuple value. (We're unlikely to see such a case, but we must
7649  * check this; deconstruct_expanded_record would cause a change of
7650  * logical state, which is not OK.)
7651  */
7652  if (ExpandedRecordIsEmpty(erh))
7653  {
7654  exec_move_row(estate, target, NULL,
7656  return;
7657  }
7658 
7659  /*
7660  * Otherwise, ensure that the source record is deconstructed, and
7661  * assign from its field values.
7662  */
7664  exec_move_row_from_fields(estate, target, newerh,
7665  erh->dvalues, erh->dnulls,
7667  }
7668  else
7669  {
7670  /*
7671  * Nope, we've got a plain composite Datum. Deconstruct it; but we
7672  * don't use deconstruct_composite_datum(), because we may be able to
7673  * skip calling lookup_rowtype_tupdesc().
7674  */
7675  HeapTupleHeader td;
7676  HeapTupleData tmptup;
7677  Oid tupType;
7678  int32 tupTypmod;
7679  TupleDesc tupdesc;
7680  MemoryContext oldcontext;
7681 
7682  /* Ensure that any detoasted data winds up in the eval_mcontext */
7683  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7684  /* Get tuple body (note this could involve detoasting) */
7686  MemoryContextSwitchTo(oldcontext);
7687 
7688  /* Build a temporary HeapTuple control structure */
7689  tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
7690  ItemPointerSetInvalid(&(tmptup.t_self));
7691  tmptup.t_tableOid = InvalidOid;
7692  tmptup.t_data = td;
7693 
7694  /* Extract rowtype info */
7695  tupType = HeapTupleHeaderGetTypeId(td);
7696  tupTypmod = HeapTupleHeaderGetTypMod(td);
7697 
7698  /* Now, if the target is record not row, maybe we can optimize ... */
7699  if (target->dtype == PLPGSQL_DTYPE_REC)
7700  {
7701  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7702 
7703  /*
7704  * If we already have an expanded record object in the target
7705  * variable, and the source datum has a matching rowtype, then we
7706  * can skip making a new expanded record and just assign the tuple
7707  * with expanded_record_set_tuple. We consider that there's a
7708  * rowtype match only if it's the same named composite type or
7709  * same registered rowtype. (Checking to reject an anonymous
7710  * rowtype here should be redundant, but let's be safe.)
7711  */
7712  if (rec->erh &&
7713  tupType == rec->erh->er_typeid &&
7714  (tupType != RECORDOID ||
7715  (tupTypmod == rec->erh->er_typmod &&
7716  tupTypmod >= 0)))
7717  {
7718  expanded_record_set_tuple(rec->erh, &tmptup,
7719  true, !estate->atomic);
7720  return;
7721  }
7722 
7723  /*
7724  * If the source datum has a rowtype compatible with the target
7725  * variable, just build a new expanded record and assign the tuple
7726  * into it. Using make_expanded_record_from_typeid() here saves
7727  * one typcache lookup compared to the code below.
7728  */
7729  if (rec->rectypeid == RECORDOID || rec->rectypeid == tupType)
7730  {
7731  ExpandedRecordHeader *newerh;
7732  MemoryContext mcontext = get_eval_mcontext(estate);
7733 
7734  newerh = make_expanded_record_from_typeid(tupType, tupTypmod,
7735  mcontext);
7736  expanded_record_set_tuple(newerh, &tmptup,
7737  true, !estate->atomic);
7738  assign_record_var(estate, rec, newerh);
7739  return;
7740  }
7741 
7742  /*
7743  * Otherwise, we're going to need conversion, so fall through to
7744  * do it the hard way.
7745  */
7746  }
7747 
7748  /*
7749  * ROW target, or unoptimizable RECORD target, so we have to expend a
7750  * lookup to obtain the source datum's tupdesc.
7751  */
7752  tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
7753 
7754  /* Do the move */
7755  exec_move_row(estate, target, &tmptup, tupdesc);
7756 
7757  /* Release tupdesc usage count */
7758  ReleaseTupleDesc(tupdesc);
7759  }
7760 }
#define ER_FLAG_FVALUE_VALID
ExpandedRecordHeader * make_expanded_record_from_typeid(Oid type_id, int32 typmod, MemoryContext parentcontext)
#define ExpandedRecordIsEmpty(erh)
#define VARATT_IS_EXTERNAL_EXPANDED(PTR)
Definition: postgres.h:322
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1710
static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
Definition: pl_exec.c:8618
void expanded_record_set_tuple(ExpandedRecordHeader *erh, HeapTuple tuple, bool copy, bool expand_external)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
ExpandedRecordHeader * erh
Definition: plpgsql.h:404
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:7140
unsigned int Oid
Definition: postgres_ext.h:31
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:294
signed int int32
Definition: c.h:362
HeapTupleHeader t_data
Definition: htup.h:68
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:468
static ExpandedRecordHeader * make_expanded_record_for_rec(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, TupleDesc srctupdesc, ExpandedRecordHeader *srcerh)
Definition: pl_exec.c:7077
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
Oid t_tableOid
Definition: htup.h:66
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29
#define get_eval_mcontext(estate)
Definition: pl_exec.c:131
#define ER_MAGIC
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:458
#define InvalidOid
Definition: postgres_ext.h:36
static struct @143 value
#define Assert(condition)
Definition: c.h:745
PLpgSQL_datum_type dtype
Definition: plpgsql.h:279
#define DatumGetPointer(X)
Definition: postgres.h:549
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
Definition: pl_exec.c:6862
static void revalidate_rectypeid(PLpgSQL_rec *rec)
Definition: pl_exec.c:6997
#define VARATT_IS_EXTERNAL_EXPANDED_RW(PTR)
Definition: postgres.h:320
Oid rectypeid
Definition: plpgsql.h:397
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:122
#define ExpandedRecordIsDomain(erh)
void deconstruct_expanded_record(ExpandedRecordHeader *erh)
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:452

◆ exec_move_row_from_fields()

static void exec_move_row_from_fields ( PLpgSQL_execstate estate,
PLpgSQL_variable target,
ExpandedRecordHeader newerh,
Datum values,
bool nulls,
TupleDesc  tupdesc 
)
static

Definition at line 7140 of file pl_exec.c.

References Assert, assign_record_var(), PLpgSQL_execstate::atomic, PLpgSQL_execstate::datums, PLpgSQL_variable::dtype, elog, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, eval_mcontext_alloc, exec_assign_value(), exec_cast_value(), expanded_record_get_tupdesc(), expanded_record_set_fields(), lengthof, TupleDescData::natts, PLpgSQL_row::nfields, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_ROW, plpgsql_extra_errors, plpgsql_extra_warnings, PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT, TupleDescAttr, value, PLpgSQL_row::varnos, and WARNING.

Referenced by exec_move_row(), and exec_move_row_from_datum().

7145 {
7146  int td_natts = tupdesc ? tupdesc->natts : 0;
7147  int fnum;
7148  int anum;
7149  int strict_multiassignment_level = 0;
7150 
7151  /*
7152  * The extra check strict strict_multi_assignment can be active, only when
7153  * input tupdesc is specified.
7154  */
7155  if (tupdesc != NULL)
7156  {
7158  strict_multiassignment_level = ERROR;
7159  else if (plpgsql_extra_warnings & PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT)
7160  strict_multiassignment_level = WARNING;
7161  }
7162 
7163  /* Handle RECORD-target case */
7164  if (target->dtype == PLPGSQL_DTYPE_REC)
7165  {
7166  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7167  TupleDesc var_tupdesc;
7168  Datum newvalues_local[64];
7169  bool newnulls_local[64];
7170 
7171  Assert(newerh != NULL); /* caller must have built new object */
7172 
7173  var_tupdesc = expanded_record_get_tupdesc(newerh);
7174 
7175  /*
7176  * Coerce field values if needed. This might involve dealing with
7177  * different sets of dropped columns and/or coercing individual column
7178  * types. That's sort of a pain, but historically plpgsql has allowed
7179  * it, so we preserve the behavior. However, it's worth a quick check
7180  * to see if the tupdescs are identical. (Since expandedrecord.c
7181  * prefers to use refcounted tupdescs from the typcache, expanded
7182  * records with the same rowtype will have pointer-equal tupdescs.)
7183  */
7184  if (var_tupdesc != tupdesc)
7185  {
7186  int vtd_natts = var_tupdesc->natts;
7187  Datum *newvalues;
7188  bool *newnulls;
7189 
7190  /*
7191  * Need workspace arrays. If vtd_natts is small enough, use local
7192  * arrays to save doing a palloc. Even if it's not small, we can
7193  * allocate both the Datum and isnull arrays in one palloc chunk.
7194  */
7195  if (vtd_natts <= lengthof(newvalues_local))
7196  {
7197  newvalues = newvalues_local;
7198  newnulls = newnulls_local;
7199  }
7200  else
7201  {
7202  char *chunk;
7203 
7204  chunk = eval_mcontext_alloc(estate,
7205  vtd_natts * (sizeof(Datum) + sizeof(bool)));
7206  newvalues = (Datum *) chunk;
7207  newnulls = (bool *) (chunk + vtd_natts * sizeof(Datum));
7208  }
7209 
7210  /* Walk over destination columns */
7211  anum = 0;
7212  for (fnum = 0; fnum < vtd_natts; fnum++)
7213  {
7214  Form_pg_attribute attr = TupleDescAttr(var_tupdesc, fnum);
7215  Datum value;
7216  bool isnull;
7217  Oid valtype;
7218  int32 valtypmod;
7219 
7220  if (attr->attisdropped)
7221  {
7222  /* expanded_record_set_fields should ignore this column */
7223  continue; /* skip dropped column in record */
7224  }
7225 
7226  while (anum < td_natts &&
7227  TupleDescAttr(tupdesc, anum)->attisdropped)
7228  anum++; /* skip dropped column in tuple */
7229 
7230  if (anum < td_natts)
7231  {
7232  value = values[anum];
7233  isnull = nulls[anum];
7234  valtype = TupleDescAttr(tupdesc, anum)->atttypid;
7235  valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
7236  anum++;
7237  }
7238  else
7239  {
7240  /* no source for destination column */
7241  value = (Datum) 0;
7242  isnull = true;
7243  valtype = UNKNOWNOID;
7244  valtypmod = -1;
7245 
7246  /* When source value is missing */
7247  if (strict_multiassignment_level)
7248  ereport(strict_multiassignment_level,
7249  (errcode(ERRCODE_DATATYPE_MISMATCH),
7250  errmsg("number of source and target fields in assignment does not match"),
7251  /* translator: %s represents a name of an extra check */
7252  errdetail("%s check of %s is active.",
7253  "strict_multi_assignment",
7254  strict_multiassignment_level == ERROR ? "extra_errors" :
7255  "extra_warnings"),
7256  errhint("Make sure the query returns the exact list of columns.")));
7257  }
7258 
7259  /* Cast the new value to the right type, if needed. */
7260  newvalues[fnum] = exec_cast_value(estate,
7261  value,
7262  &isnull,
7263  valtype,
7264  valtypmod,
7265  attr->atttypid,
7266  attr->atttypmod);
7267  newnulls[fnum] = isnull;
7268  }
7269 
7270  /*
7271  * When strict_multiassignment extra check is active, then ensure
7272  * there are no unassigned source attributes.
7273  */
7274  if (strict_multiassignment_level && anum < td_natts)
7275  {
7276  /* skip dropped columns in the source descriptor */
7277  while (anum < td_natts &&
7278  TupleDescAttr(tupdesc, anum)->attisdropped)
7279  anum++;
7280 
7281  if (anum < td_natts)
7282  ereport(strict_multiassignment_level,
7283  (errcode(ERRCODE_DATATYPE_MISMATCH),
7284  errmsg("number of source and target fields in assignment does not match"),
7285  /* translator: %s represents a name of an extra check */
7286  errdetail("%s check of %s is active.",
7287  "strict_multi_assignment",
7288  strict_multiassignment_level == ERROR ? "extra_errors" :
7289  "extra_warnings"),
7290  errhint("Make sure the query returns the exact list of columns.")));
7291  }
7292 
7293  values = newvalues;
7294  nulls = newnulls;
7295  }
7296 
7297  /* Insert the coerced field values into the new expanded record */
7298  expanded_record_set_fields(newerh, values, nulls, !estate->atomic);
7299 
7300  /* Complete the assignment */
7301  assign_record_var(estate, rec, newerh);
7302 
7303  return;
7304  }
7305 
7306  /* newerh should not have been passed in non-RECORD cases */
7307  Assert(newerh == NULL);
7308 
7309  /*
7310  * For a row, we assign the individual field values to the variables the
7311  * row points to.
7312  *
7313  * NOTE: both this code and the record code above silently ignore extra
7314  * columns in the source and assume NULL for missing columns. This is
7315  * pretty dubious but it's the historical behavior.
7316  *
7317  * If we have no input data at all, we'll assign NULL to all columns of
7318  * the row variable.
7319  */
7320  if (target->dtype == PLPGSQL_DTYPE_ROW)
7321  {
7322  PLpgSQL_row *row = (PLpgSQL_row *) target;
7323 
7324  anum = 0;
7325  for (fnum = 0; fnum < row->nfields; fnum++)
7326  {
7327  PLpgSQL_var *var;
7328  Datum value;
7329  bool isnull;
7330  Oid valtype;
7331  int32 valtypmod;
7332 
7333  var = (PLpgSQL_var *) (estate->datums[row->varnos[fnum]]);
7334 
7335  while (anum < td_natts &&
7336  TupleDescAttr(tupdesc, anum)->attisdropped)
7337  anum++; /* skip dropped column in tuple */
7338 
7339  if (anum < td_natts)
7340  {
7341  value = values[anum];
7342  isnull = nulls[anum];
7343  valtype = TupleDescAttr(tupdesc, anum)->atttypid;
7344  valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
7345  anum++;
7346  }
7347  else
7348  {
7349  /* no source for destination column */
7350  value = (Datum) 0;
7351  isnull = true;
7352  valtype = UNKNOWNOID;
7353  valtypmod = -1;
7354 
7355  if (strict_multiassignment_level)
7356  ereport(strict_multiassignment_level,
7357  (errcode(ERRCODE_DATATYPE_MISMATCH),
7358  errmsg("number of source and target fields in assignment does not match"),
7359  /* translator: %s represents a name of an extra check */
7360  errdetail("%s check of %s is active.",
7361  "strict_multi_assignment",
7362  strict_multiassignment_level == ERROR ? "extra_errors" :
7363  "extra_warnings"),
7364  errhint("Make sure the query returns the exact list of columns.")));
7365  }
7366 
7367  exec_assign_value(estate, (PLpgSQL_datum *) var,
7368  value, isnull, valtype, valtypmod);
7369  }
7370 
7371  /*
7372  * When strict_multiassignment extra check is active, ensure there are
7373  * no unassigned source attributes.
7374  */
7375  if (strict_multiassignment_level && anum < td_natts)
7376  {
7377  while (anum < td_natts &&
7378  TupleDescAttr(tupdesc, anum)->attisdropped)
7379  anum++; /* skip dropped column in tuple */
7380 
7381  if (anum < td_natts)
7382  ereport(strict_multiassignment_level,
7383  (errcode(ERRCODE_DATATYPE_MISMATCH),
7384  errmsg("number of source and target fields in assignment does not match"),
7385  /* translator: %s represents a name of an extra check */
7386  errdetail("%s check of %s is active.",
7387  "strict_multi_assignment",
7388  strict_multiassignment_level == ERROR ? "extra_errors" :
7389  "extra_warnings"),
7390  errhint("Make sure the query returns the exact list of columns.")));
7391  }
7392 
7393  return;
7394  }
7395 
7396  elog(ERROR, "unsupported target type: %d", target->dtype);
7397 }
int errhint(const char *fmt,...)
Definition: elog.c:1071
static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
Definition: pl_exec.c:8618
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT
Definition: plpgsql.h:1209
int plpgsql_extra_errors
Definition: pl_handler.c:53
int errcode(int sqlerrcode)
Definition: elog.c:610
void expanded_record_set_fields(ExpandedRecordHeader *erh, const Datum *newValues, const bool *isnulls, bool expand_external)
#define lengthof(array)
Definition: c.h:675
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:362
PLpgSQL_datum ** datums
Definition: plpgsql.h:1082
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7833
#define ERROR
Definition: elog.h:43
#define eval_mcontext_alloc(estate, sz)
Definition: pl_exec.c:133
int plpgsql_extra_warnings
Definition: pl_handler.c:52
int errdetail(const char *fmt,...)
Definition: elog.c:957
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
int * varnos
Definition: plpgsql.h:373
#define WARNING
Definition: elog.h:40
uintptr_t Datum
Definition: postgres.h:367
static struct @143 value
#define ereport(elevel,...)
Definition: elog.h:144
#define Assert(condition)
Definition: c.h:745
int nfields
Definition: plpgsql.h:371
PLpgSQL_datum_type dtype
Definition: plpgsql.h:279
static Datum values[MAXATTR]
Definition: bootstrap.c:167
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:5037

◆ exec_prepare_plan()

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

Definition at line 4119 of file pl_exec.c.

References elog, ERROR, exec_simple_check_plan(), PLpgSQL_expr::func, PLpgSQL_execstate::func, plpgsql_parser_setup(), PLpgSQL_expr::query, SPI_keepplan(), SPI_prepare_params(), SPI_result, and SPI_result_code_string().

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

4122 {
4123  SPIPlanPtr plan;
4124 
4125  /*
4126  * The grammar can't conveniently set expr->func while building the parse
4127  * tree, so make sure it's set before parser hooks need it.
4128  */
4129  expr->func = estate->func;
4130 
4131  /*
4132  * Generate and save the plan
4133  */
4134  plan = SPI_prepare_params(expr->query,
4136  (void *) expr,
4137  cursorOptions);
4138  if (plan == NULL)
4139  elog(ERROR, "SPI_prepare_params failed for \"%s\": %s",
4141  if (keepplan)
4142  SPI_keepplan(plan);
4143  expr->plan = plan;
4144 
4145  /* Check to see if it's a simple expression */
4146  exec_simple_check_plan(estate, expr);
4147 
4148  /*
4149  * Mark expression as not using a read-write param. exec_assign_value has
4150  * to take steps to override this if appropriate; that seems cleaner than
4151  * adding parameters to all other callers.
4152  */
4153  expr->rwparam = -1;
4154 }
char * query
Definition: plpgsql.h:221
PLpgSQL_function * func
Definition: plpgsql.h:1047
static void exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:8062
SPIPlanPtr plan
Definition: plpgsql.h:222
int SPI_result
Definition: spi.c:47
#define ERROR
Definition: elog.h:43
const char * SPI_result_code_string(int code)
Definition: spi.c:1815
void(* ParserSetupHook)(struct ParseState *pstate, void *arg)
Definition: params.h:108
void plpgsql_parser_setup(struct ParseState *pstate, PLpgSQL_expr *expr)
Definition: pl_comp.c:1074
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:825
int rwparam
Definition: plpgsql.h:224
struct PLpgSQL_function * func
Definition: plpgsql.h:227
#define elog(elevel,...)
Definition: elog.h:214
SPIPlanPtr SPI_prepare_params(const char *src, ParserSetupHook parserSetup, void *parserSetupArg, int cursorOptions)
Definition: spi.c:788

◆ exec_run_select()

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

Definition at line 5916 of file pl_exec.c.

References Assert, CURSOR_OPT_PARALLEL_OK, elog, ereport, errcode(), errmsg(), ERROR, PLpgSQL_execstate::eval_processed, PLpgSQL_execstate::eval_tuptable, exec_eval_cleanup(), exec_prepare_plan(), PLpgSQL_expr::plan, PLpgSQL_expr::query, PLpgSQL_execstate::readonly_func, setup_param_list(), SPI_cursor_open_with_paramlist(), SPI_execute_plan_with_paramlist(), SPI_OK_CURSOR, SPI_OK_SELECT, SPI_processed, SPI_result, SPI_result_code_string(), and SPI_tuptable.

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

5918 {
5919  ParamListInfo paramLI;
5920  int rc;
5921 
5922  /*
5923  * On the first call for this expression generate the plan.
5924  *
5925  * If we don't need to return a portal, then we're just going to execute
5926  * the query once, which means it's OK to use a parallel plan, even if the
5927  * number of rows being fetched is limited. If we do need to return a
5928  * portal, the caller might do cursor operations, which parallel query
5929  * can't support.
5930  */
5931  if (expr->plan == NULL)
5932  exec_prepare_plan(estate, expr,
5933  portalP == NULL ? CURSOR_OPT_PARALLEL_OK : 0, true);
5934 
5935  /*
5936  * Set up ParamListInfo to pass to executor
5937  */
5938  paramLI = setup_param_list(estate, expr);
5939 
5940  /*
5941  * If a portal was requested, put the query and paramlist into the portal
5942  */
5943  if (portalP != NULL)
5944  {
5945  *portalP = SPI_cursor_open_with_paramlist(NULL, expr->plan,
5946  paramLI,
5947  estate->readonly_func);
5948  if (*portalP == NULL)
5949  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
5951  exec_eval_cleanup(estate);
5952  return SPI_OK_CURSOR;
5953  }
5954 
5955  /*
5956  * Execute the query
5957  */
5958  rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
5959  estate->readonly_func, maxtuples);
5960  if (rc != SPI_OK_SELECT)
5961  ereport(ERROR,
5962  (errcode(ERRCODE_SYNTAX_ERROR),
5963  errmsg("query \"%s\" is not a SELECT", expr->query)));
5964 
5965  /* Save query results for eventual cleanup */
5966  Assert(estate->eval_tuptable == NULL);
5967  estate->eval_tuptable = SPI_tuptable;
5968  estate->eval_processed = SPI_processed;
5969 
5970  return rc;
5971 }
char * query
Definition: plpgsql.h:221
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions, bool keepplan)
Definition: pl_exec.c:4119
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1107
uint64 eval_processed
Definition: plpgsql.h:1108
Portal SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan, ParamListInfo params, bool read_only)
Definition: spi.c:1373
SPITupleTable * SPI_tuptable
Definition: spi.c:46
int errcode(int sqlerrcode)
Definition: elog.c:610
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4098
#define SPI_OK_CURSOR
Definition: spi.h:62
uint64 SPI_processed
Definition: spi.c:45
SPIPlanPtr plan
Definition: plpgsql.h:222
int SPI_result
Definition: spi.c:47
#define ERROR
Definition: elog.h:43
int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params, bool read_only, long tcount)
Definition: spi.c:566
const char * SPI_result_code_string(int code)
Definition: spi.c:1815
static ParamListInfo setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:6369
#define SPI_OK_SELECT
Definition: spi.h:57
#define ereport(elevel,...)
Definition: elog.h:144
#define Assert(condition)
Definition: c.h:745
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2715
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214

◆ exec_save_simple_expr()

static void exec_save_simple_expr ( PLpgSQL_expr expr,
CachedPlan cplan 
)
static

Definition at line 8179 of file pl_exec.c.

References Assert, castNode, CMD_SELECT, PlannedStmt::commandType, contain_mutable_functions(), elog, ERROR, PLpgSQL_expr::expr_simple_expr, PLpgSQL_expr::expr_simple_in_use, PLpgSQL_expr::expr_simple_lxid, PLpgSQL_expr::expr_simple_mutable, PLpgSQL_expr::expr_simple_state, PLpgSQL_expr::expr_simple_type, PLpgSQL_expr::expr_simple_typmod, exprType(), exprTypmod(), Plan::initPlan, InvalidLocalTransactionId, IsA, Plan::lefttree, linitial, linitial_node, list_length(), nodeTag, OUTER_VAR, PlannedStmt::planTree, Plan::qual, Plan::righttree, CachedPlan::stmt_list, and Plan::targetlist.

Referenced by exec_eval_simple_expr(), and exec_simple_check_plan().

8180 {
8181  PlannedStmt *stmt;
8182  Plan *plan;
8183  Expr *tle_expr;
8184 
8185  /*
8186  * Given the checks that exec_simple_check_plan did, none of the Asserts
8187  * here should ever fail.
8188  */
8189 
8190  /* Extract the single PlannedStmt */
8191  Assert(list_length(cplan->stmt_list) == 1);
8192  stmt = linitial_node(PlannedStmt, cplan->stmt_list);
8193  Assert(stmt->commandType == CMD_SELECT);
8194 
8195  /*
8196  * Ordinarily, the plan node should be a simple Result. However, if
8197  * force_parallel_mode is on, the planner might've stuck a Gather node
8198  * atop that. The simplest way to deal with this is to look through the
8199  * Gather node. The Gather node's tlist would normally contain a Var
8200  * referencing the child node's output, but it could also be a Param, or
8201  * it could be a Const that setrefs.c copied as-is.
8202  */
8203  plan = stmt->planTree;
8204  for (;;)
8205  {
8206  /* Extract the single tlist expression */
8207  Assert(list_length(plan->targetlist) == 1);
8208  tle_expr = castNode(TargetEntry, linitial(plan->targetlist))->expr;
8209 
8210  if (IsA(plan, Result))
8211  {
8212  Assert(plan->lefttree == NULL &&
8213  plan->righttree == NULL &&
8214  plan->initPlan == NULL &&
8215  plan->qual == NULL &&
8216  ((Result *) plan)->resconstantqual == NULL);
8217  break;
8218  }
8219  else if (IsA(plan, Gather))
8220  {
8221  Assert(plan->lefttree != NULL &&
8222  plan->righttree == NULL &&
8223  plan->initPlan == NULL &&
8224  plan->qual == NULL);
8225  /* If setrefs.c copied up a Const, no need to look further */
8226  if (IsA(tle_expr, Const))
8227  break;
8228  /* Otherwise, it had better be a Param or an outer Var */
8229  Assert(IsA(tle_expr, Param) || (IsA(tle_expr, Var) &&
8230  ((Var *) tle_expr)->varno == OUTER_VAR));
8231  /* Descend to the child node */
8232  plan = plan->lefttree;
8233  }
8234  else
8235  elog(ERROR, "unexpected plan node type: %d",
8236  (int) nodeTag(plan));
8237  }
8238 
8239  /*
8240  * Save the simple expression, and initialize state to "not valid in
8241  * current transaction".
8242  */
8243  expr->expr_simple_expr = tle_expr;
8244  expr->expr_simple_state = NULL;
8245  expr->expr_simple_in_use = false;
8247  /* Also stash away the expression result type */
8248  expr->expr_simple_type = exprType((Node *) tle_expr);
8249  expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
8250  /* We also want to remember if it is immutable or not */
8251  expr->expr_simple_mutable = contain_mutable_functions((Node *) tle_expr);
8252 }
List * qual
Definition: plannodes.h:143
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
#define castNode(_type_, nodeptr)
Definition: nodes.h:598
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:275
Definition: nodes.h:529
Definition: primnodes.h:181
#define linitial_node(type, l)
Definition: pg_list.h:198
struct Plan * planTree
Definition: plannodes.h:64
struct Plan * righttree
Definition: plannodes.h:145
#define linitial(l)
Definition: pg_list.h:195
#define ERROR
Definition: elog.h:43
Expr * expr_simple_expr
Definition: plpgsql.h:233
ExprState * expr_simple_state
Definition: plpgsql.h:254
bool expr_simple_mutable
Definition: plpgsql.h:236
CmdType commandType
Definition: plannodes.h:46
LocalTransactionId expr_simple_lxid
Definition: plpgsql.h:256
#define Assert(condition)
Definition: c.h:745
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
static int list_length(const List *l)
Definition: pg_list.h:169
struct Plan * lefttree
Definition: plannodes.h:144
#define nodeTag(nodeptr)
Definition: nodes.h:534
List * targetlist
Definition: plannodes.h:142
int32 expr_simple_typmod
Definition: plpgsql.h:235
List * initPlan
Definition: plannodes.h:146
#define elog(elevel,...)
Definition: elog.h:214
#define InvalidLocalTransactionId
Definition: lock.h:68
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:647
List * stmt_list
Definition: plancache.h:150
bool expr_simple_in_use
Definition: plpgsql.h:255
#define OUTER_VAR
Definition: primnodes.h:172
Oid expr_simple_type
Definition: plpgsql.h:234

◆ exec_set_found()

static void exec_set_found ( PLpgSQL_execstate estate,
bool  state 
)
static

Definition at line 8366 of file pl_exec.c.

References assign_simple_var(), BoolGetDatum, PLpgSQL_execstate::datums, and PLpgSQL_execstate::found_varno.

Referenced by exec_for_query(), exec_stmt_execsql(), exec_stmt_fetch(), exec_stmt_foreach_a(), exec_stmt_fori(), exec_stmt_perform(), exec_stmt_return_query(), plpgsql_exec_function(), and plpgsql_exec_trigger().

8367 {
8368  PLpgSQL_var *var;
8369 
8370  var = (PLpgSQL_var *) (estate->datums[estate->found_varno]);
8371  assign_simple_var(estate, var, BoolGetDatum(state), false, false);
8372 }
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8542
PLpgSQL_datum ** datums
Definition: plpgsql.h:1082
#define BoolGetDatum(X)
Definition: postgres.h:402
Definition: regguts.h:298

◆ exec_simple_check_plan()

static void exec_simple_check_plan ( PLpgSQL_execstate estate,
PLpgSQL_expr expr 
)
static

Definition at line 8062 of file pl_exec.c.

References Assert, CachedPlanAllowsSimpleValidityCheck(), CMD_SELECT, Query::commandType, Query::cteList, Query::distinctClause, exec_save_simple_expr(), PLpgSQL_expr::expr_simple_expr, PLpgSQL_expr::expr_simple_plan, PLpgSQL_expr::expr_simple_plan_lxid, PLpgSQL_expr::expr_simple_plansource, FromExpr::fromlist, get_eval_mcontext, Query::groupClause, Query::groupingSets, Query::hasAggs, Query::hasSubLinks, Query::hasTargetSRFs, Query::hasWindowFuncs, Query::havingQual, IsA, Query::jointree, Query::limitCount, Query::limitOffset, linitial, list_length(), PGPROC::lxid, MemoryContextSwitchTo(), MyProc, NIL, PLpgSQL_expr::plan, FromExpr::quals, CachedPlanSource::query_list, ReleaseCachedPlan(), Query::rtable, Query::setOperations, PLpgSQL_execstate::simple_eval_resowner, Query::sortClause, SPI_plan_get_cached_plan(), SPI_plan_get_plan_sources(), Query::targetList, and Query::windowClause.

Referenced by exec_prepare_plan().

8063 {
8064  List *plansources;
8065  CachedPlanSource *plansource;
8066  Query *query;
8067  CachedPlan *cplan;
8068  MemoryContext oldcontext;
8069 
8070  /*
8071  * Initialize to "not simple".
8072  */
8073  expr->expr_simple_expr = NULL;
8074 
8075  /*
8076  * Check the analyzed-and-rewritten form of the query to see if we will be
8077  * able to treat it as a simple expression. Since this function is only
8078  * called immediately after creating the CachedPlanSource, we need not
8079  * worry about the query being stale.
8080  */
8081 
8082  /*
8083  * We can only test queries that resulted in exactly one CachedPlanSource
8084  */
8085  plansources = SPI_plan_get_plan_sources(expr->plan);
8086  if (list_length(plansources) != 1)
8087  return;
8088  plansource = (CachedPlanSource *) linitial(plansources);
8089 
8090  /*
8091  * 1. There must be one single querytree.
8092  */
8093  if (list_length(plansource->query_list) != 1)
8094  return;
8095  query = (Query *) linitial(plansource->query_list);
8096 
8097  /*
8098  * 2. It must be a plain SELECT query without any input tables
8099  */
8100  if (!IsA(query, Query))
8101  return;
8102  if (query->commandType != CMD_SELECT)
8103  return;
8104  if (query->rtable != NIL)
8105  return;
8106 
8107  /*
8108  * 3. Can't have any subplans, aggregates, qual clauses either. (These
8109  * tests should generally match what inline_function() checks before
8110  * inlining a SQL function; otherwise, inlining could change our
8111  * conclusion about whether an expression is simple, which we don't want.)
8112  */
8113  if (query->hasAggs ||
8114  query->hasWindowFuncs ||
8115  query->hasTargetSRFs ||
8116  query->hasSubLinks ||
8117  query->cteList ||
8118  query->jointree->fromlist ||
8119  query->jointree->quals ||
8120  query->groupClause ||
8121  query->groupingSets ||
8122  query->havingQual ||
8123  query->windowClause ||
8124  query->distinctClause ||
8125  query->sortClause ||
8126  query->limitOffset ||
8127  query->limitCount ||
8128  query->setOperations)
8129  return;
8130 
8131  /*
8132  * 4. The query must have a single attribute as result
8133  */
8134  if (list_length(query->targetList) != 1)
8135  return;
8136 
8137  /*
8138  * OK, we can treat it as a simple plan.
8139  *
8140  * Get the generic plan for the query. If replanning is needed, do that
8141  * work in the eval_mcontext.
8142  */
8143  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
8144  cplan = SPI_plan_get_cached_plan(expr->plan);
8145  MemoryContextSwitchTo(oldcontext);
8146 
8147  /* Can't fail, because we checked for a single CachedPlanSource above */
8148  Assert(cplan != NULL);
8149 
8150  /*
8151  * Verify that plancache.c thinks the plan is simple enough to use
8152  * CachedPlanIsSimplyValid. Given the restrictions above, it's unlikely
8153  * that this could fail, but if it does, just treat plan as not simple. On
8154  * success, save a refcount on the plan in the simple-expression resowner.
8155  */
8156  if (CachedPlanAllowsSimpleValidityCheck(plansource, cplan,
8157  estate->simple_eval_resowner))
8158  {
8159  /* Remember that we have the refcount */
8160  expr->expr_simple_plansource = plansource;
8161  expr->expr_simple_plan = cplan;
8163 
8164  /* Share the remaining work with the replan code path */
8165  exec_save_simple_expr(expr, cplan);
8166  }
8167 
8168  /*
8169  * Release the plan refcount obtained by SPI_plan_get_cached_plan. (This
8170  * refcount is held by the wrong resowner, so we can't just repurpose it.)
8171  */
8172  ReleaseCachedPlan(cplan, true);
8173 }
Node * limitOffset
Definition: parsenodes.h:160
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
List * sortClause
Definition: parsenodes.h:158
ResourceOwner simple_eval_resowner
Definition: plpgsql.h:1096
FromExpr * jointree
Definition: parsenodes.h:138
PGPROC * MyProc
Definition: proc.c:67
bool hasAggs
Definition: parsenodes.h:125
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
List * groupingSets
Definition: parsenodes.h:150
List * fromlist
Definition: primnodes.h:1510
Node * quals
Definition: primnodes.h:1511
static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
Definition: pl_exec.c:8179
SPIPlanPtr plan
Definition: plpgsql.h:222
List * windowClause
Definition: parsenodes.h:154
List * targetList
Definition: parsenodes.h:140
CachedPlan * SPI_plan_get_cached_plan(SPIPlanPtr plan)
Definition: spi.c:1908
#define linitial(l)
Definition: pg_list.h:195
List * rtable
Definition: parsenodes.h:137
List * distinctClause
Definition: parsenodes.h:156
CachedPlanSource * expr_simple_plansource
Definition: plpgsql.h:244
Node * limitCount
Definition: parsenodes.h:161
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1264
Expr * expr_simple_expr
Definition: plpgsql.h:233
bool CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1309
#define get_eval_mcontext(estate)
Definition: pl_exec.c:131
CachedPlan * expr_simple_plan
Definition: plpgsql.h:245
CmdType commandType
Definition: parsenodes.h:112
bool hasTargetSRFs
Definition: parsenodes.h:127
#define Assert(condition)
Definition: c.h:745
bool hasWindowFuncs
Definition: parsenodes.h:126
static int list_length(const List *l)
Definition: pg_list.h:169
List * cteList
Definition: parsenodes.h:135
Node * setOperations
Definition: parsenodes.h:166
List * groupClause
Definition: parsenodes.h:148
bool hasSubLinks
Definition: parsenodes.h:128
List * SPI_plan_get_plan_sources(SPIPlanPtr plan)
Definition: spi.c:1892
List * query_list
Definition: plancache.h:111
LocalTransactionId expr_simple_plan_lxid
Definition: plpgsql.h:246
Node * havingQual
Definition: parsenodes.h:152
Definition: pg_list.h:50
LocalTransactionId lxid
Definition: proc.h:112

◆ exec_stmt_assert()

static int exec_stmt_assert ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assert stmt 
)
static

Definition at line 3905 of file pl_exec.c.

References PLpgSQL_stmt_assert::cond, convert_value_to_string(), ereport, errcode(), errmsg(), errmsg_internal(), ERROR, exec_eval_boolean(), exec_eval_cleanup(), exec_eval_expr(), PLpgSQL_stmt_assert::message, plpgsql_check_asserts, PLPGSQL_RC_OK, val, and value.

Referenced by exec_stmts().

3906 {
3907  bool value;
3908  bool isnull;
3909 
3910  /* do nothing when asserts are not enabled */
3911  if (!plpgsql_check_asserts)
3912  return PLPGSQL_RC_OK;
3913 
3914  value = exec_eval_boolean(estate, stmt->cond, &isnull);
3915  exec_eval_cleanup(estate);
3916 
3917  if (isnull || !value)
3918  {
3919  char *message = NULL;
3920 
3921  if (stmt->message != NULL)
3922  {
3923  Datum val;
3924  Oid typeid;
3925  int32 typmod;
3926 
3927  val = exec_eval_expr(estate, stmt->message,
3928  &isnull, &typeid, &typmod);
3929  if (!isnull)
3930  message = convert_value_to_string(estate, val, typeid);
3931  /* we mustn't do exec_eval_cleanup here */
3932  }
3933 
3934  ereport(ERROR,
3935  (errcode(ERRCODE_ASSERT_FAILURE),
3936  message ? errmsg_internal("%s", message) :
3937  errmsg("assertion failed")));
3938  }
3939 
3940  return PLPGSQL_RC_OK;
3941 }
int errcode(int sqlerrcode)
Definition: elog.c:610
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4098
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:362
#define ERROR
Definition: elog.h:43
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5833
PLpgSQL_expr * message
Definition: plpgsql.h:910
static bool exec_eval_boolean(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
Definition: pl_exec.c:5810
uintptr_t Datum
Definition: postgres.h:367
static struct @143 value
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg_internal(const char *fmt,...)
Definition: elog.c:911
int errmsg(const char *fmt,...)
Definition: elog.c:824
static char * convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
Definition: pl_exec.c:7804
PLpgSQL_expr * cond
Definition: plpgsql.h:909
bool plpgsql_check_asserts
Definition: pl_handler.c:48
long val
Definition: informix.c:664

◆ exec_stmt_assign()

static int exec_stmt_assign ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assign stmt 
)
static

Definition at line 2119 of file pl_exec.c.

References Assert, PLpgSQL_execstate::datums, exec_assign_expr(), PLpgSQL_stmt_assign::expr, PLPGSQL_RC_OK, and PLpgSQL_stmt_assign::varno.

Referenced by exec_stmts().

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

◆ exec_stmt_block()

static int exec_stmt_block ( PLpgSQL_execstate estate,
PLpgSQL_stmt_block block 
)
static

Definition at line 1621 of file pl_exec.c.

References PLpgSQL_exception::action, Assert, assign_simple_var(), assign_text_var(), BeginInternalSubTransaction(), PLpgSQL_stmt_block::body, PLpgSQL_exception::conditions, CopyErrorData(), PLpgSQL_execstate::cur_error, CurrentMemoryContext, CurrentResourceOwner, PLpgSQL_var::datatype, PLpgSQL_execstate::datums, datumTransfer(), PLpgSQL_var::default_val, PLpgSQL_rec::default_val, PLpgSQL_datum::dtype, elog, PLpgSQL_execstate::err_text, ERROR, PLpgSQL_execstate::eval_econtext, PLpgSQL_execstate::eval_tuptable, PLpgSQL_exception_block::exc_list, exception_matches_conditions(), PLpgSQL_stmt_block::exceptions, exec_assign_expr(), exec_assign_value(), exec_eval_cleanup(), exec_move_row(), exec_stmts(), PLpgSQL_execstate::exitlabel, FlushErrorState(), get_stmt_mcontext(), get_typlenbyval(), gettext_noop, i, PLpgSQL_stmt_block::initvarnos, PLpgSQL_stmt_block::label, lfirst, MemoryContextDeleteChildren(), MemoryContextReset(), MemoryContextSwitchTo(), ErrorData::message, PLpgSQL_stmt_block::n_initvars, PLpgSQL_variable::notnull, PG_CATCH, PG_END_TRY, PG_TRY, plpgsql_create_econtext(), PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_VAR, PLPGSQL_RC_CONTINUE, PLPGSQL_RC_EXIT, PLPGSQL_RC_OK, PLPGSQL_RC_RETURN, pop_stmt_mcontext(), ReleaseCurrentSubTransaction(), ReThrowError(), PLpgSQL_execstate::retisnull, PLpgSQL_execstate::retisset, PLpgSQL_execstate::rettype, PLpgSQL_execstate::retval, RollbackAndReleaseCurrentSubTransaction(), ErrorData::sqlerrcode, PLpgSQL_exception_block::sqlerrm_varno, PLpgSQL_exception_block::sqlstate_varno, PLpgSQL_execstate::stmt_mcontext, PLpgSQL_execstate::stmt_mcontext_parent, PLpgSQL_type::typtype, and unpack_sql_state().

Referenced by exec_stmts(), and exec_toplevel_block().

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

◆ exec_stmt_call()

static int exec_stmt_call ( PLpgSQL_execstate estate,
PLpgSQL_stmt_call stmt 
)
static

Definition at line 2150 of file pl_exec.c.

References FuncExpr::args, PLpgSQL_execstate::atomic, PLpgSQL_row::dtype, elog, ereport, errcode(), errmsg(), ERROR, exec_eval_cleanup(), exec_move_row(), exec_prepare_plan(), expand_function_arguments(), PLpgSQL_stmt_call::expr, PLpgSQL_function::fn_cxt, PLpgSQL_execstate::func, FuncExpr::funcid, FuncExpr::funcresulttype, get_func_arg_info(), GetTransactionSnapshot(), HeapTupleIsValid, i, PLpgSQL_stmt_call::is_call, IsA, lfirst, PLpgSQL_row::lineno, linitial, linitial_node, list_length(), PGPROC::lxid, MemoryContextSwitchTo(), MyProc, PLpgSQL_row::nfields, _SPI_plan::no_snapshots, ObjectIdGetDatum, palloc(), palloc0(), Param::paramid, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLpgSQL_expr::plan, _SPI_plan::plancache_list, plpgsql_create_econtext(), PLPGSQL_DTYPE_ROW, PLPGSQL_RC_OK, PopActiveSnapshot(), PROCOID, PushActiveSnapshot(), PLpgSQL_expr::query, PLpgSQL_execstate::readonly_func, PLpgSQL_row::refname, ReleaseSysCache(), _SPI_plan::saved, SearchSysCache1(), setup_param_list(), PLpgSQL_execstate::simple_eval_estate, PLpgSQL_execstate::simple_eval_resowner, SPI_execute_plan_with_paramlist(), SPI_freetuptable(), SPI_processed, SPI_result_code_string(), SPI_tuptable, PLpgSQL_stmt_call::target, SPITupleTable::tupdesc, SPITupleTable::vals, and PLpgSQL_row::varnos.

Referenced by exec_stmts().

2151 {
2152  PLpgSQL_expr *expr = stmt->expr;
2153  volatile LocalTransactionId before_lxid;
2154  LocalTransactionId after_lxid;
2155  volatile bool pushed_active_snap = false;
2156  volatile int rc;
2157 
2158  /* PG_TRY to ensure we clear the plan link, if needed, on failure */
2159  PG_TRY();
2160  {
2161  SPIPlanPtr plan = expr->plan;
2162  ParamListInfo paramLI;
2163 
2164  if (plan == NULL)
2165  {
2166 
2167  /*
2168  * Don't save the plan if not in atomic context. Otherwise,
2169  * transaction ends would cause errors about plancache leaks.