timescaledb/test/sql/loader.sql
Matvey Arye da8cc797a4 Add support for multiple extension version in one pg instance
This PR adds the ability to have multiple different versions of the timescaledb
extension be used by different databases in the same PostgreSQL
instance (server).

This is accomplished by splitting this extension into two .so files.
1) timescaledb.so -- stuff under loader/. Really not a lot of code.
    This code MUST be backwards compatible in the future.
2) timescaledb-version.so (most of our code). Need
   not be backwards compatible.

Timescaledb.so becomes a small stub which is preloaded and whose main
reason for existing is to dynamically load the right
timescaledb-version.so when the time comes.

This change allows either of the above .so to be loaded in
shared_preload_libraries. But timescaledb.so allows for multiple
versions used on different databases in the same instance along
with smoother upgrades. Using timescaledb-version.so allows for
finer-grained control and lock-in and is appropriate in only a few
production environments.

This PR also adds version checking so that a clear failure message
will be displayed if the .so version does not match the SQL extension
version.

To support multi-version functionality we changed the way SQL update
scripts are generated. Previously, the system used a bunch of
intermediate upgrade scripts.  So with 3 versions, you would have an
update script of 1--2, 2--3.  But, this PR changes things so that we
produce direct "shortcut" update files: 1--3, 2--3.
This is done for 2 reasons:
 1) Each of the update files should point to
    $libdir/timescaledb-current_version. Since you cannot guarantee that
    Previous .so for each intermediate version has been installed.
 2) You don't want intermediate version updates installed without the
    .so. For example, if you have versions 1,2,3
    and you are installing version 3, you want the upgrade files 1--3,
    2--3 but not 1--2 because if you have 1--2
    then a user could do ALTER EXTENSION timescaledb UPDATE TO 2. But
    the .so for version 2 may not be installed.

In order to test this functionality, we add a mock extension version .so
that we can test extension loading inside the regression framework.
2018-01-05 12:15:54 -05:00

168 lines
3.6 KiB
SQL

\c single :ROLE_SUPERUSER
DROP EXTENSION timescaledb;
--no extension
\dx
SELECT 1;
CREATE EXTENSION timescaledb VERSION 'mock-1';
--same backend as create extension;
SELECT 1;
\dx
--start new backend;
\c single :ROLE_DEFAULT_PERM_USER
SELECT 1;
SELECT 1;
--test fn call after load
SELECT mock_function();
\dx
\c single :ROLE_DEFAULT_PERM_USER
--test fn call as first command
SELECT mock_function();
--use guc to prevent loading
\c single :ROLE_SUPERUSER
SET timescaledb.disable_load = 'on';
SELECT 1;
SELECT 1;
SET timescaledb.disable_load = 'off';
SELECT 1;
\set ON_ERROR_STOP 0
SET timescaledb.disable_load = 'not bool';
\set ON_ERROR_STOP 1
\set ON_ERROR_STOP 0
--cannot update extension after .so of previous version already loaded
ALTER EXTENSION timescaledb UPDATE TO 'mock-2';
\set ON_ERROR_STOP 1
\c single_2 :ROLE_SUPERUSER
\dx
CREATE EXTENSION timescaledb VERSION 'mock-1';
\dx
--start a new backend to update
\c single_2 :ROLE_SUPERUSER
ALTER EXTENSION timescaledb UPDATE TO 'mock-2';
SELECT 1;
\dx
--drop extension
DROP EXTENSION timescaledb;
SELECT 1;
\dx
\c single_2 :ROLE_SUPERUSER
CREATE EXTENSION timescaledb VERSION 'mock-2';
SELECT 1;
\dx
--single still has old version
\c single :ROLE_SUPERUSER
SELECT 1;
\dx
--try a broken upgrade
\c single_2 :ROLE_SUPERUSER
\dx
\set ON_ERROR_STOP 0
ALTER EXTENSION timescaledb UPDATE TO 'mock-3';
\set ON_ERROR_STOP 1
--should still be on mock-2
SELECT 1;
\dx
--drop extension
DROP EXTENSION timescaledb;
SELECT 1;
\dx
--create extension anew, only upgrade was broken
\c single_2 :ROLE_SUPERUSER
CREATE EXTENSION timescaledb VERSION 'mock-3';
SELECT 1;
\dx
DROP EXTENSION timescaledb;
SELECT 1;
--mismatched version errors
\c single_2 :ROLE_SUPERUSER
\set ON_ERROR_STOP 0
--mock-4 has mismatched versions, so the .so load should throw an error
CREATE EXTENSION timescaledb VERSION 'mock-4';
\set ON_ERROR_STOP 1
--mock-4 not installed.
\dx
\set ON_ERROR_STOP 0
--should not allow since the errored-out mock-4 above already poisoned the well.
CREATE EXTENSION timescaledb VERSION 'mock-5';
\set ON_ERROR_STOP 1
\c single_2 :ROLE_SUPERUSER
--broken version and drop
CREATE EXTENSION timescaledb VERSION 'mock-broken';
\set ON_ERROR_STOP 0
--intentional broken version
\dx
SELECT 1;
SELECT 1;
--cannot drop extension; already loaded broken version
DROP EXTENSION timescaledb;
\set ON_ERROR_STOP 1
\c single_2 :ROLE_SUPERUSER
--can drop extension now. Since drop first command.
DROP EXTENSION timescaledb;
\dx
--broken version and update to fixed
\c single_2 :ROLE_SUPERUSER
CREATE EXTENSION timescaledb VERSION 'mock-broken';
\set ON_ERROR_STOP 0
--intentional broken version
SELECT 1;
--cannot update extension; already loaded bad version
ALTER EXTENSION timescaledb UPDATE TO 'mock-5';
\set ON_ERROR_STOP 1
\c single_2 :ROLE_SUPERUSER
--can update extension now.
ALTER EXTENSION timescaledb UPDATE TO 'mock-5';
SELECT 1;
SELECT mock_function();
\c single_2 :ROLE_SUPERUSER
ALTER EXTENSION timescaledb UPDATE TO 'mock-6';
\set ON_ERROR_STOP 0
--The mock-5->mock_6 upgrade is intentionally broken.
--The mock_function was never changed to point to mock-6 in the update script.
--Thus mock_function is defined incorrectly to point to the mock-5.so
--This should be an error.
SELECT mock_function();
\set ON_ERROR_STOP 1
\dx
--TEST: create extension when old .so already loaded
\c single :ROLE_SUPERUSER
--force load of extension with (\dx)
\dx
DROP EXTENSION timescaledb;
\dx
\set ON_ERROR_STOP 0
CREATE EXTENSION timescaledb VERSION 'mock-2';
\set ON_ERROR_STOP 1
\dx
--can create in a new session.
\c single :ROLE_SUPERUSER
CREATE EXTENSION timescaledb VERSION 'mock-2';
\dx