Selectivity estimation for intarray with @@

Started by Uriy Zhuravlevover 10 years ago8 messages
#1Uriy Zhuravlev
u.zhuravlev@postgrespro.ru
1 attachment(s)

Hello.

Attached patch based on:
/messages/by-id/CAPpHfdssY+qEPDCOvxx-b4LP3ybR+qS04M6-ARgGKNFk3FrFow@mail.gmail.com

and adds selectivity estimation functions to @@ (port from tsquery). Now we
support &&, @>, <@ and @@.
In addition it was written migration to version 1.1 intarray. Because of what
this patch requires my other patch:
/messages/by-id/14346041.DNcb5Y1inS@dinodell

Alexander Korotkov know about this patch.

Thanks.

--
Uriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Attachments:

selectivity_functions_for_intarray_v1.patchtext/x-patch; charset=UTF-8; name=selectivity_functions_for_intarray_v1.patchDownload
diff --git a/contrib/intarray/Makefile b/contrib/intarray/Makefile
index 920c5b1..16c829c 100644
--- a/contrib/intarray/Makefile
+++ b/contrib/intarray/Makefile
@@ -2,10 +2,10 @@
 
 MODULE_big = _int
 OBJS = _int_bool.o _int_gist.o _int_op.o _int_tool.o \
-	_intbig_gist.o _int_gin.o $(WIN32RES)
+	_intbig_gist.o _int_gin.o _int_selfuncs.o $(WIN32RES)
 
 EXTENSION = intarray
-DATA = intarray--1.0.sql intarray--unpackaged--1.0.sql
+DATA = intarray--1.0.sql intarray--1.1.sql intarray--1.0--1.1.sql intarray--unpackaged--1.0.sql
 PGFILEDESC = "intarray - functions and operators for arrays of integers"
 
 REGRESS = _int
diff --git a/contrib/intarray/_int.h b/contrib/intarray/_int.h
index d524f0f..739c3c0 100644
--- a/contrib/intarray/_int.h
+++ b/contrib/intarray/_int.h
@@ -140,6 +140,7 @@ typedef struct QUERYTYPE
 #define COMPUTESIZE(size)	( HDRSIZEQT + (size) * sizeof(ITEM) )
 #define QUERYTYPEMAXITEMS	((MaxAllocSize - HDRSIZEQT) / sizeof(ITEM))
 #define GETQUERY(x)  ( (x)->items )
+#define GETRQUERY(x)  ( (x)->items + ((x)->size - 1) )
 
 /* "type" codes for ITEM */
 #define END		0
diff --git a/contrib/intarray/_int_selfuncs.c b/contrib/intarray/_int_selfuncs.c
new file mode 100644
index 0000000..fd80668
--- /dev/null
+++ b/contrib/intarray/_int_selfuncs.c
@@ -0,0 +1,346 @@
+/*-------------------------------------------------------------------------
+ *
+ * _int_selfuncs.c
+ *	  Functions for selectivity estimation of intarray operators
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  contrib/intarray/_int_selfuncs.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+#include "_int.h"
+
+#include "access/htup_details.h"
+#include "catalog/pg_operator.h"
+#include "catalog/pg_statistic.h"
+#include "catalog/pg_type.h"
+#include "utils/selfuncs.h"
+#include "utils/syscache.h"
+#include "utils/lsyscache.h"
+#include "miscadmin.h"
+
+PG_FUNCTION_INFO_V1(_int_contsel);
+PG_FUNCTION_INFO_V1(_int_contjoinsel);
+PG_FUNCTION_INFO_V1(_int_matchsel);
+
+Datum _int_contsel(PG_FUNCTION_ARGS);
+Datum _int_contjoinsel(PG_FUNCTION_ARGS);
+Datum _int_matchsel(PG_FUNCTION_ARGS);
+
+/* lookup table type for binary searching through MCELEMs */
+typedef struct
+{
+	int32	   element;
+	float4		frequency;
+} Int4Freq;
+
+
+static Oid transformOperator(Oid oprOid);
+static Selectivity int_querysel(VariableStatData *vardata, Datum constval);
+static Selectivity int_query_opr_selec(ITEM *item, Int4Freq *lookup,
+									   int length, float4 minfreq);
+static Selectivity mcelem_int_query_selec(QUERYTYPE *query,
+					 Datum *mcelem, int nmcelem,
+					 float4 *numbers, int nnumbers);
+
+static int
+compare_val_int4freq(const void *a, const void *b);
+
+#define int_query_opr_selec_no_stats(query) \
+	int_query_opr_selec(GETRQUERY(query), NULL, 0, 0)
+
+
+
+static Oid
+transformOperator(Oid oprOid)
+{
+	HeapTuple			tup;
+	Form_pg_operator	op;
+	Oid					result = InvalidOid;
+
+	tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprOid));
+	if (!HeapTupleIsValid(tup))
+		elog(ERROR, "Invalid operator: %u", oprOid);
+
+	op = (Form_pg_operator) GETSTRUCT(tup);
+
+	if (!strcmp(op->oprname.data, "&&"))
+		result = OID_ARRAY_OVERLAP_OP;
+	else if (!strcmp(op->oprname.data, "@>"))
+		result = OID_ARRAY_CONTAINS_OP;
+	else if (!strcmp(op->oprname.data, "<@"))
+		result = OID_ARRAY_CONTAINED_OP;
+
+	ReleaseSysCache(tup);
+
+	if (!OidIsValid(result))
+		elog(ERROR, "Invalid operator: %u", oprOid);
+
+	return result;
+}
+
+/*
+ * _int_contsel -- restriction selectivity for array @>, &&, <@ operators
+ */
+Datum
+_int_contsel(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_DATUM(DirectFunctionCall4(arraycontsel,
+			PG_GETARG_DATUM(0),
+			ObjectIdGetDatum(transformOperator(PG_GETARG_OID(1))),
+			PG_GETARG_DATUM(2),
+			PG_GETARG_DATUM(3)));
+}
+
+/*
+ * _int_contjoinsel -- join selectivity for array @>, &&, <@ operators
+ */
+Datum
+_int_contjoinsel(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_DATUM(DirectFunctionCall5(arraycontjoinsel,
+			PG_GETARG_DATUM(0),
+			ObjectIdGetDatum(transformOperator(PG_GETARG_OID(1))),
+			PG_GETARG_DATUM(2),
+			PG_GETARG_DATUM(3),
+			PG_GETARG_DATUM(4)));
+}
+
+
+/*
+ * _int_matchsel -- restriction selectivity function for intarray @@ int_query
+ */
+Datum
+_int_matchsel(PG_FUNCTION_ARGS)
+{
+	PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
+
+	List	   *args = (List *) PG_GETARG_POINTER(2);
+	int			varRelid = PG_GETARG_INT32(3);
+	VariableStatData vardata;
+	Node	   *other;
+	bool		varonleft;
+	Selectivity selec;
+	/*
+	 * If expression is not variable = something or something = variable, then
+	 * punt and return a default estimate.
+	 */
+	if (!get_restriction_variable(root, args, varRelid,
+								  &vardata, &other, &varonleft))
+		PG_RETURN_FLOAT8(DEFAULT_EQ_SEL);
+
+	/*
+	 * Can't do anything useful if the something is not a constant, either.
+	 */
+	if (!IsA(other, Const))
+	{
+		ReleaseVariableStats(vardata);
+		PG_RETURN_FLOAT8(DEFAULT_EQ_SEL);
+	}
+
+	/*
+	 * The "@@" operator is strict, so we can cope with NULL right away
+	 */
+	if (((Const *) other)->constisnull)
+	{
+		ReleaseVariableStats(vardata);
+		PG_RETURN_FLOAT8(0.0);
+	}
+
+	selec = int_querysel(&vardata, ((Const *) other)->constvalue);
+
+	ReleaseVariableStats(vardata);
+
+	CLAMP_PROBABILITY(selec);
+
+	PG_RETURN_FLOAT8((float8) selec);
+}
+
+static Selectivity int_querysel(VariableStatData *vardata, Datum constval) {
+	Selectivity selec;
+	QUERYTYPE		*query;
+
+	/* The caller made sure the const is a query, so get it now */
+	query = DatumGetQueryTypeP(constval);
+
+	/* Empty query matches nothing */
+	if (query->size == 0)
+		return (Selectivity) 0.0;
+
+	if (HeapTupleIsValid(vardata->statsTuple))
+	{
+		Form_pg_statistic stats;
+		Datum	   *values;
+		int			nvalues;
+		float4	   *numbers;
+		int			nnumbers;
+
+		stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple);
+
+		/* MCELEM will be an array of INT4 elements for a intarray column */
+		if (get_attstatsslot(vardata->statsTuple,
+							 INT4OID, -1,
+							 STATISTIC_KIND_MCELEM, InvalidOid,
+							 NULL,
+							 &values, &nvalues,
+							 &numbers, &nnumbers))
+		{
+			/*
+			 * There is a most-common-elements slot for the intarray Var, so
+			 * use that.
+			 */
+			selec = mcelem_int_query_selec(query, values, nvalues,
+										   numbers, nnumbers);
+			free_attstatsslot(INT4OID, values, nvalues, numbers, nnumbers);
+		}
+		else
+		{
+			/* No most-common-elements info, so do without */
+			selec = int_query_opr_selec_no_stats(query);
+		}
+		/*
+		 * MCE stats count only non-null rows, so adjust for null rows.
+		 */
+		selec *= (1.0 - stats->stanullfrac);
+	}
+	else
+	{
+		/* No stats at all, so do without */
+		selec = int_query_opr_selec_no_stats(query);
+		/* we assume no nulls here, so no stanullfrac correction */
+	}
+
+	return selec;
+}
+
+static Selectivity int_query_opr_selec(ITEM *item, Int4Freq *lookup,
+									   int length, float4 minfreq)
+{
+	Selectivity selec = 0;
+
+	/* since this function recurses, it could be driven to stack overflow */
+	check_stack_depth();
+	if (item->type == VAL)
+	{
+		Int4Freq   *searchres;
+
+		if (lookup == NULL)
+			return (Selectivity) DEFAULT_EQ_SEL;
+
+		searchres = (Int4Freq *) bsearch(&item->val, lookup, length,
+										 sizeof(Int4Freq),
+										 compare_val_int4freq);
+
+		if (searchres)
+		{
+			/*
+			 * The element is in MCELEM.  Return precise selectivity (or
+			 * at least as precise as ANALYZE could find out).
+			 */
+			selec = searchres->frequency;
+		}
+		else
+		{
+			/*
+			 * The element is not in MCELEM.  Punt, but assume that the
+			 * selectivity cannot be more than minfreq / 2.
+			 */
+			selec = Min(DEFAULT_EQ_SEL, minfreq / 2);
+		}
+	}
+	else if (item->type == OPR)
+	{
+		/* Current query node is an operator */
+		Selectivity s1,
+					s2;
+
+		switch (item->val)
+		{
+			case (int32) '!':
+				selec = 1.0 - int_query_opr_selec(item - 1,
+												lookup, length, minfreq);
+				break;
+
+			case (int32) '&':
+				s1 = int_query_opr_selec(item - 1,
+									   lookup, length, minfreq);
+				s2 = int_query_opr_selec(item + item->left,
+									   lookup, length, minfreq);
+				selec = s1 * s2;
+				break;
+
+			case (int32) '|':
+				s1 = int_query_opr_selec(item - 1,
+									   lookup, length, minfreq);
+				s2 = int_query_opr_selec(item + item->left,
+									   lookup, length, minfreq);
+				selec = s1 + s2 - s1 * s2;
+				break;
+
+			default:
+				elog(ERROR, "unrecognized operator: %d", item->val);
+				selec = 0;		/* keep compiler quiet */
+				break;
+		}
+	}
+
+	/* Clamp intermediate results to stay sane despite roundoff error */
+	CLAMP_PROBABILITY(selec);
+
+	return selec;
+}
+
+/*
+ * Extract data from the pg_statistic arrays into useful format.
+ */
+static Selectivity
+mcelem_int_query_selec(QUERYTYPE *query, Datum *mcelem, int nmcelem,
+					   float4 *numbers, int nnumbers)
+{
+	float4		minfreq;
+	Int4Freq   *lookup;
+	Selectivity selec;
+	int			i;
+
+	/*
+	 * There should be two more Numbers than Values, because the last 3 (for intarray)
+	 * cells are taken for minimal, maximal and nulls frequency.  Punt if not.
+	 *
+	 */
+	if (nnumbers < nmcelem + 2)
+		return int_query_opr_selec_no_stats(query);
+
+	/*
+	 * Transpose the data into a single array so we can use bsearch().
+	 */
+	lookup = (Int4Freq *) palloc(sizeof(Int4Freq) * nmcelem);
+	for (i = 0; i < nmcelem; i++)
+	{
+		lookup[i].element = DatumGetInt32(mcelem[i]);
+		lookup[i].frequency = numbers[i];
+	}
+
+	/*
+	 * Grab the lowest frequency.
+	 */
+	minfreq = numbers[nnumbers - (nnumbers-nmcelem)];
+	selec = int_query_opr_selec(GETRQUERY(query), lookup,
+								nmcelem, minfreq);
+
+	pfree(lookup);
+
+	return selec;
+}
+
+static int
+compare_val_int4freq(const void *a, const void *b)
+{
+	int32 key = *(int32 *) a;
+	const Int4Freq *t = (const Int4Freq *) b;
+	return key - t->element;
+}
\ No newline at end of file
diff --git a/contrib/intarray/intarray--1.0--1.1.sql b/contrib/intarray/intarray--1.0--1.1.sql
new file mode 100644
index 0000000..018dfd4
--- /dev/null
+++ b/contrib/intarray/intarray--1.0--1.1.sql
@@ -0,0 +1,25 @@
+/* contrib/intarray/intarray--1.0--1.1.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "ALTER EXTENSION intarray UPDATE TO '1.1'" to load this file. \quit
+
+CREATE FUNCTION _int_matchsel(internal, oid, internal, integer)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE;
+
+ALTER OPERATOR @@ (_int4, query_int) SET (RESTRICT = _int_matchsel);
+
+CREATE FUNCTION _int_contsel(internal, oid, internal, integer)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE;
+
+CREATE FUNCTION _int_contjoinsel(internal, oid, internal, smallint, internal)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE;
+
+ALTER OPERATOR && (_int4, _int4) SET (RESTRICT = _int_contsel, JOIN = _int_contjoinsel);
+ALTER OPERATOR @> (_int4, _int4) SET (RESTRICT = _int_contsel, JOIN = _int_contjoinsel);
+ALTER OPERATOR <@ (_int4, _int4) SET (RESTRICT = _int_contsel, JOIN = _int_contjoinsel);
\ No newline at end of file
diff --git a/contrib/intarray/intarray--1.1.sql b/contrib/intarray/intarray--1.1.sql
new file mode 100644
index 0000000..5d4fa39
--- /dev/null
+++ b/contrib/intarray/intarray--1.1.sql
@@ -0,0 +1,500 @@
+/* contrib/intarray/intarray--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION intarray" to load this file. \quit
+
+--
+-- Create the user-defined type for the 1-D integer arrays (_int4)
+--
+
+-- Query type
+CREATE FUNCTION bqarr_in(cstring)
+RETURNS query_int
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION bqarr_out(query_int)
+RETURNS cstring
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE TYPE query_int (
+	INTERNALLENGTH = -1,
+	INPUT = bqarr_in,
+	OUTPUT = bqarr_out
+);
+
+--only for debug
+CREATE FUNCTION querytree(query_int)
+RETURNS text
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+
+CREATE FUNCTION boolop(_int4, query_int)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION boolop(_int4, query_int) IS 'boolean operation with array';
+
+CREATE FUNCTION rboolop(query_int, _int4)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION rboolop(query_int, _int4) IS 'boolean operation with array';
+
+CREATE FUNCTION _int_matchsel(internal, oid, internal, integer)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE;
+
+CREATE OPERATOR @@ (
+	LEFTARG = _int4,
+	RIGHTARG = query_int,
+	PROCEDURE = boolop,
+	COMMUTATOR = '~~',
+	RESTRICT = _int_matchsel,
+	JOIN = contjoinsel
+);
+
+CREATE OPERATOR ~~ (
+	LEFTARG = query_int,
+	RIGHTARG = _int4,
+	PROCEDURE = rboolop,
+	COMMUTATOR = '@@',
+	RESTRICT = contsel,
+	JOIN = contjoinsel
+);
+
+
+--
+-- External C-functions for R-tree methods
+--
+
+-- Comparison methods
+
+CREATE FUNCTION _int_contains(_int4, _int4)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION _int_contains(_int4, _int4) IS 'contains';
+
+CREATE FUNCTION _int_contained(_int4, _int4)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION _int_contained(_int4, _int4) IS 'contained in';
+
+CREATE FUNCTION _int_overlap(_int4, _int4)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION _int_overlap(_int4, _int4) IS 'overlaps';
+
+CREATE FUNCTION _int_same(_int4, _int4)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION _int_same(_int4, _int4) IS 'same as';
+
+CREATE FUNCTION _int_different(_int4, _int4)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION _int_different(_int4, _int4) IS 'different';
+
+-- support routines for indexing
+
+CREATE FUNCTION _int_union(_int4, _int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION _int_inter(_int4, _int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION _int_contsel(internal, oid, internal, integer)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE;
+
+CREATE FUNCTION _int_contjoinsel(internal, oid, internal, smallint, internal)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE;
+
+--
+-- OPERATORS
+--
+
+CREATE OPERATOR && (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	PROCEDURE = _int_overlap,
+	COMMUTATOR = '&&',
+	RESTRICT = _int_contsel,
+	JOIN = _int_contjoinsel
+);
+
+--CREATE OPERATOR = (
+--	LEFTARG = _int4,
+--	RIGHTARG = _int4,
+--	PROCEDURE = _int_same,
+--	COMMUTATOR = '=',
+--	NEGATOR = '<>',
+--	RESTRICT = eqsel,
+--	JOIN = eqjoinsel,
+--	SORT1 = '<',
+--	SORT2 = '<'
+--);
+
+--CREATE OPERATOR <> (
+--	LEFTARG = _int4,
+--	RIGHTARG = _int4,
+--	PROCEDURE = _int_different,
+--	COMMUTATOR = '<>',
+--	NEGATOR = '=',
+--	RESTRICT = neqsel,
+--	JOIN = neqjoinsel
+--);
+
+CREATE OPERATOR @> (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	PROCEDURE = _int_contains,
+	COMMUTATOR = '<@',
+	RESTRICT = _int_contsel,
+	JOIN = _int_contjoinsel
+);
+
+CREATE OPERATOR <@ (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	PROCEDURE = _int_contained,
+	COMMUTATOR = '@>',
+	RESTRICT = _int_contsel,
+	JOIN = _int_contjoinsel
+);
+
+-- obsolete:
+CREATE OPERATOR @ (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	PROCEDURE = _int_contains,
+	COMMUTATOR = '~',
+	RESTRICT = contsel,
+	JOIN = contjoinsel
+);
+
+CREATE OPERATOR ~ (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	PROCEDURE = _int_contained,
+	COMMUTATOR = '@',
+	RESTRICT = contsel,
+	JOIN = contjoinsel
+);
+
+--------------
+CREATE FUNCTION intset(int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION icount(_int4)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR # (
+	RIGHTARG = _int4,
+	PROCEDURE = icount
+);
+
+CREATE FUNCTION sort(_int4, text)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION sort(_int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION sort_asc(_int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION sort_desc(_int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION uniq(_int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION idx(_int4, int4)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR # (
+	LEFTARG = _int4,
+	RIGHTARG = int4,
+	PROCEDURE = idx
+);
+
+CREATE FUNCTION subarray(_int4, int4, int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION subarray(_int4, int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION intarray_push_elem(_int4, int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR + (
+	LEFTARG = _int4,
+	RIGHTARG = int4,
+	PROCEDURE = intarray_push_elem
+);
+
+CREATE FUNCTION intarray_push_array(_int4, _int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR + (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	COMMUTATOR = +,
+	PROCEDURE = intarray_push_array
+);
+
+CREATE FUNCTION intarray_del_elem(_int4, int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR - (
+	LEFTARG = _int4,
+	RIGHTARG = int4,
+	PROCEDURE = intarray_del_elem
+);
+
+CREATE FUNCTION intset_union_elem(_int4, int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR | (
+	LEFTARG = _int4,
+	RIGHTARG = int4,
+	PROCEDURE = intset_union_elem
+);
+
+CREATE OPERATOR | (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	COMMUTATOR = |,
+	PROCEDURE = _int_union
+);
+
+CREATE FUNCTION intset_subtract(_int4, _int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR - (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	PROCEDURE = intset_subtract
+);
+
+CREATE OPERATOR & (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	COMMUTATOR = &,
+	PROCEDURE = _int_inter
+);
+--------------
+
+-- define the GiST support methods
+CREATE FUNCTION g_int_consistent(internal,_int4,int,oid,internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_int_compress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_int_decompress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_int_penalty(internal,internal,internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_int_picksplit(internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_int_union(internal, internal)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_int_same(_int4, _int4, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+
+-- Create the operator class for indexing
+
+CREATE OPERATOR CLASS gist__int_ops
+DEFAULT FOR TYPE _int4 USING gist AS
+	OPERATOR	3	&&,
+	OPERATOR	6	= (anyarray, anyarray),
+	OPERATOR	7	@>,
+	OPERATOR	8	<@,
+	OPERATOR	13	@,
+	OPERATOR	14	~,
+	OPERATOR	20	@@ (_int4, query_int),
+	FUNCTION	1	g_int_consistent (internal, _int4, int, oid, internal),
+	FUNCTION	2	g_int_union (internal, internal),
+	FUNCTION	3	g_int_compress (internal),
+	FUNCTION	4	g_int_decompress (internal),
+	FUNCTION	5	g_int_penalty (internal, internal, internal),
+	FUNCTION	6	g_int_picksplit (internal, internal),
+	FUNCTION	7	g_int_same (_int4, _int4, internal);
+
+
+---------------------------------------------
+-- intbig
+---------------------------------------------
+-- define the GiST support methods
+
+CREATE FUNCTION _intbig_in(cstring)
+RETURNS intbig_gkey
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION _intbig_out(intbig_gkey)
+RETURNS cstring
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE TYPE intbig_gkey (
+        INTERNALLENGTH = -1,
+        INPUT = _intbig_in,
+        OUTPUT = _intbig_out
+);
+
+CREATE FUNCTION g_intbig_consistent(internal,internal,int,oid,internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_intbig_compress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_intbig_decompress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_intbig_penalty(internal,internal,internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_intbig_picksplit(internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_intbig_union(internal, internal)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_intbig_same(internal, internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+-- register the opclass for indexing (not as default)
+
+CREATE OPERATOR CLASS gist__intbig_ops
+FOR TYPE _int4 USING gist
+AS
+	OPERATOR	3	&&,
+	OPERATOR	6	= (anyarray, anyarray),
+	OPERATOR	7	@>,
+	OPERATOR	8	<@,
+	OPERATOR	13	@,
+	OPERATOR	14	~,
+	OPERATOR	20	@@ (_int4, query_int),
+	FUNCTION	1	g_intbig_consistent (internal, internal, int, oid, internal),
+	FUNCTION	2	g_intbig_union (internal, internal),
+	FUNCTION	3	g_intbig_compress (internal),
+	FUNCTION	4	g_intbig_decompress (internal),
+	FUNCTION	5	g_intbig_penalty (internal, internal, internal),
+	FUNCTION	6	g_intbig_picksplit (internal, internal),
+	FUNCTION	7	g_intbig_same (internal, internal, internal),
+	STORAGE		intbig_gkey;
+
+--GIN
+
+CREATE FUNCTION ginint4_queryextract(internal, internal, int2, internal, internal, internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION ginint4_consistent(internal, int2, internal, int4, internal, internal, internal, internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR CLASS gin__int_ops
+FOR TYPE _int4 USING gin
+AS
+	OPERATOR	3	&&,
+	OPERATOR	6	= (anyarray, anyarray),
+	OPERATOR	7	@>,
+	OPERATOR	8	<@,
+	OPERATOR	13	@,
+	OPERATOR	14	~,
+	OPERATOR	20	@@ (_int4, query_int),
+	FUNCTION	1	btint4cmp (int4, int4),
+	FUNCTION	2	ginarrayextract (anyarray, internal, internal),
+	FUNCTION	3	ginint4_queryextract (internal, internal, int2, internal, internal, internal, internal),
+	FUNCTION	4	ginint4_consistent (internal, int2, internal, int4, internal, internal, internal, internal),
+	STORAGE		int4;
diff --git a/contrib/intarray/intarray.control b/contrib/intarray/intarray.control
index 7b3d4f7..8c23e8d 100644
--- a/contrib/intarray/intarray.control
+++ b/contrib/intarray/intarray.control
@@ -1,5 +1,5 @@
 # intarray extension
 comment = 'functions, operators, and index support for 1-D arrays of integers'
-default_version = '1.0'
+default_version = '1.1'
 module_pathname = '$libdir/_int'
 relocatable = true
#2Jeff Janes
jeff.janes@gmail.com
In reply to: Uriy Zhuravlev (#1)
Re: Selectivity estimation for intarray with @@

On Tue, May 26, 2015 at 4:58 AM, Uriy Zhuravlev <u.zhuravlev@postgrespro.ru>
wrote:

Hello.

Attached patch based on:

/messages/by-id/CAPpHfdssY+qEPDCOvxx-b4LP3ybR+qS04M6-ARgGKNFk3FrFow@mail.gmail.com

and adds selectivity estimation functions to @@ (port from tsquery). Now we
support &&, @>, <@ and @@.
In addition it was written migration to version 1.1 intarray. Because of
what
this patch requires my other patch:
/messages/by-id/14346041.DNcb5Y1inS@dinodell

Alexander Korotkov know about this patch.

Hi Uriy,

This patch looks pretty good.

The first line of intarray--1.1.sql mis-identifies itself as "/*
contrib/intarray/intarray--1.0.sql */"

