Newer
Older
/*-------------------------------------------------------------------------
*
* lsyscache.c
* Convenience routines for common queries in the system catalog cache.
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.143 2007/01/10 18:06:04 tgl Exp $
* Eventually, the index information should go through here, too.
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/hash.h"
#include "access/nbtree.h"
#include "bootstrap/bootstrap.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
/* ---------- AMOP CACHES ---------- */
* op_in_opfamily
* Return t iff operator 'opno' is in operator family 'opfamily'.
op_in_opfamily(Oid opno, Oid opfamily)
return SearchSysCacheExists(AMOPOPID,
ObjectIdGetDatum(opno),
ObjectIdGetDatum(opfamily),
0, 0);
}
* get_op_opfamily_strategy
* Get the operator's strategy number within the specified opfamily,
* or 0 if it's not a member of the opfamily.
*/
int
get_op_opfamily_strategy(Oid opno, Oid opfamily)
{
HeapTuple tp;
Form_pg_amop amop_tup;
int result;
tp = SearchSysCache(AMOPOPID,
ObjectIdGetDatum(opno),
ObjectIdGetDatum(opfamily),
0, 0);
if (!HeapTupleIsValid(tp))
return 0;
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
result = amop_tup->amopstrategy;
ReleaseSysCache(tp);
return result;
}
* get_op_opfamily_properties
* Get the operator's strategy number, input types, and recheck (lossy)
* flag within the specified opfamily.
* Caller should already have verified that opno is a member of opfamily,
* therefore we raise an error if the tuple is not found.
*/
get_op_opfamily_properties(Oid opno, Oid opfamily,
int *strategy,
Oid *lefttype,
Oid *righttype,
bool *recheck)
{
HeapTuple tp;
Form_pg_amop amop_tup;
tp = SearchSysCache(AMOPOPID,
ObjectIdGetDatum(opno),
ObjectIdGetDatum(opfamily),
0, 0);
if (!HeapTupleIsValid(tp))
elog(ERROR, "operator %u is not a member of opfamily %u",
opno, opfamily);
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
*strategy = amop_tup->amopstrategy;
*lefttype = amop_tup->amoplefttype;
*righttype = amop_tup->amoprighttype;
*recheck = amop_tup->amopreqcheck;
ReleaseSysCache(tp);
/*
* get_opfamily_member
* Get the OID of the operator that implements the specified strategy
* with the specified datatypes for the specified opfamily.
*
* Returns InvalidOid if there is no pg_amop entry for the given keys.
*/
Oid
get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
int16 strategy)
{
HeapTuple tp;
Form_pg_amop amop_tup;
Oid result;
tp = SearchSysCache(AMOPSTRATEGY,
ObjectIdGetDatum(opfamily),
ObjectIdGetDatum(lefttype),
ObjectIdGetDatum(righttype),
Int16GetDatum(strategy));
if (!HeapTupleIsValid(tp))
return InvalidOid;
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
result = amop_tup->amopopr;
ReleaseSysCache(tp);
return result;
}
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/*
* get_op_mergejoin_info
* Given the OIDs of a (putatively) mergejoinable equality operator
* and a sortop defining the sort ordering of the lefthand input of
* the merge clause, determine whether this sort ordering is actually
* usable for merging. If so, return the required sort ordering op
* for the righthand input, as well as the btree opfamily OID containing
* these operators and the operator strategy number of the two sortops
* (either BTLessStrategyNumber or BTGreaterStrategyNumber).
*
* We can mergejoin if we find the two operators in the same opfamily as
* equality and either less-than or greater-than respectively. If there
* are multiple such opfamilies, assume we can use any one.
*/
#ifdef NOT_YET
/* eventually should look like this */
bool
get_op_mergejoin_info(Oid eq_op, Oid left_sortop,
Oid *right_sortop, Oid *opfamily, int *opstrategy)
{
bool result = false;
Oid lefttype;
Oid righttype;
CatCList *catlist;
int i;
/* Make sure output args are initialized even on failure */
*right_sortop = InvalidOid;
*opfamily = InvalidOid;
*opstrategy = 0;
/* Need the righthand input datatype */
op_input_types(eq_op, &lefttype, &righttype);
/*
* Search through all the pg_amop entries containing the equality operator
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(eq_op),
0, 0, 0);
for (i = 0; i < catlist->n_members; i++)
{
HeapTuple op_tuple = &catlist->members[i]->tuple;
Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
Oid opfamily_id;
StrategyNumber op_strategy;
/* must be btree */
if (op_form->amopmethod != BTREE_AM_OID)
continue;
/* must use the operator as equality */
if (op_form->amopstrategy != BTEqualStrategyNumber)
continue;
/* See if sort operator is also in this opfamily with OK semantics */
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
opfamily_id = op_form->amopfamily;
op_strategy = get_op_opfamily_strategy(left_sortop, opfamily_id);
if (op_strategy == BTLessStrategyNumber ||
op_strategy == BTGreaterStrategyNumber)
{
/* Yes, so find the corresponding righthand sortop */
*right_sortop = get_opfamily_member(opfamily_id,
righttype,
righttype,
op_strategy);
if (OidIsValid(*right_sortop))
{
/* Found a workable mergejoin semantics */
*opfamily = opfamily_id;
*opstrategy = op_strategy;
result = true;
break;
}
}
}
ReleaseSysCacheList(catlist);
return result;
}
#else
/* temp implementation until planner gets smarter: left_sortop is output */
bool
get_op_mergejoin_info(Oid eq_op, Oid *left_sortop,
Oid *right_sortop, Oid *opfamily)
{
bool result = false;
Oid lefttype;
Oid righttype;
CatCList *catlist;
int i;
/* Make sure output args are initialized even on failure */
*left_sortop = InvalidOid;
*right_sortop = InvalidOid;
*opfamily = InvalidOid;
/* Need the input datatypes */
op_input_types(eq_op, &lefttype, &righttype);
/*
* Search through all the pg_amop entries containing the equality operator
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(eq_op),
0, 0, 0);
for (i = 0; i < catlist->n_members; i++)
{
HeapTuple op_tuple = &catlist->members[i]->tuple;
Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
Oid opfamily_id;
/* must be btree */
if (op_form->amopmethod != BTREE_AM_OID)
continue;
/* must use the operator as equality */
if (op_form->amopstrategy != BTEqualStrategyNumber)
continue;
opfamily_id = op_form->amopfamily;
/* Find the matching sortops */
*left_sortop = get_opfamily_member(opfamily_id,
lefttype,
lefttype,
BTLessStrategyNumber);
*right_sortop = get_opfamily_member(opfamily_id,
righttype,
righttype,
BTLessStrategyNumber);
if (OidIsValid(*left_sortop) && OidIsValid(*right_sortop))
{
/* Found a workable mergejoin semantics */
*opfamily = opfamily_id;
result = true;
break;
}
}
ReleaseSysCacheList(catlist);
return result;
}
#endif
/*
* get_compare_function_for_ordering_op
* Get the OID of the datatype-specific btree comparison function
* associated with an ordering operator (a "<" or ">" operator).
*
* *cmpfunc receives the comparison function OID.
* *reverse is set FALSE if the operator is "<", TRUE if it's ">"
* (indicating the comparison result must be negated before use).
*
* Returns TRUE if successful, FALSE if no btree function can be found.
* (This indicates that the operator is not a valid ordering operator.)
*/
bool
get_compare_function_for_ordering_op(Oid opno, Oid *cmpfunc, bool *reverse)
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
{
bool result = false;
CatCList *catlist;
int i;
/* ensure outputs are set on failure */
*cmpfunc = InvalidOid;
*reverse = false;
/*
* Search pg_amop to see if the target operator is registered as the "<"
* or ">" operator of any btree opfamily. It's possible that it might be
* registered both ways (if someone were to build a "reverse sort"
* opfamily); assume we can use either interpretation. (Note: the
* existence of a reverse-sort opfamily would result in uncertainty as
* to whether "ORDER BY USING op" would default to NULLS FIRST or NULLS
* LAST. Since there is no longer any particularly good reason to build
* reverse-sort opfamilies, we don't bother expending any extra work to
* make this more determinate. In practice, because of the way the
* syscache search works, we'll use the interpretation associated with
* the opfamily with smallest OID, which is probably determinate enough.)
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(opno),
0, 0, 0);
for (i = 0; i < catlist->n_members; i++)
{
HeapTuple tuple = &catlist->members[i]->tuple;
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
/* must be btree */
if (aform->amopmethod != BTREE_AM_OID)
continue;
if (aform->amopstrategy == BTLessStrategyNumber ||
aform->amopstrategy == BTGreaterStrategyNumber)
{
/* Found a suitable opfamily, get matching support function */
*reverse = (aform->amopstrategy == BTGreaterStrategyNumber);
*cmpfunc = get_opfamily_proc(aform->amopfamily,
aform->amoplefttype,
aform->amoprighttype,
BTORDER_PROC);
if (!OidIsValid(*cmpfunc)) /* should not happen */
elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
BTORDER_PROC, aform->amoplefttype, aform->amoprighttype,
aform->amopfamily);
result = true;
break;
}
}
ReleaseSysCacheList(catlist);
return result;
}
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
/*
* get_equality_op_for_ordering_op
* Get the OID of the datatype-specific btree equality operator
* associated with an ordering operator (a "<" or ">" operator).
*
* Returns InvalidOid if no matching equality operator can be found.
* (This indicates that the operator is not a valid ordering operator.)
*/
Oid
get_equality_op_for_ordering_op(Oid opno)
{
Oid result = InvalidOid;
CatCList *catlist;
int i;
/*
* Search pg_amop to see if the target operator is registered as the "<"
* or ">" operator of any btree opfamily. This is exactly like
* get_compare_function_for_ordering_op except we don't care whether the
* ordering op is "<" or ">" ... the equality operator will be the same
* either way.
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(opno),
0, 0, 0);
for (i = 0; i < catlist->n_members; i++)
{
HeapTuple tuple = &catlist->members[i]->tuple;
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
/* must be btree */
if (aform->amopmethod != BTREE_AM_OID)
continue;
if (aform->amopstrategy == BTLessStrategyNumber ||
aform->amopstrategy == BTGreaterStrategyNumber)
{
/* Found a suitable opfamily, get matching equality operator */
result = get_opfamily_member(aform->amopfamily,
aform->amoplefttype,
aform->amoprighttype,
BTEqualStrategyNumber);
if (OidIsValid(result))
break;
/* failure probably shouldn't happen, but keep looking if so */
}
}
ReleaseSysCacheList(catlist);
return result;
}
/*
* get_ordering_op_for_equality_op
* Get the OID of a datatype-specific btree ordering operator
* associated with an equality operator. (If there are multiple
* possibilities, assume any one will do.)
*
* This function is used when we have to sort data before unique-ifying,
* and don't much care which sorting op is used as long as it's compatible
* with the intended equality operator. Since we need a sorting operator,
* it should be single-data-type even if the given operator is cross-type.
* The caller specifies whether to find an op for the LHS or RHS data type.
*
* Returns InvalidOid if no matching ordering operator can be found.
*/
Oid
get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type)
{
Oid result = InvalidOid;
CatCList *catlist;
int i;
/*
* Search pg_amop to see if the target operator is registered as the "="
* operator of any btree opfamily.
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(opno),
0, 0, 0);
for (i = 0; i < catlist->n_members; i++)
{
HeapTuple tuple = &catlist->members[i]->tuple;
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
/* must be btree */
if (aform->amopmethod != BTREE_AM_OID)
continue;
if (aform->amopstrategy == BTEqualStrategyNumber)
{
/* Found a suitable opfamily, get matching ordering operator */
Oid typid;
typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
result = get_opfamily_member(aform->amopfamily,
typid, typid,
BTLessStrategyNumber);
if (OidIsValid(result))
break;
/* failure probably shouldn't happen, but keep looking if so */
}
}
ReleaseSysCacheList(catlist);
return result;
}
/*
* get_compatible_hash_operator
* Get the OID of a hash equality operator compatible with the given
* operator, but operating on its LHS or RHS datatype as specified.
*
* If the given operator is not cross-type, the result should be the same
* operator, but in cross-type situations it is different.
*
* Returns InvalidOid if no compatible operator can be found. (This indicates
* that the operator should not have been marked oprcanhash.)
*/
Oid
get_compatible_hash_operator(Oid opno, bool use_lhs_type)
{
Oid result = InvalidOid;
CatCList *catlist;
int i;
/*
* Search pg_amop to see if the target operator is registered as the "="
* operator of any hash opfamily. If the operator is registered in
* multiple opfamilies, assume we can use any one.
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(opno),
0, 0, 0);
for (i = 0; i < catlist->n_members; i++)
{
HeapTuple tuple = &catlist->members[i]->tuple;
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
if (aform->amopmethod == HASH_AM_OID &&
aform->amopstrategy == HTEqualStrategyNumber)
{
/* Found a suitable opfamily, get matching single-type operator */
Oid typid;
/* No extra lookup needed if given operator is single-type */
if (aform->amoplefttype == aform->amoprighttype)
{
result = opno;
break;
}
typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
result = get_opfamily_member(aform->amopfamily,
typid, typid,
HTEqualStrategyNumber);
if (OidIsValid(result))
break;
/* failure probably shouldn't happen, but keep looking if so */
}
}
ReleaseSysCacheList(catlist);
return result;
}
/*
* get_op_hash_function
* Get the OID of the datatype-specific hash function associated with
* a hashable equality operator.
*
* XXX API needs to be generalized for the case of different left and right
* datatypes.
*
* Returns InvalidOid if no hash function can be found. (This indicates
* that the operator should not have been marked oprcanhash.)
*/
Oid
get_op_hash_function(Oid opno)
{
Oid result = InvalidOid;
CatCList *catlist;
int i;
/*
* Search pg_amop to see if the target operator is registered as the "="
* operator of any hash opfamily. If the operator is registered in
* multiple opfamilies, assume we can use the associated hash function from
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(opno),
0, 0, 0);
for (i = 0; i < catlist->n_members; i++)
{
HeapTuple tuple = &catlist->members[i]->tuple;
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
if (aform->amopmethod == HASH_AM_OID &&
aform->amopstrategy == HTEqualStrategyNumber)
/* Found a suitable opfamily, get matching hash support function */
result = get_opfamily_proc(aform->amopfamily,
aform->amoplefttype,
aform->amoprighttype,
HASHPROC);
break;
}
}
ReleaseSysCacheList(catlist);
return result;
/*
* get_op_btree_interpretation
* Given an operator's OID, find out which btree opfamilies it belongs to,
* and what strategy number it has within each one. The results are
* returned as an OID list and a parallel integer list.
*
* In addition to the normal btree operators, we consider a <> operator to be
* a "member" of an opfamily if its negator is an equality operator of the
* opfamily. ROWCOMPARE_NE is returned as the strategy number for this case.
*/
void
get_op_btree_interpretation(Oid opno, List **opfamilies, List **opstrats)
{
CatCList *catlist;
bool op_negated;
int i;
*opfamilies = NIL;
*opstrats = NIL;
/*
* Find all the pg_amop entries containing the operator.
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(opno),
0, 0, 0);
* If we can't find any opfamily containing the op, perhaps it is a <>
* operator. See if it has a negator that is in an opfamily.
*/
op_negated = false;
if (catlist->n_members == 0)
{
if (OidIsValid(op_negator))
{
op_negated = true;
ReleaseSysCacheList(catlist);
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(op_negator),
0, 0, 0);
}
}
/* Now search the opfamilies */
for (i = 0; i < catlist->n_members; i++)
{
HeapTuple op_tuple = &catlist->members[i]->tuple;
Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
Oid opfamily_id;
StrategyNumber op_strategy;
/* must be btree */
if (op_form->amopmethod != BTREE_AM_OID)
continue;
/* Get the operator's btree strategy number */
opfamily_id = op_form->amopfamily;
op_strategy = (StrategyNumber) op_form->amopstrategy;
Assert(op_strategy >= 1 && op_strategy <= 5);
if (op_negated)
{
/* Only consider negators that are = */
if (op_strategy != BTEqualStrategyNumber)
continue;
op_strategy = ROWCOMPARE_NE;
}
*opfamilies = lappend_oid(*opfamilies, opfamily_id);
*opstrats = lappend_int(*opstrats, op_strategy);
}
ReleaseSysCacheList(catlist);
}
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
/*
* ops_in_same_btree_opfamily
* Return TRUE if there exists a btree opfamily containing both operators.
* (This implies that they have compatible notions of equality.)
*/
bool
ops_in_same_btree_opfamily(Oid opno1, Oid opno2)
{
bool result = false;
CatCList *catlist;
int i;
/*
* We search through all the pg_amop entries for opno1.
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(opno1),
0, 0, 0);
for (i = 0; i < catlist->n_members; i++)
{
HeapTuple op_tuple = &catlist->members[i]->tuple;
Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
/* must be btree */
if (op_form->amopmethod != BTREE_AM_OID)
continue;
if (op_in_opfamily(opno2, op_form->amopfamily))
{
result = true;
break;
}
}
ReleaseSysCacheList(catlist);
return result;
}
/* ---------- AMPROC CACHES ---------- */
/*
* get_opfamily_proc
* Get the OID of the specified support function
* for the specified opfamily and datatypes.
*
* Returns InvalidOid if there is no pg_amproc entry for the given keys.
*/
Oid
get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
{
HeapTuple tp;
Form_pg_amproc amproc_tup;
RegProcedure result;
tp = SearchSysCache(AMPROCNUM,
ObjectIdGetDatum(opfamily),
ObjectIdGetDatum(lefttype),
ObjectIdGetDatum(righttype),
Int16GetDatum(procnum));
if (!HeapTupleIsValid(tp))
return InvalidOid;
amproc_tup = (Form_pg_amproc) GETSTRUCT(tp);
result = amproc_tup->amproc;
ReleaseSysCache(tp);
return result;
}
/* ---------- ATTRIBUTE CACHES ---------- */
* get_attname
* Given the relation id and the attribute number,
* return the "attname" field from the attribute relation.
* Note: returns a palloc'd copy of the string, or NULL if no such attribute.
get_attname(Oid relid, AttrNumber attnum)
{
tp = SearchSysCache(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum),
0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
result = pstrdup(NameStr(att_tup->attname));
ReleaseSysCache(tp);
return result;
/*
* get_relid_attribute_name
*
* Same as above routine get_attname(), except that error
* is handled by elog() instead of returning NULL.
*/
char *
get_relid_attribute_name(Oid relid, AttrNumber attnum)
{
char *attname;
attname = get_attname(relid, attnum);
if (attname == NULL)
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
attnum, relid);
return attname;
}
* get_attnum
*
* Given the relation id and the attribute name,
* return the "attnum" field from the attribute relation.
*
* Returns InvalidAttrNumber if the attr doesn't exist (or is dropped).
get_attnum(Oid relid, const char *attname)
tp = SearchSysCacheAttName(relid, attname);
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
AttrNumber result;
result = att_tup->attnum;
ReleaseSysCache(tp);
return result;
* get_atttype
*
* Given the relation OID and the attribute number with the relation,
* return the attribute type OID.
*/
Oid
get_atttype(Oid relid, AttrNumber attnum)
{
tp = SearchSysCache(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum),
0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
result = att_tup->atttypid;
ReleaseSysCache(tp);
return result;
return InvalidOid;
* get_atttypmod
*
* Given the relation id and the attribute number,
* return the "atttypmod" field from the attribute relation.
*/
tp = SearchSysCache(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum),
0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
result = att_tup->atttypmod;
ReleaseSysCache(tp);
return result;
/*
* get_atttypetypmod
*
* A two-fer: given the relation id and the attribute number,
* fetch both type OID and atttypmod in a single cache lookup.
*
* Unlike the otherwise-similar get_atttype/get_atttypmod, this routine
* raises an error if it can't obtain the information.
*/
void
get_atttypetypmod(Oid relid, AttrNumber attnum,
Oid *typid, int32 *typmod)
{
HeapTuple tp;
Form_pg_attribute att_tup;
tp = SearchSysCache(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum),
0, 0);
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
attnum, relid);
att_tup = (Form_pg_attribute) GETSTRUCT(tp);
*typid = att_tup->atttypid;
*typmod = att_tup->atttypmod;
ReleaseSysCache(tp);
}
/* ---------- INDEX CACHE ---------- */
/* watch this space...
/* ---------- OPCLASS CACHE ---------- */
/*
* get_opclass_family
* Returns the OID of the operator family the opclass belongs to.
*/
Oid
get_opclass_family(Oid opclass)
{
HeapTuple tp;
Form_pg_opclass cla_tup;
Oid result;
tp = SearchSysCache(CLAOID,
ObjectIdGetDatum(opclass),
0, 0, 0);
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for opclass %u", opclass);
cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
result = cla_tup->opcfamily;
ReleaseSysCache(tp);
return result;
}
/*
* get_opclass_input_type
*
* Returns the OID of the datatype the opclass indexes.
*/
Oid
get_opclass_input_type(Oid opclass)
{
HeapTuple tp;
Form_pg_opclass cla_tup;
Oid result;
tp = SearchSysCache(CLAOID,
ObjectIdGetDatum(opclass),
0, 0, 0);
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for opclass %u", opclass);
cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
result = cla_tup->opcintype;
ReleaseSysCache(tp);
return result;
}
/* ---------- OPERATOR CACHE ---------- */
* get_opcode
*
* Returns the regproc id of the routine used to implement an
* operator given the operator oid.
*/
RegProcedure
get_opcode(Oid opno)
{
tp = SearchSysCache(OPEROID,
ObjectIdGetDatum(opno),
0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
result = optup->oprcode;
ReleaseSysCache(tp);
return result;
return (RegProcedure) InvalidOid;
* get_opname
* returns the name of the operator with the given opno
* Note: returns a palloc'd copy of the string, or NULL if no such operator.
get_opname(Oid opno)
{
tp = SearchSysCache(OPEROID,
ObjectIdGetDatum(opno),
0, 0, 0);
if (HeapTupleIsValid(tp))
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
result = pstrdup(NameStr(optup->oprname));
ReleaseSysCache(tp);
return result;
else
return NULL;