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

Go to the source code of this file.

Data Structures

struct  SimpleEcontextStackEntry
 
struct  plpgsql_CastHashKey
 
struct  plpgsql_CastExprHashEntry
 
struct  plpgsql_CastHashEntry
 

Macros

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

Typedefs

typedef struct SimpleEcontextStackEntry SimpleEcontextStackEntry
 

Functions

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

Variables

static EStateshared_simple_eval_estate = NULL
 
static SimpleEcontextStackEntrysimple_econtext_stack = NULL
 
static ResourceOwner shared_simple_eval_resowner = NULL
 
static HTABcast_expr_hash = NULL
 
static HTABshared_cast_hash = NULL
 

Macro Definition Documentation

◆ eval_mcontext_alloc

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

Definition at line 133 of file pl_exec.c.

◆ eval_mcontext_alloc0

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

Definition at line 135 of file pl_exec.c.

◆ get_eval_mcontext

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

Definition at line 131 of file pl_exec.c.

◆ LOOP_RC_PROCESSING

#define LOOP_RC_PROCESSING (   looplabel,
  exit_action 
)

Definition at line 208 of file pl_exec.c.

◆ SET_RAISE_OPTION_TEXT

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

Definition at line 3711 of file pl_exec.c.

Typedef Documentation

◆ SimpleEcontextStackEntry

Function Documentation

◆ assign_record_var()

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

Definition at line 8629 of file pl_exec.c.

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

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

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

◆ assign_simple_var()

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

Definition at line 8553 of file pl_exec.c.

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

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

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

◆ assign_text_var()

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

Definition at line 8620 of file pl_exec.c.

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

References assign_simple_var(), CStringGetTextDatum, and str.

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

◆ coerce_function_result_tuple()

static void coerce_function_result_tuple ( PLpgSQL_execstate estate,
TupleDesc  tupdesc 
)
static

Definition at line 812 of file pl_exec.c.

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

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

Referenced by plpgsql_exec_function().

◆ compatible_tupdescs()

static bool compatible_tupdescs ( TupleDesc  src_tupdesc,
TupleDesc  dst_tupdesc 
)
static

Definition at line 7295 of file pl_exec.c.

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

References i, TupleDescData::natts, and TupleDescAttr.

Referenced by exec_for_query(), and exec_move_row().

◆ convert_value_to_string()

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

Definition at line 7693 of file pl_exec.c.

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

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

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

◆ copy_plpgsql_datums()

static void copy_plpgsql_datums ( PLpgSQL_execstate estate,
PLpgSQL_function func 
)
static

Definition at line 1298 of file pl_exec.c.

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

References Assert, PLpgSQL_function::copiable_size, PLpgSQL_function::datums, PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, elog, ERROR, i, MAXALIGN, PLpgSQL_execstate::ndatums, palloc(), PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ROW, and PLPGSQL_DTYPE_VAR.

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

◆ deconstruct_composite_datum()

static TupleDesc deconstruct_composite_datum ( Datum  value,
HeapTupleData tmptup 
)
static

Definition at line 7394 of file pl_exec.c.

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

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

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

◆ do_cast_value()

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

Definition at line 7746 of file pl_exec.c.

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

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

Referenced by exec_cast_value().

◆ exception_matches_conditions()

static bool exception_matches_conditions ( ErrorData edata,
PLpgSQL_condition cond 
)
static

Definition at line 1583 of file pl_exec.c.

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

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

Referenced by exec_stmt_block().

◆ exec_assign_c_string()

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

Definition at line 5053 of file pl_exec.c.

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

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

Referenced by exec_stmt_getdiag().

◆ exec_assign_expr()

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

Definition at line 5009 of file pl_exec.c.

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

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

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

◆ exec_assign_value()

static void exec_assign_value ( PLpgSQL_execstate estate,
PLpgSQL_datum target,
Datum  value,
bool  isNull,
Oid  valtype,
int32  valtypmod 
)
static

Definition at line 5081 of file pl_exec.c.

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

References assign_simple_var(), PLpgSQL_execstate::atomic, PLpgSQL_type::atttypmod, PLpgSQL_var::datatype, PLpgSQL_execstate::datum_context, DatumGetPointer(), PLpgSQL_execstate::datums, datumTransfer(), PLpgSQL_datum::dtype, elog, ExpandedRecordHeader::er_tupdesc_id, ereport, PLpgSQL_rec::erh, errcode(), errmsg(), ERROR, exec_cast_value(), exec_move_row(), exec_move_row_from_datum(), expand_array(), expanded_record_lookup_field(), expanded_record_set_field, PLpgSQL_recfield::fieldname, PLpgSQL_recfield::finfo, ExpandedRecordFieldInfo::fnumber, ExpandedRecordFieldInfo::ftypeid, ExpandedRecordFieldInfo::ftypmod, instantiate_empty_record_variable(), PLpgSQL_var::isnull, PLpgSQL_var::notnull, PLpgSQL_rec::notnull, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, PLPGSQL_PROMISE_NONE, PLpgSQL_var::promise, PLpgSQL_recfield::recparentno, PLpgSQL_recfield::rectupledescid, PLpgSQL_var::refname, PLpgSQL_rec::refname, PLpgSQL_type::typbyval, type_is_rowtype(), PLpgSQL_type::typisarray, PLpgSQL_type::typlen, PLpgSQL_type::typoid, unlikely, value, PLpgSQL_var::value, and VARATT_IS_EXTERNAL_EXPANDED_RW.

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

◆ exec_cast_value()

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

Definition at line 7722 of file pl_exec.c.

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

References do_cast_value(), and value.

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

◆ exec_check_assignable()

static void exec_check_assignable ( PLpgSQL_execstate estate,
int  dno 
)
static

Definition at line 8341 of file pl_exec.c.

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

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

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

◆ exec_check_rw_parameter()

static void exec_check_rw_parameter ( PLpgSQL_expr expr)
static

Definition at line 8230 of file pl_exec.c.

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

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

Referenced by exec_save_simple_expr().

◆ exec_dynquery_with_params()

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

Definition at line 8734 of file pl_exec.c.

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

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

Referenced by exec_stmt_dynfors(), and exec_stmt_open().

◆ exec_eval_boolean()

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

Definition at line 5662 of file pl_exec.c.

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

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

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

◆ exec_eval_cleanup()

static void exec_eval_cleanup ( PLpgSQL_execstate estate)
static

Definition at line 4137 of file pl_exec.c.

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

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

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

◆ exec_eval_datum()

static void exec_eval_datum ( PLpgSQL_execstate estate,
PLpgSQL_datum datum,
Oid typeid,
int32 typetypmod,
Datum value,
bool isnull 
)
static

Definition at line 5308 of file pl_exec.c.

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

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

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

◆ exec_eval_expr()

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

Definition at line 5685 of file pl_exec.c.

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

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

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

◆ exec_eval_integer()

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

Definition at line 5639 of file pl_exec.c.

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

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

Referenced by exec_stmt_fetch().

◆ exec_eval_simple_expr()

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

Definition at line 6035 of file pl_exec.c.

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

References Assert, CachedPlanAllowsSimpleValidityCheck(), CachedPlanIsSimplyValid(), CommandCounterIncrement(), CurrentResourceOwner, ExprContext::ecxt_param_list_info, EnsurePortalSnapshotExists(), EState::es_query_cxt, PLpgSQL_execstate::eval_econtext, exec_is_simple_query(), exec_save_simple_expr(), ExecEvalExpr(), ExecInitExprWithParams(), PLpgSQL_expr::expr_rw_param, PLpgSQL_expr::expr_simple_expr, PLpgSQL_expr::expr_simple_in_use, PLpgSQL_expr::expr_simple_lxid, PLpgSQL_expr::expr_simple_mutable, PLpgSQL_expr::expr_simple_plan, PLpgSQL_expr::expr_simple_plan_lxid, PLpgSQL_expr::expr_simple_plansource, PLpgSQL_expr::expr_simple_state, PLpgSQL_expr::expr_simple_type, PLpgSQL_expr::expr_simple_typmod, get_eval_mcontext, GetTransactionSnapshot(), InvalidLocalTransactionId, likely, PGPROC::lxid, MemoryContextSwitchTo(), MyProc, PLpgSQL_execstate::paramLI, ParamListInfoData::parserSetupArg, PLpgSQL_expr::plan, PopActiveSnapshot(), PushActiveSnapshot(), PLpgSQL_execstate::readonly_func, ReleaseCachedPlan(), PLpgSQL_execstate::simple_eval_estate, PLpgSQL_execstate::simple_eval_resowner, SPI_plan_get_cached_plan(), unlikely, and PGPROC::vxid.

Referenced by exec_eval_expr().

◆ exec_eval_using_params()

static ParamListInfo exec_eval_using_params ( PLpgSQL_execstate estate,
List params 
)
static

Definition at line 8652 of file pl_exec.c.

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

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

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

◆ exec_for_query()

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

Definition at line 5853 of file pl_exec.c.

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

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

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

◆ exec_init_tuple_store()

static void exec_init_tuple_store ( PLpgSQL_execstate estate)
static

Definition at line 3670 of file pl_exec.c.

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

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

Referenced by exec_stmt_return_next(), and exec_stmt_return_query().

◆ exec_is_simple_query()

static bool exec_is_simple_query ( PLpgSQL_expr expr)
static

Definition at line 8052 of file pl_exec.c.

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

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

Referenced by exec_eval_simple_expr(), and exec_simple_check_plan().

◆ exec_move_row()

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

Definition at line 6751 of file pl_exec.c.

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

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

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

◆ exec_move_row_from_datum()

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

Definition at line 7425 of file pl_exec.c.

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

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

Referenced by exec_assign_value(), and plpgsql_exec_function().

◆ exec_move_row_from_fields()

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

Definition at line 7029 of file pl_exec.c.

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

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

Referenced by exec_move_row(), and exec_move_row_from_datum().

◆ exec_prepare_plan()

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

Definition at line 4174 of file pl_exec.c.

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

References elog, ERROR, exec_simple_check_plan(), PLpgSQL_expr::func, PLpgSQL_execstate::func, options, PLpgSQL_expr::parseMode, PLpgSQL_expr::plan, plan, plpgsql_parser_setup(), PLpgSQL_expr::query, SPI_keepplan(), SPI_prepare_extended(), SPI_result, and SPI_result_code_string().

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

◆ exec_run_select()

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

Definition at line 5769 of file pl_exec.c.

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

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

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

◆ exec_save_simple_expr()

static void exec_save_simple_expr ( PLpgSQL_expr expr,
CachedPlan cplan 
)
static

Definition at line 8123 of file pl_exec.c.

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

References Assert, CMD_SELECT, contain_mutable_functions(), elog, ERROR, exec_check_rw_parameter(), PLpgSQL_expr::expr_simple_expr, PLpgSQL_expr::expr_simple_in_use, PLpgSQL_expr::expr_simple_lxid, PLpgSQL_expr::expr_simple_mutable, PLpgSQL_expr::expr_simple_state, PLpgSQL_expr::expr_simple_type, PLpgSQL_expr::expr_simple_typmod, exprType(), exprTypmod(), InvalidLocalTransactionId, IsA, linitial_node, list_length(), nodeTag, OUTER_VAR, plan, stmt, and CachedPlan::stmt_list.

Referenced by exec_eval_simple_expr(), and exec_simple_check_plan().

◆ exec_set_found()

static void exec_set_found ( PLpgSQL_execstate estate,
bool  state 
)
static

Definition at line 8377 of file pl_exec.c.

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

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

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

◆ exec_simple_check_plan()

static void exec_simple_check_plan ( PLpgSQL_execstate estate,
PLpgSQL_expr expr 
)
static

Definition at line 7981 of file pl_exec.c.

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

References Assert, CachedPlanAllowsSimpleValidityCheck(), CurrentResourceOwner, exec_is_simple_query(), exec_save_simple_expr(), PLpgSQL_expr::expr_rw_param, PLpgSQL_expr::expr_simple_expr, PLpgSQL_expr::expr_simple_plan, PLpgSQL_expr::expr_simple_plan_lxid, PLpgSQL_expr::expr_simple_plansource, get_eval_mcontext, linitial, PGPROC::lxid, MemoryContextSwitchTo(), MyProc, PLpgSQL_expr::plan, ReleaseCachedPlan(), PLpgSQL_execstate::simple_eval_resowner, SPI_plan_get_cached_plan(), SPI_plan_get_plan_sources(), and PGPROC::vxid.

Referenced by exec_prepare_plan().

◆ exec_stmt_assert()

static int exec_stmt_assert ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assert stmt 
)
static

Definition at line 3937 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_assign()

static int exec_stmt_assign ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assign stmt 
)
static

Definition at line 2152 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_block()

static int exec_stmt_block ( PLpgSQL_execstate estate,
PLpgSQL_stmt_block block 
)
static

Definition at line 1651 of file pl_exec.c.

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

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

Referenced by exec_stmts(), and exec_toplevel_block().

◆ exec_stmt_call()

static int exec_stmt_call ( PLpgSQL_execstate estate,
PLpgSQL_stmt_call stmt 
)
static

Definition at line 2185 of file pl_exec.c.

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

References Assert, elog, ERROR, exec_eval_cleanup(), exec_move_row(), exec_prepare_plan(), PLpgSQL_expr::expr_simple_expr, PGPROC::lxid, make_callstmt_target(), MyProc, options, PLpgSQL_expr::plan, plpgsql_create_econtext(), PLPGSQL_RC_OK, PLpgSQL_execstate::procedure_resowner, PLpgSQL_expr::query, PLpgSQL_execstate::readonly_func, setup_param_list(), PLpgSQL_execstate::simple_eval_estate, PLpgSQL_execstate::simple_eval_resowner, SPI_execute_plan_extended(), SPI_freetuptable(), SPI_processed, SPI_result_code_string(), SPI_tuptable, stmt, SPITupleTable::tupdesc, SPITupleTable::vals, and PGPROC::vxid.

Referenced by exec_stmts().

◆ exec_stmt_case()

static int exec_stmt_case ( PLpgSQL_execstate estate,
PLpgSQL_stmt_case stmt 
)
static

Definition at line 2543 of file pl_exec.c.

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

References assign_simple_var(), PLpgSQL_type::atttypmod, PLpgSQL_var::datatype, PLpgSQL_execstate::datums, ereport, errcode(), errhint(), errmsg(), ERROR, exec_assign_value(), exec_eval_boolean(), exec_eval_cleanup(), exec_eval_expr(), exec_stmts(), PLpgSQL_case_when::expr, PLpgSQL_function::fn_input_collation, PLpgSQL_execstate::func, if(), lfirst, plpgsql_build_datatype(), stmt, PLpgSQL_case_when::stmts, PLpgSQL_type::typoid, and value.

Referenced by exec_stmts().

◆ exec_stmt_close()

static int exec_stmt_close ( PLpgSQL_execstate estate,
PLpgSQL_stmt_close stmt 
)
static

Definition at line 4919 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_commit()

static int exec_stmt_commit ( PLpgSQL_execstate estate,
PLpgSQL_stmt_commit stmt 
)
static

Definition at line 4962 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_dynexecute()

static int exec_stmt_dynexecute ( PLpgSQL_execstate estate,
PLpgSQL_stmt_dynexecute stmt 
)
static

Definition at line 4446 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_dynfors()

static int exec_stmt_dynfors ( PLpgSQL_execstate estate,
PLpgSQL_stmt_dynfors stmt 
)
static

Definition at line 4636 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_execsql()

static int exec_stmt_execsql ( PLpgSQL_execstate estate,
PLpgSQL_stmt_execsql stmt 
)
static

Definition at line 4215 of file pl_exec.c.

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

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

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

◆ exec_stmt_exit()

static int exec_stmt_exit ( PLpgSQL_execstate estate,
PLpgSQL_stmt_exit stmt 
)
static

Definition at line 3151 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_fetch()

static int exec_stmt_fetch ( PLpgSQL_execstate estate,
PLpgSQL_stmt_fetch stmt 
)
static

Definition at line 4828 of file pl_exec.c.

4829 {
4830  PLpgSQL_var *curvar;
4831  long how_many = stmt->how_many;
4832  SPITupleTable *tuptab;
4833  Portal portal;
4834  char *curname;
4835  uint64 n;
4836  MemoryContext oldcontext;
4837 
4838  /* ----------
4839  * Get the portal of the cursor by name
4840  * ----------
4841  */
4842  curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
4843  if (curvar->isnull)
4844  ereport(ERROR,
4845  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4846  errmsg("cursor variable \"%s\" is null", curvar->refname)));
4847 
4848  /* Use eval_mcontext for short-lived string */
4849  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
4850  curname = TextDatumGetCString(curvar->value);
4851  MemoryContextSwitchTo(oldcontext);
4852 
4853  portal = SPI_cursor_find(curname);
4854  if (portal == NULL)
4855  ereport(ERROR,
4856  (errcode(ERRCODE_UNDEFINED_CURSOR),
4857  errmsg("cursor \"%s\" does not exist", curname)));
4858 
4859  /* Calculate position for FETCH_RELATIVE or FETCH_ABSOLUTE */
4860  if (stmt->expr)
4861  {
4862  bool isnull;
4863 
4864  /* XXX should be doing this in LONG not INT width */
4865  how_many = exec_eval_integer(estate, stmt->expr, &isnull);
4866 
4867  if (isnull)
4868  ereport(ERROR,
4869  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4870  errmsg("relative or absolute cursor position is null")));
4871 
4872  exec_eval_cleanup(estate);
4873  }
4874 
4875  if (!stmt->is_move)
4876  {
4877  PLpgSQL_variable *target;
4878 
4879  /* ----------
4880  * Fetch 1 tuple from the cursor
4881  * ----------
4882  */
4883  SPI_scroll_cursor_fetch(portal,