コード例 #1
0
ファイル: analyzefuncs.c プロジェクト: AnLingm/gpdb
/**
 * Given the oid of a relation, this method calculates reltuples, relpages. This only looks up
 * local information (on master or segments). It produces meaningful values for AO and
 * heap tables and returns [0.0,0.0] for all other relations.
 * Input: 
 * 	relationoid
 * Output:
 * 	array of two values [reltuples,relpages]
 */
Datum
gp_statistics_estimate_reltuples_relpages_oid(PG_FUNCTION_ARGS)
{
	
	float4		relpages = 0.0;		
	float4		reltuples = 0.0;			
	Oid			relOid = PG_GETARG_OID(0);
	Datum		values[2];
	ArrayType   *result;
	
	Relation rel = try_relation_open(relOid, AccessShareLock, false);

	if (rel != NULL)
	{
		if (rel->rd_rel->relkind == RELKIND_RELATION)
		{
			if (RelationIsHeap(rel))
			{
				gp_statistics_estimate_reltuples_relpages_heap(rel, &reltuples, &relpages);
			}
			else if (RelationIsAoRows(rel))
			{
				gp_statistics_estimate_reltuples_relpages_ao_rows(rel, &reltuples, &relpages);
			}
			else if	(RelationIsAoCols(rel))
			{
				gp_statistics_estimate_reltuples_relpages_ao_cs(rel, &reltuples, &relpages);
			}
		}
		else if (rel->rd_rel->relkind == RELKIND_INDEX)
		{
			reltuples = 1.0;
			relpages = RelationGetNumberOfBlocks(rel);
		}
		else
		{
			/**
			 * Should we silently return [0.0,0.0] or error out? Currently, we choose option 1.
			 */
		}
		relation_close(rel, AccessShareLock);
	}
	else
	{
		/**
		 * Should we silently return [0.0,0.0] or error out? Currently, we choose option 1.
		 */
	}
	
	values[0] = Float4GetDatum(reltuples);
	values[1] = Float4GetDatum(relpages);

	result = construct_array(values, 2,
					FLOAT4OID,
					sizeof(float4), true, 'i');

	PG_RETURN_ARRAYTYPE_P(result);
}
コード例 #2
0
Datum HASHAPI_Hash_1_float4(PG_FUNCTION_ARGS)
{
    int32 num_segs;            /* number of segments  */
	float4    val1;        	   /* varchar value		  */
    unsigned int targetbucket; /* 0-based             */
	int16 algorithm;  /* hashing algorithm   */
	Datum d1;
	Oid oid;

	/* Get number of segments */
    num_segs = PG_GETARG_INT32(0);
    
	/* Get hashing algoriithm */
	algorithm = PG_GETARG_INT16(1);

	/* Get the value to hash */
	val1 = PG_GETARG_FLOAT4(2);
	
	d1 = Float4GetDatum(val1);
	
	/* create a CdbHash for this hash test. */
	h = makeCdbHash(num_segs, algorithm);
	
	/* init cdb hash */
	cdbhashinit(h);
	oid = FLOAT4OID;
	cdbhash(h, d1, oid);
	
	/* reduce the result hash value */
	targetbucket = cdbhashreduce(h);	
	
	PG_RETURN_INT32(targetbucket); /* return target bucket (segID) */
}
コード例 #3
0
ファイル: indexam.c プロジェクト: hasegeli/postgres
/* ----------------
 *		index_store_float8_orderby_distances
 *
 *		Convert AM distance function's results (that can be inexact)
 *		to ORDER BY types and save them into xs_orderbyvals/xs_orderbynulls
 *		for a possible recheck.
 * ----------------
 */
void
index_store_float8_orderby_distances(IndexScanDesc scan, Oid *orderByTypes,
									 double *distances, bool recheckOrderBy)
{
	int			i;

	scan->xs_recheckorderby = recheckOrderBy;

	if (!distances)
	{
		Assert(!scan->xs_recheckorderby);

		for (i = 0; i < scan->numberOfOrderBys; i++)
		{
			scan->xs_orderbyvals[i] = (Datum) 0;
			scan->xs_orderbynulls[i] = true;
		}

		return;
	}

	for (i = 0; i < scan->numberOfOrderBys; i++)
	{
		if (orderByTypes[i] == FLOAT8OID)
		{
#ifndef USE_FLOAT8_BYVAL
			/* must free any old value to avoid memory leakage */
			if (!scan->xs_orderbynulls[i])
				pfree(DatumGetPointer(scan->xs_orderbyvals[i]));
#endif
			scan->xs_orderbyvals[i] = Float8GetDatum(distances[i]);
			scan->xs_orderbynulls[i] = false;
		}
		else if (orderByTypes[i] == FLOAT4OID)
		{
			/* convert distance function's result to ORDER BY type */
#ifndef USE_FLOAT4_BYVAL
			/* must free any old value to avoid memory leakage */
			if (!scan->xs_orderbynulls[i])
				pfree(DatumGetPointer(scan->xs_orderbyvals[i]));
#endif
			scan->xs_orderbyvals[i] = Float4GetDatum((float4) distances[i]);
			scan->xs_orderbynulls[i] = false;
		}
		else
		{
			/*
			 * If the ordering operator's return value is anything else, we
			 * don't know how to convert the float8 bound calculated by the
			 * distance function to that.  The executor won't actually need
			 * the order by values we return here, if there are no lossy
			 * results, so only insist on converting if the *recheck flag is
			 * set.
			 */
			if (scan->xs_recheckorderby)
				elog(ERROR, "ORDER BY operator must return float8 or float4 if the distance function is lossy");
			scan->xs_orderbynulls[i] = true;
		}
	}
}
コード例 #4
0
ファイル: btree_utils_num.c プロジェクト: AmiGanguli/postgres
/*
 * Convert a compressed leaf item back to the original type, for index-only
 * scans.
 */
GISTENTRY *
gbt_num_fetch(GISTENTRY *entry, const gbtree_ninfo *tinfo)
{
	GISTENTRY  *retval;
	Datum		datum;

	Assert(tinfo->indexsize >= 2 * tinfo->size);

	/*
	 * Get the original Datum from the stored datum. On leaf entries, the
	 * lower and upper bound are the same. We just grab the lower bound and
	 * return it.
	 */
	switch (tinfo->t)
	{
		case gbt_t_int2:
			datum = Int16GetDatum(*(int16 *) entry->key);
			break;
		case gbt_t_int4:
			datum = Int32GetDatum(*(int32 *) entry->key);
			break;
		case gbt_t_int8:
			datum = Int64GetDatum(*(int64 *) entry->key);
			break;
		case gbt_t_oid:
		case gbt_t_enum:
			datum = ObjectIdGetDatum(*(Oid *) entry->key);
			break;
		case gbt_t_float4:
			datum = Float4GetDatum(*(float4 *) entry->key);
			break;
		case gbt_t_float8:
			datum = Float8GetDatum(*(float8 *) entry->key);
			break;
		case gbt_t_date:
			datum = DateADTGetDatum(*(DateADT *) entry->key);
			break;
		case gbt_t_time:
			datum = TimeADTGetDatum(*(TimeADT *) entry->key);
			break;
		case gbt_t_ts:
			datum = TimestampGetDatum(*(Timestamp *) entry->key);
			break;
		case gbt_t_cash:
			datum = CashGetDatum(*(Cash *) entry->key);
			break;
		default:
			datum = PointerGetDatum(entry->key);
	}

	retval = palloc(sizeof(GISTENTRY));
	gistentryinit(*retval, datum, entry->rel, entry->page, entry->offset,
				  false);
	return retval;
}
コード例 #5
0
ファイル: trgm_op.c プロジェクト: BenjaminYu/postgres
/*
 * Deprecated function.
 * Use "pg_trgm.similarity_threshold" GUC variable instead of this function.
 */
