Source-compatible upgrade: exported signatures are unchanged apart from additions, so code that compiled against v1.16.0 compiles against v1.17.0. Parse acceptance, rendered SQL, security findings, transpiler errors and some CLI and LSP behaviour change. Work through the checklist below; the CHANGELOG has the full list.
- Real-world dialect corpus: 2,813 production-style statements across all 8 dialects now parse, format, re-parse identically and keep every word (1,327 failures before).
- Faithful formatting:
gosqlx.Format,gosqlx format, LSP and C-binding formatting keep comments, optimizer hints, SQL ServerGOlines, Oracle/lines and PostgreSQLU&"..."spellings. - Security:
ScanSQLbypasses through inline comments, quoted dollar tags and input truncation are closed,Scanner.Scanwalks the whole AST, and the CLI merges both scanners. - Robustness: the LSP server, C exports and transpiler no longer crash on malformed input, very long operator chains or panics, and metadata extraction is linear on nested CTEs.
gosqlx.FormatWithDialect,gosqlx.WithComments(), and the*Checkedformat variants (gosqlx.FormatASTChecked,gosqlx.FormatTreeChecked,Tree.FormatChecked,formatter.FormatASTChecked/FormatStatementChecked/FormatExpressionChecked,transform.FormatSQLChecked/FormatSQLWithDialectChecked), which return an error for nodes the target dialect cannot render instead of emitting changed SQL.formatter.JoinWithComments,formatter.JoinASTWithComments,formatter.CommentLayoutandformatter.ErrUnplaceableComment.linter.FileResult.TokenizeError,ParseErrorandSyntaxError().security.MaxScanInputSizeandsecurity.PatternInputTooLarge;dialect.StringEscape;tokenizer.IsKeyword.- AST:
ast.BatchSeparator(SQL ServerGO [n]),AST.ExecuteSlash/ExecuteSlashPositions,AST.StatementEnds,AST.UnicodeIdentifiers, identifierNameQuote/QuoteStylefields,LiteralValue.DialectExtras(),SelectStatement.Extras/DMLTargetFieldsand the other fields listed in the CHANGELOG.
- SQL Server
GO: a line holding onlyGO [n]inside a statement is a parse error, andGO 0/GO 1.5report "invalid GO repeat count".AST.Statementsnow contains*ast.BatchSeparatornodes: skip them when counting or indexing statements. Statement counts ingosqlx analyze/parse, MCPparse_sqland the C binding exclude GO. - SQL Server
top: unquotedtopis rejected as a table, target or alias name. Write[top]. - Numeric lexing is per dialect:
1_000,0b101,1xand similar forms are one literal or an error instead of a number plus an alias. See the table in the CHANGELOG. - MySQL / MariaDB:
#starts a line comment;:=assigns only to user variables. - Statement boundaries: outside SQL Server, a utility statement (
SET,GRANT,COPY,VACUUM, ...) followed by another statement without;is an error. Utility statements are accepted only in dialects that have them; a parser without a dialect still accepts all of them. -
gosqlx.Lint/LintWithDialectreturn an error wrappingErrTokenizeorErrSyntaxfor invalid SQL. Checkerrinstead of treating an empty result as clean. - Formatting keeps comments, hints, Oracle
/lines andU&"..."spellings; input whose hints cannot be placed returnsformatter.ErrUnplaceableComment. Regenerate golden files. - Fingerprints keep identifier quoting. Recompute stored fingerprints.
-
ScanSQLreports more findings (comment-obfuscated keywords, tautology checks over the whole input) and always adds a CRITICALINPUT_TOO_LARGEfinding above 10 MiB.a.id = b.idis no longer reported as a tautology. - Transpile to SQL Server: LIMIT / OFFSET on a UNION, INTERSECT or EXCEPT becomes
ORDER BY ... OFFSET ... FETCH; without ORDER BY it returns an error. Unrepresentable literals and operators,TOP PERCENT/WITH TIESwhere the target has no equivalent, and rewrites nested more than 512 levels deep return errors. - LSP: capabilities use the standard
textDocumentSynckey, so custom clients that readtextDocumentSyncOptionsmust switch; unknown methods return-32601;didChangecolumns are UTF-16 code units. - CLI:
gosqlx lintexits 1 on syntax errors;analyze --securityandlintincludeScanSQLfindings; empty and comment-only input is valid forvalidate,lintandformat;postgres,pg,mssql,tsqlandsqlite3work for every--dialect. - C binding: the ABI is unchanged. A recovered panic returns a JSON
"internal error"result, andgosqlx_version()returns NULL in that case, so handle NULL.
| Component | v1.16.0 | v1.17.0 |
|---|---|---|
Library (github.com/ajitpratap0/GoSQLX) |
1.16.0 | 1.17.0 |
CLI, MCP server and LSP serverInfo.version |
1.16.0 | 1.17.0 |
| VS Code extension and Claude Code plugin | 1.16.0 | 1.17.0 |
C binding (libgosqlx) |
1.16.0 exports | 1.17.0: same exports, panic-safe |
Python bindings (pygosqlx) |
1.16.0 | 1.17.0 |
Integrations (integrations/gorm, integrations/opentelemetry) |
1.16.0 | updated to 1.17.0 after the tag |
Source-compatible upgrade: exported signatures are unchanged apart from additions, so code that compiled against v1.15.0 compiles against v1.16.0. Runtime behaviour does change in several places (token positions, rendered SQL, parse acceptance, CLI refusals, MCP HTTP limits). Read the checklist below before upgrading. The CHANGELOG has the full list.
- SQL syntax highlighting: new
pkg/highlight,gosqlx.Highlight*, thegosqlx highlightcommand, LSP semantic tokens and the playground editor all share one dialect-aware classifier. See HIGHLIGHTING.md. - Dialect-aware LSP: the configured dialect drives diagnostics, formatting, symbols, completion and hover, and can be changed at runtime with
workspace/didChangeConfiguration. gosqlx-mcphardening and ChatGPT app support, plus a Claude Code plugin (/plugin marketplace add ajitpratap0/GoSQLX).- Performance audit (#566): zero-copy token values, linear position tracking and fewer allocations across the tokenizer, parser, AST, linter and LSP.
- Correctness sweep:
SQL(), the formatter andgosqlx formatround-trip far more constructs, and render-time SQL injection through quoted names is closed.
gosqlx.Highlight,gosqlx.HighlightANSI,gosqlx.HighlightHTMLandpkg/highlight(Spans,ANSI,HTML,CSS,WithDialect).gosqlx.LintWithDialect(sql, dialect)and(*linter.Linter).SetDialect.parser.WithPipesAsConcat()/gosqlx.WithPipesAsConcat()for MySQL/MariaDB servers running withPIPES_AS_CONCAT.Tokenizer.TokenizeString/TokenizeStringContextto tokenize a string without a[]bytecopy.keywords.DialectNames(): the 11 dialect names every surface accepts.pkg/mcp:NewRateLimitMiddleware,Config.TrustedProxyHeader,TrustedProxyHops,TrustedProxySecretHeader,TrustedProxySecret,Server.Shutdown.- AST additions:
FieldAccessExpression,ParenthesizedExpression,JoinClause.Using,TableReference.SetSubquery,TableReference.ColumnAliases,TableReference.WithOrdinality,BinaryExpression.PipesOr,Identifier.Quoted,WindowFrame.Exclude,WindowSpec.BaseWindow,SelectStatement.Settingsand others listed in the CHANGELOG. - CLI:
gosqlx highlight, and--dialectonparse,format,analyzeandlint.
- Token columns: a tab is now one column (it was four), and a token's
Startafter comments is the token itself. Columns are 1-based byte offsets. If you mapmodels.Location.Columnback to text, treat it as a byte offset. L006 reports byte columns too. - MySQL/MariaDB
||: undermysql/mariadb,||is logical OR. PassWithPipesAsConcat()if your server usesPIPES_AS_CONCAT. - Composite field access
(expr).fieldreturns E4001 under MySQL, MariaDB, SQL Server, SQLite, Oracle, Snowflake, ClickHouse and Redshift. - Zero-copy token values: token and AST strings reference the input.
strings.Cloneany value you cache long-term. - Oracle binds: under the Oracle dialect
:1and:nameare placeholders. - Sorted extraction:
Extract*andExtractMetadataresults are sorted; drop any code that sorted them itself or relied on map order. -
gosqlx formatrenders throughpkg/formatterand exits non-zero if the result does not re-parse to the same query;format -ithen leaves the file untouched. - Rendering: quoted names that need quotes keep them,
NOT EXISTS, named windows and window frame offsets render correctly, and readable style emits a single trailing;. Update golden files that captured the old output. - AST pooling:
ReleaseASTno longer pools most expression and statement nodes, andChildren()/Walkreturn pointers into the parent, so visitor edits now change the tree. Do not use those pointers afterReleaseAST. - Limits: comments count toward
MaxTokens; unary operators,NOTand derived tables count towardMaxRecursionDepth; qualified names over 5 parts return E2004. - LSP semantic tokens: the
identifiertoken type is now the standardvariable. Update editor rules such as Neovim@lsp.type.identifier. - Schema loaders: the PostgreSQL loader needs PostgreSQL 11+.
Index.Columnsexcludes INCLUDE columns (nowIndex.IncludeColumns), and tables with no foreign keys carry a nil slice. - LSP
serverInfo.versionnow reports the GoSQLX library version (1.16.0) instead of a hard-coded1.0.0. Update any client check that matched1.0.0. - CLI version stamping: release builds can set the
gosqlx --versionstring with-ldflags "-X github.com/ajitpratap0/GoSQLX/cmd/gosqlx/cmd.Version=<version>"; a plaingo buildkeeps the built-in 1.16.0. - C binding
gosqlx_version()now returns a newly allocated string on every call. Free each result once withgosqlx_free(earlier releases returned a shared pointer, so freeing it twice crashed). Callers that never freed it now leak a few bytes per call. - pygosqlx 1.16.0 (previously 0.2.0; now versioned in lockstep with GoSQLX) requires Python 3.10 or later (3.8 and 3.9 are dropped). An unknown
dialect=raisesUnsupportedDialectError, a subclass of bothGoSQLXErrorandValueError. -
gosqlx-mcpbehind a proxy: rate limiting keys on the TCP peer. SetGOSQLX_MCP_TRUSTED_PROXY_HEADER(for exampleCF-Connecting-IP) orGOSQLX_MCP_TRUSTED_PROXY_HOPS, optionally with the proxy-secret pair, or every client shares one bucket. Tool input errors are nowisErrorresults, andindent_sizemust be 0 to 16. See MCP_GUIDE.md.
| Component | v1.15.0 | v1.16.0 |
|---|---|---|
Library (github.com/ajitpratap0/GoSQLX) |
1.15.0 | 1.16.0 |
CLI (cmd/gosqlx, gosqlx --version) |
1.14.0 (stale constant) | 1.16.0 |
MCP server (cmd/gosqlx-mcp) |
1.14.0 (stale constant) | 1.16.0 |
VS Code extension (ajitpratap0.gosqlx) |
1.15.0 | 1.16.0 |
Claude Code plugin (gosqlx@gosqlx) |
— (new) | 1.16.0 |
OpenTelemetry integration (integrations/opentelemetry) |
requires v1.14.0 | updated after the tag |
GORM integration (integrations/gorm) |
requires v1.14.0 | updated after the tag |
LSP serverInfo.version (gosqlx lsp) |
1.0.0 (hard-coded) | 1.16.0 (library version) |
C binding (libgosqlx) |
1.15.0 exports | 1.16.0: adds gosqlx_*_dialect, gosqlx_lint, gosqlx_security_scan, gosqlx_transpile, gosqlx_dialects |
Python bindings (pygosqlx) |
0.2.0 (alpha) | 1.16.0 (alpha), now versioned in lockstep with GoSQLX; Python 3.10+; first PyPI release, published by the v1.16.0 tag |
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 has the full list.
- High-level
TreeAPI:gosqlx.ParseTreewith typed walkers,RewriteandClone, and functional options instead of theParseWith*combinations. - ClickHouse at 83/83 of the QA corpus:
ARRAY JOIN, scalar CTEs,CREATE MATERIALIZED VIEW ... ENGINE/TO,SAMPLE ... OFFSETandLIMIT offset, count. - Oracle gaps closed:
ROWNUM/ROWID/LEVEL/SYSDATEpseudo-columns,PIVOT/UNPIVOTINlists 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 thatWalk/Inspectused to skip.
gosqlx.ParseTree(ctx, sql, opts...)returning*Tree, withWalkSelects,WalkInserts,WalkUpdates,WalkDeletes,WalkCreateTables,WalkJoins,WalkCTEs,WalkFunctionCalls,WalkIdentifiers,WalkBinaryExpressions, genericWalkBy[T],Tree.RewriteandTree.Clone.- Options
WithDialect,WithStrict,WithTimeout,WithRecoveryandWithMaxBytes;ParseReader/ParseReaderMultiple, witherrors.Is(err, gosqlx.ErrTooLarge)when theWithMaxByteslimit is exceeded. FormatTree/FormatASTto format without re-parsing.gosqlx.SplitStatements(sql, dialect): dialect-aware script splitting on top-level;.gosqlx.Lint(sql)(all 30 rules),gosqlx.Analyze(sql), andErrorCode,ErrorLocationandErrorHintto unwrap structured error details.pkg/sql/dialect: typedDialectandCapabilities, exposed throughParser.DialectTyped(),Parser.Capabilities()andParser.Is<Dialect>()helpers.pkg/linter/config:.gosqlx.ymllinter configuration with rule enable/disable, severity overrides and ignore globs.keywords.Conflicts(),ast.UnsupportedStatementwithAST.HasUnsupportedStatements(), andast.PoolLeakCount().
- 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.Errorvalues with a code and position, and the legacyParse-family functions wrap theErrSyntax,ErrTokenize,ErrTimeoutandErrUnsupportedDialectsentinels. Match witherrors.Is/errors.Asinstead of comparing message strings. - Cancellation: a cancelled context returns
ctx.Err()directly, soerrors.Is(err, context.Canceled)works. -
*errors.Error.WithXmethods copy instead of mutating the receiver. Use the returned value. -
parser.ValidateBytes("")returns an error, matchinggosqlx.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.
pkg/sql/monitoris deprecated in favour ofpkg/metrics.parser.Parse([]token.Token),ParseFromModelTokensWithPositionsandConversionResult.PositionMappingare scheduled for removal in v2.0.
| 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 |
Drop-in upgrade — no breaking API changes. Anything that compiled against v1.13.0 will still compile and run identically against v1.14.0.
v1.14.0 is the largest dialect-coverage release in the project's history. Headline reasons to upgrade:
- Dialect-aware formatting —
transform.FormatSQLWithDialect()renders SQL in the target dialect's row-limiting syntax (TOP for SQL Server, FETCH FIRST for Oracle, LIMIT everywhere else). Closes #479. - Snowflake at 100% of the QA corpus (87/87) — MATCH_RECOGNIZE, @stage, SAMPLE, QUALIFY, VARIANT paths, time-travel, MINUS, LATERAL FLATTEN, TRY_CAST, IGNORE/RESPECT NULLS, LIKE ANY/ALL, CREATE STAGE/STREAM/TASK/PIPE stubs
- ClickHouse dialect significantly expanded (69/83 of the QA corpus, up from 53% in v1.13.0) — nested column types, parametric aggregates, bare-bracket arrays, ORDER BY WITH FILL, CODEC, WITH TOTALS, LIMIT BY, ANY/ALL JOIN, SETTINGS/TTL, INSERT FORMAT,
table/partitionas identifiers (#480). Known gaps tracked for v1.15: ARRAY JOIN, named windows, scalar CTE subqueries, materialized views - MariaDB dialect — SEQUENCE DDL, temporal tables, CONNECT BY
- Live schema introspection —
gosqlx.LoadSchema()queries Postgres, MySQL, and SQLite at runtime - SQL transpilation —
gosqlx.Transpile()converts between MySQL, PostgreSQL, and SQLite - 30 linter rules (up from 10) covering safety, performance, and naming
- CVE-2026-39883 (OpenTelemetry SDK) fixed
import (
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
"github.com/ajitpratap0/GoSQLX/pkg/sql/keywords"
"github.com/ajitpratap0/GoSQLX/pkg/transform"
)
tree, _ := gosqlx.ParseWithDialect("SELECT * FROM users u", keywords.DialectPostgreSQL)
stmt := tree.Statements[0]
transform.Apply(stmt, transform.SetLimit(100))
// Dialect-specific output
sqlserver := transform.FormatSQLWithDialect(stmt, keywords.DialectSQLServer)
// -> SELECT TOP 100 * FROM users u
oracle := transform.FormatSQLWithDialect(stmt, keywords.DialectOracle)
// -> SELECT * FROM users u FETCH FIRST 100 ROWS ONLY
postgres := transform.FormatSQLWithDialect(stmt, keywords.DialectPostgreSQL)
// -> SELECT * FROM users u LIMIT 100transform.FormatSQL(stmt) (generic, no dialect) continues to work unchanged.
import (
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
"github.com/ajitpratap0/GoSQLX/pkg/sql/keywords"
)
result, err := gosqlx.Transpile(
"CREATE TABLE t (id INT AUTO_INCREMENT PRIMARY KEY)",
keywords.DialectMySQL,
keywords.DialectPostgreSQL,
)
// result: "CREATE TABLE t (id SERIAL PRIMARY KEY)"Or from the CLI:
gosqlx transpile --from postgresql --to sqlite "SELECT * FROM users WHERE id = ANY(ARRAY[1,2,3])"import (
"context"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
"github.com/ajitpratap0/GoSQLX/pkg/schema/postgres"
)
loader, _ := postgres.New("postgres://user:pw@host/db")
defer loader.Close()
schema, _ := gosqlx.LoadSchema(context.Background(), loader)
for _, table := range schema.Tables {
fmt.Printf("%s.%s (%d columns)\n", table.Schema, table.Name, len(table.Columns))
}Also available: pkg/schema/mysql and pkg/schema/sqlite.
import "github.com/ajitpratap0/GoSQLX/pkg/fingerprint"
norm := fingerprint.Normalize("SELECT * FROM users WHERE id = 123")
// norm: "SELECT * FROM users WHERE id = ?"
hash := fingerprint.Fingerprint("SELECT * FROM users WHERE id = 123")
// hash: deterministic SHA-256 of the normalized formUse for query deduplication, caching, or aggregating metrics by query shape.
gosqlx transpile --from <dialect> --to <dialect> "<sql>" # Cross-dialect conversion
gosqlx optimize query.sql # Run OPT-001 through OPT-020 advisor
gosqlx stats # Object pool utilization
gosqlx watch queries/*.sql # Continuous validation on file change
gosqlx action --fail-on warn queries/ # GitHub Actions integrationSQL Server TOP clauses now render. If you were parsing SELECT TOP 10 * FROM users and round-tripping through formatter.FormatStatement() (or transform.FormatSQL()), the TOP 10 was being silently dropped from the output. This was a bug. In v1.14.0, parsed TopClause values correctly render.
If your code relied on the broken behavior (unlikely — it would have produced queries that returned the wrong row count), you'll now see TOP N in formatted output. For dialect-specific control, use FormatSQLWithDialect() and it will normalize based on the target.
parser.Parse([]token.Token)— useParseFromModelTokensinsteadParseFromModelTokensWithPositions— consolidated intoParseFromModelTokensConversionResult.PositionMapping— always nil, will be removed in v2
- CVE-2026-39883 (HIGH severity,
go.opentelemetry.io/otel/sdk): fixed by upgrading to v1.43.0. No action required for consumers —go get github.com/ajitpratap0/GoSQLX@v1.14.0 && go mod tidypicks up the fix transitively.
| Component | v1.13.0 | v1.14.0 |
|---|---|---|
Library (github.com/ajitpratap0/GoSQLX) |
1.13.0 | 1.14.0 |
CLI (cmd/gosqlx) |
1.13.0 | 1.14.0 |
MCP server (cmd/gosqlx-mcp) |
1.13.0 | 1.14.0 |
VS Code extension (ajitpratap0.gosqlx) |
1.13.0 | 1.14.0 |
OpenTelemetry integration (integrations/opentelemetry) |
v1.13.0 | v1.14.0 |
GORM integration (integrations/gorm) |
v1.13.0 | v1.14.0 |
Python bindings (pygosqlx) |
0.1.0 (alpha) | 0.2.0 (alpha) — independent semver track |
Go version requirement changed: Go 1.23+ is now required (was 1.21+). This is due to the mark3labs/mcp-go dependency used by the new MCP server. If you only use the parsing SDK (not the MCP server), Go 1.21+ still works, but go.mod declares 1.23.
No breaking API changes. Drop-in upgrade for existing code.
pkg/mcp/- MCP server package with 7 SQL toolscmd/gosqlx-mcp/- Standalone MCP server binary- See
docs/MCP_GUIDE.mdfor usage
No breaking changes. No API changes. Drop-in upgrade.
lint exit codes (CLI-7):
Previously: exits 0 unless errors present or --fail-on-warn set
Now: exits 1 whenever any violation (error, warning, or info) is found
Impact: CI pipelines using gosqlx lint as a gate will now correctly fail on warnings
E1009 for unterminated block comments (ERR-1):
Previously: unterminated /* ... */ emitted E1002 (generic string error code)
Now: emits E1009 ErrCodeUnterminatedBlockComment
Impact: code catching specific error codes for /* handling should update to E1009
This guide covers breaking changes in GoSQLX v1.8.0 and how to update your code. The primary breaking change is the token type system overhaul (#215) completed across PRs #252, #254, #255, #257, #258, #281, #267, #282, and #283.
| Usage Pattern | Breaking? | Action Required |
|---|---|---|
gosqlx.Parse(), gosqlx.Validate(), gosqlx.Format() |
No | None |
gosqlx.ParseWithTimeout(), gosqlx.ParseBytes() |
No | None |
CLI tool (gosqlx validate, gosqlx format, etc.) |
No | None |
pkg/sql/parser with parser.Parse() |
No | None |
Direct token.Token struct field access |
Yes | See below |
String-based token constants (token.SELECT, etc.) |
Yes | See below |
token.Token.ModelType field |
Yes | Renamed to Type |
ConvertTokensForParser() function |
Yes | Removed - use ParseFromModelTokens() |
If you only use the high-level gosqlx package or the CLI tool, v1.8.0 is fully backward compatible and no changes are needed.
The legacy string-based token.Type system has been completely removed. All token type comparisons now use models.TokenType (an integer type) for O(1) performance.
type Type stringfrompkg/sql/token- the string-based type definitionType(string) field fromtoken.Tokenstruct - replaced by the renamedModelType→Type- All string-based token constants -
token.SELECT,token.FROM,token.WHERE, etc. stringTypeToModelTypemap - the bridge between old and new type systemsnormalizeTokens()function - no longer needed with unified typesConvertTokensForParser()function - replaced byParseFromModelTokens()
// BEFORE (v1.7.0)
import "github.com/ajitpratap0/GoSQLX/pkg/sql/token"
tok := token.Token{
Type: token.SELECT, // string-based
ModelType: models.TokenTypeSelect, // int-based (was secondary)
Literal: "SELECT",
}
// AFTER (v1.8.0)
import "github.com/ajitpratap0/GoSQLX/pkg/sql/token"
import "github.com/ajitpratap0/GoSQLX/pkg/models"
tok := token.Token{
Type: models.TokenTypeSelect, // int-based (now primary)
Literal: "SELECT",
}// BEFORE (v1.7.0) - string comparison
if tok.Type == token.SELECT {
// handle SELECT
}
if tok.Type == "SELECT" {
// also worked
}
// AFTER (v1.8.0) - integer comparison (faster)
if tok.Type == models.TokenTypeSelect {
// handle SELECT
}| Old (string) | New (int) |
|---|---|
token.SELECT |
models.TokenTypeSelect |
token.FROM |
models.TokenTypeFrom |
token.WHERE |
models.TokenTypeWhere |
token.INSERT |
models.TokenTypeInsert |
token.UPDATE |
models.TokenTypeUpdate |
token.DELETE |
models.TokenTypeDelete |
token.CREATE |
models.TokenTypeCreate |
token.ALTER |
models.TokenTypeAlter |
token.DROP |
models.TokenTypeDrop |
token.JOIN |
models.TokenTypeJoin |
token.ON |
models.TokenTypeOn |
token.AND |
models.TokenTypeAnd |
token.OR |
models.TokenTypeOr |
token.NOT |
models.TokenTypeNot |
token.NULL |
models.TokenTypeNull |
token.TRUE |
models.TokenTypeTrue |
token.FALSE |
models.TokenTypeFalse |
token.AS |
models.TokenTypeAs |
token.IN |
models.TokenTypeIn |
token.LIKE |
models.TokenTypeLike |
token.BETWEEN |
models.TokenTypeBetween |
token.EXISTS |
models.TokenTypeExists |
token.CASE |
models.TokenTypeCase |
token.WHEN |
models.TokenTypeWhen |
token.THEN |
models.TokenTypeThen |
token.ELSE |
models.TokenTypeElse |
token.END |
models.TokenTypeEnd |
token.ORDER |
models.TokenTypeOrder |
token.GROUP |
models.TokenTypeGroup |
token.HAVING |
models.TokenTypeHaving |
token.LIMIT |
models.TokenTypeLimit |
token.OFFSET |
models.TokenTypeOffset |
token.UNION |
models.TokenTypeUnion |
token.EXCEPT |
models.TokenTypeExcept |
token.INTERSECT |
models.TokenTypeIntersect |
For a complete mapping, see the models.TokenType constants in pkg/models/token.go.
// BEFORE (v1.7.0)
tokenType := tok.ModelType // was the int-based secondary field
// AFTER (v1.8.0)
tokenType := tok.Type // ModelType renamed to Type// BEFORE (v1.7.0)
tokens, _ := tkz.Tokenize([]byte(sql))
converted, _ := parser.ConvertTokensForParser(tokens)
ast, _ := p.Parse(converted)
// AFTER (v1.8.0)
tokens, _ := tkz.Tokenize([]byte(sql))
ast, _ := p.ParseFromModelTokens(tokens)The TokenType.String() method provides human-readable names for all token types:
tok := token.Token{Type: models.TokenTypeSelect, Literal: "SELECT"}
fmt.Println(tok.Type.String()) // "SELECT"v1.8.0 adds dialect-aware parsing. No migration needed - existing code defaults to PostgreSQL:
// New (optional) - parse with explicit dialect
ast, err := parser.ParseWithDialect(sql, "mysql")
err = parser.ValidateWithDialect(sql, "mysql")The new pkg/transform/ package is purely additive:
import "github.com/ajitpratap0/GoSQLX/pkg/transform"
stmt, _ := transform.ParseSQL("SELECT * FROM orders")
transform.AddWhere(stmt, "tenant_id = 42")For multi-error parsing (useful for IDE integration):
ast, errors := gosqlx.ParseWithRecovery(sql)
// ast may be partial, errors contains all parse errors| Old | New | PR |
|---|---|---|
pkg/optimizer/ |
pkg/advisor/ |
#261 |
// BEFORE (v1.7.0)
tkz.SetDebugLogger(myLogger)
// AFTER (v1.8.0)
import "log/slog"
tkz.SetLogger(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelDebug})))The token type overhaul delivers ~50% faster parsing with no API changes needed for high-level users:
| Benchmark | v1.7.0 | v1.8.0 | Improvement |
|---|---|---|---|
| SimpleSelect 10 cols | 1542 ns/op | 783 ns/op | 49% faster |
| SimpleSelect 100 cols | 9736 ns/op | 4843 ns/op | 50% faster |
| SimpleSelect 1000 cols | 83612 ns/op | 39487 ns/op | 53% faster |
| SingleJoin | 1425 ns/op | 621 ns/op | 56% faster |
| SimpleWhere | 736 ns/op | 373 ns/op | 49% faster |
GoSQLX was relicensed from AGPL-3.0 to Apache License 2.0 in this release cycle (PR #227). This is a more permissive license that allows commercial use without copyleft obligations.
- Search your code for
token.SELECT,token.FROM, etc. - replace withmodels.TokenType* - Search for
tok.ModelType- rename totok.Type - Search for
tok.Type == "..."(string comparison) - replace withtok.Type == models.TokenType* - Search for
ConvertTokensForParser- replace withParseFromModelTokens - Search for
SetDebugLogger- replace withSetLogger - Search for
pkg/optimizerimports - replace withpkg/advisor - Run
go build ./...to verify - Run
go test -race ./...to validate
If you encounter issues migrating:
- Open an issue: https://github.com/ajitpratap0/GoSQLX/issues
- Join discussions: https://github.com/ajitpratap0/GoSQLX/discussions