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 "executor/execExpr.h"
#include "executor/spi.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 "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/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_getdiag (PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
 
static int exec_stmt_if (PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
 
static int exec_stmt_case (PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
 
static int exec_stmt_loop (PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
 
static int exec_stmt_while (PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
 
static int exec_stmt_fori (PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
 
static int exec_stmt_fors (PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
 
static int exec_stmt_forc (PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt)
 
static int exec_stmt_foreach_a (PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt)
 
static int exec_stmt_open (PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
 
static int exec_stmt_fetch (PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
 
static int exec_stmt_close (PLpgSQL_execstate *estate, PLpgSQL_stmt_close *stmt)
 
static int exec_stmt_exit (PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt)
 
static int exec_stmt_return (PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
 
static int exec_stmt_return_next (PLpgSQL_execstate *estate, PLpgSQL_stmt_return_next *stmt)
 
static int exec_stmt_return_query (PLpgSQL_execstate *estate, PLpgSQL_stmt_return_query *stmt)
 
static int exec_stmt_raise (PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 
static int exec_stmt_assert (PLpgSQL_execstate *estate, PLpgSQL_stmt_assert *stmt)
 
static int exec_stmt_execsql (PLpgSQL_execstate *estate, PLpgSQL_stmt_execsql *stmt)
 
static int exec_stmt_dynexecute (PLpgSQL_execstate *estate, PLpgSQL_stmt_dynexecute *stmt)
 
static int exec_stmt_dynfors (PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
 
static int exec_stmt_commit (PLpgSQL_execstate *estate, PLpgSQL_stmt_commit *stmt)
 
static int exec_stmt_rollback (PLpgSQL_execstate *estate, PLpgSQL_stmt_rollback *stmt)
 
static void plpgsql_estate_setup (PLpgSQL_execstate *estate, PLpgSQL_function *func, ReturnSetInfo *rsi, EState *simple_eval_estate)
 
static void exec_eval_cleanup (PLpgSQL_execstate *estate)
 
static void exec_prepare_plan (PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions)
 
static void exec_simple_check_plan (PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
 
static void exec_save_simple_expr (PLpgSQL_expr *expr, CachedPlan *cplan)
 
static void exec_check_rw_parameter (PLpgSQL_expr *expr, 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)
 
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 119 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:1050

Definition at line 3310 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 7871 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().

7873 {
7874  Assert(rec->dtype == PLPGSQL_DTYPE_REC);
7875 
7876  /* Transfer new record object into datum_context */
7877  TransferExpandedRecord(erh, estate->datum_context);
7878 
7879  /* Free the old value ... */
7880  if (rec->erh)
7882 
7883  /* ... and install the new */
7884  rec->erh = erh;
7885 }
PLpgSQL_datum_type dtype
Definition: plpgsql.h:360
ExpandedRecordHeader * erh
Definition: plpgsql.h:377
void DeleteExpandedObject(Datum d)
#define Assert(condition)
Definition: c.h:688
#define TransferExpandedRecord(erh, cxt)
MemoryContext datum_context
Definition: plpgsql.h:991
#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 7830 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().

7832 {
7833  Assert(var->dtype == PLPGSQL_DTYPE_VAR ||
7834  var->dtype == PLPGSQL_DTYPE_PROMISE);
7835  /* Free the old value if needed */
7836  if (var->freeval)
7837  {
7839  var->isnull,
7840  var->datatype->typlen))
7842  else
7843  pfree(DatumGetPointer(var->value));
7844  }
7845  /* Assign new value to datum */
7846  var->value = newvalue;
7847  var->isnull = isnull;
7848  var->freeval = freeable;
7849 
7850  /*
7851  * If it's a promise variable, then either we just assigned the promised
7852  * value, or the user explicitly assigned an overriding value. Either
7853  * way, cancel the promise.
7854  */
7856 }
PLpgSQL_promise_type promise
Definition: plpgsql.h:316
PLpgSQL_datum_type dtype
Definition: plpgsql.h:285
PLpgSQL_type * datatype
Definition: plpgsql.h:294
void pfree(void *pointer)
Definition: mcxt.c:936
bool freeval
Definition: plpgsql.h:309
Datum value
Definition: plpgsql.h:307
void DeleteExpandedObject(Datum d)
#define Assert(condition)
Definition: c.h:688
#define DatumIsReadWriteExpandedObject(d, isnull, typlen)
#define DatumGetPointer(X)
Definition: postgres.h:532
int16 typlen
Definition: plpgsql.h:202
bool isnull
Definition: plpgsql.h:308

◆ assign_text_var()

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

Definition at line 7862 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().

7863 {
7864  assign_simple_var(estate, var, CStringGetTextDatum(str), false, true);
7865 }
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:7830
#define CStringGetTextDatum(s)
Definition: builtins.h:91

◆ coerce_function_result_tuple()

static void coerce_function_result_tuple ( PLpgSQL_execstate estate,
TupleDesc  tupdesc 
)
static

Definition at line 765 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().

766 {
767  HeapTuple rettup;
768  TupleDesc retdesc;
769  TupleConversionMap *tupmap;
770 
771  /* We assume exec_stmt_return verified that result is composite */
772  Assert(type_is_rowtype(estate->rettype));
773 
774  /* We can special-case expanded records for speed */
776  {
778 
779  Assert(erh->er_magic == ER_MAGIC);
780 
781  /* Extract record's TupleDesc */
782  retdesc = expanded_record_get_tupdesc(erh);
783 
784  /* check rowtype compatibility */
785  tupmap = convert_tuples_by_position(retdesc,
786  tupdesc,
787  gettext_noop("returned record type does not match expected record type"));
788 
789  /* it might need conversion */
790  if (tupmap)
791  {
792  rettup = expanded_record_get_tuple(erh);
793  Assert(rettup);
794  rettup = do_convert_tuple(rettup, tupmap);
795 
796  /*
797  * Copy tuple to upper executor memory, as a tuple Datum. Make
798  * sure it is labeled with the caller-supplied tuple type.
799  */
800  estate->retval = PointerGetDatum(SPI_returntuple(rettup, tupdesc));
801  /* no need to free map, we're about to return anyway */
802  }
803  else
804  {
805  /*
806  * We need only copy result into upper executor memory context.
807  * However, if we have a R/W expanded datum, we can just transfer
808  * its ownership out to the upper executor context.
809  */
810  estate->retval = SPI_datumTransfer(estate->retval,
811  false,
812  -1);
813  }
814  }
815  else
816  {
817  /* Convert composite datum to a HeapTuple and TupleDesc */
818  HeapTupleData tmptup;
819 
820  retdesc = deconstruct_composite_datum(estate->retval, &tmptup);
821  rettup = &tmptup;
822 
823  /* check rowtype compatibility */
824  tupmap = convert_tuples_by_position(retdesc,
825  tupdesc,
826  gettext_noop("returned record type does not match expected record type"));
827 
828  /* it might need conversion */
829  if (tupmap)
830  rettup = do_convert_tuple(rettup, tupmap);
831 
832  /*
833  * Copy tuple to upper executor memory, as a tuple Datum. Make sure
834  * it is labeled with the caller-supplied tuple type.
835  */
836  estate->retval = PointerGetDatum(SPI_returntuple(rettup, tupdesc));
837 
838  /* no need to free map, we're about to return anyway */
839 
840  ReleaseTupleDesc(retdesc);
841  }
842 }
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:1025
static TupleDesc deconstruct_composite_datum(Datum value, HeapTupleData *tmptup)
Definition: pl_exec.c:6878
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:688
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:121

◆ compatible_tupdescs()

static bool compatible_tupdescs ( TupleDesc  src_tupdesc,
TupleDesc  dst_tupdesc 
)
static

Definition at line 6779 of file pl_exec.c.

References i, tupleDesc::natts, and TupleDescAttr.

Referenced by exec_for_query(), and exec_move_row().

6780 {
6781  int i;
6782 
6783  /* Possibly we could allow src_tupdesc to have extra columns? */
6784  if (dst_tupdesc->natts != src_tupdesc->natts)
6785  return false;
6786 
6787  for (i = 0; i < dst_tupdesc->natts; i++)
6788  {
6789  Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
6790  Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
6791 
6792  if (dattr->attisdropped != sattr->attisdropped)
6793  return false;
6794  if (!dattr->attisdropped)
6795  {
6796  /* Normal columns must match by type and typmod */
6797  if (dattr->atttypid != sattr->atttypid ||
6798  (dattr->atttypmod >= 0 &&
6799  dattr->atttypmod != sattr->atttypmod))
6800  return false;
6801  }
6802  else
6803  {
6804  /* Dropped columns are OK as long as length/alignment match */
6805  if (dattr->attlen != sattr->attlen ||
6806  dattr->attalign != sattr->attalign)
6807  return false;
6808  }
6809  }
6810  return true;
6811 }
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
int natts
Definition: tupdesc.h:79
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
int i

◆ contains_target_param()

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

Definition at line 7663 of file pl_exec.c.

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

Referenced by exec_check_rw_parameter().

7664 {
7665  if (node == NULL)
7666  return false;
7667  if (IsA(node, Param))
7668  {
7669  Param *param = (Param *) node;
7670 
7671  if (param->paramkind == PARAM_EXTERN &&
7672  param->paramid == *target_dno + 1)
7673  return true;
7674  return false;
7675  }
7677  (void *) target_dno);
7678 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:564
ParamKind paramkind
Definition: primnodes.h:244
static bool contains_target_param(Node *node, int *target_dno)
Definition: pl_exec.c:7663
int paramid
Definition: primnodes.h:245
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 7165 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().

7166 {
7167  char *result;
7168  MemoryContext oldcontext;
7169  Oid typoutput;
7170  bool typIsVarlena;
7171 
7172  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7173  getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
7174  result = OidOutputFunctionCall(typoutput, value);
7175  MemoryContextSwitchTo(oldcontext);
7176 
7177  return result;
7178 }
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2650
static struct @130 value
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:115
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1742

◆ copy_plpgsql_datums()

static void copy_plpgsql_datums ( PLpgSQL_execstate estate,
PLpgSQL_function func 
)
static

Definition at line 1200 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().

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

◆ deconstruct_composite_datum()

static TupleDesc deconstruct_composite_datum ( Datum  value,
HeapTupleData tmptup 
)
static

Definition at line 6878 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().

6879 {
6880  HeapTupleHeader td;
6881  Oid tupType;
6882  int32 tupTypmod;
6883 
6884  /* Get tuple body (note this could involve detoasting) */
6886 
6887  /* Build a temporary HeapTuple control structure */
6888  tmptup->t_len = HeapTupleHeaderGetDatumLength(td);
6889  ItemPointerSetInvalid(&(tmptup->t_self));
6890  tmptup->t_tableOid = InvalidOid;
6891  tmptup->t_data = td;
6892 
6893  /* Extract rowtype info and find a tupdesc */
6894  tupType = HeapTupleHeaderGetTypeId(td);
6895  tupTypmod = HeapTupleHeaderGetTypMod(td);
6896  return lookup_rowtype_tupdesc(tupType, tupTypmod);
6897 }
static struct @130 value
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:259
signed int int32
Definition: c.h:302
HeapTupleHeader t_data
Definition: htup.h:67
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:460
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:450
#define InvalidOid
Definition: postgres_ext.h:36
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:150
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:444

◆ exception_matches_conditions()

static bool exception_matches_conditions ( ErrorData edata,
PLpgSQL_condition cond 
)
static

Definition at line 1486 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().

1487 {
1488  for (; cond != NULL; cond = cond->next)
1489  {
1490  int sqlerrstate = cond->sqlerrstate;
1491 
1492  /*
1493  * OTHERS matches everything *except* query-canceled and
1494  * assert-failure. If you're foolish enough, you can match those
1495  * explicitly.
1496  */
1497  if (sqlerrstate == 0)
1498  {
1499  if (edata->sqlerrcode != ERRCODE_QUERY_CANCELED &&
1500  edata->sqlerrcode != ERRCODE_ASSERT_FAILURE)
1501  return true;
1502  }
1503  /* Exact match? */
1504  else if (edata->sqlerrcode == sqlerrstate)
1505  return true;
1506  /* Category match? */
1507  else if (ERRCODE_IS_CATEGORY(sqlerrstate) &&
1508  ERRCODE_TO_CATEGORY(edata->sqlerrcode) == sqlerrstate)
1509  return true;
1510  }
1511  return false;
1512 }
#define ERRCODE_IS_CATEGORY(ec)
Definition: elog.h:68
int sqlerrcode
Definition: elog.h:342
struct PLpgSQL_condition * next
Definition: plpgsql.h:453
#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 4611 of file pl_exec.c.

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

Referenced by exec_stmt_getdiag().

4613 {
4614  text *value;
4615  MemoryContext oldcontext;
4616 
4617  /* Use eval_mcontext for short-lived text value */
4618  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
4619  if (str != NULL)
4620  value = cstring_to_text(str);
4621  else
4622  value = cstring_to_text("");
4623  MemoryContextSwitchTo(oldcontext);
4624 
4625  exec_assign_value(estate, target, PointerGetDatum(value), false,
4626  TEXTOID, -1);
4627 }
static struct @130 value
#define TEXTOID
Definition: pg_type.h:324
#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:115
text * cstring_to_text(const char *s)
Definition: varlena.c:150
Definition: c.h:505
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:4639

◆ exec_assign_expr()

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

Definition at line 4574 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().

4576 {
4577  Datum value;
4578  bool isnull;
4579  Oid valtype;
4580  int32 valtypmod;
4581 
4582  /*
4583  * If first time through, create a plan for this expression, and then see
4584  * if we can pass the target variable as a read-write parameter to the
4585  * expression. (This is a bit messy, but it seems cleaner than modifying
4586  * the API of exec_eval_expr for the purpose.)
4587  */
4588  if (expr->plan == NULL)
4589  {
4590  exec_prepare_plan(estate, expr, 0);
4591  if (target->dtype == PLPGSQL_DTYPE_VAR)
4592  exec_check_rw_parameter(expr, target->dno);
4593  }
4594 
4595  value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod);
4596  exec_assign_value(estate, target, value, isnull, valtype, valtypmod);
4597  exec_eval_cleanup(estate);
4598 }
static struct @130 value
static void exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno)
Definition: pl_exec.c:7586
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:3724
unsigned int Oid
Definition: postgres_ext.h:31
PLpgSQL_datum_type dtype
Definition: plpgsql.h:251
SPIPlanPtr plan
Definition: plpgsql.h:216
signed int int32
Definition: c.h:302
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5435
uintptr_t Datum
Definition: postgres.h:365
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions)
Definition: pl_exec.c:3745
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:4639

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

4643 {
4644  switch (target->dtype)
4645  {
4646  case PLPGSQL_DTYPE_VAR:
4647  case PLPGSQL_DTYPE_PROMISE:
4648  {
4649  /*
4650  * Target is a variable
4651  */
4652  PLpgSQL_var *var = (PLpgSQL_var *) target;
4653  Datum newvalue;
4654 
4655  newvalue = exec_cast_value(estate,
4656  value,
4657  &isNull,
4658  valtype,
4659  valtypmod,
4660  var->datatype->typoid,
4661  var->datatype->atttypmod);
4662 
4663  if (isNull && var->notnull)
4664  ereport(ERROR,
4665  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4666  errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
4667  var->refname)));
4668 
4669  /*
4670  * If type is by-reference, copy the new value (which is
4671  * probably in the eval_mcontext) into the procedure's main
4672  * memory context. But if it's a read/write reference to an
4673  * expanded object, no physical copy needs to happen; at most
4674  * we need to reparent the object's memory context.
4675  *
4676  * If it's an array, we force the value to be stored in R/W
4677  * expanded form. This wins if the function later does, say,
4678  * a lot of array subscripting operations on the variable, and
4679  * otherwise might lose. We might need to use a different
4680  * heuristic, but it's too soon to tell. Also, are there
4681  * cases where it'd be useful to force non-array values into
4682  * expanded form?
4683  */
4684  if (!var->datatype->typbyval && !isNull)
4685  {
4686  if (var->datatype->typisarray &&
4688  {
4689  /* array and not already R/W, so apply expand_array */
4690  newvalue = expand_array(newvalue,
4691  estate->datum_context,
4692  NULL);
4693  }
4694  else
4695  {
4696  /* else transfer value if R/W, else just datumCopy */
4697  newvalue = datumTransfer(newvalue,
4698  false,
4699  var->datatype->typlen);
4700  }
4701  }
4702 
4703  /*
4704  * Now free the old value, if any, and assign the new one. But
4705  * skip the assignment if old and new values are the same.
4706  * Note that for expanded objects, this test is necessary and
4707  * cannot reliably be made any earlier; we have to be looking
4708  * at the object's standard R/W pointer to be sure pointer
4709  * equality is meaningful.
4710  *
4711  * Also, if it's a promise variable, we should disarm the
4712  * promise in any case --- otherwise, assigning null to an
4713  * armed promise variable would fail to disarm the promise.
4714  */
4715  if (var->value != newvalue || var->isnull || isNull)
4716  assign_simple_var(estate, var, newvalue, isNull,
4717  (!var->datatype->typbyval && !isNull));
4718  else
4720  break;
4721  }
4722 
4723  case PLPGSQL_DTYPE_ROW:
4724  {
4725  /*
4726  * Target is a row variable
4727  */
4728  PLpgSQL_row *row = (PLpgSQL_row *) target;
4729 
4730  if (isNull)
4731  {
4732  /* If source is null, just assign nulls to the row */
4733  exec_move_row(estate, (PLpgSQL_variable *) row,
4734  NULL, NULL);
4735  }
4736  else
4737  {
4738  /* Source must be of RECORD or composite type */
4739  if (!type_is_rowtype(valtype))
4740  ereport(ERROR,
4741  (errcode(ERRCODE_DATATYPE_MISMATCH),
4742  errmsg("cannot assign non-composite value to a row variable")));
4744  value);
4745  }
4746  break;
4747  }
4748 
4749  case PLPGSQL_DTYPE_REC:
4750  {
4751  /*
4752  * Target is a record variable
4753  */
4754  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
4755 
4756  if (isNull)
4757  {
4758  if (rec->notnull)
4759  ereport(ERROR,
4760  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4761  errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
4762  rec->refname)));
4763 
4764  /* Set variable to a simple NULL */
4765  exec_move_row(estate, (PLpgSQL_variable *) rec,
4766  NULL, NULL);
4767  }
4768  else
4769  {
4770  /* Source must be of RECORD or composite type */
4771  if (!type_is_rowtype(valtype))
4772  ereport(ERROR,
4773  (errcode(ERRCODE_DATATYPE_MISMATCH),
4774  errmsg("cannot assign non-composite value to a record variable")));
4776  value);
4777  }
4778  break;
4779  }
4780 
4782  {
4783  /*
4784  * Target is a field of a record
4785  */
4786  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) target;
4787  PLpgSQL_rec *rec;
4788  ExpandedRecordHeader *erh;
4789 
4790  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
4791  erh = rec->erh;
4792 
4793  /*
4794  * If record variable is NULL, instantiate it if it has a
4795  * named composite type, else complain. (This won't change
4796  * the logical state of the record, but if we successfully
4797  * assign below, the unassigned fields will all become NULLs.)
4798  */
4799  if (erh == NULL)
4800  {
4801  instantiate_empty_record_variable(estate, rec);
4802  erh = rec->erh;
4803  }
4804 
4805  /*
4806  * Look up the field's properties if we have not already, or
4807  * if the tuple descriptor ID changed since last time.
4808  */
4809  if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
4810  {
4812  recfield->fieldname,
4813  &recfield->finfo))
4814  ereport(ERROR,
4815  (errcode(ERRCODE_UNDEFINED_COLUMN),
4816  errmsg("record \"%s\" has no field \"%s\"",
4817  rec->refname, recfield->fieldname)));
4818  recfield->rectupledescid = erh->er_tupdesc_id;
4819  }
4820 
4821  /* We don't support assignments to system columns. */
4822  if (recfield->finfo.fnumber <= 0)
4823  ereport(ERROR,
4824  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4825  errmsg("cannot assign to system column \"%s\"",
4826  recfield->fieldname)));
4827 
4828  /* Cast the new value to the right type, if needed. */
4829  value = exec_cast_value(estate,
4830  value,
4831  &isNull,
4832  valtype,
4833  valtypmod,
4834  recfield->finfo.ftypeid,
4835  recfield->finfo.ftypmod);
4836 
4837  /* And assign it. */
4838  expanded_record_set_field(erh, recfield->finfo.fnumber,
4839  value, isNull);
4840  break;
4841  }
4842 
4844  {
4845  /*
4846  * Target is an element of an array
4847  */
4848  PLpgSQL_arrayelem *arrayelem;
4849  int nsubscripts;
4850  int i;
4851  PLpgSQL_expr *subscripts[MAXDIM];
4852  int subscriptvals[MAXDIM];
4853  Datum oldarraydatum,
4854  newarraydatum,
4855  coerced_value;
4856  bool oldarrayisnull;
4857  Oid parenttypoid;
4858  int32 parenttypmod;
4859  SPITupleTable *save_eval_tuptable;
4860  MemoryContext oldcontext;
4861 
4862  /*
4863  * We need to do subscript evaluation, which might require
4864  * evaluating general expressions; and the caller might have
4865  * done that too in order to prepare the input Datum. We have
4866  * to save and restore the caller's SPI_execute result, if
4867  * any.
4868  */
4869  save_eval_tuptable = estate->eval_tuptable;
4870  estate->eval_tuptable = NULL;
4871 
4872  /*
4873  * To handle constructs like x[1][2] := something, we have to
4874  * be prepared to deal with a chain of arrayelem datums. Chase
4875  * back to find the base array datum, and save the subscript
4876  * expressions as we go. (We are scanning right to left here,
4877  * but want to evaluate the subscripts left-to-right to
4878  * minimize surprises.) Note that arrayelem is left pointing
4879  * to the leftmost arrayelem datum, where we will cache the
4880  * array element type data.
4881  */
4882  nsubscripts = 0;
4883  do
4884  {
4885  arrayelem = (PLpgSQL_arrayelem *) target;
4886  if (nsubscripts >= MAXDIM)
4887  ereport(ERROR,
4888  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
4889  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
4890  nsubscripts + 1, MAXDIM)));
4891  subscripts[nsubscripts++] = arrayelem->subscript;
4892  target = estate->datums[arrayelem->arrayparentno];
4893  } while (target->dtype == PLPGSQL_DTYPE_ARRAYELEM);
4894 
4895  /* Fetch current value of array datum */
4896  exec_eval_datum(estate, target,
4897  &parenttypoid, &parenttypmod,
4898  &oldarraydatum, &oldarrayisnull);
4899 
4900  /* Update cached type data if necessary */
4901  if (arrayelem->parenttypoid != parenttypoid ||
4902  arrayelem->parenttypmod != parenttypmod)
4903  {
4904  Oid arraytypoid;
4905  int32 arraytypmod = parenttypmod;
4906  int16 arraytyplen;
4907  Oid elemtypoid;
4908  int16 elemtyplen;
4909  bool elemtypbyval;
4910  char elemtypalign;
4911 
4912  /* If target is domain over array, reduce to base type */
4913  arraytypoid = getBaseTypeAndTypmod(parenttypoid,
4914  &arraytypmod);
4915 
4916  /* ... and identify the element type */
4917  elemtypoid = get_element_type(arraytypoid);
4918  if (!OidIsValid(elemtypoid))
4919  ereport(ERROR,
4920  (errcode(ERRCODE_DATATYPE_MISMATCH),
4921  errmsg("subscripted object is not an array")));
4922 
4923  /* Collect needed data about the types */
4924  arraytyplen = get_typlen(arraytypoid);
4925 
4926  get_typlenbyvalalign(elemtypoid,
4927  &elemtyplen,
4928  &elemtypbyval,
4929  &elemtypalign);
4930 
4931  /* Now safe to update the cached data */
4932  arrayelem->parenttypoid = parenttypoid;
4933  arrayelem->parenttypmod = parenttypmod;
4934  arrayelem->arraytypoid = arraytypoid;
4935  arrayelem->arraytypmod = arraytypmod;
4936  arrayelem->arraytyplen = arraytyplen;
4937  arrayelem->elemtypoid = elemtypoid;
4938  arrayelem->elemtyplen = elemtyplen;
4939  arrayelem->elemtypbyval = elemtypbyval;
4940  arrayelem->elemtypalign = elemtypalign;
4941  }
4942 
4943  /*
4944  * Evaluate the subscripts, switch into left-to-right order.
4945  * Like the expression built by ExecInitArrayRef(), complain
4946  * if any subscript is null.
4947  */
4948  for (i = 0; i < nsubscripts; i++)
4949  {
4950  bool subisnull;
4951 
4952  subscriptvals[i] =
4953  exec_eval_integer(estate,
4954  subscripts[nsubscripts - 1 - i],
4955  &subisnull);
4956  if (subisnull)
4957  ereport(ERROR,
4958  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4959  errmsg("array subscript in assignment must not be null")));
4960 
4961  /*
4962  * Clean up in case the subscript expression wasn't
4963  * simple. We can't do exec_eval_cleanup, but we can do
4964  * this much (which is safe because the integer subscript
4965  * value is surely pass-by-value), and we must do it in
4966  * case the next subscript expression isn't simple either.
4967  */
4968  if (estate->eval_tuptable != NULL)
4970  estate->eval_tuptable = NULL;
4971  }
4972 
4973  /* Now we can restore caller's SPI_execute result if any. */
4974  Assert(estate->eval_tuptable == NULL);
4975  estate->eval_tuptable = save_eval_tuptable;
4976 
4977  /* Coerce source value to match array element type. */
4978  coerced_value = exec_cast_value(estate,
4979  value,
4980  &isNull,
4981  valtype,
4982  valtypmod,
4983  arrayelem->elemtypoid,
4984  arrayelem->arraytypmod);
4985 
4986  /*
4987  * If the original array is null, cons up an empty array so
4988  * that the assignment can proceed; we'll end with a
4989  * one-element array containing just the assigned-to
4990  * subscript. This only works for varlena arrays, though; for
4991  * fixed-length array types we skip the assignment. We can't
4992  * support assignment of a null entry into a fixed-length
4993  * array, either, so that's a no-op too. This is all ugly but
4994  * corresponds to the current behavior of execExpr*.c.
4995  */
4996  if (arrayelem->arraytyplen > 0 && /* fixed-length array? */
4997  (oldarrayisnull || isNull))
4998  return;
4999 
5000  /* empty array, if any, and newarraydatum are short-lived */
5001  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5002 
5003  if (oldarrayisnull)
5004  oldarraydatum = PointerGetDatum(construct_empty_array(arrayelem->elemtypoid));
5005 
5006  /*
5007  * Build the modified array value.
5008  */
5009  newarraydatum = array_set_element(oldarraydatum,
5010  nsubscripts,
5011  subscriptvals,
5012  coerced_value,
5013  isNull,
5014  arrayelem->arraytyplen,
5015  arrayelem->elemtyplen,
5016  arrayelem->elemtypbyval,
5017  arrayelem->elemtypalign);
5018 
5019  MemoryContextSwitchTo(oldcontext);
5020 
5021  /*
5022  * Assign the new array to the base variable. It's never NULL
5023  * at this point. Note that if the target is a domain,
5024  * coercing the base array type back up to the domain will
5025  * happen within exec_assign_value.
5026  */
5027  exec_assign_value(estate, target,
5028  newarraydatum,
5029  false,
5030  arrayelem->arraytypoid,
5031  arrayelem->arraytypmod);
5032  break;
5033  }
5034 
5035  default:
5036  elog(ERROR, "unrecognized dtype: %d", target->dtype);
5037  }
5038 }
PLpgSQL_promise_type promise
Definition: plpgsql.h:316
signed short int16
Definition: c.h:301
int16 elemtyplen
Definition: plpgsql.h:416
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2292
static struct @130 value
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1013
char * refname
Definition: plpgsql.h:287
static void exec_eval_datum(PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeid, int32 *typetypmod, Datum *value, bool *isnull)
Definition: pl_exec.c:5058
bool expanded_record_lookup_field(ExpandedRecordHeader *erh, const char *fieldname, ExpandedRecordFieldInfo *finfo)
#define MAXDIM
Definition: c.h:485
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:294
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:7133
ExpandedRecordHeader * erh
Definition: plpgsql.h:377
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:7830
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:6909
PLpgSQL_datum_type dtype
Definition: plpgsql.h:251
#define OidIsValid(objectId)
Definition: c.h:594
char * refname
Definition: plpgsql.h:362
signed int int32
Definition: c.h:302
PLpgSQL_datum ** datums
Definition: plpgsql.h:989
int32 arraytypmod
Definition: plpgsql.h:413
bool notnull
Definition: plpgsql.h:290
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7194
#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:392
bool typbyval
Definition: plpgsql.h:203
#define get_eval_mcontext(estate)
Definition: pl_exec.c:115
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1066
bool typisarray
Definition: plpgsql.h:206
uintptr_t Datum
Definition: postgres.h:365
static int exec_eval_integer(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
Definition: pl_exec.c:5389
ExpandedRecordFieldInfo finfo
Definition: plpgsql.h:393
int32 parenttypmod
Definition: plpgsql.h:411
Datum value
Definition: plpgsql.h:307
Datum datumTransfer(Datum value, bool typByVal, int typLen)
Definition: datum.c:190
#define Assert(condition)
Definition: c.h:688
int16 arraytyplen
Definition: plpgsql.h:414
#define DatumGetPointer(X)
Definition: postgres.h:532
MemoryContext datum_context
Definition: plpgsql.h:991
int16 get_typlen(Oid typid)
Definition: lsyscache.c:1951
int errmsg(const char *fmt,...)
Definition: elog.c:797
int32 atttypmod
Definition: plpgsql.h:207
static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
Definition: pl_exec.c:6393
int i
PLpgSQL_expr * subscript
Definition: plpgsql.h:406
#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:202
bool notnull
Definition: plpgsql.h:365
char * fieldname
Definition: plpgsql.h:389
static void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, bool isNull, Oid valtype, int32 valtypmod)
Definition: pl_exec.c:4639
#define expanded_record_set_field(erh, fnumber, newValue, isnull)
bool isnull
Definition: plpgsql.h:308
Oid typoid
Definition: plpgsql.h:200

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

7198 {
7199  /*
7200  * If the type of the given value isn't what's requested, convert it.
7201  */
7202  if (valtype != reqtype ||
7203  (valtypmod != reqtypmod && reqtypmod != -1))
7204  {
7205  plpgsql_CastHashEntry *cast_entry;
7206 
7207  cast_entry = get_cast_hashentry(estate,
7208  valtype, valtypmod,
7209  reqtype, reqtypmod);
7210  if (cast_entry)
7211  {
7212  ExprContext *econtext = estate->eval_econtext;
7213  MemoryContext oldcontext;
7214 
7215  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7216 
7217  econtext->caseValue_datum = value;
7218  econtext->caseValue_isNull = *isnull;
7219 
7220  cast_entry->cast_in_use = true;
7221 
7222  value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
7223  isnull);
7224 
7225  cast_entry->cast_in_use = false;
7226 
7227  MemoryContextSwitchTo(oldcontext);
7228  }
7229  }
7230 
7231  return value;
7232 }
static struct @130 value
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:7245
Datum caseValue_datum
Definition: execnodes.h:231
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:282
#define get_eval_mcontext(estate)
Definition: pl_exec.c:115
ExprContext * eval_econtext
Definition: plpgsql.h:1016
bool caseValue_isNull
Definition: execnodes.h:232
ExprState * cast_exprstate
Definition: pl_exec.c:150

◆ exec_check_rw_parameter()

static void exec_check_rw_parameter ( PLpgSQL_expr expr,
int  target_dno 
)
static

Definition at line 7586 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().

7587 {
7588  Oid funcid;
7589  List *fargs;
7590  ListCell *lc;
7591 
7592  /* Assume unsafe */
7593  expr->rwparam = -1;
7594 
7595  /*
7596  * If the expression isn't simple, there's no point in trying to optimize
7597  * (because the exec_run_select code path will flatten any expanded result
7598  * anyway). Even without that, this seems like a good safety restriction.
7599  */
7600  if (expr->expr_simple_expr == NULL)
7601  return;
7602 
7603  /*
7604  * If target variable isn't referenced by expression, no need to look
7605  * further.
7606  */
7607  if (!bms_is_member(target_dno, expr->paramnos))
7608  return;
7609 
7610  /*
7611  * Top level of expression must be a simple FuncExpr or OpExpr.
7612  */
7613  if (IsA(expr->expr_simple_expr, FuncExpr))
7614  {
7615  FuncExpr *fexpr = (FuncExpr *) expr->expr_simple_expr;
7616 
7617  funcid = fexpr->funcid;
7618  fargs = fexpr->args;
7619  }
7620  else if (IsA(expr->expr_simple_expr, OpExpr))
7621  {
7622  OpExpr *opexpr = (OpExpr *) expr->expr_simple_expr;
7623 
7624  funcid = opexpr->opfuncid;
7625  fargs = opexpr->args;
7626  }
7627  else
7628  return;
7629 
7630  /*
7631  * The top-level function must be one that we trust to be "safe".
7632  * Currently we hard-wire the list, but it would be very desirable to
7633  * allow extensions to mark their functions as safe ...
7634  */
7635  if (!(funcid == F_ARRAY_APPEND ||
7636  funcid == F_ARRAY_PREPEND))
7637  return;
7638 
7639  /*
7640  * The target variable (in the form of a Param) must only appear as a
7641  * direct argument of the top-level function.
7642  */
7643  foreach(lc, fargs)
7644  {
7645  Node *arg = (Node *) lfirst(lc);
7646 
7647  /* A Param is OK, whether it's the target variable or not */
7648  if (arg && IsA(arg, Param))
7649  continue;
7650  /* Otherwise, argument expression must not reference target */
7651  if (contains_target_param(arg, &target_dno))
7652  return;
7653  }
7654 
7655  /* OK, we can pass target as a read-write parameter */
7656  expr->rwparam = target_dno;
7657 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:564
List * args
Definition: primnodes.h:457
Definition: nodes.h:513
unsigned int Oid
Definition: postgres_ext.h:31
Bitmapset * paramnos
Definition: plpgsql.h:217
Oid funcid
Definition: primnodes.h:449
static bool contains_target_param(Node *node, int *target_dno)
Definition: pl_exec.c:7663
Expr * expr_simple_expr
Definition: plpgsql.h:227
int rwparam
Definition: plpgsql.h:218
Oid opfuncid
Definition: primnodes.h:497
#define lfirst(lc)
Definition: pg_list.h:106
void * arg
List * args
Definition: primnodes.h:502
Definition: pg_list.h:45
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:464

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

7978 {
7979  Portal portal;
7980  Datum query;
7981  bool isnull;
7982  Oid restype;
7983  int32 restypmod;
7984  char *querystr;
7985  MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
7986 
7987  /*
7988  * Evaluate the string expression after the EXECUTE keyword. Its result is
7989  * the querystring we have to execute.
7990  */
7991  query = exec_eval_expr(estate, dynquery, &isnull, &restype, &restypmod);
7992  if (isnull)
7993  ereport(ERROR,
7994  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
7995  errmsg("query string argument of EXECUTE is null")));
7996 
7997  /* Get the C-String representation */
7998  querystr = convert_value_to_string(estate, query, restype);
7999 
8000  /* copy it into the stmt_mcontext before we clean up */
8001  querystr = MemoryContextStrdup(stmt_mcontext, querystr);
8002 
8003  exec_eval_cleanup(estate);
8004 
8005  /*
8006  * Open an implicit cursor for the query. We use
8007  * SPI_cursor_open_with_args even when there are no params, because this
8008  * avoids making and freeing one copy of the plan.
8009  */
8010  if (params)
8011  {
8012  PreparedParamsData *ppd;
8013 
8014  ppd = exec_eval_using_params(estate, params);
8015  portal = SPI_cursor_open_with_args(portalname,
8016  querystr,
8017  ppd->nargs, ppd->types,
8018  ppd->values, ppd->nulls,
8019  estate->readonly_func,
8020  cursorOptions);
8021  }
8022  else
8023  {
8024  portal = SPI_cursor_open_with_args(portalname,
8025  querystr,
8026  0, NULL,
8027  NULL, NULL,
8028  estate->readonly_func,
8029  cursorOptions);
8030  }
8031 
8032  if (portal == NULL)
8033  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
8034  querystr, SPI_result_code_string(SPI_result));
8035 
8036  /* Release transient data */
8037  MemoryContextReset(stmt_mcontext);
8038 
8039  return portal;
8040 }
int errcode(int sqlerrcode)
Definition: elog.c:575
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:134
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:3724
Datum * values
Definition: pl_exec.c:52
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:302
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:5435
static PreparedParamsData * exec_eval_using_params(PLpgSQL_execstate *estate, List *params)
Definition: pl_exec.c:7894
const char * SPI_result_code_string(int code)
Definition: spi.c:1609
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1435
#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:968
int errmsg(const char *fmt,...)
Definition: elog.c:797
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1050
static char * convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
Definition: pl_exec.c:7165
#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 5412 of file pl_exec.c.

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

5415 {
5416  Datum exprdatum;
5417  Oid exprtypeid;
5418  int32 exprtypmod;
5419 
5420  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5421  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5422  exprtypeid, exprtypmod,
5423  BOOLOID, -1);
5424  return DatumGetBool(exprdatum);
5425 }
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:302
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7194
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5435
#define DatumGetBool(X)
Definition: postgres.h:376
uintptr_t Datum
Definition: postgres.h:365
#define BOOLOID
Definition: pg_type.h:288

◆ exec_eval_cleanup()

static void exec_eval_cleanup ( PLpgSQL_execstate estate)
static

Definition at line 3724 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_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().

3725 {
3726  /* Clear result of a full SPI_execute */
3727  if (estate->eval_tuptable != NULL)
3729  estate->eval_tuptable = NULL;
3730 
3731  /*
3732  * Clear result of exec_eval_simple_expr (but keep the econtext). This
3733  * also clears any short-lived allocations done via get_eval_mcontext.
3734  */
3735  if (estate->eval_econtext != NULL)
3737 }
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1013
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1066
ExprContext * eval_econtext
Definition: plpgsql.h:1016
#define ResetExprContext(econtext)
Definition: executor.h:484

◆ 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 5058 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(), RECORDOID, 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().

5064 {
5065  MemoryContext oldcontext;
5066 
5067  switch (datum->dtype)
5068  {
5069  case PLPGSQL_DTYPE_PROMISE:
5070  /* fulfill promise if needed, then handle like regular var */
5071  plpgsql_fulfill_promise(estate, (PLpgSQL_var *) datum);
5072 
5073  /* FALL THRU */
5074 
5075  case PLPGSQL_DTYPE_VAR:
5076  {
5077  PLpgSQL_var *var = (PLpgSQL_var *) datum;
5078 
5079  *typeid = var->datatype->typoid;
5080  *typetypmod = var->datatype->atttypmod;
5081  *value = var->value;
5082  *isnull = var->isnull;
5083  break;
5084  }
5085 
5086  case PLPGSQL_DTYPE_ROW:
5087  {
5088  PLpgSQL_row *row = (PLpgSQL_row *) datum;
5089  HeapTuple tup;
5090 
5091  /* We get here if there are multiple OUT parameters */
5092  if (!row->rowtupdesc) /* should not happen */
5093  elog(ERROR, "row variable has no tupdesc");
5094  /* Make sure we have a valid type/typmod setting */
5095  BlessTupleDesc(row->rowtupdesc);
5096  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5097  tup = make_tuple_from_row(estate, row, row->rowtupdesc);
5098  if (tup == NULL) /* should not happen */
5099  elog(ERROR, "row not compatible with its own tupdesc");
5100  *typeid = row->rowtupdesc->tdtypeid;
5101  *typetypmod = row->rowtupdesc->tdtypmod;
5102  *value = HeapTupleGetDatum(tup);
5103  *isnull = false;
5104  MemoryContextSwitchTo(oldcontext);
5105  break;
5106  }
5107 
5108  case PLPGSQL_DTYPE_REC:
5109  {
5110  PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
5111 
5112  if (rec->erh == NULL)
5113  {
5114  /* Treat uninstantiated record as a simple NULL */
5115  *value = (Datum) 0;
5116  *isnull = true;
5117  /* Report variable's declared type */
5118  *typeid = rec->rectypeid;
5119  *typetypmod = -1;
5120  }
5121  else
5122  {
5123  if (ExpandedRecordIsEmpty(rec->erh))
5124  {
5125  /* Empty record is also a NULL */
5126  *value = (Datum) 0;
5127  *isnull = true;
5128  }
5129  else
5130  {
5131  *value = ExpandedRecordGetDatum(rec->erh);
5132  *isnull = false;
5133  }
5134  if (rec->rectypeid != RECORDOID)
5135  {
5136  /* Report variable's declared type, if not RECORD */
5137  *typeid = rec->rectypeid;
5138  *typetypmod = -1;
5139  }
5140  else
5141  {
5142  /* Report record's actual type if declared RECORD */
5143  *typeid = rec->erh->er_typeid;
5144  *typetypmod = rec->erh->er_typmod;
5145  }
5146  }
5147  break;
5148  }
5149 
5151  {
5152  PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
5153  PLpgSQL_rec *rec;
5154  ExpandedRecordHeader *erh;
5155 
5156  rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
5157  erh = rec->erh;
5158 
5159  /*
5160  * If record variable is NULL, instantiate it if it has a
5161  * named composite type, else complain. (This won't change
5162  * the logical state of the record: it's still NULL.)
5163  */
5164  if (erh == NULL)
5165  {
5166  instantiate_empty_record_variable(estate, rec);
5167  erh = rec->erh;
5168  }
5169 
5170  /*
5171  * Look up the field's properties if we have not already, or
5172  * if the tuple descriptor ID changed since last time.
5173  */
5174  if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
5175  {
5177  recfield->fieldname,
5178  &recfield->finfo))
5179  ereport(ERROR,
5180  (errcode(ERRCODE_UNDEFINED_COLUMN),
5181  errmsg("record \"%s\" has no field \"%s\"",
5182  rec->refname, recfield->fieldname)));
5183  recfield->rectupledescid = erh->er_tupdesc_id;
5184  }
5185 
5186  /* Report type data. */
5187  *typeid = recfield->finfo.ftypeid;
5188  *typetypmod = recfield->finfo.ftypmod;
5189 
5190  /* And fetch the field value. */
5192  recfield->finfo.fnumber,
5193  isnull);
5194  break;
5195  }
5196 
5197  default:
5198  elog(ERROR, "unrecognized dtype: %d", datum->dtype);
5199  }
5200 }
static HeapTuple make_tuple_from_row(PLpgSQL_execstate *estate, PLpgSQL_row *row, TupleDesc tupdesc)
Definition: pl_exec.c:6823
Oid tdtypeid
Definition: tupdesc.h:80
static struct @130 value
#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:294
static void plpgsql_fulfill_promise(PLpgSQL_execstate *estate, PLpgSQL_var *var)
Definition: pl_exec.c:1275
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:7133
ExpandedRecordHeader * erh
Definition: plpgsql.h:377
int errcode(int sqlerrcode)
Definition: elog.c:575
PLpgSQL_datum_type dtype
Definition: plpgsql.h:251
char * refname
Definition: plpgsql.h:362
int32 tdtypmod
Definition: tupdesc.h:81
PLpgSQL_datum ** datums
Definition: plpgsql.h:989
#define ERROR
Definition: elog.h:43
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:1088
#define RECORDOID
Definition: pg_type.h:680
#define ereport(elevel, rest)
Definition: elog.h:122
uint64 rectupledescid
Definition: plpgsql.h:392
#define get_eval_mcontext(estate)
Definition: pl_exec.c:115
uintptr_t Datum
Definition: postgres.h:365
ExpandedRecordFieldInfo finfo
Definition: plpgsql.h:393
Datum value
Definition: plpgsql.h:307
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:230
int errmsg(const char *fmt,...)
Definition: elog.c:797
int32 atttypmod
Definition: plpgsql.h:207
TupleDesc rowtupdesc
Definition: plpgsql.h:348
#define unlikely(x)
Definition: c.h:208
#define elog
Definition: elog.h:219
Oid rectypeid
Definition: plpgsql.h:370
#define ExpandedRecordGetDatum(erh)
char * fieldname
Definition: plpgsql.h:389
bool isnull
Definition: plpgsql.h:308
Oid typoid
Definition: plpgsql.h:200

◆ exec_eval_expr()

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

Definition at line 5435 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().

5440 {
5441  Datum result = 0;
5442  int rc;
5443  Form_pg_attribute attr;
5444 
5445  /*
5446  * If first time through, create a plan for this expression.
5447  */
5448  if (expr->plan == NULL)
5450 
5451  /*
5452  * If this is a simple expression, bypass SPI and use the executor
5453  * directly
5454  */
5455  if (exec_eval_simple_expr(estate, expr,
5456  &result, isNull, rettype, rettypmod))
5457  return result;
5458 
5459  /*
5460  * Else do it the hard way via exec_run_select
5461  */
5462  rc = exec_run_select(estate, expr, 2, NULL);
5463  if (rc != SPI_OK_SELECT)
5464  ereport(ERROR,
5465  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5466  errmsg("query \"%s\" did not return data", expr->query)));
5467 
5468  /*
5469  * Check that the expression returns exactly one column...
5470  */
5471  if (estate->eval_tuptable->tupdesc->natts != 1)
5472  ereport(ERROR,
5473  (errcode(ERRCODE_SYNTAX_ERROR),
5474  errmsg_plural("query \"%s\" returned %d column",
5475  "query \"%s\" returned %d columns",
5476  estate->eval_tuptable->tupdesc->natts,
5477  expr->query,
5478  estate->eval_tuptable->tupdesc->natts)));
5479 
5480  /*
5481  * ... and get the column's datatype.
5482  */
5483  attr = TupleDescAttr(estate->eval_tuptable->tupdesc, 0);
5484  *rettype = attr->atttypid;
5485  *rettypmod = attr->atttypmod;
5486 
5487  /*
5488  * If there are no rows selected, the result is a NULL of that type.
5489  */
5490  if (estate->eval_processed == 0)
5491  {
5492  *isNull = true;
5493  return (Datum) 0;
5494  }
5495 
5496  /*
5497  * Check that the expression returned no more than one row.
5498  */
5499  if (estate->eval_processed != 1)
5500  ereport(ERROR,
5501  (errcode(ERRCODE_CARDINALITY_VIOLATION),
5502  errmsg("query \"%s\" returned more than one row",
5503  expr->query)));
5504 
5505  /*
5506  * Return the single result Datum.
5507  */
5508  return SPI_getbinval(estate->eval_tuptable->vals[0],
5509  estate->eval_tuptable->tupdesc, 1, isNull);
5510 }
char * query
Definition: plpgsql.h:215
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1013
uint64 eval_processed
Definition: plpgsql.h:1014
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:90
int errcode(int sqlerrcode)
Definition: elog.c:575
HeapTuple * vals
Definition: spi.h:28
int natts
Definition: tupdesc.h:79
SPIPlanPtr plan
Definition: plpgsql.h:216
#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:187
#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 void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions)
Definition: pl_exec.c:3745
static int exec_run_select(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
Definition: pl_exec.c:5518
static bool exec_eval_simple_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, Datum *result, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5755
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2647
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 5389 of file pl_exec.c.

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

Referenced by exec_assign_value(), and exec_stmt_fetch().

5392 {
5393  Datum exprdatum;
5394  Oid exprtypeid;
5395  int32 exprtypmod;
5396 
5397  exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
5398  exprdatum = exec_cast_value(estate, exprdatum, isNull,
5399  exprtypeid, exprtypmod,
5400  INT4OID, -1);
5401  return DatumGetInt32(exprdatum);
5402 }
#define DatumGetInt32(X)
Definition: postgres.h:455
#define INT4OID
Definition: pg_type.h:316
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:302
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7194
static Datum exec_eval_expr(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull, Oid *rettype, int32 *rettypmod)
Definition: pl_exec.c:5435
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 5755 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().

5761 {
5762  ExprContext *econtext = estate->eval_econtext;
5763  LocalTransactionId curlxid = MyProc->lxid;
5764  CachedPlan *cplan;
5765  void *save_setup_arg;
5766  MemoryContext oldcontext;
5767 
5768  /*
5769  * Forget it if expression wasn't simple before.
5770  */
5771  if (expr->expr_simple_expr == NULL)
5772  return false;
5773 
5774  /*
5775  * If expression is in use in current xact, don't touch it.
5776  */
5777  if (expr->expr_simple_in_use && expr->expr_simple_lxid == curlxid)
5778  return false;
5779 
5780  /*
5781  * Revalidate cached plan, so that we will notice if it became stale. (We
5782  * need to hold a refcount while using the plan, anyway.) If replanning
5783  * is needed, do that work in the eval_mcontext.
5784  */
5785  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5786  cplan = SPI_plan_get_cached_plan(expr->plan);
5787  MemoryContextSwitchTo(oldcontext);
5788 
5789  /*
5790  * We can't get a failure here, because the number of CachedPlanSources in
5791  * the SPI plan can't change from what exec_simple_check_plan saw; it's a
5792  * property of the raw parsetree generated from the query text.
5793  */
5794  Assert(cplan != NULL);
5795 
5796  /* If it got replanned, update our copy of the simple expression */
5797  if (cplan->generation != expr->expr_simple_generation)
5798  {
5799  exec_save_simple_expr(expr, cplan);
5800  /* better recheck r/w safety, as it could change due to inlining */
5801  if (expr->rwparam >= 0)
5802  exec_check_rw_parameter(expr, expr->rwparam);
5803  }
5804 
5805  /*
5806  * Pass back previously-determined result type.
5807  */
5808  *rettype = expr->expr_simple_type;
5809  *rettypmod = expr->expr_simple_typmod;
5810 
5811  /*
5812  * Set up ParamListInfo to pass to executor. For safety, save and restore
5813  * estate->paramLI->parserSetupArg around our use of the param list.
5814  */
5815  save_setup_arg = estate->paramLI->parserSetupArg;
5816 
5817  econtext->ecxt_param_list_info = setup_param_list(estate, expr);
5818 
5819  /*
5820  * Prepare the expression for execution, if it's not been done already in
5821  * the current transaction. (This will be forced to happen if we called
5822  * exec_save_simple_expr above.)
5823  */
5824  if (expr->expr_simple_lxid != curlxid)
5825  {
5826  oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
5827  expr->expr_simple_state =
5829  econtext->ecxt_param_list_info);
5830  expr->expr_simple_in_use = false;
5831  expr->expr_simple_lxid = curlxid;
5832  MemoryContextSwitchTo(oldcontext);
5833  }
5834 
5835  /*
5836  * We have to do some of the things SPI_execute_plan would do, in
5837  * particular advance the snapshot if we are in a non-read-only function.
5838  * Without this, stable functions within the expression would fail to see
5839  * updates made so far by our own function.
5840  */
5841  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
5842  if (!estate->readonly_func)
5843  {
5846  }
5847 
5848  /*
5849  * Mark expression as busy for the duration of the ExecEvalExpr call.
5850  */
5851  expr->expr_simple_in_use = true;
5852 
5853  /*
5854  * Finally we can call the executor to evaluate the expression
5855  */
5856  *result = ExecEvalExpr(expr->expr_simple_state,
5857  econtext,
5858  isNull);
5859 
5860  /* Assorted cleanup */
5861  expr->expr_simple_in_use = false;
5862 
5863  econtext->ecxt_param_list_info = NULL;
5864 
5865  estate->paramLI->parserSetupArg = save_setup_arg;
5866 
5867  if (!estate->readonly_func)
5869 
5870  MemoryContextSwitchTo(oldcontext);
5871 
5872  /*
5873  * Now we can release our refcount on the cached plan.
5874  */
5875  ReleaseCachedPlan(cplan, true);
5876 
5877  /*
5878  * That's it.
5879  */
5880  return true;
5881 }
int expr_simple_generation
Definition: plpgsql.h:228
void * parserSetupArg
Definition: params.h:117
static void exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno)
Definition: pl_exec.c:7586
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:7499
SPIPlanPtr plan
Definition: plpgsql.h:216
CachedPlan * SPI_plan_get_cached_plan(SPIPlanPtr plan)
Definition: spi.c:1702
MemoryContext es_query_cxt
Definition: execnodes.h:488
ParamListInfo paramLI
Definition: plpgsql.h:999
EState * simple_eval_estate
Definition: plpgsql.h:1002
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:733
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:282
ExprState * ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
Definition: execExpr.c:155
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1256
Expr * expr_simple_expr
Definition: plpgsql.h:227
uint32 LocalTransactionId
Definition: c.h:465
static ParamListInfo setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:5900
int rwparam
Definition: plpgsql.h:218
#define get_eval_mcontext(estate)
Definition: pl_exec.c:115
ExprState * expr_simple_state
Definition: plpgsql.h:238
void CommandCounterIncrement(void)
Definition: xact.c:915
LocalTransactionId expr_simple_lxid
Definition: plpgsql.h:240
#define Assert(condition)
Definition: c.h:688
ExprContext * eval_econtext
Definition: plpgsql.h:1016
bool readonly_func
Definition: plpgsql.h:968
int generation
Definition: plancache.h:141
int32 expr_simple_typmod
Definition: plpgsql.h:230
bool expr_simple_in_use
Definition: plpgsql.h:239
ParamListInfo ecxt_param_list_info
Definition: execnodes.h:221
Oid expr_simple_type
Definition: plpgsql.h:229
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 7894 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, TEXTOID, PreparedParamsData::types, UNKNOWNOID, and PreparedParamsData::values.

Referenced by exec_dynquery_with_params(), and exec_stmt_dynexecute().

7895 {
7896  PreparedParamsData *ppd;
7897  MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
7898  int nargs;
7899  int i;
7900  ListCell *lc;
7901 
7902  ppd = (PreparedParamsData *)
7903  MemoryContextAlloc(stmt_mcontext, sizeof(PreparedParamsData));
7904  nargs = list_length(params);
7905 
7906  ppd->nargs = nargs;
7907  ppd->types = (Oid *)
7908  MemoryContextAlloc(stmt_mcontext, nargs * sizeof(Oid));
7909  ppd->values = (Datum *)
7910  MemoryContextAlloc(stmt_mcontext, nargs * sizeof(Datum));
7911  ppd->nulls = (char *)
7912  MemoryContextAlloc(stmt_mcontext, nargs * sizeof(char));
7913 
7914  i = 0;
7915  foreach(lc, params)
7916  {
7917  PLpgSQL_expr *param = (PLpgSQL_expr *) lfirst(lc);
7918  bool isnull;
7919  int32 ppdtypmod;
7920  MemoryContext oldcontext;
7921 
7922  ppd->values[i] = exec_eval_expr(estate, param,
7923  &isnull,
7924  &ppd->types[i],
7925  &ppdtypmod);
7926  ppd->nulls[i] = isnull ? 'n' : ' ';
7927 
7928  oldcontext = MemoryContextSwitchTo(stmt_mcontext);
7929 
7930  if (ppd->types[i] == UNKNOWNOID)
7931  {
7932  /*
7933  * Treat 'unknown' parameters as text, since that's what most
7934  * people would expect. SPI_execute_with_args can coerce unknown
7935  * constants in a more intelligent way, but not unknown Params.
7936  * This code also takes care of copying into the right context.
7937  * Note we assume 'unknown' has the representation of C-string.
7938  */
7939  ppd->types[i] = TEXTOID;
7940  if (!isnull)
7942  }
7943  /* pass-by-ref non null values must be copied into stmt_mcontext */
7944  else if (!isnull)
7945  {
7946  int16 typLen;
7947  bool typByVal;
7948 
7949  get_typlenbyval(ppd->types[i], &typLen, &typByVal);
7950  if (!typByVal)
7951  ppd->values[i] = datumCopy(ppd->values[i], typByVal, typLen);
7952  }
7953 
7954  MemoryContextSwitchTo(oldcontext);
7955 
7956  exec_eval_cleanup(estate);
7957 
7958  i++;
7959  }
7960 
7961  return ppd;
7962 }
signed short int16
Definition: c.h:301
#define TEXTOID
Definition: pg_type.h:324
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:3724
Datum * values
Definition: pl_exec.c:52
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:302
#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:5435
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate)
Definition: pl_exec.c:1435
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
#define UNKNOWNOID
Definition: pg_type.h:431
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:693
int i
#define CStringGetTextDatum(s)
Definition: builtins.h:91

◆ exec_for_query()

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

Definition at line 5583 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, RECORDOID, 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().

5585 {
5586  PLpgSQL_variable *var;
5587  SPITupleTable *tuptab;
5588  bool found = false;
5589  int rc = PLPGSQL_RC_OK;
5590  uint64 previous_id = INVALID_TUPLEDESC_IDENTIFIER;
5591  bool tupdescs_match = true;
5592  uint64 n;
5593 
5594  /* Fetch loop variable's datum entry */
5595  var = (PLpgSQL_variable *) estate->datums[stmt->var->dno];
5596 
5597  /*
5598  * Make sure the portal doesn't get closed by the user statements we
5599  * execute.
5600  */
5601  PinPortal(portal);
5602 
5603  /*
5604  * Fetch the initial tuple(s). If prefetching is allowed then we grab a
5605  * few more rows to avoid multiple trips through executor startup
5606  * overhead.
5607  */
5608  SPI_cursor_fetch(portal, true, prefetch_ok ? 10 : 1);
5609  tuptab = SPI_tuptable;
5610  n = SPI_processed;
5611 
5612  /*
5613  * If the query didn't return any rows, set the target to NULL and fall
5614  * through with found = false.
5615  */
5616  if (n == 0)
5617  {
5618  exec_move_row(estate, var, NULL, tuptab->tupdesc);
5619  exec_eval_cleanup(estate);
5620  }
5621  else
5622  found = true; /* processed at least one tuple */
5623 
5624  /*
5625  * Now do the loop
5626  */
5627  while (n > 0)
5628  {
5629  uint64 i;
5630 
5631  for (i = 0; i < n; i++)
5632  {
5633  /*
5634  * Assign the tuple to the target. Here, because we know that all
5635  * loop iterations should be assigning the same tupdesc, we can
5636  * optimize away repeated creations of expanded records with
5637  * identical tupdescs. Testing for changes of er_tupdesc_id is
5638  * reliable even if the loop body contains assignments that
5639  * replace the target's value entirely, because it's assigned from
5640  * a process-global counter. The case where the tupdescs don't
5641  * match could possibly be handled more efficiently than this
5642  * coding does, but it's not clear extra effort is worthwhile.
5643  */
5644  if (var->dtype == PLPGSQL_DTYPE_REC)
5645  {
5646  PLpgSQL_rec *rec = (PLpgSQL_rec *) var;
5647 
5648  if (rec->erh &&
5649  rec->erh->er_tupdesc_id == previous_id &&
5650  tupdescs_match)
5651  {
5652  /* Only need to assign a new tuple value */
5653  expanded_record_set_tuple(rec->erh, tuptab->vals[i], true);
5654  }
5655  else
5656  {
5657  /*
5658  * First time through, or var's tupdesc changed in loop,
5659  * or we have to do it the hard way because type coercion
5660  * is needed.
5661  */
5662  exec_move_row(estate, var,
5663  tuptab->vals[i], tuptab->tupdesc);
5664 
5665  /*
5666  * Check to see if physical assignment is OK next time.
5667  * Once the tupdesc comparison has failed once, we don't
5668  * bother rechecking in subsequent loop iterations.
5669  */
5670  if (tupdescs_match)
5671  {
5672  tupdescs_match =
5673  (rec->rectypeid == RECORDOID ||
5674  rec->rectypeid == tuptab->tupdesc->tdtypeid ||
5675  compatible_tupdescs(tuptab->tupdesc,
5677  }
5678  previous_id = rec->erh->er_tupdesc_id;
5679  }
5680  }
5681  else
5682  exec_move_row(estate, var, tuptab->vals[i], tuptab->tupdesc);
5683 
5684  exec_eval_cleanup(estate);
5685 
5686  /*
5687  * Execute the statements
5688  */
5689  rc = exec_stmts(estate, stmt->body);
5690 
5691  LOOP_RC_PROCESSING(stmt->label, goto loop_exit);
5692  }
5693 
5694  SPI_freetuptable(tuptab);
5695 
5696  /*
5697  * Fetch more tuples. If prefetching is allowed, grab 50 at a time.
5698  */
5699  SPI_cursor_fetch(portal, true, prefetch_ok ? 50 : 1);
5700  tuptab = SPI_tuptable;
5701  n = SPI_processed;
5702  }
5703 
5704 loop_exit:
5705 
5706  /*
5707  * Release last group of tuples (if any)
5708  */
5709  SPI_freetuptable(tuptab);
5710 
5711  UnpinPortal(portal);
5712 
5713  /*
5714  * Set the FOUND variable to indicate the result of executing the loop
5715  * (namely, whether we looped one or more times). This must be set last so
5716  * that it does not interfere with the value of the FOUND variable inside
5717  * the loop processing itself.
5718  */
5719  exec_set_found(estate, found);
5720 
5721  return rc;
5722 }
void UnpinPortal(Portal portal)
Definition: portalmem.c:374
Oid tdtypeid
Definition: tupdesc.h:80
SPITupleTable * SPI_tuptable
Definition: spi.c:41
ExpandedRecordHeader * erh
Definition: plpgsql.h:377
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:3724
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:989
void PinPortal(Portal portal)
Definition: portalmem.c:365
#define LOOP_RC_PROCESSING(looplabel, exit_action)
Definition: pl_exec.c:181
#define RECORDOID
Definition: pg_type.h:680
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:6779
TupleDesc tupdesc
Definition: spi.h:27
PLpgSQL_datum_type dtype
Definition: plpgsql.h:263
PLpgSQL_variable * var
Definition: plpgsql.h:645
static void exec_set_found(PLpgSQL_execstate *estate, bool state)
Definition: pl_exec.c:7685
static void exec_move_row(PLpgSQL_execstate *estate, PLpgSQL_variable *target, HeapTuple tup, TupleDesc tupdesc)
Definition: pl_exec.c:6393
int i
void SPI_cursor_fetch(Portal portal, bool forward, long count)
Definition: spi.c:1443
Oid rectypeid
Definition: plpgsql.h:370
void expanded_record_set_tuple(ExpandedRecordHeader *erh, HeapTuple tuple, bool copy)
static int exec_stmts(PLpgSQL_execstate *estate, List *stmts)
Definition: pl_exec.c:1846

◆ exec_init_tuple_store()

static void exec_init_tuple_store ( PLpgSQL_execstate estate)
static

Definition at line 3273 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().

3274 {
3275  ReturnSetInfo *rsi = estate->rsi;
3276  MemoryContext oldcxt;
3277  ResourceOwner oldowner;
3278 
3279  /*
3280  * Check caller can handle a set result in the way we want
3281  */
3282  if (!rsi || !IsA(rsi, ReturnSetInfo) ||
3283  (rsi->allowedModes & SFRM_Materialize) == 0 ||
3284  rsi->expectedDesc == NULL)
3285  ereport(ERROR,
3286  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3287  errmsg("set-valued function called in context that cannot accept a set")));
3288 
3289  /*
3290  * Switch to the right memory context and resource owner for storing the
3291  * tuplestore for return set. If we're within a subtransaction opened for
3292  * an exception-block, for example, we must still create the tuplestore in
3293  * the resource owner that was active when this function was entered, and
3294  * not in the subtransaction resource owner.
3295  */
3296  oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
3297  oldowner = CurrentResourceOwner;
3299 
3300  estate->tuple_store =
3302  false, work_mem);
3303 
3304  CurrentResourceOwner = oldowner;
3305  MemoryContextSwitchTo(oldcxt);
3306 
3307  estate->tuple_store_desc = rsi->expectedDesc;
3308 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:564
ResourceOwner tuple_store_owner
Definition: plpgsql.h:977
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:575
TupleDesc expectedDesc
Definition: execnodes.h:281
TupleDesc tuple_store_desc
Definition: plpgsql.h:975
#define ERROR
Definition: elog.h:43
MemoryContext tuple_store_cxt
Definition: plpgsql.h:976
ReturnSetInfo * rsi
Definition: plpgsql.h:978
#define ereport(elevel, rest)
Definition: elog.h:122
Tuplestorestate * tuple_store
Definition: plpgsql.h:974
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
int work_mem
Definition: globals.c:113
int allowedModes
Definition: execnodes.h:282
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 6393 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, RECORDOID, PLpgSQL_rec::rectypeid, tupleDesc::tdtypeid, PLpgSQL_type::typtype, TYPTYPE_DOMAIN, and values.

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

6396 {
6397  ExpandedRecordHeader *newerh = NULL;
6398 
6399  /*
6400  * If target is RECORD, we may be able to avoid field-by-field processing.
6401  */
6402  if (target->dtype == PLPGSQL_DTYPE_REC)
6403  {
6404  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
6405 
6406  /*
6407  * If we have no source tupdesc, just set the record variable to NULL.
6408  * (If we have a source tupdesc but not a tuple, we'll set the
6409  * variable to a row of nulls, instead. This is odd perhaps, but
6410  * backwards compatible.)
6411  */
6412  if (tupdesc == NULL)
6413  {
6414  if (rec->datatype &&
6415  rec->datatype->typtype == TYPTYPE_DOMAIN)
6416  {
6417  /*
6418  * If it's a composite domain, NULL might not be a legal
6419  * value, so we instead need to make an empty expanded record
6420  * and ensure that domain type checking gets done. If there
6421  * is already an expanded record, piggyback on its lookups.
6422  */
6423  newerh = make_expanded_record_for_rec(estate, rec,
6424  NULL, rec->erh);
6425  expanded_record_set_tuple(newerh, NULL, false);
6426  assign_record_var(estate, rec, newerh);
6427  }
6428  else
6429  {
6430  /* Just clear it to NULL */
6431  if (rec->erh)
6433  rec->erh = NULL;
6434  }
6435  return;
6436  }
6437 
6438  /*
6439  * Build a new expanded record with appropriate tupdesc.
6440  */
6441  newerh = make_expanded_record_for_rec(estate, rec, tupdesc, NULL);
6442 
6443  /*
6444  * If the rowtypes match, or if we have no tuple anyway, we can
6445  * complete the assignment without field-by-field processing.
6446  *
6447  * The tests here are ordered more or less in order of cheapness. We
6448  * can easily detect it will work if the target is declared RECORD or
6449  * has the same typeid as the source. But when assigning from a query
6450  * result, it's common to have a source tupdesc that's labeled RECORD
6451  * but is actually physically compatible with a named-composite-type
6452  * target, so it's worth spending extra cycles to check for that.
6453  */
6454  if (rec->rectypeid == RECORDOID ||
6455  rec->rectypeid == tupdesc->tdtypeid ||
6456  !HeapTupleIsValid(tup) ||
6458  {
6459  if (!HeapTupleIsValid(tup))
6460  {
6461  /* No data, so force the record into all-nulls state */
6463  }
6464  else
6465  {
6466  /* No coercion is needed, so just assign the row value */
6467  expanded_record_set_tuple(newerh, tup, true);
6468  }
6469 
6470  /* Complete the assignment */
6471  assign_record_var(estate, rec, newerh);
6472 
6473  return;
6474  }
6475  }
6476 
6477  /*
6478  * Otherwise, deconstruct the tuple and do field-by-field assignment,
6479  * using exec_move_row_from_fields.
6480  */
6481  if (tupdesc && HeapTupleIsValid(tup))
6482  {
6483  int td_natts = tupdesc->natts;
6484  Datum *values;
6485  bool *nulls;
6486  Datum values_local[64];
6487  bool nulls_local[64];
6488 
6489  /*
6490  * Need workspace arrays. If td_natts is small enough, use local
6491  * arrays to save doing a palloc. Even if it's not small, we can
6492  * allocate both the Datum and isnull arrays in one palloc chunk.
6493  */
6494  if (td_natts <= lengthof(values_local))
6495  {
6496  values = values_local;
6497  nulls = nulls_local;
6498  }
6499  else
6500  {
6501  char *chunk;
6502 
6503  chunk = eval_mcontext_alloc(estate,
6504  td_natts * (sizeof(Datum) + sizeof(bool)));
6505  values = (Datum *) chunk;
6506  nulls = (bool *) (chunk + td_natts * sizeof(Datum));
6507  }
6508 
6509  heap_deform_tuple(tup, tupdesc, values, nulls);
6510 
6511  exec_move_row_from_fields(estate, target, newerh,
6512  values, nulls, tupdesc);
6513  }
6514  else
6515  {
6516  /*
6517  * Assign all-nulls.
6518  */
6519  exec_move_row_from_fields(estate, target, newerh,
6520  NULL, NULL, NULL);
6521  }
6522 }
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
Oid tdtypeid
Definition: tupdesc.h:80
PLpgSQL_type * datatype
Definition: plpgsql.h:369
static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
Definition: pl_exec.c:7871
ExpandedRecordHeader * erh
Definition: plpgsql.h:377
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:6596
#define lengthof(array)
Definition: c.h:618
int natts
Definition: tupdesc.h:79
static ExpandedRecordHeader * make_expanded_record_for_rec(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, TupleDesc srctupdesc, ExpandedRecordHeader *srcerh)
Definition: pl_exec.c:6538
#define eval_mcontext_alloc(estate, sz)
Definition: pl_exec.c:117
#define RECORDOID
Definition: pg_type.h:680
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:6779
void DeleteExpandedObject(Datum d)
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
PLpgSQL_datum_type dtype
Definition: plpgsql.h:263
char typtype
Definition: plpgsql.h:204
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:936
static Datum values[MAXATTR]
Definition: bootstrap.c:164
Oid rectypeid
Definition: plpgsql.h:370
#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 6909 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, RECORDOID, 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().

6912 {
6913  /* Check to see if source is an expanded record */
6915  {
6917  ExpandedRecordHeader *newerh = NULL;
6918 
6919  Assert(erh->er_magic == ER_MAGIC);
6920 
6921  /* These cases apply if the target is record not row... */
6922  if (target->dtype == PLPGSQL_DTYPE_REC)
6923  {
6924  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
6925 
6926  /*
6927  * If it's the same record already stored in the variable, do
6928  * nothing. This would happen only in silly cases like "r := r",
6929  * but we need some check to avoid possibly freeing the variable's
6930  * live value below. Note that this applies even if what we have
6931  * is a R/O pointer.
6932  */
6933  if (erh == rec->erh)
6934  return;
6935 
6936  /*
6937  * If we have a R/W pointer, we're allowed to just commandeer
6938  * ownership of the expanded record. If it's of the right type to
6939  * put into the record variable, do that. (Note we don't accept
6940  * an expanded record of a composite-domain type as a RECORD
6941  * value. We'll treat it as the base composite type instead;
6942  * compare logic in make_expanded_record_for_rec.)
6943  */
6945  (rec->rectypeid == erh->er_decltypeid ||
6946  (rec->rectypeid == RECORDOID &&
6947  !ExpandedRecordIsDomain(erh))))
6948  {
6949  assign_record_var(estate, rec, erh);
6950  return;
6951  }
6952 
6953  /*
6954  * If we already have an expanded record object in the target
6955  * variable, and the source record contains a valid tuple
6956  * representation with the right rowtype, then we can skip making
6957  * a new expanded record and just assign the tuple with
6958  * expanded_record_set_tuple. (We can't do the equivalent if we
6959  * have to do field-by-field assignment, since that wouldn't be
6960  * atomic if there's an error.) We consider that there's a
6961  * rowtype match only if it's the same named composite type or
6962  * same registered rowtype; checking for matches of anonymous
6963  * rowtypes would be more expensive than this is worth.
6964  */
6965  if (rec->erh &&
6966  (erh->flags & ER_FLAG_FVALUE_VALID) &&
6967  erh->er_typeid == rec->erh->er_typeid &&
6968  (erh->er_typeid != RECORDOID ||
6969  (erh->er_typmod == rec->erh->er_typmod &&
6970  erh->er_typmod >= 0)))
6971  {
6972  expanded_record_set_tuple(rec->erh, erh->fvalue, true);
6973  return;
6974  }
6975 
6976  /*
6977  * Otherwise we're gonna need a new expanded record object. Make
6978  * it here in hopes of piggybacking on the source object's
6979  * previous typcache lookup.
6980  */
6981  newerh = make_expanded_record_for_rec(estate, rec, NULL, erh);
6982 
6983  /*
6984  * If the expanded record contains a valid tuple representation,
6985  * and we don't need rowtype conversion, then just copying the
6986  * tuple is probably faster than field-by-field processing. (This
6987  * isn't duplicative of the previous check, since here we will
6988  * catch the case where the record variable was previously empty.)
6989  */
6990  if ((erh->flags & ER_FLAG_FVALUE_VALID) &&
6991  (rec->rectypeid == RECORDOID ||
6992  rec->rectypeid == erh->er_typeid))
6993  {
6994  expanded_record_set_tuple(newerh, erh->fvalue, true);
6995  assign_record_var(estate, rec, newerh);
6996  return;
6997  }
6998 
6999  /*
7000  * Need to special-case empty source record, else code below would
7001  * leak newerh.
7002  */
7003  if (ExpandedRecordIsEmpty(erh))
7004  {
7005  /* Set newerh to a row of NULLs */
7007  assign_record_var(estate, rec, newerh);
7008  return;
7009  }
7010  } /* end of record-target-only cases */
7011 
7012  /*
7013  * If the source expanded record is empty, we should treat that like a
7014  * NULL tuple value. (We're unlikely to see such a case, but we must
7015  * check this; deconstruct_expanded_record would cause a change of
7016  * logical state, which is not OK.)
7017  */
7018  if (ExpandedRecordIsEmpty(erh))
7019  {
7020  exec_move_row(estate, target, NULL,
7022  return;
7023  }
7024 
7025  /*
7026  * Otherwise, ensure that the source record is deconstructed, and
7027  * assign from its field values.
7028  */
7030  exec_move_row_from_fields(estate, target, newerh,
7031  erh->dvalues, erh->dnulls,
7033  }
7034  else
7035  {
7036  /*
7037  * Nope, we've got a plain composite Datum. Deconstruct it; but we
7038  * don't use deconstruct_composite_datum(), because we may be able to
7039  * skip calling lookup_rowtype_tupdesc().
7040  */
7041  HeapTupleHeader td;
7042  HeapTupleData tmptup;
7043  Oid tupType;
7044  int32 tupTypmod;
7045  TupleDesc tupdesc;
7046  MemoryContext oldcontext;
7047 
7048  /* Ensure that any detoasted data winds up in the eval_mcontext */
7049  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7050  /* Get tuple body (note this could involve detoasting) */
7052  MemoryContextSwitchTo(oldcontext);
7053 
7054  /* Build a temporary HeapTuple control structure */
7055  tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
7056  ItemPointerSetInvalid(&(tmptup.t_self));
7057  tmptup.t_tableOid = InvalidOid;
7058  tmptup.t_data = td;
7059 
7060  /* Extract rowtype info */
7061  tupType = HeapTupleHeaderGetTypeId(td);
7062  tupTypmod = HeapTupleHeaderGetTypMod(td);
7063 
7064  /* Now, if the target is record not row, maybe we can optimize ... */
7065  if (target->dtype == PLPGSQL_DTYPE_REC)
7066  {
7067  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
7068 
7069  /*
7070  * If we already have an expanded record object in the target
7071  * variable, and the source datum has a matching rowtype, then we
7072  * can skip making a new expanded record and just assign the tuple
7073  * with expanded_record_set_tuple. We consider that there's a
7074  * rowtype match only if it's the same named composite type or
7075  * same registered rowtype. (Checking to reject an anonymous
7076  * rowtype here should be redundant, but let's be safe.)
7077  */
7078  if (rec->erh &&
7079  tupType == rec->erh->er_typeid &&
7080  (tupType != RECORDOID ||
7081  (tupTypmod == rec->erh->er_typmod &&
7082  tupTypmod >= 0)))
7083  {
7084  expanded_record_set_tuple(rec->erh, &tmptup, true);
7085  return;
7086  }
7087 
7088  /*
7089  * If the source datum has a rowtype compatible with the target
7090  * variable, just build a new expanded record and assign the tuple
7091  * into it. Using make_expanded_record_from_typeid() here saves
7092  * one typcache lookup compared to the code below.
7093  */
7094  if (rec->rectypeid == RECORDOID || rec->rectypeid == tupType)
7095  {
7096  ExpandedRecordHeader *newerh;
7097  MemoryContext mcontext = get_eval_mcontext(estate);
7098 
7099  newerh = make_expanded_record_from_typeid(tupType, tupTypmod,
7100  mcontext);
7101  expanded_record_set_tuple(newerh, &tmptup, true);
7102  assign_record_var(estate, rec, newerh);
7103  return;
7104  }
7105 
7106  /*
7107  * Otherwise, we're going to need conversion, so fall through to
7108  * do it the hard way.
7109  */
7110  }
7111 
7112  /*
7113  * ROW target, or unoptimizable RECORD target, so we have to expend a
7114  * lookup to obtain the source datum's tupdesc.
7115  */
7116  tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
7117 
7118  /* Do the move */
7119  exec_move_row(estate, target, &tmptup, tupdesc);
7120 
7121  /* Release tupdesc usage count */
7122  ReleaseTupleDesc(tupdesc);
7123  }
7124 }
#define ER_FLAG_FVALUE_VALID
ExpandedRecordHeader * make_expanded_record_from_typeid(Oid type_id, int32 typmod, MemoryContext parentcontext)
static struct @130 value
#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:7871
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
ExpandedRecordHeader * erh
Definition: plpgsql.h:377
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:6596
unsigned int Oid
Definition: postgres_ext.h:31
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:259
signed int int32
Definition: c.h:302
HeapTupleHeader t_data
Definition: htup.h:67
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:460
static ExpandedRecordHeader * make_expanded_record_for_rec(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, TupleDesc srctupdesc, ExpandedRecordHeader *srcerh)
Definition: pl_exec.c:6538
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
Oid t_tableOid
Definition: htup.h:66
#define RECORDOID
Definition: pg_type.h:680
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:115
#define ER_MAGIC
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:450
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:688
PLpgSQL_datum_type dtype
Definition: plpgsql.h:263
#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:6393
#define VARATT_IS_EXTERNAL_EXPANDED_RW(PTR)
Definition: postgres.h:320
Oid rectypeid
Definition: plpgsql.h:370
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:121
#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:444

◆ 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 6596 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, UNKNOWNOID, value, and PLpgSQL_row::varnos.

Referenced by exec_move_row(), and exec_move_row_from_datum().

6601 {
6602  int td_natts = tupdesc ? tupdesc->natts : 0;
6603  int fnum;
6604  int anum;
6605 
6606  /* Handle RECORD-target case */
6607  if (target->dtype == PLPGSQL_DTYPE_REC)
6608  {
6609  PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
6610  TupleDesc var_tupdesc;
6611  Datum newvalues_local[64];
6612  bool newnulls_local[64];
6613 
6614  Assert(newerh != NULL); /* caller must have built new object */
6615 
6616  var_tupdesc = expanded_record_get_tupdesc(newerh);
6617 
6618  /*
6619  * Coerce field values if needed. This might involve dealing with
6620  * different sets of dropped columns and/or coercing individual column
6621  * types. That's sort of a pain, but historically plpgsql has allowed
6622  * it, so we preserve the behavior. However, it's worth a quick check
6623  * to see if the tupdescs are identical. (Since expandedrecord.c
6624  * prefers to use refcounted tupdescs from the typcache, expanded
6625  * records with the same rowtype will have pointer-equal tupdescs.)
6626  */
6627  if (var_tupdesc != tupdesc)
6628  {
6629  int vtd_natts = var_tupdesc->natts;
6630  Datum *newvalues;
6631  bool *newnulls;
6632 
6633  /*
6634  * Need workspace arrays. If vtd_natts is small enough, use local
6635  * arrays to save doing a palloc. Even if it's not small, we can
6636  * allocate both the Datum and isnull arrays in one palloc chunk.
6637  */
6638  if (vtd_natts <= lengthof(newvalues_local))
6639  {
6640  newvalues = newvalues_local;
6641  newnulls = newnulls_local;
6642  }
6643  else
6644  {
6645  char *chunk;
6646 
6647  chunk = eval_mcontext_alloc(estate,
6648  vtd_natts * (sizeof(Datum) + sizeof(bool)));
6649  newvalues = (Datum *) chunk;
6650  newnulls = (bool *) (chunk + vtd_natts * sizeof(Datum));
6651  }
6652 
6653  /* Walk over destination columns */
6654  anum = 0;
6655  for (fnum = 0; fnum < vtd_natts; fnum++)
6656  {
6657  Form_pg_attribute attr = TupleDescAttr(var_tupdesc, fnum);
6658  Datum value;
6659  bool isnull;
6660  Oid valtype;
6661  int32 valtypmod;
6662 
6663  if (attr->attisdropped)
6664  {
6665  /* expanded_record_set_fields should ignore this column */
6666  continue; /* skip dropped column in record */
6667  }
6668 
6669  while (anum < td_natts &&
6670  TupleDescAttr(tupdesc, anum)->attisdropped)
6671  anum++; /* skip dropped column in tuple */
6672 
6673  if (anum < td_natts)
6674  {
6675  value = values[anum];
6676  isnull = nulls[anum];
6677  valtype = TupleDescAttr(tupdesc, anum)->atttypid;
6678  valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
6679  anum++;
6680  }
6681  else
6682  {
6683  value = (Datum) 0;
6684  isnull = true;
6685  valtype = UNKNOWNOID;
6686  valtypmod = -1;
6687  }
6688 
6689  /* Cast the new value to the right type, if needed. */
6690  newvalues[fnum] = exec_cast_value(estate,
6691  value,
6692  &isnull,
6693  valtype,
6694  valtypmod,
6695  attr->atttypid,
6696  attr->atttypmod);
6697  newnulls[fnum] = isnull;
6698  }
6699 
6700  values = newvalues;
6701  nulls = newnulls;
6702  }
6703 
6704  /* Insert the coerced field values into the new expanded record */
6705  expanded_record_set_fields(newerh, values, nulls);
6706 
6707  /* Complete the assignment */
6708  assign_record_var(estate, rec, newerh);
6709 
6710  return;
6711  }
6712 
6713  /* newerh should not have been passed in non-RECORD cases */
6714  Assert(newerh == NULL);
6715 
6716  /*
6717  * For a row, we assign the individual field values to the variables the
6718  * row points to.
6719  *
6720  * NOTE: both this code and the record code above silently ignore extra
6721  * columns in the source and assume NULL for missing columns. This is
6722  * pretty dubious but it's the historical behavior.
6723  *
6724  * If we have no input data at all, we'll assign NULL to all columns of
6725  * the row variable.
6726  */
6727  if (target->dtype == PLPGSQL_DTYPE_ROW)
6728  {
6729  PLpgSQL_row *row = (PLpgSQL_row *) target;
6730 
6731  anum = 0;
6732  for (fnum = 0; fnum < row->nfields; fnum++)
6733  {
6734  PLpgSQL_var *var;
6735  Datum value;
6736  bool isnull;
6737  Oid valtype;
6738  int32 valtypmod;
6739 
6740  var = (PLpgSQL_var *) (estate->datums[row->varnos[fnum]]);
6741 
6742  while (anum < td_natts &&
6743  TupleDescAttr(tupdesc, anum)->attisdropped)
6744  anum++; /* skip dropped column in tuple */
6745 
6746  if (anum < td_natts)
6747  {
6748  value = values[anum];
6749  isnull = nulls[anum];
6750  valtype = TupleDescAttr(tupdesc, anum)->atttypid;
6751  valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
6752  anum++;
6753  }
6754  else
6755  {
6756  value = (Datum) 0;
6757  isnull = true;
6758  valtype = UNKNOWNOID;
6759  valtypmod = -1;
6760  }
6761 
6762  exec_assign_value(estate, (PLpgSQL_datum *) var,
6763  value, isnull, valtype, valtypmod);
6764  }
6765 
6766  return;
6767  }
6768 
6769  elog(ERROR, "unsupported target");
6770 }
static struct @130 value
static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec, ExpandedRecordHeader *erh)
Definition: pl_exec.c:7871
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
void expanded_record_set_fields(ExpandedRecordHeader *erh, const Datum *newValues, const bool *isnulls)
#define lengthof(array)
Definition: c.h:618
unsigned int Oid
Definition: postgres_ext.h:31
int natts
Definition: tupdesc.h:79
signed int int32
Definition: c.h:302
PLpgSQL_datum ** datums
Definition: plpgsql.h:989
static Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod)
Definition: pl_exec.c:7194
#define ERROR
Definition: elog.h:43
#define eval_mcontext_alloc(estate, sz)
Definition: pl_exec.c:117
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
int * varnos
Definition: plpgsql.h:352
uintptr_t Datum
Definition: postgres.h:365
#define Assert(condition)
Definition: c.h:688
int nfields
Definition: plpgsql.h:350
PLpgSQL_datum_type dtype
Definition: plpgsql.h:263
#define UNKNOWNOID
Definition: pg_type.h:431
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:4639

◆ exec_prepare_plan()

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

Definition at line 3745 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_execsql(), exec_stmt_forc(), and exec_stmt_open().

3747 {
3748  SPIPlanPtr plan;
3749 
3750  /*
3751  * The grammar can't conveniently set expr->func while building the parse
3752  * tree, so make sure it's set before parser hooks need it.
3753  */
3754  expr->func = estate->func;
3755 
3756  /*
3757  * Generate and save the plan
3758  */
3759  plan = SPI_prepare_params(expr->query,
3761  (void *) expr,
3762  cursorOptions);
3763  if (plan == NULL)
3764  {
3765  /* Some SPI errors deserve specific error messages */
3766  switch (SPI_result)
3767  {
3768  case SPI_ERROR_COPY:
3769  ereport(ERROR,
3770  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3771  errmsg("cannot COPY to/from client in PL/pgSQL")));
3772  case SPI_ERROR_TRANSACTION:
3773  ereport(ERROR,
3774  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3775  errmsg("cannot begin/end transactions in PL/pgSQL"),
3776  errhint("Use a BEGIN block with an EXCEPTION clause instead.")));
3777  default:
3778  elog(ERROR, "SPI_prepare_params failed for \"%s\": %s",
3780  }
3781  }
3782  SPI_keepplan(plan);
3783  expr->plan = plan;
3784 
3785  /* Check to see if it's a simple expression */
3786  exec_simple_check_plan(estate, expr);
3787 
3788  /*
3789  * Mark expression as not using a read-write param. exec_assign_value has
3790  * to take steps to override this if appropriate; that seems cleaner than
3791  * adding parameters to all other callers.
3792  */
3793  expr->rwparam = -1;
3794 }
int errhint(const char *fmt,...)
Definition: elog.c:987
char * query
Definition: plpgsql.h:215
#define SPI_ERROR_COPY
Definition: spi.h:37
int errcode(int sqlerrcode)
Definition: elog.c:575
PLpgSQL_function * func
Definition: plpgsql.h:955
static void exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
Definition: pl_exec.c:7400
SPIPlanPtr plan
Definition: plpgsql.h:216
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:1050
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:218
struct PLpgSQL_function * func
Definition: plpgsql.h:221
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 5518 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().

