From bffadbcc8140ea4c31ef45a3bca317b3f1429d2a Mon Sep 17 00:00:00 2001 From: yevs Date: Mon, 30 Oct 2023 10:39:13 +0200 Subject: [PATCH] Add new extensions/plugins --- config.yaml | 92 +++++++++++++++++++++ src/charm.py | 4 + src/config.py | 23 ++++++ tests/integration/test_plugins.py | 129 ++++++++++++++++++------------ 4 files changed, 198 insertions(+), 50 deletions(-) diff --git a/config.yaml b/config.yaml index daa72aa7fb..8e05fec54c 100644 --- a/config.yaml +++ b/config.yaml @@ -123,6 +123,98 @@ options: default: false type: boolean description: Enable unaccent extension. + plugin_bloom_enable: + default: false + type: boolean + description: Enable bloom extension. + plugin_btree_gin_enable: + default: false + type: boolean + description: Enable btree_gin extension. + plugin_btree_gist_enable: + default: false + type: boolean + description: Enable btree_gist extension. + plugin_cube_enable: + default: false + type: boolean + description: Enable cube extension. + plugin_dict_int_enable: + default: false + type: boolean + description: Enable dict_int extension. + plugin_dict_xsyn_enable: + default: false + type: boolean + description: Enable dict_xsyn extension. + plugin_earthdistance_enable: + default: false + type: boolean + description: Enable earthdistance extension. + plugin_fuzzystrmatch_enable: + default: false + type: boolean + description: Enable fuzzystrmatch extension. + plugin_intarray_enable: + default: false + type: boolean + description: Enable intarray extension. + plugin_isn_enable: + default: false + type: boolean + description: Enable isn extension. + plugin_lo_enable: + default: false + type: boolean + description: Enable lo extension. + plugin_ltree_enable: + default: false + type: boolean + description: Enable ltree extension. + plugin_old_snapshot_enable: + default: false + type: boolean + description: Enable old_snapshot extension. + plugin_pg_freespacemap_enable: + default: false + type: boolean + description: Enable pg_freespacemap extension. + plugin_pgrowlocks_enable: + default: false + type: boolean + description: Enable pgrowlocks extension. + plugin_pgstattuple_enable: + default: false + type: boolean + description: Enable pgstattuple extension. + plugin_pg_visibility_enable: + default: false + type: boolean + description: Enable pg_visibility extension. + plugin_seg_enable: + default: false + type: boolean + description: Enable seg extension. + plugin_tablefunc_enable: + default: false + type: boolean + description: Enable tablefunc extension. + plugin_tcn_enable: + default: false + type: boolean + description: Enable tcn extension. + plugin_tsm_system_rows_enable: + default: false + type: boolean + description: Enable tsm_system_rows extension. + plugin_tsm_system_time_enable: + default: false + type: boolean + description: Enable tsm_system_time extension. + plugin_uuid_ossp_enable: + default: false + type: boolean + description: Enable uuid_ossp extension. profile: description: | Profile representing the scope of deployment, and used to tune resource allocation. diff --git a/src/charm.py b/src/charm.py index 1a17f40824..7c57423b24 100755 --- a/src/charm.py +++ b/src/charm.py @@ -552,10 +552,14 @@ def enable_disable_extensions(self, database: str = None) -> None: database: optional database where to enable/disable the extension. """ original_status = self.unit.status + plugins_exception = {"uuid_ossp": '"uuid-ossp"'} for plugin in self.config.plugin_keys(): enable = self.config[plugin] + # Enable or disable the plugin/extension. extension = "_".join(plugin.split("_")[1:-1]) + if extension in plugins_exception: + extension = plugins_exception[extension] self.unit.status = WaitingStatus( f"{'Enabling' if enable else 'Disabling'} {extension}" ) diff --git a/src/config.py b/src/config.py index 96886ef514..b0339b7a67 100644 --- a/src/config.py +++ b/src/config.py @@ -39,6 +39,29 @@ class CharmConfig(BaseConfigModel): plugin_pg_trgm_enable: bool plugin_plpython3u_enable: bool plugin_unaccent_enable: bool + plugin_bloom_enable: bool + plugin_btree_gin_enable: bool + plugin_btree_gist_enable: bool + plugin_cube_enable: bool + plugin_dict_int_enable: bool + plugin_dict_xsyn_enable: bool + plugin_earthdistance_enable: bool + plugin_fuzzystrmatch_enable: bool + plugin_intarray_enable: bool + plugin_isn_enable: bool + plugin_lo_enable: bool + plugin_ltree_enable: bool + plugin_old_snapshot_enable: bool + plugin_pg_freespacemap_enable: bool + plugin_pgrowlocks_enable: bool + plugin_pgstattuple_enable: bool + plugin_pg_visibility_enable: bool + plugin_seg_enable: bool + plugin_tablefunc_enable: bool + plugin_tcn_enable: bool + plugin_tsm_system_rows_enable: bool + plugin_tsm_system_time_enable: bool + plugin_uuid_ossp_enable: bool request_date_style: Optional[str] request_standard_conforming_strings: Optional[bool] request_time_zone: Optional[str] diff --git a/tests/integration/test_plugins.py b/tests/integration/test_plugins.py index 4ed39d8242..9293fb4cd5 100644 --- a/tests/integration/test_plugins.py +++ b/tests/integration/test_plugins.py @@ -24,6 +24,35 @@ PG_TRGM_EXTENSION_STATEMENT = "SELECT word_similarity('word', 'two words');" PLPYTHON3U_EXTENSION_STATEMENT = 'CREATE FUNCTION plpython_test() RETURNS varchar[] AS $$ return "hello" $$ LANGUAGE plpython3u;' UNACCENT_EXTENSION_STATEMENT = "SELECT ts_lexize('unaccent','Hôtel');" +BLOOM_EXTENSION_STATEMENT = ( + "CREATE TABLE tbloom_test (i int);CREATE INDEX btreeidx ON tbloom_test USING bloom (i);" +) +BTREEGIN_EXTENSION_STATEMENT = "CREATE TABLE btree_gin_test (a int4);CREATE INDEX btreeginidx ON btree_gin_test USING GIN (a);" +BTREEGIST_EXTENSION_STATEMENT = "CREATE TABLE btree_gist_test (a int4);CREATE INDEX btreegistidx ON btree_gist_test USING GIST (a);" +CUBE_EXTENSION_STATEMENT = "SELECT cube_inter('(0,-1),(1,1)', '(-2),(2)');" +DICTINT_EXTENSION_STATEMENT = "SELECT ts_lexize('intdict', '12345678');" +DICTXSYN_EXTENSION_STATEMENT = "SELECT ts_lexize('xsyn', 'word');" +EARTHDISTANCE_EXTENSION_STATEMENT = "SELECT earth_distance(ll_to_earth(-81.3927381, 30.2918842),ll_to_earth(-87.6473133, 41.8853881));" +FUZZYSTRMATCH_EXTENSION_STATEMENT = "SELECT soundex('hello world!');" +INTARRAY_EXTENSION_STATEMENT = "CREATE TABLE intarray_test (mid INT PRIMARY KEY, sections INT[]);SELECT intarray_test.mid FROM intarray_test WHERE intarray_test.sections @> '{1,2}';" +ISN_EXTENSION_STATEMENT = "SELECT isbn('978-0-393-04002-9');" +LO_EXTENSION_STATEMENT = "CREATE TABLE lo_test (value lo);" +LTREE_EXTENSION_STATEMENT = "CREATE TABLE ltree_test (path ltree);" +OLD_SNAPSHOT_EXTENSION_STATEMENT = "SELECT * from pg_old_snapshot_time_mapping();" +PG_FREESPACEMAP_EXTENSION_STATEMENT = ( + "CREATE TABLE pg_freespacemap_test (i int);SELECT * FROM pg_freespace('pg_freespacemap_test');" +) +PGROWLOCKS_EXTENSION_STATEMENT = ( + "CREATE TABLE pgrowlocks_test (i int);SELECT * FROM pgrowlocks('pgrowlocks_test');" +) +PGSTATTUPLE_EXTENSION_STATEMENT = "SELECT * FROM pgstattuple('pg_catalog.pg_proc');" +PG_VISIBILITY_EXTENSION_STATEMENT = "CREATE TABLE pg_visibility_test (i int);SELECT * FROM pg_visibility('pg_visibility_test'::regclass);" +SEG_EXTENSION_STATEMENT = "SELECT '10(+-)1'::seg as seg;" +TABLEFUNC_EXTENSION_STATEMENT = "SELECT * FROM normal_rand(1000, 5, 3);" +TCN_EXTENSION_STATEMENT = "CREATE TABLE tcn_test (i int);CREATE TRIGGER tcn_test_idx AFTER INSERT OR UPDATE OR DELETE ON tcn_test FOR EACH ROW EXECUTE FUNCTION TRIGGERED_CHANGE_NOTIFICATION();" +TSM_SYSTEM_ROWS_EXTENSION_STATEMENT = "CREATE TABLE tsm_system_rows_test (i int);SELECT * FROM tsm_system_rows_test TABLESAMPLE SYSTEM_ROWS(100);" +TSM_SYSTEM_TIME_EXTENSION_STATEMENT = "CREATE TABLE tsm_system_time_test (i int);SELECT * FROM tsm_system_time_test TABLESAMPLE SYSTEM_TIME(1000);" +UUID_OSSP_EXTENSION_STATEMENT = "SELECT uuid_nil();" @pytest.mark.abort_on_fail @@ -33,49 +62,65 @@ async def test_plugins(ops_test: OpsTest) -> None: async with ops_test.fast_forward(): await build_and_deploy(ops_test, 2) + sql_tests = { + "plugin_citext_enable": CITEXT_EXTENSION_STATEMENT, + "plugin_debversion_enable": DEBVERSION_EXTENSION_STATEMENT, + "plugin_hstore_enable": HSTORE_EXTENSION_STATEMENT, + "plugin_pg_trgm_enable": PG_TRGM_EXTENSION_STATEMENT, + "plugin_plpython3u_enable": PLPYTHON3U_EXTENSION_STATEMENT, + "plugin_unaccent_enable": UNACCENT_EXTENSION_STATEMENT, + "plugin_bloom_enable": BLOOM_EXTENSION_STATEMENT, + "plugin_btree_gin_enable": BTREEGIN_EXTENSION_STATEMENT, + "plugin_btree_gist_enable": BTREEGIST_EXTENSION_STATEMENT, + "plugin_cube_enable": CUBE_EXTENSION_STATEMENT, + "plugin_dict_int_enable": DICTINT_EXTENSION_STATEMENT, + "plugin_dict_xsyn_enable": DICTXSYN_EXTENSION_STATEMENT, + "plugin_earthdistance_enable": EARTHDISTANCE_EXTENSION_STATEMENT, + "plugin_fuzzystrmatch_enable": FUZZYSTRMATCH_EXTENSION_STATEMENT, + "plugin_intarray_enable": INTARRAY_EXTENSION_STATEMENT, + "plugin_isn_enable": ISN_EXTENSION_STATEMENT, + "plugin_lo_enable": LO_EXTENSION_STATEMENT, + "plugin_ltree_enable": LTREE_EXTENSION_STATEMENT, + "plugin_old_snapshot_enable": OLD_SNAPSHOT_EXTENSION_STATEMENT, + "plugin_pg_freespacemap_enable": PG_FREESPACEMAP_EXTENSION_STATEMENT, + "plugin_pgrowlocks_enable": PGROWLOCKS_EXTENSION_STATEMENT, + "plugin_pgstattuple_enable": PGSTATTUPLE_EXTENSION_STATEMENT, + "plugin_pg_visibility_enable": PG_VISIBILITY_EXTENSION_STATEMENT, + "plugin_seg_enable": SEG_EXTENSION_STATEMENT, + "plugin_tablefunc_enable": TABLEFUNC_EXTENSION_STATEMENT, + "plugin_tcn_enable": TCN_EXTENSION_STATEMENT, + "plugin_tsm_system_rows_enable": TSM_SYSTEM_ROWS_EXTENSION_STATEMENT, + "plugin_tsm_system_time_enable": TSM_SYSTEM_TIME_EXTENSION_STATEMENT, + "plugin_uuid_ossp_enable": UUID_OSSP_EXTENSION_STATEMENT, + } + + def enable_disable_config(enabled: False): + config = {} + for plugin in sql_tests.keys(): + config[plugin] = f"{enabled}" + return config + # Check that the available plugins are disabled. primary = await get_primary(ops_test) password = await get_password(ops_test) address = await get_unit_address(ops_test, primary) + + config = enable_disable_config(False) + await ops_test.model.applications[DATABASE_APP_NAME].set_config(config) + await ops_test.model.wait_for_idle(apps=[DATABASE_APP_NAME], status="active") + logger.info("checking that the plugins are disabled") with db_connect(host=address, password=password) as connection: connection.autocommit = True - - # Test citext extension disabled. - with pytest.raises(psycopg2.Error): - connection.cursor().execute(CITEXT_EXTENSION_STATEMENT) - - # Test debversion extension disabled. - with pytest.raises(psycopg2.Error): - connection.cursor().execute(DEBVERSION_EXTENSION_STATEMENT) - - # Test hstore extension disabled. - with pytest.raises(psycopg2.Error): - connection.cursor().execute(HSTORE_EXTENSION_STATEMENT) - - # Test pg_trgm extension disabled. - with pytest.raises(psycopg2.Error): - connection.cursor().execute(PG_TRGM_EXTENSION_STATEMENT) - - # Test PL/Python extension disabled. - with pytest.raises(psycopg2.Error): - connection.cursor().execute(PLPYTHON3U_EXTENSION_STATEMENT) - - # Test unaccent extension disabled. - with pytest.raises(psycopg2.Error): - connection.cursor().execute(UNACCENT_EXTENSION_STATEMENT) + for query in sql_tests.values(): + with pytest.raises(psycopg2.Error): + connection.cursor().execute(query) connection.close() # Enable the plugins. logger.info("enabling the plugins") - config = { - "plugin_citext_enable": "True", - "plugin_debversion_enable": "True", - "plugin_hstore_enable": "True", - "plugin_pg_trgm_enable": "True", - "plugin_plpython3u_enable": "True", - "plugin_unaccent_enable": "True", - } + + config = enable_disable_config(True) await ops_test.model.applications[DATABASE_APP_NAME].set_config(config) await ops_test.model.wait_for_idle(apps=[DATABASE_APP_NAME], status="active") @@ -83,22 +128,6 @@ async def test_plugins(ops_test: OpsTest) -> None: logger.info("checking that the plugins are enabled") with db_connect(host=address, password=password) as connection: connection.autocommit = True - - # Test citext extension enabled. - connection.cursor().execute(CITEXT_EXTENSION_STATEMENT) - - # Test debversion extension enabled. - connection.cursor().execute(DEBVERSION_EXTENSION_STATEMENT) - - # Test hstore extension enabled. - connection.cursor().execute(HSTORE_EXTENSION_STATEMENT) - - # Test pg_trgm extension enabled. - connection.cursor().execute(PG_TRGM_EXTENSION_STATEMENT) - - # Test PL/Python extension enabled. - connection.cursor().execute(PLPYTHON3U_EXTENSION_STATEMENT) - - # Test unaccent extension enabled. - connection.cursor().execute(UNACCENT_EXTENSION_STATEMENT) + for query in sql_tests.values(): + connection.cursor().execute(query) connection.close()