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_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 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 MemoryContext shared_cast_context = NULL
 
static HTABshared_cast_hash = NULL
 

Macro Definition Documentation

◆ eval_mcontext_alloc

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

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 198 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:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
const char * name
Definition: encode.c:571
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1611

Definition at line 3694 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 8554 of file pl_exec.c.

8556 {
8557  Assert(rec->dtype == PLPGSQL_DTYPE_REC);
8558 
8559  /* Transfer new record object into datum_context */
8560  TransferExpandedRecord(erh, estate->datum_context);
8561 
8562  /* Free the old value ... */
8563  if (rec->erh)
8565 
8566  /* ... and install the new */
8567  rec->erh = erh;
8568 }
void DeleteExpandedObject(Datum d)
static Datum ExpandedRecordGetDatum(const ExpandedRecordHeader *erh)
#define TransferExpandedRecord(erh, cxt)
Assert(fmt[strlen(fmt) - 1] !='\n')
@ PLPGSQL_DTYPE_REC
Definition: plpgsql.h:65
MemoryContext datum_context
Definition: plpgsql.h:1059
ExpandedRecordHeader * erh
Definition: plpgsql.h:413
PLpgSQL_datum_type dtype
Definition: plpgsql.h:390

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

8480 {
8481  Assert(var->dtype == PLPGSQL_DTYPE_VAR ||
8482  var->dtype == PLPGSQL_DTYPE_PROMISE);
8483 
8484  /*
8485  * In non-atomic contexts, we do not want to store TOAST pointers in
8486  * variables, because such pointers might become stale after a commit.
8487  * Forcibly detoast in such cases. We don't want to detoast (flatten)
8488  * expanded objects, however; those should be OK across a transaction
8489  * boundary since they're just memory-resident objects. (Elsewhere in
8490  * this module, operations on expanded records likewise need to request
8491  * detoasting of record fields when !estate->atomic. Expanded arrays are
8492  * not a problem since all array entries are always detoasted.)
8493  */
8494  if (!estate->atomic && !isnull && var->datatype->typlen == -1 &&
8496  {
8497  MemoryContext oldcxt;
8498  Datum detoasted;
8499 
8500  /*
8501  * Do the detoasting in the eval_mcontext to avoid long-term leakage
8502  * of whatever memory toast fetching might leak. Then we have to copy
8503  * the detoasted datum to the function's main context, which is a
8504  * pain, but there's little choice.
8505  */
8506  oldcxt = MemoryContextSwitchTo(get_eval_mcontext(estate));
8507  detoasted = PointerGetDatum(detoast_external_attr((struct varlena *) DatumGetPointer(newvalue)));
8508  MemoryContextSwitchTo(oldcxt);
8509  /* Now's a good time to not leak the input value if it's freeable */
8510  if (freeable)
8511  pfree(DatumGetPointer(newvalue));
8512  /* Once we copy the value, it's definitely freeable */
8513  newvalue = datumCopy(detoasted, false, -1);
8514  freeable = true;
8515  /* Can't clean up eval_mcontext here, but it'll happen before long */
8516  }
8517 
8518  /* Free the old value if needed */
8519  if (var->freeval)
8520  {
8522  var->isnull,
8523  var->datatype->typlen))
8525  else
8526  pfree(DatumGetPointer(var->value));
8527  }
8528  /* Assign new value to datum */
8529  var->value = newvalue;
8530  var->isnull = isnull;
8531  var->freeval = freeable;
8532 
8533  /*
8534  * If it's a promise variable, then either we just assigned the promised
8535  * value, or the user explicitly assigned an overriding value. Either
8536  * way, cancel the promise.
8537  */
8539 }
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:1436
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
#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
int16 typlen
Definition: plpgsql.h:202
PLpgSQL_promise_type promise
Definition: plpgsql.h:341
PLpgSQL_datum_type dtype
Definition: plpgsql.h:310
bool freeval
Definition: plpgsql.h:334
bool isnull
Definition: plpgsql.h:333
PLpgSQL_type * datatype
Definition: plpgsql.h:319
Datum value
Definition: plpgsql.h:332
Definition: c.h:671
#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 8545 of file pl_exec.c.

8546 {
8547  assign_simple_var(estate, var, CStringGetTextDatum(str), false, true);
8548 }
#define CStringGetTextDatum(s)
Definition: builtins.h:94
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8478

References assign_simple_var(), CStringGetTextDatum, and generate_unaccent_rules::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 801 of file pl_exec.c.

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

7265 {
7266  int i;
7267 
7268  /* Possibly we could allow src_tupdesc to have extra columns? */
7269  if (dst_tupdesc->natts != src_tupdesc->natts)
7270  return false;
7271 
7272  for (i = 0; i < dst_tupdesc->natts; i++)
7273  {
7274  Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
7275  Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
7276 
7277  if (dattr->attisdropped != sattr->attisdropped)
7278  return false;
7279  if (!dattr->attisdropped)
7280  {
7281  /* Normal columns must match by type and typmod */
7282  if (dattr->atttypid != sattr->atttypid ||
7283  (dattr->atttypmod >= 0 &&
7284  dattr->atttypmod != sattr->atttypmod))
7285  return false;
7286  }
7287  else
7288  {
7289  /* Dropped columns are OK as long as length/alignment match */
7290  if (dattr->attlen != sattr->attlen ||
7291  dattr->attalign != sattr->attalign)
7292  return false;
7293  }
7294  }
7295  return true;
7296 }
int i
Definition: isn.c:73
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
#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 7662 of file pl_exec.c.

7663 {
7664  char *result;
7665  MemoryContext oldcontext;
7666  Oid typoutput;
7667  bool typIsVarlena;
7668 
7669  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7670  getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
7671  result = OidOutputFunctionCall(typoutput, value);
7672  MemoryContextSwitchTo(oldcontext);
7673 
7674  return result;
7675 }
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1750
static struct @143 value
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2865
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 1287 of file pl_exec.c.

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

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

7364 {
7365  HeapTupleHeader td;
7366  Oid tupType;
7367  int32 tupTypmod;
7368 
7369  /* Get tuple body (note this could involve detoasting) */
7371 
7372  /* Build a temporary HeapTuple control structure */
7373  tmptup->t_len = HeapTupleHeaderGetDatumLength(td);
7374  ItemPointerSetInvalid(&(tmptup->t_self));
7375  tmptup->t_tableOid = InvalidOid;
7376  tmptup->t_data = td;
7377 
7378  /* Extract rowtype info and find a tupdesc */
7379  tupType = HeapTupleHeaderGetTypeId(td);
7380  tupTypmod = HeapTupleHeaderGetTypMod(td);
7381  return lookup_rowtype_tupdesc(tupType, tupTypmod);
7382 }
signed int int32
Definition: c.h:478
#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:1824

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

7719 {
7720  plpgsql_CastHashEntry *cast_entry;
7721 
7722  cast_entry = get_cast_hashentry(estate,
7723  valtype, valtypmod,
7724  reqtype, reqtypmod);
7725  if (cast_entry)
7726  {
7727  ExprContext *econtext = estate->eval_econtext;
7728  MemoryContext oldcontext;
7729 
7730  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7731 
7732  econtext->caseValue_datum = value;
7733  econtext->caseValue_isNull = *isnull;
7734 
7735  cast_entry->cast_in_use = true;
7736 
7737  value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
7738  isnull);
7739 
7740  cast_entry->cast_in_use = false;
7741 
7742  MemoryContextSwitchTo(oldcontext);
7743  }
7744 
7745  return value;
7746 }
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:321
static plpgsql_CastHashEntry * get_cast_hashentry(PLpgSQL_execstate *estate, Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod)
Definition: pl_exec.c:7759
bool caseValue_isNull
Definition: execnodes.h:276
Datum caseValue_datum
Definition: execnodes.h:274
ExprContext * eval_econtext
Definition: plpgsql.h:1087
ExprState * cast_exprstate
Definition: pl_exec.c:167

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

1573 {
1574  for (; cond != NULL; cond = cond->next)
1575  {
1576  int sqlerrstate = cond->sqlerrstate;
1577 
1578  /*
1579  * OTHERS matches everything *except* query-canceled and
1580  * assert-failure. If you're foolish enough, you can match those
1581  * explicitly.
1582  */
1583  if (sqlerrstate == 0)
1584  {
1585  if (edata->sqlerrcode != ERRCODE_QUERY_CANCELED &&
1586  edata->sqlerrcode != ERRCODE_ASSERT_FAILURE)
1587  return true;
1588  }
1589  /* Exact match? */
1590  else if (edata->sqlerrcode == sqlerrstate)
1591  return true;
1592  /* Category match? */
1593  else if (ERRCODE_IS_CATEGORY(sqlerrstate) &&
1594  ERRCODE_TO_CATEGORY(edata->sqlerrcode) == sqlerrstate)
1595  return true;
1596  }
1597  return false;
1598 }
#define ERRCODE_IS_CATEGORY(ec)
Definition: elog.h:62
#define ERRCODE_TO_CATEGORY(ec)
Definition: elog.h:61
int sqlerrcode
Definition: elog.h:438
struct PLpgSQL_condition * next
Definition: plpgsql.h:472

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

5031 {
5032  text *value;
5033  MemoryContext oldcontext;
5034 
5035  /* Use eval_mcontext for short-lived text value */
5036  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5037  if (str != NULL)
5039  else
5040  value = cstring_to_text("");
5041  MemoryContextSwitchTo(oldcontext);
5042 
5043  exec_assign_value(estate, target, PointerGetDatum(value), false,
5044  TEXTOID, -1);
5045 }
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:5057
text * cstring_to_text(const char *s)
Definition: varlena.c:182

References cstring_to_text(), exec_assign_value(), get_eval_mcontext, MemoryContextSwitchTo(), PointerGetDatum(), generate_unaccent_rules::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 4985 of file pl_exec.c.

4987 {
4988  Datum value;
4989  bool isnull;
4990  Oid valtype;
4991  int32 valtypmod;
4992 
4993  /*
4994  * If first time through, create a plan for this expression.
4995  */
4996  if (expr->plan == NULL)
4997  {
4998  /*
4999  * Mark the expression as being an assignment source, if target is a
5000  * simple variable. (This is a bit messy, but it seems cleaner than
5001  * modifying the API of exec_prepare_plan for the purpose. We need to
5002  * stash the target dno into the expr anyway, so that it will be
5003  * available if we have to replan.)
5004  */
5005  if (target->dtype == PLPGSQL_DTYPE_VAR)
5006  expr->target_param = target->dno;
5007  else
5008  expr->target_param = -1; /* should be that already */
5009 
5010  exec_prepare_plan(estate, expr, 0);
5011  }
5012 
5013  value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod);
5014  exec_assign_value(estate, target, value, isnull, valtype, valtypmod);
5015  exec_eval_cleanup(estate);
5016 }
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4115
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions)
Definition: pl_exec.c:4152
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5661
int target_param
Definition: plpgsql.h:244
SPIPlanPtr plan
Definition: plpgsql.h:221

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

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

7695 {
7696  /*
7697  * If the type of the given value isn't what's requested, convert it.
7698  */
7699  if (valtype != reqtype ||
7700  (valtypmod != reqtypmod && reqtypmod != -1))
7701  {
7702  /* We keep the slow path out-of-line. */
7703  value = do_cast_value(estate, value, isnull, valtype, valtypmod,
7704  reqtype, reqtypmod);
7705  }
7706 
7707  return value;
7708 }
static Datum do_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7715

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

8267 {
8268  PLpgSQL_datum *datum;
8269 
8270  Assert(dno >= 0 && dno < estate->ndatums);
8271  datum = estate->datums[dno];
8272  switch (datum->dtype)
8273  {
8274  case PLPGSQL_DTYPE_VAR:
8275  case PLPGSQL_DTYPE_PROMISE:
8276  case PLPGSQL_DTYPE_REC:
8277  if (((PLpgSQL_variable *) datum)->isconst)
8278  ereport(ERROR,
8279  (errcode(ERRCODE_ERROR_IN_ASSIGNMENT),
8280  errmsg("variable \"%s\" is declared CONSTANT",
8281  ((PLpgSQL_variable *) datum)->refname)));
8282  break;
8283  case PLPGSQL_DTYPE_ROW:
8284  /* always assignable; member vars were checked at compile time */
8285  break;
8287  /* assignable if parent record is */
8288  exec_check_assignable(estate,
8289  ((PLpgSQL_recfield *) datum)->recparentno);
8290  break;
8291  default:
8292  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
8293  break;
8294  }
8295 }
static void exec_check_assignable(PLpgSQL_execstate *estate, int dno)
Definition: pl_exec.c:8266
PLpgSQL_datum_type dtype
Definition: plpgsql.h:288

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

8156 {
8157  int target_dno;
8158  Oid funcid;
8159  List *fargs;
8160  ListCell *lc;
8161 
8162  /* Assume unsafe */
8163  expr->expr_rw_param = NULL;
8164 
8165  /* Done if expression isn't an assignment source */
8166  target_dno = expr->target_param;
8167  if (target_dno < 0)
8168  return;
8169 
8170  /*
8171  * If target variable isn't referenced by expression, no need to look
8172  * further.
8173  */
8174  if (!bms_is_member(target_dno, expr->paramnos))
8175  return;
8176 
8177  /* Shouldn't be here for non-simple expression */
8178  Assert(expr->expr_simple_expr != NULL);
8179 
8180  /*
8181  * Top level of expression must be a simple FuncExpr, OpExpr, or
8182  * SubscriptingRef, else we can't optimize.
8183  */
8184  if (IsA(expr->expr_simple_expr, FuncExpr))
8185  {
8186  FuncExpr *fexpr = (FuncExpr *) expr->expr_simple_expr;
8187 
8188  funcid = fexpr->funcid;
8189  fargs = fexpr->args;
8190  }
8191  else if (IsA(expr->expr_simple_expr, OpExpr))
8192  {
8193  OpExpr *opexpr = (OpExpr *) expr->expr_simple_expr;
8194 
8195  funcid = opexpr->opfuncid;
8196  fargs = opexpr->args;
8197  }
8198  else if (IsA(expr->expr_simple_expr, SubscriptingRef))
8199  {
8200  SubscriptingRef *sbsref = (SubscriptingRef *) expr->expr_simple_expr;
8201 
8202  /* We only trust standard varlena arrays to be safe */
8203  if (get_typsubscript(sbsref->refcontainertype, NULL) !=
8204  F_ARRAY_SUBSCRIPT_HANDLER)
8205  return;
8206 
8207  /* We can optimize the refexpr if it's the target, otherwise not */
8208  if (sbsref->refexpr && IsA(sbsref->refexpr, Param))
8209  {
8210  Param *param = (Param *) sbsref->refexpr;
8211 
8212  if (param->paramkind == PARAM_EXTERN &&
8213  param->paramid == target_dno + 1)
8214  {
8215  /* Found the Param we want to pass as read/write */
8216  expr->expr_rw_param = param;
8217  return;
8218  }
8219  }
8220 
8221  return;
8222  }
8223  else
8224  return;
8225 
8226  /*
8227  * The top-level function must be one that we trust to be "safe".
8228  * Currently we hard-wire the list, but it would be very desirable to
8229  * allow extensions to mark their functions as safe ...
8230  */
8231  if (!(funcid == F_ARRAY_APPEND ||
8232  funcid == F_ARRAY_PREPEND))
8233  return;
8234 
8235  /*
8236  * The target variable (in the form of a Param) must appear as a direct
8237  * argument of the top-level function. References further down in the
8238  * tree can't be optimized; but on the other hand, they don't invalidate
8239  * optimizing the top-level call, since that will be executed last.
8240  */
8241  foreach(lc, fargs)
8242  {
8243  Node *arg = (Node *) lfirst(lc);
8244 
8245  if (arg && IsA(arg, Param))
8246  {
8247  Param *param = (Param *) arg;
8248 
8249  if (param->paramkind == PARAM_EXTERN &&
8250  param->paramid == target_dno + 1)
8251  {
8252  /* Found the Param we want to pass as read/write */
8253  expr->expr_rw_param = param;
8254  return;
8255  }
8256  }
8257  }
8258 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:444
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
RegProcedure get_typsubscript(Oid typid, Oid *typelemp)
Definition: lsyscache.c:3055
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
void * arg
#define lfirst(lc)
Definition: pg_list.h:172
@ PARAM_EXTERN
Definition: primnodes.h:345
Oid funcid
Definition: primnodes.h:677
List * args
Definition: primnodes.h:695
Definition: pg_list.h:54
Definition: nodes.h:129
List * args
Definition: primnodes.h:763
Expr * expr_simple_expr
Definition: plpgsql.h:231
Bitmapset * paramnos
Definition: plpgsql.h:222
Param * expr_rw_param
Definition: plpgsql.h:245
int paramid
Definition: primnodes.h:355
ParamKind paramkind
Definition: primnodes.h:354
Expr * refexpr
Definition: primnodes.h:628

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

8664 {
8665  Portal portal;
8666  Datum query;
8667  bool isnull;
8668  Oid restype;
8669  int32 restypmod;
8670  char *querystr;
8672  MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
8673 
8674  /*
8675  * Evaluate the string expression after the EXECUTE keyword. Its result is
8676  * the querystring we have to execute.
8677  */
8678  query = exec_eval_expr(estate, dynquery, &isnull, &restype, &restypmod);
8679  if (isnull)
8680  ereport(ERROR,
8681  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
8682  errmsg("query string argument of EXECUTE is null")));
8683 
8684  /* Get the C-String representation */
8685  querystr = convert_value_to_string(estate, query, restype);
8686 
8687  /* copy it into the stmt_mcontext before we clean up */
8688  querystr = MemoryContextStrdup(stmt_mcontext, querystr);
8689 
8690  exec_eval_cleanup(estate);
8691 
8692  /*
8693  * Open an implicit cursor for the query. We use SPI_cursor_parse_open
8694  * even when there are no params, because this avoids making and freeing
8695  * one copy of the plan.
8696  */
8697  memset(&options, 0, sizeof(options));
8698  options.params = exec_eval_using_params(estate, params);
8699  options.cursorOptions = cursorOptions;
8700  options.read_only = estate->readonly_func;
8701 
8702  portal = SPI_cursor_parse_open(portalname, querystr, &options);
8703 
8704  if (portal == NULL)
8705  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
8706  querystr, SPI_result_code_string(SPI_result));
8707 
8708  /* Release transient data */
8709  MemoryContextReset(stmt_mcontext);
8710 
8711  return portal;
8712 }
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:314
static char ** options
static char * convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
Definition: pl_exec.c:7662
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1521
static ParamListInfo exec_eval_using_params(PLpgSQL_execstate *estate, List *params)
Definition: pl_exec.c:8577
int SPI_result
Definition: spi.c:47
const char * SPI_result_code_string(int code)
Definition: spi.c:1970
Portal SPI_cursor_parse_open(const char *name, const char *src, const SPIParseOpenOptions *options)
Definition: spi.c:1531

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

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

4116 {
4117  /* Clear result of a full SPI_execute */
4118  if (estate->eval_tuptable != NULL)
4120  estate->eval_tuptable = NULL;
4121 
4122  /*
4123  * Clear result of exec_eval_simple_expr (but keep the econtext). This
4124  * also clears any short-lived allocations done via get_eval_mcontext.
4125  */
4126  if (estate->eval_econtext != NULL)
4128 }
#define ResetExprContext(econtext)
Definition: executor.h:532
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1384
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 5284 of file pl_exec.c.

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

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

5666 {
5667  Datum result = 0;
5668  int rc;
5669  Form_pg_attribute attr;
5670 
5671  /*
5672  * If first time through, create a plan for this expression.
5673  */
5674  if (expr->plan == NULL)
5676 
5677  /*
5678  * If this is a simple expression, bypass SPI and use the executor
5679  * directly
5680  */
5681  if (exec_eval_simple_expr(estate, expr,
5682  &result, isNull, rettype, rettypmod))
5683  return result;
5684 
5685  /*
5686  * Else do it the hard way via exec_run_select
5687  */
5688  rc = exec_run_select(estate, expr, 2, NULL);
5689  if (rc != SPI_OK_SELECT)
5690  ereport(ERROR,
5691  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5692  errmsg("query did not return data"),
5693  errcontext("query: %s", expr->query)));
5694 
5695  /*
5696  * Check that the expression returns exactly one column...
5697  */
5698  if (estate->eval_tuptable->tupdesc->natts != 1)
5699  ereport(ERROR,
5700  (errcode(ERRCODE_SYNTAX_ERROR),
5701  errmsg_plural("query returned %d column",
5702  "query returned %d columns",
5703  estate->eval_tuptable->tupdesc->natts,
5704  estate->eval_tuptable->tupdesc->natts),
5705  errcontext("query: %s", expr->query)));
5706 
5707  /*
5708  * ... and get the column's datatype.
5709  */
5710  attr = TupleDescAttr(estate->eval_tuptable->tupdesc, 0);
5711  *rettype = attr->atttypid;
5712  *rettypmod = attr->atttypmod;
5713 
5714  /*
5715  * If there are no rows selected, the result is a NULL of that type.
5716  */
5717  if (estate->eval_processed == 0)
5718  {
5719  *isNull = true;
5720  return (Datum) 0;
5721  }
5722 
5723  /*
5724  * Check that the expression returned no more than one row.
5725  */
5726  if (estate->eval_processed != 1)
5727  ereport(ERROR,
5728  (errcode(ERRCODE_CARDINALITY_VIOLATION),
5729  errmsg("query returned more than one row"),
5730  errcontext("query: %s", expr->query)));
5731 
5732  /*
5733  * Return the single result Datum.
5734  */
5735  return SPI_getbinval(estate->eval_tuptable->vals[0],
5736  estate->eval_tuptable->tupdesc, 1, isNull);
5737 }
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1179
#define errcontext
Definition: elog.h:196
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:3017
static bool exec_eval_simple_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, Datum *result, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:6011
static int exec_run_select(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
Definition: pl_exec.c:5745
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition: spi.c:1250
#define SPI_OK_SELECT
Definition: spi.h:86
uint64 eval_processed
Definition: plpgsql.h:1086
char * query
Definition: plpgsql.h:219
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 5615 of file pl_exec.c.

5618 {
5619  Datum exprdatum;
5620  Oid exprtypeid;
5621  int32 exprtypmod;
5622 
5623  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5624  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5625  exprtypeid, exprtypmod,
5626  INT4OID, -1);
5627  return DatumGetInt32(exprdatum);
5628 }
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 6011 of file pl_exec.c.

6017 {
6018  ExprContext *econtext = estate->eval_econtext;
6019  LocalTransactionId curlxid = MyProc->lxid;
6020  ParamListInfo paramLI;
6021  void *save_setup_arg;
6022  bool need_snapshot;
6023  MemoryContext oldcontext;
6024 
6025  /*
6026  * Forget it if expression wasn't simple before.
6027  */
6028  if (expr->expr_simple_expr == NULL)
6029  return false;
6030 
6031  /*
6032  * If expression is in use in current xact, don't touch it.
6033  */
6034  if (unlikely(expr->expr_simple_in_use) &&
6035  expr->expr_simple_lxid == curlxid)
6036  return false;
6037 
6038  /*
6039  * Ensure that there's a portal-level snapshot, in case this simple
6040  * expression is the first thing evaluated after a COMMIT or ROLLBACK.
6041  * We'd have to do this anyway before executing the expression, so we
6042  * might as well do it now to ensure that any possible replanning doesn't
6043  * need to take a new snapshot.
6044  */
6046 
6047  /*
6048  * Check to see if the cached plan has been invalidated. If not, and this
6049  * is the first use in the current transaction, save a plan refcount in
6050  * the simple-expression resowner.
6051  */
6053  expr->expr_simple_plan,
6054  (expr->expr_simple_plan_lxid != curlxid ?
6055  estate->simple_eval_resowner : NULL))))
6056  {
6057  /*
6058  * It's still good, so just remember that we have a refcount on the
6059  * plan in the current transaction. (If we already had one, this
6060  * assignment is a no-op.)
6061  */
6062  expr->expr_simple_plan_lxid = curlxid;
6063  }
6064  else
6065  {
6066  /* Need to replan */
6067  CachedPlan *cplan;
6068 
6069  /*
6070  * If we have a valid refcount on some previous version of the plan,
6071  * release it, so we don't leak plans intra-transaction.
6072  */
6073  if (expr->expr_simple_plan_lxid == curlxid)
6074  {
6076  estate->simple_eval_resowner);
6077  expr->expr_simple_plan = NULL;
6079  }
6080 
6081  /* Do the replanning work in the eval_mcontext */
6082  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6083  cplan = SPI_plan_get_cached_plan(expr->plan);
6084  MemoryContextSwitchTo(oldcontext);
6085 
6086  /*
6087  * We can't get a failure here, because the number of
6088  * CachedPlanSources in the SPI plan can't change from what
6089  * exec_simple_check_plan saw; it's a property of the raw parsetree
6090  * generated from the query text.
6091  */
6092  Assert(cplan != NULL);
6093 
6094  /*
6095  * This test probably can't fail either, but if it does, cope by
6096  * declaring the plan to be non-simple. On success, we'll acquire a
6097  * refcount on the new plan, stored in simple_eval_resowner.
6098  */
6100  cplan,
6101  estate->simple_eval_resowner))
6102  {
6103  /* Remember that we have the refcount */
6104  expr->expr_simple_plan = cplan;
6105  expr->expr_simple_plan_lxid = curlxid;
6106  }
6107  else
6108  {
6109  /* Release SPI_plan_get_cached_plan's refcount */
6111  /* Mark expression as non-simple, and fail */
6112  expr->expr_simple_expr = NULL;
6113  expr->expr_rw_param = NULL;
6114  return false;
6115  }
6116 
6117  /*
6118  * SPI_plan_get_cached_plan acquired a plan refcount stored in the
6119  * active resowner. We don't need that anymore, so release it.
6120  */
6122 
6123  /* Extract desired scalar expression from cached plan */
6124  exec_save_simple_expr(expr, cplan);
6125  }
6126 
6127  /*
6128  * Pass back previously-determined result type.
6129  */
6130  *rettype = expr->expr_simple_type;
6131  *rettypmod = expr->expr_simple_typmod;
6132 
6133  /*
6134  * Set up ParamListInfo to pass to executor. For safety, save and restore
6135  * estate->paramLI->parserSetupArg around our use of the param list.
6136  */
6137  paramLI = estate->paramLI;
6138  save_setup_arg = paramLI->parserSetupArg;
6139 
6140  /*
6141  * We can skip using setup_param_list() in favor of just doing this
6142  * unconditionally, because there's no need for the optimization of
6143  * possibly setting ecxt_param_list_info to NULL; we've already forced use
6144  * of a generic plan.
6145  */
6146  paramLI->parserSetupArg = (void *) expr;
6147  econtext->ecxt_param_list_info = paramLI;
6148 
6149  /*
6150  * Prepare the expression for execution, if it's not been done already in
6151  * the current transaction. (This will be forced to happen if we called
6152  * exec_save_simple_expr above.)
6153  */
6154  if (unlikely(expr->expr_simple_lxid != curlxid))
6155  {
6156  oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
6157  expr->expr_simple_state =
6159  econtext->ecxt_param_list_info);
6160  expr->expr_simple_in_use = false;
6161  expr->expr_simple_lxid = curlxid;
6162  MemoryContextSwitchTo(oldcontext);
6163  }
6164 
6165  /*
6166  * We have to do some of the things SPI_execute_plan would do, in
6167  * particular push a new snapshot so that stable functions within the
6168  * expression can see updates made so far by our own function. However,
6169  * we can skip doing that (and just invoke the expression with the same
6170  * snapshot passed to our function) in some cases, which is useful because
6171  * it's quite expensive relative to the cost of a simple expression. We
6172  * can skip it if the expression contains no stable or volatile functions;
6173  * immutable functions shouldn't need to see our updates. Also, if this
6174  * is a read-only function, we haven't made any updates so again it's okay
6175  * to skip.
6176  */
6177  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6178  need_snapshot = (expr->expr_simple_mutable && !estate->readonly_func);
6179  if (need_snapshot)
6180  {
6183  }
6184 
6185  /*
6186  * Mark expression as busy for the duration of the ExecEvalExpr call.
6187  */
6188  expr->expr_simple_in_use = true;
6189 
6190  /*
6191  * Finally we can call the executor to evaluate the expression
6192  */
6193  *result = ExecEvalExpr(expr->expr_simple_state,
6194  econtext,
6195  isNull);
6196 
6197  /* Assorted cleanup */
6198  expr->expr_simple_in_use = false;
6199 
6200  econtext->ecxt_param_list_info = NULL;
6201 
6202  paramLI->parserSetupArg = save_setup_arg;
6203 
6204  if (need_snapshot)
6206 
6207  MemoryContextSwitchTo(oldcontext);
6208 
6209  /*
6210  * That's it.
6211  */
6212  return true;
6213 }
#define likely(x)
Definition: c.h:294
uint32 LocalTransactionId
Definition: c.h:638
ExprState * ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
Definition: execExpr.c:164
#define InvalidLocalTransactionId
Definition: lock.h:65
static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
Definition: pl_exec.c:8048
bool CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1309
bool CachedPlanIsSimplyValid(CachedPlanSource *plansource, CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1424
void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1264
void EnsurePortalSnapshotExists(void)
Definition: pquery.c:1780
ResourceOwner CurrentResourceOwner
Definition: resowner.c:146
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:251
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:683
void PopActiveSnapshot(void)
Definition: snapmgr.c:778
CachedPlan * SPI_plan_get_cached_plan(SPIPlanPtr plan)
Definition: spi.c:2070
PGPROC * MyProc
Definition: proc.c:66
MemoryContext es_query_cxt
Definition: execnodes.h:660
ParamListInfo ecxt_param_list_info
Definition: execnodes.h:261
LocalTransactionId lxid
Definition: proc.h:183
EState * simple_eval_estate
Definition: plpgsql.h:1070
ParamListInfo paramLI
Definition: plpgsql.h:1067
ResourceOwner simple_eval_resowner
Definition: plpgsql.h:1071
CachedPlanSource * expr_simple_plansource
Definition: plpgsql.h:253
CachedPlan * expr_simple_plan
Definition: plpgsql.h:254
Oid expr_simple_type
Definition: plpgsql.h:232
ExprState * expr_simple_state
Definition: plpgsql.h:263
bool expr_simple_mutable
Definition: plpgsql.h:234
bool expr_simple_in_use
Definition: plpgsql.h:264
LocalTransactionId expr_simple_plan_lxid
Definition: plpgsql.h:255
LocalTransactionId expr_simple_lxid
Definition: plpgsql.h:265
int32 expr_simple_typmod
Definition: plpgsql.h:233
void * parserSetupArg
Definition: params.h:117
void CommandCounterIncrement(void)
Definition: xact.c:1078

References Assert(), CachedPlanAllowsSimpleValidityCheck(), CachedPlanIsSimplyValid(), CommandCounterIncrement(), CurrentResourceOwner, ExprContext::ecxt_param_list_info, EnsurePortalSnapshotExists(), EState::es_query_cxt, PLpgSQL_execstate::eval_econtext, 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(), and unlikely.

Referenced by exec_eval_expr().

◆ exec_eval_using_params()

static ParamListInfo exec_eval_using_params ( PLpgSQL_execstate estate,
List params 
)
static

Definition at line 8577 of file pl_exec.c.

8578 {
8579  ParamListInfo paramLI;
8580  int nargs;
8581  MemoryContext stmt_mcontext;
8582  MemoryContext oldcontext;
8583  int i;
8584  ListCell *lc;
8585 
8586  /* Fast path for no parameters: we can just return NULL */
8587  if (params == NIL)
8588  return NULL;
8589 
8590  nargs = list_length(params);
8591  stmt_mcontext = get_stmt_mcontext(estate);
8592  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8593  paramLI = makeParamList(nargs);
8594  MemoryContextSwitchTo(oldcontext);
8595 
8596  i = 0;
8597  foreach(lc, params)
8598  {
8599  PLpgSQL_expr *param = (PLpgSQL_expr *) lfirst(lc);
8600  ParamExternData *prm = &paramLI->params[i];
8601  int32 ppdtypmod;
8602 
8603  /*
8604  * Always mark params as const, since we only use the result with
8605  * one-shot plans.
8606  */
8607  prm->pflags = PARAM_FLAG_CONST;
8608 
8609  prm->value = exec_eval_expr(estate, param,
8610  &prm->isnull,
8611  &prm->ptype,
8612  &ppdtypmod);
8613 
8614  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8615 
8616  if (prm->ptype == UNKNOWNOID)
8617  {
8618  /*
8619  * Treat 'unknown' parameters as text, since that's what most
8620  * people would expect. The SPI functions can coerce unknown
8621  * constants in a more intelligent way, but not unknown Params.
8622  * This code also takes care of copying into the right context.
8623  * Note we assume 'unknown' has the representation of C-string.
8624  */
8625  prm->ptype = TEXTOID;
8626  if (!prm->isnull)
8628  }
8629  /* pass-by-ref non null values must be copied into stmt_mcontext */
8630  else if (!prm->isnull)
8631  {
8632  int16 typLen;
8633  bool typByVal;
8634 
8635  get_typlenbyval(prm->ptype, &typLen, &typByVal);
8636  if (!typByVal)
8637  prm->value = datumCopy(prm->value, typByVal, typLen);
8638  }
8639 
8640  MemoryContextSwitchTo(oldcontext);
8641 
8642  exec_eval_cleanup(estate);
8643 
8644  i++;
8645  }
8646 
8647  return paramLI;
8648 }
signed short int16
Definition: c.h:477
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2209
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 5829 of file pl_exec.c.

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

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

3654 {
3655  ReturnSetInfo *rsi = estate->rsi;
3656  MemoryContext oldcxt;
3657  ResourceOwner oldowner;
3658 
3659  /*
3660  * Check caller can handle a set result in the way we want
3661  */
3662  if (!rsi || !IsA(rsi, ReturnSetInfo))
3663  ereport(ERROR,
3664  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3665  errmsg("set-valued function called in context that cannot accept a set")));
3666 
3667  if (!(rsi->allowedModes & SFRM_Materialize) ||
3668  rsi->expectedDesc == NULL)
3669  ereport(ERROR,
3670  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3671  errmsg("materialize mode required, but it is not allowed in this context")));
3672 
3673  /*
3674  * Switch to the right memory context and resource owner for storing the
3675  * tuplestore for return set. If we're within a subtransaction opened for
3676  * an exception-block, for example, we must still create the tuplestore in
3677  * the resource owner that was active when this function was entered, and
3678  * not in the subtransaction resource owner.
3679  */
3680  oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
3681  oldowner = CurrentResourceOwner;
3683 
3684  estate->tuple_store =
3686  false, work_mem);
3687 
3688  CurrentResourceOwner = oldowner;
3689  MemoryContextSwitchTo(oldcxt);
3690 
3691  estate->tuple_store_desc = rsi->expectedDesc;
3692 }
@ SFRM_Materialize_Random
Definition: execnodes.h:312
@ SFRM_Materialize
Definition: execnodes.h:311
int work_mem
Definition: globals.c:125
Tuplestorestate * tuple_store
Definition: plpgsql.h:1042
MemoryContext tuple_store_cxt
Definition: plpgsql.h:1044
TupleDesc tuple_store_desc
Definition: plpgsql.h:1043
ReturnSetInfo * rsi
Definition: plpgsql.h:1046
ResourceOwner tuple_store_owner
Definition: plpgsql.h:1045
TupleDesc expectedDesc
Definition: execnodes.h:327
int allowedModes
Definition: execnodes.h:328
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318

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_move_row()

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

Definition at line 6720 of file pl_exec.c.

6723 {
6724  ExpandedRecordHeader *newerh = NULL;
6725 
6726  /*
6727  * If target is RECORD, we may be able to avoid field-by-field processing.
6728  */
6729  if (target->dtype == PLPGSQL_DTYPE_REC)
6730  {
6731  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
6732 
6733  /*
6734  * If we have no source tupdesc, just set the record variable to NULL.
6735  * (If we have a source tupdesc but not a tuple, we'll set the
6736  * variable to a row of nulls, instead. This is odd perhaps, but
6737  * backwards compatible.)
6738  */
6739  if (tupdesc == NULL)
6740  {
6741  if (rec->datatype &&
6742  rec->datatype->typtype == TYPTYPE_DOMAIN)
6743  {
6744  /*
6745  * If it's a composite domain, NULL might not be a legal
6746  * value, so we instead need to make an empty expanded record
6747  * and ensure that domain type checking gets done. If there
6748  * is already an expanded record, piggyback on its lookups.
6749  */
6750  newerh = make_expanded_record_for_rec(estate, rec,
6751  NULL, rec->erh);
6752  expanded_record_set_tuple(newerh, NULL, false, false);
6753  assign_record_var(estate, rec, newerh);
6754  }
6755  else
6756  {
6757  /* Just clear it to NULL */
6758  if (rec->erh)
6760  rec->erh = NULL;
6761  }
6762  return;
6763  }
6764 
6765  /*
6766  * Build a new expanded record with appropriate tupdesc.
6767  */
6768  newerh = make_expanded_record_for_rec(estate, rec, tupdesc, NULL);
6769 
6770  /*
6771  * If the rowtypes match, or if we have no tuple anyway, we can
6772  * complete the assignment without field-by-field processing.
6773  *
6774  * The tests here are ordered more or less in order of cheapness. We
6775  * can easily detect it will work if the target is declared RECORD or
6776  * has the same typeid as the source. But when assigning from a query
6777  * result, it's common to have a source tupdesc that's labeled RECORD
6778  * but is actually physically compatible with a named-composite-type
6779  * target, so it's worth spending extra cycles to check for that.
6780  */
6781  if (rec->rectypeid == RECORDOID ||
6782  rec->rectypeid == tupdesc->tdtypeid ||
6783  !HeapTupleIsValid(tup) ||
6785  {
6786  if (!HeapTupleIsValid(tup))
6787  {
6788  /* No data, so force the record into all-nulls state */
6790  }
6791  else
6792  {
6793  /* No coercion is needed, so just assign the row value */
6794  expanded_record_set_tuple(newerh, tup, true, !estate->atomic);
6795  }
6796 
6797  /* Complete the assignment */
6798  assign_record_var(estate, rec, newerh);
6799 
6800  return;
6801  }
6802  }
6803 
6804  /*
6805  * Otherwise, deconstruct the tuple and do field-by-field assignment,
6806  * using exec_move_row_from_fields.
6807  */
6808  if (tupdesc && HeapTupleIsValid(tup))
6809  {
6810  int td_natts = tupdesc->natts;
6811  Datum *values;
6812  bool *nulls;
6813  Datum values_local[64];
6814  bool nulls_local[64];
6815 
6816  /*
6817  * Need workspace arrays. If td_natts is small enough, use local
6818  * arrays to save doing a palloc. Even if it's not small, we can
6819  * allocate both the Datum and isnull arrays in one palloc chunk.
6820  */
6821  if (td_natts <= lengthof(values_local))
6822  {
6823  values = values_local;
6824  nulls = nulls_local;
6825  }
6826  else
6827  {
6828  char *chunk;
6829 
6830  chunk = eval_mcontext_alloc(estate,
6831  td_natts * (sizeof(Datum) + sizeof(bool)));
6832  values = (Datum *) chunk;
6833  nulls = (bool *) (chunk + td_natts * sizeof(Datum));
6834  }
6835 
6836  heap_deform_tuple(tup, tupdesc, values, nulls);
6837 
6838  exec_move_row_from_fields(estate, target, newerh,
6839  values, nulls, tupdesc);
6840  }
6841  else
6842  {
6843  /*
6844  * Assign all-nulls.
6845  */
6846  exec_move_row_from_fields(estate, target, newerh,
6847  NULL, NULL, NULL);
6848  }
6849 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define lengthof(array)
Definition: c.h:772
void deconstruct_expanded_record(ExpandedRecordHeader *erh)
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1249
#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:8554
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:6998
static ExpandedRecordHeader * make_expanded_record_for_rec(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, TupleDesc srctupdesc, ExpandedRecordHeader *srcerh)
Definition: pl_exec.c:6935
PLpgSQL_type * datatype
Definition: plpgsql.h:405
char typtype
Definition: plpgsql.h:204

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

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

◆ exec_move_row_from_datum()

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

Definition at line 7394 of file pl_exec.c.

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

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

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

References Assert(), assign_record_var(), PLpgSQL_execstate::atomic, PLpgSQL_execstate::datums, PLpgSQL_variable::dtype, elog(), ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, eval_mcontext_alloc, exec_assign_value(), exec_cast_value(), expanded_record_get_tupdesc(), expanded_record_set_fields(), lengthof, TupleDescData::natts, PLpgSQL_row::nfields, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_ROW, plpgsql_extra_errors, plpgsql_extra_warnings, PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT, TupleDescAttr, value, 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 4152 of file pl_exec.c.

4154 {
4155  SPIPlanPtr plan;
4157 
4158  /*
4159  * The grammar can't conveniently set expr->func while building the parse
4160  * tree, so make sure it's set before parser hooks need it.
4161  */
4162  expr->func = estate->func;
4163 
4164  /*
4165  * Generate and save the plan
4166  */
4167  memset(&options, 0, sizeof(options));
4169  options.parserSetupArg = (void *) expr;
4170  options.parseMode = expr->parseMode;
4171  options.cursorOptions = cursorOptions;
4172  plan = SPI_prepare_extended(expr->query, &options);
4173  if (plan == NULL)
4174  elog(ERROR, "SPI_prepare_extended failed for \"%s\": %s",
4176 
4177  SPI_keepplan(plan);
4178  expr->plan = plan;
4179 
4180  /* Check to see if it's a simple expression */
4181  exec_simple_check_plan(estate, expr);
4182 }
void(* ParserSetupHook)(struct ParseState *pstate, void *arg)
Definition: params.h:108
void plpgsql_parser_setup(struct ParseState *pstate, PLpgSQL_expr *expr)
Definition: pl_comp.c:1081
static void exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:7929
SPIPlanPtr SPI_prepare_extended(const char *src, const SPIPrepareOptions *options)
Definition: spi.c:900
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:974
PLpgSQL_function * func
Definition: plpgsql.h:1022
RawParseMode parseMode
Definition: plpgsql.h:220
struct PLpgSQL_function * func
Definition: plpgsql.h:225

References elog(), ERROR, exec_simple_check_plan(), PLpgSQL_expr::func, PLpgSQL_execstate::func, options, PLpgSQL_expr::parseMode, PLpgSQL_expr::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 5745 of file pl_exec.c.

5747 {
5748  ParamListInfo paramLI;
5749  int rc;
5750 
5751  /*
5752  * On the first call for this expression generate the plan.
5753  *
5754  * If we don't need to return a portal, then we're just going to execute
5755  * the query immediately, which means it's OK to use a parallel plan, even
5756  * if the number of rows being fetched is limited. If we do need to
5757  * return a portal (i.e., this is for a FOR loop), the user's code might
5758  * invoke additional operations inside the FOR loop, making parallel query
5759  * unsafe. In any case, we don't expect any cursor operations to be done,
5760  * so specify NO_SCROLL for efficiency and semantic safety.
5761  */
5762  if (expr->plan == NULL)
5763  {
5764  int cursorOptions = CURSOR_OPT_NO_SCROLL;
5765 
5766  if (portalP == NULL)
5767  cursorOptions |= CURSOR_OPT_PARALLEL_OK;
5768  exec_prepare_plan(estate, expr, cursorOptions);
5769  }
5770 
5771  /*
5772  * Set up ParamListInfo to pass to executor
5773  */
5774  paramLI = setup_param_list(estate, expr);
5775 
5776  /*
5777  * If a portal was requested, put the query and paramlist into the portal
5778  */
5779  if (portalP != NULL)
5780  {
5781  *portalP = SPI_cursor_open_with_paramlist(NULL, expr->plan,
5782  paramLI,
5783  estate->readonly_func);
5784  if (*portalP == NULL)
5785  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
5787  exec_eval_cleanup(estate);
5788  return SPI_OK_CURSOR;
5789  }
5790 
5791  /*
5792  * Execute the query
5793  */
5794  rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
5795  estate->readonly_func, maxtuples);
5796  if (rc != SPI_OK_SELECT)
5797  {
5798  /*
5799  * SELECT INTO deserves a special error message, because "query is not
5800  * a SELECT" is not very helpful in that case.
5801  */
5802  if (rc == SPI_OK_SELINTO)
5803  ereport(ERROR,
5804  (errcode(ERRCODE_SYNTAX_ERROR),
5805  errmsg("query is SELECT INTO, but it should be plain SELECT"),
5806  errcontext("query: %s", expr->query)));
5807  else
5808  ereport(ERROR,
5809  (errcode(ERRCODE_SYNTAX_ERROR),
5810  errmsg("query is not a SELECT"),
5811  errcontext("query: %s", expr->query)));
5812  }
5813 
5814  /* Save query results for eventual cleanup */
5815  Assert(estate->eval_tuptable == NULL);
5816  estate->eval_tuptable = SPI_tuptable;
5817  estate->eval_processed = SPI_processed;
5818 
5819  return rc;
5820 }
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:3009
static ParamListInfo setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:6232
int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params, bool read_only, long tcount)
Definition: spi.c:731
Portal SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan, ParamListInfo params, bool read_only)
Definition: spi.c:1523
#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 8048 of file pl_exec.c.

