Repository: cloudspannerecosystem/memefish (go)

Issue:
Support DROP VIEW statement
`DROP VIEW` statement is not supporetd.

https://cloud.google.com/spanner/docs/reference/standard-sql/data-definition-language#drop-view

```
DROP VIEW view_name
```

Related: #115 

Pull request description:
Implement DROP VIEW statement
This PR implements `DROP VIEW` statement.

fixes #126 

Patch:
diff --git a/ast/ast.go b/ast/ast.go
index c123d13..1d8c21e 100644
--- a/ast/ast.go
+++ b/ast/ast.go
@@ -55,6 +55,7 @@ func (CreateDatabase) isStatement()     {}
 func (CreateTable) isStatement()        {}
 func (CreateSequence) isStatement()     {}
 func (CreateView) isStatement()         {}
+func (DropView) isStatement()           {}
 func (CreateIndex) isStatement()        {}
 func (CreateVectorIndex) isStatement()  {}
 func (CreateRole) isStatement()         {}
@@ -256,6 +257,7 @@ type DDL interface {
 func (CreateDatabase) isDDL()     {}
 func (CreateTable) isDDL()        {}
 func (CreateView) isDDL()         {}
+func (DropView) isDDL()           {}
 func (CreateSequence) isDDL()     {}
 func (AlterTable) isDDL()         {}
 func (DropTable) isDDL()          {}
@@ -1676,7 +1678,7 @@ type ColumnDefaultExpr struct {
 //	AS ({{.Expr | sql}}) STORED
 type GeneratedColumnExpr struct {
 	// pos = As
-	// end = Stored
+	// end = Stored + 6
 
 	As     token.Pos // position of "AS" keyword
 	Stored token.Pos // position of "STORED" keyword
@@ -1797,6 +1799,18 @@ type CreateView struct {
 	Query        QueryExpr
 }
 
+// DropView is DROP VIEW statement node.
+//
+//	DROP VIEW {{.Name | sql}}
+type DropView struct {
+	// pos = Drop
+	// end = Name.end
+
+	Drop token.Pos
+
+	Name *Ident
+}
+
 // AlterTable is ALTER TABLE statement node.
 //
 //	ALTER TABLE {{.Name | sql}} {{.TableAlteration | sql}}
diff --git a/ast/pos.go b/ast/pos.go
index f8d86cd..12fe577 100644
--- a/ast/pos.go
+++ b/ast/pos.go
@@ -574,6 +574,9 @@ func (c *CreateView) End() token.Pos {
 	return c.Query.End()
 }
 
+func (d *DropView) Pos() token.Pos { return d.Drop }
+func (d *DropView) End() token.Pos { return d.Name.End() }
+
 func (c *ColumnDef) Pos() token.Pos {
 	return c.Name.Pos()
 }
@@ -598,7 +601,7 @@ func (g *ColumnDefaultExpr) Pos() token.Pos { return g.Default }
 func (g *ColumnDefaultExpr) End() token.Pos { return g.Rparen }
 
 func (g *GeneratedColumnExpr) Pos() token.Pos { return g.As }
-func (g *GeneratedColumnExpr) End() token.Pos { return g.Stored }
+func (g *GeneratedColumnExpr) End() token.Pos { return g.Stored + 6 }
 
 func (c *TableConstraint) Pos() token.Pos {
 	if c.Name != nil {
diff --git a/ast/sql.go b/ast/sql.go
index 2bdcb60..34c16ec 100644
--- a/ast/sql.go
+++ b/ast/sql.go
@@ -828,6 +828,8 @@ func (c *CreateView) SQL() string {
 	return sql
 }
 
+func (d *DropView) SQL() string { return "DROP VIEW " + d.Name.SQL() }
+
 func (c *ColumnDef) SQL() string {
 	sql := c.Name.SQL() + " " + c.Type.SQL()
 	if c.NotNull {
diff --git a/parser.go b/parser.go
index fc59264..eefa17b 100644
--- a/parser.go
+++ b/parser.go
@@ -2160,6 +2160,8 @@ func (p *Parser) parseDDL() ast.DDL {
 			return p.parseDropVectorIndex(pos)
 		case p.Token.IsKeywordLike("SEQUENCE"):
 			return p.parseDropSequence(pos)
+		case p.Token.IsKeywordLike("VIEW"):
+			return p.parseDropView(pos)
 		case p.Token.IsKeywordLike("ROLE"):
 			return p.parseDropRole(pos)
 		case p.Token.IsKeywordLike("CHANGE"):
@@ -2314,6 +2316,16 @@ func (p *Parser) parseCreateView(pos token.Pos) *ast.CreateView {
 	}
 }
 
+func (p *Parser) parseDropView(pos token.Pos) *ast.DropView {
+	p.expectKeywordLike("VIEW")
+	name := p.parseIdent()
+
+	return &ast.DropView{
+		Drop: pos,
+		Name: name,
+	}
+}
+
 func (p *Parser) parseColumnDef() *ast.ColumnDef {
 	name := p.parseIdent()
 	t, notNull, null := p.parseTypeNotNull()
@@ -2424,15 +2436,15 @@ func (p *Parser) tryParseGeneratedColumnExpr() *ast.GeneratedColumnExpr {
 		return nil
 	}
 
-	posAs := p.expect("AS").Pos
+	pos := p.expect("AS").Pos
 	p.expect("(")
 	expr := p.parseExpr()
 	p.expect(")")
-	posEnd := p.expectKeywordLike("STORED").End
+	stored := p.expectKeywordLike("STORED").Pos
 
 	return &ast.GeneratedColumnExpr{
-		As:     posAs,
-		Stored: posEnd,
+		As:     pos,
+		Stored: stored,
 		Expr:   expr,
 	}
 }
@@ -3237,7 +3249,7 @@ func (p *Parser) parseSchemaType() ast.SchemaType {
 		pos := p.expect("ARRAY").Pos
 		p.expect("<")
 		t := p.parseScalarSchemaType()
-		end := p.expect(">").End
+		end := p.expect(">").Pos
 		return &ast.ArraySchemaType{
 			Array: pos,
 			Gt:    end,


Test patch:
diff --git a/ast/ast_test.go b/ast/ast_test.go
index dbf0954..4c974d3 100644
--- a/ast/ast_test.go
+++ b/ast/ast_test.go
@@ -136,6 +136,7 @@ func TestDDL(t *testing.T) {
 	DDL(&AlterSequence{}).isDDL()
 	DDL(&DropSequence{}).isDDL()
 	DDL(&CreateView{}).isDDL()
+	DDL(&DropView{}).isDDL()
 	DDL(&AlterTable{}).isDDL()
 	DDL(&DropTable{}).isDDL()
 	DDL(&CreateIndex{}).isDDL()
diff --git a/testdata/input/ddl/drop_view.sql b/testdata/input/ddl/drop_view.sql
new file mode 100644
index 0000000..05bd489
--- /dev/null
+++ b/testdata/input/ddl/drop_view.sql
@@ -0,0 +1,1 @@
+DROP VIEW SingersView
\ No newline at end of file
diff --git a/testdata/result/ddl/alter_table_add_column_with_if_expression.sql.txt b/testdata/result/ddl/alter_table_add_column_with_if_expression.sql.txt
index be16d69..6624b33 100644
--- a/testdata/result/ddl/alter_table_add_column_with_if_expression.sql.txt
+++ b/testdata/result/ddl/alter_table_add_column_with_if_expression.sql.txt
@@ -26,7 +26,7 @@ ALTER TABLE foo ADD COLUMN expired_at TIMESTAMP AS (IF (status != "OPEN" AND sta
       DefaultExpr:   (*ast.ColumnDefaultExpr)(nil),
       GeneratedExpr: &ast.GeneratedColumnExpr{
         As:     48,
-        Stored: 159,
+        Stored: 153,
         Expr:   &ast.CallExpr{
           Rparen: 150,
           Func:   &ast.Ident{
diff --git a/testdata/result/ddl/create_table.sql.txt b/testdata/result/ddl/create_table.sql.txt
index 6ae97cc..03c0ed7 100644
--- a/testdata/result/ddl/create_table.sql.txt
+++ b/testdata/result/ddl/create_table.sql.txt
@@ -119,7 +119,7 @@ create table foo (
       DefaultExpr:   (*ast.ColumnDefaultExpr)(nil),
       GeneratedExpr: &ast.GeneratedColumnExpr{
         As:     150,
-        Stored: 178,
+        Stored: 172,
         Expr:   &ast.CallExpr{
           Rparen: 169,
           Func:   &ast.Ident{
diff --git a/testdata/result/ddl/create_table_types.sql.txt b/testdata/result/ddl/create_table_types.sql.txt
index dbf09c3..3afd6e7 100644
--- a/testdata/result/ddl/create_table_types.sql.txt
+++ b/testdata/result/ddl/create_table_types.sql.txt
@@ -217,7 +217,7 @@ create table types (
       },
       Type: &ast.ArraySchemaType{
         Array: 174,
-        Gt:    185,
+        Gt:    184,
         Item:  &ast.ScalarSchemaType{
           NamePos: 180,
           Name:    "BOOL",
@@ -237,7 +237,7 @@ create table types (
       },
       Type: &ast.ArraySchemaType{
         Array: 193,
-        Gt:    210,
+        Gt:    209,
         Item:  &ast.SizedSchemaType{
           NamePos: 199,
           Rparen:  208,
diff --git a/testdata/result/ddl/drop_view.sql.txt b/testdata/result/ddl/drop_view.sql.txt
new file mode 100644
index 0000000..7003638
--- /dev/null
+++ b/testdata/result/ddl/drop_view.sql.txt
@@ -0,0 +1,14 @@
+--- drop_view.sql
+DROP VIEW SingersView
+--- AST
+&ast.DropView{
+  Drop: 0,
+  Name: &ast.Ident{
+    NamePos: 10,
+    NameEnd: 21,
+    Name:    "SingersView",
+  },
+}
+
+--- SQL
+DROP VIEW SingersView
diff --git a/testdata/result/statement/alter_table_add_column_with_if_expression.sql.txt b/testdata/result/statement/alter_table_add_column_with_if_expression.sql.txt
index be16d69..6624b33 100644
--- a/testdata/result/statement/alter_table_add_column_with_if_expression.sql.txt
+++ b/testdata/result/statement/alter_table_add_column_with_if_expression.sql.txt
@@ -26,7 +26,7 @@ ALTER TABLE foo ADD COLUMN expired_at TIMESTAMP AS (IF (status != "OPEN" AND sta
       DefaultExpr:   (*ast.ColumnDefaultExpr)(nil),
       GeneratedExpr: &ast.GeneratedColumnExpr{
         As:     48,
-        Stored: 159,
+        Stored: 153,
         Expr:   &ast.CallExpr{
           Rparen: 150,
           Func:   &ast.Ident{
diff --git a/testdata/result/statement/create_table.sql.txt b/testdata/result/statement/create_table.sql.txt
index 6ae97cc..03c0ed7 100644
--- a/testdata/result/statement/create_table.sql.txt
+++ b/testdata/result/statement/create_table.sql.txt
@@ -119,7 +119,7 @@ create table foo (
       DefaultExpr:   (*ast.ColumnDefaultExpr)(nil),
       GeneratedExpr: &ast.GeneratedColumnExpr{
         As:     150,
-        Stored: 178,
+        Stored: 172,
         Expr:   &ast.CallExpr{
           Rparen: 169,
           Func:   &ast.Ident{
diff --git a/testdata/result/statement/create_table_types.sql.txt b/testdata/result/statement/create_table_types.sql.txt
index dbf09c3..3afd6e7 100644
--- a/testdata/result/statement/create_table_types.sql.txt
+++ b/testdata/result/statement/create_table_types.sql.txt
@@ -217,7 +217,7 @@ create table types (
       },
       Type: &ast.ArraySchemaType{
         Array: 174,
-        Gt:    185,
+        Gt:    184,
         Item:  &ast.ScalarSchemaType{
           NamePos: 180,
           Name:    "BOOL",
@@ -237,7 +237,7 @@ create table types (
       },
       Type: &ast.ArraySchemaType{
         Array: 193,
-        Gt:    210,
+        Gt:    209,
         Item:  &ast.SizedSchemaType{
           NamePos: 199,
           Rparen:  208,
diff --git a/testdata/result/statement/drop_view.sql.txt b/testdata/result/statement/drop_view.sql.txt
new file mode 100644
index 0000000..7003638
--- /dev/null
+++ b/testdata/result/statement/drop_view.sql.txt
@@ -0,0 +1,14 @@
+--- drop_view.sql
+DROP VIEW SingersView
+--- AST
+&ast.DropView{
+  Drop: 0,
+  Name: &ast.Ident{
+    NamePos: 10,
+    NameEnd: 21,
+    Name:    "SingersView",
+  },
+}
+
+--- SQL
+DROP VIEW SingersView