15670430创建于 2020年12月28日历史提交
/*
 * Copyright (c) 2020 Huawei Technologies Co.,Ltd.
 *
 * openGauss is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * -------------------------------------------------------------------------
 *
 * int4.inl
 *	  template implementation of 32-bit integers.
 *
 * IDENTIFICATION
 *    src/gausskernel/runtime/vecexecutor/vecprimitive/int4.inl
 *
 *-------------------------------------------------------------------------
 */

#ifndef INT4_INL
#define INT4_INL

#include "catalog/pg_type.h"
#include <ctype.h>
#include <limits.h>
#include "vecexecutor/vechashtable.h"
#include "utils/array.h"
#include "utils/biginteger.h"
#include "vectorsonic/vsonichashagg.h"

#define SAMESIGN(a,b)	(((a) < 0) == ((b) < 0))

typedef struct vecInt8TransTypeData
{
	int64		count;
	int64		sum;
} VecInt8TransTypeData;

template <SimpleOp sop,typename Datatype>
ScalarVector*
vint_sop(PG_FUNCTION_ARGS)
{
	ScalarValue* parg1 = PG_GETARG_VECVAL(0);
	ScalarValue* parg2 = PG_GETARG_VECVAL(1);
	int32		 nvalues = PG_GETARG_INT32(2);
	ScalarValue* presult = PG_GETARG_VECVAL(3);
	uint8*	pflag = (uint8*)(PG_GETARG_VECTOR(3)->m_flag);
	bool*		pselection = PG_GETARG_SELECTION(4);
	uint8*		pflags1 = (uint8*)(PG_GETARG_VECTOR(0)->m_flag);
	uint8*		pflags2 = (uint8*)(PG_GETARG_VECTOR(1)->m_flag);
	int          i;


    if(likely(pselection == NULL))
    {
    	for (i = 0; i < nvalues; i++)
		{
			if (BOTH_NOT_NULL(pflags1[i], pflags2[i]))
			{
				presult[i] = eval_simple_op<sop, Datatype>((Datatype)parg1[i], (Datatype)parg2[i]);
				SET_NOTNULL(pflag[i]);
			}
			else
				SET_NULL(pflag[i]);
		}
    }
	else
	{
		for (i = 0; i < nvalues; i++)
		{
			if(pselection[i])
			{
				if (BOTH_NOT_NULL(pflags1[i], pflags2[i]))
				{
					presult[i] = eval_simple_op<sop, Datatype>((Datatype)parg1[i], (Datatype)parg2[i]);
					SET_NOTNULL(pflag[i]);
				}
			else
				SET_NULL(pflag[i]);
			}
		}
	}

    PG_GETARG_VECTOR(3)->m_rows = nvalues;
    PG_GETARG_VECTOR(3)->m_desc.typeId = BOOLOID;
    return PG_GETARG_VECTOR(3);
}

/* 
 * vint_avg_final: For each level of avg, a final operation is needed.
 *
 * singlenode: is the last stage of avg. If so, output is numeric type, or array type.
 */
template<bool singlenode>
Datum
vint_avg_final(PG_FUNCTION_ARGS)
{
	hashCell* cell = (hashCell*)PG_GETARG_DATUM(0);
	int		  idx  = PG_GETARG_DATUM(1);
	ScalarValue*  pvals = (ScalarValue*)PG_GETARG_DATUM(2);
	uint8  *pflag = (uint8*)PG_GETARG_DATUM(3);
	Datum	  args[2];
	FunctionCallInfoData finfo;

	finfo.arg = &args[0];
	if(singlenode)
	{
		if(IS_NULL(cell->m_val[idx].flag))
		{
			SET_NULL(*pflag);
			return (Datum) 0;
		}

		/* call int8_numeric_bi and numeric_div, the avg result can be big integer type */
		args[0] = DirectFunctionCall1(int8_numeric_bi, cell->m_val[idx].val);
		args[1] = DirectFunctionCall1(int8_numeric_bi, cell->m_val[idx+1].val);

		*pvals = numeric_div(&finfo);
		SET_NOTNULL(*pflag);
	}
	else
	{
		ArrayType  *transarray = NULL;
		VecInt8TransTypeData *transdata = NULL;
		if(IS_NULL(cell->m_val[idx].flag))
		{
			SET_NULL(*pflag);
			return (Datum) 0;
		}

		args[0] = cell->m_val[idx].val;
		args[1] = cell->m_val[idx+1].val;
		
		transarray = construct_array(args, 2, INT8OID, sizeof(int64), true, 'd');

		transdata = (VecInt8TransTypeData *) ARR_DATA_PTR(transarray);
		transdata->count = args[1];
		transdata->sum = args[0];
		*pvals = PointerGetDatum(transarray);
		SET_NOTNULL(*pflag);
	}
	
	return (Datum) 0;
}

/*
 * @Description	: avg(int)'s final function, support int4 and int2.
 *
 * @in m_data[idx]	: value of sum(int) for each group.
 * @in m_data[idx + 1]: number of sum(int) for each group.
 * @out pVal		: avg(int)'s result for nrows-th row. 
 */
template<bool singlenode>
Datum
vsint_avg_final(PG_FUNCTION_ARGS)
{
	SonicDatumArray** sdata = (SonicDatumArray**)PG_GETARG_DATUM(0);
	int idx = (int)PG_GETARG_DATUM(1);
	ScalarVector* pVector = (ScalarVector*)PG_GETARG_DATUM(2);
	int dataIdx = (int)PG_GETARG_DATUM(3);
	
	SonicDatumArray* data = sdata[idx];
	SonicDatumArray* count = sdata[idx + 1];
	
	int		nrows = pVector->m_rows;
	uint8*	pflag = &pVector->m_flag[nrows];
	ScalarValue* pvals = &pVector->m_vals[nrows];
	Datum	args[2];
	Datum	*leftdata = NULL;
	Datum	*countdata = NULL;
	uint8	leftflag;
	FunctionCallInfoData finfo;
	int		arrIndx, atomIndx;

	finfo.arg = &args[0];
	nrows = nrows + 1;

	/* the same index are used for data and m_count */
	arrIndx = getArrayIndx(dataIdx, data->m_nbit);
	atomIndx = getArrayLoc(dataIdx, data->m_atomSize - 1);

	/* get sum (leftdata) amd count (countdata) */
	leftdata = &((Datum *)data->m_arr[arrIndx]->data)[atomIndx];
	leftflag = data->getNthNullFlag(arrIndx, atomIndx);
	countdata = &((Datum *)count->m_arr[arrIndx]->data)[atomIndx];

	if (singlenode)
	{
		if (IS_NULL(leftflag))
		{
			SET_NULL(*pflag);
			return (Datum) 0;
		}
		
		/* call int8_numeric_bi and numeric_div, the avg result can be big integer type */
		args[0] = DirectFunctionCall1(int8_numeric_bi, *leftdata);
		args[1] = DirectFunctionCall1(int8_numeric_bi, *countdata);

		*pvals = numeric_div(&finfo);
		SET_NOTNULL(*pflag);
	}
	else
	{
		ArrayType  *transarray = NULL;
		VecInt8TransTypeData *transdata = NULL;
		if (IS_NULL(leftflag))
		{
			SET_NULL(*pflag);
			return (Datum) 0;
		}

		args[0] = *leftdata;
		args[1] = *countdata;
	
		transarray = construct_array(args, 2, INT8OID, sizeof(int64), true, 'd');
		transdata = (VecInt8TransTypeData *) ARR_DATA_PTR(transarray);
		transdata->count = args[1];
		transdata->sum = args[0];
		*pvals = PointerGetDatum(transarray);
		SET_NOTNULL(*pflag);
	}

	return (Datum) 0;
}

/* 
 * vint_avg: For each level of avg, a final operation is needed.
 *
 * isTransition: is the first stage of avg. If so, input is simple type, or array type.
 */
