예제 #1
0
/**
* A modified version of PostgreSQL's DirectFunctionCall1 which allows NULL results; this
* is required for aggregates that return NULL.
*/
Datum
PGISDirectFunctionCall1(PGFunction func, Datum arg1)
{
	FunctionCallInfoData fcinfo;
	Datum           result;

#if POSTGIS_PGSQL_VERSION > 90

	InitFunctionCallInfoData(fcinfo, NULL, 1, InvalidOid, NULL, NULL);
#else

	InitFunctionCallInfoData(fcinfo, NULL, 1, NULL, NULL);
#endif

	fcinfo.arg[0] = arg1;
	fcinfo.argnull[0] = false;

	result = (*func) (&fcinfo);

	/* Check for null result, returning a "NULL" Datum if indicated */
	if (fcinfo.isnull)
		return (Datum) 0;

	return result;
}
예제 #2
0
/*
 *		int2vectorrecv			- converts external binary format to int2vector
 */
Datum
int2vectorrecv(PG_FUNCTION_ARGS)
{
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
	FunctionCallInfoData locfcinfo;
	int2vector *result;

	/*
	 * Normally one would call array_recv() using DirectFunctionCall3, but
	 * that does not work since array_recv wants to cache some data using
	 * fcinfo->flinfo->fn_extra.  So we need to pass it our own flinfo
	 * parameter.
	 */
	InitFunctionCallInfoData(locfcinfo, fcinfo->flinfo, 3, NULL, NULL);

	locfcinfo.arg[0] = PointerGetDatum(buf);
	locfcinfo.arg[1] = ObjectIdGetDatum(INT2OID);
	locfcinfo.arg[2] = Int32GetDatum(-1);
	locfcinfo.argnull[0] = false;
	locfcinfo.argnull[1] = false;
	locfcinfo.argnull[2] = false;

	result = (int2vector *) DatumGetPointer(array_recv(&locfcinfo));

	Assert(!locfcinfo.isnull);

	/* sanity checks: int2vector must be 1-D, no nulls */
	if (ARR_NDIM(result) != 1 ||
		ARR_HASNULL(result) ||
		ARR_ELEMTYPE(result) != INT2OID)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
				 errmsg("invalid int2vector data")));
	PG_RETURN_POINTER(result);
}
예제 #3
0
파일: plvsubst.c 프로젝트: 50wu/gpdb
Datum
plvsubst_string_string(PG_FUNCTION_ARGS)
{
	Datum		r;
	ArrayType  *array;
	FunctionCallInfoData locfcinfo;

	init_c_subst();

	if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
		PG_RETURN_NULL();

	/*
	 * I can't use DirectFunctionCall2
	 */

	InitFunctionCallInfoData(locfcinfo, fcinfo->flinfo, 2, NULL, NULL);
	locfcinfo.arg[0] = PG_GETARG_DATUM(1);
	locfcinfo.arg[1] = PG_GETARG_IF_EXISTS(2, DATUM, CStringGetTextDatum(","));
	locfcinfo.argnull[0] = false;
	locfcinfo.argnull[1] = false;
	r = text_to_array(&locfcinfo);

	if (locfcinfo.isnull || r == (Datum) 0)
		array = NULL;
	else
		array = DatumGetArrayTypeP(r);

	PG_RETURN_TEXT_P(plvsubst_string(PG_GETARG_TEXT_P(0),
					 array,
					 PG_GETARG_IF_EXISTS(3, TEXT_P, c_subst),
					 fcinfo));
}
예제 #4
0
hdfsFS
HdfsConnect(FsysName protocol, char * host, uint16_t port, char *ccname, void *token)
{
	FunctionCallInfoData fcinfo;
	FileSystemUdfData fsysUdf;
	FmgrInfo *fsysFunc = FsysInterfaceGetFunc(protocol, FSYS_FUNC_CONNECT);

#ifdef USE_ASSERT_CHECKING
    if (testmode_fault(gp_fsys_fault_inject_percent))
        return NULL;
#endif

	fsysUdf.type = T_FileSystemFunctionData;
	fsysUdf.fsys_host = host;
	fsysUdf.fsys_port = port;
	fsysUdf.fsys_hdfs = NULL;
	fsysUdf.fsys_ccname = ccname;
	fsysUdf.fsys_token = token;

	InitFunctionCallInfoData(/* FunctionCallInfoData */ fcinfo,
							 /* FmgrInfo */ fsysFunc,
							 /* nArgs */ 0, 
							 /* Call Context */ (Node *) (&fsysUdf),
							 /* ResultSetInfo */ NULL);

	FunctionCallInvoke(&fcinfo);

	return FSYS_UDF_GET_HDFS(&fcinfo);
}
예제 #5
0
hdfsFile HdfsOpenFile(FsysName protocol, hdfsFS fileSystem, char * path, int flags,
					  int bufferSize, short replication, int64_t blocksize)
{
	FunctionCallInfoData fcinfo;
	FileSystemUdfData fsysUdf;
	FmgrInfo *fsysFunc = FsysInterfaceGetFunc(protocol, FSYS_FUNC_OPEN);

#ifdef USE_ASSERT_CHECKING
    if (testmode_fault(gp_fsys_fault_inject_percent))
        return NULL;
#endif

	fsysUdf.type = T_FileSystemFunctionData;
	fsysUdf.fsys_hdfs = fileSystem;
	fsysUdf.fsys_filepath = path;
	fsysUdf.fsys_fileflags = flags;
	fsysUdf.fsys_filebufsize = bufferSize;
	fsysUdf.fsys_replication = replication;
	fsysUdf.fsys_fileblksize = blocksize;
	fsysUdf.fsys_hfile = NULL;

	InitFunctionCallInfoData(/* FunctionCallInfoData */ fcinfo,
							 /* FmgrInfo */ fsysFunc,
							 /* nArgs */ 0, 
							 /* Call Context */ (Node *) (&fsysUdf),
							 /* ResultSetInfo */ NULL);

	FunctionCallInvoke(&fcinfo);

	return FSYS_UDF_GET_HFILE(&fcinfo);
}
예제 #6
0
int HdfsTruncate(FsysName protocol, hdfsFS fileSystem, char * path, int64_t size)
{
	FunctionCallInfoData fcinfo;
	FileSystemUdfData fsysUdf;
	FmgrInfo *fsysFunc = FsysInterfaceGetFunc(protocol, FSYS_FUNC_TRUNCATE);

#ifdef USE_ASSERT_CHECKING
    if (testmode_fault(gp_fsys_fault_inject_percent))
        return -1;
#endif

	fsysUdf.type = T_FileSystemFunctionData;
	fsysUdf.fsys_hdfs = fileSystem;
	fsysUdf.fsys_filepath = path;
	fsysUdf.fsys_pos = size;

	InitFunctionCallInfoData(/* FunctionCallInfoData */ fcinfo,
							 /* FmgrInfo */ fsysFunc,
							 /* nArgs */ 0, 
							 /* Call Context */ (Node *) (&fsysUdf),
							 /* ResultSetInfo */ NULL);

	Datum d = FunctionCallInvoke(&fcinfo);

	return DatumGetInt32(d);
}
예제 #7
0
int
HdfsWrite(FsysName protocol, hdfsFS fileSystem, hdfsFile file, const void * buffer, int length)
{
	FunctionCallInfoData fcinfo;
	FileSystemUdfData fsysUdf;
	FmgrInfo *fsysFunc = FsysInterfaceGetFunc(protocol, FSYS_FUNC_WRITE);

#ifdef USE_ASSERT_CHECKING
    if (testmode_fault(gp_fsys_fault_inject_percent))
        return -1;
#endif

	fsysUdf.type = T_FileSystemFunctionData;
	fsysUdf.fsys_hdfs = fileSystem;
	fsysUdf.fsys_hfile = file;
    fsysUdf.fsys_databuf = (char *) buffer;
	fsysUdf.fsys_maxbytes = length;

	InitFunctionCallInfoData(/* FunctionCallInfoData */ fcinfo,
							 /* FmgrInfo */ fsysFunc,
							 /* nArgs */ 0, 
							 /* Call Context */ (Node *) (&fsysUdf),
							 /* ResultSetInfo */ NULL);

	Datum d = FunctionCallInvoke(&fcinfo);

	return DatumGetInt32(d);
}
예제 #8
0
int
HdfsSeek(FsysName protocol, hdfsFS fileSystem, hdfsFile file, int64_t desiredPos)
{
	FunctionCallInfoData fcinfo;
	FileSystemUdfData fsysUdf;
	FmgrInfo *fsysFunc = FsysInterfaceGetFunc(protocol, FSYS_FUNC_SEEK);

#ifdef USE_ASSERT_CHECKING
    if (testmode_fault(gp_fsys_fault_inject_percent))
        return -1;
#endif

	fsysUdf.type = T_FileSystemFunctionData;
	fsysUdf.fsys_hdfs = fileSystem;
	fsysUdf.fsys_hfile = file;
	fsysUdf.fsys_pos = desiredPos;

	InitFunctionCallInfoData(/* FunctionCallInfoData */ fcinfo,
							 /* FmgrInfo */ fsysFunc,
							 /* nArgs */ 0, 
							 /* Call Context */ (Node *) (&fsysUdf),
							 /* ResultSetInfo */ NULL);

	Datum d = FunctionCallInvoke(&fcinfo);

	return DatumGetInt32(d);
}
예제 #9
0
파일: pllua_pgfunc.c 프로젝트: eugwne/pllua
static int
pg_callable_func(lua_State *L)
{
	MemoryContext m;
	int i;
	FunctionCallInfoData fcinfo;
	Lua_pgfunc *fi;

	fi = (Lua_pgfunc *) lua_touserdata(L, lua_upvalueindex(1));

	InitFunctionCallInfoData(fcinfo, &fi->fi, fi->numargs, InvalidOid, NULL, NULL);

	if(tmpcontext_usage> RESET_CONTEXT_AFTER ){
		MemoryContextReset(tmpcontext);
		tmpcontext_usage = 0;
	}
	++tmpcontext_usage;

	m = MemoryContextSwitchTo(tmpcontext);

	for (i=0; i<fi->numargs; ++i){
		fcinfo.arg[i] = luaP_todatum(L, fi->argtypes[i], 0, &fcinfo.argnull[i], i+1);
	}

	if(!fi->options.only_internal && fi->options.throwable){
		SPI_push();
		PG_TRY();
		{
			Datum d = FunctionCallInvoke(&fcinfo);
			MemoryContextSwitchTo(m);
			if (fcinfo.isnull) {
				lua_pushnil(L);
			} else {
				luaP_pushdatum(L, d, fi->prorettype);
			}
			SPI_pop();
		}
		PG_CATCH();
		{
			lua_pop(L, lua_gettop(L));
			push_spi_error(L, m); /*context switch to m inside push_spi_error*/
			SPI_pop();
			return lua_error(L);
		}PG_END_TRY();
	}else{
		Datum d = FunctionCallInvoke(&fcinfo);
		MemoryContextSwitchTo(m);
		if (fcinfo.isnull) {
			lua_pushnil(L);
		} else {
			luaP_pushdatum(L, d, fi->prorettype);
		}
	}

	return 1;
}
예제 #10
0
파일: pllua_pgfunc.c 프로젝트: eugwne/pllua
static int
pgfunc_rows (lua_State *L) {
	int i;

	Lua_pgfunc *fi;

	ReturnSetInfo *rsinfo;
	ExprContext *econtext;
	FunctionCallInfoData *fcinfo;
	Lua_pgfunc_srf *srfi;
	int argc;

	BEGINLUA;

	argc = lua_gettop(L);
	fi = (Lua_pgfunc *) lua_touserdata(L, lua_upvalueindex(1));

	srfi = (Lua_pgfunc_srf *)lua_newuserdata(L, sizeof(Lua_pgfunc_srf));

	econtext = &srfi->econtext;
	rsinfo = &srfi->rsinfo;
	fcinfo = &srfi->fcinfo;
	srfi->prorettype = fi->prorettype;

	fmgr_info(fi->funcid, &srfi->fi);

	memset(econtext, 0, sizeof(ExprContext));
	econtext->ecxt_per_query_memory = CurrentMemoryContext;

	rsinfo->type = T_ReturnSetInfo;
	rsinfo->econtext = econtext;
	rsinfo->allowedModes = (int)(SFRM_ValuePerCall /*| SFRM_Materialize*/);
	rsinfo->returnMode = SFRM_ValuePerCall;//SFRM_Materialize;
	rsinfo->setResult = NULL;
	rsinfo->setDesc = NULL;

	InitFunctionCallInfoData((*fcinfo), &srfi->fi, fi->numargs, InvalidOid, NULL, (fmNodePtr)rsinfo);

	for (i=0; i<fi->numargs; ++i){
		if(i>=argc){
			for (i = argc; i<fi->numargs; ++i){
				fcinfo->arg[i] = 0 ;//Datum;
				fcinfo->argnull[i] = true;
			}
			break;
		}
		fcinfo->arg[i] = luaP_todatum(L, fi->argtypes[i], 0, &fcinfo->argnull[i], i+1);
	}

	lua_pushcclosure(L, pgfunc_rowsaux, 1);
	ENDLUAV(1);
	return 1;

}
예제 #11
0
static Jsonb *
jnumber_op(PGFunction f, Jsonb *l, Jsonb *r)
{
	FunctionCallInfoData fcinfo;
	JsonbValue *jv;
	Datum		n;

	AssertArg(r != NULL);

	if (!((l == NULL || JB_ROOT_IS_SCALAR(l)) && JB_ROOT_IS_SCALAR(r)))
		ereport_op(f, l, r);

	InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);

	if (l != NULL)
	{
		jv = getIthJsonbValueFromContainer(&l->root, 0);
		if (jv->type != jbvNumeric)
			ereport_op(f, l, r);

		fcinfo.arg[fcinfo.nargs] = NumericGetDatum(jv->val.numeric);
		fcinfo.argnull[fcinfo.nargs] = false;
		fcinfo.nargs++;
	}

	jv = getIthJsonbValueFromContainer(&r->root, 0);
	if (jv->type != jbvNumeric)
		ereport_op(f, l, r);

	fcinfo.arg[fcinfo.nargs] = NumericGetDatum(jv->val.numeric);
	fcinfo.argnull[fcinfo.nargs] = false;
	fcinfo.nargs++;

	n = (*f) (&fcinfo);
	if (fcinfo.isnull)
		elog(ERROR, "function %p returned NULL", (void *) f);

	if (f == numeric_power || f == numeric_div)
	{
		int			s;

		s = DatumGetInt32(DirectFunctionCall1(numeric_scale, fcinfo.arg[0])) +
			DatumGetInt32(DirectFunctionCall1(numeric_scale, fcinfo.arg[1]));
		if (s == 0)
			n = DirectFunctionCall2(numeric_trunc, n, 0);
	}

	return numeric_to_jnumber(DatumGetNumeric(n));
}
예제 #12
0
파일: int.c 프로젝트: eubide/postgres
/*
 *		int2vectorrecv			- converts external binary format to int2vector
 */
