e141697d创建于 2025年5月16日历史提交
/* -------------------------------------------------------------------------
 *
 * fmgr.h
 *	  Definitions for the openGauss function manager and function-call
 *	  interface.
 *
 * This file must be included by all openGauss modules that either define
 * or call fmgr-callable functions.
 *
 *
 * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/fmgr.h
 *
 * -------------------------------------------------------------------------
 */
#ifndef FMGR_H
#define FMGR_H

#if defined(FRONTEND_PARSER)
#include "postgres_fe.h"
#else
#include "postgres.h"
#endif // FRONTEND_PARSER
#include "fmgr/fmgr_comp.h"
#include "fmgr/fmgr_core.h"
#include "lib/stringinfo.h"
#include "access/tupdesc.h"
#include "nodes/primnodes.h"

#ifndef FRONTEND_PARSER

typedef ScalarVector* (*VectorFunction)(FunctionCallInfo fcinfo);
typedef Datum (*GenericArgExtract)(Datum* data);

extern void InitFuncCallUDFInfo(FunctionCallInfoData* fcinfo, int argN, bool setFuncPtr);
extern void InitFunctionCallUDFArgs(FunctionCallInfoData* fcinfo, int argN, int batchRows);
extern void FreeFuncCallUDFInfo(FunctionCallInfoData* Fcinfo);

#define VECTOR_GENERIC_FUNCTION_PREALLOCED_ARGS 32
#define VECTOR_GENERIC_FUNCTION_INCREMENTAL_ARGS 10

struct GenericFunRuntimeArg {
    ScalarVector** arg;
    Oid argType;
    GenericArgExtract getArgFun;
};

struct GenericFunRuntime {
    /* maxium number of the arguements can be stored */
    uint16 compacity;

    /* pointer to the address of the real arg */
    GenericFunRuntimeArg* args;
    Datum* inputargs;
    bool* nulls;

    bool restrictFlag[BatchMaxSize];
    FunctionCallInfoData* internalFinfo;
};
/*
 * This struct holds the system-catalog information that must be looked up
 * before a function can be called through fmgr.  If the same function is
 * to be called multiple times, the lookup need be done only once and the
 * info struct saved for re-use.
 *
 * Note that fn_expr really is parse-time-determined information about the
 * arguments, rather than about the function itself.  But it's convenient
 * to store it here rather than in FunctionCallInfoData, where it might more
 * logically belong.
 */
typedef struct FmgrInfo {
    PGFunction fn_addr;       /* pointer to function or handler to be called */
    Oid fn_oid;               /* OID of function (NOT of handler, if any) */
    short fn_nargs;           /* 0..FUNC_MAX_ARGS, or -1 if variable arg
                               * count */
    bool fn_strict;           /* function is "strict" (NULL in => NULL out) */
    bool fn_retset;           /* function returns a set */
    unsigned char fn_stats;   /* collect stats if track_functions > this */
    void* fn_extra;           /* extra space for use by handler */
    MemoryContext fn_mcxt;    /* memory context to store fn_extra in */
    fmNodePtr fn_expr;        /* expression parse tree for call, or NULL */
    Oid fn_rettype;           // Oid of function return type
    Oid fn_rettypemod;        /* Oid of the function returnt typmod */
    char fnName[NAMEDATALEN]; /* function name */
    char* fnLibPath;          /* library path for c-udf
                               * package.class.method(args) for java-udf */
    bool fn_fenced;
    Oid fn_languageId; /* function language id*/
    char fn_volatile;  /* procvolatile */
    // Vector Function
    VectorFunction vec_fn_addr;
    VectorFunction* vec_fn_cache;
    GenericFunRuntime* genericRuntime;
} FmgrInfo;

/*
 * number of prealloced arguments to a function.
 * In deepsql (SVM and elastic_net), we cannot explicitly set all elements to false.
 */
#define FUNC_PREALLOCED_ARGS 10

