sqldelight icon indicating copy to clipboard operation
sqldelight copied to clipboard

Foreign Key's Implicit Parent Columns Cause Error

Open gecko10000 opened this issue 1 year ago • 0 comments

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

gecko10000 avatar Dec 31 '23 01:12 gecko10000