sqldelight
sqldelight copied to clipboard
Foreign Key's Implicit Parent Columns Cause Error
SQLDelight Version
2.0.1
Operating System
Linux x86_64
Gradle Version
8.4
Kotlin Version
1.9.10
Dialect
SQLite
AGP Version
8.2.0
Describe the Bug
When a FOREIGN KEY
constraint is created referencing another table's column with the same name, putting the name of the parent column is not required (e.g. FOREIGN KEY(student_id) REFERENCES Students
). However, the compiler gives an error as it tries to access index 0 of the relevant columns when there are no explicitly defined columns. The error points to this line. The fix for this should be simple; if there are 0 explicitly defined columns in the parent table reference, the program should search for the child column names of the constraints (referencing the earlier example, it should search for the student_id
column in Students
).
Example SQL:
CREATE TABLE Students(
student_id INTEGER PRIMARY KEY,
gpa REAL
);
CREATE TABLE Parents(
parent_name TEXT PRIMARY KEY,
student_id INTEGER,
FOREIGN KEY(student_id) REFERENCES Students
);
With ...REFERENCES Students(student_id)
, this works correctly.
Stacktrace
Caused by: java.lang.IllegalStateException: Failed to compile {}: [] :
CREATE TABLE Parents(
parent_name TEXT PRIMARY KEY,
student_id INTEGER,
FOREIGN KEY(student_id) REFERENCES Students
)
at app.cash.sqldelight.core.compiler.SqlDelightCompilerKt.tryWithElement(SqlDelightCompiler.kt:234)
at app.cash.sqldelight.core.compiler.SqlDelightCompiler.writeTableInterfaces$sqldelight_compiler(SqlDelightCompiler.kt:144)
at app.cash.sqldelight.core.compiler.SqlDelightCompiler.writeTableInterfaces$sqldelight_compiler$default(SqlDelightCompiler.kt:125)
at app.cash.sqldelight.core.compiler.SqlDelightCompiler.writeInterfaces(SqlDelightCompiler.kt:50)
at app.cash.sqldelight.core.SqlDelightEnvironment$generateSqlDelightFiles$2.invoke(SqlDelightEnvironment.kt:165)
at app.cash.sqldelight.core.SqlDelightEnvironment$generateSqlDelightFiles$2.invoke(SqlDelightEnvironment.kt:156)
at app.cash.sqldelight.core.SqlDelightEnvironment$forSourceFiles$1.invoke(SqlDelightEnvironment.kt:125)
at app.cash.sqldelight.core.SqlDelightEnvironment$forSourceFiles$1.invoke(SqlDelightEnvironment.kt:120)
at com.alecstrong.sql.psi.core.SqlCoreEnvironment.forSourceFiles$lambda$2(SqlCoreEnvironment.kt:157)
at com.alecstrong.sql.psi.core.CoreFileIndex.iterateContentUnderDirectory(SqlCoreEnvironment.kt:218)
at com.alecstrong.sql.psi.core.CoreFileIndex.iterateContentUnderDirectory(SqlCoreEnvironment.kt:215)
at com.alecstrong.sql.psi.core.CoreFileIndex.iterateContentUnderDirectory(SqlCoreEnvironment.kt:215)
at com.alecstrong.sql.psi.core.CoreFileIndex.iterateContentUnderDirectory(SqlCoreEnvironment.kt:215)
at com.alecstrong.sql.psi.core.CoreFileIndex.iterateContentUnderDirectory(SqlCoreEnvironment.kt:215)
at com.alecstrong.sql.psi.core.CoreFileIndex.iterateContent(SqlCoreEnvironment.kt:209)
at com.alecstrong.sql.psi.core.SqlCoreEnvironment.forSourceFiles(SqlCoreEnvironment.kt:154)
at app.cash.sqldelight.core.SqlDelightEnvironment.forSourceFiles(SqlDelightEnvironment.kt:120)
at app.cash.sqldelight.core.SqlDelightEnvironment.forSqlFileBases(SqlDelightEnvironment.kt:366)
at app.cash.sqldelight.core.SqlDelightEnvironment.generateSqlDelightFiles(SqlDelightEnvironment.kt:156)
at app.cash.sqldelight.gradle.SqlDelightTask$GenerateInterfaces.execute(SqlDelightTask.kt:98)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:63)
at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:54)
at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:48)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100)
at org.gradle.workers.internal.AbstractClassLoaderWorker.executeInClassLoader(AbstractClassLoaderWorker.java:48)
at org.gradle.workers.internal.IsolatedClassloaderWorker.run(IsolatedClassloaderWorker.java:49)
at org.gradle.workers.internal.IsolatedClassloaderWorker.run(IsolatedClassloaderWorker.java:30)
at org.gradle.workers.internal.IsolatedClassloaderWorkerFactory$1.lambda$execute$0(IsolatedClassloaderWorkerFactory.java:57)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:78)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.IsolatedClassloaderWorkerFactory$1.execute(IsolatedClassloaderWorkerFactory.java:49)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:170)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:187)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:120)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:162)
at org.gradle.internal.Factories$1.create(Factories.java:31)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:264)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:128)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:133)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:157)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:126)
... 2 more
Caused by: java.lang.IndexOutOfBoundsException: Index: 0
at app.cash.sqldelight.core.lang.psi.ColumnTypeMixin.type(ColumnTypeMixin.kt:75)
at app.cash.sqldelight.core.compiler.TableInterfaceGenerator.kotlinImplementationSpec(TableInterfaceGenerator.kt:62)
at app.cash.sqldelight.core.compiler.SqlDelightCompiler$writeTableInterfaces$1$fileSpec$1$1.invoke(SqlDelightCompiler.kt:146)
at app.cash.sqldelight.core.compiler.SqlDelightCompiler$writeTableInterfaces$1$fileSpec$1$1.invoke(SqlDelightCompiler.kt:144)
at app.cash.sqldelight.core.compiler.SqlDelightCompilerKt.tryWithElement(SqlDelightCompiler.kt:227)
... 51 more