summaryrefslogtreecommitdiff
path: root/src/backend/access/gin/ginarrayproc.c
blob: c453cda525cb80d85000d0de895ad5c5454ecb50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*-------------------------------------------------------------------------
 *
 * ginarrayproc.c
 *	  support functions for GIN's indexing of any array
 *
 *
 * Portions Copyright (c) 1996-2008, 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.12 2008/01/01 19:45:46 momjian Exp $
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/gin.h"
#include "utils/array.h"
#include "utils/lsyscache.h"


#define GinOverlapStrategy		1
#define GinContainsStrategy		2
#define GinContainedStrategy	3
#define GinEqualStrategy		4

#define ARRAYCHECK(x) do {									\
	if ( ARR_HASNULL(x) )									\
		ereport(ERROR,										\
			(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),		\
			 errmsg("array must not contain null values")));		\
} while(0)


/*
 * Function used as extractValue and extractQuery both
 */
Datum
ginarrayextract(PG_FUNCTION_ARGS)
{
	ArrayType  *array;
	int32	   *nentries = (int32 *) 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);

	if (*nentries == 0 && PG_NARGS() == 3)
	{
		switch (PG_GETARG_UINT16(2))	/* StrategyNumber */
		{
			case GinOverlapStrategy:
				*nentries = -1; /* nobody can be found */
				break;
			case GinContainsStrategy:
			case GinContainedStrategy:
			case GinEqualStrategy:
			default:			/* require fullscan: GIN can't find void
								 * arrays */
				break;
		}
	}

	/* we should not free array, entries[i] points into it */
	PG_RETURN_POINTER(entries);
}

Datum
ginqueryarrayextract(PG_FUNCTION_ARGS)
{
	PG_RETURN_DATUM(DirectFunctionCall3(ginarrayextract,
										PG_GETARG_DATUM(0),
										PG_GETARG_DATUM(1),
										PG_GETARG_DATUM(2)));
}

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,
				i,
				nentries;

	/* ARRAYCHECK was already 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:
		case GinEqualStrategy:
			nentries = ArrayGetNItems(ARR_NDIM(query), ARR_DIMS(query));
			res = TRUE;
			for (i = 0; i < nentries; i++)
				if (!check[i])
				{
					res = FALSE;
					break;
				}
			break;
		default:
			elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
				 strategy);
			res = FALSE;
	}

	PG_RETURN_BOOL(res);
}