diff --git a/contrib/ltree/Makefile b/contrib/ltree/Makefile
index c101603..b0e90a3 100644
--- a/contrib/ltree/Makefile
+++ b/contrib/ltree/Makefile
@@ -6,7 +6,7 @@ OBJS = 	ltree_io.o ltree_op.o lquery_op.o _ltree_op.o crc32.o \
 PG_CPPFLAGS = -DLOWER_NODE
 
 EXTENSION = ltree
-DATA = ltree--1.1.sql ltree--1.0--1.1.sql ltree--unpackaged--1.0.sql
+DATA = ltree--1.1--1.2.sql ltree--1.1.sql ltree--1.0--1.1.sql ltree--unpackaged--1.0.sql
 PGFILEDESC = "ltree - hierarchical label data type"
 
 REGRESS = ltree
diff --git a/contrib/ltree/_ltree_gist.c b/contrib/ltree/_ltree_gist.c
index 28bf7ad..394f7ad 100644
--- a/contrib/ltree/_ltree_gist.c
+++ b/contrib/ltree/_ltree_gist.c
@@ -8,6 +8,7 @@
 #include "postgres.h"
 
 #include "access/gist.h"
+#include "access/reloptions.h"
 #include "access/stratnum.h"
 #include "crc32.h"
 #include "ltree.h"
@@ -19,6 +20,7 @@ PG_FUNCTION_INFO_V1(_ltree_union);
 PG_FUNCTION_INFO_V1(_ltree_penalty);
 PG_FUNCTION_INFO_V1(_ltree_picksplit);
 PG_FUNCTION_INFO_V1(_ltree_consistent);
+PG_FUNCTION_INFO_V1(_ltree_gist_options);
 
 #define GETENTRY(vec,pos) ((ltree_gist *) DatumGetPointer((vec)->vector[(pos)].key))
 #define NEXTVAL(x) ( (ltree*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