Datum
set_limit(PG_FUNCTION_ARGS)
{
	float4		nlimit = PG_GETARG_FLOAT4(0);
	char	   *nlimit_str;
	Oid			func_out_oid;
	bool		is_varlena;

	getTypeOutputInfo(FLOAT4OID, &func_out_oid, &is_varlena);

	nlimit_str = OidOutputFunctionCall(func_out_oid, Float4GetDatum(nlimit));

	SetConfigOption("pg_trgm.similarity_threshold", nlimit_str,
					PGC_USERSET, PGC_S_SESSION);

	PG_RETURN_FLOAT4(similarity_threshold);
}
コード例 #6
0
ファイル: float.c プロジェクト: sunyangkobe/cscd43
/*
 *		float4_text		- converts a float4 number to a text string
 */
Datum
float4_text(PG_FUNCTION_ARGS)
{
	float4		num = PG_GETARG_FLOAT4(0);
	text	   *result;
	int			len;
	char	   *str;

	str = DatumGetCString(DirectFunctionCall1(float4out,
											  Float4GetDatum(num)));

	len = strlen(str) + VARHDRSZ;

	result = (text *) palloc(len);

	VARATT_SIZEP(result) = len;
	memcpy(VARDATA(result), str, (len - VARHDRSZ));

	pfree(str);

	PG_RETURN_TEXT_P(result);
}
コード例 #7
0
ファイル: pg_proc.c プロジェクト: eubide/postgres
/* ----------------------------------------------------------------
 *		ProcedureCreate
 *
 * Note: allParameterTypes, parameterModes, parameterNames, trftypes, and proconfig
 * are either arrays of the proper types or NULL.  We declare them Datum,
 * not "ArrayType *", to avoid importing array.h into pg_proc.h.
 * ----------------------------------------------------------------
 */
