* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
* Portions Copyright (c) 2021, openGauss Contributors
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* ---------------------------------------------------------------------------------------
*
* pg_partition_fn.h
*
*
*
* IDENTIFICATION
* src/include/catalog/pg_partition_fn.h
*
* ---------------------------------------------------------------------------------------
*/
#ifndef PG_PARTITION_FN_H
#define PG_PARTITION_FN_H
#include "postgres.h"
#include "knl/knl_variable.h"
#include "catalog/indexing.h"
#include "catalog/pg_type.h"
#include "nodes/parsenodes.h"
#include "utils/rel.h"
#include "utils/rel_gs.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "nodes/pg_list.h"
#include "access/htup.h"
#include "storage/lock/lock.h"
#include "access/heapam.h"
#include "storage/lmgr.h"
#define MAX_PARTITION_NUM 1048575
#define INTERVAL_PARTITION_NAME_PREFIX "sys_p"
#define INTERVAL_PARTITION_NAME_PREFIX_FMT "sys_p%u"
#define INTERVAL_PARTITION_NAME_SUFFIX_LEN 5
#define SUBPARTITION_NAME_PREFIX "sys_subp"
#define SUBPARTITION_NAME_PREFIX_FMT "sys_subp%u"
* In start/end syntax, partition name is of form:
* PARTITION_PREFIX_NUM,
* so length of the name prefix must be restricted to:
* NAMEDATALEN (64) - 1 - LENGTH ( "MAX_PARTITION_NUM" ) - 1
* NOTICE: please update LEN_PARTITION_PREFIX if you modify macro MAX_PARTITION_NUM
*/
#define LEN_PARTITION_PREFIX 55
* A suppositional sequence number for partition lock.
* We apply PARTITION OBJECT_LOCK to protect partition parallel work.
* In this case, the relid will be locked by LockPartitionObject(relid, PARTITION_OBJECT_LOCK_SDEQUENCE, lockmode).
* We take these three cases in condition:
* 1. If it's a DML operation, the OBJECT_LOCK(ShareLock) will be added in parserOpenTable, and will be released
* in InitPlan. Note that the snapshot is obtained before InitPlan.
* 2. If it's a DDL operation, the OBJECT_LOCK(ExclusiveLock) will be added before CommitTransaction, which will
* be released during CommitTransaction.
* 3. If it's a ADD_INTERVAL_PARTITION operation, the operation will be transformed from DML to DDL. Besides the two
* actions above, we apply an additinal OBJECT_LOCK, INTERVAL_PARTITION_LOCK_SDEQUENCE on all INTERVAL DDL operation
* (including ADD_INTERVAL_PARTITION) to protect the whole process.
*/
typedef enum PartitionObjectLock {
PARTITION_OBJECT_LOCK_SDEQUENCE = MAX_PARTITION_NUM + 1,
* we get the DML executor snapshot before InitPlan.
* This is to forbid instantaneous inconsistency. Just Consider the following condition: a SQL scans the destination
* partitioned table and uses both Local Partitioned Index and Global Partitioned Index, the LPI scan partition info
* is generated in static pruning in optimizer, while the GPI is in executor. Without PARTITION OBJECT_LOCK, if a
* DDL operation commits, which creates a new partition and inserts into data, such as ADD_INTERVAL_PARTITION, the
* inconsistency may accur. Since the new partition data is invisible for static pruning of LPI scan, and is visible
* for GPI scan. */
INTERVAL_PARTITION_LOCK_SDEQUENCE
* concurrency of ADD_INTERVAL_PARTITION. Note that an ADD_INTERVAL_PARTITION action only holds RowExclusiveLock
* on the table, we need an additinal OBJECT_LOCK to protect the whole process. */
} PartitionObjectLock;
typedef enum PartitionObjectLockType {
PARTITION_SHARE_LOCK = AccessShareLock,
PARTITION_EXCLUSIVE_LOCK = AccessExclusiveLock
} PartitionObjectLockType;
extern void LockPartitionObject(Oid relOid, PartitionObjectLock object, PartitionObjectLockType type);
extern void UnlockPartitionObject(Oid relOid, PartitionObjectLock object, PartitionObjectLockType type);
extern bool ConditionalLockPartitionObject(Oid relOid, PartitionObjectLock object, PartitionObjectLockType type);
#ifndef ENABLE_MULTIPLE_NODES
extern void AddPartitionDMLInfo(Oid relOid);
extern void AddPartitionDDLInfo(Oid relOid);
extern void LockPartitionDDLOperation();
#endif
* PARTITIONNO/SUBPARTITIONNO: An unique identifier of each partition in a partitioned/subpartitioned table.
* The partitionno/subpartitionno is recorded in catalog PG_PARTITION. See pg_partition.h for more detail.
* 1. When create a partitioned table containing n partitions, the partitionno of each partition is set to 1~n, and the
* partitioned tuple records the maxvalue, we use a negative value, -n to distinguish from the partition tuple.
* Similarly, if a partition contains m subpartitions, the subpartitionno of each subpartition is set to 1~m, and the
* partition tuple records the maxvalue -m.
* 2. When DDL is done on the partitioned table, think of four base conditions:
* a). ADD_PARTITION_ACTION: Firstly we read the record of partitioned tuple, and get the maxvalue of partitionno,
* we mask it as -x(the maxvalue is records in negative type). Then the partitionno of the new partition is set
* to x+1, and the maxvalue is updated into -(x+1).
* b). DROP_PARTITION_ACTION: Do nothing.
* c). INPLACE_UPDATE_ACTION: Firstly we read the record of the src partition tuple, we mask it as k. Then the
* partitionno of the new partition is set to k. Do nothing on the partitioned tuple.
* d). OTHER_PARTITION_ACTION: Do nothing.
* In fact, a partition DDL can be a collection of these four action above. For example, a Merge-Partition operation
* has a series of DROP_PARTITION_ACTION and an ADD_PARTITION_ACTION, a Truncate-Partition operation with
* UPDATE_GLOBAL_INDEX has an OTHER_PARTITION_ACTION and a INPLACE_UPDATE_ACTION.
* 3. When DML is done on the partitioned table, think of three stages: pruning -> obtain-partoid -> partition-open.
* In the period of pruning -> obtain-partoid, the partseq may be dislocationed, in the period of obtain-partoid ->
* partition-open, the partoid may be inplace-updated to a new oid with an UPDATE_GLOBAL_INDEX DDL action. So the
* partitionno is used to solve these problem.
* a). When pruning, we save partitionno list when obtain the partseq list. See the definition of PruningResult.
* b). When obtain-partoid, we use partseq to get the partoid, and check the src partitionno with dest one, if not
* match, we use partitionno to research. See the definition of getPartitionOidFromSequence.
* c). When partition-open, if we have the dest partitionno, firstly we will do tryPartitionOpen, if not found, just
* use partitionno to research the new partoid, and retry. See the definition of PartitionOpenWithPartitionno. */
#define MAX_PARTITION_NO (INT32_MAX - MAX_PARTITION_NUM)
#define INVALID_PARTITION_NO 0
#define PARTITIONNO_IS_VALID(partitionno) ((partitionno) > 0)
extern HeapTuple ScanPgPartition(Oid targetPartId, bool indexOK, Snapshot snapshot);
extern Oid RelOidGetPartitionTupleid(Oid relOid);
extern int GetCurrentPartitionNo(Oid partOid);
extern int GetCurrentSubPartitionNo(Oid partOid);
extern void UpdateCurrentPartitionNo(Oid partOid, int partitionno, bool inplace);
extern void UpdateCurrentSubPartitionNo(Oid partOid, int subpartitionno);
extern Oid GetPartOidWithPartitionno(Oid parentid, int partitionno, char parttype);
extern Oid InvisiblePartidGetNewPartid(Oid partoid);
extern void SetPartitionnoForPartitionState(PartitionState *partTableState);
extern void RelationResetPartitionno(Oid relOid, LOCKMODE relationlock);
extern int GetPartitionnoFromSequence(PartitionMap *partmap, int partseq);
#define PARTITION_LOG(format, ...) \
do { \
if (module_logging_is_on(MOD_PARTITION)) { \
ereport(DEBUG2, (errmodule(MOD_PARTITION), errmsg(format, ##__VA_ARGS__), ignore_interrupt(true))); \
} \
} while (0)
extern const uint32 PARTITION_ENHANCE_VERSION_NUM;
#define PARTITIONNO_IN_UPGRADE (t_thrd.proc->workingVersionNum < PARTITION_ENHANCE_VERSION_NUM)
#define PARTITIONNO_VALID_ASSERT(partitionno) \
Assert(PARTITIONNO_IN_UPGRADE || (!PARTITIONNO_IN_UPGRADE && (partitionno) > 0))
typedef void (*PartitionNameGetPartidCallback) (Oid partitioned_relation, const char *partition_name, Oid partId,
Oid oldPartId, char partition_type, void *callback_arg, LOCKMODE callbackobj_lockMode);
struct PartitionExprKeyInfo {
bool partkeyexprIsNull;
bool partkeyIsFunc;
char* partExprKeyStr;
PartitionExprKeyInfo()
{
partkeyexprIsNull = true;
partkeyIsFunc = false;
partExprKeyStr = NULL;
}
};
struct PartitionTupleInfo {
int2vector* pkey;
oidvector* intablespace;
Datum interval;
Datum boundaries;
Datum transitionPoint;
Datum reloptions;
int partitionno;
int subpartitionno;
PartitionExprKeyInfo partexprkeyinfo;
PartitionTupleInfo()
{
pkey = NULL;
intablespace = NULL;
interval = (Datum)0;
boundaries = (Datum)0;
transitionPoint = (Datum)0;
reloptions = (Datum)0;
partitionno = INVALID_PARTITION_NO;
subpartitionno = INVALID_PARTITION_NO;
partexprkeyinfo = PartitionExprKeyInfo();
}
};
extern void insertPartitionEntry(Relation pg_partition_desc, Partition new_part_desc, Oid new_part_id,
PartitionTupleInfo *partTupleInfo);
extern bool isPartitionedObject(Oid relid, char relkind, bool missing_ok);
extern bool isSubPartitionedObject(Oid relid, char relkind, bool missing_ok);
extern bool isPartitionObject(Oid partid, char partkind, bool missing_ok);
extern Oid getPartitionIndexOid(Oid indexid, Oid partitionid);
extern Oid getPartitionIndexTblspcOid(Oid indexid, Oid partitionid);
extern char* getPartitionIndexName(Oid indexid, Oid partitionid);
extern Oid indexPartGetHeapPart(Oid indexPart, bool missing_ok);
extern Oid searchPartitionIndexOid(Oid partitionedIndexid, List *pindex);
extern List *getPartitionObjectIdList(Oid relid, char relkind);
extern List* getSubPartitionObjectIdList(Oid relid);
extern Oid PartitionNameGetPartitionOid (Oid partitionedTableOid,
const char *partitionName,
char objectType,
LOCKMODE lockMode,
bool missingOk,
bool noWait,
PartitionNameGetPartidCallback callback,
void *callback_arg,
LOCKMODE callbackobj_lockMode);
extern Oid SubPartitionNameGetSubPartitionOid(Oid partitionedRelationOid,
const char* subpartitionName,
LOCKMODE partlock,
LOCKMODE subpartlock,
bool missingOk,
bool noWait,
PartitionNameGetPartidCallback callback,
void* callback_arg,
LOCKMODE callbackobj_lockMode,
Oid *partOidForSubPart);
extern Oid PartitionValuesGetPartitionOid(Relation rel, List *partKeyValueList, LOCKMODE lockMode, bool topClosed,
bool missingOk, bool noWait);
extern Oid SubPartitionValuesGetSubPartitionOid(Relation rel, List *partKeyValueList, List *subpartKeyValueList,
LOCKMODE partlock, LOCKMODE subpartlock, bool topClosed, bool missingOk, bool noWait, Oid *partOidForSubPart);
extern List *searchPartitionIndexesByblid(Oid blid);
extern List *searchPgPartitionByParentId(char parttype, Oid parentId, ScanDirection direction = ForwardScanDirection);
extern List *searchPgSubPartitionByParentId(char parttype, List *parentOids,
ScanDirection direction = ForwardScanDirection);
extern void freePartList(List *l);
extern HeapTuple searchPgPartitionByParentIdCopy(char parttype, Oid parentId);
extern Oid GetBaseRelOidOfParition(Relation relation);
extern List* relationGetPartitionOidList(Relation rel);
extern List* RelationGetSubPartitionOidList(Relation rel, LOCKMODE lockmode = AccessShareLock, bool estimate = false);
extern List* RelationGetSubPartitionOidListList(Relation rel);
extern List* relationGetPartitionList(Relation relation, LOCKMODE lockmode);
extern List* RelationGetPartitionNameList(Relation relation);
extern void RelationGetSubpartitionInfo(Relation relation, char *subparttype, List **subpartKeyPosList,
int2vector **subpartitionKey);
extern List* indexGetPartitionOidList(Relation indexRelation);
extern List* indexGetPartitionList(Relation indexRelation, LOCKMODE lockmode);
extern Relation SubPartitionGetRelation(Relation heap, Partition indexpart, LOCKMODE lockmode);
extern Partition SubPartitionOidGetPartition(Relation rel, Oid subPartOid, LOCKMODE lockmode);
extern Relation SubPartitionOidGetParentRelation(Relation rel, Oid subPartOid, LOCKMODE lockmode);
extern List* RelationGetSubPartitionList(Relation relation, LOCKMODE lockmode);
extern void releasePartitionList(Relation relation, List** partList, LOCKMODE lockmode, bool validCheck = true);
extern void releaseSubPartitionList(Relation relation, List** partList, LOCKMODE lockmode);
extern void releasePartitionOidList(List** partList);
extern void ReleaseSubPartitionOidList(List** partList);
extern bool PartExprKeyIsNull(Relation rel, char** partExprKeyStr = NULL);
#endif