f55b74a5创建于 2023年7月14日历史提交
/*
 * Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
 * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * openGauss is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * ---------------------------------------------------------------------------------------
 *
 * extension_dependency.h
 *        postgis extension head file
 *
 *
 *
 * IDENTIFICATION
 *        contrib/postgis/extension_dependency.h
 *
 * ---------------------------------------------------------------------------------------
 */
#ifndef EXTENSION_DEPENDENCY
#define EXTENSION_DEPENDENCY

#include "../postgis_config.h"

#include <stdint.h>
#include <signal.h>
#include <ctype.h>
#include "postgres.h"
#include "access/htup.h"
#include <access/heapam.h>
#include <access/skey.h>
#include <access/genam.h>
#include "access/tuptoaster.h" /* For toast_raw_datum_size */
#include <access/sysattr.h>
#include "catalog/pg_type.h"
#include "catalog/pg_extension.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "commands/extension.h"
//#include "commands/vacuum.h"
#include "fmgr.h"
#include "lib/stringinfo.h"
#include "mb/pg_wchar.h"
#include "nodes/memnodes.h"
#include "nodes/nodes.h"
#include "nodes/pg_list.h"
#include "nodes/parsenodes.h"
#include "utils/array.h"
#include "utils/elog.h"
#include "utils/errcodes.h"
#include "utils/geo_decls.h"
#include "utils/guc.h"
#include "utils/guc_tables.h"
#include "utils/hsearch.h"
#include "utils/palloc.h"
#include "utils/syscache.h"
#include "utils/memutils.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/typcache.h"
#include "utils/fmgroids.h"
#include "knl/knl_variable.h"


typedef int Buffer;
typedef uint16 StrategyNumber;
typedef int16 AttrNumber;

typedef uint16 LocationIndex;
typedef uint32 BlockNumber;
#define RTLeftStrategyNumber 1
#define RTOverLeftStrategyNumber 2
#define RTOverlapStrategyNumber 3
#define RTOverRightStrategyNumber 4
#define RTRightStrategyNumber 5
#define RTSameStrategyNumber 6
#define RTContainsStrategyNumber 7    /* for @> */
#define RTContainedByStrategyNumber 8 /* for <@ */
#define RTOverBelowStrategyNumber 9
#define RTBelowStrategyNumber 10
#define RTAboveStrategyNumber 11
#define RTOverAboveStrategyNumber 12
#define RTOldContainsStrategyNumber 13    /* for old spelling of @> */
#define RTOldContainedByStrategyNumber 14 /* for old spelling of <@ */
#define RTKNNSearchStrategyNumber 15

#define WINDOW_SEEK_CURRENT 0
#define WINDOW_SEEK_HEAD 1
#define WINDOW_SEEK_TAIL 2

#define STATISTIC_NUM_SLOTS 5
#define STATISTIC_KIND_TBLSIZE 6
#define STARELKIND_CLASS 'c'
#define STARELKIND_PARTITION 'p'


#define GIST_ROOT_BLKNO 0
#define GistTupleIsInvalid(itup) (ItemPointerGetOffsetNumber(&((itup)->t_tid)) == TUPLE_IS_INVALID)
#define GistTupleSetValid(itup) ItemPointerSetOffsetNumber(&((itup)->t_tid), TUPLE_IS_VALID)
#define TUPLE_IS_VALID 0xffff
#define TUPLE_IS_INVALID 0xfffe


/* spi.h */
#ifndef SPI_H
#define SPI_OK_CONNECT 1
#define SPI_OK_FINISH 2
#define SPI_OK_FETCH 3
#define SPI_OK_UTILITY 4
#define SPI_OK_SELECT 5
#define SPI_ERROR_NOOUTFUNC (-10)
#define SPI_ERROR_NOATTRIBUTE (-9)


extern THR_LOCAL PGDLLIMPORT uint32 SPI_processed;
extern THR_LOCAL int SPI_result;

typedef uint32 AclMode;
typedef uint16 OffsetNumber;
typedef struct GISTPageOpaqueData GISTPageOpaqueData;
typedef GISTPageOpaqueData* GISTPageOpaque;
typedef struct _SPI_plan* SPIPlanPtr;

typedef struct SPITupleTable {
    MemoryContext tuptabcxt; /* memory context of result table */
    uint32 alloced;          /* of alloced vals */
    uint32 free;             /* of free vals */
    TupleDesc tupdesc;       /* tuple descriptor */
    HeapTuple* vals;         /* tuples */
} SPITupleTable;

#endif

/* pg_proc.h */
typedef struct {
    NameData    proname;         /* procedure name */
    Oid         pronamespace;    /* OID of namespace containing this proc */
    Oid         proowner;        /* procedure owner */
    Oid         prolang;         /* OID of pg_language entry */
    float4      procost;         /* estimated execution cost */
    float4      prorows;         /* estimated # of rows out (if proretset) */
    Oid         provariadic;     /* element type of variadic array, or 0 */
    regproc     protransform;    /* transforms calls to it during planning */
    bool        proisagg;        /* is it an aggregate? */
    bool        proiswindow;     /* is it a window function? */
    bool        prosecdef;       /* security definer */
    bool        proleakproof;    /* is it a leak-proof function? */
    bool        proisstrict;     /* strict with respect to NULLs? */
    bool        proretset;       /* returns a set? */
    char        provolatile;     /* see PROVOLATILE_ categories below */
    int2        pronargs;        /* number of arguments */
    int2        pronargdefaults; /* number of arguments with defaults */
    Oid         prorettype;      /* OID of result type */

    oidvector    proargtypes;    /* parameter types (excludes OUT params) */

#ifdef CATALOG_VARLEN
    Oid         proallargtypes[1];        /* all param types (NULL if IN only) */
    char        proargmodes[1];           /* parameter modes (NULL if IN only) */
    text        proargnames[1];           /* parameter names (NULL if no names) */
    pg_node_tree proargdefaults;          /* list of expression trees for argument */
    text        prosrc;                   /* procedure source text */
    text        probin;                   /* secondary procedure info (can be NULL) */
    text        proconfig[1];             /* procedure-local GUC settings */
    aclitem     proacl[1];                /* access permissions */
    int2vector  prodefaultargpos;
    bool        fencedmode;
    bool        proshippable;    /* if provolatile is not 'i', proshippable will determine if the func can be shipped */
    bool        propackage;
    char        prokind;         /* see PROKIND_ categories below */
#endif
} FormData_pg_proc;
typedef FormData_pg_proc *Form_pg_proc;

/* funcapi.h */
#ifndef FUNCAPI_H
typedef enum TypeFuncClass {
    TYPEFUNC_SCALAR,    /* scalar result type */
    TYPEFUNC_COMPOSITE, /* determinable rowtype result */
    TYPEFUNC_RECORD,    /* indeterminate rowtype result */
    TYPEFUNC_OTHER      /* bogus type, eg pseudotype */
} TypeFuncClass;
#endif

/* nodes/execnodes.h */
typedef struct ExprContext ExprContext;
/* utils/tuplestore.h */
typedef struct Tuplestorestate Tuplestorestate;

/* nodes/execnodes.h */
#ifndef EXECNODES_H
typedef enum {
    ExprSingleResult,   /* expression does not return a set */
    ExprMultipleResult, /* this result is an element of a set */
    ExprEndResult       /* there are no more elements in the set */
} ExprDoneCond;

/* nodes/execnodes.h */
typedef enum {
    SFRM_ValuePerCall = 0x01,         /* one value returned per call */
    SFRM_Materialize = 0x02,          /* result set instantiated in Tuplestore */
    SFRM_Materialize_Random = 0x04,   /* Tuplestore needs randomAccess */
    SFRM_Materialize_Preferred = 0x08 /* caller prefers Tuplestore */
} SetFunctionReturnMode;

/* nodes/execnodes.h */
typedef struct ReturnSetInfo {
    NodeTag type;
    /* values set by caller */
    ExprContext* econtext;  /* context function is being called in */
    TupleDesc expectedDesc; /* tuple descriptor expected by caller */
    int allowedModes;       /* bitmask: return modes caller can handle */
    /* result status from function (but pre-initialized by caller): */
    SetFunctionReturnMode returnMode; /* actual return mode */
    ExprDoneCond isDone;              /* status for ValuePerCall mode */
    /* fields filled by function in Materialize return mode: */
    Tuplestorestate* setResult; /* holds the complete returned tuple set */
    TupleDesc setDesc;          /* actual descriptor for returned tuples */
} ReturnSetInfo;
#endif

typedef PageHeaderData* PageHeader;

/* funcapi.h */
#ifndef FUNCAPI_H
typedef struct AttInMetadata {
    /* full TupleDesc */
    TupleDesc tupdesc;
    /* array of attribute type input function finfo */
    FmgrInfo* attinfuncs;
    /* array of attribute type i/o parameter OIDs */
    Oid* attioparams;
    /* array of attribute typmod */
    int32* atttypmods;
} AttInMetadata;

/* funcapi.h */
typedef struct FuncCallContext {
    /*
     * Number of times we've been called before
     * call_cntr is initialized to 0 for you by SRF_FIRSTCALL_INIT(), and
     * incremented for you every time SRF_RETURN_NEXT() is called.
     */
    uint32 call_cntr;

    /*
     * OPTIONAL maximum number of calls
     *
     * max_calls is here for convenience only and setting it is optional. If
     * not set, you must provide alternative means to know when the function
     * is done.
     */
    uint32 max_calls;

    /*
     * OPTIONAL pointer to result slot
     *
     * This is obsolete and only present for backwards compatibility, viz,
     * user-defined SRFs that use the deprecated TupleDescGetSlot().
     */
    TupleTableSlot* slot;

    /*
     * OPTIONAL pointer to miscellaneous user-provided context information
     *
     * user_fctx is for use as a pointer to your own struct to retain
     * arbitrary context information between calls of your function.
     */
    void* user_fctx;

    /*
     * OPTIONAL pointer to struct containing attribute type input metadata
     *
     * attinmeta is for use when returning tuples (i.e. composite data types)
     * and is not used when returning base data types. It is only needed if
     * you intend to use BuildTupleFromCStrings() to create the return tuple.
     */
    AttInMetadata* attinmeta;

    /*
     * memory context used for structures that must live for multiple calls
     *
     * multi_call_memory_ctx is set by SRF_FIRSTCALL_INIT() for you, and used
     * by SRF_RETURN_DONE() for cleanup. It is the most appropriate memory
     * context for any memory that is to be reused across multiple calls of
     * the SRF.
     */
    MemoryContext multi_call_memory_ctx;

    /*
     * OPTIONAL pointer to struct containing tuple description
     *
     * tuple_desc is for use when returning tuples (i.e. composite data types)
     * and is only needed if you are going to build the tuples with
     * heap_form_tuple() rather than with BuildTupleFromCStrings(). Note that
     * the TupleDesc pointer stored here should usually have been run through
     * BlessTupleDesc() first.
     */
    TupleDesc tuple_desc;
} FuncCallContext;
#endif

/* windowapi.h */
typedef struct WindowAggState WindowAggState;
typedef struct WindowObjectData {
    NodeTag type;
    WindowAggState* winstate; /* parent WindowAggState */
    List* argstates;          /* ExprState trees for fn's arguments */
    void* localmem;           /* WinGetPartitionLocalMemory's chunk */
    int markptr;              /* tuplestore mark pointer for this fn */
    int readptr;              /* tuplestore read pointer for this fn */
    int64 markpos;            /* row that markptr is positioned on */
    int64 seekpos;            /* row that readptr is positioned on */
} WindowObjectData;

typedef Pointer Page;
typedef struct RelationData* Relation;
/* gist.h */
typedef struct GISTENTRY {
    Datum key;
    Relation rel;
    Page page;
    OffsetNumber offset;
    bool leafkey;
} GISTENTRY;

typedef XLogRecPtr GistNSN;

typedef struct GISTPageOpaqueData {
    GistNSN nsn;           /* this value must change on page split */
    BlockNumber rightlink; /* next page if any */
    uint16 flags;          /* see bit definitions above */
    uint16 gist_page_id;   /* for identification of GiST indexes */
} GISTPageOpaqueData;

typedef struct {
    int32 n; /* number of elements */
    GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER];
} GistEntryVector;

typedef struct GIST_SPLITVEC {
    OffsetNumber* spl_left; /* array of entries that go left */
    int spl_nleft;          /* size of this array */
    Datum spl_ldatum;       /* Union of keys in spl_left */
    bool spl_ldatum_exists; /* true, if spl_ldatum already exists. */

    OffsetNumber* spl_right; /* array of entries that go right */
    int spl_nright;          /* size of the array */
    Datum spl_rdatum;        /* Union of keys in spl_right */
    bool spl_rdatum_exists;  /* true, if spl_rdatum already exists. */
} GIST_SPLITVEC;

#ifndef RELATION_H
/* nodes/relation.h */
typedef struct ItstDisKey {
    List* superset_keys; /* list of superset keys list, several members possible */
    List* matching_keys; /* list of exact matching keys,  */
} ItstDisKey;

typedef struct PlannerGlobal PlannerGlobal;

typedef struct PlannerInfo {
    NodeTag type;

    Query* parse; /* the Query being planned */

    PlannerGlobal* glob; /* global info for current planner run */

    Index query_level; /* 1 at the outermost Query */

    struct PlannerInfo* parent_root; /* NULL at outermost Query */

    /*
     * simple_rel_array holds pointers to "base rels" and "other rels" (see
     * comments for RelOptInfo for more info).    It is indexed by rangetable
     * index (so entry 0 is always wasted).  Entries can be NULL when an RTE
     * does not correspond to a base relation, such as a join RTE or an
     * unreferenced view RTE; or if the RelOptInfo hasn't been made yet.
     */
    struct RelOptInfo** simple_rel_array; /* All 1-rel RelOptInfos */
    int simple_rel_array_size;            /* allocated size of array */

    /*
     * List of changed var that mutated during cost-based rewrite optimization, the
     * element in the list is "struct RewriteVarMapping", for example:
     * inlist2join
     * pushjoin2union (will implemented)
     *
     */
    List* var_mappings;
    Relids var_mapping_rels; /* all the relations that related to inlist2join */

    /*
     * simple_rte_array is the same length as simple_rel_array and holds
     * pointers to the associated rangetable entries.  This lets us avoid
     * rt_fetch(), which can be a bit slow once large inheritance sets have
     * been expanded.
     */
    RangeTblEntry** simple_rte_array; /* rangetable as an array */

    /*
     * all_baserels is a Relids set of all base relids (but not "other"
     * relids) in the query; that is, the Relids identifier of the final join
     * we need to form.
     */
    Relids all_baserels;

    /*
     * join_rel_list is a list of all join-relation RelOptInfos we have
     * considered in this planning run.  For small problems we just scan the
     * list to do lookups, but when there are many join relations we build a
     * hash table for faster lookups.  The hash table is present and valid
     * when join_rel_hash is not NULL.    Note that we still maintain the list
     * even when using the hash table for lookups; this simplifies life for
     * GEQO
     */
    List* join_rel_list;        /* list of join-relation RelOptInfos */
    struct HTAB* join_rel_hash; /* optional hashtable for join relations */

    /*
     * When doing a dynamic-programming-style join search, join_rel_level[k]
     * is a list of all join-relation RelOptInfos of level k, and
     * join_cur_level is the current level.  New join-relation RelOptInfos are
     * automatically added to the join_rel_level[join_cur_level] list.
     * join_rel_level is NULL if not in use.
     */
    List** join_rel_level; /* lists of join-relation RelOptInfos */

    int join_cur_level; /* index of list being extended */

    List* init_plans; /* init SubPlans for query */

    List* cte_plan_ids; /* per-CTE-item list of subplan IDs */

    List* eq_classes; /* list of active EquivalenceClasses */

    List* canon_pathkeys; /* list of "canonical" PathKeys */

    /* list of RestrictInfos for mergejoinable outer join clauses
     * w/nonnullable var on left
     */
    List* left_join_clauses;

    /* list of RestrictInfos for mergejoinable outer join clauses
     * w/nonnullable var on right
     */
    List* right_join_clauses;

    /* list of RestrictInfos for mergejoinable full join clauses */
    List* full_join_clauses;

    List* join_info_list; /* list of SpecialJoinInfos */

    List* append_rel_list; /* list of AppendRelInfos */

    List* rowMarks; /* list of PlanRowMarks */

    List* placeholder_list; /* list of PlaceHolderInfos */

    /* desired pathkeys for query_planner(), and actual pathkeys afterwards */
    List* query_pathkeys;

    List* group_pathkeys;    /* groupClause pathkeys, if any */
    List* window_pathkeys;   /* pathkeys of bottom window, if any */
    List* distinct_pathkeys; /* distinctClause pathkeys, if any */
    List* sort_pathkeys;     /* sortClause pathkeys, if any */

    List* minmax_aggs; /* List of MinMaxAggInfos */

    List* initial_rels; /* RelOptInfos we are now trying to join */

    MemoryContext planner_cxt; /* context holding PlannerInfo */

    double total_table_pages; /* of pages in all tables of query */

    double tuple_fraction; /* tuple_fraction passed to query_planner */
    double limit_tuples;   /* limit_tuples passed to query_planner */

    /* true if parse->resultRelation is an inheritance child rel */
    bool hasInheritedTarget;
    bool hasJoinRTEs;            /* true if any RTEs are RTE_JOIN kind */
    bool hasHavingQual;          /* true if havingQual was non-null */
    bool hasPseudoConstantQuals; /* true if any RestrictInfo has * pseudoconstant = true */
    bool hasRecursion;           /* true if planning a recursive WITH item */

    /* Note: qualSecurityLevel is zero if there are no securityQuals */
    Index qualSecurityLevel; /* minimum security_level for quals */

#ifdef PGXC
    /* This field is used only when RemoteScan nodes are involved */
    int rs_alias_index; /* used to build the alias reference */

    /*
     * In Postgres-XC Coordinators are supposed to skip the handling of
     * row marks of type ROW_MARK_EXCLUSIVE & ROW_MARK_SHARE.
     * In order to do that we simply remove such type
     * of row marks from the list rowMarks. Instead they are saved
     * in xc_rowMarks list that is then handeled to add
     * FOR UPDATE/SHARE in the remote query
     */
    List* xc_rowMarks; /* list of PlanRowMarks of type ROW_MARK_EXCLUSIVE & ROW_MARK_SHARE */
#endif

    /* These fields are used only when hasRecursion is true: */
    int wt_param_id;                 /* PARAM_EXEC ID for the work table */
    struct Plan* non_recursive_plan; /* plan for non-recursive term */

    /* These fields are workspace for createplan.c */
    Relids curOuterRels;  /* outer rels above current node */
    List* curOuterParams; /* not-yet-assigned NestLoopParams */

    Index curIteratorParamIndex;
    bool isPartIteratorPlanning;
    int curItrs;
    List* subqueryRestrictInfo; /* Subquery RestrictInfo, which only be used in wondows agg */

    /* optional private data for join_search_hook, e.g., GEQO */
    void* join_search_private;

    /* Added post-release, will be in a saner place in 9.3: */
    List* plan_params; /* list of PlannerParamItems, see below */

    /* For count_distinct, save null info for group by clause */
    List* join_null_info;
    /* for GroupingFunc fixup in setrefs */
    AttrNumber* grouping_map;

    /* If current query level is correlated with upper level */
    bool is_correlated;

    /* data redistribution for DFS table.
     * dataDestRelIndex is index into the range table. This variable
     * will take effect on data redistribution state.
     * The effective value must be greater than 0.
     */
    Index dataDestRelIndex;

    /* interesting keys of current query level */
    ItstDisKey dis_keys;

    /*
     * indicate if the subquery planning root (PlannerInfo) is under or rooted from
     * recursive-cte planning.
     */
    bool is_under_recursive_cte;

    /*
     * indicate if the subquery planning root (PlannerInfo) is under recursive-cte's
     * recursive branch
     */
    bool is_under_recursive_tree;
    bool has_recursive_correlated_rte; /* true if any RTE correlated with recursive cte */
} PlannerInfo;
#endif

/* commands/vacuum.h */
typedef struct VacAttrStats VacAttrStats;
typedef struct VacAttrStats* VacAttrStatsP;

