Search code examples
c++sqlitebindunsigned-integer

Binding an 'unsigned long' (uint64) in an sqlite3 statement? C++


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!


Solution

  • 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.