Repository: sqldelight/sqldelight

Issue #1018: UPDATE statement on a VIEW built with a UNION clause does not compile
Created: 2018-10-21T08:56:56Z
Versions: 1.0.0-alpha5, 1.0.0-rc2
Have a couple of tables, a VIEW, a TRIGGER on a VIEW and an UPDATE statement:
CREATE TABLE foo (
  id INTEGER NOT NULL PRIMARY KEY,
  name TEXT NOT NULL,
  selected INTEGER AS Boolean NOT NULL
);

CREATE TABLE bar (
  id INTEGER NOT NULL PRIMARY KEY,
  short_name TEXT NOT NULL,
  full_name TEXT NOT NULL,
  selected INTEGER AS Boolean NOT NULL
);

CREATE VIEW foobar AS
SELECT id, name, selected FROM foo
UNION
SELECT id, short_name AS name, selected FROM bar;

CREATE TRIGGER foobar_update_added
INSTEAD OF UPDATE OF selected ON foobar
BEGIN
  UPDATE foo SET selected = new.selected WHERE id = new.id;
  UPDATE bar SET selected = new.selected WHERE id = new.id;
END;

updateFoobarSelected:
UPDATE OR IGNORE foobar SET selected = ? WHERE id = ?;
Compilation fails with the following error:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':foobar:generateDebugSqlDelightInterface'.
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:110)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:77)
	at org.gradle.api.internal.tasks.execution.OutputDirectoryCreatingTaskExecuter.execute(OutputDirectoryCreatingTaskExecuter.java:51)
	at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:59)
	at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
	at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:59)
	at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:101)
	at org.gradle.api.internal.tasks.execution.FinalizeInputFilePropertiesTaskExecuter.execute(FinalizeInputFilePropertiesTaskExecuter.java:44)
	at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:91)
	at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:62)
	at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:59)
	at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
	at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
	at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.run(EventFiringTaskExecuter.java:51)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:300)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:292)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:174)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:90)
	at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:46)
	at org.gradle.execution.taskgraph.LocalTaskInfoExecutor.execute(LocalTaskInfoExecutor.java:42)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareWorkItemExecutor.execute(DefaultTaskExecutionGraph.java:277)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareWorkItemExecutor.execute(DefaultTaskExecutionGraph.java:262)
	at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:135)
	at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:130)
	at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker.execute(DefaultTaskPlanExecutor.java:200)
	at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker.executeWithWork(DefaultTaskPlanExecutor.java:191)
	at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker.run(DefaultTaskPlanExecutor.java:130)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: Failed to compile SqliteUpdateStmtLimitedImpl(UPDATE_STMT_LIMITED): [] :
UPDATE OR IGNORE foobar SET selected = ? WHERE id = ?
	at com.squareup.sqldelight.core.compiler.SqlDelightCompilerKt.tryWithElement(SqlDelightCompiler.kt:119)
	at com.squareup.sqldelight.core.compiler.QueriesTypeGenerator.generateType(QueriesTypeGenerator.kt:76)
	at com.squareup.sqldelight.core.compiler.SqlDelightCompiler.writeQueriesType$sqldelight_compiler(SqlDelightCompiler.kt:80)
	at com.squareup.sqldelight.core.compiler.SqlDelightCompiler.compile(SqlDelightCompiler.kt:36)
	at com.squareup.sqldelight.core.SqlDelightEnvironment$generateSqlDelightFiles$2.invoke(SqlDelightEnvironment.kt:108)
	at com.squareup.sqldelight.core.SqlDelightEnvironment$generateSqlDelightFiles$2.invoke(SqlDelightEnvironment.kt:53)
	at com.alecstrong.sqlite.psi.core.SqliteCoreEnvironment$forSourceFiles$1.processFile(SqliteCoreEnvironment.kt:69)
	at com.alecstrong.sqlite.psi.core.CoreFileIndex.iterateContentUnderDirectory(SqliteCoreEnvironment.kt:100)
	at com.alecstrong.sqlite.psi.core.CoreFileIndex.iterateContentUnderDirectory(SqliteCoreEnvironment.kt:97)
	at com.alecstrong.sqlite.psi.core.CoreFileIndex.iterateContentUnderDirectory(SqliteCoreEnvironment.kt:97)
	at com.alecstrong.sqlite.psi.core.CoreFileIndex.iterateContentUnderDirectory(SqliteCoreEnvironment.kt:97)
	at com.alecstrong.sqlite.psi.core.CoreFileIndex.iterateContentUnderDirectory(SqliteCoreEnvironment.kt:97)
	at com.alecstrong.sqlite.psi.core.CoreFileIndex.iterateContentUnderDirectory(SqliteCoreEnvironment.kt:97)
	at com.alecstrong.sqlite.psi.core.CoreFileIndex.iterateContent(SqliteCoreEnvironment.kt:91)
	at com.alecstrong.sqlite.psi.core.SqliteCoreEnvironment.forSourceFiles(SqliteCoreEnvironment.kt:67)
	at com.squareup.sqldelight.core.SqlDelightEnvironment.generateSqlDelightFiles(SqlDelightEnvironment.kt:105)
	at com.squareup.sqldelight.gradle.SqlDelightTask.generateSqlDelightFiles(SqlDelightTask.kt:47)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:46)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:39)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:26)
	at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:801)
	at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:768)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.run(ExecuteActionsTaskExecuter.java:131)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:300)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:292)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:174)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:90)
	at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:120)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:99)
	... 34 more
Caused by: java.lang.IllegalArgumentException: List has more than one element.
	at kotlin.collections.CollectionsKt___CollectionsKt.single(_Collections.kt:480)
	at com.squareup.sqldelight.core.compiler.model.NamedMutator$tableEffected$2.invoke(NamedMutator.kt:36)
	at com.squareup.sqldelight.core.compiler.model.NamedMutator$tableEffected$2.invoke(NamedMutator.kt:28)
	at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
	at com.squareup.sqldelight.core.compiler.model.NamedMutator.getTableEffected$sqldelight_compiler(NamedMutator.kt)
	at com.squareup.sqldelight.core.compiler.MutatorQueryGenerator$notifyQueries$1.invoke(MutatorQueryGenerator.kt:73)
	at com.squareup.sqldelight.core.compiler.MutatorQueryGenerator$notifyQueries$1.invoke(MutatorQueryGenerator.kt:28)
	at com.squareup.sqldelight.core.lang.SqlDelightFile.iterateSqliteFiles(SqlDelightFile.kt:92)
	at com.squareup.sqldelight.core.compiler.MutatorQueryGenerator.notifyQueries(MutatorQueryGenerator.kt:71)
	at com.squareup.sqldelight.core.compiler.MutatorQueryGenerator.type(MutatorQueryGenerator.kt:167)
	at com.squareup.sqldelight.core.compiler.QueriesTypeGenerator$generateType$$inlined$forEach$lambda$2.invoke(QueriesTypeGenerator.kt:82)
	at com.squareup.sqldelight.core.compiler.QueriesTypeGenerator$generateType$$inlined$forEach$lambda$2.invoke(QueriesTypeGenerator.kt:18)
	at com.squareup.sqldelight.core.compiler.SqlDelightCompilerKt.tryWithElement(SqlDelightCompiler.kt:117)
	... 68 more
Removing UNION and the second SELECT from the VIEW lets the compiler to run just fine.

Duplicate issue #904: SqlDelight compiler crashes when compiling an INSERT into a VIEW
Created: 2018-08-04T19:33:34Z
I'm using com.squareup.sqldelight:runtime-jdk:1.0.0-alpha4 and com.squareup.sqldelight:sqlite-driver:1.0.0-alpha4, here's a minimal repro:
CREATE VIEW Foo AS SELECT 1;

insertFoo:
INSERT INTO Foo VALUES ?;

It seems to be a mistaken assumption with a cast:
Caused by: java.lang.ClassCastException: com.alecstrong.sqlite.psi.core.psi.impl.SqliteLiteralExprImpl cannot be cast to com.alecstrong.sqlite.psi.core.psi.SqliteColumnName
        at com.squareup.sqldelight.core.lang.psi.InsertStmtMixin.annotate(InsertStmtMixin.kt:19)

Here's a full stacktrace

Closing comment (2018-11-24T23:32:32Z): Marking as dup of #1018