/*
 * src/test/regress/regress.c
 */

#include "postgres.h"
#include "knl/knl_variable.h"

#include <float.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "c.h"

#include "fmgr.h"
#include "libpq/pqformat.h"
#include "stdio.h"

#include "nodes/parsenodes.h"
#include "utils/date.h"
#include "utils/datetime.h"

#include "access/transam.h"
#include "access/tuptoaster.h"
#include "access/xact.h"
#include "catalog/pg_type.h"
#include "commands/sequence.h"
#include "commands/trigger.h"
#include "executor/executor.h"
#include "executor/spi.h"
#include "utils/atomic.h"
#include "utils/builtins.h"
#include "utils/geo_decls.h"
#include "utils/rel.h"
#include "utils/rel_gs.h"
#include "utils/typcache.h"
#include "utils/memutils.h"

#define P_MAXDIG 12
#define LDELIM '('
#define RDELIM ')'
#define DELIM ','

#define IsNull -1
#define IsNotNull 0
#define Multiplier_J 10000
#define LastDay(y, m) (((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) ? LastDaysL[m] : LastDays[m])
extern "C" Datum regress_dist_ptpath(PG_FUNCTION_ARGS);
extern "C" Datum regress_path_dist(PG_FUNCTION_ARGS);
extern "C" PATH* poly2path(POLYGON* poly);
extern "C" Datum interpt_pp(PG_FUNCTION_ARGS);
extern "C" void regress_lseg_construct(LSEG* lseg, Point* pt1, Point* pt2);
extern "C" Datum overpaid(PG_FUNCTION_ARGS);
extern "C" Datum boxarea(PG_FUNCTION_ARGS);
extern "C" Datum reverse_name(PG_FUNCTION_ARGS);
extern "C" Datum oldstyle_length(PG_FUNCTION_ARGS);
extern "C" Datum int44in(PG_FUNCTION_ARGS);
extern "C" Datum int44out(PG_FUNCTION_ARGS);
extern "C" Datum vec_int4add_0(PG_FUNCTION_ARGS);
extern "C" Datum vec_int4add_7(PG_FUNCTION_ARGS);
extern "C" Datum vec_int4add_8(PG_FUNCTION_ARGS);
extern "C" Datum vec_int4add_9(PG_FUNCTION_ARGS);
extern "C" Datum vec_int4add_10(PG_FUNCTION_ARGS);
extern "C" Datum vec_int4add_11(PG_FUNCTION_ARGS);
extern Datum make_tuple_indirect(PG_FUNCTION_ARGS);

/************c function overload and v0&v1 support***********/
extern "C" Datum funcA(PG_FUNCTION_ARGS);
extern "C" Datum funcB(PG_FUNCTION_ARGS);
extern "C" Datum funcC(PG_FUNCTION_ARGS);

/**************create_type check*****************************/
extern "C" Datum complex_in(PG_FUNCTION_ARGS);
extern "C" Datum complex_out(PG_FUNCTION_ARGS);
extern "C" Datum complex_recv(PG_FUNCTION_ARGS);
extern "C" Datum complex_send(PG_FUNCTION_ARGS);
extern "C" Datum query_get_unique_sql_id(PG_FUNCTION_ARGS);

/***************************UDF CREM**************************/

extern "C" {
Datum truncInt1(PG_FUNCTION_ARGS);
Datum truncInt(PG_FUNCTION_ARGS);
Datum truncDec81(PG_FUNCTION_ARGS);
Datum truncDec8(PG_FUNCTION_ARGS);
Datum truncFloat(PG_FUNCTION_ARGS);
Datum TransTimestamp(PG_FUNCTION_ARGS);
Datum TransDate(PG_FUNCTION_ARGS);
Datum signi(PG_FUNCTION_ARGS);
Datum signf(PG_FUNCTION_ARGS);
Datum RoundInt(PG_FUNCTION_ARGS);
Datum RoundFloat(PG_FUNCTION_ARGS);
Datum RoundDec8(PG_FUNCTION_ARGS);
Datum lpad_f(PG_FUNCTION_ARGS);
Datum rpad_f(PG_FUNCTION_ARGS);
Datum normsdist(PG_FUNCTION_ARGS);
Datum months_between_dd(PG_FUNCTION_ARGS);
Datum months_between_dt(PG_FUNCTION_ARGS);
Datum months_between_td(PG_FUNCTION_ARGS);
Datum months_between_tt(PG_FUNCTION_ARGS);
//	Datum FUNC_JUDGE_ACC(PG_FUNCTION_ARGS);
//	Datum FUNC_GREAST_MOB24(PG_FUNCTION_ARGS);
Datum last_day_d(PG_FUNCTION_ARGS);
Datum last_day_t(PG_FUNCTION_ARGS);
Datum last_day_tz(PG_FUNCTION_ARGS);
}

/*
extern "C"
{
    Datum FUNC_II_DIV_CL_MOB6(PG_FUNCTION_ARGS);
    Datum oadd_months_d(PG_FUNCTION_ARGS);
    Datum oadd_months_t(PG_FUNCTION_ARGS);
    Datum oadd_months_tz(PG_FUNCTION_ARGS);
    Datum ceilDec8(PG_FUNCTION_ARGS);
    Datum ceilFloat(PG_FUNCTION_ARGS);
    Datum ceilInt(PG_FUNCTION_ARGS);
    Datum FUNC_AGE_JUDGE(PG_FUNCTION_ARGS);
    Datum FUNC_CAP(PG_FUNCTION_ARGS);
    Datum FUNC_COST_SERVICE(PG_FUNCTION_ARGS);
    Datum FUNC_DIV_CIIS_DATA_100(PG_FUNCTION_ARGS);
    Datum FUNC_DIV_CIIS_DATA_ZERO(PG_FUNCTION_ARGS);
    Datum FUNC_DIV_DATA(PG_FUNCTION_ARGS);
    Datum FUNC_DIV_MOB3(PG_FUNCTION_ARGS);
    Datum FUNC_DIV_MOB6(PG_FUNCTION_ARGS);
//	Datum FUNC_DIV_MOB9(PG_FUNCTION_ARGS);
//	Datum FUNC_DIV_MOB12(PG_FUNCTION_ARGS);
//	Datum FUNC_DPT_MOB12(PG_FUNCTION_ARGS);
    Datum FUNC_DPTADD_MOB6(PG_FUNCTION_ARGS);
    Datum FUNC_FOUR_SEG(PG_FUNCTION_ARGS);
    Datum FUNC_GREAST_MOB3(PG_FUNCTION_ARGS);
    Datum FUNC_GREAST_MOB6(PG_FUNCTION_ARGS);
//	Datum FUNC_GREAST_MOB12(PG_FUNCTION_ARGS);
    Datum FUNC_II_CL_DPM_CAST(PG_FUNCTION_ARGS);
    Datum FUNC_II_DIV_MOB3(PG_FUNCTION_ARGS);
    Datum FUNC_II_DIV_MOB6(PG_FUNCTION_ARGS);
//	Datum FUNC_II_DIV_MOB9(PG_FUNCTION_ARGS);
//	Datum FUNC_II_DIV_MOB12(PG_FUNCTION_ARGS);
    Datum FUNC_II_DIV_NULL_MOB3(PG_FUNCTION_ARGS);
    Datum FUNC_II_DIV_NULL_MOB6(PG_FUNCTION_ARGS);
    Datum FUNC_II_DIV_NULL_MOB9(PG_FUNCTION_ARGS);
    Datum FUNC_II_DIV_NULL_MOB12(PG_FUNCTION_ARGS);
    Datum FUNC_II_CL_SUM_MOB3(PG_FUNCTION_ARGS);
    Datum FUNC_II_CL_SUM_MOB6(PG_FUNCTION_ARGS);
    Datum FUNC_II_DIV_CL_MOB3(PG_FUNCTION_ARGS);
    Datum FUNC_II_GREAST_MOB3(PG_FUNCTION_ARGS);
    Datum FUNC_II_GREAST_MOB6(PG_FUNCTION_ARGS);
    Datum FUNC_II_GREAST_MOB9(PG_FUNCTION_ARGS);
    Datum FUNC_II_GREAST_MOB12(PG_FUNCTION_ARGS);
    Datum FUNC_II_GREAST_VAR_MOB3(PG_FUNCTION_ARGS);
    Datum FUNC_II_GREAST_VAR_MOB6(PG_FUNCTION_ARGS);
    Datum FUNC_II_GREAST_VAR_MOB9(PG_FUNCTION_ARGS);
    Datum FUNC_II_DIV_CEIL_DATA(PG_FUNCTION_ARGS);
    Datum FUNC_II_DIV_DATA(PG_FUNCTION_ARGS);
    Datum FUNC_II_DIV_DATA_NULL(PG_FUNCTION_ARGS);
    Datum FUNC_II_DPM_QC_MIN1(PG_FUNCTION_ARGS);
    Datum FUNC_II_FLOOR_ZERO(PG_FUNCTION_ARGS);
    Datum FUNC_III_CS0507_2(PG_FUNCTION_ARGS);
}
*/

extern "C" {
//	Datum FUNC_II_GREAST_VAR_MOB12(PG_FUNCTION_ARGS);
Datum FUNC_III_CS0507_3(PG_FUNCTION_ARGS);
Datum FUNC_III_CS0507(PG_FUNCTION_ARGS);
Datum FUNC_II_JUDGE_DF_AGE(PG_FUNCTION_ARGS);
//	Datum FUNC_II_LEAST_CL_MOB6(PG_FUNCTION_ARGS);
//	Datum FUNC_II_LEAST_MOB12(PG_FUNCTION_ARGS);
//	Datum FUNC_II_LEAST_MOB3(PG_FUNCTION_ARGS);
//	Datum FUNC_II_LEAST_MOB6(PG_FUNCTION_ARGS);
//	Datum FUNC_II_LEAST_MOB9(PG_FUNCTION_ARGS);
//	Datum FUNC_II_LEAST_VAR_MOB3(PG_FUNCTION_ARGS);
//	Datum FUNC_II_SUM_MOB12(PG_FUNCTION_ARGS);
//	Datum FUNC_II_SUM_MOB9(PG_FUNCTION_ARGS);
//	Datum FUNC_II_SUM_MOB6(PG_FUNCTION_ARGS);
//	Datum FUNC_II_SUM_MOB3(PG_FUNCTION_ARGS);
//	Datum FUNC_JUDGE_ACC_3(PG_FUNCTION_ARGS);
//	Datum FUNC_JUDGE_ACC_6(PG_FUNCTION_ARGS);
//	Datum FUNC_JUDGE_ACC_9(PG_FUNCTION_ARGS);
////	Datum FUNC_JUDGE_ACC_12(PG_FUNCTION_ARGS);
////	Datum FUNC_JUDGE_ACC_15(PG_FUNCTION_ARGS);
////	Datum FUNC_JUDGE_ACC_18(PG_FUNCTION_ARGS);
////	Datum FUNC_JUDGE_ACC_21(PG_FUNCTION_ARGS);
////	Datum FUNC_JUDGE_ACC_24(PG_FUNCTION_ARGS);
//	Datum FUNC_JUDGE_EAD(PG_FUNCTION_ARGS);
//	Datum FUNC_JUDGE_NUMBER(PG_FUNCTION_ARGS);
//	Datum FUNC_LEAST_MOB3(PG_FUNCTION_ARGS);
//	Datum FUNC_LEAST_MOB6(PG_FUNCTION_ARGS);
//	Datum FUNC_LEAST_MOB9(PG_FUNCTION_ARGS);
//	Datum FUNC_MINROC_AMOUNT(PG_FUNCTION_ARGS);
//	Datum FUNC_MINROC_NUM(PG_FUNCTION_ARGS);
//	Datum FUNC_MONTH_FLAG_BANNIAN(PG_FUNCTION_ARGS);
//	Datum FUNC_MONTH_FLAG_JI(PG_FUNCTION_ARGS);
//	Datum FUNC_OVE_MONTH_CODE(PG_FUNCTION_ARGS);
//	Datum FUNC_PRICE_CODE(PG_FUNCTION_ARGS);
//	Datum FUNC_SUM_MOB3(PG_FUNCTION_ARGS);
//	Datum FUNC_SUM_MOB6(PG_FUNCTION_ARGS);
//	Datum FUNC_SUM_MOB9(PG_FUNCTION_ARGS);
//	Datum FUNC_SUM_MOB12(PG_FUNCTION_ARGS);
Datum FUNC_TRANS_MOBCODE(PG_FUNCTION_ARGS);
Datum FUNC_TRANS_RISKCODE(PG_FUNCTION_ARGS);
Datum FUNC_XW_FIX_DPD(PG_FUNCTION_ARGS);
Datum FUNC_ZERO_NULL(PG_FUNCTION_ARGS);
Datum greatestcc(PG_FUNCTION_ARGS);
Datum greatestcd(PG_FUNCTION_ARGS);
Datum greatestci(PG_FUNCTION_ARGS);
Datum greatestdc(PG_FUNCTION_ARGS);
Datum greatestdd(PG_FUNCTION_ARGS);
Datum greatestdi(PG_FUNCTION_ARGS);
Datum greatestic(PG_FUNCTION_ARGS);
Datum greatestid(PG_FUNCTION_ARGS);
}

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

PG_FUNCTION_INFO_V1(funcA);
PG_FUNCTION_INFO_V1(funcB);

/***************************UDF CREM**************************/

PG_FUNCTION_INFO_V1(truncInt1);
PG_FUNCTION_INFO_V1(truncInt);
PG_FUNCTION_INFO_V1(truncDec81);
PG_FUNCTION_INFO_V1(truncDec8);
PG_FUNCTION_INFO_V1(truncFloat);
PG_FUNCTION_INFO_V1(TransTimestamp);
PG_FUNCTION_INFO_V1(TransDate);
PG_FUNCTION_INFO_V1(signi);
PG_FUNCTION_INFO_V1(signf);
PG_FUNCTION_INFO_V1(RoundInt);
PG_FUNCTION_INFO_V1(RoundFloat);
PG_FUNCTION_INFO_V1(RoundDec8);
PG_FUNCTION_INFO_V1(lpad_f);
PG_FUNCTION_INFO_V1(rpad_f);
PG_FUNCTION_INFO_V1(normsdist);
PG_FUNCTION_INFO_V1(months_between_dd);
PG_FUNCTION_INFO_V1(months_between_dt);
PG_FUNCTION_INFO_V1(months_between_td);
PG_FUNCTION_INFO_V1(months_between_tt);
// PG_FUNCTION_INFO_V1(FUNC_JUDGE_ACC);
// PG_FUNCTION_INFO_V1(FUNC_GREAST_MOB24);
PG_FUNCTION_INFO_V1(last_day_d);
PG_FUNCTION_INFO_V1(last_day_t);
PG_FUNCTION_INFO_V1(last_day_tz);