template<int int_size, bool isTransition>
ScalarVector*
vint_avg(PG_FUNCTION_ARGS)
{

	ScalarVector* pVector = (ScalarVector*)PG_GETARG_DATUM(0);
	int			  idx = PG_GETARG_DATUM(1);
	hashCell**	  loc = (hashCell**)PG_GETARG_DATUM(2);
	hashCell*	  cell = NULL;
	int			  i;
	ScalarValue*  pVal = pVector->m_vals;
	uint8*		  flag = pVector->m_flag;
	int			  nrows = pVector->m_rows;
	Datum 		  args[2];
	Datum		  result;
	FunctionCallInfoData finfo;
	ArrayType  *transarray = NULL;
	VecInt8TransTypeData *transdata = NULL;
	
	finfo.arg = &args[0];

	for(i = 0 ; i < nrows; i++)
	{
		cell = loc[i];
		if(cell && IS_NULL(flag[i]) == false) //only do when not null
		{
			if(IS_NULL(cell->m_val[idx].flag))
			{
				if(isTransition)
				{
					if(int_size == 4)
						cell->m_val[idx].val = (int64)DatumGetInt32(pVal[i]);
					else if(int_size == 2)
						cell->m_val[idx].val = (int64)DatumGetInt16(pVal[i]);
					else if(int_size == 1)
						cell->m_val[idx].val = (int64)DatumGetUInt8(pVal[i]);

					cell->m_val[idx + 1].val = 1; //count set 1
				}
				else
				{
					transarray = DatumGetArrayTypeP(pVal[i]);
					transdata = (VecInt8TransTypeData *) ARR_DATA_PTR(transarray);
					cell->m_val[idx].val = transdata->sum;
					cell->m_val[idx + 1].val = transdata->count;
				}

				SET_NOTNULL(cell->m_val[idx].flag);
				SET_NOTNULL(cell->m_val[idx + 1].flag);
				SET_NULL(cell->m_val[idx + 2].flag);
			}
			else
			{
				
				if(isTransition)
				{
					args[0] = cell->m_val[idx].val;
					args[1] = pVal[i];

					if(int_size == 4)
						result = int84pl(&finfo);
					else if(int_size == 2)
						result = int82pl(&finfo);
					else if(int_size == 1)
					{
						args[1] = Int64GetDatum((int64)DatumGetUInt8(pVal[i]));
						result = int8pl(&finfo);
					}
					
					cell->m_val[idx].val = result;
					cell->m_val[idx + 1].val++; //count++
				}
				else
				{
					transarray = DatumGetArrayTypeP(pVal[i]);
					transdata = (VecInt8TransTypeData *) ARR_DATA_PTR(transarray);

					cell->m_val[idx].val = DirectFunctionCall2(int8pl,cell->m_val[idx].val, Int64GetDatum(transdata->sum));
					cell->m_val[idx+1].val += transdata->count;
				}
			}
		}
	}

	return NULL;
}

/*
 * @Description	: avg(int)'s transition function, support int2 and int4.
 *
 * @in m_loc		: location in hash table.
 * @in pVal		: vector to be calculated.   
 * @out m_data[idx]	: value of sum(int) for each group.
 * @out m_data[idx + 1]	: number of sum(int) for each group.
 */
