From f0baa3c37b4ec14ce5ac6cb6c4739836a6470de5 Mon Sep 17 00:00:00 2001 From: Jake Wheat Date: Sun, 2 Aug 2015 23:22:06 +0300 Subject: [PATCH] add alter table variations: set default drop default set not null drop not null set data type drop column add constraint drop constraint fix bug where generated didn't have to be followed with 'always' or 'by default' for identities in create table --- Language/SQL/SimpleSQL/Parser.lhs | 40 +++++- Language/SQL/SimpleSQL/Pretty.lhs | 76 +++++++--- Language/SQL/SimpleSQL/Syntax.lhs | 22 +-- .../Language/SQL/SimpleSQL/SQL2011Schema.lhs | 134 +++++++++++++++--- 4 files changed, 218 insertions(+), 54 deletions(-) diff --git a/Language/SQL/SimpleSQL/Parser.lhs b/Language/SQL/SimpleSQL/Parser.lhs index 46d2234..b321856 100644 --- a/Language/SQL/SimpleSQL/Parser.lhs +++ b/Language/SQL/SimpleSQL/Parser.lhs @@ -1461,7 +1461,7 @@ TODO: change style > CreateTable > <$> names > -- todo: is this order mandatory or is it a perm? -> <*> parens (commaSep1 (tableConstraintDef +> <*> parens (commaSep1 (uncurry TableConstraintDef <$> tableConstraintDef > <|> TableColumnDef <$> columnDef)) > columnDef :: Parser ColumnDef @@ -1477,8 +1477,7 @@ TODO: change style > GenerationClause <$> parens valueExpr) > ,keyword_ "generated" >> > IdentityColumnSpec -> <$> option GeneratedDefault -> (GeneratedAlways <$ keyword_ "always" +> <$> (GeneratedAlways <$ keyword_ "always" > <|> GeneratedByDefault <$ keywords_ ["by", "default"]) > <*> (keywords_ ["as", "identity"] *> > option [] (parens sequenceGeneratorOptions)) @@ -1509,9 +1508,9 @@ TODO: change style > scycle = SGOCycle <$ keyword_ "cycle" > noCycle = SGONoCycle <$ try (keywords_ ["no","cycle"]) -> tableConstraintDef :: Parser TableElement +> tableConstraintDef :: Parser (Maybe [Name], TableConstraint) > tableConstraintDef = -> TableConstraintDef +> (,) > <$> (optionMaybe (keyword_ "constraint" *> names)) > <*> (unique <|> primaryKey <|> check <|> references) > where @@ -1575,11 +1574,40 @@ slightly hacky parser for signed integers > alterTable :: Parser Statement > alterTable = keyword_ "table" >> -> AlterTable <$> names <*> choice [addColumnDef] +> -- the choices have been ordered so that it works +> AlterTable <$> names <*> choice [addConstraint +> ,dropConstraint +> ,addColumnDef +> ,alterColumn +> ,dropColumn +> ] > where > addColumnDef = try (keyword_ "add" > *> optional (keyword_ "column")) >> > AddColumnDef <$> columnDef +> alterColumn = keyword_ "alter" >> optional (keyword_ "column") >> +> name <**> choice [setDefault +> ,dropDefault +> ,setNotNull +> ,dropNotNull +> ,setDataType] +> setDefault :: Parser (Name -> AlterTableAction) +> -- todo: left factor +> setDefault = try (keywords_ ["set","default"]) >> +> valueExpr <$$> AlterColumnSetDefault +> dropDefault = AlterColumnDropDefault <$ try (keywords_ ["drop","default"]) +> setNotNull = AlterColumnSetNotNull <$ try (keywords_ ["set","not","null"]) +> dropNotNull = AlterColumnDropNotNull <$ try (keywords_ ["drop","not","null"]) +> setDataType = try (keywords_ ["set","data","type"]) >> +> typeName <$$> AlterColumnSetDataType +> dropColumn = try (keyword_ "drop" *> optional (keyword_ "column")) >> +> DropColumn <$> name <*> dropBehaviour +> -- todo: left factor, this try is especially bad +> addConstraint = try (keyword_ "add" >> +> uncurry AddTableConstraintDef <$> tableConstraintDef) +> dropConstraint = try (keywords_ ["drop","constraint"]) >> +> DropTableConstraintDef <$> names <*> dropBehaviour + > dropSchema :: Parser Statement > dropSchema = keyword_ "schema" >> diff --git a/Language/SQL/SimpleSQL/Pretty.lhs b/Language/SQL/SimpleSQL/Pretty.lhs index 76e4a06..918b3f8 100644 --- a/Language/SQL/SimpleSQL/Pretty.lhs +++ b/Language/SQL/SimpleSQL/Pretty.lhs @@ -459,22 +459,8 @@ which have been changed to try to improve the layout of the output. > where > cd (TableConstraintDef n con) = > maybe empty (\s -> text "constraint" <+> names s) n -> <+> ptcon con +> <+> tableConstraint d con > cd (TableColumnDef cd') = columnDef d cd' -> ptcon (TableUniqueConstraint ns) = -> text "unique" <+> parens (commaSep $ map name ns) -> ptcon (TablePrimaryKeyConstraint ns) = -> texts ["primary","key"] <+> parens (commaSep $ map name ns) -> ptcon (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 -> ptcon (TableCheckConstraint v) = text "check" <+> parens (valueExpr d v) > statement d (AlterTable t act) = > texts ["alter","table"] <+> names t @@ -543,7 +529,6 @@ which have been changed to try to improve the layout of the output. > Just (IdentityColumnSpec w o) -> > text "generated" > <+> (case w of -> GeneratedDefault -> empty > GeneratedAlways -> text "always" > GeneratedByDefault -> text "by" <+> text "default") > <+> text "as" <+> text "identity" @@ -595,6 +580,65 @@ which have been changed to try to improve the layout of the output. > alterTableAction d (AddColumnDef cd) = > texts ["add", "column"] <+> columnDef d cd +> alterTableAction d (AlterColumnSetDefault n v) = +> texts ["alter", "column"] +> <+> name n +> <+> texts ["set","default"] <+> valueExpr 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 +> tableConstraint d (TableCheckConstraint v) = text "check" <+> parens (valueExpr d v) + + + = utils > commaSep :: [Doc] -> Doc diff --git a/Language/SQL/SimpleSQL/Syntax.lhs b/Language/SQL/SimpleSQL/Syntax.lhs index 576d553..662336f 100644 --- a/Language/SQL/SimpleSQL/Syntax.lhs +++ b/Language/SQL/SimpleSQL/Syntax.lhs @@ -553,13 +553,18 @@ I'm not sure if this is valid syntax or not. > data AlterTableAction = > AddColumnDef ColumnDef -> {- -> | AlterColumnDef -> | DropColumnDef -> | AddTableConstraintDef -> | AlterTableConstraintDef -> | DropTableConstraintDef -> -} +> | AlterColumnSetDefault Name ValueExpr +> | AlterColumnDropDefault Name +> | AlterColumnSetNotNull Name +> | AlterColumnDropNotNull Name +> | AlterColumnSetDataType Name TypeName +> {- | AlterColumnAlterIdentity +> | AlterColumnDropIdentity +> | AlterColumnDropColumnGeneration-} +> | DropColumn Name DropBehaviour +> | AddTableConstraintDef (Maybe [Name]) TableConstraint +> -- | AlterTableConstraintDef +> | DropTableConstraintDef [Name] DropBehaviour > deriving (Eq,Show,Read,Data,Typeable) > {-data ConstraintCharacteristics = @@ -597,8 +602,7 @@ I'm not sure if this is valid syntax or not. > deriving (Eq,Show,Read,Data,Typeable) > data IdentityWhen = -> GeneratedDefault -> | GeneratedAlways +> GeneratedAlways > | GeneratedByDefault > deriving (Eq,Show,Read,Data,Typeable) diff --git a/tools/Language/SQL/SimpleSQL/SQL2011Schema.lhs b/tools/Language/SQL/SimpleSQL/SQL2011Schema.lhs index 9378406..5614704 100644 --- a/tools/Language/SQL/SimpleSQL/SQL2011Schema.lhs +++ b/tools/Language/SQL/SimpleSQL/SQL2011Schema.lhs @@ -455,11 +455,6 @@ options GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ] -> ,(TestStatement SQL2011 "create table t (a int generated as identity);" -> $ CreateTable [Name "t"] -> [TableColumnDef $ ColumnDef (Name "a") (TypeName [Name "int"]) -> (Just $ IdentityColumnSpec GeneratedDefault []) []]) - > ,(TestStatement SQL2011 "create table t (a int generated always as identity);" > $ CreateTable [Name "t"] > [TableColumnDef $ ColumnDef (Name "a") (TypeName [Name "int"]) @@ -472,11 +467,11 @@ options > ,(TestStatement SQL2011 -> "create table t (a int generated as identity\n\ +> "create table t (a int generated always as identity\n\ > \ ( start with 5 increment by 5 maxvalue 500 minvalue 5 cycle ));" > $ CreateTable [Name "t"] > [TableColumnDef $ ColumnDef (Name "a") (TypeName [Name "int"]) -> (Just $ IdentityColumnSpec GeneratedDefault +> (Just $ IdentityColumnSpec GeneratedAlways > [SGOStartWith 5 > ,SGOIncrementBy 5 > ,SGOMaxValue 500 @@ -484,11 +479,11 @@ options > ,SGOCycle]) []]) > ,(TestStatement SQL2011 -> "create table t (a int generated as identity\n\ +> "create table t (a int generated always as identity\n\ > \ ( start with -4 no maxvalue no minvalue no cycle ));" > $ CreateTable [Name "t"] > [TableColumnDef $ ColumnDef (Name "a") (TypeName [Name "int"]) -> (Just $ IdentityColumnSpec GeneratedDefault +> (Just $ IdentityColumnSpec GeneratedAlways > [SGOStartWith (-4) > ,SGONoMaxValue > ,SGONoMinValue @@ -764,6 +759,7 @@ alter table t add a int unique not null check (a>0) > $ ColumnDef (Name "a") (TypeName [Name "int"]) Nothing [] > ) +todo: more add column 11.12 @@ -788,29 +784,39 @@ alter table t add a int unique not null check (a>0) ::= SET -alter table t alter column c set default ... -alter table t alter c set default ... + +> ,(TestStatement SQL2011 +> "alter table t alter column c set default 0" +> $ AlterTable [Name "t"] $ AlterColumnSetDefault (Name "c") +> $ NumLit "0") 11.14 ::= DROP DEFAULT -alter table t alter column c drop default +> ,(TestStatement SQL2011 +> "alter table t alter column c drop default" +> $ AlterTable [Name "t"] $ AlterColumnDropDefault (Name "c")) + 11.15 ::= SET NOT NULL -alter table t alter column c set not null +> ,(TestStatement SQL2011 +> "alter table t alter column c set not null" +> $ AlterTable [Name "t"] $ AlterColumnSetNotNull (Name "c")) 11.16 ::= DROP NOT NULL -alter table t alter column c drop not null +> ,(TestStatement SQL2011 +> "alter table t alter column c drop not null" +> $ AlterTable [Name "t"] $ AlterColumnDropNotNull (Name "c")) 11.17 @@ -827,7 +833,12 @@ alter table t alter column c drop not null ::= SET DATA TYPE -alter table t alter column c set data type int; +> ,(TestStatement SQL2011 +> "alter table t alter column c set data type int;" +> $ AlterTable [Name "t"] $ +> AlterColumnSetDataType (Name "c") (TypeName [Name "int"])) + + 11.20 @@ -838,6 +849,18 @@ alter table t alter column c set data type int; ::= SET GENERATED { ALWAYS | BY DEFAULT } +so you have to write set generated for alter identity? +and you have to use always or by default + +makes no sense: if you just want to restart you have to explicitly set +the always or by default? you can't just leave it unchanged? + +you don't write as identity like with create table, this is wrong: + +alter table t alter column c set generated always as identity + +but these are ok? + alter table t alter column c set generated always alter table t alter column c set generated by default @@ -846,10 +869,39 @@ alter table t alter column c set generated by default | SET -alter table t alter column c restart -alter table t alter column c restart with 4 (snl) +alter table t alter column c set generated always restart +alter table t alter column c set generated always restart with 4 -alter table t alter column c set increment by minvalue maxvalue cycle +you can just write restart + +but to write others you have to repeat set? each time? + +alter table t alter column c set generated always set increment by 5 set minvalue 0 set maxvalue 5 set cycle restart with 5 +(no set before the restart + +in create table, it looks like this: + +c int generated generated always as identity (increment by 5 minvalue 0 maxvalue 5 cycle restart with 5) + +why gratuituous differences??? + +is there no way to do this: + +alter table t alter column c set generated as (a * 3) +?? + +PLAN: TODO + +don't implement alter table alter column generated now + +review the syntax for generated in db2, oracle, sql server, postgres, others? + +observe which features are supported, and the consistency between +create table and alter table + +try to find some people to ask if the standard really is this much of +a mess or I have misunderstood the grammer, or maybe there is a good +reason for the inconsistencies? 11.21 @@ -859,6 +911,8 @@ alter table t alter column c set increment by minvalue maxvalue cycle alter table t alter column c drop identity +included in the generated plan above + 11.22 ::= @@ -866,22 +920,48 @@ alter table t alter column c drop identity alter table t alter column c drop expression +included in the generated plan above + + 11.23 ::= DROP [ COLUMN ] -alter table t alter drop column c +> ,(TestStatement SQL2011 +> "alter table t drop column c" +> $ AlterTable [Name "t"] $ +> DropColumn (Name "c") DefaultDropBehaviour) + +> ,(TestStatement SQL2011 +> "alter table t drop c cascade" +> $ AlterTable [Name "t"] $ +> DropColumn (Name "c") Cascade) + +> ,(TestStatement SQL2011 +> "alter table t drop c restrict" +> $ AlterTable [Name "t"] $ +> DropColumn (Name "c") Restrict) + -alter table t alter drop c restrict -alter table t alter drop c cascade 11.24 ::= ADD -todo +> ,(TestStatement SQL2011 +> "alter table t add constraint c unique (a,b)" +> $ AlterTable [Name "t"] $ +> AddTableConstraintDef (Just [Name "c"]) +> $ TableUniqueConstraint [Name "a", Name "b"]) + +> ,(TestStatement SQL2011 +> "alter table t add unique (a,b)" +> $ AlterTable [Name "t"] $ +> AddTableConstraintDef Nothing +> $ TableUniqueConstraint [Name "a", Name "b"]) + 11.25 ::= @@ -894,7 +974,15 @@ todo ::= DROP CONSTRAINT -todo +> ,(TestStatement SQL2011 +> "alter table t drop constraint c" +> $ AlterTable [Name "t"] $ +> DropTableConstraintDef [Name "c"] DefaultDropBehaviour) + +> ,(TestStatement SQL2011 +> "alter table t drop constraint c restrict" +> $ AlterTable [Name "t"] $ +> DropTableConstraintDef [Name "c"] Restrict) 11.27