merge code for global temporary table(GTT)

This commit is contained in:
wangzhijun 2020-07-29 18:23:11 +08:00
parent 53626285eb
commit 797043b60a
90 changed files with 4479 additions and 295 deletions

View File

@ -2526,6 +2526,10 @@ static void makeTableDataInfo(TableInfo* tbinfo, bool boids)
if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED && no_unlogged_table_data)
return;
/* Don't dump data in global temp table/sequence */
if (tbinfo->relpersistence == RELPERSISTENCE_GLOBAL_TEMP)
return;
/* Check that the data is not explicitly excluded */
if (simple_oid_list_member(&tabledata_exclude_oids, tbinfo->dobj.catId.oid))
return;
@ -16035,9 +16039,17 @@ static void dumpTableSchema(Archive* fout, TableInfo* tbinfo)
if (tbinfo->parttype == PARTTYPE_PARTITIONED_RELATION) {
appendPQExpBuffer(q, "CREATE %s %s", reltypename, fmtId(tbinfo->dobj.name));
} else {
const char *tableType = nullptr;
if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED) {
tableType = "UNLOGGED ";
} else if (tbinfo->relpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
tableType = "GLOBAL TEMPORARY ";
} else {
tableType = "";
}
appendPQExpBuffer(q,
"CREATE %s%s %s",
tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ? "UNLOGGED " : "",
tableType,
reltypename,
fmtId(tbinfo->dobj.name));
}
@ -16715,7 +16727,9 @@ static void dumpTableSchema(Archive* fout, TableInfo* tbinfo)
* attislocal correctly, plus fix up any inherited CHECK constraints.
* Analogously, we set up typed tables using ALTER TABLE / OF here.
*/
if (binary_upgrade && ((tbinfo->relkind == RELKIND_RELATION) || (tbinfo->relkind == RELKIND_FOREIGN_TABLE))) {
if (binary_upgrade &&
((tbinfo->relkind == RELKIND_RELATION) || (tbinfo->relkind == RELKIND_FOREIGN_TABLE)) &&
tbinfo->relpersistence != RELPERSISTENCE_GLOBAL_TEMP) {
for (j = 0; j < tbinfo->numatts; j++) {
if (tbinfo->attisdropped[j]) {
appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column.\n");

View File

@ -21,7 +21,8 @@ OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
objectaddress.o pg_aggregate.o pg_collation.o pg_constraint.o pg_conversion.o \
pg_depend.o pg_enum.o pg_inherits.o pg_largeobject.o pg_namespace.o pg_object.o\
pg_operator.o pg_proc.o pg_range.o pg_db_role_setting.o pg_shdepend.o pg_synonym.o\
pg_type.o pgxc_class.o storage.o toasting.o pg_job.o pg_partition.o pg_hashbucket.o cstore_ctlg.o dfsstore_ctlg.o pg_builtin_proc.o
pg_type.o pgxc_class.o storage_gtt.o storage.o toasting.o pg_job.o pg_partition.o \
pg_hashbucket.o cstore_ctlg.o dfsstore_ctlg.o pg_builtin_proc.o
BKIFILES = postgres.bki postgres.description postgres.shdescription

View File

@ -6358,6 +6358,14 @@
"pg_get_functiondef", 1,
AddBuiltinFunc(_0(2098), _1("pg_get_functiondef"), _2(1), _3(true), _4(false), _5(pg_get_functiondef), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14('f'), _15(false), _16(false), _17('s'), _18(0), _19(1, 26), _20(3, 26, 23, 25), _21(3, 'i', 'o', 'o'), _22(3, "funcid", "headerlines", "definition"), _23(NULL), _24("pg_get_functiondef"), _25(NULL), _26(NULL), _27(NULL), _28(0), _29(false), _30(NULL), _31(false))
),
AddFuncGroup(
"pg_get_gtt_relstats", 1,
AddBuiltinFunc(_0(3596), _1("pg_get_gtt_relstats"), _2(1), _3(true), _4(true), _5(pg_get_gtt_relstats), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(10), _12(0), _13(0), _14('f'), _15(false), _16(false), _17('v'), _18(0), _19(1, 26), _20(7, 26, 26, 23, 700, 23, 28, 28), _21(7, 'i', 'o', 'o', 'o', 'o', 'o', 'o'), _22(7, "relid", "relfilenode", "relpages", "reltuples", "relallvisible", "relfrozenxid", "relminmxid"), _23(NULL), _24("pg_get_gtt_relstats"), _25(NULL), _26(NULL), _27(NULL), _28(0), _29(false), _30(NULL), _31(false))
),
AddFuncGroup(
"pg_get_gtt_statistics", 1,
AddBuiltinFunc(_0(3597), _1("pg_get_gtt_statistics"), _2(3), _3(false), _4(true), _5(pg_get_gtt_statistics), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(10), _12(0), _13(0), _14('f'), _15(false), _16(false), _17('v'), _18(0), _19(3, 26, 23, 2283), _20(32, 26, 23, 2283, 26, 18, 21, 16, 700, 23, 700, 21, 21, 21, 21, 21, 26, 26, 26, 26, 26, 1021, 1021, 1021, 1021, 1021, 2277, 2277, 2277, 2277, 2277, 700, 25), _21(32, 'i', 'i', 'i', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o'), _22(32, "relid", "att", "x", "starelid", "starelkind", "staattnum", "stainherit", "stanullfrac", "stawidth", "stadistinct", "stakind1", "stakind2", "stakind3", "stakind4", "stakind5", "staop1", "staop2", "staop3", "staop4", "staop5", "stanumbers1", "stanumbers2", "stanumbers3", "stanumbers4", "stanumbers5", "stavalues1", "stavalues2", "stavalues3", "stavalues4", "stavalues5", "stadndistinct", "staextinfo"), _23(NULL), _24("pg_get_gtt_statistics"), _25(NULL), _26(NULL), _27(NULL), _28(0), _29(false), _30(NULL), _31(false))
),
AddFuncGroup(
"pg_get_indexdef", 2,
AddBuiltinFunc(_0(1643), _1("pg_get_indexdef"), _2(1), _3(true), _4(false), _5(pg_get_indexdef), _6(25), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14('f'), _15(false), _16(false), _17('s'), _18(0), _19(1, 26), _20(NULL), _21(NULL), _22(NULL), _23(NULL), _24("pg_get_indexdef"), _25(NULL), _26(NULL), _27(NULL), _28(0), _29(false), _30(NULL), _31(false)),
@ -6417,6 +6425,10 @@
"pg_get_xidlimit", 1,
AddBuiltinFunc(_0(2000), _1("pg_get_xidlimit"), _2(0), _3(true), _4(true), _5(pg_get_xidlimit), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(1000), _12(0), _13(0), _14('f'), _15(false), _16(false), _17('v'), _18(0), _19(0), _20(7, 28, 28, 28, 28, 28, 28, 26), _21(7, 'o', 'o', 'o', 'o', 'o', 'o', 'o'), _22(7, "nextXid", "oldestXid", "xidVacLimit", "xidWarnLimit", "xidStopLimit", "xidWrapLimit", "oldestXidDB"), _23(NULL), _24("pg_get_xidlimit"), _25(NULL), _26(NULL), _27(NULL), _28(0), _29(false), _30(NULL), _31(false))
),
AddFuncGroup(
"pg_gtt_attached_pid", 1,
AddBuiltinFunc(_0(3598), _1("pg_gtt_attached_pid"), _2(1), _3(true), _4(true), _5(pg_gtt_attached_pid), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(10), _12(0), _13(0), _14('f'), _15(false), _16(false), _17('v'), _18(0), _19(1, 26), _20(3, 26, 26, 20), _21(3, 'i', 'o', 'o'), _22(3, "relid", "relid", "pid"), _23(NULL), _24("pg_gtt_attached_pid"), _25(NULL), _26(NULL), _27(NULL), _28(0), _29(false), _30(NULL), _31(false))
),
AddFuncGroup(
"pg_has_role", 6,
AddBuiltinFunc(_0(2705), _1("pg_has_role"), _2(3), _3(true), _4(false), _5(pg_has_role_name_name), _6(16), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14('f'), _15(false), _16(false), _17('s'), _18(0), _19(3, 19, 19, 25), _20(NULL), _21(NULL), _22(NULL), _23(NULL), _24("pg_has_role_name_name"), _25(NULL), _26(NULL), _27(NULL), _28(0), _29(false), _30(NULL), _31(false)),
@ -6454,6 +6466,10 @@
"pg_last_xlog_replay_location", 1,
AddBuiltinFunc(_0(3821), _1("pg_last_xlog_replay_location"), _2(0), _3(true), _4(false), _5(pg_last_xlog_replay_location), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14('f'), _15(false), _16(false), _17('v'), _18(0), _19(0), _20(2, 25, 25), _21(2, 'o', 'o'), _22(2, "term", "lsn"), _23(NULL), _24("pg_last_xlog_replay_location"), _25(NULL), _26(NULL), _27(NULL), _28(0), _29(false), _30(NULL), _31(false))
),
AddFuncGroup(
"pg_list_gtt_relfrozenxids", 1,
AddBuiltinFunc(_0(3599), _1("pg_list_gtt_relfrozenxids"), _2(0), _3(true), _4(true), _5(pg_list_gtt_relfrozenxids), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(10), _12(0), _13(0), _14('f'), _15(false), _16(false), _17('v'), _18(0), _19(0), _20(2, 20, 28), _21(2, 'o', 'o'), _22(2, "pid", "relfrozenxid"), _23(NULL), _24("pg_list_gtt_relfrozenxids"), _25(NULL), _26(NULL), _27(NULL), _28(0), _29(false), _30(NULL), _31(false))
),
AddFuncGroup(
"pg_listening_channels", 1,
AddBuiltinFunc(_0(3035), _1("pg_listening_channels"), _2(0), _3(true), _4(true), _5(pg_listening_channels), _6(25), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(10), _12(0), _13(0), _14('f'), _15(false), _16(false), _17('s'), _18(0), _19(0), _20(NULL), _21(NULL), _22(NULL), _23(NULL), _24("pg_listening_channels"), _25(NULL), _26(NULL), _27(NULL), _28(0), _29(false), _30(NULL), _31(false))

View File

@ -1049,9 +1049,22 @@ Oid GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
char* rpath = NULL;
int fd;
bool collides = false;
BackendId backend;
switch (relpersistence) {
case RELPERSISTENCE_GLOBAL_TEMP:
backend = t_thrd.proc_cxt.MyBackendId;
break;
case RELPERSISTENCE_TEMP:
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT:
backend = InvalidBackendId;
break;
default:
elog(ERROR, "invalid relpersistence: %c", relpersistence);
return InvalidOid; /* placate compiler */
}
//@Temp Table. we now use same storage as unlogged table for temp table,
// so backendID is no need.
/* This logic should match relation_init_physical_addr */
rnode.node.spcNode = ConvertToRelfilenodeTblspcOid(reltablespace);
rnode.node.dbNode = (rnode.node.spcNode == GLOBALTABLESPACE_OID) ? InvalidOid : u_sess->proc_cxt.MyDatabaseId;
@ -1061,7 +1074,7 @@ Oid GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
* that properly here to make sure that any collisions based on filename
* are properly detected.
*/
rnode.backend = InvalidBackendId;
rnode.backend = backend;
do {
CHECK_FOR_INTERRUPTS();

View File

@ -63,6 +63,7 @@
#include "catalog/pg_type_fn.h"
#include "catalog/storage.h"
#include "catalog/storage_xlog.h"
#include "catalog/storage_gtt.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "commands/typecmds.h"
@ -110,7 +111,8 @@
#endif
static void AddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Oid new_type_oid,
Oid reloftype, Oid relowner, char relkind, Datum relacl, Datum reloptions, int2vector* bucketcol, bool ispartrel);
Oid reloftype, Oid relowner, char relkind, char relpersistence, Datum relacl, Datum reloptions,
int2vector* bucketcol, bool ispartrel);
static oidvector* BuildIntervalTablespace(const IntervalPartitionDefState* intervalPartDef);
static void deletePartitionTuple(Oid part_id);
static void addNewPartitionTuplesForPartition(Relation pg_partition_rel, Oid relid, List *filenodelist, Oid reltablespace,
@ -406,7 +408,8 @@ Form_pg_attribute SystemAttributeByName(const char* attname, bool relhasoids)
*/
Relation heap_create(const char* relname, Oid relnamespace, Oid reltablespace, Oid relid, Oid relfilenode,
Oid bucketOid, TupleDesc tupDesc, char relkind, char relpersistence, bool partitioned_relation, bool rowMovement,
bool shared_relation, bool mapped_relation, bool allow_system_table_mods, int8 row_compress, Oid ownerid)
bool shared_relation, bool mapped_relation, bool allow_system_table_mods, int8 row_compress, Oid ownerid,
bool skip_create_storage)
{
bool create_storage = false;
Relation rel;
@ -512,6 +515,9 @@ Relation heap_create(const char* relname, Oid relnamespace, Oid reltablespace, O
if (u_sess->attr.attr_common.IsInplaceUpgrade && !u_sess->upg_cxt.new_catalog_need_storage)
create_storage = false;
if (skip_create_storage) {
create_storage = false;
}
/*
* Have the storage manager create the relation's disk file, if needed.
*
@ -520,7 +526,7 @@ Relation heap_create(const char* relname, Oid relnamespace, Oid reltablespace, O
*/
if (create_storage) {
RelationOpenSmgr(rel);
RelationCreateStorage(rel->rd_node, relpersistence, ownerid, bucketOid);
RelationCreateStorage(rel->rd_node, relpersistence, ownerid, bucketOid, rel);
}
if (RelationUsesSpaceType(rel->rd_rel->relpersistence) == SP_TEMP) {
@ -1008,7 +1014,8 @@ void InsertPgClassTuple(
* --------------------------------
*/
static void AddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Oid new_type_oid,
Oid reloftype, Oid relowner, char relkind, Datum relacl, Datum reloptions, int2vector* bucketcol, bool ispartrel)
Oid reloftype, Oid relowner, char relkind, char relpersistence, Datum relacl, Datum reloptions,
int2vector* bucketcol, bool ispartrel)
{
Form_pg_class new_rel_reltup;
@ -1040,6 +1047,7 @@ static void AddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, O
new_rel_reltup->relallvisible = 0;
break;
}
/* Initialize relfrozenxid */
if (relkind == RELKIND_RELATION || relkind == RELKIND_TOASTVALUE) {
/*
@ -1057,6 +1065,12 @@ static void AddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, O
*/
new_rel_reltup->relfrozenxid = (ShortTransactionId)InvalidTransactionId;
}
/* global temp table not remember transaction info in catalog */
if (relpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
new_rel_reltup->relfrozenxid = (ShortTransactionId)InvalidTransactionId;
}
new_rel_reltup->relowner = relowner;
new_rel_reltup->reltype = new_type_oid;
new_rel_reltup->reloftype = reloftype;
@ -1928,7 +1942,8 @@ Oid heap_create_with_catalog(const char* relname, Oid relnamespace, Oid reltable
mapped_relation,
allow_system_table_mods,
row_compress,
ownerid);
ownerid,
false);
/* Recode the table or other object in pg_class create time. */
PgObjectType objectType = GetPgObjectTypePgClass(relkind);
@ -2068,6 +2083,7 @@ Oid heap_create_with_catalog(const char* relname, Oid relnamespace, Oid reltable
reloftypeid,
ownerid,
relkind,
relpersistence,
PointerGetDatum(relacl),
reloptions,
bucketcol,
@ -2701,6 +2717,15 @@ void heap_drop_with_catalog(Oid relid)
heapDropPartitionTable(rel);
}
/* We allow to drop global temp table only this session use it */
if (RELATION_IS_GLOBAL_TEMP(rel)) {
if (is_other_backend_use_gtt(RelationGetRelid(rel)))
ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop global temporary table %s when other backend attached it.",
RelationGetRelationName(rel))));
}
/*
* When dropping temp objects, we need further check whether current datanode is
* suffered from an unclean shutdown without gsql reconnect, as in this case the
@ -3603,7 +3628,7 @@ void RemoveStatistics(Oid relid, AttrNumber attnum)
* The routine will truncate and then reconstruct the indexes on
* the specified relation. Caller must hold exclusive lock on rel.
*/
static void RelationTruncateIndexes(Relation heapRelation)
static void RelationTruncateIndexes(Relation heapRelation, LOCKMODE lockmode)
{
ListCell* indlist = NULL;
@ -3614,7 +3639,7 @@ static void RelationTruncateIndexes(Relation heapRelation)
IndexInfo* indexInfo = NULL;
/* Open the index relation; use exclusive lock, just to be sure */
currentIndex = index_open(indexId, AccessExclusiveLock);
currentIndex = index_open(indexId, lockmode);
/* Fetch info needed for index_build */
indexInfo = BuildIndexInfo(currentIndex);
@ -3629,7 +3654,7 @@ static void RelationTruncateIndexes(Relation heapRelation)
}
/* truncate psort relation */
if (unlikely(currentIndex->rd_rel->relam == PSORT_AM_OID)) {
Relation psort_rel = heap_open(currentIndex->rd_rel->relcudescrelid, AccessExclusiveLock);
Relation psort_rel = heap_open(currentIndex->rd_rel->relcudescrelid, lockmode);
heap_truncate_one_rel(psort_rel);
heap_close(psort_rel, NoLock);
}
@ -3661,8 +3686,14 @@ void heap_truncate(List* relids)
foreach (cell, relids) {
Oid rid = lfirst_oid(cell);
Relation rel;
LOCKMODE lockmode = AccessExclusiveLock;
rel = heap_open(rid, AccessExclusiveLock);
/* truncate global temp table only need RowExclusiveLock */
if (get_rel_persistence(rid) == RELPERSISTENCE_GLOBAL_TEMP) {
lockmode = RowExclusiveLock;
}
rel = heap_open(rid, lockmode);
relations = lappend(relations, rel);
}
@ -3725,7 +3756,7 @@ static void heap_truncate_one_rel_for_bucket(Relation rel, Partition part)
if (OidIsValid(toastOid)) {
toastBucketRel = bucketGetRelation(rel, NULL, bucketlist->values[i]);
RelationTruncate(toastBucketRel, 0);
RelationTruncateIndexes(toastBucketRel);
RelationTruncateIndexes(toastBucketRel, AccessExclusiveLock);
bucketCloseRelation(toastBucketRel);
}
}
@ -3747,6 +3778,17 @@ static void heap_truncate_one_rel_for_bucket(Relation rel, Partition part)
void heap_truncate_one_rel(Relation rel)
{
Oid toastrelid;
LOCKMODE lockmode = AccessExclusiveLock;
if (RELATION_IS_GLOBAL_TEMP(rel)) {
if (!gtt_storage_attached(RelationGetRelid(rel)))
return;
/*
* Truncate global temp table only need RowExclusiveLock
*/
lockmode = RowExclusiveLock;
}
if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE && isMOTFromTblOid(RelationGetRelid(rel))) {
FdwRoutine* fdwroutine = GetFdwRoutineByRelId(RelationGetRelid(rel));
@ -3767,12 +3809,12 @@ void heap_truncate_one_rel(Relation rel)
/* If the relation is a cloumn store */
if (RelationIsColStore(rel)) {
/* cudesc */
Relation cudesc_rel = heap_open(rel->rd_rel->relcudescrelid, AccessExclusiveLock);
Relation cudesc_rel = heap_open(rel->rd_rel->relcudescrelid, lockmode);
heap_truncate_one_rel(cudesc_rel);
heap_close(cudesc_rel, NoLock);
/* delta */
Relation delta_rel = heap_open(rel->rd_rel->reldeltarelid, AccessExclusiveLock);
Relation delta_rel = heap_open(rel->rd_rel->reldeltarelid, lockmode);
heap_truncate_one_rel(delta_rel);
heap_close(delta_rel, NoLock);
@ -3783,16 +3825,16 @@ void heap_truncate_one_rel(Relation rel)
/* If there is a toast table, truncate that too */
toastrelid = rel->rd_rel->reltoastrelid;
if (OidIsValid(toastrelid)) {
Relation toastrel = heap_open(toastrelid, AccessExclusiveLock);
Relation toastrel = heap_open(toastrelid, lockmode);
RelationTruncate(toastrel, 0);
RelationTruncateIndexes(toastrel);
RelationTruncateIndexes(toastrel, lockmode);
/* keep the lock... */
heap_close(toastrel, NoLock);
}
}
/* If the relation has indexes, truncate the indexes too */
RelationTruncateIndexes(rel);
RelationTruncateIndexes(rel, lockmode);
} else /* partitioned table */
{
List* partOidList = NIL;
@ -3806,7 +3848,7 @@ void heap_truncate_one_rel(Relation rel)
/* truncate each partition */
partOidList = searchPgPartitionByParentId(PART_OBJ_TYPE_TABLE_PARTITION, rel->rd_id);
foreach (partCell, partOidList) {
Partition p = partitionOpen(rel, HeapTupleGetOid((HeapTuple)lfirst(partCell)), AccessExclusiveLock);
Partition p = partitionOpen(rel, HeapTupleGetOid((HeapTuple)lfirst(partCell)), lockmode);
/*
* two levels and in dn
@ -3831,7 +3873,7 @@ void heap_truncate_one_rel(Relation rel)
ListCell* cell1 = NULL;
IndexInfo* indexInfo = NULL;
Oid indexId = lfirst_oid(indCell);
currentIndex = index_open(indexId, AccessExclusiveLock);
currentIndex = index_open(indexId, lockmode);
indexInfo = BuildIndexInfo(currentIndex);
@ -3839,7 +3881,7 @@ void heap_truncate_one_rel(Relation rel)
foreach (cell1, currentParttiionIndexList) {
Partition indexPart =
partitionOpen(currentIndex, HeapTupleGetOid((HeapTuple)lfirst(cell1)), AccessExclusiveLock);
partitionOpen(currentIndex, HeapTupleGetOid((HeapTuple)lfirst(cell1)), lockmode);
Partition p;
if (RELATION_OWN_BUCKET(currentIndex)) {
@ -3849,7 +3891,7 @@ void heap_truncate_one_rel(Relation rel)
}
/* truncate psort relation */
if (unlikely(currentIndex->rd_rel->relam == PSORT_AM_OID)) {
Relation psort_rel = heap_open(currentIndex->rd_rel->relcudescrelid, AccessExclusiveLock);
Relation psort_rel = heap_open(currentIndex->rd_rel->relcudescrelid, lockmode);
heap_truncate_one_rel(psort_rel);
heap_close(psort_rel, NoLock);
}
@ -3873,10 +3915,10 @@ void heap_truncate_one_rel(Relation rel)
Form_pg_partition partForm = (Form_pg_partition)GETSTRUCT(tup);
if (partForm->reltoastrelid != InvalidOid) {
Relation toastrel = heap_open(partForm->reltoastrelid, AccessExclusiveLock);
Relation toastrel = heap_open(partForm->reltoastrelid, lockmode);
RelationTruncate(toastrel, 0);
RelationTruncateIndexes(toastrel);
RelationTruncateIndexes(toastrel, lockmode);
/* keep the lock... */
heap_close(toastrel, NoLock);
}
@ -3885,6 +3927,11 @@ void heap_truncate_one_rel(Relation rel)
freePartList(partOidList);
}
// for GTT
if (RELATION_IS_GLOBAL_TEMP(rel)) {
up_gtt_relstats(rel, 0, 0, 0, u_sess->utils_cxt.RecentXmin);
}
}
/*

View File

@ -21,6 +21,7 @@
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include "access/multixact.h"
#include "access/reloptions.h"
#include "access/relscan.h"
#include "access/sysattr.h"
@ -43,6 +44,7 @@
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/storage.h"
#include "catalog/storage_gtt.h"
#include "commands/tablecmds.h"
#include "commands/trigger.h"
#include "commands/vacuum.h"
@ -689,6 +691,11 @@ Oid index_create(Relation heapRelation, const char* indexRelationName, Oid index
int i;
char relpersistence;
Oid psortRelationId = InvalidOid;
bool skip_create_storage = false;
if (RELATION_IS_GLOBAL_TEMP(heapRelation) && !gtt_storage_attached(RelationGetRelid(heapRelation))) {
skip_create_storage = true;
}
is_exclusion = (indexInfo->ii_ExclusionOps != NULL);
@ -766,6 +773,20 @@ Oid index_create(Relation heapRelation, const char* indexRelationName, Oid index
if (get_relname_relid(indexRelationName, namespaceId))
ereport(ERROR, (errcode(ERRCODE_DUPLICATE_TABLE), errmsg("relation \"%s\" already exists", indexRelationName)));
if (RELATION_IS_GLOBAL_TEMP(heapRelation))
{
/* No support create index on global temp table use concurrent mode yet */
if (concurrent)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot reindex global temporary tables concurrently")));
/* if global temp table not init storage, then skip build index */
if (!gtt_storage_attached(RelationGetRelid(heapRelation))) {
skip_build = true;
}
}
/*
* construct tuple descriptor for index tuples
@ -828,7 +849,8 @@ Oid index_create(Relation heapRelation, const char* indexRelationName, Oid index
mapped_relation,
allow_system_table_mods,
REL_CMPRS_NOT_SUPPORT,
heapRelation->rd_rel->relowner);
heapRelation->rd_rel->relowner,
skip_create_storage);
Assert(indexRelationId == RelationGetRelid(indexRelation));
@ -1413,6 +1435,15 @@ void index_drop(Oid indexId, bool concurrent)
VirtualTransactionId* old_lockholders = NULL;
List* partIndexlist = NIL;
/*
* A temporary relation uses a non-concurrent DROP. Other backends can't
* access a temporary relation, so there's no harm in grabbing a stronger
* lock (see comments in RemoveRelations), and a non-concurrent DROP is
* more efficient.
*/
Assert(!(get_rel_persistence(indexId) == RELPERSISTENCE_TEMP ||
get_rel_persistence(indexId) == RELPERSISTENCE_GLOBAL_TEMP) ||
(!concurrent));
/*
* To drop an index safely, we must grab exclusive lock on its parent
@ -1443,6 +1474,14 @@ void index_drop(Oid indexId, bool concurrent)
*/
CheckTableNotInUse(userIndexRelation, "DROP INDEX");
/* We allow to drop index on global temp table only this session use it */
if (RELATION_IS_GLOBAL_TEMP(userHeapRelation)) {
if (is_other_backend_use_gtt(RelationGetRelid(userHeapRelation))) {
elog(ERROR,
"can not drop index %s when other backend attached this global temp table.",
RelationGetRelationName(userHeapRelation));
}
}
/*
* Drop Index Concurrently is more or less the reverse process of Create
* Index Concurrently.
@ -1760,36 +1799,69 @@ IndexInfo* BuildIndexInfo(Relation index)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("invalid indnatts %d for index %u", numKeys, RelationGetRelid(index))));
ii->ii_NumIndexAttrs = numKeys;
for (i = 0; i < numKeys; i++)
ii = makeIndexInfo(indexStruct->indnatts,
RelationGetIndexExpressions(index),
RelationGetIndexPredicate(index),
indexStruct->indisunique,
IndexIsReady(indexStruct),
false);
/* fill in attribute numbers */
for (i = 0; i < numKeys; i++) {
ii->ii_KeyAttrNumbers[i] = indexStruct->indkey.values[i];
/* fetch any expressions needed for expressional indexes */
ii->ii_Expressions = RelationGetIndexExpressions(index);
ii->ii_ExpressionsState = NIL;
/* fetch index predicate if any */
ii->ii_Predicate = RelationGetIndexPredicate(index);
ii->ii_PredicateState = NIL;
}
/* fetch exclusion constraint info if any */
if (indexStruct->indisexclusion) {
RelationGetExclusionInfo(index, &ii->ii_ExclusionOps, &ii->ii_ExclusionProcs, &ii->ii_ExclusionStrats);
} else {
ii->ii_ExclusionOps = NULL;
ii->ii_ExclusionProcs = NULL;
ii->ii_ExclusionStrats = NULL;
}
return ii;
}
/* ----------------
* BuildDummyIndexInfo
* Construct a dummy IndexInfo record for an open index
*
* This differs from the real BuildIndexInfo in that it will never run any
* user-defined code that might exist in index expressions or predicates.
* Instead of the real index expressions, we return null constants that have
* the right types/typmods/collations. Predicates and exclusion clauses are
* just ignored. This is sufficient for the purpose of truncating an index,
* since we will not need to actually evaluate the expressions or predicates;
* the only thing that's likely to be done with the data is construction of
* a tupdesc describing the index's rowtype.
* ----------------
*/
IndexInfo* BuildDummyIndexInfo(Relation index)
{
IndexInfo* ii;
Form_pg_index indexStruct = index->rd_index;
int i;
int numAtts;
/* check the number of keys, and copy attr numbers into the IndexInfo */
numAtts = indexStruct->indnatts;
if (numAtts < 1 || numAtts > INDEX_MAX_KEYS) {
elog(ERROR, "invalid indnatts %d for index %u", numAtts, RelationGetRelid(index));
}
/* other info */
ii->ii_Unique = indexStruct->indisunique;
ii->ii_ReadyForInserts = IndexIsReady(indexStruct);
/*
* Create the node, using dummy index expressions, and pretending there is
* no predicate.
*/
ii = makeIndexInfo(indexStruct->indnatts,
RelationGetDummyIndexExpressions(index),
NIL,
indexStruct->indisunique,
indexStruct->indisready,
false);
/* initialize index-build state to default */
ii->ii_Concurrent = false;
ii->ii_BrokenHotChain = false;
ii->ii_PgClassAttrId = 0;
/* fill in attribute numbers */
for (i = 0; i < numAtts; i++) {
ii->ii_KeyAttrNumbers[i] = indexStruct->indkey.values[i];
}
/* We ignore the exclusion constraint if any */
return ii;
}
@ -1889,7 +1961,12 @@ void index_update_stats(
HeapTuple tuple;
Form_pg_class rd_rel;
bool dirty = false;
bool is_gtt = false;
/* update index stats into localhash and rel_rd_rel for global temp table */
if (RELATION_IS_GLOBAL_TEMP(rel)) {
is_gtt = true;
}
/*
* We always update the pg_class row using a non-transactional,
* overwrite-in-place update. There are several reasons for this:
@ -1996,18 +2073,30 @@ void index_update_stats(
else /* don't bother for indexes */
relallvisible = 0;
if (rd_rel->relpages != (float8)relpages) {
if (is_gtt) {
rel->rd_rel->relpages = static_cast<int32>(relpages);
} else if (rd_rel->relpages != (float8)relpages) {
rd_rel->relpages = (float8)relpages;
dirty = true;
}
if (rd_rel->reltuples != (float8)reltuples) {
if (is_gtt) {
rel->rd_rel->reltuples = (float4) reltuples;
} else if (rd_rel->reltuples != (float8)reltuples) {
rd_rel->reltuples = (float8)reltuples;
dirty = true;
}
if (rd_rel->relallvisible != (int32)relallvisible) {
if (is_gtt) {
rel->rd_rel->relallvisible = (int32) relallvisible;
} else if (rd_rel->relallvisible != (int32)relallvisible) {
rd_rel->relallvisible = (int32)relallvisible;
dirty = true;
}
if (is_gtt) {
up_gtt_relstats(rel, relpages, reltuples, relallvisible, InvalidTransactionId);
}
}
#ifdef PGXC
}
@ -2311,12 +2400,25 @@ void index_build(Relation heapRelation, Partition heapPartition, Relation indexR
relation_close(psortRel, NoLock);
}
if (RELATION_IS_GLOBAL_TEMP(indexRelation)) {
if (indexRelation->rd_smgr == NULL) {
/* Open it at the smgr level if not already done */
RelationOpenSmgr(indexRelation);
}
if (!gtt_storage_attached(RelationGetRelid(indexRelation)) ||
!smgrexists(indexRelation->rd_smgr, MAIN_FORKNUM)) {
gtt_force_enable_index(indexRelation);
RelationCreateStorage(indexRelation->rd_node, RELPERSISTENCE_GLOBAL_TEMP, indexRelation->rd_rel->relowner,
indexRelation->rd_bucketoid, indexRelation);
}
}
/*
* Call the access method's build procedure
*/
hasbucket = (!isPartition && RELATION_CREATE_BUCKET(heapRelation)) ||
(isPartition && RELATION_OWN_BUCKETKEY(heapRelation));
if (hasbucket == true) {
if (hasbucket) {
index_build_storage_for_bucket(heapRelation,
indexRelation,
heapPartition,
@ -3527,7 +3629,8 @@ void reindex_indexpart_internal(Relation heapRelation, Relation iRel, IndexInfo*
/*
* reindex_index - This routine is used to recreate a single index
*/
void reindex_index(Oid indexId, Oid indexPartId, bool skip_constraint_checks, AdaptMem* mem_info, bool db_wide)
void reindex_index(Oid indexId, Oid indexPartId, bool skip_constraint_checks,
AdaptMem *memInfo, bool dbWide, char persistence)
{
Relation iRel, heapRelation;
Oid heapId;
@ -3615,19 +3718,19 @@ void reindex_index(Oid indexId, Oid indexPartId, bool skip_constraint_checks, Ad
/* workload client manager */
if (IS_PGXC_COORDINATOR && ENABLE_WORKLOAD_CONTROL) {
/* if operatorMem is already set, the mem check is already done */
if (mem_info != NULL && mem_info->work_mem == 0) {
if (memInfo != NULL && memInfo->work_mem == 0) {
EstIdxMemInfo(heapRelation, NULL, &indexInfo->ii_desc, indexInfo, iRel->rd_am->amname.data);
if (db_wide) {
if (dbWide) {
indexInfo->ii_desc.cost = g_instance.cost_cxt.disable_cost;
indexInfo->ii_desc.query_mem[0] = Max(STATEMENT_MIN_MEM * 1024, indexInfo->ii_desc.query_mem[0]);
}
WLMInitQueryPlan((QueryDesc*)&indexInfo->ii_desc, false);
dywlm_client_manager((QueryDesc*)&indexInfo->ii_desc, false);
AdjustIdxMemInfo(mem_info, &indexInfo->ii_desc);
AdjustIdxMemInfo(memInfo, &indexInfo->ii_desc);
}
} else if (IS_PGXC_DATANODE && mem_info != NULL && mem_info->work_mem > 0) {
indexInfo->ii_desc.query_mem[0] = mem_info->work_mem;
indexInfo->ii_desc.query_mem[1] = mem_info->max_mem;
} else if (IS_PGXC_DATANODE && memInfo != NULL && memInfo->work_mem > 0) {
indexInfo->ii_desc.query_mem[0] = memInfo->work_mem;
indexInfo->ii_desc.query_mem[1] = memInfo->max_mem;
}
if (!RELATION_IS_PARTITIONED(heapRelation)) /* for non partitioned table */
@ -3862,8 +3965,9 @@ bool reindex_relation(Oid relid, int flags, int reindexType, AdaptMem* memInfo,
Oid indexOid = lfirst_oid(indexId);
Relation indexRel = index_open(indexOid, AccessShareLock);
if (is_pg_class)
if (is_pg_class) {
RelationSetIndexList(rel, doneIndexes, InvalidOid);
}
if ((((uint32)reindexType) & REINDEX_ALL_INDEX) ||
((((uint32)reindexType) & REINDEX_BTREE_INDEX) && (indexRel->rd_rel->relam == BTREE_AM_OID)) ||
@ -3873,17 +3977,19 @@ bool reindex_relation(Oid relid, int flags, int reindexType, AdaptMem* memInfo,
((((uint32)reindexType) & REINDEX_GIST_INDEX) && (indexRel->rd_rel->relam == GIST_AM_OID))) {
index_close(indexRel, AccessShareLock);
reindex_index(
indexOid, InvalidOid, !(((uint32)flags) & REINDEX_REL_CHECK_CONSTRAINTS), memInfo, dbWide);
indexOid, InvalidOid, !((static_cast<uint32>(flags)) & REINDEX_REL_CHECK_CONSTRAINTS), memInfo,
dbWide, rel->rd_rel->relpersistence);
CommandCounterIncrement();
} else
} else {
index_close(indexRel, AccessShareLock);
}
/* Index should no longer be in the pending list */
Assert(!ReindexIsProcessingIndex(indexOid));
if (is_pg_class)
if (is_pg_class) {
doneIndexes = lappend_oid(doneIndexes, indexOid);
}
}
}
PG_CATCH();
@ -3895,8 +4001,9 @@ bool reindex_relation(Oid relid, int flags, int reindexType, AdaptMem* memInfo,
PG_END_TRY();
ResetReindexPending();
if (is_pg_class)
if (is_pg_class) {
RelationSetIndexList(rel, indexIds, ClassOidIndexId);
}
/*
* Close rel, but continue to hold the lock.
@ -3904,8 +4011,7 @@ bool reindex_relation(Oid relid, int flags, int reindexType, AdaptMem* memInfo,
heap_close(rel, NoLock);
// reset all local indexes on partition usable if needed
if (RELATION_IS_PARTITIONED(rel)) /* for partitioned table */
{
if (RELATION_IS_PARTITIONED(rel)) { /* for partitioned table */
Oid partOid;
ListCell* cell = NULL;
List* partOidList = relationGetPartitionOidList(rel);
@ -3918,16 +4024,14 @@ bool reindex_relation(Oid relid, int flags, int reindexType, AdaptMem* memInfo,
result = (indexIds != NIL);
if (!isPartitioned) /* for non partitioned table */
{
if (!isPartitioned) { /* for non partitioned table */
/*
* If the relation has a secondary toast rel, reindex that too while we
* still hold the lock on the master table.
*/
if ((((uint32)flags) & REINDEX_REL_PROCESS_TOAST) && OidIsValid(toast_relid))
result = reindex_relation(toast_relid, flags, REINDEX_BTREE_INDEX) || result;
} else /* for partitioned table */
{
} else { /* for partitioned table */
List* partTupleList = NULL;
ListCell* partCell = NULL;

View File

@ -593,6 +593,12 @@ void RangeVarAdjustRelationPersistence(RangeVar* newRelation, Oid nspid)
errmsg("cannot create temporary relation in non-temporary schema")));
}
break;
case RELPERSISTENCE_GLOBAL_TEMP: /* global temp table */
if (isAnyTempNamespace(nspid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("cannot create global temp relations in temporary schemas")));
break;
case RELPERSISTENCE_PERMANENT:
if (isTempOrToastNamespace(nspid))
newRelation->relpersistence = RELPERSISTENCE_TEMP;

View File

@ -31,6 +31,7 @@
#include "catalog/catalog.h"
#include "catalog/dfsstore_ctlg.h"
#include "catalog/storage.h"
#include "catalog/storage_gtt.h"
#include "catalog/storage_xlog.h"
#include "catalog/pg_hashbucket_fn.h"
#include "commands/tablespace.h"
@ -67,6 +68,7 @@ typedef struct PendingRelDelete {
RelFileNode relnode; /* relation that may need to be deleted */
ForkNumber forknum; /* MAIN_FORKNUM for row table; or valid column ForkNum */
BackendId backend; /* InvalidBackendId if not a temp rel */
Oid relOid; /* InvalidOid if not a global temp rel */
Oid ownerid; /* owner id for user space statistics */
bool atCommit; /* T=delete at commit; F=delete at abort */
int nestLevel; /* xact nesting level of request */
@ -117,6 +119,10 @@ static void StorageSetBackendAndLogged(_in_ char relpersistence, _out_ BackendId
*needs_wal = false;
}
break;
case RELPERSISTENCE_GLOBAL_TEMP:
*backend = t_thrd.proc_cxt.MyBackendId;
*needs_wal = false;
break;
case RELPERSISTENCE_UNLOGGED:
*backend = InvalidBackendId;
*needs_wal = false;
@ -136,8 +142,8 @@ static void StorageSetBackendAndLogged(_in_ char relpersistence, _out_ BackendId
* if it's a row-storage table, *whichAttr* must is *AllTheAttrs*.
* if it's a column-storage table, *whichAttr* >= *AllTheAttrs*.
*/
static void InsertStorageIntoPendingList(_in_ RelFileNode* rnode, _in_ AttrNumber attrnum, _in_ BackendId backend,
_in_ Oid ownerid, _in_ bool atCommit, _in_ bool isDfsTruncate = false)
static void InsertStorageIntoPendingList(_in_ const RelFileNode* rnode, _in_ AttrNumber attrnum, _in_ BackendId backend,
_in_ Oid ownerid, _in_ bool atCommit, _in_ bool isDfsTruncate = false, Relation rel = NULL)
{
PendingRelDelete* pending = (PendingRelDelete*)MemoryContextAlloc(u_sess->top_mem_cxt, sizeof(PendingRelDelete));
pending->relnode = *rnode;
@ -165,17 +171,22 @@ static void InsertStorageIntoPendingList(_in_ RelFileNode* rnode, _in_ AttrNumbe
}
}
pending->backend = backend;
pending->relOid = InvalidOid;
pending->ownerid = ownerid;
pending->atCommit = atCommit; /* false: delete if abort; true: delete if commit */
pending->nestLevel = GetCurrentTransactionNestLevel();
pending->next = u_sess->catalog_cxt.pendingDeletes;
u_sess->catalog_cxt.pendingDeletes = pending;
/* Lock RelFileNode to control concurrent with Catchup Thread */
LockRelFileNode(*rnode, AccessExclusiveLock);
if (RELATION_IS_GLOBAL_TEMP(rel)) {
pending->relOid = RelationGetRelid(rel);
} else {
/* Lock RelFileNode to control concurrent with Catchup Thread */
LockRelFileNode(*rnode, AccessExclusiveLock);
}
}
void RelationCreateStorageInternal(RelFileNode rnode, char relpersistence, Oid ownerid)
static void RelationCreateStorageInternal(RelFileNode rnode, char relpersistence, Oid ownerid, Relation rel = NULL)
{
SMgrRelation srel;
BackendId backend;
@ -190,7 +201,12 @@ void RelationCreateStorageInternal(RelFileNode rnode, char relpersistence, Oid o
log_smgrcreate(&srel->smgr_rnode.node, MAIN_FORKNUM);
/* Add the relation to the list of stuff to delete at abort */
InsertStorageIntoPendingList(&rnode, InvalidAttrNumber, backend, ownerid, false);
InsertStorageIntoPendingList(&rnode, InvalidAttrNumber, backend, ownerid, false, false, rel);
/* remember global temp table storage info to localhash */
if (rel && relpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
remember_gtt_storage_info(rnode, rel);
}
}
/*
@ -204,12 +220,12 @@ void RelationCreateStorageInternal(RelFileNode rnode, char relpersistence, Oid o
* This function is transactional. The creation is WAL-logged, and if the
* transaction aborts later on, the storage will be destroyed.
*/
void RelationCreateStorage(RelFileNode rnode, char relpersistence, Oid ownerid, Oid bucketOid)
void RelationCreateStorage(RelFileNode rnode, char relpersistence, Oid ownerid, Oid bucketOid, Relation rel)
{
if (OidIsValid(bucketOid) && (bucketOid != VirtualBktOid)) {
BucketCreateStorage(rnode, bucketOid, ownerid);
} else {
RelationCreateStorageInternal(rnode, relpersistence, ownerid);
RelationCreateStorageInternal(rnode, relpersistence, ownerid, rel);
}
}
@ -328,6 +344,17 @@ void CStoreRelDropColumn(Relation rel, AttrNumber attrnum, Oid ownerid)
*/
void RelationDropStorage(Relation rel, bool isDfsTruncate)
{
// global temp table files may not exist
if (RELATION_IS_GLOBAL_TEMP(rel)) {
if (rel->rd_smgr == NULL) {
/* Open it at the smgr level if not already done */
RelationOpenSmgr(rel);
}
if (!smgrexists(rel->rd_smgr, MAIN_FORKNUM)) {
return;
}
}
/*
* First we must push the column file, column bcm file to the pendingDeletes and
* then push the logical table file to pendingDeletes.
@ -369,7 +396,7 @@ void RelationDropStorage(Relation rel, bool isDfsTruncate)
} else {
/* Add the relation to the list of stuff to delete at commit */
InsertStorageIntoPendingList(
&rel->rd_node, InvalidAttrNumber, rel->rd_backend, rel->rd_rel->relowner, true, isDfsTruncate);
&rel->rd_node, InvalidAttrNumber, rel->rd_backend, rel->rd_rel->relowner, true, isDfsTruncate, rel);
}
/*
@ -536,6 +563,11 @@ void RelationTruncate(Relation rel, BlockNumber nblocks)
if (bcm)
BCM_truncate(rel);
/* skip truncating if global temp table index does not exist */
if (RELATION_IS_GLOBAL_TEMP(rel) && !smgrexists(rel->rd_smgr, MAIN_FORKNUM)) {
return;
}
/*
* We WAL-log the truncation before actually truncating, which means
* trouble if the truncation fails. If we then crash, the WAL replay
@ -570,9 +602,10 @@ void RelationTruncate(Relation rel, BlockNumber nblocks)
if (fsm || vm)
XLogFlush(lsn);
}
/* Lock RelFileNode to control concurrent with Catchup Thread */
LockRelFileNode(rel->rd_node, AccessExclusiveLock);
if (!RELATION_IS_GLOBAL_TEMP(rel)) {
/* Lock RelFileNode to control concurrent with Catchup Thread */
LockRelFileNode(rel->rd_node, AccessExclusiveLock);
}
/* Do the real work */
smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks);
@ -686,7 +719,8 @@ void smgrDoPendingDeletes(bool isCommit)
/* do deletion if called for */
if (pending->atCommit == isCommit) {
if (!IsValidColForkNum(pending->forknum)) {
RowRelationDoDeleteFiles(pending->relnode, pending->backend, pending->ownerid);
RowRelationDoDeleteFiles(
pending->relnode, pending->backend, pending->ownerid, pending->relOid, isCommit);
/*
* "CREATE/DROP hdfs table" will use Two-Phrases Commit Transaction,
@ -1900,7 +1934,7 @@ void ColumnRelationDoDeleteFiles(RelFileNode* rnode, ForkNumber forknum, Backend
}
/* Delete all the physical files for row relation. */
void RowRelationDoDeleteFiles(RelFileNode rnode, BackendId backend, Oid ownerid)
void RowRelationDoDeleteFiles(RelFileNode rnode, BackendId backend, Oid ownerid, Oid relOid, bool isCommit)
{
/* decrease the permanent space on users' record */
uint64 size = GetSMgrRelSize(&rnode, backend, InvalidForkNumber);
@ -1912,6 +1946,11 @@ void RowRelationDoDeleteFiles(RelFileNode rnode, BackendId backend, Oid ownerid)
smgrdounlink(srel, false);
smgrclose(srel);
/* clean global temp table flags when transaction commit or rollback */
if (SmgrIsTemp(srel) && relOid != InvalidOid && gtt_storage_attached(relOid)) {
forget_gtt_storage_info(relOid, rnode, isCommit);
}
/*
* After files are deleted, append this filenode into BCM file list,
* so that we know all the BCM shared buffers of column relation has been

File diff suppressed because it is too large Load Diff

View File

@ -182,6 +182,117 @@ CREATE VIEW pg_indexes AS
LEFT JOIN pg_tablespace T ON (T.oid = I.reltablespace)
WHERE C.relkind = 'r' AND I.relkind = 'i';
-- For global temporary table
CREATE VIEW pg_gtt_relstats WITH (security_barrier) AS
SELECT n.nspname AS schemaname,
c.relname AS tablename,
(select relfilenode from pg_get_gtt_relstats(c.oid)),
(select relpages from pg_get_gtt_relstats(c.oid)),
(select reltuples from pg_get_gtt_relstats(c.oid)),
(select relallvisible from pg_get_gtt_relstats(c.oid)),
(select relfrozenxid from pg_get_gtt_relstats(c.oid)),
(select relminmxid from pg_get_gtt_relstats(c.oid))
FROM
pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relpersistence='g' AND c.relkind in('r','p','i','t');
CREATE VIEW pg_gtt_attached_pids WITH (security_barrier) AS
SELECT n.nspname AS schemaname,
c.relname AS tablename,
c.oid AS relid,
array(select pid from pg_gtt_attached_pid(c.oid)) AS pids
FROM
pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relpersistence='g' AND c.relkind in('r','S');
CREATE VIEW pg_gtt_stats WITH (security_barrier) AS
SELECT s.nspname AS schemaname,
s.relname AS tablename,
s.attname,
s.stainherit AS inherited,
s.stanullfrac AS null_frac,
s.stawidth AS avg_width,
s.stadistinct AS n_distinct,
CASE
WHEN s.stakind1 = 1 THEN s.stavalues1
WHEN s.stakind2 = 1 THEN s.stavalues2
WHEN s.stakind3 = 1 THEN s.stavalues3
WHEN s.stakind4 = 1 THEN s.stavalues4
WHEN s.stakind5 = 1 THEN s.stavalues5
END AS most_common_vals,
CASE
WHEN s.stakind1 = 1 THEN s.stanumbers1
WHEN s.stakind2 = 1 THEN s.stanumbers2
WHEN s.stakind3 = 1 THEN s.stanumbers3
WHEN s.stakind4 = 1 THEN s.stanumbers4
WHEN s.stakind5 = 1 THEN s.stanumbers5
END AS most_common_freqs,
CASE
WHEN s.stakind1 = 2 THEN s.stavalues1
WHEN s.stakind2 = 2 THEN s.stavalues2
WHEN s.stakind3 = 2 THEN s.stavalues3
WHEN s.stakind4 = 2 THEN s.stavalues4
WHEN s.stakind5 = 2 THEN s.stavalues5
END AS histogram_bounds,
CASE
WHEN s.stakind1 = 3 THEN s.stanumbers1[1]
WHEN s.stakind2 = 3 THEN s.stanumbers2[1]
WHEN s.stakind3 = 3 THEN s.stanumbers3[1]
WHEN s.stakind4 = 3 THEN s.stanumbers4[1]
WHEN s.stakind5 = 3 THEN s.stanumbers5[1]
END AS correlation,
CASE
WHEN s.stakind1 = 4 THEN s.stavalues1
WHEN s.stakind2 = 4 THEN s.stavalues2
WHEN s.stakind3 = 4 THEN s.stavalues3
WHEN s.stakind4 = 4 THEN s.stavalues4
WHEN s.stakind5 = 4 THEN s.stavalues5
END AS most_common_elems,
CASE
WHEN s.stakind1 = 4 THEN s.stanumbers1
WHEN s.stakind2 = 4 THEN s.stanumbers2
WHEN s.stakind3 = 4 THEN s.stanumbers3
WHEN s.stakind4 = 4 THEN s.stanumbers4
WHEN s.stakind5 = 4 THEN s.stanumbers5
END AS most_common_elem_freqs,
CASE
WHEN s.stakind1 = 5 THEN s.stanumbers1
WHEN s.stakind2 = 5 THEN s.stanumbers2
WHEN s.stakind3 = 5 THEN s.stanumbers3
WHEN s.stakind4 = 5 THEN s.stanumbers4
WHEN s.stakind5 = 5 THEN s.stanumbers5
END AS elem_count_histogram
FROM
(SELECT n.nspname,
c.relname,
a.attname,
(select stainherit from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stainherit,
(select stanullfrac from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stanullfrac,
(select stawidth from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stawidth,
(select stadistinct from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stadistinct,
(select stakind1 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stakind1,
(select stakind2 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stakind2,
(select stakind3 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stakind3,
(select stakind4 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stakind4,
(select stakind5 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stakind5,
(select stanumbers1 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stanumbers1,
(select stanumbers2 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stanumbers2,
(select stanumbers3 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stanumbers3,
(select stanumbers4 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stanumbers4,
(select stanumbers5 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stanumbers5,
(select stavalues1 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stavalues1,
(select stavalues2 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stavalues2,
(select stavalues3 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stavalues3,
(select stavalues4 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stavalues4,
(select stavalues5 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stavalues5
FROM
pg_class c
JOIN pg_attribute a ON c.oid = a.attrelid
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relpersistence='g' AND c.relkind in('r','p','i','t') and a.attnum > 0 and NOT a.attisdropped AND has_column_privilege(c.oid, a.attnum, 'select'::text)) s;
CREATE VIEW pg_stats AS
SELECT
nspname AS schemaname,

View File

@ -1750,3 +1750,22 @@ List* list_merge_int(List* list1, List* list2)
return list_dst;
}
List* list_insert_nth_oid(List* list, int pos, Oid datum)
{
if (list == NIL) {
Assert(pos == 0);
return list_make1_oid(datum);
}
Assert(IsOidList(list));
if (pos == 0) { // add at first pos
list = lcons_oid(datum, list);
} else { // find cell at pos - 1, then add new cell after it;
ListCell* prevCell = list_nth_cell(list, pos - 1);
ListCell* newCell = add_new_cell(list, prevCell);
lfirst_oid(newCell) = datum;
}
check_list_invariants(list);
return list;
}

View File

@ -615,3 +615,36 @@ Param* makeParam(ParamKind paramkind, int paramid, Oid paramtype, int32 paramtyp
return argp;
}
/*
* makeIndexInfo
* create an IndexInfo node
*/
IndexInfo* makeIndexInfo(int numattrs, List* expressions, List* predicates, bool unique, bool isready, bool concurrent)
{
IndexInfo* n = makeNode(IndexInfo);
n->ii_NumIndexAttrs = numattrs;
n->ii_Unique = unique;
n->ii_ReadyForInserts = isready;
n->ii_Concurrent = concurrent;
/* expressions */
n->ii_Expressions = expressions;
n->ii_ExpressionsState = NIL;
/* predicates */
n->ii_Predicate = predicates;
n->ii_PredicateState = NULL;
/* exclusion constraints */
n->ii_ExclusionOps = NULL;
n->ii_ExclusionProcs = NULL;
n->ii_ExclusionStrats = NULL;
/* initialize index-build state to default */
n->ii_BrokenHotChain = false;
n->ii_PgClassAttrId = 0;
return n;
}

View File

@ -4184,20 +4184,8 @@ OptTemp: TEMPORARY { $$ = RELPERSISTENCE_TEMP; }
| TEMP { $$ = RELPERSISTENCE_TEMP; }
| LOCAL TEMPORARY { $$ = RELPERSISTENCE_TEMP; }
| LOCAL TEMP { $$ = RELPERSISTENCE_TEMP; }
| GLOBAL TEMPORARY
{
ereport(WARNING,
(errmsg("GLOBAL is deprecated in temporary table creation"),
parser_errposition(@1)));
$$ = RELPERSISTENCE_TEMP;
}
| GLOBAL TEMP
{
ereport(WARNING,
(errmsg("GLOBAL is deprecated in temporary table creation"),
parser_errposition(@1)));
$$ = RELPERSISTENCE_TEMP;
}
| GLOBAL TEMPORARY { $$ = RELPERSISTENCE_GLOBAL_TEMP; }
| GLOBAL TEMP { $$ = RELPERSISTENCE_GLOBAL_TEMP; }
| UNLOGGED { $$ = RELPERSISTENCE_UNLOGGED; }
| /*EMPTY*/ { $$ = RELPERSISTENCE_PERMANENT; }
;
@ -13646,19 +13634,13 @@ OptTempTableName:
}
| GLOBAL TEMPORARY opt_table qualified_name
{
ereport(WARNING,
(errmsg("GLOBAL is deprecated in temporary table creation"),
parser_errposition(@1)));
$$ = $4;
$$->relpersistence = RELPERSISTENCE_TEMP;
$$->relpersistence = RELPERSISTENCE_GLOBAL_TEMP;
}
| GLOBAL TEMP opt_table qualified_name
{
ereport(WARNING,
(errmsg("GLOBAL is deprecated in temporary table creation"),
parser_errposition(@1)));
$$ = $4;
$$->relpersistence = RELPERSISTENCE_TEMP;
$$->relpersistence = RELPERSISTENCE_GLOBAL_TEMP;
}
| UNLOGGED opt_table qualified_name
{

View File

@ -3508,6 +3508,7 @@ List* transformAlterTableStmt(Oid relid, AlterTableStmt* stmt, const char* query
cxt.stmtType = ALTER_TABLE;
}
cxt.relation = stmt->relation;
cxt.relation->relpersistence = RelationGetRelPersistence(rel);
cxt.rel = rel;
cxt.inhRelations = NIL;
cxt.isalter = true;

View File

@ -1822,10 +1822,13 @@ Datum pg_relation_filepath(PG_FUNCTION_ARGS)
switch (relform->relpersistence) {
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT:
case RELPERSISTENCE_TEMP: // @Temp Table. temp table is the same as unlogged table here.
case RELPERSISTENCE_TEMP:
backend = InvalidBackendId;
break;
case RELPERSISTENCE_GLOBAL_TEMP:
backend = t_thrd.proc_cxt.MyBackendId;
break;
default:
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),

View File

@ -112,6 +112,7 @@
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
#include "catalog/pg_proc.h"
#include "catalog/storage_gtt.h"
#include "executor/executor.h"
#include "foreign/foreign.h"
#include "mb/pg_wchar.h"
@ -4754,18 +4755,23 @@ void examine_variable(PlannerInfo* root, Node* node, int var_relid, VariableStat
*/
char stakind = STARELKIND_CLASS;
Oid indexid = index->indexoid;
char relPersistence = get_rel_persistence(index->indexoid);
if (u_sess->attr.attr_common.upgrade_mode != 0) {
var_data->statsTuple = NULL;
var_data->freefunc = ReleaseSysCache;
} else if (relPersistence == RELPERSISTENCE_GLOBAL_TEMP) {
var_data->statsTuple = get_gtt_att_statistic(index->indexoid,
Int16GetDatum(pos + 1));
var_data->freefunc = release_gtt_statistic_cache;
} else {
var_data->statsTuple = SearchSysCache4(STATRELKINDATTINH,
ObjectIdGetDatum(indexid),
CharGetDatum(stakind),
Int16GetDatum(pos + 1),
BoolGetDatum(false));
var_data->freefunc = ReleaseSysCache;
}
var_data->freefunc = ReleaseSysCache;
if (HeapTupleIsValid(var_data->statsTuple)) {
/* Get index's table for permission check */
RangeTblEntry *rte;
@ -4853,17 +4859,22 @@ static void examine_simple_variable(PlannerInfo* root, Var* var, VariableStatDat
*
* We do not search system cache in upgrading
*/
char relPersistence = get_rel_persistence(rte->relid);
if (u_sess->attr.attr_common.upgrade_mode != 0) {
var_data->statsTuple = NULL;
var_data->freefunc = ReleaseSysCache;
} else if (relPersistence == RELPERSISTENCE_GLOBAL_TEMP) {
var_data->statsTuple = get_gtt_att_statistic(rte->relid, var->varattno);
var_data->freefunc = release_gtt_statistic_cache;
} else {
var_data->statsTuple = SearchSysCache4(STATRELKINDATTINH,
ObjectIdGetDatum(sta_relid),
CharGetDatum(sta_kind),
Int16GetDatum(var->varattno),
BoolGetDatum(rte->inh));
var_data->freefunc = ReleaseSysCache;
}
var_data->freefunc = ReleaseSysCache;
if (HeapTupleIsValid(var_data->statsTuple)) {
/* check if user has permission to read this column */
var_data->aclOk = (pg_class_aclcheck(rte->relid, GetUserId(), ACL_SELECT) == ACLCHECK_OK) ||
@ -5800,7 +5811,6 @@ static Pattern_Prefix_Status regex_fixed_prefix(
/* Use the regexp machinery to extract the prefix, if any */
prefix = regexp_fixed_prefix(DatumGetTextPP(patt_const->constvalue), case_insensitive, collation, &exact);
if (prefix == NULL) {
*prefix_const = NULL;
@ -6851,7 +6861,7 @@ Datum btcostestimate(PG_FUNCTION_ARGS)
if (index->indexkeys[0] != 0) {
/* Simple variable --- look to stats for the underlying table */
RangeTblEntry* rte = planner_rt_fetch(index->rel->relid, root);
char relPersistence = get_rel_persistence(rte->relid);
Assert(rte->rtekind == RTE_RELATION);
relid = rte->relid;
Assert(relid != InvalidOid);
@ -6868,16 +6878,22 @@ Datum btcostestimate(PG_FUNCTION_ARGS)
if (u_sess->attr.attr_common.upgrade_mode != 0) {
var_data.statsTuple = NULL;
var_data.freefunc = ReleaseSysCache;
} else if (relPersistence == RELPERSISTENCE_GLOBAL_TEMP) {
var_data.statsTuple = get_gtt_att_statistic(rte->relid, col_num);
var_data.freefunc = release_gtt_statistic_cache;
} else {
var_data.statsTuple = SearchSysCache4(STATRELKINDATTINH,
ObjectIdGetDatum(staoid),
CharGetDatum(stakind),
Int16GetDatum(col_num),
BoolGetDatum(rte->inh));
var_data.freefunc = ReleaseSysCache;
}
var_data.freefunc = ReleaseSysCache;
} else {
/* Expression --- maybe there are stats for the index itself */
char relPersistence = get_rel_persistence(index->indexoid);
relid = index->indexoid;
col_num = 1;
@ -6892,14 +6908,19 @@ Datum btcostestimate(PG_FUNCTION_ARGS)
if (u_sess->attr.attr_common.upgrade_mode != 0) {
var_data.statsTuple = NULL;
var_data.freefunc = ReleaseSysCache;
} else if (relPersistence == RELPERSISTENCE_GLOBAL_TEMP) {
var_data.statsTuple = get_gtt_att_statistic(relid, col_num);
var_data.freefunc = release_gtt_statistic_cache;
} else {
var_data.statsTuple = SearchSysCache4(STATRELKINDATTINH,
ObjectIdGetDatum(staoid),
CharGetDatum(stakind),
Int16GetDatum(col_num),
BoolGetDatum(false));
var_data.freefunc = ReleaseSysCache;
}
var_data.freefunc = ReleaseSysCache;
}
if (HeapTupleIsValid(var_data.statsTuple)) {
@ -8420,7 +8441,6 @@ void set_noanalyze_rellist(Oid relid, AttrNumber attid)
* so only check the statistics of foreign table. do not check column statistic.
*/
Relation rel = relation_open(relid, AccessShareLock);
if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE && isSpecifiedSrvTypeFromRelId(relid, OBS_SERVER)) {
is_obs_ft = true;
}

View File

@ -697,6 +697,25 @@ void AtEOXact_CatCache(bool is_commit)
#endif
}
/*
* Standard routine for creating cache context if it doesn't exist yet
*
* There are a lot of places (probably far more than necessary) that check
* whether CacheMemoryContext exists yet and want to create it if not.
* We centralize knowledge of exactly how to create it here.
*/
void CreateCacheMemoryContext(void)
{
/*
* Purely for paranoia, check that context doesn't exist; caller probably
* did so already.
*/
if (!CacheMemoryContext)
CacheMemoryContext = AllocSetContextCreate(TopMemoryContext,
"CacheMemoryContext",
ALLOCSET_DEFAULT_SIZES);
}
/*
* reset_catalog_cache
*

View File

@ -47,6 +47,7 @@
#include "catalog/pg_app_workloadgroup_mapping.h"
#include "catalog/namespace.h"
#endif
#include "catalog/storage_gtt.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
@ -1912,6 +1913,27 @@ Oid get_rel_tablespace(Oid relid)
}
}
/*
* get_rel_persistence
*
* Returns the relpersistence associated with a given relation.
*/
char get_rel_persistence(Oid relid)
{
HeapTuple tp;
Form_pg_class reltup;
char result;
tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for relation %u", relid);
reltup = (Form_pg_class) GETSTRUCT(tp);
result = reltup->relpersistence;
ReleaseSysCache(tp);
return result;
}
/*
* get_typisdefined
*
@ -4073,6 +4095,18 @@ int32 get_attavgwidth(Oid relid, AttrNumber attnum, bool ispartition)
if (u_sess->attr.attr_common.upgrade_mode != 0) {
return 0;
}
if (!ispartition && get_rel_persistence(relid) == RELPERSISTENCE_GLOBAL_TEMP) {
tp = get_gtt_att_statistic(relid, attnum);
if (!HeapTupleIsValid(tp)) {
return 0;
}
stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
if (stawidth > 0) {
return stawidth;
} else {
return 0;
}
}
tp = SearchSysCache4(
STATRELKINDATTINH, ObjectIdGetDatum(relid), CharGetDatum(stakind), Int16GetDatum(attnum), BoolGetDatum(false));
if (HeapTupleIsValid(tp)) {

View File

@ -112,6 +112,7 @@
#include "catalog/schemapg.h"
#include "catalog/storage.h"
#include "catalog/pg_extension_data_source.h"
#include "catalog/storage_gtt.h"
#include "commands/sec_rls_cmds.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
@ -148,6 +149,8 @@
#include "utils/partitionmap_gs.h"
#include "utils/resowner.h"
#include "access/cstore_am.h"
#include "nodes/nodeFuncs.h"
#include "nodes/makefuncs.h"
/*
* name of relcache init file(s), used to speed up backend startup
@ -1693,10 +1696,27 @@ static Relation relation_build_desc(Oid targetRelId, bool insertIt, bool buildke
switch (relation->rd_rel->relpersistence) {
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT:
case RELPERSISTENCE_TEMP: // @Temp Table. Temp table here is just like unlogged table.
relation->rd_backend = InvalidBackendId;
relation->rd_islocaltemp = false;
break;
case RELPERSISTENCE_TEMP: // @Temp Table. Temp table here is just like unlogged table.
relation->rd_backend = InvalidBackendId;
relation->rd_islocaltemp = true;
break;
case RELPERSISTENCE_GLOBAL_TEMP: // global temp table
{
BlockNumber relpages = 0;
double reltuples = 0;
BlockNumber relallvisible = 0;
relation->rd_backend = t_thrd.proc_cxt.MyBackendId;
relation->rd_islocaltemp = false;
get_gtt_relstats(RelationGetRelid(relation), &relpages, &reltuples, &relallvisible, NULL);
relation->rd_rel->relpages = static_cast<float8>(relpages);
relation->rd_rel->reltuples = static_cast<float8>(reltuples);
relation->rd_rel->relallvisible = static_cast<int4>(relallvisible);
}
break;
default:
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@ -1961,7 +1981,16 @@ static void relation_init_physical_addr(Relation relation)
heap_freetuple_ext(phys_tuple);
}
relation->rd_node.relNode = relation->rd_rel->relfilenode;
if (RELATION_IS_GLOBAL_TEMP(relation)) {
Oid newrelnode = gtt_fetch_current_relfilenode(RelationGetRelid(relation));
if (newrelnode != InvalidOid && newrelnode != relation->rd_rel->relfilenode) {
relation->rd_node.relNode = newrelnode;
} else {
relation->rd_node.relNode = relation->rd_rel->relfilenode;
}
} else {
relation->rd_node.relNode = relation->rd_rel->relfilenode;
}
} else {
/* Consult the relation mapper */
relation->rd_node.relNode = RelationMapOidToFilenode(relation->rd_id, relation->rd_rel->relisshared);
@ -2735,6 +2764,8 @@ static void relation_reload_index_info(Relation relation)
HeapTupleSetXmin(relation->rd_indextuple, HeapTupleGetRawXmin(tuple));
ReleaseSysCache(tuple);
gtt_fix_index_state(relation);
}
/* Okay, now it's valid again */
@ -3672,10 +3703,16 @@ Relation RelationBuildLocalRelation(const char* relname, Oid relnamespace, Tuple
switch (relpersistence) {
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT:
case RELPERSISTENCE_TEMP: // @Temp Table. Temp table here is just like unlogged table.
rel->rd_backend = InvalidBackendId;
rel->rd_islocaltemp = false;
break;
case RELPERSISTENCE_TEMP: // @Temp Table. Temp table here is just like unlogged table.
rel->rd_backend = InvalidBackendId;
rel->rd_islocaltemp = true;
break;
case RELPERSISTENCE_GLOBAL_TEMP: // global temp table
rel->rd_backend = t_thrd.proc_cxt.MyBackendId;
rel->rd_islocaltemp = false;
break;
default:
ereport(ERROR,
@ -3815,8 +3852,8 @@ void RelationSetNewRelfilenode(Relation relation, TransactionId freezeXid, bool
Datum values[Natts_pg_class];
bool nulls[Natts_pg_class];
bool replaces[Natts_pg_class];
errno_t rc;
errno_t rc = EOK;
bool modifyPgClass = !RELATION_IS_GLOBAL_TEMP(relation);
/* Indexes, sequences must have Invalid frozenxid; other rels must not */
Assert(((relation->rd_rel->relkind == RELKIND_INDEX || relation->rd_rel->relkind == RELKIND_SEQUENCE)
? freezeXid == InvalidTransactionId : TransactionIdIsNormal(freezeXid)) ||
@ -3850,17 +3887,22 @@ void RelationSetNewRelfilenode(Relation relation, TransactionId freezeXid, bool
}
}
/*
* Get a writable copy of the pg_class tuple for the given relation.
*/
pg_class = heap_open(RelationRelationId, RowExclusiveLock);
tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(RelationGetRelid(relation)));
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not find tuple for relation %u", RelationGetRelid(relation))));
classform = (Form_pg_class)GETSTRUCT(tuple);
if (modifyPgClass) {
/*
* Get a writable copy of the pg_class tuple for the given relation.
*/
pg_class = heap_open(RelationRelationId, RowExclusiveLock);
tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(RelationGetRelid(relation)));
if (!HeapTupleIsValid(tuple)) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not find tuple for relation %u", RelationGetRelid(relation))));
}
classform = (Form_pg_class) GETSTRUCT(tuple);
} else {
memset_s(&classform, sizeof(classform), 0, sizeof(classform));
securec_check(rc, "\0", "\0");
}
ereport(LOG,
(errmsg("Relation %s(%u) set newfilenode %u oldfilenode %u xid %lu",
@ -3880,52 +3922,58 @@ void RelationSetNewRelfilenode(Relation relation, TransactionId freezeXid, bool
newrnode.node.relNode = newrelfilenode;
newrnode.backend = relation->rd_backend;
RelationCreateStorage(
newrnode.node, relation->rd_rel->relpersistence, relation->rd_rel->relowner, relation->rd_bucketoid);
newrnode.node, relation->rd_rel->relpersistence, relation->rd_rel->relowner, relation->rd_bucketoid, relation);
smgrclosenode(newrnode);
/*
* Schedule unlinking of the old storage at transaction commit.
*/
RelationDropStorage(relation, isDfsTruncate);
if (!modifyPgClass) {
Oid relnode = gtt_fetch_current_relfilenode(RelationGetRelid(relation));
Assert(RELATION_IS_GLOBAL_TEMP(relation));
Assert(!RelationIsMapped(relation));
relation->rd_node.relNode = relnode;
CacheInvalidateRelcache(relation);
} else {
/*
* Now update the pg_class row. However, if we're dealing with a mapped
* index, pg_class.relfilenode doesn't change; instead we have to send the
* update to the relation mapper.
*/
if (RelationIsMapped(relation))
RelationMapUpdateMap(RelationGetRelid(relation), newrelfilenode, relation->rd_rel->relisshared, false);
else
classform->relfilenode = newrelfilenode;
/*
* Now update the pg_class row. However, if we're dealing with a mapped
* index, pg_class.relfilenode doesn't change; instead we have to send the
* update to the relation mapper.
*/
if (RelationIsMapped(relation))
RelationMapUpdateMap(RelationGetRelid(relation), newrelfilenode, relation->rd_rel->relisshared, false);
else
classform->relfilenode = newrelfilenode;
/* These changes are safe even for a mapped relation */
if (relation->rd_rel->relkind != RELKIND_SEQUENCE) {
classform->relpages = 0; /* it's empty until further notice */
classform->reltuples = 0;
classform->relallvisible = 0;
}
/* set classform's relfrozenxid and relfrozenxid64 */
classform->relfrozenxid = (ShortTransactionId)InvalidTransactionId;
/* These changes are safe even for a mapped relation */
if (relation->rd_rel->relkind != RELKIND_SEQUENCE) {
classform->relpages = 0; /* it's empty until further notice */
classform->reltuples = 0;
classform->relallvisible = 0;
rc = memset_s(values, sizeof(values), 0, sizeof(values));
securec_check(rc, "\0", "\0");
rc = memset_s(nulls, sizeof(nulls), false, sizeof(nulls));
securec_check(rc, "\0", "\0");
rc = memset_s(replaces, sizeof(replaces), false, sizeof(replaces));
securec_check(rc, "\0", "\0");
replaces[Anum_pg_class_relfrozenxid64 - 1] = true;
values[Anum_pg_class_relfrozenxid64 - 1] = TransactionIdGetDatum(freezeXid);
nctup = heap_modify_tuple(tuple, RelationGetDescr(pg_class), values, nulls, replaces);
simple_heap_update(pg_class, &nctup->t_self, nctup);
CatalogUpdateIndexes(pg_class, nctup);
heap_freetuple_ext(nctup);
heap_freetuple_ext(tuple);
heap_close(pg_class, RowExclusiveLock);
}
/* set classform's relfrozenxid and relfrozenxid64 */
classform->relfrozenxid = (ShortTransactionId)InvalidTransactionId;
rc = memset_s(values, sizeof(values), 0, sizeof(values));
securec_check(rc, "\0", "\0");
rc = memset_s(nulls, sizeof(nulls), false, sizeof(nulls));
securec_check(rc, "\0", "\0");
rc = memset_s(replaces, sizeof(replaces), false, sizeof(replaces));
securec_check(rc, "\0", "\0");
replaces[Anum_pg_class_relfrozenxid64 - 1] = true;
values[Anum_pg_class_relfrozenxid64 - 1] = TransactionIdGetDatum(freezeXid);
nctup = heap_modify_tuple(tuple, RelationGetDescr(pg_class), values, nulls, replaces);
simple_heap_update(pg_class, &nctup->t_self, nctup);
CatalogUpdateIndexes(pg_class, nctup);
heap_freetuple_ext(nctup);
heap_freetuple_ext(tuple);
heap_close(pg_class, RowExclusiveLock);
/*
* Make the pg_class row change visible, as well as the relation map
@ -5067,6 +5115,45 @@ List* RelationGetIndexExpressions(Relation relation)
return result;
}
/*
* RelationGetDummyIndexExpressions -- get dummy expressions for an index
*
* Return a list of dummy expressions (just Const nodes) with the same
* types/typmods/collations as the index's real expressions. This is
* useful in situations where we don't want to run any user-defined code.
*/
List* RelationGetDummyIndexExpressions(Relation relation)
{
List* result;
Datum exprsDatum;
bool isnull;
char* exprsString;
List* rawExprs;
ListCell* lc;
/* Quick exit if there is nothing to do. */
if (relation->rd_indextuple == NULL || heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL)) {
return NIL;
}
/* Extract raw node tree(s) from index tuple. */
exprsDatum = heap_getattr(relation->rd_indextuple, Anum_pg_index_indexprs, get_pg_index_descriptor(), &isnull);
Assert(!isnull);
exprsString = TextDatumGetCString(exprsDatum);
rawExprs = (List*)stringToNode(exprsString);
pfree(exprsString);
/* Construct null Consts; the typlen and typbyval are arbitrary. */
result = NIL;
foreach (lc, rawExprs) {
Node* rawExpr = (Node*)lfirst(lc);
result = lappend(
result, makeConst(exprType(rawExpr), exprTypmod(rawExpr), exprCollation(rawExpr), 1, (Datum)0, true, true));
}
return result;
}
/*
* RelationGetIndexPredicate -- get the index predicate for an index
*

View File

@ -40,6 +40,7 @@
#include "access/dfs/dfs_insert.h"
#include "catalog/namespace.h"
#include "catalog/pgxc_group.h"
#include "catalog/storage_gtt.h"
#include "commands/async.h"
#include "commands/prepare.h"
#include "commands/vacuum.h"
@ -4597,6 +4598,38 @@ void set_qunit_case_number_hook(int newval, void* extra)
static void init_configure_names_int()
{
struct config_int local_configure_names_int[] = {
{
{
"max_active_global_temporary_table",
PGC_USERSET,
UNGROUPED,
gettext_noop("max active global temporary table."),
NULL
},
&u_sess->attr.attr_storage.max_active_gtt,
1000,
0,
1000000,
NULL,
NULL,
NULL
},
{
{
"vacuum_gtt_defer_check_age",
PGC_USERSET,
CLIENT_CONN_STATEMENT,
gettext_noop("The defer check age of GTT, used to check expired data after vacuum."),
NULL
},
&u_sess->attr.attr_storage.vacuum_gtt_defer_check_age,
10000,
0,
1000000,
NULL,
NULL,
NULL
},
{
{
"archive_timeout",

View File

@ -57,6 +57,7 @@ MemoryContext StreamInfoContext = NULL;
* of these contexts, refer to src/backend/utils/mmgr/README
*/
THR_LOCAL MemoryContext ErrorContext = NULL;
THR_LOCAL MemoryContext CacheMemoryContext = NULL;
THR_LOCAL MemoryContext SelfMemoryContext = NULL;
THR_LOCAL MemoryContext TopMemoryContext = NULL;
THR_LOCAL MemoryContext AlignMemoryContext = NULL;

View File

@ -233,7 +233,8 @@ Boot_CreateStmt:
mapped_relation,
true,
REL_CMPRS_NOT_SUPPORT,
BOOTSTRAP_SUPERUSERID);
BOOTSTRAP_SUPERUSERID,
false);
ereport(DEBUG4, (errmsg("bootstrap relation created")));
/*

View File

@ -34,6 +34,7 @@
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_hashbucket_fn.h"
#include "catalog/namespace.h"
#include "catalog/storage_gtt.h"
#include "commands/dbcommands.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
@ -234,7 +235,8 @@ static void get_sample_rows_for_query(
MemoryContext speccontext, Relation rel, VacuumStmt* vacstmt, int64* num_sample_rows, HeapTuple** samplerows);
template <bool isSingleColumn>
static void update_stats_catalog(
Relation pgstat, MemoryContext oldcontext, Oid relid, char relkind, bool inh, VacAttrStats* stats);
Relation pgstat, MemoryContext oldcontext, Oid relid, char relkind, bool inh, VacAttrStats* stats, int natts,
char relpersistence);
/* The sample info of special attribute for compute statistic for index or type of tsvector. */
typedef struct {
@ -494,6 +496,11 @@ static void analyze_rel_internal(Relation onerel, VacuumStmt* vacstmt, BufferAcc
return;
}
if (RELATION_IS_GLOBAL_TEMP(onerel) && !gtt_storage_attached(RelationGetRelid(onerel))) {
relation_close(onerel, ShareUpdateExclusiveLock);
return;
}
/*
* We can ANALYZE any table except pg_statistic. See update_attstats
*/
@ -720,7 +727,7 @@ static int get_total_width(
total_width1 = 0;
for (i = 0; i < thisdata->attr_cnt; i++) {
for (unsigned int j = 0; j < vacattrstats[i]->num_attrs; ++j) {
for (unsigned int j = 0; j < thisdata->vacattrstats[i]->num_attrs; ++j) {
attr = thisdata->vacattrstats[i]->attrs[j];
/* This should match set_rel_width() in costsize.c */
@ -1578,7 +1585,8 @@ static void do_analyze_rel(Relation onerel, VacuumStmt* vacstmt, BlockNumber rel
VacAttrStats* stats = vacattrstats[i];
if (stats->num_attrs > 1) {
stats->stats_valid = true;
update_attstats(RelationGetRelid(onerel), STARELKIND_CLASS, inh, 1, &stats);
update_attstats(RelationGetRelid(onerel), STARELKIND_CLASS, inh, 1, &stats,
RelationGetRelPersistence(onerel));
}
}
}
@ -4188,7 +4196,7 @@ void releaseSourceAfterDelteOrUpdateAttStats(
* function
*/
// Added parameter - char relkind by data partition
void update_attstats(Oid relid, char relkind, bool inh, int natts, VacAttrStats** vacattrstats)
void update_attstats(Oid relid, char relkind, bool inh, int natts, VacAttrStats** vacattrstats, char relpersistence)
{
Relation pgstat = NULL;
Relation pgstat_ext = NULL;
@ -4226,7 +4234,7 @@ void update_attstats(Oid relid, char relkind, bool inh, int natts, VacAttrStats*
}
/* do multi column stats update */
update_stats_catalog<false>(pgstat_ext, oldcontext, relid, relkind, inh, stats);
update_stats_catalog<false>(pgstat_ext, oldcontext, relid, relkind, inh, stats, natts, relpersistence);
} else {
/* Open rel handler for pg_statistic to process single-column statistic */
if (!pgstat) {
@ -4234,7 +4242,7 @@ void update_attstats(Oid relid, char relkind, bool inh, int natts, VacAttrStats*
}
/* do signle column stats update */
update_stats_catalog<true>(pgstat, oldcontext, relid, relkind, inh, stats);
update_stats_catalog<true>(pgstat, oldcontext, relid, relkind, inh, stats, natts, relpersistence);
}
}
@ -4261,7 +4269,8 @@ void update_attstats(Oid relid, char relkind, bool inh, int natts, VacAttrStats*
*/
template <bool isSingleColumn>
static void update_stats_catalog(
Relation pgstat, MemoryContext oldcontext, Oid relid, char relkind, bool inh, VacAttrStats* stats)
Relation pgstat, MemoryContext oldcontext, Oid relid, char relkind, bool inh, VacAttrStats* stats, int natts,
char relpersistence)
{
HeapTuple stup, oldtup;
int i, k, n;
@ -4402,6 +4411,17 @@ static void update_stats_catalog(
values[Anum_pg_statistic_ext_stakey - 1] = PointerGetDatum(stakey);
}
/* Update column statistic to localhash, not catalog */
if (relpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
up_gtt_att_statistic(relid,
attnum,
natts,
RelationGetDescr(pgstat),
values,
nulls);
return;
}
/* store tuple to pg_statistic(_ext) */
PG_TRY();
{
@ -6546,11 +6566,13 @@ static bool do_analyze_samplerows(Relation onerel, VacuumStmt* vacstmt, int attr
* previous statistics for the target columns. (If there are stats in
* pg_statistic for columns we didn't process, we leave them alone.)
*/
update_attstats(RelationGetRelid(onerel), STARELKIND_CLASS, inh, attr_cnt, vacattrstats);
update_attstats(RelationGetRelid(onerel), STARELKIND_CLASS, inh, attr_cnt, vacattrstats,
RelationGetRelPersistence(onerel));
for (i = 0; i < nindexes; i++) {
AnlIndexData* thisdata = &indexdata[i];
update_attstats(RelationGetRelid(Irel[i]), STARELKIND_CLASS, false, thisdata->attr_cnt, thisdata->vacattrstats);
update_attstats(RelationGetRelid(Irel[i]), STARELKIND_CLASS, false, thisdata->attr_cnt, thisdata->vacattrstats,
RelationGetRelPersistence(Irel[i]));
}
return true;
@ -6685,7 +6707,8 @@ static void do_analyze_sampletable(Relation onerel, VacuumStmt* vacstmt, int att
* previous statistics for the target columns. (If there are stats in
* pg_statistic for columns we didn't process, we leave them alone.)
*/
update_attstats(RelationGetRelid(onerel), STARELKIND_CLASS, inh, attr_cnt, vacattrstats);
update_attstats(RelationGetRelid(onerel), STARELKIND_CLASS, inh, attr_cnt, vacattrstats,
RelationGetRelPersistence(onerel));
/*
* Update stats of dfs table or delta table using statistic of complex table
@ -6693,10 +6716,12 @@ static void do_analyze_sampletable(Relation onerel, VacuumStmt* vacstmt, int att
*/
if (analyzemode == ANALYZECOMPLEX) {
if (!vacstmt->pstGlobalStatEx[ANALYZEMAIN - 1].exec_query)
update_attstats(RelationGetRelid(onerel), STARELKIND_CLASS, false, attr_cnt, vacattrstats);
update_attstats(RelationGetRelid(onerel), STARELKIND_CLASS, false,
attr_cnt, vacattrstats, RelationGetRelPersistence(onerel));
if (!vacstmt->pstGlobalStatEx[ANALYZEDELTA - 1].exec_query)
update_attstats(onerel->rd_rel->reldeltarelid, STARELKIND_CLASS, false, attr_cnt, vacattrstats);
update_attstats(onerel->rd_rel->reldeltarelid, STARELKIND_CLASS, false,
attr_cnt, vacattrstats, RelationGetRelPersistence(onerel));
}
/*
@ -6712,7 +6737,8 @@ static void do_analyze_sampletable(Relation onerel, VacuumStmt* vacstmt, int att
AnlIndexData* thisdata = &indexdata[i];
update_attstats(
RelationGetRelid(Irel[i]), STARELKIND_CLASS, false, thisdata->attr_cnt, thisdata->vacattrstats);
RelationGetRelid(Irel[i]), STARELKIND_CLASS, false, thisdata->attr_cnt, thisdata->vacattrstats,
RelationGetRelPersistence(Irel[i]));
}
}

View File

@ -33,6 +33,7 @@
#include "catalog/index.h"
#include "catalog/namespace.h"
#include "catalog/toasting.h"
#include "catalog/storage_gtt.h"
#include "commands/cluster.h"
#include "commands/tablecmds.h"
#include "commands/vacuum.h"
@ -141,6 +142,9 @@ static Datum pgxc_parallel_execution(const char* query, ExecNodes* exec_nodes);
static int switch_relfilenode_execnode(Oid relOid1, Oid relOid2, bool isbucket, RedisSwitchNode* rsn);
#endif
static void swapRelationIndicesRelfileNode(Relation rel1, Relation rel2, bool swapBucket);
static void GttSwapRelationFiles(Oid r1, Oid r2, bool targetIsPgClass, bool swapToastByContent,
TransactionId frozenXid, Oid *mappedTables);
/* ---------------------------------------------------------------------------
* This cluster code allows for clustering multiple tables at once. Because
* of this, we cannot just run everything on a single transaction, or we
@ -453,6 +457,12 @@ void cluster_rel(Oid tableOid, Oid partitionOid, Oid indexOid, bool recheck, boo
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot vacuum temporary tables of other sessions")));
}
if (RELATION_IS_GLOBAL_TEMP(OldHeap) && !gtt_storage_attached(RelationGetRelid(OldHeap))) {
relation_close(OldHeap, lockMode);
gstrace_exit(GS_TRC_ID_cluster_rel);
return;
}
/*
* Also check for active uses of the relation in the current transaction,
* including open scans and pending AFTER trigger events.
@ -688,6 +698,7 @@ static void rebuild_relation(
Oid tableOid = RelationGetRelid(OldHeap);
Oid tableSpace = OldHeap->rd_rel->reltablespace;
Oid OIDNewHeap;
char relpersistence;
bool is_system_catalog = false;
bool swap_toast_by_content = false;
TransactionId frozenXid;
@ -699,6 +710,7 @@ static void rebuild_relation(
mark_index_clustered(OldHeap, indexOid);
/* Remember if it's a system catalog */
relpersistence = OldHeap->rd_rel->relpersistence;
is_system_catalog = IsSystemRelation(OldHeap);
/* Close relcache entry, but keep lock until transaction commit */
@ -732,7 +744,8 @@ static void rebuild_relation(
* Swap the physical files of the target and transient tables, then
* rebuild the target's indexes and throw away the transient table.
*/
finish_heap_swap(tableOid, OIDNewHeap, is_system_catalog, swap_toast_by_content, false, frozenXid, memUsage);
finish_heap_swap(
tableOid, OIDNewHeap, is_system_catalog, swap_toast_by_content, false, frozenXid, memUsage, relpersistence);
/* report vacuum full stat to PgStatCollector */
pgstat_report_vacuum(tableOid, InvalidOid, is_shared, deleteTupleNum);
@ -1783,6 +1796,8 @@ static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, int
TransactionId FreezeXid;
bool use_sort = false;
double tups_vacuumed = 0;
bool isGtt = false;
TransactionId gttRelfrozenxid = 0;
/*
* Open the relations we need.
@ -1794,6 +1809,10 @@ static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, int
else
OldIndex = NULL;
if (RELATION_IS_GLOBAL_TEMP(OldHeap)) {
isGtt = true;
}
/*
* If the OldHeap has a toast table, get lock on the toast table to keep
* it from being vacuumed. This is needed because autovacuum processes
@ -1851,32 +1870,38 @@ static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, int
* FreezeXid will become the table's new relfrozenxid, and that mustn't go
* backwards, so take the max.
*/
bool isNull = false;
TransactionId relfrozenxid;
Relation rel = heap_open(RelationRelationId, AccessShareLock);
HeapTuple tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(OIDOldHeap));
if (!HeapTupleIsValid(tuple)) {
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("cache lookup failed for relation %u", RelationGetRelid(OldHeap))));
}
Datum xid64datum = heap_getattr(tuple, Anum_pg_class_relfrozenxid64, RelationGetDescr(rel), &isNull);
heap_close(rel, AccessShareLock);
heap_freetuple(tuple);
if (isNull) {
relfrozenxid = OldHeap->rd_rel->relfrozenxid;
if (TransactionIdPrecedes(t_thrd.xact_cxt.ShmemVariableCache->nextXid, relfrozenxid) ||
!TransactionIdIsNormal(relfrozenxid)) {
relfrozenxid = FirstNormalTransactionId;
}
if (isGtt) {
(void)get_gtt_relstats(OIDOldHeap, NULL, NULL, NULL, &gttRelfrozenxid);
if (TransactionIdIsValid(gttRelfrozenxid) && TransactionIdPrecedes(FreezeXid, gttRelfrozenxid))
FreezeXid = gttRelfrozenxid;
} else {
relfrozenxid = DatumGetTransactionId(xid64datum);
}
bool isNull = false;
TransactionId relfrozenxid;
Relation rel = heap_open(RelationRelationId, AccessShareLock);
HeapTuple tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(OIDOldHeap));
if (!HeapTupleIsValid(tuple)) {
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("cache lookup failed for relation %u", RelationGetRelid(OldHeap))));
}
Datum xid64datum = heap_getattr(tuple, Anum_pg_class_relfrozenxid64, RelationGetDescr(rel), &isNull);
heap_close(rel, AccessShareLock);
heap_freetuple(tuple);
if (TransactionIdPrecedes(FreezeXid, relfrozenxid)) {
FreezeXid = relfrozenxid;
if (isNull) {
relfrozenxid = OldHeap->rd_rel->relfrozenxid;
if (TransactionIdPrecedes(t_thrd.xact_cxt.ShmemVariableCache->nextXid, relfrozenxid) ||
!TransactionIdIsNormal(relfrozenxid)) {
relfrozenxid = FirstNormalTransactionId;
}
} else {
relfrozenxid = DatumGetTransactionId(xid64datum);
}
if (TransactionIdPrecedes(FreezeXid, relfrozenxid)) {
FreezeXid = relfrozenxid;
}
}
/* return selected value to caller */
*pFreezeXid = FreezeXid;
@ -2765,7 +2790,7 @@ static void SwapCStoreTables(Oid relId1, Oid relId2, Oid parentOid, Oid tempTabl
* cleaning up (including rebuilding all indexes on the old heap).
*/
void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, bool is_system_catalog, bool swap_toast_by_content,
bool check_constraints, TransactionId frozenXid, AdaptMem* memInfo)
bool checkConstraints, TransactionId frozenXid, AdaptMem* memInfo, char newrelpersistence)
{
ObjectAddress object;
Oid mapped_tables[4];
@ -2781,8 +2806,15 @@ void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, bool is_system_catalog, bo
* Swap the contents of the heap relations (including any toast tables).
* Also set old heap's relfrozenxid to frozenXid.
*/
swap_relation_files(
OIDOldHeap, OIDNewHeap, (OIDOldHeap == RelationRelationId), swap_toast_by_content, frozenXid, mapped_tables);
if (newrelpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
Assert(!is_system_catalog);
GttSwapRelationFiles(OIDOldHeap, OIDNewHeap, (OIDOldHeap == RelationRelationId),
swap_toast_by_content, frozenXid, mapped_tables);
} else {
swap_relation_files(OIDOldHeap, OIDNewHeap, (OIDOldHeap == RelationRelationId),
swap_toast_by_content, frozenXid, mapped_tables);
}
/*
* If it's a system catalog, queue an sinval message to flush all
* catcaches on the catalog when we reach CommandCounterIncrement.
@ -2806,7 +2838,7 @@ void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, bool is_system_catalog, bo
* broken ones, so it can't be necessary to set indcheckxmin.
*/
reindex_flags = REINDEX_REL_SUPPRESS_INDEX_USE;
if (check_constraints)
if (checkConstraints)
reindex_flags |= REINDEX_REL_CHECK_CONSTRAINTS;
reindex_relation(OIDOldHeap, reindex_flags, REINDEX_ALL_INDEX, memInfo);
@ -2965,6 +2997,111 @@ static List* get_tables_to_cluster(MemoryContext cluster_context)
return rvs;
}
static void GttSwapRelationFiles(Oid r1, Oid r2, bool targetIsPgClass, bool swapToastByContent,
TransactionId frozenXid, Oid *mappedTables)
{
Relation relRelation;
Oid relfilenode1,
relfilenode2;
Relation rel1;
Relation rel2;
relRelation = relation_open(RelationRelationId, RowExclusiveLock);
rel1 = relation_open(r1, AccessExclusiveLock);
rel2 = relation_open(r2, AccessExclusiveLock);
relfilenode1 = gtt_fetch_current_relfilenode(r1);
relfilenode2 = gtt_fetch_current_relfilenode(r2);
Assert(OidIsValid(relfilenode1) && OidIsValid(relfilenode2));
gtt_switch_rel_relfilenode(r1, relfilenode1, r2, relfilenode2, true);
CacheInvalidateRelcache(rel1);
CacheInvalidateRelcache(rel2);
if (rel1->rd_rel->reltoastrelid || rel2->rd_rel->reltoastrelid) {
if (swapToastByContent) {
if (rel1->rd_rel->reltoastrelid && rel2->rd_rel->reltoastrelid) {
GttSwapRelationFiles(rel1->rd_rel->reltoastrelid,
rel2->rd_rel->reltoastrelid,
targetIsPgClass,
swapToastByContent,
frozenXid,
mappedTables);
} else {
elog(ERROR, "cannot swap toast files by content when there's only one");
}
} else {
ObjectAddress baseobject,
toastobject;
long count;
if (IsSystemRelation(rel1)) {
elog(ERROR, "cannot swap toast files by links for system catalogs");
}
if (rel1->rd_rel->reltoastrelid) {
count = deleteDependencyRecordsFor(RelationRelationId,
rel1->rd_rel->reltoastrelid,
false);
if (count != 1) {
elog(ERROR, "expected one dependency record for TOAST table, found %ld",
count);
}
}
if (rel2->rd_rel->reltoastrelid) {
count = deleteDependencyRecordsFor(RelationRelationId,
rel2->rd_rel->reltoastrelid,
false);
if (count != 1) {
elog(ERROR, "expected one dependency record for TOAST table, found %ld",
count);
}
}
/* Register new dependencies */
baseobject.classId = RelationRelationId;
baseobject.objectSubId = 0;
toastobject.classId = RelationRelationId;
toastobject.objectSubId = 0;
if (rel1->rd_rel->reltoastrelid) {
baseobject.objectId = r1;
toastobject.objectId = rel1->rd_rel->reltoastrelid;
recordDependencyOn(&toastobject, &baseobject,
DEPENDENCY_INTERNAL);
}
if (rel2->rd_rel->reltoastrelid) {
baseobject.objectId = r2;
toastobject.objectId = rel2->rd_rel->reltoastrelid;
recordDependencyOn(&toastobject, &baseobject, DEPENDENCY_INTERNAL);
}
}
}
if (swapToastByContent && rel1->rd_rel->relkind == RELKIND_TOASTVALUE &&
rel2->rd_rel->relkind == RELKIND_TOASTVALUE) {
GttSwapRelationFiles(rel1->rd_rel->reltoastidxid,
rel2->rd_rel->reltoastidxid,
targetIsPgClass,
swapToastByContent,
InvalidTransactionId,
mappedTables);
}
relation_close(rel1, NoLock);
relation_close(rel2, NoLock);
relation_close(relRelation, RowExclusiveLock);
RelationCloseSmgrByOid(r1);
RelationCloseSmgrByOid(r2);
CommandCounterIncrement();
}
/*
* Reconstruct and rewrite the given tuple
*

View File

@ -34,6 +34,7 @@
#ifdef PGXC
#include "catalog/pg_trigger.h"
#endif
#include "catalog/storage_gtt.h"
#include "commands/copy.h"
#include "commands/defrem.h"
#include "commands/trigger.h"
@ -982,7 +983,7 @@ uint64 DoCopy(CopyStmt* stmt, const char* queryString)
Assert(rel);
/* check read-only transaction */
if (u_sess->attr.attr_common.XactReadOnly && !RelationIsLocalTemp(rel))
if (u_sess->attr.attr_common.XactReadOnly && !RELATION_IS_TEMP(rel))
PreventCommandIfReadOnly("COPY FROM");
/* set write for backend status for the thread, we will use it to check default transaction readOnly */
@ -3479,6 +3480,7 @@ static uint64 CopyFrom(CopyState cstate)
0);
ExecOpenIndices(resultRelInfo);
init_gtt_storage(CMD_INSERT, resultRelInfo);
resultRelationDesc = resultRelInfo->ri_RelationDesc;
isPartitionRel = RELATION_IS_PARTITIONED(resultRelationDesc);

View File

@ -332,6 +332,23 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
List* partitionTableList = NIL;
List* partitionIndexdef = NIL;
List* partitiontspList = NIL;
char relPersistence;
bool concurrent;
/*
* Force non-concurrent build on temporary relations, even if CONCURRENTLY
* was requested. Other backends can't access a temporary relation, so
* there's no harm in grabbing a stronger lock, and a non-concurrent DROP
* is more efficient. Do this before any use of the concurrent option is
* done.
*/
relPersistence = get_rel_persistence(relationId);
if (stmt->concurrent && !(relPersistence == RELPERSISTENCE_TEMP ||
relPersistence == RELPERSISTENCE_GLOBAL_TEMP)) {
concurrent = true;
} else {
concurrent = false;
}
/*
* count attributes in index
@ -356,7 +373,7 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
* the relation. To avoid lock upgrade hazards, that lock should be at
* least as strong as the one we take here.
*/
lockmode = stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock;
lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
rel = heap_open(relationId, lockmode);
relationId = RelationGetRelid(rel);
@ -393,7 +410,7 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
/*
* partitioned index not is not support concurrent index
*/
if (stmt->isPartitioned && stmt->concurrent) {
if (stmt->isPartitioned && concurrent) {
ereport(
ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot create concurrent partitioned indexes ")));
}
@ -655,8 +672,8 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
indexInfo->ii_ExclusionStrats = NULL;
indexInfo->ii_Unique = stmt->unique;
/* In a concurrent build, mark it not-ready-for-inserts */
indexInfo->ii_ReadyForInserts = !stmt->concurrent;
indexInfo->ii_Concurrent = stmt->concurrent;
indexInfo->ii_ReadyForInserts = !concurrent;
indexInfo->ii_Concurrent = concurrent;
indexInfo->ii_BrokenHotChain = false;
indexInfo->ii_PgClassAttrId = 0;
@ -765,7 +782,7 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
* A valid stmt->oldPSortOid implies that we already have a built form
* of the psort index.
*/
if ((OidIsValid(stmt->oldNode) && !(skip_build && !stmt->concurrent) &&
if ((OidIsValid(stmt->oldNode) && !(skip_build && !concurrent) &&
!u_sess->attr.attr_sql.enable_cluster_resize) ||
(OidIsValid(stmt->oldPSortOid) && !OidIsValid(stmt->oldNode))) {
ereport(defence_errlevel(),
@ -803,7 +820,7 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
stmt->initdeferred,
g_instance.attr.attr_common.allowSystemTableMods,
true,
stmt->concurrent,
concurrent,
&extra);
heap_close(rel, NoLock);
return indexRelationId;
@ -855,8 +872,8 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
stmt->deferrable,
stmt->initdeferred,
(g_instance.attr.attr_common.allowSystemTableMods || u_sess->attr.attr_common.IsInplaceUpgrade),
skip_build || stmt->concurrent,
stmt->concurrent,
skip_build || concurrent,
concurrent,
&extra);
/* Add any requested comment */
if (stmt->idxcomment != NULL)
@ -984,7 +1001,7 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
return indexRelationId;
}
if (!stmt->concurrent) {
if (!concurrent) {
/* Close the heap and we're done, in the non-concurrent case */
heap_close(rel, NoLock);
return indexRelationId;
@ -2105,6 +2122,8 @@ void ReindexIndex(RangeVar* indexRelation, const char* partition_name, AdaptMem*
Oid heapOid = InvalidOid;
Oid heapPartOid = InvalidOid;
LOCKMODE lockmode;
Relation irel;
char persistence;
/* lock level used here should match index lock reindex_index() */
if (partition_name != NULL)
@ -2120,6 +2139,13 @@ void ReindexIndex(RangeVar* indexRelation, const char* partition_name, AdaptMem*
false,
RangeVarCallbackForReindexIndex,
(void*)&heapOid);
/*
* Obtain the current persistence of the existing index. We already hold
* lock on the index.
*/
irel = index_open(indOid, NoLock);
persistence = irel->rd_rel->relpersistence;
index_close(irel, NoLock);
if (partition_name != NULL)
indPartOid = partitionNameGetPartitionOid(indOid,
@ -2131,7 +2157,7 @@ void ReindexIndex(RangeVar* indexRelation, const char* partition_name, AdaptMem*
PartitionNameCallbackForIndexPartition,
(void*)&heapPartOid,
ShareLock); // lock on heap partition
reindex_index(indOid, indPartOid, false, mem_info, false);
reindex_index(indOid, indPartOid, false, mem_info, false, persistence);
}
void PartitionNameCallbackForIndexPartition(Oid partitionedRelationOid, const char* partitionName, Oid partId,

View File

@ -408,7 +408,8 @@ void DefineSequence(CreateSeqStmt* seq)
isUseLocalSeq = IS_SINGLE_NODE || isTempNamespace(namespaceOid);
bool notSupportTmpSeq = false;
if (seq->sequence->relpersistence == RELPERSISTENCE_TEMP) {
if (seq->sequence->relpersistence == RELPERSISTENCE_TEMP ||
seq->sequence->relpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
notSupportTmpSeq = true;
} else if (IS_MAIN_COORDINATOR || IS_SINGLE_NODE) {
if (seq->canCreateTempSeq) {

View File

@ -61,6 +61,7 @@
#include "catalog/storage_xlog.h"
#include "catalog/toasting.h"
#include "catalog/cstore_ctlg.h"
#include "catalog/storage_gtt.h"
#include "commands/cluster.h"
#include "commands/comment.h"
#include "commands/defrem.h"
@ -608,6 +609,8 @@ static void ResetRelRedisCtidRelOptions(
Relation rel, Oid part_oid, int cat_id, int att_num, int att_inx, Oid pgcat_oid);
static bool WLMRelationCanTruncate(Relation rel);
static void alter_partition_policy_if_needed(Relation rel, List* defList);
static OnCommitAction GttOncommitOption(const List *options);
/* get all partitions oid */
static List* get_all_part_oid(Oid relid)
@ -1429,12 +1432,16 @@ Oid DefineRelation(CreateStmt* stmt, char relkind, Oid ownerId)
stmt->relation->relpersistence = RELPERSISTENCE_PERMANENT;
/* Check consistency of arguments */
if (stmt->oncommit != ONCOMMIT_NOOP && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
if (stmt->oncommit != ONCOMMIT_NOOP &&
!(stmt->relation->relpersistence == RELPERSISTENCE_TEMP ||
stmt->relation->relpersistence == RELPERSISTENCE_GLOBAL_TEMP))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("ON COMMIT can only be used on temporary tables")));
/* @Temp Table. We do not support on commit drop right now. */
if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP && stmt->oncommit == ONCOMMIT_DROP)
if ((stmt->relation->relpersistence == RELPERSISTENCE_TEMP ||
stmt->relation->relpersistence == RELPERSISTENCE_GLOBAL_TEMP) &&
stmt->oncommit == ONCOMMIT_DROP)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("ON COMMIT only support PRESERVE ROWS or DELETE ROWS option")));
@ -1494,7 +1501,9 @@ Oid DefineRelation(CreateStmt* stmt, char relkind, Oid ownerId)
* code. This is needed because calling code might not expect untrusted
* tables to appear in pg_temp at the front of its search path.
*/
if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP && InSecurityRestrictedOperation())
if ((stmt->relation->relpersistence == RELPERSISTENCE_TEMP ||
stmt->relation->relpersistence == RELPERSISTENCE_GLOBAL_TEMP) &&
InSecurityRestrictedOperation())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("cannot create temporary table within security-restricted operation")));
@ -1567,6 +1576,40 @@ Oid DefineRelation(CreateStmt* stmt, char relkind, Oid ownerId)
/*
* Parse and validate reloptions, if any.
*/
/* global temp table */
OnCommitAction oncommitAction = GttOncommitOption(stmt->options);
if (stmt->relation->relpersistence == RELPERSISTENCE_GLOBAL_TEMP &&
relkind == RELKIND_RELATION) {
if (oncommitAction != ONCOMMIT_NOOP) {
if (stmt->oncommit != ONCOMMIT_NOOP) {
elog(ERROR, "could not create global temporary table with on commit and with clause at same time");
}
stmt->oncommit = oncommitAction;
} else {
DefElem *opt = makeNode(DefElem);
opt->type = T_DefElem;
opt->defnamespace = NULL;
opt->defname = "on_commit_delete_rows";
opt->defaction = DEFELEM_UNSPEC;
/* use reloptions to remember on commit clause */
if (stmt->oncommit == ONCOMMIT_DELETE_ROWS) {
opt->arg = reinterpret_cast<Node *>(makeString("true"));
} else if (stmt->oncommit == ONCOMMIT_PRESERVE_ROWS) {
opt->arg = reinterpret_cast<Node *>(makeString("false"));
} else if (stmt->oncommit == ONCOMMIT_NOOP) {
opt->arg = reinterpret_cast<Node *>(makeString("false"));
} else {
elog(ERROR, "global temp table not support on commit drop clause");
}
stmt->options = lappend(stmt->options, opt);
}
} else if (oncommitAction != ONCOMMIT_NOOP) {
elog(ERROR, "The parameter on_commit_delete_rows is exclusive to the global temp table, which cannot be "
"specified by a regular table");
}
reloptions = transformRelOptions((Datum)0, stmt->options, NULL, validnsps, true, false);
orientedFrom = (Node*)makeString(ORIENTATION_ROW); /* default is ORIENTATION_ROW */
@ -1850,7 +1893,7 @@ Oid DefineRelation(CreateStmt* stmt, char relkind, Oid ownerId)
Assert((createbucket == true && bucketinfo->bucketlist != NULL && bucketinfo->bucketcol != NULL) ||
(createbucket == false && bucketinfo->bucketlist == NULL && bucketinfo->bucketcol != NULL));
}
} else {
} else {
/* here is normal mode */
/* check if the table can be hash partition */
if (!IS_SINGLE_NODE && !IsInitdb && (relkind == RELKIND_RELATION) && !IsSystemNamespace(namespaceId) &&
@ -2345,10 +2388,10 @@ void RemoveRelations(DropStmt* drop, StringInfo tmp_queryString, RemoteQueryExec
LOCKMODE lockmode = AccessExclusiveLock;
bool cn_miss_relation = false;
StringInfo relation_namelist = makeStringInfo();
char relPersistence;
/* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
if (drop->concurrent) {
flags |= PERFORM_DELETION_CONCURRENTLY;
lockmode = ShareUpdateExclusiveLock;
Assert(drop->removeType == OBJECT_INDEX);
if (list_length(drop->objects) != 1)
@ -2467,7 +2510,13 @@ void RemoveRelations(DropStmt* drop, StringInfo tmp_queryString, RemoteQueryExec
if (delrel != NULL) {
relation_close(delrel, NoLock);
}
relPersistence = get_rel_persistence(relOid);
if (drop->concurrent &&
!(relPersistence == RELPERSISTENCE_TEMP || relPersistence == RELPERSISTENCE_GLOBAL_TEMP)) {
Assert(list_length(drop->objects) == 1 && drop->removeType == OBJECT_INDEX);
flags |= PERFORM_DELETION_CONCURRENTLY;
}
/* OK, we're ready to delete this one */
obj.classId = RelationRelationId;
obj.objectId = relOid;
@ -3054,6 +3103,10 @@ void ExecuteTruncate(TruncateStmt* stmt)
*/
CheckTableForSerializableConflictIn(rel);
if (RELATION_IS_GLOBAL_TEMP(rel) && !gtt_storage_attached(RelationGetRelid(rel))) {
continue;
}
if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE && isMOTFromTblOid(RelationGetRelid(rel))) {
FdwRoutine* fdwroutine = GetFdwRoutineByRelId(RelationGetRelid(rel));
if (fdwroutine->TruncateForeignTable != NULL) {
@ -4554,7 +4607,6 @@ void RenameRelationInternal(Oid myrelid, const char* newrelname)
*/
if (targetrelation->rd_rel->relkind == RELKIND_INDEX) {
Oid constraintId = get_index_constraint(myrelid);
if (OidIsValid(constraintId))
RenameConstraintById(constraintId, newrelname);
}
@ -5275,6 +5327,17 @@ void AlterTable(Oid relid, LOCKMODE lockmode, AlterTableStmt* stmt)
/* Caller is required to provide an adequate lock. */
rel = relation_open(relid, lockmode);
/* We allow to alter global temp table only this session use it */
if (RELATION_IS_GLOBAL_TEMP(rel)) {
if (is_other_backend_use_gtt(RelationGetRelid(rel))) {
ereport(
ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("can not alter table %s when other backend attached this global temp table",
RelationGetRelationName(rel))));
}
}
CheckTableNotInUse(rel, "ALTER TABLE");
/*
@ -6598,6 +6661,28 @@ static void ATRewriteTables(List** wqueue, LOCKMODE lockmode)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot rewrite temporary tables of other sessions")));
if (RELATION_IS_GLOBAL_TEMP(OldHeap)) {
/* gtt may not attached, create it */
if (!gtt_storage_attached(tab->relid)) {
ResultRelInfo *resultRelInfo;
MemoryContext oldcontext;
MemoryContext ctx_alter_gtt;
ctx_alter_gtt =
AllocSetContextCreate(CurrentMemoryContext, "gtt alter table", ALLOCSET_DEFAULT_SIZES);
oldcontext = MemoryContextSwitchTo(ctx_alter_gtt);
resultRelInfo = makeNode(ResultRelInfo);
InitResultRelInfo(resultRelInfo, OldHeap, 1, 0);
if (resultRelInfo->ri_RelationDesc->rd_rel->relhasindex &&
resultRelInfo->ri_IndexRelationDescs == NULL)
ExecOpenIndices(resultRelInfo);
init_gtt_storage(CMD_UTILITY, resultRelInfo);
ExecCloseIndices(resultRelInfo);
(void)MemoryContextSwitchTo(oldcontext);
MemoryContextDelete(ctx_alter_gtt);
}
}
/*
* Select destination tablespace (same as original unless user
* requested a change)
@ -8248,15 +8333,16 @@ static void ATExecAddStatistics(Relation rel, Node* def, LOCKMODE lockmode)
VacAttrStats** vacattrstats_array = es_build_vacattrstats_array(rel, (List*)def, true, &array_length, inh);
if (array_length > 0) {
update_attstats(relid, relkind, false, array_length, vacattrstats_array);
update_attstats(relid, relkind, false, array_length, vacattrstats_array, RelationGetRelPersistence(rel));
if (RelationIsDfsStore(rel)) {
/* HDFS complex table */
update_attstats(relid, relkind, true, array_length, vacattrstats_array);
update_attstats(relid, relkind, true, array_length, vacattrstats_array, RelationGetRelPersistence(rel));
/* HDFS delta table */
Oid delta_relid = rel->rd_rel->reldeltarelid;
Assert(OidIsValid(delta_relid));
update_attstats(delta_relid, relkind, false, array_length, vacattrstats_array);
update_attstats(
delta_relid, relkind, false, array_length, vacattrstats_array, RelationGetRelPersistence(rel));
}
}
}
@ -9120,6 +9206,13 @@ static void ATAddForeignKeyConstraint(AlteredTableInfo* tab, Relation rel, Const
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("constraints on temporary tables must involve temporary tables of this session")));
break;
case RELPERSISTENCE_GLOBAL_TEMP:
if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_GLOBAL_TEMP) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("constraints on global temporary tables may reference only global temporary tables")));
}
break;
default:
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
@ -12198,6 +12291,12 @@ static void ATExecSetRelOptions(Relation rel, List* defList, AlterTableType oper
if (defList == NIL && operation != AT_ReplaceRelOptions)
return; /* nothing to do */
if (GttOncommitOption(defList) != ONCOMMIT_NOOP) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_OPERATION),
errmsg("table cannot add or modify on commit parameter by ALTER TABLE command.")));
}
/* forbid user to set or change inner options */
ForbidOutUsersToSetInnerOptions(defList);
@ -12617,7 +12716,7 @@ static void atexecset_table_space_internal(Relation rel, Oid newTableSpace, Oid
* NOTE: any conflict in relfilenode value will be caught in
* RelationCreateStorage function.
*/
RelationCreateStorage(newrnode, rel->rd_rel->relpersistence, rel->rd_rel->relowner, rel->rd_bucketoid);
RelationCreateStorage(newrnode, rel->rd_rel->relpersistence, rel->rd_rel->relowner, rel->rd_bucketoid, rel);
/* copy main fork */
copy_relation_data(rel, &dstrel, MAIN_FORKNUM, rel->rd_rel->relpersistence);
@ -12730,6 +12829,11 @@ static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmo
*/
rel = relation_open(tableOid, lockmode);
if (RELATION_IS_GLOBAL_TEMP(rel)) {
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("not support alter table set tablespace on global temp table.")));
}
/*
* No work if no change in tablespace.
*/
@ -15134,14 +15238,7 @@ void PreCommit_on_commit_actions(void)
/* Do nothing (there shouldn't be such entries, actually) */
break;
case ONCOMMIT_DELETE_ROWS:
/*
* If this transaction hasn't accessed any temporary
* relations, we can skip truncating ON COMMIT DELETE ROWS
* tables, as they must still be empty.
*/
if (t_thrd.xact_cxt.MyXactAccessedTempRel)
oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
break;
case ONCOMMIT_DROP: {
ObjectAddress object;
@ -21182,3 +21279,32 @@ static void at_timeseries_check(Relation rel, AlterTableCmd* cmd)
}
}
static OnCommitAction GttOncommitOption(const List *options)
{
ListCell *listptr;
OnCommitAction action = ONCOMMIT_NOOP;
foreach(listptr, options) {
DefElem *def = reinterpret_cast<DefElem *>(lfirst(listptr));
if (strcmp(def->defname, "on_commit_delete_rows") == 0) {
bool res = false;
char *sval = defGetString(def);
if (!parse_bool(sval, &res)) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("parameter \"on_commit_delete_rows\" requires a Boolean value")));
}
if (res) {
action = ONCOMMIT_DELETE_ROWS;
} else {
action = ONCOMMIT_PRESERVE_ROWS;
}
break;
}
}
return action;
}

View File

@ -39,6 +39,7 @@
#include "catalog/pg_namespace.h"
#include "catalog/pgxc_class.h"
#include "catalog/storage.h"
#include "catalog/storage_gtt.h"
#include "commands/cluster.h"
#include "commands/tablespace.h"
#include "commands/vacuum.h"
@ -975,6 +976,16 @@ void vac_update_relstats(Relation relation, Relation classRel, RelPageType num_p
bool isNull = false;
TransactionId relfrozenxid;
Datum xid64datum;
bool isGtt = false;
/* global temp table remember relstats to localhash and rel->rd_rel, not catalog */
if (RELATION_IS_GLOBAL_TEMP(relation)) {
isGtt = true;
up_gtt_relstats(relation,
static_cast<unsigned int>(num_pages), num_tuples,
num_all_visible_pages,
frozenxid);
}
/* Fetch a copy of the tuple to scribble on */
ctup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@ -989,17 +1000,23 @@ void vac_update_relstats(Relation relation, Relation classRel, RelPageType num_p
// frozenxid == BootstrapTransactionId means it was invoked by execRemote.cpp:ReceivePageAndTuple()
if (IS_PGXC_DATANODE || (frozenxid == BootstrapTransactionId) || IsSystemRelation(relation)) {
#endif
if (pgcform->relpages - num_pages != 0) {
pgcform->relpages = num_pages;
dirty = true;
}
if (pgcform->reltuples - num_tuples != 0) {
pgcform->reltuples = num_tuples;
dirty = true;
}
if (pgcform->relallvisible != (int32)num_all_visible_pages) {
pgcform->relallvisible = (int32)num_all_visible_pages;
dirty = true;
if (isGtt) {
relation->rd_rel->relpages = (int32) num_pages;
relation->rd_rel->reltuples = (float4) num_tuples;
relation->rd_rel->relallvisible = (int32) num_all_visible_pages;
} else {
if (pgcform->relpages - num_pages != 0) {
pgcform->relpages = num_pages;
dirty = true;
}
if (pgcform->reltuples - num_tuples != 0) {
pgcform->reltuples = num_tuples;
dirty = true;
}
if (pgcform->relallvisible != (int32)num_all_visible_pages) {
pgcform->relallvisible = (int32)num_all_visible_pages;
dirty = true;
}
}
#ifdef PGXC
}
@ -1144,6 +1161,11 @@ void vac_update_datfrozenxid(void)
if (classForm->relkind != RELKIND_RELATION && classForm->relkind != RELKIND_TOASTVALUE)
continue;
/* global temp table relstats not in pg_class */
if (classForm->relpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
continue;
}
xid64datum = heap_getattr(classTup, Anum_pg_class_relfrozenxid64, RelationGetDescr(relation), &isNull);
if (isNull) {
@ -1198,6 +1220,40 @@ void vac_update_datfrozenxid(void)
}
Assert(TransactionIdIsNormal(newFrozenXid));
/*
* Global temp table get frozenxid from MyProc
* to avoid the vacuum truncate clog that gtt need.
*/
if (u_sess->attr.attr_storage.max_active_gtt > 0) {
TransactionId safeAge;
TransactionId oldestGttFrozenxid = list_all_session_gtt_frozenxids(0, NULL, NULL, NULL);
if (TransactionIdIsNormal(oldestGttFrozenxid)) {
safeAge =
oldestGttFrozenxid + static_cast<TransactionId>(u_sess->attr.attr_storage.vacuum_gtt_defer_check_age);
if (safeAge < FirstNormalTransactionId) {
safeAge += FirstNormalTransactionId;
}
/*
* We tolerate that the minimum age of gtt is less than
* the minimum age of conventional tables, otherwise it will
* throw warning message.
*/
if (TransactionIdIsNormal(safeAge) &&
TransactionIdPrecedes(safeAge, newFrozenXid)) {
ereport(WARNING,
(errmsg(
"global temp table oldest relfrozenxid %lu is the oldest in the entire db", oldestGttFrozenxid),
errdetail("The oldest relfrozenxid in pg_class is %lu", newFrozenXid),
errhint("If they differ greatly, please consider cleaning up the data in global temp table.")));
}
if (TransactionIdPrecedes(oldestGttFrozenxid, newFrozenXid)) {
newFrozenXid = oldestGttFrozenxid;
}
}
}
/* Now fetch the pg_database tuple we need to update. */
relation = heap_open(DatabaseRelationId, RowExclusiveLock);
@ -1791,6 +1847,13 @@ static bool vacuum_rel(Oid relid, VacuumStmt* vacstmt, bool do_toast)
return false;
}
if (RELATION_IS_GLOBAL_TEMP(onerel) &&
!gtt_storage_attached(RelationGetRelid(onerel))) {
CloseAllRelationsBeforeReturnFalse();
proc_snapshot_and_transaction();
return false;
}
/*
* Get a session-level lock too. This will protect our access to the
* relation across multiple transactions, so that we can vacuum the
@ -2263,9 +2326,7 @@ void vac_open_part_indexes(
Assert(vacstmt->onepartrel != NULL);
indexoidlist = PartitionGetPartIndexList(vacstmt->onepart);
i = list_length(indexoidlist);
if (i > 0) {
*Irel = (Relation*)palloc((long)(i) * sizeof(Relation));
*indexrel = (Relation*)palloc((long)(i) * sizeof(Relation));

View File

@ -49,6 +49,7 @@
#include "catalog/catalog.h"
#include "catalog/storage.h"
#include "catalog/pg_hashbucket_fn.h"
#include "catalog/storage_gtt.h"
#include "commands/dbcommands.h"
#include "commands/vacuum.h"
#include "miscadmin.h"

View File

@ -475,6 +475,12 @@ void DefineView(ViewStmt* stmt, const char* queryString, bool isFirstNode)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), errmsg("views cannot be unlogged because they do not have storage")));
if (stmt->view->relpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("views cannot be global temp because they do not have storage")));
}
/*
* If the user didn't explicitly ask for a temporary view, check whether
* we need one implicitly. We allow TEMP to be inserted automatically as

View File

@ -27,6 +27,7 @@
#include "catalog/pg_partition_fn.h"
#include "catalog/pg_statistic.h"
#include "catalog/heap.h"
#include "catalog/storage_gtt.h"
#include "commands/dbcommands.h"
#include "executor/nodeModifyTable.h"
#include "foreign/fdwapi.h"
@ -232,6 +233,12 @@ void get_relation_info(PlannerInfo* root, Oid relationObjectId, bool inhparent,
continue;
}
/* Ignore empty index for global temp table */
if (RELATION_IS_GLOBAL_TEMP(indexRelation) &&
!gtt_storage_attached(RelationGetRelid(indexRelation))) {
index_close(indexRelation, NoLock);
continue;
}
/*
* If the index is valid, but cannot yet be used, ignore it; but
* mark the plan we are generating as transient. See

View File

@ -2170,8 +2170,10 @@ static void do_autovacuum(void)
bool enable_vacuum = false;
/* We cannot safely process other backends' temp tables, so skip 'em. */
if (RELPERSISTENCE_TEMP == classForm->relpersistence)
if (classForm->relpersistence == RELPERSISTENCE_TEMP ||
classForm->relpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
continue;
}
/* Fetch reloptions for this table */
relopts = extract_autovac_opts(tuple, pg_class_desc);
@ -2414,7 +2416,8 @@ static void do_autovacuum(void)
av_toastid_mainid* at_entry = NULL;
/* We cannot safely process other backends' temp tables, so skip 'em. */
if (classForm->relpersistence == RELPERSISTENCE_TEMP)
if (classForm->relpersistence == RELPERSISTENCE_TEMP ||
classForm->relpersistence == RELPERSISTENCE_GLOBAL_TEMP)
continue;
at_entry = (av_toastid_mainid*)hash_search(toast_table_map, &(relid), HASH_FIND, &found);

View File

@ -1045,6 +1045,11 @@ void ExecCheckXactReadOnly(PlannedStmt *plannedstmt)
if (isTempNamespace(get_rel_namespace(rte->relid))) {
continue;
}
if (get_rel_persistence(rte->relid) == RELPERSISTENCE_GLOBAL_TEMP) {
continue;
}
if (rte->relid == PgxcNodeRelationId && g_instance.attr.attr_storage.IsRoachStandbyCluster &&
u_sess->attr.attr_common.xc_maintenance_mode) {
continue;

View File

@ -43,6 +43,7 @@
#include "catalog/heap.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_partition_fn.h"
#include "catalog/storage_gtt.h"
#include "commands/defrem.h"
#include "commands/tablecmds.h"
#ifdef PGXC
@ -2161,7 +2162,7 @@ ModifyTableState* ExecInitModifyTable(ModifyTable* node, EState* estate, int efl
result_rel_info->ri_FdwRoutine->GetFdwType() != MOT_ORC)
ExecOpenIndices(result_rel_info);
}
init_gtt_storage(operation, result_rel_info);
/* Now init the plan for this result rel */
estate->es_result_relation_info = result_rel_info;
mt_state->mt_plans[i] = ExecInitNode(sub_plan, estate, eflags);

View File

@ -29,6 +29,7 @@
#include "access/printtup.h"
#include "access/transam.h"
#include "catalog/pg_aggregate.h"
#include "catalog/storage_gtt.h"
#include "commands/copy.h"
#include "executor/nodeIndexscan.h"
#include "gstrace/executer_gstrace.h"
@ -1099,7 +1100,7 @@ bool InsertFusion::execute(long max_rows, char* completionTag)
CommandId mycid = GetCurrentCommandId(true);
refreshParameterIfNecessary();
init_gtt_storage(CMD_INSERT, result_rel_info);
/************************
* step 2: begin insert *
************************/

View File

@ -85,6 +85,7 @@ static relopt_bool boolRelOpts[] = {
{{"multi_zall", "segmente all word from long words in zhparser text search praser", RELOPT_KIND_ZHPARSER}, false},
{{"ignore_enable_hadoop_env", "ignore enable_hadoop_env option", RELOPT_KIND_HEAP}, false},
{{"hashbucket", "Enables hashbucket in this relation", RELOPT_KIND_HEAP}, false},
{{"on_commit_delete_rows", "global temp table on commit options", RELOPT_KIND_HEAP}, true},
/* list terminator */
{{NULL}}};
@ -1490,7 +1491,8 @@ bytea* default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
{"start_ctid_internal", RELOPT_TYPE_STRING, offsetof(StdRdOptions, start_ctid_internal)},
{"end_ctid_internal", RELOPT_TYPE_STRING, offsetof(StdRdOptions, end_ctid_internal)},
{"user_catalog_table", RELOPT_TYPE_BOOL, offsetof(StdRdOptions, user_catalog_table)},
{"hashbucket", RELOPT_TYPE_BOOL, offsetof(StdRdOptions, hashbucket)}};
{"hashbucket", RELOPT_TYPE_BOOL, offsetof(StdRdOptions, hashbucket)},
{"on_commit_delete_rows", RELOPT_TYPE_BOOL, offsetof(StdRdOptions, on_commit_delete_rows)}};
options = parseRelOptions(reloptions, validate, kind, &numoptions);

View File

@ -228,6 +228,17 @@ Datum btinsert(PG_FUNCTION_ARGS)
bool result = false;
IndexTuple itup;
/* skip inserting if global temp table index does not exist */
if (RELATION_IS_GLOBAL_TEMP(rel)) {
if (rel->rd_smgr == NULL) {
/* Open it at the smgr level if not already done */
RelationOpenSmgr(rel);
}
if (!smgrexists(rel->rd_smgr, MAIN_FORKNUM)) {
PG_RETURN_BOOL(result);
}
}
/* generate an index tuple */
itup = index_form_tuple(RelationGetDescr(rel), values, isnull);
itup->t_tid = *ht_ctid;

View File

@ -503,6 +503,25 @@ static void MultiXactIdSetOldestVisible(void)
}
}
/*
* ReadNextMultiXactId
* Return the next MultiXactId to be assigned, but don't allocate it
*/
MultiXactId ReadNextMultiXactId(void)
{
MultiXactId mxid;
/* XXX we could presumably do this without a lock. */
LWLockAcquire(MultiXactGenLock, LW_SHARED);
mxid = t_thrd.shemem_ptr_cxt.MultiXactState->nextMXact;
LWLockRelease(MultiXactGenLock);
if (mxid < FirstMultiXactId)
mxid = FirstMultiXactId;
return mxid;
}
/*
* MultiXactIdWait
* Sleep on a MultiXactId.

View File

@ -7958,6 +7958,11 @@ void StartupXLOG(void)
*/
t_thrd.xlog_cxt.recoveryTargetTLI = t_thrd.shemem_ptr_cxt.ControlFile->checkPointCopy.ThisTimeLineID;
/* clean temp relation files */
if (u_sess->attr.attr_storage.max_active_gtt > 0) {
RemovePgTempFiles();
}
// Check for recovery control file, and if so set up state for offline recovery
readRecoveryCommandFile();

View File

@ -44,6 +44,7 @@
#include "catalog/catalog.h"
#include "catalog/dfsstore_ctlg.h"
#include "catalog/pg_hashbucket_fn.h"
#include "catalog/storage_gtt.h"
#include "commands/tablespace.h"
#include "executor/instrument.h"
#include "lib/binaryheap.h"
@ -4197,6 +4198,14 @@ void FlushBuffer(void* buf, SMgrRelation reln, ReadBufferMethod flushmethod)
BlockNumber RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber fork_num)
{
BlockNumber result = 0;
/*
* When this backend not init gtt storage
* return 0
*/
if (RELATION_IS_GLOBAL_TEMP(relation) &&
!gtt_storage_attached(RelationGetRelid(relation))) {
return result;
}
// Just return the relpages in pg_class for column-store relation.
// Future: new interface should be implemented to calculate the number of blocks.

View File

@ -3135,13 +3135,20 @@ void RemovePgTempFiles(void)
if (strcmp(spc_de->d_name, ".") == 0 || strcmp(spc_de->d_name, "..") == 0)
continue;
/*
* subDir returned by ReadDir will be overwritten by the next invoking.
* therefore, the result needs to be saved.
*/
char curSubDir[MAXPGPATH] = {0};
strncpy_s(curSubDir, MAXPGPATH, spc_de->d_name, strlen(spc_de->d_name));
securec_check_ss(rc, "", "");
#ifdef PGXC
/* Postgres-XC tablespaces include node name in path */
rc = snprintf_s(temp_path,
sizeof(temp_path),
sizeof(temp_path) - 1,
"pg_tblspc/%s/%s_%s/%s",
spc_de->d_name,
curSubDir,
TABLESPACE_VERSION_DIRECTORY,
g_instance.attr.attr_common.PGXCNodeName,
PG_TEMP_FILES_DIR);
@ -3151,7 +3158,7 @@ void RemovePgTempFiles(void)
sizeof(temp_path),
sizeof(temp_path) - 1,
"pg_tblspc/%s/%s/%s",
spc_de->d_name,
curSubDir,
TABLESPACE_VERSION_DIRECTORY,
PG_TEMP_FILES_DIR);
securec_check_ss(rc, "", "");
@ -3164,7 +3171,7 @@ void RemovePgTempFiles(void)
sizeof(temp_path),
sizeof(temp_path) - 1,
"pg_tblspc/%s/%s_%s",
spc_de->d_name,
curSubDir,
TABLESPACE_VERSION_DIRECTORY,
g_instance.attr.attr_common.PGXCNodeName);
securec_check_ss(rc, "", "");
@ -3173,7 +3180,7 @@ void RemovePgTempFiles(void)
sizeof(temp_path),
sizeof(temp_path) - 1,
"pg_tblspc/%s/%s",
spc_de->d_name,
curSubDir,
TABLESPACE_VERSION_DIRECTORY);
securec_check_ss(rc, "", "");
#endif

View File

@ -481,6 +481,23 @@ void shmem_exit(int code)
t_thrd.storage_cxt.on_shmem_exit_index = 0;
}
/* ----------------------------------------------------------------
* atexit_callback
*
* Backstop to ensure that direct calls of exit() don't mess us up.
*
* Somebody who was being really uncooperative could call _exit(),
* but for that case we have a "dead man switch" that will make the
* postmaster treat it as a crash --- see pmsignal.c.
* ----------------------------------------------------------------
*/
static void atexit_callback(void)
{
/* Clean up everything that must be cleaned up */
/* ... too bad we don't know the real exit code ... */
proc_exit_prepare(-1);
}
/* ----------------------------------------------------------------
* on_proc_exit
*
@ -503,6 +520,32 @@ void on_proc_exit(pg_on_exit_callback function, Datum arg)
}
}
/* ----------------------------------------------------------------
* before_shmem_exit
*
* Register early callback to perform user-level cleanup,
* e.g. transaction abort, before we begin shutting down
* low-level subsystems.
* ----------------------------------------------------------------
*/
void before_shmem_exit(pg_on_exit_callback function, Datum arg)
{
if (t_thrd.storage_cxt.before_shmem_exit_index >= MAX_ON_EXITS)
ereport(FATAL,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg_internal("out of before_shmem_exit slots")));
t_thrd.storage_cxt.before_shmem_exit_list[t_thrd.storage_cxt.before_shmem_exit_index].function = function;
t_thrd.storage_cxt.before_shmem_exit_list[t_thrd.storage_cxt.before_shmem_exit_index].arg = arg;
++t_thrd.storage_cxt.before_shmem_exit_index;
if (!t_thrd.storage_cxt.atexit_callback_setup) {
(void)atexit(atexit_callback);
t_thrd.storage_cxt.atexit_callback_setup = true;
}
}
/* ----------------------------------------------------------------
* on_shmem_exit
*

View File

@ -26,6 +26,7 @@
#include "access/subtrans.h"
#include "access/twophase.h"
#include "access/double_write.h"
#include "catalog/storage_gtt.h"
#include "commands/tablespace.h"
#include "commands/async.h"
#include "foreign/dummyserver.h"
@ -161,6 +162,7 @@ void CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
size = add_size(size, BTreeShmemSize());
size = add_size(size, SyncScanShmemSize());
size = add_size(size, AsyncShmemSize());
size = add_size(size, active_gtt_shared_hash_size());
#ifdef PGXC
size = add_size(size, NodeTablesShmemSize());
#endif
@ -243,6 +245,8 @@ void CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
CSNLOGShmemInit();
MultiXactShmemInit();
InitBufferPool();
/* global temporay table */
active_gtt_shared_hash_init();
/*
* Set up lock manager
*/

View File

@ -4523,3 +4523,70 @@ char* transfer_snapshot_type(SnapshotType snap_type)
}
return "UnKnown";
}
/*
* search all active backend to get oldest frozenxid
* for global temp table.
*/
TransactionId list_all_session_gtt_frozenxids(int max_size, ThreadId *pids, TransactionId *xids, int *n)
{
ProcArrayStruct *arrayP = g_instance.proc_array_idx;
TransactionId result = InvalidTransactionId;
int index;
int flags = 0;
int i = 0;
if (u_sess->attr.attr_storage.max_active_gtt <= 0)
return 0;
if (max_size > 0) {
Assert(pids);
Assert(xids);
Assert(n);
*n = 0;
}
if (u_sess->attr.attr_storage.max_active_gtt <= 0)
return InvalidTransactionId;
if (RecoveryInProgress())
return InvalidTransactionId;
flags |= PROC_IS_AUTOVACUUM;
flags |= PROC_IN_LOGICAL_DECODING;
LWLockAcquire(ProcArrayLock, LW_SHARED);
if (max_size > 0 && max_size < arrayP->numProcs) {
LWLockRelease(ProcArrayLock);
elog(ERROR, "list_all_gtt_frozenxids require more array");
}
for (index = 0; index < arrayP->numProcs; index++) {
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = g_instance.proc_base_all_procs[pgprocno];
volatile PGXACT *pgxact = &g_instance.proc_base_all_xacts[pgprocno];
if (pgxact->vacuumFlags & flags)
continue;
if (proc->databaseId == u_sess->proc_cxt.MyDatabaseId &&
TransactionIdIsNormal(proc->session_gtt_frozenxid)) {
if (result == InvalidTransactionId)
result = proc->session_gtt_frozenxid;
else if (TransactionIdPrecedes(proc->session_gtt_frozenxid, result))
result = proc->session_gtt_frozenxid;
if (max_size > 0) {
pids[i] = proc->pid;
xids[i] = proc->session_gtt_frozenxid;
i++;
}
}
}
LWLockRelease(ProcArrayLock);
if (max_size > 0) {
*n = i;
}
return result;
}

View File

@ -153,7 +153,9 @@ static const char *BuiltinTrancheNames[] = {
"DoubleWriteLock",
"BufFreeListLock",
"LWTRANCHE_ACCOUNT_TABLE",
"GeneralExtendedLock"
"GeneralExtendedLock",
/* LWTRANCHE_GTT_CTL */
"GlobalTempTableControl"
};
static void RegisterLWLockTranches(void);

View File

@ -573,6 +573,7 @@ void InitProcess(void)
t_thrd.proc->backendId = InvalidBackendId;
t_thrd.proc->databaseId = InvalidOid;
t_thrd.proc->roleId = InvalidOid;
t_thrd.proc->session_gtt_frozenxid = InvalidTransactionId; /* init session level gtt frozenxid */
/* For backends, upgrade status is either passed down from remote backends or inherit from PM */
t_thrd.proc->workingVersionNum = (u_sess->proc_cxt.MyProcPort ? u_sess->proc_cxt.MyProcPort->SessionVersionNum
: pg_atomic_read_u32(&WorkingGrandVersionNum));
@ -786,6 +787,7 @@ void InitAuxiliaryProcess(void)
t_thrd.proc->backendId = InvalidBackendId;
t_thrd.proc->databaseId = InvalidOid;
t_thrd.proc->roleId = InvalidOid;
t_thrd.proc->session_gtt_frozenxid = InvalidTransactionId; /* init session level gtt frozenxid */
t_thrd.pgxact->delayChkpt = false;
t_thrd.pgxact->vacuumFlags = 0;
t_thrd.proc->lwWaiting = false;

View File

@ -590,6 +590,9 @@ static MdfdVec* mdopen(SMgrRelation reln, ForkNumber forknum, ExtensionBehavior
*/
void mdclose(SMgrRelation reln, ForkNumber forknum)
{
if (reln->md_fd == NULL) {
return;
}
MdfdVec* v = reln->md_fd[forknum];
/* No work if already closed */

View File

@ -285,6 +285,9 @@ void smgrclearowner(SMgrRelation* owner, SMgrRelation reln)
*/
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
{
if (reln == NULL) {
return false;
}
return (*(g_smgrsw[reln->smgr_which].smgr_exists))(reln, forknum);
}
@ -296,6 +299,10 @@ void smgrclose(SMgrRelation reln)
SMgrRelation* owner = NULL;
int forknum;
if (reln == NULL) {
return;
}
for (forknum = 0; forknum < (int)(reln->md_fdarray_size); forknum++) {
(*(g_smgrsw[reln->smgr_which].smgr_close))(reln, (ForkNumber)forknum);
}

View File

@ -50,6 +50,7 @@ extern MultiXactId MultiXactIdCreate(TransactionId xid1, TransactionId xid2);
extern MultiXactId MultiXactIdExpand(MultiXactId multi, TransactionId xid);
extern bool MultiXactIdIsRunning(MultiXactId multi);
extern bool MultiXactIdIsCurrent(MultiXactId multi);
extern MultiXactId ReadNextMultiXactId(void);
extern void MultiXactIdWait(MultiXactId multi, bool allow_con_update = false);
extern bool ConditionalMultiXactIdWait(MultiXactId multi);
extern void MultiXactIdSetOldestMember(void);

View File

@ -47,7 +47,8 @@ typedef struct HashBucketInfo {
extern Relation heap_create(const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, Oid relfilenode,
Oid bucketOid, TupleDesc tupDesc, char relkind, char relpersistence, bool partitioned_relation, bool rowMovement,
bool shared_relation, bool mapped_relation, bool allow_system_table_mods, int8 row_compress, Oid ownerid);
bool shared_relation, bool mapped_relation, bool allow_system_table_mods, int8 row_compress, Oid ownerid,
bool skip_create_storage);
extern Partition heapCreatePartition(const char* part_name, bool for_partitioned_table, Oid part_tablespace, Oid part_id,
Oid partFileNode, Oid bucketOid, Oid ownerid);

View File

@ -72,6 +72,7 @@ extern void index_constraint_create(Relation heapRelation, Oid indexRelationId,
extern void index_drop(Oid indexId, bool concurrent);
extern IndexInfo *BuildIndexInfo(Relation index);
extern IndexInfo *BuildDummyIndexInfo(Relation index);
extern void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull);
extern void index_build(Relation heapRelation, Partition heapPartition, Relation indexRelation,
@ -94,7 +95,9 @@ extern void reindex_indexpart_internal(Relation heapRelation,
Relation iRel,
IndexInfo* indexInfo,
Oid indexPartId);
extern void reindex_index(Oid indexId, Oid indexPartId, bool skip_constraint_checks, AdaptMem *memInfo, bool dbWide);
extern void reindex_index(Oid indexId, Oid indexPartId,
bool skip_constraint_checks, AdaptMem *memInfo,
bool dbWide, char persistence);
/* Flag bits for reindex_relation(): */
#define REINDEX_REL_PROCESS_TOAST 0x01

View File

@ -174,6 +174,7 @@ DESCR("");
#define RELPERSISTENCE_PERMANENT 'p' /* regular table */
#define RELPERSISTENCE_UNLOGGED 'u' /* unlogged permanent table */
#define RELPERSISTENCE_TEMP 't' /* temporary table */
#define RELPERSISTENCE_GLOBAL_TEMP 'g' /* global temporary table */
/* default selection for replica identity (primary key or nothing) */
#define REPLICA_IDENTITY_DEFAULT 'd'
@ -181,6 +182,18 @@ DESCR("");
#define REPLICA_IDENTITY_NOTHING 'n'
/* all columns are loged as replica identity */
#define REPLICA_IDENTITY_FULL 'f'
/*
* Relation kinds that have physical storage. These relations normally have
* relfilenode set to non-zero, but it can also be zero if the relation is
* mapped.
*/
#define RELKIND_HAS_STORAGE(relkind) \
((relkind) == RELKIND_RELATION || \
(relkind) == RELKIND_INDEX || \
(relkind) == RELKIND_SEQUENCE || \
(relkind) == RELKIND_TOASTVALUE)
/*
* an explicitly chosen candidate key's columns are used as identity;
* will still be set if the index has been dropped, in that case it

View File

@ -25,7 +25,8 @@
#define DFS_STOR_FLAG -1
extern void RelationCreateStorage(RelFileNode rnode, char relpersistence, Oid ownerid, Oid bucketOid = InvalidOid);
extern void RelationCreateStorage(RelFileNode rnode, char relpersistence, Oid ownerid, Oid bucketOid = InvalidOid,
Relation rel = NULL);
extern void RelationDropStorage(Relation rel, bool isDfsTruncate = false);
extern void RelationPreserveStorage(RelFileNode rnode, bool atCommit);
extern void RelationTruncate(Relation rel, BlockNumber nblocks);
@ -57,7 +58,8 @@ extern void ColMainFileNodesCreate(void);
extern void ColMainFileNodesDestroy(void);
extern void ColMainFileNodesAppend(RelFileNode* bcmFileNode, BackendId backend);
extern void ColumnRelationDoDeleteFiles(RelFileNode* bcmFileNode, ForkNumber forknum, BackendId backend, Oid ownerid);
extern void RowRelationDoDeleteFiles(RelFileNode rnode, BackendId backend, Oid ownerid);
extern void RowRelationDoDeleteFiles(RelFileNode rnode, BackendId backend, Oid ownerid, Oid relOid = InvalidOid,
bool isCommit = false);
extern uint64 GetSMgrRelSize(RelFileNode* relfilenode, BackendId backend, ForkNumber forkNum);
/*

View File

@ -0,0 +1,47 @@
/* -------------------------------------------------------------------------
*
* storage_gtt.h
* prototypes for functions in backend/catalog/storage_gtt.c
*
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 2010-2012 Postgres-XC Development Group
*
* src/include/catalog/storage_gtt.h
*
* -------------------------------------------------------------------------
*/
#ifndef STORAGE_GTT_H
#define STORAGE_GTT_H
#include "access/htup.h"
#include "storage/block.h"
#include "storage/relfilenode.h"
#include "nodes/execnodes.h"
#include "utils/relcache.h"
extern Size active_gtt_shared_hash_size(void);
extern void active_gtt_shared_hash_init(void);
extern void remember_gtt_storage_info(const RelFileNode rnode, Relation rel);
extern void forget_gtt_storage_info(Oid relid, const RelFileNode relfilenode, bool isCommit);
extern bool is_other_backend_use_gtt(Oid relid);
extern bool gtt_storage_attached(Oid relid);
extern Bitmapset *copy_active_gtt_bitmap(Oid relid);
extern void up_gtt_att_statistic(
Oid reloid, int attnum, int natts, TupleDesc tupleDescriptor, Datum* values, bool* isnull);
extern HeapTuple get_gtt_att_statistic(Oid reloid, int attnum);
extern void release_gtt_statistic_cache(HeapTuple tup);
extern void up_gtt_relstats(const Relation relation,
BlockNumber numPages,
double numTuples,
BlockNumber numAllVisiblePages,
TransactionId relfrozenxid);
extern bool get_gtt_relstats(
Oid relid, BlockNumber* relpages, double* reltuples, BlockNumber* relallvisible, TransactionId* relfrozenxid);
extern void gtt_force_enable_index(Relation index);
extern void gtt_fix_index_state(Relation index);
extern void init_gtt_storage(CmdType operation, ResultRelInfo *resultRelInfo);
extern Oid gtt_fetch_current_relfilenode(Oid relid);
extern void gtt_switch_rel_relfilenode(Oid rel1, Oid relfilenode1, Oid rel2, Oid relfilenode2, bool footprint);
#endif /* STORAGE_GTT_H */

View File

@ -36,7 +36,8 @@ extern void finishPartitionHeapSwap(Oid partitionOid, Oid tempTableOid, bool swa
TransactionId frozenXid, bool tempTableIsPartition = false);
extern void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, bool is_system_catalog, bool swap_toast_by_content,
bool check_constraints, TransactionId frozenXid, AdaptMem* memInfo = NULL);
bool check_constraints, TransactionId frozenXid, AdaptMem* memInfo = NULL,
char newrelpersistence = RELPERSISTENCE_PERMANENT);
extern void vacuumFullPart(Oid partOid, VacuumStmt* vacstmt, int freeze_min_age, int freeze_table_age);
extern void updateRelationName(Oid relOid, bool isPartition, const char* relNewName);

View File

@ -363,7 +363,8 @@ extern char* buildTempSampleTable(Oid relid, Oid mian_relid, TempSmpleTblType ty
extern void dropSampleTable(const char* tableName);
extern const char* get_sample_tblname(AnalyzeMode analyzemode, List* tmpSampleTblNameList);
extern VacAttrStats* examine_attribute(Relation onerel, Bitmapset* bms_attnums, bool isLog);
extern void update_attstats(Oid relid, char relkind, bool inh, int natts, VacAttrStats** vacattrstats);
extern void update_attstats(
Oid relid, char relkind, bool inh, int natts, VacAttrStats** vacattrstats, char relpersistence);
/* we should delete all records in pg_statistic when the data is dirty and current totalrows is null. */
extern void delete_attstats(Oid relid, char relkind, bool inh, int natts, VacAttrStats** vacattrstats,
unsigned int delete_stats_option = DELETE_STATS_SINGLE);

View File

@ -176,6 +176,10 @@ typedef struct knl_session_attr_storage {
*/
bool enable_xlog_prune;
int defer_csn_cleanup_time;
/* for GTT */
int max_active_gtt;
int vacuum_gtt_defer_check_age;
} knl_session_attr_storage;
#endif /* SRC_INCLUDE_KNL_KNL_SESSION_ATTR_STORAGE */

View File

@ -841,6 +841,10 @@ typedef struct knl_t_shemem_ptr_context {
* where we have special measures to pass it down).
*/
union LWLockPadded *mainLWLockArray;
// for GTT table to track sessions and their usage of GTTs
struct gtt_ctl_data* gtt_shared_ctl;
struct HTAB* active_gtt_shared_hash;
} knl_t_shemem_ptr_context;
typedef struct knl_t_cstore_context {
@ -2425,8 +2429,10 @@ typedef struct knl_t_storage_context {
bool atexit_callback_setup;
ONEXIT on_proc_exit_list[MAX_ON_EXITS];
ONEXIT on_shmem_exit_list[MAX_ON_EXITS];
ONEXIT before_shmem_exit_list[MAX_ON_EXITS];
int on_proc_exit_index;
int on_shmem_exit_index;
int before_shmem_exit_index;
union CmprMetaUnion* cmprMetaInfo;

View File

@ -15,6 +15,7 @@
#define MAKEFUNC_H
#include "nodes/parsenodes.h"
#include "nodes/execnodes.h"
extern A_Expr* makeA_Expr(A_Expr_Kind kind, List* name, Node* lexpr, Node* rexpr, int location);
@ -70,4 +71,6 @@ extern Node* makeTidConst(ItemPointer item);
extern FuncCall* makeFuncCall(List* funcname, List* args, int location);
extern Param* makeParam(
ParamKind paramkind, int paramid, Oid paramtype, int32 paramtypmod, Oid paramcollid, int location);
extern IndexInfo* makeIndexInfo(int numattrs, List *expressions, List *predicates,
bool unique, bool isready, bool concurrent);
#endif /* MAKEFUNC_H */

View File

@ -303,6 +303,8 @@ extern List* list_copy_tail(const List* list, int nskip);
extern void dlist_add_tail_cell(DList* dlist, DListCell* cell);
extern List* list_merge_int(List* list1, List* list2);
extern List* list_insert_nth_oid(List *list, int pos, Oid datum);
/*
* To ease migration to the new list API, a set of compatibility
* macros are provided that reduce the impact of the list API changes

View File

@ -433,6 +433,9 @@ inline void PageSetLSN(Page page, XLogRecPtr LSN, bool check = true)
} while (0)
#define PageClearPrunable(page) (HeapPageSetPruneXid(page, InvalidTransactionId))
#define GlobalTempRelationPageIsNotInitialized(rel, page) \
((rel)->rd_rel->relpersistence == RELPERSISTENCE_GLOBAL_TEMP && PageIsNew(page))
constexpr int PAGE_INDEX_CAN_TUPLE_DELETE = 2;
/* ----------------------------------------------------------------

View File

@ -72,6 +72,7 @@ extern void proc_exit(int code);
extern void sess_exit(int code);
extern void shmem_exit(int code);
extern void on_proc_exit(pg_on_exit_callback function, Datum arg);
extern void before_shmem_exit(pg_on_exit_callback function, Datum arg);
extern void on_shmem_exit(pg_on_exit_callback function, Datum arg);
extern void cancel_shmem_exit(pg_on_exit_callback function, Datum arg);
extern void on_exit_reset(void);

View File

@ -142,6 +142,7 @@ enum BuiltinTrancheIds {
LWTRANCHE_BUFFER_FREELIST,
LWTRANCHE_ACCOUNT_TABLE,
LWTRANCHE_EXTEND, // For general 3rd plugin
LWTRANCHE_GTT_CTL, // For GTT
/*
* Each trancheId above should have a corresponding item in BuiltinTrancheNames;
@ -227,6 +228,8 @@ typedef union LWLockPadded {
char pad[LWLOCK_PADDED_SIZE];
} LWLockPadded;
extern PGDLLIMPORT LWLockPadded *MainLWLockArray;
/*
* We use this structure to keep track of locked LWLocks for release
* during error recovery. The maximum size could be determined at runtime
@ -269,6 +272,21 @@ extern void CreateLWLocks(void);
extern void RequestAddinLWLocks(int n);
extern const char *GetBuiltInTrancheName(int trancheId);
/*
* There is another, more flexible method of obtaining lwlocks. First, call
* LWLockNewTrancheId just once to obtain a tranche ID; this allocates from
* a shared counter. Next, each individual process using the tranche should
* call LWLockRegisterTranche() to associate that tranche ID with a name.
* Finally, LWLockInitialize should be called just once per lwlock, passing
* the tranche ID as an argument.
*
* It may seem strange that each process using the tranche must register it
* separately, but dynamic shared memory segments aren't guaranteed to be
* mapped at the same address in all coordinating backends, so storing the
* registration in the main shared memory segment wouldn't work for that case.
*/
extern void LWLockRegisterTranche(int tranche_id, const char *tranche_name);
extern void wakeup_victim(LWLock *lock, ThreadId victim_tid);
extern int *get_held_lwlocks_num(void);
extern uint32 get_held_lwlocks_maxnum(void);

View File

@ -128,6 +128,7 @@ struct PGPROC {
ThreadId sessMemorySessionid;
uint64 sessionid; /* if not zero, session id in thread pool*/
int logictid; /*logic thread id*/
TransactionId session_gtt_frozenxid; /* session level global temp table relfrozenxid */
int pgprocno;
int nodeno;

View File

@ -127,3 +127,6 @@ extern void UpdateCSNLogAtTransactionEND(
extern void ResetProcXidCache(PGPROC* proc, bool needlock);
#endif /* USE_UT */
// For GTT
extern TransactionId list_all_session_gtt_frozenxids(int max_size, ThreadId *pids, TransactionId *xids, int *n);

View File

@ -174,6 +174,11 @@ typedef struct CatCacheHeader {
extern void AtEOXact_CatCache(bool isCommit);
/* this extern duplicates utils/memutils.h... */
extern THR_LOCAL PGDLLIMPORT MemoryContext CacheMemoryContext;
extern void CreateCacheMemoryContext(void);
extern CatCache* InitCatCache(int id, Oid reloid, Oid indexoid, int nkeys, const int* key, int nbuckets);
extern void InitCatCachePhase2(CatCache* cache, bool touch_index);

View File

@ -94,6 +94,7 @@ extern int get_relnatts(Oid relid);
extern char* get_rel_name(Oid relid);
extern char* getPartitionName(Oid partid, bool missing_ok);
extern Oid get_rel_namespace(Oid relid);
extern char get_rel_persistence(Oid relid);
extern bool is_sys_table(Oid relid);
extern Oid get_rel_type_id(Oid relid);
extern char get_rel_relkind(Oid relid);

View File

@ -86,6 +86,7 @@ extern MemoryContext PmTopMemoryContext;
extern MemoryContext StreamInfoContext;
extern THR_LOCAL PGDLLIMPORT MemoryContext ErrorContext;
extern THR_LOCAL PGDLLIMPORT MemoryContext CacheMemoryContext;
/*
* Memory-context-type-independent functions in mcxt.c

View File

@ -306,6 +306,7 @@ typedef struct StdRdOptions {
char* start_ctid_internal;
char* end_ctid_internal;
char *merge_list;
bool on_commit_delete_rows; /* global temp table */
} StdRdOptions;
#define HEAP_MIN_FILLFACTOR 10
@ -477,7 +478,9 @@ typedef struct StdRdOptions {
* RelationUsesLocalBuffers
* True if relation's pages are stored in local buffers.
*/
#define RelationUsesLocalBuffers(relation) ((relation)->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
#define RelationUsesLocalBuffers(relation) \
((relation)->rd_rel->relpersistence == RELPERSISTENCE_TEMP || \
(relation)->rd_rel->relpersistence == RELPERSISTENCE_GLOBAL_TEMP)
#define RelationIsLocalTemp(relation) \
((relation)->rd_rel->relnamespace == u_sess->catalog_cxt.myTempNamespace || \
(relation)->rd_rel->relnamespace == u_sess->catalog_cxt.myTempToastNamespace)
@ -505,14 +508,38 @@ typedef struct StdRdOptions {
/*
* RELATION_IS_LOCAL
* If a rel is either temp or newly created in the current transaction,
* If a rel is either local temp or global temp relation
* or newly created in the current transaction,
* it can be assumed to be accessible only to the current backend.
* This is typically used to decide that we can skip acquiring locks.
*
* Beware of multiple eval of argument
*/
#define RELATION_IS_LOCAL(relation) \
((relation)->rd_islocaltemp || (relation)->rd_createSubid != InvalidSubTransactionId)
((relation)->rd_islocaltemp || \
(relation)->rd_rel->relpersistence == RELPERSISTENCE_GLOBAL_TEMP || \
(relation)->rd_createSubid != InvalidSubTransactionId)
/*
* RELATION_IS_TEMP
* Test a rel is either local temp relation of this session
* or global temp relation.
*/
#define RELATION_IS_TEMP(relation) \
((relation)->rd_islocaltemp || \
(relation)->rd_rel->relpersistence == RELPERSISTENCE_GLOBAL_TEMP)
/* global temp table implementations */
#define RELATION_IS_GLOBAL_TEMP(relation) \
((relation) != NULL && (relation)->rd_rel != NULL && \
(relation)->rd_rel->relpersistence == RELPERSISTENCE_GLOBAL_TEMP)
#define RELATION_GTT_ON_COMMIT_DELETE(relation) \
((relation)->rd_options && (relation)->rd_rel->relkind == RELKIND_RELATION && \
(relation)->rd_rel->relpersistence == RELPERSISTENCE_GLOBAL_TEMP ? \
(reinterpret_cast<StdRdOptions *>((relation)->rd_options))->on_commit_delete_rows : false)
#define RelationGetRelPersistence(relation) ((relation)->rd_rel->relpersistence)
/* routines in utils/cache/relcache.c */
extern void RelationIncrementReferenceCount(Relation rel);

View File

@ -56,8 +56,11 @@ extern int RelationGetIndexNum(Relation relation);
extern Oid RelationGetOidIndex(Relation relation);
extern Oid RelationGetReplicaIndex(Relation relation);
extern List* RelationGetIndexExpressions(Relation relation);
extern List* RelationGetIndexExpressions(Relation relation);
extern List* RelationGetDummyIndexExpressions(Relation relation);
extern List* RelationGetIndexPredicate(Relation relation);
typedef enum IndexAttrBitmapKind {
INDEX_ATTR_BITMAP_ALL,
INDEX_ATTR_BITMAP_KEY,

View File

@ -0,0 +1,14 @@
reset search_path;
select pg_sleep(5);
pg_sleep
----------
(1 row)
drop schema gtt cascade;
NOTICE: drop cascades to 5 other objects
DETAIL: drop cascades to table gtt.gtt1
drop cascades to table gtt.gtt2
drop cascades to table gtt.gtt3
drop cascades to table gtt.gtt_t_kenyon
drop cascades to table gtt.gtt_with_seq

View File

@ -0,0 +1,361 @@
CREATE SCHEMA gtt_function;
set search_path=gtt_function,sys;
create global temp table gtt1(a int primary key, b text);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "gtt1_pkey" for table "gtt1"
create global temp table gtt_test_rename(a int primary key, b text);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "gtt_test_rename_pkey" for table "gtt_test_rename"
create global temp table gtt2(a int primary key, b text) on commit delete rows;
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "gtt2_pkey" for table "gtt2"
create global temp table gtt3(a int primary key, b text) on commit PRESERVE rows;
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "gtt3_pkey" for table "gtt3"
create global temp table tmp_t0(c0 tsvector,c1 varchar(100));
create table tbl_inherits_parent(
a int not null,
b varchar(32) not null default 'Got u',
c int check (c > 0),
d date not null
);
create global temp table tbl_inherits_parent_global_temp(
a int not null,
b varchar(32) not null default 'Got u',
c int check (c > 0),
d date not null
)on commit delete rows;
CREATE global temp TABLE products (
product_no integer PRIMARY KEY,
name text,
price numeric
);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "products_pkey" for table "products"
create global temp table gtt6(n int) with (on_commit_delete_rows='true');
begin;
insert into gtt6 values (9);
-- 1 row
select * from gtt6;
n
---
9
(1 row)
commit;
-- 0 row
select * from gtt6;
n
---
(0 rows)
-- ERROR
create index CONCURRENTLY idx_gtt1 on gtt1 (b);
ERROR: PGXC does not support concurrent INDEX yet
DETAIL: The feature is not currently supported
-- ERROR
cluster gtt1 using gtt1_pkey;
-- ERROR
create table gtt1(a int primary key, b text) on commit delete rows;
ERROR: ON COMMIT can only be used on temporary tables
-- ERROR
alter table gtt1 SET TABLESPACE pg_default;
ERROR: not support alter table set tablespace on global temp table.
-- ERROR
alter table gtt1 set ( on_commit_delete_rows='true');
ERROR: table cannot add or modify on commit parameter by ALTER TABLE command.
-- ERROR
create table gtt1(a int primary key, b text) with(on_commit_delete_rows=true);
ERROR: The parameter on_commit_delete_rows is exclusive to the global temp table, which cannot be specified by a regular table
-- ERROR
create or replace global temp view gtt_v as select 5;
ERROR: views cannot be global temp because they do not have storage
create table foo();
ERROR: must have at least one column
-- ERROR
alter table foo set (on_commit_delete_rows='true');
ERROR: relation "foo" does not exist
-- ok
--CREATE global temp TABLE measurement (
-- logdate date not null,
-- peaktemp int,
-- unitsales int
--) PARTITION BY RANGE (logdate);
--ok
--CREATE global temp TABLE p_table01 (
--id bigserial NOT NULL,
--cre_time timestamp without time zone,
--note varchar(30)
--) PARTITION BY RANGE (cre_time)
--WITH (
--OIDS = FALSE
--)on commit delete rows;
--CREATE global temp TABLE p_table01_2018
--PARTITION OF p_table01
--FOR VALUES FROM ('2018-01-01 00:00:00') TO ('2019-01-01 00:00:00') on commit delete rows;
--CREATE global temp TABLE p_table01_2017
--PARTITION OF p_table01
--FOR VALUES FROM ('2017-01-01 00:00:00') TO ('2018-01-01 00:00:00') on commit delete rows;
--begin;
--insert into p_table01 values(1,'2018-01-02 00:00:00','test1');
--insert into p_table01 values(1,'2018-01-02 00:00:00','test2');
--select count(*) from p_table01;
--commit;
--select count(*) from p_table01;
--ok
--CREATE global temp TABLE p_table02 (
--id bigserial NOT NULL,
--cre_time timestamp without time zone,
--note varchar(30)
--) PARTITION BY RANGE (cre_time)
--WITH (
--OIDS = FALSE
--)
--on commit PRESERVE rows;
--CREATE global temp TABLE p_table02_2018
--PARTITION OF p_table02
--FOR VALUES FROM ('2018-01-01 00:00:00') TO ('2019-01-01 00:00:00');
--CREATE global temp TABLE p_table02_2017
--PARTITION OF p_table02
--FOR VALUES FROM ('2017-01-01 00:00:00') TO ('2018-01-01 00:00:00');
-- ERROR
--create global temp table tbl_inherits_partition() inherits (tbl_inherits_parent);
-- ok
--create global temp table tbl_inherits_partition() inherits (tbl_inherits_parent_global_temp) on commit delete rows;
select relname ,relkind, relpersistence, reloptions from pg_class where relname like 'p_table0%' or relname like 'tbl_inherits%' order by relname;
relname | relkind | relpersistence | reloptions
---------------------------------+---------+----------------+-------------------------------------------------------------
tbl_inherits_parent | r | p | {orientation=row,compression=no}
tbl_inherits_parent_global_temp | r | g | {orientation=row,compression=no,on_commit_delete_rows=true}
(2 rows)
-- ERROR
create global temp table gtt3(a int primary key, b text) on commit drop;
ERROR: ON COMMIT only support PRESERVE ROWS or DELETE ROWS option
-- ERROR
create global temp table gtt4(a int primary key, b text) with(on_commit_delete_rows=true) on commit delete rows;
ERROR: could not create global temporary table with on commit and with clause at same time
-- ok
create global temp table gtt5(a int primary key, b text) with(on_commit_delete_rows=true);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "gtt5_pkey" for table "gtt5"
--ok
alter table gtt_test_rename rename to gtt_test_new;
-- ok
ALTER TABLE gtt_test_new ADD COLUMN address varchar(30);
-- ERROR
CREATE TABLE orders (
order_id integer PRIMARY KEY,
product_no integer REFERENCES products (product_no),
quantity integer
);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "orders_pkey" for table "orders"
ERROR: constraints on permanent tables may reference only permanent tables
-- ok
CREATE global temp TABLE orders (
order_id integer PRIMARY KEY,
product_no integer REFERENCES products (product_no),
quantity integer
)on commit delete rows;
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "orders_pkey" for table "orders"
--ERROR
insert into orders values(1,1,1);
ERROR: insert or update on table "orders" violates foreign key constraint "orders_product_no_fkey"
DETAIL: Key (product_no)=(1) is not present in table "products".
--ok
insert into products values(1,'test',1.0);
begin;
insert into orders values(1,1,1);
commit;
select count(*) from products;
count
-------
1
(1 row)
select count(*) from orders;
count
-------
0
(1 row)
-- ok
CREATE GLOBAL TEMPORARY TABLE mytable (
id SERIAL PRIMARY KEY,
data text
) on commit preserve rows;
NOTICE: CREATE TABLE will create implicit sequence "mytable_id_seq" for serial column "mytable.id"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "mytable_pkey" for table "mytable"
-- ok
--create global temp table gtt_seq(id int GENERATED ALWAYS AS IDENTITY (START WITH 2) primary key, a int) on commit PRESERVE rows;
--insert into gtt_seq (a) values(1);
--insert into gtt_seq (a) values(2);
--select * from gtt_seq order by id;
--truncate gtt_seq;
--select * from gtt_seq order by id;
--insert into gtt_seq (a) values(3);
--select * from gtt_seq order by id;
--ERROR
--CREATE MATERIALIZED VIEW mv_gtt1 as select * from gtt1;
-- ok
create index idx_gtt1_1 on gtt1 using hash (a);
ERROR: access method "hash" does not support row store
create index idx_tmp_t0_1 on tmp_t0 using gin (c0);
create index idx_tmp_t0_2 on tmp_t0 using gist (c0);
--ok
create global temp table gt (a SERIAL,b int);
NOTICE: CREATE TABLE will create implicit sequence "gt_a_seq" for serial column "gt.a"
begin;
set transaction_read_only = true;
insert into gt (b) values(1);
select * from gt;
a | b
---+---
1 | 1
(1 row)
commit;
--create sequence seq_1;
CREATE GLOBAL TEMPORARY TABLE gtt_s_1(c1 int PRIMARY KEY) ON COMMIT DELETE ROWS;
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "gtt_s_1_pkey" for table "gtt_s_1"
CREATE GLOBAL TEMPORARY TABLE gtt_s_2(c1 int PRIMARY KEY) ON COMMIT PRESERVE ROWS;
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "gtt_s_2_pkey" for table "gtt_s_2"
--alter table gtt_s_1 add c2 int default nextval('seq_1');
--alter table gtt_s_2 add c2 int default nextval('seq_1');
begin;
insert into gtt_s_1 (c1)values(1);
insert into gtt_s_2 (c1)values(1);
insert into gtt_s_1 (c1)values(2);
insert into gtt_s_2 (c1)values(2);
select * from gtt_s_1 order by c1;
c1
----
1
2
(2 rows)
commit;
select * from gtt_s_1 order by c1;
c1
----
(0 rows)
select * from gtt_s_2 order by c1;
c1
----
1
2
(2 rows)
--ok
create global temp table gt1(a int);
insert into gt1 values(generate_series(1,100000));
create index idx_gt1_1 on gt1 (a);
create index idx_gt1_2 on gt1((a + 1));
create index idx_gt1_3 on gt1((a*10),(a+a),(a-1));
explain (costs off) select * from gt1 where a=1;
QUERY PLAN
--------------------------------------
Bitmap Heap Scan on gt1
Recheck Cond: (a = 1)
-> Bitmap Index Scan on idx_gt1_1
Index Cond: (a = 1)
(4 rows)
explain (costs off) select * from gt1 where a=200000;
QUERY PLAN
--------------------------------------
Bitmap Heap Scan on gt1
Recheck Cond: (a = 200000)
-> Bitmap Index Scan on idx_gt1_1
Index Cond: (a = 200000)
(4 rows)
explain (costs off) select * from gt1 where a*10=300;
QUERY PLAN
--------------------------------------
Bitmap Heap Scan on gt1
Recheck Cond: ((a * 10) = 300)
-> Bitmap Index Scan on idx_gt1_3
Index Cond: ((a * 10) = 300)
(4 rows)
explain (costs off) select * from gt1 where a*10=3;
QUERY PLAN
--------------------------------------
Bitmap Heap Scan on gt1
Recheck Cond: ((a * 10) = 3)
-> Bitmap Index Scan on idx_gt1_3
Index Cond: ((a * 10) = 3)
(4 rows)
analyze gt1;
explain (costs off) select * from gt1 where a=1;
QUERY PLAN
----------------------------------------
[Bypass]
Index Only Scan using idx_gt1_1 on gt1
Index Cond: (a = 1)
(3 rows)
explain (costs off) select * from gt1 where a=200000;
QUERY PLAN
----------------------------------------
[Bypass]
Index Only Scan using idx_gt1_1 on gt1
Index Cond: (a = 200000)
(3 rows)
explain (costs off) select * from gt1 where a*10=300;
QUERY PLAN
-----------------------------------
[Bypass]
Index Scan using idx_gt1_3 on gt1
Index Cond: ((a * 10) = 300)
(3 rows)
explain (costs off) select * from gt1 where a*10=3;
QUERY PLAN
-----------------------------------
[Bypass]
Index Scan using idx_gt1_3 on gt1
Index Cond: ((a * 10) = 3)
(3 rows)
--ok
create global temp table gtt_test1(c1 int) with(on_commit_delete_rows='1');
create global temp table gtt_test2(c1 int) with(on_commit_delete_rows='0');
create global temp table gtt_test3(c1 int) with(on_commit_delete_rows='t');
create global temp table gtt_test4(c1 int) with(on_commit_delete_rows='f');
create global temp table gtt_test5(c1 int) with(on_commit_delete_rows='yes');
create global temp table gtt_test6(c1 int) with(on_commit_delete_rows='no');
create global temp table gtt_test7(c1 int) with(on_commit_delete_rows='y');
create global temp table gtt_test8(c1 int) with(on_commit_delete_rows='n');
--error
create global temp table gtt_test9(c1 int) with(on_commit_delete_rows='tr');
create global temp table gtt_test10(c1 int) with(on_commit_delete_rows='ye');
reset search_path;
drop schema gtt_function cascade;
NOTICE: drop cascades to 26 other objects
DETAIL: drop cascades to table gtt_function.gtt1
drop cascades to table gtt_function.gtt_test_new
drop cascades to table gtt_function.gtt2
drop cascades to table gtt_function.gtt3
drop cascades to table gtt_function.tmp_t0
drop cascades to table gtt_function.tbl_inherits_parent
drop cascades to table gtt_function.tbl_inherits_parent_global_temp
drop cascades to table gtt_function.products
drop cascades to table gtt_function.gtt6
drop cascades to table gtt_function.gtt5
drop cascades to table gtt_function.orders
drop cascades to table gtt_function.mytable
drop cascades to table gtt_function.gt
drop cascades to table gtt_function.gtt_s_1
drop cascades to table gtt_function.gtt_s_2
drop cascades to table gtt_function.gt1
drop cascades to table gtt_function.gtt_test1
drop cascades to table gtt_function.gtt_test2
drop cascades to table gtt_function.gtt_test3
drop cascades to table gtt_function.gtt_test4
drop cascades to table gtt_function.gtt_test5
drop cascades to table gtt_function.gtt_test6
drop cascades to table gtt_function.gtt_test7
drop cascades to table gtt_function.gtt_test8
drop cascades to table gtt_function.gtt_test9
drop cascades to table gtt_function.gtt_test10

View File

@ -0,0 +1,90 @@
set search_path=gtt,sys;
select nextval('gtt_with_seq_c2_seq');
nextval
---------
1
(1 row)
insert into gtt1 values(1, 'test1');
select * from gtt1 order by a;
a | b
---+---
(0 rows)
begin;
insert into gtt1 values(1, 'test1');
select * from gtt1 order by a;
a | b
---+-------
1 | test1
(1 row)
commit;
select * from gtt1 order by a;
a | b
---+---
(0 rows)
begin;
insert into gtt1 values(1, 'test1');
select * from gtt1 order by a;
a | b
---+-------
1 | test1
(1 row)
rollback;
select * from gtt1 order by a;
a | b
---+---
(0 rows)
truncate gtt1;
select * from gtt1 order by a;
a | b
---+---
(0 rows)
begin;
insert into gtt1 values(1, 'test1');
select * from gtt1 order by a;
a | b
---+-------
1 | test1
(1 row)
truncate gtt1;
select * from gtt1 order by a;
a | b
---+---
(0 rows)
insert into gtt1 values(1, 'test1');
rollback;
select * from gtt1 order by a;
a | b
---+---
(0 rows)
begin;
select * from gtt1 order by a;
a | b
---+---
(0 rows)
truncate gtt1;
insert into gtt1 values(1, 'test1');
select * from gtt1 order by a;
a | b
---+-------
1 | test1
(1 row)
truncate gtt1;
commit;
select * from gtt1 order by a;
a | b
---+---
(0 rows)
reset search_path;

View File

@ -0,0 +1,333 @@
set search_path=gtt,sys;
insert into gtt3 values(1, 'test1');
select * from gtt3 order by a;
a | b
---+-------
1 | test1
(1 row)
begin;
insert into gtt3 values(2, 'test1');
select * from gtt3 order by a;
a | b
---+-------
1 | test1
2 | test1
(2 rows)
commit;
select * from gtt3 order by a;
a | b
---+-------
1 | test1
2 | test1
(2 rows)
begin;
insert into gtt3 values(3, 'test1');
select * from gtt3 order by a;
a | b
---+-------
1 | test1
2 | test1
3 | test1
(3 rows)
rollback;
select * from gtt3 order by a;
a | b
---+-------
1 | test1
2 | test1
(2 rows)
truncate gtt3;
select * from gtt3 order by a;
a | b
---+---
(0 rows)
insert into gtt3 values(1, 'test1');
select * from gtt3 order by a;
a | b
---+-------
1 | test1
(1 row)
begin;
insert into gtt3 values(2, 'test2');
select * from gtt3 order by a;
a | b
---+-------
1 | test1
2 | test2
(2 rows)
truncate gtt3;
select * from gtt3 order by a;
a | b
---+---
(0 rows)
insert into gtt3 values(3, 'test3');
update gtt3 set a = 3 where b = 'test1';
select * from gtt3 order by a;
a | b
---+-------
3 | test3
(1 row)
rollback;
select * from gtt3 order by a;
a | b
---+-------
1 | test1
(1 row)
begin;
select * from gtt3 order by a;
a | b
---+-------
1 | test1
(1 row)
truncate gtt3;
insert into gtt3 values(5, 'test5');
select * from gtt3 order by a;
a | b
---+-------
5 | test5
(1 row)
truncate gtt3;
insert into gtt3 values(6, 'test6');
commit;
select * from gtt3 order by a;
a | b
---+-------
6 | test6
(1 row)
truncate gtt3;
insert into gtt3 values(1);
select * from gtt3;
a | b
---+---
1 |
(1 row)
begin;
insert into gtt3 values(2);
select * from gtt3;
a | b
---+---
1 |
2 |
(2 rows)
SAVEPOINT save1;
truncate gtt3;
insert into gtt3 values(3);
select * from gtt3;
a | b
---+---
3 |
(1 row)
SAVEPOINT save2;
truncate gtt3;
insert into gtt3 values(4);
select * from gtt3;
a | b
---+---
4 |
(1 row)
SAVEPOINT save3;
rollback to savepoint save2;
Select * from gtt3;
a | b
---+---
3 |
(1 row)
insert into gtt3 values(5);
select * from gtt3;
a | b
---+---
3 |
5 |
(2 rows)
rollback;
select * from gtt3;
a | b
---+---
1 |
(1 row)
truncate gtt3;
insert into gtt3 values(1);
select * from gtt3;
a | b
---+---
1 |
(1 row)
begin;
insert into gtt3 values(2);
select * from gtt3;
a | b
---+---
1 |
2 |
(2 rows)
SAVEPOINT save1;
truncate gtt3;
insert into gtt3 values(3);
select * from gtt3;
a | b
---+---
3 |
(1 row)
SAVEPOINT save2;
truncate gtt3;
insert into gtt3 values(4);
select * from gtt3;
a | b
---+---
4 |
(1 row)
SAVEPOINT save3;
rollback to savepoint save2;
Select * from gtt3;
a | b
---+---
3 |
(1 row)
insert into gtt3 values(5);
select * from gtt3;
a | b
---+---
3 |
5 |
(2 rows)
commit;
select * from gtt3;
a | b
---+---
3 |
5 |
(2 rows)
truncate gtt3;
insert into gtt3 values(generate_series(1,100000), 'testing');
select count(*) from gtt3;
count
--------
100000
(1 row)
analyze gtt3;
explain (COSTS FALSE) select * from gtt3 where a =300;
QUERY PLAN
------------------------------------
[Bypass]
Index Scan using gtt3_pkey on gtt3
Index Cond: (a = 300)
(3 rows)
insert into gtt_t_kenyon select generate_series(1,2000),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God',500);
insert into gtt_t_kenyon select generate_series(1,2),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God,Remark here!!',2000);
insert into gtt_t_kenyon select generate_series(3,4),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God,Remark here!!',4000);
insert into gtt_t_kenyon select generate_series(5,6),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God,Remark here!!',5500);
select relname, pg_relation_size(oid),pg_relation_size(reltoastrelid),pg_table_size(oid),pg_indexes_size(oid),pg_total_relation_size(oid) from pg_class where relname = 'gtt_t_kenyon';
relname | pg_relation_size | pg_relation_size | pg_table_size | pg_indexes_size | pg_total_relation_size
--------------+------------------+------------------+---------------+-----------------+------------------------
--? gtt_t_kenyon.*
(1 row)
select relname from pg_class where relname = 'gtt_t_kenyon' and reltoastrelid != 0;
relname
--------------
gtt_t_kenyon
(1 row)
select
c.relname, pg_relation_size(c.oid),pg_table_size(c.oid),pg_total_relation_size(c.oid)
from
pg_class c
where
c.oid in
(
select
i.indexrelid as indexrelid
from
pg_index i ,pg_class cc
where cc.relname = 'gtt_t_kenyon' and cc.oid = i.indrelid
)
order by c.relname;
relname | pg_relation_size | pg_table_size | pg_total_relation_size
--------------------+------------------+---------------+------------------------
--? idx_gtt_t_kenyon_1.*
--? idx_gtt_t_kenyon_2.*
(2 rows)
select count(*) from gtt_t_kenyon;
count
-------
2006
(1 row)
cluster gtt_t_kenyon using idx_gtt_t_kenyon_1;
select count(*) from gtt_t_kenyon;
count
-------
2006
(1 row)
vacuum full gtt_t_kenyon;
select count(*) from gtt_t_kenyon;
count
-------
2006
(1 row)
begin;
truncate gtt_t_kenyon;
insert into gtt_t_kenyon select generate_series(1,2000),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God',500);
commit;
cluster gtt_t_kenyon using idx_gtt_t_kenyon_1;
select count(*) from gtt_t_kenyon;
count
-------
2000
(1 row)
insert into gtt_t_kenyon select generate_series(1,2),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God,Remark here!!',2000);
insert into gtt_t_kenyon select generate_series(3,4),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God,Remark here!!',4000);
insert into gtt_t_kenyon select generate_series(5,6),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God,Remark here!!',5500);
begin;
truncate gtt_t_kenyon;
insert into gtt_t_kenyon select generate_series(1,2000),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God',500);
rollback;
cluster gtt_t_kenyon using idx_gtt_t_kenyon_1;
select count(*) from gtt_t_kenyon;
count
-------
2006
(1 row)
insert into gtt_with_seq (c1) values(1);
select * from gtt_with_seq;
c1 | c2
----+----
1 | 2
(1 row)
reset search_path;

View File

@ -0,0 +1,14 @@
CREATE SCHEMA gtt;
set search_path=gtt,sys;
create global temp table gtt1(a int primary key, b text) on commit delete rows;
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "gtt1_pkey" for table "gtt1"
create global temp table gtt2(a int primary key, b text) on commit delete rows;
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "gtt2_pkey" for table "gtt2"
create global temp table gtt3(a int primary key, b text);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "gtt3_pkey" for table "gtt3"
create global temp table gtt_t_kenyon(id int,vname varchar(48),remark text) on commit PRESERVE rows;
create index idx_gtt_t_kenyon_1 on gtt_t_kenyon(id);
create index idx_gtt_t_kenyon_2 on gtt_t_kenyon(remark);
CREATE GLOBAL TEMPORARY TABLE gtt_with_seq(c1 bigint, c2 bigserial) on commit PRESERVE rows;
NOTICE: CREATE TABLE will create implicit sequence "gtt_with_seq_c2_seq" for serial column "gtt_with_seq.c2"
reset search_path;

View File

@ -0,0 +1,95 @@
CREATE SCHEMA gtt_stats;
set search_path=gtt_stats,sys;
-- expect 0
select count(*) from pg_gtt_attached_pids;
count
-------
0
(1 row)
-- expect 0
select count(*) from pg_list_gtt_relfrozenxids();
count
-------
0
(1 row)
create global temp table gtt_stats.gtt(a int primary key, b text) on commit PRESERVE rows;
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "gtt_pkey" for table "gtt"
-- expect 0
select count(*) from pg_gtt_attached_pids;
count
-------
1
(1 row)
-- expect 0
select count(*) from pg_list_gtt_relfrozenxids();
count
-------
2
(1 row)
insert into gtt values(generate_series(1,10000),'test');
-- expect 1
select count(*) from pg_gtt_attached_pids;
count
-------
1
(1 row)
-- expect 2
select count(*) from pg_list_gtt_relfrozenxids();
count
-------
2
(1 row)
-- expect 2
select schemaname, tablename, relpages, reltuples, relallvisible from pg_gtt_relstats where schemaname = 'gtt_stats' order by tablename;
schemaname | tablename | relpages | reltuples | relallvisible
------------+-----------+----------+-----------+---------------
gtt_stats | gtt | 0 | 0 | 0
gtt_stats | gtt_pkey | 1 | 0 | 0
(2 rows)
-- expect 0
select * from pg_gtt_stats order by tablename, attname;
schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram
------------+----------------------+------------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------
gtt_stats | gtt | a | | | | | | | | | | |
gtt_stats | gtt | b | | | | | | | | | | |
gtt_stats | gtt_pkey | a | | | | | | | | | | |
pg_toast | pg_toast_16386 | chunk_data | | | | | | | | | | |
pg_toast | pg_toast_16386 | chunk_id | | | | | | | | | | |
pg_toast | pg_toast_16386 | chunk_seq | | | | | | | | | | |
pg_toast | pg_toast_16386_index | chunk_id | | | | | | | | | | |
pg_toast | pg_toast_16386_index | chunk_seq | | | | | | | | | | |
(22 rows)
reindex table gtt;
reindex index gtt_pkey;
analyze gtt;
select schemaname, tablename, relpages, reltuples, relallvisible from pg_gtt_relstats where schemaname = 'gtt_stats' order by tablename;
schemaname | tablename | relpages | reltuples | relallvisible
------------+-----------+----------+-----------+---------------
gtt_stats | gtt | 55 | 10000 | 0
gtt_stats | gtt_pkey | 30 | 10000 | 0
(2 rows)
select * from pg_gtt_stats order by tablename, attname;
schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram
------------+----------------------+------------+-----------+-----------+-----------+------------+------------------+-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------+-------------------+------------------------+----------------------
gtt_stats | gtt | a | f | 0 | 4 | -1 | | | {1,100,200,300,400,500,600,700,800,900,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3100,3200,3300,3400,3500,3600,3700,3800,3900,4000,4100,4200,4300,4400,4500,4600,4700,4800,4900,5000,5100,5200,5300,5400,5500,5600,5700,5800,5900,6000,6100,6200,6300,6400,6500,6600,6700,6800,6900,7000,7100,7200,7300,7400,7500,7600,7700,7800,7900,8000,8100,8200,8300,8400,8500,8600,8700,8800,8900,9000,9100,9200,9300,9400,9500,9600,9700,9800,9900,10000} | 1 | | |
gtt_stats | gtt | b | f | 0 | 5 | 1 | {test} | {1} | | 1 | | |
gtt_stats | gtt_pkey | a | | | | | | | | | | |
pg_toast | pg_toast_16386 | chunk_data | | | | | | | | | | |
pg_toast | pg_toast_16386 | chunk_id | | | | | | | | | | |
pg_toast | pg_toast_16386 | chunk_seq | | | | | | | | | | |
pg_toast | pg_toast_16386_index | chunk_id | | | | | | | | | | |
pg_toast | pg_toast_16386_index | chunk_seq | | | | | | | | | | |
(22 rows)
reset search_path;
drop schema gtt_stats cascade;
NOTICE: drop cascades to table gtt_stats.gtt

View File

@ -2024,6 +2024,10 @@ WHERE d.classoid IS NULL AND p1.oid <= 9999 order by 1;
3589 | timestamptz_list_agg_noarg2_transfn
3590 | listagg
3591 | pgxc_get_thread_wait_status
3596 | pg_get_gtt_relstats
3597 | pg_get_gtt_statistics
3598 | pg_gtt_attached_pid
3599 | pg_list_gtt_relfrozenxids
3610 | tsvectorin
3611 | tsvectorout
3612 | tsqueryin
@ -2632,7 +2636,7 @@ WHERE d.classoid IS NULL AND p1.oid <= 9999 order by 1;
9016 | pg_advisory_lock
9017 | pgxc_unlock_for_sp_database
9999 | pg_test_err_contain_err
(2270 rows)
(2274 rows)
-- **************** pg_cast ****************
-- Catch bogus values in pg_cast columns (other than cases detected by

View File

@ -1346,6 +1346,94 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
pg_get_invalid_backends | SELECT c.pid, c.node_name, s.datname AS dbname, s.backend_start, s.query FROM (pg_pool_validate(false) c(pid, node_name) LEFT JOIN pg_stat_activity s ON ((c.pid = s.pid)));
pg_get_senders_catchup_time | SELECT w.pid, w.sender_pid AS lwpid, w.local_role, w.peer_role, w.state, 'Wal'::text AS type, w.catchup_start, w.catchup_end FROM pg_stat_get_wal_senders() w(pid, sender_pid, local_role, peer_role, peer_state, state, catchup_start, catchup_end, sender_sent_location, sender_write_location, sender_flush_location, sender_replay_location, receiver_received_location, receiver_write_location, receiver_flush_location, receiver_replay_location, sync_percent, sync_state, sync_priority, sync_most_available, channel) UNION ALL SELECT d.pid, d.sender_pid AS lwpid, d.local_role, d.peer_role, d.state, 'Data'::text AS type, d.catchup_start, d.catchup_end FROM pg_stat_get_data_senders() d(pid, sender_pid, local_role, peer_role, state, catchup_start, catchup_end, queue_size, queue_lower_tail, queue_header, queue_upper_tail, send_position, receive_position);
pg_group | SELECT pg_authid.rolname AS groname, pg_authid.oid AS grosysid, ARRAY(SELECT pg_auth_members.member FROM pg_auth_members WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist FROM pg_authid WHERE (NOT pg_authid.rolcanlogin);
pg_gtt_attached_pids| SELECT n.nspname AS schemaname,
c.relname AS tablename,
s.relid,
s.pid
FROM (pg_class c
LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))),
LATERAL pg_gtt_attached_pid(c.oid) s(relid, pid)
WHERE ((c.relpersistence = 'g'::"char") AND (c.relkind = ANY (ARRAY['r'::"char", 'S'::"char"])) AND ((c.relrowsecurity = false) OR (NOT row_security_active(c.oid))));
pg_gtt_relstats| SELECT n.nspname AS schemaname,
c.relname AS tablename,
s.relfilenode,
s.relpages,
s.reltuples,
s.relallvisible,
s.relfrozenxid,
s.relminmxid
FROM (pg_class c
LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))),
LATERAL pg_get_gtt_relstats(c.oid) s(relfilenode, relpages, reltuples, relallvisible, relfrozenxid, relminmxid)
WHERE ((c.relpersistence = 'g'::"char") AND (c.relkind = ANY (ARRAY['r'::"char", 'p'::"char", 'i'::"char", 't'::"char"])) AND ((c.relrowsecurity = false) OR (NOT row_security_active(c.oid))));
pg_gtt_stats| SELECT n.nspname AS schemaname,
c.relname AS tablename,
a.attname,
s.stainherit AS inherited,
s.stanullfrac AS null_frac,
s.stawidth AS avg_width,
s.stadistinct AS n_distinct,
CASE
WHEN (s.stakind1 = 1) THEN s.stavalues1
WHEN (s.stakind2 = 1) THEN s.stavalues2
WHEN (s.stakind3 = 1) THEN s.stavalues3
WHEN (s.stakind4 = 1) THEN s.stavalues4
WHEN (s.stakind5 = 1) THEN s.stavalues5
ELSE NULL::text[]
END AS most_common_vals,
CASE
WHEN (s.stakind1 = 1) THEN s.stanumbers1
WHEN (s.stakind2 = 1) THEN s.stanumbers2
WHEN (s.stakind3 = 1) THEN s.stanumbers3
WHEN (s.stakind4 = 1) THEN s.stanumbers4
WHEN (s.stakind5 = 1) THEN s.stanumbers5
ELSE NULL::real[]
END AS most_common_freqs,
CASE
WHEN (s.stakind1 = 2) THEN s.stavalues1
WHEN (s.stakind2 = 2) THEN s.stavalues2
WHEN (s.stakind3 = 2) THEN s.stavalues3
WHEN (s.stakind4 = 2) THEN s.stavalues4
WHEN (s.stakind5 = 2) THEN s.stavalues5
ELSE NULL::text[]
END AS histogram_bounds,
CASE
WHEN (s.stakind1 = 3) THEN s.stanumbers1[1]
WHEN (s.stakind2 = 3) THEN s.stanumbers2[1]
WHEN (s.stakind3 = 3) THEN s.stanumbers3[1]
WHEN (s.stakind4 = 3) THEN s.stanumbers4[1]
WHEN (s.stakind5 = 3) THEN s.stanumbers5[1]
ELSE NULL::real
END AS correlation,
CASE
WHEN (s.stakind1 = 4) THEN s.stavalues1
WHEN (s.stakind2 = 4) THEN s.stavalues2
WHEN (s.stakind3 = 4) THEN s.stavalues3
WHEN (s.stakind4 = 4) THEN s.stavalues4
WHEN (s.stakind5 = 4) THEN s.stavalues5
ELSE NULL::text[]
END AS most_common_elems,
CASE
WHEN (s.stakind1 = 4) THEN s.stanumbers1
WHEN (s.stakind2 = 4) THEN s.stanumbers2
WHEN (s.stakind3 = 4) THEN s.stanumbers3
WHEN (s.stakind4 = 4) THEN s.stanumbers4
WHEN (s.stakind5 = 4) THEN s.stanumbers5
ELSE NULL::real[]
END AS most_common_elem_freqs,
CASE
WHEN (s.stakind1 = 5) THEN s.stanumbers1
WHEN (s.stakind2 = 5) THEN s.stanumbers2
WHEN (s.stakind3 = 5) THEN s.stanumbers3
WHEN (s.stakind4 = 5) THEN s.stanumbers4
WHEN (s.stakind5 = 5) THEN s.stanumbers5
ELSE NULL::real[]
END AS elem_count_histogram
FROM ((pg_class c
JOIN pg_attribute a ON ((c.oid = a.attrelid)))
LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))),
LATERAL pg_get_gtt_statistics(c.oid, (a.attnum)::integer, ''::text) s(starelid, staattnum, stainherit, stanullfrac, stawidth, stadistinct, stakind1, stakind2, stakind3, stakind4, stakind5, staop1, staop2, staop3, staop4, staop5, stacoll1, stacoll2, stacoll3, stacoll4, stac
WHERE ((c.relpersistence = 'g'::"char") AND (c.relkind = ANY (ARRAY['r'::"char", 'p'::"char", 'i'::"char", 't'::"char"])) AND (NOT a.attisdropped) AND has_column_privilege(c.oid, a.attnum, 'select'::text) AND ((c.relrowsecurity = false) OR (NOT row_security_active(c.oid))));
pg_indexes | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, t.spcname AS tablespace, pg_get_indexdef(i.oid) AS indexdef FROM ((((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = i.reltablespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char"));
pg_locks | SELECT l.locktype, l.database, l.relation, l.page, l.tuple, l.virtualxid, l.transactionid, l.classid, l.objid, l.objsubid, l.virtualtransaction, l.pid, l.mode, l.granted, l.fastpath FROM pg_lock_status() l(locktype, database, relation, page, tuple, virtualxid, transactionid, classid, objid, objsubid, virtualtransaction, pid, mode, granted, fastpath);
pg_node_env | SELECT s.node_name, s.host, s.process, s.port, s.installpath, s.datapath, s.log_directory FROM pg_stat_get_env() s(node_name, host, process, port, installpath, datapath, log_directory);

View File

@ -2063,6 +2063,10 @@ WHERE d.classoid IS NULL AND p1.oid <= 9999 order by 1;
3589 | timestamptz_list_agg_noarg2_transfn
3590 | listagg
3591 | pgxc_get_thread_wait_status
3596 | pg_get_gtt_relstats
3597 | pg_get_gtt_statistics
3598 | pg_gtt_attached_pid
3599 | pg_list_gtt_relfrozenxids
3610 | tsvectorin
3611 | tsvectorout
3612 | tsqueryin
@ -2671,7 +2675,7 @@ WHERE d.classoid IS NULL AND p1.oid <= 9999 order by 1;
9016 | pg_advisory_lock
9017 | pgxc_unlock_for_sp_database
9999 | pg_test_err_contain_err
(2270 rows)
(2274 rows)
-- Check prokind
select count(*) from pg_proc where prokind = 'a';
@ -2689,7 +2693,7 @@ select count(*) from pg_proc where prokind = 'w';
select count(*) from pg_proc where prokind = 'f';
count
-------
3130
3134
(1 row)
select count(*) from pg_proc where prokind = 'p';

View File

@ -238,15 +238,7 @@ insert into temp_col2 select * from temp_col1;
--Other features
--temp function
--Create temp table
create global temp table tg(a int, b varchar2(3000));
WARNING: GLOBAL is deprecated in temporary table creation
LINE 1: create global temp table tg(a int, b varchar2(3000));
^
create local temp table tl(a int, b varchar2(3000));
create global temporary table gt(a int, b varchar2(3000));
WARNING: GLOBAL is deprecated in temporary table creation
LINE 1: create global temporary table gt(a int, b varchar2(3000));
^
create local temporary table lt(a int, b varchar2(3000));
create temp table pg_temp.temp_t(a int);
ERROR: temporary tables cannot specify a schema name
@ -819,7 +811,7 @@ create temp table test_serial(a serial, b varchar2(100));
ERROR: It's not supported to create serial column on temporary table
create temp table test_serial2(a int);
alter table test_serial2 add b serial;
ERROR: It's not supported to alter table add serial column
ERROR: It's not supported to create serial column on temporary table
drop table test_serial;
ERROR: table "test_serial" does not exist
drop table test_serial2;

View File

@ -24,4 +24,4 @@ enable_sonic_hashagg=on
enable_sonic_hashjoin=on
enable_opfusion=on
uncontrolled_memory_context='HashCacheContext,TupleHashTable,TupleSort,AggContext,SRF multi-call context,CteScan*,FunctionScan*,RemoteQuery*,VecAgg*,HashContext,TopTransactionContext'
enable_thread_pool = on
enable_thread_pool = off

View File

@ -571,3 +571,9 @@ test: udf_crem create_c_function
#test: redis_truncate_col
#test: redis_alter_truncate_partition
#test: redis_alter_truncate_col_partition
# global temp table test
test: gtt_stats
test: gtt_function
test: gtt_prepare
test: gtt_parallel_1 gtt_parallel_2
test: gtt_clean

View File

@ -0,0 +1,6 @@
reset search_path;
select pg_sleep(5);
drop schema gtt cascade;

View File

@ -0,0 +1,253 @@
CREATE SCHEMA gtt_function;
set search_path=gtt_function,sys;
create global temp table gtt1(a int primary key, b text);
create global temp table gtt_test_rename(a int primary key, b text);
create global temp table gtt2(a int primary key, b text) on commit delete rows;
create global temp table gtt3(a int primary key, b text) on commit PRESERVE rows;
create global temp table tmp_t0(c0 tsvector,c1 varchar(100));
create table tbl_inherits_parent(
a int not null,
b varchar(32) not null default 'Got u',
c int check (c > 0),
d date not null
);
create global temp table tbl_inherits_parent_global_temp(
a int not null,
b varchar(32) not null default 'Got u',
c int check (c > 0),
d date not null
)on commit delete rows;
CREATE global temp TABLE products (
product_no integer PRIMARY KEY,
name text,
price numeric
);
create global temp table gtt6(n int) with (on_commit_delete_rows='true');
begin;
insert into gtt6 values (9);
-- 1 row
select * from gtt6;
commit;
-- 0 row
select * from gtt6;
-- ERROR
create index CONCURRENTLY idx_gtt1 on gtt1 (b);
-- ERROR
cluster gtt1 using gtt1_pkey;
-- ERROR
create table gtt1(a int primary key, b text) on commit delete rows;
-- ERROR
alter table gtt1 SET TABLESPACE pg_default;
-- ERROR
alter table gtt1 set ( on_commit_delete_rows='true');
-- ERROR
create table gtt1(a int primary key, b text) with(on_commit_delete_rows=true);
-- ERROR
create or replace global temp view gtt_v as select 5;
create table foo();
-- ERROR
alter table foo set (on_commit_delete_rows='true');
-- ok
--CREATE global temp TABLE measurement (
-- logdate date not null,
-- peaktemp int,
-- unitsales int
--) PARTITION BY RANGE (logdate);
--ok
--CREATE global temp TABLE p_table01 (
--id bigserial NOT NULL,
--cre_time timestamp without time zone,
--note varchar(30)
--) PARTITION BY RANGE (cre_time)
--WITH (
--OIDS = FALSE
--)on commit delete rows;
--CREATE global temp TABLE p_table01_2018
--PARTITION OF p_table01
--FOR VALUES FROM ('2018-01-01 00:00:00') TO ('2019-01-01 00:00:00') on commit delete rows;
--CREATE global temp TABLE p_table01_2017
--PARTITION OF p_table01
--FOR VALUES FROM ('2017-01-01 00:00:00') TO ('2018-01-01 00:00:00') on commit delete rows;
--begin;
--insert into p_table01 values(1,'2018-01-02 00:00:00','test1');
--insert into p_table01 values(1,'2018-01-02 00:00:00','test2');
--select count(*) from p_table01;
--commit;
--select count(*) from p_table01;
--ok
--CREATE global temp TABLE p_table02 (
--id bigserial NOT NULL,
--cre_time timestamp without time zone,
--note varchar(30)
--) PARTITION BY RANGE (cre_time)
--WITH (
--OIDS = FALSE
--)
--on commit PRESERVE rows;
--CREATE global temp TABLE p_table02_2018
--PARTITION OF p_table02
--FOR VALUES FROM ('2018-01-01 00:00:00') TO ('2019-01-01 00:00:00');
--CREATE global temp TABLE p_table02_2017
--PARTITION OF p_table02
--FOR VALUES FROM ('2017-01-01 00:00:00') TO ('2018-01-01 00:00:00');
-- ERROR
--create global temp table tbl_inherits_partition() inherits (tbl_inherits_parent);
-- ok
--create global temp table tbl_inherits_partition() inherits (tbl_inherits_parent_global_temp) on commit delete rows;
select relname ,relkind, relpersistence, reloptions from pg_class where relname like 'p_table0%' or relname like 'tbl_inherits%' order by relname;
-- ERROR
create global temp table gtt3(a int primary key, b text) on commit drop;
-- ERROR
create global temp table gtt4(a int primary key, b text) with(on_commit_delete_rows=true) on commit delete rows;
-- ok
create global temp table gtt5(a int primary key, b text) with(on_commit_delete_rows=true);
--ok
alter table gtt_test_rename rename to gtt_test_new;
-- ok
ALTER TABLE gtt_test_new ADD COLUMN address varchar(30);
-- ERROR
CREATE TABLE orders (
order_id integer PRIMARY KEY,
product_no integer REFERENCES products (product_no),
quantity integer
);
-- ok
CREATE global temp TABLE orders (
order_id integer PRIMARY KEY,
product_no integer REFERENCES products (product_no),
quantity integer
)on commit delete rows;
--ERROR
insert into orders values(1,1,1);
--ok
insert into products values(1,'test',1.0);
begin;
insert into orders values(1,1,1);
commit;
select count(*) from products;
select count(*) from orders;
-- ok
CREATE GLOBAL TEMPORARY TABLE mytable (
id SERIAL PRIMARY KEY,
data text
) on commit preserve rows;
-- ok
--create global temp table gtt_seq(id int GENERATED ALWAYS AS IDENTITY (START WITH 2) primary key, a int) on commit PRESERVE rows;
--insert into gtt_seq (a) values(1);
--insert into gtt_seq (a) values(2);
--select * from gtt_seq order by id;
--truncate gtt_seq;
--select * from gtt_seq order by id;
--insert into gtt_seq (a) values(3);
--select * from gtt_seq order by id;
--ERROR
--CREATE MATERIALIZED VIEW mv_gtt1 as select * from gtt1;
-- ok
create index idx_gtt1_1 on gtt1 using hash (a);
create index idx_tmp_t0_1 on tmp_t0 using gin (c0);
create index idx_tmp_t0_2 on tmp_t0 using gist (c0);
--ok
create global temp table gt (a SERIAL,b int);
begin;
set transaction_read_only = true;
insert into gt (b) values(1);
select * from gt;
commit;
--create sequence seq_1;
CREATE GLOBAL TEMPORARY TABLE gtt_s_1(c1 int PRIMARY KEY) ON COMMIT DELETE ROWS;
CREATE GLOBAL TEMPORARY TABLE gtt_s_2(c1 int PRIMARY KEY) ON COMMIT PRESERVE ROWS;
--alter table gtt_s_1 add c2 int default nextval('seq_1');
--alter table gtt_s_2 add c2 int default nextval('seq_1');
begin;
insert into gtt_s_1 (c1)values(1);
insert into gtt_s_2 (c1)values(1);
insert into gtt_s_1 (c1)values(2);
insert into gtt_s_2 (c1)values(2);
select * from gtt_s_1 order by c1;
commit;
select * from gtt_s_1 order by c1;
select * from gtt_s_2 order by c1;
--ok
create global temp table gt1(a int);
insert into gt1 values(generate_series(1,100000));
create index idx_gt1_1 on gt1 (a);
create index idx_gt1_2 on gt1((a + 1));
create index idx_gt1_3 on gt1((a*10),(a+a),(a-1));
explain (costs off) select * from gt1 where a=1;
explain (costs off) select * from gt1 where a=200000;
explain (costs off) select * from gt1 where a*10=300;
explain (costs off) select * from gt1 where a*10=3;
analyze gt1;
explain (costs off) select * from gt1 where a=1;
explain (costs off) select * from gt1 where a=200000;
explain (costs off) select * from gt1 where a*10=300;
explain (costs off) select * from gt1 where a*10=3;
--ok
create global temp table gtt_test1(c1 int) with(on_commit_delete_rows='1');
create global temp table gtt_test2(c1 int) with(on_commit_delete_rows='0');
create global temp table gtt_test3(c1 int) with(on_commit_delete_rows='t');
create global temp table gtt_test4(c1 int) with(on_commit_delete_rows='f');
create global temp table gtt_test5(c1 int) with(on_commit_delete_rows='yes');
create global temp table gtt_test6(c1 int) with(on_commit_delete_rows='no');
create global temp table gtt_test7(c1 int) with(on_commit_delete_rows='y');
create global temp table gtt_test8(c1 int) with(on_commit_delete_rows='n');
--error
create global temp table gtt_test9(c1 int) with(on_commit_delete_rows='tr');
create global temp table gtt_test10(c1 int) with(on_commit_delete_rows='ye');
reset search_path;
drop schema gtt_function cascade;

View File

@ -0,0 +1,43 @@
set search_path=gtt,sys;
select nextval('gtt_with_seq_c2_seq');
insert into gtt1 values(1, 'test1');
select * from gtt1 order by a;
begin;
insert into gtt1 values(1, 'test1');
select * from gtt1 order by a;
commit;
select * from gtt1 order by a;
begin;
insert into gtt1 values(1, 'test1');
select * from gtt1 order by a;
rollback;
select * from gtt1 order by a;
truncate gtt1;
select * from gtt1 order by a;
begin;
insert into gtt1 values(1, 'test1');
select * from gtt1 order by a;
truncate gtt1;
select * from gtt1 order by a;
insert into gtt1 values(1, 'test1');
rollback;
select * from gtt1 order by a;
begin;
select * from gtt1 order by a;
truncate gtt1;
insert into gtt1 values(1, 'test1');
select * from gtt1 order by a;
truncate gtt1;
commit;
select * from gtt1 order by a;
reset search_path;

View File

@ -0,0 +1,146 @@
set search_path=gtt,sys;
insert into gtt3 values(1, 'test1');
select * from gtt3 order by a;
begin;
insert into gtt3 values(2, 'test1');
select * from gtt3 order by a;
commit;
select * from gtt3 order by a;
begin;
insert into gtt3 values(3, 'test1');
select * from gtt3 order by a;
rollback;
select * from gtt3 order by a;
truncate gtt3;
select * from gtt3 order by a;
insert into gtt3 values(1, 'test1');
select * from gtt3 order by a;
begin;
insert into gtt3 values(2, 'test2');
select * from gtt3 order by a;
truncate gtt3;
select * from gtt3 order by a;
insert into gtt3 values(3, 'test3');
update gtt3 set a = 3 where b = 'test1';
select * from gtt3 order by a;
rollback;
select * from gtt3 order by a;
begin;
select * from gtt3 order by a;
truncate gtt3;
insert into gtt3 values(5, 'test5');
select * from gtt3 order by a;
truncate gtt3;
insert into gtt3 values(6, 'test6');
commit;
select * from gtt3 order by a;
truncate gtt3;
insert into gtt3 values(1);
select * from gtt3;
begin;
insert into gtt3 values(2);
select * from gtt3;
SAVEPOINT save1;
truncate gtt3;
insert into gtt3 values(3);
select * from gtt3;
SAVEPOINT save2;
truncate gtt3;
insert into gtt3 values(4);
select * from gtt3;
SAVEPOINT save3;
rollback to savepoint save2;
Select * from gtt3;
insert into gtt3 values(5);
select * from gtt3;
rollback;
select * from gtt3;
truncate gtt3;
insert into gtt3 values(1);
select * from gtt3;
begin;
insert into gtt3 values(2);
select * from gtt3;
SAVEPOINT save1;
truncate gtt3;
insert into gtt3 values(3);
select * from gtt3;
SAVEPOINT save2;
truncate gtt3;
insert into gtt3 values(4);
select * from gtt3;
SAVEPOINT save3;
rollback to savepoint save2;
Select * from gtt3;
insert into gtt3 values(5);
select * from gtt3;
commit;
select * from gtt3;
truncate gtt3;
insert into gtt3 values(generate_series(1,100000), 'testing');
select count(*) from gtt3;
analyze gtt3;
explain (COSTS FALSE) select * from gtt3 where a =300;
insert into gtt_t_kenyon select generate_series(1,2000),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God',500);
insert into gtt_t_kenyon select generate_series(1,2),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God,Remark here!!',2000);
insert into gtt_t_kenyon select generate_series(3,4),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God,Remark here!!',4000);
insert into gtt_t_kenyon select generate_series(5,6),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God,Remark here!!',5500);
select relname, pg_relation_size(oid),pg_relation_size(reltoastrelid),pg_table_size(oid),pg_indexes_size(oid),pg_total_relation_size(oid) from pg_class where relname = 'gtt_t_kenyon';
select relname from pg_class where relname = 'gtt_t_kenyon' and reltoastrelid != 0;
select
c.relname, pg_relation_size(c.oid),pg_table_size(c.oid),pg_total_relation_size(c.oid)
from
pg_class c
where
c.oid in
(
select
i.indexrelid as indexrelid
from
pg_index i ,pg_class cc
where cc.relname = 'gtt_t_kenyon' and cc.oid = i.indrelid
)
order by c.relname;
select count(*) from gtt_t_kenyon;
cluster gtt_t_kenyon using idx_gtt_t_kenyon_1;
select count(*) from gtt_t_kenyon;
vacuum full gtt_t_kenyon;
select count(*) from gtt_t_kenyon;
begin;
truncate gtt_t_kenyon;
insert into gtt_t_kenyon select generate_series(1,2000),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God',500);
commit;
cluster gtt_t_kenyon using idx_gtt_t_kenyon_1;
select count(*) from gtt_t_kenyon;
insert into gtt_t_kenyon select generate_series(1,2),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God,Remark here!!',2000);
insert into gtt_t_kenyon select generate_series(3,4),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God,Remark here!!',4000);
insert into gtt_t_kenyon select generate_series(5,6),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God,Remark here!!',5500);
begin;
truncate gtt_t_kenyon;
insert into gtt_t_kenyon select generate_series(1,2000),repeat('kenyon here'||'^_^',2),repeat('^_^ Kenyon is not God',500);
rollback;
cluster gtt_t_kenyon using idx_gtt_t_kenyon_1;
select count(*) from gtt_t_kenyon;
insert into gtt_with_seq (c1) values(1);
select * from gtt_with_seq;
reset search_path;

View File

@ -0,0 +1,19 @@
CREATE SCHEMA gtt;
set search_path=gtt,sys;
create global temp table gtt1(a int primary key, b text) on commit delete rows;
create global temp table gtt2(a int primary key, b text) on commit delete rows;
create global temp table gtt3(a int primary key, b text);
create global temp table gtt_t_kenyon(id int,vname varchar(48),remark text) on commit PRESERVE rows;
create index idx_gtt_t_kenyon_1 on gtt_t_kenyon(id);
create index idx_gtt_t_kenyon_2 on gtt_t_kenyon(remark);
CREATE GLOBAL TEMPORARY TABLE gtt_with_seq(c1 bigint, c2 bigserial) on commit PRESERVE rows;
reset search_path;

View File

@ -0,0 +1,46 @@
CREATE SCHEMA gtt_stats;
set search_path=gtt_stats,sys;
-- expect 0
select count(*) from pg_gtt_attached_pids;
-- expect 0
select count(*) from pg_list_gtt_relfrozenxids();
create global temp table gtt_stats.gtt(a int primary key, b text) on commit PRESERVE rows;
-- expect 0
select count(*) from pg_gtt_attached_pids;
-- expect 0
select count(*) from pg_list_gtt_relfrozenxids();
insert into gtt values(generate_series(1,10000),'test');
-- expect 1
select count(*) from pg_gtt_attached_pids;
-- expect 2
select count(*) from pg_list_gtt_relfrozenxids();
-- expect 2
select schemaname, tablename, relpages, reltuples, relallvisible from pg_gtt_relstats where schemaname = 'gtt_stats' order by tablename;
-- expect 0
select * from pg_gtt_stats order by tablename, attname;
reindex table gtt;
reindex index gtt_pkey;
analyze gtt;
select schemaname, tablename, relpages, reltuples, relallvisible from pg_gtt_relstats where schemaname = 'gtt_stats' order by tablename;
select * from pg_gtt_stats order by tablename, attname;
reset search_path;
drop schema gtt_stats cascade;

View File

@ -211,9 +211,7 @@ insert into temp_col2 select * from temp_col1;
--temp function
--Create temp table
create global temp table tg(a int, b varchar2(3000));
create local temp table tl(a int, b varchar2(3000));
create global temporary table gt(a int, b varchar2(3000));
create local temporary table lt(a int, b varchar2(3000));
create temp table pg_temp.temp_t(a int);
create table pg_temp.temp_t1(a int);