typedef struct UDFInfoType {
    UDFArgsFuncType* UDFArgsHandlerPtr; /* UDF send/recv argument function */
    UDFArgsFuncType UDFResultHandlerPtr;
    StringInfo udfMsgBuf;
    char* msgReadPtr;
    int argBatchRows;
    int allocRows;
    Datum** arg;
    bool** null;
    Datum* result;
    bool* resultIsNull;
    bool valid_UDFArgsHandlerPtr; /* True if funcUDFArgs are filled ok */

    UDFInfoType()
    {
        udfMsgBuf = NULL;
        msgReadPtr = NULL;
        arg = NULL;
        null = NULL;
        result = NULL;
        resultIsNull = NULL;
        UDFArgsHandlerPtr = NULL;
        UDFResultHandlerPtr = NULL;
        valid_UDFArgsHandlerPtr = false;
        allocRows = 0;
        argBatchRows = 0;
    }
} UDFInfoType;

typedef struct RefcusorInfoData {
    Cursor_Data* argCursor;
    Cursor_Data* returnCursor;
    int return_number;
} RefcusorInfoData;

/*
 * start-with support
 *
 * Note, need revisit. Basically, we don't want feature oriented stuffs put here
 */
typedef struct StartWithFuncEvalInfo
{
    Node   *sw_econtext;
    Node   *sw_exprstate;
    bool   sw_is_flt_frame;
} StartWithFuncEvalInfo;

/*
 * This struct is the data actually passed to an fmgr-called function.
 */
typedef struct FunctionCallInfoData {
    FmgrInfo* flinfo;                            /* ptr to lookup info used for this call */
    fmNodePtr context;                           /* pass info about context of call */
    fmNodePtr resultinfo;                        /* pass or return extra info about result */
    Oid fncollation;                             /* collation for function to use */
    bool isnull;                                 /* function must set true if result is NULL */
    bool can_ignore;                             /* function can ignore overflow or underflow conditions for type transform function */
    short nargs;                                 /* # arguments actually passed */
    Datum* arg;                                  /* Arguments passed to function */
    bool* argnull;                               /* T if arg[i] is actually NULL */
    Oid* argTypes;                               /* Argument type */
    Datum prealloc_arg[FUNC_PREALLOCED_ARGS];    /* prealloced arguments.*/
    bool prealloc_argnull[FUNC_PREALLOCED_ARGS]; /* prealloced argument null flags.*/
    Oid prealloc_argTypes[FUNC_PREALLOCED_ARGS] = {InvalidOid}; /* prealloced argument type */
    ScalarVector* argVector;                     /* Scalar Vector */
    RefcusorInfoData refcursor_data;
    UDFInfoType udfInfo;
    StartWithFuncEvalInfo  swinfo;
    CoercionContext ccontext;
    bool is_plpgsql_language_function_with_outparam;

    FunctionCallInfoData()
    {
        flinfo = NULL;
        arg = NULL;
        argnull = NULL;
        argTypes = NULL;
        argVector = NULL;
        fncollation = 0;
        context = NULL;
        resultinfo = NULL;
        nargs = 0;
        isnull = false;
        can_ignore = false;
        ccontext = COERCION_UNKNOWN;
        is_plpgsql_language_function_with_outparam = false;
    }
} FunctionCallInfoData;

/*
 * List of dynamically loaded files (kept in malloc'd memory).
 */

typedef struct df_files {
    struct df_files* next; /* List link */
    dev_t device;          /* Device file is on */
#ifndef WIN32              /* ensures we never again depend on this under \
                            * win32 */
    ino_t inode;           /* Inode number of file */
#endif
    void* handle;                         /* a handle for pg_dl* functions */
    char filename[FLEXIBLE_ARRAY_MEMBER]; /* Full pathname of file */

    /*
     * we allocate the block big enough for actual length of pathname.
     * filename[] must be last item in struct!
     */
} DynamicFileList;

/*Introduced to judge whether PG_init has done or not*/
typedef struct df_files_init {
    struct df_files_init* next; /*List Link*/
    DynamicFileList* file_list; /*restore file_list in the linked list*/
} FileListInit;

extern DynamicFileList* file_list;
extern DynamicFileList* file_tail;

#define EXTRA_NARGS 3

