1 /*-------------------------------------------------------------------------
2  *
3  * rel.h
4  *	  POSTGRES relation descriptor (a/k/a relcache entry) definitions.
5  *
6  *
7  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * src/include/utils/rel.h
11  *
12  *-------------------------------------------------------------------------
13  */
14 #ifndef REL_H
15 #define REL_H
16 
17 #include "access/tupdesc.h"
18 #include "access/xlog.h"
19 #include "catalog/pg_class.h"
20 #include "catalog/pg_index.h"
21 #include "catalog/pg_publication.h"
22 #include "fmgr.h"
23 #include "nodes/bitmapset.h"
24 #include "rewrite/prs2lock.h"
25 #include "storage/block.h"
26 #include "storage/relfilenode.h"
27 #include "utils/relcache.h"
28 #include "utils/reltrigger.h"
29 
30 
31 /*
32  * LockRelId and LockInfo really belong to lmgr.h, but it's more convenient
33  * to declare them here so we can have a LockInfoData field in a Relation.
34  */
35 
36 typedef struct LockRelId
37 {
38 	Oid			relId;			/* a relation identifier */
39 	Oid			dbId;			/* a database identifier */
40 } LockRelId;
41 
42 typedef struct LockInfoData
43 {
44 	LockRelId	lockRelId;
45 } LockInfoData;
46 
47 typedef LockInfoData *LockInfo;
48 
49 /*
50  * Information about the partition key of a relation
51  */
52 typedef struct PartitionKeyData
53 {
54 	char		strategy;		/* partitioning strategy */
55 	int16		partnatts;		/* number of columns in the partition key */
56 	AttrNumber *partattrs;		/* attribute numbers of columns in the
57 								 * partition key */
58 	List	   *partexprs;		/* list of expressions in the partitioning
59 								 * key, or NIL */
60 
61 	Oid		   *partopfamily;	/* OIDs of operator families */
62 	Oid		   *partopcintype;	/* OIDs of opclass declared input data types */
63 	FmgrInfo   *partsupfunc;	/* lookup info for support funcs */
64 
65 	/* Partitioning collation per attribute */
66 	Oid		   *partcollation;
67 
68 	/* Type information per attribute */
69 	Oid		   *parttypid;
70 	int32	   *parttypmod;
71 	int16	   *parttyplen;
72 	bool	   *parttypbyval;
73 	char	   *parttypalign;
74 	Oid		   *parttypcoll;
75 }			PartitionKeyData;
76 
77 typedef struct PartitionKeyData *PartitionKey;
78 
79 /*
80  * Here are the contents of a relation cache entry.
81  */
82 
83 typedef struct RelationData
84 {
85 	RelFileNode rd_node;		/* relation physical identifier */
86 	/* use "struct" here to avoid needing to include smgr.h: */
87 	struct SMgrRelationData *rd_smgr;	/* cached file handle, or NULL */
88 	int			rd_refcnt;		/* reference count */
89 	BackendId	rd_backend;		/* owning backend id, if temporary relation */
90 	bool		rd_islocaltemp; /* rel is a temp rel of this session */
91 	bool		rd_isnailed;	/* rel is nailed in cache */
92 	bool		rd_isvalid;		/* relcache entry is valid */
93 	char		rd_indexvalid;	/* state of rd_indexlist: 0 = not valid, 1 =
94 								 * valid, 2 = temporarily forced */
95 	bool		rd_statvalid;	/* is rd_statlist valid? */
96 
97 	/*----------
98 	 * rd_createSubid is the ID of the highest subtransaction the rel has
99 	 * survived into; or zero if the rel was not created in the current top
100 	 * transaction.  This can be now be relied on, whereas previously it could
101 	 * be "forgotten" in earlier releases. Likewise, rd_newRelfilenodeSubid is
102 	 * the ID of the highest subtransaction the relfilenode change has
103 	 * survived into, or zero if not changed in the current transaction (or we
104 	 * have forgotten changing it). rd_newRelfilenodeSubid can be forgotten
105 	 * when a relation has multiple new relfilenodes within a single
106 	 * transaction, with one of them occurring in a subsequently aborted
107 	 * subtransaction, e.g.
108 	 *		BEGIN;
109 	 *		TRUNCATE t;
110 	 *		SAVEPOINT save;
111 	 *		TRUNCATE t;
112 	 *		ROLLBACK TO save;
113 	 *		-- rd_newRelfilenodeSubid is now forgotten
114 	 */
115 	SubTransactionId rd_createSubid;	/* rel was created in current xact */
116 	SubTransactionId rd_newRelfilenodeSubid;	/* new relfilenode assigned in
117 												 * current xact */
118 
119 	Form_pg_class rd_rel;		/* RELATION tuple */
120 	TupleDesc	rd_att;			/* tuple descriptor */
121 	Oid			rd_id;			/* relation's object id */
122 	LockInfoData rd_lockInfo;	/* lock mgr's info for locking relation */
123 	RuleLock   *rd_rules;		/* rewrite rules */
124 	MemoryContext rd_rulescxt;	/* private memory cxt for rd_rules, if any */
125 	TriggerDesc *trigdesc;		/* Trigger info, or NULL if rel has none */
126 	/* use "struct" here to avoid needing to include rowsecurity.h: */
127 	struct RowSecurityDesc *rd_rsdesc;	/* row security policies, or NULL */
128 
129 	/* data managed by RelationGetFKeyList: */
130 	List	   *rd_fkeylist;	/* list of ForeignKeyCacheInfo (see below) */
131 	bool		rd_fkeyvalid;	/* true if list has been computed */
132 
133 	MemoryContext rd_partkeycxt;	/* private context for rd_partkey, if any */
134 	struct PartitionKeyData *rd_partkey;	/* partition key, or NULL */
135 	MemoryContext rd_pdcxt;		/* private context for rd_partdesc, if any */
136 	struct PartitionDescData *rd_partdesc;	/* partitions, or NULL */
137 	List	   *rd_partcheck;	/* partition CHECK quals */
138 
139 	/* data managed by RelationGetIndexList: */
140 	List	   *rd_indexlist;	/* list of OIDs of indexes on relation */
141 	Oid			rd_oidindex;	/* OID of unique index on OID, if any */
142 	Oid			rd_pkindex;		/* OID of primary key, if any */
143 	Oid			rd_replidindex; /* OID of replica identity index, if any */
144 
145 	/* data managed by RelationGetStatExtList: */
146 	List	   *rd_statlist;	/* list of OIDs of extended stats */
147 
148 	/* data managed by RelationGetIndexAttrBitmap: */
149 	Bitmapset  *rd_indexattr;	/* identifies columns used in indexes */
150 	Bitmapset  *rd_keyattr;		/* cols that can be ref'd by foreign keys */
151 	Bitmapset  *rd_pkattr;		/* cols included in primary key */
152 	Bitmapset  *rd_idattr;		/* included in replica identity index */
153 
154 	PublicationActions *rd_pubactions;	/* publication actions */
155 
156 	/*
157 	 * rd_options is set whenever rd_rel is loaded into the relcache entry.
158 	 * Note that you can NOT look into rd_rel for this data.  NULL means "use
159 	 * defaults".
160 	 */
161 	bytea	   *rd_options;		/* parsed pg_class.reloptions */
162 
163 	/* These are non-NULL only for an index relation: */
164 	Form_pg_index rd_index;		/* pg_index tuple describing this index */
165 	/* use "struct" here to avoid needing to include htup.h: */
166 	struct HeapTupleData *rd_indextuple;	/* all of pg_index tuple */
167 
168 	/*
169 	 * index access support info (used only for an index relation)
170 	 *
171 	 * Note: only default support procs for each opclass are cached, namely
172 	 * those with lefttype and righttype equal to the opclass's opcintype. The
173 	 * arrays are indexed by support function number, which is a sufficient
174 	 * identifier given that restriction.
175 	 *
176 	 * Note: rd_amcache is available for index AMs to cache private data about
177 	 * an index.  This must be just a cache since it may get reset at any time
178 	 * (in particular, it will get reset by a relcache inval message for the
179 	 * index).  If used, it must point to a single memory chunk palloc'd in
180 	 * rd_indexcxt.  A relcache reset will include freeing that chunk and
181 	 * setting rd_amcache = NULL.
182 	 */
183 	Oid			rd_amhandler;	/* OID of index AM's handler function */
184 	MemoryContext rd_indexcxt;	/* private memory cxt for this stuff */
185 	/* use "struct" here to avoid needing to include amapi.h: */
186 	struct IndexAmRoutine *rd_amroutine;	/* index AM's API struct */
187 	Oid		   *rd_opfamily;	/* OIDs of op families for each index col */
188 	Oid		   *rd_opcintype;	/* OIDs of opclass declared input data types */
189 	RegProcedure *rd_support;	/* OIDs of support procedures */
190 	FmgrInfo   *rd_supportinfo; /* lookup info for support procedures */
191 	int16	   *rd_indoption;	/* per-column AM-specific flags */
192 	List	   *rd_indexprs;	/* index expression trees, if any */
193 	List	   *rd_indpred;		/* index predicate tree, if any */
194 	Oid		   *rd_exclops;		/* OIDs of exclusion operators, if any */
195 	Oid		   *rd_exclprocs;	/* OIDs of exclusion ops' procs, if any */
196 	uint16	   *rd_exclstrats;	/* exclusion ops' strategy numbers, if any */
197 	void	   *rd_amcache;		/* available for use by index AM */
198 	Oid		   *rd_indcollation;	/* OIDs of index collations */
199 
200 	/*
201 	 * foreign-table support
202 	 *
203 	 * rd_fdwroutine must point to a single memory chunk palloc'd in
204 	 * CacheMemoryContext.  It will be freed and reset to NULL on a relcache
205 	 * reset.
206 	 */
207 
208 	/* use "struct" here to avoid needing to include fdwapi.h: */
209 	struct FdwRoutine *rd_fdwroutine;	/* cached function pointers, or NULL */
210 
211 	/*
212 	 * Hack for CLUSTER, rewriting ALTER TABLE, etc: when writing a new
213 	 * version of a table, we need to make any toast pointers inserted into it
214 	 * have the existing toast table's OID, not the OID of the transient toast
215 	 * table.  If rd_toastoid isn't InvalidOid, it is the OID to place in
216 	 * toast pointers inserted into this rel.  (Note it's set on the new
217 	 * version of the main heap, not the toast table itself.)  This also
218 	 * causes toast_save_datum() to try to preserve toast value OIDs.
219 	 */
220 	Oid			rd_toastoid;	/* Real TOAST table's OID, or InvalidOid */
221 
222 	/* use "struct" here to avoid needing to include pgstat.h: */
223 	struct PgStat_TableStatus *pgstat_info; /* statistics collection area */
224 
225 	/* placed here to avoid ABI break before v12: */
226 	bool		rd_partcheckvalid;	/* true if list has been computed */
227 	MemoryContext rd_partcheckcxt;	/* private cxt for rd_partcheck, if any */
228 } RelationData;
229 
230 
231 /*
232  * ForeignKeyCacheInfo
233  *		Information the relcache can cache about foreign key constraints
234  *
235  * This is basically just an image of relevant columns from pg_constraint.
236  * We make it a subclass of Node so that copyObject() can be used on a list
237  * of these, but we also ensure it is a "flat" object without substructure,
238  * so that list_free_deep() is sufficient to free such a list.
239  * The per-FK-column arrays can be fixed-size because we allow at most
240  * INDEX_MAX_KEYS columns in a foreign key constraint.
241  *
242  * Currently, we only cache fields of interest to the planner, but the
243  * set of fields could be expanded in future.
244  */
245 typedef struct ForeignKeyCacheInfo
246 {
247 	NodeTag		type;
248 	Oid			conrelid;		/* relation constrained by the foreign key */
249 	Oid			confrelid;		/* relation referenced by the foreign key */
250 	int			nkeys;			/* number of columns in the foreign key */
251 	/* these arrays each have nkeys valid entries: */
252 	AttrNumber	conkey[INDEX_MAX_KEYS]; /* cols in referencing table */
253 	AttrNumber	confkey[INDEX_MAX_KEYS];	/* cols in referenced table */
254 	Oid			conpfeqop[INDEX_MAX_KEYS];	/* PK = FK operator OIDs */
255 } ForeignKeyCacheInfo;
256 
257 
258 /*
259  * StdRdOptions
260  *		Standard contents of rd_options for heaps and generic indexes.
261  *
262  * RelationGetFillFactor() and RelationGetTargetPageFreeSpace() can only
263  * be applied to relations that use this format or a superset for
264  * private options data.
265  */
266  /* autovacuum-related reloptions. */
267 typedef struct AutoVacOpts
268 {
269 	bool		enabled;
270 	int			vacuum_threshold;
271 	int			analyze_threshold;
272 	int			vacuum_cost_delay;
273 	int			vacuum_cost_limit;
274 	int			freeze_min_age;
275 	int			freeze_max_age;
276 	int			freeze_table_age;
277 	int			multixact_freeze_min_age;
278 	int			multixact_freeze_max_age;
279 	int			multixact_freeze_table_age;
280 	int			log_min_duration;
281 	float8		vacuum_scale_factor;
282 	float8		analyze_scale_factor;
283 } AutoVacOpts;
284 
285 typedef struct StdRdOptions
286 {
287 	int32		vl_len_;		/* varlena header (do not touch directly!) */
288 	int			fillfactor;		/* page fill factor in percent (0..100) */
289 	AutoVacOpts autovacuum;		/* autovacuum-related options */
290 	bool		user_catalog_table; /* use as an additional catalog relation */
291 	int			parallel_workers;	/* max number of parallel workers */
292 } StdRdOptions;
293 
294 #define HEAP_MIN_FILLFACTOR			10
295 #define HEAP_DEFAULT_FILLFACTOR		100
296 
297 /*
298  * RelationGetFillFactor
299  *		Returns the relation's fillfactor.  Note multiple eval of argument!
300  */
301 #define RelationGetFillFactor(relation, defaultff) \
302 	((relation)->rd_options ? \
303 	 ((StdRdOptions *) (relation)->rd_options)->fillfactor : (defaultff))
304 
305 /*
306  * RelationGetTargetPageUsage
307  *		Returns the relation's desired space usage per page in bytes.
308  */
309 #define RelationGetTargetPageUsage(relation, defaultff) \
310 	(BLCKSZ * RelationGetFillFactor(relation, defaultff) / 100)
311 
312 /*
313  * RelationGetTargetPageFreeSpace
314  *		Returns the relation's desired freespace per page in bytes.
315  */
316 #define RelationGetTargetPageFreeSpace(relation, defaultff) \
317 	(BLCKSZ * (100 - RelationGetFillFactor(relation, defaultff)) / 100)
318 
319 /*
320  * RelationIsUsedAsCatalogTable
321  *		Returns whether the relation should be treated as a catalog table
322  *		from the pov of logical decoding.  Note multiple eval of argument!
323  */
324 #define RelationIsUsedAsCatalogTable(relation)	\
325 	((relation)->rd_options && \
326 	 ((relation)->rd_rel->relkind == RELKIND_RELATION || \
327 	  (relation)->rd_rel->relkind == RELKIND_MATVIEW) ? \
328 	 ((StdRdOptions *) (relation)->rd_options)->user_catalog_table : false)
329 
330 /*
331  * RelationGetParallelWorkers
332  *		Returns the relation's parallel_workers reloption setting.
333  *		Note multiple eval of argument!
334  */
335 #define RelationGetParallelWorkers(relation, defaultpw) \
336 	((relation)->rd_options ? \
337 	 ((StdRdOptions *) (relation)->rd_options)->parallel_workers : (defaultpw))
338 
339 
340 /*
341  * ViewOptions
342  *		Contents of rd_options for views
343  */
344 typedef struct ViewOptions
345 {
346 	int32		vl_len_;		/* varlena header (do not touch directly!) */
347 	bool		security_barrier;
348 	int			check_option_offset;
349 } ViewOptions;
350 
351 /*
352  * RelationIsSecurityView
353  *		Returns whether the relation is security view, or not.  Note multiple
354  *		eval of argument!
355  */
356 #define RelationIsSecurityView(relation)	\
357 	((relation)->rd_options ?				\
358 	 ((ViewOptions *) (relation)->rd_options)->security_barrier : false)
359 
360 /*
361  * RelationHasCheckOption
362  *		Returns true if the relation is a view defined with either the local
363  *		or the cascaded check option.  Note multiple eval of argument!
364  */
365 #define RelationHasCheckOption(relation)									\
366 	((relation)->rd_options &&												\
367 	 ((ViewOptions *) (relation)->rd_options)->check_option_offset != 0)
368 
369 /*
370  * RelationHasLocalCheckOption
371  *		Returns true if the relation is a view defined with the local check
372  *		option.  Note multiple eval of argument!
373  */
374 #define RelationHasLocalCheckOption(relation)								\
375 	((relation)->rd_options &&												\
376 	 ((ViewOptions *) (relation)->rd_options)->check_option_offset != 0 ?	\
377 	 strcmp((char *) (relation)->rd_options +								\
378 			((ViewOptions *) (relation)->rd_options)->check_option_offset,	\
379 			"local") == 0 : false)
380 
381 /*
382  * RelationHasCascadedCheckOption
383  *		Returns true if the relation is a view defined with the cascaded check
384  *		option.  Note multiple eval of argument!
385  */
386 #define RelationHasCascadedCheckOption(relation)							\
387 	((relation)->rd_options &&												\
388 	 ((ViewOptions *) (relation)->rd_options)->check_option_offset != 0 ?	\
389 	 strcmp((char *) (relation)->rd_options +								\
390 			((ViewOptions *) (relation)->rd_options)->check_option_offset,	\
391 			"cascaded") == 0 : false)
392 
393 
394 /*
395  * RelationIsValid
396  *		True iff relation descriptor is valid.
397  */
398 #define RelationIsValid(relation) PointerIsValid(relation)
399 
400 #define InvalidRelation ((Relation) NULL)
401 
402 /*
403  * RelationHasReferenceCountZero
404  *		True iff relation reference count is zero.
405  *
406  * Note:
407  *		Assumes relation descriptor is valid.
408  */
409 #define RelationHasReferenceCountZero(relation) \
410 		((bool)((relation)->rd_refcnt == 0))
411 
412 /*
413  * RelationGetForm
414  *		Returns pg_class tuple for a relation.
415  *
416  * Note:
417  *		Assumes relation descriptor is valid.
418  */
419 #define RelationGetForm(relation) ((relation)->rd_rel)
420 
421 /*
422  * RelationGetRelid
423  *		Returns the OID of the relation
424  */
425 #define RelationGetRelid(relation) ((relation)->rd_id)
426 
427 /*
428  * RelationGetNumberOfAttributes
429  *		Returns the number of attributes in a relation.
430  */
431 #define RelationGetNumberOfAttributes(relation) ((relation)->rd_rel->relnatts)
432 
433 /*
434  * RelationGetDescr
435  *		Returns tuple descriptor for a relation.
436  */
437 #define RelationGetDescr(relation) ((relation)->rd_att)
438 
439 /*
440  * RelationGetRelationName
441  *		Returns the rel's name.
442  *
443  * Note that the name is only unique within the containing namespace.
444  */
445 #define RelationGetRelationName(relation) \
446 	(NameStr((relation)->rd_rel->relname))
447 
448 /*
449  * RelationGetNamespace
450  *		Returns the rel's namespace OID.
451  */
452 #define RelationGetNamespace(relation) \
453 	((relation)->rd_rel->relnamespace)
454 
455 /*
456  * RelationIsMapped
457  *		True if the relation uses the relfilenode map.
458  *
459  * NB: this is only meaningful for relkinds that have storage, else it
460  * will misleadingly say "true".
461  */
462 #define RelationIsMapped(relation) \
463 	((relation)->rd_rel->relfilenode == InvalidOid)
464 
465 /*
466  * RelationOpenSmgr
467  *		Open the relation at the smgr level, if not already done.
468  */
469 #define RelationOpenSmgr(relation) \
470 	do { \
471 		if ((relation)->rd_smgr == NULL) \
472 			smgrsetowner(&((relation)->rd_smgr), smgropen((relation)->rd_node, (relation)->rd_backend)); \
473 	} while (0)
474 
475 /*
476  * RelationCloseSmgr
477  *		Close the relation at the smgr level, if not already done.
478  *
479  * Note: smgrclose should unhook from owner pointer, hence the Assert.
480  */
481 #define RelationCloseSmgr(relation) \
482 	do { \
483 		if ((relation)->rd_smgr != NULL) \
484 		{ \
485 			smgrclose((relation)->rd_smgr); \
486 			Assert((relation)->rd_smgr == NULL); \
487 		} \
488 	} while (0)
489 
490 /*
491  * RelationGetTargetBlock
492  *		Fetch relation's current insertion target block.
493  *
494  * Returns InvalidBlockNumber if there is no current target block.  Note
495  * that the target block status is discarded on any smgr-level invalidation.
496  */
497 #define RelationGetTargetBlock(relation) \
498 	( (relation)->rd_smgr != NULL ? (relation)->rd_smgr->smgr_targblock : InvalidBlockNumber )
499 
500 /*
501  * RelationSetTargetBlock
502  *		Set relation's current insertion target block.
503  */
504 #define RelationSetTargetBlock(relation, targblock) \
505 	do { \
506 		RelationOpenSmgr(relation); \
507 		(relation)->rd_smgr->smgr_targblock = (targblock); \
508 	} while (0)
509 
510 /*
511  * RelationNeedsWAL
512  *		True if relation needs WAL.
513  */
514 #define RelationNeedsWAL(relation) \
515 	((relation)->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT)
516 
517 /*
518  * RelationUsesLocalBuffers
519  *		True if relation's pages are stored in local buffers.
520  */
521 #define RelationUsesLocalBuffers(relation) \
522 	((relation)->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
523 
524 /*
525  * RELATION_IS_LOCAL
526  *		If a rel is either temp or newly created in the current transaction,
527  *		it can be assumed to be accessible only to the current backend.
528  *		This is typically used to decide that we can skip acquiring locks.
529  *
530  * Beware of multiple eval of argument
531  */
532 #define RELATION_IS_LOCAL(relation) \
533 	((relation)->rd_islocaltemp || \
534 	 (relation)->rd_createSubid != InvalidSubTransactionId)
535 
536 /*
537  * RELATION_IS_OTHER_TEMP
538  *		Test for a temporary relation that belongs to some other session.
539  *
540  * Beware of multiple eval of argument
541  */
542 #define RELATION_IS_OTHER_TEMP(relation) \
543 	((relation)->rd_rel->relpersistence == RELPERSISTENCE_TEMP && \
544 	 !(relation)->rd_islocaltemp)
545 
546 
547 /*
548  * RelationIsScannable
549  *		Currently can only be false for a materialized view which has not been
550  *		populated by its query.  This is likely to get more complicated later,
551  *		so use a macro which looks like a function.
552  */
553 #define RelationIsScannable(relation) ((relation)->rd_rel->relispopulated)
554 
555 /*
556  * RelationIsPopulated
557  *		Currently, we don't physically distinguish the "populated" and
558  *		"scannable" properties of matviews, but that may change later.
559  *		Hence, use the appropriate one of these macros in code tests.
560  */
561 #define RelationIsPopulated(relation) ((relation)->rd_rel->relispopulated)
562 
563 /*
564  * RelationIsAccessibleInLogicalDecoding
565  *		True if we need to log enough information to have access via
566  *		decoding snapshot.
567  */
568 #define RelationIsAccessibleInLogicalDecoding(relation) \
569 	(XLogLogicalInfoActive() && \
570 	 RelationNeedsWAL(relation) && \
571 	 (IsCatalogRelation(relation) || RelationIsUsedAsCatalogTable(relation)))
572 
573 /*
574  * RelationIsLogicallyLogged
575  *		True if we need to log enough information to extract the data from the
576  *		WAL stream.
577  *
578  * We don't log information for unlogged tables (since they don't WAL log
579  * anyway) and for system tables (their content is hard to make sense of, and
580  * it would complicate decoding slightly for little gain). Note that we *do*
581  * log information for user defined catalog tables since they presumably are
582  * interesting to the user...
583  */
584 #define RelationIsLogicallyLogged(relation) \
585 	(XLogLogicalInfoActive() && \
586 	 RelationNeedsWAL(relation) && \
587 	 !IsCatalogRelation(relation))
588 
589 /*
590  * RelationGetPartitionKey
591  *		Returns the PartitionKey of a relation
592  */
593 #define RelationGetPartitionKey(relation) ((relation)->rd_partkey)
594 
595 /*
596  * PartitionKey inquiry functions
597  */
598 static inline int
get_partition_strategy(PartitionKey key)599 get_partition_strategy(PartitionKey key)
600 {
601 	return key->strategy;
602 }
603 
604 static inline int
get_partition_natts(PartitionKey key)605 get_partition_natts(PartitionKey key)
606 {
607 	return key->partnatts;
608 }
609 
610 static inline List *
get_partition_exprs(PartitionKey key)611 get_partition_exprs(PartitionKey key)
612 {
613 	return key->partexprs;
614 }
615 
616 /*
617  * PartitionKey inquiry functions - one column
618  */
619 static inline int16
get_partition_col_attnum(PartitionKey key,int col)620 get_partition_col_attnum(PartitionKey key, int col)
621 {
622 	return key->partattrs[col];
623 }
624 
625 static inline Oid
get_partition_col_typid(PartitionKey key,int col)626 get_partition_col_typid(PartitionKey key, int col)
627 {
628 	return key->parttypid[col];
629 }
630 
631 static inline int32
get_partition_col_typmod(PartitionKey key,int col)632 get_partition_col_typmod(PartitionKey key, int col)
633 {
634 	return key->parttypmod[col];
635 }
636 
637 /*
638  * RelationGetPartitionDesc
639  *		Returns partition descriptor for a relation.
640  */
641 #define RelationGetPartitionDesc(relation) ((relation)->rd_partdesc)
642 
643 /* routines in utils/cache/relcache.c */
644 extern void RelationIncrementReferenceCount(Relation rel);
645 extern void RelationDecrementReferenceCount(Relation rel);
646 extern List *RelationGetRepsetList(Relation rel);
647 
648 #endif							/* REL_H */
649