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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ Formatting turns one-line SQL into a readable query:
- **[Analysis](https://gosqlx.dev/docs/reference/linting-rules/)** - SQL injection scanner, 30 lint rules (L001-L030), 20 optimizer rules and metadata extraction.
- **[Tooling](https://gosqlx.dev/docs/cli-guide/)** - AST-based formatter, query transforms API, VS Code extension and GitHub Action.
- **[Syntax highlighting](docs/HIGHLIGHTING.md)** - dialect-aware highlighting for terminals (ANSI), HTML/CSS, JSON spans, LSP semantic tokens and WASM; `gosqlx highlight query.sql` or `gosqlx.HighlightANSI(sql)`.
- **[Multi-dialect](https://gosqlx.dev/docs/reference/sql-compatibility/)** - PostgreSQL, MySQL, MariaDB, SQL Server, Oracle, SQLite, Snowflake, ClickHouse.
- **[Multi-dialect](https://gosqlx.dev/docs/reference/sql-compatibility/)** - 8 dialects with dedicated grammar support: PostgreSQL, MySQL, MariaDB, SQL Server, Oracle, SQLite, Snowflake, ClickHouse. The `--dialect` flag and `WithDialect` accept 11 names: those 8 (`postgresql`, `mysql`, `mariadb`, `sqlserver`, `oracle`, `sqlite`, `snowflake`, `clickhouse`) plus `generic`, and `bigquery` and `redshift`, which have keyword recognition and basic parsing only.
- **[AI-ready](https://gosqlx.dev/docs/integrations/mcp/)** - MCP server with 7 tools, public remote endpoint, Streamable HTTP.
- **[Tested](https://gosqlx.dev/docs/reference/sql-compatibility/)** - race-detector clean in CI, ~80-85% SQL-99 (estimated).

Expand Down
21 changes: 20 additions & 1 deletion cmd/gosqlx/cmd/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,17 @@
// - parse: AST generation and inspection with multiple output formats
// - analyze: Security and complexity analysis with grading
// - lint: Style and quality checking with L001-L010 rules
// - highlight (alias hl): Syntax highlighting as ANSI, HTML, CSS or JSON spans
// - lsp: Language Server Protocol server for IDE integration
// - config: Configuration file management
// - completion: Shell autocompletion setup
//
// validate, parse, format, analyze, lint and highlight accept --dialect with
// one of the 11 names from keywords.DialectNames(): generic, postgresql,
// mysql, mariadb, sqlserver, oracle, sqlite, snowflake, bigquery, redshift
// and clickhouse; an unknown name is rejected with an error. Each
// command's --help names its default (highlight uses the generic keyword set).
//
// # Architecture
//
// The package follows a modular design with separation of concerns:
Expand All @@ -44,6 +51,7 @@
// ├── sql_analyzer.go - AST-based analysis engine
// ├── analysis_types.go - Analysis data structures
// ├── lint.go - Lint command definition
// ├── highlight.go - Highlight command (pkg/highlight renderers)
// ├── lsp.go - LSP server command
// ├── config.go - Config management commands
// ├── config_manager.go - Config management logic
Expand Down Expand Up @@ -314,13 +322,24 @@
// Key types: Analyzer, SQLAnalyzer, AnalysisReport
// Key functions: Analyze(), DisplayReport(), scoreQuery()
//
// ## highlight Command
//
// Syntax-highlights SQL through pkg/highlight. --format selects ansi (the
// default), html, css or json spans; --theme selects dark, light or mono;
// --color auto|always|never controls ANSI coloring; --standalone emits a full
// HTML document. Highlighting is lexical and never fails: invalid SQL is
// highlighted up to the first lexical error and the rest is marked as an
// error.
//
// Implementation: highlight.go
//
// ## lint Command
//
// Checks SQL for style violations.
//
// Implementation: lint.go
// Key functions: lintRun(), createLinter()
// Rules: L001-L010 (see pkg/linter)
// Rules: L001-L010 (see pkg/linter); --dialect is passed to Linter.SetDialect
//
// ## lsp Command
//
Expand Down
121 changes: 2 additions & 119 deletions docs/API_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ New to GoSQLX? Start with [Getting Started](GETTING_STARTED.md), then pick a tas
| [errors](api/errors.md) | `pkg/errors` | Structured errors with codes, positions and hints |
| [metrics](api/metrics.md) | `pkg/metrics` | Production counters and timings |
| [security](api/security.md) | `pkg/sql/security` | SQL injection pattern detection |
| [highlight](#highlight-package) | `pkg/highlight` | Dialect-aware SQL syntax highlighting as spans, ANSI, HTML and CSS |
| [highlight](api/highlight.md) | `pkg/highlight` | Dialect-aware SQL syntax highlighting as spans, ANSI, HTML and CSS |
| [linter](api/linter.md) | `pkg/linter` | The lint engine and its rules |
| [lsp](api/lsp.md) | `pkg/lsp` | The Language Server Protocol server |
| [mcp](api/mcp.md) | `pkg/mcp` | The Model Context Protocol server |
Expand Down Expand Up @@ -65,124 +65,7 @@ Moved to the [security package reference](api/security.md).

## Highlight Package

`github.com/ajitpratap0/GoSQLX/pkg/highlight` classifies SQL into byte-offset spans for terminals, HTML and editors. The guide with examples is [Syntax Highlighting](HIGHLIGHTING.md).

### Spans

```go
func Spans(sql string, opts ...Option) []Span
func WithDialect(d keywords.SQLDialect) Option // type Option func(*config)

type Span struct {
Start int `json:"start"` // byte offset, inclusive
End int `json:"end"` // byte offset, exclusive
Category Category `json:"category"`
}
func (s Span) Text(src string) string
```

`Spans` returns spans sorted by `Start` that never overlap and never carry `Plain`; uncovered bytes are plain text. It never returns an error: after the first lexical error the rest of the input is one `Error` span. Input the tokenizer refuses outright (beyond its size or token limits) yields no spans. `Spans` is safe for concurrent use. `WithDialect` accepts the dialect identifiers listed below; an empty or unknown dialect uses the generic keyword set.

### Categories

```go
type Category uint8

const (
Plain Category = iota // never on a Span; implicit category of gaps
Keyword
Function
DataType
Identifier
QuotedIdentifier
String
Number
Constant
Operator
Punctuation
Comment
Placeholder
Error
)

func Categories() []Category // every category except Plain, in declaration order
func ParseCategory(name string) (Category, bool)
func (c Category) String() string // stable name, e.g. "quoted-identifier"
```

Stable names, used as JSON values, HTML class suffixes and theme keys: `keyword`, `function`, `type` (`DataType`), `identifier`, `quoted-identifier`, `string`, `number`, `constant`, `operator`, `punctuation`, `comment`, `placeholder`, `error`. `Category` marshals to and from these names in JSON.

### Terminal Output

```go
func ANSI(src string, spans []Span, opts ANSIOptions) string
func WriteANSI(w io.Writer, src string, spans []Span, opts ANSIOptions) error

type ANSIOptions struct {
Theme Theme // zero Theme means DarkTheme
Mode ColorMode // zero value is Color256
}

type ColorMode int // Color256 (default), TrueColor, NoColor
```

`NoColor` emits only bold, italic and underline. Styles are reset before each newline and re-applied after it, so output stays correct through `head`, `grep` or a pager.

### HTML and CSS

```go
func HTML(src string, spans []Span, opts HTMLOptions) string
func WriteHTML(w io.Writer, src string, spans []Span, opts HTMLOptions) error
func CSS(theme Theme, classPrefix string) string

type HTMLOptions struct {
ClassPrefix string // empty means DefaultClassPrefix ("gsx-")
InlineStyles bool // emit style="..." from Theme instead of classes
Theme Theme // used with InlineStyles; zero means DarkTheme
Wrap bool // wrap in <pre class="{prefix}highlight"><code>
}

const DefaultClassPrefix = "gsx-"
```

All source text is HTML-escaped. Spans become `<span class="gsx-<category>">`. `CSS` returns one rule per category for the same class names; it styles the token classes only.

### Themes

```go
type Theme struct {
Name string
Styles map[Category]Style
}

type Style struct {
Color string // "#RRGGBB" or "#RGB"; other values are ignored
Bold bool
Italic bool
Underline bool
}

func DarkTheme() Theme
func LightTheme() Theme
func MonoTheme() Theme
func ThemeByName(name string) (Theme, bool) // case-insensitive
func ThemeNames() []string // "dark", "light", "mono"
func (t Theme) Style(c Category) Style
```

Each constructor returns a fresh copy that the caller may modify.

### High-Level Helpers (gosqlx)

```go
func gosqlx.Highlight(sql string, opts ...highlight.Option) []highlight.Span
func gosqlx.HighlightANSI(sql string, opts ...highlight.Option) string // dark theme, 256 colors
func gosqlx.HighlightHTML(sql string, opts ...highlight.Option) string // wrapped in <pre class="gsx-highlight">
```

### Dialects

`highlight.WithDialect` and the CLI `--dialect` flag accept `generic`, `postgresql`, `mysql`, `mariadb`, `sqlserver`, `oracle`, `sqlite`, `snowflake`, `bigquery`, `redshift` and `clickhouse` (the values of `keywords.AllDialects()`). With no dialect, the generic keyword set is used.
Moved to the [highlight package reference](api/highlight.md). The guide with examples is [Syntax Highlighting](HIGHLIGHTING.md).

## Linter Package

Expand Down
26 changes: 23 additions & 3 deletions docs/MCP_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ All 7 GoSQLX SQL tools are available instantly:
- `parse_sql` - Parse SQL into AST statement types
- `extract_metadata` - Extract tables, columns, and functions
- `security_scan` - Detect SQL injection patterns
- `lint_sql` - Lint against the style rules (L001–L010)
- `lint_sql` - Lint against the ten style rules L001–L010 (not the L011–L030 safety, performance and naming rules)
- `analyze_sql` - Run all 6 tools in one concurrent request

### Rate Limits

The public server has smart rate limiting to ensure fair usage:
The public server has smart rate limiting to ensure fair usage. These limits come from the rate-limit middleware that the `gosqlx-mcp` binary installs (`NewRateLimitMiddleware`); a server embedded with `pkg/mcp` through `Server.Start` or `Server.Handler` has none of them unless you add the middleware yourself (see [Embedding as a Go Library](#embedding-as-a-go-library)):
- **Burst**: 10 requests/second per IP
- **Sustained**: 120 weighted-requests/minute per IP
- Heavier tools (`analyze_sql`) consume more budget than simple ones (`validate_sql`)
Expand Down Expand Up @@ -521,7 +521,7 @@ curl -s -X POST http://127.0.0.1:8080/mcp \

### lint\_sql

**Description**: Lint SQL against the GoSQLX style rules (L001–L010).
**Description**: Lint SQL against the ten GoSQLX style rules L001–L010, the same set `gosqlx lint` runs, with L005's maximum line length fixed at 100 characters. The safety, performance and naming rules L011–L030, which `gosqlx.Lint` also runs, are not applied.

#### Parameters

Expand Down Expand Up @@ -745,6 +745,26 @@ func main() {
}
```

`Start` and `Handler` apply bearer auth only. They do **not** apply the rate limiting described under [Rate Limits](#rate-limits): there is no per-client rate limit, no `GET` stream cap, no request body size cap and no body read deadline. That is fine on `127.0.0.1`, but before exposing an embedded server to untrusted clients, serve `Handler` wrapped in `NewRateLimitMiddleware`, as `gosqlx-mcp` does:

```go
cfg, err := mcp.LoadConfig()
if err != nil {
log.Fatal(err)
}
srv := mcp.New(cfg)
defer srv.Shutdown(context.Background())

httpSrv := &http.Server{
Addr: cfg.Addr(),
Handler: mcp.NewRateLimitMiddleware(cfg, srv.Handler()),
ReadHeaderTimeout: 10 * time.Second,
}
log.Fatal(httpSrv.ListenAndServe())
```

`NewRateLimitMiddleware` honours the trusted-proxy settings in `cfg` (see [Client IP and reverse proxies](#client-ip-and-reverse-proxies)). `Shutdown` stops the idle-session sweeper that `Handler` starts; it does not close an `http.Server` you built yourself.

### Public API

| Symbol | Signature | Description |
Expand Down
49 changes: 49 additions & 0 deletions docs/MIGRATION.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,54 @@
# Migration Guide

## v1.14.0 → v1.15.0 (2026-07-30)

**Source-compatible upgrade**: exported signatures are unchanged apart from additions, so code that compiled against v1.14.0 compiles against v1.15.0. Some runtime behavior changed; read the checklist below. The [CHANGELOG](../CHANGELOG.md) has the full list.

### Why upgrade

- **High-level `Tree` API**: `gosqlx.ParseTree` with typed walkers, `Rewrite` and `Clone`, and functional options instead of the `ParseWith*` combinations.
- **ClickHouse at 83/83 of the QA corpus**: `ARRAY JOIN`, scalar CTEs, `CREATE MATERIALIZED VIEW ... ENGINE/TO`, `SAMPLE ... OFFSET` and `LIMIT offset, count`.
- **Oracle gaps closed**: `ROWNUM`/`ROWID`/`LEVEL`/`SYSDATE` pseudo-columns, `PIVOT`/`UNPIVOT` `IN` lists with aliases, and literal backslashes in strings outside MySQL/PostgreSQL.
- **Correctness sweep**: structured parser errors, pool leak fixes, and `Children()` coverage for 14 node types that `Walk`/`Inspect` used to skip.

### New APIs to adopt

- `gosqlx.ParseTree(ctx, sql, opts...)` returning `*Tree`, with `WalkSelects`, `WalkInserts`, `WalkUpdates`, `WalkDeletes`, `WalkCreateTables`, `WalkJoins`, `WalkCTEs`, `WalkFunctionCalls`, `WalkIdentifiers`, `WalkBinaryExpressions`, generic `WalkBy[T]`, `Tree.Rewrite` and `Tree.Clone`.
- Options `WithDialect`, `WithStrict`, `WithTimeout`, `WithRecovery` and `WithMaxBytes`; `ParseReader` / `ParseReaderMultiple`, with `errors.Is(err, gosqlx.ErrTooLarge)` when the `WithMaxBytes` limit is exceeded.
- `FormatTree` / `FormatAST` to format without re-parsing.
- `gosqlx.SplitStatements(sql, dialect)`: dialect-aware script splitting on top-level `;`.
- `gosqlx.Lint(sql)` (all 30 rules), `gosqlx.Analyze(sql)`, and `ErrorCode`, `ErrorLocation` and `ErrorHint` to unwrap structured error details.
- `pkg/sql/dialect`: typed `Dialect` and `Capabilities`, exposed through `Parser.DialectTyped()`, `Parser.Capabilities()` and `Parser.Is<Dialect>()` helpers.
- `pkg/linter/config`: `.gosqlx.yml` linter configuration with rule enable/disable, severity overrides and ignore globs.
- `keywords.Conflicts()`, `ast.UnsupportedStatement` with `AST.HasUnsupportedStatements()`, and `ast.PoolLeakCount()`.

### Behavior changes to act on

- [ ] **Lint findings in nested queries**: fourteen rules now walk the whole AST, so violations inside subqueries and CTEs are reported. Expect more findings.
- [ ] **Structured parser errors**: parser errors are `*errors.Error` values with a code and position, and the legacy `Parse`-family functions wrap the `ErrSyntax`, `ErrTokenize`, `ErrTimeout` and `ErrUnsupportedDialect` sentinels. Match with `errors.Is` / `errors.As` instead of comparing message strings.
- [ ] **Cancellation**: a cancelled context returns `ctx.Err()` directly, so `errors.Is(err, context.Canceled)` works.
- [ ] **`*errors.Error.WithX` methods copy** instead of mutating the receiver. Use the returned value.
- [ ] **`parser.ValidateBytes("")` returns an error**, matching `gosqlx.Validate("")`.
- [ ] **Snowflake stub statements** (`USE`, `COPY INTO`, `PUT`, `GET`, `LIST`, `REMOVE`, `CREATE STAGE/STREAM/TASK/PIPE/...`) are `*ast.UnsupportedStatement`, not `*ast.DescribeStatement`, and the formatter emits `-- UNSUPPORTED: <raw SQL>` for them. Update type switches.
- [ ] **Metrics error statistics** are counted per error code instead of per `err.Error()` string.

### Deprecations

- `pkg/sql/monitor` is deprecated in favour of `pkg/metrics`.
- `parser.Parse([]token.Token)`, `ParseFromModelTokensWithPositions` and `ConversionResult.PositionMapping` are scheduled for removal in v2.0.

### Companion release versions

| Component | v1.14.0 | v1.15.0 |
|-----------|---------|---------|
| Library (`github.com/ajitpratap0/GoSQLX`) | 1.14.0 | **1.15.0** (the `gosqlx.Version` constant still reads 1.14.0) |
| CLI (`cmd/gosqlx`, `gosqlx --version`) | 1.14.0 | 1.14.0 (stale constant) |
| VS Code extension (`ajitpratap0.gosqlx`) | 1.14.0 | **1.15.0** (version taken from the release tag) |
| OpenTelemetry integration (`integrations/opentelemetry`) | requires v1.14.0 | requires v1.14.0 |
| GORM integration (`integrations/gorm`) | requires v1.14.0 | requires v1.14.0 |

---

## v1.13.0 → v1.14.0 (2026-04-12)

**Drop-in upgrade** — no breaking API changes. Anything that compiled against v1.13.0 will still compile and run identically against v1.14.0.
Expand Down
8 changes: 6 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ GoSQLX is a production-ready, high-performance SQL parsing SDK for Go with compr

### Core Capabilities
- **High-Performance Parsing** - 1.38M+ operations/second sustained, 1.5M peak with zero-copy tokenization
- **Multi-Dialect Support** - PostgreSQL, MySQL, SQL Server, Oracle, SQLite with ~80-85% SQL-99 compliance
- **Multi-Dialect Support** - PostgreSQL, MySQL, MariaDB, SQL Server, Oracle, SQLite, Snowflake and ClickHouse (plus `generic`, `bigquery` and `redshift` as accepted dialect names) with ~80-85% SQL-99 compliance
- **Thread-Safe Operations** - Race-free concurrent processing validated with 20,000+ concurrent operations
- **Memory Efficient** - Object pooling architecture with 60-80% memory reduction
- **Production Ready** - Comprehensive error handling, position tracking, and recovery
Expand Down Expand Up @@ -46,6 +46,8 @@ GoSQLX is a production-ready, high-performance SQL parsing SDK for Go with compr
| [**GETTING_STARTED.md**](GETTING_STARTED.md) | 5-minute quickstart guide for new users | Beginners |
| [**CLI_GUIDE.md**](CLI_GUIDE.md) | Command-line tool usage and examples | CLI Users |
| [**LSP_GUIDE.md**](LSP_GUIDE.md) | Language Server Protocol integration for IDEs | IDE Users/Developers |
| [**MCP_GUIDE.md**](MCP_GUIDE.md) | MCP server for AI assistants: tools, configuration, rate limits and embedding | AI Tooling/DevOps |
| [**CHATGPT_APP.md**](CHATGPT_APP.md) | How `gosqlx-mcp` works as a ChatGPT app and in MCP Apps hosts | AI Tooling |

### Core Documentation

Expand All @@ -57,6 +59,7 @@ GoSQLX is a production-ready, high-performance SQL parsing SDK for Go with compr
| [**TROUBLESHOOTING.md**](TROUBLESHOOTING.md) | Common issues, error messages, debugging techniques, and FAQ | Support/Debug |
| [**LINTING_RULES.md**](LINTING_RULES.md) | Complete linting rules reference (L001-L030) with examples | Developers/QA |
| [**CONFIGURATION.md**](CONFIGURATION.md) | Configuration file (.gosqlx.yml) guide with all options | DevOps/Teams |
| [**HIGHLIGHTING.md**](HIGHLIGHTING.md) | SQL syntax highlighting: categories, themes, CLI, LSP semantic tokens and WASM ([API](api/highlight.md)) | Developers/Tool Builders |

### Reference Documentation

Expand Down Expand Up @@ -86,6 +89,7 @@ GoSQLX is a production-ready, high-performance SQL parsing SDK for Go with compr

| Document | Description |
|----------|-------------|
| [**MIGRATION.md**](MIGRATION.md) | Release-by-release upgrade notes: new APIs, behavior changes and companion versions |
| [**UPGRADE_GUIDE.md**](UPGRADE_GUIDE.md) | Version upgrade guide with breaking changes |
| [**migration/FROM_JSQLPARSER.md**](migration/FROM_JSQLPARSER.md) | Migrating from JSqlParser |
| [**migration/FROM_PG_QUERY.md**](migration/FROM_PG_QUERY.md) | Migrating from pg_query |
Expand Down Expand Up @@ -387,7 +391,7 @@ The command-line tool now includes:

### Comprehensive SQL Support
- **80-85% SQL-99 Compliance**: Window functions, CTEs, set operations
- **Multi-Dialect**: PostgreSQL, MySQL, SQL Server, Oracle, SQLite
- **Multi-Dialect**: PostgreSQL, MySQL, MariaDB, SQL Server, Oracle, SQLite, Snowflake, ClickHouse
- **Advanced Features**: MERGE, GROUPING SETS, materialized views
- **Modern SQL**: Full window function and CTE support

Expand Down
Loading
Loading