我正试图通过HDBC和ODBC从MSSQL数据库中查询一些数据。然而,当我试图从列名中带有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实例来测试这一点,但HDBC-odbc
中的代码使用UTF-8对查询进行编码。同时,本文档表明,对于现代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"
,然后立即将其重置为""
。