Datum
int2vectorrecv(PG_FUNCTION_ARGS)
{
	LOCAL_FCINFO(locfcinfo, 3);
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
	int2vector *result;

	/*
	 * Normally one would call array_recv() using DirectFunctionCall3, but
	 * that does not work since array_recv wants to cache some data using
	 * fcinfo->flinfo->fn_extra.  So we need to pass it our own flinfo
	 * parameter.
	 */
	InitFunctionCallInfoData(*locfcinfo, fcinfo->flinfo, 3,
							 InvalidOid, NULL, NULL);

	locfcinfo->args[0].value = PointerGetDatum(buf);
	locfcinfo->args[0].isnull = false;
	locfcinfo->args[1].value = ObjectIdGetDatum(INT2OID);
	locfcinfo->args[1].isnull = false;
	locfcinfo->args[2].value = Int32GetDatum(-1);
	locfcinfo->args[2].isnull = false;

	result = (int2vector *) DatumGetPointer(array_recv(locfcinfo));

	Assert(!locfcinfo->isnull);

	/* sanity checks: int2vector must be 1-D, 0-based, no nulls */
	if (ARR_NDIM(result) != 1 ||
		ARR_HASNULL(result) ||
		ARR_ELEMTYPE(result) != INT2OID ||
		ARR_LBOUND(result)[0] != 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
				 errmsg("invalid int2vector data")));

	/* check length for consistency with int2vectorin() */
	if (ARR_DIMS(result)[0] > FUNC_MAX_ARGS)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("oidvector has too many elements")));

	PG_RETURN_POINTER(result);
}
예제 #13
0
int HdfsFreeFileInfo(FsysName protocol, hdfsFileInfo * info, int numEntries)
{
	FunctionCallInfoData fcinfo;
	FileSystemUdfData fsysUdf;
	FmgrInfo *fsysFunc = FsysInterfaceGetFunc(protocol, FSYS_FUNC_FREEFILEINFO);

	fsysUdf.type = T_FileSystemFunctionData;
	fsysUdf.fsys_fileinfo = info;
	fsysUdf.fsys_fileinfonum = numEntries;

	InitFunctionCallInfoData(/* FunctionCallInfoData */ fcinfo,
							 /* FmgrInfo */ fsysFunc,
							 /* nArgs */ 0, 
							 /* Call Context */ (Node *) (&fsysUdf),
							 /* ResultSetInfo */ NULL);

	Datum d = FunctionCallInvoke(&fcinfo);

	return DatumGetInt32(d);
}
예제 #14
0
/*
 * Set up a shim function to allow use of an old-style btree comparison
 * function as if it were a sort support comparator.
 */