5520 {
5521  ParamListInfo paramLI;
5522  int rc;
5523 
5524  /*
5525  * On the first call for this expression generate the plan.
5526  *
5527  * If we don't need to return a portal, then we're just going to execute
5528  * the query once, which means it's OK to use a parallel plan, even if the
5529  * number of rows being fetched is limited. If we do need to return a
5530  * portal, the caller might do cursor operations, which parallel query
5531  * can't support.
5532  */
5533  if (expr->plan == NULL)
5534  exec_prepare_plan(estate, expr,
5535  portalP == NULL ? CURSOR_OPT_PARALLEL_OK : 0);
5536 
5537  /*
5538  * Set up ParamListInfo to pass to executor
5539  */
5540  paramLI = setup_param_list(estate, expr);
5541 
5542  /*
5543  * If a portal was requested, put the query and paramlist into the portal
5544  */
5545  if (portalP != NULL)
5546  {
5547  *portalP = SPI_cursor_open_with_paramlist(NULL, expr->plan,
5548  paramLI,
5549  estate->readonly_func);
5550  if (*portalP == NULL)
5551  elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
5553  exec_eval_cleanup(estate);
5554  return SPI_OK_CURSOR;
5555  }
5556 
5557  /*
5558  * Execute the query
5559  */
5560  rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
5561  estate->readonly_func, maxtuples);
5562  if (rc != SPI_OK_SELECT)
5563  ereport(ERROR,
5564  (errcode(ERRCODE_SYNTAX_ERROR),
5565  errmsg("query \"%s\" is not a SELECT", expr->query)));
5566 
5567  /* Save query results for eventual cleanup */
5568  Assert(estate->eval_tuptable == NULL);
5569  estate->eval_tuptable = SPI_tuptable;
5570  estate->eval_processed = SPI_processed;
5571  estate->eval_lastoid = SPI_lastoid;
5572 
5573  return rc;
5574 }
char * query
Definition: plpgsql.h:215
SPITupleTable * eval_tuptable
Definition: plpgsql.h:1013
uint64 eval_processed
Definition: plpgsql.h:1014
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:3724
#define SPI_OK_CURSOR
Definition: spi.h:59
uint64 SPI_processed
Definition: spi.c:39
SPIPlanPtr plan
Definition: plpgsql.h:216
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:5900
#define ereport(elevel, rest)
Definition: elog.h:122
Oid SPI_lastoid
Definition: spi.c:40
#define SPI_OK_SELECT
Definition: spi.h:54
static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions)
Definition: pl_exec.c:3745
#define Assert(condition)
Definition: c.h:688
bool readonly_func
Definition: plpgsql.h:968
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2647
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 7499 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().