typedef Datum (*AnalyzeAttrFetchFunc)(VacAttrStatsP stats, int rownum, bool* isNull, Relation rel);

typedef void (*AnalyzeAttrComputeStatsFunc)(
    VacAttrStatsP stats, AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows, Relation rel);

/*
 * ATTRIBUTE_FIXED_PART_SIZE is the size of the fixed-layout,
 * guaranteed-not-null part of a pg_attribute row.    This is in fact as much
 * of the row as gets copied into tuple descriptors, so don't expect you
 * can access fields beyond attcollation except in a real tuple!
 */
#define ATTRIBUTE_FIXED_PART_SIZE (offsetof(FormData_pg_attribute, attkvtype) + sizeof(Oid))

#define CacheMemoryContext (u_sess->cache_mem_cxt)

// typedef void (*AnalyzeAttrComputeStatsFunc)(
//     VacAttrStatsP stats, AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows);

#ifndef GAUSSDB
/* commands/vacuum.h */
typedef struct VacAttrStats {
    /*
     * These fields are set up by the main ANALYZE code before invoking the
     * type-specific typanalyze function.
     *
     * Note: do not assume that the data being analyzed has the same datatype
     * shown in attr, ie do not trust attr->atttypid, attlen, etc.    This is
     * because some index opclasses store a different type than the underlying
     * column/expression.  Instead use attrtypid, attrtypmod, and attrtype for
     * information about the datatype being fed to the typanalyze function.
     */
    unsigned int num_attrs;
    Form_pg_attribute* attrs;  /* copy of pg_attribute row for columns */
    Oid* attrtypid;            /* type of data being analyzed */
    int32* attrtypmod;         /* typmod of data being analyzed */
    Form_pg_type* attrtype;    /* copy of pg_type row for attrtypid */
    MemoryContext anl_context; /* where to save long-lived data */

    /*
     * These fields must be filled in by the typanalyze routine, unless it
     * returns FALSE.
     */
    AnalyzeAttrComputeStatsFunc compute_stats; /* function pointer */
    int minrows;                               /* Minimum # of rows wanted for stats */
    void* extra_data;                          /* for extra type-specific data */

    /*
     * These fields are to be filled in by the compute_stats routine. (They
     * are initialized to zero when the struct is created.)
     */
    bool stats_valid;
    float4 stanullfrac;   /* fraction of entries that are NULL */
    int4 stawidth;        /* average width of column values */
    float4 stadistinct;   /* # distinct values */
    float4 stadndistinct; /* # distinct value of dn1*/
    int2 stakind[STATISTIC_NUM_SLOTS];
    Oid staop[STATISTIC_NUM_SLOTS];
    int numnumbers[STATISTIC_NUM_SLOTS];
    float4* stanumbers[STATISTIC_NUM_SLOTS];
    int numvalues[STATISTIC_NUM_SLOTS];
    Datum* stavalues[STATISTIC_NUM_SLOTS];
    bool* stanulls[STATISTIC_NUM_SLOTS];

    /*
     * These fields describe the stavalues[n] element types. They will be
     * initialized to match attrtypid, but a custom typanalyze function might
     * want to store an array of something other than the analyzed column's
     * elements. It should then overwrite these fields.
     */
    Oid statypid[STATISTIC_NUM_SLOTS];
    int2 statyplen[STATISTIC_NUM_SLOTS];
    bool statypbyval[STATISTIC_NUM_SLOTS];
    char statypalign[STATISTIC_NUM_SLOTS];

    /*
     * These fields are private to the main ANALYZE code and should not be
     * looked at by type-specific functions.
     */
    int tupattnum;   /* attribute number within tuples */
    HeapTuple* rows; /* access info for std fetch function */
#if POSTGIS_GSSQL_VERSION >= 310
#ifndef ENABLE_MULTIPLE_NODES
    int numSamplerows; /* numbers of sample rows */
#endif
#endif
    TupleDesc tupDesc;
    Datum* exprvals; /* access info for index fetch function */
    bool* exprnulls;
    int rowstride;
} VacAttrStats;

#else
#define ereport(elevel, rest)   \
    (((elevel) > DEBUG1 || (elevel) < DEBUG5 || log_min_messages <= (elevel) || client_min_messages <= (elevel)) ?   \
        EREPORT_DOMAIN(0, elevel, TEXTDOMAIN, rest) : (void)0)

#define elog(elevel, rest, ...)  elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO), elog_finish_with_errnum(0, elevel, rest, ##__VA_ARGS__)

typedef Datum (*AnalyzeAttrFetchFuncExt)(VacAttrStatsP stats, int attnum, int rownum, bool* isNull, Relation rel);

typedef void (*AnalyzeAttrComputeStatsFuncExt)(
    VacAttrStatsP stats, AnalyzeAttrFetchFuncExt fetchfunc, int samplerows, double totalrows, Relation rel);
