I'm looking to store GUIDs in my SQLite database, using C# and python clients.
Creating a database, and inserting a row, storing the GUID as a string:
conn = sqlite3.connect(filename)
c = conn.cursor()
# Create the table. Yes, I know GUID isn't a real SQLite datatype.
c.execute('CREATE TABLE test (guid GUID PRIMARY KEY, name text)')
u = uuid.uuid4()
print u
t = (str(u), 'foo')
c.execute('INSERT INTO test VALUES (?,?)', t)
conn.commit()
conn.close()
Fetching:
# ...
c.execute('SELECT * FROM test WHERE guid = "c1332103-6031-4ff7-b610-f8f3b940fa66"')
print c.fetchone()
This all works perfectly. Using the default Python __str__
representation of the UUID works well.
C:\Users\Jonathon>makedb.py test.db
c1332103-6031-4ff7-b610-f8f3b940fa66
C:\Users\Jonathon>opendb.py test.db
(u'c1332103-6031-4ff7-b610-f8f3b940fa66', u'foo')
My doubts arise from using SQLite Expert. It appears that SQLite Expert is happy with my GUID datatype declaration:
But, if I edit a row:
it seems that it changes the datatype! My SELECT
from before yields None
, and if I SELECT *
, I see that it is no longer a simple unicode string:
C:\Users\Jonathon>opendb.py test.db
(<read-write buffer ptr 0x02239520, size 16 at 0x02239500>, u'foo')
Looking at the data on disk, you can see that the GUID is stored in binary, after SQLite Expert touches it:
Before - the GUID is ASCII text:
After - the previous data is garbage, and a binary version of the GUID exists:
So what is the "correct" way to store GUIDs in SQLite, specifically using Python? Later, I will have C# code interacting with this as well, and want to make sure I'm going things the "right" way.
One can essentially add support for GUID datatypes to sqlite3 in Python. You can register conversion functions:
register_converter()
: convert SQLite types to Python typesregister_adapter()
: convert Python types to SQLite typesTo use these, you need to pass an argument for the detect_types
parameter of connect()
.
Example:
import sqlite3
import uuid
sqlite3.register_converter('GUID', lambda b: uuid.UUID(bytes_le=b))
sqlite3.register_adapter(uuid.UUID, lambda u: buffer(u.bytes_le))
conn = sqlite3.connect('test.db', detect_types=sqlite3.PARSE_DECLTYPES)
c = conn.cursor()
c.execute('CREATE TABLE test (guid GUID PRIMARY KEY, name TEXT)')
data = (uuid.uuid4(), 'foo')
print 'Input Data:', data
c.execute('INSERT INTO test VALUES (?,?)', data)
c.execute('SELECT * FROM test')
print 'Result Data:', c.fetchone()
Output:
Input Data: (UUID('59cc2646-8666-4fb3-9f57-fe76e22603c0'), 'foo')
Result Data: (UUID('59cc2646-8666-4fb3-9f57-fe76e22603c0'), u'foo')
Results:
uuid.UUID
objects directly to execute()
. The adapter lambda u: buffer(u.bytes)
tells sqlite3 how to convert those to a buffer
(which translates to an X'ABCD....'
blob in SQLite.fectchone()
is returning uuid.UUID
objects directly. The converter lambda u: buffer(u.bytes)
tells sqlite3 how to create those from a byte array when it encounters a declared type of GUID
.Your GUID is a string. Declare it as a VARCHAR or CHAR and it will pick up the text affinity correctly. As GUID is not a type the field has no type affinity, and thus will have the datatype of NONE.
This is described here: http://www.sqlite.org/datatype3.html
There is also a brief discussion of someone trying to use a Guid within SQLite Expert on their support forum here: http://sqliteexpert.com/forum/YaBB.pl?num=1368018774/0
Support talks about the mapping system and how to change a mapping, as well as the tool defaulting to the use of a Blob.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With