Search code examples
pythonpython-3.xsqlitepeewee

peewee: Python int too large to convert to SQLite INTEGER


I have the following code:

from peewee import Model, CharField, BigIntegerField, DateTimeField, SqliteDatabase
db = SqliteDatabase('samples.db')

class UnsignedIntegerField(BigIntegerField):
    field_type = 'int unsigned'

class MyBaseModel(Model):
    class Meta:
        database = db

class Sample(MyBaseModel):
    myint = UnsignedIntegerField(index=True)
    description = CharField(default="")


Sample.create_table()

sample = Sample()
sample.description = 'description'
sample.myint = '15235670141346654134'
sample.save()

The code gives me the error mentioned above. After that if I try to insert the values by hand I have no problems with:

insert into sample (description,myint) values('description',15235670141346654134);

This is how the schema appears:

 CREATE TABLE IF NOT EXISTS "sample" ("id" INTEGER NOT NULL PRIMARY KEY, "myint" int unsigned NOT NULL, "description" VARCHAR(255) NOT NULL);
CREATE INDEX "sample_myint" ON "sample" ("myint");

For some reason peewee isn't able to use sqlite's unsigned int. I did try it on cygwin's latest sqlite's drivers. I'm using python3.


Solution

  • Sqlite integers are signed 64-bit values. It does not have any concept of an unsigned type. What it does have is an extremely liberal acceptance of arbitrary strings for column types; CREATE table ex(col fee fie fo fum); is valid. See the documentation for how column types are translated to column affinity and other important details.

    The largest number it can thus hold as an integer is 9223372036854775807, which is smaller than the 15235670141346654134 you're trying to insert. You need to tell your ORM to store it as a string or blob and convert between that and a Python arbitrary-size integer.

    When you do a manual

    insert into sample (description,myint) values('description',15235670141346654134);
    

    and then look at that row in your table, you'll see that that really big number was converted to a floating-point (real) value (Any numeric literal larger than what an integer can hold is treated as one). This is unlikely to be what you want, as it causes data loss.