我的产品面向葡萄牙观众,逗号为十进制符号。我通常使用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问题。
答案 0 :(得分: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来执行操作。)
答案 1 :(得分:9)
关于使用ostringstream的Pukku建议的评论:为了使这个独立于语言环境,人们应该明确地使用所需的语言环境灌输():
std::ostringstream s;
s.imbue(std::locale::classic());
s << "INSERT INTO Vertices (X, Y) VALUES (" << pt.X << ", " << pt.Y << ")";
否则,使用当前的全局语言环境。
答案 2 :(得分:6)
参数化查询应该完全避免这个问题。你应该研究那些。也就是说,您应该能够使用setlocale或类似的更改小数分隔符。
答案 3 :(得分: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;
}
答案 4 :(得分:1)
使用
_create_locale( LC_NUMERIC, "C" )
创建一个&#39;英语&#39; (默认为C语言环境),然后将其传递给_sprintf_l函数组之一。
e.g。
_locale_t locale = _create_locale( LC_NUMERIC, "C" );
_sprintf_l( pszValue, "%f", locale, 3.141 );
_free_locale(locale);
这是线程安全的。语言环境可以存储在静态变量中,以避免每次需要格式化值时创建它。