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
11 changes: 11 additions & 0 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,17 @@ func (d *DataType) Pos() token.Position { return d.Position }
func (d *DataType) End() token.Position { return d.Position }
func (d *DataType) expressionNode() {}

// ObjectTypeArgument wraps an expression that is an argument to JSON/OBJECT types.
// This matches ClickHouse's ASTObjectTypeArgument node structure.
type ObjectTypeArgument struct {
Position token.Position `json:"-"`
Expr Expression `json:"expr"`
}

func (o *ObjectTypeArgument) Pos() token.Position { return o.Position }
func (o *ObjectTypeArgument) End() token.Position { return o.Position }
func (o *ObjectTypeArgument) expressionNode() {}

// NameTypePair represents a named type pair, used in Nested types.
type NameTypePair struct {
Position token.Position `json:"-"`
Expand Down
2 changes: 2 additions & 0 deletions internal/explain/explain.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ func Node(sb *strings.Builder, node interface{}, depth int) {
// Types
case *ast.DataType:
explainDataType(sb, n, indent, depth)
case *ast.ObjectTypeArgument:
explainObjectTypeArgument(sb, n, indent, depth)
case *ast.NameTypePair:
explainNameTypePair(sb, n, indent, depth)
case *ast.Parameter:
Expand Down
4 changes: 4 additions & 0 deletions internal/explain/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ func FormatDataType(dt *ast.DataType) string {
}
var params []string
for _, p := range dt.Parameters {
// Unwrap ObjectTypeArgument if present (used for JSON/OBJECT types)
if ota, ok := p.(*ast.ObjectTypeArgument); ok {
p = ota.Expr
}
if lit, ok := p.(*ast.Literal); ok {
if lit.Type == ast.LiteralString {
// String parameters in type need extra escaping: 'val' -> \\\'val\\\'
Expand Down
5 changes: 5 additions & 0 deletions internal/explain/statements.go
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,11 @@ func explainDataType(sb *strings.Builder, n *ast.DataType, indent string, depth
}
}

func explainObjectTypeArgument(sb *strings.Builder, n *ast.ObjectTypeArgument, indent string, depth int) {
fmt.Fprintf(sb, "%sASTObjectTypeArgument (children %d)\n", indent, 1)
Node(sb, n.Expr, depth+1)
}

func explainNameTypePair(sb *strings.Builder, n *ast.NameTypePair, indent string, depth int) {
fmt.Fprintf(sb, "%sNameTypePair %s (children %d)\n", indent, n.Name, 1)
Node(sb, n.Type, depth+1)
Expand Down
28 changes: 21 additions & 7 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2413,7 +2413,9 @@ func (p *Parser) parseDataType() *ast.DataType {

// Determine if this type uses named parameters (Nested, Tuple, JSON)
upperName := strings.ToUpper(dt.Name)
usesNamedParams := upperName == "NESTED" || upperName == "TUPLE" || upperName == "JSON"
usesNamedParams := upperName == "NESTED" || upperName == "TUPLE" || upperName == "JSON" || upperName == "OBJECT"
// JSON and OBJECT types wrap their parameters in ObjectTypeArgument
isObjectType := upperName == "JSON" || upperName == "OBJECT"

// Parse type parameters, but stop on keywords that can't be part of type params
for !p.currentIs(token.RPAREN) && !p.currentIs(token.EOF) && !p.currentIs(token.COLLATE) {
Expand All @@ -2422,10 +2424,11 @@ func (p *Parser) parseDataType() *ast.DataType {
isNamedParam := false
if usesNamedParams && (p.currentIs(token.IDENT) || p.current.Token.IsKeyword()) {
// Check if current is NOT a type name and peek IS a type name or LPAREN follows for complex types
if !p.isDataTypeName(p.current.Value) {
// But NOT if peek is '=' which indicates an expression like max_dynamic_paths=8
if !p.isDataTypeName(p.current.Value) && !p.peekIs(token.EQ) {
// Current is a name (not a type), next should be a type
isNamedParam = true
} else if p.peekIs(token.IDENT) || p.peekIs(token.LPAREN) {
} else if !p.peekIs(token.EQ) && (p.peekIs(token.IDENT) || p.peekIs(token.LPAREN)) {
// Current looks like a type name but is followed by another identifier
// This happens with things like "a Tuple(...)" where "a" looks like it could be a type
// Check if peek is a known type name
Expand All @@ -2441,6 +2444,7 @@ func (p *Parser) parseDataType() *ast.DataType {
}
}

var param ast.Expression
if isNamedParam {
// Parse as name + type pair
pos := p.current.Pos
Expand All @@ -2449,19 +2453,29 @@ func (p *Parser) parseDataType() *ast.DataType {
// Parse the type for this parameter
paramType := p.parseDataType()
if paramType != nil {
ntp := &ast.NameTypePair{
param = &ast.NameTypePair{
Position: pos,
Name: paramName,
Type: paramType,
}
dt.Parameters = append(dt.Parameters, ntp)
}
} else if (p.currentIs(token.IDENT) || p.current.Token.IsKeyword()) && p.isDataTypeName(p.current.Value) {
// It's a type name, parse as data type
dt.Parameters = append(dt.Parameters, p.parseDataType())
param = p.parseDataType()
} else {
// Parse as expression (for things like Decimal(10, 2))
dt.Parameters = append(dt.Parameters, p.parseExpression(LOWEST))
param = p.parseExpression(LOWEST)
}

// Wrap in ObjectTypeArgument for JSON/OBJECT types
if param != nil {
if isObjectType {
param = &ast.ObjectTypeArgument{
Position: param.Pos(),
Expr: param,
}
}
dt.Parameters = append(dt.Parameters, param)
}

if p.currentIs(token.COMMA) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
"stmt12": true,
"stmt14": true,
"stmt16": true,
"stmt3": true,
"stmt8": true
}
}
6 changes: 0 additions & 6 deletions parser/testdata/03205_json_cast_from_string/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,6 @@
"stmt10": true,
"stmt11": true,
"stmt12": true,
"stmt14": true,
"stmt15": true,
"stmt16": true,
"stmt17": true,
"stmt18": true,
"stmt19": true,
"stmt5": true,
"stmt6": true,
"stmt7": true,
Expand Down
7 changes: 1 addition & 6 deletions parser/testdata/03205_json_syntax/metadata.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
{
"explain_todo": {
"stmt11": true,
"stmt13": true,
"stmt15": true,
"stmt17": true,
"stmt19": true,
Expand All @@ -13,9 +11,6 @@
"stmt31": true,
"stmt33": true,
"stmt35": true,
"stmt37": true,
"stmt5": true,
"stmt7": true,
"stmt9": true
"stmt37": true
}
}
7 changes: 1 addition & 6 deletions parser/testdata/03214_json_typed_dynamic_path/metadata.json
Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
{
"explain_todo": {
"stmt10": true,
"stmt4": true
}
}
{}
8 changes: 0 additions & 8 deletions parser/testdata/03222_json_squashing/metadata.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
{
"explain_todo": {
"stmt21": true,
"stmt22": true,
"stmt30": true,
"stmt38": true,
"stmt46": true,
"stmt47": true,
"stmt49": true,
"stmt51": true,
"stmt53": true,
"stmt55": true,
"stmt57": true,
"stmt59": true,
"stmt61": true,
"stmt63": true,
"stmt65": true,
"stmt67": true,
"stmt69": true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@
"explain_todo": {
"stmt10": true,
"stmt12": true,
"stmt13": true,
"stmt16": true,
"stmt18": true,
"stmt20": true,
"stmt3": true,
"stmt4": true,
"stmt8": true
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
{
"explain_todo": {
"stmt3": true
}
}
{}
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
{
"explain_todo": {
"stmt11": true,
"stmt12": true,
"stmt15": true,
"stmt16": true,
"stmt17": true,
"stmt18": true,
"stmt21": true,
"stmt22": true,
"stmt23": true,
"stmt3": true,
"stmt4": true,
"stmt5": true,
"stmt8": true
"stmt23": true
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
{
"explain_todo": {
"stmt7": true
}
}
{}
6 changes: 1 addition & 5 deletions parser/testdata/03232_json_uniq_group_by/metadata.json
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
{
"explain_todo": {
"stmt3": true
}
}
{}
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
{
"explain_todo": {
"stmt5": true
}
}
{}
6 changes: 1 addition & 5 deletions parser/testdata/03247_object_column_copy/metadata.json
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
{
"explain_todo": {
"stmt6": true
}
}
{}
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
{
"explain_todo": {
"stmt5": true
}
}
{}
10 changes: 1 addition & 9 deletions parser/testdata/03272_json_to_json_cast_1/metadata.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
{
"explain_todo": {
"stmt10": true,
"stmt12": true,
"stmt14": true,
"stmt16": true,
"stmt18": true,
"stmt20": true,
"stmt22": true,
"stmt5": true,
"stmt8": true
"stmt5": true
}
}
15 changes: 1 addition & 14 deletions parser/testdata/03272_json_to_json_cast_2/metadata.json
Original file line number Diff line number Diff line change
@@ -1,14 +1 @@
{
"explain_todo": {
"stmt10": true,
"stmt12": true,
"stmt14": true,
"stmt18": true,
"stmt22": true,
"stmt25": true,
"stmt28": true,
"stmt31": true,
"stmt5": true,
"stmt8": true
}
}
{}
17 changes: 1 addition & 16 deletions parser/testdata/03272_json_to_json_cast_3/metadata.json
Original file line number Diff line number Diff line change
@@ -1,39 +1,24 @@
{
"explain_todo": {
"stmt10": true,
"stmt12": true,
"stmt14": true,
"stmt16": true,
"stmt18": true,
"stmt20": true,
"stmt22": true,
"stmt24": true,
"stmt26": true,
"stmt28": true,
"stmt30": true,
"stmt32": true,
"stmt34": true,
"stmt36": true,
"stmt38": true,
"stmt40": true,
"stmt42": true,
"stmt44": true,
"stmt46": true,
"stmt48": true,
"stmt5": true,
"stmt50": true,
"stmt52": true,
"stmt54": true,
"stmt56": true,
"stmt58": true,
"stmt60": true,
"stmt62": true,
"stmt64": true,
"stmt66": true,
"stmt68": true,
"stmt70": true,
"stmt72": true,
"stmt74": true,
"stmt8": true
"stmt74": true
}
}
11 changes: 1 addition & 10 deletions parser/testdata/03272_json_to_json_cast_4/metadata.json
Original file line number Diff line number Diff line change
@@ -1,10 +1 @@
{
"explain_todo": {
"stmt11": true,
"stmt13": true,
"stmt15": true,
"stmt5": true,
"stmt7": true,
"stmt9": true
}
}
{}
15 changes: 1 addition & 14 deletions parser/testdata/03272_json_to_json_cast_5/metadata.json
Original file line number Diff line number Diff line change
@@ -1,14 +1 @@
{
"explain_todo": {
"stmt11": true,
"stmt13": true,
"stmt15": true,
"stmt17": true,
"stmt19": true,
"stmt21": true,
"stmt23": true,
"stmt5": true,
"stmt7": true,
"stmt9": true
}
}
{}
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,14 @@
"stmt10": true,
"stmt12": true,
"stmt14": true,
"stmt16": true,
"stmt21": true,
"stmt23": true,
"stmt25": true,
"stmt27": true,
"stmt28": true,
"stmt33": true,
"stmt35": true,
"stmt37": true,
"stmt39": true,
"stmt4": true,
"stmt40": true,
"stmt45": true,
"stmt47": true,
"stmt49": true,
Expand Down
8 changes: 1 addition & 7 deletions parser/testdata/03279_not_empty_json/metadata.json
Original file line number Diff line number Diff line change
@@ -1,7 +1 @@
{
"explain_todo": {
"stmt10": true,
"stmt14": true,
"stmt6": true
}
}
{}
6 changes: 1 addition & 5 deletions parser/testdata/03282_json_equal_comparison/metadata.json
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
{
"explain_todo": {
"stmt3": true
}
}
{}
Loading