template<int int_size, bool isTransition>
ScalarVector*
vsint_avg(PG_FUNCTION_ARGS)
{
	ScalarVector* pVector = (ScalarVector*)PG_GETARG_DATUM(0);
	int idx = (int)PG_GETARG_DATUM(1);
	uint32*	  loc = (uint32*)PG_GETARG_DATUM(2);
	SonicDatumArray** sdata = (SonicDatumArray**)PG_GETARG_DATUM(3);
	SonicDatumArray* data = sdata[idx];
	SonicDatumArray* count = sdata[idx + 1];
	
	ScalarValue*  pVal = pVector->m_vals;
	uint8*		flag = pVector->m_flag;
	int			nrows = pVector->m_rows;
	int			arrIndx, atomIndx;
	
	Datum		args[2];
	Datum		*leftdata = NULL;
	Datum		*countdata = NULL;
	uint8		leftflag;
	int			i;
	
	ArrayType  *transarray = NULL;
	VecInt8TransTypeData *transdata = NULL;
	FunctionCallInfoData finfo;
	
	finfo.arg = &args[0];

	for (i = 0; i < nrows; i++)
	{
		if (loc[i] != 0 && NOT_NULL(flag[i]))
		{
			arrIndx = getArrayIndx(loc[i], data->m_nbit);
			atomIndx = getArrayLoc(loc[i], data->m_atomSize - 1);

			/* previous sum result(leftdata) */
			leftdata = &((Datum *)data->m_arr[arrIndx]->data)[atomIndx];
			leftflag = data->getNthNullFlag(arrIndx, atomIndx);

			/* previous count result(countdata) */
			countdata = &((Datum *)count->m_arr[arrIndx]->data)[atomIndx];

			if (IS_NULL(leftflag))
			{
				/* store the first data pVal[i] in data and count */
				if (isTransition)
				{
					/* convert to int64 and then convert to uint64 */
					if (int_size == 4)
						*leftdata = (int64)DatumGetInt32(pVal[i]);
					else if (int_size == 2)
						*leftdata = (int64)DatumGetInt16(pVal[i]);
					else if (int_size == 1)
						*leftdata = (int64)DatumGetUInt8(pVal[i]);
					data->setNthNullFlag(arrIndx, atomIndx, false);

					*countdata = 1;
				}
				else
				{
					transarray = DatumGetArrayTypeP(pVal[i]);
					transdata = (VecInt8TransTypeData *) ARR_DATA_PTR(transarray);

					*leftdata = transdata->sum;
					data->setNthNullFlag(arrIndx, atomIndx, false);

					*countdata = transdata->count;
				}
			}
			else
			{
				/* updata previous sum result based on the given pVal[i] */
				if (isTransition)
				{
					args[0] = *leftdata;
					args[1] = pVal[i];

					if (int_size == 4)
						*leftdata  = int84pl(&finfo);
					else if (int_size == 2)
						*leftdata  = int82pl(&finfo);
					else if (int_size == 1)
					{
						args[1] = Int64GetDatum((int64)DatumGetUInt8(pVal[i]));
						*leftdata  = int8pl(&finfo);
					}
					(*countdata)++;
				}
				else
				{
					transarray = DatumGetArrayTypeP(pVal[i]);
					transdata = (VecInt8TransTypeData *)ARR_DATA_PTR(transarray);

					*leftdata = DirectFunctionCall2(int8pl, *leftdata, Int64GetDatum(transdata->sum));
					*countdata += transdata->count;
				}
			}
		}
	}
	return NULL;
}

template<bool isInt32, bool isTransition>
ScalarVector*
vint_sum(PG_FUNCTION_ARGS)
{
	ScalarVector* pVector = (ScalarVector*)PG_GETARG_DATUM(0);
	int			  idx = PG_GETARG_DATUM(1);
	hashCell**	  loc = (hashCell**)PG_GETARG_DATUM(2);
	hashCell*	  cell = NULL;
	int			  i;
	ScalarValue*  pVal = pVector->m_vals;
	uint8*		  flag = pVector->m_flag;
	int			  nrows = pVector->m_rows;
	Datum 		  args[2];
	Datum		  result;
	
	for(i = 0 ; i < nrows; i++)
	{
		cell = loc[i];
		if(cell && IS_NULL(flag[i]) == false) //only do when not null
		{
			if(IS_NULL(cell->m_val[idx].flag))
			{
				if(isTransition)
				{
					if(isInt32)
						cell->m_val[idx].val = (int64)DatumGetInt32(pVal[i]);
					else
						cell->m_val[idx].val = (int64)DatumGetInt16(pVal[i]);
				}
				else
					cell->m_val[idx].val = pVal[i];
				
				SET_NOTNULL(cell->m_val[idx].flag);
			}
			else
			{
				args[0] = cell->m_val[idx].val;
				args[1] = pVal[i];
				if(isTransition)
				{
					if(isInt32)
						result = DirectFunctionCall2(int84pl,args[0],args[1]);
					else
						result = DirectFunctionCall2(int82pl,args[0],args[1]);
				}
				else
					result = DirectFunctionCall2(int8pl,args[0],args[1]);
				
				cell->m_val[idx].val = result;
			}
		}
	}
	return NULL;
}