The real file intarray--1.0.sql file probably should not be included in the
final patch, but I like having it for testing.

It applies and builds cleanly over the alter operator patch (and now the
commit as well), passes make check of the contrib module both with and
without cassert.

I could succesfully upgrade from version 1.0 to 1.1 without having to drop
the gin__int_ops indexes in the process.

I could do pg_upgrade from 9.2 and 9.4 to 9.6devel with large indexes in
place, and then upgrade the extension to 1.1, and it worked without having
to rebuild the index.

It does what it says, and I think we want this.

There were some cases where the estimates were not very good, but that
seems to be limitation of what pg_stats makes available, not of this
patch. Specifically if the elements listed in the query text are not part
of most_common_elems (or worse yet, most_common_elems is null) then it is
left to guess with no real data, and those guesses can be pretty bad. It
is not this patches job to fix that, however.

It assumes all the stats are independent and so doesn't account for
correlation between members. This is also how the core selectivity
estimates work between columns, so I can't really complain about that. It
is easy to trick it with things like @@ '(!300 & 300)'::query_int, but I
don't think that is necessary to fix that.

I have not been creative enough to come up with queries for which this
improvement in selectivity estimate causes the execution plan to change in
important ways. I'm sure the serious users of this module would have such
cases, however.

I haven't tested gist__int_ops as I can't get those indexes to build in a
feasible amount of time. But the selectivity estimates are independent of
any actual index, so testing those doesn't seem to be critical.

There is no documentation change, which makes sense as this internal stuff
which isn't documented to start with.

There are no regression test changes. Not sure about that, it does seem
like regression tests would be desirable.

I haven't gone through the C code.

Cheers,

Jeff

#3Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Jeff Janes (#2)
1 attachment(s)
Re: Selectivity estimation for intarray with @@

Hi!

While Uriy is on vacation, I've revised this patch a bit.

On Tue, Jul 14, 2015 at 8:55 PM, Jeff Janes <jeff.janes@gmail.com> wrote:

Hi Uriy,

This patch looks pretty good.

The first line of intarray--1.1.sql mis-identifies itself as "/*
contrib/intarray/intarray--1.0.sql */"

Fixed.

The real file intarray--1.0.sql file probably should not be included in
the final patch, but I like having it for testing.

I've removed intarray--1.0.sql since it shouldn't be in final commit.

It applies and builds cleanly over the alter operator patch (and now the
commit as well), passes make check of the contrib module both with and
without cassert.

I could succesfully upgrade from version 1.0 to 1.1 without having to drop
the gin__int_ops indexes in the process.

I could do pg_upgrade from 9.2 and 9.4 to 9.6devel with large indexes in
place, and then upgrade the extension to 1.1, and it worked without having
to rebuild the index.

It does what it says, and I think we want this.

Good.

There were some cases where the estimates were not very good, but that
seems to be limitation of what pg_stats makes available, not of this
patch. Specifically if the elements listed in the query text are not part
of most_common_elems (or worse yet, most_common_elems is null) then it is
left to guess with no real data, and those guesses can be pretty bad. It
is not this patches job to fix that, however.

It assumes all the stats are independent and so doesn't account for
correlation between members. This is also how the core selectivity
estimates work between columns, so I can't really complain about that. It
is easy to trick it with things like @@ '(!300 & 300)'::query_int, but I
don't think that is necessary to fix that.

Analysis of all the dependencies inside query is NP-complete task. We could
try to workout simple cases, but postgres optimizer currently doesn't care
about it.

# explain select * from test where val = 'val' and val != 'val';
QUERY PLAN
-------------------------------------------------------------
Seq Scan on test (cost=0.00..39831.00 rows=499995 width=8)
Filter: ((val <> 'val'::text) AND (val = 'val'::text))
(2 rows)

I think we could do the same inside intquery until we figure out some
better solution for postgres optimizer in general.

I have not been creative enough to come up with queries for which this
improvement in selectivity estimate causes the execution plan to change in
important ways. I'm sure the serious users of this module would have such
cases, however.

I haven't tested gist__int_ops as I can't get those indexes to build in a
feasible amount of time. But the selectivity estimates are independent of
any actual index, so testing those doesn't seem to be critical.

There is no documentation change, which makes sense as this internal stuff
which isn't documented to start with.

Yes. For instance, tsquery make very similar selectivity estimation as
intquery, but it's assumed to be internal and isn't mentioned in
documentation.

There are no regression test changes. Not sure about that, it does seem

like regression tests would be desirable.

It would be nice to cover selectivity estimation with regression tests, but
AFAICS we didn't do it for any selectivity estimation functions yet.
Problem is that selectivity estimation is quite complex process and its
result depending on random sampling during analyze, floating points
operations and so on. We could make a test like "with very high level of
confidence, estimate number of rows here should be in [10;100]". But it's
hard to fit such assumptions into our current regression tests
infrastructure.

I haven't gone through the C code.

I also did some coding style and comments modifications.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Attachments:

intarray_sel-2.patchapplication/octet-stream; name=intarray_sel-2.patchDownload
diff --git a/contrib/intarray/Makefile b/contrib/intarray/Makefile
new file mode 100644
index 920c5b1..5ea7f2a
*** a/contrib/intarray/Makefile
--- b/contrib/intarray/Makefile
***************
*** 2,11 ****
  
  MODULE_big = _int
  OBJS = _int_bool.o _int_gist.o _int_op.o _int_tool.o \
! 	_intbig_gist.o _int_gin.o $(WIN32RES)
  
  EXTENSION = intarray
! DATA = intarray--1.0.sql intarray--unpackaged--1.0.sql
  PGFILEDESC = "intarray - functions and operators for arrays of integers"
  
  REGRESS = _int
--- 2,11 ----
  
  MODULE_big = _int
  OBJS = _int_bool.o _int_gist.o _int_op.o _int_tool.o \
! 	_intbig_gist.o _int_gin.o _int_selfuncs.o $(WIN32RES)
  
  EXTENSION = intarray
! DATA = intarray--1.1.sql intarray--1.0--1.1.sql intarray--unpackaged--1.0.sql
  PGFILEDESC = "intarray - functions and operators for arrays of integers"
  
  REGRESS = _int
diff --git a/contrib/intarray/_int.h b/contrib/intarray/_int.h
new file mode 100644
index d524f0f..739c3c0
*** a/contrib/intarray/_int.h
--- b/contrib/intarray/_int.h
*************** typedef struct QUERYTYPE
*** 140,145 ****
--- 140,146 ----
  #define COMPUTESIZE(size)	( HDRSIZEQT + (size) * sizeof(ITEM) )
  #define QUERYTYPEMAXITEMS	((MaxAllocSize - HDRSIZEQT) / sizeof(ITEM))
  #define GETQUERY(x)  ( (x)->items )
+ #define GETRQUERY(x)  ( (x)->items + ((x)->size - 1) )
  
  /* "type" codes for ITEM */
  #define END		0
diff --git a/contrib/intarray/_int_selfuncs.c b/contrib/intarray/_int_selfuncs.c
new file mode 100644
index ...4444a01
*** a/contrib/intarray/_int_selfuncs.c
--- b/contrib/intarray/_int_selfuncs.c
***************
*** 0 ****
--- 1,367 ----
+ /*-------------------------------------------------------------------------
+  *
+  * _int_selfuncs.c
+  *	  Functions for selectivity estimation of intarray operators
+  *
+  * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *	  contrib/intarray/_int_selfuncs.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ #include "_int.h"
+ 
+ #include "access/htup_details.h"
+ #include "catalog/pg_operator.h"
+ #include "catalog/pg_statistic.h"
+ #include "catalog/pg_type.h"
+ #include "utils/selfuncs.h"
+ #include "utils/syscache.h"
+ #include "utils/lsyscache.h"
+ #include "miscadmin.h"
+ 
+ PG_FUNCTION_INFO_V1(_int_contsel);
+ PG_FUNCTION_INFO_V1(_int_contjoinsel);
+ PG_FUNCTION_INFO_V1(_int_matchsel);
+ 
+ Datum _int_contsel(PG_FUNCTION_ARGS);
+ Datum _int_contjoinsel(PG_FUNCTION_ARGS);
+ Datum _int_matchsel(PG_FUNCTION_ARGS);
+ 
+ /* lookup table type for binary searching through MCELEMs */
+ typedef struct
+ {
+ 	int32	element;
+ 	float4	frequency;
+ } Int4Freq;
+ 
+ 
+ static Oid transformOperator(Oid oprOid);
+ static Selectivity int_querysel(VariableStatData *vardata, Datum constval);
+ static Selectivity int_query_opr_selec(ITEM *item, Int4Freq *lookup,
+ 									   int length, float4 minfreq);
+ static Selectivity mcelem_int_query_selec(QUERYTYPE *query,
+ 					 Datum *mcelem, int nmcelem,
+ 					 float4 *numbers, int nnumbers);
+ static int compare_val_int4freq(const void *a, const void *b);
+ 
+ #define int_query_opr_selec_no_stats(query) \
+ 	int_query_opr_selec(GETRQUERY(query), NULL, 0, 0)
+ 
+ 
+ /*
+  * Transform intarray &&, @>, @< operators into correspoinding buildin
+  * operators.
+  */
+ static Oid
+ transformOperator(Oid oprOid)
+ {
+ 	HeapTuple			tup;
+ 	Form_pg_operator	op;
+ 	Oid					result = InvalidOid;
+ 
+ 	tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprOid));
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "Invalid operator: %u", oprOid);
+ 
+ 	op = (Form_pg_operator) GETSTRUCT(tup);
+ 
+ 	if (!strcmp(op->oprname.data, "&&"))
+ 		result = OID_ARRAY_OVERLAP_OP;
+ 	else if (!strcmp(op->oprname.data, "@>"))
+ 		result = OID_ARRAY_CONTAINS_OP;
+ 	else if (!strcmp(op->oprname.data, "<@"))
+ 		result = OID_ARRAY_CONTAINED_OP;
+ 
+ 	ReleaseSysCache(tup);
+ 
+ 	if (!OidIsValid(result))
+ 		elog(ERROR, "Invalid operator: %u", oprOid);
+ 
+ 	return result;
+ }
+ 
+ /*
+  * _int_contsel -- restriction selectivity for array @>, &&, <@ operators
+  */
+ Datum
+ _int_contsel(PG_FUNCTION_ARGS)
+ {
+ 	/*
+ 	 * Reuse builtin selectivity estimation with corresponding operator
+ 	 * replacement.
+ 	 */
+ 	PG_RETURN_DATUM(DirectFunctionCall4(arraycontsel,
+ 			PG_GETARG_DATUM(0),
+ 			ObjectIdGetDatum(transformOperator(PG_GETARG_OID(1))),
+ 			PG_GETARG_DATUM(2),
+ 			PG_GETARG_DATUM(3)));
+ }
+ 
+ /*
+  * _int_contjoinsel -- join selectivity for array @>, &&, <@ operators
+  */
+ Datum
+ _int_contjoinsel(PG_FUNCTION_ARGS)
+ {
+ 	/*
+ 	 * Reuse builtin selectivity estimation with corresponding operator
+ 	 * replacement.
+ 	 */
+ 	PG_RETURN_DATUM(DirectFunctionCall5(arraycontjoinsel,
+ 			PG_GETARG_DATUM(0),
+ 			ObjectIdGetDatum(transformOperator(PG_GETARG_OID(1))),
+ 			PG_GETARG_DATUM(2),
+ 			PG_GETARG_DATUM(3),
+ 			PG_GETARG_DATUM(4)));
+ }
+ 
+ 
+ /*
+  * _int_matchsel -- restriction selectivity function for intarray @@ int_query
+  */
+ Datum
+ _int_matchsel(PG_FUNCTION_ARGS)
+ {
+ 	PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
+ 
+ 	List	   *args = (List *) PG_GETARG_POINTER(2);
+ 	int			varRelid = PG_GETARG_INT32(3);
+ 	VariableStatData vardata;
+ 	Node	   *other;
+ 	bool		varonleft;
+ 	Selectivity selec;
+ 
+ 	/*
+ 	 * If expression is not "variable @@ something" or "something @@ variable"
+ 	 * then punt and return a default estimate.
+ 	 */
+ 	if (!get_restriction_variable(root, args, varRelid,
+ 								  &vardata, &other, &varonleft))
+ 		PG_RETURN_FLOAT8(DEFAULT_EQ_SEL);
+ 
+ 	/*
+ 	 * Can't do anything useful if the something is not a constant, either.
+ 	 */
+ 	if (!IsA(other, Const))
+ 	{
+ 		ReleaseVariableStats(vardata);
+ 		PG_RETURN_FLOAT8(DEFAULT_EQ_SEL);
+ 	}
+ 
+ 	/*
+ 	 * The "@@" operator is strict, so we can cope with NULL right away.
+ 	 */
+ 	if (((Const *) other)->constisnull)
+ 	{
+ 		ReleaseVariableStats(vardata);
+ 		PG_RETURN_FLOAT8(0.0);
+ 	}
+ 
+ 	selec = int_querysel(&vardata, ((Const *) other)->constvalue);
+ 
+ 	ReleaseVariableStats(vardata);
+ 
+ 	CLAMP_PROBABILITY(selec);
+ 
+ 	PG_RETURN_FLOAT8((float8) selec);
+ }
+ 
+ /*
+  * Estimate selectivity of "variable @@ const"
+  */
+ static Selectivity
+ int_querysel(VariableStatData *vardata, Datum constval)
+ {
+ 	Selectivity selec;
+ 	QUERYTYPE		*query;
+ 
+ 	/* The caller made sure the const is a query, so get it now */
+ 	query = DatumGetQueryTypeP(constval);
+ 
+ 	/* Empty query matches nothing */
+ 	if (query->size == 0)
+ 		return (Selectivity) 0.0;
+ 
+ 	if (HeapTupleIsValid(vardata->statsTuple))
+ 	{
+ 		Form_pg_statistic stats;
+ 		Datum	   *values;
+ 		int			nvalues;
+ 		float4	   *numbers;
+ 		int			nnumbers;
+ 
+ 		stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple);
+ 
+ 		/* MCELEM will be an array of INT4 elements for a intarray column */
+ 		if (get_attstatsslot(vardata->statsTuple,
+ 							 INT4OID, -1,
+ 							 STATISTIC_KIND_MCELEM, InvalidOid,
+ 							 NULL,
+ 							 &values, &nvalues,
+ 							 &numbers, &nnumbers))
+ 		{
+ 			/*
+ 			 * There is a most-common-elements slot for the intarray Var, so
+ 			 * use that.
+ 			 */
+ 			selec = mcelem_int_query_selec(query, values, nvalues,
+ 										   numbers, nnumbers);
+ 			free_attstatsslot(INT4OID, values, nvalues, numbers, nnumbers);
+ 		}
+ 		else
+ 		{
+ 			/* No most-common-elements info, so do without */
+ 			selec = int_query_opr_selec_no_stats(query);
+ 		}
+ 		/*
+ 		 * MCE stats count only non-null rows, so adjust for null rows.
+ 		 */
+ 		selec *= (1.0 - stats->stanullfrac);
+ 	}
+ 	else
+ 	{
+ 		/* No stats at all, so do without */
+ 		selec = int_query_opr_selec_no_stats(query);
+ 		/* we assume no nulls here, so no stanullfrac correction */
+ 	}
+ 
+ 	return selec;
+ }
+ 
+ /*
+  * Estimate selectivity of single intquery operator
+  */
+ static Selectivity
+ int_query_opr_selec(ITEM *item, Int4Freq *lookup, int length, float4 minfreq)
+ {
+ 	Selectivity selec = 0;
+ 
+ 	/* since this function recurses, it could be driven to stack overflow */
+ 	check_stack_depth();
+ 	if (item->type == VAL)
+ 	{
+ 		Int4Freq   *searchres;
+ 
+ 		if (lookup == NULL)
+ 			return (Selectivity) DEFAULT_EQ_SEL;
+ 
+ 		searchres = (Int4Freq *) bsearch(&item->val, lookup, length,
+ 										 sizeof(Int4Freq),
+ 										 compare_val_int4freq);
+ 
+ 		if (searchres)
+ 		{
+ 			/*
+ 			 * The element is in MCELEM.  Return precise selectivity (or
+ 			 * at least as precise as ANALYZE could find out).
+ 			 */
+ 			selec = searchres->frequency;
+ 		}
+ 		else
+ 		{
+ 			/*
+ 			 * The element is not in MCELEM.  Punt, but assume that the
+ 			 * selectivity cannot be more than minfreq / 2.
+ 			 */
+ 			selec = Min(DEFAULT_EQ_SEL, minfreq / 2);
+ 		}
+ 	}
+ 	else if (item->type == OPR)
+ 	{
+ 		/* Current query node is an operator */
+ 		Selectivity s1,
+ 					s2;
+ 
+ 		switch (item->val)
+ 		{
+ 			case (int32) '!':
+ 				selec = 1.0 - int_query_opr_selec(item - 1,
+ 												lookup, length, minfreq);
+ 				break;
+ 
+ 			case (int32) '&':
+ 				s1 = int_query_opr_selec(item - 1,
+ 									   lookup, length, minfreq);
+ 				s2 = int_query_opr_selec(item + item->left,
+ 									   lookup, length, minfreq);
+ 				selec = s1 * s2;
+ 				break;
+ 
+ 			case (int32) '|':
+ 				s1 = int_query_opr_selec(item - 1,
+ 									   lookup, length, minfreq);
+ 				s2 = int_query_opr_selec(item + item->left,
+ 									   lookup, length, minfreq);
+ 				selec = s1 + s2 - s1 * s2;
+ 				break;
+ 
+ 			default:
+ 				elog(ERROR, "unrecognized operator: %d", item->val);
+ 				selec = 0;		/* keep compiler quiet */
+ 				break;
+ 		}
+ 	}
+ 
+ 	/* Clamp intermediate results to stay sane despite roundoff error */
+ 	CLAMP_PROBABILITY(selec);
+ 
+ 	return selec;
+ }
+ 
+ /*
+  * Extract data from the pg_statistic arrays into useful format.
+  */
+ static Selectivity
+ mcelem_int_query_selec(QUERYTYPE *query, Datum *mcelem, int nmcelem,
+ 					   float4 *numbers, int nnumbers)
+ {
+ 	float4		minfreq;
+ 	Int4Freq   *lookup;
+ 	Selectivity selec;
+ 	int			i;
+ 
+ 	/*
+ 	 * There should be two more Numbers than Values, because the last 3 (for intarray)
+ 	 * cells are taken for minimal, maximal and nulls frequency.  Punt if not.
+ 	 *
+ 	 */
+ 	if (nnumbers < nmcelem + 2)
+ 		return int_query_opr_selec_no_stats(query);
+ 
+ 	/*
+ 	 * Transpose the data into a single array so we can use bsearch().
+ 	 */
+ 	lookup = (Int4Freq *) palloc(sizeof(Int4Freq) * nmcelem);
+ 	for (i = 0; i < nmcelem; i++)
+ 	{
+ 		lookup[i].element = DatumGetInt32(mcelem[i]);
+ 		lookup[i].frequency = numbers[i];
+ 	}
+ 
+ 	/*
+ 	 * Grab the lowest frequency.
+ 	 */
+ 	minfreq = numbers[nnumbers - (nnumbers-nmcelem)];
+ 	selec = int_query_opr_selec(GETRQUERY(query), lookup,
+ 								nmcelem, minfreq);
+ 
+ 	pfree(lookup);
+ 
+ 	return selec;
+ }
+ 
+ /*
+  * Comparison function for binary search in mcelem array.
+  */
+ static int
+ compare_val_int4freq(const void *a, const void *b)
+ {
+ 	int32 key = *(int32 *) a;
+ 	const Int4Freq *t = (const Int4Freq *) b;
+ 	return key - t->element;
+ }
diff --git a/contrib/intarray/intarray--1.0--1.1.sql b/contrib/intarray/intarray--1.0--1.1.sql
new file mode 100644
index ...018dfd4
*** a/contrib/intarray/intarray--1.0--1.1.sql
--- b/contrib/intarray/intarray--1.0--1.1.sql
***************
*** 0 ****
--- 1,25 ----
+ /* contrib/intarray/intarray--1.0--1.1.sql */
+ 
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "ALTER EXTENSION intarray UPDATE TO '1.1'" to load this file. \quit
+ 
+ CREATE FUNCTION _int_matchsel(internal, oid, internal, integer)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ ALTER OPERATOR @@ (_int4, query_int) SET (RESTRICT = _int_matchsel);
+ 
+ CREATE FUNCTION _int_contsel(internal, oid, internal, integer)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE FUNCTION _int_contjoinsel(internal, oid, internal, smallint, internal)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ ALTER OPERATOR && (_int4, _int4) SET (RESTRICT = _int_contsel, JOIN = _int_contjoinsel);
+ ALTER OPERATOR @> (_int4, _int4) SET (RESTRICT = _int_contsel, JOIN = _int_contjoinsel);
+ ALTER OPERATOR <@ (_int4, _int4) SET (RESTRICT = _int_contsel, JOIN = _int_contjoinsel);
\ No newline at end of file
diff --git a/contrib/intarray/intarray--1.0.sql b/contrib/intarray/intarray--1.0.sql
new file mode .
index 0b89e0f..e69de29
*** a/contrib/intarray/intarray--1.0.sql
--- b/contrib/intarray/intarray--1.0.sql
***************
*** 1,485 ****
- /* contrib/intarray/intarray--1.0.sql */
- 
- -- complain if script is sourced in psql, rather than via CREATE EXTENSION
- \echo Use "CREATE EXTENSION intarray" to load this file. \quit
- 
- --
- -- Create the user-defined type for the 1-D integer arrays (_int4)
- --
- 
- -- Query type
- CREATE FUNCTION bqarr_in(cstring)
- RETURNS query_int
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION bqarr_out(query_int)
- RETURNS cstring
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE TYPE query_int (
- 	INTERNALLENGTH = -1,
- 	INPUT = bqarr_in,
- 	OUTPUT = bqarr_out
- );
- 
- --only for debug
- CREATE FUNCTION querytree(query_int)
- RETURNS text
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- 
- CREATE FUNCTION boolop(_int4, query_int)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION boolop(_int4, query_int) IS 'boolean operation with array';
- 
- CREATE FUNCTION rboolop(query_int, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION rboolop(query_int, _int4) IS 'boolean operation with array';
- 
- CREATE OPERATOR @@ (
- 	LEFTARG = _int4,
- 	RIGHTARG = query_int,
- 	PROCEDURE = boolop,
- 	COMMUTATOR = '~~',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE OPERATOR ~~ (
- 	LEFTARG = query_int,
- 	RIGHTARG = _int4,
- 	PROCEDURE = rboolop,
- 	COMMUTATOR = '@@',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- 
- --
- -- External C-functions for R-tree methods
- --
- 
- -- Comparison methods
- 
- CREATE FUNCTION _int_contains(_int4, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION _int_contains(_int4, _int4) IS 'contains';
- 
- CREATE FUNCTION _int_contained(_int4, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION _int_contained(_int4, _int4) IS 'contained in';
- 
- CREATE FUNCTION _int_overlap(_int4, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION _int_overlap(_int4, _int4) IS 'overlaps';
- 
- CREATE FUNCTION _int_same(_int4, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION _int_same(_int4, _int4) IS 'same as';
- 
- CREATE FUNCTION _int_different(_int4, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION _int_different(_int4, _int4) IS 'different';
- 
- -- support routines for indexing
- 
- CREATE FUNCTION _int_union(_int4, _int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION _int_inter(_int4, _int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- --
- -- OPERATORS
- --
- 
- CREATE OPERATOR && (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = _int_overlap,
- 	COMMUTATOR = '&&',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- --CREATE OPERATOR = (
- --	LEFTARG = _int4,
- --	RIGHTARG = _int4,
- --	PROCEDURE = _int_same,
- --	COMMUTATOR = '=',
- --	NEGATOR = '<>',
- --	RESTRICT = eqsel,
- --	JOIN = eqjoinsel,
- --	SORT1 = '<',
- --	SORT2 = '<'
- --);
- 
- --CREATE OPERATOR <> (
- --	LEFTARG = _int4,
- --	RIGHTARG = _int4,
- --	PROCEDURE = _int_different,
- --	COMMUTATOR = '<>',
- --	NEGATOR = '=',
- --	RESTRICT = neqsel,
- --	JOIN = neqjoinsel
- --);
- 
- CREATE OPERATOR @> (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = _int_contains,
- 	COMMUTATOR = '<@',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE OPERATOR <@ (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = _int_contained,
- 	COMMUTATOR = '@>',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- -- obsolete:
- CREATE OPERATOR @ (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = _int_contains,
- 	COMMUTATOR = '~',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE OPERATOR ~ (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = _int_contained,
- 	COMMUTATOR = '@',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- --------------
- CREATE FUNCTION intset(int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION icount(_int4)
- RETURNS int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR # (
- 	RIGHTARG = _int4,
- 	PROCEDURE = icount
- );
- 
- CREATE FUNCTION sort(_int4, text)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION sort(_int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION sort_asc(_int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION sort_desc(_int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION uniq(_int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION idx(_int4, int4)
- RETURNS int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR # (
- 	LEFTARG = _int4,
- 	RIGHTARG = int4,
- 	PROCEDURE = idx
- );
- 
- CREATE FUNCTION subarray(_int4, int4, int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION subarray(_int4, int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION intarray_push_elem(_int4, int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR + (
- 	LEFTARG = _int4,
- 	RIGHTARG = int4,
- 	PROCEDURE = intarray_push_elem
- );
- 
- CREATE FUNCTION intarray_push_array(_int4, _int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR + (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	COMMUTATOR = +,
- 	PROCEDURE = intarray_push_array
- );
- 
- CREATE FUNCTION intarray_del_elem(_int4, int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR - (
- 	LEFTARG = _int4,
- 	RIGHTARG = int4,
- 	PROCEDURE = intarray_del_elem
- );
- 
- CREATE FUNCTION intset_union_elem(_int4, int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR | (
- 	LEFTARG = _int4,
- 	RIGHTARG = int4,
- 	PROCEDURE = intset_union_elem
- );
- 
- CREATE OPERATOR | (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	COMMUTATOR = |,
- 	PROCEDURE = _int_union
- );
- 
- CREATE FUNCTION intset_subtract(_int4, _int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR - (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = intset_subtract
- );
- 
- CREATE OPERATOR & (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	COMMUTATOR = &,
- 	PROCEDURE = _int_inter
- );
- --------------
- 
- -- define the GiST support methods
- CREATE FUNCTION g_int_consistent(internal,_int4,int,oid,internal)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_compress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_decompress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_penalty(internal,internal,internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_picksplit(internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_union(internal, internal)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_same(_int4, _int4, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- 
- -- Create the operator class for indexing
- 
- CREATE OPERATOR CLASS gist__int_ops
- DEFAULT FOR TYPE _int4 USING gist AS
- 	OPERATOR	3	&&,
- 	OPERATOR	6	= (anyarray, anyarray),
- 	OPERATOR	7	@>,
- 	OPERATOR	8	<@,
- 	OPERATOR	13	@,
- 	OPERATOR	14	~,
- 	OPERATOR	20	@@ (_int4, query_int),
- 	FUNCTION	1	g_int_consistent (internal, _int4, int, oid, internal),
- 	FUNCTION	2	g_int_union (internal, internal),
- 	FUNCTION	3	g_int_compress (internal),
- 	FUNCTION	4	g_int_decompress (internal),
- 	FUNCTION	5	g_int_penalty (internal, internal, internal),
- 	FUNCTION	6	g_int_picksplit (internal, internal),
- 	FUNCTION	7	g_int_same (_int4, _int4, internal);
- 
- 
- ---------------------------------------------
- -- intbig
- ---------------------------------------------
- -- define the GiST support methods
- 
- CREATE FUNCTION _intbig_in(cstring)
- RETURNS intbig_gkey
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION _intbig_out(intbig_gkey)
- RETURNS cstring
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE TYPE intbig_gkey (
-         INTERNALLENGTH = -1,
-         INPUT = _intbig_in,
-         OUTPUT = _intbig_out
- );
- 
- CREATE FUNCTION g_intbig_consistent(internal,internal,int,oid,internal)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_compress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_decompress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_penalty(internal,internal,internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_picksplit(internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_union(internal, internal)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_same(internal, internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- -- register the opclass for indexing (not as default)
- 
- CREATE OPERATOR CLASS gist__intbig_ops
- FOR TYPE _int4 USING gist
- AS
- 	OPERATOR	3	&&,
- 	OPERATOR	6	= (anyarray, anyarray),
- 	OPERATOR	7	@>,
- 	OPERATOR	8	<@,
- 	OPERATOR	13	@,
- 	OPERATOR	14	~,
- 	OPERATOR	20	@@ (_int4, query_int),
- 	FUNCTION	1	g_intbig_consistent (internal, internal, int, oid, internal),
- 	FUNCTION	2	g_intbig_union (internal, internal),
- 	FUNCTION	3	g_intbig_compress (internal),
- 	FUNCTION	4	g_intbig_decompress (internal),
- 	FUNCTION	5	g_intbig_penalty (internal, internal, internal),
- 	FUNCTION	6	g_intbig_picksplit (internal, internal),
- 	FUNCTION	7	g_intbig_same (internal, internal, internal),
- 	STORAGE		intbig_gkey;
- 
- --GIN
- 
- CREATE FUNCTION ginint4_queryextract(internal, internal, int2, internal, internal, internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION ginint4_consistent(internal, int2, internal, int4, internal, internal, internal, internal)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE OPERATOR CLASS gin__int_ops
- FOR TYPE _int4 USING gin
- AS
- 	OPERATOR	3	&&,
- 	OPERATOR	6	= (anyarray, anyarray),
- 	OPERATOR	7	@>,
- 	OPERATOR	8	<@,
- 	OPERATOR	13	@,
- 	OPERATOR	14	~,
- 	OPERATOR	20	@@ (_int4, query_int),
- 	FUNCTION	1	btint4cmp (int4, int4),
- 	FUNCTION	2	ginarrayextract (anyarray, internal, internal),
- 	FUNCTION	3	ginint4_queryextract (internal, internal, int2, internal, internal, internal, internal),
- 	FUNCTION	4	ginint4_consistent (internal, int2, internal, int4, internal, internal, internal, internal),
- 	STORAGE		int4;
--- 0 ----
diff --git a/contrib/intarray/intarray--1.1.sql b/contrib/intarray/intarray--1.1.sql
new file mode 100644
index ...f29c488
*** a/contrib/intarray/intarray--1.1.sql
--- b/contrib/intarray/intarray--1.1.sql
***************
*** 0 ****
--- 1,500 ----
+ /* contrib/intarray/intarray--1.1.sql */
+ 
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "CREATE EXTENSION intarray" to load this file. \quit
+ 
+ --
+ -- Create the user-defined type for the 1-D integer arrays (_int4)
+ --
+ 
+ -- Query type
+ CREATE FUNCTION bqarr_in(cstring)
+ RETURNS query_int
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION bqarr_out(query_int)
+ RETURNS cstring
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE TYPE query_int (
+ 	INTERNALLENGTH = -1,
+ 	INPUT = bqarr_in,
+ 	OUTPUT = bqarr_out
+ );
+ 
+ --only for debug
+ CREATE FUNCTION querytree(query_int)
+ RETURNS text
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ 
+ CREATE FUNCTION boolop(_int4, query_int)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION boolop(_int4, query_int) IS 'boolean operation with array';
+ 
+ CREATE FUNCTION rboolop(query_int, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION rboolop(query_int, _int4) IS 'boolean operation with array';
+ 
+ CREATE FUNCTION _int_matchsel(internal, oid, internal, integer)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE OPERATOR @@ (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = query_int,
+ 	PROCEDURE = boolop,
+ 	COMMUTATOR = '~~',
+ 	RESTRICT = _int_matchsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ CREATE OPERATOR ~~ (
+ 	LEFTARG = query_int,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = rboolop,
+ 	COMMUTATOR = '@@',
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ 
+ --
+ -- External C-functions for R-tree methods
+ --
+ 
+ -- Comparison methods
+ 
+ CREATE FUNCTION _int_contains(_int4, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION _int_contains(_int4, _int4) IS 'contains';
+ 
+ CREATE FUNCTION _int_contained(_int4, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION _int_contained(_int4, _int4) IS 'contained in';
+ 
+ CREATE FUNCTION _int_overlap(_int4, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION _int_overlap(_int4, _int4) IS 'overlaps';
+ 
+ CREATE FUNCTION _int_same(_int4, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION _int_same(_int4, _int4) IS 'same as';
+ 
+ CREATE FUNCTION _int_different(_int4, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION _int_different(_int4, _int4) IS 'different';
+ 
+ -- support routines for indexing
+ 
+ CREATE FUNCTION _int_union(_int4, _int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION _int_inter(_int4, _int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION _int_contsel(internal, oid, internal, integer)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE FUNCTION _int_contjoinsel(internal, oid, internal, smallint, internal)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ --
+ -- OPERATORS
+ --
+ 
+ CREATE OPERATOR && (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = _int_overlap,
+ 	COMMUTATOR = '&&',
+ 	RESTRICT = _int_contsel,
+ 	JOIN = _int_contjoinsel
+ );
+ 
+ --CREATE OPERATOR = (
+ --	LEFTARG = _int4,
+ --	RIGHTARG = _int4,
+ --	PROCEDURE = _int_same,
+ --	COMMUTATOR = '=',
+ --	NEGATOR = '<>',
+ --	RESTRICT = eqsel,
+ --	JOIN = eqjoinsel,
+ --	SORT1 = '<',
+ --	SORT2 = '<'
+ --);
+ 
+ --CREATE OPERATOR <> (
+ --	LEFTARG = _int4,
+ --	RIGHTARG = _int4,
+ --	PROCEDURE = _int_different,
+ --	COMMUTATOR = '<>',
+ --	NEGATOR = '=',
+ --	RESTRICT = neqsel,
+ --	JOIN = neqjoinsel
+ --);
+ 
+ CREATE OPERATOR @> (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = _int_contains,
+ 	COMMUTATOR = '<@',
+ 	RESTRICT = _int_contsel,
+ 	JOIN = _int_contjoinsel
+ );
+ 
+ CREATE OPERATOR <@ (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = _int_contained,
+ 	COMMUTATOR = '@>',
+ 	RESTRICT = _int_contsel,
+ 	JOIN = _int_contjoinsel
+ );
+ 
+ -- obsolete:
+ CREATE OPERATOR @ (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = _int_contains,
+ 	COMMUTATOR = '~',
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ CREATE OPERATOR ~ (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = _int_contained,
+ 	COMMUTATOR = '@',
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ --------------
+ CREATE FUNCTION intset(int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION icount(_int4)
+ RETURNS int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR # (
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = icount
+ );
+ 
+ CREATE FUNCTION sort(_int4, text)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION sort(_int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION sort_asc(_int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION sort_desc(_int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION uniq(_int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION idx(_int4, int4)
+ RETURNS int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR # (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = int4,
+ 	PROCEDURE = idx
+ );
+ 
+ CREATE FUNCTION subarray(_int4, int4, int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION subarray(_int4, int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION intarray_push_elem(_int4, int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR + (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = int4,
+ 	PROCEDURE = intarray_push_elem
+ );
+ 
+ CREATE FUNCTION intarray_push_array(_int4, _int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR + (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	COMMUTATOR = +,
+ 	PROCEDURE = intarray_push_array
+ );
+ 
+ CREATE FUNCTION intarray_del_elem(_int4, int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR - (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = int4,
+ 	PROCEDURE = intarray_del_elem
+ );
+ 
+ CREATE FUNCTION intset_union_elem(_int4, int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR | (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = int4,
+ 	PROCEDURE = intset_union_elem
+ );
+ 
+ CREATE OPERATOR | (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	COMMUTATOR = |,
+ 	PROCEDURE = _int_union
+ );
+ 
+ CREATE FUNCTION intset_subtract(_int4, _int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR - (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = intset_subtract
+ );
+ 
+ CREATE OPERATOR & (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	COMMUTATOR = &,
+ 	PROCEDURE = _int_inter
+ );
+ --------------
+ 
+ -- define the GiST support methods
+ CREATE FUNCTION g_int_consistent(internal,_int4,int,oid,internal)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_compress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_decompress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_penalty(internal,internal,internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_picksplit(internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_union(internal, internal)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_same(_int4, _int4, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ 
+ -- Create the operator class for indexing
+ 
+ CREATE OPERATOR CLASS gist__int_ops
+ DEFAULT FOR TYPE _int4 USING gist AS
+ 	OPERATOR	3	&&,
+ 	OPERATOR	6	= (anyarray, anyarray),
+ 	OPERATOR	7	@>,
+ 	OPERATOR	8	<@,
+ 	OPERATOR	13	@,
+ 	OPERATOR	14	~,
+ 	OPERATOR	20	@@ (_int4, query_int),
+ 	FUNCTION	1	g_int_consistent (internal, _int4, int, oid, internal),
+ 	FUNCTION	2	g_int_union (internal, internal),
+ 	FUNCTION	3	g_int_compress (internal),
+ 	FUNCTION	4	g_int_decompress (internal),
+ 	FUNCTION	5	g_int_penalty (internal, internal, internal),
+ 	FUNCTION	6	g_int_picksplit (internal, internal),
+ 	FUNCTION	7	g_int_same (_int4, _int4, internal);
+ 
+ 
+ ---------------------------------------------
+ -- intbig
+ ---------------------------------------------
+ -- define the GiST support methods
+ 
+ CREATE FUNCTION _intbig_in(cstring)
+ RETURNS intbig_gkey
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION _intbig_out(intbig_gkey)
+ RETURNS cstring
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE TYPE intbig_gkey (
+         INTERNALLENGTH = -1,
+         INPUT = _intbig_in,
+         OUTPUT = _intbig_out
+ );
+ 
+ CREATE FUNCTION g_intbig_consistent(internal,internal,int,oid,internal)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_compress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_decompress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_penalty(internal,internal,internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_picksplit(internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_union(internal, internal)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_same(internal, internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ -- register the opclass for indexing (not as default)
+ 
+ CREATE OPERATOR CLASS gist__intbig_ops
+ FOR TYPE _int4 USING gist
+ AS
+ 	OPERATOR	3	&&,
+ 	OPERATOR	6	= (anyarray, anyarray),
+ 	OPERATOR	7	@>,
+ 	OPERATOR	8	<@,
+ 	OPERATOR	13	@,
+ 	OPERATOR	14	~,
+ 	OPERATOR	20	@@ (_int4, query_int),
+ 	FUNCTION	1	g_intbig_consistent (internal, internal, int, oid, internal),
+ 	FUNCTION	2	g_intbig_union (internal, internal),
+ 	FUNCTION	3	g_intbig_compress (internal),
+ 	FUNCTION	4	g_intbig_decompress (internal),
+ 	FUNCTION	5	g_intbig_penalty (internal, internal, internal),
+ 	FUNCTION	6	g_intbig_picksplit (internal, internal),
+ 	FUNCTION	7	g_intbig_same (internal, internal, internal),
+ 	STORAGE		intbig_gkey;
+ 
+ --GIN
+ 
+ CREATE FUNCTION ginint4_queryextract(internal, internal, int2, internal, internal, internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION ginint4_consistent(internal, int2, internal, int4, internal, internal, internal, internal)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE OPERATOR CLASS gin__int_ops
+ FOR TYPE _int4 USING gin
+ AS
+ 	OPERATOR	3	&&,
+ 	OPERATOR	6	= (anyarray, anyarray),
+ 	OPERATOR	7	@>,
+ 	OPERATOR	8	<@,
+ 	OPERATOR	13	@,
+ 	OPERATOR	14	~,
+ 	OPERATOR	20	@@ (_int4, query_int),
+ 	FUNCTION	1	btint4cmp (int4, int4),
+ 	FUNCTION	2	ginarrayextract (anyarray, internal, internal),
+ 	FUNCTION	3	ginint4_queryextract (internal, internal, int2, internal, internal, internal, internal),
+ 	FUNCTION	4	ginint4_consistent (internal, int2, internal, int4, internal, internal, internal, internal),
+ 	STORAGE		int4;
diff --git a/contrib/intarray/intarray.control b/contrib/intarray/intarray.control
new file mode 100644
index 7b3d4f7..8c23e8d
*** a/contrib/intarray/intarray.control
--- b/contrib/intarray/intarray.control
***************
*** 1,5 ****
  # intarray extension
  comment = 'functions, operators, and index support for 1-D arrays of integers'
! default_version = '1.0'
  module_pathname = '$libdir/_int'
  relocatable = true
--- 1,5 ----
  # intarray extension
  comment = 'functions, operators, and index support for 1-D arrays of integers'
! default_version = '1.1'
  module_pathname = '$libdir/_int'
  relocatable = true
#4Teodor Sigaev
teodor@sigaev.ru
In reply to: Alexander Korotkov (#3)
Re: Selectivity estimation for intarray with @@

Some notices about code:

1 Near function transformOperator() there is wrong operator name "@<"
2 int_query (and intquery) should be replaced to query_int to be consistent with
actual type name. At least where it's used as separate lexeme.
3 For historical reasons @@ doesn't commutate with itself, it has a commutator
~~. Patch assumes that @@ is self-commutator, but ~~ will use 'contsel' as a
restrict estimation. Suppose, we need to declare ~~ as deprecated and introduce
commutating @@ operator.

--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#5Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Teodor Sigaev (#4)
1 attachment(s)
Re: Selectivity estimation for intarray with @@

On Tue, Jul 21, 2015 at 5:14 PM, Teodor Sigaev <teodor@sigaev.ru> wrote:

Some notices about code:

1 Near function transformOperator() there is wrong operator name "@<"

Fixed.

2 int_query (and intquery) should be replaced to query_int to be
consistent with actual type name. At least where it's used as separate
lexeme.

Fixed.

3 For historical reasons @@ doesn't commutate with itself, it has a
commutator ~~. Patch assumes that @@ is self-commutator, but ~~ will use
'contsel' as a restrict estimation. Suppose, we need to declare ~~ as
deprecated and introduce commutating @@ operator.

I think deprecating ~~ is a subject of separate patch. I fixed patch
behavior in the different way. @@ and ~~ are now handled by the same
function. The function handles "var @@ const" and "const ~~ var", but
doesn't handle "const @@ var" and "var ~~ const". It determines the case
by type of variable: it should be int[].

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Attachments:

intarray_sel-3.patchapplication/octet-stream; name=intarray_sel-3.patchDownload
diff --git a/contrib/intarray/Makefile b/contrib/intarray/Makefile
new file mode 100644
index 920c5b1..5ea7f2a
*** a/contrib/intarray/Makefile
--- b/contrib/intarray/Makefile
***************
*** 2,11 ****
  
  MODULE_big = _int
  OBJS = _int_bool.o _int_gist.o _int_op.o _int_tool.o \
! 	_intbig_gist.o _int_gin.o $(WIN32RES)
  
  EXTENSION = intarray
! DATA = intarray--1.0.sql intarray--unpackaged--1.0.sql
  PGFILEDESC = "intarray - functions and operators for arrays of integers"
  
  REGRESS = _int
--- 2,11 ----
  
  MODULE_big = _int
  OBJS = _int_bool.o _int_gist.o _int_op.o _int_tool.o \
! 	_intbig_gist.o _int_gin.o _int_selfuncs.o $(WIN32RES)
  
  EXTENSION = intarray
! DATA = intarray--1.1.sql intarray--1.0--1.1.sql intarray--unpackaged--1.0.sql
  PGFILEDESC = "intarray - functions and operators for arrays of integers"
  
  REGRESS = _int
diff --git a/contrib/intarray/_int.h b/contrib/intarray/_int.h
new file mode 100644
index d524f0f..739c3c0
*** a/contrib/intarray/_int.h
--- b/contrib/intarray/_int.h
*************** typedef struct QUERYTYPE
*** 140,145 ****
--- 140,146 ----
  #define COMPUTESIZE(size)	( HDRSIZEQT + (size) * sizeof(ITEM) )
  #define QUERYTYPEMAXITEMS	((MaxAllocSize - HDRSIZEQT) / sizeof(ITEM))
  #define GETQUERY(x)  ( (x)->items )
+ #define GETRQUERY(x)  ( (x)->items + ((x)->size - 1) )
  
  /* "type" codes for ITEM */
  #define END		0
diff --git a/contrib/intarray/_int_selfuncs.c b/contrib/intarray/_int_selfuncs.c
new file mode 100644
index ...adb524f
*** a/contrib/intarray/_int_selfuncs.c
--- b/contrib/intarray/_int_selfuncs.c
***************
*** 0 ****
--- 1,375 ----
+ /*-------------------------------------------------------------------------
+  *
+  * _int_selfuncs.c
+  *	  Functions for selectivity estimation of intarray operators
+  *
+  * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *	  contrib/intarray/_int_selfuncs.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ #include "_int.h"
+ 
+ #include "access/htup_details.h"
+ #include "catalog/pg_operator.h"
+ #include "catalog/pg_statistic.h"
+ #include "catalog/pg_type.h"
+ #include "utils/selfuncs.h"
+ #include "utils/syscache.h"
+ #include "utils/lsyscache.h"
+ #include "miscadmin.h"
+ 
+ PG_FUNCTION_INFO_V1(_int_contsel);
+ PG_FUNCTION_INFO_V1(_int_contjoinsel);
+ PG_FUNCTION_INFO_V1(_int_matchsel);
+ 
+ Datum _int_contsel(PG_FUNCTION_ARGS);
+ Datum _int_contjoinsel(PG_FUNCTION_ARGS);
+ Datum _int_matchsel(PG_FUNCTION_ARGS);
+ 
+ /* lookup table type for binary searching through MCELEMs */
+ typedef struct
+ {
+ 	int32	element;
+ 	float4	frequency;
+ } Int4Freq;
+ 
+ 
+ static Oid transformOperator(Oid oprOid);
+ static Selectivity query_intsel(VariableStatData *vardata, Datum constval);
+ static Selectivity query_int_opr_selec(ITEM *item, Int4Freq *lookup,
+ 									   int length, float4 minfreq);
+ static Selectivity mcelem_query_int_selec(QUERYTYPE *query,
+ 					 Datum *mcelem, int nmcelem,
+ 					 float4 *numbers, int nnumbers);
+ static int compare_val_int4freq(const void *a, const void *b);
+ 
+ #define query_int_opr_selec_no_stats(query) \
+ 	query_int_opr_selec(GETRQUERY(query), NULL, 0, 0)
+ 
+ 
+ /*
+  * Transform intarray &&, @>, <@ operators into correspoinding buildin
+  * operators.
+  */
+ static Oid
+ transformOperator(Oid oprOid)
+ {
+ 	HeapTuple			tup;
+ 	Form_pg_operator	op;
+ 	Oid					result = InvalidOid;
+ 
+ 	tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprOid));
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "Invalid operator: %u", oprOid);
+ 
+ 	op = (Form_pg_operator) GETSTRUCT(tup);
+ 
+ 	if (!strcmp(op->oprname.data, "&&"))
+ 		result = OID_ARRAY_OVERLAP_OP;
+ 	else if (!strcmp(op->oprname.data, "@>"))
+ 		result = OID_ARRAY_CONTAINS_OP;
+ 	else if (!strcmp(op->oprname.data, "<@"))
+ 		result = OID_ARRAY_CONTAINED_OP;
+ 
+ 	ReleaseSysCache(tup);
+ 
+ 	if (!OidIsValid(result))
+ 		elog(ERROR, "Invalid operator: %u", oprOid);
+ 
+ 	return result;
+ }
+ 
+ /*
+  * _int_contsel -- restriction selectivity for array @>, &&, <@ operators
+  */
+ Datum
+ _int_contsel(PG_FUNCTION_ARGS)
+ {
+ 	/*
+ 	 * Reuse builtin selectivity estimation with corresponding operator
+ 	 * replacement.
+ 	 */
+ 	PG_RETURN_DATUM(DirectFunctionCall4(arraycontsel,
+ 			PG_GETARG_DATUM(0),
+ 			ObjectIdGetDatum(transformOperator(PG_GETARG_OID(1))),
+ 			PG_GETARG_DATUM(2),
+ 			PG_GETARG_DATUM(3)));
+ }
+ 
+ /*
+  * _int_contjoinsel -- join selectivity for array @>, &&, <@ operators
+  */
+ Datum
+ _int_contjoinsel(PG_FUNCTION_ARGS)
+ {
+ 	/*
+ 	 * Reuse builtin selectivity estimation with corresponding operator
+ 	 * replacement.
+ 	 */
+ 	PG_RETURN_DATUM(DirectFunctionCall5(arraycontjoinsel,
+ 			PG_GETARG_DATUM(0),
+ 			ObjectIdGetDatum(transformOperator(PG_GETARG_OID(1))),
+ 			PG_GETARG_DATUM(2),
+ 			PG_GETARG_DATUM(3),
+ 			PG_GETARG_DATUM(4)));
+ }
+ 
+ 
+ /*
+  * _int_matchsel -- restriction selectivity function for intarray @@ query_int
+  */
+ Datum
+ _int_matchsel(PG_FUNCTION_ARGS)
+ {
+ 	PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
+ 
+ 	List	   *args = (List *) PG_GETARG_POINTER(2);
+ 	int			varRelid = PG_GETARG_INT32(3);
+ 	VariableStatData vardata;
+ 	Node	   *other;
+ 	bool		varonleft;
+ 	Selectivity selec;
+ 
+ 	/*
+ 	 * If expression is not "variable @@ something" or "something ~~ variable"
+ 	 * then punt and return a default estimate.
+ 	 */
+ 	if (!get_restriction_variable(root, args, varRelid,
+ 								  &vardata, &other, &varonleft))
+ 		PG_RETURN_FLOAT8(DEFAULT_EQ_SEL);
+ 
+ 	/*
+ 	 * Variable should be int[]. We don't support "something @@ variable" and
+ 	 * "variable ~~ something" cases.
+ 	 */
+ 	if (vardata.vartype != INT4ARRAYOID)
+ 		PG_RETURN_FLOAT8(DEFAULT_EQ_SEL);
+ 
+ 	/*
+ 	 * Can't do anything useful if the something is not a constant, either.
+ 	 */
+ 	if (!IsA(other, Const))
+ 	{
+ 		ReleaseVariableStats(vardata);
+ 		PG_RETURN_FLOAT8(DEFAULT_EQ_SEL);
+ 	}
+ 
+ 	/*
+ 	 * The "@@" and "~~" operators are strict, so we can cope with NULL right
+ 	 * away.
+ 	 */
+ 	if (((Const *) other)->constisnull)
+ 	{
+ 		ReleaseVariableStats(vardata);
+ 		PG_RETURN_FLOAT8(0.0);
+ 	}
+ 
+ 	selec = query_intsel(&vardata, ((Const *) other)->constvalue);
+ 
+ 	ReleaseVariableStats(vardata);
+ 
+ 	CLAMP_PROBABILITY(selec);
+ 
+ 	PG_RETURN_FLOAT8((float8) selec);
+ }
+ 
+ /*
+  * Estimate selectivity of "variable @@ const"
+  */
+ static Selectivity
+ query_intsel(VariableStatData *vardata, Datum constval)
+ {
+ 	Selectivity selec;
+ 	QUERYTYPE		*query;
+ 
+ 	/* The caller made sure the const is a query, so get it now */
+ 	query = DatumGetQueryTypeP(constval);
+ 
+ 	/* Empty query matches nothing */
+ 	if (query->size == 0)
+ 		return (Selectivity) 0.0;
+ 
+ 	if (HeapTupleIsValid(vardata->statsTuple))
+ 	{
+ 		Form_pg_statistic stats;
+ 		Datum	   *values;
+ 		int			nvalues;
+ 		float4	   *numbers;
+ 		int			nnumbers;
+ 
+ 		stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple);
+ 
+ 		/* MCELEM will be an array of INT4 elements for a intarray column */
+ 		if (get_attstatsslot(vardata->statsTuple,
+ 							 INT4OID, -1,
+ 							 STATISTIC_KIND_MCELEM, InvalidOid,
+ 							 NULL,
+ 							 &values, &nvalues,
+ 							 &numbers, &nnumbers))
+ 		{
+ 			/*
+ 			 * There is a most-common-elements slot for the intarray Var, so
+ 			 * use that.
+ 			 */
+ 			selec = mcelem_query_int_selec(query, values, nvalues,
+ 										   numbers, nnumbers);
+ 			free_attstatsslot(INT4OID, values, nvalues, numbers, nnumbers);
+ 		}
+ 		else
+ 		{
+ 			/* No most-common-elements info, so do without */
+ 			selec = query_int_opr_selec_no_stats(query);
+ 		}
+ 		/*
+ 		 * MCE stats count only non-null rows, so adjust for null rows.
+ 		 */
+ 		selec *= (1.0 - stats->stanullfrac);
+ 	}
+ 	else
+ 	{
+ 		/* No stats at all, so do without */
+ 		selec = query_int_opr_selec_no_stats(query);
+ 		/* we assume no nulls here, so no stanullfrac correction */
+ 	}
+ 
+ 	return selec;
+ }
+ 
+ /*
+  * Estimate selectivity of single query_int operator
+  */
+ static Selectivity
+ query_int_opr_selec(ITEM *item, Int4Freq *lookup, int length, float4 minfreq)
+ {
+ 	Selectivity selec = 0;
+ 
+ 	/* since this function recurses, it could be driven to stack overflow */
+ 	check_stack_depth();
+ 	if (item->type == VAL)
+ 	{
+ 		Int4Freq   *searchres;
+ 
+ 		if (lookup == NULL)
+ 			return (Selectivity) DEFAULT_EQ_SEL;
+ 
+ 		searchres = (Int4Freq *) bsearch(&item->val, lookup, length,
+ 										 sizeof(Int4Freq),
+ 										 compare_val_int4freq);
+ 
+ 		if (searchres)
+ 		{
+ 			/*
+ 			 * The element is in MCELEM.  Return precise selectivity (or
+ 			 * at least as precise as ANALYZE could find out).
+ 			 */
+ 			selec = searchres->frequency;
+ 		}
+ 		else
+ 		{
+ 			/*
+ 			 * The element is not in MCELEM.  Punt, but assume that the
+ 			 * selectivity cannot be more than minfreq / 2.
+ 			 */
+ 			selec = Min(DEFAULT_EQ_SEL, minfreq / 2);
+ 		}
+ 	}
+ 	else if (item->type == OPR)
+ 	{
+ 		/* Current query node is an operator */
+ 		Selectivity s1,
+ 					s2;
+ 
+ 		switch (item->val)
+ 		{
+ 			case (int32) '!':
+ 				selec = 1.0 - query_int_opr_selec(item - 1,
+ 												lookup, length, minfreq);
+ 				break;
+ 
+ 			case (int32) '&':
+ 				s1 = query_int_opr_selec(item - 1,
+ 									   lookup, length, minfreq);
+ 				s2 = query_int_opr_selec(item + item->left,
+ 									   lookup, length, minfreq);
+ 				selec = s1 * s2;
+ 				break;
+ 
+ 			case (int32) '|':
+ 				s1 = query_int_opr_selec(item - 1,
+ 									   lookup, length, minfreq);
+ 				s2 = query_int_opr_selec(item + item->left,
+ 									   lookup, length, minfreq);
+ 				selec = s1 + s2 - s1 * s2;
+ 				break;
+ 
+ 			default:
+ 				elog(ERROR, "unrecognized operator: %d", item->val);
+ 				selec = 0;		/* keep compiler quiet */
+ 				break;
+ 		}
+ 	}
+ 
+ 	/* Clamp intermediate results to stay sane despite roundoff error */
+ 	CLAMP_PROBABILITY(selec);
+ 
+ 	return selec;
+ }
+ 
+ /*
+  * Extract data from the pg_statistic arrays into useful format.
+  */
+ static Selectivity
+ mcelem_query_int_selec(QUERYTYPE *query, Datum *mcelem, int nmcelem,
+ 					   float4 *numbers, int nnumbers)
+ {
+ 	float4		minfreq;
+ 	Int4Freq   *lookup;
+ 	Selectivity selec;
+ 	int			i;
+ 
+ 	/*
+ 	 * There should be two more Numbers than Values, because the last 3 (for intarray)
+ 	 * cells are taken for minimal, maximal and nulls frequency.  Punt if not.
+ 	 *
+ 	 */
+ 	if (nnumbers < nmcelem + 2)
+ 		return query_int_opr_selec_no_stats(query);
+ 
+ 	/*
+ 	 * Transpose the data into a single array so we can use bsearch().
+ 	 */
+ 	lookup = (Int4Freq *) palloc(sizeof(Int4Freq) * nmcelem);
+ 	for (i = 0; i < nmcelem; i++)
+ 	{
+ 		lookup[i].element = DatumGetInt32(mcelem[i]);
+ 		lookup[i].frequency = numbers[i];
+ 	}
+ 
+ 	/*
+ 	 * Grab the lowest frequency.
+ 	 */
+ 	minfreq = numbers[nnumbers - (nnumbers-nmcelem)];
+ 	selec = query_int_opr_selec(GETRQUERY(query), lookup,
+ 								nmcelem, minfreq);
+ 
+ 	pfree(lookup);
+ 
+ 	return selec;
+ }
+ 
+ /*
+  * Comparison function for binary search in mcelem array.
+  */
+ static int
+ compare_val_int4freq(const void *a, const void *b)
+ {
+ 	int32 key = *(int32 *) a;
+ 	const Int4Freq *t = (const Int4Freq *) b;
+ 	return key - t->element;
+ }
diff --git a/contrib/intarray/intarray--1.0--1.1.sql b/contrib/intarray/intarray--1.0--1.1.sql
new file mode 100644
index ...54987e0
*** a/contrib/intarray/intarray--1.0--1.1.sql
--- b/contrib/intarray/intarray--1.0--1.1.sql
***************
*** 0 ****
--- 1,26 ----
+ /* contrib/intarray/intarray--1.0--1.1.sql */
+ 
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "ALTER EXTENSION intarray UPDATE TO '1.1'" to load this file. \quit
+ 
+ CREATE FUNCTION _int_matchsel(internal, oid, internal, integer)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ ALTER OPERATOR @@ (_int4, query_int) SET (RESTRICT = _int_matchsel);
+ ALTER OPERATOR ~~ (query_int, _int4) SET (RESTRICT = _int_matchsel);
+ 
+ CREATE FUNCTION _int_contsel(internal, oid, internal, integer)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE FUNCTION _int_contjoinsel(internal, oid, internal, smallint, internal)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ ALTER OPERATOR && (_int4, _int4) SET (RESTRICT = _int_contsel, JOIN = _int_contjoinsel);
+ ALTER OPERATOR @> (_int4, _int4) SET (RESTRICT = _int_contsel, JOIN = _int_contjoinsel);
+ ALTER OPERATOR <@ (_int4, _int4) SET (RESTRICT = _int_contsel, JOIN = _int_contjoinsel);
\ No newline at end of file
diff --git a/contrib/intarray/intarray--1.0.sql b/contrib/intarray/intarray--1.0.sql
new file mode .
index 0b89e0f..e69de29
*** a/contrib/intarray/intarray--1.0.sql
--- b/contrib/intarray/intarray--1.0.sql
***************
*** 1,485 ****
- /* contrib/intarray/intarray--1.0.sql */
- 
- -- complain if script is sourced in psql, rather than via CREATE EXTENSION
- \echo Use "CREATE EXTENSION intarray" to load this file. \quit
- 
- --
- -- Create the user-defined type for the 1-D integer arrays (_int4)
- --
- 
- -- Query type
- CREATE FUNCTION bqarr_in(cstring)
- RETURNS query_int
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION bqarr_out(query_int)
- RETURNS cstring
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE TYPE query_int (
- 	INTERNALLENGTH = -1,
- 	INPUT = bqarr_in,
- 	OUTPUT = bqarr_out
- );
- 
- --only for debug
- CREATE FUNCTION querytree(query_int)
- RETURNS text
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- 
- CREATE FUNCTION boolop(_int4, query_int)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION boolop(_int4, query_int) IS 'boolean operation with array';
- 
- CREATE FUNCTION rboolop(query_int, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION rboolop(query_int, _int4) IS 'boolean operation with array';
- 
- CREATE OPERATOR @@ (
- 	LEFTARG = _int4,
- 	RIGHTARG = query_int,
- 	PROCEDURE = boolop,
- 	COMMUTATOR = '~~',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE OPERATOR ~~ (
- 	LEFTARG = query_int,
- 	RIGHTARG = _int4,
- 	PROCEDURE = rboolop,
- 	COMMUTATOR = '@@',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- 
- --
- -- External C-functions for R-tree methods
- --
- 
- -- Comparison methods
- 
- CREATE FUNCTION _int_contains(_int4, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION _int_contains(_int4, _int4) IS 'contains';
- 
- CREATE FUNCTION _int_contained(_int4, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION _int_contained(_int4, _int4) IS 'contained in';
- 
- CREATE FUNCTION _int_overlap(_int4, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION _int_overlap(_int4, _int4) IS 'overlaps';
- 
- CREATE FUNCTION _int_same(_int4, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION _int_same(_int4, _int4) IS 'same as';
- 
- CREATE FUNCTION _int_different(_int4, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION _int_different(_int4, _int4) IS 'different';
- 
- -- support routines for indexing
- 
- CREATE FUNCTION _int_union(_int4, _int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION _int_inter(_int4, _int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- --
- -- OPERATORS
- --
- 
- CREATE OPERATOR && (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = _int_overlap,
- 	COMMUTATOR = '&&',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- --CREATE OPERATOR = (
- --	LEFTARG = _int4,
- --	RIGHTARG = _int4,
- --	PROCEDURE = _int_same,
- --	COMMUTATOR = '=',
- --	NEGATOR = '<>',
- --	RESTRICT = eqsel,
- --	JOIN = eqjoinsel,
- --	SORT1 = '<',
- --	SORT2 = '<'
- --);
- 
- --CREATE OPERATOR <> (
- --	LEFTARG = _int4,
- --	RIGHTARG = _int4,
- --	PROCEDURE = _int_different,
- --	COMMUTATOR = '<>',
- --	NEGATOR = '=',
- --	RESTRICT = neqsel,
- --	JOIN = neqjoinsel
- --);
- 
- CREATE OPERATOR @> (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = _int_contains,
- 	COMMUTATOR = '<@',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE OPERATOR <@ (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = _int_contained,
- 	COMMUTATOR = '@>',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- -- obsolete:
- CREATE OPERATOR @ (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = _int_contains,
- 	COMMUTATOR = '~',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE OPERATOR ~ (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = _int_contained,
- 	COMMUTATOR = '@',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- --------------
- CREATE FUNCTION intset(int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION icount(_int4)
- RETURNS int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR # (
- 	RIGHTARG = _int4,
- 	PROCEDURE = icount
- );
- 
- CREATE FUNCTION sort(_int4, text)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION sort(_int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION sort_asc(_int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION sort_desc(_int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION uniq(_int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION idx(_int4, int4)
- RETURNS int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR # (
- 	LEFTARG = _int4,
- 	RIGHTARG = int4,
- 	PROCEDURE = idx
- );
- 
- CREATE FUNCTION subarray(_int4, int4, int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION subarray(_int4, int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION intarray_push_elem(_int4, int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR + (
- 	LEFTARG = _int4,
- 	RIGHTARG = int4,
- 	PROCEDURE = intarray_push_elem
- );
- 
- CREATE FUNCTION intarray_push_array(_int4, _int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR + (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	COMMUTATOR = +,
- 	PROCEDURE = intarray_push_array
- );
- 
- CREATE FUNCTION intarray_del_elem(_int4, int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR - (
- 	LEFTARG = _int4,
- 	RIGHTARG = int4,
- 	PROCEDURE = intarray_del_elem
- );
- 
- CREATE FUNCTION intset_union_elem(_int4, int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR | (
- 	LEFTARG = _int4,
- 	RIGHTARG = int4,
- 	PROCEDURE = intset_union_elem
- );
- 
- CREATE OPERATOR | (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	COMMUTATOR = |,
- 	PROCEDURE = _int_union
- );
- 
- CREATE FUNCTION intset_subtract(_int4, _int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR - (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = intset_subtract
- );
- 
- CREATE OPERATOR & (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	COMMUTATOR = &,
- 	PROCEDURE = _int_inter
- );
- --------------
- 
- -- define the GiST support methods
- CREATE FUNCTION g_int_consistent(internal,_int4,int,oid,internal)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_compress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_decompress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_penalty(internal,internal,internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_picksplit(internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_union(internal, internal)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_same(_int4, _int4, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- 
- -- Create the operator class for indexing
- 
- CREATE OPERATOR CLASS gist__int_ops
- DEFAULT FOR TYPE _int4 USING gist AS
- 	OPERATOR	3	&&,
- 	OPERATOR	6	= (anyarray, anyarray),
- 	OPERATOR	7	@>,
- 	OPERATOR	8	<@,
- 	OPERATOR	13	@,
- 	OPERATOR	14	~,
- 	OPERATOR	20	@@ (_int4, query_int),
- 	FUNCTION	1	g_int_consistent (internal, _int4, int, oid, internal),
- 	FUNCTION	2	g_int_union (internal, internal),
- 	FUNCTION	3	g_int_compress (internal),
- 	FUNCTION	4	g_int_decompress (internal),
- 	FUNCTION	5	g_int_penalty (internal, internal, internal),
- 	FUNCTION	6	g_int_picksplit (internal, internal),
- 	FUNCTION	7	g_int_same (_int4, _int4, internal);
- 
- 
- ---------------------------------------------
- -- intbig
- ---------------------------------------------
- -- define the GiST support methods
- 
- CREATE FUNCTION _intbig_in(cstring)
- RETURNS intbig_gkey
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION _intbig_out(intbig_gkey)
- RETURNS cstring
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE TYPE intbig_gkey (
-         INTERNALLENGTH = -1,
-         INPUT = _intbig_in,
-         OUTPUT = _intbig_out
- );
- 
- CREATE FUNCTION g_intbig_consistent(internal,internal,int,oid,internal)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_compress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_decompress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_penalty(internal,internal,internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_picksplit(internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_union(internal, internal)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_same(internal, internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- -- register the opclass for indexing (not as default)
- 
- CREATE OPERATOR CLASS gist__intbig_ops
- FOR TYPE _int4 USING gist
- AS
- 	OPERATOR	3	&&,
- 	OPERATOR	6	= (anyarray, anyarray),
- 	OPERATOR	7	@>,
- 	OPERATOR	8	<@,
- 	OPERATOR	13	@,
- 	OPERATOR	14	~,
- 	OPERATOR	20	@@ (_int4, query_int),
- 	FUNCTION	1	g_intbig_consistent (internal, internal, int, oid, internal),
- 	FUNCTION	2	g_intbig_union (internal, internal),
- 	FUNCTION	3	g_intbig_compress (internal),
- 	FUNCTION	4	g_intbig_decompress (internal),
- 	FUNCTION	5	g_intbig_penalty (internal, internal, internal),
- 	FUNCTION	6	g_intbig_picksplit (internal, internal),
- 	FUNCTION	7	g_intbig_same (internal, internal, internal),
- 	STORAGE		intbig_gkey;
- 
- --GIN
- 
- CREATE FUNCTION ginint4_queryextract(internal, internal, int2, internal, internal, internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION ginint4_consistent(internal, int2, internal, int4, internal, internal, internal, internal)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE OPERATOR CLASS gin__int_ops
- FOR TYPE _int4 USING gin
- AS
- 	OPERATOR	3	&&,
- 	OPERATOR	6	= (anyarray, anyarray),
- 	OPERATOR	7	@>,
- 	OPERATOR	8	<@,
- 	OPERATOR	13	@,
- 	OPERATOR	14	~,
- 	OPERATOR	20	@@ (_int4, query_int),
- 	FUNCTION	1	btint4cmp (int4, int4),
- 	FUNCTION	2	ginarrayextract (anyarray, internal, internal),
- 	FUNCTION	3	ginint4_queryextract (internal, internal, int2, internal, internal, internal, internal),
- 	FUNCTION	4	ginint4_consistent (internal, int2, internal, int4, internal, internal, internal, internal),
- 	STORAGE		int4;
--- 0 ----
diff --git a/contrib/intarray/intarray--1.1.sql b/contrib/intarray/intarray--1.1.sql
new file mode 100644
index ...18e9ec8
*** a/contrib/intarray/intarray--1.1.sql
--- b/contrib/intarray/intarray--1.1.sql
***************
*** 0 ****
--- 1,500 ----
+ /* contrib/intarray/intarray--1.1.sql */
+ 
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "CREATE EXTENSION intarray" to load this file. \quit
+ 
+ --
+ -- Create the user-defined type for the 1-D integer arrays (_int4)
+ --
+ 
+ -- Query type
+ CREATE FUNCTION bqarr_in(cstring)
+ RETURNS query_int
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION bqarr_out(query_int)
+ RETURNS cstring
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE TYPE query_int (
+ 	INTERNALLENGTH = -1,
+ 	INPUT = bqarr_in,
+ 	OUTPUT = bqarr_out
+ );
+ 
+ --only for debug
+ CREATE FUNCTION querytree(query_int)
+ RETURNS text
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ 
+ CREATE FUNCTION boolop(_int4, query_int)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION boolop(_int4, query_int) IS 'boolean operation with array';
+ 
+ CREATE FUNCTION rboolop(query_int, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION rboolop(query_int, _int4) IS 'boolean operation with array';
+ 
+ CREATE FUNCTION _int_matchsel(internal, oid, internal, integer)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE OPERATOR @@ (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = query_int,
+ 	PROCEDURE = boolop,
+ 	COMMUTATOR = '~~',
+ 	RESTRICT = _int_matchsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ CREATE OPERATOR ~~ (
+ 	LEFTARG = query_int,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = rboolop,
+ 	COMMUTATOR = '@@',
+ 	RESTRICT = _int_matchsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ 
+ --
+ -- External C-functions for R-tree methods
+ --
+ 
+ -- Comparison methods
+ 
+ CREATE FUNCTION _int_contains(_int4, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION _int_contains(_int4, _int4) IS 'contains';
+ 
+ CREATE FUNCTION _int_contained(_int4, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION _int_contained(_int4, _int4) IS 'contained in';
+ 
+ CREATE FUNCTION _int_overlap(_int4, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION _int_overlap(_int4, _int4) IS 'overlaps';
+ 
+ CREATE FUNCTION _int_same(_int4, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION _int_same(_int4, _int4) IS 'same as';
+ 
+ CREATE FUNCTION _int_different(_int4, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION _int_different(_int4, _int4) IS 'different';
+ 
+ -- support routines for indexing
+ 
+ CREATE FUNCTION _int_union(_int4, _int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION _int_inter(_int4, _int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION _int_contsel(internal, oid, internal, integer)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE FUNCTION _int_contjoinsel(internal, oid, internal, smallint, internal)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ --
+ -- OPERATORS
+ --
+ 
+ CREATE OPERATOR && (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = _int_overlap,
+ 	COMMUTATOR = '&&',
+ 	RESTRICT = _int_contsel,
+ 	JOIN = _int_contjoinsel
+ );
+ 
+ --CREATE OPERATOR = (
+ --	LEFTARG = _int4,
+ --	RIGHTARG = _int4,
+ --	PROCEDURE = _int_same,
+ --	COMMUTATOR = '=',
+ --	NEGATOR = '<>',
+ --	RESTRICT = eqsel,
+ --	JOIN = eqjoinsel,
+ --	SORT1 = '<',
+ --	SORT2 = '<'
+ --);
+ 
+ --CREATE OPERATOR <> (
+ --	LEFTARG = _int4,
+ --	RIGHTARG = _int4,
+ --	PROCEDURE = _int_different,
+ --	COMMUTATOR = '<>',
+ --	NEGATOR = '=',
+ --	RESTRICT = neqsel,
+ --	JOIN = neqjoinsel
+ --);
+ 
+ CREATE OPERATOR @> (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = _int_contains,
+ 	COMMUTATOR = '<@',
+ 	RESTRICT = _int_contsel,
+ 	JOIN = _int_contjoinsel
+ );
+ 
+ CREATE OPERATOR <@ (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = _int_contained,
+ 	COMMUTATOR = '@>',
+ 	RESTRICT = _int_contsel,
+ 	JOIN = _int_contjoinsel
+ );
+ 
+ -- obsolete:
+ CREATE OPERATOR @ (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = _int_contains,
+ 	COMMUTATOR = '~',
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ CREATE OPERATOR ~ (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = _int_contained,
+ 	COMMUTATOR = '@',
+ 	RESTRICT = contsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ --------------
+ CREATE FUNCTION intset(int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION icount(_int4)
+ RETURNS int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR # (
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = icount
+ );
+ 
+ CREATE FUNCTION sort(_int4, text)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION sort(_int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION sort_asc(_int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION sort_desc(_int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION uniq(_int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION idx(_int4, int4)
+ RETURNS int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR # (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = int4,
+ 	PROCEDURE = idx
+ );
+ 
+ CREATE FUNCTION subarray(_int4, int4, int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION subarray(_int4, int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION intarray_push_elem(_int4, int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR + (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = int4,
+ 	PROCEDURE = intarray_push_elem
+ );
+ 
+ CREATE FUNCTION intarray_push_array(_int4, _int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR + (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	COMMUTATOR = +,
+ 	PROCEDURE = intarray_push_array
+ );
+ 
+ CREATE FUNCTION intarray_del_elem(_int4, int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR - (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = int4,
+ 	PROCEDURE = intarray_del_elem
+ );
+ 
+ CREATE FUNCTION intset_union_elem(_int4, int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR | (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = int4,
+ 	PROCEDURE = intset_union_elem
+ );
+ 
+ CREATE OPERATOR | (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	COMMUTATOR = |,
+ 	PROCEDURE = _int_union
+ );
+ 
+ CREATE FUNCTION intset_subtract(_int4, _int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR - (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = intset_subtract
+ );
+ 
+ CREATE OPERATOR & (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	COMMUTATOR = &,
+ 	PROCEDURE = _int_inter
+ );
+ --------------
+ 
+ -- define the GiST support methods
+ CREATE FUNCTION g_int_consistent(internal,_int4,int,oid,internal)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_compress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_decompress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_penalty(internal,internal,internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_picksplit(internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_union(internal, internal)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_same(_int4, _int4, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ 
+ -- Create the operator class for indexing
+ 
+ CREATE OPERATOR CLASS gist__int_ops
+ DEFAULT FOR TYPE _int4 USING gist AS
+ 	OPERATOR	3	&&,
+ 	OPERATOR	6	= (anyarray, anyarray),
+ 	OPERATOR	7	@>,
+ 	OPERATOR	8	<@,
+ 	OPERATOR	13	@,
+ 	OPERATOR	14	~,
+ 	OPERATOR	20	@@ (_int4, query_int),
+ 	FUNCTION	1	g_int_consistent (internal, _int4, int, oid, internal),
+ 	FUNCTION	2	g_int_union (internal, internal),
+ 	FUNCTION	3	g_int_compress (internal),
+ 	FUNCTION	4	g_int_decompress (internal),
+ 	FUNCTION	5	g_int_penalty (internal, internal, internal),
+ 	FUNCTION	6	g_int_picksplit (internal, internal),
+ 	FUNCTION	7	g_int_same (_int4, _int4, internal);
+ 
+ 
+ ---------------------------------------------
+ -- intbig
+ ---------------------------------------------
+ -- define the GiST support methods
+ 
+ CREATE FUNCTION _intbig_in(cstring)
+ RETURNS intbig_gkey
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION _intbig_out(intbig_gkey)
+ RETURNS cstring
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE TYPE intbig_gkey (
+         INTERNALLENGTH = -1,
+         INPUT = _intbig_in,
+         OUTPUT = _intbig_out
+ );
+ 
+ CREATE FUNCTION g_intbig_consistent(internal,internal,int,oid,internal)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_compress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_decompress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_penalty(internal,internal,internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_picksplit(internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_union(internal, internal)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_same(internal, internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ -- register the opclass for indexing (not as default)
+ 
+ CREATE OPERATOR CLASS gist__intbig_ops
+ FOR TYPE _int4 USING gist
+ AS
+ 	OPERATOR	3	&&,
+ 	OPERATOR	6	= (anyarray, anyarray),
+ 	OPERATOR	7	@>,
+ 	OPERATOR	8	<@,
+ 	OPERATOR	13	@,
+ 	OPERATOR	14	~,
+ 	OPERATOR	20	@@ (_int4, query_int),
+ 	FUNCTION	1	g_intbig_consistent (internal, internal, int, oid, internal),
+ 	FUNCTION	2	g_intbig_union (internal, internal),
+ 	FUNCTION	3	g_intbig_compress (internal),
+ 	FUNCTION	4	g_intbig_decompress (internal),
+ 	FUNCTION	5	g_intbig_penalty (internal, internal, internal),
+ 	FUNCTION	6	g_intbig_picksplit (internal, internal),
+ 	FUNCTION	7	g_intbig_same (internal, internal, internal),
+ 	STORAGE		intbig_gkey;
+ 
+ --GIN
+ 
+ CREATE FUNCTION ginint4_queryextract(internal, internal, int2, internal, internal, internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION ginint4_consistent(internal, int2, internal, int4, internal, internal, internal, internal)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE OPERATOR CLASS gin__int_ops
+ FOR TYPE _int4 USING gin
+ AS
+ 	OPERATOR	3	&&,
+ 	OPERATOR	6	= (anyarray, anyarray),
+ 	OPERATOR	7	@>,
+ 	OPERATOR	8	<@,
+ 	OPERATOR	13	@,
+ 	OPERATOR	14	~,
+ 	OPERATOR	20	@@ (_int4, query_int),
+ 	FUNCTION	1	btint4cmp (int4, int4),
+ 	FUNCTION	2	ginarrayextract (anyarray, internal, internal),
+ 	FUNCTION	3	ginint4_queryextract (internal, internal, int2, internal, internal, internal, internal),
+ 	FUNCTION	4	ginint4_consistent (internal, int2, internal, int4, internal, internal, internal, internal),
+ 	STORAGE		int4;
diff --git a/contrib/intarray/intarray.control b/contrib/intarray/intarray.control
new file mode 100644
index 7b3d4f7..8c23e8d
*** a/contrib/intarray/intarray.control
--- b/contrib/intarray/intarray.control
***************
*** 1,5 ****
  # intarray extension
  comment = 'functions, operators, and index support for 1-D arrays of integers'
! default_version = '1.0'
  module_pathname = '$libdir/_int'
  relocatable = true
--- 1,5 ----
  # intarray extension
  comment = 'functions, operators, and index support for 1-D arrays of integers'
! default_version = '1.1'
  module_pathname = '$libdir/_int'
  relocatable = true
#6Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Alexander Korotkov (#3)
1 attachment(s)
Re: Selectivity estimation for intarray with @@

On 07/21/2015 03:44 PM, Alexander Korotkov wrote:

While Uriy is on vacation, I've revised this patch a bit.

I whacked this around quite a bit, and I think it's in a committable
state now. But if you could run whatever tests you were using before on
this, to make sure it still produces the same estimates, that would be
great. I didn't change the estimates it should produce, only the code
structure.

One thing that bothers me slightly with this patch is the way it peeks
into the Most-Common-Elements arrays, which is produced by the built-in
type analyze function. If we ever change what statistics are collected
for arrays, or the way they are stored, this might break. In matchsel,
why don't we just call the built-in estimator function for each element
that we need to probe, and not look into the statistics ourselves at
all? I actually experimented with that, and it did slash much of the
code, and it would be more future-proof. However, it was also a lot
slower for queries that contain multiple values. That's understandable:
the built-in estimator will fetch the statistics tuple, parse the
arrays, etc. separately for each value in the query_int, while this
patch will do it only once for the whole query, and perform a simple
binary search for each value. So overall, I think this is OK as it is.
But if we find that we need to use the MCE list in this fashion in more
places in the future, it might be worthwhile to add some support code
for this in the backend to allow extracting the stats once, and doing
multiple "lightweight estimations" using the extracted stats.

Some things I fixed/changed:

* I didn't like that transformOperator() function, which looked up the
function's name. I replaced it with separate wrapper functions for each
operator, so that the built-in operator's OID can be hardcoded into each.

* I refactored the matchsel function heavily. I think it's more readable
now.

* I got rid of the Int4Freq array. It didn't seem significantly easier
to work with than the separate values/numbers arrays, so I just used
those directly.

* Also use the matchsel estimator for ~~ (the commutator of @@)

* Also use the estimators for the obsolete @ and ~ operators. Not that I
care much about those as they are obsolete, but seems strange not to, as
it's a trivial matter of setting the right estimator function.

* I added an ANALYZE in the regression test. It still won't
systematically test all the cost estimation code, and there's nothing to
check that the estimates make sense, but at least more of the code will
now run.

- Heikki

Attachments:

intarray-sel-3-heikki.patchapplication/x-patch; name=intarray-sel-3-heikki.patchDownload
diff --git a/contrib/intarray/Makefile b/contrib/intarray/Makefile
index 920c5b1..5ea7f2a 100644
--- a/contrib/intarray/Makefile
+++ b/contrib/intarray/Makefile
@@ -2,10 +2,10 @@
 
 MODULE_big = _int
 OBJS = _int_bool.o _int_gist.o _int_op.o _int_tool.o \
-	_intbig_gist.o _int_gin.o $(WIN32RES)
+	_intbig_gist.o _int_gin.o _int_selfuncs.o $(WIN32RES)
 
 EXTENSION = intarray
-DATA = intarray--1.0.sql intarray--unpackaged--1.0.sql
+DATA = intarray--1.1.sql intarray--1.0--1.1.sql intarray--unpackaged--1.0.sql
 PGFILEDESC = "intarray - functions and operators for arrays of integers"
 
 REGRESS = _int
diff --git a/contrib/intarray/_int_selfuncs.c b/contrib/intarray/_int_selfuncs.c
new file mode 100644
index 0000000..4896461
--- /dev/null
+++ b/contrib/intarray/_int_selfuncs.c
@@ -0,0 +1,334 @@
+/*-------------------------------------------------------------------------
+ *
+ * _int_selfuncs.c
+ *	  Functions for selectivity estimation of intarray operators
+ *
+ * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  contrib/intarray/_int_selfuncs.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+#include "_int.h"
+
+#include "access/htup_details.h"
+#include "catalog/pg_operator.h"
+#include "catalog/pg_statistic.h"
+#include "catalog/pg_type.h"
+#include "utils/selfuncs.h"
+#include "utils/syscache.h"
+#include "utils/lsyscache.h"
+#include "miscadmin.h"
+
+PG_FUNCTION_INFO_V1(_int_overlap_sel);
+PG_FUNCTION_INFO_V1(_int_contains_sel);
+PG_FUNCTION_INFO_V1(_int_contained_sel);
+PG_FUNCTION_INFO_V1(_int_overlap_joinsel);
+PG_FUNCTION_INFO_V1(_int_contains_joinsel);
+PG_FUNCTION_INFO_V1(_int_contained_joinsel);
+PG_FUNCTION_INFO_V1(_int_matchsel);
+
+Datum		_int_overlap_sel(PG_FUNCTION_ARGS);
+Datum		_int_contains_sel(PG_FUNCTION_ARGS);
+Datum		_int_contained_sel(PG_FUNCTION_ARGS);
+Datum		_int_overlap_joinsel(PG_FUNCTION_ARGS);
+Datum		_int_contains_joinsel(PG_FUNCTION_ARGS);
+Datum		_int_contained_joinsel(PG_FUNCTION_ARGS);
+Datum		_int_matchsel(PG_FUNCTION_ARGS);
+
+
+static Selectivity int_query_opr_selec(ITEM *item, Datum *values, float4 *freqs,
+					int nmncelems, float4 minfreq);
+static int	compare_val_int4(const void *a, const void *b);
+
+/*
+ * Wrappers around the default array selectivity estimation functions.
+ *
+ * The default array selectivity operators for the @>, && and @< operators
+ * work fine for integer arrays. However, if we tried to just use arraycontsel
+ * and arracontjoinsel directly as the cost estimator functions for our
+ * operators, they would not work as intended, because they look at the
+ * operator's OID. Our operators behave exactly like the built-in anyarray
+ * versions, but we must tell the cost estimator functions which built-in
+ * operators they correspond to. These wrappers just replace the operator
+ * OID with the corresponding built-in operator's OID, and call the built-in
+ * function.
+ */
+
+Datum
+_int_overlap_sel(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_DATUM(DirectFunctionCall4(arraycontsel,
+										PG_GETARG_DATUM(0),
+										ObjectIdGetDatum(OID_ARRAY_OVERLAP_OP),
+										PG_GETARG_DATUM(2),
+										PG_GETARG_DATUM(3)));
+}
+
+Datum
+_int_contains_sel(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_DATUM(DirectFunctionCall4(arraycontsel,
+										PG_GETARG_DATUM(0),
+										ObjectIdGetDatum(OID_ARRAY_CONTAINS_OP),
+										PG_GETARG_DATUM(2),
+										PG_GETARG_DATUM(3)));
+}
+
+Datum
+_int_contained_sel(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_DATUM(DirectFunctionCall4(arraycontsel,
+										PG_GETARG_DATUM(0),
+										ObjectIdGetDatum(OID_ARRAY_CONTAINED_OP),
+										PG_GETARG_DATUM(2),
+										PG_GETARG_DATUM(3)));
+}
+
+Datum
+_int_overlap_joinsel(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_DATUM(DirectFunctionCall5(arraycontjoinsel,
+										PG_GETARG_DATUM(0),
+										ObjectIdGetDatum(OID_ARRAY_OVERLAP_OP),
+										PG_GETARG_DATUM(2),
+										PG_GETARG_DATUM(3),
+										PG_GETARG_DATUM(4)));
+}
+
+Datum
+_int_contains_joinsel(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_DATUM(DirectFunctionCall5(arraycontjoinsel,
+										PG_GETARG_DATUM(0),
+										ObjectIdGetDatum(OID_ARRAY_CONTAINS_OP),
+										PG_GETARG_DATUM(2),
+										PG_GETARG_DATUM(3),
+										PG_GETARG_DATUM(4)));
+}
+
+Datum
+_int_contained_joinsel(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_DATUM(DirectFunctionCall5(arraycontjoinsel,
+										PG_GETARG_DATUM(0),
+										ObjectIdGetDatum(OID_ARRAY_CONTAINED_OP),
+										PG_GETARG_DATUM(2),
+										PG_GETARG_DATUM(3),
+										PG_GETARG_DATUM(4)));
+}
+
+
+/*
+ * _int_matchsel -- restriction selectivity function for intarray @@ query_int
+ */
+Datum
+_int_matchsel(PG_FUNCTION_ARGS)
+{
+	PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
+
+	List	   *args = (List *) PG_GETARG_POINTER(2);
+	int			varRelid = PG_GETARG_INT32(3);
+	VariableStatData vardata;
+	Node	   *other;
+	bool		varonleft;
+	Selectivity selec;
+	QUERYTYPE  *query;
+	Datum	   *mcelems = NULL;
+	float4	   *mcefreqs = NULL;
+	int			nmcelems = 0;
+	float4		minfreq = 0.0;
+	float4		nullfrac = 0.0;
+	Form_pg_statistic stats;
+	Datum	   *values = NULL;
+	int			nvalues = 0;
+	float4	   *numbers = NULL;
+	int			nnumbers = 0;
+
+	/*
+	 * If expression is not "variable @@ something" or "something @@ variable"
+	 * then punt and return a default estimate.
+	 */
+	if (!get_restriction_variable(root, args, varRelid,
+								  &vardata, &other, &varonleft))
+		PG_RETURN_FLOAT8(DEFAULT_EQ_SEL);
+
+	/*
+	 * Can't do anything useful if the something is not a constant, either.
+	 */
+	if (!IsA(other, Const))
+	{
+		ReleaseVariableStats(vardata);
+		PG_RETURN_FLOAT8(DEFAULT_EQ_SEL);
+	}
+
+	/*
+	 * The "@@" operator is strict, so we can cope with NULL right away.
+	 */
+	if (((Const *) other)->constisnull)
+	{
+		ReleaseVariableStats(vardata);
+		PG_RETURN_FLOAT8(0.0);
+	}
+
+	/* The caller made sure the const is a query, so get it now */
+	query = DatumGetQueryTypeP(((Const *) other)->constvalue);
+
+	/* Empty query matches nothing */
+	if (query->size == 0)
+	{
+		ReleaseVariableStats(vardata);
+		return (Selectivity) 0.0;
+	}
+
+	/*
+	 * Get the statistics for the intarray column.
+	 *
+	 * We're interested in the Most-Common-Elements list, and the NULL
+	 * fraction.
+	 */
+	if (HeapTupleIsValid(vardata.statsTuple))
+	{
+		stats = (Form_pg_statistic) GETSTRUCT(vardata.statsTuple);
+		nullfrac = stats->stanullfrac;
+
+		/*
+		 * For an int4 array, the default array type analyze function will
+		 * collect a Most Common Elements list, which is an array of int4s.
+		 */
+		if (get_attstatsslot(vardata.statsTuple,
+							 INT4OID, -1,
+							 STATISTIC_KIND_MCELEM, InvalidOid,
+							 NULL,
+							 &values, &nvalues,
+							 &numbers, &nnumbers))
+		{
+			/*
+			 * There should be three more Numbers than Values, because the last
+			 * three (for intarray) cells are taken for minimal, maximal and nulls
+			 * frequency. Punt if not.
+			 */
+			if (nnumbers == nvalues + 3)
+			{
+				/* Grab the lowest frequency. */
+				minfreq = numbers[nnumbers - (nnumbers - nvalues)];
+
+				mcelems = values;
+				mcefreqs = numbers;
+				nmcelems = nvalues;
+			}
+		}
+	}
+
+	/* Process the logical expression in the query, using the stats */
+	selec = int_query_opr_selec(GETQUERY(query) + query->size - 1,
+								mcelems, mcefreqs, nmcelems, minfreq);
+
+	/* MCE stats count only non-null rows, so adjust for null rows. */
+	selec *= (1.0 - nullfrac);
+
+	free_attstatsslot(INT4OID, values, nvalues, numbers, nnumbers);
+	ReleaseVariableStats(vardata);
+
+	CLAMP_PROBABILITY(selec);
+
+	PG_RETURN_FLOAT8((float8) selec);
+}
+
+/*
+ * Estimate selectivity of single intquery operator
+ */
+static Selectivity
+int_query_opr_selec(ITEM *item, Datum *mcelems, float4 *mcefreqs,
+					int nmcelems, float4 minfreq)
+{
+	Selectivity selec;
+
+	/* since this function recurses, it could be driven to stack overflow */
+	check_stack_depth();
+
+	if (item->type == VAL)
+	{
+		Datum	   *searchres;
+
+		if (mcelems == NULL)
+			return (Selectivity) DEFAULT_EQ_SEL;
+
+		searchres = (Datum *) bsearch(&item->val, mcelems, nmcelems,
+									  sizeof(Datum), compare_val_int4);
+		if (searchres)
+		{
+			/*
+			 * The element is in MCELEM.  Return precise selectivity (or at
+			 * least as precise as ANALYZE could find out).
+			 */
+			selec = mcefreqs[searchres - mcelems];
+		}
+		else
+		{
+			/*
+			 * The element is not in MCELEM.  Punt, but assume that the
+			 * selectivity cannot be more than minfreq / 2.
+			 */
+			selec = Min(DEFAULT_EQ_SEL, minfreq / 2);
+		}
+	}
+	else if (item->type == OPR)
+	{
+		/* Current query node is an operator */
+		Selectivity s1,
+					s2;
+
+		s1 = int_query_opr_selec(item - 1, mcelems, mcefreqs, nmcelems,
+								 minfreq);
+		switch (item->val)
+		{
+			case (int32) '!':
+				selec = 1.0 - s1;
+				break;
+
+			case (int32) '&':
+				s2 = int_query_opr_selec(item + item->left, mcelems, mcefreqs,
+										 nmcelems, minfreq);
+				selec = s1 * s2;
+				break;
+
+			case (int32) '|':
+				s2 = int_query_opr_selec(item + item->left, mcelems, mcefreqs,
+										 nmcelems, minfreq);
+				selec = s1 + s2 - s1 * s2;
+				break;
+
+			default:
+				elog(ERROR, "unrecognized operator: %d", item->val);
+				selec = 0;		/* keep compiler quiet */
+				break;
+		}
+	}
+	else
+	{
+		elog(ERROR, "unrecognized int query item type: %u", item->type);
+		selec = 0;				/* keep compiler quiet */
+	}
+
+	/* Clamp intermediate results to stay sane despite roundoff error */
+	CLAMP_PROBABILITY(selec);
+
+	return selec;
+}
+
+/*
+ * Comparison function for binary search in mcelem array.
+ */
+static int
+compare_val_int4(const void *a, const void *b)
+{
+	int32		key = *(int32 *) a;
+	const Datum *t = (const Datum *) b;
+
+	return key - DatumGetInt32(*t);
+}
diff --git a/contrib/intarray/expected/_int.out b/contrib/intarray/expected/_int.out
index 4080b96..962e5c6 100644
--- a/contrib/intarray/expected/_int.out
+++ b/contrib/intarray/expected/_int.out
@@ -368,6 +368,7 @@ SELECT '1&(2&(4&(5|!6)))'::query_int;
 
 CREATE TABLE test__int( a int[] );
 \copy test__int from 'data/test__int.data'
+ANALYZE test__int;
 SELECT count(*) from test__int WHERE a && '{23,50}';
  count 
 -------
diff --git a/contrib/intarray/intarray--1.0.sql b/contrib/intarray/intarray--1.0.sql
deleted file mode 100644
index 0b89e0f..0000000
--- a/contrib/intarray/intarray--1.0.sql
+++ /dev/null
@@ -1,485 +0,0 @@
-/* contrib/intarray/intarray--1.0.sql */
-
--- complain if script is sourced in psql, rather than via CREATE EXTENSION
-\echo Use "CREATE EXTENSION intarray" to load this file. \quit
-
---
--- Create the user-defined type for the 1-D integer arrays (_int4)
---
-
--- Query type
-CREATE FUNCTION bqarr_in(cstring)
-RETURNS query_int
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE FUNCTION bqarr_out(query_int)
-RETURNS cstring
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE TYPE query_int (
-	INTERNALLENGTH = -1,
-	INPUT = bqarr_in,
-	OUTPUT = bqarr_out
-);
-
---only for debug
-CREATE FUNCTION querytree(query_int)
-RETURNS text
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-
-CREATE FUNCTION boolop(_int4, query_int)
-RETURNS bool
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-COMMENT ON FUNCTION boolop(_int4, query_int) IS 'boolean operation with array';
-
-CREATE FUNCTION rboolop(query_int, _int4)
-RETURNS bool
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-COMMENT ON FUNCTION rboolop(query_int, _int4) IS 'boolean operation with array';
-
-CREATE OPERATOR @@ (
-	LEFTARG = _int4,
-	RIGHTARG = query_int,
-	PROCEDURE = boolop,
-	COMMUTATOR = '~~',
-	RESTRICT = contsel,
-	JOIN = contjoinsel
-);
-
-CREATE OPERATOR ~~ (
-	LEFTARG = query_int,
-	RIGHTARG = _int4,
-	PROCEDURE = rboolop,
-	COMMUTATOR = '@@',
-	RESTRICT = contsel,
-	JOIN = contjoinsel
-);
-
-
---
--- External C-functions for R-tree methods
---
-
--- Comparison methods
-
-CREATE FUNCTION _int_contains(_int4, _int4)
-RETURNS bool
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-COMMENT ON FUNCTION _int_contains(_int4, _int4) IS 'contains';
-
-CREATE FUNCTION _int_contained(_int4, _int4)
-RETURNS bool
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-COMMENT ON FUNCTION _int_contained(_int4, _int4) IS 'contained in';
-
-CREATE FUNCTION _int_overlap(_int4, _int4)
-RETURNS bool
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-COMMENT ON FUNCTION _int_overlap(_int4, _int4) IS 'overlaps';
-
-CREATE FUNCTION _int_same(_int4, _int4)
-RETURNS bool
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-COMMENT ON FUNCTION _int_same(_int4, _int4) IS 'same as';
-
-CREATE FUNCTION _int_different(_int4, _int4)
-RETURNS bool
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-COMMENT ON FUNCTION _int_different(_int4, _int4) IS 'different';
-
--- support routines for indexing
-
-CREATE FUNCTION _int_union(_int4, _int4)
-RETURNS _int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE FUNCTION _int_inter(_int4, _int4)
-RETURNS _int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
---
--- OPERATORS
---
-
-CREATE OPERATOR && (
-	LEFTARG = _int4,
-	RIGHTARG = _int4,
-	PROCEDURE = _int_overlap,
-	COMMUTATOR = '&&',
-	RESTRICT = contsel,
-	JOIN = contjoinsel
-);
-
---CREATE OPERATOR = (
---	LEFTARG = _int4,
---	RIGHTARG = _int4,
---	PROCEDURE = _int_same,
---	COMMUTATOR = '=',
---	NEGATOR = '<>',
---	RESTRICT = eqsel,
---	JOIN = eqjoinsel,
---	SORT1 = '<',
---	SORT2 = '<'
---);
-
---CREATE OPERATOR <> (
---	LEFTARG = _int4,
---	RIGHTARG = _int4,
---	PROCEDURE = _int_different,
---	COMMUTATOR = '<>',
---	NEGATOR = '=',
---	RESTRICT = neqsel,
---	JOIN = neqjoinsel
---);
-
-CREATE OPERATOR @> (
-	LEFTARG = _int4,
-	RIGHTARG = _int4,
-	PROCEDURE = _int_contains,
-	COMMUTATOR = '<@',
-	RESTRICT = contsel,
-	JOIN = contjoinsel
-);
-
-CREATE OPERATOR <@ (
-	LEFTARG = _int4,
-	RIGHTARG = _int4,
-	PROCEDURE = _int_contained,
-	COMMUTATOR = '@>',
-	RESTRICT = contsel,
-	JOIN = contjoinsel
-);
-
--- obsolete:
-CREATE OPERATOR @ (
-	LEFTARG = _int4,
-	RIGHTARG = _int4,
-	PROCEDURE = _int_contains,
-	COMMUTATOR = '~',
-	RESTRICT = contsel,
-	JOIN = contjoinsel
-);
-
-CREATE OPERATOR ~ (
-	LEFTARG = _int4,
-	RIGHTARG = _int4,
-	PROCEDURE = _int_contained,
-	COMMUTATOR = '@',
-	RESTRICT = contsel,
-	JOIN = contjoinsel
-);
-
---------------
-CREATE FUNCTION intset(int4)
-RETURNS _int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE FUNCTION icount(_int4)
-RETURNS int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OPERATOR # (
-	RIGHTARG = _int4,
-	PROCEDURE = icount
-);
-
-CREATE FUNCTION sort(_int4, text)
-RETURNS _int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE FUNCTION sort(_int4)
-RETURNS _int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE FUNCTION sort_asc(_int4)
-RETURNS _int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE FUNCTION sort_desc(_int4)
-RETURNS _int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE FUNCTION uniq(_int4)
-RETURNS _int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE FUNCTION idx(_int4, int4)
-RETURNS int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OPERATOR # (
-	LEFTARG = _int4,
-	RIGHTARG = int4,
-	PROCEDURE = idx
-);
-
-CREATE FUNCTION subarray(_int4, int4, int4)
-RETURNS _int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE FUNCTION subarray(_int4, int4)
-RETURNS _int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE FUNCTION intarray_push_elem(_int4, int4)
-RETURNS _int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OPERATOR + (
-	LEFTARG = _int4,
-	RIGHTARG = int4,
-	PROCEDURE = intarray_push_elem
-);
-
-CREATE FUNCTION intarray_push_array(_int4, _int4)
-RETURNS _int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OPERATOR + (
-	LEFTARG = _int4,
-	RIGHTARG = _int4,
-	COMMUTATOR = +,
-	PROCEDURE = intarray_push_array
-);
-
-CREATE FUNCTION intarray_del_elem(_int4, int4)
-RETURNS _int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OPERATOR - (
-	LEFTARG = _int4,
-	RIGHTARG = int4,
-	PROCEDURE = intarray_del_elem
-);
-
-CREATE FUNCTION intset_union_elem(_int4, int4)
-RETURNS _int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OPERATOR | (
-	LEFTARG = _int4,
-	RIGHTARG = int4,
-	PROCEDURE = intset_union_elem
-);
-
-CREATE OPERATOR | (
-	LEFTARG = _int4,
-	RIGHTARG = _int4,
-	COMMUTATOR = |,
-	PROCEDURE = _int_union
-);
-
-CREATE FUNCTION intset_subtract(_int4, _int4)
-RETURNS _int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OPERATOR - (
-	LEFTARG = _int4,
-	RIGHTARG = _int4,
-	PROCEDURE = intset_subtract
-);
-
-CREATE OPERATOR & (
-	LEFTARG = _int4,
-	RIGHTARG = _int4,
-	COMMUTATOR = &,
-	PROCEDURE = _int_inter
-);
---------------
-
--- define the GiST support methods
-CREATE FUNCTION g_int_consistent(internal,_int4,int,oid,internal)
-RETURNS bool
-AS 'MODULE_PATHNAME'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION g_int_compress(internal)
-RETURNS internal
-AS 'MODULE_PATHNAME'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION g_int_decompress(internal)
-RETURNS internal
-AS 'MODULE_PATHNAME'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION g_int_penalty(internal,internal,internal)
-RETURNS internal
-AS 'MODULE_PATHNAME'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION g_int_picksplit(internal, internal)
-RETURNS internal
-AS 'MODULE_PATHNAME'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION g_int_union(internal, internal)
-RETURNS _int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION g_int_same(_int4, _int4, internal)
-RETURNS internal
-AS 'MODULE_PATHNAME'
-LANGUAGE C IMMUTABLE STRICT;
-
-
--- Create the operator class for indexing
-
-CREATE OPERATOR CLASS gist__int_ops
-DEFAULT FOR TYPE _int4 USING gist AS
-	OPERATOR	3	&&,
-	OPERATOR	6	= (anyarray, anyarray),
-	OPERATOR	7	@>,
-	OPERATOR	8	<@,
-	OPERATOR	13	@,
-	OPERATOR	14	~,
-	OPERATOR	20	@@ (_int4, query_int),
-	FUNCTION	1	g_int_consistent (internal, _int4, int, oid, internal),
-	FUNCTION	2	g_int_union (internal, internal),
-	FUNCTION	3	g_int_compress (internal),
-	FUNCTION	4	g_int_decompress (internal),
-	FUNCTION	5	g_int_penalty (internal, internal, internal),
-	FUNCTION	6	g_int_picksplit (internal, internal),
-	FUNCTION	7	g_int_same (_int4, _int4, internal);
-
-
----------------------------------------------
--- intbig
----------------------------------------------
--- define the GiST support methods
-
-CREATE FUNCTION _intbig_in(cstring)
-RETURNS intbig_gkey
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE FUNCTION _intbig_out(intbig_gkey)
-RETURNS cstring
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE TYPE intbig_gkey (
-        INTERNALLENGTH = -1,
-        INPUT = _intbig_in,
-        OUTPUT = _intbig_out
-);
-
-CREATE FUNCTION g_intbig_consistent(internal,internal,int,oid,internal)
-RETURNS bool
-AS 'MODULE_PATHNAME'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION g_intbig_compress(internal)
-RETURNS internal
-AS 'MODULE_PATHNAME'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION g_intbig_decompress(internal)
-RETURNS internal
-AS 'MODULE_PATHNAME'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION g_intbig_penalty(internal,internal,internal)
-RETURNS internal
-AS 'MODULE_PATHNAME'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION g_intbig_picksplit(internal, internal)
-RETURNS internal
-AS 'MODULE_PATHNAME'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION g_intbig_union(internal, internal)
-RETURNS _int4
-AS 'MODULE_PATHNAME'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION g_intbig_same(internal, internal, internal)
-RETURNS internal
-AS 'MODULE_PATHNAME'
-LANGUAGE C IMMUTABLE STRICT;
-
--- register the opclass for indexing (not as default)
-
-CREATE OPERATOR CLASS gist__intbig_ops
-FOR TYPE _int4 USING gist
-AS
-	OPERATOR	3	&&,
-	OPERATOR	6	= (anyarray, anyarray),
-	OPERATOR	7	@>,
-	OPERATOR	8	<@,
-	OPERATOR	13	@,
-	OPERATOR	14	~,
-	OPERATOR	20	@@ (_int4, query_int),
-	FUNCTION	1	g_intbig_consistent (internal, internal, int, oid, internal),
-	FUNCTION	2	g_intbig_union (internal, internal),
-	FUNCTION	3	g_intbig_compress (internal),
-	FUNCTION	4	g_intbig_decompress (internal),
-	FUNCTION	5	g_intbig_penalty (internal, internal, internal),
-	FUNCTION	6	g_intbig_picksplit (internal, internal),
-	FUNCTION	7	g_intbig_same (internal, internal, internal),
-	STORAGE		intbig_gkey;
-
---GIN
-
-CREATE FUNCTION ginint4_queryextract(internal, internal, int2, internal, internal, internal, internal)
-RETURNS internal
-AS 'MODULE_PATHNAME'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION ginint4_consistent(internal, int2, internal, int4, internal, internal, internal, internal)
-RETURNS bool
-AS 'MODULE_PATHNAME'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE OPERATOR CLASS gin__int_ops
-FOR TYPE _int4 USING gin
-AS
-	OPERATOR	3	&&,
-	OPERATOR	6	= (anyarray, anyarray),
-	OPERATOR	7	@>,
-	OPERATOR	8	<@,
-	OPERATOR	13	@,
-	OPERATOR	14	~,
-	OPERATOR	20	@@ (_int4, query_int),
-	FUNCTION	1	btint4cmp (int4, int4),
-	FUNCTION	2	ginarrayextract (anyarray, internal, internal),
-	FUNCTION	3	ginint4_queryextract (internal, internal, int2, internal, internal, internal, internal),
-	FUNCTION	4	ginint4_consistent (internal, int2, internal, int4, internal, internal, internal, internal),
-	STORAGE		int4;
diff --git a/contrib/intarray/intarray--1.1.sql b/contrib/intarray/intarray--1.1.sql
new file mode 100644
index 0000000..817625e
--- /dev/null
+++ b/contrib/intarray/intarray--1.1.sql
@@ -0,0 +1,520 @@
+/* contrib/intarray/intarray--1.1.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION intarray" to load this file. \quit
+
+--
+-- Create the user-defined type for the 1-D integer arrays (_int4)
+--
+
+-- Query type
+CREATE FUNCTION bqarr_in(cstring)
+RETURNS query_int
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION bqarr_out(query_int)
+RETURNS cstring
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE TYPE query_int (
+	INTERNALLENGTH = -1,
+	INPUT = bqarr_in,
+	OUTPUT = bqarr_out
+);
+
+--only for debug
+CREATE FUNCTION querytree(query_int)
+RETURNS text
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+
+CREATE FUNCTION boolop(_int4, query_int)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION boolop(_int4, query_int) IS 'boolean operation with array';
+
+CREATE FUNCTION rboolop(query_int, _int4)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION rboolop(query_int, _int4) IS 'boolean operation with array';
+
+CREATE FUNCTION _int_matchsel(internal, oid, internal, integer)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE;
+
+CREATE OPERATOR @@ (
+	LEFTARG = _int4,
+	RIGHTARG = query_int,
+	PROCEDURE = boolop,
+	COMMUTATOR = '~~',
+	RESTRICT = _int_matchsel,
+	JOIN = contjoinsel
+);
+
+CREATE OPERATOR ~~ (
+	LEFTARG = query_int,
+	RIGHTARG = _int4,
+	PROCEDURE = rboolop,
+	COMMUTATOR = '@@',
+	RESTRICT = _int_matchsel,
+	JOIN = contjoinsel
+);
+
+
+--
+-- External C-functions for R-tree methods
+--
+
+-- Comparison methods
+
+CREATE FUNCTION _int_contains(_int4, _int4)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION _int_contains(_int4, _int4) IS 'contains';
+
+CREATE FUNCTION _int_contained(_int4, _int4)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION _int_contained(_int4, _int4) IS 'contained in';
+
+CREATE FUNCTION _int_overlap(_int4, _int4)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION _int_overlap(_int4, _int4) IS 'overlaps';
+
+CREATE FUNCTION _int_same(_int4, _int4)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION _int_same(_int4, _int4) IS 'same as';
+
+CREATE FUNCTION _int_different(_int4, _int4)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION _int_different(_int4, _int4) IS 'different';
+
+-- support routines for indexing
+
+CREATE FUNCTION _int_union(_int4, _int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION _int_inter(_int4, _int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION _int_overlap_sel(internal, oid, internal, integer)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE;
+
+CREATE FUNCTION _int_contains_sel(internal, oid, internal, integer)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE;
+
+CREATE FUNCTION _int_contained_sel(internal, oid, internal, integer)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE;
+
+CREATE FUNCTION _int_overlap_joinsel(internal, oid, internal, smallint, internal)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE;
+
+CREATE FUNCTION _int_contains_joinsel(internal, oid, internal, smallint, internal)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE;
+
+CREATE FUNCTION _int_contained_joinsel(internal, oid, internal, smallint, internal)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE;
+
+--
+-- OPERATORS
+--
+
+CREATE OPERATOR && (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	PROCEDURE = _int_overlap,
+	COMMUTATOR = '&&',
+	RESTRICT = _int_overlap_sel,
+	JOIN = _int_overlap_joinsel
+);
+
+--CREATE OPERATOR = (
+--	LEFTARG = _int4,
+--	RIGHTARG = _int4,
+--	PROCEDURE = _int_same,
+--	COMMUTATOR = '=',
+--	NEGATOR = '<>',
+--	RESTRICT = eqsel,
+--	JOIN = eqjoinsel,
+--	SORT1 = '<',
+--	SORT2 = '<'
+--);
+
+--CREATE OPERATOR <> (
+--	LEFTARG = _int4,
+--	RIGHTARG = _int4,
+--	PROCEDURE = _int_different,
+--	COMMUTATOR = '<>',
+--	NEGATOR = '=',
+--	RESTRICT = neqsel,
+--	JOIN = neqjoinsel
+--);
+
+CREATE OPERATOR @> (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	PROCEDURE = _int_contains,
+	COMMUTATOR = '<@',
+	RESTRICT = _int_contains_sel,
+	JOIN = _int_contains_joinsel
+);
+
+CREATE OPERATOR <@ (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	PROCEDURE = _int_contained,
+	COMMUTATOR = '@>',
+	RESTRICT = _int_contained_sel,
+	JOIN = _int_contained_joinsel
+);
+
+-- obsolete:
+CREATE OPERATOR @ (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	PROCEDURE = _int_contains,
+	COMMUTATOR = '~',
+	RESTRICT = _int_contains_sel,
+	JOIN = _int_contains_joinsel
+);
+
+CREATE OPERATOR ~ (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	PROCEDURE = _int_contained,
+	COMMUTATOR = '@',
+	RESTRICT = _int_contained_sel,
+	JOIN = _int_contained_joinsel
+);
+
+--------------
+CREATE FUNCTION intset(int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION icount(_int4)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR # (
+	RIGHTARG = _int4,
+	PROCEDURE = icount
+);
+
+CREATE FUNCTION sort(_int4, text)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION sort(_int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION sort_asc(_int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION sort_desc(_int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION uniq(_int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION idx(_int4, int4)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR # (
+	LEFTARG = _int4,
+	RIGHTARG = int4,
+	PROCEDURE = idx
+);
+
+CREATE FUNCTION subarray(_int4, int4, int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION subarray(_int4, int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION intarray_push_elem(_int4, int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR + (
+	LEFTARG = _int4,
+	RIGHTARG = int4,
+	PROCEDURE = intarray_push_elem
+);
+
+CREATE FUNCTION intarray_push_array(_int4, _int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR + (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	COMMUTATOR = +,
+	PROCEDURE = intarray_push_array
+);
+
+CREATE FUNCTION intarray_del_elem(_int4, int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR - (
+	LEFTARG = _int4,
+	RIGHTARG = int4,
+	PROCEDURE = intarray_del_elem
+);
+
+CREATE FUNCTION intset_union_elem(_int4, int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR | (
+	LEFTARG = _int4,
+	RIGHTARG = int4,
+	PROCEDURE = intset_union_elem
+);
+
+CREATE OPERATOR | (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	COMMUTATOR = |,
+	PROCEDURE = _int_union
+);
+
+CREATE FUNCTION intset_subtract(_int4, _int4)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR - (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	PROCEDURE = intset_subtract
+);
+
+CREATE OPERATOR & (
+	LEFTARG = _int4,
+	RIGHTARG = _int4,
+	COMMUTATOR = &,
+	PROCEDURE = _int_inter
+);
+--------------
+
+-- define the GiST support methods
+CREATE FUNCTION g_int_consistent(internal,_int4,int,oid,internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_int_compress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_int_decompress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_int_penalty(internal,internal,internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_int_picksplit(internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_int_union(internal, internal)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_int_same(_int4, _int4, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+
+-- Create the operator class for indexing
+
+CREATE OPERATOR CLASS gist__int_ops
+DEFAULT FOR TYPE _int4 USING gist AS
+	OPERATOR	3	&&,
+	OPERATOR	6	= (anyarray, anyarray),
+	OPERATOR	7	@>,
+	OPERATOR	8	<@,
+	OPERATOR	13	@,
+	OPERATOR	14	~,
+	OPERATOR	20	@@ (_int4, query_int),
+	FUNCTION	1	g_int_consistent (internal, _int4, int, oid, internal),
+	FUNCTION	2	g_int_union (internal, internal),
+	FUNCTION	3	g_int_compress (internal),
+	FUNCTION	4	g_int_decompress (internal),
+	FUNCTION	5	g_int_penalty (internal, internal, internal),
+	FUNCTION	6	g_int_picksplit (internal, internal),
+	FUNCTION	7	g_int_same (_int4, _int4, internal);
+
+
+---------------------------------------------
+-- intbig
+---------------------------------------------
+-- define the GiST support methods
+
+CREATE FUNCTION _intbig_in(cstring)
+RETURNS intbig_gkey
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION _intbig_out(intbig_gkey)
+RETURNS cstring
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE TYPE intbig_gkey (
+        INTERNALLENGTH = -1,
+        INPUT = _intbig_in,
+        OUTPUT = _intbig_out
+);
+
+CREATE FUNCTION g_intbig_consistent(internal,internal,int,oid,internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_intbig_compress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_intbig_decompress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_intbig_penalty(internal,internal,internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_intbig_picksplit(internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_intbig_union(internal, internal)
+RETURNS _int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION g_intbig_same(internal, internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+-- register the opclass for indexing (not as default)
+
+CREATE OPERATOR CLASS gist__intbig_ops
+FOR TYPE _int4 USING gist
+AS
+	OPERATOR	3	&&,
+	OPERATOR	6	= (anyarray, anyarray),
+	OPERATOR	7	@>,
+	OPERATOR	8	<@,
+	OPERATOR	13	@,
+	OPERATOR	14	~,
+	OPERATOR	20	@@ (_int4, query_int),
+	FUNCTION	1	g_intbig_consistent (internal, internal, int, oid, internal),
+	FUNCTION	2	g_intbig_union (internal, internal),
+	FUNCTION	3	g_intbig_compress (internal),
+	FUNCTION	4	g_intbig_decompress (internal),
+	FUNCTION	5	g_intbig_penalty (internal, internal, internal),
+	FUNCTION	6	g_intbig_picksplit (internal, internal),
+	FUNCTION	7	g_intbig_same (internal, internal, internal),
+	STORAGE		intbig_gkey;
+
+--GIN
+
+CREATE FUNCTION ginint4_queryextract(internal, internal, int2, internal, internal, internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION ginint4_consistent(internal, int2, internal, int4, internal, internal, internal, internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OPERATOR CLASS gin__int_ops
+FOR TYPE _int4 USING gin
+AS
+	OPERATOR	3	&&,
+	OPERATOR	6	= (anyarray, anyarray),
+	OPERATOR	7	@>,
+	OPERATOR	8	<@,
+	OPERATOR	13	@,
+	OPERATOR	14	~,
+	OPERATOR	20	@@ (_int4, query_int),
+	FUNCTION	1	btint4cmp (int4, int4),
+	FUNCTION	2	ginarrayextract (anyarray, internal, internal),
+	FUNCTION	3	ginint4_queryextract (internal, internal, int2, internal, internal, internal, internal),
+	FUNCTION	4	ginint4_consistent (internal, int2, internal, int4, internal, internal, internal, internal),
+	STORAGE		int4;
diff --git a/contrib/intarray/intarray.control b/contrib/intarray/intarray.control
index 7b3d4f7..8c23e8d 100644
--- a/contrib/intarray/intarray.control
+++ b/contrib/intarray/intarray.control
@@ -1,5 +1,5 @@
 # intarray extension
 comment = 'functions, operators, and index support for 1-D arrays of integers'
-default_version = '1.0'
+default_version = '1.1'
 module_pathname = '$libdir/_int'
 relocatable = true
diff --git a/contrib/intarray/sql/_int.sql b/contrib/intarray/sql/_int.sql
index 216c5c5..f6fe2de 100644
--- a/contrib/intarray/sql/_int.sql
+++ b/contrib/intarray/sql/_int.sql
@@ -68,8 +68,8 @@ SELECT '1&(2&(4&(5|!6)))'::query_int;
 
 
 CREATE TABLE test__int( a int[] );
-
 \copy test__int from 'data/test__int.data'
+ANALYZE test__int;
 
 SELECT count(*) from test__int WHERE a && '{23,50}';
 SELECT count(*) from test__int WHERE a @@ '23|50';
#7Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Heikki Linnakangas (#6)
1 attachment(s)
Re: Selectivity estimation for intarray with @@

On Tue, Jul 21, 2015 at 6:49 PM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:

On 07/21/2015 03:44 PM, Alexander Korotkov wrote:

While Uriy is on vacation, I've revised this patch a bit.

I whacked this around quite a bit, and I think it's in a committable state
now. But if you could run whatever tests you were using before on this, to
make sure it still produces the same estimates, that would be great. I
didn't change the estimates it should produce, only the code structure.

One thing that bothers me slightly with this patch is the way it peeks
into the Most-Common-Elements arrays, which is produced by the built-in
type analyze function. If we ever change what statistics are collected for
arrays, or the way they are stored, this might break. In matchsel, why
don't we just call the built-in estimator function for each element that we
need to probe, and not look into the statistics ourselves at all? I
actually experimented with that, and it did slash much of the code, and it
would be more future-proof. However, it was also a lot slower for queries
that contain multiple values. That's understandable: the built-in estimator
will fetch the statistics tuple, parse the arrays, etc. separately for each
value in the query_int, while this patch will do it only once for the whole
query, and perform a simple binary search for each value. So overall, I
think this is OK as it is. But if we find that we need to use the MCE list
in this fashion in more places in the future, it might be worthwhile to add
some support code for this in the backend to allow extracting the stats
once, and doing multiple "lightweight estimations" using the extracted
stats.

Yeah, I see. We could end up with something like this. But probably we
would need something more general for extensions which wants to play with
statistics.
For instance, pg_trgm could estimate selectivity for "text % text"
operator. But in order to provide that it needs trigram statistics. Now it
could be implemented by defining separate datatype, but it's a kluge.
Probably, we would end up with custom additional statistics for datatypes.

Some things I fixed/changed:

* I didn't like that transformOperator() function, which looked up the
function's name. I replaced it with separate wrapper functions for each
operator, so that the built-in operator's OID can be hardcoded into each.

* I refactored the matchsel function heavily. I think it's more readable
now.

* I got rid of the Int4Freq array. It didn't seem significantly easier to
work with than the separate values/numbers arrays, so I just used those
directly.

* Also use the matchsel estimator for ~~ (the commutator of @@)

In this version of patch it's not checked if variable is actually and int[]
not query_int. See following test case.

# create table test2 as (select '1'::query_int val from
generate_series(1,1000000));
# analyze test2;

# explain select * from test2 where '{1}'::int[] @@ val;
ERROR: unrecognized int query item type: 0

I've added this check.

* Also use the estimators for the obsolete @ and ~ operators. Not that I

care much about those as they are obsolete, but seems strange not to, as
it's a trivial matter of setting the right estimator function.

* I added an ANALYZE in the regression test. It still won't systematically
test all the cost estimation code, and there's nothing to check that the
estimates make sense, but at least more of the code will now run.

You also forgot to include intarray--1.0--1.1.sql into patch. I've also
added it.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Attachments:

intarray-sel-4.patchapplication/octet-stream; name=intarray-sel-4.patchDownload
diff --git a/contrib/intarray/Makefile b/contrib/intarray/Makefile
new file mode 100644
index 920c5b1..5ea7f2a
*** a/contrib/intarray/Makefile
--- b/contrib/intarray/Makefile
***************
*** 2,11 ****
  
  MODULE_big = _int
  OBJS = _int_bool.o _int_gist.o _int_op.o _int_tool.o \
! 	_intbig_gist.o _int_gin.o $(WIN32RES)
  
  EXTENSION = intarray
! DATA = intarray--1.0.sql intarray--unpackaged--1.0.sql
  PGFILEDESC = "intarray - functions and operators for arrays of integers"
  
  REGRESS = _int
--- 2,11 ----
  
  MODULE_big = _int
  OBJS = _int_bool.o _int_gist.o _int_op.o _int_tool.o \
! 	_intbig_gist.o _int_gin.o _int_selfuncs.o $(WIN32RES)
  
  EXTENSION = intarray
! DATA = intarray--1.1.sql intarray--1.0--1.1.sql intarray--unpackaged--1.0.sql
  PGFILEDESC = "intarray - functions and operators for arrays of integers"
  
  REGRESS = _int
diff --git a/contrib/intarray/_int_selfuncs.c b/contrib/intarray/_int_selfuncs.c
new file mode 100644
index ...8c1c18e
*** a/contrib/intarray/_int_selfuncs.c
--- b/contrib/intarray/_int_selfuncs.c
***************
*** 0 ****
--- 1,341 ----
+ /*-------------------------------------------------------------------------
+  *
+  * _int_selfuncs.c
+  *	  Functions for selectivity estimation of intarray operators
+  *
+  * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *	  contrib/intarray/_int_selfuncs.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ #include "_int.h"
+ 
+ #include "access/htup_details.h"
+ #include "catalog/pg_operator.h"
+ #include "catalog/pg_statistic.h"
+ #include "catalog/pg_type.h"
+ #include "utils/selfuncs.h"
+ #include "utils/syscache.h"
+ #include "utils/lsyscache.h"
+ #include "miscadmin.h"
+ 
+ PG_FUNCTION_INFO_V1(_int_overlap_sel);
+ PG_FUNCTION_INFO_V1(_int_contains_sel);
+ PG_FUNCTION_INFO_V1(_int_contained_sel);
+ PG_FUNCTION_INFO_V1(_int_overlap_joinsel);
+ PG_FUNCTION_INFO_V1(_int_contains_joinsel);
+ PG_FUNCTION_INFO_V1(_int_contained_joinsel);
+ PG_FUNCTION_INFO_V1(_int_matchsel);
+ 
+ Datum		_int_overlap_sel(PG_FUNCTION_ARGS);
+ Datum		_int_contains_sel(PG_FUNCTION_ARGS);
+ Datum		_int_contained_sel(PG_FUNCTION_ARGS);
+ Datum		_int_overlap_joinsel(PG_FUNCTION_ARGS);
+ Datum		_int_contains_joinsel(PG_FUNCTION_ARGS);
+ Datum		_int_contained_joinsel(PG_FUNCTION_ARGS);
+ Datum		_int_matchsel(PG_FUNCTION_ARGS);
+ 
+ 
+ static Selectivity int_query_opr_selec(ITEM *item, Datum *values, float4 *freqs,
+ 					int nmncelems, float4 minfreq);
+ static int	compare_val_int4(const void *a, const void *b);
+ 
+ /*
+  * Wrappers around the default array selectivity estimation functions.
+  *
+  * The default array selectivity operators for the @>, && and @< operators
+  * work fine for integer arrays. However, if we tried to just use arraycontsel
+  * and arracontjoinsel directly as the cost estimator functions for our
+  * operators, they would not work as intended, because they look at the
+  * operator's OID. Our operators behave exactly like the built-in anyarray
+  * versions, but we must tell the cost estimator functions which built-in
+  * operators they correspond to. These wrappers just replace the operator
+  * OID with the corresponding built-in operator's OID, and call the built-in
+  * function.
+  */
+ 
+ Datum
+ _int_overlap_sel(PG_FUNCTION_ARGS)
+ {
+ 	PG_RETURN_DATUM(DirectFunctionCall4(arraycontsel,
+ 										PG_GETARG_DATUM(0),
+ 										ObjectIdGetDatum(OID_ARRAY_OVERLAP_OP),
+ 										PG_GETARG_DATUM(2),
+ 										PG_GETARG_DATUM(3)));
+ }
+ 
+ Datum
+ _int_contains_sel(PG_FUNCTION_ARGS)
+ {
+ 	PG_RETURN_DATUM(DirectFunctionCall4(arraycontsel,
+ 										PG_GETARG_DATUM(0),
+ 										ObjectIdGetDatum(OID_ARRAY_CONTAINS_OP),
+ 										PG_GETARG_DATUM(2),
+ 										PG_GETARG_DATUM(3)));
+ }
+ 
+ Datum
+ _int_contained_sel(PG_FUNCTION_ARGS)
+ {
+ 	PG_RETURN_DATUM(DirectFunctionCall4(arraycontsel,
+ 										PG_GETARG_DATUM(0),
+ 										ObjectIdGetDatum(OID_ARRAY_CONTAINED_OP),
+ 										PG_GETARG_DATUM(2),
+ 										PG_GETARG_DATUM(3)));
+ }
+ 
+ Datum
+ _int_overlap_joinsel(PG_FUNCTION_ARGS)
+ {
+ 	PG_RETURN_DATUM(DirectFunctionCall5(arraycontjoinsel,
+ 										PG_GETARG_DATUM(0),
+ 										ObjectIdGetDatum(OID_ARRAY_OVERLAP_OP),
+ 										PG_GETARG_DATUM(2),
+ 										PG_GETARG_DATUM(3),
+ 										PG_GETARG_DATUM(4)));
+ }
+ 
+ Datum
+ _int_contains_joinsel(PG_FUNCTION_ARGS)
+ {
+ 	PG_RETURN_DATUM(DirectFunctionCall5(arraycontjoinsel,
+ 										PG_GETARG_DATUM(0),
+ 										ObjectIdGetDatum(OID_ARRAY_CONTAINS_OP),
+ 										PG_GETARG_DATUM(2),
+ 										PG_GETARG_DATUM(3),
+ 										PG_GETARG_DATUM(4)));
+ }
+ 
+ Datum
+ _int_contained_joinsel(PG_FUNCTION_ARGS)
+ {
+ 	PG_RETURN_DATUM(DirectFunctionCall5(arraycontjoinsel,
+ 										PG_GETARG_DATUM(0),
+ 										ObjectIdGetDatum(OID_ARRAY_CONTAINED_OP),
+ 										PG_GETARG_DATUM(2),
+ 										PG_GETARG_DATUM(3),
+ 										PG_GETARG_DATUM(4)));
+ }
+ 
+ 
+ /*
+  * _int_matchsel -- restriction selectivity function for intarray @@ query_int
+  */
+ Datum
+ _int_matchsel(PG_FUNCTION_ARGS)
+ {
+ 	PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
+ 
+ 	List	   *args = (List *) PG_GETARG_POINTER(2);
+ 	int			varRelid = PG_GETARG_INT32(3);
+ 	VariableStatData vardata;
+ 	Node	   *other;
+ 	bool		varonleft;
+ 	Selectivity selec;
+ 	QUERYTYPE  *query;
+ 	Datum	   *mcelems = NULL;
+ 	float4	   *mcefreqs = NULL;
+ 	int			nmcelems = 0;
+ 	float4		minfreq = 0.0;
+ 	float4		nullfrac = 0.0;
+ 	Form_pg_statistic stats;
+ 	Datum	   *values = NULL;
+ 	int			nvalues = 0;
+ 	float4	   *numbers = NULL;
+ 	int			nnumbers = 0;
+ 
+ 	/*
+ 	 * If expression is not "variable @@ something" or "something @@ variable"
+ 	 * then punt and return a default estimate.
+ 	 */
+ 	if (!get_restriction_variable(root, args, varRelid,
+ 								  &vardata, &other, &varonleft))
+ 		PG_RETURN_FLOAT8(DEFAULT_EQ_SEL);
+ 
+ 	/*
+ 	 * Variable should be int[]. We don't support cases where variable is
+ 	 * query_int.
+ 	 */
+ 	if (vardata.vartype != INT4ARRAYOID)
+ 		PG_RETURN_FLOAT8(DEFAULT_EQ_SEL);
+ 
+ 	/*
+ 	 * Can't do anything useful if the something is not a constant, either.
+ 	 */
+ 	if (!IsA(other, Const))
+ 	{
+ 		ReleaseVariableStats(vardata);
+ 		PG_RETURN_FLOAT8(DEFAULT_EQ_SEL);
+ 	}
+ 
+ 	/*
+ 	 * The "@@" operator is strict, so we can cope with NULL right away.
+ 	 */
+ 	if (((Const *) other)->constisnull)
+ 	{
+ 		ReleaseVariableStats(vardata);
+ 		PG_RETURN_FLOAT8(0.0);
+ 	}
+ 
+ 	/* The caller made sure the const is a query, so get it now */
+ 	query = DatumGetQueryTypeP(((Const *) other)->constvalue);
+ 
+ 	/* Empty query matches nothing */
+ 	if (query->size == 0)
+ 	{
+ 		ReleaseVariableStats(vardata);
+ 		return (Selectivity) 0.0;
+ 	}
+ 
+ 	/*
+ 	 * Get the statistics for the intarray column.
+ 	 *
+ 	 * We're interested in the Most-Common-Elements list, and the NULL
+ 	 * fraction.
+ 	 */
+ 	if (HeapTupleIsValid(vardata.statsTuple))
+ 	{
+ 		stats = (Form_pg_statistic) GETSTRUCT(vardata.statsTuple);
+ 		nullfrac = stats->stanullfrac;
+ 
+ 		/*
+ 		 * For an int4 array, the default array type analyze function will
+ 		 * collect a Most Common Elements list, which is an array of int4s.
+ 		 */
+ 		if (get_attstatsslot(vardata.statsTuple,
+ 							 INT4OID, -1,
+ 							 STATISTIC_KIND_MCELEM, InvalidOid,
+ 							 NULL,
+ 							 &values, &nvalues,
+ 							 &numbers, &nnumbers))
+ 		{
+ 			/*
+ 			 * There should be three more Numbers than Values, because the last
+ 			 * three (for intarray) cells are taken for minimal, maximal and nulls
+ 			 * frequency. Punt if not.
+ 			 */
+ 			if (nnumbers == nvalues + 3)
+ 			{
+ 				/* Grab the lowest frequency. */
+ 				minfreq = numbers[nnumbers - (nnumbers - nvalues)];
+ 
+ 				mcelems = values;
+ 				mcefreqs = numbers;
+ 				nmcelems = nvalues;
+ 			}
+ 		}
+ 	}
+ 
+ 	/* Process the logical expression in the query, using the stats */
+ 	selec = int_query_opr_selec(GETQUERY(query) + query->size - 1,
+ 								mcelems, mcefreqs, nmcelems, minfreq);
+ 
+ 	/* MCE stats count only non-null rows, so adjust for null rows. */
+ 	selec *= (1.0 - nullfrac);
+ 
+ 	free_attstatsslot(INT4OID, values, nvalues, numbers, nnumbers);
+ 	ReleaseVariableStats(vardata);
+ 
+ 	CLAMP_PROBABILITY(selec);
+ 
+ 	PG_RETURN_FLOAT8((float8) selec);
+ }
+ 
+ /*
+  * Estimate selectivity of single intquery operator
+  */
+ static Selectivity
+ int_query_opr_selec(ITEM *item, Datum *mcelems, float4 *mcefreqs,
+ 					int nmcelems, float4 minfreq)
+ {
+ 	Selectivity selec;
+ 
+ 	/* since this function recurses, it could be driven to stack overflow */
+ 	check_stack_depth();
+ 
+ 	if (item->type == VAL)
+ 	{
+ 		Datum	   *searchres;
+ 
+ 		if (mcelems == NULL)
+ 			return (Selectivity) DEFAULT_EQ_SEL;
+ 
+ 		searchres = (Datum *) bsearch(&item->val, mcelems, nmcelems,
+ 									  sizeof(Datum), compare_val_int4);
+ 		if (searchres)
+ 		{
+ 			/*
+ 			 * The element is in MCELEM.  Return precise selectivity (or at
+ 			 * least as precise as ANALYZE could find out).
+ 			 */
+ 			selec = mcefreqs[searchres - mcelems];
+ 		}
+ 		else
+ 		{
+ 			/*
+ 			 * The element is not in MCELEM.  Punt, but assume that the
+ 			 * selectivity cannot be more than minfreq / 2.
+ 			 */
+ 			selec = Min(DEFAULT_EQ_SEL, minfreq / 2);
+ 		}
+ 	}
+ 	else if (item->type == OPR)
+ 	{
+ 		/* Current query node is an operator */
+ 		Selectivity s1,
+ 					s2;
+ 
+ 		s1 = int_query_opr_selec(item - 1, mcelems, mcefreqs, nmcelems,
+ 								 minfreq);
+ 		switch (item->val)
+ 		{
+ 			case (int32) '!':
+ 				selec = 1.0 - s1;
+ 				break;
+ 
+ 			case (int32) '&':
+ 				s2 = int_query_opr_selec(item + item->left, mcelems, mcefreqs,
+ 										 nmcelems, minfreq);
+ 				selec = s1 * s2;
+ 				break;
+ 
+ 			case (int32) '|':
+ 				s2 = int_query_opr_selec(item + item->left, mcelems, mcefreqs,
+ 										 nmcelems, minfreq);
+ 				selec = s1 + s2 - s1 * s2;
+ 				break;
+ 
+ 			default:
+ 				elog(ERROR, "unrecognized operator: %d", item->val);
+ 				selec = 0;		/* keep compiler quiet */
+ 				break;
+ 		}
+ 	}
+ 	else
+ 	{
+ 		elog(ERROR, "unrecognized int query item type: %u", item->type);
+ 		selec = 0;				/* keep compiler quiet */
+ 	}
+ 
+ 	/* Clamp intermediate results to stay sane despite roundoff error */
+ 	CLAMP_PROBABILITY(selec);
+ 
+ 	return selec;
+ }
+ 
+ /*
+  * Comparison function for binary search in mcelem array.
+  */
+ static int
+ compare_val_int4(const void *a, const void *b)
+ {
+ 	int32		key = *(int32 *) a;
+ 	const Datum *t = (const Datum *) b;
+ 
+ 	return key - DatumGetInt32(*t);
+ }
diff --git a/contrib/intarray/expected/_int.out b/contrib/intarray/expected/_int.out
new file mode 100644
index 4080b96..962e5c6
*** a/contrib/intarray/expected/_int.out
--- b/contrib/intarray/expected/_int.out
*************** SELECT '1&(2&(4&(5|!6)))'::query_int;
*** 368,373 ****
--- 368,374 ----
  
  CREATE TABLE test__int( a int[] );
  \copy test__int from 'data/test__int.data'
+ ANALYZE test__int;
  SELECT count(*) from test__int WHERE a && '{23,50}';
   count 
  -------
diff --git a/contrib/intarray/intarray--1.0--1.1.sql b/contrib/intarray/intarray--1.0--1.1.sql
new file mode 100644
index ...098e55d
*** a/contrib/intarray/intarray--1.0--1.1.sql
--- b/contrib/intarray/intarray--1.0--1.1.sql
***************
*** 0 ****
--- 1,46 ----
+ /* contrib/intarray/intarray--1.0--1.1.sql */
+ 
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "ALTER EXTENSION intarray UPDATE TO '1.1'" to load this file. \quit
+ 
+ CREATE FUNCTION _int_matchsel(internal, oid, internal, integer)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ ALTER OPERATOR @@ (_int4, query_int) SET (RESTRICT = _int_matchsel);
+ ALTER OPERATOR ~~ (query_int, _int4) SET (RESTRICT = _int_matchsel);
+ 
+ CREATE FUNCTION _int_overlap_sel(internal, oid, internal, integer)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE FUNCTION _int_contains_sel(internal, oid, internal, integer)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE FUNCTION _int_contained_sel(internal, oid, internal, integer)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE FUNCTION _int_overlap_joinsel(internal, oid, internal, smallint, internal)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE FUNCTION _int_contains_joinsel(internal, oid, internal, smallint, internal)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE FUNCTION _int_contained_joinsel(internal, oid, internal, smallint, internal)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ ALTER OPERATOR && (_int4, _int4) SET (RESTRICT = _int_overlap_sel, JOIN = _int_overlap_joinsel);
+ ALTER OPERATOR @> (_int4, _int4) SET (RESTRICT = _int_contains_sel, JOIN = _int_contains_joinsel);
+ ALTER OPERATOR <@ (_int4, _int4) SET (RESTRICT = _int_contained_sel, JOIN = _int_contained_joinsel);
\ No newline at end of file
diff --git a/contrib/intarray/intarray--1.0.sql b/contrib/intarray/intarray--1.0.sql
new file mode .
index 0b89e0f..e69de29
*** a/contrib/intarray/intarray--1.0.sql
--- b/contrib/intarray/intarray--1.0.sql
***************
*** 1,485 ****
- /* contrib/intarray/intarray--1.0.sql */
- 
- -- complain if script is sourced in psql, rather than via CREATE EXTENSION
- \echo Use "CREATE EXTENSION intarray" to load this file. \quit
- 
- --
- -- Create the user-defined type for the 1-D integer arrays (_int4)
- --
- 
- -- Query type
- CREATE FUNCTION bqarr_in(cstring)
- RETURNS query_int
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION bqarr_out(query_int)
- RETURNS cstring
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE TYPE query_int (
- 	INTERNALLENGTH = -1,
- 	INPUT = bqarr_in,
- 	OUTPUT = bqarr_out
- );
- 
- --only for debug
- CREATE FUNCTION querytree(query_int)
- RETURNS text
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- 
- CREATE FUNCTION boolop(_int4, query_int)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION boolop(_int4, query_int) IS 'boolean operation with array';
- 
- CREATE FUNCTION rboolop(query_int, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION rboolop(query_int, _int4) IS 'boolean operation with array';
- 
- CREATE OPERATOR @@ (
- 	LEFTARG = _int4,
- 	RIGHTARG = query_int,
- 	PROCEDURE = boolop,
- 	COMMUTATOR = '~~',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE OPERATOR ~~ (
- 	LEFTARG = query_int,
- 	RIGHTARG = _int4,
- 	PROCEDURE = rboolop,
- 	COMMUTATOR = '@@',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- 
- --
- -- External C-functions for R-tree methods
- --
- 
- -- Comparison methods
- 
- CREATE FUNCTION _int_contains(_int4, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION _int_contains(_int4, _int4) IS 'contains';
- 
- CREATE FUNCTION _int_contained(_int4, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION _int_contained(_int4, _int4) IS 'contained in';
- 
- CREATE FUNCTION _int_overlap(_int4, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION _int_overlap(_int4, _int4) IS 'overlaps';
- 
- CREATE FUNCTION _int_same(_int4, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION _int_same(_int4, _int4) IS 'same as';
- 
- CREATE FUNCTION _int_different(_int4, _int4)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- COMMENT ON FUNCTION _int_different(_int4, _int4) IS 'different';
- 
- -- support routines for indexing
- 
- CREATE FUNCTION _int_union(_int4, _int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION _int_inter(_int4, _int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- --
- -- OPERATORS
- --
- 
- CREATE OPERATOR && (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = _int_overlap,
- 	COMMUTATOR = '&&',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- --CREATE OPERATOR = (
- --	LEFTARG = _int4,
- --	RIGHTARG = _int4,
- --	PROCEDURE = _int_same,
- --	COMMUTATOR = '=',
- --	NEGATOR = '<>',
- --	RESTRICT = eqsel,
- --	JOIN = eqjoinsel,
- --	SORT1 = '<',
- --	SORT2 = '<'
- --);
- 
- --CREATE OPERATOR <> (
- --	LEFTARG = _int4,
- --	RIGHTARG = _int4,
- --	PROCEDURE = _int_different,
- --	COMMUTATOR = '<>',
- --	NEGATOR = '=',
- --	RESTRICT = neqsel,
- --	JOIN = neqjoinsel
- --);
- 
- CREATE OPERATOR @> (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = _int_contains,
- 	COMMUTATOR = '<@',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE OPERATOR <@ (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = _int_contained,
- 	COMMUTATOR = '@>',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- -- obsolete:
- CREATE OPERATOR @ (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = _int_contains,
- 	COMMUTATOR = '~',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- CREATE OPERATOR ~ (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = _int_contained,
- 	COMMUTATOR = '@',
- 	RESTRICT = contsel,
- 	JOIN = contjoinsel
- );
- 
- --------------
- CREATE FUNCTION intset(int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION icount(_int4)
- RETURNS int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR # (
- 	RIGHTARG = _int4,
- 	PROCEDURE = icount
- );
- 
- CREATE FUNCTION sort(_int4, text)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION sort(_int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION sort_asc(_int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION sort_desc(_int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION uniq(_int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION idx(_int4, int4)
- RETURNS int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR # (
- 	LEFTARG = _int4,
- 	RIGHTARG = int4,
- 	PROCEDURE = idx
- );
- 
- CREATE FUNCTION subarray(_int4, int4, int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION subarray(_int4, int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION intarray_push_elem(_int4, int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR + (
- 	LEFTARG = _int4,
- 	RIGHTARG = int4,
- 	PROCEDURE = intarray_push_elem
- );
- 
- CREATE FUNCTION intarray_push_array(_int4, _int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR + (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	COMMUTATOR = +,
- 	PROCEDURE = intarray_push_array
- );
- 
- CREATE FUNCTION intarray_del_elem(_int4, int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR - (
- 	LEFTARG = _int4,
- 	RIGHTARG = int4,
- 	PROCEDURE = intarray_del_elem
- );
- 
- CREATE FUNCTION intset_union_elem(_int4, int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR | (
- 	LEFTARG = _int4,
- 	RIGHTARG = int4,
- 	PROCEDURE = intset_union_elem
- );
- 
- CREATE OPERATOR | (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	COMMUTATOR = |,
- 	PROCEDURE = _int_union
- );
- 
- CREATE FUNCTION intset_subtract(_int4, _int4)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE OPERATOR - (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	PROCEDURE = intset_subtract
- );
- 
- CREATE OPERATOR & (
- 	LEFTARG = _int4,
- 	RIGHTARG = _int4,
- 	COMMUTATOR = &,
- 	PROCEDURE = _int_inter
- );
- --------------
- 
- -- define the GiST support methods
- CREATE FUNCTION g_int_consistent(internal,_int4,int,oid,internal)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_compress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_decompress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_penalty(internal,internal,internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_picksplit(internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_union(internal, internal)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_int_same(_int4, _int4, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- 
- -- Create the operator class for indexing
- 
- CREATE OPERATOR CLASS gist__int_ops
- DEFAULT FOR TYPE _int4 USING gist AS
- 	OPERATOR	3	&&,
- 	OPERATOR	6	= (anyarray, anyarray),
- 	OPERATOR	7	@>,
- 	OPERATOR	8	<@,
- 	OPERATOR	13	@,
- 	OPERATOR	14	~,
- 	OPERATOR	20	@@ (_int4, query_int),
- 	FUNCTION	1	g_int_consistent (internal, _int4, int, oid, internal),
- 	FUNCTION	2	g_int_union (internal, internal),
- 	FUNCTION	3	g_int_compress (internal),
- 	FUNCTION	4	g_int_decompress (internal),
- 	FUNCTION	5	g_int_penalty (internal, internal, internal),
- 	FUNCTION	6	g_int_picksplit (internal, internal),
- 	FUNCTION	7	g_int_same (_int4, _int4, internal);
- 
- 
- ---------------------------------------------
- -- intbig
- ---------------------------------------------
- -- define the GiST support methods
- 
- CREATE FUNCTION _intbig_in(cstring)
- RETURNS intbig_gkey
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE FUNCTION _intbig_out(intbig_gkey)
- RETURNS cstring
- AS 'MODULE_PATHNAME'
- LANGUAGE C STRICT IMMUTABLE;
- 
- CREATE TYPE intbig_gkey (
-         INTERNALLENGTH = -1,
-         INPUT = _intbig_in,
-         OUTPUT = _intbig_out
- );
- 
- CREATE FUNCTION g_intbig_consistent(internal,internal,int,oid,internal)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_compress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_decompress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_penalty(internal,internal,internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_picksplit(internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_union(internal, internal)
- RETURNS _int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION g_intbig_same(internal, internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- -- register the opclass for indexing (not as default)
- 
- CREATE OPERATOR CLASS gist__intbig_ops
- FOR TYPE _int4 USING gist
- AS
- 	OPERATOR	3	&&,
- 	OPERATOR	6	= (anyarray, anyarray),
- 	OPERATOR	7	@>,
- 	OPERATOR	8	<@,
- 	OPERATOR	13	@,
- 	OPERATOR	14	~,
- 	OPERATOR	20	@@ (_int4, query_int),
- 	FUNCTION	1	g_intbig_consistent (internal, internal, int, oid, internal),
- 	FUNCTION	2	g_intbig_union (internal, internal),
- 	FUNCTION	3	g_intbig_compress (internal),
- 	FUNCTION	4	g_intbig_decompress (internal),
- 	FUNCTION	5	g_intbig_penalty (internal, internal, internal),
- 	FUNCTION	6	g_intbig_picksplit (internal, internal),
- 	FUNCTION	7	g_intbig_same (internal, internal, internal),
- 	STORAGE		intbig_gkey;
- 
- --GIN
- 
- CREATE FUNCTION ginint4_queryextract(internal, internal, int2, internal, internal, internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE FUNCTION ginint4_consistent(internal, int2, internal, int4, internal, internal, internal, internal)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
- 
- CREATE OPERATOR CLASS gin__int_ops
- FOR TYPE _int4 USING gin
- AS
- 	OPERATOR	3	&&,
- 	OPERATOR	6	= (anyarray, anyarray),
- 	OPERATOR	7	@>,
- 	OPERATOR	8	<@,
- 	OPERATOR	13	@,
- 	OPERATOR	14	~,
- 	OPERATOR	20	@@ (_int4, query_int),
- 	FUNCTION	1	btint4cmp (int4, int4),
- 	FUNCTION	2	ginarrayextract (anyarray, internal, internal),
- 	FUNCTION	3	ginint4_queryextract (internal, internal, int2, internal, internal, internal, internal),
- 	FUNCTION	4	ginint4_consistent (internal, int2, internal, int4, internal, internal, internal, internal),
- 	STORAGE		int4;
--- 0 ----
diff --git a/contrib/intarray/intarray--1.1.sql b/contrib/intarray/intarray--1.1.sql
new file mode 100644
index ...817625e
*** a/contrib/intarray/intarray--1.1.sql
--- b/contrib/intarray/intarray--1.1.sql
***************
*** 0 ****
--- 1,520 ----
+ /* contrib/intarray/intarray--1.1.sql */
+ 
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "CREATE EXTENSION intarray" to load this file. \quit
+ 
+ --
+ -- Create the user-defined type for the 1-D integer arrays (_int4)
+ --
+ 
+ -- Query type
+ CREATE FUNCTION bqarr_in(cstring)
+ RETURNS query_int
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION bqarr_out(query_int)
+ RETURNS cstring
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE TYPE query_int (
+ 	INTERNALLENGTH = -1,
+ 	INPUT = bqarr_in,
+ 	OUTPUT = bqarr_out
+ );
+ 
+ --only for debug
+ CREATE FUNCTION querytree(query_int)
+ RETURNS text
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ 
+ CREATE FUNCTION boolop(_int4, query_int)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION boolop(_int4, query_int) IS 'boolean operation with array';
+ 
+ CREATE FUNCTION rboolop(query_int, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION rboolop(query_int, _int4) IS 'boolean operation with array';
+ 
+ CREATE FUNCTION _int_matchsel(internal, oid, internal, integer)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE OPERATOR @@ (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = query_int,
+ 	PROCEDURE = boolop,
+ 	COMMUTATOR = '~~',
+ 	RESTRICT = _int_matchsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ CREATE OPERATOR ~~ (
+ 	LEFTARG = query_int,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = rboolop,
+ 	COMMUTATOR = '@@',
+ 	RESTRICT = _int_matchsel,
+ 	JOIN = contjoinsel
+ );
+ 
+ 
+ --
+ -- External C-functions for R-tree methods
+ --
+ 
+ -- Comparison methods
+ 
+ CREATE FUNCTION _int_contains(_int4, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION _int_contains(_int4, _int4) IS 'contains';
+ 
+ CREATE FUNCTION _int_contained(_int4, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION _int_contained(_int4, _int4) IS 'contained in';
+ 
+ CREATE FUNCTION _int_overlap(_int4, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION _int_overlap(_int4, _int4) IS 'overlaps';
+ 
+ CREATE FUNCTION _int_same(_int4, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION _int_same(_int4, _int4) IS 'same as';
+ 
+ CREATE FUNCTION _int_different(_int4, _int4)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ COMMENT ON FUNCTION _int_different(_int4, _int4) IS 'different';
+ 
+ -- support routines for indexing
+ 
+ CREATE FUNCTION _int_union(_int4, _int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION _int_inter(_int4, _int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION _int_overlap_sel(internal, oid, internal, integer)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE FUNCTION _int_contains_sel(internal, oid, internal, integer)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE FUNCTION _int_contained_sel(internal, oid, internal, integer)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE FUNCTION _int_overlap_joinsel(internal, oid, internal, smallint, internal)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE FUNCTION _int_contains_joinsel(internal, oid, internal, smallint, internal)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ CREATE FUNCTION _int_contained_joinsel(internal, oid, internal, smallint, internal)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT STABLE;
+ 
+ --
+ -- OPERATORS
+ --
+ 
+ CREATE OPERATOR && (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = _int_overlap,
+ 	COMMUTATOR = '&&',
+ 	RESTRICT = _int_overlap_sel,
+ 	JOIN = _int_overlap_joinsel
+ );
+ 
+ --CREATE OPERATOR = (
+ --	LEFTARG = _int4,
+ --	RIGHTARG = _int4,
+ --	PROCEDURE = _int_same,
+ --	COMMUTATOR = '=',
+ --	NEGATOR = '<>',
+ --	RESTRICT = eqsel,
+ --	JOIN = eqjoinsel,
+ --	SORT1 = '<',
+ --	SORT2 = '<'
+ --);
+ 
+ --CREATE OPERATOR <> (
+ --	LEFTARG = _int4,
+ --	RIGHTARG = _int4,
+ --	PROCEDURE = _int_different,
+ --	COMMUTATOR = '<>',
+ --	NEGATOR = '=',
+ --	RESTRICT = neqsel,
+ --	JOIN = neqjoinsel
+ --);
+ 
+ CREATE OPERATOR @> (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = _int_contains,
+ 	COMMUTATOR = '<@',
+ 	RESTRICT = _int_contains_sel,
+ 	JOIN = _int_contains_joinsel
+ );
+ 
+ CREATE OPERATOR <@ (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = _int_contained,
+ 	COMMUTATOR = '@>',
+ 	RESTRICT = _int_contained_sel,
+ 	JOIN = _int_contained_joinsel
+ );
+ 
+ -- obsolete:
+ CREATE OPERATOR @ (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = _int_contains,
+ 	COMMUTATOR = '~',
+ 	RESTRICT = _int_contains_sel,
+ 	JOIN = _int_contains_joinsel
+ );
+ 
+ CREATE OPERATOR ~ (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = _int_contained,
+ 	COMMUTATOR = '@',
+ 	RESTRICT = _int_contained_sel,
+ 	JOIN = _int_contained_joinsel
+ );
+ 
+ --------------
+ CREATE FUNCTION intset(int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION icount(_int4)
+ RETURNS int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR # (
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = icount
+ );
+ 
+ CREATE FUNCTION sort(_int4, text)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION sort(_int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION sort_asc(_int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION sort_desc(_int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION uniq(_int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION idx(_int4, int4)
+ RETURNS int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR # (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = int4,
+ 	PROCEDURE = idx
+ );
+ 
+ CREATE FUNCTION subarray(_int4, int4, int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION subarray(_int4, int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION intarray_push_elem(_int4, int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR + (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = int4,
+ 	PROCEDURE = intarray_push_elem
+ );
+ 
+ CREATE FUNCTION intarray_push_array(_int4, _int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR + (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	COMMUTATOR = +,
+ 	PROCEDURE = intarray_push_array
+ );
+ 
+ CREATE FUNCTION intarray_del_elem(_int4, int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR - (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = int4,
+ 	PROCEDURE = intarray_del_elem
+ );
+ 
+ CREATE FUNCTION intset_union_elem(_int4, int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR | (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = int4,
+ 	PROCEDURE = intset_union_elem
+ );
+ 
+ CREATE OPERATOR | (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	COMMUTATOR = |,
+ 	PROCEDURE = _int_union
+ );
+ 
+ CREATE FUNCTION intset_subtract(_int4, _int4)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE OPERATOR - (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	PROCEDURE = intset_subtract
+ );
+ 
+ CREATE OPERATOR & (
+ 	LEFTARG = _int4,
+ 	RIGHTARG = _int4,
+ 	COMMUTATOR = &,
+ 	PROCEDURE = _int_inter
+ );
+ --------------
+ 
+ -- define the GiST support methods
+ CREATE FUNCTION g_int_consistent(internal,_int4,int,oid,internal)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_compress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_decompress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_penalty(internal,internal,internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_picksplit(internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_union(internal, internal)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_int_same(_int4, _int4, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ 
+ -- Create the operator class for indexing
+ 
+ CREATE OPERATOR CLASS gist__int_ops
+ DEFAULT FOR TYPE _int4 USING gist AS
+ 	OPERATOR	3	&&,
+ 	OPERATOR	6	= (anyarray, anyarray),
+ 	OPERATOR	7	@>,
+ 	OPERATOR	8	<@,
+ 	OPERATOR	13	@,
+ 	OPERATOR	14	~,
+ 	OPERATOR	20	@@ (_int4, query_int),
+ 	FUNCTION	1	g_int_consistent (internal, _int4, int, oid, internal),
+ 	FUNCTION	2	g_int_union (internal, internal),
+ 	FUNCTION	3	g_int_compress (internal),
+ 	FUNCTION	4	g_int_decompress (internal),
+ 	FUNCTION	5	g_int_penalty (internal, internal, internal),
+ 	FUNCTION	6	g_int_picksplit (internal, internal),
+ 	FUNCTION	7	g_int_same (_int4, _int4, internal);
+ 
+ 
+ ---------------------------------------------
+ -- intbig
+ ---------------------------------------------
+ -- define the GiST support methods
+ 
+ CREATE FUNCTION _intbig_in(cstring)
+ RETURNS intbig_gkey
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE FUNCTION _intbig_out(intbig_gkey)
+ RETURNS cstring
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+ 
+ CREATE TYPE intbig_gkey (
+         INTERNALLENGTH = -1,
+         INPUT = _intbig_in,
+         OUTPUT = _intbig_out
+ );
+ 
+ CREATE FUNCTION g_intbig_consistent(internal,internal,int,oid,internal)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_compress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_decompress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_penalty(internal,internal,internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_picksplit(internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_union(internal, internal)
+ RETURNS _int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION g_intbig_same(internal, internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ -- register the opclass for indexing (not as default)
+ 
+ CREATE OPERATOR CLASS gist__intbig_ops
+ FOR TYPE _int4 USING gist
+ AS
+ 	OPERATOR	3	&&,
+ 	OPERATOR	6	= (anyarray, anyarray),
+ 	OPERATOR	7	@>,
+ 	OPERATOR	8	<@,
+ 	OPERATOR	13	@,
+ 	OPERATOR	14	~,
+ 	OPERATOR	20	@@ (_int4, query_int),
+ 	FUNCTION	1	g_intbig_consistent (internal, internal, int, oid, internal),
+ 	FUNCTION	2	g_intbig_union (internal, internal),
+ 	FUNCTION	3	g_intbig_compress (internal),
+ 	FUNCTION	4	g_intbig_decompress (internal),
+ 	FUNCTION	5	g_intbig_penalty (internal, internal, internal),
+ 	FUNCTION	6	g_intbig_picksplit (internal, internal),
+ 	FUNCTION	7	g_intbig_same (internal, internal, internal),
+ 	STORAGE		intbig_gkey;
+ 
+ --GIN
+ 
+ CREATE FUNCTION ginint4_queryextract(internal, internal, int2, internal, internal, internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE FUNCTION ginint4_consistent(internal, int2, internal, int4, internal, internal, internal, internal)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
+ CREATE OPERATOR CLASS gin__int_ops
+ FOR TYPE _int4 USING gin
+ AS
+ 	OPERATOR	3	&&,
+ 	OPERATOR	6	= (anyarray, anyarray),
+ 	OPERATOR	7	@>,
+ 	OPERATOR	8	<@,
+ 	OPERATOR	13	@,
+ 	OPERATOR	14	~,
+ 	OPERATOR	20	@@ (_int4, query_int),
+ 	FUNCTION	1	btint4cmp (int4, int4),
+ 	FUNCTION	2	ginarrayextract (anyarray, internal, internal),
+ 	FUNCTION	3	ginint4_queryextract (internal, internal, int2, internal, internal, internal, internal),
+ 	FUNCTION	4	ginint4_consistent (internal, int2, internal, int4, internal, internal, internal, internal),
+ 	STORAGE		int4;
diff --git a/contrib/intarray/intarray.control b/contrib/intarray/intarray.control
new file mode 100644
index 7b3d4f7..8c23e8d
*** a/contrib/intarray/intarray.control
--- b/contrib/intarray/intarray.control
***************
*** 1,5 ****
  # intarray extension
  comment = 'functions, operators, and index support for 1-D arrays of integers'
! default_version = '1.0'
  module_pathname = '$libdir/_int'
  relocatable = true
--- 1,5 ----
  # intarray extension
  comment = 'functions, operators, and index support for 1-D arrays of integers'
! default_version = '1.1'
  module_pathname = '$libdir/_int'
  relocatable = true
diff --git a/contrib/intarray/sql/_int.sql b/contrib/intarray/sql/_int.sql
new file mode 100644
index 216c5c5..f6fe2de
*** a/contrib/intarray/sql/_int.sql
--- b/contrib/intarray/sql/_int.sql
*************** SELECT '1&(2&(4&(5|!6)))'::query_int;
*** 68,75 ****
  
  
  CREATE TABLE test__int( a int[] );
- 
  \copy test__int from 'data/test__int.data'
  
  SELECT count(*) from test__int WHERE a && '{23,50}';
  SELECT count(*) from test__int WHERE a @@ '23|50';
--- 68,75 ----
  
  
  CREATE TABLE test__int( a int[] );
  \copy test__int from 'data/test__int.data'
+ ANALYZE test__int;
  
  SELECT count(*) from test__int WHERE a && '{23,50}';
  SELECT count(*) from test__int WHERE a @@ '23|50';
#8Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Alexander Korotkov (#7)
Re: Selectivity estimation for intarray with @@

On 07/21/2015 07:28 PM, Alexander Korotkov wrote:

On Tue, Jul 21, 2015 at 6:49 PM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:

In this version of patch it's not checked if variable is actually and int[]
not query_int. See following test case.

# create table test2 as (select '1'::query_int val from
generate_series(1,1000000));
# analyze test2;

# explain select * from test2 where '{1}'::int[] @@ val;
ERROR: unrecognized int query item type: 0

I've added this check.

* Also use the estimators for the obsolete @ and ~ operators. Not that I

care much about those as they are obsolete, but seems strange not to, as
it's a trivial matter of setting the right estimator function.

* I added an ANALYZE in the regression test. It still won't systematically
test all the cost estimation code, and there's nothing to check that the
estimates make sense, but at least more of the code will now run.

You also forgot to include intarray--1.0--1.1.sql into patch. I've also
added it.

Thanks, committed!

- Heikki

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers