Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support full-text search DDLs #111

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
fe57780
Implement CREATE/DROP/ALTER SEARCH INDEX
apstndb Sep 21, 2024
17228a1
Make STORED optional
apstndb Sep 21, 2024
a9c66b1
Support HIDDEN columns
apstndb Sep 21, 2024
3d8958c
Add TOKENLIST type
apstndb Sep 21, 2024
41d9fdc
Update testdata
apstndb Sep 21, 2024
403348a
Implement CREATE/DROP/ALTER SEARCH INDEX
apstndb Sep 21, 2024
6987a82
Add parser functions/methods
apstndb Oct 15, 2024
c159518
Add TOKENLIST as simple type
apstndb Oct 15, 2024
50c47ee
Fix HIDDEN implementation
apstndb Oct 15, 2024
d3d9be2
Update testdata
apstndb Oct 15, 2024
758b422
Fix ast of search index DDLs
apstndb Oct 15, 2024
48751bf
Fix some SQL()
apstndb Oct 15, 2024
f1c69e8
Add create_search_index_full.sql
apstndb Oct 15, 2024
51314c4
Implement SearchIndexOptions on GenericOptions
apstndb Oct 15, 2024
161e1da
Fix ast_test.go
apstndb Oct 15, 2024
fb67c7a
Update TestDDL
apstndb Oct 15, 2024
5a84774
Improve placement of GenericOptions/GenericOption
apstndb Oct 15, 2024
c3f3a97
Refine Find/FindBool
apstndb Oct 15, 2024
aecd271
Remove GeneratedColumnExpr.IsStored
apstndb Oct 15, 2024
2b459ad
Move SearchIndexOptions methods to correct place
apstndb Oct 15, 2024
57b212a
Fix comment
apstndb Oct 15, 2024
2127e0e
Refactor using Pos arithmetic
apstndb Oct 15, 2024
49f5dcc
Remove unnecessary comment
apstndb Oct 15, 2024
fdefffb
Revert unneeded change
apstndb Oct 15, 2024
b292b49
Merge remote-tracking branch 'origin/main' into feature/search-index-…
apstndb Oct 18, 2024
8671d6b
Add Options
apstndb Oct 18, 2024
a90745c
Migrate to parseCommaSeparatedList
apstndb Oct 18, 2024
4969ac5
Remove p.tryExpect() and p.tryExpectKeywordLike()
apstndb Oct 18, 2024
358d86c
Add *Field methods
apstndb Oct 18, 2024
86f449b
Update testdata
apstndb Oct 18, 2024
6164814
Merge remote-tracking branch 'origin/main' into feature/search-index-…
apstndb Oct 20, 2024
ce4aec8
Merge remote-tracking branch 'origin/main' into feature/search-index-…
apstndb Oct 20, 2024
33a2b05
Merge remote-tracking branch 'origin/main' into feature/search-index-…
apstndb Oct 22, 2024
79842b1
Fix some wording and ordering
apstndb Oct 22, 2024
beb79fb
Add parseIndexAlteration method
apstndb Oct 22, 2024
1e8cfe4
Remove unneeded newlines
apstndb Oct 22, 2024
ca9a1b6
Update ast/ast.go
apstndb Oct 24, 2024
e7f3191
Remove useless use of isnil
apstndb Oct 24, 2024
419e660
Merge remote-tracking branch 'origin/main' into feature/search-index-…
apstndb Oct 24, 2024
ebd86bd
Update testdata
apstndb Oct 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 85 additions & 4 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ func (RenameTable) isStatement() {}
func (CreateIndex) isStatement() {}
func (AlterIndex) isStatement() {}
func (DropIndex) isStatement() {}
func (CreateSearchIndex) isStatement() {}
func (DropSearchIndex) isStatement() {}
func (AlterSearchIndex) isStatement() {}
func (CreateView) isStatement() {}
func (DropView) isStatement() {}
func (CreateChangeStream) isStatement() {}
Expand Down Expand Up @@ -277,6 +280,9 @@ func (CreateIndex) isDDL() {}
func (AlterIndex) isDDL() {}
func (DropIndex) isDDL() {}
func (CreateView) isDDL() {}
func (CreateSearchIndex) isDDL() {}
func (DropSearchIndex) isDDL() {}
func (AlterSearchIndex) isDDL() {}
func (DropView) isDDL() {}
func (CreateChangeStream) isDDL() {}
func (AlterChangeStream) isDDL() {}
Expand Down Expand Up @@ -1720,10 +1726,11 @@ type CreateSequence struct {
// {{.Type | sql}} {{if .NotNull}}NOT NULL{{end}}
// {{.DefaultExpr | sqlOpt}}
// {{.GeneratedExpr | sqlOpt}}
// {{if .Hidden.Invalid | not)}}HIDDEN{{end}}
// {{.Options | sqlOpt}}
type ColumnDef struct {
// pos = Name.pos
// end = Options.end || GeneratedExpr.end || DefaultExpr.end || Null + 4 || Type.end
// end = Options.end || Hidden + 6 || GeneratedExpr.end || DefaultExpr.end || Null + 4 || Type.end

Null token.Pos // position of "NULL"

Expand All @@ -1732,6 +1739,7 @@ type ColumnDef struct {
NotNull bool
DefaultExpr *ColumnDefaultExpr // optional
GeneratedExpr *GeneratedColumnExpr // optional
Hidden token.Pos // InvalidPos if not hidden
Options *Options // optional
}

Expand All @@ -1750,17 +1758,31 @@ type ColumnDefaultExpr struct {

// GeneratedColumnExpr is generated column expression.
//
// AS ({{.Expr | sql}}) STORED
// AS ({{.Expr | sql}}) {{if .IsStored}}STORED{{end}}
type GeneratedColumnExpr struct {
// pos = As
// end = Stored + 6
// end = Stored + 6 || Rparen + 1

As token.Pos // position of "AS" keyword
Stored token.Pos // position of "STORED" keyword
Stored token.Pos // position of "STORED" keyword, optional
Rparen token.Pos // position of ")"

Expr Expr
}

// ColumnDefOption is options for column definition.
//
// OPTIONS(allow_commit_timestamp = {{if .AllowCommitTimestamp}}true{{else}null{{end}}})
type ColumnDefOptions struct {
// pos = Options
// end = Rparen + 1

Options token.Pos // position of "OPTIONS" keyword
Rparen token.Pos // position of ")"

AllowCommitTimestamp bool
}

// TableConstraint is table constraint in CREATE TABLE and ALTER TABLE.
//
// {{if .Name}}CONSTRAINT {{.Name}}{{end}}{{.Constraint | sql}}
Expand Down Expand Up @@ -2628,6 +2650,65 @@ type ArraySchemaType struct {
Item SchemaType // ScalarSchemaType or SizedSchemaType
}

// ================================================================================
//
// Search Index DDL
//
// ================================================================================

// CreateSearchIndex represents CREATE SEARCH INDEX statement
//
// CREATE SEARCH INDEX {{.Name | sql}}
// ON {{.TableName | sql}}
// ({{.TokenListPart | sqlJoin ", "}})
// {{.Storing | sqlOpt}}
// {{if .PartitionColumns}}PARTITION BY {{.PartitionColumns | sqlJoin ", "}}{{end}}
// {{.OrderBy | sqlOpt}}
// {{.Where | sqlOpt}}
// {{.Interleave | sqlOpt}}
// {{.Options | sqlOpt}}
type CreateSearchIndex struct {
// pos = Create
// end = (Options ?? Interleave ?? Where ?? OrderBy ?? PartitionColumns[$] ?? Storing).end || Rparen + 1

Create token.Pos

Name *Ident
TableName *Ident
TokenListPart []*Ident
Rparen token.Pos // position of ")" after TokenListPart
Storing *Storing // optional
PartitionColumns []*Ident // optional
OrderBy *OrderBy // optional
Where *Where // optional
Interleave *InterleaveIn // optional
Options *Options // optional
}

// DropSearchIndex represents DROP SEARCH INDEX statement.
//
// DROP SEARCH INDEX{{if .IfExists}}IF EXISTS{{end}} {{Name | sql}}
type DropSearchIndex struct {
// pos = Drop
// end = Name.end

Drop token.Pos
IfExists bool
Name *Ident
}

// AlterSearchIndex represents ALTER SEARCH INDEX statement.
//
// ALTER SEARCH INDEX {{.Name | sql}} {{.IndexAlteration | sql}}
type AlterSearchIndex struct {
// pos = Alter
// end = IndexAlteration.end

Alter token.Pos
Name *Ident
IndexAlteration IndexAlteration
}

// ================================================================================
//
// DML
Expand Down
3 changes: 3 additions & 0 deletions ast/ast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ func TestDDL(t *testing.T) {
DDL(&CreateIndex{}).isDDL()
DDL(&AlterIndex{}).isDDL()
DDL(&DropIndex{}).isDDL()
DDL(&CreateSearchIndex{}).isDDL()
DDL(&DropSearchIndex{}).isDDL()
DDL(&AlterSearchIndex{}).isDDL()
DDL(&CreateView{}).isDDL()
DDL(&DropView{}).isDDL()
DDL(&CreateChangeStream{}).isDDL()
Expand Down
1 change: 1 addition & 0 deletions ast/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ const (
TimestampTypeName ScalarTypeName = "TIMESTAMP"
NumericTypeName ScalarTypeName = "NUMERIC"
JSONTypeName ScalarTypeName = "JSON"
TokenListTypeName ScalarTypeName = "TOKENLIST"
)

type OnDeleteAction string
Expand Down
68 changes: 54 additions & 14 deletions ast/pos.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ func lastEnd[T Node](s []T) token.Pos {
return lastNode(s).End()
}

// firstValid returns the first valid token.Pos in arguments.
// This function corresponds to PosExpr ("||" PosExpr)* in ast.go
func firstValid(ps ...token.Pos) token.Pos {
for _, p := range ps {
if !p.Invalid() {
return p
}
}
return token.InvalidPos
}

// ================================================================================
//
// SELECT
Expand Down Expand Up @@ -593,26 +604,25 @@ func (c *ColumnDef) Pos() token.Pos {
}

func (c *ColumnDef) End() token.Pos {
if c.Options != nil {
return c.Options.End()
}
if c.GeneratedExpr != nil {
return c.GeneratedExpr.End()
}
if c.DefaultExpr != nil {
return c.DefaultExpr.End()
}
if !c.Null.Invalid() {
return c.Null + 4
}
return c.Type.End()
return firstValid(
firstValidEnd(c.Options),
c.Hidden.Add(6),
firstValidEnd(c.GeneratedExpr, c.DefaultExpr),
c.Null.Add(4),
c.Type.End(),
)
}

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 + 6 }
func (g *GeneratedColumnExpr) End() token.Pos {
return firstValid(g.Stored.Add(6), g.Rparen.Add(1))
}

func (c *ColumnDefOptions) Pos() token.Pos { return c.Options }
func (c *ColumnDefOptions) End() token.Pos { return c.Rparen + 1 }

func (c *TableConstraint) Pos() token.Pos {
if c.Name != nil {
Expand Down Expand Up @@ -917,6 +927,36 @@ func (c *ChangeStreamForTable) End() token.Pos {
return c.Rparen + 1
}

// ================================================================================
//
// Search Index DDL
//
// ================================================================================

func (c *CreateSearchIndex) Pos() token.Pos { return c.Create }

func (c *CreateSearchIndex) End() token.Pos {
return firstValid(
firstValidEnd(c.Options,
c.Interleave,
c.Where,
c.OrderBy,
lastNode(c.PartitionColumns),
c.Storing),
c.Rparen.Add(1))
}

func (d *DropSearchIndex) Pos() token.Pos {
return d.Drop
}

func (d *DropSearchIndex) End() token.Pos {
return d.Name.End()
}

func (a *AlterSearchIndex) Pos() token.Pos { return a.Alter }
func (a *AlterSearchIndex) End() token.Pos { return a.IndexAlteration.End() }

// ================================================================================
//
// DML
Expand Down
47 changes: 32 additions & 15 deletions ast/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -810,20 +810,12 @@ func (c *CreateView) SQL() string {
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 {
sql += " NOT NULL"
}
if c.DefaultExpr != nil {
sql += " " + c.DefaultExpr.SQL()
}
if c.GeneratedExpr != nil {
sql += " " + c.GeneratedExpr.SQL()
}
if c.Options != nil {
sql += " " + c.Options.SQL()
}
return sql
return c.Name.SQL() + " " + c.Type.SQL() +
strOpt(c.NotNull, " NOT NULL") +
sqlOpt(" ", c.DefaultExpr, "") +
sqlOpt(" ", c.GeneratedExpr, "") +
strOpt(!c.Hidden.Invalid(), " HIDDEN") +
sqlOpt(" ", c.Options, "")
}

func (c *TableConstraint) SQL() string {
Expand Down Expand Up @@ -868,7 +860,7 @@ func (c *ColumnDefaultExpr) SQL() string {
}

func (g *GeneratedColumnExpr) SQL() string {
return "AS (" + g.Expr.SQL() + ") STORED"
return "AS (" + g.Expr.SQL() + ")" + strOpt(!g.Stored.Invalid(), " STORED")
}

func (i *IndexKey) SQL() string {
Expand Down Expand Up @@ -1267,6 +1259,31 @@ func (a *ArraySchemaType) SQL() string {
return "ARRAY<" + a.Item.SQL() + ">"
}

// ================================================================================
//
// Search Index DDL
//
// ================================================================================

func (c *CreateSearchIndex) SQL() string {
return "CREATE SEARCH INDEX " + c.Name.SQL() + " ON " + c.TableName.SQL() +
"(" + sqlJoin(c.TokenListPart, ", ") + ")" +
sqlOpt(" ", c.Storing, "") +
strOpt(len(c.PartitionColumns) > 0, " PARTITION BY "+sqlJoin(c.PartitionColumns, ", ")) +
sqlOpt(" ", c.OrderBy, "") +
sqlOpt(" ", c.Where, "") +
sqlOpt("", c.Interleave, "") +
sqlOpt(" ", c.Options, "")
}

func (d *DropSearchIndex) SQL() string {
return "DROP SEARCH INDEX " + strOpt(d.IfExists, "IF EXISTS ") + d.Name.SQL()
}

func (a *AlterSearchIndex) SQL() string {
return "ALTER SEARCH INDEX " + a.Name.SQL() + " " + a.IndexAlteration.SQL()
}

// ================================================================================
//
// DML
Expand Down
Loading
Loading