sqlcli-odbc 0.1.0.1 → 0.2.0.0
raw patch · 3 files changed
+530/−13 lines, 3 filesdep +loggingdep ~sqlcli
Dependencies added: logging
Dependency ranges changed: sqlcli
Files
- sqlcli-odbc.cabal +3/−2
- src/SQL/CLI/ODBC.hs +34/−10
- src/SQL/ODBC.hs +493/−1
sqlcli-odbc.cabal view
@@ -1,5 +1,5 @@ name: sqlcli-odbc-version: 0.1.0.1+version: 0.2.0.0 synopsis: Specific ODBC definitions to be used by SQL CLI clients. description: You should use this package if you intend to use sqlcli package to connect to ODBC datasources.@@ -19,7 +19,8 @@ exposed-modules: SQL.ODBC, SQL.CLI.ODBC build-depends: base >= 4.7 && < 5,- sqlcli >= 0.1 && < 0.2+ logging >= 3.0 && < 4,+ sqlcli >= 0.2 && < 0.3 default-language: Haskell2010 source-repository head
src/SQL/CLI/ODBC.hs view
@@ -1,17 +1,27 @@ module SQL.CLI.ODBC where -import Prelude hiding (fail) +import Prelude hiding (fail, log) +import Control.Logging (log) + import Control.Monad.IO.Class (MonadIO, liftIO) import Control.Monad.Fail (MonadFail, fail) +import Data.String (fromString) + import System.IO (hPutStrLn, stderr) import Foreign.Ptr (wordPtrToPtr) -import SQL.ODBC (sql_attr_odbc_version, sql_ov_odbc3) -import SQL.CLI (SQLHENV, sqlsetenvattr, sql_handle_env, sql_null_handle, sql_success, sql_success_with_info, sql_invalid_handle, sql_error) -import SQL.CLI.Utils (SQLConfig(SQLConfig), allocHandle, displayDiagInfo) +import SQL.ODBC (sql_attr_odbc_version, + sql_ov_odbc3, + sql_longvarchar, + sql_binary, + sql_longvarbinary, + sql_varbinary, + sql_interval) +import SQL.CLI (SQLHENV, SQLSMALLINT, sqlsetenvattr, sql_handle_env, sql_null_handle, sql_success, sql_success_with_info, sql_invalid_handle, sql_error, sql_char) +import SQL.CLI.Utils (SQLConfig(SQLConfig), allocHandle, displayDiagInfo, toCLIType) -- | holds information specific to ODBC implementation odbcImplementation :: SQLConfig @@ -22,24 +32,38 @@ -- or setting the environment failed; it requires ODBC 3 implementation setupEnv :: (MonadIO m, MonadFail m) => m SQLHENV setupEnv = do - liftIO $ hPutStrLn stderr "alloc env handle" + liftIO $ log $ fromString "alloc env handle" henv <- allocHandle sql_handle_env sql_null_handle - liftIO $ hPutStrLn stderr "odbc specific - set odbc version env attr" + liftIO $ log $ fromString $ "allocated environment handle: " ++ (show henv) + liftIO $ log $ fromString "odbc specific - set odbc version env attr" resultSetEnvOV <- liftIO $ sqlsetenvattr henv sql_attr_odbc_version (wordPtrToPtr $ fromIntegral sql_ov_odbc3) 0 case resultSetEnvOV of x | x == sql_success -> return henv | x == sql_success_with_info -> do liftIO $ do - hPutStrLn stderr "Set ODBC version generated warnings" + log $ fromString "Set ODBC version generated warnings" displayDiagInfo sql_handle_env henv return henv | x == sql_invalid_handle -> do - liftIO $ hPutStrLn stderr "Set ODBC version failed because invalid handle was passed to SetEnvAttr function." + liftIO $ log $ fromString "Set ODBC version failed because invalid handle was passed to SetEnvAttr function." fail "Set ODBC version failed" | x == sql_error -> do liftIO $ do - hPutStrLn stderr "Set ODBC version failed. Error diagnostics follow:" + log $ fromString "Set ODBC version failed. Error diagnostics follow:" displayDiagInfo sql_handle_env henv fail "Set ODBC version failed" | otherwise -> do - liftIO $ hPutStrLn stderr $ "SetEnvAttr returned unexpected return code: " ++ (show x) + liftIO $ log $ fromString $ "SetEnvAttr returned unexpected return code: " ++ (show x) fail "Set ODBC version failed" + +-- | convert an implementation type identifier to an ODBC known type +toODBCType :: SQLSMALLINT -> SQLSMALLINT +toODBCType t = if t == sql_char + then sql_char + else if clitype == sql_char + then odbctype + else clitype + where + clitype = toCLIType t + odbctype = if elem t [sql_longvarchar, sql_binary, sql_longvarbinary, sql_varbinary, sql_interval] + then t + else sql_char
src/SQL/ODBC.hs view
@@ -1,7 +1,11 @@-module SQL.ODBC where+{-# LANGUAGE CPP #-} +module SQL.ODBC (module SQL.ODBC, module SQL.CLI) where+ import Foreign.C.Types +import SQL.CLI+ -- env attribute sql_attr_odbc_version :: Num a => a sql_attr_odbc_version = 200@@ -56,3 +60,491 @@ -- From ODBC 3.8 onwards, we should use <major version> * 100 + <minor version> sql_ov_odbc3_80 :: CULong sql_ov_odbc3_80 = 380+++-- connection attributes+sql_attr_access_mode :: Num a => a+sql_attr_access_mode = 101++sql_attr_autocommit :: Num a => a+sql_attr_autocommit = 102++sql_attr_connection_timeout :: Num a => a+sql_attr_connection_timeout = 113++sql_attr_current_catalog :: Num a => a+sql_attr_current_catalog = 109++sql_attr_disconnect_behavior :: Num a => a+sql_attr_disconnect_behavior = 114++sql_attr_enlist_in_dtc :: Num a => a+sql_attr_enlist_in_dtc = 1207++sql_attr_enlist_in_xa :: Num a => a+sql_attr_enlist_in_xa = 1208++sql_attr_login_timeout :: Num a => a+sql_attr_login_timeout = 103++sql_attr_odbc_cursors :: Num a => a+sql_attr_odbc_cursors = 110++sql_attr_packet_size :: Num a => a+sql_attr_packet_size = 112++sql_attr_quiet_mode :: Num a => a+sql_attr_quiet_mode = 111++sql_attr_trace :: Num a => a+sql_attr_trace = 104++sql_attr_tracefile :: Num a => a+sql_attr_tracefile = 105++sql_attr_translate_lib :: Num a => a+sql_attr_translate_lib = 106++sql_attr_translate_option :: Num a => a+sql_attr_translate_option = 107++sql_attr_txn_isolation :: Num a => a+sql_attr_txn_isolation = 108++sql_attr_connection_dead :: Num a => a+sql_attr_connection_dead = 1209 -- GetConnectAttr only++sql_attr_driver_threading :: Num a => a+sql_attr_driver_threading = 1028 -- Driver threading level++{--+if (ODBCVER >= 0x0351)+ ODBC Driver Manager sets this connection attribute to a unicode driver+ (which supports SQLConnectW) when the application is an ANSI application+ (which calls SQLConnect, SQLDriverConnect, or SQLBrowseConnect).+ This is SetConnectAttr only and application does not set this attribute+ This attribute was introduced because some unicode driver's some APIs may+ need to behave differently on ANSI or Unicode applications. A unicode+ driver, which has same behavior for both ANSI or Unicode applications,+ should return SQL_ERROR when the driver manager sets this connection+ attribute. When a unicode driver returns SQL_SUCCESS on this attribute,+ the driver manager treates ANSI and Unicode connections differently in+ connection pooling.+--}++sql_attr_ansi_app :: Num a => a+sql_attr_ansi_app = 115++{--+endif+--}++sql_attr_reset_connection :: Num a => a+sql_attr_reset_connection = 116++sql_attr_async_dbc_functions_enable :: Num a => a+sql_attr_async_dbc_functions_enable = 117++-- SQL_CONNECT_OPT_DRVR_START is not meaningful for 3.0 driver+sql_connect_opt_drvr_start :: Num a => a+sql_connect_opt_drvr_start = 1000++sql_conn_opt_max :: Num a => a+sql_conn_opt_max = sql_attr_packet_size++sql_conn_opt_min :: Num a => a+sql_conn_opt_min = sql_attr_access_mode++-- SQL_ACCESS_MODE options+sql_mode_read_write :: Num a => a+sql_mode_read_write = 0++sql_mode_read_only :: Num a => a+sql_mode_read_only = 1++sql_mode_default :: Num a => a+sql_mode_default = sql_mode_read_write++-- SQL_AUTOCOMMIT options+sql_autocommit_off :: Num a => a+sql_autocommit_off = 0++sql_autocommit_on :: Num a => a+sql_autocommit_on = 1++sql_autocommit_default :: Num a => a+sql_autocommit_default = sql_autocommit_on++-- SQL_LOGIN_TIMEOUT options+sql_login_timeout_default :: Num a => a+sql_login_timeout_default = 15++-- SQL_OPT_TRACE options+sql_opt_trace_off :: Num a => a+sql_opt_trace_off = 0++sql_opt_trace_on :: Num a => a+sql_opt_trace_on = 1++sql_opt_trace_default :: Num a => a+sql_opt_trace_default = sql_opt_trace_off++sql_opt_trace_file_default :: String+#ifdef _WINDOWS_+sql_opt_trace_file_default = "\\temp\\SQL.LOG"+#else+sql_opt_trace_file_default = "/tmp/SQL.LOG"+#endif++-- SQL_ODBC_CURSORS options +sql_cur_use_if_needed :: Num a => a+sql_cur_use_if_needed = 0++sql_cur_use_odbc :: Num a => a+sql_cur_use_odbc = 1++sql_cur_use_driver :: Num a => a+sql_cur_use_driver = 2++sql_cur_default :: Num a => a+sql_cur_default = sql_cur_use_driver++-- values for SQL_ATTR_DISCONNECT_BEHAVIOR+sql_db_return_to_pool :: Num a => a+sql_db_return_to_pool = 0++sql_db_disconnect :: Num a => a+sql_db_disconnect = 1++sql_db_default :: Num a => a+sql_db_default = sql_db_return_to_pool++-- values for SQL_ATTR_ENLIST_IN_DTC+sql_dtc_done :: Num a => a+sql_dtc_done = 0+++-- values for SQL_ATTR_CONNECTION_DEAD+sql_cd_true :: Num a => a+sql_cd_true = 1 -- Connection is closed/dead++sql_cd_false :: Num a => a+sql_cd_false = 0 -- Connection is open/available++-- values for SQL_ATTR_ANSI_APP+sql_aa_true :: Num a => a+sql_aa_true = 1++sql_aa_false :: Num a => a+sql_aa_false = 0 -- the application is a Unicode app+++-- values for SQL_ATTR_RESET_CONNECTION+sql_reset_connection_yes :: Num a => a+sql_reset_connection_yes = 1++-- values for SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE+sql_async_dbc_enable_on :: Num a => a+sql_async_dbc_enable_on = 1++sql_async_dbc_enable_off :: Num a => a+sql_async_dbc_enable_off = 0++sql_async_dbc_enable_default :: Num a => a+sql_async_dbc_enable_default = sql_async_dbc_enable_off++++-- types specific to ODBC+sql_date :: (Num a) => a+sql_date = 9++sql_interval :: (Num a) => a+sql_interval = 10++sql_time :: (Num a) => a+sql_time = 10++sql_timestamp :: (Num a) => a+sql_timestamp = 11++sql_longvarchar :: (Num a) => a+sql_longvarchar = -1++sql_binary :: (Num a) => a+sql_binary = -2++sql_varbinary :: (Num a) => a+sql_varbinary = -3++sql_longvarbinary :: (Num a) => a+sql_longvarbinary = -4++sql_bigint :: (Num a) => a+sql_bigint = -5++sql_tinyint :: (Num a) => a+sql_tinyint = -6++sql_bit :: (Num a) => a+sql_bit = -7++sql_guid :: (Num a) => a+sql_guid = -11++sql_code_year :: (Num a) => a+sql_code_year = 1++sql_code_month :: (Num a) => a+sql_code_month = 2++sql_code_day :: (Num a) => a+sql_code_day = 3++sql_code_hour :: (Num a) => a+sql_code_hour = 4++sql_code_minute :: (Num a) => a+sql_code_minute = 5++sql_code_second :: (Num a) => a+sql_code_second = 6++sql_code_year_to_month :: (Num a) => a+sql_code_year_to_month = 7++sql_code_day_to_hour :: (Num a) => a+sql_code_day_to_hour = 8++sql_code_day_to_minute :: (Num a) => a+sql_code_day_to_minute = 9++sql_code_day_to_second :: (Num a) => a+sql_code_day_to_second = 10++sql_code_hour_to_minute :: (Num a) => a+sql_code_hour_to_minute = 11++sql_code_hour_to_second :: (Num a) => a+sql_code_hour_to_second = 12++sql_code_minute_to_second :: (Num a) => a+sql_code_minute_to_second = 13++sql_interval_year :: (Num a) => a+sql_interval_year = 100 + sql_code_year++sql_interval_month :: (Num a) => a+sql_interval_month = 100 + sql_code_month++sql_interval_day :: (Num a) => a+sql_interval_day = 100 + sql_code_day++sql_interval_hour :: (Num a) => a+sql_interval_hour = 100 + sql_code_hour++sql_interval_minute :: (Num a) => a+sql_interval_minute = 100 + sql_code_minute++sql_interval_second :: (Num a) => a+sql_interval_second = 100 + sql_code_second++sql_interval_year_to_month :: (Num a) => a+sql_interval_year_to_month = 100 + sql_code_year_to_month++sql_interval_day_to_hour :: (Num a) => a+sql_interval_day_to_hour = 100 + sql_code_day_to_hour++sql_interval_day_to_minute :: (Num a) => a+sql_interval_day_to_minute = 100 + sql_code_day_to_minute++sql_interval_day_to_second :: (Num a) => a+sql_interval_day_to_second = 100 + sql_code_day_to_second++sql_interval_hour_to_minute :: (Num a) => a+sql_interval_hour_to_minute = 100 + sql_code_hour_to_minute++sql_interval_hour_to_second :: (Num a) => a+sql_interval_hour_to_second = 100 + sql_code_hour_to_second++sql_interval_minute_to_second :: (Num a) => a+sql_interval_minute_to_second = 100 + sql_interval_minute_to_second+++-- ODBC c data types++sql_c_char :: (Num a) => a+sql_c_char = sql_char++sql_c_long :: (Num a) => a+sql_c_long = sql_integer++sql_c_short :: (Num a) => a+sql_c_short = sql_smallint++sql_c_float :: (Num a) => a+sql_c_float = sql_real++sql_c_double :: (Num a) => a+sql_c_double = sql_double++sql_c_numeric :: (Num a) => a+sql_c_numeric = sql_numeric++sql_c_default :: (Num a) => a+sql_c_default = 99++sql_signed_offset :: (Num a) => a+sql_signed_offset = -20++sql_unsigned_offset :: (Num a) => a+sql_unsigned_offset = -22++sql_c_date :: (Num a) => a+sql_c_date = sql_date++sql_c_time :: (Num a) => a+sql_c_time = sql_time++sql_c_timestamp :: (Num a) => a+sql_c_timestamp = sql_timestamp++sql_c_type_date :: (Num a) => a+sql_c_type_date = sql_type_date++sql_c_type_time :: (Num a) => a+sql_c_type_time = sql_type_time++sql_c_type_timestamp :: (Num a) => a+sql_c_type_timestamp = sql_type_timestamp++sql_c_interval_year :: (Num a) => a+sql_c_interval_year = sql_interval_year++sql_c_interval_month :: (Num a) => a+sql_c_interval_month = sql_interval_month++sql_c_interval_day :: (Num a) => a+sql_c_interval_day = sql_interval_day++sql_c_interval_hour :: (Num a) => a+sql_c_interval_hour = sql_interval_hour++sql_c_interval_minute :: (Num a) => a+sql_c_interval_minute = sql_interval_minute++sql_c_interval_second :: (Num a) => a+sql_c_interval_second = sql_interval_second++sql_c_interval_year_to_month :: (Num a) => a+sql_c_interval_year_to_month = sql_interval_year_to_month++sql_c_interval_day_to_hour :: (Num a) => a+sql_c_interval_day_to_hour = sql_interval_day_to_hour++sql_c_interval_day_to_minute :: (Num a) => a+sql_c_interval_day_to_minute = sql_interval_day_to_minute++sql_c_interval_day_to_second :: (Num a) => a+sql_c_interval_day_to_second = sql_interval_day_to_second++sql_c_interval_hour_to_minute :: (Num a) => a+sql_c_interval_hour_to_minute = sql_interval_hour_to_minute++sql_c_interval_hour_to_second :: (Num a) => a+sql_c_interval_hour_to_second = sql_interval_hour_to_second++sql_c_interval_minute_to_second :: (Num a) => a+sql_c_interval_minute_to_second = sql_interval_minute_to_second++sql_c_binary :: (Num a) => a+sql_c_binary = sql_binary++sql_c_bit :: (Num a) => a+sql_c_bit = sql_bit++sql_c_sbigint :: (Num a) => a+sql_c_sbigint = sql_bigint + sql_signed_offset++sql_c_ubigint :: (Num a) => a+sql_c_ubigint = sql_bigint + sql_unsigned_offset++sql_c_tinyint :: (Num a) => a+sql_c_tinyint = sql_tinyint++sql_c_slong :: (Num a) => a+sql_c_slong = sql_c_long + sql_signed_offset++sql_c_sshort :: (Num a) => a+sql_c_sshort = sql_c_short + sql_signed_offset++sql_c_stinyint :: (Num a) => a+sql_c_stinyint = sql_tinyint + sql_signed_offset++sql_c_ulong :: (Num a) => a+sql_c_ulong = sql_c_long + sql_unsigned_offset++sql_c_ushort :: (Num a) => a+sql_c_ushort = sql_c_short + sql_unsigned_offset++sql_c_utinyint :: (Num a) => a+sql_c_utinyint = sql_tinyint + sql_unsigned_offset++sql_c_bookmark :: (Num a) => a+sql_c_bookmark = sql_c_ubigint++sql_c_guid :: (Num a) => a+sql_c_guid = sql_guid++sql_wchar :: (Num a) => a+sql_wchar = -8++sql_wvarchar :: (Num a) => a+sql_wvarchar = -9++sql_wlongvarchar :: (Num a) => a+sql_wlongvarchar = -10++sql_c_wchar :: (Num a) => a+sql_c_wchar = sql_wchar++++-- | returns the length of the buffer for odbc C types; returns Nothing for+-- variable length fields or unknown fields, otherwise returns the number of+-- octets needed to hold the value of that type+odbcCTypeLen :: (Num a) => SQLSMALLINT -> Maybe a+odbcCTypeLen dataType =+ case dataType of+ _ | dataType == sql_c_bit -> Just 1+ | dataType == sql_c_tinyint -> Just 1+ | dataType == sql_c_stinyint -> Just 1+ | dataType == sql_c_utinyint -> Just 1+ | dataType == sql_c_short -> Just 2+ | dataType == sql_c_sshort -> Just 2+ | dataType == sql_c_ushort -> Just 2+ | dataType == sql_c_long -> Just 4+ | dataType == sql_c_slong -> Just 4+ | dataType == sql_c_ulong -> Just 4+ | dataType == sql_c_sbigint -> Just 8+ | dataType == sql_c_ubigint -> Just 8+ | dataType == sql_c_float -> Just 4+ | dataType == sql_c_double -> Just 8+ | dataType == sql_c_type_date -> Just 6+ | dataType == sql_c_type_time -> Just 6+ | dataType == sql_c_type_timestamp -> Just 16+ | dataType == sql_c_interval_year -> Just 34+ | dataType == sql_c_interval_month -> Just 34+ | dataType == sql_c_interval_day -> Just 34+ | dataType == sql_c_interval_hour -> Just 34+ | dataType == sql_c_interval_minute -> Just 34+ | dataType == sql_c_interval_second -> Just 34+ | dataType == sql_c_interval_year_to_month -> Just 34+ | dataType == sql_c_interval_day_to_hour -> Just 34+ | dataType == sql_c_interval_day_to_minute -> Just 34+ | dataType == sql_c_interval_day_to_second -> Just 34+ | dataType == sql_c_interval_hour_to_minute -> Just 34+ | dataType == sql_c_interval_hour_to_second -> Just 34+ | dataType == sql_c_interval_minute_to_second -> Just 34+ | dataType == sql_c_guid -> Just 16+ | otherwise -> Nothing