From 04de085042ae4d6a146c9ade0b78c243a1ce833e Mon Sep 17 00:00:00 2001 From: "xu.han01" Date: Tue, 3 Sep 2024 05:57:26 +0000 Subject: [PATCH] support global sequence cache --- src/common/backend/parser/gram.y | 8 + src/common/backend/utils/adt/ruleutils.cpp | 5 + .../optimizer/commands/sequence/sequence.cpp | 1476 ++++++++++-- .../commands/sequence/sequence_util.cpp | 197 +- .../optimizer/commands/tablecmds.cpp | 17 +- .../process/threadpool/knl_session.cpp | 2 + .../runtime/executor/execUtils.cpp | 6 +- src/gausskernel/storage/lmgr/lwlock.cpp | 9 +- src/include/commands/sequence.h | 59 +- src/include/knl/knl_instance.h | 9 + src/include/knl/knl_session.h | 5 + src/include/storage/lock/lwlock.h | 10 +- .../regress/expected/alter_seq_max_in_txn.out | 36 +- src/test/regress/expected/large_sequence.out | 22 +- .../regress/expected/single_node_insert.out | 12 +- src/test/regress/expected/updatable_views.out | 3 +- .../input/global_sequence_cache.source | 908 +++++++ .../input/session_sequence_cache.source | 790 +++++++ .../output/global_sequence_cache.source | 2105 +++++++++++++++++ src/test/regress/output/psql.source | 1 + .../output/session_sequence_cache.source | 1974 ++++++++++++++++ src/test/regress/parallel_schedule0 | 4 + 22 files changed, 7420 insertions(+), 238 deletions(-) create mode 100644 src/test/regress/input/global_sequence_cache.source create mode 100644 src/test/regress/input/session_sequence_cache.source create mode 100644 src/test/regress/output/global_sequence_cache.source create mode 100644 src/test/regress/output/session_sequence_cache.source diff --git a/src/common/backend/parser/gram.y b/src/common/backend/parser/gram.y index ea91ef32e1..1b6283e0ad 100644 --- a/src/common/backend/parser/gram.y +++ b/src/common/backend/parser/gram.y @@ -10263,6 +10263,14 @@ SeqOptElem: CACHE NumericOnly { $$ = makeDefElem("minvalue", NULL); } + | GLOBAL + { + $$ = makeDefElem("cache_level", (Node *)makeInteger(1)); + } + | SESSION + { + $$ = makeDefElem("cache_level", (Node *)makeInteger(0)); + } ; opt_by: BY {} diff --git a/src/common/backend/utils/adt/ruleutils.cpp b/src/common/backend/utils/adt/ruleutils.cpp index 0f8b670b9a..43fc26c5c8 100644 --- a/src/common/backend/utils/adt/ruleutils.cpp +++ b/src/common/backend/utils/adt/ruleutils.cpp @@ -13061,6 +13061,11 @@ static void deparse_sequence_options(List* options, StringInfoData& str, bool ow appendStringInfo(&str, "%s.%s", quote_identifier(rel->relname), quote_identifier(attrname)); } + } else if (strcmp(defel->defname, "cache_level") == 0) { + if (defGetBoolean(defel)) + appendStringInfo(&str, " GLOBAL"); + else + appendStringInfo(&str, " SESSION"); } else { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("option \"%s\" not recognized", defel->defname))); } diff --git a/src/gausskernel/optimizer/commands/sequence/sequence.cpp b/src/gausskernel/optimizer/commands/sequence/sequence.cpp index 7c101598d0..28e13e5fc5 100644 --- a/src/gausskernel/optimizer/commands/sequence/sequence.cpp +++ b/src/gausskernel/optimizer/commands/sequence/sequence.cpp @@ -27,6 +27,7 @@ #include "access/xloginsert.h" #include "access/xlogutils.h" #include "access/xlogproc.h" +#include "access/hash.h" #include "catalog/dependency.h" #include "catalog/namespace.h" #include "catalog/pg_object.h" @@ -50,6 +51,7 @@ #include "utils/resowner.h" #include "utils/syscache.h" #include "utils/snapmgr.h" +#include "utils/guc.h" #include "commands/dbcommands.h" #include "replication/slot.h" @@ -72,17 +74,21 @@ static T_Form read_seq_tuple(SeqTable elm, Relation rel, Buffer* buf, HeapTuple template static ObjectAddress DefineSequence(CreateSeqStmt* seq); template -static ObjectAddress AlterSequence(const AlterSeqStmt* stmt); +static ObjectAddress AlterSequence(const AlterSeqStmt* stmt, Oid relid); +template +static ObjectAddress AlterSequenceForGlobalCache(const AlterSeqStmt* stmt, Oid relid); #ifdef PGXC template static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* newm_p, List** owned_by, - bool* is_restart, bool* need_seq_rewrite); + bool* is_restart, bool* need_seq_rewrite, SeqTable cache_elm = NULL); #else static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* newm_p, List** owned_by, - bool* need_seq_rewrite); + bool* need_seq_rewrite, SeqTable cache_elm = NULL); #endif template static void do_setval(Oid relid, int128 next, bool iscalled); +template +static void do_setval_for_global_seq_cache(Oid relid, int128 next, bool iscalled); static void process_owned_by(const Relation seqrel, List* owned_by); template static GTM_UUID get_uuid_from_tuple(const void* seq_p, const Relation rel, const HeapTuple seqtuple); @@ -93,6 +99,7 @@ static SeqTable InitGlobalSeqElm(Oid relid); static int64 GetNextvalGlobal(SeqTable sess_elm, Relation seqrel); template static int128 GetNextvalLocal(SeqTable elm, Relation seqrel); +static int128 GetNextvalGlobalForSingleNode(SeqTable elm); template static T_Int FetchLogLocal(T_Int* next, T_Int* result, T_Int* last, T_Int maxv, T_Int minv, T_Int fetch, T_Int log, T_Int incby, T_Int rescnt, bool is_cycled, T_Int cache, Relation seqrel); @@ -104,8 +111,22 @@ static void updateNextValForSequence(Buffer buf, Form_pg_sequence seq, HeapTuple int64 result); static int64 GetNextvalResult(SeqTable sess_elm, Relation seqrel, Form_pg_sequence seq, HeapTupleData seqtuple, Buffer buf, int64* rangemax, SeqTable elm, GTM_UUID uuid); +static void copyLastValSequenceElem(SeqTable elm, bool is_replace); +static void initGlobalSequenceCache(); +static void initCacheLevelHashTab(); +static void removeGlobalSeqCache_internal(Oid relid); +static void removeGlobalSeqCacheForCurrval_internal(Oid relid); +static void removeSessionSeqScache_internal(Oid relid); +static bool is_alter_sequence_cache_level(List* options, CACHE_LEVEL cache_level); +static int128 findlastedSequenceValueByOid(Oid relid, bool* isvalid); +static void changeSequenceCacheLevel(Oid relid); +bool is_global_level_sequence_cache(Oid relid); +template +uint32 GSCHashFunc(const void *key, Size keysize); +uint32 GetGSCBucket(uint32 hashvalue); template static char* Int8or16Out(T_Int num); +typedef ObjectAddress (*AlterSequenceFuncPtr)(const AlterSeqStmt*, Oid); /* * Sequence concurrent improvements * @@ -377,6 +398,13 @@ void InitGlobalSeq() g_instance.global_seq[i].shb_list = NULL; g_instance.global_seq[i].lock_id = FirstGlobalSeqLock + i; } + + /* + * Init the Global Sequence Cache bucket data, regardless of + * whether the parameter enable_global_sequence_cache is enabled + */ + initGlobalSequenceCache(); + initCacheLevelHashTab(); } static SeqTable InitGlobalSeqElm(Oid relid) @@ -662,6 +690,23 @@ static int128 GetNextvalLocal(SeqTable elm, Relation seqrel) return result; } +static int128 GetNextvalGlobalForSingleNode(SeqTable elm) +{ + int128 result = 0; + Relation seqrel = lock_and_open_seq(elm); + if (!RELKIND_IS_SEQUENCE(seqrel->rd_rel->relkind)) { + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s.%s\" is not a sequence", get_namespace_name(RelationGetNamespace(seqrel)), RelationGetRelationName(seqrel)))); + } else if (seqrel->rd_rel->relkind == RELKIND_SEQUENCE) { + result = GetNextvalLocal(elm, seqrel); + } else { + result = GetNextvalLocal(elm, seqrel); + } + relation_close(seqrel, NoLock); + return result; +} + template static bool FetchNOverMaxBound(T_Int maxv, T_Int next, T_Int incby) { @@ -994,7 +1039,11 @@ static ObjectAddress DefineSequence(CreateSeqStmt* seq) coldef->typname = makeTypeNameFromOid(INT8OID, -1); coldef->colname = "uuid"; value[i - 1] = Int64GetDatum(seq->uuid); - + break; + case SEQ_COL_CACHELEVEL: + coldef->typname = makeTypeNameFromOid(intTypeOid, -1); + coldef->colname = "cache_level"; + value[i - 1] = Int8or16GetDatum(newm.cache_level); break; default: ereport(ERROR, @@ -1104,47 +1153,185 @@ void ResetSequence(Oid seq_relid, bool restart) Relation seq_rel; SeqTable elm = NULL; HeapTuple tuple; - - /* - * Read the old sequence. This does a bit more work than really - * necessary, but it's simple, and we do want to double-check that it's - * indeed a sequence. - */ - init_sequence(seq_relid, &elm, &seq_rel); - if (RelationGetRelkind(seq_rel) == RELKIND_SEQUENCE) { - tuple = ResetSequenceTuple(seq_rel, elm, restart); - } else { - tuple = ResetSequenceTuple(seq_rel, elm, restart); + uint32 hashCode; + GSCKey key; + uint32 bucket_id; + bool is_global_cache = is_global_level_sequence_cache(seq_relid); + + if (is_global_cache) { + /* lock the destination bucket to obtain the global cache */ + key.dbOid = u_sess->proc_cxt.MyDatabaseId; + key.relid = seq_relid; + hashCode = GSCHashFunc((const void *) &key, sizeof(GSCKey)); + bucket_id = GetGSCBucket(hashCode); + (void)LWLockAcquire(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id), LW_EXCLUSIVE); } - /* - * Create a new storage file for the sequence. We want to keep the - * sequence's relfrozenxid at 0, since it won't contain any unfrozen XIDs. - */ - RelationSetNewRelfilenode(seq_rel, InvalidTransactionId, InvalidMultiXactId); + PG_TRY(); + { + if (is_global_cache) { + init_sequence_single_node_global_cache(seq_relid, &elm, &seq_rel, &key, hashCode, bucket_id); + } else { + /* + * Read the old sequence. This does a bit more work than really + * necessary, but it's simple, and we do want to double-check that it's + * indeed a sequence. + */ + init_sequence(seq_relid, &elm, &seq_rel); + } + + if (RelationGetRelkind(seq_rel) == RELKIND_SEQUENCE) { + tuple = ResetSequenceTuple(seq_rel, elm, restart); + } else { + tuple = ResetSequenceTuple(seq_rel, elm, restart); + } - /* - * Insert the modified tuple into the new storage file. - */ - fill_seq_with_data(seq_rel, tuple); + /* + * Create a new storage file for the sequence. We want to keep the + * sequence's relfrozenxid at 0, since it won't contain any unfrozen XIDs. + */ + RelationSetNewRelfilenode(seq_rel, InvalidTransactionId, InvalidMultiXactId); - /* Clear local cache so that we don't think we have cached numbers */ - /* Note that we do not change the currval() state */ - AssignInt(&(elm->cached), elm->last); - if (restart) { - elm->last_valid = false; - } + /* + * Insert the modified tuple into the new storage file. + */ + fill_seq_with_data(seq_rel, tuple); + + /* Clear local cache so that we don't think we have cached numbers */ + /* Note that we do not change the currval() state */ + AssignInt(&(elm->cached), elm->last); + if (restart) { + elm->last_valid = false; + } + + relation_close(seq_rel, NoLock); - relation_close(seq_rel, NoLock); + if (is_global_cache) { + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + } + } + PG_CATCH(); + { + if (is_global_cache) { + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + } + PG_RE_THROW(); + } + PG_END_TRY(); } ObjectAddress AlterSequenceWrapper(AlterSeqStmt* stmt) { + ObjectAddress address; + /* Open and lock sequence. */ + Oid relid = RangeVarGetRelid(stmt->sequence, ShareRowExclusiveLock, stmt->missing_ok); + if (relid == InvalidOid) { + ereport(NOTICE, (errmsg("relation \"%s\" does not exist, skipping", stmt->sequence->relname))); + return InvalidObjectAddress; + } + + Relation rel = relation_open(relid, NoLock); + char relkind = RelationGetRelkind(rel); + relation_close(rel, NoLock); + if (stmt->is_large && relkind == RELKIND_SEQUENCE) { + ereport(ERROR, ( + errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s is not a large sequence, please use ALTER SEQUENCE instead.", stmt->sequence->relname))); + } else if (!stmt->is_large && relkind == RELKIND_LARGE_SEQUENCE) { + ereport(ERROR, ( + errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s is not a sequence, please use ALTER LARGE SEQUENCE instead.", stmt->sequence->relname))); + } + if (CheckSeqOwnedByAutoInc(relid)) { + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot alter sequence owned by auto_increment column"))); + } + + /* Must be owner or have alter privilege of the sequence. */ + AclResult aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_ALTER); + if (aclresult != ACLCHECK_OK && !pg_class_ownercheck(relid, GetUserId())) { + aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS, stmt->sequence->relname); + } + + bool is_global_cache = is_global_level_sequence_cache(relid); + bool is_alter_cache_level = is_alter_sequence_cache_level(stmt->options, is_global_cache ? GLOBAL_LEVEL : SESSION_LEVEL); + + AlterSequenceFuncPtr alterSeqFuncPtr = NULL; + /* + * When modifying a sequence using ALTER SEQUENCE, the actual function that gets called depends on the + * current state of the sequence (whether it's a global cache or a session-level cache) and the desired change. + * If the current sequence is a global cache and want to change it to a session-level cache, in this case, need to call the AlterSequence function. + * If the current sequence is a session cache and want to change it to a global cache, would call the AlterSequenceForGlobalCache function. + */ if (stmt->is_large) { - return AlterSequence(stmt); + if (is_global_cache) { + if (is_alter_cache_level) + alterSeqFuncPtr = &AlterSequence; + else + alterSeqFuncPtr = &AlterSequenceForGlobalCache; + } else { + if (is_alter_cache_level) + alterSeqFuncPtr = &AlterSequenceForGlobalCache; + else + alterSeqFuncPtr = &AlterSequence; + } } else { - return AlterSequence(stmt); + if (is_global_cache) { + if (is_alter_cache_level) + alterSeqFuncPtr = &AlterSequence; + else + alterSeqFuncPtr = &AlterSequenceForGlobalCache; + } else { + if (is_alter_cache_level) + alterSeqFuncPtr = &AlterSequenceForGlobalCache; + else + alterSeqFuncPtr = &AlterSequence; + } + } + + if (is_alter_cache_level) { + (void)LWLockAcquire(g_instance.alter_sequence_lock, LW_EXCLUSIVE); + } + PG_TRY(); + { + if (is_alter_cache_level) { + if (is_global_cache) { + /* reclaim unused sequence numbers */ + bool isvalid = false; + int128 l_val = findlastedSequenceValueByOid(relid, &isvalid); + if (isvalid) { + Numeric last_val = convert_int128_to_numeric(l_val, 0); + DirectFunctionCall2(setval_oid, relid, NumericGetDatum(last_val)); + } + /* remove global cache */ + removeGlobalSeqCache_internal(relid); + removeGlobalSeqCacheForCurrval_internal(relid); + } else { + /* remove local cache */ + removeSessionSeqScache_internal(relid); + } + /* switch the cache level to another strategy */ + changeSequenceCacheLevel(relid); + /* undo the recording of lastval */ + u_sess->cmd_cxt.last_used_seq = NULL; + } + + /* invoke the function that alters the actual caching strategy for sequences */ + address = alterSeqFuncPtr(stmt, relid); + + if (is_alter_cache_level) { + LWLockRelease(g_instance.alter_sequence_lock); + } + } + PG_CATCH(); + { + if (is_alter_cache_level) { + LWLockRelease(g_instance.alter_sequence_lock); + } + PG_RE_THROW(); } + PG_END_TRY(); + return address; } bool CheckSeqOwnedByAutoInc(Oid seqoid) @@ -1174,9 +1361,8 @@ bool CheckSeqOwnedByAutoInc(Oid seqoid) * Alter sequence maxvalue needs update info in GTM. */ template -static ObjectAddress AlterSequence(const AlterSeqStmt* stmt) +static ObjectAddress AlterSequence(const AlterSeqStmt* stmt, Oid relid) { - Oid relid; SeqTable elm = NULL; Relation seqrel; Buffer buf; @@ -1191,35 +1377,9 @@ static ObjectAddress AlterSequence(const AlterSeqStmt* stmt) bool need_seq_rewrite = false; ObjectAddress address; - /* Open and lock sequence. */ - relid = RangeVarGetRelid(stmt->sequence, ShareRowExclusiveLock, stmt->missing_ok); - if (relid == InvalidOid) { - ereport(NOTICE, (errmsg("relation \"%s\" does not exist, skipping", stmt->sequence->relname))); - return InvalidObjectAddress; - } - TrForbidAccessRbObject(RelationRelationId, relid, stmt->sequence->relname); init_sequence(relid, &elm, &seqrel); - char relkind = RelationGetRelkind(seqrel); - if (large && relkind == RELKIND_SEQUENCE) { - ereport(ERROR, ( - errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s is not a large sequence, please use ALTER SEQUENCE instead.", stmt->sequence->relname))); - } else if (!large && relkind == RELKIND_LARGE_SEQUENCE) { - ereport(ERROR, ( - errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s is not a sequence, please use ALTER LARGE SEQUENCE instead.", stmt->sequence->relname))); - } - if (CheckSeqOwnedByAutoInc(relid)) { - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot alter sequence owned by auto_increment column"))); - } - /* Must be owner or have alter privilege of the sequence. */ - AclResult aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_ALTER); - if (aclresult != ACLCHECK_OK && !pg_class_ownercheck(relid, GetUserId())) { - aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS, stmt->sequence->relname); - } /* temp sequence and single_node do not need gtm, they only use info on local node */ isUseLocalSeq = RelationIsLocalTemp(seqrel) || IS_SINGLE_NODE; @@ -1309,6 +1469,100 @@ static ObjectAddress AlterSequence(const AlterSeqStmt* stmt) return address; } +/* AlterSequence for global sequence cache */ +template +static ObjectAddress AlterSequenceForGlobalCache(const AlterSeqStmt* stmt, Oid relid) +{ + SeqTable elm = NULL; + Relation seqrel; + Buffer buf; + HeapTupleData seqtuple; + HeapTuple tuple = NULL; + T_Form newm = NULL; + List* owned_by = NIL; + uint32 hashCode; + GSCKey key; + uint32 bucket_id; + bool is_restart = false; + bool need_seq_rewrite = false; + ObjectAddress address; + + TrForbidAccessRbObject(RelationRelationId, relid, stmt->sequence->relname); + + /* lock the destination bucket to obtain the global cache */ + key.dbOid = u_sess->proc_cxt.MyDatabaseId; + key.relid = relid; + hashCode = GSCHashFunc((const void *) &key, sizeof(GSCKey)); + bucket_id = GetGSCBucket(hashCode); + (void)LWLockAcquire(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id), LW_EXCLUSIVE); + int saveInterruptHoldoffCount = t_thrd.int_cxt.InterruptHoldoffCount; + + PG_TRY(); + { + init_sequence_single_node_global_cache(relid, &elm, &seqrel, &key, hashCode, bucket_id); + /* lock page' buffer and read tuple into new sequence structure */ + GTM_UUID uuid; + (void)read_seq_tuple(elm, seqrel, &buf, &seqtuple, &uuid); + + /* Copy the existing sequence tuple. */ + tuple = (HeapTuple)tableam_tops_copy_tuple(&seqtuple); + UnlockReleaseBuffer(buf); + + newm = (T_Form)GETSTRUCT(tuple); + + /* Check and set new values */ + init_params(stmt->options, false, true, newm, &owned_by, + &is_restart, &need_seq_rewrite, elm); + /* Clear local cache so that we don't think we have cached numbers */ + /* Note that we do not change the currval() state */ + AssignInt(&(elm->cached), (int128)elm->last); + + /* If needed, rewrite the sequence relation itself */ + if (need_seq_rewrite) { + /* + * Create a new storage file for the sequence, making the state + * changes transactional. We want to keep the sequence's relfrozenxid + * at 0, since it won't contain any unfrozen XIDs. + */ + RelationSetNewRelfilenode(seqrel, InvalidTransactionId, InvalidMultiXactId); + /* + * Insert the modified tuple into the new storage file. + */ + fill_seq_with_data(seqrel, tuple); + + /* Recalculates the global sequence cache */ + if (seqrel->rd_rel->relfilenode != elm->filenode) { + elm->filenode = seqrel->rd_rel->relfilenode; + errno_t rc = memcpy_s(&(elm->cached), sizeof(int128), &(elm->last), sizeof(int128)); + securec_check(rc, "\0", "\0"); + } + } + heap_freetuple(tuple); + + /* process OWNED BY if given */ + if (owned_by != NIL) + process_owned_by(seqrel, owned_by); + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + } + PG_CATCH(); + { + t_thrd.int_cxt.InterruptHoldoffCount = saveInterruptHoldoffCount; + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + PG_RE_THROW(); + } + PG_END_TRY(); + + /* Recode the sequence alter time. */ + PgObjectType objectType = GetPgObjectTypePgClass(seqrel->rd_rel->relkind); + if (objectType != OBJECT_TYPE_INVALID) { + UpdatePgObjectMtime(seqrel->rd_id, objectType); + } + + ObjectAddressSet(address, RelationRelationId, relid); + relation_close(seqrel, NoLock); + return address; +} + /* * Note: nextval cannot rollback, but it can be used a in transaction block. * Thus when we alter sequence and select nextval() in the same transaction, we may @@ -1353,7 +1607,11 @@ Datum nextval(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot change sequence owned by auto_increment column"))); } - PG_RETURN_INT64(nextval_internal(relid)); + if (is_global_level_sequence_cache(relid)) { + PG_RETURN_INT64(nextval_internal_for_global_seq_cache(relid)); + } else { + PG_RETURN_INT64(nextval_internal(relid)); + } } Oid get_nextval_rettype() @@ -1417,12 +1675,17 @@ bool shouldReturnNumeric() Datum nextval_oid(PG_FUNCTION_ARGS) { + int128 result; Oid relid = PG_GETARG_OID(0); if (CheckSeqOwnedByAutoInc(relid)) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot change sequence owned by auto_increment column"))); } - int128 result = nextval_internal(relid); + if (is_global_level_sequence_cache(relid)) { + result = nextval_internal_for_global_seq_cache(relid); + } else { + result = nextval_internal(relid); + } if (shouldReturnNumeric()) { PG_RETURN_NUMERIC(convert_int128_to_numeric(result, 0)); @@ -1507,6 +1770,107 @@ int128 nextval_internal(Oid relid) return result; } +int128 nextval_internal_for_global_seq_cache(Oid relid) +{ + SeqTable elm = NULL; + uint32 hashCode; + GSCKey key; + uint32 bucket_id; + SeqTableData currval_seqdata; + char* relname = NULL; + int128 result = 0; + + if (t_thrd.postmaster_cxt.HaShmData->current_mode == STANDBY_MODE) { + ereport(ERROR, (errmsg("Standby do not support nextval, please do it in primary!"))); + } + + relname = get_rel_name(relid); + + TrForbidAccessRbObject(RelationRelationId, relid, relname); + + if (pg_class_aclcheck(relid, GetUserId(), ACL_USAGE) != ACLCHECK_OK && pg_class_aclcheck(relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied for sequence %s", relname))); + + /* lock the destination bucket to obtain the global cache */ + key.dbOid = u_sess->proc_cxt.MyDatabaseId; + key.relid = relid; + hashCode = GSCHashFunc((const void *) &key, sizeof(GSCKey)); + bucket_id = GetGSCBucket(hashCode); + + (void)LWLockAcquire(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id), LW_EXCLUSIVE); + + PG_TRY(); + { + /* Get global sequence cache. */ + init_sequence_single_node_global_cache(relid, &elm, NULL, &key, hashCode, bucket_id); + + if (elm->last != elm->cached) { + /* some numbers were cached */ + int128 elm_cached = elm->cached; + Assert(elm->last_valid); + Assert(elm->increment != 0); + elm->last += elm->increment; + result = elm->last; + errno_t rc = memcpy_s(&currval_seqdata, sizeof(SeqTableData), elm, sizeof(SeqTableData)); + securec_check(rc, "\0", "\0"); + + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + + char* buf_last = DatumGetCString(DirectFunctionCall1(int16out, Int128GetDatum(result))); + char* buf_cached = DatumGetCString(DirectFunctionCall1(int16out, Int128GetDatum(elm_cached))); + + ereport(DEBUG2, + (errmodule(MOD_SEQ), + (errmsg("Sequence %s retrun ID %s from cache, the cached is %s, ", + relname, + buf_last, + buf_cached)))); + + pfree_ext(buf_last); + pfree_ext(buf_cached); + pfree_ext(relname); + + /* record the local cache for lastval currval */ + copyLastValSequenceElem(&currval_seqdata, true); + global_sequence_cache_set_currval_elm(relid, result); + + PG_TRY_RETURN(result); + } + + /* If don't have cached value, we should fetch some. */ + result = GetNextvalGlobalForSingleNode(elm); + + /* Record global sequence cache for currval function. */ + errno_t rc = memcpy_s(&currval_seqdata, sizeof(SeqTableData), elm, sizeof(SeqTableData)); + securec_check(rc, "\0", "\0"); + + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + + char* buf = DatumGetCString(DirectFunctionCall1(int16out, Int128GetDatum(result))); + ereport(DEBUG2, + (errmodule(MOD_SEQ), + (errmsg("Sequence %s retrun ID from nextval %s, ", relname, buf)))); + + pfree_ext(buf); + pfree_ext(relname); + + /* record the local cache for lastval() and currval() */ + copyLastValSequenceElem(&currval_seqdata, true); + global_sequence_cache_set_currval_elm(relid, result); + } + PG_CATCH(); + { + pfree_ext(relname); + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + PG_RE_THROW(); + } + PG_END_TRY(); + + return result; +} + Datum currval_oid(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); @@ -1519,7 +1883,12 @@ Datum currval_oid(PG_FUNCTION_ARGS) } /* open and lock sequence */ - init_sequence(relid, &elm, &seqrel); + if (is_global_level_sequence_cache(relid)) { + /* sequence cache is global, but currval cache is local */ + init_sequence_single_node_global_cache_for_currval(relid, &elm, &seqrel); + } else { + init_sequence(relid, &elm, &seqrel); + } TrForbidAccessRbObject(RelationRelationId, relid, RelationGetRelationName(seqrel)); @@ -1554,7 +1923,7 @@ Datum lastval(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("lastval function is not supported"))); } - if (u_sess->cmd_cxt.last_used_seq == NULL) + if (u_sess->cmd_cxt.last_used_seq == NULL || !u_sess->cmd_cxt.last_used_seq->last_valid) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("lastval is not yet defined in this session"))); @@ -1623,6 +1992,11 @@ void autoinc_setval(Oid relid, int128 next, bool iscalled) Buffer buf; HeapTupleData seqtuple; + if (is_global_level_sequence_cache(relid)) { + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("in B mode, auto_increment only supports sequence cached in session."))); + } + init_sequence(relid, &elm, &seqrel); /* no need to set a small value */ if (elm->last_valid && next < elm->last) { @@ -1691,6 +2065,11 @@ int128 autoinc_get_nextval(Oid relid) Form_pg_large_sequence seq; int128 result; + if (is_global_level_sequence_cache(relid)) { + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("in B mode, auto_increment only supports sequence cached in session."))); + } + init_sequence(relid, &elm, &seqrel); seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple, &uuid); if (seq->is_called) { @@ -1852,54 +2231,196 @@ static void do_setval(Oid relid, int128 next, bool iscalled) relation_close(seqrel, NoLock); } -/* - * Implement the 2 arg setval procedure. - * See do_setval for discussion. - */ -Datum setval_oid(PG_FUNCTION_ARGS) +template +static void do_setval_for_global_seq_cache(Oid relid, int128 next, bool iscalled) { - Oid relid = PG_GETARG_OID(0); - Numeric nextArg = PG_GETARG_NUMERIC(1); - int128 next = numeric_int16_internal(nextArg); - - Relation rel = relation_open(relid, NoLock); - char relkind = RelationGetRelkind(rel); - relation_close(rel, NoLock); - if (CheckSeqOwnedByAutoInc(relid)) { - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot change sequence owned by auto_increment column"))); - } - if (relkind == RELKIND_SEQUENCE) { - do_setval(relid, next, true); - } else if (relkind == RELKIND_LARGE_SEQUENCE) { - do_setval(relid, next, true); + SeqTable elm = NULL; + Relation seqrel; + Buffer buf; + HeapTupleData seqtuple; + T_Form seq; + bool result_isvalid = false; + int128 result; + uint32 hashCode; + GSCKey key; + uint32 bucket_id; + char* relname = NULL; + SeqTableData currval_seqdata; + if (t_thrd.postmaster_cxt.HaShmData->current_mode == STANDBY_MODE) { + ereport(ERROR, (errmsg("Standby do not support setval, please do it in primary!"))); } - PG_RETURN_NUMERIC(nextArg); -} + relname = get_rel_name(relid); -/* - * Implement the 3 arg setval procedure. - * See do_setval for discussion. - */ -Datum setval3_oid(PG_FUNCTION_ARGS) -{ - Oid relid = PG_GETARG_OID(0); - Numeric nextArg = PG_GETARG_NUMERIC(1); - int128 next = numeric_int16_internal(nextArg); - bool iscalled = PG_GETARG_BOOL(2); + TrForbidAccessRbObject(RelationRelationId, relid, relname); + if (pg_class_aclcheck(relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied for sequence %s", relname))); - Relation rel = relation_open(relid, NoLock); - char relkind = RelationGetRelkind(rel); - relation_close(rel, NoLock); - if (CheckSeqOwnedByAutoInc(relid)) { + /* lock the destination bucket to obtain the global cache */ + key.dbOid = u_sess->proc_cxt.MyDatabaseId; + key.relid = relid; + hashCode = GSCHashFunc((const void *) &key, sizeof(GSCKey)); + bucket_id = GetGSCBucket(hashCode); + (void)LWLockAcquire(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id), LW_EXCLUSIVE); + int saveInterruptHoldoffCount = t_thrd.int_cxt.InterruptHoldoffCount; + + PG_TRY(); + { + init_sequence_single_node_global_cache(relid, &elm, &seqrel, &key, hashCode, bucket_id); + + /* read-only transactions may only modify temp sequences */ + if (!RelationIsLocalTemp(seqrel)) + PreventCommandIfReadOnly("setval()"); + + /* lock page' buffer and read tuple */ + GTM_UUID uuid; + seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple, &uuid); + + if ((next < seq->min_value) || (next > seq->max_value)) { + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("setval: value %s is out of bounds for sequence \"%s\" (%s..%s)", + DatumGetCString(DirectFunctionCall1(int16out, Int128GetDatum(next))), + RelationGetRelationName(seqrel), + DatumGetCString(DirectFunctionCall1(int16out, Int128GetDatum(seq->min_value))), + DatumGetCString(DirectFunctionCall1(int16out, Int128GetDatum(seq->max_value)))))); + } + + if (iscalled) { + AssignInt(&(elm->last), (int128)next); /* last returned number */ + errno_t rc = memcpy_s(&currval_seqdata, sizeof(SeqTableData), elm, sizeof(SeqTableData)); + securec_check(rc, "\0", "\0"); + AssignInt(&(result), (int128)next); + result_isvalid = true; + elm->last_valid = true; + } + + /* In any case, forget any future cached numbers */ + AssignInt(&(elm->cached), elm->last); + + /* ready to change the on-disk (or really, in-buffer) tuple */ + START_CRIT_SECTION(); + + /* keep the last value */ + AssignInt(&(seq->last_value), (T_Int)next); /* last fetched number */ + + seq->is_called = iscalled; + seq->log_cnt = 0; + + MarkBufferDirty(buf); + + /* XLOG stuff */ + if (RelationNeedsWAL(seqrel)) { + xl_seq_rec xlrec; + XLogRecPtr recptr; + Page page = BufferGetPage(buf); + + RelFileNodeRelCopy(xlrec.node, seqrel->rd_node); + + XLogBeginInsert(); + XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT); + XLogRegisterData((char*)&xlrec, sizeof(xl_seq_rec)); + XLogRegisterData((char*)seqtuple.t_data, seqtuple.t_len); + + recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG, seqrel->rd_node.bucketNode); + + PageSetLSN(page, recptr); + } + + END_CRIT_SECTION(); + UnlockReleaseBuffer(buf); + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + } + PG_CATCH(); + { + /* + * handle ereport error will reset InterruptHoldoffCount issue, if not handle, + * LWLockRelease will be failed on assert + */ + t_thrd.int_cxt.InterruptHoldoffCount = saveInterruptHoldoffCount; + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + pfree_ext(relname); + PG_RE_THROW(); + } + PG_END_TRY(); + + relation_close(seqrel, NoLock); + pfree_ext(relname); + + if (result_isvalid) { + copyLastValSequenceElem(&currval_seqdata, false); + global_sequence_cache_set_currval_elm(elm->relid, result); + } +} + +/* + * Implement the 2 arg setval procedure. + * See do_setval for discussion. + */ +Datum setval_oid(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + Numeric nextArg = PG_GETARG_NUMERIC(1); + int128 next = numeric_int16_internal(nextArg); + + Relation rel = relation_open(relid, NoLock); + char relkind = RelationGetRelkind(rel); + relation_close(rel, NoLock); + if (CheckSeqOwnedByAutoInc(relid)) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot change sequence owned by auto_increment column"))); } + bool is_global_cache = is_global_level_sequence_cache(relid); if (relkind == RELKIND_SEQUENCE) { - do_setval(relid, next, iscalled); + if (is_global_cache) { + do_setval_for_global_seq_cache(relid, next, true); + } else { + do_setval(relid, next, true); + } } else if (relkind == RELKIND_LARGE_SEQUENCE) { - do_setval(relid, next, iscalled); + if (is_global_cache) { + do_setval_for_global_seq_cache(relid, next, true); + } else { + do_setval(relid, next, true); + } + } + + PG_RETURN_NUMERIC(nextArg); +} + +/* + * Implement the 3 arg setval procedure. + * See do_setval for discussion. + */ +Datum setval3_oid(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + Numeric nextArg = PG_GETARG_NUMERIC(1); + int128 next = numeric_int16_internal(nextArg); + bool iscalled = PG_GETARG_BOOL(2); + + Relation rel = relation_open(relid, NoLock); + char relkind = RelationGetRelkind(rel); + relation_close(rel, NoLock); + if (CheckSeqOwnedByAutoInc(relid)) { + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot change sequence owned by auto_increment column"))); + } + bool is_global_cache = is_global_level_sequence_cache(relid); + if (relkind == RELKIND_SEQUENCE) { + if (is_global_cache) { + do_setval_for_global_seq_cache(relid, next, iscalled); + } else { + do_setval(relid, next, iscalled); + } + } else if (relkind == RELKIND_LARGE_SEQUENCE) { + if (is_global_cache) { + do_setval_for_global_seq_cache(relid, next, iscalled); + } else { + do_setval(relid, next, iscalled); + } } PG_RETURN_NUMERIC(nextArg); @@ -2030,7 +2551,7 @@ static T_Form read_seq_tuple(SeqTable elm, Relation rel, Buffer* buf, HeapTuple } template -static void CheckValueMinMax(T_Int value, T_Int minValue, T_Int maxValue, bool isStart) +static void CheckValueMinMax(T_Int value, T_Int minValue, T_Int maxValue, bool isStart, CACHE_LEVEL cache_level) { char* bufs = NULL; char* bufm = NULL; @@ -2040,18 +2561,30 @@ static void CheckValueMinMax(T_Int value, T_Int minValue, T_Int maxValue, bool i DatumGetCString(DirectFunctionCall1(int8out, value)); bufm = large ? DatumGetCString(DirectFunctionCall1(int16out, Int128GetDatum(minValue))) : DatumGetCString(DirectFunctionCall1(int8out, minValue)); - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("%s value (%s) cannot be less than MINVALUE (%s)", isStart? "START":"RESTART", bufs, bufm))); + if (cache_level == GLOBAL_LEVEL) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("%s value (%s) (or current value) cannot be less than MINVALUE (%s)", isStart? "START":"RESTART", bufs, bufm))); + } else { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("%s value (%s) cannot be less than MINVALUE (%s)", isStart? "START":"RESTART", bufs, bufm))); + } } if (value > maxValue) { bufs = large ? DatumGetCString(DirectFunctionCall1(int16out, Int128GetDatum(value))) : DatumGetCString(DirectFunctionCall1(int8out, value)); bufm = large ? DatumGetCString(DirectFunctionCall1(int16out, Int128GetDatum(maxValue))) : DatumGetCString(DirectFunctionCall1(int8out, maxValue)); - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("%s value (%s) cannot be greater than MAXVALUE (%s)", isStart? "START":"RESTART", bufs, bufm))); + if (cache_level == GLOBAL_LEVEL) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("%s value (%s) (or current value) cannot be less than MINVALUE (%s)", isStart? "START":"RESTART", bufs, bufm))); + } else { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("%s value (%s) cannot be less than MINVALUE (%s)", isStart? "START":"RESTART", bufs, bufm))); + } } } @@ -2088,6 +2621,7 @@ enum { DEF_IDX_MIN_VALUE, DEF_IDX_CACHE_VALUE, DEF_IDX_IS_CYCLED, + DEF_IDX_CACHE_LEVEL, DEF_IDX_NUM }; @@ -2137,6 +2671,10 @@ static void PreProcessSequenceOptions( } else if (strcmp(defel->defname, "owned_by") == 0) { CheckDuplicateDef(*owned_by); *owned_by = defGetQualifiedName(defel); + } else if (strcmp(defel->defname, "cache_level") == 0) { + CheckDuplicateDef(elms[DEF_IDX_CACHE_LEVEL]); + elms[DEF_IDX_CACHE_LEVEL] = defel; + *need_seq_rewrite = true; } else { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("option \"%s\" not recognized", defel->defname))); } @@ -2206,17 +2744,27 @@ static void ProcessSequenceOptMin(DefElem* elm, T_Form newm, bool isInit) } template -static void ProcessSequenceOptStartWith(DefElem* elm, T_Form newm, bool isInit) +static void ProcessSequenceOptStartWith(DefElem* elm, T_Form newm, bool isInit, SeqTable cache_elm) { - if (elm != NULL) + if (elm != NULL) { AssignInt(&(newm->start_value), defGetInt(elm)); + /* When the start value is set, the last_value should be recalculated. */ + if (newm->cache_level == GLOBAL_LEVEL) { + AssignInt(&(newm->last_value), newm->start_value); + newm->is_called = false; + if (cache_elm != NULL) { + AssignInt(&(cache_elm->last), (int128)newm->start_value); + cache_elm->last_valid = false; + } + } + } else if (isInit) { AssignInt(&(newm->start_value), (newm->increment_by > 0) ? newm->min_value : newm->max_value); } } template -static void ProcessSequenceOptReStartWith(DefElem* elm, T_Form newm, bool isInit, bool* is_restart, bool isUseLocalSeq) +static void ProcessSequenceOptReStartWith(DefElem* elm, T_Form newm, bool isInit, bool* is_restart, bool isUseLocalSeq, SeqTable cache_elm) { if (elm != NULL) { AssignInt(&(newm->last_value), @@ -2229,6 +2777,12 @@ static void ProcessSequenceOptReStartWith(DefElem* elm, T_Form newm, bool isInit } else if (isInit) { AssignInt(&(newm->last_value), (isUseLocalSeq) ? newm->start_value : (int128)-1); newm->is_called = false; + } else { + /* When using the global sequence cache, recycle the allocated sequence cache after alter sequence. */ + if (newm->cache_level == GLOBAL_LEVEL && cache_elm != NULL && cache_elm->last_valid) { + AssignInt(&(newm->last_value), cache_elm->last); + newm->is_called = true; + } } } @@ -2256,6 +2810,18 @@ static void ProcessSequenceOptCache(DefElem* elmCache, DefElem* elmMax, DefElem* } } +template +static void ProcessSequenceOptCacheLevel(DefElem* elm, T_Form newm, bool isInit) +{ + if (elm != NULL) { + newm->cache_level = (CACHE_LEVEL)intVal(elm->arg); + Assert(newm->cache_level == SESSION_LEVEL || newm->cache_level == GLOBAL_LEVEL); + newm->log_cnt = 0; + } else if (isInit) { + newm->cache_level = SESSION_LEVEL; + } +} + template static void CrossCheckMinMax(T_Int min, T_Int max) { @@ -2289,11 +2855,11 @@ static void CrossCheckMinMax(T_Int min, T_Int max) #ifdef PGXC template static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* newm_p, List** owned_by, - bool* is_restart, bool* need_seq_rewrite) + bool* is_restart, bool* need_seq_rewrite, SeqTable cache_elm) #else template static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* newm_p, List** owned_by, - bool* need_seq_rewrite) + bool* need_seq_rewrite, SeqTable cache_elm) #endif { T_Form newm = (T_Form)newm_p; @@ -2317,23 +2883,24 @@ static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* ne ProcessSequenceOptIncrementBy(elms[DEF_IDX_INCREMENT_BY], newm, isInit); ProcessSequenceOptCycle(elms[DEF_IDX_IS_CYCLED], newm, isInit); + ProcessSequenceOptCacheLevel(elms[DEF_IDX_CACHE_LEVEL], newm, isInit); ProcessSequenceOptMax(elms[DEF_IDX_MAX_VALUE], newm, isInit); ProcessSequenceOptMin(elms[DEF_IDX_MIN_VALUE], newm, isInit); /* crosscheck min/max */ CrossCheckMinMax(newm->min_value, newm->max_value); - ProcessSequenceOptStartWith(elms[DEF_IDX_START_VALUE], newm, isInit); + ProcessSequenceOptStartWith(elms[DEF_IDX_START_VALUE], newm, isInit, cache_elm); /* crosscheck START */ - CheckValueMinMax(newm->start_value, newm->min_value, newm->max_value, true); + CheckValueMinMax(newm->start_value, newm->min_value, newm->max_value, true, newm->cache_level); ProcessSequenceOptReStartWith( - elms[DEF_IDX_RESTART_VALUE], newm, isInit, is_restart, isUseLocalSeq); + elms[DEF_IDX_RESTART_VALUE], newm, isInit, is_restart, isUseLocalSeq, cache_elm); if (isUseLocalSeq) { /* crosscheck RESTART (or current value, if changing MIN/MAX) */ - CheckValueMinMax(newm->last_value, newm->min_value, newm->max_value, false); + CheckValueMinMax(newm->last_value, newm->min_value, newm->max_value, false, newm->cache_level); } ProcessSequenceOptCache( @@ -2443,44 +3010,75 @@ sequence_values *get_sequence_values(Oid sequenceId) HeapTupleData seqtuple; int64 uuid; Buffer buf; + uint32 hashCode; + GSCKey key; + uint32 bucket_id; sequence_values *seqvalues = NULL; - - /* - * Read the old sequence. This does a bit more work than really - * necessary, but it's simple, and we do want to double-check that it's - * indeed a sequence. - */ - init_sequence(sequenceId, &elm, &seq_rel); - - seqvalues = (sequence_values *)palloc(sizeof(sequence_values)); - seqvalues->large = (RelationGetRelkind(seq_rel) == RELKIND_LARGE_SEQUENCE); - - if (seqvalues->large) { - Form_pg_large_sequence seq = read_seq_tuple(elm, seq_rel, &buf, &seqtuple, &uuid); - seqvalues->sequence_name = pstrdup(seq->sequence_name.data); - seqvalues->is_cycled = seq->is_cycled; - seqvalues->last_value = Int8or16Out(seq->last_value); - seqvalues->start_value = Int8or16Out(seq->start_value); - seqvalues->increment_by = Int8or16Out(seq->increment_by); - seqvalues->max_value = Int8or16Out(seq->max_value); - seqvalues->min_value = Int8or16Out(seq->min_value); - seqvalues->cache_value = Int8or16Out(seq->cache_value); - UnlockReleaseBuffer(buf); - } else { - Form_pg_sequence seq = read_seq_tuple(elm, seq_rel, &buf, &seqtuple, &uuid); - seqvalues->sequence_name = pstrdup(seq->sequence_name.data); - seqvalues->is_cycled = seq->is_cycled; - seqvalues->last_value = Int8or16Out(seq->last_value); - seqvalues->start_value = Int8or16Out(seq->start_value); - seqvalues->increment_by = Int8or16Out(seq->increment_by); - seqvalues->max_value = Int8or16Out(seq->max_value); - seqvalues->min_value = Int8or16Out(seq->min_value); - seqvalues->cache_value = Int8or16Out(seq->cache_value); - UnlockReleaseBuffer(buf); + bool is_global_cache = is_global_level_sequence_cache(sequenceId); + + if (is_global_cache) { + /* lock the destination bucket to obtain the global cache */ + key.dbOid = u_sess->proc_cxt.MyDatabaseId; + key.relid = sequenceId; + hashCode = GSCHashFunc((const void *) &key, sizeof(GSCKey)); + bucket_id = GetGSCBucket(hashCode); + (void)LWLockAcquire(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id), LW_EXCLUSIVE); } - relation_close(seq_rel, NoLock); + PG_TRY(); + { + if (is_global_cache) { + init_sequence_single_node_global_cache(sequenceId, &elm, &seq_rel, &key, hashCode, bucket_id); + } else { + /* + * Read the old sequence. This does a bit more work than really + * necessary, but it's simple, and we do want to double-check that it's + * indeed a sequence. + */ + init_sequence(sequenceId, &elm, &seq_rel); + } + + seqvalues = (sequence_values *)palloc(sizeof(sequence_values)); + seqvalues->large = (RelationGetRelkind(seq_rel) == RELKIND_LARGE_SEQUENCE); + + if (seqvalues->large) { + Form_pg_large_sequence seq = read_seq_tuple(elm, seq_rel, &buf, &seqtuple, &uuid); + seqvalues->sequence_name = pstrdup(seq->sequence_name.data); + seqvalues->is_cycled = seq->is_cycled; + seqvalues->last_value = Int8or16Out(seq->last_value); + seqvalues->start_value = Int8or16Out(seq->start_value); + seqvalues->increment_by = Int8or16Out(seq->increment_by); + seqvalues->max_value = Int8or16Out(seq->max_value); + seqvalues->min_value = Int8or16Out(seq->min_value); + seqvalues->cache_value = Int8or16Out(seq->cache_value); + UnlockReleaseBuffer(buf); + } else { + Form_pg_sequence seq = read_seq_tuple(elm, seq_rel, &buf, &seqtuple, &uuid); + seqvalues->sequence_name = pstrdup(seq->sequence_name.data); + seqvalues->is_cycled = seq->is_cycled; + seqvalues->last_value = Int8or16Out(seq->last_value); + seqvalues->start_value = Int8or16Out(seq->start_value); + seqvalues->increment_by = Int8or16Out(seq->increment_by); + seqvalues->max_value = Int8or16Out(seq->max_value); + seqvalues->min_value = Int8or16Out(seq->min_value); + seqvalues->cache_value = Int8or16Out(seq->cache_value); + UnlockReleaseBuffer(buf); + } + + relation_close(seq_rel, NoLock); + if (is_global_cache) { + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + } + } + PG_CATCH(); + { + if (is_global_cache) { + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + } + PG_RE_THROW(); + } + PG_END_TRY(); return seqvalues; } @@ -2526,14 +3124,18 @@ Datum pg_sequence_parameters(PG_FUNCTION_ARGS) Relation seqrel; Buffer buf; HeapTupleData seqtuple; + uint32 hashCode; + GSCKey key; + uint32 bucket_id; + char* relname = NULL; + bool is_global_cache = is_global_level_sequence_cache(relid); - /* open and lock sequence */ - init_sequence(relid, &elm, &seqrel); + relname = get_rel_name(relid); if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT | ACL_UPDATE | ACL_USAGE) != ACLCHECK_OK) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("permission denied for sequence %s", RelationGetRelationName(seqrel)))); + errmsg("permission denied for sequence %s", relname))); tupdesc = CreateTemplateTupleDesc(5, false); TupleDescInitEntry(tupdesc, (AttrNumber)1, "start_value", INT16OID, -1, 0); @@ -2547,26 +3149,55 @@ Datum pg_sequence_parameters(PG_FUNCTION_ARGS) errno_t rc = memset_s(isnull, sizeof(isnull), 0, sizeof(isnull)); securec_check(rc, "\0", "\0"); - GTM_UUID uuid; - int i = 0; - if (large) { - Form_pg_large_sequence seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple, &uuid); - values[i++] = Int128GetDatum(seq->start_value); - values[i++] = Int128GetDatum(seq->min_value); - values[i++] = Int128GetDatum(seq->max_value); - values[i++] = Int128GetDatum(seq->increment_by); - values[i++] = BoolGetDatum(seq->is_cycled); - } else { - Form_pg_sequence seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple, &uuid); - values[i++] = Int128GetDatum((int128)seq->start_value); - values[i++] = Int128GetDatum((int128)seq->min_value); - values[i++] = Int128GetDatum((int128)seq->max_value); - values[i++] = Int128GetDatum((int128)seq->increment_by); - values[i++] = BoolGetDatum(seq->is_cycled); + if (is_global_cache) { + /* lock the destination bucket to obtain the global cache */ + key.dbOid = u_sess->proc_cxt.MyDatabaseId; + key.relid = relid; + hashCode = GSCHashFunc((const void *) &key, sizeof(GSCKey)); + bucket_id = GetGSCBucket(hashCode); + (void)LWLockAcquire(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id), LW_EXCLUSIVE); } - UnlockReleaseBuffer(buf); - relation_close(seqrel, NoLock); + PG_TRY(); + { + if (is_global_cache) { + init_sequence_single_node_global_cache(relid, &elm, &seqrel, &key, hashCode, bucket_id); + } else { + init_sequence(relid, &elm, &seqrel); + } + + GTM_UUID uuid; + int i = 0; + if (large) { + Form_pg_large_sequence seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple, &uuid); + values[i++] = Int128GetDatum(seq->start_value); + values[i++] = Int128GetDatum(seq->min_value); + values[i++] = Int128GetDatum(seq->max_value); + values[i++] = Int128GetDatum(seq->increment_by); + values[i++] = BoolGetDatum(seq->is_cycled); + } else { + Form_pg_sequence seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple, &uuid); + values[i++] = Int128GetDatum((int128)seq->start_value); + values[i++] = Int128GetDatum((int128)seq->min_value); + values[i++] = Int128GetDatum((int128)seq->max_value); + values[i++] = Int128GetDatum((int128)seq->increment_by); + values[i++] = BoolGetDatum(seq->is_cycled); + } + + UnlockReleaseBuffer(buf); + relation_close(seqrel, NoLock); + if (is_global_cache) { + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + } + } + PG_CATCH(); + { + if (is_global_cache) { + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + } + PG_RE_THROW(); + } + PG_END_TRY(); return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull)); } @@ -2585,14 +3216,18 @@ Datum pg_sequence_last_value(PG_FUNCTION_ARGS) Relation seqrel; Buffer buf; HeapTupleData seqtuple; + uint32 hashCode; + GSCKey key; + uint32 bucket_id; + char* relname = NULL; + bool is_global_cache = is_global_level_sequence_cache(relid); - /* open and lock sequence */ - init_sequence(relid, &elm, &seqrel); + relname = get_rel_name(relid); if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT | ACL_UPDATE | ACL_USAGE) != ACLCHECK_OK) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("permission denied for sequence %s", RelationGetRelationName(seqrel)))); + errmsg("permission denied for sequence %s", relname))); tupdesc = CreateTemplateTupleDesc(2, false); TupleDescInitEntry(tupdesc, (AttrNumber)1, "cache_value", INT16OID, -1, 0); @@ -2603,20 +3238,49 @@ Datum pg_sequence_last_value(PG_FUNCTION_ARGS) errno_t rc = memset_s(isnull, sizeof(isnull), 0, sizeof(isnull)); securec_check(rc, "\0", "\0"); - GTM_UUID uuid; - int i = 0; - if (large) { - Form_pg_large_sequence seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple, &uuid); - values[i++] = Int128GetDatum(seq->cache_value); - values[i++] = Int128GetDatum(seq->last_value); - } else { - Form_pg_sequence seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple, &uuid); - values[i++] = Int128GetDatum((int128)seq->cache_value); - values[i++] = Int128GetDatum((int128)seq->last_value); + if (is_global_cache) { + /* lock the destination bucket to obtain the global cache */ + key.dbOid = u_sess->proc_cxt.MyDatabaseId; + key.relid = relid; + hashCode = GSCHashFunc((const void *) &key, sizeof(GSCKey)); + bucket_id = GetGSCBucket(hashCode); + (void)LWLockAcquire(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id), LW_EXCLUSIVE); } - UnlockReleaseBuffer(buf); - relation_close(seqrel, NoLock); + PG_TRY(); + { + if (is_global_cache) { + init_sequence_single_node_global_cache(relid, &elm, &seqrel, &key, hashCode, bucket_id); + } else { + init_sequence(relid, &elm, &seqrel); + } + + GTM_UUID uuid; + int i = 0; + if (large) { + Form_pg_large_sequence seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple, &uuid); + values[i++] = Int128GetDatum(seq->cache_value); + values[i++] = Int128GetDatum(seq->last_value); + } else { + Form_pg_sequence seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple, &uuid); + values[i++] = Int128GetDatum((int128)seq->cache_value); + values[i++] = Int128GetDatum((int128)seq->last_value); + } + + UnlockReleaseBuffer(buf); + relation_close(seqrel, NoLock); + if (is_global_cache) { + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + } + } + PG_CATCH(); + { + if (is_global_cache) { + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + } + PG_RE_THROW(); + } + PG_END_TRY(); return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull)); } @@ -2828,6 +3492,10 @@ void processUpdateSequenceMsg(List* nameList, int64 lastvalue) Buffer buf; SeqTable elm = NULL; Relation seqrel; + uint32 hashCode; + GSCKey key; + uint32 bucket_id; + bool is_global_cache = false; /* * XXX: This is not safe in the presence of concurrent DDL, but acquiring * a lock here is more expensive than letting nextval_internal do it, @@ -2843,12 +3511,42 @@ void processUpdateSequenceMsg(List* nameList, int64 lastvalue) WARNING, (errcode(ERRCODE_OPERATE_FAILED), errmsg("Failed to find relation %s for sequence update", sequence->relname))); return; } - /* open and lock sequence */ - init_sequence(relid, &elm, &seqrel); - /* lock page' buffer and read tuple */ - seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple, &uuid); - updateNextValForSequence(buf, seq, seqtuple, seqrel, lastvalue); - relation_close(seqrel, NoLock); + + is_global_cache = is_global_level_sequence_cache(relid); + if (is_global_cache) { + /* lock the destination bucket to obtain the global cache */ + key.dbOid = u_sess->proc_cxt.MyDatabaseId; + key.relid = relid; + hashCode = GSCHashFunc((const void *) &key, sizeof(GSCKey)); + bucket_id = GetGSCBucket(hashCode); + (void)LWLockAcquire(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id), LW_EXCLUSIVE); + } + + PG_TRY(); + { + if (is_global_cache) { + init_sequence_single_node_global_cache(relid, &elm, &seqrel, &key, hashCode, bucket_id); + } else { + /* open and lock sequence */ + init_sequence(relid, &elm, &seqrel); + } + + /* lock page' buffer and read tuple */ + seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple, &uuid); + updateNextValForSequence(buf, seq, seqtuple, seqrel, lastvalue); + relation_close(seqrel, NoLock); + if (is_global_cache) { + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + } + } + PG_CATCH(); + { + if (is_global_cache) { + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + } + PG_RE_THROW(); + } + PG_END_TRY(); } #ifdef ENABLE_MULTIPLE_NODES @@ -3081,3 +3779,391 @@ static char* Int8or16Out(T_Int num) } return ret; } + +static void removeGlobalSeqCache_internal(Oid relid) +{ + uint32 hashCode; + GSCKey key; + uint32 bucket_id; + bool found = false; + key.dbOid = u_sess->proc_cxt.MyDatabaseId; + key.relid = relid; + hashCode = GSCHashFunc((const void *) &key, sizeof(GSCKey)); + bucket_id = GetGSCBucket(hashCode); + + (void)LWLockAcquire(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id), LW_EXCLUSIVE); + PG_TRY(); + { + (void *)hash_search_with_hash_value(g_instance.global_seqtab[bucket_id].hash_tbl, + (const void*)&key, hashCode, HASH_REMOVE, &found); + } + PG_CATCH(); + { + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + PG_RE_THROW(); + } + PG_END_TRY(); + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); +} + +static void removeGlobalSeqCacheForCurrval_internal(Oid relid) +{ + DListCell* elem_tmp = NULL; + DListCell* elm_cell = NULL; + SeqTable currseq = NULL; + + /* Look to see if we already have a seqtable entry for relation */ + dlist_foreach_cell(elem_tmp, u_sess->cmd_cxt.global_currval_seq) + { + currseq = (SeqTable)lfirst(elem_tmp); + if (currseq->relid == relid && currseq->dbOid == u_sess->proc_cxt.MyDatabaseId) { + elm_cell = elem_tmp; + break; + } + } + + if (elm_cell != NULL) { + u_sess->cmd_cxt.global_currval_seq = dlist_delete_cell(u_sess->cmd_cxt.global_currval_seq, elm_cell, true); + } +} + +static void removeSessionSeqScache_internal(Oid relid) +{ + SeqTable prevelm = NULL; + /* Look to see if we already have a seqtable entry for relation */ + SeqTable elm = u_sess->cmd_cxt.seqtab; + while (elm != NULL) { + if (elm->relid == relid) + break; + prevelm = elm; + elm = elm->next; + } + + if (elm != NULL) { + if (prevelm) { + prevelm->next = elm->next; + } else { + u_sess->cmd_cxt.seqtab = elm->next; + } + pfree_ext(elm); + } +} + +void removeSequenceCacheOfRelOid(List* relOids) +{ + ListCell *cell = NULL; + uint32 hashCode; + GSCOid2LevelKey key; + foreach (cell, relOids) { + Oid relOid = lfirst_oid(cell); + if (OidIsValid(relOid)) { + if (is_global_level_sequence_cache(relOid)) { + removeGlobalSeqCache_internal(relOid); + removeGlobalSeqCacheForCurrval_internal(relOid); + /* after drop sequence, we need clean lastval record */ + } else { + removeSessionSeqScache_internal(relOid); + /* after drop sequence, we need clean lastval record */ + } + u_sess->cmd_cxt.last_used_seq = NULL; + + /* remove mapping of seqoid to cache_level */ + key.dbOid = u_sess->proc_cxt.MyDatabaseId; + key.relid = relOid; + hashCode = GSCHashFunc((const void *) &key, sizeof(GSCOid2LevelKey)); + (void)LWLockAcquire(g_instance.oid_map_lock, LW_EXCLUSIVE); + PG_TRY(); + { + (void *)hash_search_with_hash_value(g_instance.relid2cachelevel, + (const void*)(&key), hashCode, HASH_REMOVE, NULL); + } + PG_CATCH(); + { + LWLockRelease(g_instance.oid_map_lock); + PG_RE_THROW(); + } + PG_END_TRY(); + LWLockRelease(g_instance.oid_map_lock); + } + } +} + +static void copyLastValSequenceElem(SeqTable elm, bool is_replace) +{ + errno_t rc = EOK; + if (u_sess->cmd_cxt.last_used_seq == NULL) { + u_sess->cmd_cxt.last_used_seq = (SeqTable)MemoryContextAlloc( + SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_OPTIMIZER), sizeof(SeqTableData)); + rc = memset_s(u_sess->cmd_cxt.last_used_seq, sizeof(SeqTableData), 0, sizeof(SeqTableData)); + securec_check(rc, "\0", "\0"); + } + if (is_replace || (u_sess->cmd_cxt.last_used_seq->relid == elm->relid && + u_sess->cmd_cxt.last_used_seq->dbOid == elm->dbOid)) { + rc = memcpy_s(u_sess->cmd_cxt.last_used_seq, sizeof(SeqTableData), elm, sizeof(SeqTableData)); + } + securec_check(rc, "\0", "\0"); +} + +template +uint32 GSCHashFunc(const void *key, Size keysize) +{ + const T_Type *item = reinterpret_cast(key); + uint32 val1 = DatumGetUInt32(hash_any((const unsigned char *)(&item->dbOid), sizeof(Oid))); + uint32 val2 = DatumGetUInt32(hash_any((const unsigned char *)(&item->relid), sizeof(Oid))); + val1 ^= val2; + + return val1; +} + +template +int GSCKeyMatch(const void *left, const void *right, Size keysize) +{ + const T_Type *leftItem = reinterpret_cast(left); + const T_Type *rightItem = reinterpret_cast(right); + Assert(NULL != leftItem); + Assert(NULL != rightItem); + + return (leftItem->dbOid != rightItem->dbOid || leftItem->relid != rightItem->relid) ? 1 : 0; +} + +uint32 GetGSCBucket(uint32 hashvalue) +{ + return (hashvalue % NUM_GSC_SINGLENODE_PARTITIONS); +} + +static void initGlobalSequenceCache() +{ + HASHCTL ctl; + errno_t rc = 0; + rc = memset_s(&ctl, sizeof(ctl), 0, sizeof(ctl)); + securec_check(rc, "\0", "\0"); + ctl.keysize = sizeof(GSCKey); + ctl.entrysize = sizeof(GSCEntry); + ctl.hash = (HashValueFunc)GSCHashFunc; + ctl.match = (HashCompareFunc)GSCKeyMatch; + + int flags = HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT | HASH_COMPARE | HASH_EXTERN_CONTEXT; + + for (int i = 0; i < NUM_GSC_SINGLENODE_PARTITIONS; ++i) { + g_instance.global_seqtab[i].lock_id = FirstGlobalSeqCacheLock + i; + ctl.hcxt = AllocSetContextCreate(g_instance.instance_context, + "GSCBucketContext", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE, + SHARED_CONTEXT); + g_instance.global_seqtab[i].hash_tbl = hash_create("GlobalSequenceCache", GSC_HTAB_SIZE, &ctl, flags); + } +} + +static void initCacheLevelHashTab() +{ + if (g_instance.relid2cachelevel == NULL) { + HASHCTL ctl; + errno_t rc = 0; + int flags = HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT | HASH_COMPARE | HASH_EXTERN_CONTEXT; + rc = memset_s(&ctl, sizeof(ctl), 0, sizeof(ctl)); + securec_check(rc, "\0", "\0"); + ctl.keysize = sizeof(GSCOid2LevelKey); + ctl.entrysize = sizeof(GSCOid2LevelEntry); + ctl.hash = (HashValueFunc)GSCHashFunc; + ctl.match = (HashCompareFunc)GSCKeyMatch; + ctl.hcxt = AllocSetContextCreate(g_instance.instance_context, + "GSCOid2CacheLevelContext", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE, + SHARED_CONTEXT); + g_instance.relid2cachelevel = hash_create("GlobalSeqCacheLevelMapCxt", GSC_HTAB_SIZE, &ctl, flags); + } + + if (g_instance.oid_map_lock == NULL) { + MemoryContext oldcontext = MemoryContextSwitchTo(g_instance.instance_context); + g_instance.oid_map_lock = LWLockAssign(LWTRANCHE_SEQ_OID_CACHE_LEVEL_MAP); + MemoryContextSwitchTo(oldcontext); + } + + if (g_instance.alter_sequence_lock == NULL) { + MemoryContext oldcontext = MemoryContextSwitchTo(g_instance.instance_context); + g_instance.alter_sequence_lock = LWLockAssign(LWTRANCHE_ALTER_SEQ_CACHE_LEVEL); + MemoryContextSwitchTo(oldcontext); + } +} + +/* + * Return sequence parameters + */ +template +static void get_sequence_cache_level(Relation rel, CACHE_LEVEL* cache_level) +{ + Buffer buf; + SeqTableData elm; + HeapTupleData seqtuple; + T_SeqType seq; + GTM_UUID uuid; + + seq = read_seq_tuple(&elm, rel, &buf, &seqtuple, &uuid); + + *cache_level = seq->cache_level; + + /* Now we're done with the old page */ + UnlockReleaseBuffer(buf); +} + +CACHE_LEVEL get_cache_level_from_oid(Oid relid) +{ + Relation relseq = relation_open(relid, AccessShareLock); + HeapTuple tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(tp)) { + relation_close(relseq, AccessShareLock); + LWLockRelease(g_instance.oid_map_lock); + ereport(ERROR, + (errcode(ERRCODE_CACHE_LOOKUP_FAILED), + errmsg("cache lookup failed for relation %u", relid))); + } + CACHE_LEVEL cache_level; + if (RelationGetRelkind(relseq) == RELKIND_LARGE_SEQUENCE) { + get_sequence_cache_level(relseq, &cache_level); + } else if (RelationGetRelkind(relseq) == RELKIND_SEQUENCE) { + get_sequence_cache_level(relseq, &cache_level); + } else { + ReleaseSysCache(tp); + relation_close(relseq, AccessShareLock); + LWLockRelease(g_instance.oid_map_lock); + ereport(ERROR, + (errcode(ERRCODE_CACHE_LOOKUP_FAILED), + errmsg("cache lookup failed for relation %u", relid))); + } + + ReleaseSysCache(tp); + relation_close(relseq, AccessShareLock); + return cache_level; +} + +bool is_global_level_sequence_cache(Oid relid) +{ + uint32 hashCode; + GSCOid2LevelKey key; + bool found = false; + GSCOid2LevelEntry *entry = NULL; + key.dbOid = u_sess->proc_cxt.MyDatabaseId; + key.relid = relid; + hashCode = GSCHashFunc((const void *) &key, sizeof(GSCOid2LevelKey)); + + /* first attempt use read lock to retrieve the mapping result from oid to cache level */ + (void)LWLockAcquire(g_instance.oid_map_lock, LW_SHARED); + PG_TRY(); + { + entry = (GSCOid2LevelEntry *)hash_search_with_hash_value(g_instance.relid2cachelevel, + (const void*)(&key), hashCode, HASH_FIND, &found); + } + PG_CATCH(); + { + LWLockRelease(g_instance.oid_map_lock); + PG_RE_THROW(); + } + PG_END_TRY(); + + if (found) { + LWLockRelease(g_instance.oid_map_lock); + return entry->val.is_global_cache; + } + LWLockRelease(g_instance.oid_map_lock); + + /* the first lookup requires inserting the mapping result into the hash table */ + (void)LWLockAcquire(g_instance.oid_map_lock, LW_EXCLUSIVE); + PG_TRY(); + { + entry = (GSCOid2LevelEntry *)hash_search_with_hash_value(g_instance.relid2cachelevel, + (const void*)(&key), hashCode, HASH_ENTER, &found); + } + PG_CATCH(); + { + LWLockRelease(g_instance.oid_map_lock); + PG_RE_THROW(); + } + PG_END_TRY(); + if (entry == NULL) { + LWLockRelease(g_instance.oid_map_lock); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_PSTATEMENT), + errmsg("store sequence cache level failed due to memory allocation failed"))); + } + /* check if any other session has already added it before acquiring the write lock */ + if (found == false) { + CACHE_LEVEL cache_level = get_cache_level_from_oid(relid); + entry->val.is_global_cache = (cache_level == GLOBAL_LEVEL) ? true : false; + } + LWLockRelease(g_instance.oid_map_lock); + return entry->val.is_global_cache; +} + +static bool is_alter_sequence_cache_level(List* options, CACHE_LEVEL cache_level) +{ + ListCell* option = NULL; + foreach (option, options) { + DefElem* defel = (DefElem*)lfirst(option); + if (strcmp(defel->defname, "cache_level") == 0) { + if ((CACHE_LEVEL)intVal(defel->arg) != cache_level) + return true; + } + } + return false; +} + +static int128 findlastedSequenceValueByOid(Oid relid, bool* isvalid) +{ + DListCell* elem_tmp = NULL; + SeqTable currseq = NULL; + + /* Look to see if we already have a seqtable entry for relation */ + dlist_foreach_cell(elem_tmp, u_sess->cmd_cxt.global_currval_seq) + { + currseq = (SeqTable)lfirst(elem_tmp); + if (currseq->relid == relid && currseq->dbOid == u_sess->proc_cxt.MyDatabaseId) { + break; + } + currseq = NULL; + } + *isvalid = currseq ? true : false; + return currseq ? currseq->last : 0; +} + +static void changeSequenceCacheLevel(Oid relid) +{ + uint32 hashCode; + GSCOid2LevelKey key; + bool found = false; + GSCOid2LevelEntry *entry = NULL; + key.dbOid = u_sess->proc_cxt.MyDatabaseId; + key.relid = relid; + hashCode = GSCHashFunc((const void *) &key, sizeof(GSCOid2LevelKey)); + + (void)LWLockAcquire(g_instance.oid_map_lock, LW_EXCLUSIVE); + int saveInterruptHoldoffCount = t_thrd.int_cxt.InterruptHoldoffCount; + PG_TRY(); + { + entry = (GSCOid2LevelEntry *)hash_search_with_hash_value(g_instance.relid2cachelevel, + (const void*)(&key), hashCode, HASH_FIND, &found); + } + PG_CATCH(); + { + /* + * handle ereport error will reset InterruptHoldoffCount issue, if not handle, + * LWLockRelease will be failed on assert + */ + t_thrd.int_cxt.InterruptHoldoffCount = saveInterruptHoldoffCount; + LWLockRelease(g_instance.oid_map_lock); + PG_RE_THROW(); + } + PG_END_TRY(); + + if (entry == NULL || !found) { + LWLockRelease(g_instance.oid_map_lock); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_PSTATEMENT), + errmsg("store sequence cache level failed due to memory allocation failed"))); + } + entry->val.is_global_cache = !entry->val.is_global_cache; + LWLockRelease(g_instance.oid_map_lock); +} \ No newline at end of file diff --git a/src/gausskernel/optimizer/commands/sequence/sequence_util.cpp b/src/gausskernel/optimizer/commands/sequence/sequence_util.cpp index 876b776bb2..55d7de5077 100644 --- a/src/gausskernel/optimizer/commands/sequence/sequence_util.cpp +++ b/src/gausskernel/optimizer/commands/sequence/sequence_util.cpp @@ -234,6 +234,163 @@ void init_sequence(Oid relid, SeqTable* p_elm, Relation* p_rel) *p_rel = seqrel; } +SeqTable searchGlobalSequenceCacheFromHashTab(GSCKey* key, uint32 hashCode, uint32 bucket_id) +{ + GSCEntry *entry = NULL; + Assert (bucket_id >= 0 && bucket_id < NUM_GSC_SINGLENODE_PARTITIONS); + bool found = false; + entry = (GSCEntry *)hash_search_with_hash_value(g_instance.global_seqtab[bucket_id].hash_tbl, + (const void*)key, hashCode, HASH_ENTER, &found); + if (entry == NULL) { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_PSTATEMENT), + errmsg("store global sequence cache failed due to memory allocation failed"))); + } + + if (found == false) { + errno_t rc = EOK; + rc = memset_s(entry, sizeof(GSCEntry), 0, sizeof(GSCEntry)); + securec_check(rc, "\0", "\0"); + entry->key.dbOid = key->dbOid; + entry->key.relid = key->relid; + entry->val.elm.relid = key->relid; + entry->val.elm.dbOid = key->dbOid; + entry->val.elm.is_global_cache = true; + + /* + * Open the sequence relation. + */ + Relation seqrel = lock_and_open_seq(&(entry->val.elm)); + if (!RELKIND_IS_SEQUENCE(seqrel->rd_rel->relkind)) { + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s.%s\" is not a sequence", get_namespace_name(RelationGetNamespace(seqrel)), RelationGetRelationName(seqrel)))); + } else { + entry->val.elm.seqkind = seqrel->rd_rel->relkind; + } + relation_close(seqrel, NoLock); + } + return &(entry->val.elm); +} + +/* + * Given a relation OID, open and lock the sequence. p_elm and p_rel are + * output parameters, and p_elm is global sequence cache elm. + */ +void init_sequence_single_node_global_cache(Oid relid, SeqTable* p_elm, Relation* p_rel, GSCKey* key, uint32 hashCode, uint32 bucket_id) +{ + SeqTable elm = NULL; + Relation seqrel; + + elm = searchGlobalSequenceCacheFromHashTab(key, hashCode, bucket_id); + + if (p_rel != NULL) { + /* + * Open the sequence relation. + */ + seqrel = lock_and_open_seq(elm); + if (!RELKIND_IS_SEQUENCE(seqrel->rd_rel->relkind)) { + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s.%s\" is not a sequence", get_namespace_name(RelationGetNamespace(seqrel)), RelationGetRelationName(seqrel)))); + } + *p_rel = seqrel; + } + + *p_elm = elm; +} + +/* + * Given a relation OID, open and lock the sequence. p_elm and p_rel are + * output parameters, and p_elm is global sequence cache elm for currval. + */ +void init_sequence_single_node_global_cache_for_currval(Oid relid, SeqTable* p_elm, Relation* p_rel) +{ + SeqTable elm = NULL; + Relation seqrel; + DListCell* elem_tmp = NULL; + SeqTable currseq = NULL; + + dlist_foreach_cell(elem_tmp, u_sess->cmd_cxt.global_currval_seq) + { + currseq = (SeqTable)lfirst(elem_tmp); + if (currseq->relid == relid && currseq->dbOid == u_sess->proc_cxt.MyDatabaseId) { + elm = currseq; + break; + } + } + + /* + * Allocate new seqtable entry if we didn't find one. + * + * NOTE: seqtable entries remain in the list for the life of a backend. If + * the sequence itself is deleted then the entry becomes wasted memory, + * but it's small enough that this should not matter. + */ + if (elm == NULL) { + /* + * Time to make a new seqtable entry. These entries live as long as + * the backend does, so we use plain malloc for them. + */ + elm = (SeqTable)MemoryContextAlloc( + SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_OPTIMIZER), sizeof(SeqTableData)); + errno_t rc = EOK; + rc = memset_s(elm, sizeof(SeqTableData), 0, sizeof(SeqTableData)); + securec_check(rc, "\0", "\0"); + elm->relid = relid; + elm->dbOid = u_sess->proc_cxt.MyDatabaseId; + + MemoryContext oldcontext = MemoryContextSwitchTo(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_OPTIMIZER)); + u_sess->cmd_cxt.global_currval_seq = dlappend(u_sess->cmd_cxt.global_currval_seq, elm); + (void)MemoryContextSwitchTo(oldcontext); + } + + /* + * Open the sequence relation. + */ + seqrel = lock_and_open_seq(elm); + if (!RELKIND_IS_SEQUENCE(seqrel->rd_rel->relkind)) { + if (seqrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP) { + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s.%s\" is not a sequence", get_namespace_name(RelationGetNamespace(seqrel)), RelationGetRelationName(seqrel)), + errdetail("Please make sure using the correct schema"))); + } else { + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s.%s\" is not a sequence", get_namespace_name(RelationGetNamespace(seqrel)), RelationGetRelationName(seqrel)))); + } + } + /* + * If the sequence has been transactionally replaced since we last saw it, + * discard any cached-but-unissued values. We do not touch the currval() + * state, however. + */ + if (seqrel->rd_rel->relfilenode != elm->filenode) { + elm->filenode = seqrel->rd_rel->relfilenode; + errno_t rc = memcpy_s(&(elm->cached), sizeof(int128), &(elm->last), sizeof(int128)); + securec_check(rc, "\0", "\0"); + } + + /* Return results */ + *p_elm = elm; + *p_rel = seqrel; +} + +/* for global sequence cache record currval elm */ +void global_sequence_cache_set_currval_elm(Oid relid, int128 value) +{ + SeqTable elm = NULL; + Relation seqrel; + + /* open and lock sequence */ + init_sequence_single_node_global_cache_for_currval(relid, &elm, &seqrel); + + elm->last = value; + elm->last_valid = true; + relation_close(seqrel, NoLock); +} + SeqTable GetSessSeqElm(Oid relid) { SeqTable elm = NULL; @@ -358,11 +515,43 @@ bool IsTempSequence(Oid relid) bool res = false; SeqTable elm = NULL; - /* open and lock sequence */ - init_sequence(relid, &elm, &seqrel); + uint32 hashCode; + GSCKey key; + uint32 bucket_id; + bool is_global_cache = is_global_level_sequence_cache(relid); + + if (is_global_cache) { + /* lock the destination bucket to obtain the global cache */ + key.dbOid = u_sess->proc_cxt.MyDatabaseId; + key.relid = relid; + hashCode = GSCHashFunc((const void *) &key, sizeof(GSCKey)); + bucket_id = GetGSCBucket(hashCode); + (void)LWLockAcquire(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id), LW_EXCLUSIVE); + } - res = RelationIsLocalTemp(seqrel); - relation_close(seqrel, NoLock); + PG_TRY(); + { + if (is_global_cache) { + init_sequence_single_node_global_cache(relid, &elm, &seqrel, &key, hashCode, bucket_id); + } else { + init_sequence(relid, &elm, &seqrel); + } + + res = RelationIsLocalTemp(seqrel); + relation_close(seqrel, NoLock); + + if (is_global_cache) { + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + } + } + PG_CATCH(); + { + if (is_global_cache) { + LWLockRelease(GetMainLWLockByIndex(g_instance.global_seqtab[bucket_id].lock_id)); + } + PG_RE_THROW(); + } + PG_END_TRY(); return res; } #endif diff --git a/src/gausskernel/optimizer/commands/tablecmds.cpp b/src/gausskernel/optimizer/commands/tablecmds.cpp index 88e3c4214b..9073aa626e 100755 --- a/src/gausskernel/optimizer/commands/tablecmds.cpp +++ b/src/gausskernel/optimizer/commands/tablecmds.cpp @@ -3627,6 +3627,7 @@ void RemoveRelations(DropStmt* drop, StringInfo tmp_queryString, RemoteQueryExec StringInfo relation_namelist = makeStringInfo(); char relPersistence; List *typlist = NULL; + List *seqOids = NIL; /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */ if (drop->concurrent) { @@ -3772,6 +3773,11 @@ void RemoveRelations(DropStmt* drop, StringInfo tmp_queryString, RemoteQueryExec relOid = RangeVarGetRelidExtended( rel, lockmode, true, false, false, false, RangeVarCallbackForDropRelation, (void*)&state); + /* record sequence reloid if drop sequence */ + if (drop->removeType == OBJECT_SEQUENCE || drop->removeType == OBJECT_LARGE_SEQUENCE) { + seqOids = lappend_oid(seqOids, relOid); + } + /* * Relation not found. * @@ -3896,6 +3902,11 @@ void RemoveRelations(DropStmt* drop, StringInfo tmp_queryString, RemoteQueryExec performMultipleDeletions(objects, drop->behavior, flags); } + /* drop global sequence cache after drop sequence */ + if (drop->removeType == OBJECT_SEQUENCE || drop->removeType == RELKIND_LARGE_SEQUENCE) { + removeSequenceCacheOfRelOid(seqOids); + } + free_object_addresses(objects); pfree_ext(relation_namelist->data); pfree_ext(relation_namelist); @@ -33357,7 +33368,11 @@ static int128 EvaluateAutoIncrement(Relation rel, TupleDesc desc, AttrNumber att if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP) { autoinc = tmptable_autoinc_nextval(rel->rd_rel->relfilenode, cons_autoinc->next); } else { - autoinc = nextval_internal(cons_autoinc->seqoid); + if (is_global_level_sequence_cache(cons_autoinc->seqoid)) { + autoinc = nextval_internal_for_global_seq_cache(cons_autoinc->seqoid); + } else { + autoinc = nextval_internal(cons_autoinc->seqoid); + } } if (modify_value) { *is_null = false; diff --git a/src/gausskernel/process/threadpool/knl_session.cpp b/src/gausskernel/process/threadpool/knl_session.cpp index 3cc387b5ad..3286b0dbc2 100755 --- a/src/gausskernel/process/threadpool/knl_session.cpp +++ b/src/gausskernel/process/threadpool/knl_session.cpp @@ -29,6 +29,7 @@ #include "access/xlogdefs.h" #include "access/ustore/knl_uundovec.h" #include "commands/tablespace.h" +#include "commands/sequence.h" #include "executor/instrument.h" #include "gssignal/gs_signal.h" #include "mb/pg_wchar.h" @@ -649,6 +650,7 @@ void knl_u_commands_init(knl_u_commands_context* cmd_cxt) cmd_cxt->seqtab = NULL; cmd_cxt->last_used_seq = NULL; + cmd_cxt->global_currval_seq = NULL; cmd_cxt->TypeCreateType = '\0'; diff --git a/src/gausskernel/runtime/executor/execUtils.cpp b/src/gausskernel/runtime/executor/execUtils.cpp index 71b4a51f45..1ced2402b5 100644 --- a/src/gausskernel/runtime/executor/execUtils.cpp +++ b/src/gausskernel/runtime/executor/execUtils.cpp @@ -1678,7 +1678,11 @@ Tuple ExecAutoIncrement(Relation rel, EState* estate, TupleTableSlot* slot, Tupl autoinc = estate->next_autoinc; estate->next_autoinc = 0; } else { - autoinc = nextval_internal(cons_autoinc->seqoid); + if (is_global_level_sequence_cache(cons_autoinc->seqoid)) { + autoinc = nextval_internal_for_global_seq_cache(cons_autoinc->seqoid); + } else { + autoinc = nextval_internal(cons_autoinc->seqoid); + } } } diff --git a/src/gausskernel/storage/lmgr/lwlock.cpp b/src/gausskernel/storage/lmgr/lwlock.cpp index d84b43345d..bc14c1b7c9 100644 --- a/src/gausskernel/storage/lmgr/lwlock.cpp +++ b/src/gausskernel/storage/lmgr/lwlock.cpp @@ -205,7 +205,10 @@ static const char *BuiltinTrancheNames[] = { "SSSnapshotXminCachePartLock", "DmsBufCtrlLock", "WalSyncRepWaitLock", - "ScaningXLogTrackLock" + "ScaningXLogTrackLock", + "GlobalSequenceCacheLock", + "SequenceOidMapCacheLevelLock", + "AlterSequneceCacheLevelLock" }; static void RegisterLWLockTranches(void); @@ -684,6 +687,10 @@ static void InitializeLWLocks(int numLocks) LWLockInitialize(&lock->lock, LWTRANCHE_SCANNING_XLOG_TRACK); } + for (id = 0; id < NUM_GSC_SINGLENODE_PARTITIONS; id++, lock++) { + LWLockInitialize(&lock->lock, LWTRANCHE_GLOBAL_SEQ_CACHE); + } + Assert((lock - t_thrd.shemem_ptr_cxt.mainLWLockArray) == NumFixedLWLocks); for (id = NumFixedLWLocks; id < numLocks; id++, lock++) { diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h index 9fbf008523..d2e4d6a2b3 100644 --- a/src/include/commands/sequence.h +++ b/src/include/commands/sequence.h @@ -36,6 +36,11 @@ typedef int64 GTM_UUID; +enum CACHE_LEVEL { + SESSION_LEVEL = 0, // session cache, such as "create sequence seq_test session;" + GLOBAL_LEVEL // global cache, such as "create sequence seq_test global;" +}; + typedef struct FormData_pg_sequence { NameData sequence_name; int64 last_value; @@ -48,6 +53,7 @@ typedef struct FormData_pg_sequence { bool is_cycled; bool is_called; GTM_UUID uuid; + CACHE_LEVEL cache_level; } FormData_pg_sequence; typedef FormData_pg_sequence* Form_pg_sequence; @@ -64,6 +70,7 @@ typedef struct FormData_pg_large_sequence { bool is_cycled; bool is_called; GTM_UUID uuid; + CACHE_LEVEL cache_level; } FormData_pg_large_sequence; typedef FormData_pg_large_sequence* Form_pg_large_sequence; @@ -83,9 +90,10 @@ typedef FormData_pg_large_sequence* Form_pg_large_sequence; #define SEQ_COL_CYCLE 9 #define SEQ_COL_CALLED 10 #define SEQ_COL_UUID 11 +#define SEQ_COL_CACHELEVEL 12 #define SEQ_COL_FIRSTCOL SEQ_COL_NAME -#define SEQ_COL_LASTCOL SEQ_COL_UUID +#define SEQ_COL_LASTCOL SEQ_COL_CACHELEVEL #define GS_NUM_OF_BUCKETS 1024 @@ -119,6 +127,9 @@ typedef struct SeqTableData { int128 maxval; int128 startval; int64 uuid; + Oid dbOid; /* record database oid for global sequence cache */ + char seqkind; /* record sequence kind */ + bool is_global_cache; /* sequence cache level is global */ } SeqTableData; typedef SeqTableData* SeqTable; @@ -150,6 +161,43 @@ typedef struct sequence_values bool is_cycled; } sequence_values; +typedef struct GSCKey +{ + Oid dbOid; /* record database oid for global sequence cache */ + Oid relid; +} GSCKey; + +typedef struct GSCVal +{ + SeqTableData elm; + Oid dbOid; +} GSCVal; + +typedef struct GSCEntry +{ + GSCKey key; + GSCVal val; +} GSCEntry; + +typedef struct GSCOid2LevelKey +{ + Oid dbOid; /* record database oid for global sequence cache */ + Oid relid; +} GSCOid2LevelKey; + +typedef struct GSCOid2LevelVal +{ + bool is_global_cache; +} GSCOid2LevelVal; + +typedef struct GSCOid2LevelEntry +{ + GSCOid2LevelKey key; + GSCOid2LevelVal val; +} GSCOid2LevelEntry; + +#define GSC_HTAB_SIZE (128) + /* * We don't want to log each fetching of a value from a sequence, * so we pre-log a few fetches in advance. In the event of @@ -179,6 +227,7 @@ extern Datum pg_sequence_parameters(PG_FUNCTION_ARGS); extern Datum pg_sequence_last_value(PG_FUNCTION_ARGS); extern int128 nextval_internal(Oid relid); +extern int128 nextval_internal_for_global_seq_cache(Oid relid); extern void autoinc_setval(Oid relid, int128 next, bool iscalled); extern int128 autoinc_get_nextval(Oid relid); extern bool CheckSeqOwnedByAutoInc(Oid seqoid); @@ -252,9 +301,17 @@ extern void fill_seq_with_data(Relation rel, HeapTuple tuple); extern void ResetvalGlobal(Oid relid); extern Relation lock_and_open_seq(SeqTable seq); extern void init_sequence(Oid relid, SeqTable* p_elm, Relation* p_rel); +extern void init_sequence_single_node_global_cache(Oid relid, SeqTable* p_elm, Relation* p_rel, GSCKey* key, uint32 hashCode, uint32 bucket_id); +extern void init_sequence_single_node_global_cache_for_currval(Oid relid, SeqTable* p_elm, Relation* p_rel); +extern void global_sequence_cache_set_currval_elm(Oid relid, int128 value); +extern void removeSequenceCacheOfRelOid(List* relOids); extern SeqTable GetSessSeqElm(Oid relid); extern char* GetGlobalSeqNameForUpdate(Relation seqrel, char** dbname, char** schemaname); extern uint32 RelidGetHash(Oid seq_relid); +extern uint32 GetGSCBucket(uint32 hashvalue); extern SeqTable GetGlobalSeqElm(Oid relid, GlobalSeqInfoHashBucket* bucket); +template +extern uint32 GSCHashFunc(const void *key, Size keysize); +extern bool is_global_level_sequence_cache(Oid relid); #endif /* SEQUENCE_H */ diff --git a/src/include/knl/knl_instance.h b/src/include/knl/knl_instance.h index 9ccabe73a5..59c9c522cc 100755 --- a/src/include/knl/knl_instance.h +++ b/src/include/knl/knl_instance.h @@ -1078,6 +1078,11 @@ typedef struct GlobalSeqInfoHashBucket { int lock_id; } GlobalSeqInfoHashBucket; +typedef struct GSCHashCtl { + int lock_id; + HTAB* hash_tbl; +} GSCHashCtl; + typedef struct knl_g_archive_context { XLogRecPtr barrierLsn; char barrierName[MAX_BARRIER_ID_LENGTH]; @@ -1342,6 +1347,10 @@ typedef struct knl_instance_context { bool dummy_standby; struct GlobalSeqInfoHashBucket global_seq[NUM_GS_PARTITIONS]; + struct GSCHashCtl global_seqtab[NUM_GSC_SINGLENODE_PARTITIONS]; + HTAB* relid2cachelevel; + LWLock *oid_map_lock; + LWLock *alter_sequence_lock; struct GlobalPlanCache* plan_cache; diff --git a/src/include/knl/knl_session.h b/src/include/knl/knl_session.h index 0f078c1447..c71e54f789 100644 --- a/src/include/knl/knl_session.h +++ b/src/include/knl/knl_session.h @@ -835,6 +835,11 @@ typedef struct knl_u_commands_context { * sequence. */ struct SeqTableData* last_used_seq; + /* + * global_currval_seq is updated by nextval() to point to the current used + * global sequence cache. + */ + DList* global_currval_seq; /* Form of the type created during inplace upgrade */ char TypeCreateType; diff --git a/src/include/storage/lock/lwlock.h b/src/include/storage/lock/lwlock.h index 63972fd490..0ff0a52a42 100644 --- a/src/include/storage/lock/lwlock.h +++ b/src/include/storage/lock/lwlock.h @@ -148,6 +148,9 @@ const struct LWLOCK_PARTITION_DESC LWLockPartInfo[] = { /* Number of standby statement hsitory needed */ #define NUM_STANDBY_STMTHIST_PARTITIONS 2 +/* Number of partions the global sequence cache hashtable */ +#define NUM_GSC_SINGLENODE_PARTITIONS 1024 + /* Number of partitions of the txnstatus mapping hashtable */ #define NUM_TXNSTATUS_CACHE_PARTITIONS 256 @@ -210,9 +213,11 @@ const struct LWLOCK_PARTITION_DESC LWLockPartInfo[] = { #define FirstSSSnapshotXminCacheLock (FirstTxnStatusCacheLock + NUM_TXNSTATUS_CACHE_PARTITIONS) /* xlog track hashmap */ #define FirstScanningXLOGTrackLock (FirstSSSnapshotXminCacheLock + NUM_SS_SNAPSHOT_XMIN_CACHE_PARTITIONS) +/* global sequence cache */ +#define FirstGlobalSeqCacheLock (FirstScanningXLOGTrackLock + NUM_SCANNING_XLOG_TRACK_PARTITIONS) /* must be last: */ -#define NumFixedLWLocks (FirstScanningXLOGTrackLock + NUM_SCANNING_XLOG_TRACK_PARTITIONS) +#define NumFixedLWLocks (FirstGlobalSeqCacheLock + NUM_GSC_SINGLENODE_PARTITIONS) /* * WARNING----Please keep BuiltinTrancheIds and BuiltinTrancheNames consistent!!! * @@ -297,6 +302,9 @@ enum BuiltinTrancheIds LWTRANCHE_DMS_BUF_CTRL, LWTRANCHE_SYNCREP_WAIT, LWTRANCHE_SCANNING_XLOG_TRACK, + LWTRANCHE_GLOBAL_SEQ_CACHE, + LWTRANCHE_SEQ_OID_CACHE_LEVEL_MAP, + LWTRANCHE_ALTER_SEQ_CACHE_LEVEL, /* * Each trancheId above should have a corresponding item in BuiltinTrancheNames; */ diff --git a/src/test/regress/expected/alter_seq_max_in_txn.out b/src/test/regress/expected/alter_seq_max_in_txn.out index 0d9590495a..55383a04d8 100644 --- a/src/test/regress/expected/alter_seq_max_in_txn.out +++ b/src/test/regress/expected/alter_seq_max_in_txn.out @@ -6,45 +6,45 @@ create sequence seqa maxvalue 50; --test what sequence would be like before/after ALTER SEQUENCE MAXVALUE txns' rollback begin; select * from seqa; - sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid ----------------+------------+-------------+--------------+-----------+-----------+-------------+---------+-----------+-----------+------ - seqa | 1 | 1 | 1 | 50 | 1 | 1 | 0 | f | f | 0 + sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid | cache_level +---------------+------------+-------------+--------------+-----------+-----------+-------------+---------+-----------+-----------+------+------------- + seqa | 1 | 1 | 1 | 50 | 1 | 1 | 0 | f | f | 0 | 0 (1 row) alter sequence seqa maxvalue 40; select * from seqa; - sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid ----------------+------------+-------------+--------------+-----------+-----------+-------------+---------+-----------+-----------+------ - seqa | 1 | 1 | 1 | 40 | 1 | 1 | 0 | f | f | 0 + sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid | cache_level +---------------+------------+-------------+--------------+-----------+-----------+-------------+---------+-----------+-----------+------+------------- + seqa | 1 | 1 | 1 | 40 | 1 | 1 | 0 | f | f | 0 | 0 (1 row) rollback; select * from seqa; - sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid ----------------+------------+-------------+--------------+-----------+-----------+-------------+---------+-----------+-----------+------ - seqa | 1 | 1 | 1 | 50 | 1 | 1 | 0 | f | f | 0 + sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid | cache_level +---------------+------------+-------------+--------------+-----------+-----------+-------------+---------+-----------+-----------+------+------------- + seqa | 1 | 1 | 1 | 50 | 1 | 1 | 0 | f | f | 0 | 0 (1 row) --test what sequence would be like before/after ALTER SEQUENCE MAXVALUE txns' rollback begin; select * from seqa; - sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid ----------------+------------+-------------+--------------+-----------+-----------+-------------+---------+-----------+-----------+------ - seqa | 1 | 1 | 1 | 50 | 1 | 1 | 0 | f | f | 0 + sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid | cache_level +---------------+------------+-------------+--------------+-----------+-----------+-------------+---------+-----------+-----------+------+------------- + seqa | 1 | 1 | 1 | 50 | 1 | 1 | 0 | f | f | 0 | 0 (1 row) alter sequence seqa maxvalue 40; select * from seqa; - sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid ----------------+------------+-------------+--------------+-----------+-----------+-------------+---------+-----------+-----------+------ - seqa | 1 | 1 | 1 | 40 | 1 | 1 | 0 | f | f | 0 + sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid | cache_level +---------------+------------+-------------+--------------+-----------+-----------+-------------+---------+-----------+-----------+------+------------- + seqa | 1 | 1 | 1 | 40 | 1 | 1 | 0 | f | f | 0 | 0 (1 row) commit; select * from seqa; - sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid ----------------+------------+-------------+--------------+-----------+-----------+-------------+---------+-----------+-----------+------ - seqa | 1 | 1 | 1 | 40 | 1 | 1 | 0 | f | f | 0 + sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid | cache_level +---------------+------------+-------------+--------------+-----------+-----------+-------------+---------+-----------+-----------+------+------------- + seqa | 1 | 1 | 1 | 40 | 1 | 1 | 0 | f | f | 0 | 0 (1 row) DROP SCHEMA test_alter_seq_max_in_txn_01 CASCADE; diff --git a/src/test/regress/expected/large_sequence.out b/src/test/regress/expected/large_sequence.out index 835fac0b61..bfece50dba 100644 --- a/src/test/regress/expected/large_sequence.out +++ b/src/test/regress/expected/large_sequence.out @@ -34,6 +34,7 @@ CREATE LARGE SEQUENCE S2; is_cycled | boolean | f is_called | boolean | f uuid | bigint | 0 + cache_level | bigint | 0 \d S2 Large Sequence "large_sequence.s2" @@ -50,6 +51,7 @@ CREATE LARGE SEQUENCE S2; is_cycled | boolean | f is_called | boolean | f uuid | bigint | 0 + cache_level | int16 | 0 COMMENT ON LARGE SEQUENCE S2 IS 'FOO'; COMMENT ON LARGE SEQUENCE S2 IS NULL; @@ -367,9 +369,9 @@ CREATE LARGE SEQUENCE foo; ALTER LARGE SEQUENCE foo RENAME TO bar; ERROR: RENAME SEQUENCE is not yet supported. SELECT * FROM foo; - sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid ----------------+------------+-------------+--------------+-----------------------------------------+-----------+-------------+---------+-----------+-----------+------ - foo | 1 | 1 | 1 | 170141183460469231731687303715884105727 | 1 | 1 | 0 | f | f | 0 + sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid | cache_level +---------------+------------+-------------+--------------+-----------------------------------------+-----------+-------------+---------+-----------+-----------+------+------------- + foo | 1 | 1 | 1 | 170141183460469231731687303715884105727 | 1 | 1 | 0 | f | f | 0 | 0 (1 row) -- alter maxvalue - ok @@ -625,9 +627,9 @@ GRANT SELECT ON priv_seq TO zeus; GRANT ALL ON SCHEMA large_sequence TO zeus; SET ROLE zeus PASSWORD '123qwe!@#'; SELECT * FROM priv_seq; - sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid ----------------+------------+-------------+--------------+-----------------------------------------+-----------+-------------+---------+-----------+-----------+------ - priv_seq | 1 | 1 | 1 | 170141183460469231731687303715884105727 | 1 | 1 | 0 | f | f | 0 + sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid | cache_level +---------------+------------+-------------+--------------+-----------------------------------------+-----------+-------------+---------+-----------+-----------+------+------------- + priv_seq | 1 | 1 | 1 | 170141183460469231731687303715884105727 | 1 | 1 | 0 | f | f | 0 | 0 (1 row) \d priv_seq @@ -645,6 +647,7 @@ SELECT * FROM priv_seq; is_cycled | boolean | f is_called | boolean | f uuid | bigint | 0 + cache_level | int16 | 0 SELECT nextval('priv_seq'); ERROR: permission denied for sequence priv_seq @@ -717,9 +720,9 @@ GRANT ALL ON ALL SEQUENCES IN SCHEMA seq_priv_schema TO zeus; SET ROLE zeus PASSWORD '123qwe!@#'; SET current_schema = seq_priv_schema; SELECT * FROM priv_seq; - sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid ----------------+------------+-------------+--------------+-----------------------------------------+-----------+-------------+---------+-----------+-----------+------ - priv_seq | 1 | 1 | 1 | 170141183460469231731687303715884105727 | 1 | 1 | 0 | f | f | 0 + sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid | cache_level +---------------+------------+-------------+--------------+-----------------------------------------+-----------+-------------+---------+-----------+-----------+------+------------- + priv_seq | 1 | 1 | 1 | 170141183460469231731687303715884105727 | 1 | 1 | 0 | f | f | 0 | 0 (1 row) \d priv_seq @@ -737,6 +740,7 @@ SELECT * FROM priv_seq; is_cycled | boolean | f is_called | boolean | f uuid | bigint | 0 + cache_level | int16 | 0 SELECT nextval('priv_seq'); nextval diff --git a/src/test/regress/expected/single_node_insert.out b/src/test/regress/expected/single_node_insert.out index f90a32f333..fb1d46f1aa 100644 --- a/src/test/regress/expected/single_node_insert.out +++ b/src/test/regress/expected/single_node_insert.out @@ -90,9 +90,9 @@ select setval('ss1_TESTTABLE', 10); (1 row) select * from ss1_TESTTABLE; - sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid ----------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------+------ - ss1_testtable | 10 | 1 | 1 | 9223372036854775807 | 1 | 1 | 0 | f | t | 0 + sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid | cache_level +---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------+------+------------- + ss1_testtable | 10 | 1 | 1 | 9223372036854775807 | 1 | 1 | 0 | f | t | 0 | 0 (1 row) alter table s1_TESTTABLE alter column id set default nextval('ss1_TESTTABLE'); @@ -106,9 +106,9 @@ select * from s1_TESTTABLE order by id; (2 rows) select * from ss1_TESTTABLE; - sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid ----------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------+------ - ss1_testtable | 12 | 1 | 1 | 9223372036854775807 | 1 | 1 | 31 | f | t | 0 + sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called | uuid | cache_level +---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------+------+------------- + ss1_testtable | 12 | 1 | 1 | 9223372036854775807 | 1 | 1 | 31 | f | t | 0 | 0 (1 row) drop table s1_TESTTABLE; diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out index 777d4c9e74..f4cb3e3b56 100644 --- a/src/test/regress/expected/updatable_views.out +++ b/src/test/regress/expected/updatable_views.out @@ -258,6 +258,7 @@ SELECT table_name, column_name, is_updatable ro_view19 | is_cycled | NO ro_view19 | is_called | NO ro_view19 | uuid | NO + ro_view19 | cache_level | NO ro_view2 | a | NO ro_view2 | b | NO ro_view20 | a | NO @@ -283,7 +284,7 @@ SELECT table_name, column_name, is_updatable rw_view16 | a | YES rw_view16 | b | YES rw_view16 | aa | YES -(47 rows) +(48 rows) -- Read-only views DELETE FROM ro_view1; diff --git a/src/test/regress/input/global_sequence_cache.source b/src/test/regress/input/global_sequence_cache.source new file mode 100644 index 0000000000..8961c9d2dd --- /dev/null +++ b/src/test/regress/input/global_sequence_cache.source @@ -0,0 +1,908 @@ +drop schema if exists global_sequence_cache_schema cascade; +create schema global_sequence_cache_schema; +set current_schema = global_sequence_cache_schema; + +-- 1.1.1 get sequence value by nextval、currval +create sequence seq_test1 increment by 2 cache 5 global; +select seq_test1.currval; +select seq_test1.nextval; +select seq_test1.nextval; +select seq_test1.nextval; +select seq_test1.currval; +select seq_test1.nextval; +select seq_test1.nextval; +select seq_test1.nextval; +select seq_test1.currval; +select nextval('seq_test1'); +select nextval('seq_test1'); +select nextval('seq_test1'); +select seq_test1.currval; +select nextval('seq_test1'); +select nextval('seq_test1'); +select nextval('seq_test1'); +select seq_test1.currval; + +-- 1.1.2 get sequence value by nextval、currval after setval +select setval('seq_test1', 100); +select seq_test1.currval; +select seq_test1.nextval; +select seq_test1.nextval; +select seq_test1.nextval; +select seq_test1.currval; +select seq_test1.nextval; +select seq_test1.nextval; +select seq_test1.nextval; +select seq_test1.currval; +select nextval('seq_test1'); +select nextval('seq_test1'); +select nextval('seq_test1'); +select seq_test1.currval; +select nextval('seq_test1'); +select nextval('seq_test1'); +select nextval('seq_test1'); +select seq_test1.currval; + +drop sequence seq_test1; + +-- 1.2.1 as column of partition table +create table test_table_for_seq(id integer, name text) +partition by range(id) +( + partition p1_test_seq values less than (10), + partition p2_test_seq values less than (20), + partition p3_test_seq values less than (30) +); +create sequence seq_test_table +increment by 1 +minvalue 1 maxvalue 30 +start 1 +cycle +cache 5 +global +owned by test_table_for_seq.id; + +select seq_test_table.currval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.currval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.currval; +select nextval('seq_test_table'); +select nextval('seq_test_table'); +select nextval('seq_test_table'); +select seq_test_table.currval; +select nextval('seq_test_table'); +select nextval('seq_test_table'); +select nextval('seq_test_table'); +select setval('seq_test_table', 1); +select seq_test_table.currval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.currval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.currval; +select nextval('seq_test_table'); +select nextval('seq_test_table'); +select nextval('seq_test_table'); +select seq_test_table.currval; +select nextval('seq_test_table'); +select nextval('seq_test_table'); +select nextval('seq_test_table'); +select setval('seq_test_table', 1); +select seq_test_table.currval; +insert into test_table_for_seq values + (currval('seq_test_table'), 'values1'), + (nextval('seq_test_table'), 'values2'), + (nextval('seq_test_table'), 'values3'), + (nextval('seq_test_table'), 'values4'), + (nextval('seq_test_table'), 'values5'), + (nextval('seq_test_table'), 'values6'), + (nextval('seq_test_table'), 'values7'), + (nextval('seq_test_table'), 'values8'), + (nextval('seq_test_table'), 'values9'), + (nextval('seq_test_table'), 'values10'), + (nextval('seq_test_table'), 'values11'), + (nextval('seq_test_table'), 'values12'), + (nextval('seq_test_table'), 'values13'), + (nextval('seq_test_table'), 'values14'), + (nextval('seq_test_table'), 'values15'), + (nextval('seq_test_table'), 'values16'), + (nextval('seq_test_table'), 'values17'), + (nextval('seq_test_table'), 'values18'), + (nextval('seq_test_table'), 'values19'), + (nextval('seq_test_table'), 'values20'), + (nextval('seq_test_table'), 'values21'), + (nextval('seq_test_table'), 'values22'), + (nextval('seq_test_table'), 'values23'), + (nextval('seq_test_table'), 'values24'), + (nextval('seq_test_table'), 'values25'), + (nextval('seq_test_table'), 'values26'), + (nextval('seq_test_table'), 'values27'), + (nextval('seq_test_table'), 'values28'), + (nextval('seq_test_table'), 'values29'); + +select * from test_table_for_seq; + +select seq_test_table.currval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.currval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.currval; + +drop table test_table_for_seq; +drop sequence seq_test_table; + +-- 1.2.2 as column of normal table +create table test_table_for_seq1(c1 integer, c2 serial); +create table test_table_for_seq2(c1 integer, c2 largeserial); +insert into test_table_for_seq1 values + (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), + (11), (12), (13), (14), (15), (16), (17), (18), (19), (20); + +insert into test_table_for_seq2 values + (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), + (11), (12), (13), (14), (15), (16), (17), (18), (19), (20); + +select * from test_table_for_seq1; +select * from test_table_for_seq2; + +drop table test_table_for_seq1; +drop table test_table_for_seq2; + +-- 1.3.1 normal sequence +create sequence normal_seq +increment by 1 +minvalue 1 maxvalue 10 +start 1 +cycle +global +cache 5; + +select normal_seq.currval; +select normal_seq.nextval; +select normal_seq.nextval; +select normal_seq.nextval; +select normal_seq.nextval; +select normal_seq.nextval; +select normal_seq.nextval; +select nextval('normal_seq'); +select nextval('normal_seq'); +select nextval('normal_seq'); +select nextval('normal_seq'); +select nextval('normal_seq'); +select nextval('normal_seq'); + +drop sequence normal_seq; + +-- 1.3.2 large sequence +create large sequence nornaml_large_seq +increment by 1 +minvalue 1 maxvalue 10 +start 1 +cycle +global +cache 5; + +select nornaml_large_seq.currval; +select nornaml_large_seq.nextval; +select nornaml_large_seq.nextval; +select nornaml_large_seq.nextval; +select nornaml_large_seq.nextval; +select nornaml_large_seq.nextval; +select nornaml_large_seq.nextval; +select nextval('nornaml_large_seq'); +select nextval('nornaml_large_seq'); +select nextval('nornaml_large_seq'); +select nextval('nornaml_large_seq'); +select nextval('nornaml_large_seq'); +select nextval('nornaml_large_seq'); + +drop large sequence nornaml_large_seq; + +-- 1.4.1 get sequence value +create sequence alter_seq_test global; + +select alter_seq_test.currval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; +select nextval('alter_seq_test'); +select nextval('alter_seq_test'); + +-- no cache +alter sequence alter_seq_test +increment by 2 +minvalue 1 maxvalue 20 +start 10 +cycle; + +select alter_seq_test.currval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; + +-- cache +alter sequence alter_seq_test +increment by 2 +minvalue 1 maxvalue 20 +start 10 +cycle +cache 5; + +select alter_seq_test.currval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; + +drop sequence alter_seq_test; + +-- 2.1.1 test boundary value: min、max +create sequence seq_test_minmax +increment by 1 +minvalue 1 maxvalue 10000000 +global +cycle; + +select setval('seq_test_minmax', 9999998); +select seq_test_minmax.currval; +select seq_test_minmax.nextval; +select seq_test_minmax.nextval; +select seq_test_minmax.nextval; +select seq_test_minmax.nextval; + +drop sequence seq_test_minmax; + +-- 2.1.2 test boundary value: min、max +create sequence seq_test_minmax1 +increment by 2 +minvalue 1 maxvalue 10000000 +cycle +global +cache 4; + +select setval('seq_test_minmax1', 9999997); +select seq_test_minmax1.currval; +select seq_test_minmax1.nextval; +select seq_test_minmax1.nextval; +select seq_test_minmax1.nextval; +select seq_test_minmax1.nextval; + +drop sequence seq_test_minmax1; + +-- 2.2.1 test boundary value: cycle、no cycle +create sequence seq_test_cycle +increment by 2 +minvalue 1 maxvalue 8 +cycle +global +cache 3; + +select seq_test_cycle.currval; +select seq_test_cycle.nextval; +select seq_test_cycle.nextval; +select seq_test_cycle.nextval; +select seq_test_cycle.nextval; +select seq_test_cycle.nextval; + +drop sequence seq_test_cycle; + +-- 2.2.2 test boundary value: cycle、no cycle +create sequence seq_test_nocycle +increment by 2 +minvalue 1 maxvalue 8 +no cycle +global +cache 3; + +select seq_test_nocycle.currval; +select seq_test_nocycle.nextval; +select seq_test_nocycle.nextval; +select seq_test_nocycle.nextval; +select seq_test_nocycle.nextval; +select seq_test_nocycle.nextval; + +drop sequence seq_test_nocycle; + +-- 2.3.1 test boundary value: last cache and maxval +create sequence seq_test_lastcache +increment by 2 +minvalue 1 maxvalue 10 +no cycle +global +cache 5; + +select seq_test_lastcache.currval; +select seq_test_lastcache.nextval; +select seq_test_lastcache.nextval; +select seq_test_lastcache.nextval; +select seq_test_lastcache.nextval; +select seq_test_lastcache.nextval; +select seq_test_lastcache.nextval; + +drop sequence seq_test_lastcache; + +create sequence seq_test_lastcache1 +increment by 2 +minvalue 2 maxvalue 10 +no cycle +global +cache 5; + +select seq_test_lastcache1.currval; +select seq_test_lastcache1.nextval; +select seq_test_lastcache1.nextval; +select seq_test_lastcache1.nextval; +select seq_test_lastcache1.nextval; +select seq_test_lastcache1.nextval; +select seq_test_lastcache1.nextval; + +drop sequence seq_test_lastcache1; + +create sequence seq_test_lastcache2 +increment by 2 +minvalue -10 maxvalue 10 +cycle +global +cache 5; + +select seq_test_lastcache2.currval; +select seq_test_lastcache2.nextval; +select seq_test_lastcache2.nextval; +select seq_test_lastcache2.nextval; +select seq_test_lastcache2.nextval; +select seq_test_lastcache2.nextval; +select seq_test_lastcache2.nextval; +select seq_test_lastcache2.nextval; + +drop sequence seq_test_lastcache2; + +-- 2.4.1 test last_insert_id +create database dolphindb_seq dbcompatibility 'B'; +\! @abs_bindir@/gsql -d dolphindb_seq -p @portstring@ -c "create table tab_test_autoincrement ( id integer primary key auto_increment, name varchar(25) not null );" -a 2>&1 +\! @abs_bindir@/gsql -d dolphindb_seq -p @portstring@ -c "select last_insert_id();insert into tab_test_autoincrement(name) values ('aaa'), ('bbb');select last_insert_id();insert into tab_test_autoincrement(name) values ('ccc'), ('ddd'), ('eee');select last_insert_id();" -a 2>&1 +\! @abs_bindir@/gsql -d dolphindb_seq -p @portstring@ -c "drop table tab_test_autoincrement;" -a 2>&1 + +-- 2.5.1 test drop sequence cache +create sequence drop_seq_cache_test cache 10 global; +select drop_seq_cache_test.currval; +select drop_seq_cache_test.nextval; +select drop_seq_cache_test.currval; +select drop_seq_cache_test.nextval; +select drop_seq_cache_test.nextval; + +-- drop and recreate sequence with the same name +drop sequence drop_seq_cache_test; +create sequence drop_seq_cache_test cache 10 global; +select drop_seq_cache_test.currval; +select drop_seq_cache_test.nextval; +select drop_seq_cache_test.nextval; +select drop_seq_cache_test.nextval; + +drop sequence drop_seq_cache_test; + +-- 2.6.1 verify whether the gsql -c execution sql has a skip number problem +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create sequence seq_test_skip_val cache 10 global;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select seq_test_skip_val.nextval; select seq_test_skip_val.nextval;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select seq_test_skip_val.nextval; select seq_test_skip_val.nextval;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select seq_test_skip_val.nextval; select seq_test_skip_val.nextval;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop sequence seq_test_skip_val;" -a 2>&1 + +-- 2.7.1 test currval and lastval setval and setval of false +create sequence seq_test_setval +increment by 1 +start 1 +no cycle +global +cache 10; + +create sequence seq_test_setval1 +increment by 1 +start 1 +no cycle +global +cache 10; + +create sequence seq_test_setval2 +increment by 1 +start 1 +no cycle +global +cache 10; + +select setval('seq_test_setval', 4); +select seq_test_setval.currval; +select lastval(); +select seq_test_setval.nextval; +select setval('seq_test_setval', 14); +select seq_test_setval.currval; +select lastval(); + +select setval('seq_test_setval1', 5, true); +select seq_test_setval1.currval; +select lastval(); +select seq_test_setval1.nextval; +select setval('seq_test_setval1', 15, true); +select seq_test_setval1.currval; +select lastval(); + +select setval('seq_test_setval2', 6, false); +select seq_test_setval2.currval; +select lastval(); +select seq_test_setval2.nextval; +select setval('seq_test_setval2', 16, false); +select seq_test_setval2.currval; +select lastval(); + + +drop sequence seq_test_setval; +drop sequence seq_test_setval1; +drop sequence seq_test_setval2; + +-- 2.8.1 test pg_sequence_last_value and pg_sequence_parameters +create sequence seq_get_last_param_by_relid +increment by 1 +start 1 +no cycle +global +cache 10; + +WITH SequenceInfo AS ( + SELECT oid + FROM pg_class + WHERE relname = 'seq_get_last_param_by_relid' +), +LastValue AS ( + SELECT pg_sequence_last_value(oid) AS last_value + FROM SequenceInfo +) +SELECT last_value FROM LastValue; + +WITH SequenceInfo AS ( + SELECT oid + FROM pg_class + WHERE relname = 'seq_get_last_param_by_relid' +), +LastValue AS ( + SELECT pg_sequence_parameters(oid) AS last_value + FROM SequenceInfo +) +SELECT last_value FROM LastValue; + +create or replace procedure proc_seq_get_val() is + relid int; + cache_value numeric; + last_value numeric; + next_val numeric; + start_value numeric; + minimum_value numeric; + maximum_value numeric; + increment numeric; + cycle_option numeric; +begin + select oid into relid from pg_class where relname = 'seq_get_last_param_by_relid'; + select * into cache_value, last_value from pg_sequence_last_value(relid); + raise info 'cache_value : %, last_value : %', cache_value, last_value; + select * into start_value, minimum_value, maximum_value, increment, cycle_option from pg_sequence_parameters(relid); + raise info 'start_value : %, minimum_value : %, maximum_value : %, increment : %, cycle_option : %', start_value, minimum_value, maximum_value, increment, cycle_option; + next_val := nextval('seq_get_last_param_by_relid'); + raise info 'next_val : %', next_val; + select * into cache_value, last_value from pg_sequence_last_value(relid); + raise info 'cache_value : %, last_value : %', cache_value, last_value; + select * into start_value, minimum_value, maximum_value, increment, cycle_option from pg_sequence_parameters(relid); + raise info 'start_value : %, minimum_value : %, maximum_value : %, increment : %, cycle_option : %', start_value, minimum_value, maximum_value, increment, cycle_option; + PERFORM setval('seq_get_last_param_by_relid', 10); + select * into cache_value, last_value from pg_sequence_last_value(relid); + raise info 'cache_value : %, last_value : %', cache_value, last_value; + select * into start_value, minimum_value, maximum_value, increment, cycle_option from pg_sequence_parameters(relid); + raise info 'start_value : %, minimum_value : %, maximum_value : %, increment : %, cycle_option : %', start_value, minimum_value, maximum_value, increment, cycle_option; +end; +/ + +call proc_seq_get_val(); + +drop sequence seq_get_last_param_by_relid; +drop procedure proc_seq_get_val; + + +-- 3.1 test of concurrent: continuity of sequence values +create table test_seqcache_for_parall(c1 integer, c2 integer); +create sequence seq_test_table increment by 1 start 1 no cycle cache 10 global owned by test_seqcache_for_parall.c2; +-- insert data in parallel +create or replace procedure proc_for_para_seq() is +begin + for i in 1 .. 10000 loop + insert into test_seqcache_for_parall values (i, nextval('seq_test_table')); + end loop; +end; +/ + +\! touch @abs_bindir@/global_sequence_cache_output.txt +\o @abs_bindir@/global_sequence_cache_output.txt +\parallel on +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +\parallel off +\o + +select count(distinct c1) from test_seqcache_for_parall; +select count(distinct c2) from test_seqcache_for_parall; +select count(c2) from test_seqcache_for_parall; +select * from test_seqcache_for_parall where c2 > 1000000; +select c2 from test_seqcache_for_parall group by c2 having count(*) > 1; +drop sequence seq_test_table; + +-- 3.2 test of concurrent: boundary of sequence values +create table test_seqcache_for_parall_boundary(c1 integer, c2 integer); +create sequence seq_test_table_boundary increment by 1 minvalue 1 maxvalue 100 cycle cache 20 global owned by test_seqcache_for_parall_boundary.c2; +-- insert data in parallel +create or replace procedure proc_for_para_seq_boundary() is +begin + for i in 1 .. 100 loop + insert into test_seqcache_for_parall_boundary values (i, nextval('seq_test_table_boundary')); + end loop; +end; +/ + +\o @abs_bindir@/global_sequence_cache_output.txt +\parallel on +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +\parallel off +\o +\! test -f @abs_bindir@/global_sequence_cache_output.txt && rm -f @abs_bindir@/global_sequence_cache_output.txt + +select count(*) from test_seqcache_for_parall_boundary; +declare + ret integer := 0; +begin + for i in 1 .. 100 loop + select count(*) into ret from test_seqcache_for_parall_boundary where c2 = i; + if ret != 100 then + raise info 'there are % entries in sequence value %', ret, i; + end if; + ret := 0; + end loop; +end; +/ + +drop sequence seq_test_table_boundary; + +-- 3.3 test of concurrent: currval of sequence values +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create sequence seq_test_parral_currval increment by 1 minvalue 1 maxvalue 100 cycle global cache 20;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create table tab_record_parall_result (col1 integer, col2 varchar(10));" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "insert into tab_record_parall_result (select seq_test_parral_currval.nextval, 'sess1'); insert into tab_record_parall_result (select seq_test_parral_currval.nextval, 'sess1'); insert into tab_record_parall_result (select seq_test_parral_currval.currval, 'sess1'); select pg_sleep(1); insert into tab_record_parall_result (select seq_test_parral_currval.currval, 'sess1');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(0.5); insert into tab_record_parall_result (select seq_test_parral_currval.nextval, 'sess2'); insert into tab_record_parall_result (select seq_test_parral_currval.nextval, 'sess2'); insert into tab_record_parall_result (select seq_test_parral_currval.currval, 'sess2');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(1.5);" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select * from tab_record_parall_result;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop sequence seq_test_parral_currval;" -a 2>&1 + +-- 3.4 test of concurrent: currval of sequence values after setval +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create sequence seq_test_parral_currval1 increment by 1 minvalue 1 maxvalue 100 cycle global cache 20;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "delete from tab_record_parall_result;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "insert into tab_record_parall_result (select setval('seq_test_parral_currval1', 10), 'sess1'); insert into tab_record_parall_result (select seq_test_parral_currval1.currval, 'sess1'); select pg_sleep(1); insert into tab_record_parall_result (select seq_test_parral_currval1.currval, 'sess1');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(0.5); insert into tab_record_parall_result (select setval('seq_test_parral_currval1', 20), 'sess2'); insert into tab_record_parall_result (select seq_test_parral_currval1.currval, 'sess2');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(1.5);" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select * from tab_record_parall_result;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop sequence seq_test_parral_currval1;" -a 2>&1 + +-- 3.5 test of concurrent: lastval of sequence values +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create sequence seq_test_parral_lastval increment by 1 minvalue 1 maxvalue 100 cycle global cache 20;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "delete from tab_record_parall_result;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "insert into tab_record_parall_result (select seq_test_parral_lastval.nextval, 'sess1'); insert into tab_record_parall_result (select seq_test_parral_lastval.nextval, 'sess1'); insert into tab_record_parall_result (select lastval(), 'sess1'); select pg_sleep(1); insert into tab_record_parall_result (select lastval(), 'sess1');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(0.5); insert into tab_record_parall_result (select seq_test_parral_lastval.nextval, 'sess2'); insert into tab_record_parall_result (select seq_test_parral_lastval.nextval, 'sess2'); insert into tab_record_parall_result (select lastval(), 'sess2');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(1.5);" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select * from tab_record_parall_result;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop sequence seq_test_parral_lastval;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop table tab_record_parall_result;" -a 2>&1 + +-- 4.1 reset global sequence +create sequence reset_global_seq +increment by 1 +minvalue 1 maxvalue 10 +start 1 +cycle +global +cache 3; + +select reset_global_seq.nextval; +select reset_global_seq.nextval; +select reset_global_seq.nextval; +select reset_global_seq.nextval; + +alter sequence reset_global_seq +increment by 1 +minvalue 1 maxvalue 10 +start 1 +cycle +global +cache 3 +restart; + +drop sequence reset_global_seq; + +-- 4.2 alter large sequence(cache_level, minmaxvalue) +create large sequence alter_large_seq_test global; + +select alter_large_seq_test.currval; +select alter_large_seq_test.nextval; + +alter large sequence alter_large_seq_test +increment by 2 +minvalue 0 maxvalue 10 +start 10 +cycle; + +alter large sequence alter_large_seq_test +increment by 2 +minvalue 0 maxvalue 10 +start 100 +cycle; + +alter large sequence alter_large_seq_test +increment by 2 +minvalue 1 maxvalue 20 +start 10 +session; + +alter large sequence alter_large_seq_test +increment by 2 +minvalue 1 maxvalue 20 +start 10 +global; + +alter large sequence alter_large_seq_test start 10 restart; + +drop large sequence alter_large_seq_test; + +-- 4.3 setval for large seq global +create large sequence set_large_seq_test global; + +select set_large_seq_test.currval; +select set_large_seq_test.nextval; + +select setval('set_large_seq_test', 10); +select setval('set_large_seq_test', 20, false); + +drop large sequence set_large_seq_test; + +-- 4.4 pg_sequence_last_value for large seq +create large sequence large_seq_get_last_param_by_relid +increment by 1 +start 1 +no cycle +global +cache 10; + +WITH SequenceInfo AS ( + SELECT oid + FROM pg_class + WHERE relname = 'large_seq_get_last_param_by_relid' +), +LastValue AS ( + SELECT pg_sequence_last_value(oid) AS last_value + FROM SequenceInfo +) +SELECT last_value FROM LastValue; +drop large sequence large_seq_get_last_param_by_relid; + +-- 4.5 reset sequence +create large sequence reset_seq; +create table reset_seq_tab(a int default nextval('reset_seq'), b int, c bigint default nextval('reset_seq')); +insert into reset_seq_tab(b) values (1); +insert into reset_seq_tab(b) values (1); +truncate reset_seq_tab; +drop table reset_seq_tab; +drop large sequence reset_seq; + +drop schema if exists global_sequence_cache_schema cascade; + +drop database if exists dolphindb_seq; \ No newline at end of file diff --git a/src/test/regress/input/session_sequence_cache.source b/src/test/regress/input/session_sequence_cache.source new file mode 100644 index 0000000000..a1107750cb --- /dev/null +++ b/src/test/regress/input/session_sequence_cache.source @@ -0,0 +1,790 @@ +drop schema if exists session_sequence_cache_schema cascade; +create schema session_sequence_cache_schema; +set current_schema = session_sequence_cache_schema; + +-- 1.1.1 get sequence value by nextval、currval +create sequence seq_test1 increment by 2 cache 5; +select seq_test1.currval; +select seq_test1.nextval; +select seq_test1.nextval; +select seq_test1.nextval; +select seq_test1.currval; +select seq_test1.nextval; +select seq_test1.nextval; +select seq_test1.nextval; +select seq_test1.currval; +select nextval('seq_test1'); +select nextval('seq_test1'); +select nextval('seq_test1'); +select seq_test1.currval; +select nextval('seq_test1'); +select nextval('seq_test1'); +select nextval('seq_test1'); +select seq_test1.currval; + +-- 1.1.2 get sequence value by nextval、currval after setval +select setval('seq_test1', 100); +select seq_test1.currval; +select seq_test1.nextval; +select seq_test1.nextval; +select seq_test1.nextval; +select seq_test1.currval; +select seq_test1.nextval; +select seq_test1.nextval; +select seq_test1.nextval; +select seq_test1.currval; +select nextval('seq_test1'); +select nextval('seq_test1'); +select nextval('seq_test1'); +select seq_test1.currval; +select nextval('seq_test1'); +select nextval('seq_test1'); +select nextval('seq_test1'); +select seq_test1.currval; + +drop sequence seq_test1; + +-- 1.2.1 as column of partition table +create table test_table_for_seq(id integer, name text) +partition by range(id) +( + partition p1_test_seq values less than (10), + partition p2_test_seq values less than (20), + partition p3_test_seq values less than (30) +); +create sequence seq_test_table +increment by 1 +minvalue 1 maxvalue 30 +start 1 +cycle +cache 5 +owned by test_table_for_seq.id; + +select seq_test_table.currval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.currval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.currval; +select nextval('seq_test_table'); +select nextval('seq_test_table'); +select nextval('seq_test_table'); +select seq_test_table.currval; +select nextval('seq_test_table'); +select nextval('seq_test_table'); +select nextval('seq_test_table'); +select setval('seq_test_table', 1); +select seq_test_table.currval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.currval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.currval; +select nextval('seq_test_table'); +select nextval('seq_test_table'); +select nextval('seq_test_table'); +select seq_test_table.currval; +select nextval('seq_test_table'); +select nextval('seq_test_table'); +select nextval('seq_test_table'); +select setval('seq_test_table', 1); +select seq_test_table.currval; +insert into test_table_for_seq values + (currval('seq_test_table'), 'values1'), + (nextval('seq_test_table'), 'values2'), + (nextval('seq_test_table'), 'values3'), + (nextval('seq_test_table'), 'values4'), + (nextval('seq_test_table'), 'values5'), + (nextval('seq_test_table'), 'values6'), + (nextval('seq_test_table'), 'values7'), + (nextval('seq_test_table'), 'values8'), + (nextval('seq_test_table'), 'values9'), + (nextval('seq_test_table'), 'values10'), + (nextval('seq_test_table'), 'values11'), + (nextval('seq_test_table'), 'values12'), + (nextval('seq_test_table'), 'values13'), + (nextval('seq_test_table'), 'values14'), + (nextval('seq_test_table'), 'values15'), + (nextval('seq_test_table'), 'values16'), + (nextval('seq_test_table'), 'values17'), + (nextval('seq_test_table'), 'values18'), + (nextval('seq_test_table'), 'values19'), + (nextval('seq_test_table'), 'values20'), + (nextval('seq_test_table'), 'values21'), + (nextval('seq_test_table'), 'values22'), + (nextval('seq_test_table'), 'values23'), + (nextval('seq_test_table'), 'values24'), + (nextval('seq_test_table'), 'values25'), + (nextval('seq_test_table'), 'values26'), + (nextval('seq_test_table'), 'values27'), + (nextval('seq_test_table'), 'values28'), + (nextval('seq_test_table'), 'values29'); + +select * from test_table_for_seq; + +select seq_test_table.currval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.currval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.nextval; +select seq_test_table.currval; + +drop table test_table_for_seq; +drop sequence seq_test_table; + +-- 1.2.2 as column of normal table +create table test_table_for_seq1(c1 integer, c2 serial); +create table test_table_for_seq2(c1 integer, c2 largeserial); +insert into test_table_for_seq1 values + (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), + (11), (12), (13), (14), (15), (16), (17), (18), (19), (20); + +insert into test_table_for_seq2 values + (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), + (11), (12), (13), (14), (15), (16), (17), (18), (19), (20); + +select * from test_table_for_seq1; +select * from test_table_for_seq2; + +drop table test_table_for_seq1; +drop table test_table_for_seq2; + +-- 1.3.1 normal sequence +create sequence normal_seq +increment by 1 +minvalue 1 maxvalue 10 +start 1 +cycle +cache 5; + +select normal_seq.currval; +select normal_seq.nextval; +select normal_seq.nextval; +select normal_seq.nextval; +select normal_seq.nextval; +select normal_seq.nextval; +select normal_seq.nextval; +select nextval('normal_seq'); +select nextval('normal_seq'); +select nextval('normal_seq'); +select nextval('normal_seq'); +select nextval('normal_seq'); +select nextval('normal_seq'); + +drop sequence normal_seq; + +-- 1.3.2 large sequence +create large sequence nornaml_large_seq +increment by 1 +minvalue 1 maxvalue 10 +start 1 +cycle +cache 5; + +select nornaml_large_seq.currval; +select nornaml_large_seq.nextval; +select nornaml_large_seq.nextval; +select nornaml_large_seq.nextval; +select nornaml_large_seq.nextval; +select nornaml_large_seq.nextval; +select nornaml_large_seq.nextval; +select nextval('nornaml_large_seq'); +select nextval('nornaml_large_seq'); +select nextval('nornaml_large_seq'); +select nextval('nornaml_large_seq'); +select nextval('nornaml_large_seq'); +select nextval('nornaml_large_seq'); + +drop large sequence nornaml_large_seq; + +-- 1.4.1 get sequence value +create sequence alter_seq_test; + +select alter_seq_test.currval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; +select nextval('alter_seq_test'); +select nextval('alter_seq_test'); + +-- no cache +alter sequence alter_seq_test +increment by 2 +minvalue 1 maxvalue 20 +start 10 +cycle; + +select alter_seq_test.currval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; + +-- cache +alter sequence alter_seq_test +increment by 2 +minvalue 1 maxvalue 20 +start 10 +cycle +cache 5; + +select alter_seq_test.currval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; +select alter_seq_test.nextval; + +drop sequence alter_seq_test; + +-- 2.1.1 test boundary value: min、max +create sequence seq_test_minmax +increment by 1 +minvalue 1 maxvalue 10000000 +cycle; + +select setval('seq_test_minmax', 9999998); +select seq_test_minmax.currval; +select seq_test_minmax.nextval; +select seq_test_minmax.nextval; +select seq_test_minmax.nextval; +select seq_test_minmax.nextval; + +drop sequence seq_test_minmax; + +-- 2.1.2 test boundary value: min、max +create sequence seq_test_minmax1 +increment by 2 +minvalue 1 maxvalue 10000000 +cycle +cache 4; + +select setval('seq_test_minmax1', 9999997); +select seq_test_minmax1.currval; +select seq_test_minmax1.nextval; +select seq_test_minmax1.nextval; +select seq_test_minmax1.nextval; +select seq_test_minmax1.nextval; + +drop sequence seq_test_minmax1; + +-- 2.2.1 test boundary value: cycle、no cycle +create sequence seq_test_cycle +increment by 2 +minvalue 1 maxvalue 8 +cycle +cache 3; + +select seq_test_cycle.currval; +select seq_test_cycle.nextval; +select seq_test_cycle.nextval; +select seq_test_cycle.nextval; +select seq_test_cycle.nextval; +select seq_test_cycle.nextval; + +drop sequence seq_test_cycle; + +-- 2.2.2 test boundary value: cycle、no cycle +create sequence seq_test_nocycle +increment by 2 +minvalue 1 maxvalue 8 +no cycle +cache 3; + +select seq_test_nocycle.currval; +select seq_test_nocycle.nextval; +select seq_test_nocycle.nextval; +select seq_test_nocycle.nextval; +select seq_test_nocycle.nextval; +select seq_test_nocycle.nextval; + +drop sequence seq_test_nocycle; + +-- 2.3.1 test boundary value: last cache and maxval +create sequence seq_test_lastcache +increment by 2 +minvalue 1 maxvalue 10 +no cycle +cache 5; + +select seq_test_lastcache.currval; +select seq_test_lastcache.nextval; +select seq_test_lastcache.nextval; +select seq_test_lastcache.nextval; +select seq_test_lastcache.nextval; +select seq_test_lastcache.nextval; +select seq_test_lastcache.nextval; + +drop sequence seq_test_lastcache; + +create sequence seq_test_lastcache1 +increment by 2 +minvalue 2 maxvalue 10 +no cycle +cache 5; + +select seq_test_lastcache1.currval; +select seq_test_lastcache1.nextval; +select seq_test_lastcache1.nextval; +select seq_test_lastcache1.nextval; +select seq_test_lastcache1.nextval; +select seq_test_lastcache1.nextval; +select seq_test_lastcache1.nextval; + +drop sequence seq_test_lastcache1; + +create sequence seq_test_lastcache2 +increment by 2 +minvalue -10 maxvalue 10 +cycle +cache 5; + +select seq_test_lastcache2.currval; +select seq_test_lastcache2.nextval; +select seq_test_lastcache2.nextval; +select seq_test_lastcache2.nextval; +select seq_test_lastcache2.nextval; +select seq_test_lastcache2.nextval; +select seq_test_lastcache2.nextval; +select seq_test_lastcache2.nextval; + +drop sequence seq_test_lastcache2; + +-- 2.4.1 test last_insert_id +create database dolphindb_seq dbcompatibility 'B'; +\! @abs_bindir@/gsql -d dolphindb_seq -p @portstring@ -c "create table tab_test_autoincrement ( id integer primary key auto_increment, name varchar(25) not null );" -a 2>&1 +\! @abs_bindir@/gsql -d dolphindb_seq -p @portstring@ -c "select last_insert_id();insert into tab_test_autoincrement(name) values ('aaa'), ('bbb');select last_insert_id();insert into tab_test_autoincrement(name) values ('ccc'), ('ddd'), ('eee');select last_insert_id();" -a 2>&1 +\! @abs_bindir@/gsql -d dolphindb_seq -p @portstring@ -c "drop table tab_test_autoincrement;" -a 2>&1 + +-- 2.5.1 test drop sequence cache +create sequence drop_seq_cache_test cache 10; +select drop_seq_cache_test.currval; +select drop_seq_cache_test.nextval; +select drop_seq_cache_test.currval; +select drop_seq_cache_test.nextval; +select drop_seq_cache_test.nextval; + +-- drop and recreate sequence with the same name +drop sequence drop_seq_cache_test; +create sequence drop_seq_cache_test cache 10; +select drop_seq_cache_test.currval; +select drop_seq_cache_test.nextval; +select drop_seq_cache_test.nextval; +select drop_seq_cache_test.nextval; + +drop sequence drop_seq_cache_test; + +-- 2.6.1 verify whether the gsql -c execution sql has a skip number problem +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create sequence seq_test_skip_val cache 10;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select seq_test_skip_val.nextval; select seq_test_skip_val.nextval;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select seq_test_skip_val.nextval; select seq_test_skip_val.nextval;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select seq_test_skip_val.nextval; select seq_test_skip_val.nextval;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop sequence seq_test_skip_val;" -a 2>&1 + +-- 2.7.1 test currval and lastval setval and setval of false +create sequence seq_test_setval +increment by 1 +start 1 +no cycle +cache 10; + +create sequence seq_test_setval1 +increment by 1 +start 1 +no cycle +cache 10; + +create sequence seq_test_setval2 +increment by 1 +start 1 +no cycle +cache 10; + +select setval('seq_test_setval', 4); +select seq_test_setval.currval; +select lastval(); +select seq_test_setval.nextval; +select setval('seq_test_setval', 14); +select seq_test_setval.currval; +select lastval(); + +select setval('seq_test_setval1', 5, true); +select seq_test_setval1.currval; +select lastval(); +select seq_test_setval1.nextval; +select setval('seq_test_setval1', 15, true); +select seq_test_setval1.currval; +select lastval(); + +select setval('seq_test_setval2', 6, false); +select seq_test_setval2.currval; +select lastval(); +select seq_test_setval2.nextval; +select setval('seq_test_setval2', 16, false); +select seq_test_setval2.currval; +select lastval(); + + +drop sequence seq_test_setval; +drop sequence seq_test_setval1; +drop sequence seq_test_setval2; + +-- 2.8.1 test pg_sequence_last_value and pg_sequence_parameters +create sequence seq_get_last_param_by_relid +increment by 1 +start 1 +no cycle +cache 10; + +create or replace procedure proc_seq_get_val() is + relid int; + cache_value numeric; + last_value numeric; + next_val numeric; + start_value numeric; + minimum_value numeric; + maximum_value numeric; + increment numeric; + cycle_option numeric; +begin + select oid into relid from pg_class where relname = 'seq_get_last_param_by_relid'; + select * into cache_value, last_value from pg_sequence_last_value(relid); + raise info 'cache_value : %, last_value : %', cache_value, last_value; + select * into start_value, minimum_value, maximum_value, increment, cycle_option from pg_sequence_parameters(relid); + raise info 'start_value : %, minimum_value : %, maximum_value : %, increment : %, cycle_option : %', start_value, minimum_value, maximum_value, increment, cycle_option; + next_val := nextval('seq_get_last_param_by_relid'); + raise info 'next_val : %', next_val; + select * into cache_value, last_value from pg_sequence_last_value(relid); + raise info 'cache_value : %, last_value : %', cache_value, last_value; + select * into start_value, minimum_value, maximum_value, increment, cycle_option from pg_sequence_parameters(relid); + raise info 'start_value : %, minimum_value : %, maximum_value : %, increment : %, cycle_option : %', start_value, minimum_value, maximum_value, increment, cycle_option; + PERFORM setval('seq_get_last_param_by_relid', 10); + select * into cache_value, last_value from pg_sequence_last_value(relid); + raise info 'cache_value : %, last_value : %', cache_value, last_value; + select * into start_value, minimum_value, maximum_value, increment, cycle_option from pg_sequence_parameters(relid); + raise info 'start_value : %, minimum_value : %, maximum_value : %, increment : %, cycle_option : %', start_value, minimum_value, maximum_value, increment, cycle_option; +end; +/ + +call proc_seq_get_val(); + +drop sequence seq_get_last_param_by_relid; +drop procedure proc_seq_get_val; + + +-- 3.1 test of concurrent: continuity of sequence values +create table test_seqcache_for_parall(c1 integer, c2 integer); +create sequence seq_test_table increment by 1 start 1 no cycle cache 10 owned by test_seqcache_for_parall.c2; +-- insert data in parallel +create or replace procedure proc_for_para_seq() is +begin + for i in 1 .. 10000 loop + insert into test_seqcache_for_parall values (i, nextval('seq_test_table')); + end loop; +end; +/ + +\! touch @abs_bindir@/session_sequence_cache_output.txt +\o @abs_bindir@/session_sequence_cache_output.txt +\parallel on +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +\parallel off +\o + +select count(distinct c1) from test_seqcache_for_parall; +select count(distinct c2) from test_seqcache_for_parall; +select count(c2) from test_seqcache_for_parall; +select * from test_seqcache_for_parall where c2 > 1000000; +select c2 from test_seqcache_for_parall group by c2 having count(*) > 1; +drop sequence seq_test_table; + +-- 3.2 test of concurrent: boundary of sequence values +create table test_seqcache_for_parall_boundary(c1 integer, c2 integer); +create sequence seq_test_table_boundary increment by 1 minvalue 1 maxvalue 100 cycle cache 20 owned by test_seqcache_for_parall_boundary.c2; +-- insert data in parallel +create or replace procedure proc_for_para_seq_boundary() is +begin + for i in 1 .. 100 loop + insert into test_seqcache_for_parall_boundary values (i, nextval('seq_test_table_boundary')); + end loop; +end; +/ + +\o @abs_bindir@/session_sequence_cache_output.txt +\parallel on +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +\parallel off +\o +\! test -f @abs_bindir@/session_sequence_cache_output.txt && rm -f @abs_bindir@/session_sequence_cache_output.txt + +select count(*) from test_seqcache_for_parall_boundary; +declare + ret integer := 0; +begin + for i in 1 .. 100 loop + select count(*) into ret from test_seqcache_for_parall_boundary where c2 = i; + if ret != 100 then + raise info 'there are % entries in sequence value %', ret, i; + end if; + ret := 0; + end loop; +end; +/ + +drop sequence seq_test_table_boundary; + +-- 3.3 test of concurrent: currval of sequence values +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create sequence seq_test_parral_currval increment by 1 minvalue 1 maxvalue 100 cycle cache 20;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create table tab_record_parall_result (col1 integer, col2 varchar(10));" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "insert into tab_record_parall_result (select seq_test_parral_currval.nextval, 'sess1'); insert into tab_record_parall_result (select seq_test_parral_currval.nextval, 'sess1'); insert into tab_record_parall_result (select seq_test_parral_currval.currval, 'sess1'); select pg_sleep(1); insert into tab_record_parall_result (select seq_test_parral_currval.currval, 'sess1');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(0.5); insert into tab_record_parall_result (select seq_test_parral_currval.nextval, 'sess2'); insert into tab_record_parall_result (select seq_test_parral_currval.nextval, 'sess2'); insert into tab_record_parall_result (select seq_test_parral_currval.currval, 'sess2');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(1.5);" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select * from tab_record_parall_result;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop sequence seq_test_parral_currval;" -a 2>&1 + +-- 3.4 test of concurrent: currval of sequence values after setval +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create sequence seq_test_parral_currval1 increment by 1 minvalue 1 maxvalue 100 cycle cache 20;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "delete from tab_record_parall_result;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "insert into tab_record_parall_result (select setval('seq_test_parral_currval1', 10), 'sess1'); insert into tab_record_parall_result (select seq_test_parral_currval1.currval, 'sess1'); select pg_sleep(1); insert into tab_record_parall_result (select seq_test_parral_currval1.currval, 'sess1');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(0.5); insert into tab_record_parall_result (select setval('seq_test_parral_currval1', 20), 'sess2'); insert into tab_record_parall_result (select seq_test_parral_currval1.currval, 'sess2');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(1.5);" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select * from tab_record_parall_result;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop sequence seq_test_parral_currval1;" -a 2>&1 + +-- 3.5 test of concurrent: lastval of sequence values +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create sequence seq_test_parral_lastval increment by 1 minvalue 1 maxvalue 100 cycle cache 20;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "delete from tab_record_parall_result;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "insert into tab_record_parall_result (select seq_test_parral_lastval.nextval, 'sess1'); insert into tab_record_parall_result (select seq_test_parral_lastval.nextval, 'sess1'); insert into tab_record_parall_result (select lastval(), 'sess1'); select pg_sleep(1); insert into tab_record_parall_result (select lastval(), 'sess1');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(0.5); insert into tab_record_parall_result (select seq_test_parral_lastval.nextval, 'sess2'); insert into tab_record_parall_result (select seq_test_parral_lastval.nextval, 'sess2'); insert into tab_record_parall_result (select lastval(), 'sess2');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(1.5);" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select * from tab_record_parall_result;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop sequence seq_test_parral_lastval;" -a 2>&1 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop table tab_record_parall_result;" -a 2>&1 + +-- 4.0 test alter sequence cache level +drop sequence alter_seq_cache_level; +create sequence alter_seq_cache_level +increment by 1 +start 1 +no cycle +cache 10; +select alter_seq_cache_level.nextval; +select alter_seq_cache_level.nextval; +alter sequence alter_seq_cache_level global; +select alter_seq_cache_level.nextval; +select alter_seq_cache_level.nextval; +alter sequence alter_seq_cache_level session; +select alter_seq_cache_level.nextval; +select alter_seq_cache_level.nextval; +drop sequence alter_seq_cache_level; + +drop schema if exists session_sequence_cache_schema cascade; + +drop database if exists dolphindb_seq; \ No newline at end of file diff --git a/src/test/regress/output/global_sequence_cache.source b/src/test/regress/output/global_sequence_cache.source new file mode 100644 index 0000000000..0ff38d42c5 --- /dev/null +++ b/src/test/regress/output/global_sequence_cache.source @@ -0,0 +1,2105 @@ +drop schema if exists global_sequence_cache_schema cascade; +NOTICE: schema "global_sequence_cache_schema" does not exist, skipping +create schema global_sequence_cache_schema; +set current_schema = global_sequence_cache_schema; +-- 1.1.1 get sequence value by nextval、currval +create sequence seq_test1 increment by 2 cache 5 global; +select seq_test1.currval; +ERROR: currval of sequence "seq_test1" is not yet defined in this session +CONTEXT: referenced column: currval +select seq_test1.nextval; + nextval +--------- + 1 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 3 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 5 +(1 row) + +select seq_test1.currval; + currval +--------- + 5 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 7 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 9 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 11 +(1 row) + +select seq_test1.currval; + currval +--------- + 11 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 13 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 15 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 17 +(1 row) + +select seq_test1.currval; + currval +--------- + 17 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 19 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 21 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 23 +(1 row) + +select seq_test1.currval; + currval +--------- + 23 +(1 row) + +-- 1.1.2 get sequence value by nextval、currval after setval +select setval('seq_test1', 100); + setval +-------- + 100 +(1 row) + +select seq_test1.currval; + currval +--------- + 100 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 102 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 104 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 106 +(1 row) + +select seq_test1.currval; + currval +--------- + 106 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 108 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 110 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 112 +(1 row) + +select seq_test1.currval; + currval +--------- + 112 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 114 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 116 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 118 +(1 row) + +select seq_test1.currval; + currval +--------- + 118 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 120 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 122 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 124 +(1 row) + +select seq_test1.currval; + currval +--------- + 124 +(1 row) + +drop sequence seq_test1; +-- 1.2.1 as column of partition table +create table test_table_for_seq(id integer, name text) +partition by range(id) +( + partition p1_test_seq values less than (10), + partition p2_test_seq values less than (20), + partition p3_test_seq values less than (30) +); +create sequence seq_test_table +increment by 1 +minvalue 1 maxvalue 30 +start 1 +cycle +cache 5 +global +owned by test_table_for_seq.id; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select seq_test_table.currval; +ERROR: currval of sequence "seq_test_table" is not yet defined in this session +CONTEXT: referenced column: currval +select seq_test_table.nextval; + nextval +--------- + 1 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 2 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 3 +(1 row) + +select seq_test_table.currval; + currval +--------- + 3 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 4 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 5 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 6 +(1 row) + +select seq_test_table.currval; + currval +--------- + 6 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 7 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 8 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 9 +(1 row) + +select seq_test_table.currval; + currval +--------- + 9 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 10 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 11 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 12 +(1 row) + +select setval('seq_test_table', 1); + setval +-------- + 1 +(1 row) + +select seq_test_table.currval; + currval +--------- + 1 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 2 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 3 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 4 +(1 row) + +select seq_test_table.currval; + currval +--------- + 4 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 5 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 6 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 7 +(1 row) + +select seq_test_table.currval; + currval +--------- + 7 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 8 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 9 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 10 +(1 row) + +select seq_test_table.currval; + currval +--------- + 10 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 11 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 12 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 13 +(1 row) + +select setval('seq_test_table', 1); + setval +-------- + 1 +(1 row) + +select seq_test_table.currval; + currval +--------- + 1 +(1 row) + +insert into test_table_for_seq values + (currval('seq_test_table'), 'values1'), + (nextval('seq_test_table'), 'values2'), + (nextval('seq_test_table'), 'values3'), + (nextval('seq_test_table'), 'values4'), + (nextval('seq_test_table'), 'values5'), + (nextval('seq_test_table'), 'values6'), + (nextval('seq_test_table'), 'values7'), + (nextval('seq_test_table'), 'values8'), + (nextval('seq_test_table'), 'values9'), + (nextval('seq_test_table'), 'values10'), + (nextval('seq_test_table'), 'values11'), + (nextval('seq_test_table'), 'values12'), + (nextval('seq_test_table'), 'values13'), + (nextval('seq_test_table'), 'values14'), + (nextval('seq_test_table'), 'values15'), + (nextval('seq_test_table'), 'values16'), + (nextval('seq_test_table'), 'values17'), + (nextval('seq_test_table'), 'values18'), + (nextval('seq_test_table'), 'values19'), + (nextval('seq_test_table'), 'values20'), + (nextval('seq_test_table'), 'values21'), + (nextval('seq_test_table'), 'values22'), + (nextval('seq_test_table'), 'values23'), + (nextval('seq_test_table'), 'values24'), + (nextval('seq_test_table'), 'values25'), + (nextval('seq_test_table'), 'values26'), + (nextval('seq_test_table'), 'values27'), + (nextval('seq_test_table'), 'values28'), + (nextval('seq_test_table'), 'values29'); +select * from test_table_for_seq; + id | name +----+---------- + 1 | values1 + 2 | values2 + 3 | values3 + 4 | values4 + 5 | values5 + 6 | values6 + 7 | values7 + 8 | values8 + 9 | values9 + 10 | values10 + 11 | values11 + 12 | values12 + 13 | values13 + 14 | values14 + 15 | values15 + 16 | values16 + 17 | values17 + 18 | values18 + 19 | values19 + 20 | values20 + 21 | values21 + 22 | values22 + 23 | values23 + 24 | values24 + 25 | values25 + 26 | values26 + 27 | values27 + 28 | values28 + 29 | values29 +(29 rows) + +select seq_test_table.currval; + currval +--------- + 29 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 30 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 1 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 2 +(1 row) + +select seq_test_table.currval; + currval +--------- + 2 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 3 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 4 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 5 +(1 row) + +select seq_test_table.currval; + currval +--------- + 5 +(1 row) + +drop table test_table_for_seq; +drop sequence seq_test_table; +ERROR: sequence "seq_test_table" does not exist +-- 1.2.2 as column of normal table +create table test_table_for_seq1(c1 integer, c2 serial); +NOTICE: CREATE TABLE will create implicit sequence "test_table_for_seq1_c2_seq" for serial column "test_table_for_seq1.c2" +create table test_table_for_seq2(c1 integer, c2 largeserial); +NOTICE: CREATE TABLE will create implicit sequence "test_table_for_seq2_c2_seq" for serial column "test_table_for_seq2.c2" +insert into test_table_for_seq1 values + (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), + (11), (12), (13), (14), (15), (16), (17), (18), (19), (20); +insert into test_table_for_seq2 values + (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), + (11), (12), (13), (14), (15), (16), (17), (18), (19), (20); +select * from test_table_for_seq1; + c1 | c2 +----+---- + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 10 | 10 + 11 | 11 + 12 | 12 + 13 | 13 + 14 | 14 + 15 | 15 + 16 | 16 + 17 | 17 + 18 | 18 + 19 | 19 + 20 | 20 +(20 rows) + +select * from test_table_for_seq2; + c1 | c2 +----+---- + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 10 | 10 + 11 | 11 + 12 | 12 + 13 | 13 + 14 | 14 + 15 | 15 + 16 | 16 + 17 | 17 + 18 | 18 + 19 | 19 + 20 | 20 +(20 rows) + +drop table test_table_for_seq1; +drop table test_table_for_seq2; +-- 1.3.1 normal sequence +create sequence normal_seq +increment by 1 +minvalue 1 maxvalue 10 +start 1 +cycle +global +cache 5; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select normal_seq.currval; +ERROR: currval of sequence "normal_seq" is not yet defined in this session +CONTEXT: referenced column: currval +select normal_seq.nextval; + nextval +--------- + 1 +(1 row) + +select normal_seq.nextval; + nextval +--------- + 2 +(1 row) + +select normal_seq.nextval; + nextval +--------- + 3 +(1 row) + +select normal_seq.nextval; + nextval +--------- + 4 +(1 row) + +select normal_seq.nextval; + nextval +--------- + 5 +(1 row) + +select normal_seq.nextval; + nextval +--------- + 6 +(1 row) + +select nextval('normal_seq'); + nextval +--------- + 7 +(1 row) + +select nextval('normal_seq'); + nextval +--------- + 8 +(1 row) + +select nextval('normal_seq'); + nextval +--------- + 9 +(1 row) + +select nextval('normal_seq'); + nextval +--------- + 10 +(1 row) + +select nextval('normal_seq'); + nextval +--------- + 1 +(1 row) + +select nextval('normal_seq'); + nextval +--------- + 2 +(1 row) + +drop sequence normal_seq; +-- 1.3.2 large sequence +create large sequence nornaml_large_seq +increment by 1 +minvalue 1 maxvalue 10 +start 1 +cycle +global +cache 5; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select nornaml_large_seq.currval; +ERROR: currval of sequence "nornaml_large_seq" is not yet defined in this session +CONTEXT: referenced column: currval +select nornaml_large_seq.nextval; + nextval +--------- + 1 +(1 row) + +select nornaml_large_seq.nextval; + nextval +--------- + 2 +(1 row) + +select nornaml_large_seq.nextval; + nextval +--------- + 3 +(1 row) + +select nornaml_large_seq.nextval; + nextval +--------- + 4 +(1 row) + +select nornaml_large_seq.nextval; + nextval +--------- + 5 +(1 row) + +select nornaml_large_seq.nextval; + nextval +--------- + 6 +(1 row) + +select nextval('nornaml_large_seq'); + nextval +--------- + 7 +(1 row) + +select nextval('nornaml_large_seq'); + nextval +--------- + 8 +(1 row) + +select nextval('nornaml_large_seq'); + nextval +--------- + 9 +(1 row) + +select nextval('nornaml_large_seq'); + nextval +--------- + 10 +(1 row) + +select nextval('nornaml_large_seq'); + nextval +--------- + 1 +(1 row) + +select nextval('nornaml_large_seq'); + nextval +--------- + 2 +(1 row) + +drop large sequence nornaml_large_seq; +-- 1.4.1 get sequence value +create sequence alter_seq_test global; +select alter_seq_test.currval; +ERROR: currval of sequence "alter_seq_test" is not yet defined in this session +CONTEXT: referenced column: currval +select alter_seq_test.nextval; + nextval +--------- + 1 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 2 +(1 row) + +select nextval('alter_seq_test'); + nextval +--------- + 3 +(1 row) + +select nextval('alter_seq_test'); + nextval +--------- + 4 +(1 row) + +-- no cache +alter sequence alter_seq_test +increment by 2 +minvalue 1 maxvalue 20 +start 10 +cycle; +select alter_seq_test.currval; + currval +--------- + 4 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 10 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 12 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 14 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 16 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 18 +(1 row) + +-- cache +alter sequence alter_seq_test +increment by 2 +minvalue 1 maxvalue 20 +start 10 +cycle +cache 5; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select alter_seq_test.currval; + currval +--------- + 18 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 10 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 12 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 14 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 16 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 18 +(1 row) + +drop sequence alter_seq_test; +-- 2.1.1 test boundary value: min、max +create sequence seq_test_minmax +increment by 1 +minvalue 1 maxvalue 10000000 +global +cycle; +select setval('seq_test_minmax', 9999998); + setval +--------- + 9999998 +(1 row) + +select seq_test_minmax.currval; + currval +--------- + 9999998 +(1 row) + +select seq_test_minmax.nextval; + nextval +--------- + 9999999 +(1 row) + +select seq_test_minmax.nextval; + nextval +---------- + 10000000 +(1 row) + +select seq_test_minmax.nextval; + nextval +--------- + 1 +(1 row) + +select seq_test_minmax.nextval; + nextval +--------- + 2 +(1 row) + +drop sequence seq_test_minmax; +-- 2.1.2 test boundary value: min、max +create sequence seq_test_minmax1 +increment by 2 +minvalue 1 maxvalue 10000000 +cycle +global +cache 4; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select setval('seq_test_minmax1', 9999997); + setval +--------- + 9999997 +(1 row) + +select seq_test_minmax1.currval; + currval +--------- + 9999997 +(1 row) + +select seq_test_minmax1.nextval; + nextval +--------- + 9999999 +(1 row) + +select seq_test_minmax1.nextval; + nextval +--------- + 1 +(1 row) + +select seq_test_minmax1.nextval; + nextval +--------- + 3 +(1 row) + +select seq_test_minmax1.nextval; + nextval +--------- + 5 +(1 row) + +drop sequence seq_test_minmax1; +-- 2.2.1 test boundary value: cycle、no cycle +create sequence seq_test_cycle +increment by 2 +minvalue 1 maxvalue 8 +cycle +global +cache 3; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select seq_test_cycle.currval; +ERROR: currval of sequence "seq_test_cycle" is not yet defined in this session +CONTEXT: referenced column: currval +select seq_test_cycle.nextval; + nextval +--------- + 1 +(1 row) + +select seq_test_cycle.nextval; + nextval +--------- + 3 +(1 row) + +select seq_test_cycle.nextval; + nextval +--------- + 5 +(1 row) + +select seq_test_cycle.nextval; + nextval +--------- + 7 +(1 row) + +select seq_test_cycle.nextval; + nextval +--------- + 1 +(1 row) + +drop sequence seq_test_cycle; +-- 2.2.2 test boundary value: cycle、no cycle +create sequence seq_test_nocycle +increment by 2 +minvalue 1 maxvalue 8 +no cycle +global +cache 3; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select seq_test_nocycle.currval; +ERROR: currval of sequence "seq_test_nocycle" is not yet defined in this session +CONTEXT: referenced column: currval +select seq_test_nocycle.nextval; + nextval +--------- + 1 +(1 row) + +select seq_test_nocycle.nextval; + nextval +--------- + 3 +(1 row) + +select seq_test_nocycle.nextval; + nextval +--------- + 5 +(1 row) + +select seq_test_nocycle.nextval; + nextval +--------- + 7 +(1 row) + +select seq_test_nocycle.nextval; +ERROR: nextval: reached maximum value of sequence "seq_test_nocycle" (8) +CONTEXT: referenced column: nextval +drop sequence seq_test_nocycle; +-- 2.3.1 test boundary value: last cache and maxval +create sequence seq_test_lastcache +increment by 2 +minvalue 1 maxvalue 10 +no cycle +global +cache 5; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select seq_test_lastcache.currval; +ERROR: currval of sequence "seq_test_lastcache" is not yet defined in this session +CONTEXT: referenced column: currval +select seq_test_lastcache.nextval; + nextval +--------- + 1 +(1 row) + +select seq_test_lastcache.nextval; + nextval +--------- + 3 +(1 row) + +select seq_test_lastcache.nextval; + nextval +--------- + 5 +(1 row) + +select seq_test_lastcache.nextval; + nextval +--------- + 7 +(1 row) + +select seq_test_lastcache.nextval; + nextval +--------- + 9 +(1 row) + +select seq_test_lastcache.nextval; +ERROR: nextval: reached maximum value of sequence "seq_test_lastcache" (10) +CONTEXT: referenced column: nextval +drop sequence seq_test_lastcache; +create sequence seq_test_lastcache1 +increment by 2 +minvalue 2 maxvalue 10 +no cycle +global +cache 5; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select seq_test_lastcache1.currval; +ERROR: currval of sequence "seq_test_lastcache1" is not yet defined in this session +CONTEXT: referenced column: currval +select seq_test_lastcache1.nextval; + nextval +--------- + 2 +(1 row) + +select seq_test_lastcache1.nextval; + nextval +--------- + 4 +(1 row) + +select seq_test_lastcache1.nextval; + nextval +--------- + 6 +(1 row) + +select seq_test_lastcache1.nextval; + nextval +--------- + 8 +(1 row) + +select seq_test_lastcache1.nextval; + nextval +--------- + 10 +(1 row) + +select seq_test_lastcache1.nextval; +ERROR: nextval: reached maximum value of sequence "seq_test_lastcache1" (10) +CONTEXT: referenced column: nextval +drop sequence seq_test_lastcache1; +create sequence seq_test_lastcache2 +increment by 2 +minvalue -10 maxvalue 10 +cycle +global +cache 5; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select seq_test_lastcache2.currval; +ERROR: currval of sequence "seq_test_lastcache2" is not yet defined in this session +CONTEXT: referenced column: currval +select seq_test_lastcache2.nextval; + nextval +--------- + -10 +(1 row) + +select seq_test_lastcache2.nextval; + nextval +--------- + -8 +(1 row) + +select seq_test_lastcache2.nextval; + nextval +--------- + -6 +(1 row) + +select seq_test_lastcache2.nextval; + nextval +--------- + -4 +(1 row) + +select seq_test_lastcache2.nextval; + nextval +--------- + -2 +(1 row) + +select seq_test_lastcache2.nextval; + nextval +--------- + 0 +(1 row) + +select seq_test_lastcache2.nextval; + nextval +--------- + 2 +(1 row) + +drop sequence seq_test_lastcache2; +-- 2.4.1 test last_insert_id +create database dolphindb_seq dbcompatibility 'B'; +\! @abs_bindir@/gsql -d dolphindb_seq -p @portstring@ -c "create table tab_test_autoincrement ( id integer primary key auto_increment, name varchar(25) not null );" -a 2>&1 +create table tab_test_autoincrement ( id integer primary key auto_increment, name varchar(25) not null ); +NOTICE: CREATE TABLE will create implicit sequence "tab_test_autoincrement_id_seq" for serial column "tab_test_autoincrement.id" +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "tab_test_autoincrement_pkey" for table "tab_test_autoincrement" +CREATE TABLE +\! @abs_bindir@/gsql -d dolphindb_seq -p @portstring@ -c "select last_insert_id();insert into tab_test_autoincrement(name) values ('aaa'), ('bbb');select last_insert_id();insert into tab_test_autoincrement(name) values ('ccc'), ('ddd'), ('eee');select last_insert_id();" -a 2>&1 +select last_insert_id();insert into tab_test_autoincrement(name) values ('aaa'), ('bbb');select last_insert_id();insert into tab_test_autoincrement(name) values ('ccc'), ('ddd'), ('eee');select last_insert_id(); + last_insert_id +---------------- + 0 +(1 row) + +INSERT 0 2 + last_insert_id +---------------- + 1 +(1 row) + +INSERT 0 3 + last_insert_id +---------------- + 3 +(1 row) + +\! @abs_bindir@/gsql -d dolphindb_seq -p @portstring@ -c "drop table tab_test_autoincrement;" -a 2>&1 +drop table tab_test_autoincrement; +DROP TABLE +-- 2.5.1 test drop sequence cache +create sequence drop_seq_cache_test cache 10 global; +select drop_seq_cache_test.currval; +ERROR: currval of sequence "drop_seq_cache_test" is not yet defined in this session +CONTEXT: referenced column: currval +select drop_seq_cache_test.nextval; + nextval +--------- + 1 +(1 row) + +select drop_seq_cache_test.currval; + currval +--------- + 1 +(1 row) + +select drop_seq_cache_test.nextval; + nextval +--------- + 2 +(1 row) + +select drop_seq_cache_test.nextval; + nextval +--------- + 3 +(1 row) + +-- drop and recreate sequence with the same name +drop sequence drop_seq_cache_test; +create sequence drop_seq_cache_test cache 10 global; +select drop_seq_cache_test.currval; +ERROR: currval of sequence "drop_seq_cache_test" is not yet defined in this session +CONTEXT: referenced column: currval +select drop_seq_cache_test.nextval; + nextval +--------- + 1 +(1 row) + +select drop_seq_cache_test.nextval; + nextval +--------- + 2 +(1 row) + +select drop_seq_cache_test.nextval; + nextval +--------- + 3 +(1 row) + +drop sequence drop_seq_cache_test; +-- 2.6.1 verify whether the gsql -c execution sql has a skip number problem +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create sequence seq_test_skip_val cache 10 global;" -a 2>&1 +create sequence seq_test_skip_val cache 10 global; +CREATE SEQUENCE +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select seq_test_skip_val.nextval; select seq_test_skip_val.nextval;" -a 2>&1 +select seq_test_skip_val.nextval; select seq_test_skip_val.nextval; + nextval +--------- + 1 +(1 row) + + nextval +--------- + 2 +(1 row) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select seq_test_skip_val.nextval; select seq_test_skip_val.nextval;" -a 2>&1 +select seq_test_skip_val.nextval; select seq_test_skip_val.nextval; + nextval +--------- + 3 +(1 row) + + nextval +--------- + 4 +(1 row) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select seq_test_skip_val.nextval; select seq_test_skip_val.nextval;" -a 2>&1 +select seq_test_skip_val.nextval; select seq_test_skip_val.nextval; + nextval +--------- + 5 +(1 row) + + nextval +--------- + 6 +(1 row) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop sequence seq_test_skip_val;" -a 2>&1 +drop sequence seq_test_skip_val; +DROP SEQUENCE +-- 2.7.1 test currval and lastval setval and setval of false +create sequence seq_test_setval +increment by 1 +start 1 +no cycle +global +cache 10; +create sequence seq_test_setval1 +increment by 1 +start 1 +no cycle +global +cache 10; +create sequence seq_test_setval2 +increment by 1 +start 1 +no cycle +global +cache 10; +select setval('seq_test_setval', 4); + setval +-------- + 4 +(1 row) + +select seq_test_setval.currval; + currval +--------- + 4 +(1 row) + +select lastval(); +ERROR: lastval is not yet defined in this session +CONTEXT: referenced column: lastval +select seq_test_setval.nextval; + nextval +--------- + 5 +(1 row) + +select setval('seq_test_setval', 14); + setval +-------- + 14 +(1 row) + +select seq_test_setval.currval; + currval +--------- + 14 +(1 row) + +select lastval(); + lastval +--------- + 14 +(1 row) + +select setval('seq_test_setval1', 5, true); + setval +-------- + 5 +(1 row) + +select seq_test_setval1.currval; + currval +--------- + 5 +(1 row) + +select lastval(); + lastval +--------- + 14 +(1 row) + +select seq_test_setval1.nextval; + nextval +--------- + 6 +(1 row) + +select setval('seq_test_setval1', 15, true); + setval +-------- + 15 +(1 row) + +select seq_test_setval1.currval; + currval +--------- + 15 +(1 row) + +select lastval(); + lastval +--------- + 15 +(1 row) + +select setval('seq_test_setval2', 6, false); + setval +-------- + 6 +(1 row) + +select seq_test_setval2.currval; +ERROR: currval of sequence "seq_test_setval2" is not yet defined in this session +CONTEXT: referenced column: currval +select lastval(); + lastval +--------- + 15 +(1 row) + +select seq_test_setval2.nextval; + nextval +--------- + 6 +(1 row) + +select setval('seq_test_setval2', 16, false); + setval +-------- + 16 +(1 row) + +select seq_test_setval2.currval; + currval +--------- + 6 +(1 row) + +select lastval(); + lastval +--------- + 6 +(1 row) + +drop sequence seq_test_setval; +drop sequence seq_test_setval1; +drop sequence seq_test_setval2; +-- 2.8.1 test pg_sequence_last_value and pg_sequence_parameters +create sequence seq_get_last_param_by_relid +increment by 1 +start 1 +no cycle +global +cache 10; +WITH SequenceInfo AS ( + SELECT oid + FROM pg_class + WHERE relname = 'seq_get_last_param_by_relid' +), +LastValue AS ( + SELECT pg_sequence_last_value(oid) AS last_value + FROM SequenceInfo +) +SELECT last_value FROM LastValue; + last_value +------------ + (10,1) +(1 row) + +WITH SequenceInfo AS ( + SELECT oid + FROM pg_class + WHERE relname = 'seq_get_last_param_by_relid' +), +LastValue AS ( + SELECT pg_sequence_parameters(oid) AS last_value + FROM SequenceInfo +) +SELECT last_value FROM LastValue; + last_value +------------------------------- + (1,1,9223372036854775807,1,f) +(1 row) + +create or replace procedure proc_seq_get_val() is + relid int; + cache_value numeric; + last_value numeric; + next_val numeric; + start_value numeric; + minimum_value numeric; + maximum_value numeric; + increment numeric; + cycle_option numeric; +begin + select oid into relid from pg_class where relname = 'seq_get_last_param_by_relid'; + select * into cache_value, last_value from pg_sequence_last_value(relid); + raise info 'cache_value : %, last_value : %', cache_value, last_value; + select * into start_value, minimum_value, maximum_value, increment, cycle_option from pg_sequence_parameters(relid); + raise info 'start_value : %, minimum_value : %, maximum_value : %, increment : %, cycle_option : %', start_value, minimum_value, maximum_value, increment, cycle_option; + next_val := nextval('seq_get_last_param_by_relid'); + raise info 'next_val : %', next_val; + select * into cache_value, last_value from pg_sequence_last_value(relid); + raise info 'cache_value : %, last_value : %', cache_value, last_value; + select * into start_value, minimum_value, maximum_value, increment, cycle_option from pg_sequence_parameters(relid); + raise info 'start_value : %, minimum_value : %, maximum_value : %, increment : %, cycle_option : %', start_value, minimum_value, maximum_value, increment, cycle_option; + PERFORM setval('seq_get_last_param_by_relid', 10); + select * into cache_value, last_value from pg_sequence_last_value(relid); + raise info 'cache_value : %, last_value : %', cache_value, last_value; + select * into start_value, minimum_value, maximum_value, increment, cycle_option from pg_sequence_parameters(relid); + raise info 'start_value : %, minimum_value : %, maximum_value : %, increment : %, cycle_option : %', start_value, minimum_value, maximum_value, increment, cycle_option; +end; +/ +call proc_seq_get_val(); +INFO: cache_value : 10, last_value : 1 +INFO: start_value : 1, minimum_value : 1, maximum_value : 9223372036854775807, increment : 1, cycle_option : 0 +INFO: next_val : 1 +INFO: cache_value : 10, last_value : 10 +INFO: start_value : 1, minimum_value : 1, maximum_value : 9223372036854775807, increment : 1, cycle_option : 0 +INFO: cache_value : 10, last_value : 10 +INFO: start_value : 1, minimum_value : 1, maximum_value : 9223372036854775807, increment : 1, cycle_option : 0 + proc_seq_get_val +------------------ + +(1 row) + +drop sequence seq_get_last_param_by_relid; +drop procedure proc_seq_get_val; +-- 3.1 test of concurrent: continuity of sequence values +create table test_seqcache_for_parall(c1 integer, c2 integer); +create sequence seq_test_table increment by 1 start 1 no cycle cache 10 global owned by test_seqcache_for_parall.c2; +-- insert data in parallel +create or replace procedure proc_for_para_seq() is +begin + for i in 1 .. 10000 loop + insert into test_seqcache_for_parall values (i, nextval('seq_test_table')); + end loop; +end; +/ +\! touch @abs_bindir@/global_sequence_cache_output.txt +\o @abs_bindir@/global_sequence_cache_output.txt +\parallel on +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +\parallel off +\o +select count(distinct c1) from test_seqcache_for_parall; + count +------- + 10000 +(1 row) + +select count(distinct c2) from test_seqcache_for_parall; + count +--------- + 1000000 +(1 row) + +select count(c2) from test_seqcache_for_parall; + count +--------- + 1000000 +(1 row) + +select * from test_seqcache_for_parall where c2 > 1000000; + c1 | c2 +----+---- +(0 rows) + +select c2 from test_seqcache_for_parall group by c2 having count(*) > 1; + c2 +---- +(0 rows) + +drop sequence seq_test_table; +-- 3.2 test of concurrent: boundary of sequence values +create table test_seqcache_for_parall_boundary(c1 integer, c2 integer); +create sequence seq_test_table_boundary increment by 1 minvalue 1 maxvalue 100 cycle cache 20 global owned by test_seqcache_for_parall_boundary.c2; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +-- insert data in parallel +create or replace procedure proc_for_para_seq_boundary() is +begin + for i in 1 .. 100 loop + insert into test_seqcache_for_parall_boundary values (i, nextval('seq_test_table_boundary')); + end loop; +end; +/ +\o @abs_bindir@/global_sequence_cache_output.txt +\parallel on +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +\parallel off +\o +\! test -f @abs_bindir@/global_sequence_cache_output.txt && rm -f @abs_bindir@/global_sequence_cache_output.txt +select count(*) from test_seqcache_for_parall_boundary; + count +------- + 10000 +(1 row) + +declare + ret integer := 0; +begin + for i in 1 .. 100 loop + select count(*) into ret from test_seqcache_for_parall_boundary where c2 = i; + if ret != 100 then + raise info 'there are % entries in sequence value %', ret, i; + end if; + ret := 0; + end loop; +end; +/ +drop sequence seq_test_table_boundary; +-- 3.3 test of concurrent: currval of sequence values +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create sequence seq_test_parral_currval increment by 1 minvalue 1 maxvalue 100 cycle global cache 20;" -a 2>&1 +create sequence seq_test_parral_currval increment by 1 minvalue 1 maxvalue 100 cycle global cache 20; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +CREATE SEQUENCE +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create table tab_record_parall_result (col1 integer, col2 varchar(10));" -a 2>&1 +create table tab_record_parall_result (col1 integer, col2 varchar(10)); +CREATE TABLE +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "insert into tab_record_parall_result (select seq_test_parral_currval.nextval, 'sess1'); insert into tab_record_parall_result (select seq_test_parral_currval.nextval, 'sess1'); insert into tab_record_parall_result (select seq_test_parral_currval.currval, 'sess1'); select pg_sleep(1); insert into tab_record_parall_result (select seq_test_parral_currval.currval, 'sess1');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(0.5); insert into tab_record_parall_result (select seq_test_parral_currval.nextval, 'sess2'); insert into tab_record_parall_result (select seq_test_parral_currval.nextval, 'sess2'); insert into tab_record_parall_result (select seq_test_parral_currval.currval, 'sess2');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(1.5);" -a 2>&1 +select pg_sleep(1.5); + pg_sleep +---------- + +(1 row) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select * from tab_record_parall_result;" -a 2>&1 +select * from tab_record_parall_result; + col1 | col2 +------+------- + 1 | sess1 + 2 | sess1 + 2 | sess1 + 3 | sess2 + 4 | sess2 + 4 | sess2 + 2 | sess1 +(7 rows) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop sequence seq_test_parral_currval;" -a 2>&1 +drop sequence seq_test_parral_currval; +DROP SEQUENCE +-- 3.4 test of concurrent: currval of sequence values after setval +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create sequence seq_test_parral_currval1 increment by 1 minvalue 1 maxvalue 100 cycle global cache 20;" -a 2>&1 +create sequence seq_test_parral_currval1 increment by 1 minvalue 1 maxvalue 100 cycle global cache 20; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +CREATE SEQUENCE +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "delete from tab_record_parall_result;" -a 2>&1 +delete from tab_record_parall_result; +DELETE 7 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "insert into tab_record_parall_result (select setval('seq_test_parral_currval1', 10), 'sess1'); insert into tab_record_parall_result (select seq_test_parral_currval1.currval, 'sess1'); select pg_sleep(1); insert into tab_record_parall_result (select seq_test_parral_currval1.currval, 'sess1');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(0.5); insert into tab_record_parall_result (select setval('seq_test_parral_currval1', 20), 'sess2'); insert into tab_record_parall_result (select seq_test_parral_currval1.currval, 'sess2');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(1.5);" -a 2>&1 +select pg_sleep(1.5); + pg_sleep +---------- + +(1 row) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select * from tab_record_parall_result;" -a 2>&1 +select * from tab_record_parall_result; + col1 | col2 +------+------- + 10 | sess1 + 10 | sess1 + 20 | sess2 + 20 | sess2 + 10 | sess1 +(5 rows) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop sequence seq_test_parral_currval1;" -a 2>&1 +drop sequence seq_test_parral_currval1; +DROP SEQUENCE +-- 3.5 test of concurrent: lastval of sequence values +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create sequence seq_test_parral_lastval increment by 1 minvalue 1 maxvalue 100 cycle global cache 20;" -a 2>&1 +create sequence seq_test_parral_lastval increment by 1 minvalue 1 maxvalue 100 cycle global cache 20; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +CREATE SEQUENCE +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "delete from tab_record_parall_result;" -a 2>&1 +delete from tab_record_parall_result; +DELETE 5 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "insert into tab_record_parall_result (select seq_test_parral_lastval.nextval, 'sess1'); insert into tab_record_parall_result (select seq_test_parral_lastval.nextval, 'sess1'); insert into tab_record_parall_result (select lastval(), 'sess1'); select pg_sleep(1); insert into tab_record_parall_result (select lastval(), 'sess1');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(0.5); insert into tab_record_parall_result (select seq_test_parral_lastval.nextval, 'sess2'); insert into tab_record_parall_result (select seq_test_parral_lastval.nextval, 'sess2'); insert into tab_record_parall_result (select lastval(), 'sess2');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(1.5);" -a 2>&1 +select pg_sleep(1.5); + pg_sleep +---------- + +(1 row) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select * from tab_record_parall_result;" -a 2>&1 +select * from tab_record_parall_result; + col1 | col2 +------+------- + 1 | sess1 + 2 | sess1 + 2 | sess1 + 3 | sess2 + 4 | sess2 + 4 | sess2 + 2 | sess1 +(7 rows) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop sequence seq_test_parral_lastval;" -a 2>&1 +drop sequence seq_test_parral_lastval; +DROP SEQUENCE +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop table tab_record_parall_result;" -a 2>&1 +drop table tab_record_parall_result; +DROP TABLE +-- 4.1 reset global sequence +create sequence reset_global_seq +increment by 1 +minvalue 1 maxvalue 10 +start 1 +cycle +global +cache 3; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select reset_global_seq.nextval; + nextval +--------- + 1 +(1 row) + +select reset_global_seq.nextval; + nextval +--------- + 2 +(1 row) + +select reset_global_seq.nextval; + nextval +--------- + 3 +(1 row) + +select reset_global_seq.nextval; + nextval +--------- + 4 +(1 row) + +alter sequence reset_global_seq +increment by 1 +minvalue 1 maxvalue 10 +start 1 +cycle +global +cache 3 +restart; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +drop sequence reset_global_seq; +-- 4.2 alter large sequence(cache_level, minmaxvalue) +create large sequence alter_large_seq_test global; +select alter_large_seq_test.currval; +ERROR: currval of sequence "alter_large_seq_test" is not yet defined in this session +CONTEXT: referenced column: currval +select alter_large_seq_test.nextval; + nextval +--------- + 1 +(1 row) + +alter large sequence alter_large_seq_test +increment by 2 +minvalue 0 maxvalue 10 +start 10 +cycle; +alter large sequence alter_large_seq_test +increment by 2 +minvalue 0 maxvalue 10 +start 100 +cycle; +ERROR: START value (100) (or current value) cannot be less than MINVALUE (10) +alter large sequence alter_large_seq_test +increment by 2 +minvalue 1 maxvalue 20 +start 10 +session; +alter large sequence alter_large_seq_test +increment by 2 +minvalue 1 maxvalue 20 +start 10 +global; +alter large sequence alter_large_seq_test start 10 restart; +drop large sequence alter_large_seq_test; +-- 4.3 setval for large seq global +create large sequence set_large_seq_test global; +select set_large_seq_test.currval; +ERROR: currval of sequence "set_large_seq_test" is not yet defined in this session +CONTEXT: referenced column: currval +select set_large_seq_test.nextval; + nextval +--------- + 1 +(1 row) + +select setval('set_large_seq_test', 10); + setval +-------- + 10 +(1 row) + +select setval('set_large_seq_test', 20, false); + setval +-------- + 20 +(1 row) + +drop large sequence set_large_seq_test; +-- 4.4 pg_sequence_last_value for large seq +create large sequence large_seq_get_last_param_by_relid +increment by 1 +start 1 +no cycle +global +cache 10; +WITH SequenceInfo AS ( + SELECT oid + FROM pg_class + WHERE relname = 'large_seq_get_last_param_by_relid' +), +LastValue AS ( + SELECT pg_sequence_last_value(oid) AS last_value + FROM SequenceInfo +) +SELECT last_value FROM LastValue; + last_value +------------ + (10,1) +(1 row) + +drop large sequence large_seq_get_last_param_by_relid; +-- 4.5 reset sequence +create large sequence reset_seq; +create table reset_seq_tab(a int default nextval('reset_seq'), b int, c bigint default nextval('reset_seq')); +insert into reset_seq_tab(b) values (1); +insert into reset_seq_tab(b) values (1); +truncate reset_seq_tab; +drop table reset_seq_tab; +drop large sequence reset_seq; +drop schema if exists global_sequence_cache_schema cascade; +NOTICE: drop cascades to 4 other objects +DETAIL: drop cascades to table test_seqcache_for_parall +drop cascades to function proc_for_para_seq() +drop cascades to table test_seqcache_for_parall_boundary +drop cascades to function proc_for_para_seq_boundary() +drop database if exists dolphindb_seq; diff --git a/src/test/regress/output/psql.source b/src/test/regress/output/psql.source index d026750d18..4a32e279eb 100644 --- a/src/test/regress/output/psql.source +++ b/src/test/regress/output/psql.source @@ -155,6 +155,7 @@ create sequence seq_test start 1 increment 2 owned by tbl_seq.col1; is_cycled | boolean | f is_called | boolean | f --? uuid | bigint | .* + cache_level | bigint | 0 Owned by: public.tbl_seq.col1 \! echo -n 'JJ 123' \.| @abs_bindir@/gsql -X -d test_sql -p @portstring@ -c "create table gsql_c_copy(name varchar2(10),age integer);copy gsql_c_copy from STDIN;" diff --git a/src/test/regress/output/session_sequence_cache.source b/src/test/regress/output/session_sequence_cache.source new file mode 100644 index 0000000000..55928421d5 --- /dev/null +++ b/src/test/regress/output/session_sequence_cache.source @@ -0,0 +1,1974 @@ +drop schema if exists session_sequence_cache_schema cascade; +NOTICE: schema "session_sequence_cache_schema" does not exist, skipping +create schema session_sequence_cache_schema; +set current_schema = session_sequence_cache_schema; +-- 1.1.1 get sequence value by nextval、currval +create sequence seq_test1 increment by 2 cache 5; +select seq_test1.currval; +ERROR: currval of sequence "seq_test1" is not yet defined in this session +CONTEXT: referenced column: currval +select seq_test1.nextval; + nextval +--------- + 1 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 3 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 5 +(1 row) + +select seq_test1.currval; + currval +--------- + 5 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 7 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 9 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 11 +(1 row) + +select seq_test1.currval; + currval +--------- + 11 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 13 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 15 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 17 +(1 row) + +select seq_test1.currval; + currval +--------- + 17 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 19 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 21 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 23 +(1 row) + +select seq_test1.currval; + currval +--------- + 23 +(1 row) + +-- 1.1.2 get sequence value by nextval、currval after setval +select setval('seq_test1', 100); + setval +-------- + 100 +(1 row) + +select seq_test1.currval; + currval +--------- + 100 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 102 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 104 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 106 +(1 row) + +select seq_test1.currval; + currval +--------- + 106 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 108 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 110 +(1 row) + +select seq_test1.nextval; + nextval +--------- + 112 +(1 row) + +select seq_test1.currval; + currval +--------- + 112 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 114 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 116 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 118 +(1 row) + +select seq_test1.currval; + currval +--------- + 118 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 120 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 122 +(1 row) + +select nextval('seq_test1'); + nextval +--------- + 124 +(1 row) + +select seq_test1.currval; + currval +--------- + 124 +(1 row) + +drop sequence seq_test1; +-- 1.2.1 as column of partition table +create table test_table_for_seq(id integer, name text) +partition by range(id) +( + partition p1_test_seq values less than (10), + partition p2_test_seq values less than (20), + partition p3_test_seq values less than (30) +); +create sequence seq_test_table +increment by 1 +minvalue 1 maxvalue 30 +start 1 +cycle +cache 5 +owned by test_table_for_seq.id; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select seq_test_table.currval; +ERROR: currval of sequence "seq_test_table" is not yet defined in this session +CONTEXT: referenced column: currval +select seq_test_table.nextval; + nextval +--------- + 1 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 2 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 3 +(1 row) + +select seq_test_table.currval; + currval +--------- + 3 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 4 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 5 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 6 +(1 row) + +select seq_test_table.currval; + currval +--------- + 6 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 7 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 8 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 9 +(1 row) + +select seq_test_table.currval; + currval +--------- + 9 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 10 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 11 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 12 +(1 row) + +select setval('seq_test_table', 1); + setval +-------- + 1 +(1 row) + +select seq_test_table.currval; + currval +--------- + 1 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 2 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 3 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 4 +(1 row) + +select seq_test_table.currval; + currval +--------- + 4 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 5 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 6 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 7 +(1 row) + +select seq_test_table.currval; + currval +--------- + 7 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 8 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 9 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 10 +(1 row) + +select seq_test_table.currval; + currval +--------- + 10 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 11 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 12 +(1 row) + +select nextval('seq_test_table'); + nextval +--------- + 13 +(1 row) + +select setval('seq_test_table', 1); + setval +-------- + 1 +(1 row) + +select seq_test_table.currval; + currval +--------- + 1 +(1 row) + +insert into test_table_for_seq values + (currval('seq_test_table'), 'values1'), + (nextval('seq_test_table'), 'values2'), + (nextval('seq_test_table'), 'values3'), + (nextval('seq_test_table'), 'values4'), + (nextval('seq_test_table'), 'values5'), + (nextval('seq_test_table'), 'values6'), + (nextval('seq_test_table'), 'values7'), + (nextval('seq_test_table'), 'values8'), + (nextval('seq_test_table'), 'values9'), + (nextval('seq_test_table'), 'values10'), + (nextval('seq_test_table'), 'values11'), + (nextval('seq_test_table'), 'values12'), + (nextval('seq_test_table'), 'values13'), + (nextval('seq_test_table'), 'values14'), + (nextval('seq_test_table'), 'values15'), + (nextval('seq_test_table'), 'values16'), + (nextval('seq_test_table'), 'values17'), + (nextval('seq_test_table'), 'values18'), + (nextval('seq_test_table'), 'values19'), + (nextval('seq_test_table'), 'values20'), + (nextval('seq_test_table'), 'values21'), + (nextval('seq_test_table'), 'values22'), + (nextval('seq_test_table'), 'values23'), + (nextval('seq_test_table'), 'values24'), + (nextval('seq_test_table'), 'values25'), + (nextval('seq_test_table'), 'values26'), + (nextval('seq_test_table'), 'values27'), + (nextval('seq_test_table'), 'values28'), + (nextval('seq_test_table'), 'values29'); +select * from test_table_for_seq; + id | name +----+---------- + 1 | values1 + 2 | values2 + 3 | values3 + 4 | values4 + 5 | values5 + 6 | values6 + 7 | values7 + 8 | values8 + 9 | values9 + 10 | values10 + 11 | values11 + 12 | values12 + 13 | values13 + 14 | values14 + 15 | values15 + 16 | values16 + 17 | values17 + 18 | values18 + 19 | values19 + 20 | values20 + 21 | values21 + 22 | values22 + 23 | values23 + 24 | values24 + 25 | values25 + 26 | values26 + 27 | values27 + 28 | values28 + 29 | values29 +(29 rows) + +select seq_test_table.currval; + currval +--------- + 29 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 30 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 1 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 2 +(1 row) + +select seq_test_table.currval; + currval +--------- + 2 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 3 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 4 +(1 row) + +select seq_test_table.nextval; + nextval +--------- + 5 +(1 row) + +select seq_test_table.currval; + currval +--------- + 5 +(1 row) + +drop table test_table_for_seq; +drop sequence seq_test_table; +ERROR: sequence "seq_test_table" does not exist +-- 1.2.2 as column of normal table +create table test_table_for_seq1(c1 integer, c2 serial); +NOTICE: CREATE TABLE will create implicit sequence "test_table_for_seq1_c2_seq" for serial column "test_table_for_seq1.c2" +create table test_table_for_seq2(c1 integer, c2 largeserial); +NOTICE: CREATE TABLE will create implicit sequence "test_table_for_seq2_c2_seq" for serial column "test_table_for_seq2.c2" +insert into test_table_for_seq1 values + (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), + (11), (12), (13), (14), (15), (16), (17), (18), (19), (20); +insert into test_table_for_seq2 values + (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), + (11), (12), (13), (14), (15), (16), (17), (18), (19), (20); +select * from test_table_for_seq1; + c1 | c2 +----+---- + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 10 | 10 + 11 | 11 + 12 | 12 + 13 | 13 + 14 | 14 + 15 | 15 + 16 | 16 + 17 | 17 + 18 | 18 + 19 | 19 + 20 | 20 +(20 rows) + +select * from test_table_for_seq2; + c1 | c2 +----+---- + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | 6 + 7 | 7 + 8 | 8 + 9 | 9 + 10 | 10 + 11 | 11 + 12 | 12 + 13 | 13 + 14 | 14 + 15 | 15 + 16 | 16 + 17 | 17 + 18 | 18 + 19 | 19 + 20 | 20 +(20 rows) + +drop table test_table_for_seq1; +drop table test_table_for_seq2; +-- 1.3.1 normal sequence +create sequence normal_seq +increment by 1 +minvalue 1 maxvalue 10 +start 1 +cycle +cache 5; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select normal_seq.currval; +ERROR: currval of sequence "normal_seq" is not yet defined in this session +CONTEXT: referenced column: currval +select normal_seq.nextval; + nextval +--------- + 1 +(1 row) + +select normal_seq.nextval; + nextval +--------- + 2 +(1 row) + +select normal_seq.nextval; + nextval +--------- + 3 +(1 row) + +select normal_seq.nextval; + nextval +--------- + 4 +(1 row) + +select normal_seq.nextval; + nextval +--------- + 5 +(1 row) + +select normal_seq.nextval; + nextval +--------- + 6 +(1 row) + +select nextval('normal_seq'); + nextval +--------- + 7 +(1 row) + +select nextval('normal_seq'); + nextval +--------- + 8 +(1 row) + +select nextval('normal_seq'); + nextval +--------- + 9 +(1 row) + +select nextval('normal_seq'); + nextval +--------- + 10 +(1 row) + +select nextval('normal_seq'); + nextval +--------- + 1 +(1 row) + +select nextval('normal_seq'); + nextval +--------- + 2 +(1 row) + +drop sequence normal_seq; +-- 1.3.2 large sequence +create large sequence nornaml_large_seq +increment by 1 +minvalue 1 maxvalue 10 +start 1 +cycle +cache 5; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select nornaml_large_seq.currval; +ERROR: currval of sequence "nornaml_large_seq" is not yet defined in this session +CONTEXT: referenced column: currval +select nornaml_large_seq.nextval; + nextval +--------- + 1 +(1 row) + +select nornaml_large_seq.nextval; + nextval +--------- + 2 +(1 row) + +select nornaml_large_seq.nextval; + nextval +--------- + 3 +(1 row) + +select nornaml_large_seq.nextval; + nextval +--------- + 4 +(1 row) + +select nornaml_large_seq.nextval; + nextval +--------- + 5 +(1 row) + +select nornaml_large_seq.nextval; + nextval +--------- + 6 +(1 row) + +select nextval('nornaml_large_seq'); + nextval +--------- + 7 +(1 row) + +select nextval('nornaml_large_seq'); + nextval +--------- + 8 +(1 row) + +select nextval('nornaml_large_seq'); + nextval +--------- + 9 +(1 row) + +select nextval('nornaml_large_seq'); + nextval +--------- + 10 +(1 row) + +select nextval('nornaml_large_seq'); + nextval +--------- + 1 +(1 row) + +select nextval('nornaml_large_seq'); + nextval +--------- + 2 +(1 row) + +drop large sequence nornaml_large_seq; +-- 1.4.1 get sequence value +create sequence alter_seq_test; +select alter_seq_test.currval; +ERROR: currval of sequence "alter_seq_test" is not yet defined in this session +CONTEXT: referenced column: currval +select alter_seq_test.nextval; + nextval +--------- + 1 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 2 +(1 row) + +select nextval('alter_seq_test'); + nextval +--------- + 3 +(1 row) + +select nextval('alter_seq_test'); + nextval +--------- + 4 +(1 row) + +-- no cache +alter sequence alter_seq_test +increment by 2 +minvalue 1 maxvalue 20 +start 10 +cycle; +select alter_seq_test.currval; + currval +--------- + 4 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 6 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 8 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 10 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 12 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 14 +(1 row) + +-- cache +alter sequence alter_seq_test +increment by 2 +minvalue 1 maxvalue 20 +start 10 +cycle +cache 5; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select alter_seq_test.currval; + currval +--------- + 14 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 16 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 18 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 20 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 1 +(1 row) + +select alter_seq_test.nextval; + nextval +--------- + 3 +(1 row) + +drop sequence alter_seq_test; +-- 2.1.1 test boundary value: min、max +create sequence seq_test_minmax +increment by 1 +minvalue 1 maxvalue 10000000 +cycle; +select setval('seq_test_minmax', 9999998); + setval +--------- + 9999998 +(1 row) + +select seq_test_minmax.currval; + currval +--------- + 9999998 +(1 row) + +select seq_test_minmax.nextval; + nextval +--------- + 9999999 +(1 row) + +select seq_test_minmax.nextval; + nextval +---------- + 10000000 +(1 row) + +select seq_test_minmax.nextval; + nextval +--------- + 1 +(1 row) + +select seq_test_minmax.nextval; + nextval +--------- + 2 +(1 row) + +drop sequence seq_test_minmax; +-- 2.1.2 test boundary value: min、max +create sequence seq_test_minmax1 +increment by 2 +minvalue 1 maxvalue 10000000 +cycle +cache 4; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select setval('seq_test_minmax1', 9999997); + setval +--------- + 9999997 +(1 row) + +select seq_test_minmax1.currval; + currval +--------- + 9999997 +(1 row) + +select seq_test_minmax1.nextval; + nextval +--------- + 9999999 +(1 row) + +select seq_test_minmax1.nextval; + nextval +--------- + 1 +(1 row) + +select seq_test_minmax1.nextval; + nextval +--------- + 3 +(1 row) + +select seq_test_minmax1.nextval; + nextval +--------- + 5 +(1 row) + +drop sequence seq_test_minmax1; +-- 2.2.1 test boundary value: cycle、no cycle +create sequence seq_test_cycle +increment by 2 +minvalue 1 maxvalue 8 +cycle +cache 3; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select seq_test_cycle.currval; +ERROR: currval of sequence "seq_test_cycle" is not yet defined in this session +CONTEXT: referenced column: currval +select seq_test_cycle.nextval; + nextval +--------- + 1 +(1 row) + +select seq_test_cycle.nextval; + nextval +--------- + 3 +(1 row) + +select seq_test_cycle.nextval; + nextval +--------- + 5 +(1 row) + +select seq_test_cycle.nextval; + nextval +--------- + 7 +(1 row) + +select seq_test_cycle.nextval; + nextval +--------- + 1 +(1 row) + +drop sequence seq_test_cycle; +-- 2.2.2 test boundary value: cycle、no cycle +create sequence seq_test_nocycle +increment by 2 +minvalue 1 maxvalue 8 +no cycle +cache 3; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select seq_test_nocycle.currval; +ERROR: currval of sequence "seq_test_nocycle" is not yet defined in this session +CONTEXT: referenced column: currval +select seq_test_nocycle.nextval; + nextval +--------- + 1 +(1 row) + +select seq_test_nocycle.nextval; + nextval +--------- + 3 +(1 row) + +select seq_test_nocycle.nextval; + nextval +--------- + 5 +(1 row) + +select seq_test_nocycle.nextval; + nextval +--------- + 7 +(1 row) + +select seq_test_nocycle.nextval; +ERROR: nextval: reached maximum value of sequence "seq_test_nocycle" (8) +CONTEXT: referenced column: nextval +drop sequence seq_test_nocycle; +-- 2.3.1 test boundary value: last cache and maxval +create sequence seq_test_lastcache +increment by 2 +minvalue 1 maxvalue 10 +no cycle +cache 5; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select seq_test_lastcache.currval; +ERROR: currval of sequence "seq_test_lastcache" is not yet defined in this session +CONTEXT: referenced column: currval +select seq_test_lastcache.nextval; + nextval +--------- + 1 +(1 row) + +select seq_test_lastcache.nextval; + nextval +--------- + 3 +(1 row) + +select seq_test_lastcache.nextval; + nextval +--------- + 5 +(1 row) + +select seq_test_lastcache.nextval; + nextval +--------- + 7 +(1 row) + +select seq_test_lastcache.nextval; + nextval +--------- + 9 +(1 row) + +select seq_test_lastcache.nextval; +ERROR: nextval: reached maximum value of sequence "seq_test_lastcache" (10) +CONTEXT: referenced column: nextval +drop sequence seq_test_lastcache; +create sequence seq_test_lastcache1 +increment by 2 +minvalue 2 maxvalue 10 +no cycle +cache 5; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select seq_test_lastcache1.currval; +ERROR: currval of sequence "seq_test_lastcache1" is not yet defined in this session +CONTEXT: referenced column: currval +select seq_test_lastcache1.nextval; + nextval +--------- + 2 +(1 row) + +select seq_test_lastcache1.nextval; + nextval +--------- + 4 +(1 row) + +select seq_test_lastcache1.nextval; + nextval +--------- + 6 +(1 row) + +select seq_test_lastcache1.nextval; + nextval +--------- + 8 +(1 row) + +select seq_test_lastcache1.nextval; + nextval +--------- + 10 +(1 row) + +select seq_test_lastcache1.nextval; +ERROR: nextval: reached maximum value of sequence "seq_test_lastcache1" (10) +CONTEXT: referenced column: nextval +drop sequence seq_test_lastcache1; +create sequence seq_test_lastcache2 +increment by 2 +minvalue -10 maxvalue 10 +cycle +cache 5; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +select seq_test_lastcache2.currval; +ERROR: currval of sequence "seq_test_lastcache2" is not yet defined in this session +CONTEXT: referenced column: currval +select seq_test_lastcache2.nextval; + nextval +--------- + -10 +(1 row) + +select seq_test_lastcache2.nextval; + nextval +--------- + -8 +(1 row) + +select seq_test_lastcache2.nextval; + nextval +--------- + -6 +(1 row) + +select seq_test_lastcache2.nextval; + nextval +--------- + -4 +(1 row) + +select seq_test_lastcache2.nextval; + nextval +--------- + -2 +(1 row) + +select seq_test_lastcache2.nextval; + nextval +--------- + 0 +(1 row) + +select seq_test_lastcache2.nextval; + nextval +--------- + 2 +(1 row) + +drop sequence seq_test_lastcache2; +-- 2.4.1 test last_insert_id +create database dolphindb_seq dbcompatibility 'B'; +\! @abs_bindir@/gsql -d dolphindb_seq -p @portstring@ -c "create table tab_test_autoincrement ( id integer primary key auto_increment, name varchar(25) not null );" -a 2>&1 +create table tab_test_autoincrement ( id integer primary key auto_increment, name varchar(25) not null ); +NOTICE: CREATE TABLE will create implicit sequence "tab_test_autoincrement_id_seq" for serial column "tab_test_autoincrement.id" +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "tab_test_autoincrement_pkey" for table "tab_test_autoincrement" +CREATE TABLE +\! @abs_bindir@/gsql -d dolphindb_seq -p @portstring@ -c "select last_insert_id();insert into tab_test_autoincrement(name) values ('aaa'), ('bbb');select last_insert_id();insert into tab_test_autoincrement(name) values ('ccc'), ('ddd'), ('eee');select last_insert_id();" -a 2>&1 +select last_insert_id();insert into tab_test_autoincrement(name) values ('aaa'), ('bbb');select last_insert_id();insert into tab_test_autoincrement(name) values ('ccc'), ('ddd'), ('eee');select last_insert_id(); + last_insert_id +---------------- + 0 +(1 row) + +INSERT 0 2 + last_insert_id +---------------- + 1 +(1 row) + +INSERT 0 3 + last_insert_id +---------------- + 3 +(1 row) + +\! @abs_bindir@/gsql -d dolphindb_seq -p @portstring@ -c "drop table tab_test_autoincrement;" -a 2>&1 +drop table tab_test_autoincrement; +DROP TABLE +-- 2.5.1 test drop sequence cache +create sequence drop_seq_cache_test cache 10; +select drop_seq_cache_test.currval; +ERROR: currval of sequence "drop_seq_cache_test" is not yet defined in this session +CONTEXT: referenced column: currval +select drop_seq_cache_test.nextval; + nextval +--------- + 1 +(1 row) + +select drop_seq_cache_test.currval; + currval +--------- + 1 +(1 row) + +select drop_seq_cache_test.nextval; + nextval +--------- + 2 +(1 row) + +select drop_seq_cache_test.nextval; + nextval +--------- + 3 +(1 row) + +-- drop and recreate sequence with the same name +drop sequence drop_seq_cache_test; +create sequence drop_seq_cache_test cache 10; +select drop_seq_cache_test.currval; +ERROR: currval of sequence "drop_seq_cache_test" is not yet defined in this session +CONTEXT: referenced column: currval +select drop_seq_cache_test.nextval; + nextval +--------- + 1 +(1 row) + +select drop_seq_cache_test.nextval; + nextval +--------- + 2 +(1 row) + +select drop_seq_cache_test.nextval; + nextval +--------- + 3 +(1 row) + +drop sequence drop_seq_cache_test; +-- 2.6.1 verify whether the gsql -c execution sql has a skip number problem +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create sequence seq_test_skip_val cache 10;" -a 2>&1 +create sequence seq_test_skip_val cache 10; +CREATE SEQUENCE +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select seq_test_skip_val.nextval; select seq_test_skip_val.nextval;" -a 2>&1 +select seq_test_skip_val.nextval; select seq_test_skip_val.nextval; + nextval +--------- + 1 +(1 row) + + nextval +--------- + 2 +(1 row) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select seq_test_skip_val.nextval; select seq_test_skip_val.nextval;" -a 2>&1 +select seq_test_skip_val.nextval; select seq_test_skip_val.nextval; + nextval +--------- + 11 +(1 row) + + nextval +--------- + 12 +(1 row) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select seq_test_skip_val.nextval; select seq_test_skip_val.nextval;" -a 2>&1 +select seq_test_skip_val.nextval; select seq_test_skip_val.nextval; + nextval +--------- + 21 +(1 row) + + nextval +--------- + 22 +(1 row) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop sequence seq_test_skip_val;" -a 2>&1 +drop sequence seq_test_skip_val; +DROP SEQUENCE +-- 2.7.1 test currval and lastval setval and setval of false +create sequence seq_test_setval +increment by 1 +start 1 +no cycle +cache 10; +create sequence seq_test_setval1 +increment by 1 +start 1 +no cycle +cache 10; +create sequence seq_test_setval2 +increment by 1 +start 1 +no cycle +cache 10; +select setval('seq_test_setval', 4); + setval +-------- + 4 +(1 row) + +select seq_test_setval.currval; + currval +--------- + 4 +(1 row) + +select lastval(); +ERROR: lastval is not yet defined in this session +CONTEXT: referenced column: lastval +select seq_test_setval.nextval; + nextval +--------- + 5 +(1 row) + +select setval('seq_test_setval', 14); + setval +-------- + 14 +(1 row) + +select seq_test_setval.currval; + currval +--------- + 14 +(1 row) + +select lastval(); + lastval +--------- + 14 +(1 row) + +select setval('seq_test_setval1', 5, true); + setval +-------- + 5 +(1 row) + +select seq_test_setval1.currval; + currval +--------- + 5 +(1 row) + +select lastval(); + lastval +--------- + 14 +(1 row) + +select seq_test_setval1.nextval; + nextval +--------- + 6 +(1 row) + +select setval('seq_test_setval1', 15, true); + setval +-------- + 15 +(1 row) + +select seq_test_setval1.currval; + currval +--------- + 15 +(1 row) + +select lastval(); + lastval +--------- + 15 +(1 row) + +select setval('seq_test_setval2', 6, false); + setval +-------- + 6 +(1 row) + +select seq_test_setval2.currval; +ERROR: currval of sequence "seq_test_setval2" is not yet defined in this session +CONTEXT: referenced column: currval +select lastval(); + lastval +--------- + 15 +(1 row) + +select seq_test_setval2.nextval; + nextval +--------- + 6 +(1 row) + +select setval('seq_test_setval2', 16, false); + setval +-------- + 16 +(1 row) + +select seq_test_setval2.currval; + currval +--------- + 6 +(1 row) + +select lastval(); + lastval +--------- + 6 +(1 row) + +drop sequence seq_test_setval; +drop sequence seq_test_setval1; +drop sequence seq_test_setval2; +-- 2.8.1 test pg_sequence_last_value and pg_sequence_parameters +create sequence seq_get_last_param_by_relid +increment by 1 +start 1 +no cycle +cache 10; +create or replace procedure proc_seq_get_val() is + relid int; + cache_value numeric; + last_value numeric; + next_val numeric; + start_value numeric; + minimum_value numeric; + maximum_value numeric; + increment numeric; + cycle_option numeric; +begin + select oid into relid from pg_class where relname = 'seq_get_last_param_by_relid'; + select * into cache_value, last_value from pg_sequence_last_value(relid); + raise info 'cache_value : %, last_value : %', cache_value, last_value; + select * into start_value, minimum_value, maximum_value, increment, cycle_option from pg_sequence_parameters(relid); + raise info 'start_value : %, minimum_value : %, maximum_value : %, increment : %, cycle_option : %', start_value, minimum_value, maximum_value, increment, cycle_option; + next_val := nextval('seq_get_last_param_by_relid'); + raise info 'next_val : %', next_val; + select * into cache_value, last_value from pg_sequence_last_value(relid); + raise info 'cache_value : %, last_value : %', cache_value, last_value; + select * into start_value, minimum_value, maximum_value, increment, cycle_option from pg_sequence_parameters(relid); + raise info 'start_value : %, minimum_value : %, maximum_value : %, increment : %, cycle_option : %', start_value, minimum_value, maximum_value, increment, cycle_option; + PERFORM setval('seq_get_last_param_by_relid', 10); + select * into cache_value, last_value from pg_sequence_last_value(relid); + raise info 'cache_value : %, last_value : %', cache_value, last_value; + select * into start_value, minimum_value, maximum_value, increment, cycle_option from pg_sequence_parameters(relid); + raise info 'start_value : %, minimum_value : %, maximum_value : %, increment : %, cycle_option : %', start_value, minimum_value, maximum_value, increment, cycle_option; +end; +/ +call proc_seq_get_val(); +INFO: cache_value : 10, last_value : 1 +INFO: start_value : 1, minimum_value : 1, maximum_value : 9223372036854775807, increment : 1, cycle_option : 0 +INFO: next_val : 1 +INFO: cache_value : 10, last_value : 10 +INFO: start_value : 1, minimum_value : 1, maximum_value : 9223372036854775807, increment : 1, cycle_option : 0 +INFO: cache_value : 10, last_value : 10 +INFO: start_value : 1, minimum_value : 1, maximum_value : 9223372036854775807, increment : 1, cycle_option : 0 + proc_seq_get_val +------------------ + +(1 row) + +drop sequence seq_get_last_param_by_relid; +drop procedure proc_seq_get_val; +-- 3.1 test of concurrent: continuity of sequence values +create table test_seqcache_for_parall(c1 integer, c2 integer); +create sequence seq_test_table increment by 1 start 1 no cycle cache 10 owned by test_seqcache_for_parall.c2; +-- insert data in parallel +create or replace procedure proc_for_para_seq() is +begin + for i in 1 .. 10000 loop + insert into test_seqcache_for_parall values (i, nextval('seq_test_table')); + end loop; +end; +/ +\! touch @abs_bindir@/session_sequence_cache_output.txt +\o @abs_bindir@/session_sequence_cache_output.txt +\parallel on +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +call proc_for_para_seq(); +\parallel off +\o +select count(distinct c1) from test_seqcache_for_parall; + count +------- + 10000 +(1 row) + +select count(distinct c2) from test_seqcache_for_parall; + count +--------- + 1000000 +(1 row) + +select count(c2) from test_seqcache_for_parall; + count +--------- + 1000000 +(1 row) + +select * from test_seqcache_for_parall where c2 > 1000000; + c1 | c2 +----+---- +(0 rows) + +select c2 from test_seqcache_for_parall group by c2 having count(*) > 1; + c2 +---- +(0 rows) + +drop sequence seq_test_table; +-- 3.2 test of concurrent: boundary of sequence values +create table test_seqcache_for_parall_boundary(c1 integer, c2 integer); +create sequence seq_test_table_boundary increment by 1 minvalue 1 maxvalue 100 cycle cache 20 owned by test_seqcache_for_parall_boundary.c2; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +-- insert data in parallel +create or replace procedure proc_for_para_seq_boundary() is +begin + for i in 1 .. 100 loop + insert into test_seqcache_for_parall_boundary values (i, nextval('seq_test_table_boundary')); + end loop; +end; +/ +\o @abs_bindir@/session_sequence_cache_output.txt +\parallel on +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +call proc_for_para_seq_boundary(); +\parallel off +\o +\! test -f @abs_bindir@/session_sequence_cache_output.txt && rm -f @abs_bindir@/session_sequence_cache_output.txt +select count(*) from test_seqcache_for_parall_boundary; + count +------- + 10000 +(1 row) + +declare + ret integer := 0; +begin + for i in 1 .. 100 loop + select count(*) into ret from test_seqcache_for_parall_boundary where c2 = i; + if ret != 100 then + raise info 'there are % entries in sequence value %', ret, i; + end if; + ret := 0; + end loop; +end; +/ +drop sequence seq_test_table_boundary; +-- 3.3 test of concurrent: currval of sequence values +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create sequence seq_test_parral_currval increment by 1 minvalue 1 maxvalue 100 cycle cache 20;" -a 2>&1 +create sequence seq_test_parral_currval increment by 1 minvalue 1 maxvalue 100 cycle cache 20; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +CREATE SEQUENCE +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create table tab_record_parall_result (col1 integer, col2 varchar(10));" -a 2>&1 +create table tab_record_parall_result (col1 integer, col2 varchar(10)); +CREATE TABLE +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "insert into tab_record_parall_result (select seq_test_parral_currval.nextval, 'sess1'); insert into tab_record_parall_result (select seq_test_parral_currval.nextval, 'sess1'); insert into tab_record_parall_result (select seq_test_parral_currval.currval, 'sess1'); select pg_sleep(1); insert into tab_record_parall_result (select seq_test_parral_currval.currval, 'sess1');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(0.5); insert into tab_record_parall_result (select seq_test_parral_currval.nextval, 'sess2'); insert into tab_record_parall_result (select seq_test_parral_currval.nextval, 'sess2'); insert into tab_record_parall_result (select seq_test_parral_currval.currval, 'sess2');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(1.5);" -a 2>&1 +select pg_sleep(1.5); + pg_sleep +---------- + +(1 row) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select * from tab_record_parall_result;" -a 2>&1 +select * from tab_record_parall_result; + col1 | col2 +------+------- + 1 | sess1 + 2 | sess1 + 2 | sess1 + 21 | sess2 + 22 | sess2 + 22 | sess2 + 2 | sess1 +(7 rows) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop sequence seq_test_parral_currval;" -a 2>&1 +drop sequence seq_test_parral_currval; +DROP SEQUENCE +-- 3.4 test of concurrent: currval of sequence values after setval +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create sequence seq_test_parral_currval1 increment by 1 minvalue 1 maxvalue 100 cycle cache 20;" -a 2>&1 +create sequence seq_test_parral_currval1 increment by 1 minvalue 1 maxvalue 100 cycle cache 20; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +CREATE SEQUENCE +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "delete from tab_record_parall_result;" -a 2>&1 +delete from tab_record_parall_result; +DELETE 7 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "insert into tab_record_parall_result (select setval('seq_test_parral_currval1', 10), 'sess1'); insert into tab_record_parall_result (select seq_test_parral_currval1.currval, 'sess1'); select pg_sleep(1); insert into tab_record_parall_result (select seq_test_parral_currval1.currval, 'sess1');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(0.5); insert into tab_record_parall_result (select setval('seq_test_parral_currval1', 20), 'sess2'); insert into tab_record_parall_result (select seq_test_parral_currval1.currval, 'sess2');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(1.5);" -a 2>&1 +select pg_sleep(1.5); + pg_sleep +---------- + +(1 row) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select * from tab_record_parall_result;" -a 2>&1 +select * from tab_record_parall_result; + col1 | col2 +------+------- + 10 | sess1 + 10 | sess1 + 20 | sess2 + 20 | sess2 + 10 | sess1 +(5 rows) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop sequence seq_test_parral_currval1;" -a 2>&1 +drop sequence seq_test_parral_currval1; +DROP SEQUENCE +-- 3.5 test of concurrent: lastval of sequence values +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "create sequence seq_test_parral_lastval increment by 1 minvalue 1 maxvalue 100 cycle cache 20;" -a 2>&1 +create sequence seq_test_parral_lastval increment by 1 minvalue 1 maxvalue 100 cycle cache 20; +NOTICE: Not advised to use MAXVALUE or MINVALUE together with CACHE. +DETAIL: If CACHE is defined, some sequence values may be wasted, causing available sequence numbers to be less than expected. +CREATE SEQUENCE +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "delete from tab_record_parall_result;" -a 2>&1 +delete from tab_record_parall_result; +DELETE 5 +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "insert into tab_record_parall_result (select seq_test_parral_lastval.nextval, 'sess1'); insert into tab_record_parall_result (select seq_test_parral_lastval.nextval, 'sess1'); insert into tab_record_parall_result (select lastval(), 'sess1'); select pg_sleep(1); insert into tab_record_parall_result (select lastval(), 'sess1');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(0.5); insert into tab_record_parall_result (select seq_test_parral_lastval.nextval, 'sess2'); insert into tab_record_parall_result (select seq_test_parral_lastval.nextval, 'sess2'); insert into tab_record_parall_result (select lastval(), 'sess2');" >/dev/null -a 2>&1 & +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select pg_sleep(1.5);" -a 2>&1 +select pg_sleep(1.5); + pg_sleep +---------- + +(1 row) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "select * from tab_record_parall_result;" -a 2>&1 +select * from tab_record_parall_result; + col1 | col2 +------+------- + 1 | sess1 + 2 | sess1 + 2 | sess1 + 21 | sess2 + 22 | sess2 + 22 | sess2 + 2 | sess1 +(7 rows) + +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop sequence seq_test_parral_lastval;" -a 2>&1 +drop sequence seq_test_parral_lastval; +DROP SEQUENCE +\! @abs_bindir@/gsql -d regression -p @portstring@ -c "drop table tab_record_parall_result;" -a 2>&1 +drop table tab_record_parall_result; +DROP TABLE +-- 4.0 test alter sequence cache level +drop sequence alter_seq_cache_level; +ERROR: sequence "alter_seq_cache_level" does not exist +create sequence alter_seq_cache_level +increment by 1 +start 1 +no cycle +cache 10; +select alter_seq_cache_level.nextval; + nextval +--------- + 1 +(1 row) + +select alter_seq_cache_level.nextval; + nextval +--------- + 2 +(1 row) + +alter sequence alter_seq_cache_level global; +select alter_seq_cache_level.nextval; + nextval +--------- + 11 +(1 row) + +select alter_seq_cache_level.nextval; + nextval +--------- + 12 +(1 row) + +alter sequence alter_seq_cache_level session; +select alter_seq_cache_level.nextval; + nextval +--------- + 13 +(1 row) + +select alter_seq_cache_level.nextval; + nextval +--------- + 14 +(1 row) + +drop sequence alter_seq_cache_level; +drop schema if exists session_sequence_cache_schema cascade; +NOTICE: drop cascades to 4 other objects +DETAIL: drop cascades to table test_seqcache_for_parall +drop cascades to function proc_for_para_seq() +drop cascades to table test_seqcache_for_parall_boundary +drop cascades to function proc_for_para_seq_boundary() +drop database if exists dolphindb_seq; diff --git a/src/test/regress/parallel_schedule0 b/src/test/regress/parallel_schedule0 index 3c3d14dfaf..368d76ee38 100644 --- a/src/test/regress/parallel_schedule0 +++ b/src/test/regress/parallel_schedule0 @@ -1130,3 +1130,7 @@ test: enable_expr_fusion_flatten test: on_update_session1 on_update_session2 test: ts_gb18030_utf8 + +# test global sequence cache +test: session_sequence_cache +test: global_sequence_cache \ No newline at end of file -- Gitee