void
PrepareSortSupportComparisonShim(Oid cmpFunc, SortSupport ssup)
{
	SortShimExtra *extra;

	extra = (SortShimExtra *) MemoryContextAlloc(ssup->ssup_cxt,
												 sizeof(SortShimExtra));

	/* Lookup the comparison function */
	fmgr_info_cxt(cmpFunc, &extra->flinfo, ssup->ssup_cxt);

	/* We can initialize the callinfo just once and re-use it */
	InitFunctionCallInfoData(extra->fcinfo, &extra->flinfo, 2,
							 ssup->ssup_collation, NULL, NULL);
	extra->fcinfo.argnull[0] = false;
	extra->fcinfo.argnull[1] = false;

	ssup->ssup_extra = extra;
	ssup->comparator = comparison_shim;
}
예제 #15
0
hdfsFileInfo * HdfsGetPathInfo(FsysName protocol, hdfsFS fileSystem, char * path)
{
	FunctionCallInfoData fcinfo;
	FileSystemUdfData fsysUdf;
	FmgrInfo *fsysFunc = FsysInterfaceGetFunc(protocol, FSYS_FUNC_GETPATHINFO);

	fsysUdf.type = T_FileSystemFunctionData;
	fsysUdf.fsys_hdfs = fileSystem;
	fsysUdf.fsys_filepath = path;
	fsysUdf.fsys_fileinfo = NULL;

	InitFunctionCallInfoData(/* FunctionCallInfoData */ fcinfo,
							 /* FmgrInfo */ fsysFunc,
							 /* nArgs */ 0, 
							 /* Call Context */ (Node *) (&fsysUdf),
							 /* ResultSetInfo */ NULL);

	(void) FunctionCallInvoke(&fcinfo);

	return FSYS_UDF_GET_FILEINFO(&fcinfo);
}
예제 #16
0
파일: pipe.c 프로젝트: orafce/orafce
Datum
dbms_pipe_pack_message_record(PG_FUNCTION_ARGS)
{
	HeapTupleHeader rec = PG_GETARG_HEAPTUPLEHEADER(0);
	Oid tupType;
	bytea *data;

#if PG_VERSION_NUM >= 120000

	LOCAL_FCINFO(info, 3);

#else

	FunctionCallInfoData info_data;
	FunctionCallInfo info = &info_data;

#endif


	tupType = HeapTupleHeaderGetTypeId(rec);

	/*
	 * Normally one would call record_send() using DirectFunctionCall3,
	 * but that does not work since record_send wants to cache some data
	 * using fcinfo->flinfo->fn_extra.  So we need to pass it our own
	 * flinfo parameter.
	 */
	InitFunctionCallInfoData(*info, fcinfo->flinfo, 3, InvalidOid, NULL, NULL);
	init_args_3(info, PointerGetDatum(rec), ObjectIdGetDatum(tupType), Int32GetDatum(-1));

	data = (bytea*) DatumGetPointer(record_send(info));

	output_buffer = check_buffer(output_buffer, LOCALMSGSZ);
	pack_field(output_buffer, IT_RECORD,
			   VARSIZE(data), VARDATA(data), tupType);

	PG_RETURN_VOID();
}
예제 #17
0
파일: kv.c 프로젝트: bhaprayan/pipelinedb
/*
 * compare_keys
 */
static int
compare_keys(KeyedAggState *state, KeyValue *kv, Datum incoming, bool incoming_null, Oid collation, bool *result_null)
{
	TypeCacheEntry *type = state->key_type;
	FunctionCallInfoData cmp_fcinfo;
	int result;

	if (incoming_null || KV_KEY_IS_NULL(kv))
	{
		*result_null = true;
		return 0;
	}

	InitFunctionCallInfoData(cmp_fcinfo, &type->cmp_proc_finfo, 2, collation, NULL, NULL);
	cmp_fcinfo.arg[0] = kv->key;
	cmp_fcinfo.argnull[0] = KV_KEY_IS_NULL(kv);
	cmp_fcinfo.arg[1] = incoming;
	cmp_fcinfo.argnull[1] = incoming_null;

	result = DatumGetInt32(FunctionCallInvoke(&cmp_fcinfo));
	*result_null = cmp_fcinfo.isnull;

	return result;
}
예제 #18
0
/*
 * record_cmp()
 * Internal comparison function for records.
 *
 * Returns -1, 0 or 1
 *
 * Do not assume that the two inputs are exactly the same record type;
 * for instance we might be comparing an anonymous ROW() construct against a
 * named composite type.  We will compare as long as they have the same number
 * of non-dropped columns of the same types.
 */
static int
record_cmp(FunctionCallInfo fcinfo)
{
	HeapTupleHeader record1 = PG_GETARG_HEAPTUPLEHEADER(0);
	HeapTupleHeader record2 = PG_GETARG_HEAPTUPLEHEADER(1);
	int			result = 0;
	Oid			tupType1;
	Oid			tupType2;
	int32		tupTypmod1;
	int32		tupTypmod2;
	TupleDesc	tupdesc1;
	TupleDesc	tupdesc2;
	HeapTupleData tuple1;
	HeapTupleData tuple2;
	int			ncolumns1;
	int			ncolumns2;
	RecordCompareData *my_extra;
	int			ncols;
	Datum	   *values1;
	Datum	   *values2;
	bool	   *nulls1;
	bool	   *nulls2;
	int			i1;
	int			i2;
	int			j;

	/* Extract type info from the tuples */
	tupType1 = HeapTupleHeaderGetTypeId(record1);
	tupTypmod1 = HeapTupleHeaderGetTypMod(record1);
	tupdesc1 = lookup_rowtype_tupdesc(tupType1, tupTypmod1);
	ncolumns1 = tupdesc1->natts;
	tupType2 = HeapTupleHeaderGetTypeId(record2);
	tupTypmod2 = HeapTupleHeaderGetTypMod(record2);
	tupdesc2 = lookup_rowtype_tupdesc(tupType2, tupTypmod2);
	ncolumns2 = tupdesc2->natts;

	/* Build temporary HeapTuple control structures */
	tuple1.t_len = HeapTupleHeaderGetDatumLength(record1);
	ItemPointerSetInvalid(&(tuple1.t_self));
	tuple1.t_tableOid = InvalidOid;
	tuple1.t_data = record1;
	tuple2.t_len = HeapTupleHeaderGetDatumLength(record2);
	ItemPointerSetInvalid(&(tuple2.t_self));
	tuple2.t_tableOid = InvalidOid;
	tuple2.t_data = record2;

	/*
	 * We arrange to look up the needed comparison info just once per series
	 * of calls, assuming the record types don't change underneath us.
	 */
	ncols = Max(ncolumns1, ncolumns2);
	my_extra = (RecordCompareData *) fcinfo->flinfo->fn_extra;
	if (my_extra == NULL ||
		my_extra->ncolumns < ncols)
	{
		fcinfo->flinfo->fn_extra =
			MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
						sizeof(RecordCompareData) - sizeof(ColumnCompareData)
							   + ncols * sizeof(ColumnCompareData));
		my_extra = (RecordCompareData *) fcinfo->flinfo->fn_extra;
		my_extra->ncolumns = ncols;
		my_extra->record1_type = InvalidOid;
		my_extra->record1_typmod = 0;
		my_extra->record2_type = InvalidOid;
		my_extra->record2_typmod = 0;
	}

	if (my_extra->record1_type != tupType1 ||
		my_extra->record1_typmod != tupTypmod1 ||
		my_extra->record2_type != tupType2 ||
		my_extra->record2_typmod != tupTypmod2)
	{
		MemSet(my_extra->columns, 0, ncols * sizeof(ColumnCompareData));
		my_extra->record1_type = tupType1;
		my_extra->record1_typmod = tupTypmod1;
		my_extra->record2_type = tupType2;
		my_extra->record2_typmod = tupTypmod2;
	}

	/* Break down the tuples into fields */
	values1 = (Datum *) palloc(ncolumns1 * sizeof(Datum));
	nulls1 = (bool *) palloc(ncolumns1 * sizeof(bool));
	heap_deform_tuple(&tuple1, tupdesc1, values1, nulls1);
	values2 = (Datum *) palloc(ncolumns2 * sizeof(Datum));
	nulls2 = (bool *) palloc(ncolumns2 * sizeof(bool));
	heap_deform_tuple(&tuple2, tupdesc2, values2, nulls2);

	/*
	 * Scan corresponding columns, allowing for dropped columns in different
	 * places in the two rows.	i1 and i2 are physical column indexes, j is
	 * the logical column index.
	 */
	i1 = i2 = j = 0;
	while (i1 < ncolumns1 || i2 < ncolumns2)
	{
		TypeCacheEntry *typentry;
		Oid			collation;
		FunctionCallInfoData locfcinfo;
		int32		cmpresult;

		/*
		 * Skip dropped columns
		 */
		if (i1 < ncolumns1 && tupdesc1->attrs[i1]->attisdropped)
		{
			i1++;
			continue;
		}
		if (i2 < ncolumns2 && tupdesc2->attrs[i2]->attisdropped)
		{
			i2++;
			continue;
		}
		if (i1 >= ncolumns1 || i2 >= ncolumns2)
			break;				/* we'll deal with mismatch below loop */

		/*
		 * Have two matching columns, they must be same type
		 */
		if (tupdesc1->attrs[i1]->atttypid !=
			tupdesc2->attrs[i2]->atttypid)
			ereport(ERROR,
					(errcode(ERRCODE_DATATYPE_MISMATCH),
					 errmsg("cannot compare dissimilar column types %s and %s at record column %d",
							format_type_be(tupdesc1->attrs[i1]->atttypid),
							format_type_be(tupdesc2->attrs[i2]->atttypid),
							j + 1)));

		/*
		 * If they're not same collation, we don't complain here, but the
		 * comparison function might.
		 */
		collation = tupdesc1->attrs[i1]->attcollation;
		if (collation != tupdesc2->attrs[i2]->attcollation)
			collation = InvalidOid;

		/*
		 * Lookup the comparison function if not done already
		 */
		typentry = my_extra->columns[j].typentry;
		if (typentry == NULL ||
			typentry->type_id != tupdesc1->attrs[i1]->atttypid)
		{
			typentry = lookup_type_cache(tupdesc1->attrs[i1]->atttypid,
										 TYPECACHE_CMP_PROC_FINFO);
			if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
				ereport(ERROR,
						(errcode(ERRCODE_UNDEFINED_FUNCTION),
				errmsg("could not identify a comparison function for type %s",
					   format_type_be(typentry->type_id))));
			my_extra->columns[j].typentry = typentry;
		}

		/*
		 * We consider two NULLs equal; NULL > not-NULL.
		 */
		if (!nulls1[i1] || !nulls2[i2])
		{
			if (nulls1[i1])
			{
				/* arg1 is greater than arg2 */
				result = 1;
				break;
			}
			if (nulls2[i2])
			{
				/* arg1 is less than arg2 */
				result = -1;
				break;
			}

			/* Compare the pair of elements */
			InitFunctionCallInfoData(locfcinfo, &typentry->cmp_proc_finfo, 2,
									 collation, NULL, NULL);
			locfcinfo.arg[0] = values1[i1];
			locfcinfo.arg[1] = values2[i2];
			locfcinfo.argnull[0] = false;
			locfcinfo.argnull[1] = false;
			locfcinfo.isnull = false;
			cmpresult = DatumGetInt32(FunctionCallInvoke(&locfcinfo));

			if (cmpresult < 0)
			{
				/* arg1 is less than arg2 */
				result = -1;
				break;
			}
			else if (cmpresult > 0)
			{
				/* arg1 is greater than arg2 */
				result = 1;
				break;
			}
		}

		/* equal, so continue to next column */
		i1++, i2++, j++;
	}

	/*
	 * If we didn't break out of the loop early, check for column count
	 * mismatch.  (We do not report such mismatch if we found unequal column
	 * values; is that a feature or a bug?)
	 */
	if (result == 0)
	{
		if (i1 != ncolumns1 || i2 != ncolumns2)
			ereport(ERROR,
					(errcode(ERRCODE_DATATYPE_MISMATCH),
					 errmsg("cannot compare record types with different numbers of columns")));
	}

	pfree(values1);
	pfree(nulls1);
	pfree(values2);
	pfree(nulls2);
	ReleaseTupleDesc(tupdesc1);
	ReleaseTupleDesc(tupdesc2);

	/* Avoid leaking memory when handed toasted input. */
	PG_FREE_IF_COPY(record1, 0);
	PG_FREE_IF_COPY(record2, 1);

	return result;
}
예제 #19
0
파일: execSRF.c 프로젝트: Brar/postgres
/*
 *		ExecMakeTableFunctionResult
 *
 * Evaluate a table function, producing a materialized result in a Tuplestore
 * object.
 *
 * This is used by nodeFunctionscan.c.
 */
