我正在尝试通过 HDBC 从 MSSQL 数据库查询一些数据和 ODBC 。然而,当我尝试从列名称中包含 unicode 的表中查询数据时,我遇到了问题。
考虑以下 MWE:
mwe :: IConnection conn => conn -> IO [[SqlValue]]
mwe conn =
do r <- quickQuery' conn
"SELECT [Højde] FROM [Table]"
[]
return r
当执行上述代码并将其传递给数据库的连接对象时,我收到以下错误消息:
*** Exception: SqlError {seState = "[\"42S22\",\"42000\"]", seNativeError = -1, seErrorMsg = "execute execute: [\"207: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Invalid column name 'H\\195\\184jde'.\",\"8180: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Statement(s) could not be prepared.\"]"}
相关部分很可能是 H\\195\\184jde
不是有效的列名称。
我的研究主要得出了有关查询参数中 unicode 的结果。我尝试使用字节串而不是普通字符串,但由于 QuickQuery'
的参数是一个没有帮助的字符串。
最佳答案
我没有 MS SQL 实例来测试这一点,但是 code HDBC-odbc
使用 UTF-8 对查询进行编码。同时,this documentation建议对于现代 ODBC 驱动程序,用于查询的字符集取决于驱动程序初始化时的进程区域设置。如果它是 "C"
(这是通常的进程默认值),则驱动程序将使用 UTF-8 字符集。但是,如果该进程执行:
setlocale(LC_ALL,"")
在初始化驱动程序之前,并且当前的 Windows 区域设置是使用 Latin-1 1252 代码页的英语,那么 ODBC 驱动程序将需要 Latin-1 编码的查询。不幸的是,GHC 运行时确实运行 setlocale(LC_ALL,"")
,所以这可能就是出了问题的地方。
如果您在 “main”
开头将语言环境重置为 “C”
,则可能会解决该问题:
{-# LANGUAGE ForeignFunctionInterface #-}
import Control.Monad
import Foreign.C
import Foreign.Ptr
foreign import ccall "locale.h setlocale" c_setlocale :: CInt -> CString -> IO CString
setCLocale :: IO ()
setCLocale = do
rc <- withCString "C" $ c_setlocale 0
when (rc == nullPtr) $ error "setCLocale failed"
main = do
setCLocale
print "whatever"
我不确定这是否会导致其他问题(例如,终端输入/输出)。如果是这样,您可以在初始化驱动程序之前将区域设置设置为 "C"
,然后立即将其重置为 ""
。
关于ODBC 中的 Haskell Unicode 列名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60617566/