extern bool directory_exists(const char* direct);
extern bool file_exists(const char* name);
/*
 * This routine fills a FmgrInfo struct, given the OID
 * of the function to be called.
 */
extern void fmgr_info(Oid functionId, FmgrInfo* finfo);

/*
 * Same, when the FmgrInfo struct is in a memory context longer-lived than
 * CurrentMemoryContext.  The specified context will be set as fn_mcxt
 * and used to hold all subsidiary data of finfo.
 */
extern void fmgr_info_cxt(Oid functionId, FmgrInfo* finfo, MemoryContext mcxt);

extern void InitVecFunctionCallInfoData(
    FunctionCallInfoData* Fcinfo, FmgrInfo* Flinfo, int Nargs, Oid Collation, fmNodePtr Context, fmNodePtr Resultinfo);

/* Convenience macro for setting the fn_expr field */
#define fmgr_info_set_expr(expr, finfo) ((finfo)->fn_expr = (expr))

/*
 * Copy an FmgrInfo struct
 */
extern void fmgr_info_copy(FmgrInfo* dstinfo, FmgrInfo* srcinfo, MemoryContext destcxt);

/*
 * This macro initializes all the fields of a GenericFunRuntime except
 * for the all the prealloc arrays.	Performance testing has shown that
 * the fastest way to set up static arrays for small numbers of arguments is to
 * explicitly set each required element to false, so we don't try to zero
 * out the static prealloc array in the macro.
 */

#define InitGenericFunRuntimeInfo(GenericRuntime, Nargs)                                                            \
    do {                                                                                                            \
        (GenericRuntime).compacity = VECTOR_GENERIC_FUNCTION_PREALLOCED_ARGS;                                       \
        if (unlikely((Nargs) > VECTOR_GENERIC_FUNCTION_PREALLOCED_ARGS)) {                                          \
            (GenericRuntime).compacity +=                                                                           \
                (((Nargs)-VECTOR_GENERIC_FUNCTION_PREALLOCED_ARGS - 1) / VECTOR_GENERIC_FUNCTION_INCREMENTAL_ARGS + \
                    1) *                                                                                            \
                VECTOR_GENERIC_FUNCTION_INCREMENTAL_ARGS;                                                           \
        }                                                                                                           \
        (GenericRuntime).args =                                                                                     \
            (GenericFunRuntimeArg*)palloc0(sizeof(GenericFunRuntimeArg) * (GenericRuntime).compacity);              \
        (GenericRuntime).inputargs = (Datum*)palloc0(sizeof(Datum) * (GenericRuntime).compacity);                   \
        (GenericRuntime).nulls = (bool*)palloc0(sizeof(bool) * (GenericRuntime).compacity);                         \
    } while (0)

#define FreeGenericFunRuntimeInfo(GenericRuntime)                        \
    do {                                                                 \
        pfree_ext((GenericRuntime).args);                                \
        pfree_ext((GenericRuntime).inputargs);                           \
        pfree_ext((GenericRuntime).nulls);                               \
        if (unlikely((GenericRuntime).internalFinfo != NULL))            \
            FreeFunctionCallInfoData(*((GenericRuntime).internalFinfo)); \
        (GenericRuntime).compacity = 0;                                  \
    } while (0)

/*
 * This macro initializes all the fields of a FunctionCallInfoData except
 * for the arg[] and argnull[] arrays.	Performance testing has shown that
 * the fastest way to set up argnull[] for small numbers of arguments is to
 * explicitly set each required element to false, so we don't try to zero
 * out the argnull[] array in the macro.
 */
#define InitFunctionCallInfoArgs(Fcinfo, Nargs, batchRow)             \
    do {                                                              \
        (Fcinfo).nargs = (Nargs);                                     \
        if ((Nargs) > FUNC_PREALLOCED_ARGS) {                         \
            (Fcinfo).arg = (Datum*)palloc0((Nargs) * sizeof(Datum));  \
            (Fcinfo).argnull = (bool*)palloc0(Nargs * sizeof(bool));  \
            (Fcinfo).argTypes = (Oid*)palloc0((Nargs) * sizeof(Oid)); \
        } else {                                                      \
            (Fcinfo).arg = (Fcinfo).prealloc_arg;                     \
            (Fcinfo).argnull = (Fcinfo).prealloc_argnull;             \
            (Fcinfo).argTypes = (Fcinfo).prealloc_argTypes;           \
        }                                                             \
        if (unlikely((Fcinfo).flinfo && (Fcinfo).flinfo->fn_fenced))  \
            InitFunctionCallUDFArgs(&(Fcinfo), (Nargs), (batchRow));  \
    } while (0)

