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

Go to the source code of this file.

Data Structures

struct  SimpleEcontextStackEntry
 
struct  plpgsql_CastHashKey
 
struct  plpgsql_CastHashEntry
 

Macros

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

Typedefs

typedef struct SimpleEcontextStackEntry SimpleEcontextStackEntry
 

Functions

static void coerce_function_result_tuple (PLpgSQL_execstate *estate, TupleDesc tupdesc)
 
static void plpgsql_exec_error_callback (void *arg)
 
static void copy_plpgsql_datums (PLpgSQL_execstate *estate, PLpgSQL_function *func)
 
static void plpgsql_fulfill_promise (PLpgSQL_execstate *estate, PLpgSQL_var *var)
 
static MemoryContext get_stmt_mcontext (PLpgSQL_execstate *estate)
 
static void push_stmt_mcontext (PLpgSQL_execstate *estate)
 
static void pop_stmt_mcontext (PLpgSQL_execstate *estate)
 
static int exec_toplevel_block (PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
 
static int exec_stmt_block (PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
 
static int exec_stmts (PLpgSQL_execstate *estate, List *stmts)
 
static int exec_stmt_assign (PLpgSQL_execstate *estate, PLpgSQL_stmt_assign *stmt)
 
static int exec_stmt_perform (PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
 
static int exec_stmt_call (PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
 
static int exec_stmt_getdiag (PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
 
static int exec_stmt_if (PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
 
static int exec_stmt_case (PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
 
static int exec_stmt_loop (PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
 
static int exec_stmt_while (PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
 
static int exec_stmt_fori (PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
 
static int exec_stmt_fors (PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
 
static int exec_stmt_forc (PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt)
 
static int exec_stmt_foreach_a (PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt)
 
static int exec_stmt_open (PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
 
static int exec_stmt_fetch (PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
 
static int exec_stmt_close (PLpgSQL_execstate *estate, PLpgSQL_stmt_close *stmt)
 
static int exec_stmt_exit (PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt)
 
static int exec_stmt_return (PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
 
static int exec_stmt_return_next (PLpgSQL_execstate *estate, PLpgSQL_stmt_return_next *stmt)
 
static int exec_stmt_return_query (PLpgSQL_execstate *estate, PLpgSQL_stmt_return_query *stmt)
 
static int exec_stmt_raise (PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 
static int exec_stmt_assert (PLpgSQL_execstate *estate, PLpgSQL_stmt_assert *stmt)
 
static int exec_stmt_execsql (PLpgSQL_execstate *estate, PLpgSQL_stmt_execsql *stmt)
 
static int exec_stmt_dynexecute (PLpgSQL_execstate *estate, PLpgSQL_stmt_dynexecute *stmt)
 
static int exec_stmt_dynfors (PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
 
static int exec_stmt_commit (PLpgSQL_execstate *estate, PLpgSQL_stmt_commit *stmt)
 
static int exec_stmt_rollback (PLpgSQL_execstate *estate, PLpgSQL_stmt_rollback *stmt)
 
static void plpgsql_estate_setup (PLpgSQL_execstate *estate, PLpgSQL_function *func, ReturnSetInfo *rsi, EState *simple_eval_estate, ResourceOwner simple_eval_resowner)
 
static void exec_eval_cleanup (PLpgSQL_execstate *estate)
 
static void exec_prepare_plan (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions)
 
static void exec_simple_check_plan (PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
 
static void exec_save_simple_expr (PLpgSQL_expr *expr, CachedPlan *cplan)
 
static void exec_check_rw_parameter (PLpgSQL_expr *expr)
 
static void exec_check_assignable (PLpgSQL_execstate *estate, int dno)
 
static bool exec_eval_simple_expr (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, Datum *result, bool *isNull, Oid *rettype, int32 *rettypmod)
 
static void exec_assign_expr (PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
 
static void exec_assign_c_string (PLpgSQL_execstate *estate, PLpgSQL_datum *target, const char *str)
 
static void exec_assign_value (PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
 
static void exec_eval_datum (PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeid, int32 *typetypmod, Datum *value, bool *isnull)
 
static int exec_eval_integer (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
 
static bool exec_eval_boolean (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
 
static Datum exec_eval_expr (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
 
static int exec_run_select (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
 
static int exec_for_query (PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt, Portal portal, bool prefetch_ok)
 
static ParamListInfo setup_param_list (PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
 
static ParamExternDataplpgsql_param_fetch (ParamListInfo params, int paramid, bool speculative, ParamExternData *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:1292

Definition at line 3694 of file pl_exec.c.

Typedef Documentation

◆ SimpleEcontextStackEntry

Function Documentation

◆ assign_record_var()

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

Definition at line 8557 of file pl_exec.c.

8559 {
8560  Assert(rec->dtype == PLPGSQL_DTYPE_REC);
8561 
8562  /* Transfer new record object into datum_context */
8563  TransferExpandedRecord(erh, estate->datum_context);
8564 
8565  /* Free the old value ... */
8566  if (rec->erh)
8568 
8569  /* ... and install the new */
8570  rec->erh = erh;
8571 }
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 8481 of file pl_exec.c.

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

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

8549 {
8550  assign_simple_var(estate, var, CStringGetTextDatum(str), false, true);
8551 }
#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:8481

References assign_simple_var(), CStringGetTextDatum, and generate_unaccent_rules::str.

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

◆ coerce_function_result_tuple()

static void coerce_function_result_tuple ( PLpgSQL_execstate estate,
TupleDesc  tupdesc 
)
static

Definition at line 801 of file pl_exec.c.

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

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

7666 {
7667  char *result;
7668  MemoryContext oldcontext;
7669  Oid typoutput;
7670  bool typIsVarlena;
7671 
7672  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7673  getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
7674  result = OidOutputFunctionCall(typoutput, value);
7675  MemoryContextSwitchTo(oldcontext);
7676 
7677  return result;
7678 }
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1639
static struct @151 value
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2864
unsigned int Oid
Definition: postgres_ext.h:31

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

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

◆ copy_plpgsql_datums()

static void copy_plpgsql_datums ( PLpgSQL_execstate estate,
PLpgSQL_function func 
)
static

Definition at line 1287 of file pl_exec.c.

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

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

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

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

Referenced by exec_cast_value().

◆ exception_matches_conditions()

static bool exception_matches_conditions ( ErrorData edata,
PLpgSQL_condition cond 
)
static

Definition at line 1572 of file pl_exec.c.

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

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

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

Referenced by exec_stmt_getdiag().

◆ exec_assign_expr()

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

Definition at line 4985 of file pl_exec.c.

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

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

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

◆ exec_assign_value()

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

Definition at line 5057 of file pl_exec.c.

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

◆ exec_cast_value()

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

Definition at line 7694 of file pl_exec.c.

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

References do_cast_value(), and value.

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

◆ exec_check_assignable()

static void exec_check_assignable ( PLpgSQL_execstate estate,
int  dno 
)
static

Definition at line 8269 of file pl_exec.c.

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

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

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

◆ exec_check_rw_parameter()

static void exec_check_rw_parameter ( PLpgSQL_expr expr)
static

Definition at line 8158 of file pl_exec.c.

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

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

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

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

Referenced by exec_stmt_dynfors(), and exec_stmt_open().

◆ exec_eval_boolean()

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

Definition at line 5638 of file pl_exec.c.

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

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

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

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

◆ exec_eval_datum()

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

Definition at line 5284 of file pl_exec.c.

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

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

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

◆ exec_eval_expr()

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

Definition at line 5661 of file pl_exec.c.

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

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

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

◆ exec_eval_integer()

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

Definition at line 5615 of file pl_exec.c.

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

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

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

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

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

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

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

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

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

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

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

Referenced by exec_move_row(), and exec_move_row_from_datum().

◆ exec_prepare_plan()

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

Definition at line 4152 of file pl_exec.c.

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

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

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

◆ exec_run_select()

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

Definition at line 5745 of file pl_exec.c.

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

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

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

◆ exec_save_simple_expr()

static void exec_save_simple_expr ( PLpgSQL_expr expr,
CachedPlan cplan 
)
static

Definition at line 8051 of file pl_exec.c.

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

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

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

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

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

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

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

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

Referenced by exec_stmts(), and exec_toplevel_block().

◆ exec_stmt_call()

static int exec_stmt_call ( PLpgSQL_execstate estate,
PLpgSQL_stmt_call stmt 
)
static

Definition at line 2174 of file pl_exec.c.

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

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

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

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

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

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

Referenced by exec_stmts().

◆ exec_stmt_dynexecute()

static int exec_stmt_dynexecute ( PLpgSQL_execstate estate,
PLpgSQL_stmt_dynexecute stmt 
)
static

Definition at line 4423 of file pl_exec.c.

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

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

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

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

4805 {
4806  PLpgSQL_var *curvar;
4807  long how_many = stmt->how_many;
4808  SPITupleTable *tuptab;
4809  Portal portal;
4810