/*
 * Create the Datum/isnull representation of an expanded array object
 * if we didn't do so previously
 */
void
deconstruct_expanded_array(ExpandedArrayHeader *eah)
{
	if (eah->dvalues == NULL)
	{
		MemoryContext oldcxt = MemoryContextSwitchTo(eah->hdr.eoh_context);
		Datum	   *dvalues;
		bool	   *dnulls;
		int			nelems;

		dnulls = NULL;
		deconstruct_array(eah->fvalue,
						  eah->element_type,
						  eah->typlen, eah->typbyval, eah->typalign,
						  &dvalues,
						  ARR_HASNULL(eah->fvalue) ? &dnulls : NULL,
						  &nelems);

		/*
		 * Update header only after successful completion of this step.  If
		 * deconstruct_array fails partway through, worst consequence is some
		 * leaked memory in the object's context.  If the caller fails at a
		 * later point, that's fine, since the deconstructed representation is
		 * valid anyhow.
		 */
		eah->dvalues = dvalues;
		eah->dnulls = dnulls;
		eah->dvalueslen = eah->nelems = nelems;
		MemoryContextSwitchTo(oldcxt);
	}
}
示例#2
0
static jvalue _doubleArray_coerceDatum(Type self, Datum arg)
{
	jvalue     result;
	ArrayType* v      = DatumGetArrayTypeP(arg);
	jsize      nElems = (jsize)ArrayGetNItems(ARR_NDIM(v), ARR_DIMS(v));
	jdoubleArray doubleArray = JNI_newDoubleArray(nElems);

#if (PGSQL_MAJOR_VER == 8 && PGSQL_MINOR_VER < 2)
	JNI_setDoubleArrayRegion(doubleArray, 0, nElems, (jdouble*)ARR_DATA_PTR(v));
#else
	if(ARR_HASNULL(v))
	{
		jsize idx;
		jboolean isCopy = JNI_FALSE;
		bits8* nullBitMap = ARR_NULLBITMAP(v);
		jdouble* values = (jdouble*)ARR_DATA_PTR(v);
		jdouble* elems  = JNI_getDoubleArrayElements(doubleArray, &isCopy);
		for(idx = 0; idx < nElems; ++idx)
		{
			if(arrayIsNull(nullBitMap, idx))
				elems[idx] = 0;
			else
				elems[idx] = *values++;
		}
		JNI_releaseDoubleArrayElements(doubleArray, elems, JNI_COMMIT);
	}
	else
		JNI_setDoubleArrayRegion(doubleArray, 0, nElems, (jdouble*)ARR_DATA_PTR(v));
#endif
	result.l = (jobject)doubleArray;
	return result;
}
示例#3
0
Datum pcpoint_from_double_array(PG_FUNCTION_ARGS)
{
	uint32 pcid = PG_GETARG_INT32(0);
	ArrayType *arrptr = PG_GETARG_ARRAYTYPE_P(1);
	int nelems;
	float8 *vals;
	PCPOINT *pt;
	PCSCHEMA *schema = pc_schema_from_pcid(pcid, fcinfo);
	SERIALIZED_POINT *serpt;

	if ( ! schema )
		elog(ERROR, "unable to load schema for pcid = %d", pcid);

	if ( ARR_ELEMTYPE(arrptr) != FLOAT8OID )
		elog(ERROR, "array must be of float8[]");

	if ( ARR_NDIM(arrptr) != 1 )
		elog(ERROR, "float8[] must have only one dimension");

	if ( ARR_HASNULL(arrptr) )
		elog(ERROR, "float8[] must not have null elements");

	nelems = ARR_DIMS(arrptr)[0];
	if ( nelems != schema->ndims || ARR_LBOUND(arrptr)[0] > 1 )
		elog(ERROR, "array dimensions do not match schema dimensions of pcid = %d", pcid);

	vals = (float8*) ARR_DATA_PTR(arrptr);
	pt = pc_point_from_double_array(schema, vals, nelems);

	serpt = pc_point_serialize(pt);
	pc_point_free(pt);
	PG_RETURN_POINTER(serpt);
}
示例#4
0
文件: Boolean.c 项目: AnLingm/gpdb
static jvalue _booleanArray_coerceDatum(Type self, Datum arg)
{
	jvalue     result;
	ArrayType* v      = DatumGetArrayTypeP(arg);
	jsize      nElems = (jsize)ArrayGetNItems(ARR_NDIM(v), ARR_DIMS(v));
	jbooleanArray booleanArray = JNI_newBooleanArray(nElems);

	if(ARR_HASNULL(v))
	{
		jsize idx;
		jboolean isCopy = JNI_FALSE;
		bits8* nullBitMap = ARR_NULLBITMAP(v);
		jboolean* values = (jboolean*)ARR_DATA_PTR(v);
		jboolean* elems  = JNI_getBooleanArrayElements(booleanArray, &isCopy);
		for(idx = 0; idx < nElems; ++idx)
		{
			if(arrayIsNull(nullBitMap, idx))
				elems[idx] = 0;
			else
				elems[idx] = *values++;
		}
		JNI_releaseBooleanArrayElements(booleanArray, elems, JNI_COMMIT);
	}
	else
		JNI_setBooleanArrayRegion(booleanArray, 0, nElems, (jboolean*)ARR_DATA_PTR(v));
	result.l = (jobject)booleanArray;
	return result;
}
示例#5
0
static bool
array_iterator(ArrayType *la, PGCALL2 callback, void *param, ltree **found)
{
	int			num = ArrayGetNItems(ARR_NDIM(la), ARR_DIMS(la));
	ltree	   *item = (ltree *) ARR_DATA_PTR(la);

	if (ARR_NDIM(la) > 1)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("array must be one-dimensional")));
	if (ARR_HASNULL(la))
		ereport(ERROR,
				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
				 errmsg("array must not contain nulls")));

	if (found)
		*found = NULL;
	while (num > 0)
	{
		if (DatumGetBool(DirectFunctionCall2(callback,
							 PointerGetDatum(item), PointerGetDatum(param))))
		{

			if (found)
				*found = item;
			return true;
		}
		num--;
		item = NEXTVAL(item);
	}

	return false;
}
示例#6
0
Datum
_lca(PG_FUNCTION_ARGS)
{
	ArrayType  *la = PG_GETARG_ARRAYTYPE_P(0);
	int			num = ArrayGetNItems(ARR_NDIM(la), ARR_DIMS(la));
	ltree	   *item = (ltree *) ARR_DATA_PTR(la);
	ltree	  **a,
			   *res;

	if (ARR_NDIM(la) > 1)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("array must be one-dimensional")));
	if (ARR_HASNULL(la))
		ereport(ERROR,
				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
				 errmsg("array must not contain nulls")));

	a = (ltree **) palloc(sizeof(ltree *) * num);
	while (num > 0)
	{
		num--;
		a[num] = item;
		item = NEXTVAL(item);
	}
	res = lca_inner(a, ArrayGetNItems(ARR_NDIM(la), ARR_DIMS(la)));
	pfree(a);

	PG_FREE_IF_COPY(la, 0);

	if (res)
		PG_RETURN_POINTER(res);
	else
		PG_RETURN_NULL();
}
示例#7
0
Datum
_lt_q_regex(PG_FUNCTION_ARGS)
{
	ArrayType  *_tree = PG_GETARG_ARRAYTYPE_P(0);
	ArrayType  *_query = PG_GETARG_ARRAYTYPE_P(1);
	lquery	   *query = (lquery *) ARR_DATA_PTR(_query);
	bool		res = false;
	int			num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));

	if (ARR_NDIM(_query) > 1)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("array must be one-dimensional")));
	if (ARR_HASNULL(_query))
		ereport(ERROR,
				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
				 errmsg("array must not contain nulls")));

	while (num > 0)
	{
		if (array_iterator(_tree, ltq_regex, (void *) query, NULL))
		{
			res = true;
			break;
		}
		num--;
		query = (lquery *) NEXTVAL(query);
	}

	PG_FREE_IF_COPY(_tree, 0);
	PG_FREE_IF_COPY(_query, 1);
	PG_RETURN_BOOL(res);
}
示例#8
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);
}
示例#9
0
/*
** Allows the construction of a cube from 2 float[]'s
*/
Datum
cube_a_f8_f8(PG_FUNCTION_ARGS)
{
	int			i;
	int			dim;
	int			size;
	NDBOX	   *result;
	ArrayType  *ur,
			   *ll;
	double	   *dur,
			   *dll;

	ur = (ArrayType *) PG_GETARG_VARLENA_P(0);
	ll = (ArrayType *) PG_GETARG_VARLENA_P(1);

	if (ARR_HASNULL(ur) || ARR_HASNULL(ll))
	{
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
				 errmsg("Cannot work with NULL arrays")));
	}

	dim = ARRNELEMS(ur);
	if (ARRNELEMS(ll) != dim)
	{
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
				 errmsg("UR and LL arrays must be of same length")));
	}

	dur = ARRPTR(ur);
	dll = ARRPTR(ll);

	size = offsetof(NDBOX, x[0]) + sizeof(double) * 2 * dim;
	result = (NDBOX *) palloc(size);
	memset(result, 0, size);
	result->size = size;
	result->dim = dim;

	for (i = 0; i < dim; i++)
	{
		result->x[i] = dur[i];
		result->x[i + dim] = dll[i];
	}

	PG_RETURN_NDBOX(result);
}
/**
 * Convert postgres Datum into a ConcreteValue object.
 */
