1
Fork 0
simple-sql-parser/Language/SQL/SimpleSQL/Pretty.lhs

844 lines
28 KiB
Plaintext
Raw Normal View History

2013-12-13 11:39:26 +01:00
2013-12-14 15:58:35 +01:00
> -- | These is the pretty printing functions, which produce SQL
> -- source from ASTs. The code attempts to format the output in a
> -- readable way.
2013-12-13 15:04:48 +01:00
> module Language.SQL.SimpleSQL.Pretty
> (prettyQueryExpr
2016-02-22 22:24:25 +01:00
> ,prettyScalarExpr
> ,prettyStatement
> ,prettyStatements
2013-12-13 15:04:48 +01:00
> ) where
2013-12-13 11:39:26 +01:00
2018-07-11 22:37:18 +02:00
> import Prelude hiding ((<>))
2013-12-31 11:20:07 +01:00
TODO: there should be more comments in this file, especially the bits
which have been changed to try to improve the layout of the output.
Try to do this when this code is ported to a modern pretty printing lib.
2013-12-31 11:20:07 +01:00
> --import Language.SQL.SimpleSQL.Dialect
> import Text.PrettyPrint (render, vcat, text, (<>), (<+>), empty, parens,
> nest, Doc, punctuate, comma, sep, quotes,
> brackets,hcat)
> import Data.Maybe (maybeToList, catMaybes)
> import Data.List (intercalate)
2013-12-13 11:39:26 +01:00
> import Language.SQL.SimpleSQL.Syntax
> import Language.SQL.SimpleSQL.Dialect
> -- | Convert a query expr ast to concrete syntax.
2014-06-27 11:19:15 +02:00
> prettyQueryExpr :: Dialect -> QueryExpr -> String
> prettyQueryExpr d = render . queryExpr d
2013-12-13 11:39:26 +01:00
> -- | Convert a value expr ast to concrete syntax.
2016-02-22 22:24:25 +01:00
> prettyScalarExpr :: Dialect -> ScalarExpr -> String
> prettyScalarExpr d = render . scalarExpr d
2020-12-20 16:03:15 +01:00
> -- | A terminating semicolon.
> terminator :: Doc
> terminator = text ";\n"
> -- | Convert a statement ast to concrete syntax.
> prettyStatement :: Dialect -> Statement -> String
2020-12-20 16:03:15 +01:00
> prettyStatement _ EmptyStatement = render terminator
> prettyStatement d s = render (statement d s)
2016-02-22 22:16:36 +01:00
> -- | Convert a list of statements to concrete syntax. A semicolon
> -- is inserted after each statement.
> prettyStatements :: Dialect -> [Statement] -> String
2020-12-20 16:03:15 +01:00
> prettyStatements d = render . vcat . map prettyStatementWithSemicolon
> where
> prettyStatementWithSemicolon :: Statement -> Doc
> prettyStatementWithSemicolon s = statement d s <> terminator
2016-02-22 22:24:25 +01:00
= scalar expressions
2016-02-22 22:24:25 +01:00
> scalarExpr :: Dialect -> ScalarExpr -> Doc
> scalarExpr _ (StringLit s e t) = text s <> text t <> text e
2013-12-17 14:09:28 +01:00
2016-02-22 22:24:25 +01:00
> scalarExpr _ (NumLit s) = text s
> scalarExpr _ (IntervalLit s v f t) =
2014-04-18 20:38:24 +02:00
> text "interval"
> <+> me (\x -> text $ case x of
> Plus -> "+"
> Minus -> "-") s
2014-04-18 20:38:24 +02:00
> <+> quotes (text v)
> <+> intervalTypeField f
> <+> me (\x -> text "to" <+> intervalTypeField x) t
2016-02-22 22:24:25 +01:00
> scalarExpr _ (Iden i) = names i
> scalarExpr _ Star = text "*"
> scalarExpr _ Parameter = text "?"
> scalarExpr _ (PositionalArg n) = text $ "$" ++ show n
> scalarExpr _ (HostParameter p i) =
> text p
> <+> me (\i' -> text "indicator" <+> text i') i
2016-02-22 22:24:25 +01:00
> scalarExpr d (App f es) = names f <> parens (commaSep (map (scalarExpr d) es))
2013-12-13 20:13:36 +01:00
2016-02-22 22:24:25 +01:00
> scalarExpr dia (AggregateApp f d es od fil) =
> names f
> <> parens ((case d of
> Distinct -> text "distinct"
> All -> text "all"
> SQDefault -> empty)
2016-02-22 22:24:25 +01:00
> <+> commaSep (map (scalarExpr dia) es)
> <+> orderBy dia od)
2014-04-19 17:01:49 +02:00
> <+> me (\x -> text "filter"
2016-02-22 22:24:25 +01:00
> <+> parens (text "where" <+> scalarExpr dia x)) fil
2014-04-19 17:01:49 +02:00
2016-02-22 22:24:25 +01:00
> scalarExpr d (AggregateAppGroup f es od) =
2014-04-19 17:01:49 +02:00
> names f
2016-02-22 22:24:25 +01:00
> <> parens (commaSep (map (scalarExpr d) es))
2014-04-19 17:01:49 +02:00
> <+> if null od
> then empty
> else text "within group" <+> parens (orderBy d od)
2016-02-22 22:24:25 +01:00
> scalarExpr d (WindowApp f es pb od fr) =
> names f <> parens (commaSep $ map (scalarExpr d) es)
2013-12-13 22:31:36 +01:00
> <+> text "over"
> <+> parens ((case pb of
> [] -> empty
> _ -> text "partition by"
2016-02-22 22:24:25 +01:00
> <+> nest 13 (commaSep $ map (scalarExpr d) pb))
> <+> orderBy d od
> <+> me frd fr)
> where
> frd (FrameFrom rs fp) = rsd rs <+> fpd fp
> frd (FrameBetween rs fps fpe) =
> rsd rs <+> text "between" <+> fpd fps
> <+> text "and" <+> fpd fpe
> rsd rs = case rs of
> FrameRows -> text "rows"
> FrameRange -> text "range"
> fpd UnboundedPreceding = text "unbounded preceding"
> fpd UnboundedFollowing = text "unbounded following"
> fpd Current = text "current row"
2016-02-22 22:24:25 +01:00
> fpd (Preceding e) = scalarExpr d e <+> text "preceding"
> fpd (Following e) = scalarExpr d e <+> text "following"
2013-12-13 22:31:36 +01:00
2016-02-22 22:24:25 +01:00
> scalarExpr dia (SpecialOp nm [a,b,c]) | nm `elem` [[Name Nothing "between"]
2016-02-12 13:13:47 +01:00
> ,[Name Nothing "not between"]] =
2016-02-22 22:24:25 +01:00
> sep [scalarExpr dia a
> ,names nm <+> scalarExpr dia b
> ,nest (length (unnames nm) + 1) $ text "and" <+> scalarExpr dia c]
2013-12-13 20:13:36 +01:00
2016-02-22 22:24:25 +01:00
> scalarExpr d (SpecialOp [Name Nothing "rowctor"] as) =
> parens $ commaSep $ map (scalarExpr d) as
2016-02-22 22:24:25 +01:00
> scalarExpr d (SpecialOp nm es) =
> names nm <+> parens (commaSep $ map (scalarExpr d) es)
2013-12-13 20:13:36 +01:00
2016-02-22 22:24:25 +01:00
> scalarExpr d (SpecialOpK nm fs as) =
> names nm <> parens (sep $ catMaybes
2016-02-22 22:24:25 +01:00
> (fmap (scalarExpr d) fs
> : map (\(n,e) -> Just (text n <+> scalarExpr d e)) as))
2016-02-22 22:24:25 +01:00
> scalarExpr d (PrefixOp f e) = names f <+> scalarExpr d e
> scalarExpr d (PostfixOp f e) = scalarExpr d e <+> names f
> scalarExpr d e@(BinOp _ op _) | op `elem` [[Name Nothing "and"]
2016-02-12 13:13:47 +01:00
> ,[Name Nothing "or"]] =
2013-12-14 13:24:49 +01:00
> -- special case for and, or, get all the ands so we can vcat them
> -- nicely
> case ands e of
2016-02-22 22:24:25 +01:00
> (e':es) -> vcat (scalarExpr d e'
> : map ((names op <+>) . scalarExpr d) es)
2013-12-14 13:24:49 +01:00
> [] -> empty -- shouldn't be possible
> where
> ands (BinOp a op' b) | op == op' = ands a ++ ands b
> ands x = [x]
2013-12-17 14:21:43 +01:00
> -- special case for . we don't use whitespace
2016-02-22 22:24:25 +01:00
> scalarExpr d (BinOp e0 [Name Nothing "."] e1) =
> scalarExpr d e0 <> text "." <> scalarExpr d e1
> scalarExpr d (BinOp e0 f e1) =
> scalarExpr d e0 <+> names f <+> scalarExpr d e1
2016-02-22 22:24:25 +01:00
> scalarExpr dia (Case t ws els) =
> sep $ [text "case" <+> me (scalarExpr dia) t]
2013-12-14 15:35:36 +01:00
> ++ map w ws
> ++ maybeToList (fmap e els)
> ++ [text "end"]
> where
2013-12-14 15:35:36 +01:00
> w (t0,t1) =
2016-02-22 22:24:25 +01:00
> text "when" <+> nest 5 (commaSep $ map (scalarExpr dia) t0)
> <+> text "then" <+> nest 5 (scalarExpr dia t1)
> e el = text "else" <+> nest 5 (scalarExpr dia el)
> scalarExpr d (Parens e) = parens $ scalarExpr d e
> scalarExpr d (Cast e tn) =
> text "cast" <> parens (sep [scalarExpr d e
> ,text "as"
> ,typeName tn])
2016-02-22 22:24:25 +01:00
> scalarExpr _ (TypedLit tn s) =
> typeName tn <+> quotes (text s)
2016-02-22 22:24:25 +01:00
> scalarExpr d (SubQueryExpr ty qe) =
> (case ty of
> SqSq -> empty
> SqExists -> text "exists"
> SqUnique -> text "unique"
> ) <+> parens (queryExpr d qe)
2016-02-22 22:24:25 +01:00
> scalarExpr d (QuantifiedComparison v c cp sq) =
> scalarExpr d v
> <+> names c
> <+> (text $ case cp of
> CPAny -> "any"
> CPSome -> "some"
> CPAll -> "all")
> <+> parens (queryExpr d sq)
2016-02-22 22:24:25 +01:00
> scalarExpr d (Match v u sq) =
> scalarExpr d v
> <+> text "match"
> <+> (if u then text "unique" else empty)
> <+> parens (queryExpr d sq)
2016-02-22 22:24:25 +01:00
> scalarExpr d (In b se x) =
> scalarExpr d se <+>
2013-12-14 15:35:36 +01:00
> (if b then empty else text "not")
> <+> text "in"
> <+> parens (nest (if b then 3 else 7) $
> case x of
2016-02-22 22:24:25 +01:00
> InList es -> commaSep $ map (scalarExpr d) es
> InQueryExpr qe -> queryExpr d qe)
2016-02-22 22:24:25 +01:00
> scalarExpr d (Array v es) =
> scalarExpr d v <> brackets (commaSep $ map (scalarExpr d) es)
2016-02-22 22:24:25 +01:00
> scalarExpr d (ArrayCtor q) =
> text "array" <> parens (queryExpr d q)
2016-02-22 22:24:25 +01:00
> scalarExpr d (MultisetCtor es) =
> text "multiset" <> brackets (commaSep $ map (scalarExpr d) es)
2014-04-18 19:50:24 +02:00
2016-02-22 22:24:25 +01:00
> scalarExpr d (MultisetQueryCtor q) =
> text "multiset" <> parens (queryExpr d q)
2014-04-18 19:50:24 +02:00
2016-02-22 22:24:25 +01:00
> scalarExpr d (MultisetBinOp a c q b) =
2014-04-18 19:50:24 +02:00
> sep
2016-02-22 22:24:25 +01:00
> [scalarExpr d a
2014-04-18 19:50:24 +02:00
> ,text "multiset"
> ,text $ case c of
> Union -> "union"
> Intersect -> "intersect"
> Except -> "except"
> ,case q of
> SQDefault -> empty
> All -> text "all"
> Distinct -> text "distinct"
2016-02-22 22:24:25 +01:00
> ,scalarExpr d b]
2014-04-18 19:50:24 +02:00
2016-02-22 22:24:25 +01:00
> {-scalarExpr d (Escape v e) =
> scalarExpr d v <+> text "escape" <+> text [e]
2016-02-22 22:24:25 +01:00
> scalarExpr d (UEscape v e) =
> scalarExpr d v <+> text "uescape" <+> text [e]-}
2016-02-22 22:24:25 +01:00
> scalarExpr d (Collate v c) =
> scalarExpr d v <+> text "collate" <+> names c
2016-02-22 22:24:25 +01:00
> scalarExpr _ (NextValueFor ns) =
> text "next value for" <+> names ns
2016-02-22 22:24:25 +01:00
> scalarExpr d (VEComment cmt v) =
> vcat $ map comment cmt ++ [scalarExpr d v]
2016-02-22 22:24:25 +01:00
> scalarExpr _ (OdbcLiteral t s) =
2016-02-21 22:43:19 +01:00
> text "{" <> lt t <+> quotes (text s) <> text "}"
> where
> lt OLDate = text "d"
> lt OLTime = text "t"
> lt OLTimestamp = text "ts"
2016-02-22 22:24:25 +01:00
> scalarExpr d (OdbcFunc e) =
> text "{fn" <+> scalarExpr d e <> text "}"
2016-02-21 22:43:19 +01:00
> scalarExpr d (Convert t e Nothing) =
> text "convert(" <> typeName t <> text "," <+> scalarExpr d e <> text ")"
> scalarExpr d (Convert t e (Just i)) =
> text "convert(" <> typeName t <> text "," <+> scalarExpr d e <> text "," <+> text (show i) <> text ")"
2013-12-17 12:21:36 +01:00
> unname :: Name -> String
2016-02-12 13:13:47 +01:00
> unname (Name Nothing n) = n
> unname (Name (Just (s,e)) n) =
> s ++ n ++ e
2013-12-17 12:21:36 +01:00
> unnames :: [Name] -> String
> unnames ns = intercalate "." $ map unname ns
2013-12-17 12:21:36 +01:00
> name :: Name -> Doc
2016-02-12 13:13:47 +01:00
> name (Name Nothing n) = text n
> name (Name (Just (s,e)) n) = text s <> text n <> text e
2013-12-17 12:21:36 +01:00
> names :: [Name] -> Doc
> names ns = hcat $ punctuate (text ".") $ map name ns
> typeName :: TypeName -> Doc
> typeName (TypeName t) = names t
> typeName (PrecTypeName t a) = names t <+> parens (text $ show a)
> typeName (PrecScaleTypeName t a b) =
> names t <+> parens (text (show a) <+> comma <+> text (show b))
> typeName (PrecLengthTypeName t i m u) =
> names t
> <> parens (text (show i)
2014-04-18 18:49:00 +02:00
> <> me (\x -> case x of
> PrecK -> text "K"
> PrecM -> text "M"
> PrecG -> text "G"
> PrecT -> text "T"
> PrecP -> text "P") m
2014-04-18 18:49:00 +02:00
> <+> me (\x -> case x of
> PrecCharacters -> text "CHARACTERS"
> PrecOctets -> text "OCTETS") u)
> typeName (CharTypeName t i cs col) =
> names t
> <> me (\x -> parens (text $ show x)) i
> <+> (if null cs
> then empty
> else text "character set" <+> names cs)
> <+> (if null col
> then empty
> else text "collate" <+> names col)
> typeName (TimeTypeName t i tz) =
> names t
> <> me (\x -> parens (text $ show x)) i
> <+> text (if tz
> then "with time zone"
> else "without time zone")
> typeName (RowTypeName cs) =
> text "row" <> parens (commaSep $ map f cs)
> where
> f (n,t) = name n <+> typeName t
> typeName (IntervalTypeName f t) =
> text "interval"
2014-04-18 20:38:24 +02:00
> <+> intervalTypeField f
> <+> me (\x -> text "to" <+> intervalTypeField x) t
2014-04-18 18:49:00 +02:00
> typeName (ArrayTypeName tn sz) =
> typeName tn <+> text "array" <+> me (brackets . text . show) sz
2014-04-18 18:49:00 +02:00
> typeName (MultisetTypeName tn) =
> typeName tn <+> text "multiset"
2014-04-18 20:38:24 +02:00
> intervalTypeField :: IntervalTypeField -> Doc
> intervalTypeField (Itf n p) =
> text n
> <+> me (\(x,x1) ->
> parens (text (show x)
> <+> me (\y -> (sep [comma,text (show y)])) x1)) p
= query expressions
> queryExpr :: Dialect -> QueryExpr -> Doc
> queryExpr dia (Select d sl fr wh gb hv od off fe) =
> sep [text "select"
2013-12-13 16:27:02 +01:00
> ,case d of
> SQDefault -> empty
> All -> text "all"
2013-12-13 16:27:02 +01:00
> Distinct -> text "distinct"
> ,nest 7 $ sep [selectList dia sl]
> ,from dia fr
2016-02-22 22:24:25 +01:00
> ,maybeScalarExpr dia "where" wh
> ,grpBy dia gb
2016-02-22 22:24:25 +01:00
> ,maybeScalarExpr dia "having" hv
> ,orderBy dia od
2016-02-22 22:24:25 +01:00
> ,me (\e -> text "offset" <+> scalarExpr dia e <+> text "rows") off
> ,fetchFirst
> ]
> where
> fetchFirst =
> me (\e -> if diLimit dia
2016-02-22 22:24:25 +01:00
> then text "limit" <+> scalarExpr dia e
> else text "fetch first" <+> scalarExpr dia e
> <+> text "rows only") fe
> queryExpr dia (QueryExprSetOp q1 ct d c q2) =
> sep [queryExpr dia q1
> ,text (case ct of
> Union -> "union"
> Intersect -> "intersect"
> Except -> "except")
> <+> case d of
> SQDefault -> empty
> All -> text "all"
> Distinct -> text "distinct"
> <+> case c of
> Corresponding -> text "corresponding"
> Respectively -> empty
> ,queryExpr dia q2]
> queryExpr d (With rc withs qe) =
> text "with" <+> (if rc then text "recursive" else empty)
2013-12-14 13:24:49 +01:00
> <+> vcat [nest 5
> (vcat $ punctuate comma $ flip map withs $ \(n,q) ->
2019-08-31 10:30:42 +02:00
> withAlias n <+> text "as" <+> parens (queryExpr d q))
> ,queryExpr d qe]
2019-08-31 10:30:42 +02:00
> where
> withAlias (Alias nm cols) = name nm
> <+> me (parens . commaSep . map name) cols
> queryExpr d (Values vs) =
2013-12-17 12:27:16 +01:00
> text "values"
2016-02-22 22:24:25 +01:00
> <+> nest 7 (commaSep (map (parens . commaSep . map (scalarExpr d)) vs))
> queryExpr _ (Table t) = text "table" <+> names t
> queryExpr d (QEComment cmt v) =
> vcat $ map comment cmt ++ [queryExpr d v]
2013-12-17 12:58:44 +01:00
> alias :: Alias -> Doc
> alias (Alias nm cols) =
> text "as" <+> name nm
> <+> me (parens . commaSep . map name) cols
2016-02-22 22:24:25 +01:00
> selectList :: Dialect -> [(ScalarExpr,Maybe Name)] -> Doc
> selectList d is = commaSep $ map si is
> where
2016-02-22 22:24:25 +01:00
> si (e,al) = scalarExpr d e <+> me als al
> als al = text "as" <+> name al
> from :: Dialect -> [TableRef] -> Doc
> from _ [] = empty
> from d ts =
> sep [text "from"
2013-12-14 13:24:49 +01:00
> ,nest 5 $ vcat $ punctuate comma $ map tr ts]
> where
> tr (TRSimple t) = names t
2013-12-17 11:45:32 +01:00
> tr (TRLateral t) = text "lateral" <+> tr t
2013-12-17 11:33:33 +01:00
> tr (TRFunction f as) =
2016-02-22 22:24:25 +01:00
> names f <> parens (commaSep $ map (scalarExpr d) as)
> tr (TRAlias t a) = sep [tr t, alias a]
2013-12-14 13:10:46 +01:00
> tr (TRParens t) = parens $ tr t
> tr (TRQueryExpr q) = parens $ queryExpr d q
> tr (TRJoin t0 b jt t1 jc) =
> sep [tr t0
> ,if b then text "natural" else empty
> ,joinText jt <+> tr t1
> ,joinCond jc]
2016-02-21 22:48:55 +01:00
> tr (TROdbc t) = text "{oj" <+> tr t <+> text "}"
> joinText jt =
> sep [case jt of
> JInner -> text "inner"
> JLeft -> text "left"
> JRight -> text "right"
> JFull -> text "full"
> JCross -> text "cross"
> ,text "join"]
2016-02-22 22:24:25 +01:00
> joinCond (Just (JoinOn e)) = text "on" <+> scalarExpr d e
2013-12-14 15:58:35 +01:00
> joinCond (Just (JoinUsing es)) =
2013-12-17 12:21:36 +01:00
> text "using" <+> parens (commaSep $ map name es)
> joinCond Nothing = empty
2016-02-22 22:24:25 +01:00
> maybeScalarExpr :: Dialect -> String -> Maybe ScalarExpr -> Doc
> maybeScalarExpr d k = me
2013-12-13 16:27:02 +01:00
> (\e -> sep [text k
2016-02-22 22:24:25 +01:00
> ,nest (length k + 1) $ scalarExpr d e])
> grpBy :: Dialect -> [GroupingExpr] -> Doc
> grpBy _ [] = empty
> grpBy d gs = sep [text "group by"
> ,nest 9 $ commaSep $ map ge gs]
> where
2016-02-22 22:24:25 +01:00
> ge (SimpleGroup e) = scalarExpr d e
> ge (GroupingParens g) = parens (commaSep $ map ge g)
> ge (Cube es) = text "cube" <> parens (commaSep $ map ge es)
> ge (Rollup es) = text "rollup" <> parens (commaSep $ map ge es)
> ge (GroupingSets es) = text "grouping sets" <> parens (commaSep $ map ge es)
> orderBy :: Dialect -> [SortSpec] -> Doc
> orderBy _ [] = empty
> orderBy dia os = sep [text "order by"
2013-12-14 13:24:49 +01:00
> ,nest 9 $ commaSep $ map f os]
2013-12-13 16:08:10 +01:00
> where
> f (SortSpec e d n) =
2016-02-22 22:24:25 +01:00
> scalarExpr dia e
> <+> (case d of
> Asc -> text "asc"
> Desc -> text "desc"
> DirDefault -> empty)
2013-12-17 17:28:31 +01:00
> <+> (case n of
> NullsOrderDefault -> empty
> NullsFirst -> text "nulls" <+> text "first"
> NullsLast -> text "nulls" <+> text "last")
= statements
> statement :: Dialect -> Statement -> Doc
== ddl
> statement _ (CreateSchema nm) =
> text "create" <+> text "schema" <+> names nm
> statement d (CreateTable nm cds) =
2015-08-01 22:16:26 +02:00
> text "create" <+> text "table" <+> names nm
> <+> parens (commaSep $ map cd cds)
> where
> cd (TableConstraintDef n con) =
> maybe empty (\s -> text "constraint" <+> names s) n
> <+> tableConstraint d con
2015-08-02 19:56:39 +02:00
> cd (TableColumnDef cd') = columnDef d cd'
2015-08-02 19:56:39 +02:00
> statement d (AlterTable t act) =
> texts ["alter","table"] <+> names t
> <+> alterTableAction d act
2015-08-01 22:16:26 +02:00
> statement _ (DropSchema nm db) =
> text "drop" <+> text "schema" <+> names nm <+> dropBehav db
2015-08-04 21:08:32 +02:00
> statement d (CreateDomain nm ty def cs) =
> text "create" <+> text "domain" <+> names nm
> <+> typeName ty
2016-02-22 22:24:25 +01:00
> <+> maybe empty (\def' -> text "default" <+> scalarExpr d def') def
2015-08-04 21:08:32 +02:00
> <+> sep (map con cs)
> where
> con (cn, e) =
> maybe empty (\cn' -> text "constraint" <+> names cn') cn
2016-02-22 22:24:25 +01:00
> <+> text "check" <> parens (scalarExpr d e)
2015-08-04 21:08:32 +02:00
> statement d (AlterDomain nm act) =
> texts ["alter","domain"]
> <+> names nm
> <+> a act
> where
2016-02-22 22:24:25 +01:00
> a (ADSetDefault v) = texts ["set","default"] <+> scalarExpr d v
2015-08-04 21:08:32 +02:00
> a (ADDropDefault) = texts ["drop","default"]
2015-08-04 21:35:51 +02:00
> a (ADAddConstraint cnm e) =
2015-08-04 21:08:32 +02:00
> text "add"
2015-08-04 21:35:51 +02:00
> <+> maybe empty (\cnm' -> text "constraint" <+> names cnm') cnm
2016-02-22 22:24:25 +01:00
> <+> text "check" <> parens (scalarExpr d e)
2015-08-04 21:35:51 +02:00
> a (ADDropConstraint cnm) = texts ["drop", "constraint"]
> <+> names cnm
2015-08-04 21:08:32 +02:00
> statement _ (DropDomain nm db) =
> text "drop" <+> text "domain" <+> names nm <+> dropBehav db
2015-08-04 21:35:51 +02:00
> statement _ (CreateSequence nm sgos) =
> texts ["create","sequence"] <+> names nm
> <+> sep (map sequenceGeneratorOption sgos)
> statement _ (AlterSequence nm sgos) =
> texts ["alter","sequence"] <+> names nm
> <+> sep (map sequenceGeneratorOption sgos)
> statement _ (DropSequence nm db) =
> text "drop" <+> text "sequence" <+> names nm <+> dropBehav db
2015-08-16 19:03:02 +02:00
> statement d (CreateAssertion nm ex) =
> texts ["create","assertion"] <+> names nm
2016-02-22 22:24:25 +01:00
> <+> text "check" <+> parens (scalarExpr d ex)
2015-08-16 19:03:02 +02:00
> statement _ (DropAssertion nm db) =
> text "drop" <+> text "assertion" <+> names nm <+> dropBehav db
> statement _ (CreateIndex un nm tbl cols) =
> texts (if un
> then ["create","unique","index"]
> else ["create","index"])
> <+> names nm
> <+> text "on"
> <+> names tbl
> <+> parens (commaSep $ map name cols)
== dml
> statement d (SelectStatement q) = queryExpr d q
> statement d (Delete t a w) =
> text "delete" <+> text "from"
> <+> names t <+> maybe empty (\x -> text "as" <+> name x) a
2016-02-22 22:24:25 +01:00
> <+> maybeScalarExpr d "where" w
> statement _ (Truncate t ir) =
> text "truncate" <+> text "table" <+> names t
> <+> case ir of
> DefaultIdentityRestart -> empty
> ContinueIdentity -> text "continue" <+> text "identity"
> RestartIdentity -> text "restart" <+> text "identity"
> statement d (Insert t cs s) =
> text "insert" <+> text "into" <+> names t
> <+> maybe empty (\cs' -> parens (commaSep $ map name cs')) cs
> <+> case s of
> DefaultInsertValues -> text "default" <+> text "values"
> InsertQuery q -> queryExpr d q
> statement d (Update t a sts whr) =
> text "update" <+> names t
> <+> maybe empty (\x -> text "as" <+> name x) a
> <+> text "set" <+> commaSep (map sc sts)
2016-02-22 22:24:25 +01:00
> <+> maybeScalarExpr d "where" whr
> where
2016-02-22 22:24:25 +01:00
> sc (Set tg v) = names tg <+> text "=" <+> scalarExpr d v
> sc (SetMultiple ts vs) = parens (commaSep $ map names ts) <+> text "="
2016-02-22 22:24:25 +01:00
> <+> parens (commaSep $ map (scalarExpr d) vs)
2015-08-02 22:27:09 +02:00
> statement _ (DropTable n b) =
> text "drop" <+> text "table" <+> names n <+> dropBehav b
2015-08-02 22:52:01 +02:00
> statement d (CreateView r nm al q co) =
> text "create" <+> (if r then text "recursive" else empty)
> <+> text "view" <+> names nm
> <+> (maybe empty (\al' -> parens $ commaSep $ map name al')) al
> <+> text "as"
> <+> queryExpr d q
> <+> case co of
> Nothing -> empty
> Just DefaultCheckOption -> texts ["with", "check", "option"]
> Just CascadedCheckOption -> texts ["with", "cascaded", "check", "option"]
> Just LocalCheckOption -> texts ["with", "local", "check", "option"]
> statement _ (DropView n b) =
> text "drop" <+> text "view" <+> names n <+> dropBehav b
== transactions
2015-08-04 21:53:08 +02:00
> statement _ StartTransaction =
> texts ["start", "transaction"]
> statement _ (Savepoint nm) =
> text "savepoint" <+> name nm
> statement _ (ReleaseSavepoint nm) =
> texts ["release", "savepoint"] <+> name nm
> statement _ Commit =
> text "commit"
> statement _ (Rollback mn) =
> text "rollback"
> <+> maybe empty (\n -> texts ["to","savepoint"] <+> name n) mn
== access control
> statement _ (GrantPrivilege pas po rs go) =
> text "grant" <+> commaSep (map privAct pas)
> <+> text "on" <+> privObj po
> <+> text "to" <+> commaSep (map name rs)
> <+> grantOpt go
> where
> grantOpt WithGrantOption = texts ["with","grant","option"]
> grantOpt WithoutGrantOption = empty
> statement _ (GrantRole rs trs ao) =
> text "grant" <+> commaSep (map name rs)
> <+> text "to" <+> commaSep (map name trs)
> <+> adminOpt ao
> where
> adminOpt WithAdminOption = texts ["with","admin","option"]
> adminOpt WithoutAdminOption = empty
> statement _ (CreateRole nm) =
> texts ["create","role"] <+> name nm
> statement _ (DropRole nm) =
> texts ["drop","role"] <+> name nm
> statement _ (RevokePrivilege go pas po rs db) =
> text "revoke"
> <+> grantOptFor go
> <+> commaSep (map privAct pas)
> <+> text "on" <+> privObj po
> <+> text "from" <+> commaSep (map name rs)
> <+> dropBehav db
> where
> grantOptFor GrantOptionFor = texts ["grant","option","for"]
> grantOptFor NoGrantOptionFor = empty
> statement _ (RevokeRole ao rs trs db) =
> text "revoke"
> <+> adminOptFor ao
> <+> commaSep (map name rs)
> <+> text "from" <+> commaSep (map name trs)
> <+> dropBehav db
> where
> adminOptFor AdminOptionFor = texts ["admin","option","for"]
> adminOptFor NoAdminOptionFor = empty
2016-02-22 22:28:59 +01:00
> statement _ (StatementComment cs) = vcat $ map comment cs
2020-12-20 16:03:15 +01:00
> statement _ EmptyStatement = empty
2016-02-22 22:28:59 +01:00
== sessions
== extras
> dropBehav :: DropBehaviour -> Doc
> dropBehav DefaultDropBehaviour = empty
> dropBehav Cascade = text "cascade"
> dropBehav Restrict = text "restrict"
2015-08-02 19:56:39 +02:00
> columnDef :: Dialect -> ColumnDef -> Doc
> columnDef d (ColumnDef n t mdef cons) =
> name n <+> typeName t
> <+> case mdef of
> Nothing -> empty
> Just (DefaultClause def) ->
2016-02-22 22:24:25 +01:00
> text "default" <+> scalarExpr d def
2015-08-02 19:56:39 +02:00
> Just (GenerationClause e) ->
2016-02-22 22:24:25 +01:00
> texts ["generated","always","as"] <+> parens (scalarExpr d e)
2015-08-02 19:56:39 +02:00
> Just (IdentityColumnSpec w o) ->
> text "generated"
> <+> (case w of
> GeneratedAlways -> text "always"
> GeneratedByDefault -> text "by" <+> text "default")
> <+> text "as" <+> text "identity"
> <+> (case o of
> [] -> empty
2015-08-04 21:35:51 +02:00
> os -> parens (sep $ map sequenceGeneratorOption os))
2015-08-02 19:56:39 +02:00
> <+> sep (map cdef cons)
> where
> cdef (ColConstraintDef cnm con) =
> maybe empty (\s -> text "constraint" <+> names s) cnm
> <+> pcon con
> pcon ColNotNullConstraint = texts ["not","null"]
> pcon ColUniqueConstraint = text "unique"
> pcon ColPrimaryKeyConstraint = texts ["primary","key"]
2016-02-22 22:24:25 +01:00
> pcon (ColCheckConstraint v) = text "check" <+> parens (scalarExpr d v)
2015-08-02 19:56:39 +02:00
> pcon (ColReferencesConstraint tb c m u del) =
> text "references"
> <+> names tb
> <+> maybe empty (\c' -> parens (name c')) c
> <+> refMatch m
> <+> refAct "update" u
> <+> refAct "delete" del
2015-08-04 21:35:51 +02:00
> sequenceGeneratorOption :: SequenceGeneratorOption -> Doc
> sequenceGeneratorOption (SGODataType t) =
> text "as" <+> typeName t
> sequenceGeneratorOption (SGORestart mi) =
> text "restart" <+> maybe empty (\mi' -> texts ["with", show mi']) mi
> sequenceGeneratorOption (SGOStartWith i) = texts ["start", "with", show i]
> sequenceGeneratorOption (SGOIncrementBy i) = texts ["increment", "by", show i]
> sequenceGeneratorOption (SGOMaxValue i) = texts ["maxvalue", show i]
> sequenceGeneratorOption SGONoMaxValue = texts ["no", "maxvalue"]
> sequenceGeneratorOption (SGOMinValue i) = texts ["minvalue", show i]
> sequenceGeneratorOption SGONoMinValue = texts ["no", "minvalue"]
> sequenceGeneratorOption SGOCycle = text "cycle"
> sequenceGeneratorOption SGONoCycle = text "no cycle"
2015-08-02 19:56:39 +02:00
> refMatch :: ReferenceMatch -> Doc
> refMatch m = case m of
> DefaultReferenceMatch -> empty
> MatchFull -> texts ["match", "full"]
> MatchPartial -> texts ["match","partial"]
> MatchSimple -> texts ["match", "simple"]
> refAct :: String -> ReferentialAction -> Doc
> refAct t a = case a of
> DefaultReferentialAction -> empty
> RefCascade -> texts ["on", t, "cascade"]
> RefSetNull -> texts ["on", t, "set", "null"]
> RefSetDefault -> texts ["on", t, "set", "default"]
> RefRestrict -> texts ["on", t, "restrict"]
> RefNoAction -> texts ["on", t, "no", "action"]
> alterTableAction :: Dialect -> AlterTableAction -> Doc
> alterTableAction d (AddColumnDef cd) =
> texts ["add", "column"] <+> columnDef d cd
> alterTableAction d (AlterColumnSetDefault n v) =
> texts ["alter", "column"]
> <+> name n
2016-02-22 22:24:25 +01:00
> <+> texts ["set","default"] <+> scalarExpr d v
> alterTableAction _ (AlterColumnDropDefault n) =
> texts ["alter", "column"]
> <+> name n
> <+> texts ["drop","default"]
> alterTableAction _ (AlterColumnSetNotNull n) =
> texts ["alter", "column"]
> <+> name n
> <+> texts ["set","not","null"]
> alterTableAction _ (AlterColumnDropNotNull n) =
> texts ["alter", "column"]
> <+> name n
> <+> texts ["drop","not","null"]
> alterTableAction _ (AlterColumnSetDataType n t) =
> texts ["alter", "column"]
> <+> name n
> <+> texts ["set","data","Type"]
> <+> typeName t
> alterTableAction _ (DropColumn n b) =
> texts ["drop", "column"]
> <+> name n
> <+> dropBehav b
> alterTableAction d (AddTableConstraintDef n con) =
> text "add"
> <+> maybe empty (\s -> text "constraint" <+> names s) n
> <+> tableConstraint d con
> alterTableAction _ (DropTableConstraintDef n b) =
> texts ["drop", "constraint"]
> <+> names n
> <+> dropBehav b
> tableConstraint :: Dialect -> TableConstraint -> Doc
> tableConstraint _ (TableUniqueConstraint ns) =
> text "unique" <+> parens (commaSep $ map name ns)
> tableConstraint _ (TablePrimaryKeyConstraint ns) =
> texts ["primary","key"] <+> parens (commaSep $ map name ns)
> tableConstraint _ (TableReferencesConstraint cs t tcs m u del) =
> texts ["foreign", "key"]
> <+> parens (commaSep $ map name cs)
> <+> text "references"
> <+> names t
> <+> maybe empty (\c' -> parens (commaSep $ map name c')) tcs
> <+> refMatch m
> <+> refAct "update" u
> <+> refAct "delete" del
2016-02-22 22:24:25 +01:00
> tableConstraint d (TableCheckConstraint v) = text "check" <+> parens (scalarExpr d v)
> privAct :: PrivilegeAction -> Doc
> privAct PrivAll = texts ["all","privileges"]
> privAct (PrivSelect cs) = text "select" <+> maybeColList cs
> privAct (PrivInsert cs) = text "insert" <+> maybeColList cs
> privAct (PrivUpdate cs) = text "update" <+> maybeColList cs
> privAct (PrivReferences cs) = text "references" <+> maybeColList cs
> privAct PrivDelete = text "delete"
> privAct PrivUsage = text "usage"
> privAct PrivTrigger = text "trigger"
> privAct PrivExecute = text "execute"
> maybeColList :: [Name] -> Doc
> maybeColList cs =
> if null cs
> then empty
> else parens (commaSep $ map name cs)
> privObj :: PrivilegeObject -> Doc
> privObj (PrivTable nm) = names nm
> privObj (PrivDomain nm) = text "domain" <+> names nm
> privObj (PrivType nm) = text "type" <+> names nm
> privObj (PrivSequence nm) = text "sequence" <+> names nm
> privObj (PrivFunction nm) = texts ["specific", "function"] <+> names nm
= utils
> commaSep :: [Doc] -> Doc
> commaSep ds = sep $ punctuate comma ds
> me :: (a -> Doc) -> Maybe a -> Doc
> me = maybe empty
> comment :: Comment -> Doc
> comment (BlockComment str) = text "/*" <+> text str <+> text "*/"
> texts :: [String] -> Doc
> texts ts = sep $ map text ts