/*
 * @Description	: sum(int)'s agg function, support int2 and int4.
 *
 * @in m_loc		: location in hash table.
 * @in pVal		: vector to be calculated.   
 * @out m_data[idx]	: value of sum(int) for each group.
 */
template<bool isInt32, bool isTransition>
ScalarVector*
vsint_sum(PG_FUNCTION_ARGS)
{
	ScalarVector* pVector = (ScalarVector*)PG_GETARG_DATUM(0);
	int idx = (int)PG_GETARG_DATUM(1);
	uint32*	  loc = (uint32*)PG_GETARG_DATUM(2);
	SonicDatumArray** sdata = (SonicDatumArray**)PG_GETARG_DATUM(3);
	SonicDatumArray* data = sdata[idx];

	ScalarValue*	pVal = pVector->m_vals;
	uint8*		flag = pVector->m_flag;
	int			nrows = pVector->m_rows;
	Datum		args[2];

	Datum		*leftdata = NULL;
	uint8		leftflag;
	int			i;
	int			arrIndx, atomIndx;

	for(i = 0 ; i < nrows; i++)
	{
		if (loc[i] != 0 && NOT_NULL(flag[i]))
		{
			arrIndx = getArrayIndx(loc[i], data->m_nbit);
			atomIndx = getArrayLoc(loc[i], data->m_atomSize - 1);

			/* get sum (leftdata) */
			leftdata = &((Datum *)data->m_arr[arrIndx]->data)[atomIndx];
			leftflag = data->getNthNullFlag(arrIndx, atomIndx);

			if (IS_NULL(leftflag))
			{
				/* store the first data pVal[i] in data */
				if (isTransition)
				{
					if (isInt32)
						*leftdata = DatumGetInt32(pVal[i]);
					else
						*leftdata = DatumGetInt16(pVal[i]);
				}
				else
					*leftdata = pVal[i];    

				data->setNthNullFlag(arrIndx, atomIndx, false);
			}
			else
			{
				/* updata previous sum result based on the given pVal[i] */
				args[0] = *leftdata;
				args[1] = pVal[i];
				if (isTransition)
				{
					if (isInt32)
						*leftdata = DirectFunctionCall2(int84pl, args[0], args[1]);
					else
						*leftdata = DirectFunctionCall2(int82pl, args[0], args[1]);
				}
				else
					*leftdata = DirectFunctionCall2(int8pl, args[0], args[1]);
			}
		}
	}
	return NULL;
}
	
template <PGFunction timetzFun>
ScalarVector*
vtimetz_min_max(PG_FUNCTION_ARGS)
{
	ScalarVector* pVector = (ScalarVector*)PG_GETARG_DATUM(0);
	int			  idx = PG_GETARG_DATUM(1);
	hashCell**	  loc = (hashCell**)PG_GETARG_DATUM(2);
	MemoryContext context = (MemoryContext)PG_GETARG_DATUM(3);
	hashCell*	  cell = NULL;
	int			  i;
	ScalarValue*  pVal = pVector->m_vals;
	uint8*		  flag = pVector->m_flag;
	int			  nrows = pVector->m_rows;
	Datum 		  args[2];
	Datum		  result;
	FunctionCallInfoData finfo;

	finfo.arg = &args[0];

	for(i = 0 ; i < nrows; i++)
	{
		cell = loc[i];
		if(cell && IS_NULL(flag[i]) == false) //only do when not null
		{
			if(IS_NULL(cell->m_val[idx].flag))
			{
				cell->m_val[idx].val = addVariable(context, pVal[i]);
				SET_NOTNULL(cell->m_val[idx].flag);
			}
			else
			{
				args[0] = PointerGetDatum((char*)ScalarVector::Decode(cell->m_val[idx].val) + VARHDRSZ_SHORT);
				args[1] = PointerGetDatum((char*)ScalarVector::Decode(pVal[i]) + VARHDRSZ_SHORT);
				result = timetzFun(&finfo);
				if(result != args[0])
				{
					cell->m_val[idx].val = replaceVariable(context, cell->m_val[idx].val, pVal[i]);
				}
			}
		}
	}

	return NULL;
}

