Пример #1
0
Datum
ginint4_queryextract(PG_FUNCTION_ARGS)
{
	int32	   *nentries = (int32 *) PG_GETARG_POINTER(1);
	StrategyNumber strategy = PG_GETARG_UINT16(2);
	Datum	   *res = NULL;

	*nentries = 0;

	if (strategy == BooleanSearchStrategy)
	{
		QUERYTYPE  *query = (QUERYTYPE *) PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0));
		ITEM	   *items = GETQUERY(query);
		int			i;

		if (query->size == 0)
			PG_RETURN_POINTER(NULL);

		if (shorterquery(items, query->size) == 0)
			elog(ERROR, "Query requires full scan, GIN doesn't support it");

		pfree(query);

		query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(0));
		items = GETQUERY(query);

		res = (Datum *) palloc(sizeof(Datum) * query->size);
		*nentries = 0;

		for (i = 0; i < query->size; i++)
			if (items[i].type == VAL)
			{
				res[*nentries] = Int32GetDatum(items[i].val);
				(*nentries)++;
			}
	}
	else
	{
		ArrayType  *query = PG_GETARG_ARRAYTYPE_P(0);
		int4	   *arr;
		uint32		i;

		CHECKARRVALID(query);
		*nentries = ARRNELEMS(query);
		if (*nentries > 0)
		{
			res = (Datum *) palloc(sizeof(Datum) * (*nentries));

			arr = ARRPTR(query);
			for (i = 0; i < *nentries; i++)
				res[i] = Int32GetDatum(arr[i]);
		}
	}

	if (*nentries == 0)
	{
		switch (strategy)
		{
			case BooleanSearchStrategy:
			case RTOverlapStrategyNumber:
				*nentries = -1; /* nobody can be found */
				break;
			default:			/* require fullscan: GIN can't find void
								 * arrays */
				break;
		}
	}

	PG_RETURN_POINTER(res);
}
Пример #2
0
Datum
ginint4_consistent(PG_FUNCTION_ARGS)
{
	bool	   *check = (bool *) PG_GETARG_POINTER(0);
	StrategyNumber strategy = PG_GETARG_UINT16(1);

	/* int32	nkeys = PG_GETARG_INT32(3); */
	/* Pointer	   *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
	bool	   *recheck = (bool *) PG_GETARG_POINTER(5);
	bool		res = FALSE;

	/*
	 * we need not check array carefully, it's done by previous
	 * ginarrayextract call
	 */

	switch (strategy)
	{
		case RTOverlapStrategyNumber:
			/* result is not lossy */
			*recheck = false;
			/* at least one element in check[] is true, so result = true */
			res = TRUE;
			break;
		case RTContainedByStrategyNumber:
		case RTOldContainedByStrategyNumber:
			/* we will need recheck */
			*recheck = true;
			/* at least one element in check[] is true, so result = true */
			res = TRUE;
			break;
		case RTSameStrategyNumber:
			{
				ArrayType  *query = PG_GETARG_ARRAYTYPE_P(2);
				int			i,
							nentries = ARRNELEMS(query);

				/* we will need recheck */
				*recheck = true;
				res = TRUE;
				for (i = 0; i < nentries; i++)
					if (!check[i])
					{
						res = FALSE;
						break;
					}
			}
			break;
		case RTContainsStrategyNumber:
		case RTOldContainsStrategyNumber:
			{
				ArrayType  *query = PG_GETARG_ARRAYTYPE_P(2);
				int			i,
							nentries = ARRNELEMS(query);

				/* result is not lossy */
				*recheck = false;
				res = TRUE;
				for (i = 0; i < nentries; i++)
					if (!check[i])
					{
						res = FALSE;
						break;
					}
			}
			break;
		case BooleanSearchStrategy:
			{
				QUERYTYPE  *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(2));

				/* result is not lossy */
				*recheck = false;
				res = ginconsistent(query, check);
			}
			break;
		default:
			elog(ERROR, "ginint4_consistent: unknown strategy number: %d",
				 strategy);
	}

	PG_RETURN_BOOL(res);
}
Пример #3
0
void
rt__int_size(ArrayType *a, float *size)
{
	*size = (float) ARRNELEMS(a);
}
Пример #4
0
datum_t
ginint4_queryextract(PG_FUNC_ARGS)
{
	int32	   *nentries = (int32 *) ARG_POINTER(1);
	strat_nr_t strategy = ARG_UINT16(2);
	int32	   *searchMode = (int32 *) ARG_POINTER(6);
	datum_t	   *res = NULL;

	*nentries = 0;

	if (strategy == BooleanSearchStrategy)
	{
		QUERYTYPE  *query = ARG_QUERYTYPE_P(0);
		ITEM	   *items = GETQUERY(query);
		int			i;

		/* empty query must fail */
		if (query->size <= 0)
			RET_POINTER(NULL);

		/*
		 * If the query doesn't have any required primitive values (for
		 * instance, it's something like '! 42'), we have to do a full index
		 * scan.
		 */
		if (query_has_required_values(query))
			*searchMode = GIN_SEARCH_MODE_DEFAULT;
		else
			*searchMode = GIN_SEARCH_MODE_ALL;

		/*
		 * Extract all the VAL items as things we want GIN to check for.
		 */
		res = (datum_t *) palloc(sizeof(datum_t) * query->size);
		*nentries = 0;

		for (i = 0; i < query->size; i++)
		{
			if (items[i].type == VAL)
			{
				res[*nentries] = INT32_TO_D(items[i].val);
				(*nentries)++;
			}
		}
	}
	else
	{
		array_s  *query = ARG_ARRAY_P(0);

		CHECKARRVALID(query);
		*nentries = ARRNELEMS(query);
		if (*nentries > 0)
		{
			int4	   *arr;
			int32		i;

			res = (datum_t *) palloc(sizeof(datum_t) * (*nentries));

			arr = ARRPTR(query);
			for (i = 0; i < *nentries; i++)
				res[i] = INT32_TO_D(arr[i]);
		}

		switch (strategy)
		{
			case RTOverlapStrategyNumber:
				*searchMode = GIN_SEARCH_MODE_DEFAULT;
				break;
			case RTContainedByStrategyNumber:
			case RTOldContainedByStrategyNumber:
				/* empty set is contained in everything */
				*searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
				break;
			case RTSameStrategyNumber:
				if (*nentries > 0)
					*searchMode = GIN_SEARCH_MODE_DEFAULT;
				else
					*searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
				break;
			case RTContainsStrategyNumber:
			case RTOldContainsStrategyNumber:
				if (*nentries > 0)
					*searchMode = GIN_SEARCH_MODE_DEFAULT;
				else	/* everything contains the empty set */
					*searchMode = GIN_SEARCH_MODE_ALL;
				break;
			default:
				elog(ERROR, "ginint4_queryextract: unknown strategy number: %d",
					 strategy);
		}
	}

	RET_POINTER(res);
}
Пример #5
0
/*
** GiST Compress and Decompress methods
*/
Datum
g_int_compress(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
	GISTENTRY  *retval;
	ArrayType  *r;
	int			len;
	int		   *dr;
	int			i,
				min,
				cand;

	if (entry->leafkey)
	{
		r = DatumGetArrayTypePCopy(entry->key);
		CHECKARRVALID(r);
		PREPAREARR(r);

		if (ARRNELEMS(r) >= 2 * MAXNUMRANGE)
			elog(NOTICE, "input array is too big (%d maximum allowed, %d current), use gist__intbig_ops opclass instead",
				 2 * MAXNUMRANGE - 1, ARRNELEMS(r));

		retval = palloc(sizeof(GISTENTRY));
		gistentryinit(*retval, PointerGetDatum(r),
					  entry->rel, entry->page, entry->offset, FALSE);

		PG_RETURN_POINTER(retval);
	}

	/*
	 * leaf entries never compress one more time, only when entry->leafkey
	 * ==true, so now we work only with internal keys
	 */

	r = DatumGetArrayTypeP(entry->key);
	CHECKARRVALID(r);
	if (ARRISEMPTY(r))
	{
		if (r != (ArrayType *) DatumGetPointer(entry->key))
			pfree(r);
		PG_RETURN_POINTER(entry);
	}

	if ((len = ARRNELEMS(r)) >= 2 * MAXNUMRANGE)
	{							/* compress */
		if (r == (ArrayType *) DatumGetPointer(entry->key))
			r = DatumGetArrayTypePCopy(entry->key);
		r = resize_intArrayType(r, 2 * (len));

		dr = ARRPTR(r);

		for (i = len - 1; i >= 0; i--)
			dr[2 * i] = dr[2 * i + 1] = dr[i];

		len *= 2;
		cand = 1;
		while (len > MAXNUMRANGE * 2)
		{
			min = 0x7fffffff;
			for (i = 2; i < len; i += 2)
				if (min > (dr[i] - dr[i - 1]))
				{
					min = (dr[i] - dr[i - 1]);
					cand = i;
				}
			memmove((void *) &dr[cand - 1], (void *) &dr[cand + 1], (len - cand - 1) * sizeof(int32));
			len -= 2;
		}
		r = resize_intArrayType(r, len);
		retval = palloc(sizeof(GISTENTRY));
		gistentryinit(*retval, PointerGetDatum(r),
					  entry->rel, entry->page, entry->offset, FALSE);
		PG_RETURN_POINTER(retval);
	}
	else
		PG_RETURN_POINTER(entry);

	PG_RETURN_POINTER(entry);
}
Пример #6
0
Datum
g_int_decompress(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
	GISTENTRY  *retval;
	ArrayType  *r;
	int		   *dr,
				lenr;
	ArrayType  *in;
	int			lenin;
	int		   *din;
	int			i,
				j;

	in = DatumGetArrayTypeP(entry->key);

	CHECKARRVALID(in);
	if (ARRISEMPTY(in))
	{
		if (in != (ArrayType *) DatumGetPointer(entry->key))
		{
			retval = palloc(sizeof(GISTENTRY));
			gistentryinit(*retval, PointerGetDatum(in),
						  entry->rel, entry->page, entry->offset, FALSE);
			PG_RETURN_POINTER(retval);
		}

		PG_RETURN_POINTER(entry);
	}

	lenin = ARRNELEMS(in);

	if (lenin < 2 * MAXNUMRANGE)
	{							/* not compressed value */
		if (in != (ArrayType *) DatumGetPointer(entry->key))
		{
			retval = palloc(sizeof(GISTENTRY));
			gistentryinit(*retval, PointerGetDatum(in),
						  entry->rel, entry->page, entry->offset, FALSE);

			PG_RETURN_POINTER(retval);
		}
		PG_RETURN_POINTER(entry);
	}

	din = ARRPTR(in);
	lenr = internal_size(din, lenin);

	r = new_intArrayType(lenr);
	dr = ARRPTR(r);

	for (i = 0; i < lenin; i += 2)
		for (j = din[i]; j <= din[i + 1]; j++)
			if ((!i) || *(dr - 1) != j)
				*dr++ = j;

	if (in != (ArrayType *) DatumGetPointer(entry->key))
		pfree(in);
	retval = palloc(sizeof(GISTENTRY));
	gistentryinit(*retval, PointerGetDatum(r),
				  entry->rel, entry->page, entry->offset, FALSE);

	PG_RETURN_POINTER(retval);
}
Пример #7
0
Datum
g_intbig_compress(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);

	if (entry->leafkey)
	{
		GISTENTRY  *retval;
		ArrayType  *in = DatumGetArrayTypeP(entry->key);
		int32	   *ptr;
		int			num;
		GISTTYPE   *res = (GISTTYPE *) palloc0(CALCGTSIZE(0));

		CHECKARRVALID(in);
		if (ARRISEMPTY(in))
		{
			ptr = NULL;
			num = 0;
		}
		else
		{
			ptr = ARRPTR(in);
			num = ARRNELEMS(in);
		}
		SET_VARSIZE(res, CALCGTSIZE(0));

		while (num--)
		{
			HASH(GETSIGN(res), *ptr);
			ptr++;
		}

		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
		gistentryinit(*retval, PointerGetDatum(res),
					  entry->rel, entry->page,
					  entry->offset, FALSE);

		if (in != DatumGetArrayTypeP(entry->key))
			pfree(in);

		PG_RETURN_POINTER(retval);
	}
	else if (!ISALLTRUE(DatumGetPointer(entry->key)))
	{
		GISTENTRY  *retval;
		int			i;
		BITVECP		sign = GETSIGN(DatumGetPointer(entry->key));
		GISTTYPE   *res;

		LOOPBYTE
		{
			if ((sign[i] & 0xff) != 0xff)
				PG_RETURN_POINTER(entry);
		}

		res = (GISTTYPE *) palloc(CALCGTSIZE(ALLISTRUE));
		SET_VARSIZE(res, CALCGTSIZE(ALLISTRUE));
		res->flag = ALLISTRUE;

		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
		gistentryinit(*retval, PointerGetDatum(res),
					  entry->rel, entry->page,
					  entry->offset, FALSE);

		PG_RETURN_POINTER(retval);
	}
Пример #8
0
/*
** GiST Compress and Decompress methods
*/
Datum
g_int_compress(PG_FUNCTION_ARGS)
{
    GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
    GISTENTRY  *retval;
    ArrayType  *r;
    int			len;
    int		   *dr;
    int			i,
                min,
                cand;

    if (entry->leafkey)
    {
        r = (ArrayType *) PG_DETOAST_DATUM_COPY(entry->key);
        PREPAREARR(r);
        r->flags |= LEAFKEY;
        retval = palloc(sizeof(GISTENTRY));
        gistentryinit(*retval, PointerGetDatum(r),
                      entry->rel, entry->page, entry->offset, VARSIZE(r), FALSE);

        PG_RETURN_POINTER(retval);
    }

    r = (ArrayType *) PG_DETOAST_DATUM(entry->key);
    if (ISLEAFKEY(r) || ARRISVOID(r))
    {
        if (r != (ArrayType *) DatumGetPointer(entry->key))
            pfree(r);
        PG_RETURN_POINTER(entry);
    }

    if ((len = ARRNELEMS(r)) >= 2 * MAXNUMRANGE)
    {   /* compress */
        if (r == (ArrayType *) DatumGetPointer(entry->key))
            r = (ArrayType *) PG_DETOAST_DATUM_COPY(entry->key);
        r = resize_intArrayType(r, 2 * (len));

        dr = ARRPTR(r);

        for (i = len - 1; i >= 0; i--)
            dr[2 * i] = dr[2 * i + 1] = dr[i];

        len *= 2;
        cand = 1;
        while (len > MAXNUMRANGE * 2)
        {
            min = 0x7fffffff;
            for (i = 2; i < len; i += 2)
                if (min > (dr[i] - dr[i - 1]))
                {
                    min = (dr[i] - dr[i - 1]);
                    cand = i;
                }
            memmove((void *) &dr[cand - 1], (void *) &dr[cand + 1], (len - cand - 1) * sizeof(int));
            len -= 2;
        }
        r = resize_intArrayType(r, len);
        retval = palloc(sizeof(GISTENTRY));
        gistentryinit(*retval, PointerGetDatum(r),
                      entry->rel, entry->page, entry->offset, VARSIZE(r), FALSE);
        PG_RETURN_POINTER(retval);
    }
    else
        PG_RETURN_POINTER(entry);

    PG_RETURN_POINTER(entry);
}
Пример #9
0
Datum ta_f( PG_FUNCTION_ARGS)
{

	// Declare for TA
	TA_RetCode retCode;
	TA_Real *closePrice = NULL;
	TA_Real *out;

	TA_Integer outBeg;
	TA_Integer outNbElement;

	// Declare for postgres
	FuncCallContext *funcctx;
	int call_cntr;
	int max_calls;
	Datum *result = NULL;
	int dim;
	int z;
	ArrayType *ur = PG_GETARG_ARRAYTYPE_P(0);

	if (array_contains_nulls(ur))
	{
		ereport(ERROR,
				( errcode(ERRCODE_ARRAY_ELEMENT_ERROR), errmsg("cannot work with arrays containing NULLs") ));
	}

	dim = ARRNELEMS(ur);
	closePrice = ARRPTR(ur);

	if (SRF_IS_FIRSTCALL())
	{
		MemoryContext oldcontext;

		funcctx = SRF_FIRSTCALL_INIT();
		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
		/* One-time setup code appears here: */
		retCode = TA_Initialize();
		if (retCode != TA_SUCCESS)
		{
			ereport(ERROR,
					( errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Cannot initialize TA-Lib (%d)!\n", retCode) ));
		}

		out = palloc(dim * sizeof(TA_Real));

		retCode = TA_MA(0, dim - 1, &closePrice[0], 5, TA_MAType_SMA, &outBeg,
				&outNbElement, &out[0]);

		result = palloc(outNbElement * sizeof(Datum));

		// Error log for debugging
		/*
		ereport(NOTICE,
				(errmsg("dims %d,  outBeg: %d, outNbElement %d\n", dim, outBeg, outNbElement)));
		*/
		for (z = 0; z < dim; z++)
		{
			// Error log for debugging
			//ereport(NOTICE, (errmsg("z: %d, out[z]: %5.1f", z, out[z])));
			if(z > outBeg-1) {
				result[z] = Float8GetDatum(out[z-outBeg]);
				continue;
			}
			result[z] = NULL;
		}
		TA_Shutdown();

		funcctx->max_calls = dim;
		funcctx->user_fctx = result;
		MemoryContextSwitchTo(oldcontext);
	}

	/* stuff done on every call of the function */
	funcctx = SRF_PERCALL_SETUP();

	call_cntr = funcctx->call_cntr;
	max_calls = funcctx->max_calls;

	if (call_cntr < max_calls)
	{
		if(((Datum *) funcctx->user_fctx)[call_cntr]) {
			SRF_RETURN_NEXT(funcctx, ((Datum *) funcctx->user_fctx)[call_cntr]);
		}
		SRF_RETURN_NEXT_NULL(funcctx);
	}
	SRF_RETURN_DONE(funcctx);
}
Пример #10
0
void
init_cfg(Oid id, TSCfgInfo * cfg)
{
    Oid			arg[2];
    bool		isnull;
    Datum		pars[2];
    int			stat,
                i,
                j;
    text	   *ptr;
    text	   *prsname = NULL;
    char	   *nsp = get_namespace(TSNSP_FunctionOid);
    char		buf[1024];
    MemoryContext oldcontext;
    void	   *plan;

    arg[0] = OIDOID;
    arg[1] = OIDOID;
    pars[0] = ObjectIdGetDatum(id);
    pars[1] = ObjectIdGetDatum(id);

    memset(cfg, 0, sizeof(TSCfgInfo));
    SPI_connect();

    sprintf(buf, "select prs_name from %s.pg_ts_cfg where oid = $1", nsp);
    plan = SPI_prepare(buf, 1, arg);
    if (!plan)
        ts_error(ERROR, "SPI_prepare() failed");

    stat = SPI_execp(plan, pars, " ", 1);
    if (stat < 0)
        ts_error(ERROR, "SPI_execp return %d", stat);
    if (SPI_processed > 0)
    {
        prsname = (text *) DatumGetPointer(
                      SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull)
                  );
        oldcontext = MemoryContextSwitchTo(TopMemoryContext);
        prsname = ptextdup(prsname);
        MemoryContextSwitchTo(oldcontext);

        cfg->id = id;
    }
    else
        ts_error(ERROR, "No tsearch cfg with id %d", id);

    SPI_freeplan(plan);

    arg[0] = TEXTOID;
    sprintf(buf, "select lt.tokid, map.dict_name from %s.pg_ts_cfgmap as map, %s.pg_ts_cfg as cfg, %s.token_type( $1 ) as lt where lt.alias =  map.tok_alias and map.ts_name = cfg.ts_name and cfg.oid= $2 order by lt.tokid desc;", nsp, nsp, nsp);
    plan = SPI_prepare(buf, 2, arg);
    if (!plan)
        ts_error(ERROR, "SPI_prepare() failed");

    pars[0] = PointerGetDatum(prsname);
    stat = SPI_execp(plan, pars, " ", 0);
    if (stat < 0)
        ts_error(ERROR, "SPI_execp return %d", stat);
    if (SPI_processed <= 0)
        ts_error(ERROR, "No parser with id %d", id);

    for (i = 0; i < SPI_processed; i++)
    {
        int			lexid = DatumGetInt32(SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull));
        ArrayType  *toasted_a = (ArrayType *) PointerGetDatum(SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 2, &isnull));
        ArrayType  *a;

        if (!cfg->map)
        {
            cfg->len = lexid + 1;
            cfg->map = (ListDictionary *) malloc(sizeof(ListDictionary) * cfg->len);
            if (!cfg->map)
                ereport(ERROR,
                        (errcode(ERRCODE_OUT_OF_MEMORY),
                         errmsg("out of memory")));
            memset(cfg->map, 0, sizeof(ListDictionary) * cfg->len);
        }

        if (isnull)
            continue;

        a = (ArrayType *) PointerGetDatum(PG_DETOAST_DATUM(DatumGetPointer(toasted_a)));

        if (ARR_NDIM(a) != 1)
            ts_error(ERROR, "Wrong dimension");
        if (ARRNELEMS(a) < 1)
            continue;
        if (ARR_HASNULL(a))
            ts_error(ERROR, "Array must not contain nulls");

        cfg->map[lexid].len = ARRNELEMS(a);
        cfg->map[lexid].dict_id = (Datum *) malloc(sizeof(Datum) * cfg->map[lexid].len);
        if (!cfg->map[lexid].dict_id)
            ts_error(ERROR, "No memory");

        memset(cfg->map[lexid].dict_id, 0, sizeof(Datum) * cfg->map[lexid].len);
        ptr = (text *) ARR_DATA_PTR(a);
        oldcontext = MemoryContextSwitchTo(TopMemoryContext);
        for (j = 0; j < cfg->map[lexid].len; j++)
        {
            cfg->map[lexid].dict_id[j] = PointerGetDatum(ptextdup(ptr));
            ptr = NEXTVAL(ptr);
        }
        MemoryContextSwitchTo(oldcontext);

        if (a != toasted_a)
            pfree(a);
    }

    SPI_freeplan(plan);
    SPI_finish();
    cfg->prs_id = name2id_prs(prsname);
    pfree(prsname);
    pfree(nsp);
    for (i = 0; i < cfg->len; i++)
    {
        for (j = 0; j < cfg->map[i].len; j++)
        {
            ptr = (text *) DatumGetPointer(cfg->map[i].dict_id[j]);
            cfg->map[i].dict_id[j] = ObjectIdGetDatum(name2id_dict(ptr));
            pfree(ptr);
        }
    }
}
Пример #11
0
/*
** Allows the construction of a cube from 2 float[]'s
*/
Datum
cube_a_f8_f8(PG_FUNCTION_ARGS)
{
	ArrayType  *ur = PG_GETARG_ARRAYTYPE_P(0);
	ArrayType  *ll = PG_GETARG_ARRAYTYPE_P(1);
	NDBOX	   *result;
	int			i;
	int			dim;
	int			size;
	bool		point;
	double	   *dur,
			   *dll;

	if (array_contains_nulls(ur) || array_contains_nulls(ll))
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
				 errmsg("cannot work with arrays containing NULLs")));

	dim = ARRNELEMS(ur);
	if (dim > CUBE_MAX_DIM)
		ereport(ERROR,
				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
				 errmsg("can't extend cube"),
				 errdetail("A cube cannot have more than %d dimensions.",
							   CUBE_MAX_DIM)));

	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);

	/* Check if it's a point */
	point = true;
	for (i = 0; i < dim; i++)
	{
		if (dur[i] != dll[i])
		{
			point = false;
			break;
		}
	}

	size = point ? POINT_SIZE(dim) : CUBE_SIZE(dim);
	result = (NDBOX *) palloc0(size);
	SET_VARSIZE(result, size);
	SET_DIM(result, dim);

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

	if (!point)
	{
		for (i = 0; i < dim; i++)
			result->x[i + dim] = dll[i];
	}
	else
		SET_POINT_BIT(result);

	PG_RETURN_NDBOX(result);
}