diff --git a/parser/ast.go b/parser/ast.go index 76a794c..36be3a0 100644 --- a/parser/ast.go +++ b/parser/ast.go @@ -5903,6 +5903,7 @@ func (s *SystemFlushExpr) Accept(visitor ASTVisitor) error { type SystemReloadExpr struct { ReloadPos Pos StatementEnd Pos + OnCluster *ClusterClause Dictionary *TableIdentifier Type string } @@ -5918,6 +5919,11 @@ func (s *SystemReloadExpr) End() Pos { func (s *SystemReloadExpr) Accept(visitor ASTVisitor) error { visitor.Enter(s) defer visitor.Leave(s) + if s.OnCluster != nil { + if err := s.OnCluster.Accept(visitor); err != nil { + return err + } + } if s.Dictionary != nil { if err := s.Dictionary.Accept(visitor); err != nil { return err diff --git a/parser/format.go b/parser/format.go index e704c4a..e221f75 100644 --- a/parser/format.go +++ b/parser/format.go @@ -2511,6 +2511,10 @@ func (s *SystemFlushExpr) FormatSQL(formatter *Formatter) { func (s *SystemReloadExpr) FormatSQL(formatter *Formatter) { formatter.WriteString("RELOAD ") formatter.WriteString(s.Type) + if s.OnCluster != nil { + formatter.WriteByte(whitespace) + formatter.WriteExpr(s.OnCluster) + } if s.Dictionary != nil { formatter.WriteByte(whitespace) formatter.WriteExpr(s.Dictionary) diff --git a/parser/parse_system.go b/parser/parse_system.go index 98cb65f..f75f091 100644 --- a/parser/parse_system.go +++ b/parser/parse_system.go @@ -67,39 +67,65 @@ func (p *Parser) parseSystemReloadExpr(pos Pos) (*SystemReloadExpr, error) { return nil, err } + var typ string + var statementEnd Pos + // Only RELOAD DICTIONARY takes a dictionary name. + hasDictionaryName := false switch { case p.matchKeyword(KeywordDictionaries): - curToken := p.current() + typ = KeywordDictionaries + statementEnd = p.current().End + _ = p.lexer.consumeToken() + case p.matchKeyword(KeywordDictionary): + typ = KeywordDictionary + statementEnd = p.current().End + hasDictionaryName = true _ = p.lexer.consumeToken() - return &SystemReloadExpr{ - ReloadPos: pos, - StatementEnd: curToken.End, - Type: KeywordDictionaries, - }, nil - case p.tryConsumeKeywords(KeywordDictionary): - dictionary, err := p.parseTableIdentifier(p.Pos()) - if err != nil { - return nil, err - } - return &SystemReloadExpr{ - ReloadPos: pos, - StatementEnd: dictionary.End(), - Type: KeywordDictionary, - Dictionary: dictionary, - }, nil case p.tryConsumeKeywords(KeywordEmbedded): - curToken := p.current() + typ = "EMBEDDED DICTIONARIES" + statementEnd = p.current().End if err := p.expectKeyword(KeywordDictionaries); err != nil { return nil, err } - return &SystemReloadExpr{ - ReloadPos: pos, - StatementEnd: curToken.End, - Type: "EMBEDDED DICTIONARIES", - }, nil default: - return nil, fmt.Errorf("expected DICTIONARIES|CONFIG") + return nil, fmt.Errorf("expected DICTIONARIES|DICTIONARY|EMBEDDED") } + + onCluster, err := p.tryParseClusterClause(p.Pos()) + if err != nil { + return nil, err + } + if onCluster != nil { + statementEnd = onCluster.End() + } + + var dictionary *TableIdentifier + if hasDictionaryName { + dictionary, err = p.parseTableIdentifier(p.Pos()) + if err != nil { + return nil, err + } + statementEnd = dictionary.End() + + // ClickHouse also accepts ON CLUSTER after the dictionary name. + if onCluster == nil { + onCluster, err = p.tryParseClusterClause(p.Pos()) + if err != nil { + return nil, err + } + if onCluster != nil { + statementEnd = onCluster.End() + } + } + } + + return &SystemReloadExpr{ + ReloadPos: pos, + StatementEnd: statementEnd, + OnCluster: onCluster, + Type: typ, + Dictionary: dictionary, + }, nil } func (p *Parser) parseSystemSyncExpr(pos Pos) (*SystemSyncExpr, error) { diff --git a/parser/testdata/ddl/format/beautify/systems.sql b/parser/testdata/ddl/format/beautify/systems.sql index 2d48c79..18ba086 100644 --- a/parser/testdata/ddl/format/beautify/systems.sql +++ b/parser/testdata/ddl/format/beautify/systems.sql @@ -2,9 +2,21 @@ SYSTEM FLUSH LOGS; SYSTEM DROP UNCOMPRESSED CACHE; SYSTEM DROP FILESYSTEM CACHE; +SYSTEM RELOAD DICTIONARIES; +SYSTEM RELOAD DICTIONARIES ON CLUSTER akvorado; +SYSTEM RELOAD DICTIONARY akvorado.asns; +SYSTEM RELOAD DICTIONARY ON CLUSTER akvorado akvorado.asns; +SYSTEM RELOAD DICTIONARY akvorado.asns ON CLUSTER akvorado; +SYSTEM RELOAD EMBEDDED DICTIONARIES ON CLUSTER akvorado; -- Beautify SQL: SYSTEM FLUSH LOGS; SYSTEM DROP UNCOMPRESSED CACHE; SYSTEM DROP FILESYSTEM CACHE; +SYSTEM RELOAD DICTIONARIES; +SYSTEM RELOAD DICTIONARIES ON CLUSTER akvorado; +SYSTEM RELOAD DICTIONARY akvorado.asns; +SYSTEM RELOAD DICTIONARY ON CLUSTER akvorado akvorado.asns; +SYSTEM RELOAD DICTIONARY ON CLUSTER akvorado akvorado.asns; +SYSTEM RELOAD EMBEDDED DICTIONARIES ON CLUSTER akvorado; diff --git a/parser/testdata/ddl/format/systems.sql b/parser/testdata/ddl/format/systems.sql index a4b7ec6..974f5de 100644 --- a/parser/testdata/ddl/format/systems.sql +++ b/parser/testdata/ddl/format/systems.sql @@ -2,9 +2,21 @@ SYSTEM FLUSH LOGS; SYSTEM DROP UNCOMPRESSED CACHE; SYSTEM DROP FILESYSTEM CACHE; +SYSTEM RELOAD DICTIONARIES; +SYSTEM RELOAD DICTIONARIES ON CLUSTER akvorado; +SYSTEM RELOAD DICTIONARY akvorado.asns; +SYSTEM RELOAD DICTIONARY ON CLUSTER akvorado akvorado.asns; +SYSTEM RELOAD DICTIONARY akvorado.asns ON CLUSTER akvorado; +SYSTEM RELOAD EMBEDDED DICTIONARIES ON CLUSTER akvorado; -- Format SQL: SYSTEM FLUSH LOGS; SYSTEM DROP UNCOMPRESSED CACHE; SYSTEM DROP FILESYSTEM CACHE; +SYSTEM RELOAD DICTIONARIES; +SYSTEM RELOAD DICTIONARIES ON CLUSTER akvorado; +SYSTEM RELOAD DICTIONARY akvorado.asns; +SYSTEM RELOAD DICTIONARY ON CLUSTER akvorado akvorado.asns; +SYSTEM RELOAD DICTIONARY ON CLUSTER akvorado akvorado.asns; +SYSTEM RELOAD EMBEDDED DICTIONARIES ON CLUSTER akvorado; diff --git a/parser/testdata/ddl/output/systems.sql.golden.json b/parser/testdata/ddl/output/systems.sql.golden.json index 6b87597..0a5b767 100644 --- a/parser/testdata/ddl/output/systems.sql.golden.json +++ b/parser/testdata/ddl/output/systems.sql.golden.json @@ -23,5 +23,136 @@ "StatementEnd": 79, "Type": "FILESYSTEM CACHE" } + }, + { + "SystemPos": 81, + "Expr": { + "ReloadPos": 88, + "StatementEnd": 107, + "OnCluster": null, + "Dictionary": null, + "Type": "DICTIONARIES" + } + }, + { + "SystemPos": 109, + "Expr": { + "ReloadPos": 116, + "StatementEnd": 155, + "OnCluster": { + "OnPos": 136, + "Expr": { + "Name": "akvorado", + "QuoteType": 1, + "NamePos": 147, + "NameEnd": 155 + } + }, + "Dictionary": null, + "Type": "DICTIONARIES" + } + }, + { + "SystemPos": 157, + "Expr": { + "ReloadPos": 164, + "StatementEnd": 195, + "OnCluster": null, + "Dictionary": { + "Database": { + "Name": "akvorado", + "QuoteType": 1, + "NamePos": 182, + "NameEnd": 190 + }, + "Table": { + "Name": "asns", + "QuoteType": 1, + "NamePos": 191, + "NameEnd": 195 + } + }, + "Type": "DICTIONARY" + } + }, + { + "SystemPos": 197, + "Expr": { + "ReloadPos": 204, + "StatementEnd": 255, + "OnCluster": { + "OnPos": 222, + "Expr": { + "Name": "akvorado", + "QuoteType": 1, + "NamePos": 233, + "NameEnd": 241 + } + }, + "Dictionary": { + "Database": { + "Name": "akvorado", + "QuoteType": 1, + "NamePos": 242, + "NameEnd": 250 + }, + "Table": { + "Name": "asns", + "QuoteType": 1, + "NamePos": 251, + "NameEnd": 255 + } + }, + "Type": "DICTIONARY" + } + }, + { + "SystemPos": 257, + "Expr": { + "ReloadPos": 264, + "StatementEnd": 315, + "OnCluster": { + "OnPos": 296, + "Expr": { + "Name": "akvorado", + "QuoteType": 1, + "NamePos": 307, + "NameEnd": 315 + } + }, + "Dictionary": { + "Database": { + "Name": "akvorado", + "QuoteType": 1, + "NamePos": 282, + "NameEnd": 290 + }, + "Table": { + "Name": "asns", + "QuoteType": 1, + "NamePos": 291, + "NameEnd": 295 + } + }, + "Type": "DICTIONARY" + } + }, + { + "SystemPos": 317, + "Expr": { + "ReloadPos": 324, + "StatementEnd": 372, + "OnCluster": { + "OnPos": 353, + "Expr": { + "Name": "akvorado", + "QuoteType": 1, + "NamePos": 364, + "NameEnd": 372 + } + }, + "Dictionary": null, + "Type": "EMBEDDED DICTIONARIES" + } } ] \ No newline at end of file diff --git a/parser/testdata/ddl/systems.sql b/parser/testdata/ddl/systems.sql index 9dab08e..a633f88 100644 --- a/parser/testdata/ddl/systems.sql +++ b/parser/testdata/ddl/systems.sql @@ -1,3 +1,9 @@ SYSTEM FLUSH LOGS; SYSTEM DROP UNCOMPRESSED CACHE; SYSTEM DROP FILESYSTEM CACHE; +SYSTEM RELOAD DICTIONARIES; +SYSTEM RELOAD DICTIONARIES ON CLUSTER akvorado; +SYSTEM RELOAD DICTIONARY akvorado.asns; +SYSTEM RELOAD DICTIONARY ON CLUSTER akvorado akvorado.asns; +SYSTEM RELOAD DICTIONARY akvorado.asns ON CLUSTER akvorado; +SYSTEM RELOAD EMBEDDED DICTIONARIES ON CLUSTER akvorado; diff --git a/parser/walk.go b/parser/walk.go index dbeb68e..e129a35 100644 --- a/parser/walk.go +++ b/parser/walk.go @@ -542,6 +542,9 @@ func Walk(node Expr, fn WalkFunc) bool { return false } case *SystemReloadExpr: + if !Walk(n.OnCluster, fn) { + return false + } if !Walk(n.Dictionary, fn) { return false }