Skip to content

Commit 963271f

Browse files
author
Johannes
committed
Merge tag 'v0.3.0' into nixify
v0.3.0
2 parents 585b54e + 8b9f41f commit 963271f

File tree

4 files changed

+54
-8
lines changed

4 files changed

+54
-8
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.stack-work
22
_release
33
result
4+
cabal.project.local

CHANGELOG

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
0.2.7:
1+
0.3.0:
22
* Add support for DATETIMEOFFSET
3+
* Add support for text-2.0
34
0.2.6:
45
* Add support for SQLSTATE
56
* Fix copying issues for error messages

odbc.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Haskell binding to the ODBC API. This has been tested
55
suite runs on OS X, Windows and Linux.
66
copyright: FP Complete 2018
77
maintainer: [email protected]
8-
version: 0.2.6
8+
version: 0.3.0
99
license: BSD3
1010
license-file: LICENSE
1111
build-type: Simple

src/Database/ODBC/Internal.hs

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
{-# LANGUAGE RankNTypes #-}
1212
{-# LANGUAGE FlexibleContexts #-}
1313
{-# LANGUAGE ForeignFunctionInterface #-}
14+
{-# LANGUAGE CPP #-}
1415

1516
-- | ODBC database API.
1617
--
@@ -62,7 +63,14 @@ import Data.Int
6263
import Data.String
6364
import Data.Text (Text)
6465
import qualified Data.Text as T
66+
#if MIN_VERSION_text(2,0,0)
67+
import qualified Data.ByteString.Internal as SI
68+
import qualified Data.Text.Encoding.Error as T
69+
import qualified Data.Text.Encoding as T
70+
#else
6571
import qualified Data.Text.Foreign as T
72+
import Data.Text.Foreign (I16)
73+
#endif
6674
import Data.Time
6775
import Foreign hiding (void)
6876
import Foreign.C
@@ -399,7 +407,7 @@ withExecDirect dbc string params cont =
399407
(assertSuccessOrNoData
400408
dbc
401409
"odbc_SQLExecDirectW"
402-
(T.useAsPtr
410+
(useAsPtrCompat
403411
string
404412
(\wstring len ->
405413
odbc_SQLExecDirectW
@@ -449,7 +457,7 @@ withBindParameter dbc parameter_number param cont statement_handle = go param
449457
go =
450458
\case
451459
TextParam text ->
452-
T.useAsPtr -- Pass as wide char UTF-16.
460+
useAsPtrCompat -- Pass as wide char UTF-16.
453461
text
454462
(\ptr len_in_chars ->
455463
runBind
@@ -587,7 +595,7 @@ fetchStatementRows dbc stmt = do
587595
-- | Describe the given column by its integer index.
588596
describeColumn :: Ptr EnvAndDbc -> SQLHSTMT s -> Int16 -> IO Column
589597
describeColumn dbPtr stmt i =
590-
T.useAsPtr
598+
useAsPtrCompat
591599
(T.replicate 1000 (fromString "0"))
592600
(\namep namelen ->
593601
(withMalloc
@@ -618,7 +626,7 @@ describeColumn dbPtr stmt i =
618626
digits <- peek digitsp
619627
isnull <- peek nullp
620628
namelen' <- peek namelenp
621-
name <- T.fromPtr namep (fromIntegral namelen')
629+
name <- fromPtrCompat namep (fromIntegral namelen')
622630
evaluate
623631
Column
624632
{ columnType = typ
@@ -930,12 +938,13 @@ getBinaryData dbc stmt column = do
930938
-- | Get the column's data as a text string.
931939
getTextData :: Ptr EnvAndDbc -> SQLHSTMT s -> SQLUSMALLINT -> IO Value
932940
getTextData dbc stmt column = do
941+
-- We need to fetch as UTF-16LE (see callsite), then convert to Text
933942
mavailableChars <- getSize dbc stmt sql_c_wchar column
934943
case mavailableChars of
935944
Just 0 -> pure (TextValue mempty)
936945
Nothing -> pure NullValue
937946
Just availableBytes -> do
938-
let allocBytes = availableBytes + 2
947+
let allocBytes = availableBytes + 2 -- room for NULL
939948
withMallocBytes
940949
(fromIntegral allocBytes)
941950
(\bufferp -> do
@@ -947,7 +956,7 @@ getTextData dbc stmt column = do
947956
column
948957
(coerce bufferp)
949958
(SQLLEN (fromIntegral allocBytes)))
950-
t <- T.fromPtr bufferp (fromIntegral (div availableBytes 2))
959+
t <- fromPtrCompat bufferp (fromIntegral (div availableBytes 2))
951960
let !v = TextValue t
952961
pure v)
953962

@@ -1433,3 +1442,38 @@ sql_c_time = coerce sql_time
14331442
-- <https://docs.rs/odbc-sys/0.6.3/odbc_sys/constant.SQL_SS_LENGTH_UNLIMITED.html>
14341443
sql_ss_length_unlimited :: SQLULEN
14351444
sql_ss_length_unlimited = 0
1445+
1446+
1447+
#if MIN_VERSION_text(2,0,0)
1448+
type I16 = Int
1449+
#endif
1450+
1451+
-- FIXME fail with Randomized with seed 1862667972
1452+
-- (on 9.2 as well)
1453+
1454+
-------- 'T.fromPtr' but compatible with text v1 and v2
1455+
1456+
fromPtrCompat :: Ptr Word16 -> I16 -> IO Text
1457+
#if MIN_VERSION_text(2,0,0)
1458+
fromPtrCompat bufferp len16 = do
1459+
let lenBytes = len16 * 2
1460+
noFinalizer = return () -- N.B. inner bufferp is 'free'd after this withMallocBytes block
1461+
-- invariant: this does no additional allocation
1462+
tempBS <- S.unsafePackCStringFinalizer (castPtr bufferp) lenBytes noFinalizer
1463+
-- invariant: this makes a copy:
1464+
return $! T.decodeUtf16LEWith T.strictDecode tempBS
1465+
#else
1466+
fromPtrCompat = T.fromPtr
1467+
#endif
1468+
1469+
useAsPtrCompat :: Text -> (Ptr Word16 -> I16 -> IO a) -> IO a
1470+
#if MIN_VERSION_text(2,0,0)
1471+
useAsPtrCompat t cont16 = do
1472+
let (fp8, len8) = SI.toForeignPtr0 $ T.encodeUtf16LE t
1473+
fp16 = castForeignPtr fp8
1474+
len16 = len8 `div` 2
1475+
withForeignPtr fp16 $ \p16 ->
1476+
cont16 p16 (fromIntegral len16)
1477+
#else
1478+
useAsPtrCompat = T.useAsPtr
1479+
#endif

0 commit comments

Comments
 (0)