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
40 changes: 40 additions & 0 deletions pkg/sql/parser/clickhouse_codec_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2026 GoSQLX Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");

package parser_test

import (
"testing"

"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
"github.com/ajitpratap0/GoSQLX/pkg/sql/keywords"
)

// TestClickHouseCODEC verifies the ClickHouse CODEC(...) column option
// parses in CREATE TABLE. Regression for #482.
func TestClickHouseCODEC(t *testing.T) {
queries := map[string]string{
"single_codec": `CREATE TABLE t (
id UInt64,
payload String CODEC(ZSTD(3))
) ENGINE = MergeTree() ORDER BY id`,

"chained_codec": `CREATE TABLE t (
id UInt64,
ts DateTime CODEC(Delta, LZ4)
) ENGINE = MergeTree() ORDER BY id`,

"delta_with_width": `CREATE TABLE t (
id UInt64 CODEC(Delta(8), ZSTD)
) ENGINE = MergeTree() ORDER BY id`,
}
for name, q := range queries {
q := q
t.Run(name, func(t *testing.T) {
if _, err := gosqlx.ParseWithDialect(q, keywords.DialectClickHouse); err != nil {
t.Fatalf("parse failed: %v", err)
}
})
}
}
22 changes: 22 additions & 0 deletions pkg/sql/parser/ddl_columns.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
goerrors "github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
"github.com/ajitpratap0/GoSQLX/pkg/sql/ast"
"github.com/ajitpratap0/GoSQLX/pkg/sql/keywords"
)

// parseColumnName parses a column name in DDL context, accepting reserved keywords
Expand Down Expand Up @@ -92,6 +93,27 @@ func (p *Parser) parseColumnDef() (*ast.ColumnDef, error) {
Type: dataTypeStr,
}

// ClickHouse column options that may appear between the type and the
// standard constraint list: CODEC(...), DEFAULT expr, MATERIALIZED expr,
// ALIAS expr, EPHEMERAL expr, TTL expr. Consume permissively; they are
// appended to the type string for now so formatters can round-trip, and
// not yet modeled on the AST.
if p.dialect == string(keywords.DialectClickHouse) {
for {
upper := strings.ToUpper(p.currentToken.Token.Value)
if upper == "CODEC" && p.peekToken().Token.Type == models.TokenTypeLParen {
p.advance() // CODEC
args, err := p.parseTypeArgsString()
if err != nil {
return nil, err
}
colDef.Type += " CODEC" + args
continue
}
break
}
}

// Parse column constraints
for {
constraint, ok, err := p.parseColumnConstraint()
Expand Down
Loading