0

I'm uing spring boot with a SQLite DB and spring keeps trying to alter the column AFTER it created the table, however SQLite alter statements only support renaming a table and such. I thought it was obvious enough that the SQLiteDialect would support this by declaring the column as unique during the table's creation but I guess i was wrong. My entity looks like this:

@Entity
@Table(name = "my_entities")
public class MyEntity {
    // usual Long id and stuff

    @Column(nullable = false, unique = true)
    private String word;

    // other fields
}

Here's the log output that shows the exception:

Error executing DDL "alter table my_entities add constraint UKegg5ipack6d4292p1uvwopxl6 unique (word)" via JDBC Statement

I considered many options:

  • actually modifying SQLiteDialect myself since it's a community dialect anyways, but after looking into it a bit more I realized I would need to do a bit more than just modify a string somewhere
  • creating some kind of import.sql that has a drop and create statement in it, but it would defy the whole point of having my DB managed for me:
DROP TABLE IF EXISTS my_entities;
CREATE TABLE my_entities(
    ...
    word varchar(255) UNIQUE,
    ...
);

Eventually, I don't understand why SQLiteDialect can't just create the table from the start with the unique modifier. Does anyone have a solution that makes spring or the dialect do that ?

GMB
  • 216,147
  • 25
  • 84
  • 135
Lorenzo
  • 591
  • 7
  • 18

1 Answers1

2

I suppose you are using Hibernate with hbm2ddl.auto=update. Spring does not manage your DDL. It is up to your JPA provider. It also has nothing to do with SQLiteDialect.

Iirc the Hibernate auto DDL parser has the following semantic (probably to fix some other bugs): if the database is already created, Hibernate won't include the CREATE TABLE with UNIQUE. Instead, it will issue ALTER CONSTRAINT. Drop the database yourself (in the case of SQLite, delete the file). Use hbm2ddl.auto=update to create everything back.

If you are not using production code, personally I do not recommend SQLite. SQLite has a lot of performance concerns which are mostly unnecessary for education and testing, thus limiting a lot of use cases. You can use the fully functional H2 (supports file backing like SQLite) instead. It should be as easy as changing your JDBC URL/Datasource configuration.

On the other hand, ideally you should provide your own DDL (hand written by the DBA) or use a Database migration tool like Flyway or Liquibase for automation.

Kamii0909
  • 56
  • 3
  • That's actually a valid point, so I'll still thumbs up the answer. This isn't production code, just my personal project and I always used SQLite in the past because I didn't want a full blown DB, but forgot H2 has an in-mem database that can be backed by a file. The only issue I have is with h2 memory corruption issues as the testimonies show here: https://stackoverflow.com/a/62845028/3225638 – Lorenzo Mar 30 '23 at 19:46
  • I deleted the db file and changed the `hbm2ddl.auto=update` like you said, and somehow everything works now. I don't really understand why though, my previous value was set to `create-drop`, and in your answer you said "if db already created => alter constraint" but it still did the alter statements even with `update` but somehow it works now. Can you explain the difference ? – Lorenzo Mar 30 '23 at 20:12
  • 1
    Sorry for the late response. For your question, it actually involve `SQLiteDialect`. A bit nonsensical bug from Hibernate, also. So `SQLiteDialect` inherit `canCreateCatalog() { return false; }` from `Dialect`. So Hibernate knows that SQLite only have 1 default catalog (database). It can't issue a normal SQL `DROP DATABASE xxx` so it attempts to drop the catalog by dropping every relevant tables (it makes no assumption about the storage system so no automatic file deletion). For whatever reasons, somehow it still think the unique constraint is not supplied and issue a `ALTER TABLE`. – Kamii0909 Apr 03 '23 at 11:19
  • 1
    The update version doesn't eliminate the error, it simply ignore them, because it can better assume that an unique constraint is already present. The create-drop version have to make sure the schema is valid, so it cries by forwarding the exception. – Kamii0909 Apr 03 '23 at 11:21