Skip to content

Commit

Permalink
Added support for extended result codes
Browse files Browse the repository at this point in the history
The library now exposes sqlite3_extended_result_codes() and
SQLITE_OPEN_EXRESCODE.
  • Loading branch information
intolerable authored and jchia committed Dec 19, 2023
1 parent 2a1c534 commit eaf3e43
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Database/SQLite3.hs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ data SQLOpenFlag
| SQLOpenPrivateCache -- Ok for sqlite3_open_v2()
| SQLOpenWAL -- VFS only
| SQLOpenNoFollow -- Ok for sqlite3_open_v2()
| SQLOpenExResCode -- Extended result codes
deriving (Eq, Show)

-- | These VFS names are used when using the `open2` function.
Expand Down Expand Up @@ -371,6 +372,7 @@ open2 path flags zvfs =
toNum SQLOpenPrivateCache = 0x00040000
toNum SQLOpenWAL = 0x00080000
toNum SQLOpenNoFollow = 0x01000000
toNum SQLOpenExResCode = 0x02000000

-- | <https://www.sqlite.org/c3ref/close.html>
close :: Database -> IO ()
Expand Down
5 changes: 5 additions & 0 deletions Database/SQLite3/Bindings.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module Database.SQLite3.Bindings (
c_sqlite3_errcode,
c_sqlite3_extended_errcode,
c_sqlite3_errmsg,
c_sqlite3_extended_result_codes,
c_sqlite3_interrupt,
c_sqlite3_trace,
CTraceCallback,
Expand Down Expand Up @@ -166,6 +167,10 @@ foreign import ccall unsafe "sqlite3_extended_errcode"
foreign import ccall unsafe "sqlite3_errmsg"
c_sqlite3_errmsg :: Ptr CDatabase -> IO CString

-- | <https://www.sqlite.org/c3ref/extended_result_codes.html>
foreign import ccall unsafe "sqlite3_extended_result_codes"
c_sqlite3_extended_result_codes :: Ptr CDatabase -> Bool -> IO CError

-- | <https://www.sqlite.org/c3ref/interrupt.html>
foreign import ccall "sqlite3_interrupt"
c_sqlite3_interrupt :: Ptr CDatabase -> IO ()
Expand Down
6 changes: 6 additions & 0 deletions Database/SQLite3/Direct.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module Database.SQLite3.Direct (
errcode,
extendedErrcode,
errmsg,
setExtendedResultCodes,
setTrace,
getAutoCommit,
setSharedCacheEnabled,
Expand Down Expand Up @@ -314,6 +315,11 @@ extendedErrcode :: Database -> IO Error
extendedErrcode (Database db) =
decodeError <$> c_sqlite3_extended_errcode db

-- | <https://www.sqlite.org/c3ref/extended_result_codes.html>
setExtendedResultCodes :: Database -> Bool -> IO (Either Error ())
setExtendedResultCodes (Database db) enabled =
toResult () <$> c_sqlite3_extended_result_codes db enabled

-- | <https://www.sqlite.org/c3ref/errcode.html>
errmsg :: Database -> IO Utf8
errmsg (Database db) =
Expand Down
33 changes: 33 additions & 0 deletions test/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ regressionTests1 =
, TestLabel "TypedColumns" . testTypedColumns
, TestLabel "ColumnName" . testColumnName
, TestLabel "Errors" . testErrors
, TestLabel "ExtendedErrors". testExtendedErrors
, TestLabel "Integrity" . testIntegrity
, TestLabel "DecodeError" . testDecodeError
, TestLabel "ResultStats" . testResultStats
Expand Down Expand Up @@ -632,6 +633,38 @@ testErrors TestEnv{..} = TestCase $ do
\INSERT INTO foo VALUES (3, 4); \
\INSERT INTO foo VALUES (5, 6)"

testExtendedErrors :: forall f . TestEnv f -> Test
testExtendedErrors TestEnv{..} = TestCase $ do
-- opening a connection with extended results mode
conn <- open2 ":memory:" [SQLOpenReadWrite, SQLOpenCreate, SQLOpenExResCode] SQLVFSDefault
exec conn "CREATE TABLE foo (a INT NOT NULL, b INT);"
res <- Direct.exec conn "INSERT INTO foo (a, b) VALUES (NULL, 0);"
case res of
Left err ->
assertEqual "testExtendedErrors: expected an extended error code, but got the wrong error code" err
(ErrorConstraintNotNull, "NOT NULL constraint failed: foo.a")
Right () ->
assertFailure "testExtendedErrors: exec should have return extended error code, but succeeded"
close conn

-- setting a connection to extended results mode after it's opened
withConn $ \conn -> do
exec conn "CREATE TABLE foo (a INT UNIQUE);"
exec conn "INSERT INTO foo (a) VALUES (1);"

res <- Direct.exec conn "INSERT INTO foo (a) VALUES (1);"
assertEqual "testExtendedErrors: expected a primary error code" res
(Left (ErrorConstraint, "UNIQUE constraint failed: foo.a"))

res2 <- Direct.setExtendedResultCodes conn True
case res2 of
Left err -> assertFailure $
"testExtendedErrors: failed to enable extended result codes, got error " <> show err
Right () -> do
res3 <- Direct.exec conn "INSERT INTO foo (a) VALUES (1);"
assertEqual "testExtendedErrors: expected an extended error code" res3
(Left (ErrorConstraintUnique, "UNIQUE constraint failed: foo.a"))

-- Make sure data stored in a table comes back as-is.
testIntegrity :: forall f. TestEnv f -> Test
testIntegrity TestEnv{..} = TestCase $ do
Expand Down

0 comments on commit eaf3e43

Please sign in to comment.