/* 
 * vinterval_avg: For each level of avg, a final operation is needed.
 *
 * isTransition: is the first stage of avg. If so, input is interval type, or array type.
 */
template<bool isTransition>
ScalarVector*
vinterval_avg(PG_FUNCTION_ARGS)
{
	ScalarVector* pVector = (ScalarVector*)PG_GETARG_DATUM(0);
	int			  idx = PG_GETARG_DATUM(1);
	hashCell**	  loc = (hashCell**)PG_GETARG_DATUM(2);
	MemoryContext context = (MemoryContext)PG_GETARG_DATUM(3);
	hashCell*	  cell = NULL;
	int			  i;
	ScalarValue*  pVal = pVector->m_vals;
	uint8*		  flag = pVector->m_flag;
	int			  nrows = pVector->m_rows;
	Datum 		  args[2];
	Datum		  result;
	FunctionCallInfoData finfo;
	Datum		  sum;
	Datum			*transdatums = NULL;
	int				ndatums;
	Interval		*N = NULL;
	
	finfo.arg = &args[0];

	for(i = 0 ; i < nrows; i++)
	{
		cell = loc[i];
		if(cell && IS_NULL(flag[i]) == false) //only do when not null
		{
			if(IS_NULL(cell->m_val[idx].flag))
			{
				if(isTransition)
				{
					cell->m_val[idx].val = addVariable(context, pVal[i]);
					cell->m_val[idx + 1].val = 1; //count set 1
				}
				else
				{
					deconstruct_array(DatumGetArrayTypeP(pVal[i]),
									  INTERVALOID, sizeof(Interval), false, 'd',
									  &transdatums, NULL, &ndatums);
					
					N = DatumGetIntervalP(transdatums[1]);
					
					cell->m_val[idx].val = addVariable(context, ScalarVector::DatumToScalar(transdatums[0],INTERVALOID,false));

					cell->m_val[idx + 1].val = N->time;
				}

				SET_NOTNULL(cell->m_val[idx].flag);
				SET_NOTNULL(cell->m_val[idx + 1].flag);
				SET_NULL(cell->m_val[idx + 2].flag);
			}
			else
			{
				args[0] = PointerGetDatum((char*)cell->m_val[idx].val + VARHDRSZ_SHORT);
				args[1] = PointerGetDatum((char*)pVal[i] + VARHDRSZ_SHORT);
				
				if(isTransition)
				{
					result = interval_pl(&finfo);
					ScalarValue     val = ScalarVector::DatumToScalar(result,INTERVALOID,false);
					cell->m_val[idx].val = replaceVariable(context, cell->m_val[idx].val, val);
					cell->m_val[idx + 1].val++; //count++
				}
				else
				{
					deconstruct_array(DatumGetArrayTypeP(pVal[i]),
										  INTERVALOID, sizeof(Interval), false, 'd',
										  &transdatums, NULL, &ndatums);
					
					N = DatumGetIntervalP(transdatums[1]);

					sum = DirectFunctionCall2(interval_pl,  transdatums[0], args[0]);
					cell->m_val[idx].val = replaceVariable(context, cell->m_val[idx].val, ScalarVector::DatumToScalar(sum,INTERVALOID,false));

					cell->m_val[idx + 1].val += N->time;
				}
			}
		}
	}
	return NULL;
}

/* 
 * vinterval_avg_final: For each level of avg, a final operation is needed.
 *
 * singlenode: is the last stage of avg. If so, output is interval type, or array type.
 */
template<bool singlenode>
Datum
vinterval_avg_final(PG_FUNCTION_ARGS)
{
	hashCell* cell = (hashCell*)PG_GETARG_DATUM(0);
	int		  idx  = PG_GETARG_DATUM(1);
	ScalarValue*  m_vals = (ScalarValue*)PG_GETARG_DATUM(2);
	uint8  *m_flag = (uint8*)PG_GETARG_DATUM(3);
	
	Datum	  args[2];
	FunctionCallInfoData finfo;
	Datum	   transdatums[2];
	Interval	N;

	finfo.arg = &args[0];
	if(singlenode)
	{
		if(IS_NULL(cell->m_val[idx].flag))
		{
			SET_NULL(*m_flag);
			return (Datum) 0;
		}
		
		args[0] = PointerGetDatum((char*)cell->m_val[idx].val + VARHDRSZ_SHORT);
		args[1] = DirectFunctionCall1(i8tod,cell->m_val[idx+1].val);
		
		*m_vals = ScalarVector::DatumToScalar(interval_div(&finfo),INTERVALOID,false);
		SET_NOTNULL(*m_flag);
	}
	else
	{
		if(IS_NULL(cell->m_val[idx].flag))
		{
			SET_NULL(*m_flag);
			return (Datum) 0;
		}

		args[0] = cell->m_val[idx].val;
		args[1] = cell->m_val[idx+1].val;
		
		N.time = args[1];
		
		transdatums[0] = PointerGetDatum((char*)args[0] + VARHDRSZ_SHORT);
		transdatums[1] = IntervalPGetDatum(&N);

		*m_vals = PointerGetDatum(construct_array(transdatums, 2, INTERVALOID, sizeof(Interval), false, 'd'));
		SET_NOTNULL(*m_flag);
	}
	
	return (Datum) 0;
}

template <PGFunction ctidFun>
ScalarVector*
vctid_sop(PG_FUNCTION_ARGS)
{
	ScalarValue* parg1 = PG_GETARG_VECVAL(0);
	ScalarValue* parg2 = PG_GETARG_VECVAL(1);
	int32		 nvalues = PG_GETARG_INT32(2);
	ScalarValue* presult = PG_GETARG_VECVAL(3);
	uint8*	pflag = (uint8*)(PG_GETARG_VECTOR(3)->m_flag);
	bool*		pselection = PG_GETARG_SELECTION(4);
	uint8*		pflags1 = (uint8*)(PG_GETARG_VECTOR(0)->m_flag);
	uint8*		pflags2 = (uint8*)(PG_GETARG_VECTOR(1)->m_flag);
	Oid     typeId1 = PG_GETARG_VECTOR(0)->m_desc.typeId;
	Oid     typeId2 = PG_GETARG_VECTOR(1)->m_desc.typeId;
	int          i;
	Datum 		  args[2];
	FunctionCallInfoData finfo;

	finfo.arg = &args[0];

	if(likely(pselection == NULL))
	{
		for (i = 0; i < nvalues; i++)
		{
			if (BOTH_NOT_NULL(pflags1[i], pflags2[i]))
			{
				args[0] = typeId1 == TIDOID?parg1[i]:PointerGetDatum(parg1+i);
				args[1] = typeId2 == TIDOID?parg2[i]:PointerGetDatum(parg2+i);

				presult[i] = ctidFun(&finfo);
				SET_NOTNULL(pflag[i]);
			}
			else
				SET_NULL(pflag[i]);
		}
	}
	else
	{
		for (i = 0; i < nvalues; i++)
		{
			if(pselection[i])
			{
				if (BOTH_NOT_NULL(pflags1[i], pflags2[i]))
				{
					args[0] = typeId1 == TIDOID?parg1[i]:PointerGetDatum(parg1+i);
					args[1] = typeId2 == TIDOID?parg2[i]:PointerGetDatum(parg2+i);

					presult[i] = ctidFun(&finfo);
					SET_NOTNULL(pflag[i]);
				}
			else
				SET_NULL(pflag[i]);
			}
		}
	}

	PG_GETARG_VECTOR(3)->m_rows = nvalues;
	PG_GETARG_VECTOR(3)->m_desc.typeId = BOOLOID;
	return PG_GETARG_VECTOR(3);
}

#endif