PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 "nodes/supportnodes.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
 
struct  count_param_references_context
 

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
 
typedef struct count_param_references_context count_param_references_context
 

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, int paramid)
 
static bool count_param_references (Node *node, count_param_references_context *context)
 
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_check (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void plpgsql_param_eval_var_transfer (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
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 129 of file pl_exec.c.

◆ eval_mcontext_alloc0

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

Definition at line 131 of file pl_exec.c.

◆ get_eval_mcontext

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

Definition at line 127 of file pl_exec.c.

◆ LOOP_RC_PROCESSING

#define LOOP_RC_PROCESSING (   looplabel,
  exit_action 
)

Definition at line 204 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:1686
const char * name

Definition at line 3724 of file pl_exec.c.

Typedef Documentation

◆ count_param_references_context

◆ SimpleEcontextStackEntry

Function Documentation

◆ assign_record_var()

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

Definition at line 8856 of file pl_exec.c.

8858{
8860
8861 /* Transfer new record object into datum_context */
8863
8864 /* Free the old value ... */
8865 if (rec->erh)
8867
8868 /* ... and install the new */
8869 rec->erh = erh;
8870}
void DeleteExpandedObject(Datum d)
static Datum ExpandedRecordGetDatum(const ExpandedRecordHeader *erh)
#define TransferExpandedRecord(erh, cxt)
Assert(PointerIsAligned(start, uint64))
@ PLPGSQL_DTYPE_REC
Definition: plpgsql.h:65
MemoryContext datum_context
Definition: plpgsql.h:1086
ExpandedRecordHeader * erh
Definition: plpgsql.h:436
PLpgSQL_datum_type dtype
Definition: plpgsql.h:413

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

8782{
8783 Assert(var->dtype == PLPGSQL_DTYPE_VAR ||
8785
8786 /*
8787 * In non-atomic contexts, we do not want to store TOAST pointers in
8788 * variables, because such pointers might become stale after a commit.
8789 * Forcibly detoast in such cases. We don't want to detoast (flatten)
8790 * expanded objects, however; those should be OK across a transaction
8791 * boundary since they're just memory-resident objects. (Elsewhere in
8792 * this module, operations on expanded records likewise need to request
8793 * detoasting of record fields when !estate->atomic. Expanded arrays are
8794 * not a problem since all array entries are always detoasted.)
8795 */
8796 if (!estate->atomic && !isnull && var->datatype->typlen == -1 &&
8798 {
8799 MemoryContext oldcxt;
8800 Datum detoasted;
8801
8802 /*
8803 * Do the detoasting in the eval_mcontext to avoid long-term leakage
8804 * of whatever memory toast fetching might leak. Then we have to copy
8805 * the detoasted datum to the function's main context, which is a
8806 * pain, but there's little choice.
8807 */
8808 oldcxt = MemoryContextSwitchTo(get_eval_mcontext(estate));
8809 detoasted = PointerGetDatum(detoast_external_attr((struct varlena *) DatumGetPointer(newvalue)));
8810 MemoryContextSwitchTo(oldcxt);
8811 /* Now's a good time to not leak the input value if it's freeable */
8812 if (freeable)
8813 pfree(DatumGetPointer(newvalue));
8814 /* Once we copy the value, it's definitely freeable */
8815 newvalue = datumCopy(detoasted, false, -1);
8816 freeable = true;
8817 /* Can't clean up eval_mcontext here, but it'll happen before long */
8818 }
8819
8820 /* Free the old value if needed */
8821 if (var->freeval)
8822 {
8824 var->isnull,
8825 var->datatype->typlen))
8827 else
8829 }
8830 /* Assign new value to datum */
8831 var->value = newvalue;
8832 var->isnull = isnull;
8833 var->freeval = freeable;
8834
8835 /*
8836 * If it's a promise variable, then either we just assigned the promised
8837 * value, or the user explicitly assigned an overriding value. Either
8838 * way, cancel the promise.
8839 */
8841}
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:1524
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define get_eval_mcontext(estate)
Definition: pl_exec.c:127
@ 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:214
PLpgSQL_promise_type promise
Definition: plpgsql.h:364
PLpgSQL_datum_type dtype
Definition: plpgsql.h:333
bool freeval
Definition: plpgsql.h:357
bool isnull
Definition: plpgsql.h:356
PLpgSQL_type * datatype
Definition: plpgsql.h:342
Datum value
Definition: plpgsql.h:355
Definition: c.h:658
#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 8847 of file pl_exec.c.

8848{
8849 assign_simple_var(estate, var, CStringGetTextDatum(str), false, true);
8850}
#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:8780

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

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

7458{
7459 int i;
7460
7461 /* Possibly we could allow src_tupdesc to have extra columns? */
7462 if (dst_tupdesc->natts != src_tupdesc->natts)
7463 return false;
7464
7465 for (i = 0; i < dst_tupdesc->natts; i++)
7466 {
7467 Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
7468 Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
7469
7470 if (dattr->attisdropped != sattr->attisdropped)
7471 return false;
7472 if (!dattr->attisdropped)
7473 {
7474 /* Normal columns must match by type and typmod */
7475 if (dattr->atttypid != sattr->atttypid ||
7476 (dattr->atttypmod >= 0 &&
7477 dattr->atttypmod != sattr->atttypmod))
7478 return false;
7479 }
7480 else
7481 {
7482 /* Dropped columns are OK as long as length/alignment match */
7483 if (dattr->attlen != sattr->attlen ||
7484 dattr->attalign != sattr->attalign)
7485 return false;
7486 }
7487 }
7488 return true;
7489}
int i
Definition: isn.c:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:154

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

7856{
7857 char *result;
7858 MemoryContext oldcontext;
7859 Oid typoutput;
7860 bool typIsVarlena;
7861
7862 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7863 getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
7864 result = OidOutputFunctionCall(typoutput, value);
7865 MemoryContextSwitchTo(oldcontext);
7866
7867 return result;
7868}
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1763
static struct @165 value
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2990
unsigned int Oid
Definition: postgres_ext.h:30

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

1312{
1313 int ndatums = estate->ndatums;
1314 PLpgSQL_datum **indatums;
1315 PLpgSQL_datum **outdatums;
1316 char *workspace;
1317 char *ws_next;
1318 int i;
1319
1320 /* Allocate local datum-pointer array */
1321 estate->datums = (PLpgSQL_datum **)
1322 palloc(sizeof(PLpgSQL_datum *) * ndatums);
1323
1324 /*
1325 * To reduce palloc overhead, we make a single palloc request for all the
1326 * space needed for locally-instantiated datums.
1327 */
1328 workspace = palloc(func->copiable_size);
1329 ws_next = workspace;
1330
1331 /* Fill datum-pointer array, copying datums into workspace as needed */
1332 indatums = func->datums;
1333 outdatums = estate->datums;
1334 for (i = 0; i < ndatums; i++)
1335 {
1336 PLpgSQL_datum *indatum = indatums[i];
1337 PLpgSQL_datum *outdatum;
1338
1339 /* This must agree with plpgsql_finish_datums on what is copiable */
1340 switch (indatum->dtype)
1341 {
1342 case PLPGSQL_DTYPE_VAR:
1344 outdatum = (PLpgSQL_datum *) ws_next;
1345 memcpy(outdatum, indatum, sizeof(PLpgSQL_var));
1346 ws_next += MAXALIGN(sizeof(PLpgSQL_var));
1347 break;
1348
1349 case PLPGSQL_DTYPE_REC:
1350 outdatum = (PLpgSQL_datum *) ws_next;
1351 memcpy(outdatum, indatum, sizeof(PLpgSQL_rec));
1352 ws_next += MAXALIGN(sizeof(PLpgSQL_rec));
1353 break;
1354
1355 case PLPGSQL_DTYPE_ROW:
1357
1358 /*
1359 * These datum records are read-only at runtime, so no need to
1360 * copy them (well, RECFIELD contains cached data, but we'd
1361 * just as soon centralize the caching anyway).
1362 */
1363 outdatum = indatum;
1364 break;
1365
1366 default:
1367 elog(ERROR, "unrecognized dtype: %d", indatum->dtype);
1368 outdatum = NULL; /* keep compiler quiet */
1369 break;
1370 }
1371
1372 outdatums[i] = outdatum;
1373 }
1374
1375 Assert(ws_next == workspace + func->copiable_size);
1376}
#define MAXALIGN(LEN)
Definition: c.h:782
#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:299
PLpgSQL_datum ** datums
Definition: plpgsql.h:1084
Size copiable_size
Definition: plpgsql.h:1029
PLpgSQL_datum ** datums
Definition: plpgsql.h:1028

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

◆ count_param_references()

static bool count_param_references ( Node node,
count_param_references_context context 
)
static

Definition at line 8541 of file pl_exec.c.

8542{
8543 if (node == NULL)
8544 return false;
8545 else if (IsA(node, Param))
8546 {
8547 Param *param = (Param *) node;
8548
8549 if (param->paramkind == PARAM_EXTERN &&
8550 param->paramid == context->paramid)
8551 {
8552 context->last_param = param;
8553 if (++(context->count) > 1)
8554 return true; /* abort tree traversal */
8555 }
8556 return false;
8557 }
8558 else
8559 return expression_tree_walker(node, count_param_references, context);
8560}
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:153
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
static bool count_param_references(Node *node, count_param_references_context *context)
Definition: pl_exec.c:8541
@ PARAM_EXTERN
Definition: primnodes.h:384
int paramid
Definition: primnodes.h:394
ParamKind paramkind
Definition: primnodes.h:393

References count_param_references_context::count, count_param_references(), expression_tree_walker, IsA, count_param_references_context::last_param, PARAM_EXTERN, Param::paramid, count_param_references_context::paramid, and Param::paramkind.

Referenced by count_param_references(), and exec_check_rw_parameter().

◆ deconstruct_composite_datum()

static TupleDesc deconstruct_composite_datum ( Datum  value,
HeapTupleData tmptup 
)
static

Definition at line 7556 of file pl_exec.c.

7557{
7558 HeapTupleHeader td;
7559 Oid tupType;
7560 int32 tupTypmod;
7561
7562 /* Get tuple body (note this could involve detoasting) */
7564
7565 /* Build a temporary HeapTuple control structure */
7567 ItemPointerSetInvalid(&(tmptup->t_self));
7568 tmptup->t_tableOid = InvalidOid;
7569 tmptup->t_data = td;
7570
7571 /* Extract rowtype info and find a tupdesc */
7572 tupType = HeapTupleHeaderGetTypeId(td);
7573 tupTypmod = HeapTupleHeaderGetTypMod(td);
7574 return lookup_rowtype_tupdesc(tupType, tupTypmod);
7575}
int32_t int32
Definition: c.h:498
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:295
static int32 HeapTupleHeaderGetTypMod(const HeapTupleHeaderData *tup)
Definition: htup_details.h:516
static uint32 HeapTupleHeaderGetDatumLength(const HeapTupleHeaderData *tup)
Definition: htup_details.h:492
static Oid HeapTupleHeaderGetTypeId(const HeapTupleHeaderData *tup)
Definition: htup_details.h:504
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition: itemptr.h:184
#define InvalidOid
Definition: postgres_ext.h:35
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 7908 of file pl_exec.c.

7912{
7913 plpgsql_CastHashEntry *cast_entry;
7914
7915 cast_entry = get_cast_hashentry(estate,
7916 valtype, valtypmod,
7917 reqtype, reqtypmod);
7918 if (cast_entry)
7919 {
7920 ExprContext *econtext = estate->eval_econtext;
7921 MemoryContext oldcontext;
7922
7923 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7924
7925 econtext->caseValue_datum = value;
7926 econtext->caseValue_isNull = *isnull;
7927
7928 cast_entry->cast_in_use = true;
7929
7930 value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
7931 isnull);
7932
7933 cast_entry->cast_in_use = false;
7934
7935 MemoryContextSwitchTo(oldcontext);
7936 }
7937
7938 return value;
7939}
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:411
static plpgsql_CastHashEntry * get_cast_hashentry(PLpgSQL_execstate *estate, Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod)
Definition: pl_exec.c:7952
bool caseValue_isNull
Definition: execnodes.h:295
Datum caseValue_datum
Definition: execnodes.h:293
ExprContext * eval_econtext
Definition: plpgsql.h:1113
ExprState * cast_exprstate
Definition: pl_exec.c:173

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

1596{
1597 for (; cond != NULL; cond = cond->next)
1598 {
1599 int sqlerrstate = cond->sqlerrstate;
1600
1601 /*
1602 * OTHERS matches everything *except* query-canceled and
1603 * assert-failure. If you're foolish enough, you can match those
1604 * explicitly.
1605 */
1606 if (sqlerrstate == PLPGSQL_OTHERS)
1607 {
1608 if (edata->sqlerrcode != ERRCODE_QUERY_CANCELED &&
1609 edata->sqlerrcode != ERRCODE_ASSERT_FAILURE)
1610 return true;
1611 }
1612 /* Exact match? */
1613 else if (edata->sqlerrcode == sqlerrstate)
1614 return true;
1615 /* Category match? */
1616 else if (ERRCODE_IS_CATEGORY(sqlerrstate) &&
1617 ERRCODE_TO_CATEGORY(edata->sqlerrcode) == sqlerrstate)
1618 return true;
1619 }
1620 return false;
1621}
#define ERRCODE_IS_CATEGORY(ec)
Definition: elog.h:62
#define ERRCODE_TO_CATEGORY(ec)
Definition: elog.h:61
#define PLPGSQL_OTHERS
Definition: plpgsql.h:499
int sqlerrcode
Definition: elog.h:430
struct PLpgSQL_condition * next
Definition: plpgsql.h:495

References ERRCODE_IS_CATEGORY, ERRCODE_TO_CATEGORY, PLpgSQL_condition::next, PLPGSQL_OTHERS, 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 5047 of file pl_exec.c.

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

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

5019{
5020 Datum value;
5021 bool isnull;
5022 Oid valtype;
5023 int32 valtypmod;
5024
5025 /*
5026 * If first time through, create a plan for this expression.
5027 */
5028 if (expr->plan == NULL)
5029 exec_prepare_plan(estate, expr, 0);
5030
5031 value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod);
5032 exec_assign_value(estate, target, value, isnull, valtype, valtypmod);
5033 exec_eval_cleanup(estate);
5034}
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:4150
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions)
Definition: pl_exec.c:4187
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5679
SPIPlanPtr plan
Definition: plpgsql.h:250

References exec_assign_value(), exec_eval_cleanup(), exec_eval_expr(), exec_prepare_plan(), PLpgSQL_expr::plan, 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 5075 of file pl_exec.c.

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

7888{
7889 /*
7890 * If the type of the given value isn't what's requested, convert it.
7891 */
7892 if (valtype != reqtype ||
7893 (valtypmod != reqtypmod && reqtypmod != -1))
7894 {
7895 /* We keep the slow path out-of-line. */
7896 value = do_cast_value(estate, value, isnull, valtype, valtypmod,
7897 reqtype, reqtypmod);
7898 }
7899
7900 return value;
7901}
static Datum do_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7908

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

8569{
8570 PLpgSQL_datum *datum;
8571
8572 Assert(dno >= 0 && dno < estate->ndatums);
8573 datum = estate->datums[dno];
8574 switch (datum->dtype)
8575 {
8576 case PLPGSQL_DTYPE_VAR:
8578 case PLPGSQL_DTYPE_REC:
8579 if (((PLpgSQL_variable *) datum)->isconst)
8580 ereport(ERROR,
8581 (errcode(ERRCODE_ERROR_IN_ASSIGNMENT),
8582 errmsg("variable \"%s\" is declared CONSTANT",
8583 ((PLpgSQL_variable *) datum)->refname)));
8584 break;
8585 case PLPGSQL_DTYPE_ROW:
8586 /* always assignable; member vars were checked at compile time */
8587 break;
8589 /* assignable if parent record is */
8590 exec_check_assignable(estate,
8591 ((PLpgSQL_recfield *) datum)->recparentno);
8592 break;
8593 default:
8594 elog(ERROR, "unrecognized dtype: %d", datum->dtype);
8595 break;
8596 }
8597}
static void exec_check_assignable(PLpgSQL_execstate *estate, int dno)
Definition: pl_exec.c:8568
PLpgSQL_datum_type dtype
Definition: plpgsql.h:311

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,
int  paramid 
)
static

Definition at line 8411 of file pl_exec.c.

8412{
8413 Expr *sexpr = expr->expr_simple_expr;
8414 Oid funcid;
8415 List *fargs;
8416 Oid prosupport;
8417
8418 /* Assume unsafe */
8420 expr->expr_rw_param = NULL;
8421
8422 /* Shouldn't be here for non-simple expression */
8423 Assert(sexpr != NULL);
8424
8425 /* Param should match the expression's assignment target, too */
8426 Assert(paramid == expr->target_param + 1);
8427
8428 /*
8429 * If the assignment is to a "local" variable (one whose value won't
8430 * matter anymore if expression evaluation fails), and this Param is the
8431 * only reference to that variable in the expression, then we can
8432 * unconditionally optimize using the "transfer" method.
8433 */
8434 if (expr->target_is_local)
8435 {
8437
8438 /* See how many references there are, and find one of them */
8439 context.paramid = paramid;
8440 context.count = 0;
8441 context.last_param = NULL;
8442 (void) count_param_references((Node *) sexpr, &context);
8443
8444 /* If we're here, the expr must contain some reference to the var */
8445 Assert(context.count > 0);
8446
8447 /* If exactly one reference, success! */
8448 if (context.count == 1)
8449 {
8451 expr->expr_rw_param = context.last_param;
8452 return;
8453 }
8454 }
8455
8456 /*
8457 * Otherwise, see if we can trust the expression's top-level function to
8458 * apply the "inplace" method.
8459 *
8460 * Top level of expression must be a simple FuncExpr, OpExpr, or
8461 * SubscriptingRef, else we can't identify which function is relevant. But
8462 * it's okay to look through any RelabelType above that, since that can't
8463 * fail.
8464 */
8465 if (IsA(sexpr, RelabelType))
8466 sexpr = ((RelabelType *) sexpr)->arg;
8467 if (IsA(sexpr, FuncExpr))
8468 {
8469 FuncExpr *fexpr = (FuncExpr *) sexpr;
8470
8471 funcid = fexpr->funcid;
8472 fargs = fexpr->args;
8473 }
8474 else if (IsA(sexpr, OpExpr))
8475 {
8476 OpExpr *opexpr = (OpExpr *) sexpr;
8477
8478 funcid = opexpr->opfuncid;
8479 fargs = opexpr->args;
8480 }
8481 else if (IsA(sexpr, SubscriptingRef))
8482 {
8483 SubscriptingRef *sbsref = (SubscriptingRef *) sexpr;
8484
8485 funcid = get_typsubscript(sbsref->refcontainertype, NULL);
8486
8487 /*
8488 * We assume that only the refexpr and refassgnexpr (if any) are
8489 * relevant to the support function's decision. If that turns out to
8490 * be a bad idea, we could incorporate the subscript expressions into
8491 * the fargs list somehow.
8492 */
8493 fargs = list_make2(sbsref->refexpr, sbsref->refassgnexpr);
8494 }
8495 else
8496 return;
8497
8498 /*
8499 * The top-level function must be one that can handle in-place update
8500 * safely. We allow functions to declare their ability to do that via a
8501 * support function request.
8502 */
8503 prosupport = get_func_support(funcid);
8504 if (OidIsValid(prosupport))
8505 {
8507 Param *param;
8508
8509 req.type = T_SupportRequestModifyInPlace;
8510 req.funcid = funcid;
8511 req.args = fargs;
8512 req.paramid = paramid;
8513
8514 param = (Param *)
8516 PointerGetDatum(&req)));
8517
8518 if (param == NULL)
8519 return; /* support function fails */
8520
8521 /* Verify support function followed the API */
8522 Assert(IsA(param, Param));
8523 Assert(param->paramkind == PARAM_EXTERN);
8524 Assert(param->paramid == paramid);
8525
8526 /* Found the Param we want to pass as read/write */
8528 expr->expr_rw_param = param;
8529 return;
8530 }
8531}
#define OidIsValid(objectId)
Definition: c.h:746
#define OidFunctionCall1(functionId, arg1)
Definition: fmgr.h:679
RegProcedure get_func_support(Oid funcid)
Definition: lsyscache.c:1941
RegProcedure get_typsubscript(Oid typid, Oid *typelemp)
Definition: lsyscache.c:3180
#define list_make2(x1, x2)
Definition: pg_list.h:214
@ PLPGSQL_RWOPT_INPLACE
Definition: plpgsql.h:198
@ PLPGSQL_RWOPT_TRANSFER
Definition: plpgsql.h:197
@ PLPGSQL_RWOPT_NOPE
Definition: plpgsql.h:196
Oid funcid
Definition: primnodes.h:767
List * args
Definition: primnodes.h:785
Definition: pg_list.h:54
Definition: nodes.h:135
List * args
Definition: primnodes.h:853
int target_param
Definition: plpgsql.h:243
Expr * expr_simple_expr
Definition: plpgsql.h:254
bool target_is_local
Definition: plpgsql.h:244
PLpgSQL_rwopt expr_rwopt
Definition: plpgsql.h:267
Param * expr_rw_param
Definition: plpgsql.h:268
Expr * refassgnexpr
Definition: primnodes.h:720
Expr * refexpr
Definition: primnodes.h:718

References FuncExpr::args, OpExpr::args, SupportRequestModifyInPlace::args, Assert(), count_param_references_context::count, count_param_references(), DatumGetPointer(), PLpgSQL_expr::expr_rw_param, PLpgSQL_expr::expr_rwopt, PLpgSQL_expr::expr_simple_expr, FuncExpr::funcid, SupportRequestModifyInPlace::funcid, get_func_support(), get_typsubscript(), IsA, count_param_references_context::last_param, list_make2, OidFunctionCall1, OidIsValid, PARAM_EXTERN, Param::paramid, SupportRequestModifyInPlace::paramid, count_param_references_context::paramid, Param::paramkind, PLPGSQL_RWOPT_INPLACE, PLPGSQL_RWOPT_NOPE, PLPGSQL_RWOPT_TRANSFER, PointerGetDatum(), SubscriptingRef::refassgnexpr, SubscriptingRef::refexpr, PLpgSQL_expr::target_is_local, PLpgSQL_expr::target_param, and SupportRequestModifyInPlace::type.

Referenced by plpgsql_param_eval_var_check().

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

8966{
8967 Portal portal;
8968 Datum query;
8969 bool isnull;
8970 Oid restype;
8971 int32 restypmod;
8972 char *querystr;
8974 MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
8975
8976 /*
8977 * Evaluate the string expression after the EXECUTE keyword. Its result is
8978 * the querystring we have to execute.
8979 */
8980 query = exec_eval_expr(estate, dynquery, &isnull, &restype, &restypmod);
8981 if (isnull)
8982 ereport(ERROR,
8983 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
8984 errmsg("query string argument of EXECUTE is null")));
8985
8986 /* Get the C-String representation */
8987 querystr = convert_value_to_string(estate, query, restype);
8988
8989 /* copy it into the stmt_mcontext before we clean up */
8990 querystr = MemoryContextStrdup(stmt_mcontext, querystr);
8991
8992 exec_eval_cleanup(estate);
8993
8994 /*
8995 * Open an implicit cursor for the query. We use SPI_cursor_parse_open
8996 * even when there are no params, because this avoids making and freeing
8997 * one copy of the plan.
8998 */
8999 memset(&options, 0, sizeof(options));
9000 options.params = exec_eval_using_params(estate, params);
9001 options.cursorOptions = cursorOptions;
9002 options.read_only = estate->readonly_func;
9003
9004 portal = SPI_cursor_parse_open(portalname, querystr, &options);
9005
9006 if (portal == NULL)
9007 elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
9009
9010 /* Release transient data */
9011 MemoryContextReset(stmt_mcontext);
9012
9013 return portal;
9014}
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:7855
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1544
static ParamListInfo exec_eval_using_params(PLpgSQL_execstate *estate, List *params)
Definition: pl_exec.c:8879
const char * SPI_result_code_string(int code)
Definition: spi.c:1974
int SPI_result
Definition: spi.c:46
Portal SPI_cursor_parse_open(const char *name, const char *src, const SPIParseOpenOptions *options)
Definition: spi.c:1534

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

5659{
5660 Datum exprdatum;
5661 Oid exprtypeid;
5662 int32 exprtypmod;
5663
5664 exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5665 exprdatum = exec_cast_value(estate, exprdatum, isNull,
5666 exprtypeid, exprtypmod,
5667 BOOLOID, -1);
5668 return DatumGetBool(exprdatum);
5669}
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 4150 of file pl_exec.c.

4151{
4152 /* Clear result of a full SPI_execute */
4153 if (estate->eval_tuptable != NULL)
4155 estate->eval_tuptable = NULL;
4156
4157 /*
4158 * Clear result of exec_eval_simple_expr (but keep the econtext). This
4159 * also clears any short-lived allocations done via get_eval_mcontext.
4160 */
4161 if (estate->eval_econtext != NULL)
4163}
#define ResetExprContext(econtext)
Definition: executor.h:668
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1387
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1111

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

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

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

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

5636{
5637 Datum exprdatum;
5638 Oid exprtypeid;
5639 int32 exprtypmod;
5640
5641 exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5642 exprdatum = exec_cast_value(estate, exprdatum, isNull,
5643 exprtypeid, exprtypmod,
5644 INT4OID, -1);
5645 return DatumGetInt32(exprdatum);
5646}
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 6029 of file pl_exec.c.

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

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_rwopt, 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, PLPGSQL_RWOPT_UNKNOWN, 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 8879 of file pl_exec.c.

8880{
8881 ParamListInfo paramLI;
8882 int nargs;
8883 MemoryContext stmt_mcontext;
8884 MemoryContext oldcontext;
8885 int i;
8886 ListCell *lc;
8887
8888 /* Fast path for no parameters: we can just return NULL */
8889 if (params == NIL)
8890 return NULL;
8891
8892 nargs = list_length(params);
8893 stmt_mcontext = get_stmt_mcontext(estate);
8894 oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8895 paramLI = makeParamList(nargs);
8896 MemoryContextSwitchTo(oldcontext);
8897
8898 i = 0;
8899 foreach(lc, params)
8900 {
8901 PLpgSQL_expr *param = (PLpgSQL_expr *) lfirst(lc);
8902 ParamExternData *prm = &paramLI->params[i];
8903 int32 ppdtypmod;
8904
8905 /*
8906 * Always mark params as const, since we only use the result with
8907 * one-shot plans.
8908 */
8909 prm->pflags = PARAM_FLAG_CONST;
8910
8911 prm->value = exec_eval_expr(estate, param,
8912 &prm->isnull,
8913 &prm->ptype,
8914 &ppdtypmod);
8915
8916 oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8917
8918 if (prm->ptype == UNKNOWNOID)
8919 {
8920 /*
8921 * Treat 'unknown' parameters as text, since that's what most
8922 * people would expect. The SPI functions can coerce unknown
8923 * constants in a more intelligent way, but not unknown Params.
8924 * This code also takes care of copying into the right context.
8925 * Note we assume 'unknown' has the representation of C-string.
8926 */
8927 prm->ptype = TEXTOID;
8928 if (!prm->isnull)
8930 }
8931 /* pass-by-ref non null values must be copied into stmt_mcontext */
8932 else if (!prm->isnull)
8933 {
8934 int16 typLen;
8935 bool typByVal;
8936
8937 get_typlenbyval(prm->ptype, &typLen, &typByVal);
8938 if (!typByVal)
8939 prm->value = datumCopy(prm->value, typByVal, typLen);
8940 }
8941
8942 MemoryContextSwitchTo(oldcontext);
8943
8944 exec_eval_cleanup(estate);
8945
8946 i++;
8947 }
8948
8949 return paramLI;
8950}
int16_t int16
Definition: c.h:497
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2334
ParamListInfo makeParamList(int numParams)
Definition: params.c:44
#define PARAM_FLAG_CONST
Definition: params.h:88
#define lfirst(lc)
Definition: pg_list.h:172
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 5847 of file pl_exec.c.

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

3684{
3685 ReturnSetInfo *rsi = estate->rsi;
3686 MemoryContext oldcxt;
3687 ResourceOwner oldowner;
3688
3689 /*
3690 * Check caller can handle a set result in the way we want
3691 */
3692 if (!rsi || !IsA(rsi, ReturnSetInfo))
3693 ereport(ERROR,
3694 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3695 errmsg("set-valued function called in context that cannot accept a set")));
3696
3697 if (!(rsi->allowedModes & SFRM_Materialize) ||
3698 rsi->expectedDesc == NULL)
3699 ereport(ERROR,
3700 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3701 errmsg("materialize mode required, but it is not allowed in this context")));
3702
3703 /*
3704 * Switch to the right memory context and resource owner for storing the
3705 * tuplestore for return set. If we're within a subtransaction opened for
3706 * an exception-block, for example, we must still create the tuplestore in
3707 * the resource owner that was active when this function was entered, and
3708 * not in the subtransaction resource owner.
3709 */
3710 oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
3711 oldowner = CurrentResourceOwner;
3713
3714 estate->tuple_store =
3716 false, work_mem);
3717
3718 CurrentResourceOwner = oldowner;
3719 MemoryContextSwitchTo(oldcxt);
3720
3721 estate->tuple_store_desc = rsi->expectedDesc;
3722}
@ SFRM_Materialize_Random
Definition: execnodes.h:337
@ SFRM_Materialize
Definition: execnodes.h:336
int work_mem
Definition: globals.c:130
Tuplestorestate * tuple_store
Definition: plpgsql.h:1069
MemoryContext tuple_store_cxt
Definition: plpgsql.h:1071
TupleDesc tuple_store_desc
Definition: plpgsql.h:1070
ReturnSetInfo * rsi
Definition: plpgsql.h:1073
ResourceOwner tuple_store_owner
Definition: plpgsql.h:1072
TupleDesc expectedDesc
Definition: execnodes.h:352
int allowedModes
Definition: execnodes.h:353
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 8215 of file pl_exec.c.

8216{
8217 List *plansources;
8218 CachedPlanSource *plansource;
8219 Query *query;
8220
8221 /*
8222 * We can only test queries that resulted in exactly one CachedPlanSource.
8223 */
8224 plansources = SPI_plan_get_plan_sources(expr->plan);
8225 if (list_length(plansources) != 1)
8226 return false;
8227 plansource = (CachedPlanSource *) linitial(plansources);
8228
8229 /*
8230 * 1. There must be one single querytree.
8231 */
8232 if (list_length(plansource->query_list) != 1)
8233 return false;
8234 query = (Query *) linitial(plansource->query_list);
8235
8236 /*
8237 * 2. It must be a plain SELECT query without any input tables.
8238 */
8239 if (!IsA(query, Query))
8240 return false;
8241 if (query->commandType != CMD_SELECT)
8242 return false;
8243 if (query->rtable != NIL)
8244 return false;
8245
8246 /*
8247 * 3. Can't have any subplans, aggregates, qual clauses either. (These
8248 * tests should generally match what inline_function() checks before
8249 * inlining a SQL function; otherwise, inlining could change our
8250 * conclusion about whether an expression is simple, which we don't want.)
8251 */
8252 if (query->hasAggs ||
8253 query->hasWindowFuncs ||
8254 query->hasTargetSRFs ||
8255 query->hasSubLinks ||
8256 query->cteList ||
8257 query->jointree->fromlist ||
8258 query->jointree->quals ||
8259 query->groupClause ||
8260 query->groupingSets ||
8261 query->havingQual ||
8262 query->windowClause ||
8263 query->distinctClause ||
8264 query->sortClause ||
8265 query->limitOffset ||
8266 query->limitCount ||
8267 query->setOperations)
8268 return false;
8269
8270 /*
8271 * 4. The query must have a single attribute as result.
8272 */
8273 if (list_length(query->targetList) != 1)
8274 return false;
8275
8276 /*
8277 * OK, we can treat it as a simple plan.
8278 */
8279 return true;
8280}
@ CMD_SELECT
Definition: nodes.h:271
#define linitial(l)
Definition: pg_list.h:178
List * SPI_plan_get_plan_sources(SPIPlanPtr plan)
Definition: spi.c:2059
List * query_list
Definition: plancache.h:108
Node * quals
Definition: primnodes.h:2338
List * fromlist
Definition: primnodes.h:2337
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 6913 of file pl_exec.c.

