Skip to content
New issue

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

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

Already on GitHub? # to your account

Foreign key constraint just doesn't work #377

Closed
nullchinchilla opened this issue Jan 28, 2017 · 15 comments
Closed

Foreign key constraint just doesn't work #377

nullchinchilla opened this issue Jan 28, 2017 · 15 comments

Comments

@nullchinchilla
Copy link

nullchinchilla commented Jan 28, 2017

I am probably misunderstanding something, but it appears that foreign key constraints are ignored no matter what I do. Here's an example:

package main

import (
	"database/sql"

	_ "github.com/mattn/go-sqlite3"
)

func main() {
	db, _ := sql.Open("sqlite3", "test.db")
	tx, _ := db.Begin()
	defer tx.Commit()
	tx.Exec("PRAGMA foreign_keys = ON")
	tx.Exec("create table foo (a)")
	tx.Exec("create table bar (a references foo(a))")
	_, err := tx.Exec("insert into bar values ('lol')")
	if err != nil {
		panic(err.Error())
	}
}

Expected result: panic. Actual result: test.db gets created, with the values being inconsistent with the foreign key constraint.

Why is this happening? I even recall using this package before with foreign keys without issue...

@nullchinchilla
Copy link
Author

nullchinchilla commented Jan 28, 2017

In fact, it seems that all PRAGMAs cannot be changed within a transaction. For example, changing the journal_mode also works only with db.Exec and not tx.Exec. If PRAGMA foreign_keys = ON is moved outside the transaction, the program successfully crashes.

Of course, for foreign_keys you have to do it for every transaction...

@gwenn
Copy link

gwenn commented Feb 8, 2017

The documentation says:

This pragma is a no-op within a transaction; foreign key constraint enforcement may only be enabled or disabled when there is no pending BEGIN or SAVEPOINT.

With SQLite shell :

sqlite> begin;
sqlite> PRAGMA foreign_keys = ON;
sqlite> create table foo (a);
sqlite> create table bar (a references foo(a));
sqlite> insert into bar values ('lol');
sqlite> commit;
sqlite> pragma foreign_key_check;
Error: foreign key mismatch - "bar" referencing "foo"

@nullchinchilla
Copy link
Author

I know. But you have to do PRAGMA foreign_keys = ON per connection, but the sql package doesn't expose such an abstraction.

This package used to allow opening files with ?foreign_keys=on to run the pragma per connection, but it seems like the code to handle that has been removed.

@gwenn
Copy link

gwenn commented Feb 17, 2017

Maybe a connection hook will do the job ?

@nullchinchilla
Copy link
Author

That's indeed what I eventually used. However, it would be nice for such a basic feature to be more easily accessible. The old foreign_keys=on thing was great, but I do not know why it was removed.

@gwenn
Copy link

gwenn commented Feb 17, 2017

Are you sure it was removed ?

$ git log -p sqlite3.go | grep 'foreign_keys'
-- no match

@nullchinchilla
Copy link
Author

nullchinchilla commented Feb 17, 2017

#255 (comment) That line no longer exists, and foreign_keys no longer works when I try to use it.

@gwenn
Copy link

gwenn commented Feb 17, 2017

Sorry for the confusion.
The #255 comment was only a suggestion for a patch (which has been ignored)...

@nullchinchilla
Copy link
Author

Perhaps it should be added and documented then? Having to use a connection hook to do things as basic as turning on foreign keys support is rather annoying.

@mattn
Copy link
Owner

mattn commented Feb 18, 2017

Well, I'm thinking it's possible to do with hook. But if many people want this feature, I'll add this.

zombiezen added a commit to zombiezen/go-sqlite3 that referenced this issue Apr 1, 2017
zombiezen added a commit to zombiezen/go-sqlite3 that referenced this issue Apr 1, 2017
@mattn mattn closed this as completed in #407 Apr 2, 2017
@maharasheed
Copy link

maharasheed commented Apr 13, 2019

So now to enforce foreign key constrains, we can only do this:
db, err := sql.Open("sqlite3", "my.db?foreign_keys=on")

@nbedos
Copy link

nbedos commented Aug 15, 2019

@maharasheed The connection parameter is _foreign_keys (with a leading underscore).

db, err := sql.Open("sqlite3", "my.db?_foreign_keys=on")

@ManishaDutt01
Copy link

I have tried everything but still i am getting foreign key error . There are my two tables
CREATE TABLE IF NOT EXISTS bag (owner CHAR(32) PRIMARY KEY, uploader CHAR(32) NOT NULL UNIQUE, downloader CHAR(32) NOT NULL UNIQUE)
"CREATE TABLE IF NOT EXISTS uploader_session(uploader CHAR(32) NOT NULL,session_id CHAR(32) NOT NULL primary key,start_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,FOREIGN KEY fk_uploader_session (uploader) REFERENCES bag(uploader) )"

error: err:"near "fk_uploader_session": syntax error"

@rittneje
Copy link
Collaborator

rittneje commented Apr 2, 2020

@ManishaDutt01 Your syntax is invalid. See https://www.sqlite.org/lang_createtable.html It would be CONSTRAINT fk_uploader_session FOREIGN KEY (uploader) REFERENCES bag(uploader).

@ManishaDutt01
Copy link

@rittneje Thanks understood

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants