diff --git a/Database/MySQL/Simple/Quasi.hs b/Database/MySQL/Simple/Quasi.hs
new file mode 100644
--- /dev/null
+++ b/Database/MySQL/Simple/Quasi.hs
@@ -0,0 +1,401 @@
+{-# LANGUAGE GADTs, QuasiQuotes, TemplateHaskell #-}
+{-# OPTIONS_GHC -Wall #-}
+
+module Database.MySQL.Simple.Quasi (
+-- * Motivation
+-- | So, you want to access a MySQL database from Haskell.
+-- In an ideal world, your database schema would be known in its entirety to the compiler,
+-- and your MySQL queries would be fully parsed at compile-time and type-checked.
+--
+-- In reality, constructing a full parser for a MySQL query is a huge job,
+-- as is creating an EDSL for MySQL queries.  But, still, the mysql-simple package by itself is a little
+-- too type-unsafe.  For example, there's nothing stopping you writing this:
+--
+-- > (a, b) <- query conn "select a, b, c from table where id = ? and name = ?" (True, "x", 7)
+--
+-- That is: there's no guarantee that the number of params or results in the query matches
+-- the number you try to pass in\/receive out of the @query@ call.  Additionally, there's no
+-- type checking on the inputs or outputs to the query.
+
+-- * Description
+-- | This module provides a quasi-quoter that is a half-way house between mysql-simple and
+-- a full-on database library/EDSL.  You write your queries as a quasi-quote, and provide
+-- type annotations /in the query itself/.  So for the previous example you would instead write:
+--
+-- > (a, b) <- query [qquery|select a{Int}, b{Bool}, c{Maybe String} from table where id = ?{Int} and name = ?{String}"|] (True, "x", 7)
+--
+-- You would then receive two type errors.  One that your tuple @(a, b)@ does not match @(Int, Bool, Maybe String)@,
+-- and the other that @(True, \"x\", 7)@ does not match @(Int, String)@.
+--
+-- So, using the 'qquery' quasi-quoter gives the following benefits:
+--
+--   * It types the query with the annotated return type (and if any @?@ are used, the param types).
+-- 
+--   * It automatically chooses to use @QQuery@ or @QQuery_@ based on whether there are @?@ present.
+-- 
+--   * It automatically wraps/unwraps @Only@ types that mysql-simple uses to disambiguate its instances (but introduces no amibiguity).
+-- 
+--   * It prevents splicing together strings to make a query.  You must provide the entire query in one literal, and use
+--   wildcards to adjust any values.  (I think this is a benefit, right?  Enforced discipline.)
+--
+-- One technique that I find useful to combine with this quasi-quoter is typing integer keys differently.
+-- For example, let's say that you have two tables, @\"users\"@ and @\"locations\"@, each with an @\"id\"@ field.  You want
+-- an inner join of these tables where the @\"id\"@s are less than a given amount.  If you use say, @Int32@, you can
+-- easily get confused, even with this quasi-quoter:
+--
+-- > (loc, user) {- mistake -} <- [qquery|select users.id{Int32}, locations.id{Int32}
+-- >   from users inner join locations
+-- >   where users.location_type = locations.type and users.id < ?{Int32} and locations.id < ?{Int32}|]
+-- >     (locIdThreshold, userIdThreshold) {- mistake -}
+--
+-- If instead you type them differently (with the appropriate instances), you will get two errors when doing this:
+--
+-- > newtype UserId = UserId Int
+-- > newtype LocationId = LocationId Int
+--
+-- > (loc, user) {- mistake -} <- [qquery|select users.id{UserId}, locations.id{LocationId}
+-- >   from users inner join locations
+-- >   where users.location_type = locations.type and users.id < ?{UserId} and locations.id < ?{LocationId}|]
+-- >     (locIdThreshold, userIdThreshold) {- mistake -}
+
+-- * Quasi-Quoters
+  qquery, qexec,
+-- * Query Types
+  QQuery, QQuery_, QExecute, QExecute_,
+-- * Running queries
+  execute, execute_, executeMany, fold, fold_, forEach, forEach_, query, query_,
+-- * Internal access
+  QExtractable(extractQuery)) where
+
+import Control.Applicative ((<$>))
+import Control.Monad (when)
+import Data.Int (Int64)
+import Data.String (fromString)
+
+import Database.MySQL.Simple (Connection, Only(..))
+import qualified Database.MySQL.Simple as Orig (Query, execute, execute_, executeMany, fold, fold_, forEach, forEach_, query, query_)
+import Database.MySQL.Simple.Param (Param)
+import Database.MySQL.Simple.QueryParams (QueryParams)
+import Database.MySQL.Simple.QueryResults (QueryResults)
+
+import Language.Haskell.TH.Syntax (Q, Exp(AppE, ConE, LitE, SigE, TupE, VarE), Lit(StringL), Name,
+  Pred(ClassP), Type(AppT, ConT, ForallT, TupleT, VarT), TyVarBndr(PlainTV), mkName)
+import Language.Haskell.TH.Quote (QuasiQuoter(..))
+
+import Language.Haskell.Meta.Parse (parseType)
+
+-- | A select-like query that takes `q` as its parameters and returns a list of `r` as its results.
+data QQuery q r where
+  QQuery :: (QueryParams q', QueryResults r') => (q -> q') -> (r' -> r) -> (String, Orig.Query) -> QQuery q r
+
+-- | A select-like query that has no parameters, and returns a list of `r` as its results.
+data QQuery_ r where
+  QQuery_ :: QueryResults r' => (r' -> r) -> (String, Orig.Query) -> QQuery_ r
+
+-- | An execute-like query that takes `q` as its parameters.
+data QExecute q where
+  QExecute :: QueryParams q' => (q -> q') -> (String, Orig.Query) -> QExecute q
+
+-- | An execute-like query that has no parameters.  There's very little gain in using
+-- this over using `Database.MySQL.Simple.execute_` from mysql-simple directly, but it's provided for completeness.
+data QExecute_ where
+  QExecute_ :: (String, Orig.Query) -> QExecute_
+
+class QExtractable q where
+  -- | Extracts the query.  This loses all the type safety
+  -- of the original query and the whole point of using the library,
+  -- but presumably you know what you're doing.
+  extractQuery :: q -> String
+
+instance QExtractable (QQuery q r) where extractQuery (QQuery _ _ q) = fst q
+
+instance QExtractable (QQuery_ r) where extractQuery (QQuery_ _ q) = fst q
+
+instance QExtractable (QExecute q) where extractQuery (QExecute _ q) = fst q
+
+instance QExtractable QExecute_ where extractQuery (QExecute_ q) = fst q
+
+-- | A wrapper
+-- for mysql-simple's 'Database.MySQL.Simple.query' function.
+--
+-- Note that no instances are required for @q@ or @r@ because the 'QQuery' type
+-- witnesses them at its construction.
+query :: Connection -> QQuery q r -> q -> IO [r]
+query conn (QQuery qf rf (_, s)) = fmap (map rf) . Orig.query conn s . qf
+
+-- | A wrapper
+-- for mysql-simple's 'Database.MySQL.Simple.query_' function.
+--
+-- Note that no instances are required for @r@ because the 'QQuery_' type
+-- witnesses them at its construction.
+query_ :: Connection -> QQuery_ r -> IO [r]
+query_ conn (QQuery_ rf (_, s)) = fmap (map rf) $ Orig.query_ conn s
+
+-- | A wrapper
+-- for mysql-simple's 'Database.MySQL.Simple.fold' function.
+--
+-- Note that no instances are required for @q@ or @r@ because the 'QQuery' type
+-- witnesses them at its construction.
+fold :: Connection -> QQuery q r -> q -> a -> (a -> r -> IO a) -> IO a
+fold conn (QQuery qf rf (_, s)) q x f = Orig.fold conn s (qf q) x (\y r -> f y (rf r))
+
+-- | A wrapper
+-- for mysql-simple's 'Database.MySQL.Simple.fold_' function.
+--
+-- Note that no instances are required for @r@ because the 'QQuery_' type
+-- witnesses them at its construction.
+fold_ :: Connection -> QQuery_ r -> a -> (a -> r -> IO a) -> IO a
+fold_ conn (QQuery_ rf (_, s)) x f = Orig.fold_ conn s x (\y r -> f y (rf r))
+
+-- | A wrapper
+-- for mysql-simple's 'Database.MySQL.Simple.forEach' function.
+--
+-- Note that no instances are required for @q@ or @r@ because the 'QQuery' type
+-- witnesses them at its construction.
+forEach :: Connection -> QQuery q r -> q -> (r -> IO ()) -> IO ()
+forEach conn (QQuery qf rf (_, s)) q f = Orig.forEach conn s (qf q) (f . rf)
+
+-- | A wrapper
+-- for mysql-simple's 'Database.MySQL.Simple.forEach_' function.
+--
+-- Note that no instances are required for @r@ because the 'QQuery_' type
+-- witnesses them at its construction.
+forEach_ :: Connection -> QQuery_ r -> (r -> IO ()) -> IO ()
+forEach_ conn (QQuery_ rf (_, s)) f = Orig.forEach_ conn s (f . rf)
+
+-- | A wrapper
+-- for mysql-simple's 'Database.MySQL.Simple.execute' function.
+--
+-- Note that no instances are required for @q@ because the 'QExecute' type
+-- witnesses them at its construction.
+execute :: Connection -> QExecute q -> q -> IO Int64
+execute conn (QExecute qf (_, s)) = Orig.execute conn s . qf
+
+-- | A wrapper
+-- for mysql-simple's 'Database.MySQL.Simple.execute_' function.
+execute_ :: Connection -> QExecute_ -> IO Int64
+execute_ conn (QExecute_ (_, s)) = Orig.execute_ conn s
+
+-- | A wrapper
+-- for mysql-simple's 'Database.MySQL.Simple.executeMany' function.
+--
+-- Note that no instances are required for @q@ because the 'QExecute' type
+-- witnesses them at its construction.
+executeMany :: Connection -> QExecute q -> [q] -> IO Int64
+executeMany conn (QExecute qf (_, s)) = Orig.executeMany conn s . map qf
+
+-- | A quasi-quoter that takes the param and result types from the query
+-- string and generates a typed query.  For example:
+--
+-- > [qquery|select * from users|]
+--
+-- will turn into an expression of type @QueryResults r => QQuery_ r@.
+-- This is not particularly useful.  However, this:
+--
+-- > [qquery|select id{Int32}, name{String} from users|]
+-- 
+-- becomes @QQuery_ (Int32, String)@.
+--
+-- Furthermore, this:
+--
+-- > [qquery|select id{Int32} from users where name = ?{String}|]
+--
+-- becomes: @QQuery String Int32@.  And this:
+--
+-- > [qquery| select a.*{Int, Maybe String, String}, b.value{Double}
+-- >            from a inner join b on a.id = b.id
+-- >            where a.name = ?{String} and b.num = ?{Int}|]
+--
+-- becomes: @QQuery (String, Int) (Int, Maybe String, String, Double)@.
+--
+-- In general:
+-- 
+-- * Any non-escaped question mark in the String is taken to be one
+--   substitution.  It is given type @QueryParam a => a@ unless it is
+--   followed immediately (no spaces) by curly brackets with a type in it,
+--   in which case it uses that type.
+-- 
+-- * A question mark preceded by a backslash is turned into a single question mark.
+-- 
+-- * To insert an actual backslash, use double backslash.
+-- 
+-- * Any other instances of curly brackets in the String are taken to
+--   be a comma-separated list of result types, which are all tupled
+--   (in the order they appear in the String) into a single result type.
+--   To get a literal curly bracket, put a backslash before it.
+-- 
+-- * If there is only a single substitution or single result, @Only@ is automatically added/removed
+--   when passing it through to the mysql-simple library.
+-- 
+-- * If there is no @?@ substitution in the query, the resulting type is @QQuery_ r@.  If there are
+--   substitutions, the resulting type is @QQuery q r@.
+qquery :: QuasiQuoter
+qquery = qqExp "qquery" qqueryExp
+
+-- | Same as `qquery`, except that it produces a query of type QExecute/QExecute_
+-- instead of QQuery/QQuery_, and it gives an error if there are any result annotations
+-- (since executes don't return any results).
+qexec :: QuasiQuoter
+qexec = qqExp "qexec" qexecExp
+
+qqExp :: String -> (String -> Q Exp) -> QuasiQuoter
+qqExp name qq = QuasiQuoter {quoteExp = qq, quotePat = err, quoteType = err, quoteDec = err}
+  where
+    err :: String -> Q a
+    err _ = fail $ name ++ " quasi-quoter only valid in expression"
+
+emptyToNothing :: [a] -> [Maybe a]
+emptyToNothing [] = [Nothing]
+emptyToNothing xs = map Just xs
+
+qqueryExp :: String -> Q Exp
+qqueryExp input = do
+  processed <- either fail return $ parse input
+  let result = tuple QResult $ emptyToNothing $ returnTypes processed
+      param = tuple QParam $ paramTypes processed
+      noParams = null (paramTypes processed)
+  return $
+   SigE
+    ((if noParams
+        then ConE 'QQuery_ `AppE` wrapUnwrap result
+        else (ConE 'QQuery `AppE` wrapUnwrap param) `AppE` wrapUnwrap result)
+      `AppE` mkQuery (stripped processed))
+    (makeContext (typeContext param ++ typeContext result) $
+       if noParams
+         then ConT ''QQuery_ `AppT` qtype result
+         else (ConT ''QQuery `AppT` qtype param) `AppT` qtype result)
+  -- Result looks like these:
+  -- (QQuery_ id "select ...") :: QQuery_ (Int, String)
+  -- (QQuery_ fromOnly "select ...") :: QQuery_ Int
+  -- (QQuery_ id "select ...") :: (QueryResults a => QQuery_ a)
+  -- (QQuery fromOnly Only "select ...") :: QQuery Int String
+  -- (QQuery id Only "select ...") :: QQuery Int (String, String)
+  -- (QQuery id id "select ...") :: QQuery (Int, Int) (Bool, String)
+  -- (QQuery id id "select ...") :: (QueryResults a, QueryParam b) => (QQuery b a))
+
+-- | A version of qqueryExp, above, that allows no return types:
+qexecExp :: String -> Q Exp
+qexecExp input = do
+    processed <- either fail return $ parse input
+    when (not . null $ returnTypes processed) $
+      fail "Found return annotations in qexec query"
+    let param = tuple QParam $ paramTypes processed
+        noParams = null $ paramTypes processed
+    return $
+      SigE
+        ((if noParams
+            then ConE 'QExecute_
+            else ConE 'QExecute `AppE` wrapUnwrap param)
+         `AppE` mkQuery (stripped processed))
+        (if noParams
+           then ConT ''QExecute_
+           else makeContext (typeContext param) $ ConT ''QExecute `AppT` qtype param)
+
+mkQuery :: String -> Exp
+mkQuery s = TupE [litS, VarE 'fromString `AppE` litS]
+  where
+    litS = LitE (StringL s)
+
+data QResultOrParam = QResult | QParam
+
+data QType = QT {
+  -- | The expression needed to wrap/unwrap a type
+  -- (Needed to add/remove the Only wrapper on single types)
+  wrapUnwrap :: Exp,
+  -- | Required context: class name, var name
+  typeContext :: [(Name, Name)],
+  -- | The actual type (may be a single type or a tuple):
+  qtype :: Type }
+
+-- | Takes a list of types and turns them 
+tuple :: QResultOrParam -> [Maybe Type] -> QType
+tuple rp mts = QT {wrapUnwrap = w, typeContext = ctxt, qtype = case subst (map VarT vars) mts of
+  [t] -> t
+  ts -> foldl AppT (TupleT (length ts)) ts}
+  where
+    w = case (mts, rp) of
+          ([Just _], QResult) -> VarE 'fromOnly
+          ([_], QParam) -> ConE 'Only
+          _ -> VarE 'id
+    (c, clz) = case rp of
+                 QResult -> ('r', ''QueryResults)
+                 QParam -> ('q', ''Param)
+
+    ctxt = zip (repeat clz) vars
+    vars = take (countNothings mts) [mkName $ c : suffix | suffix <- "" : map show [(1::Int)..]]
+
+makeContext :: [(Name, Name)] -> (Type -> Type)
+makeContext [] = id
+makeContext classVars
+  = ForallT (map (PlainTV . snd) classVars)
+            [ClassP cls [VarT var] | (cls, var) <- classVars]
+
+countNothings :: [Maybe a] -> Int
+countNothings xs = length [() | Nothing <- xs]
+
+subst :: [a] -> [Maybe a] -> [a]
+subst _ [] = []
+subst (s:ss) (Nothing:xs) = s : subst ss xs
+subst [] (Nothing : _) = error "Internal error: not enough types to substitue"
+subst ss (Just x : xs) = x : subst ss xs
+
+(<:>) :: Functor m => Char -> m ProcessedQuery -> m ProcessedQuery
+(<:>) c = fmap (\p -> p { stripped = c : stripped p })
+
+toCloseCurly :: String -> Either String (String, String)
+toCloseCurly src = case span (/= '}') src of
+  (before, '}':after) -> return (before, after)
+  _ -> Left $ "Unclosed '{' in remainder of expression: " ++ src
+
+data ProcessedQuery = PQ { returnTypes :: [Type], paramTypes :: [Maybe Type], stripped :: String }
+
+-- | Parses a String looking for various annotations. Gives back either an error,
+-- or the query string with the annotations removed and processed into lists of types.
+parse :: String -> Either String ProcessedQuery
+-- Double backslash becomes single backslash:
+parse ('\\':'\\':rest) = '\\' <:> parse rest
+-- Backslashed question mark or curly bracket makes it literal:
+parse ('\\':'{':rest) = '{' <:> parse rest
+parse ('\\':'?':rest) = '?' <:> parse rest
+-- Question mark then curly bracket is a param type:
+parse ('?':'{':rest) = '?' <:> do
+  (before, after) <- toCloseCurly rest
+  types <- parseTypes before
+  remainder <- parse after
+  case types of
+    [single] -> return $ remainder { paramTypes = Just single : paramTypes remainder }
+    _ -> fail $ "Multiple types given for substitution: " ++ before
+-- Any other curly bracket is a return type:
+parse ('{':rest) = do
+  (before, after) <- toCloseCurly rest
+  types <- parseTypes before
+  remainder <- parse after
+  return $ remainder { returnTypes = types ++ returnTypes remainder }
+parse ('?':rest) = '?' <:> do
+  remainder <- parse rest
+  return $ remainder { paramTypes = Nothing : paramTypes remainder }
+parse (c:cs) = c <:> parse cs
+parse "" = return $ PQ [] [] ""
+
+-- | Takes a comma-separated list of types and parses them.
+parseTypes :: String -> Either String [Type]
+-- Slight hack; make sure a single type parses as a tuple too, by adding another type
+-- so that it's at least size 2:
+parseTypes s = case flattenAppT <$> parseType ("( ()," ++ s ++ ")") of
+  Right (TupleT n : _ : xs) | n == 1 + length xs -> Right xs
+  Left e -> Left e
+  Right t -> Left $ "Bad type: " ++ show t
+
+-- | Takes a type that is a series of nested applications and flattens it into a list.
+-- For example, the type (Int, String, Bool) is really (,,) Int String Bool,
+-- which is represented in an AST as:
+-- ((( (,,) `AppT` Int) `AppT` String) `AppT` Bool)
+-- or rather:
+-- AppT (AppT (AppT (,,) Int) String) Bool
+--
+-- This function takes something like that and turns it into:
+--
+-- [(,,), Int, String, Bool]
+flattenAppT :: Type -> [Type]
+flattenAppT (AppT f t) = flattenAppT f ++ [t]
+flattenAppT t = [t]
diff --git a/Database/MySQL/Simple/Quasi/Test.hs b/Database/MySQL/Simple/Quasi/Test.hs
new file mode 100644
--- /dev/null
+++ b/Database/MySQL/Simple/Quasi/Test.hs
@@ -0,0 +1,100 @@
+{-# OPTIONS_GHC -Wall -fno-warn-missing-signatures #-}
+--module Database.MySQL.Simple.QQ.Test where
+
+import Control.Applicative ((<$>))
+import System.Exit (ExitCode(..), exitWith)
+
+import Data.Generics (everywhere, mkT)
+import Data.Generics.Text (gshow)
+import Data.List (isPrefixOf)
+
+import Database.MySQL.Simple.Quasi
+
+import Language.Haskell.TH (runQ)
+import Language.Haskell.TH.Ppr (pprint)
+import Language.Haskell.TH.Quote (quoteExp)
+import qualified Language.Haskell.TH.Syntax as TH
+import Language.Haskell.Meta.Parse (parseExp)
+
+qual :: [(String, String)] -> String -> String
+qual prefixTgts = go prefixTgts
+  where
+    go _ [] = []
+    go ((prefix, tgt):more) src
+      | tgt `isPrefixOf` src = prefix ++ tgt ++ go prefixTgts (drop (length tgt) src)
+      | otherwise = go more src
+    go [] (c:cs) = c : go prefixTgts cs
+
+
+collapseForall :: TH.Exp -> TH.Exp
+collapseForall (TH.SigE e t) = TH.SigE e $ collapseForallT t
+  where
+    collapseForallT (TH.ForallT ts [] (TH.ForallT [] ctxt inner)) = TH.ForallT ts ctxt inner
+    collapseForallT x = x
+collapseForall e = e
+
+-- | Code from qquery uses NameG but haskell-src-meta uses NameQ.
+-- This hack turns all NameG into NameQ ready for comparison:
+canonName :: TH.Name -> TH.Name
+canonName = TH.mkName . show 
+
+unqualName :: TH.Name -> TH.Name
+unqualName = TH.mkName . TH.nameBase
+
+asCode :: TH.Exp -> String
+asCode = pprint . everywhere (mkT unqualName)
+
+dupeQueries :: String -> String
+dupeQueries ('$':'\"':rest)
+  = let (queryStr, '\"':more) = span (/= '\"') rest
+    in "(\"" ++ queryStr ++ "\", Data.String.fromString \"" ++ queryStr ++ "\")" ++ dupeQueries more
+dupeQueries (c:cs) = c : dupeQueries cs
+dupeQueries [] = []
+
+(==>) :: String -> String -> IO Bool
+(==>) src expS = do
+  act <- everywhere (mkT canonName) <$> runQ (quoteExp qquery src)
+  let expS' = qual [("Database.MySQL.Simple.QQ.", "QQuery") -- Handles QQuery_ too
+                   ,("Database.MySQL.Simple.QueryResults.", "QueryResults")
+                   ,("Database.MySQL.Simple.Param.", "Param")
+                   ,("Database.MySQL.Simple.Types.", "fromOnly") -- Try fromOnly before Only
+                   ,("Database.MySQL.Simple.Types.", "Only")
+                   ] . dupeQueries $ expS
+  case collapseForall <$> parseExp expS' of
+    Left e -> do putStrLn $ "Problem parsing expected output: " ++ e
+                 return False
+    Right x | x == act -> return True
+            | otherwise -> do mapM_ putStrLn
+                                [ "Mismatch. Expected:", "  " ++ asCode x, "  " ++ gshow x
+                                , "Actual:", "  " ++ asCode act, "  " ++ gshow act]
+                              return False
+
+simple = "select * from users" ==> "QQuery_ GHC.Base.id $\"select * from users\" :: forall r. QueryResults r => QQuery_ r"
+
+ret1 = "select id{Int} from users" ==> "QQuery_ fromOnly $\"select id from users\" :: QQuery_ Int" 
+
+ret2 = "select id{Int}, name{String} from users" ==> "QQuery_ GHC.Base.id $\"select id, name from users\" :: QQuery_ (Int, String)"
+
+ret4 = "select id{Int}, f.*{String, Bool}, name{Double} from users, f" ==>
+       "QQuery_ GHC.Base.id $\"select id, f.*, name from users, f\" :: QQuery_ (Int, String, Bool, Double)"
+
+subst1 = "select * from users where name = ?{String}" ==>
+         "QQuery Only GHC.Base.id $\"select * from users where name = ?\" :: forall r. QueryResults r => QQuery String r"
+
+subst1b = "select * from users where name = ?" ==>
+          "QQuery Only GHC.Base.id $\"select * from users where name = ?\" :: forall q r. (Param q, QueryResults r) => QQuery q r"
+
+subst3 = "select id{Maybe Int} from users where name = ?{Int} and name2 = ?{Bool} and name3 = ?{Maybe Double}" ==>
+          "QQuery GHC.Base.id fromOnly $\"select id from users where name = ? and name2 = ? and name3 = ?\" :: QQuery (Int, Bool, Maybe Double) (Maybe Int)"
+
+subst3b = "select * from users where name = ? and name2 = ? and name3 = ?" ==>
+          "QQuery GHC.Base.id GHC.Base.id $\"select * from users where name = ? and name2 = ? and name3 = ?\" :: forall q q1 q2 r. (Param q, Param q1, Param q2, QueryResults r) => QQuery (q, q1, q2) r"
+
+
+escaped = "select \\{curled} from whatever where text = 'hello\\?'" ==>
+          "QQuery_ GHC.Base.id $\"select {curled} from whatever where text = 'hello?'\" :: forall r. QueryResults r => QQuery_ r"
+
+main :: IO ()
+main = do passed <- and <$> sequence [simple, ret1, ret2, ret4, escaped, subst1, subst1b,
+            subst3, subst3b]
+          exitWith $ if passed then ExitSuccess else ExitFailure 1
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,31 @@
+mysql-simple-quasi library
+Copyright (c) 2013, Neil Brown
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Neil Brown nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/mysql-simple-quasi.cabal b/mysql-simple-quasi.cabal
new file mode 100644
--- /dev/null
+++ b/mysql-simple-quasi.cabal
@@ -0,0 +1,27 @@
+-- Initial mysql-simple-qq.cabal generated by cabal init.  For further 
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+name:                mysql-simple-quasi
+version:             1.0.0.0
+synopsis:            Quasi-quoter for use with mysql-simple.
+description:         See the "Database.MySQL.Simple.Quasi" module documentation for more details.
+license:             BSD3
+license-file:        LICENSE
+author:              Neil Brown
+maintainer:          neil@twistedsquare.com
+-- copyright:           
+category:            Database
+build-type:          Simple
+cabal-version:       >=1.8
+
+library
+  exposed-modules:     Database.MySQL.Simple.Quasi
+  build-depends:       base == 4.*,
+                       haskell-src-meta, 
+                       mysql-simple == 0.2.*,
+                       template-haskell
+
+Test-Suite test-qq
+    type:              exitcode-stdio-1.0
+    main-is:           Database/MySQL/Simple/Quasi/Test.hs
+    build-depends:     base, Cabal >= 1.18, haskell-src-meta, mysql-simple == 0.2.*, syb, template-haskell
