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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
/*-------------------------------------------------------------------------
*
* ginvalidate.c
* Opclass validator for GIN.
*
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* src/backend/access/gin/ginvalidate.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/gin_private.h"
#include "access/htup_details.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_opclass.h"
#include "utils/catcache.h"
#include "utils/syscache.h"
/*
* Validator for a GIN opclass.
*/
bool
ginvalidate(Oid opclassoid)
{
HeapTuple classtup;
Form_pg_opclass classform;
Oid opfamilyoid;
Oid opcintype;
int numclassops;
int32 classfuncbits;
CatCList *proclist,
*oprlist;
int i;
/* Fetch opclass information */
classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
if (!HeapTupleIsValid(classtup))
elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
classform = (Form_pg_opclass) GETSTRUCT(classtup);
opfamilyoid = classform->opcfamily;
opcintype = classform->opcintype;
ReleaseSysCache(classtup);
/* Fetch all operators and support functions of the opfamily */
oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
/* We'll track the ops and functions belonging to the named opclass */
numclassops = 0;
classfuncbits = 0;
/* Check support functions */
for (i = 0; i < proclist->n_members; i++)
{
HeapTuple proctup = &proclist->members[i]->tuple;
Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
/* Check that only allowed procedure numbers exist */
if (procform->amprocnum < 1 ||
procform->amprocnum > GINNProcs)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("gin opfamily %u contains invalid support number %d for procedure %u",
opfamilyoid,
procform->amprocnum, procform->amproc)));
/* Remember functions that are specifically for the named opclass */
if (procform->amproclefttype == opcintype &&
procform->amprocrighttype == opcintype)
classfuncbits |= (1 << procform->amprocnum);
}
/* Check operators */
for (i = 0; i < oprlist->n_members; i++)
{
HeapTuple oprtup = &oprlist->members[i]->tuple;
Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
/* TODO: Check that only allowed strategy numbers exist */
if (oprform->amopstrategy < 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("gin opfamily %u contains invalid strategy number %d for operator %u",
opfamilyoid,
oprform->amopstrategy, oprform->amopopr)));
/* gin doesn't support ORDER BY operators */
if (oprform->amoppurpose != AMOP_SEARCH ||
OidIsValid(oprform->amopsortfamily))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("gin opfamily %u contains invalid ORDER BY specification for operator %u",
opfamilyoid, oprform->amopopr)));
/* Count operators that are specifically for the named opclass */
if (oprform->amoplefttype == opcintype &&
oprform->amoprighttype == opcintype)
numclassops++;
}
/* Check that the named opclass is complete */
/* XXX needs work: we need to detect applicability of ANYARRAY operators */
#ifdef NOT_USED
if (numclassops == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("gin opclass %u is missing operator(s)",
opclassoid)));
#endif
for (i = 1; i <= GINNProcs; i++)
{
if ((classfuncbits & (1 << i)) != 0)
continue; /* got it */
if (i == GIN_COMPARE_PARTIAL_PROC)
continue; /* optional method */
if (i == GIN_CONSISTENT_PROC || i == GIN_TRICONSISTENT_PROC)
continue; /* don't need to have both, see check below
* loop */
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("gin opclass %u is missing required support function %d",
opclassoid, i)));
}
if ((classfuncbits & (1 << GIN_CONSISTENT_PROC)) == 0 &&
(classfuncbits & (1 << GIN_TRICONSISTENT_PROC)) == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("gin opclass %u is missing required support function",
opclassoid)));
ReleaseCatCacheList(proclist);
ReleaseCatCacheList(oprlist);
return true;
}
|