Files
PgTidy/pkg/pgast/pgast.go
T
Hein 04711cf7b2
CI / Test (push) Successful in 28s
CI / Build (push) Successful in 25s
fix(cmd): handle errors and improve output formatting
* update error handling in various commands to use blank identifier
* enhance output formatting for better readability
* add golangci-lint to Makefile for linting checks
2026-07-01 12:53:25 +02:00

76 lines
2.1 KiB
Go

// Package pgast wraps go-pgquery (libpg_query compiled to WASM via wazero, no
// cgo) to produce a PostgreSQL parse tree from a SQL string.
//
// The concrete node types live in github.com/pganalyze/pg_query_go/v6 and are
// generated from the PostgreSQL source; callers import that package directly
// when walking the tree.
package pgast
import (
"strings"
pg_query "github.com/pganalyze/pg_query_go/v6"
waspg "github.com/wasilibs/go-pgquery"
)
// ParseResult is re-exported so callers don't need to import both packages.
type ParseResult = pg_query.ParseResult
// Parse parses sql and returns the PostgreSQL parse tree. The returned error
// is a pg_query parse error containing a message and location; it is safe to
// display to the user.
func Parse(sql string) (*ParseResult, error) {
return waspg.Parse(sql)
}
// FirstTokenOffset advances past whitespace and SQL comments (-- line and
// /* block */) from start, returning the byte offset of the first real token.
// This is needed because RawStmt.StmtLocation points to the start of the
// statement "block" which includes any preceding comments, not to the first
// keyword token.
func FirstTokenOffset(sql string, start int) int {
i := start
n := len(sql)
for i < n {
switch {
case sql[i] == ' ' || sql[i] == '\t' || sql[i] == '\r' || sql[i] == '\n':
i++
case i+1 < n && sql[i] == '-' && sql[i+1] == '-':
for i < n && sql[i] != '\n' {
i++
}
case i+1 < n && sql[i] == '/' && sql[i+1] == '*':
i += 2
for i+1 < n && (sql[i] != '*' || sql[i+1] != '/') {
i++
}
if i+1 < n {
i += 2
}
default:
return i
}
}
return start
}
// LocationToLineCol converts a 0-based byte offset into a 1-based (line, col)
// pair. Returns (1, 1) for a negative offset.
func LocationToLineCol(sql string, offset int) (line, col int) {
if offset < 0 {
return 1, 1
}
if offset > len(sql) {
offset = len(sql)
}
before := sql[:offset]
line = strings.Count(before, "\n") + 1
lastNL := strings.LastIndex(before, "\n")
if lastNL < 0 {
col = offset + 1
} else {
col = offset - lastNL
}
return line, col
}