From 71e1f531d36b1fb54d0fa2568c26c4f1f44cab3f Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Wed, 19 Feb 2003 03:50:09 +0000
Subject: [PATCH] Please apply patches for contrib/ltree.

ltree_73.patch.gz - for 7.3 :
        Fix ~ operation bug: eg '1.1.1' ~ '*.1'

ltree_74.patch.gz - for current CVS
    Fix ~ operation bug: eg '1.1.1' ~ '*.1'
    Add ? operation
    Optimize index storage

Last change needs drop/create all ltree indexes, so only for 7.4

Teodor Sigaev
---
 contrib/ltree/README.ltree       |  14 +-
 contrib/ltree/_ltree_gist.c      |  29 ++-
 contrib/ltree/_ltree_op.c        |  38 ++++
 contrib/ltree/expected/ltree.out | 324 ++++++++++++++++++++-----------
 contrib/ltree/lquery_op.c        |  69 ++++++-
 contrib/ltree/ltree.h            |   6 +-
 contrib/ltree/ltree.sql.in       |  97 +++++++++
 contrib/ltree/ltree_gist.c       |  30 ++-
 contrib/ltree/sql/ltree.sql      |  30 ++-
 9 files changed, 509 insertions(+), 128 deletions(-)

diff --git a/contrib/ltree/README.ltree b/contrib/ltree/README.ltree
index a23f7b09458..e9471b4e355 100644
--- a/contrib/ltree/README.ltree
+++ b/contrib/ltree/README.ltree
@@ -110,6 +110,9 @@ ltree <@ ltree
     equal).
 ltree ~ lquery, lquery ~ ltree
     - return TRUE if node represented by ltree satisfies lquery.
+ltree ? lquery[], lquery ? ltree[]
+    - return TRUE if node represented by ltree satisfies at least one lquery
+	from array.
 ltree @ ltxtquery, ltxtquery @ ltree
     - return TRUE if node represented by ltree satisfies ltxtquery.
 ltree || ltree, ltree || text, text || ltree
@@ -123,6 +126,9 @@ ltree @> ltree[], ltree[] <@ ltree
     - returns TRUE if array ltree[] contains a descendant of ltree.
 ltree[] ~ lquery, lquery ~ ltree[]
     - returns TRUE if array ltree[] contains label paths matched lquery.
+ltree[] ? lquery[], lquery[] ? ltree[]
+    - returns TRUE if array ltree[] contains label paths matched atleaset one
+	lquery from array.
 ltree[] @ ltxtquery, ltxtquery @ ltree[]
     - returns TRUE if array ltree[] contains label paths matched ltxtquery
     (full text search).
@@ -142,11 +148,11 @@ Various indices could be created to speed up execution of operations:
   * B-tree index over ltree:
     <, <=, =, =>, >
   * GiST index over ltree:
-    <, <=, =, =>, >, @>, <@, @, ~
+    <, <=, =, =>, >, @>, <@, @, ~, ?
     Example:
     create index path_gist_idx on test using gist (path);
   * GiST index over ltree[]:
-    ltree[]<@ ltree, ltree @> ltree[], @, ~.
+    ltree[]<@ ltree, ltree @> ltree[], @, ~, ?.
     Example:
     create index path_gist_idx on test using gist (array_path);
     Notices: This index is lossy.
@@ -426,6 +432,10 @@ appreciate your input. So far, below some (rather obvious) results:
 
 CHANGES
 
+Feb 7, 2003
+   Add ? operation
+   Fix ~ operation bug: eg '1.1.1' ~ '*.1'
+   Optimize index storage
 Aug 9, 2002
    Fixed very stupid but important bug :-)
 July 31, 2002
diff --git a/contrib/ltree/_ltree_gist.c b/contrib/ltree/_ltree_gist.c
index d8efd8096d0..1791f5bd8d4 100644
--- a/contrib/ltree/_ltree_gist.c
+++ b/contrib/ltree/_ltree_gist.c
@@ -96,7 +96,7 @@ _ltree_compress(PG_FUNCTION_ARGS)
 					  entry->rel, entry->page,
 					  entry->offset, key->len, FALSE);
 	}
-	else
+	else if ( !LTG_ISALLTRUE(entry->key) ) 
 	{
 		int4		i,
 					len;
@@ -105,10 +105,9 @@ _ltree_compress(PG_FUNCTION_ARGS)
 		BITVECP		sign = LTG_SIGN(DatumGetPointer(entry->key));
 
 		ALOOPBYTE(
-				  if (sign[i] != 0xff)
+				  if ((sign[i]&0xff) != 0xff)
 				  PG_RETURN_POINTER(retval);
 		);
-
 		len = LTG_HDRSIZE;
 		key = (ltree_gist *) palloc(len);
 		key->len = len;
@@ -222,7 +221,7 @@ _ltree_penalty(PG_FUNCTION_ARGS)
 
 	if (LTG_ISALLTRUE(origval))
 	{
-		*penalty = 0.0;
+		*penalty = 0.1;
 		PG_RETURN_POINTER(penalty);
 	}
 
@@ -489,7 +488,7 @@ _ltree_picksplit(PG_FUNCTION_ARGS)
 			);
 		}
 
-		if (size_alpha - size_l < size_beta - size_r + WISH_F(v->spl_nleft, v->spl_nright, 0.1))
+		if (size_alpha - size_l < size_beta - size_r + WISH_F(v->spl_nleft, v->spl_nright, 0.00001))
 		{
 			if (!LTG_ISALLTRUE(datum_l))
 			{
@@ -613,6 +612,22 @@ gist_qe(ltree_gist * key, lquery * query)
 	return true;
 }
 
+static bool
+_arrq_cons(ltree_gist *key, ArrayType *_query) {
+        lquery  *query = (lquery *) ARR_DATA_PTR(_query);
+        int     num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
+
+        if (ARR_NDIM(_query) != 1)
+                elog(ERROR, "Dimension of array != 1");
+
+        while (num > 0) {
+                if ( gist_qe(key, query) )
+                        return true;
+                num--;
+                query = (lquery*)NEXTVAL(query);
+        }
+        return false;
+}
 
 Datum
 _ltree_consistent(PG_FUNCTION_ARGS)
@@ -641,6 +656,10 @@ _ltree_consistent(PG_FUNCTION_ARGS)
 		case 15:
 			res = gist_qtxt(key, (ltxtquery *) query);
 			break;
+		case 16:
+		case 17:
+			res = _arrq_cons(key, (ArrayType *) query);
+			break;
 		default:
 			elog(ERROR, "Unknown StrategyNumber: %d", strategy);
 	}
diff --git a/contrib/ltree/_ltree_op.c b/contrib/ltree/_ltree_op.c
index 59de0a51e4a..f7cd8f2ab6a 100644
--- a/contrib/ltree/_ltree_op.c
+++ b/contrib/ltree/_ltree_op.c
@@ -13,6 +13,8 @@ PG_FUNCTION_INFO_V1(_ltree_risparent);
 PG_FUNCTION_INFO_V1(_ltree_r_risparent);
 PG_FUNCTION_INFO_V1(_ltq_regex);
 PG_FUNCTION_INFO_V1(_ltq_rregex);
+PG_FUNCTION_INFO_V1(_lt_q_regex);
+PG_FUNCTION_INFO_V1(_lt_q_rregex);
 PG_FUNCTION_INFO_V1(_ltxtq_exec);
 PG_FUNCTION_INFO_V1(_ltxtq_rexec);
 
@@ -126,6 +128,42 @@ _ltq_rregex(PG_FUNCTION_ARGS)
 										));
 }
 
+Datum
+_lt_q_regex(PG_FUNCTION_ARGS)
+{
+        ArrayType      *_tree = PG_GETARG_ARRAYTYPE_P(0);
+        ArrayType   *_query =  PG_GETARG_ARRAYTYPE_P(1);
+        lquery  *query = (lquery *) ARR_DATA_PTR(_query);
+        bool    res = false;
+        int     num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
+
+        if (ARR_NDIM(_query) != 1)
+                elog(ERROR, "Dimension of array != 1");
+
+        while (num > 0) {
+		if ( array_iterator(_tree, ltq_regex, (void*)query, NULL) ) {
+                        res = true;
+                        break;
+                }
+                num--;
+                query = (lquery*)NEXTVAL(query);
+        }
+
+        PG_FREE_IF_COPY(_tree, 0);
+        PG_FREE_IF_COPY(_query, 1);
+        PG_RETURN_BOOL(res);
+}
+
+Datum
+_lt_q_rregex(PG_FUNCTION_ARGS)
+{
+        PG_RETURN_DATUM(DirectFunctionCall2(_lt_q_regex,
+                                                                                PG_GETARG_DATUM(1),
+                                                                                PG_GETARG_DATUM(0)
+                                                                                ));
+}
+
+
 Datum
 _ltxtq_exec(PG_FUNCTION_ARGS)
 {
diff --git a/contrib/ltree/expected/ltree.out b/contrib/ltree/expected/ltree.out
index 1b6526c5e9c..f4ab1f63783 100644
--- a/contrib/ltree/expected/ltree.out
+++ b/contrib/ltree/expected/ltree.out
@@ -3,10 +3,10 @@ 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:345: NOTICE:  ProcedureCreate: type ltxtquery is not yet defined
-psql:ltree.sql:350: NOTICE:  Argument type "ltxtquery" is only a shell
-psql:ltree.sql:412: NOTICE:  ProcedureCreate: type ltree_gist is not yet defined
-psql:ltree.sql:417: NOTICE:  Argument type "ltree_gist" 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
 SELECT ''::ltree;
  ltree 
 -------
@@ -963,6 +963,36 @@ SELECT '{j.k.l.m, g.b.c.d.e}'::ltree[] ~ 'A*@|g.b.c.d.e';
  t
 (1 row)
 
+SELECT 'a.b.c.d.e'::ltree ? '{A.b.c.d.e}';
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT 'a.b.c.d.e'::ltree ? '{a.b.c.d.e}';
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT 'a.b.c.d.e'::ltree ? '{A.b.c.d.e, a.*}';
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT '{a.b.c.d.e,B.df}'::ltree[] ? '{A.b.c.d.e}';
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT '{a.b.c.d.e,B.df}'::ltree[] ? '{A.b.c.d.e,*.df}';
+ ?column? 
+----------
+ t
+(1 row)
+
 --exractors
 SELECT ('{3456,1.2.3.34}'::ltree[] ?@> '1.2.3.4') is null;
  ?column? 
@@ -3058,6 +3088,50 @@ SELECT * FROM ltreetest WHERE t <@ '1.1.1' order by t asc;
  1.1.1.2.1
 (4 rows)
 
+SELECT * FROM ltreetest WHERE t @ '23 & 1' order by t asc;
+               t                
+--------------------------------
+ 1.10.23.25.5.11
+ 1.10.4.18.22.23.24
+ 1.12.25.26.22.8.15.23
+ 1.19.22.11.14.7.32.23.19.14
+ 1.21.28.4.23
+ 1.26.15.23.5.31.29.11.19.28.1
+ 1.27.22.23.2.26.32.17.7.9
+ 10.12.9.6.6.26.14.8.23.1.25
+ 12.27.23.32.1.1.9.29.13
+ 14.1.15.25.27.23.25.26.28.10
+ 14.27.29.23.4.1.17.32.6.25.22
+ 15.11.26.1.30.6.23.5
+ 19.22.29.32.1.21.26.24.23.17
+ 19.9.32.23.13.24.1
+ 21.23.17.8.23.11.8.1
+ 22.30.31.24.23.22.5.20.28.1
+ 23.1.23.18.12.29
+ 23.12.1.5.32.25.8.24.1.25
+ 23.12.32.22.19.1.22.4
+ 23.17.22.1.23.4.29.32.4.1
+ 23.17.25.4.1.16.29.10
+ 23.19.17.31.29.13.1.12.5.25
+ 23.22.10.1.14.24
+ 23.28.1
+ 23.3.32.21.5.14.10.17.1
+ 27.29.1.5.30.6.22.16.23.2.28
+ 28.23.2.30.3.8.1.15.15.14.13
+ 29.23.1.21.31.8
+ 29.23.15.25.1.6.6.10
+ 30.23.10.1.10.7.22.28.18.11.17
+ 31.30.23.7.7.24.32.10.11.1.31
+ 32.1.23.20.14.12.23.5.32.15
+ 32.15.20.28.5.1.23.4
+ 5.13.23.19.28.26.27.6.1.22
+ 6.18.1.4.18.23
+ 7.23.1.24.29.13.31.19.23.17.7
+ 8.16.1.16.28.6.3.22.6.23
+ 8.2.18.23.5.16.17.1
+ 9.5.9.3.23.9.25.14.1.29.28
+(39 rows)
+
 SELECT * FROM ltreetest WHERE t ~ '1.1.1.*' order by t asc;
      t     
 -----------
@@ -3071,9 +3145,17 @@ SELECT * FROM ltreetest WHERE t ~ '*.1' order by t asc;
                t                
 --------------------------------
  1
+ 1.1
+ 1.1.1
+ 1.1.1.1
+ 1.1.1.2.1
+ 1.1.2.1
+ 1.26.15.23.5.31.29.11.19.28.1
+ 10.13.22.1.8.30.9.24.1.2.1
  10.22.1
  10.26.30.15.1
  11.1
+ 12.1.1
  17.25.2.13.10.27.13.1
  18.13.6.12.26.26.26.29.18.20.1
  19.20.25.7.27.28.27.17.9.3.1
@@ -3083,6 +3165,7 @@ SELECT * FROM ltreetest WHERE t ~ '*.1' order by t asc;
  21.18.2.1
  21.23.17.8.23.11.8.1
  22.30.31.24.23.22.5.20.28.1
+ 23.17.22.1.23.4.29.32.4.1
  23.28.1
  23.3.32.21.5.14.10.17.1
  25.6.12.16.1
@@ -3095,14 +3178,7 @@ SELECT * FROM ltreetest WHERE t ~ '*.1' order by t asc;
  8.2.18.23.5.16.17.1
  8.32.30.1
  9.21.20.29.1
-(25 rows)
-
-SELECT * FROM ltreetest WHERE t ~ '23.*.1' order by t asc;
-            t            
--------------------------
- 23.28.1
- 23.3.32.21.5.14.10.17.1
-(2 rows)
+(34 rows)
 
 SELECT * FROM ltreetest WHERE t ~ '23.*{1}.1' order by t asc;
     t    
@@ -3110,49 +3186,28 @@ SELECT * FROM ltreetest WHERE t ~ '23.*{1}.1' order by t asc;
  23.28.1
 (1 row)
 
-SELECT * FROM ltreetest WHERE t @ '23 & 1' order by t asc;
-               t                
---------------------------------
- 1.10.23.25.5.11
- 1.10.4.18.22.23.24
- 1.12.25.26.22.8.15.23
- 1.19.22.11.14.7.32.23.19.14
- 1.21.28.4.23
- 1.26.15.23.5.31.29.11.19.28.1
- 1.27.22.23.2.26.32.17.7.9
- 10.12.9.6.6.26.14.8.23.1.25
- 12.27.23.32.1.1.9.29.13
- 14.1.15.25.27.23.25.26.28.10
- 14.27.29.23.4.1.17.32.6.25.22
- 15.11.26.1.30.6.23.5
- 19.22.29.32.1.21.26.24.23.17
- 19.9.32.23.13.24.1
- 21.23.17.8.23.11.8.1
- 22.30.31.24.23.22.5.20.28.1
- 23.1.23.18.12.29
- 23.12.1.5.32.25.8.24.1.25
- 23.12.32.22.19.1.22.4
+SELECT * FROM ltreetest WHERE t ~ '23.*.1' order by t asc;
+             t             
+---------------------------
  23.17.22.1.23.4.29.32.4.1
- 23.17.25.4.1.16.29.10
- 23.19.17.31.29.13.1.12.5.25
- 23.22.10.1.14.24
  23.28.1
  23.3.32.21.5.14.10.17.1
- 27.29.1.5.30.6.22.16.23.2.28
- 28.23.2.30.3.8.1.15.15.14.13
- 29.23.1.21.31.8
- 29.23.15.25.1.6.6.10
- 30.23.10.1.10.7.22.28.18.11.17
- 31.30.23.7.7.24.32.10.11.1.31
- 32.1.23.20.14.12.23.5.32.15
- 32.15.20.28.5.1.23.4
- 5.13.23.19.28.26.27.6.1.22
- 6.18.1.4.18.23
- 7.23.1.24.29.13.31.19.23.17.7
- 8.16.1.16.28.6.3.22.6.23
- 8.2.18.23.5.16.17.1
- 9.5.9.3.23.9.25.14.1.29.28
-(39 rows)
+(3 rows)
+
+SELECT * FROM ltreetest WHERE t ~ '23.*.2' order by t asc;
+        t         
+------------------
+ 23.20.12.16.15.2
+(1 row)
+
+SELECT * FROM ltreetest WHERE t ? '{23.*.1,23.*.2}' order by t asc;
+             t             
+---------------------------
+ 23.17.22.1.23.4.29.32.4.1
+ 23.20.12.16.15.2
+ 23.28.1
+ 23.3.32.21.5.14.10.17.1
+(4 rows)
 
 create unique index tstidx on ltreetest (t);
 set enable_seqscan=off;
@@ -7253,6 +7308,50 @@ SELECT * FROM ltreetest WHERE t <@ '1.1.1' order by t asc;
  1.1.1.2.1
 (4 rows)
 
+SELECT * FROM ltreetest WHERE t @ '23 & 1' order by t asc;
+               t                
+--------------------------------
+ 1.10.23.25.5.11
+ 1.10.4.18.22.23.24
+ 1.12.25.26.22.8.15.23
+ 1.19.22.11.14.7.32.23.19.14
+ 1.21.28.4.23
+ 1.26.15.23.5.31.29.11.19.28.1
+ 1.27.22.23.2.26.32.17.7.9
+ 10.12.9.6.6.26.14.8.23.1.25
+ 12.27.23.32.1.1.9.29.13
+ 14.1.15.25.27.23.25.26.28.10
+ 14.27.29.23.4.1.17.32.6.25.22
+ 15.11.26.1.30.6.23.5
+ 19.22.29.32.1.21.26.24.23.17
+ 19.9.32.23.13.24.1
+ 21.23.17.8.23.11.8.1
+ 22.30.31.24.23.22.5.20.28.1
+ 23.1.23.18.12.29
+ 23.12.1.5.32.25.8.24.1.25
+ 23.12.32.22.19.1.22.4
+ 23.17.22.1.23.4.29.32.4.1
+ 23.17.25.4.1.16.29.10
+ 23.19.17.31.29.13.1.12.5.25
+ 23.22.10.1.14.24
+ 23.28.1
+ 23.3.32.21.5.14.10.17.1
+ 27.29.1.5.30.6.22.16.23.2.28
+ 28.23.2.30.3.8.1.15.15.14.13
+ 29.23.1.21.31.8
+ 29.23.15.25.1.6.6.10
+ 30.23.10.1.10.7.22.28.18.11.17
+ 31.30.23.7.7.24.32.10.11.1.31
+ 32.1.23.20.14.12.23.5.32.15
+ 32.15.20.28.5.1.23.4
+ 5.13.23.19.28.26.27.6.1.22
+ 6.18.1.4.18.23
+ 7.23.1.24.29.13.31.19.23.17.7
+ 8.16.1.16.28.6.3.22.6.23
+ 8.2.18.23.5.16.17.1
+ 9.5.9.3.23.9.25.14.1.29.28
+(39 rows)
+
 SELECT * FROM ltreetest WHERE t ~ '1.1.1.*' order by t asc;
      t     
 -----------
@@ -7266,9 +7365,17 @@ SELECT * FROM ltreetest WHERE t ~ '*.1' order by t asc;
                t                
 --------------------------------
  1
+ 1.1
+ 1.1.1
+ 1.1.1.1
+ 1.1.1.2.1
+ 1.1.2.1
+ 1.26.15.23.5.31.29.11.19.28.1
+ 10.13.22.1.8.30.9.24.1.2.1
  10.22.1
  10.26.30.15.1
  11.1
+ 12.1.1
  17.25.2.13.10.27.13.1
  18.13.6.12.26.26.26.29.18.20.1
  19.20.25.7.27.28.27.17.9.3.1
@@ -7278,6 +7385,7 @@ SELECT * FROM ltreetest WHERE t ~ '*.1' order by t asc;
  21.18.2.1
  21.23.17.8.23.11.8.1
  22.30.31.24.23.22.5.20.28.1
+ 23.17.22.1.23.4.29.32.4.1
  23.28.1
  23.3.32.21.5.14.10.17.1
  25.6.12.16.1
@@ -7290,14 +7398,7 @@ SELECT * FROM ltreetest WHERE t ~ '*.1' order by t asc;
  8.2.18.23.5.16.17.1
  8.32.30.1
  9.21.20.29.1
-(25 rows)
-
-SELECT * FROM ltreetest WHERE t ~ '23.*.1' order by t asc;
-            t            
--------------------------
- 23.28.1
- 23.3.32.21.5.14.10.17.1
-(2 rows)
+(34 rows)
 
 SELECT * FROM ltreetest WHERE t ~ '23.*{1}.1' order by t asc;
     t    
@@ -7305,49 +7406,28 @@ SELECT * FROM ltreetest WHERE t ~ '23.*{1}.1' order by t asc;
  23.28.1
 (1 row)
 
-SELECT * FROM ltreetest WHERE t @ '23 & 1' order by t asc;
-               t                
---------------------------------
- 1.10.23.25.5.11
- 1.10.4.18.22.23.24
- 1.12.25.26.22.8.15.23
- 1.19.22.11.14.7.32.23.19.14
- 1.21.28.4.23
- 1.26.15.23.5.31.29.11.19.28.1
- 1.27.22.23.2.26.32.17.7.9
- 10.12.9.6.6.26.14.8.23.1.25
- 12.27.23.32.1.1.9.29.13
- 14.1.15.25.27.23.25.26.28.10
- 14.27.29.23.4.1.17.32.6.25.22
- 15.11.26.1.30.6.23.5
- 19.22.29.32.1.21.26.24.23.17
- 19.9.32.23.13.24.1
- 21.23.17.8.23.11.8.1
- 22.30.31.24.23.22.5.20.28.1
- 23.1.23.18.12.29
- 23.12.1.5.32.25.8.24.1.25
- 23.12.32.22.19.1.22.4
+SELECT * FROM ltreetest WHERE t ~ '23.*.1' order by t asc;
+             t             
+---------------------------
  23.17.22.1.23.4.29.32.4.1
- 23.17.25.4.1.16.29.10
- 23.19.17.31.29.13.1.12.5.25
- 23.22.10.1.14.24
  23.28.1
  23.3.32.21.5.14.10.17.1
- 27.29.1.5.30.6.22.16.23.2.28
- 28.23.2.30.3.8.1.15.15.14.13
- 29.23.1.21.31.8
- 29.23.15.25.1.6.6.10
- 30.23.10.1.10.7.22.28.18.11.17
- 31.30.23.7.7.24.32.10.11.1.31
- 32.1.23.20.14.12.23.5.32.15
- 32.15.20.28.5.1.23.4
- 5.13.23.19.28.26.27.6.1.22
- 6.18.1.4.18.23
- 7.23.1.24.29.13.31.19.23.17.7
- 8.16.1.16.28.6.3.22.6.23
- 8.2.18.23.5.16.17.1
- 9.5.9.3.23.9.25.14.1.29.28
-(39 rows)
+(3 rows)
+
+SELECT * FROM ltreetest WHERE t ~ '23.*.2' order by t asc;
+        t         
+------------------
+ 23.20.12.16.15.2
+(1 row)
+
+SELECT * FROM ltreetest WHERE t ? '{23.*.1,23.*.2}' order by t asc;
+             t             
+---------------------------
+ 23.17.22.1.23.4.29.32.4.1
+ 23.20.12.16.15.2
+ 23.28.1
+ 23.3.32.21.5.14.10.17.1
+(4 rows)
 
 create table _ltreetest (t ltree[]);
 \copy _ltreetest FROM 'data/_ltree.data'
@@ -7363,6 +7443,12 @@ SELECT count(*) FROM _ltreetest WHERE t <@ '1.1.1' ;
     19
 (1 row)
 
+SELECT count(*) FROM _ltreetest WHERE t @ '23 & 1' ;
+ count 
+-------
+   147
+(1 row)
+
 SELECT count(*) FROM _ltreetest WHERE t ~ '1.1.1.*' ;
  count 
 -------
@@ -7372,25 +7458,31 @@ SELECT count(*) FROM _ltreetest WHERE t ~ '1.1.1.*' ;
 SELECT count(*) FROM _ltreetest WHERE t ~ '*.1' ;
  count 
 -------
-    83
+   109
+(1 row)
+
+SELECT count(*) FROM _ltreetest WHERE t ~ '23.*{1}.1' ;
+ count 
+-------
+     5
 (1 row)
 
 SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.1' ;
  count 
 -------
-    10
+    11
 (1 row)
 
-SELECT count(*) FROM _ltreetest WHERE t ~ '23.*{1}.1' ;
+SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.2' ;
  count 
 -------
      5
 (1 row)
 
-SELECT count(*) FROM _ltreetest WHERE t @ '23 & 1' ;
+SELECT count(*) FROM _ltreetest WHERE t ? '{23.*.1,23.*.2}' ;
  count 
 -------
-   147
+    15
 (1 row)
 
 create index _tstidx on _ltreetest using gist (t);
@@ -7407,6 +7499,12 @@ SELECT count(*) FROM _ltreetest WHERE t <@ '1.1.1' ;
     19
 (1 row)
 
+SELECT count(*) FROM _ltreetest WHERE t @ '23 & 1' ;
+ count 
+-------
+   147
+(1 row)
+
 SELECT count(*) FROM _ltreetest WHERE t ~ '1.1.1.*' ;
  count 
 -------
@@ -7416,24 +7514,30 @@ SELECT count(*) FROM _ltreetest WHERE t ~ '1.1.1.*' ;
 SELECT count(*) FROM _ltreetest WHERE t ~ '*.1' ;
  count 
 -------
-    83
+   109
+(1 row)
+
+SELECT count(*) FROM _ltreetest WHERE t ~ '23.*{1}.1' ;
+ count 
+-------
+     5
 (1 row)
 
 SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.1' ;
  count 
 -------
-    10
+    11
 (1 row)
 
-SELECT count(*) FROM _ltreetest WHERE t ~ '23.*{1}.1' ;
+SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.2' ;
  count 
 -------
      5
 (1 row)
 
-SELECT count(*) FROM _ltreetest WHERE t @ '23 & 1' ;
+SELECT count(*) FROM _ltreetest WHERE t ? '{23.*.1,23.*.2}' ;
  count 
 -------
-   147
+    15
 (1 row)
 
diff --git a/contrib/ltree/lquery_op.c b/contrib/ltree/lquery_op.c
index e24cc8559fc..1156723d58a 100644
--- a/contrib/ltree/lquery_op.c
+++ b/contrib/ltree/lquery_op.c
@@ -5,10 +5,16 @@
 
 #include "ltree.h"
 #include <ctype.h>
+#include "utils/array.h"
 
 PG_FUNCTION_INFO_V1(ltq_regex);
 PG_FUNCTION_INFO_V1(ltq_rregex);
 
+PG_FUNCTION_INFO_V1(lt_q_regex);
+PG_FUNCTION_INFO_V1(lt_q_rregex);
+
+#define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
+
 typedef struct
 {
 	lquery_level *q;
@@ -39,7 +45,7 @@ getlexem(char *start, char *end, int *len)
 }
 
 bool
-			compare_subnode(ltree_level * t, char *qn, int len, int (*cmpptr) (const char *, const char *, size_t), bool anyend)
+compare_subnode(ltree_level * t, char *qn, int len, int (*cmpptr) (const char *, const char *, size_t), bool anyend)
 {
 	char	   *endt = t->name + t->len;
 	char	   *endq = qn + len;
@@ -117,6 +123,11 @@ printFieldNot(FieldNot *fn ) {
 }
 */
 
+static struct {
+	bool muse;
+	uint32	high_pos;
+} SomeStack = {false,0,};
+
 static bool
 checkCond(lquery_level * curq, int query_numlevel, ltree_level * curt, int tree_numlevel, FieldNot * ptr)
 {
@@ -129,6 +140,14 @@ checkCond(lquery_level * curq, int query_numlevel, ltree_level * curt, int tree_
 	lquery_level *prevq = NULL;
 	ltree_level *prevt = NULL;
 
+	if ( SomeStack.muse ) {
+		high_pos = SomeStack.high_pos;
+		qlen--;
+		prevq = curq;
+		curq = LQL_NEXT(curq);
+		SomeStack.muse = false;
+	}
+
 	while (tlen > 0 && qlen > 0)
 	{
 		if (curq->numvar)
@@ -181,6 +200,15 @@ checkCond(lquery_level * curq, int query_numlevel, ltree_level * curt, int tree_
 					curt = LEVEL_NEXT(curt);
 					tlen--;
 					cur_tpos++;
+					if ( isok && prevq && prevq->numvar==0 && tlen>0 && cur_tpos <= high_pos ) {
+						FieldNot tmpptr;
+						if ( ptr )
+							memcpy(&tmpptr,ptr,sizeof(FieldNot));
+						SomeStack.high_pos = high_pos-cur_tpos;
+						SomeStack.muse = true;
+						if ( checkCond(prevq, qlen+1, curt, tlen, (ptr) ? &tmpptr : NULL) )
+							return true;
+					}
 					if (!isok && ptr)
 						ptr->nt++;
 				}
@@ -278,3 +306,42 @@ ltq_rregex(PG_FUNCTION_ARGS)
 										PG_GETARG_DATUM(0)
 										));
 }
+
+Datum
+lt_q_regex(PG_FUNCTION_ARGS)
+{
+	ltree	   *tree = PG_GETARG_LTREE(0);
+	ArrayType   *_query =  PG_GETARG_ARRAYTYPE_P(1);
+	lquery	*query = (lquery *) ARR_DATA_PTR(_query);	
+	bool	res = false;
+        int     num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
+
+        if (ARR_NDIM(_query) != 1)
+                elog(ERROR, "Dimension of array != 1");
+
+	while (num > 0) {
+		if (DatumGetBool(DirectFunctionCall2(ltq_regex,
+				PointerGetDatum(tree), PointerGetDatum(query)))) {
+
+			res = true;
+			break;
+		}
+		num--;
+		query = NEXTVAL(query);
+	}
+
+	PG_FREE_IF_COPY(tree, 0);
+	PG_FREE_IF_COPY(_query, 1);
+	PG_RETURN_BOOL(res);
+}
+
+Datum
+lt_q_rregex(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_DATUM(DirectFunctionCall2(lt_q_regex,
+										PG_GETARG_DATUM(1),
+										PG_GETARG_DATUM(0)
+										));
+}
+
+
diff --git a/contrib/ltree/ltree.h b/contrib/ltree/ltree.h
index 606b3e3a747..1bc36e722de 100644
--- a/contrib/ltree/ltree.h
+++ b/contrib/ltree/ltree.h
@@ -140,10 +140,14 @@ Datum		ltree_isparent(PG_FUNCTION_ARGS);
 Datum		ltree_risparent(PG_FUNCTION_ARGS);
 Datum		ltq_regex(PG_FUNCTION_ARGS);
 Datum		ltq_rregex(PG_FUNCTION_ARGS);
+Datum		lt_q_regex(PG_FUNCTION_ARGS);
+Datum		lt_q_rregex(PG_FUNCTION_ARGS);
 Datum		ltxtq_exec(PG_FUNCTION_ARGS);
 Datum		ltxtq_rexec(PG_FUNCTION_ARGS);
 Datum		_ltq_regex(PG_FUNCTION_ARGS);
 Datum		_ltq_rregex(PG_FUNCTION_ARGS);
+Datum		_lt_q_regex(PG_FUNCTION_ARGS);
+Datum		_lt_q_rregex(PG_FUNCTION_ARGS);
 Datum		_ltxtq_exec(PG_FUNCTION_ARGS);
 Datum		_ltxtq_rexec(PG_FUNCTION_ARGS);
 Datum		_ltree_isparent(PG_FUNCTION_ARGS);
@@ -173,7 +177,7 @@ ltree	   *lca_inner(ltree ** a, int len);
 /* GiST support for ltree */
 
 #define BITBYTE 8
-#define SIGLENINT  8
+#define SIGLENINT  2
 #define SIGLEN	( sizeof(int4)*SIGLENINT )
 #define SIGLENBIT (SIGLEN*BITBYTE)
 typedef unsigned char BITVEC[SIGLEN];
diff --git a/contrib/ltree/ltree.sql.in b/contrib/ltree/ltree.sql.in
index eae1454a9aa..3bf7617fff6 100644
--- a/contrib/ltree/ltree.sql.in
+++ b/contrib/ltree/ltree.sql.in
@@ -339,6 +339,53 @@ CREATE OPERATOR ^~ (
 	JOIN = contjoinsel
 );
 
+CREATE FUNCTION lt_q_regex(ltree,_lquery)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE 'C' WITH (isstrict,iscachable);
+
+CREATE FUNCTION lt_q_rregex(_lquery,ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE 'C' WITH (isstrict,iscachable);
+
+CREATE OPERATOR ? (
+        LEFTARG = ltree,
+	RIGHTARG = _lquery,
+	PROCEDURE = lt_q_regex,
+	COMMUTATOR = '?',
+	RESTRICT = contsel,
+	JOIN = contjoinsel
+);
+
+CREATE OPERATOR ? (
+        LEFTARG = _lquery,
+	RIGHTARG = ltree,
+	PROCEDURE = lt_q_rregex,
+	COMMUTATOR = '?',
+	RESTRICT = contsel,
+	JOIN = contjoinsel
+);
+
+--not-indexed
+CREATE OPERATOR ^? (
+        LEFTARG = ltree,
+	RIGHTARG = _lquery,
+	PROCEDURE = lt_q_regex,
+	COMMUTATOR = '^?',
+	RESTRICT = contsel,
+	JOIN = contjoinsel
+);
+
+CREATE OPERATOR ^? (
+        LEFTARG = _lquery,
+	RIGHTARG = ltree,
+	PROCEDURE = lt_q_rregex,
+	COMMUTATOR = '^?',
+	RESTRICT = contsel,
+	JOIN = contjoinsel
+);
+
 CREATE FUNCTION ltxtq_in(cstring)
 RETURNS ltxtquery
 AS 'MODULE_PATHNAME'
@@ -452,6 +499,8 @@ CREATE OPERATOR CLASS gist_ltree_ops
 	OPERATOR	13	~ (lquery, ltree) ,
 	OPERATOR	14	@ (ltree, ltxtquery) ,
 	OPERATOR	15	@ (ltxtquery, ltree) ,
+	OPERATOR	16	? (ltree, _lquery) ,
+	OPERATOR	17	? (_lquery, ltree) ,
 	FUNCTION	1	ltree_consistent (internal, internal, int2),
 	FUNCTION	2	ltree_union (bytea, internal),
 	FUNCTION	3	ltree_compress (internal),
@@ -494,6 +543,16 @@ RETURNS bool
 AS 'MODULE_PATHNAME'
 LANGUAGE 'C' WITH (isstrict,iscachable);
 
+CREATE FUNCTION _lt_q_regex(_ltree,_lquery)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE 'C' WITH (isstrict,iscachable);
+
+CREATE FUNCTION _lt_q_rregex(_lquery,_ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE 'C' WITH (isstrict,iscachable);
+
 CREATE FUNCTION _ltxtq_exec(_ltree, ltxtquery)
 RETURNS bool
 AS 'MODULE_PATHNAME'
@@ -558,6 +617,24 @@ CREATE OPERATOR ~ (
 	JOIN = contjoinsel
 );
 
+CREATE OPERATOR ? (
+        LEFTARG = _ltree,
+	RIGHTARG = _lquery,
+	PROCEDURE = _lt_q_regex,
+        COMMUTATOR = '?',
+        RESTRICT = contsel,
+	JOIN = contjoinsel
+);
+
+CREATE OPERATOR ? (
+        LEFTARG = _lquery,
+	RIGHTARG = _ltree,
+	PROCEDURE = _lt_q_rregex,
+        COMMUTATOR = '?',
+        RESTRICT = contsel,
+	JOIN = contjoinsel
+);
+
 CREATE OPERATOR @ (
         LEFTARG = _ltree,
 	RIGHTARG = ltxtquery,
@@ -632,6 +709,24 @@ CREATE OPERATOR ^~ (
 	JOIN = contjoinsel
 );
 
+CREATE OPERATOR ^? (
+        LEFTARG = _ltree,
+	RIGHTARG = _lquery,
+	PROCEDURE = _lt_q_regex,
+        COMMUTATOR = '^?',
+        RESTRICT = contsel,
+	JOIN = contjoinsel
+);
+
+CREATE OPERATOR ^? (
+        LEFTARG = _lquery,
+	RIGHTARG = _ltree,
+	PROCEDURE = _lt_q_rregex,
+        COMMUTATOR = '^?',
+        RESTRICT = contsel,
+	JOIN = contjoinsel
+);
+
 CREATE OPERATOR ^@ (
         LEFTARG = _ltree,
 	RIGHTARG = ltxtquery,
@@ -729,6 +824,8 @@ CREATE OPERATOR CLASS gist__ltree_ops
 	OPERATOR	13	~ (lquery, _ltree)	RECHECK ,
 	OPERATOR	14	@ (_ltree, ltxtquery)	RECHECK ,
 	OPERATOR	15	@ (ltxtquery, _ltree)	RECHECK ,
+	OPERATOR	16	? (_ltree, _lquery)	RECHECK ,
+	OPERATOR	17	? (_lquery, _ltree)	RECHECK ,
 	FUNCTION	1	_ltree_consistent (internal, internal, int2),
 	FUNCTION	2	_ltree_union (bytea, internal),
 	FUNCTION	3	_ltree_compress (internal),
diff --git a/contrib/ltree/ltree_gist.c b/contrib/ltree/ltree_gist.c
index 5c5f4c7d6dc..41c92ac57b2 100644
--- a/contrib/ltree/ltree_gist.c
+++ b/contrib/ltree/ltree_gist.c
@@ -7,9 +7,11 @@
 #include "access/gist.h"
 #include "access/rtree.h"
 #include "access/nbtree.h"
-
+#include "utils/array.h"
 #include "crc32.h"
 
+#define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
+
 PG_FUNCTION_INFO_V1(ltree_gist_in);
 Datum		ltree_gist_in(PG_FUNCTION_ARGS);
 
@@ -596,6 +598,22 @@ gist_qtxt(ltree_gist * key, ltxtquery * query)
 		);
 }
 
+static bool
+arrq_cons(ltree_gist *key, ArrayType *_query) {
+        lquery  *query = (lquery *) ARR_DATA_PTR(_query);
+        int     num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
+
+        if (ARR_NDIM(_query) != 1)
+                elog(ERROR, "Dimension of array != 1");
+
+        while (num > 0) {
+		if ( gist_qe(key, query) && gist_between(key, query) ) 
+                        return true;
+                num--;
+                query = NEXTVAL(query);
+        }
+	return false;
+}
 
 Datum
 ltree_consistent(PG_FUNCTION_ARGS)
@@ -672,6 +690,16 @@ ltree_consistent(PG_FUNCTION_ARGS)
 			else
 				res = gist_qtxt(key, (ltxtquery *) query);
 			break;
+		case 16:
+		case 17:
+			if (GIST_LEAF(entry))
+				res = DatumGetBool(DirectFunctionCall2(lt_q_regex,
+										  PointerGetDatum(LTG_NODE(key)),
+										PointerGetDatum((ArrayType *) query)
+													   ));
+			else
+				res = arrq_cons(key, (ArrayType *) query);
+			break;
 		default:
 			elog(ERROR, "Unknown StrategyNumber: %d", strategy);
 	}
diff --git a/contrib/ltree/sql/ltree.sql b/contrib/ltree/sql/ltree.sql
index 141bd434360..9e8f485f1e5 100644
--- a/contrib/ltree/sql/ltree.sql
+++ b/contrib/ltree/sql/ltree.sql
@@ -139,6 +139,7 @@ SELECT 'a.b.c.d.e'::ltree ~ '!b.*{1}.!c.*';
 SELECT 'a.b.c.d.e'::ltree ~ '*.!b.*{1}.!c.*';
 SELECT 'a.b.c.d.e'::ltree ~ '*.!b.*.!c.*';
 
+
 SELECT 'QWER_TY'::ltree ~ 'q%@*';
 SELECT 'QWER_TY'::ltree ~ 'Q_t%@*';
 SELECT 'QWER_GY'::ltree ~ 'q_t%@*';
@@ -175,6 +176,11 @@ SELECT '{1.2.3.4.5, 7.12.asd}'::ltree[] @> '1.2.3.4';
 SELECT '{1.3.3, 7.12.asd}'::ltree[] @> '1.2.3.4';
 SELECT '{ltree.asd, tree.awdfg}'::ltree[] @ 'tree & aWdfg@'::ltxtquery;
 SELECT '{j.k.l.m, g.b.c.d.e}'::ltree[] ~ 'A*@|g.b.c.d.e';
+SELECT 'a.b.c.d.e'::ltree ? '{A.b.c.d.e}';
+SELECT 'a.b.c.d.e'::ltree ? '{a.b.c.d.e}';
+SELECT 'a.b.c.d.e'::ltree ? '{A.b.c.d.e, a.*}';
+SELECT '{a.b.c.d.e,B.df}'::ltree[] ? '{A.b.c.d.e}';
+SELECT '{a.b.c.d.e,B.df}'::ltree[] ? '{A.b.c.d.e,*.df}';
 
 --exractors
 SELECT ('{3456,1.2.3.34}'::ltree[] ?@> '1.2.3.4') is null;
@@ -194,11 +200,13 @@ SELECT * FROM ltreetest WHERE t >= '12.3' order by t asc;
 SELECT * FROM ltreetest WHERE t >  '12.3' order by t asc;
 SELECT * FROM ltreetest WHERE t @> '1.1.1' order by t asc;
 SELECT * FROM ltreetest WHERE t <@ '1.1.1' order by t asc;
+SELECT * FROM ltreetest WHERE t @ '23 & 1' order by t asc;
 SELECT * FROM ltreetest WHERE t ~ '1.1.1.*' order by t asc;
 SELECT * FROM ltreetest WHERE t ~ '*.1' order by t asc;
-SELECT * FROM ltreetest WHERE t ~ '23.*.1' order by t asc;
 SELECT * FROM ltreetest WHERE t ~ '23.*{1}.1' order by t asc;
-SELECT * FROM ltreetest WHERE t @ '23 & 1' order by t asc;
+SELECT * FROM ltreetest WHERE t ~ '23.*.1' order by t asc;
+SELECT * FROM ltreetest WHERE t ~ '23.*.2' order by t asc;
+SELECT * FROM ltreetest WHERE t ? '{23.*.1,23.*.2}' order by t asc;
 
 create unique index tstidx on ltreetest (t);
 set enable_seqscan=off;
@@ -220,31 +228,37 @@ SELECT * FROM ltreetest WHERE t >= '12.3' order by t asc;
 SELECT * FROM ltreetest WHERE t >  '12.3' order by t asc;
 SELECT * FROM ltreetest WHERE t @> '1.1.1' order by t asc;
 SELECT * FROM ltreetest WHERE t <@ '1.1.1' order by t asc;
+SELECT * FROM ltreetest WHERE t @ '23 & 1' order by t asc;
 SELECT * FROM ltreetest WHERE t ~ '1.1.1.*' order by t asc;
 SELECT * FROM ltreetest WHERE t ~ '*.1' order by t asc;
-SELECT * FROM ltreetest WHERE t ~ '23.*.1' order by t asc;
 SELECT * FROM ltreetest WHERE t ~ '23.*{1}.1' order by t asc;
-SELECT * FROM ltreetest WHERE t @ '23 & 1' order by t asc;
+SELECT * FROM ltreetest WHERE t ~ '23.*.1' order by t asc;
+SELECT * FROM ltreetest WHERE t ~ '23.*.2' order by t asc;
+SELECT * FROM ltreetest WHERE t ? '{23.*.1,23.*.2}' order by t asc;
 
 create table _ltreetest (t ltree[]);
 \copy _ltreetest FROM 'data/_ltree.data'
 
 SELECT count(*) FROM _ltreetest WHERE t @> '1.1.1' ;
 SELECT count(*) FROM _ltreetest WHERE t <@ '1.1.1' ;
+SELECT count(*) FROM _ltreetest WHERE t @ '23 & 1' ;
 SELECT count(*) FROM _ltreetest WHERE t ~ '1.1.1.*' ;
 SELECT count(*) FROM _ltreetest WHERE t ~ '*.1' ;
-SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.1' ;
 SELECT count(*) FROM _ltreetest WHERE t ~ '23.*{1}.1' ;
-SELECT count(*) FROM _ltreetest WHERE t @ '23 & 1' ;
+SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.1' ;
+SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.2' ;
+SELECT count(*) FROM _ltreetest WHERE t ? '{23.*.1,23.*.2}' ;
 
 create index _tstidx on _ltreetest using gist (t);
 set enable_seqscan=off;
 
 SELECT count(*) FROM _ltreetest WHERE t @> '1.1.1' ;
 SELECT count(*) FROM _ltreetest WHERE t <@ '1.1.1' ;
+SELECT count(*) FROM _ltreetest WHERE t @ '23 & 1' ;
 SELECT count(*) FROM _ltreetest WHERE t ~ '1.1.1.*' ;
 SELECT count(*) FROM _ltreetest WHERE t ~ '*.1' ;
-SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.1' ;
 SELECT count(*) FROM _ltreetest WHERE t ~ '23.*{1}.1' ;
-SELECT count(*) FROM _ltreetest WHERE t @ '23 & 1' ;
+SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.1' ;
+SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.2' ;
+SELECT count(*) FROM _ltreetest WHERE t ? '{23.*.1,23.*.2}' ;
 
-- 
GitLab