#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo) \
    do {                                                                                \
        (Fcinfo).flinfo = (Flinfo);                                                     \
        (Fcinfo).context = (Context);                                                   \
        (Fcinfo).resultinfo = (Resultinfo);                                             \
        (Fcinfo).fncollation = (Collation);                                             \
        (Fcinfo).isnull = false;                                                        \
        (Fcinfo).nargs = (Nargs);                                                       \
        if (unlikely((Nargs) > FUNC_PREALLOCED_ARGS)) {                                 \
            (Fcinfo).arg = (Datum*)palloc0((Nargs) * sizeof(Datum));                    \
            (Fcinfo).argnull = (bool*)palloc0((Nargs) * sizeof(bool));                  \
            (Fcinfo).argTypes = (Oid*)palloc0((Nargs) * sizeof(Oid));                   \
        } else {                                                                        \
            (Fcinfo).arg = (Fcinfo).prealloc_arg;                                       \
            (Fcinfo).argnull = (Fcinfo).prealloc_argnull;                               \
            (Fcinfo).argTypes = (Fcinfo).prealloc_argTypes;                             \
        }                                                                               \
        if (unlikely((Flinfo) != NULL && (Fcinfo).flinfo->fn_fenced))                   \
            InitFuncCallUDFInfo(&(Fcinfo), (Nargs), false);                             \
        (Fcinfo).refcursor_data.argCursor = NULL;                                       \
        (Fcinfo).refcursor_data.returnCursor = NULL;                                    \
        (Fcinfo).refcursor_data.return_number = 0;                                      \
    } while (0)

#define FreeFunctionCallInfoData(Fcinfo)             \
    do {                                             \
        if ((Fcinfo).nargs > FUNC_PREALLOCED_ARGS) { \
            pfree((Fcinfo).arg);                     \
            pfree((Fcinfo).argnull);                 \
            pfree((Fcinfo).argTypes);                \
            (Fcinfo).argTypes = NULL;                \
            (Fcinfo).arg = NULL;                     \
            (Fcinfo).argnull = NULL;                 \
        }                                            \
        FreeFuncCallUDFInfo(&(Fcinfo));              \
    } while (0)
/*
 * This macro invokes a function given a filled-in FunctionCallInfoData
 * struct.	The macro result is the returned Datum --- but note that
 * caller must still check fcinfo->isnull!	Also, if function is strict,
 * it is caller's responsibility to verify that no null arguments are present
 * before calling.
 */
#define FunctionCallInvoke(fcinfo) ((*(fcinfo)->flinfo->fn_addr)(fcinfo))

#define VecFunctionCallInvoke(fcinfo) ((*(fcinfo)->flinfo->vec_fn_addr)(fcinfo))

/* -------------------------------------------------------------------------
 *		Support for detecting call convention of dynamically-loaded functions
 *
 * Dynamically loaded functions may use either the version-1 ("new style")
 * or version-0 ("old style") calling convention.  Version 1 is the call
 * convention defined in this header file; version 0 is the old "plain C"
 * convention.	A version-1 function must be accompanied by the macro call
 *
 *		PG_FUNCTION_INFO_V1(function_name);
 *
 * Note that internal functions do not need this decoration since they are
 * assumed to be version-1.
 *
 * -------------------------------------------------------------------------
 */

typedef struct {
    int api_version; /* specifies call convention version number */
                     /* More fields may be added later, for version numbers > 1. */
} Pg_finfo_record;

/* Expected signature of an info function */
typedef const Pg_finfo_record* (*PGFInfoFunction)(void);

/*
 *	Macro to build an info function associated with the given function name.
 *	Win32 loadable functions usually link with 'dlltool --export-all', but it
 *	doesn't hurt to add PGDLLIMPORT in case they don't.
 */
#define PG_FUNCTION_INFO_V1(funcname)                                                   \
    extern "C" PGDLLEXPORT const Pg_finfo_record* CppConcat(pg_finfo_, funcname)(void); \
    const Pg_finfo_record* CppConcat(pg_finfo_, funcname)(void)                         \
    {                                                                                   \
        static const Pg_finfo_record my_finfo = {1};                                    \
        return &my_finfo;                                                               \
    }                                                                                   \
    extern int no_such_variable

/* -------------------------------------------------------------------------
 *		Support for verifying backend compatibility of loaded modules
 *
 * We require dynamically-loaded modules to include the macro call
 *		PG_MODULE_MAGIC;
 * so that we can check for obvious incompatibility, such as being compiled
 * for a different major openGauss version.
 *
 * To compile with versions of openGauss that do not support this,
 * you may put an #ifdef/#endif test around it.  Note that in a multiple-
 * source-file module, the macro call should only appear once.
 *
 * The specific items included in the magic block are intended to be ones that
 * are custom-configurable and especially likely to break dynamically loaded
 * modules if they were compiled with other values.  Also, the length field
 * can be used to detect definition changes.
 *
 * Note: we compare magic blocks with memcmp(), so there had better not be
 * any alignment pad bytes in them.
 *
 * Note: when changing the contents of magic blocks, be sure to adjust the
 * incompatible_module_error() function in dfmgr.c.
 * -------------------------------------------------------------------------
 */

/* Definition of the magic block structure */
typedef struct {
    int len;          /* sizeof(this struct) */
    int version;      /* PostgreSQL major version */
    int funcmaxargs;  /* FUNC_MAX_ARGS */
    int indexmaxkeys; /* INDEX_MAX_KEYS */
    int namedatalen;  /* NAMEDATALEN */
    int float4byval;  /* FLOAT4PASSBYVAL */
    int float8byval;  /* FLOAT8PASSBYVAL */
} Pg_magic_struct;

/* The actual data block contents */
#define PG_MODULE_MAGIC_DATA                                                                                        \
    {                                                                                                               \
        sizeof(Pg_magic_struct), PG_VERSION_NUM / 100, FUNC_MAX_ARGS, INDEX_MAX_KEYS, NAMEDATALEN, FLOAT4PASSBYVAL, \
            FLOAT8PASSBYVAL                                                                                         \
    }

/*
 * Declare the module magic function.  It needs to be a function as the dlsym
 * in the backend is only guaranteed to work on functions, not data
 */
typedef const Pg_magic_struct* (*PGModuleMagicFunction)(void);

#define PG_MAGIC_FUNCTION_NAME Pg_magic_func
#define PG_MAGIC_FUNCTION_NAME_STRING "Pg_magic_func"

#define PG_MODULE_MAGIC                                                         \
    extern "C" PGDLLEXPORT const Pg_magic_struct* PG_MAGIC_FUNCTION_NAME(void); \
    const Pg_magic_struct* PG_MAGIC_FUNCTION_NAME(void)                         \
    {                                                                           \
        static const Pg_magic_struct Pg_magic_data = PG_MODULE_MAGIC_DATA;      \
        return &Pg_magic_data;                                                  \
    }                                                                           \
    extern int no_such_variable

/* -------------------------------------------------------------------------
 *		Support routines and macros for callers of fmgr-compatible functions
 * -------------------------------------------------------------------------
 */

/* These are for invocation of a specifically named function with a
 * directly-computed parameter list.  Note that neither arguments nor result
 * are allowed to be NULL.
 */
extern Datum DirectFunctionCall1Coll(PGFunction func, Oid collation, Datum arg1, bool can_ignore = false);
extern Datum DirectFunctionCall2Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, bool can_ignore = false);
extern Datum DirectFunctionCall3Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3,
    bool can_ignore = false);
extern Datum DirectFunctionCall4Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4,
    bool can_ignore = false);
extern Datum DirectFunctionCall5Coll(
    PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5,
    bool can_ignore = false);
extern Datum DirectFunctionCall6Coll(
    PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6,
    bool can_ignore = false);
extern Datum DirectFunctionCall7Coll(
    PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7,
    bool can_ignore = false);
extern Datum DirectFunctionCall8Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4,
    Datum arg5, Datum arg6, Datum arg7, Datum arg8, bool can_ignore = false);
extern Datum DirectFunctionCall9Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4,
    Datum arg5, Datum arg6, Datum arg7, Datum arg8, Datum arg9, bool can_ignore = false);

/* These are for invocation of a previously-looked-up function with a
 * directly-computed parameter list.  Note that neither arguments nor result
 * are allowed to be NULL.
 */
extern Datum FunctionCall1Coll(FmgrInfo* flinfo, Oid collation, Datum arg1);
extern Datum FunctionCall2Coll(FmgrInfo* flinfo, Oid collation, Datum arg1, Datum arg2);
extern Datum FunctionCall3Coll(FmgrInfo* flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3);
extern Datum FunctionCall4Coll(FmgrInfo* flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4);
extern Datum FunctionCall5Coll(
    FmgrInfo* flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5);
extern Datum FunctionCall6Coll(
    FmgrInfo* flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6);
extern Datum FunctionCall7Coll(FmgrInfo* flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4,
    Datum arg5, Datum arg6, Datum arg7);
extern Datum FunctionCall8Coll(FmgrInfo* flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4,
    Datum arg5, Datum arg6, Datum arg7, Datum arg8);
extern Datum FunctionCall9Coll(FmgrInfo* flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4,
    Datum arg5, Datum arg6, Datum arg7, Datum arg8, Datum arg9);

/* These are for invocation of a function identified by OID with a
 * directly-computed parameter list.  Note that neither arguments nor result
 * are allowed to be NULL.	These are essentially FunctionLookup() followed
 * by FunctionCallN().	If the same function is to be invoked repeatedly,
 * do the FunctionLookup() once and then use FunctionCallN().
 */
extern Datum OidFunctionCall0Coll(Oid functionId, Oid collation, bool can_ignore = false);
extern Datum OidFunctionCall1Coll(Oid functionId, Oid collation, Datum arg1, bool can_ignore = false);
extern Datum OidFunctionCall2Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, bool can_ignore = false);
extern Datum OidFunctionCall3Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, Datum arg3, 
    bool can_ignore = false);
extern Datum OidFunctionCall4Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4,
    bool can_ignore = false);
extern Datum OidFunctionCall5Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4,
    Datum arg5, bool can_ignore = false);
extern Datum OidFunctionCall6Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4,
    Datum arg5, Datum arg6, bool can_ignore = false);
extern Datum OidFunctionCall7Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4,
    Datum arg5, Datum arg6, Datum arg7, bool can_ignore = false);
extern Datum OidFunctionCall8Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4,
    Datum arg5, Datum arg6, Datum arg7, Datum arg8, bool can_ignore = false);
extern Datum OidFunctionCall9Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4,
    Datum arg5, Datum arg6, Datum arg7, Datum arg8, Datum arg9, bool can_ignore = false);

/* These macros allow the collation argument to be omitted (with a default of
 * InvalidOid, ie, no collation).  They exist mostly for backwards
 * compatibility of source code.
 */
#define DirectFunctionCall1(func, arg1) DirectFunctionCall1Coll(func, InvalidOid, arg1)
#define DirectFunctionCall2(func, arg1, arg2) DirectFunctionCall2Coll(func, InvalidOid, arg1, arg2)
#define DirectFunctionCall3(func, arg1, arg2, arg3) DirectFunctionCall3Coll(func, InvalidOid, arg1, arg2, arg3)
#define DirectFunctionCall4(func, arg1, arg2, arg3, arg4) \
    DirectFunctionCall4Coll(func, InvalidOid, arg1, arg2, arg3, arg4)
#define DirectFunctionCall5(func, arg1, arg2, arg3, arg4, arg5) \
    DirectFunctionCall5Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5)
