diff --git a/contrib/ltree/README.ltree b/contrib/ltree/README.ltree
index e9471b4e3553fd10c6c3906335e968a7af5cbca2..249678147a1c90680452980fc31a107e9835a39c 100644
--- a/contrib/ltree/README.ltree
+++ b/contrib/ltree/README.ltree
@@ -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'
diff --git a/contrib/ltree/expected/ltree.out b/contrib/ltree/expected/ltree.out
index f4ab1f637835672e6cc6972008bec7ccc1f83386..01246444f8955228259a82a229f380da98e8a037 100644
--- a/contrib/ltree/expected/ltree.out
+++ b/contrib/ltree/expected/ltree.out
@@ -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?         
 --------------------------
diff --git a/contrib/ltree/ltree.sql.in b/contrib/ltree/ltree.sql.in
index 3bf7617fff6777323aec77dcff69bd9ce16f9bc1..2f267b9828aecadaff57c772707ca6188755f078 100644
--- a/contrib/ltree/ltree.sql.in
+++ b/contrib/ltree/ltree.sql.in
@@ -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'
diff --git a/contrib/ltree/ltree_op.c b/contrib/ltree/ltree_op.c
index 4dcf6f736321eac1d352f1accb99601cad697b75..28fcfb7f7e3bfe4c053311ba54da113fd4e48924 100644
--- a/contrib/ltree/ltree_op.c
+++ b/contrib/ltree/ltree_op.c
@@ -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);
+}
+
+	
+
+
diff --git a/contrib/ltree/sql/ltree.sql b/contrib/ltree/sql/ltree.sql
index 9e8f485f1e5c28d1d6e52385048673d0d6954596..8d28c9e53e8cd69edd27b6e0d368072a8d862bae 100644
--- a/contrib/ltree/sql/ltree.sql
+++ b/contrib/ltree/sql/ltree.sql
@@ -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;