312e4f70f1
ЛК (bj-lk берёт данные у bj-server) сам работает с той СУБД, что выбрана для DEPO. - Перевод на Firebird: YEAR/MONTH/DAY(x) — EXTRACT, AS float — AS DOUBLE PRECISION (float T-SQL — 8 байт, FLOAT Firebird — 4: точность сумм и цен в ЛК); шаблоны со сложением строк (история операций Hist02, поиск клиента Man01) — Firebird-тексты до подстановки (depoSQL); UPPER по кириллице — в WIN1251 (база NONE). - Курсы валют (Fx01): на Firebird запрос от всех курсов шёл больше 200 с (лимит 15 с — курсов нет) — для Firebird от 20 валют, 0,2 с. - База SPECTRE (архив портфеля и операций ЛК): поле в «Трансферные таблицы DEPO»; у Firebird — путь или строка подключения Fancy (может быть на другом компьютере); не задана — ЛК пишет, где указать. На данных SPECTRE не проверено: базы нет. - Тест FBLiveLK: функции ЛК, ручного ввода, сверки переводов и QUIK на копии базы по договору К1 Бубликова — все работают, 0,07–0,26 с каждая; FBLivePrepare — 101 из 101 запроса. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
116 lines
9.4 KiB
Go
116 lines
9.4 KiB
Go
package fsql
|
||
|
||
// FB — запросы к DEPO на Firebird (Fancy на Firebird 2.5, 27.10.2026): ключ — текст T-SQL, значение — текст
|
||
// Firebird с теми же @именами параметров. Здесь только то, что подключение к Firebird не переводит само
|
||
// (lkgateway/fancyfb.go переводит dbo., TOP, ISNULL, GETDATE(), N'…', exec): системные каталоги, LIKE с [_],
|
||
// оконные функции, OFFSET…FETCH, DATEADD с параметром. Параметр внутри функции — с CAST: Firebird иначе не
|
||
// знает его типа.
|
||
var FB = map[string]string{
|
||
Cat01: `SELECT CASE WHEN EXISTS (SELECT 1 FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = UPPER(REPLACE(CAST(@p1 AS VARCHAR(63)), 'dbo.', ''))) THEN 1 ELSE 0 END FROM RDB$DATABASE`,
|
||
|
||
Cat02: `SELECT TRIM(RDB$FIELD_NAME) FROM RDB$RELATION_FIELDS WHERE RDB$RELATION_NAME = UPPER(REPLACE(CAST(@p1 AS VARCHAR(63)), 'dbo.', ''))`,
|
||
|
||
// права: SYSDBA и владелец таблицы — всё; иначе — выданное логину или PUBLIC (RDB$PRIVILEGE: S, I, U, D)
|
||
Cat03: `SELECT CASE WHEN CURRENT_USER = 'SYSDBA'
|
||
OR EXISTS (SELECT 1 FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = UPPER(REPLACE(CAST(@p1 AS VARCHAR(63)), 'dbo.', '')) AND RDB$OWNER_NAME = CURRENT_USER)
|
||
OR EXISTS (SELECT 1 FROM RDB$USER_PRIVILEGES WHERE RDB$USER IN (CURRENT_USER, 'PUBLIC')
|
||
AND RDB$RELATION_NAME = UPPER(REPLACE(CAST(@p1 AS VARCHAR(63)), 'dbo.', '')) AND RDB$PRIVILEGE = SUBSTRING(CAST(@p2 AS VARCHAR(10)) FROM 1 FOR 1))
|
||
THEN 1 ELSE 0 END FROM RDB$DATABASE`,
|
||
|
||
Cat04: `SELECT COUNT(*) FROM RDB$RELATION_FIELDS WHERE RDB$RELATION_NAME = UPPER(CAST(@t AS VARCHAR(63))) AND RDB$FIELD_NAME = UPPER(CAST(@c AS VARCHAR(63)))`,
|
||
|
||
Cat05: `SELECT COUNT(*) FROM RDB$PROCEDURES p WHERE p.RDB$PROCEDURE_NAME = UPPER(REPLACE(CAST(@p AS VARCHAR(63)), 'dbo.', ''))
|
||
AND (CURRENT_USER = 'SYSDBA' OR p.RDB$OWNER_NAME = CURRENT_USER OR EXISTS (SELECT 1 FROM RDB$USER_PRIVILEGES u
|
||
WHERE u.RDB$USER IN (CURRENT_USER, 'PUBLIC') AND u.RDB$RELATION_NAME = p.RDB$PROCEDURE_NAME AND u.RDB$PRIVILEGE = 'X'))`,
|
||
|
||
Cat06: `SELECT CASE WHEN EXISTS (SELECT 1 FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = UPPER(REPLACE(CAST(@n AS VARCHAR(63)), 'dbo.', '')))
|
||
OR EXISTS (SELECT 1 FROM RDB$PROCEDURES WHERE RDB$PROCEDURE_NAME = UPPER(REPLACE(CAST(@n AS VARCHAR(63)), 'dbo.', ''))) THEN 1 ELSE 0 END FROM RDB$DATABASE`,
|
||
|
||
// в Firebird нет EXECUTE AS: процедуры работают правами, выданными им самим, — пользователь не нужен
|
||
Cat07: `SELECT 1 FROM RDB$DATABASE`,
|
||
|
||
QEv09: `SELECT REFERENCE FROM FTV_M2M_LINES WHERE GUID=@g AND (CAST(@i AS VARCHAR(12)) = '' OR UPPER(ISIN) = CAST(@i AS VARCHAR(12))) ORDER BY ID`,
|
||
|
||
QEv11: `SELECT FIRST 1 EVENT_DATE, COALESCE(STATE,''), COALESCE(COMMENT,'') FROM FTV_M2M_EVENTS
|
||
WHERE EVENT_TYPE='HANDBOOK' AND (COMMENT IS NOT NULL OR TRIM(COALESCE(STATE,'')) <> '') ORDER BY EVENT_DATE DESC`,
|
||
|
||
Hlth01: `SELECT FIRST (@n) * FROM (
|
||
SELECT CAST('FTV_M2M' AS VARCHAR(16)) AS T, ID, CAST(GUID AS VARCHAR(36)) AS G, CAST('' AS VARCHAR(36)) AS R, CAST(COALESCE(DIRECTION,'') AS VARCHAR(64)) AS K, COALESCE(TimeEnd, TimeNew) AS A, COALESCE(COMMENT,'') AS C
|
||
FROM FTV_M2M WHERE STATE='ERROR' AND COALESCE(TimeEnd, TimeNew) > DATEADD(DAY, -CAST(@d AS INTEGER), CURRENT_TIMESTAMP)
|
||
UNION ALL
|
||
SELECT 'FTV_M2M_EVENTS', ID, CAST(GUID AS VARCHAR(36)), COALESCE(REFERENCE,''), EVENT_TYPE, COALESCE(TimeEnd, TimeNew), COALESCE(COMMENT,'')
|
||
FROM FTV_M2M_EVENTS WHERE STATE='ERROR' AND EVENT_TYPE STARTING WITH 'BJ_' AND EVENT_TYPE <> 'BJ_PING' AND COALESCE(TimeEnd, TimeNew) > DATEADD(DAY, -CAST(@d AS INTEGER), CURRENT_TIMESTAMP)
|
||
) x ORDER BY A DESC`,
|
||
|
||
// COUNT(*) OVER () и OFFSET…FETCH в Firebird 2.5 нет: число — подзапросом, первая строка — FIRST 1
|
||
Hlth02: `SELECT FIRST 1 (SELECT COUNT(*) FROM FTV_M2M_EVENTS e WHERE e.STATE='ERROR' AND e.EVENT_TYPE STARTING WITH 'BJ_' AND e.ID > @last AND COALESCE(e.TimeEnd, e.TimeNew) > DATEADD(DAY, -1, CURRENT_TIMESTAMP)),
|
||
ID, EVENT_TYPE, CAST(GUID AS VARCHAR(36)), COALESCE(COMMENT,'')
|
||
FROM FTV_M2M_EVENTS WHERE STATE='ERROR' AND EVENT_TYPE STARTING WITH 'BJ_' AND ID > @last AND COALESCE(TimeEnd, TimeNew) > DATEADD(DAY, -1, CURRENT_TIMESTAMP)
|
||
ORDER BY ID DESC`,
|
||
|
||
Hlth03: `SELECT COALESCE(MAX(ID),0) FROM FTV_M2M_EVENTS WHERE EVENT_TYPE STARTING WITH 'BJ_'`,
|
||
|
||
// сложение строк (+) — ||; UNION строк разной длины — CAST; параметр в DATEADD — CAST
|
||
Hist02: `SELECT FIRST %d * FROM (
|
||
SELECT d.R_DATE AS RD, d.PROC_DATE AS PD, COALESCE(d.NUM,'') AS NUM, d.STATE AS ST, CAST('зачисление' AS VARCHAR(32)) AS KIND,
|
||
z.DEPO AS ACC, COALESCE(v.ISIN,'') AS ISIN, COALESCE(v.NAME,'') AS SEC, CAST(COALESCE(z.AMOUNT,0) AS DOUBLE PRECISION) AS QTY,
|
||
CAST(TRIM(COALESCE(z.COMMENT,'') || ' ' || COALESCE(z.REJECT_REASON,'')) AS VARCHAR(600)) AS NOTE
|
||
FROM U_OP_INV_ZACH z JOIN OD_DOCS d ON d.ID = z.DOC LEFT JOIN OD_VALUES v ON v.ID = z.SHARE
|
||
WHERE z.DEPO IN (%s)
|
||
UNION ALL
|
||
SELECT d.R_DATE, d.PROC_DATE, COALESCE(d.NUM,''), d.STATE, 'списание',
|
||
p.DEPO, COALESCE(v.ISIN,''), COALESCE(v.NAME,''), -CAST(COALESCE(p.AMOUNT,0) AS DOUBLE PRECISION),
|
||
TRIM(COALESCE(p.COMMENT,'') || ' ' || COALESCE(p.REJECT_REASON,''))
|
||
FROM U_OP_INV_SPIS p JOIN OD_DOCS d ON d.ID = p.DOC LEFT JOIN OD_VALUES v ON v.ID = p.SHARE
|
||
WHERE p.DEPO IN (%s)
|
||
UNION ALL
|
||
SELECT d.R_DATE, d.PROC_DATE, COALESCE(d.NUM,''), d.STATE, 'перевод: списание',
|
||
t.D_DEPO, COALESCE(v.ISIN,''), COALESCE(v.NAME,''), -CAST(COALESCE(t.AMOUNT,0) AS DOUBLE PRECISION),
|
||
TRIM(COALESCE(t.COMMENT,'') || ' ' || COALESCE(t.REJECT_REASON,''))
|
||
FROM U_OP_INV_PEREVOD t JOIN OD_DOCS d ON d.ID = t.DOC LEFT JOIN OD_VALUES v ON v.ID = t.SHARE
|
||
WHERE t.D_DEPO IN (%s)
|
||
UNION ALL
|
||
SELECT d.R_DATE, d.PROC_DATE, COALESCE(d.NUM,''), d.STATE, 'перевод: зачисление',
|
||
t.K_DEPO, COALESCE(v.ISIN,''), COALESCE(v.NAME,''), CAST(COALESCE(t.AMOUNT,0) AS DOUBLE PRECISION),
|
||
TRIM(COALESCE(t.COMMENT,'') || ' ' || COALESCE(t.REJECT_REASON,''))
|
||
FROM U_OP_INV_PEREVOD t JOIN OD_DOCS d ON d.ID = t.DOC LEFT JOIN OD_VALUES v ON v.ID = t.SHARE
|
||
WHERE t.K_DEPO IN (%s)) x
|
||
WHERE x.RD >= @p1 AND x.RD < DATEADD(DAY, 1, CAST(@p2 AS TIMESTAMP))
|
||
ORDER BY x.RD DESC, x.NUM DESC`,
|
||
|
||
// сложение строк — ||; UPPER по кириллице — в WIN1251 (база Fancy — NONE, там UPPER меняет только латиницу)
|
||
Man01: `SELECT FIRST 20 COALESCE(NULLIF(f.SELF_ID,0),f.ID), COALESCE(f.NAME,''), f.DATE_BIRTH, COALESCE(f.DOC_TYPE,0), COALESCE(f.DOC_SER,''), COALESCE(f.DOC_NUM,''),
|
||
f.DOC_DAT, COALESCE(f.DOC_PLACE,''), COALESCE(f.DOC_CODE,''), COALESCE(f.PHONE,'')
|
||
FROM OD_FACES f
|
||
WHERE COALESCE(f.LAST_FLAG,1)=1 AND (UPPER(CAST(f.NAME AS VARCHAR(255) CHARACTER SET WIN1251)) LIKE UPPER(CAST(@q AS VARCHAR(255) CHARACTER SET WIN1251))
|
||
OR f.DOC_NUM=@d OR REPLACE(COALESCE(f.DOC_SER,''),' ','') || f.DOC_NUM=@d)
|
||
AND EXISTS (SELECT 1 FROM OD_CLIENTS c WHERE c.FACE=COALESCE(NULLIF(f.SELF_ID,0),f.ID) AND c.NUMBER LIKE '{ACC}%' AND c.STATE=0 AND c.D_CLOSE IS NULL)
|
||
ORDER BY f.NAME`,
|
||
|
||
// последние курсы валют: от 20 валют, а не от всех курсов — Firebird иначе перебирает миллионы строк
|
||
// с подзапросом на каждую (на MSSQL — доли секунды, на Firebird — больше 200 с)
|
||
Fx01: `SELECT UPPER(TRIM(v.SYSNAME)),
|
||
(SELECT FIRST 1 x.OFICDATE FROM OD_VALUES_RATES x WHERE x.VALUE_ID = v.ID AND x.MARKET = 0 AND x.RATE > 0 ORDER BY x.OFICDATE DESC),
|
||
(SELECT FIRST 1 CAST(x.RATE AS DOUBLE PRECISION) FROM OD_VALUES_RATES x WHERE x.VALUE_ID = v.ID AND x.MARKET = 0 AND x.RATE > 0 ORDER BY x.OFICDATE DESC)
|
||
FROM OD_VALUES v WHERE v.V_TYPE = 1`,
|
||
|
||
// SELECT без FROM в Firebird нет
|
||
QEvPosted: `SELECT (SELECT COUNT(*) FROM FTV_M2M WHERE GUID=@g),
|
||
(SELECT COUNT(*) FROM FTV_M2M_EVENTS WHERE GUID=@g AND EVENT_TYPE='BJ_ORDER_ACCEPTED' AND STATE='SUCCESS'),
|
||
(SELECT COUNT(*) FROM FTV_M2M_EVENTS WHERE GUID=@g AND EVENT_TYPE='BJ_ORDER_ACCEPTED' AND STATE<>'SUCCESS'),
|
||
COALESCE((SELECT FIRST 1 STATE FROM FTV_M2M WHERE GUID=@g ORDER BY ID DESC),''),
|
||
COALESCE((SELECT FIRST 1 COMMENT FROM FTV_M2M WHERE GUID=@g AND STATE='ERROR' ORDER BY ID DESC),
|
||
(SELECT FIRST 1 COMMENT FROM FTV_M2M_EVENTS WHERE GUID=@g AND EVENT_TYPE='BJ_ORDER_ACCEPTED' AND STATE='ERROR' ORDER BY ID DESC), '')
|
||
FROM RDB$DATABASE`,
|
||
|
||
// PATINDEX в Firebird 2.5 нет: начало номера до первой цифры — по ближайшей из позиций цифр
|
||
Acc01: `SELECT FIRST 8 p, COUNT(*) FROM (SELECT LEFT(NUMBER, MINVALUE(POSITION('0' IN NUMBER || '0'),
|
||
COALESCE(NULLIF(POSITION('1' IN NUMBER), 0), 9999), COALESCE(NULLIF(POSITION('2' IN NUMBER), 0), 9999),
|
||
COALESCE(NULLIF(POSITION('3' IN NUMBER), 0), 9999), COALESCE(NULLIF(POSITION('4' IN NUMBER), 0), 9999),
|
||
COALESCE(NULLIF(POSITION('5' IN NUMBER), 0), 9999), COALESCE(NULLIF(POSITION('6' IN NUMBER), 0), 9999),
|
||
COALESCE(NULLIF(POSITION('7' IN NUMBER), 0), 9999), COALESCE(NULLIF(POSITION('8' IN NUMBER), 0), 9999),
|
||
COALESCE(NULLIF(POSITION('9' IN NUMBER), 0), 9999)) - 1) AS p
|
||
FROM OD_CLIENTS WHERE STATE=0 AND D_CLOSE IS NULL AND NUMBER IS NOT NULL) x
|
||
WHERE p <> '' GROUP BY p ORDER BY COUNT(*) DESC`,
|
||
}
|