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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
1,735 changes: 0 additions & 1,735 deletions ast/explain.go

This file was deleted.

86 changes: 0 additions & 86 deletions ast/explain_test.go

This file was deleted.

51 changes: 42 additions & 9 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,30 @@ type testMetadata struct {
Source string `json:"source,omitempty"`
}

// astJSON represents the structure of ast.json from ClickHouse EXPLAIN AST
type astJSON struct {
Meta []struct {
Name string `json:"name"`
Type string `json:"type"`
} `json:"meta"`
Data []struct {
Explain string `json:"explain"`
} `json:"data"`
Rows int `json:"rows"`
Statistics struct {
Elapsed float64 `json:"elapsed"`
RowsRead int `json:"rows_read"`
BytesRead int `json:"bytes_read"`
} `json:"statistics"`
Error bool `json:"error,omitempty"`
}

// TestParser tests the parser using test cases from the testdata directory.
// Each subdirectory in testdata represents a test case with:
// - query.sql: The SQL query to parse
// - ast.json: Expected AST from ClickHouse EXPLAIN AST
// - metadata.json (optional): Metadata including:
// - todo: true if the test is not yet expected to pass
// - source: URL to the source file in ClickHouse repository
func TestParser(t *testing.T) {
testdataDir := "testdata"

Expand All @@ -37,21 +55,24 @@ func TestParser(t *testing.T) {
continue
}

testName := entry.Name()
testDir := filepath.Join(testdataDir, testName)
testDir := filepath.Join(testdataDir, entry.Name())

t.Run(entry.Name(), func(t *testing.T) {
t.Parallel()

t.Run(testName, func(t *testing.T) {
// Create context with 1 second timeout
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()

// Read the query
// Read the query (only first line, as ast.json was generated from first statement)
queryPath := filepath.Join(testDir, "query.sql")
queryBytes, err := os.ReadFile(queryPath)
if err != nil {
t.Fatalf("Failed to read query.sql: %v", err)
}
query := strings.TrimSpace(string(queryBytes))
// Get first line only (ast.json contains AST for first statement)
lines := strings.SplitN(string(queryBytes), "\n", 2)
query := strings.TrimSpace(lines[0])

// Read optional metadata
var metadata testMetadata
Expand All @@ -62,9 +83,19 @@ func TestParser(t *testing.T) {
}
}

// Log source if available
if metadata.Source != "" {
t.Logf("Source: %s", metadata.Source)
// Read expected AST from ClickHouse
var expectedAST astJSON
astPath := filepath.Join(testDir, "ast.json")
if astBytes, err := os.ReadFile(astPath); err == nil {
if err := json.Unmarshal(astBytes, &expectedAST); err != nil {
t.Fatalf("Failed to parse ast.json: %v", err)
}
}

// Skip tests where ClickHouse also couldn't parse the query
if expectedAST.Error {
t.Skipf("ClickHouse also failed to parse this query")
return
}

// Parse the query
Expand Down Expand Up @@ -94,6 +125,8 @@ func TestParser(t *testing.T) {
}
t.Fatalf("JSON marshal error: %v\nQuery: %s", jsonErr, query)
}

// TODO: Compare parsed AST against expectedAST.Data
})
}
}
Expand Down
1 change: 1 addition & 0 deletions parser/testdata/00001_count_hits/ast.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"error": true}
2 changes: 2 additions & 0 deletions parser/testdata/00001_count_hits/query.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Tags: stateful
SELECT count() FROM test.hits
37 changes: 37 additions & 0 deletions parser/testdata/00001_select_1/ast.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"meta":
[
{
"name": "explain",
"type": "String"
}
],

"data":
[
{
"explain": "SelectWithUnionQuery (children 1)"
},
{
"explain": " ExpressionList (children 1)"
},
{
"explain": " SelectQuery (children 1)"
},
{
"explain": " ExpressionList (children 1)"
},
{
"explain": " Literal UInt64_1"
}
],

"rows": 5,

"statistics":
{
"elapsed": 0.001936758,
"rows_read": 5,
"bytes_read": 177
}
}
1 change: 1 addition & 0 deletions parser/testdata/00002_count_visits/ast.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"error": true}
2 changes: 2 additions & 0 deletions parser/testdata/00002_count_visits/query.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Tags: stateful
SELECT sum(Sign) FROM test.visits
25 changes: 25 additions & 0 deletions parser/testdata/00002_system_numbers/ast.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"meta":
[
{
"name": "explain",
"type": "String"
}
],

"data":
[
{
"explain": "Set"
}
],

"rows": 1,

"statistics":
{
"elapsed": 0.001602544,
"rows_read": 1,
"bytes_read": 11
}
}
14 changes: 14 additions & 0 deletions parser/testdata/00002_system_numbers/query.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
SET send_logs_level = 'fatal';

SELECT * FROM system.numbers LIMIT 3;
SELECT sys_num.number FROM system.numbers AS sys_num WHERE number > 2 LIMIT 2;
SELECT number FROM system.numbers WHERE number >= 5 LIMIT 2;
SELECT * FROM system.numbers WHERE number == 7 LIMIT 1;
SELECT number AS n FROM system.numbers WHERE number IN(8, 9) LIMIT 2;
select number from system.numbers limit 0;
select x from system.numbers limit 1; -- { serverError UNKNOWN_IDENTIFIER }
SELECT x, number FROM system.numbers LIMIT 1; -- { serverError UNKNOWN_IDENTIFIER }
SELECT * FROM system.number LIMIT 1; -- { serverError UNKNOWN_TABLE }
SELECT * FROM system LIMIT 1; -- { serverError UNKNOWN_TABLE }
SELECT * FROM numbers LIMIT 1; -- { serverError UNKNOWN_TABLE }
SELECT sys.number FROM system.numbers AS sys_num LIMIT 1; -- { serverError UNKNOWN_IDENTIFIER }
70 changes: 70 additions & 0 deletions parser/testdata/00003_reinterpret_as_string/ast.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"meta":
[
{
"name": "explain",
"type": "String"
}
],

"data":
[
{
"explain": "SelectWithUnionQuery (children 1)"
},
{
"explain": " ExpressionList (children 1)"
},
{
"explain": " SelectQuery (children 4)"
},
{
"explain": " ExpressionList (children 1)"
},
{
"explain": " Identifier number"
},
{
"explain": " TablesInSelectQuery (children 1)"
},
{
"explain": " TablesInSelectQueryElement (children 1)"
},
{
"explain": " TableExpression (children 1)"
},
{
"explain": " TableIdentifier system.numbers"
},
{
"explain": " Function equals (children 1)"
},
{
"explain": " ExpressionList (children 2)"
},
{
"explain": " Function reinterpretAsString (children 1)"
},
{
"explain": " ExpressionList (children 1)"
},
{
"explain": " Identifier number"
},
{
"explain": " Literal 'Ё'"
},
{
"explain": " Literal UInt64_1"
}
],

"rows": 16,

"statistics":
{
"elapsed": 0.001337951,
"rows_read": 16,
"bytes_read": 614
}
}
1 change: 1 addition & 0 deletions parser/testdata/00003_reinterpret_as_string/query.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SELECT number FROM system.numbers WHERE reinterpretAsString(number) = 'Ё' LIMIT 1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"error": true}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- Tags: shard

SELECT (dummy AS x) - 1 FROM remote('127.0.0.{2,3}', system, one)
1 change: 1 addition & 0 deletions parser/testdata/00004_top_counters/ast.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"error": true}
3 changes: 3 additions & 0 deletions parser/testdata/00004_top_counters/query.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- Tags: stateful
SELECT CounterID, count() AS c FROM test.hits GROUP BY CounterID ORDER BY c DESC LIMIT 10;
SELECT CounterID, count() AS c FROM test.hits GROUP BY CounterID ORDER BY c DESC LIMIT 10 SETTINGS optimize_aggregation_in_order = 1
1 change: 1 addition & 0 deletions parser/testdata/00005_filtering/ast.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"error": true}
3 changes: 3 additions & 0 deletions parser/testdata/00005_filtering/query.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- Tags: stateful
SELECT count() FROM test.hits WHERE AdvEngineID != 0

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"error": true}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- Tags: shard

SELECT count() FROM remote('127.0.0.{2,3}', system, one) WHERE arrayExists((x) -> x = 1, [1, 2, 3])
1 change: 1 addition & 0 deletions parser/testdata/00006_agregates/ast.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"error": true}
2 changes: 2 additions & 0 deletions parser/testdata/00006_agregates/query.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Tags: stateful
SELECT sum(AdvEngineID), count(), avg(ResolutionWidth) FROM test.hits
25 changes: 25 additions & 0 deletions parser/testdata/00006_extremes_and_subquery_from/ast.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"meta":
[
{
"name": "explain",
"type": "String"
}
],

"data":
[
{
"explain": "Set"
}
],

"rows": 1,

"statistics":
{
"elapsed": 0.001759471,
"rows_read": 1,
"bytes_read": 11
}
}
Loading