Please, apply patch for contrib/ltree to current CVS and 7.3.2
authorBruce Momjian <bruce@momjian.us>
Mon, 31 Mar 2003 20:53:45 +0000 (20:53 +0000)
committerBruce Momjian <bruce@momjian.us>
Mon, 31 Mar 2003 20:53:45 +0000 (20:53 +0000)
CHANGES

Mar 28, 2003
    Added finctions index(ltree,ltree,offset), text2ltree(text),
                    ltree2text(text)

Teodor Sigaev

contrib/ltree/README.ltree
contrib/ltree/expected/ltree.out
contrib/ltree/ltree.sql.in
contrib/ltree/ltree_op.c
contrib/ltree/sql/ltree.sql

index e9471b4e3553fd10c6c3906335e968a7af5cbca2..249678147a1c90680452980fc31a107e9835a39c 100644 (file)
@@ -192,7 +192,24 @@ int4 nlevel
           3
     Note, that arguments start, end, OFFSET, LEN have meaning of level of the
     node !
-   
+
+int4 index(ltree,ltree), int4 index(ltree,ltree,OFFSET)
+    returns number of level of the first occurence of second argument in first
+    one beginning from OFFSET. if OFFSET is negative, than search begins from |
+    OFFSET| levels from the end of the path.
+     SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',3);
+      index
+     -------
+          6
+     SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',-4);
+      index  
+     -------
+          9
+  
+ltree text2ltree(text), text ltree2text(text)
+    cast functions for ltree and text.
+  
 ltree lca(ltree,ltree,...) (up to 8 arguments)
     ltree lca(ltree[])
     Returns Lowest Common Ancestor (lca)
@@ -432,6 +449,9 @@ appreciate your input. So far, below some (rather obvious) results:
 
 CHANGES
 
+Mar 28, 2003
+   Added functions index(ltree,ltree,offset), text2ltree(text),
+                   ltree2text(text)
 Feb 7, 2003
    Add ? operation
    Fix ~ operation bug: eg '1.1.1' ~ '*.1'
index f4ab1f637835672e6cc6972008bec7ccc1f83386..01246444f8955228259a82a229f380da98e8a037 100644 (file)
@@ -1,12 +1,12 @@
 \set ECHO none
 psql:ltree.sql:9: NOTICE:  ProcedureCreate: type ltree is not yet defined
 psql:ltree.sql:14: NOTICE:  Argument type "ltree" is only a shell
-psql:ltree.sql:281: NOTICE:  ProcedureCreate: type lquery is not yet defined
-psql:ltree.sql:286: NOTICE:  Argument type "lquery" is only a shell
-psql:ltree.sql:392: NOTICE:  ProcedureCreate: type ltxtquery is not yet defined
-psql:ltree.sql:397: NOTICE:  Argument type "ltxtquery" is only a shell
-psql:ltree.sql:459: NOTICE:  ProcedureCreate: type ltree_gist is not yet defined
-psql:ltree.sql:464: NOTICE:  Argument type "ltree_gist" is only a shell
+psql:ltree.sql:301: NOTICE:  ProcedureCreate: type lquery is not yet defined
+psql:ltree.sql:306: NOTICE:  Argument type "lquery" is only a shell
+psql:ltree.sql:412: NOTICE:  ProcedureCreate: type ltxtquery is not yet defined
+psql:ltree.sql:417: NOTICE:  Argument type "ltxtquery" is only a shell
+psql:ltree.sql:479: NOTICE:  ProcedureCreate: type ltree_gist is not yet defined
+psql:ltree.sql:484: NOTICE:  Argument type "ltree_gist" is only a shell
 SELECT ''::ltree;
  ltree 
 -------
@@ -31,6 +31,18 @@ SELECT '1.2._3'::ltree;
  1.2._3
 (1 row)
 
