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 bool exec_eval_simple_expr (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, Datum *result, bool *isNull, Oid *rettype, int32 *rettypmod)
 
static void exec_assign_expr (PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
 
static void exec_assign_c_string (PLpgSQL_execstate *estate, PLpgSQL_datum *target, const char *str)
 
static void exec_assign_value (PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
 
static void exec_eval_datum (PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeid, int32 *typetypmod, Datum *value, bool *isnull)
 
static int exec_eval_integer (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
 
static bool exec_eval_boolean (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
 
static Datum exec_eval_expr (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
 
static int exec_run_select (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
 
static int exec_for_query (PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt, Portal portal, bool prefetch_ok)
 
static ParamListInfo setup_param_list (PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
 
static ParamExternDataplpgsql_param_fetch (ParamListInfo params, int paramid, bool speculative, ParamExternData *workspace)
 
static void plpgsql_param_compile (ParamListInfo params, Param *param, ExprState *state, Datum *resv, bool *resnull)
 
static void plpgsql_param_eval_var (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void plpgsql_param_eval_var_ro (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void plpgsql_param_eval_recfield (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void plpgsql_param_eval_generic (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void plpgsql_param_eval_generic_ro (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void exec_move_row (PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
 
static void revalidate_rectypeid (PLpgSQL_rec *rec)
 
static ExpandedRecordHeadermake_expanded_record_for_rec (PLpgSQL_execstate *estate, PLpgSQL_rec *rec, TupleDesc srctupdesc, ExpandedRecordHeader *srcerh)
 
static void exec_move_row_from_fields (PLpgSQL_execstate *estate, PLpgSQL_variable *target, ExpandedRecordHeader *newerh, Datum *values, bool *nulls, TupleDesc tupdesc)
 
static bool compatible_tupdescs (TupleDesc src_tupdesc, TupleDesc dst_tupdesc)
 
static HeapTuple make_tuple_from_row (PLpgSQL_execstate *estate, PLpgSQL_row *row, TupleDesc tupdesc)
 
static TupleDesc deconstruct_composite_datum (Datum value, HeapTupleData *tmptup)
 
static void exec_move_row_from_datum (PLpgSQL_execstate *estate, PLpgSQL_variable *target, Datum value)
 
static void instantiate_empty_record_variable (PLpgSQL_execstate *estate, PLpgSQL_rec *rec)
 
static char * convert_value_to_string (PLpgSQL_execstate *estate, Datum value, Oid valtype)
 
static Datum exec_cast_value (PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
 
static Datum do_cast_value (PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
 
static plpgsql_CastHashEntryget_cast_hashentry (PLpgSQL_execstate *estate, Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod)
 
static void exec_init_tuple_store (PLpgSQL_execstate *estate)
 
static void exec_set_found (PLpgSQL_execstate *estate, bool state)
 
static void plpgsql_create_econtext (PLpgSQL_execstate *estate)
 
static void plpgsql_destroy_econtext (PLpgSQL_execstate *estate)
 
static void assign_simple_var (PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
 
static void assign_text_var (PLpgSQL_execstate *estate, PLpgSQL_var *var, const char *str)
 
static void assign_record_var (PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
 
static ParamListInfo exec_eval_using_params (PLpgSQL_execstate *estate, List *params)
 
static Portal exec_dynquery_with_params (PLpgSQL_execstate *estate, PLpgSQL_expr *dynquery, List *params, const char *portalname, int cursorOptions)
 
static char * format_expr_params (PLpgSQL_execstate *estate, const PLpgSQL_expr *expr)
 
static char * format_preparedparamsdata (PLpgSQL_execstate *estate, ParamListInfo paramLI)
 
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:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
const char * name
Definition: encode.c:561
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1286

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

8495 {
8496  Assert(rec->dtype == PLPGSQL_DTYPE_REC);
8497 
8498  /* Transfer new record object into datum_context */
8499  TransferExpandedRecord(erh, estate->datum_context);
8500 
8501  /* Free the old value ... */
8502  if (rec->erh)
8504 
8505  /* ... and install the new */
8506  rec->erh = erh;
8507 }
void DeleteExpandedObject(Datum d)
#define TransferExpandedRecord(erh, cxt)
#define ExpandedRecordGetDatum(erh)
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 8417 of file pl_exec.c.

8419 {
8420  Assert(var->dtype == PLPGSQL_DTYPE_VAR ||
8421  var->dtype == PLPGSQL_DTYPE_PROMISE);
8422 
8423  /*
8424  * In non-atomic contexts, we do not want to store TOAST pointers in
8425  * variables, because such pointers might become stale after a commit.
8426  * Forcibly detoast in such cases. We don't want to detoast (flatten)
8427  * expanded objects, however; those should be OK across a transaction
8428  * boundary since they're just memory-resident objects. (Elsewhere in
8429  * this module, operations on expanded records likewise need to request
8430  * detoasting of record fields when !estate->atomic. Expanded arrays are
8431  * not a problem since all array entries are always detoasted.)
8432  */
8433  if (!estate->atomic && !isnull && var->datatype->typlen == -1 &&
8435  {
8436  MemoryContext oldcxt;
8437  Datum detoasted;
8438 
8439  /*
8440  * Do the detoasting in the eval_mcontext to avoid long-term leakage
8441  * of whatever memory toast fetching might leak. Then we have to copy
8442  * the detoasted datum to the function's main context, which is a
8443  * pain, but there's little choice.
8444  */
8445  oldcxt = MemoryContextSwitchTo(get_eval_mcontext(estate));
8446  detoasted = PointerGetDatum(detoast_external_attr((struct varlena *) DatumGetPointer(newvalue)));
8447  MemoryContextSwitchTo(oldcxt);
8448  /* Now's a good time to not leak the input value if it's freeable */
8449  if (freeable)
8450  pfree(DatumGetPointer(newvalue));
8451  /* Once we copy the value, it's definitely freeable */
8452  newvalue = datumCopy(detoasted, false, -1);
8453  freeable = true;
8454  /* Can't clean up eval_mcontext here, but it'll happen before long */
8455  }
8456 
8457  /* Free the old value if needed */
8458  if (var->freeval)
8459  {
8461  var->isnull,
8462  var->datatype->typlen))
8464  else
8465  pfree(DatumGetPointer(var->value));
8466  }
8467  /* Assign new value to datum */
8468  var->value = newvalue;
8469  var->isnull = isnull;
8470  var->freeval = freeable;
8471 
8472  /*
8473  * If it's a promise variable, then either we just assigned the promised
8474  * value, or the user explicitly assigned an overriding value. Either
8475  * way, cancel the promise.
8476  */
8478 }
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:1169
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#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
uintptr_t Datum
Definition: postgres.h:411
#define DatumGetPointer(X)
Definition: postgres.h:593
#define VARATT_IS_EXTERNAL_NON_EXPANDED(PTR)
Definition: postgres.h:337
#define PointerGetDatum(X)
Definition: postgres.h:600
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:622

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

8485 {
8486  assign_simple_var(estate, var, CStringGetTextDatum(str), false, true);
8487 }
#define CStringGetTextDatum(s)
Definition: builtins.h:85
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8417

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

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

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

7241 {
7242  int i;
7243 
7244  /* Possibly we could allow src_tupdesc to have extra columns? */
7245  if (dst_tupdesc->natts != src_tupdesc->natts)
7246  return false;
7247 
7248  for (i = 0; i < dst_tupdesc->natts; i++)
7249  {
7250  Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
7251  Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
7252 
7253  if (dattr->attisdropped != sattr->attisdropped)
7254  return false;
7255  if (!dattr->attisdropped)
7256  {
7257  /* Normal columns must match by type and typmod */
7258  if (dattr->atttypid != sattr->atttypid ||
7259  (dattr->atttypmod >= 0 &&
7260  dattr->atttypmod != sattr->atttypmod))
7261  return false;
7262  }
7263  else
7264  {
7265  /* Dropped columns are OK as long as length/alignment match */
7266  if (dattr->attlen != sattr->attlen ||
7267  dattr->attalign != sattr->attalign)
7268  return false;
7269  }
7270  }
7271  return true;
7272 }
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 7638 of file pl_exec.c.

7639 {
7640  char *result;
7641  MemoryContext oldcontext;
7642  Oid typoutput;
7643  bool typIsVarlena;
7644 
7645  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7646  getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
7647  result = OidOutputFunctionCall(typoutput, value);
7648  MemoryContextSwitchTo(oldcontext);
7649 
7650  return result;
7651 }
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1653
static struct @142 value
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2854
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 1281 of file pl_exec.c.

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

7340 {
7341  HeapTupleHeader td;
7342  Oid tupType;
7343  int32 tupTypmod;
7344 
7345  /* Get tuple body (note this could involve detoasting) */
7347 
7348  /* Build a temporary HeapTuple control structure */
7349  tmptup->t_len = HeapTupleHeaderGetDatumLength(td);
7350  ItemPointerSetInvalid(&(tmptup->t_self));
7351  tmptup->t_tableOid = InvalidOid;
7352  tmptup->t_data = td;
7353 
7354  /* Extract rowtype info and find a tupdesc */
7355  tupType = HeapTupleHeaderGetTypeId(td);
7356  tupTypmod = HeapTupleHeaderGetTypMod(td);
7357  return lookup_rowtype_tupdesc(tupType, tupTypmod);
7358 }
signed int int32
Definition: c.h:429
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:295
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:462
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:452
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:446
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
#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:1830

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

7695 {
7696  plpgsql_CastHashEntry *cast_entry;
7697 
7698  cast_entry = get_cast_hashentry(estate,
7699  valtype, valtypmod,
7700  reqtype, reqtypmod);
7701  if (cast_entry)
7702  {
7703  ExprContext *econtext = estate->eval_econtext;
7704  MemoryContext oldcontext;
7705 
7706  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7707 
7708  econtext->caseValue_datum = value;
7709  econtext->caseValue_isNull = *isnull;
7710 
7711  cast_entry->cast_in_use = true;
7712 
7713  value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
7714  isnull);
7715 
7716  cast_entry->cast_in_use = false;
7717 
7718  MemoryContextSwitchTo(oldcontext);
7719  }
7720 
7721  return value;
7722 }
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:316
static plpgsql_CastHashEntry * get_cast_hashentry(PLpgSQL_execstate *estate, Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod)
Definition: pl_exec.c:7735
bool caseValue_isNull
Definition: execnodes.h:258
Datum caseValue_datum
Definition: execnodes.h:256
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 1566 of file pl_exec.c.

1567 {
1568  for (; cond != NULL; cond = cond->next)
1569  {
1570  int sqlerrstate = cond->sqlerrstate;
1571 
1572  /*
1573  * OTHERS matches everything *except* query-canceled and
1574  * assert-failure. If you're foolish enough, you can match those
1575  * explicitly.
1576  */
1577  if (sqlerrstate == 0)
1578  {
1579  if (edata->sqlerrcode != ERRCODE_QUERY_CANCELED &&
1580  edata->sqlerrcode != ERRCODE_ASSERT_FAILURE)
1581  return true;
1582  }
1583  /* Exact match? */
1584  else if (edata->sqlerrcode == sqlerrstate)
1585  return true;
1586  /* Category match? */
1587  else if (ERRCODE_IS_CATEGORY(sqlerrstate) &&
1588  ERRCODE_TO_CATEGORY(edata->sqlerrcode) == sqlerrstate)
1589  return true;
1590  }
1591  return false;
1592 }
#define ERRCODE_IS_CATEGORY(ec)
Definition: elog.h:56
#define ERRCODE_TO_CATEGORY(ec)
Definition: elog.h:55
int sqlerrcode
Definition: elog.h:367
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 5002 of file pl_exec.c.

5004 {
5005  text *value;
5006  MemoryContext oldcontext;
5007 
5008  /* Use eval_mcontext for short-lived text value */
5009  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5010  if (str != NULL)
5012  else
5013  value = cstring_to_text("");
5014  MemoryContextSwitchTo(oldcontext);
5015 
5016  exec_assign_value(estate, target, PointerGetDatum(value), false,
5017  TEXTOID, -1);
5018 }
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:5030
text * cstring_to_text(const char *s)
Definition: varlena.c:189

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

4960 {
4961  Datum value;
4962  bool isnull;
4963  Oid valtype;
4964  int32 valtypmod;
4965 
4966  /*
4967  * If first time through, create a plan for this expression.
4968  */
4969  if (expr->plan == NULL)
4970  {
4971  /*
4972  * Mark the expression as being an assignment source, if target is a
4973  * simple variable. (This is a bit messy, but it seems cleaner than
4974  * modifying the API of exec_prepare_plan for the purpose. We need to
4975  * stash the target dno into the expr anyway, so that it will be
4976  * available if we have to replan.)
4977  */
4978  if (target->dtype == PLPGSQL_DTYPE_VAR)
4979  expr->target_param = target->dno;
4980  else
4981  expr->target_param = -1; /* should be that already */
4982 
4983  exec_prepare_plan(estate, expr, 0);
4984  }
4985 
4986  value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod);
4987  exec_assign_value(estate, target, value, isnull, valtype, valtypmod);
4988  exec_eval_cleanup(estate);
4989 }
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4094
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions)
Definition: pl_exec.c:4131
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5634
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 5030 of file pl_exec.c.

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

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(), and exec_stmt_getdiag().

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

7671 {
7672  /*
7673  * If the type of the given value isn't what's requested, convert it.
7674  */
7675  if (valtype != reqtype ||
7676  (valtypmod != reqtypmod && reqtypmod != -1))
7677  {
7678  /* We keep the slow path out-of-line. */
7679  value = do_cast_value(estate, value, isnull, valtype, valtypmod,
7680  reqtype, reqtypmod);
7681  }
7682 
7683  return value;
7684 }
static Datum do_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7691

References do_cast_value(), and value.

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

◆ exec_check_rw_parameter()

static void exec_check_rw_parameter ( PLpgSQL_expr expr)
static

Definition at line 8131 of file pl_exec.c.

8132 {
8133  int target_dno;
8134  Oid funcid;
8135  List *fargs;
8136  ListCell *lc;
8137 
8138  /* Assume unsafe */
8139  expr->expr_rw_param = NULL;
8140 
8141  /* Done if expression isn't an assignment source */
8142  target_dno = expr->target_param;
8143  if (target_dno < 0)
8144  return;
8145 
8146  /*
8147  * If target variable isn't referenced by expression, no need to look
8148  * further.
8149  */
8150  if (!bms_is_member(target_dno, expr->paramnos))
8151  return;
8152 
8153  /* Shouldn't be here for non-simple expression */
8154  Assert(expr->expr_simple_expr != NULL);
8155 
8156  /*
8157  * Top level of expression must be a simple FuncExpr, OpExpr, or
8158  * SubscriptingRef, else we can't optimize.
8159  */
8160  if (IsA(expr->expr_simple_expr, FuncExpr))
8161  {
8162  FuncExpr *fexpr = (FuncExpr *) expr->expr_simple_expr;
8163 
8164  funcid = fexpr->funcid;
8165  fargs = fexpr->args;
8166  }
8167  else if (IsA(expr->expr_simple_expr, OpExpr))
8168  {
8169  OpExpr *opexpr = (OpExpr *) expr->expr_simple_expr;
8170 
8171  funcid = opexpr->opfuncid;
8172  fargs = opexpr->args;
8173  }
8174  else if (IsA(expr->expr_simple_expr, SubscriptingRef))
8175  {
8176  SubscriptingRef *sbsref = (SubscriptingRef *) expr->expr_simple_expr;
8177 
8178  /* We only trust standard varlena arrays to be safe */
8179  if (get_typsubscript(sbsref->refcontainertype, NULL) !=
8180  F_ARRAY_SUBSCRIPT_HANDLER)
8181  return;
8182 
8183  /* We can optimize the refexpr if it's the target, otherwise not */
8184  if (sbsref->refexpr && IsA(sbsref->refexpr, Param))
8185  {
8186  Param *param = (Param *) sbsref->refexpr;
8187 
8188  if (param->paramkind == PARAM_EXTERN &&
8189  param->paramid == target_dno + 1)
8190  {
8191  /* Found the Param we want to pass as read/write */
8192  expr->expr_rw_param = param;
8193  return;
8194  }
8195  }
8196 
8197  return;
8198  }
8199  else
8200  return;
8201 
8202  /*
8203  * The top-level function must be one that we trust to be "safe".
8204  * Currently we hard-wire the list, but it would be very desirable to
8205  * allow extensions to mark their functions as safe ...
8206  */
8207  if (!(funcid == F_ARRAY_APPEND ||
8208  funcid == F_ARRAY_PREPEND))
8209  return;
8210 
8211  /*
8212  * The target variable (in the form of a Param) must appear as a direct
8213  * argument of the top-level function. References further down in the
8214  * tree can't be optimized; but on the other hand, they don't invalidate
8215  * optimizing the top-level call, since that will be executed last.
8216  */
8217  foreach(lc, fargs)
8218  {
8219  Node *arg = (Node *) lfirst(lc);
8220 
8221  if (arg && IsA(arg, Param))
8222  {
8223  Param *param = (Param *) arg;
8224 
8225  if (param->paramkind == PARAM_EXTERN &&
8226  param->paramid == target_dno + 1)
8227  {
8228  /* Found the Param we want to pass as read/write */
8229  expr->expr_rw_param = param;
8230  return;
8231  }
8232  }
8233  }
8234 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
RegProcedure get_typsubscript(Oid typid, Oid *typelemp)
Definition: lsyscache.c:3044
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
void * arg
#define lfirst(lc)
Definition: pg_list.h:169
@ PARAM_EXTERN
Definition: primnodes.h:258
Oid funcid
Definition: primnodes.h:495
List * args
Definition: primnodes.h:503
Definition: pg_list.h:51
Definition: nodes.h:540
List * args
Definition: primnodes.h:548
Oid opfuncid
Definition: primnodes.h:543
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:268
ParamKind paramkind
Definition: primnodes.h:267
Expr * refexpr
Definition: primnodes.h:449
Oid refcontainertype
Definition: primnodes.h:439

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, OpExpr::opfuncid, PARAM_EXTERN, Param::paramid, Param::paramkind, PLpgSQL_expr::paramnos, SubscriptingRef::refcontainertype, 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 8598 of file pl_exec.c.

8603 {
8604  Portal portal;
8605  Datum query;
8606  bool isnull;
8607  Oid restype;
8608  int32 restypmod;
8609  char *querystr;
8611  MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
8612 
8613  /*
8614  * Evaluate the string expression after the EXECUTE keyword. Its result is
8615  * the querystring we have to execute.
8616  */
8617  query = exec_eval_expr(estate, dynquery, &isnull, &restype, &restypmod);
8618  if (isnull)
8619  ereport(ERROR,
8620  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
8621  errmsg("query string argument of EXECUTE is null")));
8622 
8623  /* Get the C-String representation */
8624  querystr = convert_value_to_string(estate, query, restype);
8625 
8626  /* copy it into the stmt_mcontext before we clean up */
8627  querystr = MemoryContextStrdup(stmt_mcontext, querystr);
8628 
8629  exec_eval_cleanup(estate);
8630 
8631  /*
8632  * Open an implicit cursor for the query. We use SPI_cursor_parse_open
8633  * even when there are no params, because this avoids making and freeing
8634  * one copy of the plan.
8635  */
8636  memset(&options, 0, sizeof(options));
8637  options.params = exec_eval_using_params(estate, params);
8638  options.cursorOptions = cursorOptions;
8639  options.read_only = estate->readonly_func;
8640 
8641  portal = SPI_cursor_parse_open(portalname, querystr, &options);
8642 
8643  if (portal == NULL)
8644  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
8645  querystr, SPI_result_code_string(SPI_result));
8646 
8647  /* Release transient data */
8648  MemoryContextReset(stmt_mcontext);
8649 
8650  return portal;
8651 }
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:143
static char ** options
static char * convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
Definition: pl_exec.c:7638
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1515
static ParamListInfo exec_eval_using_params(PLpgSQL_execstate *estate, List *params)
Definition: pl_exec.c:8516
int SPI_result
Definition: spi.c:47
const char * SPI_result_code_string(int code)
Definition: spi.c:1877
Portal SPI_cursor_parse_open(const char *name, const char *src, const SPIParseOpenOptions *options)
Definition: spi.c:1438

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

5614 {
5615  Datum exprdatum;
5616  Oid exprtypeid;
5617  int32 exprtypmod;
5618 
5619  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5620  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5621  exprtypeid, exprtypmod,
5622  BOOLOID, -1);
5623  return DatumGetBool(exprdatum);
5624 }
#define DatumGetBool(X)
Definition: postgres.h:437

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

4095 {
4096  /* Clear result of a full SPI_execute */
4097  if (estate->eval_tuptable != NULL)
4099  estate->eval_tuptable = NULL;
4100 
4101  /*
4102  * Clear result of exec_eval_simple_expr (but keep the econtext). This
4103  * also clears any short-lived allocations done via get_eval_mcontext.
4104  */
4105  if (estate->eval_econtext != NULL)
4107 }
#define ResetExprContext(econtext)
Definition: executor.h:527
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1291
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 5257 of file pl_exec.c.

5263 {
5264  MemoryContext oldcontext;
5265 
5266  switch (datum->dtype)
5267  {
5268  case PLPGSQL_DTYPE_PROMISE:
5269  /* fulfill promise if needed, then handle like regular var */
5270  plpgsql_fulfill_promise(estate, (PLpgSQL_var *) datum);
5271 
5272  /* FALL THRU */
5273 
5274  case PLPGSQL_DTYPE_VAR:
5275  {
5276  PLpgSQL_var *var = (PLpgSQL_var *) datum;
5277 
5278  *typeid = var->datatype->typoid;
5279  *typetypmod = var->datatype->atttypmod;
5280  *value = var->value;
5281  *isnull = var->isnull;
5282  break;
5283  }
5284 
5285  case PLPGSQL_DTYPE_ROW:
5286  {
5287  PLpgSQL_row *row = (PLpgSQL_row *) datum;
5288  HeapTuple tup;
5289 
5290  /* We get here if there are multiple OUT parameters */
5291  if (!row->rowtupdesc) /* should not happen */
5292  elog(ERROR, "row variable has no tupdesc");
5293  /* Make sure we have a valid type/typmod setting */
5294  BlessTupleDesc(row->rowtupdesc);
5295  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5296  tup = make_tuple_from_row(estate, row, row->rowtupdesc);
5297  if (tup == NULL) /* should not happen */
5298  elog(ERROR, "row not compatible with its own tupdesc");
5299  *typeid = row->rowtupdesc->tdtypeid;
5300  *typetypmod = row->rowtupdesc->tdtypmod;
5301  *value = HeapTupleGetDatum(tup);
5302  *isnull = false;
5303  MemoryContextSwitchTo(oldcontext);
5304  break;
5305  }
5306 
5307  case PLPGSQL_DTYPE_REC:
5308  {
5309  PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
5310 
5311  if (rec->erh == NULL)
5312  {
5313  /* Treat uninstantiated record as a simple NULL */
5314  *value = (Datum) 0;
5315  *isnull = true;
5316  /* Report variable's declared type */
5317  *typeid = rec->rectypeid;
5318  *typetypmod = -1;
5319  }
5320  else
5321  {
5322  if (ExpandedRecordIsEmpty(rec->erh))
5323  {
5324  /* Empty record is also a NULL */
5325  *value = (Datum) 0;
5326  *isnull = true;
5327  }
5328  else
5329  {
5330  *value = ExpandedRecordGetDatum(rec->erh);
5331  *isnull = false;
5332  }
5333  if (rec->rectypeid != RECORDOID)
5334  {
5335  /* Report variable's declared type, if not RECORD */
5336  *typeid = rec->rectypeid;
5337  *typetypmod = -1;
5338  }
5339  else
5340  {
5341  /* Report record's actual type if declared RECORD */
5342  *typeid = rec->erh->er_typeid;
5343  *typetypmod = rec->erh->er_typmod;
5344  }
5345  }
5346  break;
5347  }
5348 
5350  {
5351  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
5352  PLpgSQL_rec *rec;
5353  ExpandedRecordHeader *erh;
5354 
5355  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5356  erh = rec->erh;
5357 
5358  /*
5359  * If record variable is NULL, instantiate it if it has a
5360  * named composite type, else complain. (This won't change
5361  * the logical state of the record: it's still NULL.)
5362  */
5363  if (erh == NULL)
5364  {
5365  instantiate_empty_record_variable(estate, rec);
5366  erh = rec->erh;
5367  }
5368 
5369  /*
5370  * Look up the field's properties if we have not already, or
5371  * if the tuple descriptor ID changed since last time.
5372  */
5373  if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
5374  {
5376  recfield->fieldname,
5377  &recfield->finfo))
5378  ereport(ERROR,
5379  (errcode(ERRCODE_UNDEFINED_COLUMN),
5380  errmsg("record \"%s\" has no field \"%s\"",
5381  rec->refname, recfield->fieldname)));
5382  recfield->rectupledescid = erh->er_tupdesc_id;
5383  }
5384 
5385  /* Report type data. */
5386  *typeid = recfield->finfo.ftypeid;
5387  *typetypmod = recfield->finfo.ftypmod;
5388 
5389  /* And fetch the field value. */
5391  recfield->finfo.fnumber,
5392  isnull);
5393  break;
5394  }
5395 
5396  default:
5397  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
5398  }
5399 }
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2082
#define ExpandedRecordIsEmpty(erh)
static Datum expanded_record_get_field(ExpandedRecordHeader *erh, int fnumber, bool *isnull)
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:220
static void plpgsql_fulfill_promise(PLpgSQL_execstate *estate, PLpgSQL_var *var)
Definition: pl_exec.c:1355
static HeapTuple make_tuple_from_row(PLpgSQL_execstate *estate, PLpgSQL_row *row, TupleDesc tupdesc)
Definition: pl_exec.c:7284
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_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 5634 of file pl_exec.c.

5639 {
5640  Datum result = 0;
5641  int rc;
5642  Form_pg_attribute attr;
5643 
5644  /*
5645  * If first time through, create a plan for this expression.
5646  */
5647  if (expr->plan == NULL)
5649 
5650  /*
5651  * If this is a simple expression, bypass SPI and use the executor
5652  * directly
5653  */
5654  if (exec_eval_simple_expr(estate, expr,
5655  &result, isNull, rettype, rettypmod))
5656  return result;
5657 
5658  /*
5659  * Else do it the hard way via exec_run_select
5660  */
5661  rc = exec_run_select(estate, expr, 2, NULL);
5662  if (rc != SPI_OK_SELECT)
5663  ereport(ERROR,
5664  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5665  errmsg("query did not return data"),
5666  errcontext("query: %s", expr->query)));
5667 
5668  /*
5669  * Check that the expression returns exactly one column...
5670  */
5671  if (estate->eval_tuptable->tupdesc->natts != 1)
5672  ereport(ERROR,
5673  (errcode(ERRCODE_SYNTAX_ERROR),
5674  errmsg_plural("query returned %d column",
5675  "query returned %d columns",
5676  estate->eval_tuptable->tupdesc->natts,
5677  estate->eval_tuptable->tupdesc->natts),
5678  errcontext("query: %s", expr->query)));
5679 
5680  /*
5681  * ... and get the column's datatype.
5682  */
5683  attr = TupleDescAttr(estate->eval_tuptable->tupdesc, 0);
5684  *rettype = attr->atttypid;
5685  *rettypmod = attr->atttypmod;
5686 
5687  /*
5688  * If there are no rows selected, the result is a NULL of that type.
5689  */
5690  if (estate->eval_processed == 0)
5691  {
5692  *isNull = true;
5693  return (Datum) 0;
5694  }
5695 
5696  /*
5697  * Check that the expression returned no more than one row.
5698  */
5699  if (estate->eval_processed != 1)
5700  ereport(ERROR,
5701  (errcode(ERRCODE_CARDINALITY_VIOLATION),
5702  errmsg("query returned more than one row"),
5703  errcontext("query: %s", expr->query)));
5704 
5705  /*
5706  * Return the single result Datum.
5707  */
5708  return SPI_getbinval(estate->eval_tuptable->vals[0],
5709  estate->eval_tuptable->tupdesc, 1, isNull);
5710 }
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1014
#define errcontext
Definition: elog.h:190
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2830
static bool exec_eval_simple_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, Datum *result, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5984
static int exec_run_select(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
Definition: pl_exec.c:5718
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition: spi.c:1157
#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 5588 of file pl_exec.c.

5591 {
5592  Datum exprdatum;
5593  Oid exprtypeid;
5594  int32 exprtypmod;
5595 
5596  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5597  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5598  exprtypeid, exprtypmod,
5599  INT4OID, -1);
5600  return DatumGetInt32(exprdatum);
5601 }
#define DatumGetInt32(X)
Definition: postgres.h:516

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

5990 {
5991  ExprContext *econtext = estate->eval_econtext;
5992  LocalTransactionId curlxid = MyProc->lxid;
5993  ParamListInfo paramLI;
5994  void *save_setup_arg;
5995  bool need_snapshot;
5996  MemoryContext oldcontext;
5997 
5998  /*
5999  * Forget it if expression wasn't simple before.
6000  */
6001  if (expr->expr_simple_expr == NULL)
6002  return false;
6003 
6004  /*
6005  * If expression is in use in current xact, don't touch it.
6006  */
6007  if (unlikely(expr->expr_simple_in_use) &&
6008  expr->expr_simple_lxid == curlxid)
6009  return false;
6010 
6011  /*
6012  * Ensure that there's a portal-level snapshot, in case this simple
6013  * expression is the first thing evaluated after a COMMIT or ROLLBACK.
6014  * We'd have to do this anyway before executing the expression, so we
6015  * might as well do it now to ensure that any possible replanning doesn't
6016  * need to take a new snapshot.
6017  */
6019 
6020  /*
6021  * Check to see if the cached plan has been invalidated. If not, and this
6022  * is the first use in the current transaction, save a plan refcount in
6023  * the simple-expression resowner.
6024  */
6026  expr->expr_simple_plan,
6027  (expr->expr_simple_plan_lxid != curlxid ?
6028  estate->simple_eval_resowner : NULL))))
6029  {
6030  /*
6031  * It's still good, so just remember that we have a refcount on the
6032  * plan in the current transaction. (If we already had one, this
6033  * assignment is a no-op.)
6034  */
6035  expr->expr_simple_plan_lxid = curlxid;
6036  }
6037  else
6038  {
6039  /* Need to replan */
6040  CachedPlan *cplan;
6041 
6042  /*
6043  * If we have a valid refcount on some previous version of the plan,
6044  * release it, so we don't leak plans intra-transaction.
6045  */
6046  if (expr->expr_simple_plan_lxid == curlxid)
6047  {
6049  estate->simple_eval_resowner);
6050  expr->expr_simple_plan = NULL;
6052  }
6053 
6054  /* Do the replanning work in the eval_mcontext */
6055  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6056  cplan = SPI_plan_get_cached_plan(expr->plan);
6057  MemoryContextSwitchTo(oldcontext);
6058 
6059  /*
6060  * We can't get a failure here, because the number of
6061  * CachedPlanSources in the SPI plan can't change from what
6062  * exec_simple_check_plan saw; it's a property of the raw parsetree
6063  * generated from the query text.
6064  */
6065  Assert(cplan != NULL);
6066 
6067  /*
6068  * This test probably can't fail either, but if it does, cope by
6069  * declaring the plan to be non-simple. On success, we'll acquire a
6070  * refcount on the new plan, stored in simple_eval_resowner.
6071  */
6073  cplan,
6074  estate->simple_eval_resowner))
6075  {
6076  /* Remember that we have the refcount */
6077  expr->expr_simple_plan = cplan;
6078  expr->expr_simple_plan_lxid = curlxid;
6079  }
6080  else
6081  {
6082  /* Release SPI_plan_get_cached_plan's refcount */
6084  /* Mark expression as non-simple, and fail */
6085  expr->expr_simple_expr = NULL;
6086  expr->expr_rw_param = NULL;
6087  return false;
6088  }
6089 
6090  /*
6091  * SPI_plan_get_cached_plan acquired a plan refcount stored in the
6092  * active resowner. We don't need that anymore, so release it.
6093  */
6095 
6096  /* Extract desired scalar expression from cached plan */
6097  exec_save_simple_expr(expr, cplan);
6098  }
6099 
6100  /*
6101  * Pass back previously-determined result type.
6102  */
6103  *rettype = expr->expr_simple_type;
6104  *rettypmod = expr->expr_simple_typmod;
6105 
6106  /*
6107  * Set up ParamListInfo to pass to executor. For safety, save and restore
6108  * estate->paramLI->parserSetupArg around our use of the param list.
6109  */
6110  paramLI = estate->paramLI;
6111  save_setup_arg = paramLI->parserSetupArg;
6112 
6113  /*
6114  * We can skip using setup_param_list() in favor of just doing this
6115  * unconditionally, because there's no need for the optimization of
6116  * possibly setting ecxt_param_list_info to NULL; we've already forced use
6117  * of a generic plan.
6118  */
6119  paramLI->parserSetupArg = (void *) expr;
6120  econtext->ecxt_param_list_info = paramLI;
6121 
6122  /*
6123  * Prepare the expression for execution, if it's not been done already in
6124  * the current transaction. (This will be forced to happen if we called
6125  * exec_save_simple_expr above.)
6126  */
6127  if (unlikely(expr->expr_simple_lxid != curlxid))
6128  {
6129  oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
6130  expr->expr_simple_state =
6132  econtext->ecxt_param_list_info);
6133  expr->expr_simple_in_use = false;
6134  expr->expr_simple_lxid = curlxid;
6135  MemoryContextSwitchTo(oldcontext);
6136  }
6137 
6138  /*
6139  * We have to do some of the things SPI_execute_plan would do, in
6140  * particular push a new snapshot so that stable functions within the
6141  * expression can see updates made so far by our own function. However,
6142  * we can skip doing that (and just invoke the expression with the same
6143  * snapshot passed to our function) in some cases, which is useful because
6144  * it's quite expensive relative to the cost of a simple expression. We
6145  * can skip it if the expression contains no stable or volatile functions;
6146  * immutable functions shouldn't need to see our updates. Also, if this
6147  * is a read-only function, we haven't made any updates so again it's okay
6148  * to skip.
6149  */
6150  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6151  need_snapshot = (expr->expr_simple_mutable && !estate->readonly_func);
6152  if (need_snapshot)
6153  {
6156  }
6157 
6158  /*
6159  * Mark expression as busy for the duration of the ExecEvalExpr call.
6160  */
6161  expr->expr_simple_in_use = true;
6162 
6163  /*
6164  * Finally we can call the executor to evaluate the expression
6165  */
6166  *result = ExecEvalExpr(expr->expr_simple_state,
6167  econtext,
6168  isNull);
6169 
6170  /* Assorted cleanup */
6171  expr->expr_simple_in_use = false;
6172 
6173  econtext->ecxt_param_list_info = NULL;
6174 
6175  paramLI->parserSetupArg = save_setup_arg;
6176 
6177  if (need_snapshot)
6179 
6180  MemoryContextSwitchTo(oldcontext);
6181 
6182  /*
6183  * That's it.
6184  */
6185  return true;
6186 }
#define likely(x)
Definition: c.h:272
uint32 LocalTransactionId
Definition: c.h:589
ExprState * ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
Definition: execExpr.c:160
#define InvalidLocalTransactionId
Definition: lock.h:70
static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
Definition: pl_exec.c:8024
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:1777
ResourceOwner CurrentResourceOwner
Definition: resowner.c:146
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:250
void PopActiveSnapshot(void)
Definition: snapmgr.c:774
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:680
CachedPlan * SPI_plan_get_cached_plan(SPIPlanPtr plan)
Definition: spi.c:1973
PGPROC * MyProc
Definition: proc.c:68
MemoryContext es_query_cxt
Definition: execnodes.h:605
ParamListInfo ecxt_param_list_info
Definition: execnodes.h:243
LocalTransactionId lxid
Definition: proc.h:146
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:1073

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

