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/tupconvert.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.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 "plpgsql.h"
#include "storage/proc.h"
#include "tcop/cmdtag.h"
#include "tcop/pquery.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
Include dependency graph for pl_exec.c:

Go to the source code of this file.

Data Structures

struct  SimpleEcontextStackEntry
 
struct  plpgsql_CastHashKey
 
struct  plpgsql_CastExprHashEntry
 
struct  plpgsql_CastHashEntry
 

Macros

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

Typedefs

typedef struct SimpleEcontextStackEntry SimpleEcontextStackEntry
 

Functions

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

Variables

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

Macro Definition Documentation

◆ eval_mcontext_alloc

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

Definition at line 128 of file pl_exec.c.

◆ eval_mcontext_alloc0

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

Definition at line 130 of file pl_exec.c.

◆ get_eval_mcontext

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

Definition at line 126 of file pl_exec.c.

◆ LOOP_RC_PROCESSING

#define LOOP_RC_PROCESSING (   looplabel,
  exit_action 
)

Definition at line 203 of file pl_exec.c.

◆ SET_RAISE_OPTION_TEXT

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

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

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

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

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

◆ assign_simple_var()

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

Definition at line 8551 of file pl_exec.c.

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

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

References assign_simple_var(), CStringGetTextDatum, and str.

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

◆ coerce_function_result_tuple()

static void coerce_function_result_tuple ( PLpgSQL_execstate estate,
TupleDesc  tupdesc 
)
static

Definition at line 808 of file pl_exec.c.

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

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

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

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

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

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

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

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

◆ deconstruct_composite_datum()

static TupleDesc deconstruct_composite_datum ( Datum  value,
HeapTupleData tmptup 
)
static

Definition at line 7392 of file pl_exec.c.

7393{
7394 HeapTupleHeader td;
7395 Oid tupType;
7396 int32 tupTypmod;
7397
7398 /* Get tuple body (note this could involve detoasting) */
7400
7401 /* Build a temporary HeapTuple control structure */
7403 ItemPointerSetInvalid(&(tmptup->t_self));
7404 tmptup->t_tableOid = InvalidOid;
7405 tmptup->t_data = td;
7406
7407 /* Extract rowtype info and find a tupdesc */
7408 tupType = HeapTupleHeaderGetTypeId(td);
7409 tupTypmod = HeapTupleHeaderGetTypMod(td);
7410 return lookup_rowtype_tupdesc(tupType, tupTypmod);
7411}
int32_t int32
Definition: c.h:484
#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:37
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:1920

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

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

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

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

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

Referenced by exec_stmt_block().

◆ exec_assign_c_string()

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

Definition at line 5051 of file pl_exec.c.

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

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

Referenced by exec_stmt_getdiag().

◆ exec_assign_expr()

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

Definition at line 5007 of file pl_exec.c.

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

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

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

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

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

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

Referenced by exec_check_assignable(), 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 8228 of file pl_exec.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

Referenced by exec_eval_expr().

◆ exec_eval_using_params()

static ParamListInfo exec_eval_using_params ( PLpgSQL_execstate estate,
List params 
)
static

Definition at line 8650 of file pl_exec.c.

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

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

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

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

◆ exec_init_tuple_store()

static void exec_init_tuple_store ( PLpgSQL_execstate estate)
static

Definition at line 3667 of file pl_exec.c.

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

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

Referenced by exec_stmt_return_next(), and exec_stmt_return_query().

◆ exec_is_simple_query()

static bool exec_is_simple_query ( PLpgSQL_expr expr)
static

Definition at line 8050 of file pl_exec.c.

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

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

Referenced by exec_eval_simple_expr(), and exec_simple_check_plan().

◆ exec_move_row()

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

Definition at line 6749 of file pl_exec.c.

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

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

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

◆ exec_move_row_from_datum()

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

Definition at line 7423 of file pl_exec.c.

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

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

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

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

Referenced by exec_move_row(), and exec_move_row_from_datum().

◆ exec_prepare_plan()

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

Definition at line 4171 of file pl_exec.c.

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

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

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

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

◆ exec_simple_check_plan()

static void exec_simple_check_plan ( PLpgSQL_execstate estate,
PLpgSQL_expr expr 
)
static

Definition at line 7979 of file pl_exec.c.

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

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

Referenced by exec_prepare_plan().

◆ exec_stmt_assert()

static int exec_stmt_assert ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assert stmt 
)
static

Definition at line 3934 of file pl_exec.c.

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

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

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

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

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

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

References Assert, elog, ERROR, exec_eval_cleanup(), exec_move_row(), exec_prepare_plan(), PLpgSQL_expr::expr_simple_expr, PGPROC::lxid, make_callstmt_target(), MyProc, options, PLpgSQL_expr::plan, plpgsql_create_econtext(), PLPGSQL_RC_OK, PLpgSQL_execstate::procedure_resowner, PLpgSQL_expr::query, PLpgSQL_execstate::readonly_func, setup_param_list(), PLpgSQL_execstate::simple_eval_estate, PLpgSQL_execstate::simple_eval_resowner, SPI_execute_plan_extended(), SPI_freetuptable(), SPI_processed, SPI_result_code_string(), SPI_tuptable, stmt, SPITupleTable::tupdesc, SPITupleTable::vals, and PGPROC::vxid.

Referenced by exec_stmts().

◆ exec_stmt_case()

static int exec_stmt_case ( PLpgSQL_execstate estate,
PLpgSQL_stmt_case stmt 
)
static

Definition at line 2540 of file pl_exec.c.

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

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

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

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

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

Referenced by exec_stmts().

◆ exec_stmt_dynexecute()

static int exec_stmt_dynexecute ( PLpgSQL_execstate estate,
PLpgSQL_stmt_dynexecute stmt 
)
static

Definition at line 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:
4492 case SPI_OK_MERGE:
4497 case SPI_OK_UTILITY:
4498 case SPI_OK_REWRITTEN:
4499 break;
4500
4501 case 0:
4502
4503 /*
4504 * Also allow a zero return, which implies the querystring
4505 * contained no commands.
4506 */
4507 break;
4508
4509 case SPI_OK_SELINTO:
4510
4511 /*
4512 * We want to disallow SELECT INTO for now, because its behavior
4513 * is not consistent with SELECT INTO in a normal plpgsql context.
4514 * (We need to reimplement EXECUTE to parse the string as a
4515 * plpgsql command, not just feed it to SPI_execute.) This is not
4516 * a functional limitation because CREATE TABLE AS is allowed.
4517 */
4518 ereport(ERROR,
4519 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4520 errmsg("EXECUTE of SELECT ... INTO is not implemented"),
4521 errhint("You might want to use EXECUTE ... INTO or EXECUTE CREATE TABLE ... AS instead.")));
4522 break;
4523
4524 /* Some SPI errors deserve specific error messages */
4525 case SPI_ERROR_COPY:
4526 ereport(ERROR,
4527 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4528 errmsg("cannot COPY to/from client in PL/pgSQL")));
4529 break;
4530
4532 ereport(ERROR,
4533 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4534 errmsg("EXECUTE of transaction commands is not implemented")));
4535 break;
4536
4537 default:
4538 elog(ERROR, "SPI_execute_extended failed executing query \"%s\": %s",
4539 querystr, SPI_result_code_string(exec_res));
4540 break;
4541 }
4542
4543 /* Save result info for GET DIAGNOSTICS */
4544 estate->eval_processed = SPI_processed;
4545
4546 /* Process INTO if present */
4547 if (stmt->into)
4548 {
4549 SPITupleTable *tuptab = SPI_tuptable;
4551 PLpgSQL_variable *target;
4552
4553 /* If the statement did not return a tuple table, complain */
4554 if (tuptab == NULL)
4555 ereport(ERROR,
4556 (errcode(ERRCODE_SYNTAX_ERROR),
4557 errmsg("INTO used with a command that cannot return data")));
4558
4559 /* Fetch target's datum entry */
4560 target = (PLpgSQL_variable *) estate->datums[stmt->target->dno];
4561
4562 /*
4563 * If SELECT ... INTO specified STRICT, and the query didn't find
4564 * exactly one row, throw an error. If STRICT was not specified, then
4565 * allow the query to find any number of rows.
4566 */
4567 if (n == 0)
4568 {
4569 if (stmt->strict)
4570 {
4571 char *errdetail;
4572
4573 if (estate->func->print_strict_params)
4574 errdetail = format_preparedparamsdata(estate, paramLI);
4575 else
4576 errdetail = NULL;
4577
4578 ereport(ERROR,
4579 (errcode(ERRCODE_NO_DATA_FOUND),
4580 errmsg("query returned no rows"),
4581 errdetail ? errdetail_internal("parameters: %s", errdetail) : 0));
4582 }
4583 /* set the target to NULL(s) */
4584 exec_move_row(estate, target, NULL, tuptab->tupdesc);
4585 }
4586 else
4587 {
4588 if (n > 1 && stmt->strict)
4589 {
4590 char *errdetail;
4591
4592 if (estate->func->print_strict_params)
4593 errdetail = format_preparedparamsdata(estate, paramLI);
4594 else
4595 errdetail = NULL;
4596
4597 ereport(ERROR,
4598 (errcode(ERRCODE_TOO_MANY_ROWS),
4599 errmsg("query returned more than one row"),
4600 errdetail ? errdetail_internal("parameters: %s", errdetail) : 0));
4601 }
4602
4603 /* Put the first result row into the target */
4604 exec_move_row(estate, target, tuptab->vals[0], tuptab->tupdesc);
4605 }
4606 /* clean up after exec_move_row() */
4607 exec_eval_cleanup(estate);
4608 }
4609 else
4610 {
4611 /*
4612 * It might be a good idea to raise an error if the query returned
4613 * tuples that are being ignored, but historically we have not done
4614 * that.
4615 */
4616 }
4617
4618 /* Release any result from SPI_execute, as well as transient data */
4620 MemoryContextReset(stmt_mcontext);
4621
4622 return PLPGSQL_RC_OK;
4623}
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1230
static char * format_preparedparamsdata(PLpgSQL_execstate *estate, ParamListInfo paramLI)
Definition: pl_exec.c:8850
int SPI_execute_extended(const char *src, const SPIExecuteOptions *options)
Definition: spi.c:637
#define SPI_ERROR_TRANSACTION
Definition: spi.h:75
#define SPI_OK_UTILITY
Definition: spi.h:85
#define SPI_OK_REWRITTEN
Definition: spi.h:95
#define SPI_OK_INSERT
Definition: spi.h:88
#define SPI_OK_UPDATE
Definition: spi.h:90
#define SPI_OK_MERGE
Definition: spi.h:99
#define SPI_OK_UPDATE_RETURNING
Definition: spi.h:94
#define SPI_OK_DELETE
Definition: spi.h:89
#define SPI_OK_INSERT_RETURNING
Definition: spi.h:92
#define SPI_ERROR_COPY
Definition: spi.h:69
#define SPI_OK_DELETE_RETURNING
Definition: spi.h:93
#define SPI_OK_MERGE_RETURNING
Definition: spi.h:100
bool print_strict_params
Definition: plpgsql.h:995

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

Referenced by exec_stmts().

◆ exec_stmt_dynfors()

static int exec_stmt_dynfors ( PLpgSQL_execstate estate,
PLpgSQL_stmt_dynfors stmt 
)
static

Definition at line 4634 of file pl_exec.c.

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

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

4214{
4215 ParamListInfo paramLI;
4216 long tcount;
4217 int rc;
4218 PLpgSQL_expr *expr = stmt->sqlstmt;
4219 int too_many_rows_level = 0;
4220
4222 too_many_rows_level = ERROR;
4224 too_many_rows_level = WARNING;
4225
4226 /*
4227 * On the first call for this statement generate the plan, and detect
4228 * whether the statement is INSERT/UPDATE/DELETE/MERGE
4229 */
4230 if (expr->plan == NULL)
4232
4233 if (!stmt->mod_stmt_set)
4234 {
4235 ListCell *l;
4236
4237 stmt->mod_stmt = false;
4238 foreach(l, SPI_plan_get_plan_sources(expr->plan))
4239 {
4240 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(l);
4241
4242 /*
4243 * We could look at the raw_parse_tree, but it seems simpler to
4244 * check the command tag. Note we should *not* look at the Query
4245 * tree(s), since those are the result of rewriting and could be
4246 * stale, or could have been transmogrified into something else
4247 * entirely.
4248 */
4249 if (plansource->commandTag == CMDTAG_INSERT ||
4250 plansource->commandTag == CMDTAG_UPDATE ||
4251 plansource->commandTag == CMDTAG_DELETE ||
4252 plansource->commandTag == CMDTAG_MERGE)
4253 {
4254 stmt->mod_stmt = true;
4255 break;
4256 }
4257 }
4258 stmt->mod_stmt_set = true;
4259 }
4260
4261 /*
4262 * Set up ParamListInfo to pass to executor
4263 */
4264 paramLI = setup_param_list(estate, expr);
4265
4266 /*
4267 * If we have INTO, then we only need one row back ... but if we have INTO
4268 * STRICT or extra check too_many_rows, ask for two rows, so that we can
4269 * verify the statement returns only one. INSERT/UPDATE/DELETE/MERGE are
4270 * always treated strictly. Without INTO, just run the statement to
4271 * completion (tcount = 0).
4272 *
4273 * We could just ask for two rows always when using INTO, but there are
4274 * some cases where demanding the extra row costs significant time, eg by
4275 * forcing completion of a sequential scan. So don't do it unless we need
4276 * to enforce strictness.
4277 */
4278 if (stmt->into)
4279 {
4280 if (stmt->strict || stmt->mod_stmt || too_many_rows_level)
4281 tcount = 2;
4282 else
4283 tcount = 1;
4284 }
4285 else
4286 tcount = 0;
4287
4288 /*
4289 * Execute the plan
4290 */
4291 rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
4292 estate->readonly_func, tcount);
4293
4294 /*
4295 * Check for error, and set FOUND if appropriate (for historical reasons
4296 * we set FOUND only for certain query types). Also Assert that we
4297 * identified the statement type the same as SPI did.
4298 */
4299 switch (rc)
4300 {
4301 case SPI_OK_SELECT:
4302 Assert(!stmt->mod_stmt);
4303 exec_set_found(estate, (SPI_processed != 0));
4304 break;
4305
4306 case SPI_OK_INSERT:
4307 case SPI_OK_UPDATE:
4308 case SPI_OK_DELETE:
4309 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
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;
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:8793
#define PLPGSQL_XCHECK_TOOMANYROWS
Definition: plpgsql.h:1205
CommandTag commandTag
Definition: plancache.h:101

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

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

◆ exec_stmt_exit()

static int exec_stmt_exit ( PLpgSQL_execstate estate,
PLpgSQL_stmt_exit stmt 
)
static

Definition at line 3148 of file pl_exec.c.

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

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

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

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

Referenced by exec_stmts().

◆ exec_stmt_forc()

static int exec_stmt_forc ( PLpgSQL_execstate estate,
PLpgSQL_stmt_forc stmt 
)
static

Definition at line 2852 of file pl_exec.c.

2853{
2854 PLpgSQL_var *curvar;
2855 MemoryContext stmt_mcontext = NULL;
2856 char *curname = NULL;
2857 PLpgSQL_expr *query;
2858 ParamListInfo paramLI;
2859 Portal portal;
2860 int rc;
2861
2862 /* ----------
2863 * Get the cursor variable and if it has an assigned name, check
2864 * that it's not in use currently.
2865 * ----------
2866 */
2867 curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
2868 if (!curvar->isnull)
2869 {
2870 MemoryContext oldcontext;
2871
2872 /* We only need stmt_mcontext to hold the cursor name string */
2873 stmt_mcontext = get_stmt_mcontext(estate);
2874 oldcontext = MemoryContextSwitchTo(stmt_mcontext);
2875 curname = TextDatumGetCString(curvar->value);
2876 MemoryContextSwitchTo(oldcontext);
2877
2878 if (SPI_cursor_find(curname) != NULL)
2879 ereport(ERROR,
2880 (errcode(ERRCODE_DUPLICATE_CURSOR),
2881 errmsg("cursor \"%s\" already in use", curname)));
2882 }
2883
2884 /* ----------
2885 * Open the cursor just like an OPEN command
2886 *
2887 * Note: parser should already have checked that statement supplies
2888 * args iff cursor needs them, but we check again to be safe.
2889 * ----------
2890 */
2891 if (stmt->argquery != NULL)
2892 {
2893 /* ----------
2894 * OPEN CURSOR with args. We fake a SELECT ... INTO ...
2895 * statement to evaluate the args and put 'em into the
2896 * internal row.
2897 * ----------
2898 */
2899 PLpgSQL_stmt_execsql set_args;
2900
2901 if (curvar->cursor_explicit_argrow < 0)
2902 ereport(ERROR,
2903 (errcode(ERRCODE_SYNTAX_ERROR),
2904 errmsg("arguments given for cursor without arguments")));
2905
2906 memset(&set_args, 0, sizeof(set_args));
2907 set_args.cmd_type = PLPGSQL_STMT_EXECSQL;
2908 set_args.lineno = stmt->lineno;
2909 set_args.sqlstmt = stmt->argquery;
2910 set_args.into = true;
2911 /* XXX historically this has not been STRICT */
2912 set_args.target = (PLpgSQL_variable *)
2913 (estate->datums[curvar->cursor_explicit_argrow]);
2914
2915 if (exec_stmt_execsql(estate, &set_args) != PLPGSQL_RC_OK)
2916 elog(ERROR, "open cursor failed during argument processing");
2917 }
2918 else
2919 {
2920 if (curvar->cursor_explicit_argrow >= 0)
2921 ereport(ERROR,
2922 (errcode(ERRCODE_SYNTAX_ERROR),
2923 errmsg("arguments required for cursor")));
2924 }
2925
2926 query = curvar->cursor_explicit_expr;
2927 Assert(query);
2928
2929 if (query->plan == NULL)
2930 exec_prepare_plan(estate, query, curvar->cursor_options);
2931
2932 /*
2933 * Set up ParamListInfo for this query
2934 */
2935 paramLI = setup_param_list(estate, query);
2936
2937 /*
2938 * Open the cursor (the paramlist will get copied into the portal)
2939 */
2940 portal = SPI_cursor_open_with_paramlist(curname, query->plan,
2941 paramLI,
2942 estate->readonly_func);
2943 if (portal == NULL)
2944 elog(ERROR, "could not open cursor: %s",
2946
2947 /*
2948 * If cursor variable was NULL, store the generated portal name in it,
2949 * after verifying it's okay to assign to.
2950 */
2951 if (curname == NULL)
2952 {
2953 exec_check_assignable(estate, stmt->curvar);
2954 assign_text_var(estate, curvar, portal->name);
2955 }
2956
2957 /*
2958 * Clean up before entering exec_for_query
2959 */
2960 exec_eval_cleanup(estate);
2961 if (stmt_mcontext)
2962 MemoryContextReset(stmt_mcontext);
2963
2964 /*
2965 * Execute the loop. We can't prefetch because the cursor is accessible
2966 * to the user, for instance via UPDATE WHERE CURRENT OF within the loop.
2967 */
2968 rc = exec_for_query(estate, (PLpgSQL_stmt_forq *) stmt, portal, false);
2969
2970 /* ----------
2971 * Close portal, and restore cursor variable if it was initially NULL.
2972 * ----------
2973 */
2974 SPI_cursor_close(portal);
2975
2976 if (curname == NULL)
2977 assign_simple_var(estate, curvar, (Datum) 0, true, false);
2978
2979 return rc;
2980}
static int exec_stmt_execsql(PLpgSQL_execstate *estate, PLpgSQL_stmt_execsql *stmt)
Definition: pl_exec.c:4212
@ PLPGSQL_STMT_EXECSQL
Definition: plpgsql.h:120
PLpgSQL_variable * target
Definition: plpgsql.h:901
PLpgSQL_expr * sqlstmt
Definition: plpgsql.h:896
PLpgSQL_stmt_type cmd_type
Definition: plpgsql.h:893
int cursor_explicit_argrow
Definition: plpgsql.h:328
int cursor_options
Definition: plpgsql.h:329
PLpgSQL_expr * cursor_explicit_expr
Definition: plpgsql.h:327
const char * name
Definition: portal.h:118

References Assert, assign_simple_var(), assign_text_var(), PLpgSQL_stmt_execsql::cmd_type, PLpgSQL_var::cursor_explicit_argrow, PLpgSQL_var::cursor_explicit_expr, PLpgSQL_var::cursor_options, PLpgSQL_execstate::datums, elog, ereport, errcode(), errmsg(), ERROR, exec_check_assignable(), exec_eval_cleanup(), exec_for_query(), exec_prepare_plan(), exec_stmt_execsql(), get_stmt_mcontext(), PLpgSQL_stmt_execsql::into, PLpgSQL_var::isnull, PLpgSQL_stmt_execsql::lineno, MemoryContextReset(), MemoryContextSwitchTo(), PortalData::name, PLpgSQL_expr::plan, PLPGSQL_RC_OK, PLPGSQL_STMT_EXECSQL, PLpgSQL_execstate::readonly_func, setup_param_list(), SPI_cursor_close(), SPI_cursor_find(), SPI_cursor_open_with_paramlist(), SPI_result, SPI_result_code_string(), PLpgSQL_stmt_execsql::sqlstmt, stmt, PLpgSQL_stmt_execsql::target, TextDatumGetCString, and PLpgSQL_var::value.

Referenced by exec_stmts().

◆ exec_stmt_foreach_a()

static int exec_stmt_foreach_a ( PLpgSQL_execstate estate,
PLpgSQL_stmt_foreach_a stmt 
)
static

Definition at line 2992 of file pl_exec.c.

2993{
2994 ArrayType *arr;
2995 Oid arrtype;
2996 int32 arrtypmod;
2997 PLpgSQL_datum *loop_var;
2998 Oid loop_var_elem_type;
2999 bool found = false;
3000 int rc = PLPGSQL_RC_OK;
3001 MemoryContext stmt_mcontext;
3002 MemoryContext oldcontext;
3004 Oid iterator_result_type;
3005 int32 iterator_result_typmod;
3006 Datum value;
3007 bool isnull;
3008
3009 /* get the value of the array expression */
3010 value = exec_eval_expr(estate, stmt->expr, &isnull, &arrtype, &arrtypmod);
3011 if (isnull)
3012 ereport(ERROR,
3013 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
3014 errmsg("FOREACH expression must not be null")));
3015
3016 /*
3017 * Do as much as possible of the code below in stmt_mcontext, to avoid any
3018 * leaks from called subroutines. We need a private stmt_mcontext since
3019 * we'll be calling arbitrary statement code.
3020 */
3021 stmt_mcontext = get_stmt_mcontext(estate);
3022 push_stmt_mcontext(estate);
3023 oldcontext = MemoryContextSwitchTo(stmt_mcontext);
3024
3025 /* check the type of the expression - must be an array */
3026 if (!OidIsValid(get_element_type(arrtype)))
3027 ereport(ERROR,
3028 (errcode(ERRCODE_DATATYPE_MISMATCH),
3029 errmsg("FOREACH expression must yield an array, not type %s",
3030 format_type_be(arrtype))));
3031
3032 /*
3033 * We must copy the array into stmt_mcontext, else it will disappear in
3034 * exec_eval_cleanup. This is annoying, but cleanup will certainly happen
3035 * while running the loop body, so we have little choice.
3036 */
3038
3039 /* Clean up any leftover temporary memory */
3040 exec_eval_cleanup(estate);
3041
3042 /* Slice dimension must be less than or equal to array dimension */
3043 if (stmt->slice < 0 || stmt->slice > ARR_NDIM(arr))
3044 ereport(ERROR,
3045 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
3046 errmsg("slice dimension (%d) is out of the valid range 0..%d",
3047 stmt->slice, ARR_NDIM(arr))));
3048
3049 /* Set up the loop variable and see if it is of an array type */
3050 loop_var = estate->datums[stmt->varno];
3051 if (loop_var->dtype == PLPGSQL_DTYPE_REC ||
3052 loop_var->dtype == PLPGSQL_DTYPE_ROW)
3053 {
3054 /*
3055 * Record/row variable is certainly not of array type, and might not
3056 * be initialized at all yet, so don't try to get its type
3057 */
3058 loop_var_elem_type = InvalidOid;
3059 }
3060 else
3061 loop_var_elem_type = get_element_type(plpgsql_exec_get_datum_type(estate,
3062 loop_var));
3063
3064 /*
3065 * Sanity-check the loop variable type. We don't try very hard here, and
3066 * should not be too picky since it's possible that exec_assign_value can
3067 * coerce values of different types. But it seems worthwhile to complain
3068 * if the array-ness of the loop variable is not right.
3069 */
3070 if (stmt->slice > 0 && loop_var_elem_type == InvalidOid)
3071 ereport(ERROR,
3072 (errcode(ERRCODE_DATATYPE_MISMATCH),
3073 errmsg("FOREACH ... SLICE loop variable must be of an array type")));
3074 if (stmt->slice == 0 && loop_var_elem_type != InvalidOid)
3075 ereport(ERROR,
3076 (errcode(ERRCODE_DATATYPE_MISMATCH),
3077 errmsg("FOREACH loop variable must not be of an array type")));
3078
3079 /* Create an iterator to step through the array */
3080 array_iterator = array_create_iterator(arr, stmt->slice, NULL);
3081
3082 /* Identify iterator result type */
3083 if (stmt->slice > 0)
3084 {
3085 /* When slicing, nominal type of result is same as array type */
3086 iterator_result_type = arrtype;
3087 iterator_result_typmod = arrtypmod;
3088 }
3089 else
3090 {
3091 /* Without slicing, results are individual array elements */
3092 iterator_result_type = ARR_ELEMTYPE(arr);
3093 iterator_result_typmod = arrtypmod;
3094 }
3095
3096 /* Iterate over the array elements or slices */
3097 while (array_iterate(array_iterator, &value, &isnull))
3098 {
3099 found = true; /* looped at least once */
3100
3101 /* exec_assign_value and exec_stmts must run in the main context */
3102 MemoryContextSwitchTo(oldcontext);
3103
3104 /* Assign current element/slice to the loop variable */
3105 exec_assign_value(estate, loop_var, value, isnull,
3106 iterator_result_type, iterator_result_typmod);
3107
3108 /* In slice case, value is temporary; must free it to avoid leakage */
3109 if (stmt->slice > 0)
3111
3112 /*
3113 * Execute the statements
3114 */
3115 rc = exec_stmts(estate, stmt->body);
3116
3117 LOOP_RC_PROCESSING(stmt->label, break);
3118
3119 MemoryContextSwitchTo(stmt_mcontext);
3120 }
3121
3122 /* Restore memory context state */
3123 MemoryContextSwitchTo(oldcontext);
3124 pop_stmt_mcontext(estate);
3125
3126 /* Release temporary memory, including the array value */
3127 MemoryContextReset(stmt_mcontext);
3128
3129 /*
3130 * Set the FOUND variable to indicate the result of executing the loop
3131 * (namely, whether we looped one or more times). This must be set here so
3132 * that it does not interfere with the value of the FOUND variable inside
3133 * the loop processing itself.
3134 */
3135 exec_set_found(estate, found);
3136
3137 return rc;
3138}
static bool array_iterator(ArrayType *la, PGCALL2 callback, void *param, ltree **found)
Definition: _ltree_op.c:38
#define DatumGetArrayTypePCopy(X)
Definition: array.h:262
#define ARR_NDIM(a)
Definition: array.h:290
#define ARR_ELEMTYPE(a)
Definition: array.h:292
bool array_iterate(ArrayIterator iterator, Datum *value, bool *isnull)
Definition: arrayfuncs.c:4676
ArrayIterator array_create_iterator(ArrayType *arr, int slice_ndim, ArrayMetaState *mstate)
Definition: arrayfuncs.c:4597
#define OidIsValid(objectId)
Definition: c.h:732
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2759
static void push_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1547
Oid plpgsql_exec_get_datum_type(PLpgSQL_execstate *estate, PLpgSQL_datum *datum)
Definition: pl_exec.c:5457

