Haskell Имя столбца Unicode в ODBC - PullRequest
3 голосов
/ 10 марта 2020

Я пытаюсь запросить некоторые данные из базы данных MS SQL через HDB C и ODB C. Однако я столкнулся с проблемой при попытке запросить данные из таблицы с юникодом в именах столбцов.

Рассмотрим следующее 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 не является допустимым именем столбца.

Мои исследования в основном привели к результаты о юникоде в параметрах запроса. Я попытался использовать строки байтов вместо обычных строк, но поскольку аргумент для QuickQuery' - это строка, которая не помогла.

1 Ответ

0 голосов
/ 11 марта 2020

У меня нет экземпляра MS SQL для проверки этого, но код в HDBC-odbc кодирует запрос с использованием UTF-8. Между тем, эта документация предполагает, что для современных драйверов ODB C набор символов, используемый для запросов, зависит от локали процесса во время инициализации драйвера. Если это "C", что является обычным процессом по умолчанию, то драйвер будет использовать набор символов UTF-8. Однако, если процесс выполняется:

setlocale(LC_ALL,"")

перед инициализацией драйвера, и текущий языковой стандарт Windows, скажем, Engli sh с использованием кодовой страницы Latin-1 1252, тогда ODB C драйвер будет ожидать запросов в кодировке Latin-1. К сожалению для вас, GH C runtime выполняет run setlocale(LC_ALL,""), так что это, вероятно, что-то не так.

Если вы сбросите локаль на "C" в начале "main", это может решить проблему:

{-# 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" перед инициализацией драйвера, а затем сразу же сбросить его на "".

...