Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sqlite3 'row value misused' error when preloading a model with composite primary keys and foreign key relations #3585

Open
RobRoyd opened this issue Oct 8, 2020 · 13 comments
Assignees
Labels
in progress type:question general questions type:with reproduction steps with reproduction steps

Comments

@RobRoyd
Copy link

RobRoyd commented Oct 8, 2020

GORM Playground Link

go-gorm/playground#168

Description

There is an issue when loading a model with composite primary keys from a sqlite3 database where the .Take() after a .Preload() will result in a sqlite3 row value misued error.

The following model (which is used in the playground link, too) can create the issue.

type (
	// Root is the root table with an autoincrement id
	// it references Branch by branch's composite primary key
	Root struct {
		ID       uint64    `gorm:"primaryKey;autoIncrement"`
		Branches []*Branch `gorm:"foreignKey:RootId;constraint:OnUpdate:RESTRICT,OnDelete:CASCADE;"`
	}

	// Branch is has a composite primary key derived from the ID of its Root and its own Name
	// it references Leaf by leaf's composite primary key
	Branch struct {
		RootId uint64  `gorm:"primaryKey"`
		Name   string  `gorm:"primaryKey;size:100"`
		Leaves []*Leaf `gorm:"foreignKey:RootId,BranchName;constraint:OnUpdate:RESTRICT,OnDelete:CASCADE;"`
	}

	// Leaf is has a composite primary key derived from the ID of its Root, Name of its Branch and its own Name
	// it does not reference anything
	Leaf struct {
		RootId     uint64 `gorm:"primaryKey"`
		BranchName string `gorm:"primaryKey;size:100"`
		Name       string `gorm:"primaryKey;size:100"`
	}
)

Basically when having a model composed of one root (ID=1) with two branches (b1 and b2) and a leaf on each branch the query to load the leaves in a preload is created as this:

SELECT * FROM `leafs` WHERE (`leafs`.`root_id`,`leafs`.`branch_name`) IN ((1,"b1"),(1,"b2"))

From my understanding, the tuples in the IN clause cause the issue, as the used sqlite3 database does not seem to handle this.
The question is if the query could be build like the following, because this works with the used sqlite3 database, too.

SELECT * FROM `leafs` WHERE (`leafs`.`root_id`,`leafs`.`branch_name`) IN (VALUES (1,"b1"),(1,"b2"));

or

SELECT * FROM `leafs` WHERE (`leafs`.`root_id`) IN (1,1) AND (`leafs`.`branch_name`) IN ("b1","b2");

I verified however, that the above query will work for a MariaDB, so I guess this issue is related to sqlite3 only.

@fwielstra
Copy link

This was 'just' a warning, but I recently updated my dependencies (gorm.io/driver/sqlite from v1.1.3 to v1.1.4 and gorm.io/gorm from v1.20.6 to v1.20.9) and it has caused one of my tests to fail because instead of a warning it now returns an error.

I narrowed it down to gorm v1.20.8; it remains a warning at v1.20.7, so it must have changed somewhere in these commits: v1.20.7...v1.20.8

@jinzhu
Copy link
Member

jinzhu commented Jan 5, 2021

It should not work before @fwielstra

@RobRoyd
Copy link
Author

RobRoyd commented Jan 12, 2021

How is the progress on this issue? Will it be fixed or is it a no fix?

@codemicro
Copy link

codemicro commented Jan 16, 2021

I'm also seeing this with GORM versions 1.20.7 and 1.20.11 and the SQLite driver versions 1.1.4 and 1.1.6, again with a composite key. This time it was as a result of a call to Delete, though, not because of preloading.

// DELETE FROM `user_bios` WHERE (`user_bios`.`user_id`,`user_bios`.`mem_id`) IN (("[...]","[...]"))

type UserBio struct {
	UserId string `gorm:"primarykey"`
	MemId  string `gorm:"primarykey"`
}

For anyone looking for a workaround, check out db.Exec.

@Z-M-Huang
Copy link

I've encountered the same for SQLite. This actually breaks some of my test cases for structs having composite keys.

codemicro added a commit to codemicro/lgballtDiscordBot that referenced this issue Jan 20, 2021
@foxcpp
Copy link

foxcpp commented Jan 31, 2021

Facing the same issue (using Preload)

The generated SQL in my case is:

SELECT * FROM `comments` WHERE `comments`.`group_id`,`comments`.`post_id` IN ((XXXX,YYYY));

The problematic part is ((XXXX,YYYY)).

Quoting https://www.sqlite.org/rowvalue.html:

For a row-value IN operator, the left-hand side (hereafter "LHS") can be either a parenthesized list of values or a subquery with multiple columns. But the right-hand side (hereafter "RHS") must be a subquery expression.

@foxcpp
Copy link

foxcpp commented Jan 31, 2021

It seems like the only way to make it work for SQLite is to generate a SELECT subexpression using SELECT ... UNION. This works correctly.

@RobRoyd
Copy link
Author

RobRoyd commented Feb 16, 2021

Can confirm. After updating gorm and the driver to latest, more tests are not running.
It seems, it is because of tables containing composite keys. Before it was only when preloading, now it is on delete, create and update, too.

@JonathonReinhart
Copy link

Just in case anyone ends up here for the same reason I did, it seems that the use of net.IP fields with the sqlite driver does not work: go-gorm/sqlite#36

@antoninbas
Copy link

Just wanted to bump this issue as the problem still seems to exist with the latest Gorm version

@choyri
Copy link

choyri commented Nov 25, 2021

I just wanted to use SQLite for unittest in CICD, but unfortunately, I encountered this error, so I had to continue to use MySQL 😢

@ToughK
Copy link

ToughK commented Oct 20, 2023

Any updates on this problem? I still get the same problem with the latest Gorm version

@LubosD
Copy link

LubosD commented May 31, 2024

I've hit the same problem. Tried to find out if it could be easily remedied via the Dialector, but the code that builds this doesn't use it.

I think it really deserves to be fixed, because I think the "IN with multiple columns" example on GORM's homepage cannot work in SQLite this way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in progress type:question general questions type:with reproduction steps with reproduction steps
Projects
None yet
Development

No branches or pull requests