@@ -47,7 +49,7 @@ static const uint8 number_of_ones[256] = {
 
 
 static void
-hashing(BITVECP sign, ltree *t)
+hashing(BITVECP sign, ltree *t, int siglen)
 {
 	int			tlen = t->numlevel;
 	ltree_level *cur = LTREE_FIRST(t);
@@ -56,7 +58,7 @@ hashing(BITVECP sign, ltree *t)
 	while (tlen > 0)
 	{
 		hash = ltree_crc32_sz(cur->name, cur->len);
-		AHASH(sign, hash);
+		AHASH(sign, hash, siglen);
 		cur = LEVEL_NEXT(cur);
 		tlen--;
 	}
@@ -67,12 +69,13 @@ _ltree_compress(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	GISTENTRY  *retval = entry;
+	LtreeGistOptions *options = (LtreeGistOptions *) PG_GETARG_POINTER(1);
+	int			siglen = options->siglen;
 
 	if (entry->leafkey)
 	{							/* ltree */
 		ltree_gist *key;
 		ArrayType  *val = DatumGetArrayTypeP(entry->key);
-		int32		len = LTG_HDRSIZE + ASIGLEN;
 		int			num = ArrayGetNItems(ARR_NDIM(val), ARR_DIMS(val));
 		ltree	   *item = (ltree *) ARR_DATA_PTR(val);
 
@@ -85,14 +88,11 @@ _ltree_compress(PG_FUNCTION_ARGS)
 					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
 					 errmsg("array must not contain nulls")));
 
-		key = (ltree_gist *) palloc0(len);
-		SET_VARSIZE(key, len);
-		key->flag = 0;
+		key = ltree_gist_alloc(false, NULL, siglen, NULL, NULL);
 
-		MemSet(LTG_SIGN(key), 0, ASIGLEN);
 		while (num > 0)
 		{
-			hashing(LTG_SIGN(key), item);
+			hashing(LTG_SIGN(key), item, siglen);
 			num--;
 			item = NEXTVAL(item);
 		}
@@ -104,22 +104,17 @@ _ltree_compress(PG_FUNCTION_ARGS)
 	}
 	else if (!LTG_ISALLTRUE(entry->key))
 	{
-		int32		i,
-					len;
+		int32		i;
 		ltree_gist *key;
-
 		BITVECP		sign = LTG_SIGN(DatumGetPointer(entry->key));
 
-		ALOOPBYTE
+		ALOOPBYTE(siglen)
 		{
 			if ((sign[i] & 0xff) != 0xff)
 				PG_RETURN_POINTER(retval);
 		}
-		len = LTG_HDRSIZE;
-		key = (ltree_gist *) palloc0(len);
-		SET_VARSIZE(key, len);
-		key->flag = LTG_ALLTRUE;
 
+		key = ltree_gist_alloc(true, sign, siglen, NULL, NULL);
 		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 		gistentryinit(*retval, PointerGetDatum(key),
 					  entry->rel, entry->page,
@@ -134,6 +129,8 @@ _ltree_same(PG_FUNCTION_ARGS)
 	ltree_gist *a = (ltree_gist *) PG_GETARG_POINTER(0);
 	ltree_gist *b = (ltree_gist *) PG_GETARG_POINTER(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
+	LtreeGistOptions *options = (LtreeGistOptions *) PG_GETARG_POINTER(3);
+	int			siglen = options->siglen;
 
 	if (LTG_ISALLTRUE(a) && LTG_ISALLTRUE(b))
 		*result = true;
@@ -148,7 +145,7 @@ _ltree_same(PG_FUNCTION_ARGS)
 					sb = LTG_SIGN(b);
 
 		*result = true;
-		ALOOPBYTE
+		ALOOPBYTE(siglen)
 		{
 			if (sa[i] != sb[i])
 			{
@@ -161,7 +158,7 @@ _ltree_same(PG_FUNCTION_ARGS)
 }
 
 static int32
-unionkey(BITVECP sbase, ltree_gist *add)
+unionkey(BITVECP sbase, ltree_gist *add, int siglen)
 {
 	int32		i;
 	BITVECP		sadd = LTG_SIGN(add);
@@ -169,7 +166,7 @@ unionkey(BITVECP sbase, ltree_gist *add)
 	if (LTG_ISALLTRUE(add))
 		return 1;
 
-	ALOOPBYTE
+	ALOOPBYTE(siglen)
 		sbase[i] |= sadd[i];
 	return 0;
 }
@@ -179,52 +176,46 @@ _ltree_union(PG_FUNCTION_ARGS)
 {
 	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
 	int		   *size = (int *) PG_GETARG_POINTER(1);
-	ABITVEC		base;
-	int32		i,
-				len;
-	int32		flag = 0;
-	ltree_gist *result;
+	LtreeGistOptions *options = (LtreeGistOptions *) PG_GETARG_POINTER(2);
+	int			siglen = options->siglen;
+	int32		i;
+	ltree_gist *result = ltree_gist_alloc(false, NULL, siglen, NULL, NULL);
+	BITVECP		base = LTG_SIGN(result);
 
-	MemSet((void *) base, 0, sizeof(ABITVEC));
 	for (i = 0; i < entryvec->n; i++)
 	{
-		if (unionkey(base, GETENTRY(entryvec, i)))
+		if (unionkey(base, GETENTRY(entryvec, i), siglen))
 		{
-			flag = LTG_ALLTRUE;
+			result->flag |= LTG_ALLTRUE;
+			SET_VARSIZE(result, LTG_HDRSIZE);
 			break;
 		}
 	}
 
-	len = LTG_HDRSIZE + ((flag & LTG_ALLTRUE) ? 0 : ASIGLEN);
-	result = (ltree_gist *) palloc0(len);
-	SET_VARSIZE(result, len);
-	result->flag = flag;
-	if (!LTG_ISALLTRUE(result))
-		memcpy((void *) LTG_SIGN(result), (void *) base, sizeof(ABITVEC));
-	*size = len;
+	*size = VARSIZE(result);
 
 	PG_RETURN_POINTER(result);
 }
 
 static int32
-sizebitvec(BITVECP sign)
+sizebitvec(BITVECP sign, int siglen)
 {
 	int32		size = 0,
 				i;
 
-	ALOOPBYTE
+	ALOOPBYTE(siglen)
 		size += number_of_ones[(unsigned char) sign[i]];
 	return size;
 }
 
 static int
-hemdistsign(BITVECP a, BITVECP b)
+hemdistsign(BITVECP a, BITVECP b, int siglen)
 {
 	int			i,
 				diff,
 				dist = 0;
 
-	ALOOPBYTE
+	ALOOPBYTE(siglen)
 	{
 		diff = (unsigned char) (a[i] ^ b[i]);
 		dist += number_of_ones[diff];
@@ -233,19 +224,19 @@ hemdistsign(BITVECP a, BITVECP b)
 }
 
 static int
-hemdist(ltree_gist *a, ltree_gist *b)
+hemdist(ltree_gist *a, ltree_gist *b, int siglen)
 {
 	if (LTG_ISALLTRUE(a))
 	{
 		if (LTG_ISALLTRUE(b))
 			return 0;
 		else
-			return ASIGLENBIT - sizebitvec(LTG_SIGN(b));
+			return ASIGLENBIT(siglen) - sizebitvec(LTG_SIGN(b), siglen);
 	}
 	else if (LTG_ISALLTRUE(b))
-		return ASIGLENBIT - sizebitvec(LTG_SIGN(a));
+		return ASIGLENBIT(siglen) - sizebitvec(LTG_SIGN(a), siglen);
 
-	return hemdistsign(LTG_SIGN(a), LTG_SIGN(b));
+	return hemdistsign(LTG_SIGN(a), LTG_SIGN(b), siglen);
 }
 
 
@@ -255,8 +246,10 @@ _ltree_penalty(PG_FUNCTION_ARGS)
 	ltree_gist *origval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
 	ltree_gist *newval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
 	float	   *penalty = (float *) PG_GETARG_POINTER(2);
+	LtreeGistOptions *options = (LtreeGistOptions *) PG_GETARG_POINTER(3);
+	int			siglen = options->siglen;
 
-	*penalty = hemdist(origval, newval);
+	*penalty = hemdist(origval, newval, siglen);
 	PG_RETURN_POINTER(penalty);
 }
 
@@ -277,6 +270,8 @@ _ltree_picksplit(PG_FUNCTION_ARGS)
 {
 	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
 	GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
+	LtreeGistOptions *options = (LtreeGistOptions *) PG_GETARG_POINTER(2);
+	int			siglen = options->siglen;
 	OffsetNumber k,
 				j;
 	ltree_gist *datum_l,
@@ -309,7 +304,7 @@ _ltree_picksplit(PG_FUNCTION_ARGS)
 		_k = GETENTRY(entryvec, k);
 		for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
 		{
-			size_waste = hemdist(_k, GETENTRY(entryvec, j));
+			size_waste = hemdist(_k, GETENTRY(entryvec, j), siglen);
 			if (size_waste > waste)
 			{
 				waste = size_waste;
@@ -331,32 +326,13 @@ _ltree_picksplit(PG_FUNCTION_ARGS)
 	}
 
 	/* form initial .. */
-	if (LTG_ISALLTRUE(GETENTRY(entryvec, seed_1)))
-	{
-		datum_l = (ltree_gist *) palloc0(LTG_HDRSIZE);
-		SET_VARSIZE(datum_l, LTG_HDRSIZE);
-		datum_l->flag = LTG_ALLTRUE;
-	}
-	else
-	{
-		datum_l = (ltree_gist *) palloc0(LTG_HDRSIZE + ASIGLEN);
-		SET_VARSIZE(datum_l, LTG_HDRSIZE + ASIGLEN);
-		datum_l->flag = 0;
-		memcpy((void *) LTG_SIGN(datum_l), (void *) LTG_SIGN(GETENTRY(entryvec, seed_1)), sizeof(ABITVEC));
-	}
-	if (LTG_ISALLTRUE(GETENTRY(entryvec, seed_2)))
-	{
-		datum_r = (ltree_gist *) palloc0(LTG_HDRSIZE);
-		SET_VARSIZE(datum_r, LTG_HDRSIZE);
-		datum_r->flag = LTG_ALLTRUE;
-	}
-	else
-	{
-		datum_r = (ltree_gist *) palloc0(LTG_HDRSIZE + ASIGLEN);
-		SET_VARSIZE(datum_r, LTG_HDRSIZE + ASIGLEN);
-		datum_r->flag = 0;
-		memcpy((void *) LTG_SIGN(datum_r), (void *) LTG_SIGN(GETENTRY(entryvec, seed_2)), sizeof(ABITVEC));
-	}
+	datum_l = ltree_gist_alloc(LTG_ISALLTRUE(GETENTRY(entryvec, seed_1)),
+							   LTG_SIGN(GETENTRY(entryvec, seed_1)),
+							   siglen, NULL, NULL);
+
+	datum_r = ltree_gist_alloc(LTG_ISALLTRUE(GETENTRY(entryvec, seed_2)),
+							   LTG_SIGN(GETENTRY(entryvec, seed_2)),
+							   siglen, NULL, NULL);
 
 	maxoff = OffsetNumberNext(maxoff);
 	/* sort before ... */
@@ -365,8 +341,8 @@ _ltree_picksplit(PG_FUNCTION_ARGS)
 	{
 		costvector[j - 1].pos = j;
 		_j = GETENTRY(entryvec, j);
-		size_alpha = hemdist(datum_l, _j);
-		size_beta = hemdist(datum_r, _j);
+		size_alpha = hemdist(datum_l, _j, siglen);
+		size_beta = hemdist(datum_r, _j, siglen);
 		costvector[j - 1].cost = Abs(size_alpha - size_beta);
 	}
 	qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost);
@@ -390,20 +366,20 @@ _ltree_picksplit(PG_FUNCTION_ARGS)
 			continue;
 		}
 		_j = GETENTRY(entryvec, j);
-		size_alpha = hemdist(datum_l, _j);
-		size_beta = hemdist(datum_r, _j);
+		size_alpha = hemdist(datum_l, _j, siglen);
+		size_beta = hemdist(datum_r, _j, siglen);
 
 		if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.00001))
 		{
 			if (LTG_ISALLTRUE(datum_l) || LTG_ISALLTRUE(_j))
 			{
 				if (!LTG_ISALLTRUE(datum_l))
-					MemSet((void *) union_l, 0xff, sizeof(ABITVEC));
+					MemSet((void *) union_l, 0xff, siglen);
 			}
 			else
 			{
 				ptr = LTG_SIGN(_j);
-				ALOOPBYTE
+				ALOOPBYTE(siglen)
 					union_l[i] |= ptr[i];
 			}
 			*left++ = j;
@@ -414,12 +390,12 @@ _ltree_picksplit(PG_FUNCTION_ARGS)
 			if (LTG_ISALLTRUE(datum_r) || LTG_ISALLTRUE(_j))
 			{
 				if (!LTG_ISALLTRUE(datum_r))
-					MemSet((void *) union_r, 0xff, sizeof(ABITVEC));
+					MemSet((void *) union_r, 0xff, siglen);
 			}
 			else
 			{
 				ptr = LTG_SIGN(_j);
-				ALOOPBYTE
+				ALOOPBYTE(siglen)
 					union_r[i] |= ptr[i];
 			}
 			*right++ = j;
@@ -436,7 +412,7 @@ _ltree_picksplit(PG_FUNCTION_ARGS)
 }
 
 static bool
-gist_te(ltree_gist *key, ltree *query)
+gist_te(ltree_gist *key, ltree *query, int siglen)
 {
 	ltree_level *curq = LTREE_FIRST(query);
 	BITVECP		sign = LTG_SIGN(key);
@@ -449,7 +425,7 @@ gist_te(ltree_gist *key, ltree *query)
 	while (qlen > 0)
 	{
 		hv = ltree_crc32_sz(curq->name, curq->len);
-		if (!GETBIT(sign, AHASHVAL(hv)))
+		if (!GETBIT(sign, AHASHVAL(hv, siglen)))
 			return false;
 		curq = LEVEL_NEXT(curq);
 		qlen--;
@@ -458,27 +434,40 @@ gist_te(ltree_gist *key, ltree *query)
 	return true;
 }
 
+typedef struct LtreeSignature
+{
+	BITVECP	sign;
+	int		siglen;
+} LtreeSignature;
+
 static bool
-checkcondition_bit(void *checkval, ITEM *val)
+checkcondition_bit(void *cxt, ITEM *val)
 {
-	return (FLG_CANLOOKSIGN(val->flag)) ? GETBIT(checkval, AHASHVAL(val->val)) : true;
+	LtreeSignature *sig = cxt;
+
+	return (FLG_CANLOOKSIGN(val->flag)) ? GETBIT(sig->sign, AHASHVAL(val->val, sig->siglen)) : true;
 }
 
 static bool
-gist_qtxt(ltree_gist *key, ltxtquery *query)
+gist_qtxt(ltree_gist *key, ltxtquery *query, int siglen)
 {
+	LtreeSignature sig;
+
 	if (LTG_ISALLTRUE(key))
 		return true;
 
+	sig.sign = LTG_SIGN(key);
+	sig.siglen = siglen;
+
 	return ltree_execute(
 						 GETQUERY(query),
-						 (void *) LTG_SIGN(key), false,
+						 &sig, false,
 						 checkcondition_bit
 		);
 }
 
 static bool
-gist_qe(ltree_gist *key, lquery *query)
+gist_qe(ltree_gist *key, lquery *query, int siglen)
 {
 	lquery_level *curq = LQUERY_FIRST(query);
 	BITVECP		sign = LTG_SIGN(key);
@@ -497,7 +486,7 @@ gist_qe(ltree_gist *key, lquery *query)
 
 			while (vlen > 0)
 			{
-				if (GETBIT(sign, AHASHVAL(curv->val)))
+				if (GETBIT(sign, AHASHVAL(curv->val, siglen)))
 				{
 					isexist = true;
 					break;
@@ -517,7 +506,7 @@ gist_qe(ltree_gist *key, lquery *query)
 }
 
 static bool
-_arrq_cons(ltree_gist *key, ArrayType *_query)
+_arrq_cons(ltree_gist *key, ArrayType *_query, int siglen)
 {
 	lquery	   *query = (lquery *) ARR_DATA_PTR(_query);
 	int			num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
@@ -533,7 +522,7 @@ _arrq_cons(ltree_gist *key, ArrayType *_query)
 
 	while (num > 0)
 	{
-		if (gist_qe(key, query))
+		if (gist_qe(key, query, siglen))
 			return true;
 		num--;
 		query = (lquery *) NEXTVAL(query);
@@ -550,6 +539,8 @@ _ltree_consistent(PG_FUNCTION_ARGS)
 
 	/* Oid		subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
+	LtreeGistOptions *options = (LtreeGistOptions *) PG_GETARG_POINTER(5);
+	int			siglen = options->siglen;
 	ltree_gist *key = (ltree_gist *) DatumGetPointer(entry->key);
 	bool		res = false;
 
@@ -560,19 +551,19 @@ _ltree_consistent(PG_FUNCTION_ARGS)
 	{
 		case 10:
 		case 11:
-			res = gist_te(key, (ltree *) query);
+			res = gist_te(key, (ltree *) query, siglen);
 			break;
 		case 12:
 		case 13:
-			res = gist_qe(key, (lquery *) query);
+			res = gist_qe(key, (lquery *) query, siglen);
 			break;
 		case 14:
 		case 15:
-			res = gist_qtxt(key, (ltxtquery *) query);
+			res = gist_qtxt(key, (ltxtquery *) query, siglen);
 			break;
 		case 16:
 		case 17:
-			res = _arrq_cons(key, (ArrayType *) query);
+			res = _arrq_cons(key, (ArrayType *) query, siglen);
 			break;
 		default:
 			/* internal error */
@@ -581,3 +572,20 @@ _ltree_consistent(PG_FUNCTION_ARGS)
 	PG_FREE_IF_COPY(query, 1);
 	PG_RETURN_BOOL(res);
 }
+
+Datum
+_ltree_gist_options(PG_FUNCTION_ARGS)
+{
+	Datum		raw_options = PG_GETARG_DATUM(0);
+	bool		validate = PG_GETARG_BOOL(1);
+	relopt_int	siglen =
+		{ {"siglen", "signature length", 0, 0, 6, RELOPT_TYPE_INT },
+			LTREE_ASIGLEN_DEFAULT, 1, LTREE_ASIGLEN_MAX };
+	relopt_gen *optgen[] = { &siglen.gen };
+	int			offsets[] = { offsetof(LtreeGistOptions, siglen) };
+	LtreeGistOptions *options =
+		parseAndFillLocalRelOptions(raw_options, optgen, offsets, 1,
+									sizeof(LtreeGistOptions), validate);
+
+	PG_RETURN_POINTER(options);
+}
diff --git a/contrib/ltree/ltree--1.1--1.2.sql b/contrib/ltree/ltree--1.1--1.2.sql
new file mode 100644
index 0000000..d002e2b
--- /dev/null
+++ b/contrib/ltree/ltree--1.1--1.2.sql
@@ -0,0 +1,47 @@
+/* contrib/ltree/ltree--1.1--1.2.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION ltree UPDATE TO '1.2'" to load this file. \quit
+
+-- Update procedure signatures the hard way.
+-- We use to_regprocedure() so that query doesn't fail if run against 9.6beta1 definitions,
+-- wherein the signatures have been updated already.  In that case to_regprocedure() will
+-- return NULL and no updates will happen.
+
+UPDATE pg_catalog.pg_proc SET
+  proargtypes = pg_catalog.array_to_string(newtypes::pg_catalog.oid[], ' ')::pg_catalog.oidvector,
+  pronargs = pg_catalog.array_length(newtypes, 1)
+FROM (VALUES
+(NULL::pg_catalog.text, NULL::pg_catalog.regtype[]), -- establish column types
+('ltree_compress(internal)', '{internal,internal}'),
+('ltree_decompress(internal)', '{internal,internal}'),
+('ltree_same(ltree_gist,ltree_gist,internal)', '{ltree_gist,ltree_gist,internal,internal}'),
+('ltree_union(internal,internal)', '{internal,internal,internal}'),
+('ltree_penalty(internal,internal,internal)', '{internal,internal,internal,internal}'),
+('ltree_picksplit(internal,internal)', '{internal,internal,internal}'),
+('ltree_consistent(internal,_int4,smallint,oid,internal)', '{internal,_int4,smallint,oid,internal,internal}'),
+('_ltree_compress(internal)', '{internal,internal}'),
+('_ltree_same(ltree_gist,ltree_gist,internal)', '{ltree_gist,ltree_gist,internal,internal}'),
+('_ltree_union(internal,internal)', '{internal,internal,internal}'),
+('_ltree_penalty(internal,internal,internal)', '{internal,internal,internal,internal}'),
+('_ltree_picksplit(internal,internal)', '{internal,internal,internal}'),
+('_ltree_consistent(internal,_int4,smallint,oid,internal)', '{internal,_int4,smallint,oid,internal,internal}')
+) AS update_data (oldproc, newtypes)
+WHERE oid = pg_catalog.to_regprocedure(oldproc);
+
+CREATE FUNCTION ltree_gist_options(internal, boolean)
+RETURNS internal
+AS 'MODULE_PATHNAME', 'ltree_gist_options'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION _ltree_gist_options(internal, boolean)
+RETURNS internal
+AS 'MODULE_PATHNAME', '_ltree_gist_options'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+ALTER OPERATOR FAMILY gist_ltree_ops USING gist
+ADD FUNCTION 10 (ltree) ltree_gist_options (internal, boolean);
+
+ALTER OPERATOR FAMILY gist__ltree_ops USING gist
+ADD FUNCTION 10 (_ltree) _ltree_gist_options (internal, boolean);
+
diff --git a/contrib/ltree/ltree.control b/contrib/ltree/ltree.control
index 03c3fb1..61c8cdf 100644
--- a/contrib/ltree/ltree.control
+++ b/contrib/ltree/ltree.control
@@ -1,5 +1,5 @@
 # ltree extension
 comment = 'data type for hierarchical tree-like structures'
-default_version = '1.1'
+default_version = '1.2'
 module_pathname = '$libdir/ltree'
 relocatable = true
diff --git a/contrib/ltree/ltree.h b/contrib/ltree/ltree.h
index e4b8c84..6247564 100644
--- a/contrib/ltree/ltree.h
+++ b/contrib/ltree/ltree.h
@@ -183,15 +183,16 @@ int			ltree_strncasecmp(const char *a, const char *b, size_t s);
 
 /* GiST support for ltree */
 
+#define SIGLEN_MAX		(122 * sizeof(int32))
+#define SIGLEN_DEFAULT	(2 * sizeof(int32))
 #define BITBYTE 8
-#define SIGLENINT  2
-#define SIGLEN	( sizeof(int32)*SIGLENINT )
-#define SIGLENBIT (SIGLEN*BITBYTE)
-typedef unsigned char BITVEC[SIGLEN];
+#define SIGLEN	(sizeof(int32) * SIGLENINT)
+#define SIGLENBIT(siglen) ((siglen) * BITBYTE)
+
 typedef unsigned char *BITVECP;
 
-#define LOOPBYTE \
-			for(i=0;i<SIGLEN;i++)
+#define LOOPBYTE(siglen) \
+			for(i = 0; i < (siglen); i++)
 
 #define GETBYTE(x,i) ( *( (BITVECP)(x) + (int)( (i) / BITBYTE ) ) )
 #define GETBITBYTE(x,i) ( ((unsigned char)(x)) >> i & 0x01 )
@@ -199,8 +200,8 @@ typedef unsigned char *BITVECP;
 #define SETBIT(x,i)   GETBYTE(x,i) |=  ( 0x01 << ( (i) % BITBYTE ) )
 #define GETBIT(x,i) ( (GETBYTE(x,i) >> ( (i) % BITBYTE )) & 0x01 )
 
-#define HASHVAL(val) (((unsigned int)(val)) % SIGLENBIT)
-#define HASH(sign, val) SETBIT((sign), HASHVAL(val))
+#define HASHVAL(val, siglen) (((unsigned int)(val)) % SIGLENBIT(siglen))
+#define HASH(sign, val, siglen) SETBIT((sign), HASHVAL(val, siglen))
 
 /*
  * type of index key for ltree. Tree are combined B-Tree and R-Tree
@@ -230,26 +231,34 @@ typedef struct
 #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)) + VARSIZE(LTG_LNODE(x))) )
-#define LTG_RNODE(x)	( LTG_ISNORIGHT(x) ? LTG_LNODE(x) : LTG_RENODE(x) )
+#define LTG_LNODE(x, siglen)	( (ltree*)( ( ((char*)(x))+LTG_HDRSIZE ) + ( LTG_ISALLTRUE(x) ? 0 : (siglen) ) ) )
+#define LTG_RENODE(x, siglen)	( (ltree*)( ((char*)LTG_LNODE(x, siglen)) + VARSIZE(LTG_LNODE(x, siglen))) )
+#define LTG_RNODE(x, siglen)	( LTG_ISNORIGHT(x) ? LTG_LNODE(x, siglen) : LTG_RENODE(x, siglen) )
 
-#define LTG_GETLNODE(x) ( LTG_ISONENODE(x) ? LTG_NODE(x) : LTG_LNODE(x) )
-#define LTG_GETRNODE(x) ( LTG_ISONENODE(x) ? LTG_NODE(x) : LTG_RNODE(x) )
+#define LTG_GETLNODE(x, siglen) ( LTG_ISONENODE(x) ? LTG_NODE(x) : LTG_LNODE(x, siglen) )
+#define LTG_GETRNODE(x, siglen) ( LTG_ISONENODE(x) ? LTG_NODE(x) : LTG_RNODE(x, siglen) )
 
+extern ltree_gist *ltree_gist_alloc(bool isalltrue, BITVECP sign, int siglen,
+				 ltree *left, ltree *right);
 
 /* GiST support for ltree[] */
 
-#define ASIGLENINT	(7)
-#define ASIGLEN		(sizeof(int32)*ASIGLENINT)
-#define ASIGLENBIT (ASIGLEN*BITBYTE)
-typedef unsigned char ABITVEC[ASIGLEN];
+#define LTREE_ASIGLEN_DEFAULT	(7 * sizeof(int32))
+#define LTREE_ASIGLEN_MAX		(122 * sizeof(int32))
+#define ASIGLENBIT(siglen)		((siglen) * BITBYTE)
+
+#define ALOOPBYTE(siglen) \
+			for (i = 0; i < (siglen); i++)
 
-#define ALOOPBYTE \
-			for(i=0;i<ASIGLEN;i++)
+#define AHASHVAL(val, siglen) (((unsigned int)(val)) % ASIGLENBIT(siglen))
+#define AHASH(sign, val, siglen) SETBIT((sign), AHASHVAL(val, siglen))
 
-#define AHASHVAL(val) (((unsigned int)(val)) % ASIGLENBIT)
-#define AHASH(sign, val) SETBIT((sign), AHASHVAL(val))
+/* gist_ltree_ops and gist__ltree_ops opclass options */
+typedef struct LtreeGistOptions
+{
+	int32		vl_len_;		/* varlena header (do not touch directly!) */
+	int			siglen;			/* signature length in bytes */
+}	LtreeGistOptions;
 
 /* type of key is the same to ltree_gist */
 
diff --git a/contrib/ltree/ltree_gist.c b/contrib/ltree/ltree_gist.c
index 12aa8ff..9847b83 100644
--- a/contrib/ltree/ltree_gist.c
+++ b/contrib/ltree/ltree_gist.c
@@ -6,11 +6,13 @@
 #include "postgres.h"
 
 #include "access/gist.h"
+#include "access/reloptions.h"
 #include "access/stratnum.h"
 #include "crc32.h"
 #include "ltree.h"
 
 #define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
+#define ISEQ(a,b)	( (a)->numlevel == (b)->numlevel && ltree_compare(a,b)==0 )
 
 PG_FUNCTION_INFO_V1(ltree_gist_in);
 PG_FUNCTION_INFO_V1(ltree_gist_out);
@@ -33,6 +35,47 @@ ltree_gist_out(PG_FUNCTION_ARGS)
 	PG_RETURN_DATUM(0);
 }
 
+ltree_gist *
+ltree_gist_alloc(bool isalltrue, BITVECP sign, int siglen,
+				 ltree *left, ltree *right)
+{
+	int32		size = LTG_HDRSIZE + (isalltrue ? 0 : siglen) +
+		(left ? VARSIZE(left) + (right ? VARSIZE(right) : 0) : 0);
+	ltree_gist *result = palloc(size);
+
+	SET_VARSIZE(result, size);
+
+	if (siglen)
+	{
+		result->flag = 0;
+
+		if (isalltrue)
+			result->flag |= LTG_ALLTRUE;
+		else if (sign)
+			memcpy(LTG_SIGN(result), sign, siglen);
+		else
+			memset(LTG_SIGN(result), 0, siglen);
+
+		if (left)
+		{
+			memcpy(LTG_LNODE(result, siglen), left, VARSIZE(left));
+
+			if (!right || left == right || ISEQ(left, right))
+				result->flag |= LTG_NORIGHT;
+			else
+				memcpy(LTG_RNODE(result, siglen), right, VARSIZE(right));
+		}
+	}
+	else
+	{
+		Assert(left);
+		result->flag = LTG_ONENODE;
+		memcpy(LTG_NODE(result), left, VARSIZE(left));
+	}
+
+	return result;
+}
+
 PG_FUNCTION_INFO_V1(ltree_compress);
 PG_FUNCTION_INFO_V1(ltree_decompress);
 PG_FUNCTION_INFO_V1(ltree_same);
@@ -40,8 +83,8 @@ PG_FUNCTION_INFO_V1(ltree_union);
 PG_FUNCTION_INFO_V1(ltree_penalty);
 PG_FUNCTION_INFO_V1(ltree_picksplit);
 PG_FUNCTION_INFO_V1(ltree_consistent);
+PG_FUNCTION_INFO_V1(ltree_gist_options);
 
-#define ISEQ(a,b)	( (a)->numlevel == (b)->numlevel && ltree_compare(a,b)==0 )
 #define GETENTRY(vec,pos) ((ltree_gist *) DatumGetPointer((vec)->vector[(pos)].key))
 
 Datum
@@ -52,14 +95,8 @@ ltree_compress(PG_FUNCTION_ARGS)
 
 	if (entry->leafkey)
 	{							/* ltree */
-		ltree_gist *key;
 		ltree	   *val = DatumGetLtreeP(entry->key);
-		int32		len = LTG_HDRSIZE + VARSIZE(val);
-
-		key = (ltree_gist *) palloc0(len);
-		SET_VARSIZE(key, len);
-		key->flag = LTG_ONENODE;
-		memcpy((void *) LTG_NODE(key), (void *) val, VARSIZE(val));
+		ltree_gist *key = ltree_gist_alloc(false, NULL, 0, val, 0);
 
 		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 		gistentryinit(*retval, PointerGetDatum(key),
@@ -93,6 +130,8 @@ ltree_same(PG_FUNCTION_ARGS)
 	ltree_gist *a = (ltree_gist *) PG_GETARG_POINTER(0);
 	ltree_gist *b = (ltree_gist *) PG_GETARG_POINTER(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
+	LtreeGistOptions *options = (LtreeGistOptions *) PG_GETARG_POINTER(3);
+	int			siglen = options->siglen;
 
 	*result = false;
 	if (LTG_ISONENODE(a) != LTG_ISONENODE(b))
@@ -109,15 +148,15 @@ ltree_same(PG_FUNCTION_ARGS)
 		if (LTG_ISALLTRUE(a) != LTG_ISALLTRUE(b))
 			PG_RETURN_POINTER(result);
 
-		if (!ISEQ(LTG_LNODE(a), LTG_LNODE(b)))
+		if (!ISEQ(LTG_LNODE(a, siglen), LTG_LNODE(b, siglen)))
 			PG_RETURN_POINTER(result);
-		if (!ISEQ(LTG_RNODE(a), LTG_RNODE(b)))
+		if (!ISEQ(LTG_RNODE(a, siglen), LTG_RNODE(b, siglen)))
 			PG_RETURN_POINTER(result);
 
 		*result = true;
 		if (!LTG_ISALLTRUE(a))
 		{
-			LOOPBYTE
+			LOOPBYTE(siglen)
 			{
 				if (sa[i] != sb[i])
 				{
@@ -132,7 +171,7 @@ ltree_same(PG_FUNCTION_ARGS)
 }
 
 static void
-hashing(BITVECP sign, ltree *t)
+hashing(BITVECP sign, ltree *t, int siglen)
 {
 	int			tlen = t->numlevel;
 	ltree_level *cur = LTREE_FIRST(t);
@@ -141,7 +180,7 @@ hashing(BITVECP sign, ltree *t)
 	while (tlen > 0)
 	{
 		hash = ltree_crc32_sz(cur->name, cur->len);
-		HASH(sign, hash);
+		HASH(sign, hash, siglen);
 		cur = LEVEL_NEXT(cur);
 		tlen--;
 	}
@@ -152,7 +191,9 @@ ltree_union(PG_FUNCTION_ARGS)
 {
 	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
 	int		   *size = (int *) PG_GETARG_POINTER(1);
-	BITVEC		base;
+	LtreeGistOptions *options = (LtreeGistOptions *) PG_GETARG_POINTER(2);
+	int			siglen = options->siglen;
+	BITVECP		base = palloc0(siglen);
 	int32		i,
 				j;
 	ltree_gist *result,
@@ -161,16 +202,14 @@ ltree_union(PG_FUNCTION_ARGS)
 			   *right = NULL,
 			   *curtree;
 	bool		isalltrue = false;
-	bool		isleqr;
 
-	MemSet((void *) base, 0, sizeof(BITVEC));
 	for (j = 0; j < entryvec->n; j++)
 	{
 		cur = GETENTRY(entryvec, j);
 		if (LTG_ISONENODE(cur))
 		{
 			curtree = LTG_NODE(cur);
-			hashing(base, curtree);
+			hashing(base, curtree, siglen);
 			if (!left || ltree_compare(left, curtree) > 0)
 				left = curtree;
 			if (!right || ltree_compare(right, curtree) < 0)
@@ -184,14 +223,14 @@ ltree_union(PG_FUNCTION_ARGS)
 			{
 				BITVECP		sc = LTG_SIGN(cur);
 
-				LOOPBYTE
+				LOOPBYTE(siglen)
 					((unsigned char *) base)[i] |= sc[i];
 			}
 
-			curtree = LTG_LNODE(cur);
+			curtree = LTG_LNODE(cur, siglen);
 			if (!left || ltree_compare(left, curtree) > 0)
 				left = curtree;
-			curtree = LTG_RNODE(cur);
+			curtree = LTG_RNODE(cur, siglen);
 			if (!right || ltree_compare(right, curtree) < 0)
 				right = curtree;
 		}
@@ -200,7 +239,7 @@ ltree_union(PG_FUNCTION_ARGS)
 	if (isalltrue == false)
 	{
 		isalltrue = true;
-		LOOPBYTE
+		LOOPBYTE(siglen)
 		{
 			if (((unsigned char *) base)[i] != 0xff)
 			{
@@ -210,23 +249,9 @@ ltree_union(PG_FUNCTION_ARGS)
 		}
 	}
 
-	isleqr = (left == right || ISEQ(left, right)) ? true : false;
-	*size = LTG_HDRSIZE + ((isalltrue) ? 0 : SIGLEN) + VARSIZE(left) + ((isleqr) ? 0 : VARSIZE(right));
-
-	result = (ltree_gist *) palloc0(*size);
-	SET_VARSIZE(result, *size);
-	result->flag = 0;
+	result = ltree_gist_alloc(isalltrue, base, siglen, left, right);
 
-	if (isalltrue)
-		result->flag |= LTG_ALLTRUE;
-	else
-		memcpy((void *) LTG_SIGN(result), base, SIGLEN);
-
-	memcpy((void *) LTG_LNODE(result), (void *) left, VARSIZE(left));
-	if (isleqr)
-		result->flag |= LTG_NORIGHT;
-	else
-		memcpy((void *) LTG_RNODE(result), (void *) right, VARSIZE(right));
+	*size = VARSIZE(result);
 
 	PG_RETURN_POINTER(result);
 }
@@ -237,11 +262,13 @@ ltree_penalty(PG_FUNCTION_ARGS)
 	ltree_gist *origval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
 	ltree_gist *newval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
 	float	   *penalty = (float *) PG_GETARG_POINTER(2);
+	LtreeGistOptions *options = (LtreeGistOptions *) PG_GETARG_POINTER(3);
+	int			siglen = options->siglen;
 	int32		cmpr,
 				cmpl;
 
-	cmpl = ltree_compare(LTG_GETLNODE(origval), LTG_GETLNODE(newval));
-	cmpr = ltree_compare(LTG_GETRNODE(newval), LTG_GETRNODE(origval));
+	cmpl = ltree_compare(LTG_GETLNODE(origval, siglen), LTG_GETLNODE(newval, siglen));
+	cmpr = ltree_compare(LTG_GETRNODE(newval, siglen), LTG_GETRNODE(origval, siglen));
 
 	*penalty = Max(cmpl, 0) + Max(cmpr, 0);
 
@@ -270,26 +297,24 @@ ltree_picksplit(PG_FUNCTION_ARGS)
 {
 	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
 	GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
+	LtreeGistOptions *options = (LtreeGistOptions *) PG_GETARG_POINTER(2);
+	int			siglen = options->siglen;
 	OffsetNumber j;
 	int32		i;
 	RIX		   *array;
 	OffsetNumber maxoff;
 	int			nbytes;
-	int			size;
 	ltree	   *lu_l,
 			   *lu_r,
 			   *ru_l,
 			   *ru_r;
 	ltree_gist *lu,
 			   *ru;
-	BITVEC		ls,
-				rs;
+	BITVECP		ls = palloc0(siglen),
+				rs = palloc0(siglen);
 	bool		lisat = false,
-				risat = false,
-				isleqr;
+				risat = false;
 
-	memset((void *) ls, 0, sizeof(BITVEC));
-	memset((void *) rs, 0, sizeof(BITVEC));
 	maxoff = entryvec->n - 1;
 	nbytes = (maxoff + 2) * sizeof(OffsetNumber);
 	v->spl_left = (OffsetNumber *) palloc(nbytes);
@@ -303,7 +328,7 @@ ltree_picksplit(PG_FUNCTION_ARGS)
 	{
 		array[j].index = j;
 		lu = GETENTRY(entryvec, j); /* use as tmp val */
-		array[j].r = LTG_GETLNODE(lu);
+		array[j].r = LTG_GETLNODE(lu, siglen);
 	}
 
 	qsort((void *) &array[FirstOffsetNumber], maxoff - FirstOffsetNumber + 1,
@@ -317,10 +342,10 @@ ltree_picksplit(PG_FUNCTION_ARGS)
 		{
 			v->spl_left[v->spl_nleft] = array[j].index;
 			v->spl_nleft++;
-			if (lu_r == NULL || ltree_compare(LTG_GETRNODE(lu), lu_r) > 0)
-				lu_r = LTG_GETRNODE(lu);
+			if (lu_r == NULL || ltree_compare(LTG_GETRNODE(lu, siglen), lu_r) > 0)
+				lu_r = LTG_GETRNODE(lu, siglen);
 			if (LTG_ISONENODE(lu))
-				hashing(ls, LTG_NODE(lu));
+				hashing(ls, LTG_NODE(lu), siglen);
 			else
 			{
 				if (lisat || LTG_ISALLTRUE(lu))
@@ -329,7 +354,7 @@ ltree_picksplit(PG_FUNCTION_ARGS)
 				{
 					BITVECP		sc = LTG_SIGN(lu);
 
-					LOOPBYTE
+					LOOPBYTE(siglen)
 						((unsigned char *) ls)[i] |= sc[i];
 				}
 			}
@@ -338,10 +363,10 @@ ltree_picksplit(PG_FUNCTION_ARGS)
 		{
 			v->spl_right[v->spl_nright] = array[j].index;
 			v->spl_nright++;
-			if (ru_r == NULL || ltree_compare(LTG_GETRNODE(lu), ru_r) > 0)
-				ru_r = LTG_GETRNODE(lu);
+			if (ru_r == NULL || ltree_compare(LTG_GETRNODE(lu, siglen), ru_r) > 0)
+				ru_r = LTG_GETRNODE(lu, siglen);
 			if (LTG_ISONENODE(lu))
-				hashing(rs, LTG_NODE(lu));
+				hashing(rs, LTG_NODE(lu), siglen);
 			else
 			{
 				if (risat || LTG_ISALLTRUE(lu))
@@ -350,7 +375,7 @@ ltree_picksplit(PG_FUNCTION_ARGS)
 				{
 					BITVECP		sc = LTG_SIGN(lu);
 
-					LOOPBYTE
+					LOOPBYTE(siglen)
 						((unsigned char *) rs)[i] |= sc[i];
 				}
 			}
@@ -360,7 +385,7 @@ ltree_picksplit(PG_FUNCTION_ARGS)
 	if (lisat == false)
 	{
 		lisat = true;
-		LOOPBYTE
+		LOOPBYTE(siglen)
 		{
 			if (((unsigned char *) ls)[i] != 0xff)
 			{
@@ -373,7 +398,7 @@ ltree_picksplit(PG_FUNCTION_ARGS)
 	if (risat == false)
 	{
 		risat = true;
-		LOOPBYTE
+		LOOPBYTE(siglen)
 		{
 			if (((unsigned char *) rs)[i] != 0xff)
 			{
@@ -383,38 +408,14 @@ ltree_picksplit(PG_FUNCTION_ARGS)
 		}
 	}
 
-	lu_l = LTG_GETLNODE(GETENTRY(entryvec, array[FirstOffsetNumber].index));
-	isleqr = (lu_l == lu_r || ISEQ(lu_l, lu_r)) ? true : false;
-	size = LTG_HDRSIZE + ((lisat) ? 0 : SIGLEN) + VARSIZE(lu_l) + ((isleqr) ? 0 : VARSIZE(lu_r));
-	lu = (ltree_gist *) palloc0(size);
-	SET_VARSIZE(lu, size);
-	lu->flag = 0;
-	if (lisat)
-		lu->flag |= LTG_ALLTRUE;
-	else
-		memcpy((void *) LTG_SIGN(lu), ls, SIGLEN);
-	memcpy((void *) LTG_LNODE(lu), (void *) lu_l, VARSIZE(lu_l));
-	if (isleqr)
-		lu->flag |= LTG_NORIGHT;
-	else
-		memcpy((void *) LTG_RNODE(lu), (void *) lu_r, VARSIZE(lu_r));
+	lu_l = LTG_GETLNODE(GETENTRY(entryvec, array[FirstOffsetNumber].index), siglen);
+	lu = ltree_gist_alloc(lisat, ls, siglen, lu_l, lu_r);
 
+	ru_l = LTG_GETLNODE(GETENTRY(entryvec, array[1 + ((maxoff - FirstOffsetNumber + 1) / 2)].index), siglen);
+	ru = ltree_gist_alloc(risat, rs, siglen, ru_l, ru_r);
 
-	ru_l = LTG_GETLNODE(GETENTRY(entryvec, array[1 + ((maxoff - FirstOffsetNumber + 1) / 2)].index));
-	isleqr = (ru_l == ru_r || ISEQ(ru_l, ru_r)) ? true : false;
-	size = LTG_HDRSIZE + ((risat) ? 0 : SIGLEN) + VARSIZE(ru_l) + ((isleqr) ? 0 : VARSIZE(ru_r));
-	ru = (ltree_gist *) palloc0(size);
-	SET_VARSIZE(ru, size);
-	ru->flag = 0;
-	if (risat)
-		ru->flag |= LTG_ALLTRUE;
-	else
-		memcpy((void *) LTG_SIGN(ru), rs, SIGLEN);
-	memcpy((void *) LTG_LNODE(ru), (void *) ru_l, VARSIZE(ru_l));
-	if (isleqr)
-		ru->flag |= LTG_NORIGHT;
-	else
-		memcpy((void *) LTG_RNODE(ru), (void *) ru_r, VARSIZE(ru_r));
+	pfree(ls);
+	pfree(rs);
 
 	v->spl_ldatum = PointerGetDatum(lu);
 	v->spl_rdatum = PointerGetDatum(ru);
@@ -423,7 +424,7 @@ ltree_picksplit(PG_FUNCTION_ARGS)
 }
 
 static bool
-gist_isparent(ltree_gist *key, ltree *query)
+gist_isparent(ltree_gist *key, ltree *query, int siglen)
 {
 	int32		numlevel = query->numlevel;
 	int			i;
@@ -431,7 +432,8 @@ gist_isparent(ltree_gist *key, ltree *query)
 	for (i = query->numlevel; i >= 0; i--)
 	{
 		query->numlevel = i;
-		if (ltree_compare(query, LTG_GETLNODE(key)) >= 0 && ltree_compare(query, LTG_GETRNODE(key)) <= 0)
+		if (ltree_compare(query, LTG_GETLNODE(key, siglen)) >= 0 &&
+			ltree_compare(query, LTG_GETRNODE(key, siglen)) <= 0)
 		{
 			query->numlevel = numlevel;
 			return true;
@@ -452,10 +454,10 @@ copy_ltree(ltree *src)
 }
 
 static bool
-gist_ischild(ltree_gist *key, ltree *query)
+gist_ischild(ltree_gist *key, ltree *query, int siglen)
 {
-	ltree	   *left = copy_ltree(LTG_GETLNODE(key));
-	ltree	   *right = copy_ltree(LTG_GETRNODE(key));
+	ltree	   *left = copy_ltree(LTG_GETLNODE(key, siglen));
+	ltree	   *right = copy_ltree(LTG_GETRNODE(key, siglen));
 	bool		res = true;
 
 	if (left->numlevel > query->numlevel)
@@ -477,7 +479,7 @@ gist_ischild(ltree_gist *key, ltree *query)
 }
 
 static bool
-gist_qe(ltree_gist *key, lquery *query)
+gist_qe(ltree_gist *key, lquery *query, int siglen)
 {
 	lquery_level *curq = LQUERY_FIRST(query);
 	BITVECP		sign = LTG_SIGN(key);
@@ -496,7 +498,7 @@ gist_qe(ltree_gist *key, lquery *query)
 
 			while (vlen > 0)
 			{
-				if (GETBIT(sign, HASHVAL(curv->val)))
+				if (GETBIT(sign, HASHVAL(curv->val, siglen)))
 				{
 					isexist = true;
 					break;
@@ -545,41 +547,54 @@ gist_tqcmp(ltree *t, lquery *q)
 }
 
 static bool
-gist_between(ltree_gist *key, lquery *query)
+gist_between(ltree_gist *key, lquery *query, int siglen)
 {
 	if (query->firstgood == 0)
 		return true;
 
-	if (gist_tqcmp(LTG_GETLNODE(key), query) > 0)
+	if (gist_tqcmp(LTG_GETLNODE(key, siglen), query) > 0)
 		return false;
 
-	if (gist_tqcmp(LTG_GETRNODE(key), query) < 0)
+	if (gist_tqcmp(LTG_GETRNODE(key, siglen), query) < 0)
 		return false;
 
 	return true;
 }
 
+typedef struct LtreeSignature
+{
+	BITVECP	sign;
+	int		siglen;
+} LtreeSignature;
+
 static bool
-checkcondition_bit(void *checkval, ITEM *val)
+checkcondition_bit(void *cxt, ITEM *val)
 {
-	return (FLG_CANLOOKSIGN(val->flag)) ? GETBIT(checkval, HASHVAL(val->val)) : true;
+	LtreeSignature *sig = cxt;
+
+	return (FLG_CANLOOKSIGN(val->flag)) ? GETBIT(sig->sign, HASHVAL(val->val, sig->siglen)) : true;
 }
 
 static bool
-gist_qtxt(ltree_gist *key, ltxtquery *query)
+gist_qtxt(ltree_gist *key, ltxtquery *query, int siglen)
 {
+	LtreeSignature sig;
+
 	if (LTG_ISALLTRUE(key))
 		return true;
 
+	sig.sign = LTG_SIGN(key);
+	sig.siglen = siglen;
+
 	return ltree_execute(
 						 GETQUERY(query),
-						 (void *) LTG_SIGN(key), false,
+						 &sig, false,
 						 checkcondition_bit
 		);
 }
 
 static bool
-arrq_cons(ltree_gist *key, ArrayType *_query)
+arrq_cons(ltree_gist *key, ArrayType *_query, int siglen)
 {
 	lquery	   *query = (lquery *) ARR_DATA_PTR(_query);
 	int			num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
@@ -595,7 +610,7 @@ arrq_cons(ltree_gist *key, ArrayType *_query)
 
 	while (num > 0)
 	{
-		if (gist_qe(key, query) && gist_between(key, query))
+		if (gist_qe(key, query, siglen) && gist_between(key, query, siglen))
 			return true;
 		num--;
 		query = NEXTVAL(query);
@@ -611,6 +626,8 @@ ltree_consistent(PG_FUNCTION_ARGS)
 
 	/* Oid		subtype = PG_GETARG_OID(3); */
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
+	LtreeGistOptions *options = (LtreeGistOptions *) PG_GETARG_POINTER(5);
+	int			siglen = options->siglen;
 	ltree_gist *key = (ltree_gist *) DatumGetPointer(entry->key);
 	void	   *query = NULL;
 	bool		res = false;
@@ -625,11 +642,11 @@ ltree_consistent(PG_FUNCTION_ARGS)
 			res = (GIST_LEAF(entry)) ?
 				(ltree_compare((ltree *) query, LTG_NODE(key)) > 0)
 				:
-				(ltree_compare((ltree *) query, LTG_GETLNODE(key)) >= 0);
+				(ltree_compare((ltree *) query, LTG_GETLNODE(key, siglen)) >= 0);
 			break;
 		case BTLessEqualStrategyNumber:
 			query = PG_GETARG_LTREE_P(1);
-			res = (ltree_compare((ltree *) query, LTG_GETLNODE(key)) >= 0);
+			res = (ltree_compare((ltree *) query, LTG_GETLNODE(key, siglen)) >= 0);
 			break;
 		case BTEqualStrategyNumber:
 			query = PG_GETARG_LTREE_P(1);
@@ -637,35 +654,35 @@ ltree_consistent(PG_FUNCTION_ARGS)
 				res = (ltree_compare((ltree *) query, LTG_NODE(key)) == 0);
 			else
 				res = (
-					   ltree_compare((ltree *) query, LTG_GETLNODE(key)) >= 0
+					   ltree_compare((ltree *) query, LTG_GETLNODE(key, siglen)) >= 0
 					   &&
-					   ltree_compare((ltree *) query, LTG_GETRNODE(key)) <= 0
+					   ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) <= 0
 					);
 			break;
 		case BTGreaterEqualStrategyNumber:
 			query = PG_GETARG_LTREE_P(1);
-			res = (ltree_compare((ltree *) query, LTG_GETRNODE(key)) <= 0);
+			res = (ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) <= 0);
 			break;
 		case BTGreaterStrategyNumber:
 			query = PG_GETARG_LTREE_P(1);
 			res = (GIST_LEAF(entry)) ?
-				(ltree_compare((ltree *) query, LTG_GETRNODE(key)) < 0)
+				(ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) < 0)
 				:
-				(ltree_compare((ltree *) query, LTG_GETRNODE(key)) <= 0);
+				(ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) <= 0);
 			break;
 		case 10:
 			query = PG_GETARG_LTREE_P_COPY(1);
 			res = (GIST_LEAF(entry)) ?
 				inner_isparent((ltree *) query, LTG_NODE(key))
 				:
-				gist_isparent(key, (ltree *) query);
+				gist_isparent(key, (ltree *) query, siglen);
 			break;
 		case 11:
 			query = PG_GETARG_LTREE_P(1);
 			res = (GIST_LEAF(entry)) ?
 				inner_isparent(LTG_NODE(key), (ltree *) query)
 				:
-				gist_ischild(key, (ltree *) query);
+				gist_ischild(key, (ltree *) query, siglen);
 			break;
 		case 12:
 		case 13:
@@ -676,7 +693,8 @@ ltree_consistent(PG_FUNCTION_ARGS)
 													   PointerGetDatum((lquery *) query)
 													   ));
 			else
-				res = (gist_qe(key, (lquery *) query) && gist_between(key, (lquery *) query));
+				res = (gist_qe(key, (lquery *) query, siglen) &&
+					   gist_between(key, (lquery *) query, siglen));
 			break;
 		case 14:
 		case 15:
@@ -687,7 +705,7 @@ ltree_consistent(PG_FUNCTION_ARGS)
 													   PointerGetDatum((ltxtquery *) query)
 													   ));
 			else
-				res = gist_qtxt(key, (ltxtquery *) query);
+				res = gist_qtxt(key, (ltxtquery *) query, siglen);
 			break;
 		case 16:
 		case 17:
@@ -698,7 +716,7 @@ ltree_consistent(PG_FUNCTION_ARGS)
 													   PointerGetDatum((ArrayType *) query)
 													   ));
 			else
-				res = arrq_cons(key, (ArrayType *) query);
+				res = arrq_cons(key, (ArrayType *) query, siglen);
 			break;
 		default:
 			/* internal error */
@@ -708,3 +726,20 @@ ltree_consistent(PG_FUNCTION_ARGS)
 	PG_FREE_IF_COPY(query, 1);
 	PG_RETURN_BOOL(res);
 }
+
+Datum
+ltree_gist_options(PG_FUNCTION_ARGS)
+{
+	Datum		raw_options = PG_GETARG_DATUM(0);
+	bool		validate = PG_GETARG_BOOL(1);
+	relopt_int	siglen =
+		{ {"siglen", "signature length", 0, 0, 6, RELOPT_TYPE_INT },
+			LTREE_ASIGLEN_DEFAULT, 1, LTREE_ASIGLEN_MAX };
+	relopt_gen *optgen[] = { &siglen.gen };
+	int			offsets[] = { offsetof(LtreeGistOptions, siglen) };
+	LtreeGistOptions *options =
+		parseAndFillLocalRelOptions(raw_options, optgen, offsets, 1,
+									sizeof(LtreeGistOptions), validate);
+
+	PG_RETURN_POINTER(options);
+}
diff --git a/doc/src/sgml/ltree.sgml b/doc/src/sgml/ltree.sgml
index ea362f8..dd4e269 100644
--- a/doc/src/sgml/ltree.sgml
+++ b/doc/src/sgml/ltree.sgml
@@ -502,11 +502,17 @@ Europe &amp; Russia*@ &amp; !Transportation
      <literal>@</literal>, <literal>~</literal>, <literal>?</literal>
     </para>
     <para>
-     Example of creating such an index:
+     Example of creating such an index with a default signature length of 8 bytes:
     </para>
 <programlisting>
 CREATE INDEX path_gist_idx ON test USING GIST (path);
 </programlisting>
+    <para>
+     Example of creating such an index with a signature length of 100 bytes:
+    </para>
+<programlisting>
+CREATE INDEX path_gist_idx ON test USING GIST (path gist_ltree_ops(siglen=100));
+</programlisting>
    </listitem>
    <listitem>
     <para>
@@ -515,12 +521,18 @@ CREATE INDEX path_gist_idx ON test USING GIST (path);
      <literal>@</literal>, <literal>~</literal>, <literal>?</literal>
     </para>
     <para>
-     Example of creating such an index:
+     Example of creating such an index with a default signature length of 28 bytes:
     </para>
 <programlisting>
 CREATE INDEX path_gist_idx ON test USING GIST (array_path);
 </programlisting>
     <para>
+     Example of creating such an index with a signature length of 100 bytes:
+    </para>
+<programlisting>
+CREATE INDEX path_gist_idx ON test USING GIST (array_path gist__ltree_ops(siglen=100));
+</programlisting>
+    <para>
      Note: This index type is lossy.
     </para>
    </listitem>