6916{
6917 ExpandedRecordHeader *newerh = NULL;
6918
6919 /*
6920 * If target is RECORD, we may be able to avoid field-by-field processing.
6921 */
6922 if (target->dtype == PLPGSQL_DTYPE_REC)
6923 {
6924 PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
6925
6926 /*
6927 * If we have no source tupdesc, just set the record variable to NULL.
6928 * (If we have a source tupdesc but not a tuple, we'll set the
6929 * variable to a row of nulls, instead. This is odd perhaps, but
6930 * backwards compatible.)
6931 */
6932 if (tupdesc == NULL)
6933 {
6934 if (rec->datatype &&
6935 rec->datatype->typtype == TYPTYPE_DOMAIN)
6936 {
6937 /*
6938 * If it's a composite domain, NULL might not be a legal
6939 * value, so we instead need to make an empty expanded record
6940 * and ensure that domain type checking gets done. If there
6941 * is already an expanded record, piggyback on its lookups.
6942 */
6943 newerh = make_expanded_record_for_rec(estate, rec,
6944 NULL, rec->erh);
6945 expanded_record_set_tuple(newerh, NULL, false, false);
6946 assign_record_var(estate, rec, newerh);
6947 }
6948 else
6949 {
6950 /* Just clear it to NULL */
6951 if (rec->erh)
6953 rec->erh = NULL;
6954 }
6955 return;
6956 }
6957
6958 /*
6959 * Build a new expanded record with appropriate tupdesc.
6960 */
6961 newerh = make_expanded_record_for_rec(estate, rec, tupdesc, NULL);
6962
6963 /*
6964 * If the rowtypes match, or if we have no tuple anyway, we can
6965 * complete the assignment without field-by-field processing.
6966 *
6967 * The tests here are ordered more or less in order of cheapness. We
6968 * can easily detect it will work if the target is declared RECORD or
6969 * has the same typeid as the source. But when assigning from a query
6970 * result, it's common to have a source tupdesc that's labeled RECORD
6971 * but is actually physically compatible with a named-composite-type
6972 * target, so it's worth spending extra cycles to check for that.
6973 */
6974 if (rec->rectypeid == RECORDOID ||
6975 rec->rectypeid == tupdesc->tdtypeid ||
6976 !HeapTupleIsValid(tup) ||
6978 {
6979 if (!HeapTupleIsValid(tup))
6980 {
6981 /* No data, so force the record into all-nulls state */
6983 }
6984 else
6985 {
6986 /* No coercion is needed, so just assign the row value */
6987 expanded_record_set_tuple(newerh, tup, true, !estate->atomic);
6988 }
6989
6990 /* Complete the assignment */
6991 assign_record_var(estate, rec, newerh);
6992
6993 return;
6994 }
6995 }
6996
6997 /*
6998 * Otherwise, deconstruct the tuple and do field-by-field assignment,
6999 * using exec_move_row_from_fields.
7000 */
7001 if (tupdesc && HeapTupleIsValid(tup))
7002 {
7003 int td_natts = tupdesc->natts;
7004 Datum *values;
7005 bool *nulls;
7006 Datum values_local[64];
7007 bool nulls_local[64];
7008
7009 /*
7010 * Need workspace arrays. If td_natts is small enough, use local
7011 * arrays to save doing a palloc. Even if it's not small, we can
7012 * allocate both the Datum and isnull arrays in one palloc chunk.
7013 */
7014 if (td_natts <= lengthof(values_local))
7015 {
7016 values = values_local;
7017 nulls = nulls_local;
7018 }
7019 else
7020 {
7021 char *chunk;
7022
7023 chunk = eval_mcontext_alloc(estate,
7024 td_natts * (sizeof(Datum) + sizeof(bool)));
7025 values = (Datum *) chunk;
7026 nulls = (bool *) (chunk + td_natts * sizeof(Datum));
7027 }
7028
7029 heap_deform_tuple(tup, tupdesc, values, nulls);
7030
7031 exec_move_row_from_fields(estate, target, newerh,
7032 values, nulls, tupdesc);
7033 }
7034 else
7035 {
7036 /*
7037 * Assign all-nulls.
7038 */
7039 exec_move_row_from_fields(estate, target, newerh,
7040 NULL, NULL, NULL);
7041 }
7042}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define lengthof(array)
Definition: c.h:759
void deconstruct_expanded_record(ExpandedRecordHeader *erh)
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:129
static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
Definition: pl_exec.c:8856
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:7191
static ExpandedRecordHeader * make_expanded_record_for_rec(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, TupleDesc srctupdesc, ExpandedRecordHeader *srcerh)
Definition: pl_exec.c:7128
PLpgSQL_type * datatype
Definition: plpgsql.h:428
char typtype
Definition: plpgsql.h:216

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

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

◆ exec_move_row_from_datum()

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

Definition at line 7587 of file pl_exec.c.

7590{
7591 /* Check to see if source is an expanded record */
7593 {
7595 ExpandedRecordHeader *newerh = NULL;
7596
7597 Assert(erh->er_magic == ER_MAGIC);
7598
7599 /* These cases apply if the target is record not row... */
7600 if (target->dtype == PLPGSQL_DTYPE_REC)
7601 {
7602 PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7603
7604 /*
7605 * If it's the same record already stored in the variable, do
7606 * nothing. This would happen only in silly cases like "r := r",
7607 * but we need some check to avoid possibly freeing the variable's
7608 * live value below. Note that this applies even if what we have
7609 * is a R/O pointer.
7610 */
7611 if (erh == rec->erh)
7612 return;
7613
7614 /*
7615 * Make sure rec->rectypeid is up-to-date before using it.
7616 */
7618
7619 /*
7620 * If we have a R/W pointer, we're allowed to just commandeer
7621 * ownership of the expanded record. If it's of the right type to
7622 * put into the record variable, do that. (Note we don't accept
7623 * an expanded record of a composite-domain type as a RECORD
7624 * value. We'll treat it as the base composite type instead;
7625 * compare logic in make_expanded_record_for_rec.)
7626 */
7628 (rec->rectypeid == erh->er_decltypeid ||
7629 (rec->rectypeid == RECORDOID &&
7630 !ExpandedRecordIsDomain(erh))))
7631 {
7632 assign_record_var(estate, rec, erh);
7633 return;
7634 }
7635
7636 /*
7637 * If we already have an expanded record object in the target
7638 * variable, and the source record contains a valid tuple
7639 * representation with the right rowtype, then we can skip making
7640 * a new expanded record and just assign the tuple with
7641 * expanded_record_set_tuple. (We can't do the equivalent if we
7642 * have to do field-by-field assignment, since that wouldn't be
7643 * atomic if there's an error.) We consider that there's a
7644 * rowtype match only if it's the same named composite type or
7645 * same registered rowtype; checking for matches of anonymous
7646 * rowtypes would be more expensive than this is worth.
7647 */
7648 if (rec->erh &&
7649 (erh->flags & ER_FLAG_FVALUE_VALID) &&
7650 erh->er_typeid == rec->erh->er_typeid &&
7651 (erh->er_typeid != RECORDOID ||
7652 (erh->er_typmod == rec->erh->er_typmod &&
7653 erh->er_typmod >= 0)))
7654 {
7656 true, !estate->atomic);
7657 return;
7658 }
7659
7660 /*
7661 * Otherwise we're gonna need a new expanded record object. Make
7662 * it here in hopes of piggybacking on the source object's
7663 * previous typcache lookup.
7664 */
7665 newerh = make_expanded_record_for_rec(estate, rec, NULL, erh);
7666
7667 /*
7668 * If the expanded record contains a valid tuple representation,
7669 * and we don't need rowtype conversion, then just copying the
7670 * tuple is probably faster than field-by-field processing. (This
7671 * isn't duplicative of the previous check, since here we will
7672 * catch the case where the record variable was previously empty.)
7673 */
7674 if ((erh->flags & ER_FLAG_FVALUE_VALID) &&
7675 (rec->rectypeid == RECORDOID ||
7676 rec->rectypeid == erh->er_typeid))
7677 {
7678 expanded_record_set_tuple(newerh, erh->fvalue,
7679 true, !estate->atomic);
7680 assign_record_var(estate, rec, newerh);
7681 return;
7682 }
7683
7684 /*
7685 * Need to special-case empty source record, else code below would
7686 * leak newerh.
7687 */
7688 if (ExpandedRecordIsEmpty(erh))
7689 {
7690 /* Set newerh to a row of NULLs */
7692 assign_record_var(estate, rec, newerh);
7693 return;
7694 }
7695 } /* end of record-target-only cases */
7696
7697 /*
7698 * If the source expanded record is empty, we should treat that like a
7699 * NULL tuple value. (We're unlikely to see such a case, but we must
7700 * check this; deconstruct_expanded_record would cause a change of
7701 * logical state, which is not OK.)
7702 */
7703 if (ExpandedRecordIsEmpty(erh))
7704 {
7705 exec_move_row(estate, target, NULL,
7707 return;
7708 }
7709
7710 /*
7711 * Otherwise, ensure that the source record is deconstructed, and
7712 * assign from its field values.
7713 */
7715 exec_move_row_from_fields(estate, target, newerh,
7716 erh->dvalues, erh->dnulls,
7718 }
7719 else
7720 {
7721 /*
7722 * Nope, we've got a plain composite Datum. Deconstruct it; but we
7723 * don't use deconstruct_composite_datum(), because we may be able to
7724 * skip calling lookup_rowtype_tupdesc().
7725 */
7726 HeapTupleHeader td;
7727 HeapTupleData tmptup;
7728 Oid tupType;
7729 int32 tupTypmod;
7730 TupleDesc tupdesc;
7731 MemoryContext oldcontext;
7732
7733 /* Ensure that any detoasted data winds up in the eval_mcontext */
7734 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7735 /* Get tuple body (note this could involve detoasting) */
7737 MemoryContextSwitchTo(oldcontext);
7738
7739 /* Build a temporary HeapTuple control structure */
7741 ItemPointerSetInvalid(&(tmptup.t_self));
7742 tmptup.t_tableOid = InvalidOid;
7743 tmptup.t_data = td;
7744
7745 /* Extract rowtype info */
7746 tupType = HeapTupleHeaderGetTypeId(td);
7747 tupTypmod = HeapTupleHeaderGetTypMod(td);
7748
7749 /* Now, if the target is record not row, maybe we can optimize ... */
7750 if (target->dtype == PLPGSQL_DTYPE_REC)
7751 {
7752 PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7753
7754 /*
7755 * If we already have an expanded record object in the target
7756 * variable, and the source datum has a matching rowtype, then we
7757 * can skip making a new expanded record and just assign the tuple
7758 * with expanded_record_set_tuple. We consider that there's a
7759 * rowtype match only if it's the same named composite type or
7760 * same registered rowtype. (Checking to reject an anonymous
7761 * rowtype here should be redundant, but let's be safe.)
7762 */
7763 if (rec->erh &&
7764 tupType == rec->erh->er_typeid &&
7765 (tupType != RECORDOID ||
7766 (tupTypmod == rec->erh->er_typmod &&
7767 tupTypmod >= 0)))
7768 {
7769 expanded_record_set_tuple(rec->erh, &tmptup,
7770 true, !estate->atomic);
7771 return;
7772 }
7773
7774 /*
7775 * If the source datum has a rowtype compatible with the target
7776 * variable, just build a new expanded record and assign the tuple
7777 * into it. Using make_expanded_record_from_typeid() here saves
7778 * one typcache lookup compared to the code below.
7779 */
7780 if (rec->rectypeid == RECORDOID || rec->rectypeid == tupType)
7781 {
7782 ExpandedRecordHeader *newerh;
7783 MemoryContext mcontext = get_eval_mcontext(estate);
7784
7785 newerh = make_expanded_record_from_typeid(tupType, tupTypmod,
7786 mcontext);
7787 expanded_record_set_tuple(newerh, &tmptup,
7788 true, !estate->atomic);
7789 assign_record_var(estate, rec, newerh);
7790 return;
7791 }
7792
7793 /*
7794 * Otherwise, we're going to need conversion, so fall through to
7795 * do it the hard way.
7796 */
7797 }
7798
7799 /*
7800 * ROW target, or unoptimizable RECORD target, so we have to expend a
7801 * lookup to obtain the source datum's tupdesc.
7802 */
7803 tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
7804
7805 /* Do the move */
7806 exec_move_row(estate, target, &tmptup, tupdesc);
7807
7808 /* Release tupdesc usage count */
7809 ReleaseTupleDesc(tupdesc);
7810 }
7811}
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:7048

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

7196{
7197 int td_natts = tupdesc ? tupdesc->natts : 0;
7198 int fnum;
7199 int anum;
7200 int strict_multiassignment_level = 0;
7201
7202 /*
7203 * The extra check strict strict_multi_assignment can be active, only when
7204 * input tupdesc is specified.
7205 */
7206 if (tupdesc != NULL)
7207 {
7209 strict_multiassignment_level = ERROR;
7211 strict_multiassignment_level = WARNING;
7212 }
7213
7214 /* Handle RECORD-target case */
7215 if (target->dtype == PLPGSQL_DTYPE_REC)
7216 {
7217 PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7218 TupleDesc var_tupdesc;
7219 Datum newvalues_local[64];
7220 bool newnulls_local[64];
7221
7222 Assert(newerh != NULL); /* caller must have built new object */
7223
7224 var_tupdesc = expanded_record_get_tupdesc(newerh);
7225
7226 /*
7227 * Coerce field values if needed. This might involve dealing with
7228 * different sets of dropped columns and/or coercing individual column
7229 * types. That's sort of a pain, but historically plpgsql has allowed
7230 * it, so we preserve the behavior. However, it's worth a quick check
7231 * to see if the tupdescs are identical. (Since expandedrecord.c
7232 * prefers to use refcounted tupdescs from the typcache, expanded
7233 * records with the same rowtype will have pointer-equal tupdescs.)
7234 */
7235 if (var_tupdesc != tupdesc)
7236 {
7237 int vtd_natts = var_tupdesc->natts;
7238 Datum *newvalues;
7239 bool *newnulls;
7240
7241 /*
7242 * Need workspace arrays. If vtd_natts is small enough, use local
7243 * arrays to save doing a palloc. Even if it's not small, we can
7244 * allocate both the Datum and isnull arrays in one palloc chunk.
7245 */
7246 if (vtd_natts <= lengthof(newvalues_local))
7247 {
7248 newvalues = newvalues_local;
7249 newnulls = newnulls_local;
7250 }
7251 else
7252 {
7253 char *chunk;
7254
7255 chunk = eval_mcontext_alloc(estate,
7256 vtd_natts * (sizeof(Datum) + sizeof(bool)));
7257 newvalues = (Datum *) chunk;
7258 newnulls = (bool *) (chunk + vtd_natts * sizeof(Datum));
7259 }
7260
7261 /* Walk over destination columns */
7262 anum = 0;
7263 for (fnum = 0; fnum < vtd_natts; fnum++)
7264 {
7265 Form_pg_attribute attr = TupleDescAttr(var_tupdesc, fnum);
7266 Datum value;
7267 bool isnull;
7268 Oid valtype;
7269 int32 valtypmod;
7270
7271 if (attr->attisdropped)
7272 {
7273 /* expanded_record_set_fields should ignore this column */
7274 continue; /* skip dropped column in record */
7275 }
7276
7277 while (anum < td_natts &&
7278 TupleDescAttr(tupdesc, anum)->attisdropped)
7279 anum++; /* skip dropped column in tuple */
7280
7281 if (anum < td_natts)
7282 {
7283 value = values[anum];
7284 isnull = nulls[anum];
7285 valtype = TupleDescAttr(tupdesc, anum)->atttypid;
7286 valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
7287 anum++;
7288 }
7289 else
7290 {
7291 /* no source for destination column */
7292 value = (Datum) 0;
7293 isnull = true;
7294 valtype = UNKNOWNOID;
7295 valtypmod = -1;
7296
7297 /* When source value is missing */
7298 if (strict_multiassignment_level)
7299 ereport(strict_multiassignment_level,
7300 (errcode(ERRCODE_DATATYPE_MISMATCH),
7301 errmsg("number of source and target fields in assignment does not match"),
7302 /* translator: %s represents a name of an extra check */
7303 errdetail("%s check of %s is active.",
7304 "strict_multi_assignment",
7305 strict_multiassignment_level == ERROR ? "extra_errors" :
7306 "extra_warnings"),
7307 errhint("Make sure the query returns the exact list of columns.")));
7308 }
7309
7310 /* Cast the new value to the right type, if needed. */
7311 newvalues[fnum] = exec_cast_value(estate,
7312 value,
7313 &isnull,
7314 valtype,
7315 valtypmod,
7316 attr->atttypid,
7317 attr->atttypmod);
7318 newnulls[fnum] = isnull;
7319 }
7320
7321 /*
7322 * When strict_multiassignment extra check is active, then ensure
7323 * there are no unassigned source attributes.
7324 */
7325 if (strict_multiassignment_level && anum < td_natts)
7326 {
7327 /* skip dropped columns in the source descriptor */
7328 while (anum < td_natts &&
7329 TupleDescAttr(tupdesc, anum)->attisdropped)
7330 anum++;
7331
7332 if (anum < td_natts)
7333 ereport(strict_multiassignment_level,
7334 (errcode(ERRCODE_DATATYPE_MISMATCH),
7335 errmsg("number of source and target fields in assignment does not match"),
7336 /* translator: %s represents a name of an extra check */
7337 errdetail("%s check of %s is active.",
7338 "strict_multi_assignment",
7339 strict_multiassignment_level == ERROR ? "extra_errors" :
7340 "extra_warnings"),
7341 errhint("Make sure the query returns the exact list of columns.")));
7342 }
7343
7344 values = newvalues;
7345 nulls = newnulls;
7346 }
7347
7348 /* Insert the coerced field values into the new expanded record */
7349 expanded_record_set_fields(newerh, values, nulls, !estate->atomic);
7350
7351 /* Complete the assignment */
7352 assign_record_var(estate, rec, newerh);
7353
7354 return;
7355 }
7356
7357 /* newerh should not have been passed in non-RECORD cases */
7358 Assert(newerh == NULL);
7359
7360 /*
7361 * For a row, we assign the individual field values to the variables the
7362 * row points to.
7363 *
7364 * NOTE: both this code and the record code above silently ignore extra
7365 * columns in the source and assume NULL for missing columns. This is
7366 * pretty dubious but it's the historical behavior.
7367 *
7368 * If we have no input data at all, we'll assign NULL to all columns of
7369 * the row variable.
7370 */
7371 if (target->dtype == PLPGSQL_DTYPE_ROW)
7372 {
7373 PLpgSQL_row *row = (PLpgSQL_row *) target;
7374
7375 anum = 0;
7376 for (fnum = 0; fnum < row->nfields; fnum++)
7377 {
7378 PLpgSQL_var *var;
7379 Datum value;
7380 bool isnull;
7381 Oid valtype;
7382 int32 valtypmod;
7383
7384 var = (PLpgSQL_var *) (estate->datums[row->varnos[fnum]]);
7385
7386 while (anum < td_natts &&
7387 TupleDescAttr(tupdesc, anum)->attisdropped)
7388 anum++; /* skip dropped column in tuple */
7389
7390 if (anum < td_natts)
7391 {
7392 value = values[anum];
7393 isnull = nulls[anum];
7394 valtype = TupleDescAttr(tupdesc, anum)->atttypid;
7395 valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
7396 anum++;
7397 }
7398 else
7399 {
7400 /* no source for destination column */
7401 value = (Datum) 0;
7402 isnull = true;
7403 valtype = UNKNOWNOID;
7404 valtypmod = -1;
7405
7406 if (strict_multiassignment_level)
7407 ereport(strict_multiassignment_level,
7408 (errcode(ERRCODE_DATATYPE_MISMATCH),
7409 errmsg("number of source and target fields in assignment does not match"),
7410 /* translator: %s represents a name of an extra check */
7411 errdetail("%s check of %s is active.",
7412 "strict_multi_assignment",
7413 strict_multiassignment_level == ERROR ? "extra_errors" :
7414 "extra_warnings"),
7415 errhint("Make sure the query returns the exact list of columns.")));
7416 }
7417
7418 exec_assign_value(estate, (PLpgSQL_datum *) var,
7419 value, isnull, valtype, valtypmod);
7420 }
7421
7422 /*
7423 * When strict_multiassignment extra check is active, ensure there are
7424 * no unassigned source attributes.
7425 */
7426 if (strict_multiassignment_level && anum < td_natts)
7427 {
7428 while (anum < td_natts &&
7429 TupleDescAttr(tupdesc, anum)->attisdropped)
7430 anum++; /* skip dropped column in tuple */
7431
7432 if (anum < td_natts)
7433 ereport(strict_multiassignment_level,
7434 (errcode(ERRCODE_DATATYPE_MISMATCH),
7435 errmsg("number of source and target fields in assignment does not match"),
7436 /* translator: %s represents a name of an extra check */
7437 errdetail("%s check of %s is active.",
7438 "strict_multi_assignment",
7439 strict_multiassignment_level == ERROR ? "extra_errors" :
7440 "extra_warnings"),
7441 errhint("Make sure the query returns the exact list of columns.")));
7442 }
7443
7444 return;
7445 }
7446
7447 elog(ERROR, "unsupported target type: %d", target->dtype);
7448}
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:1232
int * varnos
Definition: plpgsql.h:405
int nfields
Definition: plpgsql.h:403

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

Referenced by exec_move_row(), and exec_move_row_from_datum().

◆ exec_prepare_plan()

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

Definition at line 4187 of file pl_exec.c.

4189{
4192
4193 /*
4194 * Generate and save the plan
4195 */
4196 memset(&options, 0, sizeof(options));
4198 options.parserSetupArg = expr;
4199 options.parseMode = expr->parseMode;
4200 options.cursorOptions = cursorOptions;
4202 if (plan == NULL)
4203 elog(ERROR, "SPI_prepare_extended failed for \"%s\": %s",
4205
4207 expr->plan = plan;
4208
4209 /* Check to see if it's a simple expression */
4210 exec_simple_check_plan(estate, expr);
4211}
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:1097
static void exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:8143
SPIPlanPtr SPI_prepare_extended(const char *src, const SPIPrepareOptions *options)
Definition: spi.c:903
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:977
RawParseMode parseMode
Definition: plpgsql.h:232

References elog, ERROR, exec_simple_check_plan(), 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 5763 of file pl_exec.c.

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

8287{
8289 Plan *plan;
8290 Expr *tle_expr;
8291
8292 /*
8293 * Given the checks that exec_simple_check_plan did, none of the Asserts
8294 * here should ever fail.
8295 */
8296
8297 /* Extract the single PlannedStmt */
8298 Assert(list_length(cplan->stmt_list) == 1);
8300 Assert(stmt->commandType == CMD_SELECT);
8301
8302 /*
8303 * Ordinarily, the plan node should be a simple Result. However, if
8304 * debug_parallel_query is on, the planner might've stuck a Gather node
8305 * atop that; and/or if this plan is for a scrollable cursor, the planner
8306 * might've stuck a Material node atop it. The simplest way to deal with
8307 * this is to look through the Gather and/or Material nodes. The upper
8308 * node's tlist would normally contain a Var referencing the child node's
8309 * output ... but setrefs.c might also have copied a Const as-is.
8310 */
8311 plan = stmt->planTree;
8312 for (;;)
8313 {
8314 /* Extract the single tlist expression */
8315 Assert(list_length(plan->targetlist) == 1);
8316 tle_expr = linitial_node(TargetEntry, plan->targetlist)->expr;
8317
8318 if (IsA(plan, Result))
8319 {
8320 Assert(plan->lefttree == NULL &&
8321 plan->righttree == NULL &&
8322 plan->initPlan == NULL &&
8323 plan->qual == NULL &&
8324 ((Result *) plan)->resconstantqual == NULL);
8325 break;
8326 }
8327 else if (IsA(plan, Gather) || IsA(plan, Material))
8328 {
8329 Assert(plan->lefttree != NULL &&
8330 plan->righttree == NULL &&
8331 plan->initPlan == NULL &&
8332 plan->qual == NULL);
8333 /* If setrefs.c copied up a Const, no need to look further */
8334 if (IsA(tle_expr, Const))
8335 break;
8336 /* Otherwise, it better be an outer Var */
8337 Assert(IsA(tle_expr, Var));
8338 Assert(((Var *) tle_expr)->varno == OUTER_VAR);
8339 /* Descend to the child node */
8340 plan = plan->lefttree;
8341 }
8342 else
8343 elog(ERROR, "unexpected plan node type: %d",
8344 (int) nodeTag(plan));
8345 }
8346
8347 /*
8348 * Save the simple expression, and initialize state to "not valid in
8349 * current transaction".
8350 */
8351 expr->expr_simple_expr = tle_expr;
8352 expr->expr_simple_state = NULL;
8353 expr->expr_simple_in_use = false;
8355 /* Also stash away the expression result type */
8356 expr->expr_simple_type = exprType((Node *) tle_expr);
8357 expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
8358 /* We also want to remember if it is immutable or not */
8360}
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:139
#define linitial_node(type, l)
Definition: pg_list.h:181
#define OUTER_VAR
Definition: primnodes.h:243
List * stmt_list
Definition: plancache.h:148
Definition: primnodes.h:262

References Assert(), CMD_SELECT, contain_mutable_functions(), elog, ERROR, 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 8143 of file pl_exec.c.

8144{
8145 List *plansources;
8146 CachedPlanSource *plansource;
8147 CachedPlan *cplan;
8148 MemoryContext oldcontext;
8149
8150 /*
8151 * Initialize to "not simple", and reset R/W optimizability.
8152 */
8153 expr->expr_simple_expr = NULL;
8155 expr->expr_rw_param = NULL;
8156
8157 /*
8158 * Check the analyzed-and-rewritten form of the query to see if we will be
8159 * able to treat it as a simple expression. Since this function is only
8160 * called immediately after creating the CachedPlanSource, we need not
8161 * worry about the query being stale.
8162 */
8163 if (!exec_is_simple_query(expr))
8164 return;
8165
8166 /* exec_is_simple_query verified that there's just one CachedPlanSource */
8167 plansources = SPI_plan_get_plan_sources(expr->plan);
8168 plansource = (CachedPlanSource *) linitial(plansources);
8169
8170 /*
8171 * Get the generic plan for the query. If replanning is needed, do that
8172 * work in the eval_mcontext. (Note that replanning could throw an error,
8173 * in which case the expr is left marked "not simple", which is fine.)
8174 */
8175 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
8176 cplan = SPI_plan_get_cached_plan(expr->plan);
8177 MemoryContextSwitchTo(oldcontext);
8178
8179 /* Can't fail, because we checked for a single CachedPlanSource above */
8180 Assert(cplan != NULL);
8181
8182 /*
8183 * Verify that plancache.c thinks the plan is simple enough to use
8184 * CachedPlanIsSimplyValid. Given the restrictions above, it's unlikely
8185 * that this could fail, but if it does, just treat plan as not simple. On
8186 * success, save a refcount on the plan in the simple-expression resowner.
8187 */
8188 if (CachedPlanAllowsSimpleValidityCheck(plansource, cplan,
8189 estate->simple_eval_resowner))
8190 {
8191 /* Remember that we have the refcount */
8192 expr->expr_simple_plansource = plansource;
8193 expr->expr_simple_plan = cplan;
8195
8196 /* Share the remaining work with the replan code path */
8197 exec_save_simple_expr(expr, cplan);
8198 }
8199
8200 /*
8201 * Release the plan refcount obtained by SPI_plan_get_cached_plan. (This
8202 * refcount is held by the wrong resowner, so we can't just repurpose it.)
8203 */
8205}

References Assert(), CachedPlanAllowsSimpleValidityCheck(), CurrentResourceOwner, exec_is_simple_query(), exec_save_simple_expr(), PLpgSQL_expr::expr_rw_param, PLpgSQL_expr::expr_rwopt, 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, PLPGSQL_RWOPT_UNKNOWN, 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 3950 of file pl_exec.c.

3951{
3952 bool value;
3953 bool isnull;
3954
3955 /* do nothing when asserts are not enabled */
3957 return PLPGSQL_RC_OK;
3958
3959 value = exec_eval_boolean(estate, stmt->cond, &isnull);
3960 exec_eval_cleanup(estate);
3961
3962 if (isnull || !value)
3963 {
3964 char *message = NULL;
3965
3966 if (stmt->message != NULL)
3967 {
3968 Datum val;
3969 Oid typeid;
3970 int32 typmod;
3971
3972 val = exec_eval_expr(estate, stmt->message,
3973 &isnull, &typeid, &typmod);
3974 if (!isnull)
3975 message = convert_value_to_string(estate, val, typeid);
3976 /* we mustn't do exec_eval_cleanup here */
3977 }
3978
3979 ereport(ERROR,
3980 (errcode(ERRCODE_ASSERT_FAILURE),
3981 message ? errmsg_internal("%s", message) :
3982 errmsg("assertion failed")));
3983 }
3984
3985 return PLPGSQL_RC_OK;
3986}
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:5656
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 2164 of file pl_exec.c.

2165{
2166 Assert(stmt->varno >= 0);
2167
2168 exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);
2169
2170 return PLPGSQL_RC_OK;
2171}
static void exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
Definition: pl_exec.c:5017

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

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

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

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

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

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

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

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

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

4971{
4972 if (stmt->chain)
4974 else
4975 SPI_commit();
4976
4977 /*
4978 * We need to build new simple-expression infrastructure, since the old
4979 * data structures are gone.
4980 */
4981 estate->simple_eval_estate = NULL;
4982 estate->simple_eval_resowner = NULL;
4984
4985 return PLPGSQL_RC_OK;
4986}
void SPI_commit(void)
Definition: spi.c:321
void SPI_commit_and_chain(void)
Definition: spi.c:327

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

Referenced by exec_stmts().

◆ exec_stmt_dynexecute()

static int exec_stmt_dynexecute ( PLpgSQL_execstate estate,
PLpgSQL_stmt_dynexecute stmt 
)
static

Definition at line 4454 of file pl_exec.c.

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

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

4645{
4646 Portal portal;
4647 int rc;
4648
4649 portal = exec_dynquery_with_params(estate, stmt->query, stmt->params,
4650 NULL, CURSOR_OPT_NO_SCROLL);
4651
4652 /*
4653 * Execute the loop
4654 */
4655 rc = exec_for_query(estate, (PLpgSQL_stmt_forq *) stmt, portal, true);
4656
4657 /*
4658 * Close the implicit cursor
4659 */
4660 SPI_cursor_close(portal);
4661
4662 return rc;
4663}
static int exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt, Portal portal, bool prefetch_ok)
Definition: pl_exec.c:5847
static Portal exec_dynquery_with_params(PLpgSQL_execstate *estate, PLpgSQL_expr *dynquery, List *params, const char *portalname, int cursorOptions)
Definition: pl_exec.c:8961

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

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

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

3165{
3166 /*
3167 * If the exit / continue has a condition, evaluate it
3168 */
3169 if (stmt->cond != NULL)
3170 {
3171 bool value;
3172 bool isnull;
3173
3174 value = exec_eval_boolean(estate, stmt->cond, &isnull);
3175 exec_eval_cleanup(estate);
3176 if (isnull || value == false)
3177 return PLPGSQL_RC_OK;
3178 }
3179
3180 estate->exitlabel = stmt->label;
3181 if (stmt->is_exit)
3182 return PLPGSQL_RC_EXIT;
3183 else
3184 return PLPGSQL_RC_CONTINUE;
3185}

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

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

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

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

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

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

2697{
2698 PLpgSQL_var *var;
2699 Datum value;
2700 bool isnull;
2701 Oid valtype;
2702 int32 valtypmod;
2703 int32 loop_value;
2704 int32 end_value;
2705 int32 step_value;
2706 bool found = false;
2707 int rc = PLPGSQL_RC_OK;
2708
2709 var = (PLpgSQL_var *) (estate->datums[stmt->var->dno]);
2710
2711 /*
2712 * Get the value of the lower bound
2713 */
2714 value = exec_eval_expr(estate, stmt->lower,
2715 &isnull, &valtype, &valtypmod);
2716 value = exec_cast_value(estate, value, &isnull,
2717 valtype, valtypmod,
2718 var->datatype->typoid,
2719 var->datatype->atttypmod);
2720 if (isnull)
2721 ereport(ERROR,
2722 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
2723 errmsg("lower bound of FOR loop cannot be null")));
2724 loop_value = DatumGetInt32(value);
2725 exec_eval_cleanup(estate);
2726
2727 /*
2728 * Get the value of the upper bound
2729 */
2730 value = exec_eval_expr(estate, stmt->upper,
2731 &isnull, &valtype, &valtypmod);
2732 value = exec_cast_value(estate, value, &isnull,
2733 valtype, valtypmod,
2734 var->datatype->typoid,
2735 var->datatype->atttypmod);
2736 if (isnull)
2737 ereport(ERROR,
2738 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
2739 errmsg("upper bound of FOR loop cannot be null")));
2740 end_value = DatumGetInt32(value);
2741 exec_eval_cleanup(estate);
2742
2743 /*
2744 * Get the step value
2745 */
2746 if (stmt->step)
2747 {
2748 value = exec_eval_expr(estate, stmt->step,
2749 &isnull, &valtype, &valtypmod);
2750 value = exec_cast_value(estate, value, &isnull,
2751 valtype, valtypmod,
2752 var->datatype->typoid,
2753 var->datatype->atttypmod);
2754 if (isnull)
2755 ereport(ERROR,
2756 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
2757 errmsg("BY value of FOR loop cannot be null")));
2758 step_value = DatumGetInt32(value);
2759 exec_eval_cleanup(estate);
2760 if (step_value <= 0)
2761 ereport(ERROR,
2762 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2763 errmsg("BY value of FOR loop must be greater than zero")));
2764 }
2765 else
2766 step_value = 1;
2767
2768 /*
2769 * Now do the loop
2770 */
2771 for (;;)
2772 {
2773 /*
2774 * Check against upper bound
2775 */
2776 if (stmt->reverse)
2777 {
2778 if (loop_value < end_value)
2779 break;
2780 }
2781 else
2782 {
2783 if (loop_value > end_value)
2784 break;
2785 }
2786
2787 found = true; /* looped at least once */
2788
2789 /*
2790 * Assign current value to loop var
2791 */
2792 assign_simple_var(estate, var, Int32GetDatum(loop_value), false, false);
2793
2794 /*
2795 * Execute the statements
2796 */
2797 rc = exec_stmts(estate, stmt->body);
2798
2799 LOOP_RC_PROCESSING(stmt->label, break);
2800
2801 /*
2802 * Increase/decrease loop value, unless it would overflow, in which
2803 * case exit the loop.
2804 */
2805 if (stmt->reverse)
2806 {
2807 if (loop_value < (PG_INT32_MIN + step_value))
2808 break;
2809 loop_value -= step_value;
2810 }
2811 else
2812 {
2813 if (loop_value > (PG_INT32_MAX - step_value))
2814 break;
2815 loop_value += step_value;
2816 }
2817 }
2818
2819 /*
2820 * Set the FOUND variable to indicate the result of executing the loop
2821 * (namely, whether we looped one or more times). This must be set here so
2822 * that it does not interfere with the value of the FOUND variable inside
2823 * the loop processing itself.
2824 */
2825 exec_set_found(estate, found);
2826
2827 return rc;
2828}
#define PG_INT32_MAX
Definition: c.h:560
#define PG_INT32_MIN
Definition: c.h:559
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217

References assign_simple_var(), PLpgSQL_type::atttypmod, PLpgSQL_var::datatype, DatumGetInt32(), PLpgSQL_execstate::datums, ereport, errcode(), errmsg(), ERROR, exec_cast_value(), exec_eval_cleanup(), exec_eval_expr(), exec_set_found(), exec_stmts(), Int32GetDatum(), LOOP_RC_PROCESSING, PG_INT32_MAX, PG_INT32_MIN, PLPGSQL_RC_OK, stmt, PLpgSQL_type::typoid, and value.

Referenced by exec_stmts().

◆ exec_stmt_fors()

static int exec_stmt_fors ( PLpgSQL_execstate estate,
PLpgSQL_stmt_fors stmt 
)
static

Definition at line 2839 of file pl_exec.c.

2840{
2841 Portal portal;
2842 int rc;
2843
2844 /*
2845 * Open the implicit cursor for the statement using exec_run_select
2846 */
2847 exec_run_select(estate, stmt->query, 0, &portal);
2848
2849 /*
2850 * Execute the loop
2851 */
2852 rc = exec_for_query(estate, (PLpgSQL_stmt_forq *) stmt, portal, true);
2853
2854 /*
2855 * Close the implicit cursor
2856 */
2857 SPI_cursor_close(portal);
2858
2859 return rc;
2860}

References exec_for_query(), exec_run_select(), SPI_cursor_close(), and stmt.

Referenced by exec_stmts().

◆ exec_stmt_getdiag()

static int exec_stmt_getdiag ( PLpgSQL_execstate estate,
PLpgSQL_stmt_getdiag stmt 
)
static

Definition at line 2410 of file pl_exec.c.

2411{
2412 ListCell *lc;
2413
2414 /*
2415 * GET STACKED DIAGNOSTICS is only valid inside an exception handler.
2416 *
2417 * Note: we trust the grammar to have disallowed the relevant item kinds
2418 * if not is_stacked, otherwise we'd dump core below.
2419 */
2420 if (stmt->is_stacked && estate->cur_error == NULL)
2421 ereport(ERROR,
2422 (errcode(ERRCODE_STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER),
2423 errmsg("GET STACKED DIAGNOSTICS cannot be used outside an exception handler")));
2424
2425 foreach(lc, stmt->diag_items)
2426 {
2427 PLpgSQL_diag_item *diag_item = (PLpgSQL_diag_item *) lfirst(lc);
2428 PLpgSQL_datum *var = estate->datums[diag_item->target];
2429
2430 switch (diag_item->kind)
2431 {
2433 exec_assign_value(estate, var,
2435 false, INT8OID, -1);
2436 break;
2437
2439 exec_assign_value(estate, var,
2440 ObjectIdGetDatum(estate->func->fn_oid),
2441 false, OIDOID, -1);
2442 break;
2443
2445 exec_assign_c_string(estate, var,
2446 estate->cur_error->context);
2447 break;
2448
2450 exec_assign_c_string(estate, var,
2451 estate->cur_error->detail);
2452 break;
2453
2455 exec_assign_c_string(estate, var,
2456 estate->cur_error->hint);
2457 break;
2458
2460 exec_assign_c_string(estate, var,
2462 break;
2463
2465 exec_assign_c_string(estate, var,
2466 estate->cur_error->column_name);
2467 break;
2468
2470 exec_assign_c_string(estate, var,
2471 estate->cur_error->constraint_name);
2472 break;
2473
2475 exec_assign_c_string(estate, var,
2476 estate->cur_error->datatype_name);
2477 break;
2478
2480 exec_assign_c_string(estate, var,
2481 estate->cur_error->message);
2482 break;
2483
2485 exec_assign_c_string(estate, var,
2486 estate->cur_error->table_name);
2487 break;
2488
2490 exec_assign_c_string(estate, var,
2491 estate->cur_error->schema_name);
2492 break;
2493
2495 {
2496 char *contextstackstr;
2497 MemoryContext oldcontext;
2498
2499 /* Use eval_mcontext for short-lived string */
2500 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
2501 contextstackstr = GetErrorContextStack();
2502 MemoryContextSwitchTo(oldcontext);
2503
2504 exec_assign_c_string(estate, var, contextstackstr);
2505 }
2506 break;
2507
2508 default:
2509 elog(ERROR, "unrecognized diagnostic item kind: %d",
2510 diag_item->kind);
2511 }
2512 }
2513
2514 exec_eval_cleanup(estate);
2515
2516 return PLPGSQL_RC_OK;
2517}
char * GetErrorContextStack(void)
Definition: elog.c:2059
static void exec_assign_c_string(PLpgSQL_execstate *estate, PLpgSQL_datum *target, const char *str)
Definition: pl_exec.c:5047
@ PLPGSQL_GETDIAG_ERROR_DETAIL
Definition: plpgsql.h:153
@ PLPGSQL_GETDIAG_SCHEMA_NAME
Definition: plpgsql.h:161
@ PLPGSQL_GETDIAG_MESSAGE_TEXT
Definition: plpgsql.h:159
@ PLPGSQL_GETDIAG_DATATYPE_NAME
Definition: plpgsql.h:158
@ PLPGSQL_GETDIAG_TABLE_NAME
Definition: plpgsql.h:160
@ PLPGSQL_GETDIAG_CONSTRAINT_NAME
Definition: plpgsql.h:157
@ PLPGSQL_GETDIAG_COLUMN_NAME
Definition: plpgsql.h:156
@ PLPGSQL_GETDIAG_ROW_COUNT
Definition: plpgsql.h:149
@ PLPGSQL_GETDIAG_RETURNED_SQLSTATE
Definition: plpgsql.h:155
@ PLPGSQL_GETDIAG_CONTEXT
Definition: plpgsql.h:151
@ PLPGSQL_GETDIAG_ERROR_HINT
Definition: plpgsql.h:154
@ PLPGSQL_GETDIAG_ERROR_CONTEXT
Definition: plpgsql.h:152
@ PLPGSQL_GETDIAG_ROUTINE_OID
Definition: plpgsql.h:150
static Datum UInt64GetDatum(uint64 X)
Definition: postgres.h:441
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
char * schema_name
Definition: elog.h:438
char * context
Definition: elog.h:435
char * datatype_name
Definition: elog.h:441
char * detail
Definition: elog.h:432
char * table_name
Definition: elog.h:439
char * hint
Definition: elog.h:434
char * constraint_name
Definition: elog.h:442
char * column_name
Definition: elog.h:440
PLpgSQL_getdiag_kind kind
Definition: plpgsql.h:599

References ErrorData::column_name, ErrorData::constraint_name, ErrorData::context, PLpgSQL_execstate::cur_error, ErrorData::datatype_name, PLpgSQL_execstate::datums, ErrorData::detail, elog, ereport, errcode(), errmsg(), ERROR, PLpgSQL_execstate::eval_processed, exec_assign_c_string(), exec_assign_value(), exec_eval_cleanup(), PLpgSQL_function::fn_oid, PLpgSQL_execstate::func, get_eval_mcontext, GetErrorContextStack(), ErrorData::hint, PLpgSQL_diag_item::kind, lfirst, MemoryContextSwitchTo(), ErrorData::message, ObjectIdGetDatum(), PLPGSQL_GETDIAG_COLUMN_NAME, PLPGSQL_GETDIAG_CONSTRAINT_NAME, PLPGSQL_GETDIAG_CONTEXT, PLPGSQL_GETDIAG_DATATYPE_NAME, PLPGSQL_GETDIAG_ERROR_CONTEXT, PLPGSQL_GETDIAG_ERROR_DETAIL, PLPGSQL_GETDIAG_ERROR_HINT, PLPGSQL_GETDIAG_MESSAGE_TEXT, PLPGSQL_GETDIAG_RETURNED_SQLSTATE, PLPGSQL_GETDIAG_ROUTINE_OID, PLPGSQL_GETDIAG_ROW_COUNT, PLPGSQL_GETDIAG_SCHEMA_NAME, PLPGSQL_GETDIAG_TABLE_NAME, PLPGSQL_RC_OK, ErrorData::schema_name, ErrorData::sqlerrcode, stmt, ErrorData::table_name, PLpgSQL_diag_item::target, UInt64GetDatum(), and unpack_sql_state().

Referenced by exec_stmts().

◆ exec_stmt_if()

static int exec_stmt_if ( PLpgSQL_execstate estate,
PLpgSQL_stmt_if stmt 
)
static

Definition at line 2526 of file pl_exec.c.

2527{
2528 bool value;
2529 bool isnull;
2530 ListCell *lc;
2531
2532 value = exec_eval_boolean(estate, stmt->cond, &isnull);
2533 exec_eval_cleanup(estate);
2534 if (!isnull && value)
2535 return exec_stmts(estate, stmt->then_body);
2536
2537 foreach(lc, stmt->elsif_list)
2538 {
2540
2541 value = exec_eval_boolean(estate, elif->cond, &isnull);
2542 exec_eval_cleanup(estate);
2543 if (!isnull && value)
2544 return exec_stmts(estate, elif->stmts);
2545 }
2546
2547 return exec_stmts(estate, stmt->else_body);
2548}
PLpgSQL_expr * cond
Definition: plpgsql.h:635
List * stmts
Definition: plpgsql.h:636

References PLpgSQL_if_elsif::cond, exec_eval_boolean(), exec_eval_cleanup(), exec_stmts(), lfirst, stmt, PLpgSQL_if_elsif::stmts, and value.

Referenced by exec_stmts().

◆ exec_stmt_loop()

static int exec_stmt_loop ( PLpgSQL_execstate estate,
PLpgSQL_stmt_loop stmt 
)
static

Definition at line 2643 of file pl_exec.c.

2644{
2645 int rc = PLPGSQL_RC_OK;
2646
2647 for (;;)
2648 {
2649 rc = exec_stmts(estate, stmt->body);
2650
2651 LOOP_RC_PROCESSING(stmt->label, break);
2652 }
2653
2654 return rc;
2655}

References exec_stmts(), LOOP_RC_PROCESSING, PLPGSQL_RC_OK, and stmt.

Referenced by exec_stmts().

◆ exec_stmt_open()

static int exec_stmt_open ( PLpgSQL_execstate estate,
PLpgSQL_stmt_open stmt 
)
static

Definition at line 4671 of file pl_exec.c.

4672{
4673 PLpgSQL_var *curvar;
4674 MemoryContext stmt_mcontext = NULL;
4675 char *curname = NULL;
4676 PLpgSQL_expr *query;
4677 Portal portal;
4678 ParamListInfo paramLI;
4679
4680 /* ----------
4681 * Get the cursor variable and if it has an assigned name, check
4682 * that it's not in use currently.
4683 * ----------
4684 */
4685 curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
4686 if (!curvar->isnull)
4687 {
4688 MemoryContext oldcontext;
4689
4690 /* We only need stmt_mcontext to hold the cursor name string */
4691 stmt_mcontext = get_stmt_mcontext(estate);
4692 oldcontext = MemoryContextSwitchTo(stmt_mcontext);
4693 curname = TextDatumGetCString(curvar->value);
4694 MemoryContextSwitchTo(oldcontext);
4695
4696 if (SPI_cursor_find(curname) != NULL)
4697 ereport(ERROR,
4698 (errcode(ERRCODE_DUPLICATE_CURSOR),
4699 errmsg("cursor \"%s\" already in use", curname)));
4700 }
4701
4702 /* ----------
4703 * Process the OPEN according to its type.
4704 * ----------
4705 */
4706 if (stmt->query != NULL)
4707 {
4708 /* ----------
4709 * This is an OPEN refcursor FOR SELECT ...
4710 *
4711 * We just make sure the query is planned. The real work is
4712 * done downstairs.
4713 * ----------
4714 */
4715 query = stmt->query;
4716 if (query->plan == NULL)
4717 exec_prepare_plan(estate, query, stmt->cursor_options);
4718 }
4719 else if (stmt->dynquery != NULL)
4720 {
4721 /* ----------
4722 * This is an OPEN refcursor FOR EXECUTE ...
4723 * ----------
4724 */
4725 portal = exec_dynquery_with_params(estate,
4726 stmt->dynquery,
4727 stmt->params,
4728 curname,
4729 stmt->cursor_options);
4730
4731 /*
4732 * If cursor variable was NULL, store the generated portal name in it,
4733 * after verifying it's okay to assign to.
4734 *
4735 * Note: exec_dynquery_with_params already reset the stmt_mcontext, so
4736 * curname is a dangling pointer here; but testing it for nullness is
4737 * OK.
4738 */
4739 if (curname == NULL)
4740 {
4741 exec_check_assignable(estate, stmt->curvar);
4742 assign_text_var(estate, curvar, portal->name);
4743 }
4744
4745 return PLPGSQL_RC_OK;
4746 }
4747 else
4748 {
4749 /* ----------
4750 * This is an OPEN cursor
4751 *
4752 * Note: parser should already have checked that statement supplies
4753 * args iff cursor needs them, but we check again to be safe.
4754 * ----------
4755 */
4756 if (stmt->argquery != NULL)
4757 {
4758 /* ----------
4759 * OPEN CURSOR with args. We fake a SELECT ... INTO ...
4760 * statement to evaluate the args and put 'em into the
4761 * internal row.
4762 * ----------
4763 */
4764 PLpgSQL_stmt_execsql set_args;
4765
4766 if (curvar->cursor_explicit_argrow < 0)
4767 ereport(ERROR,
4768 (errcode(ERRCODE_SYNTAX_ERROR),
4769 errmsg("arguments given for cursor without arguments")));
4770
4771 memset(&set_args, 0, sizeof(set_args));
4772 set_args.cmd_type = PLPGSQL_STMT_EXECSQL;
4773 set_args.lineno = stmt->lineno;
4774 set_args.sqlstmt = stmt->argquery;
4775 set_args.into = true;
4776 /* XXX historically this has not been STRICT */
4777 set_args.target = (PLpgSQL_variable *)
4778 (estate->datums[curvar->cursor_explicit_argrow]);
4779
4780 if (exec_stmt_execsql(estate, &set_args) != PLPGSQL_RC_OK)
4781 elog(ERROR, "open cursor failed during argument processing");
4782 }
4783 else
4784 {
4785 if (curvar->cursor_explicit_argrow >= 0)
4786 ereport(ERROR,
4787 (errcode(ERRCODE_SYNTAX_ERROR),
4788 errmsg("arguments required for cursor")));
4789 }
4790
4791 query = curvar->cursor_explicit_expr;
4792 if (query->plan == NULL)
4793 exec_prepare_plan(estate, query, curvar->cursor_options);
4794 }
4795
4796 /*
4797 * Set up ParamListInfo for this query
4798 */
4799 paramLI = setup_param_list(estate, query);
4800
4801 /*
4802 * Open the cursor (the paramlist will get copied into the portal)
4803 */
4804 portal = SPI_cursor_open_with_paramlist(curname, query->plan,
4805 paramLI,
4806 estate->readonly_func);
4807 if (portal == NULL)
4808 elog(ERROR, "could not open cursor: %s",
4810
4811 /*
4812 * If cursor variable was NULL, store the generated portal name in it,
4813 * after verifying it's okay to assign to.
4814 */
4815 if (curname == NULL)
4816 {
4817 exec_check_assignable(estate, stmt->curvar);
4818 assign_text_var(estate, curvar, portal->name);
4819 }
4820
4821 /* If we had any transient data, clean it up */
4822 exec_eval_cleanup(estate);
4823 if (stmt_mcontext)
4824 MemoryContextReset(stmt_mcontext);
4825
4826 return PLPGSQL_RC_OK;
4827}

References 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_dynquery_with_params(), exec_eval_cleanup(), 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_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_perform()

static int exec_stmt_perform ( PLpgSQL_execstate estate,
PLpgSQL_stmt_perform stmt 
)
static

Definition at line 2180 of file pl_exec.c.

2181{
2182 PLpgSQL_expr *expr = stmt->expr;
2183
2184 (void) exec_run_select(estate, expr, 0, NULL);
2185 exec_set_found(estate, (estate->eval_processed != 0));
2186 exec_eval_cleanup(estate);
2187
2188 return PLPGSQL_RC_OK;
2189}

References PLpgSQL_execstate::eval_processed, exec_eval_cleanup(), exec_run_select(), exec_set_found(), PLPGSQL_RC_OK, and stmt.

Referenced by exec_stmts().

◆ exec_stmt_raise()

static int exec_stmt_raise ( PLpgSQL_execstate estate,
PLpgSQL_stmt_raise stmt 
)
static

Definition at line 3739 of file pl_exec.c.

3740{
3741 int err_code = 0;
3742 char *condname = NULL;
3743 char *err_message = NULL;
3744 char *err_detail = NULL;
3745 char *err_hint = NULL;
3746 char *err_column = NULL;
3747 char *err_constraint = NULL;
3748 char *err_datatype = NULL;
3749 char *err_table = NULL;
3750 char *err_schema = NULL;
3751 MemoryContext stmt_mcontext;
3752 ListCell *lc;
3753
3754 /* RAISE with no parameters: re-throw current exception */
3755 if (stmt->condname == NULL && stmt->message == NULL &&
3756 stmt->options == NIL)
3757 {
3758 if (estate->cur_error != NULL)
3759 ReThrowError(estate->cur_error);
3760 /* oops, we're not inside a handler */
3761 ereport(ERROR,
3762 (errcode(ERRCODE_STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER),
3763 errmsg("RAISE without parameters cannot be used outside an exception handler")));
3764 }
3765
3766 /* We'll need to accumulate the various strings in stmt_mcontext */
3767 stmt_mcontext = get_stmt_mcontext(estate);
3768
3769 if (stmt->condname)
3770 {
3771 err_code = plpgsql_recognize_err_condition(stmt->condname, true);
3772 condname = MemoryContextStrdup(stmt_mcontext, stmt->condname);
3773 }
3774
3775 if (stmt->message)
3776 {
3777 StringInfoData ds;
3778 ListCell *current_param;
3779 char *cp;
3780 MemoryContext oldcontext;
3781
3782 /* build string in stmt_mcontext */
3783 oldcontext = MemoryContextSwitchTo(stmt_mcontext);
3784 initStringInfo(&ds);
3785 MemoryContextSwitchTo(oldcontext);
3786
3787 current_param = list_head(stmt->params);
3788
3789 for (cp = stmt->message; *cp; cp++)
3790 {
3791 /*
3792 * Occurrences of a single % are replaced by the next parameter's
3793 * external representation. Double %'s are converted to one %.
3794 */
3795 if (cp[0] == '%')
3796 {
3797 Oid paramtypeid;
3798 int32 paramtypmod;
3799 Datum paramvalue;
3800 bool paramisnull;
3801 char *extval;
3802
3803 if (cp[1] == '%')
3804 {
3805 appendStringInfoChar(&ds, '%');
3806 cp++;
3807 continue;
3808 }
3809
3810 /* should have been checked at compile time */
3811 if (current_param == NULL)
3812 elog(ERROR, "unexpected RAISE parameter list length");
3813
3814 paramvalue = exec_eval_expr(estate,
3815 (PLpgSQL_expr *) lfirst(current_param),
3816 &paramisnull,
3817 &paramtypeid,
3818 &paramtypmod);
3819
3820 if (paramisnull)
3821 extval = "<NULL>";
3822 else
3823 extval = convert_value_to_string(estate,
3824 paramvalue,
3825 paramtypeid);
3826 appendStringInfoString(&ds, extval);
3827 current_param = lnext(stmt->params, current_param);
3828 exec_eval_cleanup(estate);
3829 }
3830 else
3831 appendStringInfoChar(&ds, cp[0]);
3832 }
3833
3834 /* should have been checked at compile time */
3835 if (current_param != NULL)
3836 elog(ERROR, "unexpected RAISE parameter list length");
3837
3838 err_message = ds.data;
3839 }
3840
3841 foreach(lc, stmt->options)
3842 {
3844 Datum optionvalue;
3845 bool optionisnull;
3846 Oid optiontypeid;
3847 int32 optiontypmod;
3848 char *extval;
3849
3850 optionvalue = exec_eval_expr(estate, opt->expr,
3851 &optionisnull,
3852 &optiontypeid,
3853 &optiontypmod);
3854 if (optionisnull)
3855 ereport(ERROR,
3856 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
3857 errmsg("RAISE statement option cannot be null")));
3858
3859 extval = convert_value_to_string(estate, optionvalue, optiontypeid);
3860
3861 switch (opt->opt_type)
3862 {
3864 if (err_code)
3865 ereport(ERROR,
3866 (errcode(ERRCODE_SYNTAX_ERROR),
3867 errmsg("RAISE option already specified: %s",
3868 "ERRCODE")));
3869 err_code = plpgsql_recognize_err_condition(extval, true);
3870 condname = MemoryContextStrdup(stmt_mcontext, extval);
3871 break;
3873 SET_RAISE_OPTION_TEXT(err_message, "MESSAGE");
3874 break;
3876 SET_RAISE_OPTION_TEXT(err_detail, "DETAIL");
3877 break;
3879 SET_RAISE_OPTION_TEXT(err_hint, "HINT");
3880 break;
3882 SET_RAISE_OPTION_TEXT(err_column, "COLUMN");
3883 break;
3885 SET_RAISE_OPTION_TEXT(err_constraint, "CONSTRAINT");
3886 break;
3888 SET_RAISE_OPTION_TEXT(err_datatype, "DATATYPE");
3889 break;
3891 SET_RAISE_OPTION_TEXT(err_table, "TABLE");
3892 break;
3894 SET_RAISE_OPTION_TEXT(err_schema, "SCHEMA");
3895 break;
3896 default:
3897 elog(ERROR, "unrecognized raise option: %d", opt->opt_type);
3898 }
3899
3900 exec_eval_cleanup(estate);
3901 }
3902
3903 /* Default code if nothing specified */
3904 if (err_code == 0 && stmt->elog_level >= ERROR)
3905 err_code = ERRCODE_RAISE_EXCEPTION;
3906
3907 /* Default error message if nothing specified */
3908 if (err_message == NULL)
3909 {
3910 if (condname)
3911 {
3912 err_message = condname;
3913 condname = NULL;
3914 }
3915 else
3916 err_message = MemoryContextStrdup(stmt_mcontext,
3917 unpack_sql_state(err_code));
3918 }
3919
3920 /*
3921 * Throw the error (may or may not come back)
3922 */
3923 ereport(stmt->elog_level,
3924 (err_code ? errcode(err_code) : 0,
3925 errmsg_internal("%s", err_message),
3926 (err_detail != NULL) ? errdetail_internal("%s", err_detail) : 0,
3927 (err_hint != NULL) ? errhint("%s", err_hint) : 0,
3928 (err_column != NULL) ?
3929 err_generic_string(PG_DIAG_COLUMN_NAME, err_column) : 0,
3930 (err_constraint != NULL) ?
3931 err_generic_string(PG_DIAG_CONSTRAINT_NAME, err_constraint) : 0,
3932 (err_datatype != NULL) ?
3933 err_generic_string(PG_DIAG_DATATYPE_NAME, err_datatype) : 0,
3934 (err_table != NULL) ?
3935 err_generic_string(PG_DIAG_TABLE_NAME, err_table) : 0,
3936 (err_schema != NULL) ?
3937 err_generic_string(PG_DIAG_SCHEMA_NAME, err_schema) : 0));
3938
3939 /* Clean up transient strings */
3940 MemoryContextReset(stmt_mcontext);
3941
3942 return PLPGSQL_RC_OK;
3943}
int err_generic_string(int field, const char *str)
Definition: elog.c:1512
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
int plpgsql_recognize_err_condition(const char *condname, bool allow_sqlstate)
Definition: pl_comp.c:2229
#define SET_RAISE_OPTION_TEXT(opt, name)
Definition: pl_exec.c:3724
@ PLPGSQL_RAISEOPTION_COLUMN
Definition: plpgsql.h:173
@ PLPGSQL_RAISEOPTION_TABLE
Definition: plpgsql.h:176
@ PLPGSQL_RAISEOPTION_SCHEMA
Definition: plpgsql.h:177
@ PLPGSQL_RAISEOPTION_CONSTRAINT
Definition: plpgsql.h:174
@ PLPGSQL_RAISEOPTION_DETAIL
Definition: plpgsql.h:171
@ PLPGSQL_RAISEOPTION_MESSAGE
Definition: plpgsql.h:170
@ PLPGSQL_RAISEOPTION_HINT
Definition: plpgsql.h:172
@ PLPGSQL_RAISEOPTION_ERRCODE
Definition: plpgsql.h:169
@ PLPGSQL_RAISEOPTION_DATATYPE
Definition: plpgsql.h:175
#define PG_DIAG_SCHEMA_NAME
Definition: postgres_ext.h:60
#define PG_DIAG_CONSTRAINT_NAME
Definition: postgres_ext.h:64
#define PG_DIAG_DATATYPE_NAME
Definition: postgres_ext.h:63
#define PG_DIAG_TABLE_NAME
Definition: postgres_ext.h:61
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:62
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:230
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
PLpgSQL_raise_option_type opt_type
Definition: plpgsql.h:897
PLpgSQL_expr * expr
Definition: plpgsql.h:898

References appendStringInfoChar(), appendStringInfoString(), convert_value_to_string(), PLpgSQL_execstate::cur_error, StringInfoData::data, elog, ereport, err_generic_string(), errcode(), errdetail_internal(), errhint(), errmsg(), errmsg_internal(), ERROR, exec_eval_cleanup(), exec_eval_expr(), PLpgSQL_raise_option::expr, get_stmt_mcontext(), initStringInfo(), lfirst, list_head(), lnext(), MemoryContextReset(), MemoryContextStrdup(), MemoryContextSwitchTo(), NIL, PLpgSQL_raise_option::opt_type, PG_DIAG_COLUMN_NAME, PG_DIAG_CONSTRAINT_NAME, PG_DIAG_DATATYPE_NAME, PG_DIAG_SCHEMA_NAME, PG_DIAG_TABLE_NAME, PLPGSQL_RAISEOPTION_COLUMN, PLPGSQL_RAISEOPTION_CONSTRAINT, PLPGSQL_RAISEOPTION_DATATYPE, PLPGSQL_RAISEOPTION_DETAIL, PLPGSQL_RAISEOPTION_ERRCODE, PLPGSQL_RAISEOPTION_HINT, PLPGSQL_RAISEOPTION_MESSAGE, PLPGSQL_RAISEOPTION_SCHEMA, PLPGSQL_RAISEOPTION_TABLE, PLPGSQL_RC_OK, plpgsql_recognize_err_condition(), ReThrowError(), SET_RAISE_OPTION_TEXT, stmt, and unpack_sql_state().

Referenced by exec_stmts().

◆ exec_stmt_return()

static int exec_stmt_return ( PLpgSQL_execstate estate,
PLpgSQL_stmt_return stmt 
)
static

Definition at line 3197 of file pl_exec.c.

3198{
3199 /*
3200 * If processing a set-returning PL/pgSQL function, the final RETURN
3201 * indicates that the function is finished producing tuples. The rest of
3202 * the work will be done at the top level.
3203 */
3204 if (estate->retisset)
3205 return PLPGSQL_RC_RETURN;
3206
3207 /* initialize for null result */
3208 estate->retval = (Datum) 0;
3209 estate->retisnull = true;
3210 estate->rettype = InvalidOid;
3211
3212 /*
3213 * Special case path when the RETURN expression is a simple variable
3214 * reference; in particular, this path is always taken in functions with
3215 * one or more OUT parameters.
3216 *
3217 * This special case is especially efficient for returning variables that
3218 * have R/W expanded values: we can put the R/W pointer directly into
3219 * estate->retval, leading to transferring the value to the caller's
3220 * context cheaply. If we went through exec_eval_expr we'd end up with a
3221 * R/O pointer. It's okay to skip MakeExpandedObjectReadOnly here since
3222 * we know we won't need the variable's value within the function anymore.
3223 */
3224 if (stmt->retvarno >= 0)
3225 {
3226 PLpgSQL_datum *retvar = estate->datums[stmt->retvarno];
3227
3228 switch (retvar->dtype)
3229 {
3231 /* fulfill promise if needed, then handle like regular var */
3232 plpgsql_fulfill_promise(estate, (PLpgSQL_var *) retvar);
3233
3234 /* FALL THRU */
3235
3236 case PLPGSQL_DTYPE_VAR:
3237 {
3238 PLpgSQL_var *var = (PLpgSQL_var *) retvar;
3239
3240 estate->retval = var->value;
3241 estate->retisnull = var->isnull;
3242 estate->rettype = var->datatype->typoid;
3243
3244 /*
3245 * A PLpgSQL_var could not be of composite type, so
3246 * conversion must fail if retistuple. We throw a custom
3247 * error mainly for consistency with historical behavior.
3248 * For the same reason, we don't throw error if the result
3249 * is NULL. (Note that plpgsql_exec_trigger assumes that
3250 * any non-null result has been verified to be composite.)
3251 */
3252 if (estate->retistuple && !estate->retisnull)
3253 ereport(ERROR,
3254 (errcode(ERRCODE_DATATYPE_MISMATCH),
3255 errmsg("cannot return non-composite value from function returning composite type")));
3256 }
3257 break;
3258
3259 case PLPGSQL_DTYPE_REC:
3260 {
3261 PLpgSQL_rec *rec = (PLpgSQL_rec *) retvar;
3262
3263 /* If record is empty, we return NULL not a row of nulls */
3264 if (rec->erh && !ExpandedRecordIsEmpty(rec->erh))
3265 {
3266 estate->retval = ExpandedRecordGetDatum(rec->erh);
3267 estate->retisnull = false;
3268 estate->rettype = rec->rectypeid;
3269 }
3270 }
3271 break;
3272
3273 case PLPGSQL_DTYPE_ROW:
3274 {
3275 PLpgSQL_row *row = (PLpgSQL_row *) retvar;
3276 int32 rettypmod;
3277
3278 /* We get here if there are multiple OUT parameters */
3279 exec_eval_datum(estate,
3280 (PLpgSQL_datum *) row,
3281 &estate->rettype,
3282 &rettypmod,
3283 &estate->retval,
3284 &estate->retisnull);
3285 }
3286 break;
3287
3288 default:
3289 elog(ERROR, "unrecognized dtype: %d", retvar->dtype);
3290 }
3291
3292 return PLPGSQL_RC_RETURN;
3293 }
3294
3295 if (stmt->expr != NULL)
3296 {
3297 int32 rettypmod;
3298
3299 estate->retval = exec_eval_expr(estate, stmt->expr,
3300 &(estate->retisnull),
3301 &(estate->rettype),
3302 &rettypmod);
3303
3304 /*
3305 * As in the DTYPE_VAR case above, throw a custom error if a non-null,
3306 * non-composite value is returned in a function returning tuple.
3307 */
3308 if (estate->retistuple && !estate->retisnull &&
3309 !type_is_rowtype(estate->rettype))
3310 ereport(ERROR,
3311 (errcode(ERRCODE_DATATYPE_MISMATCH),
3312 errmsg("cannot return non-composite value from function returning composite type")));
3313
3314 return PLPGSQL_RC_RETURN;
3315 }
3316
3317 /*
3318 * Special hack for function returning VOID: instead of NULL, return a
3319 * non-null VOID value. This is of dubious importance but is kept for
3320 * backwards compatibility. We don't do it for procedures, though.
3321 */
3322 if (estate->fn_rettype == VOIDOID &&
3323 estate->func->fn_prokind != PROKIND_PROCEDURE)
3324 {
3325 estate->retval = (Datum) 0;
3326 estate->retisnull = false;
3327 estate->rettype = VOIDOID;
3328 }
3329
3330 return PLPGSQL_RC_RETURN;
3331}
static void exec_eval_datum(PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeid, int32 *typetypmod, Datum *value, bool *isnull)
Definition: pl_exec.c:5302

References PLpgSQL_var::datatype, PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, PLpgSQL_var::dtype, elog, ereport, PLpgSQL_rec::erh, errcode(), errmsg(), ERROR, exec_eval_datum(), exec_eval_expr(), ExpandedRecordGetDatum(), ExpandedRecordIsEmpty, PLpgSQL_function::fn_prokind, PLpgSQL_execstate::fn_rettype, PLpgSQL_execstate::func, InvalidOid, PLpgSQL_var::isnull, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, plpgsql_fulfill_promise(), PLPGSQL_RC_RETURN, PLpgSQL_rec::rectypeid, PLpgSQL_execstate::retisnull, PLpgSQL_execstate::retisset, PLpgSQL_execstate::retistuple, PLpgSQL_execstate::rettype, PLpgSQL_execstate::retval, stmt, type_is_rowtype(), PLpgSQL_type::typoid, and PLpgSQL_var::value.

Referenced by exec_stmts().

◆ exec_stmt_return_next()

static int exec_stmt_return_next ( PLpgSQL_execstate estate,
PLpgSQL_stmt_return_next stmt 
)
static

Definition at line 3340 of file pl_exec.c.

3342{
3343 TupleDesc tupdesc;
3344 int natts;
3345 HeapTuple tuple;
3346 MemoryContext oldcontext;
3347
3348 if (!estate->retisset)
3349 ereport(ERROR,
3350 (errcode(ERRCODE_SYNTAX_ERROR),
3351 errmsg("cannot use RETURN NEXT in a non-SETOF function")));
3352
3353 if (estate->tuple_store == NULL)
3354 exec_init_tuple_store(estate);
3355
3356 /* tuple_store_desc will be filled by exec_init_tuple_store */
3357 tupdesc = estate->tuple_store_desc;
3358 natts = tupdesc->natts;
3359
3360 /*
3361 * Special case path when the RETURN NEXT expression is a simple variable
3362 * reference; in particular, this path is always taken in functions with
3363 * one or more OUT parameters.
3364 *
3365 * Unlike exec_stmt_return, there's no special win here for R/W expanded
3366 * values, since they'll have to get flattened to go into the tuplestore.
3367 * Indeed, we'd better make them R/O to avoid any risk of the casting step
3368 * changing them in-place.
3369 */
3370 if (stmt->retvarno >= 0)
3371 {
3372 PLpgSQL_datum *retvar = estate->datums[stmt->retvarno];
3373
3374 switch (retvar->dtype)
3375 {
3377 /* fulfill promise if needed, then handle like regular var */
3378 plpgsql_fulfill_promise(estate, (PLpgSQL_var *) retvar);
3379
3380 /* FALL THRU */
3381
3382 case PLPGSQL_DTYPE_VAR:
3383 {
3384 PLpgSQL_var *var = (PLpgSQL_var *) retvar;
3385 Datum retval = var->value;
3386 bool isNull = var->isnull;
3387 Form_pg_attribute attr = TupleDescAttr(tupdesc, 0);
3388
3389 if (natts != 1)
3390 ereport(ERROR,
3391 (errcode(ERRCODE_DATATYPE_MISMATCH),
3392 errmsg("wrong result type supplied in RETURN NEXT")));
3393
3394 /* let's be very paranoid about the cast step */
3395 retval = MakeExpandedObjectReadOnly(retval,
3396 isNull,
3397 var->datatype->typlen);
3398
3399 /* coerce type if needed */
3400 retval = exec_cast_value(estate,
3401 retval,
3402 &isNull,
3403 var->datatype->typoid,
3404 var->datatype->atttypmod,
3405 attr->atttypid,
3406 attr->atttypmod);
3407
3408 tuplestore_putvalues(estate->tuple_store, tupdesc,
3409 &retval, &isNull);
3410 }
3411 break;
3412
3413 case PLPGSQL_DTYPE_REC:
3414 {
3415 PLpgSQL_rec *rec = (PLpgSQL_rec *) retvar;
3416 TupleDesc rec_tupdesc;
3417 TupleConversionMap *tupmap;
3418
3419 /* If rec is null, try to convert it to a row of nulls */
3420 if (rec->erh == NULL)
3422 if (ExpandedRecordIsEmpty(rec->erh))
3424
3425 /* Use eval_mcontext for tuple conversion work */
3426 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
3427 rec_tupdesc = expanded_record_get_tupdesc(rec->erh);
3428 tupmap = convert_tuples_by_position(rec_tupdesc,
3429 tupdesc,
3430 gettext_noop("wrong record type supplied in RETURN NEXT"));
3431 tuple = expanded_record_get_tuple(rec->erh);
3432 if (tupmap)
3433 tuple = execute_attr_map_tuple(tuple, tupmap);
3434 tuplestore_puttuple(estate->tuple_store, tuple);
3435 MemoryContextSwitchTo(oldcontext);
3436 }
3437 break;
3438
3439 case PLPGSQL_DTYPE_ROW:
3440 {
3441 PLpgSQL_row *row = (PLpgSQL_row *) retvar;
3442
3443 /* We get here if there are multiple OUT parameters */
3444
3445 /* Use eval_mcontext for tuple conversion work */
3446 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
3447 tuple = make_tuple_from_row(estate, row, tupdesc);
3448 if (tuple == NULL) /* should not happen */
3449 ereport(ERROR,
3450 (errcode(ERRCODE_DATATYPE_MISMATCH),
3451 errmsg("wrong record type supplied in RETURN NEXT")));
3452 tuplestore_puttuple(estate->tuple_store, tuple);
3453 MemoryContextSwitchTo(oldcontext);
3454 }
3455 break;
3456
3457 default:
3458 elog(ERROR, "unrecognized dtype: %d", retvar->dtype);
3459 break;
3460 }
3461 }
3462 else if (stmt->expr)
3463 {
3464 Datum retval;
3465 bool isNull;
3466 Oid rettype;
3467 int32 rettypmod;
3468
3469 retval = exec_eval_expr(estate,
3470 stmt->expr,
3471 &isNull,
3472 &rettype,
3473 &rettypmod);
3474
3475 if (estate->retistuple)
3476 {
3477 /* Expression should be of RECORD or composite type */
3478 if (!isNull)
3479 {
3480 HeapTupleData tmptup;
3481 TupleDesc retvaldesc;
3482 TupleConversionMap *tupmap;
3483
3484 if (!type_is_rowtype(rettype))
3485 ereport(ERROR,
3486 (errcode(ERRCODE_DATATYPE_MISMATCH),
3487 errmsg("cannot return non-composite value from function returning composite type")));
3488
3489 /* Use eval_mcontext for tuple conversion work */
3490 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
3491 retvaldesc = deconstruct_composite_datum(retval, &tmptup);
3492 tuple = &tmptup;
3493 tupmap = convert_tuples_by_position(retvaldesc, tupdesc,
3494 gettext_noop("returned record type does not match expected record type"));
3495 if (tupmap)
3496 tuple = execute_attr_map_tuple(tuple, tupmap);
3497 tuplestore_puttuple(estate->tuple_store, tuple);
3498 ReleaseTupleDesc(retvaldesc);
3499 MemoryContextSwitchTo(oldcontext);
3500 }
3501 else
3502 {
3503 /* Composite NULL --- store a row of nulls */
3504 Datum *nulldatums;
3505 bool *nullflags;
3506
3507 nulldatums = (Datum *)
3508 eval_mcontext_alloc0(estate, natts * sizeof(Datum));
3509 nullflags = (bool *)
3510 eval_mcontext_alloc(estate, natts * sizeof(bool));
3511 memset(nullflags, true, natts * sizeof(bool));
3512 tuplestore_putvalues(estate->tuple_store, tupdesc,
3513 nulldatums, nullflags);
3514 }
3515 }
3516 else
3517 {
3518 Form_pg_attribute attr = TupleDescAttr(tupdesc, 0);
3519
3520 /* Simple scalar result */
3521 if (natts != 1)
3522 ereport(ERROR,
3523 (errcode(ERRCODE_DATATYPE_MISMATCH),
3524 errmsg("wrong result type supplied in RETURN NEXT")));
3525
3526 /* coerce type if needed */
3527 retval = exec_cast_value(estate,
3528 retval,
3529 &isNull,
3530 rettype,
3531 rettypmod,
3532 attr->atttypid,
3533 attr->atttypmod);
3534
3535 tuplestore_putvalues(estate->tuple_store, tupdesc,
3536 &retval, &isNull);
3537 }
3538 }
3539 else
3540 {
3541 ereport(ERROR,
3542 (errcode(ERRCODE_SYNTAX_ERROR),
3543 errmsg("RETURN NEXT must have a parameter")));
3544 }
3545
3546 exec_eval_cleanup(estate);
3547
3548 return PLPGSQL_RC_OK;
3549}
#define MakeExpandedObjectReadOnly(d, isnull, typlen)
static void exec_init_tuple_store(PLpgSQL_execstate *estate)
Definition: pl_exec.c:3683
#define eval_mcontext_alloc0(estate, sz)
Definition: pl_exec.c:131
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:784
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition: tuplestore.c:764

References PLpgSQL_type::atttypmod, convert_tuples_by_position(), PLpgSQL_var::datatype, PLpgSQL_execstate::datums, deconstruct_composite_datum(), deconstruct_expanded_record(), PLpgSQL_datum::dtype, PLpgSQL_var::dtype, elog, ereport, PLpgSQL_rec::erh, errcode(), errmsg(), ERROR, eval_mcontext_alloc, eval_mcontext_alloc0, exec_cast_value(), exec_eval_cleanup(), exec_eval_expr(), exec_init_tuple_store(), execute_attr_map_tuple(), expanded_record_get_tupdesc(), expanded_record_get_tuple(), ExpandedRecordIsEmpty, get_eval_mcontext, gettext_noop, instantiate_empty_record_variable(), PLpgSQL_var::isnull, make_tuple_from_row(), MakeExpandedObjectReadOnly, MemoryContextSwitchTo(), TupleDescData::natts, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, plpgsql_fulfill_promise(), PLPGSQL_RC_OK, ReleaseTupleDesc, PLpgSQL_execstate::retisset, PLpgSQL_execstate::retistuple, stmt, PLpgSQL_execstate::tuple_store, PLpgSQL_execstate::tuple_store_desc, TupleDescAttr(), tuplestore_puttuple(), tuplestore_putvalues(), type_is_rowtype(), PLpgSQL_type::typlen, PLpgSQL_type::typoid, and PLpgSQL_var::value.

Referenced by exec_stmts().

◆ exec_stmt_return_query()

static int exec_stmt_return_query ( PLpgSQL_execstate estate,
PLpgSQL_stmt_return_query stmt 
)
static

Definition at line 3558 of file pl_exec.c.

3560{
3561 int64 tcount;
3562 DestReceiver *treceiver;
3563 int rc;
3564 uint64 processed;
3565 MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
3566 MemoryContext oldcontext;
3567
3568 if (!estate->retisset)
3569 ereport(ERROR,
3570 (errcode(ERRCODE_SYNTAX_ERROR),
3571 errmsg("cannot use RETURN QUERY in a non-SETOF function")));
3572
3573 if (estate->tuple_store == NULL)
3574 exec_init_tuple_store(estate);
3575 /* There might be some tuples in the tuplestore already */
3576 tcount = tuplestore_tuple_count(estate->tuple_store);
3577
3578 /*
3579 * Set up DestReceiver to transfer results directly to tuplestore,
3580 * converting rowtype if necessary. DestReceiver lives in mcontext.
3581 */
3582 oldcontext = MemoryContextSwitchTo(stmt_mcontext);
3585 estate->tuple_store,
3586 estate->tuple_store_cxt,
3587 false,
3588 estate->tuple_store_desc,
3589 gettext_noop("structure of query does not match function result type"));
3590 MemoryContextSwitchTo(oldcontext);
3591
3592 if (stmt->query != NULL)
3593 {
3594 /* static query */
3595 PLpgSQL_expr *expr = stmt->query;
3596 ParamListInfo paramLI;
3598
3599 /*
3600 * On the first call for this expression generate the plan.
3601 */
3602 if (expr->plan == NULL)
3604
3605 /*
3606 * Set up ParamListInfo to pass to executor
3607 */
3608 paramLI = setup_param_list(estate, expr);
3609
3610 /*
3611 * Execute the query
3612 */
3613 memset(&options, 0, sizeof(options));
3614 options.params = paramLI;
3615 options.read_only = estate->readonly_func;
3616 options.must_return_tuples = true;
3617 options.dest = treceiver;
3618
3620 if (rc < 0)
3621 elog(ERROR, "SPI_execute_plan_extended failed executing query \"%s\": %s",
3622 expr->query, SPI_result_code_string(rc));
3623 }
3624 else
3625 {
3626 /* RETURN QUERY EXECUTE */
3627 Datum query;
3628 bool isnull;
3629 Oid restype;
3630 int32 restypmod;
3631 char *querystr;
3633
3634 /*
3635 * Evaluate the string expression after the EXECUTE keyword. Its
3636 * result is the querystring we have to execute.
3637 */
3638 Assert(stmt->dynquery != NULL);
3639 query = exec_eval_expr(estate, stmt->dynquery,
3640 &isnull, &restype, &restypmod);
3641 if (isnull)
3642 ereport(ERROR,
3643 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
3644 errmsg("query string argument of EXECUTE is null")));
3645
3646 /* Get the C-String representation */
3647 querystr = convert_value_to_string(estate, query, restype);
3648
3649 /* copy it into the stmt_mcontext before we clean up */
3650 querystr = MemoryContextStrdup(stmt_mcontext, querystr);
3651
3652 exec_eval_cleanup(estate);
3653
3654 /* Execute query, passing params if necessary */
3655 memset(&options, 0, sizeof(options));
3656 options.params = exec_eval_using_params(estate,
3657 stmt->params);
3658 options.read_only = estate->readonly_func;
3659 options.must_return_tuples = true;
3660 options.dest = treceiver;
3661
3662 rc = SPI_execute_extended(querystr, &options);
3663 if (rc < 0)
3664 elog(ERROR, "SPI_execute_extended failed executing query \"%s\": %s",
3665 querystr, SPI_result_code_string(rc));
3666 }
3667
3668 /* Clean up */
3669 treceiver->rDestroy(treceiver);
3670 exec_eval_cleanup(estate);
3671 MemoryContextReset(stmt_mcontext);
3672
3673 /* Count how many tuples we got */
3674 processed = tuplestore_tuple_count(estate->tuple_store) - tcount;
3675
3676 estate->eval_processed = processed;
3677 exec_set_found(estate, processed != 0);
3678
3679 return PLPGSQL_RC_OK;
3680}
int64_t int64
Definition: c.h:499
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:113
@ DestTuplestore
Definition: dest.h:93
void(* rDestroy)(DestReceiver *self)
Definition: dest.h:126
void SetTuplestoreDestReceiverParams(DestReceiver *self, Tuplestorestate *tStore, MemoryContext tContext, bool detoast, TupleDesc target_tupdesc, const char *map_failure_msg)
int64 tuplestore_tuple_count(Tuplestorestate *state)
Definition: tuplestore.c:580

References Assert(), convert_value_to_string(), CreateDestReceiver(), CURSOR_OPT_PARALLEL_OK, DestTuplestore, elog, ereport, errcode(), errmsg(), ERROR, PLpgSQL_execstate::eval_processed, exec_eval_cleanup(), exec_eval_expr(), exec_eval_using_params(), exec_init_tuple_store(), exec_prepare_plan(), exec_set_found(), get_stmt_mcontext(), gettext_noop, MemoryContextReset(), MemoryContextStrdup(), MemoryContextSwitchTo(), options, PLpgSQL_expr::plan, PLPGSQL_RC_OK, PLpgSQL_expr::query, _DestReceiver::rDestroy, PLpgSQL_execstate::readonly_func, PLpgSQL_execstate::retisset, SetTuplestoreDestReceiverParams(), setup_param_list(), SPI_execute_extended(), SPI_execute_plan_extended(), SPI_result_code_string(), stmt, PLpgSQL_execstate::tuple_store, PLpgSQL_execstate::tuple_store_cxt, PLpgSQL_execstate::tuple_store_desc, and tuplestore_tuple_count().

Referenced by exec_stmts().

◆ exec_stmt_rollback()

static int exec_stmt_rollback ( PLpgSQL_execstate estate,
PLpgSQL_stmt_rollback stmt 
)
static

Definition at line 4994 of file pl_exec.c.

4995{
4996 if (stmt->chain)
4998 else
4999 SPI_rollback();
5000
5001 /*
5002 * We need to build new simple-expression infrastructure, since the old
5003 * data structures are gone.
5004 */
5005 estate->simple_eval_estate = NULL;
5006 estate->simple_eval_resowner = NULL;
5008
5009 return PLPGSQL_RC_OK;
5010}
void SPI_rollback_and_chain(void)
Definition: spi.c:420
void SPI_rollback(void)
Definition: spi.c:414

References plpgsql_create_econtext(), PLPGSQL_RC_OK, PLpgSQL_execstate::simple_eval_estate, PLpgSQL_execstate::simple_eval_resowner, SPI_rollback(), SPI_rollback_and_chain(), and stmt.

Referenced by exec_stmts().

◆ exec_stmt_while()

static int exec_stmt_while ( PLpgSQL_execstate estate,
PLpgSQL_stmt_while stmt 
)
static

Definition at line 2665 of file pl_exec.c.

2666{
2667 int rc = PLPGSQL_RC_OK;
2668
2669 for (;;)
2670 {
2671 bool value;
2672 bool isnull;
2673
2674 value = exec_eval_boolean(estate, stmt->cond, &isnull);
2675 exec_eval_cleanup(estate);
2676
2677 if (isnull || !value)
2678 break;
2679
2680 rc = exec_stmts(estate, stmt->body);
2681
2682 LOOP_RC_PROCESSING(stmt->label, break);
2683 }
2684
2685 return rc;
2686}

References exec_eval_boolean(), exec_eval_cleanup(), exec_stmts(), LOOP_RC_PROCESSING, PLPGSQL_RC_OK, stmt, and value.

Referenced by exec_stmts().

◆ exec_stmts()

static int exec_stmts ( PLpgSQL_execstate estate,
List stmts 
)
static

Definition at line 1996 of file pl_exec.c.

