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

Go to the source code of this file.

Data Structures

struct  SimpleEcontextStackEntry
 
struct  plpgsql_CastHashKey
 
struct  plpgsql_CastExprHashEntry
 
struct  plpgsql_CastHashEntry
 

Macros

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

Typedefs

typedef struct SimpleEcontextStackEntry SimpleEcontextStackEntry
 

Functions

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

Variables

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

Macro Definition Documentation

◆ eval_mcontext_alloc

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

Definition at line 133 of file pl_exec.c.

◆ eval_mcontext_alloc0

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

Definition at line 135 of file pl_exec.c.

◆ get_eval_mcontext

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

Definition at line 131 of file pl_exec.c.

◆ LOOP_RC_PROCESSING

#define LOOP_RC_PROCESSING (   looplabel,
  exit_action 
)

Definition at line 208 of file pl_exec.c.

◆ SET_RAISE_OPTION_TEXT

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

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

8598 {
8599  Assert(rec->dtype == PLPGSQL_DTYPE_REC);
8600 
8601  /* Transfer new record object into datum_context */
8602  TransferExpandedRecord(erh, estate->datum_context);
8603 
8604  /* Free the old value ... */
8605  if (rec->erh)
8607 
8608  /* ... and install the new */
8609  rec->erh = erh;
8610 }
void DeleteExpandedObject(Datum d)
static Datum ExpandedRecordGetDatum(const ExpandedRecordHeader *erh)
#define TransferExpandedRecord(erh, cxt)
Assert(fmt[strlen(fmt) - 1] !='\n')
@ PLPGSQL_DTYPE_REC
Definition: plpgsql.h:65
MemoryContext datum_context
Definition: plpgsql.h:1060
ExpandedRecordHeader * erh
Definition: plpgsql.h:414
PLpgSQL_datum_type dtype
Definition: plpgsql.h:391

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

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

◆ assign_simple_var()

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

Definition at line 8520 of file pl_exec.c.

8522 {
8523  Assert(var->dtype == PLPGSQL_DTYPE_VAR ||
8524  var->dtype == PLPGSQL_DTYPE_PROMISE);
8525 
8526  /*
8527  * In non-atomic contexts, we do not want to store TOAST pointers in
8528  * variables, because such pointers might become stale after a commit.
8529  * Forcibly detoast in such cases. We don't want to detoast (flatten)
8530  * expanded objects, however; those should be OK across a transaction
8531  * boundary since they're just memory-resident objects. (Elsewhere in
8532  * this module, operations on expanded records likewise need to request
8533  * detoasting of record fields when !estate->atomic. Expanded arrays are
8534  * not a problem since all array entries are always detoasted.)
8535  */
8536  if (!estate->atomic && !isnull && var->datatype->typlen == -1 &&
8538  {
8539  MemoryContext oldcxt;
8540  Datum detoasted;
8541 
8542  /*
8543  * Do the detoasting in the eval_mcontext to avoid long-term leakage
8544  * of whatever memory toast fetching might leak. Then we have to copy
8545  * the detoasted datum to the function's main context, which is a
8546  * pain, but there's little choice.
8547  */
8548  oldcxt = MemoryContextSwitchTo(get_eval_mcontext(estate));
8549  detoasted = PointerGetDatum(detoast_external_attr((struct varlena *) DatumGetPointer(newvalue)));
8550  MemoryContextSwitchTo(oldcxt);
8551  /* Now's a good time to not leak the input value if it's freeable */
8552  if (freeable)
8553  pfree(DatumGetPointer(newvalue));
8554  /* Once we copy the value, it's definitely freeable */
8555  newvalue = datumCopy(detoasted, false, -1);
8556  freeable = true;
8557  /* Can't clean up eval_mcontext here, but it'll happen before long */
8558  }
8559 
8560  /* Free the old value if needed */
8561  if (var->freeval)
8562  {
8564  var->isnull,
8565  var->datatype->typlen))
8567  else
8568  pfree(DatumGetPointer(var->value));
8569  }
8570  /* Assign new value to datum */
8571  var->value = newvalue;
8572  var->isnull = isnull;
8573  var->freeval = freeable;
8574 
8575  /*
8576  * If it's a promise variable, then either we just assigned the promised
8577  * value, or the user explicitly assigned an overriding value. Either
8578  * way, cancel the promise.
8579  */
8581 }
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:1456
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
#define get_eval_mcontext(estate)
Definition: pl_exec.c:131
@ PLPGSQL_PROMISE_NONE
Definition: plpgsql.h:75
@ PLPGSQL_DTYPE_PROMISE
Definition: plpgsql.h:67
@ PLPGSQL_DTYPE_VAR
Definition: plpgsql.h:63
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
int16 typlen
Definition: plpgsql.h:203
PLpgSQL_promise_type promise
Definition: plpgsql.h:342
PLpgSQL_datum_type dtype
Definition: plpgsql.h:311
bool freeval
Definition: plpgsql.h:335
bool isnull
Definition: plpgsql.h:334
PLpgSQL_type * datatype
Definition: plpgsql.h:320
Datum value
Definition: plpgsql.h:333
Definition: c.h:676
#define VARATT_IS_EXTERNAL_NON_EXPANDED(PTR)
Definition: varatt.h:300

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

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

