PostgreSQL Source Code git master
ginvalidate.c File Reference
#include "postgres.h"
#include "access/amvalidate.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 "catalog/pg_opfamily.h"
#include "catalog/pg_type.h"
#include "utils/regproc.h"
#include "utils/syscache.h"
Include dependency graph for ginvalidate.c:

Go to the source code of this file.

Functions

bool ginvalidate (Oid opclassoid)
 
void ginadjustmembers (Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
 

Function Documentation

◆ ginadjustmembers()

void ginadjustmembers ( Oid  opfamilyoid,
Oid  opclassoid,
List operators,
List functions 
)

Definition at line 277 of file ginvalidate.c.

281{
282 ListCell *lc;
283
284 /*
285 * Operator members of a GIN opfamily should never have hard dependencies,
286 * since their connection to the opfamily depends only on what the support
287 * functions think, and that can be altered. For consistency, we make all
288 * soft dependencies point to the opfamily, though a soft dependency on
289 * the opclass would work as well in the CREATE OPERATOR CLASS case.
290 */
291 foreach(lc, operators)
292 {
294
295 op->ref_is_hard = false;
296 op->ref_is_family = true;
297 op->refobjid = opfamilyoid;
298 }
299
300 /*
301 * Required support functions should have hard dependencies. Preferably
302 * those are just dependencies on the opclass, but if we're in ALTER
303 * OPERATOR FAMILY, we leave the dependency pointing at the whole
304 * opfamily. (Given that GIN opclasses generally don't share opfamilies,
305 * it seems unlikely to be worth working harder.)
306 */
307 foreach(lc, functions)
308 {
310
311 switch (op->number)
312 {
315 /* Required support function */
316 op->ref_is_hard = true;
317 break;
318 case GIN_COMPARE_PROC:
322 case GIN_OPTIONS_PROC:
323 /* Optional, so force it to be a soft family dependency */
324 op->ref_is_hard = false;
325 op->ref_is_family = true;
326 op->refobjid = opfamilyoid;
327 break;
328 default:
330 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
331 errmsg("support function number %d is invalid for access method %s",
332 op->number, "gin")));
333 break;
334 }
335 }
336}
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define GIN_COMPARE_PROC
Definition: gin.h:22
#define GIN_CONSISTENT_PROC
Definition: gin.h:25
#define GIN_EXTRACTQUERY_PROC
Definition: gin.h:24
#define GIN_EXTRACTVALUE_PROC
Definition: gin.h:23
#define GIN_TRICONSISTENT_PROC
Definition: gin.h:27
#define GIN_COMPARE_PARTIAL_PROC
Definition: gin.h:26
#define GIN_OPTIONS_PROC
Definition: gin.h:28
#define lfirst(lc)
Definition: pg_list.h:172
static const struct fns functions
Definition: regcomp.c:358
Oid refobjid
Definition: amapi.h:94
bool ref_is_family
Definition: amapi.h:93
int number
Definition: amapi.h:88
bool ref_is_hard
Definition: amapi.h:92

References ereport, errcode(), errmsg(), ERROR, functions, GIN_COMPARE_PARTIAL_PROC, GIN_COMPARE_PROC, GIN_CONSISTENT_PROC, GIN_EXTRACTQUERY_PROC, GIN_EXTRACTVALUE_PROC, GIN_OPTIONS_PROC, GIN_TRICONSISTENT_PROC, lfirst, OpFamilyMember::number, OpFamilyMember::ref_is_family, OpFamilyMember::ref_is_hard, and OpFamilyMember::refobjid.

Referenced by ginhandler().

◆ ginvalidate()

bool ginvalidate ( Oid  opclassoid)

Definition at line 31 of file ginvalidate.c.

