diff --git a/postgresql-simple.cabal b/postgresql-simple.cabal
--- a/postgresql-simple.cabal
+++ b/postgresql-simple.cabal
@@ -1,5 +1,5 @@
 Name:                postgresql-simple
-Version:             0.4.2.0
+Version:             0.4.2.1
 Synopsis:            Mid-Level PostgreSQL client library
 Description:
     Mid-Level PostgreSQL client library, forked from mysql-simple.
@@ -81,7 +81,7 @@
 source-repository this
   type:     git
   location: http://github.com/lpsmith/postgresql-simple
-  tag:      v0.4.1.0
+  tag:      v0.4.2.1
 
 test-suite test
   type:           exitcode-stdio-1.0
diff --git a/src/Database/PostgreSQL/Simple.hs b/src/Database/PostgreSQL/Simple.hs
--- a/src/Database/PostgreSQL/Simple.hs
+++ b/src/Database/PostgreSQL/Simple.hs
@@ -343,6 +343,27 @@
 -- Returns the number of rows affected.
 --
 -- Throws 'FormatError' if the query could not be formatted correctly.
+--
+-- 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 sometable.y = upd.y
+--       FROM (VALUES (?,?)) as upd(x,y)
+--      WHERE sometable.x = upd.x
+--  |] [(1, \"hello\"),(2, \"world\")
+-- @
+
 executeMany :: (ToRow q) => Connection -> Query -> [q] -> IO Int64
 executeMany _ _ [] = return 0
 executeMany conn q qs = do
diff --git a/src/Database/PostgreSQL/Simple/FromField.hs b/src/Database/PostgreSQL/Simple/FromField.hs
--- a/src/Database/PostgreSQL/Simple/FromField.hs
+++ b/src/Database/PostgreSQL/Simple/FromField.hs
@@ -23,6 +23,14 @@
 since a 'Double' might lose precision if representing PostgreSQL's 64-bit
 @bigint@, the two are /not/ considered compatible.
 
+Note that the 'Float' and 'Double' instances use attoparsec's 'double'
+conversion routine,  which sacrifices some accuracy for speed.   If you
+need accuracy,  consider first converting data to a 'Scientific' or 'Rational'
+type,  and then converting to a floating-point type.   If you are defining
+your own 'ToRow' instances,  this can be acheived simply by
+@'fromRational' '<$>' 'field'@,  although this idiom additionally compatible
+with PostgreSQL's @numeric@ type.
+
 Because 'FromField' is a typeclass,  one may provide conversions to
 additional Haskell types without modifying postgresql-simple.  This is
 particularly useful for supporting PostgreSQL types that postgresql-simple
@@ -301,12 +309,14 @@
 instance FromField Integer where
     fromField = atto ok64 $ signed decimal
 
--- | int2, float4
+-- | int2, float4    (Uses attoparsec's 'double' routine,  for
+--   better accuracy convert to 'Scientific' or 'Rational' first)
 instance FromField Float where
     fromField = atto ok (realToFrac <$> double)
       where ok = $(mkCompats [TI.float4,TI.int2])
 
--- | int2, int4, float4, float8
+-- | int2, int4, float4, float8  (Uses attoparsec's 'double' routine,  for
+--   better accuracy convert to 'Scientific' or 'Rational' first)
 instance FromField Double where
     fromField = atto ok double
       where ok = $(mkCompats [TI.float4,TI.float8,TI.int2,TI.int4])
diff --git a/src/Database/PostgreSQL/Simple/ToField.hs b/src/Database/PostgreSQL/Simple/ToField.hs
--- a/src/Database/PostgreSQL/Simple/ToField.hs
+++ b/src/Database/PostgreSQL/Simple/ToField.hs
@@ -338,14 +338,16 @@
         typedRows :: ToRow a => [a] -> [QualifiedIdentifier] -> [Action] -> [Action]
         typedRows [] _ _ = error funcname
         typedRows (val:vals) types rest =
-            typedRow (toRow val) types (litC ',' : untypedRows vals rest)
+            typedRow (toRow val) types (multiRows vals rest)
 
         untypedRows :: ToRow a => [a] -> [Action] -> [Action]
-        untypedRows [] rest = rest
+        untypedRows [] _ = error funcname
         untypedRows (val:vals) rest =
-            untypedRow (toRow val) $
-              interleaveFoldr
-                  (untypedRow . toRow)
-                  (litC ',')
-                  rest
-                  vals
+            untypedRow (toRow val) (multiRows vals rest)
+
+        multiRows :: ToRow a => [a] -> [Action] -> [Action]
+        multiRows vals rest = interleaveFoldr
+                                (untypedRow . toRow)
+                                (litC ',')
+                                rest
+                                vals
diff --git a/src/Database/PostgreSQL/Simple/Types.hs b/src/Database/PostgreSQL/Simple/Types.hs
--- a/src/Database/PostgreSQL/Simple/Types.hs
+++ b/src/Database/PostgreSQL/Simple/Types.hs
@@ -139,6 +139,13 @@
 instance Hashable QualifiedIdentifier where
     hashWithSalt i (QualifiedIdentifier q t) = hashWithSalt i (q, t)
 
+-- | @\"foo.bar\"@ will get turned into
+-- @QualifiedIdentifier (Just \"foo\") \"bar\"@,  while @\"foo\"@ will get
+-- turned into @QualifiedIdentifier Nothing \"foo\"@.   Note this instance
+-- is for convenience,  and does not match postgres syntax.   It
+-- only examines the first period character,  and thus cannot be used if the
+-- qualifying identifier contains a period for example.
+
 instance IsString QualifiedIdentifier where
     fromString str = let (x,y) = T.break (== '.') (fromString str)
                       in if T.null y
@@ -173,26 +180,40 @@
     deriving (Eq, Ord, Show, Read, Typeable)
 
 -- | Represents a @VALUES@ table literal,  usable as an alternative
---   to @executeMany@ and @returning@.  For example:
+--   to @executeMany@ and @returning@.  The main advantage is that
+--   you can parametrize more than just a single @VALUES@ expression.
+--   For example,  here's a query to insert a thing into one table
+--   and some attributes of that thing into another,   returning the
+--   new id generated by the database:
 --
--- > execute c "INSERT INTO table (key,val) ?"
--- >      (Only (Values ["int4","text"]
--- >                    [(1,"hello"),(2,"world")]))
 --
---   Issues the following query:
+-- > query c [sql|
+-- >     WITH new_thing AS (
+-- >       INSERT INTO thing (name) VALUES (?) RETURNING id
+-- >     ), new_attributes AS (
+-- >       INSERT INTO thing_attributes
+-- >          SELECT new_thing.id, attrs.*
+-- >            FROM new_thing JOIN ? attrs
+-- >     ) SELECT * FROM new_thing
+-- >  |] ("foo", Values [  "int4", "text"    ]
+-- >                    [ ( 1    , "hello" )
+-- >                    , ( 2    , "world" ) ])
 --
--- > INSERT INTO table (key,val) (VALUES (1::"int4",'hello'::"text"),(2,'world'))
+--   (Note this example uses writable common table expressions,
+--    which were added in PostgreSQL 9.1)
 --
---   When the list of values is empty,  the following query will be issued:
+--   The second parameter gets expanded into the following SQL syntax:
 --
--- > INSERT INTO table (key,val) (VALUES (null::"int4",null::"text") LIMIT 0)
+-- > (VALUES (1::"int4",'hello'::"text"),(2,'world'))
 --
+--   When the list of attributes is empty,  the second parameter expands to:
+--
+-- > (VALUES (null::"int4",null::"text") LIMIT 0)
+--
 --   By contrast, @executeMany@ and @returning@ don't issue the query
 --   in the empty case, and simply return @0@ and @[]@ respectively.
---
---   The advantage over @executeMany@ is in cases when you want to
---   parameterize table literals in addition to other parameters,  as can
---   occur with writable common table expressions, for example.
+--   This behavior is usually correct given their intended use cases,
+--   but would certainly be wrong in the example above.
 --
 --   The first argument is a list of postgresql type names.  Because this
 --   is turned into a properly quoted identifier,  the type name is case
@@ -202,11 +223,10 @@
 --
 --   You may omit the type names,  however,  if you do so the list
 --   of values must be non-empty,  and postgresql must be able to infer
---   the types of the columns from the surrounding context.   If these
---   conditions are not met,  postgresql-simple will throw an exception
---   without issuing the query in the former case,  and in the latter
---   the postgres server will return an error which will be turned into
---   a @SqlError@ exception.
+--   the types of the columns from the surrounding context.   If the first
+--   condition is not met,  postgresql-simple will throw an exception
+--   without issuing the query.   In the second case,  the postgres server
+--   will return an error which will be turned into a @SqlError@ exception.
 --
 --   See <http://www.postgresql.org/docs/9.3/static/sql-values.html> for
 --   more information.
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -3,7 +3,7 @@
 {-# LANGUAGE ScopedTypeVariables #-}
 import Common
 import Database.PostgreSQL.Simple.FromField (FromField)
-import Database.PostgreSQL.Simple.Types(Query(..))
+import Database.PostgreSQL.Simple.Types(Query(..),Values(..))
 import Database.PostgreSQL.Simple.HStore
 import qualified Database.PostgreSQL.Simple.Transaction as ST
 import Control.Applicative
@@ -40,6 +40,7 @@
     , TestLabel "JSON"          . testJSON
     , TestLabel "Savepoint"     . testSavepoint
     , TestLabel "Unicode"       . testUnicode
+    , TestLabel "Values"        . testValues
     ]
 
 testBytea :: TestEnv -> Test
@@ -249,12 +250,30 @@
 
 testUnicode :: TestEnv -> Test
 testUnicode TestEnv{..} = TestCase $ do
-    let q = Query . T.encodeUtf8
+    let q = Query . T.encodeUtf8  -- Handle encoding ourselves to ensure
+                                  -- the table gets created correctly.
     let messages = map Only ["привет","мир"] :: [Only Text]
     execute_ conn (q "CREATE TEMPORARY TABLE ру́сский (сообщение TEXT)")
     executeMany conn "INSERT INTO ру́сский (сообщение) VALUES (?)" messages
     messages' <- query_ conn "SELECT сообщение FROM ру́сский"
     sort messages @?= sort messages'
+
+testValues :: TestEnv -> Test
+testValues TestEnv{..} = TestCase $ do
+    execute_ conn "CREATE TEMPORARY TABLE values_test (x int, y text)"
+    test (Values ["int4","text"] [])
+    test (Values ["int4","text"] [(1,"hello")])
+    test (Values ["int4","text"] [(1,"hello"),(2,"world")])
+    test (Values ["int4","text"] [(1,"hello"),(2,"world"),(3,"goodbye")])
+    test (Values [] [(1,"hello")])
+    test (Values [] [(1,"hello"),(2,"world")])
+    test (Values [] [(1,"hello"),(2,"world"),(3,"goodbye")])
+  where
+    test :: Values (Int, Text) -> Assertion
+    test table@(Values _ vals) = do
+      execute conn "INSERT INTO values_test ?" (Only table)
+      vals' <- query_  conn "DELETE FROM values_test RETURNING *"
+      sort vals @?= sort vals'
 
 data TestException
   = TestException