◆ assign_text_var()

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

Definition at line 8587 of file pl_exec.c.

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

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

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

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

Referenced by plpgsql_exec_function().

◆ compatible_tupdescs()

static bool compatible_tupdescs ( TupleDesc  src_tupdesc,
TupleDesc  dst_tupdesc 
)
static

Definition at line 7285 of file pl_exec.c.

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

References i, TupleDescData::natts, and TupleDescAttr.

Referenced by exec_for_query(), and exec_move_row().

◆ convert_value_to_string()

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

Definition at line 7683 of file pl_exec.c.

7684 {
7685  char *result;
7686  MemoryContext oldcontext;
7687  Oid typoutput;
7688  bool typIsVarlena;
7689 
7690  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7691  getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
7692  result = OidOutputFunctionCall(typoutput, value);
7693  MemoryContextSwitchTo(oldcontext);
7694 
7695  return result;
7696 }
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1746
static struct @148 value
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2889
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 1297 of file pl_exec.c.

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

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

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

◆ deconstruct_composite_datum()

static TupleDesc deconstruct_composite_datum ( Datum  value,
HeapTupleData tmptup 
)
static

Definition at line 7384 of file pl_exec.c.

7385 {
7386  HeapTupleHeader td;
7387  Oid tupType;
7388  int32 tupTypmod;
7389 
7390  /* Get tuple body (note this could involve detoasting) */
7392 
7393  /* Build a temporary HeapTuple control structure */
7394  tmptup->t_len = HeapTupleHeaderGetDatumLength(td);
7395  ItemPointerSetInvalid(&(tmptup->t_self));
7396  tmptup->t_tableOid = InvalidOid;
7397  tmptup->t_data = td;
7398 
7399  /* Extract rowtype info and find a tupdesc */
7400  tupType = HeapTupleHeaderGetTypeId(td);
7401  tupTypmod = HeapTupleHeaderGetTypMod(td);
7402  return lookup_rowtype_tupdesc(tupType, tupTypmod);
7403 }
signed int int32
Definition: c.h:483
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:295
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:466
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:456
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:450
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition: itemptr.h:184
#define InvalidOid
Definition: postgres_ext.h:36
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
HeapTupleHeader t_data
Definition: htup.h:68
Oid t_tableOid
Definition: htup.h:66
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c: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 7736 of file pl_exec.c.

7740 {
7741  plpgsql_CastHashEntry *cast_entry;
7742 
7743  cast_entry = get_cast_hashentry(estate,
7744  valtype, valtypmod,
7745  reqtype, reqtypmod);
7746  if (cast_entry)
7747  {
7748  ExprContext *econtext = estate->eval_econtext;
7749  MemoryContext oldcontext;
7750 
7751  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7752 
7753  econtext->caseValue_datum = value;
7754  econtext->caseValue_isNull = *isnull;
7755 
7756  cast_entry->cast_in_use = true;
7757 
7758  value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
7759  isnull);
7760 
7761  cast_entry->cast_in_use = false;
7762 
7763  MemoryContextSwitchTo(oldcontext);
7764  }
7765 
7766  return value;
7767 }
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:332
static plpgsql_CastHashEntry * get_cast_hashentry(PLpgSQL_execstate *estate, Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod)
Definition: pl_exec.c:7780
bool caseValue_isNull
Definition: execnodes.h:276
Datum caseValue_datum
Definition: execnodes.h:274
ExprContext * eval_econtext
Definition: plpgsql.h:1087
ExprState * cast_exprstate
Definition: pl_exec.c:177

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

Referenced by exec_cast_value().

◆ exception_matches_conditions()

static bool exception_matches_conditions ( ErrorData edata,
PLpgSQL_condition cond 
)
static

Definition at line 1582 of file pl_exec.c.

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

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

Referenced by exec_stmt_block().

◆ exec_assign_c_string()

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

Definition at line 5050 of file pl_exec.c.

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

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

Referenced by exec_stmt_getdiag().

◆ exec_assign_expr()

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

Definition at line 5006 of file pl_exec.c.

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

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

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

◆ exec_assign_value()

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

Definition at line 5078 of file pl_exec.c.

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

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

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

◆ exec_cast_value()

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

Definition at line 7712 of file pl_exec.c.

7716 {
7717  /*
7718  * If the type of the given value isn't what's requested, convert it.
7719  */
7720  if (valtype != reqtype ||
7721  (valtypmod != reqtypmod && reqtypmod != -1))
7722  {
7723  /* We keep the slow path out-of-line. */
7724  value = do_cast_value(estate, value, isnull, valtype, valtypmod,
7725  reqtype, reqtypmod);
7726  }
7727 
7728  return value;
7729 }
static Datum do_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7736

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

8309 {
8310  PLpgSQL_datum *datum;
8311 
8312  Assert(dno >= 0 && dno < estate->ndatums);
8313  datum = estate->datums[dno];
8314  switch (datum->dtype)
8315  {
8316  case PLPGSQL_DTYPE_VAR:
8317  case PLPGSQL_DTYPE_PROMISE:
8318  case PLPGSQL_DTYPE_REC:
8319  if (((PLpgSQL_variable *) datum)->isconst)
8320  ereport(ERROR,
8321  (errcode(ERRCODE_ERROR_IN_ASSIGNMENT),
8322  errmsg("variable \"%s\" is declared CONSTANT",
8323  ((PLpgSQL_variable *) datum)->refname)));
8324  break;
8325  case PLPGSQL_DTYPE_ROW:
8326  /* always assignable; member vars were checked at compile time */
8327  break;
8329  /* assignable if parent record is */
8330  exec_check_assignable(estate,
8331  ((PLpgSQL_recfield *) datum)->recparentno);
8332  break;
8333  default:
8334  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
8335  break;
8336  }
8337 }
static void exec_check_assignable(PLpgSQL_execstate *estate, int dno)
Definition: pl_exec.c:8308
PLpgSQL_datum_type dtype
Definition: plpgsql.h:289

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

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

◆ exec_check_rw_parameter()

static void exec_check_rw_parameter ( PLpgSQL_expr expr)
static

Definition at line 8197 of file pl_exec.c.

8198 {
8199  int target_dno;
8200  Oid funcid;
8201  List *fargs;
8202  ListCell *lc;
8203 
8204  /* Assume unsafe */
8205  expr->expr_rw_param = NULL;
8206 
8207  /* Done if expression isn't an assignment source */
8208  target_dno = expr->target_param;
8209  if (target_dno < 0)
8210  return;
8211 
8212  /*
8213  * If target variable isn't referenced by expression, no need to look
8214  * further.
8215  */
8216  if (!bms_is_member(target_dno, expr->paramnos))
8217  return;
8218 
8219  /* Shouldn't be here for non-simple expression */
8220  Assert(expr->expr_simple_expr != NULL);
8221 
8222  /*
8223  * Top level of expression must be a simple FuncExpr, OpExpr, or
8224  * SubscriptingRef, else we can't optimize.
8225  */
8226  if (IsA(expr->expr_simple_expr, FuncExpr))
8227  {
8228  FuncExpr *fexpr = (FuncExpr *) expr->expr_simple_expr;
8229 
8230  funcid = fexpr->funcid;
8231  fargs = fexpr->args;
8232  }
8233  else if (IsA(expr->expr_simple_expr, OpExpr))
8234  {
8235  OpExpr *opexpr = (OpExpr *) expr->expr_simple_expr;
8236 
8237  funcid = opexpr->opfuncid;
8238  fargs = opexpr->args;
8239  }
8240  else if (IsA(expr->expr_simple_expr, SubscriptingRef))
8241  {
8242  SubscriptingRef *sbsref = (SubscriptingRef *) expr->expr_simple_expr;
8243 
8244  /* We only trust standard varlena arrays to be safe */
8245  if (get_typsubscript(sbsref->refcontainertype, NULL) !=
8246  F_ARRAY_SUBSCRIPT_HANDLER)
8247  return;
8248 
8249  /* We can optimize the refexpr if it's the target, otherwise not */
8250  if (sbsref->refexpr && IsA(sbsref->refexpr, Param))
8251  {
8252  Param *param = (Param *) sbsref->refexpr;
8253 
8254  if (param->paramkind == PARAM_EXTERN &&
8255  param->paramid == target_dno + 1)
8256  {
8257  /* Found the Param we want to pass as read/write */
8258  expr->expr_rw_param = param;
8259  return;
8260  }
8261  }
8262 
8263  return;
8264  }
8265  else
8266  return;
8267 
8268  /*
8269  * The top-level function must be one that we trust to be "safe".
8270  * Currently we hard-wire the list, but it would be very desirable to
8271  * allow extensions to mark their functions as safe ...
8272  */
8273  if (!(funcid == F_ARRAY_APPEND ||
8274  funcid == F_ARRAY_PREPEND))
8275  return;
8276 
8277  /*
8278  * The target variable (in the form of a Param) must appear as a direct
8279  * argument of the top-level function. References further down in the
8280  * tree can't be optimized; but on the other hand, they don't invalidate
8281  * optimizing the top-level call, since that will be executed last.
8282  */
8283  foreach(lc, fargs)
8284  {
8285  Node *arg = (Node *) lfirst(lc);
8286 
8287  if (arg && IsA(arg, Param))
8288  {
8289  Param *param = (Param *) arg;
8290 
8291  if (param->paramkind == PARAM_EXTERN &&
8292  param->paramid == target_dno + 1)
8293  {
8294  /* Found the Param we want to pass as read/write */
8295  expr->expr_rw_param = param;
8296  return;
8297  }
8298  }
8299  }
8300 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:460
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
RegProcedure get_typsubscript(Oid typid, Oid *typelemp)
Definition: lsyscache.c:3079
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
void * arg
#define lfirst(lc)
Definition: pg_list.h:172
@ PARAM_EXTERN
Definition: primnodes.h:345
Oid funcid
Definition: primnodes.h:677
List * args
Definition: primnodes.h:695
Definition: pg_list.h:54
Definition: nodes.h:129
List * args
Definition: primnodes.h:763
Expr * expr_simple_expr
Definition: plpgsql.h:232
Bitmapset * paramnos
Definition: plpgsql.h:223
Param * expr_rw_param
Definition: plpgsql.h:246
int paramid
Definition: primnodes.h:355
ParamKind paramkind
Definition: primnodes.h:354
Expr * refexpr
Definition: primnodes.h:628

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

Referenced by exec_save_simple_expr().

◆ exec_dynquery_with_params()

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

Definition at line 8701 of file pl_exec.c.

8706 {
8707  Portal portal;
8708  Datum query;
8709  bool isnull;
8710  Oid restype;
8711  int32 restypmod;
8712  char *querystr;
8714  MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
8715 
8716  /*
8717  * Evaluate the string expression after the EXECUTE keyword. Its result is
8718  * the querystring we have to execute.
8719  */
8720  query = exec_eval_expr(estate, dynquery, &isnull, &restype, &restypmod);
8721  if (isnull)
8722  ereport(ERROR,
8723  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
8724  errmsg("query string argument of EXECUTE is null")));
8725 
8726  /* Get the C-String representation */
8727  querystr = convert_value_to_string(estate, query, restype);
8728 
8729  /* copy it into the stmt_mcontext before we clean up */
8730  querystr = MemoryContextStrdup(stmt_mcontext, querystr);
8731 
8732  exec_eval_cleanup(estate);
8733 
8734  /*
8735  * Open an implicit cursor for the query. We use SPI_cursor_parse_open
8736  * even when there are no params, because this avoids making and freeing
8737  * one copy of the plan.
8738  */
8739  memset(&options, 0, sizeof(options));
8740  options.params = exec_eval_using_params(estate, params);
8741  options.cursorOptions = cursorOptions;
8742  options.read_only = estate->readonly_func;
8743 
8744  portal = SPI_cursor_parse_open(portalname, querystr, &options);
8745 
8746  if (portal == NULL)
8747  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
8748  querystr, SPI_result_code_string(SPI_result));
8749 
8750  /* Release transient data */
8751  MemoryContextReset(stmt_mcontext);
8752 
8753  return portal;
8754 }
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:330
static char ** options
static char * convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
Definition: pl_exec.c:7683
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1531
static ParamListInfo exec_eval_using_params(PLpgSQL_execstate *estate, List *params)
Definition: pl_exec.c:8619
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 5659 of file pl_exec.c.

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

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

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

◆ exec_eval_cleanup()

static void exec_eval_cleanup ( PLpgSQL_execstate estate)
static

Definition at line 4136 of file pl_exec.c.

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

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

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

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

◆ exec_eval_expr()

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

Definition at line 5682 of file pl_exec.c.

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

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

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

◆ exec_eval_integer()

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

Definition at line 5636 of file pl_exec.c.

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

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

Referenced by exec_stmt_fetch().

◆ exec_eval_simple_expr()

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

Definition at line 6032 of file pl_exec.c.

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

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

Referenced by exec_eval_expr().

◆ exec_eval_using_params()

static ParamListInfo exec_eval_using_params ( PLpgSQL_execstate estate,
List params 
)
static

Definition at line 8619 of file pl_exec.c.

8620 {
8621  ParamListInfo paramLI;
8622  int nargs;
8623  MemoryContext stmt_mcontext;
8624  MemoryContext oldcontext;
8625  int i;
8626  ListCell *lc;
8627 
8628  /* Fast path for no parameters: we can just return NULL */
8629  if (params == NIL)
8630  return NULL;
8631 
8632  nargs = list_length(params);
8633  stmt_mcontext = get_stmt_mcontext(estate);
8634  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8635  paramLI = makeParamList(nargs);
8636  MemoryContextSwitchTo(oldcontext);
8637 
8638  i = 0;
8639  foreach(lc, params)
8640  {
8641  PLpgSQL_expr *param = (PLpgSQL_expr *) lfirst(lc);
8642  ParamExternData *prm = &paramLI->params[i];
8643  int32 ppdtypmod;
8644 
8645  /*
8646  * Always mark params as const, since we only use the result with
8647  * one-shot plans.
8648  */
8649  prm->pflags = PARAM_FLAG_CONST;
8650 
8651  prm->value = exec_eval_expr(estate, param,
8652  &prm->isnull,
8653  &prm->ptype,
8654  &ppdtypmod);
8655 
8656  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8657 
8658  if (prm->ptype == UNKNOWNOID)
8659  {
8660  /*
8661  * Treat 'unknown' parameters as text, since that's what most
8662  * people would expect. The SPI functions can coerce unknown
8663  * constants in a more intelligent way, but not unknown Params.
8664  * This code also takes care of copying into the right context.
8665  * Note we assume 'unknown' has the representation of C-string.
8666  */
8667  prm->ptype = TEXTOID;
8668  if (!prm->isnull)
8670  }
8671  /* pass-by-ref non null values must be copied into stmt_mcontext */
8672  else if (!prm->isnull)
8673  {
8674  int16 typLen;
8675  bool typByVal;
8676 
8677  get_typlenbyval(prm->ptype, &typLen, &typByVal);
8678  if (!typByVal)
8679  prm->value = datumCopy(prm->value, typByVal, typLen);
8680  }
8681 
8682  MemoryContextSwitchTo(oldcontext);
8683 
8684  exec_eval_cleanup(estate);
8685 
8686  i++;
8687  }
8688 
8689  return paramLI;
8690 }
signed short int16
Definition: c.h:482
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2233
ParamListInfo makeParamList(int numParams)
Definition: params.c:44
#define PARAM_FLAG_CONST
Definition: params.h:88
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
static char * DatumGetCString(Datum X)
Definition: postgres.h:335
bool isnull
Definition: params.h:93
uint16 pflags
Definition: params.h:94
Datum value
Definition: params.h:92
ParamExternData params[FLEXIBLE_ARRAY_MEMBER]
Definition: params.h:125

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

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

◆ exec_for_query()

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

Definition at line 5850 of file pl_exec.c.

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

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

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

◆ exec_init_tuple_store()

static void exec_init_tuple_store ( PLpgSQL_execstate estate)
static

Definition at line 3669 of file pl_exec.c.

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

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

Referenced by exec_stmt_return_next(), and exec_stmt_return_query().

◆ exec_move_row()

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

Definition at line 6741 of file pl_exec.c.

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

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

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

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

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

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

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

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

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

◆ exec_run_select()

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

Definition at line 5766 of file pl_exec.c.

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

8091 {
8092  PlannedStmt *stmt;
8093  Plan *plan;
8094  Expr *tle_expr;
8095 
8096  /*
8097  * Given the checks that exec_simple_check_plan did, none of the Asserts
8098  * here should ever fail.
8099  */
8100 
8101  /* Extract the single PlannedStmt */
8102  Assert(list_length(cplan->stmt_list) == 1);
8104  Assert(stmt->commandType == CMD_SELECT);
8105 
8106  /*
8107  * Ordinarily, the plan node should be a simple Result. However, if
8108  * debug_parallel_query is on, the planner might've stuck a Gather node
8109  * atop that. The simplest way to deal with this is to look through the
8110  * Gather node. The Gather node's tlist would normally contain a Var
8111  * referencing the child node's output, but it could also be a Param, or
8112  * it could be a Const that setrefs.c copied as-is.
8113  */
8114  plan = stmt->planTree;
8115  for (;;)
8116  {
8117  /* Extract the single tlist expression */
8118  Assert(list_length(plan->targetlist) == 1);
8119  tle_expr = linitial_node(TargetEntry, plan->targetlist)->expr;
8120 
8121  if (IsA(plan, Result))
8122  {
8123  Assert(plan->lefttree == NULL &&
8124  plan->righttree == NULL &&
8125  plan->initPlan == NULL &&
8126  plan->qual == NULL &&
8127  ((Result *) plan)->resconstantqual == NULL);
8128  break;
8129  }
8130  else if (IsA(plan, Gather))
8131  {
8132  Assert(plan->lefttree != NULL &&
8133  plan->righttree == NULL &&
8134  plan->initPlan == NULL &&
8135  plan->qual == NULL);
8136  /* If setrefs.c copied up a Const, no need to look further */
8137  if (IsA(tle_expr, Const))
8138  break;
8139  /* Otherwise, it had better be a Param or an outer Var */
8140  Assert(IsA(tle_expr, Param) || (IsA(tle_expr, Var) &&
8141  ((Var *) tle_expr)->varno == OUTER_VAR));
8142  /* Descend to the child node */
8143  plan = plan->lefttree;
8144  }
8145  else
8146  elog(ERROR, "unexpected plan node type: %d",
8147  (int) nodeTag(plan));
8148  }
8149 
8150  /*
8151  * Save the simple expression, and initialize state to "not valid in
8152  * current transaction".
8153  */
8154  expr->expr_simple_expr = tle_expr;
8155  expr->expr_simple_state = NULL;
8156  expr->expr_simple_in_use = false;
8158  /* Also stash away the expression result type */
8159  expr->expr_simple_type = exprType((Node *) tle_expr);
8160  expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
8161  /* We also want to remember if it is immutable or not */
8162  expr->expr_simple_mutable = contain_mutable_functions((Node *) tle_expr);
8163 
8164  /*
8165  * Lastly, check to see if there's a possibility of optimizing a
8166  * read/write parameter.
8167  */
8169 }
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:367
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:282
#define nodeTag(nodeptr)
Definition: nodes.h:133
@ CMD_SELECT
Definition: nodes.h:276
#define linitial_node(type, l)
Definition: pg_list.h:181
static void exec_check_rw_parameter(PLpgSQL_expr *expr)
Definition: pl_exec.c:8197
#define OUTER_VAR
Definition: primnodes.h:215
List * stmt_list
Definition: plancache.h:150
Definition: primnodes.h:226

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

Referenced by exec_eval_simple_expr(), and exec_simple_check_plan().

◆ exec_set_found()

static void exec_set_found ( PLpgSQL_execstate estate,
bool  state 
)
static

Definition at line 8344 of file pl_exec.c.

8345 {
8346  PLpgSQL_var *var;
8347 
8348  var = (PLpgSQL_var *) (estate->datums[estate->found_varno]);
8349  assign_simple_var(estate, var, BoolGetDatum(state), false, false);
8350 }
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
Definition: regguts.h:323

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

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

◆ exec_simple_check_plan()

static void exec_simple_check_plan ( PLpgSQL_execstate estate,
PLpgSQL_expr expr 
)
static

Definition at line 7971 of file pl_exec.c.