References ARR_ELEMTYPE, ARR_NDIM, array_create_iterator(), array_iterate(), array_iterator(), DatumGetArrayTypePCopy, DatumGetPointer(), PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, ereport, errcode(), errmsg(), ERROR, exec_assign_value(), exec_eval_cleanup(), exec_eval_expr(), exec_set_found(), exec_stmts(), format_type_be(), get_element_type(), get_stmt_mcontext(), InvalidOid, LOOP_RC_PROCESSING, MemoryContextReset(), MemoryContextSwitchTo(), OidIsValid, pfree(), PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_ROW, plpgsql_exec_get_datum_type(), PLPGSQL_RC_OK, pop_stmt_mcontext(), push_stmt_mcontext(), stmt, and value.

Referenced by exec_stmts().

◆ exec_stmt_fori()

static int exec_stmt_fori ( PLpgSQL_execstate estate,
PLpgSQL_stmt_fori stmt 
)
static

Definition at line 2680 of file pl_exec.c.

2681{
2682 PLpgSQL_var *var;
2683 Datum value;
2684 bool isnull;
2685 Oid valtype;
2686 int32 valtypmod;
2687 int32 loop_value;
2688 int32 end_value;
2689 int32 step_value;
2690 bool found = false;
2691 int rc = PLPGSQL_RC_OK;
2692
2693 var = (PLpgSQL_var *) (estate->datums[stmt->var->dno]);
2694
2695 /*
2696 * Get the value of the lower bound
2697 */
2698 value = exec_eval_expr(estate, stmt->lower,
2699 &isnull, &valtype, &valtypmod);