Bruce,
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
Regards,
Oleg
_____________________________________________________________
Oleg Bartunov, sci.researcher, hostmaster of AstroNet,
Sternberg Astronomical Institute, Moscow University (Russia)
Internet: [EMAIL PROTECTED], http://www.sai.msu.su/~megera/
phone: +007(095)939-16-83, +007(095)939-23-83
Common subdirectories: contrib/ltree.old/CVS and contrib/ltree/CVS
diff -c contrib/ltree.old/README.ltree contrib/ltree/README.ltree
*** contrib/ltree.old/README.ltree Tue Jul 30 20:40:34 2002
--- contrib/ltree/README.ltree Wed Jul 31 21:38:07 2002
***************
*** 4,10 ****
types, indexed access methods and queries for data organized as a tree-like
structures.
This module will works for PostgreSQL version 7.3.
! (patch for 7.2 version is provided, see INSTALLATION)
-------------------------------------------------------------------------------
All work was done by Teodor Sigaev ([EMAIL PROTECTED]) and Oleg Bartunov
([EMAIL PROTECTED]). See http://www.sai.msu.su/~megera/postgres/gist for
--- 4,10 ----
types, indexed access methods and queries for data organized as a tree-like
structures.
This module will works for PostgreSQL version 7.3.
! (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 ([EMAIL PROTECTED]) and Oleg Bartunov
([EMAIL PROTECTED]). See http://www.sai.msu.su/~megera/postgres/gist for
***************
*** 184,192 ****
nlevel
--------
3
!
! Note, that arguments start, end, OFFSET, LEN have meaning of level of the node
! !
INSTALLATION
--- 184,204 ----
nlevel
--------
3
! Note, that arguments start, end, OFFSET, LEN have meaning of level of the
! 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
***************
*** 195,202 ****
make install
make installcheck
- for 7.2 one needs to apply patch ( patch < patch.72) before installation !
-
EXAMPLE OF USAGE
createdb ltreetest
--- 207,212 ----
***************
*** 416,421 ****
--- 426,436 ----
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
Initial release.
diff -c contrib/ltree.old/_ltree_op.c contrib/ltree/_ltree_op.c
*** contrib/ltree.old/_ltree_op.c Tue Jul 30 20:40:34 2002
--- contrib/ltree/_ltree_op.c Wed Jul 31 21:31:47 2002
***************
*** 28,33 ****
--- 28,35 ----
Datum _ltq_extract_regex(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);
#define NEXTVAL(x) ( (ltree*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
***************
*** 208,212 ****
--- 210,238 ----
PG_FREE_IF_COPY(la,0);
PG_FREE_IF_COPY(query,1);
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();
}
Common subdirectories: contrib/ltree.old/data and contrib/ltree/data
Common subdirectories: contrib/ltree.old/expected and contrib/ltree/expected
diff -c contrib/ltree.old/ltree.h contrib/ltree/ltree.h
*** contrib/ltree.old/ltree.h Tue Jul 30 20:40:34 2002
--- contrib/ltree/ltree.h Wed Jul 31 21:31:47 2002
***************
*** 12,18 ****
} ltree_level;
#define LEVEL_HDRSIZE (sizeof(uint8))
! #define LEVEL_NEXT(x) ( (ltree_level*)( ((char*)(x)) + ((ltree_level*)(x))->len +
LEVEL_HDRSIZE ) )
typedef struct {
int32 len;
--- 12,18 ----
} ltree_level;
#define LEVEL_HDRSIZE (sizeof(uint8))
! #define LEVEL_NEXT(x) ( (ltree_level*)( ((char*)(x)) +
MAXALIGN(((ltree_level*)(x))->len + LEVEL_HDRSIZE) ) )
typedef struct {
int32 len;
***************
*** 20,27 ****
char data[1];
} ltree;
! #define LTREE_HDRSIZE ( sizeof(int32) + sizeof(uint16) )
! #define LTREE_FIRST(x) ( (ltree_level*)( ((ltree*)(x))->data ) )
/* lquery */
--- 20,27 ----
char data[1];
} ltree;
! #define LTREE_HDRSIZE MAXALIGN( sizeof(int32) + sizeof(uint16) )
! #define LTREE_FIRST(x) ( (ltree_level*)( ((char*)(x))+LTREE_HDRSIZE ) )
/* lquery */
***************
*** 33,40 ****
char name[1];
} lquery_variant;
! #define LVAR_HDRSIZE (sizeof(uint8)*2 + sizeof(int4))
! #define LVAR_NEXT(x) ( (lquery_variant*)( ((char*)(x)) +
((lquery_variant*)(x))->len + LVAR_HDRSIZE ) )
#define LVAR_ANYEND 0x01
#define LVAR_INCASE 0x02
--- 33,40 ----
char name[1];
} lquery_variant;
! #define LVAR_HDRSIZE MAXALIGN(sizeof(uint8)*2 + sizeof(int4))
! #define LVAR_NEXT(x) ( (lquery_variant*)( ((char*)(x)) +
MAXALIGN(((lquery_variant*)(x))->len) + LVAR_HDRSIZE ) )
#define LVAR_ANYEND 0x01
#define LVAR_INCASE 0x02
***************
*** 49,57 ****
char variants[1];
} lquery_level;
! #define LQL_HDRSIZE ( sizeof(uint16)*5 )
! #define LQL_NEXT(x) ( (lquery_level*)( ((char*)(x)) +
((lquery_level*)(x))->totallen ) )
! #define LQL_FIRST(x) ( (lquery_variant*)( ((lquery_level*)(x))->variants ) )
#define LQL_NOT 0x10
#ifdef LOWER_NODE
--- 49,57 ----
char variants[1];
} lquery_level;
! #define LQL_HDRSIZE MAXALIGN( sizeof(uint16)*5 )
! #define LQL_NEXT(x) ( (lquery_level*)( ((char*)(x)) +
MAXALIGN(((lquery_level*)(x))->totallen) ) )
! #define LQL_FIRST(x) ( (lquery_variant*)( ((char*)(x))+LQL_HDRSIZE ) )
#define LQL_NOT 0x10
#ifdef LOWER_NODE
***************
*** 69,76 ****
char data[1];
} lquery;
! #define LQUERY_HDRSIZE ( sizeof(int32) + 3*sizeof(uint16) )
! #define LQUERY_FIRST(x) ( (lquery_level*)( ((lquery*)(x))->data ) )
#define LQUERY_HASNOT 0x01
--- 69,76 ----
char data[1];
} lquery;
! #define LQUERY_HDRSIZE MAXALIGN( sizeof(int32) + 3*sizeof(uint16) )
! #define LQUERY_FIRST(x) ( (lquery_level*)( ((char*)(x))+LQUERY_HDRSIZE ) )
#define LQUERY_HASNOT 0x01
***************
*** 113,119 ****
char data[1];
} ltxtquery;
! #define HDRSIZEQT ( 2*sizeof(int4) )
#define COMPUTESIZE(size,lenofoperand) ( HDRSIZEQT + size * sizeof(ITEM) +
lenofoperand )
#define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT )
#define GETOPERAND(x) ( (char*)GETQUERY(x) + ((ltxtquery*)x)->size * sizeof(ITEM)
)
--- 113,119 ----
char data[1];
} ltxtquery;
! #define HDRSIZEQT MAXALIGN( 2*sizeof(int4) )
#define COMPUTESIZE(size,lenofoperand) ( HDRSIZEQT + size * sizeof(ITEM) +
lenofoperand )
#define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT )
#define GETOPERAND(x) ( (char*)GETQUERY(x) + ((ltxtquery*)x)->size * sizeof(ITEM)
)
***************
*** 159,164 ****
--- 159,165 ----
bool inner_isparent(const ltree *c, const ltree *p);
bool compare_subnode( ltree_level *t, char *q, int len,
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_LQUERY(x)
((lquery*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(x))))
***************
*** 212,225 ****
#define LTG_ALLTRUE 0x02
#define LTG_NORIGHT 0x04
! #define LTG_HDRSIZE ( sizeof(int4) + sizeof(uint32) )
! #define LTG_SIGN(x) ( (BITVECP)( ((ltree_gist*)(x))->data ) )
! #define LTG_NODE(x) ( (ltree*)( ((ltree_gist*)(x))->data ) )
#define LTG_ISONENODE(x) ( ((ltree_gist*)(x))->flag & LTG_ONENODE )
#define LTG_ISALLTRUE(x) ( ((ltree_gist*)(x))->flag & LTG_ALLTRUE )
#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_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_GETLNODE(x) ( LTG_ISONENODE(x) ? LTG_NODE(x) : LTG_LNODE(x) )
--- 213,226 ----
#define LTG_ALLTRUE 0x02
#define LTG_NORIGHT 0x04
! #define LTG_HDRSIZE MAXALIGN( sizeof(int4) + sizeof(uint32) )
! #define LTG_SIGN(x) ( (BITVECP)( ((char*)(x))+LTG_HDRSIZE ) )
! #define LTG_NODE(x) ( (ltree*)( ((char*)(x))+LTG_HDRSIZE ) )
#define LTG_ISONENODE(x) ( ((ltree_gist*)(x))->flag & LTG_ONENODE )
#define LTG_ISALLTRUE(x) ( ((ltree_gist*)(x))->flag & LTG_ALLTRUE )
#define LTG_ISNORIGHT(x) ( ((ltree_gist*)(x))->flag & LTG_NORIGHT )
! #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_RNODE(x) ( LTG_ISNORIGHT(x) ? LTG_LNODE(x) : LTG_RENODE(x) )
#define LTG_GETLNODE(x) ( LTG_ISONENODE(x) ? LTG_NODE(x) : LTG_LNODE(x) )
diff -c contrib/ltree.old/ltree.sql.in contrib/ltree/ltree.sql.in
*** contrib/ltree.old/ltree.sql.in Tue Jul 30 22:48:34 2002
--- contrib/ltree/ltree.sql.in Wed Jul 31 21:31:47 2002
***************
*** 117,122 ****
--- 117,162 ----
AS 'MODULE_PATHNAME'
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)
RETURNS bool
AS 'MODULE_PATHNAME'
diff -c contrib/ltree.old/ltree_io.c contrib/ltree/ltree_io.c
*** contrib/ltree.old/ltree_io.c Tue Jul 30 20:40:34 2002
--- contrib/ltree/ltree_io.c Wed Jul 31 21:31:47 2002
***************
*** 61,67 ****
if ( lptr->len > 255 )
elog(ERROR,"Name of level is too long (%d,
must be < 256) in position %d",
lptr->len, lptr->start - buf);
! totallen += lptr->len + LEVEL_HDRSIZE;
lptr++;
state = LTPRS_WAITNAME;
} else if ( !ISALNUM(*ptr) )
--- 61,67 ----
if ( lptr->len > 255 )
elog(ERROR,"Name of level is too long (%d,
must be < 256) in position %d",
lptr->len, lptr->start - buf);
! totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
lptr++;
state = LTPRS_WAITNAME;
} else if ( !ISALNUM(*ptr) )
***************
*** 76,82 ****
if ( lptr->len > 255 )
elog(ERROR,"Name of level is too long (%d, must be < 256) in
position %d",
lptr->len, lptr->start - buf);
! totallen += lptr->len + LEVEL_HDRSIZE;
lptr++;
} else if ( ! (state == LTPRS_WAITNAME && lptr == list) )
elog(ERROR,"Unexpected end of line");
--- 76,82 ----
if ( lptr->len > 255 )
elog(ERROR,"Name of level is too long (%d, must be < 256) in
position %d",
lptr->len, lptr->start - buf);
! totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
lptr++;
} else if ( ! (state == LTPRS_WAITNAME && lptr == list) )
elog(ERROR,"Unexpected end of line");
***************
*** 94,100 ****
}
pfree(list);
-
PG_RETURN_POINTER(result);
}
--- 94,99 ----
***************
*** 134,140 ****
#define LQPRS_WAITVAR 8
! #define GETVAR(x) ( *((nodeitem**)LQL_FIRST(x)) )
Datum
lquery_in(PG_FUNCTION_ARGS) {
--- 133,141 ----
#define LQPRS_WAITVAR 8
! #define GETVAR(x) ( *((nodeitem**)LQL_FIRST(x)) )
! #define ITEMSIZE MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*))
! #define NEXTLEV(x) ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) )
Datum
lquery_in(PG_FUNCTION_ARGS) {
***************
*** 159,166 ****
}
num++;
! curqlevel = tmpql = (lquery_level*) palloc( ( LQL_HDRSIZE+sizeof(nodeitem*)
)*(num) );
! memset((void*)tmpql,0, ( LQL_HDRSIZE+sizeof(nodeitem*) )*(num) );
ptr=buf;
while( *ptr ) {
if ( state==LQPRS_WAITLEVEL ) {
--- 160,167 ----
}
num++;
! curqlevel = tmpql = (lquery_level*) palloc( ITEMSIZE*num );
! memset((void*)tmpql,0, ITEMSIZE*num );
ptr=buf;
while( *ptr ) {
if ( state==LQPRS_WAITLEVEL ) {
***************
*** 224,230 ****
elog(ERROR,"Name of level is too long (%d,
must be < 256) in position %d",
lptr->len, lptr->start - buf);
state = LQPRS_WAITLEVEL;
! curqlevel++;
} else if ( ISALNUM(*ptr) ) {
if ( lptr->flag )
UNCHAR;
--- 225,231 ----
elog(ERROR,"Name of level is too long (%d,
must be < 256) in position %d",
lptr->len, lptr->start - buf);
state = LQPRS_WAITLEVEL;
! curqlevel = NEXTLEV(curqlevel);
} else if ( ISALNUM(*ptr) ) {
if ( lptr->flag )
UNCHAR;
***************
*** 236,242 ****
} else if ( *ptr == '.' ) {
curqlevel->low=0;
curqlevel->high=0xffff;
! curqlevel++;
state = LQPRS_WAITLEVEL;
} else
UNCHAR;
--- 237,243 ----
} else if ( *ptr == '.' ) {
curqlevel->low=0;
curqlevel->high=0xffff;
! curqlevel = NEXTLEV(curqlevel);
state = LQPRS_WAITLEVEL;
} else
UNCHAR;
***************
*** 273,279 ****
} else if ( state == LQPRS_WAITEND ) {
if ( *ptr == '.' ) {
state = LQPRS_WAITLEVEL;
! curqlevel++;
} else
UNCHAR;
} else
--- 274,280 ----
} else if ( state == LQPRS_WAITEND ) {
if ( *ptr == '.' ) {
state = LQPRS_WAITLEVEL;
! curqlevel = NEXTLEV(curqlevel);
} else
UNCHAR;
} else
***************
*** 300,318 ****
curqlevel = tmpql;
totallen = LQUERY_HDRSIZE;
! while( curqlevel-tmpql < num ) {
totallen += LQL_HDRSIZE;
if ( curqlevel->numvar ) {
lptr = GETVAR(curqlevel);
while( lptr-GETVAR(curqlevel) < curqlevel->numvar ) {
! totallen += LVAR_HDRSIZE + lptr->len;
lptr++;
}
} else if ( curqlevel->low > curqlevel->high )
elog(ERROR,"Low limit(%d) is greater than
upper(%d)",curqlevel->low,curqlevel->high );
! curqlevel++;
}
!
result = (lquery*)palloc( totallen );
result->len = totallen;
result->numlevel = num;
--- 301,319 ----
curqlevel = tmpql;
totallen = LQUERY_HDRSIZE;
! while( (char*)curqlevel-(char*)tmpql < num*ITEMSIZE ) {
totallen += LQL_HDRSIZE;
if ( curqlevel->numvar ) {
lptr = GETVAR(curqlevel);
while( lptr-GETVAR(curqlevel) < curqlevel->numvar ) {
! totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
lptr++;
}
} else if ( curqlevel->low > curqlevel->high )
elog(ERROR,"Low limit(%d) is greater than
upper(%d)",curqlevel->low,curqlevel->high );
! curqlevel = NEXTLEV(curqlevel);
}
!
result = (lquery*)palloc( totallen );
result->len = totallen;
result->numlevel = num;
***************
*** 322,335 ****
result->flag |= LQUERY_HASNOT;
cur = LQUERY_FIRST(result);
curqlevel = tmpql;
! while( curqlevel-tmpql < num ) {
memcpy(cur,curqlevel,LQL_HDRSIZE);
cur->totallen=LQL_HDRSIZE;
if ( curqlevel->numvar ) {
lrptr = LQL_FIRST(cur);
lptr = GETVAR(curqlevel);
while( lptr-GETVAR(curqlevel) < curqlevel->numvar ) {
! cur->totallen += LVAR_HDRSIZE + lptr->len;
lrptr->len = lptr->len;
lrptr->flag = lptr->flag;
lrptr->val = crc32_sz((uint8 *) lptr->start,
lptr->len);
--- 323,336 ----
result->flag |= LQUERY_HASNOT;
cur = LQUERY_FIRST(result);
curqlevel = tmpql;
! while( (char*)curqlevel-(char*)tmpql < num*ITEMSIZE ) {
memcpy(cur,curqlevel,LQL_HDRSIZE);
cur->totallen=LQL_HDRSIZE;
if ( curqlevel->numvar ) {
lrptr = LQL_FIRST(cur);
lptr = GETVAR(curqlevel);
while( lptr-GETVAR(curqlevel) < curqlevel->numvar ) {
! cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
lrptr->len = lptr->len;
lrptr->flag = lptr->flag;
lrptr->val = crc32_sz((uint8 *) lptr->start,
lptr->len);
***************
*** 344,350 ****
(result->firstgood)++;
} else
wasbad=true;
! curqlevel++;
cur = LQL_NEXT(cur);
}
--- 345,351 ----
(result->firstgood)++;
} else
wasbad=true;
! curqlevel = NEXTLEV(curqlevel);
cur = LQL_NEXT(cur);
}
diff -c contrib/ltree.old/ltree_op.c contrib/ltree/ltree_op.c
*** contrib/ltree.old/ltree_op.c Tue Jul 30 20:40:34 2002
--- contrib/ltree/ltree_op.c Wed Jul 31 21:31:47 2002
***************
*** 22,27 ****
--- 22,28 ----
PG_FUNCTION_INFO_V1(ltree_addltree);
PG_FUNCTION_INFO_V1(ltree_addtext);
PG_FUNCTION_INFO_V1(ltree_textadd);
+ PG_FUNCTION_INFO_V1(lca);
Datum ltree_cmp(PG_FUNCTION_ARGS);
Datum ltree_lt(PG_FUNCTION_ARGS);
Datum ltree_le(PG_FUNCTION_ARGS);
***************
*** 35,40 ****
--- 36,42 ----
Datum ltree_addltree(PG_FUNCTION_ARGS);
Datum ltree_addtext(PG_FUNCTION_ARGS);
Datum ltree_textadd(PG_FUNCTION_ARGS);
+ Datum lca(PG_FUNCTION_ARGS);
int
ltree_compare(const ltree *a, const ltree *b) {
***************
*** 308,310 ****
--- 310,388 ----
PG_FREE_IF_COPY(b,0);
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();
+ }
+
+
Only in contrib/ltree.old: patch.72
Common subdirectories: contrib/ltree.old/sql and contrib/ltree/sql
---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
(send "unregister YourEmailAddressHere" to [EMAIL PROTECTED])