32{
33 bool result = true;
34 HeapTuple classtup;
35 Form_pg_opclass classform;
36 Oid opfamilyoid;
37 Oid opcintype;
38 Oid opckeytype;
39 char *opclassname;
40 HeapTuple familytup;
41 Form_pg_opfamily familyform;
42 char *opfamilyname;
43 CatCList *proclist,
44 *oprlist;
45 List *grouplist;
46 OpFamilyOpFuncGroup *opclassgroup;
47 int i;
48 ListCell *lc;
49
50 /* Fetch opclass information */
51 classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
52 if (!HeapTupleIsValid(classtup))
53 elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
54 classform = (Form_pg_opclass) GETSTRUCT(classtup);
55
56 opfamilyoid = classform->opcfamily;
57 opcintype = classform->opcintype;
58 opckeytype = classform->opckeytype;
59 if (!OidIsValid(opckeytype))
60 opckeytype = opcintype;
61 opclassname = NameStr(classform->opcname);
62
63 /* Fetch opfamily information */
64 familytup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyoid));
65 if (!HeapTupleIsValid(familytup))
66 elog(ERROR, "cache lookup failed for operator family %u", opfamilyoid);
67 familyform = (Form_pg_opfamily) GETSTRUCT(familytup);
68
69 opfamilyname = NameStr(familyform->opfname);
70
71 /* Fetch all operators and support functions of the opfamily */
72 oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
73 proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
74
75 /* Check individual support functions */
76 for (i = 0; i < proclist->n_members; i++)
77 {
78 HeapTuple proctup = &proclist->members[i]->tuple;
79 Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
80 bool ok;
81
82 /*
83 * All GIN support functions should be registered with matching
84 * left/right types
85 */
86 if (procform->amproclefttype != procform->amprocrighttype)
87 {
89 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
90 errmsg("operator family \"%s\" of access method %s contains support function %s with different left and right input types",
91 opfamilyname, "gin",
92 format_procedure(procform->amproc))));
93 result = false;
94 }
95
96 /*
97 * We can't check signatures except within the specific opclass, since
98 * we need to know the associated opckeytype in many cases.
99 */
100 if (procform->amproclefttype != opcintype)
101 continue;
102
103 /* Check procedure numbers and function signatures */
104 switch (procform->amprocnum)
105 {
106 case GIN_COMPARE_PROC:
107 ok = check_amproc_signature(procform->amproc, INT4OID, false,
108 2, 2, opckeytype, opckeytype);
109 break;
111 /* Some opclasses omit nullFlags */
112 ok = check_amproc_signature(procform->amproc, INTERNALOID, false,
113 2, 3, opcintype, INTERNALOID,
114 INTERNALOID);
115 break;
117 /* Some opclasses omit nullFlags and searchMode */
118 ok = check_amproc_signature(procform->amproc, INTERNALOID, false,
119 5, 7, opcintype, INTERNALOID,
120 INT2OID, INTERNALOID, INTERNALOID,
121 INTERNALOID, INTERNALOID);
122 break;
124 /* Some opclasses omit queryKeys and nullFlags */
125 ok = check_amproc_signature(procform->amproc, BOOLOID, false,
126 6, 8, INTERNALOID, INT2OID,
127 opcintype, INT4OID,
128 INTERNALOID, INTERNALOID,
129 INTERNALOID, INTERNALOID);
130 break;
132 ok = check_amproc_signature(procform->amproc, INT4OID, false,
133 4, 4, opckeytype, opckeytype,
134 INT2OID, INTERNALOID);
135 break;
137 ok = check_amproc_signature(procform->amproc, CHAROID, false,
138 7, 7, INTERNALOID, INT2OID,
139 opcintype, INT4OID,
140 INTERNALOID, INTERNALOID,
141 INTERNALOID);
142 break;
143 case GIN_OPTIONS_PROC:
144 ok = check_amoptsproc_signature(procform->amproc);
145 break;
146 default:
148 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
149 errmsg("operator family \"%s\" of access method %s contains function %s with invalid support number %d",
150 opfamilyname, "gin",
151 format_procedure(procform->amproc),
152 procform->amprocnum)));
153 result = false;
154 continue; /* don't want additional message */
155 }
156
157 if (!ok)
158 {
160 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
161 errmsg("operator family \"%s\" of access method %s contains function %s with wrong signature for support number %d",
162 opfamilyname, "gin",
163 format_procedure(procform->amproc),
164 procform->amprocnum)));
165 result = false;
166 }
167 }
168
169 /* Check individual operators */
170 for (i = 0; i < oprlist->n_members; i++)
171 {
172 HeapTuple oprtup = &oprlist->members[i]->tuple;
173 Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
174
175 /* TODO: Check that only allowed strategy numbers exist */
176 if (oprform->amopstrategy < 1 || oprform->amopstrategy > 63)
177 {
179 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
180 errmsg("operator family \"%s\" of access method %s contains operator %s with invalid strategy number %d",
181 opfamilyname, "gin",
182 format_operator(oprform->amopopr),
183 oprform->amopstrategy)));
184 result = false;
185 }
186
187 /* gin doesn't support ORDER BY operators */
188 if (oprform->amoppurpose != AMOP_SEARCH ||
189 OidIsValid(oprform->amopsortfamily))
190 {
192 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
193 errmsg("operator family \"%s\" of access method %s contains invalid ORDER BY specification for operator %s",
194 opfamilyname, "gin",
195 format_operator(oprform->amopopr))));
196 result = false;
197 }
198
199 /* Check operator signature --- same for all gin strategies */
200 if (!check_amop_signature(oprform->amopopr, BOOLOID,
201 oprform->amoplefttype,
202 oprform->amoprighttype))
203 {
205 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
206 errmsg("operator family \"%s\" of access method %s contains operator %s with wrong signature",
207 opfamilyname, "gin",
208 format_operator(oprform->amopopr))));
209 result = false;
210 }
211 }
212
213 /* Now check for inconsistent groups of operators/functions */
214 grouplist = identify_opfamily_groups(oprlist, proclist);
215 opclassgroup = NULL;
216 foreach(lc, grouplist)
217 {
219
220 /* Remember the group exactly matching the test opclass */
221 if (thisgroup->lefttype == opcintype &&
222 thisgroup->righttype == opcintype)
223 opclassgroup = thisgroup;
224
225 /*
226 * There is not a lot we can do to check the operator sets, since each
227 * GIN opclass is more or less a law unto itself, and some contain
228 * only operators that are binary-compatible with the opclass datatype
229 * (meaning that empty operator sets can be OK). That case also means
230 * that we shouldn't insist on nonempty function sets except for the
231 * opclass's own group.
232 */
233 }
234
235 /* Check that the originally-named opclass is complete */
236 for (i = 1; i <= GINNProcs; i++)
237 {
238 if (opclassgroup &&
239 (opclassgroup->functionset & (((uint64) 1) << i)) != 0)
240 continue; /* got it */
243 continue; /* optional method */
245 continue; /* don't need both, see check below loop */
247 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
248 errmsg("operator class \"%s\" of access method %s is missing support function %d",
249 opclassname, "gin", i)));
250 result = false;
251 }
252 if (!opclassgroup ||
253 ((opclassgroup->functionset & (1 << GIN_CONSISTENT_PROC)) == 0 &&
254 (opclassgroup->functionset & (1 << GIN_TRICONSISTENT_PROC)) == 0))
255 {
257 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
258 errmsg("operator class \"%s\" of access method %s is missing support function %d or %d",
259 opclassname, "gin",
261 result = false;
262 }
263
264
265 ReleaseCatCacheList(proclist);
266 ReleaseCatCacheList(oprlist);
267 ReleaseSysCache(familytup);
268 ReleaseSysCache(classtup);
269
270 return result;
271}
bool check_amproc_signature(Oid funcid, Oid restype, bool exact, int minargs, int maxargs,...)
Definition: amvalidate.c:152
bool check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
Definition: amvalidate.c:206
List * identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
Definition: amvalidate.c:43
bool check_amoptsproc_signature(Oid funcid)
Definition: amvalidate.c:192
#define NameStr(name)
Definition: c.h:703
uint64_t uint64
Definition: c.h:489
#define OidIsValid(objectId)
Definition: c.h:732
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:2071
#define elog(elevel,...)
Definition: elog.h:225
#define INFO
Definition: elog.h:34
#define GINNProcs
Definition: gin.h:29
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
int i
Definition: isn.c:72
FormData_pg_amop * Form_pg_amop
Definition: pg_amop.h:88
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:68
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:51
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
unsigned int Oid
Definition: postgres_ext.h:32
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:299
char * format_operator(Oid operator_oid)
Definition: regproc.c:793
Definition: pg_list.h:54
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:180
int n_members
Definition: catcache.h:178
HeapTupleData tuple
Definition: catcache.h:123
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:127

References check_amop_signature(), check_amoptsproc_signature(), check_amproc_signature(), elog, ereport, errcode(), errmsg(), ERROR, format_operator(), format_procedure(), OpFamilyOpFuncGroup::functionset, GETSTRUCT(), GIN_COMPARE_PARTIAL_PROC, GIN_COMPARE_PROC, GIN_CONSISTENT_PROC, GIN_EXTRACTQUERY_PROC, GIN_EXTRACTVALUE_PROC, GIN_OPTIONS_PROC, GIN_TRICONSISTENT_PROC, GINNProcs, HeapTupleIsValid, i, identify_opfamily_groups(), INFO, OpFamilyOpFuncGroup::lefttype, lfirst, catclist::members, catclist::n_members, NameStr, ObjectIdGetDatum(), OidIsValid, ReleaseCatCacheList(), ReleaseSysCache(), OpFamilyOpFuncGroup::righttype, SearchSysCache1(), SearchSysCacheList1, and catctup::tuple.

Referenced by ginhandler().