ObjectAddress
ProcedureCreate(const char *procedureName,
				Oid procNamespace,
				bool replace,
				bool returnsSet,
				Oid returnType,
				Oid proowner,
				Oid languageObjectId,
				Oid languageValidator,
				const char *prosrc,
				const char *probin,
				char prokind,
				bool security_definer,
				bool isLeakProof,
				bool isStrict,
				char volatility,
				char parallel,
				oidvector *parameterTypes,
				Datum allParameterTypes,
				Datum parameterModes,
				Datum parameterNames,
				List *parameterDefaults,
				Datum trftypes,
				Datum proconfig,
				float4 procost,
				float4 prorows)
{
	Oid			retval;
	int			parameterCount;
	int			allParamCount;
	Oid		   *allParams;
	char	   *paramModes = NULL;
	bool		genericInParam = false;
	bool		genericOutParam = false;
	bool		anyrangeInParam = false;
	bool		anyrangeOutParam = false;
	bool		internalInParam = false;
	bool		internalOutParam = false;
	Oid			variadicType = InvalidOid;
	Acl		   *proacl = NULL;
	Relation	rel;
	HeapTuple	tup;
	HeapTuple	oldtup;
	bool		nulls[Natts_pg_proc];
	Datum		values[Natts_pg_proc];
	bool		replaces[Natts_pg_proc];
	NameData	procname;
	TupleDesc	tupDesc;
	bool		is_update;
	ObjectAddress myself,
				referenced;
	int			i;
	Oid			trfid;

	/*
	 * sanity checks
	 */
	Assert(PointerIsValid(prosrc));

	parameterCount = parameterTypes->dim1;
	if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS)
		ereport(ERROR,
				(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
				 errmsg_plural("functions cannot have more than %d argument",
							   "functions cannot have more than %d arguments",
							   FUNC_MAX_ARGS,
							   FUNC_MAX_ARGS)));
	/* note: the above is correct, we do NOT count output arguments */

	/* Deconstruct array inputs */
	if (allParameterTypes != PointerGetDatum(NULL))
	{
		/*
		 * We expect the array to be a 1-D OID array; verify that. We don't
		 * need to use deconstruct_array() since the array data is just going
		 * to look like a C array of OID values.
		 */
		ArrayType  *allParamArray = (ArrayType *) DatumGetPointer(allParameterTypes);

		allParamCount = ARR_DIMS(allParamArray)[0];
		if (ARR_NDIM(allParamArray) != 1 ||
			allParamCount <= 0 ||
			ARR_HASNULL(allParamArray) ||
			ARR_ELEMTYPE(allParamArray) != OIDOID)
			elog(ERROR, "allParameterTypes is not a 1-D Oid array");
		allParams = (Oid *) ARR_DATA_PTR(allParamArray);
		Assert(allParamCount >= parameterCount);
		/* we assume caller got the contents right */
	}
	else
	{
		allParamCount = parameterCount;
		allParams = parameterTypes->values;
	}

	if (parameterModes != PointerGetDatum(NULL))
	{
		/*
		 * We expect the array to be a 1-D CHAR array; verify that. We don't
		 * need to use deconstruct_array() since the array data is just going
		 * to look like a C array of char values.
		 */
		ArrayType  *modesArray = (ArrayType *) DatumGetPointer(parameterModes);

		if (ARR_NDIM(modesArray) != 1 ||
			ARR_DIMS(modesArray)[0] != allParamCount ||
			ARR_HASNULL(modesArray) ||
			ARR_ELEMTYPE(modesArray) != CHAROID)
			elog(ERROR, "parameterModes is not a 1-D char array");
		paramModes = (char *) ARR_DATA_PTR(modesArray);
	}

	/*
	 * Detect whether we have polymorphic or INTERNAL arguments.  The first
	 * loop checks input arguments, the second output arguments.
	 */
	for (i = 0; i < parameterCount; i++)
	{
		switch (parameterTypes->values[i])
		{
			case ANYARRAYOID:
			case ANYELEMENTOID:
			case ANYNONARRAYOID:
			case ANYENUMOID:
				genericInParam = true;
				break;
			case ANYRANGEOID:
				genericInParam = true;
				anyrangeInParam = true;
				break;
			case INTERNALOID:
				internalInParam = true;
				break;
		}
	}

	if (allParameterTypes != PointerGetDatum(NULL))
	{
		for (i = 0; i < allParamCount; i++)
		{
			if (paramModes == NULL ||
				paramModes[i] == PROARGMODE_IN ||
				paramModes[i] == PROARGMODE_VARIADIC)
				continue;		/* ignore input-only params */

			switch (allParams[i])
			{
				case ANYARRAYOID:
				case ANYELEMENTOID:
				case ANYNONARRAYOID:
				case ANYENUMOID:
					genericOutParam = true;
					break;
				case ANYRANGEOID:
					genericOutParam = true;
					anyrangeOutParam = true;
					break;
				case INTERNALOID:
					internalOutParam = true;
					break;
			}
		}
	}

	/*
	 * Do not allow polymorphic return type unless at least one input argument
	 * is polymorphic.  ANYRANGE return type is even stricter: must have an
	 * ANYRANGE input (since we can't deduce the specific range type from
	 * ANYELEMENT).  Also, do not allow return type INTERNAL unless at least
	 * one input argument is INTERNAL.
	 */
	if ((IsPolymorphicType(returnType) || genericOutParam)
		&& !genericInParam)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
				 errmsg("cannot determine result data type"),
				 errdetail("A function returning a polymorphic type must have at least one polymorphic argument.")));

	if ((returnType == ANYRANGEOID || anyrangeOutParam) &&
		!anyrangeInParam)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
				 errmsg("cannot determine result data type"),
				 errdetail("A function returning \"anyrange\" must have at least one \"anyrange\" argument.")));

	if ((returnType == INTERNALOID || internalOutParam) && !internalInParam)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
				 errmsg("unsafe use of pseudo-type \"internal\""),
				 errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));

	if (paramModes != NULL)
	{
		/*
		 * Only the last input parameter can be variadic; if it is, save its
		 * element type.  Errors here are just elog since caller should have
		 * checked this already.
		 */
		for (i = 0; i < allParamCount; i++)
		{
			switch (paramModes[i])
			{
				case PROARGMODE_IN:
				case PROARGMODE_INOUT:
					if (OidIsValid(variadicType))
						elog(ERROR, "variadic parameter must be last");
					break;
				case PROARGMODE_OUT:
				case PROARGMODE_TABLE:
					/* okay */
					break;
				case PROARGMODE_VARIADIC:
					if (OidIsValid(variadicType))
						elog(ERROR, "variadic parameter must be last");
					switch (allParams[i])
					{
						case ANYOID:
							variadicType = ANYOID;
							break;
						case ANYARRAYOID:
							variadicType = ANYELEMENTOID;
							break;
						default:
							variadicType = get_element_type(allParams[i]);
							if (!OidIsValid(variadicType))
								elog(ERROR, "variadic parameter is not an array");
							break;
					}
					break;
				default:
					elog(ERROR, "invalid parameter mode '%c'", paramModes[i]);
					break;
			}
		}
	}

	/*
	 * All seems OK; prepare the data to be inserted into pg_proc.
	 */

	for (i = 0; i < Natts_pg_proc; ++i)
	{
		nulls[i] = false;
		values[i] = (Datum) 0;
		replaces[i] = true;
	}

	namestrcpy(&procname, procedureName);
	values[Anum_pg_proc_proname - 1] = NameGetDatum(&procname);
	values[Anum_pg_proc_pronamespace - 1] = ObjectIdGetDatum(procNamespace);
	values[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(proowner);
	values[Anum_pg_proc_prolang - 1] = ObjectIdGetDatum(languageObjectId);
	values[Anum_pg_proc_procost - 1] = Float4GetDatum(procost);
	values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows);
	values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType);
	values[Anum_pg_proc_protransform - 1] = ObjectIdGetDatum(InvalidOid);
	values[Anum_pg_proc_prokind - 1] = CharGetDatum(prokind);
	values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer);
	values[Anum_pg_proc_proleakproof - 1] = BoolGetDatum(isLeakProof);
	values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict);
	values[Anum_pg_proc_proretset - 1] = BoolGetDatum(returnsSet);
	values[Anum_pg_proc_provolatile - 1] = CharGetDatum(volatility);
	values[Anum_pg_proc_proparallel - 1] = CharGetDatum(parallel);
	values[Anum_pg_proc_pronargs - 1] = UInt16GetDatum(parameterCount);
	values[Anum_pg_proc_pronargdefaults - 1] = UInt16GetDatum(list_length(parameterDefaults));
	values[Anum_pg_proc_prorettype - 1] = ObjectIdGetDatum(returnType);
	values[Anum_pg_proc_proargtypes - 1] = PointerGetDatum(parameterTypes);
	if (allParameterTypes != PointerGetDatum(NULL))
		values[Anum_pg_proc_proallargtypes - 1] = allParameterTypes;
	else
		nulls[Anum_pg_proc_proallargtypes - 1] = true;
	if (parameterModes != PointerGetDatum(NULL))
		values[Anum_pg_proc_proargmodes - 1] = parameterModes;
	else
		nulls[Anum_pg_proc_proargmodes - 1] = true;
	if (parameterNames != PointerGetDatum(NULL))
		values[Anum_pg_proc_proargnames - 1] = parameterNames;
	else
		nulls[Anum_pg_proc_proargnames - 1] = true;
	if (parameterDefaults != NIL)
		values[Anum_pg_proc_proargdefaults - 1] = CStringGetTextDatum(nodeToString(parameterDefaults));
	else
		nulls[Anum_pg_proc_proargdefaults - 1] = true;
	if (trftypes != PointerGetDatum(NULL))
		values[Anum_pg_proc_protrftypes - 1] = trftypes;
	else
		nulls[Anum_pg_proc_protrftypes - 1] = true;
	values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc);
	if (probin)
		values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin);
	else
		nulls[Anum_pg_proc_probin - 1] = true;
	if (proconfig != PointerGetDatum(NULL))
		values[Anum_pg_proc_proconfig - 1] = proconfig;
	else
		nulls[Anum_pg_proc_proconfig - 1] = true;
	/* proacl will be determined later */

	rel = table_open(ProcedureRelationId, RowExclusiveLock);
	tupDesc = RelationGetDescr(rel);

	/* Check for pre-existing definition */
	oldtup = SearchSysCache3(PROCNAMEARGSNSP,
							 PointerGetDatum(procedureName),
							 PointerGetDatum(parameterTypes),
							 ObjectIdGetDatum(procNamespace));

	if (HeapTupleIsValid(oldtup))
	{
		/* There is one; okay to replace it? */
		Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup);
		Datum		proargnames;
		bool		isnull;
		const char *dropcmd;

		if (!replace)
			ereport(ERROR,
					(errcode(ERRCODE_DUPLICATE_FUNCTION),
					 errmsg("function \"%s\" already exists with same argument types",
							procedureName)));
		if (!pg_proc_ownercheck(oldproc->oid, proowner))
			aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
						   procedureName);

		/* Not okay to change routine kind */
		if (oldproc->prokind != prokind)
			ereport(ERROR,
					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
					 errmsg("cannot change routine kind"),
					 (oldproc->prokind == PROKIND_AGGREGATE ?
					  errdetail("\"%s\" is an aggregate function.", procedureName) :
					  oldproc->prokind == PROKIND_FUNCTION ?
					  errdetail("\"%s\" is a function.", procedureName) :
					  oldproc->prokind == PROKIND_PROCEDURE ?
					  errdetail("\"%s\" is a procedure.", procedureName) :
					  oldproc->prokind == PROKIND_WINDOW ?
					  errdetail("\"%s\" is a window function.", procedureName) :
					  0)));

		dropcmd = (prokind == PROKIND_PROCEDURE ? "DROP PROCEDURE" : "DROP FUNCTION");

		/*
		 * Not okay to change the return type of the existing proc, since
		 * existing rules, views, etc may depend on the return type.
		 *
		 * In case of a procedure, a changing return type means that whether
		 * the procedure has output parameters was changed.  Since there is no
		 * user visible return type, we produce a more specific error message.
		 */
		if (returnType != oldproc->prorettype ||
			returnsSet != oldproc->proretset)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
					 prokind == PROKIND_PROCEDURE
					 ? errmsg("cannot change whether a procedure has output parameters")
					 : errmsg("cannot change return type of existing function"),
					 /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */
					 errhint("Use %s %s first.",
							 dropcmd,
							 format_procedure(oldproc->oid))));

		/*
		 * If it returns RECORD, check for possible change of record type
		 * implied by OUT parameters
		 */
		if (returnType == RECORDOID)
		{
			TupleDesc	olddesc;
			TupleDesc	newdesc;

			olddesc = build_function_result_tupdesc_t(oldtup);
			newdesc = build_function_result_tupdesc_d(prokind,
													  allParameterTypes,
													  parameterModes,
													  parameterNames);
			if (olddesc == NULL && newdesc == NULL)
				 /* ok, both are runtime-defined RECORDs */ ;
			else if (olddesc == NULL || newdesc == NULL ||
					 !equalTupleDescs(olddesc, newdesc))
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
						 errmsg("cannot change return type of existing function"),
						 errdetail("Row type defined by OUT parameters is different."),
						 /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */
						 errhint("Use %s %s first.",
								 dropcmd,
								 format_procedure(oldproc->oid))));
		}

		/*
		 * If there were any named input parameters, check to make sure the
		 * names have not been changed, as this could break existing calls. We
		 * allow adding names to formerly unnamed parameters, though.
		 */
		proargnames = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup,
									  Anum_pg_proc_proargnames,
									  &isnull);
		if (!isnull)
		{
			Datum		proargmodes;
			char	  **old_arg_names;
			char	  **new_arg_names;
			int			n_old_arg_names;
			int			n_new_arg_names;
			int			j;

			proargmodes = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup,
										  Anum_pg_proc_proargmodes,
										  &isnull);
			if (isnull)
				proargmodes = PointerGetDatum(NULL);	/* just to be sure */

			n_old_arg_names = get_func_input_arg_names(proargnames,
													   proargmodes,
													   &old_arg_names);
			n_new_arg_names = get_func_input_arg_names(parameterNames,
													   parameterModes,
													   &new_arg_names);
			for (j = 0; j < n_old_arg_names; j++)
			{
				if (old_arg_names[j] == NULL)
					continue;
				if (j >= n_new_arg_names || new_arg_names[j] == NULL ||
					strcmp(old_arg_names[j], new_arg_names[j]) != 0)
					ereport(ERROR,
							(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
							 errmsg("cannot change name of input parameter \"%s\"",
									old_arg_names[j]),
							 /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */
							 errhint("Use %s %s first.",
									 dropcmd,
									 format_procedure(oldproc->oid))));
			}
		}

		/*
		 * If there are existing defaults, check compatibility: redefinition
		 * must not remove any defaults nor change their types.  (Removing a
		 * default might cause a function to fail to satisfy an existing call.
		 * Changing type would only be possible if the associated parameter is
		 * polymorphic, and in such cases a change of default type might alter
		 * the resolved output type of existing calls.)
		 */
		if (oldproc->pronargdefaults != 0)
		{
			Datum		proargdefaults;
			List	   *oldDefaults;
			ListCell   *oldlc;
			ListCell   *newlc;

			if (list_length(parameterDefaults) < oldproc->pronargdefaults)
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
						 errmsg("cannot remove parameter defaults from existing function"),
						 /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */
						 errhint("Use %s %s first.",
								 dropcmd,
								 format_procedure(oldproc->oid))));

			proargdefaults = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup,
											 Anum_pg_proc_proargdefaults,
											 &isnull);
			Assert(!isnull);
			oldDefaults = castNode(List, stringToNode(TextDatumGetCString(proargdefaults)));
			Assert(list_length(oldDefaults) == oldproc->pronargdefaults);

			/* new list can have more defaults than old, advance over 'em */
			newlc = list_head(parameterDefaults);
			for (i = list_length(parameterDefaults) - oldproc->pronargdefaults;
				 i > 0;
				 i--)
				newlc = lnext(newlc);

			foreach(oldlc, oldDefaults)
			{
				Node	   *oldDef = (Node *) lfirst(oldlc);
				Node	   *newDef = (Node *) lfirst(newlc);

				if (exprType(oldDef) != exprType(newDef))
					ereport(ERROR,
							(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
							 errmsg("cannot change data type of existing parameter default value"),
							 /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */
							 errhint("Use %s %s first.",
									 dropcmd,
									 format_procedure(oldproc->oid))));
				newlc = lnext(newlc);
			}
		}
