diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,7 +1,5 @@
 # Changelog for hs-opentelemetry-instrumentation-postgresql-simple
 
-## Unreleased changes
-
-### Breaking changes
+## 0.2.0.0
 
-- Use `HashMap Text Attribute` instead of `[(Text, Attribute)]` as attributes
+- Significantly reworked implementation
diff --git a/hs-opentelemetry-instrumentation-postgresql-simple.cabal b/hs-opentelemetry-instrumentation-postgresql-simple.cabal
--- a/hs-opentelemetry-instrumentation-postgresql-simple.cabal
+++ b/hs-opentelemetry-instrumentation-postgresql-simple.cabal
@@ -1,17 +1,17 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.35.2.
+-- This file has been generated from package.yaml by hpack version 0.36.0.
 --
 -- see: https://github.com/sol/hpack
 
 name:               hs-opentelemetry-instrumentation-postgresql-simple
-version:            0.1.0.0
+version:            0.2.0.0
 description:        Please see the README on GitHub at <https://github.com/iand675/hs-opentelemetry/tree/main/instrumentation/postgresql-simple#readme>
 homepage:           https://github.com/iand675/hs-opentelemetry#readme
 bug-reports:        https://github.com/iand675/hs-opentelemetry/issues
 author:             Ian Duncan, Jade Lovelace
 maintainer:         ian@iankduncan.com
-copyright:          2023 Ian Duncan, Mercury Technologies
+copyright:          2024 Ian Duncan, Mercury Technologies
 license:            BSD3
 license-file:       LICENSE
 build-type:         Simple
@@ -33,34 +33,12 @@
   build-depends:
       base >=4.7 && <5
     , bytestring
-    , hs-opentelemetry-api ==0.1.*
+    , hs-opentelemetry-api ==0.2.*
     , iproute
-    , network
     , postgresql-libpq
     , postgresql-simple
     , text
     , unliftio
-    , unordered-containers
-  default-language: Haskell2010
-
-test-suite hs-opentelemetry-instrumentation-postgresql-simple-test
-  type: exitcode-stdio-1.0
-  main-is: Spec.hs
-  other-modules:
-      Paths_hs_opentelemetry_instrumentation_postgresql_simple
-  hs-source-dirs:
-      test
-  ghc-options: -threaded -rtsopts -with-rtsopts=-N
-  build-depends:
-      base >=4.7 && <5
-    , bytestring
-    , hs-opentelemetry-api ==0.1.*
-    , hs-opentelemetry-instrumentation-postgresql-simple
-    , iproute
-    , network
-    , postgresql-libpq
-    , postgresql-simple
-    , text
-    , unliftio
+    , unliftio-core
     , unordered-containers
   default-language: Haskell2010
diff --git a/src/OpenTelemetry/Instrumentation/PostgresqlSimple.hs b/src/OpenTelemetry/Instrumentation/PostgresqlSimple.hs
--- a/src/OpenTelemetry/Instrumentation/PostgresqlSimple.hs
+++ b/src/OpenTelemetry/Instrumentation/PostgresqlSimple.hs
@@ -1,45 +1,61 @@
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TemplateHaskell #-}
 