typedef struct VacAttrStats {
    /*
     * These fields are set up by the main ANALYZE code before invoking the
     * type-specific typanalyze function.
     *
     * Note: do not assume that the data being analyzed has the same datatype
     * shown in attr, ie do not trust attr->atttypid, attlen, etc.    This is
     * because some index opclasses store a different type than the underlying
     * column/expression.  Instead use attrtypid, attrtypmod, and attrtype for
     * information about the datatype being fed to the typanalyze function.
     */
    unsigned int num_attrs;
    Form_pg_attribute* attrs;  /* copy of pg_attribute row for columns */
    Oid* attrtypid;            /* type of data being analyzed */
    int32* attrtypmod;         /* typmod of data being analyzed */
    Form_pg_type* attrtype;    /* copy of pg_type row for attrtypid */
    MemoryContext anl_context; /* where to save long-lived data */

    /*
     * These fields must be filled in by the typanalyze routine, unless it
     * returns FALSE.
     */
    AnalyzeAttrComputeStatsFunc compute_stats; /* function pointer */
    AnalyzeAttrComputeStatsFuncExt compute_stats_ext; /* function pointer for multi-column statistics */
    int minrows;                               /* Minimum # of rows wanted for stats */
    void* extra_data;                          /* for extra type-specific data */

    /*
     * These fields are to be filled in by the compute_stats routine. (They
     * are initialized to zero when the struct is created.)
     */
    bool stats_valid;
    float4 stanullfrac;   /* fraction of entries that are NULL */
    int4 stawidth;        /* average width of column values */
    float4 stadistinct;   /* # distinct values */
    float4 stadndistinct; /* # distinct value of dn1 */
    int2 stakind[STATISTIC_NUM_SLOTS];
    Oid staop[STATISTIC_NUM_SLOTS];
    int numnumbers[STATISTIC_NUM_SLOTS];
    float4* stanumbers[STATISTIC_NUM_SLOTS];
    int numvalues[STATISTIC_NUM_SLOTS];
    Datum* stavalues[STATISTIC_NUM_SLOTS];
    bool* stanulls[STATISTIC_NUM_SLOTS];

    /*
     * These fields describe the stavalues[n] element types. They will be
     * initialized to match attrtypid, but a custom typanalyze function might
     * want to store an array of something other than the analyzed column's
     * elements. It should then overwrite these fields.
     */
    Oid statypid[STATISTIC_NUM_SLOTS];
    int2 statyplen[STATISTIC_NUM_SLOTS];
    bool statypbyval[STATISTIC_NUM_SLOTS];
    char statypalign[STATISTIC_NUM_SLOTS];

    /*
     * These fields are private to the main ANALYZE code and should not be
     * looked at by type-specific functions.
     */
    int tupattnum;   /* attribute number within tuples */
    HeapTuple* rows; /* access info for std fetch function */
    int numSamplerows; /* numbers of sample rows */
    TupleDesc tupDesc;
    Datum* exprvals; /* access info for index fetch function */
    bool* exprnulls;
    int rowstride;

    /*
     * sources of multi-column statistics:
     * 'a': automatically created based on indexes
     * 'm': manually created
     */
    char stasource;

    /*
     * status of multi-column statistics:
     * 'a': active
     * 'd': disabled
     */
    char stastatus;
} VacAttrStats;
#endif

/* utils/selfuncs.h */
typedef struct VariableStatData {
    Node* var;            /* the Var or expression tree */
    RelOptInfo* rel;      /* Relation, or NULL if not identifiable */
    HeapTuple statsTuple; /* pg_statistic tuple, or NULL if none */
    /* NB: if statsTuple!=NULL, it must be freed when caller is done */
    void (*freefunc)(HeapTuple tuple); /* how to free statsTuple */
    Oid vartype;                       /* exposed type of expression */
    Oid atttype;                       /* type to pass to get_attstatsslot */
    int32 atttypmod;                   /* typmod to pass to get_attstatsslot */
    bool isunique;                     /* matches unique index or DISTINCT clause */
    bool enablePossion;                /* indentify we can use possion or not */
    bool acl_ok;                       /* result of ACL check on table or column */
    PlannerInfo *root;                 /* Planner info the var reference */
    double numDistinct[2];             /* estimated numdistinct, 0: means unknown, [0]: local, [1]: global */
    bool isEstimated;                  /* indicate that whether estimation have already been done */
    PlannerInfo *baseRoot;             /* Planner info of the baseVar */
    Node *baseVar;                     /* base Var, owner of the statsTuple */
    RelOptInfo *baseRel;               /* rel of the baseVar */
    bool needAdjust;                   /* true if need adjust on rel */
} VariableStatData;

typedef GISTPageOpaqueData* GISTPageOpaque;
/* this struct is private in nodeWindowAgg.c */
typedef struct WindowObjectData* WindowObject;

extern THR_LOCAL PGDLLIMPORT SPITupleTable* SPI_tuptable;

/* miscadmin.h */
extern THR_LOCAL PGDLLIMPORT char my_exec_path[];
extern THR_LOCAL PGDLLIMPORT volatile bool InterruptPending;

#define PageIsValid(page) PointerIsValid(page)
#define PointerIsValid(pointer) ((const void*)(pointer) != NULL)
typedef struct PortalData* Portal;

extern bool std_typanalyze(VacAttrStats* stats);
extern bool get_restriction_variable(
    PlannerInfo* root, List* args, int varRelid, VariableStatData* vardata, Node** other, bool* varonleft);

#if POSTGIS_GSSQL_VERSION == 210


extern int SPI_exec(const char* src, long tcount);
extern int SPI_connect(CommandDest dest = DestSPI, void (*spiCallbackfn)(void*) = NULL, void* clientData = NULL);
extern int SPI_finish(void);
extern int SPI_execute(const char* src, bool read_only, long tcount, bool isCollectParam = false);
extern char* SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber);
extern int SPI_freeplan(SPIPlanPtr plan);
extern void SPI_freetuptable(SPITupleTable *tuptable);
extern void SPI_cursor_close(Portal portal);
extern int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount);
extern int SPI_execute_with_args(const char* src, int nargs, Oid* argtypes, Datum* Values, const char* Nulls,
    bool read_only, long tcount, Cursor_Data* cursor_data);
extern SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes);
extern Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull);
extern Portal SPI_cursor_open_with_args(const char* name, const char* src, int nargs, Oid* argtypes, Datum* Values,
										const char* Nulls, bool read_only, int cursorOptions);
extern void SPI_cursor_fetch(Portal portal, bool forward, long count);
extern void* SPI_repalloc(void* pointer, Size size);

#endif 

extern char* text_to_cstring(const text* t);
extern text* cstring_to_text(const char* s);

extern HTAB* hash_create(const char* tabname, long nelem, HASHCTL* info, int flags);
extern void hash_destroy(HTAB* hashp);
extern void hash_remove(HTAB* hashp);
extern void hash_stats(const char* where, HTAB* hashp);
extern void* hash_search(HTAB* hashp, const void* keyPtr, HASHACTION action, bool* foundPtr);
extern uint32 get_hash_value(HTAB* hashp, const void* keyPtr);

extern MemoryContext MemoryContextCreate(
    NodeTag tag, Size size, MemoryContextMethods* methods, MemoryContext parent, const char* name);

extern void MemoryContextDelete(MemoryContext context);

extern void get_share_path(const char* my_exec_path, char* ret_path);

/* funcapi.h */
#define HeapTupleGetDatum(_tuple) PointerGetDatum((_tuple)->t_data)
#define TupleGetDatum(_slot, _tuple) PointerGetDatum((_tuple)->t_data)
extern TypeFuncClass get_func_result_type(Oid functionId, Oid* resultTypeId, TupleDesc* resultTupleDesc);

/* executor/executor.h */
extern Datum GetAttributeByName(HeapTupleHeader tuple, const char* attname, bool* isNull);

/* server/miscadmin.h */
#define CHECK_FOR_INTERRUPTS()   \
    do {                         \
        if (InterruptPending)    \
            ProcessInterrupts(); \
    } while (0)

extern void ProcessInterrupts(void);
extern int GetNumConfigOptions(void);

typedef void (*pqsigfunc)(int);
extern pqsigfunc pqsignal(int signo, pqsigfunc func);

typedef const Pg_finfo_record* (*PGFInfoFunction)(void);

extern Oid get_fn_expr_argtype(FmgrInfo* flinfo, int argnum);
extern int16 get_typlen(Oid typid);
extern bool get_typbyval(Oid typid);

extern Datum hash_any(register const unsigned char* k, register int keylen);

#define ARR_DIMS(a) ((int*)(((char*)(a)) + sizeof(ArrayType)))

extern int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext* aggcontext);
extern Datum datumCopy(Datum value, bool typByVal, int typLen);

extern TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid* resultTypeId, TupleDesc* resultTupleDesc);
extern TupleDesc BlessTupleDesc(TupleDesc tupdesc);
extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum* values, bool* isnull);

extern TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid* resultTypeId, TupleDesc* resultTupleDesc);

extern int GetDatabaseEncoding(void);

extern Datum numeric_int4(PG_FUNCTION_ARGS);
extern Datum textout(PG_FUNCTION_ARGS);
extern int16 get_typlen(Oid typid);
extern bool get_typbyval(Oid typid);
extern void get_typlenbyval(Oid typid, int16* typlen, bool* typbyval);
extern void get_typlenbyvalalign(Oid typid, int16* typlen, bool* typbyval, char* typalign);

extern TupleDesc RelationNameGetTupleDesc(const char* relname);
extern AttInMetadata* TupleDescGetAttInMetadata(TupleDesc tupdesc);
extern HeapTuple BuildTupleFromCStrings(AttInMetadata* attinmeta, char** values);
extern void heap_freetuple(HeapTuple htup);
extern ArrayType* construct_array(Datum* elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign);
#define ARR_ELEMTYPE(a) ((a)->elemtype)

#if POSTGIS_GSSQL_VERSION == 210
extern int32 pg_atoi(char *s, int size, int c, bool b = false);
#else
extern int32 pg_atoi(char *s, int size, int c, bool b = false);
#endif
extern void* SPI_palloc(Size size);
typedef bool (*GucStringCheckHook)(char** newval, void** extra, GucSource source);
typedef const char* (*GucShowHook)(void);

extern int SPI_fnumber(TupleDesc tupdesc, const char* fname);

extern ArrayBuildState* accumArrayResult(
    ArrayBuildState* astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext);