#define DirectFunctionCall6(func, arg1, arg2, arg3, arg4, arg5, arg6) \
    DirectFunctionCall6Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6)
#define DirectFunctionCall7(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
    DirectFunctionCall7Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
#define DirectFunctionCall8(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
    DirectFunctionCall8Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
#define DirectFunctionCall9(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \
    DirectFunctionCall9Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
#define FunctionCall1(flinfo, arg1) FunctionCall1Coll(flinfo, InvalidOid, arg1)
#define FunctionCall2(flinfo, arg1, arg2) FunctionCall2Coll(flinfo, InvalidOid, arg1, arg2)
#define FunctionCall3(flinfo, arg1, arg2, arg3) FunctionCall3Coll(flinfo, InvalidOid, arg1, arg2, arg3)
#define FunctionCall4(flinfo, arg1, arg2, arg3, arg4) FunctionCall4Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4)
#define FunctionCall5(flinfo, arg1, arg2, arg3, arg4, arg5) \
    FunctionCall5Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5)
#define FunctionCall6(flinfo, arg1, arg2, arg3, arg4, arg5, arg6) \
    FunctionCall6Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6)
#define FunctionCall7(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
    FunctionCall7Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
#define FunctionCall8(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
    FunctionCall8Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
#define FunctionCall9(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \
    FunctionCall9Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
#define OidFunctionCall0(functionId) OidFunctionCall0Coll(functionId, InvalidOid)
#define OidFunctionCall1(functionId, arg1) OidFunctionCall1Coll(functionId, InvalidOid, arg1)
#define OidFunctionCall2(functionId, arg1, arg2) OidFunctionCall2Coll(functionId, InvalidOid, arg1, arg2)
#define OidFunctionCall3(functionId, arg1, arg2, arg3) OidFunctionCall3Coll(functionId, InvalidOid, arg1, arg2, arg3)
#define OidFunctionCall4(functionId, arg1, arg2, arg3, arg4) \
    OidFunctionCall4Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4)
#define OidFunctionCall5(functionId, arg1, arg2, arg3, arg4, arg5) \
    OidFunctionCall5Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5)
#define OidFunctionCall6(functionId, arg1, arg2, arg3, arg4, arg5, arg6) \
    OidFunctionCall6Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6)
#define OidFunctionCall7(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
    OidFunctionCall7Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
#define OidFunctionCall8(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
    OidFunctionCall8Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
#define OidFunctionCall9(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \
    OidFunctionCall9Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)

typedef struct {
    PGFunction user_fn;             /* the function's address */
    const Pg_finfo_record* inforec; /* address of its info record */
} CFunInfo;

/* Special cases for convenient invocation of datatype I/O functions. */
extern Datum InputFunctionCall(FmgrInfo* flinfo, char* str, Oid typioparam, int32 typmod, bool can_ignore = false, Oid collation = InvalidOid);
extern Datum InputFunctionCallForDateType(
    FmgrInfo* flinfo, char* str, Oid typioparam, int32 typmod, char* date_time_fmt);
extern Datum OidInputFunctionCall(Oid functionId, char* str, Oid typioparam, int32 typmod, bool can_ignore = false);
extern char* OutputFunctionCall(FmgrInfo* flinfo, Datum val);
extern char* OidOutputFunctionCall(Oid functionId, Datum val);
extern Datum ReceiveFunctionCall(FmgrInfo* flinfo, fmStringInfo buf, Oid typioparam, int32 typmod);
extern Datum OidReceiveFunctionCall(Oid functionId, fmStringInfo buf, Oid typioparam, int32 typmod);
extern bytea* SendFunctionCall(FmgrInfo* flinfo, Datum val);
extern bytea* OidSendFunctionCall(Oid functionId, Datum val);
extern Datum OidInputFunctionCallColl(Oid functionId, char* str, Oid typioparam, int32 typmod, Oid collation);

/*
 * Routines in fmgr.c
 */
