|
From: Pavan D. <pa...@us...> - 2010-06-24 07:33:34
|
Project "Postgres-XC".
The branch, master has been updated
via c0169fa52ff019450c45dd9e50502e12375f33f2 (commit)
from a216b00661e2b76267681bade35a620566fe9345 (commit)
- Log -----------------------------------------------------------------
commit c0169fa52ff019450c45dd9e50502e12375f33f2
Author: Pavan Deolasee <pav...@gm...>
Date: Thu Jun 24 13:00:09 2010 +0530
Add support for ALTER Sequence. Michael Paquier with some editorilization from Pavan Deolasee
diff --git a/src/backend/access/transam/gtm.c b/src/backend/access/transam/gtm.c
index c3cb72b..f9499c9 100644
--- a/src/backend/access/transam/gtm.c
+++ b/src/backend/access/transam/gtm.c
@@ -172,10 +172,8 @@ GetSnapshotGTM(GlobalTransactionId gxid, bool canbe_grouped)
}
-/**
+/*
* Create a sequence on the GTM.
- *
- *
*/
int
CreateSequenceGTM(char *seqname, GTM_Sequence increment, GTM_Sequence minval,
@@ -189,7 +187,45 @@ CreateSequenceGTM(char *seqname, GTM_Sequence increment, GTM_Sequence minval,
return conn ? open_sequence(conn, &seqkey, increment, minval, maxval, startval, cycle) : 0;
}
-/**
+/*
+ * Alter a sequence on the GTM
+ */
+int
+AlterSequenceGTM(char *seqname, GTM_Sequence increment, GTM_Sequence minval,
+ GTM_Sequence maxval, GTM_Sequence startval, GTM_Sequence lastval, bool cycle, bool is_restart)
+{
+ GTM_SequenceKeyData seqkey;
+ CheckConnection();
+ seqkey.gsk_keylen = strlen(seqname);
+ seqkey.gsk_key = seqname;
+
+ return conn ? alter_sequence(conn, &seqkey, increment, minval, maxval, startval, lastval, cycle, is_restart) : 0;
+}
+
+/*
+ * get the current sequence value
+ */
+
+GTM_Sequence
+GetCurrentValGTM(char *seqname)
+{
+ GTM_Sequence ret = -1;
+ GTM_SequenceKeyData seqkey;
+ CheckConnection();
+ seqkey.gsk_keylen = strlen(seqname);
+ seqkey.gsk_key = seqname;
+
+ if (conn)
+ ret = get_current(conn, &seqkey);
+ if (ret < 0)
+ {
+ CloseGTM();
+ InitGTM();
+ }
+ return ret;
+}
+
+/*
* Get the next sequence value
*/
GTM_Sequence
@@ -211,7 +247,21 @@ GetNextValGTM(char *seqname)
return ret;
}
-/**
+/*
+ * Set values for sequence
+ */
+int
+SetValGTM(char *seqname, GTM_Sequence nextval, bool iscalled)
+{
+ GTM_SequenceKeyData seqkey;
+ CheckConnection();
+ seqkey.gsk_keylen = strlen(seqname);
+ seqkey.gsk_key = seqname;
+
+ return conn ? set_val(conn, &seqkey, nextval, iscalled) : -1;
+}
+
+/*
* Drop the sequence
*/
int
@@ -224,3 +274,19 @@ DropSequenceGTM(char *seqname)
return conn ? close_sequence(conn, &seqkey) : -1;
}
+
+/*
+ * Rename the sequence
+ */
+int
+RenameSequenceGTM(char *seqname, const char *newseqname)
+{
+ GTM_SequenceKeyData seqkey, newseqkey;
+ CheckConnection();
+ seqkey.gsk_keylen = strlen(seqname);
+ seqkey.gsk_key = seqname;
+ newseqkey.gsk_keylen = strlen(newseqname);
+ newseqkey.gsk_key = (char *)newseqname;
+
+ return conn ? rename_sequence(conn, &seqkey, &newseqkey) : -1;
+}
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index ba9a932..ba30206 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -35,6 +35,7 @@
#include "utils/lsyscache.h"
#include "utils/resowner.h"
#include "utils/syscache.h"
+#include "commands/dbcommands.h"
#ifdef PGXC
#include "pgxc/pgxc.h"
@@ -97,8 +98,13 @@ static int64 nextval_internal(Oid relid);
static Relation open_share_lock(SeqTable seq);
static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel);
static Form_pg_sequence read_info(SeqTable elm, Relation rel, Buffer *buf);
+#ifdef PGXC
+static void init_params(List *options, bool isInit,
+ Form_pg_sequence new, List **owned_by, bool *is_restart);
+#else
static void init_params(List *options, bool isInit,
- Form_pg_sequence new, List **owned_by);
+ Form_pg_sequence new, List **owned_by);
+#endif
static void do_setval(Oid relid, int64 next, bool iscalled);
static void process_owned_by(Relation seqrel, List *owned_by);
@@ -130,10 +136,15 @@ DefineSequence(CreateSeqStmt *seq)
GTM_Sequence max_value = InvalidSequenceValue;
GTM_Sequence increment = 1;
bool cycle = false;
+ bool is_restart;
#endif
/* Check and set all option values */
+#ifdef PGXC
+ init_params(seq->options, true, &new, &owned_by, &is_restart);
+#else
init_params(seq->options, true, &new, &owned_by);
+#endif
/*
* Create relation (and fill value[] and null[] for the tuple)
@@ -341,14 +352,20 @@ DefineSequence(CreateSeqStmt *seq)
#ifdef PGXC /* PGXC_COORD */
if (IS_PGXC_COORDINATOR)
{
+ char *seqname = GetGlobalSeqName(rel, NULL);
+
/* We also need to create it on the GTM */
- if (CreateSequenceGTM(name.data, increment, min_value, max_value,
+ if (CreateSequenceGTM(seqname,
+ increment,
+ min_value,
+ max_value,
start_value, cycle) < 0)
{
ereport(ERROR,
(errcode(ERRCODE_CONNECTION_FAILURE),
errmsg("GTM error, could not create sequence")));
}
+ pfree(seqname);
}
#endif
}
@@ -392,6 +409,15 @@ AlterSequenceInternal(Oid relid, List *options)
Form_pg_sequence seq;
FormData_pg_sequence new;
List *owned_by;
+#ifdef PGXC
+ GTM_Sequence start_value;
+ GTM_Sequence last_value;
+ GTM_Sequence min_value;
+ GTM_Sequence max_value;
+ GTM_Sequence increment;
+ bool cycle;
+ bool is_restart;
+#endif
/* open and AccessShareLock sequence */
init_sequence(relid, &elm, &seqrel);
@@ -404,7 +430,11 @@ AlterSequenceInternal(Oid relid, List *options)
memcpy(&new, seq, sizeof(FormData_pg_sequence));
/* Check and set new values */
+#ifdef PGXC
+ init_params(options, false, &new, &owned_by, &is_restart);
+#else
init_params(options, false, &new, &owned_by);
+#endif
/* Clear local cache so that we don't think we have cached numbers */
/* Note that we do not change the currval() state */
@@ -413,6 +443,15 @@ AlterSequenceInternal(Oid relid, List *options)
/* Now okay to update the on-disk tuple */
memcpy(seq, &new, sizeof(FormData_pg_sequence));
+#ifdef PGXC
+ increment = new.increment_by;
+ min_value = new.min_value;
+ max_value = new.max_value;
+ start_value = new.start_value;
+ last_value = new.last_value;
+ cycle = new.is_cycled;
+#endif
+
START_CRIT_SECTION();
MarkBufferDirty(buf);
@@ -451,6 +490,27 @@ AlterSequenceInternal(Oid relid, List *options)
process_owned_by(seqrel, owned_by);
relation_close(seqrel, NoLock);
+
+#ifdef PGXC
+ if (IS_PGXC_COORDINATOR)
+ {
+ char *seqname = GetGlobalSeqName(seqrel, NULL);
+
+ /* We also need to create it on the GTM */
+ if (AlterSequenceGTM(seqname,
+ increment,
+ min_value,
+ max_value,
+ start_value,
+ last_value,
+ cycle,
+ is_restart) < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_CONNECTION_FAILURE),
+ errmsg("GTM error, could not alter sequence")));
+ pfree(seqname);
+ }
+#endif
}
@@ -527,14 +587,22 @@ nextval_internal(Oid relid)
#ifdef PGXC /* PGXC_COORD */
if (IS_PGXC_COORDINATOR)
{
- /* Above, we still use the page as a locking mechanism to handle
- * concurrency
+ char *seqname = GetGlobalSeqName(seqrel, NULL);
+
+ /*
+ * Above, we still use the page as a locking mechanism to handle
+ * concurrency
*/
- result = (int64) GetNextValGTM(RelationGetRelationName(seqrel));
+ result = (int64) GetNextValGTM(seqname);
if (result < 0)
ereport(ERROR,
- (errcode(ERRCODE_CONNECTION_FAILURE),
- errmsg("GTM error, could not obtain sequence value")));
+ (errcode(ERRCODE_CONNECTION_FAILURE),
+ errmsg("GTM error, could not obtain sequence value")));
+ pfree(seqname);
+
+ /* Update the on-disk data */
+ seq->last_value = result; /* last fetched number */
+ seq->is_called = true;
} else
{
#endif
@@ -714,6 +782,22 @@ currval_oid(PG_FUNCTION_ARGS)
/* open and AccessShareLock sequence */
init_sequence(relid, &elm, &seqrel);
+#ifdef PGXC
+ if (IS_PGXC_COORDINATOR)
+ {
+ char *seqname = GetGlobalSeqName(seqrel, NULL);
+
+ result = (int64) GetCurrentValGTM(seqname);
+ if (result < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_CONNECTION_FAILURE),
+ errmsg("GTM error, could not obtain sequence value")));
+ pfree(seqname);
+ }
+ else
+ {
+#endif
+
if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK &&
pg_class_aclcheck(elm->relid, GetUserId(), ACL_USAGE) != ACLCHECK_OK)
ereport(ERROR,
@@ -729,6 +813,10 @@ currval_oid(PG_FUNCTION_ARGS)
result = elm->last;
+#ifdef PGXC
+ }
+#endif
+
relation_close(seqrel, NoLock);
PG_RETURN_INT64(result);
@@ -820,6 +908,24 @@ do_setval(Oid relid, int64 next, bool iscalled)
bufm, bufx)));
}
+#ifdef PGXC
+ if (IS_PGXC_COORDINATOR)
+ {
+ char *seqname = GetGlobalSeqName(seqrel, NULL);
+
+ if (SetValGTM(seqname, next, iscalled) < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_CONNECTION_FAILURE),
+ errmsg("GTM error, could not obtain sequence value")));
+ pfree(seqname);
+ /* Update the on-disk data */
+ seq->last_value = next; /* last fetched number */
+ seq->is_called = iscalled;
+ }
+ else
+ {
+#endif
+
/* Set the currval() state only if iscalled = true */
if (iscalled)
{
@@ -872,6 +978,10 @@ do_setval(Oid relid, int64 next, bool iscalled)
END_CRIT_SECTION();
+#ifdef PGXC
+ }
+#endif
+
UnlockReleaseBuffer(buf);
relation_close(seqrel, NoLock);
@@ -1050,8 +1160,13 @@ read_info(SeqTable elm, Relation rel, Buffer *buf)
* otherwise, do not change existing options that aren't explicitly overridden.
*/
static void
+#ifdef PGXC
+init_params(List *options, bool isInit,
+ Form_pg_sequence new, List **owned_by, bool *is_restart)
+#else
init_params(List *options, bool isInit,
Form_pg_sequence new, List **owned_by)
+#endif
{
DefElem *start_value = NULL;
DefElem *restart_value = NULL;
@@ -1062,6 +1177,10 @@ init_params(List *options, bool isInit,
DefElem *is_cycled = NULL;
ListCell *option;
+#ifdef PGXC
+ *is_restart = false;
+#endif
+
*owned_by = NIL;
foreach(option, options)
@@ -1227,8 +1346,8 @@ init_params(List *options, bool isInit,
snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->max_value);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("START value (%s) cannot be greater than MAXVALUE (%s)",
- bufs, bufm)));
+ errmsg("START value (%s) cannot be greater than MAXVALUE (%s)",
+ bufs, bufm)));
}
/* RESTART [WITH] */
@@ -1238,6 +1357,9 @@ init_params(List *options, bool isInit,
new->last_value = defGetInt64(restart_value);
else
new->last_value = new->start_value;
+#ifdef PGXC
+ *is_restart = true;
+#endif
new->is_called = false;
new->log_cnt = 1;
}
@@ -1258,8 +1380,8 @@ init_params(List *options, bool isInit,
snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("RESTART value (%s) cannot be less than MINVALUE (%s)",
- bufs, bufm)));
+ errmsg("RESTART value (%s) cannot be less than MINVALUE (%s)",
+ bufs, bufm)));
}
if (new->last_value > new->max_value)
{
@@ -1270,8 +1392,8 @@ init_params(List *options, bool isInit,
snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->max_value);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("RESTART value (%s) cannot be greater than MAXVALUE (%s)",
- bufs, bufm)));
+ errmsg("RESTART value (%s) cannot be greater than MAXVALUE (%s)",
+ bufs, bufm)));
}
/* CACHE */
@@ -1293,6 +1415,49 @@ init_params(List *options, bool isInit,
new->cache_value = 1;
}
+#ifdef PGXC
+/*
+ * Returns a global sequence name adapted to GTM
+ * Name format is dbname.schemaname.seqname
+ * so as to identify in a unique way in the whole cluster each sequence
+ */
+
+char *
+GetGlobalSeqName(Relation seqrel, const char *new_seqname)
+{
+ char *seqname, *dbname, *schemaname, *relname;
+ int charlen;
+
+ /* Get all the necessary relation names */
+ dbname = get_database_name(seqrel->rd_node.dbNode);
+ schemaname = get_namespace_name(RelationGetNamespace(seqrel));
+
+ if (new_seqname)
+ relname = new_seqname;
+ else
+ relname = RelationGetRelationName(seqrel);
+
+ /* Calculate the global name size including the dots and \0 */
+ charlen = strlen(dbname) + strlen(schemaname) + strlen(relname) + 3;
+ seqname = (char *) palloc(charlen);
+
+ /* Form a unique sequence name with schema and database name for GTM */
+ snprintf(seqname,
+ charlen,
+ "%s.%s.%s",
+ dbname,
+ schemaname,
+ relname);
+
+ if (dbname)
+ pfree(dbname);
+ if (schemaname)
+ pfree(schemaname);
+
+ return seqname;
+}
+#endif
+
/*
* Process an OWNED BY option for CREATE/ALTER SEQUENCE
*
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index fa6456a..33782c4 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -768,14 +768,27 @@ RemoveRelations(DropStmt *drop)
add_exact_object_address(&obj, objects);
-
#ifdef PGXC /* PGXC_COORD */
/* PGXCTODO: allow the ability to rollback dropping sequences. */
/* Drop the sequence */
if (IS_PGXC_COORDINATOR && classform->relkind == RELKIND_SEQUENCE)
{
- DropSequenceGTM(rel->relname);
+ Relation relseq;
+ char *seqname;
+
+ /*
+ * A relation is opened to get the schema and database name as
+ * such data is not available before when dropping a function.
+ */
+ relseq = relation_open(obj.objectId, AccessShareLock);
+ seqname = GetGlobalSeqName(relseq, NULL);
+
+ DropSequenceGTM(seqname);
+ pfree(seqname);
+
+ /* Then close the relation opened previously */
+ relation_close(relseq, AccessShareLock);
}
#endif
ReleaseSysCache(tuple);
@@ -2103,6 +2116,20 @@ RenameRelation(Oid myrelid, const char *newrelname, ObjectType reltype)
/* Do the work */
RenameRelationInternal(myrelid, newrelname, namespaceId);
+#ifdef PGXC
+ if (IS_PGXC_COORDINATOR &&
+ (reltype == OBJECT_SEQUENCE || relkind == RELKIND_SEQUENCE)) /* It is possible to rename a sequence with ALTER TABLE */
+ {
+ char *seqname = GetGlobalSeqName(targetrelation, NULL);
+ char *newseqname = GetGlobalSeqName(targetrelation, newrelname);
+
+ /* We also need to rename it on the GTM */
+ if (RenameSequenceGTM(seqname, newseqname) < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_CONNECTION_FAILURE),
+ errmsg("GTM error, could not rename sequence")));
+ }
+#endif
/*
* Close rel, but keep exclusive lock!
diff --git a/src/backend/pgxc/plan/planner.c b/src/backend/pgxc/plan/planner.c
index 0d73fc9..0fb4a2b 100644
--- a/src/backend/pgxc/plan/planner.c
+++ b/src/backend/pgxc/plan/planner.c
@@ -1466,14 +1466,9 @@ GetQueryPlan(Node *parsetree, const char *sql_statement, List *querytree_list)
{
query_plan->exec_loc_type = EXEC_ON_DATA_NODES;
- /*
- * If the nodelist is NULL, it is not safe for us to
- * execute
- */
- if (!query_step->exec_nodes && StrictStatementChecking)
- ereport(ERROR,
- (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
- (errmsg("Cannot safely execute statement in a single step."))));
+ /* If node list is NULL, execute on coordinator */
+ if (!query_step->exec_nodes)
+ query_plan->exec_loc_type = EXEC_ON_COORD;
}
}
@@ -1517,19 +1512,10 @@ GetQueryPlan(Node *parsetree, const char *sql_statement, List *querytree_list)
break;
/* Statements that we only want to execute on the Coordinator */
- case T_CreateSeqStmt:
case T_VariableShowStmt:
query_plan->exec_loc_type = EXEC_ON_COORD;
break;
- /* DROP */
- case T_DropStmt:
- if (((DropStmt *) parsetree)->removeType == OBJECT_SEQUENCE)
- query_plan->exec_loc_type = EXEC_ON_COORD;
- else
- query_plan->exec_loc_type = EXEC_ON_COORD | EXEC_ON_DATA_NODES;
- break;
-
/*
* Statements that need to run in autocommit mode, on Coordinator
* and Data Nodes with suppressed implicit two phase commit.
@@ -1542,51 +1528,7 @@ GetQueryPlan(Node *parsetree, const char *sql_statement, List *querytree_list)
query_plan->exec_loc_type = EXEC_ON_COORD | EXEC_ON_DATA_NODES;
query_plan->force_autocommit = true;
break;
- case T_AlterObjectSchemaStmt:
- /* Sequences are just defined on coordinator */
- if (((AlterObjectSchemaStmt *) parsetree)->objectType == OBJECT_SEQUENCE)
- query_plan->exec_loc_type = EXEC_ON_COORD;
- else
- query_plan->exec_loc_type = EXEC_ON_COORD | EXEC_ON_DATA_NODES;
- break;
- case T_AlterSeqStmt:
- /* Alter sequence is not supported yet, it needs complementary interactions with GTM */
- ereport(ERROR,
- (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
- (errmsg("This command is not yet supported"))));
- break;
- case T_AlterTableStmt:
- /*
- * ALTER SEQUENCE needs some interactions with GTM,
- * this query is not supported yet.
- */
- if (((AlterTableStmt *) parsetree)->relkind == OBJECT_SEQUENCE)
- ereport(ERROR,
- (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
- (errmsg("Cannot yet alter a sequence"))));
- else
- query_plan->exec_loc_type = EXEC_ON_COORD | EXEC_ON_DATA_NODES;
- break;
- case T_CommentStmt:
- /* Sequences are only defined on coordinator */
- if (((CommentStmt *) parsetree)->objtype == OBJECT_SEQUENCE)
- query_plan->exec_loc_type = EXEC_ON_COORD;
- else
- query_plan->exec_loc_type = EXEC_ON_COORD | EXEC_ON_DATA_NODES;
- break;
- case T_RenameStmt:
- /* Sequences are only defined on coordinator */
- if (((RenameStmt *) parsetree)->renameType == OBJECT_SEQUENCE)
- /*
- * Renaming a sequence requires interactions with GTM
- * what is not supported yet
- */
- ereport(ERROR,
- (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
- (errmsg("Sequence renaming not yet supported, you should drop it and created a new one"))));
- else
- query_plan->exec_loc_type = EXEC_ON_COORD | EXEC_ON_DATA_NODES;
- break;
+
case T_DropPropertyStmt:
/*
* Triggers are not yet supported by PGXC
@@ -1619,10 +1561,14 @@ GetQueryPlan(Node *parsetree, const char *sql_statement, List *querytree_list)
case T_AlterFdwStmt:
case T_AlterForeignServerStmt:
case T_AlterFunctionStmt:
+ case T_AlterObjectSchemaStmt:
case T_AlterOpFamilyStmt:
+ case T_AlterSeqStmt:
+ case T_AlterTableStmt: /* Can also be used to rename a sequence */
case T_AlterTSConfigurationStmt:
case T_AlterTSDictionaryStmt:
- case T_ClosePortalStmt: /* In case CLOSE ALL is issued */
+ case T_ClosePortalStmt: /* In case CLOSE ALL is issued */
+ case T_CommentStmt:
case T_CompositeTypeStmt:
case T_ConstraintsSetStmt:
case T_CreateCastStmt:
@@ -1635,19 +1581,22 @@ GetQueryPlan(Node *parsetree, const char *sql_statement, List *querytree_list)
case T_CreateOpClassStmt:
case T_CreateOpFamilyStmt:
case T_CreatePLangStmt:
+ case T_CreateSeqStmt:
case T_CreateSchemaStmt:
- case T_DeallocateStmt: /* Allow for DEALLOCATE ALL */
+ case T_DeallocateStmt: /* Allow for DEALLOCATE ALL */
case T_DiscardStmt:
case T_DropCastStmt:
case T_DropFdwStmt:
case T_DropForeignServerStmt:
case T_DropPLangStmt:
+ case T_DropStmt:
case T_IndexStmt:
case T_LockStmt:
case T_ReindexStmt:
case T_RemoveFuncStmt:
case T_RemoveOpClassStmt:
case T_RemoveOpFamilyStmt:
+ case T_RenameStmt:
case T_TruncateStmt:
case T_VariableSetStmt:
case T_ViewStmt:
@@ -1695,11 +1644,11 @@ GetQueryPlan(Node *parsetree, const char *sql_statement, List *querytree_list)
* data node will do
*/
case T_ExplainStmt:
- if (((ExplainStmt *) parsetree)->analyze)
+ if (((ExplainStmt *) parsetree)->analyze)
ereport(ERROR,
(errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
(errmsg("ANALYZE with EXPLAIN is currently not supported."))));
-
+
query_step->exec_nodes = palloc0(sizeof(Exec_Nodes));
query_step->exec_nodes->nodelist = GetAnyDataNode();
query_step->exec_nodes->baselocatortype = LOCATOR_TYPE_RROBIN;
diff --git a/src/gtm/client/fe-protocol.c b/src/gtm/client/fe-protocol.c
index a102202..051bb1d 100644
--- a/src/gtm/client/fe-protocol.c
+++ b/src/gtm/client/fe-protocol.c
@@ -493,12 +493,16 @@ gtmpqParseSuccess(GTM_Conn *conn, GTM_Result *result)
case SEQUENCE_INIT_RESULT:
case SEQUENCE_RESET_RESULT:
case SEQUENCE_CLOSE_RESULT:
+ case SEQUENCE_RENAME_RESULT:
+ case SEQUENCE_ALTER_RESULT:
+ case SEQUENCE_SET_VAL_RESULT:
if (gtmpqReadSeqKey(&result->gr_resdata.grd_seqkey, conn))
result->gr_status = -1;
break;
case SEQUENCE_GET_CURRENT_RESULT:
case SEQUENCE_GET_NEXT_RESULT:
+ case SEQUENCE_GET_LAST_RESULT:
if (gtmpqReadSeqKey(&result->gr_resdata.grd_seq.seqkey, conn))
{
result->gr_status = -1;
@@ -566,6 +570,9 @@ gtmpqFreeResultData(GTM_Result *result, bool is_proxy)
case SEQUENCE_INIT_RESULT:
case SEQUENCE_RESET_RESULT:
case SEQUENCE_CLOSE_RESULT:
+ case SEQUENCE_RENAME_RESULT:
+ case SEQUENCE_ALTER_RESULT:
+ case SEQUENCE_SET_VAL_RESULT:
if (result->gr_resdata.grd_seqkey.gsk_key != NULL)
free(result->gr_resdata.grd_seqkey.gsk_key);
result->gr_resdata.grd_seqkey.gsk_key = NULL;
@@ -573,6 +580,7 @@ gtmpqFreeResultData(GTM_Result *result, bool is_proxy)
case SEQUENCE_GET_CURRENT_RESULT:
case SEQUENCE_GET_NEXT_RESULT:
+ case SEQUENCE_GET_LAST_RESULT:
if (result->gr_resdata.grd_seq.seqkey.gsk_key != NULL)
free(result->gr_resdata.grd_seq.seqkey.gsk_key);
result->gr_resdata.grd_seqkey.gsk_key = NULL;
diff --git a/src/gtm/client/gtm_client.c b/src/gtm/client/gtm_client.c
index 089689e..9df28c7 100644
--- a/src/gtm/client/gtm_client.c
+++ b/src/gtm/client/gtm_client.c
@@ -356,6 +356,51 @@ send_failed:
}
int
+alter_sequence(GTM_Conn *conn, GTM_SequenceKey key, GTM_Sequence increment,
+ GTM_Sequence minval, GTM_Sequence maxval,
+ GTM_Sequence startval, GTM_Sequence lastval, bool cycle, bool is_restart)
+{
+ GTM_Result *res = NULL;
+ time_t finish_time;
+
+ /* Start the message. */
+ if (gtmpqPutMsgStart('C', true, conn) ||
+ gtmpqPutInt(MSG_SEQUENCE_ALTER, sizeof (GTM_MessageType), conn) ||
+ gtmpqPutInt(key->gsk_keylen, 4, conn) ||
+ gtmpqPutnchar(key->gsk_key, key->gsk_keylen, conn) ||
+ gtmpqPutnchar((char *)&increment, sizeof (GTM_Sequence), conn) ||
+ gtmpqPutnchar((char *)&minval, sizeof (GTM_Sequence), conn) ||
+ gtmpqPutnchar((char *)&maxval, sizeof (GTM_Sequence), conn) ||
+ gtmpqPutnchar((char *)&startval, sizeof (GTM_Sequence), conn) ||
+ gtmpqPutnchar((char *)&lastval, sizeof (GTM_Sequence), conn) ||
+ gtmpqPutc(cycle, conn) ||
+ gtmpqPutc(is_restart, conn))
+ goto send_failed;
+
+ /* Finish the message. */
+ if (gtmpqPutMsgEnd(conn))
+ goto send_failed;
+
+ /* Flush to ensure backend gets it. */
+ if (gtmpqFlush(conn))
+ goto send_failed;
+
+ finish_time = time(NULL) + CLIENT_GTM_TIMEOUT;
+ if (gtmpqWaitTimed(true, false, conn, finish_time) ||
+ gtmpqReadData(conn) < 0)
+ goto receive_failed;
+
+ if ((res = GTMPQgetResult(conn)) == NULL)
+ goto receive_failed;
+
+ return res->gr_status;
+
+receive_failed:
+send_failed:
+ return -1;
+}
+
+int
close_sequence(GTM_Conn *conn, GTM_SequenceKey key)
{
GTM_Result *res = NULL;
@@ -391,6 +436,44 @@ send_failed:
return -1;
}
+int
+rename_sequence(GTM_Conn *conn, GTM_SequenceKey key, GTM_SequenceKey newkey)
+{
+ GTM_Result *res = NULL;
+ time_t finish_time;
+
+ /* Start the message. */
+ if (gtmpqPutMsgStart('C', true, conn) ||
+ gtmpqPutInt(MSG_SEQUENCE_RENAME, sizeof (GTM_MessageType), conn) ||
+ gtmpqPutInt(key->gsk_keylen, 4, conn) ||
+ gtmpqPutnchar(key->gsk_key, key->gsk_keylen, conn)||
+ gtmpqPutInt(newkey->gsk_keylen, 4, conn) ||
+ gtmpqPutnchar(newkey->gsk_key, newkey->gsk_keylen, conn))
+ goto send_failed;
+
+ /* Finish the message. */
+ if (gtmpqPutMsgEnd(conn))
+ goto send_failed;
+
+ /* Flush to ensure backend gets it. */
+ if (gtmpqFlush(conn))
+ goto send_failed;
+
+ finish_time = time(NULL) + CLIENT_GTM_TIMEOUT;
+ if (gtmpqWaitTimed(true, false, conn, finish_time) ||
+ gtmpqReadData(conn) < 0)
+ goto receive_failed;
+
+ if ((res = GTMPQgetResult(conn)) == NULL)
+ goto receive_failed;
+
+ return res->gr_status;
+
+ receive_failed:
+ send_failed:
+ return -1;
+}
+
GTM_Sequence
get_current(GTM_Conn *conn, GTM_SequenceKey key)
{
@@ -430,13 +513,51 @@ send_failed:
return -1;
}
+int
+set_val(GTM_Conn *conn, GTM_SequenceKey key, GTM_Sequence nextval, bool iscalled)
+{
+ GTM_Result *res = NULL;
+ time_t finish_time;
+
+ /* Start the message. */
+ if (gtmpqPutMsgStart('C', true, conn) ||
+ gtmpqPutInt(MSG_SEQUENCE_SET_VAL, sizeof (GTM_MessageType), conn) ||
+ gtmpqPutInt(key->gsk_keylen, 4, conn) ||
+ gtmpqPutnchar(key->gsk_key, key->gsk_keylen, conn) ||
+ gtmpqPutnchar((char *)&nextval, sizeof (GTM_Sequence), conn) ||
+ gtmpqPutc(iscalled, conn))
+ goto send_failed;
+
+ /* Finish the message. */
+ if (gtmpqPutMsgEnd(conn))
+ goto send_failed;
+
+ /* Flush to ensure backend gets it. */
+ if (gtmpqFlush(conn))
+ goto send_failed;
+
+ finish_time = time(NULL) + CLIENT_GTM_TIMEOUT;
+ if (gtmpqWaitTimed(true, false, conn, finish_time) ||
+ gtmpqReadData(conn) < 0)
+ goto receive_failed;
+
+ if ((res = GTMPQgetResult(conn)) == NULL)
+ goto receive_failed;
+
+ return res->gr_status;
+
+receive_failed:
+send_failed:
+ return -1;
+}
+
GTM_Sequence
get_next(GTM_Conn *conn, GTM_SequenceKey key)
{
GTM_Result *res = NULL;
time_t finish_time;
- /* Start the message. */
+ /* Start the message. */
if (gtmpqPutMsgStart('C', true, conn) ||
gtmpqPutInt(MSG_SEQUENCE_GET_NEXT, sizeof (GTM_MessageType), conn) ||
gtmpqPutInt(key->gsk_keylen, 4, conn) ||
diff --git a/src/gtm/main/gtm_seq.c b/src/gtm/main/gtm_seq.c
index 73af34e..8611f40 100644
--- a/src/gtm/main/gtm_seq.c
+++ b/src/gtm/main/gtm_seq.c
@@ -326,9 +326,12 @@ GTM_SeqOpen(GTM_SequenceKey seqkey,
*/
seqinfo->gs_cycle = cycle;
+ /* Set the last value in case of a future restart */
+ seqinfo->gs_last_value = seqinfo->gs_init_value;
+
if ((errcode = seq_add_seqinfo(seqinfo)))
{
- GTM_RWLockDestroy(&seqinfo->gs_lock);
+ GTM_RWLockDestroy(&seqinfo->gs_lock);
pfree(seqinfo->gs_key);
pfree(seqinfo);
}
@@ -336,6 +339,62 @@ GTM_SeqOpen(GTM_SequenceKey seqkey,
}
/*
+ * Alter a sequence
+ */
+int GTM_SeqAlter(GTM_SequenceKey seqkey,
+ GTM_Sequence increment_by,
+ GTM_Sequence minval,
+ GTM_Sequence maxval,
+ GTM_Sequence startval,
+ GTM_Sequence lastval,
+ bool cycle,
+ bool is_restart)
+{
+ GTM_SeqInfo *seqinfo = seq_find_seqinfo(seqkey);
+
+ if (seqinfo == NULL)
+ {
+ ereport(LOG,
+ (EINVAL,
+ errmsg("The sequence with the given key does not exist")));
+ return EINVAL;
+ }
+
+ GTM_RWLockAcquire(&seqinfo->gs_lock, GTM_LOCKMODE_WRITE);
+
+ /* Modify the data if necessary */
+
+ if (seqinfo->gs_cycle != cycle)
+ seqinfo->gs_cycle = cycle;
+ if (seqinfo->gs_min_value != minval)
+ seqinfo->gs_min_value = minval;
+ if (seqinfo->gs_max_value != maxval)
+ seqinfo->gs_max_value = maxval;
+ if (seqinfo->gs_increment_by != increment_by)
+ seqinfo->gs_increment_by = increment_by;
+
+ /* Here Restart has been used with a value, reinitialize last_value to a new value */
+ if (seqinfo->gs_last_value != lastval)
+ seqinfo->gs_last_value = lastval;
+
+ /* Start has been used, reinitialize init value */
+ if (seqinfo->gs_init_value != startval)
+ seqinfo->gs_last_value = seqinfo->gs_init_value = startval;
+
+ /* Restart command has been used, reset the sequence */
+ if (is_restart)
+ {
+ seqinfo->gs_called = false;
+ seqinfo->gs_init_value = seqinfo->gs_last_value;
+ }
+
+ /* Remove the old key with the old name */
+ GTM_RWLockRelease(&seqinfo->gs_lock);
+ seq_release_seqinfo(seqinfo);
+ return 0;
+}
+
+/*
* Restore a sequence.
*/
static int
@@ -367,7 +426,7 @@ GTM_SeqRestore(GTM_SequenceKey seqkey,
seqinfo->gs_min_value = minval;
seqinfo->gs_max_value = maxval;
- seqinfo->gs_init_value = startval;
+ seqinfo->gs_init_value = seqinfo->gs_last_value = startval;
seqinfo->gs_value = curval;
/*
@@ -402,6 +461,66 @@ GTM_SeqClose(GTM_SequenceKey seqkey)
}
/*
+ * Rename an existing sequence with a new name
+ */
+int
+GTM_SeqRename(GTM_SequenceKey seqkey, GTM_SequenceKey newseqkey)
+{
+ GTM_SeqInfo *seqinfo = seq_find_seqinfo(seqkey);
+ GTM_SeqInfo *newseqinfo = NULL;
+ int errcode = 0;
+
+ /* replace old key by new key */
+ if (seqinfo == NULL)
+ {
+ ereport(LOG,
+ (EINVAL,
+ errmsg("The sequence with the given key does not exist")));
+ return EINVAL;
+ }
+
+ /* Now create the new sequence info */
+ newseqinfo = (GTM_SeqInfo *) palloc(sizeof (GTM_SeqInfo));
+
+ GTM_RWLockAcquire(&seqinfo->gs_lock, GTM_LOCKMODE_WRITE);
+ GTM_RWLockInit(&newseqinfo->gs_lock);
+
+ newseqinfo->gs_ref_count = 0;
+ newseqinfo->gs_key = seq_copy_key(newseqkey);
+ newseqinfo->gs_state = seqinfo->gs_state;
+ newseqinfo->gs_called = seqinfo->gs_called;
+
+ newseqinfo->gs_increment_by = seqinfo->gs_increment_by;
+ newseqinfo->gs_min_value = seqinfo->gs_min_value;
+ newseqinfo->gs_max_value = seqinfo->gs_max_value;
+
+ newseqinfo->gs_init_value = seqinfo->gs_init_value;
+ newseqinfo->gs_value = seqinfo->gs_value;
+ newseqinfo->gs_cycle = seqinfo->gs_cycle;
+
+ newseqinfo->gs_state = seqinfo->gs_state;
+ newseqinfo->gs_last_value = seqinfo->gs_last_value;
+
+ /* Add the copy to the list */
+ if ((errcode = seq_add_seqinfo(newseqinfo))) /* a lock is taken here for the new sequence */
+ {
+ GTM_RWLockDestroy(&newseqinfo->gs_lock);
+ pfree(newseqinfo->gs_key);
+ pfree(newseqinfo);
+ return errcode;
+ }
+
+ /* Remove the old key with the old name */
+ GTM_RWLockRelease(&seqinfo->gs_lock);
+ /* Release first the structure as it has been taken previously */
+ seq_release_seqinfo(seqinfo);
+
+ /* Then close properly the old sequence */
+ GTM_SeqClose(seqkey);
+ return errcode;
+}
+
+/*
* Get current value for the sequence without incrementing it
*/
GTM_Sequence
@@ -436,7 +555,37 @@ GTM_SeqGetCurrent(GTM_SequenceKey seqkey)
}
/*
- * Get next vlaue for the sequence
+ * Set values for the sequence
+ */
+int
+GTM_SeqSetVal(GTM_SequenceKey seqkey, GTM_Sequence nextval, bool iscalled)
+{
+ GTM_SeqInfo *seqinfo = seq_find_seqinfo(seqkey);
+
+ if (seqinfo == NULL)
+ {
+ ereport(LOG,
+ (EINVAL,
+ errmsg("The sequence with the given key does not exist")));
+ return EINVAL;
+ }
+
+ GT...
[truncated message content] |