forked from huawei/openGauss-server
merge code for global temporary table(GTT)
This commit is contained in:
parent
53626285eb
commit
797043b60a
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -233,7 +233,8 @@ Boot_CreateStmt:
|
|||
mapped_relation,
|
||||
true,
|
||||
REL_CMPRS_NOT_SUPPORT,
|
||||
BOOTSTRAP_SUPERUSERID);
|
||||
BOOTSTRAP_SUPERUSERID,
|
||||
false);
|
||||
ereport(DEBUG4, (errmsg("bootstrap relation created")));
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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, >tRelfrozenxid);
|
||||
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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
************************/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -153,7 +153,9 @@ static const char *BuiltinTrancheNames[] = {
|
|||
"DoubleWriteLock",
|
||||
"BufFreeListLock",
|
||||
"LWTRANCHE_ACCOUNT_TABLE",
|
||||
"GeneralExtendedLock"
|
||||
"GeneralExtendedLock",
|
||||
/* LWTRANCHE_GTT_CTL */
|
||||
"GlobalTempTableControl"
|
||||
};
|
||||
|
||||
static void RegisterLWLockTranches(void);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
reset search_path;
|
||||
|
||||
select pg_sleep(5);
|
||||
|
||||
drop schema gtt cascade;
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue