18

sqlite.orgで入手できるsqlite3ライブラリを使用しています。

データベースに保存したい署名されていないlongがいくつかあります。自分でクエリを作成して、何らかの注入(偶発的かどうかに関係なく)を可能にしておきたくありません。したがって、私はsqlite_bind_*関数を使用してパラメーターを「サニタイズ」しています。

問題は、符号なし長整数の関数型がなく、整数だけであるということです。

int sqlite3_bind_int(sqlite3_stmt*, int, int);

int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);

署名なしで保存できない場合は、間違いなくオーバーフローする番号があります。

これを自分で管理する必要がありますか?(つまり、データベースから選択した後に符号なし型にキャストするか、データベースに挿入する前に符号付き型にキャストします)

これを自分で管理する必要がある場合、比較が実際には符号なしの範囲にあることを意図しているときに、符号付き長整数として格納されているいくつかの比較クエリをどのように実行しますか?

変換されるINTEGERデータ型を見ると、unsignedlongsは問題なく表現できると思います。

他に利用できる解決策がある場合は、私に教えてください!ありがとう!

4

6 に答える 6

14

SQLiteデータベースには、符号なし64ビット整数を格納する機能がありません。これはデータの制限にすぎません。

オプションは次のとおりです。

  • 文字列として保存し、必要に応じて変換します。
  • 必要に応じて変換しながら、バイナリブロブとして保存します。
  • キャスト付きの符号付き64ビット整数であると偽って、必要に応じて変換します。
  • 2つの情報を2つの列として格納します。符号なし63ビット整数(下位63ビット)と、上位ビットを表す値です。

これらはハッシュであるため、同等性テスト以外の比較についてはおそらく気にしないでしょう。したがって、これらの方法のほとんどは問題なく機能します。

于 2011-12-14T04:38:22.350 に答える
10

uint64_tをsqliteデータベースに保存し、それをSQLでuint64_tとして使用できるようにする場合は、おそらくいくつかのカスタム関数を作成する必要があります。

データベースとの間で送受信するときに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_collat​​ionを使用できるはずです。

実行するすべての操作に対してカスタム関数を作成する必要があるため、これは完全なソリューションではありませんが、少なくとも機能するはずです。

于 2011-12-14T10:56:13.807 に答える
1

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データベースに送信できます。

于 2011-12-13T23:20:57.130 に答える
1

https://www.sqlite.org/c3ref/int64.htmlで説明されているように、主に列タイプをsqlite3_uint64として機能させることを試みて、さまざまなアプローチを試しました。

uint64がテーブルにuint64として格納されていなかったため、運がありませんでした。保存されたデータを見ると署名されていたので、int64として保存されていると思いました。

変換を行わずにsqliteにテキストとして保存させるために、値の前に1つの文字を付けることになりました。比較のためにselectクエリ値にcharを追加する方がはるかに簡単でした。したがって、9223360144090060712はA9223360144090060712になり、SELECT WHERE HASH='A9223360144090060712'を実行するだけで済みます。

于 2015-09-08T13:56:36.883 に答える
-1

これはハックですが、intとunsignedのビット深度は同じであるため、次のことができます。

int i=static_cast<int>(unsigned_int);

そしてそれを元に戻します

unsigned unsigned_int=static_cast<unsigned>(i);

あなたのプラットフォームの安全側にいること

static_assert(sizeof(int)==sizeof(unsigned));

または特定の幅を使用します

#include <stdint.h>
uint32_t
int32_t 
于 2011-12-13T21:58:58.333 に答える
-1

個人的には、データベースに比較などを実行させながらこの問題に対処する最も簡単な方法は、sqlite3_bind_int64関数を使用して符号なし整数をデータベースに格納することです。私はあなたが32ビットの符号なし整数を使用していると仮定しています。これは64ビットの符号付き整数に簡単に格納できます。

例えば:

uint32_t x = 0xFFFFFFFF;
sqlite3_bind_int64( stmt, 1, x );

次に、変数を取得します(boostを使用していると仮定します。そうでない場合は、独自のオーバーフローチェックコードを作成する必要があります)。

 #include <boost/numeric/conversion/cast.hpp>
 ...
 uint32_t x = boost::numeric_cast< uint32_t >( sqlite3_column_int64( stmt, 0 ) );

もちろん、署名されていないint64を保存したい場合、これは崩壊しますが、それはsqliteの少しの制限です。

于 2011-12-13T22:05:46.800 に答える