Skip to content

read_scalar_relations returns labels in wrong order when a covering index exists on the FK column #23

@rafabench

Description

@rafabench

_get_scalar_relation_map (src/read.jl:594) issues a SELECT with no ORDER BY. When the FK column has a covering index, SQLite scans via the index in FK-value order, so the returned vector is shuffled and no longer aligned with source rows in id order.

using PSRDatabase

work_dir = mktempdir()
mig1 = joinpath(work_dir, "migrations", "1"); mkpath(mig1)
write(joinpath(mig1, "up.sql"), """
PRAGMA user_version = 1;
CREATE TABLE Configuration (id INTEGER PRIMARY KEY, label TEXT UNIQUE NOT NULL DEFAULT 'Configuration') STRICT;
CREATE TABLE System (id INTEGER PRIMARY KEY, label TEXT UNIQUE NOT NULL) STRICT;
CREATE TABLE Transmission (
    id INTEGER PRIMARY KEY, label TEXT UNIQUE NOT NULL,
    system_origin_id INTEGER, system_destination_id INTEGER,
    FOREIGN KEY (system_origin_id) REFERENCES System (id) ON UPDATE CASCADE ON DELETE SET NULL,
    FOREIGN KEY (system_destination_id) REFERENCES System (id) ON UPDATE CASCADE ON DELETE SET NULL
) STRICT;
CREATE INDEX idx_origin ON Transmission (system_origin_id);
""")
write(joinpath(mig1, "down.sql"), "DROP TABLE Transmission; DROP TABLE System; DROP TABLE Configuration;")

dbfile = joinpath(work_dir, "study.sqlite")
PSRDatabase.close!(PSRDatabase.create_empty_db_from_migrations(dbfile, joinpath(work_dir, "migrations"); force = true))

using PSRDatabase.SQLite, PSRDatabase.DBInterface
sdb = SQLite.DB(dbfile)
for s in ("SE", "SU", "NE")
    DBInterface.execute(sdb, "INSERT INTO System (label) VALUES (?)", (s,))
end
for (l, o, d) in [("L1", 1, 2), ("L2", 2, 1), ("L3", 1, 3), ("L4", 3, 1)]
    DBInterface.execute(sdb,
        "INSERT INTO Transmission (label, system_origin_id, system_destination_id) VALUES (?,?,?)",
        (l, o, d))
end
DBInterface.close!(sdb)

db = PSRDatabase.load_db(dbfile; read_only = true)
got = PSRDatabase.read_scalar_relations(db, "Transmission", "System", "origin_id")
expected = ["SE", "SU", "SE", "NE"]  # rows L1..L4 origin labels in id order
println("got:      ", got)
println("expected: ", expected)
PSRDatabase.close!(db)

Got:

got:      Any["SE", "SE", "SU", "NE"]
expected: ["SE", "SU", "SE", "NE"]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions