04711cf7b2
* update error handling in various commands to use blank identifier * enhance output formatting for better readability * add golangci-lint to Makefile for linting checks
76 lines
2.1 KiB
Go
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
|
|
}
|