diff --git a/hasql-postgres.cabal b/hasql-postgres.cabal
--- a/hasql-postgres.cabal
+++ b/hasql-postgres.cabal
@@ -1,12 +1,18 @@
 name:
   hasql-postgres
 version:
-  0.1.3
+  0.2.0
 synopsis:
   A "PostgreSQL" backend for the "hasql" library
 description:
   This library provides a \"PostgreSQL\" driver for 
   <http://hackage.haskell.org/package/hasql the "hasql" library>.
+  .
+  According to the included benchmarks,
+  it performs up to 2.5x faster than \"postgresql-simple\" and
+  up to 8x faster than \"HDBC\".
+  You can read up
+  <http://nikita-volkov.github.io/hasql-benchmarks/ a post with analysis of those benchmarks>.
 category:
   Database
 homepage:
@@ -47,12 +53,10 @@
     Haskell2010
   other-modules:
     Hasql.Postgres.Prelude
-    Hasql.Postgres.Renderer
     Hasql.Postgres.ErrorCode
     Hasql.Postgres.PTI
-    Hasql.Postgres.OIDMapping
+    Hasql.Postgres.Mapping
     Hasql.Postgres.Statement
-    Hasql.Postgres.Parser
     Hasql.Postgres.StatementPreparer
     Hasql.Postgres.TemplateConverter
     Hasql.Postgres.TemplateConverter.Parser
@@ -68,19 +72,18 @@
     attoparsec == 0.12.*,
     -- database:
     hasql-backend == 0.1.*,
+    postgresql-binary == 0.1.*,
     postgresql-libpq == 0.9.*,
     -- data:
-    base16-bytestring == 0.1.*,
+    uuid == 1.3.*,
     vector == 0.10.*,
-    old-locale == 1.0.*,
-    time == 1.4.*,
+    time >= 1.4 && < 1.6,
     hashtables == 1.1.*,
     scientific == 0.3.*,
     text >= 1 && < 1.3,
     bytestring >= 0.10.4.0 && < 0.11,
     hashable == 1.2.*,
     -- control:
-    mmorph == 1.0.*,
     list-t >= 0.2.3 && < 0.3,
     -- errors:
     loch-th == 0.2.*,
@@ -118,22 +121,19 @@
     -- parsers:
     attoparsec == 0.12.*,
     -- database:
-    hasql == 0.1.*,
+    hasql >= 0.1.4 && < 0.2,
+    postgresql-binary == 0.1.*,
     postgresql-libpq == 0.9.*,
     -- data:
-    base16-bytestring == 0.1.*,
+    uuid == 1.3.*,
     vector == 0.10.*,
-    utf8-string >= 0.3.8 && < 0.4,
-    old-locale == 1.0.*,
-    time == 1.4.*,
+    time >= 1.4 && < 1.6,
     hashtables == 1.1.*,
-    Decimal == 0.4.*,
     scientific == 0.3.*,
     text >= 1 && < 1.3,
     bytestring >= 0.10.4.0 && < 0.11,
     hashable == 1.2.*,
     -- control:
-    mmorph == 1.0.*,
     list-t >= 0.2.3 && < 0.3,
     -- errors:
     loch-th == 0.2.*,
@@ -162,7 +162,7 @@
   build-depends:
     hasql-postgres,
     hasql-backend,
-    hasql == 0.1.*,
+    hasql >= 0.1.4 && < 0.2,
     -- testing:
     HTF == 0.12.*,
     quickcheck-instances == 0.3.*,
@@ -174,7 +174,7 @@
     -- data:
     vector == 0.10.*,
     old-locale == 1.0.*,
-    time == 1.4.*,
+    time >= 1.4 && < 1.6,
     scientific == 0.3.*,
     text >= 1 && < 1.3,
     bytestring >= 0.10.4.0 && < 0.11,
@@ -208,7 +208,7 @@
     postgresql-simple == 0.4.*,
     hasql-postgres,
     hasql-backend,
-    hasql == 0.1.*,
+    hasql >= 0.1.4 && < 0.2,
     -- random:
     QuickCheck == 2.7.*,
     quickcheck-instances == 0.3.*,
@@ -216,7 +216,7 @@
     criterion-plus == 0.1.*,
     -- data:
     vector == 0.10.*,
-    time == 1.4.*,
+    time >= 1.4 && < 1.6,
     text >= 1 && < 1.3,
     scientific == 0.3.*,
     -- general:
@@ -250,13 +250,13 @@
     postgresql-simple == 0.4.*,
     hasql-postgres,
     hasql-backend,
-    hasql == 0.1.*,
+    hasql >= 0.1.4 && < 0.2,
     -- random:
     QuickCheck == 2.7.*,
     quickcheck-instances == 0.3.*,
     -- data:
     vector == 0.10.*,
-    time == 1.4.*,
+    time >= 1.4 && < 1.6,
     text >= 1 && < 1.3,
     scientific == 0.3.*,
     -- general:
diff --git a/library-tests/Main.hs b/library-tests/Main.hs
--- a/library-tests/Main.hs
+++ b/library-tests/Main.hs
@@ -4,8 +4,6 @@
 import Test.Framework
 import Hasql.Postgres.Prelude
 
-import {-@ HTF_TESTS @-} Hasql.Postgres.ParserTests
-import {-@ HTF_TESTS @-} Hasql.Postgres.ParserAndRendererTests
 import {-@ HTF_TESTS @-} Hasql.Postgres.TemplateConverterTests
 
 main = 
