1 /*-------------------------------------------------------------------------
2  *
3  * syscache.c
4  *	  System cache management routines
5  *
6  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/backend/utils/cache/syscache.c
12  *
13  * NOTES
14  *	  These routines allow the parser/planner/executor to perform
15  *	  rapid lookups on the contents of the system catalogs.
16  *
17  *	  see utils/syscache.h for a list of the cache IDs
18  *
19  *-------------------------------------------------------------------------
20  */
21 #include "postgres.h"
22 
23 #include "access/htup_details.h"
24 #include "access/sysattr.h"
25 #include "catalog/indexing.h"
26 #include "catalog/pg_aggregate.h"
27 #include "catalog/pg_am.h"
28 #include "catalog/pg_amop.h"
29 #include "catalog/pg_amproc.h"
30 #include "catalog/pg_auth_members.h"
31 #include "catalog/pg_authid.h"
32 #include "catalog/pg_cast.h"
33 #include "catalog/pg_collation.h"
34 #include "catalog/pg_constraint.h"
35 #include "catalog/pg_conversion.h"
36 #include "catalog/pg_database.h"
37 #include "catalog/pg_db_role_setting.h"
38 #include "catalog/pg_default_acl.h"
39 #include "catalog/pg_depend.h"
40 #include "catalog/pg_description.h"
41 #include "catalog/pg_enum.h"
42 #include "catalog/pg_event_trigger.h"
43 #include "catalog/pg_foreign_data_wrapper.h"
44 #include "catalog/pg_foreign_server.h"
45 #include "catalog/pg_foreign_table.h"
46 #include "catalog/pg_language.h"
47 #include "catalog/pg_namespace.h"
48 #include "catalog/pg_opclass.h"
49 #include "catalog/pg_operator.h"
50 #include "catalog/pg_opfamily.h"
51 #include "catalog/pg_partitioned_table.h"
52 #include "catalog/pg_proc.h"
53 #include "catalog/pg_publication.h"
54 #include "catalog/pg_publication_rel.h"
55 #include "catalog/pg_range.h"
56 #include "catalog/pg_replication_origin.h"
57 #include "catalog/pg_rewrite.h"
58 #include "catalog/pg_seclabel.h"
59 #include "catalog/pg_sequence.h"
60 #include "catalog/pg_shdepend.h"
61 #include "catalog/pg_shdescription.h"
62 #include "catalog/pg_shseclabel.h"
63 #include "catalog/pg_statistic.h"
64 #include "catalog/pg_statistic_ext.h"
65 #include "catalog/pg_statistic_ext_data.h"
66 #include "catalog/pg_subscription.h"
67 #include "catalog/pg_subscription_rel.h"
68 #include "catalog/pg_tablespace.h"
69 #include "catalog/pg_transform.h"
70 #include "catalog/pg_ts_config.h"
71 #include "catalog/pg_ts_config_map.h"
72 #include "catalog/pg_ts_dict.h"
73 #include "catalog/pg_ts_parser.h"
74 #include "catalog/pg_ts_template.h"
75 #include "catalog/pg_type.h"
76 #include "catalog/pg_user_mapping.h"
77 #include "lib/qunique.h"
78 #include "utils/catcache.h"
79 #include "utils/rel.h"
80 #include "utils/syscache.h"
81 
82 /*---------------------------------------------------------------------------
83 
84 	Adding system caches:
85 
86 	Add your new cache to the list in include/utils/syscache.h.
87 	Keep the list sorted alphabetically.
88 
89 	Add your entry to the cacheinfo[] array below. All cache lists are
90 	alphabetical, so add it in the proper place.  Specify the relation OID,
91 	index OID, number of keys, key attribute numbers, and initial number of
92 	hash buckets.
93 
94 	The number of hash buckets must be a power of 2.  It's reasonable to
95 	set this to the number of entries that might be in the particular cache
96 	in a medium-size database.
97 
98 	There must be a unique index underlying each syscache (ie, an index
99 	whose key is the same as that of the cache).  If there is not one
100 	already, add definitions for it to include/catalog/indexing.h: you need
101 	to add a DECLARE_UNIQUE_INDEX macro and a #define for the index OID.
102 	(Adding an index requires a catversion.h update, while simply
103 	adding/deleting caches only requires a recompile.)
104 
105 	Finally, any place your relation gets heap_insert() or
106 	heap_update() calls, use CatalogTupleInsert() or CatalogTupleUpdate()
107 	instead, which also update indexes.  The heap_* calls do not do that.
108 
109 *---------------------------------------------------------------------------
110 */
111 
112 /*
113  *		struct cachedesc: information defining a single syscache
114  */
115 struct cachedesc
116 {
117 	Oid			reloid;			/* OID of the relation being cached */
118 	Oid			indoid;			/* OID of index relation for this cache */
119 	int			nkeys;			/* # of keys needed for cache lookup */
120 	int			key[4];			/* attribute numbers of key attrs */
121 	int			nbuckets;		/* number of hash buckets for this cache */
122 };
123 
124 static const struct cachedesc cacheinfo[] = {
125 	{AggregateRelationId,		/* AGGFNOID */
126 		AggregateFnoidIndexId,
127 		1,
128 		{
129 			Anum_pg_aggregate_aggfnoid,
130 			0,
131 			0,
132 			0
133 		},
134 		16
135 	},
136 	{AccessMethodRelationId,	/* AMNAME */
137 		AmNameIndexId,
138 		1,
139 		{
140 			Anum_pg_am_amname,
141 			0,
142 			0,
143 			0
144 		},
145 		4
146 	},
147 	{AccessMethodRelationId,	/* AMOID */
148 		AmOidIndexId,
149 		1,
150 		{
151 			Anum_pg_am_oid,
152 			0,
153 			0,
154 			0
155 		},
156 		4
157 	},
158 	{AccessMethodOperatorRelationId,	/* AMOPOPID */
159 		AccessMethodOperatorIndexId,
160 		3,
161 		{
162 			Anum_pg_amop_amopopr,
163 			Anum_pg_amop_amoppurpose,
164 			Anum_pg_amop_amopfamily,
165 			0
166 		},
167 		64
168 	},
169 	{AccessMethodOperatorRelationId,	/* AMOPSTRATEGY */
170 		AccessMethodStrategyIndexId,
171 		4,
172 		{
173 			Anum_pg_amop_amopfamily,
174 			Anum_pg_amop_amoplefttype,
175 			Anum_pg_amop_amoprighttype,
176 			Anum_pg_amop_amopstrategy
177 		},
178 		64
179 	},
180 	{AccessMethodProcedureRelationId,	/* AMPROCNUM */
181 		AccessMethodProcedureIndexId,
182 		4,
183 		{
184 			Anum_pg_amproc_amprocfamily,
185 			Anum_pg_amproc_amproclefttype,
186 			Anum_pg_amproc_amprocrighttype,
187 			Anum_pg_amproc_amprocnum
188 		},
189 		16
190 	},
191 	{AttributeRelationId,		/* ATTNAME */
192 		AttributeRelidNameIndexId,
193 		2,
194 		{
195 			Anum_pg_attribute_attrelid,
196 			Anum_pg_attribute_attname,
197 			0,
198 			0
199 		},
200 		32
201 	},
202 	{AttributeRelationId,		/* ATTNUM */
203 		AttributeRelidNumIndexId,
204 		2,
205 		{
206 			Anum_pg_attribute_attrelid,
207 			Anum_pg_attribute_attnum,
208 			0,
209 			0
210 		},
211 		128
212 	},
213 	{AuthMemRelationId,			/* AUTHMEMMEMROLE */
214 		AuthMemMemRoleIndexId,
215 		2,
216 		{
217 			Anum_pg_auth_members_member,
218 			Anum_pg_auth_members_roleid,
219 			0,
220 			0
221 		},
222 		8
223 	},
224 	{AuthMemRelationId,			/* AUTHMEMROLEMEM */
225 		AuthMemRoleMemIndexId,
226 		2,
227 		{
228 			Anum_pg_auth_members_roleid,
229 			Anum_pg_auth_members_member,
230 			0,
231 			0
232 		},
233 		8
234 	},
235 	{AuthIdRelationId,			/* AUTHNAME */
236 		AuthIdRolnameIndexId,
237 		1,
238 		{
239 			Anum_pg_authid_rolname,
240 			0,
241 			0,
242 			0
243 		},
244 		8
245 	},
246 	{AuthIdRelationId,			/* AUTHOID */
247 		AuthIdOidIndexId,
248 		1,
249 		{
250 			Anum_pg_authid_oid,
251 			0,
252 			0,
253 			0
254 		},
255 		8
256 	},
257 	{
258 		CastRelationId,			/* CASTSOURCETARGET */
259 		CastSourceTargetIndexId,
260 		2,
261 		{
262 			Anum_pg_cast_castsource,
263 			Anum_pg_cast_casttarget,
264 			0,
265 			0
266 		},
267 		256
268 	},
269 	{OperatorClassRelationId,	/* CLAAMNAMENSP */
270 		OpclassAmNameNspIndexId,
271 		3,
272 		{
273 			Anum_pg_opclass_opcmethod,
274 			Anum_pg_opclass_opcname,
275 			Anum_pg_opclass_opcnamespace,
276 			0
277 		},
278 		8
279 	},
280 	{OperatorClassRelationId,	/* CLAOID */
281 		OpclassOidIndexId,
282 		1,
283 		{
284 			Anum_pg_opclass_oid,
285 			0,
286 			0,
287 			0
288 		},
289 		8
290 	},
291 	{CollationRelationId,		/* COLLNAMEENCNSP */
292 		CollationNameEncNspIndexId,
293 		3,
294 		{
295 			Anum_pg_collation_collname,
296 			Anum_pg_collation_collencoding,
297 			Anum_pg_collation_collnamespace,
298 			0
299 		},
300 		8
301 	},
302 	{CollationRelationId,		/* COLLOID */
303 		CollationOidIndexId,
304 		1,
305 		{
306 			Anum_pg_collation_oid,
307 			0,
308 			0,
309 			0
310 		},
311 		8
312 	},
313 	{ConversionRelationId,		/* CONDEFAULT */
314 		ConversionDefaultIndexId,
315 		4,
316 		{
317 			Anum_pg_conversion_connamespace,
318 			Anum_pg_conversion_conforencoding,
319 			Anum_pg_conversion_contoencoding,
320 			Anum_pg_conversion_oid
321 		},
322 		8
323 	},
324 	{ConversionRelationId,		/* CONNAMENSP */
325 		ConversionNameNspIndexId,
326 		2,
327 		{
328 			Anum_pg_conversion_conname,
329 			Anum_pg_conversion_connamespace,
330 			0,
331 			0
332 		},
333 		8
334 	},
335 	{ConstraintRelationId,		/* CONSTROID */
336 		ConstraintOidIndexId,
337 		1,
338 		{
339 			Anum_pg_constraint_oid,
340 			0,
341 			0,
342 			0
343 		},
344 		16
345 	},
346 	{ConversionRelationId,		/* CONVOID */
347 		ConversionOidIndexId,
348 		1,
349 		{
350 			Anum_pg_conversion_oid,
351 			0,
352 			0,
353 			0
354 		},
355 		8
356 	},
357 	{DatabaseRelationId,		/* DATABASEOID */
358 		DatabaseOidIndexId,
359 		1,
360 		{
361 			Anum_pg_database_oid,
362 			0,
363 			0,
364 			0
365 		},
366 		4
367 	},
368 	{DefaultAclRelationId,		/* DEFACLROLENSPOBJ */
369 		DefaultAclRoleNspObjIndexId,
370 		3,
371 		{
372 			Anum_pg_default_acl_defaclrole,
373 			Anum_pg_default_acl_defaclnamespace,
374 			Anum_pg_default_acl_defaclobjtype,
375 			0
376 		},
377 		8
378 	},
379 	{EnumRelationId,			/* ENUMOID */
380 		EnumOidIndexId,
381 		1,
382 		{
383 			Anum_pg_enum_oid,
384 			0,
385 			0,
386 			0
387 		},
388 		8
389 	},
390 	{EnumRelationId,			/* ENUMTYPOIDNAME */
391 		EnumTypIdLabelIndexId,
392 		2,
393 		{
394 			Anum_pg_enum_enumtypid,
395 			Anum_pg_enum_enumlabel,
396 			0,
397 			0
398 		},
399 		8
400 	},
401 	{EventTriggerRelationId,	/* EVENTTRIGGERNAME */
402 		EventTriggerNameIndexId,
403 		1,
404 		{
405 			Anum_pg_event_trigger_evtname,
406 			0,
407 			0,
408 			0
409 		},
410 		8
411 	},
412 	{EventTriggerRelationId,	/* EVENTTRIGGEROID */
413 		EventTriggerOidIndexId,
414 		1,
415 		{
416 			Anum_pg_event_trigger_oid,
417 			0,
418 			0,
419 			0
420 		},
421 		8
422 	},
423 	{ForeignDataWrapperRelationId,	/* FOREIGNDATAWRAPPERNAME */
424 		ForeignDataWrapperNameIndexId,
425 		1,
426 		{
427 			Anum_pg_foreign_data_wrapper_fdwname,
428 			0,
429 			0,
430 			0
431 		},
432 		2
433 	},
434 	{ForeignDataWrapperRelationId,	/* FOREIGNDATAWRAPPEROID */
435 		ForeignDataWrapperOidIndexId,
436 		1,
437 		{
438 			Anum_pg_foreign_data_wrapper_oid,
439 			0,
440 			0,
441 			0
442 		},
443 		2
444 	},
445 	{ForeignServerRelationId,	/* FOREIGNSERVERNAME */
446 		ForeignServerNameIndexId,
447 		1,
448 		{
449 			Anum_pg_foreign_server_srvname,
450 			0,
451 			0,
452 			0
453 		},
454 		2
455 	},
456 	{ForeignServerRelationId,	/* FOREIGNSERVEROID */
457 		ForeignServerOidIndexId,
458 		1,
459 		{
460 			Anum_pg_foreign_server_oid,
461 			0,
462 			0,
463 			0
464 		},
465 		2
466 	},
467 	{ForeignTableRelationId,	/* FOREIGNTABLEREL */
468 		ForeignTableRelidIndexId,
469 		1,
470 		{
471 			Anum_pg_foreign_table_ftrelid,
472 			0,
473 			0,
474 			0
475 		},
476 		4
477 	},
478 	{IndexRelationId,			/* INDEXRELID */
479 		IndexRelidIndexId,
480 		1,
481 		{
482 			Anum_pg_index_indexrelid,
483 			0,
484 			0,
485 			0
486 		},
487 		64
488 	},
489 	{LanguageRelationId,		/* LANGNAME */
490 		LanguageNameIndexId,
491 		1,
492 		{
493 			Anum_pg_language_lanname,
494 			0,
495 			0,
496 			0
497 		},
498 		4
499 	},
500 	{LanguageRelationId,		/* LANGOID */
501 		LanguageOidIndexId,
502 		1,
503 		{
504 			Anum_pg_language_oid,
505 			0,
506 			0,
507 			0
508 		},
509 		4
510 	},
511 	{NamespaceRelationId,		/* NAMESPACENAME */
512 		NamespaceNameIndexId,
513 		1,
514 		{
515 			Anum_pg_namespace_nspname,
516 			0,
517 			0,
518 			0
519 		},
520 		4
521 	},
522 	{NamespaceRelationId,		/* NAMESPACEOID */
523 		NamespaceOidIndexId,
524 		1,
525 		{
526 			Anum_pg_namespace_oid,
527 			0,
528 			0,
529 			0
530 		},
531 		16
532 	},
533 	{OperatorRelationId,		/* OPERNAMENSP */
534 		OperatorNameNspIndexId,
535 		4,
536 		{
537 			Anum_pg_operator_oprname,
538 			Anum_pg_operator_oprleft,
539 			Anum_pg_operator_oprright,
540 			Anum_pg_operator_oprnamespace
541 		},
542 		256
543 	},
544 	{OperatorRelationId,		/* OPEROID */
545 		OperatorOidIndexId,
546 		1,
547 		{
548 			Anum_pg_operator_oid,
549 			0,
550 			0,
551 			0
552 		},
553 		32
554 	},
555 	{OperatorFamilyRelationId,	/* OPFAMILYAMNAMENSP */
556 		OpfamilyAmNameNspIndexId,
557 		3,
558 		{
559 			Anum_pg_opfamily_opfmethod,
560 			Anum_pg_opfamily_opfname,
561 			Anum_pg_opfamily_opfnamespace,
562 			0
563 		},
564 		8
565 	},
566 	{OperatorFamilyRelationId,	/* OPFAMILYOID */
567 		OpfamilyOidIndexId,
568 		1,
569 		{
570 			Anum_pg_opfamily_oid,
571 			0,
572 			0,
573 			0
574 		},
575 		8
576 	},
577 	{PartitionedRelationId,		/* PARTRELID */
578 		PartitionedRelidIndexId,
579 		1,
580 		{
581 			Anum_pg_partitioned_table_partrelid,
582 			0,
583 			0,
584 			0
585 		},
586 		32
587 	},
588 	{ProcedureRelationId,		/* PROCNAMEARGSNSP */
589 		ProcedureNameArgsNspIndexId,
590 		3,
591 		{
592 			Anum_pg_proc_proname,
593 			Anum_pg_proc_proargtypes,
594 			Anum_pg_proc_pronamespace,
595 			0
596 		},
597 		128
598 	},
599 	{ProcedureRelationId,		/* PROCOID */
600 		ProcedureOidIndexId,
601 		1,
602 		{
603 			Anum_pg_proc_oid,
604 			0,
605 			0,
606 			0
607 		},
608 		128
609 	},
610 	{PublicationRelationId,		/* PUBLICATIONNAME */
611 		PublicationNameIndexId,
612 		1,
613 		{
614 			Anum_pg_publication_pubname,
615 			0,
616 			0,
617 			0
618 		},
619 		8
620 	},
621 	{PublicationRelationId,		/* PUBLICATIONOID */
622 		PublicationObjectIndexId,
623 		1,
624 		{
625 			Anum_pg_publication_oid,
626 			0,
627 			0,
628 			0
629 		},
630 		8
631 	},
632 	{PublicationRelRelationId,	/* PUBLICATIONREL */
633 		PublicationRelObjectIndexId,
634 		1,
635 		{
636 			Anum_pg_publication_rel_oid,
637 			0,
638 			0,
639 			0
640 		},
641 		64
642 	},
643 	{PublicationRelRelationId,	/* PUBLICATIONRELMAP */
644 		PublicationRelPrrelidPrpubidIndexId,
645 		2,
646 		{
647 			Anum_pg_publication_rel_prrelid,
648 			Anum_pg_publication_rel_prpubid,
649 			0,
650 			0
651 		},
652 		64
653 	},
654 	{RangeRelationId,			/* RANGETYPE */
655 		RangeTypidIndexId,
656 		1,
657 		{
658 			Anum_pg_range_rngtypid,
659 			0,
660 			0,
661 			0
662 		},
663 		4
664 	},
665 	{RelationRelationId,		/* RELNAMENSP */
666 		ClassNameNspIndexId,
667 		2,
668 		{
669 			Anum_pg_class_relname,
670 			Anum_pg_class_relnamespace,
671 			0,
672 			0
673 		},
674 		128
675 	},
676 	{RelationRelationId,		/* RELOID */
677 		ClassOidIndexId,
678 		1,
679 		{
680 			Anum_pg_class_oid,
681 			0,
682 			0,
683 			0
684 		},
685 		128
686 	},
687 	{ReplicationOriginRelationId,	/* REPLORIGIDENT */
688 		ReplicationOriginIdentIndex,
689 		1,
690 		{
691 			Anum_pg_replication_origin_roident,
692 			0,
693 			0,
694 			0
695 		},
696 		16
697 	},
698 	{ReplicationOriginRelationId,	/* REPLORIGNAME */
699 		ReplicationOriginNameIndex,
700 		1,
701 		{
702 			Anum_pg_replication_origin_roname,
703 			0,
704 			0,
705 			0
706 		},
707 		16
708 	},
709 	{RewriteRelationId,			/* RULERELNAME */
710 		RewriteRelRulenameIndexId,
711 		2,
712 		{
713 			Anum_pg_rewrite_ev_class,
714 			Anum_pg_rewrite_rulename,
715 			0,
716 			0
717 		},
718 		8
719 	},
720 	{SequenceRelationId,		/* SEQRELID */
721 		SequenceRelidIndexId,
722 		1,
723 		{
724 			Anum_pg_sequence_seqrelid,
725 			0,
726 			0,
727 			0
728 		},
729 		32
730 	},
731 	{StatisticExtDataRelationId,	/* STATEXTDATASTXOID */
732 		StatisticExtDataStxoidIndexId,
733 		1,
734 		{
735 			Anum_pg_statistic_ext_data_stxoid,
736 			0,
737 			0,
738 			0
739 		},
740 		4
741 	},
742 	{StatisticExtRelationId,	/* STATEXTNAMENSP */
743 		StatisticExtNameIndexId,
744 		2,
745 		{
746 			Anum_pg_statistic_ext_stxname,
747 			Anum_pg_statistic_ext_stxnamespace,
748 			0,
749 			0
750 		},
751 		4
752 	},
753 	{StatisticExtRelationId,	/* STATEXTOID */
754 		StatisticExtOidIndexId,
755 		1,
756 		{
757 			Anum_pg_statistic_ext_oid,
758 			0,
759 			0,
760 			0
761 		},
762 		4
763 	},
764 	{StatisticRelationId,		/* STATRELATTINH */
765 		StatisticRelidAttnumInhIndexId,
766 		3,
767 		{
768 			Anum_pg_statistic_starelid,
769 			Anum_pg_statistic_staattnum,
770 			Anum_pg_statistic_stainherit,
771 			0
772 		},
773 		128
774 	},
775 	{SubscriptionRelationId,	/* SUBSCRIPTIONNAME */
776 		SubscriptionNameIndexId,
777 		2,
778 		{
779 			Anum_pg_subscription_subdbid,
780 			Anum_pg_subscription_subname,
781 			0,
782 			0
783 		},
784 		4
785 	},
786 	{SubscriptionRelationId,	/* SUBSCRIPTIONOID */
787 		SubscriptionObjectIndexId,
788 		1,
789 		{
790 			Anum_pg_subscription_oid,
791 			0,
792 			0,
793 			0
794 		},
795 		4
796 	},
797 	{SubscriptionRelRelationId, /* SUBSCRIPTIONRELMAP */
798 		SubscriptionRelSrrelidSrsubidIndexId,
799 		2,
800 		{
801 			Anum_pg_subscription_rel_srrelid,
802 			Anum_pg_subscription_rel_srsubid,
803 			0,
804 			0
805 		},
806 		64
807 	},
808 	{TableSpaceRelationId,		/* TABLESPACEOID */
809 		TablespaceOidIndexId,
810 		1,
811 		{
812 			Anum_pg_tablespace_oid,
813 			0,
814 			0,
815 			0,
816 		},
817 		4
818 	},
819 	{TransformRelationId,		/* TRFOID */
820 		TransformOidIndexId,
821 		1,
822 		{
823 			Anum_pg_transform_oid,
824 			0,
825 			0,
826 			0,
827 		},
828 		16
829 	},
830 	{TransformRelationId,		/* TRFTYPELANG */
831 		TransformTypeLangIndexId,
832 		2,
833 		{
834 			Anum_pg_transform_trftype,
835 			Anum_pg_transform_trflang,
836 			0,
837 			0,
838 		},
839 		16
840 	},
841 	{TSConfigMapRelationId,		/* TSCONFIGMAP */
842 		TSConfigMapIndexId,
843 		3,
844 		{
845 			Anum_pg_ts_config_map_mapcfg,
846 			Anum_pg_ts_config_map_maptokentype,
847 			Anum_pg_ts_config_map_mapseqno,
848 			0
849 		},
850 		2
851 	},
852 	{TSConfigRelationId,		/* TSCONFIGNAMENSP */
853 		TSConfigNameNspIndexId,
854 		2,
855 		{
856 			Anum_pg_ts_config_cfgname,
857 			Anum_pg_ts_config_cfgnamespace,
858 			0,
859 			0
860 		},
861 		2
862 	},
863 	{TSConfigRelationId,		/* TSCONFIGOID */
864 		TSConfigOidIndexId,
865 		1,
866 		{
867 			Anum_pg_ts_config_oid,
868 			0,
869 			0,
870 			0
871 		},
872 		2
873 	},
874 	{TSDictionaryRelationId,	/* TSDICTNAMENSP */
875 		TSDictionaryNameNspIndexId,
876 		2,
877 		{
878 			Anum_pg_ts_dict_dictname,
879 			Anum_pg_ts_dict_dictnamespace,
880 			0,
881 			0
882 		},
883 		2
884 	},
885 	{TSDictionaryRelationId,	/* TSDICTOID */
886 		TSDictionaryOidIndexId,
887 		1,
888 		{
889 			Anum_pg_ts_dict_oid,
890 			0,
891 			0,
892 			0
893 		},
894 		2
895 	},
896 	{TSParserRelationId,		/* TSPARSERNAMENSP */
897 		TSParserNameNspIndexId,
898 		2,
899 		{
900 			Anum_pg_ts_parser_prsname,
901 			Anum_pg_ts_parser_prsnamespace,
902 			0,
903 			0
904 		},
905 		2
906 	},
907 	{TSParserRelationId,		/* TSPARSEROID */
908 		TSParserOidIndexId,
909 		1,
910 		{
911 			Anum_pg_ts_parser_oid,
912 			0,
913 			0,
914 			0
915 		},
916 		2
917 	},
918 	{TSTemplateRelationId,		/* TSTEMPLATENAMENSP */
919 		TSTemplateNameNspIndexId,
920 		2,
921 		{
922 			Anum_pg_ts_template_tmplname,
923 			Anum_pg_ts_template_tmplnamespace,
924 			0,
925 			0
926 		},
927 		2
928 	},
929 	{TSTemplateRelationId,		/* TSTEMPLATEOID */
930 		TSTemplateOidIndexId,
931 		1,
932 		{
933 			Anum_pg_ts_template_oid,
934 			0,
935 			0,
936 			0
937 		},
938 		2
939 	},
940 	{TypeRelationId,			/* TYPENAMENSP */
941 		TypeNameNspIndexId,
942 		2,
943 		{
944 			Anum_pg_type_typname,
945 			Anum_pg_type_typnamespace,
946 			0,
947 			0
948 		},
949 		64
950 	},
951 	{TypeRelationId,			/* TYPEOID */
952 		TypeOidIndexId,
953 		1,
954 		{
955 			Anum_pg_type_oid,
956 			0,
957 			0,
958 			0
959 		},
960 		64
961 	},
962 	{UserMappingRelationId,		/* USERMAPPINGOID */
963 		UserMappingOidIndexId,
964 		1,
965 		{
966 			Anum_pg_user_mapping_oid,
967 			0,
968 			0,
969 			0
970 		},
971 		2
972 	},
973 	{UserMappingRelationId,		/* USERMAPPINGUSERSERVER */
974 		UserMappingUserServerIndexId,
975 		2,
976 		{
977 			Anum_pg_user_mapping_umuser,
978 			Anum_pg_user_mapping_umserver,
979 			0,
980 			0
981 		},
982 		2
983 	}
984 };
985 
986 static CatCache *SysCache[SysCacheSize];
987 
988 static bool CacheInitialized = false;
989 
990 /* Sorted array of OIDs of tables that have caches on them */
991 static Oid	SysCacheRelationOid[SysCacheSize];
992 static int	SysCacheRelationOidSize;
993 
994 /* Sorted array of OIDs of tables and indexes used by caches */
995 static Oid	SysCacheSupportingRelOid[SysCacheSize * 2];
996 static int	SysCacheSupportingRelOidSize;
997 
998 static int	oid_compare(const void *a, const void *b);
999 
1000 
1001 /*
1002  * InitCatalogCache - initialize the caches
1003  *
1004  * Note that no database access is done here; we only allocate memory
1005  * and initialize the cache structure.  Interrogation of the database
1006  * to complete initialization of a cache happens upon first use
1007  * of that cache.
1008  */
1009 void
InitCatalogCache(void)1010 InitCatalogCache(void)
1011 {
1012 	int			cacheId;
1013 
1014 	StaticAssertStmt(SysCacheSize == (int) lengthof(cacheinfo),
1015 					 "SysCacheSize does not match syscache.c's array");
1016 
1017 	Assert(!CacheInitialized);
1018 
1019 	SysCacheRelationOidSize = SysCacheSupportingRelOidSize = 0;
1020 
1021 	for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
1022 	{
1023 		SysCache[cacheId] = InitCatCache(cacheId,
1024 										 cacheinfo[cacheId].reloid,
1025 										 cacheinfo[cacheId].indoid,
1026 										 cacheinfo[cacheId].nkeys,
1027 										 cacheinfo[cacheId].key,
1028 										 cacheinfo[cacheId].nbuckets);
1029 		if (!PointerIsValid(SysCache[cacheId]))
1030 			elog(ERROR, "could not initialize cache %u (%d)",
1031 				 cacheinfo[cacheId].reloid, cacheId);
1032 		/* Accumulate data for OID lists, too */
1033 		SysCacheRelationOid[SysCacheRelationOidSize++] =
1034 			cacheinfo[cacheId].reloid;
1035 		SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] =
1036 			cacheinfo[cacheId].reloid;
1037 		SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] =
1038 			cacheinfo[cacheId].indoid;
1039 		/* see comments for RelationInvalidatesSnapshotsOnly */
1040 		Assert(!RelationInvalidatesSnapshotsOnly(cacheinfo[cacheId].reloid));
1041 	}
1042 
1043 	Assert(SysCacheRelationOidSize <= lengthof(SysCacheRelationOid));
1044 	Assert(SysCacheSupportingRelOidSize <= lengthof(SysCacheSupportingRelOid));
1045 
1046 	/* Sort and de-dup OID arrays, so we can use binary search. */
1047 	pg_qsort(SysCacheRelationOid, SysCacheRelationOidSize,
1048 			 sizeof(Oid), oid_compare);
1049 	SysCacheRelationOidSize =
1050 		qunique(SysCacheRelationOid, SysCacheRelationOidSize, sizeof(Oid),
1051 				oid_compare);
1052 
1053 	pg_qsort(SysCacheSupportingRelOid, SysCacheSupportingRelOidSize,
1054 			 sizeof(Oid), oid_compare);
1055 	SysCacheSupportingRelOidSize =
1056 		qunique(SysCacheSupportingRelOid, SysCacheSupportingRelOidSize,
1057 				sizeof(Oid), oid_compare);
1058 
1059 	CacheInitialized = true;
1060 }
1061 
1062 /*
1063  * InitCatalogCachePhase2 - finish initializing the caches
1064  *
1065  * Finish initializing all the caches, including necessary database
1066  * access.
1067  *
1068  * This is *not* essential; normally we allow syscaches to be initialized
1069  * on first use.  However, it is useful as a mechanism to preload the
1070  * relcache with entries for the most-commonly-used system catalogs.
1071  * Therefore, we invoke this routine when we need to write a new relcache
1072  * init file.
1073  */
1074 void
InitCatalogCachePhase2(void)1075 InitCatalogCachePhase2(void)
1076 {
1077 	int			cacheId;
1078 
1079 	Assert(CacheInitialized);
1080 
1081 	for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
1082 		InitCatCachePhase2(SysCache[cacheId], true);
1083 }
1084 
1085 
1086 /*
1087  * SearchSysCache
1088  *
1089  *	A layer on top of SearchCatCache that does the initialization and
1090  *	key-setting for you.
1091  *
1092  *	Returns the cache copy of the tuple if one is found, NULL if not.
1093  *	The tuple is the 'cache' copy and must NOT be modified!
1094  *
1095  *	When the caller is done using the tuple, call ReleaseSysCache()
1096  *	to release the reference count grabbed by SearchSysCache().  If this
1097  *	is not done, the tuple will remain locked in cache until end of
1098  *	transaction, which is tolerable but not desirable.
1099  *
1100  *	CAUTION: The tuple that is returned must NOT be freed by the caller!
1101  */
1102 HeapTuple
SearchSysCache(int cacheId,Datum key1,Datum key2,Datum key3,Datum key4)1103 SearchSysCache(int cacheId,
1104 			   Datum key1,
1105 			   Datum key2,
1106 			   Datum key3,
1107 			   Datum key4)
1108 {
1109 	Assert(cacheId >= 0 && cacheId < SysCacheSize &&
1110 		   PointerIsValid(SysCache[cacheId]));
1111 
1112 	return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4);
1113 }
1114 
1115 HeapTuple
SearchSysCache1(int cacheId,Datum key1)1116 SearchSysCache1(int cacheId,
1117 				Datum key1)
1118 {
1119 	Assert(cacheId >= 0 && cacheId < SysCacheSize &&
1120 		   PointerIsValid(SysCache[cacheId]));
1121 	Assert(SysCache[cacheId]->cc_nkeys == 1);
1122 
1123 	return SearchCatCache1(SysCache[cacheId], key1);
1124 }
1125 
1126 HeapTuple
SearchSysCache2(int cacheId,Datum key1,Datum key2)1127 SearchSysCache2(int cacheId,
1128 				Datum key1, Datum key2)
1129 {
1130 	Assert(cacheId >= 0 && cacheId < SysCacheSize &&
1131 		   PointerIsValid(SysCache[cacheId]));
1132 	Assert(SysCache[cacheId]->cc_nkeys == 2);
1133 
1134 	return SearchCatCache2(SysCache[cacheId], key1, key2);
1135 }
1136 
1137 HeapTuple
SearchSysCache3(int cacheId,Datum key1,Datum key2,Datum key3)1138 SearchSysCache3(int cacheId,
1139 				Datum key1, Datum key2, Datum key3)
1140 {
1141 	Assert(cacheId >= 0 && cacheId < SysCacheSize &&
1142 		   PointerIsValid(SysCache[cacheId]));
1143 	Assert(SysCache[cacheId]->cc_nkeys == 3);
1144 
1145 	return SearchCatCache3(SysCache[cacheId], key1, key2, key3);
1146 }
1147 
1148 HeapTuple
SearchSysCache4(int cacheId,Datum key1,Datum key2,Datum key3,Datum key4)1149 SearchSysCache4(int cacheId,
1150 				Datum key1, Datum key2, Datum key3, Datum key4)
1151 {
1152 	Assert(cacheId >= 0 && cacheId < SysCacheSize &&
1153 		   PointerIsValid(SysCache[cacheId]));
1154 	Assert(SysCache[cacheId]->cc_nkeys == 4);
1155 
1156 	return SearchCatCache4(SysCache[cacheId], key1, key2, key3, key4);
1157 }
1158 
1159 /*
1160  * ReleaseSysCache
1161  *		Release previously grabbed reference count on a tuple
1162  */
1163 void
ReleaseSysCache(HeapTuple tuple)1164 ReleaseSysCache(HeapTuple tuple)
1165 {
1166 	ReleaseCatCache(tuple);
1167 }
1168 
1169 /*
1170  * SearchSysCacheCopy
1171  *
1172  * A convenience routine that does SearchSysCache and (if successful)
1173  * returns a modifiable copy of the syscache entry.  The original
1174  * syscache entry is released before returning.  The caller should
1175  * heap_freetuple() the result when done with it.
1176  */
1177 HeapTuple
SearchSysCacheCopy(int cacheId,Datum key1,Datum key2,Datum key3,Datum key4)1178 SearchSysCacheCopy(int cacheId,
1179 				   Datum key1,
1180 				   Datum key2,
1181 				   Datum key3,
1182 				   Datum key4)
1183 {
1184 	HeapTuple	tuple,
1185 				newtuple;
1186 
1187 	tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
1188 	if (!HeapTupleIsValid(tuple))
1189 		return tuple;
1190 	newtuple = heap_copytuple(tuple);
1191 	ReleaseSysCache(tuple);
1192 	return newtuple;
1193 }
1194 
1195 /*
1196  * SearchSysCacheExists
1197  *
1198  * A convenience routine that just probes to see if a tuple can be found.
1199  * No lock is retained on the syscache entry.
1200  */
1201 bool
SearchSysCacheExists(int cacheId,Datum key1,Datum key2,Datum key3,Datum key4)1202 SearchSysCacheExists(int cacheId,
1203 					 Datum key1,
1204 					 Datum key2,
1205 					 Datum key3,
1206 					 Datum key4)
1207 {
1208 	HeapTuple	tuple;
1209 
1210 	tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
1211 	if (!HeapTupleIsValid(tuple))
1212 		return false;
1213 	ReleaseSysCache(tuple);
1214 	return true;
1215 }
1216 
1217 /*
1218  * GetSysCacheOid
1219  *
1220  * A convenience routine that does SearchSysCache and returns the OID in the
1221  * oidcol column of the found tuple, or InvalidOid if no tuple could be found.
1222  * No lock is retained on the syscache entry.
1223  */
1224 Oid
GetSysCacheOid(int cacheId,AttrNumber oidcol,Datum key1,Datum key2,Datum key3,Datum key4)1225 GetSysCacheOid(int cacheId,
1226 			   AttrNumber oidcol,
1227 			   Datum key1,
1228 			   Datum key2,
1229 			   Datum key3,
1230 			   Datum key4)
1231 {
1232 	HeapTuple	tuple;
1233 	bool		isNull;
1234 	Oid			result;
1235 
1236 	tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
1237 	if (!HeapTupleIsValid(tuple))
1238 		return InvalidOid;
1239 	result = heap_getattr(tuple, oidcol,
1240 						  SysCache[cacheId]->cc_tupdesc,
1241 						  &isNull);
1242 	Assert(!isNull);			/* columns used as oids should never be NULL */
1243 	ReleaseSysCache(tuple);
1244 	return result;
1245 }
1246 
1247 
1248 /*
1249  * SearchSysCacheAttName
1250  *
1251  * This routine is equivalent to SearchSysCache on the ATTNAME cache,
1252  * except that it will return NULL if the found attribute is marked
1253  * attisdropped.  This is convenient for callers that want to act as
1254  * though dropped attributes don't exist.
1255  */
1256 HeapTuple
SearchSysCacheAttName(Oid relid,const char * attname)1257 SearchSysCacheAttName(Oid relid, const char *attname)
1258 {
1259 	HeapTuple	tuple;
1260 
1261 	tuple = SearchSysCache2(ATTNAME,
1262 							ObjectIdGetDatum(relid),
1263 							CStringGetDatum(attname));
1264 	if (!HeapTupleIsValid(tuple))
1265 		return NULL;
1266 	if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
1267 	{
1268 		ReleaseSysCache(tuple);
1269 		return NULL;
1270 	}
1271 	return tuple;
1272 }
1273 
1274 /*
1275  * SearchSysCacheCopyAttName
1276  *
1277  * As above, an attisdropped-aware version of SearchSysCacheCopy.
1278  */
1279 HeapTuple
SearchSysCacheCopyAttName(Oid relid,const char * attname)1280 SearchSysCacheCopyAttName(Oid relid, const char *attname)
1281 {
1282 	HeapTuple	tuple,
1283 				newtuple;
1284 
1285 	tuple = SearchSysCacheAttName(relid, attname);
1286 	if (!HeapTupleIsValid(tuple))
1287 		return tuple;
1288 	newtuple = heap_copytuple(tuple);
1289 	ReleaseSysCache(tuple);
1290 	return newtuple;
1291 }
1292 
1293 /*
1294  * SearchSysCacheExistsAttName
1295  *
1296  * As above, an attisdropped-aware version of SearchSysCacheExists.
1297  */
1298 bool
SearchSysCacheExistsAttName(Oid relid,const char * attname)1299 SearchSysCacheExistsAttName(Oid relid, const char *attname)
1300 {
1301 	HeapTuple	tuple;
1302 
1303 	tuple = SearchSysCacheAttName(relid, attname);
1304 	if (!HeapTupleIsValid(tuple))
1305 		return false;
1306 	ReleaseSysCache(tuple);
1307 	return true;
1308 }
1309 
1310 
1311 /*
1312  * SearchSysCacheAttNum
1313  *
1314  * This routine is equivalent to SearchSysCache on the ATTNUM cache,
1315  * except that it will return NULL if the found attribute is marked
1316  * attisdropped.  This is convenient for callers that want to act as
1317  * though dropped attributes don't exist.
1318  */
1319 HeapTuple
SearchSysCacheAttNum(Oid relid,int16 attnum)1320 SearchSysCacheAttNum(Oid relid, int16 attnum)
1321 {
1322 	HeapTuple	tuple;
1323 
1324 	tuple = SearchSysCache2(ATTNUM,
1325 							ObjectIdGetDatum(relid),
1326 							Int16GetDatum(attnum));
1327 	if (!HeapTupleIsValid(tuple))
1328 		return NULL;
1329 	if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
1330 	{
1331 		ReleaseSysCache(tuple);
1332 		return NULL;
1333 	}
1334 	return tuple;
1335 }
1336 
1337 /*
1338  * SearchSysCacheCopyAttNum
1339  *
1340  * As above, an attisdropped-aware version of SearchSysCacheCopy.
1341  */
1342 HeapTuple
SearchSysCacheCopyAttNum(Oid relid,int16 attnum)1343 SearchSysCacheCopyAttNum(Oid relid, int16 attnum)
1344 {
1345 	HeapTuple	tuple,
1346 				newtuple;
1347 
1348 	tuple = SearchSysCacheAttNum(relid, attnum);
1349 	if (!HeapTupleIsValid(tuple))
1350 		return NULL;
1351 	newtuple = heap_copytuple(tuple);
1352 	ReleaseSysCache(tuple);
1353 	return newtuple;
1354 }
1355 
1356 
1357 /*
1358  * SysCacheGetAttr
1359  *
1360  *		Given a tuple previously fetched by SearchSysCache(),
1361  *		extract a specific attribute.
1362  *
1363  * This is equivalent to using heap_getattr() on a tuple fetched
1364  * from a non-cached relation.  Usually, this is only used for attributes
1365  * that could be NULL or variable length; the fixed-size attributes in
1366  * a system table are accessed just by mapping the tuple onto the C struct
1367  * declarations from include/catalog/.
1368  *
1369  * As with heap_getattr(), if the attribute is of a pass-by-reference type
1370  * then a pointer into the tuple data area is returned --- the caller must
1371  * not modify or pfree the datum!
1372  *
1373  * Note: it is legal to use SysCacheGetAttr() with a cacheId referencing
1374  * a different cache for the same catalog the tuple was fetched from.
1375  */
1376 Datum
SysCacheGetAttr(int cacheId,HeapTuple tup,AttrNumber attributeNumber,bool * isNull)1377 SysCacheGetAttr(int cacheId, HeapTuple tup,
1378 				AttrNumber attributeNumber,
1379 				bool *isNull)
1380 {
1381 	/*
1382 	 * We just need to get the TupleDesc out of the cache entry, and then we
1383 	 * can apply heap_getattr().  Normally the cache control data is already
1384 	 * valid (because the caller recently fetched the tuple via this same
1385 	 * cache), but there are cases where we have to initialize the cache here.
1386 	 */
1387 	if (cacheId < 0 || cacheId >= SysCacheSize ||
1388 		!PointerIsValid(SysCache[cacheId]))
1389 		elog(ERROR, "invalid cache ID: %d", cacheId);
1390 	if (!PointerIsValid(SysCache[cacheId]->cc_tupdesc))
1391 	{
1392 		InitCatCachePhase2(SysCache[cacheId], false);
1393 		Assert(PointerIsValid(SysCache[cacheId]->cc_tupdesc));
1394 	}
1395 
1396 	return heap_getattr(tup, attributeNumber,
1397 						SysCache[cacheId]->cc_tupdesc,
1398 						isNull);
1399 }
1400 
1401 /*
1402  * GetSysCacheHashValue
1403  *
1404  * Get the hash value that would be used for a tuple in the specified cache
1405  * with the given search keys.
1406  *
1407  * The reason for exposing this as part of the API is that the hash value is
1408  * exposed in cache invalidation operations, so there are places outside the
1409  * catcache code that need to be able to compute the hash values.
1410  */
1411 uint32
GetSysCacheHashValue(int cacheId,Datum key1,Datum key2,Datum key3,Datum key4)1412 GetSysCacheHashValue(int cacheId,
1413 					 Datum key1,
1414 					 Datum key2,
1415 					 Datum key3,
1416 					 Datum key4)
1417 {
1418 	if (cacheId < 0 || cacheId >= SysCacheSize ||
1419 		!PointerIsValid(SysCache[cacheId]))
1420 		elog(ERROR, "invalid cache ID: %d", cacheId);
1421 
1422 	return GetCatCacheHashValue(SysCache[cacheId], key1, key2, key3, key4);
1423 }
1424 
1425 /*
1426  * List-search interface
1427  */
1428 struct catclist *
SearchSysCacheList(int cacheId,int nkeys,Datum key1,Datum key2,Datum key3)1429 SearchSysCacheList(int cacheId, int nkeys,
1430 				   Datum key1, Datum key2, Datum key3)
1431 {
1432 	if (cacheId < 0 || cacheId >= SysCacheSize ||
1433 		!PointerIsValid(SysCache[cacheId]))
1434 		elog(ERROR, "invalid cache ID: %d", cacheId);
1435 
1436 	return SearchCatCacheList(SysCache[cacheId], nkeys,
1437 							  key1, key2, key3);
1438 }
1439 
1440 /*
1441  * SysCacheInvalidate
1442  *
1443  *	Invalidate entries in the specified cache, given a hash value.
1444  *	See CatCacheInvalidate() for more info.
1445  *
1446  *	This routine is only quasi-public: it should only be used by inval.c.
1447  */
1448 void
SysCacheInvalidate(int cacheId,uint32 hashValue)1449 SysCacheInvalidate(int cacheId, uint32 hashValue)
1450 {
1451 	if (cacheId < 0 || cacheId >= SysCacheSize)
1452 		elog(ERROR, "invalid cache ID: %d", cacheId);
1453 
1454 	/* if this cache isn't initialized yet, no need to do anything */
1455 	if (!PointerIsValid(SysCache[cacheId]))
1456 		return;
1457 
1458 	CatCacheInvalidate(SysCache[cacheId], hashValue);
1459 }
1460 
1461 /*
1462  * Certain relations that do not have system caches send snapshot invalidation
1463  * messages in lieu of catcache messages.  This is for the benefit of
1464  * GetCatalogSnapshot(), which can then reuse its existing MVCC snapshot
1465  * for scanning one of those catalogs, rather than taking a new one, if no
1466  * invalidation has been received.
1467  *
1468  * Relations that have syscaches need not (and must not) be listed here.  The
1469  * catcache invalidation messages will also flush the snapshot.  If you add a
1470  * syscache for one of these relations, remove it from this list.
1471  */
1472 bool
RelationInvalidatesSnapshotsOnly(Oid relid)1473 RelationInvalidatesSnapshotsOnly(Oid relid)
1474 {
1475 	switch (relid)
1476 	{
1477 		case DbRoleSettingRelationId:
1478 		case DependRelationId:
1479 		case SharedDependRelationId:
1480 		case DescriptionRelationId:
1481 		case SharedDescriptionRelationId:
1482 		case SecLabelRelationId:
1483 		case SharedSecLabelRelationId:
1484 			return true;
1485 		default:
1486 			break;
1487 	}
1488 
1489 	return false;
1490 }
1491 
1492 /*
1493  * Test whether a relation has a system cache.
1494  */
1495 bool
RelationHasSysCache(Oid relid)1496 RelationHasSysCache(Oid relid)
1497 {
1498 	int			low = 0,
1499 				high = SysCacheRelationOidSize - 1;
1500 
1501 	while (low <= high)
1502 	{
1503 		int			middle = low + (high - low) / 2;
1504 
1505 		if (SysCacheRelationOid[middle] == relid)
1506 			return true;
1507 		if (SysCacheRelationOid[middle] < relid)
1508 			low = middle + 1;
1509 		else
1510 			high = middle - 1;
1511 	}
1512 
1513 	return false;
1514 }
1515 
1516 /*
1517  * Test whether a relation supports a system cache, ie it is either a
1518  * cached table or the index used for a cache.
1519  */
1520 bool
RelationSupportsSysCache(Oid relid)1521 RelationSupportsSysCache(Oid relid)
1522 {
1523 	int			low = 0,
1524 				high = SysCacheSupportingRelOidSize - 1;
1525 
1526 	while (low <= high)
1527 	{
1528 		int			middle = low + (high - low) / 2;
1529 
1530 		if (SysCacheSupportingRelOid[middle] == relid)
1531 			return true;
1532 		if (SysCacheSupportingRelOid[middle] < relid)
1533 			low = middle + 1;
1534 		else
1535 			high = middle - 1;
1536 	}
1537 
1538 	return false;
1539 }
1540 
1541 
1542 /*
1543  * OID comparator for pg_qsort
1544  */
1545 static int
oid_compare(const void * a,const void * b)1546 oid_compare(const void *a, const void *b)
1547 {
1548 	Oid			oa = *((const Oid *) a);
1549 	Oid			ob = *((const Oid *) b);
1550 
1551 	if (oa == ob)
1552 		return 0;
1553 	return (oa > ob) ? 1 : -1;
1554 }
1555