summaryrefslogtreecommitdiffstats
path: root/src/pl/plpgsql/src/plpgsql.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/pl/plpgsql/src/plpgsql.h')
-rw-r--r--src/pl/plpgsql/src/plpgsql.h1343
1 files changed, 1343 insertions, 0 deletions
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
new file mode 100644
index 0000000..2b6cda6
--- /dev/null
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -0,0 +1,1343 @@
+/*-------------------------------------------------------------------------
+ *
+ * plpgsql.h - Definitions for the PL/pgSQL
+ * procedural language
+ *
+ * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/pl/plpgsql/src/plpgsql.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef PLPGSQL_H
+#define PLPGSQL_H
+
+#include "access/xact.h"
+#include "commands/event_trigger.h"
+#include "commands/trigger.h"
+#include "executor/spi.h"
+#include "utils/expandedrecord.h"
+#include "utils/typcache.h"
+
+
+/**********************************************************************
+ * Definitions
+ **********************************************************************/
+
+/* define our text domain for translations */
+#undef TEXTDOMAIN
+#define TEXTDOMAIN PG_TEXTDOMAIN("plpgsql")
+
+#undef _
+#define _(x) dgettext(TEXTDOMAIN, x)
+
+/*
+ * Compiler's namespace item types
+ */
+typedef enum PLpgSQL_nsitem_type
+{
+ PLPGSQL_NSTYPE_LABEL, /* block label */
+ PLPGSQL_NSTYPE_VAR, /* scalar variable */
+ PLPGSQL_NSTYPE_REC /* composite variable */
+} PLpgSQL_nsitem_type;
+
+/*
+ * A PLPGSQL_NSTYPE_LABEL stack entry must be one of these types
+ */
+typedef enum PLpgSQL_label_type
+{
+ PLPGSQL_LABEL_BLOCK, /* DECLARE/BEGIN block */
+ PLPGSQL_LABEL_LOOP, /* looping construct */
+ PLPGSQL_LABEL_OTHER /* anything else */
+} PLpgSQL_label_type;
+
+/*
+ * Datum array node types
+ */
+typedef enum PLpgSQL_datum_type
+{
+ PLPGSQL_DTYPE_VAR,
+ PLPGSQL_DTYPE_ROW,
+ PLPGSQL_DTYPE_REC,
+ PLPGSQL_DTYPE_RECFIELD,
+ PLPGSQL_DTYPE_PROMISE
+} PLpgSQL_datum_type;
+
+/*
+ * DTYPE_PROMISE datums have these possible ways of computing the promise
+ */
+typedef enum PLpgSQL_promise_type
+{
+ PLPGSQL_PROMISE_NONE = 0, /* not a promise, or promise satisfied */
+ PLPGSQL_PROMISE_TG_NAME,
+ PLPGSQL_PROMISE_TG_WHEN,
+ PLPGSQL_PROMISE_TG_LEVEL,
+ PLPGSQL_PROMISE_TG_OP,
+ PLPGSQL_PROMISE_TG_RELID,
+ PLPGSQL_PROMISE_TG_TABLE_NAME,
+ PLPGSQL_PROMISE_TG_TABLE_SCHEMA,
+ PLPGSQL_PROMISE_TG_NARGS,
+ PLPGSQL_PROMISE_TG_ARGV,
+ PLPGSQL_PROMISE_TG_EVENT,
+ PLPGSQL_PROMISE_TG_TAG
+} PLpgSQL_promise_type;
+
+/*
+ * Variants distinguished in PLpgSQL_type structs
+ */
+typedef enum PLpgSQL_type_type
+{
+ PLPGSQL_TTYPE_SCALAR, /* scalar types and domains */
+ PLPGSQL_TTYPE_REC, /* composite types, including RECORD */
+ PLPGSQL_TTYPE_PSEUDO /* pseudotypes */
+} PLpgSQL_type_type;
+
+/*
+ * Execution tree node types
+ */
+typedef enum PLpgSQL_stmt_type
+{
+ PLPGSQL_STMT_BLOCK,
+ PLPGSQL_STMT_ASSIGN,
+ PLPGSQL_STMT_IF,
+ PLPGSQL_STMT_CASE,
+ PLPGSQL_STMT_LOOP,
+ PLPGSQL_STMT_WHILE,
+ PLPGSQL_STMT_FORI,
+ PLPGSQL_STMT_FORS,
+ PLPGSQL_STMT_FORC,
+ PLPGSQL_STMT_FOREACH_A,
+ PLPGSQL_STMT_EXIT,
+ PLPGSQL_STMT_RETURN,
+ PLPGSQL_STMT_RETURN_NEXT,
+ PLPGSQL_STMT_RETURN_QUERY,
+ PLPGSQL_STMT_RAISE,
+ PLPGSQL_STMT_ASSERT,
+ PLPGSQL_STMT_EXECSQL,
+ PLPGSQL_STMT_DYNEXECUTE,
+ PLPGSQL_STMT_DYNFORS,
+ PLPGSQL_STMT_GETDIAG,
+ PLPGSQL_STMT_OPEN,
+ PLPGSQL_STMT_FETCH,
+ PLPGSQL_STMT_CLOSE,
+ PLPGSQL_STMT_PERFORM,
+ PLPGSQL_STMT_CALL,
+ PLPGSQL_STMT_COMMIT,
+ PLPGSQL_STMT_ROLLBACK
+} PLpgSQL_stmt_type;
+
+/*
+ * Execution node return codes
+ */
+enum
+{
+ PLPGSQL_RC_OK,
+ PLPGSQL_RC_EXIT,
+ PLPGSQL_RC_RETURN,
+ PLPGSQL_RC_CONTINUE
+};
+
+/*
+ * GET DIAGNOSTICS information items
+ */
+typedef enum PLpgSQL_getdiag_kind
+{
+ PLPGSQL_GETDIAG_ROW_COUNT,
+ PLPGSQL_GETDIAG_CONTEXT,
+ PLPGSQL_GETDIAG_ERROR_CONTEXT,
+ PLPGSQL_GETDIAG_ERROR_DETAIL,
+ PLPGSQL_GETDIAG_ERROR_HINT,
+ PLPGSQL_GETDIAG_RETURNED_SQLSTATE,
+ PLPGSQL_GETDIAG_COLUMN_NAME,
+ PLPGSQL_GETDIAG_CONSTRAINT_NAME,
+ PLPGSQL_GETDIAG_DATATYPE_NAME,
+ PLPGSQL_GETDIAG_MESSAGE_TEXT,
+ PLPGSQL_GETDIAG_TABLE_NAME,
+ PLPGSQL_GETDIAG_SCHEMA_NAME
+} PLpgSQL_getdiag_kind;
+
+/*
+ * RAISE statement options
+ */
+typedef enum PLpgSQL_raise_option_type
+{
+ PLPGSQL_RAISEOPTION_ERRCODE,
+ PLPGSQL_RAISEOPTION_MESSAGE,
+ PLPGSQL_RAISEOPTION_DETAIL,
+ PLPGSQL_RAISEOPTION_HINT,
+ PLPGSQL_RAISEOPTION_COLUMN,
+ PLPGSQL_RAISEOPTION_CONSTRAINT,
+ PLPGSQL_RAISEOPTION_DATATYPE,
+ PLPGSQL_RAISEOPTION_TABLE,
+ PLPGSQL_RAISEOPTION_SCHEMA
+} PLpgSQL_raise_option_type;
+
+/*
+ * Behavioral modes for plpgsql variable resolution
+ */
+typedef enum PLpgSQL_resolve_option
+{
+ PLPGSQL_RESOLVE_ERROR, /* throw error if ambiguous */
+ PLPGSQL_RESOLVE_VARIABLE, /* prefer plpgsql var to table column */
+ PLPGSQL_RESOLVE_COLUMN /* prefer table column to plpgsql var */
+} PLpgSQL_resolve_option;
+
+
+/**********************************************************************
+ * Node and structure definitions
+ **********************************************************************/
+
+/*
+ * Postgres data type
+ */
+typedef struct PLpgSQL_type
+{
+ char *typname; /* (simple) name of the type */
+ Oid typoid; /* OID of the data type */
+ PLpgSQL_type_type ttype; /* PLPGSQL_TTYPE_ code */
+ int16 typlen; /* stuff copied from its pg_type entry */
+ bool typbyval;
+ char typtype;
+ Oid collation; /* from pg_type, but can be overridden */
+ bool typisarray; /* is "true" array, or domain over one */
+ int32 atttypmod; /* typmod (taken from someplace else) */
+ /* Remaining fields are used only for named composite types (not RECORD) */
+ TypeName *origtypname; /* type name as written by user */
+ TypeCacheEntry *tcache; /* typcache entry for composite type */
+ uint64 tupdesc_id; /* last-seen tupdesc identifier */
+} PLpgSQL_type;
+
+/*
+ * SQL Query to plan and execute
+ */
+typedef struct PLpgSQL_expr
+{
+ char *query; /* query string, verbatim from function body */
+ RawParseMode parseMode; /* raw_parser() mode to use */
+ SPIPlanPtr plan; /* plan, or NULL if not made yet */
+ Bitmapset *paramnos; /* all dnos referenced by this query */
+
+ /* function containing this expr (not set until we first parse query) */
+ struct PLpgSQL_function *func;
+
+ /* namespace chain visible to this expr */
+ struct PLpgSQL_nsitem *ns;
+
+ /* fields for "simple expression" fast-path execution: */
+ Expr *expr_simple_expr; /* NULL means not a simple expr */
+ Oid expr_simple_type; /* result type Oid, if simple */
+ int32 expr_simple_typmod; /* result typmod, if simple */
+ bool expr_simple_mutable; /* true if simple expr is mutable */
+
+ /*
+ * These fields are used to optimize assignments to expanded-datum
+ * variables. If this expression is the source of an assignment to a
+ * simple variable, target_param holds that variable's dno; else it's -1.
+ * If we match a Param within expr_simple_expr to such a variable, that
+ * Param's address is stored in expr_rw_param; then expression code
+ * generation will allow the value for that Param to be passed read/write.
+ */
+ int target_param; /* dno of assign target, or -1 if none */
+ Param *expr_rw_param; /* read/write Param within expr, if any */
+
+ /*
+ * If the expression was ever determined to be simple, we remember its
+ * CachedPlanSource and CachedPlan here. If expr_simple_plan_lxid matches
+ * current LXID, then we hold a refcount on expr_simple_plan in the
+ * current transaction. Otherwise we need to get one before re-using it.
+ */
+ CachedPlanSource *expr_simple_plansource; /* extracted from "plan" */
+ CachedPlan *expr_simple_plan; /* extracted from "plan" */
+ LocalTransactionId expr_simple_plan_lxid;
+
+ /*
+ * if expr is simple AND prepared in current transaction,
+ * expr_simple_state and expr_simple_in_use are valid. Test validity by
+ * seeing if expr_simple_lxid matches current LXID. (If not,
+ * expr_simple_state probably points at garbage!)
+ */
+ ExprState *expr_simple_state; /* eval tree for expr_simple_expr */
+ bool expr_simple_in_use; /* true if eval tree is active */
+ LocalTransactionId expr_simple_lxid;
+} PLpgSQL_expr;
+
+/*
+ * Generic datum array item
+ *
+ * PLpgSQL_datum is the common supertype for PLpgSQL_var, PLpgSQL_row,
+ * PLpgSQL_rec, and PLpgSQL_recfield.
+ */
+typedef struct PLpgSQL_datum
+{
+ PLpgSQL_datum_type dtype;
+ int dno;
+} PLpgSQL_datum;
+
+/*
+ * Scalar or composite variable
+ *
+ * The variants PLpgSQL_var, PLpgSQL_row, and PLpgSQL_rec share these
+ * fields.
+ */
+typedef struct PLpgSQL_variable
+{
+ PLpgSQL_datum_type dtype;
+ int dno;
+ char *refname;
+ int lineno;
+ bool isconst;
+ bool notnull;
+ PLpgSQL_expr *default_val;
+} PLpgSQL_variable;
+
+/*
+ * Scalar variable
+ *
+ * DTYPE_VAR and DTYPE_PROMISE datums both use this struct type.
+ * A PROMISE datum works exactly like a VAR datum for most purposes,
+ * but if it is read without having previously been assigned to, then
+ * a special "promised" value is computed and assigned to the datum
+ * before the read is performed. This technique avoids the overhead of
+ * computing the variable's value in cases where we expect that many
+ * functions will never read it.
+ */
+typedef struct PLpgSQL_var
+{
+ PLpgSQL_datum_type dtype;
+ int dno;
+ char *refname;
+ int lineno;
+ bool isconst;
+ bool notnull;
+ PLpgSQL_expr *default_val;
+ /* end of PLpgSQL_variable fields */
+
+ PLpgSQL_type *datatype;
+
+ /*
+ * Variables declared as CURSOR FOR <query> are mostly like ordinary
+ * scalar variables of type refcursor, but they have these additional
+ * properties:
+ */
+ PLpgSQL_expr *cursor_explicit_expr;
+ int cursor_explicit_argrow;
+ int cursor_options;
+
+ /* Fields below here can change at runtime */
+
+ Datum value;
+ bool isnull;
+ bool freeval;
+
+ /*
+ * The promise field records which "promised" value to assign if the
+ * promise must be honored. If it's a normal variable, or the promise has
+ * been fulfilled, this is PLPGSQL_PROMISE_NONE.
+ */
+ PLpgSQL_promise_type promise;
+} PLpgSQL_var;
+
+/*
+ * Row variable - this represents one or more variables that are listed in an
+ * INTO clause, FOR-loop targetlist, cursor argument list, etc. We also use
+ * a row to represent a function's OUT parameters when there's more than one.
+ *
+ * Note that there's no way to name the row as such from PL/pgSQL code,
+ * so many functions don't need to support these.
+ *
+ * That also means that there's no real name for the row variable, so we
+ * conventionally set refname to "(unnamed row)". We could leave it NULL,
+ * but it's too convenient to be able to assume that refname is valid in
+ * all variants of PLpgSQL_variable.
+ *
+ * isconst, notnull, and default_val are unsupported (and hence
+ * always zero/null) for a row. The member variables of a row should have
+ * been checked to be writable at compile time, so isconst is correctly set
+ * to false. notnull and default_val aren't applicable.
+ */
+typedef struct PLpgSQL_row
+{
+ PLpgSQL_datum_type dtype;
+ int dno;
+ char *refname;
+ int lineno;
+ bool isconst;
+ bool notnull;
+ PLpgSQL_expr *default_val;
+ /* end of PLpgSQL_variable fields */
+
+ /*
+ * rowtupdesc is only set up if we might need to convert the row into a
+ * composite datum, which currently only happens for OUT parameters.
+ * Otherwise it is NULL.
+ */
+ TupleDesc rowtupdesc;
+
+ int nfields;
+ char **fieldnames;
+ int *varnos;
+} PLpgSQL_row;
+
+/*
+ * Record variable (any composite type, including RECORD)
+ */
+typedef struct PLpgSQL_rec
+{
+ PLpgSQL_datum_type dtype;
+ int dno;
+ char *refname;
+ int lineno;
+ bool isconst;
+ bool notnull;
+ PLpgSQL_expr *default_val;
+ /* end of PLpgSQL_variable fields */
+
+ /*
+ * Note: for non-RECORD cases, we may from time to time re-look-up the
+ * composite type, using datatype->origtypname. That can result in
+ * changing rectypeid.
+ */
+
+ PLpgSQL_type *datatype; /* can be NULL, if rectypeid is RECORDOID */
+ Oid rectypeid; /* declared type of variable */
+ /* RECFIELDs for this record are chained together for easy access */
+ int firstfield; /* dno of first RECFIELD, or -1 if none */
+
+ /* Fields below here can change at runtime */
+
+ /* We always store record variables as "expanded" records */
+ ExpandedRecordHeader *erh;
+} PLpgSQL_rec;
+
+/*
+ * Field in record
+ */
+typedef struct PLpgSQL_recfield
+{
+ PLpgSQL_datum_type dtype;
+ int dno;
+ /* end of PLpgSQL_datum fields */
+
+ char *fieldname; /* name of field */
+ int recparentno; /* dno of parent record */
+ int nextfield; /* dno of next child, or -1 if none */
+ uint64 rectupledescid; /* record's tupledesc ID as of last lookup */
+ ExpandedRecordFieldInfo finfo; /* field's attnum and type info */
+ /* if rectupledescid == INVALID_TUPLEDESC_IDENTIFIER, finfo isn't valid */
+} PLpgSQL_recfield;
+
+/*
+ * Item in the compilers namespace tree
+ */
+typedef struct PLpgSQL_nsitem
+{
+ PLpgSQL_nsitem_type itemtype;
+
+ /*
+ * For labels, itemno is a value of enum PLpgSQL_label_type. For other
+ * itemtypes, itemno is the associated PLpgSQL_datum's dno.
+ */
+ int itemno;
+ struct PLpgSQL_nsitem *prev;
+ char name[FLEXIBLE_ARRAY_MEMBER]; /* nul-terminated string */
+} PLpgSQL_nsitem;
+
+/*
+ * Generic execution node
+ */
+typedef struct PLpgSQL_stmt
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+
+ /*
+ * Unique statement ID in this function (starting at 1; 0 is invalid/not
+ * set). This can be used by a profiler as the index for an array of
+ * per-statement metrics.
+ */
+ unsigned int stmtid;
+} PLpgSQL_stmt;
+
+/*
+ * One EXCEPTION condition name
+ */
+typedef struct PLpgSQL_condition
+{
+ int sqlerrstate; /* SQLSTATE code */
+ char *condname; /* condition name (for debugging) */
+ struct PLpgSQL_condition *next;
+} PLpgSQL_condition;
+
+/*
+ * EXCEPTION block
+ */
+typedef struct PLpgSQL_exception_block
+{
+ int sqlstate_varno;
+ int sqlerrm_varno;
+ List *exc_list; /* List of WHEN clauses */
+} PLpgSQL_exception_block;
+
+/*
+ * One EXCEPTION ... WHEN clause
+ */
+typedef struct PLpgSQL_exception
+{
+ int lineno;
+ PLpgSQL_condition *conditions;
+ List *action; /* List of statements */
+} PLpgSQL_exception;
+
+/*
+ * Block of statements
+ */
+typedef struct PLpgSQL_stmt_block
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ char *label;
+ List *body; /* List of statements */
+ int n_initvars; /* Length of initvarnos[] */
+ int *initvarnos; /* dnos of variables declared in this block */
+ PLpgSQL_exception_block *exceptions;
+} PLpgSQL_stmt_block;
+
+/*
+ * Assign statement
+ */
+typedef struct PLpgSQL_stmt_assign
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ int varno;
+ PLpgSQL_expr *expr;
+} PLpgSQL_stmt_assign;
+
+/*
+ * PERFORM statement
+ */
+typedef struct PLpgSQL_stmt_perform
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ PLpgSQL_expr *expr;
+} PLpgSQL_stmt_perform;
+
+/*
+ * CALL statement
+ */
+typedef struct PLpgSQL_stmt_call
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ PLpgSQL_expr *expr;
+ bool is_call;
+ PLpgSQL_variable *target;
+} PLpgSQL_stmt_call;
+
+/*
+ * COMMIT statement
+ */
+typedef struct PLpgSQL_stmt_commit
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ bool chain;
+} PLpgSQL_stmt_commit;
+
+/*
+ * ROLLBACK statement
+ */
+typedef struct PLpgSQL_stmt_rollback
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ bool chain;
+} PLpgSQL_stmt_rollback;
+
+/*
+ * GET DIAGNOSTICS item
+ */
+typedef struct PLpgSQL_diag_item
+{
+ PLpgSQL_getdiag_kind kind; /* id for diagnostic value desired */
+ int target; /* where to assign it */
+} PLpgSQL_diag_item;
+
+/*
+ * GET DIAGNOSTICS statement
+ */
+typedef struct PLpgSQL_stmt_getdiag
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ bool is_stacked; /* STACKED or CURRENT diagnostics area? */
+ List *diag_items; /* List of PLpgSQL_diag_item */
+} PLpgSQL_stmt_getdiag;
+
+/*
+ * IF statement
+ */
+typedef struct PLpgSQL_stmt_if
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ PLpgSQL_expr *cond; /* boolean expression for THEN */
+ List *then_body; /* List of statements */
+ List *elsif_list; /* List of PLpgSQL_if_elsif structs */
+ List *else_body; /* List of statements */
+} PLpgSQL_stmt_if;
+
+/*
+ * one ELSIF arm of IF statement
+ */
+typedef struct PLpgSQL_if_elsif
+{
+ int lineno;
+ PLpgSQL_expr *cond; /* boolean expression for this case */
+ List *stmts; /* List of statements */
+} PLpgSQL_if_elsif;
+
+/*
+ * CASE statement
+ */
+typedef struct PLpgSQL_stmt_case
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ PLpgSQL_expr *t_expr; /* test expression, or NULL if none */
+ int t_varno; /* var to store test expression value into */
+ List *case_when_list; /* List of PLpgSQL_case_when structs */
+ bool have_else; /* flag needed because list could be empty */
+ List *else_stmts; /* List of statements */
+} PLpgSQL_stmt_case;
+
+/*
+ * one arm of CASE statement
+ */
+typedef struct PLpgSQL_case_when
+{
+ int lineno;
+ PLpgSQL_expr *expr; /* boolean expression for this case */
+ List *stmts; /* List of statements */
+} PLpgSQL_case_when;
+
+/*
+ * Unconditional LOOP statement
+ */
+typedef struct PLpgSQL_stmt_loop
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ char *label;
+ List *body; /* List of statements */
+} PLpgSQL_stmt_loop;
+
+/*
+ * WHILE cond LOOP statement
+ */
+typedef struct PLpgSQL_stmt_while
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ char *label;
+ PLpgSQL_expr *cond;
+ List *body; /* List of statements */
+} PLpgSQL_stmt_while;
+
+/*
+ * FOR statement with integer loopvar
+ */
+typedef struct PLpgSQL_stmt_fori
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ char *label;
+ PLpgSQL_var *var;
+ PLpgSQL_expr *lower;
+ PLpgSQL_expr *upper;
+ PLpgSQL_expr *step; /* NULL means default (ie, BY 1) */
+ int reverse;
+ List *body; /* List of statements */
+} PLpgSQL_stmt_fori;
+
+/*
+ * PLpgSQL_stmt_forq represents a FOR statement running over a SQL query.
+ * It is the common supertype of PLpgSQL_stmt_fors, PLpgSQL_stmt_forc
+ * and PLpgSQL_stmt_dynfors.
+ */
+typedef struct PLpgSQL_stmt_forq
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ char *label;
+ PLpgSQL_variable *var; /* Loop variable (record or row) */
+ List *body; /* List of statements */
+} PLpgSQL_stmt_forq;
+
+/*
+ * FOR statement running over SELECT
+ */
+typedef struct PLpgSQL_stmt_fors
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ char *label;
+ PLpgSQL_variable *var; /* Loop variable (record or row) */
+ List *body; /* List of statements */
+ /* end of fields that must match PLpgSQL_stmt_forq */
+ PLpgSQL_expr *query;
+} PLpgSQL_stmt_fors;
+
+/*
+ * FOR statement running over cursor
+ */
+typedef struct PLpgSQL_stmt_forc
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ char *label;
+ PLpgSQL_variable *var; /* Loop variable (record or row) */
+ List *body; /* List of statements */
+ /* end of fields that must match PLpgSQL_stmt_forq */
+ int curvar;
+ PLpgSQL_expr *argquery; /* cursor arguments if any */
+} PLpgSQL_stmt_forc;
+
+/*
+ * FOR statement running over EXECUTE
+ */
+typedef struct PLpgSQL_stmt_dynfors
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ char *label;
+ PLpgSQL_variable *var; /* Loop variable (record or row) */
+ List *body; /* List of statements */
+ /* end of fields that must match PLpgSQL_stmt_forq */
+ PLpgSQL_expr *query;
+ List *params; /* USING expressions */
+} PLpgSQL_stmt_dynfors;
+
+/*
+ * FOREACH item in array loop
+ */
+typedef struct PLpgSQL_stmt_foreach_a
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ char *label;
+ int varno; /* loop target variable */
+ int slice; /* slice dimension, or 0 */
+ PLpgSQL_expr *expr; /* array expression */
+ List *body; /* List of statements */
+} PLpgSQL_stmt_foreach_a;
+
+/*
+ * OPEN a curvar
+ */
+typedef struct PLpgSQL_stmt_open
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ int curvar;
+ int cursor_options;
+ PLpgSQL_expr *argquery;
+ PLpgSQL_expr *query;
+ PLpgSQL_expr *dynquery;
+ List *params; /* USING expressions */
+} PLpgSQL_stmt_open;
+
+/*
+ * FETCH or MOVE statement
+ */
+typedef struct PLpgSQL_stmt_fetch
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ PLpgSQL_variable *target; /* target (record or row) */
+ int curvar; /* cursor variable to fetch from */
+ FetchDirection direction; /* fetch direction */
+ long how_many; /* count, if constant (expr is NULL) */
+ PLpgSQL_expr *expr; /* count, if expression */
+ bool is_move; /* is this a fetch or move? */
+ bool returns_multiple_rows; /* can return more than one row? */
+} PLpgSQL_stmt_fetch;
+
+/*
+ * CLOSE curvar
+ */
+typedef struct PLpgSQL_stmt_close
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ int curvar;
+} PLpgSQL_stmt_close;
+
+/*
+ * EXIT or CONTINUE statement
+ */
+typedef struct PLpgSQL_stmt_exit
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ bool is_exit; /* Is this an exit or a continue? */
+ char *label; /* NULL if it's an unlabeled EXIT/CONTINUE */
+ PLpgSQL_expr *cond;
+} PLpgSQL_stmt_exit;
+
+/*
+ * RETURN statement
+ */
+typedef struct PLpgSQL_stmt_return
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ PLpgSQL_expr *expr;
+ int retvarno;
+} PLpgSQL_stmt_return;
+
+/*
+ * RETURN NEXT statement
+ */
+typedef struct PLpgSQL_stmt_return_next
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ PLpgSQL_expr *expr;
+ int retvarno;
+} PLpgSQL_stmt_return_next;
+
+/*
+ * RETURN QUERY statement
+ */
+typedef struct PLpgSQL_stmt_return_query
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ PLpgSQL_expr *query; /* if static query */
+ PLpgSQL_expr *dynquery; /* if dynamic query (RETURN QUERY EXECUTE) */
+ List *params; /* USING arguments for dynamic query */
+} PLpgSQL_stmt_return_query;
+
+/*
+ * RAISE statement
+ */
+typedef struct PLpgSQL_stmt_raise
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ int elog_level;
+ char *condname; /* condition name, SQLSTATE, or NULL */
+ char *message; /* old-style message format literal, or NULL */
+ List *params; /* list of expressions for old-style message */
+ List *options; /* list of PLpgSQL_raise_option */
+} PLpgSQL_stmt_raise;
+
+/*
+ * RAISE statement option
+ */
+typedef struct PLpgSQL_raise_option
+{
+ PLpgSQL_raise_option_type opt_type;
+ PLpgSQL_expr *expr;
+} PLpgSQL_raise_option;
+
+/*
+ * ASSERT statement
+ */
+typedef struct PLpgSQL_stmt_assert
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ PLpgSQL_expr *cond;
+ PLpgSQL_expr *message;
+} PLpgSQL_stmt_assert;
+
+/*
+ * Generic SQL statement to execute
+ */
+typedef struct PLpgSQL_stmt_execsql
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ PLpgSQL_expr *sqlstmt;
+ bool mod_stmt; /* is the stmt INSERT/UPDATE/DELETE/MERGE? */
+ bool mod_stmt_set; /* is mod_stmt valid yet? */
+ bool into; /* INTO supplied? */
+ bool strict; /* INTO STRICT flag */
+ PLpgSQL_variable *target; /* INTO target (record or row) */
+} PLpgSQL_stmt_execsql;
+
+/*
+ * Dynamic SQL string to execute
+ */
+typedef struct PLpgSQL_stmt_dynexecute
+{
+ PLpgSQL_stmt_type cmd_type;
+ int lineno;
+ unsigned int stmtid;
+ PLpgSQL_expr *query; /* string expression */
+ bool into; /* INTO supplied? */
+ bool strict; /* INTO STRICT flag */
+ PLpgSQL_variable *target; /* INTO target (record or row) */
+ List *params; /* USING expressions */
+} PLpgSQL_stmt_dynexecute;
+
+/*
+ * Hash lookup key for functions
+ */
+typedef struct PLpgSQL_func_hashkey
+{
+ Oid funcOid;
+
+ bool isTrigger; /* true if called as a DML trigger */
+ bool isEventTrigger; /* true if called as an event trigger */
+
+ /* be careful that pad bytes in this struct get zeroed! */
+
+ /*
+ * For a trigger function, the OID of the trigger is part of the hash key
+ * --- we want to compile the trigger function separately for each trigger
+ * it is used with, in case the rowtype or transition table names are
+ * different. Zero if not called as a DML trigger.
+ */
+ Oid trigOid;
+
+ /*
+ * We must include the input collation as part of the hash key too,
+ * because we have to generate different plans (with different Param
+ * collations) for different collation settings.
+ */
+ Oid inputCollation;
+
+ /*
+ * We include actual argument types in the hash key to support polymorphic
+ * PLpgSQL functions. Be careful that extra positions are zeroed!
+ */
+ Oid argtypes[FUNC_MAX_ARGS];
+} PLpgSQL_func_hashkey;
+
+/*
+ * Trigger type
+ */
+typedef enum PLpgSQL_trigtype
+{
+ PLPGSQL_DML_TRIGGER,
+ PLPGSQL_EVENT_TRIGGER,
+ PLPGSQL_NOT_TRIGGER
+} PLpgSQL_trigtype;
+
+/*
+ * Complete compiled function
+ */
+typedef struct PLpgSQL_function
+{
+ char *fn_signature;
+ Oid fn_oid;
+ TransactionId fn_xmin;
+ ItemPointerData fn_tid;
+ PLpgSQL_trigtype fn_is_trigger;
+ Oid fn_input_collation;
+ PLpgSQL_func_hashkey *fn_hashkey; /* back-link to hashtable key */
+ MemoryContext fn_cxt;
+
+ Oid fn_rettype;
+ int fn_rettyplen;
+ bool fn_retbyval;
+ bool fn_retistuple;
+ bool fn_retisdomain;
+ bool fn_retset;
+ bool fn_readonly;
+ char fn_prokind;
+
+ int fn_nargs;
+ int fn_argvarnos[FUNC_MAX_ARGS];
+ int out_param_varno;
+ int found_varno;
+ int new_varno;
+ int old_varno;
+
+ PLpgSQL_resolve_option resolve_option;
+
+ bool print_strict_params;
+
+ /* extra checks */
+ int extra_warnings;
+ int extra_errors;
+
+ /* the datums representing the function's local variables */
+ int ndatums;
+ PLpgSQL_datum **datums;
+ Size copiable_size; /* space for locally instantiated datums */
+
+ /* function body parsetree */
+ PLpgSQL_stmt_block *action;
+
+ /* data derived while parsing body */
+ unsigned int nstatements; /* counter for assigning stmtids */
+ bool requires_procedure_resowner; /* contains CALL or DO? */
+
+ /* these fields change when the function is used */
+ struct PLpgSQL_execstate *cur_estate;
+ unsigned long use_count;
+} PLpgSQL_function;
+
+/*
+ * Runtime execution data
+ */
+typedef struct PLpgSQL_execstate
+{
+ PLpgSQL_function *func; /* function being executed */
+
+ TriggerData *trigdata; /* if regular trigger, data about firing */
+ EventTriggerData *evtrigdata; /* if event trigger, data about firing */
+
+ Datum retval;
+ bool retisnull;
+ Oid rettype; /* type of current retval */
+
+ Oid fn_rettype; /* info about declared function rettype */
+ bool retistuple;
+ bool retisset;
+
+ bool readonly_func;
+ bool atomic;
+
+ char *exitlabel; /* the "target" label of the current EXIT or
+ * CONTINUE stmt, if any */
+ ErrorData *cur_error; /* current exception handler's error */
+
+ Tuplestorestate *tuple_store; /* SRFs accumulate results here */
+ TupleDesc tuple_store_desc; /* descriptor for tuples in tuple_store */
+ MemoryContext tuple_store_cxt;
+ ResourceOwner tuple_store_owner;
+ ReturnSetInfo *rsi;
+
+ int found_varno;
+
+ /*
+ * The datums representing the function's local variables. Some of these
+ * are local storage in this execstate, but some just point to the shared
+ * copy belonging to the PLpgSQL_function, depending on whether or not we
+ * need any per-execution state for the datum's dtype.
+ */
+ int ndatums;
+ PLpgSQL_datum **datums;
+ /* context containing variable values (same as func's SPI_proc context) */
+ MemoryContext datum_context;
+
+ /*
+ * paramLI is what we use to pass local variable values to the executor.
+ * It does not have a ParamExternData array; we just dynamically
+ * instantiate parameter data as needed. By convention, PARAM_EXTERN
+ * Params have paramid equal to the dno of the referenced local variable.
+ */
+ ParamListInfo paramLI;
+
+ /* EState and resowner to use for "simple" expression evaluation */
+ EState *simple_eval_estate;
+ ResourceOwner simple_eval_resowner;
+
+ /* if running nonatomic procedure or DO block, resowner to use for CALL */
+ ResourceOwner procedure_resowner;
+
+ /* lookup table to use for executing type casts */
+ HTAB *cast_hash;
+ MemoryContext cast_hash_context; /* not used; now always NULL */
+
+ /* memory context for statement-lifespan temporary values */
+ MemoryContext stmt_mcontext; /* current stmt context, or NULL if none */
+ MemoryContext stmt_mcontext_parent; /* parent of current context */
+
+ /* temporary state for results from evaluation of query or expr */
+ SPITupleTable *eval_tuptable;
+ uint64 eval_processed;
+ ExprContext *eval_econtext; /* for executing simple expressions */
+
+ /* status information for error context reporting */
+ PLpgSQL_stmt *err_stmt; /* current stmt */
+ PLpgSQL_variable *err_var; /* current variable, if in a DECLARE section */
+ const char *err_text; /* additional state info */
+
+ void *plugin_info; /* reserved for use by optional plugin */
+} PLpgSQL_execstate;
+
+/*
+ * A PLpgSQL_plugin structure represents an instrumentation plugin.
+ * To instrument PL/pgSQL, a plugin library must access the rendezvous
+ * variable "PLpgSQL_plugin" and set it to point to a PLpgSQL_plugin struct.
+ * Typically the struct could just be static data in the plugin library.
+ * We expect that a plugin would do this at library load time (_PG_init()).
+ *
+ * This structure is basically a collection of function pointers --- at
+ * various interesting points in pl_exec.c, we call these functions
+ * (if the pointers are non-NULL) to give the plugin a chance to watch
+ * what we are doing.
+ *
+ * func_setup is called when we start a function, before we've initialized
+ * the local variables defined by the function.
+ *
+ * func_beg is called when we start a function, after we've initialized
+ * the local variables.
+ *
+ * func_end is called at the end of a function.
+ *
+ * stmt_beg and stmt_end are called before and after (respectively) each
+ * statement.
+ *
+ * Also, immediately before any call to func_setup, PL/pgSQL fills in the
+ * remaining fields with pointers to some of its own functions, allowing the
+ * plugin to invoke those functions conveniently. The exposed functions are:
+ * plpgsql_exec_error_callback
+ * exec_assign_expr
+ * exec_assign_value
+ * exec_eval_datum
+ * exec_cast_value
+ * (plpgsql_exec_error_callback is not actually meant to be called by the
+ * plugin, but rather to allow it to identify PL/pgSQL error context stack
+ * frames. The others are useful for debugger-like plugins to examine and
+ * set variables.)
+ */
+typedef struct PLpgSQL_plugin
+{
+ /* Function pointers set up by the plugin */
+ void (*func_setup) (PLpgSQL_execstate *estate, PLpgSQL_function *func);
+ void (*func_beg) (PLpgSQL_execstate *estate, PLpgSQL_function *func);
+ void (*func_end) (PLpgSQL_execstate *estate, PLpgSQL_function *func);
+ void (*stmt_beg) (PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt);
+ void (*stmt_end) (PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt);
+
+ /* Function pointers set by PL/pgSQL itself */
+ void (*error_callback) (void *arg);
+ void (*assign_expr) (PLpgSQL_execstate *estate,
+ PLpgSQL_datum *target,
+ PLpgSQL_expr *expr);
+ void (*assign_value) (PLpgSQL_execstate *estate,
+ PLpgSQL_datum *target,
+ Datum value, bool isNull,
+ Oid valtype, int32 valtypmod);
+ void (*eval_datum) (PLpgSQL_execstate *estate, PLpgSQL_datum *datum,
+ Oid *typeId, int32 *typetypmod,
+ Datum *value, bool *isnull);
+ Datum (*cast_value) (PLpgSQL_execstate *estate,
+ Datum value, bool *isnull,
+ Oid valtype, int32 valtypmod,
+ Oid reqtype, int32 reqtypmod);
+} PLpgSQL_plugin;
+
+/*
+ * Struct types used during parsing
+ */
+
+typedef struct PLword
+{
+ char *ident; /* palloc'd converted identifier */
+ bool quoted; /* Was it double-quoted? */
+} PLword;
+
+typedef struct PLcword
+{
+ List *idents; /* composite identifiers (list of String) */
+} PLcword;
+
+typedef struct PLwdatum
+{
+ PLpgSQL_datum *datum; /* referenced variable */
+ char *ident; /* valid if simple name */
+ bool quoted;
+ List *idents; /* valid if composite name */
+} PLwdatum;
+
+/**********************************************************************
+ * Global variable declarations
+ **********************************************************************/
+
+typedef enum
+{
+ IDENTIFIER_LOOKUP_NORMAL, /* normal processing of var names */
+ IDENTIFIER_LOOKUP_DECLARE, /* In DECLARE --- don't look up names */
+ IDENTIFIER_LOOKUP_EXPR /* In SQL expression --- special case */
+} IdentifierLookup;
+
+extern IdentifierLookup plpgsql_IdentifierLookup;
+
+extern int plpgsql_variable_conflict;
+
+extern bool plpgsql_print_strict_params;
+
+extern bool plpgsql_check_asserts;
+
+/* extra compile-time and run-time checks */
+#define PLPGSQL_XCHECK_NONE 0
+#define PLPGSQL_XCHECK_SHADOWVAR (1 << 1)
+#define PLPGSQL_XCHECK_TOOMANYROWS (1 << 2)
+#define PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT (1 << 3)
+#define PLPGSQL_XCHECK_ALL ((int) ~0)
+
+extern int plpgsql_extra_warnings;
+extern int plpgsql_extra_errors;
+
+extern bool plpgsql_check_syntax;
+extern bool plpgsql_DumpExecTree;
+
+extern PLpgSQL_stmt_block *plpgsql_parse_result;
+
+extern int plpgsql_nDatums;
+extern PLpgSQL_datum **plpgsql_Datums;
+
+extern char *plpgsql_error_funcname;
+
+extern PLpgSQL_function *plpgsql_curr_compile;
+extern MemoryContext plpgsql_compile_tmp_cxt;
+
+extern PLpgSQL_plugin **plpgsql_plugin_ptr;
+
+/**********************************************************************
+ * Function declarations
+ **********************************************************************/
+
+/*
+ * Functions in pl_comp.c
+ */
+extern PLpgSQL_function *plpgsql_compile(FunctionCallInfo fcinfo,
+ bool forValidator);
+extern PLpgSQL_function *plpgsql_compile_inline(char *proc_source);
+extern void plpgsql_parser_setup(struct ParseState *pstate,
+ PLpgSQL_expr *expr);
+extern bool plpgsql_parse_word(char *word1, const char *yytxt, bool lookup,
+ PLwdatum *wdatum, PLword *word);
+extern bool plpgsql_parse_dblword(char *word1, char *word2,
+ PLwdatum *wdatum, PLcword *cword);
+extern bool plpgsql_parse_tripword(char *word1, char *word2, char *word3,
+ PLwdatum *wdatum, PLcword *cword);
+extern PLpgSQL_type *plpgsql_parse_wordtype(char *ident);
+extern PLpgSQL_type *plpgsql_parse_cwordtype(List *idents);
+extern PLpgSQL_type *plpgsql_parse_wordrowtype(char *ident);
+extern PLpgSQL_type *plpgsql_parse_cwordrowtype(List *idents);
+extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod,
+ Oid collation,
+ TypeName *origtypname);
+extern PLpgSQL_variable *plpgsql_build_variable(const char *refname, int lineno,
+ PLpgSQL_type *dtype,
+ bool add2namespace);
+extern PLpgSQL_rec *plpgsql_build_record(const char *refname, int lineno,
+ PLpgSQL_type *dtype, Oid rectypeid,
+ bool add2namespace);
+extern PLpgSQL_recfield *plpgsql_build_recfield(PLpgSQL_rec *rec,
+ const char *fldname);
+extern int plpgsql_recognize_err_condition(const char *condname,
+ bool allow_sqlstate);
+extern PLpgSQL_condition *plpgsql_parse_err_condition(char *condname);
+extern void plpgsql_adddatum(PLpgSQL_datum *newdatum);
+extern int plpgsql_add_initdatums(int **varnos);
+extern void plpgsql_HashTableInit(void);
+
+/*
+ * Functions in pl_handler.c
+ */
+extern void _PG_init(void);
+
+/*
+ * Functions in pl_exec.c
+ */
+extern Datum plpgsql_exec_function(PLpgSQL_function *func,
+ FunctionCallInfo fcinfo,
+ EState *simple_eval_estate,
+ ResourceOwner simple_eval_resowner,
+ ResourceOwner procedure_resowner,
+ bool atomic);
+extern HeapTuple plpgsql_exec_trigger(PLpgSQL_function *func,
+ TriggerData *trigdata);
+extern void plpgsql_exec_event_trigger(PLpgSQL_function *func,
+ EventTriggerData *trigdata);
+extern void plpgsql_xact_cb(XactEvent event, void *arg);
+extern void plpgsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid,
+ SubTransactionId parentSubid, void *arg);
+extern Oid plpgsql_exec_get_datum_type(PLpgSQL_execstate *estate,
+ PLpgSQL_datum *datum);
+extern void plpgsql_exec_get_datum_type_info(PLpgSQL_execstate *estate,
+ PLpgSQL_datum *datum,
+ Oid *typeId, int32 *typMod,
+ Oid *collation);
+
+/*
+ * Functions for namespace handling in pl_funcs.c
+ */
+extern void plpgsql_ns_init(void);
+extern void plpgsql_ns_push(const char *label,
+ PLpgSQL_label_type label_type);
+extern void plpgsql_ns_pop(void);
+extern PLpgSQL_nsitem *plpgsql_ns_top(void);
+extern void plpgsql_ns_additem(PLpgSQL_nsitem_type itemtype, int itemno, const char *name);
+extern PLpgSQL_nsitem *plpgsql_ns_lookup(PLpgSQL_nsitem *ns_cur, bool localmode,
+ const char *name1, const char *name2,
+ const char *name3, int *names_used);
+extern PLpgSQL_nsitem *plpgsql_ns_lookup_label(PLpgSQL_nsitem *ns_cur,
+ const char *name);
+extern PLpgSQL_nsitem *plpgsql_ns_find_nearest_loop(PLpgSQL_nsitem *ns_cur);
+
+/*
+ * Other functions in pl_funcs.c
+ */
+extern const char *plpgsql_stmt_typename(PLpgSQL_stmt *stmt);
+extern const char *plpgsql_getdiag_kindname(PLpgSQL_getdiag_kind kind);
+extern void plpgsql_free_function_memory(PLpgSQL_function *func);
+extern void plpgsql_dumptree(PLpgSQL_function *func);
+
+/*
+ * Scanner functions in pl_scanner.c
+ */
+extern int plpgsql_base_yylex(void);
+extern int plpgsql_yylex(void);
+extern void plpgsql_push_back_token(int token);
+extern bool plpgsql_token_is_unreserved_keyword(int token);
+extern void plpgsql_append_source_text(StringInfo buf,
+ int startlocation, int endlocation);
+extern int plpgsql_peek(void);
+extern void plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc,
+ int *tok2_loc);
+extern int plpgsql_scanner_errposition(int location);
+extern void plpgsql_yyerror(const char *message) pg_attribute_noreturn();
+extern int plpgsql_location_to_lineno(int location);
+extern int plpgsql_latest_lineno(void);
+extern void plpgsql_scanner_init(const char *str);
+extern void plpgsql_scanner_finish(void);
+
+/*
+ * Externs in gram.y
+ */
+extern int plpgsql_yyparse(void);
+
+#endif /* PLPGSQL_H */