Commit 978c8c6d authored by Bruce Momjian's avatar Bruce Momjian

please find attached patch to current CVS ( contrib/ltree )

Changes:

July 31, 2002
   Now works on 64-bit platforms.
   Added function lca - lowest common ancestor
   Version for 7.2 is distributed as separate package -
   http://www.sai.msu.su/~megera/postgres/gist/ltree/ltree-7.2.tar.gz

Oleg Bartunov
parent 6495f4e5
...@@ -4,7 +4,7 @@ ltree - is a PostgreSQL contrib module which contains implementation of data ...@@ -4,7 +4,7 @@ ltree - is a PostgreSQL contrib module which contains implementation of data
types, indexed access methods and queries for data organized as a tree-like types, indexed access methods and queries for data organized as a tree-like
structures. structures.
This module will works for PostgreSQL version 7.3. This module will works for PostgreSQL version 7.3.
(patch for 7.2 version is provided, see INSTALLATION) (version for 7.2 version is available from http://www.sai.msu.su/~megera/postgres/gist/ltree/ltree-7.2.tar.gz)
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
All work was done by Teodor Sigaev (teodor@stack.net) and Oleg Bartunov All work was done by Teodor Sigaev (teodor@stack.net) and Oleg Bartunov
(oleg@sai.msu.su). See http://www.sai.msu.su/~megera/postgres/gist for (oleg@sai.msu.su). See http://www.sai.msu.su/~megera/postgres/gist for
...@@ -184,9 +184,21 @@ int4 nlevel ...@@ -184,9 +184,21 @@ int4 nlevel
nlevel nlevel
-------- --------
3 3
Note, that arguments start, end, OFFSET, LEN have meaning of level of the
Note, that arguments start, end, OFFSET, LEN have meaning of level of the node node !
!
ltree lca(ltree,ltree,...) (up to 8 arguments)
ltree lca(ltree[])
Returns Lowest Common Ancestor (lca)
# select lca('1.2.2.3','1.2.3.4.5.6');
lca
-----
1.2
# select lca('{la.2.3,1.2.3.4.5.6}') is null;
?column?
----------
f
INSTALLATION INSTALLATION
...@@ -195,8 +207,6 @@ INSTALLATION ...@@ -195,8 +207,6 @@ INSTALLATION
make install make install
make installcheck make installcheck
for 7.2 one needs to apply patch ( patch < patch.72) before installation !
EXAMPLE OF USAGE EXAMPLE OF USAGE
createdb ltreetest createdb ltreetest
...@@ -416,6 +426,11 @@ appreciate your input. So far, below some (rather obvious) results: ...@@ -416,6 +426,11 @@ appreciate your input. So far, below some (rather obvious) results:
CHANGES CHANGES
July 31, 2002
Now works on 64-bit platforms.
Added function lca - lowest common ancestor
Version for 7.2 is distributed as separate package -
http://www.sai.msu.su/~megera/postgres/gist/ltree/ltree-7.2.tar.gz
July 13, 2002 July 13, 2002
Initial release. Initial release.
......
...@@ -28,6 +28,8 @@ Datum _ltree_extract_risparent(PG_FUNCTION_ARGS); ...@@ -28,6 +28,8 @@ Datum _ltree_extract_risparent(PG_FUNCTION_ARGS);
Datum _ltq_extract_regex(PG_FUNCTION_ARGS); Datum _ltq_extract_regex(PG_FUNCTION_ARGS);
Datum _ltxtq_extract_exec(PG_FUNCTION_ARGS); Datum _ltxtq_extract_exec(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(_lca);
Datum _lca(PG_FUNCTION_ARGS);
typedef Datum (*PGCALL2)(PG_FUNCTION_ARGS); typedef Datum (*PGCALL2)(PG_FUNCTION_ARGS);
#define NEXTVAL(x) ( (ltree*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) ) #define NEXTVAL(x) ( (ltree*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
...@@ -210,3 +212,27 @@ _ltxtq_extract_exec(PG_FUNCTION_ARGS) { ...@@ -210,3 +212,27 @@ _ltxtq_extract_exec(PG_FUNCTION_ARGS) {
PG_RETURN_POINTER(item); PG_RETURN_POINTER(item);
} }
Datum
_lca(PG_FUNCTION_ARGS) {
ArrayType *la = (ArrayType *)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
int num=ArrayGetNItems( ARR_NDIM(la), ARR_DIMS(la));
ltree *item = (ltree*)ARR_DATA_PTR(la);
ltree **a,*res;
a=(ltree**)palloc( sizeof(ltree*) * num );
while( num>0 ) {
num--;
a[num] = item;
item = NEXTVAL(item);
}
res = lca_inner(a, ArrayGetNItems( ARR_NDIM(la), ARR_DIMS(la)));
pfree(a);
PG_FREE_IF_COPY(la,0);
if ( res )
PG_RETURN_POINTER(res);
else
PG_RETURN_NULL();
}
...@@ -12,7 +12,7 @@ typedef struct { ...@@ -12,7 +12,7 @@ typedef struct {
} ltree_level; } ltree_level;
#define LEVEL_HDRSIZE (sizeof(uint8)) #define LEVEL_HDRSIZE (sizeof(uint8))
#define LEVEL_NEXT(x) ( (ltree_level*)( ((char*)(x)) + ((ltree_level*)(x))->len + LEVEL_HDRSIZE ) ) #define LEVEL_NEXT(x) ( (ltree_level*)( ((char*)(x)) + MAXALIGN(((ltree_level*)(x))->len + LEVEL_HDRSIZE) ) )
typedef struct { typedef struct {
int32 len; int32 len;
...@@ -20,8 +20,8 @@ typedef struct { ...@@ -20,8 +20,8 @@ typedef struct {
char data[1]; char data[1];
} ltree; } ltree;
#define LTREE_HDRSIZE ( sizeof(int32) + sizeof(uint16) ) #define LTREE_HDRSIZE MAXALIGN( sizeof(int32) + sizeof(uint16) )
#define LTREE_FIRST(x) ( (ltree_level*)( ((ltree*)(x))->data ) ) #define LTREE_FIRST(x) ( (ltree_level*)( ((char*)(x))+LTREE_HDRSIZE ) )
/* lquery */ /* lquery */
...@@ -33,8 +33,8 @@ typedef struct { ...@@ -33,8 +33,8 @@ typedef struct {
char name[1]; char name[1];
} lquery_variant; } lquery_variant;
#define LVAR_HDRSIZE (sizeof(uint8)*2 + sizeof(int4)) #define LVAR_HDRSIZE MAXALIGN(sizeof(uint8)*2 + sizeof(int4))
#define LVAR_NEXT(x) ( (lquery_variant*)( ((char*)(x)) + ((lquery_variant*)(x))->len + LVAR_HDRSIZE ) ) #define LVAR_NEXT(x) ( (lquery_variant*)( ((char*)(x)) + MAXALIGN(((lquery_variant*)(x))->len) + LVAR_HDRSIZE ) )
#define LVAR_ANYEND 0x01 #define LVAR_ANYEND 0x01
#define LVAR_INCASE 0x02 #define LVAR_INCASE 0x02
...@@ -49,9 +49,9 @@ typedef struct { ...@@ -49,9 +49,9 @@ typedef struct {
char variants[1]; char variants[1];
} lquery_level; } lquery_level;
#define LQL_HDRSIZE ( sizeof(uint16)*5 ) #define LQL_HDRSIZE MAXALIGN( sizeof(uint16)*5 )
#define LQL_NEXT(x) ( (lquery_level*)( ((char*)(x)) + ((lquery_level*)(x))->totallen ) ) #define LQL_NEXT(x) ( (lquery_level*)( ((char*)(x)) + MAXALIGN(((lquery_level*)(x))->totallen) ) )
#define LQL_FIRST(x) ( (lquery_variant*)( ((lquery_level*)(x))->variants ) ) #define LQL_FIRST(x) ( (lquery_variant*)( ((char*)(x))+LQL_HDRSIZE ) )
#define LQL_NOT 0x10 #define LQL_NOT 0x10
#ifdef LOWER_NODE #ifdef LOWER_NODE
...@@ -69,8 +69,8 @@ typedef struct { ...@@ -69,8 +69,8 @@ typedef struct {
char data[1]; char data[1];
} lquery; } lquery;
#define LQUERY_HDRSIZE ( sizeof(int32) + 3*sizeof(uint16) ) #define LQUERY_HDRSIZE MAXALIGN( sizeof(int32) + 3*sizeof(uint16) )
#define LQUERY_FIRST(x) ( (lquery_level*)( ((lquery*)(x))->data ) ) #define LQUERY_FIRST(x) ( (lquery_level*)( ((char*)(x))+LQUERY_HDRSIZE ) )
#define LQUERY_HASNOT 0x01 #define LQUERY_HASNOT 0x01
...@@ -113,7 +113,7 @@ typedef struct ...@@ -113,7 +113,7 @@ typedef struct
char data[1]; char data[1];
} ltxtquery; } ltxtquery;
#define HDRSIZEQT ( 2*sizeof(int4) ) #define HDRSIZEQT MAXALIGN( 2*sizeof(int4) )
#define COMPUTESIZE(size,lenofoperand) ( HDRSIZEQT + size * sizeof(ITEM) + lenofoperand ) #define COMPUTESIZE(size,lenofoperand) ( HDRSIZEQT + size * sizeof(ITEM) + lenofoperand )
#define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT ) #define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT )
#define GETOPERAND(x) ( (char*)GETQUERY(x) + ((ltxtquery*)x)->size * sizeof(ITEM) ) #define GETOPERAND(x) ( (char*)GETQUERY(x) + ((ltxtquery*)x)->size * sizeof(ITEM) )
...@@ -159,6 +159,7 @@ int ltree_compare(const ltree *a, const ltree *b); ...@@ -159,6 +159,7 @@ int ltree_compare(const ltree *a, const ltree *b);
bool inner_isparent(const ltree *c, const ltree *p); bool inner_isparent(const ltree *c, const ltree *p);
bool compare_subnode( ltree_level *t, char *q, int len, bool compare_subnode( ltree_level *t, char *q, int len,
int (*cmpptr)(const char *,const char *,size_t), bool anyend ); int (*cmpptr)(const char *,const char *,size_t), bool anyend );
ltree* lca_inner(ltree** a, int len);
#define PG_GETARG_LTREE(x) ((ltree*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(x)))) #define PG_GETARG_LTREE(x) ((ltree*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(x))))
#define PG_GETARG_LQUERY(x) ((lquery*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(x)))) #define PG_GETARG_LQUERY(x) ((lquery*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(x))))
...@@ -212,14 +213,14 @@ typedef struct { ...@@ -212,14 +213,14 @@ typedef struct {
#define LTG_ALLTRUE 0x02 #define LTG_ALLTRUE 0x02
#define LTG_NORIGHT 0x04 #define LTG_NORIGHT 0x04
#define LTG_HDRSIZE ( sizeof(int4) + sizeof(uint32) ) #define LTG_HDRSIZE MAXALIGN( sizeof(int4) + sizeof(uint32) )
#define LTG_SIGN(x) ( (BITVECP)( ((ltree_gist*)(x))->data ) ) #define LTG_SIGN(x) ( (BITVECP)( ((char*)(x))+LTG_HDRSIZE ) )
#define LTG_NODE(x) ( (ltree*)( ((ltree_gist*)(x))->data ) ) #define LTG_NODE(x) ( (ltree*)( ((char*)(x))+LTG_HDRSIZE ) )
#define LTG_ISONENODE(x) ( ((ltree_gist*)(x))->flag & LTG_ONENODE ) #define LTG_ISONENODE(x) ( ((ltree_gist*)(x))->flag & LTG_ONENODE )
#define LTG_ISALLTRUE(x) ( ((ltree_gist*)(x))->flag & LTG_ALLTRUE ) #define LTG_ISALLTRUE(x) ( ((ltree_gist*)(x))->flag & LTG_ALLTRUE )
#define LTG_ISNORIGHT(x) ( ((ltree_gist*)(x))->flag & LTG_NORIGHT ) #define LTG_ISNORIGHT(x) ( ((ltree_gist*)(x))->flag & LTG_NORIGHT )
#define LTG_LNODE(x) ( (ltree*)( ( (char*)( ((ltree_gist*)(x))->data ) ) + ( LTG_ISALLTRUE(x) ? 0 : SIGLEN ) ) ) #define LTG_LNODE(x) ( (ltree*)( ( ((char*)(x))+LTG_HDRSIZE ) + ( LTG_ISALLTRUE(x) ? 0 : SIGLEN ) ) )
#define LTG_RENODE(x) ( (ltree*)( ((char*)LTG_LNODE(x)) + LTG_LNODE(x)->len ) ) #define LTG_RENODE(x) ( (ltree*)( ((char*)LTG_LNODE(x)) + LTG_LNODE(x)->len) )
#define LTG_RNODE(x) ( LTG_ISNORIGHT(x) ? LTG_LNODE(x) : LTG_RENODE(x) ) #define LTG_RNODE(x) ( LTG_ISNORIGHT(x) ? LTG_LNODE(x) : LTG_RENODE(x) )
#define LTG_GETLNODE(x) ( LTG_ISONENODE(x) ? LTG_NODE(x) : LTG_LNODE(x) ) #define LTG_GETLNODE(x) ( LTG_ISONENODE(x) ? LTG_NODE(x) : LTG_LNODE(x) )
......
...@@ -117,6 +117,46 @@ RETURNS int4 ...@@ -117,6 +117,46 @@ RETURNS int4
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict,iscachable); LANGUAGE 'c' with (isstrict,iscachable);
CREATE FUNCTION lca(_ltree)
RETURNS ltree
AS 'MODULE_PATHNAME','_lca'
LANGUAGE 'c' with (isstrict,iscachable);
CREATE FUNCTION lca(ltree,ltree)
RETURNS ltree
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict,iscachable);
CREATE FUNCTION lca(ltree,ltree,ltree)
RETURNS ltree
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict,iscachable);
CREATE FUNCTION lca(ltree,ltree,ltree,ltree)
RETURNS ltree
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict,iscachable);
CREATE FUNCTION lca(ltree,ltree,ltree,ltree,ltree)
RETURNS ltree
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict,iscachable);
CREATE FUNCTION lca(ltree,ltree,ltree,ltree,ltree,ltree)
RETURNS ltree
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict,iscachable);
CREATE FUNCTION lca(ltree,ltree,ltree,ltree,ltree,ltree,ltree)
RETURNS ltree
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict,iscachable);
CREATE FUNCTION lca(ltree,ltree,ltree,ltree,ltree,ltree,ltree,ltree)
RETURNS ltree
AS 'MODULE_PATHNAME'
LANGUAGE 'c' with (isstrict,iscachable);
CREATE FUNCTION ltree_isparent(ltree,ltree) CREATE FUNCTION ltree_isparent(ltree,ltree)
RETURNS bool RETURNS bool
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
......
...@@ -61,7 +61,7 @@ ltree_in(PG_FUNCTION_ARGS) { ...@@ -61,7 +61,7 @@ ltree_in(PG_FUNCTION_ARGS) {
if ( lptr->len > 255 ) if ( lptr->len > 255 )
elog(ERROR,"Name of level is too long (%d, must be < 256) in position %d", elog(ERROR,"Name of level is too long (%d, must be < 256) in position %d",
lptr->len, lptr->start - buf); lptr->len, lptr->start - buf);
totallen += lptr->len + LEVEL_HDRSIZE; totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
lptr++; lptr++;
state = LTPRS_WAITNAME; state = LTPRS_WAITNAME;
} else if ( !ISALNUM(*ptr) ) } else if ( !ISALNUM(*ptr) )
...@@ -76,7 +76,7 @@ ltree_in(PG_FUNCTION_ARGS) { ...@@ -76,7 +76,7 @@ ltree_in(PG_FUNCTION_ARGS) {
if ( lptr->len > 255 ) if ( lptr->len > 255 )
elog(ERROR,"Name of level is too long (%d, must be < 256) in position %d", elog(ERROR,"Name of level is too long (%d, must be < 256) in position %d",
lptr->len, lptr->start - buf); lptr->len, lptr->start - buf);
totallen += lptr->len + LEVEL_HDRSIZE; totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
lptr++; lptr++;
} else if ( ! (state == LTPRS_WAITNAME && lptr == list) ) } else if ( ! (state == LTPRS_WAITNAME && lptr == list) )
elog(ERROR,"Unexpected end of line"); elog(ERROR,"Unexpected end of line");
...@@ -94,7 +94,6 @@ ltree_in(PG_FUNCTION_ARGS) { ...@@ -94,7 +94,6 @@ ltree_in(PG_FUNCTION_ARGS) {
} }
pfree(list); pfree(list);
PG_RETURN_POINTER(result); PG_RETURN_POINTER(result);
} }
...@@ -134,7 +133,9 @@ ltree_out(PG_FUNCTION_ARGS) { ...@@ -134,7 +133,9 @@ ltree_out(PG_FUNCTION_ARGS) {
#define LQPRS_WAITVAR 8 #define LQPRS_WAITVAR 8
#define GETVAR(x) ( *((nodeitem**)LQL_FIRST(x)) ) #define GETVAR(x) ( *((nodeitem**)LQL_FIRST(x)) )
#define ITEMSIZE MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*))
#define NEXTLEV(x) ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) )
Datum Datum
lquery_in(PG_FUNCTION_ARGS) { lquery_in(PG_FUNCTION_ARGS) {
...@@ -159,8 +160,8 @@ lquery_in(PG_FUNCTION_ARGS) { ...@@ -159,8 +160,8 @@ lquery_in(PG_FUNCTION_ARGS) {
} }
num++; num++;
curqlevel = tmpql = (lquery_level*) palloc( ( LQL_HDRSIZE+sizeof(nodeitem*) )*(num) ); curqlevel = tmpql = (lquery_level*) palloc( ITEMSIZE*num );
memset((void*)tmpql,0, ( LQL_HDRSIZE+sizeof(nodeitem*) )*(num) ); memset((void*)tmpql,0, ITEMSIZE*num );
ptr=buf; ptr=buf;
while( *ptr ) { while( *ptr ) {
if ( state==LQPRS_WAITLEVEL ) { if ( state==LQPRS_WAITLEVEL ) {
...@@ -224,7 +225,7 @@ lquery_in(PG_FUNCTION_ARGS) { ...@@ -224,7 +225,7 @@ lquery_in(PG_FUNCTION_ARGS) {
elog(ERROR,"Name of level is too long (%d, must be < 256) in position %d", elog(ERROR,"Name of level is too long (%d, must be < 256) in position %d",
lptr->len, lptr->start - buf); lptr->len, lptr->start - buf);
state = LQPRS_WAITLEVEL; state = LQPRS_WAITLEVEL;
curqlevel++; curqlevel = NEXTLEV(curqlevel);
} else if ( ISALNUM(*ptr) ) { } else if ( ISALNUM(*ptr) ) {
if ( lptr->flag ) if ( lptr->flag )
UNCHAR; UNCHAR;
...@@ -236,7 +237,7 @@ lquery_in(PG_FUNCTION_ARGS) { ...@@ -236,7 +237,7 @@ lquery_in(PG_FUNCTION_ARGS) {
} else if ( *ptr == '.' ) { } else if ( *ptr == '.' ) {
curqlevel->low=0; curqlevel->low=0;
curqlevel->high=0xffff; curqlevel->high=0xffff;
curqlevel++; curqlevel = NEXTLEV(curqlevel);
state = LQPRS_WAITLEVEL; state = LQPRS_WAITLEVEL;
} else } else
UNCHAR; UNCHAR;
...@@ -273,7 +274,7 @@ lquery_in(PG_FUNCTION_ARGS) { ...@@ -273,7 +274,7 @@ lquery_in(PG_FUNCTION_ARGS) {
} else if ( state == LQPRS_WAITEND ) { } else if ( state == LQPRS_WAITEND ) {
if ( *ptr == '.' ) { if ( *ptr == '.' ) {
state = LQPRS_WAITLEVEL; state = LQPRS_WAITLEVEL;
curqlevel++; curqlevel = NEXTLEV(curqlevel);
} else } else
UNCHAR; UNCHAR;
} else } else
...@@ -300,19 +301,19 @@ lquery_in(PG_FUNCTION_ARGS) { ...@@ -300,19 +301,19 @@ lquery_in(PG_FUNCTION_ARGS) {
curqlevel = tmpql; curqlevel = tmpql;
totallen = LQUERY_HDRSIZE; totallen = LQUERY_HDRSIZE;
while( curqlevel-tmpql < num ) { while( (char*)curqlevel-(char*)tmpql < num*ITEMSIZE ) {
totallen += LQL_HDRSIZE; totallen += LQL_HDRSIZE;
if ( curqlevel->numvar ) { if ( curqlevel->numvar ) {
lptr = GETVAR(curqlevel); lptr = GETVAR(curqlevel);
while( lptr-GETVAR(curqlevel) < curqlevel->numvar ) { while( lptr-GETVAR(curqlevel) < curqlevel->numvar ) {
totallen += LVAR_HDRSIZE + lptr->len; totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
lptr++; lptr++;
} }
} else if ( curqlevel->low > curqlevel->high ) } else if ( curqlevel->low > curqlevel->high )
elog(ERROR,"Low limit(%d) is greater than upper(%d)",curqlevel->low,curqlevel->high ); elog(ERROR,"Low limit(%d) is greater than upper(%d)",curqlevel->low,curqlevel->high );
curqlevel++; curqlevel = NEXTLEV(curqlevel);
} }
result = (lquery*)palloc( totallen ); result = (lquery*)palloc( totallen );
result->len = totallen; result->len = totallen;
result->numlevel = num; result->numlevel = num;
...@@ -322,14 +323,14 @@ lquery_in(PG_FUNCTION_ARGS) { ...@@ -322,14 +323,14 @@ lquery_in(PG_FUNCTION_ARGS) {
result->flag |= LQUERY_HASNOT; result->flag |= LQUERY_HASNOT;
cur = LQUERY_FIRST(result); cur = LQUERY_FIRST(result);
curqlevel = tmpql; curqlevel = tmpql;
while( curqlevel-tmpql < num ) { while( (char*)curqlevel-(char*)tmpql < num*ITEMSIZE ) {
memcpy(cur,curqlevel,LQL_HDRSIZE); memcpy(cur,curqlevel,LQL_HDRSIZE);
cur->totallen=LQL_HDRSIZE; cur->totallen=LQL_HDRSIZE;
if ( curqlevel->numvar ) { if ( curqlevel->numvar ) {
lrptr = LQL_FIRST(cur); lrptr = LQL_FIRST(cur);
lptr = GETVAR(curqlevel); lptr = GETVAR(curqlevel);
while( lptr-GETVAR(curqlevel) < curqlevel->numvar ) { while( lptr-GETVAR(curqlevel) < curqlevel->numvar ) {
cur->totallen += LVAR_HDRSIZE + lptr->len; cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
lrptr->len = lptr->len; lrptr->len = lptr->len;
lrptr->flag = lptr->flag; lrptr->flag = lptr->flag;
lrptr->val = crc32_sz((uint8 *) lptr->start, lptr->len); lrptr->val = crc32_sz((uint8 *) lptr->start, lptr->len);
...@@ -344,7 +345,7 @@ lquery_in(PG_FUNCTION_ARGS) { ...@@ -344,7 +345,7 @@ lquery_in(PG_FUNCTION_ARGS) {
(result->firstgood)++; (result->firstgood)++;
} else } else
wasbad=true; wasbad=true;
curqlevel++; curqlevel = NEXTLEV(curqlevel);
cur = LQL_NEXT(cur); cur = LQL_NEXT(cur);
} }
......
...@@ -22,6 +22,7 @@ PG_FUNCTION_INFO_V1(subpath); ...@@ -22,6 +22,7 @@ PG_FUNCTION_INFO_V1(subpath);
PG_FUNCTION_INFO_V1(ltree_addltree); PG_FUNCTION_INFO_V1(ltree_addltree);
PG_FUNCTION_INFO_V1(ltree_addtext); PG_FUNCTION_INFO_V1(ltree_addtext);
PG_FUNCTION_INFO_V1(ltree_textadd); PG_FUNCTION_INFO_V1(ltree_textadd);
PG_FUNCTION_INFO_V1(lca);
Datum ltree_cmp(PG_FUNCTION_ARGS); Datum ltree_cmp(PG_FUNCTION_ARGS);
Datum ltree_lt(PG_FUNCTION_ARGS); Datum ltree_lt(PG_FUNCTION_ARGS);
Datum ltree_le(PG_FUNCTION_ARGS); Datum ltree_le(PG_FUNCTION_ARGS);
...@@ -35,6 +36,7 @@ Datum subpath(PG_FUNCTION_ARGS); ...@@ -35,6 +36,7 @@ Datum subpath(PG_FUNCTION_ARGS);
Datum ltree_addltree(PG_FUNCTION_ARGS); Datum ltree_addltree(PG_FUNCTION_ARGS);
Datum ltree_addtext(PG_FUNCTION_ARGS); Datum ltree_addtext(PG_FUNCTION_ARGS);
Datum ltree_textadd(PG_FUNCTION_ARGS); Datum ltree_textadd(PG_FUNCTION_ARGS);
Datum lca(PG_FUNCTION_ARGS);
int int
ltree_compare(const ltree *a, const ltree *b) { ltree_compare(const ltree *a, const ltree *b) {
...@@ -308,3 +310,79 @@ ltree_textadd(PG_FUNCTION_ARGS) { ...@@ -308,3 +310,79 @@ ltree_textadd(PG_FUNCTION_ARGS) {
PG_FREE_IF_COPY(b,0); PG_FREE_IF_COPY(b,0);
PG_RETURN_POINTER(r); PG_RETURN_POINTER(r);
} }
ltree*
lca_inner(ltree** a, int len) {
int tmp,num=( (*a)->numlevel ) ? (*a)->numlevel-1 : 0;
ltree **ptr=a+1;
int i,reslen=LTREE_HDRSIZE;
ltree_level *l1, *l2;
ltree *res;
if ( (*a)->numlevel == 0 )
return NULL;
while( ptr-a < len ) {
if ( (*ptr)->numlevel == 0 )
return NULL;
else if ( (*ptr)->numlevel == 1 )
num=0;
else {
l1 = LTREE_FIRST(*a);
l2 = LTREE_FIRST(*ptr);
tmp=num; num=0;
for(i=0;i<min(tmp, (*ptr)->numlevel-1); i++) {
if ( l1->len == l2->len && strncmp(l1->name,l2->name,l1->len) == 0 )
num=i+1;
else
break;
l1=LEVEL_NEXT(l1);
l2=LEVEL_NEXT(l2);
}
}
ptr++;
}
l1 = LTREE_FIRST(*a);
for(i=0;i<num;i++) {
reslen += MAXALIGN(l1->len + LEVEL_HDRSIZE);
l1=LEVEL_NEXT(l1);
}
res=(ltree*)palloc( reslen );
res->len = reslen;
res->numlevel = num;
l1 = LTREE_FIRST(*a);
l2 = LTREE_FIRST(res);
for(i=0;i<num;i++) {
memcpy(l2,l1, MAXALIGN(l1->len + LEVEL_HDRSIZE));
l1=LEVEL_NEXT(l1);
l2=LEVEL_NEXT(l2);
}
return res;
}
Datum
lca(PG_FUNCTION_ARGS) {
int i;
ltree **a,*res;
a=(ltree**)palloc( sizeof(ltree*) * fcinfo->nargs );
for(i=0;i<fcinfo->nargs;i++)
a[i] = PG_GETARG_LTREE(i);
res = lca_inner(a, (int) fcinfo->nargs);
for(i=0;i<fcinfo->nargs;i++)
PG_FREE_IF_COPY(a[i],i);
pfree(a);
if ( res )
PG_RETURN_POINTER(res);
else
PG_RETURN_NULL();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment