hsql-odbc (empty) → 1.7
raw patch · 5 files changed
+455/−0 lines, 5 filesdep +basedep +hsqlbuild-type:Customsetup-changed
Dependencies added: base, hsql
Files
- Database/HSQL/HsODBC.c +13/−0
- Database/HSQL/HsODBC.h +29/−0
- Database/HSQL/ODBC.hsc +383/−0
- Setup.lhs +18/−0
- hsql-odbc.cabal +12/−0
+ Database/HSQL/HsODBC.c view
@@ -0,0 +1,13 @@+#include "HsODBC.h"++#if defined(mingw32_HOST_OS)+// Under Windows SQLFreeEnv function has stdcall calling convention+// while in Haskell functions represented with FunPtr must be always+// with ccall convention. For that reason we need to redirect calling+// to this function.++void my_sqlFreeEnv(HENV hEnv)+{+ SQLFreeEnv(hEnv);+}+#endif
+ Database/HSQL/HsODBC.h view
@@ -0,0 +1,29 @@+#ifndef HsODBC+#define HsODBC++#ifdef mingw32_HOST_OS+#include <windows.h>+#endif++#include <sqlext.h>+#include <sqlucode.h>++#define FIELD_NAME_LENGTH 255++typedef struct+ {+ HSTMT hSTMT;+ SQLUSMALLINT fieldsCount;+ SQLCHAR fieldName[FIELD_NAME_LENGTH];+ SQLSMALLINT NameLength;+ SQLSMALLINT DataType;+ SQLULEN ColumnSize;+ SQLSMALLINT DecimalDigits;+ SQLSMALLINT Nullable;+ } FIELD;++#ifdef mingw32_HOST_OS+void my_sqlFreeEnv(HENV hEnv);+#endif++#endif
+ Database/HSQL/ODBC.hsc view
@@ -0,0 +1,383 @@+{-# OPTIONS -fglasgow-exts #-} + +-----------------------------------------------------------------------------------------+{-| Module : Database.HSQL.ODBC+ Copyright : (c) Krasimir Angelov 2003+ License : BSD-style++ Maintainer : kr.angelov@gmail.com+ Stability : provisional+ Portability : portable++ The module provides interface to ODBC+-}+-----------------------------------------------------------------------------------------++module Database.HSQL.ODBC(connect, driverConnect, module Database.HSQL) where++import Database.HSQL+import Database.HSQL.Types+import Data.Word(Word32, Word16)+import Data.Int(Int32, Int16)+import Data.Maybe+import Foreign+import Foreign.C+import Control.Monad(unless)+import Control.Exception(throwDyn)+import Control.Concurrent.MVar+import System.IO.Unsafe+import System.Time+#ifdef DEBUG+import Debug.Trace+#endif++#include <time.h>+#include <HsODBC.h>++type SQLHANDLE = Ptr ()+type HENV = SQLHANDLE+type HDBC = SQLHANDLE+type HSTMT = SQLHANDLE+type HENVRef = ForeignPtr ()++type SQLSMALLINT = #type SQLSMALLINT+type SQLUSMALLINT = #type SQLUSMALLINT+type SQLINTEGER = #type SQLINTEGER+type SQLUINTEGER = #type SQLUINTEGER+type SQLRETURN = SQLSMALLINT+type SQLLEN = SQLINTEGER+type SQLULEN = SQLINTEGER++#ifdef mingw32_HOST_OS+#let CALLCONV = "stdcall"+#else+#let CALLCONV = "ccall"+#endif++foreign import #{CALLCONV} "HsODBC.h SQLAllocEnv" sqlAllocEnv :: Ptr HENV -> IO SQLRETURN+#ifdef mingw32_HOST_OS+foreign import ccall "HsODBC.h &my_sqlFreeEnv" sqlFreeEnv_p :: FunPtr (HENV -> IO ())+#else+foreign import ccall "HsODBC.h &SQLFreeEnv" sqlFreeEnv_p :: FunPtr (HENV -> IO ())+#endif+foreign import #{CALLCONV} "HsODBC.h SQLAllocConnect" sqlAllocConnect :: HENV -> Ptr HDBC -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLFreeConnect" sqlFreeConnect:: HDBC -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLConnect" sqlConnect :: HDBC -> CString -> Int -> CString -> Int -> CString -> Int -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLDriverConnect" sqlDriverConnect :: HDBC -> Ptr () -> CString -> SQLSMALLINT -> CString -> SQLSMALLINT -> Ptr SQLSMALLINT -> SQLUSMALLINT -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLDisconnect" sqlDisconnect :: HDBC -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLAllocStmt" sqlAllocStmt :: HDBC -> Ptr HSTMT -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLFreeStmt" sqlFreeStmt :: HSTMT -> SQLUSMALLINT -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLNumResultCols" sqlNumResultCols :: HSTMT -> Ptr SQLUSMALLINT -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLDescribeCol" sqlDescribeCol :: HSTMT -> SQLUSMALLINT -> CString -> SQLSMALLINT -> Ptr SQLSMALLINT -> Ptr SQLSMALLINT -> Ptr SQLULEN -> Ptr SQLSMALLINT -> Ptr SQLSMALLINT -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLBindCol" sqlBindCol :: HSTMT -> SQLUSMALLINT -> SQLSMALLINT -> Ptr a -> SQLLEN -> Ptr SQLINTEGER -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLFetch" sqlFetch :: HSTMT -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLGetDiagRec" sqlGetDiagRec :: SQLSMALLINT -> SQLHANDLE -> SQLSMALLINT -> CString -> Ptr SQLINTEGER -> CString -> SQLSMALLINT -> Ptr SQLSMALLINT -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLExecDirect" sqlExecDirect :: HSTMT -> CString -> Int -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLSetConnectOption" sqlSetConnectOption :: HDBC -> SQLUSMALLINT -> SQLULEN -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLTransact" sqlTransact :: HENV -> HDBC -> SQLUSMALLINT -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLGetData" sqlGetData :: HSTMT -> SQLUSMALLINT -> SQLSMALLINT -> Ptr () -> SQLINTEGER -> Ptr SQLINTEGER -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLTables" sqlTables :: HSTMT -> CString -> SQLSMALLINT -> CString -> SQLSMALLINT -> CString -> SQLSMALLINT -> CString -> SQLSMALLINT -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLColumns" sqlColumns :: HSTMT -> CString -> SQLSMALLINT -> CString -> SQLSMALLINT -> CString -> SQLSMALLINT -> CString -> SQLSMALLINT -> IO SQLRETURN+foreign import #{CALLCONV} "HsODBC.h SQLMoreResults" sqlMoreResults :: HSTMT -> IO SQLRETURN+#if defined(MSSQL_ODBC)+foreign import #{CALLCONV} "HsODBC.h SQLSetStmtAttr" sqlSetStmtAttr :: HSTMT -> SQLINTEGER -> SQLINTEGER -> SQLINTEGER -> IO SQLRETURN +#endif++-----------------------------------------------------------------------------------------+-- routines for handling exceptions+-----------------------------------------------------------------------------------------++handleSqlResult :: SQLSMALLINT -> SQLHANDLE -> SQLRETURN -> IO ()+handleSqlResult handleType handle res+ | res == (#const SQL_SUCCESS) || res == (#const SQL_NO_DATA) = return ()+ | res == (#const SQL_SUCCESS_WITH_INFO) = do+#ifdef DEBUG+ e <- getSqlError+ putTraceMsg (show e)+#else+ return ()+#endif+ | res == (#const SQL_INVALID_HANDLE) = throwDyn SqlInvalidHandle+ | res == (#const SQL_STILL_EXECUTING) = throwDyn SqlStillExecuting+ | res == (#const SQL_NEED_DATA) = throwDyn SqlNeedData+ | res == (#const SQL_ERROR) = do+ e <- getSqlError+ throwDyn e+ | otherwise = error (show res)+ where+ getSqlError =+ allocaBytes 256 $ \pState ->+ alloca $ \pNative ->+ allocaBytes 256 $ \pMsg ->+ alloca $ \pTextLen -> do+ res <- sqlGetDiagRec handleType handle 1 pState pNative pMsg 256 pTextLen+ if res == (#const SQL_NO_DATA)+ then return SqlNoData+ else do+ state <- peekCString pState+ native <- peek pNative+ msg <- peekCString pMsg+ return (SqlError {seState=state, seNativeError=fromIntegral native, seErrorMsg=msg})++-----------------------------------------------------------------------------------------+-- keeper of HENV+-----------------------------------------------------------------------------------------++{-# NOINLINE myEnvironment #-}+myEnvironment :: HENVRef+myEnvironment = unsafePerformIO $ alloca $ \ (phEnv :: Ptr HENV) -> do+ res <- sqlAllocEnv phEnv+ hEnv <- peek phEnv+ handleSqlResult 0 nullPtr res+ newForeignPtr sqlFreeEnv_p hEnv++-----------------------------------------------------------------------------------------+-- Connect/Disconnect+-----------------------------------------------------------------------------------------++-- | Makes a new connection to the ODBC data source+connect :: String -- ^ Data source name+ -> String -- ^ User identifier+ -> String -- ^ Authentication string (password)+ -> IO Connection -- ^ the returned value represents the new connection+connect server user authentication = connectHelper $ \hDBC ->+ withCString server $ \pServer ->+ withCString user $ \pUser ->+ withCString authentication $ \pAuthentication ->+ sqlConnect hDBC pServer (#const SQL_NTS) pUser (#const SQL_NTS) pAuthentication (#const SQL_NTS)++-- | 'driverConnect' is an alternative to 'connect'. It supports data sources that +-- require more connection information than the three arguments in 'connect' +-- and data sources that are not defined in the system information.+driverConnect :: String -- ^ Connection string+ -> IO Connection -- ^ the returned value represents the new connection+driverConnect connString = connectHelper $ \hDBC -> + withCString connString $ \pConnString ->+ allocaBytes 1024 $ \pOutConnString ->+ alloca $ \pLen ->+ sqlDriverConnect hDBC nullPtr pConnString (#const SQL_NTS) pOutConnString 1024 pLen (#const SQL_DRIVER_NOPROMPT)++connectHelper :: (HDBC -> IO SQLRETURN) -> IO Connection+connectHelper connectFunction = withForeignPtr myEnvironment $ \hEnv -> do+ hDBC <- alloca $ \ (phDBC :: Ptr HDBC) -> do+ res <- sqlAllocConnect hEnv phDBC+ handleSqlResult (#const SQL_HANDLE_ENV) hEnv res+ peek phDBC+ res <- connectFunction hDBC+ handleSqlResult (#const SQL_HANDLE_DBC) hDBC res+ refFalse <- newMVar False+ let connection = (Connection+ { connDisconnect = disconnect hDBC+ , connExecute = execute hDBC+ , connQuery = query connection hDBC+ , connTables = tables connection hDBC+ , connDescribe = describe connection hDBC+ , connBeginTransaction = beginTransaction myEnvironment hDBC+ , connCommitTransaction = commitTransaction myEnvironment hDBC+ , connRollbackTransaction = rollbackTransaction myEnvironment hDBC+ , connClosed = refFalse+ })+ return connection+ where+ disconnect :: HDBC -> IO ()+ disconnect hDBC = do+ sqlDisconnect hDBC >>= handleSqlResult (#const SQL_HANDLE_DBC) hDBC+ sqlFreeConnect hDBC >>= handleSqlResult (#const SQL_HANDLE_DBC) hDBC++ execute :: HDBC -> String -> IO ()+ execute hDBC query = allocaBytes (#const sizeof(HSTMT)) $+ \pStmt -> do+ res <- sqlAllocStmt hDBC pStmt+ handleSqlResult (#const SQL_HANDLE_DBC) hDBC res+ hSTMT <- peek pStmt+ withCStringLen query $ \(pQuery,len) -> do+ res <- sqlExecDirect hSTMT pQuery len+ handleSqlResult (#const SQL_HANDLE_STMT) hSTMT res+ res <- sqlFreeStmt hSTMT (#const SQL_DROP)+ handleSqlResult (#const SQL_HANDLE_STMT) hSTMT res++ stmtBufferSize = 256++ withStatement :: Connection -> HDBC -> (HSTMT -> IO SQLRETURN) -> IO Statement+ withStatement connection hDBC f = + allocaBytes (#const sizeof(FIELD)) $ \pFIELD -> do+ res <- sqlAllocStmt hDBC ((#ptr FIELD, hSTMT) pFIELD)+ handleSqlResult (#const SQL_HANDLE_DBC) hDBC res+ hSTMT <- (#peek FIELD, hSTMT) pFIELD+ let handleResult res = handleSqlResult (#const SQL_HANDLE_STMT) hSTMT res+#if defined(MSSQL_ODBC)+ sqlSetStmtAttr hSTMT (#const SQL_ATTR_ROW_ARRAY_SIZE) 2 (#const SQL_IS_INTEGER)+ sqlSetStmtAttr hSTMT (#const SQL_ATTR_CURSOR_TYPE) (#const SQL_CURSOR_STATIC) (#const SQL_IS_INTEGER)+#endif+ f hSTMT >>= handleResult+ fields <- moveToFirstResult hSTMT pFIELD+ buffer <- mallocBytes (fromIntegral stmtBufferSize)+ refFalse <- newMVar False+ let statement = Statement+ { stmtConn = connection+ , stmtClose = closeStatement hSTMT buffer+ , stmtFetch = fetch hSTMT+ , stmtGetCol = getColValue hSTMT buffer+ , stmtFields = fields+ , stmtClosed = refFalse+ }+ return statement+ where+ moveToFirstResult :: HSTMT -> Ptr a -> IO [FieldDef]+ moveToFirstResult hSTMT pFIELD = do+ res <- sqlNumResultCols hSTMT ((#ptr FIELD, fieldsCount) pFIELD)+ handleSqlResult (#const SQL_HANDLE_STMT) hSTMT res+ count <- (#peek FIELD, fieldsCount) pFIELD+ if count == 0+ then do+#if defined(MSSQL_ODBC)+ sqlSetStmtAttr hSTMT (#const SQL_ATTR_ROW_ARRAY_SIZE) 2 (#const SQL_IS_INTEGER)+ sqlSetStmtAttr hSTMT (#const SQL_ATTR_CURSOR_TYPE) (#const SQL_CURSOR_STATIC) (#const SQL_IS_INTEGER)+#endif+ res <- sqlMoreResults hSTMT+ handleSqlResult (#const SQL_HANDLE_STMT) hSTMT res+ if res == (#const SQL_NO_DATA)+ then return []+ else moveToFirstResult hSTMT pFIELD+ else+ getFieldDefs hSTMT pFIELD 1 count++ getFieldDefs :: HSTMT -> Ptr a -> SQLUSMALLINT -> SQLUSMALLINT -> IO [FieldDef]+ getFieldDefs hSTMT pFIELD n count+ | n > count = return []+ | otherwise = do+ res <- sqlDescribeCol hSTMT n ((#ptr FIELD, fieldName) pFIELD) (#const FIELD_NAME_LENGTH) ((#ptr FIELD, NameLength) pFIELD) ((#ptr FIELD, DataType) pFIELD) ((#ptr FIELD, ColumnSize) pFIELD) ((#ptr FIELD, DecimalDigits) pFIELD) ((#ptr FIELD, Nullable) pFIELD)+ handleSqlResult (#const SQL_HANDLE_STMT) hSTMT res+ name <- peekCString ((#ptr FIELD, fieldName) pFIELD)+ dataType <- (#peek FIELD, DataType) pFIELD+ columnSize <- (#peek FIELD, ColumnSize) pFIELD+ decimalDigits <- (#peek FIELD, DecimalDigits) pFIELD+ (nullable :: SQLSMALLINT) <- (#peek FIELD, Nullable) pFIELD+ let sqlType = mkSqlType dataType columnSize decimalDigits+ fields <- getFieldDefs hSTMT pFIELD (n+1) count+ return ((name,sqlType,toBool nullable):fields)++ mkSqlType :: SQLSMALLINT -> SQLULEN -> SQLSMALLINT -> SqlType+ mkSqlType (#const SQL_CHAR) size _ = SqlChar (fromIntegral size)+ mkSqlType (#const SQL_VARCHAR) size _ = SqlVarChar (fromIntegral size)+ mkSqlType (#const SQL_LONGVARCHAR) size _ = SqlLongVarChar (fromIntegral size)+ mkSqlType (#const SQL_DECIMAL) size prec = SqlDecimal (fromIntegral size) (fromIntegral prec)+ mkSqlType (#const SQL_NUMERIC) size prec = SqlNumeric (fromIntegral size) (fromIntegral prec)+ mkSqlType (#const SQL_SMALLINT) _ _ = SqlSmallInt+ mkSqlType (#const SQL_INTEGER) _ _ = SqlInteger+ mkSqlType (#const SQL_REAL) _ _ = SqlReal+ -- From: http://msdn.microsoft.com/library/en-us/odbc/htm/odappdpr_2.asp+ -- "Depending on the implementation, the precision of SQL_FLOAT can be either 24 or 53:+ -- if it is 24, the SQL_FLOAT data type is the same as SQL_REAL;+ -- if it is 53, the SQL_FLOAT data type is the same as SQL_DOUBLE."+ mkSqlType (#const SQL_FLOAT) _ _ = SqlFloat+ mkSqlType (#const SQL_DOUBLE) _ _ = SqlDouble+ mkSqlType (#const SQL_BIT) _ _ = SqlBit+ mkSqlType (#const SQL_TINYINT) _ _ = SqlTinyInt+ mkSqlType (#const SQL_BIGINT) _ _ = SqlBigInt+ mkSqlType (#const SQL_BINARY) size _ = SqlBinary (fromIntegral size)+ mkSqlType (#const SQL_VARBINARY) size _ = SqlVarBinary (fromIntegral size)+ mkSqlType (#const SQL_LONGVARBINARY)size _ = SqlLongVarBinary (fromIntegral size)+ mkSqlType (#const SQL_DATE) _ _ = SqlDate+ mkSqlType (#const SQL_TIME) _ _ = SqlTime+ mkSqlType (#const SQL_TIMESTAMP) _ _ = SqlDateTime+ mkSqlType (#const SQL_WCHAR) size _ = SqlWChar (fromIntegral size)+ mkSqlType (#const SQL_WVARCHAR) size _ = SqlWVarChar (fromIntegral size)+ mkSqlType (#const SQL_WLONGVARCHAR) size _ = SqlWLongVarChar (fromIntegral size)+ mkSqlType tp _ _ = SqlUnknown (fromIntegral tp)++ query :: Connection -> HDBC -> String -> IO Statement+ query connection hDBC q = withStatement connection hDBC doQuery+ where doQuery hSTMT = withCStringLen q (uncurry (sqlExecDirect hSTMT))++ beginTransaction myEnvironment hDBC = do+ sqlSetConnectOption hDBC (#const SQL_AUTOCOMMIT) (#const SQL_AUTOCOMMIT_OFF)+ return ()++ commitTransaction myEnvironment hDBC = withForeignPtr myEnvironment $ \hEnv -> do+ sqlTransact hEnv hDBC (#const SQL_COMMIT)+ sqlSetConnectOption hDBC (#const SQL_AUTOCOMMIT) (#const SQL_AUTOCOMMIT_ON)+ return ()++ rollbackTransaction myEnvironment hDBC = withForeignPtr myEnvironment $ \hEnv -> do+ sqlTransact hEnv hDBC (#const SQL_ROLLBACK)+ sqlSetConnectOption hDBC (#const SQL_AUTOCOMMIT) (#const SQL_AUTOCOMMIT_ON)+ return ()++ tables :: Connection -> HDBC -> IO [String]+ tables connection hDBC = do+ stmt <- withStatement connection hDBC sqlTables'+ -- SQLTables returns (column names may vary):+ -- Column name # Type+ -- TABLE_NAME 3 VARCHAR+ collectRows (\s -> getFieldValue s "TABLE_NAME") stmt+ where sqlTables' hSTMT = sqlTables hSTMT nullPtr 0 nullPtr 0 nullPtr 0 nullPtr 0++ describe :: Connection -> HDBC -> String -> IO [FieldDef]+ describe connection hDBC table = do+ stmt <- withStatement connection hDBC (sqlColumns' table)+ collectRows getColumnInfo stmt+ where+ sqlColumns' table hSTMT =+ withCStringLen table (\(pTable,len) ->+ sqlColumns hSTMT nullPtr 0 nullPtr 0 pTable (fromIntegral len) nullPtr 0)+ -- SQLColumns returns (column names may vary):+ -- Column name # Type+ -- COLUMN_NAME 4 Varchar not NULL+ -- DATA_TYPE 5 Smallint not NULL+ -- COLUMN_SIZE 7 Integer+ -- DECIMAL_DIGITS 9 Smallint+ -- NULLABLE 11 Smallint not NULL++ getColumnInfo stmt = do+ column_name <- getFieldValue stmt "COLUMN_NAME"+ (data_type::Int) <- getFieldValue stmt "DATA_TYPE"+ (column_size::Int) <- getFieldValue' stmt "COLUMN_SIZE" 0+ (decimal_digits::Int) <- getFieldValue' stmt "DECIMAL_DIGITS" 0+ (nullable::Int) <- getFieldValue stmt "NULLABLE"+ let sqlType = mkSqlType (fromIntegral data_type) (fromIntegral column_size) (fromIntegral decimal_digits)+ return (column_name, sqlType, toBool nullable)++ fetch :: HSTMT -> IO Bool+ fetch hSTMT = do+ res <- sqlFetch hSTMT+ handleSqlResult (#const SQL_HANDLE_STMT) hSTMT res+ return (res /= (#const SQL_NO_DATA))++ getColValue :: HSTMT -> CString -> Int -> FieldDef -> (FieldDef -> CString -> Int -> IO a) -> IO a+ getColValue hSTMT buffer colNumber fieldDef f = do+ (res,len_or_ind) <- getData buffer (fromIntegral stmtBufferSize)+ if len_or_ind == (#const SQL_NULL_DATA)+ then f fieldDef nullPtr 0+ else if res == (#const SQL_SUCCESS_WITH_INFO)+ then getLongData len_or_ind+ else f fieldDef buffer (fromIntegral len_or_ind)+ where+ getData :: CString -> SQLINTEGER -> IO (SQLRETURN, SQLINTEGER)+ getData buffer size = alloca $ \lenP -> do+ res <- sqlGetData hSTMT (fromIntegral colNumber+1) (#const SQL_C_CHAR) (castPtr buffer) size lenP+ handleSqlResult (#const SQL_HANDLE_STMT) hSTMT res+ len_or_ind <- peek lenP+ return (res, len_or_ind)++ -- gets called only when there is more data than would+ -- fit in the normal buffer. This call to+ -- SQLGetData() will fetch the rest of the data.+ -- We create a new buffer big enough to hold the+ -- old and the new data, copy the old data into+ -- it and put the new data in buffer after the old.+ getLongData len = allocaBytes (fromIntegral newBufSize) $ \newBuf -> do+ copyBytes newBuf buffer stmtBufferSize+ -- The last byte of the old data with always be null,+ -- so it is overwritten with the first byte of the new data.+ let newDataStart = newBuf `plusPtr` (stmtBufferSize - 1)+ newDataLen = newBufSize - (fromIntegral stmtBufferSize - 1)+ (res,_) <- getData newDataStart newDataLen+ f fieldDef newBuf (fromIntegral newBufSize-1)+ where+ newBufSize = len+1 -- to allow for terminating null character++ closeStatement :: HSTMT -> CString -> IO ()+ closeStatement hSTMT buffer = do+ free buffer+ sqlFreeStmt hSTMT (#const SQL_DROP) >>= handleSqlResult (#const SQL_HANDLE_STMT) hSTMT
+ Setup.lhs view
@@ -0,0 +1,18 @@+#!/usr/bin/runghc++\begin{code}+import Distribution.Simple+import Distribution.Setup+import Distribution.PackageDescription+import System.Info++main = defaultMainWithHooks defaultUserHooks{preConf=configure}+ where+ configure :: [String] -> ConfigFlags -> IO HookedBuildInfo+ configure args flags = do+ let binfo | os == "mingw32" = emptyBuildInfo{extraLibs=["odbc32"], ccOptions=["-Dmingw32_HOST_OS"]}+ | otherwise = emptyBuildInfo{extraLibs=["odbc"]}+ hbi = (Just binfo,[])+ writeHookedBuildInfo "ODBC.buildinfo" hbi+ return hbi+\end{code}
+ hsql-odbc.cabal view
@@ -0,0 +1,12 @@+name: hsql-odbc+version: 1.7+license: BSD3+author: Krasimir Angelov <kr.angelov@gmail.com>+category: Database+description: ODBC driver for HSQL.+exposed-modules:Database.HSQL.ODBC+build-depends: base, hsql+extensions: ForeignFunctionInterface, CPP+cc-options: -IDatabase/HSQL+c-sources: Database/HSQL/HsODBC.c+extra-source-files: Database/HSQL/HsODBC.h