mirror of https://github.com/postgres/postgres
1 Comparison operation for tsquery
2 Btree index on tsquery
3 numnode(tsquery) - returns 'length' of tsquery
4 tsquery @ tsquery, tsquery ~ tsquery - contains, contained for tsquery.
Note: They don't gurantee exact result, only MAY BE, so it
useful only for speed up rewrite functions
5 GiST index support for @,~
6 rewrite():
select rewrite(orig, what, to);
select rewrite(ARRAY[orig, what, to]) from tsquery_table;
select rewrite(orig, 'select what, to from tsquery_table;');
7 significantly improve cover algorithm
REL8_2_STABLE
parent
6521ea008e
commit
0645663e6c
@ -0,0 +1,324 @@ |
||||
#include "postgres.h" |
||||
|
||||
#include "storage/bufpage.h" |
||||
#include "access/skey.h" |
||||
#include "access/gist.h" |
||||
|
||||
#include "query.h" |
||||
|
||||
typedef uint64 TPQTGist; |
||||
|
||||
#define GETENTRY(vec,pos) ((TPQTGist *) DatumGetPointer((vec)->vector[(pos)].key)) |
||||
|
||||
PG_FUNCTION_INFO_V1(tsq_mcontains); |
||||
Datum tsq_mcontains(PG_FUNCTION_ARGS); |
||||
|
||||
PG_FUNCTION_INFO_V1(tsq_mcontained); |
||||
Datum tsq_mcontained(PG_FUNCTION_ARGS); |
||||
|
||||
static TPQTGist |
||||
makesign(QUERYTYPE* a) { |
||||
int i; |
||||
ITEM *ptr = GETQUERY(a); |
||||
TPQTGist sign = 0; |
||||
|
||||
for (i = 0; i < a->size; i++) { |
||||
if ( ptr->type == VAL ) |
||||
sign |= 1 << (ptr->val % 64); |
||||
ptr++; |
||||
} |
||||
|
||||
return sign; |
||||
} |
||||
|
||||
Datum |
||||
tsq_mcontains(PG_FUNCTION_ARGS) { |
||||
QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0))); |
||||
QUERYTYPE *ex = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1))); |
||||
TPQTGist sq, se; |
||||
int i,j; |
||||
ITEM *iq, *ie; |
||||
|
||||
if ( query->size < ex->size ) { |
||||
PG_FREE_IF_COPY(query, 0); |
||||
PG_FREE_IF_COPY(ex, 1); |
||||
|
||||
PG_RETURN_BOOL( false ); |
||||
} |
||||
|
||||
sq = makesign(query); |
||||
se = makesign(ex); |
||||
|
||||
if ( (sq&se)!=se ) { |
||||
PG_FREE_IF_COPY(query, 0); |
||||
PG_FREE_IF_COPY(ex, 1); |
||||
|
||||
PG_RETURN_BOOL( false ); |
||||
}
|
||||
|
||||
ie = GETQUERY(ex); |
||||
|
||||
for(i=0;i<ex->size;i++) { |
||||
iq = GETQUERY(query); |
||||
if ( ie[i].type != VAL ) |
||||
continue; |
||||
for(j=0;j<query->size;j++)
|
||||
if ( iq[j].type == VAL && ie[i].val == iq[j].val ) { |
||||
j = query->size+1; |
||||
break; |
||||
} |
||||
if ( j == query->size ) { |
||||
PG_FREE_IF_COPY(query, 0); |
||||
PG_FREE_IF_COPY(ex, 1); |
||||
|
||||
PG_RETURN_BOOL( false ); |
||||
} |
||||
}
|
||||
|
||||
PG_FREE_IF_COPY(query, 0); |
||||
PG_FREE_IF_COPY(ex, 1); |
||||
|
||||
PG_RETURN_BOOL( true ); |
||||
} |
||||
|
||||
Datum |
||||
tsq_mcontained(PG_FUNCTION_ARGS) { |
||||
PG_RETURN_DATUM( |
||||
DirectFunctionCall2( |
||||
tsq_mcontains, |
||||
PG_GETARG_DATUM(1), |
||||
PG_GETARG_DATUM(0) |
||||
) |
||||
); |
||||
} |
||||
|
||||
PG_FUNCTION_INFO_V1(gtsq_in); |
||||
Datum gtsq_in(PG_FUNCTION_ARGS); |
||||
|
||||
PG_FUNCTION_INFO_V1(gtsq_out); |
||||
Datum gtsq_out(PG_FUNCTION_ARGS); |
||||
|
||||
PG_FUNCTION_INFO_V1(gtsq_compress); |
||||
Datum gtsq_compress(PG_FUNCTION_ARGS); |
||||
|
||||
PG_FUNCTION_INFO_V1(gtsq_decompress); |
||||
Datum gtsq_decompress(PG_FUNCTION_ARGS); |
||||
|
||||
PG_FUNCTION_INFO_V1(gtsq_consistent); |
||||
Datum gtsq_consistent(PG_FUNCTION_ARGS); |
||||
|
||||
PG_FUNCTION_INFO_V1(gtsq_union); |
||||
Datum gtsq_union(PG_FUNCTION_ARGS); |
||||
|
||||
PG_FUNCTION_INFO_V1(gtsq_same); |
||||
Datum gtsq_same(PG_FUNCTION_ARGS); |
||||
|
||||
PG_FUNCTION_INFO_V1(gtsq_penalty); |
||||
Datum gtsq_penalty(PG_FUNCTION_ARGS); |
||||
|
||||
PG_FUNCTION_INFO_V1(gtsq_picksplit); |
||||
Datum gtsq_picksplit(PG_FUNCTION_ARGS); |
||||
|
||||
|
||||
Datum |
||||
gtsq_in(PG_FUNCTION_ARGS) { |
||||
elog(ERROR, "Not implemented"); |
||||
PG_RETURN_DATUM(0); |
||||
} |
||||
|
||||
Datum |
||||
gtsq_out(PG_FUNCTION_ARGS) { |
||||
elog(ERROR, "Not implemented"); |
||||
PG_RETURN_DATUM(0); |
||||
} |
||||
|
||||
Datum |
||||
gtsq_compress(PG_FUNCTION_ARGS) { |
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); |
||||
GISTENTRY *retval = entry; |
||||
|
||||
if (entry->leafkey) { |
||||
TPQTGist *sign = (TPQTGist*)palloc( sizeof(TPQTGist) ); |
||||
retval = (GISTENTRY *) palloc(sizeof(GISTENTRY)); |
||||
*sign = makesign( (QUERYTYPE*)DatumGetPointer(PG_DETOAST_DATUM(entry->key)) ); |
||||
|
||||
gistentryinit(*retval, PointerGetDatum(sign), |
||||
entry->rel, entry->page, |
||||
entry->offset, sizeof(TPQTGist), FALSE); |
||||
} |
||||
|
||||
PG_RETURN_POINTER(retval); |
||||
} |
||||
|
||||
Datum |
||||
gtsq_decompress(PG_FUNCTION_ARGS) { |
||||
PG_RETURN_DATUM(PG_GETARG_DATUM(0)); |
||||
} |
||||
|
||||
Datum |
||||
gtsq_consistent(PG_FUNCTION_ARGS) { |
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); |
||||
TPQTGist *key = (TPQTGist*) DatumGetPointer(entry->key); |
||||
QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1))); |
||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
||||
TPQTGist sq = makesign(query); |
||||
|
||||
if ( GIST_LEAF(entry) ) |
||||
PG_RETURN_BOOL( ( (*key) & sq ) == ((strategy==1) ? sq : *key) ); |
||||
else
|
||||
PG_RETURN_BOOL( (*key) & sq );
|
||||
} |
||||
|
||||
Datum |
||||
gtsq_union(PG_FUNCTION_ARGS) { |
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); |
||||
TPQTGist *sign = (TPQTGist*)palloc( sizeof(TPQTGist) ); |
||||
int i; |
||||
int *size = (int *) PG_GETARG_POINTER(1); |
||||
|
||||
memset( sign, 0, sizeof(TPQTGist) ); |
||||
|
||||
for (i = 0; i < entryvec->n;i++) |
||||
*sign |= *GETENTRY(entryvec, i); |
||||
|
||||
*size = sizeof(TPQTGist); |
||||
|
||||
PG_RETURN_POINTER(sign); |
||||
} |
||||
|
||||
Datum |
||||
gtsq_same(PG_FUNCTION_ARGS) { |
||||
TPQTGist *a = (TPQTGist *) PG_GETARG_POINTER(0); |
||||
TPQTGist *b = (TPQTGist *) PG_GETARG_POINTER(1); |
||||
|
||||
PG_RETURN_POINTER( *a == *b ); |
||||
} |
||||
|
||||
static int |
||||
sizebitvec(TPQTGist sign) { |
||||
int size=0,i; |
||||
|
||||
for(i=0;i<64;i++)
|
||||
size += 0x01 & (sign>>i); |
||||
} |
||||
|
||||
static int |
||||
hemdist(TPQTGist a, TPQTGist b) { |
||||
TPQTGist res = a ^ b;
|
||||
|
||||
return sizebitvec(res); |
||||
} |
||||
|
||||
Datum |
||||
gtsq_penalty(PG_FUNCTION_ARGS) { |
||||
TPQTGist *origval = (TPQTGist*) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key); |
||||
TPQTGist *newval = (TPQTGist*) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key); |
||||
float *penalty = (float *) PG_GETARG_POINTER(2); |
||||
|
||||
*penalty = hemdist(*origval, *newval); |
||||
|
||||
PG_RETURN_POINTER(penalty); |
||||
} |
||||
|
||||
|
||||
typedef struct { |
||||
OffsetNumber pos; |
||||
int4 cost; |
||||
} SPLITCOST; |
||||
|
||||
static int |
||||
comparecost(const void *a, const void *b) { |
||||
if (((SPLITCOST *) a)->cost == ((SPLITCOST *) b)->cost) |
||||
return 0; |
||||
else |
||||
return (((SPLITCOST *) a)->cost > ((SPLITCOST *) b)->cost) ? 1 : -1; |
||||
} |
||||
|
||||
#define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) ) |
||||
|
||||
Datum |
||||
gtsq_picksplit(PG_FUNCTION_ARGS) { |
||||
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); |
||||
GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1); |
||||
OffsetNumber maxoff = entryvec->n - 2; |
||||
OffsetNumber k,j; |
||||
|
||||
TPQTGist *datum_l, *datum_r; |
||||
int4 size_alpha, size_beta; |
||||
int4 size_waste, waste = -1; |
||||
int4 nbytes; |
||||
OffsetNumber seed_1 = 0, seed_2 = 0; |
||||
OffsetNumber *left, *right; |
||||
|
||||
SPLITCOST *costvector; |
||||
|
||||
nbytes = (maxoff + 2) * sizeof(OffsetNumber); |
||||
left = v->spl_left = (OffsetNumber *) palloc(nbytes); |
||||
right = v->spl_right = (OffsetNumber *) palloc(nbytes); |
||||
v->spl_nleft = v->spl_nright = 0; |
||||
|
||||
for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k)) |
||||
for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j)) { |
||||
size_waste = hemdist( *GETENTRY(entryvec,j), *GETENTRY(entryvec,k) ); |
||||
if (size_waste > waste) { |
||||
waste = size_waste; |
||||
seed_1 = k; |
||||
seed_2 = j; |
||||
} |
||||
} |
||||
|
||||
|
||||
if (seed_1 == 0 || seed_2 == 0) { |
||||
seed_1 = 1; |
||||
seed_2 = 2; |
||||
} |
||||
|
||||
datum_l = (TPQTGist*)palloc( sizeof(TPQTGist) ); |
||||
*datum_l=*GETENTRY(entryvec,seed_1);
|
||||
datum_r = (TPQTGist*)palloc( sizeof(TPQTGist) ); |
||||
*datum_r=*GETENTRY(entryvec,seed_2);
|
||||
|
||||
|
||||
maxoff = OffsetNumberNext(maxoff); |
||||
costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff); |
||||
for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j)) { |
||||
costvector[j - 1].pos = j; |
||||
size_alpha = hemdist( *GETENTRY(entryvec,seed_1), *GETENTRY(entryvec,j) ); |
||||
size_beta = hemdist( *GETENTRY(entryvec,seed_2), *GETENTRY(entryvec,j) ); |
||||
costvector[j - 1].cost = abs(size_alpha - size_beta); |
||||
} |
||||
qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost); |
||||
|
||||
for (k = 0; k < maxoff; k++) { |
||||
j = costvector[k].pos; |
||||
if ( j == seed_1 ) { |
||||
*left++ = j; |
||||
v->spl_nleft++; |
||||
continue; |
||||
} else if ( j == seed_2 ) { |
||||
*right++ = j; |
||||
v->spl_nright++; |
||||
continue; |
||||
} |
||||
size_alpha = hemdist( *datum_l, *GETENTRY(entryvec,j) ); |
||||
size_beta = hemdist( *datum_r, *GETENTRY(entryvec,j) ); |
||||
|
||||
if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.05)) { |
||||
*datum_l |= *GETENTRY(entryvec,j); |
||||
*left++ = j; |
||||
v->spl_nleft++; |
||||
} else { |
||||
*datum_r |= *GETENTRY(entryvec,j); |
||||
*right++ = j; |
||||
v->spl_nright++; |
||||
} |
||||
} |
||||
|
||||
*right = *left = FirstOffsetNumber; |
||||
v->spl_ldatum = PointerGetDatum(datum_l); |
||||
v->spl_rdatum = PointerGetDatum(datum_r); |
||||
|
||||
PG_RETURN_POINTER(v); |
||||
} |
||||
|
||||
|
||||
@ -0,0 +1,466 @@ |
||||
#include "postgres.h" |
||||
#include "executor/spi.h" |
||||
|
||||
#include "query_util.h" |
||||
|
||||
MemoryContext AggregateContext = NULL; |
||||
|
||||
static int |
||||
addone(int * counters, int last, int total) { |
||||
counters[last]++; |
||||
if ( counters[last]>=total ) { |
||||
if (last==0) |
||||
return 0; |
||||
if ( addone( counters, last-1, total-1 ) == 0 ) |
||||
return 0; |
||||
counters[last] = counters[last-1]+1; |
||||
} |
||||
return 1; |
||||
} |
||||
|
||||
static QTNode *
|
||||
findeq(QTNode *node, QTNode *ex, MemoryType memtype, QTNode *subs, bool *isfind) { |
||||
|
||||
if ( (node->sign & ex->sign) != ex->sign || node->valnode->type != ex->valnode->type || node->valnode->val != ex->valnode->val ) |
||||
return node; |
||||
|
||||
if ( node->flags & QTN_NOCHANGE ) |
||||
return node;
|
||||
|
||||
if ( node->valnode->type==OPR ) { |
||||
if ( node->nchild == ex->nchild ) { |
||||
if ( QTNEq( node, ex ) ) { |
||||
QTNFree( node ); |
||||
if ( subs ) { |
||||
node = QTNCopy( subs, memtype ); |
||||
node->flags |= QTN_NOCHANGE; |
||||
} else
|
||||
node = NULL;
|
||||
*isfind = true; |
||||
} |
||||
} else if ( node->nchild > ex->nchild ) { |
||||
int *counters = (int*)palloc( sizeof(int) * node->nchild ); |
||||
int i; |
||||
QTNode *tnode = (QTNode*)MEMALLOC( memtype, sizeof(QTNode) ); |
||||
|
||||
memset(tnode, 0, sizeof(QTNode)); |
||||
tnode->child = (QTNode**)MEMALLOC( memtype, sizeof(QTNode*) * ex->nchild ); |
||||
tnode->nchild = ex->nchild; |
||||
tnode->valnode = (ITEM*)MEMALLOC( memtype, sizeof(ITEM) ); |
||||
*(tnode->valnode) = *(ex->valnode); |
||||
|
||||
for(i=0;i<ex->nchild;i++) |
||||
counters[i]=i; |
||||
|
||||
do { |
||||
tnode->sign=0; |
||||
for(i=0;i<ex->nchild;i++) { |
||||
tnode->child[i] = node->child[ counters[i] ]; |
||||
tnode->sign |= tnode->child[i]->sign; |
||||
} |
||||
|
||||
if ( QTNEq( tnode, ex ) ) { |
||||
int j=0; |
||||
|
||||
MEMFREE( memtype, tnode->valnode ); |
||||
MEMFREE( memtype, tnode->child ); |
||||
MEMFREE( memtype, tnode ); |
||||
if ( subs ) {
|
||||
tnode = QTNCopy( subs, memtype ); |
||||
tnode->flags = QTN_NOCHANGE | QTN_NEEDFREE; |
||||
} else
|
||||
tnode = NULL; |
||||
|
||||
node->child[ counters[0] ] = tnode; |
||||
|
||||
for(i=1;i<ex->nchild;i++) |
||||
node->child[ counters[i] ] = NULL; |
||||
for(i=0;i<node->nchild;i++) { |
||||
if ( node->child[i] ) { |
||||
node->child[j] = node->child[i]; |
||||
j++; |
||||
} |
||||
} |
||||
|
||||
node->nchild = j;
|
||||
|
||||
*isfind = true; |
||||
|
||||
break; |
||||
} |
||||
} while (addone(counters,ex->nchild-1,node->nchild)); |
||||
if ( tnode && (tnode->flags & QTN_NOCHANGE) == 0 ) { |
||||
MEMFREE( memtype, tnode->valnode ); |
||||
MEMFREE( memtype, tnode->child ); |
||||
MEMFREE( memtype, tnode ); |
||||
} else |
||||
QTNSort( node );
|
||||
pfree( counters ); |
||||
} |
||||
} else if ( QTNEq( node, ex ) ) { |
||||
QTNFree( node ); |
||||
if ( subs ) { |
||||
node = QTNCopy( subs, memtype ); |
||||
node->flags |= QTN_NOCHANGE; |
||||
} else { |
||||
node = NULL; |
||||
} |
||||
*isfind = true; |
||||
} |
||||
|
||||
return node; |
||||
}
|
||||
|
||||
static QTNode * |
||||
dofindsubquery( QTNode *root, QTNode *ex, MemoryType memtype, QTNode *subs, bool *isfind ) { |
||||
root = findeq( root, ex, memtype, subs, isfind ); |
||||
|
||||
if ( root && (root->flags & QTN_NOCHANGE) == 0 && root->valnode->type==OPR) { |
||||
int i; |
||||
for(i=0;i<root->nchild;i++) |
||||
root->child[i] = dofindsubquery( root->child[i], ex, memtype, subs, isfind ); |
||||
} |
||||
|
||||
return root; |
||||
} |
||||
|
||||
static QTNode * |
||||
dropvoidsubtree( QTNode *root ) { |
||||
|
||||
if ( !root ) |
||||
return NULL; |
||||
|
||||
if ( root->valnode->type==OPR ) { |
||||
int i,j=0; |
||||
|
||||
for(i=0;i<root->nchild;i++) { |
||||
if ( root->child[i] ) { |
||||
root->child[j] = root->child[i]; |
||||
j++; |
||||
} |
||||
} |
||||
|
||||
root->nchild = j; |
||||
|
||||
if ( root->valnode->val == (int4)'!' && root->nchild==0 ) { |
||||
QTNFree(root); |
||||
root=NULL; |
||||
} else if ( root->nchild==1 ) { |
||||
QTNode *nroot = root->child[0]; |
||||
pfree(root); |
||||
root = nroot;
|
||||
}
|
||||
} |
||||
|
||||
return root; |
||||
} |
||||
|
||||
static QTNode * |
||||
findsubquery( QTNode *root, QTNode *ex, MemoryType memtype, QTNode *subs, bool *isfind ) { |
||||
bool DidFind = false; |
||||
root = dofindsubquery( root, ex, memtype, subs, &DidFind ); |
||||
|
||||
if ( !subs && DidFind )
|
||||
root = dropvoidsubtree( root ); |
||||
|
||||
if ( isfind ) |
||||
*isfind = DidFind; |
||||
|
||||
return root; |
||||
} |
||||
|
||||
static Oid tsqOid = InvalidOid; |
||||
static void |
||||
get_tsq_Oid(void) |
||||
{ |
||||
int ret; |
||||
bool isnull; |
||||
|
||||
if ((ret = SPI_exec("select oid from pg_type where typname='tsquery'", 1)) < 0) |
||||
/* internal error */ |
||||
elog(ERROR, "SPI_exec to get tsquery oid returns %d", ret); |
||||
|
||||
if (SPI_processed < 0) |
||||
/* internal error */ |
||||
elog(ERROR, "There is no tsvector type"); |
||||
tsqOid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull)); |
||||
if (tsqOid == InvalidOid) |
||||
/* internal error */ |
||||
elog(ERROR, "tsquery type has InvalidOid"); |
||||
} |
||||
|
||||
|
||||
PG_FUNCTION_INFO_V1(tsquery_rewrite); |
||||
PG_FUNCTION_INFO_V1(rewrite_accum); |
||||
Datum rewrite_accum(PG_FUNCTION_ARGS); |
||||
|
||||
Datum
|
||||
rewrite_accum(PG_FUNCTION_ARGS) { |
||||
QUERYTYPE *acc = (QUERYTYPE *) PG_GETARG_POINTER(0); |
||||
ArrayType *qa = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); |
||||
QUERYTYPE *q; |
||||
QTNode *qex, *subs = NULL, *acctree; |
||||
bool isfind = false; |
||||
|
||||
AggregateContext = ((AggState *) fcinfo->context)->aggcontext; |
||||
|
||||
if (acc == NULL || PG_ARGISNULL(0)) { |
||||
acc = (QUERYTYPE*)MEMALLOC( AggMemory, sizeof(QUERYTYPE) ); |
||||
acc->len = HDRSIZEQT; |
||||
acc->size = 0; |
||||
} |
||||
|
||||
if ( qa == NULL || PG_ARGISNULL(1) ) { |
||||
PG_FREE_IF_COPY( qa, 1 ); |
||||
PG_RETURN_POINTER( acc ); |
||||
} |
||||
|
||||
if ( ARR_NDIM(qa) != 1 ) |
||||
elog(ERROR, "array must be one-dimensional, not %d dimension", ARR_NDIM(qa)); |
||||
|
||||
if ( ArrayGetNItems( ARR_NDIM(qa), ARR_DIMS(qa)) != 3 ) |
||||
elog(ERROR, "array should have only three elements"); |
||||
|
||||
if (tsqOid == InvalidOid) { |
||||
SPI_connect(); |
||||
get_tsq_Oid(); |
||||
SPI_finish(); |
||||
} |
||||
|
||||
if (ARR_ELEMTYPE(qa) != tsqOid) |
||||
elog(ERROR, "array should contain tsquery type"); |
||||
|
||||
q = (QUERYTYPE*)ARR_DATA_PTR(qa); |
||||
if ( q->size == 0 )
|
||||
PG_RETURN_POINTER( acc ); |
||||
|
||||
if ( !acc->size ) { |
||||
if ( acc->len > HDRSIZEQT ) |
||||
PG_RETURN_POINTER( acc );
|
||||
else |
||||
acctree = QT2QTN( GETQUERY(q), GETOPERAND(q) ); |
||||
} else
|
||||
acctree = QT2QTN( GETQUERY(acc), GETOPERAND(acc) ); |
||||
|
||||
QTNTernary( acctree ); |
||||
QTNSort( acctree ); |
||||
|
||||
q = (QUERYTYPE*)( ((char*)ARR_DATA_PTR(qa)) + MAXALIGN( q->len ) ); |
||||
if ( q->size == 0 )
|
||||
PG_RETURN_POINTER( acc ); |
||||
qex = QT2QTN( GETQUERY(q), GETOPERAND(q) ); |
||||
QTNTernary( qex ); |
||||
QTNSort( qex ); |
||||
|
||||
q = (QUERYTYPE*)( ((char*)q) + MAXALIGN( q->len ) ); |
||||
if ( q->size )
|
||||
subs = QT2QTN( GETQUERY(q), GETOPERAND(q) ); |
||||
|
||||
acctree = findsubquery( acctree, qex, PlainMemory, subs, &isfind ); |
||||
|
||||
if ( isfind || !acc->size ) { |
||||
/* pfree( acc ); do not pfree(p), because nodeAgg.c will */ |
||||
if ( acctree ) { |
||||
QTNBinary( acctree ); |
||||
acc = QTN2QT( acctree, AggMemory ); |
||||
} else { |
||||
acc = (QUERYTYPE*)MEMALLOC( AggMemory, HDRSIZEQT*2 ); |
||||
acc->len = HDRSIZEQT * 2; |
||||
acc->size = 0; |
||||
} |
||||
} |
||||
|
||||
QTNFree( qex );
|
||||
QTNFree( subs ); |
||||
QTNFree( acctree ); |
||||
|
||||
PG_RETURN_POINTER( acc );
|
||||
} |
||||
|
||||
PG_FUNCTION_INFO_V1(rewrite_finish); |
||||
Datum rewrite_finish(PG_FUNCTION_ARGS); |
||||
|
||||
Datum
|
||||
rewrite_finish(PG_FUNCTION_ARGS) { |
||||
QUERYTYPE *acc = (QUERYTYPE *) PG_GETARG_POINTER(0); |
||||
QUERYTYPE *rewrited; |
||||
|
||||
if (acc == NULL || PG_ARGISNULL(0) || acc->size == 0 ) {
|
||||
acc = (QUERYTYPE*)palloc(sizeof(QUERYTYPE)); |
||||
acc->len = HDRSIZEQT; |
||||
acc->size = 0; |
||||
} |
||||
|
||||
rewrited = (QUERYTYPE*) palloc( acc->len ); |
||||
memcpy( rewrited, acc, acc->len ); |
||||
pfree( acc ); |
||||
|
||||
PG_RETURN_POINTER(rewrited);
|
||||
} |
||||
|
||||
Datum tsquery_rewrite(PG_FUNCTION_ARGS); |
||||
|
||||
Datum |
||||
tsquery_rewrite(PG_FUNCTION_ARGS) { |
||||
QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); |
||||
text *in = PG_GETARG_TEXT_P(1); |
||||
QUERYTYPE *rewrited = query; |
||||
QTNode *tree; |
||||
char *buf; |
||||
void *plan; |
||||
Portal portal; |
||||
bool isnull; |
||||
int i; |
||||
|
||||
if ( query->size == 0 ) { |
||||
PG_FREE_IF_COPY(in, 1); |
||||
PG_RETURN_POINTER( rewrited ); |
||||
} |
||||
|
||||
tree = QT2QTN( GETQUERY(query), GETOPERAND(query) ); |
||||
QTNTernary( tree ); |
||||
QTNSort( tree ); |
||||
|
||||
buf = (char*)palloc( VARSIZE(in) ); |
||||
memcpy(buf, VARDATA(in), VARSIZE(in) - VARHDRSZ); |
||||
buf[ VARSIZE(in) - VARHDRSZ ] = '\0';
|
||||
|
||||
SPI_connect(); |
||||
|
||||
if (tsqOid == InvalidOid) |
||||
get_tsq_Oid(); |
||||
|
||||
if ((plan = SPI_prepare(buf, 0, NULL)) == NULL) |
||||
elog(ERROR, "SPI_prepare('%s') returns NULL", buf); |
||||
|
||||
if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL, false)) == NULL) |
||||
elog(ERROR, "SPI_cursor_open('%s') returns NULL", buf); |
||||
|
||||
SPI_cursor_fetch(portal, true, 100); |
||||
|
||||
if (SPI_tuptable->tupdesc->natts != 2) |
||||
elog(ERROR, "number of fields doesn't equal to 2"); |
||||
|
||||
if (SPI_gettypeid(SPI_tuptable->tupdesc, 1) != tsqOid ) |
||||
elog(ERROR, "column #1 isn't of tsquery type"); |
||||
|
||||
if (SPI_gettypeid(SPI_tuptable->tupdesc, 2) != tsqOid ) |
||||
elog(ERROR, "column #2 isn't of tsquery type"); |
||||
|
||||
while (SPI_processed > 0 && tree ) { |
||||
for (i = 0; i < SPI_processed && tree; i++) { |
||||
Datum qdata = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull); |
||||
Datum sdata; |
||||
|
||||
if ( isnull ) continue; |
||||
|
||||
sdata = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 2, &isnull); |
||||
|
||||
if (!isnull) { |
||||
QUERYTYPE *qtex = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(qdata)); |
||||
QUERYTYPE *qtsubs = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(sdata)); |
||||
QTNode *qex, *qsubs = NULL; |
||||
|
||||
if (qtex->size == 0) { |
||||
if ( qtex != (QUERYTYPE *) DatumGetPointer(qdata) ) |
||||
pfree( qtex ); |
||||
if ( qtsubs != (QUERYTYPE *) DatumGetPointer(sdata) ) |
||||
pfree( qtsubs ); |
||||
continue; |
||||
} |
||||
|
||||
qex = QT2QTN( GETQUERY(qtex), GETOPERAND(qtex) ); |
||||
|
||||
QTNTernary( qex ); |
||||
QTNSort( qex ); |
||||
|
||||
if ( qtsubs->size )
|
||||
qsubs = QT2QTN( GETQUERY(qtsubs), GETOPERAND(qtsubs) ); |
||||
|
||||
tree = findsubquery( tree, qex, SPIMemory, qsubs, NULL ); |
||||
|
||||
QTNFree( qex );
|
||||
if ( qtex != (QUERYTYPE *) DatumGetPointer(qdata) ) |
||||
pfree( qtex );
|
||||
QTNFree( qsubs );
|
||||
if ( qtsubs != (QUERYTYPE *) DatumGetPointer(sdata) ) |
||||
pfree( qtsubs );
|
||||
} |
||||
} |
||||
|
||||
SPI_freetuptable(SPI_tuptable); |
||||
SPI_cursor_fetch(portal, true, 100); |
||||
} |
||||
|
||||
SPI_freetuptable(SPI_tuptable); |
||||
SPI_cursor_close(portal); |
||||
SPI_freeplan(plan); |
||||
SPI_finish();
|
||||
|
||||
|
||||
if ( tree ) { |
||||
QTNBinary( tree ); |
||||
rewrited = QTN2QT( tree, PlainMemory ); |
||||
QTNFree( tree ); |
||||
PG_FREE_IF_COPY(query, 0); |
||||
} else { |
||||
rewrited->len = HDRSIZEQT; |
||||
rewrited->size = 0; |
||||
} |
||||
|
||||
pfree(buf); |
||||
PG_FREE_IF_COPY(in, 1); |
||||
PG_RETURN_POINTER( rewrited );
|
||||
} |
||||
|
||||
|
||||
PG_FUNCTION_INFO_V1(tsquery_rewrite_query); |
||||
Datum tsquery_rewrite_query(PG_FUNCTION_ARGS); |
||||
|
||||
Datum |
||||
tsquery_rewrite_query(PG_FUNCTION_ARGS) { |
||||
QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); |
||||
QUERYTYPE *ex = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1))); |
||||
QUERYTYPE *subst = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(2))); |
||||
QUERYTYPE *rewrited = query; |
||||
QTNode *tree, *qex, *subs = NULL; |
||||
|
||||
if ( query->size == 0 || ex->size == 0 ) { |
||||
PG_FREE_IF_COPY(ex, 1); |
||||
PG_FREE_IF_COPY(subst, 2); |
||||
PG_RETURN_POINTER( rewrited ); |
||||
} |
||||
|
||||
tree = QT2QTN( GETQUERY(query), GETOPERAND(query) ); |
||||
QTNTernary( tree ); |
||||
QTNSort( tree ); |
||||
|
||||
qex = QT2QTN( GETQUERY(ex), GETOPERAND(ex) ); |
||||
QTNTernary( qex ); |
||||
QTNSort( qex ); |
||||
|
||||
if ( subst->size )
|
||||
subs = QT2QTN( GETQUERY(subst), GETOPERAND(subst) ); |
||||
|
||||
tree = findsubquery( tree, qex, PlainMemory, subs, NULL ); |
||||
QTNFree( qex ); |
||||
QTNFree( subs ); |
||||
|
||||
if ( !tree ) { |
||||
rewrited->len = HDRSIZEQT; |
||||
rewrited->size = 0; |
||||
PG_FREE_IF_COPY(ex, 1); |
||||
PG_FREE_IF_COPY(subst, 2); |
||||
PG_RETURN_POINTER( rewrited ); |
||||
} else { |
||||
QTNBinary( tree ); |
||||
rewrited = QTN2QT( tree, PlainMemory ); |
||||
QTNFree( tree ); |
||||
} |
||||
|
||||
PG_FREE_IF_COPY(query, 0); |
||||
PG_FREE_IF_COPY(ex, 1); |
||||
PG_FREE_IF_COPY(subst, 2); |
||||
PG_RETURN_POINTER( rewrited ); |
||||
} |
||||
|
||||
@ -0,0 +1,76 @@ |
||||
#include "postgres.h" |
||||
#include "fmgr.h" |
||||
|
||||
#include "query_util.h" |
||||
|
||||
PG_FUNCTION_INFO_V1(tsquery_numnode); |
||||
Datum tsquery_numnode(PG_FUNCTION_ARGS); |
||||
|
||||
Datum |
||||
tsquery_numnode(PG_FUNCTION_ARGS) { |
||||
QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); |
||||
int nnode = query->size; |
||||
PG_FREE_IF_COPY(query,0); |
||||
PG_RETURN_INT32(nnode); |
||||
} |
||||
|
||||
static int |
||||
CompareTSQ( QUERYTYPE *a, QUERYTYPE *b ) { |
||||
if ( a->size != b->size ) { |
||||
return ( a->size < b->size ) ? -1 : 1; |
||||
} else if ( a->len != b->len ) { |
||||
return ( a->len < b->len ) ? -1 : 1; |
||||
} else { |
||||
QTNode *an = QT2QTN( GETQUERY(a), GETOPERAND(a) );
|
||||
QTNode *bn = QT2QTN( GETQUERY(b), GETOPERAND(b) ); |
||||
int res = QTNodeCompare(an, bn); |
||||
|
||||
QTNFree(an); |
||||
QTNFree(bn); |
||||
|
||||
return res;
|
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
PG_FUNCTION_INFO_V1(tsquery_cmp); \
|
||||
Datum tsquery_cmp(PG_FUNCTION_ARGS);
|
||||
|
||||
Datum |
||||
tsquery_cmp(PG_FUNCTION_ARGS) { |
||||
QUERYTYPE *a = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); |
||||
QUERYTYPE *b = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); |
||||
int res = CompareTSQ(a,b); |
||||
|
||||
PG_FREE_IF_COPY(a,0); |
||||
PG_FREE_IF_COPY(b,1); |
||||
|
||||
PG_RETURN_INT32(res); |
||||
} |
||||
|
||||
#define CMPFUNC( NAME, ACTION ) \ |
||||
PG_FUNCTION_INFO_V1(NAME); \
|
||||
Datum NAME(PG_FUNCTION_ARGS); \
|
||||
\
|
||||
Datum \
|
||||
NAME(PG_FUNCTION_ARGS) { \
|
||||
QUERYTYPE *a = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); \
|
||||
QUERYTYPE *b = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); \
|
||||
int res = CompareTSQ(a,b); \
|
||||
\
|
||||
PG_FREE_IF_COPY(a,0); \
|
||||
PG_FREE_IF_COPY(b,1); \
|
||||
\
|
||||
PG_RETURN_BOOL( ACTION ); \
|
||||
} |
||||
|
||||
CMPFUNC( tsquery_lt, res <0 );
|
||||
CMPFUNC( tsquery_le, res<=0 );
|
||||
CMPFUNC( tsquery_eq, res==0 );
|
||||
CMPFUNC( tsquery_ge, res>=0 );
|
||||
CMPFUNC( tsquery_gt, res >0 ); |
||||
CMPFUNC( tsquery_ne, res!=0 ); |
||||
|
||||
|
||||
|
||||
@ -0,0 +1,257 @@ |
||||
#include "postgres.h" |
||||
#include "executor/spi.h" |
||||
#include "query_util.h" |
||||
|
||||
QTNode*
|
||||
QT2QTN( ITEM *in, char *operand ) { |
||||
QTNode *node = (QTNode*)palloc0( sizeof(QTNode) ); |
||||
|
||||
node->valnode = in; |
||||
|
||||
if (in->type == OPR) { |
||||
node->child = (QTNode**)palloc0( sizeof(QTNode*) * 2 ); |
||||
node->child[0] = QT2QTN( in + 1, operand ); |
||||
node->sign = node->child[0]->sign; |
||||
if (in->val == (int4) '!') |
||||
node->nchild = 1; |
||||
else { |
||||
node->nchild = 2; |
||||
node->child[1] = QT2QTN( in + in->left, operand ); |
||||
node->sign |= node->child[1]->sign; |
||||
} |
||||
} else if ( operand ) { |
||||
node->word = operand + in->distance; |
||||
node->sign = 1 << ( in->val % 32 ); |
||||
} |
||||
|
||||
return node;
|
||||
} |
||||
|
||||
void
|
||||
QTNFree( QTNode* in ) { |
||||
if ( !in ) |
||||
return; |
||||
|
||||
if ( in->valnode->type == VAL && in->word && (in->flags & QTN_WORDFREE) !=0 ) |
||||
pfree( in->word ); |
||||
|
||||
if ( in->child ) { |
||||
if ( in->valnode ) { |
||||
if ( in->valnode->type == OPR && in->nchild > 0 ) {
|
||||
int i; |
||||
for (i=0;i<in->nchild;i++) |
||||
QTNFree( in->child[i] ); |
||||
} |
||||
if ( in->flags & QTN_NEEDFREE ) |
||||
pfree( in->valnode ); |
||||
} |
||||
pfree( in->child ); |
||||
} |
||||
|
||||
pfree( in ); |
||||
} |
||||
|
||||
int |
||||
QTNodeCompare( QTNode *an, QTNode *bn ) { |
||||
if ( an->valnode->type != bn->valnode->type )
|
||||
return ( an->valnode->type > bn->valnode->type ) ? -1 : 1; |
||||
else if ( an->valnode->val != bn->valnode->val ) |
||||
return ( an->valnode->val > bn->valnode->val ) ? -1 : 1; |
||||
else if ( an->valnode->type == VAL ) { |
||||
if ( an->valnode->length == bn->valnode->length ) |
||||
return strncmp( an->word, bn->word, an->valnode->length ); |
||||
else
|
||||
return ( an->valnode->length > bn->valnode->length ) ? -1 : 1; |
||||
} else if ( an->nchild != bn->nchild ) { |
||||
return ( an->nchild > bn->nchild ) ? -1 : 1; |
||||
} else { |
||||
int i,res; |
||||
|
||||
for( i=0; i<an->nchild; i++ )
|
||||
if ( (res=QTNodeCompare(an->child[i], bn->child[i]))!=0 ) |
||||
return res; |
||||
}
|
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int |
||||
cmpQTN( const void *a, const void *b ) { |
||||
return QTNodeCompare( *(QTNode**)a, *(QTNode**)b ); |
||||
} |
||||
|
||||
void
|
||||
QTNSort( QTNode* in ) { |
||||
int i; |
||||
|
||||
if ( in->valnode->type != OPR ) |
||||
return; |
||||
|
||||
for (i=0;i<in->nchild;i++) |
||||
QTNSort( in->child[i] ); |
||||
if ( in->nchild > 1 ) |
||||
qsort((void *) in->child, in->nchild, sizeof(QTNode*), cmpQTN);
|
||||
} |
||||
|
||||
bool
|
||||
QTNEq( QTNode* a, QTNode* b ) { |
||||
uint32 sign = a->sign & b->sign; |
||||
if ( !(sign == a->sign && sign == b->sign) ) |
||||
return 0; |
||||
|
||||
return ( QTNodeCompare(a,b) == 0 ) ? true : false; |
||||
} |
||||
|
||||
void
|
||||
QTNTernary( QTNode* in ) { |
||||
int i; |
||||
|
||||
if ( in->valnode->type != OPR ) |
||||
return; |
||||
|
||||
for (i=0;i<in->nchild;i++) |
||||
QTNTernary( in->child[i] ); |
||||
|
||||
for (i=0;i<in->nchild;i++) { |
||||
if ( in->valnode->type == in->child[i]->valnode->type && in->valnode->val == in->child[i]->valnode->val ) { |
||||
QTNode* cc = in->child[i]; |
||||
int oldnchild = in->nchild;
|
||||
|
||||
in->nchild += cc->nchild-1; |
||||
in->child = (QTNode**)repalloc( in->child, in->nchild * sizeof(QTNode*) ); |
||||
|
||||
if ( i+1 != oldnchild )
|
||||
memmove( in->child + i + cc->nchild, in->child + i + 1,
|
||||
(oldnchild-i-1)*sizeof(QTNode*) ); |
||||
|
||||
memcpy( in->child + i, cc->child, cc->nchild * sizeof(QTNode*) );
|
||||
i += cc->nchild-1; |
||||
|
||||
pfree(cc); |
||||
}
|
||||
} |
||||
} |
||||
|
||||
void
|
||||
QTNBinary( QTNode* in ) { |
||||
int i; |
||||
|
||||
if ( in->valnode->type != OPR ) |
||||
return; |
||||
|
||||
for (i=0;i<in->nchild;i++) |
||||
QTNBinary( in->child[i] ); |
||||
|
||||
if ( in->nchild <= 2 ) |
||||
return;
|
||||
|
||||
while( in->nchild > 2 ) { |
||||
QTNode *nn = (QTNode*)palloc0( sizeof(QTNode) ); |
||||
nn->valnode = (ITEM*)palloc0( sizeof(ITEM) ); |
||||
nn->child = (QTNode**)palloc0( sizeof(QTNode*) * 2 ); |
||||
|
||||
nn->nchild = 2; |
||||
nn->flags = QTN_NEEDFREE; |
||||
|
||||
nn->child[0] = in->child[0]; |
||||
nn->child[1] = in->child[1]; |
||||
nn->sign = nn->child[0]->sign | nn->child[1]->sign; |
||||
|
||||
nn->valnode->type = in->valnode->type; |
||||
nn->valnode->val = in->valnode->val; |
||||
|
||||
in->child[0] = nn; |
||||
in->child[1] = in->child[ in->nchild-1 ]; |
||||
in->nchild--; |
||||
}
|
||||
} |
||||
|
||||
static void |
||||
cntsize(QTNode *in, int4 *sumlen, int4 *nnode) { |
||||
*nnode += 1; |
||||
if ( in->valnode->type == OPR ) { |
||||
int i; |
||||
for (i=0;i<in->nchild;i++) |
||||
cntsize(in->child[i], sumlen, nnode); |
||||
} else { |
||||
*sumlen += in->valnode->length+1; |
||||
} |
||||
} |
||||
|
||||
typedef struct { |
||||
ITEM *curitem; |
||||
char *operand; |
||||
char *curoperand; |
||||
} QTN2QTState; |
||||
|
||||
static void |
||||
fillQT( QTN2QTState *state, QTNode *in ) { |
||||
*(state->curitem) = *(in->valnode); |
||||
|
||||
if ( in->valnode->type == VAL ) { |
||||
memcpy( state->curoperand, in->word, in->valnode->length ); |
||||
state->curitem->distance = state->curoperand - state->operand; |
||||
state->curoperand[ in->valnode->length ] = '\0'; |
||||
state->curoperand += in->valnode->length + 1;
|
||||
state->curitem++; |
||||
} else { |
||||
ITEM *curitem = state->curitem; |
||||
|
||||
Assert( in->nchild<=2 ); |
||||
state->curitem++; |
||||
|
||||
fillQT( state, in->child[0] ); |
||||
|
||||
if ( in->nchild==2 ) { |
||||
curitem->left = state->curitem - curitem; |
||||
fillQT( state, in->child[1] ); |
||||
}
|
||||
} |
||||
}
|
||||
|
||||
QUERYTYPE*
|
||||
QTN2QT( QTNode* in, MemoryType memtype ) { |
||||
QUERYTYPE *out; |
||||
int len; |
||||
int sumlen=0, nnode=0; |
||||
QTN2QTState state;
|
||||
|
||||
cntsize(in, &sumlen, &nnode); |
||||
len = COMPUTESIZE( nnode, sumlen ); |
||||
|
||||
out = (QUERYTYPE*)MEMALLOC(memtype, len); |
||||
out->len = len;
|
||||
out->size = nnode;
|
||||
|
||||
state.curitem = GETQUERY( out );
|
||||
state.operand = state.curoperand = GETOPERAND( out ); |
||||
|
||||
fillQT( &state, in ); |
||||
return out;
|
||||
} |
||||
|
||||
QTNode * |
||||
QTNCopy( QTNode* in, MemoryType memtype ) { |
||||
QTNode *out = (QTNode*)MEMALLOC( memtype, sizeof(QTNode) ); |
||||
|
||||
*out = *in; |
||||
out->valnode = (ITEM*)MEMALLOC( memtype, sizeof(ITEM) ); |
||||
*(out->valnode) = *(in->valnode); |
||||
out->flags |= QTN_NEEDFREE; |
||||
|
||||
if ( in->valnode->type == VAL ) { |
||||
out->word = MEMALLOC( memtype, in->valnode->length + 1 ); |
||||
memcpy( out->word, in->word, in->valnode->length ); |
||||
out->word[ in->valnode->length ] = '\0';
|
||||
out->flags |= QTN_WORDFREE; |
||||
} else { |
||||
int i; |
||||
|
||||
out->child = (QTNode**)MEMALLOC( memtype, sizeof(QTNode*) * in->nchild ); |
||||
|
||||
for(i=0;i<in->nchild;i++) |
||||
out->child[i] = QTNCopy( in->child[i], memtype ); |
||||
}
|
||||
|
||||
return out; |
||||
} |
||||
@ -0,0 +1,44 @@ |
||||
#ifndef __QUERY_UTIL_H__ |
||||
#define __QUERY_UTIL_H__ |
||||
|
||||
#include "postgres.h" |
||||
#include "utils/memutils.h" |
||||
|
||||
#include "query.h" |
||||
|
||||
typedef struct QTNode { |
||||
ITEM *valnode; |
||||
uint32 flags; |
||||
int4 nchild; |
||||
char *word; |
||||
uint32 sign; |
||||
struct QTNode **child;
|
||||
} QTNode; |
||||
|
||||
#define QTN_NEEDFREE 0x01 |
||||
#define QTN_NOCHANGE 0x02 |
||||
#define QTN_WORDFREE 0x04 |
||||
|
||||
typedef enum { |
||||
PlainMemory, |
||||
SPIMemory, |
||||
AggMemory |
||||
} MemoryType; |
||||
|
||||
QTNode* QT2QTN( ITEM *in, char *operand ); |
||||
QUERYTYPE* QTN2QT( QTNode* in, MemoryType memtype ); |
||||
void QTNFree( QTNode* in );
|
||||
void QTNSort( QTNode* in );
|
||||
void QTNTernary( QTNode* in );
|
||||
void QTNBinary( QTNode* in ); |
||||
int QTNodeCompare( QTNode *an, QTNode *bn ); |
||||
QTNode* QTNCopy( QTNode* in, MemoryType memtype); |
||||
bool QTNEq( QTNode* a, QTNode* b );
|
||||
|
||||
|
||||
extern MemoryContext AggregateContext;
|
||||
|
||||
#define MEMALLOC(us, s) ( ((us)==SPIMemory) ? SPI_palloc(s) : ( ( (us)==PlainMemory ) ? palloc(s) : MemoryContextAlloc(AggregateContext, (s)) ) ) |
||||
#define MEMFREE(us, p) ( ((us)==SPIMemory) ? SPI_pfree(p) : pfree(p) ) |
||||
|
||||
#endif |
||||
Loading…
Reference in new issue