+{- |
+[New HTTP semantic conventions have been declared stable.](https://opentelemetry.io/blog/2023/http-conventions-declared-stable/#migration-plan) Opt-in by setting the environment variable OTEL_SEMCONV_STABILITY_OPT_IN to
+- "http" - to use the stable conventions
+- "http/dup" - to emit both the old and the stable conventions
+Otherwise, the old conventions will be used. The stable conventions will replace the old conventions in the next major release of this library.
+-}
 module OpenTelemetry.Instrumentation.PostgresqlSimple (
   staticConnectionAttributes,
-  {-
+
   -- * Queries that return results
-    query
-  , query_
+  query,
+  query_,
+
   -- ** Queries taking parser as argument
-  , queryWith
-  , queryWith_
+  queryWith,
+  queryWith_,
+
   -- * Queries that stream results
-  , fold
-  , foldWithOptions
-  , fold_
-  , foldWithOptions_
-  , forEach
-  , forEach_
-  , returning
+  fold,
+  foldWithOptions,
+  fold_,
+  foldWithOptions_,
+  forEach,
+  forEach_,
+  returning,
+
   -- ** Queries that stream results taking a parser as an argument
-  , foldWith
-  , foldWithOptionsAndParser
-  , foldWith_
-  , foldWithOptionsAndParser_
-  , forEachWith
-  , forEachWith_
-  , returningWith
+  foldWith,
+  foldWithOptionsAndParser,
+  foldWith_,
+  foldWithOptionsAndParser_,
+  forEachWith,
+  forEachWith_,
+  returningWith,
+
   -- * Statements that do not return results
-  , execute
-  , execute_
-  , executeMany
+  execute,
+  execute_,
+  executeMany,
+
   -- * Reexported functions
-  , module X
-  -}
+  module X,
+
+  -- * Utility functions
+  pgsSpan,
 ) where
 
 import Control.Monad.IO.Class
+import Control.Monad.IO.Unlift
 import qualified Data.ByteString.Char8 as C
 import qualified Data.HashMap.Strict as H
 import Data.IP
 import Data.Int (Int64)
+import Data.List
 import Data.Maybe (catMaybes)
 import Data.Text (Text)
 import qualified Data.Text as T
@@ -72,17 +88,19 @@
 import qualified Database.PostgreSQL.Simple.FromRow as Simple
 import Database.PostgreSQL.Simple.Internal (
   Connection (Connection, connectionHandle),
+  withConnection,
  )
 import GHC.Stack
 import OpenTelemetry.Resource ((.=), (.=?))
-import OpenTelemetry.Trace.Core
+import OpenTelemetry.SemanticsConfig
+import OpenTelemetry.Trace.Core as TC
 import OpenTelemetry.Trace.Monad
 import Text.Read (readMaybe)
 import UnliftIO
 
 
 -- | Get attributes that can be attached to a span denoting some database action
-staticConnectionAttributes :: (MonadIO m) => Connection -> m (H.HashMap T.Text Attribute)
+staticConnectionAttributes :: (HasCallStack, MonadIO m) => Connection -> m (H.HashMap T.Text Attribute)
 staticConnectionAttributes Connection {connectionHandle} = liftIO $ do
   (mDb, mUser, mHost, mPort) <- withMVar connectionHandle $ \pqConn -> do
     (,,,)
@@ -90,12 +108,25 @@
       <*> LibPQ.user pqConn
       <*> LibPQ.host pqConn
       <*> LibPQ.port pqConn
-  pure $
-    H.fromList $
-      catMaybes
+
+  let stableMaybeAttributes =
         [ "db.system" .= toAttribute ("postgresql" :: T.Text)
         , "db.user" .=? (TE.decodeUtf8 <$> mUser)
         , "db.name" .=? (TE.decodeUtf8 <$> mDb)
+        , "server.port"
+            .=? ( do
+                    port <- TE.decodeUtf8 <$> mPort
+                    (readMaybe $ T.unpack port) :: Maybe Int
+                )
+        , case (readMaybe . C.unpack) =<< mHost of
+            Nothing -> "server.address" .=? (TE.decodeUtf8 <$> mHost)
+            Just (IPv4 ipv4) -> "server.address" .= T.pack (show ipv4)
+            Just (IPv6 ipv6) -> "server.address" .= T.pack (show ipv6)
+        ]
+      oldMaybeAttributes =
+        [ "db.system" .= toAttribute ("postgresql" :: T.Text)
+        , "db.user" .=? (TE.decodeUtf8 <$> mUser)
+        , "db.name" .=? (TE.decodeUtf8 <$> mDb)
         , "net.peer.port"
             .=? ( do
                     port <- TE.decodeUtf8 <$> mPort
@@ -107,254 +138,150 @@
             Just (IPv6 ipv6) -> "net.peer.ip" .= T.pack (show ipv6)
         ]
 
-{-
--- | Perform a @SELECT@ or other SQL query that is expected to return
--- results. All results are retrieved and converted before this
--- function returns.
---
--- When processing large results, this function will consume a lot of
--- client-side memory.  Consider using 'fold' instead.
---
--- Exceptions that may be thrown:
---
--- * 'FormatError': the query string could not be formatted correctly.
---
--- * 'QueryError': the result contains no columns (i.e. you should be
---   using 'execute' instead of 'query').
---
--- * 'ResultError': result conversion failed.
---
--- * 'SqlError':  the postgresql backend returned an error,  e.g.
---   a syntax or type error,  or an incorrect table or column name.
-query :: (MonadIO m, MonadGetContext m, ToRow q, FromRow r) => Connection -> Query -> q -> m [r]
-query = liftIO $ Simple.query
+  semanticsOptions <- getSemanticsOptions
+  pure $
+    H.fromList $
+      catMaybes $
+        case httpOption semanticsOptions of
+          Stable -> stableMaybeAttributes
+          StableAndOld -> stableMaybeAttributes `union` oldMaybeAttributes
+          Old -> oldMaybeAttributes
 
--- | A version of 'query' that does not perform query substitution.
-query_ :: (MonadIO m, MonadGetContext m, FromRow r) => Connection -> Query -> m [r]
-query_ = _
 
--- | A version of 'query' taking parser as argument
-queryWith :: (MonadIO m, MonadGetContext m, ToRow q) => Simple.RowParser r -> Connection -> Query -> q -> m [r]
-queryWith parser conn template qs = _
+-- | Function to help with wrapping functions in postgresql-simple
+pgsSpan :: HasCallStack => Connection -> C.ByteString -> IO a -> IO a
+pgsSpan conn statement f = do
+  connAttr <- staticConnectionAttributes conn
+  dbName <- maybe "unknown db" TE.decodeUtf8 <$> withConnection conn LibPQ.db
+  let callAttr = H.fromList [("db.statement", toAttribute $ TE.decodeUtf8 statement)]
+      attrs = connAttr <> callAttr
+      spanArgs = SpanArguments Client attrs [] Nothing
+  tracerProvider <- getGlobalTracerProvider
+  let tracer = makeTracer tracerProvider $detectInstrumentationLibrary tracerOptions
+  TC.inSpan tracer dbName spanArgs f
 
--- | A version of 'query_' taking parser as argument
-queryWith_ :: (MonadIO m, MonadGetContext m) => Simple.RowParser r -> Connection -> Query -> m [r]
-queryWith_ parser conn q = _
 
--- | Perform a @SELECT@ or other SQL query that is expected to return
--- results. Results are streamed incrementally from the server, and
--- consumed via a left fold.
---
--- When dealing with small results, it may be simpler (and perhaps
--- faster) to use 'query' instead.
---
--- This fold is /not/ strict. The stream consumer is responsible for
--- forcing the evaluation of its result to avoid space leaks.
---
--- This is implemented using a database cursor.    As such,  this requires
--- a transaction.   This function will detect whether or not there is a
--- transaction in progress,  and will create a 'ReadCommitted' 'ReadOnly'
--- transaction if needed.   The cursor is given a unique temporary name,
--- so the consumer may itself call fold.
---
--- Exceptions that may be thrown:
---
--- * 'FormatError': the query string could not be formatted correctly.
---
--- * 'QueryError': the result contains no columns (i.e. you should be
---   using 'execute' instead of 'query').
---
--- * 'ResultError': result conversion failed.
---
--- * 'SqlError':  the postgresql backend returned an error,  e.g.
---   a syntax or type error,  or an incorrect table or column name.
-fold            :: (MonadBracketError m, MonadLocalContext m, FromRow row, ToRow params)
-                => Connection
-                -> Query
-                -> params
-                -> a
-                -> (a -> row -> m a)
-                -> m a
-fold = _
+-- | Instrumented version of 'Simple.query'
+query :: (HasCallStack, MonadIO m, ToRow q, FromRow r) => Connection -> Query -> q -> m [r]
+query = queryWith Simple.fromRow
 
--- | A version of 'fold' taking a parser as an argument
-foldWith        :: (MonadBracketError m, MonadLocalContext m, ToRow params)
-                => Simple.RowParser row
-                -> Connection
-                -> Query
-                -> params
-                -> a
-                -> (a -> row -> m a)
-                -> m a
-foldWith = _
--- | The same as 'fold',  but this provides a bit more control over
---   lower-level details.  Currently,  the number of rows fetched per
---   round-trip to the server and the transaction mode may be adjusted
---   accordingly.    If the connection is already in a transaction,
---   then the existing transaction is used and thus the 'transactionMode'
---   option is ignored.
-foldWithOptions :: (MonadBracketError m, MonadLocalContext m, FromRow row, ToRow params)
-                => FoldOptions
-                -> Connection
-                -> Query
-                -> params
-                -> a
-                -> (a -> row -> m a)
-                -> m a
-foldWithOptions opts = _
 
--- | A version of 'foldWithOptions' taking a parser as an argument
-foldWithOptionsAndParser :: (MonadBracketError m, MonadLocalContext m, ToRow params)
-                         => FoldOptions
-                         -> Simple.RowParser row
-                         -> Connection
-                         -> Query
-                         -> params
-                         -> a
-                         -> (a -> row -> m a)
-                         -> m a
-foldWithOptionsAndParser opts parser conn template qs a f = _
+-- | Instrumented version of 'Simple.query_'
+query_ :: (HasCallStack, MonadIO m, FromRow r) => Connection -> Query -> m [r]
+query_ = queryWith_ Simple.fromRow
 
--- | A version of 'fold' that does not perform query substitution.
-fold_ :: (MonadBracketError m, MonadLocalContext m, FromRow r) =>
-         Connection
-      -> Query                  -- ^ Query.
-      -> a                      -- ^ Initial state for result consumer.
-      -> (a -> r -> m a)       -- ^ Result consumer.
-      -> m a
-fold_ = _
 
--- | A version of 'fold_' taking a parser as an argument
-foldWith_ :: (MonadUnliftIO m, MonadBracketError m, MonadLocalContext m) =>
-             Simple.RowParser r
-          -> Connection
-          -> Query
-          -> a
-          -> (a -> r -> m a)
-          -> m a
-foldWith_ = _
+-- | Instrumented version of 'Simple.queryWith'
+queryWith :: (HasCallStack, MonadIO m, ToRow q) => Simple.RowParser r -> Connection -> Query -> q -> m [r]
+queryWith parser conn template qs = liftIO $ do
+  statement <- formatQuery conn template qs
+  pgsSpan conn statement $ Simple.queryWith parser conn template qs
 
-foldWithOptions_ :: (MonadUnliftIO m, MonadBracketError m, MonadLocalContext m, FromRow r) =>
-                    FoldOptions
-                 -> Connection
-                 -> Query             -- ^ Query.
-                 -> a                 -- ^ Initial state for result consumer.
-                 -> (a -> r -> m a)  -- ^ Result consumer.
-                 -> m a
-foldWithOptions_ opts conn query' a f = Simple.foldWithOptions_ opts conn query' a f
 
--- | A version of 'foldWithOptions_' taking a parser as an argument
-foldWithOptionsAndParser_ :: FoldOptions
-                          -> Simple.RowParser r
-                          -> Connection
-                          -> Query             -- ^ Query.
-                          -> a                 -- ^ Initial state for result consumer.
-                          -> (a -> r -> IO a)  -- ^ Result consumer.
-                          -> IO a
-foldWithOptionsAndParser_ opts parser conn query' a f = _
+-- | Instrumented version of 'Simple.queryWith_'
+queryWith_ :: MonadIO m => Simple.RowParser r -> Connection -> Query -> m [r]
+queryWith_ parser conn query = liftIO $ do
+  statement <- formatQuery conn query ()
+  pgsSpan conn statement $ Simple.queryWith_ parser conn query
 
--- | A version of 'fold' that does not transform a state value.
-forEach :: (MonadUnliftIO m, MonadBracketError m, MonadLocalContext m, ToRow q, FromRow r) =>
-           Connection
-        -> Query                -- ^ Query template.
-        -> q                    -- ^ Query parameters.
-        -> (r -> m ())         -- ^ Result consumer.
-        -> m ()
-forEach = _
+
+-- | Instrumented version of 'Simple.fold'
+fold :: (HasCallStack, MonadUnliftIO m, FromRow row, ToRow params) => Connection -> Query -> params -> a -> (a -> row -> m a) -> m a
+fold = foldWithOptionsAndParser Simple.defaultFoldOptions Simple.fromRow
+
+
+-- | Instrumented version of 'Simple.foldWith'
+foldWith :: (HasCallStack, MonadUnliftIO m, ToRow params) => Simple.RowParser row -> Connection -> Query -> params -> a -> (a -> row -> m a) -> m a
+foldWith = foldWithOptionsAndParser Simple.defaultFoldOptions
+
+
+-- | Instrumented version of 'Simple.foldWithOptions'
+foldWithOptions :: (HasCallStack, MonadUnliftIO m, FromRow row, ToRow params) => FoldOptions -> Connection -> Query -> params -> a -> (a -> row -> m a) -> m a
+foldWithOptions opts = foldWithOptionsAndParser opts Simple.fromRow
+
+
+-- | Instrumented version of 'Simple.foldWithOptionsAndParser'
+foldWithOptionsAndParser :: (HasCallStack, MonadUnliftIO m, ToRow params) => FoldOptions -> Simple.RowParser row -> Connection -> Query -> params -> a -> (a -> row -> m a) -> m a
+foldWithOptionsAndParser opts parser conn template qs a f = withRunInIO $ \runInIO -> do
+  statement <- formatQuery conn template qs
+  pgsSpan conn statement $ Simple.foldWithOptionsAndParser opts parser conn template qs a (\a' r -> runInIO (f a' r))
+
+
+-- | Instrumented version of 'Simple.fold_'
+fold_ :: (HasCallStack, MonadUnliftIO m, FromRow r) => Connection -> Query -> a -> (a -> r -> m a) -> m a
+fold_ = foldWithOptionsAndParser_ Simple.defaultFoldOptions Simple.fromRow
+
+
+-- | Instrumented version of 'Simple.foldWith_'
+foldWith_ :: MonadUnliftIO m => Simple.RowParser r -> Connection -> Query -> a -> (a -> r -> m a) -> m a
+foldWith_ = foldWithOptionsAndParser_ Simple.defaultFoldOptions
+
+
+-- | Instrumented version of 'Simple.foldWithOptions_'
+foldWithOptions_ :: (HasCallStack, MonadUnliftIO m, FromRow r) => FoldOptions -> Connection -> Query -> a -> (a -> r -> m a) -> m a
+foldWithOptions_ opts = foldWithOptionsAndParser_ opts Simple.fromRow
+
+
+-- | Instrumented version of 'Simple.foldWithOptionsAndParser_'
+foldWithOptionsAndParser_ :: MonadUnliftIO m => FoldOptions -> Simple.RowParser r -> Connection -> Query -> a -> (a -> r -> m a) -> m a
+foldWithOptionsAndParser_ opts parser conn q a f = withRunInIO $ \runInIO -> do
+  statement <- formatQuery conn q ()
+  pgsSpan conn statement $ Simple.foldWithOptionsAndParser_ opts parser conn q a (\a' r -> runInIO (f a' r))
+
+
+{- | Instrumented version of 'Simple.forEach'
+ forEach :: (HasCallStack, MonadUnliftIO m, ToRow q, FromRow r) => Connection -> Query -> q -> (r -> m ()) -> m ()
+-}
+forEach conn template qs f = forEachWith Simple.fromRow
 {-# INLINE forEach #-}
 
--- | A version of 'forEach' taking a parser as an argument
-forEachWith :: (MonadBracketError m, MonadLocalContext m, ToRow q)
-            => Simple.RowParser r
-            -> Connection
-            -> Query
-            -> q
-            -> (r -> m ())
-            -> m ()
-forEachWith parser conn template qs = _
+
+-- | Instrumented version of 'Simple.forEachWith'
+forEachWith :: (HasCallStack, MonadUnliftIO m, ToRow q) => Simple.RowParser r -> Connection -> Query -> q -> (r -> m ()) -> m ()
+forEachWith parser conn template qs = foldWith parser conn template qs () . const
 {-# INLINE forEachWith #-}
 
--- | A version of 'forEach' that does not perform query substitution.
-forEach_ :: (MonadBracketError m, MonadLocalContext m, FromRow r) =>
-            Connection
-         -> Query                -- ^ Query template.
-         -> (r -> m ())         -- ^ Result consumer.
-         -> m ()
-forEach_ = _
+
+-- | Instrumented version of 'Simple.forEach_'
+forEach_ :: (HasCallStack, MonadUnliftIO m, FromRow r) => Connection -> Query -> (r -> m ()) -> m ()
+forEach_ = forEachWith_ Simple.fromRow
 {-# INLINE forEach_ #-}
 
-forEachWith_ :: (MonadBracketError m, MonadLocalContext m) =>
-                Simple.RowParser r
-             -> Connection
-             -> Query
-             -> (r -> m ())
-             -> m ()
-forEachWith_ parser conn template = _
+
+-- | Instrumented version of 'Simple.forEachWith_'
+forEachWith_ :: MonadUnliftIO m => Simple.RowParser r -> Connection -> Query -> (r -> m ()) -> m ()
+forEachWith_ parser conn template = foldWith_ parser conn template () . const
 {-# INLINE forEachWith_ #-}
 
--- | Execute @INSERT ... RETURNING@, @UPDATE ... RETURNING@, or other SQL
--- query that accepts multi-row input and is expected to return results.
--- Note that it is possible to write
---    @'query' conn "INSERT ... RETURNING ..." ...@
--- in cases where you are only inserting a single row,  and do not need
--- functionality analogous to 'executeMany'.
---
--- If the list of parameters is empty,  this function will simply return @[]@
--- without issuing the query to the backend.   If this is not desired,
--- consider using the 'Values' constructor instead.
---
--- Throws 'FormatError' if the query could not be formatted correctly.
-returning :: (MonadIO m, MonadGetContext m, ToRow q, FromRow r) => Connection -> Query -> [q] -> m [r]
-returning = _
 
+-- | Instrumented version of 'Simple.returning'
+returning :: (HasCallStack, MonadIO m, ToRow q, FromRow r) => Connection -> Query -> [q] -> m [r]
+returning = returningWith Simple.fromRow
+
+
 -- | A version of 'returning' taking parser as argument
-returningWith :: (MonadIO m, MonadGetContext m, ToRow q) => Simple.RowParser r -> Connection -> Query -> [q] -> m [r]
-returningWith = _
+returningWith :: (HasCallStack, MonadIO m, ToRow q) => Simple.RowParser r -> Connection -> Query -> [q] -> m [r]
+returningWith parser conn q qs = liftIO $ do
+  statement <- formatMany conn q qs
+  pgsSpan conn statement $ Simple.returningWith parser conn q qs
 
--- | Execute an @INSERT@, @UPDATE@, or other SQL query that is not
--- expected to return results.
---
--- Returns the number of rows affected.
---
--- Throws 'FormatError' if the query could not be formatted correctly, or
--- a 'SqlError' exception if the backend returns an error.
-execute :: (MonadIO m, MonadGetContext m, ToRow q) => Connection -> Query -> q -> m Int64
-execute conn template qs = _
 
--- | A version of 'execute' that does not perform query substitution.
-execute_ :: (MonadIO m, MonadGetContext m) => Connection -> Query -> m Int64
-execute_ = _
+-- | Instrumented version of 'Simple.execute'
+execute :: (HasCallStack, MonadIO m, ToRow q) => Connection -> Query -> q -> m Int64
+execute conn template qs = liftIO $ do
+  statement <- formatQuery conn template qs
+  pgsSpan conn statement $ Simple.execute conn template qs
 
--- | 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,
--- this function will simply return 0 without issuing the query to the backend.
--- If this is not desired, consider using the 'Values' constructor instead.
---
--- Throws 'FormatError' if the query could not be formatted correctly, or
--- a 'SqlError' exception if the backend returns an error.
---
--- For example,  here's a command that inserts two rows into a table
--- with two columns:
---
--- @
--- executeMany c [sql|
---     INSERT INTO sometable VALUES (?,?)
---  |] [(1, \"hello\"),(2, \"world\")]
--- @
---
--- Here's an canonical example of a multi-row update command:
---
--- @
--- executeMany c [sql|
---     UPDATE sometable
---        SET y = upd.y
---       FROM (VALUES (?,?)) as upd(x,y)
---      WHERE sometable.x = upd.x
---  |] [(1, \"hello\"),(2, \"world\")]
--- @
 
-executeMany :: (MonadIO m, MonadGetContext m, ToRow q) => Connection -> Query -> [q] -> m Int64
-executeMany = _
--}
+-- | Instrumented version of 'Simple.execute_'
+execute_ :: MonadIO m => Connection -> Query -> m Int64
+execute_ conn q = liftIO $ do
+  statement <- formatQuery conn q ()
+  pgsSpan conn statement $ Simple.execute_ conn q
+
+
+-- | Instrumented version of 'Simple.executeMany'
+executeMany :: (HasCallStack, MonadIO m, ToRow q) => Connection -> Query -> [q] -> m Int64
+executeMany conn q qs = liftIO $ do
+  statement <- formatMany conn q qs
+  pgsSpan conn statement $ Simple.executeMany conn q qs
diff --git a/test/Spec.hs b/test/Spec.hs
deleted file mode 100644
--- a/test/Spec.hs
+++ /dev/null
@@ -1,3 +0,0 @@
-
-main :: IO ()
-main = putStrLn "Test suite not yet implemented"