7972 {
7973  List *plansources;
7974  CachedPlanSource *plansource;
7975  Query *query;
7976  CachedPlan *cplan;
7977  MemoryContext oldcontext;
7978 
7979  /*
7980  * Initialize to "not simple".
7981  */
7982  expr->expr_simple_expr = NULL;
7983  expr->expr_rw_param = NULL;
7984 
7985  /*
7986  * Check the analyzed-and-rewritten form of the query to see if we will be
7987  * able to treat it as a simple expression. Since this function is only
7988  * called immediately after creating the CachedPlanSource, we need not
7989  * worry about the query being stale.
7990  */
7991 
7992  /*
7993  * We can only test queries that resulted in exactly one CachedPlanSource
7994  */
7995  plansources = SPI_plan_get_plan_sources(expr->plan);
7996  if (list_length(plansources) != 1)
7997  return;
7998  plansource = (CachedPlanSource *) linitial(plansources);
7999 
8000  /*
8001  * 1. There must be one single querytree.
8002  */
8003  if (list_length(plansource->query_list) != 1)
8004  return;
8005  query = (Query *) linitial(plansource->query_list);
8006 
8007  /*
8008  * 2. It must be a plain SELECT query without any input tables
8009  */
8010  if (!IsA(query, Query))
8011  return;
8012  if (query->commandType != CMD_SELECT)
8013  return;
8014  if (query->rtable != NIL)
8015  return;
8016 
8017  /*
8018  * 3. Can't have any subplans, aggregates, qual clauses either. (These
8019  * tests should generally match what inline_function() checks before
8020  * inlining a SQL function; otherwise, inlining could change our
8021  * conclusion about whether an expression is simple, which we don't want.)
8022  */
8023  if (query->hasAggs ||
8024  query->hasWindowFuncs ||
8025  query->hasTargetSRFs ||
8026  query->hasSubLinks ||
8027  query->cteList ||
8028  query->jointree->fromlist ||
8029  query->jointree->quals ||
8030  query->groupClause ||
8031  query->groupingSets ||
8032  query->havingQual ||
8033  query->windowClause ||
8034  query->distinctClause ||
8035  query->sortClause ||
8036  query->limitOffset ||
8037  query->limitCount ||
8038  query->setOperations)
8039  return;
8040 
8041  /*
8042  * 4. The query must have a single attribute as result
8043  */
8044  if (list_length(query->targetList) != 1)
8045  return;
8046 
8047  /*
8048  * OK, we can treat it as a simple plan.
8049  *
8050  * Get the generic plan for the query. If replanning is needed, do that
8051  * work in the eval_mcontext. (Note that replanning could throw an error,
8052  * in which case the expr is left marked "not simple", which is fine.)
8053  */
8054  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
8055  cplan = SPI_plan_get_cached_plan(expr->plan);
8056  MemoryContextSwitchTo(oldcontext);
8057 
8058  /* Can't fail, because we checked for a single CachedPlanSource above */
8059  Assert(cplan != NULL);
8060 
8061  /*
8062  * Verify that plancache.c thinks the plan is simple enough to use
8063  * CachedPlanIsSimplyValid. Given the restrictions above, it's unlikely
8064  * that this could fail, but if it does, just treat plan as not simple. On
8065  * success, save a refcount on the plan in the simple-expression resowner.
8066  */
8067  if (CachedPlanAllowsSimpleValidityCheck(plansource, cplan,
8068  estate->simple_eval_resowner))
8069  {
8070  /* Remember that we have the refcount */
8071  expr->expr_simple_plansource = plansource;
8072  expr->expr_simple_plan = cplan;
8074 
8075  /* Share the remaining work with the replan code path */
8076  exec_save_simple_expr(expr, cplan);
8077  }
8078 
8079  /*
8080  * Release the plan refcount obtained by SPI_plan_get_cached_plan. (This
8081  * refcount is held by the wrong resowner, so we can't just repurpose it.)
8082  */
8084 }
#define linitial(l)
Definition: pg_list.h:178
List * SPI_plan_get_plan_sources(SPIPlanPtr plan)
Definition: spi.c:2051
List * query_list
Definition: plancache.h:111
Node * quals
Definition: primnodes.h:2014
List * fromlist
Definition: primnodes.h:2013
Node * limitCount
Definition: parsenodes.h:211
FromExpr * jointree
Definition: parsenodes.h:181
Node * setOperations
Definition: parsenodes.h:216
List * cteList
Definition: parsenodes.h:172
List * groupClause
Definition: parsenodes.h:197
Node * havingQual
Definition: parsenodes.h:202
List * rtable
Definition: parsenodes.h:174
Node * limitOffset
Definition: parsenodes.h:210
CmdType commandType
Definition: parsenodes.h:127
List * windowClause
Definition: parsenodes.h:204
List * targetList
Definition: parsenodes.h:188
List * groupingSets
Definition: parsenodes.h:200
List * distinctClause
Definition: parsenodes.h:206
List * sortClause
Definition: parsenodes.h:208

References Assert(), CachedPlanAllowsSimpleValidityCheck(), CMD_SELECT, Query::commandType, Query::cteList, CurrentResourceOwner, Query::distinctClause, exec_save_simple_expr(), PLpgSQL_expr::expr_rw_param, PLpgSQL_expr::expr_simple_expr, PLpgSQL_expr::expr_simple_plan, PLpgSQL_expr::expr_simple_plan_lxid, PLpgSQL_expr::expr_simple_plansource, FromExpr::fromlist, get_eval_mcontext, Query::groupClause, Query::groupingSets, Query::havingQual, IsA, Query::jointree, Query::limitCount, Query::limitOffset, linitial, list_length(), PGPROC::lxid, MemoryContextSwitchTo(), MyProc, NIL, PLpgSQL_expr::plan, FromExpr::quals, CachedPlanSource::query_list, ReleaseCachedPlan(), Query::rtable, Query::setOperations, PLpgSQL_execstate::simple_eval_resowner, Query::sortClause, SPI_plan_get_cached_plan(), SPI_plan_get_plan_sources(), Query::targetList, and Query::windowClause.

Referenced by exec_prepare_plan().

◆ exec_stmt_assert()

static int exec_stmt_assert ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assert stmt 
)
static

Definition at line 3936 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_assign()

static int exec_stmt_assign ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assign stmt 
)
static

Definition at line 2151 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_block()

static int exec_stmt_block ( PLpgSQL_execstate estate,
PLpgSQL_stmt_block block 
)
static

Definition at line 1650 of file pl_exec.c.

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

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

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

References Assert(), elog(), ERROR, exec_eval_cleanup(), exec_move_row(), exec_prepare_plan(), PLpgSQL_expr::expr_simple_expr, PGPROC::lxid, make_callstmt_target(), MyProc, options, PLpgSQL_expr::plan, plpgsql_create_econtext(), PLPGSQL_RC_OK, PLpgSQL_execstate::procedure_resowner, PLpgSQL_expr::query, PLpgSQL_execstate::readonly_func, setup_param_list(), PLpgSQL_execstate::simple_eval_estate, PLpgSQL_execstate::simple_eval_resowner, SPI_execute_plan_extended(), SPI_freetuptable(), SPI_processed, SPI_result_code_string(), SPI_tuptable, stmt, SPITupleTable::tupdesc, 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 2542 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_close()

static int exec_stmt_close ( PLpgSQL_execstate estate,
PLpgSQL_stmt_close stmt 
)
static

Definition at line 4916 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_commit()

static int exec_stmt_commit ( PLpgSQL_execstate estate,
PLpgSQL_stmt_commit stmt 
)
static

Definition at line 4959 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_dynexecute()

static int exec_stmt_dynexecute ( PLpgSQL_execstate estate,
PLpgSQL_stmt_dynexecute stmt 
)
static

Definition at line 4444 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_dynfors()

static int exec_stmt_dynfors ( PLpgSQL_execstate estate,
PLpgSQL_stmt_dynfors stmt 
)
static

Definition at line 4633 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_execsql()

static int exec_stmt_execsql ( PLpgSQL_execstate estate,
PLpgSQL_stmt_execsql stmt 
)
static

Definition at line 4214 of file pl_exec.c.

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

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

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

◆ exec_stmt_exit()

static int exec_stmt_exit ( PLpgSQL_execstate estate,
PLpgSQL_stmt_exit stmt 
)
static

Definition at line 3150 of file pl_exec.c.

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

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

Referenced by exec_stmts().

◆ exec_stmt_fetch()

static int exec_stmt_fetch ( PLpgSQL_execstate estate,
PLpgSQL_stmt_fetch stmt 
)
static

Definition at line 4825 of file pl_exec.c.

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

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