diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,116 @@
+# 0.11.1.0
+
+## New features
+
+* Added a cross-backend abstraction for the `COPY` statement in
+  `Database.Beam.Backend.SQL.BeamExtensions`:
+  * file-mode `COPY ... TO 'file'` / `COPY ... FROM 'file'`. Defines
+    `MonadBeamCopyTo` / `MonadBeamCopyFrom`, and the user-facing
+    `copyTableTo` / `copySelectTo` / `copyTableFrom` builders.
+  * streaming `COPY ... TO STDOUT` / `COPY ... FROM STDIN`. Mirrors the file-mode
+    API: `MonadBeamCopyToStream` / `MonadBeamCopyFromStream`,
+     and the `copyTableToStream` / `copySelectToStream` / `copyTableFromStream` builders.
+
+## Bug fixes
+
+* Fixed an issue where a window function applied over the result of `nub_` (or
+  the Postgres-specific `pgNubBy_`) would emit `DISTINCT` and the window
+  expression in the same `SELECT`, causing the window to evaluate against the
+  pre-deduplicated rows. The inner select is now materialised as a subquery
+  whenever it carries `DISTINCT`, `GROUP BY`, or `HAVING` (#756).
+
+## Dependencies
+
+* Removed dependency on `ghc-prim`.
+
+# 0.11.0.0
+
+## New features
+
+* Add projection methods to `MonadBeamInsertReturning`/`MonadBeamUpdateReturning`/`MonadBeamDeleteReturning` (#801).
+* Made `genericSerial` be generic over `Integral` rathern than only `Int` (#534).
+* Added the `week_` combinator to extract the week of a timestamp (#599).
+
+## Bug fixes
+
+* Changed the type of `values_` to `NonEmpty` rather than a list, preventing runtime exceptions (#742).
+* Fixed an issue where `lead1_`, `lag1_`, `lead_`, and `lag_` did not have the appropriate type, leading to runtime exceptions (#745).
+
+# 0.10.5.0
+
+## Updated dependencies
+
+* Updated the upper bound on `time` to include `time-1.14`
+
+## Query combinator API change
+
+* The `Database be db` context has been removed from the query combinators `all_`,
+  `allFromView_`, `join_`, `join'`, `related_`, `relatedBy_` and `relatedBy_'`.
+
+  This constraint was not used by any of these functions.
+
+# 0.10.4.0
+
+## Added features
+
+* Added a `Generic` instance to `SqlNull`, `SqlBitString`, and `SqlSerial` (#736).
+* Added a note to `default_` to specify that it has more restrictions than its type may indicate (#744).
+* Added `limitMaybe_` and `offsetMaybe_` (#633).
+
+
+## Updated dependencies
+
+* Updated the upper bound to include `containers-0.8`.
+
+# 0.10.3.1
+
+## Updated dependencies
+
+* Updated the upper bound to include `hashable-1.5`.
+
+## Bug fixes
+
+* The `Pagila` example in `beam-postgres` has been updated to compile using the most recent version of `beam` packages (#729).
+
+## Packaging
+
+* Remove the GHC flag `-O3`, which resulted in increased compilation time by default. This flag can still be activated using your build system of choice, as with every library.
+
+# 0.10.3.0
+
+## Added features
+
+* Export generic classes (#585).
+
+## Bug fixes
+
+ * Fixed an issue where a WHERE clause would be dropped in the absence of a FROM (#695).
+
+# 0.10.2.0
+
+## Added features
+
+ * Added support for creating database schemas and associated tables with `createDatabaseSchema`, `createTableWithSchema`, and `existingDatabaseSchema` (#716).
+ * Added `FromBackendRow` instance for `Identity` (#717).
+
+# 0.10.1.0
+
+## Added features
+
+ * Allow embedding database types
+ * Loosen some version bounds
+
+# 0.10.0.0
+
+## Bug fixes
+
+ * Make sure lateral join names do not overlap
+
+## Addded features
+
+ * Add `runSelectReturningFirst`
+ * `IN (SELECT ...)` syntax via `inQuery_`
+
 # 0.9.2.1
 
 ## Added features
diff --git a/Database/Beam/Backend/SQL.hs b/Database/Beam/Backend/SQL.hs
--- a/Database/Beam/Backend/SQL.hs
+++ b/Database/Beam/Backend/SQL.hs
@@ -133,6 +133,12 @@
                  Nothing -> pure (Just x)
                  Just _ -> pure Nothing
 
+  -- | Run the given command and fetch the first result. The result is
+  --   'Nothing' if no results are returned.
+  --   This is not guaranteed to automatically limit the query to one result.
+  runReturningFirst :: FromBackendRow be x => BeamSqlBackendSyntax be -> m (Maybe x)
+  runReturningFirst cmd = runReturningMany cmd id
+
   -- | Run the given command, collect all the results, and return them as a
   --   list. May be more convenient than 'runReturningMany', but reads the entire
   --   result set into memory.
diff --git a/Database/Beam/Backend/SQL/AST.hs b/Database/Beam/Backend/SQL/AST.hs
--- a/Database/Beam/Backend/SQL/AST.hs
+++ b/Database/Beam/Backend/SQL/AST.hs
@@ -156,6 +156,7 @@
 
   | ExtractFieldDateTimeYear
   | ExtractFieldDateTimeMonth
+  | ExtractFieldDateTimeWeek
   | ExtractFieldDateTimeDay
   | ExtractFieldDateTimeHour
   | ExtractFieldDateTimeMinute
@@ -234,6 +235,7 @@
   | ExpressionRow [ Expression ]
 
   | ExpressionIn Expression [ Expression ]
+  | ExpressionInSelect Expression Select
 
   | ExpressionIsNull Expression
   | ExpressionIsNotNull Expression
@@ -290,6 +292,7 @@
   minutesField = ExtractFieldDateTimeMinute
   hourField = ExtractFieldDateTimeHour
   dayField = ExtractFieldDateTimeDay
+  weekField = ExtractFieldDateTimeWeek
   monthField = ExtractFieldDateTimeMonth
   yearField = ExtractFieldDateTimeYear
 
@@ -359,6 +362,7 @@
 
   defaultE = ExpressionDefault
   inE = ExpressionIn
+  inSelectE = ExpressionInSelect
 
 instance IsSql99FunctionExpressionSyntax Expression where
   functionNameE = ExpressionNamedFunction
@@ -461,6 +465,12 @@
   type Sql92GroupingExpressionSyntax Grouping = Expression
 
   groupByExpressions = Grouping
+
+data SchemaName = SchemaName Text
+  deriving (Show, Eq, Ord)
+
+instance IsSql92SchemaNameSyntax SchemaName where
+  schemaName = SchemaName
 
 data TableName = TableName (Maybe Text) Text
   deriving (Show, Eq, Ord)
diff --git a/Database/Beam/Backend/SQL/BeamExtensions.hs b/Database/Beam/Backend/SQL/BeamExtensions.hs
--- a/Database/Beam/Backend/SQL/BeamExtensions.hs
+++ b/Database/Beam/Backend/SQL/BeamExtensions.hs
@@ -9,10 +9,18 @@
 -- emulated on others.
 module Database.Beam.Backend.SQL.BeamExtensions
   ( MonadBeamInsertReturning(..)
+  , runInsertReturningList
   , MonadBeamUpdateReturning(..)
+  , runUpdateReturningList
   , MonadBeamDeleteReturning(..)
+  , runDeleteReturningList
   , BeamHasInsertOnConflict(..)
 
+  -- * Support for copying to external files
+  , module Database.Beam.Backend.SQL.BeamExtensions.Copy.File
+  -- * Support for streaming copy
+  , module Database.Beam.Backend.SQL.BeamExtensions.Copy.Stream
+
   , SqlSerial(..)
   , onConflictUpdateInstead
   , onConflictUpdateAll
@@ -38,111 +46,166 @@
 import           Data.Kind (Type)
 import           Data.Proxy
 import           Data.Semigroup
+import           Database.Beam.Backend.SQL.BeamExtensions.Copy.File hiding (projection) -- internal function
+import           Database.Beam.Backend.SQL.BeamExtensions.Copy.Stream
 
 --import GHC.Generics
 
--- | 'MonadBeam's that support returning the newly created rows of an @INSERT@ statement.
---   Useful for discovering the real value of a defaulted value.
+-- | 'MonadBeam's that support returning data from the newly created rows of an
+--   @INSERT@ statement. Useful for discovering the real value of a defaulted
+--   field (such as a serial primary key).
 class MonadBeam be m =>
   MonadBeamInsertReturning be m | m -> be where
-  runInsertReturningList
+  -- | Execute an @INSERT@ statement and return a list of values projected from
+  --   the inserted rows. The projection function selects which columns are
+  --   returned: pass 'id' to return the full row, or supply a custom
+  --   projection to return a subset.
+  runInsertReturningListWith
     :: ( Beamable table
-       , Projectible be (table (QExpr be ()))
-       , FromBackendRow be (table Identity) )
+       , Projectible be a
+       , FromBackendRow be (QExprToIdentity a) )
     => SqlInsert be table
-    -> m [table Identity]
+    -> (table (QExpr be ()) -> a)
+    -> m [QExprToIdentity a]
 
+-- | Execute an @INSERT@ statement and return the inserted rows in full.
+--   A convenience around 'runInsertReturningListWith' that uses 'id' as the
+--   projection.
+runInsertReturningList
+  :: ( MonadBeamInsertReturning be m
+     , Beamable table
+     , Projectible be (table (QExpr be ()))
+     , FromBackendRow be (table Identity) )
+  => SqlInsert be table
+  -> m [table Identity]
+runInsertReturningList sql = runInsertReturningListWith sql id
+
 instance MonadBeamInsertReturning be m => MonadBeamInsertReturning be (ExceptT e m) where
-    runInsertReturningList = lift . runInsertReturningList
+    runInsertReturningListWith sql proj = lift $ runInsertReturningListWith sql proj
 instance MonadBeamInsertReturning be m => MonadBeamInsertReturning be (ContT r m) where
-    runInsertReturningList = lift . runInsertReturningList
+    runInsertReturningListWith sql proj = lift $ runInsertReturningListWith sql proj
 instance MonadBeamInsertReturning be m => MonadBeamInsertReturning be (ReaderT r m) where
-    runInsertReturningList = lift . runInsertReturningList
+    runInsertReturningListWith sql proj = lift $ runInsertReturningListWith sql proj
 instance MonadBeamInsertReturning be m => MonadBeamInsertReturning be (Lazy.StateT r m) where
-    runInsertReturningList = lift . runInsertReturningList
+    runInsertReturningListWith sql proj = lift $ runInsertReturningListWith sql proj
 instance MonadBeamInsertReturning be m => MonadBeamInsertReturning be (Strict.StateT r m) where
-    runInsertReturningList = lift . runInsertReturningList
+    runInsertReturningListWith sql proj = lift $ runInsertReturningListWith sql proj
 instance (MonadBeamInsertReturning be m, Monoid r)
     => MonadBeamInsertReturning be (Lazy.WriterT r m) where
-    runInsertReturningList = lift . runInsertReturningList
+    runInsertReturningListWith sql proj = lift $ runInsertReturningListWith sql proj
 instance (MonadBeamInsertReturning be m, Monoid r)
     => MonadBeamInsertReturning be (Strict.WriterT r m) where
-    runInsertReturningList = lift . runInsertReturningList
+    runInsertReturningListWith sql proj = lift $ runInsertReturningListWith sql proj
 instance (MonadBeamInsertReturning be m, Monoid w)
     => MonadBeamInsertReturning be (Lazy.RWST r w s m) where
-    runInsertReturningList = lift . runInsertReturningList
+    runInsertReturningListWith sql proj = lift $ runInsertReturningListWith sql proj
 instance (MonadBeamInsertReturning be m, Monoid w)
     => MonadBeamInsertReturning be (Strict.RWST r w s m) where
-    runInsertReturningList = lift . runInsertReturningList
+    runInsertReturningListWith sql proj = lift $ runInsertReturningListWith sql proj
 
--- | 'MonadBeam's that support returning the updated rows of an @UPDATE@ statement.
---   Useful for discovering the new values of the updated rows.
+-- | 'MonadBeam's that support returning data from the updated rows of an
+--   @UPDATE@ statement. Useful for observing the post-update values of the
+--   affected rows.
 class MonadBeam be m =>
   MonadBeamUpdateReturning be m | m -> be where
-  runUpdateReturningList
+  -- | Execute an @UPDATE@ statement and return a list of values projected from
+  --   the updated rows. The projection function selects which columns are
+  --   returned: pass 'id' to return the full row, or supply a custom
+  --   projection to return a subset.
+  runUpdateReturningListWith
     :: ( Beamable table
-       , Projectible be (table (QExpr be ()))
-       , FromBackendRow be (table Identity) )
+       , Projectible be a
+       , FromBackendRow be (QExprToIdentity a) )
     => SqlUpdate be table
-    -> m [table Identity]
+    -> (table (QExpr be ()) -> a)
+    -> m [QExprToIdentity a]
 
+-- | Execute an @UPDATE@ statement and return the updated rows in full.
+--   A convenience around 'runUpdateReturningListWith' that uses 'id' as the
+--   projection.
+runUpdateReturningList
+  :: ( MonadBeamUpdateReturning be m
+     , Beamable table
+     , Projectible be (table (QExpr be ()))
+     , FromBackendRow be (table Identity) )
+  => SqlUpdate be table
+  -> m [table Identity]
+runUpdateReturningList sql = runUpdateReturningListWith sql id
+
 instance MonadBeamUpdateReturning be m => MonadBeamUpdateReturning be (ExceptT e m) where
-    runUpdateReturningList = lift . runUpdateReturningList
+    runUpdateReturningListWith sql proj = lift $ runUpdateReturningListWith sql proj
 instance MonadBeamUpdateReturning be m => MonadBeamUpdateReturning be (ContT r m) where
-    runUpdateReturningList = lift . runUpdateReturningList
+    runUpdateReturningListWith sql proj = lift $ runUpdateReturningListWith sql proj
 instance MonadBeamUpdateReturning be m => MonadBeamUpdateReturning be (ReaderT r m) where
-    runUpdateReturningList = lift . runUpdateReturningList
+    runUpdateReturningListWith sql proj = lift $ runUpdateReturningListWith sql proj
 instance MonadBeamUpdateReturning be m => MonadBeamUpdateReturning be (Lazy.StateT r m) where
-    runUpdateReturningList = lift . runUpdateReturningList
+    runUpdateReturningListWith sql proj = lift $ runUpdateReturningListWith sql proj
 instance MonadBeamUpdateReturning be m => MonadBeamUpdateReturning be (Strict.StateT r m) where
-    runUpdateReturningList = lift . runUpdateReturningList
+    runUpdateReturningListWith sql proj = lift $ runUpdateReturningListWith sql proj
 instance (MonadBeamUpdateReturning be m, Monoid r)
     => MonadBeamUpdateReturning be (Lazy.WriterT r m) where
-    runUpdateReturningList = lift . runUpdateReturningList
+    runUpdateReturningListWith sql proj = lift $ runUpdateReturningListWith sql proj
 instance (MonadBeamUpdateReturning be m, Monoid r)
     => MonadBeamUpdateReturning be (Strict.WriterT r m) where
-    runUpdateReturningList = lift . runUpdateReturningList
+    runUpdateReturningListWith sql proj = lift $ runUpdateReturningListWith sql proj
 instance (MonadBeamUpdateReturning be m, Monoid w)
     => MonadBeamUpdateReturning be (Lazy.RWST r w s m) where
-    runUpdateReturningList = lift . runUpdateReturningList
+    runUpdateReturningListWith sql proj = lift $ runUpdateReturningListWith sql proj
 instance (MonadBeamUpdateReturning be m, Monoid w)
     => MonadBeamUpdateReturning be (Strict.RWST r w s m) where
-    runUpdateReturningList = lift . runUpdateReturningList
+    runUpdateReturningListWith sql proj = lift $ runUpdateReturningListWith sql proj
 
--- | 'MonadBeam's that suppert returning rows that will be deleted by the given
--- @DELETE@ statement. Useful for deallocating resources based on the value of
--- deleted rows.
+-- | 'MonadBeam's that support returning data from rows that will be deleted by
+--   the given @DELETE@ statement. Useful for deallocating resources based on
+--   the value of deleted rows.
 class MonadBeam be m =>
   MonadBeamDeleteReturning be m | m -> be where
-  runDeleteReturningList
+  -- | Execute a @DELETE@ statement and return a list of values projected from
+  --   the deleted rows. The projection function selects which columns are
+  --   returned: pass 'id' to return the full row, or supply a custom
+  --   projection to return a subset.
+  runDeleteReturningListWith
     :: ( Beamable table
-       , Projectible be (table (QExpr be ()))
-       , FromBackendRow be (table Identity) )
+       , Projectible be a
+       , FromBackendRow be (QExprToIdentity a) )
     => SqlDelete be table
-    -> m [table Identity]
+    -> (table (QExpr be ()) -> a)
+    -> m [QExprToIdentity a]
 
+-- | Execute a @DELETE@ statement and return the deleted rows in full.
+--   A convenience around 'runDeleteReturningListWith' that uses 'id' as the
+--   projection.
+runDeleteReturningList
+  :: ( MonadBeamDeleteReturning be m
+     , Beamable table
+     , Projectible be (table (QExpr be ()))
+     , FromBackendRow be (table Identity) )
+  => SqlDelete be table
+  -> m [table Identity]
+runDeleteReturningList sql = runDeleteReturningListWith sql id
+
 instance MonadBeamDeleteReturning be m => MonadBeamDeleteReturning be (ExceptT e m) where
-    runDeleteReturningList = lift . runDeleteReturningList
+    runDeleteReturningListWith sql proj = lift $ runDeleteReturningListWith sql proj
 instance MonadBeamDeleteReturning be m => MonadBeamDeleteReturning be (ContT r m) where
-    runDeleteReturningList = lift . runDeleteReturningList
+    runDeleteReturningListWith sql proj = lift $ runDeleteReturningListWith sql proj
 instance MonadBeamDeleteReturning be m => MonadBeamDeleteReturning be (ReaderT r m) where
-    runDeleteReturningList = lift . runDeleteReturningList
+    runDeleteReturningListWith sql proj = lift $ runDeleteReturningListWith sql proj
 instance MonadBeamDeleteReturning be m => MonadBeamDeleteReturning be (Lazy.StateT r m) where
-    runDeleteReturningList = lift . runDeleteReturningList
+    runDeleteReturningListWith sql proj = lift $ runDeleteReturningListWith sql proj
 instance MonadBeamDeleteReturning be m => MonadBeamDeleteReturning be (Strict.StateT r m) where
-    runDeleteReturningList = lift . runDeleteReturningList
+    runDeleteReturningListWith sql proj = lift $ runDeleteReturningListWith sql proj
 instance (MonadBeamDeleteReturning be m, Monoid r)
     => MonadBeamDeleteReturning be (Lazy.WriterT r m) where
-    runDeleteReturningList = lift . runDeleteReturningList
+    runDeleteReturningListWith sql proj = lift $ runDeleteReturningListWith sql proj
 instance (MonadBeamDeleteReturning be m, Monoid r)
     => MonadBeamDeleteReturning be (Strict.WriterT r m) where
-    runDeleteReturningList = lift . runDeleteReturningList
+    runDeleteReturningListWith sql proj = lift $ runDeleteReturningListWith sql proj
 instance (MonadBeamDeleteReturning be m, Monoid w)
     => MonadBeamDeleteReturning be (Lazy.RWST r w s m) where
-    runDeleteReturningList = lift . runDeleteReturningList
+    runDeleteReturningListWith sql proj = lift $ runDeleteReturningListWith sql proj
 instance (MonadBeamDeleteReturning be m, Monoid w)
     => MonadBeamDeleteReturning be (Strict.RWST r w s m) where
-    runDeleteReturningList = lift . runDeleteReturningList
+    runDeleteReturningListWith sql proj = lift $ runDeleteReturningListWith sql proj
 
 class BeamSqlBackend be => BeamHasInsertOnConflict be where
   -- | Specifies the kind of constraint that must be violated for the action to occur
diff --git a/Database/Beam/Backend/SQL/BeamExtensions/Copy/File.hs b/Database/Beam/Backend/SQL/BeamExtensions/Copy/File.hs
new file mode 100644
--- /dev/null
+++ b/Database/Beam/Backend/SQL/BeamExtensions/Copy/File.hs
@@ -0,0 +1,320 @@
+{-# LANGUAGE UndecidableInstances #-}
+
+-- | File-mode @COPY@: the data lives on the database server's filesystem.
+--
+-- For the variant that streams data through the client connection instead, see
+-- "Database.Beam.Backend.SQL.BeamExtensions.Copy.Stream".
+module Database.Beam.Backend.SQL.BeamExtensions.Copy.File
+  ( -- * Building a COPY statement
+    copyTableTo,
+    copySelectTo,
+    SqlCopyTo (..),
+    copyTableFrom,
+    SqlCopyFrom (..),
+
+    -- * Source-syntax classes (shared with streaming COPY)
+    IsSqlCopyToSourceSyntax (..),
+    IsSqlCopyFromSourceSyntax (..),
+
+    -- * File-mode statement-level syntax classes
+    IsSqlCopyToSyntax (..),
+    IsSqlCopyFromSyntax (..),
+    BeamSqlBackendCopyToSyntax,
+    BeamSqlBackendCopyFromSyntax,
+
+    -- * Runner classes
+    MonadBeamCopyTo (..),
+    MonadBeamCopyFrom (..),
+
+    -- * Internal — exposed for use by sibling modules
+    projection,
+  )
+where
+
+import Control.Monad.Cont (ContT)
+import Control.Monad.Except (ExceptT)
+import qualified Control.Monad.RWS.Lazy as Lazy
+import qualified Control.Monad.RWS.Strict as Strict
+import Control.Monad.Reader (ReaderT)
+import qualified Control.Monad.State.Lazy as Lazy
+import qualified Control.Monad.State.Strict as Strict
+import Control.Monad.Trans (lift)
+import qualified Control.Monad.Writer.Lazy as Lazy
+import qualified Control.Monad.Writer.Strict as Strict
+import Data.Data (Proxy (..))
+import Data.Kind (Type)
+import Data.List.NonEmpty (NonEmpty, nonEmpty)
+import Data.Text (Text)
+import Database.Beam.Backend.SQL (BeamSqlBackendSelectSyntax, MonadBeam (..))
+import Database.Beam.Query (QField, SqlSelect (..))
+import Database.Beam.Query.Internal (AnyType, ProjectibleWithPredicate, QField (..), project')
+import Database.Beam.Schema (TableEntity)
+import Database.Beam.Schema.Tables
+  ( Beamable,
+    Columnar' (..),
+    DatabaseEntity (..),
+    DatabaseEntityDescriptor (DatabaseTable, dbTableSettings),
+    IsDatabaseEntity (dbEntityName, dbEntitySchema),
+    changeBeamRep,
+    fieldName,
+  )
+import Lens.Micro ((^.))
+
+-- | This class allows to express the source of a `COPY ... TO` statement.
+-- The options are either from a table (with a possible projection),
+-- or from the result of a select query.
+--
+-- Reused by both file-mode and streaming COPY: the source shape (a table or
+-- a @SELECT@) is the same regardless of where the data ends up.
+class IsSqlCopyToSourceSyntax syntax where
+  -- | Expected to be equal to `BeamSqlBackendSelectSyntax be`
+  type SqlCopyToSourceSelectSyntax syntax :: Type
+
+  -- Copy an entire table, perhaps with some column projections
+  copyTableToSyntax ::
+    Maybe Text -> -- schema (Nothing = default search path)
+    Text -> -- table name
+    Maybe (NonEmpty Text) -> -- column list; `Nothing` means "all columns"
+    syntax
+
+  -- Copy the result of a select statement
+  copySelectToSyntax ::
+    SqlCopyToSourceSelectSyntax syntax ->
+    syntax
+
+-- | This class allows to express the source of a `COPY ... FROM` statement.
+-- Reused by both file-mode and streaming COPY.
+class IsSqlCopyFromSourceSyntax syntax where
+  -- Copy data into a table, perhaps with some column projections
+  copyTableFromSyntax ::
+    Maybe Text -> -- schema (Nothing = default search path)
+    Text -> -- table name
+    Maybe (NonEmpty Text) -> -- column list; `Nothing` means "all columns"
+    syntax
+
+-- | Statement-level syntax for backends that support @COPY ... TO@ file.
+class (IsSqlCopyToSourceSyntax (SqlCopyToSourceSyntax cmd)) => IsSqlCopyToSyntax cmd where
+  -- | The syntax for the source of the copy. For example, in Postgres,
+  --  this can be either a table (and optional projection), or a select statement.
+  type SqlCopyToSourceSyntax cmd :: Type
+
+  -- | All backend-specific options which determine HOW the copy is performed,
+  --  including the destination of the data (e.g. a filepath).
+  type SqlCopyToParams cmd :: Type
+
+  -- | Combine a source and a parameters value into a complete
+  -- @COPY ... TO ...@ statement.
+  copyToStmt ::
+    SqlCopyToSourceSyntax cmd ->
+    SqlCopyToParams cmd ->
+    cmd
+
+-- | Statement-level syntax for backends that support file-mode @COPY ... FROM@ file.
+--
+-- Symmetric to 'IsSqlCopyToSyntax', but the data flows in the opposite
+-- direction: the params value supplies the source path and any
+-- format-specific options.
+class (IsSqlCopyFromSourceSyntax (SqlCopyFromSourceSyntax cmd)) => IsSqlCopyFromSyntax cmd where
+  -- | The syntax for the destination table of the copy.
+  type SqlCopyFromSourceSyntax cmd :: Type
+
+  -- | All backend-specific options which determine HOW the copy is performed,
+  --  including the source of the data (e.g. a filepath).
+  type SqlCopyFromParams cmd :: Type
+
+  -- | Combine a destination and a parameters value into a complete
+  -- @COPY ... FROM ...@ statement.
+  copyFromStmt ::
+    SqlCopyFromSourceSyntax cmd ->
+    SqlCopyFromParams cmd ->
+    cmd
+
+-- | Type-family selector for the backend's file-mode @COPY ... TO@ syntax.
+-- A backend instance binds this to the concrete syntax type that implements
+-- 'IsSqlCopyToSyntax'.
+type family BeamSqlBackendCopyToSyntax be :: Type
+
+-- | Type-family selector for the backend's file-mode @COPY ... FROM@ syntax.
+-- See 'BeamSqlBackendCopyToSyntax'.
+type family BeamSqlBackendCopyFromSyntax be :: Type
+
+-- | A built file-mode @COPY ... TO@ statement, ready to be executed by
+-- 'runCopyTo'. Construct via 'copyTableTo' or 'copySelectTo'; the @table@
+-- and @proj@ phantom parameters track which table the statement applies to
+-- and which columns it projects.
+data SqlCopyTo be a
+  = SqlCopyTo !(BeamSqlBackendCopyToSyntax be)
+  | -- | A projection covering zero columns. 'runCopyTo' should treat this as a
+    --    no-op rather than emit an empty @COPY tbl () TO ...@ statement.
+    SqlCopyToNoColumns
+
+-- | A built file-mode @COPY ... FROM@ statement, ready to be executed by
+-- 'runCopyFrom'. Construct via 'copyTableFrom'.
+data SqlCopyFrom be a
+  = SqlCopyFrom !(BeamSqlBackendCopyFromSyntax be)
+  | -- | A projection covering zero columns. 'runCopyFrom' should treat this as
+    --    a no-op rather than emit an empty @COPY tbl () FROM ...@ statement.
+    SqlCopyFromNoColumns
+
+-- | Express the copy from a table, to a destination (typically a file).
+--
+-- To copy the result of a @SELECT@ query instead, see `copySelectTo`.
+--
+-- @since 0.11.1.0
+copyTableTo ::
+  ( IsSqlCopyToSyntax (BeamSqlBackendCopyToSyntax be),
+    ProjectibleWithPredicate AnyType () Text proj
+  ) =>
+  DatabaseEntity be db (TableEntity table) ->
+  -- | Projection from table to columns. If you want
+  --  to copy the entire table, use 'id'.
+  (table (QField s) -> proj) ->
+  -- | Backend-specific options. The output is also determined by this value
+  SqlCopyToParams (BeamSqlBackendCopyToSyntax be) ->
+  SqlCopyTo be proj
+copyTableTo (DatabaseEntity dt@(DatabaseTable {})) mkProj options =
+  case nonEmpty (projection dt mkProj) of
+    Nothing -> SqlCopyToNoColumns
+    Just cols ->
+      let source = copyTableToSyntax (dt ^. dbEntitySchema) (dt ^. dbEntityName) (Just cols)
+       in SqlCopyTo
+            (copyToStmt source options)
+
+-- | Express the copy from the result of a @SELECT@ statement to a destination
+-- (typically a file). Use this when the source rows are produced by a query
+-- rather than read directly from a table.
+--
+-- To copy a table, or a subset of columns, see `copyTableTo`.
+--
+-- @since 0.11.1.0
+copySelectTo ::
+  ( IsSqlCopyToSyntax (BeamSqlBackendCopyToSyntax be),
+    SqlCopyToSourceSelectSyntax (SqlCopyToSourceSyntax (BeamSqlBackendCopyToSyntax be))
+      ~ BeamSqlBackendSelectSyntax be
+  ) =>
+  SqlSelect be a ->
+  -- | Backend-specific options. The format is pinned by this value
+  SqlCopyToParams (BeamSqlBackendCopyToSyntax be) ->
+  SqlCopyTo be a
+copySelectTo (SqlSelect selectSyntax) options =
+  let source = copySelectToSyntax selectSyntax
+   in SqlCopyTo (copyToStmt source options)
+
+-- | Express the copy to a table, from an external source (typically a file).
+--
+-- @since 0.11.1.0
+copyTableFrom ::
+  ( IsSqlCopyFromSyntax (BeamSqlBackendCopyFromSyntax be),
+    ProjectibleWithPredicate AnyType () Text proj
+  ) =>
+  DatabaseEntity be db (TableEntity table) ->
+  -- | Projection from table to columns. If you want
+  --  to copy into the entire table, use 'id'.
+  (table (QField s) -> proj) ->
+  -- | Backend-specific options. The format is pinned by this value
+  SqlCopyFromParams (BeamSqlBackendCopyFromSyntax be) ->
+  SqlCopyFrom be proj
+copyTableFrom (DatabaseEntity dt@(DatabaseTable {})) mkProj options =
+  case nonEmpty (projection dt mkProj) of
+    Nothing -> SqlCopyFromNoColumns
+    Just cols ->
+      let source = copyTableFromSyntax (dt ^. dbEntitySchema) (dt ^. dbEntityName) (Just cols)
+       in SqlCopyFrom
+            (copyFromStmt source options)
+
+-- | Walk a projection and collect the names of the columns it touches.
+--
+-- This is the building block 'copyTableTo' / 'copyTableFrom' (and their
+-- streaming counterparts) use to derive the column list for the emitted
+-- @COPY@ statement. Exposed here so that the streaming submodule can reuse
+-- the same logic without duplication.
+projection ::
+  (ProjectibleWithPredicate AnyType () Text proj, Beamable table) =>
+  DatabaseEntityDescriptor be (TableEntity table) ->
+  (table (QField s) -> proj) ->
+  [Text]
+projection dt mkProj =
+  Strict.execWriter
+    ( project'
+        (Proxy @AnyType)
+        (Proxy @((), Text))
+        (\_ _ f -> Strict.tell [f] >> pure f)
+        (mkProj tblFields)
+    )
+  where
+    tblFields =
+      changeBeamRep
+        (\(Columnar' fd) -> Columnar' (QField False (dt ^. dbEntityName) (fd ^. fieldName)))
+        (dbTableSettings dt)
+
+-- | 'MonadBeam's that support copying data out of a database, to some other location.
+--
+-- See 'MonadBeamCopyFrom' for the inverse operation.
+--
+-- @since 0.11.1.0
+class (MonadBeam be m) => MonadBeamCopyTo be m | m -> be where
+  -- | Execute a built @COPY ... TO@ file statement.
+  runCopyTo :: SqlCopyTo be res -> m ()
+
+instance (MonadBeamCopyTo be m) => MonadBeamCopyTo be (ExceptT e m) where
+  runCopyTo = lift . runCopyTo
+
+instance (MonadBeamCopyTo be m) => MonadBeamCopyTo be (ContT r m) where
+  runCopyTo = lift . runCopyTo
+
+instance (MonadBeamCopyTo be m) => MonadBeamCopyTo be (ReaderT r m) where
+  runCopyTo = lift . runCopyTo
+
+instance (MonadBeamCopyTo be m) => MonadBeamCopyTo be (Lazy.StateT r m) where
+  runCopyTo = lift . runCopyTo
+
+instance (MonadBeamCopyTo be m) => MonadBeamCopyTo be (Strict.StateT r m) where
+  runCopyTo = lift . runCopyTo
+
+instance (MonadBeamCopyTo be m, Monoid r) => MonadBeamCopyTo be (Lazy.WriterT r m) where
+  runCopyTo = lift . runCopyTo
+
+instance (MonadBeamCopyTo be m, Monoid r) => MonadBeamCopyTo be (Strict.WriterT r m) where
+  runCopyTo = lift . runCopyTo
+
+instance (MonadBeamCopyTo be m, Monoid w) => MonadBeamCopyTo be (Lazy.RWST r w s m) where
+  runCopyTo = lift . runCopyTo
+
+instance (MonadBeamCopyTo be m, Monoid w) => MonadBeamCopyTo be (Strict.RWST r w s m) where
+  runCopyTo = lift . runCopyTo
+
+-- | 'MonadBeam's that support copying data into database, from other location.
+--
+-- See 'MonadBeamCopyTo' for the inverse operation.
+--
+-- @since 0.11.1.0
+class (MonadBeam be m) => MonadBeamCopyFrom be m | m -> be where
+  -- | Execute a built @COPY ... FROM@ file statement.
+  runCopyFrom :: SqlCopyFrom be proj -> m ()
+
+instance (MonadBeamCopyFrom be m) => MonadBeamCopyFrom be (ExceptT e m) where
+  runCopyFrom = lift . runCopyFrom
+
+instance (MonadBeamCopyFrom be m) => MonadBeamCopyFrom be (ContT r m) where
+  runCopyFrom = lift . runCopyFrom
+
+instance (MonadBeamCopyFrom be m) => MonadBeamCopyFrom be (ReaderT r m) where
+  runCopyFrom = lift . runCopyFrom
+
+instance (MonadBeamCopyFrom be m) => MonadBeamCopyFrom be (Lazy.StateT r m) where
+  runCopyFrom = lift . runCopyFrom
+
+instance (MonadBeamCopyFrom be m) => MonadBeamCopyFrom be (Strict.StateT r m) where
+  runCopyFrom = lift . runCopyFrom
+
+instance (MonadBeamCopyFrom be m, Monoid r) => MonadBeamCopyFrom be (Lazy.WriterT r m) where
+  runCopyFrom = lift . runCopyFrom
+
+instance (MonadBeamCopyFrom be m, Monoid r) => MonadBeamCopyFrom be (Strict.WriterT r m) where
+  runCopyFrom = lift . runCopyFrom
+
+instance (MonadBeamCopyFrom be m, Monoid w) => MonadBeamCopyFrom be (Lazy.RWST r w s m) where
+  runCopyFrom = lift . runCopyFrom
+
+instance (MonadBeamCopyFrom be m, Monoid w) => MonadBeamCopyFrom be (Strict.RWST r w s m) where
+  runCopyFrom = lift . runCopyFrom
diff --git a/Database/Beam/Backend/SQL/BeamExtensions/Copy/Stream.hs b/Database/Beam/Backend/SQL/BeamExtensions/Copy/Stream.hs
new file mode 100644
--- /dev/null
+++ b/Database/Beam/Backend/SQL/BeamExtensions/Copy/Stream.hs
@@ -0,0 +1,289 @@
+{-# LANGUAGE UndecidableInstances #-}
+
+-- | Streaming-mode @COPY@: the data flows through the client connection
+-- rather than to or from a file on the database server.
+--
+-- For the file-mode variant, see
+-- "Database.Beam.Backend.SQL.BeamExtensions.Copy.File".
+module Database.Beam.Backend.SQL.BeamExtensions.Copy.Stream
+  ( -- * Building a streaming COPY statement
+    copyTableToStream,
+    copySelectToStream,
+    SqlCopyToStream (..),
+    copyTableFromStream,
+    SqlCopyFromStream (..),
+
+    -- * Streaming statement-level syntax classes
+    IsSqlCopyToStreamSyntax (..),
+    IsSqlCopyFromStreamSyntax (..),
+    BeamSqlBackendCopyToStreamSyntax,
+    BeamSqlBackendCopyFromStreamSyntax,
+
+    -- * Runner classes
+    MonadBeamCopyToStream (..),
+    MonadBeamCopyFromStream (..),
+  )
+where
+
+import Control.Monad.Cont (ContT)
+import Control.Monad.Except (ExceptT)
+import qualified Control.Monad.RWS.Lazy as Lazy
+import qualified Control.Monad.RWS.Strict as Strict
+import Control.Monad.Reader (ReaderT)
+import qualified Control.Monad.State.Lazy as Lazy
+import qualified Control.Monad.State.Strict as Strict
+import Control.Monad.Trans (lift)
+import qualified Control.Monad.Writer.Lazy as Lazy
+import qualified Control.Monad.Writer.Strict as Strict
+import Data.ByteString (ByteString)
+import Data.Kind (Type)
+import Data.List.NonEmpty (nonEmpty)
+import Data.Text (Text)
+import Database.Beam.Backend.SQL (BeamSqlBackendSelectSyntax, MonadBeam)
+import Database.Beam.Backend.SQL.BeamExtensions.Copy.File
+  ( IsSqlCopyFromSourceSyntax (..),
+    IsSqlCopyToSourceSyntax (..),
+    projection,
+  )
+import Database.Beam.Query (QField, SqlSelect (..))
+import Database.Beam.Query.Internal (AnyType, ProjectibleWithPredicate)
+import Database.Beam.Schema (TableEntity)
+import Database.Beam.Schema.Tables
+  ( DatabaseEntity (..),
+    DatabaseEntityDescriptor (DatabaseTable),
+    IsDatabaseEntity (dbEntityName, dbEntitySchema),
+  )
+import Lens.Micro ((^.))
+
+-- | Statement-level syntax for backends that support streaming
+-- @COPY ... TO@ (data leaving the database through the client connection).
+--
+-- Mirrors 'Database.Beam.Backend.SQL.BeamExtensions.Copy.File.IsSqlCopyToSyntax',
+-- but the params value carries only format options — no destination path,
+-- since chunks travel through the wire.
+class (IsSqlCopyToSourceSyntax (SqlCopyToStreamSourceSyntax cmd)) => IsSqlCopyToStreamSyntax cmd where
+  -- | The syntax for the source of the streaming copy. As with file-mode
+  --  COPY, this can be a table (perhaps with a projection) or a @SELECT@
+  --  query.
+  type SqlCopyToStreamSourceSyntax cmd :: Type
+
+  -- | All backend-specific options which determine HOW the streaming copy
+  --  is performed (format, delimiter, etc.). Unlike the file-mode params,
+  --  there is no destination — chunks flow through the connection.
+  type SqlCopyToStreamParams cmd :: Type
+
+  -- | Combine a source and a parameters value into a complete
+  -- streaming @COPY ... TO@ stream statement.
+  copyToStreamStmt ::
+    SqlCopyToStreamSourceSyntax cmd ->
+    SqlCopyToStreamParams cmd ->
+    cmd
+
+-- | Statement-level syntax for backends that support streaming
+-- @COPY ... FROM@ (data entering the database through the client connection).
+--
+-- Mirrors 'Database.Beam.Backend.SQL.BeamExtensions.Copy.File.IsSqlCopyFromSyntax'.
+class (IsSqlCopyFromSourceSyntax (SqlCopyFromStreamSourceSyntax cmd)) => IsSqlCopyFromStreamSyntax cmd where
+  -- | The syntax for the destination table of the streaming copy.
+  type SqlCopyFromStreamSourceSyntax cmd :: Type
+
+  -- | All backend-specific options which determine HOW the streaming copy
+  --  is performed. Unlike the file-mode params, there is no source path —
+  --  chunks flow through the connection.
+  type SqlCopyFromStreamParams cmd :: Type
+
+  -- | Combine a destination and a parameters value into a complete
+  -- streaming @COPY ... FROM@ stream statement.
+  copyFromStreamStmt ::
+    SqlCopyFromStreamSourceSyntax cmd ->
+    SqlCopyFromStreamParams cmd ->
+    cmd
+
+-- | Type-family selector for the backend's streaming @COPY ... TO@ syntax.
+-- A backend instance binds this to the concrete syntax type that
+-- implements 'IsSqlCopyToStreamSyntax'.
+type family BeamSqlBackendCopyToStreamSyntax be :: Type
+
+-- | Type-family selector for the backend's streaming @COPY ... FROM@ syntax.
+-- See 'BeamSqlBackendCopyToStreamSyntax'.
+type family BeamSqlBackendCopyFromStreamSyntax be :: Type
+
+-- | A built streaming-mode @COPY ... TO@ statement, ready to be executed by
+-- 'runCopyToStream'.
+data SqlCopyToStream be a
+  = SqlCopyToStream !(BeamSqlBackendCopyToStreamSyntax be)
+  | -- | A projection covering zero columns. 'runCopyToStream' should treat
+    --    this as a no-op (it must still call the sink zero times) rather
+    --    than emit an empty @COPY tbl () TO STDOUT@ statement.
+    SqlCopyToStreamNoColumns
+
+-- | A built streaming-mode @COPY ... FROM@ statement, ready to be executed
+-- by 'runCopyFromStream'.
+data SqlCopyFromStream be a
+  = SqlCopyFromStream !(BeamSqlBackendCopyFromStreamSyntax be)
+  | -- | A projection covering zero columns. 'runCopyFromStream' should
+    --    treat this as a no-op (it should not pull from the source) rather
+    --    than emit an empty @COPY tbl () FROM STDIN@ statement.
+    SqlCopyFromStreamNoColumns
+
+-- | Express a streaming copy from a table, the data flowing through the
+-- client connection rather than to a server-side file.
+--
+-- To stream the result of a @SELECT@ query instead, see 'copySelectToStream'.
+--
+-- @since 0.11.1.0
+copyTableToStream ::
+  ( IsSqlCopyToStreamSyntax (BeamSqlBackendCopyToStreamSyntax be),
+    ProjectibleWithPredicate AnyType () Text proj
+  ) =>
+  DatabaseEntity be db (TableEntity table) ->
+  -- | Projection from table to columns. If you want
+  --  to copy the entire table, use 'id'.
+  (table (QField s) -> proj) ->
+  -- | Backend-specific options.
+  SqlCopyToStreamParams (BeamSqlBackendCopyToStreamSyntax be) ->
+  SqlCopyToStream be proj
+copyTableToStream (DatabaseEntity dt@(DatabaseTable {})) mkProj options =
+  case nonEmpty (projection dt mkProj) of
+    Nothing -> SqlCopyToStreamNoColumns
+    Just cols ->
+      let source = copyTableToSyntax (dt ^. dbEntitySchema) (dt ^. dbEntityName) (Just cols)
+       in SqlCopyToStream
+            (copyToStreamStmt source options)
+
+-- | Express a streaming copy from the result of a @SELECT@ statement.
+--
+-- To stream a table, or a subset of columns, see 'copyTableToStream'.
+--
+-- @since 0.11.1.0
+copySelectToStream ::
+  ( IsSqlCopyToStreamSyntax (BeamSqlBackendCopyToStreamSyntax be),
+    SqlCopyToSourceSelectSyntax (SqlCopyToStreamSourceSyntax (BeamSqlBackendCopyToStreamSyntax be))
+      ~ BeamSqlBackendSelectSyntax be
+  ) =>
+  SqlSelect be a ->
+  SqlCopyToStreamParams (BeamSqlBackendCopyToStreamSyntax be) ->
+  SqlCopyToStream be a
+copySelectToStream (SqlSelect selectSyntax) options =
+  let source = copySelectToSyntax selectSyntax
+   in SqlCopyToStream (copyToStreamStmt source options)
+
+-- | Express a streaming copy into a table, the data flowing through the
+-- client connection rather than from a server-side file.
+--
+-- @since 0.11.1.0
+copyTableFromStream ::
+  ( IsSqlCopyFromStreamSyntax (BeamSqlBackendCopyFromStreamSyntax be),
+    ProjectibleWithPredicate AnyType () Text proj
+  ) =>
+  DatabaseEntity be db (TableEntity table) ->
+  -- | Projection from which to copy columns. Other columns
+  -- will have their default value inserted.
+  --
+  -- To copy the stream into the entire table, use 'id'.
+  (table (QField s) -> proj) ->
+  SqlCopyFromStreamParams (BeamSqlBackendCopyFromStreamSyntax be) ->
+  SqlCopyFromStream be proj
+copyTableFromStream (DatabaseEntity dt@(DatabaseTable {})) mkProj options =
+  case nonEmpty (projection dt mkProj) of
+    Nothing -> SqlCopyFromStreamNoColumns
+    Just cols ->
+      let source = copyTableFromSyntax (dt ^. dbEntitySchema) (dt ^. dbEntityName) (Just cols)
+       in SqlCopyFromStream
+            (copyFromStreamStmt source options)
+
+-- | 'MonadBeam's that support streaming data out of a database through the
+-- client connection (e.g. PostgreSQL's @COPY ... TO STDOUT@).
+--
+-- The supplied @ByteString -> IO ()@ callback is invoked once per chunk
+-- received. The 'runCopyToStream' call blocks until the COPY completes; on
+-- failure it raises the underlying backend's exception.
+--
+-- See 'MonadBeamCopyFromStream' for the inverse operation.
+--
+-- @since 0.11.1.0
+class (MonadBeam be m) => MonadBeamCopyToStream be m | m -> be where
+  -- | Execute a built streaming @COPY ... TO@ stream statement. The supplied sink
+  -- is invoked from 'IO' once per chunk emitted by the server, in order;
+  -- 'runCopyToStream' returns once the server signals end of stream.
+  runCopyToStream ::
+    SqlCopyToStream be a ->
+    -- | Sink. Called once for each chunk of bytes the server emits.
+    (ByteString -> IO ()) ->
+    m ()
+
+instance (MonadBeamCopyToStream be m) => MonadBeamCopyToStream be (ExceptT e m) where
+  runCopyToStream s cb = lift (runCopyToStream s cb)
+
+instance (MonadBeamCopyToStream be m) => MonadBeamCopyToStream be (ContT r m) where
+  runCopyToStream s cb = lift (runCopyToStream s cb)
+
+instance (MonadBeamCopyToStream be m) => MonadBeamCopyToStream be (ReaderT r m) where
+  runCopyToStream s cb = lift (runCopyToStream s cb)
+
+instance (MonadBeamCopyToStream be m) => MonadBeamCopyToStream be (Lazy.StateT r m) where
+  runCopyToStream s cb = lift (runCopyToStream s cb)
+
+instance (MonadBeamCopyToStream be m) => MonadBeamCopyToStream be (Strict.StateT r m) where
+  runCopyToStream s cb = lift (runCopyToStream s cb)
+
+instance (MonadBeamCopyToStream be m, Monoid r) => MonadBeamCopyToStream be (Lazy.WriterT r m) where
+  runCopyToStream s cb = lift (runCopyToStream s cb)
+
+instance (MonadBeamCopyToStream be m, Monoid r) => MonadBeamCopyToStream be (Strict.WriterT r m) where
+  runCopyToStream s cb = lift (runCopyToStream s cb)
+
+instance (MonadBeamCopyToStream be m, Monoid w) => MonadBeamCopyToStream be (Lazy.RWST r w s m) where
+  runCopyToStream s cb = lift (runCopyToStream s cb)
+
+instance (MonadBeamCopyToStream be m, Monoid w) => MonadBeamCopyToStream be (Strict.RWST r w s m) where
+  runCopyToStream s cb = lift (runCopyToStream s cb)
+
+-- | 'MonadBeam's that support streaming data into a database through the
+-- client connection (e.g. PostgreSQL's @COPY ... FROM STDIN@).
+--
+-- The supplied @IO (Maybe ByteString)@ source is pulled repeatedly until it
+-- returns 'Nothing', signalling end of data. 'runCopyFromStream' blocks
+-- until the COPY commits; on failure it raises the underlying backend's
+-- exception.
+--
+-- See 'MonadBeamCopyToStream' for the inverse operation.
+--
+-- @since 0.11.1.0
+class (MonadBeam be m) => MonadBeamCopyFromStream be m | m -> be where
+  -- | Execute a built streaming @COPY ... FROM@ statement. The supplied
+  -- producer is pulled from 'IO' until it returns 'Nothing'; each 'Just'
+  -- chunk is forwarded to the server in order. 'runCopyFromStream' returns
+  -- once the server has acknowledged the end of stream.
+  runCopyFromStream ::
+    SqlCopyFromStream be a ->
+    -- | Source. Called repeatedly. 'Nothing' signals end of data.
+    IO (Maybe ByteString) ->
+    m ()
+
+instance (MonadBeamCopyFromStream be m) => MonadBeamCopyFromStream be (ExceptT e m) where
+  runCopyFromStream s producer = lift (runCopyFromStream s producer)
+
+instance (MonadBeamCopyFromStream be m) => MonadBeamCopyFromStream be (ContT r m) where
+  runCopyFromStream s producer = lift (runCopyFromStream s producer)
+
+instance (MonadBeamCopyFromStream be m) => MonadBeamCopyFromStream be (ReaderT r m) where
+  runCopyFromStream s producer = lift (runCopyFromStream s producer)
+
+instance (MonadBeamCopyFromStream be m) => MonadBeamCopyFromStream be (Lazy.StateT r m) where
+  runCopyFromStream s producer = lift (runCopyFromStream s producer)
+
+instance (MonadBeamCopyFromStream be m) => MonadBeamCopyFromStream be (Strict.StateT r m) where
+  runCopyFromStream s producer = lift (runCopyFromStream s producer)
+
+instance (MonadBeamCopyFromStream be m, Monoid r) => MonadBeamCopyFromStream be (Lazy.WriterT r m) where
+  runCopyFromStream s producer = lift (runCopyFromStream s producer)
+
+instance (MonadBeamCopyFromStream be m, Monoid r) => MonadBeamCopyFromStream be (Strict.WriterT r m) where
+  runCopyFromStream s producer = lift (runCopyFromStream s producer)
+
+instance (MonadBeamCopyFromStream be m, Monoid w) => MonadBeamCopyFromStream be (Lazy.RWST r w s m) where
+  runCopyFromStream s producer = lift (runCopyFromStream s producer)
+
+instance (MonadBeamCopyFromStream be m, Monoid w) => MonadBeamCopyFromStream be (Strict.RWST r w s m) where
+  runCopyFromStream s producer = lift (runCopyFromStream s producer)
diff --git a/Database/Beam/Backend/SQL/Builder.hs b/Database/Beam/Backend/SQL/Builder.hs
--- a/Database/Beam/Backend/SQL/Builder.hs
+++ b/Database/Beam/Backend/SQL/Builder.hs
@@ -191,6 +191,7 @@
   minutesField = SqlSyntaxBuilder (byteString "MINUTE")
   hourField    = SqlSyntaxBuilder (byteString "HOUR")
   dayField     = SqlSyntaxBuilder (byteString "DAY")
+  weekField    = SqlSyntaxBuilder (byteString "WEEK")
   monthField   = SqlSyntaxBuilder (byteString "MONTH")
   yearField    = SqlSyntaxBuilder (byteString "YEAR")
 
@@ -272,7 +273,9 @@
 
   defaultE = SqlSyntaxBuilder (byteString "DEFAULT")
   inE a es = SqlSyntaxBuilder (byteString "(" <> buildSql a <> byteString ") IN (" <>
-                               buildSepBy (byteString ", ") (map buildSql es))
+                               buildSepBy (byteString ", ") (map buildSql es) <> byteString ")")
+  inSelectE a sel = SqlSyntaxBuilder (byteString "(" <> buildSql a <> byteString ") IN (" <>
+                                      buildSql sel <> byteString ")")
 
 instance IsSql99FunctionExpressionSyntax SqlSyntaxBuilder where
   functionNameE fn = SqlSyntaxBuilder (byteString (TE.encodeUtf8 fn))
@@ -402,6 +405,9 @@
        (map (\vs -> byteString "(" <>
                     buildSepBy (byteString ", ") (map buildSql vs) <>
                     byteString ")") vss)
+
+instance IsSql92SchemaNameSyntax SqlSyntaxBuilder where
+  schemaName = SqlSyntaxBuilder . quoteSql
 
 instance IsSql92TableNameSyntax SqlSyntaxBuilder where
   tableName Nothing t  = SqlSyntaxBuilder $ quoteSql t
diff --git a/Database/Beam/Backend/SQL/Row.hs b/Database/Beam/Backend/SQL/Row.hs
--- a/Database/Beam/Backend/SQL/Row.hs
+++ b/Database/Beam/Backend/SQL/Row.hs
@@ -13,6 +13,9 @@
   , ColumnParseError(..), BeamRowReadError(..)
 
   , FromBackendRow(..)
+
+    -- * Exported so we can override defaults
+  , GFromBackendRow(..) -- for 'runSelectReturningList' and co
   ) where
 
 import           Database.Beam.Backend.SQL.Types
@@ -20,6 +23,7 @@
 
 import           Control.Applicative
 import           Control.Exception (Exception)
+import           Control.Monad
 import           Control.Monad.Free.Church
 import           Control.Monad.Identity
 import           Data.Kind (Type)
@@ -101,6 +105,8 @@
   valuesNeeded :: Proxy be -> Proxy a -> Int
   valuesNeeded _ _ = 1
 
+deriving instance FromBackendRow be a => FromBackendRow be (Identity a)
+
 class GFromBackendRow be (exposed :: Type -> Type) rep where
   gFromBackendRow :: Proxy exposed -> FromBackendRowM be (rep ())
   gValuesNeeded :: Proxy be -> Proxy exposed -> Proxy rep -> Int
@@ -114,6 +120,9 @@
   gFromBackendRow _ = (:*:) <$> gFromBackendRow (Proxy @aExp) <*> gFromBackendRow (Proxy @bExp)
   gValuesNeeded be _ _ = gValuesNeeded be (Proxy @aExp) (Proxy @a) + gValuesNeeded be (Proxy @bExp) (Proxy @b)
 instance FromBackendRow be x => GFromBackendRow be (K1 R (Exposed x)) (K1 R x) where
+  gFromBackendRow _ = K1 <$> fromBackendRow
+  gValuesNeeded be _ _ = valuesNeeded be (Proxy @x)
+instance FromBackendRow be x => GFromBackendRow be (K1 R (Exposed x))  (K1 R (Identity x)) where
   gFromBackendRow _ = K1 <$> fromBackendRow
   gValuesNeeded be _ _ = valuesNeeded be (Proxy @x)
 instance FromBackendRow be (t Identity) => GFromBackendRow be (K1 R (t Exposed)) (K1 R (t Identity)) where
diff --git a/Database/Beam/Backend/SQL/SQL92.hs b/Database/Beam/Backend/SQL/SQL92.hs
--- a/Database/Beam/Backend/SQL/SQL92.hs
+++ b/Database/Beam/Backend/SQL/SQL92.hs
@@ -206,6 +206,7 @@
   minutesField :: extractField
   hourField :: extractField
   dayField :: extractField
+  weekField :: extractField
   monthField :: extractField
   yearField :: extractField
 
@@ -315,6 +316,7 @@
   defaultE :: expr
 
   inE :: expr -> [ expr ] -> expr
+  inSelectE :: expr -> Sql92ExpressionSelectSyntax expr -> expr
 
 instance HasSqlValueSyntax syntax x => HasSqlValueSyntax syntax (SqlSerial x) where
   sqlValueSyntax (SqlSerial x) = sqlValueSyntax x
@@ -341,6 +343,10 @@
   type Sql92OrderingExpressionSyntax ord :: Type
   ascOrdering, descOrdering
     :: Sql92OrderingExpressionSyntax ord -> ord
+
+class IsSql92SchemaNameSyntax schemaName where
+  schemaName :: Text {-^ Schema name -}
+             -> schemaName
 
 class IsSql92TableNameSyntax tblName where
   tableName :: Maybe Text {-^ Schema -}
diff --git a/Database/Beam/Backend/SQL/Types.hs b/Database/Beam/Backend/SQL/Types.hs
--- a/Database/Beam/Backend/SQL/Types.hs
+++ b/Database/Beam/Backend/SQL/Types.hs
@@ -3,14 +3,15 @@
 
 import qualified Data.Aeson as Json
 import           Data.Bits
+import           GHC.Generics (Generic)
 
 data SqlNull = SqlNull
-  deriving (Show, Eq, Ord, Bounded, Enum)
+  deriving (Show, Eq, Ord, Bounded, Enum, Generic)
 newtype SqlBitString = SqlBitString Integer
-  deriving (Show, Eq, Ord, Enum, Bits)
+  deriving (Show, Eq, Ord, Enum, Bits, Generic)
 
 newtype SqlSerial a = SqlSerial { unSerial :: a }
-  deriving (Show, Read, Eq, Ord, Num, Integral, Real, Enum)
+  deriving (Show, Read, Eq, Ord, Num, Integral, Real, Enum, Generic)
 
 instance Json.FromJSON a => Json.FromJSON (SqlSerial a) where
   parseJSON a = SqlSerial <$> Json.parseJSON a
diff --git a/Database/Beam/Backend/Types.hs b/Database/Beam/Backend/Types.hs
--- a/Database/Beam/Backend/Types.hs
+++ b/Database/Beam/Backend/Types.hs
@@ -6,8 +6,8 @@
   , Exposed, Nullable
 
   ) where
+import Data.Kind (Type, Constraint)
 
-import GHC.Types
 
 -- | Class for all Beam backends
 class BeamBackend be where
diff --git a/Database/Beam/Query.hs b/Database/Beam/Query.hs
--- a/Database/Beam/Query.hs
+++ b/Database/Beam/Query.hs
@@ -45,6 +45,7 @@
     , HasTableEquality
     , SqlEq(..), SqlOrd(..), SqlIn(..)
     , HasSqlInTable(..)
+    , inQuery_
 
     -- ** Quantified Comparison Operators #quantified-comparison-operator#
     , SqlEqQuantified(..), SqlOrdQuantified(..)
@@ -64,6 +65,7 @@
     , select, selectWith, lookup_
     , runSelectReturningList
     , runSelectReturningOne
+    , runSelectReturningFirst
     , dumpSqlSelect
 
     -- ** @INSERT@
@@ -194,6 +196,15 @@
   SqlSelect be a -> m (Maybe a)
 runSelectReturningOne (SqlSelect s) =
   runReturningOne (selectCmd s)
+
+-- | Run a 'SqlSelect' in a 'MonadBeam' and get the first result, if there is
+--   one.
+--   This is not guaranteed to automatically limit the query to one result.
+runSelectReturningFirst ::
+  (MonadBeam be m, BeamSqlBackend be, FromBackendRow be a) =>
+  SqlSelect be a -> m (Maybe a)
+runSelectReturningFirst (SqlSelect s) =
+  runReturningFirst (selectCmd s)
 
 -- | Use a special debug syntax to print out an ANSI Standard @SELECT@ statement
 --   that may be generated for a given 'Q'.
diff --git a/Database/Beam/Query/CTE.hs b/Database/Beam/Query/CTE.hs
--- a/Database/Beam/Query/CTE.hs
+++ b/Database/Beam/Query/CTE.hs
@@ -8,8 +8,9 @@
 import Database.Beam.Query.Internal
 import Database.Beam.Query.Types
 
+import Control.Monad.Fix
 import Control.Monad.Free.Church
-import Control.Monad.Writer hiding ((<>))
+import Control.Monad.Writer (WriterT, tell)
 import Control.Monad.State.Strict
 
 import Data.Kind (Type)
diff --git a/Database/Beam/Query/Combinators.hs b/Database/Beam/Query/Combinators.hs
--- a/Database/Beam/Query/Combinators.hs
+++ b/Database/Beam/Query/Combinators.hs
@@ -1,6 +1,5 @@
 {-# LANGUAGE CPP #-}
 {-# LANGUAGE UndecidableInstances #-}
-{-# LANGUAGE CPP #-}
 
 module Database.Beam.Query.Combinators
     ( -- * Various SQL functions and constructs
@@ -41,7 +40,8 @@
     , QIfCond, QIfElse
     , (<|>.)
 
-    , limit_, offset_
+    , limit_, limitMaybe_
+    , offset_, offsetMaybe_
 
     , as_
 
@@ -66,8 +66,8 @@
     , orderBy_, asc_, desc_, nullsFirst_, nullsLast_
     ) where
 
-import Database.Beam.Backend.Types
 import Database.Beam.Backend.SQL
+import Database.Beam.Backend.Types
 
 import Database.Beam.Query.Internal
 import Database.Beam.Query.Ord
@@ -80,41 +80,49 @@
 import Control.Monad.Free
 import Control.Applicative
 
+import Data.List.NonEmpty (NonEmpty)
+import qualified Data.List.NonEmpty as NonEmpty
 import Data.Maybe
 import Data.Proxy
 import Data.Time (LocalTime)
+import Unsafe.Coerce (unsafeCoerce)
 
 import GHC.TypeLits (TypeError, ErrorMessage(Text))
 
 -- | Introduce all entries of a table into the 'Q' monad
-all_ :: ( Database be db, BeamSqlBackend be )
-       => DatabaseEntity be db (TableEntity table)
-       -> Q be db s (table (QExpr be s))
+all_ :: BeamSqlBackend be
+     => DatabaseEntity be db (TableEntity table)
+     -> Q be db s (table (QExpr be s))
 all_ (DatabaseEntity dt@(DatabaseTable {})) =
     Q $ liftF (QAll (\_ -> fromTable (tableNamed (tableName (dbTableSchema dt) (dbTableCurrentName dt))) . Just . (,Nothing))
                     (tableFieldsToExpressions (dbTableSettings dt))
                     (\_ -> Nothing) snd)
 
 -- | Introduce all entries of a view into the 'Q' monad
-allFromView_ :: ( Database be db, Beamable table
-                , BeamSqlBackend be )
-               => DatabaseEntity be db (ViewEntity table)
-               -> Q be db s (table (QExpr be s))
+allFromView_ :: ( Beamable table, BeamSqlBackend be )
+             => DatabaseEntity be db (ViewEntity table)
+             -> Q be db s (table (QExpr be s))
 allFromView_ (DatabaseEntity vw) =
     Q $ liftF (QAll (\_ -> fromTable (tableNamed (tableName (dbViewSchema vw) (dbViewCurrentName vw))) . Just . (,Nothing))
                     (tableFieldsToExpressions (dbViewSettings vw))
                     (\_ -> Nothing) snd)
 
--- | SQL @VALUES@ clause. Introduce the elements of the given list as
+-- | SQL @VALUES@ clause. Introduce the elements of the given non-empty list as
 -- rows in a joined table.
 values_ :: forall be db s a
          . ( Projectible be a
            , BeamSqlBackend be )
-        => [ a ] -> Q be db s a
+        => NonEmpty a
+        -> Q be db s a
 values_ rows =
-    Q $ liftF (QAll (\tblPfx -> fromTable (tableFromValues (map (\row -> project (Proxy @be) row tblPfx) rows)) . Just . (,Just fieldNames))
+    Q $ liftF (QAll (\tblPfx -> 
+                      fromTable 
+                        (tableFromValues (NonEmpty.toList (NonEmpty.map (\row -> project (Proxy @be) row tblPfx) rows))) 
+                        . Just 
+                        . (,Just fieldNames))
                     (\tblNm' -> fst $ mkFieldNames (qualifiedField tblNm'))
-                    (\_ -> Nothing) snd)
+                    (\_ -> Nothing) snd
+              )
     where
       fieldNames = snd $ mkFieldNames @be @a unqualifiedField
 
@@ -123,7 +131,7 @@
 --   'Bool'. For a version that takes 'SqlBool' (a possibly @UNKNOWN@
 --   boolean, that maps more closely to the SQL standard), see
 --   'join_''.
-join_ :: ( Database be db, Table table, BeamSqlBackend be )
+join_ :: ( Table table, BeamSqlBackend be )
       => DatabaseEntity be db (TableEntity table)
       -> (table (QExpr be s) -> QExpr be s Bool)
       -> Q be db s (table (QExpr be s))
@@ -131,7 +139,7 @@
 
 -- | Like 'join_', but accepting an @ON@ condition that returns
 -- 'SqlBool'
-join_' :: ( Database be db, Table table, BeamSqlBackend be )
+join_' :: ( Table table, BeamSqlBackend be )
        => DatabaseEntity be db (TableEntity table)
        -> (table (QExpr be s) -> QExpr be s SqlBool)
        -> Q be db s (table (QExpr be s))
@@ -152,7 +160,7 @@
          -> Q be db s (Retag Nullable (WithRewrittenThread (QNested s) s r))
 perhaps_ (Q sub) =
   Q $ liftF (QArbitraryJoin
-              sub leftJoin
+              sub "" leftJoin
               (\_ -> Nothing)
               (\r -> retag (\(Columnar' (QExpr e) :: Columnar' (QExpr be s) a) ->
                                             Columnar' (QExpr e) :: Columnar' (Nullable (QExpr be s)) a) $
@@ -232,7 +240,7 @@
            -> Q be db s (Retag Nullable (WithRewrittenThread (QNested s) s r))
 leftJoin_' (Q sub) on_ =
   Q $ liftF (QArbitraryJoin
-               sub leftJoin
+               sub "" leftJoin
                (\r -> let QExpr e = on_ (rewriteThread (Proxy @s) r) in Just e)
                (\r -> retag (\(Columnar' (QExpr e) :: Columnar' (QExpr be s) a) ->
                                 Columnar' (QExpr e) :: Columnar' (Nullable (QExpr be s)) a) $
@@ -281,7 +289,7 @@
 
 -- | Introduce all entries of the given table which are referenced by the given 'PrimaryKey'
 related_ :: forall be db rel s
-          . ( Database be db, Table rel, BeamSqlBackend be
+          . ( Table rel, BeamSqlBackend be
             , HasTableEquality be (PrimaryKey rel)
             )
          => DatabaseEntity be db (TableEntity rel)
@@ -292,7 +300,7 @@
 
 -- | Introduce all entries of the given table for which the expression (which can depend on the queried table returns true)
 relatedBy_ :: forall be db rel s
-            . ( Database be db, Table rel, BeamSqlBackend be )
+            . ( Table rel, BeamSqlBackend be )
            => DatabaseEntity be db (TableEntity rel)
            -> (rel (QExpr be s) -> QExpr be s Bool)
            -> Q be db s (rel (QExpr be s))
@@ -300,7 +308,7 @@
 
 -- | Introduce all entries of the given table for which the expression (which can depend on the queried table returns true)
 relatedBy_' :: forall be db rel s
-             . ( Database be db, Table rel, BeamSqlBackend be )
+             . ( Table rel, BeamSqlBackend be )
             => DatabaseEntity be db (TableEntity rel)
             -> (rel (QExpr be s) -> QExpr be s SqlBool)
             -> Q be db s (rel (QExpr be s))
@@ -328,6 +336,8 @@
 nub_ (Q sub) = Q $ liftF (QDistinct (\_ _ -> setQuantifierDistinct) sub id)
 
 -- | Limit the number of results returned by a query.
+--
+-- See also `limitMaybe_` to conditionally apply a limit.
 limit_ :: forall s a be db
         . ( Projectible be a
           , ThreadRewritable (QNested s) a )
@@ -335,7 +345,22 @@
 limit_ limit' (Q q) =
   Q (liftF (QLimit limit' q (rewriteThread (Proxy @s))))
 
--- | Drop the first `offset'` results.
+-- | Conditionally limit the number of results returned by a query.
+--
+-- @since 0.10.4.0
+limitMaybe_ :: forall s a be db
+        . ( Projectible be a
+          , ThreadRewritable (QNested s) a )
+        => Maybe Integer -> Q be db (QNested s) a -> Q be db s (WithRewrittenThread (QNested s) s a)
+limitMaybe_ (Just limit') (Q q) =
+  Q (liftF (QLimit limit' q (rewriteThread (Proxy @s))))
+-- This uses unsafeCoerce, but should be safe since this function is tested.
+-- See discussion on https://github.com/haskell-beam/beam/pull/633.
+limitMaybe_ Nothing (Q q) = Q (unsafeCoerce q)
+
+-- | Drop the first `offset` results.
+--
+-- See also `offsetMaybe_` to conditionally apply an offset
 offset_ :: forall s a be db
          . ( Projectible be a
            , ThreadRewritable (QNested s) a )
@@ -343,6 +368,19 @@
 offset_ offset' (Q q) =
   Q (liftF (QOffset offset' q (rewriteThread (Proxy @s))))
 
+-- | Conditionally drop the first `offset` results.
+--
+-- @since 0.10.4.0
+offsetMaybe_ :: forall s a be db
+         . ( Projectible be a
+           , ThreadRewritable (QNested s) a )
+        => Maybe Integer -> Q be db (QNested s) a -> Q be db s (WithRewrittenThread (QNested s) s a)
+offsetMaybe_ (Just offset') (Q q) =
+  Q (liftF (QOffset offset' q (rewriteThread (Proxy @s))))
+-- This uses unsafeCoerce, but should be safe since this function is tested.
+-- See discussion on https://github.com/haskell-beam/beam/pull/633.
+offsetMaybe_ Nothing (Q q) = Q (unsafeCoerce q)
+
 -- | Use the SQL @EXISTS@ operator to determine if the given query returns any results
 exists_ :: ( BeamSqlBackend be, HasQBuilder be, Projectible be a)
         => Q be db s a -> QExpr be s Bool
@@ -564,7 +602,14 @@
     in changeBeamRep (\(Columnar' (WithConstraint x :: WithConstraint (BeamSqlBackendCanSerialize be) (Maybe x))) ->
                          Columnar' (QExpr (pure (valueE (sqlValueSyntax x))))) fields
 
+-- | SQL @DEFAULT@ support.
+--
+-- Note that  `default_` has restrictions not currently represented in the Haskell type system.
+-- For example, using `default_` as the argument to a function like `coalesce_`
+-- will result in a runtime error, just like the SQL code @COALESCE (NULL, DEFAULT)@
+-- would raise a runtime error.
 default_ :: BeamSqlBackend be => QGenExpr ctxt be s a
+-- See #744 for issues with `default_`.
 default_ = QExpr (pure defaultE)
 
 -- * Window functions
@@ -854,7 +899,7 @@
     isNothing_ t = allE (allBeamValues (\(Columnar' e) -> isNothing_ e) t)
     maybe_ (QExpr onNothing) onJust tbl =
       let QExpr onJust' = onJust (changeBeamRep (\(Columnar' (QExpr e)) -> Columnar' (QExpr e)) tbl)
-          QExpr cond = isJust_ tbl
+          QExpr cond = isJust_ @be tbl
       in QExpr (\tblPfx -> caseE [(cond tblPfx, onJust' tblPfx)] (onNothing tblPfx))
 
 infixl 3 <|>.
diff --git a/Database/Beam/Query/Extensions.hs b/Database/Beam/Query/Extensions.hs
--- a/Database/Beam/Query/Extensions.hs
+++ b/Database/Beam/Query/Extensions.hs
@@ -47,13 +47,13 @@
 
 lead1_, lag1_
   :: (BeamSqlBackend be, BeamSqlT615Backend be)
-  => QExpr be s a -> QAgg be s a
+  => QExpr be s a -> QAgg be s (Maybe a)
 lead1_ (QExpr a) = QExpr (leadE <$> a <*> pure Nothing <*> pure Nothing)
 lag1_ (QExpr a) = QExpr (lagE <$> a <*> pure Nothing <*> pure Nothing)
 
 lead_, lag_
   :: (BeamSqlBackend be, BeamSqlT615Backend be, Integral n)
-  => QExpr be s a -> QExpr be s n -> QAgg be s a
+  => QExpr be s a -> QExpr be s n -> QAgg be s (Maybe a)
 lead_ (QExpr a) (QExpr n) = QExpr (leadE <$> a <*> (Just <$> n) <*> pure Nothing)
 lag_ (QExpr a) (QExpr n) = QExpr (lagE <$> a <*> (Just <$> n) <*> pure Nothing)
 
diff --git a/Database/Beam/Query/Extract.hs b/Database/Beam/Query/Extract.hs
--- a/Database/Beam/Query/Extract.hs
+++ b/Database/Beam/Query/Extract.hs
@@ -7,7 +7,7 @@
 
       -- ** SQL92 fields
       hour_, minutes_, seconds_,
-      year_, month_, day_,
+      year_, month_, week_, day_,
 
       HasSqlTime, HasSqlDate
     ) where
@@ -53,9 +53,10 @@
 instance HasSqlDate UTCTime
 instance HasSqlDate Day
 
-year_, month_, day_
+year_, month_, week_, day_
     :: ( BeamSqlBackend be, HasSqlDate tgt )
     => ExtractField be tgt Double
 year_  = ExtractField yearField
 month_ = ExtractField monthField
 day_   = ExtractField dayField
+week_  = ExtractField weekField
diff --git a/Database/Beam/Query/Internal.hs b/Database/Beam/Query/Internal.hs
--- a/Database/Beam/Query/Internal.hs
+++ b/Database/Beam/Query/Internal.hs
@@ -1,6 +1,5 @@
 {-# OPTIONS_GHC -fno-warn-unticked-promoted-constructors#-}
 {-# LANGUAGE UndecidableInstances #-}
-{-# LANGUAGE CPP #-}
 
 module Database.Beam.Query.Internal where
 
@@ -10,21 +9,18 @@
 
 import qualified Data.DList as DList
 import           Data.Functor.Const
+import           Data.Kind (Type, Constraint)
 import           Data.String
 import qualified Data.Text as T
 import           Data.Typeable
 import           Data.Vector.Sized (Vector)
 import qualified Data.Vector.Sized as VS
-#if !MIN_VERSION_base(4, 11, 0)
-import           Data.Semigroup
-#endif
 
 import           Control.Monad.Free.Church
 import           Control.Monad.State
 import           Control.Monad.Writer
 
 import           GHC.TypeLits
-import           GHC.Types
 
 import           Unsafe.Coerce
 
@@ -41,12 +37,18 @@
 
   QAll :: Projectible be r
        => (TablePrefix -> T.Text -> BeamSqlBackendFromSyntax be)
+           -- ^ build the FROM syntax using the table prefix and the table name
        -> (T.Text -> r)
+          -- ^ Given a table name, get the various Qs for all the expressions in that table
        -> (r -> Maybe (WithExprContext (BeamSqlBackendExpressionSyntax be)))
-       -> ((T.Text, r) -> next) -> QF be db s next
+          -- ^ on clause, if any
+       -> ((T.Text, r) -> next)
+          -- ^ Generate the result from the table name and projectible result
+       -> QF be db s next
 
   QArbitraryJoin :: Projectible be r
                  => QM be db (QNested s) r
+                 -> T.Text -- Table namespace
                  -> (BeamSqlBackendFromSyntax be -> BeamSqlBackendFromSyntax be ->
                      Maybe (BeamSqlBackendExpressionSyntax be) ->
                      BeamSqlBackendFromSyntax be)
diff --git a/Database/Beam/Query/Ord.hs b/Database/Beam/Query/Ord.hs
--- a/Database/Beam/Query/Ord.hs
+++ b/Database/Beam/Query/Ord.hs
@@ -38,6 +38,8 @@
   , anyOf_, anyIn_
   , allOf_, allIn_
 
+  , inQuery_
+
   , between_
   ) where
 
@@ -199,7 +201,11 @@
     where toExpr :: table (QGenExpr context be s) -> TablePrefix -> BeamSqlBackendExpressionSyntax be
           toExpr = fmap rowE . sequence . allBeamValues (\(Columnar' (QExpr x)) -> x)
 
-infix 4 `between_`, `in_`
+infix 4 `between_`, `in_`, `inQuery_`
+
+inQuery_ :: (HasQBuilder be, BeamSqlBackend be)
+         => QGenExpr ctx be s a -> Q be db s (QExpr be s a) -> QGenExpr ctx be s Bool
+inQuery_ (QExpr needle) haystack = QExpr (inSelectE <$> needle <*> flip buildSqlQuery haystack)
 
 -- | Class for expression types or expression containers for which there is a
 --   notion of equality.
diff --git a/Database/Beam/Query/SQL92.hs b/Database/Beam/Query/SQL92.hs
--- a/Database/Beam/Query/SQL92.hs
+++ b/Database/Beam/Query/SQL92.hs
@@ -212,28 +212,29 @@
                  -> T.Text {-^ Table prefix -}
                  -> Q be db s a
                  -> BeamSqlBackendSelectSyntax be
-buildSql92Query' arbitrarilyNestedCombinations tblPfx (Q q) =
-    buildSelect tblPfx (buildQuery (fromF q))
+buildSql92Query' arbitrarilyNestedCombinations baseTblPfx (Q q) =
+    buildSelect baseTblPfx (buildQuery baseTblPfx (fromF q))
   where
     be :: Proxy be
     be = Proxy
 
     buildQuery :: forall s x
                 . Projectible be x
-               => Free (QF be db s) x
+               => T.Text
+               -> Free (QF be db s) x
                -> SelectBuilder be db x
-    buildQuery (Pure x) = SelectBuilderQ x emptyQb
-    buildQuery (Free (QGuard _ next)) = buildQuery next
-    buildQuery f@(Free QAll {}) = buildJoinedQuery f emptyQb
-    buildQuery f@(Free QArbitraryJoin {}) = buildJoinedQuery f emptyQb
-    buildQuery f@(Free QTwoWayJoin {}) = buildJoinedQuery f emptyQb
-    buildQuery (Free (QSubSelect q' next)) =
-        let sb = buildQuery (fromF q')
+    buildQuery _ (Pure x) = SelectBuilderQ x emptyQb
+    buildQuery tblPfx f@(Free (QGuard _ _)) = buildJoinedQuery tblPfx f emptyQb
+    buildQuery tblPfx f@(Free QAll {}) = buildJoinedQuery tblPfx f emptyQb
+    buildQuery tblPfx f@(Free QArbitraryJoin {}) = buildJoinedQuery tblPfx f emptyQb
+    buildQuery tblPfx f@(Free QTwoWayJoin {}) = buildJoinedQuery tblPfx f emptyQb
+    buildQuery tblPfx (Free (QSubSelect q' next)) =
+        let sb = buildQuery tblPfx (fromF q')
             (proj, qb) = selectBuilderToQueryBuilder tblPfx sb
-        in buildJoinedQuery (next proj) qb
-    buildQuery (Free (QDistinct nubType q' next)) =
+        in buildJoinedQuery tblPfx (next proj) qb
+    buildQuery tblPfx (Free (QDistinct nubType q' next)) =
       let (proj, qb, gp, hv) =
-            case buildQuery (fromF q') of
+            case buildQuery tblPfx (fromF q') of
               SelectBuilderQ proj qb ->
                 ( proj, qb, Nothing, Nothing)
               SelectBuilderGrouping proj qb gp hv Nothing ->
@@ -244,11 +245,11 @@
       in case next proj of
            Pure x -> SelectBuilderGrouping x qb gp hv (Just (exprWithContext tblPfx (nubType proj)))
            _ -> let ( proj', qb' ) = selectBuilderToQueryBuilder tblPfx (SelectBuilderGrouping proj qb gp hv (Just (exprWithContext tblPfx (nubType proj))))
-                in buildJoinedQuery (next proj') qb'
-    buildQuery (Free (QAggregate mkAgg q' next)) =
-        let sb = buildQuery (fromF q')
+                in buildJoinedQuery tblPfx (next proj') qb'
+    buildQuery tblPfx (Free (QAggregate mkAgg q' next)) =
+        let sb = buildQuery tblPfx (fromF q')
             (groupingSyntax, aggProj) = mkAgg (sbProj sb) (nextTblPfx tblPfx)
-        in case tryBuildGuardsOnly (next aggProj) Nothing of
+        in case tryBuildGuardsOnly tblPfx (next aggProj) Nothing of
             Just (proj, having) ->
                 case sb of
                   SelectBuilderQ _ q'' -> SelectBuilderGrouping proj q'' groupingSyntax having Nothing
@@ -256,13 +257,13 @@
                   -- We'll have to generate a subselect
                   _ -> let (subProj, qb) = selectBuilderToQueryBuilder tblPfx sb --(setSelectBuilderProjection sb aggProj)
                            (groupingSyntax, aggProj') = mkAgg subProj (nextTblPfx tblPfx)
-                       in case tryBuildGuardsOnly (next aggProj') Nothing of
+                       in case tryBuildGuardsOnly tblPfx (next aggProj') Nothing of
                             Nothing -> error "buildQuery (Free (QAggregate ...)): Impossible"
                             Just (aggProj'', having') ->
                               SelectBuilderGrouping aggProj'' qb groupingSyntax having' Nothing
             Nothing ->
-              let (_, having) = tryCollectHaving (next aggProj') Nothing
-                  (next', _) = tryCollectHaving (next x') Nothing
+              let (_, having) = tryCollectHaving tblPfx (next aggProj') Nothing
+                  (next', _) = tryCollectHaving tblPfx (next x') Nothing
                   (groupingSyntax', aggProj', qb) =
                     case sb of
                       SelectBuilderQ _ q'' -> (groupingSyntax, aggProj, q'')
@@ -271,10 +272,10 @@
                            in (groupingSyntax', aggProj', qb''')
                   (x', qb') = selectBuilderToQueryBuilder tblPfx $
                               SelectBuilderGrouping aggProj' qb groupingSyntax' having Nothing
-              in buildJoinedQuery next' qb'
+              in buildJoinedQuery tblPfx next' qb'
 
-    buildQuery (Free (QOrderBy mkOrdering q' next)) =
-        let sb = buildQuery (fromF q')
+    buildQuery tblPfx (Free (QOrderBy mkOrdering q' next)) =
+        let sb = buildQuery tblPfx (fromF q')
             proj = sbProj sb
             ordering = exprWithContext tblPfx (mkOrdering proj)
 
@@ -296,7 +297,7 @@
                                 | otherwise -> error "buildQuery (Free (QOrderBy ...)): query inspected expression"
 
                     (joinedProj, qb) = selectBuilderToQueryBuilder tblPfx sb'
-                in buildJoinedQuery (next joinedProj) qb
+                in buildJoinedQuery tblPfx (next joinedProj) qb
         in case next proj of
              Pure proj' ->
                case ordering of
@@ -320,8 +321,13 @@
                            | otherwise -> error "buildQuery (Free (QOrderBy ...)): query inspected expression"
              _ -> doJoined
 
-    buildQuery (Free (QWindowOver mkWindows mkProjection q' next)) =
-        let sb = buildQuery (fromF q')
+    buildQuery tblPfx (Free (QWindowOver mkWindows mkProjection q' next)) =
+        -- If the inner select carries DISTINCT, GROUP BY, or HAVING, those must
+        -- apply to the row set *before* the window function. Emitting them in
+        -- the same SELECT as the window projection inverts that order in SQL,
+        -- yielding wrong results (issue #746). Materialise the inner select as
+        -- a subquery in that case so the window evaluates over its output.
+        let sb = forceSubqueryIfGrouping (buildQuery tblPfx (fromF q'))
 
             x = sbProj sb
             windows = mkWindows x
@@ -334,10 +340,21 @@
                  sb' -> SelectBuilderTopLevel Nothing Nothing [] sb' Nothing
              _       ->
                let (x', qb) = selectBuilderToQueryBuilder tblPfx (setSelectBuilderProjection sb projection)
-               in buildJoinedQuery (next x') qb
+               in buildJoinedQuery tblPfx (next x') qb
+      where
+        forceSubqueryIfGrouping :: Projectible be x' => SelectBuilder be db x' -> SelectBuilder be db x'
+        forceSubqueryIfGrouping sb0
+          | hasGroupingClause sb0 = uncurry SelectBuilderQ $ selectBuilderToQueryBuilder tblPfx sb0
+          | otherwise = sb0
+          where
+            hasGroupingClause :: SelectBuilder be db x' -> Bool
+            hasGroupingClause (SelectBuilderGrouping _ _ grouping having distinct) =
+                isJust grouping || isJust having || isJust distinct
+            hasGroupingClause (SelectBuilderTopLevel _ _ _ inner _) = hasGroupingClause inner
+            hasGroupingClause _ = False
 
-    buildQuery (Free (QLimit limit q' next)) =
-        let sb = limitSelectBuilder limit (buildQuery (fromF q'))
+    buildQuery tblPfx (Free (QLimit limit q' next)) =
+        let sb = limitSelectBuilder limit (buildQuery tblPfx (fromF q'))
             x = sbProj sb
         -- In the case of limit, we must directly return whatever was given
         in case next x of
@@ -345,23 +362,23 @@
 
              -- Otherwise, this is going to be part of a join...
              _ -> let (x', qb) = selectBuilderToQueryBuilder tblPfx sb
-                  in buildJoinedQuery (next x') qb
+                  in buildJoinedQuery tblPfx (next x') qb
 
-    buildQuery (Free (QOffset offset q' next)) =
-        let sb = offsetSelectBuilder offset (buildQuery (fromF q'))
+    buildQuery tblPfx (Free (QOffset offset q' next)) =
+        let sb = offsetSelectBuilder offset (buildQuery tblPfx (fromF q'))
             x = sbProj sb
         -- In the case of limit, we must directly return whatever was given
         in case next x of
              Pure x' -> setSelectBuilderProjection sb x'
              -- Otherwise, this is going to be part of a join...
              _ -> let (x', qb) = selectBuilderToQueryBuilder tblPfx sb
-                  in buildJoinedQuery (next x') qb
+                  in buildJoinedQuery tblPfx (next x') qb
 
-    buildQuery (Free (QSetOp combine left right next)) =
-      buildTableCombination combine left right next
+    buildQuery tblPfx (Free (QSetOp combine left right next)) =
+      buildTableCombination tblPfx combine left right next
 
-    buildQuery (Free (QForceSelect selectStmt' over next)) =
-      let sb = buildQuery (fromF over)
+    buildQuery tblPfx (Free (QForceSelect selectStmt' over next)) =
+      let sb = buildQuery tblPfx (fromF over)
           x = sbProj sb
 
           selectStmt'' = selectStmt' (sbProj sb)
@@ -375,33 +392,36 @@
       in case next (sbProj sb') of
            Pure x' -> setSelectBuilderProjection sb' x'
            _ -> let (x', qb) = selectBuilderToQueryBuilder tblPfx sb'
-                in buildJoinedQuery (next x') qb
+                in buildJoinedQuery tblPfx (next x') qb
 
     tryBuildGuardsOnly :: forall s x
-                        . Free (QF be db s) x
+                        . T.Text
+                       -> Free (QF be db s) x
                        -> Maybe (BeamSqlBackendExpressionSyntax be)
                        -> Maybe (x, Maybe (BeamSqlBackendExpressionSyntax be))
-    tryBuildGuardsOnly next having =
-      case tryCollectHaving next having of
+    tryBuildGuardsOnly tblPfx next having =
+      case tryCollectHaving tblPfx next having of
         (Pure x, having') -> Just (x, having')
         _ -> Nothing
 
-    tryCollectHaving :: forall s x.
-                        Free (QF be db s) x
+    tryCollectHaving :: forall s x
+                      . T.Text
+                     -> Free (QF be db s) x
                      -> Maybe (BeamSqlBackendExpressionSyntax be)
                      -> (Free (QF be db s) x, Maybe (BeamSqlBackendExpressionSyntax be))
-    tryCollectHaving (Free (QGuard cond next)) having = tryCollectHaving next (andE' having (Just (exprWithContext tblPfx cond)))
-    tryCollectHaving next having = (next, having)
+    tryCollectHaving tblPfx (Free (QGuard cond next)) having = tryCollectHaving tblPfx next (andE' having (Just (exprWithContext tblPfx cond)))
+    tryCollectHaving _ next having = (next, having)
 
     buildTableCombination
       :: forall s x r
        . ( Projectible be r, Projectible be x )
-      => (BeamSqlBackendSelectTableSyntax be -> BeamSqlBackendSelectTableSyntax be -> BeamSqlBackendSelectTableSyntax be)
+      => T.Text
+      -> (BeamSqlBackendSelectTableSyntax be -> BeamSqlBackendSelectTableSyntax be -> BeamSqlBackendSelectTableSyntax be)
       -> QM be db (QNested s) x -> QM be db (QNested s) x -> (x -> Free (QF be db s) r) -> SelectBuilder be db r
-    buildTableCombination combineTables left right next =
-        let leftSb = buildQuery (fromF left)
+    buildTableCombination tblPfx combineTables left right next =
+        let leftSb = buildQuery tblPfx (fromF left)
             leftTb = selectBuilderToTableSource tblPfx leftSb
-            rightSb = buildQuery (fromF right)
+            rightSb = buildQuery tblPfx (fromF right)
             rightTb = selectBuilderToTableSource tblPfx rightSb
 
             proj = reproject be (fieldNameFunc unqualifiedField) (sbProj leftSb)
@@ -423,16 +443,16 @@
                | projOrder be proj (nextTblPfx tblPfx) == projOrder be proj' (nextTblPfx tblPfx) ->
                    setSelectBuilderProjection sb proj'
              _ -> let (x', qb) = selectBuilderToQueryBuilder tblPfx sb
-                  in buildJoinedQuery (next x') qb
+                  in buildJoinedQuery tblPfx (next x') qb
 
-    buildJoinedQuery :: forall s x.
-                        Projectible be x =>
-                        Free (QF be db s) x -> QueryBuilder be -> SelectBuilder be db x
-    buildJoinedQuery (Pure x) qb = SelectBuilderQ x qb
-    buildJoinedQuery (Free (QAll mkFrom mkTbl on next)) qb =
+    buildJoinedQuery :: forall s x
+                      . Projectible be x
+                     => T.Text -> Free (QF be db s) x -> QueryBuilder be -> SelectBuilder be db x
+    buildJoinedQuery _ (Pure x) qb = SelectBuilderQ x qb
+    buildJoinedQuery tblPfx (Free (QAll mkFrom mkTbl on next)) qb =
         let (newTblNm, newTbl, qb') = buildInnerJoinQuery tblPfx mkFrom mkTbl on qb
-        in buildJoinedQuery (next (newTblNm, newTbl)) qb'
-    buildJoinedQuery (Free (QArbitraryJoin q mkJoin on next)) qb =
+        in buildJoinedQuery tblPfx (next (newTblNm, newTbl)) qb'
+    buildJoinedQuery tblPfx (Free (QArbitraryJoin q tblNs mkJoin on next)) qb =
       case fromF q of
         Free (QAll mkDbFrom dbMkTbl on' next')
           | (newTbl, newTblNm, qb') <- nextTbl qb tblPfx dbMkTbl,
@@ -444,10 +464,12 @@
                   case qbFrom qb' of
                     Nothing -> (Just newSource, andE' (qbWhere qb) on'')
                     Just oldFrom -> (Just (mkJoin oldFrom newSource on''), qbWhere qb)
-            in buildJoinedQuery (next proj) (qb' { qbFrom = from', qbWhere = where' })
+            in buildJoinedQuery tblPfx (next proj) (qb' { qbFrom = from', qbWhere = where' })
 
-        q' -> let sb = buildQuery q'
-                  tblSource = buildSelect tblPfx sb
+        q' -> let tblPfx' = tblPfx <> tblNs
+
+                  sb = buildQuery tblPfx' q'
+                  tblSource = buildSelect tblPfx' sb
                   newTblNm = tblPfx <> fromString (show (qbNextTblRef qb))
 
                   newSource = fromTable (tableFromSubSelect tblSource) (Just (newTblNm, Nothing))
@@ -460,9 +482,9 @@
                       Nothing -> (Just newSource, andE' (qbWhere qb) on')
                       Just oldFrom -> (Just (mkJoin oldFrom newSource on'), qbWhere qb)
 
-              in buildJoinedQuery (next proj') (qb { qbNextTblRef = qbNextTblRef qb + 1
-                                                   , qbFrom = from', qbWhere = where' })
-    buildJoinedQuery (Free (QTwoWayJoin a b mkJoin on next)) qb =
+              in buildJoinedQuery tblPfx (next proj') (qb { qbNextTblRef = qbNextTblRef qb + 1
+                                                          , qbFrom = from', qbWhere = where' })
+    buildJoinedQuery tblPfx (Free (QTwoWayJoin a b mkJoin on next)) qb =
       let (aProj, aSource, qb') =
             case fromF a of
               Free (QAll mkDbFrom dbMkTbl on' next')
@@ -470,7 +492,7 @@
                   Nothing <- on' newTbl, Pure proj <- next' (newTblNm, newTbl) ->
                     (proj, mkDbFrom (nextTblPfx tblPfx) newTblNm, qb')
 
-              a -> let sb = buildQuery a
+              a -> let sb = buildQuery tblPfx a
                        tblSource = buildSelect tblPfx sb
 
                        newTblNm = tblPfx <> fromString (show (qbNextTblRef qb))
@@ -485,7 +507,7 @@
                   Nothing <- on' newTbl, Pure proj <- next' (newTblNm, newTbl) ->
                     (proj, mkDbFrom (nextTblPfx tblPfx) newTblNm, qb'')
 
-              b -> let sb = buildQuery b
+              b -> let sb = buildQuery tblPfx b
                        tblSource = buildSelect tblPfx sb
 
                        newTblNm = tblPfx <> fromString (show (qbNextTblRef qb))
@@ -500,16 +522,16 @@
               Nothing -> Just abSource
               Just oldFrom -> Just (innerJoin oldFrom abSource Nothing)
 
-      in buildJoinedQuery (next (aProj, bProj)) (qb'' { qbFrom = from' })
-    buildJoinedQuery (Free (QGuard cond next)) qb =
-        buildJoinedQuery next (qb { qbWhere = andE' (qbWhere qb) (Just (exprWithContext tblPfx cond)) })
-    buildJoinedQuery now qb =
+      in buildJoinedQuery tblPfx (next (aProj, bProj)) (qb'' { qbFrom = from' })
+    buildJoinedQuery tblPfx (Free (QGuard cond next)) qb =
+        buildJoinedQuery tblPfx next (qb { qbWhere = andE' (qbWhere qb) (Just (exprWithContext tblPfx cond)) })
+    buildJoinedQuery tblPfx now qb =
       onlyQ now
         (\now' next ->
-           let sb = buildQuery now'
+           let sb = buildQuery tblPfx now'
                tblSource = buildSelect tblPfx sb
                (x', qb') = buildJoinTableSourceQuery tblPfx tblSource (sbProj sb) qb
-           in buildJoinedQuery (next x') qb')
+           in buildJoinedQuery tblPfx (next x') qb')
 
     onlyQ :: forall s x.
              Free (QF be db s) x
@@ -518,8 +540,8 @@
     onlyQ (Free (QAll entityNm mkTbl mkOn next)) f =
       f (Free (QAll entityNm mkTbl mkOn (Pure . PreserveLeft))) (next . unPreserveLeft)
 --      f (Free (QAll entityNm mkTbl mkOn (Pure . PreserveLeft))) (next . unPreserveLeft)
-    onlyQ (Free (QArbitraryJoin entity mkJoin mkOn next)) f =
-      f (Free (QArbitraryJoin entity mkJoin mkOn Pure)) next
+    onlyQ (Free (QArbitraryJoin entity tblNs mkJoin mkOn next)) f =
+      f (Free (QArbitraryJoin entity tblNs mkJoin mkOn Pure)) next
     onlyQ (Free (QTwoWayJoin a b mkJoin mkOn next)) f =
       f (Free (QTwoWayJoin a b mkJoin mkOn Pure)) next
     onlyQ (Free (QSubSelect q' next)) f =
diff --git a/Database/Beam/Schema/Lenses.hs b/Database/Beam/Schema/Lenses.hs
--- a/Database/Beam/Schema/Lenses.hs
+++ b/Database/Beam/Schema/Lenses.hs
@@ -4,12 +4,18 @@
     ( tableLenses
     , TableLens(..)
 
-    , dbLenses ) where
+    , dbLenses
 
+    -- * Exported so we can override defaults
+    , GTableLenses(..)
+    , GDatabaseLenses(..)
+    ) where
+
 import Database.Beam.Schema.Tables
 
 import Control.Monad.Identity
 
+import Data.Function
 import Data.Kind (Type)
 import Data.Proxy
 
diff --git a/Database/Beam/Schema/Tables.hs b/Database/Beam/Schema/Tables.hs
--- a/Database/Beam/Schema/Tables.hs
+++ b/Database/Beam/Schema/Tables.hs
@@ -19,13 +19,14 @@
     , DatabaseEntityDescriptor(..)
     , DatabaseEntity(..), TableEntity, ViewEntity, DomainTypeEntity
     , dbEntityDescriptor
+    , dbName, dbSchema, dbTableFields
     , DatabaseModification, EntityModification(..)
     , FieldModification(..)
     , dbModification, tableModification, withDbModification
     , withTableModification, modifyTable, modifyEntityName
     , setEntityName, modifyTableFields, fieldNamed
     , modifyEntitySchema, setEntitySchema
-    , defaultDbSettings
+    , defaultDbSettings, embedDatabase
 
     , RenamableWithRule(..), RenamableField(..)
     , FieldRenamer(..)
@@ -57,7 +58,20 @@
     , pk
     , allBeamValues, changeBeamRep
     , alongsideTable
-    , defaultFieldName )
+    , defaultFieldName
+
+    -- * Exported so we can override defaults
+    -- ** For 'Beamable'
+    , GZipTables(..)
+    , GTableSkeleton(..)
+    -- ** For 'Database'
+    , GZipDatabase(..)
+    -- ** For 'defaultDbSettings'
+    , GAutoDbSettings(..)
+    , GDefaultTableFieldSettings(..)
+    , ChooseSubTableStrategy
+    , SubTableStrategyImpl
+    )
     where
 
 import           Database.Beam.Backend.Types
@@ -65,11 +79,13 @@
 import           Control.Applicative (liftA2)
 import           Control.Arrow (first)
 import           Control.Monad.Identity
-import           Control.Monad.Writer hiding ((<>))
+import           Control.Monad.Writer (Writer, execWriter, tell)
 
 import           Data.Char (isUpper, toLower)
 import           Data.Foldable (fold)
+import           Data.Kind (Type, Constraint)
 import qualified Data.List.NonEmpty as NE
+import           Data.Monoid
 import           Data.Proxy
 import           Data.String (IsString(..))
 import           Data.Text (Text)
@@ -79,10 +95,8 @@
 import qualified GHC.Generics as Generic
 import           GHC.Generics hiding (R, C)
 import           GHC.TypeLits
-import           GHC.Types
 
 import           Lens.Micro hiding (to)
-import qualified Lens.Micro as Lens
 
 -- | Allows introspection into database types.
 --
@@ -186,7 +200,9 @@
 -- > db = defaultDbSettings `withDbModification`
 -- >      dbModification {
 -- >        -- Change default name "table1" to "Table_1". Change the name of "table1Field1" to "first_name"
--- >        table1 = modifyTable (\_ -> "Table_1") (tableModification { table1Field1 = "first_name" }
+-- >        table1 = setEntityName "Table_1" <> modifyTableFields tableModification { 
+-- >            table1Field1 = "first_name" 
+-- >         }
 -- >      }
 withDbModification :: forall db be entity
                     . Database be db
@@ -204,7 +220,6 @@
   runIdentity $ zipBeamFieldsM (\(Columnar' field :: Columnar' f a) (Columnar' (FieldModification fieldFn :: FieldModification f a)) ->
                                   pure (Columnar' (fieldFn field))) tbl mods
 
-
 -- | Provide an 'EntityModification' for 'TableEntity's. Allows you to modify
 --   the name of the table and provide a modification for each field in the
 --   table. See the examples for 'withDbModification' for more.
@@ -230,6 +245,14 @@
 setEntitySchema :: IsDatabaseEntity be entity => Maybe Text -> EntityModification (DatabaseEntity be db) be entity
 setEntitySchema nm = modifyEntitySchema (\_ -> nm)
 
+-- | Embed database settings in a larger database
+embedDatabase :: forall be embedded db. Database be embedded => DatabaseSettings be embedded -> embedded (EntityModification (DatabaseEntity be db) be)
+embedDatabase db =
+    runIdentity $
+    zipTables (Proxy @be)
+              (\(DatabaseEntity x) _ -> pure (EntityModification (Endo (\_ -> DatabaseEntity x))))
+              db db
+
 -- | Construct an 'EntityModification' to rename the fields of a 'TableEntity'
 modifyTableFields :: tbl (FieldModification (TableField tbl)) -> EntityModification (DatabaseEntity be db) be (TableEntity tbl)
 modifyTableFields modFields = EntityModification (Endo (\(DatabaseEntity tbl@(DatabaseTable {})) -> DatabaseEntity tbl { dbTableSettings = withTableModification modFields (dbTableSettings tbl) }))
@@ -375,9 +398,22 @@
       IsDatabaseEntity be entityType =>
       DatabaseEntityDescriptor be entityType ->  DatabaseEntity be db entityType
 
-dbEntityDescriptor :: SimpleGetter (DatabaseEntity be db entityType) (DatabaseEntityDescriptor be entityType)
-dbEntityDescriptor = Lens.to (\(DatabaseEntity e) -> e)
+dbEntityDescriptor :: Lens' (DatabaseEntity be db entityType) (DatabaseEntityDescriptor be entityType)
+dbEntityDescriptor f (DatabaseEntity d) = DatabaseEntity <$> f d
 
+dbName :: IsDatabaseEntity be entityType => Lens' (DatabaseEntity be db entityType) Text
+dbName = dbEntityDescriptor . dbEntityName
+
+dbSchema :: IsDatabaseEntity be entityType => Traversal' (DatabaseEntity be db entityType) (Maybe Text)
+dbSchema = dbEntityDescriptor . dbEntitySchema
+
+dbTableFields :: Lens' (DatabaseEntity be db (TableEntity table)) (TableSettings table)
+dbTableFields = dbEntityDescriptor . (\f DatabaseTable { dbTableSchema = sch
+                                                       , dbTableOrigName = nm
+                                                       , dbTableCurrentName = curNm
+                                                       , dbTableSettings = s } ->
+                                      DatabaseTable sch nm curNm <$> f s)
+
 -- | When parameterized by this entity tag, a database type will hold
 --   meta-information on the Haskell mappings of database entities. Under the
 --   hood, each entity type is transformed into its 'DatabaseEntityDescriptor'
@@ -397,6 +433,16 @@
   GAutoDbSettings (S1 f (K1 Generic.R (DatabaseEntity be db x)) p) where
   autoDbSettings' = M1 (K1 (DatabaseEntity (dbEntityAuto name)))
     where name = T.pack (selName (undefined :: S1 f (K1 Generic.R (DatabaseEntity be db x)) p))
+instance ( Database be embedded
+         , Generic (DatabaseSettings be embedded)
+         , GAutoDbSettings (Rep (DatabaseSettings be embedded) ()) ) =>
+    GAutoDbSettings (S1 f (K1 Generic.R (embedded (DatabaseEntity be super))) p) where
+  autoDbSettings' =
+    M1 . K1 . runIdentity $
+    zipTables (Proxy @be)
+              (\(DatabaseEntity x) _ -> pure (DatabaseEntity x))
+              db db
+    where db = defaultDbSettings @be
 
 class GZipDatabase be f g h x y z where
   gZipDatabase :: Applicative m =>
@@ -416,7 +462,12 @@
 
   gZipDatabase _ combine ~(K1 x) ~(K1 y) =
     K1 <$> combine x y
+instance Database be db =>
+    GZipDatabase be f g h (K1 Generic.R (db f)) (K1 Generic.R (db g)) (K1 Generic.R (db h)) where
 
+  gZipDatabase _ combine ~(K1 x) ~(K1 y) =
+      K1 <$> zipTables (Proxy @be) combine x y
+
 data Lenses (t :: (Type -> Type) -> Type) (f :: Type -> Type) x
 data LensFor t x where
     LensFor :: Generic t => Lens' t x -> LensFor t x
@@ -447,7 +498,7 @@
 -- >                   { _refToAnotherTable :: PrimaryKey AnotherTableT (Nullable f)
 -- >                   , ... }
 --
---   Now we can use 'justRef' and 'nothingRef' to refer to this table optionally. The embedded 'PrimaryKey' in '_refToAnotherTable'
+--   Now we can use 'just_' and 'nothing_' to refer to this table optionally. The embedded 'PrimaryKey' in '_refToAnotherTable'
 --   automatically has its fields converted into 'Maybe' using 'Nullable'.
 --
 --   The last 'Columnar' rule is
diff --git a/beam-core.cabal b/beam-core.cabal
--- a/beam-core.cabal
+++ b/beam-core.cabal
@@ -1,8 +1,5 @@
--- Initial beam.cabal generated by cabal init.  For further documentation,
--- see http://haskell.org/cabal/users-guide/
-
 name:                beam-core
-version:             0.9.2.1
+version:             0.11.1.0
 synopsis:            Type-safe, feature-complete SQL query and manipulation interface for Haskell
 description:         Beam is a Haskell library for type-safe querying and manipulation of SQL databases.
                      Beam is modular and supports various backends. In order to use beam, you will need to use
@@ -50,7 +47,10 @@
 
                        Database.Beam.Backend.Internal.Compat
 
-  other-modules:       Database.Beam.Query.Aggregate
+  other-modules:       Database.Beam.Backend.SQL.BeamExtensions.Copy.File
+                       Database.Beam.Backend.SQL.BeamExtensions.Copy.Stream
+
+                       Database.Beam.Query.Aggregate
                        Database.Beam.Query.Combinators
                        Database.Beam.Query.Extensions
                        Database.Beam.Query.Extract
@@ -61,21 +61,20 @@
                        Database.Beam.Schema.Lenses
 
   build-depends:       base         >=4.11    && <5.0,
-                       aeson        >=0.11    && <2.1,
-                       text         >=1.2.2.0 && <1.3,
-                       bytestring   >=0.10    && <0.12,
-                       mtl          >=2.2.1   && <2.3,
-                       microlens    >=0.4     && <0.5,
-                       ghc-prim     >=0.5     && <0.9,
-                       free         >=4.12    && <5.2,
+                       aeson        >=0.11    && <2.3,
+                       text         >=1.2.2.0 && <2.2,
+                       bytestring   >=0.10    && <0.13,
+                       mtl          >=2.2.1   && <2.4,
+                       microlens    >=0.4     && <0.6,
+                       free         >=4.12    && <5.3,
                        dlist        >=0.7.1.2 && <1.1,
-                       time         >=1.6     && <1.12,
-                       hashable     >=1.2.4.0 && <1.5,
+                       time         >=1.6     && <1.17,
+                       hashable     >=1.2.4.0 && <1.6,
                        network-uri  >=2.6     && <2.7,
-                       containers   >=0.5     && <0.7,
+                       containers   >=0.5     && <0.9,
                        scientific   >=0.3     && <0.4,
-                       vector       >=0.11    && <0.13,
-                       vector-sized >=0.5     && <1.6,
+                       vector       >=0.11    && <0.14,
+                       vector-sized >=0.5     && <1.7,
                        tagged       >=0.8     && <0.9
 
   Default-language:    Haskell2010
@@ -83,9 +82,14 @@
                        GeneralizedNewtypeDeriving, RankNTypes, TupleSections, ConstraintKinds, StandaloneDeriving, TypeOperators,
                        DefaultSignatures, KindSignatures, MultiParamTypeClasses, DeriveGeneric, DeriveFunctor, DeriveDataTypeable,
                        TypeApplications, FunctionalDependencies, DataKinds, BangPatterns, InstanceSigs
-  ghc-options:         -Wall -O3
+  ghc-options:         -Wall
+                       -Widentities
+                       -Wincomplete-uni-patterns
+                       -Wincomplete-record-updates
   if impl(ghc >= 8.8)
     ghc-options: -Wcompat
+  if impl(ghc >= 8.10)
+    ghc-options: -Wunused-packages
   if flag(werror)
     ghc-options:       -Werror
   if impl(ghc >= 8.10)
@@ -101,7 +105,7 @@
   hs-source-dirs: test
   main-is: Main.hs
   other-modules: Database.Beam.Test.Schema Database.Beam.Test.SQL
-  build-depends: base, beam-core, text, bytestring, time, tasty, tasty-hunit
+  build-depends: base, beam-core, text, bytestring, time, tasty, tasty-hunit, microlens
   default-language: Haskell2010
   default-extensions: OverloadedStrings, FlexibleInstances, FlexibleContexts, GADTs, TypeFamilies,
                       DeriveGeneric, DefaultSignatures, RankNTypes, StandaloneDeriving, KindSignatures,
diff --git a/test/Database/Beam/Test/SQL.hs b/test/Database/Beam/Test/SQL.hs
--- a/test/Database/Beam/Test/SQL.hs
+++ b/test/Database/Beam/Test/SQL.hs
@@ -12,7 +12,7 @@
 import Database.Beam
 import Database.Beam.Backend.SQL (MockSqlBackend)
 import Database.Beam.Backend.SQL.AST
-
+import Data.Kind (Type)
 import Data.Int
 import Data.Time.Clock
 import Data.Text (Text)
@@ -24,12 +24,14 @@
 tests = testGroup "SQL generation tests"
                   [ simpleSelect
                   , simpleWhere
+                  , simpleWhereNoFrom
                   , simpleJoin
                   , selfJoin
                   , leftJoin
                   , leftJoinSingle
                   , aggregates
                   , orderBy
+                  , innerNub
 
                   , joinHaving
 
@@ -118,6 +120,32 @@
 
      selectWhere @?= Just (ExpressionBinOp "AND" salaryCond (ExpressionBinOp "AND" ageCond nameCond))
 
+-- | Simple select without FROM clause (#667)
+
+data EmptyDb (f :: Type -> Type) = EmptyDb
+
+simpleWhereNoFrom :: TestTree
+simpleWhereNoFrom =
+  testCase "WHERE clause not dropped if there is no FROM" $ do
+    SqlSelect Select { selectTable = SelectTable { .. }, .. } <- pure $ selectMock simple
+
+    selectGrouping @?= Nothing
+    selectOrdering @?= []
+    selectLimit @?= Nothing
+    selectOffset @?= Nothing
+    selectHaving @?= Nothing
+    selectQuantifier @?= Nothing
+    -- Important point: no FROM clause, yet WHERE clause should still be here
+    selectFrom @?= Nothing
+    selectWhere @?= (Just (ExpressionValue (Value False)))
+
+  where
+    simple :: Q (MockSqlBackend Command) EmptyDb s (QExpr (MockSqlBackend Command) s Bool)
+    simple = do
+      guard_ (val_ False)
+      pure (val_ True)
+
+
 -- | Ensure that multiple tables are correctly joined
 
 simpleJoin :: TestTree
@@ -743,6 +771,61 @@
                                           (FromTable (TableFromSubSelect subselect) (Just ("t1", Nothing)))
                                           Nothing)
 
+
+-- | Ensure that a SQL DISTINCT in a subquery does not propagate up (see issue #746)
+innerNub :: TestTree
+innerNub =
+  testCase "DISTINCT clause on inner SELECT" $ do
+    stmt@(SqlSelect Select{selectTable = SelectTable{..}, ..}) <- pure $ selectMock query
+
+    selectGrouping @?= Nothing
+    selectOrdering @?= []
+    selectLimit @?= Nothing
+    selectOffset @?= Nothing
+    selectHaving @?= Nothing
+    selectQuantifier @?= Nothing -- quantifier should be in the subquery
+    selectFrom
+      @?= Just
+        ( FromTable
+            ( TableFromSubSelect
+                ( Select
+                    { selectTable =
+                        SelectTable
+                          { selectQuantifier = Just SetQuantifierDistinct
+                          , selectProjection = ProjExprs [(ExpressionFieldName (QualifiedField "t0" "first_name"), Just "res0")]
+                          , selectFrom = Just (FromTable (TableNamed (TableName Nothing "employees")) (Just ("t0", Nothing)))
+                          , selectWhere = Nothing
+                          , selectGrouping = Nothing
+                          , selectHaving = Nothing
+                          }
+                    , selectOrdering = []
+                    , selectLimit = Nothing
+                    , selectOffset = Nothing
+                    }
+                )
+            )
+            (Just ("t0", Nothing))
+        )
+    selectWhere
+      @?= Just
+        ( ExpressionCompOp
+            "=="
+            Nothing
+            (ExpressionFieldName (QualifiedField "t0" "res0"))
+            (ExpressionValue (Value @Text "Alice"))
+        )
+ where
+  query :: Q (MockSqlBackend Command) EmployeeDb s (QExpr (MockSqlBackend Command) s Text)
+  query = do
+    name <- subQuery
+    guard_ (name ==. val_ "Alice")
+    pure name
+
+  -- This sub query contains a DISTINCT clause via `nub_`
+  subQuery :: Q (MockSqlBackend Command) EmployeeDb s (QExpr (MockSqlBackend Command) s Text)
+  subQuery = nub_ $ _employeeFirstName <$> (all_ (_employees employeeDbSettings))
+
+
 -- | HAVING clause should not be floated out of a join
 
 joinHaving :: TestTree
@@ -1032,7 +1115,9 @@
 limitOffset :: TestTree
 limitOffset =
   testGroup "LIMIT/OFFSET support"
-  [ limitSupport, offsetSupport, limitOffsetSupport
+  [ limitSupport, maybeLimitSupportJust, maybeLimitSupportNothing
+  , offsetSupport, maybeOffsetSupportJust, maybeOffsetSupportNothing
+  , limitOffsetSupport
 
   , limitPlacedOnUnion ]
   where
@@ -1044,6 +1129,22 @@
          selectLimit @?= Just 20
          selectOffset @?= Nothing
 
+    maybeLimitSupportJust =
+      testCase "Maybe LIMIT support (Just)" $
+      do SqlSelect Select { selectLimit, selectOffset } <-
+           pure $ selectMock $ limitMaybe_ (Just 20) (all_ (_employees employeeDbSettings))
+
+         selectLimit @?= Just 20
+         selectOffset @?= Nothing
+
+    maybeLimitSupportNothing =
+      testCase "Maybe LIMIT support (Nothing)" $
+      do SqlSelect Select { selectLimit, selectOffset } <-
+           pure $ selectMock $ limitMaybe_ Nothing (all_ (_employees employeeDbSettings))
+
+         selectLimit @?= Nothing
+         selectOffset @?= Nothing
+
     offsetSupport =
       testCase "Basic OFFSET support" $
       do SqlSelect Select { selectLimit, selectOffset } <-
@@ -1051,6 +1152,22 @@
 
          selectLimit @?= Nothing
          selectOffset @?= Just 102
+
+    maybeOffsetSupportJust =
+      testCase "Maybe OFFSET support (Just)" $
+      do SqlSelect Select { selectLimit, selectOffset } <-
+           pure $ selectMock $ offsetMaybe_ (Just 2) $ offset_ 100 (all_ (_employees employeeDbSettings))
+
+         selectLimit @?= Nothing
+         selectOffset @?= Just 102
+
+    maybeOffsetSupportNothing =
+      testCase "Maybe OFFSET support (Nothing)" $
+      do SqlSelect Select { selectLimit, selectOffset } <-
+           pure $ selectMock $ offsetMaybe_ Nothing $ offset_ 100 (all_ (_employees employeeDbSettings))
+
+         selectLimit @?= Nothing
+         selectOffset @?= Just 100
 
     limitOffsetSupport =
       testCase "Basic LIMIT .. OFFSET .. support" $
diff --git a/test/Database/Beam/Test/Schema.hs b/test/Database/Beam/Test/Schema.hs
--- a/test/Database/Beam/Test/Schema.hs
+++ b/test/Database/Beam/Test/Schema.hs
@@ -23,6 +23,8 @@
 import qualified Data.Text as T
 import           Data.Time.Clock (UTCTime)
 
+import           Lens.Micro.Extras (view)
+
 import           Test.Tasty
 import           Test.Tasty.HUnit
 
@@ -34,9 +36,8 @@
                   , parametricAndFixedNestedBeamsAreEquivalent
 --                  , automaticNestedFieldsAreUnset
 --                  , nullableForeignKeysGivenMaybeType
-                  , underscoresAreHandledGracefully ]
---                  , dbSchemaGeneration ]
---                  , dbSchemaModification ]
+                  , underscoresAreHandledGracefully
+                  , embeddedDatabases ]
 
 data DummyBackend
 
@@ -315,34 +316,38 @@
                                                   Nothing -> defName
                                                   Just _ -> "pfx_" <> defName)
 
--- employeeDbSettingsModified :: DatabaseSettings EmployeeDb
--- employeeDbSettingsModified =
---   defaultDbSettings `withDbModifications`
---   (modifyingDb { _employees = tableModification (\_ -> "emps") tableFieldsModification
---                , _departments = tableModification (\_ -> "depts")
---                                                   (tableFieldsModification
---                                                     { _departmentName = fieldModification (\_ -> "depts_name") id }) })
+data VehicleDb f
+    = VehicleDb
+    { _vdbVehiculesA :: f (TableEntity ADepartmentVehiculeT)
+    , _vdbVehiculesB :: f (TableEntity BDepartmentVehiculeT)
+    } deriving Generic
+instance Database be VehicleDb
 
--- dbSchemaGeneration :: TestTree
--- dbSchemaGeneration =
---   testCase "Database schema generation" $
---   do let names = allTables (\(DatabaseTable _ nm _) -> nm) employeeDbSettings
---      names @?= [ "employees"
---                , "departments"
---                , "roles"
---                , "funny" ]
+data SuperDb f
+    = SuperDb
+    { _embedEmployeeDb :: EmployeeDb f
+    , _embedVehicleDb  :: VehicleDb f
+    } deriving Generic
+instance Database be SuperDb
 
--- dbSchemaModification :: TestTree
--- dbSchemaModification =
---   testCase "Database schema modification" $
---   do let names = allTables (\(DatabaseTable _ nm _ ) -> nm) employeeDbSettingsModified
---      names @?= [ "emps"
---                , "depts"
---                , "roles"
---                , "funny" ]
+superDbSettingsDefault :: DatabaseSettings be SuperDb
+superDbSettingsDefault = defaultDbSettings
 
---      let DatabaseTable _ _ departmentT = _departments employeeDbSettingsModified
---      departmentT @?= DepartmentT (TableField "depts_name" (DummyField False False DummyFieldText))
---                                  (EmployeeId (TableField "head__first_name" (DummyField True False (DummyFieldMaybe DummyFieldText)))
---                                              (TableField "head__last_name" (DummyField True False (DummyFieldMaybe DummyFieldText)))
---                                              (TableField "head__created" (DummyField True False (DummyFieldMaybe DummyFieldUTCTime))))
+superDbSettingsCustom :: DatabaseSettings be SuperDb
+superDbSettingsCustom = defaultDbSettings `withDbModification` dbModification { _embedVehicleDb = embedDatabase customVehicleDb }
+
+customVehicleDb :: DatabaseSettings be VehicleDb
+customVehicleDb = defaultDbSettings `withDbModification` dbModification
+                  { _vdbVehiculesA = setEntityName "something_random" }
+
+
+embeddedDatabases :: TestTree
+embeddedDatabases =
+    testGroup "Embedded databases"
+      [ testCase "Databases can be embedded" $ do
+          view (dbEntityDescriptor . dbEntityName) (_vdbVehiculesA (_embedVehicleDb superDbSettingsDefault)) @?= "vehicules_a"
+          view (dbEntityDescriptor . dbEntityName) (_vdbVehiculesB (_embedVehicleDb superDbSettingsDefault)) @?= "vehicules_b"
+      , testCase "Databases can be customized when embedded" $ do
+          view (dbEntityDescriptor . dbEntityName) (_vdbVehiculesA (_embedVehicleDb superDbSettingsCustom)) @?= "something_random"
+      ]
+