1997{
1998 PLpgSQL_stmt *save_estmt = estate->err_stmt;
1999 ListCell *s;
2000
2001 if (stmts == NIL)
2002 {
2003 /*
2004 * Ensure we do a CHECK_FOR_INTERRUPTS() even though there is no
2005 * statement. This prevents hangup in a tight loop if, for instance,
2006 * there is a LOOP construct with an empty body.
2007 */
2009 return PLPGSQL_RC_OK;
2010 }
2011
2012 foreach(s, stmts)
2013 {
2015 int rc;
2016
2017 estate->err_stmt = stmt;
2018
2019 /* Let the plugin know that we are about to execute this statement */
2020 if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
2021 ((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt);
2022
2024
2025 switch (stmt->cmd_type)
2026 {
2027 case PLPGSQL_STMT_BLOCK:
2028 rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt);
2029 break;
2030
2032 rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
2033 break;
2034
2037 break;
2038
2039 case PLPGSQL_STMT_CALL:
2040 rc = exec_stmt_call(estate, (PLpgSQL_stmt_call *) stmt);
2041 break;
2042
2045 break;
2046
2047 case PLPGSQL_STMT_IF:
2048 rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);
2049 break;
2050
2051 case PLPGSQL_STMT_CASE:
2052 rc = exec_stmt_case(estate, (PLpgSQL_stmt_case *) stmt);
2053 break;
2054
2055 case PLPGSQL_STMT_LOOP:
2056 rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt);
2057 break;
2058
2059 case PLPGSQL_STMT_WHILE:
2060 rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt);
2061 break;
2062
2063 case PLPGSQL_STMT_FORI:
2064 rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt);
2065 break;
2066
2067 case PLPGSQL_STMT_FORS:
2068 rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt);
2069 break;
2070
2071 case PLPGSQL_STMT_FORC:
2072 rc = exec_stmt_forc(estate, (PLpgSQL_stmt_forc *) stmt);
2073 break;
2074
2077 break;
2078
2079 case PLPGSQL_STMT_EXIT:
2080 rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt);
2081 break;
2082
2084 rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt);
2085 break;
2086
2089 break;
2090
2093 break;
2094
2095 case PLPGSQL_STMT_RAISE:
2096 rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt);
2097 break;
2098
2100 rc = exec_stmt_assert(estate, (PLpgSQL_stmt_assert *) stmt);
2101 break;
2102
2105 break;
2106
2109 break;
2110
2113 break;
2114
2115 case PLPGSQL_STMT_OPEN:
2116 rc = exec_stmt_open(estate, (PLpgSQL_stmt_open *) stmt);
2117 break;
2118
2119 case PLPGSQL_STMT_FETCH:
2120 rc = exec_stmt_fetch(estate, (PLpgSQL_stmt_fetch *) stmt);
2121 break;
2122
2123 case PLPGSQL_STMT_CLOSE:
2124 rc = exec_stmt_close(estate, (PLpgSQL_stmt_close *) stmt);
2125 break;
2126
2128 rc = exec_stmt_commit(estate, (PLpgSQL_stmt_commit *) stmt);
2129 break;
2130
2133 break;
2134
2135 default:
2136 /* point err_stmt to parent, since this one seems corrupt */
2137 estate->err_stmt = save_estmt;
2138 elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
2139 rc = -1; /* keep compiler quiet */
2140 }
2141
2142 /* Let the plugin know that we have finished executing this statement */
2143 if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
2144 ((*plpgsql_plugin_ptr)->stmt_end) (estate, stmt);
2145
2146 if (rc != PLPGSQL_RC_OK)
2147 {
2148 estate->err_stmt = save_estmt;
2149 return rc;
2150 }
2151 } /* end of loop over statements */
2152
2153 estate->err_stmt = save_estmt;
2154 return PLPGSQL_RC_OK;
2155}
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
static int exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
Definition: pl_exec.c:2839
static int exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
Definition: pl_exec.c:4836
static int exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
Definition: pl_exec.c:1663
static int exec_stmt_commit(PLpgSQL_execstate *estate, PLpgSQL_stmt_commit *stmt)
Definition: pl_exec.c:4970
static int exec_stmt_forc(PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt)
Definition: pl_exec.c:2868
static int exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt)
Definition: pl_exec.c:3008
static int exec_stmt_rollback(PLpgSQL_execstate *estate, PLpgSQL_stmt_rollback *stmt)
Definition: pl_exec.c:4994
static int exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
Definition: pl_exec.c:3197
static int exec_stmt_exit(PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt)
Definition: pl_exec.c:3164
static int exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
Definition: pl_exec.c:3739
static int exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
Definition: pl_exec.c:2643
static int exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
Definition: pl_exec.c:4671
static int exec_stmt_dynexecute(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynexecute *stmt)
Definition: pl_exec.c:4454
static int exec_stmt_assert(PLpgSQL_execstate *estate, PLpgSQL_stmt_assert *stmt)
Definition: pl_exec.c:3950
static int exec_stmt_return_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_return_query *stmt)
Definition: pl_exec.c:3558
static int exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
Definition: pl_exec.c:2197
static int exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
Definition: pl_exec.c:2696
static int exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
Definition: pl_exec.c:2526
static int exec_stmt_case(PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
Definition: pl_exec.c:2556
static int exec_stmt_return_next(PLpgSQL_execstate *estate, PLpgSQL_stmt_return_next *stmt)
Definition: pl_exec.c:3340
static int exec_stmt_assign(PLpgSQL_execstate *estate, PLpgSQL_stmt_assign *stmt)
Definition: pl_exec.c:2164
static int exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
Definition: pl_exec.c:4644
static int exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
Definition: pl_exec.c:2410
static int exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
Definition: pl_exec.c:2665
static int exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
Definition: pl_exec.c:2180
static int exec_stmt_close(PLpgSQL_execstate *estate, PLpgSQL_stmt_close *stmt)
Definition: pl_exec.c:4927
PLpgSQL_plugin ** plpgsql_plugin_ptr
Definition: pl_handler.c:56
@ PLPGSQL_STMT_DYNFORS
Definition: plpgsql.h:122
@ PLPGSQL_STMT_FORI
Definition: plpgsql.h:110
@ PLPGSQL_STMT_FETCH
Definition: plpgsql.h:125
@ PLPGSQL_STMT_CASE
Definition: plpgsql.h:107
@ PLPGSQL_STMT_OPEN
Definition: plpgsql.h:124
@ PLPGSQL_STMT_ROLLBACK
Definition: plpgsql.h:130
@ PLPGSQL_STMT_COMMIT
Definition: plpgsql.h:129
@ PLPGSQL_STMT_RETURN_QUERY
Definition: plpgsql.h:117
@ PLPGSQL_STMT_RETURN
Definition: plpgsql.h:115
@ PLPGSQL_STMT_CLOSE
Definition: plpgsql.h:126
@ PLPGSQL_STMT_WHILE
Definition: plpgsql.h:109
@ PLPGSQL_STMT_BLOCK
Definition: plpgsql.h:104
@ PLPGSQL_STMT_FORS
Definition: plpgsql.h:111
@ PLPGSQL_STMT_FORC
Definition: plpgsql.h:112
@ PLPGSQL_STMT_IF
Definition: plpgsql.h:106
@ PLPGSQL_STMT_PERFORM
Definition: plpgsql.h:127
@ PLPGSQL_STMT_LOOP
Definition: plpgsql.h:108
@ PLPGSQL_STMT_ASSERT
Definition: plpgsql.h:119
@ PLPGSQL_STMT_FOREACH_A
Definition: plpgsql.h:113
@ PLPGSQL_STMT_GETDIAG
Definition: plpgsql.h:123
@ PLPGSQL_STMT_RETURN_NEXT
Definition: plpgsql.h:116
@ PLPGSQL_STMT_ASSIGN
Definition: plpgsql.h:105
@ PLPGSQL_STMT_EXIT
Definition: plpgsql.h:114
@ PLPGSQL_STMT_RAISE
Definition: plpgsql.h:118
@ PLPGSQL_STMT_CALL
Definition: plpgsql.h:128
@ PLPGSQL_STMT_DYNEXECUTE
Definition: plpgsql.h:121
PLpgSQL_stmt * err_stmt
Definition: plpgsql.h:1116
void(* stmt_end)(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
Definition: plpgsql.h:1166
void(* stmt_beg)(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
Definition: plpgsql.h:1165

References CHECK_FOR_INTERRUPTS, elog, PLpgSQL_execstate::err_stmt, ERROR, exec_stmt_assert(), exec_stmt_assign(), exec_stmt_block(), exec_stmt_call(), exec_stmt_case(), exec_stmt_close(), exec_stmt_commit(), exec_stmt_dynexecute(), exec_stmt_dynfors(), exec_stmt_execsql(), exec_stmt_exit(), exec_stmt_fetch(), exec_stmt_forc(), exec_stmt_foreach_a(), exec_stmt_fori(), exec_stmt_fors(), exec_stmt_getdiag(), exec_stmt_if(), exec_stmt_loop(), exec_stmt_open(), exec_stmt_perform(), exec_stmt_raise(), exec_stmt_return(), exec_stmt_return_next(), exec_stmt_return_query(), exec_stmt_rollback(), exec_stmt_while(), lfirst, NIL, plpgsql_plugin_ptr, PLPGSQL_RC_OK, PLPGSQL_STMT_ASSERT, PLPGSQL_STMT_ASSIGN, PLPGSQL_STMT_BLOCK, PLPGSQL_STMT_CALL, PLPGSQL_STMT_CASE, PLPGSQL_STMT_CLOSE, PLPGSQL_STMT_COMMIT, PLPGSQL_STMT_DYNEXECUTE, PLPGSQL_STMT_DYNFORS, PLPGSQL_STMT_EXECSQL, PLPGSQL_STMT_EXIT, PLPGSQL_STMT_FETCH, PLPGSQL_STMT_FORC, PLPGSQL_STMT_FOREACH_A, PLPGSQL_STMT_FORI, PLPGSQL_STMT_FORS, PLPGSQL_STMT_GETDIAG, PLPGSQL_STMT_IF, PLPGSQL_STMT_LOOP, PLPGSQL_STMT_OPEN, PLPGSQL_STMT_PERFORM, PLPGSQL_STMT_RAISE, PLPGSQL_STMT_RETURN, PLPGSQL_STMT_RETURN_NEXT, PLPGSQL_STMT_RETURN_QUERY, PLPGSQL_STMT_ROLLBACK, PLPGSQL_STMT_WHILE, stmt, PLpgSQL_plugin::stmt_beg, and PLpgSQL_plugin::stmt_end.

Referenced by exec_for_query(), exec_stmt_block(), exec_stmt_case(), exec_stmt_foreach_a(), exec_stmt_fori(), exec_stmt_if(), exec_stmt_loop(), and exec_stmt_while().

◆ exec_toplevel_block()

static int exec_toplevel_block ( PLpgSQL_execstate estate,
PLpgSQL_stmt_block block 
)
static

Definition at line 1634 of file pl_exec.c.

1635{
1636 int rc;
1637
1638 estate->err_stmt = (PLpgSQL_stmt *) block;
1639
1640 /* Let the plugin know that we are about to execute this statement */
1641 if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
1642 ((*plpgsql_plugin_ptr)->stmt_beg) (estate, (PLpgSQL_stmt *) block);
1643
1645
1646 rc = exec_stmt_block(estate, block);
1647
1648 /* Let the plugin know that we have finished executing this statement */
1649 if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
1650 ((*plpgsql_plugin_ptr)->stmt_end) (estate, (PLpgSQL_stmt *) block);
1651
1652 estate->err_stmt = NULL;
1653
1654 return rc;
1655}

References CHECK_FOR_INTERRUPTS, PLpgSQL_execstate::err_stmt, exec_stmt_block(), plpgsql_plugin_ptr, PLpgSQL_plugin::stmt_beg, and PLpgSQL_plugin::stmt_end.

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

◆ format_expr_params()

static char * format_expr_params ( PLpgSQL_execstate estate,
const PLpgSQL_expr expr 
)
static

Definition at line 9022 of file pl_exec.c.

9024{
9025 int paramno;
9026 int dno;
9027 StringInfoData paramstr;
9028 MemoryContext oldcontext;
9029
9030 if (!expr->paramnos)
9031 return NULL;
9032
9033 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
9034
9035 initStringInfo(&paramstr);
9036 paramno = 0;
9037 dno = -1;
9038 while ((dno = bms_next_member(expr->paramnos, dno)) >= 0)
9039 {
9040 Datum paramdatum;
9041 Oid paramtypeid;
9042 bool paramisnull;
9043 int32 paramtypmod;
9044 PLpgSQL_var *curvar;
9045
9046 curvar = (PLpgSQL_var *) estate->datums[dno];
9047
9048 exec_eval_datum(estate, (PLpgSQL_datum *) curvar,
9049 &paramtypeid, &paramtypmod,
9050 &paramdatum, &paramisnull);
9051
9052 appendStringInfo(&paramstr, "%s%s = ",
9053 paramno > 0 ? ", " : "",
9054 curvar->refname);
9055
9056 if (paramisnull)
9057 appendStringInfoString(&paramstr, "NULL");
9058 else
9061 paramdatum,
9062 paramtypeid),
9063 -1);
9064
9065 paramno++;
9066 }
9067
9068 MemoryContextSwitchTo(oldcontext);
9069
9070 return paramstr.data;
9071}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void appendStringInfoStringQuoted(StringInfo str, const char *s, int maxlen)
Definition: stringinfo_mb.c:34
Bitmapset * paramnos
Definition: plpgsql.h:251

References appendStringInfo(), appendStringInfoString(), appendStringInfoStringQuoted(), bms_next_member(), convert_value_to_string(), StringInfoData::data, PLpgSQL_execstate::datums, exec_eval_datum(), get_eval_mcontext, initStringInfo(), MemoryContextSwitchTo(), PLpgSQL_expr::paramnos, and PLpgSQL_var::refname.

Referenced by exec_stmt_execsql().

◆ format_preparedparamsdata()

static char * format_preparedparamsdata ( PLpgSQL_execstate estate,
ParamListInfo  paramLI 
)
static

Definition at line 9079 of file pl_exec.c.

9081{
9082 int paramno;
9083 StringInfoData paramstr;
9084 MemoryContext oldcontext;
9085
9086 if (!paramLI)
9087 return NULL;
9088
9089 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
9090
9091 initStringInfo(&paramstr);
9092 for (paramno = 0; paramno < paramLI->numParams; paramno++)
9093 {
9094 ParamExternData *prm = &paramLI->params[paramno];
9095
9096 /*
9097 * Note: for now, this is only used on ParamListInfos produced by
9098 * exec_eval_using_params(), so we don't worry about invoking the
9099 * paramFetch hook or skipping unused parameters.
9100 */
9101 appendStringInfo(&paramstr, "%s$%d = ",
9102 paramno > 0 ? ", " : "",
9103 paramno + 1);
9104
9105 if (prm->isnull)
9106 appendStringInfoString(&paramstr, "NULL");
9107 else
9110 prm->value,
9111 prm->ptype),
9112 -1);
9113 }
9114
9115 MemoryContextSwitchTo(oldcontext);
9116
9117 return paramstr.data;
9118}

References appendStringInfo(), appendStringInfoString(), appendStringInfoStringQuoted(), convert_value_to_string(), StringInfoData::data, get_eval_mcontext, initStringInfo(), ParamExternData::isnull, MemoryContextSwitchTo(), ParamListInfoData::numParams, ParamListInfoData::params, ParamExternData::ptype, and ParamExternData::value.

Referenced by exec_stmt_dynexecute().

◆ get_cast_hashentry()

static plpgsql_CastHashEntry * get_cast_hashentry ( PLpgSQL_execstate estate,
Oid  srctype,
int32  srctypmod,
Oid  dsttype,
int32  dsttypmod 
)
static

Definition at line 7952 of file pl_exec.c.

7955{
7956 plpgsql_CastHashKey cast_key;
7957 plpgsql_CastHashEntry *cast_entry;
7958 plpgsql_CastExprHashEntry *expr_entry;
7959 bool found;
7960 LocalTransactionId curlxid;
7961 MemoryContext oldcontext;
7962
7963 /* Look for existing entry */
7964 cast_key.srctype = srctype;
7965 cast_key.dsttype = dsttype;
7966 cast_key.srctypmod = srctypmod;
7967 cast_key.dsttypmod = dsttypmod;
7968 cast_entry = (plpgsql_CastHashEntry *) hash_search(estate->cast_hash,
7969 &cast_key,
7970 HASH_ENTER, &found);
7971 if (!found) /* initialize if new entry */
7972 {
7973 /* We need a second lookup to see if a cast_expr_hash entry exists */
7975 &cast_key,
7976 HASH_ENTER,
7977 &found);
7978 if (!found) /* initialize if new expr entry */
7979 expr_entry->cast_cexpr = NULL;
7980
7981 cast_entry->cast_centry = expr_entry;
7982 cast_entry->cast_exprstate = NULL;
7983 cast_entry->cast_in_use = false;
7985 }
7986 else
7987 {
7988 /* Use always-valid link to avoid a second hash lookup */
7989 expr_entry = cast_entry->cast_centry;
7990 }
7991
7992 if (expr_entry->cast_cexpr == NULL ||
7993 !expr_entry->cast_cexpr->is_valid)
7994 {
7995 /*
7996 * We've not looked up this coercion before, or we have but the cached
7997 * expression has been invalidated.
7998 */
7999 Node *cast_expr;
8000 CachedExpression *cast_cexpr;
8001 CaseTestExpr *placeholder;
8002
8003 /*
8004 * Drop old cached expression if there is one.
8005 */
8006 if (expr_entry->cast_cexpr)
8007 {
8008 FreeCachedExpression(expr_entry->cast_cexpr);
8009 expr_entry->cast_cexpr = NULL;
8010 }
8011
8012 /*
8013 * Since we could easily fail (no such coercion), construct a
8014 * temporary coercion expression tree in the short-lived
8015 * eval_mcontext, then if successful save it as a CachedExpression.
8016 */
8017 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
8018
8019 /*
8020 * We use a CaseTestExpr as the base of the coercion tree, since it's
8021 * very cheap to insert the source value for that.
8022 */
8023 placeholder = makeNode(CaseTestExpr);
8024 placeholder->typeId = srctype;
8025 placeholder->typeMod = srctypmod;
8026 placeholder->collation = get_typcollation(srctype);
8027
8028 /*
8029 * Apply coercion. We use the special coercion context
8030 * COERCION_PLPGSQL to match plpgsql's historical behavior, namely
8031 * that any cast not available at ASSIGNMENT level will be implemented
8032 * as an I/O coercion. (It's somewhat dubious that we prefer I/O
8033 * coercion over cast pathways that exist at EXPLICIT level. Changing
8034 * that would cause assorted minor behavioral differences though, and
8035 * a user who wants the explicit-cast behavior can always write an
8036 * explicit cast.)
8037 *
8038 * If source type is UNKNOWN, coerce_to_target_type will fail (it only
8039 * expects to see that for Const input nodes), so don't call it; we'll
8040 * apply CoerceViaIO instead. Likewise, it doesn't currently work for
8041 * coercing RECORD to some other type, so skip for that too.
8042 */
8043 if (srctype == UNKNOWNOID || srctype == RECORDOID)
8044 cast_expr = NULL;
8045 else
8046 cast_expr = coerce_to_target_type(NULL,
8047 (Node *) placeholder, srctype,
8048 dsttype, dsttypmod,
8051 -1);
8052
8053 /*
8054 * If there's no cast path according to the parser, fall back to using
8055 * an I/O coercion; this is semantically dubious but matches plpgsql's
8056 * historical behavior. We would need something of the sort for
8057 * UNKNOWN literals in any case. (This is probably now only reachable
8058 * in the case where srctype is UNKNOWN/RECORD.)
8059 */
8060 if (cast_expr == NULL)
8061 {
8062 CoerceViaIO *iocoerce = makeNode(CoerceViaIO);
8063
8064 iocoerce->arg = (Expr *) placeholder;
8065 iocoerce->resulttype = dsttype;
8066 iocoerce->resultcollid = InvalidOid;
8067 iocoerce->coerceformat = COERCE_IMPLICIT_CAST;
8068 iocoerce->location = -1;
8069 cast_expr = (Node *) iocoerce;
8070 if (dsttypmod != -1)
8071 cast_expr = coerce_to_target_type(NULL,
8072 cast_expr, dsttype,
8073 dsttype, dsttypmod,
8076 -1);
8077 }
8078
8079 /* Note: we don't bother labeling the expression tree with collation */
8080
8081 /* Plan the expression and build a CachedExpression */
8082 cast_cexpr = GetCachedExpression(cast_expr);
8083 cast_expr = cast_cexpr->expr;
8084
8085 /* Detect whether we have a no-op (RelabelType) coercion */
8086 if (IsA(cast_expr, RelabelType) &&
8087 ((RelabelType *) cast_expr)->arg == (Expr *) placeholder)
8088 cast_expr = NULL;
8089
8090 /* Now we can fill in the expression hashtable entry. */
8091 expr_entry->cast_cexpr = cast_cexpr;
8092 expr_entry->cast_expr = (Expr *) cast_expr;
8093
8094 /* Be sure to reset the exprstate hashtable entry, too. */
8095 cast_entry->cast_exprstate = NULL;
8096 cast_entry->cast_in_use = false;
8098
8099 MemoryContextSwitchTo(oldcontext);
8100 }
8101
8102 /* Done if we have determined that this is a no-op cast. */
8103 if (expr_entry->cast_expr == NULL)
8104 return NULL;
8105
8106 /*
8107 * Prepare the expression for execution, if it's not been done already in
8108 * the current transaction; also, if it's marked busy in the current
8109 * transaction, abandon that expression tree and build a new one, so as to
8110 * avoid potential problems with recursive cast expressions and failed
8111 * executions. (We will leak some memory intra-transaction if that
8112 * happens a lot, but we don't expect it to.) It's okay to update the
8113 * hash table with the new tree because all plpgsql functions within a
8114 * given transaction share the same simple_eval_estate. (Well, regular
8115 * functions do; DO blocks have private simple_eval_estates, and private
8116 * cast hash tables to go with them.)
8117 */
8118 curlxid = MyProc->vxid.lxid;
8119 if (cast_entry->cast_lxid != curlxid || cast_entry->cast_in_use)
8120 {
8122 cast_entry->cast_exprstate = ExecInitExpr(expr_entry->cast_expr, NULL);
8123 cast_entry->cast_in_use = false;
8124 cast_entry->cast_lxid = curlxid;
8125 MemoryContextSwitchTo(oldcontext);
8126 }
8127
8128 return cast_entry;
8129}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:143
@ HASH_ENTER
Definition: hsearch.h:114
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3139
#define makeNode(_type_)
Definition: nodes.h:161
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
void * arg
static HTAB * cast_expr_hash
Definition: pl_exec.c:178
void FreeCachedExpression(CachedExpression *cexpr)
Definition: plancache.c:1878
CachedExpression * GetCachedExpression(Node *expr)
Definition: plancache.c:1821
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:753
@ COERCION_PLPGSQL
Definition: primnodes.h:733
@ COERCION_ASSIGNMENT
Definition: primnodes.h:732
Expr * arg
Definition: primnodes.h:1224
ParseLoc location
Definition: primnodes.h:1231
Oid resulttype
Definition: primnodes.h:1225
HTAB * cast_hash
Definition: plpgsql.h:1104
CachedExpression * cast_cexpr
Definition: pl_exec.c:165
LocalTransactionId cast_lxid
Definition: pl_exec.c:175
plpgsql_CastExprHashEntry * cast_centry
Definition: pl_exec.c:171

References arg, CoerceViaIO::arg, plpgsql_CastHashEntry::cast_centry, plpgsql_CastExprHashEntry::cast_cexpr, plpgsql_CastExprHashEntry::cast_expr, cast_expr_hash, plpgsql_CastHashEntry::cast_exprstate, PLpgSQL_execstate::cast_hash, plpgsql_CastHashEntry::cast_in_use, plpgsql_CastHashEntry::cast_lxid, COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, COERCION_PLPGSQL, plpgsql_CastHashKey::dsttype, plpgsql_CastHashKey::dsttypmod, EState::es_query_cxt, ExecInitExpr(), CachedExpression::expr, FreeCachedExpression(), get_eval_mcontext, get_typcollation(), GetCachedExpression(), HASH_ENTER, hash_search(), InvalidLocalTransactionId, InvalidOid, CachedExpression::is_valid, IsA, CoerceViaIO::location, PGPROC::lxid, makeNode, MemoryContextSwitchTo(), MyProc, CoerceViaIO::resulttype, PLpgSQL_execstate::simple_eval_estate, plpgsql_CastHashKey::srctype, plpgsql_CastHashKey::srctypmod, CaseTestExpr::typeId, and PGPROC::vxid.

Referenced by do_cast_value().

◆ get_stmt_mcontext()

static MemoryContext get_stmt_mcontext ( PLpgSQL_execstate estate)
static

Definition at line 1544 of file pl_exec.c.

1545{
1546 if (estate->stmt_mcontext == NULL)
1547 {
1548 estate->stmt_mcontext =
1550 "PLpgSQL per-statement data",
1552 }
1553 return estate->stmt_mcontext;
1554}
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, PLpgSQL_execstate::stmt_mcontext, and PLpgSQL_execstate::stmt_mcontext_parent.

Referenced by exec_dynquery_with_params(), exec_eval_using_params(), exec_stmt_block(), exec_stmt_dynexecute(), exec_stmt_forc(), exec_stmt_foreach_a(), exec_stmt_open(), exec_stmt_raise(), and exec_stmt_return_query().

◆ instantiate_empty_record_variable()

static void instantiate_empty_record_variable ( PLpgSQL_execstate estate,
PLpgSQL_rec rec 
)
static

Definition at line 7820 of file pl_exec.c.

7821{
7822 Assert(rec->erh == NULL); /* else caller error */
7823
7824 /* If declared type is RECORD, we can't instantiate */
7825 if (rec->rectypeid == RECORDOID)
7826 ereport(ERROR,
7827 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7828 errmsg("record \"%s\" is not assigned yet", rec->refname),
7829 errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
7830
7831 /* Make sure rec->rectypeid is up-to-date before using it */
7833
7834 /* OK, do it */
7836 estate->datum_context);
7837}

References Assert(), PLpgSQL_execstate::datum_context, ereport, PLpgSQL_rec::erh, errcode(), errdetail(), errmsg(), ERROR, make_expanded_record_from_typeid(), PLpgSQL_rec::rectypeid, PLpgSQL_rec::refname, and revalidate_rectypeid().

Referenced by exec_assign_value(), exec_eval_datum(), exec_stmt_return_next(), plpgsql_exec_get_datum_type(), plpgsql_exec_get_datum_type_info(), and plpgsql_param_eval_recfield().

◆ make_callstmt_target()

static PLpgSQL_variable * make_callstmt_target ( PLpgSQL_execstate estate,
PLpgSQL_expr expr 
)
static

Definition at line 2289 of file pl_exec.c.

2290{
2291 CachedPlan *cplan;
2292 PlannedStmt *pstmt;
2293 CallStmt *stmt;
2294 FuncExpr *funcexpr;
2295 HeapTuple func_tuple;
2296 Oid *argtypes;
2297 char **argnames;
2298 char *argmodes;
2299 int numargs;
2300 MemoryContext oldcontext;
2301 PLpgSQL_row *row;
2302 int nfields;
2303 int i;
2304
2305 /* Use eval_mcontext for any cruft accumulated here */
2306 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
2307
2308 /*
2309 * Get the parsed CallStmt, and look up the called procedure. We use
2310 * SPI_plan_get_cached_plan to cover the edge case where expr->plan is
2311 * already stale and needs to be updated.
2312 */
2313 cplan = SPI_plan_get_cached_plan(expr->plan);
2314 if (cplan == NULL || list_length(cplan->stmt_list) != 1)
2315 elog(ERROR, "query for CALL statement is not a CallStmt");
2316 pstmt = linitial_node(PlannedStmt, cplan->stmt_list);
2317 stmt = (CallStmt *) pstmt->utilityStmt;
2318 if (stmt == NULL || !IsA(stmt, CallStmt))
2319 elog(ERROR, "query for CALL statement is not a CallStmt");
2320
2321 funcexpr = stmt->funcexpr;
2322
2323 func_tuple = SearchSysCache1(PROCOID,
2324 ObjectIdGetDatum(funcexpr->funcid));
2325 if (!HeapTupleIsValid(func_tuple))
2326 elog(ERROR, "cache lookup failed for function %u",
2327 funcexpr->funcid);
2328
2329 /*
2330 * Get the argument names and modes, so that we can deliver on-point error
2331 * messages when something is wrong.
2332 */
2333 numargs = get_func_arg_info(func_tuple, &argtypes, &argnames, &argmodes);
2334
2335 ReleaseSysCache(func_tuple);
2336
2337 /*
2338 * Begin constructing row Datum; keep it in fn_cxt so it's adequately
2339 * long-lived.
2340 */
2342
2343 row = (PLpgSQL_row *) palloc0(sizeof(PLpgSQL_row));
2344 row->dtype = PLPGSQL_DTYPE_ROW;
2345 row->refname = "(unnamed row)";
2346 row->lineno = -1;
2347 row->varnos = (int *) palloc(numargs * sizeof(int));
2348
2350
2351 /*
2352 * Examine procedure's argument list. Each output arg position should be
2353 * an unadorned plpgsql variable (Datum), which we can insert into the row
2354 * Datum.
2355 */
2356 nfields = 0;
2357 for (i = 0; i < numargs; i++)
2358 {
2359 if (argmodes &&
2360 (argmodes[i] == PROARGMODE_INOUT ||
2361 argmodes[i] == PROARGMODE_OUT))
2362 {
2363 Node *n = list_nth(stmt->outargs, nfields);
2364
2365 if (IsA(n, Param))
2366 {
2367 Param *param = (Param *) n;
2368 int dno;
2369
2370 /* paramid is offset by 1 (see make_datum_param()) */
2371 dno = param->paramid - 1;
2372 /* must check assignability now, because grammar can't */
2373 exec_check_assignable(estate, dno);
2374 row->varnos[nfields++] = dno;
2375 }
2376 else
2377 {
2378 /* report error using parameter name, if available */
2379 if (argnames && argnames[i] && argnames[i][0])
2380 ereport(ERROR,
2381 (errcode(ERRCODE_SYNTAX_ERROR),
2382 errmsg("procedure parameter \"%s\" is an output parameter but corresponding argument is not writable",
2383 argnames[i])));
2384 else
2385 ereport(ERROR,
2386 (errcode(ERRCODE_SYNTAX_ERROR),
2387 errmsg("procedure parameter %d is an output parameter but corresponding argument is not writable",
2388 i + 1)));
2389 }
2390 }
2391 }
2392
2393 Assert(nfields == list_length(stmt->outargs));
2394
2395 row->nfields = nfields;
2396
2398
2399 MemoryContextSwitchTo(oldcontext);
2400
2401 return (PLpgSQL_variable *) row;
2402}
int get_func_arg_info(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
Definition: funcapi.c:1379
void * palloc0(Size size)
Definition: mcxt.c:1347
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
MemoryContext fn_cxt
Definition: plpgsql.h:1000
int lineno
Definition: plpgsql.h:390
PLpgSQL_datum_type dtype
Definition: plpgsql.h:387
char * refname
Definition: plpgsql.h:389
Node * utilityStmt
Definition: plannodes.h:139
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

References Assert(), CurrentResourceOwner, PLpgSQL_row::dtype, elog, ereport, errcode(), errmsg(), ERROR, exec_check_assignable(), PLpgSQL_function::fn_cxt, PLpgSQL_execstate::func, FuncExpr::funcid, get_eval_mcontext, get_func_arg_info(), HeapTupleIsValid, i, if(), IsA, PLpgSQL_row::lineno, linitial_node, list_length(), list_nth(), MemoryContextSwitchTo(), PLpgSQL_row::nfields, ObjectIdGetDatum(), palloc(), palloc0(), Param::paramid, PLpgSQL_expr::plan, PLPGSQL_DTYPE_ROW, PLpgSQL_row::refname, ReleaseCachedPlan(), ReleaseSysCache(), SearchSysCache1(), SPI_plan_get_cached_plan(), stmt, CachedPlan::stmt_list, PlannedStmt::utilityStmt, and PLpgSQL_row::varnos.

Referenced by exec_stmt_call().

◆ make_expanded_record_for_rec()

static ExpandedRecordHeader * make_expanded_record_for_rec ( PLpgSQL_execstate estate,
PLpgSQL_rec rec,
TupleDesc  srctupdesc,
ExpandedRecordHeader srcerh 
)
static

Definition at line 7128 of file pl_exec.c.

7132{
7133 ExpandedRecordHeader *newerh;
7134 MemoryContext mcontext = get_eval_mcontext(estate);
7135
7136 if (rec->rectypeid != RECORDOID)
7137 {
7138 /*
7139 * Make sure rec->rectypeid is up-to-date before using it.
7140 */
7142
7143 /*
7144 * New record must be of desired type, but maybe srcerh has already
7145 * done all the same lookups.
7146 */
7147 if (srcerh && rec->rectypeid == srcerh->er_decltypeid)
7149 mcontext);
7150 else
7152 mcontext);
7153 }
7154 else
7155 {
7156 /*
7157 * We'll adopt the input tupdesc. We can still use
7158 * make_expanded_record_from_exprecord, if srcerh isn't a composite
7159 * domain. (If it is, we effectively adopt its base type.)
7160 */
7161 if (srcerh && !ExpandedRecordIsDomain(srcerh))
7163 mcontext);
7164 else
7165 {
7166 if (!srctupdesc)
7167 srctupdesc = expanded_record_get_tupdesc(srcerh);
7168 newerh = make_expanded_record_from_tupdesc(srctupdesc,
7169 mcontext);
7170 }
7171 }
7172
7173 return newerh;
7174}
ExpandedRecordHeader * make_expanded_record_from_exprecord(ExpandedRecordHeader *olderh, MemoryContext parentcontext)
ExpandedRecordHeader * make_expanded_record_from_tupdesc(TupleDesc tupdesc, MemoryContext parentcontext)

References ExpandedRecordHeader::er_decltypeid, expanded_record_get_tupdesc(), ExpandedRecordIsDomain, get_eval_mcontext, make_expanded_record_from_exprecord(), make_expanded_record_from_tupdesc(), make_expanded_record_from_typeid(), PLpgSQL_rec::rectypeid, and revalidate_rectypeid().

Referenced by exec_move_row(), and exec_move_row_from_datum().

◆ make_tuple_from_row()

static HeapTuple make_tuple_from_row ( PLpgSQL_execstate estate,
PLpgSQL_row row,
TupleDesc  tupdesc 
)
static

Definition at line 7501 of file pl_exec.c.

7504{
7505 int natts = tupdesc->natts;
7506 HeapTuple tuple;
7507 Datum *dvalues;
7508 bool *nulls;
7509 int i;
7510
7511 if (natts != row->nfields)
7512 return NULL;
7513
7514 dvalues = (Datum *) eval_mcontext_alloc0(estate, natts * sizeof(Datum));
7515 nulls = (bool *) eval_mcontext_alloc(estate, natts * sizeof(bool));
7516
7517 for (i = 0; i < natts; i++)
7518 {
7519 Oid fieldtypeid;
7520 int32 fieldtypmod;
7521
7522 if (TupleDescAttr(tupdesc, i)->attisdropped)
7523 {
7524 nulls[i] = true; /* leave the column as null */
7525 continue;
7526 }
7527
7528 exec_eval_datum(estate, estate->datums[row->varnos[i]],
7529 &fieldtypeid, &fieldtypmod,
7530 &dvalues[i], &nulls[i]);
7531 if (fieldtypeid != TupleDescAttr(tupdesc, i)->atttypid)
7532 return NULL;
7533 /* XXX should we insist on typmod match, too? */
7534 }
7535
7536 tuple = heap_form_tuple(tupdesc, dvalues, nulls);
7537
7538 return tuple;
7539}
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117

References PLpgSQL_execstate::datums, eval_mcontext_alloc, eval_mcontext_alloc0, exec_eval_datum(), heap_form_tuple(), i, TupleDescData::natts, PLpgSQL_row::nfields, TupleDescAttr(), and PLpgSQL_row::varnos.

Referenced by exec_eval_datum(), and exec_stmt_return_next().

◆ plpgsql_create_econtext()

static void plpgsql_create_econtext ( PLpgSQL_execstate estate)
static

Definition at line 8620 of file pl_exec.c.

8621{
8623
8624 /*
8625 * Create an EState for evaluation of simple expressions, if there's not
8626 * one already in the current transaction. The EState is made a child of
8627 * TopTransactionContext so it will have the right lifespan.
8628 *
8629 * Note that this path is never taken when beginning a DO block; the
8630 * required EState was already made by plpgsql_inline_handler. However,
8631 * if the DO block executes COMMIT or ROLLBACK, then we'll come here and
8632 * make a shared EState to use for the rest of the DO block. That's OK;
8633 * see the comments for shared_simple_eval_estate. (Note also that a DO
8634 * block will continue to use its private cast hash table for the rest of
8635 * the block. That's okay for now, but it might cause problems someday.)
8636 */
8637 if (estate->simple_eval_estate == NULL)
8638 {
8639 MemoryContext oldcontext;
8640
8641 if (shared_simple_eval_estate == NULL)
8642 {
8645 MemoryContextSwitchTo(oldcontext);
8646 }
8648 }
8649
8650 /*
8651 * Likewise for the simple-expression resource owner.
8652 */
8653 if (estate->simple_eval_resowner == NULL)
8654 {
8655 if (shared_simple_eval_resowner == NULL)
8658 "PL/pgSQL simple expressions");
8660 }
8661
8662 /*
8663 * Create a child econtext for the current function.
8664 */
8666
8667 /*
8668 * Make a stack entry so we can clean up the econtext at subxact end.
8669 * Stack entries are kept in TopTransactionContext for simplicity.
8670 */
8671 entry = (SimpleEcontextStackEntry *)
8673 sizeof(SimpleEcontextStackEntry));
8674
8675 entry->stack_econtext = estate->eval_econtext;
8677
8678 entry->next = simple_econtext_stack;
8679 simple_econtext_stack = entry;
8680}
ExprContext * CreateExprContext(EState *estate)
Definition: execUtils.c:308
EState * CreateExecutorState(void)
Definition: execUtils.c:88
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
MemoryContext TopTransactionContext
Definition: mcxt.c:154
static ResourceOwner shared_simple_eval_resowner
Definition: pl_exec.c:102
static EState * shared_simple_eval_estate
Definition: pl_exec.c:91
static SimpleEcontextStackEntry * simple_econtext_stack
Definition: pl_exec.c:92
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:175
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition: resowner.c:421
struct SimpleEcontextStackEntry * next
Definition: pl_exec.c:88
ExprContext * stack_econtext
Definition: pl_exec.c:86
SubTransactionId xact_subxid
Definition: pl_exec.c:87
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:791

References CreateExecutorState(), CreateExprContext(), PLpgSQL_execstate::eval_econtext, GetCurrentSubTransactionId(), MemoryContextAlloc(), MemoryContextSwitchTo(), SimpleEcontextStackEntry::next, ResourceOwnerCreate(), shared_simple_eval_estate, shared_simple_eval_resowner, simple_econtext_stack, PLpgSQL_execstate::simple_eval_estate, PLpgSQL_execstate::simple_eval_resowner, SimpleEcontextStackEntry::stack_econtext, TopTransactionContext, TopTransactionResourceOwner, and SimpleEcontextStackEntry::xact_subxid.

Referenced by exec_stmt_block(), exec_stmt_call(), exec_stmt_commit(), exec_stmt_rollback(), and plpgsql_estate_setup().

◆ plpgsql_destroy_econtext()

static void plpgsql_destroy_econtext ( PLpgSQL_execstate estate)
static

◆ plpgsql_estate_setup()

static void plpgsql_estate_setup ( PLpgSQL_execstate estate,
PLpgSQL_function func,
ReturnSetInfo rsi,
EState simple_eval_estate,
ResourceOwner  simple_eval_resowner 
)
static

Definition at line 3993 of file pl_exec.c.

3998{
3999 HASHCTL ctl;
4000
4001 /* this link will be restored at exit from plpgsql_call_handler */
4002 func->cur_estate = estate;
4003
4004 estate->func = func;
4005 estate->trigdata = NULL;
4006 estate->evtrigdata = NULL;
4007
4008 estate->retval = (Datum) 0;
4009 estate->retisnull = true;
4010 estate->rettype = InvalidOid;
4011
4012 estate->fn_rettype = func->fn_rettype;
4013 estate->retistuple = func->fn_retistuple;
4014 estate->retisset = func->fn_retset;
4015
4016 estate->readonly_func = func->fn_readonly;
4017 estate->atomic = true;
4018
4019 estate->exitlabel = NULL;
4020 estate->cur_error = NULL;
4021
4022 estate->tuple_store = NULL;
4023 estate->tuple_store_desc = NULL;
4024 if (rsi)
4025 {
4028 }
4029 else
4030 {
4031 estate->tuple_store_cxt = NULL;
4032 estate->tuple_store_owner = NULL;
4033 }
4034 estate->rsi = rsi;
4035
4036 estate->found_varno = func->found_varno;
4037 estate->ndatums = func->ndatums;
4038 estate->datums = NULL;
4039 /* the datums array will be filled by copy_plpgsql_datums() */
4041
4042 /* initialize our ParamListInfo with appropriate hook functions */
4043 estate->paramLI = makeParamList(0);
4045 estate->paramLI->paramFetchArg = estate;
4047 estate->paramLI->paramCompileArg = NULL; /* not needed */
4049 estate->paramLI->parserSetupArg = NULL; /* filled during use */
4050 estate->paramLI->numParams = estate->ndatums;
4051
4052 /* Create the session-wide cast-expression hash if we didn't already */
4053 if (cast_expr_hash == NULL)
4054 {
4055 ctl.keysize = sizeof(plpgsql_CastHashKey);
4056 ctl.entrysize = sizeof(plpgsql_CastExprHashEntry);
4057 cast_expr_hash = hash_create("PLpgSQL cast expressions",
4058 16, /* start small and extend */
4059 &ctl,
4061 }
4062
4063 /* set up for use of appropriate simple-expression EState and cast hash */
4064 if (simple_eval_estate)
4065 {
4066 estate->simple_eval_estate = simple_eval_estate;
4067 /* Private cast hash just lives in function's main context */
4068 ctl.keysize = sizeof(plpgsql_CastHashKey);
4069 ctl.entrysize = sizeof(plpgsql_CastHashEntry);
4071 estate->cast_hash = hash_create("PLpgSQL private cast cache",
4072 16, /* start small and extend */
4073 &ctl,
4075 }
4076 else
4077 {
4079 /* Create the session-wide cast-info hash table if we didn't already */
4080 if (shared_cast_hash == NULL)
4081 {
4082 ctl.keysize = sizeof(plpgsql_CastHashKey);
4083 ctl.entrysize = sizeof(plpgsql_CastHashEntry);
4084 shared_cast_hash = hash_create("PLpgSQL cast cache",
4085 16, /* start small and extend */
4086 &ctl,
4088 }
4089 estate->cast_hash = shared_cast_hash;
4090 }
4091 /* likewise for the simple-expression resource owner */
4092 if (simple_eval_resowner)
4093 estate->simple_eval_resowner = simple_eval_resowner;
4094 else
4096
4097 /* if there's a procedure resowner, it'll be filled in later */
4098 estate->procedure_resowner = NULL;
4099
4100 /*
4101 * We start with no stmt_mcontext; one will be created only if needed.
4102 * That context will be a direct child of the function's main execution
4103 * context. Additional stmt_mcontexts might be created as children of it.
4104 */
4105 estate->stmt_mcontext = NULL;
4107
4108 estate->eval_tuptable = NULL;
4109 estate->eval_processed = 0;
4110 estate->eval_econtext = NULL;
4111
4112 estate->err_stmt = NULL;
4113 estate->err_var = NULL;
4114 estate->err_text = NULL;
4115
4116 estate->plugin_info = NULL;
4117
4118 /*
4119 * Create an EState and ExprContext for evaluation of simple expressions.
4120 */
4122
4123 /*
4124 * Let the plugin, if any, see this function before we initialize local
4125 * PL/pgSQL variables. Note that we also give the plugin a few function
4126 * pointers, so it can call back into PL/pgSQL for doing things like
4127 * variable assignments and stack traces.
4128 */
4129 if (*plpgsql_plugin_ptr)
4130 {
4131 (*plpgsql_plugin_ptr)->error_callback = plpgsql_exec_error_callback;
4132 (*plpgsql_plugin_ptr)->assign_expr = exec_assign_expr;
4133 (*plpgsql_plugin_ptr)->assign_value = exec_assign_value;
4134 (*plpgsql_plugin_ptr)->eval_datum = exec_eval_datum;
4135 (*plpgsql_plugin_ptr)->cast_value = exec_cast_value;
4136
4137 if ((*plpgsql_plugin_ptr)->func_setup)
4138 ((*plpgsql_plugin_ptr)->func_setup) (estate, func);
4139 }
4140}
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
static ParamExternData * plpgsql_param_fetch(ParamListInfo params, int paramid, bool speculative, ParamExternData *prm)
Definition: pl_exec.c:6308
static HTAB * shared_cast_hash
Definition: pl_exec.c:179
static void plpgsql_exec_error_callback(void *arg)
Definition: pl_exec.c:1243
static void plpgsql_param_compile(ParamListInfo params, Param *param, ExprState *state, Datum *resv, bool *resnull)
Definition: pl_exec.c:6435
tree ctl
Definition: radixtree.h:1838
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:275
TriggerData * trigdata
Definition: plpgsql.h:1051
EventTriggerData * evtrigdata
Definition: plpgsql.h:1052
void * plugin_info
Definition: plpgsql.h:1120
bool fn_retistuple
Definition: plpgsql.h:1005
struct PLpgSQL_execstate * cur_estate
Definition: plpgsql.h:1040
ParserSetupHook parserSetup
Definition: params.h:116
ParamCompileHook paramCompile
Definition: params.h:114
void * paramCompileArg
Definition: params.h:115
ParamFetchHook paramFetch
Definition: params.h:112
void * paramFetchArg
Definition: params.h:113
ExprContext * econtext
Definition: execnodes.h:351

References PLpgSQL_execstate::atomic, cast_expr_hash, PLpgSQL_execstate::cast_hash, ctl, PLpgSQL_execstate::cur_error, PLpgSQL_function::cur_estate, CurrentMemoryContext, CurrentResourceOwner, PLpgSQL_execstate::datum_context, PLpgSQL_execstate::datums, ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, PLpgSQL_execstate::err_stmt, PLpgSQL_execstate::err_text, PLpgSQL_execstate::err_var, PLpgSQL_execstate::eval_econtext, PLpgSQL_execstate::eval_processed, PLpgSQL_execstate::eval_tuptable, PLpgSQL_execstate::evtrigdata, exec_assign_expr(), exec_assign_value(), exec_cast_value(), exec_eval_datum(), PLpgSQL_execstate::exitlabel, PLpgSQL_function::fn_readonly, PLpgSQL_function::fn_retistuple, PLpgSQL_function::fn_retset, PLpgSQL_function::fn_rettype, PLpgSQL_execstate::fn_rettype, PLpgSQL_function::found_varno, PLpgSQL_execstate::found_varno, PLpgSQL_execstate::func, HASH_BLOBS, HASH_CONTEXT, hash_create(), HASH_ELEM, InvalidOid, makeParamList(), PLpgSQL_function::ndatums, PLpgSQL_execstate::ndatums, ParamListInfoData::numParams, ParamListInfoData::paramCompile, ParamListInfoData::paramCompileArg, ParamListInfoData::paramFetch, ParamListInfoData::paramFetchArg, PLpgSQL_execstate::paramLI, ParamListInfoData::parserSetup, ParamListInfoData::parserSetupArg, plpgsql_create_econtext(), plpgsql_exec_error_callback(), plpgsql_param_compile(), plpgsql_param_fetch(), plpgsql_parser_setup(), plpgsql_plugin_ptr, PLpgSQL_execstate::plugin_info, PLpgSQL_execstate::procedure_resowner, PLpgSQL_execstate::readonly_func, PLpgSQL_execstate::retisnull, PLpgSQL_execstate::retisset, PLpgSQL_execstate::retistuple, PLpgSQL_execstate::rettype, PLpgSQL_execstate::retval, PLpgSQL_execstate::rsi, shared_cast_hash, shared_simple_eval_estate, shared_simple_eval_resowner, PLpgSQL_execstate::simple_eval_estate, PLpgSQL_execstate::simple_eval_resowner, PLpgSQL_execstate::stmt_mcontext, PLpgSQL_execstate::stmt_mcontext_parent, PLpgSQL_execstate::trigdata, PLpgSQL_execstate::tuple_store, PLpgSQL_execstate::tuple_store_cxt, PLpgSQL_execstate::tuple_store_desc, and PLpgSQL_execstate::tuple_store_owner.

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

◆ plpgsql_exec_error_callback()

static void plpgsql_exec_error_callback ( void *  arg)
static

Definition at line 1243 of file pl_exec.c.

1244{
1246 int err_lineno;
1247
1248 /*
1249 * If err_var is set, report the variable's declaration line number.
1250 * Otherwise, if err_stmt is set, report the err_stmt's line number. When
1251 * err_stmt is not set, we're in function entry/exit, or some such place
1252 * not attached to a specific line number.
1253 */
1254 if (estate->err_var != NULL)
1255 err_lineno = estate->err_var->lineno;
1256 else if (estate->err_stmt != NULL)
1257 err_lineno = estate->err_stmt->lineno;
1258 else
1259 err_lineno = 0;
1260
1261 if (estate->err_text != NULL)
1262 {
1263 /*
1264 * We don't expend the cycles to run gettext() on err_text unless we
1265 * actually need it. Therefore, places that set up err_text should
1266 * use gettext_noop() to ensure the strings get recorded in the
1267 * message dictionary.
1268 */
1269 if (err_lineno > 0)
1270 {
1271 /*
1272 * translator: last %s is a phrase such as "during statement block
1273 * local variable initialization"
1274 */
1275 errcontext("PL/pgSQL function %s line %d %s",
1276 estate->func->fn_signature,
1277 err_lineno,
1278 _(estate->err_text));
1279 }
1280 else
1281 {
1282 /*
1283 * translator: last %s is a phrase such as "while storing call
1284 * arguments into local variables"
1285 */
1286 errcontext("PL/pgSQL function %s %s",
1287 estate->func->fn_signature,
1288 _(estate->err_text));
1289 }
1290 }
1291 else if (estate->err_stmt != NULL && err_lineno > 0)
1292 {
1293 /* translator: last %s is a plpgsql statement type name */
1294 errcontext("PL/pgSQL function %s line %d at %s",
1295 estate->func->fn_signature,
1296 err_lineno,
1298 }
1299 else
1300 errcontext("PL/pgSQL function %s",
1301 estate->func->fn_signature);
1302}
#define _(x)
Definition: elog.c:90
const char * plpgsql_stmt_typename(PLpgSQL_stmt *stmt)
Definition: pl_funcs.c:232
char * fn_signature
Definition: plpgsql.h:993
int lineno
Definition: plpgsql.h:478

References _, arg, PLpgSQL_execstate::err_stmt, PLpgSQL_execstate::err_text, PLpgSQL_execstate::err_var, errcontext, PLpgSQL_function::fn_signature, PLpgSQL_execstate::func, PLpgSQL_variable::lineno, PLpgSQL_stmt::lineno, and plpgsql_stmt_typename().

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

◆ plpgsql_exec_event_trigger()

void plpgsql_exec_event_trigger ( PLpgSQL_function func,
EventTriggerData trigdata 
)

Definition at line 1175 of file pl_exec.c.

1176{
1177 PLpgSQL_execstate estate;
1178 ErrorContextCallback plerrcontext;
1179 int rc;
1180
1181 /*
1182 * Setup the execution state
1183 */
1184 plpgsql_estate_setup(&estate, func, NULL, NULL, NULL);
1185 estate.evtrigdata = trigdata;
1186
1187 /*
1188 * Setup error traceback support for ereport()
1189 */
1191 plerrcontext.arg = &estate;
1192 plerrcontext.previous = error_context_stack;
1193 error_context_stack = &plerrcontext;
1194
1195 /*
1196 * Make local execution copies of all the datums
1197 */
1198 estate.err_text = gettext_noop("during initialization of execution state");
1199 copy_plpgsql_datums(&estate, func);
1200
1201 /*
1202 * Let the instrumentation plugin peek at this function
1203 */
1204 if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_beg)
1205 ((*plpgsql_plugin_ptr)->func_beg) (&estate, func);
1206
1207 /*
1208 * Now call the toplevel block of statements
1209 */
1210 estate.err_text = NULL;
1211 rc = exec_toplevel_block(&estate, func->action);
1212 if (rc != PLPGSQL_RC_RETURN)
1213 {
1214 estate.err_text = NULL;
1215 ereport(ERROR,
1216 (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
1217 errmsg("control reached end of trigger procedure without RETURN")));
1218 }
1219
1220 estate.err_text = gettext_noop("during function exit");
1221
1222 /*
1223 * Let the instrumentation plugin peek at this function
1224 */
1225 if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_end)
1226 ((*plpgsql_plugin_ptr)->func_end) (&estate, func);
1227
1228 /* Clean up any leftover temporary memory */
1229 plpgsql_destroy_econtext(&estate);
1230 exec_eval_cleanup(&estate);
1231 /* stmt_mcontext will be destroyed when function's main context is */
1232
1233 /*
1234 * Pop the error context stack
1235 */
1236 error_context_stack = plerrcontext.previous;
1237}
ErrorContextCallback * error_context_stack
Definition: elog.c:94
static void plpgsql_estate_setup(PLpgSQL_execstate *estate, PLpgSQL_function *func, ReturnSetInfo *rsi, EState *simple_eval_estate, ResourceOwner simple_eval_resowner)
Definition: pl_exec.c:3993
static int exec_toplevel_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
Definition: pl_exec.c:1634
static void plpgsql_destroy_econtext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:8689
static void copy_plpgsql_datums(PLpgSQL_execstate *estate, PLpgSQL_function *func)
Definition: pl_exec.c:1310
struct ErrorContextCallback * previous
Definition: elog.h:296
void(* callback)(void *arg)
Definition: elog.h:297
PLpgSQL_stmt_block * action
Definition: plpgsql.h:1032
void(* func_beg)(PLpgSQL_execstate *estate, PLpgSQL_function *func)
Definition: plpgsql.h:1163
void(* func_end)(PLpgSQL_execstate *estate, PLpgSQL_function *func)
Definition: plpgsql.h:1164

References PLpgSQL_function::action, ErrorContextCallback::arg, ErrorContextCallback::callback, copy_plpgsql_datums(), ereport, PLpgSQL_execstate::err_text, errcode(), errmsg(), ERROR, error_context_stack, PLpgSQL_execstate::evtrigdata, exec_eval_cleanup(), exec_toplevel_block(), PLpgSQL_plugin::func_beg, PLpgSQL_plugin::func_end, gettext_noop, plpgsql_destroy_econtext(), plpgsql_estate_setup(), plpgsql_exec_error_callback(), plpgsql_plugin_ptr, PLPGSQL_RC_RETURN, and ErrorContextCallback::previous.

Referenced by plpgsql_call_handler().

◆ plpgsql_exec_function()

Datum plpgsql_exec_function ( PLpgSQL_function func,
FunctionCallInfo  fcinfo,
EState simple_eval_estate,
ResourceOwner  simple_eval_resowner,
ResourceOwner  procedure_resowner,
bool  atomic 
)

Definition at line 493 of file pl_exec.c.

498{
499 PLpgSQL_execstate estate;
500 ErrorContextCallback plerrcontext;
501 int i;
502 int rc;
503
504 /*
505 * Setup the execution state
506 */
507 plpgsql_estate_setup(&estate, func, (ReturnSetInfo *) fcinfo->resultinfo,
508 simple_eval_estate, simple_eval_resowner);
509 estate.procedure_resowner = procedure_resowner;
510 estate.atomic = atomic;
511
512 /*
513 * Setup error traceback support for ereport()
514 */
516 plerrcontext.arg = &estate;
517 plerrcontext.previous = error_context_stack;
518 error_context_stack = &plerrcontext;
519
520 /*
521 * Make local execution copies of all the datums
522 */
523 estate.err_text = gettext_noop("during initialization of execution state");
524 copy_plpgsql_datums(&estate, func);
525
526 /*
527 * Store the actual call argument values into the appropriate variables
528 */
529 estate.err_text = gettext_noop("while storing call arguments into local variables");
530 for (i = 0; i < func->fn_nargs; i++)
531 {
532 int n = func->fn_argvarnos[i];
533
534 switch (estate.datums[n]->dtype)
535 {
537 {
538 PLpgSQL_var *var = (PLpgSQL_var *) estate.datums[n];
539
540 assign_simple_var(&estate, var,
541 fcinfo->args[i].value,
542 fcinfo->args[i].isnull,
543 false);
544
545 /*
546 * If it's a varlena type, check to see if we received a
547 * R/W expanded-object pointer. If so, we can commandeer
548 * the object rather than having to copy it. If passed a
549 * R/O expanded pointer, just keep it as the value of the
550 * variable for the moment. (We can change it to R/W if
551 * the variable gets modified, but that may very well
552 * never happen.)
553 *
554 * Also, force any flat array value to be stored in
555 * expanded form in our local variable, in hopes of
556 * improving efficiency of uses of the variable. (This is
557 * a hack, really: why only arrays? Need more thought
558 * about which cases are likely to win. See also
559 * typisarray-specific heuristic in exec_assign_value.)
560 */
561 if (!var->isnull && var->datatype->typlen == -1)
562 {
564 {
565 /* take ownership of R/W object */
566 assign_simple_var(&estate, var,
568 estate.datum_context),
569 false,
570 true);
571 }
573 {
574 /* R/O pointer, keep it as-is until assigned to */
575 }
576 else if (var->datatype->typisarray)
577 {
578 /* flat array, so force to expanded form */
579 assign_simple_var(&estate, var,
580 expand_array(var->value,
581 estate.datum_context,
582 NULL),
583 false,
584 true);
585 }
586 }
587 }
588 break;
589
591 {
592 PLpgSQL_rec *rec = (PLpgSQL_rec *) estate.datums[n];
593
594 if (!fcinfo->args[i].isnull)
595 {
596 /* Assign row value from composite datum */
598 (PLpgSQL_variable *) rec,
599 fcinfo->args[i].value);
600 }
601 else
602 {
603 /* If arg is null, set variable to null */
604 exec_move_row(&estate, (PLpgSQL_variable *) rec,
605 NULL, NULL);
606 }
607 /* clean up after exec_move_row() */
608 exec_eval_cleanup(&estate);
609 }
610 break;
611
612 default:
613 /* Anything else should not be an argument variable */
614 elog(ERROR, "unrecognized dtype: %d", func->datums[i]->dtype);
615 }
616 }
617
618 estate.err_text = gettext_noop("during function entry");
619
620 /*
621 * Set the magic variable FOUND to false
622 */
623 exec_set_found(&estate, false);
624
625 /*
626 * Let the instrumentation plugin peek at this function
627 */
628 if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_beg)
629 ((*plpgsql_plugin_ptr)->func_beg) (&estate, func);
630
631 /*
632 * Now call the toplevel block of statements
633 */
634 estate.err_text = NULL;
635 rc = exec_toplevel_block(&estate, func->action);
636 if (rc != PLPGSQL_RC_RETURN)
637 {
638 estate.err_text = NULL;
640 (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
641 errmsg("control reached end of function without RETURN")));
642 }
643
644 /*
645 * We got a return value - process it
646 */
647 estate.err_text = gettext_noop("while casting return value to function's return type");
648
649 fcinfo->isnull = estate.retisnull;
650
651 if (estate.retisset)
652 {
653 ReturnSetInfo *rsi = estate.rsi;
654
655 /* Check caller can handle a set result */
656 if (!rsi || !IsA(rsi, ReturnSetInfo))
658 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
659 errmsg("set-valued function called in context that cannot accept a set")));
660
661 if (!(rsi->allowedModes & SFRM_Materialize))
663 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
664 errmsg("materialize mode required, but it is not allowed in this context")));
665
667
668 /* If we produced any tuples, send back the result */
669 if (estate.tuple_store)
670 {
671 MemoryContext oldcxt;
672
673 rsi->setResult = estate.tuple_store;
674 oldcxt = MemoryContextSwitchTo(estate.tuple_store_cxt);
676 MemoryContextSwitchTo(oldcxt);
677 }
678 estate.retval = (Datum) 0;
679 fcinfo->isnull = true;
680 }
681 else if (!estate.retisnull)
682 {
683 /*
684 * Cast result value to function's declared result type, and copy it
685 * out to the upper executor memory context. We must treat tuple
686 * results specially in order to deal with cases like rowtypes
687 * involving dropped columns.
688 */
689 if (estate.retistuple)
690 {
691 /* Don't need coercion if rowtype is known to match */
692 if (func->fn_rettype == estate.rettype &&
693 func->fn_rettype != RECORDOID)
694 {
695 /*
696 * Copy the tuple result into upper executor memory context.
697 * However, if we have a R/W expanded datum, we can just
698 * transfer its ownership out to the upper context.
699 */
700 estate.retval = SPI_datumTransfer(estate.retval,
701 false,
702 -1);
703 }
704 else
705 {
706 /*
707 * Need to look up the expected result type. XXX would be
708 * better to cache the tupdesc instead of repeating
709 * get_call_result_type(), but the only easy place to save it
710 * is in the PLpgSQL_function struct, and that's too
711 * long-lived: composite types could change during the
712 * existence of a PLpgSQL_function.
713 */
714 Oid resultTypeId;
715 TupleDesc tupdesc;
716
717 switch (get_call_result_type(fcinfo, &resultTypeId, &tupdesc))
718 {
720 /* got the expected result rowtype, now coerce it */
721 coerce_function_result_tuple(&estate, tupdesc);
722 break;
724 /* got the expected result rowtype, now coerce it */
725 coerce_function_result_tuple(&estate, tupdesc);
726 /* and check domain constraints */
727 /* XXX allowing caching here would be good, too */
728 domain_check(estate.retval, false, resultTypeId,
729 NULL, NULL);
730 break;
731 case TYPEFUNC_RECORD:
732
733 /*
734 * Failed to determine actual type of RECORD. We
735 * could raise an error here, but what this means in
736 * practice is that the caller is expecting any old
737 * generic rowtype, so we don't really need to be
738 * restrictive. Pass back the generated result as-is.
739 */
740 estate.retval = SPI_datumTransfer(estate.retval,
741 false,
742 -1);
743 break;
744 default:
745 /* shouldn't get here if retistuple is true ... */
746 elog(ERROR, "return type must be a row type");
747 break;
748 }
749 }
750 }
751 else
752 {
753 /* Scalar case: use exec_cast_value */
754 estate.retval = exec_cast_value(&estate,
755 estate.retval,
756 &fcinfo->isnull,
757 estate.rettype,
758 -1,
759 func->fn_rettype,
760 -1);
761
762 /*
763 * If the function's return type isn't by value, copy the value
764 * into upper executor memory context. However, if we have a R/W
765 * expanded datum, we can just transfer its ownership out to the
766 * upper executor context.
767 */
768 if (!fcinfo->isnull && !func->fn_retbyval)
769 estate.retval = SPI_datumTransfer(estate.retval,
770 false,
771 func->fn_rettyplen);
772 }
773 }
774 else
775 {
776 /*
777 * We're returning a NULL, which normally requires no conversion work
778 * regardless of datatypes. But, if we are casting it to a domain
779 * return type, we'd better check that the domain's constraints pass.
780 */
781 if (func->fn_retisdomain)
782 estate.retval = exec_cast_value(&estate,
783 estate.retval,
784 &fcinfo->isnull,
785 estate.rettype,
786 -1,
787 func->fn_rettype,
788 -1);
789 }
790
791 estate.err_text = gettext_noop("during function exit");
792
793 /*
794 * Let the instrumentation plugin peek at this function
795 */
796 if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_end)
797 ((*plpgsql_plugin_ptr)->func_end) (&estate, func);
798
799 /* Clean up any leftover temporary memory */
801 exec_eval_cleanup(&estate);
802 /* stmt_mcontext will be destroyed when function's main context is */
803
804 /*
805 * Pop the error context stack
806 */
807 error_context_stack = plerrcontext.previous;
808
809 /*
810 * Return the function's result
811 */
812 return estate.retval;
813}
void domain_check(Datum value, bool isnull, Oid domainType, void **extra, MemoryContext mcxt)
Definition: domains.c:346
Datum TransferExpandedObject(Datum d, MemoryContext new_parent)
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
@ TYPEFUNC_RECORD
Definition: funcapi.h:151
@ TYPEFUNC_COMPOSITE_DOMAIN
Definition: funcapi.h:150
static void coerce_function_result_tuple(PLpgSQL_execstate *estate, TupleDesc tupdesc)
Definition: pl_exec.c:824
fmNodePtr resultinfo
Definition: fmgr.h:89
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
Datum value
Definition: postgres.h:80
bool isnull
Definition: postgres.h:82
bool fn_retisdomain
Definition: plpgsql.h:1006
int fn_argvarnos[FUNC_MAX_ARGS]
Definition: plpgsql.h:1012
SetFunctionReturnMode returnMode
Definition: execnodes.h:355
TupleDesc setDesc
Definition: execnodes.h:359
Tuplestorestate * setResult
Definition: execnodes.h:358
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:234
#define VARATT_IS_EXTERNAL_EXPANDED_RO(PTR)
Definition: varatt.h:294

References PLpgSQL_function::action, ReturnSetInfo::allowedModes, ErrorContextCallback::arg, FunctionCallInfoBaseData::args, assign_simple_var(), PLpgSQL_execstate::atomic, ErrorContextCallback::callback, coerce_function_result_tuple(), copy_plpgsql_datums(), CreateTupleDescCopy(), PLpgSQL_var::datatype, PLpgSQL_execstate::datum_context, DatumGetPointer(), PLpgSQL_function::datums, PLpgSQL_execstate::datums, domain_check(), PLpgSQL_datum::dtype, elog, ereport, PLpgSQL_execstate::err_text, errcode(), errmsg(), ERROR, error_context_stack, exec_cast_value(), exec_eval_cleanup(), exec_move_row(), exec_move_row_from_datum(), exec_set_found(), exec_toplevel_block(), expand_array(), PLpgSQL_function::fn_argvarnos, PLpgSQL_function::fn_nargs, PLpgSQL_function::fn_retbyval, PLpgSQL_function::fn_retisdomain, PLpgSQL_function::fn_rettype, PLpgSQL_function::fn_rettyplen, PLpgSQL_plugin::func_beg, PLpgSQL_plugin::func_end, get_call_result_type(), gettext_noop, i, if(), IsA, FunctionCallInfoBaseData::isnull, NullableDatum::isnull, PLpgSQL_var::isnull, MemoryContextSwitchTo(), plpgsql_destroy_econtext(), PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_VAR, plpgsql_estate_setup(), plpgsql_exec_error_callback(), plpgsql_plugin_ptr, PLPGSQL_RC_RETURN, ErrorContextCallback::previous, PLpgSQL_execstate::procedure_resowner, FunctionCallInfoBaseData::resultinfo, PLpgSQL_execstate::retisnull, PLpgSQL_execstate::retisset, PLpgSQL_execstate::retistuple, PLpgSQL_execstate::rettype, ReturnSetInfo::returnMode, PLpgSQL_execstate::retval, PLpgSQL_execstate::rsi, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize, SPI_datumTransfer(), TransferExpandedObject(), PLpgSQL_execstate::tuple_store, PLpgSQL_execstate::tuple_store_cxt, PLpgSQL_execstate::tuple_store_desc, TYPEFUNC_COMPOSITE, TYPEFUNC_COMPOSITE_DOMAIN, TYPEFUNC_RECORD, PLpgSQL_type::typisarray, PLpgSQL_type::typlen, NullableDatum::value, PLpgSQL_var::value, VARATT_IS_EXTERNAL_EXPANDED_RO, and VARATT_IS_EXTERNAL_EXPANDED_RW.

Referenced by plpgsql_call_handler(), and plpgsql_inline_handler().

◆ plpgsql_exec_get_datum_type()

Oid plpgsql_exec_get_datum_type ( PLpgSQL_execstate estate,
PLpgSQL_datum datum 
)

Definition at line 5453 of file pl_exec.c.

5455{
5456 Oid typeid;
5457
5458 switch (datum->dtype)
5459 {
5460 case PLPGSQL_DTYPE_VAR:
5462 {
5463 PLpgSQL_var *var = (PLpgSQL_var *) datum;
5464
5465 typeid = var->datatype->typoid;
5466 break;
5467 }
5468
5469 case PLPGSQL_DTYPE_REC:
5470 {
5471 PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
5472
5473 if (rec->erh == NULL || rec->rectypeid != RECORDOID)
5474 {
5475 /* Report variable's declared type */
5476 typeid = rec->rectypeid;
5477 }
5478 else
5479 {
5480 /* Report record's actual type if declared RECORD */
5481 typeid = rec->erh->er_typeid;
5482 }
5483 break;
5484 }
5485
5487 {
5488 PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
5489 PLpgSQL_rec *rec;
5490
5491 rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5492
5493 /*
5494 * If record variable is NULL, instantiate it if it has a
5495 * named composite type, else complain. (This won't change
5496 * the logical state of the record: it's still NULL.)
5497 */
5498 if (rec->erh == NULL)
5500
5501 /*
5502 * Look up the field's properties if we have not already, or
5503 * if the tuple descriptor ID changed since last time.
5504 */
5505 if (unlikely(recfield->rectupledescid != rec->erh->er_tupdesc_id))
5506 {
5508 recfield->fieldname,
5509 &recfield->finfo))
5510 ereport(ERROR,
5511 (errcode(ERRCODE_UNDEFINED_COLUMN),
5512 errmsg("record \"%s\" has no field \"%s\"",
5513 rec->refname, recfield->fieldname)));
5514 recfield->rectupledescid = rec->erh->er_tupdesc_id;
5515 }
5516
5517 typeid = recfield->finfo.ftypeid;
5518 break;
5519 }
5520
5521 default:
5522 elog(ERROR, "unrecognized dtype: %d", datum->dtype);
5523 typeid = InvalidOid; /* keep compiler quiet */
5524 break;
5525 }
5526
5527 return typeid;
5528}

References PLpgSQL_var::datatype, PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, elog, ExpandedRecordHeader::er_tupdesc_id, ExpandedRecordHeader::er_typeid, ereport, PLpgSQL_rec::erh, errcode(), errmsg(), ERROR, expanded_record_lookup_field(), PLpgSQL_recfield::fieldname, PLpgSQL_recfield::finfo, ExpandedRecordFieldInfo::ftypeid, instantiate_empty_record_variable(), InvalidOid, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_VAR, PLpgSQL_recfield::recparentno, PLpgSQL_recfield::rectupledescid, PLpgSQL_rec::rectypeid, PLpgSQL_rec::refname, PLpgSQL_type::typoid, and unlikely.

Referenced by exec_stmt_foreach_a().

◆ plpgsql_exec_get_datum_type_info()

void plpgsql_exec_get_datum_type_info ( PLpgSQL_execstate estate,
PLpgSQL_datum datum,
Oid typeId,
int32 typMod,
Oid collation 
)

Definition at line 5538 of file pl_exec.c.

5541{
5542 switch (datum->dtype)
5543 {
5544 case PLPGSQL_DTYPE_VAR:
5546 {
5547 PLpgSQL_var *var = (PLpgSQL_var *) datum;
5548
5549 *typeId = var->datatype->typoid;
5550 *typMod = var->datatype->atttypmod;
5551 *collation = var->datatype->collation;
5552 break;
5553 }
5554
5555 case PLPGSQL_DTYPE_REC:
5556 {
5557 PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
5558
5559 if (rec->erh == NULL || rec->rectypeid != RECORDOID)
5560 {
5561 /* Report variable's declared type */
5562 *typeId = rec->rectypeid;
5563 *typMod = -1;
5564 }
5565 else
5566 {
5567 /* Report record's actual type if declared RECORD */
5568 *typeId = rec->erh->er_typeid;
5569 /* do NOT return the mutable typmod of a RECORD variable */
5570 *typMod = -1;
5571 }
5572 /* composite types are never collatable */
5573 *collation = InvalidOid;
5574 break;
5575 }
5576
5578 {
5579 PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
5580 PLpgSQL_rec *rec;
5581
5582 rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5583
5584 /*
5585 * If record variable is NULL, instantiate it if it has a
5586 * named composite type, else complain. (This won't change
5587 * the logical state of the record: it's still NULL.)
5588 */
5589 if (rec->erh == NULL)
5591
5592 /*
5593 * Look up the field's properties if we have not already, or
5594 * if the tuple descriptor ID changed since last time.
5595 */
5596 if (unlikely(recfield->rectupledescid != rec->erh->er_tupdesc_id))
5597 {
5599 recfield->fieldname,
5600 &recfield->finfo))
5601 ereport(ERROR,
5602 (errcode(ERRCODE_UNDEFINED_COLUMN),
5603 errmsg("record \"%s\" has no field \"%s\"",
5604 rec->refname, recfield->fieldname)));
5605 recfield->rectupledescid = rec->erh->er_tupdesc_id;
5606 }
5607
5608 *typeId = recfield->finfo.ftypeid;
5609 *typMod = recfield->finfo.ftypmod;
5610 *collation = recfield->finfo.fcollation;
5611 break;
5612 }
5613
5614 default:
5615 elog(ERROR, "unrecognized dtype: %d", datum->dtype);
5616 *typeId = InvalidOid; /* keep compiler quiet */
5617 *typMod = -1;
5618 *collation = InvalidOid;
5619 break;
5620 }
5621}
Oid collation
Definition: plpgsql.h:217

References PLpgSQL_type::atttypmod, PLpgSQL_type::collation, PLpgSQL_var::datatype, PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, elog, ExpandedRecordHeader::er_tupdesc_id, ExpandedRecordHeader::er_typeid, ereport, PLpgSQL_rec::erh, errcode(), errmsg(), ERROR, expanded_record_lookup_field(), ExpandedRecordFieldInfo::fcollation, PLpgSQL_recfield::fieldname, PLpgSQL_recfield::finfo, ExpandedRecordFieldInfo::ftypeid, ExpandedRecordFieldInfo::ftypmod, instantiate_empty_record_variable(), InvalidOid, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_VAR, PLpgSQL_recfield::recparentno, PLpgSQL_recfield::rectupledescid, PLpgSQL_rec::rectypeid, PLpgSQL_rec::refname, PLpgSQL_type::typoid, and unlikely.

Referenced by make_datum_param().

◆ plpgsql_exec_trigger()

HeapTuple plpgsql_exec_trigger ( PLpgSQL_function func,
TriggerData trigdata 
)

Definition at line 935 of file pl_exec.c.

937{
938 PLpgSQL_execstate estate;
939 ErrorContextCallback plerrcontext;
940 int rc;
941 TupleDesc tupdesc;
942 PLpgSQL_rec *rec_new,
943 *rec_old;
944 HeapTuple rettup;
945
946 /*
947 * Setup the execution state
948 */
949 plpgsql_estate_setup(&estate, func, NULL, NULL, NULL);
950 estate.trigdata = trigdata;
951
952 /*
953 * Setup error traceback support for ereport()
954 */
956 plerrcontext.arg = &estate;
957 plerrcontext.previous = error_context_stack;
958 error_context_stack = &plerrcontext;
959
960 /*
961 * Make local execution copies of all the datums
962 */
963 estate.err_text = gettext_noop("during initialization of execution state");
964 copy_plpgsql_datums(&estate, func);
965
966 /*
967 * Put the OLD and NEW tuples into record variables
968 *
969 * We set up expanded records for both variables even though only one may
970 * have a value. This allows record references to succeed in functions
971 * that are used for multiple trigger types. For example, we might have a
972 * test like "if (TG_OP = 'INSERT' and NEW.foo = 'xyz')", which should
973 * work regardless of the current trigger type. If a value is actually
974 * fetched from an unsupplied tuple, it will read as NULL.
975 */
976 tupdesc = RelationGetDescr(trigdata->tg_relation);
977
978 rec_new = (PLpgSQL_rec *) (estate.datums[func->new_varno]);
979 rec_old = (PLpgSQL_rec *) (estate.datums[func->old_varno]);
980
981 rec_new->erh = make_expanded_record_from_tupdesc(tupdesc,
982 estate.datum_context);
983 rec_old->erh = make_expanded_record_from_exprecord(rec_new->erh,
984 estate.datum_context);
985
986 if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
987 {
988 /*
989 * Per-statement triggers don't use OLD/NEW variables
990 */
991 }
992 else if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
993 {
994 expanded_record_set_tuple(rec_new->erh, trigdata->tg_trigtuple,
995 false, false);
996 }
997 else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
998 {
999 expanded_record_set_tuple(rec_new->erh, trigdata->tg_newtuple,
1000 false, false);
1001 expanded_record_set_tuple(rec_old->erh, trigdata->tg_trigtuple,
1002 false, false);
1003
1004 /*
1005 * In BEFORE trigger, stored generated columns are not computed yet,
1006 * so make them null in the NEW row. (Only needed in UPDATE branch;
1007 * in the INSERT case, they are already null, but in UPDATE, the field
1008 * still contains the old value.) Alternatively, we could construct a
1009 * whole new row structure without the generated columns, but this way
1010 * seems more efficient and potentially less confusing.
1011 */
1012 if (tupdesc->constr && tupdesc->constr->has_generated_stored &&
1013 TRIGGER_FIRED_BEFORE(trigdata->tg_event))
1014 {
1015 for (int i = 0; i < tupdesc->natts; i++)
1016 if (TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED)
1018 i + 1,
1019 (Datum) 0,
1020 true, /* isnull */
1021 false, false);
1022 }
1023 }
1024 else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
1025 {
1026 expanded_record_set_tuple(rec_old->erh, trigdata->tg_trigtuple,
1027 false, false);
1028 }
1029 else
1030 elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, or UPDATE");
1031
1032 /* Make transition tables visible to this SPI connection */
1033 rc = SPI_register_trigger_data(trigdata);
1034 Assert(rc >= 0);
1035
1036 estate.err_text = gettext_noop("during function entry");
1037
1038 /*
1039 * Set the magic variable FOUND to false
1040 */
1041 exec_set_found(&estate, false);
1042
1043 /*
1044 * Let the instrumentation plugin peek at this function
1045 */
1046 if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_beg)
1047 ((*plpgsql_plugin_ptr)->func_beg) (&estate, func);
1048
1049 /*
1050 * Now call the toplevel block of statements
1051 */
1052 estate.err_text = NULL;
1053 rc = exec_toplevel_block(&estate, func->action);
1054 if (rc != PLPGSQL_RC_RETURN)
1055 {
1056 estate.err_text = NULL;
1057 ereport(ERROR,
1058 (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
1059 errmsg("control reached end of trigger procedure without RETURN")));
1060 }
1061
1062 estate.err_text = gettext_noop("during function exit");
1063
1064 if (estate.retisset)
1065 ereport(ERROR,
1066 (errcode(ERRCODE_DATATYPE_MISMATCH),
1067 errmsg("trigger procedure cannot return a set")));
1068
1069 /*
1070 * Check that the returned tuple structure has the same attributes, the
1071 * relation that fired the trigger has. A per-statement trigger always
1072 * needs to return NULL, so we ignore any return value the function itself
1073 * produces (XXX: is this a good idea?)
1074 *
1075 * XXX This way it is possible, that the trigger returns a tuple where
1076 * attributes don't have the correct atttypmod's length. It's up to the
1077 * trigger's programmer to ensure that this doesn't happen. Jan
1078 */
1079 if (estate.retisnull || !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
1080 rettup = NULL;
1081 else
1082 {
1083 TupleDesc retdesc;
1084 TupleConversionMap *tupmap;
1085
1086 /* We assume exec_stmt_return verified that result is composite */
1088
1089 /* We can special-case expanded records for speed */
1091 {
1093
1094 Assert(erh->er_magic == ER_MAGIC);
1095
1096 /* Extract HeapTuple and TupleDesc */
1097 rettup = expanded_record_get_tuple(erh);
1098 Assert(rettup);
1099 retdesc = expanded_record_get_tupdesc(erh);
1100
1101 if (retdesc != RelationGetDescr(trigdata->tg_relation))
1102 {
1103 /* check rowtype compatibility */
1104 tupmap = convert_tuples_by_position(retdesc,
1105 RelationGetDescr(trigdata->tg_relation),
1106 gettext_noop("returned row structure does not match the structure of the triggering table"));
1107 /* it might need conversion */
1108 if (tupmap)
1109 rettup = execute_attr_map_tuple(rettup, tupmap);
1110 /* no need to free map, we're about to return anyway */
1111 }
1112
1113 /*
1114 * Copy tuple to upper executor memory. But if user just did
1115 * "return new" or "return old" without changing anything, there's
1116 * no need to copy; we can return the original tuple (which will
1117 * save a few cycles in trigger.c as well as here).
1118 */
1119 if (rettup != trigdata->tg_newtuple &&
1120 rettup != trigdata->tg_trigtuple)
1121 rettup = SPI_copytuple(rettup);
1122 }
1123 else
1124 {
1125 /* Convert composite datum to a HeapTuple and TupleDesc */
1126 HeapTupleData tmptup;
1127
1128 retdesc = deconstruct_composite_datum(estate.retval, &tmptup);
1129 rettup = &tmptup;
1130
1131 /* check rowtype compatibility */
1132 tupmap = convert_tuples_by_position(retdesc,
1133 RelationGetDescr(trigdata->tg_relation),
1134 gettext_noop("returned row structure does not match the structure of the triggering table"));
1135 /* it might need conversion */
1136 if (tupmap)
1137 rettup = execute_attr_map_tuple(rettup, tupmap);
1138
1139 ReleaseTupleDesc(retdesc);
1140 /* no need to free map, we're about to return anyway */
1141
1142 /* Copy tuple to upper executor memory */
1143 rettup = SPI_copytuple(rettup);
1144 }
1145 }
1146
1147 /*
1148 * Let the instrumentation plugin peek at this function
1149 */
1150 if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_end)
1151 ((*plpgsql_plugin_ptr)->func_end) (&estate, func);
1152
1153 /* Clean up any leftover temporary memory */
1154 plpgsql_destroy_econtext(&estate);
1155 exec_eval_cleanup(&estate);
1156 /* stmt_mcontext will be destroyed when function's main context is */
1157
1158 /*
1159 * Pop the error context stack
1160 */
1161 error_context_stack = plerrcontext.previous;
1162
1163 /*
1164 * Return the trigger's result
1165 */
1166 return rettup;
1167}
void expanded_record_set_field_internal(ExpandedRecordHeader *erh, int fnumber, Datum newValue, bool isnull, bool expand_external, bool check_constraints)
#define RelationGetDescr(relation)
Definition: rel.h:539
int SPI_register_trigger_data(TriggerData *tdata)
Definition: spi.c:3381
HeapTuple SPI_copytuple(HeapTuple tuple)
Definition: spi.c:1048
Relation tg_relation
Definition: trigger.h:35
TriggerEvent tg_event
Definition: trigger.h:34
HeapTuple tg_newtuple
Definition: trigger.h:37
HeapTuple tg_trigtuple
Definition: trigger.h:36
bool has_generated_stored
Definition: tupdesc.h:46
TupleConstr * constr
Definition: tupdesc.h:135
#define TRIGGER_FIRED_BY_DELETE(event)
Definition: trigger.h:113
#define TRIGGER_FIRED_BEFORE(event)
Definition: trigger.h:128
#define TRIGGER_FIRED_FOR_ROW(event)
Definition: trigger.h:122
#define TRIGGER_FIRED_BY_INSERT(event)
Definition: trigger.h:110
#define TRIGGER_FIRED_BY_UPDATE(event)
Definition: trigger.h:116

References PLpgSQL_function::action, ErrorContextCallback::arg, Assert(), ErrorContextCallback::callback, TupleDescData::constr, convert_tuples_by_position(), copy_plpgsql_datums(), PLpgSQL_execstate::datum_context, DatumGetEOHP(), DatumGetPointer(), PLpgSQL_execstate::datums, deconstruct_composite_datum(), elog, ER_MAGIC, ExpandedRecordHeader::er_magic, ereport, PLpgSQL_rec::erh, PLpgSQL_execstate::err_text, errcode(), errmsg(), ERROR, error_context_stack, exec_eval_cleanup(), exec_set_found(), exec_toplevel_block(), execute_attr_map_tuple(), expanded_record_get_tupdesc(), expanded_record_get_tuple(), expanded_record_set_field_internal(), expanded_record_set_tuple(), PLpgSQL_plugin::func_beg, PLpgSQL_plugin::func_end, gettext_noop, TupleConstr::has_generated_stored, i, make_expanded_record_from_exprecord(), make_expanded_record_from_tupdesc(), TupleDescData::natts, PLpgSQL_function::new_varno, PLpgSQL_function::old_varno, plpgsql_destroy_econtext(), plpgsql_estate_setup(), plpgsql_exec_error_callback(), plpgsql_plugin_ptr, PLPGSQL_RC_RETURN, ErrorContextCallback::previous, RelationGetDescr, ReleaseTupleDesc, PLpgSQL_execstate::retisnull, PLpgSQL_execstate::retisset, PLpgSQL_execstate::rettype, PLpgSQL_execstate::retval, SPI_copytuple(), SPI_register_trigger_data(), TriggerData::tg_event, TriggerData::tg_newtuple, TriggerData::tg_relation, TriggerData::tg_trigtuple, PLpgSQL_execstate::trigdata, TRIGGER_FIRED_BEFORE, TRIGGER_FIRED_BY_DELETE, TRIGGER_FIRED_BY_INSERT, TRIGGER_FIRED_BY_UPDATE, TRIGGER_FIRED_FOR_ROW, TupleDescAttr(), type_is_rowtype(), and VARATT_IS_EXTERNAL_EXPANDED.

Referenced by plpgsql_call_handler().

◆ plpgsql_fulfill_promise()

static void plpgsql_fulfill_promise ( PLpgSQL_execstate estate,
PLpgSQL_var var 
)
static

Definition at line 1384 of file pl_exec.c.

