-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
INTEGER PRIMARY KEY in SQLite #852
Comments
Is this really an issue ? I just tried and I was able to insert 2^256 in an integer field. SQLite does not really care about types. It would be confusing for users to deserialize what they think is an integer to an i64 though as I'm sure nobody knows about this bug. If you need to retrieve a I Bigint from SQLite, you can use the table macro and say it's a bigint |
It's not an issue for
Yeah, that works. |
I'm a bit torn on what to do here. It's really unfortunate that SQLite requires the type name to be exactly |
Despite SQLite considering BIGINT and INTEGER as synonymous, we have to declare this field as BigInt in order to have greater than 32bits of resolution. See also: diesel-rs/diesel#852
Is there a reason i32 was picked instead of i64? I can store an i32 in a i64 but not the other way around, so using a i64 seems like the obviously better choice. Are there any docs I can read on how to work around this? I'm currently stuck with a number that I need to store but can't. |
I think you can use |
@kpcyrd To quote Sean from the replay literally above yours:
|
My column is not a primary key, should I raise a separate issue for this? For anybody with the same issue, I'm currently editing my
Since this file is auto-generated it is overwritten every time |
I didn't realize that. How does |
I think it's correct that the file is rewritten to pick up possible schema changes, the problem is that I need to edit this file afterwards. Allowing me to overwrite the type for certain fields with a config file might work as a solution. |
Ah, okay. My solution was to not run |
@weiznich I have a primary key and want it to be i64. Your proposed guide mentions the
So after changing the database schema I would still have to manually change the |
Ok, now I understand. First, deactivate the auto-generation of the
Then use the command I can live with that, but I still do not understand how |
@tobx |
@weiznich
How can I make it work on Windows? I followed the guide and did [print_schema]
file = "src/schema.rs"
patch_file = "src/schema.patch" |
I want to propose reopening this. While it is true that most applications using sqlite won't ever have 4 billion rows in a table at a time, sqlite's autoincrement algorithm can and will generate integers above the i32 limit. This means that if you end up with around 2 billion inserts to a table, you'll end up over the i32 limit and something will happen. It would be nice to at least clarify what that something is. This isn't rows in the table, just inserts. You can hit this in a month with a mere 1000 updates per second, so that's kind of rendering schema inference unsuitable for any application with 1000 updates a second. That seems like a pretty low limit. You could hit that just using sqlite to store metrics data or logs or something with a retention policy in a pretty reasonable time frame. For more reasonable sqlite volumes, you can hit it in a year or so, say 100 or 200 updates a second. Your database needn't even go over a few megabytes to make that happen. I understand why you wouldn't want to make the schema inference special, but it's already bad enough to maintain two places on every schema change, and for production applications you appear to literally have no choice but to do so if you don't want to hit the above problem. If there's also an underlying ticking time bomb that's going to fail silently, I strongly suggest that fixing said problem would be worth the special case. This needs to at least fail loudly, otherwise you just get spurious failures that you'd have to spend an afternoon tracking down. |
@camlorn As it is simple to change the corresponding field type in the autogenerated schema later I do not see any reason to change the behavior here. Additionally the CLI tool provides multiple ways to automate such changes for future schema changes, so I really do not see why we should break a lot of already existing code to fix a "special" case. |
Nb. I'm the one who filed this issue. I've come to think that this is actually a bug in As for the use cases for SQLite and whether they need 64-bit surrogate keys or not, I think that's up to the application developers to decide, and not the ORM's choice. Consider that SQLite is actually used in embedded systems. On the other hand, manually updating the generated schema on changes will usually take less time than installing the
It could be done for a 2.0 release, whenever that happens. |
As @camlorn said, a silent failure in a production system would be a good reason to fix this case. I think not everyone should be forced to understand such detail of the ORM just to be sure to run a production system that will not randomly break after a month or a year. To avoid breaking code maybe for now the system could just print out a big warning for this case? |
First of all the type mapping support from diesel for sqlite has been that what we as diesel maintainers have defined by ourself as being reasonable since diesel supports sqlite. That's because in the end types do not really matter for sqlite. From a theoretical point of view we as developer cannot assume that a column defined as So let's assume we only want to "fix" this specific issue here: create table test(id integer primary key autoincrement);
create table test2(id integer primary key); Now let's have a look at the corresponding output:
As you can see both return the same table info. That means we do not have any chance to even infer if a primary key is |
That's a fair reason. Pre-emptively (since others will probably point them out anyway), you can use some heuristics:
Neither of them is perfect (e.g. first one breaks when you rename the table or if it's never had any data), but they would probably cover most of the users. And it only reinforces my point about "declare your column types instead of letting the ORM infer them". But I agree that both of the solutions above are icky and you're not unreasonable if you don't want to implement something like that. |
Just for the sake of completeness:
As already noted that works only for tables that already have entries. I would say that this assumption is not true for a significant amount of tables that are generated via
As written above: that requires parsing sql, because otherwise this will fail as soon as someone has something like the following table: create table test3(text defaut 'primary key autoincrement'); As already stated: It least I do not want to write or maintain a sql parser for sqlites create table statements.
That's definitively a valid strategy. To reiterate this: Diesel explicitly supports this use case, it's at any point possible to write your own |
For anyone else who finds this later and who wants to use schema inference, the solution appears to be as follows: Create a
Then, in your print-schema, add If it's obvious, I missed where it's documented. There's a couple offhand mentions of I now understand that it breaks code to change this (and why), but I'm not too enthused about the silent breakage. I almost missed this point myself. Your autogenerated schema will work fine until it doesn't and until it doesn't is far enough out that it'd be in prod by that point in all likelihood. At the moment, the only warning you get is that i64 doesn't work. Maybe this should be called out somewhere in the documentation? Though beside the point for this issue, "maintain everything yourself" doesn't make Diesel competitive with options in other languages. Checking is a good idea, but going down that road gives manually written sql migrations, manually written |
To call that out at least once explicitly: This will change the mapping for all
As for the location where options to manipulate the generated schema are documented like this are documented, have a look at this guide at the official web page? Otherwise I'm fine with getting a PR extending that documentation to make this more clear.
I mean nobody forces you to use diesel. If you don't like it just use something different or write your own ORM 🤷 . I do not consider it as friendly to call out design decisions because "makes it easier only on the developers of Diesel". I mean we provide this crate in our free time, so maybe recheck your wording. |
I'm not saying that I have a problem with the diesel developers, only that the justification here seems weak and the usability much less than ideal. Not having the resources and developing something for free are indeed good reasons to not do something, but the justification here seems to be that manually maintaining these is fine, and if it's a resource issue then in general I'd have expected someone to say "that's a resource issue". Perhaps they did and I missed it. Not having one authoritative location for configuration in your code is a good way to introduce bugs. But if there's wider discussion to be had, that's probably out of scope for this issue in any case, and regardless I found (and documented) a workaround which at least temporarily reduces the pain points for people who need to use Sqlite. maybe I will revisit this topic in general somewhere else in a month or two after we've finished adopting the Rust stack, when I may perhaps be able to propose concrete action. |
Upvote for re-opening this issue - it's clearly a bug in The fact that Manually maintaining the schema may be an acceptable work-around and the cost of fixing this bug may exceed the benefit. If so, I'd propose a loud warning from |
@curtisleefulton As outlined above: I do not see this issue as actionable, therefore it remains closed as long as noone can point out a solution that is:
I'm happy to read your suggestions how to address these point. Otherwise its discouraged to post on old issues to just repeat what already has been said. I do not consider adding a bolt warning here as a valid solution as I expect that only fraction of our users will ever have more than |
Hello, my first post here so first thank you to the Diesel developers and contributors for this great library. I also ran into this issue. Good discussion and I agree it's a tricky one. I also worked around it via [print_schema]
import_types = ["crate::sqlite_mapping::*"]
file = "src/schema.rs"
// https://github.com/diesel-rs/diesel/issues/852
pub use diesel::sql_types::*;
// This will change the mapping for all Integer columns in your database to i64, not only the PRIMARY KEY AUTOINCREMENT ones.
// Depending on your use case this can be fine or not...
pub type Integer = BigInt; Perhaps it's arguably a bug in SQLIte as it should, instead of, CREATE TABLE items (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
) let you write: CREATE TABLE items (
id BIGINT PRIMARY KEY AUTOINCREMENT NOT NULL
) because in the |
I made a PR to fix this issue : #3940. |
This issue is now fixed. |
Diesel deduces the a column's type as
BigInt
if it's declared asBIGINT
in the database. This is generally fine in SQLite becauseINTEGER
andBIGINT
are synonyms, butINTEGER PRIMARY KEY
is treated differently and is always 64-bit according to https://sqlite.org/autoinc.html. Moreso,BIGINT PRIMARY KEY AUTOINCREMENT
is not accepted.It might be a good idea to detect these columns and use
BigInt
for them. Note that the SQLite documentation says thatINTEGER PRIMARY KEY
is special only for tables that aren't declared withWITHOUT ROWID
, butBIGINT PRIMARY KEY
is still not allowed even when using that.The text was updated successfully, but these errors were encountered: