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

Go to the source code of this file.

Data Structures

struct  PreparedParamsData
 
struct  SimpleEcontextStackEntry
 
struct  plpgsql_CastHashKey
 
struct  plpgsql_CastHashEntry
 

Macros

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

Typedefs

typedef struct SimpleEcontextStackEntry SimpleEcontextStackEntry
 

Functions

static void coerce_function_result_tuple (PLpgSQL_execstate *estate, TupleDesc tupdesc)
 
static void plpgsql_exec_error_callback (void *arg)
 
static void copy_plpgsql_datums (PLpgSQL_execstate *estate, PLpgSQL_function *func)
 
static void plpgsql_fulfill_promise (PLpgSQL_execstate *estate, PLpgSQL_var *var)
 
static MemoryContext get_stmt_mcontext (PLpgSQL_execstate *estate)
 
static void push_stmt_mcontext (PLpgSQL_execstate *estate)
 
static void pop_stmt_mcontext (PLpgSQL_execstate *estate)
 
static int exec_stmt_block (PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
 
static int exec_stmts (PLpgSQL_execstate *estate, List *stmts)
 
static int exec_stmt (PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
 
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 int exec_stmt_set (PLpgSQL_execstate *estate, PLpgSQL_stmt_set *stmt)
 
static void plpgsql_estate_setup (PLpgSQL_execstate *estate, PLpgSQL_function *func, ReturnSetInfo *rsi, EState *simple_eval_estate)
 
static void exec_eval_cleanup (PLpgSQL_execstate *estate)
 
static void exec_prepare_plan (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions, bool keepplan)
 
static void exec_simple_check_plan (PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
 
static void exec_save_simple_expr (PLpgSQL_expr *expr, CachedPlan *cplan)
 
static void exec_check_rw_parameter (PLpgSQL_expr *expr, int target_dno)
 
static bool contains_target_param (Node *node, int *target_dno)
 
static bool exec_eval_simple_expr (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, Datum *result, bool *isNull, Oid *rettype, int32 *rettypmod)
 
static void exec_assign_expr (PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
 
static void exec_assign_c_string (PLpgSQL_execstate *estate, PLpgSQL_datum *target, const char *str)
 
static void exec_assign_value (PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
 
static void exec_eval_datum (PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeid, int32 *typetypmod, Datum *value, bool *isnull)
 
static int exec_eval_integer (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
 
static bool exec_eval_boolean (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
 
static Datum exec_eval_expr (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
 
static int exec_run_select (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
 
static int exec_for_query (PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt, Portal portal, bool prefetch_ok)
 
static ParamListInfo setup_param_list (PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
 
static ParamExternDataplpgsql_param_fetch (ParamListInfo params, int paramid, bool speculative, ParamExternData *workspace)
 
static void plpgsql_param_compile (ParamListInfo params, Param *param, ExprState *state, Datum *resv, bool *resnull)
 
static void plpgsql_param_eval_var (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void plpgsql_param_eval_var_ro (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void plpgsql_param_eval_recfield (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void plpgsql_param_eval_generic (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void plpgsql_param_eval_generic_ro (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void exec_move_row (PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
 
static 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 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 PreparedParamsDataexec_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, const PreparedParamsData *ppd)
 
Datum plpgsql_exec_function (PLpgSQL_function *func, FunctionCallInfo fcinfo, EState *simple_eval_estate, 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 MemoryContext shared_cast_context = NULL
 
static HTABshared_cast_hash = NULL
 

Macro Definition Documentation

◆ eval_mcontext_alloc

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

◆ eval_mcontext_alloc0

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

Definition at line 123 of file pl_exec.c.

Referenced by exec_stmt_return_next(), and make_tuple_from_row().

◆ get_eval_mcontext

◆ LOOP_RC_PROCESSING

#define LOOP_RC_PROCESSING (   looplabel,
  exit_action 
)

◆ 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:575
#define ERROR
Definition: elog.h:43
const char * name
Definition: encode.c:521
int errmsg(const char *fmt,...)
Definition: elog.c:797
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1148

Definition at line 3507 of file pl_exec.c.

Referenced by exec_stmt_raise().

Typedef Documentation

◆ SimpleEcontextStackEntry

Function Documentation

◆ assign_record_var()

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

Definition at line 8088 of file pl_exec.c.

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

8090 {
8091  Assert(rec->dtype == PLPGSQL_DTYPE_REC);
8092 
8093  /* Transfer new record object into datum_context */
8094  TransferExpandedRecord(erh, estate->datum_context);
8095 
8096  /* Free the old value ... */
8097  if (rec->erh)
8099 
8100  /* ... and install the new */
8101  rec->erh = erh;
8102 }
PLpgSQL_datum_type dtype
Definition: plpgsql.h:362
ExpandedRecordHeader * erh
Definition: plpgsql.h:379
void DeleteExpandedObject(Datum d)
#define Assert(condition)
Definition: c.h:699
#define TransferExpandedRecord(erh, cxt)
MemoryContext datum_context
Definition: plpgsql.h:1017
#define ExpandedRecordGetDatum(erh)

◆ assign_simple_var()

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

Definition at line 8047 of file pl_exec.c.

References Assert, PLpgSQL_var::datatype, DatumGetPointer, DatumIsReadWriteExpandedObject, DeleteExpandedObject(), PLpgSQL_var::dtype, PLpgSQL_var::freeval, PLpgSQL_var::isnull, pfree(), PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_VAR, PLPGSQL_PROMISE_NONE, PLpgSQL_var::promise, PLpgSQL_type::typlen, and PLpgSQL_var::value.

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

8049 {
8050  Assert(var->dtype == PLPGSQL_DTYPE_VAR ||
8051  var->dtype == PLPGSQL_DTYPE_PROMISE);
8052  /* Free the old value if needed */
8053  if (var->freeval)
8054  {
8056  var->isnull,
8057  var->datatype->typlen))
8059  else
8060  pfree(DatumGetPointer(var->value));
8061  }
8062  /* Assign new value to datum */
8063  var->value = newvalue;
8064  var->isnull = isnull;
8065  var->freeval = freeable;
8066 
8067  /*
8068  * If it's a promise variable, then either we just assigned the promised
8069  * value, or the user explicitly assigned an overriding value. Either
8070  * way, cancel the promise.
8071  */
8073 }
PLpgSQL_promise_type promise
Definition: plpgsql.h:318
PLpgSQL_datum_type dtype
Definition: plpgsql.h:287
PLpgSQL_type * datatype
Definition: plpgsql.h:296
void pfree(void *pointer)
Definition: mcxt.c:1031
bool freeval
Definition: plpgsql.h:311
Datum value
Definition: plpgsql.h:309
void DeleteExpandedObject(Datum d)
#define Assert(condition)
Definition: c.h:699
#define DatumIsReadWriteExpandedObject(d, isnull, typlen)
#define DatumGetPointer(X)
Definition: postgres.h:532
int16 typlen
Definition: plpgsql.h:204
bool isnull
Definition: plpgsql.h:310

◆ assign_text_var()

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

Definition at line 8079 of file pl_exec.c.

References assign_simple_var(), and CStringGetTextDatum.

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

8080 {
8081  assign_simple_var(estate, var, CStringGetTextDatum(str), false, true);
8082 }
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8047
#define CStringGetTextDatum(s)
Definition: builtins.h:95

◆ coerce_function_result_tuple()

static void coerce_function_result_tuple ( PLpgSQL_execstate estate,
TupleDesc  tupdesc 
)
static

Definition at line 771 of file pl_exec.c.

References Assert, convert_tuples_by_position(), DatumGetEOHP(), DatumGetPointer, deconstruct_composite_datum(), do_convert_tuple(), ER_MAGIC, ExpandedRecordHeader::er_magic, expanded_record_get_tupdesc(), expanded_record_get_tuple(), gettext_noop, PointerGetDatum, ReleaseTupleDesc, PLpgSQL_execstate::rettype, PLpgSQL_execstate::retval, SPI_datumTransfer(), SPI_returntuple(), type_is_rowtype(), and VARATT_IS_EXTERNAL_EXPANDED.

Referenced by plpgsql_exec_function().

772 {
773  HeapTuple rettup;
774  TupleDesc retdesc;
775  TupleConversionMap *tupmap;
776 
777  /* We assume exec_stmt_return verified that result is composite */
778  Assert(type_is_rowtype(estate->rettype));
779 
780  /* We can special-case expanded records for speed */
782  {
784 
785  Assert(erh->er_magic == ER_MAGIC);
786 
787  /* Extract record's TupleDesc */
788  retdesc = expanded_record_get_tupdesc(erh);
789 
790  /* check rowtype compatibility */
791  tupmap = convert_tuples_by_position(retdesc,
792  tupdesc,
793  gettext_noop("returned record type does not match expected record type"));
794 
795  /* it might need conversion */
796  if (tupmap)
797  {
798  rettup = expanded_record_get_tuple(erh);
799  Assert(rettup);
800  rettup = do_convert_tuple(rettup, tupmap);
801 
802  /*
803  * Copy tuple to upper executor memory, as a tuple Datum. Make
804  * sure it is labeled with the caller-supplied tuple type.
805  */
806  estate->retval = PointerGetDatum(SPI_returntuple(rettup, tupdesc));
807  /* no need to free map, we're about to return anyway */
808  }
809  else
810  {
811  /*
812  * We need only copy result into upper executor memory context.
813  * However, if we have a R/W expanded datum, we can just transfer
814  * its ownership out to the upper executor context.
815  */
816  estate->retval = SPI_datumTransfer(estate->retval,
817  false,
818  -1);
819  }
820  }
821  else
822  {
823  /* Convert composite datum to a HeapTuple and TupleDesc */
824  HeapTupleData tmptup;
825 
826  retdesc = deconstruct_composite_datum(estate->retval, &tmptup);
827  rettup = &tmptup;
828 
829  /* check rowtype compatibility */
830  tupmap = convert_tuples_by_position(retdesc,
831  tupdesc,
832  gettext_noop("returned record type does not match expected record type"));
833 
834  /* it might need conversion */
835  if (tupmap)
836  rettup = do_convert_tuple(rettup, tupmap);
837 
838  /*
839  * Copy tuple to upper executor memory, as a tuple Datum. Make sure
840  * it is labeled with the caller-supplied tuple type.
841  */
842  estate->retval = PointerGetDatum(SPI_returntuple(rettup, tupdesc));
843 
844  /* no need to free map, we're about to return anyway */
845 
846  ReleaseTupleDesc(retdesc);
847  }
848 }
HeapTuple expanded_record_get_tuple(ExpandedRecordHeader *erh)
HeapTupleHeader SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc)
Definition: spi.c:752
#define VARATT_IS_EXTERNAL_EXPANDED(PTR)
Definition: postgres.h:322
TupleConversionMap * convert_tuples_by_position(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:66
#define PointerGetDatum(X)
Definition: postgres.h:539
#define gettext_noop(x)
Definition: c.h:1036
static TupleDesc deconstruct_composite_datum(Datum value, HeapTupleData *tmptup)
Definition: pl_exec.c:7093
Datum SPI_datumTransfer(Datum value, bool typByVal, int typLen)
Definition: spi.c:1041
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2409
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29
#define ER_MAGIC
#define Assert(condition)
Definition: c.h:699
HeapTuple do_convert_tuple(HeapTuple tuple, TupleConversionMap *map)
Definition: tupconvert.c:354
#define DatumGetPointer(X)
Definition: postgres.h:532
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:124

◆ compatible_tupdescs()

static bool compatible_tupdescs ( TupleDesc  src_tupdesc,
TupleDesc  dst_tupdesc 
)
static

Definition at line 6994 of file pl_exec.c.

References i, tupleDesc::natts, and TupleDescAttr.

Referenced by exec_for_query(), and exec_move_row().

6995 {
6996  int i;
6997 
6998  /* Possibly we could allow src_tupdesc to have extra columns? */
6999  if (dst_tupdesc->natts != src_tupdesc->natts)
7000  return false;
7001 
7002  for (i = 0; i < dst_tupdesc->natts; i++)
7003  {
7004  Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
7005  Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
7006 
7007  if (dattr->attisdropped != sattr->attisdropped)
7008  return false;
7009  if (!dattr->attisdropped)
7010  {
7011  /* Normal columns must match by type and typmod */
7012  if (dattr->atttypid != sattr->atttypid ||
7013  (dattr->atttypmod >= 0 &&
7014  dattr->atttypmod != sattr->atttypmod))
7015  return false;
7016  }
7017  else
7018  {
7019  /* Dropped columns are OK as long as length/alignment match */
7020  if (dattr->attlen != sattr->attlen ||
7021  dattr->attalign != sattr->attalign)
7022  return false;
7023  }
7024  }
7025  return true;
7026 }
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
int natts
Definition: tupdesc.h:82
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
int i

◆ contains_target_param()

static bool contains_target_param ( Node node,
int *  target_dno 
)
static

Definition at line 7878 of file pl_exec.c.

References expression_tree_walker(), IsA, PARAM_EXTERN, Param::paramid, and Param::paramkind.

Referenced by exec_check_rw_parameter().

7879 {
7880  if (node == NULL)
7881  return false;
7882  if (IsA(node, Param))
7883  {
7884  Param *param = (Param *) node;
7885 
7886  if (param->paramkind == PARAM_EXTERN &&
7887  param->paramid == *target_dno + 1)
7888  return true;
7889  return false;
7890  }
7892  (void *) target_dno);
7893 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
ParamKind paramkind
Definition: primnodes.h:245
static bool contains_target_param(Node *node, int *target_dno)
Definition: pl_exec.c:7878
int paramid
Definition: primnodes.h:246
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1834

◆ convert_value_to_string()

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

Definition at line 7380 of file pl_exec.c.

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

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

7381 {
7382  char *result;
7383  MemoryContext oldcontext;
7384  Oid typoutput;
7385  bool typIsVarlena;
7386 
7387  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7388  getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
7389  result = OidOutputFunctionCall(typoutput, value);
7390  MemoryContextSwitchTo(oldcontext);
7391 
7392  return result;
7393 }
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2650
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned int Oid
Definition: postgres_ext.h:31
#define get_eval_mcontext(estate)
Definition: pl_exec.c:119
static struct @131 value
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1832

◆ copy_plpgsql_datums()

static void copy_plpgsql_datums ( PLpgSQL_execstate estate,
PLpgSQL_function func 
)
static

Definition at line 1206 of file pl_exec.c.

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

1208 {
1209  int ndatums = estate->ndatums;
1210  PLpgSQL_datum **indatums;
1211  PLpgSQL_datum **outdatums;
1212  char *workspace;
1213  char *ws_next;
1214  int i;
1215 
1216  /* Allocate local datum-pointer array */
1217  estate->datums = (PLpgSQL_datum **)
1218  palloc(sizeof(PLpgSQL_datum *) * ndatums);
1219 
1220  /*
1221  * To reduce palloc overhead, we make a single palloc request for all the
1222  * space needed for locally-instantiated datums.
1223  */
1224  workspace = palloc(func->copiable_size);
1225  ws_next = workspace;
1226 
1227  /* Fill datum-pointer array, copying datums into workspace as needed */
1228  indatums = func->datums;
1229  outdatums = estate->datums;
1230  for (i = 0; i < ndatums; i++)
1231  {
1232  PLpgSQL_datum *indatum = indatums[i];
1233  PLpgSQL_datum *outdatum;
1234 
1235  /* This must agree with plpgsql_finish_datums on what is copiable */
1236  switch (indatum->dtype)
1237  {
1238  case PLPGSQL_DTYPE_VAR:
1239  case PLPGSQL_DTYPE_PROMISE:
1240  outdatum = (PLpgSQL_datum *) ws_next;
1241  memcpy(outdatum, indatum, sizeof(PLpgSQL_var));
1242  ws_next += MAXALIGN(sizeof(PLpgSQL_var));
1243  break;
1244 
1245  case PLPGSQL_DTYPE_REC:
1246  outdatum = (PLpgSQL_datum *) ws_next;
1247  memcpy(outdatum, indatum, sizeof(PLpgSQL_rec));
1248  ws_next += MAXALIGN(sizeof(PLpgSQL_rec));
1249  break;
1250 
1251  case PLPGSQL_DTYPE_ROW:
1254 
1255  /*
1256  * These datum records are read-only at runtime, so no need to
1257  * copy them (well, RECFIELD and ARRAYELEM contain cached
1258  * data, but we'd just as soon centralize the caching anyway).
1259  */
1260  outdatum = indatum;
1261  break;
1262 
1263  default:
1264  elog(ERROR, "unrecognized dtype: %d", indatum->dtype);
1265  outdatum = NULL; /* keep compiler quiet */
1266  break;
1267  }
1268 
1269  outdatums[i] = outdatum;
1270  }
1271 
1272  Assert(ws_next == workspace + func->copiable_size);
1273 }
PLpgSQL_datum ** datums
Definition: plpgsql.h:964
PLpgSQL_datum_type dtype
Definition: plpgsql.h:253
PLpgSQL_datum ** datums
Definition: plpgsql.h:1015
#define ERROR
Definition: elog.h:43
#define Assert(condition)
Definition: c.h:699
#define MAXALIGN(LEN)
Definition: c.h:652
void * palloc(Size size)
Definition: mcxt.c:924
int i
Size copiable_size
Definition: plpgsql.h:965
#define elog
Definition: elog.h:219

◆ deconstruct_composite_datum()

static TupleDesc deconstruct_composite_datum ( Datum  value,
HeapTupleData tmptup 
)
static

Definition at line 7093 of file pl_exec.c.

References DatumGetHeapTupleHeader, HeapTupleHeaderGetDatumLength, HeapTupleHeaderGetTypeId, HeapTupleHeaderGetTypMod, InvalidOid, ItemPointerSetInvalid, lookup_rowtype_tupdesc(), HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, and HeapTupleData::t_tableOid.

Referenced by coerce_function_result_tuple(), exec_stmt_return_next(), and plpgsql_exec_trigger().

7094 {
7095  HeapTupleHeader td;
7096  Oid tupType;
7097  int32 tupTypmod;
7098 
7099  /* Get tuple body (note this could involve detoasting) */
7101 
7102  /* Build a temporary HeapTuple control structure */
7103  tmptup->t_len = HeapTupleHeaderGetDatumLength(td);
7104  ItemPointerSetInvalid(&(tmptup->t_self));
7105  tmptup->t_tableOid = InvalidOid;
7106  tmptup->t_data = td;
7107 
7108  /* Extract rowtype info and find a tupdesc */
7109  tupType = HeapTupleHeaderGetTypeId(td);
7110  tupTypmod = HeapTupleHeaderGetTypMod(td);
7111  return lookup_rowtype_tupdesc(tupType, tupTypmod);
7112 }
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1641
unsigned int Oid
Definition: postgres_ext.h:31
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:264
signed int int32
Definition: c.h:313
HeapTupleHeader t_data
Definition: htup.h:68
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:472
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
Oid t_tableOid
Definition: htup.h:66
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:462
static struct @131 value
#define InvalidOid
Definition: postgres_ext.h:36
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:150
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:456

◆ exception_matches_conditions()

static bool exception_matches_conditions ( ErrorData edata,
PLpgSQL_condition cond 
)
static

Definition at line 1492 of file pl_exec.c.

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

Referenced by exec_stmt_block().

1493 {
1494  for (; cond != NULL; cond = cond->next)
1495  {
1496  int sqlerrstate = cond->sqlerrstate;
1497 
1498  /*
1499  * OTHERS matches everything *except* query-canceled and
1500  * assert-failure. If you're foolish enough, you can match those
1501  * explicitly.
1502  */
1503  if (sqlerrstate == 0)
1504  {
1505  if (edata->sqlerrcode != ERRCODE_QUERY_CANCELED &&
1506  edata->sqlerrcode != ERRCODE_ASSERT_FAILURE)
1507  return true;
1508  }
1509  /* Exact match? */
1510  else if (edata->sqlerrcode == sqlerrstate)
1511  return true;
1512  /* Category match? */
1513  else if (ERRCODE_IS_CATEGORY(sqlerrstate) &&
1514  ERRCODE_TO_CATEGORY(edata->sqlerrcode) == sqlerrstate)
1515  return true;
1516  }
1517  return false;
1518 }
#define ERRCODE_IS_CATEGORY(ec)
Definition: elog.h:68
int sqlerrcode
Definition: elog.h:342
struct PLpgSQL_condition * next
Definition: plpgsql.h:455
#define ERRCODE_TO_CATEGORY(ec)
Definition: elog.h:67

◆ exec_assign_c_string()

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

Definition at line 4826 of file pl_exec.c.

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

Referenced by exec_stmt_getdiag().

4828 {
4829  text *value;
4830  MemoryContext oldcontext;
4831 
4832  /* Use eval_mcontext for short-lived text value */
4833  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
4834  if (str != NULL)
4835  value = cstring_to_text(str);
4836  else
4837  value = cstring_to_text("");
4838  MemoryContextSwitchTo(oldcontext);
4839 
4840  exec_assign_value(estate, target, PointerGetDatum(value), false,
4841  TEXTOID, -1);
4842 }
#define PointerGetDatum(X)
Definition: postgres.h:539
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define get_eval_mcontext(estate)
Definition: pl_exec.c:119
static struct @131 value
text * cstring_to_text(const char *s)
Definition: varlena.c:149
Definition: c.h:516
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:4854

◆ exec_assign_expr()

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

Definition at line 4789 of file pl_exec.c.

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

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

4791 {
4792  Datum value;
4793  bool isnull;
4794  Oid valtype;
4795  int32 valtypmod;
4796 
4797  /*
4798  * If first time through, create a plan for this expression, and then see
4799  * if we can pass the target variable as a read-write parameter to the
4800  * expression. (This is a bit messy, but it seems cleaner than modifying
4801  * the API of exec_eval_expr for the purpose.)
4802  */
4803  if (expr->plan == NULL)
4804  {
4805  exec_prepare_plan(estate, expr, 0, true);
4806  if (target->dtype == PLPGSQL_DTYPE_VAR)
4807  exec_check_rw_parameter(expr, target->dno);
4808  }
4809 
4810  value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod);
4811  exec_assign_value(estate, target, value, isnull, valtype, valtypmod);
4812  exec_eval_cleanup(estate);
4813 }
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions, bool keepplan)
Definition: pl_exec.c:3943
static void exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno)
Definition: pl_exec.c:7801
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:3922
unsigned int Oid
Definition: postgres_ext.h:31
PLpgSQL_datum_type dtype
Definition: plpgsql.h:253
SPIPlanPtr plan
Definition: plpgsql.h:218
signed int int32
Definition: c.h:313
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5650
uintptr_t Datum
Definition: postgres.h:365
static struct @131 value
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:4854

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

References array_set_element(), PLpgSQL_arrayelem::arrayparentno, PLpgSQL_arrayelem::arraytyplen, PLpgSQL_arrayelem::arraytypmod, PLpgSQL_arrayelem::arraytypoid, Assert, assign_simple_var(), PLpgSQL_type::atttypmod, construct_empty_array(), PLpgSQL_var::datatype, PLpgSQL_execstate::datum_context, DatumGetPointer, PLpgSQL_execstate::datums, datumTransfer(), PLpgSQL_datum::dtype, PLpgSQL_arrayelem::elemtypalign, PLpgSQL_arrayelem::elemtypbyval, PLpgSQL_arrayelem::elemtyplen, PLpgSQL_arrayelem::elemtypoid, elog, ExpandedRecordHeader::er_tupdesc_id, ereport, PLpgSQL_rec::erh, errcode(), errmsg(), ERROR, PLpgSQL_execstate::eval_tuptable, exec_cast_value(), exec_eval_datum(), exec_eval_integer(), 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, get_element_type(), get_eval_mcontext, get_typlen(), get_typlenbyvalalign(), getBaseTypeAndTypmod(), i, instantiate_empty_record_variable(), PLpgSQL_var::isnull, MAXDIM, MemoryContextSwitchTo(), PLpgSQL_var::notnull, PLpgSQL_rec::notnull, OidIsValid, PLpgSQL_arrayelem::parenttypmod, PLpgSQL_arrayelem::parenttypoid, PLPGSQL_DTYPE_ARRAYELEM, PLPGSQL_DTYPE_PROMISE, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, PLPGSQL_PROMISE_NONE, PointerGetDatum, PLpgSQL_var::promise, PLpgSQL_recfield::recparentno, PLpgSQL_recfield::rectupledescid, PLpgSQL_var::refname, PLpgSQL_rec::refname, SPI_freetuptable(), PLpgSQL_arrayelem::subscript, PLpgSQL_type::typbyval, type_is_rowtype(), PLpgSQL_type::typisarray, PLpgSQL_type::typlen, PLpgSQL_type::typoid, unlikely, PLpgSQL_var::value, and VARATT_IS_EXTERNAL_EXPANDED_RW.

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

4858 {
4859  switch (target->dtype)
4860  {
4861  case PLPGSQL_DTYPE_VAR:
4862  case PLPGSQL_DTYPE_PROMISE:
4863  {
4864  /*
4865  * Target is a variable
4866  */
4867  PLpgSQL_var *var = (PLpgSQL_var *) target;
4868  Datum newvalue;
4869 
4870  newvalue = exec_cast_value(estate,
4871  value,
4872  &isNull,
4873  valtype,
4874  valtypmod,
4875  var->datatype->typoid,
4876  var->datatype->atttypmod);
4877 
4878  if (isNull && var->notnull)
4879  ereport(ERROR,
4880  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4881  errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
4882  var->refname)));
4883 
4884  /*
4885  * If type is by-reference, copy the new value (which is
4886  * probably in the eval_mcontext) into the procedure's main
4887  * memory context. But if it's a read/write reference to an
4888  * expanded object, no physical copy needs to happen; at most
4889  * we need to reparent the object's memory context.
4890  *
4891  * If it's an array, we force the value to be stored in R/W
4892  * expanded form. This wins if the function later does, say,
4893  * a lot of array subscripting operations on the variable, and
4894  * otherwise might lose. We might need to use a different
4895  * heuristic, but it's too soon to tell. Also, are there
4896  * cases where it'd be useful to force non-array values into
4897  * expanded form?
4898  */
4899  if (!var->datatype->typbyval && !isNull)
4900  {
4901  if (var->datatype->typisarray &&
4903  {
4904  /* array and not already R/W, so apply expand_array */
4905  newvalue = expand_array(newvalue,
4906  estate->datum_context,
4907  NULL);
4908  }
4909  else
4910  {
4911  /* else transfer value if R/W, else just datumCopy */
4912  newvalue = datumTransfer(newvalue,
4913  false,
4914  var->datatype->typlen);
4915  }
4916  }
4917 
4918  /*
4919  * Now free the old value, if any, and assign the new one. But
4920  * skip the assignment if old and new values are the same.
4921  * Note that for expanded objects, this test is necessary and
4922  * cannot reliably be made any earlier; we have to be looking
4923  * at the object's standard R/W pointer to be sure pointer
4924  * equality is meaningful.
4925  *
4926  * Also, if it's a promise variable, we should disarm the
4927  * promise in any case --- otherwise, assigning null to an
4928  * armed promise variable would fail to disarm the promise.
4929  */
4930  if (var->value != newvalue || var->isnull || isNull)
4931  assign_simple_var(estate, var, newvalue, isNull,
4932  (!var->datatype->typbyval && !isNull));
4933  else
4935  break;
4936  }
4937 
4938  case PLPGSQL_DTYPE_ROW:
4939  {
4940  /*
4941  * Target is a row variable
4942  */
4943  PLpgSQL_row *row = (PLpgSQL_row *) target;
4944 
4945  if (isNull)
4946  {
4947  /* If source is null, just assign nulls to the row */
4948  exec_move_row(estate, (PLpgSQL_variable *) row,
4949  NULL, NULL);
4950  }
4951  else
4952  {
4953  /* Source must be of RECORD or composite type */
4954  if (!type_is_rowtype(valtype))
4955  ereport(ERROR,
4956  (errcode(ERRCODE_DATATYPE_MISMATCH),
4957  errmsg("cannot assign non-composite value to a row variable")));
4959  value);
4960  }
4961  break;
4962  }
4963 
4964  case PLPGSQL_DTYPE_REC:
4965  {
4966  /*
4967  * Target is a record variable
4968  */
4969  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
4970 
4971  if (isNull)
4972  {
4973  if (rec->notnull)
4974  ereport(ERROR,
4975  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4976  errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
4977  rec->refname)));
4978 
4979  /* Set variable to a simple NULL */
4980  exec_move_row(estate, (PLpgSQL_variable *) rec,
4981  NULL, NULL);
4982  }
4983  else
4984  {
4985  /* Source must be of RECORD or composite type */
4986  if (!type_is_rowtype(valtype))
4987  ereport(ERROR,
4988  (errcode(ERRCODE_DATATYPE_MISMATCH),
4989  errmsg("cannot assign non-composite value to a record variable")));
4991  value);
4992  }
4993  break;
4994  }
4995 
4997  {
4998  /*
4999  * Target is a field of a record
5000  */
5001  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) target;
5002  PLpgSQL_rec *rec;
5003  ExpandedRecordHeader *erh;
5004 
5005  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5006  erh = rec->erh;
5007 
5008  /*
5009  * If record variable is NULL, instantiate it if it has a
5010  * named composite type, else complain. (This won't change
5011  * the logical state of the record, but if we successfully
5012  * assign below, the unassigned fields will all become NULLs.)
5013  */
5014  if (erh == NULL)
5015  {
5016  instantiate_empty_record_variable(estate, rec);
5017  erh = rec->erh;
5018  }
5019 
5020  /*
5021  * Look up the field's properties if we have not already, or
5022  * if the tuple descriptor ID changed since last time.
5023  */
5024  if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
5025  {
5027  recfield->fieldname,
5028  &recfield->finfo))
5029  ereport(ERROR,
5030  (errcode(ERRCODE_UNDEFINED_COLUMN),
5031  errmsg("record \"%s\" has no field \"%s\"",
5032  rec->refname, recfield->fieldname)));
5033  recfield->rectupledescid = erh->er_tupdesc_id;
5034  }
5035 
5036  /* We don't support assignments to system columns. */
5037  if (recfield->finfo.fnumber <= 0)
5038  ereport(ERROR,
5039  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5040  errmsg("cannot assign to system column \"%s\"",
5041  recfield->fieldname)));
5042 
5043  /* Cast the new value to the right type, if needed. */
5044  value = exec_cast_value(estate,
5045  value,
5046  &isNull,
5047  valtype,
5048  valtypmod,
5049  recfield->finfo.ftypeid,
5050  recfield->finfo.ftypmod);
5051 
5052  /* And assign it. */
5053  expanded_record_set_field(erh, recfield->finfo.fnumber,
5054  value, isNull);
5055  break;
5056  }
5057 
5059  {
5060  /*
5061  * Target is an element of an array
5062  */
5063  PLpgSQL_arrayelem *arrayelem;
5064  int nsubscripts;
5065  int i;
5066  PLpgSQL_expr *subscripts[MAXDIM];
5067  int subscriptvals[MAXDIM];
5068  Datum oldarraydatum,
5069  newarraydatum,
5070  coerced_value;
5071  bool oldarrayisnull;
5072  Oid parenttypoid;
5073  int32 parenttypmod;
5074  SPITupleTable *save_eval_tuptable;
5075  MemoryContext oldcontext;
5076 
5077  /*
5078  * We need to do subscript evaluation, which might require
5079  * evaluating general expressions; and the caller might have
5080  * done that too in order to prepare the input Datum. We have
5081  * to save and restore the caller's SPI_execute result, if
5082  * any.
5083  */
5084  save_eval_tuptable = estate->eval_tuptable;
5085  estate->eval_tuptable = NULL;
5086 
5087  /*
5088  * To handle constructs like x[1][2] := something, we have to
5089  * be prepared to deal with a chain of arrayelem datums. Chase
5090  * back to find the base array datum, and save the subscript
5091  * expressions as we go. (We are scanning right to left here,
5092  * but want to evaluate the subscripts left-to-right to
5093  * minimize surprises.) Note that arrayelem is left pointing
5094  * to the leftmost arrayelem datum, where we will cache the
5095  * array element type data.
5096  */
5097  nsubscripts = 0;
5098  do
5099  {
5100  arrayelem = (PLpgSQL_arrayelem *) target;
5101  if (nsubscripts >= MAXDIM)
5102  ereport(ERROR,
5103  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5104  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
5105  nsubscripts + 1, MAXDIM)));
5106  subscripts[nsubscripts++] = arrayelem->subscript;
5107  target = estate->datums[arrayelem->arrayparentno];
5108  } while (target->dtype == PLPGSQL_DTYPE_ARRAYELEM);
5109 
5110  /* Fetch current value of array datum */
5111  exec_eval_datum(estate, target,
5112  &parenttypoid, &parenttypmod,
5113  &oldarraydatum, &oldarrayisnull);
5114 
5115  /* Update cached type data if necessary */
5116  if (arrayelem->parenttypoid != parenttypoid ||
5117  arrayelem->parenttypmod != parenttypmod)
5118  {
5119  Oid arraytypoid;
5120  int32 arraytypmod = parenttypmod;
5121  int16 arraytyplen;
5122  Oid elemtypoid;
5123  int16 elemtyplen;
5124  bool elemtypbyval;
5125  char elemtypalign;
5126 
5127  /* If target is domain over array, reduce to base type */
5128  arraytypoid = getBaseTypeAndTypmod(parenttypoid,
5129  &arraytypmod);
5130 
5131  /* ... and identify the element type */
5132  elemtypoid = get_element_type(arraytypoid);
5133  if (!OidIsValid(elemtypoid))
5134  ereport(ERROR,
5135  (errcode(ERRCODE_DATATYPE_MISMATCH),
5136  errmsg("subscripted object is not an array")));
5137 
5138  /* Collect needed data about the types */
5139  arraytyplen = get_typlen(arraytypoid);
5140 
5141  get_typlenbyvalalign(elemtypoid,
5142  &elemtyplen,
5143  &elemtypbyval,
5144  &elemtypalign);
5145 
5146  /* Now safe to update the cached data */
5147  arrayelem->parenttypoid = parenttypoid;
5148  arrayelem->parenttypmod = parenttypmod;
5149  arrayelem->arraytypoid = arraytypoid;
5150  arrayelem->arraytypmod = arraytypmod;
5151  arrayelem->arraytyplen = arraytyplen;
5152  arrayelem->elemtypoid = elemtypoid;
5153  arrayelem->elemtyplen = elemtyplen;
5154  arrayelem->elemtypbyval = elemtypbyval;
5155  arrayelem->elemtypalign = elemtypalign;
5156  }
5157 
5158  /*
5159  * Evaluate the subscripts, switch into left-to-right order.
5160  * Like the expression built by ExecInitArrayRef(), complain
5161  * if any subscript is null.
5162  */
5163  for (i = 0; i < nsubscripts; i++)
5164  {
5165  bool subisnull;
5166 
5167  subscriptvals[i] =
5168  exec_eval_integer(estate,
5169  subscripts[nsubscripts - 1 - i],
5170  &subisnull);
5171  if (subisnull)
5172  ereport(ERROR,
5173  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5174  errmsg("array subscript in assignment must not be null")));
5175 
5176  /*
5177  * Clean up in case the subscript expression wasn't
5178  * simple. We can't do exec_eval_cleanup, but we can do
5179  * this much (which is safe because the integer subscript
5180  * value is surely pass-by-value), and we must do it in
5181  * case the next subscript expression isn't simple either.
5182  */
5183  if (estate->eval_tuptable != NULL)
5185  estate->eval_tuptable = NULL;
5186  }
5187 
5188  /* Now we can restore caller's SPI_execute result if any. */
5189  Assert(estate->eval_tuptable == NULL);
5190  estate->eval_tuptable = save_eval_tuptable;
5191 
5192  /* Coerce source value to match array element type. */
5193  coerced_value = exec_cast_value(estate,
5194  value,
5195  &isNull,
5196  valtype,
5197  valtypmod,
5198  arrayelem->elemtypoid,
5199  arrayelem->arraytypmod);
5200 
5201  /*
5202  * If the original array is null, cons up an empty array so
5203  * that the assignment can proceed; we'll end with a
5204  * one-element array containing just the assigned-to
5205  * subscript. This only works for varlena arrays, though; for
5206  * fixed-length array types we skip the assignment. We can't
5207  * support assignment of a null entry into a fixed-length
5208  * array, either, so that's a no-op too. This is all ugly but
5209  * corresponds to the current behavior of execExpr*.c.
5210  */
5211  if (arrayelem->arraytyplen > 0 && /* fixed-length array? */
5212  (oldarrayisnull || isNull))
5213  return;
5214 
5215  /* empty array, if any, and newarraydatum are short-lived */
5216  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5217 
5218  if (oldarrayisnull)
5219  oldarraydatum = PointerGetDatum(construct_empty_array(arrayelem->elemtypoid));
5220 
5221  /*
5222  * Build the modified array value.
5223  */
5224  newarraydatum = array_set_element(oldarraydatum,
5225  nsubscripts,
5226  subscriptvals,
5227  coerced_value,
5228  isNull,
5229  arrayelem->arraytyplen,
5230  arrayelem->elemtyplen,
5231  arrayelem->elemtypbyval,
5232  arrayelem->elemtypalign);
5233 
5234  MemoryContextSwitchTo(oldcontext);
5235 
5236  /*
5237  * Assign the new array to the base variable. It's never NULL
5238  * at this point. Note that if the target is a domain,
5239  * coercing the base array type back up to the domain will
5240  * happen within exec_assign_value.
5241  */
5242  exec_assign_value(estate, target,
5243  newarraydatum,
5244  false,
5245  arrayelem->arraytypoid,
5246  arrayelem->arraytypmod);
5247  break;
5248  }
5249 
5250  default:
5251  elog(ERROR, "unrecognized dtype: %d", target->dtype);
5252  }
5253 }
PLpgSQL_promise_type promise
Definition: plpgsql.h:318
signed short int16
Definition: c.h:312
int16 elemtyplen
Definition: plpgsql.h:418
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2292
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1039
char * refname
Definition: plpgsql.h:289
static void exec_eval_datum(PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeid, int32 *typetypmod, Datum *value, bool *isnull)
Definition: pl_exec.c:5273
bool expanded_record_lookup_field(ExpandedRecordHeader *erh, const char *fieldname, ExpandedRecordFieldInfo *finfo)
#define MAXDIM
Definition: c.h:496
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2502
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2025
#define PointerGetDatum(X)
Definition: postgres.h:539
PLpgSQL_type * datatype
Definition: plpgsql.h:296
Datum expand_array(Datum arraydatum, MemoryContext parentcontext, ArrayMetaState *metacache)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void instantiate_empty_record_variable(PLpgSQL_execstate *estate, PLpgSQL_rec *rec)
Definition: pl_exec.c:7348
ExpandedRecordHeader * erh
Definition: plpgsql.h:379
int errcode(int sqlerrcode)
Definition: elog.c:575
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8047
Datum array_set_element(Datum arraydatum, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:2187
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3398
unsigned int Oid
Definition: postgres_ext.h:31
static void exec_move_row_from_datum(PLpgSQL_execstate *estate, PLpgSQL_variable *target, Datum value)
Definition: pl_exec.c:7124
PLpgSQL_datum_type dtype
Definition: plpgsql.h:253
#define OidIsValid(objectId)
Definition: c.h:605
char * refname
Definition: plpgsql.h:364
signed int int32
Definition: c.h:313
PLpgSQL_datum ** datums
Definition: plpgsql.h:1015
int32 arraytypmod
Definition: plpgsql.h:415
bool notnull
Definition: plpgsql.h:292
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7409
#define ERROR
Definition: elog.h:43
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2409
#define ereport(elevel, rest)
Definition: elog.h:122
uint64 rectupledescid
Definition: plpgsql.h:394
bool typbyval
Definition: plpgsql.h:205
#define get_eval_mcontext(estate)
Definition: pl_exec.c:119
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1066
bool typisarray
Definition: plpgsql.h:208
uintptr_t Datum
Definition: postgres.h:365
static int exec_eval_integer(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
Definition: pl_exec.c:5604
ExpandedRecordFieldInfo finfo
Definition: plpgsql.h:395
int32 parenttypmod
Definition: plpgsql.h:413
static struct @131 value
Datum value
Definition: plpgsql.h:309
Datum datumTransfer(Datum value, bool typByVal, int typLen)
Definition: datum.c:190
#define Assert(condition)
Definition: c.h:699
int16 arraytyplen
Definition: plpgsql.h:416
#define DatumGetPointer(X)
Definition: postgres.h:532
MemoryContext datum_context
Definition: plpgsql.h:1017
int16 get_typlen(Oid typid)
Definition: lsyscache.c:1951
int errmsg(const char *fmt,...)
Definition: elog.c:797
int32 atttypmod
Definition: plpgsql.h:209
static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
Definition: pl_exec.c:6608
int i
PLpgSQL_expr * subscript
Definition: plpgsql.h:408
#define VARATT_IS_EXTERNAL_EXPANDED_RW(PTR)
Definition: postgres.h:320
#define unlikely(x)
Definition: c.h:208
#define elog
Definition: elog.h:219
int16 typlen
Definition: plpgsql.h:204
bool notnull
Definition: plpgsql.h:367
char * fieldname
Definition: plpgsql.h:391
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:4854
#define expanded_record_set_field(erh, fnumber, newValue, isnull)
bool isnull
Definition: plpgsql.h:310
Oid typoid
Definition: plpgsql.h:202

◆ exec_cast_value()

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

Definition at line 7409 of file pl_exec.c.

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_assign_value(), exec_eval_boolean(), exec_eval_integer(), exec_move_row_from_fields(), exec_stmt_fori(), exec_stmt_return_next(), and plpgsql_exec_function().

7413 {
7414  /*
7415  * If the type of the given value isn't what's requested, convert it.
7416  */
7417  if (valtype != reqtype ||
7418  (valtypmod != reqtypmod && reqtypmod != -1))
7419  {
7420  plpgsql_CastHashEntry *cast_entry;
7421 
7422  cast_entry = get_cast_hashentry(estate,
7423  valtype, valtypmod,
7424  reqtype, reqtypmod);
7425  if (cast_entry)
7426  {
7427  ExprContext *econtext = estate->eval_econtext;
7428  MemoryContext oldcontext;
7429 
7430  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7431 
7432  econtext->caseValue_datum = value;
7433  econtext->caseValue_isNull = *isnull;
7434 
7435  cast_entry->cast_in_use = true;
7436 
7437  value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
7438  isnull);
7439 
7440  cast_entry->cast_in_use = false;
7441 
7442  MemoryContextSwitchTo(oldcontext);
7443  }
7444  }
7445 
7446  return value;
7447 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static plpgsql_CastHashEntry * get_cast_hashentry(PLpgSQL_execstate *estate, Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod)
Definition: pl_exec.c:7460
Datum caseValue_datum
Definition: execnodes.h:243
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:281
#define get_eval_mcontext(estate)
Definition: pl_exec.c:119
static struct @131 value
ExprContext * eval_econtext
Definition: plpgsql.h:1042
bool caseValue_isNull
Definition: execnodes.h:245
ExprState * cast_exprstate
Definition: pl_exec.c:154

◆ exec_check_rw_parameter()

static void exec_check_rw_parameter ( PLpgSQL_expr expr,
int  target_dno 
)
static

Definition at line 7801 of file pl_exec.c.

References arg, FuncExpr::args, OpExpr::args, bms_is_member(), contains_target_param(), PLpgSQL_expr::expr_simple_expr, FuncExpr::funcid, IsA, lfirst, OpExpr::opfuncid, PLpgSQL_expr::paramnos, and PLpgSQL_expr::rwparam.

Referenced by exec_assign_expr(), and exec_eval_simple_expr().

7802 {
7803  Oid funcid;
7804  List *fargs;
7805  ListCell *lc;
7806 
7807  /* Assume unsafe */
7808  expr->rwparam = -1;
7809 
7810  /*
7811  * If the expression isn't simple, there's no point in trying to optimize
7812  * (because the exec_run_select code path will flatten any expanded result
7813  * anyway). Even without that, this seems like a good safety restriction.
7814  */
7815  if (expr->expr_simple_expr == NULL)
7816  return;
7817 
7818  /*
7819  * If target variable isn't referenced by expression, no need to look
7820  * further.
7821  */
7822  if (!bms_is_member(target_dno, expr->paramnos))
7823  return;
7824 
7825  /*
7826  * Top level of expression must be a simple FuncExpr or OpExpr.
7827  */
7828  if (IsA(expr->expr_simple_expr, FuncExpr))
7829  {
7830  FuncExpr *fexpr = (FuncExpr *) expr->expr_simple_expr;
7831 
7832  funcid = fexpr->funcid;
7833  fargs = fexpr->args;
7834  }
7835  else if (IsA(expr->expr_simple_expr, OpExpr))
7836  {
7837  OpExpr *opexpr = (OpExpr *) expr->expr_simple_expr;
7838 
7839  funcid = opexpr->opfuncid;
7840  fargs = opexpr->args;
7841  }
7842  else
7843  return;
7844 
7845  /*
7846  * The top-level function must be one that we trust to be "safe".
7847  * Currently we hard-wire the list, but it would be very desirable to
7848  * allow extensions to mark their functions as safe ...
7849  */
7850  if (!(funcid == F_ARRAY_APPEND ||
7851  funcid == F_ARRAY_PREPEND))
7852  return;
7853 
7854  /*
7855  * The target variable (in the form of a Param) must only appear as a
7856  * direct argument of the top-level function.
7857  */
7858  foreach(lc, fargs)
7859  {
7860  Node *arg = (Node *) lfirst(lc);
7861 
7862  /* A Param is OK, whether it's the target variable or not */
7863  if (arg && IsA(arg, Param))
7864  continue;
7865  /* Otherwise, argument expression must not reference target */
7866  if (contains_target_param(arg, &target_dno))
7867  return;
7868  }
7869 
7870  /* OK, we can pass target as a read-write parameter */
7871  expr->rwparam = target_dno;
7872 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
List * args
Definition: primnodes.h:458
Definition: nodes.h:517
unsigned int Oid
Definition: postgres_ext.h:31
Bitmapset * paramnos
Definition: plpgsql.h:219
Oid funcid
Definition: primnodes.h:450
static bool contains_target_param(Node *node, int *target_dno)
Definition: pl_exec.c:7878
Expr * expr_simple_expr
Definition: plpgsql.h:229
int rwparam
Definition: plpgsql.h:220
Oid opfuncid
Definition: primnodes.h:498
#define lfirst(lc)
Definition: pg_list.h:106
void * arg
List * args
Definition: primnodes.h:503
Definition: pg_list.h:45
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:486

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

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(), PreparedParamsData::nargs, PreparedParamsData::nulls, PLpgSQL_execstate::readonly_func, SPI_cursor_open_with_args(), SPI_result, SPI_result_code_string(), PreparedParamsData::types, and PreparedParamsData::values.

Referenced by exec_stmt_dynfors(), exec_stmt_open(), and exec_stmt_return_query().

8195 {
8196  Portal portal;
8197  Datum query;
8198  bool isnull;
8199  Oid restype;
8200  int32 restypmod;
8201  char *querystr;
8202  MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
8203 
8204  /*
8205  * Evaluate the string expression after the EXECUTE keyword. Its result is
8206  * the querystring we have to execute.
8207  */
8208  query = exec_eval_expr(estate, dynquery, &isnull, &restype, &restypmod);
8209  if (isnull)
8210  ereport(ERROR,
8211  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
8212  errmsg("query string argument of EXECUTE is null")));
8213 
8214  /* Get the C-String representation */
8215  querystr = convert_value_to_string(estate, query, restype);
8216 
8217  /* copy it into the stmt_mcontext before we clean up */
8218  querystr = MemoryContextStrdup(stmt_mcontext, querystr);
8219 
8220  exec_eval_cleanup(estate);
8221 
8222  /*
8223  * Open an implicit cursor for the query. We use
8224  * SPI_cursor_open_with_args even when there are no params, because this
8225  * avoids making and freeing one copy of the plan.
8226  */
8227  if (params)
8228  {
8229  PreparedParamsData *ppd;
8230 
8231  ppd = exec_eval_using_params(estate, params);
8232  portal = SPI_cursor_open_with_args(portalname,
8233  querystr,
8234  ppd->nargs, ppd->types,
8235  ppd->values, ppd->nulls,
8236  estate->readonly_func,
8237  cursorOptions);
8238  }
8239  else
8240  {
8241  portal = SPI_cursor_open_with_args(portalname,
8242  querystr,
8243  0, NULL,
8244  NULL, NULL,
8245  estate->readonly_func,
8246  cursorOptions);
8247  }
8248 
8249  if (portal == NULL)
8250  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
8251  querystr, SPI_result_code_string(SPI_result));
8252 
8253  /* Release transient data */
8254  MemoryContextReset(stmt_mcontext);
8255 
8256  return portal;
8257 }
int errcode(int sqlerrcode)
Definition: elog.c:575
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:3922
Datum * values
Definition: pl_exec.c:56
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:313
int SPI_result
Definition: spi.c:42
#define ERROR
Definition: elog.h:43
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5650
static PreparedParamsData * exec_eval_using_params(PLpgSQL_execstate *estate, List *params)
Definition: pl_exec.c:8111
const char * SPI_result_code_string(int code)
Definition: spi.c:1609
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1441
#define ereport(elevel, rest)
Definition: elog.h:122
uintptr_t Datum
Definition: postgres.h:365
Portal SPI_cursor_open_with_args(const char *name, const char *src, int nargs, Oid *argtypes, Datum *Values, const char *Nulls, bool read_only, int cursorOptions)
Definition: spi.c:1152
bool readonly_func
Definition: plpgsql.h:993
int errmsg(const char *fmt,...)
Definition: elog.c:797
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1148
static char * convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
Definition: pl_exec.c:7380
#define elog
Definition: elog.h:219

◆ exec_eval_boolean()

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

Definition at line 5627 of file pl_exec.c.

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

5630 {
5631  Datum exprdatum;
5632  Oid exprtypeid;
5633  int32 exprtypmod;
5634 
5635  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5636  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5637  exprtypeid, exprtypmod,
5638  BOOLOID, -1);
5639  return DatumGetBool(exprdatum);
5640 }
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:313
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7409
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5650
#define DatumGetBool(X)
Definition: postgres.h:376
uintptr_t Datum
Definition: postgres.h:365

◆ exec_eval_cleanup()

static void exec_eval_cleanup ( PLpgSQL_execstate estate)
static

Definition at line 3922 of file pl_exec.c.

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

3923 {
3924  /* Clear result of a full SPI_execute */
3925  if (estate->eval_tuptable != NULL)
3927  estate->eval_tuptable = NULL;
3928 
3929  /*
3930  * Clear result of exec_eval_simple_expr (but keep the econtext). This
3931  * also clears any short-lived allocations done via get_eval_mcontext.
3932  */
3933  if (estate->eval_econtext != NULL)
3935 }
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1039
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1066
ExprContext * eval_econtext
Definition: plpgsql.h:1042
#define ResetExprContext(econtext)
Definition: executor.h:483

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

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, tupleDesc::tdtypeid, tupleDesc::tdtypmod, PLpgSQL_type::typoid, unlikely, and PLpgSQL_var::value.

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

5279 {
5280  MemoryContext oldcontext;
5281 
5282  switch (datum->dtype)
5283  {
5284  case PLPGSQL_DTYPE_PROMISE:
5285  /* fulfill promise if needed, then handle like regular var */
5286  plpgsql_fulfill_promise(estate, (PLpgSQL_var *) datum);
5287 
5288  /* FALL THRU */
5289 
5290  case PLPGSQL_DTYPE_VAR:
5291  {
5292  PLpgSQL_var *var = (PLpgSQL_var *) datum;
5293 
5294  *typeid = var->datatype->typoid;
5295  *typetypmod = var->datatype->atttypmod;
5296  *value = var->value;
5297  *isnull = var->isnull;
5298  break;
5299  }
5300 
5301  case PLPGSQL_DTYPE_ROW:
5302  {
5303  PLpgSQL_row *row = (PLpgSQL_row *) datum;
5304  HeapTuple tup;
5305 
5306  /* We get here if there are multiple OUT parameters */
5307  if (!row->rowtupdesc) /* should not happen */
5308  elog(ERROR, "row variable has no tupdesc");
5309  /* Make sure we have a valid type/typmod setting */
5310  BlessTupleDesc(row->rowtupdesc);
5311  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5312  tup = make_tuple_from_row(estate, row, row->rowtupdesc);
5313  if (tup == NULL) /* should not happen */
5314  elog(ERROR, "row not compatible with its own tupdesc");
5315  *typeid = row->rowtupdesc->tdtypeid;
5316  *typetypmod = row->rowtupdesc->tdtypmod;
5317  *value = HeapTupleGetDatum(tup);
5318  *isnull = false;
5319  MemoryContextSwitchTo(oldcontext);
5320  break;
5321  }
5322 
5323  case PLPGSQL_DTYPE_REC:
5324  {
5325  PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
5326 
5327  if (rec->erh == NULL)
5328  {
5329  /* Treat uninstantiated record as a simple NULL */
5330  *value = (Datum) 0;
5331  *isnull = true;
5332  /* Report variable's declared type */
5333  *typeid = rec->rectypeid;
5334  *typetypmod = -1;
5335  }
5336  else
5337  {
5338  if (ExpandedRecordIsEmpty(rec->erh))
5339  {
5340  /* Empty record is also a NULL */
5341  *value = (Datum) 0;
5342  *isnull = true;
5343  }
5344  else
5345  {
5346  *value = ExpandedRecordGetDatum(rec->erh);
5347  *isnull = false;
5348  }
5349  if (rec->rectypeid != RECORDOID)
5350  {
5351  /* Report variable's declared type, if not RECORD */
5352  *typeid = rec->rectypeid;
5353  *typetypmod = -1;
5354  }
5355  else
5356  {
5357  /* Report record's actual type if declared RECORD */
5358  *typeid = rec->erh->er_typeid;
5359  *typetypmod = rec->erh->er_typmod;
5360  }
5361  }
5362  break;
5363  }
5364 
5366  {
5367  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
5368  PLpgSQL_rec *rec;
5369  ExpandedRecordHeader *erh;
5370 
5371  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5372  erh = rec->erh;
5373 
5374  /*
5375  * If record variable is NULL, instantiate it if it has a
5376  * named composite type, else complain. (This won't change
5377  * the logical state of the record: it's still NULL.)
5378  */
5379  if (erh == NULL)
5380  {
5381  instantiate_empty_record_variable(estate, rec);
5382  erh = rec->erh;
5383  }
5384 
5385  /*
5386  * Look up the field's properties if we have not already, or
5387  * if the tuple descriptor ID changed since last time.
5388  */
5389  if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
5390  {
5392  recfield->fieldname,
5393  &recfield->finfo))
5394  ereport(ERROR,
5395  (errcode(ERRCODE_UNDEFINED_COLUMN),
5396  errmsg("record \"%s\" has no field \"%s\"",
5397  rec->refname, recfield->fieldname)));
5398  recfield->rectupledescid = erh->er_tupdesc_id;
5399  }
5400 
5401  /* Report type data. */
5402  *typeid = recfield->finfo.ftypeid;
5403  *typetypmod = recfield->finfo.ftypmod;
5404 
5405  /* And fetch the field value. */
5407  recfield->finfo.fnumber,
5408  isnull);
5409  break;
5410  }
5411 
5412  default:
5413  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
5414  }
5415 }
static HeapTuple make_tuple_from_row(PLpgSQL_execstate *estate, PLpgSQL_row *row, TupleDesc tupdesc)
Definition: pl_exec.c:7038
Oid tdtypeid
Definition: tupdesc.h:83
#define ExpandedRecordIsEmpty(erh)
bool expanded_record_lookup_field(ExpandedRecordHeader *erh, const char *fieldname, ExpandedRecordFieldInfo *finfo)
static Datum expanded_record_get_field(ExpandedRecordHeader *erh, int fnumber, bool *isnull)
PLpgSQL_type * datatype
Definition: plpgsql.h:296
static void plpgsql_fulfill_promise(PLpgSQL_execstate *estate, PLpgSQL_var *var)
Definition: pl_exec.c:1281
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void instantiate_empty_record_variable(PLpgSQL_execstate *estate, PLpgSQL_rec *rec)
Definition: pl_exec.c:7348
ExpandedRecordHeader * erh
Definition: plpgsql.h:379
int errcode(int sqlerrcode)
Definition: elog.c:575
PLpgSQL_datum_type dtype
Definition: plpgsql.h:253
char * refname
Definition: plpgsql.h:364
int32 tdtypmod
Definition: tupdesc.h:84
PLpgSQL_datum ** datums
Definition: plpgsql.h:1015
#define ERROR
Definition: elog.h:43
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:1109
#define ereport(elevel, rest)
Definition: elog.h:122
uint64 rectupledescid
Definition: plpgsql.h:394
#define get_eval_mcontext(estate)
Definition: pl_exec.c:119
uintptr_t Datum
Definition: postgres.h:365
ExpandedRecordFieldInfo finfo
Definition: plpgsql.h:395
static struct @131 value
Datum value
Definition: plpgsql.h:309
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:231
int errmsg(const char *fmt,...)
Definition: elog.c:797
int32 atttypmod
Definition: plpgsql.h:209
TupleDesc rowtupdesc
Definition: plpgsql.h:350
#define unlikely(x)
Definition: c.h:208
#define elog
Definition: elog.h:219
Oid rectypeid
Definition: plpgsql.h:372
#define ExpandedRecordGetDatum(erh)
char * fieldname
Definition: plpgsql.h:391
bool isnull
Definition: plpgsql.h:310
Oid typoid
Definition: plpgsql.h:202