7500 {
7501  PlannedStmt *stmt;
7502  Plan *plan;
7503  Expr *tle_expr;
7504 
7505  /*
7506  * Given the checks that exec_simple_check_plan did, none of the Asserts
7507  * here should ever fail.
7508  */
7509 
7510  /* Extract the single PlannedStmt */
7511  Assert(list_length(cplan->stmt_list) == 1);
7512  stmt = linitial_node(PlannedStmt, cplan->stmt_list);
7513  Assert(stmt->commandType == CMD_SELECT);
7514 
7515  /*
7516  * Ordinarily, the plan node should be a simple Result. However, if
7517  * force_parallel_mode is on, the planner might've stuck a Gather node
7518  * atop that. The simplest way to deal with this is to look through the
7519  * Gather node. The Gather node's tlist would normally contain a Var
7520  * referencing the child node's output, but it could also be a Param, or
7521  * it could be a Const that setrefs.c copied as-is.
7522  */
7523  plan = stmt->planTree;
7524  for (;;)
7525  {
7526  /* Extract the single tlist expression */
7527  Assert(list_length(plan->targetlist) == 1);
7528  tle_expr = castNode(TargetEntry, linitial(plan->targetlist))->expr;
7529 
7530  if (IsA(plan, Result))
7531  {
7532  Assert(plan->lefttree == NULL &&
7533  plan->righttree == NULL &&
7534  plan->initPlan == NULL &&
7535  plan->qual == NULL &&
7536  ((Result *) plan)->resconstantqual == NULL);
7537  break;
7538  }
7539  else if (IsA(plan, Gather))
7540  {
7541  Assert(plan->lefttree != NULL &&
7542  plan->righttree == NULL &&
7543  plan->initPlan == NULL &&
7544  plan->qual == NULL);
7545  /* If setrefs.c copied up a Const, no need to look further */
7546  if (IsA(tle_expr, Const))
7547  break;
7548  /* Otherwise, it had better be a Param or an outer Var */
7549  Assert(IsA(tle_expr, Param) ||(IsA(tle_expr, Var) &&
7550  ((Var *) tle_expr)->varno == OUTER_VAR));
7551  /* Descend to the child node */
7552  plan = plan->lefttree;
7553  }
7554  else
7555  elog(ERROR, "unexpected plan node type: %d",
7556  (int) nodeTag(plan));
7557  }
7558 
7559  /*
7560  * Save the simple expression, and initialize state to "not valid in
7561  * current transaction".
7562  */
7563  expr->expr_simple_expr = tle_expr;
7564  expr->expr_simple_generation = cplan->generation;
7565  expr->expr_simple_state = NULL;
7566  expr->expr_simple_in_use = false;
7568  /* Also stash away the expression result type */
7569  expr->expr_simple_type = exprType((Node *) tle_expr);
7570  expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
7571 }
int expr_simple_generation
Definition: plpgsql.h:228
List * qual
Definition: plannodes.h:145
#define IsA(nodeptr, _type_)
Definition: nodes.h:564
#define castNode(_type_, nodeptr)
Definition: nodes.h:582
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:276
Definition: nodes.h:513
Definition: primnodes.h:163
#define linitial_node(type, l)
Definition: pg_list.h:114
struct Plan * planTree
Definition: plannodes.h:61
struct Plan * righttree
Definition: plannodes.h:147
#define linitial(l)
Definition: pg_list.h:111
#define ERROR
Definition: elog.h:43
Expr * expr_simple_expr
Definition: plpgsql.h:227
ExprState * expr_simple_state
Definition: plpgsql.h:238
CmdType commandType
Definition: plannodes.h:45
LocalTransactionId expr_simple_lxid
Definition: plpgsql.h:240
#define Assert(condition)
Definition: c.h:688
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:146
#define nodeTag(nodeptr)
Definition: nodes.h:518
List * targetlist
Definition: plannodes.h:144
int32 expr_simple_typmod
Definition: plpgsql.h:230
List * initPlan
Definition: plannodes.h:148
#define InvalidLocalTransactionId
Definition: lock.h:69
List * stmt_list
Definition: plancache.h:133
bool expr_simple_in_use
Definition: plpgsql.h:239
#define elog
Definition: elog.h:219
#define OUTER_VAR
Definition: primnodes.h:154
Oid expr_simple_type
Definition: plpgsql.h:229

◆ exec_set_found()

static void exec_set_found ( PLpgSQL_execstate estate,
bool  state 
)
static

Definition at line 7685 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().

7686 {
7687  PLpgSQL_var *var;
7688 
7689  var = (PLpgSQL_var *) (estate->datums[estate->found_varno]);
7690  assign_simple_var(estate, var, BoolGetDatum(state), false, false);
7691 }
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, Datum newvalue, bool isnull, bool freeable)
Definition: pl_exec.c:7830
PLpgSQL_datum ** datums
Definition: plpgsql.h:989
#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 7400 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().

7401 {
7402  List *plansources;
7403  CachedPlanSource *plansource;
7404  Query *query;
7405  CachedPlan *cplan;
7406  MemoryContext oldcontext;
7407 
7408  /*
7409  * Initialize to "not simple".
7410  */
7411  expr->expr_simple_expr = NULL;
7412 
7413  /*
7414  * Check the analyzed-and-rewritten form of the query to see if we will be
7415  * able to treat it as a simple expression. Since this function is only
7416  * called immediately after creating the CachedPlanSource, we need not
7417  * worry about the query being stale.
7418  */
7419 
7420  /*
7421  * We can only test queries that resulted in exactly one CachedPlanSource
7422  */
7423  plansources = SPI_plan_get_plan_sources(expr->plan);
7424  if (list_length(plansources) != 1)
7425  return;
7426  plansource = (CachedPlanSource *) linitial(plansources);
7427 
7428  /*
7429  * 1. There must be one single querytree.
7430  */
7431  if (list_length(plansource->query_list) != 1)
7432  return;
7433  query = (Query *) linitial(plansource->query_list);
7434 
7435  /*
7436  * 2. It must be a plain SELECT query without any input tables
7437  */
7438  if (!IsA(query, Query))
7439  return;
7440  if (query->commandType != CMD_SELECT)
7441  return;
7442  if (query->rtable != NIL)
7443  return;
7444 
7445  /*
7446  * 3. Can't have any subplans, aggregates, qual clauses either. (These
7447  * tests should generally match what inline_function() checks before
7448  * inlining a SQL function; otherwise, inlining could change our
7449  * conclusion about whether an expression is simple, which we don't want.)
7450  */
7451  if (query->hasAggs ||
7452  query->hasWindowFuncs ||
7453  query->hasTargetSRFs ||
7454  query->hasSubLinks ||
7455  query->cteList ||
7456  query->jointree->fromlist ||
7457  query->jointree->quals ||
7458  query->groupClause ||
7459  query->groupingSets ||
7460  query->havingQual ||
7461  query->windowClause ||
7462  query->distinctClause ||
7463  query->sortClause ||
7464  query->limitOffset ||
7465  query->limitCount ||
7466  query->setOperations)
7467  return;
7468 
7469  /*
7470  * 4. The query must have a single attribute as result
7471  */
7472  if (list_length(query->targetList) != 1)
7473  return;
7474 
7475  /*
7476  * OK, we can treat it as a simple plan.
7477  *
7478  * Get the generic plan for the query. If replanning is needed, do that
7479  * work in the eval_mcontext.
7480  */
7481  oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
7482  cplan = SPI_plan_get_cached_plan(expr->plan);
7483  MemoryContextSwitchTo(oldcontext);
7484 
7485  /* Can't fail, because we checked for a single CachedPlanSource above */
7486  Assert(cplan != NULL);
7487 
7488  /* Share the remaining work with replan code path */
7489  exec_save_simple_expr(expr, cplan);
7490 
7491  /* Release our plan refcount */
7492  ReleaseCachedPlan(cplan, true);
7493 }
Node * limitOffset
Definition: parsenodes.h:158
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:564
List * sortClause
Definition: parsenodes.h:156
FromExpr * jointree
Definition: parsenodes.h:136
bool hasAggs
Definition: parsenodes.h:123
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
List * groupingSets
Definition: parsenodes.h:148
List * fromlist
Definition: primnodes.h:1478
Node * quals
Definition: primnodes.h:1479
static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
Definition: pl_exec.c:7499
SPIPlanPtr plan
Definition: plpgsql.h:216
List * windowClause
Definition: parsenodes.h:152
List * targetList
Definition: parsenodes.h:138
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:135
List * distinctClause
Definition: parsenodes.h:154
Node * limitCount
Definition: parsenodes.h:159
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1256
Expr * expr_simple_expr
Definition: plpgsql.h:227
#define get_eval_mcontext(estate)
Definition: pl_exec.c:115
CmdType commandType
Definition: parsenodes.h:110
bool hasTargetSRFs
Definition: parsenodes.h:125
#define Assert(condition)
Definition: c.h:688
bool hasWindowFuncs
Definition: parsenodes.h:124
static int list_length(const List *l)
Definition: pg_list.h:89
List * cteList
Definition: parsenodes.h:133
Node * setOperations
Definition: parsenodes.h:163
List * groupClause
Definition: parsenodes.h:146
bool hasSubLinks
Definition: parsenodes.h:126
List * SPI_plan_get_plan_sources(SPIPlanPtr plan)
Definition: spi.c:1686
List * query_list
Definition: plancache.h:95
Node * havingQual
Definition: parsenodes.h:150
Definition: pg_list.h:45

◆ exec_stmt()

static int exec_stmt ( PLpgSQL_execstate estate,
PLpgSQL_stmt stmt 
)
static

Definition at line 1880 of file pl_exec.c.

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

Referenced by exec_stmts().

1881 {
1882  PLpgSQL_stmt *save_estmt;
1883  int rc = -1;
1884 
1885  save_estmt = estate->err_stmt;
1886  estate->err_stmt = stmt;
1887 
1888  /* Let the plugin know that we are about to execute this statement */
1889  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
1890  ((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt);
1891 
1893 
1894  switch (stmt->cmd_type)
1895  {
1896  case PLPGSQL_STMT_BLOCK:
1897  rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt);
1898  break;
1899 
1900  case PLPGSQL_STMT_ASSIGN:
1901  rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
1902  break;
1903 
1904  case PLPGSQL_STMT_PERFORM:
1905  rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt);
1906  break;
1907 
1908  case PLPGSQL_STMT_GETDIAG:
1909  rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt);
1910  break;
1911 
1912  case PLPGSQL_STMT_IF:
1913  rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);
1914  break;
1915 
1916  case PLPGSQL_STMT_CASE:
1917  rc = exec_stmt_case(estate, (PLpgSQL_stmt_case *) stmt);
1918  break;
1919 
1920  case PLPGSQL_STMT_LOOP:
1921  rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt);
1922  break;
1923 
1924  case PLPGSQL_STMT_WHILE:
1925  rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt);
1926  break;
1927 
1928  case PLPGSQL_STMT_FORI:
1929  rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt);
1930  break;
1931 
1932  case PLPGSQL_STMT_FORS:
1933  rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt);
1934  break;
1935 
1936  case PLPGSQL_STMT_FORC:
1937  rc = exec_stmt_forc(estate, (PLpgSQL_stmt_forc *) stmt);
1938  break;
1939 
1941  rc = exec_stmt_foreach_a(estate, (PLpgSQL_stmt_foreach_a *) stmt);
1942  break;
1943 
1944  case PLPGSQL_STMT_EXIT:
1945  rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt);
1946  break;
1947 
1948  case PLPGSQL_STMT_RETURN:
1949  rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt);
1950  break;
1951 
1953  rc = exec_stmt_return_next(estate, (PLpgSQL_stmt_return_next *) stmt);
1954  break;
1955 
1957  rc = exec_stmt_return_query(estate, (PLpgSQL_stmt_return_query *) stmt);
1958  break;
1959 
1960  case PLPGSQL_STMT_RAISE:
1961  rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt);
1962  break;
1963 
1964  case PLPGSQL_STMT_ASSERT:
1965  rc = exec_stmt_assert(estate, (PLpgSQL_stmt_assert *) stmt);
1966  break;
1967 
1968  case PLPGSQL_STMT_EXECSQL:
1969  rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt);
1970  break;
1971 
1973  rc = exec_stmt_dynexecute(estate, (PLpgSQL_stmt_dynexecute *) stmt);
1974  break;
1975 
1976  case PLPGSQL_STMT_DYNFORS:
1977  rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt);
1978  break;
1979 
1980  case PLPGSQL_STMT_OPEN:
1981  rc = exec_stmt_open(estate, (PLpgSQL_stmt_open *) stmt);
1982  break;
1983 
1984  case PLPGSQL_STMT_FETCH:
1985  rc = exec_stmt_fetch(estate, (PLpgSQL_stmt_fetch *) stmt);
1986  break;
1987 
1988  case PLPGSQL_STMT_CLOSE:
1989  rc = exec_stmt_close(estate, (PLpgSQL_stmt_close *) stmt);
1990  break;
1991 
1992  case PLPGSQL_STMT_COMMIT:
1993  rc = exec_stmt_commit(estate, (PLpgSQL_stmt_commit *) stmt);
1994  break;
1995 
1996  case PLPGSQL_STMT_ROLLBACK:
1997  rc = exec_stmt_rollback(estate, (PLpgSQL_stmt_rollback *) stmt);
1998  break;
1999 
2000  default:
2001  estate->err_stmt = save_estmt;
2002  elog(ERROR, "unrecognized cmdtype: %d", stmt->cmd_type);
2003  }
2004 
2005  /* Let the plugin know that we have finished executing this statement */
2006  if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
2007  ((*plpgsql_plugin_ptr)->stmt_end) (estate, stmt);
2008 
2009  estate->err_stmt = save_estmt;
2010 
2011  return rc;
2012 }
static int exec_stmt_execsql(PLpgSQL_execstate *estate, PLpgSQL_stmt_execsql *stmt)
Definition: pl_exec.c:3805
static int exec_stmt_case(PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
Definition: pl_exec.c:2200
PLpgSQL_stmt * err_stmt
Definition: plpgsql.h:1019
static int exec_stmt_return_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_return_query *stmt)
Definition: pl_exec.c:3196
static int exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt)
Definition: pl_exec.c:2647
static int exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
Definition: pl_exec.c:4233
static int exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
Definition: pl_exec.c:4206
static int exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
Definition: pl_exec.c:2286
static int exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
Definition: pl_exec.c:2482
static int exec_stmt_assign(PLpgSQL_execstate *estate, PLpgSQL_stmt_assign *stmt)
Definition: pl_exec.c:2021
#define ERROR
Definition: elog.h:43
static int exec_stmt_rollback(PLpgSQL_execstate *estate, PLpgSQL_stmt_rollback *stmt)
Definition: pl_exec.c:4549
static int exec_stmt_assert(PLpgSQL_execstate *estate, PLpgSQL_stmt_assert *stmt)
Definition: pl_exec.c:3536
static int exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
Definition: pl_exec.c:3325
static int exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
Definition: pl_exec.c:2339
static int exec_stmt_dynexecute(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynexecute *stmt)
Definition: pl_exec.c:4017
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:2054
static int exec_stmt_exit(PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt)
Definition: pl_exec.c:2803
static int exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
Definition: pl_exec.c:2836
static int exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
Definition: pl_exec.c:2308
static int exec_stmt_commit(PLpgSQL_execstate *estate, PLpgSQL_stmt_commit *stmt)
Definition: pl_exec.c:4523
static int exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
Definition: pl_exec.c:4389
static int exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
Definition: pl_exec.c:1520
static int exec_stmt_return_next(PLpgSQL_execstate *estate, PLpgSQL_stmt_return_next *stmt)
Definition: pl_exec.c:2978
static int exec_stmt_close(PLpgSQL_execstate *estate, PLpgSQL_stmt_close *stmt)
Definition: pl_exec.c:4480
static int exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
Definition: pl_exec.c:2170
static int exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
Definition: pl_exec.c:2037
PLpgSQL_stmt_type cmd_type
Definition: plpgsql.h:442
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
void(* stmt_end)(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
Definition: plpgsql.h:1062
#define elog
Definition: elog.h:219
void(* stmt_beg)(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
Definition: plpgsql.h:1061
static int exec_stmt_forc(PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt)
Definition: pl_exec.c:2511

◆ exec_stmt_assert()

static int exec_stmt_assert ( PLpgSQL_execstate estate,
PLpgSQL_stmt_assert stmt 
)
static

Definition at line 3536 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().

3537 {
3538  bool value;
3539  bool isnull;
3540 
3541  /* do nothing when asserts are not enabled */
3542  if (!plpgsql_check_asserts)
3543  return PLPGSQL_RC_OK;
3544 
3545  value = exec_eval_boolean(estate, stmt->cond, &isnull);
3546  exec_eval_cleanup(estate);
3547 
3548  if (isnull || !value)
3549  {
3550  char *message = NULL;
3551 
3552  if (stmt->message != NULL)
3553  {
3554  Datum val;
3555  Oid typeid;
3556  int32 typmod;
3557 
3558  val = exec_eval_expr(estate, stmt->message,
3559  &isnull, &typeid, &typmod);
3560  if (!isnull)
3561  message = convert_value_to_string(estate, val, typeid);
3562  /* we mustn't do exec_eval_cleanup here */
3563  }
3564 
3565  ereport(ERROR,
3566  (errcode(ERRCODE_ASSERT_FAILURE),
3567  message ? errmsg_internal("%s", message) :
3568  errmsg("assertion failed")));
3569  }
3570 
3571  return PLPGSQL_RC_OK;
3572 }
static struct @130 value
int errcode(int sqlerrcode)
Definition: elog.c:575
static void exec_eval_cleanup(PLpgSQL_execstate *estate)
Definition: pl_exec.c:3724
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:302
#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:5435
PLpgSQL_expr * message
Definition: plpgsql.h:825
static bool exec_eval_boolean(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, bool *isNull)
Definition: pl_exec.c:5412
#define ereport(elevel, rest)
Definition: elog.h:122
uintptr_t Datum
Definition: postgres.h:365
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:7165
PLpgSQL_expr * cond
Definition: plpgsql.h:824
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 2021 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().

2022 {
2023  Assert(stmt->varno >= 0);
2024 
2025  exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);
2026 
2027  return PLPGSQL_RC_OK;
2028 }
PLpgSQL_datum ** datums
Definition: plpgsql.h:989
static void exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr)
Definition: pl_exec.c:4574
#define Assert(condition)
Definition: c.h:688
PLpgSQL_expr * expr
Definition: plpgsql.h:498

◆ exec_stmt_block()

static int exec_stmt_block ( PLpgSQL_execstate estate,
PLpgSQL_stmt_block block 
)
static

Definition at line 1520 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, TYPTYPE_DOMAIN, UNKNOWNOID, and unpack_sql_state().

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

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

◆ exec_stmt_case()

static int exec_stmt_case ( PLpgSQL_execstate estate,
PLpgSQL_stmt_case stmt 
)
static

Definition at line 2200 of file pl_exec.c.

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

Referenced by exec_stmt().

2201 {
2202  PLpgSQL_var *t_var = NULL;
2203  bool isnull;
2204  ListCell *l;
2205 
2206  if (stmt->t_expr != NULL)
2207  {
2208  /* simple case */
2209  Datum t_val;
2210  Oid t_typoid;
2211  int32 t_typmod;
2212 
2213  t_val = exec_eval_expr(estate, stmt->t_expr,
2214  &isnull, &t_typoid, &t_typmod);
2215 
2216  t_var = (PLpgSQL_var *) estate->datums[stmt->t_varno];
2217 
2218  /*
2219  * When expected datatype is different from real, change it. Note that
2220  * what we're modifying here is an execution copy of the datum, so
2221  * this doesn't affect the originally stored function parse tree. (In
2222  * theory, if the expression datatype keeps changing during execution,
2223  * this could cause a function-lifespan memory leak. Doesn't seem
2224  * worth worrying about though.)
2225  */
2226  if (t_var->datatype->typoid != t_typoid ||
2227  t_var->datatype->atttypmod != t_typmod)
2228  t_var->datatype = plpgsql_build_datatype(t_typoid,
2229  t_typmod,
2230  estate->func->fn_input_collation);
2231 
2232  /* now we can assign to the variable */
2233  exec_assign_value(estate,
2234  (PLpgSQL_datum *) t_var,
2235  t_val,
2236  isnull,
2237  t_typoid,
2238  t_typmod);
2239 
2240  exec_eval_cleanup(estate);
2241  }
2242 
2243  /* Now search for a successful WHEN clause */
2244  foreach(l, stmt->case_when_list)
2245  {
2247  bool value;
2248 
2249  value = exec_eval_boolean(estate, cwt->expr, &isnull);
2250  exec_eval_cleanup(estate);