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 已经有一段时间了 - 事实证明这是隐藏得很好。我开始看到我们如何以 SQL 注入错误告终,感谢 Microsoft。使用原始 ODBC,您可以使用 SQLPrepare 创建一个语句(一次)。通过?对于要填写的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

关于 Pukku 对 ostringstream 的建议的评论:为了使其与语言环境无关,应该明确地 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 函数组之一。

例如

_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 回答