Skip to content

Releases: dobpilot/open-sdbl

open-sdbl 0.8.0

Choose a tag to compare

@dobpilot dobpilot released this 22 Sep 11:35

Релиз после 0.7.0: open-sdbl-db научился отдавать не только имена, которые нужны компилятору, но и саму конфигурацию — одним чтением, из той же read-only транзакции, что и метаданные. Изменение оформлено спецификацией OpenSpec (crate-architecture, onec-metadata, access-rights).

Зачем

Потребителю, которому нужны ресурсы конфигурации, приходилось читать Config второй раз — уже после закрытия сеанса, против базы, о которой он больше ничего не знает. Между двумя чтениями конфигурацию могли обновить, расширение включить, ресурс переписать, и ничто в результате об этом бы не сказало.

Согласованное получение конфигурации

use open_sdbl_db::{DatabaseSession, Limits, NoProgress};

let mut session =
    DatabaseSession::connect(&connection, &credentials, Limits::default()).await?;
let configuration = session.configuration(&mut NoProgress).await?;

// Снимок и отчёт — те же, что вернул бы `metadata()`.
let snapshot = &configuration.metadata;
// Каждый ресурс таблицы `Config`, собранный из всех `PartNo`, байтами как
// их хранит база: сырой DEFLATE, без распаковки и перекодирования.
for resource in &configuration.config_resources {
    let _ = (&resource.file_name, &resource.compressed);
}
// Расширения в порядке применения платформой, каждое со своими ресурсами.
for extension in &configuration.extensions {
    if extension.active == Some(false) {
        continue;
    }
    let _ = (&extension.identity, &extension.name, extension.order, &extension.resources);
}

AcquiredConfiguration несёт metadata, report, layout, config_resources и extensions; AcquiredExtension — identity, name, active, order, resources. Операция есть и на DatabaseSession, и на обеих сессиях провайдеров, и как свободная acquire_configuration над MetadataSource.

Что операция обещает и чего не обещает

Второго конвейера метаданных и второго пути к СУБД нет: acquire_metadata стала обёрткой над одним внутренним получением, план различается ровно одним шагом. Возвращаются те самые ресурсы, из которых разрешён снимок, — конфигурация читается один раз, а не дважды.

Это не атомарный снимок базы. Транзакция идёт на READ COMMITTED: каждый оператор видит зафиксированное на момент своего начала, и запись в базу во время чтения может развести соседние операторы. Поднять изоляцию бесплатно нельзя — у SQL Server нет MVCC-уровня без ALLOW_SNAPSHOT_ISOLATION, настройки базы, которой библиотека не вправе требовать, а блокирующие уровни заставили бы read-only инструмент блокировать писателей. Поэтому сужен контракт, а не поднята изоляция: операция убирает второе чтение после закрытия сеанса, а узнать, сдвинулась ли конфигурация, можно сравнением CONFIG_FINGERPRINT до и после. Результат публикуется только после успешного завершения всего чтения; любая ошибка откатывает транзакцию и не отдаёт частичный результат.

Расширения

Ресурсы группируются по корневому индексу каждого расширения, а не по имени в content-addressed ConfigCAS, поэтому одинаковые имена в двух расширениях не сливаются. Идентичность — _IDRRef в hex, переживает переименование; порядок — _ExtensionOrder.

Признак применяемости измерен, а не угадан: на базе с двумя расширениями, одинаковыми во всём, кроме того, что платформа применяет одно и не применяет другое, записи по 177 байт различаются в корневом ключе, одном символе синонима и байте на три от конца — 0x82 у применяемого, 0x81 у остального. Оба блоба легли фикстурами.

active — Option<bool>. Разбор _ExtensionZippedInfo знает свои теги и останавливается на любом другом, а флаг принимается, только если разбор дошёл до терминатора и прошёл этот байт именно как односложный тег, а не как payload неизвестного счётного поля. Иначе активность неизвестна: сообщить false про расширение, которое база применяет, значило бы заставить потребителя пропустить живой код.

Пределы и расход памяти

ConfigResource::compressed — Arc<[u8]>: общая строка хранилища и партии декодера стоят ссылку, а не копию конфигурации. В Limits добавлены config_resource_limit (1 000 000) и config_retained_byte_limit (2 ГиБ). Потолки применяются к каждому собираемому хранилищу по отдельности — сначала Config, затем самостоятельно ConfigCAS, — и оба набора удерживаются одновременно, поэтому пик равен потолку столько раз, сколько хранилищ собирается. Totals проверяются до первой строки ресурсов, а потолок повторно — по фактически пришедшему, поскольку totals это отдельный оператор и может устареть. При превышении возвращается типизированная DbError, а не OOM.

Прочее

  • DatabaseSession::metadata не изменился: та же сигнатура, тот же результат, та же цена — по-прежнему поток с фильтром, ничего не удерживающий.
  • Новые SELECT-only выражения CONFIG_ALL, CONFIG_ALL_LEGACY, CONFIG_ALL_TOTALS у обоих провайдеров, в обоих вариантах раскладки; EXTENSIONS теперь отдаёт идентичность и порядок рядом с именем.
  • open_sdbl::metadata::is_config_metadata_resource задаёт фильтр имён ресурсов один раз — тот же, что кодируют выражения обоих провайдеров.
  • InfoBaseUser::can_authenticate() — владелец правила «есть ли у пользователя способ войти»: стандартная аутентификация или непустой логин ОС. Ни список выбора, ни AdmRole, ни роли на ответ не влияют; AdmRole — право, а не способ входа.

Новых production-зависимостей не добавлено. cargo tree -p open-sdbl -e normal по-прежнему пуст: ядро остаётся без зависимостей и без I/O.

open-sdbl 0.7.0

Choose a tag to compare

@dobpilot dobpilot released this 20 Sep 16:05

Релиз после 0.6.0: слой работы с СУБД вынесен из консоли в отдельную библиотеку open-sdbl-db. Это перенос, а не переписывание — поведение консоли не изменилось ни в одном месте: те же коды возврата, те же сообщения об ошибках, тот же вывод \users, \roles, \role, \rls, \as, \restrict, \session, \d. Изменение оформлено спецификацией OpenSpec (crate-architecture).

Зачем

Подключение в проверенной read-only транзакции, чтение метаданных, права ролей, разворачивание RLS-ограничений пользователя и декодирование ячеек результата жили в crates/open-sdbl-cli/src под pub(crate) и были доступны только консоли. Это security-логика: копировать её во второе приложение — значит получить две копии, которые разойдутся. Поэтому она стала библиотекой, а консоль — её первым потребителем.

Три крейта

  • open-sdbl (корень) — без изменений: ноль production-зависимостей, #![forbid(unsafe_code)], никакого I/O. Декодирует переданные байты и генерирует SQL.
  • open-sdbl-db (новый) — I/O СУБД и сети: оба драйвера (tokio-postgres, Tiberius), конвейер чтения метаданных, транспорт SOCKS5, ячейки результата, AccessStore с выводом ограничений пользователя, RestrictionStore, кеш параметров сеанса БСП и индекс ролей расширений конфигурации. Ничего не печатает, не разбирает командную строку, не читает переменные окружения и файл паролей.
  • open-sdbl-cli — процесс, терминал и файловая система: разбор аргументов, REPL, форматирование вывода, отрисовка прогресса, ~/.pgpass и работа с секретами.

Публичный API библиотеки

use open_sdbl_db::{DatabaseSession, Limits, NoProgress};

let mut session =
    DatabaseSession::connect(&connection, &credentials, Limits::default()).await?;
let (snapshot, report) = session.metadata(&mut NoProgress).await?;
let rows = session.query(&sql, columns).await?;
session.close().await?;

Доступны DatabaseSession, DatabaseDialect, QueryCancellation, MetadataSource, acquire_metadata, AccessStore, role_restrictions, user_restrictions, derive_restrictions, RestrictionStore, read_current_user, read_template_parameters, ExtensionIndex, read_extension_index, read_extension_roles, Cell, QueryRows, декодеры ячеек обоих диалектов, DbError, типы описания подключения, Credentials и трейт прогресса. Всё публичное документировано по-английски; cargo doc проходит с -D warnings.

Где проведена граница

  • DbError — ошибки СУБД с предикатами is_database_timeout, is_mssql_connection_failure, requires_mssql_disconnect. CliError получил вариант Db(DbError) и From, коды возврата и тексты сообщений сохранены до байта.
  • Отчёт резолвера не печатается библиотекой: acquire_metadata возвращает (snapshot, layout, report), печатает вызывающий — в том же месте последовательности, что и раньше.
  • Прогресс — трейт MetadataProgress с пустыми телами по умолчанию и готовой реализацией NoProgress. Терминальная отрисовка осталась в консоли.
  • Описание подключения и носитель секрета — обычные типы библиотеки. Чтение PGPASSWORD/MSSQL_PASSWORD/SOCKS5_PASSWORD и PGPASSFILE/~/.pgpass, вместе с проверкой владельца и прав файла, осталось в консоли: она отдаёт библиотеке уже готовый секрет в зачищаемой памяти.
  • Параметры сеанса: библиотечные функции принимают &SessionParameters. Команды \users…\as, которые пишут в стор параметров REPL, остались в консоли.
  • Limits — одна структура вместо четырёх констант: таймаут соединения, таймаут запроса, таймаут закрытия PostgreSQL и размер пакета декодирования Config. Default даёт ровно прежние значения (10 с, 120 с, 5 с, 256), сессия применяет то, с чем открыта, внешний потребитель задаёт своё.

Чего нет

Фич postgres/mssql для отключения ненужного драйвера в этом релизе нет: они потребовали бы #[cfg] на вариантах DatabaseSession, DatabaseDialect, DbError и примерно на двадцати ветвях match, то есть переписывания того самого кода, который переносится без изменений. Обоснование — в openspec/changes/archive/2026-09-20-extract-database-crate/design.md.

Новых production-зависимостей не добавлено: все зависимости нового крейта переехали из манифеста консоли. cargo tree -p open-sdbl -e normal по-прежнему пуст.

open-sdbl 0.6.0

Choose a tag to compare

@dobpilot dobpilot released this 20 Sep 12:36

Релиз после 0.5.5: чтение прав доступа доведено до рабочего состояния на трёх типовых базах — УНФ, «Документооборот» (PostgreSQL и MS SQL Server). Каждое изменение поведения — со своей спецификацией OpenSpec.

Ограничения доступа применяются к запросам

\as <пользователь> теперь не только запоминает пользователя, а разворачивает ограничения его ролей на Чтение и кладёт их в тот же список, что и \restrict, — по строке на объект, на языке 1С:

open-sdbl=> \as Петрова (бухгалтер)
Current user: Петрова (бухгалтер) (640 roles): …
7 session parameters read from the base: ВерсииШаблоновОграниченияДоступа, …
375 restrictions derived into \restrict.
Петрова (бухгалтер)=>

Набранное руками \restrict перекрывает развёрнутое и никогда не затирается; \as clear и \refresh забывают развёрнутые, \session разворачивает их заново. Приглашение консоли называет текущего пользователя.

Параметры сеанса берутся из базы

\as читает то, что база хранит для своих шаблонов: регистр сведений ПараметрыОграниченияДоступа (на MS SQL Server значение лежит в колонке, на PostgreSQL — ссылкой STORHDR на части в binarydata), элемент Справочник.Пользователи по идентификатору пользователя ИБ как ТекущийПользователь и пустую ссылку ВнешниеПользователи. Заданное руками не перетирается; если регистр есть, а прочитать его не удалось — названа причина.

Шаблоны ограничений

  • parse_template разбирает текст ограничения или тело шаблона в узлы TemplateNode — текст, #Если с ветвями, вызовы с аргументами, #Параметр(N) и прочие имена — со смещением каждого узла; несбалансированные директивы дают ошибку с позицией.
  • Директивы по документации 5.5.4.8.7: #ТекущаяТаблица (имя таблицы), #ИмяТекущейТаблицы (оно же строковым значением, в кавычках), ## как один #, вызов шаблона без скобок.
  • Полная форма платформы: описание таблицы после ИЗ и соединения ЛЕВОЕ/ВНУТРЕННЕЕ перед ГДЕ. Соединения компилируются в коррелированный предикат со строкой-якорем (VALUES (1)), поэтому не размножают строки ограничиваемой таблицы.
  • Консоль показывает шаблоны: \role — сигнатуры, \template <роль> [<имя>] — тело, из чего оно состоит и разбирается ли.

Роли расширений

Роль, которой нет в Config, ищется в расширениях: _ExtensionsInfo хранит ключ корневого ресурса, корень — индекс имя → ключ, ConfigCas адресует ресурсы по ключу. Читаются и права (<guid>.0), и описатель (<guid>), поэтому роль расширения называется и ограничивает. Роль, которой нет нигде, ничего не даёт и названа в отчёте, а не валит команду.

Консоль

  • \users и \user показывают e-mail (v8users.Email, с проверкой наличия колонки).
  • \rls без аргументов — список ограничений в прочитанных правах: роль, объект, право.
  • Команды доступа добавлены в автодополнение.

Производительность

Поиск без учёта регистра при разворачивании сворачивал текст на каждое вхождение: одно разворачивание шаблона БСП стоило 0.63 с. Теперь текст сворачивается один раз на поиск — \as для пользователя с 640 ролями и 470 ограниченными объектами занимает 2 с вместо 5 минут, и настолько же быстрее любой запрос к ограниченной таблице.

Совместимость

  • ExpandedRestriction получил поле joins; RestrictionError — вариант SyntaxAt { message, offset } (перечисление #[non_exhaustive]).
  • Новое в API: parse_template, TemplateNode, TemplateBranch, RestrictionTemplate::new, parse_serialized_sequence, ContentKey, extension_root_key, parse_extension_index, StoredValueRef, decode_stored_value, RoleCatalog::extend, InfoBaseUser::email.
  • #ИмяТекущейТаблицы теперь подставляется в кавычках, как описывает документация платформы.

open-sdbl 0.5.5

Choose a tag to compare

@dobpilot dobpilot released this 18 Sep 20:46

Релиз после 0.4.0: регистры бухгалтерии, широкие корпуса двух типовых конфигураций и чтение прав доступа прямо из базы. Каждое изменение поведения — со своей спецификацией OpenSpec.

Регистры бухгалтерии

Виртуальные таблицы РегистрБухгалтерии: Остатки, Обороты, ОстаткиИОбороты, ДвиженияССубконто, ОборотыДтКт. Субконто как аргумент и как поля Субконто1…/СубконтоДт/СубконтоКт, корреспонденция (КорСчет, <Измерение>Кор, КорСубконто), развёрнутые остатки (РазвернутыйОстатокДт/Кт, начальные и конечные), периодичности Регистратор и Запись, Порядок/Первые у движений с субконто, метки составных членов Имя_TYPE. Разыменование через многотипную ссылку в выражениях (Регистратор.Организация = &Орг).

Язык запросов

  • ИЗ &Таблица — таблицы-параметры с типизированными колонками, встроенные как CTE SELECT 1, … UNION ALL …; в консоли литерал ТАБЛИЦА(Код КАК СТРОКА, …)((…), …).
  • Безымянное разыменование получает платформенное имя слитно: Д.Организация.Наименование → ОрганизацияНаименование; ключевое слово после КАК — псевдоним (КАК Конец).
  • Псевдоним.* среди других полей и в соединениях; РАЗЛИЧНЫЕ с сортировкой по спроецированной ссылке; вложенное объединение с ПЕРВЫЕ в каждой ветке; ССЫЛКА над ВЫРАЗИТЬ; разнотипный ВЫБОР в сравнении; псевдоним подзапроса затеняет внешний; МАКСИМУМ(Регистратор) остаётся runtime-typed; член объединения узнаётся по запрошенному имени и при обрезке метки до лимита PostgreSQL.
  • АВТОУПОРЯДОЧИВАНИЕ, АВТОНОМЕРЗАПИСИ(), соединения без якорного равенства, ПОЛНОЕ с прежним правилом.

Корпуса

Бухгалтерия предприятия 3.0 — 613 из 622, УНФ — 674 из 688 запросов модулей и схем компоновки, включая широкую выборку по 200 запросов без регистров на каждую базу. Инструменты корпуса привязывают даты и таблицы-заготовки, а виды колонок заготовок берут из метаданных фикстуры (bind_tables.py --kinds, выгрузка dump_field_kinds).

Права доступа (новая capability access-rights)

  • Роли и права читаются из записей Config (<guid> и <guid>.0): права на объекты и их члены, ограничения на уровне записей с полями, шаблоны, флаги. Right называет стандартные права; таблица гвидов выведена из самой базы и подтверждена ролями-одиночками БСП на 8.3.27. Незаписанное право следует умолчанию setForNewObjects.
  • Пользователи ИБ — v8users, колонка Data (XOR + скобочная запись) даёт имя, полное имя и роли; хеши паролей не отдаются.
  • Разворачивание ограничений (open_sdbl::access): шаблоны БСП с #Параметр(N), #Если/#ИначеЕсли/#Иначе/#КонецЕсли по параметрам сеанса, СтрСодержит, Значение(…ПустаяСсылка); результат — полная форма платформы ТекущаяТаблица [КАК Т] ГДЕ …, которую принимает компилятор, в том числе ТекущаяТаблица.Поле во вложенных запросах условия. read_access объединяет роли пользователя.

CLI

\users, \user, \roles, \role, \rls, \as: пользователи, роли, права и ограничения, а ВЫБРАТЬ РАЗРЕШЕННЫЕ от имени пользователя получает ограничения его ролей на «Чтение». Проверено на демо-базе УНФ вплоть до исполнения запроса через ветвь ключей доступа шаблона ДляОбъекта. Нечитаемые ресурсы Config (двоичные .7) пропускаются с предупреждением, а не срывают чтение метаданных.

open-sdbl 0.4.0

Choose a tag to compare

@dobpilot dobpilot released this 16 Sep 14:50

Первый публичный релиз с момента 0.3.6: 62 промежуточные версии, 72 изменения поведения, каждое — со своей спецификацией OpenSpec и сверкой с платформой 1С.

Язык запросов

Корпус реальных запросов демо-конфигурации компилируется на 377 из 381 — остальные четыре отказа платформа разделяет либо они защищают от заведомо неверного ответа.

  • Табличная часть как колонка выборки. Д.Товары, Д.Товары.(Поле, …) и Д.Товары.* возвращаются вложенным результатом: главный оператор плюс по одному вложенному на секцию, со структурной связью по ссылке владельца. Замерено, что платформа отвечает так же — через временную таблицу ключей.
  • ПОЛНОЕ СОЕДИНЕНИЕ → нативный FULL JOIN: снят запрет на цепочку, агрегаты и группировку, разыменование в ПО выносится внутрь своей стороны.
  • Элемент списка через запятую присоединяется целиком — прежний плоский рендер давал неверный ответ для внешних соединений внутри элемента.
  • Разыменование любой глубины, в том числе через составные ссылки; цели берутся из описания типа в Config, категории ссылок — из платформенных констант.
  • ИТОГИ … ПО (включая ОБЩИЕ, ИЕРАРХИЯ, ТОЛЬКО ИЕРАРХИЯ), виртуальные таблицы регистров (срезы, остатки, обороты, ОстаткиИОбороты с периодичностью), журналы документов, критерии отбора, Константы и Константа.<Имя>.
  • Условие по колонке табличной части компилируется в коррелированный EXISTS; В ИЕРАРХИИ принимает составную ссылку; ПРЕДСТАВЛЕНИЕ берётся от агрегата и от ВЫБОР с разнотипными ветвями.
  • Функции дат и строк, ТИП/ТИПЗНАЧЕНИЯ/НЕОПРЕДЕЛЕНО, ССЫЛКА, МЕЖДУ, ВЫРАЗИТЬ, параметры запроса и сеанса, разделители данных, ограничения доступа РАЗРЕШЕННЫЕ, временные таблицы.

Публичный API

CompiledQuery помечен #[non_exhaustive] и получил nested — вложенные результаты табличных частей со связью, описанной данными, а не текстом SQL, — и service_columns. Добавлен тип NestedResult. Генерируемый PostgreSQL рассчитан на версию 13 и новее.

CLI

Сессия MSSQL больше не опрашивает сервер перед чтением: права учётной записи и уровень изоляции — решение администратора, а компилятор порождает только SELECT. Read-only application intent, транзакция вокруг чтения и её откат сохранены.

Приложение разобрано по модулям: точка входа, контроллер команд, фасад сессии, консоль из восьми модулей и по три модуля на провайдера. Тесты вынесены в отдельный каталог.

Проверки

Три независимые сети: голдены компиляции, 256 проб против живой платформы 8.3.27 (расхождений нет) и исполнение всего корпуса на настоящей базе PostgreSQL. CI собирает релиз, выкладывает архив исходников и исполняемый файл для Windows MSVC.