extern const Pg_finfo_record* fetch_finfo_record(void* filehandle, char* funcname, bool isValidate);
extern void clear_external_function_hash(void* filehandle);
extern Oid fmgr_internal_function(const char* proname);
extern Oid get_fn_expr_rettype(FmgrInfo* flinfo);
extern Oid get_fn_expr_argtype(FmgrInfo* flinfo, int argnum);
extern Oid get_call_expr_argtype(fmNodePtr expr, int argnum);
extern bool get_fn_expr_arg_stable(FmgrInfo* flinfo, int argnum);
extern bool get_call_expr_arg_stable(fmNodePtr expr, int argnum);
extern bool get_fn_expr_variadic(FmgrInfo* flinfo);
extern bool CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid);

extern PGFunction lookup_C_func_by_oid(Oid fn_oid, char* probin, char* prosrc);

extern void check_external_function(const char* filepath, const char* filename, const char* funcname);
extern CFunInfo load_external_function(const char* filename, char* funcname, bool signalNotFound, bool isValidate);
extern char* expand_dynamic_library_name(const char* name);
extern PGFunction lookup_external_function(void* filehandle, const char* funcname);
extern void load_file(const char* filename, bool restricted);
extern void** find_rendezvous_variable(const char* varName);

/*
 * Support for aggregate functions
 *
 * This is actually in executor/nodeAgg.c, but we declare it here since the
 * whole point is for callers of it to not be overly friendly with nodeAgg.
 */

/* AggCheckCallContext can return one of the following codes, or 0: */
#define AGG_CONTEXT_AGGREGATE 1 /* regular aggregate */
#define AGG_CONTEXT_WINDOW 2    /* window function */

extern int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext* aggcontext);

typedef struct Aggref *fmAggrefPtr;
typedef struct ExprContext *fmExprContextPtr;
extern fmAggrefPtr AggGetAggref(FunctionCallInfo fcinfo);
extern fmExprContextPtr AggGetPerTupleEContext(FunctionCallInfo fcinfo);
extern fmExprContextPtr AggGetPerAggEContext(FunctionCallInfo fcinfo);
/*
 * We allow plugin modules to hook function entry/exit.  This is intended
 * as support for loadable security policy modules, which may want to
 * perform additional privilege checks on function entry or exit, or to do
 * other internal bookkeeping.	To make this possible, such modules must be
 * able not only to support normal function entry and exit, but also to trap
 * the case where we bail out due to an error; and they must also be able to
 * prevent inlining.
 */
typedef enum FmgrHookEventType { FHET_START, FHET_END, FHET_ABORT } FmgrHookEventType;

typedef bool (*needs_fmgr_hook_type)(Oid fn_oid);

typedef void (*fmgr_hook_type)(FmgrHookEventType event, FmgrInfo* flinfo, Datum* arg);

extern THR_LOCAL PGDLLIMPORT needs_fmgr_hook_type needs_fmgr_hook;
extern THR_LOCAL PGDLLIMPORT fmgr_hook_type fmgr_hook;

#define FmgrHookIsNeeded(fn_oid) (!needs_fmgr_hook ? false : (*needs_fmgr_hook)(fn_oid))

// Define common stuff for vectorized expression //
typedef enum SimpleOp {
    SOP_EQ,   // =
    SOP_NEQ,  // !=
    SOP_LE,   // <=
    SOP_LT,   // <
    SOP_GE,   // >=
    SOP_GT,   // >
} SimpleOp;

template <SimpleOp sop, typename Datatype>
inline bool eval_simple_op(Datatype dataVal1, Datatype dataVal2)
{
    if (sop == SOP_EQ)
        return ((dataVal1) == (dataVal2));
    if (sop == SOP_NEQ)
        return ((dataVal1) != (dataVal2));
    if (sop == SOP_LE)
        return ((dataVal1) <= (dataVal2));
    if (sop == SOP_LT)
        return ((dataVal1) < (dataVal2));
    if (sop == SOP_GE)
        return ((dataVal1) >= (dataVal2));
    if (sop == SOP_GT)
        return ((dataVal1) > (dataVal2));
    return false;
}

#endif /* !FRONTEND_PARSER */

extern void CopyCursorInfoData(Cursor_Data* target_data, Cursor_Data* source_data);

#endif /* FMGR_H */