2

私の製品は、コンマが小数点記号であるポルトガルの聴衆を対象としています。私は通常、CString :: Formatを使用して数値を文字列に入力し、コンピューターの地域設定を考慮に入れます。一般的にこれは良いアプローチですが、SQLクエリのフォーマットに問題があります。たとえば、次のようになります。

CString szInsert;
szInsert.Format("INSERT INTO Vertices (X, Y) VALUES (%f, %f)", pt.X, pt.Y);

値が渡されると、間違ったクエリである次の文字列を取得します。

INSERT INTO Vertices (X, Y) VALUES (3,56, 4,67)

地域の設定を変更したり、浮動小数点値ごとに特殊な文字列を作成したりせずに、これらの文字列の小数点記号としてドットを適用するにはどうすればよいですか?

注:これは一般的な質問であり、SQLの質問ではありません。

4

5 に答える 5

10

悪い考えです。本当に準備済みステートメントを使用する必要があります。数値だけで SQL インジェクションを行うのは簡単なことではありませんが、CString::Format はパラメーター バインディングを行う正しい方法ではありません。

(MFC と SQL は久しぶりです - これは非常によく隠されていることがわかりました。Microsoft に感謝します。SQL インジェクションのバグがどのように発生したかがわかり始めています。未加工の ODBC では、SQLPrepare でステートメントを (1 回) 作成します。Pass ?入力する 2 つのパラメーターに対して。その後、各 INSERT 呼び出しに対してSQLBindParameter(stmt, 1, &X); SQLBindParameter(stmt, 2, &Y) /*extra parameters omitted, see http://msdn.microsoft.com/en-us/library/ms710963(VS.85).aspx */。最後に、SQLExecute を呼び出して操作を実行します。)

于 2009-02-03T15:30:47.267 に答える
9

ostringstream を使用した Pukku の提案に関するコメント: これをロケールに依存しないようにするには、ストリームに目的のロケールを明示的に imbue() する必要があります。

std::ostringstream s;
s.imbue(std::locale::classic());
s << "INSERT INTO Vertices (X, Y) VALUES (" << pt.X << ", " << pt.Y << ")";

それ以外の場合は、現在のグローバル ロケールが使用されます。

于 2009-02-03T15:47:39.403 に答える
6

パラメータ化されたクエリは、この問題を完全に回避する必要があります。それらを調べる必要があります。つまり、 setlocaleなどを使用して小数点記号を変更できるはずです。

于 2009-02-03T15:35:33.047 に答える
2

使用する

_create_locale( LC_NUMERIC, "C" )

'英語' (C デフォルト) ロケールを作成し、これを関数の _sprintf_l グループの 1 つに渡します。

例えば

_locale_t locale = _create_locale( LC_NUMERIC, "C" );
_sprintf_l( pszValue, "%f", locale, 3.141 );
_free_locale(locale);

これはスレッドセーフです。ロケールは、値をフォーマットする必要があるたびに作成することを避けるために、静的変数に格納できます。

于 2014-10-06T15:07:26.413 に答える
1

これが私がしたことです。

CString FormatQuery(LPCTSTR pszFormat, ...)
{
    CString szLocale = setlocale(LC_NUMERIC, NULL);
    setlocale(LC_NUMERIC, "English");

    va_list args;
    va_start(args, pszFormat);
    CString szFormatted;
    int nSize = (_vscprintf(pszFormat, args) + 1) * sizeof(char);
    _vsnprintf_s(szFormatted.GetBuffer(nSize), nSize, nSize, pszFormat, args);
    szFormatted.ReleaseBuffer();
    va_end(args);

    setlocale(LC_NUMERIC, szLocale);
    return szFormatted;
}

のように使用する必要がありますsprintf#include <locale.h>それが機能するためには、あなたがしなければなりません。

私は少し頑固なので、準備されたステートメント/パラメーター化されたクエリを使用しませんでした。同様の問題がある場合は、それを行うことをお勧めします。一方、問題が SQL 関連でない場合は、私の回答が役に立ちます。

編集:これはスレッドセーフバージョンです:

CString FormatQuery(LPCTSTR pszFormat, ...)
{
    _locale_t locale = _create_locale(LC_NUMERIC, "English");

    va_list args;
    va_start(args, pszFormat);
    CString szFormatted;
    int nSize = (_vscprintf_l(pszFormat, locale, args) + 1) * sizeof(char);
    _vsnprintf_s_l(szFormatted.GetBuffer(nSize), nSize, nSize, pszFormat, locale, args);
    szFormatted.ReleaseBuffer();
    va_end(args);

    return szFormatted;
}
于 2009-09-29T16:56:42.293 に答える