{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ScopedTypeVariables #-}

{- |
Module      : Database.DuckDB.Simple.Copy
Description : High-level wrappers for DuckDB custom COPY functions.
-}
module Database.DuckDB.Simple.Copy (
    CopyBindInfo (..),
    CopyInitInfo (..),
    CopySinkInfo (..),
    CopyFinalizeInfo (..),
    registerCopyToFunction,
) where

import Control.Exception (SomeException, bracket, displayException, onException, try)
import Control.Monad (forM, when)
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Foreign as TextForeign
import Database.DuckDB.FFI
import Database.DuckDB.Simple.FromField (Field (..))
import Database.DuckDB.Simple.Internal (Connection, destroyLogicalType, mkDeleteCallback, releaseStablePtrData, throwRegistrationError, withConnectionHandle)
import Database.DuckDB.Simple.Materialize (materializeValue)
import Foreign.C.String (CString, peekCString)
import Foreign.Marshal.Alloc (alloca)
import Foreign.Ptr (Ptr, freeHaskellFunPtr, nullPtr)
import Foreign.StablePtr (StablePtr, castPtrToStablePtr, castStablePtrToPtr, deRefStablePtr, freeStablePtr, newStablePtr)
import Foreign.Storable (poke)

-- | Bind-phase metadata for a custom `COPY ... TO` function.
data CopyBindInfo = CopyBindInfo
    { CopyBindInfo -> [DuckDBType]
copyBindColumnTypes :: ![DuckDBType]
    }
    deriving (CopyBindInfo -> CopyBindInfo -> Bool
(CopyBindInfo -> CopyBindInfo -> Bool)
-> (CopyBindInfo -> CopyBindInfo -> Bool) -> Eq CopyBindInfo
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CopyBindInfo -> CopyBindInfo -> Bool
== :: CopyBindInfo -> CopyBindInfo -> Bool
$c/= :: CopyBindInfo -> CopyBindInfo -> Bool
/= :: CopyBindInfo -> CopyBindInfo -> Bool
Eq, Int -> CopyBindInfo -> ShowS
[CopyBindInfo] -> ShowS
CopyBindInfo -> String
(Int -> CopyBindInfo -> ShowS)
-> (CopyBindInfo -> String)
-> ([CopyBindInfo] -> ShowS)
-> Show CopyBindInfo
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CopyBindInfo -> ShowS
showsPrec :: Int -> CopyBindInfo -> ShowS
$cshow :: CopyBindInfo -> String
show :: CopyBindInfo -> String
$cshowList :: [CopyBindInfo] -> ShowS
showList :: [CopyBindInfo] -> ShowS
Show)

-- | Init-phase inputs for a custom `COPY ... TO` function.
data CopyInitInfo bindState = CopyInitInfo
    { forall bindState. CopyInitInfo bindState -> bindState
copyInitBindState :: !bindState
    , forall bindState. CopyInitInfo bindState -> String
copyInitFilePath :: !FilePath
    }

-- | Sink-phase inputs for a custom `COPY ... TO` function.
data CopySinkInfo bindState globalState = CopySinkInfo
    { forall bindState globalState.
CopySinkInfo bindState globalState -> bindState
copySinkBindState :: !bindState
    , forall bindState globalState.
CopySinkInfo bindState globalState -> globalState
copySinkGlobalState :: !globalState
    }

-- | Finalize-phase inputs for a custom `COPY ... TO` function.
data CopyFinalizeInfo bindState globalState = CopyFinalizeInfo
    { forall bindState globalState.
CopyFinalizeInfo bindState globalState -> bindState
copyFinalizeBindState :: !bindState
    , forall bindState globalState.
CopyFinalizeInfo bindState globalState -> globalState
copyFinalizeGlobalState :: !globalState
    }

data CopyFunctionResources = CopyFunctionResources
    { CopyFunctionResources -> DuckDBCopyFunctionBindFun
copyBindPtr :: !DuckDBCopyFunctionBindFun
    , CopyFunctionResources -> DuckDBCopyFunctionGlobalInitFun
copyInitPtr :: !DuckDBCopyFunctionGlobalInitFun
    , CopyFunctionResources -> DuckDBCopyFunctionSinkFun
copySinkPtr :: !DuckDBCopyFunctionSinkFun
    , CopyFunctionResources -> DuckDBCopyFunctionFinalizeFun
copyFinalizePtr :: !DuckDBCopyFunctionFinalizeFun
    , CopyFunctionResources -> DuckDBDeleteCallback
copyStateDestroyPtr :: !DuckDBDeleteCallback
    }

-- | Register a custom `COPY ... TO` implementation backed by Haskell callbacks.
registerCopyToFunction ::
    forall bindState globalState.
    Connection ->
    Text ->
    (CopyBindInfo -> IO bindState) ->
    (CopyInitInfo bindState -> IO globalState) ->
    (CopySinkInfo bindState globalState -> [[Field]] -> IO ()) ->
    (CopyFinalizeInfo bindState globalState -> IO ()) ->
    IO ()
registerCopyToFunction :: forall bindState globalState.
Connection
-> Text
-> (CopyBindInfo -> IO bindState)
-> (CopyInitInfo bindState -> IO globalState)
-> (CopySinkInfo bindState globalState -> [[Field]] -> IO ())
-> (CopyFinalizeInfo bindState globalState -> IO ())
-> IO ()
registerCopyToFunction Connection
conn Text
name CopyBindInfo -> IO bindState
bindFn CopyInitInfo bindState -> IO globalState
initFn CopySinkInfo bindState globalState -> [[Field]] -> IO ()
sinkFn CopyFinalizeInfo bindState globalState -> IO ()
finalizeFn = do
    stateDestroyCb <- (Ptr () -> IO ()) -> IO DuckDBDeleteCallback
mkDeleteCallback Ptr () -> IO ()
releaseStablePtrData
    bindPtr <- mkCopyBindFun (copyBindHandler stateDestroyCb bindFn)
    initPtr <- mkCopyGlobalInitFun (copyGlobalInitHandler stateDestroyCb initFn)
    sinkPtr <- mkCopySinkFun (copySinkHandler sinkFn)
    finalizePtr <- mkCopyFinalizeFun (copyFinalizeHandler finalizeFn)
    resources <-
        newStablePtr
            CopyFunctionResources
                { copyBindPtr = bindPtr
                , copyInitPtr = initPtr
                , copySinkPtr = sinkPtr
                , copyFinalizePtr = finalizePtr
                , copyStateDestroyPtr = stateDestroyCb
                }
    destroyCb <- mkDeleteCallback releaseCopyResources
    let release =
            DuckDBCopyFunctionBindFun -> IO ()
forall a. FunPtr a -> IO ()
freeHaskellFunPtr DuckDBCopyFunctionBindFun
bindPtr
                IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> DuckDBCopyFunctionGlobalInitFun -> IO ()
forall a. FunPtr a -> IO ()
freeHaskellFunPtr DuckDBCopyFunctionGlobalInitFun
initPtr
                IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> DuckDBCopyFunctionSinkFun -> IO ()
forall a. FunPtr a -> IO ()
freeHaskellFunPtr DuckDBCopyFunctionSinkFun
sinkPtr
                IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> DuckDBCopyFunctionFinalizeFun -> IO ()
forall a. FunPtr a -> IO ()
freeHaskellFunPtr DuckDBCopyFunctionFinalizeFun
finalizePtr
                IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> DuckDBDeleteCallback -> IO ()
forall a. FunPtr a -> IO ()
freeHaskellFunPtr DuckDBDeleteCallback
stateDestroyCb
                IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> StablePtr CopyFunctionResources -> IO ()
forall a. StablePtr a -> IO ()
freeStablePtr StablePtr CopyFunctionResources
resources
                IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> DuckDBDeleteCallback -> IO ()
forall a. FunPtr a -> IO ()
freeHaskellFunPtr DuckDBDeleteCallback
destroyCb
    bracket c_duckdb_create_copy_function destroyCopyFunction \DuckDBCopyFunction
copyFun ->
        (IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO a
`onException` IO ()
release) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
            Text -> (CString -> IO ()) -> IO ()
forall a. Text -> (CString -> IO a) -> IO a
TextForeign.withCString Text
name \CString
cName ->
                DuckDBCopyFunction -> CString -> IO ()
c_duckdb_copy_function_set_name DuckDBCopyFunction
copyFun CString
cName
            DuckDBCopyFunction -> DuckDBCopyFunctionBindFun -> IO ()
c_duckdb_copy_function_set_bind DuckDBCopyFunction
copyFun DuckDBCopyFunctionBindFun
bindPtr
            DuckDBCopyFunction -> DuckDBCopyFunctionGlobalInitFun -> IO ()
c_duckdb_copy_function_set_global_init DuckDBCopyFunction
copyFun DuckDBCopyFunctionGlobalInitFun
initPtr
            DuckDBCopyFunction -> DuckDBCopyFunctionSinkFun -> IO ()
c_duckdb_copy_function_set_sink DuckDBCopyFunction
copyFun DuckDBCopyFunctionSinkFun
sinkPtr
            DuckDBCopyFunction -> DuckDBCopyFunctionFinalizeFun -> IO ()
c_duckdb_copy_function_set_finalize DuckDBCopyFunction
copyFun DuckDBCopyFunctionFinalizeFun
finalizePtr
            DuckDBCopyFunction -> Ptr () -> DuckDBDeleteCallback -> IO ()
c_duckdb_copy_function_set_extra_info DuckDBCopyFunction
copyFun (StablePtr CopyFunctionResources -> Ptr ()
forall a. StablePtr a -> Ptr ()
castStablePtrToPtr StablePtr CopyFunctionResources
resources) DuckDBDeleteCallback
destroyCb
            Connection -> (DuckDBConnection -> IO ()) -> IO ()
forall a. Connection -> (DuckDBConnection -> IO a) -> IO a
withConnectionHandle Connection
conn \DuckDBConnection
connPtr -> do
                rc <- DuckDBConnection -> DuckDBCopyFunction -> IO DuckDBState
c_duckdb_register_copy_function DuckDBConnection
connPtr DuckDBCopyFunction
copyFun
                if rc == DuckDBSuccess
                    then pure ()
                    else throwRegistrationError "register copy function"

copyBindHandler ::
    forall bindState.
    DuckDBDeleteCallback ->
    (CopyBindInfo -> IO bindState) ->
    DuckDBCopyFunctionBindInfo ->
    IO ()
copyBindHandler :: forall bindState.
DuckDBDeleteCallback
-> (CopyBindInfo -> IO bindState)
-> DuckDBCopyFunctionBindInfo
-> IO ()
copyBindHandler DuckDBDeleteCallback
destroyCb CopyBindInfo -> IO bindState
bindFn DuckDBCopyFunctionBindInfo
info = do
    outcome <- IO () -> IO (Either SomeException ())
forall e a. Exception e => IO a -> IO (Either e a)
try do
        copyBindColumnTypes <- DuckDBCopyFunctionBindInfo -> IO [DuckDBType]
fetchColumnTypes DuckDBCopyFunctionBindInfo
info
        bindState <- bindFn CopyBindInfo{copyBindColumnTypes}
        stable <- newStablePtr bindState
        c_duckdb_copy_function_bind_set_bind_data info (castStablePtrToPtr stable) destroyCb
    reportCopyError c_duckdb_copy_function_bind_set_error info outcome

copyGlobalInitHandler ::
    forall bindState globalState.
    DuckDBDeleteCallback ->
    (CopyInitInfo bindState -> IO globalState) ->
    DuckDBCopyFunctionGlobalInitInfo ->
    IO ()
copyGlobalInitHandler :: forall bindState globalState.
DuckDBDeleteCallback
-> (CopyInitInfo bindState -> IO globalState)
-> DuckDBCopyFunctionGlobalInitInfo
-> IO ()
copyGlobalInitHandler DuckDBDeleteCallback
destroyCb CopyInitInfo bindState -> IO globalState
initFn DuckDBCopyFunctionGlobalInitInfo
info = do
    outcome <- IO () -> IO (Either SomeException ())
forall e a. Exception e => IO a -> IO (Either e a)
try do
        rawBindState <- DuckDBCopyFunctionGlobalInitInfo -> IO (Ptr ())
c_duckdb_copy_function_global_init_get_bind_data DuckDBCopyFunctionGlobalInitInfo
info
        when (rawBindState == nullPtr) $
            throwRegistrationError "missing copy bind state"
        bindState <- deRefStablePtr (castPtrToStablePtr rawBindState :: StablePtr bindState)
        pathPtr <- c_duckdb_copy_function_global_init_get_file_path info
        filePath <-
            if pathPtr == nullPtr
                then pure ""
                else peekCString pathPtr
        globalState <- initFn CopyInitInfo{copyInitBindState = bindState, copyInitFilePath = filePath}
        stable <- newStablePtr globalState
        c_duckdb_copy_function_global_init_set_global_state info (castStablePtrToPtr stable) destroyCb
    reportCopyError c_duckdb_copy_function_global_init_set_error info outcome

copySinkHandler ::
    forall bindState globalState.
    (CopySinkInfo bindState globalState -> [[Field]] -> IO ()) ->
    DuckDBCopyFunctionSinkInfo ->
    DuckDBDataChunk ->
    IO ()
copySinkHandler :: forall bindState globalState.
(CopySinkInfo bindState globalState -> [[Field]] -> IO ())
-> DuckDBCopyFunctionSinkInfo -> DuckDBDataChunk -> IO ()
copySinkHandler CopySinkInfo bindState globalState -> [[Field]] -> IO ()
sinkFn DuckDBCopyFunctionSinkInfo
info DuckDBDataChunk
chunk = do
    outcome <- IO () -> IO (Either SomeException ())
forall e a. Exception e => IO a -> IO (Either e a)
try do
        bindState <- (DuckDBCopyFunctionSinkInfo -> IO (Ptr ()))
-> DuckDBCopyFunctionSinkInfo -> IO bindState
forall a i. (i -> IO (Ptr ())) -> i -> IO a
readStablePtrState DuckDBCopyFunctionSinkInfo -> IO (Ptr ())
c_duckdb_copy_function_sink_get_bind_data DuckDBCopyFunctionSinkInfo
info
        globalState <- readStablePtrState c_duckdb_copy_function_sink_get_global_state info
        rows <- materializeChunkRows chunk
        sinkFn CopySinkInfo{copySinkBindState = bindState, copySinkGlobalState = globalState} rows
    reportCopyError c_duckdb_copy_function_sink_set_error info outcome

copyFinalizeHandler ::
    forall bindState globalState.
    (CopyFinalizeInfo bindState globalState -> IO ()) ->
    DuckDBCopyFunctionFinalizeInfo ->
    IO ()
copyFinalizeHandler :: forall bindState globalState.
(CopyFinalizeInfo bindState globalState -> IO ())
-> DuckDBCopyFunctionFinalizeInfo -> IO ()
copyFinalizeHandler CopyFinalizeInfo bindState globalState -> IO ()
finalizeFn DuckDBCopyFunctionFinalizeInfo
info = do
    outcome <- IO () -> IO (Either SomeException ())
forall e a. Exception e => IO a -> IO (Either e a)
try do
        bindState <- (DuckDBCopyFunctionFinalizeInfo -> IO (Ptr ()))
-> DuckDBCopyFunctionFinalizeInfo -> IO bindState
forall a i. (i -> IO (Ptr ())) -> i -> IO a
readStablePtrState DuckDBCopyFunctionFinalizeInfo -> IO (Ptr ())
c_duckdb_copy_function_finalize_get_bind_data DuckDBCopyFunctionFinalizeInfo
info
        globalState <- readStablePtrState c_duckdb_copy_function_finalize_get_global_state info
        finalizeFn CopyFinalizeInfo{copyFinalizeBindState = bindState, copyFinalizeGlobalState = globalState}
    reportCopyError c_duckdb_copy_function_finalize_set_error info outcome

reportCopyError :: (i -> CString -> IO ()) -> i -> Either SomeException () -> IO ()
reportCopyError :: forall i.
(i -> CString -> IO ()) -> i -> Either SomeException () -> IO ()
reportCopyError i -> CString -> IO ()
_ i
_ (Right ()) = () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
reportCopyError i -> CString -> IO ()
setError i
info (Left SomeException
err) =
    Text -> (CString -> IO ()) -> IO ()
forall a. Text -> (CString -> IO a) -> IO a
TextForeign.withCString (String -> Text
Text.pack (SomeException -> String
forall e. Exception e => e -> String
displayException SomeException
err)) \CString
cMsg ->
        i -> CString -> IO ()
setError i
info CString
cMsg

fetchColumnTypes :: DuckDBCopyFunctionBindInfo -> IO [DuckDBType]
fetchColumnTypes :: DuckDBCopyFunctionBindInfo -> IO [DuckDBType]
fetchColumnTypes DuckDBCopyFunctionBindInfo
info = do
    count <- DuckDBCopyFunctionBindInfo -> IO DuckDBIdx
c_duckdb_copy_function_bind_get_column_count DuckDBCopyFunctionBindInfo
info
    let indices = [Int
0 .. DuckDBIdx -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral DuckDBIdx
count Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1] :: [Int]
    forM indices \Int
idx -> do
        logical <- DuckDBCopyFunctionBindInfo -> DuckDBIdx -> IO DuckDBLogicalType
c_duckdb_copy_function_bind_get_column_type DuckDBCopyFunctionBindInfo
info (Int -> DuckDBIdx
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
idx)
        dtype <- c_duckdb_get_type_id logical
        destroyLogicalType logical
        pure dtype

readStablePtrState :: forall a i. (i -> IO (Ptr ())) -> i -> IO a
readStablePtrState :: forall a i. (i -> IO (Ptr ())) -> i -> IO a
readStablePtrState i -> IO (Ptr ())
getter i
info = do
    rawPtr <- i -> IO (Ptr ())
getter i
info
    if rawPtr == nullPtr
        then throwRegistrationError "missing copy callback state"
        else deRefStablePtr (castPtrToStablePtr rawPtr :: StablePtr a)

materializeChunkRows :: DuckDBDataChunk -> IO [[Field]]
materializeChunkRows :: DuckDBDataChunk -> IO [[Field]]
materializeChunkRows DuckDBDataChunk
chunk = do
    rawColumnCount <- DuckDBDataChunk -> IO DuckDBIdx
c_duckdb_data_chunk_get_column_count DuckDBDataChunk
chunk
    let columnCount = DuckDBIdx -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral DuckDBIdx
rawColumnCount :: Int
    readers <- mapM (makeColumnReader chunk) [0 .. columnCount - 1]
    rawRowCount <- c_duckdb_data_chunk_get_size chunk
    let rowCount = DuckDBIdx -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral DuckDBIdx
rawRowCount :: Int
    forM [0 .. rowCount - 1] \Int
row ->
        [ColumnReader] -> (ColumnReader -> IO Field) -> IO [Field]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [ColumnReader]
readers \ColumnReader
reader ->
            ColumnReader
reader (Int -> DuckDBIdx
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
row)

type ColumnReader = DuckDBIdx -> IO Field

makeColumnReader :: DuckDBDataChunk -> Int -> IO ColumnReader
makeColumnReader :: DuckDBDataChunk -> Int -> IO ColumnReader
makeColumnReader DuckDBDataChunk
chunk Int
columnIndex = do
    vector <- DuckDBDataChunk -> DuckDBIdx -> IO DuckDBVector
c_duckdb_data_chunk_get_vector DuckDBDataChunk
chunk (Int -> DuckDBIdx
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
columnIndex)
    logical <- c_duckdb_vector_get_column_type vector
    dtype <- c_duckdb_get_type_id logical
    destroyLogicalType logical
    dataPtr <- c_duckdb_vector_get_data vector
    validity <- c_duckdb_vector_get_validity vector
    let name = String -> Text
Text.pack (String
"column" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show Int
columnIndex)
    pure \DuckDBIdx
rowIdx -> do
        fieldValue <- DuckDBType
-> DuckDBVector -> Ptr () -> Ptr DuckDBIdx -> Int -> IO FieldValue
materializeValue DuckDBType
dtype DuckDBVector
vector Ptr ()
dataPtr Ptr DuckDBIdx
validity (DuckDBIdx -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral DuckDBIdx
rowIdx)
        pure Field{fieldName = name, fieldIndex = columnIndex, fieldValue}

releaseCopyResources :: Ptr () -> IO ()
releaseCopyResources :: Ptr () -> IO ()
releaseCopyResources Ptr ()
rawPtr =
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Ptr ()
rawPtr Ptr () -> Ptr () -> Bool
forall a. Eq a => a -> a -> Bool
/= Ptr ()
forall a. Ptr a
nullPtr) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
        let stablePtr :: StablePtr CopyFunctionResources
stablePtr = Ptr () -> StablePtr CopyFunctionResources
forall a. Ptr () -> StablePtr a
castPtrToStablePtr Ptr ()
rawPtr :: StablePtr CopyFunctionResources
        CopyFunctionResources{copyBindPtr, copyInitPtr, copySinkPtr, copyFinalizePtr, copyStateDestroyPtr} <- StablePtr CopyFunctionResources -> IO CopyFunctionResources
forall a. StablePtr a -> IO a
deRefStablePtr StablePtr CopyFunctionResources
stablePtr
        freeHaskellFunPtr copyBindPtr
        freeHaskellFunPtr copyInitPtr
        freeHaskellFunPtr copySinkPtr
        freeHaskellFunPtr copyFinalizePtr
        freeHaskellFunPtr copyStateDestroyPtr
        freeStablePtr stablePtr

destroyCopyFunction :: DuckDBCopyFunction -> IO ()
destroyCopyFunction :: DuckDBCopyFunction -> IO ()
destroyCopyFunction DuckDBCopyFunction
copyFun =
    (Ptr DuckDBCopyFunction -> IO ()) -> IO ()
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca \Ptr DuckDBCopyFunction
ptr -> Ptr DuckDBCopyFunction -> DuckDBCopyFunction -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr DuckDBCopyFunction
ptr DuckDBCopyFunction
copyFun IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Ptr DuckDBCopyFunction -> IO ()
c_duckdb_destroy_copy_function Ptr DuckDBCopyFunction
ptr

foreign import ccall "wrapper"
    mkCopyBindFun :: (DuckDBCopyFunctionBindInfo -> IO ()) -> IO DuckDBCopyFunctionBindFun

foreign import ccall "wrapper"
    mkCopyGlobalInitFun :: (DuckDBCopyFunctionGlobalInitInfo -> IO ()) -> IO DuckDBCopyFunctionGlobalInitFun

foreign import ccall "wrapper"
    mkCopySinkFun :: (DuckDBCopyFunctionSinkInfo -> DuckDBDataChunk -> IO ()) -> IO DuckDBCopyFunctionSinkFun

foreign import ccall "wrapper"
    mkCopyFinalizeFun :: (DuckDBCopyFunctionFinalizeInfo -> IO ()) -> IO DuckDBCopyFunctionFinalizeFun