diff --git a/Makefile b/Makefile index 10841d743..9574600ad 100644 --- a/Makefile +++ b/Makefile @@ -13,14 +13,14 @@ include Makefile.global all: extension # build extension -extension: +extension: $(citus_abs_srcdir)/src/include/citus_version.h $(MAKE) -C src/backend/distributed/ all install-extension: extension $(MAKE) -C src/backend/distributed/ install install-headers: extension $(MKDIR_P) '$(DESTDIR)$(includedir_server)/distributed/' # generated headers are located in the build directory - $(INSTALL_DATA) src/include/citus_config.h '$(DESTDIR)$(includedir_server)/' + $(INSTALL_DATA) $(citus_abs_srcdir)/src/include/citus_config.h '$(DESTDIR)$(includedir_server)/' # the rest in the source tree $(INSTALL_DATA) $(citus_abs_srcdir)/src/include/distributed/*.h '$(DESTDIR)$(includedir_server)/distributed/' clean-extension: diff --git a/Makefile.global.in b/Makefile.global.in index 7cdbcd5d9..57678e137 100644 --- a/Makefile.global.in +++ b/Makefile.global.in @@ -44,8 +44,8 @@ $(citus_top_builddir)/Makefile.global: $(citus_abs_top_srcdir)/configure $(citus # Ensure configuration is generated by the most recent configure, # useful for longer existing build directories. -$(citus_top_builddir)/config.status: $(citus_abs_top_srcdir)/configure - cd @abs_top_builddir@ && ./config.status --recheck +$(citus_top_builddir)/config.status: $(citus_abs_top_srcdir)/configure $(citus_abs_top_srcdir)/src/backend/distributed/citus.control + cd @abs_top_builddir@ && ./config.status --recheck && ./config.status # Regenerate configure if configure.in changed $(citus_abs_top_srcdir)/configure: $(citus_abs_top_srcdir)/configure.in diff --git a/configure b/configure index c46b262b8..8ec14379c 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for Citus 5.0. +# Generated by GNU Autoconf 2.69 for Citus 6.2devel. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -9,7 +9,7 @@ # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # -# Copyright (c) 2012-2016, Citus Data, Inc. +# Copyright (c) 2012-2017, Citus Data, Inc. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## @@ -579,8 +579,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='Citus' PACKAGE_TARNAME='citus' -PACKAGE_VERSION='5.0' -PACKAGE_STRING='Citus 5.0' +PACKAGE_VERSION='6.2devel' +PACKAGE_STRING='Citus 6.2devel' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1194,7 +1194,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures Citus 5.0 to adapt to many kinds of systems. +\`configure' configures Citus 6.2devel to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1255,7 +1255,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of Citus 5.0:";; + short | recursive ) echo "Configuration of Citus 6.2devel:";; esac cat <<\_ACEOF @@ -1343,14 +1343,14 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -Citus configure 5.0 +Citus configure 6.2devel generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. -Copyright (c) 2012-2016, Citus Data, Inc. +Copyright (c) 2012-2017, Citus Data, Inc. _ACEOF exit fi @@ -1400,7 +1400,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by Citus $as_me 5.0, which was +It was created by Citus $as_me 6.2devel, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -1750,6 +1750,39 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu +# CITUS_MAJORVERSION definition +CITUS_MAJORVERSION=`expr "$PACKAGE_VERSION" : '\([0-9][0-9]*\.[0-9][0-9]*\)'` + +cat >>confdefs.h <<_ACEOF +#define CITUS_MAJORVERSION "$CITUS_MAJORVERSION" +_ACEOF + + +# CITUS_VERSION definition + +cat >>confdefs.h <<_ACEOF +#define CITUS_VERSION "$PACKAGE_VERSION" +_ACEOF + + +# CITUS_VERSION_NUM definition +CITUS_VERSION_NUM="`echo "$PACKAGE_VERSION" | sed 's/[A-Za-z].*$//' | +tr '.' ' ' | +$AWK '{printf "%d%02d%02d", $1, $2, (NF >= 3) ? $3 : 0}'`" + +cat >>confdefs.h <<_ACEOF +#define CITUS_VERSION_NUM $CITUS_VERSION_NUM +_ACEOF + + +# CITUS_EXTENSIONVERSION definition +citus_extensionversion=$(grep "^default_version" src/backend/distributed/citus.control | cut -d\' -f2) + +cat >>confdefs.h <<_ACEOF +#define CITUS_EXTENSIONVERSION "$citus_extensionversion" +_ACEOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : @@ -2974,7 +3007,7 @@ POSTGRES_BUILDDIR="$POSTGRES_BUILDDIR" ac_config_files="$ac_config_files Makefile.global" -ac_config_headers="$ac_config_headers src/include/citus_config.h" +ac_config_headers="$ac_config_headers src/include/citus_config.h src/include/citus_version.h" cat >confcache <<\_ACEOF @@ -3483,7 +3516,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by Citus $as_me 5.0, which was +This file was extended by Citus $as_me 6.2devel, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -3545,7 +3578,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -Citus config.status 5.0 +Citus config.status 6.2devel configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -3668,6 +3701,7 @@ do case $ac_config_target in "Makefile.global") CONFIG_FILES="$CONFIG_FILES Makefile.global" ;; "src/include/citus_config.h") CONFIG_HEADERS="$CONFIG_HEADERS src/include/citus_config.h" ;; + "src/include/citus_version.h") CONFIG_HEADERS="$CONFIG_HEADERS src/include/citus_version.h" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac diff --git a/configure.in b/configure.in index 25bcbe666..fb261d08b 100644 --- a/configure.in +++ b/configure.in @@ -5,8 +5,25 @@ # everyone needing autoconf installed, the resulting files are checked # into the SCM. -AC_INIT([Citus], [5.0], [], [citus], []) -AC_COPYRIGHT([Copyright (c) 2012-2016, Citus Data, Inc.]) +AC_INIT([Citus], [6.2devel]) +AC_COPYRIGHT([Copyright (c) 2012-2017, Citus Data, Inc.]) + +# CITUS_MAJORVERSION definition +[CITUS_MAJORVERSION=`expr "$PACKAGE_VERSION" : '\([0-9][0-9]*\.[0-9][0-9]*\)'`] +AC_DEFINE_UNQUOTED(CITUS_MAJORVERSION, "$CITUS_MAJORVERSION", [Citus major version as a string]) + +# CITUS_VERSION definition +AC_DEFINE_UNQUOTED(CITUS_VERSION, "$PACKAGE_VERSION", [Citus version as a string]) + +# CITUS_VERSION_NUM definition +[CITUS_VERSION_NUM="`echo "$PACKAGE_VERSION" | sed 's/[A-Za-z].*$//' | +tr '.' ' ' | +$AWK '{printf "%d%02d%02d", $1, $2, (NF >= 3) ? $3 : 0}'`"] +AC_DEFINE_UNQUOTED(CITUS_VERSION_NUM, $CITUS_VERSION_NUM, [Citus version as a number]) + +# CITUS_EXTENSIONVERSION definition +citus_extensionversion=$(grep "^default_version" src/backend/distributed/citus.control | cut -d\' -f2) +AC_DEFINE_UNQUOTED([CITUS_EXTENSIONVERSION], "$citus_extensionversion", [so the shared-library knows its own version]) AC_PROG_SED @@ -122,7 +139,7 @@ AC_SUBST(POSTGRES_SRCDIR, "$POSTGRES_SRCDIR") AC_SUBST(POSTGRES_BUILDDIR, "$POSTGRES_BUILDDIR") AC_CONFIG_FILES([Makefile.global]) -AC_CONFIG_HEADERS([src/include/citus_config.h]) +AC_CONFIG_HEADERS([src/include/citus_config.h] [src/include/citus_version.h]) AH_TOP([ /* * citus_config.h.in is generated by autoconf/autoheader and diff --git a/src/backend/distributed/executor/multi_utility.c b/src/backend/distributed/executor/multi_utility.c index d70fd1930..2c40167db 100644 --- a/src/backend/distributed/executor/multi_utility.c +++ b/src/backend/distributed/executor/multi_utility.c @@ -28,6 +28,7 @@ #include "catalog/namespace.h" #include "catalog/pg_attribute.h" #include "catalog/pg_class.h" +#include "citus_version.h" #include "commands/defrem.h" #include "commands/tablecmds.h" #include "commands/prepare.h" @@ -120,6 +121,7 @@ static char * DeparseVacuumColumnNames(List *columnNameList); /* Local functions forward declarations for unsupported command checks */ +static void ErrorIfUnstableCreateOrAlterExtensionStmt(Node *parsetree); static void ErrorIfUnsupportedIndexStmt(IndexStmt *createIndexStatement); static void ErrorIfUnsupportedDropIndexStmt(DropStmt *dropIndexStatement); static void ErrorIfUnsupportedAlterTableStmt(AlterTableStmt *alterTableStatement); @@ -170,6 +172,7 @@ multi_ProcessUtility(Node *parsetree, Oid savedUserId = InvalidOid; int savedSecurityContext = 0; List *ddlJobs = NIL; + bool extensionStatement = false; if (IsA(parsetree, TransactionStmt)) { @@ -185,6 +188,53 @@ multi_ProcessUtility(Node *parsetree, return; } + if (IsA(parsetree, CreateExtensionStmt)) + { + CreateExtensionStmt *createExtensionStmt = (CreateExtensionStmt *) parsetree; + if (strcmp(createExtensionStmt->extname, "citus") == 0) + { + ErrorIfUnstableCreateOrAlterExtensionStmt(parsetree); + } + + extensionStatement = true; + } + + if (IsA(parsetree, AlterExtensionStmt)) + { + AlterExtensionStmt *alterExtensionStmt = (AlterExtensionStmt *) parsetree; + if (strcmp(alterExtensionStmt->extname, "citus") == 0) + { + ErrorIfUnstableCreateOrAlterExtensionStmt(parsetree); + } + + extensionStatement = true; + } + + if (IsA(parsetree, DropStmt)) + { + DropStmt *dropStatement = (DropStmt *) parsetree; + + if (dropStatement->removeType == OBJECT_EXTENSION) + { + extensionStatement = true; + } + } + + if (extensionStatement) + { + /* + * In CitusHasBeenLoaded check below, we compare binary Citus version, + * extension version and available version. If they are different, we + * force user to execute ALTER EXTENSION citus UPDATE. Therefore, if + * user executes ALTER EXTENSION or DROP EXTENSION query we should drop + * to the standart utility before CitusHasBeenLoaded check. + */ + standard_ProcessUtility(parsetree, queryString, context, + params, dest, completionTag); + + return; + } + if (!CitusHasBeenLoaded()) { /* @@ -1256,6 +1306,62 @@ DeparseVacuumColumnNames(List *columnNameList) } +/* + * ErrorIfUnstableCreateOrAlterExtensionStmt compares CITUS_EXTENSIONVERSION + * and version given CREATE/ALTER EXTENSION statement will create/update to. If + * they are not same in major or minor version numbers, this function errors + * out. It ignores the catalog version. + */ +static void +ErrorIfUnstableCreateOrAlterExtensionStmt(Node *parsetree) +{ + List *optionsList = NIL; + ListCell *optionsCell = NULL; + + if (IsA(parsetree, CreateExtensionStmt)) + { + CreateExtensionStmt *createExtensionStmt = (CreateExtensionStmt *) parsetree; + optionsList = createExtensionStmt->options; + } + else if (IsA(parsetree, AlterExtensionStmt)) + { + AlterExtensionStmt *alterExtensionStmt = (AlterExtensionStmt *) parsetree; + optionsList = alterExtensionStmt->options; + } + else + { + ereport(ERROR, (errmsg("unsupported node type, create or alter extension " + "is expected"))); + } + + foreach(optionsCell, optionsList) + { + DefElem *defElement = (DefElem *) lfirst(optionsCell); + + if (strcmp(defElement->defname, "new_version") == 0) + { + char *newVersion = strVal(defElement->arg); + + if (!CompareVersions(newVersion, CITUS_EXTENSIONVERSION)) + { + ereport(ERROR, (errmsg("requested version is not compatible with " + "loaded Citus binaries."))); + } + + return; + } + } + + /* + * new_version is not specified in ALTER EXTENSION statement, PostgreSQL will use + * default_version from citus.control file. We will flush availableMajorVersion to + * re-check the available version from citus.control file. + */ + availableMajorVersion = NULL; + ErrorIfNewMajorVersionAvailable(); +} + + /* * ErrorIfUnsupportedIndexStmt checks if the corresponding index statement is * supported for distributed tables and errors out if it is not. diff --git a/src/backend/distributed/shared_library_init.c b/src/backend/distributed/shared_library_init.c index 689296b08..de5ee793a 100644 --- a/src/backend/distributed/shared_library_init.c +++ b/src/backend/distributed/shared_library_init.c @@ -16,6 +16,7 @@ #include "fmgr.h" #include "miscadmin.h" +#include "citus_version.h" #include "commands/explain.h" #include "executor/executor.h" #include "distributed/citus_nodefuncs.h" @@ -48,6 +49,8 @@ /* marks shared object as one loadable by the postgres version compiled against */ PG_MODULE_MAGIC; +static char *CitusVersion; + void _PG_init(void); static void CreateRequiredDirectories(void); @@ -610,6 +613,16 @@ RegisterCitusConfigVariables(void) 0, NULL, NULL, NULL); + DefineCustomStringVariable( + "citus.version", + gettext_noop("Shows the running Citus version"), + NULL, + &CitusVersion, + CITUS_VERSION, + PGC_INTERNAL, + 0, + NULL, NULL, NULL); + /* warn about config items in the citus namespace that are not registered above */ EmitWarningsOnPlaceholders("citus"); } diff --git a/src/backend/distributed/utils/metadata_cache.c b/src/backend/distributed/utils/metadata_cache.c index 2939ade41..f8360556e 100644 --- a/src/backend/distributed/utils/metadata_cache.c +++ b/src/backend/distributed/utils/metadata_cache.c @@ -22,6 +22,7 @@ #include "catalog/pg_extension.h" #include "catalog/pg_namespace.h" #include "catalog/pg_type.h" +#include "citus_version.h" #include "commands/extension.h" #include "commands/trigger.h" #include "distributed/colocation_utils.h" @@ -35,6 +36,7 @@ #include "distributed/shardinterval_utils.h" #include "distributed/worker_manager.h" #include "distributed/worker_protocol.h" +#include "executor/executor.h" #include "parser/parse_func.h" #include "utils/builtins.h" #include "utils/catcache.h" @@ -98,6 +100,10 @@ static Oid distTransactionRelationId = InvalidOid; static Oid distTransactionGroupIndexId = InvalidOid; static Oid extraDataContainerFuncId = InvalidOid; +/* Citus installed extension version */ +char *availableMajorVersion = NULL; +static char *installedExtensionVersion = NULL; + /* Hash table for informations about each partition */ static HTAB *DistTableCacheHash = NULL; @@ -133,6 +139,9 @@ static bool HasUniformHashDistribution(ShardInterval **shardIntervalArray, int shardIntervalArrayLength); static bool HasUninitializedShardInterval(ShardInterval **sortedShardIntervalArray, int shardCount); +static void ErrorIfExtensionUpdateNeeded(void); +static char * AvailableMajorVersion(void); +static char * InstalledExtensionVersion(void); static void InitializeDistTableCache(void); static void InitializeWorkerNodeCache(void); static uint32 WorkerNodeHashCode(const void *key, Size keySize); @@ -927,7 +936,7 @@ bool CitusHasBeenLoaded(void) { /* recheck presence until citus has been loaded */ - if (!extensionLoaded) + if (!extensionLoaded || creating_extension) { bool extensionPresent = false; bool extensionScriptExecuted = true; @@ -964,13 +973,246 @@ CitusHasBeenLoaded(void) * present during early stages of upgrade operation. */ DistPartitionRelationId(); + + /* + * We also set installedExtensionVersion to NULL so that it will be re-read + * in case of extension update. + */ + installedExtensionVersion = NULL; } } + if (extensionLoaded) + { + ErrorIfNewMajorVersionAvailable(); + ErrorIfExtensionUpdateNeeded(); + } + return extensionLoaded; } +/* + * ErrorIfNewMajorVersionAvailable compares CITUS_EXTENSIONVERSION and currently + * available version from citus.control file. If they are not same in major or + * minor version numbers, this function errors out. It ignores the schema version. + */ +void +ErrorIfNewMajorVersionAvailable(void) +{ + char *availableVersion = AvailableMajorVersion(); + + if (!CompareVersions(availableVersion, CITUS_EXTENSIONVERSION)) + { + ereport(ERROR, (errmsg("server restart is needed because, loaded Citus binaries " + "does not match the available extension version"))); + } +} + + +/* + * ErrorIfExtensionUpdateNeeded compares CITUS_EXTENSIONVERSION and currently and + * catalog version from pg_extemsion catalog table. If they are not same in major or + * minor version numbers, this function errors out. It ignores the schema version. + */ +static void +ErrorIfExtensionUpdateNeeded(void) +{ + char *installedVersion = InstalledExtensionVersion(); + + if (!CompareVersions(installedVersion, CITUS_EXTENSIONVERSION)) + { + ereport(ERROR, (errmsg("\"ALTER EXTENSION citus UPDATE;\" is needed, because " + "loaded Citus binaries does not match the installed " + "extension version"))); + } +} + + +/* + * CompareVersions compares given two versions. If they are same in major and + * minor version numbers, this function returns true. It ignores the schema version. + */ +bool +CompareVersions(char *leftVersion, char *rightVersion) +{ + const char schemaVersionSeparator = '-'; + char *seperatorPosition = strchr(leftVersion, schemaVersionSeparator); + int comparisionLimit = 0; + + if (seperatorPosition != NULL) + { + comparisionLimit = seperatorPosition - leftVersion; + } + else + { + comparisionLimit = strlen(leftVersion); + } + + return strncmp(leftVersion, rightVersion, comparisionLimit) == 0; +} + + +/* + * AvailableMajorVersion returns the Citus version from citus.control file. It also + * saves the result, thus consecutive calls to CitusExtensionAvailableVersion will + * not read the citus.control file again. + */ +static char * +AvailableMajorVersion(void) +{ + ReturnSetInfo *extensionsResultSet = NULL; + TupleTableSlot *tupleTableSlot = NULL; + FunctionCallInfoData *fcinfo = NULL; + FmgrInfo *flinfo = NULL; + int argumentCount = 0; + EState *estate = NULL; + + bool hasTuple = false; + bool goForward = true; + bool doCopy = false; + + /* if we cached the result before, return it*/ + if (availableMajorVersion != NULL) + { + return availableMajorVersion; + } + + estate = CreateExecutorState(); + extensionsResultSet = makeNode(ReturnSetInfo); + extensionsResultSet->econtext = GetPerTupleExprContext(estate); + extensionsResultSet->allowedModes = SFRM_Materialize; + + fcinfo = palloc0(sizeof(FunctionCallInfoData)); + flinfo = palloc0(sizeof(FmgrInfo)); + + fmgr_info(F_PG_AVAILABLE_EXTENSIONS, flinfo); + InitFunctionCallInfoData(*fcinfo, flinfo, argumentCount, InvalidOid, NULL, + (Node *) extensionsResultSet); + + /* pg_available_extensions returns result set containing all available extensions */ + (*pg_available_extensions)(fcinfo); + + tupleTableSlot = MakeSingleTupleTableSlot(extensionsResultSet->setDesc); + hasTuple = tuplestore_gettupleslot(extensionsResultSet->setResult, goForward, doCopy, + tupleTableSlot); + while (hasTuple) + { + Datum extensionNameDatum = 0; + char *extensionName = NULL; + bool isNull = false; + + extensionNameDatum = slot_getattr(tupleTableSlot, 1, &isNull); + extensionName = NameStr(*DatumGetName(extensionNameDatum)); + if (strcmp(extensionName, "citus") == 0) + { + MemoryContext oldMemoryContext = NULL; + Datum citusVersionDatum = slot_getattr(tupleTableSlot, 2, &isNull); + + /* we will cache the result of citus version to prevent catalog access */ + if (CacheMemoryContext == NULL) + { + CreateCacheMemoryContext(); + } + oldMemoryContext = MemoryContextSwitchTo(CacheMemoryContext); + + availableMajorVersion = text_to_cstring(DatumGetTextPP(citusVersionDatum)); + + MemoryContextSwitchTo(oldMemoryContext); + + ExecClearTuple(tupleTableSlot); + ExecDropSingleTupleTableSlot(tupleTableSlot); + + return availableMajorVersion; + } + + ExecClearTuple(tupleTableSlot); + hasTuple = tuplestore_gettupleslot(extensionsResultSet->setResult, goForward, + doCopy, tupleTableSlot); + } + + ExecDropSingleTupleTableSlot(tupleTableSlot); + + ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("citus extension is not found"))); + + return NULL; +} + + +/* + * InstalledExtensionVersion returns the Citus version in PostgreSQL pg_extension table. + * It also saves the result, thus consecutive calls to CitusExtensionCatalogVersion + * will not read the catalog tables again. + */ +static char * +InstalledExtensionVersion(void) +{ + Relation relation = NULL; + SysScanDesc scandesc; + ScanKeyData entry[1]; + HeapTuple extensionTuple = NULL; + + /* if we cached the result before, return it*/ + if (installedExtensionVersion != NULL) + { + return installedExtensionVersion; + } + + relation = heap_open(ExtensionRelationId, AccessShareLock); + + ScanKeyInit(&entry[0], Anum_pg_extension_extname, BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum("citus")); + + scandesc = systable_beginscan(relation, ExtensionNameIndexId, true, + NULL, 1, entry); + + extensionTuple = systable_getnext(scandesc); + + /* We assume that there can be at most one matching tuple */ + if (HeapTupleIsValid(extensionTuple)) + { + MemoryContext oldMemoryContext = NULL; + int extensionIndex = Anum_pg_extension_extversion; + TupleDesc tupleDescriptor = RelationGetDescr(relation); + bool isNull = false; + + Datum extensionVersionDatum = heap_getattr(extensionTuple, extensionIndex, + tupleDescriptor, &isNull); + + if (isNull) + { + ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("citus extension version is null"))); + } + + /* we will cache the result of citus version to prevent catalog access */ + if (CacheMemoryContext == NULL) + { + CreateCacheMemoryContext(); + } + + oldMemoryContext = MemoryContextSwitchTo(CacheMemoryContext); + + installedExtensionVersion = text_to_cstring(DatumGetTextPP( + extensionVersionDatum)); + + MemoryContextSwitchTo(oldMemoryContext); + } + else + { + ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("citus extension is not loaded"))); + } + + systable_endscan(scandesc); + + heap_close(relation, AccessShareLock); + + return installedExtensionVersion; +} + + /* return oid of pg_dist_shard relation */ Oid DistShardRelationId(void) diff --git a/src/include/citus_config.h.in b/src/include/citus_config.h.in index 33da446e7..97ad673aa 100644 --- a/src/include/citus_config.h.in +++ b/src/include/citus_config.h.in @@ -10,6 +10,18 @@ */ +/* so the shared-library knows its own version */ +#undef CITUS_EXTENSIONVERSION + +/* Citus major version as a string */ +#undef CITUS_MAJORVERSION + +/* Citus version as a string */ +#undef CITUS_VERSION + +/* Citus version as a number */ +#undef CITUS_VERSION_NUM + /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT diff --git a/src/include/citus_version.h.in b/src/include/citus_version.h.in new file mode 100644 index 000000000..b576c29aa --- /dev/null +++ b/src/include/citus_version.h.in @@ -0,0 +1,13 @@ +/* This file is created manually */ + +/* so the shared-library knows its own version */ +#undef CITUS_EXTENSIONVERSION + +/* Citus major version as a string */ +#undef CITUS_MAJORVERSION + +/* Citus version as a string */ +#undef CITUS_VERSION + +/* Citus version as a number */ +#undef CITUS_VERSION_NUM diff --git a/src/include/distributed/metadata_cache.h b/src/include/distributed/metadata_cache.h index abd1861c0..36b9ccfc4 100644 --- a/src/include/distributed/metadata_cache.h +++ b/src/include/distributed/metadata_cache.h @@ -17,6 +17,7 @@ #include "distributed/worker_manager.h" #include "utils/hsearch.h" +extern char *availableMajorVersion; /* * Representation of a table's metadata that is frequently used for @@ -68,6 +69,8 @@ extern void CitusInvalidateRelcacheByRelid(Oid relationId); extern void CitusInvalidateRelcacheByShardId(int64 shardId); extern bool CitusHasBeenLoaded(void); +void ErrorIfNewMajorVersionAvailable(void); +bool CompareVersions(char *leftVersion, char *rightVersion); /* access WorkerNodeHash */ extern HTAB * GetWorkerNodeHash(void); diff --git a/src/test/regress/expected/multi_extension.out b/src/test/regress/expected/multi_extension.out index 8655907f8..9b2c85c93 100644 --- a/src/test/regress/expected/multi_extension.out +++ b/src/test/regress/expected/multi_extension.out @@ -24,59 +24,19 @@ WHERE pgd.refclassid = 'pg_extension'::regclass AND -- DROP EXTENSION pre-created by the regression suite DROP EXTENSION citus; \c --- Create extension in oldest version, test every upgrade step +-- Create extension in oldest version, this is expected to fail CREATE EXTENSION citus VERSION '5.0'; -ALTER EXTENSION citus UPDATE TO '5.0-1'; -ALTER EXTENSION citus UPDATE TO '5.0-2'; -ALTER EXTENSION citus UPDATE TO '5.1-1'; -ALTER EXTENSION citus UPDATE TO '5.1-2'; -ALTER EXTENSION citus UPDATE TO '5.1-3'; -ALTER EXTENSION citus UPDATE TO '5.1-4'; -ALTER EXTENSION citus UPDATE TO '5.1-5'; -ALTER EXTENSION citus UPDATE TO '5.1-6'; -ALTER EXTENSION citus UPDATE TO '5.1-7'; -ALTER EXTENSION citus UPDATE TO '5.1-8'; -ALTER EXTENSION citus UPDATE TO '5.2-1'; -ALTER EXTENSION citus UPDATE TO '5.2-2'; -ALTER EXTENSION citus UPDATE TO '5.2-3'; -ALTER EXTENSION citus UPDATE TO '5.2-4'; -ALTER EXTENSION citus UPDATE TO '6.0-1'; -ALTER EXTENSION citus UPDATE TO '6.0-2'; -ALTER EXTENSION citus UPDATE TO '6.0-3'; -ALTER EXTENSION citus UPDATE TO '6.0-4'; -ALTER EXTENSION citus UPDATE TO '6.0-5'; -ALTER EXTENSION citus UPDATE TO '6.0-6'; -ALTER EXTENSION citus UPDATE TO '6.0-7'; -ALTER EXTENSION citus UPDATE TO '6.0-8'; -ALTER EXTENSION citus UPDATE TO '6.0-9'; -ALTER EXTENSION citus UPDATE TO '6.0-10'; -ALTER EXTENSION citus UPDATE TO '6.0-11'; -ALTER EXTENSION citus UPDATE TO '6.0-12'; -ALTER EXTENSION citus UPDATE TO '6.0-13'; -ALTER EXTENSION citus UPDATE TO '6.0-14'; -ALTER EXTENSION citus UPDATE TO '6.0-15'; -ALTER EXTENSION citus UPDATE TO '6.0-16'; -ALTER EXTENSION citus UPDATE TO '6.0-17'; -ALTER EXTENSION citus UPDATE TO '6.0-18'; -ALTER EXTENSION citus UPDATE TO '6.1-1'; -ALTER EXTENSION citus UPDATE TO '6.1-2'; -ALTER EXTENSION citus UPDATE TO '6.1-3'; -ALTER EXTENSION citus UPDATE TO '6.1-4'; -ALTER EXTENSION citus UPDATE TO '6.1-5'; -ALTER EXTENSION citus UPDATE TO '6.1-6'; -ALTER EXTENSION citus UPDATE TO '6.1-7'; -ALTER EXTENSION citus UPDATE TO '6.1-8'; -ALTER EXTENSION citus UPDATE TO '6.1-9'; -ALTER EXTENSION citus UPDATE TO '6.1-10'; -ALTER EXTENSION citus UPDATE TO '6.1-11'; -ALTER EXTENSION citus UPDATE TO '6.1-12'; -ALTER EXTENSION citus UPDATE TO '6.1-13'; -ALTER EXTENSION citus UPDATE TO '6.1-14'; -ALTER EXTENSION citus UPDATE TO '6.1-15'; -ALTER EXTENSION citus UPDATE TO '6.1-16'; -ALTER EXTENSION citus UPDATE TO '6.1-17'; -ALTER EXTENSION citus UPDATE TO '6.2-1'; +ERROR: requested version is not compatible with loaded Citus binaries. +-- Create extension in newest major version, test every upgrade step +CREATE EXTENSION citus VERSION '6.2-1'; ALTER EXTENSION citus UPDATE TO '6.2-2'; +-- show running version +SHOW citus.version; + citus.version +--------------- + 6.2devel +(1 row) + -- ensure no objects were created outside pg_catalog SELECT COUNT(*) FROM pg_depend AS pgd, diff --git a/src/test/regress/sql/multi_extension.sql b/src/test/regress/sql/multi_extension.sql index d1a1ff559..1b4d13f97 100644 --- a/src/test/regress/sql/multi_extension.sql +++ b/src/test/regress/sql/multi_extension.sql @@ -24,60 +24,16 @@ WHERE pgd.refclassid = 'pg_extension'::regclass AND DROP EXTENSION citus; \c --- Create extension in oldest version, test every upgrade step +-- Create extension in oldest version, this is expected to fail CREATE EXTENSION citus VERSION '5.0'; -ALTER EXTENSION citus UPDATE TO '5.0-1'; -ALTER EXTENSION citus UPDATE TO '5.0-2'; -ALTER EXTENSION citus UPDATE TO '5.1-1'; -ALTER EXTENSION citus UPDATE TO '5.1-2'; -ALTER EXTENSION citus UPDATE TO '5.1-3'; -ALTER EXTENSION citus UPDATE TO '5.1-4'; -ALTER EXTENSION citus UPDATE TO '5.1-5'; -ALTER EXTENSION citus UPDATE TO '5.1-6'; -ALTER EXTENSION citus UPDATE TO '5.1-7'; -ALTER EXTENSION citus UPDATE TO '5.1-8'; -ALTER EXTENSION citus UPDATE TO '5.2-1'; -ALTER EXTENSION citus UPDATE TO '5.2-2'; -ALTER EXTENSION citus UPDATE TO '5.2-3'; -ALTER EXTENSION citus UPDATE TO '5.2-4'; -ALTER EXTENSION citus UPDATE TO '6.0-1'; -ALTER EXTENSION citus UPDATE TO '6.0-2'; -ALTER EXTENSION citus UPDATE TO '6.0-3'; -ALTER EXTENSION citus UPDATE TO '6.0-4'; -ALTER EXTENSION citus UPDATE TO '6.0-5'; -ALTER EXTENSION citus UPDATE TO '6.0-6'; -ALTER EXTENSION citus UPDATE TO '6.0-7'; -ALTER EXTENSION citus UPDATE TO '6.0-8'; -ALTER EXTENSION citus UPDATE TO '6.0-9'; -ALTER EXTENSION citus UPDATE TO '6.0-10'; -ALTER EXTENSION citus UPDATE TO '6.0-11'; -ALTER EXTENSION citus UPDATE TO '6.0-12'; -ALTER EXTENSION citus UPDATE TO '6.0-13'; -ALTER EXTENSION citus UPDATE TO '6.0-14'; -ALTER EXTENSION citus UPDATE TO '6.0-15'; -ALTER EXTENSION citus UPDATE TO '6.0-16'; -ALTER EXTENSION citus UPDATE TO '6.0-17'; -ALTER EXTENSION citus UPDATE TO '6.0-18'; -ALTER EXTENSION citus UPDATE TO '6.1-1'; -ALTER EXTENSION citus UPDATE TO '6.1-2'; -ALTER EXTENSION citus UPDATE TO '6.1-3'; -ALTER EXTENSION citus UPDATE TO '6.1-4'; -ALTER EXTENSION citus UPDATE TO '6.1-5'; -ALTER EXTENSION citus UPDATE TO '6.1-6'; -ALTER EXTENSION citus UPDATE TO '6.1-7'; -ALTER EXTENSION citus UPDATE TO '6.1-8'; -ALTER EXTENSION citus UPDATE TO '6.1-9'; -ALTER EXTENSION citus UPDATE TO '6.1-10'; -ALTER EXTENSION citus UPDATE TO '6.1-11'; -ALTER EXTENSION citus UPDATE TO '6.1-12'; -ALTER EXTENSION citus UPDATE TO '6.1-13'; -ALTER EXTENSION citus UPDATE TO '6.1-14'; -ALTER EXTENSION citus UPDATE TO '6.1-15'; -ALTER EXTENSION citus UPDATE TO '6.1-16'; -ALTER EXTENSION citus UPDATE TO '6.1-17'; -ALTER EXTENSION citus UPDATE TO '6.2-1'; + +-- Create extension in newest major version, test every upgrade step +CREATE EXTENSION citus VERSION '6.2-1'; ALTER EXTENSION citus UPDATE TO '6.2-2'; +-- show running version +SHOW citus.version; + -- ensure no objects were created outside pg_catalog SELECT COUNT(*) FROM pg_depend AS pgd,