AbstractValueSPtr AbstractPGValue::DatumToValue(bool inMemoryIsWritable,
    Oid inTypeID, Datum inDatum) const {
        
    // First check if datum is rowtype
    if (type_is_rowtype(inTypeID)) {
        HeapTupleHeader pgTuple = DatumGetHeapTupleHeader(inDatum);
        return AbstractValueSPtr(new PGValue<HeapTupleHeader>(pgTuple));
    } else if (type_is_array(inTypeID)) {
        ArrayType *pgArray = DatumGetArrayTypeP(inDatum);
        
        if (ARR_NDIM(pgArray) != 1)
            throw std::invalid_argument("Multidimensional arrays not yet supported");
        
        if (ARR_HASNULL(pgArray))
            throw std::invalid_argument("Arrays with NULLs not yet supported");
        
        switch (ARR_ELEMTYPE(pgArray)) {
            case FLOAT8OID: {
                MemHandleSPtr memoryHandle(new PGArrayHandle(pgArray));
                
                if (inMemoryIsWritable) {
                    return AbstractValueSPtr(
                        new ConcreteValue<Array<double> >(
                            Array<double>(memoryHandle,
                                boost::extents[ ARR_DIMS(pgArray)[0] ])
                            )
                        );
                } else {
                    return AbstractValueSPtr(
                        new ConcreteValue<Array_const<double> >(
                            Array_const<double>(memoryHandle,
                                boost::extents[ ARR_DIMS(pgArray)[0] ])
                            )
                        );
                }
            }
        }
    }

    switch (inTypeID) {
        case BOOLOID: return AbstractValueSPtr(
            new ConcreteValue<bool>( DatumGetBool(inDatum) ));
        case INT2OID: return AbstractValueSPtr(
            new ConcreteValue<int16_t>( DatumGetInt16(inDatum) ));
        case INT4OID: return AbstractValueSPtr(
            new ConcreteValue<int32_t>( DatumGetInt32(inDatum) ));
        case INT8OID: return AbstractValueSPtr(
            new ConcreteValue<int64_t>( DatumGetInt64(inDatum) ));
        case FLOAT4OID: return AbstractValueSPtr(
            new ConcreteValue<float>( DatumGetFloat4(inDatum) ));
        case FLOAT8OID: return AbstractValueSPtr(
            new ConcreteValue<double>( DatumGetFloat8(inDatum) ));
    }
    
    return AbstractValueSPtr();
}
示例#11
0
/*
 * ex_avg() - an enhanced average calculation that takes two arguments;
 * number of rows in this group and partial sum of the value.
 * Then, it eventually generate mathmatically compatible average value.
 */