extern Datum makeMdArrayResult(
    ArrayBuildState* astate, int ndims, int* dims, int* lbs, MemoryContext rcontext, bool release);

extern Datum regclassin(PG_FUNCTION_ARGS);

extern void examine_variable(PlannerInfo* root, Node* node, int varRelid, VariableStatData* vardata);

#define PointerIsValid(pointer) ((const void*)(pointer) != NULL)
#define HeapTupleIsValid(tuple) PointerIsValid(tuple)

#define ReleaseVariableStats(vardata)                    \
    do {                                                 \
        if (HeapTupleIsValid((vardata).statsTuple))      \
            (*(vardata).freefunc)((vardata).statsTuple); \
    } while (0)

extern FuncCallContext* init_MultiFuncCall(PG_FUNCTION_ARGS);
extern FuncCallContext* per_MultiFuncCall(PG_FUNCTION_ARGS);
extern void end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext* funcctx);

#define PG_WINDOW_OBJECT() ((WindowObject)fcinfo->context)

#define WindowObjectIsValid(winobj) ((winobj) != NULL && IsA(winobj, WindowObjectData))

extern void* WinGetPartitionLocalMemory(WindowObject winobj, Size sz);

extern int64 WinGetCurrentPosition(WindowObject winobj);
extern int64 WinGetPartitionRowCount(WindowObject winobj);

extern void WinSetMarkPosition(WindowObject winobj, int64 markpos);

extern bool WinRowsArePeers(WindowObject winobj, int64 pos1, int64 pos2);

extern Datum WinGetFuncArgInPartition(
    WindowObject winobj, int argno, int relpos, int seektype, bool set_mark, bool* isnull, bool* isout);

extern Datum WinGetFuncArgInFrame(
    WindowObject winobj, int argno, int relpos, int seektype, bool set_mark, bool* isnull, bool* isout);

extern Datum WinGetFuncArgCurrent(WindowObject winobj, int argno, bool* isnull);

/* funcapi.h */
#define SRF_IS_FIRSTCALL() (fcinfo->flinfo->fn_extra == NULL)
#define SRF_FIRSTCALL_INIT() init_MultiFuncCall(fcinfo)
#define SRF_PERCALL_SETUP() per_MultiFuncCall(fcinfo)
#define SRF_RETURN_NEXT(_funcctx, _result)        \
    do {                                          \
        ReturnSetInfo* rsi;                       \
        (_funcctx)->call_cntr++;                  \
        rsi = (ReturnSetInfo*)fcinfo->resultinfo; \
        rsi->isDone = ExprMultipleResult;         \
        PG_RETURN_DATUM(_result);                 \
    } while (0)
#define SRF_RETURN_DONE(_funcctx)                 \
    do {                                          \
        ReturnSetInfo* rsi;                       \
        end_MultiFuncCall(fcinfo, _funcctx);      \
        rsi = (ReturnSetInfo*)fcinfo->resultinfo; \
        rsi->isDone = ExprEndResult;              \
        PG_RETURN_NULL();                         \
    } while (0)

#define gistentryinit(e, k, r, pg, o, l) \
    do {                                 \
        (e).key = (k);                   \
        (e).rel = (r);                   \
        (e).page = (pg);                 \
        (e).offset = (o);                \
        (e).leafkey = (l);               \
    } while (0)

#define PageGetSpecialPointer(page) \
    (AssertMacro(PageIsValid(page)), (char*)((char*)(page) + ((PageHeader)(page))->pd_special))

#define GistPageGetOpaque(page) ((GISTPageOpaque)PageGetSpecialPointer(page))

#define F_LEAF (1 << 0) /* leaf page */
#define GistPageIsLeaf(page) (GistPageGetOpaque(page)->flags & F_LEAF)
#define GIST_LEAF(entry) (GistPageIsLeaf((entry)->page))

#define InvalidOffsetNumber ((OffsetNumber)0)
#define FirstOffsetNumber ((OffsetNumber)1)

#define OffsetNumberNext(offsetNumber) ((OffsetNumber)(1 + (offsetNumber)))

extern bool get_attstatsslot(HeapTuple statstuple, Oid atttype, int32 atttypmod, int reqkind, Oid reqop, Oid* actualop,
    Datum** values, int* nvalues, float4** numbers, int* nnumbers);

extern void free_attstatsslot(Oid atttype, Datum* values, int nvalues, float4* numbers, int nnumbers);

extern AttrNumber get_attnum(Oid relid, const char* attname);

#define rt_fetch(rangetable_index, rangetable) ((RangeTblEntry*)list_nth(rangetable, (rangetable_index)-1))

#define getrelid(rangeindex, rangetable) (rt_fetch(rangeindex, rangetable)->relid)

extern void vacuum_delay_point(void);

extern char* get_rel_name(Oid relid);

extern THR_LOCAL PGDLLIMPORT int default_statistics_target;

extern Datum GetAttributeByNum(HeapTupleHeader tuple, AttrNumber attrno, bool* isNull);
extern Datum GetAttributeByName(HeapTupleHeader tuple, const char* attname, bool* isNull);

#define CStringGetTextDatum(s) PointerGetDatum(cstring_to_text(s))

#endif /* EXTENSION_DEPENDENCY */