Tuplestorestate *
ExecMakeTableFunctionResult(SetExprState *setexpr,
							ExprContext *econtext,
							MemoryContext argContext,
							TupleDesc expectedDesc,
							bool randomAccess)
{
	Tuplestorestate *tupstore = NULL;
	TupleDesc	tupdesc = NULL;
	Oid			funcrettype;
	bool		returnsTuple;
	bool		returnsSet = false;
	FunctionCallInfoData fcinfo;
	PgStat_FunctionCallUsage fcusage;
	ReturnSetInfo rsinfo;
	HeapTupleData tmptup;
	MemoryContext callerContext;
	MemoryContext oldcontext;
	bool		first_time = true;

	callerContext = CurrentMemoryContext;

	funcrettype = exprType((Node *) setexpr->expr);

	returnsTuple = type_is_rowtype(funcrettype);

	/*
	 * Prepare a resultinfo node for communication.  We always do this even if
	 * not expecting a set result, so that we can pass expectedDesc.  In the
	 * generic-expression case, the expression doesn't actually get to see the
	 * resultinfo, but set it up anyway because we use some of the fields as
	 * our own state variables.
	 */
	rsinfo.type = T_ReturnSetInfo;
	rsinfo.econtext = econtext;
	rsinfo.expectedDesc = expectedDesc;
	rsinfo.allowedModes = (int) (SFRM_ValuePerCall | SFRM_Materialize | SFRM_Materialize_Preferred);
	if (randomAccess)
		rsinfo.allowedModes |= (int) SFRM_Materialize_Random;
	rsinfo.returnMode = SFRM_ValuePerCall;
	/* isDone is filled below */
	rsinfo.setResult = NULL;
	rsinfo.setDesc = NULL;

	/*
	 * Normally the passed expression tree will be a SetExprState, since the
	 * grammar only allows a function call at the top level of a table
	 * function reference.  However, if the function doesn't return set then
	 * the planner might have replaced the function call via constant-folding
	 * or inlining.  So if we see any other kind of expression node, execute
	 * it via the general ExecEvalExpr() code; the only difference is that we
	 * don't get a chance to pass a special ReturnSetInfo to any functions
	 * buried in the expression.
	 */
	if (!setexpr->elidedFuncState)
	{
		/*
		 * This path is similar to ExecMakeFunctionResultSet.
		 */
		returnsSet = setexpr->funcReturnsSet;
		InitFunctionCallInfoData(fcinfo, &(setexpr->func),
								 list_length(setexpr->args),
								 setexpr->fcinfo_data.fncollation,
								 NULL, (Node *) &rsinfo);

		/*
		 * Evaluate the function's argument list.
		 *
		 * We can't do this in the per-tuple context: the argument values
		 * would disappear when we reset that context in the inner loop.  And
		 * the caller's CurrentMemoryContext is typically a query-lifespan
		 * context, so we don't want to leak memory there.  We require the
		 * caller to pass a separate memory context that can be used for this,
		 * and can be reset each time through to avoid bloat.
		 */
		MemoryContextReset(argContext);
		oldcontext = MemoryContextSwitchTo(argContext);
		ExecEvalFuncArgs(&fcinfo, setexpr->args, econtext);
		MemoryContextSwitchTo(oldcontext);

		/*
		 * If function is strict, and there are any NULL arguments, skip
		 * calling the function and act like it returned NULL (or an empty
		 * set, in the returns-set case).
		 */
		if (setexpr->func.fn_strict)
		{
			int			i;

			for (i = 0; i < fcinfo.nargs; i++)
			{
				if (fcinfo.argnull[i])
					goto no_function_result;
			}
		}
	}
	else
	{
		/* Treat setexpr as a generic expression */
		InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
	}

	/*
	 * Switch to short-lived context for calling the function or expression.
	 */
	MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);

	/*
	 * Loop to handle the ValuePerCall protocol (which is also the same
	 * behavior needed in the generic ExecEvalExpr path).
	 */
	for (;;)
	{
		Datum		result;

		CHECK_FOR_INTERRUPTS();

		/*
		 * reset per-tuple memory context before each call of the function or
		 * expression. This cleans up any local memory the function may leak
		 * when called.
		 */
		ResetExprContext(econtext);

		/* Call the function or expression one time */
		if (!setexpr->elidedFuncState)
		{
			pgstat_init_function_usage(&fcinfo, &fcusage);

			fcinfo.isnull = false;
			rsinfo.isDone = ExprSingleResult;
			result = FunctionCallInvoke(&fcinfo);

			pgstat_end_function_usage(&fcusage,
									  rsinfo.isDone != ExprMultipleResult);
		}
		else
		{
			result =
				ExecEvalExpr(setexpr->elidedFuncState, econtext, &fcinfo.isnull);
			rsinfo.isDone = ExprSingleResult;
		}

		/* Which protocol does function want to use? */
		if (rsinfo.returnMode == SFRM_ValuePerCall)
		{
			/*
			 * Check for end of result set.
			 */
			if (rsinfo.isDone == ExprEndResult)
				break;

			/*
			 * If first time through, build tuplestore for result.  For a
			 * scalar function result type, also make a suitable tupdesc.
			 */
			if (first_time)
			{
				oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
				tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
				rsinfo.setResult = tupstore;
				if (!returnsTuple)
				{
					tupdesc = CreateTemplateTupleDesc(1, false);
					TupleDescInitEntry(tupdesc,
									   (AttrNumber) 1,
									   "column",
									   funcrettype,
									   -1,
									   0);
					rsinfo.setDesc = tupdesc;
				}
				MemoryContextSwitchTo(oldcontext);
			}

			/*
			 * Store current resultset item.
			 */
			if (returnsTuple)
			{
				if (!fcinfo.isnull)
				{
					HeapTupleHeader td = DatumGetHeapTupleHeader(result);

					if (tupdesc == NULL)
					{
						/*
						 * This is the first non-NULL result from the
						 * function.  Use the type info embedded in the
						 * rowtype Datum to look up the needed tupdesc.  Make
						 * a copy for the query.
						 */
						oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
						tupdesc = lookup_rowtype_tupdesc_copy(HeapTupleHeaderGetTypeId(td),
															  HeapTupleHeaderGetTypMod(td));
						rsinfo.setDesc = tupdesc;
						MemoryContextSwitchTo(oldcontext);
					}
					else
					{
						/*
						 * Verify all later returned rows have same subtype;
						 * necessary in case the type is RECORD.
						 */
						if (HeapTupleHeaderGetTypeId(td) != tupdesc->tdtypeid ||
							HeapTupleHeaderGetTypMod(td) != tupdesc->tdtypmod)
							ereport(ERROR,
									(errcode(ERRCODE_DATATYPE_MISMATCH),
									 errmsg("rows returned by function are not all of the same row type")));
					}

					/*
					 * tuplestore_puttuple needs a HeapTuple not a bare
					 * HeapTupleHeader, but it doesn't need all the fields.
					 */
					tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
					tmptup.t_data = td;

					tuplestore_puttuple(tupstore, &tmptup);
				}
				else
				{
					/*
					 * NULL result from a tuple-returning function; expand it
					 * to a row of all nulls.  We rely on the expectedDesc to
					 * form such rows.  (Note: this would be problematic if
					 * tuplestore_putvalues saved the tdtypeid/tdtypmod from
					 * the provided descriptor, since that might not match
					 * what we get from the function itself.  But it doesn't.)
					 */
					int			natts = expectedDesc->natts;
					bool	   *nullflags;

					nullflags = (bool *) palloc(natts * sizeof(bool));
					memset(nullflags, true, natts * sizeof(bool));
					tuplestore_putvalues(tupstore, expectedDesc, NULL, nullflags);
				}
			}
			else
			{
				/* Scalar-type case: just store the function result */
				tuplestore_putvalues(tupstore, tupdesc, &result, &fcinfo.isnull);
			}

			/*
			 * Are we done?
			 */
			if (rsinfo.isDone != ExprMultipleResult)
				break;
		}
		else if (rsinfo.returnMode == SFRM_Materialize)
		{
			/* check we're on the same page as the function author */
			if (!first_time || rsinfo.isDone != ExprSingleResult)
				ereport(ERROR,
						(errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
						 errmsg("table-function protocol for materialize mode was not followed")));
			/* Done evaluating the set result */
			break;
		}
		else
			ereport(ERROR,
					(errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
					 errmsg("unrecognized table-function returnMode: %d",
							(int) rsinfo.returnMode)));

		first_time = false;
	}

no_function_result:

	/*
	 * If we got nothing from the function (ie, an empty-set or NULL result),
	 * we have to create the tuplestore to return, and if it's a
	 * non-set-returning function then insert a single all-nulls row.  As
	 * above, we depend on the expectedDesc to manufacture the dummy row.
	 */
	if (rsinfo.setResult == NULL)
	{
		MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
		tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
		rsinfo.setResult = tupstore;
		if (!returnsSet)
		{
			int			natts = expectedDesc->natts;
			bool	   *nullflags;

			MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
			nullflags = (bool *) palloc(natts * sizeof(bool));
			memset(nullflags, true, natts * sizeof(bool));
			tuplestore_putvalues(tupstore, expectedDesc, NULL, nullflags);
		}
	}

	/*
	 * If function provided a tupdesc, cross-check it.  We only really need to
	 * do this for functions returning RECORD, but might as well do it always.
	 */
	if (rsinfo.setDesc)
	{
		tupledesc_match(expectedDesc, rsinfo.setDesc);

		/*
		 * If it is a dynamically-allocated TupleDesc, free it: it is
		 * typically allocated in a per-query context, so we must avoid
		 * leaking it across multiple usages.
		 */
		if (rsinfo.setDesc->tdrefcount == -1)
			FreeTupleDesc(rsinfo.setDesc);
	}

	MemoryContextSwitchTo(callerContext);

	/* All done, pass back the tuplestore */
	return rsinfo.setResult;
}
예제 #20
0
파일: execSRF.c 프로젝트: Brar/postgres
/*
 * init_sexpr - initialize a SetExprState node during first use
 */
static void
init_sexpr(Oid foid, Oid input_collation, Expr *node,
		   SetExprState *sexpr, PlanState *parent,
		   MemoryContext sexprCxt, bool allowSRF, bool needDescForSRF)
{
	AclResult	aclresult;

	/* Check permission to call function */
	aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
	if (aclresult != ACLCHECK_OK)
		aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
	InvokeFunctionExecuteHook(foid);

	/*
	 * Safety check on nargs.  Under normal circumstances this should never
	 * fail, as parser should check sooner.  But possibly it might fail if
	 * server has been compiled with FUNC_MAX_ARGS smaller than some functions
	 * declared in pg_proc?
	 */
	if (list_length(sexpr->args) > FUNC_MAX_ARGS)
		ereport(ERROR,
				(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
				 errmsg_plural("cannot pass more than %d argument to a function",
							   "cannot pass more than %d arguments to a function",
							   FUNC_MAX_ARGS,
							   FUNC_MAX_ARGS)));

	/* Set up the primary fmgr lookup information */
	fmgr_info_cxt(foid, &(sexpr->func), sexprCxt);
	fmgr_info_set_expr((Node *) sexpr->expr, &(sexpr->func));

	/* Initialize the function call parameter struct as well */
	InitFunctionCallInfoData(sexpr->fcinfo_data, &(sexpr->func),
							 list_length(sexpr->args),
							 input_collation, NULL, NULL);

	/* If function returns set, check if that's allowed by caller */
	if (sexpr->func.fn_retset && !allowSRF)
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("set-valued function called in context that cannot accept a set"),
				 parent ? executor_errposition(parent->state,
											   exprLocation((Node *) node)) : 0));

	/* Otherwise, caller should have marked the sexpr correctly */
	Assert(sexpr->func.fn_retset == sexpr->funcReturnsSet);

	/* If function returns set, prepare expected tuple descriptor */
	if (sexpr->func.fn_retset && needDescForSRF)
	{
		TypeFuncClass functypclass;
		Oid			funcrettype;
		TupleDesc	tupdesc;
		MemoryContext oldcontext;

		functypclass = get_expr_result_type(sexpr->func.fn_expr,
											&funcrettype,
											&tupdesc);

		/* Must save tupdesc in sexpr's context */
		oldcontext = MemoryContextSwitchTo(sexprCxt);

		if (functypclass == TYPEFUNC_COMPOSITE ||
			functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
		{
			/* Composite data type, e.g. a table's row type */
			Assert(tupdesc);
			/* Must copy it out of typcache for safety */
			sexpr->funcResultDesc = CreateTupleDescCopy(tupdesc);
			sexpr->funcReturnsTuple = true;
		}
		else if (functypclass == TYPEFUNC_SCALAR)
		{
			/* Base data type, i.e. scalar */
			tupdesc = CreateTemplateTupleDesc(1, false);
			TupleDescInitEntry(tupdesc,
							   (AttrNumber) 1,
							   NULL,
							   funcrettype,
							   -1,
							   0);
			sexpr->funcResultDesc = tupdesc;
			sexpr->funcReturnsTuple = false;
		}
		else if (functypclass == TYPEFUNC_RECORD)
		{
			/* This will work if function doesn't need an expectedDesc */
			sexpr->funcResultDesc = NULL;
			sexpr->funcReturnsTuple = true;
		}
		else
		{
			/* Else, we will fail if function needs an expectedDesc */
			sexpr->funcResultDesc = NULL;
		}

		MemoryContextSwitchTo(oldcontext);
	}
	else
		sexpr->funcResultDesc = NULL;

	/* Initialize additional state */
	sexpr->funcResultStore = NULL;
	sexpr->funcResultSlot = NULL;
	sexpr->shutdown_reg = false;
}
예제 #21
0
파일: pipe.c 프로젝트: orafce/orafce
static Datum
dbms_pipe_unpack_message(PG_FUNCTION_ARGS, message_data_type dtype)
{
	Oid		tupType;
	void *ptr;
	message_data_type type;
	int32 size;
	Datum result;
	message_data_type next_type;

	if (input_buffer == NULL ||
		input_buffer->items_count <= 0 ||
		input_buffer->next == NULL ||
		input_buffer->next->type == IT_NO_MORE_ITEMS)
		PG_RETURN_NULL();

	next_type = input_buffer->next->type;
	if (next_type != dtype)
		ereport(ERROR,
				(errcode(ERRCODE_DATATYPE_MISMATCH),
				 errmsg("datatype mismatch"),
				 errdetail("unpack unexpected type: %d", next_type)));

	ptr = unpack_field(input_buffer, &type, &size, &tupType);
	Assert(ptr != NULL);

	switch (type)
	{
		case IT_TIMESTAMPTZ:
			result = TimestampTzGetDatum(*(TimestampTz*)ptr);
			break;
		case IT_DATE:
			result = DateADTGetDatum(*(DateADT*)ptr);
			break;
		case IT_VARCHAR:
		case IT_NUMBER:
		case IT_BYTEA:
			result = PointerGetDatum(cstring_to_text_with_len(ptr, size));
			break;
		case IT_RECORD:
		{
#if PG_VERSION_NUM >= 120000

			LOCAL_FCINFO(info, 3);

#else

			FunctionCallInfoData info_data;
			FunctionCallInfo info = &info_data;

#endif

			StringInfoData	buf;
			text		   *data = cstring_to_text_with_len(ptr, size);

			buf.data = VARDATA(data);
			buf.len = VARSIZE(data) - VARHDRSZ;
			buf.maxlen = buf.len;
			buf.cursor = 0;

			/*
			 * Normally one would call record_recv() using DirectFunctionCall3,
			 * but that does not work since record_recv wants to cache some data
			 * using fcinfo->flinfo->fn_extra.  So we need to pass it our own
			 * flinfo parameter.
			 */
			InitFunctionCallInfoData(*info, fcinfo->flinfo, 3, InvalidOid, NULL, NULL);
			init_args_3(info, PointerGetDatum(&buf), ObjectIdGetDatum(tupType), Int32GetDatum(-1));

			result = record_recv(info);
			break;
		}
		default:
			elog(ERROR, "unexpected type: %d", type);
			result = (Datum) 0;	/* keep compiler quiet */
	}

	if (input_buffer->items_count == 0)
	{
		pfree(input_buffer);
		input_buffer = NULL;
	}

	PG_RETURN_DATUM(result);
}
예제 #22
0
파일: others.c 프로젝트: asdliuquan/orafce
/*
 * decode(lhs, [rhs, ret], ..., [default])
 */
Datum
ora_decode(PG_FUNCTION_ARGS)
{
	int		nargs;
	int		i;
	int		retarg;

	/* default value is last arg or NULL. */
	nargs = PG_NARGS();
	if (nargs % 2 == 0)
	{
		retarg = nargs - 1;
		nargs -= 1;		/* ignore the last argument */
	}
	else
		retarg = -1;	/* NULL */

	if (PG_ARGISNULL(0))
	{
		for (i = 1; i < nargs; i += 2)
		{
			if (PG_ARGISNULL(i))
			{
				retarg = i + 1;
				break;
			}
		}
	}
	else
	{
		FmgrInfo   *eq;
#if PG_VERSION_NUM >= 90100
		Oid		collation = PG_GET_COLLATION();
#endif

		/*
		 * On first call, get the input type's operator '=' and save at
		 * fn_extra.
		 */
		if (fcinfo->flinfo->fn_extra == NULL)
		{
			MemoryContext	oldctx;
			Oid				typid = get_fn_expr_argtype(fcinfo->flinfo, 0);
			Oid				eqoid = equality_oper_funcid(typid);

			oldctx = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
			eq = palloc(sizeof(FmgrInfo));
			fmgr_info(eqoid, eq);
			MemoryContextSwitchTo(oldctx);

			fcinfo->flinfo->fn_extra = eq;
		}
		else
			eq = fcinfo->flinfo->fn_extra;

		for (i = 1; i < nargs; i += 2)
		{
			FunctionCallInfoData	func;
			Datum					result;

			if (PG_ARGISNULL(i))
				continue;

#if PG_VERSION_NUM >= 90100
			InitFunctionCallInfoData(func, eq, 2, collation, NULL, NULL);
#else
			InitFunctionCallInfoData(func, eq, 2, NULL, NULL);
#endif
			func.arg[0] = PG_GETARG_DATUM(0);
			func.arg[1] = PG_GETARG_DATUM(i);
			func.argnull[0] = false;
			func.argnull[1] = false;
			result = FunctionCallInvoke(&func);

			if (!func.isnull && DatumGetBool(result))
			{
				retarg = i + 1;
				break;
			}
		}
	}

	if (retarg < 0 || PG_ARGISNULL(retarg))
		PG_RETURN_NULL();
	else
		PG_RETURN_DATUM(PG_GETARG_DATUM(retarg));
}
예제 #23
0
/*
 * Initialize the TABLESAMPLE Descriptor and the TABLESAMPLE Method.
 */
TableSampleDesc *
tablesample_init(SampleScanState *scanstate, TableSampleClause *tablesample)
{
	FunctionCallInfoData fcinfo;
	int			i;
	List	   *args = tablesample->args;
	ListCell   *arg;
	ExprContext *econtext = scanstate->ss.ps.ps_ExprContext;
	TableSampleDesc	*tsdesc = (TableSampleDesc *) palloc0(sizeof(TableSampleDesc));

	/* Load functions */
	fmgr_info(tablesample->tsminit, &(tsdesc->tsminit));
	fmgr_info(tablesample->tsmnextblock, &(tsdesc->tsmnextblock));
	fmgr_info(tablesample->tsmnexttuple, &(tsdesc->tsmnexttuple));
	if (OidIsValid(tablesample->tsmexaminetuple))
		fmgr_info(tablesample->tsmexaminetuple, &(tsdesc->tsmexaminetuple));
	else
		tsdesc->tsmexaminetuple.fn_oid = InvalidOid;
	fmgr_info(tablesample->tsmreset, &(tsdesc->tsmreset));
	fmgr_info(tablesample->tsmend, &(tsdesc->tsmend));

	InitFunctionCallInfoData(fcinfo, &tsdesc->tsminit,
							 list_length(args) + 2,
							 InvalidOid, NULL, NULL);

	tsdesc->tupDesc = scanstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
	tsdesc->heapScan = scanstate->ss.ss_currentScanDesc;

	/* First argument for init function is always TableSampleDesc */
	fcinfo.arg[0] = PointerGetDatum(tsdesc);
	fcinfo.argnull[0] = false;

	/*
	 * Second arg for init function is always REPEATABLE
	 * When tablesample->repeatable is NULL then REPEATABLE clause was not
	 * specified.
	 * When specified, the expression cannot evaluate to NULL.
	 */
	if (tablesample->repeatable)
	{
		ExprState  *argstate = ExecInitExpr((Expr *) tablesample->repeatable,
											(PlanState *) scanstate);
		fcinfo.arg[1] = ExecEvalExpr(argstate, econtext,
									 &fcinfo.argnull[1], NULL);
		if (fcinfo.argnull[1])
			ereport(ERROR,
					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
					 errmsg("REPEATABLE clause must be NOT NULL numeric value")));
	}
	else
	{
		fcinfo.arg[1] = UInt32GetDatum(random());
		fcinfo.argnull[1] = false;
	}

	/* Rest of the arguments come from user.  */
	i = 2;
	foreach(arg, args)
	{
		Expr	   *argexpr = (Expr *) lfirst(arg);
		ExprState  *argstate = ExecInitExpr(argexpr, (PlanState *) scanstate);

		if (argstate == NULL)
		{
			fcinfo.argnull[i] = true;
			fcinfo.arg[i] = (Datum) 0;;
		}

		fcinfo.arg[i] = ExecEvalExpr(argstate, econtext,
									 &fcinfo.argnull[i], NULL);
		i++;
	}