// PG_FUNCTION_INFO_V1(FUNC_II_DIV_CL_MOB6);
// PG_FUNCTION_INFO_V1(oadd_months_d);
// PG_FUNCTION_INFO_V1(oadd_months_t);
// PG_FUNCTION_INFO_V1(oadd_months_tz);
// PG_FUNCTION_INFO_V1(ceilDec8);
// PG_FUNCTION_INFO_V1(ceilFloat);
// PG_FUNCTION_INFO_V1(ceilInt);
// PG_FUNCTION_INFO_V1(FUNC_AGE_JUDGE);
// PG_FUNCTION_INFO_V1(FUNC_CAP);
// PG_FUNCTION_INFO_V1(FUNC_COST_SERVICE);
// PG_FUNCTION_INFO_V1(FUNC_DIV_CIIS_DATA_100);
// PG_FUNCTION_INFO_V1(FUNC_DIV_CIIS_DATA_ZERO);
// PG_FUNCTION_INFO_V1(FUNC_DIV_DATA);
// PG_FUNCTION_INFO_V1(FUNC_DIV_MOB3);
// PG_FUNCTION_INFO_V1(FUNC_DIV_MOB6);
////PG_FUNCTION_INFO_V1(FUNC_DIV_MOB9);
////PG_FUNCTION_INFO_V1(FUNC_DIV_MOB12);
////PG_FUNCTION_INFO_V1(FUNC_DPT_MOB12);
// PG_FUNCTION_INFO_V1(FUNC_DPTADD_MOB6);
// PG_FUNCTION_INFO_V1(FUNC_FOUR_SEG);
// PG_FUNCTION_INFO_V1(FUNC_GREAST_MOB3);
// PG_FUNCTION_INFO_V1(FUNC_GREAST_MOB6);
////PG_FUNCTION_INFO_V1(FUNC_GREAST_MOB12);
// PG_FUNCTION_INFO_V1(FUNC_II_CL_DPM_CAST);
// PG_FUNCTION_INFO_V1(FUNC_II_DIV_MOB3);
// PG_FUNCTION_INFO_V1(FUNC_II_DIV_MOB6);
////PG_FUNCTION_INFO_V1(FUNC_II_DIV_MOB9);
////PG_FUNCTION_INFO_V1(FUNC_II_DIV_MOB12);
// PG_FUNCTION_INFO_V1(FUNC_II_DIV_NULL_MOB3);
// PG_FUNCTION_INFO_V1(FUNC_II_DIV_NULL_MOB6);
// PG_FUNCTION_INFO_V1(FUNC_II_DIV_NULL_MOB9);
// PG_FUNCTION_INFO_V1(FUNC_II_DIV_NULL_MOB12);
// PG_FUNCTION_INFO_V1(FUNC_II_CL_SUM_MOB3);
// PG_FUNCTION_INFO_V1(FUNC_II_CL_SUM_MOB6);
// PG_FUNCTION_INFO_V1(FUNC_II_DIV_CL_MOB3);
// PG_FUNCTION_INFO_V1(FUNC_II_GREAST_MOB3);
// PG_FUNCTION_INFO_V1(FUNC_II_GREAST_MOB6);
// PG_FUNCTION_INFO_V1(FUNC_II_GREAST_MOB9);
// PG_FUNCTION_INFO_V1(FUNC_II_GREAST_MOB12);
// PG_FUNCTION_INFO_V1(FUNC_II_GREAST_VAR_MOB3);
// PG_FUNCTION_INFO_V1(FUNC_II_GREAST_VAR_MOB6);
// PG_FUNCTION_INFO_V1(FUNC_II_GREAST_VAR_MOB9);
// PG_FUNCTION_INFO_V1(FUNC_II_DIV_CEIL_DATA);
// PG_FUNCTION_INFO_V1(FUNC_II_DIV_DATA);
// PG_FUNCTION_INFO_V1(FUNC_II_DIV_DATA_NULL);
// PG_FUNCTION_INFO_V1(FUNC_II_DPM_QC_MIN1);
// PG_FUNCTION_INFO_V1(FUNC_II_FLOOR_ZERO);
// PG_FUNCTION_INFO_V1(FUNC_III_CS0507_2);

// PG_FUNCTION_INFO_V1(FUNC_II_GREAST_VAR_MOB12);
PG_FUNCTION_INFO_V1(FUNC_III_CS0507_3);
PG_FUNCTION_INFO_V1(FUNC_III_CS0507);
PG_FUNCTION_INFO_V1(FUNC_II_JUDGE_DF_AGE);
// PG_FUNCTION_INFO_V1(FUNC_II_LEAST_CL_MOB6);
// PG_FUNCTION_INFO_V1(FUNC_II_LEAST_MOB12);
// PG_FUNCTION_INFO_V1(FUNC_II_LEAST_MOB3);
// PG_FUNCTION_INFO_V1(FUNC_II_LEAST_MOB6);
// PG_FUNCTION_INFO_V1(FUNC_II_LEAST_MOB9);
// PG_FUNCTION_INFO_V1(FUNC_II_LEAST_VAR_MOB3);
// PG_FUNCTION_INFO_V1(FUNC_II_SUM_MOB12);
// PG_FUNCTION_INFO_V1(FUNC_II_SUM_MOB9);
// PG_FUNCTION_INFO_V1(FUNC_II_SUM_MOB6);
// PG_FUNCTION_INFO_V1(FUNC_II_SUM_MOB3);
// PG_FUNCTION_INFO_V1(FUNC_JUDGE_ACC_3);
// PG_FUNCTION_INFO_V1(FUNC_JUDGE_ACC_6);
// PG_FUNCTION_INFO_V1(FUNC_JUDGE_ACC_9);
////PG_FUNCTION_INFO_V1(FUNC_JUDGE_ACC_12);
////PG_FUNCTION_INFO_V1(FUNC_JUDGE_ACC_15);
////PG_FUNCTION_INFO_V1(FUNC_JUDGE_ACC_18);
////PG_FUNCTION_INFO_V1(FUNC_JUDGE_ACC_21);
////PG_FUNCTION_INFO_V1(FUNC_JUDGE_ACC_24);
// PG_FUNCTION_INFO_V1(FUNC_JUDGE_EAD);
// PG_FUNCTION_INFO_V1(FUNC_JUDGE_NUMBER);
// PG_FUNCTION_INFO_V1(FUNC_LEAST_MOB3);
// PG_FUNCTION_INFO_V1(FUNC_LEAST_MOB6);
// PG_FUNCTION_INFO_V1(FUNC_LEAST_MOB9);
// PG_FUNCTION_INFO_V1(FUNC_MINROC_AMOUNT);
// PG_FUNCTION_INFO_V1(FUNC_MINROC_NUM);
// PG_FUNCTION_INFO_V1(FUNC_MONTH_FLAG_BANNIAN);
// PG_FUNCTION_INFO_V1(FUNC_MONTH_FLAG_JI);
// PG_FUNCTION_INFO_V1(FUNC_OVE_MONTH_CODE);
// PG_FUNCTION_INFO_V1(FUNC_PRICE_CODE);
// PG_FUNCTION_INFO_V1(FUNC_SUM_MOB3);
// PG_FUNCTION_INFO_V1(FUNC_SUM_MOB6);
// PG_FUNCTION_INFO_V1(FUNC_SUM_MOB9);
// PG_FUNCTION_INFO_V1(FUNC_SUM_MOB12);
PG_FUNCTION_INFO_V1(FUNC_TRANS_MOBCODE);
PG_FUNCTION_INFO_V1(FUNC_TRANS_RISKCODE);
PG_FUNCTION_INFO_V1(FUNC_XW_FIX_DPD);
PG_FUNCTION_INFO_V1(FUNC_ZERO_NULL);
PG_FUNCTION_INFO_V1(greatestcc);
PG_FUNCTION_INFO_V1(greatestcd);
PG_FUNCTION_INFO_V1(greatestci);
PG_FUNCTION_INFO_V1(greatestdc);
PG_FUNCTION_INFO_V1(greatestdd);
PG_FUNCTION_INFO_V1(greatestdi);
PG_FUNCTION_INFO_V1(greatestic);
PG_FUNCTION_INFO_V1(greatestid);

/***************create_type check*****************/
PG_FUNCTION_INFO_V1(complex_in);
PG_FUNCTION_INFO_V1(complex_out);
PG_FUNCTION_INFO_V1(complex_recv);
PG_FUNCTION_INFO_V1(complex_send);
PG_FUNCTION_INFO_V1(query_get_unique_sql_id);

/*
 * Distance from a point to a path
 */
PG_FUNCTION_INFO_V1(regress_dist_ptpath);

Datum regress_dist_ptpath(PG_FUNCTION_ARGS)
{
    Point* pt = PG_GETARG_POINT_P(0);
    PATH* path = PG_GETARG_PATH_P(1);
    float8 result = 0.0; /* keep compiler quiet */
    float8 tmp;
    int i;
    LSEG lseg;

    switch (path->npts) {
        case 0:
            PG_RETURN_NULL();
        case 1:
            result = point_dt(pt, &path->p[0]);
            break;
        default:

            /*
             * the distance from a point to a path is the smallest distance
             * from the point to any of its constituent segments.
             */
            Assert(path->npts > 1);
            for (i = 0; i < path->npts - 1; ++i) {
                regress_lseg_construct(&lseg, &path->p[i], &path->p[i + 1]);
                tmp = DatumGetFloat8(DirectFunctionCall2(dist_ps, PointPGetDatum(pt), LsegPGetDatum(&lseg)));
                if (i == 0 || tmp < result)
                    result = tmp;
            }
            break;
    }
    PG_RETURN_FLOAT8(result);
}

/*
 * this essentially does a cartesian product of the lsegs in the
 * two paths, and finds the min distance between any two lsegs
 */
PG_FUNCTION_INFO_V1(regress_path_dist);

Datum regress_path_dist(PG_FUNCTION_ARGS)
{
    PATH* p1 = PG_GETARG_PATH_P(0);
    PATH* p2 = PG_GETARG_PATH_P(1);
    bool have_min = false;
    float8 min = 0.0; /* initialize to keep compiler quiet */
    float8 tmp;
    int i, j;
    LSEG seg1, seg2;

    for (i = 0; i < p1->npts - 1; i++) {
        for (j = 0; j < p2->npts - 1; j++) {
            regress_lseg_construct(&seg1, &p1->p[i], &p1->p[i + 1]);
            regress_lseg_construct(&seg2, &p2->p[j], &p2->p[j + 1]);

            tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance, LsegPGetDatum(&seg1), LsegPGetDatum(&seg2)));
            if (!have_min || tmp < min) {
                min = tmp;
                have_min = true;
            }
        }
    }

    if (!have_min)
        PG_RETURN_NULL();

    PG_RETURN_FLOAT8(min);
}

PATH* poly2path(POLYGON* poly)
{
    int i;
    char* output = (char*)palloc(2 * (P_MAXDIG + 1) * poly->npts + 64);
    char buf[2 * (P_MAXDIG) + 20];

    sprintf(output, "(1, %*d", P_MAXDIG, poly->npts);

    for (i = 0; i < poly->npts; i++) {
        snprintf(buf, sizeof(buf), ",%*g,%*g", P_MAXDIG, poly->p[i].x, P_MAXDIG, poly->p[i].y);
        strcat(output, buf);
    }

    snprintf(buf, sizeof(buf), "%c", RDELIM);
    strcat(output, buf);
    return DatumGetPathP(DirectFunctionCall1(path_in, CStringGetDatum(output)));
}

/* return the point where two paths intersect, or NULL if no intersection. */
PG_FUNCTION_INFO_V1(interpt_pp);

Datum interpt_pp(PG_FUNCTION_ARGS)
{
    PATH* p1 = PG_GETARG_PATH_P(0);
    PATH* p2 = PG_GETARG_PATH_P(1);
    int i, j;
    LSEG seg1, seg2;
    bool found = false; /* We've found the intersection */

    found = false; /* Haven't found it yet */

    for (i = 0; i < p1->npts - 1 && !found; i++) {
        regress_lseg_construct(&seg1, &p1->p[i], &p1->p[i + 1]);
        for (j = 0; j < p2->npts - 1 && !found; j++) {
            regress_lseg_construct(&seg2, &p2->p[j], &p2->p[j + 1]);
            if (DatumGetBool(DirectFunctionCall2(lseg_intersect, LsegPGetDatum(&seg1), LsegPGetDatum(&seg2))))
                found = true;
        }
    }

    if (!found)
        PG_RETURN_NULL();

    /*
     * Note: DirectFunctionCall2 will kick out an error if lseg_interpt()
     * returns NULL, but that should be impossible since we know the two
     * segments intersect.
     */
    PG_RETURN_DATUM(DirectFunctionCall2(lseg_interpt, LsegPGetDatum(&seg1), LsegPGetDatum(&seg2)));
}

/* like lseg_construct, but assume space already allocated */
void regress_lseg_construct(LSEG* lseg, Point* pt1, Point* pt2)
{
    lseg->p[0].x = pt1->x;
    lseg->p[0].y = pt1->y;
    lseg->p[1].x = pt2->x;
    lseg->p[1].y = pt2->y;
    lseg->m = point_sl(pt1, pt2);
}

PG_FUNCTION_INFO_V1(overpaid);