+SELECT ltree2text('1.2.3.34.sdf');
+  ltree2text  
+--------------
+ 1.2.3.34.sdf
+(1 row)
+
+SELECT text2ltree('1.2.3.34.sdf');
+  text2ltree  
+--------------
+ 1.2.3.34.sdf
+(1 row)
+
 SELECT subltree('Top.Child1.Child2',1,2);
  subltree 
 ----------
@@ -85,6 +97,114 @@ SELECT subpath('Top.Child1.Child2',1);
  Child1.Child2
 (1 row)
 
+SELECT index('1.2.3.4.5.6','1.2');
+ index 
+-------
+     0
+(1 row)
+
+SELECT index('a.1.2.3.4.5.6','1.2');
+ index 
+-------
+     1
+(1 row)
+
+SELECT index('a.1.2.3.4.5.6','1.2.3');
+ index 
+-------
+     1
+(1 row)
+
+SELECT index('a.1.2.3.4.5.6','1.2.3.j');
+ index 
+-------
+    -1
+(1 row)
+
+SELECT index('a.1.2.3.4.5.6','1.2.3.j.4.5.5.5.5.5.5');
+ index 
+-------
+    -1
+(1 row)
+
+SELECT index('a.1.2.3.4.5.6','1.2.3');
+ index 
+-------
+     1
+(1 row)
+
+SELECT index('a.1.2.3.4.5.6','6');
+ index 
+-------
+     6
+(1 row)
+
+SELECT index('a.1.2.3.4.5.6','6.1');
+ index 
+-------
+    -1
+(1 row)
+
+SELECT index('a.1.2.3.4.5.6','5.6');
+ index 
+-------
+     5
+(1 row)
+
+SELECT index('0.1.2.3.5.4.5.6','5.6');
+ index 
+-------
+     6
+(1 row)
+
+SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',3);
+ index 
+-------
+     6
+(1 row)
+
+SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',6);
+ index 
+-------
+     6
+(1 row)
+
+SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',7);
+ index 
+-------
+     9
+(1 row)
+
+SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',-7);
+ index 
+-------
+     6
+(1 row)
+
+SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',-4);
+ index 
+-------
+     9
+(1 row)
+
+SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',-3);
+ index 
+-------
+     9
+(1 row)
+
+SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',-2);
+ index 
+-------
+    -1
+(1 row)
+
+SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',-20000);
+ index 
+-------
+     6
+(1 row)
+
 SELECT 'Top.Child1.Child2'::ltree || 'Child3'::text;
          ?column?         
 --------------------------
index 3bf7617fff6777323aec77dcff69bd9ce16f9bc1..2f267b9828aecadaff57c772707ca6188755f078 100644 (file)
@@ -137,11 +137,31 @@ RETURNS ltree
 AS 'MODULE_PATHNAME'
 LANGUAGE 'C' WITH (isstrict,iscachable);
 
+CREATE FUNCTION index(ltree,ltree)
+RETURNS int4
+AS 'MODULE_PATHNAME', 'ltree_index'
+LANGUAGE 'C' WITH (isstrict,iscachable);
+
+CREATE FUNCTION index(ltree,ltree,int4)
+RETURNS int4
+AS 'MODULE_PATHNAME', 'ltree_index'
+LANGUAGE 'C' WITH (isstrict,iscachable);
+
 CREATE FUNCTION nlevel(ltree)
 RETURNS int4
 AS 'MODULE_PATHNAME'
 LANGUAGE 'C' WITH (isstrict,iscachable);
 
+CREATE FUNCTION ltree2text(ltree)
+RETURNS text
+AS 'MODULE_PATHNAME'
+LANGUAGE 'C' WITH (isstrict,iscachable);
+
+CREATE FUNCTION text2ltree(text)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE 'C' WITH (isstrict,iscachable);
+
 CREATE FUNCTION lca(_ltree)
 RETURNS ltree
 AS 'MODULE_PATHNAME','_lca'
index 4dcf6f736321eac1d352f1accb99601cad697b75..28fcfb7f7e3bfe4c053311ba54da113fd4e48924 100644 (file)
@@ -19,10 +19,13 @@ PG_FUNCTION_INFO_V1(ltree_isparent);
 PG_FUNCTION_INFO_V1(ltree_risparent);
 PG_FUNCTION_INFO_V1(subltree);
 PG_FUNCTION_INFO_V1(subpath);
+PG_FUNCTION_INFO_V1(ltree_index);
 PG_FUNCTION_INFO_V1(ltree_addltree);
 PG_FUNCTION_INFO_V1(ltree_addtext);
 PG_FUNCTION_INFO_V1(ltree_textadd);
 PG_FUNCTION_INFO_V1(lca);
+PG_FUNCTION_INFO_V1(ltree2text);
+PG_FUNCTION_INFO_V1(text2ltree);
 Datum      ltree_cmp(PG_FUNCTION_ARGS);
 Datum      ltree_lt(PG_FUNCTION_ARGS);
 Datum      ltree_le(PG_FUNCTION_ARGS);
@@ -33,10 +36,13 @@ Datum       ltree_gt(PG_FUNCTION_ARGS);
 Datum      nlevel(PG_FUNCTION_ARGS);
 Datum      subltree(PG_FUNCTION_ARGS);
 Datum      subpath(PG_FUNCTION_ARGS);
+Datum      ltree_index(PG_FUNCTION_ARGS);
 Datum      ltree_addltree(PG_FUNCTION_ARGS);
 Datum      ltree_addtext(PG_FUNCTION_ARGS);
 Datum      ltree_textadd(PG_FUNCTION_ARGS);
 Datum      lca(PG_FUNCTION_ARGS);
+Datum      ltree2text(PG_FUNCTION_ARGS);
+Datum      text2ltree(PG_FUNCTION_ARGS);
 
 int
 ltree_compare(const ltree * a, const ltree * b)
@@ -317,6 +323,57 @@ ltree_addtext(PG_FUNCTION_ARGS)
    PG_RETURN_POINTER(r);
 }
 
+Datum
+ltree_index(PG_FUNCTION_ARGS)
+{
+   ltree      *a = PG_GETARG_LTREE(0);
+   ltree      *b = PG_GETARG_LTREE(1);
+   int start=(fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
+   int i,j;
+   ltree_level *startptr, *aptr, *bptr;
+   bool found=false;
+
+   if ( start < 0 ) {
+       if ( -start >= a->numlevel ) 
+           start=0;
+       else 
+           start = (int)(a->numlevel)+start;
+   }
+
+   if ( a->numlevel - start < b->numlevel || a->numlevel==0 || b->numlevel==0 ) {
+       PG_FREE_IF_COPY(a, 0);
+       PG_FREE_IF_COPY(b, 1);
+       PG_RETURN_INT32(-1);
+   }
+
+   startptr=LTREE_FIRST(a);
+   for(i=0; i<=a->numlevel-b->numlevel; i++) {
+       if ( i>=start ) {
+           aptr=startptr;
+           bptr=LTREE_FIRST(b);
+           for(j=0;j<b->numlevel;j++) {
+               if ( !(aptr->len==bptr->len && strncmp(aptr->name,bptr->name, aptr->len)==0) )
+                   break; 
+               aptr=LEVEL_NEXT(aptr);
+               bptr=LEVEL_NEXT(bptr);
+           }
+   
+           if ( j==b->numlevel ) {
+               found=true;
+               break;
+           }
+       }
+       startptr=LEVEL_NEXT(startptr);  
+   }
+   
+   if ( !found ) 
+       i=-1;
+
+   PG_FREE_IF_COPY(a, 0);
+   PG_FREE_IF_COPY(b, 1);
+   PG_RETURN_INT32(i);
+}
+
 Datum
 ltree_textadd(PG_FUNCTION_ARGS)
 {
@@ -431,3 +488,55 @@ lca(PG_FUNCTION_ARGS)
    else
        PG_RETURN_NULL();
 }
+
+Datum
+text2ltree(PG_FUNCTION_ARGS)
+{
+   text       *in = PG_GETARG_TEXT_P(0);
+   char *s = (char *) palloc(VARSIZE(in) - VARHDRSZ + 1);
+   ltree *out;
+
+   memcpy(s, VARDATA(in), VARSIZE(in) - VARHDRSZ);
+   s[VARSIZE(in) - VARHDRSZ] = '\0';
+
+   out = (ltree *) DatumGetPointer(DirectFunctionCall1(
+               ltree_in,
+               PointerGetDatum(s)
+           ));
+   pfree(s);
+   PG_FREE_IF_COPY(in,0);
+   PG_RETURN_POINTER(out);
+}
+
+
+Datum
+ltree2text(PG_FUNCTION_ARGS)
+{
+   ltree      *in = PG_GETARG_LTREE(0);
+   char       *ptr;
+   int                     i;
+   ltree_level *curlevel;
+   text    *out;
+                    
+   out=(text*)palloc(in->len+VARHDRSZ);
+   ptr = VARDATA(out); 
+   curlevel = LTREE_FIRST(in);
+   for (i = 0; i < in->numlevel; i++) {
+       if (i != 0) {
+           *ptr = '.';
+           ptr++;
+       }
+       memcpy(ptr, curlevel->name, curlevel->len);
+       ptr += curlevel->len;
+       curlevel = LEVEL_NEXT(curlevel);
+   }
+               
+   VARATT_SIZEP(out) = VARHDRSZ + (ptr-VARDATA(out)); 
+   PG_FREE_IF_COPY(in, 0);
+        
+   PG_RETURN_POINTER(out);
+}
+
+   
+
+
index 9e8f485f1e5c28d1d6e52385048673d0d6954596..8d28c9e53e8cd69edd27b6e0d368072a8d862bae 100644 (file)
@@ -7,6 +7,9 @@ SELECT '1'::ltree;
 SELECT '1.2'::ltree;
 SELECT '1.2._3'::ltree;
 
+SELECT ltree2text('1.2.3.34.sdf');
+SELECT text2ltree('1.2.3.34.sdf');
+
 SELECT subltree('Top.Child1.Child2',1,2);
 SELECT subpath('Top.Child1.Child2',1,2);
 SELECT subpath('Top.Child1.Child2',-1,1);
@@ -17,6 +20,27 @@ SELECT subpath('Top.Child1.Child2',1,0);
 SELECT subpath('Top.Child1.Child2',0);
 SELECT subpath('Top.Child1.Child2',1);
 
+
+SELECT index('1.2.3.4.5.6','1.2');
+SELECT index('a.1.2.3.4.5.6','1.2');
+SELECT index('a.1.2.3.4.5.6','1.2.3');
+SELECT index('a.1.2.3.4.5.6','1.2.3.j');
+SELECT index('a.1.2.3.4.5.6','1.2.3.j.4.5.5.5.5.5.5');
+SELECT index('a.1.2.3.4.5.6','1.2.3');
+SELECT index('a.1.2.3.4.5.6','6');
+SELECT index('a.1.2.3.4.5.6','6.1');
+SELECT index('a.1.2.3.4.5.6','5.6');
+SELECT index('0.1.2.3.5.4.5.6','5.6');
+SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',3);
+SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',6);
+SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',7);
+SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',-7);
+SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',-4);
+SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',-3);
+SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',-2);
+SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',-20000);
+
+
 SELECT 'Top.Child1.Child2'::ltree || 'Child3'::text;
 SELECT 'Top.Child1.Child2'::ltree || 'Child3'::ltree;
 SELECT 'Top_0'::ltree || 'Top.Child1.Child2'::ltree;