diff --git a/Database/Groundhog/Generic/Sql/Utf8.hs b/Database/Groundhog/Generic/Sql/Utf8.hs
new file mode 100644
--- /dev/null
+++ b/Database/Groundhog/Generic/Sql/Utf8.hs
@@ -0,0 +1,47 @@
+module Database.Groundhog.Generic.Sql.Utf8
+    ( module Database.Groundhog.Generic.Sql
+    , Utf8 (..)
+    , fromUtf8
+    ) where
+
+import Database.Groundhog.Core
+import Database.Groundhog.Generic.Sql
+import Blaze.ByteString.Builder
+import qualified Blaze.ByteString.Builder.Char.Utf8 as B
+import Data.ByteString
+import Data.Monoid
+import Data.String
+
+newtype Utf8 = Utf8 Builder
+
+fromUtf8 :: Utf8 -> ByteString
+fromUtf8 (Utf8 a) = toByteString a
+
+instance Monoid Utf8 where
+  mempty = Utf8 mempty
+  mappend (Utf8 a) (Utf8 b) = Utf8 (mappend a b)
+
+instance IsString Utf8 where
+  fromString = Utf8 . B.fromString
+
+instance StringLike Utf8 where
+  fromChar = Utf8 . B.fromChar
+
+{-# SPECIALIZE (<>) :: RenderS Utf8 -> RenderS Utf8 -> RenderS Utf8 #-}
+
+{-# SPECIALIZE renderArith :: (PersistEntity v, Constructor c, DbDescriptor db) => Proxy db -> (Utf8 -> Utf8) -> Arith v c a -> RenderS Utf8 #-}
+
+{-# SPECIALIZE renderCond :: (PersistEntity v, Constructor c, DbDescriptor db)
+  => Proxy db
+  -> (Utf8 -> Utf8)
+  -> (Utf8 -> Utf8 -> Utf8)
+  -> (Utf8 -> Utf8 -> Utf8)
+  -> Cond v c -> Maybe (RenderS Utf8) #-}
+
+{-# SPECIALIZE renderOrders :: (PersistEntity v, Constructor c) => (Utf8 -> Utf8) -> [Order v c] -> Utf8 #-}
+
+{-# SPECIALIZE renderUpdates :: (PersistEntity v, Constructor c, DbDescriptor db) => Proxy db -> (Utf8 -> Utf8) -> [Update v c] -> Maybe (RenderS Utf8) #-}
+
+{-# SPECIALIZE renderFields :: (Utf8 -> Utf8) -> [(String, DbType)] -> Utf8 #-}
+
+{-# SPECIALIZE renderChain :: (Utf8 -> Utf8) -> FieldChain -> [Utf8] -> [Utf8] #-}
diff --git a/Database/Groundhog/Sqlite.hs b/Database/Groundhog/Sqlite.hs
--- a/Database/Groundhog/Sqlite.hs
+++ b/Database/Groundhog/Sqlite.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ScopedTypeVariables, FlexibleInstances #-}
+{-# LANGUAGE ScopedTypeVariables, FlexibleInstances, FlexibleContexts, OverloadedStrings, TypeFamilies, RecordWildCards, Rank2Types #-}
 module Database.Groundhog.Sqlite
     ( withSqlitePool
     , withSqliteConn
@@ -11,77 +11,88 @@
 import Database.Groundhog
 import Database.Groundhog.Core
 import Database.Groundhog.Generic
-import Database.Groundhog.Generic.Sql
+import Database.Groundhog.Generic.Migration hiding (MigrationPack(..))
+import qualified Database.Groundhog.Generic.Migration as GM
+import Database.Groundhog.Generic.Sql.Utf8
+import qualified Database.Groundhog.Generic.PersistBackendHelpers as H
 
 import qualified Database.Sqlite as S
 
-import Control.Exception.Control (bracket, onException, finally)
-import Control.Monad(liftM, forM, (>=>))
-import Control.Monad.IO.Control (MonadControlIO)
+import Control.Arrow ((***))
+import Control.Monad (liftM, forM)
+import Control.Monad.Trans.Control (MonadBaseControl)
 import Control.Monad.IO.Class (MonadIO(..))
-import Control.Monad.Trans.Class(MonadTrans(..))
-import Control.Monad.Trans.Reader(ask)
-import Data.Enumerator(Enumerator, Iteratee(..), Stream(..), checkContinue0, (>>==), joinE, runIteratee, continue, concatEnums)
-import qualified Data.Enumerator.List as EL
+import Control.Monad.Trans.Reader (ask)
+import qualified Data.ByteString as BS
+import Data.Char (toUpper)
+import Data.Function (on)
 import Data.Int (Int64)
-import Data.List (intercalate)
+import Data.List (groupBy, intercalate, isInfixOf, sort)
 import Data.IORef
-import qualified Data.Map as Map
-import Data.Pool
+import qualified Data.HashMap.Strict as Map
+import Data.Maybe (maybeToList)
+import Data.Conduit.Pool
 
+import GHC.Exts (inline)
+
 -- typical operations for connection: OPEN, BEGIN, COMMIT, ROLLBACK, CLOSE
-data Sqlite = Sqlite S.Database (IORef (Map.Map String S.Statement))
+data Sqlite = Sqlite S.Database (IORef (Map.HashMap BS.ByteString S.Statement))
 
-instance MonadControlIO m => PersistBackend (DbPersist Sqlite m) where
+instance DbDescriptor Sqlite where
+  type AutoKeyType Sqlite = Int64
+
+instance (MonadBaseControl IO m, MonadIO m) => PersistBackend (DbPersist Sqlite m) where
   {-# SPECIALIZE instance PersistBackend (DbPersist Sqlite IO) #-}
+  type PhantomDb (DbPersist Sqlite m) = Sqlite
   insert v = insert' v
-  insertBy v = insertBy' v
-  replace k v = replace' k v
-  selectEnum cond ords limit offset = selectEnum' cond ords limit offset
-  selectAllEnum = selectAllEnum'
-  select cond ords limit offset = select' cond ords limit offset
-  selectAll = selectAll'
-  get k = get' k
-  update upds cond = update' upds cond
-  delete cond = delete' cond
-  deleteByKey k = deleteByKey' k
-  count cond = count' cond
-  countAll fakeV = countAll' fakeV
+  insertBy u v = H.insertBy escapeS queryRawTyped u v
+  insertByAll v = H.insertByAll escapeS queryRawTyped v
+  replace k v = H.replace escapeS queryRawTyped executeRawCached' insertIntoConstructorTable k v
+  select options = H.select escapeS queryRawTyped "LIMIT -1" renderCond' options -- select' options
+  selectAll = H.selectAll escapeS queryRawTyped
+  get k = inline $ H.get escapeS queryRawTyped k
+  getBy k = H.getBy escapeS queryRawTyped k
+  update upds cond = H.update escapeS executeRawCached' renderCond' upds cond
+  delete cond = H.delete escapeS executeRawCached' renderCond' cond
+  deleteByKey k = H.deleteByKey escapeS executeRawCached' k
+  count cond = H.count escapeS queryRawTyped renderCond' cond
+  countAll fakeV = H.countAll escapeS queryRawTyped fakeV
+  project p options = H.project escapeS queryRawTyped "LIMIT -1" renderCond' p options
   migrate fakeV = migrate' fakeV
 
-  executeRaw False query ps = executeRaw' query ps
-  executeRaw True query ps = executeRawCached' query ps
-  queryRaw False query ps f = queryRaw' query ps f
-  queryRaw True query ps f = queryRawCached' query ps f
+  executeRaw False query ps = executeRaw' (fromString query) ps
+  executeRaw True query ps = executeRawCached' (fromString query) ps
+  queryRaw False query ps f = queryRaw' (fromString query) ps f
+  queryRaw True query ps f = queryRawCached' (fromString query) ps f
 
   insertList l = insertList' l
   getList k = getList' k
-  insertTuple t ts = insertTuple' t ts
-  getTuple t k = getTuple' t k
 
+--{-# SPECIALIZE INLINE H.get :: (MonadBaseControl IO m, MonadIO m, PersistEntity v, PrimitivePersistField (Key v BackendSpecific)) => (Utf8 -> Utf8) -> (forall a . Utf8 -> [DbType] -> [PersistValue] -> (RowPopper (DbPersist Sqlite m) -> DbPersist Sqlite m a) -> DbPersist Sqlite m a) -> Key v BackendSpecific -> DbPersist Sqlite m (Maybe v) #-}
+
 --{-# SPECIALIZE withSqlitePool :: String -> Int -> (Pool Sqlite -> IO a) -> IO a #-}
-withSqlitePool :: MonadControlIO m
+withSqlitePool :: (MonadBaseControl IO m, MonadIO m)
                => String
                -> Int -- ^ number of connections to open
                -> (Pool Sqlite -> m a)
                -> m a
-withSqlitePool s = createPool (open' s) close'
+withSqlitePool s connCount f = liftIO (createPool (open' s) close' 1 20 connCount) >>= f
 
 {-# SPECIALIZE withSqliteConn :: String -> (Sqlite -> IO a) -> IO a #-}
 {-# INLINE withSqliteConn #-}
-withSqliteConn :: MonadControlIO m
+withSqliteConn :: (MonadBaseControl IO m, MonadIO m)
                => String
                -> (Sqlite -> m a)
                -> m a
-withSqliteConn s = bracket (liftIO $ open' s) (liftIO.close')
+withSqliteConn s = bracket (liftIO $ open' s) (liftIO . close')
 
 {-# SPECIALIZE runSqlitePool :: DbPersist Sqlite IO a -> Pool Sqlite -> IO a #-}
-runSqlitePool :: MonadControlIO m => DbPersist Sqlite m a -> Pool Sqlite -> m a
-runSqlitePool = flip withPool' . runSqliteConn
+runSqlitePool :: (MonadBaseControl IO m, MonadIO m) => DbPersist Sqlite m a -> Pool Sqlite -> m a
+runSqlitePool f pconn = withResource pconn $ runSqliteConn f
 
 {-# SPECIALIZE runSqliteConn :: DbPersist Sqlite IO a -> Sqlite -> IO a #-}
 {-# INLINE runSqliteConn #-}
-runSqliteConn :: MonadControlIO m => DbPersist Sqlite m a -> Sqlite -> m a
+runSqliteConn :: (MonadBaseControl IO m, MonadIO m) => DbPersist Sqlite m a -> Sqlite -> m a
 runSqliteConn f conn@(Sqlite c _) = do
   let runStmt query = S.prepare c query >>= \stmt -> S.step stmt >> S.finalize stmt
   liftIO $ runStmt "BEGIN"
@@ -92,6 +103,7 @@
 open' :: String -> IO Sqlite
 open' s = do
   conn <- S.open s
+  S.prepare conn "PRAGMA foreign_keys = ON" >>= \stmt -> S.step stmt >> S.finalize stmt
   cache <- newIORef Map.empty
   return $ Sqlite conn cache
 
@@ -100,181 +112,63 @@
   readIORef smap >>= mapM_ S.finalize . Map.elems
   S.close conn
 
-{- ********************RULES******************** --
-For type with a single constructor, a single table is created.
-TABLE Entity(id, [fields])
-If constructor has no fields, then ????
-
-For type with a multiple constructors, the main table is created.
-TABLE(id, discriminator)
-where discriminator is defined by constructor.
-Each constructor has its table, where id is the same as in 
-TABLE EntityConstructor2(id, [fields])
-
-In Java Hibernate each class member of list type is stored in a separate table
-TABLE Student$Phones(studentId, phone)
-Here we can use triggers to automatically remove list after Student removal.
-However, toPersistValue :: a -> DbPersist conn m () becomes impossible because we must know container id
-
-We can either follow this scheme or store same type lists from different types in one table
-TABLE List$Int(id, value)
-
--- ********************************************* --}
-migrate' :: (PersistEntity v, MonadControlIO m) => v -> Migration (DbPersist Sqlite m)
-migrate' = migrateRecursively migE migT migL where
-  migE e = do
-    let name = getEntityName e
-    let constrs = constructors e
-    let mainTableQuery = "CREATE TABLE " ++ escape name ++ " (id INTEGER PRIMARY KEY, discr INTEGER NOT NULL)"
-    if isSimple constrs
-      then do
-        x <- checkTable name
-        -- check whether the table was created for multiple constructors before
-        case x of
-          Just sql | sql == mainTableQuery -> do
-            return $ Left ["Datatype with multiple constructors was truncated to one constructor. Manual migration required. Datatype: " ++ name]
-          _ -> liftM snd $ migConstrAndTrigger True name $ head constrs
-      else do
-        mainsql <- checkTable name
-        let constrTable c = name ++ [defDelim] ++ constrName c
-        res <- mapM (\c -> migConstrAndTrigger False name c) constrs
-        case mainsql of
-          Nothing -> do
-            -- no constructor tables can exist if there is no main data table
-            let orphans = filter fst res
-            return $ if null orphans
-              then mergeMigrations $ Right [(False, mainTableQuery)]:map snd res
-              else Left $ foldl (\l (_, c) -> ("Orphan constructor table found: " ++ constrTable c):l) [] $ filter (fst.fst) $ zip res constrs
-          Just sql -> do
-            if sql == mainTableQuery
-              then do -- the datatype had also many constructors before
--- check whether any new constructors appeared and increment older discriminators, which were shifted by newer constructors inserted not in the end
-                return $ if any (not.fst) res
-                  then Left ["Migration with constructors addition will be implemented soon. Datatype: " ++ name]
-                  else mergeMigrations $ map snd res
-              else do
-                return $ Left ["Migration from one constructor to many will be implemented soon. Datatype: " ++ name]
-            
-  -- we don't need any escaping because tuple table name and fields are always valid
-  migT n ts = do
-    let name = intercalate "$" $ ("Tuple" ++ show n ++ "$") : map getName ts
-    let fields = zipWith (\i t -> ("val" ++ show i, t)) [0::Int ..] ts
-    (_, trigger) <- migTriggerOnDelete name $ mkDeletesOnDelete fields
-    x <- checkTable name
-    let fields' = concatMap (\(s, t) -> sqlColumn s (getType t)) fields
-    let query = "CREATE TABLE " ++ name ++ " (id INTEGER PRIMARY KEY" ++ fields' ++ ")"
-    return $ case x of
-      Nothing  -> mergeMigrations [Right [(False, query)], trigger]
-      Just sql -> if sql == query
-        then Right []
-        else Left ["Tuple table " ++ name ++ " has unexpected structure"]
-
-  -- we should consider storing tuples as is, not their id. For example for [(a, b)] this will prevent many unnecessary queries
-  --TODO:finish
-  migL t = do
-    let mainName = "List$" ++ "$" ++ getName t
-    let valuesName = mainName ++ "$" ++ "values"
-    let mainQuery = "CREATE TABLE " ++ mainName ++ " (id INTEGER PRIMARY KEY)"
-    let valuesQuery = "CREATE TABLE " ++ valuesName ++ " (id INTEGER, ord$ INTEGER NOT NULL" ++ sqlColumn "value" (getType t) ++ ")"
-    x <- checkTable mainName
-    y <- checkTable valuesName
-    (_, triggerMain) <- migTriggerOnDelete mainName ["DELETE FROM " ++ valuesName ++ " WHERE id=old.id;"]
-    (_, triggerValues) <- migTriggerOnDelete valuesName $ mkDeletesOnDelete [("value", t)]
-    let f name a b = if a /= b then ["List table " ++ name ++ " error. Expected: " ++ a ++ ". Found: " ++ b] else []
-    return $ case (x, y) of
-      (Nothing, Nothing) -> mergeMigrations [Right [(False, mainQuery), (False, valuesQuery)], triggerMain, triggerValues]
-      (Just sql1, Just sql2) -> let errors = f mainName mainQuery sql1 ++ f valuesName valuesQuery sql2
-                                in if null errors then Right [] else Left errors
-      (_, Nothing) -> Left ["Found orphan main list table " ++ mainName]
-      (Nothing, _) -> Left ["Found orphan list values table " ++ valuesName]
-
-migConstrAndTrigger :: MonadControlIO m => Bool -> String -> ConstructorDef -> DbPersist Sqlite m (Bool, SingleMigration)
-migConstrAndTrigger simple name constr = do
-  let cName = if simple then name else name ++ [defDelim] ++ constrName constr
-  (constrExisted, mig) <- migConstr cName constr
-  let dels = mkDeletesOnDelete $ constrParams constr
-  let allDels = if simple then dels else ("DELETE FROM " ++ escape name ++ " WHERE id=old." ++ constrId ++ ";"):dels
-  (triggerExisted, delTrigger) <- migTriggerOnDelete cName allDels
-  let updDels = mkDeletesOnUpdate $ constrParams constr
-  updTriggers <- mapM (liftM snd . uncurry (migTriggerOnUpdate cName)) updDels
-  return $ if constrExisted == triggerExisted || (constrExisted && null allDels)
-    then (constrExisted, mergeMigrations ([mig, delTrigger] ++ updTriggers))
-    -- this can happen when an ephemeral field was added. Consider doing something else except throwing an error
-    else (constrExisted, Left ["Trigger and constructor table must exist together: " ++ cName])
+migrate' :: (PersistEntity v, MonadBaseControl IO m, MonadIO m) => v -> Migration (DbPersist Sqlite m)
+migrate' = migrateRecursively (migrateEntity migrationPack) (migrateList migrationPack)
 
-migConstr :: MonadControlIO m => String -> ConstructorDef -> DbPersist Sqlite m (Bool, SingleMigration)
-migConstr name constr = do
-  let fields = constrParams constr
-  let uniques = constrConstrs constr
-  let query = "CREATE TABLE " ++ escape name ++ " (" ++ constrId ++ " INTEGER PRIMARY KEY" ++ concatMap (\(n, t) -> sqlColumn n (getType t)) fields ++ concatMap sqlUnique uniques ++ ")"
-  x <- checkTable name
-  return $ case x of
-    Nothing  -> (False, Right [(False, query)])
-    Just sql -> (True, if sql == query
-      then Right []
-      else Left ["Constructor table must be altered: " ++ name])
+migrationPack :: (MonadBaseControl IO m, MonadIO m) => GM.MigrationPack (DbPersist Sqlite m) Affinity
+migrationPack = GM.MigrationPack
+  compareColumns
+  compareRefs
+  compareUniqs
+  checkTable
+  migTriggerOnDelete
+  migTriggerOnUpdate
+  GM.defaultMigConstr
+  escape
+  "INTEGER PRIMARY KEY"
+  "INTEGER"
+  mainTableId
+  defaultPriority
+  dbTypeAffinity
+  (\uniques refs -> (map sqlUnique uniques ++ map sqlReference refs, []))
+  showColumn
+  showAlterDb
 
--- it handles only delete operations. So far when list or tuple replace is not allowed, it is ok
-migTriggerOnDelete :: MonadControlIO m => String -> [String] -> DbPersist Sqlite m (Bool, SingleMigration)
+-- it handles only delete operations. So far when list replace is not allowed, it is ok
+migTriggerOnDelete :: (MonadBaseControl IO m, MonadIO m) => String -> [(String, String)] -> DbPersist Sqlite m (Bool, [AlterDB Affinity])
 migTriggerOnDelete name deletes = do
-  let query = "CREATE TRIGGER " ++ escape name ++ " DELETE ON " ++ escape name ++ " BEGIN " ++ concat deletes ++ "END"
+  let addTrigger = AddTriggerOnDelete name name (concatMap snd deletes)
   x <- checkTrigger name
   return $ case x of
-    Nothing | null deletes -> (False, Right [])
-    Nothing -> (False, Right [(False, query)])
+    Nothing | null deletes -> (False, [])
+    Nothing -> (False, [addTrigger])
     Just sql -> (True, if null deletes -- remove old trigger if a datatype earlier had fields of ephemeral types
-      then Right [(False, "DROP TRIGGER " ++ escape name)]
-      else if sql == query
-        then Right []
-        -- this can happen when a field was added or removed. Consider trigger replacement.
-        else Left ["The trigger " ++ name ++ " is different from expected. Manual migration required.\n" ++ sql ++ "\n" ++ query])
+      then [DropTrigger name name]
+      else if Right [(False, triggerPriority, sql)] == showAlterDb addTrigger
+        then []
+        -- this can happen when an ephemeral field was added or removed.
+        else [DropTrigger name name, addTrigger])
         
 -- | Table name and a  list of field names and according delete statements
 -- assume that this function is called only for ephemeral fields
-migTriggerOnUpdate :: MonadControlIO m => String -> String -> String -> DbPersist Sqlite m (Bool, SingleMigration)
+migTriggerOnUpdate :: (MonadBaseControl IO m, MonadIO m) => String -> String -> String -> DbPersist Sqlite m (Bool, [AlterDB Affinity])
 migTriggerOnUpdate name fieldName del = do
-  let tname = name ++ "$" ++ fieldName
-  let query = "CREATE TRIGGER " ++ escape tname ++ " UPDATE OF " ++ escape fieldName ++ " ON " ++ escape name ++ " BEGIN " ++ del ++ "END"
-  x <- checkTrigger tname
+  let trigName = name ++ delim : fieldName
+  let addTrigger = AddTriggerOnUpdate trigName name fieldName del
+  x <- checkTrigger trigName
   return $ case x of
-    Nothing -> (False, Right [(False, query)])
-    Just sql -> (True, if sql == query
-        then Right []
-        else Left ["The trigger " ++ tname ++ " is different from expected. Manual migration required.\n" ++ sql ++ "\n" ++ query])
-
--- on delete removes all ephemeral data
--- TODO: merge several delete queries for a case when a constructor has several fields of the same ephemeral type
-mkDeletesOnDelete :: [(String, NamedType)] -> [String]
-mkDeletesOnDelete types = map (uncurry delField) ephemerals where
-  -- we have the same query structure for tuples and lists
-  delField field t = "DELETE FROM " ++ tname ++ " WHERE id=old." ++ escape field ++ ";" where
-    tname = getName t
-  ephemerals = filter (isEphemeral.snd) types
+    Nothing -> (False, [addTrigger])
+    Just sql -> (True, if Right [(False, triggerPriority, sql)] == showAlterDb addTrigger
+        then []
+        else [DropTrigger trigName name, addTrigger])
   
--- on delete removes all ephemeral data
-mkDeletesOnUpdate :: [(String, NamedType)] -> [(String, String)]
-mkDeletesOnUpdate types = map (uncurry delField) ephemerals where
-  -- we have the same query structure for tuples and lists
-  delField field t = (field, "DELETE FROM " ++ tname ++ " WHERE id=old." ++ escape field ++ ";") where
-    tname = getName t
-  ephemerals = filter (isEphemeral.snd) types
-
-isEphemeral :: NamedType -> Bool
-isEphemeral a = case getType a of
-  DbList _    -> True
-  DbTuple _ _ -> True
-  _           -> False
-
-checkTrigger :: MonadControlIO m => String -> DbPersist Sqlite m (Maybe String)
+checkTrigger :: (MonadBaseControl IO m, MonadIO m) => String -> DbPersist Sqlite m (Maybe String)
 checkTrigger = checkSqliteMaster "trigger"
 
-checkTable :: MonadControlIO m => String -> DbPersist Sqlite m (Maybe String)
-checkTable = checkSqliteMaster "table"
-
-checkSqliteMaster :: MonadControlIO m => String -> String -> DbPersist Sqlite m (Maybe String)
+checkSqliteMaster :: (MonadBaseControl IO m, MonadIO m) => String -> String -> DbPersist Sqlite m (Maybe String)
 checkSqliteMaster vtype name = do
   let query = "SELECT sql FROM sqlite_master WHERE type = ? AND name = ?"
-  x <- queryRawTyped query [DbString] [toPrim vtype, toPrim name] firstRow
+  x <- queryRawTyped query [DbString] [toPrimitivePersistValue proxy vtype, toPrimitivePersistValue proxy name] id
   let throwErr = error . ("Unexpected result from sqlite_master: " ++)
   case x of
     Nothing -> return Nothing
@@ -283,22 +177,71 @@
       err               -> throwErr $ "column sql is not string: " ++ show err
     Just xs -> throwErr $ "requested 1 column, returned " ++ show xs
 
-getStatementCached :: MonadIO m => String -> DbPersist Sqlite m S.Statement
+checkTable :: (MonadBaseControl IO m, MonadIO m) => String -> DbPersist Sqlite m (Maybe (Either [String] (TableInfo Affinity)))
+checkTable tableName = do
+  let fromName = escapeS . fromString
+  tableInfo <- queryRaw' ("pragma table_info(" <> fromName tableName <> ")") [] $ mapAllRows (return . fst . fromPurePersistValues proxy)
+  case tableInfo of
+    [] -> return Nothing
+    xs -> liftM Just $ do
+      let rawColumns = filter (\(_ , (_, _, _, _, isPrimary)) -> isPrimary == 0) xs
+      let mkColumn :: (Int, (String, String, Int, Maybe String, Int)) -> Column Affinity
+          mkColumn (_, (name, typ, isNotNull, defaultValue, _)) = Column name (isNotNull == 0) (readSqlTypeAffinity typ) defaultValue
+      let columns = map mkColumn rawColumns
+      indexList <- queryRaw' ("pragma index_list(" <> fromName tableName <> ")") [] $ mapAllRows (return . fst . fromPurePersistValues proxy)
+      let uniqueNames = map (\(_ :: Int, name, _) -> name) $ filter (\(_, _, isUnique) -> isUnique) indexList
+      uniques <- forM uniqueNames $ \name -> do
+        let mkUnique :: [(Int, Int, String)] -> UniqueDef'
+            mkUnique us = UniqueDef'
+              ""
+              (map (\(_, _, columnName) -> columnName) us)
+        queryRaw' ("pragma index_info(" <> fromName name <> ")") [] $ liftM mkUnique . mapAllRows (return . fst . fromPurePersistValues proxy)
+      foreignKeyList <- queryRaw' ("pragma foreign_key_list(" <> fromName tableName <> ")") [] $ mapAllRows (return . fst . fromPurePersistValues proxy)
+      (foreigns :: [(Maybe String, Reference)]) <- do
+          let foreigns :: [[(Int, (Int, String, (String, Maybe String), (String, String, String)))]]
+              foreigns = groupBy ((==) `on` fst) . sort $ foreignKeyList -- sort by foreign key number and column number inside key (first and second integers)
+          --mkForeignKey :: [(Int, (Int, String, (String, Maybe String), (String, String, String)))] -> (Maybe String, Reference)
+          forM foreigns $ \rows -> do 
+            let (_, (_, foreignTable, _, _)) = head rows
+            refs <- forM rows $ \(_, (_, _, (child, parent), _)) -> case parent of
+              Nothing -> checkPrimaryKey foreignTable >>= \x -> case x of
+                Left (Just primaryKeyName) -> return (child, primaryKeyName)
+                _ -> error $ "checkTable: cannot find primary key for table " ++ foreignTable ++ " which is referenced without specifying column names"
+              Just columnName -> return (child, columnName)
+            return (Nothing, (foreignTable, refs))
+      primaryKeyResult <- checkPrimaryKey tableName
+      let (primaryKey, uniques') = case primaryKeyResult of
+            Left primaryKeyName -> (primaryKeyName, uniques)
+            Right u -> (Nothing, u:uniques)
+      return $ Right $ TableInfo primaryKey columns uniques' foreigns
+
+checkPrimaryKey :: (MonadBaseControl IO m, MonadIO m) => String -> DbPersist Sqlite m (Either (Maybe String) UniqueDef')
+checkPrimaryKey tableName = do
+  tableInfo <- queryRaw' ("pragma table_info(" <> escapeS (fromString tableName) <> ")") [] $ mapAllRows (return . fst . fromPurePersistValues proxy)
+  let rawColumns :: [(Int, (String, String, Int, Maybe String, Int))]
+      rawColumns = filter (\(_ , (_, _, _, _, isPrimary)) -> isPrimary == 1) tableInfo
+  return $ case rawColumns of
+    [] -> Left Nothing
+    [(_, (name, _, _, _, _))] -> Left (Just name)
+    us -> Right $ UniqueDef' "" (map (\(_, (name, _, _, _, _)) -> name) us)
+
+getStatementCached :: (MonadBaseControl IO m, MonadIO m) => Utf8 -> DbPersist Sqlite m S.Statement
 getStatementCached sql = do
   Sqlite conn smap <- DbPersist ask
   liftIO $ do
     smap' <- readIORef smap
-    case Map.lookup sql smap' of
+    let sql' = fromUtf8 sql
+    case Map.lookup sql' smap' of
       Nothing -> do
-        stmt <- S.prepare conn sql
-        writeIORef smap (Map.insert sql stmt smap')
+        stmt <- S.prepare conn sql'
+        writeIORef smap (Map.insert sql' stmt smap')
         return stmt
       Just stmt -> return stmt
 
-getStatement :: MonadIO m => String -> DbPersist Sqlite m S.Statement
+getStatement :: (MonadBaseControl IO m, MonadIO m) => Utf8 -> DbPersist Sqlite m S.Statement
 getStatement sql = do
   Sqlite conn _ <- DbPersist ask
-  liftIO $ S.prepare conn sql
+  liftIO $ S.prepare conn (fromUtf8 sql)
 
 showSqlType :: DbType -> String
 showSqlType DbString = "VARCHAR"
@@ -309,392 +252,131 @@
 showSqlType DbDay = "DATE"
 showSqlType DbTime = "TIME"
 showSqlType DbDayTime = "TIMESTAMP"
+showSqlType DbDayTimeZoned = "TIMESTAMP"
 showSqlType DbBlob = "BLOB"
-showSqlType (DbMaybe t) = showSqlType (getType t)
-showSqlType (DbList _) = "INTEGER"
-showSqlType (DbTuple _ _) = "INTEGER"
-showSqlType (DbEntity _) = "INTEGER"
+showSqlType (DbMaybe t) = showSqlType t
+showSqlType (DbList _ _) = showSqlType DbInt64
+showSqlType (DbEntity Nothing _) = showSqlType DbInt64
+showSqlType t = error $ "showSqlType: DbType does not have corresponding database type: " ++ show t
 
-{-
-DbMaybe prim -> name type
-prim         -> name type NOT NULL
-comp         -> name type NOT NULL REFERENCES table
-DbMaybe comp -> name type REFERENCES table
--}
+data Affinity = TEXT | NUMERIC | INTEGER | REAL | NONE deriving (Eq, Show)
 
-sqlColumn :: String -> DbType -> String
-sqlColumn name typ = ", " ++ escape name ++ " " ++ showSqlType typ ++ f typ where
-  f (DbMaybe t) = g (getType t)
-  f t = " NOT NULL" ++ g t
-  -- TODO: add references for tuple and list
-  g (DbEntity t) = " REFERENCES " ++ escape (getEntityName t)
-  g (DbTuple n ts) = " REFERENCES " ++ (intercalate "$" $ ("Tuple" ++ show n ++ "$") : map getName ts)
-  g (DbList t) = " REFERENCES " ++ "List$$" ++ getName t
-  g _ = ""
+dbTypeAffinity :: DbType -> Affinity
+dbTypeAffinity DbString = TEXT
+dbTypeAffinity DbInt32 = INTEGER
+dbTypeAffinity DbInt64 = INTEGER
+dbTypeAffinity DbReal = REAL
+dbTypeAffinity DbBool = NUMERIC
+dbTypeAffinity DbDay = NUMERIC
+dbTypeAffinity DbTime = NUMERIC
+dbTypeAffinity DbDayTime = NUMERIC
+dbTypeAffinity DbDayTimeZoned = NUMERIC
+dbTypeAffinity DbBlob = NONE
+dbTypeAffinity (DbMaybe t) = dbTypeAffinity t
+dbTypeAffinity (DbList _ _) = INTEGER
+dbTypeAffinity (DbEntity Nothing _) = INTEGER
+dbTypeAffinity t = error $ "showSqlType: DbType does not have corresponding database type: " ++ show t
 
-sqlUnique :: Constraint -> String
-sqlUnique (cname, cols) = concat
-    [ ", CONSTRAINT "
-    , escape cname
+readSqlTypeAffinity :: String -> Affinity
+readSqlTypeAffinity typ = affinity where
+  contains = any (`isInfixOf` map toUpper typ)
+  affinity = case () of
+    _ | contains ["INT"] -> INTEGER
+    _ | contains ["CHAR", "CLOB", "TEXT"]  -> TEXT
+    _ | contains ["BLOB"] || null typ -> NONE
+    _ | contains ["REAL", "FLOA", "DOUB"]  -> REAL
+    _ -> NUMERIC
+
+showColumn :: Column DbType -> String
+showColumn (Column name isNull typ _) = escape name ++ " " ++ showSqlType typ ++ rest where
+  rest = if not isNull 
+           then " NOT NULL"
+           else ""
+
+sqlReference :: Reference -> String
+sqlReference (tname, columns) = "FOREIGN KEY(" ++ our ++ ") REFERENCES " ++ escape tname ++ "(" ++ foreign ++ ")" where
+  (our, foreign) = f *** f $ unzip columns
+  f = intercalate ", " . map escape
+
+sqlUnique :: UniqueDef' -> String
+sqlUnique (UniqueDef' name cols) = concat
+    [ "CONSTRAINT "
+    , escape name
     , " UNIQUE ("
     , intercalate "," $ map escape cols
     , ")"
     ]
 
-{-# SPECIALIZE insert' :: PersistEntity v => v -> DbPersist Sqlite IO (Key v) #-}
+{-# SPECIALIZE insert' :: PersistEntity v => v -> DbPersist Sqlite IO (AutoKey v) #-}
 {-# INLINE insert' #-}
-insert' :: (PersistEntity v, MonadControlIO m) => v -> DbPersist Sqlite m (Key v)
+insert' :: (PersistEntity v, MonadBaseControl IO m, MonadIO m) => v -> DbPersist Sqlite m (AutoKey v)
 insert' v = do
   -- constructor number and the rest of the field values
-  vals <- toPersistValues v
+  vals <- toEntityPersistValues' v
   let e = entityDef v
-  let name = getEntityName e
-  let constructorNum = fromPrim (head vals)
+  let name = persistName v
+  let constructorNum = fromPrimitivePersistValue proxy (head vals)
 
-  if isSimple (constructors e)
+  liftM fst $ if isSimple (constructors e)
     then do
       let constr = head $ constructors e
       let query = insertIntoConstructorTable False name constr
-      executeRaw True query (tail vals)
-      rowid <- getLastInsertRowId
-      return $ Key rowid
+      executeRawCached' query (tail vals)
+      case constrAutoKeyName constr of
+        Nothing -> pureFromPersistValue []
+        Just _  -> getLastInsertRowId >>= \rowid -> pureFromPersistValue [rowid]
     else do
       let constr = constructors e !! constructorNum
-      let cName = name ++ [defDelim] ++ constrName constr
-      let query = "INSERT INTO " ++ escape name ++ "(discr)VALUES(?)"
-      executeRaw True query $ take 1 vals
+      let cName = name ++ [delim] ++ constrName constr
+      let query = "INSERT INTO " <> escapeS (fromString name) <> "(discr)VALUES(?)"
+      executeRawCached' query $ take 1 vals
       rowid <- getLastInsertRowId
       let cQuery = insertIntoConstructorTable True cName constr
-      executeRaw True cQuery $ PersistInt64 rowid:(tail vals)
-      return $ Key rowid
-
--- in Sqlite we can insert null to the id column. If so, id will be generated automatically
-insertIntoConstructorTable :: Bool -> String -> ConstructorDef -> String
-insertIntoConstructorTable withId tName c = "INSERT INTO " ++ escape tName ++ "(" ++ fieldNames ++ ")VALUES(" ++ placeholders ++ ")" where
-  fieldNames   = intercalate "," $ (if withId then (constrId:) else id) $ map (escape.fst) (constrParams c)
-  placeholders = intercalate "," $ (if withId then ("?":) else id) $ map (const "?") (constrParams c)
-
-{-# SPECIALIZE insertBy' :: PersistEntity v => v -> DbPersist Sqlite IO (Either (Key v) (Key v)) #-}
-insertBy' :: (MonadControlIO m, PersistEntity v) => v -> DbPersist Sqlite m (Either (Key v) (Key v))
-insertBy' v = do
-  let e = entityDef v
-  let name = getEntityName e
-
-  let constraints = getConstraints v
-  let constructorNum = fst constraints
-  let constraintFields = map snd $ snd constraints
-  let constrCond = intercalate " OR " $ map (intercalate " AND " . map (\(fname, _) -> escape fname ++ "=?")) constraintFields
-
-  let ifAbsent tname ins = if null constraintFields
-       then liftM (Right . Key) ins
-       else do
-         let query = "SELECT " ++ constrId ++ " FROM " ++ escape tname ++ " WHERE " ++ constrCond
-         x <- queryRawTyped query [DbInt64] (concatMap (map snd) constraintFields) firstRow
-         case x of
-           Nothing  -> liftM (Right . Key) ins
-           Just [k] -> return $ Left $ fromPrim k
-           Just xs  -> fail $ "unexpected query result: " ++ show xs
-
-  if isSimple (constructors e)
-    then do
-      let constr = head $ constructors e
-      ifAbsent name $ do
-        let query = insertIntoConstructorTable False name constr
-        vals <- toPersistValues v
-        executeRaw True query (tail vals)
-        getLastInsertRowId
-    else do
-      let constr = constructors e !! constructorNum
-      let cName = name ++ [defDelim] ++ constrName constr
-      ifAbsent cName $ do
-        let query = "INSERT INTO " ++ escape name ++ "(discr)VALUES(?)"
-        vals <- toPersistValues v
-        executeRaw True query $ take 1 vals
-        rowid <- getLastInsertRowId
-        let cQuery = insertIntoConstructorTable True cName constr
-        executeRaw True cQuery $ PersistInt64 rowid :(tail vals)
-        return rowid
-
-replace' :: (MonadControlIO m, PersistEntity v) => Key v -> v -> DbPersist Sqlite m ()
-replace' k v = do
-  vals <- toPersistValues v
-  let e = entityDef v
-  let name = getEntityName e
-  let constructorNum = fromPrim (head vals)
-  let constr = constructors e !! constructorNum
-
-  let upds = intercalate "," $ map (\f -> escape (fst f) ++ "=?") $ constrParams constr
-  let mkQuery tname = "UPDATE " ++ escape tname ++ " SET " ++ upds ++ " WHERE " ++ constrId ++ "=?"
-
-  if isSimple (constructors e)
-    then executeRaw True (mkQuery name) (tail vals ++ [toPrim k])
-    else do
-      let query = "SELECT discr FROM " ++ escape name ++ " WHERE id=?"
-      x <- queryRawTyped query [DbInt32] [toPrim k] (firstRow >=> return.fmap (fromPrim . head))
-      case x of
-        Just discr -> do
-          let cName = name ++ [defDelim] ++ constrName constr
-
-          if discr == constructorNum
-            then executeRaw True (mkQuery cName) (tail vals ++ [toPrim k])
-            else do
-              let insQuery = insertIntoConstructorTable True cName constr
-              executeRaw True insQuery (toPrim k:tail vals)
-
-              let oldCName = name ++ [defDelim] ++ constrName (constructors e !! discr)
-              let delQuery = "DELETE FROM " ++ escape oldCName ++ " WHERE " ++ constrId ++ "=?"
-              executeRaw True delQuery [toPrim k]
-
-              -- UGLY: reinsert entry with a new discr to the main table after it was deleted by a trigger.
-              let reInsQuery = "INSERT INTO " ++ escape name ++ "(id,discr)VALUES(?,?)"
-              executeRaw True reInsQuery [toPrim k, head vals]
-        Nothing -> return ()
-
--- | receives constructor number and row of values from the constructor table
-mkEntity :: (PersistEntity v, PersistBackend m) => Int -> [PersistValue] -> m (Key v, v)
-mkEntity i (k:xs) = fromPersistValues (toPrim i:xs) >>= \v -> return (fromPrim k, v)
-mkEntity _ [] = error "Unable to create entity. No values supplied"
-
-selectEnum' :: (MonadControlIO m, PersistEntity v, Constructor c) => Cond v c -> [Order v c] -> Int -> Int -> Enumerator (Key v, v) (DbPersist Sqlite m) a
-selectEnum' (cond :: Cond v c) ords limit offset = start where
-  start = if isSimple (constructors e)
-    then joinE (queryEnum (mkQuery name) types binds) (EL.mapM (mkEntity 0))
-    else let
-      query = mkQuery $ name ++ [defDelim] ++ constrName constr
-      in joinE (queryEnum query types binds) (EL.mapM (mkEntity $ constrNum constr))
-
-  e = entityDef (undefined :: v)
-  orders = renderOrders escape ords
-  name = getEntityName e
-  (lim, limps) = case (limit, offset) of
-        (0, 0) -> ("", [])
-        (0, o) -> (" LIMIT -1 OFFSET ?", [toPrim o])
-        (l, 0) -> (" LIMIT ?", [toPrim l])
-        (l, o) -> (" LIMIT ? OFFSET ?", [toPrim l, toPrim o])
-  (conds, condps) = renderCond' cond
-  mkQuery tname = "SELECT * FROM " ++ escape tname ++ " WHERE " ++ (conds . orders $ lim)
-  binds = condps limps
-  constr = (constructors e) !! phantomConstrNum (undefined :: c)
-  types = DbInt64:getConstructorTypes constr
-
-selectAllEnum' :: forall m v a.(MonadControlIO m, PersistEntity v) => Enumerator (Key v, v) (DbPersist Sqlite m) a
-selectAllEnum' = start where
-  start = if isSimple (constructors e)
-    then let
-      query = "SELECT * FROM " ++ escape name
-      types = DbInt64:(getConstructorTypes $ head $ constructors e)
-      in joinE (queryEnum query types []) (EL.mapM (mkEntity 0))
-    else concatEnums $ zipWith q [0..] (constructors e) where
-      q cNum constr = let
-        cName = name ++ [defDelim] ++ constrName constr
-        query = "SELECT * FROM " ++ escape cName
-        types = DbInt64:getConstructorTypes constr
-        in joinE (queryEnum query types []) (EL.mapM (mkEntity cNum))
-
-  e = entityDef (undefined :: v)
-  name = getEntityName e
-
--- unfortunately, running consume on Enumerator is ~50% slower. So, lets duplicate the code
-select' :: (MonadControlIO m, PersistEntity v, Constructor c) => Cond v c -> [Order v c] -> Int -> Int -> DbPersist Sqlite m [(Key v, v)]
-select' (cond :: Cond v c) ords limit offset = start where
-  start = if isSimple (constructors e)
-    then doSelectQuery (mkQuery name) 0
-    else let
-      cName = name ++ [defDelim] ++ constrName constr
-      in doSelectQuery (mkQuery cName) $ constrNum constr
-
-  e = entityDef (undefined :: v)
-  orders = renderOrders escape ords
-  name = getEntityName e
-  (lim, limps) = case (limit, offset) of
-        (0, 0) -> ("", [])
-        (0, o) -> (" LIMIT -1 OFFSET ?", [toPrim o])
-        (l, 0) -> (" LIMIT ?", [toPrim l])
-        (l, o) -> (" LIMIT ? OFFSET ?", [toPrim l, toPrim o])
-  (conds, condps) = renderCond' cond
-  mkQuery tname = "SELECT * FROM " ++ escape tname ++ " WHERE " ++ (conds . orders $ lim)
-  doSelectQuery query cNum = queryRawTyped query types binds $ mapAllRows (mkEntity cNum)
-  binds = condps limps
-  constr = constructors e !! phantomConstrNum (undefined :: c)
-  types = DbInt64:getConstructorTypes constr
-
-selectAll' :: forall m v.(MonadControlIO m, PersistEntity v) => DbPersist Sqlite m [(Key v, v)]
-selectAll' = start where
-  start = if isSimple (constructors e)
-    then let
-      query = "SELECT * FROM " ++ escape name
-      types = DbInt64:(getConstructorTypes $ head $ constructors e)
-      in queryRawTyped query types [] $ mapAllRows (mkEntity 0)
-    else liftM concat $ forM (zip [0..] (constructors e)) $ \(i, constr) -> do
-        let cName = name ++ [defDelim] ++ constrName constr
-        let query = "SELECT * FROM " ++ escape cName
-        let types = DbInt64:getConstructorTypes constr
-        queryRawTyped query types [] $ mapAllRows (mkEntity i)
-
-  e = entityDef (undefined :: v)
-  name = getEntityName e
-
-{-
-insertList :: PersistField a => [a] -> DbPersist conn m Int64
-insertList xs = do
-  xs' <- mapM toPersistValue xs
-  let name = persistName xs
-  let query = "INSERT INTO " ++ name ++ " ("
-  getStatement 
--}
-
-insertTuple' :: MonadIO m => NamedType -> [PersistValue] -> DbPersist Sqlite m Int64
-insertTuple' t vals = do
-  let name = getName t
-  let (DbTuple _ ts) = getType t
-  let fields = map (\i -> "val" ++ show i) [0 .. length ts - 1] 
-  let query = "INSERT INTO " ++ name ++ " (" ++ intercalate ", " fields ++ ")VALUES(" ++ intercalate ", " (replicate (length ts) "?") ++ ")"
-  executeRawCached' query vals
-  getLastInsertRowId
-
-getTuple' :: MonadControlIO m => NamedType -> Int64 -> DbPersist Sqlite m [PersistValue]
-getTuple' t k = do
-  let name = getName t
-  let (DbTuple _ ts) = getType t
-  let query = "SELECT * FROM " ++ name ++ " WHERE id = ?"
-  x <- queryRawTyped query (DbInt64:map getType ts) [toPrim k] firstRow
-  maybe (fail $ "No tuple with id " ++ show k) (return . tail) x
-
-{-# SPECIALIZE get' :: PersistEntity v => Key v -> DbPersist Sqlite IO (Maybe v) #-}
-{-# INLINE get' #-}
-get' :: (MonadControlIO m, PersistEntity v) => Key v -> DbPersist Sqlite m (Maybe v)
-get' (k :: Key v) = do
-  let e = entityDef (undefined :: v)
-  let name = getEntityName e
-  if isSimple (constructors e)
-    then do
-      let constr = head $ constructors e
-      let query = "SELECT * FROM " ++ escape name ++ " WHERE " ++ constrId ++ "=?"
-      x <- queryRawTyped query (DbInt64:getConstructorTypes constr) [toPrim k] firstRow
-      case x of
-        Just (_:xs) -> liftM Just $ fromPersistValues $ PersistInt64 0:xs
-        Just x'    -> fail $ "Unexpected number of columns returned: " ++ show x'
-        Nothing -> return Nothing
-    else do
-      let query = "SELECT discr FROM " ++ escape name ++ " WHERE id=?"
-      x <- queryRawTyped query [DbInt64] [toPrim k] firstRow
-      case x of
-        Just [discr] -> do
-          let constructorNum = fromPrim discr
-          let constr = constructors e !! constructorNum
-          let cName = name ++ [defDelim] ++ constrName constr
-          let cQuery = "SELECT * FROM " ++ escape cName ++ " WHERE " ++ constrId ++ "=?"
-          x2 <- queryRawTyped cQuery (DbInt64:getConstructorTypes constr) [toPrim k] firstRow
-          case x2 of
-            Just (_:xs) -> liftM Just $ fromPersistValues $ discr:xs
-            Just x2'    -> fail $ "Unexpected number of columns returned: " ++ show x2'
-            Nothing     -> fail "Missing entry in constructor table"
-        Just x' -> fail $ "Unexpected number of columns returned: " ++ show x'
-        Nothing -> return Nothing
-
-update' :: (PersistBackend m, PersistEntity v, Constructor c) => [Update v c] -> Cond v c -> m ()
-update' upds (cond :: Cond v c) = do
-  let e = entityDef (undefined :: v)
-  let name = getEntityName e
-  let (conds, condps) = renderCond' cond
-  let (upds', ps) = renderUpdates escape upds
-  let mkQuery tname = "UPDATE " ++ escape tname ++ " SET " ++ (upds' . (" WHERE " ++) . conds $ "")
-  if isSimple (constructors e)
-    then executeRaw True (mkQuery name) (ps $ condps [])
-    else do
-      let cName = name ++ [defDelim] ++ phantomConstrName (undefined :: c)
-      executeRaw True (mkQuery cName) (ps $ condps [])
-
-delete' :: (PersistBackend m, PersistEntity v, Constructor c) => Cond v c -> m ()
-delete' (cond :: Cond v c) = do
-  let e = entityDef (undefined :: v)
-  let (conds, condps) = renderCond' cond
-  let name = getEntityName e
-  if isSimple (constructors e)
-    then do
-      let query = "DELETE FROM " ++ escape name ++ " WHERE " ++ conds ""
-      executeRaw True query (condps [])
-    else do
-      -- after removal from the constructor table, entry from the main table is removed by trigger
-      let cName = name ++ [defDelim] ++ phantomConstrName (undefined :: c)
-      let query = "DELETE FROM " ++ escape cName ++ " WHERE " ++ conds ""
-      executeRaw True query (condps [])
-      
-deleteByKey' :: (MonadControlIO m, PersistEntity v) => Key v -> DbPersist Sqlite m ()
-deleteByKey' (k :: Key v) = do
-  let e = entityDef (undefined :: v)
-  let name = getEntityName e
-  if isSimple (constructors e)
-    then do
-      let query = "DELETE FROM " ++ escape name ++ " WHERE id$=?"
-      executeRaw True query [toPrim k]
-    else do
-      let query = "SELECT discr FROM " ++ escape name
-      x <- queryRawTyped query [DbInt64] [] firstRow
-      case x of
-        Just [discr] -> do
-          let cName = name ++ [defDelim] ++ constrName (constructors e !! fromPrim discr)
-          let cQuery = "DELETE FROM " ++ escape cName ++ " WHERE id$=?"
-          executeRaw True cQuery [toPrim k]
-        Just xs -> fail $ "requested 1 column, returned " ++ show xs
-        Nothing -> return ()
+      executeRawCached' cQuery $ rowid:(tail vals)
+      pureFromPersistValue [rowid]
 
-{-# SPECIALIZE count' :: (PersistEntity v, Constructor c) => Cond v c -> DbPersist Sqlite IO Int #-}
-count' :: (MonadControlIO m, PersistEntity v, Constructor c) => Cond v c -> DbPersist Sqlite m Int
-count' (cond :: Cond v c) = do
-  let cName = persistName (undefined :: v) ++ [defDelim] ++ phantomConstrName (undefined :: c)
-  let (conds, condps) = renderCond' cond
-  let query = "SELECT COUNT(*) FROM " ++ cName ++ " WHERE " ++ conds ""
-  x <- queryRawTyped query [DbInt64] (condps []) firstRow
-  case x of
-    Just [num] -> return $ fromPrim num
-    Just xs -> fail $ "requested 1 column, returned " ++ show (length xs)
-    Nothing -> fail $ "COUNT returned no rows"
+-- TODO: In Sqlite we can insert null to the id column. If so, id will be generated automatically. Check performance change from this.
+insertIntoConstructorTable :: Bool -> String -> ConstructorDef -> Utf8
+insertIntoConstructorTable withId tName c = "INSERT INTO " <> escapeS (fromString tName) <> "(" <> fieldNames <> ")VALUES(" <> placeholders <> ")" where
+  fields = case constrAutoKeyName c of
+    Just idName | withId -> (idName, dbType (0 :: Int64)):constrParams c
+    _                    -> constrParams c
+  fieldNames   = renderFields escapeS fields
+  placeholders = renderFields (const $ fromChar '?') fields
 
-{-# SPECIALIZE countAll' :: PersistEntity v => v -> DbPersist Sqlite IO Int #-}
-countAll' :: (MonadControlIO m, PersistEntity v) => v -> DbPersist Sqlite m Int
-countAll' (_ :: v) = do
-  let name = persistName (undefined :: v)
-  let query = "SELECT COUNT(*) FROM " ++ name
-  x <- queryRawTyped query [DbInt64] [] firstRow
-  case x of
-    Just [num] -> return $ fromPrim num
-    Just xs -> fail $ "requested 1 column, returned " ++ show (length xs)
-    Nothing -> fail $ "COUNT returned no rows"
-    
-insertList' :: forall m a.(MonadControlIO m, PersistField a) => [a] -> DbPersist Sqlite m Int64
+insertList' :: forall m a.(MonadBaseControl IO m, MonadIO m, PersistField a) => [a] -> DbPersist Sqlite m Int64
 insertList' l = do
-  let mainName = "List$$" ++ persistName (undefined :: a)
-  executeRaw True ("INSERT INTO " ++ mainName ++ " DEFAULT VALUES") []
+  let mainName = "List" <> delim' <> delim' <> fromString (persistName (undefined :: a))
+  executeRawCached' ("INSERT INTO " <> escapeS mainName <> " DEFAULT VALUES") []
   k <- getLastInsertRowId
-  let valuesName = mainName ++ "$" ++ "values"
-  let query = "INSERT INTO " ++ valuesName ++ "(id,ord$,value)VALUES(?,?,?)"
+  let valuesName = mainName <> delim' <> "values"
+  let fields = [("ord", dbType (0 :: Int)), ("value", dbType (undefined :: a))]
+  let query = "INSERT INTO " <> escapeS valuesName <> "(id," <> renderFields escapeS fields <> ")VALUES(?," <> renderFields (const $ fromChar '?') fields <> ")"
   let go :: Int -> [a] -> DbPersist Sqlite m ()
       go n (x:xs) = do
-       x' <- toPersistValue x
-       executeRaw True query [toPrim k, toPrim n, x']
+       x' <- toPersistValues x
+       executeRawCached' query $ (k:) . (toPrimitivePersistValue proxy n:) . x' $ []
        go (n + 1) xs
       go _ [] = return ()
   go 0 l
-  return k
+  return $ fromPrimitivePersistValue proxy k
   
-getList' :: forall m a.(MonadControlIO m, PersistField a) => Int64 -> DbPersist Sqlite m [a]
+getList' :: forall m a.(MonadBaseControl IO m, MonadIO m, PersistField a) => Int64 -> DbPersist Sqlite m [a]
 getList' k = do
-  let mainName = "List$$" ++ persistName (undefined :: a)
-  let valuesName = mainName ++ "$" ++ "values"
-  queryRawTyped ("SELECT value FROM " ++ valuesName ++ " WHERE id=? ORDER BY ord$") [dbType (undefined :: a)] [toPrim k] $ mapAllRows (fromPersistValue.head)
+  let mainName = "List" <> delim' <> delim' <> fromString (persistName (undefined :: a))
+  let valuesName = mainName <> delim' <> "values"
+  let value = ("value", dbType (undefined :: a))
+  let query = "SELECT " <> renderFields escapeS [value] <> " FROM " <> escapeS valuesName <> " WHERE id=? ORDER BY ord"
+  queryRawTyped query (getDbTypes (dbType (undefined :: a)) []) [toPrimitivePersistValue proxy k] $ mapAllRows (liftM fst . fromPersistValues)
     
-{-# SPECIALIZE getLastInsertRowId :: DbPersist Sqlite IO Int64 #-}
-getLastInsertRowId :: MonadIO m => DbPersist Sqlite m Int64
+{-# SPECIALIZE getLastInsertRowId :: DbPersist Sqlite IO PersistValue #-}
+getLastInsertRowId :: (MonadBaseControl IO m, MonadIO m) => DbPersist Sqlite m PersistValue
 getLastInsertRowId = do
   stmt <- getStatementCached "SELECT last_insert_rowid()"
   liftIO $ flip finally (liftIO $ S.reset stmt) $ do
     S.step stmt
     x <- S.column stmt 0
-    return $ fromPrim $ pFromSql x
-
-constrId :: String
-constrId = defId
+    return $ pFromSql x
 
 ----------
 
@@ -712,9 +394,10 @@
       PersistDay d           -> S.bindText stmt i $ show d
       PersistTimeOfDay d     -> S.bindText stmt i $ show d
       PersistUTCTime d       -> S.bindText stmt i $ show d
-    go (i+1) xs
+      PersistZonedTime (ZT d)-> S.bindText stmt i $ show d
+    go (i + 1) xs
 
-executeRaw' :: MonadIO m => String -> [PersistValue] -> DbPersist Sqlite m ()
+executeRaw' :: (MonadBaseControl IO m, MonadIO m) => Utf8 -> [PersistValue] -> DbPersist Sqlite m ()
 executeRaw' query vals = do
   stmt <- getStatement query
   liftIO $ flip finally (S.finalize stmt) $ do
@@ -722,8 +405,8 @@
     S.Done <- S.step stmt
     return ()
 
-{-# SPECIALIZE executeRawCached' :: String -> [PersistValue] -> DbPersist Sqlite IO () #-}
-executeRawCached' :: MonadIO m => String -> [PersistValue] -> DbPersist Sqlite m ()
+{-# SPECIALIZE executeRawCached' :: Utf8 -> [PersistValue] -> DbPersist Sqlite IO () #-}
+executeRawCached' :: (MonadBaseControl IO m, MonadIO m) => Utf8 -> [PersistValue] -> DbPersist Sqlite m ()
 executeRawCached' query vals = do
   stmt <- getStatementCached query
   liftIO $ flip finally (S.reset stmt) $ do
@@ -731,7 +414,7 @@
     S.Done <- S.step stmt
     return ()
 
-queryRaw' :: MonadControlIO m => String -> [PersistValue] -> (RowPopper (DbPersist Sqlite m) -> DbPersist Sqlite m a) -> DbPersist Sqlite m a
+queryRaw' :: (MonadBaseControl IO m, MonadIO m) => Utf8 -> [PersistValue] -> (RowPopper (DbPersist Sqlite m) -> DbPersist Sqlite m a) -> DbPersist Sqlite m a
 queryRaw' query vals f = do
   stmt <- getStatement query
   flip finally (liftIO $ S.finalize stmt) $ do
@@ -742,7 +425,7 @@
         S.Done -> return Nothing
         S.Row  -> liftM (Just . map pFromSql) $ S.columns stmt
 
-queryRawCached' :: MonadControlIO m => String -> [PersistValue] -> (RowPopper (DbPersist Sqlite m) -> DbPersist Sqlite m a) -> DbPersist Sqlite m a
+queryRawCached' :: (MonadBaseControl IO m, MonadIO m) => Utf8 -> [PersistValue] -> (RowPopper (DbPersist Sqlite m) -> DbPersist Sqlite m a) -> DbPersist Sqlite m a
 queryRawCached' query vals f = do
   stmt <- getStatementCached query
   flip finally (liftIO $ S.reset stmt) $ do
@@ -753,7 +436,7 @@
         S.Done -> return Nothing
         S.Row  -> fmap (Just . map pFromSql) $ S.columns stmt
 
-queryRawTyped :: MonadControlIO m => String -> [DbType] -> [PersistValue] -> (RowPopper (DbPersist Sqlite m) -> DbPersist Sqlite m a) -> DbPersist Sqlite m a
+queryRawTyped :: (MonadBaseControl IO m, MonadIO m) => Utf8 -> [DbType] -> [PersistValue] -> (RowPopper (DbPersist Sqlite m) -> DbPersist Sqlite m a) -> DbPersist Sqlite m a
 queryRawTyped query types vals f = do
   stmt <- getStatementCached query
   let types' = map typeToSqlite types
@@ -765,20 +448,6 @@
         S.Done -> return Nothing
         S.Row  -> fmap (Just . map pFromSql) $ S.unsafeColumns stmt types'
 
-queryEnum :: MonadControlIO m => String -> [DbType] -> [PersistValue] -> Enumerator [PersistValue] (DbPersist Sqlite m) b
-queryEnum query types vals = \step -> do
-  stmt <- lift $ getStatementCached query
-  liftIO $ S.reset stmt >> bind stmt vals
-  let iter = checkContinue0 $ \loop k -> do
-      x <- liftIO $ do
-        x <- S.step stmt
-        case x of
-          S.Done -> return Nothing
-          S.Row  -> do
-            fmap (Just . map pFromSql) $ S.unsafeColumns stmt (map typeToSqlite types)
-      maybe (continue k) (\row -> k (Chunks [row]) >>== loop) x
-  Iteratee (runIteratee (iter step))
-
 typeToSqlite :: DbType -> Maybe S.ColumnType
 typeToSqlite DbString = Just S.TextColumn
 typeToSqlite DbInt32 = Just S.IntegerColumn
@@ -788,21 +457,18 @@
 typeToSqlite DbDay = Nothing
 typeToSqlite DbTime = Nothing
 typeToSqlite DbDayTime = Nothing
+typeToSqlite DbDayTimeZoned = Nothing
 typeToSqlite DbBlob = Just S.BlobColumn
 typeToSqlite (DbMaybe _) = Nothing
-typeToSqlite (DbList _) = Just S.IntegerColumn
-typeToSqlite (DbTuple _ _) = Just S.IntegerColumn
-typeToSqlite (DbEntity _) = Just S.IntegerColumn
-
-getConstructorTypes :: ConstructorDef -> [DbType]
-getConstructorTypes = map (getType.snd) . constrParams
-
-firstRow :: Monad m => RowPopper m -> m (Maybe [PersistValue])
-firstRow pop = pop >>= return
+typeToSqlite (DbList _ _) = Just S.IntegerColumn
+typeToSqlite (DbEntity Nothing _) = Just S.IntegerColumn
+typeToSqlite t = error $ "typeToSqlite: DbType does not have corresponding database type: " ++ show t
 
-mapAllRows :: Monad m => ([PersistValue] -> m a) -> RowPopper m -> m [a]
-mapAllRows f pop = go where
-  go = pop >>= maybe (return []) (f >=> \a -> liftM (a:) go)
+getDbTypes :: DbType -> [DbType] -> [DbType]
+getDbTypes typ acc = case typ of
+  DbEmbedded (EmbeddedDef _ ts) -> foldr (getDbTypes . snd) acc ts
+  DbEntity (Just (EmbeddedDef _ ts, _)) _ -> foldr (getDbTypes . snd) acc ts
+  t               -> t:acc
 
 pFromSql :: S.SQLData -> PersistValue
 pFromSql (S.SQLInteger i) = PersistInt64 i
@@ -815,14 +481,89 @@
 escape :: String -> String
 escape s = '\"' : s ++ "\""
 
-renderCond' :: (PersistEntity v, Constructor c) => Cond v c -> RenderS
-renderCond' = renderCond escape constrId renderEquals renderNotEquals where
-  renderEquals :: (String -> String) -> Expr v c a -> Expr v c a -> RenderS
-  renderEquals esc a b = renderExpr esc a <> ((" IS " ++), id) <> renderExpr esc b
+escapeS :: Utf8 -> Utf8
+escapeS a = let q = fromChar '"' in q <> a <> q
 
-  renderNotEquals :: (String -> String) -> Expr v c a -> Expr v c a -> RenderS
-  renderNotEquals esc a b = renderExpr esc a <> ((" IS NOT " ++), id) <> renderExpr esc b
+renderCond' :: (PersistEntity v, Constructor c) => Cond v c -> Maybe (RenderS Utf8)
+renderCond' = renderCond proxy escapeS renderEquals renderNotEquals where
+  renderEquals a b = a <> " IS " <> b
+  renderNotEquals a b = a <> " IS NOT " <> b
 
-isSimple :: [ConstructorDef] -> Bool
-isSimple [_] = True
-isSimple _   = False
+defaultPriority :: Int
+defaultPriority = 0
+
+triggerPriority :: Int
+triggerPriority = 1
+
+proxy :: Proxy Sqlite
+proxy = error "Proxy Sqlite"
+
+delim' :: Utf8
+delim' = fromChar delim
+
+toEntityPersistValues' :: (MonadBaseControl IO m, MonadIO m, PersistEntity v) => v -> DbPersist Sqlite m [PersistValue]
+toEntityPersistValues' = liftM ($ []) . toEntityPersistValues
+
+compareColumns :: Column Affinity -> Column DbType -> Bool
+compareColumns (Column name1 isNull1 aff1 def1) (Column name2 isNull2 type2 def2) =
+  aff1 == dbTypeAffinity type2 && name1 == name2 && isNull1 == isNull2 && def1 == def2
+
+compareUniqs :: UniqueDef' -> UniqueDef' -> Bool
+compareUniqs (UniqueDef' _ cols1) (UniqueDef' _ cols2) = haveSameElems (==) cols1 cols2
+
+compareRefs :: (Maybe String, Reference) -> (Maybe String, Reference) -> Bool
+compareRefs (_, (tbl1, pairs1)) (_, (tbl2, pairs2)) = unescape tbl1 == unescape tbl2 && haveSameElems (==) pairs1 pairs2 where
+  unescape name = if head name == '"' && last name == '"' then tail $ init name else name
+
+mainTableId :: String
+mainTableId = "id"
+
+showAlterDb :: AlterDB Affinity -> SingleMigration
+showAlterDb (AddTable s) = Right [(False, defaultPriority, s)]
+showAlterDb (AlterTable table createTable (TableInfo oldId oldCols _ _) (TableInfo newId newCols _ _) alts) | not (all isSupported alts) = (Right
+  [ (False, defaultPriority, "CREATE TEMP TABLE " ++ escape tableTmp ++ "(" ++ columnsTmp ++ ")")
+  , (False, defaultPriority, copy (table, columnsTmp) (tableTmp, columnsTmp))
+  , (not (null oldOnlyColumns), defaultPriority, "DROP TABLE " ++ escape table)
+  , (False, defaultPriority, createTable)
+  , (False, defaultPriority, copy (tableTmp, columnsTmp) (table, columnsNew))
+  , (False, defaultPriority, "DROP TABLE " ++ escape tableTmp)
+  ]) where
+    tableTmp = table ++ "_backup"
+    copy (from, fromCols) (to, toCols) = "INSERT INTO " ++ escape to ++ "(" ++ toCols ++ ") SELECT " ++ fromCols ++ " FROM " ++ escape from
+    (oldOnlyColumns, _, commonColumns) = matchElements compareColumns oldCols newCols
+    columnsTmp = intercalate "," $ map escape $ maybeToList (newId >> oldId) ++ map (colName . snd) commonColumns
+    columnsNew = intercalate "," $ map escape $ maybeToList (oldId >> newId) ++ map (colName . snd) commonColumns
+    isSupported (AlterColumn (_, Add _)) = True
+    isSupported (AlterColumn (_, UpdateValue _)) = True
+    isSupported _ = False
+showAlterDb (AlterTable t _ _ _ alts) = Right $ map (showAlterTable t) alts
+showAlterDb (DropTrigger name _) = Right [(False, triggerPriority, "DROP TRIGGER " ++ escape name)]
+showAlterDb (AddTriggerOnDelete trigName tableName body) = Right [(False, triggerPriority,
+  "CREATE TRIGGER " ++ escape trigName ++ " DELETE ON " ++ escape tableName ++ " BEGIN " ++ body ++ "END")]
+showAlterDb (AddTriggerOnUpdate trigName tableName fieldName body) = Right [(False, triggerPriority,
+  "CREATE TRIGGER " ++ escape trigName ++ " UPDATE OF " ++ escape fieldName ++ " ON " ++ escape tableName ++ " BEGIN " ++ body ++ "END")]
+showAlterDb alt = error $ "showAlterDb: does not support " ++ show alt
+
+showAlterTable :: String -> AlterTable -> (Bool, Int, String)
+showAlterTable table (AlterColumn alt) = showAlterColumn table alt
+showAlterTable table alt = error $ "showAlterTable: does not support " ++ show alt ++ " (table " ++ table ++ ")"
+
+showAlterColumn :: String -> AlterColumn' -> (Bool, Int, String)
+showAlterColumn table (_, Add col) = (False, defaultPriority, concat
+    [ "ALTER TABLE "
+    , escape table
+    , " ADD COLUMN "
+    , showColumn col
+    ])
+showAlterColumn table (n, UpdateValue s) = (False, defaultPriority, concat
+    [ "UPDATE "
+    , escape table
+    , " SET "
+    , escape n
+    , "="
+    , s
+    , " WHERE "
+    , escape n
+    , " IS NULL"
+    ])
+showAlterColumn table alt = error $ "showAlterColumn: does not support " ++ show alt ++ " (table " ++ table ++ ")"
diff --git a/Database/Sqlite.hs b/Database/Sqlite.hs
--- a/Database/Sqlite.hs
+++ b/Database/Sqlite.hs
@@ -165,9 +165,9 @@
 
 foreign import ccall "sqlite3_prepare_v2"
   prepareC :: Ptr () -> CString -> Int -> Ptr (Ptr ()) -> Ptr (Ptr ()) -> IO Int
-prepareError :: Database -> String -> IO (Either Statement Error)
+prepareError :: Database -> BS.ByteString -> IO (Either Statement Error)
 prepareError db@(Database database) text = do
-  BS.useAsCString (UTF8.fromString text)
+  BS.useAsCString text
                   (\textC -> do
                      alloca (\statementC -> do
                                err <- prepareC database textC (-1) statementC nullPtr
@@ -176,7 +176,7 @@
                                    statement <- peek statementC
                                    return $ Left $ Statement statement db
                                  else return $ Right err))
-prepare :: Database -> String -> IO Statement
+prepare :: Database -> BS.ByteString -> IO Statement
 prepare database text = do
   statementOrError <- prepareError database text
   case statementOrError of
@@ -345,18 +345,10 @@
 typedColumn :: ColumnType -> Statement -> Int -> IO SQLData
 typedColumn theType statement columnIndex = do
   case theType of
-    IntegerColumn -> do
-                 int64 <- columnInt64 statement columnIndex
-                 return $ SQLInteger int64
-    FloatColumn -> do
-                 double <- columnDouble statement columnIndex
-                 return $ SQLFloat double
-    TextColumn -> do
-                 text <- columnText statement columnIndex
-                 return $ SQLText text
-    BlobColumn -> do
-                 byteString <- columnBlob statement columnIndex
-                 return $ SQLBlob byteString
+    IntegerColumn -> fmap SQLInteger $ columnInt64 statement columnIndex
+    FloatColumn -> fmap SQLFloat $ columnDouble statement columnIndex
+    TextColumn -> fmap SQLText $ columnText statement columnIndex
+    BlobColumn -> fmap SQLBlob $ columnBlob statement columnIndex
     NullColumn -> return SQLNull
 
 columns :: Statement -> IO [SQLData]
@@ -367,8 +359,10 @@
 unsafeColumns :: Statement -> [Maybe ColumnType] -> IO [SQLData]
 unsafeColumns statement types = go 0 types where
   go :: Int -> [Maybe ColumnType] -> IO [SQLData]
-  go _ [] = return []
+  go n [] = n `seq` return []
   go n (t:ts) = do
-    c <- (maybe column typedColumn t) statement n
+    c <- case t of
+      Nothing -> column statement n
+      Just t' -> typedColumn t' statement n
     cs <- go (n + 1) ts
     return (c:cs)
diff --git a/cbits/sqlite3.c b/cbits/sqlite3.c
# file too large to diff: cbits/sqlite3.c
diff --git a/groundhog-sqlite.cabal b/groundhog-sqlite.cabal
--- a/groundhog-sqlite.cabal
+++ b/groundhog-sqlite.cabal
@@ -1,14 +1,14 @@
 name:            groundhog-sqlite
-version:         0.0.1.1
+version:         0.1.0
 license:         BSD3
 license-file:    LICENSE
 author:          Boris Lykah <lykahb@gmail.com>
 maintainer:      Boris Lykah <lykahb@gmail.com>
-synopsis:        Backend for the groundhog library using sqlite3.
+synopsis:        Sqlite3 backend for the groundhog library
 description:     This package includes a thin sqlite3 wrapper based on the direct-sqlite package, as well as the entire C library, so there are no system dependencies.
 category:        Database
 stability:       Non-stable
-cabal-version:   >= 1.10
+cabal-version:   >= 1.6
 build-type:      Simple
 
 flag systemlib
@@ -18,18 +18,23 @@
 library
     build-depends:   base                    >= 4         && < 5
                    , bytestring              >= 0.9.1     && < 0.10
-                   , transformers            >= 0.2.1     && < 0.3
-                   , groundhog               >= 0.0.1     && < 0.1
-                   , monad-control           >= 0.2       && < 0.3
+                   , transformers            >= 0.2.1     && < 0.4
+                   , groundhog               >= 0.1.0     && < 0.2.0
+                   , monad-control           >= 0.3       && < 0.4
                    , containers              >= 0.2       && < 0.5
-                   , enumerator              >= 0.4.9     && < 0.5
                    , utf8-string             >= 0.3.4     && < 0.4
-                   , pool                    >= 0.1       && < 0.2
+                   , blaze-builder           >= 0.3.0.0   && < 0.4
+                   , pool-conduit            >= 0.1       && < 0.2
+                   , unordered-containers
     exposed-modules: Database.Sqlite
                      Database.Groundhog.Sqlite
+    other-modules:   Database.Groundhog.Generic.Sql.Utf8
     ghc-options:     -Wall -fno-warn-unused-do-bind
     if flag(systemlib)
         extra-libraries: sqlite3
     else
         c-sources:   cbits/sqlite3.c
-    default-language: Haskell2010
+
+source-repository head
+  type:     git
+  location: git://github.com/lykahb/groundhog.git