Datum overpaid(PG_FUNCTION_ARGS)
{
    HeapTupleHeader tuple = PG_GETARG_HEAPTUPLEHEADER(0);
    bool isnull = false;
    int32 salary;

    salary = DatumGetInt32(GetAttributeByName(tuple, "salary", &isnull));
    if (isnull)
        PG_RETURN_NULL();
    PG_RETURN_BOOL(salary > 699);
}

/* New type "widget"
 * This used to be "circle", but I added circle to builtins,
 *	so needed to make sure the names do not collide. - tgl 97/04/21
 */

typedef struct {
    Point center;
    double radius;
} WIDGET;

extern "C" Datum widget_in(PG_FUNCTION_ARGS);
extern "C" Datum widget_out(PG_FUNCTION_ARGS);
extern "C" Datum pt_in_widget(PG_FUNCTION_ARGS);

PG_FUNCTION_INFO_V1(widget_in);
PG_FUNCTION_INFO_V1(widget_out);

#define NARGS 3

Datum widget_in(PG_FUNCTION_ARGS)
{
    char* str = PG_GETARG_CSTRING(0);
    char *p, *coord[NARGS], buf2[1000];
    int i;
    WIDGET* result = NULL;

    if (str == NULL)
        PG_RETURN_NULL();
    for (i = 0, p = str; *p && i < NARGS && *p != RDELIM; p++)
        if (*p == ',' || (*p == LDELIM && !i))
            coord[i++] = p + 1;
    if (i < NARGS - 1)
        PG_RETURN_NULL();
    result = (WIDGET*)palloc(sizeof(WIDGET));
    result->center.x = atof(coord[0]);
    result->center.y = atof(coord[1]);
    result->radius = atof(coord[2]);

    snprintf(buf2, sizeof(buf2), "widget_in: read (%f, %f, %f)\n", result->center.x, result->center.y, result->radius);
    PG_RETURN_POINTER(result);
}

Datum widget_out(PG_FUNCTION_ARGS)
{
    WIDGET* widget = (WIDGET*)PG_GETARG_POINTER(0);
    char* result = NULL;

    if (widget == NULL)
        PG_RETURN_NULL();

    result = (char*)palloc(60);
    sprintf(result, "(%g,%g,%g)", widget->center.x, widget->center.y, widget->radius);
    PG_RETURN_CSTRING(result);
}

PG_FUNCTION_INFO_V1(pt_in_widget);

Datum pt_in_widget(PG_FUNCTION_ARGS)
{
    Point* point = PG_GETARG_POINT_P(0);
    WIDGET* widget = (WIDGET*)PG_GETARG_POINTER(1);

    PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius);
}

PG_FUNCTION_INFO_V1(boxarea);

Datum boxarea(PG_FUNCTION_ARGS)
{
    BOX* box = PG_GETARG_BOX_P(0);
    double width, height;

    width = Abs(box->high.x - box->low.x);
    height = Abs(box->high.y - box->low.y);
    PG_RETURN_FLOAT8(width * height);
}

PG_FUNCTION_INFO_V1(reverse_name);

Datum reverse_name(PG_FUNCTION_ARGS)
{
    char* string = PG_GETARG_CSTRING(0);
    int i;
    int len;
    char* new_string = NULL;

    new_string = (char*)palloc0(NAMEDATALEN);
    for (i = 0; i < NAMEDATALEN && string[i]; ++i)
        ;
    if (i == NAMEDATALEN || !string[i])
        --i;
    len = i;
    for (; i >= 0; --i)
        new_string[len - i] = string[i];
    PG_RETURN_CSTRING(new_string);
}

PG_FUNCTION_INFO_V1(oldstyle_length);

/*
 * This rather silly function is just to test that oldstyle functions
 * work correctly on toast-able inputs.
 */
Datum oldstyle_length(PG_FUNCTION_ARGS)
{
    int n = PG_GETARG_INT32(0);
    text* t = (text*)PG_GETARG_DATUM(1);
    int len = 0;

    if (!PG_ARGISNULL(1))
        len = VARSIZE(t) - VARHDRSZ;
    else
        PG_RETURN_NULL();

    PG_RETURN_INT32(n + len);
}

static TransactionId fd17b_xid = InvalidTransactionId;
static TransactionId fd17a_xid = InvalidTransactionId;
static int fd17b_level = 0;
static int fd17a_level = 0;
static bool fd17b_recursion = true;
static bool fd17a_recursion = true;
extern "C" Datum funny_dup17(PG_FUNCTION_ARGS);

PG_FUNCTION_INFO_V1(funny_dup17);

Datum funny_dup17(PG_FUNCTION_ARGS)
{
    TriggerData* trigdata = (TriggerData*)fcinfo->context;
    TransactionId* xid = NULL;
    int* level = NULL;
    bool* recursion = NULL;
    Relation rel;
    TupleDesc tupdesc;
    HeapTuple tuple;
    char *query, *fieldval, *fieldtype;
    char* when = NULL;
    int inserted;
    int selected = 0;
    int ret;

    if (!CALLED_AS_TRIGGER(fcinfo))
        (elog(ERROR, "funny_dup17: not fired by trigger manager"));

    tuple = trigdata->tg_trigtuple;
    rel = trigdata->tg_relation;
    tupdesc = rel->rd_att;
    if (TRIGGER_FIRED_BEFORE(trigdata->tg_event)) {
        xid = &fd17b_xid;
        level = &fd17b_level;
        recursion = &fd17b_recursion;
        when = "BEFORE";
    } else {
        xid = &fd17a_xid;
        level = &fd17a_level;
        recursion = &fd17a_recursion;
        when = "AFTER ";
    }

    if (!TransactionIdIsCurrentTransactionId(*xid)) {
        *xid = GetCurrentTransactionId();
        *level = 0;
        *recursion = true;
    }

    if (*level == 17) {
        *recursion = false;
        return PointerGetDatum(tuple);
    }

    if (!(*recursion))
        return PointerGetDatum(tuple);

    (*level)++;

    SPI_connect();

    fieldval = SPI_getvalue(tuple, tupdesc, 1);
    fieldtype = SPI_gettype(tupdesc, 1);

    query = (char*)palloc(100 + NAMEDATALEN * 3 + strlen(fieldval) + strlen(fieldtype));

    sprintf(query,
        "insert into %s select * from %s where %s = '%s'::%s",
        SPI_getrelname(rel),
        SPI_getrelname(rel),
        SPI_fname(tupdesc, 1),
        fieldval,
        fieldtype);

    if ((ret = SPI_exec(query, 0)) < 0)
        (elog(ERROR, "funny_dup17 (fired %s) on level %3d: SPI_exec (insert ...) returned %d", when, *level, ret));

    inserted = SPI_processed;

    sprintf(query,
        "select count (*) from %s where %s = '%s'::%s",
        SPI_getrelname(rel),
        SPI_fname(tupdesc, 1),
        fieldval,
        fieldtype);

    if ((ret = SPI_exec(query, 0)) < 0)
        (elog(ERROR, "funny_dup17 (fired %s) on level %3d: SPI_exec (select ...) returned %d", when, *level, ret));

    if (SPI_processed > 0) {
        selected = DatumGetInt32(DirectFunctionCall1(
            int4in, CStringGetDatum(SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1))));
    }

    elog(DEBUG4,
        "funny_dup17 (fired %s) on level %3d: %d/%d tuples inserted/selected",
        when,
        *level,
        inserted,
        selected);

    SPI_finish();

    (*level)--;

    if (*level == 0)
        *xid = InvalidTransactionId;

    return PointerGetDatum(tuple);
}

extern "C" Datum ttdummy(PG_FUNCTION_ARGS);
extern "C" Datum set_ttdummy(PG_FUNCTION_ARGS);

#define TTDUMMY_INFINITY 999999

static SPIPlanPtr splan = NULL;
static bool ttoff = false;

PG_FUNCTION_INFO_V1(ttdummy);

Datum ttdummy(PG_FUNCTION_ARGS)
{
    TriggerData* trigdata = (TriggerData*)fcinfo->context;
    Trigger* trigger = NULL; /* to get trigger name */
    char** args;             /* arguments */
    int attnum[2];           /* fnumbers of start/stop columns */
    Datum oldon, oldoff;
    Datum newon, newoff;
    Datum* cvals = NULL;  /* column values */
    char* cnulls = NULL;  /* column nulls */
    char* relname = NULL; /* triggered relation name */
    Relation rel;         /* triggered relation */
    HeapTuple trigtuple;
    HeapTuple newtuple = NULL;
    HeapTuple rettuple;
    TupleDesc tupdesc;   /* tuple description */
    int natts;           /* # of attributes */
    bool isnull = false; /* to know is some column NULL or not */
    int ret;
    int i;

    if (!CALLED_AS_TRIGGER(fcinfo))
        (elog(ERROR, "ttdummy: not fired by trigger manager"));
    if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
        (elog(ERROR, "ttdummy: must be fired for row"));
    if (!TRIGGER_FIRED_BEFORE(trigdata->tg_event))
        (elog(ERROR, "ttdummy: must be fired before event"));
    if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
        (elog(ERROR, "ttdummy: cannot process INSERT event"));
    if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
        newtuple = trigdata->tg_newtuple;

    trigtuple = trigdata->tg_trigtuple;

    rel = trigdata->tg_relation;
    relname = SPI_getrelname(rel);

    /* check if TT is OFF for this relation */
    if (ttoff) /* OFF - nothing to do */
    {
        pfree(relname);
        return PointerGetDatum((newtuple != NULL) ? newtuple : trigtuple);
    }

    trigger = trigdata->tg_trigger;

    if (trigger->tgnargs != 2)
        (elog(ERROR, "ttdummy (%s): invalid (!= 2) number of arguments %d", relname, trigger->tgnargs));

    args = trigger->tgargs;
    tupdesc = rel->rd_att;
    natts = tupdesc->natts;

    for (i = 0; i < 2; i++) {
        attnum[i] = SPI_fnumber(tupdesc, args[i]);
        if (attnum[i] < 0)
            (elog(ERROR, "ttdummy (%s): there is no attribute %s", relname, args[i]));
        if (SPI_gettypeid(tupdesc, attnum[i]) != INT4OID)
            (elog(ERROR, "ttdummy (%s): attributes %s and %s must be of abstime type", relname, args[0], args[1]));
    }

    oldon = SPI_getbinval(trigtuple, tupdesc, attnum[0], &isnull);
    if (isnull)
        (elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[0]));

    oldoff = SPI_getbinval(trigtuple, tupdesc, attnum[1], &isnull);
    if (isnull)
        (elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[1]));

    if (newtuple != NULL) /* UPDATE */
    {
        newon = SPI_getbinval(newtuple, tupdesc, attnum[0], &isnull);
        if (isnull)
            (elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[0]));
        newoff = SPI_getbinval(newtuple, tupdesc, attnum[1], &isnull);
        if (isnull)
            (elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[1]));

        if (oldon != newon || oldoff != newoff)
            (elog(ERROR,
                "ttdummy (%s): you cannot change %s and/or %s columns (use set_ttdummy)",
                relname,
                args[0],
                args[1]));

        if (newoff != TTDUMMY_INFINITY) {
            pfree(relname); /* allocated in upper executor context */
            return PointerGetDatum(NULL);
        }
    } else if (oldoff != TTDUMMY_INFINITY) /* DELETE */
    {
        pfree(relname);
        return PointerGetDatum(NULL);
    }

    newoff = DirectFunctionCall1(nextval, CStringGetTextDatum("ttdummy_seq"));
    /* nextval now returns int64; coerce down to int32 */
    newoff = Int32GetDatum((int32)DatumGetInt64(newoff));

    /* Connect to SPI manager */
    if ((ret = SPI_connect()) < 0)
        (elog(ERROR, "ttdummy (%s): SPI_connect returned %d", relname, ret));

    /* Fetch tuple values and nulls */
    cvals = (Datum*)palloc(natts * sizeof(Datum));
    cnulls = (char*)palloc(natts * sizeof(char));
    for (i = 0; i < natts; i++) {
        cvals[i] = SPI_getbinval((newtuple != NULL) ? newtuple : trigtuple, tupdesc, i + 1, &isnull);
        cnulls[i] = (isnull) ? 'n' : ' ';
    }

    /* change date column(s) */
    if (newtuple) /* UPDATE */
    {
        cvals[attnum[0] - 1] = newoff; /* start_date eq current date */
        cnulls[attnum[0] - 1] = ' ';
        cvals[attnum[1] - 1] = TTDUMMY_INFINITY; /* stop_date eq INFINITY */
        cnulls[attnum[1] - 1] = ' ';
    } else
    /* DELETE */
    {
        cvals[attnum[1] - 1] = newoff; /* stop_date eq current date */
        cnulls[attnum[1] - 1] = ' ';
    }

    /* if there is no plan ... */
    if (splan == NULL) {
        SPIPlanPtr pplan;
        Oid* ctypes = NULL;
        char* query = NULL;

        /* allocate space in preparation */
        ctypes = (Oid*)palloc(natts * sizeof(Oid));
        query = (char*)palloc(100 + 16 * natts);

        /*
         * Construct query: INSERT INTO _relation_ VALUES ($1, ...)
         */
        sprintf(query, "INSERT INTO %s VALUES (", relname);
        for (i = 1; i <= natts; i++) {
            sprintf(query + strlen(query), "$%d%s", i, (i < natts) ? ", " : ")");
            ctypes[i - 1] = SPI_gettypeid(tupdesc, i);
        }

        /* Prepare plan for query */
        pplan = SPI_prepare(query, natts, ctypes);
        if (pplan == NULL)
            (elog(ERROR, "ttdummy (%s): SPI_prepare returned %d", relname, SPI_result));

        if (SPI_keepplan(pplan))
            (elog(ERROR, "ttdummy (%s): SPI_keepplan failed", relname));

        splan = pplan;
    }

    ret = SPI_execp(splan, cvals, cnulls, 0);

    if (ret < 0)
        (elog(ERROR, "ttdummy (%s): SPI_execp returned %d", relname, ret));

    /* Tuple to return to upper Executor ... */
    if (newtuple) /* UPDATE */
    {
        HeapTuple tmptuple;

        tmptuple = SPI_copytuple(trigtuple);
        rettuple = SPI_modifytuple(rel, tmptuple, 1, &(attnum[1]), &newoff, NULL);
        SPI_freetuple(tmptuple);
    } else
        /* DELETE */
        rettuple = trigtuple;

    SPI_finish(); /* don't forget say Bye to SPI mgr */

    pfree(relname);

    return PointerGetDatum(rettuple);
}

