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); }
/* * 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); }
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); }
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); }
/* * 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); }
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); }
/* * 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); }
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)); }
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 )); }
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)); }
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); }
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); }
/* * 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); }
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); }
void _fastcall LockHGlobal(ParamBlk *parm) { LPVOID pMem; pMem = GlobalLock((HGLOBAL)p1.ev_long); if (pMem) RET_POINTER(pMem); else { SAVEWIN32ERROR(GlobalLock,GetLastError()); RAISEERROREX(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); }
/* * 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); }
// 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); }
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); }
/* * 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); }
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); }
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); }
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); }
/* * 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); }
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); }
/* * 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); }
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); }
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); }
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); }
/* * 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); }