I'm using the sqlite3 library that is available at sqlite.org.
I have some unsigned longs that I would like store in a database. I do not want to construct the query myself and leave it open to some sort of injection (whether it be accidental or not). Thus, I'm using the sqlite_bind_*
functions to 'sanitize' my parameters.
The issue is that there isn't a function type for unsigned long integers, just integers.
int sqlite3_bind_int(sqlite3_stmt*, int, int);
int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
I am definitely going to have numbers that will overflow if I am unable to store them in an unsigned manner.
Am I going to need to manage this myself? (i.e. casting to an unsigned type after selecting from the db or casting to signed type before inserting into database)
If I do have to manage this myself, how would one do some comparison queries that are stored as a signed long integer when the comparisons are really meant to be in the unsigned range?
Looking at the INTEGER datatypes that get converted, one would think that unsigned longs could be represented without issue.
If there are other solutions available, please enlighten me! Thanks!
In 32-bit mode, the compiler (more precisely the <stdint. h> header) defines uint64_t as unsigned long long , because unsigned long isn't wide enough. In 64-bit mode, it defines uint64_t as unsigned long . It could have defined it as unsigned long long in both modes.
Usually, SQLite allows at most one writer to proceed concurrently. The BEGIN CONCURRENT enhancement allows multiple writers to process write transactions simultanously if the database is in "wal" or "wal2" mode, although the system still serializes COMMIT commands.
SQLite does support multiple concurrent connections, and therefore it can be used with a multi-threaded or multi-process application. The catch is that when SQLite opens a write transaction, it will lock all the tables.
The UInt64 value type represents unsigned integers with values ranging from 0 to 18,446,744,073,709,551,615. Important. The UInt64 type is not CLS-compliant. The CLS-compliant alternative type is Decimal. Int64 can be used instead to replace a UInt64 value that ranges from zero to MaxValue.
An SQLite database does not have the ability to store unsigned 64-bit integers in it. It's just a limitation of the data.
Your options are:
Since these are hashes, you probably don't care about comparisons other than equality testing. So most of these methods would work just fine for you.
If you wanted to store a uint64_t in a sqlite database and still allow it to be used as a uint64_t in SQL, then you're probably going to need to write some custom functions.
You simply need to cast the uint64_t to an int64_t when sending to and from the database, and then write a custom function to perform whatever comparison etc. you need. For example, to do a greater than comparison:
void greaterThan( sqlite3_context* ctx, sqlite3_value** values )
{
uint64_t value1 = boost::numeric_cast< uint64_t >( sqlite3_value_int64( value[ 0 ] ) );
uint64_t value2 = boost::numeric_cast< uint64_t >( sqlite3_value_int64( value[ 1 ] ) );
sqlite3_result_int( ctx, value1 > value2 );
}
//Register this function using sqlite3_create_function
sqlite3_create_function( db, "UINT_GT", 2, SQLITE3_ANY, NULL, &greaterThan, NULL, NULL );
Then to use this in SQL:
SELECT something FROM aTable WHERE UINT_GT(value1,value2);
Alternatively, if you need custom collation based on uint64_t, you should be able to use sqlite3_create_collation in a similar manner.
It's not a perfect solution as you'll need to write a custom function for every operation you want to do, but it should at least work.
uint32_t
fits entirely inside of a int64_t
without any worries, so you can do a simple assignment.
int64_t i64;
uint32_t u32 = 32;
i64 = u32;
Assigning the other way you should check the bounds of the int64_t
so that any changes made to the value inside of the database are caught early.
int64_t i64 = 32;
uint32_t u32;
if (i64 < 0 || i64 > std::numeric_limits<uint32_t>::max())
throw std::runtime_error("invalid uint32_t");
u32 = i64;
You can then send your int64
to the sqlite database as you normally would.
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