PG_FUNCTION_INFO_V1(set_ttdummy);

Datum set_ttdummy(PG_FUNCTION_ARGS)
{
    int32 on = PG_GETARG_INT32(0);

    if (ttoff) /* OFF currently */
    {
        if (on == 0)
            PG_RETURN_INT32(0);

        /* turn ON */
        ttoff = false;
        PG_RETURN_INT32(0);
    }

    /* ON currently */
    if (on != 0)
        PG_RETURN_INT32(1);

    /* turn OFF */
    ttoff = true;

    PG_RETURN_INT32(1);
}

/*
 * Type int44 has no real-world use, but the regression tests use it.
 * It's a four-element vector of int4's.
 */

/*
 *		int44in			- converts "num num ..." to internal form
 *
 *		Note: Fills any missing positions with zeroes.
 */
PG_FUNCTION_INFO_V1(int44in);

Datum int44in(PG_FUNCTION_ARGS)
{
    char* input_string = PG_GETARG_CSTRING(0);
    int32* result = (int32*)palloc(4 * sizeof(int32));
    int i;

    i = sscanf(input_string, "%d, %d, %d, %d", &result[0], &result[1], &result[2], &result[3]);
    while (i < 4)
        result[i++] = 0;

    PG_RETURN_POINTER(result);
}

/*
 *		int44out		- converts internal form to "num num ..."
 */
PG_FUNCTION_INFO_V1(int44out);

Datum int44out(PG_FUNCTION_ARGS)
{
    int32* an_array = (int32*)PG_GETARG_POINTER(0);
    char* result = (char*)palloc(16 * 4); /* Allow 14 digits +
                                           * sign */
    int i;
    char* walk = NULL;

    walk = result;
    for (i = 0; i < 4; i++) {
        pg_ltoa(an_array[i], walk);
        while (*++walk != '\0')
            ;
        *walk++ = ' ';
    }
    *--walk = '\0';
    PG_RETURN_CSTRING(result);
}

PG_FUNCTION_INFO_V1(make_tuple_indirect);
Datum make_tuple_indirect(PG_FUNCTION_ARGS)
{
    HeapTupleHeader rec = PG_GETARG_HEAPTUPLEHEADER(0);
    HeapTupleData tuple;
    int ncolumns;
    Datum* values = NULL;
    bool* nulls = NULL;

    Oid tupType;
    int32 tupTypmod;
    TupleDesc tupdesc;

    HeapTuple newtup;

    int i;

    MemoryContext old_context;

    /* Extract type info from the tuple itself */
    tupType = HeapTupleHeaderGetTypeId(rec);
    tupTypmod = HeapTupleHeaderGetTypMod(rec);
    tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
    ncolumns = tupdesc->natts;

    /* Build a temporary HeapTuple control structure */
    tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
    ItemPointerSetInvalid(&(tuple.t_self));
    tuple.t_tableOid = InvalidOid;
    tuple.t_data = rec;

    values = (Datum*)palloc(ncolumns * sizeof(Datum));
    nulls = (bool*)palloc(ncolumns * sizeof(bool));

    heap_deform_tuple(&tuple, tupdesc, values, nulls);

    old_context = MemoryContextSwitchTo(u_sess->top_transaction_mem_cxt);

    for (i = 0; i < ncolumns; i++) {
        struct varlena* attr;
        struct varlena* new_attr;
        struct varatt_indirect redirect_pointer;

        /* only work on existing, not-null varlenas */
        if (tupdesc->attrs[i].attisdropped || nulls[i] || tupdesc->attrs[i].attlen != -1)
            continue;

        attr = (struct varlena*)DatumGetPointer(values[i]);

        /* don't recursively indirect */
        if (VARATT_IS_EXTERNAL_INDIRECT(attr))
            continue;

        /* copy datum, so it still lives later */
        if (VARATT_IS_EXTERNAL_ONDISK(attr))
            attr = heap_tuple_fetch_attr(attr);
        else {
            struct varlena* oldattr = attr;
            attr = (struct varlena*)palloc0(VARSIZE_ANY(oldattr));
            memcpy(attr, oldattr, VARSIZE_ANY(oldattr));
        }

        /* build indirection Datum */
        new_attr = (struct varlena*)palloc0(INDIRECT_POINTER_SIZE);
        redirect_pointer.pointer = attr;
        SET_VARTAG_EXTERNAL(new_attr, VARTAG_INDIRECT);
        memcpy(VARDATA_EXTERNAL(new_attr), &redirect_pointer, sizeof(redirect_pointer));

        values[i] = PointerGetDatum(new_attr);
    }

    newtup = heap_form_tuple(tupdesc, values, nulls);
    pfree(values);
    pfree(nulls);
    ReleaseTupleDesc(tupdesc);

    MemoryContextSwitchTo(old_context);

    PG_RETURN_HEAPTUPLEHEADER(newtup->t_data);
}

/*
 *		vec_int4add_0 	- add int4 with 0 args
 */

PG_FUNCTION_INFO_V1(vec_int4add_0);
Datum vec_int4add_0(PG_FUNCTION_ARGS)
{
    int32 result;

    result = 1;

    PG_RETURN_INT32(result);
}
/*
 *		vec_int4add_7		- add int4 with 7 args
 */

PG_FUNCTION_INFO_V1(vec_int4add_7);
Datum vec_int4add_7(PG_FUNCTION_ARGS)
{
    int32 p1 = PG_GETARG_INT32(0);
    int32 p2 = PG_GETARG_INT32(1);
    int32 p3 = PG_GETARG_INT32(2);
    int32 p4 = PG_GETARG_INT32(3);
    int32 p5 = PG_GETARG_INT32(4);
    int32 p6 = PG_GETARG_INT32(5);
    int32 p7 = PG_GETARG_INT32(6);
    int32 result;

    result = p1 + p2 + p3 + p4 + p5 + p6 + p7;

    PG_RETURN_INT32(result);
}

/*
 *		vec_int4add_8		- add int4 with 8 args
 */

PG_FUNCTION_INFO_V1(vec_int4add_8);
Datum vec_int4add_8(PG_FUNCTION_ARGS)
{
    int32 p1 = PG_GETARG_INT32(0);
    int32 p2 = PG_GETARG_INT32(1);
    int32 p3 = PG_GETARG_INT32(2);
    int32 p4 = PG_GETARG_INT32(3);
    int32 p5 = PG_GETARG_INT32(4);
    int32 p6 = PG_GETARG_INT32(5);
    int32 p7 = PG_GETARG_INT32(6);
    int32 p8 = PG_GETARG_INT32(7);
    int32 result;

    result = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8;

    PG_RETURN_INT32(result);
}

/*
 *		vec_int4add_9	- add int4 with 9 args
 */

PG_FUNCTION_INFO_V1(vec_int4add_9);
Datum vec_int4add_9(PG_FUNCTION_ARGS)
{
    int32 p1 = PG_GETARG_INT32(0);
    int32 p2 = PG_GETARG_INT32(1);
    int32 p3 = PG_GETARG_INT32(2);
    int32 p4 = PG_GETARG_INT32(3);
    int32 p5 = PG_GETARG_INT32(4);
    int32 p6 = PG_GETARG_INT32(5);
    int32 p7 = PG_GETARG_INT32(6);
    int32 p8 = PG_GETARG_INT32(7);
    int32 p9 = PG_GETARG_INT32(8);
    int32 result;

    result = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;

    PG_RETURN_INT32(result);
}

PG_FUNCTION_INFO_V1(vec_int4add_10);
Datum vec_int4add_10(PG_FUNCTION_ARGS)
{
    int32 p1 = PG_GETARG_INT32(0);
    int32 p2 = PG_GETARG_INT32(1);
    int32 p3 = PG_GETARG_INT32(2);
    int32 p4 = PG_GETARG_INT32(3);
    int32 p5 = PG_GETARG_INT32(4);
    int32 p6 = PG_GETARG_INT32(5);
    int32 p7 = PG_GETARG_INT32(6);
    int32 p8 = PG_GETARG_INT32(7);
    int32 p9 = PG_GETARG_INT32(8);
    int32 p10 = PG_GETARG_INT32(9);
    int32 result;

    result = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10;

    PG_RETURN_INT32(result);
}

PG_FUNCTION_INFO_V1(vec_int4add_11);
Datum vec_int4add_11(PG_FUNCTION_ARGS)
{
    int32 p1 = PG_GETARG_INT32(0);
    int32 p2 = PG_GETARG_INT32(1);
    int32 p3 = PG_GETARG_INT32(2);
    int32 p4 = PG_GETARG_INT32(3);
    int32 p5 = PG_GETARG_INT32(4);
    int32 p6 = PG_GETARG_INT32(5);
    int32 p7 = PG_GETARG_INT32(6);
    int32 p8 = PG_GETARG_INT32(7);
    int32 p9 = PG_GETARG_INT32(8);
    int32 p10 = PG_GETARG_INT32(9);
    int32 result;

    result = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10;

    PG_RETURN_INT32(result);
}

static void test_atomic_uint32(void)
{
    uint32 var;
    uint32 expected;
    int i;

    pg_atomic_init_u32(&var, 0);

    if (pg_atomic_read_u32(&var) != 0)
        (elog(ERROR, "atomic_read_u32() #1 wrong"));

    pg_atomic_write_u32(&var, 3);

    if (pg_atomic_read_u32(&var) != 3)
        (elog(ERROR, "atomic_read_u32() #2 wrong"));

    if (pg_atomic_fetch_add_u32(&var, 1) != 3)
        (elog(ERROR, "atomic_fetch_add_u32() #1 wrong"));

    if (pg_atomic_fetch_sub_u32(&var, 1) != 4)
        (elog(ERROR, "atomic_fetch_sub_u32() #1 wrong"));

    if (pg_atomic_sub_fetch_u32(&var, 3) != 0)
        (elog(ERROR, "atomic_sub_fetch_u32() #1 wrong"));

    if (pg_atomic_add_fetch_u32(&var, 10) != 10)
        (elog(ERROR, "atomic_add_fetch_u32() #1 wrong"));

    if (pg_atomic_exchange_u32(&var, 5) != 10)
        (elog(ERROR, "pg_atomic_exchange_u32() #1 wrong"));

    if (pg_atomic_exchange_u32(&var, 0) != 5)
        (elog(ERROR, "pg_atomic_exchange_u32() #0 wrong"));

    /* test around numerical limits */
    if (pg_atomic_fetch_add_u32(&var, INT_MAX) != 0)
        (elog(ERROR, "pg_atomic_fetch_add_u32() #2 wrong"));

    if (pg_atomic_fetch_add_u32(&var, INT_MAX) != INT_MAX)
        (elog(ERROR, "pg_atomic_add_fetch_u32() #3 wrong"));

    pg_atomic_fetch_add_u32(&var, 1); /* top up to UINT_MAX */

    if (pg_atomic_read_u32(&var) != UINT_MAX)
        (elog(ERROR, "atomic_read_u32() #2 wrong"));

    if (pg_atomic_fetch_sub_u32(&var, INT_MAX) != UINT_MAX)
        (elog(ERROR, "pg_atomic_fetch_sub_u32() #2 wrong"));

    if (pg_atomic_read_u32(&var) != (uint32)INT_MAX + 1)
        (elog(ERROR, "atomic_read_u32() #3 wrong: %u", pg_atomic_read_u32(&var)));

    expected = pg_atomic_sub_fetch_u32(&var, INT_MAX);
    if (expected != 1)
        (elog(ERROR, "pg_atomic_sub_fetch_u32() #3 wrong: %u", expected));

    pg_atomic_sub_fetch_u32(&var, 1);

    /* fail exchange because of old expected */
    expected = 10;
    if (pg_atomic_compare_exchange_u32(&var, &expected, 1))
        (elog(ERROR, "atomic_compare_exchange_u32() changed value spuriously"));

    /* CAS is allowed to fail due to interrupts, try a couple of times */
    for (i = 0; i < 1000; i++) {
        expected = 0;
        if (!pg_atomic_compare_exchange_u32(&var, &expected, 1))
            break;
    }
    if (i == 1000)
        (elog(ERROR, "atomic_compare_exchange_u32() never succeeded"));
    if (pg_atomic_read_u32(&var) != 1)
        (elog(ERROR, "atomic_compare_exchange_u32() didn't set value properly"));

    pg_atomic_write_u32(&var, 0);

    /* try setting flagbits */
    if (pg_atomic_fetch_or_u32(&var, 1) & 1)
        (elog(ERROR, "pg_atomic_fetch_or_u32() #1 wrong"));

    if (!(pg_atomic_fetch_or_u32(&var, 2) & 1))
        (elog(ERROR, "pg_atomic_fetch_or_u32() #2 wrong"));

    if (pg_atomic_read_u32(&var) != 3)
        (elog(ERROR, "invalid result after pg_atomic_fetch_or_u32()"));

    /* try clearing flagbits */
    if ((pg_atomic_fetch_and_u32(&var, ~2) & 3) != 3)
        (elog(ERROR, "pg_atomic_fetch_and_u32() #1 wrong"));

    if (pg_atomic_fetch_and_u32(&var, ~1) != 1)
        (elog(ERROR, "pg_atomic_fetch_and_u32() #2 wrong: is %u", pg_atomic_read_u32(&var)));
    /* no bits set anymore */
    if (pg_atomic_fetch_and_u32(&var, ~0) != 0)
        (elog(ERROR, "pg_atomic_fetch_and_u32() #3 wrong"));
}

static void test_atomic_uint64(void)
{
    uint64 var;
    uint64 expected;
    int i;

    pg_atomic_init_u64(&var, 0);

    if (pg_atomic_read_u64(&var) != 0)
        (elog(ERROR, "atomic_read_u64() #1 wrong"));

    pg_atomic_write_u64(&var, 3);

    if (pg_atomic_read_u64(&var) != 3)
        (elog(ERROR, "atomic_read_u64() #2 wrong"));

    if (pg_atomic_fetch_add_u64(&var, 1) != 3)
        (elog(ERROR, "atomic_fetch_add_u64() #1 wrong"));

    if (pg_atomic_fetch_sub_u64(&var, 1) != 4)
        (elog(ERROR, "atomic_fetch_sub_u64() #1 wrong"));

    if (pg_atomic_sub_fetch_u64(&var, 3) != 0)
        (elog(ERROR, "atomic_sub_fetch_u64() #1 wrong"));

    if (pg_atomic_add_fetch_u64(&var, 10) != 10)
        (elog(ERROR, "atomic_add_fetch_u64() #1 wrong"));

    if (pg_atomic_exchange_u64(&var, 5) != 10)
        (elog(ERROR, "pg_atomic_exchange_u64() #1 wrong"));

    if (pg_atomic_exchange_u64(&var, 0) != 5)
        (elog(ERROR, "pg_atomic_exchange_u64() #0 wrong"));

    /* fail exchange because of old expected */
    expected = 10;
    if (pg_atomic_compare_exchange_u64(&var, &expected, 1))
        (elog(ERROR, "atomic_compare_exchange_u64() changed value spuriously"));

    /* CAS is allowed to fail due to interrupts, try a couple of times */
    for (i = 0; i < 100; i++) {
        expected = 0;
        if (!pg_atomic_compare_exchange_u64(&var, &expected, 1))
            break;
    }
    if (i == 100)
        (elog(ERROR, "atomic_compare_exchange_u64() never succeeded"));
    if (pg_atomic_read_u64(&var) != 1)
        (elog(ERROR, "atomic_compare_exchange_u64() didn't set value properly"));

    pg_atomic_write_u64(&var, 0);

    /* try setting flagbits */
    if (pg_atomic_fetch_or_u64(&var, 1) & 1)
        (elog(ERROR, "pg_atomic_fetch_or_u64() #1 wrong"));

    if (!(pg_atomic_fetch_or_u64(&var, 2) & 1))
        (elog(ERROR, "pg_atomic_fetch_or_u64() #2 wrong"));

    if (pg_atomic_read_u64(&var) != 3)
        (elog(ERROR, "invalid result after pg_atomic_fetch_or_u64()"));

    /* try clearing flagbits */
    if ((pg_atomic_fetch_and_u64(&var, ~2) & 3) != 3)
        (elog(ERROR, "pg_atomic_fetch_and_u64() #1 wrong"));

    if (pg_atomic_fetch_and_u64(&var, ~1) != 1)
        (elog(ERROR, "pg_atomic_fetch_and_u64() #2 wrong: is " UINT64_FORMAT, pg_atomic_read_u64(&var)));
    /* no bits set anymore */
    if (pg_atomic_fetch_and_u64(&var, ~0) != 0)
        (elog(ERROR, "pg_atomic_fetch_and_u64() #3 wrong"));
}

extern "C" Datum test_atomic_ops(PG_FUNCTION_ARGS);

PG_FUNCTION_INFO_V1(test_atomic_ops);
Datum test_atomic_ops(PG_FUNCTION_ARGS)
{

    test_atomic_uint32();

    test_atomic_uint64();

    PG_RETURN_BOOL(true);
}

Datum funcA(PG_FUNCTION_ARGS)
{
    StringInfoData si;
    initStringInfo(&si);

    appendStringInfo(&si, "funcA");

    PG_RETURN_TEXT_P(cstring_to_text(pstrdup(si.data)));
}

Datum funcB(PG_FUNCTION_ARGS)
{
    StringInfoData si;
    initStringInfo(&si);

    appendStringInfo(&si, "funcB");

    PG_RETURN_TEXT_P(cstring_to_text(pstrdup(si.data)));
}

Datum funcC(PG_FUNCTION_ARGS)
{
    StringInfoData si;
    initStringInfo(&si);

    appendStringInfo(&si, "funcC");

    PG_RETURN_TEXT_P(cstring_to_text(pstrdup(si.data)));
}

/***************************UDF CREM**************************/

/*½«½Å±¾ÖÐÖØ¸´µÄÓï¾ä¶¨ÒåΪºê */
#define if_judeg()                                                                               \
    if (((PRODUCT[0] == 'P' && PRODUCT[1] == 'M') && p > 3 * Multiplier_J && length == 2) ||     \
        ((PRODUCT[0] == 'P' && (PRODUCT[1] == 'O' || PRODUCT[1] == 'A' || PRODUCT[1] == 'C')) && \
            p > 2 * Multiplier_J && length == 2))

static int64 to_int64(Datum dm, int64 ml)
{
    Datum ml_n = DirectFunctionCall1(int8_numeric, Int64GetDatum(ml));
    Datum cj_n = DirectFunctionCall2(numeric_mul, ml_n, dm);
    Datum int_n = DirectFunctionCall1(numeric_int8, cj_n);

    return DatumGetInt64(int_n);
}

#define TmpVar -999999999
/* logic here is the same as C, only used for decimal(18,4) */

Datum truncInt1(PG_FUNCTION_ARGS)
{
    int inputInteger = PG_GETARG_INT32(0);

    PG_RETURN_INT32(inputInteger);
}

Datum truncInt(PG_FUNCTION_ARGS)
{
    int64 V0 = 0;
    int64 VR = 0;
    int64 P0 = 0;
    int64 M = 0;

    // check for NULL Value
    if (PG_ARGISNULL(0))
        PG_RETURN_NULL();

    V0 = (int64)PG_GETARG_INT32(0);
    // if Places is zero or NULL, then nothing to do, exit
    if (PG_ARGISNULL(1) || (M = (int64)PG_GETARG_INT32(1)) > 0)
        PG_RETURN_INT32((int32)V0);

    // calculate the truncating
    P0 = pow(10, -M);
    VR = (V0 / P0) * P0;

    PG_RETURN_INT32((int32)VR);
}

Datum truncFloat(PG_FUNCTION_ARGS)
{
    float arg1 = 0;
    double V0 = 0;
    double V1 = 0;
    double V2 = 0;
    double V3 = 0;
    double VR = 0;
    long P0 = 0;
    long M = 0;

    if (PG_ARGISNULL(0))
        PG_RETURN_NULL();

    arg1 = PG_GETARG_FLOAT4(0);
    V0 = (double)arg1;
    if (!PG_ARGISNULL(1))
        M = PG_GETARG_INT32(1);
    if (M >= 0)  // Positive POWER Case
    {
        // calculate the truncating
        P0 = pow(10, M);
        V3 = V0 * P0;
        V1 = modf(V3, &V2);
        VR = V2 / P0;
    } else  // Negative POWER case
    {
        // calculate the truncating
        P0 = pow(10, -M);
        V2 = modf((V0 / P0), &V1);
        VR = V1 * P0;
    }

    PG_RETURN_FLOAT8(VR);
}

Datum truncDec81(PG_FUNCTION_ARGS)
{
    return DirectFunctionCall2(numeric_trunc, PG_GETARG_DATUM(0), Int32GetDatum(0));
}

Datum truncDec8(PG_FUNCTION_ARGS)
{
    int scale = 0;

    if (PG_ARGISNULL(0))
        PG_RETURN_NULL();

    if (!PG_ARGISNULL(1))
        scale = PG_GETARG_INT32(1);

    if (scale >= 5)
        return PG_GETARG_DATUM(0);  //Èç¹û½ØÈ¡µÄÊýÖµ´óÓÚ5£¬Ö±½Ó¾ÍÔ­Öµµ¼³ö

    return DirectFunctionCall2(numeric_trunc, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1));
}

int is_separator(char a, const int sepaNums, const char* sepa_char)
{
    int i = 0;

    for (; i < sepaNums; i++) {
        if (a == sepa_char[i])
            return 1;
    }

    return 0;
}

/**
 * ´Ó×Ö·û´®ÖлñµÃÊý×Ö
 */
int get_int_from_str(char* source, int len)
{
    int i = 0;
    int value = 0;

    for (i = 0; i < len; i++) {
        if (source[i] < '0' || source[i] > '9')
            return -1;
        value = value * 10 + (source[i] - '0');
    }

    return value;
}

Datum TransTimestamp(PG_FUNCTION_ARGS)
{
    VarChar* source_v = NULL;
    uint32 len;
    char* source = NULL;
    char* result = NULL;
    Datum result_v;
    int year = 0;
    int month = 0;
    int day = 0;
    int hour = 0;
    int min = 0;
    int sec = 0;
    const int sepaNums = 5;
    const char sepa_char[] = {'.', '/', '-', ':', ' '};

#define IS_SEPA(a) is_separator(a, sepaNums, sepa_char)

    if (PG_ARGISNULL(0))
        PG_RETURN_NULL();

    source_v = PG_GETARG_BYTEA_PP(0);
    source = VARDATA_ANY(source_v);
    len = PG_GETARG_INT32(1);

    if (len > VARSIZE_ANY_EXHDR(source_v)) {
        PG_FREE_IF_COPY(source_v, 0);
        return PG_GETARG_DATUM(2);
    }

    if (len == 19) {
        //'2010-01-02 23:59:59'
        //ÅжϷָô·ûÊÇ·ñÕýÈ·
        if (IS_SEPA(source[4]) && IS_SEPA(source[7]) && IS_SEPA(source[10]) && IS_SEPA(source[13]) &&
            IS_SEPA(source[16])) {
            year = get_int_from_str(source, 4);
            month = get_int_from_str(source + 5, 2);
            day = get_int_from_str(source + 8, 2);
            hour = get_int_from_str(source + 11, 2);
            min = get_int_from_str(source + 14, 2);
            sec = get_int_from_str(source + 17, 2);
        }
    } else if (len == 14) {
        //'20100102235959'
        year = get_int_from_str(source, 4);
        month = get_int_from_str(source + 4, 2);
        day = get_int_from_str(source + 6, 2);
        hour = get_int_from_str(source + 8, 2);
        min = get_int_from_str(source + 10, 2);
        sec = get_int_from_str(source + 12, 2);
    }

    //²¹È«Äê·Ý
    if (year >= 0 && year <= 20)
        year += 2000;
    else if (year > 20 && year <= 99)
        year += 1900;

    //ÅжÏÈÕÆÚµÄºÏ·¨ÐÔ
    int valid = 1;
    if (year <= 0)
        valid = -1;
    if (month < 1 || month > 12)
        valid = -1;
    if (day < 1 || day > 31)
        valid = -1;
    if (hour < 0 || hour > 23)
        valid = -1;
    if (min < 0 || min > 59)
        valid = -1;
    if (sec < 0 || sec > 59)
        valid = -1;

    //СÔÂ
    if ((month == 4 || month == 6 || month == 9 || month == 11) && day > 30)
        valid = -1;

    //¶þÔÂ
    if (month == 2) {
        if (((year % 4 != 0) || (year % 4 == 0 && year % 100 == 0 && year % 400 != 0)) && day > 28)
            valid = -1;
        else if (day > 29)
            valid = -1;
    }

    if (valid == -1) {
        PG_FREE_IF_COPY(source_v, 0);
        return PG_GETARG_DATUM(2);
    }

    result = (char*)palloc0(21);
    sprintf(result, "%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, min, sec);
    result_v = DirectFunctionCall3(varcharin, PointerGetDatum(result), UInt32GetDatum(0), Int32GetDatum(-1));

    PG_FREE_IF_COPY(source_v, 0);
    pfree(result);

    return result_v;
}

//×Ö·û´®¸ñʽÀàÐÍ
#define DATE_STR_ERR -1    //´íÎóµÄÈÕÆÚÀàÐÍ
#define DATE_STR_TYPE_1 1  //'yyyy-mm-dd' 'yyyy/mm/dd' 'yyyy.mm.dd'
#define DATE_STR_TYPE_2 2  //'yyyymmdd'
#define DATE_STR_TYPE_3 3  //'yy-mm-dd' »ò 'yy/mm/dd' »ò 'yy.mm.dd'

/**
 * ½«Ö¸¶¨¸ñʽµÄÈÕÆÚ×Ö·û´®×ª»»ÎªÕûÊý£¬Èç¹ûÈÕÆÚ·Ç·¨£¬·µ»Ø-1
 */
int convert_to_int(char* source, int date_str_type)
{
    int year = 0;
    int month = 0;
    int day = 0;
    int i = 0;
    if (date_str_type == DATE_STR_TYPE_1) {
        //'2010-01-02'
        for (i = 0; i < 4; i++) {
            if (source[i] < '0' || source[i] > '9')
                return -1;
            year = year * 10 + (source[i] - '0');
        }

        for (i = 5; i < 7; i++) {
            if (source[i] < '0' || source[i] > '9')
                return -1;
            month = month * 10 + (source[i] - '0');
        }

        for (i = 8; i < 10; i++) {
            if (source[i] < '0' || source[i] > '9')
                return -1;
            day = day * 10 + (source[i] - '0');
        }
    } else if (date_str_type == DATE_STR_TYPE_2) {
        //'yyyymmdd'
        for (i = 0; i < 4; i++) {
            if (source[i] < '0' || source[i] > '9')
                return -1;
            year = year * 10 + (source[i] - '0');
        }
        for (i = 4; i < 6; i++) {
            if (source[i] < '0' || source[i] > '9')
                return -1;
            month = month * 10 + (source[i] - '0');
        }
        for (i = 6; i < 8; i++) {
            if (source[i] < '0' || source[i] > '9')
                return -1;
            day = day * 10 + (source[i] - '0');
        }
    } else if (date_str_type == DATE_STR_TYPE_3) {
        //'yy-mm-dd'
        for (i = 0; i < 2; i++) {
            if (source[i] < '0' || source[i] > '9')
                return -1;
            year = year * 10 + (source[i] - '0');
        }
        for (i = 3; i < 5; i++) {
            if (source[i] < '0' || source[i] > '9')
                return -1;
            month = month * 10 + (source[i] - '0');
        }
        for (i = 6; i < 8; i++) {
            if (source[i] < '0' || source[i] > '9')
                return -1;
            day = day * 10 + (source[i] - '0');
        }
    } else {
        return -1;
    }

    //²¹È«Äê·Ý
    if (year >= 0 && year <= 20)
        year += 2000;
    else if (year > 20 && year <= 99)
        year += 1900;
    // if(year < 100 && date_str_type == DATE_STR_TYPE_3) year += 1900;
    if (year == 0)
        return -1;

    // if(year < 1949) return -1;
    // if(year > 2049) return -1;
    if (month < 1 || month > 12)
        return -1;
    if (day < 1 || day > 31)
        return -1;

    //СÔÂ
    if ((month == 4 || month == 6 || month == 9 || month == 11) && day > 30)
        return -1;

    //¶þÔÂ
    if (month == 2) {
        if (((year % 4 != 0) || (year % 4 == 0 && year % 100 == 0 && year % 400 != 0)) && day > 28)
            return -1;
        else if (day > 29)
            return -1;
    }

    return year * 10000 + month * 100 + day;
}

/**
 * ÅжÏÊäÈë´®µÄ¸ñʽÀàÐÍ£¬Ö»Í¨¹ý·Ö¸ô·ûÅжÏ
 */
int check_date_string(char* source, int len)
{
    //·Ö¸ô·û
    const int sepNums = 3;
    const char separator_char[] = {'.', '/', '-'};

#define IS_SEPA_C(a) is_separator(a, sepNums, separator_char)

    if (len == 8) {
        if (IS_SEPA_C(source[2]) && IS_SEPA_C(source[5]))
            return DATE_STR_TYPE_3;
        else
            return DATE_STR_TYPE_2;
    }

    if (len == 10) {
        if (IS_SEPA_C(source[4]) && IS_SEPA_C(source[7]))
            return DATE_STR_TYPE_1;
        else
            return DATE_STR_ERR;
    }

    return DATE_STR_ERR;
}

Datum TransDate(PG_FUNCTION_ARGS)
{
    VarChar* source_v = NULL;
    uint32 len;
    char* source = NULL;
    char* result = NULL;
    Datum result_v;

    if (PG_ARGISNULL(0))
        PG_RETURN_NULL();

    source_v = PG_GETARG_BYTEA_PP(0);
    source = VARDATA_ANY(source_v);
    len = PG_GETARG_INT32(1);

    if (len > VARSIZE_ANY_EXHDR(source_v)) {
        PG_FREE_IF_COPY(source_v, 0);
        return PG_GETARG_DATUM(2);
    }

    //»ñÈ¡×Ö·û´®µÄ¸ñʽÀàÐÍ
    int date_str_type = check_date_string(source, len);
    if (date_str_type < 0) {
        PG_FREE_IF_COPY(source_v, 0);
        return PG_GETARG_DATUM(2);
    }

    int date_int = convert_to_int(source, date_str_type);
    if (date_int < 0) {
        PG_FREE_IF_COPY(source_v, 0);
        return PG_GETARG_DATUM(2);
    }

    result = (char*)palloc0(21);
    sprintf(result, "%08d", date_int);
    result_v = DirectFunctionCall3(varcharin, PointerGetDatum(result), UInt32GetDatum(0), Int32GetDatum(-1));
    PG_FREE_IF_COPY(source_v, 0);
    pfree(result);

    return result_v;
}

Datum signf(PG_FUNCTION_ARGS)
{
    float4 inputFlt;
    int result;

    if (PG_ARGISNULL(0))
        PG_RETURN_NULL();

    inputFlt = PG_GETARG_FLOAT4(0);
    result = (inputFlt > 0 ? 1 : (inputFlt < 0 ? -1 : 0));

    PG_RETURN_INT32(result);
}

Datum signi(PG_FUNCTION_ARGS)
{
    float4 inputInt;
    int result;

    if (PG_ARGISNULL(0))
        PG_RETURN_NULL();

    inputInt = PG_GETARG_INT32(0);
    result = (inputInt > 0 ? 1 : (inputInt < 0 ? -1 : 0));

    PG_RETURN_INT32(result);
}

Datum lpad_f(PG_FUNCTION_ARGS)
{
    Datum num;

    num = DirectFunctionCall2(numeric_trunc, PG_GETARG_DATUM(1), Int32GetDatum(0));
    num = DirectFunctionCall1(numeric_int4, num);

    return DirectFunctionCall3(lpad, PG_GETARG_DATUM(0), num, PG_GETARG_DATUM(2));
}

Datum rpad_f(PG_FUNCTION_ARGS)
{
    Datum num;

    num = DirectFunctionCall2(numeric_trunc, PG_GETARG_DATUM(1), Int32GetDatum(0));
    num = DirectFunctionCall1(numeric_int4, num);

    return DirectFunctionCall3(rpad, PG_GETARG_DATUM(0), num, PG_GETARG_DATUM(2));
}

Datum RoundInt(PG_FUNCTION_ARGS)
{
    int64 V0 = 0;
    int64 V2 = 0;
    int64 V3 = 0;
    int64 VR = 0;
    int64 P0 = 0;
    int64 M = 0;

    if (PG_ARGISNULL(0))
        PG_RETURN_NULL();

    V0 = PG_GETARG_INT32(0);
    if (PG_ARGISNULL(1) || (M = PG_GETARG_INT32(1)) > 0)
        PG_RETURN_INT32((int32)V0);

    P0 = pow(10, -M);
    V2 = (V0 / P0) * P0;
    V3 = V0 - V2;

    VR = V2;
    if (labs(V3) >= (0.5 * P0)) {
        if (V2 < 0)
            P0 = -P0;
        VR = V2 + P0;
    }

    PG_RETURN_INT32((int32)VR);
}

Datum RoundFloat(PG_FUNCTION_ARGS)
{
    float8 V0;
    float8 V1;
    float8 V2;
    float8 V3;
    float8 VR;
    int64 P0;
    int64 M = 0;

    if (PG_ARGISNULL(0))
        PG_RETURN_NULL();

    V0 = PG_GETARG_FLOAT4(0);
    if (!PG_ARGISNULL(1))
        M = PG_GETARG_INT32(1);

    if (M >= 0)  // Positive POWER Case
    {
        // calculate the rounding
        P0 = pow(10, M);
        V3 = V0 * P0;
        V1 = modf(V3, &V2);
        V2 = V2 / P0;
        V3 = V3 / P0;
        V3 = V0 - V2;
        VR = V2;
        // here we round up if >= 0.5 of that scale
        if (fabs(V3) >= (0.499999999999 / P0)) {
            if (V2 < 0)
                P0 = -P0;
            VR = V2 + ((float)1 / P0);
        }
    } else  // Negative POWER case
    {
        // calculate the rounding
        P0 = pow(10, -M);
        V2 = modf((V0 / P0), &V1);
        V2 = V1 * P0;
        V3 = V0 - V2;
        VR = V2;
        // here we round up if >= 0.5 of that scale
        if (fabs(V3) >= (0.5 * P0)) {
            if (V2 < 0)
                P0 = -P0;
            VR = V2 + P0;
        }
    }

    PG_RETURN_FLOAT8(VR);
}

Datum normsdist(PG_FUNCTION_ARGS)
{
    int64 I0;
    int64 I0_abs;
    int64 mid;
    int64 base_value;
    int64 min_x_value;
    int64 max_pro_value;
    int64 min_pro_value;

    float8 normvalue;
    float8 gamma;
    float8 mid_value;
    float8 a1;
    float8 a2;
    float8 a3;
    float8 a4;
    float8 a5;
    float8 k;
    float8 n;
    float8 result;

    int64 Multiplier = 1000000000000000;

    gamma = 0.2316419;
    a1 = 0.31938153;
    a2 = -0.356563782;
    a3 = 1.781477973;
    a4 = -1.821255978;
    a5 = 1.330274429;
    k = 0;
    n = 0;
    base_value = 0.5 * Multiplier;
    min_x_value = 10 * Multiplier;
    max_pro_value = 0.999999999 * Multiplier;
    min_pro_value = 0.000000001 * Multiplier;

    if (PG_ARGISNULL(0))
        PG_RETURN_NULL();

    I0 = to_int64(PG_GETARG_DATUM(0), Multiplier);
    // È¡´úÔ­ÏȵÄabs(I0)
    I0_abs = I0 < 0 ? -I0 : I0;
    if (I0 == 0) {
        result = (float8)base_value / Multiplier;
        return DirectFunctionCall1(float8_numeric, Float8GetDatum(result));
    };

    if (I0 >= min_x_value) {
        result = (float8)max_pro_value / Multiplier;
        return DirectFunctionCall1(float8_numeric, Float8GetDatum(result));
    }

    if (I0_abs >= min_x_value) {
        result = (float8)min_pro_value / Multiplier;
        return DirectFunctionCall1(float8_numeric, Float8GetDatum(result));
    }

    k = (float8)Multiplier / (Multiplier + I0_abs * gamma);
    n = (float8)k * (a1 + k * (a2 + k * (a3 + k * (a4 + k * a5))));

    mid_value = (float8)I0 / Multiplier;  // modify 20130506
    mid_value = mid_value * mid_value;
    mid_value = exp(-mid_value / 2);
    normvalue = (1 / sqrt(2 * 3.1415926)) * mid_value;
    n = 1 - normvalue * n;

    // for test start
    // mid = n*Multiplier;
    // memcpy((BYTE *) result, &mid, 8);
    // r/eturn;
    // for test end

    if (I0 < 0)
        mid = (1 - n) * Multiplier;
    else
        mid = n * Multiplier;
    result = (float8)mid / Multiplier;
    return DirectFunctionCall1(float8_numeric, Float8GetDatum(result));
}

#define LastDay(y, m) (((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) ? LastDaysL[m] : LastDays[m])

Datum months_between_dd(PG_FUNCTION_ARGS)
{
    DateADT date1 = PG_GETARG_DATEADT(0);
    DateADT date2 = PG_GETARG_DATEADT(1);
    struct pg_tm tm1;
    struct pg_tm tm2;
    short LastDays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    short LastDaysL[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    float result;

    j2date(date1 + POSTGRES_EPOCH_JDATE, &tm1.tm_year, &tm1.tm_mon, &tm1.tm_mday);
    j2date(date2 + POSTGRES_EPOCH_JDATE, &tm2.tm_year, &tm2.tm_mon, &tm2.tm_mday);
    tm1.tm_mon = tm1.tm_mon - 1;
    tm2.tm_mon = tm2.tm_mon - 1;

    if (tm1.tm_mday > 27 && tm2.tm_mday > 27 && tm1.tm_mday == LastDay(tm1.tm_year, tm1.tm_mon) &&
        tm2.tm_mday == LastDay(tm2.tm_year, tm2.tm_mon))
        result = (tm1.tm_year * 12 + tm1.tm_mon) - (tm2.tm_year * 12 + tm2.tm_mon);
    else
        result =
            (((tm1.tm_year * 12 + tm1.tm_mon) - (tm2.tm_year * 12 + tm2.tm_mon)) * 31 + tm1.tm_mday - tm2.tm_mday) /
            31.0;

    PG_RETURN_FLOAT4(result);
}

Datum months_between_dt(PG_FUNCTION_ARGS)
{
    DateADT date1 = PG_GETARG_DATEADT(0);
    Timestamp date2 = PG_GETARG_TIMESTAMP(1);
    fsec_t fsec;
    struct pg_tm tt, *tm = &tt;
    int LastDays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int LastDaysL[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int Year1, Month1, Months1, Day1;
    int Year2, Month2, Months2, Day2;
    float result;

    j2date(date1 + POSTGRES_EPOCH_JDATE, &Year1, &Month1, &Day1);
    Month1 = Month1 - 1;

    timestamp2tm(date2, NULL, tm, &fsec, NULL, NULL);
    Year2 = tm->tm_year;
    Month2 = tm->tm_mon - 1;
    Day2 = tm->tm_mday;

    Months1 = Year1 * 12 + Month1;
    Months2 = Year2 * 12 + Month2;

    if (Day1 > 27 && Day2 > 27 && Day1 == LastDay(Year1, Month1) && Day2 == LastDay(Year2, Month2))
        result = Months1 - Months2;
    else
        result = ((Months1 - Months2) * 31 + Day1 - Day2) / 31.0;

    PG_RETURN_FLOAT4(result);
}

Datum months_between_td(PG_FUNCTION_ARGS)
{
    Timestamp date1 = PG_GETARG_TIMESTAMP(0);
    DateADT date2 = PG_GETARG_DATEADT(1);
    fsec_t fsec;
    struct pg_tm tt, *tm = &tt;
    int LastDays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int LastDaysL[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int Year1, Month1, Months1, Day1;
    int Year2, Month2, Months2, Day2;
    float result;

    timestamp2tm(date1, NULL, tm, &fsec, NULL, NULL);
    Year1 = tm->tm_year;
    Month1 = tm->tm_mon - 1;
    Day1 = tm->tm_mday;
    j2date(date2 + POSTGRES_EPOCH_JDATE, &Year2, &Month2, &Day2);
    Month2 = Month2 - 1;

    Months1 = Year1 * 12 + Month1;
    Months2 = Year2 * 12 + Month2;

    if (Day1 > 27 && Day2 > 27 && Day1 == LastDay(Year1, Month1) && Day2 == LastDay(Year2, Month2))
        result = Months1 - Months2;
    else
        result = ((Months1 - Months2) * 31 + Day1 - Day2) / 31.0;

    PG_RETURN_FLOAT4(result);
}

Datum months_between_tt(PG_FUNCTION_ARGS)
{
    Timestamp date1 = PG_GETARG_TIMESTAMP(0);
    Timestamp date2 = PG_GETARG_TIMESTAMP(1);
    fsec_t fsec;
    struct pg_tm tt, *tm = &tt;
    int LastDays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int LastDaysL[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int Year1, Month1, Months1, Day1;
    int Year2, Month2, Months2, Day2;
    float result;

    timestamp2tm(date1, NULL, tm, &fsec, NULL, NULL);
    Year1 = tm->tm_year;
    Month1 = tm->tm_mon - 1;
    Day1 = tm->tm_mday;
    timestamp2tm(date2, NULL, tm, &fsec, NULL, NULL);
    Year2 = tm->tm_year;
    Month2 = tm->tm_mon - 1;
    Day2 = tm->tm_mday;

    Months1 = Year1 * 12 + Month1;
    Months2 = Year2 * 12 + Month2;

    if (Day1 > 27 && Day2 > 27 && Day1 == LastDay(Year1, Month1) && Day2 == LastDay(Year2, Month2))
        result = Months1 - Months2;
    else
        result = ((Months1 - Months2) * 31 + Day1 - Day2) / 31.0;

    PG_RETURN_FLOAT4(result);
}

Datum last_day_d(PG_FUNCTION_ARGS)
{
    DateADT inDate = PG_GETARG_DATEADT(0);
    short LastDays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    short LastDaysL[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    int syear;
    int smonth;
    int sday;
    j2date(inDate + POSTGRES_EPOCH_JDATE, &syear, &smonth, &sday);
    sday = LastDay(syear, smonth - 1);

    PG_RETURN_DATEADT(date2j(syear, smonth, sday) - POSTGRES_EPOCH_JDATE);
}

Datum last_day_t(PG_FUNCTION_ARGS)
{
    Timestamp inTimestamp = PG_GETARG_TIMESTAMP(0);
    Timestamp result;
    int tz = 0;
    short LastDays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    short LastDaysL[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    struct pg_tm tt, *tm = &tt;
    fsec_t fsec;

    if (timestamp2tm(inTimestamp, NULL, tm, &fsec, NULL, NULL) != 0)
        ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range")));

    tm->tm_mday = LastDay(tm->tm_year, tm->tm_mon - 1);

    if (tm2timestamp(tm, fsec, &tz, &result) != 0)
        ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range")));

    PG_RETURN_TIMESTAMP(result);
}

Datum last_day_tz(PG_FUNCTION_ARGS)
{
    TimestampTz inTimestampTz = PG_GETARG_TIMESTAMPTZ(0);
    TimestampTz result;
    int tz;
    short LastDays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    short LastDaysL[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    struct pg_tm tt, *tm = &tt;
    fsec_t fsec;

    if (timestamp2tm(inTimestampTz, &tz, tm, &fsec, NULL, NULL) != 0)
        ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range")));
    tm->tm_mday = LastDay(tm->tm_year, tm->tm_mon - 1);

    if (tm2timestamp(tm, fsec, &tz, &result) != 0)
        ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range")));

    PG_RETURN_TIMESTAMP(result);
}

/* FUNC_III_CS0507_3 */
Datum FUNC_III_CS0507_3(PG_FUNCTION_ARGS)
{
    text* result = NULL;
    StringInfo buf = NULL;
    int64 p1;
    int64 Multiplier = 10000;

    buf = makeStringInfo();

    if (PG_ARGISNULL(0)) {
        appendBinaryStringInfo(buf, "030", strlen("030"));
        result = cstring_to_text(buf->data);
        pfree(buf->data);
        pfree(buf);
        PG_RETURN_TEXT_P(result);
    } else {
        p1 = to_int64(PG_GETARG_DATUM(0), Multiplier);
    }

    if (p1 > 0 && p1 <= 30 * Multiplier) {
        appendBinaryStringInfo(buf, "021", strlen("021"));
        result = cstring_to_text(buf->data);
        pfree(buf->data);
        pfree(buf);
        PG_RETURN_TEXT_P(result);
    } else if (p1 > 30 * Multiplier && p1 <= 50 * Multiplier) {
        appendBinaryStringInfo(buf, "022", strlen("022"));
        result = cstring_to_text(buf->data);
        pfree(buf->data);
        pfree(buf);
        PG_RETURN_TEXT_P(result);
    } else if (p1 > 50 * Multiplier && p1 <= 60 * Multiplier) {
        appendBinaryStringInfo(buf, "023", strlen("023"));
        result = cstring_to_text(buf->data);
        pfree(buf->data);
        pfree(buf);
        PG_RETURN_TEXT_P(result);
    }

    else if (p1 > 60 * Multiplier && p1 <= 70 * Multiplier) {
        appendBinaryStringInfo(buf, "024", strlen("024"));
        result = cstring_to_text(buf->data);
        pfree(buf->data);
        pfree(buf);
        PG_RETURN_TEXT_P(result);
    }

    else if (p1 > 70 * Multiplier && p1 <= 80 * Multiplier) {
        appendBinaryStringInfo(buf, "025", strlen("025"));
        result = cstring_to_text(buf->data);
        pfree(buf->data);
        pfree(buf);
        PG_RETURN_TEXT_P(result);
    }

    else if (p1 > 80 * Multiplier && p1 <= 90 * Multiplier) {
        appendBinaryStringInfo(buf, "026", strlen("026"));
        result = cstring_to_text(buf->data);
        pfree(buf->data);
        pfree(buf);
        PG_RETURN_TEXT_P(result);
    }

    else {
        appendBinaryStringInfo(buf, "027", strlen("027"));
        result = cstring_to_text(buf->data);
        pfree(buf->data);
        pfree(buf);
        PG_RETURN_TEXT_P(result);
    }
}

/* FUNC_III_CS0507 */
Datum FUNC_III_CS0507(PG_FUNCTION_ARGS)
{
    text* result = NULL;
    StringInfo buf = NULL;

    int64 p1;
    int64 Multiplier = 10000;

    buf = makeStringInfo();
    if (PG_ARGISNULL(0)) {
        appendBinaryStringInfo(buf, "004", strlen("004"));
        result = cstring_to_text(buf->data);
        pfree(buf->data);
        pfree(buf);
        PG_RETURN_TEXT_P(result);
    } else {
        p1 = to_int64(PG_GETARG_DATUM(0), Multiplier);
    }

    if (p1 < 12 * Multiplier) {
        appendBinaryStringInfo(buf, "001", strlen("001"));
        result = cstring_to_text(buf->data);
        pfree(buf->data);
        pfree(buf);
        PG_RETURN_TEXT_P(result);
    } else if (p1 >= 12 * Multiplier && p1 <= 35 * Multiplier) {
        appendBinaryStringInfo(buf, "002", strlen("002"));
        result = cstring_to_text(buf->data);
        pfree(buf->data);
        pfree(buf);
        PG_RETURN_TEXT_P(result);
    } else if (p1 >= 36 * Multiplier && p1 <= 59 * Multiplier) {
        appendBinaryStringInfo(buf, "003", strlen("003"));
        result = cstring_to_text(buf->data);
        pfree(buf->data);
        pfree(buf);
        PG_RETURN_TEXT_P(result);
    } else {
        appendBinaryStringInfo(buf, "004", strlen("004"));
        result = cstring_to_text(buf->data);
        pfree(buf->data);
        pfree(buf);
        PG_RETURN_TEXT_P(result);
    }
}

/* FUNC_II_JUDGE_DF_AGE */
Datum FUNC_II_JUDGE_DF_AGE(PG_FUNCTION_ARGS)
{
    int64 p1;
    int64 p2;
    int64 p3;
    int64 p4;
    int64 p5;
    int64 p6;
    int64 p7;
    int64 p8;
    int64 p9;
    int64 p10;
    int64 p11;
    int64 p12;
    int64 Multiplier = 10000;

    int p;

    // ¡ä|¨¤¨ª¨¨?2??aNULl¦Ì??¨¦??
    if (PG_ARGISNULL(0)) {
        p1 = -1 * Multiplier;
    } else
        p1 = to_int64(PG_GETARG_DATUM(0), Multiplier);

    if (PG_ARGISNULL(1)) {
        p2 = -1 * Multiplier;
    } else
        p2 = to_int64(PG_GETARG_DATUM(1), Multiplier);

    if (PG_ARGISNULL(2)) {
        p3 = -1 * Multiplier;
    } else
        p3 = to_int64(PG_GETARG_DATUM(2), Multiplier);

    if (PG_ARGISNULL(3)) {
        p4 = -1 * Multiplier;
    } else
        p4 = to_int64(PG_GETARG_DATUM(3), Multiplier);

    if (PG_ARGISNULL(4)) {
        p5 = -1 * Multiplier;
    } else
        p5 = to_int64(PG_GETARG_DATUM(4), Multiplier);

    if (PG_ARGISNULL(5)) {
        p6 = -1 * Multiplier;
    } else
        p6 = to_int64(PG_GETARG_DATUM(5), Multiplier);

    if (PG_ARGISNULL(6)) {
        p7 = -1 * Multiplier;
    } else
        p7 = to_int64(PG_GETARG_DATUM(6), Multiplier);

    if (PG_ARGISNULL(7)) {
        p8 = -1 * Multiplier;
    } else
        p8 = to_int64(PG_GETARG_DATUM(7), Multiplier);

    if (PG_ARGISNULL(8)) {
        p9 = -1 * Multiplier;
    } else
        p9 = to_int64(PG_GETARG_DATUM(8), Multiplier);

    if (PG_ARGISNULL(9)) {
        p10 = -1 * Multiplier;
    } else
        p10 = to_int64(PG_GETARG_DATUM(9), Multiplier);

    if (PG_ARGISNULL(10)) {
        p11 = -1 * Multiplier;
    } else
        p11 = to_int64(PG_GETARG_DATUM(10), Multiplier);

    if (PG_ARGISNULL(11)) {
        p12 = -1 * Multiplier;
    } else
        p12 = to_int64(PG_GETARG_DATUM(11), Multiplier);

    if (p1 == 0) {
        p = 0;
        PG_RETURN_INT32(p);
    } else if (p2 == 0 && p1 == 1 * Multiplier) {
        p = 1;
        PG_RETURN_INT32(p);
    } else if (p3 == 0 && p2 == 1 * Multiplier) {
        p = 2;
        PG_RETURN_INT32(p);
    } else if (p4 == 0 && p3 == 1 * Multiplier) {
        p = 3;
        PG_RETURN_INT32(p);
    } else if (p5 == 0 && p4 == 1 * Multiplier) {
        p = 4;
        PG_RETURN_INT32(p);
    } else if (p6 == 0 && p5 == 1 * Multiplier) {
        p = 5;
        PG_RETURN_INT32(p);
    } else if (p7 == 0 && p6 == 1 * Multiplier) {
        p = 6;
        PG_RETURN_INT32(p);
    } else if (p8 == 0 && p7 == 1 * Multiplier) {
        p = 7;
        PG_RETURN_INT32(p);
    } else if (p9 == 0 && p8 == 1 * Multiplier) {
        p = 8;
        PG_RETURN_INT32(p);
    } else if (p10 == 0 && p9 == 1 * Multiplier) {
        p = 9;
        PG_RETURN_INT32(p);
    } else if (p11 == 0 && p10 == 1 * Multiplier) {
        p = 10;
        PG_RETURN_INT32(p);
    } else if (p12 == 0 && p11 == 1 * Multiplier) {
        p = 11;
        PG_RETURN_INT32(p);
    } else {
        p = 99;
        PG_RETURN_INT32(p);
    }
}

/* FUNC_TRANS_MOBCODE */
Datum FUNC_TRANS_MOBCODE(PG_FUNCTION_ARGS)
{
    int64 p1;
    text* result = NULL;
    StringInfo buf = NULL;
    int64 Multiplier = 10000;

    buf = makeStringInfo();
    if (PG_ARGISNULL(0)) {
        appendBinaryStringInfo(buf, "001", 3);
        result = cstring_to_text(buf->data);
        pfree(buf->data);
        pfree(buf);
        PG_RETURN_TEXT_P(result);
    } else
        p1 = to_int64(PG_GETARG_DATUM(0), Multiplier);

    if (p1 == Multiplier) {
        appendBinaryStringInfo(buf, "001", 3);
    } else if (p1 == 2 * Multiplier) {
        appendBinaryStringInfo(buf, "002", 3);
    } else if (p1 == 3 * Multiplier) {
        appendBinaryStringInfo(buf, "003", 3);
    } else if (p1 == 4 * Multiplier) {
        appendBinaryStringInfo(buf, "004", 3);
    } else if (p1 == 5 * Multiplier) {
        appendBinaryStringInfo(buf, "005", 3);
    } else if (p1 == 6 * Multiplier) {
        appendBinaryStringInfo(buf, "006", 3);
    } else if (p1 == 7 * Multiplier) {
        appendBinaryStringInfo(buf, "007", 3);
    } else if (p1 == 8 * Multiplier) {
        appendBinaryStringInfo(buf, "008", 3);
    } else if (p1 == 9 * Multiplier) {
        appendBinaryStringInfo(buf, "009", 3);
    } else if (p1 == 10 * Multiplier) {
        appendBinaryStringInfo(buf, "010", 3);
    } else if (p1 == 11 * Multiplier) {
        appendBinaryStringInfo(buf, "011", 3);
    } else if (p1 == 12 * Multiplier) {
        appendBinaryStringInfo(buf, "012", 3);
    } else {
        appendBinaryStringInfo(buf, "013", 3);
    }

    result = cstring_to_text(buf->data);
    pfree(buf->data);
    pfree(buf);
    PG_RETURN_TEXT_P(result);
}

/* FUNC_TRANS_RISKCODE */
Datum FUNC_TRANS_RISKCODE(PG_FUNCTION_ARGS)
{
    int64 p1;
    StringInfo buf = NULL;
    text* result = NULL;
    char* p_i_cardtype = NULL;
    int64 Multiplier = 10000;

    buf = makeStringInfo();
    if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) {
        appendBinaryStringInfo(buf, "014", 3);
        result = cstring_to_text(buf->data);
        pfree(buf->data);
        pfree(buf);
        PG_RETURN_TEXT_P(result);
    } else {
        p_i_cardtype = text_to_cstring(PG_GETARG_TEXT_PP(0));
        p1 = to_int64(PG_GETARG_DATUM(1), Multiplier);
    }

    // if( ( p_i_cardtype[0] == 'C' || p_i_cardtype[0] == 'I' ) && p_i_cardtype[1] == 'C' )
    if (strcmp((const char*)p_i_cardtype, (const char*)"CC") == 0 ||
        strcmp((const char*)p_i_cardtype, (const char*)"IC") == 0) {
        if (p1 == 0) {
            appendBinaryStringInfo(buf, "015", 3);
        } else if (p1 == Multiplier) {
            appendBinaryStringInfo(buf, "001", 3);
        } else if (p1 == 2 * Multiplier) {
            appendBinaryStringInfo(buf, "002", 3);
        } else if (p1 == 3 * Multiplier) {
            appendBinaryStringInfo(buf, "003", 3);
        } else if (p1 == 4 * Multiplier) {
            appendBinaryStringInfo(buf, "004", 3);
        } else if (p1 == 5 * Multiplier) {
            appendBinaryStringInfo(buf, "005", 3);
        } else if (p1 == 6 * Multiplier) {
            appendBinaryStringInfo(buf, "006", 3);
        } else if (p1 == 7 * Multiplier) {
            appendBinaryStringInfo(buf, "007", 3);
        } else if (p1 == 8 * Multiplier) {
            appendBinaryStringInfo(buf, "008", 3);
        } else if (p1 == 9 * Multiplier) {
            appendBinaryStringInfo(buf, "009", 3);
        } else if (p1 == 10 * Multiplier) {
            appendBinaryStringInfo(buf, "010", 3);
        } else if (p1 == 11 * Multiplier) {
            appendBinaryStringInfo(buf, "011", 3);
        } else if (p1 == 12 * Multiplier) {
            appendBinaryStringInfo(buf, "012", 3);
        } else {
            appendBinaryStringInfo(buf, "013", 3);
        }
    } else {
        if (p1 == 0) {
            appendBinaryStringInfo(buf, "015", 3);
        } else if (p1 == Multiplier) {
            appendBinaryStringInfo(buf, "016", 3);
        } else if (p1 == 2 * Multiplier) {
            appendBinaryStringInfo(buf, "001", 3);
        } else if (p1 == 3 * Multiplier) {
            appendBinaryStringInfo(buf, "002", 3);
        } else if (p1 == 4 * Multiplier) {
            appendBinaryStringInfo(buf, "003", 3);
        } else if (p1 == 5 * Multiplier) {
            appendBinaryStringInfo(buf, "004", 3);
        } else if (p1 == 6 * Multiplier) {
            appendBinaryStringInfo(buf, "005", 3);
        } else if (p1 == 7 * Multiplier) {
            appendBinaryStringInfo(buf, "006", 3);
        } else if (p1 == 8 * Multiplier) {
            appendBinaryStringInfo(buf, "007", 3);
        } else if (p1 == 9 * Multiplier) {
            appendBinaryStringInfo(buf, "008", 3);
        } else if (p1 == 10 * Multiplier) {
            appendBinaryStringInfo(buf, "009", 3);
        } else if (p1 == 11 * Multiplier) {
            appendBinaryStringInfo(buf, "010", 3);
        } else if (p1 == 12 * Multiplier) {
            appendBinaryStringInfo(buf, "011", 3);
        } else {
            appendBinaryStringInfo(buf, "013", 3);
        }
    }

    result = cstring_to_text(buf->data);
    pfree(buf->data);
    pfree(buf);
    pfree(p_i_cardtype);
    PG_RETURN_TEXT_P(result);
}

/* FUNC_XW_FIX_DPD */
Datum FUNC_XW_FIX_DPD(PG_FUNCTION_ARGS)
{

    int64 p1;
    char* var1 = NULL;
    int result;
    int64 Multiplier = 10000;

    if (PG_ARGISNULL(0)) {
        result = 2;
        PG_RETURN_INT32(result);
    } else
        var1 = text_to_cstring(PG_GETARG_TEXT_PP(0));

    if (strcmp(var1, "002") == 0 || strcmp(var1, "003") == 0 || strcmp(var1, "004") == 0) {
        if (PG_ARGISNULL(1)) {
            result = 2;
            PG_RETURN_INT32(result);
        } else
            p1 = to_int64(PG_GETARG_DATUM(1), Multiplier);

        if (p1 == 2 * Multiplier) {
            result = 8;
        } else if (p1 == 3 * Multiplier) {
            result = 7;
        } else if (p1 == 4 * Multiplier) {
            result = 6;
        } else if (p1 == 5 * Multiplier) {
            result = 5;
        } else if (p1 == 6 * Multiplier) {
            result = 4;
        } else if (p1 == 7 * Multiplier) {
            result = 3;
        } else {
            result = 2;
        }
    } else {
        if (PG_ARGISNULL(1)) {
            result = 2;
            PG_RETURN_INT32(result);
        } else
            p1 = to_int64(PG_GETARG_DATUM(1), Multiplier);

        if (p1 == 4 * Multiplier) {
            result = 8;
        } else if (p1 == 5 * Multiplier) {
            result = 7;
        } else if (p1 == 6 * Multiplier) {
            result = 6;
        } else if (p1 == 7 * Multiplier) {
            result = 5;
        } else if (p1 == 8 * Multiplier) {
            result = 4;
        } else if (p1 == 9 * Multiplier) {
            result = 3;
        } else {
            result = 2;
        }
    }

    pfree(var1);
    PG_RETURN_INT32(result);
}

/* FUNC_ZERO_NULL */
Datum FUNC_ZERO_NULL(PG_FUNCTION_ARGS)
{
    int64 p1;
    float8 result;
    int64 Multiplier = 10000;

    p1 = to_int64(PG_GETARG_DATUM(0), Multiplier);

    if (p1 == 0) {
        PG_RETURN_NULL();
    } else {
        result = (float8)p1 / Multiplier;
        return DirectFunctionCall1(float8_numeric, Float8GetDatum(result));
    }
}

/* greatestcc (text, text):
 * 	compare text with text
 */
Datum greatestcc(PG_FUNCTION_ARGS)
{
    text* result = NULL;
    char* str1 = NULL;
    char* str2 = NULL;

    str1 = text_to_cstring(PG_GETARG_TEXT_PP(0));
    str2 = text_to_cstring(PG_GETARG_TEXT_PP(1));

    if (strcmp((const char*)str2, (const char*)str1) > 0) {
        result = cstring_to_text(str2);
    } else {
        result = cstring_to_text(str1);
    }

    pfree(str1);
    pfree(str2);
    PG_RETURN_TEXT_P(result);
}

/* greatestcd (text, float8):
 * 	compare text with float8_to_text
 * Note: input float8 will be convert to numeric with 4 decimal digits
 */
Datum greatestcd(PG_FUNCTION_ARGS)
{
    int64 p2;
    int64 Multiplier = 10000;
    int length;
    int i, j;

    char inputStr2[30] = "";
    char* inputStr1 = NULL;
    char char_result[32] = "";
    text* result = NULL;

    inputStr1 = text_to_cstring(PG_GETARG_TEXT_PP(0));
    p2 = to_int64(PG_GETARG_DATUM(1), Multiplier);

    /* assume that: input data is decimal(18,4) */
    sprintf(inputStr2, "%lld", (long long)p2);

    length = strlen(inputStr2);

    j = 0;
    for (i = 0; i <= length; i++) {
        char_result[i] = inputStr2[j];
        j = j + 1;

        if (i == length - 4 - 1) {  // ?D??¦Ì¡À?a¦Ì1¨ºy¦Ì¨²4??¡Á?¡¤?¨º¡À, ?1?-D?¨ºy¦Ì?
            i = i + 1;
            char_result[i] = '.';
        }
    }
    char_result[i] = '\0';  // ¨¬¨ª?¨®¡Á?¡¤?¡ä??¨¢¨º?¡¤?

    if (strcmp((const char*)char_result, (const char*)inputStr1) > 0)
        result = cstring_to_text(char_result);
    else
        result = cstring_to_text(inputStr1);

    pfree(inputStr1);
    PG_RETURN_TEXT_P(result);
}

/* greatestci (text, int):
 * 	compare text with int_to_text
 */
Datum greatestci(PG_FUNCTION_ARGS)
{
    int32 p2;

    char inputStr2[20] = "";
    char* inputStr1 = NULL;
    text* result = NULL;

    inputStr1 = text_to_cstring(PG_GETARG_TEXT_PP(0));
    p2 = PG_GETARG_INT32(1);

    sprintf(inputStr2, "%d", p2);

    if (strcmp((const char*)inputStr2, (const char*)inputStr1) > 0)
        result = cstring_to_text(inputStr2);
    else
        result = cstring_to_text(inputStr1);

    pfree(inputStr1);
    PG_RETURN_TEXT_P(result);
}

/* greatestdc (float8, text):
 * 	compare float8 with text_to_float8
 */
Datum greatestdc(PG_FUNCTION_ARGS)
{

    int64 p1;
    float8 p2;
    int64 p = 0;
    char* str2 = NULL;
    int64 Multiplier = 10000;
    float8 result;
    Datum q2;
    int64 i2;

    p1 = to_int64(PG_GETARG_DATUM(0), Multiplier);
    str2 = text_to_cstring(PG_GETARG_TEXT_PP(1));

    p2 = strtod((const char*)str2, (char**)NULL);
    q2 = DirectFunctionCall1(float8_numeric, Float8GetDatum(p2));
    i2 = to_int64(q2, Multiplier);
    p = i2 > p1 ? i2 : p1;

    pfree(str2);
    result = (float8)p / Multiplier;
    return DirectFunctionCall1(float8_numeric, Float8GetDatum(result));
}

/* greatestdd (float8, float8):
 * 	compare float8 with float8
 */
Datum greatestdd(PG_FUNCTION_ARGS)
{
    int64 p1;
    int64 p2;
    int64 p;
    int64 Multiplier = 10000;
    float8 result;

    p1 = to_int64(PG_GETARG_DATUM(0), Multiplier);
    p2 = to_int64(PG_GETARG_DATUM(1), Multiplier);

    p = (p2 > p1 ? p2 : p1);
    result = (float8)p / Multiplier;
    return DirectFunctionCall1(float8_numeric, Float8GetDatum(result));
}

/* greatestdi (float8, int):
 * 	compare float8 with int
 */
Datum greatestdi(PG_FUNCTION_ARGS)
{

    int64 p1;
    int32 p2;
    int64 p;
    int64 Multiplier = 10000;
    float8 result;

    p1 = to_int64(PG_GETARG_DATUM(0), Multiplier);
    p2 = PG_GETARG_INT32(1);
    p = (p2 * Multiplier) > p1 ? (p2 * Multiplier) : p1;

    result = (float8)p / Multiplier;
    return DirectFunctionCall1(float8_numeric, Float8GetDatum(result));
}

/* greatestic (int, text):
 * 	compare int with text_to_int
 */
Datum greatestic(PG_FUNCTION_ARGS)
{
    int32 p1;
    int32 p2 = 0;
    char* str2 = NULL;
    int32 p;

    p1 = PG_GETARG_INT32(0);
    str2 = text_to_cstring(PG_GETARG_TEXT_PP(1));
    p2 = (int32)strtol((const char*)str2, (char**)NULL, 10);

    p = p2 > p1 ? p2 : p1;
    pfree(str2);
    PG_RETURN_INT32(p);
}

/* greatestid (int, float8):
 * 	compare int with float8
 */
Datum greatestid(PG_FUNCTION_ARGS)
{
    int32 p1;
    int64 p2;
    int64 p;
    int64 Multiplier = 10000;
    float8 result;

    p1 = PG_GETARG_INT32(0);
    p2 = to_int64(PG_GETARG_DATUM(1), Multiplier);

    p = (p1 * Multiplier) > p2 ? (p1 * Multiplier) : p2;
    result = (float8)p / Multiplier;
    return DirectFunctionCall1(float8_numeric, Float8GetDatum(result));
}

/***************create_type check*****************************/
typedef struct Complex {
    double x;
    double y;
} Complex;

Datum complex_in(PG_FUNCTION_ARGS)
{
    char* str = PG_GETARG_CSTRING(0);
    double x, y;
    Complex* result = NULL;

    if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2)
        ereport(ERROR,
            (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for complex: \"%s\"", str)));

    result = (Complex*)palloc(sizeof(Complex));
    result->x = x;
    result->y = y;
    PG_RETURN_POINTER(result);
}

Datum complex_out(PG_FUNCTION_ARGS)
{
    Complex* complex = (Complex*)PG_GETARG_POINTER(0);
    char* result = NULL;

    result = (char*)palloc(100);
    snprintf(result, 100, "(%g,%g)", complex->x, complex->y);
    PG_RETURN_CSTRING(result);
}

Datum complex_recv(PG_FUNCTION_ARGS)
{
    StringInfo buf = (StringInfo)PG_GETARG_POINTER(0);
    Complex* result = NULL;

    result = (Complex*)palloc(sizeof(Complex));
    result->x = pq_getmsgfloat8(buf);
    result->y = pq_getmsgfloat8(buf);
    PG_RETURN_POINTER(result);
}

Datum complex_send(PG_FUNCTION_ARGS)
{
    Complex* complex = (Complex*)PG_GETARG_POINTER(0);
    StringInfoData buf;

    pq_begintypsend(&buf);
    pq_sendfloat8(&buf, complex->x);
    pq_sendfloat8(&buf, complex->y);
    PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}

extern bool analyze_requires_snapshot(Node* parseTree);

Datum query_get_unique_sql_id(PG_FUNCTION_ARGS)
{
    char* query_string = text_to_cstring(PG_GETARG_TEXT_PP(0));
    List* parsetree_list = pg_parse_query(query_string);
    List* querytree_list = NIL;
    bool snapshot_set = false;
    if (parsetree_list == NIL || list_length(parsetree_list) > 1) {
        ereport(ERROR,
            (errcode(ERRCODE_SYNTAX_ERROR), errmsg("only support single statement")));
    }
    Node* raw_parse_tree = (Node*)linitial(parsetree_list);
    if (analyze_requires_snapshot(raw_parse_tree)) {
        PushActiveSnapshot(GetTransactionSnapshot());
        snapshot_set = true;
    }
    u_sess->unique_sql_cxt.is_top_unique_sql = false;
    querytree_list = pg_analyze_and_rewrite(raw_parse_tree, query_string, NULL, 0);
    u_sess->unique_sql_cxt.is_top_unique_sql = true;
    Query* query = (Query*)linitial(querytree_list);
    uint64 query_id = query->uniqueSQLId;
    if (snapshot_set) {
        PopActiveSnapshot();
    }
    list_free_deep(parsetree_list);
    list_free_deep(querytree_list);
    pfree_ext(query_string);
    PG_RETURN_INT64((int64)query_id);
}