static int64 *
check_int64_array(ArrayType *transarray, int n)
{
	if (ARR_NDIM(transarray) != 1 ||
		ARR_DIMS(transarray)[0] != n ||
		ARR_HASNULL(transarray) ||
		ARR_ELEMTYPE(transarray) != INT8OID)
		elog(ERROR, "Two elements int8 array is expected");
	return (int64 *) ARR_DATA_PTR(transarray);
}
示例#12
0
static PyObj
array_has_null(PyObj self, void *closure)
{
	PyObj rob;

	if (ARR_HASNULL(DatumGetArrayTypeP(PyPgObject_GetDatum(self))))
		rob = Py_True;
	else
		rob = Py_False;

	Py_INCREF(rob);
	return(rob);
}
示例#13
0
Datum
rank_cd(PG_FUNCTION_ARGS)
{
	ArrayType  *win;
	tsvector   *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
	QUERYTYPE  *query = (QUERYTYPE *) PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(2));
	int			method = DEF_NORM_METHOD;
	float4		res;

	/*
	 * Pre-8.2, rank_cd took just a plain int as its first argument.
	 * It was a mistake to keep the same C function name while changing the
	 * signature, but it's too late to fix that.  Instead, do a runtime test
	 * to make sure the expected datatype has been passed.  This is needed
	 * to prevent core dumps if tsearch2 function definitions from an old
	 * database are loaded into an 8.2 server.
	 */
	if (get_fn_expr_argtype(fcinfo->flinfo, 0) != FLOAT4ARRAYOID)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
				 errmsg("rank_cd() now takes real[] as its first argument, not integer")));

	/* now safe to dereference the first arg */
	win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));

	if (ARR_NDIM(win) != 1)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("array of weight must be one-dimensional")));

	if (ARRNELEMS(win) < lengthof(weights))
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("array of weight is too short")));

	if (ARR_HASNULL(win))
		ereport(ERROR,
				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
				 errmsg("array of weight must not contain nulls")));

	if (PG_NARGS() == 4)
		method = PG_GETARG_INT32(3);

	res = calc_rank_cd((float4 *) ARR_DATA_PTR(win), txt, query, method);

	PG_FREE_IF_COPY(win, 0);
	PG_FREE_IF_COPY(txt, 1);
	PG_FREE_IF_COPY(query, 2);

	PG_RETURN_FLOAT4(res);
}
示例#14
0
/* logic copied from utils/adt/float.c */
static inline float8 *
check_float8_array(ArrayType *transarray, int nitems)
{
	/*
	 * We expect the input to be an N-element float 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 N float8 values.
	 */
	if (ARR_NDIM(transarray) != 1 ||
		ARR_DIMS(transarray)[0] != nitems ||
		ARR_HASNULL(transarray) ||
		ARR_ELEMTYPE(transarray) != FLOAT8OID)
		elog(ERROR, "%d-elements float8 array is expected", nitems);
	return (float8 *) ARR_DATA_PTR(transarray);
}
示例#15
0
Datum
rank(PG_FUNCTION_ARGS)
{
	ArrayType  *win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
	tsvector   *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
	QUERYTYPE  *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(2));
	int			method = DEF_NORM_METHOD;
	float		res = 0.0;
	float		ws[lengthof(weights)];
	float4	   *arrdata;
	int			i;

	if (ARR_NDIM(win) != 1)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("array of weight must be one-dimensional")));

	if (ARRNELEMS(win) < lengthof(weights))
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("array of weight is too short")));

	if (ARR_HASNULL(win))
		ereport(ERROR,
				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
				 errmsg("array of weight must not contain nulls")));

	arrdata = (float4 *) ARR_DATA_PTR(win);
	for (i = 0; i < lengthof(weights); i++)
	{
		ws[i] = (arrdata[i] >= 0) ? arrdata[i] : weights[i];
		if (ws[i] > 1.0)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("weight out of range")));
	}

	if (PG_NARGS() == 4)
		method = PG_GETARG_INT32(3);

	res = calc_rank(ws, txt, query, method);

	PG_FREE_IF_COPY(win, 0);
	PG_FREE_IF_COPY(txt, 1);
	PG_FREE_IF_COPY(query, 2);
	PG_RETURN_FLOAT4(res);
}
示例#16
0
Datum
cube_subset(PG_FUNCTION_ARGS)
{
	NDBOX	   *c,
			   *result;
	ArrayType  *idx;
	int			size,
				dim,
				i;
	int		   *dx;

	c = PG_GETARG_NDBOX(0);
	idx = (ArrayType *) PG_GETARG_VARLENA_P(1);

	if (ARR_HASNULL(idx))
	{
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
				 errmsg("Cannot work with NULL arrays")));
	}

	dx = (int4 *) ARR_DATA_PTR(idx);

	dim = ARRNELEMS(idx);
	size = offsetof(NDBOX, x[0]) + sizeof(double) * 2 * dim;
	result = (NDBOX *) palloc(size);
	memset(result, 0, size);
	result->size = size;
	result->dim = dim;

	for (i = 0; i < dim; i++)
	{
		if ((dx[i] <= 0) || (dx[i] > c->dim))
		{
			pfree(result);
			ereport(ERROR,
					(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
					 errmsg("Index out of bounds")));
		}
		result->x[i] = c->x[dx[i] - 1];
		result->x[i + dim] = c->x[dx[i] + c->dim - 1];
	}

	PG_FREE_IF_COPY(c,0);
	PG_RETURN_NDBOX(result);
}
示例#17
0
文件: int.c 项目: colinet/sqlix
/*
 *		int2vectorrecv			- converts external binary format to int2_vector_s
 */
datum_t int2vectorrecv(PG_FUNC_ARGS)
{
	struct string* buf = (struct string*) ARG_POINTER(0);
	struct fc_info locfcinfo;
	int2_vector_s *result;

	/*
	 * Normally one would call array_recv() using DIRECT_FC3, 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.
	 */
	INIT_FC_INFO(locfcinfo, fcinfo->flinfo, 3, INVALID_OID, NULL, NULL);

	locfcinfo.arg[0] = PTR_TO_D(buf);
	locfcinfo.arg[1] = OID_TO_D(INT2OID);
	locfcinfo.arg[2] = INT32_TO_D(-1);

	locfcinfo.argnull[0] = false;
	locfcinfo.argnull[1] = false;
	locfcinfo.argnull[2] = false;

	result = (int2_vector_s *) D_TO_PTR(array_recv(&locfcinfo));

	ASSERT(!locfcinfo.isnull);

	/* sanity checks: int2_vector_s 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(E_INVALID_BINARY_REPRESENTATION),
		errmsg("invalid int2_vector_s data")));
	}

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

	RET_POINTER(result);
}
示例#18
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);
}
示例#19
0
Datum pc_typmod_in(PG_FUNCTION_ARGS)
{
	uint32 typmod = 0;
	Datum *elem_values;
	int n = 0;
	int i = 0;
	ArrayType *arr = (ArrayType *) DatumGetPointer(PG_GETARG_DATUM(0));

	if (ARR_ELEMTYPE(arr) != CSTRINGOID)
		ereport(ERROR,
		        (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
		         errmsg("typmod array must be type cstring[]")));

	if (ARR_NDIM(arr) != 1)
		ereport(ERROR,
		        (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
		         errmsg("typmod array must be one-dimensional")));

	if (ARR_HASNULL(arr))
		ereport(ERROR,
		        (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
		         errmsg("typmod array must not contain nulls")));

	if (ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr)) > 1)
		ereport(ERROR,
		        (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
		         errmsg("typmod array must have one element")));

	deconstruct_array(arr,
	                  CSTRINGOID, -2, false, 'c', /* hardwire cstring representation details */
	                  &elem_values, NULL, &n);

	for (i = 0; i < n; i++)
	{
		if ( i == 0 ) /* PCID */
		{
			char *s = DatumGetCString(elem_values[i]);
			typmod = pg_atoi(s, sizeof(int32), '\0');
		}
	}

	PG_RETURN_INT32(typmod);
}
示例#20
0
/*
 * Decode text[] to an array of C strings.
 *
 * We could avoid a bit of overhead here if we were willing to duplicate some
 * of the logic from deconstruct_array, but it doesn't seem worth the code
 * complexity.
 */
static int
DecodeTextArrayToCString(Datum array, char ***cstringp)
{
    ArrayType  *arr = DatumGetArrayTypeP(array);
    Datum	   *elems;
    char	  **cstring;
    int			i;
    int			nelems;

    if (ARR_NDIM(arr) != 1 || ARR_HASNULL(arr) || ARR_ELEMTYPE(arr) != TEXTOID)
        elog(ERROR, "expected 1-D text array");
    deconstruct_array(arr, TEXTOID, -1, false, 'i', &elems, NULL, &nelems);

    cstring = palloc(nelems * sizeof(char *));
    for (i = 0; i < nelems; ++i)
        cstring[i] = TextDatumGetCString(elems[i]);

    pfree(elems);
    *cstringp = cstring;
    return nelems;
}
示例#21
0
/*
 * get_func_trftypes
 *
 * Returns a number of transformated types used by function.
 */
int
get_func_trftypes(HeapTuple procTup,
				  Oid **p_trftypes)
{

	Datum		protrftypes;
	ArrayType  *arr;
	int			nelems;
	bool			isNull;

	protrftypes = SysCacheGetAttr(PROCOID, procTup,
									 Anum_pg_proc_protrftypes,
									 &isNull);
	if (!isNull)
	{
		/*
		 * We expect the arrays to be 1-D arrays of the right types; verify
		 * that.  For the OID and char arrays, we don't need to use
		 * deconstruct_array() since the array data is just going to look like
		 * a C array of values.
		 */
		arr = DatumGetArrayTypeP(protrftypes);		/* ensure not toasted */
		nelems = ARR_DIMS(arr)[0];
		if (ARR_NDIM(arr) != 1 ||
			nelems < 0 ||
			ARR_HASNULL(arr) ||
			ARR_ELEMTYPE(arr) != OIDOID)
			elog(ERROR, "protrftypes is not a 1-D Oid array");
		Assert(nelems >= ((Form_pg_proc) GETSTRUCT(procTup))->pronargs);
		*p_trftypes = (Oid *) palloc(nelems * sizeof(Oid));
		memcpy(*p_trftypes, ARR_DATA_PTR(arr),
			   nelems * sizeof(Oid));

		return nelems;
	}
	else
		return 0;
}
示例#22
0
文件: arrayutils.c 项目: AnLingm/gpdb
/*
 * ArrayGetIntegerTypmods: verify that argument is a 1-D cstring array,
 * and get the contents converted to integers.	Returns a palloc'd array
 * and places the length at *n.
 */
int32 *
ArrayGetIntegerTypmods(ArrayType *arr, int *n)
{
	int32	   *result;
	Datum	   *elem_values;
	int			i;

	if (ARR_ELEMTYPE(arr) != CSTRINGOID)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
				 errmsg("typmod array must be type cstring[]")));

	if (ARR_NDIM(arr) != 1)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("typmod array must be one-dimensional")));

	if (ARR_HASNULL(arr))
		ereport(ERROR,
				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
				 errmsg("typmod array must not contain nulls")));

	/* hardwired knowledge about cstring's representation details here */
	deconstruct_array(arr, CSTRINGOID,
					  -2, false, 'c',
					  &elem_values, NULL, n);

	result = (int32 *) palloc(*n * sizeof(int32));

	for (i = 0; i < *n; i++)
		result[i] = pg_atoi(DatumGetCString(elem_values[i]),
							sizeof(int32), '\0');

	pfree(elem_values);

	return result;
}
static float *
getWeights(ArrayType *win)
{
	static float ws[lengthof(weights)];
	int			i;
	float4	   *arrdata;

	if (win == 0)
		return weights;

	if (ARR_NDIM(win) != 1)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("array of weight must be one-dimensional")));

	if (ArrayGetNItems(ARR_NDIM(win), ARR_DIMS(win)) < lengthof(weights))
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("array of weight is too short")));

	if (ARR_HASNULL(win))
		ereport(ERROR,
				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
				 errmsg("array of weight must not contain nulls")));

	arrdata = (float4 *) ARR_DATA_PTR(win);
	for (i = 0; i < lengthof(weights); i++)
	{
		ws[i] = (arrdata[i] >= 0) ? arrdata[i] : weights[i];
		if (ws[i] > 1.0)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("weight out of range")));
	}

	return ws;
}
示例#24
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);
			}
		}
示例#25
0
/*-----------------------------------------------------------------------------
 * array_cat :
 *		concatenate two nD arrays to form an nD array, or
 *		push an (n-1)D array onto the end of an nD array
 *----------------------------------------------------------------------------
 */