8049 {
8050  PlannedStmt *stmt;
8051  Plan *plan;
8052  Expr *tle_expr;
8053 
8054  /*
8055  * Given the checks that exec_simple_check_plan did, none of the Asserts
8056  * here should ever fail.
8057  */
8058 
8059  /* Extract the single PlannedStmt */
8060  Assert(list_length(cplan->stmt_list) == 1);
8062  Assert(stmt->commandType == CMD_SELECT);
8063 
8064  /*
8065  * Ordinarily, the plan node should be a simple Result. However, if
8066  * debug_parallel_query is on, the planner might've stuck a Gather node
8067  * atop that. The simplest way to deal with this is to look through the
8068  * Gather node. The Gather node's tlist would normally contain a Var
8069  * referencing the child node's output, but it could also be a Param, or
8070  * it could be a Const that setrefs.c copied as-is.
8071  */
8072  plan = stmt->planTree;
8073  for (;;)
8074  {
8075  /* Extract the single tlist expression */
8076  Assert(list_length(plan->targetlist) == 1);
8077  tle_expr = linitial_node(TargetEntry, plan->targetlist)->expr;
8078 
8079  if (IsA(plan, Result))
8080  {
8081  Assert(plan->lefttree == NULL &&
8082  plan->righttree == NULL &&
8083  plan->initPlan == NULL &&
8084  plan->qual == NULL &&
8085  ((Result *) plan)->resconstantqual == NULL);
8086  break;
8087  }
8088  else if (IsA(plan, Gather))
8089  {
8090  Assert(plan->lefttree != NULL &&
8091  plan->righttree == NULL &&
8092  plan->initPlan == NULL &&
8093  plan->qual == NULL);
8094  /* If setrefs.c copied up a Const, no need to look further */
8095  if (IsA(tle_expr, Const))
8096  break;
8097  /* Otherwise, it had better be a Param or an outer Var */
8098  Assert(IsA(tle_expr, Param) || (IsA(tle_expr, Var) &&
8099  ((Var *) tle_expr)->varno == OUTER_VAR));
8100  /* Descend to the child node */
8101  plan = plan->lefttree;
8102  }
8103  else
8104  elog(ERROR, "unexpected plan node type: %d",
8105  (int) nodeTag(plan));
8106  }
8107 
8108  /*
8109  * Save the simple expression, and initialize state to "not valid in
8110  * current transaction".
8111  */
8112  expr->expr_simple_expr = tle_expr;
8113  expr->expr_simple_state = NULL;
8114  expr->expr_simple_in_use = false;
8116  /* Also stash away the expression result type */
8117  expr->expr_simple_type = exprType((Node *) tle_expr);
8118  expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
8119  /* We also want to remember if it is immutable or not */
8120  expr->expr_simple_mutable = contain_mutable_functions((Node *) tle_expr);
8121 
8122  /*
8123  * Lastly, check to see if there's a possibility of optimizing a
8124  * read/write parameter.
8125  */
8127 }
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:365
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:266
#define nodeTag(nodeptr)
Definition: nodes.h:133
@ CMD_SELECT
Definition: nodes.h:276
#define linitial_node(type, l)
Definition: pg_list.h:181
static void exec_check_rw_parameter(PLpgSQL_expr *expr)
Definition: pl_exec.c:8155
#define OUTER_VAR
Definition: primnodes.h:215
List * stmt_list
Definition: plancache.h:150
struct Plan * lefttree
Definition: plannodes.h:158
struct Plan * righttree
Definition: plannodes.h:159
List * qual
Definition: plannodes.h:157
List * targetlist
Definition: plannodes.h:156
List * initPlan
Definition: plannodes.h:160
Definition: primnodes.h:226

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(), Plan::initPlan, InvalidLocalTransactionId, IsA, Plan::lefttree, linitial_node, list_length(), nodeTag, OUTER_VAR, Plan::qual, Plan::righttree, stmt, CachedPlan::stmt_list, and Plan::targetlist.

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

