2011-10-04 10 views
5

これは初心者の質問かもしれませんが、私はバッファオーバーフローを避けたいです。私は非常にレジストリからSQLデータベースにアップロードされるデータを読みます。私はループ内のデータを読み取り、データは各ループの後に挿入されました。私の問題は、このように、もし私が20のキーを読んで、その下の値が(各コンピュータのキーの数が違う)なら、SQLデータベースに20回接続しなければならないということです。巨大な文字列を正しく扱うには?

しかし、ストアドプロシージャを作成してデータ全体を渡す方法があることがわかったので、SQLサーバーはデータを処理し、SQLサーバーに一度だけ接続する必要があります。

残念ながら、バッファーのような予期しないエラーを避けるために、このような大きな文字列を処理する方法はわかりません。だから私の質問はどのように私はこの文字列を宣言する必要がありますか?

ちょうどchar string[ 15000 ];のような文字列を作成し、値を連結する必要がありますか?またはこれを行うための簡単な方法はありますか?

ありがとうございます!

+6

私たちは、あなたが、CまたはC++を使用しているプログラミング言語を知っていた場合、それが役立つだろう –

+0

@Rob:。私はCを使用していますが、誰かがC++の例を示している場合、私はあまりにも – kampi

+4

なぜだけではなく、それを使用することができます1つの接続で複数の挿入クエリを実行するのですか? – Dmitri

答えて

2

STL文字列は、記述した方法よりもはるかに優れた処理を行う必要があります。

また、いくつかのしきい値を作成する必要があります。たとえば、文字列がメガバイトを超えると、トランザクションが長すぎるため、異なるSQL接続を検討する価値があります。

+1

また、標準のC++ライブラリ文字列はCではなくC++のみであることに注意してください.C++実装に付属するライブラリは標準C++ライブラリであり、STLではありません。 –

+0

Mooing Duck:少なくともこの( 'std :: string')の場合、potatopotàto。 'STL'は、もともとSTLとして知られていたC++標準ライブラリのその部分を参照するために明白に使用され、後で標準ライブラリに組み込まれます。 – rubenvb

0

これをCで正しく実行するには、mallocまたは同等のオペレーティングシステムのいずれかを使用して、メモリを動的に割り当てる必要があります。ここでのアイデアは、実際に必要なメモリ量を把握し、正しい量を割り当てることです。レジストリ関数は、読み取りごとに必要なメモリ量を決定するさまざまな方法を提供します。

複数の値を読み込んで連結している場合は、少し難解です。 1つのアプローチは、別々に割り当てられたメモリブロックに各値を読み込み、それらをすべて取得した後に新しいメモリブロックに連結することです。

しかし、これほど多くのトラブルに行く必要はないかもしれません。 "データがXバイト以上の場合、プログラムは失敗します"と言うことができる場合は、提案するようにスタティックバッファを作成することができます。バッファの残りの部分に正しいサイズのレジストリおよび/または文字列連結関数を指定し、エラーがないかどうかを確認して、失敗した場合はクラッシュせずに正しく失敗するようにしてください。

もう1つの注記:char buf[15000];は、プログラムスコープ内であればOKですが、関数に表示される場合はstatic指定子を追加する必要があります。関数内の暗黙的に割り当てられたメモリは、デフォルトでスタックから取得されるため、大きな割り当てが失敗し、プログラムがクラッシュする可能性があります。 (フィフティーン千バイトはOKでなければなりませんが、に入るために良い習慣ではありません。)

また、あなたのバッファのサイズのためのマクロを定義することが好ましく、それを一貫して使用します。

#define BUFFER_SIZE 15000 
char buf[BUFFER_SIZE]; 

1つの行を変更することで、後でバッファのサイズを簡単に増やすことができます。

+0

あなたの答えを少し編集しました。マクロ名は、従来からすべてが大文字ですので、目立つようになりました。また、 'string'はオブジェクトの名前としてはあまりよくありません。私はそれを 'buf'に変更しました。 –

+0

@Keith、私は文字列[]を使用しました。なぜなら、それはOPが彼の質問で使ったものでしたが、それは本当に問題ではありません。小文字のマクロ名をキャッチしてくれてありがとう、私はまだ半分眠っているに違いない。 –

0

レジストリから(キー、値)のペアを読み取り、そこに十分なスペースがある間にプリアロケートされたバッファに格納することができます。 バッファ内に「書き込み」位置を維持します。バッファーに新しいキー、値のペアのための十分なスペースがあるかどうかをチェックするために使用することができます。 新しい(キー、値)ペアにスペースが残っていない場合、ストアドプロシージャを実行し、バッファ内の "書き込み"位置をリセットします。 "read key、value pairs"の最後にループチェックバッファの「書き込み」位置があり、0より大きい場合はストアドプロシージャを実行します。 このようにすると、サーバー上でストアドプロシージャを実行する回数が最小限に抑えられます。

const int MAX_BUFFER_SIZE = 15000; 
char buffer[MAX_BUFFER_SIZE]; 
char buffer_pos = 0; // "write" position within the buffer. 

... 

// Retrieve key, value pairs and push them into the buffer. 
while(get_next_key_value(key, value)) { 
    post(key, value); 
} 

// Execute stored procedure if buffer is not empty. 
if(buffer_pos > 0) { 
    exec_stored_procedure(buffer); 
} 
... 

bool post(const char* key, const char* value) 
{ 
    int len = strlen(key) + strlen(value) + <length of separators>; 

    // Execute stored procedure if there is no space for new key/value pair. 
    if(len + buffer_pos >= MAX_BUFFER_SIZE) { 
    exec_stored_procedure(buffer); 
    buffer_pos = 0; // Reset "write" position. 
    } 

    // Copy key, value pair to the buffer if there is sufficient space. 
    if(len + buffer_pos < MAX_BUFFER_SIZE) { 
    <copy key, value to the buffer, starting from "write" position> 
    buffer_pos += len; // Adjust "write" position. 
    return true; 
    } 
    else { 
    return false; 
    } 
} 

bool exec_stored_procedure(const char* buf) 
{ 
    <connect to SQL database and execute stored procedure.> 
} 
関連する問題