Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,7 @@ type ShowQuery struct {
Like string `json:"like,omitempty"`
Where Expression `json:"where,omitempty"`
Limit Expression `json:"limit,omitempty"`
Format string `json:"format,omitempty"`
}

func (s *ShowQuery) Pos() token.Position { return s.Position }
Expand Down Expand Up @@ -780,7 +781,9 @@ func (r *RenameQuery) statementNode() {}
// ExchangeQuery represents an EXCHANGE TABLES statement.
type ExchangeQuery struct {
Position token.Position `json:"-"`
Database1 string `json:"database1,omitempty"`
Table1 string `json:"table1"`
Database2 string `json:"database2,omitempty"`
Table2 string `json:"table2"`
OnCluster string `json:"on_cluster,omitempty"`
}
Expand Down
2 changes: 2 additions & 0 deletions internal/explain/explain.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ func Node(sb *strings.Builder, node interface{}, depth int) {
explainDropQuery(sb, n, indent, depth)
case *ast.RenameQuery:
explainRenameQuery(sb, n, indent, depth)
case *ast.ExchangeQuery:
explainExchangeQuery(sb, n, indent)
case *ast.SetQuery:
explainSetQuery(sb, indent)
case *ast.SystemQuery:
Expand Down
102 changes: 80 additions & 22 deletions internal/explain/statements.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,37 @@ func explainRenameQuery(sb *strings.Builder, n *ast.RenameQuery, indent string,
}
}

func explainExchangeQuery(sb *strings.Builder, n *ast.ExchangeQuery, indent string) {
if n == nil {
fmt.Fprintf(sb, "%s*ast.ExchangeQuery\n", indent)
return
}
// Count identifiers: 2 per table (db + table if qualified, or just table)
// EXCHANGE TABLES outputs as "Rename" in ClickHouse
children := 0
if n.Database1 != "" {
children += 2 // db1 + table1
} else {
children += 1 // just table1
}
if n.Database2 != "" {
children += 2 // db2 + table2
} else {
children += 1 // just table2
}
fmt.Fprintf(sb, "%sRename (children %d)\n", indent, children)
// First table
if n.Database1 != "" {
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Database1)
}
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Table1)
// Second table
if n.Database2 != "" {
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Database2)
}
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Table2)
}

func explainSetQuery(sb *strings.Builder, indent string) {
fmt.Fprintf(sb, "%sSet\n", indent)
}
Expand Down Expand Up @@ -554,18 +585,39 @@ func explainShowQuery(sb *strings.Builder, n *ast.ShowQuery, indent string) {

// SHOW CREATE TABLE has special output format with database and table identifiers
if n.ShowType == ast.ShowCreate && (n.Database != "" || n.From != "") {
// Format: ShowCreateTableQuery database table (children 2)
// Format: ShowCreateTableQuery database table (children 2) or with FORMAT
name := n.From
if n.Database != "" && n.From != "" {
fmt.Fprintf(sb, "%sShowCreateTableQuery %s %s (children 2)\n", indent, n.Database, n.From)
children := 2
if n.Format != "" {
children = 3
}
fmt.Fprintf(sb, "%sShowCreateTableQuery %s %s (children %d)\n", indent, n.Database, n.From, children)
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Database)
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.From)
if n.Format != "" {
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format)
}
} else if n.From != "" {
fmt.Fprintf(sb, "%sShowCreateTableQuery %s (children 1)\n", indent, name)
children := 1
if n.Format != "" {
children = 2
}
fmt.Fprintf(sb, "%sShowCreateTableQuery %s (children %d)\n", indent, name, children)
fmt.Fprintf(sb, "%s Identifier %s\n", indent, name)
if n.Format != "" {
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format)
}
} else if n.Database != "" {
fmt.Fprintf(sb, "%sShowCreateTableQuery %s (children 1)\n", indent, n.Database)
children := 1
if n.Format != "" {
children = 2
}
fmt.Fprintf(sb, "%sShowCreateTableQuery %s (children %d)\n", indent, n.Database, children)
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Database)
if n.Format != "" {
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format)
}
} else {
fmt.Fprintf(sb, "%sShow%s\n", indent, showType)
}
Expand Down Expand Up @@ -714,17 +766,20 @@ func explainDetachQuery(sb *strings.Builder, n *ast.DetachQuery, indent string)
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Table)
return
}
// Single name (table only or database only for DETACH DATABASE)
name := n.Table
if name == "" {
name = n.Database
// DETACH DATABASE db: Database set, Table empty -> "DetachQuery db (children 1)"
if n.Database != "" && n.Table == "" {
fmt.Fprintf(sb, "%sDetachQuery %s (children 1)\n", indent, n.Database)
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Database)
return
}
if name != "" {
fmt.Fprintf(sb, "%sDetachQuery %s (children 1)\n", indent, name)
fmt.Fprintf(sb, "%s Identifier %s\n", indent, name)
} else {
fmt.Fprintf(sb, "%sDetachQuery\n", indent)
// DETACH TABLE table: Database empty, Table set -> "DetachQuery table (children 1)"
if n.Table != "" {
fmt.Fprintf(sb, "%sDetachQuery %s (children 1)\n", indent, n.Table)
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Table)
return
}
// No name
fmt.Fprintf(sb, "%sDetachQuery\n", indent)
}

func explainAttachQuery(sb *strings.Builder, n *ast.AttachQuery, indent string) {
Expand All @@ -736,17 +791,20 @@ func explainAttachQuery(sb *strings.Builder, n *ast.AttachQuery, indent string)
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Table)
return
}
// Single name (table only or database only for ATTACH DATABASE)
name := n.Table
if name == "" {
name = n.Database
// ATTACH DATABASE db: Database set, Table empty -> "AttachQuery db (children 1)"
if n.Database != "" && n.Table == "" {
fmt.Fprintf(sb, "%sAttachQuery %s (children 1)\n", indent, n.Database)
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Database)
return
}
if name != "" {
fmt.Fprintf(sb, "%sAttachQuery %s (children 1)\n", indent, name)
fmt.Fprintf(sb, "%s Identifier %s\n", indent, name)
} else {
fmt.Fprintf(sb, "%sAttachQuery\n", indent)
// ATTACH TABLE table: Database empty, Table set -> "AttachQuery table (children 1)" (single space)
if n.Table != "" {
fmt.Fprintf(sb, "%sAttachQuery %s (children 1)\n", indent, n.Table)
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Table)
return
}
// No name
fmt.Fprintf(sb, "%sAttachQuery\n", indent)
}

func explainAlterQuery(sb *strings.Builder, n *ast.AlterQuery, indent string, depth int) {
Expand Down
71 changes: 53 additions & 18 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -3652,6 +3652,15 @@ func (p *Parser) parseShow() ast.Statement {
show.Limit = p.parseExpression(LOWEST)
}

// Parse FORMAT clause
if p.currentIs(token.FORMAT) {
p.nextToken()
if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() {
show.Format = p.current.Value
p.nextToken()
}
}

return show
}

Expand Down Expand Up @@ -3931,15 +3940,29 @@ func (p *Parser) parseExchange() *ast.ExchangeQuery {
return nil
}

// Parse first table name (can start with a number in ClickHouse)
exchange.Table1 = p.parseIdentifierName()
// Parse first table name (can be database.table)
name1 := p.parseIdentifierName()
if p.currentIs(token.DOT) {
p.nextToken()
exchange.Database1 = name1
exchange.Table1 = p.parseIdentifierName()
} else {
exchange.Table1 = name1
}

if !p.expect(token.AND) {
return nil
}

// Parse second table name (can start with a number in ClickHouse)
exchange.Table2 = p.parseIdentifierName()
// Parse second table name (can be database.table)
name2 := p.parseIdentifierName()
if p.currentIs(token.DOT) {
p.nextToken()
exchange.Database2 = name2
exchange.Table2 = p.parseIdentifierName()
} else {
exchange.Table2 = name2
}

