package lkgateway // Живая проверка перевода запросов на Firebird: каждый запрос bj к DEPO (fsql) готовится (PREPARE, без // выполнения) на настоящей базе Fancy. Запуск — с подключением к копии базы: // BJ_FB_TEST_DSN='firebird://SYSDBA:пароль@127.0.0.1:3050/путь_к_базе?charset=WIN1251' go test -run FBLive ./internal/lkgateway import ( "context" "database/sql" "database/sql/driver" "fmt" "go/ast" "go/parser" "go/token" "os" "path/filepath" "sort" "strconv" "strings" "testing" "time" "git.zetit.ru/zuevav/Bridge-and-Join-s/internal/lkgateway/fsql" ) func readRepoFile(p string) ([]byte, error) { return os.ReadFile(filepath.Join("..", "..", p)) } // fbLiveTodo — личный кабинет и ручной ввод: на Firebird — следующий этап (YEAR(), %, сложение строк). var fbLiveTodo = map[string]bool{"Arch02": true, "Arch03": true, "Arch07": true, "Arch08": true, "Arch10": true, "Hist02": true, "Man01": true} // fbLiveSkip — не к DEPO (PostgreSQL bj и экспорт QUIK, база МНП QUIK, SPECTRE) или куски составных запросов. var fbLiveSkip = map[string]bool{ "Doc02": true, "Doc03": true, "Doc04": true, "Sn01": true, "Sn02": true, "Sn03": true, "Sn04": true, "Sn05": true, "On01": true, "On02": true, "On03": true, "Pr01": true, "Qk01": true, "Cl01": true, "Tbl01": true, "Tbl02": true, "QTb01": true, "Ev05": true, // DEPONENT_ID — пишется, только если колонка есть (depoHasColumn) "Que04": true, "Que05": true, "Ev06": true, "Ev07": true, "Ev08": true, "Ev09": true, "Que01": true, "Que02": true, "Que03": true, "Flow01": true, "Flow02": true, } // fbLiveQueries — строки-запросы пакета fsql по именам; шаблоны заполнены так, как их заполняет код. func fbLiveQueries(t *testing.T) map[string]string { fset := token.NewFileSet() pkgs, err := parser.ParseDir(fset, "fsql", nil, 0) if err != nil { t.Fatal(err) } out := map[string]string{} for _, p := range pkgs { for _, f := range p.Files { for _, d := range f.Decls { g, ok := d.(*ast.GenDecl) if !ok || g.Tok != token.VAR { continue } for _, s := range g.Specs { vs := s.(*ast.ValueSpec) for i, n := range vs.Names { if i >= len(vs.Values) { continue } lit, ok := vs.Values[i].(*ast.BasicLit) if !ok || lit.Kind != token.STRING || fbLiveSkip[n.Name] { continue } q, err := strconv.Unquote(lit.Value) if err != nil { continue } q = strings.ReplaceAll(q, "{ACC}", "ВТНКЦ") q = strings.ReplaceAll(q, "%d", "10") q = strings.ReplaceAll(q, "%s", "1") out[n.Name] = q } } } } } doc := "CAST(m.DOC AS varchar(32))" out["Ev07+"] = fsql.Ev07 + doc + fsql.Ev08 + doc + fsql.Ev09 + doc + `) FROM dbo.FTV_M2M m WHERE m.TimeNew > DATEADD(day,-45,GETDATE()) ORDER BY m.ID DESC` out["Que01+"] = fsql.Que01 + "m.TimeNew" + `, ISNULL(` + doc + fsql.Que02 + doc + fsql.Que03 + doc + `) FROM dbo.FTV_M2M m ORDER BY m.TimeNew DESC` out["Flow01+"] = fsql.Flow01 + doc + fsql.Flow02 out["Que04+"] = fsql.Que04 + "TimeNew DESC)" out["Que05+"] = fsql.Que05 + "TimeNew DESC) ORDER BY e.EVENT_DATE" out["Ev06+"] = fsql.Ev06 + "GUID, REFERENCE, ISIN, SEC_CODE, AMOUNT, PLACE_NUMBER, LINK_NUMBER, SHARE, DEPO_NUMBER, TimeNew) VALUES (@g, @r, @i, @c, @a, @p, @lnk, @sh, @acc, GETDATE())" return out } func TestFBLivePrepare(t *testing.T) { dsn := os.Getenv("BJ_FB_TEST_DSN") if dsn == "" { t.Skip("BJ_FB_TEST_DSN не задан") } probe, err := sql.Open("firebirdsql", dsn) if err != nil { t.Fatal(err) } base, err := probe.Driver().(driver.DriverContext).OpenConnector(dsn) if err != nil { t.Fatal(err) } db := sql.OpenDB(fbConnector{base: base}) defer db.Close() ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() qs := fbLiveQueries(t) names := make([]string, 0, len(qs)) for n := range qs { names = append(names, n) } sort.Strings(names) var bad []string todo := 0 for _, n := range names { st, err := db.PrepareContext(ctx, qs[n]) if err != nil { if fbLiveTodo[n] { todo++ t.Logf("(следующий этап) %s: %v", n, strings.ReplaceAll(err.Error(), "\n", " ")) continue } bad = append(bad, fmt.Sprintf("%s: %v\n %s", n, err, depoStmtHead(fbSQL(qs[n])))) continue } st.Close() } t.Logf("подготовлено %d из %d запросов, отложено %d", len(names)-len(bad)-todo, len(names), todo) for _, b := range bad { t.Log(b) } if len(bad) > 0 { t.Fail() } } var _ driver.Connector = fbConnector{}