From c7d2c55228eb3608cd24c2750b7ffff713c45aa3 Mon Sep 17 00:00:00 2001 From: Dan Hansen Date: Thu, 28 Mar 2024 11:19:50 -0700 Subject: [PATCH 1/2] Enable `QUALIFY` without `GROUP BY` / `WHERE` / `HAVING` --- internal/analyzer.go | 3 +++ query_test.go | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/internal/analyzer.go b/internal/analyzer.go index c778cf0..c533bf4 100644 --- a/internal/analyzer.go +++ b/internal/analyzer.go @@ -88,6 +88,9 @@ func newAnalyzerOptions() *zetasql.AnalyzerOptions { ast.CreateViewStmt, ast.DropFunctionStmt, }) + // Enable QUALIFY without WHERE + //https://github.com/google/zetasql/issues/124 + langOpt.EnableReservableKeyword("QUALIFY", true) opt := zetasql.NewAnalyzerOptions() opt.SetAllowUndeclaredParameters(true) opt.SetLanguage(langOpt) diff --git a/query_test.go b/query_test.go index f92065e..6de6335 100644 --- a/query_test.go +++ b/query_test.go @@ -1807,7 +1807,6 @@ FROM UNNEST(['c', NULL, 'b', 'a']) AS x`, {"a", nil, "a", "c"}, }, }, - { name: "window range", query: ` @@ -3028,6 +3027,15 @@ FROM Produce WHERE Produce.category = 'vegetable' QUALIFY rank <= 3`, {"cabbage", int64(3)}, }, }, + // Regression test goccy/go-zetasqlite#123 + { + name: "qualify without group by / where / having", + query: `WITH toks AS (SELECT 1 AS x UNION ALL SELECT 2 AS x) + SELECT x FROM toks QUALIFY MAX(x) OVER (PARTITION BY x) > 1`, + expectedRows: [][]interface{}{ + {int64(2)}, + }, + }, // Regression test goccy/go-zetasqlite#150 { name: "qualify group", From 7793738092eccaea75d7fdfbfbc9af7e0e06b3fd Mon Sep 17 00:00:00 2001 From: Dan Hansen Date: Thu, 28 Mar 2024 15:22:20 -0700 Subject: [PATCH 2/2] handle error --- driver.go | 6 +++++- internal/analyzer.go | 19 +++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/driver.go b/driver.go index 3e93a8e..708a29a 100644 --- a/driver.go +++ b/driver.go @@ -85,9 +85,13 @@ func newZetaSQLiteConn(db *sql.DB, catalog *internal.Catalog) (*ZetaSQLiteConn, if err != nil { return nil, fmt.Errorf("failed to get sqlite3 connection: %w", err) } + analyzer, err := internal.NewAnalyzer(catalog) + if err != nil { + return nil, fmt.Errorf("failed to create analyzer: %w", err) + } return &ZetaSQLiteConn{ conn: conn, - analyzer: internal.NewAnalyzer(catalog), + analyzer: analyzer, }, nil } diff --git a/internal/analyzer.go b/internal/analyzer.go index c533bf4..8ac9da8 100644 --- a/internal/analyzer.go +++ b/internal/analyzer.go @@ -20,15 +20,19 @@ type Analyzer struct { opt *zetasql.AnalyzerOptions } -func NewAnalyzer(catalog *Catalog) *Analyzer { +func NewAnalyzer(catalog *Catalog) (*Analyzer, error) { + opt, err := newAnalyzerOptions() + if err != nil { + return nil, err + } return &Analyzer{ catalog: catalog, - opt: newAnalyzerOptions(), + opt: opt, namePath: &NamePath{}, - } + }, nil } -func newAnalyzerOptions() *zetasql.AnalyzerOptions { +func newAnalyzerOptions() (*zetasql.AnalyzerOptions, error) { langOpt := zetasql.NewLanguageOptions() langOpt.SetNameResolutionMode(zetasql.NameResolutionDefault) langOpt.SetProductMode(types.ProductInternal) @@ -90,12 +94,15 @@ func newAnalyzerOptions() *zetasql.AnalyzerOptions { }) // Enable QUALIFY without WHERE //https://github.com/google/zetasql/issues/124 - langOpt.EnableReservableKeyword("QUALIFY", true) + err := langOpt.EnableReservableKeyword("QUALIFY", true) + if err != nil { + return nil, err + } opt := zetasql.NewAnalyzerOptions() opt.SetAllowUndeclaredParameters(true) opt.SetLanguage(langOpt) opt.SetParseLocationRecordType(zetasql.ParseLocationRecordFullNodeScope) - return opt + return opt, nil } func (a *Analyzer) SetAutoIndexMode(enabled bool) {