/*--------------------------------------------------------------------------------------- * * plpgsql.h * Definitions for the PL/pgSQL procedural language * * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * Portions Copyright (c) 2021, openGauss Contributors * IDENTIFICATION * src/include/utils/plpgsql.h * * --------------------------------------------------------------------------------------- */ #ifndef PLPGSQL_H #define PLPGSQL_H #include "postgres.h" #include "knl/knl_variable.h" #include "access/xact.h" #include "catalog/namespace.h" #include "catalog/pg_proc.h" #include "commands/trigger.h" #include "commands/event_trigger.h" #include "executor/spi.h" #include "executor/functions.h" #include "parser/scanner.h" #include "utils/pl_global_package_runtime_cache.h" /********************************************************************** * Definitions **********************************************************************/ #define TABLEOFINDEXBUCKETNUM 128 #define MAX_INT32_LEN 11 #define GSPLSQL_LOCKED_HTAB_SIZE 128 /* * Compile status mark */ enum { /* compile new function */ COMPILIE_FUNC, /* compile new package */ COMPILIE_PKG, /* compile new function in package */ COMPILIE_PKG_FUNC, /* compile anonyous block in package */ COMPILIE_PKG_ANON_BLOCK, /* compile anonyous block's func in package */ COMPILIE_PKG_ANON_BLOCK_FUNC, /* compile anonyous block */ COMPILIE_ANON_BLOCK, NONE_STATUS }; /* ---------- * Compiler's namespace item types * ---------- */ enum { PLPGSQL_NSTYPE_LABEL, PLPGSQL_NSTYPE_VAR, PLPGSQL_NSTYPE_ROW, PLPGSQL_NSTYPE_REC, PLPGSQL_NSTYPE_RECORD, PLPGSQL_NSTYPE_REFCURSOR, PLPGSQL_NSTYPE_VARRAY, PLPGSQL_NSTYPE_TABLE, PLPGSQL_NSTYPE_PROC, PLPGSQL_NSTYPE_UNKNOWN, PLPGSQL_NSTYPE_COMPOSITE, PLPGSQL_NSTYPE_GOTO_LABEL, PLPGSQL_NSTYPE_CURSORROW, PLPGSQL_NSTYPE_SUBTYPE }; /* ---------- * Datum array node types * ---------- */ enum { PLPGSQL_DTYPE_VAR, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECORD, /* record variable */ PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ARRAYELEM, PLPGSQL_DTYPE_TABLEELEM, PLPGSQL_DTYPE_EXPR, PLPGSQL_DTYPE_UNKNOWN, PLPGSQL_DTYPE_VARRAY, PLPGSQL_DTYPE_TABLE, PLPGSQL_DTYPE_ASSIGNLIST, PLPGSQL_DTYPE_COMPOSITE, /* composite type */ PLPGSQL_DTYPE_RECORD_TYPE, /* record type */ PLPGSQL_DTYPE_CURSORROW, PLPGSQL_DTYPE_SUBTYPE }; /* ---------- * Compile status * ---------- */ enum { PLPGSQL_COMPILE_PACKAGE, PLPGSQL_COMPILE_PROC, PLPGSQL_COMPILE_PACKAGE_PROC, PLPGSQL_COMPILE_NULL }; /* ---------- * drop status * ---------- */ enum { PLPGSQL_PACKAGE, PLPGSQL_PACKAGE_BODY, PLPGSQL_PROC }; // enums token flag enum { PLPGSQL_TOK_REFCURSOR, PLPGSQL_TOK_VARRAY, PLPGSQL_TOK_VARRAY_FIRST, PLPGSQL_TOK_VARRAY_LAST, PLPGSQL_TOK_VARRAY_COUNT, PLPGSQL_TOK_VARRAY_EXTEND, PLPGSQL_TOK_VARRAY_EXISTS, PLPGSQL_TOK_VARRAY_PRIOR, PLPGSQL_TOK_VARRAY_NEXT, PLPGSQL_TOK_VARRAY_DELETE, PLPGSQL_TOK_VARRAY_TRIM, PLPGSQL_TOK_VARRAY_VAR, PLPGSQL_TOK_TABLE, PLPGSQL_TOK_TABLE_VAR, PLPGSQL_TOK_RECORD, PLPGSQL_TOK_PACKAGE_VARIABLE, PLPGSQL_TOK_OBJECT_TYPE_VAR_METHOD }; /* ---------- * Variants distinguished in PLpgSQL_type structs * ---------- */ enum { PLPGSQL_TTYPE_SCALAR, /* scalar types and domains */ PLPGSQL_TTYPE_ROW, /* composite types */ PLPGSQL_TTYPE_REC, /* RECORD pseudotype */ PLPGSQL_TTYPE_RECORD, /* RECORD pseudotype complitable A db */ PLPGSQL_TTYPE_PSEUDO, /* other pseudotypes */ PLPGSQL_TTYPE_CURSORROW }; /* ---------- * distinguish array and table in PLpgSQL_type structs * ---------- */ enum { PLPGSQL_COLLECTION_NONE = 0, PLPGSQL_COLLECTION_ARRAY, PLPGSQL_COLLECTION_TABLE }; /* ---------- * Execution tree node types * ---------- */ enum PLpgSQL_stmt_types { PLPGSQL_STMT_BLOCK, PLPGSQL_STMT_ASSIGN, PLPGSQL_STMT_IF, PLPGSQL_STMT_GOTO, 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_EXECSQL, PLPGSQL_STMT_DYNEXECUTE, PLPGSQL_STMT_DYNFORS, PLPGSQL_STMT_GETDIAG, PLPGSQL_STMT_OPEN, PLPGSQL_STMT_FETCH, PLPGSQL_STMT_CLOSE, PLPGSQL_STMT_PERFORM, PLPGSQL_STMT_COMMIT, PLPGSQL_STMT_ROLLBACK, PLPGSQL_STMT_NULL, PLPGSQL_STMT_SAVEPOINT, PLPGSQL_STMT_SIGNAL, PLPGSQL_STMT_RESIGNAL, PLPGSQL_STMT_PIPE_ROW }; /* ---------- * Execution node return codes * ---------- */ enum { PLPGSQL_RC_OK, PLPGSQL_RC_EXIT, PLPGSQL_RC_RETURN, PLPGSQL_RC_CONTINUE, PLPGSQL_RC_GOTO_UNRESOLVED }; /* ---------- * GET DIAGNOSTICS information items * ---------- */ enum { PLPGSQL_GETDIAG_ROW_COUNT, PLPGSQL_GETDIAG_RESULT_OID, PLPGSQL_GETDIAG_ERROR_CONTEXT, PLPGSQL_GETDIAG_ERROR_DETAIL, PLPGSQL_GETDIAG_ERROR_HINT, PLPGSQL_GETDIAG_RETURNED_SQLSTATE, PLPGSQL_GETDIAG_MESSAGE_TEXT, PLPGSQL_GETDIAG_B_NUMBER, PLPGSQL_GETDIAG_B_CLASS_ORIGIN, PLPGSQL_GETDIAG_B_SUBCLASS_ORIGIN, PLPGSQL_GETDIAG_B_CONSTRAINT_CATALOG, PLPGSQL_GETDIAG_B_CONSTRAINT_SCHEMA, PLPGSQL_GETDIAG_B_CONSTRAINT_NAME, PLPGSQL_GETDIAG_B_CATALOG_NAME, PLPGSQL_GETDIAG_B_SCHEMA_NAME, PLPGSQL_GETDIAG_B_TABLE_NAME, PLPGSQL_GETDIAG_B_COLUMN_NAME, PLPGSQL_GETDIAG_B_CURSOR_NAME, PLPGSQL_GETDIAG_B_MESSAGE_TEXT, PLPGSQL_GETDIAG_B_MYSQL_ERRNO, PLPGSQL_GETDIAG_B_RETURNED_SQLSTATE }; /* -------- * RAISE statement options * -------- */ enum { PLPGSQL_RAISEOPTION_ERRCODE, PLPGSQL_RAISEOPTION_MESSAGE, PLPGSQL_RAISEOPTION_DETAIL, PLPGSQL_RAISEOPTION_HINT }; /* -------- * Behavioral modes for plpgsql variable resolution * -------- */ typedef enum { 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; /* -------- * State of cursor found/notfound variable * -------- */ typedef enum { PLPGSQL_TRUE, PLPGSQL_FALSE, PLPGSQL_NULL } PLpgSQL_state; /* -------- * Type of the DECLARE HANDLER. * ref: https://dev.mysql.com/doc/refman/8.0/en/declare-handler.html * -------- */ typedef enum { DECLARE_HANDLER_EXIT, DECLARE_HANDLER_CONTINUE } PLpgSQL_declare_handler; /* -------- * State of RESIGNAL * -------- */ typedef enum { PLPGSQL_NORMAL, PLPGSQL_SIGNAL, PLPGSQL_RESIGNAL_WITH_SQLSTATE, PLPGSQL_RESIGNAL_WITHOUT_SQLSTATE} PLpgSQL_signal_resignal; /* -------- * condition_information_item_name of the SIGNAL/RESIGNAL * ref: https://docs.oracle.com/cd/E17952_01/mysql-5.7-en/signal.html */ typedef enum { PLPGSQL_CLASS_ORIGIN, PLPGSQL_SUBCLASS_ORIGIN, PLPGSQL_MESSAGE_TEXT, PLPGSQL_MYSQL_ERRNO, PLPGSQL_CONSTRAINT_CATALOG, PLPGSQL_CONSTRAINT_SCHEMA, PLPGSQL_CONSTRAINT_NAME, PLPGSQL_CATALOG_NAME, PLPGSQL_SCHEMA_NAME, PLPGSQL_TABLE_NAME, PLPGSQL_COLUMN_NAME, PLPGSQL_CURSOR_NAME } PLpgSQL_con_info_item_value; /* * GsDependency object type */ typedef enum { GSDEPEND_OBJECT_TYPE_INVALID = 0, GSDEPEND_OBJECT_TYPE_UNDEFIND, GSDEPEND_OBJECT_TYPE_VARIABLE, GSDEPEND_OBJECT_TYPE_TYPE, GSDEPEND_OBJECT_TYPE_FUNCTION, GSDEPEND_OBJECT_TYPE_PROCHEAD, GSDEPEND_OBJECT_TYPE_PKG, GSDEPEND_OBJECT_TYPE_PKG_BODY, GSDEPEND_OBJECT_TYPE_PKG_RECOMPILE } GsDependObjectType; /* * GsDependency reference object position type */ #define GSDEPEND_REFOBJ_POS_INVALID 0 #define GSDEPEND_REFOBJ_POS_IN_TYPE 1 #define GSDEPEND_REFOBJ_POS_IN_PKGSPEC 2 #define GSDEPEND_REFOBJ_POS_IN_PROCHEAD 4 #define GSDEPEND_REFOBJ_POS_IN_PROCBODY 8 #define GSDEPEND_REFOBJ_POS_IN_PKGBODY 16 #define GSDEPEND_REFOBJ_POS_IN_PKGRECOMPILE_OBJ (GSDEPEND_REFOBJ_POS_IN_PKGSPEC | \ GSDEPEND_REFOBJ_POS_IN_PKGBODY | GSDEPEND_REFOBJ_POS_IN_PROCBODY) #define GSDEPEND_REFOBJ_POS_IN_PKGALL_OBJ (GSDEPEND_REFOBJ_POS_IN_PKGRECOMPILE_OBJ) #define GSDEPEND_REFOBJ_POS_IN_PROCALL (GSDEPEND_REFOBJ_POS_IN_PROCHEAD | GSDEPEND_REFOBJ_POS_IN_PROCBODY) /********************************************************************** * Node and structure definitions **********************************************************************/ typedef struct PLpgSQL_nest_type { /* Generic datum array item */ char* typname; int layer; int index; } PLpgSQL_nest_type; /* * PLpgSQL_datum is the common supertype for PLpgSQL_expr, PLpgSQL_var, * PLpgSQL_row, PLpgSQL_rec, PLpgSQL_recfield, and PLpgSQL_arrayelem */ typedef struct PLpgSQL_datum { /* Generic datum array item */ int dtype; int dno; bool ispkg; bool inherit; } PLpgSQL_datum; /* * DependenciesDatum is the common supertype for DependenciesUndefined, DependenciesVariable, * DependenciesType, DependenciesProchead */ typedef struct DependenciesDatum { /* Generic datum array item */ NodeTag type; } DependenciesDatum; /* * PLpgSQL dependencies undefined/type/variable/function/procedure */ typedef struct DependenciesUndefined { /* Generic datum array item */ NodeTag type; } DependenciesUndefined; typedef struct DependenciesVariable { NodeTag type; char* typName; int32 typMod; char* extraInfo; } DependenciesVariable; typedef struct DependenciesType{ NodeTag type; char typType; char typCategory; char* attrInfo; bool isRel; char* elemTypName; char* idxByTypName; } DependenciesType; typedef struct DependenciesProchead{ NodeTag type; bool undefined; char* proName; char* proArgSrc; char* funcHeadSrc; } DependenciesProchead; typedef enum PLpgSQL_trigtype { PLPGSQL_DML_TRIGGER, PLPGSQL_EVENT_TRIGGER, PLPGSQL_NOT_TRIGGER } PLpgSQL_trigtype; /* * The variants PLpgSQL_var, PLpgSQL_row, and PLpgSQL_rec share these * fields */ typedef struct { /* Scalar or composite variable */ int dtype; int dno; bool ispkg; bool inherit; Oid pkg_oid; char* refname; int lineno; bool isImplicit; bool addNamespace; bool varname; } PLpgSQL_variable; typedef struct PLpgSQL_expr { /* SQpL Query to plan and execute */ int dtype; int dno; bool ispkg; bool inherit; char* query; List* nest_typnames; SPIPlanPtr plan; 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 */ int expr_simple_generation; /* plancache generation we checked */ 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 */ bool expr_simple_need_snapshot; /* true means need snapshot */ /* * 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; bool isouttype; /* the parameter will output */ bool is_funccall; int out_param_dno; /* if expr is func call and param is seperate from return values */ uint32 idx; bool is_cachedplan_shared; /* if the expr have table of index var, we should found its param. */ bool is_have_tableof_index_var; int tableof_var_dno; /* if the expr have table of index function, we should found its args->param. */ bool is_have_tableof_index_func; /* dno maybe is 0, so need an extra variable */ int tableof_func_dno; uint64 unique_sql_id; } PLpgSQL_expr; /* To save subtype range constraints */ typedef struct SubTypeRange { bool valid; Oid SubTypeOid; Oid functionOid; Oid packageOid; PLpgSQL_expr* lowValue; PLpgSQL_expr* highValue; } SubTypeRange; typedef struct { /* openGauss data type */ int dtype; int dno; bool ispkg; bool inherit; char* typname; /* (simple) name of the type */ Oid typoid; /* OID of the data type */ int ttype; /* PLPGSQL_TTYPE_ code */ int16 typlen; /* stuff copied from its pg_type entry */ bool typbyval; Oid typrelid; Oid typioparam; Oid collation; /* from pg_type, but can be overridden */ FmgrInfo typinput; /* lookup info for typinput function */ int32 atttypmod; /* typmod (taken from someplace else) */ char* typnamespace; /* name of typnamespace */ int collectionType; /* PLPGSQL_COLLECTION_ code */ Oid tableOfIndexType; /* * If a defined cursor is found during the compilation of the function, * parse and rewrite the sql immediately to get the query targetlist, * then convert to tuple descriptior. */ Oid cursorCompositeOid = InvalidOid; Oid tableofOid; TypeDependExtend* dependExtend; PLpgSQL_expr* cursorExpr; int cursorDno; char typtyp; PLpgSQL_expr** defaultvalues; } PLpgSQL_type; typedef struct { Oid userId; int secContext; int level; } transactionNode; typedef struct PLpgSQL_var { /* Scalar variable */ int dtype; int dno; bool ispkg; bool inherit; Oid pkg_oid; char* refname; int lineno; bool isImplicit; bool addNamespace; char* varname; PLpgSQL_type* datatype; int isconst; int notnull; PLpgSQL_expr* default_val; PLpgSQL_expr* cursor_explicit_expr; int cursor_explicit_argrow; /* count of cursor's args including those with default exprs */ int cursor_implicit_argrow; /* count of cursor's args requiring values (those without default exprs) */ int cursor_options; MemoryContext datum_cxt; Datum value; bool isnull; bool freeval; bool is_cursor_var; /* variable is a refcursor */ bool is_cursor_open; /* mark var is isopen for isopen option shoule be always not null */ bool cursor_closed; /* if the var is cursor, mark the cursor is closed by close cursor? */ List* pkg_name = NULL; PLpgSQL_package* pkg = NULL; Oid tableOfIndexType = InvalidOid; /* type Oid of table of */ bool isIndexByTblOf; struct PLpgSQL_var* nest_table; /* origin nest table type, copy from it when add new nest table */ HTAB* tableOfIndex = NULL; /* mapping of table of index */ int nest_layers = 0; List* nest_typnames; } PLpgSQL_var; typedef struct { /* Row variable */ int dtype; int dno; bool ispkg; bool inherit; Oid pkg_oid; char* refname; int lineno; bool isImplicit; bool addNamespace; char* varname; PLpgSQL_type* datatype; Oid func_oid; TupleDesc rowtupdesc; MemoryContext datum_cxt; /* * Note: TupleDesc is only set up for named rowtypes, else it is NULL. * * Note: if the underlying rowtype contains a dropped column, the * corresponding fieldnames[] entry will be NULL, and there is no * corresponding var (varnos[] will be -1). */ int nfields; char** fieldnames; int needValDno; /* count of fields that require values (don't have defaults) */ PLpgSQL_expr** argDefExpr; int* varnos; /* only use for unpkg's var, pkg's var is in row->pkg->datums */ int customErrorCode; /* only for exception variable. */ int intoplaceholders; /* number of placeholders, for anonymous block in dynamic stmt */ PLpgSQL_datum** intodatums; List* pkg_name = NULL; PLpgSQL_package* pkg = NULL; PLpgSQL_expr* default_val = NULL; Oid recordVarTypOid; /* package record var's composite type oid */ bool hasExceptionInit; bool atomically_null_object; List* nest_typnames; } PLpgSQL_row; typedef struct { char* attrname; PLpgSQL_type* type; bool notnull; PLpgSQL_expr* defaultvalue; List* nest_typnames; PLpgSQL_nest_type* cur_ntype; } PLpgSQL_rec_attr; typedef struct { int dtype; int dno; bool ispkg; bool inherit; Oid pkg_oid; char* typname; /* (simple) name of the type */ Oid typoid; /* OID of the data type */ int ttype; /* PLPGSQL_TTYPE_ code */ int16 typlen; /* stuff copied from its pg_type entry */ bool typbyval; Oid typrelid; Oid typioparam; Oid collation; /* from pg_type, but can be overridden */ FmgrInfo typinput; /* lookup info for typinput function */ int32 atttypmod; /* typmod (taken from someplace else) */ int attrnum; char** attrnames; PLpgSQL_type** types; bool* notnulls; bool addNamespace; PLpgSQL_expr** defaultvalues; List* nest_typnames; } PLpgSQL_rec_type; typedef struct { /* Record variable (non-fixed structure) */ int dtype; int dno; bool ispkg; bool inherit; Oid pkg_oid; char* refname; int lineno; bool isImplicit; bool addNamespace; bool notnull; char* varname; HeapTuple tup; TupleDesc tupdesc; bool freetup; bool freetupdesc; List* pkg_name = NULL; List* field_need_check = NULL; MemoryContext datum_cxt; PLpgSQL_package* pkg = NULL; PLpgSQL_expr* default_val = NULL; PLpgSQL_expr* expr = NULL; int cursorDno; } PLpgSQL_rec; typedef struct { /* Field in record */ int dtype; int dno; bool ispkg; bool inherit; char* fieldname; int recparentno; /* dno of parent record */ } PLpgSQL_recfield; typedef struct { /* Element of array variable */ int dtype; int dno; bool ispkg; bool inherit; PLpgSQL_expr* subscript; int arrayparentno; /* dno of parent array variable */ /* Remaining fields are cached info about the array variable's type */ Oid parenttypoid; /* type of array variable; 0 if not yet set */ int32 parenttypmod; /* typmod of array variable */ Oid arraytypoid; /* OID of actual array type */ int32 arraytypmod; /* typmod of array (and its elements too) */ int16 arraytyplen; /* typlen of array type */ Oid elemtypoid; /* OID of array element type */ int16 elemtyplen; /* typlen of element type */ bool elemtypbyval; /* element type is pass-by-value? */ char elemtypalign; /* typalign of element type */ AttrNumber assignattrno; /* index of assign attribute */ List* pkg_name = NULL; PLpgSQL_package* pkg = NULL; } PLpgSQL_arrayelem; typedef struct { /* assign list */ int dtype; int dno; bool ispkg; bool inherit; List* assignlist; /* assign list, contains subscripts or attributes */ int targetno; /* the dno of assign target */ } PLpgSQL_assignlist; typedef struct { /* Scalar variable */ int dtype; int dno; bool ispkg; bool isnull; bool inherit; Datum value; char* attrname; uint32 attnum; bool isarrayelem; int* subscriptvals; int nsubscripts; Oid typoid; int32 typmod; } PLpgSQL_temp_assignvar; typedef struct { /* Element of table variable */ int dtype; int dno; bool ispkg; bool inherit; PLpgSQL_expr* subscript; int tableparentno; /* dno of parent table variable */ /* Remaining fields are cached info about the array variable's type */ Oid parenttypoid; /* type of table variable; 0 if not yet set */ int32 parenttypmod; /* typmod of table variable */ Oid tabletypoid; /* OID of actual table type */ int32 tabletypmod; /* typmod of table (and its elements too) */ int16 tabletyplen; /* typlen of table type */ Oid elemtypoid; /* OID of table element type */ int16 elemtyplen; /* typlen of element type */ bool elemtypbyval; /* element type is pass-by-value? */ char elemtypalign; /* typalign of element type */ AttrNumber assignattrno; /* index of assign attribute */ List* pkg_name = NULL; PLpgSQL_package* pkg = NULL; } PLpgSQL_tableelem; typedef struct { Oid exprtypeid; Datum exprdatum; } TableOfIndexKey; typedef struct { TableOfIndexKey key; int index; struct PLpgSQL_var* var; } TableOfIndexEntry; typedef struct PLpgSQL_nsitem { /* Item in the compilers namespace tree */ int itemtype; int itemno; struct PLpgSQL_nsitem* prev; bool inherit; char* pkgname; char* schemaName; char name[FLEXIBLE_ARRAY_MEMBER]; /* actually, as long as needed */ } PLpgSQL_nsitem; typedef struct { /* Generic execution node */ int cmd_type; int lineno; } PLpgSQL_stmt; typedef struct PLpgSQL_stmt_null { int cmd_type; int lineno; char* sqlString; } PLpgSQL_stmt_null; extern THR_LOCAL List* goto_labels; typedef struct { char* label; PLpgSQL_stmt* stmt; } PLpgSQL_gotoLabel; typedef struct PLpgSQL_cond_item { PLpgSQL_con_info_item_value cond_item; char* condString; }PLpgSQL_cond_item; typedef struct PLpgSQL_condition { /* One EXCEPTION condition name */ int sqlerrstate; /* SQLSTATE integer format */ char *sqlstate; /* SQLSTATE string format */ char *condname; /* condition name (for debugging) */ bool isSqlvalue; struct PLpgSQL_condition* next; } PLpgSQL_condition; typedef struct { List* exc_list; /* List of WHEN clauses */ } PLpgSQL_exception_block; typedef struct { /* One EXCEPTION ... WHEN clause */ int lineno; PLpgSQL_condition* conditions; List* action; /* List of statements */ PLpgSQL_declare_handler handler_type; } PLpgSQL_exception; typedef struct PLpgSQL_stmt_block { /* Block of statements */ int cmd_type; int lineno; char* label; bool isAutonomous; bool isDeclareHandlerStmt; /* mysql declare handler syntax */ List* body; /* List of statements */ int n_initvars; int* initvarnos; PLpgSQL_exception_block* exceptions; char* sqlString; } PLpgSQL_stmt_block; typedef struct { /* Assign statement */ int cmd_type; int lineno; int varno; PLpgSQL_expr* expr; char* sqlString; } PLpgSQL_stmt_assign; typedef struct { /* PERFORM statement */ int cmd_type; int lineno; PLpgSQL_expr* expr; char* sqlString; } PLpgSQL_stmt_perform; /* * COMMIT statement */ typedef struct { int cmd_type; int lineno; char* sqlString; } PLpgSQL_stmt_commit; /* * ROLLBACK statement */ typedef struct { int cmd_type; int lineno; char* sqlString; } PLpgSQL_stmt_rollback; typedef struct { /* Get Diagnostics item */ int kind; /* id for diagnostic value desired */ int target; /* where to assign it */ char* user_ident; } PLpgSQL_diag_item; typedef struct { /* Get Diagnostics statement */ int cmd_type; int lineno; bool is_stacked; /* STACKED or CURRENT diagnostics area? */ bool has_cond; bool is_cond_item; int cond_number; List* diag_items; /* List of PLpgSQL_diag_item */ char* sqlString; } PLpgSQL_stmt_getdiag; typedef struct { /* IF statement */ int cmd_type; int lineno; 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 */ char* sqlString; } PLpgSQL_stmt_if; typedef struct { /* GOTO statement */ int cmd_type; int lineno; char* label; char* sqlString; } PLpgSQL_stmt_goto; typedef struct /* one ELSIF arm of IF statement */ { int lineno; PLpgSQL_expr* cond; /* boolean expression for this case */ List* stmts; /* List of statements */ } PLpgSQL_if_elsif; typedef struct /* CASE statement */ { int cmd_type; int lineno; 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 */ char* sqlString; } PLpgSQL_stmt_case; typedef struct /* one arm of CASE statement */ { int lineno; PLpgSQL_expr* expr; /* boolean expression for this case */ List* stmts; /* List of statements */ char* sqlString; } PLpgSQL_case_when; typedef struct { /* Unconditional LOOP statement */ int cmd_type; int lineno; char* label; List* body; /* List of statements */ char* sqlString; } PLpgSQL_stmt_loop; typedef struct { /* WHILE cond LOOP statement */ int cmd_type; int lineno; char* label; PLpgSQL_expr* cond; List* body; /* List of statements */ char* sqlString; bool condition; } PLpgSQL_stmt_while; typedef struct { /* FOR statement with integer loopvar */ int cmd_type; int lineno; 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 */ char* sqlString; bool save_exceptions; } 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_dynfors. */ typedef struct { int cmd_type; int lineno; char* label; PLpgSQL_rec* rec; PLpgSQL_row* row; List* body; /* List of statements */ char* sqlString; } PLpgSQL_stmt_forq; typedef struct { /* FOR statement running over SELECT */ int cmd_type; int lineno; char* label; PLpgSQL_rec* rec; PLpgSQL_row* row; List* body; /* List of statements */ char* sqlString; /* end of fields that must match PLpgSQL_stmt_forq */ PLpgSQL_expr* query; bool addNamespace; } PLpgSQL_stmt_fors; typedef struct { /* FOR statement running over cursor */ int cmd_type; int lineno; char* label; PLpgSQL_rec* rec; PLpgSQL_row* row; List* body; /* List of statements */ char* sqlString; /* end of fields that must match PLpgSQL_stmt_forq */ int curvar; PLpgSQL_expr* argquery; /* cursor arguments if any */ } PLpgSQL_stmt_forc; typedef struct { /* FOR statement running over EXECUTE */ int cmd_type; int lineno; char* label; PLpgSQL_rec* rec; PLpgSQL_row* row; List* body; /* List of statements */ char* sqlString; /* end of fields that must match PLpgSQL_stmt_forq */ PLpgSQL_expr* query; List* params; /* USING expressions */ } PLpgSQL_stmt_dynfors; typedef struct { /* FOREACH item in array loop */ int cmd_type; int lineno; char* label; int varno; /* loop target variable */ int slice; /* slice dimension, or 0 */ PLpgSQL_expr* expr; /* array expression */ List* body; /* List of statements */ char* sqlString; } PLpgSQL_stmt_foreach_a; typedef struct { /* OPEN a curvar */ int cmd_type; int lineno; int curvar; int cursor_options; PLpgSQL_row* returntype; PLpgSQL_expr* argquery; PLpgSQL_expr* query; PLpgSQL_expr* dynquery; List* params; /* USING expressions */ char* sqlString; } PLpgSQL_stmt_open; typedef struct { /* FETCH or MOVE statement */ int cmd_type; int lineno; PLpgSQL_rec* rec; /* target, as record or row */ PLpgSQL_row* 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 bulk_collect; /* is bulk collect? */ bool has_direction; /* has direction clause */ bool returns_multiple_rows; /* can return more than one row? */ char* sqlString; } PLpgSQL_stmt_fetch; typedef struct { /* CLOSE curvar */ int cmd_type; int lineno; int curvar; char* sqlString; } PLpgSQL_stmt_close; typedef struct { /* EXIT or CONTINUE statement */ int cmd_type; int lineno; bool is_exit; /* Is this an exit or a continue? */ char* label; /* NULL if it's an unlabelled EXIT/CONTINUE */ PLpgSQL_expr* cond; char* sqlString; } PLpgSQL_stmt_exit; typedef struct { /* RETURN statement */ int cmd_type; int lineno; PLpgSQL_expr* expr; int retvarno; char* sqlString; } PLpgSQL_stmt_return; typedef struct { /* RETURN NEXT statement */ int cmd_type; int lineno; PLpgSQL_expr* expr; int retvarno; char* sqlString; } PLpgSQL_stmt_return_next; typedef struct { /* RETURN QUERY statement */ int cmd_type; int lineno; PLpgSQL_expr* query; /* if static query */ PLpgSQL_expr* dynquery; /* if dynamic query (RETURN QUERY EXECUTE) */ List* params; /* USING arguments for dynamic query */ char* sqlString; } PLpgSQL_stmt_return_query; typedef struct { int cmd_type; int lineno; PLpgSQL_expr * expr; int retvarno; char* sqlString; } PLpgSQL_stmt_pipe_row; typedef struct { /* RAISE statement */ int cmd_type; int lineno; 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 */ char* sqlString; bool hasExceptionInit; } PLpgSQL_stmt_raise; typedef struct { /* RAISE statement option */ int opt_type; PLpgSQL_expr* expr; } PLpgSQL_raise_option; typedef struct { /* signal/resignal statement */ int cmd_type; int lineno; int sqlerrstate; /* SQLSTATE integer format */ char *sqlstate; /* SQLSTATE string format */ char *condname; /* condition name, SQLSTATE, or NULL */ List *cond_info_item; /* PLpgSQL_signal_info_item */ char *sqlString; } PLpgSQL_stmt_signal; typedef struct { /* condition information item name for signal/resignal */ char *sqlstate; char *class_origin; char *subclass_origin; char *message_text; char *constraint_catalog; char *constraint_schema; char *constraint_name; char *catalog_name; char *schema_name; char *table_name; char *column_name; char *cursor_name; char *sqlerrcode; /* mysql_errno */ } PLpgSQL_condition_info_item; typedef struct { /* siganl_information_item */ int con_info_value; /* PLpgSQL_con_info_item_value */ char *con_name; PLpgSQL_expr *expr; } PLpgSQL_signal_info_item; typedef struct { /* Generic SQL statement to execute */ int cmd_type; int lineno; PLpgSQL_expr* sqlstmt; bool mod_stmt; /* is the stmt INSERT/UPDATE/DELETE? */ /* note: mod_stmt is set when we plan the query */ bool into; /* INTO supplied? */ bool bulk_collect; /* BULK COLLECT? */ bool strict; /* INTO STRICT flag */ PLpgSQL_rec* rec; /* INTO target, if record */ PLpgSQL_row* row; /* INTO target, if row */ // A db function invoke feature int placeholders; bool multi_func; bool object_rel_value; /* Contain value for object type relation? */ char* sqlString; } PLpgSQL_stmt_execsql; // Added USING IN/OUT/IN OUT for plpgsql typedef struct { /* Dynamic SQL string to execute */ int cmd_type; int lineno; PLpgSQL_expr* query; /* string expression */ bool into; /* INTO supplied? */ bool strict; /* INTO STRICT flag */ PLpgSQL_rec* rec; /* INTO target, if record */ union { PLpgSQL_row* row; /* INTO target, if row */ PLpgSQL_row* out_row; /* USING output */ }; List* params; /* USING expressions */ bool isinouttype; /* IN OUT parameters, differ from INTO statment */ bool isanonymousblock; /* check if it is anonymous block */ void* ppd; /* IN or IN OUT parameters */ char* sqlString; } PLpgSQL_stmt_dynexecute; /* ---------- * SAVEPOINT operate types * ---------- */ enum { PLPGSQL_SAVEPOINT_CREATE, PLPGSQL_SAVEPOINT_ROLLBACKTO, PLPGSQL_SAVEPOINT_RELEASE }; /* * SAVEPOINT statement */ typedef struct { int cmd_type; int lineno; int opType; /* create or rollback to or release */ char* spName; /* savepoint's identifier */ char* sqlString; } PLpgSQL_stmt_savepoint; typedef struct PLpgSQL_func_hashkey { /* Hash lookup key for functions */ Oid funcOid; bool isTrigger; /* true if called as a 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 relation triggered on is part of * the hash key --- we want to compile the trigger separately for each * relation it is used with, in case the rowtype is different. Zero if * not called as a trigger. */ Oid trigrelOid; /* * 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]; Oid packageOid; /* package oid if is in a package */ } PLpgSQL_func_hashkey; typedef struct PLpgSQL_error { /* Element of table variable */ int line; char* errmsg; } PLpgSQL_error; typedef struct FuncInvalItem { NodeTag type; int cacheId; /* a syscache ID, see utils/syscache.h */ Oid objId; Oid dbId; } FuncInvalItem; typedef struct PLpgSQL_function { /* Complete compiled function */ char* fn_signature; Oid fn_oid; Oid pkg_oid; OverrideSearchPath* fn_searchpath; Oid fn_owner; TransactionId fn_xmin; ItemPointerData fn_tid; bool is_private; 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; FmgrInfo fn_retinput; Oid fn_rettypioparam; bool fn_retistuple; bool fn_retset; bool fn_readonly; int fn_nargs; int fn_argvarnos[FUNC_MAX_ARGS]; int out_param_varno; int found_varno; // magic variables' varno for implicit cursor attributes int sql_cursor_found_varno; int sql_notfound_varno; int sql_isopen_varno; int sql_rowcount_varno; int sql_bulk_exceptions_varno; // the magic sqlcode no int sqlcode_varno; int sqlstate_varno; int sqlerrm_varno; int new_varno; int old_varno; int tg_name_varno; int tg_when_varno; int tg_level_varno; int tg_op_varno; int tg_relid_varno; int tg_relname_varno; int tg_table_name_varno; int tg_table_schema_varno; int tg_nargs_varno; int tg_argv_varno; /* for event triggers */ int tg_event_varno; int tg_tag_varno; List* invalItems; /* other dependencies, like other pkg's type or variable */ PLpgSQL_resolve_option resolve_option; /* for function subprograms. */ Oid parent_oid = InvalidOid; PLpgSQL_function *parent_func; List* sub_func_oid_list; List* sub_type_oid_list; List* record_oid_list; List* proc_list; bool in_anonymous = false; int block_level = 0; int ndatums; int subprogram_ndatums; PLpgSQL_datum** datums; bool* datum_need_free; /* need free datum when free function memory? */ PLpgSQL_stmt_block* action; List* goto_labels; /* these fields change when the function is used */ struct PLpgSQL_execstate* cur_estate; unsigned long use_count; /* these fields are used during trigger pre-parsing */ bool pre_parse_trig; Relation tg_relation; /* pl debugger ptr */ struct DebugInfo* debug; struct PLpgSQL_nsitem* ns_top; uint64 guc_stat; bool is_autonomous; bool is_plpgsql_func_with_outparam; bool is_insert_gs_source; /* gs depend */ bool isValid; bool is_need_recompile; Oid namespaceOid; bool is_pipelined; bool pipelined_resistuple; } PLpgSQL_function; class AutonomousSession; typedef struct PLpgSQL_execstate { /* Runtime execution data */ PLpgSQL_function* func; /* function being executed */ Datum retval; bool retisnull; bool is_flt_frame; /* Indicates whether it is a flattened expr frame */ Oid rettype; /* type of current retval */ Datum paramval; bool paramisnull; Oid paramtype; Oid fn_rettype; /* info about declared function rettype */ bool retistuple; bool retisset; bool readonly_func; TupleDesc rettupdesc; TupleDesc paramtupdesc; 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 */ MemoryContext tuple_store_cxt; ResourceOwner tuple_store_owner; ReturnSetInfo* rsi; int found_varno; /* * The execute state variable estate->rowcount keeps * the current rowcount while executing store procedure */ int32 rowcount; /* magic variables' varno for implicit cursor attributes */ int sql_cursor_found_varno; int sql_notfound_varno; int sql_isopen_varno; int sql_rowcount_varno; int sqlcode_varno; int sqlstate_varno; int sqlerrm_varno; int sql_bulk_exceptions_varno; int ndatums; int datums_alloc; PLpgSQL_datum** datums; /* EState and resowner to use for "simple" expression evaluation */ EState *simple_eval_estate; ResourceOwner simple_eval_resowner; ParamListInfo paramLI; /* temporary state for results from evaluation of query or expr */ SPITupleTable* eval_tuptable; uint32 eval_processed; Oid eval_lastoid; ExprContext* eval_econtext; /* for executing simple expressions */ PLpgSQL_expr* cur_expr; /* current query/expr being evaluated */ /* status information for error context reporting */ PLpgSQL_stmt* err_stmt; /* current stmt */ const char* err_text; /* additional state info */ void* plugin_info; /* reserved for use by optional plugin */ /* support GOTO */ List* goto_labels; char* goto_target_label; PLpgSQL_stmt* goto_target_stmt; /* current GOTO */ int block_level; /* block level, 0 for topmost */ Cursor_Data* cursor_return_data; int cursor_return_numbers; int64 stack_entry_start; /* ExprContext's starting number for eval simple expression */ Oid curr_nested_table_type; int curr_nested_table_layers; bool is_exception; bool is_declare_handler; /* the block has declare handler stmt */ int handler_level; bool is_pipelined; bool pipelined_resistuple; MemoryContext proc_ctx; } PLpgSQL_execstate; typedef struct PLpgSQL_pkg_execstate { /* Runtime execution data */ Oid pkgoid; char pkgkind; MemoryContext pkgcontext; int ndatums; int n_initvars; int* initvarnos; PLpgSQL_datum** datums; bool is_bodycompiled; struct PLpgSQL_nsitem* public_ns; /* namespace chain visible to this package */ struct PLpgSQL_nsitem* private_ns; } PLpgSQL_pkg_execstate; typedef struct PLpgSQL_func_tableof_index { int varno; Oid tableOfIndexType; HTAB* tableOfIndex; } PLpgSQL_func_tableof_index; typedef struct ExecTableOfIndexInfo { ExprContext* econtext; HTAB* tableOfIndex; Oid tableOfIndexType; bool isnestedtable; int tableOfLayers; int paramid; Oid paramtype; } ExecTableOfIndexInfo; /* * 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()). * It must also be careful to set the rendezvous variable back to NULL * if it is unloaded (_PG_fini()). * * 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 * error_callback and assign_expr fields with pointers to its own * plpgsql_exec_error_callback and exec_assign_expr functions. This is * a somewhat ad-hoc expedient to simplify life for debugger plugins. */ 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); Datum (*eval_expr)(PLpgSQL_execstate* estate, PLpgSQL_expr* expr, bool* isNull, Oid* rettype, HTAB** tableOfIndex, ExecTableOfIndexInfo* tableOfIndexInfo); void (*assign_value)(PLpgSQL_execstate* estate, PLpgSQL_datum* target, Datum value, Oid valtype, bool* isNull, HTAB* tableOfIndex, ExecTableOfIndexInfo* tableOfIndexInfo); void (*eval_cleanup)(PLpgSQL_execstate* estate); int (*validate_line)(PLpgSQL_stmt_block* block, int linenum); } PLpgSQL_plugin; /* Struct types used during parsing */ typedef struct { char* ident; /* palloc'd converted identifier */ bool quoted; /* Was it double-quoted? */ } PLword; typedef struct { List* idents; /* composite identifiers (list of String) */ } PLcword; typedef struct { PLpgSQL_datum* datum; /* referenced variable */ char* ident; /* valid if simple name */ bool quoted; List* idents; /* valid if composite name */ int dno; } PLwdatum; typedef struct PLpgSQL_pkg_hashkey { /* Hash lookup key for functions */ Oid pkgOid; } PLpgSQL_pkg_hashkey; typedef struct plpgsql_pkg_hashent { PLpgSQL_pkg_hashkey key; PLpgSQL_package* package; DListCell* cell; /* Dlist cell for delete package compile results. */ } plpgsql_pkg_HashEnt; #define PACKAGE_INVALID 0x0 #define PACKAGE_SPEC_VALID 0x1 #define PACKAGE_SPEC_INVALID 0xFE #define PACKAGE_BODY_VALID 0x2 #define PACKAGE_BODY_INVALID 0xFD #define PACKAGE_VALID 0x3 typedef struct PLpgSQL_package { /* Complete compiled package */ char* pkg_signature; Oid pkg_oid; OverrideSearchPath* pkg_searchpath; Oid pkg_owner; TransactionId pkg_xmin; ItemPointerData pkg_tid; MemoryContext pkg_cxt; PLpgSQL_pkg_hashkey* pkg_hashkey; /* back-link to hashtable key */ bool is_spec_compiling; bool is_bodycompiled; /* namespace chain visible to this package */ struct PLpgSQL_nsitem* public_ns; /*proc list in package*/ List* proc_list; /* namespace chain visible to this package */ struct PLpgSQL_nsitem* private_ns; /*compiled list in package*/ List* proc_compiled_list; // magic variables' varno for implicit cursor attributes int sql_cursor_found_varno; int sql_notfound_varno; int sql_isopen_varno; int sql_rowcount_varno; PLpgSQL_resolve_option resolve_option; int ndatums; int public_ndatums; int datums_alloc; PLpgSQL_datum** datums; bool* datum_need_free; /* need free datum when free package memory? */ int n_initvars; int* initvarnos; List* invalItems; /* other dependencies, like other pkg's type or variable */ unsigned long use_count; /* count for other func use */ Cursor_Data* cursor_return_data; char* plpgsql_error_funcname; knl_u_plpgsql_pkg_context* u_pkg; Oid namespaceOid; bool isInit; /** * gs_dependencies_fn.h */ NodeTag type; List* preRefObjectOidList; List* preSelfObjectList; unsigned char status; bool is_need_recompile; } PLpgSQL_package; /********************************************************************** * Pl debugger **********************************************************************/ typedef void (*PlpgsqlDebugFunc)(PLpgSQL_function* func, PLpgSQL_execstate* estate); typedef void (*PlpgsqlStartUpFunc)(PLpgSQL_function* func); typedef struct CodeLine { int lineno; char* code; bool canBreak; } CodeLine; typedef struct PLDebug_variable { NodeTag type; char* name; char* var_type; char* value; char* pkgname; bool isconst; } PLDebug_variable; typedef struct PLDebug_frame { NodeTag type; int frameno; char* funcname; int lineno; char* query; int funcoid; } PLDebug_frame; typedef struct DebugInfoComm { int comm_idx; /* buffer */ char* send_buffer; char* rec_buffer; int send_ptr; /* send msg len */ int rec_ptr; /* received msg len */ int send_buf_len; /* send_buffer's size */ int rec_buf_len; /* rec_buffer's size */ } DebugInfoSocket; typedef struct DebugInfo { int lineno; bool stop_next_stmt; char cur_opt; int debugStackIdx; PlpgsqlDebugFunc debugCallback; PlpgsqlStartUpFunc startUp; PLpgSQL_function* func; MemoryContext debug_cxt; DebugInfo* inner_called_debugger; /* debug socket */ DebugInfoComm* comm; /* break point */ List* bp_list; /* current stmt */ PLpgSQL_stmt* cur_stmt; PLpgSQL_execstate* estate; } DebugInfo; typedef struct PLDebug_breakPoint { NodeTag type; int bpIndex; Oid funcoid; int lineno; bool active; bool deleted; char* query; } PLDebug_breakPoint; typedef struct DebugClientInfo { int comm_idx; MemoryContext context; /* buffer */ char* send_buffer; char* rec_buffer; int send_ptr; int rec_ptr; int send_buf_len; int rec_buf_len; } DebugClientInfo; typedef struct PlDebugEntry { Oid key; int commIdx; PLpgSQL_function* func; } PlDebugEntry; typedef enum AddBreakPointError { ADD_BP_ERR_ALREADY_EXISTS = -1, ADD_BP_ERR_OUT_OF_RANGE = -2, ADD_BP_ERR_INVALID_BP_POS = -3 } AddBreakPointError; typedef struct PLDebug_codeline { NodeTag type; int lineno; char* code; bool canBreak; } PLDebug_codeline; typedef List* (*RawParserHook)(const char*, List**); const int MAXINT8LEN = 25; const int DEFAULT_DEBUG_BUF_SIZE = 1024; const long NANOSECOND_PER_SECOND = 1000000000L; /* 1s */ const int MAX_INT_SIZE = 12; extern const char* DEFAULT_UNKNOWN_VALUE; /* after header use upper case letter */ const char DEBUG_NOTHING_HEADER = 'e'; const char DEBUG_ATTACH_HEADER = 'p'; const char DEBUG_LOCALS_HEADER = 'v'; const char DEBUG_NEXT_HEADER = 'n'; const char DEBUG_NEXT_HEADER_AFTER = 'N'; const char DEBUG_ABORT_HEADER = 'a'; const char DEBUG_ABORT_HEADER_AFTER = 'A'; const char DEBUG_CONTINUE_HEADER = 'c'; const char DEBUG_CONTINUE_HEADER_AFTER = 'C'; const char DEBUG_ADDBREAKPOINT_HEADER = 'b'; const char DEBUG_DELETEBREAKPOINT_HEADER = 'r'; const char DEBUG_ENABLEBREAKPOINT_HEADER = 'e'; const char DEBUG_DISABLEBREAKPOINT_HEADER = 'g'; const char DEBUG_FINISH_HEADER = 'f'; const char DEBUG_FINISH_HEADER_AFTER = 'F'; const char DEBUG_BREAKPOINT_HEADER = 'q'; const char DEBUG_STEP_INTO_HEADER = 's'; const char DEBUG_STEP_INTO_HEADER_AFTER = 'S'; const char DEBUG_BACKTRACE_HEADER = 't'; const char DEBUG_SET_VARIABLE_HEADER = 'h'; const char DEBUG_INFOCODE_HEADER = 'i'; const char GMS_DEBUG_NEXT_HEADER = 'd'; const char GMS_DEBUG_NEXT_HEADER_AFTER = 'D'; const char GMS_DEBUG_STEP_INTO_HEADER = 'j'; const char GMS_DEBUG_STEP_INTO_HEADER_AFTER = 'J'; const char GMS_DEBUG_FINISH_HEADER = 'k'; const char GMS_DEBUG_FINISH_HEADER_AFTER = 'K'; const char GMS_DEBUG_ABORT_HEADER = 'l'; const char GMS_DEBUG_ABORT_HEADER_AFTER = 'L'; const char GMS_DEBUG_CONTINUE_HEADER = 'o'; const char GMS_DEBUG_CONTINUE_HEADER_AFTER = 'O'; const char GMS_DEBUG_RUNTIMEINFO_HEADER = 'm'; const char GMS_DEBUG_ADDBREAKPOINT_HEADER = 'x'; /* server return message */ const int DEBUG_SERVER_SUCCESS = 0; enum { DEBUG_SERVER_SET_NO_VAR = 1, DEBUG_SERVER_SET_EXEC_FAILURE, DEBUG_SERVER_SET_CURSOR, DEBUG_SERVER_SET_CONST }; const int DEBUG_SERVER_PRINT_VAR_FRAMENO_EXCEED = 1; #define PLDEBUG_FEATURE_NOT_SUPPORT_IN_DISTRIBUTED() \ do { \ ereport(ERROR, \ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ errmsg("Un-support feature"), \ errdetail("Pldebug is not supported for distribute currently."))); \ } while (0) #define PLDEBUG_FUNCTION_NOT_SUPPORT(funcname) \ do { \ ereport(ERROR, \ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ errmsg("Un-support feature"), \ errdetail("func %s is not supported currently.", funcname))); \ } while (0) #define CHECK_DEBUG_COMM_VALID(idx) \ do { \ if (!g_instance.pldebug_cxt.debug_comm[idx].Used()) \ ereport(ERROR, \ (errmodule(MOD_PLDEBUGGER), errcode(ERRCODE_PLDEBUGGER_ERROR), \ errmsg("Debug Comm %d has been released or not turned on yet.", idx))); \ } while (0) static const char *stringFromCompileStatus(int strindex) { static const char *strings[] = {"COMPILIE_FUNC", "COMPILIE_PKG", "COMPILIE_PKG_FUNC", "COMPILIE_PKG_ANON_BLOCK", "COMPILIE_ANON_BLOCK", "NONE_STATUS"}; return strings[strindex]; } inline void spi_nest_compile_log(MemoryContext cxt, const char* filename, int lineno, const char* funcname) { if (cxt && u_sess->attr.attr_common.log_min_messages <= DEBUG3 && module_logging_is_on(MOD_NEST_COMPILE)) { ereport(DEBUG3, (errmodule(MOD_NEST_COMPILE), errcode(ERRCODE_LOG), errmsg("compile cxt(Location %s,%d, Funcname:%s)curr_compile_context: %p, init compile context status: %s,"\ "new compile_cxt: %p, context name: %s, context parent name: %s, level: %d", filename, lineno, funcname, u_sess->plsql_cxt.curr_compile_context, stringFromCompileStatus(u_sess->plsql_cxt.compile_status), cxt, cxt->name, cxt->parent != NULL ? cxt->parent->name : NULL, list_length(u_sess->plsql_cxt.compile_context_list) + 1))); } } #define SPI_NESTCOMPILE_LOG(cxt) \ (spi_nest_compile_log(cxt, __FILE__, __LINE__, __func__)) extern Datum debug_server_turn_on(PG_FUNCTION_ARGS); extern Datum debug_server_turn_off(PG_FUNCTION_ARGS); extern Datum debug_client_attatch(PG_FUNCTION_ARGS); extern Datum debug_client_abort(PG_FUNCTION_ARGS); extern Datum debug_client_next(PG_FUNCTION_ARGS); extern Datum debug_client_local_variables(PG_FUNCTION_ARGS); extern Datum debug_client_continue(PG_FUNCTION_ARGS); extern Datum debug_client_finish(PG_FUNCTION_ARGS); /* Reserved interface */ extern Datum debug_client_add_breakpoint(PG_FUNCTION_ARGS); extern Datum debug_client_delete_breakpoint(PG_FUNCTION_ARGS); extern Datum debug_client_enable_breakpoint(PG_FUNCTION_ARGS); extern Datum debug_client_disable_breakpoint(PG_FUNCTION_ARGS); extern Datum debug_client_info_breakpoints(PG_FUNCTION_ARGS); extern Datum debug_client_backtrace(PG_FUNCTION_ARGS); extern Datum debug_client_info_code(PG_FUNCTION_ARGS); extern Datum debug_client_info_step(PG_FUNCTION_ARGS); extern Datum local_debug_server_info(PG_FUNCTION_ARGS); void check_debug(PLpgSQL_function* func, PLpgSQL_execstate* estate); void server_pass_upper_debug_opt(DebugInfo* debug); void clean_up_debug_client(bool hasError = false); void clean_up_debug_server(DebugInfo* debug, bool sessClose, bool hasError); void server_send_end_msg(DebugInfo* debug); void server_send_gms_end_msg(DebugInfo* debug); int GetValidDebugCommIdx(); void WaitSendMsg(int commIdx, bool isClient, char** destBuffer, int* destLen); bool WakeUpReceiver(int commIdx, bool isClient); extern void PlDebugerCleanUp(int code, Datum arg); extern void ReportInvalidMsg(const char* buf); extern char* AssignStr(char* src, bool copy = true); extern PlDebugEntry* has_debug_func(Oid key, bool* found); extern bool delete_debug_func(Oid key); extern void add_gms_debug_func(Oid funcOid, int commIdx); extern void RecvUnixMsg(const char* buf, int bufLen, char* destBuf, int destLen); extern char* ResizeDebugBufferIfNecessary(char* buffer, int* oldSize, int needSize); extern void ReleaseDebugCommIdx(int idx); extern void SendUnixMsg(int socket, const char* val, int len, bool is_client); extern List* collect_breakable_line(PLpgSQL_function* func); extern bool SetDebugCommGmsUsed(int commIdx, bool flag); /********************************************************************** * Function declarations **********************************************************************/ /* ---------- * Functions in pl_comp.c * ---------- */ typedef struct plpgsql_hashent { PLpgSQL_func_hashkey key; PLpgSQL_function* function; DListCell* cell; /* Dlist cell for delete function compile results. */ } plpgsql_HashEnt; extern PLpgSQL_function* plpgsql_compile(FunctionCallInfo fcinfo, bool forValidator, bool isRecompile = false); extern void delete_function(PLpgSQL_function* func, bool fromPackage = false); extern PLpgSQL_function* plpgsql_compile_nohashkey(FunctionCallInfo fcinfo); /* parse trigger func */ extern PLpgSQL_function* plpgsql_compile_inline(char* proc_source); extern void plpgsql_parser_setup(struct ParseState* pstate, PLpgSQL_expr* expr); extern void plpgsql_parser_setup_bind(struct ParseState* pstate, List** expr); extern void plpgsql_parser_setup_describe(struct ParseState* pstate, List** expr); extern bool plpgsql_parse_word(char* word1, const char* yytxt, PLwdatum* wdatum, PLword* word, int* tok_flag); extern bool plpgsql_parse_dblword(char* word1, char* word2, PLwdatum* wdatum, PLcword* cword, int* nsflag); extern bool plpgsql_parse_tripword(char* word1, char* word2, char* word3, PLwdatum* wdatum, PLcword* cword, int* tok_flag); extern bool plpgsql_parse_quadword(char* word1, char* word2, char* word3, char* word4, PLwdatum* wdatum, PLcword* cword, int* tok_flag); extern PLpgSQL_type* plpgsql_parse_wordtype(char* ident); extern PLpgSQL_type* plpgsql_parse_cwordtype(List* idents, TypeDependExtend* dependExtend = NULL); 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, TypeDependExtend* type_depend_extend = NULL); extern PLpgSQL_type* build_datatype(HeapTuple type_tup, int32 typmod, Oid collation); extern PLpgSQL_type* plpgsql_build_nested_datatype(); extern const char *plpgsql_code_int2cstring(int sqlcode); extern const int plpgsql_code_cstring2int(const char *codename); extern void plpgsql_set_variable(const char* varname, int value); extern PLpgSQL_variable* plpgsql_build_variable(const char* refname, int lineno, PLpgSQL_type* dtype, bool add2namespace, bool isImplicit = false, const char* varname = NULL, knl_pl_body_type plType = PL_BODY_FUNCTION, bool notNull = false); PLpgSQL_variable* plpgsql_build_varrayType(const char* refname, int lineno, PLpgSQL_type* dtype, bool add2namespace); PLpgSQL_variable* plpgsql_build_tableType(const char* refname, int lineno, PLpgSQL_type* dtype, bool add2namespace); extern PLpgSQL_rec_type* plpgsql_build_rec_type(const char* typname, int lineno, List* list, bool add2namespace); extern List* search_external_nest_type(char* name, Oid typeOid, int layer, List* nest_typnames, PLpgSQL_nest_type* cur_ntype); extern PLpgSQL_rec* plpgsql_build_record(const char* refname, int lineno, bool add2namespace, TupleDesc tupleDesc); extern void plpgsql_build_synonym(char* typname, char* basetypname); extern int plpgsql_recognize_err_condition(const char* condname, bool allow_sqlstate); extern PLpgSQL_condition* plpgsql_parse_err_condition(char* condname); PLpgSQL_condition* plpgsql_parse_err_condition_b_signal(const char* condname); extern PLpgSQL_condition* plpgsql_parse_err_condition_b(const char* condname); extern int plpgsql_adddatum(PLpgSQL_datum* newm, bool isChange = true); extern int plpgsql_add_initdatums(int** varnos); extern void compute_function_hashkey(HeapTuple proc_tup, FunctionCallInfo fcinfo, Form_pg_proc proc_struct, PLpgSQL_func_hashkey* hashkey, bool for_validator); extern PLpgSQL_function* plpgsql_HashTableLookup(PLpgSQL_func_hashkey* func_key); extern void build_cursor_variable(int varno); extern PLpgSQL_datum* GetOriginSubprogramDatum(PLpgSQL_execstate *estate, int dno, Oid func_oid); extern void plpgsql_HashTableInit(void); extern PLpgSQL_row* build_row_from_tuple_desc(const char* rowname, int lineno, TupleDesc desc); extern PLpgSQL_row* build_row_from_rec_type(const char* rowname, int lineno, PLpgSQL_rec_type* type); extern bool plpgsql_check_colocate(Query* query, RangeTblEntry* rte, void* plpgsql_func); extern void plpgsql_HashTableDeleteAll(); extern void plpgsql_hashtable_delete_and_check_invalid_item(int classId, Oid objId); extern void delete_package_and_check_invalid_item(Oid pkgOid); extern void saveCallFromFuncOid(Oid funcOid); extern void plpgsql_hashtable_clear_invalid_obj(bool need_clear = false); extern void plpgsql_HashTableDelete(PLpgSQL_function* func); extern bool plpgsql_get_current_value_stp_with_exception(); extern void plpgsql_restore_current_value_stp_with_exception(bool saved_current_stp_with_exception); extern void plpgsql_set_current_value_stp_with_exception(); extern void delete_pkg_in_HashTable(Oid pkgOid); extern PLpgSQL_package* plpgsql_pkg_compile(Oid pkgOid, bool for_validator, bool isSpec, bool isCreate=false, bool isRecompile = false); extern PLpgSQL_datum* plpgsql_pkg_adddatum(const List* wholeName, char** objname, char** pkgname); extern int plpgsql_pkg_adddatum2ns(const List* name); extern bool plpgsql_check_insert_colocate( Query* query, List* qry_part_attr_num, List* trig_part_attr_num, PLpgSQL_function* func); extern int plpgsql_pkg_add_unknown_var_to_namespace(List* name); extern int plpgsql_build_pkg_variable(List* name, PLpgSQL_datum* datum, bool isSamePkg = false); extern void plpgsql_pkg_HashTableDelete(PLpgSQL_package* pkg); extern PLpgSQL_datum* plpgsql_lookup_datum( bool localmode, const char* name1, const char* name2, const char* name3, int* names_used); extern PLpgSQL_type* plpgsql_get_row_field_type(int dno, const char* fieldname, MemoryContext old_cxt); extern PLpgSQL_resolve_option GetResolveOption(); extern Node* plpgsql_check_match_var(Node* node, ParseState* pstate, ColumnRef* cref); extern Node* get_default_node_from_plpgsql_expr(PLpgSQL_expr *expr); extern PLpgSQL_expr** get_default_plpgsql_expr_from_typeoid(Oid typeOid, int* attrnum); /* ---------- * Functions in pl_handler.c * ---------- */ extern "C" void _PG_init(void); extern "C" Datum plpgsql_call_handler(PG_FUNCTION_ARGS); extern "C" Datum plpgsql_inline_handler(PG_FUNCTION_ARGS); extern "C" Datum plpgsql_validator(PG_FUNCTION_ARGS); extern "C" PLpgSQL_package* plpgsql_package_validator(Oid packageOid, bool isSpec, bool isCreate=false); extern void record_pkg_function_dependency(PLpgSQL_package* pkg, List** invalItems, Oid funcid, Oid pkgid); extern void DecreasePackageUseCount(PLpgSQL_function* func); extern void AddPackageUseCount(PLpgSQL_function* func); /* --- --- --- * Functions in plsql_packages.c * --- --- */ extern "C" { Datum regexp_substr(PG_FUNCTION_ARGS); Datum intervaltonum(PG_FUNCTION_ARGS); Datum rawtohex(PG_FUNCTION_ARGS); Datum report_application_error(PG_FUNCTION_ARGS); Datum raise_application_error(PG_FUNCTION_ARGS); } extern THR_LOCAL PLpgSQL_execstate* plpgsql_estate; /* ---------- * Functions in pl_exec.c * ---------- */ /* save ErrorData for plpgsql exception handler */ typedef struct plpgsql_exception_stack { struct plpgsql_exception_stack* prev; void* elem; } plpgsql_exception_stack; #define BULK_COLLECT_MAX ((Size)0x3FFFFFF) /* maximum number of rows can be bulk collected (by 3FFFFFFF/16) */ extern Datum plpgsql_exec_function(PLpgSQL_function* func, FunctionCallInfo fcinfo, bool dynexec_anonymous_block, int* coverage = NULL); extern Datum plpgsql_exec_autonm_function(PLpgSQL_function* func, FunctionCallInfo fcinfo, char* source_text); extern HeapTuple plpgsql_exec_trigger(PLpgSQL_function* func, TriggerData* 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 exec_get_datum_type(PLpgSQL_execstate* estate, PLpgSQL_datum* datum); extern void exec_get_datum_type_info(PLpgSQL_execstate* estate, PLpgSQL_datum* datum, Oid* typid, int32* typmod, Oid* collation, List** tableOfIndexType, PLpgSQL_function* func = NULL); extern Datum exec_simple_cast_datum( PLpgSQL_execstate* estate, Datum value, Oid valtype, Oid reqtype, int32 reqtypmod, bool isnull); extern void ResetCursorOption(Portal portal, bool reset); extern void LockProcName(char* schemaname, char* pkgname, const char* funcname); #ifndef ENABLE_MULTIPLE_NODES extern void ResetCursorAtrribute(Portal portal); #endif extern void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, Oid valtype, bool *isNull, HTAB* tableOfIndex = NULL, ExecTableOfIndexInfo* tableOfIndexInfo = NULL); extern void exec_eval_datum(PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeId, int32 *typetypmod, Datum *value, bool *isnull, bool isretry); extern void exec_eval_cleanup(PLpgSQL_execstate *estate); extern void plpgsql_estate_setup(PLpgSQL_execstate* estate, PLpgSQL_function* func, ReturnSetInfo* rsi); extern void plpgsql_destroy_econtext(PLpgSQL_execstate* estate); extern PLpgSQL_datum* copy_plpgsql_datum(PLpgSQL_datum* datum); extern void free_expr(PLpgSQL_expr* expr); extern void free_assignlist(List* assignlist); extern HeapTuple make_tuple_from_row(PLpgSQL_execstate* estate, PLpgSQL_row* row, TupleDesc tupdesc); void exec_assign_expr(PLpgSQL_execstate* estate, PLpgSQL_datum* target, PLpgSQL_expr* expr); extern int getTableOfIndexByDatumValue(TableOfIndexKey key, HTAB* tableOfIndex, PLpgSQL_var** node = NULL); extern Datum fillNestedTableArray(ArrayType* arrayval, Oid parenttypoid, Oid elemtypoid, int value, int idx); extern int plpgsql_estate_adddatum(PLpgSQL_execstate* estate, PLpgSQL_datum* newm); extern void CheckCurrCompileDependOnPackage(Oid pkgOid); extern bool needRecompilePlan(SPIPlanPtr plan); extern void plpgsql_param_fetch(ParamListInfo params, int paramid); extern Datum pl_coerce_type_typmod(Datum value, Oid targetTypeId, int32 targetTypMod); #ifndef ENABLE_MULTIPLE_NODES extern void estate_cursor_set(FormatCallStack* plcallstack); #endif extern Datum ExecEvalArrayRef(ArrayRefExprState* astate, ExprContext* econtext, bool* isNull, ExprDoneCond* isDone); extern void free_exception_stack(); /* ---------- * Functions for namespace handling in pl_funcs.c * ---------- */ extern void plpgsql_ns_init(void); extern void plpgsql_ns_push(const char* label); extern void add_pkg_compile(); extern void plpgsql_add_pkg_ns(PLpgSQL_package* pkg); extern void plpgsql_add_pkg_public_ns(PLpgSQL_package* pkg); extern void plpgsql_ns_pop(void); extern PLpgSQL_nsitem* plpgsql_ns_top(void); extern void plpgsql_ns_additem(int itemtype, int itemno, const char* name, const char* pkgname = NULL, const char* schemaName = NULL, bool inherit = false); 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 void free_func_tableof_index(); extern void free_temp_func_tableof_index(List* temp_tableof_index); extern char* GetPackageSchemaName(Oid packageOid); /* ---------- * Other functions in pl_funcs.c * ---------- */ extern const char* plpgsql_stmt_typename(PLpgSQL_stmt* stmt); extern const char* plpgsql_getdiag_kindname(int kind); extern void plpgsql_free_function_memory(PLpgSQL_function* func, bool fromPackage = false); extern void plpgsql_free_package_memory(PLpgSQL_package* pkg); extern void plpgsql_dumptree(PLpgSQL_function* func); extern bool plpgsql_is_trigger_shippable(PLpgSQL_function* func); /* ---------- * Other functions in ruleutils.cpp * ---------- */ extern char* pg_get_functiondef_worker(Oid funcid, int* headerlines); /* ---------- * 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 void plpgsql_append_source_text(StringInfo buf, int startlocation, int endlocation); extern void plpgsql_peek(int* tok1_p); extern void plpgsql_peek2(int* tok1_p, int* tok2_p, int* tok1_loc, int* tok2_loc); extern void plpgsql_peek(int* tok1_p); extern int plpgsql_scanner_errposition(int location); extern void plpgsql_yyerror(const char* message, bool isError = false); 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); extern char* plpgsql_get_curline_query(); extern void plpgsql_process_stmt_array(StringInfo buf, List* bracket_loc); extern void plpgsql_append_object_typename(StringInfo buf, PLpgSQL_type *var_type); extern void CheckSaveExceptionsDML(int errstate); extern PLpgSQL_package* GetCompileListPkg(Oid pkgOid); extern void plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata); /* ---------- * Externs in gram.y * ---------- */ typedef enum { /* PLpgSQL_ArrayState: array parsing FSM flags(states) */ NOT_AN_ARRAY, /* Initial state, not an array */ ARRAY_START, /* Start of an array */ ARRAY_ELEMENT, /* Array element */ ARRAY_COERCE, /* Array element coerce, always set before ARRAY_SEPERATOR */ ARRAY_SEPERATOR, /* Array element seperator, i.e. ',' */ ARRAY_ACCESS /* Accessing the array, placeholder */ } PLpgSQL_ArrayState; typedef struct ArrayParseContext{ List *list_datatype; List *list_left_bracket; List *list_right_bracket; List *list_array_state; bool array_is_empty; /* mark array as empty */ bool array_is_nested; /* mark array as nested */ } ArrayParseContext; typedef struct PackageRuntimeState { Oid packageId; PLpgSQL_datum** datums; int size; } PackageRuntimeState; typedef struct VarName{ char *name; int lineno; } VarName; typedef struct AutoSessionFuncValInfo { bool found; int sql_cursor_found; int sql_notfound; bool sql_isopen; int sql_rowcount; int sqlcode; bool sqlcode_isnull; } AutoSessionFuncValInfo; typedef struct AutoSessionPortalData { int outParamIndex; PortalStrategy strategy; int cursorOptions; const char* sourceText; const char* commandTag; bool atStart; bool atEnd; bool posOverflow; long portalPos; Tuplestorestate* holdStore; MemoryContext holdContext; TupleDesc tupDesc; bool is_open; bool found; bool not_found; int row_count; bool null_open; bool null_fetch; } AutoSessionPortalData; typedef enum { /* PLpgSQL_PortalContextState */ CONTEXT_NEW, /* Initial state, new */ CONTEXT_USED, /* already used by one portal */ } PLpgSQL_PortalContextState; typedef struct AutoSessionPortalContextData { PLpgSQL_PortalContextState status; MemoryContext portalHoldContext; } AutoSessionPortalContextData; /* Context for exception block */ typedef struct ExceptionContext { MemoryContext oldMemCxt; /* CurrentMemoryContext saved at exception's entry */ ResourceOwner oldResOwner; /* CurrentResourceOwner saved at exception's entry */ TransactionId oldTransactionId; /* top transaction id saved at exception entry */ SubTransactionId subXid; /* exception subtransaction's id */ int curExceptionCounter; /* serial number for this exception block */ bool hasReleased; /* whehter or not exception subtransaction has released. */ ErrorData* cur_edata; /* ErrorData captured by this exception block. */ ErrorData* old_edata; /* saved ErrorData before this Exception block. */ int spi_connected; /* SPI connected level before exception. */ int64 stackId; /* the start stack Id before entry exception block. */ PLpgSQL_declare_handler handler_type; } ExceptionContext; /*Save the type recorded during the cursor definition*/ typedef struct CursorRecordType { char* cursor_name; Oid type_oid; } CursorRecordType; typedef enum { PRO_NAME_COL, DB_NAME_COL, COVERAGE_ARR_COL, PRO_QUERYS_COL, COVERAGE_COL } CoverageColumn; /* Quick access array state */ #define IS_ARRAY_STATE(state_list, state) ((state_list && u_sess->attr.attr_sql.sql_compatibility == A_FORMAT) ? \ (linitial_int(state_list) == state) : false) #define SET_ARRAY_STATE(state_list, state) (linitial_int(state_list) = state) extern int plpgsql_yyparse(void); extern bool plpgsql_is_token_match2(int token, int token_next); extern bool plpgsql_is_token_match(int token); extern void pl_validate_function_sql(PLpgSQL_function* func, bool is_replace); extern void validate_stmt_dynexecute(PLpgSQL_stmt_dynexecute* stmt, PLpgSQL_function* func, SQLFunctionParseInfoPtr pinfo, List** stmt_list); extern void pl_validate_expression(PLpgSQL_expr* expr, PLpgSQL_function* func, SQLFunctionParseInfoPtr pinfo, SPIPlanPtr* plan); extern void pl_validate_stmt_block(PLpgSQL_stmt_block *block, PLpgSQL_function* func, SQLFunctionParseInfoPtr pinfo, SPIPlanPtr* plan, List** dynexec_list); extern void pl_validate_stmt_block_in_subtransaction(PLpgSQL_stmt_block* block, PLpgSQL_function* func, SQLFunctionParseInfoPtr pinfo, SPIPlanPtr* plan, List** dynexec_list); extern TupleDesc getCursorTupleDesc(PLpgSQL_expr* expr, bool isOnlySelect, bool isOnlyParse = false); extern int CompileStatusSwtichTo(int newCompileStatus); extern void checkCompileMemoryContext(MemoryContext cxt); extern int getCompileStatus(); extern void getPkgFuncTypeName(char* typname, char** functypname, char** pkgtypname); extern void pushCompileContext(); extern PLpgSQL_compile_context* popCompileContext(); void popToOldCompileContext(PLpgSQL_compile_context* save); extern PLpgSQL_compile_context* createCompileContext(char* const context_name); extern void clearCompileContext(PLpgSQL_compile_context* compile_cxt); extern void clearCompileContextList(const int releaseLength); extern PLpgSQL_datum* GetPackageDatum(List* name, bool* isSamePackage = NULL); extern bool pushed_bulk_exception(); extern bool CheckElementParsetreeTag(Node* parsetree); extern Datum transVaratt1BTo4B(Datum value); extern PLpgSQL_datum* deepCopyPlpgsqlDatum(PLpgSQL_datum* datum); extern PLpgSQL_var* copyPlpgsqlVar(PLpgSQL_var* src); extern PLpgSQL_expr* copyPLpgsqlExpr(PLpgSQL_expr* srcExpr); extern void assign_text_var(PLpgSQL_var* var, const char* str); extern MemoryContext GetAvailableHoldContext(List* PortalContextList); extern void stp_reset_xact(); extern void stp_reset_stmt(); extern void stp_reserve_subxact_resowner(ResourceOwner resowner); extern void stp_cleanup_subxact_resowner(int64 minStackId); extern void stp_cleanup_subxact_resource(int64 stackId); extern void InsertGsSource(Oid objId, Oid nspid, const char* name, const char* type, bool status); extern void examine_parameter_list(List* parameters, Oid languageOid, const char* queryString, oidvector** parameterTypes, TypeDependExtend** type_depend_extend, ArrayType** allParameterTypes, ArrayType** parameterModes, ArrayType** parameterNames, List** parameterDefaults, Oid* requiredResultType, List** defargpos, bool fenced, bool* has_undefined = NULL); extern void compute_return_type( TypeName* returnType, Oid languageOid, Oid* prorettype_p, bool* returnsSet_p, bool fenced, int startLineNumber, TypeDependExtend* type_depend_extend, bool is_refresh_head, bool isPipelined); extern CodeLine* debug_show_code_worker(Oid funcid, uint32* num, int* headerlines); void plpgsql_free_override_stack(int depth); /* gsplsql lock/unlock api */ typedef struct GSPLSQLLockedObjKey { uint32 isPkg; /* 1 is pkg, 0 is func */ Oid objId; Oid dbId; } GSPLSQLLockedObj; typedef struct GSPLSQLLockedObjEntry { GSPLSQLLockedObj key; bool has_locked; } GSPLSQLLockedObjEntry; typedef enum { PLSQL_UNKNOW_OBJ, PLSQL_FUNCTION_OBJ, PLSQL_PACKAGE_OBJ, } GSPLSQLObjectType; extern void init_lock_hash_table(); extern void gsplsql_lock_func_pkg_dependency_all(Oid obj_oid, GSPLSQLObjectType type); extern void gsplsql_unlock_func_pkg_dependency_all(); extern void gsplsql_lock_depend_pkg_on_session(PLpgSQL_function* func); void ProcessSubprograms(List* func_proc_list, Oid parentFuncOid); extern void FunctionInSubprogramCompile(Oid parentFuncOid); extern void add_parent_func_compile(PLpgSQL_compile_context* context); extern void record_inline_subprogram_type(Oid typeoid); extern char* getPlpgsqlVarName(PLpgSQL_datum *datum, bool ref = true); extern void raise_application_error_context_callback(void* arg); typedef PLpgSQL_function* (*plsql_compile)(FunctionCallInfo fcinfo, bool forValidator, bool isRecompile); typedef bool (*checkValidUsername)(const char* name); #endif /* PLPGSQL_H */