8517 {
8518  ParamListInfo paramLI;
8519  int nargs;
8520  MemoryContext stmt_mcontext;
8521  MemoryContext oldcontext;
8522  int i;
8523  ListCell *lc;
8524 
8525  /* Fast path for no parameters: we can just return NULL */
8526  if (params == NIL)
8527  return NULL;
8528 
8529  nargs = list_length(params);
8530  stmt_mcontext = get_stmt_mcontext(estate);
8531  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8532  paramLI = makeParamList(nargs);
8533  MemoryContextSwitchTo(oldcontext);
8534 
8535  i = 0;
8536  foreach(lc, params)
8537  {
8538  PLpgSQL_expr *param = (PLpgSQL_expr *) lfirst(lc);
8539  ParamExternData *prm = &paramLI->params[i];
8540  int32 ppdtypmod;
8541 
8542  /*
8543  * Always mark params as const, since we only use the result with
8544  * one-shot plans.
8545  */
8546  prm->pflags = PARAM_FLAG_CONST;
8547 
8548  prm->value = exec_eval_expr(estate, param,
8549  &prm->isnull,
8550  &prm->ptype,
8551  &ppdtypmod);
8552 
8553  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8554 
8555  if (prm->ptype == UNKNOWNOID)
8556  {
8557  /*
8558  * Treat 'unknown' parameters as text, since that's what most
8559  * people would expect. The SPI functions can coerce unknown
8560  * constants in a more intelligent way, but not unknown Params.
8561  * This code also takes care of copying into the right context.
8562  * Note we assume 'unknown' has the representation of C-string.
8563  */
8564  prm->ptype = TEXTOID;
8565  if (!prm->isnull)
8567  }
8568  /* pass-by-ref non null values must be copied into stmt_mcontext */
8569  else if (!prm->isnull)
8570  {
8571  int16 typLen;
8572  bool typByVal;
8573 
8574  get_typlenbyval(prm->ptype, &typLen, &typByVal);
8575  if (!typByVal)
8576  prm->value = datumCopy(prm->value, typByVal, typLen);
8577  }
8578 
8579  MemoryContextSwitchTo(oldcontext);
8580 
8581  exec_eval_cleanup(estate);
8582 
8583  i++;
8584  }
8585 
8586  return paramLI;
8587 }
signed short int16
Definition: c.h:428
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2198
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:149
#define NIL
Definition: pg_list.h:65
#define DatumGetCString(X)
Definition: postgres.h:610
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 5802 of file pl_exec.c.

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

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

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