8303 {
8304  PLpgSQL_var *var;
8305 
8306  var = (PLpgSQL_var *) (estate->datums[estate->found_varno]);
8307  assign_simple_var(estate, var, BoolGetDatum(state), false, false);
8308 }
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
Definition: regguts.h:318

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

7930 {
7931  List *plansources;
7932  CachedPlanSource *plansource;
7933  Query *query;
7934  CachedPlan *cplan;
7935  MemoryContext oldcontext;
7936 
7937  /*
7938  * Initialize to "not simple".
7939  */
7940  expr->expr_simple_expr = NULL;
7941  expr->expr_rw_param = NULL;
7942 
7943  /*
7944  * Check the analyzed-and-rewritten form of the query to see if we will be
7945  * able to treat it as a simple expression. Since this function is only
7946  * called immediately after creating the CachedPlanSource, we need not
7947  * worry about the query being stale.
7948  */
7949 
7950  /*
7951  * We can only test queries that resulted in exactly one CachedPlanSource
7952  */
7953  plansources = SPI_plan_get_plan_sources(expr->plan);
7954  if (list_length(plansources) != 1)
7955  return;
7956  plansource = (CachedPlanSource *) linitial(plansources);
7957 
7958  /*
7959  * 1. There must be one single querytree.
7960  */
7961  if (list_length(plansource->query_list) != 1)
7962  return;
7963  query = (Query *) linitial(plansource->query_list);
7964 
7965  /*
7966  * 2. It must be a plain SELECT query without any input tables
7967  */
7968  if (!IsA(query, Query))
7969  return;
7970  if (query->commandType != CMD_SELECT)
7971  return;
7972  if (query->rtable != NIL)
7973  return;
7974 
7975  /*
7976  * 3. Can't have any subplans, aggregates, qual clauses either. (These
7977  * tests should generally match what inline_function() checks before
7978  * inlining a SQL function; otherwise, inlining could change our
7979  * conclusion about whether an expression is simple, which we don't want.)
7980  */
7981  if (query->hasAggs ||
7982  query->hasWindowFuncs ||
7983  query->hasTargetSRFs ||
7984  query->hasSubLinks ||
7985  query->cteList ||
7986  query->jointree->fromlist ||
7987  query->jointree->quals ||
7988  query->groupClause ||
7989  query->groupingSets ||
7990  query->havingQual ||
7991  query->windowClause ||
7992  query->distinctClause ||
7993  query->sortClause ||
7994  query->limitOffset ||
7995  query->limitCount ||
7996  query->setOperations)
7997  return;
7998 
7999  /*
8000  * 4. The query must have a single attribute as result
8001  */
8002  if (list_length(query->targetList) != 1)
8003  return;
8004 
8005  /*
8006  * OK, we can treat it as a simple plan.
8007  *
8008  * Get the generic plan for the query. If replanning is needed, do that
8009  * work in the eval_mcontext. (Note that replanning could throw an error,
8010  * in which case the expr is left marked "not simple", which is fine.)
8011  */
8012  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
8013  cplan = SPI_plan_get_cached_plan(expr->plan);
8014  MemoryContextSwitchTo(oldcontext);
8015 
8016  /* Can't fail, because we checked for a single CachedPlanSource above */
8017  Assert(cplan != NULL);
8018 
8019  /*
8020  * Verify that plancache.c thinks the plan is simple enough to use
8021  * CachedPlanIsSimplyValid. Given the restrictions above, it's unlikely
8022  * that this could fail, but if it does, just treat plan as not simple. On
8023  * success, save a refcount on the plan in the simple-expression resowner.
8024  */
8025  if (CachedPlanAllowsSimpleValidityCheck(plansource, cplan,
8026  estate->simple_eval_resowner))
8027  {
8028  /* Remember that we have the refcount */
8029  expr->expr_simple_plansource = plansource;
8030  expr->expr_simple_plan = cplan;
8032 
8033  /* Share the remaining work with the replan code path */
8034  exec_save_simple_expr(expr, cplan);
8035  }
8036 
8037  /*
8038  * Release the plan refcount obtained by SPI_plan_get_cached_plan. (This
8039  * refcount is held by the wrong resowner, so we can't just repurpose it.)
8040  */
8042 }
#define linitial(l)
Definition: pg_list.h:178
List * SPI_plan_get_plan_sources(SPIPlanPtr plan)
Definition: spi.c:2051
List * query_list
Definition: plancache.h:111
Node * quals
Definition: primnodes.h:1850
List * fromlist
Definition: primnodes.h:1849
Node * limitCount
Definition: parsenodes.h:212
FromExpr * jointree
Definition: parsenodes.h:182
Node * setOperations
Definition: parsenodes.h:217
List * cteList
Definition: parsenodes.h:173
List * groupClause
Definition: parsenodes.h:198
Node * havingQual
Definition: parsenodes.h:203
List * rtable
Definition: parsenodes.h:175
Node * limitOffset
Definition: parsenodes.h:211
CmdType commandType
Definition: parsenodes.h:128
List * windowClause
Definition: parsenodes.h:205
List * targetList
Definition: parsenodes.h:189
List * groupingSets
Definition: parsenodes.h:201
List * distinctClause
Definition: parsenodes.h:207
List * sortClause
Definition: parsenodes.h:209

References Assert(), CachedPlanAllowsSimpleValidityCheck(), CMD_SELECT, Query::commandType, Query::cteList, CurrentResourceOwner, Query::distinctClause, 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, FromExpr::fromlist, get_eval_mcontext, Query::groupClause, Query::groupingSets, Query::havingQual, IsA, Query::jointree, Query::limitCount, Query::limitOffset, linitial, list_length(), PGPROC::lxid, MemoryContextSwitchTo(), MyProc, NIL, PLpgSQL_expr::plan, FromExpr::quals, CachedPlanSource::query_list, ReleaseCachedPlan(), Query::rtable, Query::setOperations, PLpgSQL_execstate::simple_eval_resowner, Query::sortClause, SPI_plan_get_cached_plan(), SPI_plan_get_plan_sources(), Query::targetList, and Query::windowClause.

Referenced by exec_prepare_plan().

◆ exec_stmt_assert()

static int exec_stmt_assert ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assert stmt 
)
static

Definition at line 3920 of file pl_exec.c.

