question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

slick-migration-api purpose

See original GitHub issue

It is not really an issue but more a request for making things clearer on the purpose of this lib. Sorry if it is not the right place to do it.

Is this lib done for propagate changes made in the db scheme to an already existing db ?

For instance I built a h2 db with a USERS table, added some entries with slick. The h2 file is built, the rows exist. Then I added a column TOTO in my slick table definition. I need to propagate this change to my h2 db file so that they are still compatible. So I did this:

val init = TableMigration(dbScheme.users)
          .addColumns(_.toto)

        db.run(init())

My h2 db file is modified but I cannot see a new column TOTO. Is it the right way to achive this ?

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
mathieuleclairecommented, Feb 23, 2017

I created a repo reproducing the bug: https://github.com/mathieuleclaire/testSlickMigration. You can either producing the initial table following the instructions in the README or use this prebuilt table (containing only two columns): h2.mv.db.tar.gz

Can you reproduce ?

0reactions
nafgcommented, Apr 6, 2017

Hi, apologies for not looking into this earlier.

Here are my findings:

After following instructions in the readme, it did not print FINISHED. The .mv.db file had not been updated, but the sibling .trace.db file was. It contained:

2017-04-05 20:29:58 database: flush
org.h2.message.DbException: General error: "java.lang.IllegalStateException: Could not open file nio:/tmp/testSlickMigration.mv.db [1.4.190/1]" [50000-190]
	at org.h2.message.DbException.get(DbException.java:168)
	at org.h2.message.DbException.convert(DbException.java:295)
	at org.h2.mvstore.db.MVTableEngine$1.uncaughtException(MVTableEngine.java:94)
	at org.h2.mvstore.MVStore.panic(MVStore.java:373)
	at org.h2.mvstore.MVStore.<init>(MVStore.java:356)
	at org.h2.mvstore.MVStore$Builder.open(MVStore.java:2888)
	at org.h2.mvstore.db.MVTableEngine$Store.open(MVTableEngine.java:154)
	at org.h2.mvstore.db.MVTableEngine.init(MVTableEngine.java:99)
	at org.h2.engine.Database.getPageStore(Database.java:2450)
	at org.h2.engine.Database.open(Database.java:672)
	at org.h2.engine.Database.openDatabase(Database.java:269)
	at org.h2.engine.Database.<init>(Database.java:263)
	at org.h2.engine.Engine.openSession(Engine.java:65)
	at org.h2.engine.Engine.openSession(Engine.java:175)
	at org.h2.engine.Engine.createSessionAndValidate(Engine.java:153)
	at org.h2.engine.Engine.createSession(Engine.java:136)
	at org.h2.engine.Engine.createSession(Engine.java:28)
	at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:349)
	at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:107)
	at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:91)
	at org.h2.Driver.connect(Driver.java:72)
	at slick.jdbc.DriverDataSource.getConnection(DriverDataSource.scala:101)
	at slick.jdbc.DataSourceJdbcDataSource.createConnection(JdbcDataSource.scala:72)
	at slick.jdbc.JdbcBackend$BaseSession.<init>(JdbcBackend.scala:439)
	at slick.jdbc.JdbcBackend$DatabaseDef.createSession(JdbcBackend.scala:47)
	at slick.jdbc.JdbcBackend$DatabaseDef.createSession(JdbcBackend.scala:38)
	at slick.basic.BasicBackend$DatabaseDef$class.acquireSession(BasicBackend.scala:218)
	at slick.jdbc.JdbcBackend$DatabaseDef.acquireSession(JdbcBackend.scala:38)
	at slick.basic.BasicBackend$DatabaseDef$$anon$2.run(BasicBackend.scala:239)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
Caused by: org.h2.jdbc.JdbcSQLException: General error: "java.lang.IllegalStateException: Could not open file nio:/tmp/testSlickMigration.mv.db [1.4.190/1]" [50000-190]
	at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
	... 32 more
Caused by: java.lang.IllegalStateException: Could not open file nio:/tmp/testSlickMigration.mv.db [1.4.190/1]
	at org.h2.mvstore.DataUtils.newIllegalStateException(DataUtils.java:773)
	at org.h2.mvstore.FileStore.open(FileStore.java:178)
	at org.h2.mvstore.MVStore.<init>(MVStore.java:342)
	... 27 more
Caused by: java.nio.channels.ClosedByInterruptException
	at java.nio.channels.spi.AbstractInterruptibleChannel.end(AbstractInterruptibleChannel.java:202)
	at sun.nio.ch.FileChannelImpl.size(FileChannelImpl.java:315)
	at org.h2.store.fs.FileNio.size(FilePathNio.java:58)
	at org.h2.mvstore.cache.FilePathCache$FileCache.size(FilePathCache.java:116)
	at org.h2.mvstore.FileStore.open(FileStore.java:176)
	... 28 more

So H2 couldn’t open the file and change it because it was interrupted. Apparently, the JVM terminated before it was done. As I explained earlier, and as you can see by looking at its type, Slick’s run method returns a Future, so just because it returns doesn’t mean the work has been done already. That’s what asynchronous means.

I then changed the code to this:

     try {
       Await.result(
          db.run(init()),
          Duration.Inf
        )
     } finally {
       println("finally")
       db.close
     }

Now it blocks so the migration has a chance to run. However it gives a different error:

slick.migration.api.MigrationException: Could not execute sql: 'alter table "USERS"
 add column "TOTO" VARCHAR NOT NULL'
	at slick.migration.api.SqlMigration$$anonfun$apply$2$$anonfun$apply$3.apply(Migration.scala:104)
	at slick.migration.api.SqlMigration$$anonfun$apply$2$$anonfun$apply$3.apply(Migration.scala:100)
	at scala.collection.immutable.List.foreach(List.scala:381)
	at slick.migration.api.SqlMigration$$anonfun$apply$2.apply(Migration.scala:100)
	at slick.migration.api.SqlMigration$$anonfun$apply$2.apply(Migration.scala:99)
	at slick.jdbc.SimpleJdbcAction.run(StreamingInvokerAction.scala:70)
	at slick.jdbc.SimpleJdbcAction.run(StreamingInvokerAction.scala:69)
	at slick.basic.BasicBackend$DatabaseDef$$anon$2.liftedTree1$1(BasicBackend.scala:240)
	at slick.basic.BasicBackend$DatabaseDef$$anon$2.run(BasicBackend.scala:240)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
Caused by: org.h2.jdbc.JdbcSQLException: NULL not allowed for column "TOTO"; SQL statement:
alter table "USERS"
 add column "TOTO" VARCHAR NOT NULL [23502-190]
	at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
	at org.h2.message.DbException.get(DbException.java:179)
	at org.h2.message.DbException.get(DbException.java:155)
	at org.h2.table.Column.validateConvertUpdateSequence(Column.java:305)
	at org.h2.table.Table.validateConvertUpdateSequence(Table.java:749)
	at org.h2.command.dml.Insert.addRow(Insert.java:195)
	at org.h2.command.dml.Select.queryFlat(Select.java:543)
	at org.h2.command.dml.Select.queryWithoutCache(Select.java:643)
	at org.h2.command.dml.Query.query(Query.java:322)
	at org.h2.command.dml.Insert.insertRows(Insert.java:167)
	at org.h2.command.dml.Insert.update(Insert.java:114)
	at org.h2.command.ddl.CreateTable.update(CreateTable.java:185)
	at org.h2.command.ddl.AlterTableAlterColumn.execute(AlterTableAlterColumn.java:464)
	at org.h2.command.ddl.AlterTableAlterColumn.cloneTableStructure(AlterTableAlterColumn.java:364)
	at org.h2.command.ddl.AlterTableAlterColumn.copyData(AlterTableAlterColumn.java:230)
	at org.h2.command.ddl.AlterTableAlterColumn.update(AlterTableAlterColumn.java:162)
	at org.h2.command.CommandContainer.update(CommandContainer.java:78)
	at org.h2.command.Command.executeUpdate(Command.java:253)
	at org.h2.jdbc.JdbcPreparedStatement.execute(JdbcPreparedStatement.java:198)
	at slick.migration.api.SqlMigration$$anonfun$apply$2$$anonfun$apply$3$$anonfun$1.apply(Migration.scala:101)
	at slick.migration.api.SqlMigration$$anonfun$apply$2$$anonfun$apply$3$$anonfun$1.apply(Migration.scala:101)
	at slick.jdbc.JdbcBackend$SessionDef$class.withPreparedStatement(JdbcBackend.scala:372)
	at slick.jdbc.JdbcBackend$BaseSession.withPreparedStatement(JdbcBackend.scala:434)
	at slick.migration.api.SqlMigration$$anonfun$apply$2$$anonfun$apply$3.apply(Migration.scala:101)
	at slick.migration.api.SqlMigration$$anonfun$apply$2$$anonfun$apply$3.apply(Migration.scala:100)
	at scala.collection.immutable.List.foreach(List.scala:381)
	at slick.migration.api.SqlMigration$$anonfun$apply$2.apply(Migration.scala:100)
	at slick.migration.api.SqlMigration$$anonfun$apply$2.apply(Migration.scala:99)
	at slick.jdbc.SimpleJdbcAction.run(StreamingInvokerAction.scala:70)
	at slick.jdbc.SimpleJdbcAction.run(StreamingInvokerAction.scala:69)
	at slick.basic.BasicBackend$DatabaseDef$$anon$2.liftedTree1$1(BasicBackend.scala:240)
	at slick.basic.BasicBackend$DatabaseDef$$anon$2.run(BasicBackend.scala:240)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)

This is a problem with your logic; it’s impossible to add a non-nullable column to a database without a default value.

I plan to add to slick-migration-api a method that lets you do the following in one step: Add the column except nullable, populate it with a specified value or sql expression, and then set it nullable.

However the simpler solution is to just set an O.Default(defaultValue) column option.

If you still have trouble please open a new issue (you can reference this one).

Read more comments on GitHub >

github_iconTop Results From Across the Web

nafg/slick-migration-api: Schema manipulation dialects and ...
Write typesafe and typo-safe database migrations, using your existing Slick table definitions. Pipeline Status · Coverage Status · Maven Central. Dependency ...
Read more >
mysql - Slick Database Migrations - Stack Overflow
I'm working on a project using Scala which uses Slick.io for handling database interactions. I have the database schema implemented via ...
Read more >
slick-migration-api-flyway - Scaladex
This library is an adapter between the Flyway database migration tool and the slick-migration-api library. One can aggregate scala.slick.migration.api.
Read more >
How to create RESTful API with Scala, Play, Silhouette and Slick
The given article can help you out with creating a RESTful API with Play Framework, Slick ORM, PostgreSQL and Silhouette JWT authentication/authorization.
Read more >
Replace your old API platform - Tyk.io
Slick, strategic and supportive API migration ... analytics puts you in a powerful position to achieve your migration and ongoing API management goals....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found