Привязка "unsigned long" (uint64) в инструкции sqlite3? С++
я использовал библиотеку sqlite3, который находится в sqlite.org.
у меня есть некоторые неподписанные длинные, которые я хотел бы сохранить в базе данных. Я не хочу сам создавать запрос и оставлять его открытым для какой-то инъекции (будь то случайно или нет). Таким образом, я использую sqlite_bind_*
функции для "дезинфекции" моих параметров.
проблема в том, что для длинных целых чисел без знака нет типа функции, только целые числа.
int sqlite3_bind_int(sqlite3_stmt*, int, int);
int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
у меня определенно будут номера, которые переполнятся, если я не смогу сохранить их без знака.
мне нужно будет управлять этим самостоятельно? (т. е. приведение к типу без знака после выбора из БД или приведение к типу со знаком перед вставкой в базу данных)
Если мне нужно управлять этим сам, как бы сделать некоторые запросы сравнения, которые хранятся как целое число, когда сравнения действительно должны быть в диапазоне без знака?
смотреть на!--24-->целочисленные типы данных это преобразуется, можно было бы подумать, что неподписанные лонги могут быть представлены без проблем.
Если есть другие решения, пожалуйста, просветите меня! Спасибо!
6 ответов
Если вы хотите сохранить uint64_t в базе данных sqlite и по-прежнему разрешать использовать его в качестве uint64_t в SQL, вам, вероятно, понадобится написать некоторые пользовательские функции.
вам просто нужно привести uint64_t к int64_t при отправке в и из базы данных,а затем написать пользовательскую функцию для выполнения любого сравнения и т. д. тебе нужно. Например, чтобы сделать больше, чем сравнение:
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 );
затем использовать это в В SQL:
SELECT something FROM aTable WHERE UINT_GT(value1,value2);
кроме того, если вам нужны пользовательские параметры сортировки на основе uint64_t, вы должны иметь возможность использовать sqlite3_create_collation аналогичным образом.
это не идеальное решение, так как вам необходимо написать пользовательскую функцию для каждой операции, которую вы хотите сделать, но она должна по крайней мере работать.
база данных SQLite не имеет возможности хранить в ней 64-разрядные целые числа без знака. Это просто ограничение данных.
ваши возможности:
- хранить его как строку, Преобразуя по мере необходимости.
- храните его как двоичный blob, Преобразуя по мере необходимости.
- представьте, что это 64-разрядное целое число со знаком и приведением, преобразуя его по мере необходимости.
- хранить две части информации в виде двух столбцов: 63-разрядное целое число без знака (Нижний 63-бит) и значение, представляющее бит знака.
поскольку это хэши, вы, вероятно, не заботитесь о сравнениях, кроме тестирования равенства. Таким образом, большинство из этих методов будет работать просто отлично для вас.
Я пробовал несколько разных подходов, в основном пытаясь заставить тип столбца работать как sqlite3_uint64, как описано в https://www.sqlite.org/c3ref/int64.html
не повезло, так как uint64 не был сохранен как uint64 в таблице. Когда я посмотрел на сохраненные данные, они были подписаны, поэтому я предположил, что они хранятся как int64.
Я закончил префикс значения с одним символом, чтобы заставить sqlite хранить его как текст без какого-либо преобразования. Было намного проще просто добавить символ в значение запроса select для сравнения. Таким образом, 9223360144090060712 стал A9223360144090060712, и я мог просто выбрать, где HASH = 'A9223360144090060712'
uint32_t
полностью помещается внутри int64_t
без каких-либо забот, так что вы можете сделать простое задание.
int64_t i64;
uint32_t u32 = 32;
i64 = u32;
назначение другим способом вы должны проверить границы int64_t
чтобы любые изменения, внесенные в значение внутри базы данных, были пойманы раньше.
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;
затем вы можете отправить свой int64
в базу данных sqlite, как обычно.
лично я обнаружил, что самый простой способ справиться с этой проблемой, все еще позволяя базе данных выполнять сравнения и т. д. хранить целые числа без знака в базе данных с помощью
это взлом, но int и unsigned имеют одинаковую битовую глубину, поэтому вы могли бы
int i=static_cast<int>(unsigned_int);
и преобразовать его обратно
unsigned unsigned_int=static_cast<unsigned>(i);
чтобы быть в безопасности на вашей plaftform
static_assert(sizeof(int)==sizeof(unsigned));
или используйте ширину specific
#include <stdint.h>
uint32_t
int32_t