◆ exec_eval_expr()

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

Definition at line 5650 of file pl_exec.c.

References CURSOR_OPT_PARALLEL_OK, ereport, errcode(), errmsg(), errmsg_plural(), ERROR, PLpgSQL_execstate::eval_processed, PLpgSQL_execstate::eval_tuptable, exec_eval_simple_expr(), exec_prepare_plan(), exec_run_select(), tupleDesc::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(), and exec_stmt_return_next().

5655 {
5656  Datum result = 0;
5657  int rc;
5658  Form_pg_attribute attr;
5659 
5660  /*
5661  * If first time through, create a plan for this expression.
5662  */
5663  if (expr->plan == NULL)
5664  exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK, true);
5665 
5666  /*
5667  * If this is a simple expression, bypass SPI and use the executor
5668  * directly
5669  */
5670  if (exec_eval_simple_expr(estate, expr,
5671  &result, isNull, rettype, rettypmod))
5672  return result;
5673 
5674  /*
5675  * Else do it the hard way via exec_run_select
5676  */
5677  rc = exec_run_select(estate, expr, 2, NULL);
5678  if (rc != SPI_OK_SELECT)
5679  ereport(ERROR,
5680  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5681  errmsg("query \"%s\" did not return data", expr->query)));
5682 
5683  /*
5684  * Check that the expression returns exactly one column...
5685  */
5686  if (estate->eval_tuptable->tupdesc->natts != 1)
5687  ereport(ERROR,
5688  (errcode(ERRCODE_SYNTAX_ERROR),
5689  errmsg_plural("query \"%s\" returned %d column",
5690  "query \"%s\" returned %d columns",
5691  estate->eval_tuptable->tupdesc->natts,
5692  expr->query,
5693  estate->eval_tuptable->tupdesc->natts)));
5694 
5695  /*
5696  * ... and get the column's datatype.
5697  */
5698  attr = TupleDescAttr(estate->eval_tuptable->tupdesc, 0);
5699  *rettype = attr->atttypid;
5700  *rettypmod = attr->atttypmod;
5701 
5702  /*
5703  * If there are no rows selected, the result is a NULL of that type.
5704  */
5705  if (estate->eval_processed == 0)
5706  {
5707  *isNull = true;
5708  return (Datum) 0;
5709  }
5710 
5711  /*
5712  * Check that the expression returned no more than one row.
5713  */
5714  if (estate->eval_processed != 1)
5715  ereport(ERROR,
5716  (errcode(ERRCODE_CARDINALITY_VIOLATION),
5717  errmsg("query \"%s\" returned more than one row",
5718  expr->query)));
5719 
5720  /*
5721  * Return the single result Datum.
5722  */
5723  return SPI_getbinval(estate->eval_tuptable->vals[0],
5724  estate->eval_tuptable->tupdesc, 1, isNull);
5725 }
char * query
Definition: plpgsql.h:217
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions, bool keepplan)
Definition: pl_exec.c:3943
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1039
uint64 eval_processed
Definition: plpgsql.h:1040
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:850
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
int errcode(int sqlerrcode)
Definition: elog.c:575
HeapTuple * vals
Definition: spi.h:28
int natts
Definition: tupdesc.h:82
SPIPlanPtr plan
Definition: plpgsql.h:218
#define ERROR
Definition: elog.h:43
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition: spi.c:932
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
#define ereport(elevel, rest)
Definition: elog.h:122
uintptr_t Datum
Definition: postgres.h:365
TupleDesc tupdesc
Definition: spi.h:27
#define SPI_OK_SELECT
Definition: spi.h:54
static int exec_run_select(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
Definition: pl_exec.c:5733
static bool exec_eval_simple_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, Datum *result, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5970
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2653
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ exec_eval_integer()

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

Definition at line 5604 of file pl_exec.c.

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

Referenced by exec_assign_value(), and exec_stmt_fetch().

5607 {
5608  Datum exprdatum;
5609  Oid exprtypeid;
5610  int32 exprtypmod;
5611 
5612  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5613  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5614  exprtypeid, exprtypmod,
5615  INT4OID, -1);
5616  return DatumGetInt32(exprdatum);
5617 }
#define DatumGetInt32(X)
Definition: postgres.h:455
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:313
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7409
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5650
uintptr_t Datum
Definition: postgres.h:365

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

References Assert, CommandCounterIncrement(), ExprContext::ecxt_param_list_info, EState::es_query_cxt, PLpgSQL_execstate::eval_econtext, exec_check_rw_parameter(), exec_save_simple_expr(), ExecEvalExpr(), ExecInitExprWithParams(), PLpgSQL_expr::expr_simple_expr, PLpgSQL_expr::expr_simple_generation, PLpgSQL_expr::expr_simple_in_use, PLpgSQL_expr::expr_simple_lxid, PLpgSQL_expr::expr_simple_state, PLpgSQL_expr::expr_simple_type, PLpgSQL_expr::expr_simple_typmod, CachedPlan::generation, get_eval_mcontext, GetTransactionSnapshot(), PGPROC::lxid, MemoryContextSwitchTo(), MyProc, PLpgSQL_execstate::paramLI, ParamListInfoData::parserSetupArg, PLpgSQL_expr::plan, PopActiveSnapshot(), PushActiveSnapshot(), PLpgSQL_execstate::readonly_func, ReleaseCachedPlan(), PLpgSQL_expr::rwparam, setup_param_list(), PLpgSQL_execstate::simple_eval_estate, and SPI_plan_get_cached_plan().

Referenced by exec_eval_expr().

5976 {
5977  ExprContext *econtext = estate->eval_econtext;
5978  LocalTransactionId curlxid = MyProc->lxid;
5979  CachedPlan *cplan;
5980  void *save_setup_arg;
5981  MemoryContext oldcontext;
5982 
5983  /*
5984  * Forget it if expression wasn't simple before.
5985  */
5986  if (expr->expr_simple_expr == NULL)
5987  return false;
5988 
5989  /*
5990  * If expression is in use in current xact, don't touch it.
5991  */
5992  if (expr->expr_simple_in_use && expr->expr_simple_lxid == curlxid)
5993  return false;
5994 
5995  /*
5996  * Revalidate cached plan, so that we will notice if it became stale. (We
5997  * need to hold a refcount while using the plan, anyway.) If replanning
5998  * is needed, do that work in the eval_mcontext.
5999  */
6000  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6001  cplan = SPI_plan_get_cached_plan(expr->plan);
6002  MemoryContextSwitchTo(oldcontext);
6003 
6004  /*
6005  * We can't get a failure here, because the number of CachedPlanSources in
6006  * the SPI plan can't change from what exec_simple_check_plan saw; it's a
6007  * property of the raw parsetree generated from the query text.
6008  */
6009  Assert(cplan != NULL);
6010 
6011  /* If it got replanned, update our copy of the simple expression */
6012  if (cplan->generation != expr->expr_simple_generation)
6013  {
6014  exec_save_simple_expr(expr, cplan);
6015  /* better recheck r/w safety, as it could change due to inlining */
6016  if (expr->rwparam >= 0)
6017  exec_check_rw_parameter(expr, expr->rwparam);
6018  }
6019 
6020  /*
6021  * Pass back previously-determined result type.
6022  */
6023  *rettype = expr->expr_simple_type;
6024  *rettypmod = expr->expr_simple_typmod;
6025 
6026  /*
6027  * Set up ParamListInfo to pass to executor. For safety, save and restore
6028  * estate->paramLI->parserSetupArg around our use of the param list.
6029  */
6030  save_setup_arg = estate->paramLI->parserSetupArg;
6031 
6032  econtext->ecxt_param_list_info = setup_param_list(estate, expr);
6033 
6034  /*
6035  * Prepare the expression for execution, if it's not been done already in
6036  * the current transaction. (This will be forced to happen if we called
6037  * exec_save_simple_expr above.)
6038  */
6039  if (expr->expr_simple_lxid != curlxid)
6040  {
6041  oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
6042  expr->expr_simple_state =
6044  econtext->ecxt_param_list_info);
6045  expr->expr_simple_in_use = false;
6046  expr->expr_simple_lxid = curlxid;
6047  MemoryContextSwitchTo(oldcontext);
6048  }
6049 
6050  /*
6051  * We have to do some of the things SPI_execute_plan would do, in
6052  * particular advance the snapshot if we are in a non-read-only function.
6053  * Without this, stable functions within the expression would fail to see
6054  * updates made so far by our own function.
6055  */
6056  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
6057  if (!estate->readonly_func)
6058  {
6061  }
6062 
6063  /*
6064  * Mark expression as busy for the duration of the ExecEvalExpr call.
6065  */
6066  expr->expr_simple_in_use = true;
6067 
6068  /*
6069  * Finally we can call the executor to evaluate the expression
6070  */
6071  *result = ExecEvalExpr(expr->expr_simple_state,
6072  econtext,
6073  isNull);
6074 
6075  /* Assorted cleanup */
6076  expr->expr_simple_in_use = false;
6077 
6078  econtext->ecxt_param_list_info = NULL;
6079 
6080  estate->paramLI->parserSetupArg = save_setup_arg;
6081 
6082  if (!estate->readonly_func)
6084 
6085  MemoryContextSwitchTo(oldcontext);
6086 
6087  /*
6088  * Now we can release our refcount on the cached plan.
6089  */
6090  ReleaseCachedPlan(cplan, true);
6091 
6092  /*
6093  * That's it.
6094  */
6095  return true;
6096 }
int expr_simple_generation
Definition: plpgsql.h:230
void * parserSetupArg
Definition: params.h:117
static void exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno)
Definition: pl_exec.c:7801
PGPROC * MyProc
Definition: proc.c:67
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void PopActiveSnapshot(void)
Definition: snapmgr.c:812
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:304
static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
Definition: pl_exec.c:7714
SPIPlanPtr plan
Definition: plpgsql.h:218
CachedPlan * SPI_plan_get_cached_plan(SPIPlanPtr plan)
Definition: spi.c:1702
MemoryContext es_query_cxt
Definition: execnodes.h:523
ParamListInfo paramLI
Definition: plpgsql.h:1025
EState * simple_eval_estate
Definition: plpgsql.h:1028
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:733
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:281
ExprState * ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
Definition: execExpr.c:156
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1258
Expr * expr_simple_expr
Definition: plpgsql.h:229
uint32 LocalTransactionId
Definition: c.h:476
static ParamListInfo setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:6115
int rwparam
Definition: plpgsql.h:220
#define get_eval_mcontext(estate)
Definition: pl_exec.c:119
ExprState * expr_simple_state
Definition: plpgsql.h:240
void CommandCounterIncrement(void)
Definition: xact.c:914
LocalTransactionId expr_simple_lxid
Definition: plpgsql.h:242
#define Assert(condition)
Definition: c.h:699
ExprContext * eval_econtext
Definition: plpgsql.h:1042
bool readonly_func
Definition: plpgsql.h:993
int generation
Definition: plancache.h:141
int32 expr_simple_typmod
Definition: plpgsql.h:232
bool expr_simple_in_use
Definition: plpgsql.h:241
ParamListInfo ecxt_param_list_info
Definition: execnodes.h:230
Oid expr_simple_type
Definition: plpgsql.h:231
LocalTransactionId lxid
Definition: proc.h:106

◆ exec_eval_using_params()

static PreparedParamsData * exec_eval_using_params ( PLpgSQL_execstate estate,
List params 
)
static

Definition at line 8111 of file pl_exec.c.

References CStringGetTextDatum, datumCopy(), DatumGetCString, exec_eval_cleanup(), exec_eval_expr(), get_stmt_mcontext(), get_typlenbyval(), i, lfirst, list_length(), MemoryContextAlloc(), MemoryContextSwitchTo(), PreparedParamsData::nargs, PreparedParamsData::nulls, PreparedParamsData::types, and PreparedParamsData::values.

Referenced by exec_dynquery_with_params(), and exec_stmt_dynexecute().

8112 {
8113  PreparedParamsData *ppd;
8114  MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
8115  int nargs;
8116  int i;
8117  ListCell *lc;
8118 
8119  ppd = (PreparedParamsData *)
8120  MemoryContextAlloc(stmt_mcontext, sizeof(PreparedParamsData));
8121  nargs = list_length(params);
8122 
8123  ppd->nargs = nargs;
8124  ppd->types = (Oid *)
8125  MemoryContextAlloc(stmt_mcontext, nargs * sizeof(Oid));
8126  ppd->values = (Datum *)
8127  MemoryContextAlloc(stmt_mcontext, nargs * sizeof(Datum));
8128  ppd->nulls = (char *)
8129  MemoryContextAlloc(stmt_mcontext, nargs * sizeof(char));
8130 
8131  i = 0;
8132  foreach(lc, params)
8133  {
8134  PLpgSQL_expr *param = (PLpgSQL_expr *) lfirst(lc);
8135  bool isnull;
8136  int32 ppdtypmod;
8137  MemoryContext oldcontext;
8138 
8139  ppd->values[i] = exec_eval_expr(estate, param,
8140  &isnull,
8141  &ppd->types[i],
8142  &ppdtypmod);
8143  ppd->nulls[i] = isnull ? 'n' : ' ';
8144 
8145  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
8146 
8147  if (ppd->types[i] == UNKNOWNOID)
8148  {
8149  /*
8150  * Treat 'unknown' parameters as text, since that's what most
8151  * people would expect. SPI_execute_with_args can coerce unknown
8152  * constants in a more intelligent way, but not unknown Params.
8153  * This code also takes care of copying into the right context.
8154  * Note we assume 'unknown' has the representation of C-string.
8155  */
8156  ppd->types[i] = TEXTOID;
8157  if (!isnull)
8159  }
8160  /* pass-by-ref non null values must be copied into stmt_mcontext */
8161  else if (!isnull)
8162  {
8163  int16 typLen;
8164  bool typByVal;
8165 
8166  get_typlenbyval(ppd->types[i], &typLen, &typByVal);
8167  if (!typByVal)
8168  ppd->values[i] = datumCopy(ppd->values[i], typByVal, typLen);
8169  }
8170 
8171  MemoryContextSwitchTo(oldcontext);
8172 
8173  exec_eval_cleanup(estate);
8174 
8175  i++;
8176  }
8177 
8178  return ppd;
8179 }
signed short int16
Definition: c.h:312
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:3922
Datum * values
Definition: pl_exec.c:56
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:313
#define DatumGetCString(X)
Definition: postgres.h:549
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5650
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1441
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
uintptr_t Datum
Definition: postgres.h:365
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2005
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:771
int i
#define CStringGetTextDatum(s)
Definition: builtins.h:95

◆ exec_for_query()

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

Definition at line 5798 of file pl_exec.c.

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

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

5800 {
5801  PLpgSQL_variable *var;
5802  SPITupleTable *tuptab;
5803  bool found = false;
5804  int rc = PLPGSQL_RC_OK;
5805  uint64 previous_id = INVALID_TUPLEDESC_IDENTIFIER;
5806  bool tupdescs_match = true;
5807  uint64 n;
5808 
5809  /* Fetch loop variable's datum entry */
5810  var = (PLpgSQL_variable *) estate->datums[stmt->var->dno];
5811 
5812  /*
5813  * Make sure the portal doesn't get closed by the user statements we
5814  * execute.
5815  */
5816  PinPortal(portal);
5817 
5818  /*
5819  * Fetch the initial tuple(s). If prefetching is allowed then we grab a
5820  * few more rows to avoid multiple trips through executor startup
5821  * overhead.
5822  */
5823  SPI_cursor_fetch(portal, true, prefetch_ok ? 10 : 1);
5824  tuptab = SPI_tuptable;
5825  n = SPI_processed;
5826 
5827  /*
5828  * If the query didn't return any rows, set the target to NULL and fall
5829  * through with found = false.
5830  */
5831  if (n == 0)
5832  {
5833  exec_move_row(estate, var, NULL, tuptab->tupdesc);
5834  exec_eval_cleanup(estate);
5835  }
5836  else
5837  found = true; /* processed at least one tuple */
5838 
5839  /*
5840  * Now do the loop
5841  */
5842  while (n > 0)
5843  {
5844  uint64 i;
5845 
5846  for (i = 0; i < n; i++)
5847  {
5848  /*
5849  * Assign the tuple to the target. Here, because we know that all
5850  * loop iterations should be assigning the same tupdesc, we can
5851  * optimize away repeated creations of expanded records with
5852  * identical tupdescs. Testing for changes of er_tupdesc_id is
5853  * reliable even if the loop body contains assignments that
5854  * replace the target's value entirely, because it's assigned from
5855  * a process-global counter. The case where the tupdescs don't
5856  * match could possibly be handled more efficiently than this
5857  * coding does, but it's not clear extra effort is worthwhile.
5858  */
5859  if (var->dtype == PLPGSQL_DTYPE_REC)
5860  {
5861  PLpgSQL_rec *rec = (PLpgSQL_rec *) var;
5862 
5863  if (rec->erh &&
5864  rec->erh->er_tupdesc_id == previous_id &&
5865  tupdescs_match)
5866  {
5867  /* Only need to assign a new tuple value */
5868  expanded_record_set_tuple(rec->erh, tuptab->vals[i], true);
5869  }
5870  else
5871  {
5872  /*
5873  * First time through, or var's tupdesc changed in loop,
5874  * or we have to do it the hard way because type coercion
5875  * is needed.
5876  */
5877  exec_move_row(estate, var,
5878  tuptab->vals[i], tuptab->tupdesc);
5879 
5880  /*
5881  * Check to see if physical assignment is OK next time.
5882  * Once the tupdesc comparison has failed once, we don't
5883  * bother rechecking in subsequent loop iterations.
5884  */
5885  if (tupdescs_match)
5886  {
5887  tupdescs_match =
5888  (rec->rectypeid == RECORDOID ||
5889  rec->rectypeid == tuptab->tupdesc->tdtypeid ||
5890  compatible_tupdescs(tuptab->tupdesc,
5892  }
5893  previous_id = rec->erh->er_tupdesc_id;
5894  }
5895  }
5896  else
5897  exec_move_row(estate, var, tuptab->vals[i], tuptab->tupdesc);
5898 
5899  exec_eval_cleanup(estate);
5900 
5901  /*
5902  * Execute the statements
5903  */
5904  rc = exec_stmts(estate, stmt->body);
5905 
5906  LOOP_RC_PROCESSING(stmt->label, goto loop_exit);
5907  }
5908 
5909  SPI_freetuptable(tuptab);
5910 
5911  /*
5912  * Fetch more tuples. If prefetching is allowed, grab 50 at a time.
5913  */
5914  SPI_cursor_fetch(portal, true, prefetch_ok ? 50 : 1);
5915  tuptab = SPI_tuptable;
5916  n = SPI_processed;
5917  }
5918 
5919 loop_exit:
5920 
5921  /*
5922  * Release last group of tuples (if any)
5923  */
5924  SPI_freetuptable(tuptab);
5925 
5926  UnpinPortal(portal);
5927 
5928  /*
5929  * Set the FOUND variable to indicate the result of executing the loop
5930  * (namely, whether we looped one or more times). This must be set last so
5931  * that it does not interfere with the value of the FOUND variable inside
5932  * the loop processing itself.
5933  */
5934  exec_set_found(estate, found);
5935 
5936  return rc;
5937 }
void UnpinPortal(Portal portal)
Definition: portalmem.c:377
Oid tdtypeid
Definition: tupdesc.h:83
SPITupleTable * SPI_tuptable
Definition: spi.c:41
ExpandedRecordHeader * erh
Definition: plpgsql.h:379
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:3922
HeapTuple * vals
Definition: spi.h:28
#define INVALID_TUPLEDESC_IDENTIFIER
Definition: typcache.h:145
uint64 SPI_processed
Definition: spi.c:39
PLpgSQL_datum ** datums
Definition: plpgsql.h:1015
void PinPortal(Portal portal)
Definition: portalmem.c:368
#define LOOP_RC_PROCESSING(looplabel, exit_action)
Definition: pl_exec.c:185
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1066
static bool compatible_tupdescs(TupleDesc src_tupdesc, TupleDesc dst_tupdesc)
Definition: pl_exec.c:6994
TupleDesc tupdesc
Definition: spi.h:27
PLpgSQL_datum_type dtype
Definition: plpgsql.h:265
PLpgSQL_variable * var
Definition: plpgsql.h:669
static void exec_set_found(PLpgSQL_execstate *estate, bool state)
Definition: pl_exec.c:7900
static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
Definition: pl_exec.c:6608
int i
void SPI_cursor_fetch(Portal portal, bool forward, long count)
Definition: spi.c:1443
Oid rectypeid
Definition: plpgsql.h:372
void expanded_record_set_tuple(ExpandedRecordHeader *erh, HeapTuple tuple, bool copy)
static int exec_stmts(PLpgSQL_execstate *estate, List *stmts)
Definition: pl_exec.c:1852

◆ exec_init_tuple_store()

static void exec_init_tuple_store ( PLpgSQL_execstate estate)
static

Definition at line 3470 of file pl_exec.c.

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

3471 {
3472  ReturnSetInfo *rsi = estate->rsi;
3473  MemoryContext oldcxt;
3474  ResourceOwner oldowner;
3475 
3476  /*
3477  * Check caller can handle a set result in the way we want
3478  */
3479  if (!rsi || !IsA(rsi, ReturnSetInfo) ||
3480  (rsi->allowedModes & SFRM_Materialize) == 0 ||
3481  rsi->expectedDesc == NULL)
3482  ereport(ERROR,
3483  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3484  errmsg("set-valued function called in context that cannot accept a set")));
3485 
3486  /*
3487  * Switch to the right memory context and resource owner for storing the
3488  * tuplestore for return set. If we're within a subtransaction opened for
3489  * an exception-block, for example, we must still create the tuplestore in
3490  * the resource owner that was active when this function was entered, and
3491  * not in the subtransaction resource owner.
3492  */
3493  oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
3494  oldowner = CurrentResourceOwner;
3496 
3497  estate->tuple_store =
3499  false, work_mem);
3500 
3501  CurrentResourceOwner = oldowner;
3502  MemoryContextSwitchTo(oldcxt);
3503 
3504  estate->tuple_store_desc = rsi->expectedDesc;
3505 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
ResourceOwner tuple_store_owner
Definition: plpgsql.h:1003
ResourceOwner CurrentResourceOwner
Definition: resowner.c:140
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:575
TupleDesc expectedDesc
Definition: execnodes.h:296
TupleDesc tuple_store_desc
Definition: plpgsql.h:1001
#define ERROR
Definition: elog.h:43
MemoryContext tuple_store_cxt
Definition: plpgsql.h:1002
ReturnSetInfo * rsi
Definition: plpgsql.h:1004
#define ereport(elevel, rest)
Definition: elog.h:122
Tuplestorestate * tuple_store
Definition: plpgsql.h:1000
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
int work_mem
Definition: globals.c:122
int allowedModes
Definition: execnodes.h:297
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ exec_move_row()

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

Definition at line 6608 of file pl_exec.c.

References assign_record_var(), 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(), tupleDesc::natts, PLPGSQL_DTYPE_REC, PLpgSQL_rec::rectypeid, tupleDesc::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().

6611 {
6612  ExpandedRecordHeader *newerh = NULL;
6613 
6614  /*
6615  * If target is RECORD, we may be able to avoid field-by-field processing.
6616  */
6617  if (target->dtype == PLPGSQL_DTYPE_REC)
6618  {
6619  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
6620 
6621  /*
6622  * If we have no source tupdesc, just set the record variable to NULL.
6623  * (If we have a source tupdesc but not a tuple, we'll set the
6624  * variable to a row of nulls, instead. This is odd perhaps, but
6625  * backwards compatible.)
6626  */
6627  if (tupdesc == NULL)
6628  {
6629  if (rec->datatype &&
6630  rec->datatype->typtype == TYPTYPE_DOMAIN)
6631  {
6632  /*
6633  * If it's a composite domain, NULL might not be a legal
6634  * value, so we instead need to make an empty expanded record
6635  * and ensure that domain type checking gets done. If there
6636  * is already an expanded record, piggyback on its lookups.
6637  */
6638  newerh = make_expanded_record_for_rec(estate, rec,
6639  NULL, rec->erh);
6640  expanded_record_set_tuple(newerh, NULL, false);
6641  assign_record_var(estate, rec, newerh);
6642  }
6643  else
6644  {
6645  /* Just clear it to NULL */
6646  if (rec->erh)
6648  rec->erh = NULL;
6649  }
6650  return;
6651  }
6652 
6653  /*
6654  * Build a new expanded record with appropriate tupdesc.
6655  */
6656  newerh = make_expanded_record_for_rec(estate, rec, tupdesc, NULL);
6657 
6658  /*
6659  * If the rowtypes match, or if we have no tuple anyway, we can
6660  * complete the assignment without field-by-field processing.
6661  *
6662  * The tests here are ordered more or less in order of cheapness. We
6663  * can easily detect it will work if the target is declared RECORD or
6664  * has the same typeid as the source. But when assigning from a query
6665  * result, it's common to have a source tupdesc that's labeled RECORD
6666  * but is actually physically compatible with a named-composite-type
6667  * target, so it's worth spending extra cycles to check for that.
6668  */
6669  if (rec->rectypeid == RECORDOID ||
6670  rec->rectypeid == tupdesc->tdtypeid ||
6671  !HeapTupleIsValid(tup) ||
6673  {
6674  if (!HeapTupleIsValid(tup))
6675  {
6676  /* No data, so force the record into all-nulls state */
6678  }
6679  else
6680  {
6681  /* No coercion is needed, so just assign the row value */
6682  expanded_record_set_tuple(newerh, tup, true);
6683  }
6684 
6685  /* Complete the assignment */
6686  assign_record_var(estate, rec, newerh);
6687 
6688  return;
6689  }
6690  }
6691 
6692  /*
6693  * Otherwise, deconstruct the tuple and do field-by-field assignment,
6694  * using exec_move_row_from_fields.
6695  */
6696  if (tupdesc && HeapTupleIsValid(tup))
6697  {
6698  int td_natts = tupdesc->natts;
6699  Datum *values;
6700  bool *nulls;
6701  Datum values_local[64];
6702  bool nulls_local[64];
6703 
6704  /*
6705  * Need workspace arrays. If td_natts is small enough, use local
6706  * arrays to save doing a palloc. Even if it's not small, we can
6707  * allocate both the Datum and isnull arrays in one palloc chunk.
6708  */
6709  if (td_natts <= lengthof(values_local))
6710  {
6711  values = values_local;
6712  nulls = nulls_local;
6713  }
6714  else
6715  {
6716  char *chunk;
6717 
6718  chunk = eval_mcontext_alloc(estate,
6719  td_natts * (sizeof(Datum) + sizeof(bool)));
6720  values = (Datum *) chunk;
6721  nulls = (bool *) (chunk + td_natts * sizeof(Datum));
6722  }
6723 
6724  heap_deform_tuple(tup, tupdesc, values, nulls);
6725 
6726  exec_move_row_from_fields(estate, target, newerh,
6727  values, nulls, tupdesc);
6728  }
6729  else
6730  {
6731  /*
6732  * Assign all-nulls.
6733  */
6734  exec_move_row_from_fields(estate, target, newerh,
6735  NULL, NULL, NULL);
6736  }
6737 }
Oid tdtypeid
Definition: tupdesc.h:83
PLpgSQL_type * datatype
Definition: plpgsql.h:371
static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
Definition: pl_exec.c:8088
ExpandedRecordHeader * erh
Definition: plpgsql.h:379
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:6811
#define lengthof(array)
Definition: c.h:629
int natts
Definition: tupdesc.h:82
static ExpandedRecordHeader * make_expanded_record_for_rec(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, TupleDesc srctupdesc, ExpandedRecordHeader *srcerh)
Definition: pl_exec.c:6753
#define eval_mcontext_alloc(estate, sz)
Definition: pl_exec.c:121
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
uintptr_t Datum
Definition: postgres.h:365
static bool compatible_tupdescs(TupleDesc src_tupdesc, TupleDesc dst_tupdesc)
Definition: pl_exec.c:6994
void DeleteExpandedObject(Datum d)
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
PLpgSQL_datum_type dtype
Definition: plpgsql.h:265
char typtype
Definition: plpgsql.h:206
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1315
static Datum values[MAXATTR]
Definition: bootstrap.c:164
Oid rectypeid
Definition: plpgsql.h:372
#define ExpandedRecordGetDatum(erh)
void deconstruct_expanded_record(ExpandedRecordHeader *erh)
void expanded_record_set_tuple(ExpandedRecordHeader *erh, HeapTuple tuple, bool copy)

◆ exec_move_row_from_datum()

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

Definition at line 7124 of file pl_exec.c.

References Assert, assign_record_var(), 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, HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, VARATT_IS_EXTERNAL_EXPANDED, and VARATT_IS_EXTERNAL_EXPANDED_RW.

Referenced by exec_assign_value(), and plpgsql_exec_function().

7127 {
7128  /* Check to see if source is an expanded record */
7130  {
7132  ExpandedRecordHeader *newerh = NULL;
7133 
7134  Assert(erh->er_magic == ER_MAGIC);
7135 
7136  /* These cases apply if the target is record not row... */
7137  if (target->dtype == PLPGSQL_DTYPE_REC)
7138  {
7139  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7140 
7141  /*
7142  * If it's the same record already stored in the variable, do
7143  * nothing. This would happen only in silly cases like "r := r",
7144  * but we need some check to avoid possibly freeing the variable's
7145  * live value below. Note that this applies even if what we have
7146  * is a R/O pointer.
7147  */
7148  if (erh == rec->erh)
7149  return;
7150 
7151  /*
7152  * If we have a R/W pointer, we're allowed to just commandeer
7153  * ownership of the expanded record. If it's of the right type to
7154  * put into the record variable, do that. (Note we don't accept
7155  * an expanded record of a composite-domain type as a RECORD
7156  * value. We'll treat it as the base composite type instead;
7157  * compare logic in make_expanded_record_for_rec.)
7158  */
7160  (rec->rectypeid == erh->er_decltypeid ||
7161  (rec->rectypeid == RECORDOID &&
7162  !ExpandedRecordIsDomain(erh))))
7163  {
7164  assign_record_var(estate, rec, erh);
7165  return;
7166  }
7167 
7168  /*
7169  * If we already have an expanded record object in the target
7170  * variable, and the source record contains a valid tuple
7171  * representation with the right rowtype, then we can skip making
7172  * a new expanded record and just assign the tuple with
7173  * expanded_record_set_tuple. (We can't do the equivalent if we
7174  * have to do field-by-field assignment, since that wouldn't be
7175  * atomic if there's an error.) We consider that there's a
7176  * rowtype match only if it's the same named composite type or
7177  * same registered rowtype; checking for matches of anonymous
7178  * rowtypes would be more expensive than this is worth.
7179  */
7180  if (rec->erh &&
7181  (erh->flags & ER_FLAG_FVALUE_VALID) &&
7182  erh->er_typeid == rec->erh->er_typeid &&
7183  (erh->er_typeid != RECORDOID ||
7184  (erh->er_typmod == rec->erh->er_typmod &&
7185  erh->er_typmod >= 0)))
7186  {
7187  expanded_record_set_tuple(rec->erh, erh->fvalue, true);
7188  return;
7189  }
7190 
7191  /*
7192  * Otherwise we're gonna need a new expanded record object. Make
7193  * it here in hopes of piggybacking on the source object's
7194  * previous typcache lookup.
7195  */
7196  newerh = make_expanded_record_for_rec(estate, rec, NULL, erh);
7197 
7198  /*
7199  * If the expanded record contains a valid tuple representation,
7200  * and we don't need rowtype conversion, then just copying the
7201  * tuple is probably faster than field-by-field processing. (This
7202  * isn't duplicative of the previous check, since here we will
7203  * catch the case where the record variable was previously empty.)
7204  */
7205  if ((erh->flags & ER_FLAG_FVALUE_VALID) &&
7206  (rec->rectypeid == RECORDOID ||
7207  rec->rectypeid == erh->er_typeid))
7208  {
7209  expanded_record_set_tuple(newerh, erh->fvalue, true);
7210  assign_record_var(estate, rec, newerh);
7211  return;
7212  }
7213 
7214  /*
7215  * Need to special-case empty source record, else code below would
7216  * leak newerh.
7217  */
7218  if (ExpandedRecordIsEmpty(erh))
7219  {
7220  /* Set newerh to a row of NULLs */
7222  assign_record_var(estate, rec, newerh);
7223  return;
7224  }
7225  } /* end of record-target-only cases */
7226 
7227  /*
7228  * If the source expanded record is empty, we should treat that like a
7229  * NULL tuple value. (We're unlikely to see such a case, but we must
7230  * check this; deconstruct_expanded_record would cause a change of
7231  * logical state, which is not OK.)
7232  */
7233  if (ExpandedRecordIsEmpty(erh))
7234  {
7235  exec_move_row(estate, target, NULL,
7237  return;
7238  }
7239 
7240  /*
7241  * Otherwise, ensure that the source record is deconstructed, and
7242  * assign from its field values.
7243  */
7245  exec_move_row_from_fields(estate, target, newerh,
7246  erh->dvalues, erh->dnulls,
7248  }
7249  else
7250  {
7251  /*
7252  * Nope, we've got a plain composite Datum. Deconstruct it; but we
7253  * don't use deconstruct_composite_datum(), because we may be able to
7254  * skip calling lookup_rowtype_tupdesc().
7255  */
7256  HeapTupleHeader td;
7257  HeapTupleData tmptup;
7258  Oid tupType;
7259  int32 tupTypmod;
7260  TupleDesc tupdesc;
7261  MemoryContext oldcontext;
7262 
7263  /* Ensure that any detoasted data winds up in the eval_mcontext */
7264  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7265  /* Get tuple body (note this could involve detoasting) */
7267  MemoryContextSwitchTo(oldcontext);
7268 
7269  /* Build a temporary HeapTuple control structure */
7270  tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
7271  ItemPointerSetInvalid(&(tmptup.t_self));
7272  tmptup.t_tableOid = InvalidOid;
7273  tmptup.t_data = td;
7274 
7275  /* Extract rowtype info */
7276  tupType = HeapTupleHeaderGetTypeId(td);
7277  tupTypmod = HeapTupleHeaderGetTypMod(td);
7278 
7279  /* Now, if the target is record not row, maybe we can optimize ... */
7280  if (target->dtype == PLPGSQL_DTYPE_REC)
7281  {
7282  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7283 
7284  /*
7285  * If we already have an expanded record object in the target
7286  * variable, and the source datum has a matching rowtype, then we
7287  * can skip making a new expanded record and just assign the tuple
7288  * with expanded_record_set_tuple. We consider that there's a
7289  * rowtype match only if it's the same named composite type or
7290  * same registered rowtype. (Checking to reject an anonymous
7291  * rowtype here should be redundant, but let's be safe.)
7292  */
7293  if (rec->erh &&
7294  tupType == rec->erh->er_typeid &&
7295  (tupType != RECORDOID ||
7296  (tupTypmod == rec->erh->er_typmod &&
7297  tupTypmod >= 0)))
7298  {
7299  expanded_record_set_tuple(rec->erh, &tmptup, true);
7300  return;
7301  }
7302 
7303  /*
7304  * If the source datum has a rowtype compatible with the target
7305  * variable, just build a new expanded record and assign the tuple
7306  * into it. Using make_expanded_record_from_typeid() here saves
7307  * one typcache lookup compared to the code below.
7308  */
7309  if (rec->rectypeid == RECORDOID || rec->rectypeid == tupType)
7310  {
7311  ExpandedRecordHeader *newerh;
7312  MemoryContext mcontext = get_eval_mcontext(estate);
7313 
7314  newerh = make_expanded_record_from_typeid(tupType, tupTypmod,
7315  mcontext);
7316  expanded_record_set_tuple(newerh, &tmptup, true);
7317  assign_record_var(estate, rec, newerh);
7318  return;
7319  }
7320 
7321  /*
7322  * Otherwise, we're going to need conversion, so fall through to
7323  * do it the hard way.
7324  */
7325  }
7326 
7327  /*
7328  * ROW target, or unoptimizable RECORD target, so we have to expend a
7329  * lookup to obtain the source datum's tupdesc.
7330  */
7331  tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
7332 
7333  /* Do the move */
7334  exec_move_row(estate, target, &tmptup, tupdesc);
7335 
7336  /* Release tupdesc usage count */
7337  ReleaseTupleDesc(tupdesc);
7338  }
7339 }
#define ER_FLAG_FVALUE_VALID
ExpandedRecordHeader * make_expanded_record_from_typeid(Oid type_id, int32 typmod, MemoryContext parentcontext)
#define ExpandedRecordIsEmpty(erh)
#define VARATT_IS_EXTERNAL_EXPANDED(PTR)
Definition: postgres.h:322
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1641
static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
Definition: pl_exec.c:8088
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
ExpandedRecordHeader * erh
Definition: plpgsql.h:379
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:6811
unsigned int Oid
Definition: postgres_ext.h:31
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:264
signed int int32
Definition: c.h:313
HeapTupleHeader t_data
Definition: htup.h:68
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:472
static ExpandedRecordHeader * make_expanded_record_for_rec(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, TupleDesc srctupdesc, ExpandedRecordHeader *srcerh)
Definition: pl_exec.c:6753
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
Oid t_tableOid
Definition: htup.h:66
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29
#define get_eval_mcontext(estate)
Definition: pl_exec.c:119
#define ER_MAGIC
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:462
static struct @131 value
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:699
PLpgSQL_datum_type dtype
Definition: plpgsql.h:265
#define DatumGetPointer(X)
Definition: postgres.h:532
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:150
static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
Definition: pl_exec.c:6608
#define VARATT_IS_EXTERNAL_EXPANDED_RW(PTR)
Definition: postgres.h:320
Oid rectypeid
Definition: plpgsql.h:372
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:124
#define ExpandedRecordIsDomain(erh)
void deconstruct_expanded_record(ExpandedRecordHeader *erh)
void expanded_record_set_tuple(ExpandedRecordHeader *erh, HeapTuple tuple, bool copy)
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:456

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

References Assert, assign_record_var(), PLpgSQL_execstate::datums, PLpgSQL_variable::dtype, elog, ERROR, eval_mcontext_alloc, exec_assign_value(), exec_cast_value(), expanded_record_get_tupdesc(), expanded_record_set_fields(), lengthof, tupleDesc::natts, PLpgSQL_row::nfields, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_ROW, TupleDescAttr, value, and PLpgSQL_row::varnos.

Referenced by exec_move_row(), and exec_move_row_from_datum().

6816 {
6817  int td_natts = tupdesc ? tupdesc->natts : 0;
6818  int fnum;
6819  int anum;
6820 
6821  /* Handle RECORD-target case */
6822  if (target->dtype == PLPGSQL_DTYPE_REC)
6823  {
6824  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
6825  TupleDesc var_tupdesc;
6826  Datum newvalues_local[64];
6827  bool newnulls_local[64];
6828 
6829  Assert(newerh != NULL); /* caller must have built new object */
6830 
6831  var_tupdesc = expanded_record_get_tupdesc(newerh);
6832 
6833  /*
6834  * Coerce field values if needed. This might involve dealing with
6835  * different sets of dropped columns and/or coercing individual column
6836  * types. That's sort of a pain, but historically plpgsql has allowed
6837  * it, so we preserve the behavior. However, it's worth a quick check
6838  * to see if the tupdescs are identical. (Since expandedrecord.c
6839  * prefers to use refcounted tupdescs from the typcache, expanded
6840  * records with the same rowtype will have pointer-equal tupdescs.)
6841  */
6842  if (var_tupdesc != tupdesc)
6843  {
6844  int vtd_natts = var_tupdesc->natts;
6845  Datum *newvalues;
6846  bool *newnulls;
6847 
6848  /*
6849  * Need workspace arrays. If vtd_natts is small enough, use local
6850  * arrays to save doing a palloc. Even if it's not small, we can
6851  * allocate both the Datum and isnull arrays in one palloc chunk.
6852  */
6853  if (vtd_natts <= lengthof(newvalues_local))
6854  {
6855  newvalues = newvalues_local;
6856  newnulls = newnulls_local;
6857  }
6858  else
6859  {
6860  char *chunk;
6861 
6862  chunk = eval_mcontext_alloc(estate,
6863  vtd_natts * (sizeof(Datum) + sizeof(bool)));
6864  newvalues = (Datum *) chunk;
6865  newnulls = (bool *) (chunk + vtd_natts * sizeof(Datum));
6866  }
6867 
6868  /* Walk over destination columns */
6869  anum = 0;
6870  for (fnum = 0; fnum < vtd_natts; fnum++)
6871  {
6872  Form_pg_attribute attr = TupleDescAttr(var_tupdesc, fnum);
6873  Datum value;
6874  bool isnull;
6875  Oid valtype;
6876  int32 valtypmod;
6877 
6878  if (attr->attisdropped)
6879  {
6880  /* expanded_record_set_fields should ignore this column */
6881  continue; /* skip dropped column in record */
6882  }
6883 
6884  while (anum < td_natts &&
6885  TupleDescAttr(tupdesc, anum)->attisdropped)
6886  anum++; /* skip dropped column in tuple */
6887 
6888  if (anum < td_natts)
6889  {
6890  value = values[anum];
6891  isnull = nulls[anum];
6892  valtype = TupleDescAttr(tupdesc, anum)->atttypid;
6893  valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
6894  anum++;
6895  }
6896  else
6897  {
6898  value = (Datum) 0;
6899  isnull = true;
6900  valtype = UNKNOWNOID;
6901  valtypmod = -1;
6902  }
6903 
6904  /* Cast the new value to the right type, if needed. */
6905  newvalues[fnum] = exec_cast_value(estate,
6906  value,
6907  &isnull,
6908  valtype,
6909  valtypmod,
6910  attr->atttypid,
6911  attr->atttypmod);
6912  newnulls[fnum] = isnull;
6913  }
6914 
6915  values = newvalues;
6916  nulls = newnulls;
6917  }
6918 
6919  /* Insert the coerced field values into the new expanded record */
6920  expanded_record_set_fields(newerh, values, nulls);
6921 
6922  /* Complete the assignment */
6923  assign_record_var(estate, rec, newerh);
6924 
6925  return;
6926  }
6927 
6928  /* newerh should not have been passed in non-RECORD cases */
6929  Assert(newerh == NULL);
6930 
6931  /*
6932  * For a row, we assign the individual field values to the variables the
6933  * row points to.
6934  *
6935  * NOTE: both this code and the record code above silently ignore extra
6936  * columns in the source and assume NULL for missing columns. This is
6937  * pretty dubious but it's the historical behavior.
6938  *
6939  * If we have no input data at all, we'll assign NULL to all columns of
6940  * the row variable.
6941  */
6942  if (target->dtype == PLPGSQL_DTYPE_ROW)
6943  {
6944  PLpgSQL_row *row = (PLpgSQL_row *) target;
6945 
6946  anum = 0;
6947  for (fnum = 0; fnum < row->nfields; fnum++)
6948  {
6949  PLpgSQL_var *var;
6950  Datum value;
6951  bool isnull;
6952  Oid valtype;
6953  int32 valtypmod;
6954 
6955  var = (PLpgSQL_var *) (estate->datums[row->varnos[fnum]]);
6956 
6957  while (anum < td_natts &&
6958  TupleDescAttr(tupdesc, anum)->attisdropped)
6959  anum++; /* skip dropped column in tuple */
6960 
6961  if (anum < td_natts)
6962  {
6963  value = values[anum];
6964  isnull = nulls[anum];
6965  valtype = TupleDescAttr(tupdesc, anum)->atttypid;
6966  valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
6967  anum++;
6968  }
6969  else
6970  {
6971  value = (Datum) 0;
6972  isnull = true;
6973  valtype = UNKNOWNOID;
6974  valtypmod = -1;
6975  }
6976 
6977  exec_assign_value(estate, (PLpgSQL_datum *) var,
6978  value, isnull, valtype, valtypmod);
6979  }
6980 
6981  return;
6982  }
6983 
6984  elog(ERROR, "unsupported target type: %d", target->dtype);
6985 }
static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
Definition: pl_exec.c:8088
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
void expanded_record_set_fields(ExpandedRecordHeader *erh, const Datum *newValues, const bool *isnulls)
#define lengthof(array)
Definition: c.h:629
unsigned int Oid
Definition: postgres_ext.h:31
int natts
Definition: tupdesc.h:82
signed int int32
Definition: c.h:313
PLpgSQL_datum ** datums
Definition: plpgsql.h:1015
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7409
#define ERROR
Definition: elog.h:43
#define eval_mcontext_alloc(estate, sz)
Definition: pl_exec.c:121
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
int * varnos
Definition: plpgsql.h:354
uintptr_t Datum
Definition: postgres.h:365
static struct @131 value
#define Assert(condition)
Definition: c.h:699
int nfields
Definition: plpgsql.h:352
PLpgSQL_datum_type dtype
Definition: plpgsql.h:265
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define elog
Definition: elog.h:219
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:4854

◆ exec_prepare_plan()

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

Definition at line 3943 of file pl_exec.c.

References elog, ereport, errcode(), errhint(), errmsg(), ERROR, exec_simple_check_plan(), PLpgSQL_expr::func, PLpgSQL_execstate::func, plpgsql_parser_setup(), PLpgSQL_expr::query, SPI_ERROR_COPY, SPI_ERROR_TRANSACTION, SPI_keepplan(), SPI_prepare_params(), 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_set().

3946 {
3947  SPIPlanPtr plan;
3948 
3949  /*
3950  * The grammar can't conveniently set expr->func while building the parse
3951  * tree, so make sure it's set before parser hooks need it.
3952  */
3953  expr->func = estate->func;
3954 
3955  /*
3956  * Generate and save the plan
3957  */
3958  plan = SPI_prepare_params(expr->query,
3960  (void *) expr,
3961  cursorOptions);
3962  if (plan == NULL)
3963  {
3964  /* Some SPI errors deserve specific error messages */
3965  switch (SPI_result)
3966  {
3967  case SPI_ERROR_COPY:
3968  ereport(ERROR,
3969  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3970  errmsg("cannot COPY to/from client in PL/pgSQL")));
3971  case SPI_ERROR_TRANSACTION:
3972  ereport(ERROR,
3973  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3974  errmsg("cannot begin/end transactions in PL/pgSQL"),
3975  errhint("Use a BEGIN block with an EXCEPTION clause instead.")));
3976  default:
3977  elog(ERROR, "SPI_prepare_params failed for \"%s\": %s",
3979  }
3980  }
3981  if (keepplan)
3982  SPI_keepplan(plan);
3983  expr->plan = plan;
3984 
3985  /* Check to see if it's a simple expression */
3986  exec_simple_check_plan(estate, expr);
3987 
3988  /*
3989  * Mark expression as not using a read-write param. exec_assign_value has
3990  * to take steps to override this if appropriate; that seems cleaner than
3991  * adding parameters to all other callers.
3992  */
3993  expr->rwparam = -1;
3994 }
int errhint(const char *fmt,...)
Definition: elog.c:987
char * query
Definition: plpgsql.h:217
#define SPI_ERROR_COPY
Definition: spi.h:37
int errcode(int sqlerrcode)
Definition: elog.c:575
PLpgSQL_function * func
Definition: plpgsql.h:980
static void exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:7615
SPIPlanPtr plan
Definition: plpgsql.h:218
int SPI_result
Definition: spi.c:42
#define ERROR
Definition: elog.h:43
const char * SPI_result_code_string(int code)
Definition: spi.c:1609
void(* ParserSetupHook)(struct ParseState *pstate, void *arg)
Definition: params.h:108
void plpgsql_parser_setup(struct ParseState *pstate, PLpgSQL_expr *expr)
Definition: pl_comp.c:1051
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:654
#define ereport(elevel, rest)
Definition: elog.h:122
#define SPI_ERROR_TRANSACTION
Definition: spi.h:43
int rwparam
Definition: plpgsql.h:220
struct PLpgSQL_function * func
Definition: plpgsql.h:223
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
SPIPlanPtr SPI_prepare_params(const char *src, ParserSetupHook parserSetup, void *parserSetupArg, int cursorOptions)
Definition: spi.c:617

◆ exec_run_select()

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

Definition at line 5733 of file pl_exec.c.

References Assert, CURSOR_OPT_PARALLEL_OK, elog, ereport, errcode(), errmsg(), ERROR, PLpgSQL_execstate::eval_lastoid, 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_lastoid, SPI_OK_CURSOR, SPI_OK_SELECT, SPI_processed, SPI_result, SPI_result_code_string(), and SPI_tuptable.

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

5735 {
5736  ParamListInfo paramLI;
5737  int rc;
5738 
5739  /*
5740  * On the first call for this expression generate the plan.
5741  *
5742  * If we don't need to return a portal, then we're just going to execute
5743  * the query once, which means it's OK to use a parallel plan, even if the
5744  * number of rows being fetched is limited. If we do need to return a
5745  * portal, the caller might do cursor operations, which parallel query
5746  * can't support.
5747  */
5748  if (expr->plan == NULL)
5749  exec_prepare_plan(estate, expr,
5750  portalP == NULL ? CURSOR_OPT_PARALLEL_OK : 0, true);
5751 
5752  /*
5753  * Set up ParamListInfo to pass to executor
5754  */
5755  paramLI = setup_param_list(estate, expr);
5756 
5757  /*
5758  * If a portal was requested, put the query and paramlist into the portal
5759  */
5760  if (portalP != NULL)
5761  {
5762  *portalP = SPI_cursor_open_with_paramlist(NULL, expr->plan,
5763  paramLI,
5764  estate->readonly_func);
5765  if (*portalP == NULL)
5766  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
5768  exec_eval_cleanup(estate);
5769  return SPI_OK_CURSOR;
5770  }
5771 
5772  /*
5773  * Execute the query
5774  */
5775  rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
5776  estate->readonly_func, maxtuples);
5777  if (rc != SPI_OK_SELECT)
5778  ereport(ERROR,
5779  (errcode(ERRCODE_SYNTAX_ERROR),
5780  errmsg("query \"%s\" is not a SELECT", expr->query)));
5781 
5782  /* Save query results for eventual cleanup */
5783  Assert(estate->eval_tuptable == NULL);
5784  estate->eval_tuptable = SPI_tuptable;
5785  estate->eval_processed = SPI_processed;
5786  estate->eval_lastoid = SPI_lastoid;
5787 
5788  return rc;
5789 }
char * query
Definition: plpgsql.h:217
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions, bool keepplan)
Definition: pl_exec.c:3943
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1039
uint64 eval_processed
Definition: plpgsql.h:1040
Portal SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan, ParamListInfo params, bool read_only)
Definition: spi.c:1204
SPITupleTable * SPI_tuptable
Definition: spi.c:41
int errcode(int sqlerrcode)
Definition: elog.c:575
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:3922
#define SPI_OK_CURSOR
Definition: spi.h:59
uint64 SPI_processed
Definition: spi.c:39
SPIPlanPtr plan
Definition: plpgsql.h:218
int SPI_result
Definition: spi.c:42
#define ERROR
Definition: elog.h:43
int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params, bool read_only, long tcount)
Definition: spi.c:467
const char * SPI_result_code_string(int code)
Definition: spi.c:1609
static ParamListInfo setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:6115
#define ereport(elevel, rest)
Definition: elog.h:122
Oid SPI_lastoid
Definition: spi.c:40
#define SPI_OK_SELECT
Definition: spi.h:54
#define Assert(condition)
Definition: c.h:699
bool readonly_func
Definition: plpgsql.h:993
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2653
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219

◆ exec_save_simple_expr()

static void exec_save_simple_expr ( PLpgSQL_expr expr,
CachedPlan cplan 
)
static

Definition at line 7714 of file pl_exec.c.

References Assert, castNode, CMD_SELECT, PlannedStmt::commandType, elog, ERROR, PLpgSQL_expr::expr_simple_expr, PLpgSQL_expr::expr_simple_generation, PLpgSQL_expr::expr_simple_in_use, PLpgSQL_expr::expr_simple_lxid, PLpgSQL_expr::expr_simple_state, PLpgSQL_expr::expr_simple_type, PLpgSQL_expr::expr_simple_typmod, exprType(), exprTypmod(), CachedPlan::generation, Plan::initPlan, InvalidLocalTransactionId, IsA, Plan::lefttree, linitial, linitial_node, list_length(), nodeTag, OUTER_VAR, PlannedStmt::planTree, Plan::qual, Plan::righttree, CachedPlan::stmt_list, and Plan::targetlist.

Referenced by exec_eval_simple_expr(), and exec_simple_check_plan().

7715 {
7716  PlannedStmt *stmt;
7717  Plan *plan;
7718  Expr *tle_expr;
7719 
7720  /*
7721  * Given the checks that exec_simple_check_plan did, none of the Asserts
7722  * here should ever fail.
7723  */
7724 
7725  /* Extract the single PlannedStmt */
7726  Assert(list_length(cplan->stmt_list) == 1);
7727  stmt = linitial_node(PlannedStmt, cplan->stmt_list);
7728  Assert(stmt->commandType == CMD_SELECT);
7729 
7730  /*
7731  * Ordinarily, the plan node should be a simple Result. However, if
7732  * force_parallel_mode is on, the planner might've stuck a Gather node
7733  * atop that. The simplest way to deal with this is to look through the
7734  * Gather node. The Gather node's tlist would normally contain a Var
7735  * referencing the child node's output, but it could also be a Param, or
7736  * it could be a Const that setrefs.c copied as-is.
7737  */
7738  plan = stmt->planTree;
7739  for (;;)
7740  {
7741  /* Extract the single tlist expression */
7742  Assert(list_length(plan->targetlist) == 1);
7743  tle_expr = castNode(TargetEntry, linitial(plan->targetlist))->expr;
7744 
7745  if (IsA(plan, Result))
7746  {
7747  Assert(plan->lefttree == NULL &&
7748  plan->righttree == NULL &&
7749  plan->initPlan == NULL &&
7750  plan->qual == NULL &&
7751  ((Result *) plan)->resconstantqual == NULL);
7752  break;
7753  }
7754  else if (IsA(plan, Gather))
7755  {
7756  Assert(plan->lefttree != NULL &&
7757  plan->righttree == NULL &&
7758  plan->initPlan == NULL &&
7759  plan->qual == NULL);
7760  /* If setrefs.c copied up a Const, no need to look further */
7761  if (IsA(tle_expr, Const))
7762  break;
7763  /* Otherwise, it had better be a Param or an outer Var */
7764  Assert(IsA(tle_expr, Param) ||(IsA(tle_expr, Var) &&
7765  ((Var *) tle_expr)->varno == OUTER_VAR));
7766  /* Descend to the child node */
7767  plan = plan->lefttree;
7768  }
7769  else
7770  elog(ERROR, "unexpected plan node type: %d",
7771  (int) nodeTag(plan));
7772  }
7773 
7774  /*
7775  * Save the simple expression, and initialize state to "not valid in
7776  * current transaction".
7777  */
7778  expr->expr_simple_expr = tle_expr;
7779  expr->expr_simple_generation = cplan->generation;
7780  expr->expr_simple_state = NULL;
7781  expr->expr_simple_in_use = false;
7783  /* Also stash away the expression result type */
7784  expr->expr_simple_type = exprType((Node *) tle_expr);
7785  expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
7786 }
int expr_simple_generation
Definition: plpgsql.h:230
List * qual
Definition: plannodes.h:147
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
#define castNode(_type_, nodeptr)
Definition: nodes.h:586
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:276
Definition: nodes.h:517
Definition: primnodes.h:164
#define linitial_node(type, l)
Definition: pg_list.h:114
struct Plan * planTree
Definition: plannodes.h:63
struct Plan * righttree
Definition: plannodes.h:149
#define linitial(l)
Definition: pg_list.h:111
#define ERROR
Definition: elog.h:43
Expr * expr_simple_expr
Definition: plpgsql.h:229
ExprState * expr_simple_state
Definition: plpgsql.h:240
CmdType commandType
Definition: plannodes.h:45
LocalTransactionId expr_simple_lxid
Definition: plpgsql.h:242
#define Assert(condition)
Definition: c.h:699
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int generation
Definition: plancache.h:141
static int list_length(const List *l)
Definition: pg_list.h:89
struct Plan * lefttree
Definition: plannodes.h:148
#define nodeTag(nodeptr)
Definition: nodes.h:522
List * targetlist
Definition: plannodes.h:146
int32 expr_simple_typmod
Definition: plpgsql.h:232
List * initPlan
Definition: plannodes.h:150
#define InvalidLocalTransactionId
Definition: lock.h:69
List * stmt_list
Definition: plancache.h:133
bool expr_simple_in_use
Definition: plpgsql.h:241
#define elog
Definition: elog.h:219
#define OUTER_VAR
Definition: primnodes.h:155
Oid expr_simple_type
Definition: plpgsql.h:231

◆ exec_set_found()

static void exec_set_found ( PLpgSQL_execstate estate,
bool  state 
)
static

Definition at line 7900 of file pl_exec.c.

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

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

7901 {
7902  PLpgSQL_var *var;
7903 
7904  var = (PLpgSQL_var *) (estate->datums[estate->found_varno]);
7905  assign_simple_var(estate, var, BoolGetDatum(state), false, false);
7906 }
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8047
PLpgSQL_datum ** datums
Definition: plpgsql.h:1015
#define BoolGetDatum(X)
Definition: postgres.h:385
Definition: regguts.h:298

◆ exec_simple_check_plan()

static void exec_simple_check_plan ( PLpgSQL_execstate estate,
PLpgSQL_expr expr 
)
static

Definition at line 7615 of file pl_exec.c.

References Assert, CMD_SELECT, Query::commandType, Query::cteList, Query::distinctClause, exec_save_simple_expr(), PLpgSQL_expr::expr_simple_expr, FromExpr::fromlist, get_eval_mcontext, Query::groupClause, Query::groupingSets, Query::hasAggs, Query::hasSubLinks, Query::hasTargetSRFs, Query::hasWindowFuncs, Query::havingQual, IsA, Query::jointree, Query::limitCount, Query::limitOffset, linitial, list_length(), MemoryContextSwitchTo(), NIL, PLpgSQL_expr::plan, FromExpr::quals, CachedPlanSource::query_list, ReleaseCachedPlan(), Query::rtable, Query::setOperations, Query::sortClause, SPI_plan_get_cached_plan(), SPI_plan_get_plan_sources(), Query::targetList, and Query::windowClause.

Referenced by exec_prepare_plan().

7616 {
7617  List *plansources;
7618  CachedPlanSource *plansource;
7619  Query *query;
7620  CachedPlan *cplan;
7621  MemoryContext oldcontext;
7622 
7623  /*
7624  * Initialize to "not simple".
7625  */
7626  expr->expr_simple_expr = NULL;
7627 
7628  /*
7629  * Check the analyzed-and-rewritten form of the query to see if we will be
7630  * able to treat it as a simple expression. Since this function is only
7631  * called immediately after creating the CachedPlanSource, we need not
7632  * worry about the query being stale.
7633  */
7634 
7635  /*
7636  * We can only test queries that resulted in exactly one CachedPlanSource
7637  */
7638  plansources = SPI_plan_get_plan_sources(expr->plan);
7639  if (list_length(plansources) != 1)
7640  return;
7641  plansource = (CachedPlanSource *) linitial(plansources);
7642 
7643  /*
7644  * 1. There must be one single querytree.
7645  */
7646  if (list_length(plansource->query_list) != 1)
7647  return;
7648  query = (Query *) linitial(plansource->query_list);
7649 
7650  /*
7651  * 2. It must be a plain SELECT query without any input tables
7652  */
7653  if (!IsA(query, Query))
7654  return;
7655  if (query->commandType != CMD_SELECT)
7656  return;
7657  if (query->rtable != NIL)
7658  return;
7659 
7660  /*
7661  * 3. Can't have any subplans, aggregates, qual clauses either. (These
7662  * tests should generally match what inline_function() checks before
7663  * inlining a SQL function; otherwise, inlining could change our
7664  * conclusion about whether an expression is simple, which we don't want.)
7665  */
7666  if (query->hasAggs ||
7667  query->hasWindowFuncs ||
7668  query->hasTargetSRFs ||
7669  query->hasSubLinks ||
7670  query->cteList ||
7671  query->jointree->fromlist ||
7672  query->jointree->quals ||
7673  query->groupClause ||
7674  query->groupingSets ||
7675  query->havingQual ||
7676  query->windowClause ||
7677  query->distinctClause ||
7678  query->sortClause ||
7679  query->limitOffset ||
7680  query->limitCount ||
7681  query->setOperations)
7682  return;
7683 
7684  /*
7685  * 4. The query must have a single attribute as result
7686  */
7687  if (list_length(query->targetList) != 1)
7688  return;
7689 
7690  /*
7691  * OK, we can treat it as a simple plan.
7692  *
7693  * Get the generic plan for the query. If replanning is needed, do that
7694  * work in the eval_mcontext.
7695  */
7696  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7697  cplan = SPI_plan_get_cached_plan(expr->plan);
7698  MemoryContextSwitchTo(oldcontext);
7699 
7700  /* Can't fail, because we checked for a single CachedPlanSource above */
7701  Assert(cplan != NULL);
7702 
7703  /* Share the remaining work with replan code path */
7704  exec_save_simple_expr(expr, cplan);
7705 
7706  /* Release our plan refcount */
7707  ReleaseCachedPlan(cplan, true);
7708 }
Node * limitOffset
Definition: parsenodes.h:160
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
List * sortClause
Definition: parsenodes.h:158
FromExpr * jointree
Definition: parsenodes.h:138
bool hasAggs
Definition: parsenodes.h:125
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
List * groupingSets
Definition: parsenodes.h:150
List * fromlist
Definition: primnodes.h:1479
Node * quals
Definition: primnodes.h:1480
static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
Definition: pl_exec.c:7714
SPIPlanPtr plan
Definition: plpgsql.h:218
List * windowClause
Definition: parsenodes.h:154
List * targetList
Definition: parsenodes.h:140
CachedPlan * SPI_plan_get_cached_plan(SPIPlanPtr plan)
Definition: spi.c:1702
#define linitial(l)
Definition: pg_list.h:111
List * rtable
Definition: parsenodes.h:137
List * distinctClause
Definition: parsenodes.h:156
Node * limitCount
Definition: parsenodes.h:161
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1258
Expr * expr_simple_expr
Definition: plpgsql.h:229
#define get_eval_mcontext(estate)
Definition: pl_exec.c:119
CmdType commandType
Definition: parsenodes.h:112
bool hasTargetSRFs
Definition: parsenodes.h:127
#define Assert(condition)
Definition: c.h:699
bool hasWindowFuncs
Definition: parsenodes.h:126
static int list_length(const List *l)
Definition: pg_list.h:89
List * cteList
Definition: parsenodes.h:135
Node * setOperations
Definition: parsenodes.h:165
List * groupClause
Definition: parsenodes.h:148
bool hasSubLinks
Definition: parsenodes.h:128
List * SPI_plan_get_plan_sources(SPIPlanPtr plan)
Definition: spi.c:1686
List * query_list
Definition: plancache.h:95
Node * havingQual
Definition: parsenodes.h:152
Definition: pg_list.h:45

◆ exec_stmt()

static int exec_stmt ( PLpgSQL_execstate estate,
PLpgSQL_stmt stmt 
)
static

Definition at line 1886 of file pl_exec.c.

References CHECK_FOR_INTERRUPTS, PLpgSQL_stmt::cmd_type, PLpgSQL_stmt_set::cmd_type, 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_set(), exec_stmt_while(), plpgsql_plugin_ptr, 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_SET, PLPGSQL_STMT_WHILE, PLpgSQL_plugin::stmt_beg, and PLpgSQL_plugin::stmt_end.

Referenced by exec_stmts().

1887 {
1888  PLpgSQL_stmt *save_estmt;
1889  int rc = -1;
1890 
1891  save_estmt = estate->err_stmt;
1892  estate->err_stmt = stmt;
1893 
1894  /* Let the plugin know that we are about to execute this statement */
1895  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
1896  ((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt);
1897 
1899 
1900  switch (stmt->cmd_type)
1901  {
1902  case PLPGSQL_STMT_BLOCK:
1903  rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt);
1904  break;
1905 
1906  case PLPGSQL_STMT_ASSIGN:
1907  rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
1908  break;
1909 
1910  case PLPGSQL_STMT_PERFORM:
1911  rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt);
1912  break;
1913 
1914  case PLPGSQL_STMT_CALL:
1915  rc = exec_stmt_call(estate, (PLpgSQL_stmt_call *) stmt);
1916  break;
1917 
1918  case PLPGSQL_STMT_GETDIAG:
1919  rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt);
1920  break;
1921 
1922  case PLPGSQL_STMT_IF:
1923  rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);
1924  break;
1925 
1926  case PLPGSQL_STMT_CASE:
1927  rc = exec_stmt_case(estate, (PLpgSQL_stmt_case *) stmt);
1928  break;
1929 
1930  case PLPGSQL_STMT_LOOP:
1931  rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt);
1932  break;
1933 
1934  case PLPGSQL_STMT_WHILE:
1935  rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt);
1936  break;
1937 
1938  case PLPGSQL_STMT_FORI:
1939  rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt);
1940  break;
1941 
1942  case PLPGSQL_STMT_FORS:
1943  rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt);
1944  break;
1945 
1946  case PLPGSQL_STMT_FORC:
1947  rc = exec_stmt_forc(estate, (PLpgSQL_stmt_forc *) stmt);
1948  break;
1949 
1951  rc = exec_stmt_foreach_a(estate, (PLpgSQL_stmt_foreach_a *) stmt);
1952  break;
1953 
1954  case PLPGSQL_STMT_EXIT:
1955  rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt);
1956  break;
1957 
1958  case PLPGSQL_STMT_RETURN:
1959  rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt);
1960  break;
1961 
1963  rc = exec_stmt_return_next(estate, (PLpgSQL_stmt_return_next *) stmt);
1964  break;
1965 
1967  rc = exec_stmt_return_query(estate, (PLpgSQL_stmt_return_query *) stmt);
1968  break;
1969 
1970  case PLPGSQL_STMT_RAISE:
1971  rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt);
1972  break;
1973 
1974  case PLPGSQL_STMT_ASSERT:
1975  rc = exec_stmt_assert(estate, (PLpgSQL_stmt_assert *) stmt);
1976  break;
1977 
1978  case PLPGSQL_STMT_EXECSQL:
1979  rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt);
1980  break;
1981 
1983  rc = exec_stmt_dynexecute(estate, (PLpgSQL_stmt_dynexecute *) stmt);
1984  break;
1985 
1986  case PLPGSQL_STMT_DYNFORS:
1987  rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt);
1988  break;
1989 
1990  case PLPGSQL_STMT_OPEN:
1991  rc = exec_stmt_open(estate, (PLpgSQL_stmt_open *) stmt);
1992  break;
1993 
1994  case PLPGSQL_STMT_FETCH:
1995  rc = exec_stmt_fetch(estate, (PLpgSQL_stmt_fetch *) stmt);
1996  break;
1997 
1998  case PLPGSQL_STMT_CLOSE:
1999  rc = exec_stmt_close(estate, (PLpgSQL_stmt_close *) stmt);
2000  break;
2001 
2002  case PLPGSQL_STMT_COMMIT:
2003  rc = exec_stmt_commit(estate, (PLpgSQL_stmt_commit *) stmt);
2004  break;
2005 
2006  case PLPGSQL_STMT_ROLLBACK:
2007  rc = exec_stmt_rollback(estate, (PLpgSQL_stmt_rollback *) stmt);
2008  break;
2009 
2010  case PLPGSQL_STMT_SET:
2011  rc = exec_stmt_set(estate, (PLpgSQL_stmt_set *) stmt);
2012  break;
2013 
2014  default:
2015  estate->err_stmt = save_estmt;
2016  elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
2017  }
2018 
2019  /* Let the plugin know that we have finished executing this statement */
2020  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
2021  ((*plpgsql_plugin_ptr)->stmt_end) (estate, stmt);
2022 
2023  estate->err_stmt = save_estmt;
2024 
2025  return rc;
2026 }
static int exec_stmt_set(PLpgSQL_execstate *estate, PLpgSQL_stmt_set *stmt)
Definition: pl_exec.c:4764
static int exec_stmt_execsql(PLpgSQL_execstate *estate, PLpgSQL_stmt_execsql *stmt)
Definition: pl_exec.c:4005
static int exec_stmt_case(PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
Definition: pl_exec.c:2396
PLpgSQL_stmt * err_stmt
Definition: plpgsql.h:1045
static int exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
Definition: pl_exec.c:2066
static int exec_stmt_return_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_return_query *stmt)
Definition: pl_exec.c:3393
static int exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt)
Definition: pl_exec.c:2843
static int exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
Definition: pl_exec.c:4433
static int exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
Definition: pl_exec.c:4406
static int exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
Definition: pl_exec.c:2482
static int exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
Definition: pl_exec.c:2678
static int exec_stmt_assign(PLpgSQL_execstate *estate, PLpgSQL_stmt_assign *stmt)
Definition: pl_exec.c:2035
#define ERROR
Definition: elog.h:43
static int exec_stmt_rollback(PLpgSQL_execstate *estate, PLpgSQL_stmt_rollback *stmt)
Definition: pl_exec.c:4742
static int exec_stmt_assert(PLpgSQL_execstate *estate, PLpgSQL_stmt_assert *stmt)
Definition: pl_exec.c:3733
static int exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
Definition: pl_exec.c:3522
static int exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
Definition: pl_exec.c:2535
static int exec_stmt_dynexecute(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynexecute *stmt)
Definition: pl_exec.c:4217
PLpgSQL_plugin ** plpgsql_plugin_ptr
Definition: pl_handler.c:58
static int exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
Definition: pl_exec.c:2250
static int exec_stmt_exit(PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt)
Definition: pl_exec.c:2999
static int exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
Definition: pl_exec.c:3032
static int exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
Definition: pl_exec.c:2504
static int exec_stmt_commit(PLpgSQL_execstate *estate, PLpgSQL_stmt_commit *stmt)
Definition: pl_exec.c:4723
static int exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
Definition: pl_exec.c:4589
static int exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
Definition: pl_exec.c:1526
static int exec_stmt_return_next(PLpgSQL_execstate *estate, PLpgSQL_stmt_return_next *stmt)
Definition: pl_exec.c:3175
static int exec_stmt_close(PLpgSQL_execstate *estate, PLpgSQL_stmt_close *stmt)
Definition: pl_exec.c:4680
static int exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
Definition: pl_exec.c:2366
static int exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
Definition: pl_exec.c:2051
PLpgSQL_stmt_type cmd_type
Definition: plpgsql.h:444
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
void(* stmt_end)(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
Definition: plpgsql.h:1088
#define elog
Definition: elog.h:219
void(* stmt_beg)(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
Definition: plpgsql.h:1087
static int exec_stmt_forc(PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt)
Definition: pl_exec.c:2707

◆ exec_stmt_assert()

static int exec_stmt_assert ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assert stmt 
)
static

Definition at line 3733 of file pl_exec.c.

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

Referenced by exec_stmt().

3734 {
3735  bool value;
3736  bool isnull;
3737 
3738  /* do nothing when asserts are not enabled */
3739  if (!plpgsql_check_asserts)
3740  return PLPGSQL_RC_OK;
3741 
3742  value = exec_eval_boolean(estate, stmt->cond, &isnull);
3743  exec_eval_cleanup(estate);
3744 
3745  if (isnull || !value)
3746  {
3747  char *message = NULL;
3748 
3749  if (stmt->message != NULL)
3750  {
3751  Datum val;
3752  Oid typeid;
3753  int32 typmod;
3754 
3755  val = exec_eval_expr(estate, stmt->message,
3756  &isnull, &typeid, &typmod);
3757  if (!isnull)
3758  message = convert_value_to_string(estate, val, typeid);
3759  /* we mustn't do exec_eval_cleanup here */
3760  }
3761 
3762  ereport(ERROR,
3763  (errcode(ERRCODE_ASSERT_FAILURE),
3764  message ? errmsg_internal("%s", message) :
3765  errmsg("assertion failed")));
3766  }
3767 
3768  return PLPGSQL_RC_OK;
3769 }
int errcode(int sqlerrcode)
Definition: elog.c:575
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:3922
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:313
#define ERROR
Definition: elog.h:43
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5650
PLpgSQL_expr * message
Definition: plpgsql.h:849
static bool exec_eval_boolean(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
Definition: pl_exec.c:5627
#define ereport(elevel, rest)
Definition: elog.h:122
uintptr_t Datum
Definition: postgres.h:365
static struct @131 value
int errmsg_internal(const char *fmt,...)
Definition: elog.c:827
int errmsg(const char *fmt,...)
Definition: elog.c:797
static char * convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
Definition: pl_exec.c:7380
PLpgSQL_expr * cond
Definition: plpgsql.h:848
bool plpgsql_check_asserts
Definition: pl_handler.c:50
long val
Definition: informix.c:689

◆ exec_stmt_assign()

static int exec_stmt_assign ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assign stmt 
)
static

Definition at line 2035 of file pl_exec.c.

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

Referenced by exec_stmt().

2036 {
2037  Assert(stmt->varno >= 0);
2038 
2039  exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);
2040 
2041  return PLPGSQL_RC_OK;
2042 }
PLpgSQL_datum ** datums
Definition: plpgsql.h:1015
static void exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
Definition: pl_exec.c:4789
#define Assert(condition)
Definition: c.h:699
PLpgSQL_expr * expr
Definition: plpgsql.h:500

◆ exec_stmt_block()

static int exec_stmt_block ( PLpgSQL_execstate estate,
PLpgSQL_stmt_block block 
)
static

Definition at line 1526 of file pl_exec.c.

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, 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_stmt(), plpgsql_exec_event_trigger(), plpgsql_exec_function(), and plpgsql_exec_trigger().

1527 {
1528  volatile int rc = -1;
1529  int i;
1530 
1531  /*
1532  * First initialize all variables declared in this block
1533  */
1534  estate->err_text = gettext_noop("during statement block local variable initialization");
1535 
1536  for (i = 0; i < block->n_initvars; i++)
1537  {
1538  int n = block->initvarnos[i];
1539  PLpgSQL_datum *datum = estate->datums[n];
1540 
1541  /*
1542  * The set of dtypes handled here must match plpgsql_add_initdatums().
1543  *
1544  * Note that we currently don't support promise datums within blocks,
1545  * only at a function's outermost scope, so we needn't handle those
1546  * here.
1547  */
1548  switch (datum->dtype)
1549  {
1550  case PLPGSQL_DTYPE_VAR:
1551  {
1552  PLpgSQL_var *var = (PLpgSQL_var *) datum;
1553 
1554  /*
1555  * Free any old value, in case re-entering block, and
1556  * initialize to NULL
1557  */
1558  assign_simple_var(estate, var, (Datum) 0, true, false);
1559 
1560  if (var->default_val == NULL)
1561  {
1562  /*
1563  * If needed, give the datatype a chance to reject
1564  * NULLs, by assigning a NULL to the variable. We
1565  * claim the value is of type UNKNOWN, not the var's
1566  * datatype, else coercion will be skipped.
1567  */
1568  if (var->datatype->typtype == TYPTYPE_DOMAIN)
1569  exec_assign_value(estate,
1570  (PLpgSQL_datum *) var,
1571  (Datum) 0,
1572  true,
1573  UNKNOWNOID,
1574  -1);
1575 
1576  /* parser should have rejected NOT NULL */
1577  Assert(!var->notnull);
1578  }
1579  else
1580  {
1581  exec_assign_expr(estate, (PLpgSQL_datum *) var,
1582  var->default_val);
1583  }
1584  }
1585  break;
1586 
1587  case PLPGSQL_DTYPE_REC:
1588  {
1589  PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
1590 
1591  /*
1592  * Deletion of any existing object will be handled during
1593  * the assignments below, and in some cases it's more
1594  * efficient for us not to get rid of it beforehand.
1595  */
1596  if (rec->default_val == NULL)
1597  {
1598  /*
1599  * If needed, give the datatype a chance to reject
1600  * NULLs, by assigning a NULL to the variable.
1601  */
1602  exec_move_row(estate, (PLpgSQL_variable *) rec,
1603  NULL, NULL);
1604 
1605  /* parser should have rejected NOT NULL */
1606  Assert(!rec->notnull);
1607  }
1608  else
1609  {
1610  exec_assign_expr(estate, (PLpgSQL_datum *) rec,
1611  rec->default_val);
1612  }
1613  }
1614  break;
1615 
1616  default:
1617  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
1618  }
1619  }
1620 
1621  if (block->exceptions)
1622  {
1623  /*
1624  * Execute the statements in the block's body inside a sub-transaction
1625  */
1626  MemoryContext oldcontext = CurrentMemoryContext;
1628  ExprContext *old_eval_econtext = estate->eval_econtext;
1629  ErrorData *save_cur_error = estate->cur_error;
1630  MemoryContext stmt_mcontext;
1631 
1632  estate->err_text = gettext_noop("during statement block entry");
1633 
1634  /*
1635  * We will need a stmt_mcontext to hold the error data if an error
1636  * occurs. It seems best to force it to exist before entering the
1637  * subtransaction, so that we reduce the risk of out-of-memory during
1638  * error recovery, and because this greatly simplifies restoring the
1639  * stmt_mcontext stack to the correct state after an error. We can
1640  * ameliorate the cost of this by allowing the called statements to
1641  * use this mcontext too; so we don't push it down here.
1642  */
1643  stmt_mcontext = get_stmt_mcontext(estate);
1644 
1646  /* Want to run statements inside function's memory context */
1647  MemoryContextSwitchTo(oldcontext);
1648 
1649  PG_TRY();
1650  {
1651  /*
1652  * We need to run the block's statements with a new eval_econtext
1653  * that belongs to the current subtransaction; if we try to use
1654  * the outer econtext then ExprContext shutdown callbacks will be
1655  * called at the wrong times.
1656  */
1657  plpgsql_create_econtext(estate);
1658 
1659  estate->err_text = NULL;
1660 
1661  /* Run the block's statements */
1662  rc = exec_stmts(estate, block->body);
1663 
1664  estate->err_text = gettext_noop("during statement block exit");
1665 
1666  /*
1667  * If the block ended with RETURN, we may need to copy the return
1668  * value out of the subtransaction eval_context. We can avoid a
1669  * physical copy if the value happens to be a R/W expanded object.
1670  */
1671  if (rc == PLPGSQL_RC_RETURN &&
1672  !estate->retisset &&
1673  !estate->retisnull)
1674  {
1675  int16 resTypLen;
1676  bool resTypByVal;
1677 
1678  get_typlenbyval(estate->rettype, &resTypLen, &resTypByVal);
1679  estate->retval = datumTransfer(estate->retval,
1680  resTypByVal, resTypLen);
1681  }
1682 
1683  /* Commit the inner transaction, return to outer xact context */
1685  MemoryContextSwitchTo(oldcontext);
1686  CurrentResourceOwner = oldowner;
1687 
1688  /* Assert that the stmt_mcontext stack is unchanged */
1689  Assert(stmt_mcontext == estate->stmt_mcontext);
1690 
1691  /*
1692  * Revert to outer eval_econtext. (The inner one was
1693  * automatically cleaned up during subxact exit.)
1694  */
1695  estate->eval_econtext = old_eval_econtext;
1696  }
1697  PG_CATCH();
1698  {
1699  ErrorData *edata;
1700  ListCell *e;
1701 
1702  estate->err_text = gettext_noop("during exception cleanup");
1703 
1704  /* Save error info in our stmt_mcontext */
1705  MemoryContextSwitchTo(stmt_mcontext);
1706  edata = CopyErrorData();
1707  FlushErrorState();
1708 
1709  /* Abort the inner transaction */
1711  MemoryContextSwitchTo(oldcontext);
1712  CurrentResourceOwner = oldowner;
1713 
1714  /*
1715  * Set up the stmt_mcontext stack as though we had restored our
1716  * previous state and then done push_stmt_mcontext(). The push is
1717  * needed so that statements in the exception handler won't
1718  * clobber the error data that's in our stmt_mcontext.
1719  */
1720  estate->stmt_mcontext_parent = stmt_mcontext;
1721  estate->stmt_mcontext = NULL;
1722 
1723  /*
1724  * Now we can delete any nested stmt_mcontexts that might have
1725  * been created as children of ours. (Note: we do not immediately
1726  * release any statement-lifespan data that might have been left
1727  * behind in stmt_mcontext itself. We could attempt that by doing
1728  * a MemoryContextReset on it before collecting the error data
1729  * above, but it seems too risky to do any significant amount of
1730  * work before collecting the error.)
1731  */
1732  MemoryContextDeleteChildren(stmt_mcontext);
1733 
1734  /* Revert to outer eval_econtext */
1735  estate->eval_econtext = old_eval_econtext;
1736 
1737  /*
1738  * Must clean up the econtext too. However, any tuple table made
1739  * in the subxact will have been thrown away by SPI during subxact
1740  * abort, so we don't need to (and mustn't try to) free the
1741  * eval_tuptable.
1742  */
1743  estate->eval_tuptable = NULL;
1744  exec_eval_cleanup(estate);
1745 
1746  /* Look for a matching exception handler */
1747  foreach(e, block->exceptions->exc_list)
1748  {
1749  PLpgSQL_exception *exception = (PLpgSQL_exception *) lfirst(e);
1750 
1751  if (exception_matches_conditions(edata, exception->conditions))
1752  {
1753  /*
1754  * Initialize the magic SQLSTATE and SQLERRM variables for
1755  * the exception block; this also frees values from any
1756  * prior use of the same exception. We needn't do this
1757  * until we have found a matching exception.
1758  */
1759  PLpgSQL_var *state_var;
1760  PLpgSQL_var *errm_var;
1761 
1762  state_var = (PLpgSQL_var *)
1763  estate->datums[block->exceptions->sqlstate_varno];
1764  errm_var = (PLpgSQL_var *)
1765  estate->datums[block->exceptions->sqlerrm_varno];
1766 
1767  assign_text_var(estate, state_var,
1768  unpack_sql_state(edata->sqlerrcode));
1769  assign_text_var(estate, errm_var, edata->message);
1770 
1771  /*
1772  * Also set up cur_error so the error data is accessible
1773  * inside the handler.
1774  */
1775  estate->cur_error = edata;
1776 
1777  estate->err_text = NULL;
1778 
1779  rc = exec_stmts(estate, exception->action);
1780 
1781  break;
1782  }
1783  }
1784 
1785  /*
1786  * Restore previous state of cur_error, whether or not we executed
1787  * a handler. This is needed in case an error got thrown from
1788  * some inner block's exception handler.
1789  */
1790  estate->cur_error = save_cur_error;
1791 
1792  /* If no match found, re-throw the error */
1793  if (e == NULL)
1794  ReThrowError(edata);
1795 
1796  /* Restore stmt_mcontext stack and release the error data */
1797  pop_stmt_mcontext(estate);
1798  MemoryContextReset(stmt_mcontext);
1799  }
1800  PG_END_TRY();
1801 
1802  Assert(save_cur_error == estate->cur_error);
1803  }
1804  else
1805  {
1806  /*
1807  * Just execute the statements in the block's body
1808  */
1809  estate->err_text = NULL;
1810 
1811  rc = exec_stmts(estate, block->body);
1812  }
1813 
1814  estate->err_text = NULL;
1815 
1816  /*
1817  * Handle the return code. This is intentionally different from
1818  * LOOP_RC_PROCESSING(): CONTINUE never matches a block, and EXIT matches
1819  * a block only if there is a label match.
1820  */
1821  switch (rc)
1822  {
1823  case PLPGSQL_RC_OK:
1824  case PLPGSQL_RC_RETURN:
1825  case PLPGSQL_RC_CONTINUE:
1826  return rc;
1827 
1828  case PLPGSQL_RC_EXIT:
1829  if (estate->exitlabel == NULL)
1830  return PLPGSQL_RC_EXIT;
1831  if (block->label == NULL)
1832  return PLPGSQL_RC_EXIT;
1833  if (strcmp(block->label, estate->exitlabel) != 0)
1834  return PLPGSQL_RC_EXIT;
1835  estate->exitlabel = NULL;
1836  return PLPGSQL_RC_OK;
1837 
1838  default:
1839  elog(ERROR, "unrecognized rc: %d", rc);
1840  }
1841 
1842  return PLPGSQL_RC_OK;
1843 }
signed short int16
Definition: c.h:312
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1039
int sqlerrcode
Definition: elog.h:342
ErrorData * CopyErrorData(void)
Definition: elog.c:1497
ResourceOwner CurrentResourceOwner
Definition: resowner.c:140
void ReleaseCurrentSubTransaction(void)
Definition: xact.c:4217
char * unpack_sql_state(int sql_state)
Definition: elog.c:2849
PLpgSQL_type * datatype
Definition: plpgsql.h:296
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define gettext_noop(x)
Definition: c.h:1036
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:8047
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:3922
PLpgSQL_datum_type dtype
Definition: plpgsql.h:253
void FlushErrorState(void)
Definition: elog.c:1587
PLpgSQL_datum ** datums
Definition: plpgsql.h:1015
static void exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
Definition: pl_exec.c:4789
#define ERROR
Definition: elog.h:43
PLpgSQL_expr * default_val
Definition: plpgsql.h:293
void RollbackAndReleaseCurrentSubTransaction(void)
Definition: xact.c:4251
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1441
static bool exception_matches_conditions(ErrorData *edata, PLpgSQL_condition *cond)
Definition: pl_exec.c:1492
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:256
ErrorData * cur_error
Definition: plpgsql.h:998
MemoryContext stmt_mcontext_parent
Definition: plpgsql.h:1036
uintptr_t Datum
Definition: postgres.h:365
const char * err_text
Definition: plpgsql.h:1046
PLpgSQL_condition * conditions
Definition: plpgsql.h:474
Datum datumTransfer(Datum value, bool typByVal, int typLen)
Definition: datum.c:190
#define PG_CATCH()
Definition: elog.h:293
static void assign_text_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, const char *str)
Definition: pl_exec.c:8079
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
PLpgSQL_exception_block * exceptions
Definition: plpgsql.h:489
void BeginInternalSubTransaction(const char *name)
Definition: xact.c:4146
ExprContext * eval_econtext
Definition: plpgsql.h:1042
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2005
char typtype
Definition: plpgsql.h:206
e
Definition: preproc-init.c:82
static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
Definition: pl_exec.c:6608
int i
static void plpgsql_create_econtext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:7916
MemoryContext stmt_mcontext
Definition: plpgsql.h:1035
static void pop_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1479
#define elog
Definition: elog.h:219
char * exitlabel
Definition: plpgsql.h:996
#define PG_TRY()
Definition: elog.h:284
PLpgSQL_expr * default_val
Definition: plpgsql.h:368
bool notnull
Definition: plpgsql.h:367
#define PG_END_TRY()
Definition: elog.h:300
void ReThrowError(ErrorData *edata)
Definition: elog.c:1670
char * message
Definition: elog.h:343
static int exec_stmts(PLpgSQL_execstate *estate, List *stmts)
Definition: pl_exec.c:1852
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:4854

◆ exec_stmt_call()

static int exec_stmt_call ( PLpgSQL_execstate estate,
PLpgSQL_stmt_call stmt 
)
static

Definition at line 2066 of file pl_exec.c.

References NamedArgExpr::arg, NamedArgExpr::argnumber, FuncExpr::args, PLpgSQL_execstate::atomic, castNode, PLpgSQL_row::dtype, elog, ereport, errcode(), errmsg(), ERROR, exec_eval_cleanup(), exec_move_row(), exec_prepare_plan(), PLpgSQL_stmt_call::expr, PLpgSQL_function::fn_cxt, PLpgSQL_execstate::func, FUNC_MAX_ARGS, FuncExpr::funcid, get_func_arg_info(), HeapTupleIsValid, i, IsA, lfirst, PLpgSQL_row::lineno, linitial, linitial_node, PGPROC::lxid, MemoryContextSwitchTo(), MyProc, PLpgSQL_row::nfields, _SPI_plan::no_snapshots, ObjectIdGetDatum, palloc(), palloc0(), Param::paramid, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLpgSQL_expr::plan, _SPI_plan::plancache_list, plpgsql_create_econtext(), PLPGSQL_DTYPE_ROW, PLPGSQL_RC_OK, PROCOID, PLpgSQL_expr::query, PLpgSQL_execstate::readonly_func, ReleaseSysCache(), _SPI_plan::saved, SearchSysCache1(), setup_param_list(), PLpgSQL_execstate::simple_eval_estate, SPI_execute_plan_with_paramlist(), SPI_freetuptable(), SPI_processed, SPI_result_code_string(), SPI_tuptable, PLpgSQL_stmt_call::target, SPITupleTable::tupdesc, SPITupleTable::vals, and PLpgSQL_row::varnos.

Referenced by exec_stmt().

2067 {
2068  PLpgSQL_expr *expr = stmt->expr;
2069  SPIPlanPtr plan;
2070  ParamListInfo paramLI;
2071  LocalTransactionId before_lxid;
2072  LocalTransactionId after_lxid;
2073  int rc;
2074 
2075  if (expr->plan == NULL)
2076  {
2077  /*
2078  * Don't save the plan if not in atomic context. Otherwise,
2079  * transaction ends would cause errors about plancache leaks. XXX
2080  * This would be fixable with some plancache/resowner surgery
2081  * elsewhere, but for now we'll just work around this here.
2082  */
2083  exec_prepare_plan(estate, expr, 0, estate->atomic);
2084 
2085  /*
2086  * The procedure call could end transactions, which would upset the
2087  * snapshot management in SPI_execute*, so don't let it do it.
2088  */
2089  expr->plan->no_snapshots = true;
2090  }
2091 
2092  paramLI = setup_param_list(estate, expr);
2093 
2094  before_lxid = MyProc->lxid;
2095 
2096  PG_TRY();
2097  {
2098  rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
2099  estate->readonly_func, 0);
2100  }
2101  PG_CATCH();
2102  {
2103  /*