Uploaded image for project: 'Dev - Nexus Repo'
  1. Dev - Nexus Repo
  2. NEXUS-36653

Postgresql statement to create extension pg_trgm can fail due to could not open extension control file

Details

    • 1
    • NXRM Sentinels Sprint 50
    • maintenance
    • non-concept
    • 2

    Description

      During the upgrade process to 3.45.0, various DB schema changes are performed, one of which is failing for the schema for SearchTableDAO

      This appears to be due to a new dependency on a pg_trgm module

      No indication of this new dependency is present in the release notes.

      The nexus.log may contain a message like this:

      2022-12-28 12:03:49,020-0500 INFO  [FelixStartLevel] *SYSTEM org.sonatype.nexus.datastore.mybatis.MyBatisDataStore - nexus - Creating schema for SearchTableDAO
      2022-12-28 12:03:49,064-0500 WARN  [FelixStartLevel] *SYSTEM Sisu - Problem adding: org.eclipse.sisu.inject.LazyBeanEntry@2c00368 to: org.sonatype.nexus.datastore.mybatis.MyBatisDataStore$$EnhancerByGuice$$366511306@400e761a via: org.sonatype.nexus.datastore.internal.DataStoreManagerImpl$DataAccessMediator@4debec0a
      org.sonatype.nexus.datastore.api.DataAccessException: 
      ### Error updating database.  Cause: org.postgresql.util.PSQLException: ERROR: could not open extension control file "/usr/share/pgsql/extension/pg_trgm.control": No such file or directory
        Where: SQL statement "CREATE EXTENSION IF NOT EXISTS pg_trgm"
      PL/pgSQL function enable_pg_trgm() line 10 at SQL statement
      ### The error may exist in org/sonatype/nexus/repository/content/search/table/SearchTableDAO.xml
      ### The error may involve defaultParameterMap
      ### The error occurred while setting parameters
      ### SQL: CREATE TABLE IF NOT EXISTS search_components     (       repository_id          INTEGER                  NOT NULL,       component_id           INTEGER                  NOT NULL,       format                 VARCHAR                  NOT NULL,       namespace              VARCHAR                  NOT NULL,       search_component_name  VARCHAR                  NOT NULL,       component_kind         VARCHAR                  NOT NULL,       version                VARCHAR                  NOT NULL,       component_created      TIMESTAMP WITH TIME ZONE NOT NULL,       search_repository_name VARCHAR(200)             NOT NULL,       normalised_version     VARCHAR                  NOT NULL,       prerelease             BOOLEAN                  NOT NULL DEFAULT false,       keywords                         TSVECTOR,       md5                              TSVECTOR,       sha1                             TSVECTOR,       sha256                           TSVECTOR,       sha512                           TSVECTOR,       format_field_values_1            TSVECTOR,       format_field_values_2            TSVECTOR,       format_field_values_3            TSVECTOR,       format_field_values_4            TSVECTOR,       format_field_values_5            TSVECTOR,       uploaders                        TSVECTOR,       uploader_ips                     TSVECTOR,       paths                            VARCHAR,       tsvector_paths                   TSVECTOR,       tsvector_format                  TSVECTOR       NOT NULL,       tsvector_namespace               TSVECTOR       NOT NULL,       tsvector_search_component_name   TSVECTOR       NOT NULL,       tsvector_version                 TSVECTOR       NOT NULL,       tsvector_search_repository_name  TSVECTOR       NOT NULL,       last_event_time                  TIMESTAMP      WITH TIME ZONE,       CONSTRAINT pk_search_components PRIMARY KEY (repository_id, component_id, format)       );      CREATE INDEX IF NOT EXISTS idx_search_components_normalised_version ON search_components (normalised_version);     CREATE INDEX IF NOT EXISTS idx_search_components_namespace ON search_components (namespace);     CREATE INDEX IF NOT EXISTS idx_search_components_component_name ON search_components (search_component_name);     CREATE INDEX IF NOT EXISTS idx_search_components_format ON search_components (format);     CREATE INDEX IF NOT EXISTS idx_search_components_repository_name ON search_components (search_repository_name);     CREATE INDEX IF NOT EXISTS idx_search_components_prerelease ON search_components (prerelease);     CREATE INDEX IF NOT EXISTS idx_search_components_keywords ON search_components USING GIN (keywords);     CREATE INDEX IF NOT EXISTS idx_search_components_md5 ON search_components USING GIN (md5);     CREATE INDEX IF NOT EXISTS idx_search_components_sha1 ON search_components USING GIN (sha1);     CREATE INDEX IF NOT EXISTS idx_search_components_sha256 ON search_components USING GIN (sha256);     CREATE INDEX IF NOT EXISTS idx_search_components_sha512 ON search_components USING GIN (sha512);     CREATE INDEX IF NOT EXISTS idx_search_components_format_field_values_1 ON search_components USING GIN (format_field_values_1);     CREATE INDEX IF NOT EXISTS idx_search_components_format_field_values_2 ON search_components USING GIN (format_field_values_2);     CREATE INDEX IF NOT EXISTS idx_search_components_format_field_values_3 ON search_components USING GIN (format_field_values_3);     CREATE INDEX IF NOT EXISTS idx_search_components_format_field_values_4 ON search_components USING GIN (format_field_values_4);     CREATE INDEX IF NOT EXISTS idx_search_components_format_field_values_5 ON search_components USING GIN (format_field_values_5);     CREATE INDEX IF NOT EXISTS idx_search_components_format_uploaders ON search_components USING GIN (uploaders);     CREATE INDEX IF NOT EXISTS idx_search_components_format_uploader_ips ON search_components USING GIN (uploader_ips);     CREATE INDEX IF NOT EXISTS idx_search_components_paths ON search_components (paths);     CREATE INDEX IF NOT EXISTS idx_search_components_tsvector_paths ON search_components USING GIN (tsvector_paths);     CREATE INDEX IF NOT EXISTS idx_search_components_tsvector_format ON search_components USING GIN (tsvector_format);     CREATE INDEX IF NOT EXISTS idx_search_components_tsvector_namespace ON search_components USING GIN (tsvector_namespace);     CREATE INDEX IF NOT EXISTS idx_search_components_tsvector_search_component_name ON search_components USING GIN (tsvector_search_component_name);     CREATE INDEX IF NOT EXISTS idx_search_components_tsvector_version ON search_components USING GIN (tsvector_version);     CREATE INDEX IF NOT EXISTS idx_search_components_tsvector_search_repository_name ON search_components USING GIN (tsvector_search_repository_name);      ALTER TABLE search_components DROP COLUMN IF EXISTS last_event_time;     ALTER TABLE search_components ADD COLUMN IF NOT EXISTS entity_version INT;     CREATE INDEX IF NOT EXISTS idx_search_components_entity_version ON search_components (entity_version);      ALTER TABLE search_components ADD COLUMN IF NOT EXISTS tsvector_tags TSVECTOR;     CREATE INDEX IF NOT EXISTS idx_search_components_tsvector_tags ON search_components USING GIN (tsvector_tags);      --These columns hold untokenised versions of other searchable (i.e. tokenised) data.     -- No index on them because they are not searched (i.e. not searchable)     ALTER TABLE search_components ADD COLUMN IF NOT EXISTS attributes JSONB;     ALTER TABLE search_components ADD COLUMN IF NOT EXISTS tags JSONB;      ALTER TABLE search_components ADD COLUMN IF NOT EXISTS format_field_values_6 TSVECTOR;     ALTER TABLE search_components ADD COLUMN IF NOT EXISTS format_field_values_7 TSVECTOR;     CREATE INDEX IF NOT EXISTS idx_search_components_format_field_values_6 ON search_components USING GIN (format_field_values_6);     CREATE INDEX IF NOT EXISTS idx_search_components_format_field_values_7 ON search_components USING GIN (format_field_values_7);      CREATE OR REPLACE FUNCTION enable_pg_trgm() RETURNS VOID AS $$         DECLARE             version_number INTEGER;             db_version VARCHAR;         BEGIN             SELECT LOWER(version()) INTO db_version;             IF db_version ~ '^postgresql \d\d' THEN                 SELECT SUBSTRING(db_version, CHAR_LENGTH('postgresql') + 2, 2) INTO version_number;                 IF version_number >= 13 THEN                     CREATE EXTENSION IF NOT EXISTS pg_trgm;                     CREATE INDEX IF NOT EXISTS trgm_idx_search_components_paths ON search_components USING GIST (paths gist_trgm_ops);                 END IF;             END IF;         END;     $$ LANGUAGE plpgsql;      SELECT enable_pg_trgm();
      ### Cause: org.postgresql.util.PSQLException: ERROR: could not open extension control file "/usr/share/pgsql/extension/pg_trgm.control": No such file or directory
        Where: SQL statement "CREATE EXTENSION IF NOT EXISTS pg_trgm"
      PL/pgSQL function enable_pg_trgm() line 10 at SQL statement
      	at org.sonatype.nexus.datastore.mybatis.DataAccessSqlSession.unwrapMyBatisException(DataAccessSqlSession.java:125)
      	at org.sonatype.nexus.datastore.mybatis.DataAccessSqlSession.update(DataAccessSqlSession.java:86)
      	at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:181)
      	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:62)
      	at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:145)
      	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86)
      	at com.sun.proxy.$Proxy202.createSchema(Unknown Source)
      	at org.sonatype.nexus.datastore.mybatis.MyBatisDataStore.register(MyBatisDataStore.java:260)
      	at org.sonatype.nexus.datastore.internal.DataStoreManagerImpl$DataAccessMediator.add(DataStoreManagerImpl.java:368)
      	at org.sonatype.nexus.datastore.internal.DataStoreManagerImpl$DataAccessMediator.add(DataStoreManagerImpl.java:1)
      	at org.eclipse.sisu.inject.WatchedBeans.add(WatchedBeans.java:80)
      	at org.eclipse.sisu.inject.InjectorBindings.publishExactMatches(InjectorBindings.java:157)
      	at org.eclipse.sisu.inject.InjectorBindings.subscribe(InjectorBindings.java:79)
      	at org.eclipse.sisu.inject.DefaultBeanLocator.watch(DefaultBeanLocator.java:80)
      	at org.sonatype.nexus.datastore.internal.DataStoreManagerImpl.doCreate(DataStoreManagerImpl.java:197)
      	at org.sonatype.nexus.datastore.internal.DataStoreManagerImpl.tryRestore(DataStoreManagerImpl.java:175)
      	at com.google.common.collect.ImmutableList.forEach(ImmutableList.java:406)
      	at org.sonatype.nexus.datastore.internal.DataStoreManagerImpl.doStart(DataStoreManagerImpl.java:124)
      	at org.sonatype.nexus.common.stateguard.StateGuardLifecycleSupport.start(StateGuardLifecycleSupport.java:69)
      	at org.sonatype.nexus.datastore.internal.DataStoreManagerImpl$$EnhancerByGuice$$141081007.GUICE$TRAMPOLINE(<generated>)
      	at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:74)
      	at org.sonatype.nexus.common.stateguard.MethodInvocationAction.run(MethodInvocationAction.java:39)
      	at org.sonatype.nexus.common.stateguard.StateGuard$TransitionImpl.run(StateGuard.java:193)
      	at org.sonatype.nexus.common.stateguard.TransitionsInterceptor.invoke(TransitionsInterceptor.java:57)
      	at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:75)
      	at com.google.inject.internal.InterceptorStackCallback.invoke(InterceptorStackCallback.java:55)
      	at org.sonatype.nexus.datastore.internal.DataStoreManagerImpl$$EnhancerByGuice$$141081007.start(<generated>)
      	at org.sonatype.nexus.extender.NexusLifecycleManager.startComponent(NexusLifecycleManager.java:199)
      	at org.sonatype.nexus.extender.NexusLifecycleManager.to(NexusLifecycleManager.java:111)
      	at org.sonatype.nexus.extender.NexusContextListener.moveToPhase(NexusContextListener.java:319)
      	at org.sonatype.nexus.extender.NexusContextListener.frameworkEvent(NexusContextListener.java:216)
      	at org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1597)
      	at org.apache.felix.framework.FrameworkStartLevelImpl.run(FrameworkStartLevelImpl.java:308)
      	at java.lang.Thread.run(Thread.java:748)
       

       

      Impact

      Startup and upgrade DOES NOT FAIL. Whether there is some other impact like certain database queries not returning expected results still needs investigation.

      Expected

      Given that the use of this module is unavoidable, this new dependency should be prominently documented to ensure the module is added to the Postgres instance before performing the upgrade.

      If installing this modules is optional, simply log a WARN message when it can't be installed, instead of a concerning stack trace.

      Workaround

      Install the postgresql-contrib package in your linux distribution system. This will work for RHEL 7 and higher based systems, Fedora, and recent debian/ubuntu systems. Other distributions may provide this extension via a different package.

      Attachments

        Activity

          People

            ldurant Lisa Durant
            dkane Daniel Kane
            Anjali Arora Anjali Arora
            NXRM - Sentinels
            Mykyta Shevelov Mykyta Shevelov
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              tigCommentSecurity.panel-title