aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/gin/ginarrayproc.c
diff options
context:
space:
mode:
authorTeodor Sigaev <teodor@sigaev.ru>2006-05-02 11:28:56 +0000
committerTeodor Sigaev <teodor@sigaev.ru>2006-05-02 11:28:56 +0000
commit8a3631f8d86cdd9b07c577d6e213b1fc824db255 (patch)
tree40bcee8383d3552cba8f79e50025613fb683a72e /src/backend/access/gin/ginarrayproc.c
parent427c6b5b984928972e955f4477c6ba64edbb66cc (diff)
downloadpostgresql-8a3631f8d86cdd9b07c577d6e213b1fc824db255.tar.gz
postgresql-8a3631f8d86cdd9b07c577d6e213b1fc824db255.zip
GIN: Generalized Inverted iNdex.
text[], int4[], Tsearch2 support for GIN.
Diffstat (limited to 'src/backend/access/gin/ginarrayproc.c')
-rw-r--r--src/backend/access/gin/ginarrayproc.c261
1 files changed, 261 insertions, 0 deletions
diff --git a/src/backend/access/gin/ginarrayproc.c b/src/backend/access/gin/ginarrayproc.c
new file mode 100644
index 00000000000..0fe213d2a8f
--- /dev/null
+++ b/src/backend/access/gin/ginarrayproc.c
@@ -0,0 +1,261 @@
+/*-------------------------------------------------------------------------
+ *
+ * ginvacuum.c
+ * support function for GIN's indexing of any array
+ *
+ *
+ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/access/gin/ginarrayproc.c,v 1.1 2006/05/02 11:28:54 teodor Exp $
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "catalog/index.h"
+#include "miscadmin.h"
+#include "storage/freespace.h"
+#include "utils/array.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+#include "utils/typcache.h"
+#include "utils/builtins.h"
+#include "access/gin.h"
+
+#define GinOverlapStrategy 1
+#define GinContainsStrategy 2
+#define GinContainedStrategy 3
+
+#define ARRAYCHECK(x) do { \
+ if ( ARR_HASNULL(x) ) \
+ ereport(ERROR, \
+ (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), \
+ errmsg("array must not contain nulls"))); \
+ \
+ if ( ARR_NDIM(x) != 1 && ARR_NDIM(x) != 0 ) \
+ ereport(ERROR, \
+ (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), \
+ errmsg("array must be one-dimensional"))); \
+} while(0)
+
+/*
+ * Function used as extractValue and extractQuery both
+ */
+Datum
+ginarrayextract(PG_FUNCTION_ARGS) {
+ ArrayType *array;
+ uint32 *nentries = (uint32*)PG_GETARG_POINTER(1);
+ Datum *entries = NULL;
+ int16 elmlen;
+ bool elmbyval;
+ char elmalign;
+
+ /* we should guarantee that array will not be destroyed during all operation */
+ array = PG_GETARG_ARRAYTYPE_P_COPY(0);
+
+ ARRAYCHECK(array);
+
+ get_typlenbyvalalign(ARR_ELEMTYPE(array),
+ &elmlen, &elmbyval, &elmalign);
+
+ deconstruct_array(array,
+ ARR_ELEMTYPE(array),
+ elmlen, elmbyval, elmalign,
+ &entries, NULL, (int*)nentries);
+
+ /* we should not free array, entries[i] points into it */
+ PG_RETURN_POINTER(entries);
+}
+
+Datum
+ginarrayconsistent(PG_FUNCTION_ARGS) {
+ bool *check = (bool*)PG_GETARG_POINTER(0);
+ StrategyNumber strategy = PG_GETARG_UINT16(1);
+ ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
+ int res=FALSE, i, nentries=ArrayGetNItems(ARR_NDIM(query), ARR_DIMS(query));
+
+ /* we can do not check array carefully, it's done by previous ginarrayextract call */
+
+ switch( strategy ) {
+ case GinOverlapStrategy:
+ case GinContainedStrategy:
+ /* at least one element in check[] is true, so result = true */
+ res = TRUE;
+ break;
+ case GinContainsStrategy:
+ res = TRUE;
+ for(i=0;i<nentries;i++)
+ if ( !check[i] ) {
+ res = FALSE;
+ break;
+ }
+ break;
+ default:
+ elog(ERROR, "ginarrayconsistent: unknown strategy number: %d", strategy);
+ }
+
+ PG_RETURN_BOOL(res);
+}
+
+static TypeCacheEntry*
+fillTypeCacheEntry( TypeCacheEntry *typentry, Oid element_type ) {
+ if ( typentry && typentry->type_id == element_type )
+ return typentry;
+
+ typentry = lookup_type_cache(element_type, TYPECACHE_EQ_OPR_FINFO);
+ if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("could not identify an equality operator for type %s", format_type_be(element_type))));
+
+ return typentry;
+}
+
+static bool
+typeEQ(FunctionCallInfoData *locfcinfo, Datum a, Datum b) {
+ locfcinfo->arg[0] = a;
+ locfcinfo->arg[1] = b;
+ locfcinfo->argnull[0] = false;
+ locfcinfo->argnull[1] = false;
+ locfcinfo->isnull = false;
+
+ return DatumGetBool(FunctionCallInvoke(locfcinfo));
+}
+
+static bool
+ginArrayOverlap(TypeCacheEntry *typentry, ArrayType *a, ArrayType *b) {
+ Datum *da, *db;
+ int na, nb, j, i;
+ FunctionCallInfoData locfcinfo;
+
+ if ( ARR_ELEMTYPE(a) != ARR_ELEMTYPE(b) )
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("cannot compare arrays of different element types")));
+
+ ARRAYCHECK(a);
+ ARRAYCHECK(b);
+
+ deconstruct_array(a,
+ ARR_ELEMTYPE(a),
+ typentry->typlen, typentry->typbyval, typentry->typalign,
+ &da, NULL, &na);
+ deconstruct_array(b,
+ ARR_ELEMTYPE(b),
+ typentry->typlen, typentry->typbyval, typentry->typalign,
+ &db, NULL, &nb);
+
+ InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
+ NULL, NULL);
+
+ for(i=0;i<na;i++) {
+ for(j=0;j<nb;j++) {
+ if ( typeEQ(&locfcinfo, da[i], db[j]) ) {
+ pfree( da );
+ pfree( db );
+ return TRUE;
+ }
+ }
+ }
+
+ pfree( da );
+ pfree( db );
+
+ return FALSE;
+}
+
+static bool
+ginArrayContains(TypeCacheEntry *typentry, ArrayType *a, ArrayType *b) {
+ Datum *da, *db;
+ int na, nb, j, i, n = 0;
+ FunctionCallInfoData locfcinfo;
+
+ if ( ARR_ELEMTYPE(a) != ARR_ELEMTYPE(b) )
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("cannot compare arrays of different element types")));
+
+ ARRAYCHECK(a);
+ ARRAYCHECK(b);
+
+ deconstruct_array(a,
+ ARR_ELEMTYPE(a),
+ typentry->typlen, typentry->typbyval, typentry->typalign,
+ &da, NULL, &na);
+ deconstruct_array(b,
+ ARR_ELEMTYPE(b),
+ typentry->typlen, typentry->typbyval, typentry->typalign,
+ &db, NULL, &nb);
+
+ InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
+ NULL, NULL);
+
+ for(i=0;i<nb;i++) {
+ for(j=0;j<na;j++) {
+ if ( typeEQ(&locfcinfo, db[i], da[j]) ) {
+ n++;
+ break;
+ }
+ }
+ }
+
+ pfree( da );
+ pfree( db );
+
+ return ( n==nb ) ? TRUE : FALSE;
+}
+
+Datum
+arrayoverlap(PG_FUNCTION_ARGS) {
+ ArrayType *a = PG_GETARG_ARRAYTYPE_P(0);
+ ArrayType *b = PG_GETARG_ARRAYTYPE_P(1);
+ TypeCacheEntry *typentry = fillTypeCacheEntry( fcinfo->flinfo->fn_extra, ARR_ELEMTYPE(a) );
+ bool res;
+
+ fcinfo->flinfo->fn_extra = (void*)typentry;
+
+ res = ginArrayOverlap( typentry, a, b );
+
+ PG_FREE_IF_COPY(a,0);
+ PG_FREE_IF_COPY(b,1);
+
+ PG_RETURN_BOOL(res);
+}
+
+Datum
+arraycontains(PG_FUNCTION_ARGS) {
+ ArrayType *a = PG_GETARG_ARRAYTYPE_P(0);
+ ArrayType *b = PG_GETARG_ARRAYTYPE_P(1);
+ TypeCacheEntry *typentry = fillTypeCacheEntry( fcinfo->flinfo->fn_extra, ARR_ELEMTYPE(a) );
+ bool res;
+
+ fcinfo->flinfo->fn_extra = (void*)typentry;
+
+ res = ginArrayContains( typentry, a, b );
+
+ PG_FREE_IF_COPY(a,0);
+ PG_FREE_IF_COPY(b,1);
+
+ PG_RETURN_BOOL(res);
+}
+
+Datum
+arraycontained(PG_FUNCTION_ARGS) {
+ ArrayType *a = PG_GETARG_ARRAYTYPE_P(0);
+ ArrayType *b = PG_GETARG_ARRAYTYPE_P(1);
+ TypeCacheEntry *typentry = fillTypeCacheEntry( fcinfo->flinfo->fn_extra, ARR_ELEMTYPE(a) );
+ bool res;
+
+ fcinfo->flinfo->fn_extra = (void*)typentry;
+
+ res = ginArrayContains( typentry, b, a );
+
+ PG_FREE_IF_COPY(a,0);
+ PG_FREE_IF_COPY(b,1);
+
+ PG_RETURN_BOOL(res);
+}
+