◆ exec_init_tuple_store()

static void exec_init_tuple_store ( PLpgSQL_execstate estate)
static

Definition at line 3639 of file pl_exec.c.

3640 {
3641  ReturnSetInfo *rsi = estate->rsi;
3642  MemoryContext oldcxt;
3643  ResourceOwner oldowner;
3644 
3645  /*
3646  * Check caller can handle a set result in the way we want
3647  */
3648  if (!rsi || !IsA(rsi, ReturnSetInfo) ||
3649  (rsi->allowedModes & SFRM_Materialize) == 0 ||
3650  rsi->expectedDesc == NULL)
3651  ereport(ERROR,
3652  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3653  errmsg("set-valued function called in context that cannot accept a set")));
3654 
3655  /*
3656  * Switch to the right memory context and resource owner for storing the
3657  * tuplestore for return set. If we're within a subtransaction opened for
3658  * an exception-block, for example, we must still create the tuplestore in
3659  * the resource owner that was active when this function was entered, and
3660  * not in the subtransaction resource owner.
3661  */
3662  oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
3663  oldowner = CurrentResourceOwner;
3665 
3666  estate->tuple_store =
3668  false, work_mem);
3669 
3670  CurrentResourceOwner = oldowner;
3671  MemoryContextSwitchTo(oldcxt);
3672 
3673  estate->tuple_store_desc = rsi->expectedDesc;
3674 }
@ SFRM_Materialize_Random
Definition: execnodes.h:294
@ SFRM_Materialize
Definition: execnodes.h:293
int work_mem
Definition: globals.c:124
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:309
int allowedModes
Definition: execnodes.h:310
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 6696 of file pl_exec.c.

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

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

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

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

4133 {
4134  SPIPlanPtr plan;
4136 
4137  /*
4138  * The grammar can't conveniently set expr->func while building the parse
4139  * tree, so make sure it's set before parser hooks need it.
4140  */
4141  expr->func = estate->func;
4142 
4143  /*
4144  * Generate and save the plan
4145  */
4146  memset(&options, 0, sizeof(options));
4148  options.parserSetupArg = (void *) expr;
4149  options.parseMode = expr->parseMode;
4150  options.cursorOptions = cursorOptions;
4151  plan = SPI_prepare_extended(expr->query, &options);
4152  if (plan == NULL)
4153  elog(ERROR, "SPI_prepare_extended failed for \"%s\": %s",
4155 
4156  SPI_keepplan(plan);
4157  expr->plan = plan;
4158 
4159  /* Check to see if it's a simple expression */
4160  exec_simple_check_plan(estate, expr);
4161 }
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:7905
SPIPlanPtr SPI_prepare_extended(const char *src, const SPIPrepareOptions *options)
Definition: spi.c:807
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:881
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 5718 of file pl_exec.c.

5720 {
5721  ParamListInfo paramLI;
5722  int rc;
5723 
5724  /*
5725  * On the first call for this expression generate the plan.
5726  *
5727  * If we don't need to return a portal, then we're just going to execute
5728  * the query immediately, which means it's OK to use a parallel plan, even
5729  * if the number of rows being fetched is limited. If we do need to
5730  * return a portal (i.e., this is for a FOR loop), the user's code might
5731  * invoke additional operations inside the FOR loop, making parallel query
5732  * unsafe. In any case, we don't expect any cursor operations to be done,
5733  * so specify NO_SCROLL for efficiency and semantic safety.
5734  */
5735  if (expr->plan == NULL)
5736  {
5737  int cursorOptions = CURSOR_OPT_NO_SCROLL;
5738 
5739  if (portalP == NULL)
5740  cursorOptions |= CURSOR_OPT_PARALLEL_OK;
5741  exec_prepare_plan(estate, expr, cursorOptions);
5742  }
5743 
5744  /*
5745  * Set up ParamListInfo to pass to executor
5746  */
5747  paramLI = setup_param_list(estate, expr);
5748 
5749  /*
5750  * If a portal was requested, put the query and paramlist into the portal
5751  */
5752  if (portalP != NULL)
5753  {
5754  *portalP = SPI_cursor_open_with_paramlist(NULL, expr->plan,
5755  paramLI,
5756  estate->readonly_func);
5757  if (*portalP == NULL)
5758  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
5760  exec_eval_cleanup(estate);
5761  return SPI_OK_CURSOR;
5762  }
5763 
5764  /*
5765  * Execute the query
5766  */
5767  rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
5768  estate->readonly_func, maxtuples);
5769  if (rc != SPI_OK_SELECT)
5770  {
5771  /*
5772  * SELECT INTO deserves a special error message, because "query is not
5773  * a SELECT" is not very helpful in that case.
5774  */
5775  if (rc == SPI_OK_SELINTO)
5776  ereport(ERROR,
5777  (errcode(ERRCODE_SYNTAX_ERROR),
5778  errmsg("query is SELECT INTO, but it should be plain SELECT"),
5779  errcontext("query: %s", expr->query)));
5780  else
5781  ereport(ERROR,
5782  (errcode(ERRCODE_SYNTAX_ERROR),
5783  errmsg("query is not a SELECT"),
5784  errcontext("query: %s", expr->query)));
5785  }
5786 
5787  /* Save query results for eventual cleanup */
5788  Assert(estate->eval_tuptable == NULL);
5789  estate->eval_tuptable = SPI_tuptable;
5790  estate->eval_processed = SPI_processed;
5791 
5792  return rc;
5793 }
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2822
static ParamListInfo setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:6205
int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params, bool read_only, long tcount)
Definition: spi.c:638
Portal SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan, ParamListInfo params, bool read_only)
Definition: spi.c:1430
#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 8024 of file pl_exec.c.

8025 {
8026  PlannedStmt *stmt;
8027  Plan *plan;
8028  Expr *tle_expr;
8029 
8030  /*
8031  * Given the checks that exec_simple_check_plan did, none of the Asserts
8032  * here should ever fail.
8033  */
8034 
8035  /* Extract the single PlannedStmt */
8036  Assert(list_length(cplan->stmt_list) == 1);
8037  stmt = linitial_node(PlannedStmt, cplan->stmt_list);
8038  Assert(stmt->commandType == CMD_SELECT);
8039 
8040  /*
8041  * Ordinarily, the plan node should be a simple Result. However, if
8042  * force_parallel_mode is on, the planner might've stuck a Gather node
8043  * atop that. The simplest way to deal with this is to look through the
8044  * Gather node. The Gather node's tlist would normally contain a Var
8045  * referencing the child node's output, but it could also be a Param, or
8046  * it could be a Const that setrefs.c copied as-is.
8047  */
8048  plan = stmt->planTree;
8049  for (;;)
8050  {
8051  /* Extract the single tlist expression */
8052  Assert(list_length(plan->targetlist) == 1);
8053  tle_expr = linitial_node(TargetEntry, plan->targetlist)->expr;
8054 
8055  if (IsA(plan, Result))
8056  {
8057  Assert(plan->lefttree == NULL &&
8058  plan->righttree == NULL &&
8059  plan->initPlan == NULL &&
8060  plan->qual == NULL &&
8061  ((Result *) plan)->resconstantqual == NULL);
8062  break;
8063  }
8064  else if (IsA(plan, Gather))
8065  {
8066  Assert(plan->lefttree != NULL &&
8067  plan->righttree == NULL &&
8068  plan->initPlan == NULL &&
8069  plan->qual == NULL);
8070  /* If setrefs.c copied up a Const, no need to look further */
8071  if (IsA(tle_expr, Const))
8072  break;
8073  /* Otherwise, it had better be a Param or an outer Var */
8074  Assert(IsA(tle_expr, Param) || (IsA(tle_expr, Var) &&
8075  ((Var *) tle_expr)->varno == OUTER_VAR));
8076  /* Descend to the child node */
8077  plan = plan->lefttree;
8078  }
8079  else
8080  elog(ERROR, "unexpected plan node type: %d",
8081  (int) nodeTag(plan));
8082  }
8083 
8084  /*
8085  * Save the simple expression, and initialize state to "not valid in
8086  * current transaction".
8087  */
8088  expr->expr_simple_expr = tle_expr;
8089  expr->expr_simple_state = NULL;
8090  expr->expr_simple_in_use = false;
8092  /* Also stash away the expression result type */
8093  expr->expr_simple_type = exprType((Node *) tle_expr);
8094  expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
8095  /* We also want to remember if it is immutable or not */
8096  expr->expr_simple_mutable = contain_mutable_functions((Node *) tle_expr);
8097 
8098  /*
8099  * Lastly, check to see if there's a possibility of optimizing a
8100  * read/write parameter.
8101  */
8103 }
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:364
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:267
#define nodeTag(nodeptr)
Definition: nodes.h:544
@ CMD_SELECT
Definition: nodes.h:686
#define linitial_node(type, l)
Definition: pg_list.h:177
static void exec_check_rw_parameter(PLpgSQL_expr *expr)
Definition: pl_exec.c:8131
#define OUTER_VAR
Definition: primnodes.h:176
List * stmt_list
Definition: plancache.h:150
struct Plan * lefttree
Definition: plannodes.h:143
struct Plan * righttree
Definition: plannodes.h:144
List * qual
Definition: plannodes.h:142
List * targetlist
Definition: plannodes.h:141
List * initPlan
Definition: plannodes.h:145
struct Plan * planTree
Definition: plannodes.h:64
CmdType commandType
Definition: plannodes.h:46
Definition: primnodes.h:187

References Assert(), CMD_SELECT, PlannedStmt::commandType, 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, PlannedStmt::planTree, Plan::qual, Plan::righttree, 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

◆ exec_simple_check_plan()

static void exec_simple_check_plan ( PLpgSQL_execstate estate,
PLpgSQL_expr expr 
)
static

Definition at line 7905 of file pl_exec.c.

7906 {
7907  List *plansources;
7908  CachedPlanSource *plansource;
7909  Query *query;
7910  CachedPlan *cplan;
7911  MemoryContext oldcontext;
7912 
7913  /*
7914  * Initialize to "not simple".
7915  */
7916  expr->expr_simple_expr = NULL;
7917  expr->expr_rw_param = NULL;
7918 
7919  /*
7920  * Check the analyzed-and-rewritten form of the query to see if we will be
7921  * able to treat it as a simple expression. Since this function is only
7922  * called immediately after creating the CachedPlanSource, we need not
7923  * worry about the query being stale.
7924  */
7925 
7926  /*
7927  * We can only test queries that resulted in exactly one CachedPlanSource
7928  */
7929  plansources = SPI_plan_get_plan_sources(expr->plan);
7930  if (list_length(plansources) != 1)
7931  return;
7932  plansource = (CachedPlanSource *) linitial(plansources);
7933 
7934  /*
7935  * 1. There must be one single querytree.
7936  */
7937  if (list_length(plansource->query_list) != 1)
7938  return;
7939  query = (Query *) linitial(plansource->query_list);
7940 
7941  /*
7942  * 2. It must be a plain SELECT query without any input tables
7943  */
7944  if (!IsA(query, Query))
7945  return;
7946  if (query->commandType != CMD_SELECT)
7947  return;
7948  if (query->rtable != NIL)
7949  return;
7950 
7951  /*
7952  * 3. Can't have any subplans, aggregates, qual clauses either. (These
7953  * tests should generally match what inline_function() checks before
7954  * inlining a SQL function; otherwise, inlining could change our
7955  * conclusion about whether an expression is simple, which we don't want.)
7956  */
7957  if (query->hasAggs ||
7958  query->hasWindowFuncs ||
7959  query->hasTargetSRFs ||
7960  query->hasSubLinks ||
7961  query->cteList ||
7962  query->jointree->fromlist ||
7963  query->jointree->quals ||
7964  query->groupClause ||
7965  query->groupingSets ||
7966  query->havingQual ||
7967  query->windowClause ||
7968  query->distinctClause ||
7969  query->sortClause ||
7970  query->limitOffset ||
7971  query->limitCount ||
7972  query->setOperations)
7973  return;
7974 
7975  /*
7976  * 4. The query must have a single attribute as result
7977  */
7978  if (list_length(query->targetList) != 1)
7979  return;
7980 
7981  /*
7982  * OK, we can treat it as a simple plan.
7983  *
7984  * Get the generic plan for the query. If replanning is needed, do that
7985  * work in the eval_mcontext. (Note that replanning could throw an error,
7986  * in which case the expr is left marked "not simple", which is fine.)
7987  */
7988  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7989  cplan = SPI_plan_get_cached_plan(expr->plan);
7990  MemoryContextSwitchTo(oldcontext);
7991 
7992  /* Can't fail, because we checked for a single CachedPlanSource above */
7993  Assert(cplan != NULL);
7994 
7995  /*
7996  * Verify that plancache.c thinks the plan is simple enough to use
7997  * CachedPlanIsSimplyValid. Given the restrictions above, it's unlikely
7998  * that this could fail, but if it does, just treat plan as not simple. On
7999  * success, save a refcount on the plan in the simple-expression resowner.
8000  */
8001  if (CachedPlanAllowsSimpleValidityCheck(plansource, cplan,
8002  estate->simple_eval_resowner))
8003  {
8004  /* Remember that we have the refcount */
8005  expr->expr_simple_plansource = plansource;
8006  expr->expr_simple_plan = cplan;
8008 
8009  /* Share the remaining work with the replan code path */
8010  exec_save_simple_expr(expr, cplan);
8011  }
8012 
8013  /*
8014  * Release the plan refcount obtained by SPI_plan_get_cached_plan. (This
8015  * refcount is held by the wrong resowner, so we can't just repurpose it.)
8016  */
8018 }
#define linitial(l)
Definition: pg_list.h:174
List * SPI_plan_get_plan_sources(SPIPlanPtr plan)
Definition: spi.c:1954
List * query_list
Definition: plancache.h:111
Node * quals
Definition: primnodes.h:1565
List * fromlist
Definition: primnodes.h:1564
bool hasWindowFuncs
Definition: parsenodes.h:133
Node * limitCount
Definition: parsenodes.h:171
FromExpr * jointree
Definition: parsenodes.h:147
Node * setOperations
Definition: parsenodes.h:176
List * cteList
Definition: parsenodes.h:144
bool hasTargetSRFs
Definition: parsenodes.h:134
List * groupClause
Definition: parsenodes.h:157
Node * havingQual
Definition: parsenodes.h:162
List * rtable
Definition: parsenodes.h:146
Node * limitOffset
Definition: parsenodes.h:170
bool hasAggs
Definition: parsenodes.h:132
CmdType commandType
Definition: parsenodes.h:119
List * windowClause
Definition: parsenodes.h:164
List * targetList
Definition: parsenodes.h:149
bool hasSubLinks
Definition: parsenodes.h:135
List * groupingSets
Definition: parsenodes.h:160
List * distinctClause
Definition: parsenodes.h:166
List * sortClause
Definition: parsenodes.h:168

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::hasAggs, Query::hasSubLinks, Query::hasTargetSRFs, Query::hasWindowFuncs, Query::havingQual, IsA, Query::jointree, Query::limitCount, Query::limitOffset, linitial, list_length(), PGPROC::lxid, MemoryContextSwitchTo(), MyProc, NIL, PLpgSQL_expr::plan, FromExpr::quals, CachedPlanSource::query_list, ReleaseCachedPlan(), Query::rtable, Query::setOperations, PLpgSQL_execstate::simple_eval_resowner, Query::sortClause, SPI_plan_get_cached_plan(), SPI_plan_get_plan_sources(), Query::targetList, and Query::windowClause.

Referenced by exec_prepare_plan().

◆ exec_stmt_assert()

static int exec_stmt_assert ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assert stmt 
)
static

Definition at line 3902 of file pl_exec.c.

3903 {
3904  bool value;
3905  bool isnull;
3906 
3907  /* do nothing when asserts are not enabled */
3908  if (!plpgsql_check_asserts)
3909  return PLPGSQL_RC_OK;
3910 
3911  value = exec_eval_boolean(estate, stmt->cond, &isnull);
3912  exec_eval_cleanup(estate);
3913 
3914  if (isnull || !value)
3915  {
3916  char *message = NULL;
3917 
3918  if (stmt->message != NULL)
3919  {
3920  Datum val;
3921  Oid typeid;
3922  int32 typmod;
3923 
3924  val = exec_eval_expr(estate, stmt->message,
3925  &isnull, &typeid, &typmod);
3926  if (!isnull)
3927  message = convert_value_to_string(estate, val, typeid);
3928  /* we mustn't do exec_eval_cleanup here */
3929  }
3930 
3931  ereport(ERROR,
3932  (errcode(ERRCODE_ASSERT_FAILURE),
3933  message ? errmsg_internal("%s", message) :
3934  errmsg("assertion failed")));
3935  }
3936 
3937  return PLPGSQL_RC_OK;
3938 }
int errmsg_internal(const char *fmt,...)
Definition: elog.c:991
long val
Definition: informix.c:664
static bool exec_eval_boolean(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
Definition: pl_exec.c:5611
bool plpgsql_check_asserts
Definition: pl_handler.c:48
PLpgSQL_expr * cond
Definition: plpgsql.h:883
PLpgSQL_expr * message
Definition: plpgsql.h:884

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

Referenced by exec_stmts().

◆ exec_stmt_assign()

static int exec_stmt_assign ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assign stmt 
)
static

Definition at line 2135 of file pl_exec.c.

2136 {
2137  Assert(stmt->varno >= 0);
2138 
2139  exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);
2140 
2141  return PLPGSQL_RC_OK;
2142 }
static void exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
Definition: pl_exec.c:4958
PLpgSQL_expr * expr
Definition: plpgsql.h:519

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

Referenced by exec_stmts().

◆ exec_stmt_block()

static int exec_stmt_block ( PLpgSQL_execstate estate,
PLpgSQL_stmt_block block 
)
static

Definition at line 1634 of file pl_exec.c.

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

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

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

References Assert(), elog, ERROR, exec_eval_cleanup(), exec_move_row(), exec_prepare_plan(), PLpgSQL_stmt_call::expr, PLpgSQL_expr::expr_simple_expr, PLpgSQL_stmt_call::is_call, 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, PLpgSQL_stmt_call::target, 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 2516 of file pl_exec.c.

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

References assign_simple_var(), PLpgSQL_type::atttypmod, PLpgSQL_stmt_case::case_when_list, PLpgSQL_var::datatype, PLpgSQL_execstate::datums, PLpgSQL_stmt_case::else_stmts, 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, PLpgSQL_stmt_case::have_else, if(), lfirst, plpgsql_build_datatype(), PLpgSQL_case_when::stmts, PLpgSQL_stmt_case::t_expr, PLpgSQL_stmt_case::t_varno, 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 4862 of file pl_exec.c.

4863 {
4864  PLpgSQL_var *curvar;
4865  Portal portal;
4866  char *curname;
4867  MemoryContext oldcontext;
4868 
4869  /* ----------
4870  * Get the portal of the cursor by name
4871  * ----------
4872  */
4873  curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
4874  if (curvar->isnull)
4875  ereport(ERROR,
4876  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4877  errmsg("cursor variable \"%s\" is null", curvar->refname)));
4878 
4879  /* Use eval_mcontext for short-lived string */
4880  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
4881  curname = TextDatumGetCString(curvar->value);
4882  MemoryContextSwitchTo(oldcontext);
4883 
4884  portal = SPI_cursor_find(curname);
4885  if (portal == NULL)
4886  ereport(ERROR,
4887  (errcode(ERRCODE_UNDEFINED_CURSOR),
4888  errmsg("cursor \"%s\" does not exist", curname)));
4889 
4890  /* ----------
4891  * And close it.
4892  * ----------
4893  */
4894  SPI_cursor_close(portal);
4895 
4896  return PLPGSQL_RC_OK;
4897 }
#define TextDatumGetCString(d)
Definition: builtins.h:86
Portal SPI_cursor_find(const char *name)
Definition: spi.c:1699
void SPI_cursor_close(Portal portal)
Definition: spi.c:1767

References PLpgSQL_stmt_close::curvar, 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(), 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 4905 of file pl_exec.c.

4906 {
4907  if (stmt->chain)
4909  else
4910  {
4911  SPI_commit();
4913  }
4914 
4915  /*
4916  * We need to build new simple-expression infrastructure, since the old
4917  * data structures are gone.
4918  */
4919  estate->simple_eval_estate = NULL;
4920  estate->simple_eval_resowner = NULL;
4921  plpgsql_create_econtext(estate);
4922 
4923  return PLPGSQL_RC_OK;
4924 }
void SPI_commit(void)
Definition: spi.c:280
void SPI_commit_and_chain(void)
Definition: spi.c:286
void SPI_start_transaction(void)
Definition: spi.c:218

References PLpgSQL_stmt_commit::chain, plpgsql_create_econtext(), PLPGSQL_RC_OK, PLpgSQL_execstate::simple_eval_estate, PLpgSQL_execstate::simple_eval_resowner, SPI_commit(), SPI_commit_and_chain(), and SPI_start_transaction().

Referenced by exec_stmts().

◆ exec_stmt_dynexecute()

static int exec_stmt_dynexecute ( PLpgSQL_execstate estate,
PLpgSQL_stmt_dynexecute stmt 
)
static

Definition at line 4400 of file pl_exec.c.

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

References convert_value_to_string(), PLpgSQL_execstate::datums, PLpgSQL_variable::dno, 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(), PLpgSQL_stmt_dynexecute::into, MemoryContextReset(), MemoryContextStrdup(), options, PLpgSQL_stmt_dynexecute::params, PLPGSQL_RC_OK, PLpgSQL_function::print_strict_params, PLpgSQL_stmt_dynexecute::query, 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_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, PLpgSQL_stmt_dynexecute::strict, PLpgSQL_stmt_dynexecute::target, 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 4588 of file pl_exec.c.

4589 {
4590  Portal portal;
4591  int rc;
4592 
4593  portal = exec_dynquery_with_params(estate, stmt->query, stmt->params,
4594  NULL, CURSOR_OPT_NO_SCROLL);
4595 
4596  /*
4597  * Execute the loop
4598  */
4599  rc = exec_for_query(estate, (PLpgSQL_stmt_forq *) stmt, portal, true);
4600 
4601  /*
4602  * Close the implicit cursor
4603  */
4604  SPI_cursor_close(portal);
4605 
4606  return rc;
4607 }
static int exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt, Portal portal, bool prefetch_ok)
Definition: pl_exec.c:5802
static Portal exec_dynquery_with_params(PLpgSQL_execstate *estate, PLpgSQL_expr *dynquery, List *params, const char *portalname, int cursorOptions)
Definition: pl_exec.c:8598
PLpgSQL_expr * query
Definition: plpgsql.h:738

References CURSOR_OPT_NO_SCROLL, exec_dynquery_with_params(), exec_for_query(), PLpgSQL_stmt_dynfors::params, PLpgSQL_stmt_dynfors::query, and SPI_cursor_close().

Referenced by exec_stmts().

◆ exec_stmt_execsql()

static int exec_stmt_execsql ( PLpgSQL_execstate estate,
PLpgSQL_stmt_execsql stmt 
)
static

Definition at line 4172 of file pl_exec.c.

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

References Assert(), CachedPlanSource::commandTag, CURSOR_OPT_PARALLEL_OK, PLpgSQL_execstate::datums, PLpgSQL_variable::dno, 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(), PLpgSQL_stmt_execsql::into, lfirst, PLpgSQL_stmt_execsql::mod_stmt, PLpgSQL_stmt_execsql::mod_stmt_set, 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_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, PLpgSQL_stmt_execsql::sqlstmt, PLpgSQL_stmt_execsql::strict, PLpgSQL_stmt_execsql::target, 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 3120 of file pl_exec.c.

3121 {
3122  /*
3123  * If the exit / continue has a condition, evaluate it
3124  */
3125  if (stmt->cond != NULL)
3126  {
3127  bool value;
3128  bool isnull;
3129 
3130  value = exec_eval_boolean(estate, stmt->cond, &isnull);
3131  exec_eval_cleanup(estate);
3132  if (isnull || value == false)
3133  return PLPGSQL_RC_OK;
3134  }
3135 
3136  estate->exitlabel = stmt->label;
3137  if (stmt->is_exit)
3138  return PLPGSQL_RC_EXIT;
3139  else
3140  return PLPGSQL_RC_CONTINUE;
3141 }
PLpgSQL_expr * cond
Definition: plpgsql.h:811

References PLpgSQL_stmt_exit::cond, exec_eval_boolean(), exec_eval_cleanup(), PLpgSQL_execstate::exitlabel, PLpgSQL_stmt_exit::is_exit, PLpgSQL_stmt_exit::label, PLPGSQL_RC_CONTINUE, PLPGSQL_RC_EXIT, PLPGSQL_RC_OK, 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 4771 of file pl_exec.c.

4772 {
4773  PLpgSQL_var *curvar;
4774  long how_many = stmt->how_many;
4775  SPITupleTable *tuptab;
4776  Portal portal;
4777  char *curname;
4778  uint64 n;
4779  MemoryContext oldcontext;
4780 
4781  /* ----------
4782  * Get the portal of the cursor by name
4783  * ----------
4784  */
4785  curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
4786  if (curvar->isnull)
4787  ereport(ERROR,
4788  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4789  errmsg("cursor variable \"%s\" is null", curvar->refname)));
4790 
4791  /* Use eval_mcontext for short-lived string */
4792  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
4793  curname = TextDatumGetCString(curvar->value);
4794  MemoryContextSwitchTo(oldcontext);
4795 
4796  portal = SPI_cursor_find(curname);
4797  if (portal == NULL)
4798  ereport(ERROR,
4799  (errcode(ERRCODE_UNDEFINED_CURSOR),
4800  errmsg("cursor \"%s\" does not exist", curname)));
4801 
4802  /* Calculate position for FETCH_RELATIVE or FETCH_ABSOLUTE */
4803  if (stmt->expr)
4804  {
4805  bool isnull;
4806 
4807  /* XXX should be doing this in LONG not INT width */
4808  how_many = exec_eval_integer(estate, stmt->expr, &isnull);
4809 
4810  if (isnull)
4811  ereport(ERROR,
4812  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4813  errmsg("relative or absolute cursor position is null")));
4814 
4815  exec_eval_cleanup(estate);
4816  }
4817 
4818  if (!stmt->is_move)
4819  {
4820  PLpgSQL_variable *target;
4821 
4822  /* ----------
4823  * Fetch 1 tuple from the cursor
4824  * ----------
4825  */
4826  SPI_scroll_cursor_fetch(portal, stmt->direction, how_many);
4827  tuptab = SPI_tuptable;
4828  n = SPI_processed;
4829 
4830  /* ----------
4831