Awesome
go-zetasql
Go bindings for ZetaSQL
ZetaSQL can parse all queries related to Cloud Spanner and BigQuery. This functionality is provided from the Go language using cgo.
Features
-
No need to install ZetaSQL library
- go-zetasql contains all the source code needed to build ZetaSQL and builds at
go get github.com/goccy/go-zetasql
timing. Therefore, there is no need to install dependent libraries separately.
- go-zetasql contains all the source code needed to build ZetaSQL and builds at
-
Can create a portable single binary even though it using cgo
- You can create a static binary even with
CGO_ENABLED=1
by specifying the following options at build time:--ldflags '-extldflags "-static"'
- You can create a static binary even with
-
Can access all the APIs of the ZetaSQL parser
- The ZetaSQL parser is not publicly available, but it is available in go-zetasql
-
Can access analyzer APIs
Status
In the features of ZetaSQL, you can use the functions of the following packages. Will be added sequentially.
Package | Supported |
---|---|
parser | yes |
public | partial |
analyzer | yes |
scripting | no |
reference_impl | no |
Prerequisites
go-zetasql uses cgo. Therefore, CGO_ENABLED=1
is required to build.
Also, the compiler recommends clang++
. Please set CXX=clang++
to install.
Environment Name | Value |
---|---|
CGO_ENABLED | 1 ( required ) |
CXX | clang++ ( recommended ) |
Installation
go get github.com/goccy/go-zetasql
The first time you run it, it takes time to build all the ZetaSQL code used by go-zetasql.
Synopsis
Parse SQL statement
package main
import (
"github.com/goccy/go-zetasql"
"github.com/goccy/go-zetasql/ast"
)
func main() {
stmt, err := zetasql.ParseStatement("SELECT * FROM Samples WHERE id = 1", nil)
if err != nil {
panic(err)
}
// use type assertion and get concrete nodes.
queryStmt := stmt.(*ast.QueryStatementNode)
}
If you want to know the specific node of ast.Node, you can traverse by using ast.Walk.
package main
import (
"fmt"
"github.com/goccy/go-zetasql"
"github.com/goccy/go-zetasql/ast"
)
func main() {
stmt, err := zetasql.ParseStatement("SELECT * FROM Samples WHERE id = 1", nil)
if err != nil {
panic(err)
}
// traverse all nodes of stmt.
ast.Walk(stmt, func(n ast.Node) error {
fmt.Printf("node: %T loc:%s\n", n, n.ParseLocationRange())
return nil
})
}
Analyze SQL statement
If you have table information, you can use the analyzer API by using it as a Catalog. By using analyzer API, you can parse SQL based on table information and output normalized node. If you want to know the specific node of resolved_ast.Node, you can traverse by using resolved_ast.Walk.
package main
import (
"fmt"
"github.com/goccy/go-zetasql"
"github.com/goccy/go-zetasql/resolved_ast"
"github.com/goccy/go-zetasql/types"
)
func main() {
const tableName = "Samples"
catalog := types.NewSimpleCatalog("catalog")
catalog.AddTable(
types.NewSimpleTable(tableName, []types.Column{
types.NewSimpleColumn(tableName, "id", types.Int64Type()),
types.NewSimpleColumn(tableName, "name", types.StringType()),
}),
)
catalog.AddZetaSQLBuiltinFunctions()
out, err := zetasql.AnalyzeStatement("SELECT * FROM Samples WHERE id = 1000", catalog, nil)
if err != nil {
panic(err)
}
// get statement node from zetasql.AnalyzerOutput.
stmt := out.Statement()
// traverse all nodes of stmt.
if err := resolved_ast.Walk(stmt, func(n resolved_ast.Node) error {
fmt.Printf("%T\n", n)
return nil
}); err != nil {
panic(err)
}
}
Also, you can use the node.DebugString()
API to dump the result of resolved_ast.Node.
This helps to understand all nodes of statement.
stmt := out.Statement()
fmt.Println(stmt.DebugString())
License
Apache-2.0 License
Since go-zetasql builds all source code including dependencies at install time, it directly contains the source code of the following libraries. Therefore, the license is set according to the license of the dependent library.