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])

Reply via email to