From 6e1550230d2f044c32febff40ce9e22c399ea133 Mon Sep 17 00:00:00 2001 From: Peter Smith Date: Tue, 23 Dec 2025 15:22:40 +1100 Subject: [PATCH v20251223] VCI - changes to postgres core --- src/backend/access/heap/heapam.c | 18 ++++ src/backend/access/heap/heapam_handler.c | 4 + src/backend/access/heap/heapam_visibility.c | 6 ++ src/backend/access/transam/xlogfuncs.c | 1 + src/backend/access/transam/xlogrecovery.c | 18 +++- src/backend/catalog/dependency.c | 7 ++ src/backend/catalog/index.c | 33 +++++++- src/backend/commands/explain.c | 24 +++++- src/backend/commands/indexcmds.c | 109 ++++++++++++------------ src/backend/commands/tablecmds.c | 125 ++++++++++++++++++++++++++++ src/backend/commands/vacuum.c | 16 ++++ src/backend/executor/execAmi.c | 2 + src/backend/executor/execExpr.c | 6 +- src/backend/executor/execExprInterp.c | 36 ++++++++ src/backend/executor/execProcnode.c | 1 + src/backend/executor/execScan.c | 2 +- src/backend/executor/nodeCustom.c | 16 ++++ src/backend/executor/nodeModifyTable.c | 10 +++ src/backend/jit/llvm/llvmjit_expr.c | 12 +++ src/backend/jit/llvm/llvmjit_types.c | 2 + src/backend/nodes/gen_node_support.pl | 56 ++++++++++--- src/backend/optimizer/path/allpaths.c | 18 +++- src/backend/optimizer/plan/createplan.c | 4 +- src/backend/storage/ipc/procarray.c | 3 +- src/backend/storage/lmgr/lock.c | 26 +++++- src/backend/utils/adt/timestamp.c | 18 +--- src/backend/utils/cache/relcache.c | 66 +++++++++++++++ src/bin/pg_dump/common.c | 1 + src/bin/pg_dump/pg_dump.c | 35 +++++++- src/bin/pg_dump/pg_dump.h | 1 + src/include/access/heapam.h | 4 + src/include/access/xlogrecovery.h | 3 + src/include/catalog/dependency.h | 3 + src/include/catalog/index.h | 2 + src/include/commands/explain.h | 4 + src/include/commands/tablecmds.h | 6 ++ src/include/datatype/timestamp.h | 22 +++++ src/include/executor/execExpr.h | 16 ++++ src/include/executor/nodeModifyTable.h | 2 + src/include/nodes/extensible.h | 4 + src/include/nodes/params.h | 2 + src/include/nodes/plannodes.h | 3 + src/include/optimizer/planner.h | 2 + src/include/utils/relcache.h | 5 ++ src/include/utils/snapshot.h | 10 +++ 45 files changed, 664 insertions(+), 100 deletions(-) diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 6daf4a8..9ae9b61 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -54,6 +54,7 @@ #include "utils/spccache.h" #include "utils/syscache.h" +void (*add_index_delete_hook) (Relation indexRelation, const ItemPointerData *heap_tid, TransactionId xmin) = NULL; static HeapTuple heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid, CommandId cid, int options); @@ -366,6 +367,9 @@ initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock) * results for a non-MVCC snapshot, the caller must hold some higher-level * lock that ensures the interesting tuple(s) won't change.) */ + if (keep_startblock) + goto skip_get_number_of_blocks; + if (scan->rs_base.rs_parallel != NULL) { bpscan = (ParallelBlockTableScanDesc) scan->rs_base.rs_parallel; @@ -374,6 +378,8 @@ initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock) else scan->rs_nblocks = RelationGetNumberOfBlocks(scan->rs_base.rs_rd); +skip_get_number_of_blocks: + /* * If the table is large relative to NBuffers, use a bulk-read access * strategy and enable synchronized scanning (see syncscan.c). Although @@ -2821,6 +2827,7 @@ heap_delete(Relation relation, const ItemPointerData *tid, bool all_visible_cleared = false; HeapTuple old_key_tuple = NULL; /* replica identity of the tuple */ bool old_key_copied = false; + TransactionId old_xmin; Assert(ItemPointerIsValid(tid)); @@ -3067,6 +3074,8 @@ l1: xid, LockTupleExclusive, true, &new_xmax, &new_infomask, &new_infomask2); + old_xmin = HeapTupleHeaderGetXmin(tp.t_data); + START_CRIT_SECTION(); /* @@ -3212,6 +3221,9 @@ l1: if (old_key_tuple != NULL && old_key_copied) heap_freetuple(old_key_tuple); + if (add_index_delete_hook) + add_index_delete_hook(relation, tid, old_xmin); + return TM_Ok; } @@ -3314,6 +3326,7 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, infomask2_old_tuple, infomask_new_tuple, infomask2_new_tuple; + TransactionId old_xmin; Assert(ItemPointerIsValid(otid)); @@ -3760,6 +3773,8 @@ l2: &xmax_old_tuple, &infomask_old_tuple, &infomask2_old_tuple); + old_xmin = HeapTupleHeaderGetRawXmin(oldtup.t_data); + /* * And also prepare an Xmax value for the new copy of the tuple. If there * was no xmax previously, or there was one but all lockers are now gone, @@ -4243,6 +4258,9 @@ l2: bms_free(modified_attrs); bms_free(interesting_attrs); + if (add_index_delete_hook) + add_index_delete_hook(relation, otid, old_xmin); + return TM_Ok; } diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index dd4fe6b..039ab8c 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -46,6 +46,9 @@ #include "utils/builtins.h" #include "utils/rel.h" +/* Preserve the original heap tuple that is passed to callback in heapam_index_build_range_scan() */ +HeapTuple IndexHeapTuple; + static void reform_and_rewrite_tuple(HeapTuple tuple, Relation OldHeap, Relation NewHeap, Datum *values, bool *isnull, RewriteState rwstate); @@ -1658,6 +1661,7 @@ heapam_index_build_range_scan(Relation heapRelation, * some index AMs want to do further processing on the data first. So * pass the values[] and isnull[] arrays, instead. */ + IndexHeapTuple = heapTuple; if (HeapTupleIsHeapOnly(heapTuple)) { diff --git a/src/backend/access/heap/heapam_visibility.c b/src/backend/access/heap/heapam_visibility.c index bf899c2..3fe0e50 100644 --- a/src/backend/access/heap/heapam_visibility.c +++ b/src/backend/access/heap/heapam_visibility.c @@ -78,6 +78,8 @@ #include "utils/builtins.h" #include "utils/snapmgr.h" +bool (*add_snapshot_satisfies_hook) (HeapTuple tup, Snapshot snapshot, Buffer buffer); + /* * SetHintBits() @@ -1620,6 +1622,10 @@ HeapTupleSatisfiesVisibility(HeapTuple htup, Snapshot snapshot, Buffer buffer) return HeapTupleSatisfiesHistoricMVCC(htup, snapshot, buffer); case SNAPSHOT_NON_VACUUMABLE: return HeapTupleSatisfiesNonVacuumable(htup, snapshot, buffer); + case SNAPSHOT_VCI_WOS2ROS: + case SNAPSHOT_VCI_LOCALROS: + if (add_snapshot_satisfies_hook) + return add_snapshot_satisfies_hook(htup, snapshot, buffer); } return false; /* keep compiler quiet */ diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c index 339cb75..12b1cc6 100644 --- a/src/backend/access/transam/xlogfuncs.c +++ b/src/backend/access/transam/xlogfuncs.c @@ -607,6 +607,7 @@ pg_get_wal_replay_pause_state(PG_FUNCTION_ARGS) statestr = "not paused"; break; case RECOVERY_PAUSE_REQUESTED: + case RECOVERY_VCI_PAUSE_REQUESTED: statestr = "pause requested"; break; case RECOVERY_PAUSED: diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c index 38b594d..ef3969f 100644 --- a/src/backend/access/transam/xlogrecovery.c +++ b/src/backend/access/transam/xlogrecovery.c @@ -2970,7 +2970,8 @@ recoveryPausesHere(bool endOfRecovery) ereport(LOG, (errmsg("pausing at the end of recovery"), errhint("Execute pg_wal_replay_resume() to promote."))); - else + /* If pause requested by VCI, the log is not output. */ + else if (GetRecoveryPauseState() != RECOVERY_VCI_PAUSE_REQUESTED) ereport(LOG, (errmsg("recovery has paused"), errhint("Execute pg_wal_replay_resume() to continue."))); @@ -3136,6 +3137,18 @@ SetRecoveryPause(bool recoveryPause) ConditionVariableBroadcast(&XLogRecoveryCtl->recoveryNotPausedCV); } +/* Set the recovery pause requested for VCI. */ +void +SetVciRecoveryPause(void) +{ + SpinLockAcquire(&XLogRecoveryCtl->info_lck); + + if (XLogRecoveryCtl->recoveryPauseState == RECOVERY_NOT_PAUSED) + XLogRecoveryCtl->recoveryPauseState = RECOVERY_VCI_PAUSE_REQUESTED; + + SpinLockRelease(&XLogRecoveryCtl->info_lck); +} + /* * Confirm the recovery pause by setting the recovery pause state to * RECOVERY_PAUSED. @@ -3145,7 +3158,8 @@ ConfirmRecoveryPaused(void) { /* If recovery pause is requested then set it paused */ SpinLockAcquire(&XLogRecoveryCtl->info_lck); - if (XLogRecoveryCtl->recoveryPauseState == RECOVERY_PAUSE_REQUESTED) + if (XLogRecoveryCtl->recoveryPauseState == RECOVERY_PAUSE_REQUESTED || + XLogRecoveryCtl->recoveryPauseState == RECOVERY_VCI_PAUSE_REQUESTED) XLogRecoveryCtl->recoveryPauseState = RECOVERY_PAUSED; SpinLockRelease(&XLogRecoveryCtl->info_lck); } diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 7489bbd..544350a 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -86,6 +86,7 @@ #include "utils/lsyscache.h" #include "utils/syscache.h" +bool (*add_drop_relation_hook) (const ObjectAddress *object, int flags) = NULL; /* * Deletion processing requires additional state for each ObjectAddress that @@ -1407,6 +1408,12 @@ doDeletion(const ObjectAddress *object, int flags) { char relKind = get_rel_relkind(object->objectId); + if (add_drop_relation_hook) + { + if (add_drop_relation_hook(object, flags)) + break; + } + if (relKind == RELKIND_INDEX || relKind == RELKIND_PARTITIONED_INDEX) { diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 8dea58a..862e569 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -133,6 +133,7 @@ static void ResetReindexProcessing(void); static void SetReindexPending(List *indexes); static void RemoveReindexPending(Oid indexOid); +bool (*add_reindex_index_hook) (Relation) = NULL; /* * relationHasPrimaryKey @@ -342,12 +343,17 @@ ConstructTupleDescriptor(Relation heapRelation, /* Simple index column */ const FormData_pg_attribute *from; - Assert(atnum > 0); /* should've been caught above */ - if (atnum > natts) /* safety check */ elog(ERROR, "invalid column number %d", atnum); - from = TupleDescAttr(heapTupDesc, - AttrNumberGetAttrOffset(atnum)); + if (atnum > 0) + { + from = TupleDescAttr(heapTupDesc, + AttrNumberGetAttrOffset(atnum)); + } + else + { + from = SystemAttributeDefinition(atnum); + } to->atttypid = from->atttypid; to->attlen = from->attlen; @@ -3692,6 +3698,25 @@ reindex_index(const ReindexStmt *stmt, Oid indexId, return; } + if (add_reindex_index_hook) + { + if (!add_reindex_index_hook(iRel)) + { + RemoveReindexPending(RelationGetRelid(iRel)); + + /* Roll back any GUC changes */ + AtEOXact_GUC(false, save_nestlevel); + + /* Restore userid and security context */ + SetUserIdAndSecContext(save_userid, save_sec_context); + + /* Close rels, but keep locks */ + index_close(iRel, NoLock); + table_close(heapRelation, NoLock); + return; + } + } + if (progress) pgstat_progress_update_param(PROGRESS_CREATEIDX_ACCESS_METHOD_OID, iRel->rd_rel->relam); diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 5a63906..250d0a1 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -1208,6 +1208,7 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used) ((ForeignScan *) plan)->fs_base_relids); break; case T_CustomScan: + case T_CustomPlanMarkPos: *rels_used = bms_add_members(*rels_used, ((CustomScan *) plan)->custom_relids); break; @@ -1511,6 +1512,7 @@ ExplainNode(PlanState *planstate, List *ancestors, } break; case T_CustomScan: + case T_CustomPlanMarkPos: sname = "Custom Scan"; custom_name = ((CustomScan *) plan)->methods->CustomName; if (custom_name) @@ -1674,10 +1676,18 @@ ExplainNode(PlanState *planstate, List *ancestors, ExplainScanTarget((Scan *) plan, es); break; case T_ForeignScan: - case T_CustomScan: if (((Scan *) plan)->scanrelid > 0) ExplainScanTarget((Scan *) plan, es); break; + case T_CustomScan: + case T_CustomPlanMarkPos: + { + CustomScanState *css = (CustomScanState *) planstate; + + if (css->methods->ExplainCustomPlanTargetRel) + css->methods->ExplainCustomPlanTargetRel(css, es); + } + break; case T_IndexScan: { IndexScan *indexscan = (IndexScan *) plan; @@ -2149,6 +2159,7 @@ ExplainNode(PlanState *planstate, List *ancestors, show_foreignscan_info((ForeignScanState *) planstate, es); break; case T_CustomScan: + case T_CustomPlanMarkPos: { CustomScanState *css = (CustomScanState *) planstate; @@ -2410,6 +2421,7 @@ ExplainNode(PlanState *planstate, List *ancestors, "Subquery", NULL, es); break; case T_CustomScan: + case T_CustomPlanMarkPos: ExplainCustomChildren((CustomScanState *) planstate, ancestors, es); break; @@ -4434,6 +4446,7 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es) case T_TidRangeScan: case T_ForeignScan: case T_CustomScan: + case T_CustomPlanMarkPos: case T_ModifyTable: /* Assert it's on a real relation */ Assert(rte->rtekind == RTE_RELATION); @@ -5115,3 +5128,12 @@ ExplainFlushWorkersState(ExplainState *es) pfree(wstate->worker_state_save); pfree(wstate); } + +void +ExplainPropertySortGroupKeys(PlanState *planstate, const char *qlabel, + int nkeys, AttrNumber *keycols, + List *ancestors, ExplainState *es) +{ + show_sort_group_keys(planstate, qlabel, nkeys, 0, keycols, + NULL, NULL, NULL, ancestors, es); +} diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index d9cccb6..4c3748d 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -1097,71 +1097,74 @@ DefineIndex(Oid tableId, } } - - /* - * We disallow indexes on system columns. They would not necessarily get - * updated correctly, and they don't seem useful anyway. - * - * Also disallow virtual generated columns in indexes (use expression - * index instead). - */ - for (int i = 0; i < indexInfo->ii_NumIndexAttrs; i++) - { - AttrNumber attno = indexInfo->ii_IndexAttrNumbers[i]; - - if (attno < 0) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("index creation on system columns is not supported"))); - - - if (TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL) - ereport(ERROR, - errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - stmt->primary ? - errmsg("primary keys on virtual generated columns are not supported") : - stmt->isconstraint ? - errmsg("unique constraints on virtual generated columns are not supported") : - errmsg("indexes on virtual generated columns are not supported")); - } - - /* - * Also check for system and generated columns used in expressions or - * predicates. - */ - if (indexInfo->ii_Expressions || indexInfo->ii_Predicate) + /* Skip disallowing index creation of system columns for VCI access method */ + if (strcmp(accessMethodName, "vci") != 0) { - Bitmapset *indexattrs = NULL; - int j; - pull_varattnos((Node *) indexInfo->ii_Expressions, 1, &indexattrs); - pull_varattnos((Node *) indexInfo->ii_Predicate, 1, &indexattrs); - - for (int i = FirstLowInvalidHeapAttributeNumber + 1; i < 0; i++) + /* + * We disallow indexes on system columns. They would not necessarily + * get updated correctly, and they don't seem useful anyway. + * + * Also disallow virtual generated columns in indexes (use expression + * index instead). + */ + for (int i = 0; i < indexInfo->ii_NumIndexAttrs; i++) { - if (bms_is_member(i - FirstLowInvalidHeapAttributeNumber, - indexattrs)) + AttrNumber attno = indexInfo->ii_IndexAttrNumbers[i]; + + if (attno < 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("index creation on system columns is not supported"))); + + if (TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL) + ereport(ERROR, + errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + stmt->primary ? + errmsg("primary keys on virtual generated columns are not supported") : + stmt->isconstraint ? + errmsg("unique constraints on virtual generated columns are not supported") : + errmsg("indexes on virtual generated columns are not supported")); } /* - * XXX Virtual generated columns in index expressions or predicates - * could be supported, but it needs support in - * RelationGetIndexExpressions() and RelationGetIndexPredicate(). + * Also check for system and generated columns used in expressions or + * predicates. */ - j = -1; - while ((j = bms_next_member(indexattrs, j)) >= 0) + if (indexInfo->ii_Expressions || indexInfo->ii_Predicate) { - AttrNumber attno = j + FirstLowInvalidHeapAttributeNumber; + Bitmapset *indexattrs = NULL; + int j; - if (TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - stmt->isconstraint ? - errmsg("unique constraints on virtual generated columns are not supported") : - errmsg("indexes on virtual generated columns are not supported"))); + pull_varattnos((Node *) indexInfo->ii_Expressions, 1, &indexattrs); + pull_varattnos((Node *) indexInfo->ii_Predicate, 1, &indexattrs); + + for (int i = FirstLowInvalidHeapAttributeNumber + 1; i < 0; i++) + { + if (bms_is_member(i - FirstLowInvalidHeapAttributeNumber, + indexattrs)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("index creation on system columns is not supported"))); + } + + /* + * XXX Virtual generated columns in index expressions or + * predicates could be supported, but it needs support in + * RelationGetIndexExpressions() and RelationGetIndexPredicate(). + */ + j = -1; + while ((j = bms_next_member(indexattrs, j)) >= 0) + { + AttrNumber attno = j + FirstLowInvalidHeapAttributeNumber; + + if (TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + stmt->isconstraint ? + errmsg("unique constraints on virtual generated columns are not supported") : + errmsg("indexes on virtual generated columns are not supported"))); + } } } diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 6b1a00e..78ed69b 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -110,6 +110,10 @@ #include "utils/typcache.h" #include "utils/usercontext.h" +bool (*add_alter_tablespace_hook) (Relation rel) = NULL; +void (*add_alter_table_change_owner_hook) (Oid relOid, char relKind, Oid newOwnerId) = NULL; +void (*add_alter_table_change_schema_hook) (Oid relOid, char relKind, Oid newNspOid) = NULL; + /* * ON COMMIT action list */ @@ -16322,6 +16326,9 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock /* If it has dependent sequences, recurse to change them too */ change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode); + + if (add_alter_table_change_owner_hook) + add_alter_table_change_owner_hook(relationOid, tuple_class->relkind, newOwnerId); } InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0); @@ -16871,6 +16878,112 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, } table_close(pgclass, RowExclusiveLock); + + /* + * Look up the index's access method, save the OID of its handler function + */ + if (rel->rd_rel->relam) + { + Form_pg_am aform; + HeapTuple amtuple; + + amtuple = SearchSysCache1(AMOID, ObjectIdGetDatum(rel->rd_rel->relam)); + if (!HeapTupleIsValid(amtuple)) + elog(ERROR, "cache lookup failed for access method %u", + rel->rd_rel->relam); + aform = (Form_pg_am) GETSTRUCT(amtuple); + + if (strcmp(NameStr(aform->amname), "vci") == 0) + + /* + * if((rel->rd_am) && (strcmp(NameStr(rel->rd_am->amname), "vci") + * == 0)) + */ + { + Relation depRel, + viewRel; + Oid vci_relid, + viewrelid; + ScanKeyData key; + SysScanDesc scan; + HeapTuple tup; + + depRel = table_open(DependRelationId, AccessShareLock); + vci_relid = RelationGetRelid(rel); + ScanKeyInit(&key, + Anum_pg_depend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(vci_relid)); + scan = systable_beginscan(depRel, DependReferenceIndexId, true, + NULL, 1, &key); + while (HeapTupleIsValid((tup = systable_getnext(scan)))) + { + Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); + + /* Retrieve objid of the internal function */ + if (depform->classid == RelationRelationId) + { + viewrelid = depform->objid; + viewRel = table_open(viewrelid, AccessExclusiveLock); + pgclass = table_open(RelationRelationId, RowExclusiveLock); + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(viewrelid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", viewrelid); + + datum = (Datum) 0; + + /* Generate new proposed reloptions (text array) */ + newOptions = transformRelOptions(datum, defList, NULL, validnsps, false, + operation == AT_ResetRelOptions); + + (void) view_reloptions(newOptions, true); + + /* + * All we need do here is update the pg_class row; the new + * options will be propagated into relcaches during + * post-commit cache inval. + */ + memset(repl_val, 0, sizeof(repl_val)); + memset(repl_null, false, sizeof(repl_null)); + memset(repl_repl, false, sizeof(repl_repl)); + + if (newOptions != (Datum) 0) + repl_val[Anum_pg_class_reloptions - 1] = newOptions; + else + repl_null[Anum_pg_class_reloptions - 1] = true; + + repl_repl[Anum_pg_class_reloptions - 1] = true; + + newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass), + repl_val, repl_null, repl_repl); + + /* + * simple_heap_update(pgclass, &newtuple->t_self, + * newtuple); + * + * CatalogUpdateIndexes(pgclass, newtuple); + */ + /* Perform actual update */ + CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple); + InvokeObjectPostAlterHook(RelationRelationId, viewrelid, 0); + + heap_freetuple(newtuple); + + ReleaseSysCache(tuple); + + table_close(pgclass, RowExclusiveLock); + table_close(viewRel, AccessExclusiveLock); + + } + } + + systable_endscan(scan); + + table_close(depRel, AccessShareLock); + } + + ReleaseSysCache(amtuple); + } } /* @@ -16892,6 +17005,15 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode) */ rel = relation_open(tableOid, lockmode); + if (add_alter_tablespace_hook) + { + if (add_alter_tablespace_hook(rel)) + { + relation_close(rel, NoLock); + return; + } + } + /* Check first if relation can be moved to new tablespace */ if (!CheckRelationTableSpaceMove(rel, newTableSpace)) { @@ -19141,6 +19263,9 @@ AlterRelationNamespaceInternal(Relation classRel, Oid relOid, { add_exact_object_address(&thisobj, objsMoved); + if (add_alter_table_change_schema_hook) + add_alter_table_change_schema_hook(relOid, classForm->relkind, newNspOid); + InvokeObjectPostAlterHook(RelationRelationId, relOid, 0); } diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 0528d1b..0ce8f6a 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -131,6 +131,8 @@ static double compute_parallel_delay(void); static VacOptValue get_vacoptval_from_boolean(DefElem *def); static bool vac_tid_reaped(ItemPointer itemptr, void *state); +bool (*add_skip_vacuum_hook) (Relation rel); + /* * GUC check function to ensure GUC value specified is within the allowable * range. @@ -2131,6 +2133,20 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, } /* + * Silently ignore if it's a VCI internal table. + */ + if (add_skip_vacuum_hook) + { + if (add_skip_vacuum_hook(rel)) + { + relation_close(rel, lmode); + PopActiveSnapshot(); + CommitTransactionCommand(); + return false; + } + } + + /* * Silently ignore tables that are temp tables of other backends --- * trying to vacuum these will lead to great unhappiness, since their * contents are probably not up-to-date on disk. (We don't throw a diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c index 1d0e8ad..fff1b85 100644 --- a/src/backend/executor/execAmi.c +++ b/src/backend/executor/execAmi.c @@ -437,6 +437,7 @@ ExecSupportsMarkRestore(Path *pathnode) return true; case T_CustomScan: + case T_CustomPlanMarkPos: if (castNode(CustomPath, pathnode)->flags & CUSTOMPATH_SUPPORT_MARK_RESTORE) return true; return false; @@ -563,6 +564,7 @@ ExecSupportsBackwardScan(Plan *node) return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan); case T_CustomScan: + case T_CustomPlanMarkPos: if (((CustomScan *) node)->flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN) return true; return false; diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index c35744b..f421ea3 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -68,7 +68,6 @@ typedef struct ExprSetupInfo List *multiexpr_subplans; } ExprSetupInfo; -static void ExecReadyExpr(ExprState *state); static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull); static void ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, @@ -77,7 +76,6 @@ static void ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, static void ExecInitSubPlanExpr(SubPlan *subplan, ExprState *state, Datum *resv, bool *resnull); -static void ExecCreateExprSetupSteps(ExprState *state, Node *node); static void ExecPushExprSetupSteps(ExprState *state, ExprSetupInfo *info); static bool expr_setup_walker(Node *node, ExprSetupInfo *info); static bool ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op); @@ -898,7 +896,7 @@ ExecCheck(ExprState *state, ExprContext *econtext) * Therefore this should be used instead of directly calling * ExecReadyInterpretedExpr(). */ -static void +void ExecReadyExpr(ExprState *state) { if (jit_compile_expr(state)) @@ -2870,7 +2868,7 @@ ExecInitSubPlanExpr(SubPlan *subplan, * Add expression steps performing setup that's needed before any of the * main execution of the expression. */ -static void +void ExecCreateExprSetupSteps(ExprState *state, Node *node) { ExprSetupInfo info = {0, 0, 0, 0, 0, NIL}; diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 5e7bd93..cf37047 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -188,6 +188,21 @@ static pg_attribute_always_inline void ExecAggPlainTransByRef(AggState *aggstate int setno); static char *ExecGetJsonValueItemString(JsonbValue *item, bool *resnull); +ExprEvalVar_hook_type ExprEvalVar_hook = NULL; +ExprEvalParam_hook_type ExprEvalParam_hook = NULL; +void +VciExprEvalVarHook(ExprState *state, ExprEvalStep *op, ExprContext *econtext) +{ + Assert(ExprEvalVar_hook != NULL); + (*ExprEvalVar_hook) (state, op, econtext); +} +void +VciExprEvalParamHook(ExprState *state, ExprEvalStep *op, ExprContext *econtext) +{ + Assert(ExprEvalParam_hook != NULL); + (*ExprEvalParam_hook) (state, op, econtext); +} + /* * ScalarArrayOpExprHashEntry * Hash table entry type used during EEOP_HASHED_SCALARARRAYOP @@ -592,6 +607,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) &&CASE_EEOP_AGG_PRESORTED_DISTINCT_MULTI, &&CASE_EEOP_AGG_ORDERED_TRANS_DATUM, &&CASE_EEOP_AGG_ORDERED_TRANS_TUPLE, + &&CASE_EEOP_VCI_VAR, + &&CASE_EEOP_VCI_PARAM_EXEC, &&CASE_EEOP_LAST }; @@ -2265,6 +2282,25 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_NEXT(); } + EEO_CASE(EEOP_VCI_VAR) + { + /* TO-do */ + Assert(ExprEvalVar_hook != NULL); + (*ExprEvalVar_hook) (state, op, econtext); + + EEO_NEXT(); + } + + EEO_CASE(EEOP_VCI_PARAM_EXEC) + { + /* To-do */ + Assert(ExprEvalParam_hook != NULL); + (*ExprEvalParam_hook) (state, op, econtext); + + EEO_NEXT(); + } + + EEO_CASE(EEOP_LAST) { /* unreachable */ diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c index f5f9cfb..60fd2a4 100644 --- a/src/backend/executor/execProcnode.c +++ b/src/backend/executor/execProcnode.c @@ -287,6 +287,7 @@ ExecInitNode(Plan *node, EState *estate, int eflags) break; case T_CustomScan: + case T_CustomPlanMarkPos: result = (PlanState *) ExecInitCustomScan((CustomScan *) node, estate, eflags); break; diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c index 31ed478..b12f0c9 100644 --- a/src/backend/executor/execScan.c +++ b/src/backend/executor/execScan.c @@ -139,7 +139,7 @@ ExecScanReScan(ScanState *node) */ if (IsA(node->ps.plan, ForeignScan)) relids = ((ForeignScan *) node->ps.plan)->fs_base_relids; - else if (IsA(node->ps.plan, CustomScan)) + else if (IsA(node->ps.plan, CustomScan) || IsA(node->ps.plan, CustomPlanMarkPos)) relids = ((CustomScan *) node->ps.plan)->custom_relids; else elog(ERROR, "unexpected scan node: %d", diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c index ac2196b..2eaef2f 100644 --- a/src/backend/executor/nodeCustom.c +++ b/src/backend/executor/nodeCustom.c @@ -49,6 +49,22 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags) css->ss.ps.state = estate; css->ss.ps.ExecProcNode = ExecCustomScan; + if (strcmp(cscan->methods->CustomName, "VCI Scan") == 0 || + strcmp(cscan->methods->CustomName, "VCI Sort") == 0 || + strcmp(cscan->methods->CustomName, "VCI Aggregate") == 0 || + strcmp(cscan->methods->CustomName, "VCI HashAggregate") == 0 || + strcmp(cscan->methods->CustomName, "VCI GroupAggregate") == 0 || + strcmp(cscan->methods->CustomName, "VCI Gather") == 0) + { + /* + * The callback of custom-scan provider applies the final + * initialization of the custom-scan-state node according to its + * logic. + */ + css->methods->BeginCustomScan(css, estate, eflags); + return css; + } + /* create expression context for node */ ExecAssignExprContext(estate, &css->ss.ps); diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 874b71e..b1e25a0 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -72,6 +72,7 @@ #include "utils/rel.h" #include "utils/snapmgr.h" +List *(*add_should_index_insert_hook) (ResultRelInfo *, TupleTableSlot *, ItemPointer, EState *) = NULL; typedef struct MTTargetRelLookup { @@ -2333,6 +2334,15 @@ ExecUpdateEpilogue(ModifyTableContext *context, UpdateContext *updateCxt, NULL, NIL, (updateCxt->updateIndexes == TU_Summarizing)); + /* + * VCI update hook + */ + else if (resultRelInfo->ri_NumIndices > 0 && !updateCxt->updateIndexes) + { + if (add_should_index_insert_hook) + recheckIndexes = add_should_index_insert_hook(resultRelInfo, slot, &slot->tts_tid, context->estate); + } + /* AFTER ROW UPDATE Triggers */ ExecARUpdateTriggers(context->estate, resultRelInfo, NULL, NULL, diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c index f9c7f29..569b505 100644 --- a/src/backend/jit/llvm/llvmjit_expr.c +++ b/src/backend/jit/llvm/llvmjit_expr.c @@ -2940,6 +2940,18 @@ llvm_compile_expr(ExprState *state) LLVMBuildBr(b, opblocks[opno + 1]); break; + case EEOP_VCI_VAR: + build_EvalXFunc(b, mod, "VciExprEvalVarHook", + v_state, op, v_econtext); + LLVMBuildBr(b, opblocks[opno + 1]); + break; + + case EEOP_VCI_PARAM_EXEC: + build_EvalXFunc(b, mod, "VciExprEvalParamHook", + v_state, op, v_econtext); + LLVMBuildBr(b, opblocks[opno + 1]); + break; + case EEOP_LAST: Assert(false); break; diff --git a/src/backend/jit/llvm/llvmjit_types.c b/src/backend/jit/llvm/llvmjit_types.c index 167cd55..4f4a2a9 100644 --- a/src/backend/jit/llvm/llvmjit_types.c +++ b/src/backend/jit/llvm/llvmjit_types.c @@ -182,4 +182,6 @@ void *referenced_functions[] = strlen, varsize_any, ExecInterpExprStillValid, + VciExprEvalParamHook, + VciExprEvalVarHook, }; diff --git a/src/backend/nodes/gen_node_support.pl b/src/backend/nodes/gen_node_support.pl index 9ecddb1..6bd0008 100644 --- a/src/backend/nodes/gen_node_support.pl +++ b/src/backend/nodes/gen_node_support.pl @@ -153,6 +153,7 @@ my @extra_tags = qw( AllocSetContext GenerationContext SlabContext BumpContext TIDBitmap WindowObjectData + CustomPlanMarkPos ); # This is a regular node, but we skip parsing it from its header file @@ -679,10 +680,21 @@ foreach my $n (@node_types) my $struct_no_equal = (elem $n, @no_equal); next if $struct_no_copy && $struct_no_equal; - print $cfs "\t\tcase T_${n}:\n" - . "\t\t\tretval = _copy${n}(from);\n" - . "\t\t\tbreak;\n" - unless $struct_no_copy; + if($n eq 'CustomScan') + { + print $cfs "\t\tcase T_${n}:\n" + . "\t\tcase T_CustomPlanMarkPos:\n" + . "\t\t\tretval = _copy${n}(from);\n" + . "\t\t\tbreak;\n" + unless $struct_no_copy; + } + else + { + print $cfs "\t\tcase T_${n}:\n" + . "\t\t\tretval = _copy${n}(from);\n" + . "\t\t\tbreak;\n" + unless $struct_no_copy; + } print $efs "\t\tcase T_${n}:\n" . "\t\t\tretval = _equal${n}(a, b);\n" @@ -691,13 +703,35 @@ foreach my $n (@node_types) next if elem $n, @custom_copy_equal; - print $cff " -static $n * -_copy${n}(const $n *from) -{ -\t${n} *newnode = makeNode($n); - -" unless $struct_no_copy; + if ($n eq 'CustomScan') + { + print $cff "static $n *\n" + . "_copy${n}(const $n *from)\n" + . "{\n" + . "\tCustomScan *newnode;\n\n" + . "\tif (strcmp(from->methods->CustomName, \"VCI Scan\") == 0 || + strcmp(from->methods->CustomName, \"VCI Sort\") == 0 || + strcmp(from->methods->CustomName, \"VCI Aggregate\") == 0 || + strcmp(from->methods->CustomName, \"VCI HashAggregate\") == 0 || + strcmp(from->methods->CustomName, \"VCI GroupAggregate\") == 0 || + strcmp(from->methods->CustomName, \"VCI Gather\") == 0)\n" + . "\t{\n" + . "\t\tnewnode = from->methods->CopyCustomPlan(from);\n" + . "\t}\n" + . "\telse\n" + . "\t\tnewnode = makeNode(CustomScan);\n\n" + . "\t((Node *) newnode)->type = nodeTag(from);\n\n" unless $struct_no_copy; + } + else + { + print $cff + "static $n *\n" + . "_copy${n}(const $n *from)\n" + . "{\n" + ."\t${n} *newnode = makeNode($n);\n\n" + + unless $struct_no_copy; + } print $eff " static bool diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 4c43fd0..1a38439 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -47,10 +47,10 @@ #include "partitioning/partbounds.h" #include "port/pg_bitutils.h" #include "rewrite/rewriteManip.h" +#include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/selfuncs.h" - /* Bitmask flags for pushdown_safety_info.unsafeFlags */ #define UNSAFE_HAS_VOLATILE_FUNC (1 << 0) #define UNSAFE_HAS_SET_FUNC (1 << 1) @@ -822,6 +822,8 @@ static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) { Relids required_outer; + char *isVCIEnabled; + bool is_partition = false; /* * We don't support pushing join clauses into the quals of a seqscan, but @@ -847,6 +849,20 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) /* If appropriate, consider parallel sequential scan */ if (rel->consider_parallel && required_outer == NULL) create_plain_partial_paths(root, rel); + /**** + * Putting the isRelHasVCIIndex after the create_plain_partial_paths because + * want to enable oss parallelscan working on VCI tables but disable other + * gather plan like parallel_loop,parallel_agg working on VCI tables. + * Don't do this for partitioned tables or partitions as parallelscans on partitioned + * tables require gather plans + */ + if (isRelHasVCIIndex(rte->relid, &is_partition) && (bms_membership(root->all_baserels) == BMS_SINGLETON) && + !is_partition) + { + isVCIEnabled = GetConfigOptionByName("vci.enable", NULL, false); + if (strcmp(isVCIEnabled, "on") == 0) + rel->consider_parallel = false; + } /* Consider index scans */ create_index_paths(root, rel); diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index bc417f9..4f6822f 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -34,6 +34,7 @@ #include "optimizer/placeholder.h" #include "optimizer/plancat.h" #include "optimizer/planmain.h" +#include "optimizer/planner.h" #include "optimizer/prep.h" #include "optimizer/restrictinfo.h" #include "optimizer/subselect.h" @@ -174,7 +175,6 @@ static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index, int indexcol static List *get_switched_clauses(List *clauses, Relids outerrelids); static List *order_qual_clauses(PlannerInfo *root, List *clauses); static void copy_generic_path_info(Plan *dest, Path *src); -static void copy_plan_costsize(Plan *dest, Plan *src); static void label_sort_with_costsize(PlannerInfo *root, Sort *plan, double limit_tuples); static void label_incrementalsort_with_costsize(PlannerInfo *root, IncrementalSort *plan, @@ -5364,7 +5364,7 @@ copy_generic_path_info(Plan *dest, Path *src) * Copy cost and size info from a lower plan node to an inserted node. * (Most callers alter the info after copying it.) */ -static void +void copy_plan_costsize(Plan *dest, Plan *src) { dest->disabled_nodes = src->disabled_nodes; diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index f3a1603..6acb395 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -1925,7 +1925,8 @@ GlobalVisHorizonKindForRel(Relation rel) Assert(!rel || rel->rd_rel->relkind == RELKIND_RELATION || rel->rd_rel->relkind == RELKIND_MATVIEW || - rel->rd_rel->relkind == RELKIND_TOASTVALUE); + rel->rd_rel->relkind == RELKIND_TOASTVALUE || + rel->rd_rel->relkind == RELKIND_INDEX); if (rel == NULL || rel->rd_rel->relisshared || RecoveryInProgress()) return VISHORIZON_SHARED; diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index 9015ba3..2b15c61 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -39,6 +39,8 @@ #include "access/xlogutils.h" #include "miscadmin.h" #include "pg_trace.h" +#include "pgstat.h" +#include "postmaster/bgworker.h" #include "storage/lmgr.h" #include "storage/proc.h" #include "storage/procarray.h" @@ -811,8 +813,18 @@ LockAcquire(const LOCKTAG *locktag, bool sessionLock, bool dontWait) { - return LockAcquireExtended(locktag, lockmode, sessionLock, dontWait, - true, NULL, false); + /* + * Don't lock for VCI parallel workers and other type of workers should go + * in normal flow, In case if there is any change in background worker + * name for VCI parallel workers, the following code also needs an update. + * FIXME: Try to use the community parallelism code, so that we don't need + * our own VCI parallel infrastructure. + */ + if (AmBackgroundWorkerProcess() && strstr(MyBgworkerEntry->bgw_name, "backend=")) + return LOCKACQUIRE_OK; + else + return LockAcquireExtended(locktag, lockmode, sessionLock, dontWait, + true, NULL, false); } /* @@ -2139,6 +2151,16 @@ LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock) */ if (!locallock || locallock->nLocks <= 0) { + /* + * Don't lock for VCI parallel workers and other type of workers + * should go in normal flow, In case if there is any change in + * background worker name for VCI parallel workers, the following code + * also needs an update. FIXME: Try to use the community parallelism + * code, so that we don't need our own VCI parallel infrastructure. + */ + if (AmBackgroundWorkerProcess() && strstr(MyBgworkerEntry->bgw_name, "backend=")) + return true; + elog(WARNING, "you don't own a lock of type %s", lockMethodTable->lockModeNames[lockmode]); return false; diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index 3569d20..1a24cc7 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -24,6 +24,7 @@ #include "catalog/pg_type.h" #include "common/int.h" #include "common/int128.h" +#include "datatype/timestamp.h" #include "funcapi.h" #include "libpq/pqformat.h" #include "miscadmin.h" @@ -73,19 +74,6 @@ typedef struct pg_tz *attimezone; } generate_series_timestamptz_fctx; -/* - * The transition datatype for interval aggregates is declared as internal. - * It's a pointer to an IntervalAggState allocated in the aggregate context. - */ -typedef struct IntervalAggState -{ - int64 N; /* count of finite intervals processed */ - Interval sumX; /* sum of finite intervals processed */ - /* These counts are *not* included in N! Use IA_TOTAL_COUNT() as needed */ - int64 pInfcount; /* count of +infinity intervals */ - int64 nInfcount; /* count of -infinity intervals */ -} IntervalAggState; - #define IA_TOTAL_COUNT(ia) \ ((ia)->N + (ia)->pInfcount + (ia)->nInfcount) @@ -3484,7 +3472,7 @@ interval_larger(PG_FUNCTION_ARGS) PG_RETURN_INTERVAL_P(result); } -static void +void finite_interval_pl(const Interval *span1, const Interval *span2, Interval *result) { Assert(!INTERVAL_NOT_FINITE(span1)); @@ -3963,7 +3951,7 @@ in_range_interval_interval(PG_FUNCTION_ARGS) * context. When the state data needs to be allocated in the current memory * context, we use palloc0 directly e.g. interval_avg_deserialize(). */ -static IntervalAggState * +IntervalAggState * makeIntervalAggState(FunctionCallInfo fcinfo) { IntervalAggState *state; diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 2d0cb7b..6104745 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -92,6 +92,8 @@ #define RELCACHE_INIT_FILEMAGIC 0x573266 /* version ID value */ +bool (*add_skip_vci_index_hook) (Relation rel) = NULL; + /* * Whether to bother checking if relation cache memory needs to be freed * eagerly. See also RelationBuildDesc() and pg_config_manual.h. @@ -5389,6 +5391,16 @@ restart: indexDesc = index_open(indexOid, AccessShareLock); + if (add_skip_vci_index_hook) + { + if (add_skip_vci_index_hook(indexDesc)) + { + /* Skip if Index is VCI index */ + index_close(indexDesc, AccessShareLock); + continue; + } + } + /* * Extract index expressions and index predicate. Note: Don't use * RelationGetIndexExpressions()/RelationGetIndexPredicate(), because @@ -6967,6 +6979,60 @@ unlink_initfile(const char *initfilename, int elevel) } } +bool +isRelHasVCIIndex(Oid relid, bool *is_partition) +{ + ListCell *l; + Relation relation; + + bool hasVCI = false; + + *is_partition = false; + relation = table_open(relid, NoLock); + + if ((relation->rd_rel->relispartition == true) || relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + *is_partition = true; + + if (relation->rd_rel->relhasindex) + { + List *indexoidlist; + + indexoidlist = RelationGetIndexList(relation); + + foreach(l, indexoidlist) + { + Oid relam; + Oid indexoid = lfirst_oid(l); + Relation indexRelation; + Form_pg_am aform; + HeapTuple amtuple; + + indexRelation = index_open(indexoid, AccessShareLock); + relam = indexRelation->rd_rel->relam; + + amtuple = SearchSysCache1(AMOID, ObjectIdGetDatum(relam)); + if (!HeapTupleIsValid(amtuple)) + elog(ERROR, "cache lookup failed for access method %u", + relam); + aform = (Form_pg_am) GETSTRUCT(amtuple); + + if (strcmp(NameStr(aform->amname), "vci") == 0) + { + hasVCI = true; + } + + ReleaseSysCache(amtuple); + index_close(indexRelation, AccessShareLock); + + if (hasVCI) + break; + } + } + + table_close(relation, NoLock); + return hasVCI; +} + /* * ResourceOwner callbacks */ diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index 0007e78..2490c35 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -360,6 +360,7 @@ flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables, AssignDumpId(&attachinfo->dobj); attachinfo->dobj.name = pg_strdup(tblinfo[i].dobj.name); attachinfo->dobj.namespace = tblinfo[i].dobj.namespace; + attachinfo->dobj.isvciview = false; attachinfo->parentTbl = tblinfo[i].parents[0]; attachinfo->partitionTbl = &tblinfo[i]; diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 27f6be3..03a0ae1 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -7566,6 +7566,8 @@ getTables(Archive *fout, int *numTables) tblinfo[i].dummy_view = false; /* might get set during sort */ tblinfo[i].postponed_def = false; /* might get set during sort */ + tblinfo[i].dobj.isvciview = false; + /* Tables have data */ tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA; @@ -8640,6 +8642,17 @@ getRules(Archive *fout) if (ruleinfo[i].ruletable) { /* + * isvciview is set to true when the table is a VCI internal relation. The + * judgement is done by the logic in vci_isVciRelation function + */ + if ((ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW || + ruleinfo[i].ruletable->relkind == RELKIND_VIEW) && + !strcmp(ruleinfo[i].ruletable->dobj.name, ruleinfo[i].dobj.name)) + { + ruleinfo[i].ruletable->dobj.isvciview = true; + } + + /* * If the table is a view or materialized view, force its ON * SELECT rule to be sorted before the view itself --- this * ensures that any dependencies for the rule affect the table's @@ -17105,8 +17118,9 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo) int j, k; - /* We had better have loaded per-column details about this table */ - Assert(tbinfo->interesting); + /* Do not dump VCI internal relations */ + if (tbinfo->dobj.isvciview) + return; qrelname = pg_strdup(fmtId(tbinfo->dobj.name)); qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo)); @@ -20176,12 +20190,27 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs, case DO_FDW: case DO_FOREIGN_SERVER: case DO_TRANSFORM: + + /* + * Do not add dependency for VCI internal relations to suppress dependency + * loop message + */ + if (dobj->isvciview) + break; /* Pre-data objects: must come before the pre-data boundary */ addObjectDependency(preDataBound, dobj->dumpId); break; + case DO_LARGE_OBJECT: + + /* + * Do not add dependency for VCI internal relations to suppress dependency + * loop message + */ + if (dobj->isvciview) + break; + /* fallthrough */ case DO_TABLE_DATA: case DO_SEQUENCE_SET: - case DO_LARGE_OBJECT: case DO_LARGE_OBJECT_DATA: /* Data objects: must come between the boundaries */ addObjectDependency(dobj, preDataBound->dumpId); diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 72a00e1..61a16ff 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -159,6 +159,7 @@ typedef struct _dumpableObject DumpId *dependencies; /* dumpIds of objects this one depends on */ int nDeps; /* number of valid dependencies */ int allocDeps; /* allocated size of dependencies[] */ + bool isvciview; /* this table is avci internal relation */ } DumpableObject; /* diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index f7e4ae3..17b0f13 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -430,6 +430,10 @@ extern void log_heap_prune_and_freeze(Relation relation, Buffer buffer, OffsetNumber *dead, int ndead, OffsetNumber *unused, int nunused); +extern PGDLLIMPORT void (*add_index_delete_hook) (Relation indexRelation, const ItemPointerData *heap_tid, TransactionId xmin); +extern PGDLLIMPORT bool (*add_snapshot_satisfies_hook) (HeapTuple htup, Snapshot snapshot, Buffer buffer); +extern PGDLLIMPORT bool (*add_skip_vacuum_hook) (Relation rel); + /* in heap/vacuumlazy.c */ extern void heap_vacuum_rel(Relation rel, const VacuumParams params, BufferAccessStrategy bstrategy); diff --git a/src/include/access/xlogrecovery.h b/src/include/access/xlogrecovery.h index 8e475e2..c4feb0b 100644 --- a/src/include/access/xlogrecovery.h +++ b/src/include/access/xlogrecovery.h @@ -56,6 +56,7 @@ typedef enum RecoveryPauseState RECOVERY_NOT_PAUSED, /* pause not requested */ RECOVERY_PAUSE_REQUESTED, /* pause requested, but not yet paused */ RECOVERY_PAUSED, /* recovery is paused */ + RECOVERY_VCI_PAUSE_REQUESTED, /* pause requested for VCI query */ } RecoveryPauseState; /* User-settable GUC parameters */ @@ -161,6 +162,8 @@ extern void WakeupRecovery(void); extern void StartupRequestWalReceiverRestart(void); extern void XLogRequestWalReceiverReply(void); +extern void SetVciRecoveryPause(void); + extern void RecoveryRequiresIntParameter(const char *param_name, int currValue, int minValue); extern void xlog_outdesc(StringInfo buf, XLogReaderState *record); diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 35cc35a..0302c85 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -236,4 +236,7 @@ extern void shdepDropOwned(List *roleids, DropBehavior behavior); extern void shdepReassignOwned(List *roleids, Oid newrole); +/* vci index original hook*/ +extern PGDLLIMPORT bool (*add_drop_relation_hook) (const ObjectAddress *object, int flags); + #endif /* DEPENDENCY_H */ diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index dda95e5..898f0cf 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -175,6 +175,8 @@ extern void RestoreReindexState(const void *reindexstate); extern void IndexSetParentIndex(Relation partitionIdx, Oid parentOid); +extern PGDLLIMPORT bool (*add_reindex_index_hook) (Relation); +extern PGDLLIMPORT HeapTuple IndexHeapTuple; /* * itemptr_encode - Encode ItemPointer as int64/int8 diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h index 6e51d50..69641b8 100644 --- a/src/include/commands/explain.h +++ b/src/include/commands/explain.h @@ -81,4 +81,8 @@ extern void ExplainQueryText(ExplainState *es, QueryDesc *queryDesc); extern void ExplainQueryParameters(ExplainState *es, ParamListInfo params, int maxlen); +extern void ExplainPropertySortGroupKeys(PlanState *planstate, const char *qlabel, + int nkeys, AttrNumber *keycols, + List *ancestors, ExplainState *es); + #endif /* EXPLAIN_H */ diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index e9b0fab..3df8070 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -108,4 +108,10 @@ extern void RangeVarCallbackOwnsRelation(const RangeVar *relation, extern bool PartConstraintImpliedByRelConstraint(Relation scanrel, List *partConstraint); +extern PGDLLIMPORT bool (*add_alter_tablespace_hook) (Relation rel); +extern PGDLLIMPORT void (*add_alter_table_change_owner_hook) (Oid relOid, + char relKind, Oid newOwnerId); +extern PGDLLIMPORT void (*add_alter_table_change_schema_hook) (Oid relOid, + char relKind, Oid newNspOid); + #endif /* TABLECMDS_H */ diff --git a/src/include/datatype/timestamp.h b/src/include/datatype/timestamp.h index a924d58..44f8bf7 100644 --- a/src/include/datatype/timestamp.h +++ b/src/include/datatype/timestamp.h @@ -15,6 +15,11 @@ #ifndef DATATYPE_TIMESTAMP_H #define DATATYPE_TIMESTAMP_H +#ifndef FRONTEND +#include "postgres.h" +#include "fmgr.h" +#endif + /* * Timestamp represents absolute time. * @@ -87,6 +92,23 @@ struct pg_itm_in int tm_year; }; +#ifndef FRONTEND +/* + * The transition datatype for interval aggregates is declared as internal. + * It's a pointer to an IntervalAggState allocated in the aggregate context. + */ +typedef struct IntervalAggState +{ + int64 N; /* count of finite intervals processed */ + Interval sumX; /* sum of finite intervals processed */ + /* These counts are *not* included in N! Use IA_TOTAL_COUNT() as needed */ + int64 pInfcount; /* count of +infinity intervals */ + int64 nInfcount; /* count of -infinity intervals */ +} IntervalAggState; + +extern IntervalAggState *makeIntervalAggState(FunctionCallInfo fcinfo); +extern void finite_interval_pl(const Interval *span1, const Interval *span2, Interval *result); +#endif /* Limits on the "precision" option (typmod) for these data types */ #define MAX_TIMESTAMP_PRECISION 6 diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h index 7536620..e137b3f 100644 --- a/src/include/executor/execExpr.h +++ b/src/include/executor/execExpr.h @@ -292,6 +292,8 @@ typedef enum ExprEvalOp EEOP_AGG_ORDERED_TRANS_DATUM, EEOP_AGG_ORDERED_TRANS_TUPLE, + EEOP_VCI_VAR, + EEOP_VCI_PARAM_EXEC, /* non-existent operation, used e.g. to check array lengths */ EEOP_LAST } ExprEvalOp; @@ -338,6 +340,7 @@ typedef struct ExprEvalStep /* but it's just the normal (negative) attr number for SYSVAR */ int attnum; Oid vartype; /* type OID of variable */ + PlanState *vci_parent_planstate; VarReturningType varreturningtype; /* return old/new/default */ } var; @@ -424,6 +427,7 @@ typedef struct ExprEvalStep { int paramid; /* numeric ID for parameter */ Oid paramtype; /* OID of parameter's datatype */ + Plan *vci_parent_plan; } param; /* for EEOP_PARAM_CALLBACK */ @@ -902,6 +906,18 @@ extern void ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext); extern void ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext, TupleTableSlot *slot); +extern void ExecCreateExprSetupSteps(ExprState *state, Node *node); +extern void ExecReadyExpr(ExprState *state); + +typedef void (*ExprEvalVar_hook_type) (ExprState *state, ExprEvalStep *op, + ExprContext *econtext); +extern PGDLLIMPORT ExprEvalVar_hook_type ExprEvalVar_hook; + +typedef void (*ExprEvalParam_hook_type) (ExprState *state, ExprEvalStep *op, + ExprContext *econtext); +extern PGDLLIMPORT ExprEvalParam_hook_type ExprEvalParam_hook; +extern void VciExprEvalVarHook(ExprState *state, ExprEvalStep *op, ExprContext *econtext); +extern void VciExprEvalParamHook(ExprState *state, ExprEvalStep *op, ExprContext *econtext); extern void ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup, ExprContext *aggcontext); diff --git a/src/include/executor/nodeModifyTable.h b/src/include/executor/nodeModifyTable.h index bf3b592..b49d552 100644 --- a/src/include/executor/nodeModifyTable.h +++ b/src/include/executor/nodeModifyTable.h @@ -27,6 +27,8 @@ extern ModifyTableState *ExecInitModifyTable(ModifyTable *node, EState *estate, extern void ExecEndModifyTable(ModifyTableState *node); extern void ExecReScanModifyTable(ModifyTableState *node); +extern PGDLLIMPORT List *(*add_should_index_insert_hook) (ResultRelInfo *, TupleTableSlot *, ItemPointer, EState *); + extern void ExecInitMergeTupleSlots(ModifyTableState *mtstate, ResultRelInfo *resultRelInfo); diff --git a/src/include/nodes/extensible.h b/src/include/nodes/extensible.h index 1129c4b..c9a349e 100644 --- a/src/include/nodes/extensible.h +++ b/src/include/nodes/extensible.h @@ -115,6 +115,7 @@ typedef struct CustomScanMethods /* Create execution state (CustomScanState) from a CustomScan plan node */ Node *(*CreateCustomScanState) (CustomScan *cscan); + struct CustomScan *(*CopyCustomPlan) (const struct CustomScan *from); } CustomScanMethods; /* @@ -155,6 +156,9 @@ typedef struct CustomExecMethods void (*ExplainCustomScan) (CustomScanState *node, List *ancestors, ExplainState *es); + void (*SetBoundCustomScan) (const LimitState *limit, + CustomScanState *cps); + void (*ExplainCustomPlanTargetRel) (CustomScanState *node, ExplainState *es); } CustomExecMethods; extern void RegisterCustomScanMethods(const CustomScanMethods *methods); diff --git a/src/include/nodes/params.h b/src/include/nodes/params.h index ca4117b..6d7add3 100644 --- a/src/include/nodes/params.h +++ b/src/include/nodes/params.h @@ -19,6 +19,7 @@ typedef struct ExprState ExprState; typedef struct Param Param; typedef struct ParseState ParseState; +struct PlanState; /* * ParamListInfo @@ -165,5 +166,6 @@ extern ParamListInfo RestoreParamList(char **start_address); extern char *BuildParamLogString(ParamListInfo params, char **knownTextValues, int maxlen); extern void ParamsErrorCallback(void *arg); +typedef struct ExprState *(*ExecInitParam_hook_type) (Param *param, struct PlanState *parent); #endif /* PARAMS_H */ diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index c4393a9..f8fbe14 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -214,6 +214,9 @@ typedef struct Plan /* OK to use as part of parallel plan? */ bool parallel_safe; + /* plan number (1-origin) in the Query */ + AttrNumber plan_no; + /* * information needed for asynchronous execution */ diff --git a/src/include/optimizer/planner.h b/src/include/optimizer/planner.h index 55d9b79..8b8c50c 100644 --- a/src/include/optimizer/planner.h +++ b/src/include/optimizer/planner.h @@ -53,6 +53,8 @@ typedef void (*create_upper_paths_hook_type) (PlannerInfo *root, void *extra); extern PGDLLIMPORT create_upper_paths_hook_type create_upper_paths_hook; +extern void copy_plan_costsize(Plan *dest, Plan *src); + extern PlannedStmt *standard_planner(Query *parse, const char *query_string, int cursorOptions, diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h index 3561c6b..7c2bcdf 100644 --- a/src/include/utils/relcache.h +++ b/src/include/utils/relcache.h @@ -61,6 +61,8 @@ extern List *RelationGetDummyIndexExpressions(Relation relation); extern List *RelationGetIndexPredicate(Relation relation); extern bytea **RelationGetIndexAttOptions(Relation relation, bool copy); +extern bool isRelHasVCIIndex(Oid relid, bool *is_partition); + /* * Which set of columns to return by RelationGetIndexAttrBitmap. */ @@ -160,4 +162,7 @@ extern PGDLLIMPORT bool criticalRelcachesBuilt; /* should be used only by relcache.c and postinit.c */ extern PGDLLIMPORT bool criticalSharedRelcachesBuilt; +/* vci index original hook*/ +extern PGDLLIMPORT bool (*add_skip_vci_index_hook) (Relation rel); + #endif /* RELCACHE_H */ diff --git a/src/include/utils/snapshot.h b/src/include/utils/snapshot.h index 0e546ec..18154d7 100644 --- a/src/include/utils/snapshot.h +++ b/src/include/utils/snapshot.h @@ -112,6 +112,16 @@ typedef enum SnapshotType * horizon to use. */ SNAPSHOT_NON_VACUUMABLE, + + /* + * VCI WOS2ROS visible + */ + SNAPSHOT_VCI_WOS2ROS, + + /* + * VCI Local ROS visible + */ + SNAPSHOT_VCI_LOCALROS } SnapshotType; typedef struct SnapshotData *Snapshot; -- 1.8.3.1