DEPO на Firebird в мастере: подготовка базы одним действием, как для MSSQL

Мастер, шаг «Учёт DEPO», и «Обмен с DEPO» в настройках: СУБД «Firebird» (Fancy на Firebird 2.5).
- Подключение: драйвер nakagami/firebirdsql, путь к файлу базы или псевдоним, WIN1251. Запросы bj к DEPO
  (T-SQL) подключение переводит само (fancyfb.go): механически (dbo., TOP, ISNULL, GETDATE, LEN, N, exec)
  вне строк и комментариев, точные тексты — fsql/fb.go (каталоги, LIKE [_], COUNT(*) OVER, SELECT без FROM,
  PATINDEX); @имена — позиционные ?, GUID — в верхнем регистре. Системные запросы из кода — в fsql/depocatalog.go.
- «Подготовить» логином SYSDBA (depo_setup_fb.go): проверка базы и UDF Fancy, логин SYSDBA_BJ (Fancy даёт права
  на документы логинам SYSDBA%; для Firebird — обычный пользователь), оператор-робот Fancy, кодировщик M2M,
  привязки FTV_M2M_SETTINGS по признакам Fancy, таблицы, процедуры, права; обработку запускает bj.
  «Получить скрипт» — то же для isql в WIN1251; письмо администратору, установка процедур, плашка обновления.
- Скрипты Firebird встроены (depoprocs/firebird, тест сверяет с deploy/); количества — DOUBLE PRECISION: из
  диалекта 3 в базу диалекта 1 процедуру с NUMERIC(18,7) не создать.
- Проверено на копии базы Fancy (отдельный экземпляр bj): мастер с нуля — все проверки, BJ_PING; тестовый режим
  DEPO — К1 Бубликов, зачисление и списание до исполнения без ошибок; очередь, справочник НРД.
  Тест FBLive готовит на базе все запросы bj к DEPO: 94 из 101, оставшиеся 7 — ЛК и ручной ввод (следующий этап).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
This commit is contained in:
fontvielle
2026-10-27 18:55:02 +03:00
parent 7073ce2a33
commit 50e420f4a0
30 changed files with 2698 additions and 71 deletions
+34 -7
View File
@@ -219,12 +219,12 @@ func (h *setupHandlers) wizardDepoRecheck(w http.ResponseWriter, r *http.Request
func (h *setupHandlers) depoSetupForm(r *http.Request) (FancyMSSQLSettings, string, bool, string) {
s := h.rc.Snapshot().Fancy
dbType := "mssql"
if r.FormValue("db_type") == "postgres" {
dbType = "postgres"
if v := r.FormValue("db_type"); v == "postgres" || v == "firebird" {
dbType = v
}
port, _ := strconv.Atoi(strings.TrimSpace(r.FormValue("port")))
if port == 0 {
port = map[string]int{"mssql": 1433, "postgres": 5432}[dbType]
port = map[string]int{"mssql": 1433, "postgres": 5432, "firebird": 3050}[dbType]
}
server := strings.TrimSpace(r.FormValue("server"))
if server != s.Server || dbType != s.DBType {
@@ -235,15 +235,24 @@ func (h *setupHandlers) depoSetupForm(r *http.Request) (FancyMSSQLSettings, stri
if s.Encrypt == "" {
s.Encrypt = "disable"
}
agent := r.FormValue("depo_job") != "bj" && dbType != "postgres"
agent := r.FormValue("depo_job") != "bj" && dbType == "mssql" // у PostgreSQL и Firebird нет SQL Server Agent
s.DepoJobMode, s.DepoJobRun = "bj", !agent
if agent {
s.DepoJobMode = "sql-auto"
}
db := strings.TrimSpace(r.FormValue("depo_database"))
if db == "" { // bj по серверу базу не ищет: с какой базой работать, клиент говорит сам
if dbType == "firebird" {
return s, "", agent, "укажите путь к базе DEPO на сервере Firebird — как в настройке подключения Fancy"
}
return s, "", agent, "укажите имя базы DEPO — как она называется на сервере"
}
if dbType == "firebird" {
if !validFBPath(db) {
return s, "", agent, "путь к базе DEPO — без кавычек, ; ? и #"
}
return s, db, agent, ""
}
if !validDBName(db) {
return s, "", agent, "имя базы DEPO — только латинские буквы, цифры и _, начинается с буквы"
}
@@ -274,7 +283,12 @@ func depoEnsureLogin(s *FancyMSSQLSettings) {
// пароль) — тогда вписывают другое имя. Пустой пароль — bj придумает сам. Возвращает текст ошибки.
func depoBjCreds(r *http.Request, s *FancyMSSQLSettings) string {
if u := strings.TrimSpace(r.FormValue("bj_user")); u != "" {
if !depoLoginRe.MatchString(u) {
if s.IsFirebird() {
if !fbLoginRe.MatchString(u) {
return "логин bj для Firebird начинается с SYSDBA (например, " + depoFBDefaultLogin + "), дальше — латинские буквы, цифры и _: Fancy даёт права на документы только логинам SYSDBA…"
}
u = strings.ToUpper(u)
} else if !depoLoginRe.MatchString(u) {
return "логин bj — латинские буквы, цифры, точка, дефис и _"
}
if u != s.User {
@@ -323,7 +337,7 @@ func (h *setupHandlers) wizardDepoScript(w http.ResponseWriter, r *http.Request)
}
}
body := depoSetupScript(s, db, s.User, s.Password, agent)
if !s.IsPostgres() { // процедуры обработки bj2depo — тем же файлом
if !s.IsPostgres() && !s.IsFirebird() { // процедуры обработки bj2depo — тем же файлом (у Firebird — уже в скрипте)
body += "\nGO\n" + depoProcsScriptFor(s, db, s.User)
}
w.Header().Set("Cache-Control", "no-store")
@@ -332,6 +346,12 @@ func (h *setupHandlers) wizardDepoScript(w http.ResponseWriter, r *http.Request)
_, _ = w.Write([]byte(body))
return
}
if s.IsFirebird() { // isql -ch WIN1251: файл — в WIN1251, как база Fancy
w.Header().Set("Content-Type", "application/sql; charset=windows-1251")
w.Header().Set("Content-Disposition", `attachment; filename="`+depoSetupFileName(s)+`"`)
_, _ = w.Write(win1251(body))
return
}
if !s.IsPostgres() {
body = "\uFEFF" + body // SSMS без BOM читает кириллицу в комментариях как ANSI
}
@@ -413,7 +433,11 @@ func (h *setupHandlers) depoSetupDo(ctx context.Context, r *http.Request, step d
if err := depoSetupRun(ctx, s, db, au, r.FormValue("admin_password"), s.User, s.Password, agent, step); err != nil {
return fail("база не подготовлена — " + err.Error())
}
if !s.IsPostgres() { // процедуры обработки bj2depo (CREATE OR ALTER, с учётом правки под клиента)
if s.IsFirebird() { // процедуры и права поставил depoFBSetup — плашка обновления процедур не нужна
s.DepoDatabase = db
s.DepoProcsApplied, s.DepoProcsAppliedAt = depoProcsHash(s), time.Now()
}
if !s.IsPostgres() && !s.IsFirebird() { // процедуры обработки bj2depo (CREATE OR ALTER, с учётом правки под клиента)
step("procs", "run", "Устанавливаю процедуры обработки bj2depo")
adm := s
adm.User, adm.Password = au, r.FormValue("admin_password")
@@ -424,6 +448,9 @@ func (h *setupHandlers) depoSetupDo(ctx context.Context, r *http.Request, step d
}
s.DepoTablesMode = "auto"
note = "база " + db + " подготовлена: логин " + s.User + ", таблицы обмена, права"
if s.IsFirebird() {
note += ", оператор Fancy и процедуры обработки"
}
if agent {
note += ", задание " + depoJobName(s)
}