// Handle ON CLUSTER
if p.currentIs(token.ON) {
Expand All @@ -3960,19 +3983,25 @@ func (p *Parser) parseDetach() *ast.DetachQuery {

p.nextToken() // skip DETACH

// Skip optional TABLE keyword
if p.currentIs(token.TABLE) {
// Check for DATABASE keyword - if present, store in Database field
isDatabase := false
if p.currentIs(token.DATABASE) {
isDatabase = true
p.nextToken()
} else if p.currentIs(token.TABLE) {
p.nextToken()
}

// Parse table name (can be qualified: database.table)
tableName := p.parseIdentifierName()
if p.currentIs(token.DOT) {
// Parse name (can be qualified: database.table for TABLE, not for DATABASE)
name := p.parseIdentifierName()
if p.currentIs(token.DOT) && !isDatabase {
p.nextToken()
detach.Database = tableName
detach.Database = name
detach.Table = p.parseIdentifierName()
} else if isDatabase {
detach.Database = name
} else {
detach.Table = tableName
detach.Table = name
}

return detach
Expand All @@ -3985,19 +4014,25 @@ func (p *Parser) parseAttach() *ast.AttachQuery {

p.nextToken() // skip ATTACH

// Skip optional TABLE keyword
if p.currentIs(token.TABLE) {
// Check for DATABASE keyword - if present, store in Database field
isDatabase := false
if p.currentIs(token.DATABASE) {
isDatabase = true
p.nextToken()
} else if p.currentIs(token.TABLE) {
p.nextToken()
}

// Parse table name (can be qualified: database.table)
tableName := p.parseIdentifierName()
if p.currentIs(token.DOT) {
// Parse name (can be qualified: database.table for TABLE, not for DATABASE)
name := p.parseIdentifierName()
if p.currentIs(token.DOT) && !isDatabase {
p.nextToken()
attach.Database = tableName
attach.Database = name
attach.Table = p.parseIdentifierName()
} else if isDatabase {
attach.Database = name
} else {
attach.Table = tableName
attach.Table = name
}

return attach
Expand Down
6 changes: 0 additions & 6 deletions parser/testdata/00077_log_tinylog_stripelog/metadata.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
{
"explain_todo": {
"stmt10": true,
"stmt11": true,
"stmt12": true,
"stmt13": true,
"stmt18": true,
"stmt19": true,
"stmt20": true,
"stmt5": true,
"stmt6": true,
"stmt7": true,
"stmt8": true,
"stmt9": true
}
Expand Down
1 change: 0 additions & 1 deletion parser/testdata/00157_cache_dictionary/metadata.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"explain_todo": {
"stmt2": true,
"stmt4": true,
"stmt7": true
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
{
"explain_todo": {
"stmt13": true,
"stmt17": true
}
}
{}
6 changes: 1 addition & 5 deletions parser/testdata/00642_cast/metadata.json
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
{
"explain_todo": {
"stmt12": true
}
}
{}
1 change: 0 additions & 1 deletion parser/testdata/00643_cast_zookeeper_long/metadata.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"explain_todo": {
"stmt10": true,
"stmt5": true,
"stmt9": true
}
}
14 changes: 1 addition & 13 deletions parser/testdata/00736_disjunction_optimisation/metadata.json
Original file line number Diff line number Diff line change
@@ -1,13 +1 @@
{
"explain_todo": {
"stmt11": true,
"stmt14": true,
"stmt17": true,
"stmt22": true,
"stmt25": true,
"stmt28": true,
"stmt31": true,
"stmt34": true,
"stmt8": true
}
}
{}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"explain_todo":{"stmt4":true}}
{}
4 changes: 1 addition & 3 deletions parser/testdata/01018_ddl_dictionaries_create/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
"stmt48": true,
"stmt51": true,
"stmt52": true,
"stmt53": true,
"stmt6": true,
"stmt7": true
"stmt53": true
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
{
"explain_todo": {
"stmt10": true,
"stmt14": true,
"stmt16": true,
"stmt21": true,
"stmt4": true,
"stmt5": true,
"stmt6": true,
"stmt8": true
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"explain_todo": {
"stmt12": true,
"stmt5": true,
"stmt6": true
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"explain_todo": {
"stmt3": true,
"stmt4": true,
"stmt9": true
}
Expand Down
5 changes: 1 addition & 4 deletions parser/testdata/01048_exists_query/metadata.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
{
"explain_todo": {
"stmt12": true,
"stmt22": true,
"stmt23": true,
"stmt24": true,
"stmt25": true,
"stmt34": true,
"stmt35": true
"stmt25": true
}
}
Loading