mirror of https://github.com/citusdata/citus.git
Merge pull request #1277 from citusdata/error_out_incomplete_installation
Error out if binary citus version does not match installed extension cr: @jasonmp85pull/1314/head
commit
8c5d0f686b
4
Makefile
4
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_version.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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=''
|
||||
|
||||
|
@ -600,6 +600,7 @@ vpath_build
|
|||
PATH
|
||||
PG_CONFIG
|
||||
FLEX
|
||||
AWK
|
||||
SED
|
||||
target_alias
|
||||
host_alias
|
||||
|
@ -1194,7 +1195,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 +1256,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 +1344,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 +1401,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 +1751,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
|||
|
||||
|
||||
|
||||
# we'll need sed and awk for some of the version commands
|
||||
{ $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 :
|
||||
|
@ -1819,6 +1821,82 @@ $as_echo "$ac_cv_path_SED" >&6; }
|
|||
SED="$ac_cv_path_SED"
|
||||
rm -f conftest.sed
|
||||
|
||||
for ac_prog in gawk mawk nawk awk
|
||||
do
|
||||
# Extract the first word of "$ac_prog", so it can be a program name with args.
|
||||
set dummy $ac_prog; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if ${ac_cv_prog_AWK+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
if test -n "$AWK"; then
|
||||
ac_cv_prog_AWK="$AWK" # Let the user override the test.
|
||||
else
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_AWK="$ac_prog"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS=$as_save_IFS
|
||||
|
||||
fi
|
||||
fi
|
||||
AWK=$ac_cv_prog_AWK
|
||||
if test -n "$AWK"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
|
||||
$as_echo "$AWK" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
test -n "$AWK" && break
|
||||
done
|
||||
|
||||
|
||||
# CITUS_VERSION definition
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define CITUS_VERSION "$PACKAGE_VERSION"
|
||||
_ACEOF
|
||||
|
||||
|
||||
# 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_NUM definition
|
||||
# awk -F is a regex on some platforms, and not on others, so make "." a tab
|
||||
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' $srcdir/src/backend/distributed/citus.control | cut -d\' -f2`"
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define CITUS_EXTENSIONVERSION "$CITUS_EXTENSIONVERSION"
|
||||
_ACEOF
|
||||
|
||||
|
||||
# Re-check for flex. That allows to compile citus against a postgres
|
||||
# which was built without flex available (possible because generated
|
||||
|
@ -2974,7 +3052,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 +3561,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 +3623,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\\"
|
||||
|
||||
|
@ -3555,6 +3633,7 @@ gives unlimited permission to copy, distribute and modify it."
|
|||
|
||||
ac_pwd='$ac_pwd'
|
||||
srcdir='$srcdir'
|
||||
AWK='$AWK'
|
||||
test -n "\$AWK" || AWK=awk
|
||||
_ACEOF
|
||||
|
||||
|
@ -3668,6 +3747,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
|
||||
|
|
26
configure.in
26
configure.in
|
@ -5,10 +5,30 @@
|
|||
# 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.])
|
||||
|
||||
# we'll need sed and awk for some of the version commands
|
||||
AC_PROG_SED
|
||||
AC_PROG_AWK
|
||||
|
||||
# CITUS_VERSION definition
|
||||
AC_DEFINE_UNQUOTED(CITUS_VERSION, "$PACKAGE_VERSION", [Citus version as a string])
|
||||
|
||||
# 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_NUM definition
|
||||
# awk -F is a regex on some platforms, and not on others, so make "." a tab
|
||||
[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' $srcdir/src/backend/distributed/citus.control | cut -d\' -f2`"]
|
||||
AC_DEFINE_UNQUOTED([CITUS_EXTENSIONVERSION], "$CITUS_EXTENSIONVERSION", [Extension version expected by this Citus build])
|
||||
|
||||
# Re-check for flex. That allows to compile citus against a postgres
|
||||
# which was built without flex available (possible because generated
|
||||
|
@ -122,7 +142,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
|
||||
|
|
|
@ -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"
|
||||
|
@ -82,7 +83,6 @@
|
|||
|
||||
bool EnableDDLPropagation = true; /* ddl propagation is enabled */
|
||||
|
||||
|
||||
/*
|
||||
* This struct defines the state for the callback for drop statements.
|
||||
* It is copied as it is from commands/tablecmds.c in Postgres source.
|
||||
|
@ -95,6 +95,10 @@ struct DropRelationCallbackState
|
|||
};
|
||||
|
||||
|
||||
/* Local functions forward declarations for deciding when to perform processing/checks */
|
||||
static bool SkipCitusProcessingForUtility(Node *parsetree);
|
||||
static bool IsCitusExtensionStmt(Node *parsetree);
|
||||
|
||||
/* Local functions forward declarations for Transmit statement */
|
||||
static bool IsTransmitStmt(Node *parsetree);
|
||||
static void VerifyTransmitStmt(CopyStmt *copyStatement);
|
||||
|
@ -120,6 +124,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);
|
||||
|
@ -130,6 +135,7 @@ static bool OptionsSpecifyOwnedBy(List *optionList, Oid *ownedByTableId);
|
|||
static void ErrorIfDistributedRenameStmt(RenameStmt *renameStatement);
|
||||
|
||||
/* Local functions forward declarations for helper functions */
|
||||
static char * ExtractNewExtensionVersion(Node *parsetree);
|
||||
static void CreateLocalTable(RangeVar *relation, char *nodeName, int32 nodePort);
|
||||
static bool IsAlterTableRenameStmt(RenameStmt *renameStatement);
|
||||
static void ExecuteDistributedDDLJob(DDLJob *ddlJob);
|
||||
|
@ -170,18 +176,20 @@ multi_ProcessUtility(Node *parsetree,
|
|||
Oid savedUserId = InvalidOid;
|
||||
int savedSecurityContext = 0;
|
||||
List *ddlJobs = NIL;
|
||||
bool skipCitusProcessing = SkipCitusProcessingForUtility(parsetree);
|
||||
|
||||
if (IsA(parsetree, TransactionStmt))
|
||||
if (skipCitusProcessing)
|
||||
{
|
||||
/*
|
||||
* Transaction statements (e.g. ABORT, COMMIT) can be run in aborted
|
||||
* transactions in which case a lot of checks cannot be done safely in
|
||||
* that state. Since we never need to intercept transaction statements,
|
||||
* skip our checks and immediately fall into standard_ProcessUtility.
|
||||
*/
|
||||
bool checkExtensionVersion = IsCitusExtensionStmt(parsetree);
|
||||
|
||||
standard_ProcessUtility(parsetree, queryString, context,
|
||||
params, dest, completionTag);
|
||||
|
||||
if (EnableVersionChecks && checkExtensionVersion)
|
||||
{
|
||||
ErrorIfUnstableCreateOrAlterExtensionStmt(parsetree);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -401,6 +409,86 @@ multi_ProcessUtility(Node *parsetree,
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* SkipCitusProcessingForUtility simply returns whether a given utility should
|
||||
* bypass Citus processing and checks and be handled exclusively by standard
|
||||
* PostgreSQL utility processing. At present, CREATE/ALTER/DROP EXTENSION,
|
||||
* ABORT, COMMIT, ROLLBACK, and SET (GUC) statements are exempt from Citus.
|
||||
*/
|
||||
static bool
|
||||
SkipCitusProcessingForUtility(Node *parsetree)
|
||||
{
|
||||
switch (parsetree->type)
|
||||
{
|
||||
/*
|
||||
* In the CitusHasBeenLoaded check, we compare versions of loaded code,
|
||||
* the installed extension, and available extension. If they differ, we
|
||||
* force user to execute ALTER EXTENSION citus UPDATE. To allow this,
|
||||
* CREATE/DROP/ALTER extension must be omitted from Citus processing.
|
||||
*/
|
||||
case T_DropStmt:
|
||||
{
|
||||
DropStmt *dropStatement = (DropStmt *) parsetree;
|
||||
|
||||
if (dropStatement->removeType != OBJECT_EXTENSION)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* no break, fall through */
|
||||
|
||||
case T_CreateExtensionStmt:
|
||||
case T_AlterExtensionStmt:
|
||||
|
||||
/*
|
||||
* Transaction statements (e.g. ABORT, COMMIT) can be run in aborted
|
||||
* transactions in which case a lot of checks cannot be done safely in
|
||||
* that state. Since we never need to intercept transaction statements,
|
||||
* skip our checks and immediately fall into standard_ProcessUtility.
|
||||
*/
|
||||
case T_TransactionStmt:
|
||||
|
||||
/*
|
||||
* Skip processing of variable set statements, to allow changing the
|
||||
* enable_version_checks GUC during testing.
|
||||
*/
|
||||
case T_VariableSetStmt:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* IsCitusExtensionStmt returns whether a given utility is a CREATE or ALTER
|
||||
* EXTENSION statement which references the citus extension. This function
|
||||
* returns false for all other inputs.
|
||||
*/
|
||||
static bool
|
||||
IsCitusExtensionStmt(Node *parsetree)
|
||||
{
|
||||
char *extensionName = "";
|
||||
|
||||
if (IsA(parsetree, CreateExtensionStmt))
|
||||
{
|
||||
extensionName = ((CreateExtensionStmt *) parsetree)->extname;
|
||||
}
|
||||
else if (IsA(parsetree, AlterExtensionStmt))
|
||||
{
|
||||
extensionName = ((AlterExtensionStmt *) parsetree)->extname;
|
||||
}
|
||||
|
||||
return (strcmp(extensionName, "citus") == 0);
|
||||
}
|
||||
|
||||
|
||||
/* Is the passed in statement a transmit statement? */
|
||||
static bool
|
||||
IsTransmitStmt(Node *parsetree)
|
||||
|
@ -1256,6 +1344,83 @@ 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 schema version.
|
||||
*/
|
||||
static void
|
||||
ErrorIfUnstableCreateOrAlterExtensionStmt(Node *parsetree)
|
||||
{
|
||||
char *newExtensionVersion = ExtractNewExtensionVersion(parsetree);
|
||||
|
||||
if (newExtensionVersion != NULL)
|
||||
{
|
||||
/* explicit version provided in CREATE or ALTER EXTENSION UPDATE; verify */
|
||||
if (!MajorVersionsCompatible(newExtensionVersion, CITUS_EXTENSIONVERSION))
|
||||
{
|
||||
ereport(ERROR, (errmsg("specified version incompatible with loaded "
|
||||
"Citus library"),
|
||||
errdetail("Loaded library requires %s, but %s was specified.",
|
||||
CITUS_MAJORVERSION, newExtensionVersion),
|
||||
errhint("If a newer library is present, restart the database "
|
||||
"and try the command again.")));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* No version was specified, so PostgreSQL will use the default_version
|
||||
* from the citus.control file. In case a new default is available, we
|
||||
* will force a compatibility check of the latest available version.
|
||||
*/
|
||||
availableExtensionVersion = NULL;
|
||||
ErrorIfAvailableVersionMismatch();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ExtractNewExtensionVersion returns the new extension version specified by
|
||||
* a CREATE or ALTER EXTENSION statement. Other inputs are not permitted. This
|
||||
* function returns NULL for statements with no explicit version specified.
|
||||
*/
|
||||
static char *
|
||||
ExtractNewExtensionVersion(Node *parsetree)
|
||||
{
|
||||
char *newVersion = NULL;
|
||||
List *optionsList = NIL;
|
||||
ListCell *optionsCell = NULL;
|
||||
|
||||
if (IsA(parsetree, CreateExtensionStmt))
|
||||
{
|
||||
optionsList = ((CreateExtensionStmt *) parsetree)->options;
|
||||
}
|
||||
else if (IsA(parsetree, AlterExtensionStmt))
|
||||
{
|
||||
optionsList = ((AlterExtensionStmt *) parsetree)->options;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* input must be one of the two above types */
|
||||
Assert(false);
|
||||
}
|
||||
|
||||
foreach(optionsCell, optionsList)
|
||||
{
|
||||
DefElem *defElement = (DefElem *) lfirst(optionsCell);
|
||||
if (strncmp(defElement->defname, "new_version", NAMEDATALEN) == 0)
|
||||
{
|
||||
newVersion = strVal(defElement->arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return newVersion;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ErrorIfUnsupportedIndexStmt checks if the corresponding index statement is
|
||||
* supported for distributed tables and errors out if it is not.
|
||||
|
|
|
@ -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 = CITUS_VERSION;
|
||||
|
||||
void _PG_init(void);
|
||||
|
||||
static void CreateRequiredDirectories(void);
|
||||
|
@ -610,6 +613,26 @@ RegisterCitusConfigVariables(void)
|
|||
0,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
DefineCustomStringVariable(
|
||||
"citus.version",
|
||||
gettext_noop("Shows the Citus library version"),
|
||||
NULL,
|
||||
&CitusVersion,
|
||||
CITUS_VERSION,
|
||||
PGC_INTERNAL,
|
||||
0,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
DefineCustomBoolVariable(
|
||||
"citus.enable_version_checks",
|
||||
gettext_noop("Enables version checks during CREATE/ALTER EXTENSION commands"),
|
||||
NULL,
|
||||
&EnableVersionChecks,
|
||||
true,
|
||||
PGC_USERSET,
|
||||
GUC_NO_SHOW_ALL,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
/* warn about config items in the citus namespace that are not registered above */
|
||||
EmitWarningsOnPlaceholders("citus");
|
||||
}
|
||||
|
|
|
@ -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,12 @@ static Oid distTransactionRelationId = InvalidOid;
|
|||
static Oid distTransactionGroupIndexId = InvalidOid;
|
||||
static Oid extraDataContainerFuncId = InvalidOid;
|
||||
|
||||
/* Citus extension version variables */
|
||||
bool EnableVersionChecks = true; /* version checks are enabled */
|
||||
|
||||
char *availableExtensionVersion = NULL;
|
||||
static char *installedExtensionVersion = NULL;
|
||||
|
||||
/* Hash table for informations about each partition */
|
||||
static HTAB *DistTableCacheHash = NULL;
|
||||
|
||||
|
@ -133,6 +141,9 @@ static bool HasUniformHashDistribution(ShardInterval **shardIntervalArray,
|
|||
int shardIntervalArrayLength);
|
||||
static bool HasUninitializedShardInterval(ShardInterval **sortedShardIntervalArray,
|
||||
int shardCount);
|
||||
static void ErrorIfInstalledVersionMismatch(void);
|
||||
static char * AvailableExtensionVersion(void);
|
||||
static char * InstalledExtensionVersion(void);
|
||||
static void InitializeDistTableCache(void);
|
||||
static void InitializeWorkerNodeCache(void);
|
||||
static uint32 WorkerNodeHashCode(const void *key, Size keySize);
|
||||
|
@ -927,7 +938,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 +975,286 @@ 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)
|
||||
{
|
||||
ErrorIfAvailableVersionMismatch();
|
||||
ErrorIfInstalledVersionMismatch();
|
||||
}
|
||||
|
||||
return extensionLoaded;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ErrorIfAvailableExtensionVersionMismatch 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
|
||||
ErrorIfAvailableVersionMismatch(void)
|
||||
{
|
||||
char *availableVersion = NULL;
|
||||
|
||||
if (!EnableVersionChecks)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
availableVersion = AvailableExtensionVersion();
|
||||
if (!MajorVersionsCompatible(availableVersion, CITUS_EXTENSIONVERSION))
|
||||
{
|
||||
ereport(ERROR, (errmsg("loaded Citus library version differs from latest "
|
||||
"available extension version"),
|
||||
errdetail("Loaded library requires %s, but the latest control "
|
||||
"file specifies %s.", CITUS_MAJORVERSION,
|
||||
availableVersion),
|
||||
errhint("Restart the database to load the latest Citus "
|
||||
"library.")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ErrorIfInstalledVersionMismatch 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
|
||||
ErrorIfInstalledVersionMismatch(void)
|
||||
{
|
||||
char *installedVersion = NULL;
|
||||
|
||||
if (!EnableVersionChecks)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
installedVersion = InstalledExtensionVersion();
|
||||
if (!MajorVersionsCompatible(installedVersion, CITUS_EXTENSIONVERSION))
|
||||
{
|
||||
ereport(ERROR, (errmsg("loaded Citus library version differs from installed "
|
||||
"extension version"),
|
||||
errdetail("Loaded library requires %s, but the installed "
|
||||
"extension version is %s.", CITUS_MAJORVERSION,
|
||||
installedVersion),
|
||||
errhint("Run ALTER EXTENSION citus UPDATE and try again.")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* MajorVersionsCompatible compares given two versions. If they are same in major
|
||||
* and minor version numbers, this function returns true. It ignores the schema
|
||||
* version.
|
||||
*/
|
||||
bool
|
||||
MajorVersionsCompatible(char *leftVersion, char *rightVersion)
|
||||
{
|
||||
const char schemaVersionSeparator = '-';
|
||||
|
||||
char *leftSeperatorPosition = strchr(leftVersion, schemaVersionSeparator);
|
||||
char *rightSeperatorPosition = strchr(rightVersion, schemaVersionSeparator);
|
||||
int leftComparisionLimit = 0;
|
||||
int rightComparisionLimit = 0;
|
||||
|
||||
if (leftSeperatorPosition != NULL)
|
||||
{
|
||||
leftComparisionLimit = leftSeperatorPosition - leftVersion;
|
||||
}
|
||||
else
|
||||
{
|
||||
leftComparisionLimit = strlen(leftVersion);
|
||||
}
|
||||
|
||||
if (rightSeperatorPosition != NULL)
|
||||
{
|
||||
rightComparisionLimit = rightSeperatorPosition - rightVersion;
|
||||
}
|
||||
else
|
||||
{
|
||||
rightComparisionLimit = strlen(leftVersion);
|
||||
}
|
||||
|
||||
/* we can error out early if hypens are not in the same position */
|
||||
if (leftComparisionLimit != rightComparisionLimit)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return strncmp(leftVersion, rightVersion, leftComparisionLimit) == 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AvailableExtensionVersion 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 *
|
||||
AvailableExtensionVersion(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 (availableExtensionVersion != NULL)
|
||||
{
|
||||
return availableExtensionVersion;
|
||||
}
|
||||
|
||||
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 availableVersion = slot_getattr(tupleTableSlot, 2, &isNull);
|
||||
|
||||
/* we will cache the result of citus version to prevent catalog access */
|
||||
if (CacheMemoryContext == NULL)
|
||||
{
|
||||
CreateCacheMemoryContext();
|
||||
}
|
||||
oldMemoryContext = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
availableExtensionVersion = text_to_cstring(DatumGetTextPP(availableVersion));
|
||||
|
||||
MemoryContextSwitchTo(oldMemoryContext);
|
||||
|
||||
ExecClearTuple(tupleTableSlot);
|
||||
ExecDropSingleTupleTableSlot(tupleTableSlot);
|
||||
|
||||
return availableExtensionVersion;
|
||||
}
|
||||
|
||||
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 installedVersion = 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(installedVersion));
|
||||
|
||||
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)
|
||||
|
|
|
@ -2,3 +2,5 @@
|
|||
/stamp-ext-h
|
||||
/citus_config.h
|
||||
/citus_config.h.in~
|
||||
/citus_version.h
|
||||
/citus_version.h.in~
|
||||
|
|
|
@ -10,6 +10,18 @@
|
|||
*/
|
||||
|
||||
|
||||
/* Extension version expected by this Citus build */
|
||||
#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
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/* This file is created manually */
|
||||
|
||||
/* Extension version expected by this Citus build */
|
||||
#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
|
|
@ -17,6 +17,8 @@
|
|||
#include "distributed/worker_manager.h"
|
||||
#include "utils/hsearch.h"
|
||||
|
||||
extern bool EnableVersionChecks;
|
||||
extern char *availableExtensionVersion;
|
||||
|
||||
/*
|
||||
* Representation of a table's metadata that is frequently used for
|
||||
|
@ -68,6 +70,8 @@ extern void CitusInvalidateRelcacheByRelid(Oid relationId);
|
|||
extern void CitusInvalidateRelcacheByShardId(int64 shardId);
|
||||
|
||||
extern bool CitusHasBeenLoaded(void);
|
||||
void ErrorIfAvailableVersionMismatch(void);
|
||||
bool MajorVersionsCompatible(char *leftVersion, char *rightVersion);
|
||||
|
||||
/* access WorkerNodeHash */
|
||||
extern HTAB * GetWorkerNodeHash(void);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "tcop/utility.h"
|
||||
|
||||
extern bool EnableDDLPropagation;
|
||||
extern bool EnableVersionChecks;
|
||||
|
||||
/*
|
||||
* A DDLJob encapsulates the remote tasks and commands needed to process all or
|
||||
|
|
|
@ -24,7 +24,8 @@ 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
|
||||
SET citus.enable_version_checks TO 'false';
|
||||
-- Create extension in oldest version
|
||||
CREATE EXTENSION citus VERSION '5.0';
|
||||
ALTER EXTENSION citus UPDATE TO '5.0-1';
|
||||
ALTER EXTENSION citus UPDATE TO '5.0-2';
|
||||
|
@ -77,6 +78,13 @@ ALTER EXTENSION citus UPDATE TO '6.1-16';
|
|||
ALTER EXTENSION citus UPDATE TO '6.1-17';
|
||||
ALTER EXTENSION citus UPDATE TO '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,
|
||||
|
@ -91,7 +99,13 @@ WHERE pgd.refclassid = 'pg_extension'::regclass AND
|
|||
0
|
||||
(1 row)
|
||||
|
||||
-- drop extension an re-create in newest version
|
||||
-- see incompatible version errors out
|
||||
RESET citus.enable_version_checks;
|
||||
DROP EXTENSION citus;
|
||||
CREATE EXTENSION citus VERSION '5.0';
|
||||
ERROR: specified version incompatible with loaded Citus library
|
||||
DETAIL: Loaded library requires 6.2, but 5.0 was specified.
|
||||
HINT: If a newer library is present, restart the database and try the command again.
|
||||
-- re-create in newest version
|
||||
\c
|
||||
CREATE EXTENSION citus;
|
||||
|
|
|
@ -24,7 +24,9 @@ WHERE pgd.refclassid = 'pg_extension'::regclass AND
|
|||
DROP EXTENSION citus;
|
||||
\c
|
||||
|
||||
-- Create extension in oldest version, test every upgrade step
|
||||
SET citus.enable_version_checks TO 'false';
|
||||
|
||||
-- Create extension in oldest version
|
||||
CREATE EXTENSION citus VERSION '5.0';
|
||||
ALTER EXTENSION citus UPDATE TO '5.0-1';
|
||||
ALTER EXTENSION citus UPDATE TO '5.0-2';
|
||||
|
@ -78,6 +80,9 @@ ALTER EXTENSION citus UPDATE TO '6.1-17';
|
|||
ALTER EXTENSION citus UPDATE TO '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,
|
||||
|
@ -88,7 +93,11 @@ WHERE pgd.refclassid = 'pg_extension'::regclass AND
|
|||
pge.extname = 'citus' AND
|
||||
pgio.schema NOT IN ('pg_catalog', 'citus');
|
||||
|
||||
-- drop extension an re-create in newest version
|
||||
-- see incompatible version errors out
|
||||
RESET citus.enable_version_checks;
|
||||
DROP EXTENSION citus;
|
||||
CREATE EXTENSION citus VERSION '5.0';
|
||||
|
||||
-- re-create in newest version
|
||||
\c
|
||||
CREATE EXTENSION citus;
|
||||
|
|
Loading…
Reference in New Issue