mirror of
https://github.com/hanzo-ds/sqlparser.git
synced 2026-10-30 20:53:50 +00:00
A tuple column is declared either way — Tuple(String, Array(String)) or Tuple(label String, path Array(String)) — and SHOW CREATE TABLE returns whichever the column carries. Only the unnamed form parsed, so a schema the server printed itself could not be read back: the parse stopped at the first element's TYPE with "expected the last token kind is: )" under `label String`. The named form is a column list, which parseNestedType already reads for Nested, so this routes to it on one token of lookahead rather than teaching a second grammar: inside the parens a NAME is followed by its type (an identifier), while an unnamed element is followed by a comma, the closing paren, or its own parameters. Measured on the estate: event.log and event.span each carry a named tuple, and every logs query against them answered 500 "failed to get logs keys" because the metadata step reads the table back through this parser.
35 lines
1.4 KiB
Go
35 lines
1.4 KiB
Go
package parser
|
|
|
|
import "testing"
|
|
|
|
// TestNamedTupleColumn reads back a column type ClickHouse itself printed.
|
|
//
|
|
// SHOW CREATE TABLE returns a tuple in whichever form the column was declared, and
|
|
// the named form is a column list, not a list of types. Reading only the unnamed
|
|
// form stopped the parse at the first element's TYPE — "expected the last token
|
|
// kind is: )" pointing at `label String` — which made an entire real table
|
|
// unreadable to anything that parses its schema back.
|
|
func TestNamedTupleColumn(t *testing.T) {
|
|
const ddl = "CREATE TABLE event.log (`el` Tuple(label String, role LowCardinality(String), path Array(String))) ENGINE = MergeTree ORDER BY tuple()"
|
|
stmts, err := NewParser(ddl).ParseStmts()
|
|
if err != nil {
|
|
t.Fatalf("named tuple did not parse: %v", err)
|
|
}
|
|
ct, ok := stmts[0].(*CreateTable)
|
|
if !ok {
|
|
t.Fatalf("statement is %T, want *CreateTable", stmts[0])
|
|
}
|
|
if n := len(ct.TableSchema.Columns); n != 1 {
|
|
t.Fatalf("columns = %d, want 1", n)
|
|
}
|
|
}
|
|
|
|
// TestUnnamedTupleColumnStillParses is the other half: the lookahead must not
|
|
// send a bare list of types down the column-list grammar.
|
|
func TestUnnamedTupleColumnStillParses(t *testing.T) {
|
|
const ddl = "CREATE TABLE t (`x` Tuple(String, Array(String), LowCardinality(String))) ENGINE = MergeTree ORDER BY tuple()"
|
|
if _, err := NewParser(ddl).ParseStmts(); err != nil {
|
|
t.Fatalf("unnamed tuple regressed: %v", err)
|
|
}
|
|
}
|