From 920c4451883e3919930235a1d7fc8c05b80c281c Mon Sep 17 00:00:00 2001 From: Arjun Khandkar Date: Thu, 16 Oct 2025 19:06:17 +0530 Subject: [PATCH] Close statements after use --- src/Database/Oracle/Simple/Execute.hs | 10 ++++++++-- src/Database/Oracle/Simple/Internal.hs | 15 +++++++++++++-- src/Database/Oracle/Simple/Query.hs | 13 ++++++++++--- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/Database/Oracle/Simple/Execute.hs b/src/Database/Oracle/Simple/Execute.hs index fd784a2..78b2ffd 100644 --- a/src/Database/Oracle/Simple/Execute.hs +++ b/src/Database/Oracle/Simple/Execute.hs @@ -16,6 +16,7 @@ import Database.Oracle.Simple.Internal Connection, DPIModeExec (DPI_MODE_EXEC_DEFAULT), dpiExecute, + closeStatement, getRowCount, prepareStmt, ) @@ -29,14 +30,18 @@ execute conn sql param = do stmt <- prepareStmt conn sql _ <- evalStateT (runRowWriter (toRow param) stmt) (Column 0) _ <- dpiExecute stmt DPI_MODE_EXEC_DEFAULT - getRowCount stmt + rowCount <- getRowCount stmt + closeStatement stmt + pure rowCount -- | A version of 'execute' that does not perform query substitution. execute_ :: Connection -> String -> IO Word64 execute_ conn sql = do stmt <- prepareStmt conn sql _ <- dpiExecute stmt DPI_MODE_EXEC_DEFAULT - getRowCount stmt + rowCount <- getRowCount stmt + closeStatement stmt + pure rowCount {- | Execute a multi-row INSERT, UPDATE or other SQL query that is not expected to return results. Returns the number of rows affected. If the list of parameters is empty, the function will simply @@ -52,4 +57,5 @@ executeMany conn sql params = do _ <- evalStateT (runRowWriter (toRow param) stmt) (Column 0) _ <- dpiExecute stmt DPI_MODE_EXEC_DEFAULT rowsAffected <- getRowCount stmt + closeStatement stmt pure (totalRowsAffected + rowsAffected) diff --git a/src/Database/Oracle/Simple/Internal.hs b/src/Database/Oracle/Simple/Internal.hs index 44a7589..1404e63 100644 --- a/src/Database/Oracle/Simple/Internal.hs +++ b/src/Database/Oracle/Simple/Internal.hs @@ -49,6 +49,7 @@ module Database.Oracle.Simple.Internal ping, fetch, close, + closeStatement, connect, withConnection, withConnCreateParams, @@ -1908,6 +1909,18 @@ foreign import ccall unsafe "dpiConn_getIsHealthy" Ptr CInt -> IO CInt +foreign import ccall "dpiStmt_close" + dpiStmt_close :: + DPIStmt -> + CString -> + CUInt -> + IO CInt + +-- | Close the statement and make it unusable for further work immediately. +closeStatement :: DPIStmt -> IO () +closeStatement stmt = + throwOracleError =<< dpiStmt_close stmt nullPtr 0 + -- | A pointer to an integer defining whether the connection is healthy (1) or not (0), which will be populated upon successful completion of this function. isHealthy :: Connection -> IO Bool isHealthy (Connection fptr) = @@ -1922,5 +1935,3 @@ Structurally equivalent to 'Data.Functor.Identity.Identity'. newtype Only a = Only {fromOnly :: a} deriving stock (Eq, Ord, Read, Show, Generic) deriving newtype (Enum) - - diff --git a/src/Database/Oracle/Simple/Query.hs b/src/Database/Oracle/Simple/Query.hs index 04f40d5..177aa86 100644 --- a/src/Database/Oracle/Simple/Query.hs +++ b/src/Database/Oracle/Simple/Query.hs @@ -13,6 +13,7 @@ import Database.Oracle.Simple.Internal Connection, DPIModeExec (DPI_MODE_EXEC_DEFAULT), dpiExecute, + closeStatement, fetch, prepareStmt, ) @@ -29,7 +30,9 @@ query conn sql param = do found <- fetch stmt loop stmt found where - loop _ n | n < 1 = pure [] + loop _ n | n < 1 = do + closeStatement stmt + pure [] loop stmt _ = do tsVal <- getRow stmt found <- fetch stmt @@ -43,7 +46,9 @@ query_ conn sql = do found <- fetch stmt loop stmt found where - loop _ n | n < 1 = pure [] + loop _ n | n < 1 = do + closeStatement stmt + pure [] loop stmt _ = do tsVal <- getRow stmt found <- fetch stmt @@ -57,7 +62,9 @@ forEach_ conn sql cont = do found <- fetch stmt loop stmt found where - loop _ n | n < 1 = pure () + loop _ n | n < 1 = do + closeStatement stmt + pure () loop stmt _ = do tsVal <- getRow stmt cont tsVal