1386{
1387 MemoryContext oldcontext;
1388
1389 if (var->promise == PLPGSQL_PROMISE_NONE)
1390 return; /* nothing to do */
1391
1392 /*
1393 * This will typically be invoked in a short-lived context such as the
1394 * mcontext. We must create variable values in the estate's datum
1395 * context. This quick-and-dirty solution risks leaking some additional
1396 * cruft there, but since any one promise is honored at most once per
1397 * function call, it's probably not worth being more careful.
1398 */
1399 oldcontext = MemoryContextSwitchTo(estate->datum_context);
1400
1401 switch (var->promise)
1402 {
1404 if (estate->trigdata == NULL)
1405 elog(ERROR, "trigger promise is not in a trigger function");
1406 assign_simple_var(estate, var,
1409 false, true);
1410 break;
1411
1413 if (estate->trigdata == NULL)
1414 elog(ERROR, "trigger promise is not in a trigger function");
1416 assign_text_var(estate, var, "BEFORE");
1417 else if (TRIGGER_FIRED_AFTER(estate->trigdata->tg_event))
1418 assign_text_var(estate, var, "AFTER");
1419 else if (TRIGGER_FIRED_INSTEAD(estate->trigdata->tg_event))
1420 assign_text_var(estate, var, "INSTEAD OF");
1421 else
1422 elog(ERROR, "unrecognized trigger execution time: not BEFORE, AFTER, or INSTEAD OF");
1423 break;
1424
1426 if (estate->trigdata == NULL)
1427 elog(ERROR, "trigger promise is not in a trigger function");
1429 assign_text_var(estate, var, "ROW");
1431 assign_text_var(estate, var, "STATEMENT");
1432 else
1433 elog(ERROR, "unrecognized trigger event type: not ROW or STATEMENT");
1434 break;
1435
1437 if (estate->trigdata == NULL)
1438 elog(ERROR, "trigger promise is not in a trigger function");
1440 assign_text_var(estate, var, "INSERT");
1441 else if (TRIGGER_FIRED_BY_UPDATE(estate->trigdata->tg_event))
1442 assign_text_var(estate, var, "UPDATE");
1443 else if (TRIGGER_FIRED_BY_DELETE(estate->trigdata->tg_event))
1444 assign_text_var(estate, var, "DELETE");
1445 else if (TRIGGER_FIRED_BY_TRUNCATE(estate->trigdata->tg_event))
1446 assign_text_var(estate, var, "TRUNCATE");
1447 else
1448 elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, UPDATE, or TRUNCATE");
1449 break;
1450
1452 if (estate->trigdata == NULL)
1453 elog(ERROR, "trigger promise is not in a trigger function");
1454 assign_simple_var(estate, var,
1456 false, false);
1457 break;
1458
1460 if (estate->trigdata == NULL)
1461 elog(ERROR, "trigger promise is not in a trigger function");
1462 assign_simple_var(estate, var,
1465 false, true);
1466 break;
1467
1469 if (estate->trigdata == NULL)
1470 elog(ERROR, "trigger promise is not in a trigger function");
1471 assign_simple_var(estate, var,
1474 false, true);
1475 break;
1476
1478 if (estate->trigdata == NULL)
1479 elog(ERROR, "trigger promise is not in a trigger function");
1480 assign_simple_var(estate, var,
1482 false, false);
1483 break;
1484
1486 if (estate->trigdata == NULL)
1487 elog(ERROR, "trigger promise is not in a trigger function");
1488 if (estate->trigdata->tg_trigger->tgnargs > 0)
1489 {
1490 /*
1491 * For historical reasons, tg_argv[] subscripts start at zero
1492 * not one. So we can't use construct_array().
1493 */
1494 int nelems = estate->trigdata->tg_trigger->tgnargs;
1495 Datum *elems;
1496 int dims[1];
1497 int lbs[1];
1498 int i;
1499
1500 elems = palloc(sizeof(Datum) * nelems);
1501 for (i = 0; i < nelems; i++)
1502 elems[i] = CStringGetTextDatum(estate->trigdata->tg_trigger->tgargs[i]);
1503 dims[0] = nelems;
1504 lbs[0] = 0;
1505
1506 assign_simple_var(estate, var,
1508 1, dims, lbs,
1509 TEXTOID,
1510 -1, false, TYPALIGN_INT)),
1511 false, true);
1512 }
1513 else
1514 {
1515 assign_simple_var(estate, var, (Datum) 0, true, false);
1516 }
1517 break;
1518
1520 if (estate->evtrigdata == NULL)
1521 elog(ERROR, "event trigger promise is not in an event trigger function");
1522 assign_text_var(estate, var, estate->evtrigdata->event);
1523 break;
1524
1526 if (estate->evtrigdata == NULL)
1527 elog(ERROR, "event trigger promise is not in an event trigger function");
1528 assign_text_var(estate, var, GetCommandTagName(estate->evtrigdata->tag));
1529 break;
1530
1531 default:
1532 elog(ERROR, "unrecognized promise type: %d", var->promise);
1533 }
1534
1535 MemoryContextSwitchTo(oldcontext);
1536}
ArrayType * construct_md_array(Datum *elems, bool *nulls, int ndims, int *dims, int *lbs, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3494
const char * GetCommandTagName(CommandTag commandTag)
Definition: cmdtag.c:47
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:641
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3449
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
@ PLPGSQL_PROMISE_TG_RELID
Definition: plpgsql.h:80
@ PLPGSQL_PROMISE_TG_WHEN
Definition: plpgsql.h:77
@ PLPGSQL_PROMISE_TG_ARGV
Definition: plpgsql.h:84
@ PLPGSQL_PROMISE_TG_TABLE_SCHEMA
Definition: plpgsql.h:82
@ PLPGSQL_PROMISE_TG_EVENT
Definition: plpgsql.h:85
@ PLPGSQL_PROMISE_TG_TABLE_NAME
Definition: plpgsql.h:81
@ PLPGSQL_PROMISE_TG_TAG
Definition: plpgsql.h:86
@ PLPGSQL_PROMISE_TG_OP
Definition: plpgsql.h:79
@ PLPGSQL_PROMISE_TG_LEVEL
Definition: plpgsql.h:78
@ PLPGSQL_PROMISE_TG_NARGS
Definition: plpgsql.h:83
@ PLPGSQL_PROMISE_TG_NAME
Definition: plpgsql.h:76
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:177
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:355
#define RelationGetRelationName(relation)
Definition: rel.h:547
#define RelationGetNamespace(relation)
Definition: rel.h:554
CommandTag tag
Definition: event_trigger.h:29
const char * event
Definition: event_trigger.h:27
Oid rd_id
Definition: rel.h:113
Trigger * tg_trigger
Definition: trigger.h:38
char * tgname
Definition: reltrigger.h:27
int16 tgnargs
Definition: reltrigger.h:38
char ** tgargs
Definition: reltrigger.h:41
#define TRIGGER_FIRED_FOR_STATEMENT(event)
Definition: trigger.h:125
#define TRIGGER_FIRED_AFTER(event)
Definition: trigger.h:131
#define TRIGGER_FIRED_BY_TRUNCATE(event)
Definition: trigger.h:119
#define TRIGGER_FIRED_INSTEAD(event)
Definition: trigger.h:134

References assign_simple_var(), assign_text_var(), construct_md_array(), CStringGetDatum(), CStringGetTextDatum, PLpgSQL_execstate::datum_context, DirectFunctionCall1, elog, ERROR, EventTriggerData::event, PLpgSQL_execstate::evtrigdata, get_namespace_name(), GetCommandTagName(), i, Int16GetDatum(), MemoryContextSwitchTo(), namein(), ObjectIdGetDatum(), palloc(), PLPGSQL_PROMISE_NONE, PLPGSQL_PROMISE_TG_ARGV, PLPGSQL_PROMISE_TG_EVENT, PLPGSQL_PROMISE_TG_LEVEL, PLPGSQL_PROMISE_TG_NAME, PLPGSQL_PROMISE_TG_NARGS, PLPGSQL_PROMISE_TG_OP, PLPGSQL_PROMISE_TG_RELID, PLPGSQL_PROMISE_TG_TABLE_NAME, PLPGSQL_PROMISE_TG_TABLE_SCHEMA, PLPGSQL_PROMISE_TG_TAG, PLPGSQL_PROMISE_TG_WHEN, PointerGetDatum(), PLpgSQL_var::promise, RelationData::rd_id, RelationGetNamespace, RelationGetRelationName, EventTriggerData::tag, TriggerData::tg_event, TriggerData::tg_relation, TriggerData::tg_trigger, Trigger::tgargs, Trigger::tgname, Trigger::tgnargs, PLpgSQL_execstate::trigdata, TRIGGER_FIRED_AFTER, TRIGGER_FIRED_BEFORE, TRIGGER_FIRED_BY_DELETE, TRIGGER_FIRED_BY_INSERT, TRIGGER_FIRED_BY_TRUNCATE, TRIGGER_FIRED_BY_UPDATE, TRIGGER_FIRED_FOR_ROW, TRIGGER_FIRED_FOR_STATEMENT, and TRIGGER_FIRED_INSTEAD.

Referenced by exec_eval_datum(), exec_stmt_return(), and exec_stmt_return_next().

◆ plpgsql_param_compile()

static void plpgsql_param_compile ( ParamListInfo  params,
Param param,
ExprState state,
Datum resv,
bool *  resnull 
)
static

Definition at line 6435 of file pl_exec.c.

6438{
6439 PLpgSQL_execstate *estate;
6440 PLpgSQL_expr *expr;
6441 int dno;
6442 PLpgSQL_datum *datum;
6443 ExprEvalStep scratch;
6444
6445 /* fetch back the hook data */
6446 estate = (PLpgSQL_execstate *) params->paramFetchArg;
6447 expr = (PLpgSQL_expr *) params->parserSetupArg;
6448
6449 /* paramid's are 1-based, but dnos are 0-based */
6450 dno = param->paramid - 1;
6451 Assert(dno >= 0 && dno < estate->ndatums);
6452
6453 /* now we can access the target datum */
6454 datum = estate->datums[dno];
6455
6456 scratch.opcode = EEOP_PARAM_CALLBACK;
6457 scratch.resvalue = resv;
6458 scratch.resnull = resnull;
6459
6460 /*
6461 * Select appropriate eval function.
6462 *
6463 * First, if this Param references the same varlena-type DTYPE_VAR datum
6464 * that is the target of the assignment containing this simple expression,
6465 * then it's possible we will be able to optimize handling of R/W expanded
6466 * datums. We don't want to do the work needed to determine that unless
6467 * we actually see a R/W expanded datum at runtime, so install a checking
6468 * function that will figure that out when needed.
6469 *
6470 * Otherwise, it seems worth special-casing DTYPE_VAR and DTYPE_RECFIELD
6471 * for performance. Also, we can determine in advance whether
6472 * MakeExpandedObjectReadOnly() will be required. Currently, only
6473 * VAR/PROMISE and REC datums could contain read/write expanded objects.
6474 */
6475 if (datum->dtype == PLPGSQL_DTYPE_VAR)
6476 {
6477 bool isvarlena = (((PLpgSQL_var *) datum)->datatype->typlen == -1);
6478
6479 if (isvarlena && dno == expr->target_param && expr->expr_simple_expr)
6481 else if (isvarlena)
6483 else
6485 }
6486 else if (datum->dtype == PLPGSQL_DTYPE_RECFIELD)
6488 else if (datum->dtype == PLPGSQL_DTYPE_PROMISE)
6489 {
6490 if (((PLpgSQL_var *) datum)->datatype->typlen == -1)
6492 else
6494 }
6495 else if (datum->dtype == PLPGSQL_DTYPE_REC)
6497 else
6499
6500 /*
6501 * Note: it's tempting to use paramarg to store the estate pointer and
6502 * thereby save an indirection or two in the eval functions. But that
6503 * doesn't work because the compiled expression might be used with
6504 * different estates for the same PL/pgSQL function. Instead, store
6505 * pointers to the PLpgSQL_expr as well as this specific Param, to support
6506 * plpgsql_param_eval_var_check().
6507 */
6508 scratch.d.cparam.paramarg = expr;
6509 scratch.d.cparam.paramarg2 = param;
6510 scratch.d.cparam.paramid = param->paramid;
6511 scratch.d.cparam.paramtype = param->paramtype;
6512 ExprEvalPushStep(state, &scratch);
6513}
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2678
@ EEOP_PARAM_CALLBACK
Definition: execExpr.h:175
static void plpgsql_param_eval_var_ro(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: pl_exec.c:6714
static void plpgsql_param_eval_recfield(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: pl_exec.c:6751
static void plpgsql_param_eval_generic_ro(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: pl_exec.c:6863
static void plpgsql_param_eval_generic(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: pl_exec.c:6823
static void plpgsql_param_eval_var(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: pl_exec.c:6682
static void plpgsql_param_eval_var_check(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: pl_exec.c:6529
void * paramarg
Definition: execExpr.h:433
void * paramarg2
Definition: execExpr.h:434
intptr_t opcode
Definition: execExpr.h:307
struct ExprEvalStep::@55::@69 cparam
ExecEvalSubroutine paramfunc
Definition: execExpr.h:432
Datum * resvalue
Definition: execExpr.h:310
Oid paramtype
Definition: execExpr.h:426
union ExprEvalStep::@55 d
bool * resnull
Definition: execExpr.h:311
Oid paramtype
Definition: primnodes.h:395

References Assert(), ExprEvalStep::cparam, ExprEvalStep::d, PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, EEOP_PARAM_CALLBACK, PLpgSQL_expr::expr_simple_expr, ExprEvalPushStep(), ExprEvalStep::opcode, ExprEvalStep::paramarg, ExprEvalStep::paramarg2, ParamListInfoData::paramFetchArg, ExprEvalStep::paramfunc, ExprEvalStep::paramid, Param::paramid, ExprEvalStep::paramtype, Param::paramtype, ParamListInfoData::parserSetupArg, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_VAR, plpgsql_param_eval_generic(), plpgsql_param_eval_generic_ro(), plpgsql_param_eval_recfield(), plpgsql_param_eval_var(), plpgsql_param_eval_var_check(), plpgsql_param_eval_var_ro(), ExprEvalStep::resnull, ExprEvalStep::resvalue, and PLpgSQL_expr::target_param.

Referenced by plpgsql_estate_setup().

◆ plpgsql_param_eval_generic()

static void plpgsql_param_eval_generic ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 6823 of file pl_exec.c.

6825{
6826 ParamListInfo params;
6827 PLpgSQL_execstate *estate;
6828 int dno = op->d.cparam.paramid - 1;
6829 PLpgSQL_datum *datum;
6830 Oid datumtype;
6831 int32 datumtypmod;
6832
6833 /* fetch back the hook data */
6834 params = econtext->ecxt_param_list_info;
6835 estate = (PLpgSQL_execstate *) params->paramFetchArg;
6836 Assert(dno >= 0 && dno < estate->ndatums);
6837
6838 /* now we can access the target datum */
6839 datum = estate->datums[dno];
6840
6841 /* fetch datum's value */
6842 exec_eval_datum(estate, datum,
6843 &datumtype, &datumtypmod,
6844 op->resvalue, op->resnull);
6845
6846 /* safety check -- needed for, eg, record fields */
6847 if (unlikely(datumtype != op->d.cparam.paramtype))
6848 ereport(ERROR,
6849 (errcode(ERRCODE_DATATYPE_MISMATCH),
6850 errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
6851 op->d.cparam.paramid,
6852 format_type_be(datumtype),
6854}

References Assert(), ExprEvalStep::cparam, ExprEvalStep::d, PLpgSQL_execstate::datums, ExprContext::ecxt_param_list_info, ereport, errcode(), errmsg(), ERROR, exec_eval_datum(), format_type_be(), ParamListInfoData::paramFetchArg, ExprEvalStep::paramid, ExprEvalStep::paramtype, ExprEvalStep::resnull, ExprEvalStep::resvalue, and unlikely.

Referenced by plpgsql_param_compile().

◆ plpgsql_param_eval_generic_ro()

static void plpgsql_param_eval_generic_ro ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 6863 of file pl_exec.c.

6865{
6866 ParamListInfo params;
6867 PLpgSQL_execstate *estate;
6868 int dno = op->d.cparam.paramid - 1;
6869 PLpgSQL_datum *datum;
6870 Oid datumtype;
6871 int32 datumtypmod;
6872
6873 /* fetch back the hook data */
6874 params = econtext->ecxt_param_list_info;
6875 estate = (PLpgSQL_execstate *) params->paramFetchArg;
6876 Assert(dno >= 0 && dno < estate->ndatums);
6877
6878 /* now we can access the target datum */
6879 datum = estate->datums[dno];
6880
6881 /* fetch datum's value */
6882 exec_eval_datum(estate, datum,
6883 &datumtype, &datumtypmod,
6884 op->resvalue, op->resnull);
6885
6886 /* safety check -- needed for, eg, record fields */
6887 if (unlikely(datumtype != op->d.cparam.paramtype))
6888 ereport(ERROR,
6889 (errcode(ERRCODE_DATATYPE_MISMATCH),
6890 errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
6891 op->d.cparam.paramid,
6892 format_type_be(datumtype),
6894
6895 /* force the value to read-only */
6897 *op->resnull,
6898 -1);
6899}

References Assert(), ExprEvalStep::cparam, ExprEvalStep::d, PLpgSQL_execstate::datums, ExprContext::ecxt_param_list_info, ereport, errcode(), errmsg(), ERROR, exec_eval_datum(), format_type_be(), MakeExpandedObjectReadOnly, ParamListInfoData::paramFetchArg, ExprEvalStep::paramid, ExprEvalStep::paramtype, ExprEvalStep::resnull, ExprEvalStep::resvalue, and unlikely.

Referenced by plpgsql_param_compile().

◆ plpgsql_param_eval_recfield()

static void plpgsql_param_eval_recfield ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 6751 of file pl_exec.c.

6753{
6754 ParamListInfo params;
6755 PLpgSQL_execstate *estate;
6756 int dno = op->d.cparam.paramid - 1;
6757 PLpgSQL_recfield *recfield;
6758 PLpgSQL_rec *rec;
6760
6761 /* fetch back the hook data */
6762 params = econtext->ecxt_param_list_info;
6763 estate = (PLpgSQL_execstate *) params->paramFetchArg;
6764 Assert(dno >= 0 && dno < estate->ndatums);
6765
6766 /* now we can access the target datum */
6767 recfield = (PLpgSQL_recfield *) estate->datums[dno];
6768 Assert(recfield->dtype == PLPGSQL_DTYPE_RECFIELD);
6769
6770 /* inline the relevant part of exec_eval_datum */
6771 rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
6772 erh = rec->erh;
6773
6774 /*
6775 * If record variable is NULL, instantiate it if it has a named composite
6776 * type, else complain. (This won't change the logical state of the
6777 * record: it's still NULL.)
6778 */
6779 if (erh == NULL)
6780 {
6782 erh = rec->erh;
6783 }
6784
6785 /*
6786 * Look up the field's properties if we have not already, or if the tuple
6787 * descriptor ID changed since last time.
6788 */
6789 if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
6790 {
6792 recfield->fieldname,
6793 &recfield->finfo))
6794 ereport(ERROR,
6795 (errcode(ERRCODE_UNDEFINED_COLUMN),
6796 errmsg("record \"%s\" has no field \"%s\"",
6797 rec->refname, recfield->fieldname)));
6798 recfield->rectupledescid = erh->er_tupdesc_id;
6799 }
6800
6801 /* OK to fetch the field value. */
6803 recfield->finfo.fnumber,
6804 op->resnull);
6805
6806 /* safety check -- needed for, eg, record fields */
6807 if (unlikely(recfield->finfo.ftypeid != op->d.cparam.paramtype))
6808 ereport(ERROR,
6809 (errcode(ERRCODE_DATATYPE_MISMATCH),
6810 errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
6811 op->d.cparam.paramid,
6812 format_type_be(recfield->finfo.ftypeid),
6814}
PLpgSQL_datum_type dtype
Definition: plpgsql.h:444

References Assert(), ExprEvalStep::cparam, ExprEvalStep::d, PLpgSQL_execstate::datums, PLpgSQL_recfield::dtype, ExprContext::ecxt_param_list_info, ExpandedRecordHeader::er_tupdesc_id, ereport, PLpgSQL_rec::erh, errcode(), errmsg(), ERROR, expanded_record_get_field(), expanded_record_lookup_field(), PLpgSQL_recfield::fieldname, PLpgSQL_recfield::finfo, ExpandedRecordFieldInfo::fnumber, format_type_be(), ExpandedRecordFieldInfo::ftypeid, instantiate_empty_record_variable(), ParamListInfoData::paramFetchArg, ExprEvalStep::paramid, ExprEvalStep::paramtype, PLPGSQL_DTYPE_RECFIELD, PLpgSQL_recfield::recparentno, PLpgSQL_recfield::rectupledescid, PLpgSQL_rec::refname, ExprEvalStep::resnull, ExprEvalStep::resvalue, and unlikely.

Referenced by plpgsql_param_compile().

◆ plpgsql_param_eval_var()

static void plpgsql_param_eval_var ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 6682 of file pl_exec.c.

6684{
6685 ParamListInfo params;
6686 PLpgSQL_execstate *estate;
6687 int dno = op->d.cparam.paramid - 1;
6688 PLpgSQL_var *var;
6689
6690 /* fetch back the hook data */
6691 params = econtext->ecxt_param_list_info;
6692 estate = (PLpgSQL_execstate *) params->paramFetchArg;
6693 Assert(dno >= 0 && dno < estate->ndatums);
6694
6695 /* now we can access the target datum */
6696 var = (PLpgSQL_var *) estate->datums[dno];
6698
6699 /* inlined version of exec_eval_datum() */
6700 *op->resvalue = var->value;
6701 *op->resnull = var->isnull;
6702
6703 /* safety check -- an assertion should be sufficient */
6704 Assert(var->datatype->typoid == op->d.cparam.paramtype);
6705}

References Assert(), ExprEvalStep::cparam, ExprEvalStep::d, PLpgSQL_var::datatype, PLpgSQL_execstate::datums, PLpgSQL_var::dtype, ExprContext::ecxt_param_list_info, PLpgSQL_var::isnull, ParamListInfoData::paramFetchArg, ExprEvalStep::paramid, ExprEvalStep::paramtype, PLPGSQL_DTYPE_VAR, ExprEvalStep::resnull, ExprEvalStep::resvalue, PLpgSQL_type::typoid, and PLpgSQL_var::value.

Referenced by plpgsql_param_compile(), and plpgsql_param_eval_var_check().

◆ plpgsql_param_eval_var_check()

static void plpgsql_param_eval_var_check ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 6529 of file pl_exec.c.

6531{
6532 ParamListInfo params;
6533 PLpgSQL_execstate *estate;
6534 int dno = op->d.cparam.paramid - 1;
6535 PLpgSQL_var *var;
6536
6537 /* fetch back the hook data */
6538 params = econtext->ecxt_param_list_info;
6539 estate = (PLpgSQL_execstate *) params->paramFetchArg;
6540 Assert(dno >= 0 && dno < estate->ndatums);
6541
6542 /* now we can access the target datum */
6543 var = (PLpgSQL_var *) estate->datums[dno];
6545
6546 /*
6547 * If the variable's current value is a R/W expanded object, it's time to
6548 * decide whether/how to optimize the assignment.
6549 */
6550 if (!var->isnull &&
6552 {
6553 PLpgSQL_expr *expr = (PLpgSQL_expr *) op->d.cparam.paramarg;
6554 Param *param = (Param *) op->d.cparam.paramarg2;
6555
6556 /*
6557 * We might have already figured this out while evaluating some other
6558 * Param referencing the same variable, so check expr_rwopt first.
6559 */
6560 if (expr->expr_rwopt == PLPGSQL_RWOPT_UNKNOWN)
6562
6563 /*
6564 * Update the callback pointer to match what we decided to do, so that
6565 * this function will not be called again. Then pass off this
6566 * execution to the newly-selected function.
6567 */
6568 switch (expr->expr_rwopt)
6569 {
6571 Assert(false);
6572 break;
6573 case PLPGSQL_RWOPT_NOPE:
6574 /* Force the value to read-only in all future executions */
6576 plpgsql_param_eval_var_ro(state, op, econtext);
6577 break;
6579 /* There can be only one matching Param in this case */
6580 Assert(param == expr->expr_rw_param);
6581 /* When the value is read/write, transfer to exec context */
6584 break;
6586 if (param == expr->expr_rw_param)
6587 {
6588 /* When the value is read/write, deliver it as-is */
6590 plpgsql_param_eval_var(state, op, econtext);
6591 }
6592 else
6593 {
6594 /* Not the optimizable reference, so force to read-only */
6596 plpgsql_param_eval_var_ro(state, op, econtext);
6597 }
6598 break;
6599 }
6600 return;
6601 }
6602
6603 /*
6604 * Otherwise, continue to postpone that decision, and execute an inlined
6605 * version of exec_eval_datum(). Although this value could potentially
6606 * need MakeExpandedObjectReadOnly, we know it doesn't right now.
6607 */
6608 *op->resvalue = var->value;
6609 *op->resnull = var->isnull;
6610
6611 /* safety check -- an assertion should be sufficient */
6612 Assert(var->datatype->typoid == op->d.cparam.paramtype);
6613}
static void plpgsql_param_eval_var_transfer(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: pl_exec.c:6626
static void exec_check_rw_parameter(PLpgSQL_expr *expr, int paramid)
Definition: pl_exec.c:8411

References Assert(), ExprEvalStep::cparam, ExprEvalStep::d, PLpgSQL_var::datatype, DatumGetPointer(), PLpgSQL_execstate::datums, PLpgSQL_var::dtype, ExprContext::ecxt_param_list_info, exec_check_rw_parameter(), PLpgSQL_expr::expr_rw_param, PLpgSQL_expr::expr_rwopt, PLpgSQL_var::isnull, ExprEvalStep::paramarg, ExprEvalStep::paramarg2, ParamListInfoData::paramFetchArg, ExprEvalStep::paramfunc, ExprEvalStep::paramid, ExprEvalStep::paramtype, PLPGSQL_DTYPE_VAR, plpgsql_param_eval_var(), plpgsql_param_eval_var_ro(), plpgsql_param_eval_var_transfer(), PLPGSQL_RWOPT_INPLACE, PLPGSQL_RWOPT_NOPE, PLPGSQL_RWOPT_TRANSFER, PLPGSQL_RWOPT_UNKNOWN, ExprEvalStep::resnull, ExprEvalStep::resvalue, PLpgSQL_type::typoid, PLpgSQL_var::value, and VARATT_IS_EXTERNAL_EXPANDED_RW.

Referenced by plpgsql_param_compile().

◆ plpgsql_param_eval_var_ro()

static void plpgsql_param_eval_var_ro ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 6714 of file pl_exec.c.

6716{
6717 ParamListInfo params;
6718 PLpgSQL_execstate *estate;
6719 int dno = op->d.cparam.paramid - 1;
6720 PLpgSQL_var *var;
6721
6722 /* fetch back the hook data */
6723 params = econtext->ecxt_param_list_info;
6724 estate = (PLpgSQL_execstate *) params->paramFetchArg;
6725 Assert(dno >= 0 && dno < estate->ndatums);
6726
6727 /* now we can access the target datum */
6728 var = (PLpgSQL_var *) estate->datums[dno];
6730
6731 /*
6732 * Inlined version of exec_eval_datum() ... and while we're at it, force
6733 * expanded datums to read-only.
6734 */
6736 var->isnull,
6737 -1);
6738 *op->resnull = var->isnull;
6739
6740 /* safety check -- an assertion should be sufficient */
6741 Assert(var->datatype->typoid == op->d.cparam.paramtype);
6742}

References Assert(), ExprEvalStep::cparam, ExprEvalStep::d, PLpgSQL_var::datatype, PLpgSQL_execstate::datums, PLpgSQL_var::dtype, ExprContext::ecxt_param_list_info, PLpgSQL_var::isnull, MakeExpandedObjectReadOnly, ParamListInfoData::paramFetchArg, ExprEvalStep::paramid, ExprEvalStep::paramtype, PLPGSQL_DTYPE_VAR, ExprEvalStep::resnull, ExprEvalStep::resvalue, PLpgSQL_type::typoid, and PLpgSQL_var::value.

Referenced by plpgsql_param_compile(), and plpgsql_param_eval_var_check().

◆ plpgsql_param_eval_var_transfer()

static void plpgsql_param_eval_var_transfer ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 6626 of file pl_exec.c.

6628{
6629 ParamListInfo params;
6630 PLpgSQL_execstate *estate;
6631 int dno = op->d.cparam.paramid - 1;
6632 PLpgSQL_var *var;
6633
6634 /* fetch back the hook data */
6635 params = econtext->ecxt_param_list_info;
6636 estate = (PLpgSQL_execstate *) params->paramFetchArg;
6637 Assert(dno >= 0 && dno < estate->ndatums);
6638
6639 /* now we can access the target datum */
6640 var = (PLpgSQL_var *) estate->datums[dno];
6642
6643 /*
6644 * If the variable's current value is a R/W expanded object, transfer its
6645 * ownership into the expression execution context, then drop our own
6646 * reference to the value by setting the variable to NULL. That'll be
6647 * overwritten (perhaps with this same object) when control comes back
6648 * from the expression.
6649 */
6650 if (!var->isnull &&
6652 {
6654 get_eval_mcontext(estate));
6655 *op->resnull = false;
6656
6657 var->value = (Datum) 0;
6658 var->isnull = true;
6659 var->freeval = false;
6660 }
6661 else
6662 {
6663 /*
6664 * Otherwise we can pass the variable's value directly; we now know
6665 * that MakeExpandedObjectReadOnly isn't needed.
6666 */
6667 *op->resvalue = var->value;
6668 *op->resnull = var->isnull;
6669 }
6670
6671 /* safety check -- an assertion should be sufficient */
6672 Assert(var->datatype->typoid == op->d.cparam.paramtype);
6673}

References Assert(), ExprEvalStep::cparam, ExprEvalStep::d, PLpgSQL_var::datatype, DatumGetPointer(), PLpgSQL_execstate::datums, PLpgSQL_var::dtype, ExprContext::ecxt_param_list_info, PLpgSQL_var::freeval, get_eval_mcontext, PLpgSQL_var::isnull, ParamListInfoData::paramFetchArg, ExprEvalStep::paramid, ExprEvalStep::paramtype, PLPGSQL_DTYPE_VAR, ExprEvalStep::resnull, ExprEvalStep::resvalue, TransferExpandedObject(), PLpgSQL_type::typoid, PLpgSQL_var::value, and VARATT_IS_EXTERNAL_EXPANDED_RW.

Referenced by plpgsql_param_eval_var_check().

◆ plpgsql_param_fetch()

static ParamExternData * plpgsql_param_fetch ( ParamListInfo  params,
int  paramid,
bool  speculative,
ParamExternData prm 
)
static

Definition at line 6308 of file pl_exec.c.

6311{
6312 int dno;
6313 PLpgSQL_execstate *estate;
6314 PLpgSQL_expr *expr;
6315 PLpgSQL_datum *datum;
6316 bool ok = true;
6317 int32 prmtypmod;
6318
6319 /* paramid's are 1-based, but dnos are 0-based */
6320 dno = paramid - 1;
6321 Assert(dno >= 0 && dno < params->numParams);
6322
6323 /* fetch back the hook data */
6324 estate = (PLpgSQL_execstate *) params->paramFetchArg;
6325 expr = (PLpgSQL_expr *) params->parserSetupArg;
6326 Assert(params->numParams == estate->ndatums);
6327
6328 /* now we can access the target datum */
6329 datum = estate->datums[dno];
6330
6331 /*
6332 * Since copyParamList() or SerializeParamList() will try to materialize
6333 * every single parameter slot, it's important to return a dummy param
6334 * when asked for a datum that's not supposed to be used by this SQL
6335 * expression. Otherwise we risk failures in exec_eval_datum(), or
6336 * copying a lot more data than necessary.
6337 */
6338 if (!bms_is_member(dno, expr->paramnos))
6339 ok = false;
6340
6341 /*
6342 * If the access is speculative, we prefer to return no data rather than
6343 * to fail in exec_eval_datum(). Check the likely failure cases.
6344 */
6345 else if (speculative)
6346 {
6347 switch (datum->dtype)
6348 {
6349 case PLPGSQL_DTYPE_VAR:
6351 /* always safe */
6352 break;
6353
6354 case PLPGSQL_DTYPE_ROW:
6355 /* should be safe in all interesting cases */
6356 break;
6357
6358 case PLPGSQL_DTYPE_REC:
6359 /* always safe (might return NULL, that's fine) */
6360 break;
6361
6363 {
6364 PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
6365 PLpgSQL_rec *rec;
6366
6367 rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
6368
6369 /*
6370 * If record variable is NULL, don't risk anything.
6371 */
6372 if (rec->erh == NULL)
6373 ok = false;
6374
6375 /*
6376 * Look up the field's properties if we have not already,
6377 * or if the tuple descriptor ID changed since last time.
6378 */
6379 else if (unlikely(recfield->rectupledescid != rec->erh->er_tupdesc_id))
6380 {
6382 recfield->fieldname,
6383 &recfield->finfo))
6384 recfield->rectupledescid = rec->erh->er_tupdesc_id;
6385 else
6386 ok = false;
6387 }
6388 break;
6389 }
6390
6391 default:
6392 ok = false;
6393 break;
6394 }
6395 }
6396
6397 /* Return "no such parameter" if not ok */
6398 if (!ok)
6399 {
6400 prm->value = (Datum) 0;
6401 prm->isnull = true;
6402 prm->pflags = 0;
6403 prm->ptype = InvalidOid;
6404 return prm;
6405 }
6406
6407 /* OK, evaluate the value and store into the return struct */
6408 exec_eval_datum(estate, datum,
6409 &prm->ptype, &prmtypmod,
6410 &prm->value, &prm->isnull);
6411 /* We can always mark params as "const" for executor's purposes */
6412 prm->pflags = PARAM_FLAG_CONST;
6413
6414 /*
6415 * If it's a read/write expanded datum, convert reference to read-only.
6416 * (There's little point in trying to optimize read/write parameters,
6417 * given the cases in which this function is used.)
6418 */
6419 if (datum->dtype == PLPGSQL_DTYPE_VAR)
6421 prm->isnull,
6422 ((PLpgSQL_var *) datum)->datatype->typlen);
6423 else if (datum->dtype == PLPGSQL_DTYPE_REC)
6425 prm->isnull,
6426 -1);
6427
6428 return prm;
6429}
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510

References Assert(), bms_is_member(), PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, ExpandedRecordHeader::er_tupdesc_id, PLpgSQL_rec::erh, exec_eval_datum(), expanded_record_lookup_field(), PLpgSQL_recfield::fieldname, PLpgSQL_recfield::finfo, InvalidOid, ParamExternData::isnull, MakeExpandedObjectReadOnly, PLpgSQL_execstate::ndatums, ParamListInfoData::numParams, PARAM_FLAG_CONST, ParamListInfoData::paramFetchArg, PLpgSQL_expr::paramnos, ParamListInfoData::parserSetupArg, ParamExternData::pflags, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, ParamExternData::ptype, PLpgSQL_recfield::recparentno, PLpgSQL_recfield::rectupledescid, unlikely, and ParamExternData::value.

Referenced by plpgsql_estate_setup().

◆ plpgsql_subxact_cb()

void plpgsql_subxact_cb ( SubXactEvent  event,
SubTransactionId  mySubid,
SubTransactionId  parentSubid,
void *  arg 
)

◆ plpgsql_xact_cb()

void plpgsql_xact_cb ( XactEvent  event,
void *  arg 
)

Definition at line 8711 of file pl_exec.c.

8712{
8713 /*
8714 * If we are doing a clean transaction shutdown, free the EState and tell
8715 * the resowner to release whatever plancache references it has, so that
8716 * all remaining resources will be released correctly. (We don't need to
8717 * actually delete the resowner here; deletion of the
8718 * TopTransactionResourceOwner will take care of that.)
8719 *
8720 * In an abort, we expect the regular abort recovery procedures to release
8721 * everything of interest, so just clear our pointers.
8722 */
8723 if (event == XACT_EVENT_COMMIT ||
8724 event == XACT_EVENT_PARALLEL_COMMIT ||
8725 event == XACT_EVENT_PREPARE)
8726 {
8727 simple_econtext_stack = NULL;
8728
8735 }
8736 else if (event == XACT_EVENT_ABORT ||
8738 {
8739 simple_econtext_stack = NULL;
8742 }
8743}
void FreeExecutorState(EState *estate)
Definition: execUtils.c:193
void ReleaseAllPlanCacheRefsInOwner(ResourceOwner owner)
Definition: plancache.c:2379
@ XACT_EVENT_COMMIT
Definition: xact.h:128
@ XACT_EVENT_PARALLEL_COMMIT
Definition: xact.h:129
@ XACT_EVENT_ABORT
Definition: xact.h:130
@ XACT_EVENT_PARALLEL_ABORT
Definition: xact.h:131
@ XACT_EVENT_PREPARE
Definition: xact.h:132

References FreeExecutorState(), ReleaseAllPlanCacheRefsInOwner(), shared_simple_eval_estate, shared_simple_eval_resowner, simple_econtext_stack, XACT_EVENT_ABORT, XACT_EVENT_COMMIT, XACT_EVENT_PARALLEL_ABORT, XACT_EVENT_PARALLEL_COMMIT, and XACT_EVENT_PREPARE.

Referenced by _PG_init().

◆ pop_stmt_mcontext()

static void pop_stmt_mcontext ( PLpgSQL_execstate estate)
static

Definition at line 1582 of file pl_exec.c.

1583{
1584 /* We need only pop the stack */
1585 estate->stmt_mcontext = estate->stmt_mcontext_parent;
1587}
MemoryContext MemoryContextGetParent(MemoryContext context)
Definition: mcxt.c:731

References MemoryContextGetParent(), PLpgSQL_execstate::stmt_mcontext, and PLpgSQL_execstate::stmt_mcontext_parent.

Referenced by exec_stmt_block(), and exec_stmt_foreach_a().

◆ push_stmt_mcontext()

static void push_stmt_mcontext ( PLpgSQL_execstate estate)
static

Definition at line 1563 of file pl_exec.c.

1564{
1565 /* Should have done get_stmt_mcontext() first */
1566 Assert(estate->stmt_mcontext != NULL);
1567 /* Assert we've not messed up the stack linkage */
1569 /* Push it down to become the parent of any nested stmt mcontext */
1570 estate->stmt_mcontext_parent = estate->stmt_mcontext;
1571 /* And make it not available for use directly */
1572 estate->stmt_mcontext = NULL;
1573}

References Assert(), MemoryContextGetParent(), PLpgSQL_execstate::stmt_mcontext, and PLpgSQL_execstate::stmt_mcontext_parent.

Referenced by exec_stmt_foreach_a().

◆ revalidate_rectypeid()

static void revalidate_rectypeid ( PLpgSQL_rec rec)
static

Definition at line 7048 of file pl_exec.c.

7049{
7050 PLpgSQL_type *typ = rec->datatype;
7051 TypeCacheEntry *typentry;
7052
7053 if (rec->rectypeid == RECORDOID)
7054 return; /* it's RECORD, so nothing to do */
7055 Assert(typ != NULL);
7056 if (typ->tcache &&
7057 typ->tcache->tupDesc_identifier == typ->tupdesc_id)
7058 {
7059 /*
7060 * Although *typ is known up-to-date, it's possible that rectypeid
7061 * isn't, because *rec is cloned during each function startup from a
7062 * copy that we don't have a good way to update. Hence, forcibly fix
7063 * rectypeid before returning.
7064 */
7065 rec->rectypeid = typ->typoid;
7066 return;
7067 }
7068
7069 /*
7070 * typcache entry has suffered invalidation, so re-look-up the type name
7071 * if possible, and then recheck the type OID. If we don't have a
7072 * TypeName, then we just have to soldier on with the OID we've got.
7073 */
7074 if (typ->origtypname != NULL)
7075 {
7076 /* this bit should match parse_datatype() in pl_gram.y */
7078 &typ->typoid,
7079 &typ->atttypmod);
7080 }
7081
7082 /* this bit should match build_datatype() in pl_comp.c */
7083 typentry = lookup_type_cache(typ->typoid,
7086 if (typentry->typtype == TYPTYPE_DOMAIN)
7087 typentry = lookup_type_cache(typentry->domainBaseType,
7089 if (typentry->tupDesc == NULL)
7090 {
7091 /*
7092 * If we get here, user tried to replace a composite type with a
7093 * non-composite one. We're not gonna support that.
7094 */
7095 ereport(ERROR,
7096 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7097 errmsg("type %s is not composite",
7098 format_type_be(typ->typoid))));
7099 }
7100
7101 /*
7102 * Update tcache and tupdesc_id. Since we don't support changing to a
7103 * non-composite type, none of the rest of *typ needs to change.
7104 */
7105 typ->tcache = typentry;
7106 typ->tupdesc_id = typentry->tupDesc_identifier;
7107
7108 /*
7109 * Update *rec, too. (We'll deal with subsidiary RECFIELDs as needed.)
7110 */
7111 rec->rectypeid = typ->typoid;
7112}
void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName, Oid *typeid_p, int32 *typmod_p)
Definition: parse_type.c:310
TypeName * origtypname
Definition: plpgsql.h:221
TypeCacheEntry * tcache
Definition: plpgsql.h:222
uint64 tupdesc_id
Definition: plpgsql.h:223
uint64 tupDesc_identifier
Definition: typcache.h:90
char typtype
Definition: typcache.h:43
TupleDesc tupDesc
Definition: typcache.h:89
Oid domainBaseType
Definition: typcache.h:114
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:386
#define TYPECACHE_TUPDESC
Definition: typcache.h:145
#define TYPECACHE_DOMAIN_BASE_INFO
Definition: typcache.h:149

References Assert(), PLpgSQL_type::atttypmod, PLpgSQL_rec::datatype, TypeCacheEntry::domainBaseType, ereport, errcode(), errmsg(), ERROR, format_type_be(), lookup_type_cache(), PLpgSQL_type::origtypname, PLpgSQL_rec::rectypeid, PLpgSQL_type::tcache, TypeCacheEntry::tupDesc, PLpgSQL_type::tupdesc_id, TypeCacheEntry::tupDesc_identifier, TYPECACHE_DOMAIN_BASE_INFO, TYPECACHE_TUPDESC, typenameTypeIdAndMod(), PLpgSQL_type::typoid, and TypeCacheEntry::typtype.

Referenced by exec_move_row_from_datum(), instantiate_empty_record_variable(), and make_expanded_record_for_rec().

◆ setup_param_list()

static ParamListInfo setup_param_list ( PLpgSQL_execstate estate,
PLpgSQL_expr expr 
)
static

Definition at line 6260 of file pl_exec.c.

6261{
6262 ParamListInfo paramLI;
6263
6264 /*
6265 * We must have created the SPIPlan already (hence, query text has been
6266 * parsed/analyzed at least once); else we cannot rely on expr->paramnos.
6267 */
6268 Assert(expr->plan != NULL);
6269
6270 /*
6271 * We only need a ParamListInfo if the expression has parameters.
6272 */
6273 if (!bms_is_empty(expr->paramnos))
6274 {
6275 /* Use the common ParamListInfo */
6276 paramLI = estate->paramLI;
6277
6278 /*
6279 * Set up link to active expr where the hook functions can find it.
6280 * Callers must save and restore parserSetupArg if there is any chance
6281 * that they are interrupting an active use of parameters.
6282 */
6283 paramLI->parserSetupArg = expr;
6284 }
6285 else
6286 {
6287 /*
6288 * Expression requires no parameters. Be sure we represent this case
6289 * as a NULL ParamListInfo, so that plancache.c knows there is no
6290 * point in a custom plan.
6291 */
6292 paramLI = NULL;
6293 }
6294 return paramLI;
6295}
#define bms_is_empty(a)
Definition: bitmapset.h:118

References Assert(), bms_is_empty, PLpgSQL_execstate::paramLI, PLpgSQL_expr::paramnos, ParamListInfoData::parserSetupArg, and PLpgSQL_expr::plan.

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

Variable Documentation

◆ cast_expr_hash

HTAB* cast_expr_hash = NULL
static

Definition at line 178 of file pl_exec.c.

Referenced by get_cast_hashentry(), and plpgsql_estate_setup().

◆ shared_cast_hash

HTAB* shared_cast_hash = NULL
static

Definition at line 179 of file pl_exec.c.

Referenced by plpgsql_estate_setup().

◆ shared_simple_eval_estate

EState* shared_simple_eval_estate = NULL
static

Definition at line 91 of file pl_exec.c.

Referenced by plpgsql_create_econtext(), plpgsql_estate_setup(), and plpgsql_xact_cb().

◆ shared_simple_eval_resowner

ResourceOwner shared_simple_eval_resowner = NULL
static

Definition at line 102 of file pl_exec.c.

Referenced by plpgsql_create_econtext(), plpgsql_estate_setup(), and plpgsql_xact_cb().

◆ simple_econtext_stack

SimpleEcontextStackEntry* simple_econtext_stack = NULL
static