HsqlException: тип не найден или пользователю не хватает прав: DATETIMEOFFSET

У меня есть приложение Java 8, Spring Boot 2 с объектами JPA, подключающимися к базе данных MS SQL Server. Я пытаюсь создать интеграционные тесты с использованием HSQLDB (2.3.3), которые отлично работают, если я не включаю информацию аудита (дата создания, последнее обновление и т. д.).

Это сообщение об ошибке, которое я получаю:

Caused by: org.hsqldb.HsqlException: type not found or user lacks privilege: DATETIMEOFFSET

Я понимаю, что ошибка «тип не найден или пользователю не хватает привилегий» является общей и может быть вызвана разными причинами. В этом случае я знаю, что в противном случае все работало бы правильно, если бы не попытка добавить в таблицу столбец datetimeoffset.

При поиске ответов в Интернете я обнаружил эта документация, что по крайней мере некоторые типы даты/времени и функции MS SQL поддерживаются, но этот (двухлетний) ответ предполагает, что HSQLDB имеет только ограниченную поддержку MS SQL. Я не нашел никакой документации, в которой говорится о HSQLDB конкретно в отношении типа данных datetimeoffset.

Мой сценарий создания таблицы и вставки данных:

    DROP SCHEMA TEST IF EXISTS;
    CREATE SCHEMA TEST;

    CREATE TABLE TEST.Example (
      ID int IDENTITY NOT NULL,
      Name nvarchar(30) NOT NULL,
      Description nvarchar(1000),
      CreatedDate datetimeoffset(7) NOT NULL
    );

    INSERT INTO TEST.Example (ID, Name, Description, CreatedDate) 
    VALUES (1, 'First', 'This is the first example.', '2019-04-18 12:00:00 -05:00');

Моя конфигурация источника данных:

    config:
      datasource:
        jdbc-url: jdbc:hsqldb:mem:testdb;sys.syntax_mss=true
        driver-class-name: org.hsqldb.jdbc.JDBCDriver
        validation-query: SELECT 1
        test-on-borrow: false
        test-while-idle: true
        time-between-eviction-runs-millis: 60000
        max-active: 10

Моя сущность:

    @Data
    @Entity
    @Table(name = "Example", schema = "TEST")
    public class ExampleEntity {    
        @Id
        @Column(name = "ID", unique = true, nullable = false)
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private int id;

        @Column(name = "Name", nullable = false)
        private String name;

        @Column(name = "Description")
        private String description;

        @Column(name = "CreatedDate", nullable = false)
        private LocalDateTime createdDate;    
    }

Мой репозиторий:

    public interface ExampleRepository extends CrudRepository<ExampleEntity, Integer> {
    }

Моя конфигурация интеграционного теста:

    @Configuration
    @EnableJpaRepositories(
        basePackages = "com.test.example.repository",
        entityManagerFactoryRef = "integrationTestEntityFactory",
        transactionManagerRef = "integrationTestTransactionManager")
    public class IntegrationTestConfig {
        @Bean
        @ConfigurationProperties(prefix = "config.datasource")
        public DataSource integrationTestDatasource() {
            return new EmbeddedDatabaseBuilder()
                .addScript("scripts/schema.sql")
                .build();
        }

        @Bean
        public LocalContainerEntityManagerFactoryBean integrationTestEntityFactory(final DataSource integrationTestDatasource) {

            HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
            vendorAdapter.setDatabase(Database.SQL_SERVER);
            vendorAdapter.setShowSql(false);

            LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
            factory.setJpaVendorAdapter(vendorAdapter);
            factory.setPackagesToScan("com.test.example.entity");
            factory.setDataSource(integrationTestDatasource);
            return factory;
        }

        @Bean
        public PlatformTransactionManager integrationTestTransactionManager(final LocalContainerEntityManagerFactoryBean integrationTestEntityFactory) {
            JpaTransactionManager transactionManager = new JpaTransactionManager();
            transactionManager.setEntityManagerFactory(integrationTestEntityFactory.getObject());
            return transactionManager;
        }

        @Bean
        public NamedParameterJdbcTemplate integrationTestJdbcTemplate(final DataSource integrationTestDatasource) {
            return new NamedParameterJdbcTemplate(integrationTestDatasource);
        }
    }
Читать документацию HSQLDB, а не SQL Server, если вы хотите узнать, какие типы данных поддерживаются: Руководство пользователя HyperSQL — Типы даты и времени. Не существует такого типа данных, как datetimeoffset.
Andreas 18.04.2019 20:35

@Andreas Андреас Я читал это, и в нем не упоминается, что он не поддерживает все функции SQL Server. Голосовать против из-за отсутствия исследований, когда я провел свое исследование и все еще нуждаюсь в помощи, мелочно и не нужно. Если вы предполагаете, что HSQLDB не может делать то, что мне нужно, то это звучит как ответ, который может помочь не только мне, но и другим с этой проблемой в будущем.

aherocalledFrog 18.04.2019 20:45

Где в вашем исследовании вы обнаружили, что HSQLDB поддерживает типы данных SQL Server? В ссылке, которую вы дали, написано «HyperSQL 2.4 добавляет несколько функции даты и времени в режим совместимости с MSS. К ним относятся DATEPART, DATENAME, EOMONTH и совместимое поведение DATEADD и DATEDIFF». Функции!!! Не типы данных. В разделе «Совместимость с MS SQLServer и Sybase» вообще не упоминаются типы данных столбцов.

Andreas 18.04.2019 20:48

@Andreas Андреас Похоже, у тебя плохой день. Я был бы признателен, если бы вы не испортили мою, не дав мне получить помощь. Или этот сайт не помогает людям?

aherocalledFrog 18.04.2019 20:50

Я помогаю, указывая на то, что вы неправильно прочитали документацию. Или, в случае, если я это сделал, я прошу вас указать мне, где, по вашему мнению, в документации сказано то, что, как вы утверждали, было сказано («Я нашел эту документацию, что по крайней мере некоторые дата/время MS SQL типы и функции поддерживаются»). Указание на ошибки вас не касается? Не отклоняйте помощь только потому, что это указывает на то, что вы чего-то не поняли. Учитесь на этом, то есть не пытайтесь использовать тип данных столбца SQL Server в DDL для HSQLDB.

Andreas 18.04.2019 20:55

Обратите внимание, что в руководстве по HSQLDB не перечислены ВСЕ поддерживаемые режимом совместимости функции и имена типов, включая это. Используемая версия OP старше ссылочного документа.

fredt 19.04.2019 13:20
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
6
347
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Для типа datetimeoffset SQL вы должны использовать тип java.time.OffsetDateTime Java:

    @Column(name = "CreatedDate", nullable = false)
    private OffsetDateTime createdDate; 

Это если у вас есть JPA версии 2.2 в пути к классам. В противном случае вам нужно будет создать пользовательский конвертер

Я получаю сообщение об ошибке, даже если я оставляю поле вне объекта. Ошибка, которую я получаю, определенно связана с созданием столбца HSQLDB, а не с получением данных из таблицы JPA.

aherocalledFrog 18.04.2019 20:22

Я буду работать над созданием конвертера, спасибо за внимание!

aherocalledFrog 18.04.2019 20:28

Я добавил конвертер, и у меня все еще есть эта проблема.

aherocalledFrog 18.04.2019 20:46

Я использовал LocalDateTime на основе существующей работы в моей организации, но OffsetDateTime будет работать намного лучше для моих нужд и без конвертера для загрузки. Ваш ответ конкретно не ответил на мой вопрос, но все же это был отличный совет. Спасибо за помощь!

aherocalledFrog 19.04.2019 21:20
Ответ принят как подходящий

Последние версии HSQLDB поддерживают DATETIMEOFFSET в режиме совместимости с MSS. Используйте 2.4.1.

Если вы хотите продолжить использовать более старую версию, которая не поддерживает этот тип, используйте CREATE TYPE DATETIMEOFFSET AS TIMESTAMP WITH TIME ZONE перед созданием таблиц.

Это решило мою проблему. Следует отметить, что в то время как SQL Server может использовать входные данные точности в определении столбца, HSQLDB этого не делает. Это означает, что мои тестовые данные не будут точно соответствовать производственным данным, но в сочетании с изменением OffsetDateTime для @MaciejKowalski я не думаю, что это будет проблемой.

aherocalledFrog 19.04.2019 21:26

Другие вопросы по теме