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

Go to the source code of this file.

Data Structures

struct  SimpleEcontextStackEntry
 
struct  plpgsql_CastHashKey
 
struct  plpgsql_CastExprHashEntry
 
struct  plpgsql_CastHashEntry
 

Macros

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

Typedefs

typedef struct SimpleEcontextStackEntry SimpleEcontextStackEntry
 

Functions

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

Variables

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

Macro Definition Documentation

◆ eval_mcontext_alloc

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

Definition at line 133 of file pl_exec.c.

◆ eval_mcontext_alloc0

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

Definition at line 135 of file pl_exec.c.

◆ get_eval_mcontext

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

Definition at line 131 of file pl_exec.c.

◆ LOOP_RC_PROCESSING

#define LOOP_RC_PROCESSING (   looplabel,
  exit_action 
)

Definition at line 208 of file pl_exec.c.

◆ SET_RAISE_OPTION_TEXT

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

Definition at line 3712 of file pl_exec.c.

Typedef Documentation

◆ SimpleEcontextStackEntry

Function Documentation

◆ assign_record_var()

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

Definition at line 8631 of file pl_exec.c.

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

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

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

◆ assign_simple_var()

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

Definition at line 8555 of file pl_exec.c.

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

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

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

◆ assign_text_var()

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

Definition at line 8622 of file pl_exec.c.

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

References assign_simple_var(), CStringGetTextDatum, and str.

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

◆ coerce_function_result_tuple()

static void coerce_function_result_tuple ( PLpgSQL_execstate estate,
TupleDesc  tupdesc 
)
static

Definition at line 812 of file pl_exec.c.

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

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

References i, TupleDescData::natts, and TupleDescAttr.

Referenced by exec_for_query(), and exec_move_row().

◆ convert_value_to_string()

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

Definition at line 7695 of file pl_exec.c.

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

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

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

◆ copy_plpgsql_datums()

static void copy_plpgsql_datums ( PLpgSQL_execstate estate,
PLpgSQL_function func 
)
static

Definition at line 1298 of file pl_exec.c.

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

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

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

◆ deconstruct_composite_datum()

static TupleDesc deconstruct_composite_datum ( Datum  value,
HeapTupleData tmptup 
)
static

Definition at line 7396 of file pl_exec.c.

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

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

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

◆ do_cast_value()

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

Definition at line 7748 of file pl_exec.c.

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

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

Referenced by exec_cast_value().

◆ exception_matches_conditions()

static bool exception_matches_conditions ( ErrorData edata,
PLpgSQL_condition cond 
)
static

Definition at line 1583 of file pl_exec.c.

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

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

Referenced by exec_stmt_block().

◆ exec_assign_c_string()

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

Definition at line 5055 of file pl_exec.c.

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

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

Referenced by exec_stmt_getdiag().

◆ exec_assign_expr()

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

Definition at line 5011 of file pl_exec.c.

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

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

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

◆ exec_assign_value()

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

Definition at line 5083 of file pl_exec.c.

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

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

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

◆ exec_cast_value()

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

Definition at line 7724 of file pl_exec.c.

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

References do_cast_value(), and value.

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

◆ exec_check_assignable()

static void exec_check_assignable ( PLpgSQL_execstate estate,
int  dno 
)
static

Definition at line 8343 of file pl_exec.c.

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

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

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

◆ exec_check_rw_parameter()

static void exec_check_rw_parameter ( PLpgSQL_expr expr)
static

Definition at line 8232 of file pl_exec.c.

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

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

Referenced by exec_save_simple_expr().

◆ exec_dynquery_with_params()

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

Definition at line 8736 of file pl_exec.c.

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

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

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

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

◆ exec_eval_cleanup()

static void exec_eval_cleanup ( PLpgSQL_execstate estate)
static

Definition at line 4138 of file pl_exec.c.

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

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

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

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

◆ exec_eval_expr()

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

Definition at line 5687 of file pl_exec.c.

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

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

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

Referenced by exec_stmt_fetch().

◆ exec_eval_simple_expr()

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

Definition at line 6037 of file pl_exec.c.

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

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

Referenced by exec_eval_expr().

◆ exec_eval_using_params()

static ParamListInfo exec_eval_using_params ( PLpgSQL_execstate estate,
List params 
)
static

Definition at line 8654 of file pl_exec.c.

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

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

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

◆ exec_for_query()

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

Definition at line 5855 of file pl_exec.c.

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

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

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

Referenced by exec_stmt_return_next(), and exec_stmt_return_query().

◆ exec_is_simple_query()

static bool exec_is_simple_query ( PLpgSQL_expr expr)
static

Definition at line 8054 of file pl_exec.c.

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

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

Referenced by exec_eval_simple_expr(), and exec_simple_check_plan().

◆ exec_move_row()

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

Definition at line 6753 of file pl_exec.c.

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

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

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

◆ exec_move_row_from_datum()

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

Definition at line 7427 of file pl_exec.c.

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

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

Referenced by exec_assign_value(), and plpgsql_exec_function().

◆ exec_move_row_from_fields()

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

Definition at line 7031 of file pl_exec.c.

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

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

Referenced by exec_move_row(), and exec_move_row_from_datum().

◆ exec_prepare_plan()

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

Definition at line 4175 of file pl_exec.c.

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

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

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

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

Referenced by exec_eval_simple_expr(), and exec_simple_check_plan().

◆ exec_set_found()

static void exec_set_found ( PLpgSQL_execstate estate,
bool  state 
)
static

Definition at line 8379 of file pl_exec.c.

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

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

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

◆ exec_simple_check_plan()

static void exec_simple_check_plan ( PLpgSQL_execstate estate,
PLpgSQL_expr expr 
)
static

Definition at line 7983 of file pl_exec.c.

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

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

Referenced by exec_prepare_plan().

◆ exec_stmt_assert()

static int exec_stmt_assert ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assert stmt 
)
static

Definition at line 3938 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_assign()

static int exec_stmt_assign ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assign stmt 
)
static

Definition at line 2152 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_block()

static int exec_stmt_block ( PLpgSQL_execstate estate,
PLpgSQL_stmt_block block 
)
static

Definition at line 1651 of file pl_exec.c.

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

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

Referenced by exec_stmts(), and exec_toplevel_block().

◆ exec_stmt_call()

static int exec_stmt_call ( PLpgSQL_execstate estate,
PLpgSQL_stmt_call stmt 
)
static

Definition at line 2185 of file pl_exec.c.

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

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

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

Referenced by exec_stmts().

◆ exec_stmt_close()

static int exec_stmt_close ( PLpgSQL_execstate estate,
PLpgSQL_stmt_close stmt 
)
static

Definition at line 4921 of file pl_exec.c.

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

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

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

Referenced by exec_stmts().

◆ exec_stmt_dynexecute()

static int exec_stmt_dynexecute ( PLpgSQL_execstate estate,
PLpgSQL_stmt_dynexecute stmt 
)
static

Definition at line 4448 of file pl_exec.c.

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

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

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

Referenced by exec_stmts().

◆ exec_stmt_execsql()

static int exec_stmt_execsql ( PLpgSQL_execstate estate,
PLpgSQL_stmt_execsql stmt 
)
static

Definition at line 4216 of file pl_exec.c.

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

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

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

◆ exec_stmt_exit()

static int exec_stmt_exit ( PLpgSQL_execstate estate,
PLpgSQL_stmt_exit stmt 
)
static

Definition at line 3152 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_fetch()

static int exec_stmt_fetch ( PLpgSQL_execstate estate,
PLpgSQL_stmt_fetch stmt 
)
static

Definition at line 4830 of file pl_exec.c.

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