diff --git a/library/Hasql/Postgres.hs b/library/Hasql/Postgres.hs
--- a/library/Hasql/Postgres.hs
+++ b/library/Hasql/Postgres.hs
@@ -1,3 +1,16 @@
+-- |
+-- This module contains everything required 
+-- to use \"hasql\" with Postgres.
+-- For information on how it should be used consult the \"hasql\" docs.
+-- 
+-- Please note that there is a few limitations inflicted by Postgres,
+-- encoding which in the type system would seriously burden the API,
+-- so it was decided to make it the user's responsibility 
+-- to make sure that certain conditions are satisfied during the runtime.
+-- Particularly this concerns the 'Backend.Mapping' instances of 
+-- @Maybe@, @[]@ and @Vector@.
+-- For details consult the docs on those instances.
+-- 
 module Hasql.Postgres 
 (
   Postgres(..), 
@@ -13,12 +26,12 @@
 import qualified Hasql.Postgres.Statement as Statement
 import qualified Hasql.Postgres.StatementPreparer as StatementPreparer
 import qualified Hasql.Postgres.TemplateConverter as TemplateConverter
-import qualified Hasql.Postgres.Parser as Parser
-import qualified Hasql.Postgres.Renderer as Renderer
-import qualified Hasql.Postgres.OIDMapping as OIDMapping
+import qualified Hasql.Postgres.PTI as PTI
+import qualified Hasql.Postgres.Mapping as Mapping
+import qualified Language.Haskell.TH as TH
+import qualified Data.Attoparsec.ByteString.Char8 as Atto
 import qualified Data.Text.Encoding as Text
 import qualified ListT
-import qualified Language.Haskell.TH as TH
 
 
 -- |
@@ -59,6 +72,7 @@
   execute s c = 
     ResultHandler.unit =<< execute (liftStatement s) c
   executeAndGetMatrix s c =
+    {-# SCC "executeAndGetMatrix" #-} 
     unsafeCoerce . ResultHandler.rowsVector =<< execute (liftStatement s) c
   executeAndStream s c =
     do
@@ -76,7 +90,7 @@
           counterM <- readIORef (transactionState c)
           counter <- maybe (throwIO Backend.NotInTransaction) return counterM
           writeIORef (transactionState c) (Just (succ counter))
-          return $ Renderer.run counter $ \n -> Renderer.char 'v' <> Renderer.word n
+          return $ fromString $ 'v' : show counter
       declareCursor =
         do
           name <- nextName
@@ -89,9 +103,9 @@
   executeAndCountEffects s c =
     do
       b <- ResultHandler.rowsAffected =<< execute (liftStatement s) c
-      case Parser.run b Parser.unsignedIntegral of
+      case Atto.parseOnly (Atto.decimal <* Atto.endOfInput) b of
         Left m -> 
-          throwIO $ Backend.UnexpectedResult m
+          throwIO $ Backend.UnexpectedResult (fromString m)
         Right r ->
           return r
   beginTransaction (isolation, write) c = 
@@ -123,10 +137,10 @@
       True -> do
         let (tl, vl) = unzip params
         key <- StatementPreparer.prepare convertedTemplate tl (preparer c)
-        PQ.execPrepared (connection c) key vl PQ.Text
+        PQ.execPrepared (connection c) key vl PQ.Binary
       False -> do
         let params' = map (\(t, v) -> (\(vb, vf) -> (t, vb, vf)) <$> v) params
-        PQ.execParams (connection c) convertedTemplate params' PQ.Text
+        PQ.execParams (connection c) convertedTemplate params' PQ.Binary
 
 convertTemplate :: ByteString -> IO ByteString
 convertTemplate t =
@@ -142,96 +156,255 @@
 
 -- * Mappings
 -------------------------
-
--- ** Helpers
+-- Not using TH to generate instances
+-- to be able to document them.
 -------------------------
 
--- |
--- Make a 'renderValue' function.
-{-# INLINE mkRenderValue #-}
-mkRenderValue :: PQ.Format -> PQ.Oid -> Renderer.R a -> (a -> Backend.StatementArgument Postgres)
-mkRenderValue f o r a =
-  StatementArgument (o, Just (Renderer.run a r, f))
 
-{-# INLINE mkParseResult #-}
-mkParseResult :: Parser.P a -> (Backend.Result Postgres -> Either Text a)
-mkParseResult p (Result r) =
-  do
-    r' <- maybe (Left "Null result") Right r
-    left (\t -> t <> "; Input: " <> (fromString . show) r') $ 
-      Parser.run r' p
-
--- ** Instances
--------------------------
+{-# INLINE renderValueUsingMapping #-}
+renderValueUsingMapping :: Mapping.Mapping a => a -> Backend.StatementArgument Postgres
+renderValueUsingMapping x = 
+  StatementArgument (oid, (,) <$> value <*> pure PQ.Binary)
+  where
+    oid = PTI.oidPQ $ Mapping.oid x
+    value = Mapping.encode x
 
--- | Maps to the same type as the underlying value, 
--- encoding the 'Nothing' as /NULL/.
-instance Backend.Mapping Postgres a => Backend.Mapping Postgres (Maybe a) where
-  renderValue =
-    \case
-      Nothing -> 
-        case Backend.renderValue ($bottom :: a) of
-          StatementArgument (oid, _) -> StatementArgument (oid, Nothing)
-      Just v ->
-        Backend.renderValue v
-  parseResult = 
-    traverse (Backend.parseResult . Result . Just) . unpackResult
+{-# INLINE parseResultUsingMapping #-}
+parseResultUsingMapping :: Mapping.Mapping a => Backend.Result Postgres -> Either Text a
+parseResultUsingMapping (Result x) = 
+  Mapping.decode x
 
-instance (Backend.Mapping Postgres a, Renderer.Renderable a, Parser.Parsable a, OIDMapping.OIDMapping a) => 
-         Backend.Mapping Postgres (Vector a) where
-  renderValue = 
-    mkRenderValue PQ.Text (OIDMapping.identifyOID (undefined :: Vector a)) (Renderer.renderer Nothing)
-  parseResult = 
-    mkParseResult (Parser.parser Nothing)
+-- | 
+-- Maps to the same type as the underlying value, 
+-- encoding 'Nothing' as /NULL/.
+-- 
+-- /LIMITATION/
+-- 
+-- Multilevel 'Maybe's are not supported.
+-- E.g., a value @Just Nothing@ of type @(Maybe (Maybe a))@ 
+-- will be encoded the same way as @Nothing@.
+instance Mapping.Mapping a => Backend.Mapping Postgres (Maybe a) where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
 
 -- |
 -- Maps to Postgres arrays. 
 -- 
--- Please note that since @String@ is just an alias to @[Char]@,
+-- /LIMITATION 1/
+-- 
+-- In multidimensional lists all rows of a dimension must have the same length.
+-- 
+-- E.g., the following is a corrupt value:
+-- 
+-- > [[1,2], [3]]
+-- 
+-- The following is a valid one:
+-- 
+-- > [[1,2], [3,4], [5,6]]
+-- 
+-- /LIMITATION 2/
+-- 
+-- 'Maybe' cannot be used to wrap an intermediate level in a multidimensional array.
+-- 
+-- E.g., the following is a corrupt type:
+-- 
+-- > [Maybe [a]]
+-- 
+-- However, both the first level list and the value are allowed to be wrapped in 'Maybe'.
+-- So the following is a valid type:
+-- 
+-- > Maybe [[[Maybe a]]]
+-- 
+-- /NOTICE/
+-- 
+-- Also, please note that since 'String' is just an alias to @['Char']@,
 -- it will be mapped to an array of characters. 
--- If you want to map to a textual type use @Text@ instead.
-instance (Backend.Mapping Postgres a, Renderer.Renderable a, Parser.Parsable a, OIDMapping.OIDMapping a) => 
-         Backend.Mapping Postgres [a] where
-  renderValue = 
-    mkRenderValue PQ.Text (OIDMapping.identifyOID (undefined :: [a])) (Renderer.renderer Nothing)
-  parseResult = 
-    mkParseResult (Parser.parser Nothing)
+-- So if you want to map to a textual type use 'Text' instead.
+-- 
+instance (Mapping.Mapping a, Mapping.ArrayMapping a) => Backend.Mapping Postgres [a] where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
 
-let
-  types =
-    [ ''Bool,
-      ''Int,
-      ''Int8,
-      ''Int16,
-      ''Int32,
-      ''Int64,
-      ''Word,
-      ''Word8,
-      ''Word16,
-      ''Word32,
-      ''Word64,
-      ''Float,
-      ''Double,
-      ''Scientific,
-      ''Day,
-      ''TimeOfDay,
-      ''LocalTime,
-      ''ZonedTime,
-      ''UTCTime,
-      ''Char,
-      ''Text,
-      ''LazyText,
-      ''ByteString,
-      ''LazyByteString ]
-  in
-    fmap concat $ forM types $ \t ->
-      [d|
-        instance Backend.Mapping Postgres $(TH.conT t) where
-          renderValue = 
-            mkRenderValue 
-              PQ.Text 
-              (OIDMapping.identifyOID (undefined :: $(TH.conT t)))
-              (Renderer.renderer Nothing)
-          parseResult =
-            mkParseResult (Parser.parser Nothing)
-      |]
+-- |
+-- Maps to Postgres' arrays.
+-- 
+-- Same rules as for the list instance apply. 
+-- Consult its docs for details.
+instance (Mapping.Mapping a, Mapping.ArrayMapping a) => Backend.Mapping Postgres (Vector a) where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @int8@.
+instance Backend.Mapping Postgres Int where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @int2@.
+instance Backend.Mapping Postgres Int8 where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @int2@.
+instance Backend.Mapping Postgres Int16 where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @int4@.
+instance Backend.Mapping Postgres Int32 where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @int8@.
+instance Backend.Mapping Postgres Int64 where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @int8@.
+instance Backend.Mapping Postgres Word where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @int2@.
+instance Backend.Mapping Postgres Word8 where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @int2@.
+instance Backend.Mapping Postgres Word16 where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @int4@.
+instance Backend.Mapping Postgres Word32 where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @int8@.
+instance Backend.Mapping Postgres Word64 where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @float4@.
+instance Backend.Mapping Postgres Float where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @float8@.
+instance Backend.Mapping Postgres Double where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @numeric@.
+instance Backend.Mapping Postgres Scientific where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @date@.
+instance Backend.Mapping Postgres Day where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @time@.
+instance Backend.Mapping Postgres TimeOfDay where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @timetz@.
+-- 
+-- Unlike with @timestamptz@, 
+-- Postgres does store the timezone information for @timetz@.
+-- However the \"time\" library does not contain any composite type,
+-- that fits the task, so we use a pair of 'TimeOfDay' and 'TimeZone'
+-- to represent a value on the Haskell's side.
+instance Backend.Mapping Postgres (TimeOfDay, TimeZone) where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @timestamptz@.
+-- 
+-- /NOTICE/
+-- 
+-- Postgres does not store the timezone information of @timestamptz@.
+-- Instead it stores a UTC value and silently interconverts 
+-- the incoming and outgoing values into a local time 
+-- of the client application according to client application's timezone.
+-- 
+-- This is a notoriously questionable design decision by the Postgres authors.
+-- This is why it is instead recommended to use @timestamp@ and 'UTCTime',
+-- while manually handling the timezone conversions on the application side.
+instance Backend.Mapping Postgres LocalTime where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @timestamp@.
+instance Backend.Mapping Postgres UTCTime where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @interval@.
+instance Backend.Mapping Postgres DiffTime where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @char@.
+-- Note that it supports UTF-8 values.
+instance Backend.Mapping Postgres Char where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @text@.
+instance Backend.Mapping Postgres Text where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @text@.
+instance Backend.Mapping Postgres LazyText where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @bytea@.
+instance Backend.Mapping Postgres ByteString where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @bytea@.
+instance Backend.Mapping Postgres LazyByteString where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @bool@.
+instance Backend.Mapping Postgres Bool where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
+-- |
+-- Maps to @uuid@.
+instance Backend.Mapping Postgres UUID where
+  renderValue = renderValueUsingMapping
+  parseResult = parseResultUsingMapping
+
diff --git a/library/Hasql/Postgres/Connector.hs b/library/Hasql/Postgres/Connector.hs
--- a/library/Hasql/Postgres/Connector.hs
+++ b/library/Hasql/Postgres/Connector.hs
@@ -4,7 +4,10 @@
 
 import Hasql.Postgres.Prelude hiding (Error)
 import qualified Database.PostgreSQL.LibPQ as L
-import qualified Hasql.Postgres.Renderer as Renderer
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Builder as BB
+import qualified Data.ByteString.Lazy as BL
+import qualified Data.Text.Encoding as TE
 
 
 data Settings =
@@ -35,7 +38,7 @@
 open :: Settings -> ExceptT Error IO L.Connection
 open s =
   do
-    c <- lift $ L.connectdb (Renderer.run s settingsRenderer)
+    c <- lift $ L.connectdb (settingsBS s)
     do
       s <- lift $ L.status c
       when (s /= L.ConnectionOk) $ 
@@ -54,15 +57,16 @@
     return c
 
 
-settingsRenderer :: Renderer.R Settings
-settingsRenderer s =
+settingsBS :: Settings -> ByteString
+settingsBS s =
+  BL.toStrict $ BB.toLazyByteString $ 
   mconcat $ intersperse " " args
   where
     args =
       [
-        "host="     <> Renderer.byteString (host s),
-        "port="     <> Renderer.word16 (port s),
-        "user="     <> Renderer.text (user s),
-        "password=" <> Renderer.text (password s),
-        "dbname="   <> Renderer.text (database s)
+        "host="     <> BB.byteString (host s),
+        "port="     <> BB.word16Dec (port s),
+        "user="     <> TE.encodeUtf8Builder (user s),
+        "password=" <> TE.encodeUtf8Builder (password s),
+        "dbname="   <> TE.encodeUtf8Builder (database s)
       ]
diff --git a/library/Hasql/Postgres/Mapping.hs b/library/Hasql/Postgres/Mapping.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/Postgres/Mapping.hs
@@ -0,0 +1,166 @@
+-- |
+-- Internal mappings.
+module Hasql.Postgres.Mapping where
+
+import Hasql.Postgres.Prelude hiding (bool)
+import qualified Language.Haskell.TH as TH
+import qualified Hasql.Postgres.PTI as PTI
+import qualified Data.Vector as V
+import qualified Data.ByteString.Lazy as BL
+import qualified Data.Text.Lazy as TL
+import qualified PostgreSQLBinary.Array as Array
+import qualified PostgreSQLBinary.Encoder as Encoder
+import qualified PostgreSQLBinary.Decoder as Decoder
+
+
+type Value =
+  Maybe ByteString
+
+-- |
+-- A final value level mapping.
+class Mapping a where
+  oid :: a -> PTI.OID
+  encode :: a -> Value
+  decode :: Value -> Either Text a
+
+-- |
+-- A mapping for construction of array values.
+class ArrayMapping a where
+  arrayOID :: a -> PTI.OID
+  arrayEncode :: a -> Array.Data
+  arrayDecode :: Array.Data -> Either Text a
+
+
+instance Mapping a => Mapping (Maybe a) where
+  oid = 
+    const $ oid (undefined :: a)
+  encode = 
+    join . traverse encode
+  decode = 
+    maybe (return Nothing) (fmap Just . decode . Just)
+
+instance (ArrayMapping a, Mapping a) => ArrayMapping (Maybe a) where
+  arrayOID =
+    const $ arrayOID (undefined :: a)
+  arrayEncode =
+    \case
+      Nothing -> 
+        Array.fromSingleton Nothing True (PTI.oidWord32 (oid (undefined :: a)))
+      Just x ->
+        setNullable True $ arrayEncode x
+        where
+          setNullable x (dl, vl, _, oid) = (dl, vl, True, oid)
+  arrayDecode =
+    \case
+      (_, [x], _, _) -> decode x
+      x -> Left $ "Array data doesn't match the 'Maybe' type: " <> (fromString . show) x
+
+
+instance (Mapping a, ArrayMapping a) => Mapping [a] where
+  oid = 
+    arrayOID
+  encode = 
+    Just . Encoder.array . arrayEncode
+  decode x = 
+    do
+      b <- maybe (Left "NULL input") return x
+      a <- Decoder.array b
+      arrayDecode a
+
+instance (Mapping a, ArrayMapping a) => ArrayMapping [a] where
+  arrayOID =
+    const $ arrayOID (undefined :: a)
+  arrayEncode =
+    \case
+      [] -> ([(0, 1)], [], False, PTI.oidWord32 $ oid (undefined :: a))
+      x -> Array.fromListUnsafe . map arrayEncode $ x
+  arrayDecode x =
+    traverse arrayDecode $ Array.elements x
+
+
+instance (Mapping a, ArrayMapping a) => Mapping (Vector a) where
+  oid =
+    arrayOID
+  encode = 
+    Just . Encoder.array . arrayEncode
+  decode x = 
+    do
+      b <- maybe (Left "NULL input") return x
+      a <- Decoder.array b
+      arrayDecode a
+
+instance (Mapping a, ArrayMapping a) => ArrayMapping (Vector a) where
+  arrayOID =
+    const $ arrayOID (undefined :: a)
+  arrayEncode =
+    arrayEncode . V.toList
+  arrayDecode =
+    fmap V.fromList . arrayDecode
+
+
+let
+  settings =
+    [ 
+      ([t|Int|], [|PTI.int8|], [|Encoder.int8 . Left . fromIntegral|], [|Decoder.int|]),
+      ([t|Int8|], [|PTI.int2|], [|Encoder.int2 . Left . fromIntegral|], [|Decoder.int|]),
+      ([t|Int16|], [|PTI.int2|], [|Encoder.int2 . Left|], [|Decoder.int|]),
+      ([t|Int32|], [|PTI.int4|], [|Encoder.int4 . Left|], [|Decoder.int|]),
+      ([t|Int64|], [|PTI.int8|], [|Encoder.int8 . Left|], [|Decoder.int|]),
+      ([t|Word|], [|PTI.int8|], [|Encoder.int8 . Right . fromIntegral|], [|Decoder.int|]),
+      ([t|Word8|], [|PTI.int2|], [|Encoder.int2 . Right . fromIntegral|], [|Decoder.int|]),
+      ([t|Word16|], [|PTI.int2|], [|Encoder.int2 . Right|], [|Decoder.int|]),
+      ([t|Word32|], [|PTI.int4|], [|Encoder.int4 . Right|], [|Decoder.int|]),
+      ([t|Word64|], [|PTI.int8|], [|Encoder.int8 . Right|], [|Decoder.int|]),
+      ([t|Float|], [|PTI.float4|], [|Encoder.float4|], [|Decoder.float4|]),
+      ([t|Double|], [|PTI.float8|], [|Encoder.float8|], [|Decoder.float8|]),
+      ([t|Scientific|], [|PTI.numeric|], [|Encoder.numeric|], [|Decoder.numeric|]),
+      ([t|Day|], [|PTI.date|], [|Encoder.date|], [|Decoder.date|]),
+      ([t|TimeOfDay|], [|PTI.time|], [|Encoder.time|], [|Decoder.time|]),
+      ([t|(TimeOfDay, TimeZone)|], [|PTI.timetz|], [|Encoder.timetz|], [|Decoder.timetz|]),
+      ([t|UTCTime|], [|PTI.timestamp|], [|Encoder.timestamp|], [|Decoder.timestamp|]),
+      ([t|LocalTime|], [|PTI.timestamptz|], [|Encoder.timestamptz|], [|Decoder.timestamptz|]),
+      ([t|DiffTime|], [|PTI.interval|], [|Encoder.interval|], [|Decoder.interval|]),
+      ([t|Char|], [|PTI.text|], [|Encoder.char|], [|Decoder.char|]),
+      ([t|Text|], [|PTI.text|], [|Encoder.text . Left|], [|Decoder.text|]),
+      ([t|LazyText|], [|PTI.text|], [|Encoder.text . Right|], [|fmap TL.fromStrict . Decoder.text|]),
+      ([t|ByteString|], [|PTI.bytea|], [|Encoder.bytea . Left|], [|Decoder.bytea|]),
+      ([t|LazyByteString|], [|PTI.bytea|], [|Encoder.bytea . Right|], [|fmap BL.fromStrict . Decoder.bytea|]),
+      ([t|Bool|], [|PTI.bool|], [|Encoder.bool|], [|Decoder.bool|]),
+      ([t|UUID|], [|PTI.uuid|], [|Encoder.uuid|], [|Decoder.uuid|])
+    ]
+  in
+    fmap concat $ forM settings $ \(t, pti, encoder, decoder) ->
+      [d|
+
+        instance Mapping $t where
+          {-# INLINE oid #-}
+          oid =
+            const $ PTI.ptiOID $pti
+          {-# INLINE encode #-}
+          encode =
+            Just . $encoder
+          {-# INLINE decode #-}
+          decode x =
+            do
+              b <- maybe (Left "NULL input") return x
+              $decoder b
+
+        instance ArrayMapping $t where
+          {-# INLINE arrayOID #-}
+          arrayOID =
+            const $ fromMaybe ($bug "No array OID") $ PTI.ptiArrayOID $pti
+          {-# INLINE arrayEncode #-}
+          arrayEncode x =
+            Array.fromSingleton (Just ($encoder x))
+                                    (False)
+                                    (PTI.oidWord32 (PTI.ptiOID $pti))
+          {-# INLINE arrayDecode #-}
+          arrayDecode =
+            \case
+              (_, [x], _, _) -> decode x
+              x -> Left $ "Array data doesn't match the '" <> 
+                          $(t >>= TH.stringE . show) <> "' type: " <> 
+                          (fromString . show) x
+
+      |]
+
diff --git a/library/Hasql/Postgres/OIDMapping.hs b/library/Hasql/Postgres/OIDMapping.hs
deleted file mode 100644
--- a/library/Hasql/Postgres/OIDMapping.hs
+++ /dev/null
@@ -1,63 +0,0 @@
-module Hasql.Postgres.OIDMapping where
-
-import Hasql.Postgres.Prelude hiding (bool)
-import Database.PostgreSQL.LibPQ (Oid(..))
-import qualified Language.Haskell.TH as TH
-import qualified Hasql.Postgres.PTI as PTI
-
-
-class OIDMapping a where
-  identifyOID :: a -> Oid
-  identifyArrayOID :: a -> Oid
-
-instance OIDMapping a => OIDMapping (Maybe a) where
-  identifyOID = const $ identifyOID (undefined :: a)
-  identifyArrayOID = const $ identifyArrayOID (undefined :: a)
-
-instance OIDMapping a => OIDMapping [a] where
-  identifyOID = const $ identifyArrayOID (undefined :: a)
-  identifyArrayOID = identifyOID
-
-instance OIDMapping a => OIDMapping (Vector a) where
-  identifyOID = const $ identifyArrayOID (undefined :: a)
-  identifyArrayOID = identifyOID
-
-let
-  mappings =
-    [ (''Bool          , PTI.bool       ),
-      (''Int           , PTI.int8       ),
-      (''Int8          , PTI.int2       ),
-      (''Int16         , PTI.int2       ),
-      (''Int32         , PTI.int4       ),
-      (''Int64         , PTI.int8       ),
-      (''Word          , PTI.int8       ),
-      (''Word8         , PTI.int2       ),
-      (''Word16        , PTI.int4       ),
-      (''Word32        , PTI.int8       ),
-      (''Word64        , PTI.int8       ),
-      (''Float         , PTI.float4     ),
-      (''Double        , PTI.float8     ),
-      (''Scientific    , PTI.numeric    ),
-      (''Day           , PTI.date       ),
-      (''TimeOfDay     , PTI.time       ),
-      (''LocalTime     , PTI.timestamp  ),
-      (''ZonedTime     , PTI.timestamptz),
-      (''UTCTime       , PTI.timestamp  ),
-      (''Char          , PTI.varchar    ),
-      (''Text          , PTI.text       ),
-      (''LazyText      , PTI.text       ),
-      (''ByteString    , PTI.bytea      ),
-      (''LazyByteString, PTI.bytea      ) ]
-  oidInt (Oid x) = 
-    fromIntegral x
-  in
-    fmap join $ forM mappings $ \(t, pti) ->
-      [d|
-        instance OIDMapping $(TH.conT t) where
-          {-# INLINE identifyOID #-}
-          identifyOID = 
-            const $ Oid $(TH.litE $ TH.integerL $ oidInt $ PTI.oidOf pti)
-          {-# INLINE identifyArrayOID #-}
-          identifyArrayOID =
-            const $ Oid $(TH.litE $ TH.integerL $ oidInt $ fromMaybe (PTI.oidOf PTI.unknown) (PTI.arrayOIDOf pti))
-      |]
diff --git a/library/Hasql/Postgres/PTI.hs b/library/Hasql/Postgres/PTI.hs
--- a/library/Hasql/Postgres/PTI.hs
+++ b/library/Hasql/Postgres/PTI.hs
@@ -1,78 +1,93 @@
 module Hasql.Postgres.PTI where
 
 import Hasql.Postgres.Prelude hiding (bool)
-import Database.PostgreSQL.LibPQ (Oid(..))
+import qualified Database.PostgreSQL.LibPQ as PQ
 
 
 -- | A Postgresql type info
-data PTI = PTI { oidOf :: Oid, arrayOIDOf :: Maybe Oid }
+data PTI = PTI { ptiOID :: !OID, ptiArrayOID :: !(Maybe OID) }
 
-abstime         = PTI (Oid 702)  (Just (Oid 1023))
-aclitem         = PTI (Oid 1033) (Just (Oid 1034))
-bit             = PTI (Oid 1560) (Just (Oid 1561))
-bool            = PTI (Oid 16)   (Just (Oid 1000))
-box             = PTI (Oid 603)  (Just (Oid 1020))
-bpchar          = PTI (Oid 1042) (Just (Oid 1014))
-bytea           = PTI (Oid 17)   (Just (Oid 1001))
-char            = PTI (Oid 18)   (Just (Oid 1002))
-cid             = PTI (Oid 29)   (Just (Oid 1012))
-cidr            = PTI (Oid 650)  (Just (Oid 651))
-circle          = PTI (Oid 718)  (Just (Oid 719))
-cstring         = PTI (Oid 2275) (Just (Oid 1263))
-date            = PTI (Oid 1082) (Just (Oid 1182))
-daterange       = PTI (Oid 3912) (Just (Oid 3913))
-float4          = PTI (Oid 700)  (Just (Oid 1021))
-float8          = PTI (Oid 701)  (Just (Oid 1022))
-gtsvector       = PTI (Oid 3642) (Just (Oid 3644))
-inet            = PTI (Oid 869)  (Just (Oid 1041))
-int2            = PTI (Oid 21)   (Just (Oid 1005))
-int2vector      = PTI (Oid 22)   (Just (Oid 1006))
-int4            = PTI (Oid 23)   (Just (Oid 1007))
-int4range       = PTI (Oid 3904) (Just (Oid 3905))
-int8            = PTI (Oid 20)   (Just (Oid 1016))
-int8range       = PTI (Oid 3926) (Just (Oid 3927))
-interval        = PTI (Oid 1186) (Just (Oid 1187))
-json            = PTI (Oid 114)  (Just (Oid 199))
-line            = PTI (Oid 628)  (Just (Oid 629))
-lseg            = PTI (Oid 601)  (Just (Oid 1018))
-macaddr         = PTI (Oid 829)  (Just (Oid 1040))
-money           = PTI (Oid 790)  (Just (Oid 791))
-name            = PTI (Oid 19)   (Just (Oid 1003))
-numeric         = PTI (Oid 1700) (Just (Oid 1231))
-numrange        = PTI (Oid 3906) (Just (Oid 3907))
-oid             = PTI (Oid 26)   (Just (Oid 1028))
-oidvector       = PTI (Oid 30)   (Just (Oid 1013))
-path            = PTI (Oid 602)  (Just (Oid 1019))
-point           = PTI (Oid 600)  (Just (Oid 1017))
-polygon         = PTI (Oid 604)  (Just (Oid 1027))
-record          = PTI (Oid 2249) (Just (Oid 2287))
-refcursor       = PTI (Oid 1790) (Just (Oid 2201))
-regclass        = PTI (Oid 2205) (Just (Oid 2210))
-regconfig       = PTI (Oid 3734) (Just (Oid 3735))
-regdictionary   = PTI (Oid 3769) (Just (Oid 3770))
-regoper         = PTI (Oid 2203) (Just (Oid 2208))
-regoperator     = PTI (Oid 2204) (Just (Oid 2209))
-regproc         = PTI (Oid 24)   (Just (Oid 1008))
-regprocedure    = PTI (Oid 2202) (Just (Oid 2207))
-regtype         = PTI (Oid 2206) (Just (Oid 2211))
-reltime         = PTI (Oid 703)  (Just (Oid 1024))
-text            = PTI (Oid 25)   (Just (Oid 1009))
-tid             = PTI (Oid 27)   (Just (Oid 1010))
-time            = PTI (Oid 1083) (Just (Oid 1183))
-timestamp       = PTI (Oid 1114) (Just (Oid 1115))
-timestamptz     = PTI (Oid 1184) (Just (Oid 1185))
-timetz          = PTI (Oid 1266) (Just (Oid 1270))
-tinterval       = PTI (Oid 704)  (Just (Oid 1025))
-tsquery         = PTI (Oid 3615) (Just (Oid 3645))
-tsrange         = PTI (Oid 3908) (Just (Oid 3909))
-tstzrange       = PTI (Oid 3910) (Just (Oid 3911))
-tsvector        = PTI (Oid 3614) (Just (Oid 3643))
-txid_snapshot   = PTI (Oid 2970) (Just (Oid 2949))
-unknown         = PTI (Oid 705)  Nothing
-uuid            = PTI (Oid 2950) (Just (Oid 2951))
-varbit          = PTI (Oid 1562) (Just (Oid 1563))
-varchar         = PTI (Oid 1043) (Just (Oid 1015))
-void            = PTI (Oid 2278) Nothing
-xid             = PTI (Oid 28)   (Just (Oid 1011))
-xml             = PTI (Oid 142)  (Just (Oid 143))
+-- | A Word32 and a LibPQ representation of an OID
+data OID = OID { oidWord32 :: !Word32, oidPQ :: !PQ.Oid }
+
+mkOID :: Word32 -> OID
+mkOID x =
+  OID x ((PQ.Oid . fromIntegral) x)
+
+mkPTI :: Word32 -> Maybe Word32 -> PTI
+mkPTI oid arrayOID =
+  PTI (mkOID oid) (fmap mkOID arrayOID)
+
+
+-- * Constants
+-------------------------
+
+abstime         = mkPTI 702  (Just 1023)
+aclitem         = mkPTI 1033 (Just 1034)
+bit             = mkPTI 1560 (Just 1561)
+bool            = mkPTI 16   (Just 1000)
+box             = mkPTI 603  (Just 1020)
+bpchar          = mkPTI 1042 (Just 1014)
+bytea           = mkPTI 17   (Just 1001)
+char            = mkPTI 18   (Just 1002)
+cid             = mkPTI 29   (Just 1012)
+cidr            = mkPTI 650  (Just 651)
+circle          = mkPTI 718  (Just 719)
+cstring         = mkPTI 2275 (Just 1263)
+date            = mkPTI 1082 (Just 1182)
+daterange       = mkPTI 3912 (Just 3913)
+float4          = mkPTI 700  (Just 1021)
+float8          = mkPTI 701  (Just 1022)
+gtsvector       = mkPTI 3642 (Just 3644)
+inet            = mkPTI 869  (Just 1041)
+int2            = mkPTI 21   (Just 1005)
+int2vector      = mkPTI 22   (Just 1006)
+int4            = mkPTI 23   (Just 1007)
+int4range       = mkPTI 3904 (Just 3905)
+int8            = mkPTI 20   (Just 1016)
+int8range       = mkPTI 3926 (Just 3927)
+interval        = mkPTI 1186 (Just 1187)
+json            = mkPTI 114  (Just 199)
+line            = mkPTI 628  (Just 629)
+lseg            = mkPTI 601  (Just 1018)
+macaddr         = mkPTI 829  (Just 1040)
+money           = mkPTI 790  (Just 791)
+name            = mkPTI 19   (Just 1003)
+numeric         = mkPTI 1700 (Just 1231)
+numrange        = mkPTI 3906 (Just 3907)
+oid             = mkPTI 26   (Just 1028)
+oidvector       = mkPTI 30   (Just 1013)
+path            = mkPTI 602  (Just 1019)
+point           = mkPTI 600  (Just 1017)
+polygon         = mkPTI 604  (Just 1027)
+record          = mkPTI 2249 (Just 2287)
+refcursor       = mkPTI 1790 (Just 2201)
+regclass        = mkPTI 2205 (Just 2210)
+regconfig       = mkPTI 3734 (Just 3735)
+regdictionary   = mkPTI 3769 (Just 3770)
+regoper         = mkPTI 2203 (Just 2208)
+regoperator     = mkPTI 2204 (Just 2209)
+regproc         = mkPTI 24   (Just 1008)
+regprocedure    = mkPTI 2202 (Just 2207)
+regtype         = mkPTI 2206 (Just 2211)
+reltime         = mkPTI 703  (Just 1024)
+text            = mkPTI 25   (Just 1009)
+tid             = mkPTI 27   (Just 1010)
+time            = mkPTI 1083 (Just 1183)
+timestamp       = mkPTI 1114 (Just 1115)
+timestamptz     = mkPTI 1184 (Just 1185)
+timetz          = mkPTI 1266 (Just 1270)
+tinterval       = mkPTI 704  (Just 1025)
+tsquery         = mkPTI 3615 (Just 3645)
+tsrange         = mkPTI 3908 (Just 3909)
+tstzrange       = mkPTI 3910 (Just 3911)
+tsvector        = mkPTI 3614 (Just 3643)
+txid_snapshot   = mkPTI 2970 (Just 2949)
+unknown         = mkPTI 705  Nothing
+uuid            = mkPTI 2950 (Just 2951)
+varbit          = mkPTI 1562 (Just 1563)
+varchar         = mkPTI 1043 (Just 1015)
+void            = mkPTI 2278 Nothing
+xid             = mkPTI 28   (Just 1011)
+xml             = mkPTI 142  (Just 143)
 
diff --git a/library/Hasql/Postgres/Parser.hs b/library/Hasql/Postgres/Parser.hs
deleted file mode 100644
--- a/library/Hasql/Postgres/Parser.hs
+++ /dev/null
@@ -1,364 +0,0 @@
-module Hasql.Postgres.Parser where
-
-import Hasql.Postgres.Prelude hiding (take, bool)
-import Data.Attoparsec.ByteString
-import Data.Attoparsec.ByteString.Char8 hiding (double)
-import qualified Data.ByteString
-import qualified Data.ByteString.Builder
-import qualified Data.ByteString.Lazy
-import qualified Data.ByteString.Base16
-import qualified Data.Text
-import qualified Data.Text.Encoding
-import qualified Data.Text.Lazy
-import qualified Data.Text.Lazy.Encoding
-import qualified Data.Text.Lazy.Builder
-import qualified Data.Vector
-import qualified Data.Attoparsec.ByteString.Char8 as A
-import qualified Database.PostgreSQL.LibPQ as PQ
-
-
-type P = Parser
-
-run :: ByteString -> P a -> Either Text a
-run input parser =
-  onResult $ parse (parser <* endOfInput) input    
-  where
-    onResult =
-      \case
-        Fail remainder contexts message ->
-          Left $ "Message: " <> (fromString . show) message <> "; " <>
-                 "Contexts: " <> (fromString . show) contexts <> "; " <>
-                 "Failing input: " <> (fromString . show) remainder
-        Partial c ->
-          onResult $ c mempty
-        Done _ result ->
-          Right result
-
--- ** Parser
--------------------------
-
-{-# INLINE labeling #-}
-labeling :: String -> Parser a -> Parser a
-labeling n p = 
-  p <?> n
-
-scientific :: P Scientific
-scientific =
-  A.scientific
-
-float :: P Float
-float =
-  realToFrac <$> double
-
-double :: P Double
-double = 
-  labeling "double" $ A.double
-
-bool :: P Bool
-bool =
-  labeling "bool" $
-    ((string "true" <|> string "t" <|> string "True" <|> string "1") *> pure True) <|>
-    ((string "false" <|> string "f" <|> string "False" <|> string "0") *> pure False)
-
-utf8Char :: P Char
-utf8Char =
-  labeling "utf8Char" $
-    asum $ map byLength [1..4]
-  where
-    byLength l =
-      do
-        b <- take l
-        t <- either (const empty) return $ Data.Text.Encoding.decodeUtf8' b
-        (c, _) <- maybe empty return $ Data.Text.uncons t
-        return c
-
-utf8LazyText :: P Data.Text.Lazy.Text
-utf8LazyText =
-  labeling "utf8LazyText" $ do
-    b <- takeLazyByteString
-    either (const empty) return $ Data.Text.Lazy.Encoding.decodeUtf8' b
-
-utf8Text :: P Text
-utf8Text =
-  Data.Text.Lazy.toStrict <$> utf8LazyText
-
-charUnit :: Char -> P ()
-charUnit c = 
-  skip ((==) (fromIntegral (ord c)))
-
--- | A signed integral value from a sequence of characters.
-{-# INLINE integral #-}
-integral :: (Integral a, Num a) => P a
-integral =
-  signed decimal
-  
--- | An unsigned integral value from a sequence of characters.
-{-# INLINE unsignedIntegral #-}
-unsignedIntegral :: (Integral a, Num a) => P a
-unsignedIntegral =
-  decimal
-
--- | An integral value from a single character.
-{-# INLINE integralDigit #-}
-integralDigit :: Integral a => P a
-integralDigit = 
-  satisfyWith (subtract 48 . fromIntegral) (\n -> n < 10 && n >= 0)
-
-day :: P Day
-day =
-  do
-    y <- unsignedIntegral
-    charUnit '-'
-    m <- unsignedIntegral
-    charUnit '-'
-    d <- unsignedIntegral
-    maybe empty return (fromGregorianValid y m d)
-
-timeOfDay :: P TimeOfDay
-timeOfDay =
-  do
-    h <- unsignedIntegral
-    charUnit ':'
-    m <- unsignedIntegral
-    charUnit ':'
-    s <- unsignedIntegral
-    p <- (charUnit '.' *> decimals) <|> pure 0
-    maybe empty return 
-      (makeTimeOfDayValid h m (fromIntegral s + p))
-  where
-    decimals = do
-      (b, i) <- match unsignedIntegral
-      return $ fromIntegral i / (10 ^ Data.ByteString.length b)
-
-localTime :: P LocalTime
-localTime = 
-  LocalTime <$> day <*> (charUnit ' ' *> timeOfDay)
-
-timeZoneTuple :: P (Bool, Int, Int, Int)
-timeZoneTuple =
-  do
-    p <- (charUnit '+' *> pure True) <|> (charUnit '-' *> pure False)
-    h <- unsignedIntegral
-    m <- (charUnit ':' *> unsignedIntegral) <|> pure 0
-    s <- (charUnit ':' *> unsignedIntegral) <|> pure 0
-    return $! (p, h, m, s)
-
-timeZone :: P TimeZone
-timeZone =
-  do
-    (p, h, m, s) <- timeZoneTuple
-    return $!
-      minutesToTimeZone ((if p then id else negate) (60 * h + m))
-
--- |
--- Takes seconds in timezone into account.
-zonedTime :: P ZonedTime
-zonedTime = 
-  do
-    LocalTime d t <- localTime
-    (zp, zh, zm, zs) <- timeZoneTuple
-    return $ ZonedTime (LocalTime d (timeOfDayDiffSecs zs t)) (composeTimezone zp zh zm)
-  where
-    timeOfDayDiffSecs s =
-      if s /= 0
-        then \t -> timeToTimeOfDay $ timeOfDayToTime t - fromIntegral s
-        else id
-    composeTimezone p h m =
-      minutesToTimeZone ((if p then id else negate) (60 * h + m))
-
-utcTime :: P UTCTime
-utcTime =
-  UTCTime <$> day <*> (charUnit ' ' *> diffTime)
-
-diffTime :: P DiffTime
-diffTime = timeOfDayToTime <$> timeOfDay
-
-
--- * Parsable
--------------------------
-
-class Parsable a where
-  -- |
-  -- @Maybe Char@ indicates which quote to expect for values,
-  -- which are quotable.
-  parser :: Maybe Char -> P a
-
-instance Parsable a => Parsable (Maybe a) where
-  parser q =
-    (string "NULL" *> pure Nothing) <|>
-    (Just <$> parser q)
-
-instance Parsable a => Parsable [a] where
-  parser _ =
-    char '{' *> sepBy (parser (Just '"')) (char ',' <* skipSpace) <* char '}'
-        
-instance Parsable a => Parsable (Vector a) where
-  parser _ =
-    Data.Vector.fromList <$> parser $bottom
-
-instance Parsable Bool where
-  parser =
-    \case
-      Nothing -> bool
-      Just q  -> char q *> bool <* char q
-
-instance Parsable Integer where
-  parser = const $ signed decimal
-
-instance Parsable Int where
-  parser = const $ signed decimal
-
-instance Parsable Int8 where
-  parser = const $ signed decimal
-
-instance Parsable Int16 where
-  parser = const $ signed decimal
-
-instance Parsable Int32 where
-  parser = const $ signed decimal
-
-instance Parsable Int64 where
-  parser = const $ signed decimal
-
-instance Parsable Word where
-  parser = const decimal
-
-instance Parsable Word8 where
-  parser = const decimal
-
-instance Parsable Word16 where
-  parser = const decimal
-
-instance Parsable Word32 where
-  parser = const decimal
-
-instance Parsable Word64 where
-  parser = const decimal
-
-instance Parsable Float where
-  parser = const float
-
-instance Parsable Double where
-  parser = const double
-
-instance Parsable Scientific where
-  parser = const A.scientific
-
-instance Parsable Day where
-  parser =
-    \case
-      Nothing -> day
-      Just q  -> char q *> day <* char q
-
-instance Parsable TimeOfDay where
-  parser =
-    \case
-      Nothing -> timeOfDay
-      Just q  -> char q *> timeOfDay <* char q
-
-instance Parsable LocalTime where
-  parser =
-    \case
-      Nothing -> localTime
-      Just q  -> char q *> localTime <* char q
-
-instance Parsable ZonedTime where
-  parser =
-    \case
-      Nothing -> zonedTime
-      Just q  -> char q *> zonedTime <* char q
-
-instance Parsable UTCTime where
-  parser =
-    \case
-      Nothing -> utcTime
-      Just q  -> char q *> utcTime <* char q
-
-instance Parsable Char where
-  parser =
-    \case
-      Nothing -> utf8Char
-      Just q  -> utf8Char <|>
-                 (char q *> (escapedChar q <|> escapedChar '\\' <|> utf8Char) <* char q)
-
-instance Parsable Text where
-  parser =
-    \case
-      Nothing -> utf8Text
-      Just q  -> Data.Text.Lazy.toStrict . Data.Text.Lazy.Builder.toLazyText <$> quotedTextBuilder q
-
-instance Parsable LazyText where
-  parser =
-    \case
-      Nothing -> utf8LazyText
-      Just q  -> Data.Text.Lazy.Builder.toLazyText <$> quotedTextBuilder q
-
-instance Parsable ByteString where
-  parser =
-    \case
-      Nothing -> Data.ByteString.Lazy.toStrict . Data.ByteString.Builder.toLazyByteString <$>
-                 (string "\\x" *> hexByteStringBuilder)
-      Just q  -> Data.ByteString.Lazy.toStrict . Data.ByteString.Builder.toLazyByteString <$>
-                 (char q *> string "\\\\x" *> hexByteStringBuilder <* char q)
-
-instance Parsable LazyByteString where
-  parser =
-    \case
-      Nothing -> Data.ByteString.Builder.toLazyByteString <$> 
-                 (string "\\x" *> hexByteStringBuilder)
-      Just q  -> Data.ByteString.Builder.toLazyByteString <$> 
-                 (char q *> string "\\\\x" *> hexByteStringBuilder <* char q)
-
-
--- * Unescaping
--------------------------
-
-escapedChar :: Char -> P Char
-escapedChar c =
-  char '\\' *> char c
-
-unescapedWord8 :: P Word8
-unescapedWord8 =
-  labeling "unescapedWord8" $ do
-    w <- anyWord8
-    if w == $([|fromIntegral $ ord '\\'|])
-      then anyWord8
-      else return w
-
-unescapedUTF8Char :: P Char
-unescapedUTF8Char =
-  labeling "unescapedUTF8Char" $ 
-    let loop attempt b = do
-          w <- unescapedWord8
-          let b' = b <> Data.ByteString.singleton w
-          case Data.Text.Encoding.decodeUtf8' b' of
-            Right t -> return $ Data.Text.head t
-            Left _ -> 
-              if attempt < 4 
-                then loop (succ attempt) b'
-                else fail "Failed to decode 4 bytes"
-        in loop 0 mempty
-
-quotedTextBuilder :: Char -> P Data.Text.Lazy.Builder.Builder
-quotedTextBuilder q =
-  labeling "quotedTextBuilder" $ 
-    char q *> loop
-  where
-    loop =
-      (char q *> pure mempty) <|>
-      ((<>) <$> (Data.Text.Lazy.Builder.singleton <$> unescapedUTF8Char) <*> loop)
-
-hexByteStringBuilder :: P Data.ByteString.Builder.Builder
-hexByteStringBuilder =
-  labeling "hexByteStringBuilder" $ 
-    loop
-  where
-    loop =
-      ((<>) <$> singleton <*> loop) <|> pure mempty
-    singleton = do
-      (c, r) <- fmap Data.ByteString.Base16.decode (take 2)
-      unless (Data.ByteString.null r) $
-        fail $ "Invalid hex encoding: " <> show r
-      return $ Data.ByteString.Builder.byteString c
-
-
diff --git a/library/Hasql/Postgres/Prelude.hs b/library/Hasql/Postgres/Prelude.hs
--- a/library/Hasql/Postgres/Prelude.hs
+++ b/library/Hasql/Postgres/Prelude.hs
@@ -12,16 +12,12 @@
 
 -- base-prelude
 -------------------------
-import BasePrelude as Exports
+import BasePrelude as Exports hiding (assert)
 
 -- mtl-prelude
 -------------------------
 import MTLPrelude as Exports hiding (shift)
 
--- mmorph
--------------------------
-import Control.Monad.Morph as Exports
-
 -- list-t
 -------------------------
 import ListT as Exports (ListT)
@@ -42,13 +38,13 @@
 -------------------------
 import Data.Scientific as Exports (Scientific)
 
--- time
+-- uuid
 -------------------------
-import Data.Time as Exports
+import Data.UUID as Exports (UUID)
 
--- old-locale
+-- time
 -------------------------
-import System.Locale as Exports
+import Data.Time as Exports
 
 -- vector
 -------------------------
@@ -57,6 +53,10 @@
 -- placeholders
 -------------------------
 import Development.Placeholders as Exports
+
+-- loch-th
+-------------------------
+import Debug.Trace.LocationTH as Exports
 
 -- custom
 -------------------------
diff --git a/library/Hasql/Postgres/Renderer.hs b/library/Hasql/Postgres/Renderer.hs
deleted file mode 100644
--- a/library/Hasql/Postgres/Renderer.hs
+++ /dev/null
@@ -1,312 +0,0 @@
--- |
--- Useful info:
--- https://github.com/hdbc/hdbc/blob/7ed3dfad534773cbfe2811ea241d245009e2961b/Database/HDBC/SqlValue.hs#L252
-module Hasql.Postgres.Renderer where
-
-import Hasql.Postgres.Prelude
-import qualified Data.ByteString as B
-import qualified Data.ByteString.Char8 as BC
-import qualified Data.ByteString.Builder as BB
-import qualified Data.ByteString.Lazy as BL
-import qualified Data.ByteString.Lazy.Char8 as BLC
-import qualified Data.ByteString.Base16 as BB16
-import qualified Data.ByteString.Base16.Lazy as BB16L
-import qualified Data.Text as T
-import qualified Data.Text.Encoding as T
-import qualified Data.Text.Lazy as TL
-import qualified Data.Text.Lazy.Encoding as TL
-import qualified Data.ByteString.Builder.Scientific
-import qualified Data.Vector as Vector
-
-
--- | A renderer of @a@.
-type R a =
-  a -> BB.Builder
-
-run :: a -> R a -> ByteString
-run a f =
-  (BL.toStrict . BB.toLazyByteString . f) a
-
-
--- ** Renderer
--------------------------
-
-ascii :: Show a => R a
-ascii =
-  BB.string7 . show
-
-
--- *** strings
--------------------------
-
-char7 :: R Char = 
-  BB.char7
-
-char :: R Char = 
-  BB.charUtf8
-
-string7 :: R String = 
-  BB.string7
-
-string :: R String = 
-  BB.string8
-
-byteString :: R ByteString = 
-  BB.byteString
-
-lazyByteString :: R LazyByteString = 
-  BB.lazyByteString
-
-text :: R Text =
-  T.encodeUtf8Builder
-
-lazyText :: R LazyText =
-  TL.encodeUtf8Builder
-
-
--- *** enumerations
--------------------------
-
-bool :: R Bool =
-  \b -> if b then word8 1 else word8 0
-
-word8 :: R Word8 =
-  BB.word8Dec
-
-word16 :: R Word16 =
-  BB.word16Dec
-
-word32 :: R Word32 =
-  BB.word32Dec
-
-word64 :: R Word64 =
-  BB.word64Dec
-
-word :: R Word =
-  BB.wordDec
-
-int8 :: R Int8 =
-  BB.int8Dec
-
-int16 :: R Int16 =
-  BB.int16Dec
-
-int32 :: R Int32 =
-  BB.int32Dec
-
-int64 :: R Int64 =
-  BB.int64Dec
-
-int :: R Int =
-  BB.intDec
-
-integer :: R Integer =
-  BB.integerDec
-
-paddedInt :: Int -> R Int
-paddedInt padding n =
-  if padding <= width
-    then int n
-    else mconcat (replicate (padding - width) (BB.char7 '0')) <> int n
-  where
-    width = fromIntegral (succ (floor (logBase 10 (fromIntegral n))) :: Integer)
-    
-
--- *** fractionals
--------------------------
-
-float :: R Float =
-  BB.floatDec
-  
-double :: R Double =
-  BB.doubleDec
-
-pico :: R Pico =
-  BB.string7 . showFixed True
-
-scientific :: R Scientific =
-  Data.ByteString.Builder.Scientific.scientificBuilder
-
-
--- *** time
--------------------------
-
-day :: R Day = 
-  BB.string7 . formatTime defaultTimeLocale (iso8601DateFormat Nothing)
-
-timeOfDay :: R TimeOfDay = 
-  BB.string7 . formatTime defaultTimeLocale "%T%Q"
-
-localTime :: R LocalTime = 
-  BB.string7 . formatTime defaultTimeLocale (iso8601DateFormat (Just "%T%Q"))
-
-timeZone :: R TimeZone =
-  \(TimeZone t _ _) ->
-    if t < 0
-      then BB.char7 '-' <> uncurry hm (divMod (negate t) 60)
-      else BB.char7 '+' <> uncurry hm (divMod t 60)
-  where
-    hm h m = 
-      paddedInt 2 h <> BB.char7 ':' <> paddedInt 2 m 
-
-zonedTime :: R ZonedTime = 
-  \(ZonedTime lt tz) ->
-    localTime lt <> timeZone tz
-
-utcTime :: R UTCTime = 
-  BB.string7 . formatTime defaultTimeLocale (iso8601DateFormat (Just "%T%Q"))
-
-diffTime :: R DiffTime =
-  pico . fromRational . toRational
-
-nominalDiffTime :: R NominalDiffTime =
-  pico . fromRational . toRational
-
-
--- * Renderable
--------------------------
-
-class Renderable a where
-  -- |
-  -- The boolean indicates a quoted mode.
-  renderer :: Maybe Char -> R a
-
-instance Renderable a => Renderable (Maybe a) where
-  renderer q v =
-    maybe (string7 "NULL") (renderer q) v
-
-instance Renderable a => Renderable [a] where
-  renderer _ v =
-    execWriter $ do
-      tell $ char7 '{'
-      tell $ mconcat $ intersperse (string7 ", ") $ map (renderer (Just '"')) v
-      tell $ char7 '}'
-
-instance Renderable a => Renderable (Vector a) where
-  renderer _ =
-    renderer $bottom . Vector.toList
-
-instance Renderable Bool where
-  renderer q =
-    maybe id quoting q . \case
-      True -> char7 't'
-      False -> char7 'f'
-
-instance Renderable Int where
-  renderer _ = 
-    BB.intDec
-
-instance Renderable Int8 where
-  renderer _ = 
-    BB.int8Dec
-
-instance Renderable Int16 where
-  renderer _ = 
-    BB.int16Dec
-
-instance Renderable Int32 where
-  renderer _ = 
-    BB.int32Dec
-
-instance Renderable Int64 where
-  renderer _ = 
-    BB.int64Dec
-
-instance Renderable Integer where
-  renderer _ = 
-    BB.integerDec
-
-instance Renderable Word where
-  renderer _ = 
-    BB.wordDec
-
-instance Renderable Word8 where
-  renderer _ = 
-    BB.word8Dec
-
-instance Renderable Word16 where
-  renderer _ = 
-    BB.word16Dec
-
-instance Renderable Word32 where
-  renderer _ = 
-    BB.word32Dec
-
-instance Renderable Word64 where
-  renderer _ = 
-    BB.word64Dec
-
-instance Renderable Float where
-  renderer _ = 
-    BB.floatDec
-
-instance Renderable Double where
-  renderer _ = 
-    BB.doubleDec
-
-instance Renderable Scientific where
-  renderer _ = 
-    Data.ByteString.Builder.Scientific.scientificBuilder
-
-instance Renderable Day where
-  renderer q = 
-    maybe id quoting q . day
-
-instance Renderable TimeOfDay where
-  renderer q = 
-    maybe id quoting q . timeOfDay
-
-instance Renderable LocalTime where
-  renderer q = 
-    maybe id quoting q . localTime
-
-instance Renderable ZonedTime where
-  renderer q = 
-    maybe id quoting q . zonedTime
-
-instance Renderable UTCTime where
-  renderer q = 
-    maybe id quoting q . utcTime
-
-instance Renderable Char where
-  renderer q =
-    renderer Nothing . T.singleton
-
-instance Renderable Text where
-  renderer =
-    maybe T.encodeUtf8Builder (\q -> quoting q . escaping q . T.encodeUtf8)
-    where
-      escaping q =
-        BC.foldr (mappend . escapedChar8 q) mempty
-
-instance Renderable LazyText where
-  renderer q =
-    maybe TL.encodeUtf8Builder (\qc -> quoting qc . escaping qc . TL.encodeUtf8) q
-    where
-      escaping q =
-        BLC.foldr (mappend . escapedChar8 q) mempty
-
-instance Renderable ByteString where
-  renderer =
-    (. encode) . maybe (BB.string7 "\\x" <>) (\q -> quoting q . (BB.string7 "\\\\x" <>))
-    where
-      encode = BB.byteString . BB16.encode
-
-instance Renderable LazyByteString where
-  renderer =
-    (. encode) . maybe (BB.string7 "\\x" <>) (\q -> quoting q . (BB.string7 "\\\\x" <>))
-    where
-      encode = BB.lazyByteString . BB16L.encode
-
-
--- ** Helpers
--------------------------
-
-quoting :: Char -> R BB.Builder
-quoting q =
-  (char7 q <>) . (<> char7 q)
-
-escapedChar8 :: Char -> R Char
-escapedChar8 q c =
-  (if c == q || c == '\\' then (char7 '\\' <>) else id) $ BB.char8 c
-
diff --git a/library/Hasql/Postgres/Statement.hs b/library/Hasql/Postgres/Statement.hs
--- a/library/Hasql/Postgres/Statement.hs
+++ b/library/Hasql/Postgres/Statement.hs
@@ -2,7 +2,9 @@
 
 import Hasql.Postgres.Prelude
 import qualified Database.PostgreSQL.LibPQ as L
-import qualified Hasql.Postgres.Renderer as Renderer
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Builder as BB
+import qualified Data.ByteString.Lazy as BL
 
 
 type Statement =
@@ -48,30 +50,29 @@
   (template, [], False)
   where
     template =
-      Renderer.run cursor $ \c -> Renderer.string7 "CLOSE " <> Renderer.byteString c
+      "CLOSE " <> cursor
 
 fetchFromCursor :: Cursor -> Statement
 fetchFromCursor cursor =
   (template, [], False)
   where
     template =
-      Renderer.run cursor $ \c -> 
-        Renderer.string7 "FETCH FORWARD 256 FROM " <> Renderer.byteString c
+      "FETCH FORWARD 256 FROM " <> cursor
 
 beginTransaction :: TransactionMode -> Statement
-beginTransaction mode =
+beginTransaction (i, w) =
   (template, [], True)
   where
     template =
-      Renderer.run mode $ \(i, w) ->
-        mconcat $ intersperse (Renderer.char7 ' ') $
+      BL.toStrict $ BB.toLazyByteString $
+        mconcat $ intersperse (BB.char7 ' ') $
           [
-            Renderer.string7 "BEGIN"
+            BB.string7 "BEGIN"
             ,
             case i of
-              ReadCommitted  -> Renderer.string7 "ISOLATION LEVEL READ COMMITTED"
-              RepeatableRead -> Renderer.string7 "ISOLATION LEVEL REPEATABLE READ"
-              Serializable   -> Renderer.string7 "ISOLATION LEVEL SERIALIZABLE"
+              ReadCommitted  -> BB.string7 "ISOLATION LEVEL READ COMMITTED"
+              RepeatableRead -> BB.string7 "ISOLATION LEVEL REPEATABLE READ"
+              Serializable   -> BB.string7 "ISOLATION LEVEL SERIALIZABLE"
             ,
             case w of
               True  -> "READ WRITE"
diff --git a/library/Hasql/Postgres/StatementPreparer.hs b/library/Hasql/Postgres/StatementPreparer.hs
--- a/library/Hasql/Postgres/StatementPreparer.hs
+++ b/library/Hasql/Postgres/StatementPreparer.hs
@@ -5,9 +5,11 @@
 import Hasql.Postgres.Prelude
 import qualified Data.HashTable.IO as Hashtables
 import qualified Database.PostgreSQL.LibPQ as PQ
-import qualified Hasql.Postgres.Renderer as Renderer
 import qualified Hasql.Postgres.ResultParser as Result
 import qualified Hasql.Postgres.ResultHandler as ResultHandler
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Builder as BB
+import qualified Data.ByteString.Lazy as BL
 
 
 
@@ -48,7 +50,7 @@
       Nothing ->
         do
           w <- readIORef counter
-          n <- return (Renderer.run w Renderer.word16)
+          n <- return (BL.toStrict $ BB.toLazyByteString $ BB.word16Dec w)
           ResultHandler.unit =<< Result.parse c =<< PQ.prepare c n s (partial (not . null) tl)
           Hashtables.insert table k n
           writeIORef counter (succ w)
diff --git a/tests/Main.hs b/tests/Main.hs
--- a/tests/Main.hs
+++ b/tests/Main.hs
@@ -131,28 +131,22 @@
     validMappingSession v1
     validMappingSession v2
   where
-    v1  = Vector.fromList [v2, v2]
-    v2  = Vector.fromList [Just 'a', Nothing, Just 'b']
+    v1  = [v2, v2]
+    v2  = [Just 'a', Nothing, Just 'b']
 
-test_mappingOfVector2 =
+test_mappingOfList2 =
   session1 $ do
     validMappingSession v1
     validMappingSession v2
   where
-    v1  = Vector.fromList [v2, v2]
-    v2  = Vector.fromList [Just (1 :: Int), Just 2, Nothing]
+    v1  = [v2, v2]
+    v2  = [Just (1 :: Int), Just 2, Nothing]
 
-test_mappingOfVector3 =
+test_mappingOfList3 =
   session1 $ do
-    validMappingSession v1
-  where
-    v1 =
-      Vector.fromList
-        [
-          " 'a' \"b\" \\c\\ " :: Text
-        ]
+    validMappingSession [" 'a' \"b\" \\c\\ " :: Text]
 
-test_mappingOfVector4 =
+test_mappingOfList4 =
   assertEqual (Just (Identity v1)) =<< do
     session1 $ tx Nothing $ do
       unit $ [q|DROP TABLE IF EXISTS a|]
@@ -161,31 +155,20 @@
       single $ [q|SELECT v FROM a|]
   where
     v1 =
-      Vector.fromList
-        [
-          Vector.fromList [Just 'a', Just 'b'],
-          Vector.fromList [Nothing, Just 'c']
-        ]
+      [
+        [Just 'a', Just 'b'],
+        [Nothing, Just 'c']
+      ]
 
-test_mappingOfVector5 =
+test_mappingOfList5 =
   session1 $ do
-    validMappingSession v1
-  where
-    v1 =
-      Vector.fromList
-        [
-          " 'a' \"b\" \\c\\ ф" :: ByteString
-        ]
+    validMappingSession [" 'a' \"b\" \\c\\ ф" :: ByteString]
 
-prop_mappingOfVectorOverByteString (list :: [ByteString]) =
-  mappingProp v
-  where
-    v = Vector.fromList list
+prop_mappingOfListOverByteString (x :: [ByteString]) =
+  mappingProp x
 
-prop_mappingOfVectorOverLazyByteString (list :: [LazyByteString]) =
-  mappingProp v
-  where
-    v = Vector.fromList list
+prop_mappingOfListOverLazyByteString (x :: [LazyByteString]) =
+  mappingProp x
 
 test_mappingOfBool =
   session1 $ do
@@ -267,17 +250,6 @@
   forAll microsLocalTimeGen $ \v -> 
     mappingProp v
 
-prop_mappingOfZonedTime =
-  forAll gen $ \v -> 
-    eq v $ fromJust $ do unsafePerformIO $ session1 $ selectSelf v
-  where
-    eq a b = zonedTimeToUTC a === zonedTimeToUTC b
-    gen =
-      do
-        t <- microsLocalTimeGen
-        z <- minutesToTimeZone <$> choose (negate (11 * 60 + 59), 11 * 60 + 59)
-        return $ ZonedTime t z
-
 prop_mappingOfUTCTime =
   forAll gen $ \v ->
     mappingProp v
@@ -341,4 +313,6 @@
 
 mappingProp :: (Show a, Eq a, Backend.Mapping Postgres a) => a -> Property
 mappingProp v =
-  Just v === do unsafePerformIO $ session1 $ selectSelf v
+  Right v === do 
+    unsafePerformIO $ (try :: IO a -> IO (Either H.Error a)) $ fmap fromJust $ 
+      session1 $ selectSelf v
