Beispiel #1
0
datum_t tsquery_not(PG_FUNC_ARGS)
{
	TSQuery a = ARG_TSQUERY_COPY(0);
	QTNode *res;
	TSQuery query;

	if (a->size == 0)
		RET_POINTER(a);

	res = (QTNode *) pzalloc(sizeof(QTNode));
	res->flags |= QTN_NEEDFREE;

	res->valnode = (QueryItem *) pzalloc(sizeof(QueryItem));
	res->valnode->type = QI_OPR;
	res->valnode->qoperator.oper = OP_NOT;

	res->child = (QTNode **) pzalloc(sizeof(QTNode *));
	res->child[0] = QT2QTN(GETQUERY(a), GETOPERAND(a));
	res->nchild = 1;

	query = QTN2QT(res);

	QTNFree(res);
	PG_FREE_IF_COPY(a, 0);

	RET_POINTER(query);
}
Beispiel #2
0
/*
 * GiST compress for polygons: represent a polygon by its bounding box
 */
datum_t gist_poly_compress(PG_FUNC_ARGS)
{
	struct gist_entry *entry = (struct gist_entry *)ARG_POINTER(0);
	struct gist_entry *retval;

	if (entry->leafkey) {
		retval = palloc(sizeof(struct gist_entry));
		if (D_TO_PTR(entry->key) != NULL) {
			POLYGON *in = D_TO_POLYGON_P(entry->key);
			BOX *r;

			r = (BOX *) palloc(sizeof(BOX));
			memcpy((void *)r, (void *)&(in->boundbox), sizeof(BOX));
			gistentryinit(*retval, PTR_TO_D(r), entry->rel, entry->page,
				entry->offset, FALSE);

		} else {
			gistentryinit(*retval, (datum_t) 0, entry->rel, entry->page,
				entry->offset, FALSE);
		}
	} else {
		retval = entry;
	}

	RET_POINTER(retval);
}
Beispiel #3
0
void _fastcall WriteCString(ParamBlk *parm)
{
	char *pNewAddress = 0;

	__try
	{
		if (p1.ev_long)
		{
			pNewAddress = HeapReAlloc(ghHeap,HEAP_E_FLAG,(void*)p1.ev_long,p2.ev_length+1);
			REPLACEDEBUGALLOC(p1.ev_long,pNewAddress,p2.ev_length+1);
		}
		else
		{
			pNewAddress = HeapAlloc(ghHeap,HEAP_E_FLAG,p2.ev_length+1);
			ADDDEBUGALLOC(pNewAddress,p2.ev_length+1);
		}
	}
	__except(SAVEHEAPEXCEPTION()) { }

	if (pNewAddress)
	{
		LOCKHAND(p2);
		memcpy(pNewAddress,HANDTOPTR(p2),p2.ev_length);
		pNewAddress[p2.ev_length] = '\0';
		UNLOCKHAND(p2);
		RET_POINTER(pNewAddress);
	}
	else
		RAISEERROREX(0);
}
Beispiel #4
0
void _fastcall WritePCString(ParamBlk *parm)
{
	char *pNewAddress = 0;
	char **pOldAddress = (char**)p1.ev_long;

	if (IS_STRING(p2) && pOldAddress)
	{
		__try
		{
			if ((*pOldAddress))
			{
				pNewAddress = HeapReAlloc(ghHeap,HEAP_E_FLAG,(*pOldAddress),p2.ev_length+1);
				REPLACEDEBUGALLOC(*pOldAddress,pNewAddress,p2.ev_length);
			}
			else
			{
				pNewAddress = HeapAlloc(ghHeap,HEAP_E_FLAG,p2.ev_length+1);
				ADDDEBUGALLOC(pNewAddress,p2.ev_length);
			}
		}
		__except(SAVEHEAPEXCEPTION()) { }

		if (pNewAddress)
		{
			*pOldAddress = pNewAddress;
			LOCKHAND(p2);
			memcpy(pNewAddress,HANDTOPTR(p2),p2.ev_length);
			pNewAddress[p2.ev_length] = '\0';		
			UNLOCKHAND(p2);
			RET_POINTER(pNewAddress);
			return;
		}
		else
			RAISEERROREX(0);
	}
Beispiel #5
0
/*
 * ARRAY_AGG aggregate function
 */
datum_t array_agg_transfn(PG_FUNC_ARGS)
{
	oid_t arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
	struct mctx * aggcontext;
	array_build_s *state;
	datum_t elem;

	if (arg1_typeid == INVALID_OID)
		ereport(ERROR, (
		errcode(E_INVALID_PARAMETER_VALUE),
		errmsg("could not determine input data type")));

	if (!AggCheckCallContext(fcinfo, &aggcontext)) {
		/* cannot be called directly because of internal-type argument */
		elog(ERROR, "array_agg_transfn called in non-aggregate context");
	}

	state = PG_ARG_ISNULL(0) ? NULL : (array_build_s *) ARG_POINTER(0);
	elem = PG_ARG_ISNULL(1) ? (datum_t) 0 : ARG_DATUM(1);
	state = accum_array_result(state, elem, PG_ARG_ISNULL(1), arg1_typeid, aggcontext);

	/*
	 * The transition type for array_agg() is declared to be "internal", which
	 * is a pass-by-value type the same size as a pointer.  So we can safely
	 * pass the array_build_s pointer through nodeAgg.c's machinations.
	 */
	RET_POINTER(state);
}
Beispiel #6
0
datum_t gistbeginscan(PG_FUNC_ARGS)
{
	struct relation *r;
	int nkeys = ARG_INT32(1);
	int norderbys = ARG_INT32(2);
	struct index_scan *scan;
	struct gist_scan_opaque *so;
	size_t size;

	r = (struct relation *)ARG_POINTER(0);
	scan = rel_get_index_scan(r, nkeys, norderbys);

	/* initialize opaque data */
	so = (struct gist_scan_opaque *) pzalloc(sizeof(struct gist_scan_opaque));
	so->queueCxt = aset_create_normal(current_mctx, "GiST queue context");
	so->tempCxt = create_tmp_gist_ctx();
	so->giststate = (struct gist_state *)palloc(sizeof(struct gist_state));
	init_gist_state(so->giststate, scan->indexRelation);

	/* workspaces with size dependent on numberOfOrderBys: */
	size = GIST_ITEM_HDR_SZ + sizeof(double) * scan->numberOfOrderBys;
	so->tmpTreeItem = palloc(size);
	so->distances = palloc(sizeof(double) * scan->numberOfOrderBys);
	so->qual_ok = true;	/* in case there are zero keys */

	scan->opaque = so;

	RET_POINTER(scan);
}
Beispiel #7
0
/*
 * GiST compress for circles: represent a circle by its bounding box
 */
datum_t gist_circle_compress(PG_FUNC_ARGS)
{
	struct gist_entry *entry = (struct gist_entry *)ARG_POINTER(0);
	struct gist_entry *retval;

	if (entry->leafkey) {
		retval = palloc(sizeof(struct gist_entry));
		if (D_TO_CIRCLE_P(entry->key) != NULL) {
			CIRCLE *in = D_TO_CIRCLE_P(entry->key);
			BOX *r;

			r = (BOX *) palloc(sizeof(BOX));
			r->high.x = in->center.x + in->radius;
			r->low.x = in->center.x - in->radius;
			r->high.y = in->center.y + in->radius;
			r->low.y = in->center.y - in->radius;
			gistentryinit(*retval, PTR_TO_D(r), entry->rel, entry->page,
				entry->offset, FALSE);
		} else {
			gistentryinit(*retval, (datum_t) 0, entry->rel, entry->page,
				entry->offset, FALSE);
		}
	} else
		retval = entry;

	RET_POINTER(retval);
}
Beispiel #8
0
datum_t
gbt_cash_compress(PG_FUNC_ARGS)
{
	struct gist_entry  *entry = (struct gist_entry *) ARG_POINTER(0);
	struct gist_entry  *retval = NULL;

	RET_POINTER(gbt_num_compress(retval, entry, &tinfo));
}
Beispiel #9
0
datum_t
gbt_cash_picksplit(PG_FUNC_ARGS)
{
	RET_POINTER(gbt_num_picksplit(
									(struct gist_entry_vector *) ARG_POINTER(0),
									  (struct gist_splitvec *) ARG_POINTER(1),
										&tinfo
										));
}
Beispiel #10
0
datum_t
gbt_cash_union(PG_FUNC_ARGS)
{
	struct gist_entry_vector *entryvec = (struct gist_entry_vector *) ARG_POINTER(0);
	void	   *out = palloc(sizeof(cashKEY));

	*(int *) ARG_POINTER(1) = sizeof(cashKEY);
	RET_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
}
Beispiel #11
0
datum_t
gbt_cash_same(PG_FUNC_ARGS)
{
	cashKEY    *b1 = (cashKEY *) ARG_POINTER(0);
	cashKEY    *b2 = (cashKEY *) ARG_POINTER(1);
	bool	   *result = (bool *) ARG_POINTER(2);

	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
	RET_POINTER(result);
}
Beispiel #12
0
datum_t gist_point_compress(PG_FUNC_ARGS)
{
	struct gist_entry *entry;

	entry = (struct gist_entry*) ARG_POINTER(0);
	if (entry->leafkey) {		/* Point, actually */
		BOX *box = palloc(sizeof(BOX));
		Point *point = D_TO_POINT_P(entry->key);
		struct gist_entry *retval = palloc(sizeof(struct gist_entry));

		box->high = box->low = *point;
		gistentryinit(*retval, BOX_P_TO_D(box), entry->rel, entry->page, entry->offset,
			FALSE);

		RET_POINTER(retval);
	}

	RET_POINTER(entry);
}
Beispiel #13
0
/*
 * The GiST Penalty method for boxes (also used for points)
 *
 * As in the R-tree paper, we use change in area as our penalty metric
 */
datum_t gist_box_penalty(PG_FUNC_ARGS)
{
	struct gist_entry* origentry = (struct gist_entry*) ARG_POINTER(0);
	struct gist_entry* newentry = (struct gist_entry*) ARG_POINTER(1);
	float* result = (float*) ARG_POINTER(2);
	datum_t ud;

	ud = DIRECT_FC2(rt_box_union, origentry->key, newentry->key);
	*result = (float)(size_box(ud) - size_box(origentry->key));
	RET_POINTER(result);
}
Beispiel #14
0
datum_t uuid_recv(PG_FUNC_ARGS)
{
	struct string* buffer;
	pg_uuid_t *uuid;

	buffer = (struct string*) ARG_POINTER(0);

	uuid = (pg_uuid_t*) palloc(UUID_LEN);
	memcpy(uuid->data, pq_getmsgbytes(buffer, UUID_LEN), UUID_LEN);
	RET_POINTER(uuid);
}
Beispiel #15
0
void _fastcall LockHGlobal(ParamBlk *parm)
{
	LPVOID pMem;
	pMem = GlobalLock((HGLOBAL)p1.ev_long);
	if (pMem)
		RET_POINTER(pMem);
	else
	{
		SAVEWIN32ERROR(GlobalLock,GetLastError());
		RAISEERROREX(0);
	}
}
Beispiel #16
0
datum_t
gbt_cash_penalty(PG_FUNC_ARGS)
{
	cashKEY    *origentry = (cashKEY *) D_TO_PTR(((struct gist_entry *) ARG_POINTER(0))->key);
	cashKEY    *newentry = (cashKEY *) D_TO_PTR(((struct gist_entry *) ARG_POINTER(1))->key);
	float	   *result = (float *) ARG_POINTER(2);

	penalty_num(result, origentry->lower, origentry->upper, newentry->lower, newentry->upper);

	RET_POINTER(result);

}
Beispiel #17
0
/*
 * Equality method
 *
 * This is used for both boxes and points.
 */
datum_t gist_box_same(PG_FUNC_ARGS)
{
	BOX *b1 = ARG_BOX_P(0);
	BOX *b2 = ARG_BOX_P(1);
	bool* result = (bool*) ARG_POINTER(2);

	if (b1 && b2)
		*result = D_TO_BOOL(DIRECT_FC2(box_same, PTR_TO_D(b1), PTR_TO_D(b2)));
	else
		*result = (b1 == NULL && b2 == NULL) ? TRUE : FALSE;

	RET_POINTER(result);
}
Beispiel #18
0
// FLL memory allocation functions using FLL's standard heap
void _fastcall AllocMem(ParamBlk *parm)
{
	void *pAlloc = 0;
	__try
	{
		pAlloc = HeapAlloc(ghHeap,HEAP_ZE_FLAG,p1.ev_long);
	}
	__except(SAVEHEAPEXCEPTION()) { }

	ADDDEBUGALLOC(pAlloc,p1.ev_long);

	RET_POINTER(pAlloc);
}
Beispiel #19
0
datum_t tsquery_or(PG_FUNC_ARGS)
{
	TSQuery a = ARG_TSQUERY_COPY(0);
	TSQuery b = ARG_TSQUERY_COPY(1);
	QTNode *res;
	TSQuery query;

	if (a->size == 0) {
		PG_FREE_IF_COPY(a, 1);
		RET_POINTER(b);
	} else if (b->size == 0) {
		PG_FREE_IF_COPY(b, 1);
		RET_POINTER(a);
	}

	res = join_tsqueries(a, b, OP_OR);
	query = QTN2QT(res);

	QTNFree(res);
	PG_FREE_IF_COPY(a, 0);
	PG_FREE_IF_COPY(b, 1);

	RET_POINTER(query);
}
Beispiel #20
0
/*
 *		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);
}
Beispiel #21
0
void _fastcall AllocMemTo(ParamBlk *parm)
{
	void *pAlloc = 0;

	if (!p1.ev_long)
		RAISEERROR(E_INVALIDPARAMS);

	__try
	{
		pAlloc = HeapAlloc(ghHeap,HEAP_ZE_FLAG,p2.ev_long);
	}
	__except(SAVEHEAPEXCEPTION()) { }
	
	if (pAlloc)
		*(void**)p1.ev_long = pAlloc;

	ADDDEBUGALLOC(pAlloc,p2.ev_long);

	RET_POINTER(pAlloc);
}
Beispiel #22
0
void _fastcall ReAllocMem(ParamBlk *parm)
{
	void *pAlloc = 0;
	__try
	{
		if (p1.ev_long)
		{
			pAlloc = HeapReAlloc(ghHeap,HEAP_ZE_FLAG,(void*)p1.ev_long,p2.ev_long);
			REPLACEDEBUGALLOC(p1.ev_long,pAlloc,p2.ev_long);
		}
		else
		{
			pAlloc = HeapAlloc(ghHeap,HEAP_ZE_FLAG,p2.ev_long);
			ADDDEBUGALLOC(pAlloc,p2.ev_long);
		}
    }
	__except(SAVEHEAPEXCEPTION()) { }

	RET_POINTER(pAlloc);
}
Beispiel #23
0
datum_t
gtrgm_compress(PG_FUNC_ARGS)
{
	struct gist_entry  *entry = (struct gist_entry *) ARG_POINTER(0);
	struct gist_entry  *retval = entry;

	if (entry->leafkey)
	{							/* trgm */
		TRGM	   *res;
		text	   *val = D_TO_TEXT_P(entry->key);

		res = generate_trgm(VLA_DATA(val), VLA_SZ(val) - VAR_HDR_SZ);
		retval = (struct gist_entry *) palloc(sizeof(struct gist_entry));
		gistentryinit(*retval, PTR_TO_D(res),
					  entry->rel, entry->page,
					  entry->offset, FALSE);
	}
	else if (ISSIGNKEY(D_TO_PTR(entry->key)) &&
			 !ISALLTRUE(D_TO_PTR(entry->key)))
	{
		int4		i,
					len;
		TRGM	   *res;
		BITVECP		sign = GETSIGN(D_TO_PTR(entry->key));

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

		len = CALCGTSIZE(SIGNKEY | ALLISTRUE, 0);
		res = (TRGM *) palloc(len);
		VLA_SET_SZ_STND(res, len);
		res->flag = SIGNKEY | ALLISTRUE;

		retval = (struct gist_entry *) palloc(sizeof(struct gist_entry));
		gistentryinit(*retval, PTR_TO_D(res),
					  entry->rel, entry->page,
					  entry->offset, FALSE);
	}
Beispiel #24
0
/*
 * The GiST Union method for boxes
 *
 * returns the minimal bounding box that encloses all the entries in entryvec
 */
datum_t gist_box_union(PG_FUNC_ARGS)
{
	struct gist_entry_vector* entryvec = (struct gist_entry_vector*) ARG_POINTER(0);
	int* sizep = (int*) ARG_POINTER(1);
	int numranges, i;
	BOX *cur;
	BOX *pageunion;

	numranges = entryvec->n;
	pageunion = (BOX *) palloc(sizeof(BOX));
	cur = D_TO_BOX_P(entryvec->vector[0].key);
	memcpy((void *)pageunion, (void *)cur, sizeof(BOX));

	for (i = 1; i < numranges; i++) {
		cur = D_TO_BOX_P(entryvec->vector[i].key);
		adjustBox(pageunion, cur);
	}

	*sizep = sizeof(BOX);
	RET_POINTER(pageunion);
}
Beispiel #25
0
datum_t
tsa_rewrite_finish(PG_FUNC_ARGS)
{
	TSQuery		acc = ARG_TSQUERY(0);
	TSQuery		rewrited;

	if (acc == NULL || PG_ARG_ISNULL(0) || acc->size == 0)
	{
		rewrited = (TSQuery) palloc(HDRSIZETQ);
		VLA_SET_SZ_STND(rewrited, HDRSIZETQ);
		rewrited->size = 0;
	}
	else
	{
		rewrited = (TSQuery) palloc(VLA_SZ(acc));
		memcpy(rewrited, acc, VLA_SZ(acc));
		pfree(acc);
	}

	RET_POINTER(rewrited);
}
Beispiel #26
0
/*
 *		int2vectorin			- converts "num num ..." to internal form
 */
datum_t int2vectorin(PG_FUNC_ARGS)
{
	char *intString = ARG_CSTRING(0);
	int2_vector_s *result;
	int n;

	result = (int2_vector_s*) pzalloc(Int2VectorSize(FUNC_MAX_ARGS));
	for (n = 0; *intString && n < FUNC_MAX_ARGS; n++) {
		while (*intString && isspace((unsigned char)*intString))
			intString++;

		if (*intString == '\0')
			break;

		result->values[n] = pg_atoi(intString, sizeof(int16), ' ');
		while (*intString && !isspace((unsigned char)*intString))
			intString++;
	}

	while (*intString && isspace((unsigned char)*intString))
		intString++;

	if (*intString) {
		ereport(ERROR, (
		errcode(E_INVALID_PARAMETER_VALUE),
		errmsg("int2vector has too many elements")));
	}

	VLA_SET_SZ_STND(result, Int2VectorSize(n));
	result->ndim = 1;
	result->dataoffset = 0;	/* never any nulls */
	result->elemtype = INT2OID;
	result->dim1 = n;
	result->lbound1 = 0;

	RET_POINTER(result);
}
Beispiel #27
0
datum_t gin_extract_tsvector(PG_FUNC_ARGS)
{
	TSVector vector = ARG_TSVECTOR(0);
	int32 *nentries = (int32 *) ARG_POINTER(1);
	datum_t *entries = NULL;

	*nentries = vector->size;
	if (vector->size > 0) {
		int i;
		WordEntry *we = ARRPTR(vector);

		entries = (datum_t *) palloc(sizeof(datum_t) * vector->size);
		for (i = 0; i < vector->size; i++) {
			text *txt;

			txt = cstring_to_text_with_len(STRPTR(vector) + we->pos, we->len);
			entries[i] = PTR_TO_D(txt);
			we++;
		}
	}

	PG_FREE_IF_COPY(vector, 0);
	RET_POINTER(entries);
}
Beispiel #28
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);
}
Beispiel #29
0
datum_t
tsa_rewrite_accum(PG_FUNC_ARGS)
{
	TSQuery		acc;
	array_s  *qa;
	TSQuery		q;
	QTNode	   *qex = NULL,
			   *subs = NULL,
			   *acctree = NULL;
	bool		isfind = false;
	datum_t	   *elemsp;
	int			nelemsp;
	struct mctx * aggcontext;
	struct mctx * oldcontext;

	if (!AggCheckCallContext(fcinfo, &aggcontext))
		elog(ERROR, "tsa_rewrite_accum called in non-aggregate context");

	if (PG_ARG_ISNULL(0) || ARG_POINTER(0) == NULL)
	{
		acc = (TSQuery) mctx_alloc(aggcontext, HDRSIZETQ);
		VLA_SET_SZ_STND(acc, HDRSIZETQ);
		acc->size = 0;
	}
	else
		acc = ARG_TSQUERY(0);

	if (PG_ARG_ISNULL(1) || ARG_POINTER(1) == NULL)
		RET_TSQUERY(acc);
	else
		qa = ARG_ARRAY_P_COPY(1);

	if (ARR_NDIM(qa) != 1)
		elog(ERROR, "array must be one-dimensional, not %d dimensions",
			 ARR_NDIM(qa));
	if (ArrayGetNItems(ARR_NDIM(qa), ARR_DIMS(qa)) != 3)
		elog(ERROR, "array must have three elements");
	if (ARR_ELEMTYPE(qa) != TSQUERYOID)
		elog(ERROR, "array must contain tsquery elements");

	deconstruct_array(qa, TSQUERYOID, -1, false, 'i', &elemsp, NULL, &nelemsp);

	q = DatumGetTSQuery(elemsp[0]);
	if (q->size == 0)
	{
		pfree(elemsp);
		RET_POINTER(acc);
	}

	if (!acc->size)
	{
		if (VLA_SZ(acc) > HDRSIZETQ)
		{
			pfree(elemsp);
			RET_POINTER(acc);
		}
		else
			acctree = QT2QTN(GETQUERY(q), GETOPERAND(q));
	}
	else
		acctree = QT2QTN(GETQUERY(acc), GETOPERAND(acc));

	QTNTernary(acctree);
	QTNSort(acctree);

	q = DatumGetTSQuery(elemsp[1]);
	if (q->size == 0)
	{
		pfree(elemsp);
		RET_POINTER(acc);
	}
	qex = QT2QTN(GETQUERY(q), GETOPERAND(q));
	QTNTernary(qex);
	QTNSort(qex);

	q = DatumGetTSQuery(elemsp[2]);
	if (q->size)
		subs = QT2QTN(GETQUERY(q), GETOPERAND(q));

	acctree = findsubquery(acctree, qex, subs, &isfind);

	if (isfind || !acc->size)
	{
		/* pfree( acc ); do not pfree(p), because nodeAgg.c will */
		if (acctree)
		{
			QTNBinary(acctree);
			oldcontext = mctx_switch(aggcontext);
			acc = QTN2QT(acctree);
			mctx_switch(oldcontext);
		}
		else
		{
			acc = (TSQuery) mctx_alloc(aggcontext, HDRSIZETQ);
			VLA_SET_SZ_STND(acc, HDRSIZETQ);
			acc->size = 0;
		}
	}

	pfree(elemsp);
	QTNFree(qex);
	QTNFree(subs);
	QTNFree(acctree);

	RET_TSQUERY(acc);
}
Beispiel #30
0
/*
 * The GiST PickSplit method
 *
 * New linear algorithm, see 'New Linear node_n Splitting Algorithm for R-tree',
 * C.H.Ang and T.C.Tan
 *
 * This is used for both boxes and points.
 */
datum_t gist_box_picksplit(PG_FUNC_ARGS)
{
	struct gist_entry_vector *entryvec = (struct gist_entry_vector *)ARG_POINTER(0);
	struct gist_splitvec *v = (struct gist_splitvec *)ARG_POINTER(1);
	item_id_t i;
	item_id_t *listL;
	item_id_t *listR;
	item_id_t *listB;
	item_id_t *listT;
	BOX *unionL;
	BOX *unionR;
	BOX *unionB;
	BOX *unionT;
	int posL, posR, posB, posT;
	BOX pageunion;
	BOX *cur;
	char direction = ' ';
	bool allisequal = true;
	item_id_t maxoff;
	int nbytes;

	posL = posR = posB = posT = 0;
	maxoff = entryvec->n - 1;

	cur = D_TO_BOX_P(entryvec->vector[FIRST_ITEM_ID].key);
	memcpy((void*) &pageunion, (void*) cur, sizeof(BOX));

	/* find MBR */
	for (i = ITEM_ID_NEXT(FIRST_ITEM_ID); i <= maxoff; i = ITEM_ID_NEXT(i)) {
		cur = D_TO_BOX_P(entryvec->vector[i].key);
		if (allisequal
			&& (pageunion.high.x != cur->high.x
				|| pageunion.high.y != cur->high.y
				|| pageunion.low.x != cur->low.x
				|| pageunion.low.y != cur->low.y))
			allisequal = false;

		adjustBox(&pageunion, cur);
	}

	if (allisequal) {
		/*
		 * All entries are the same
		 */
		fallbackSplit(entryvec, v);
		RET_POINTER(v);
	}

	nbytes = (maxoff + 2) * sizeof(item_id_t);
	listL = (item_id_t *) palloc(nbytes);
	listR = (item_id_t *) palloc(nbytes);
	listB = (item_id_t *) palloc(nbytes);
	listT = (item_id_t *) palloc(nbytes);
	unionL = (BOX *) palloc(sizeof(BOX));
	unionR = (BOX *) palloc(sizeof(BOX));
	unionB = (BOX *) palloc(sizeof(BOX));
	unionT = (BOX *) palloc(sizeof(BOX));

#define ADDLIST( list, unionD, pos, num ) do { \
	if ( pos ) { \
		if ( (unionD)->high.x < cur->high.x ) (unionD)->high.x	= cur->high.x; \
		if ( (unionD)->low.x  > cur->low.x	) (unionD)->low.x	= cur->low.x; \
		if ( (unionD)->high.y < cur->high.y ) (unionD)->high.y	= cur->high.y; \
		if ( (unionD)->low.y  > cur->low.y	) (unionD)->low.y	= cur->low.y; \
	} else { \
			memcpy( (void*)(unionD), (void*) cur, sizeof( BOX ) );	\
	} \
		\
	(list)[pos] = num; \
	(pos)++; \
} while(0)

	for (i = FIRST_ITEM_ID; i <= maxoff; i = ITEM_ID_NEXT(i)) {
		cur = D_TO_BOX_P(entryvec->vector[i].key);
		if (cur->low.x - pageunion.low.x < pageunion.high.x - cur->high.x)
			ADDLIST(listL, unionL, posL, i);
		else
			ADDLIST(listR, unionR, posR, i);

		if (cur->low.y - pageunion.low.y < pageunion.high.y - cur->high.y)
			ADDLIST(listB, unionB, posB, i);
		else
			ADDLIST(listT, unionT, posT, i);
	}

#define LIMIT_RATIO 0.1
#define _IS_BADRATIO(x,y)	( (y) == 0 || (float)(x)/(float)(y) < LIMIT_RATIO )
#define IS_BADRATIO(x,y) 	( _IS_BADRATIO((x),(y)) || _IS_BADRATIO((y),(x)) )

	/* bad disposition, try to split by centers of boxes  */
	if (IS_BADRATIO(posR, posL) && IS_BADRATIO(posT, posB)) {
		double avgCenterX = 0.0;
		double avgCenterY = 0.0;
		double CenterX;
		double CenterY;

		for (i = FIRST_ITEM_ID; i <= maxoff; i = ITEM_ID_NEXT(i)) {
			cur = D_TO_BOX_P(entryvec->vector[i].key);
			avgCenterX += ((double)cur->high.x + (double)cur->low.x) / 2.0;
			avgCenterY += ((double)cur->high.y + (double)cur->low.y) / 2.0;
		}

		avgCenterX /= maxoff;
		avgCenterY /= maxoff;

		posL = posR = posB = posT = 0;
		for (i = FIRST_ITEM_ID; i <= maxoff; i = ITEM_ID_NEXT(i)) {
			cur = D_TO_BOX_P(entryvec->vector[i].key);

			CenterX = ((double)cur->high.x + (double)cur->low.x) / 2.0;
			CenterY = ((double)cur->high.y + (double)cur->low.y) / 2.0;

			if (CenterX < avgCenterX)
				ADDLIST(listL, unionL, posL, i);
			else if (CenterX == avgCenterX) {
				if (posL > posR)
					ADDLIST(listR, unionR, posR, i);
				else
					ADDLIST(listL, unionL, posL, i);
			} else
				ADDLIST(listR, unionR, posR, i);

			if (CenterY < avgCenterY)
				ADDLIST(listB, unionB, posB, i);
			else if (CenterY == avgCenterY) {
				if (posB > posT)
					ADDLIST(listT, unionT, posT, i);
				else
					ADDLIST(listB, unionB, posB, i);
			} else
				ADDLIST(listT, unionT, posT, i);
		}

		if (IS_BADRATIO(posR, posL) && IS_BADRATIO(posT, posB)) {
			fallbackSplit(entryvec, v);
			RET_POINTER(v);
		}
	}

	/* which split more optimal? */
	if (Max(posL, posR) < Max(posB, posT))
		direction = 'x';
	else if (Max(posL, posR) > Max(posB, posT))
		direction = 'y';
	else {
		datum_t interLR = DIRECT_FC2(rt_box_inter, BOX_P_TO_D(unionL), BOX_P_TO_D(unionR));
		datum_t interBT = DIRECT_FC2(rt_box_inter, BOX_P_TO_D(unionB), BOX_P_TO_D(unionT));
		double sizeLR;
		double sizeBT;

		sizeLR = size_box(interLR);
		sizeBT = size_box(interBT);
		if (sizeLR < sizeBT)
			direction = 'x';
		else
			direction = 'y';
	}

	if (direction == 'x')
		chooseLR(v, listL, posL, unionL, listR, posR, unionR);
	else
		chooseLR(v, listB, posB, unionB, listT, posT, unionT);

	RET_POINTER(v);
}