コード例 #8
0
/*
 * EnumValuesCreate
 *		Create an entry in pg_enum for each of the supplied enum values.
 *
 * vals is a list of Value strings.
 */
void
EnumValuesCreate(Oid enumTypeOid, List *vals)
{
	Relation	pg_enum;
	NameData	enumlabel;
	Oid		   *oids;
	int			elemno,
				num_elems;
	Datum		values[Natts_pg_enum];
	bool		nulls[Natts_pg_enum];
	ListCell   *lc;
	HeapTuple	tup;

	num_elems = list_length(vals);

	/*
	 * We do not bother to check the list of values for duplicates --- if you
	 * have any, you'll get a less-than-friendly unique-index violation. It is
	 * probably not worth trying harder.
	 */

	pg_enum = heap_open(EnumRelationId, RowExclusiveLock);

	/*
	 * Allocate OIDs for the enum's members.
	 *
	 * While this method does not absolutely guarantee that we generate no
	 * duplicate OIDs (since we haven't entered each oid into the table before
	 * allocating the next), trouble could only occur if the OID counter wraps
	 * all the way around before we finish. Which seems unlikely.
	 */
	oids = (Oid *) palloc(num_elems * sizeof(Oid));

	for (elemno = 0; elemno < num_elems; elemno++)
	{
		/*
		 * We assign even-numbered OIDs to all the new enum labels.  This
		 * tells the comparison functions the OIDs are in the correct sort
		 * order and can be compared directly.
		 */
		Oid			new_oid;

		do
		{
			new_oid = GetNewOid(pg_enum);
		} while (new_oid & 1);
		oids[elemno] = new_oid;
	}

	/* sort them, just in case OID counter wrapped from high to low */
	qsort(oids, num_elems, sizeof(Oid), oid_cmp);

	/* and make the entries */
	memset(nulls, false, sizeof(nulls));

	elemno = 0;
	foreach(lc, vals)
	{
		char	   *lab = strVal(lfirst(lc));

		/*
		 * labels are stored in a name field, for easier syscache lookup, so
		 * check the length to make sure it's within range.
		 */
		if (strlen(lab) > (NAMEDATALEN - 1))
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_NAME),
					 errmsg("invalid enum label \"%s\"", lab),
					 errdetail("Labels must be %d characters or less.",
							   NAMEDATALEN - 1)));

		values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid);
		values[Anum_pg_enum_enumsortorder - 1] = Float4GetDatum(elemno + 1);
		namestrcpy(&enumlabel, lab);
		values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel);

		tup = heap_form_tuple(RelationGetDescr(pg_enum), values, nulls);
		HeapTupleSetOid(tup, oids[elemno]);

		simple_heap_insert(pg_enum, tup);
		CatalogUpdateIndexes(pg_enum, tup);
		heap_freetuple(tup);

		elemno++;
	}
コード例 #9
0
ファイル: payment.c プロジェクト: mw2q/dbt2
Datum payment(PG_FUNCTION_ARGS)
{
	/* Input variables. */
	int32 w_id = PG_GETARG_INT32(0);
	int32 d_id = PG_GETARG_INT32(1);
	int32 c_id = PG_GETARG_INT32(2);
	int32 c_w_id = PG_GETARG_INT32(3);
	int32 c_d_id = PG_GETARG_INT32(4);
	text *c_last = PG_GETARG_TEXT_P(5);
	float4 h_amount = PG_GETARG_FLOAT4(6);

	TupleDesc tupdesc;
	SPITupleTable *tuptable;
	HeapTuple tuple;

	int ret;
	char *w_name = NULL;
	char *w_street_1 = NULL;
	char *w_street_2 = NULL;
	char *w_city = NULL;
	char *w_state = NULL;
	char *w_zip = NULL;

	char *d_name = NULL;
	char *d_street_1 = NULL;
	char *d_street_2 = NULL;
	char *d_city = NULL;
	char *d_state = NULL;
	char *d_zip = NULL;

	char *tmp_c_id = NULL;
	int my_c_id = 0;
	int count;

	char *c_first = NULL;
	char *c_middle = NULL;
	char *my_c_last = NULL;
	char *c_street_1 = NULL;
	char *c_street_2 = NULL;
	char *c_city = NULL;
	char *c_state = NULL;
	char *c_zip = NULL;
	char *c_phone = NULL;
	char *c_since = NULL;
	char *c_credit = NULL;
	char *c_credit_lim = NULL;
	char *c_discount = NULL;
	char *c_balance = NULL;
	char *c_data = NULL;
	char *c_ytd_payment = NULL;

	Datum	args[8];
	char	nulls[8] = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' };

	elog(DEBUG1, "w_id = %d", w_id);
	elog(DEBUG1, "d_id = %d", d_id);
	elog(DEBUG1, "c_id = %d", c_id);
	elog(DEBUG1, "c_w_id = %d", c_w_id);
	elog(DEBUG1, "c_d_id = %d", c_d_id);
	elog(DEBUG1, "c_last = %s",
			DatumGetCString(DirectFunctionCall1(textout,
			PointerGetDatum(c_last))));
	elog(DEBUG1, "h_amount = %f", h_amount);

	SPI_connect();

	plan_queries(statements);

	args[0] = Int32GetDatum(w_id);
	ret = SPI_execute_plan(PAYMENT_1, args, nulls, true, 0);
	if (ret == SPI_OK_SELECT && SPI_processed > 0) {
		tupdesc = SPI_tuptable->tupdesc;
		tuptable = SPI_tuptable;
		tuple = tuptable->vals[0];

		w_name = SPI_getvalue(tuple, tupdesc, 1);
		w_street_1 = SPI_getvalue(tuple, tupdesc, 2);
		w_street_2 = SPI_getvalue(tuple, tupdesc, 3);
		w_city = SPI_getvalue(tuple, tupdesc, 4);
		w_state = SPI_getvalue(tuple, tupdesc, 5);
		w_zip = SPI_getvalue(tuple, tupdesc, 6);
		elog(DEBUG1, "w_name = %s", w_name);
		elog(DEBUG1, "w_street_1 = %s", w_street_1);
		elog(DEBUG1, "w_street_2 = %s", w_street_2);
		elog(DEBUG1, "w_city = %s", w_city);
		elog(DEBUG1, "w_state = %s", w_state);
		elog(DEBUG1, "w_zip = %s", w_zip);
	} else {
		SPI_finish();
		PG_RETURN_INT32(-1);
	}

	args[0] = Float4GetDatum(h_amount);
	args[1] = Int32GetDatum(w_id);
	ret = SPI_execute_plan(PAYMENT_2, args, nulls, false, 0);
	if (ret != SPI_OK_UPDATE) {
		SPI_finish();
		PG_RETURN_INT32(-1);
	}

	args[0] = Int32GetDatum(d_id);
	args[1] = Int32GetDatum(w_id);
	ret = SPI_execute_plan(PAYMENT_3, args, nulls, true, 0);
	if (ret == SPI_OK_SELECT && SPI_processed > 0) {
		tupdesc = SPI_tuptable->tupdesc;
		tuptable = SPI_tuptable;
		tuple = tuptable->vals[0];

		d_name = SPI_getvalue(tuple, tupdesc, 1);
		d_street_1 = SPI_getvalue(tuple, tupdesc, 2);
		d_street_2 = SPI_getvalue(tuple, tupdesc, 3);
		d_city = SPI_getvalue(tuple, tupdesc, 4);
		d_state = SPI_getvalue(tuple, tupdesc, 5);
		d_zip = SPI_getvalue(tuple, tupdesc, 6);
		elog(DEBUG1, "d_name = %s", d_name);
		elog(DEBUG1, "d_street_1 = %s", d_street_1);
		elog(DEBUG1, "d_street_2 = %s", d_street_2);
		elog(DEBUG1, "d_city = %s", d_city);
		elog(DEBUG1, "d_state = %s", d_state);
		elog(DEBUG1, "d_zip = %s", d_zip);
	} else {
		SPI_finish();
		PG_RETURN_INT32(-1);
	}

	args[0] = Float4GetDatum(h_amount);
	args[1] = Int32GetDatum(d_id);
	args[2] = Int32GetDatum(w_id);
	ret = SPI_execute_plan(PAYMENT_4, args, nulls, false, 0);
	if (ret != SPI_OK_UPDATE) {
		SPI_finish();
		PG_RETURN_INT32(-1);
	}

	if (c_id == 0) {
		args[0] = Int32GetDatum(w_id);
		args[1] = Int32GetDatum(d_id);
		args[2] = PointerGetDatum(c_last);
		ret = SPI_execute_plan(PAYMENT_5, args, nulls, true, 0);
		count = SPI_processed;
		if (ret == SPI_OK_SELECT && SPI_processed > 0) {
			tupdesc = SPI_tuptable->tupdesc;
			tuptable = SPI_tuptable;
			tuple = tuptable->vals[count / 2];

			tmp_c_id = SPI_getvalue(tuple, tupdesc, 1);
			elog(DEBUG1, "c_id = %s, %d total, selected %d",
					tmp_c_id, count, count / 2);
			my_c_id = atoi(tmp_c_id);
		} else {
			SPI_finish();
			PG_RETURN_INT32(-1);
		}
	} else {
		my_c_id = c_id;
	}

	args[0] = Int32GetDatum(c_w_id);
	args[1] = Int32GetDatum(c_d_id);
	args[2] = Int32GetDatum(my_c_id);
	ret = SPI_execute_plan(PAYMENT_6, args, nulls, true, 0);
	if (ret == SPI_OK_SELECT && SPI_processed > 0) {
		tupdesc = SPI_tuptable->tupdesc;
		tuptable = SPI_tuptable;
		tuple = tuptable->vals[0];

		c_first = SPI_getvalue(tuple, tupdesc, 1);
		c_middle = SPI_getvalue(tuple, tupdesc, 2);
		my_c_last = SPI_getvalue(tuple, tupdesc, 3);
		c_street_1 = SPI_getvalue(tuple, tupdesc, 4);
		c_street_2 = SPI_getvalue(tuple, tupdesc, 5);
		c_city = SPI_getvalue(tuple, tupdesc, 6);
		c_state = SPI_getvalue(tuple, tupdesc, 7);
		c_zip = SPI_getvalue(tuple, tupdesc, 8);
		c_phone = SPI_getvalue(tuple, tupdesc, 9);
		c_since = SPI_getvalue(tuple, tupdesc, 10);
		c_credit = SPI_getvalue(tuple, tupdesc, 11);
		c_credit_lim = SPI_getvalue(tuple, tupdesc, 12);
		c_discount = SPI_getvalue(tuple, tupdesc, 13);
		c_balance = SPI_getvalue(tuple, tupdesc, 14);
		c_data = SPI_getvalue(tuple, tupdesc, 15);
		c_ytd_payment = SPI_getvalue(tuple, tupdesc, 16);
		elog(DEBUG1, "c_first = %s", c_first);
		elog(DEBUG1, "c_middle = %s", c_middle);
		elog(DEBUG1, "c_last = %s", my_c_last);
		elog(DEBUG1, "c_street_1 = %s", c_street_1);
		elog(DEBUG1, "c_street_2 = %s", c_street_2);
		elog(DEBUG1, "c_city = %s", c_city);
		elog(DEBUG1, "c_state = %s", c_state);
		elog(DEBUG1, "c_zip = %s", c_zip);
		elog(DEBUG1, "c_phone = %s", c_phone);
		elog(DEBUG1, "c_since = %s", c_since);
		elog(DEBUG1, "c_credit = %s", c_credit);
		elog(DEBUG1, "c_credit_lim = %s", c_credit_lim);
		elog(DEBUG1, "c_discount = %s", c_discount);
		elog(DEBUG1, "c_balance = %s", c_balance);
		elog(DEBUG1, "c_data = %s", c_data);
		elog(DEBUG1, "c_ytd_payment = %s", c_ytd_payment);
	} else {
		SPI_finish();
		PG_RETURN_INT32(-1);
	}

	/* It's either "BC" or "GC". */
	if (c_credit[0] == 'G') {
		args[0] = Float4GetDatum(h_amount);
		args[1] = Int32GetDatum(my_c_id);
		args[2] = Int32GetDatum(c_w_id);
		args[3] = Int32GetDatum(c_d_id);
		ret = SPI_execute_plan(PAYMENT_7_GC, args, nulls, false, 0);
		if (ret != SPI_OK_UPDATE) {
			SPI_finish();
			PG_RETURN_INT32(-1);
		}
	} else {
		char my_c_data[1000];

		sprintf(my_c_data, "%d %d %d %d %d %f ", my_c_id, c_d_id,
				c_w_id, d_id, w_id, h_amount);

		args[0] = Float4GetDatum(h_amount);
		args[1] = CStringGetTextDatum(my_c_data);
		args[2] = Int32GetDatum(my_c_id);
		args[3] = Int32GetDatum(c_w_id);
		args[4] = Int32GetDatum(c_d_id);
		ret = SPI_execute_plan(PAYMENT_7_BC, args, nulls, false, 0);
		if (ret != SPI_OK_UPDATE) {
			SPI_finish();
			PG_RETURN_INT32(-1);
		}
	}

	args[0] = Int32GetDatum(my_c_id);
	args[1] = Int32GetDatum(c_d_id);
	args[2] = Int32GetDatum(c_w_id);
	args[3] = Int32GetDatum(d_id);
	args[4] = Int32GetDatum(w_id);
	args[5] = Float4GetDatum(h_amount);
	args[6] = CStringGetTextDatum(w_name);
	args[7] = CStringGetTextDatum(d_name);
	ret = SPI_execute_plan(PAYMENT_8, args, nulls, false, 0);
	if (ret != SPI_OK_INSERT) {
		SPI_finish();
		PG_RETURN_INT32(-1);
	}

	SPI_finish();
	PG_RETURN_INT32(1);
}
コード例 #10
0
Datum
query_histogram(PG_FUNCTION_ARGS)
{
	FuncCallContext *funcctx;
	TupleDesc	   tupdesc;
	AttInMetadata   *attinmeta;
	histogram_data* data;

	/* init on the first call */
	if (SRF_IS_FIRSTCALL()) {

		MemoryContext oldcontext;

		funcctx = SRF_FIRSTCALL_INIT();
		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

		data = query_hist_get_data(PG_GETARG_BOOL(0));

		/* init (open file, etc.), maybe read all the data in memory
		 * so that the file is not kept open for a long time */
		funcctx->user_fctx = data;
		funcctx->max_calls = data->bins_count;

		if (data->bins_count > 0) {
			funcctx->max_calls = data->bins_count + 1;
		}

		/* Build a tuple descriptor for our result type */
		if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 errmsg("function returning record called in context "
							"that cannot accept type record")));

		/*
		 * generate attribute metadata needed later to produce tuples from raw
		 * C strings
		 */
		attinmeta = TupleDescGetAttInMetadata(tupdesc);
		funcctx->attinmeta = attinmeta;
		funcctx->tuple_desc = tupdesc;

		/* switch back to the old context */
		MemoryContextSwitchTo(oldcontext);

	}

	/* init the context */
	funcctx = SRF_PERCALL_SETUP();

	/* check if we have more data */
	if (funcctx->max_calls > funcctx->call_cntr)
	{
		HeapTuple	   tuple;
		Datum		   result;
		Datum		   values[6];
		bool			nulls[6];

		int binIdx;

		binIdx = funcctx->call_cntr;

		data = (histogram_data*)funcctx->user_fctx;

		memset(nulls, 0, sizeof(nulls));

		if (data->histogram_type == HISTOGRAM_LINEAR) {

			values[0] = UInt32GetDatum(binIdx * data->bins_width);

			if (funcctx->max_calls - 1 == funcctx->call_cntr) {
				values[1] = UInt32GetDatum(0);
				nulls[1] = TRUE;
			} else {
				values[1] = UInt32GetDatum((binIdx+1)* data->bins_width);
			}
		} else {

			if (funcctx->call_cntr == 0) {
				values[0] = UInt32GetDatum(0);
			} else {
				values[0] = UInt32GetDatum(pow(2,binIdx-1) * data->bins_width);
			}

			if (funcctx->max_calls - 1 == funcctx->call_cntr) {
				values[1] = UInt32GetDatum(0);
				nulls[1] = TRUE;
			} else {
				values[1] = UInt32GetDatum(pow(2,binIdx) * data->bins_width);
			}

		}

		values[2] = Int64GetDatum(data->count_data[binIdx]);

		if (data->total_count > 0) {
			values[3] = Float4GetDatum(100.0*data->count_data[binIdx] / data->total_count);
		} else {
			values[3] = Float4GetDatum(0);
		}

		values[4] = Float8GetDatum(data->time_data[binIdx]);

		if (data->total_time > 0) {
			values[5] = Float4GetDatum(100*data->time_data[binIdx] / data->total_time);
		} else {
			values[5] = Float4GetDatum(0);
		}

		/* Build and return the tuple. */
		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);

		/* make the tuple into a datum */
		result = HeapTupleGetDatum(tuple);

		/* Here we want to return another item: */
		SRF_RETURN_NEXT(funcctx, result);

	}
	else
	{
		/* Here we are done returning items and just need to clean up: */
		SRF_RETURN_DONE(funcctx);
	}

}
コード例 #11
0
Datum summarize_variant( PG_FUNCTION_ARGS ) {
	if( PG_ARGISNULL(0) ) {
		ereport( ERROR, (errmsg("summarize_variant: array of values must be non-null")) );
	}

	TupleDesc tuple_desc;
	if( get_call_result_type( fcinfo, NULL, &tuple_desc ) != TYPEFUNC_COMPOSITE ) {
		ereport( ERROR, (errmsg("summarize_variant: function returning composite type called in context that cannot accept composite type")) );
	}
	tuple_desc = BlessTupleDesc( tuple_desc );

	ArrayType* values = PG_GETARG_ARRAYTYPE_P( 0 );

	Oid values_type = ARR_ELEMTYPE( values );
	int16 values_width;
	bool values_passbyvalue;
	char values_alignmentcode;
	Datum* values_content;
	bool* values_nullflags;
	int values_length;
	get_typlenbyvalalign( values_type, &values_width, &values_passbyvalue, &values_alignmentcode );
	deconstruct_array( values, values_type, values_width, values_passbyvalue, values_alignmentcode, &values_content, &values_nullflags, &values_length );

	size_t composite_type_elements = 9;
	Datum* results_content = (Datum*)palloc0( sizeof(Datum) * composite_type_elements );
	bool* results_nullflags = (bool*)palloc0( sizeof(bool) * composite_type_elements );
	// FORMAT
	// [0] - call rate
	// [1] - subset call rate
	// [2] - alternate allele frequency
	// [3] - sample alternate allele frequency


	if( !PG_ARGISNULL(1) ) {
		ArrayType* indices = PG_GETARG_ARRAYTYPE_P(1);
		Oid indices_type = ARR_ELEMTYPE( indices );
		int16 indices_width;
		bool indices_passbyvalue;
		char indices_alignmentcode;
		Datum* indices_content;
		bool* indices_nullflags;
		int indices_length;
		get_typlenbyvalalign( indices_type, &indices_width, &indices_passbyvalue, &indices_alignmentcode );
		deconstruct_array( indices, indices_type, indices_width, indices_passbyvalue, indices_alignmentcode, &indices_content, &indices_nullflags, &indices_length );
		int count = 0;
		int nonnull_count = 0;
		int alternate_count = 0;
		int i;
		for( i = 0; i < indices_length; ++i ) {
			if( !indices_nullflags[i] && indices_content[i] - 1 < (long unsigned)values_length ) {
				++count;
				if( !values_nullflags[ indices_content[i] - 1 ] ) {
					++nonnull_count;
					alternate_count += values_content[ indices_content[i] - 1 ];
				}
			}
		}
		results_content[1] = Float4GetDatum( nonnull_count / (float4)count );
		results_content[3] = Float4GetDatum( nonnull_count == 0 ? 0 : alternate_count/(2.0*nonnull_count) );
		results_nullflags[3] = nonnull_count == 0;
	} else {
		results_nullflags[1] = true;
		results_nullflags[3] = true;
	}

	int count = values_length;
	unsigned int nonnull_count = 0;
	unsigned int alternate_count = 0;
	int i;
	for( i = 0; i < values_length; ++i ) {
		if( !values_nullflags[i] ) {
			++nonnull_count;
			alternate_count += values_content[i];
		}
	}

	results_content[0] = Float4GetDatum( nonnull_count / (float4)count );
	results_content[2] = Float4GetDatum( nonnull_count == 0 ? 0 : alternate_count/(2.0*nonnull_count) );
	results_nullflags[2] = nonnull_count == 0;

	HeapTuple tuple = heap_form_tuple( tuple_desc, results_content, results_nullflags );
	Datum result = HeapTupleGetDatum( tuple );
	PG_RETURN_DATUM( result );
}
コード例 #12
0
/*
 * Fetch next heap tuple in an ordered search
 */