3921 {
3922  bool value;
3923  bool isnull;
3924 
3925  /* do nothing when asserts are not enabled */
3926  if (!plpgsql_check_asserts)
3927  return PLPGSQL_RC_OK;
3928 
3929  value = exec_eval_boolean(estate, stmt->cond, &isnull);
3930  exec_eval_cleanup(estate);
3931 
3932  if (isnull || !value)
3933  {
3934  char *message = NULL;
3935 
3936  if (stmt->message != NULL)
3937  {
3938  Datum val;
3939  Oid typeid;
3940  int32 typmod;
3941 
3942  val = exec_eval_expr(estate, stmt->message,
3943  &isnull, &typeid, &typmod);
3944  if (!isnull)
3945  message = convert_value_to_string(estate, val, typeid);
3946  /* we mustn't do exec_eval_cleanup here */
3947  }
3948 
3949  ereport(ERROR,
3950  (errcode(ERRCODE_ASSERT_FAILURE),
3951  message ? errmsg_internal("%s", message) :
3952  errmsg("assertion failed")));
3953  }
3954 
3955  return PLPGSQL_RC_OK;
3956 }
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1156
long val
Definition: informix.c:664
static bool exec_eval_boolean(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
Definition: pl_exec.c:5638
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 2141 of file pl_exec.c.

2142 {
2143  Assert(stmt->varno >= 0);
2144 
2145  exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);
2146 
2147  return PLPGSQL_RC_OK;
2148 }
static void exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
Definition: pl_exec.c:4985

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

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

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

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

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, and SPITupleTable::vals.

Referenced by exec_stmts().

◆ exec_stmt_case()

static int exec_stmt_case ( PLpgSQL_execstate estate,
PLpgSQL_stmt_case stmt 
)
static

Definition at line 2526 of file pl_exec.c.

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

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

4896 {
4897  PLpgSQL_var *curvar;
4898  Portal portal;
4899  char *curname;
4900  MemoryContext oldcontext;
4901 
4902  /* ----------
4903  * Get the portal of the cursor by name
4904  * ----------
4905  */
4906  curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
4907  if (curvar->isnull)
4908  ereport(ERROR,
4909  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4910  errmsg("cursor variable \"%s\" is null", curvar->refname)));
4911 
4912  /* Use eval_mcontext for short-lived string */
4913  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
4914  curname = TextDatumGetCString(curvar->value);
4915  MemoryContextSwitchTo(oldcontext);
4916 
4917  portal = SPI_cursor_find(curname);
4918  if (portal == NULL)
4919  ereport(ERROR,
4920  (errcode(ERRCODE_UNDEFINED_CURSOR),
4921  errmsg("cursor \"%s\" does not exist", curname)));
4922 
4923  /* ----------
4924  * And close it.
4925  * ----------
4926  */
4927  SPI_cursor_close(portal);
4928 
4929  return PLPGSQL_RC_OK;
4930 }
#define TextDatumGetCString(d)
Definition: builtins.h:95
Portal SPI_cursor_find(const char *name)
Definition: spi.c:1792
void SPI_cursor_close(Portal portal)
Definition: spi.c:1860

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

4939 {
4940  if (stmt->chain)
4942  else
4943  SPI_commit();
4944 
4945  /*
4946  * We need to build new simple-expression infrastructure, since the old
4947  * data structures are gone.
4948  */
4949  estate->simple_eval_estate = NULL;
4950  estate->simple_eval_resowner = NULL;
4951  plpgsql_create_econtext(estate);
4952 
4953  return PLPGSQL_RC_OK;
4954 }
void SPI_commit(void)
Definition: spi.c:321
void SPI_commit_and_chain(void)
Definition: spi.c:327

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

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

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

4613 {
4614  Portal portal;
4615  int rc;
4616 
4617  portal = exec_dynquery_with_params(estate, stmt->query, stmt->params,
4618  NULL, CURSOR_OPT_NO_SCROLL);
4619 
4620  /*
4621  * Execute the loop
4622  */
4623  rc = exec_for_query(estate, (PLpgSQL_stmt_forq *) stmt, portal, true);
4624 
4625  /*
4626  * Close the implicit cursor
4627  */
4628  SPI_cursor_close(portal);
4629 
4630  return rc;
4631 }
static int exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt, Portal portal, bool prefetch_ok)
Definition: pl_exec.c:5829
static Portal exec_dynquery_with_params(PLpgSQL_execstate *estate, PLpgSQL_expr *dynquery, List *params, const char *portalname, int cursorOptions)
Definition: pl_exec.c:8659

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

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

3135 {
3136  /*
3137  * If the exit / continue has a condition, evaluate it
3138  */
3139  if (stmt->cond != NULL)
3140  {
3141  bool value;
3142  bool isnull;
3143 
3144  value = exec_eval_boolean(estate, stmt->cond, &isnull);
3145  exec_eval_cleanup(estate);
3146  if (isnull || value == false)
3147  return PLPGSQL_RC_OK;
3148  }
3149 
3150  estate->exitlabel = stmt->label;
3151  if (stmt->is_exit)
3152  return PLPGSQL_RC_EXIT;
3153  else
3154  return PLPGSQL_RC_CONTINUE;
3155 }

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

4805 {
4806  PLpgSQL_var *curvar;
4807  long how_many = stmt->how_many;
4808  SPITupleTable *tuptab;
4809  Portal portal;
4810  char *curname;
4811  uint64 n;
4812  MemoryContext oldcontext;
4813 
4814  /* ----------
4815  * Get the portal of the cursor by name
4816  * ----------
4817  */
4818  curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
4819  if (curvar->isnull)
4820  ereport(ERROR,
4821  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4822  errmsg("cursor variable \"%s\" is null", curvar->refname)));
4823 
4824  /* Use eval_mcontext for short-lived string */
4825  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
4826  curname = TextDatumGetCString(curvar->value);
4827  MemoryContextSwitchTo(oldcontext);
4828 
4829  portal = SPI_cursor_find(curname);
4830  if (portal == NULL)
4831  ereport(ERROR,
4832  (errcode(ERRCODE_UNDEFINED_CURSOR),
4833  errmsg("cursor \"%s\" does not exist", curname)));
4834 
4835  /* Calculate position for FETCH_RELATIVE or FETCH_ABSOLUTE */
4836  if (stmt->expr)
4837  {
4838  bool isnull;
4839 
4840  /* XXX should be doing this in LONG not INT width */
4841  how_many = exec_eval_integer(estate, stmt->expr, &isnull);
4842 
4843  if (isnull)
4844  ereport(ERROR,
4845  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4846  errmsg("relative or absolute cursor position is null")));
4847 
4848  exec_eval_cleanup(estate);
4849  }
4850 
4851  if (!stmt->is_move)
4852  {
4853  PLpgSQL_variable *target;
4854 
4855  /* ----------
4856  * Fetch 1 tuple from the cursor
4857  * ----------
4858  */
4859  SPI_scroll_cursor_fetch(portal, stmt->direction, how_many);
4860  tuptab = SPI_tuptable;
4861  n = SPI_processed;
4862 
4863  /* ----------
4864  * Set the target appropriately.
4865  * ----------
4866  */
4867  target = (PLpgSQL_variable *) estate->datums[stmt->target->dno];
4868  if (n == 0)
4869  exec_move_row(estate, target, NULL, tuptab->tupdesc);
4870  else
4871  exec_move_row(estate, target, tuptab->vals[0], tuptab->tupdesc);
4872 
4873  exec_eval_cleanup(estate);
4874  SPI_freetuptable(tuptab);
4875  }
4876  else
4877  {
4878  /* Move the cursor */
4879  SPI_scroll_cursor_move(portal, stmt->direction, how_many);
4880  n = SPI_processed;
4881  }
4882 
4883  /* Set the ROW_COUNT and the global FOUND variable appropriately. */
4884  estate->eval_processed = n;
4885  exec_set_found(estate, n != 0);
4886 
4887  return PLPGSQL_RC_OK;
4888 }
static int exec_eval_integer(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
Definition: pl_exec.c:5615
void SPI_scroll_cursor_move(Portal portal, FetchDirection direction, long count)
Definition: spi.c:1848
void SPI_scroll_cursor_fetch(Portal portal, FetchDirection direction, long count)
Definition: spi.c:1833

References PLpgSQL_execstate::datums, ereport, errcode(), errmsg(), ERROR, PLpgSQL_execstate::eval_processed, exec_eval_cleanup(), exec_eval_integer(), exec_move_row(), exec_set_found(), get_eval_mcontext, if(), PLpgSQL_var::isnull, MemoryContextSwitchTo(), PLPGSQL_RC_OK, PLpgSQL_var::refname, SPI_cursor_find(), SPI_freetuptable(), SPI_processed, SPI_scroll_cursor_fetch(), SPI_scroll_cursor_move(), S