Datum
array_cat(PG_FUNCTION_ARGS)
{
	ArrayType  *v1,
			   *v2;
	ArrayType  *result;
	int		   *dims,
			   *lbs,
				ndims,
				nitems,
				ndatabytes,
				nbytes;
	int		   *dims1,
			   *lbs1,
				ndims1,
				nitems1,
				ndatabytes1;
	int		   *dims2,
			   *lbs2,
				ndims2,
				nitems2,
				ndatabytes2;
	int			i;
	char	   *dat1,
			   *dat2;
	bits8	   *bitmap1,
			   *bitmap2;
	Oid			element_type;
	Oid			element_type1;
	Oid			element_type2;
	int32		dataoffset;

	/* Concatenating a null array is a no-op, just return the other input */
	if (PG_ARGISNULL(0))
	{
		if (PG_ARGISNULL(1))
			PG_RETURN_NULL();
		result = PG_GETARG_ARRAYTYPE_P(1);
		PG_RETURN_ARRAYTYPE_P(result);
	}
	if (PG_ARGISNULL(1))
	{
		result = PG_GETARG_ARRAYTYPE_P(0);
		PG_RETURN_ARRAYTYPE_P(result);
	}

	v1 = PG_GETARG_ARRAYTYPE_P(0);
	v2 = PG_GETARG_ARRAYTYPE_P(1);

	element_type1 = ARR_ELEMTYPE(v1);
	element_type2 = ARR_ELEMTYPE(v2);

	/* Check we have matching element types */
	if (element_type1 != element_type2)
		ereport(ERROR,
				(errcode(ERRCODE_DATATYPE_MISMATCH),
				 errmsg("cannot concatenate incompatible arrays"),
				 errdetail("Arrays with element types %s and %s are not "
						   "compatible for concatenation.",
						   format_type_be(element_type1),
						   format_type_be(element_type2))));

	/* OK, use it */
	element_type = element_type1;

	/*----------
	 * We must have one of the following combinations of inputs:
	 * 1) one empty array, and one non-empty array
	 * 2) both arrays empty
	 * 3) two arrays with ndims1 == ndims2
	 * 4) ndims1 == ndims2 - 1
	 * 5) ndims1 == ndims2 + 1
	 *----------
	 */
	ndims1 = ARR_NDIM(v1);
	ndims2 = ARR_NDIM(v2);

	/*
	 * short circuit - if one input array is empty, and the other is not, we
	 * return the non-empty one as the result
	 *
	 * if both are empty, return the first one
	 */
	if (ndims1 == 0 && ndims2 > 0)
		PG_RETURN_ARRAYTYPE_P(v2);

	if (ndims2 == 0)
		PG_RETURN_ARRAYTYPE_P(v1);

	/* the rest fall under rule 3, 4, or 5 */
	if (ndims1 != ndims2 &&
		ndims1 != ndims2 - 1 &&
		ndims1 != ndims2 + 1)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("cannot concatenate incompatible arrays"),
				 errdetail("Arrays of %d and %d dimensions are not "
						   "compatible for concatenation.",
						   ndims1, ndims2)));

	/* get argument array details */
	lbs1 = ARR_LBOUND(v1);
	lbs2 = ARR_LBOUND(v2);
	dims1 = ARR_DIMS(v1);
	dims2 = ARR_DIMS(v2);
	dat1 = ARR_DATA_PTR(v1);
	dat2 = ARR_DATA_PTR(v2);
	bitmap1 = ARR_NULLBITMAP(v1);
	bitmap2 = ARR_NULLBITMAP(v2);
	nitems1 = ArrayGetNItems(ndims1, dims1);
	nitems2 = ArrayGetNItems(ndims2, dims2);
	ndatabytes1 = ARR_SIZE(v1) - ARR_DATA_OFFSET(v1);
	ndatabytes2 = ARR_SIZE(v2) - ARR_DATA_OFFSET(v2);

	if (ndims1 == ndims2)
	{
		/*
		 * resulting array is made up of the elements (possibly arrays
		 * themselves) of the input argument arrays
		 */
		ndims = ndims1;
		dims = (int *) palloc(ndims * sizeof(int));
		lbs = (int *) palloc(ndims * sizeof(int));

		dims[0] = dims1[0] + dims2[0];
		lbs[0] = lbs1[0];

		for (i = 1; i < ndims; i++)
		{
			if (dims1[i] != dims2[i] || lbs1[i] != lbs2[i])
				ereport(ERROR,
						(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
						 errmsg("cannot concatenate incompatible arrays"),
					errdetail("Arrays with differing element dimensions are "
							  "not compatible for concatenation.")));

			dims[i] = dims1[i];
			lbs[i] = lbs1[i];
		}
	}
	else if (ndims1 == ndims2 - 1)
	{
		/*
		 * resulting array has the second argument as the outer array, with
		 * the first argument inserted at the front of the outer dimension
		 */
		ndims = ndims2;
		dims = (int *) palloc(ndims * sizeof(int));
		lbs = (int *) palloc(ndims * sizeof(int));
		memcpy(dims, dims2, ndims * sizeof(int));
		memcpy(lbs, lbs2, ndims * sizeof(int));

		/* increment number of elements in outer array */
		dims[0] += 1;

		/* make sure the added element matches our existing elements */
		for (i = 0; i < ndims1; i++)
		{
			if (dims1[i] != dims[i + 1] || lbs1[i] != lbs[i + 1])
				ereport(ERROR,
						(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
						 errmsg("cannot concatenate incompatible arrays"),
						 errdetail("Arrays with differing dimensions are not "
								   "compatible for concatenation.")));
		}
	}
	else
	{
		/*
		 * (ndims1 == ndims2 + 1)
		 *
		 * resulting array has the first argument as the outer array, with the
		 * second argument appended to the end of the outer dimension
		 */
		ndims = ndims1;
		dims = (int *) palloc(ndims * sizeof(int));
		lbs = (int *) palloc(ndims * sizeof(int));
		memcpy(dims, dims1, ndims * sizeof(int));
		memcpy(lbs, lbs1, ndims * sizeof(int));

		/* increment number of elements in outer array */
		dims[0] += 1;

		/* make sure the added element matches our existing elements */
		for (i = 0; i < ndims2; i++)
		{
			if (dims2[i] != dims[i + 1] || lbs2[i] != lbs[i + 1])
				ereport(ERROR,
						(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
						 errmsg("cannot concatenate incompatible arrays"),
						 errdetail("Arrays with differing dimensions are not "
								   "compatible for concatenation.")));
		}
	}

	/* Do this mainly for overflow checking */
	nitems = ArrayGetNItems(ndims, dims);

	/* build the result array */
	ndatabytes = ndatabytes1 + ndatabytes2;
	if (ARR_HASNULL(v1) || ARR_HASNULL(v2))
	{
		dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
		nbytes = ndatabytes + dataoffset;
	}
	else
	{
		dataoffset = 0;			/* marker for no null bitmap */
		nbytes = ndatabytes + ARR_OVERHEAD_NONULLS(ndims);
	}
	result = (ArrayType *) palloc(nbytes);
	SET_VARSIZE(result, nbytes);
	result->ndim = ndims;
	result->dataoffset = dataoffset;
	result->elemtype = element_type;
	memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
	memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
	/* data area is arg1 then arg2 */
	memcpy(ARR_DATA_PTR(result), dat1, ndatabytes1);
	memcpy(ARR_DATA_PTR(result) + ndatabytes1, dat2, ndatabytes2);
	/* handle the null bitmap if needed */
	if (ARR_HASNULL(result))
	{
		array_bitmap_copy(ARR_NULLBITMAP(result), 0,
						  bitmap1, 0,
						  nitems1);
		array_bitmap_copy(ARR_NULLBITMAP(result), nitems1,
						  bitmap2, 0,
						  nitems2);
	}

	PG_RETURN_ARRAYTYPE_P(result);
}
示例#26
0
/*
 * Determine whether a relation can be proven functionally dependent on
 * a set of grouping columns.  If so, return TRUE and add the pg_constraint
 * OIDs of the constraints needed for the proof to the *constraintDeps list.
 *
 * grouping_columns is a list of grouping expressions, in which columns of
 * the rel of interest are Vars with the indicated varno/varlevelsup.
 *
 * Currently we only check to see if the rel has a primary key that is a
 * subset of the grouping_columns.  We could also use plain unique constraints
 * if all their columns are known not null, but there's a problem: we need
 * to be able to represent the not-null-ness as part of the constraints added
 * to *constraintDeps.  FIXME whenever not-null constraints get represented
 * in pg_constraint.
 */
bool
check_functional_grouping(Oid relid,
						  Index varno, Index varlevelsup,
						  List *grouping_columns,
						  List **constraintDeps)
{
	bool		result = false;
	Relation	pg_constraint;
	HeapTuple	tuple;
	SysScanDesc scan;
	ScanKeyData skey[1];

	/* Scan pg_constraint for constraints of the target rel */
	pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);

	ScanKeyInit(&skey[0],
				Anum_pg_constraint_conrelid,
				BTEqualStrategyNumber, F_OIDEQ,
				ObjectIdGetDatum(relid));

	scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
							  NULL, 1, skey);

	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
	{
		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
		Datum		adatum;
		bool		isNull;
		ArrayType  *arr;
		int16	   *attnums;
		int			numkeys;
		int			i;
		bool		found_col;

		/* Only PK constraints are of interest for now, see comment above */
		if (con->contype != CONSTRAINT_PRIMARY)
			continue;
		/* Constraint must be non-deferrable */
		if (con->condeferrable)
			continue;

		/* Extract the conkey array, ie, attnums of PK's columns */
		adatum = heap_getattr(tuple, Anum_pg_constraint_conkey,
							  RelationGetDescr(pg_constraint), &isNull);
		if (isNull)
			elog(ERROR, "null conkey for constraint %u",
				 HeapTupleGetOid(tuple));
		arr = DatumGetArrayTypeP(adatum);		/* ensure not toasted */
		numkeys = ARR_DIMS(arr)[0];
		if (ARR_NDIM(arr) != 1 ||
			numkeys < 0 ||
			ARR_HASNULL(arr) ||
			ARR_ELEMTYPE(arr) != INT2OID)
			elog(ERROR, "conkey is not a 1-D smallint array");
		attnums = (int16 *) ARR_DATA_PTR(arr);

		found_col = false;
		for (i = 0; i < numkeys; i++)
		{
			AttrNumber	attnum = attnums[i];
			ListCell   *gl;

			found_col = false;
			foreach(gl, grouping_columns)
			{
				Var		   *gvar = (Var *) lfirst(gl);

				if (IsA(gvar, Var) &&
					gvar->varno == varno &&
					gvar->varlevelsup == varlevelsup &&
					gvar->varattno == attnum)
				{
					found_col = true;
					break;
				}
			}
			if (!found_col)
				break;
		}

		if (found_col)
		{
			/* The PK is a subset of grouping_columns, so we win */
			*constraintDeps = lappend_oid(*constraintDeps,
										  HeapTupleGetOid(tuple));
			result = true;
			break;
		}
	}
示例#27
0
Datum kc_delete(PG_FUNCTION_ARGS) {
    
    char       *map_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
    char       *start_time = text_to_cstring(PG_GETARG_TEXT_PP(1));
    ArrayType  *rids = PG_GETARG_ARRAYTYPE_P(2);
    int        i;
    Datum      *rid_datums;
    bool       *rid_nulls;
    int        rid_count;
    char       *next_rid;
    KCDB       *main_db;
    char       *vbuf;
    size_t      vsiz;
    int64_t     num_keys_to_run;
    int64_t     num_keys_deleted;
    char        **keys_to_use;
    Cloudflare__ZoneTimeBucket *msg_new;

    // Open our DB.
    main_db = kcdbnew();
    if (!open_db (main_db, map_name, start_time)) {
        PG_RETURN_INT64(0);
    }
    kcdbbegintran (main_db, 0);

    // Now run over the array.
    deconstruct_array(rids, TEXTOID, -1, false, 'i',
                      &rid_datums, &rid_nulls, &rid_count);
    if (ARR_HASNULL(rids)) {
        ereport(ERROR,
                (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
                 errmsg("cannot work with arrays containing NULLs")));
    }

    keys_to_use = (char **)palloc(KC_MAX_ENTRIES_PER_RID * sizeof(char));
    num_keys_deleted = 0;
    char prefixes_to_use[rid_count][KC_MAX_RID];

    for (i = 0; i < rid_count; i++) {
        next_rid = TextDatumGetCString(rid_datums[i]);
        snprintf(prefixes_to_use[i], KC_MAX_RID, "%s%s", next_rid, CF_LABEL_SEP);
        num_keys_to_run = kcdbmatchprefix (main_db,	prefixes_to_use[i], keys_to_use, KC_MAX_ENTRIES_PER_RID);
        if (num_keys_to_run != -1) {
            num_keys_deleted += num_keys_to_run;
            int next_key;
            for (next_key=0; next_key < num_keys_to_run; next_key++) {
                vbuf = kcdbget(main_db, keys_to_use[next_key], strlen(keys_to_use[next_key]), &vsiz);
                if (vbuf) {
                    msg_new = cloudflare__zone_time_bucket__unpack(NULL, vsiz, (const uint8_t *)vbuf);
                    if (msg_new == NULL) {   // Something failed
                        ereport(ERROR,
                                (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
                                 errmsg("error unpacking incoming message")));
                    } else {
                        if (msg_new->kv_map_file) {
                            unlink(msg_new->kv_map_file);
                        }
                        kcdbremove (main_db, keys_to_use[next_key], strlen(keys_to_use[next_key]));	
                    }
                    cloudflare__zone_time_bucket__free_unpacked(msg_new, NULL);
                    kcfree(vbuf);
                    kcfree(keys_to_use[next_key]);
                } else {
                    ereport(NOTICE,
                            (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
                             errmsg("get error on %s -- %s", keys_to_use[next_key], kcecodename(kcdbecode(main_db)))));
                }
            }
        } else {
            ereport(NOTICE,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("prefix error on %s -- %s", prefixes_to_use[i], kcecodename(kcdbecode(main_db)))));
        }
    }

    pfree(keys_to_use);
    
    // Done!
    kcdbendtran (main_db, 1);
    if (!kcdbclose(main_db)) {
        ereport(ERROR,
                (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
                 errmsg("Error Closeing db: \"%s\"", kcecodename(kcdbecode(main_db)))));
    }

    PG_RETURN_INT64(num_keys_deleted);
}
示例#28
0
Datum kc_shrink(PG_FUNCTION_ARGS) {
    
    char       *map_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
    char       *start_time = text_to_cstring(PG_GETARG_TEXT_PP(1)); // Start time + uid!!!
    char       *new_rid = text_to_cstring(PG_GETARG_TEXT_PP(2));
    ArrayType  *old_rids = PG_GETARG_ARRAYTYPE_P(3);
    char       *classification = text_to_cstring(PG_GETARG_TEXT_PP(4));
    char       *doctype = text_to_cstring(PG_GETARG_TEXT_PP(5));
    char       *pop = text_to_cstring(PG_GETARG_TEXT_PP(6));
    char       *psource = text_to_cstring(PG_GETARG_TEXT_PP(7));
    text       *tout;   
    int        i,j;
    Datum      *rid_datums;
    bool       *rid_nulls;
    int        rid_count;
    char       *next_rid;
    KCDB       *main_db;
    char       *vbuf;
    size_t      vsiz;

    // Open our DB.
    main_db = kcdbnew();
    if (!open_db (main_db, map_name, start_time)) {
        tout = cstring_to_text(new_rid);
        PG_RETURN_TEXT_P(tout);        
    }
    kcdbbegintran (main_db, 0);
    
    // First fill in what we can from the input.
    Cloudflare__ZoneTimeBucket msg = CLOUDFLARE__ZONE_TIME_BUCKET__INIT;
    
    msg.map_name = (char *)palloc(MAX_KC_ROW_ENTRY * sizeof(char));
    msg.doctype = (char *)palloc(MAX_KC_ROW_ENTRY * sizeof(char));
    msg.classification = (char *)palloc(MAX_KC_ROW_ENTRY * sizeof(char));
    msg.pop = (char *)palloc(MAX_KC_ROW_ENTRY * sizeof(char));
    msg.psource = (char *)palloc(MAX_KC_ROW_ENTRY * sizeof(char));
    msg.result_id = (char *)palloc(MAX_KC_ROW_ENTRY * sizeof(char));
    msg.db_key = (char *)palloc(MAX_KC_ROW_ENTRY * sizeof(char));
    msg.db_path = (char *)palloc(MAX_KC_ROW_ENTRY * sizeof(char));
    msg.map_entry = palloc(MAX_KEYS_BEFORE_KV_MAP * sizeof(Cloudflare__ZoneTimeBucket__Counter));
    msg.n_map_entry = 0;

    strncpy(msg.map_name, map_name, MAX_KC_ROW_ENTRY);
    strncpy(msg.classification, classification, MAX_KC_ROW_ENTRY);
    strncpy(msg.doctype, doctype, MAX_KC_ROW_ENTRY);
    strncpy(msg.pop, pop, MAX_KC_ROW_ENTRY);
    strncpy(msg.psource, psource, MAX_KC_ROW_ENTRY);
    strncpy(msg.result_id, new_rid, KC_MAX_RID);
    snprintf(msg.db_path, MAX_KC_ROW_ENTRY, "%s%s%s", 
             map_name, "/", start_time);

    snprintf(msg.db_key, KC_MAX_RID, "%s%s%s%s%s%s%s%s%s%s%s", 
             new_rid, CF_LABEL_SEP,
             classification, CF_LABEL_SEP, 
             doctype, CF_LABEL_SEP,
             pop, CF_LABEL_SEP,
             psource, CF_LABEL_SEP,
             map_name);

    // Now run over the array.
    deconstruct_array(old_rids, TEXTOID, -1, false, 'i',
                      &rid_datums, &rid_nulls, &rid_count);
    if (ARR_HASNULL(old_rids)) {
        ereport(ERROR,
                (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
                 errmsg("cannot work with arrays containing NULLs")));
    }

    int num_new_keys = 0;
    int num_entries = 0;
    char keys_to_use[rid_count][KC_MAX_RID];
    Cloudflare__ZoneTimeBucket *msg_new[rid_count];
    j=0;
    for (i = 0; i < rid_count; i++) {
        next_rid = TextDatumGetCString(rid_datums[i]);
        snprintf(keys_to_use[i], KC_MAX_RID, "%s%s%s%s%s%s%s%s%s%s%s", 
                 next_rid, CF_LABEL_SEP, 
                 classification, CF_LABEL_SEP,
                 doctype, CF_LABEL_SEP,
                 pop, CF_LABEL_SEP,
                 psource, CF_LABEL_SEP,
                 map_name);

        vbuf = kcdbget(main_db, keys_to_use[i], strlen(keys_to_use[i]), &vsiz);
        if (vbuf) {
            msg_new[j] = cloudflare__zone_time_bucket__unpack(NULL, vsiz, (const uint8_t *)vbuf);
            if (msg_new[j] == NULL) {   // Something failed
                ereport(ERROR,
                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                         errmsg("error unpacking incoming message")));
            } else {
                if (msg_new[j]->kv_map_file) {
                    num_entries = MAX_KEYS_BEFORE_KV_MAP + 1;                    
                } else {
                    num_entries += msg_new[j]->n_map_entry; 
                }
                j++;
            }
            kcfree(vbuf);
        } else {
#ifdef CF_DUBUG
            ereport(NOTICE,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("get error on %s -- %s", keys_to_use[i], kcecodename(kcdbecode(main_db)))));
#endif
        }
    }
    
    // Now merge the buffers.
    KCDB* msg_db = NULL;
    if (num_entries > MAX_KEYS_BEFORE_KV_MAP) {
        msg_db = kcdbnew();
        set_kv_path(&msg, map_name, start_time, msg_db);
    }

    for (i = 0; i < j; i++) {
        if (num_entries > MAX_KEYS_BEFORE_KV_MAP) {
            num_new_keys += merge_using_kv_map(&msg, msg_new[i], msg_db);
        } else {
            num_new_keys += merge_messages_basic(&msg, msg_new[i]);
        }
        cloudflare__zone_time_bucket__free_unpacked(msg_new[i], NULL);
    }

    if (num_entries > MAX_KEYS_BEFORE_KV_MAP) {
        // Close the db.
        kcdbendtran (msg_db, 1);
        kcdbclose(msg_db);
    }

#ifdef CF_DUBUG
    ereport(NOTICE,
            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
             errmsg("saving: num map entries: %zu -- writting with %d keys", msg.n_map_entry, num_new_keys)));
#endif

    // Save the updated buffer.
    if (num_new_keys > 0) {
        unsigned int len;
        void *buf;
        len = cloudflare__zone_time_bucket__get_packed_size (&msg);  
        buf = palloc (len);           
        cloudflare__zone_time_bucket__pack (&msg, buf);
        if(!kcdbset(main_db, msg.db_key, strlen(msg.db_key), buf, len)) {
            ereport(ERROR,
                    (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
                     errmsg("set error: %s\n", kcecodename(kcdbecode(main_db)))));
        }
        pfree (buf);
    }

    // Done!
    kcdbendtran (main_db, 1);
    if (!kcdbclose(main_db)) {
        ereport(ERROR,
                (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
                 errmsg("Error Closeing db: \"%s\"", kcecodename(kcdbecode(main_db)))));
    }

    tout = cstring_to_text(new_rid);
    PG_RETURN_TEXT_P(tout);
}
示例#29
0
SvecType * svec_in_internal(char * str)
{
	char *values;
	ArrayType *pgarray_vals,*pgarray_ix;
	double *vals, *vals_temp;
	StringInfo index;
	int64 *u_index;
	int32_t num_values,total_value_count;
	SparseData sdata;
	SvecType *result;
	bits8 *bitmap;
	int bitmask;
	int i,j;

	/* Read in the two arrays defining the Sparse Vector, first is the array
	 * of run lengths (the count array), the second is an array of the 
	 * unique values (the data array).
	 *
	 * The input format is a pair of standard Postgres arrays separated by 
	 * a colon, like this:
	 * 	{1,10,1,5,1}:{4.3,0,0.2,0,7.4}
	 *
	 * For now, the data array must only have float8 elements.
	 */
	if ((values=strchr(str,':')) == NULL) {
		ereport(ERROR,
			(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
			 errmsg("Invalid input string for svec")));
	} else {
		*values = '\0';
		values = values+1;
	}
	/* Get the count and data arrays */
	pgarray_ix = DatumGetArrayTypeP(
			    OidFunctionCall3(F_ARRAY_IN,CStringGetDatum(str),
			    ObjectIdGetDatum(INT8OID),Int32GetDatum(-1)));

	pgarray_vals = DatumGetArrayTypeP(
			    OidFunctionCall3(F_ARRAY_IN,CStringGetDatum(values),
			    ObjectIdGetDatum(FLOAT8OID),Int32GetDatum(-1)));

	num_values = *(ARR_DIMS(pgarray_ix));
	u_index = (int64 *)ARR_DATA_PTR(pgarray_ix);
	vals = (double *)ARR_DATA_PTR(pgarray_vals);

	/* The count and value arrays must be non-empty */
	int size1 = ARR_NDIM(pgarray_ix);
	int size2 = ARR_NDIM(pgarray_vals);
	if (size1 == 0 || size2 == 0)
		ereport(ERROR,
			(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
			 errmsg("The count and value arrays must be non-empty")));

	/* The count and value arrays must have the same dimension */
	if (num_values != *(ARR_DIMS(pgarray_vals)))
		ereport(ERROR,
			(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
			 errmsg("Unique value count not equal to run length count %d != %d", num_values, *(ARR_DIMS(pgarray_vals)))));

	/* Count array cannot have NULLs */
	if (ARR_HASNULL(pgarray_ix))
		ereport(ERROR,
			(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
			 errmsg("NULL value in the count array.")));

	/* If the data array has NULLs, then we need to create an array to
	 * store the NULL values as NVP values defined in float_specials.h. 
	 */
	if (ARR_HASNULL(pgarray_vals)) {
		vals_temp = vals;
		vals = (double *)palloc(sizeof(float8) * num_values);
		bitmap = ARR_NULLBITMAP(pgarray_vals);
		bitmask = 1;
		j = 0;
		for (i=0; i<num_values; i++) {
			if (bitmap && (*bitmap & bitmask) == 0) // if NULL
				vals[i] = NVP;
			else { 
				vals[i] = vals_temp[j];
				j++;
			}
			if (bitmap) { // advance bitmap pointer
				bitmask <<= 1;
				if (bitmask == 0x100) {
					bitmap++;
					bitmask = 1;
				}
			}
		}
	 }

	/* Make an empty StringInfo because we have the data array already */
	index = makeStringInfo();
	total_value_count = 0;
	for (int i=0;i<num_values;i++) {
		if (u_index[i] <= 0) 
			ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("Non-positive run length in input")));

		total_value_count+=u_index[i]; 
		append_to_rle_index(index,u_index[i]);
	}

	sdata = makeInplaceSparseData((char *)vals,index->data,
			num_values*sizeof(double),index->len,FLOAT8OID,
			num_values,total_value_count);
	sdata->type_of_data = FLOAT8OID;

	result = svec_from_sparsedata(sdata,true);
	if (total_value_count == 1) result->dimension = -1; //Scalar

	if (ARR_HASNULL(pgarray_vals)) pfree(vals);
	pfree(str); /* str is allocated from a strdup */
	pfree(pgarray_ix);
	pfree(pgarray_vals);

	return result;
}
示例#30
0
Datum
hvault_table_count_step(PG_FUNCTION_ARGS)
{
    MemoryContext aggmemctx, oldmemctx;
    ArrayType * ctx;
    ArrayType * idx_array;
    int i, pos_idx;
    int32_t * ctx_data;
    
    if (!AggCheckCallContext(fcinfo, &aggmemctx))
        elog(ERROR, "hvault_table_group_step called in non-aggregate context");

    
    ctx = PG_ARGISNULL(0) ? NULL : PG_GETARG_ARRAYTYPE_P(0);
    if (ctx == NULL)
    {
        int ndim;
        int32_t * bounds_data;
        int dims[MAXDIM];
        int lbs[MAXDIM]; 
        ArrayType * bounds_array;

        oldmemctx = MemoryContextSwitchTo(aggmemctx);

        if (PG_ARGISNULL(2))
            elog(ERROR, "bounds array must not be null");

//        if (!get_fn_expr_arg_stable(fcinfo->flinfo, 2))
//            elog(ERROR, "bounds array must be const");

        bounds_array = PG_GETARG_ARRAYTYPE_P(2);
        Assert(bounds_array != NULL);
        Assert(bounds_array->elemtype == INT4OID);

        if (bounds_array->ndim != 2 || ARR_DIMS(bounds_array)[1] != 2)
            elog(ERROR, "bounds array size is invalid");

        if (ARR_HASNULL(bounds_array))
        {
            int size = ARR_DIMS(bounds_array)[0] * ARR_DIMS(bounds_array)[1]; 
            for (i = 0; i < (size + 7) / 8; i++)
                if (ARR_NULLBITMAP(bounds_array)[i] != 0)
                    elog(ERROR, "bounds array must not contain NULLs");
        }

        ndim = ARR_DIMS(bounds_array)[0]; 
        if (ndim > MAXDIM)
            elog(ERROR, "too many dimensions, max supported is %d", MAXDIM);

        bounds_data = (int32_t *) ARR_DATA_PTR(bounds_array);
        for (i = 0; i < ndim; i++) 
        {
            int ubs;

            lbs[i] = bounds_data[2*i];
            ubs = bounds_data[2*i+1];
            dims[i] = ubs - lbs[i];
        }

        ctx = intArrayInit(ndim, dims, lbs);
        MemoryContextSwitchTo(oldmemctx);
    }
    
    Assert(!ARR_HASNULL(ctx));
    Assert(ctx->elemtype == INT4OID);
    
    if (PG_ARGISNULL(1))
        elog(ERROR, "group index array must not be null");

    idx_array = PG_GETARG_ARRAYTYPE_P(1);
    Assert(idx_array != NULL);
    Assert(idx_array->elemtype == INT4OID);

    if (idx_array->ndim != 1)
        elog(ERROR, "group index array must have single dimension");

    if (ARR_DIMS(idx_array)[0] != ctx->ndim)
        elog(ERROR, "group index array length is inconsistent");

    if (ARR_HASNULL(idx_array))
    {
        int size = ARR_DIMS(idx_array)[0];
        for (i = 0; i < (size + 7) / 8; i++)
            /* Skip elements with nulls */
            if (ARR_NULLBITMAP(idx_array)[i] != 0)
            {
                elog(WARNING, "index array contains NULL, skipping");
                PG_RETURN_ARRAYTYPE_P(ctx); 
            }
    }
    

    pos_idx = intArrayIdx(ctx, (int *) ARR_DATA_PTR(idx_array), true);
    if (pos_idx != -1)
    {
        Assert(pos_idx >= 0);
        if (ARR_SIZE(ctx) - ARR_DATA_OFFSET(ctx) <= pos_idx * 4)
        {
            elog(ERROR, "Array out of bounds access: %ld %d", 
                 ARR_SIZE(ctx) - ARR_DATA_OFFSET(ctx), pos_idx * 4);
        }
        ctx_data = (int32_t *) ARR_DATA_PTR(ctx);
        ctx_data[pos_idx]++;
    }
    
    PG_RETURN_ARRAYTYPE_P(ctx);
}