static bool
getNextNearest(IndexScanDesc scan)
{
	GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
	bool		res = false;
	int			i;

	if (scan->xs_itup)
	{
		/* free previously returned tuple */
		pfree(scan->xs_itup);
		scan->xs_itup = NULL;
	}

	do
	{
		GISTSearchItem *item = getNextGISTSearchItem(so);

		if (!item)
			break;

		if (GISTSearchItemIsHeap(*item))
		{
			/* found a heap item at currently minimal distance */
			scan->xs_ctup.t_self = item->data.heap.heapPtr;
			scan->xs_recheck = item->data.heap.recheck;
			scan->xs_recheckorderby = item->data.heap.recheckDistances;
			for (i = 0; i < scan->numberOfOrderBys; i++)
			{
				if (so->orderByTypes[i] == FLOAT8OID)
				{
#ifndef USE_FLOAT8_BYVAL
					/* must free any old value to avoid memory leakage */
					if (!scan->xs_orderbynulls[i])
						pfree(DatumGetPointer(scan->xs_orderbyvals[i]));
#endif
					scan->xs_orderbyvals[i] = Float8GetDatum(item->distances[i]);
					scan->xs_orderbynulls[i] = false;
				}
				else if (so->orderByTypes[i] == FLOAT4OID)
				{
					/* convert distance function's result to ORDER BY type */
#ifndef USE_FLOAT4_BYVAL
					/* must free any old value to avoid memory leakage */
					if (!scan->xs_orderbynulls[i])
						pfree(DatumGetPointer(scan->xs_orderbyvals[i]));
#endif
					scan->xs_orderbyvals[i] = Float4GetDatum((float4) item->distances[i]);
					scan->xs_orderbynulls[i] = false;
				}
				else
				{
					/*
					 * If the ordering operator's return value is anything
					 * else, we don't know how to convert the float8 bound
					 * calculated by the distance function to that.  The
					 * executor won't actually need the order by values we
					 * return here, if there are no lossy results, so only
					 * insist on converting if the *recheck flag is set.
					 */
					if (scan->xs_recheckorderby)
						elog(ERROR, "GiST operator family's FOR ORDER BY operator must return float8 or float4 if the distance function is lossy");
					scan->xs_orderbynulls[i] = true;
				}
			}

			/* in an index-only scan, also return the reconstructed tuple. */
			if (scan->xs_want_itup)
				scan->xs_itup = item->data.heap.ftup;
			res = true;
		}
		else
		{
			/* visit an index page, extract its items into queue */
			CHECK_FOR_INTERRUPTS();

			gistScanPage(scan, item, item->distances, NULL, NULL);
		}

		pfree(item);
	} while (!res);

	return res;
}
コード例 #13
0
ファイル: btree_gin.c プロジェクト: Marketcircle/postgres
static Datum
leftmostvalue_float4(void)
{
	return Float4GetDatum(-get_float4_infinity());
}
コード例 #14
0
/* ----------------------------------------------------------------
 *		ProcedureCreate
 *
 * Note: allParameterTypes, parameterModes, parameterNames, and proconfig
 * are either arrays of the proper types or NULL.  We declare them Datum,
 * not "ArrayType *", to avoid importing array.h into pg_proc_fn.h.
 * ----------------------------------------------------------------
 */
Oid
ProcedureCreate(const char *procedureName,
				Oid procNamespace,
				bool replace,
				bool returnsSet,
				Oid returnType,
				Oid languageObjectId,
				Oid languageValidator,
				const char *prosrc,
				const char *probin,
				bool isAgg,
				bool isWindowFunc,
				bool security_definer,
				bool isStrict,
				char volatility,
				oidvector *parameterTypes,
				Datum allParameterTypes,
				Datum parameterModes,
				Datum parameterNames,
				List *parameterDefaults,
				Datum proconfig,
				float4 procost,
				float4 prorows)
{
	Oid			retval;
	int			parameterCount;
	int			allParamCount;
	Oid		   *allParams;
	bool		genericInParam = false;
	bool		genericOutParam = false;
	bool		internalInParam = false;
	bool		internalOutParam = false;
	Oid			variadicType = InvalidOid;
	Oid			proowner = GetUserId();
	Relation	rel;
	HeapTuple	tup;
	HeapTuple	oldtup;
	bool		nulls[Natts_pg_proc];
	Datum		values[Natts_pg_proc];
	bool		replaces[Natts_pg_proc];
	Oid			relid;
	NameData	procname;
	TupleDesc	tupDesc;
	bool		is_update;
	ObjectAddress myself,
				referenced;
	int			i;

	/*
	 * sanity checks
	 */
	Assert(PointerIsValid(prosrc));

	parameterCount = parameterTypes->dim1;
	if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS)
		ereport(ERROR,
				(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
				 errmsg_plural("functions cannot have more than %d argument",
							   "functions cannot have more than %d arguments",
							   FUNC_MAX_ARGS,
							   FUNC_MAX_ARGS)));
	/* note: the above is correct, we do NOT count output arguments */

	if (allParameterTypes != PointerGetDatum(NULL))
	{
		/*
		 * We expect the array to be a 1-D OID array; verify that. We don't
		 * need to use deconstruct_array() since the array data is just going
		 * to look like a C array of OID values.
		 */
		ArrayType  *allParamArray = (ArrayType *) DatumGetPointer(allParameterTypes);

		allParamCount = ARR_DIMS(allParamArray)[0];
		if (ARR_NDIM(allParamArray) != 1 ||
			allParamCount <= 0 ||
			ARR_HASNULL(allParamArray) ||
			ARR_ELEMTYPE(allParamArray) != OIDOID)
			elog(ERROR, "allParameterTypes is not a 1-D Oid array");
		allParams = (Oid *) ARR_DATA_PTR(allParamArray);
		Assert(allParamCount >= parameterCount);
		/* we assume caller got the contents right */
	}
	else
	{
		allParamCount = parameterCount;
		allParams = parameterTypes->values;
	}

	/*
	 * Do not allow polymorphic return type unless at least one input argument
	 * is polymorphic.	Also, do not allow return type INTERNAL unless at
	 * least one input argument is INTERNAL.
	 */
	for (i = 0; i < parameterCount; i++)
	{
		switch (parameterTypes->values[i])
		{
			case ANYARRAYOID:
			case ANYELEMENTOID:
			case ANYNONARRAYOID:
			case ANYENUMOID:
				genericInParam = true;
				break;
			case INTERNALOID:
				internalInParam = true;
				break;
		}
	}

	if (allParameterTypes != PointerGetDatum(NULL))
	{
		for (i = 0; i < allParamCount; i++)
		{
			/*
			 * We don't bother to distinguish input and output params here, so
			 * if there is, say, just an input INTERNAL param then we will
			 * still set internalOutParam.	This is OK since we don't really
			 * care.
			 */
			switch (allParams[i])
			{
				case ANYARRAYOID:
				case ANYELEMENTOID:
				case ANYNONARRAYOID:
				case ANYENUMOID:
					genericOutParam = true;
					break;
				case INTERNALOID:
					internalOutParam = true;
					break;
			}
		}
	}

	if ((IsPolymorphicType(returnType) || genericOutParam)
		&& !genericInParam)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
				 errmsg("cannot determine result data type"),
				 errdetail("A function returning a polymorphic type must have at least one polymorphic argument.")));

	if ((returnType == INTERNALOID || internalOutParam) && !internalInParam)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
				 errmsg("unsafe use of pseudo-type \"internal\""),
				 errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));

	/*
	 * don't allow functions of complex types that have the same name as
	 * existing attributes of the type
	 */
	if (parameterCount == 1 &&
		OidIsValid(parameterTypes->values[0]) &&
		(relid = typeidTypeRelid(parameterTypes->values[0])) != InvalidOid &&
		get_attnum(relid, procedureName) != InvalidAttrNumber)
		ereport(ERROR,
				(errcode(ERRCODE_DUPLICATE_COLUMN),
				 errmsg("\"%s\" is already an attribute of type %s",
						procedureName,
						format_type_be(parameterTypes->values[0]))));

	if (parameterModes != PointerGetDatum(NULL))
	{
		/*
		 * We expect the array to be a 1-D CHAR array; verify that. We don't
		 * need to use deconstruct_array() since the array data is just going
		 * to look like a C array of char values.
		 */
		ArrayType  *modesArray = (ArrayType *) DatumGetPointer(parameterModes);
		char	   *modes;

		if (ARR_NDIM(modesArray) != 1 ||
			ARR_DIMS(modesArray)[0] != allParamCount ||
			ARR_HASNULL(modesArray) ||
			ARR_ELEMTYPE(modesArray) != CHAROID)
			elog(ERROR, "parameterModes is not a 1-D char array");
		modes = (char *) ARR_DATA_PTR(modesArray);

		/*
		 * Only the last input parameter can be variadic; if it is, save its
		 * element type.  Errors here are just elog since caller should have
		 * checked this already.
		 */
		for (i = 0; i < allParamCount; i++)
		{
			switch (modes[i])
			{
				case PROARGMODE_IN:
				case PROARGMODE_INOUT:
					if (OidIsValid(variadicType))
						elog(ERROR, "variadic parameter must be last");
					break;
				case PROARGMODE_OUT:
				case PROARGMODE_TABLE:
					/* okay */
					break;
				case PROARGMODE_VARIADIC:
					if (OidIsValid(variadicType))
						elog(ERROR, "variadic parameter must be last");
					switch (allParams[i])
					{
						case ANYOID:
							variadicType = ANYOID;
							break;
						case ANYARRAYOID:
							variadicType = ANYELEMENTOID;
							break;
						default:
							variadicType = get_element_type(allParams[i]);
							if (!OidIsValid(variadicType))
								elog(ERROR, "variadic parameter is not an array");
							break;
					}
					break;
				default:
					elog(ERROR, "invalid parameter mode '%c'", modes[i]);
					break;
			}
		}
	}

	/*
	 * All seems OK; prepare the data to be inserted into pg_proc.
	 */

	for (i = 0; i < Natts_pg_proc; ++i)
	{
		nulls[i] = false;
		values[i] = (Datum) 0;
		replaces[i] = true;
	}

	namestrcpy(&procname, procedureName);
	values[Anum_pg_proc_proname - 1] = NameGetDatum(&procname);
	values[Anum_pg_proc_pronamespace - 1] = ObjectIdGetDatum(procNamespace);
	values[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(proowner);
	values[Anum_pg_proc_prolang - 1] = ObjectIdGetDatum(languageObjectId);
	values[Anum_pg_proc_procost - 1] = Float4GetDatum(procost);
	values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows);
	values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType);
	values[Anum_pg_proc_proisagg - 1] = BoolGetDatum(isAgg);
	values[Anum_pg_proc_proiswindow - 1] = BoolGetDatum(isWindowFunc);
	values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer);
	values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict);
	values[Anum_pg_proc_proretset - 1] = BoolGetDatum(returnsSet);
	values[Anum_pg_proc_provolatile - 1] = CharGetDatum(volatility);
	values[Anum_pg_proc_pronargs - 1] = UInt16GetDatum(parameterCount);
	values[Anum_pg_proc_pronargdefaults - 1] = UInt16GetDatum(list_length(parameterDefaults));
	values[Anum_pg_proc_prorettype - 1] = ObjectIdGetDatum(returnType);
	values[Anum_pg_proc_proargtypes - 1] = PointerGetDatum(parameterTypes);
	if (allParameterTypes != PointerGetDatum(NULL))
		values[Anum_pg_proc_proallargtypes - 1] = allParameterTypes;
	else
		nulls[Anum_pg_proc_proallargtypes - 1] = true;
	if (parameterModes != PointerGetDatum(NULL))
		values[Anum_pg_proc_proargmodes - 1] = parameterModes;
	else
		nulls[Anum_pg_proc_proargmodes - 1] = true;
	if (parameterNames != PointerGetDatum(NULL))
		values[Anum_pg_proc_proargnames - 1] = parameterNames;
	else
		nulls[Anum_pg_proc_proargnames - 1] = true;
	if (parameterDefaults != NIL)
		values[Anum_pg_proc_proargdefaults - 1] = CStringGetTextDatum(nodeToString(parameterDefaults));
	else
		nulls[Anum_pg_proc_proargdefaults - 1] = true;
	values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc);
	if (probin)
		values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin);
	else
		nulls[Anum_pg_proc_probin - 1] = true;
	if (proconfig != PointerGetDatum(NULL))
		values[Anum_pg_proc_proconfig - 1] = proconfig;
	else
		nulls[Anum_pg_proc_proconfig - 1] = true;
	/* start out with empty permissions */
	nulls[Anum_pg_proc_proacl - 1] = true;

	rel = heap_open(ProcedureRelationId, RowExclusiveLock);
	tupDesc = RelationGetDescr(rel);

	/* Check for pre-existing definition */
	oldtup = SearchSysCache(PROCNAMEARGSNSP,
							PointerGetDatum(procedureName),
							PointerGetDatum(parameterTypes),
							ObjectIdGetDatum(procNamespace),
							0);

	if (HeapTupleIsValid(oldtup))
	{
		/* There is one; okay to replace it? */
		Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup);

		if (!replace)
			ereport(ERROR,
					(errcode(ERRCODE_DUPLICATE_FUNCTION),
			errmsg("function \"%s\" already exists with same argument types",
				   procedureName)));
		if (!pg_proc_ownercheck(HeapTupleGetOid(oldtup), proowner))
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
						   procedureName);

		/*
		 * Not okay to change the return type of the existing proc, since
		 * existing rules, views, etc may depend on the return type.
		 */
		if (returnType != oldproc->prorettype ||
			returnsSet != oldproc->proretset)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
					 errmsg("cannot change return type of existing function"),
					 errhint("Use DROP FUNCTION first.")));

		/*
		 * If it returns RECORD, check for possible change of record type
		 * implied by OUT parameters
		 */
		if (returnType == RECORDOID)
		{
			TupleDesc	olddesc;
			TupleDesc	newdesc;

			olddesc = build_function_result_tupdesc_t(oldtup);
			newdesc = build_function_result_tupdesc_d(allParameterTypes,
													  parameterModes,
													  parameterNames);
			if (olddesc == NULL && newdesc == NULL)
				 /* ok, both are runtime-defined RECORDs */ ;
			else if (olddesc == NULL || newdesc == NULL ||
					 !equalTupleDescs(olddesc, newdesc))
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
					errmsg("cannot change return type of existing function"),
				errdetail("Row type defined by OUT parameters is different."),
						 errhint("Use DROP FUNCTION first.")));
		}

		/*
		 * If there are existing defaults, check compatibility: redefinition
		 * must not remove any defaults nor change their types.  (Removing a
		 * default might cause a function to fail to satisfy an existing call.
		 * Changing type would only be possible if the associated parameter is
		 * polymorphic, and in such cases a change of default type might alter
		 * the resolved output type of existing calls.)
		 */
		if (oldproc->pronargdefaults != 0)
		{
			Datum		proargdefaults;
			bool		isnull;
			List	   *oldDefaults;
			ListCell   *oldlc;
			ListCell   *newlc;

			if (list_length(parameterDefaults) < oldproc->pronargdefaults)
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
						 errmsg("cannot remove parameter defaults from existing function"),
						 errhint("Use DROP FUNCTION first.")));

			proargdefaults = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup,
											 Anum_pg_proc_proargdefaults,
											 &isnull);
			Assert(!isnull);
			oldDefaults = (List *) stringToNode(TextDatumGetCString(proargdefaults));
			Assert(IsA(oldDefaults, List));
			Assert(list_length(oldDefaults) == oldproc->pronargdefaults);

			/* new list can have more defaults than old, advance over 'em */
			newlc = list_head(parameterDefaults);
			for (i = list_length(parameterDefaults) - oldproc->pronargdefaults;
				 i > 0;
				 i--)
				newlc = lnext(newlc);

			foreach(oldlc, oldDefaults)
			{
				Node	   *oldDef = (Node *) lfirst(oldlc);
				Node	   *newDef = (Node *) lfirst(newlc);

				if (exprType(oldDef) != exprType(newDef))
					ereport(ERROR,
							(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
							 errmsg("cannot change data type of existing parameter default value"),
							 errhint("Use DROP FUNCTION first.")));
				newlc = lnext(newlc);
			}
		}