Дорогие подписчики!
✅ Продолжаем рассказывать о встроенных пакетах Digital Q.DataBase, обеспечивающих совместимость с PL/SQL-окружением Oracle. Сегодня разберём ещё два пакета из тех, что попали в последний выпуск (версия от 21 марта), — DBMS_ERRLOG и DBMS_HASH.
DBMS_ERRLOG — логирование ошибок DML-операций
➡️ Пакет DBMS_ERRLOG позволяет сохранять информацию об ошибках, возникающих при выполнении массовых DML-операций (INSERT, UPDATE, MERGE, DELETE), без прерывания всего процесса. Это особенно полезно при загрузке больших объёмов данных, когда отдельные некорректные записи не должны останавливать обработку всего набора.
Основные возможности:
· Создание таблицы логирования ошибок для указанной таблицы;
· Продолжение выполнения DML-операции при возникновении ошибок в отдельных строках;
· Фиксация кода ошибки, номера строки и значений ошибочных колонок;
· Настройка перечня колонок, подлежащих логированию.
Пример использования:
Области применения:
· Загрузка данных из внешних источников с «грязными» данными;
· Массовые обновления в условиях, когда часть строк не проходит валидацию;
· Аудит и анализ причин отбраковки данных при ETL-процессах;
· Обеспечение отказоустойчивости пакетной обработки.
DBMS_HASH — хэширование данных
➡️ Пакет DBMS_HASH предоставляет функции для вычисления хэш-значений данных различных типов. Это позволяет создавать контрольные суммы, сравнивать большие объёмы данных, реализовывать механизмы кэширования и проверки целостности.
Основные возможности:
· Вычисление хэша для значений типов VARCHAR2, NUMBER, DATE, RAW, CLOB, BLOB;
· Поддержка алгоритмов MD5 и SHA-1 (совместимость с Oracle);
· Получение хэша от конкатенации нескольких значений;
· Использование в выражениях SQL и PL/SQL.
Пример использования:
Области применения:
· Сравнение содержимого двух таблиц без построчного обхода;
· Проверка целостности данных при репликации;
· Создание ключей кэширования на основе сложных составных данных;
· Обнаружение дубликатов при отсутствии однозначного первичного ключа;
· Контроль неизменности конфигурационных данных.
✅ Хочу ещё раз напомнить: именно наличие большого количества аналогов DBMS-пакетов Oracle, позволяющих не изменять хранимую бизнес-логику при уходе с Oracle, делает Digital Q.DataBase наиболее рациональным вариантом для замены этой зарубежной СУБД.
DBMS_ERRLOG — логирование ошибок DML-операций
Основные возможности:
· Создание таблицы логирования ошибок для указанной таблицы;
· Продолжение выполнения DML-операции при возникновении ошибок в отдельных строках;
· Фиксация кода ошибки, номера строки и значений ошибочных колонок;
· Настройка перечня колонок, подлежащих логированию.
Пример использования:
-- Создание таблицы логирования ошибок для таблицы employees
EXEC DBMS_ERRLOG.CREATE_ERROR_LOG('employees', 'err_employees');
-- Выполнение массовой вставки с логированием ошибок
INSERT INTO employees (id, name, salary)
SELECT emp_id, emp_name, emp_salary FROM source_data
LOG ERRORS INTO err_employees REJECT LIMIT UNLIMITED;
Области применения:
· Загрузка данных из внешних источников с «грязными» данными;
· Массовые обновления в условиях, когда часть строк не проходит валидацию;
· Аудит и анализ причин отбраковки данных при ETL-процессах;
· Обеспечение отказоустойчивости пакетной обработки.
DBMS_HASH — хэширование данных
Основные возможности:
· Вычисление хэша для значений типов VARCHAR2, NUMBER, DATE, RAW, CLOB, BLOB;
· Поддержка алгоритмов MD5 и SHA-1 (совместимость с Oracle);
· Получение хэша от конкатенации нескольких значений;
· Использование в выражениях SQL и PL/SQL.
Пример использования:
-- Вычисление хэша для строкового значения
DECLARE
v_hash RAW(16);
BEGIN
v_hash := DBMS_HASH.MD5('Hello, Digital Q.DataBase');
DBMS_OUTPUT.PUT_LINE(RAWTOHEX(v_hash));
END;
-- Использование в SQL-запросе для сравнения таблиц
SELECT DBMS_HASH.MD5(column1 || column2 || column3) AS row_hash
FROM my_table;Области применения:
· Сравнение содержимого двух таблиц без построчного обхода;
· Проверка целостности данных при репликации;
· Создание ключей кэширования на основе сложных составных данных;
· Обнаружение дубликатов при отсутствии однозначного первичного ключа;
· Контроль неизменности конфигурационных данных.
Please open Telegram to view this post
VIEW IN TELEGRAM
Дорогие подписчики!
➡️ Продолжаем рассказывать о доработках, вошедших в последний выпуск Digital Q.DataBase (версия от 21 марта). Сегодня — о рабочей поддержке команды UPDATE STATISTICS.
Для чего нужна эта команда
➡️ Статистика — это метаданные, которые описывают распределение данных в таблицах и индексах. Оптимизатор запросов использует их для выбора наиболее эффективного плана выполнения. Если статистика устаревает, например после массовой вставки, обновления или удаления данных, оптимизатор может принять неверное решение, что приведёт к падению производительности.
Команда UPDATE STATISTICS обновляет эту информацию, позволяя оптимизатору строить актуальные планы запросов.
Что именно добавлено
➡️ В Digital Q.DataBase теперь поддерживаются следующие варианты синтаксиса UPDATE STATISTICS, совместимые с MS SQL Server:
Основные возможности:
· Обновление статистики на уровне таблицы, отдельного индекса или статистического объекта;
· Выбор режима сбора данных: полное сканирование или указание процента выборки;
· Совместимость с существующими скриптами и хранимыми процедурами, переходящими с MS SQL Server.
Пример использования в миграционных сценариях
➡️ При переходе с MS SQL Server на Digital Q.DataBase многие приложения содержат вызовы UPDATE STATISTICS и sp_updatestats в регламентных заданиях. Ранее такие вызовы приходилось удалять или заменять. Теперь основные прикладные сценарии работают без изменений:
➡️ В текущей реализации поддерживаются основные варианты синтаксиса и вызовы системной процедуры, необходимые для подавляющего большинства прикладных сценариев обслуживания и миграции.
➡️ Хочу ещё раз напомнить: именно такие, на первый взгляд небольшие, доработки делают переход с зарубежных СУБД на Digital Q.DataBase максимально плавным. Хранимые процедуры, регламентные задания и скрипты обслуживания продолжают работать так же, как и раньше, — без переписывания.
Для чего нужна эта команда
Команда UPDATE STATISTICS обновляет эту информацию, позволяя оптимизатору строить актуальные планы запросов.
Что именно добавлено
-- Обновление статистики по указанной таблице
UPDATE STATISTICS employees;
-- Обновление статистики по конкретному индексу или статистическому объекту
UPDATE STATISTICS employees (ix_employees_name);
-- Обновление статистики с полным сканированием таблицы
UPDATE STATISTICS employees WITH FULLSCAN;
-- Обновление статистики с указанием процента выборки
UPDATE STATISTICS employees WITH SAMPLE 10 PERCENT;
Основные возможности:
· Обновление статистики на уровне таблицы, отдельного индекса или статистического объекта;
· Выбор режима сбора данных: полное сканирование или указание процента выборки;
· Совместимость с существующими скриптами и хранимыми процедурами, переходящими с MS SQL Server.
Пример использования в миграционных сценариях
-- Типовой скрипт обслуживания из MS SQL Server
EXEC sp_updatestats; -- Вызов хранимой процедуры обновления статистики по всей БД
-- Или прямая команда
UPDATE STATISTICS sales.orders WITH FULLSCAN;
Please open Telegram to view this post
VIEW IN TELEGRAM
«Мучения клиента выгодны бизнесу».
Я показал, что это возможно, если СУБД изначально спроектирована с учетом реальных сценариев миграции, а не просто повторяет PostgreSQL с частичными доработками.
Отдельно разобрали, почему классические подходы через «форки ради форков» создают для заказчика:
почему другие отечественные компании не достигли такого же результата?
либо у них нет технологий и ресурсов,
либо они не стремятся облегчать переход заказчику,
так как «мучение клиента» выгодно для бизнеса.
Обсуждение получилось живым, а сам тезис разошёлся далеко за пределы мероприятия.
Порой правда звучит немного неудобно - зато её хорошо запоминают.
Статья на Tadviser
Please open Telegram to view this post
VIEW IN TELEGRAM
Дорогие подписчики!
➡️ Продолжаем рассказывать о встроенных пакетах Digital Q.DataBase, обеспечивающих совместимость с PL/SQL-окружением Oracle. Сегодня разберём ещё два пакета — DBMS_XMLDOM и DBMS_XMLGEN.
DBMS_XMLDOM — работа с XML-документами через DOM-модель
➡️ Пакет DBMS_XMLDOM предоставляет интерфейс для работы с XML-документами на основе объектной модели DOM (Document Object Model). Он позволяет создавать, модифицировать и анализировать XML-структуры непосредственно в хранимых процедурах.
Основные возможности:
· Создание XML-документов с нуля с использованием DOM-узлов;
· Парсинг существующих XML-документов в DOM-структуру;
· Навигация по дереву документа с доступом к любому узлу;
· Модификация содержимого, атрибутов и структуры документа;
· Преобразование DOM-документа обратно в текстовое представление XML.
Пример использования:
Области применения:
· Формирование сложных XML-отчётов внутри базы данных;
· Генерация XML-файлов для обмена с внешними системами;
· Разбор входящих XML-сообщений без привлечения внешних парсеров;
· Преобразование реляционных данных в иерархические XML-структуры.
DBMS_XMLGEN — преобразование SQL-результатов в XML
➡️ Пакет DBMS_XMLGEN позволяет преобразовывать результаты SQL-запросов в XML-формат. В отличие от DBMS_XMLDOM, этот пакет ориентирован на автоматическую генерацию XML из реляционных данных с минимальным участием разработчика.
Основные возможности:
· Преобразование результатов SELECT в XML любого уровня вложенности;
· Настройка форматирования: имя корневого элемента, кодировка, отступы;
· Поддержка как прямой генерации в память, так и потокового вывода;
· Возможность задавать правила отображения столбцов в XML-элементы.
Пример использования:
Области применения:
· Экспорт табличных данных в XML для интеграции с внешними системами;
· Создание XML-представлений для веб-сервисов;
· Формирование XML-отчётов по шаблону «запрос — XML»;
· Быстрое прототипирование XML-интерфейсов без написания сложного парсинга.
DBMS_XMLDOM — работа с XML-документами через DOM-модель
Основные возможности:
· Создание XML-документов с нуля с использованием DOM-узлов;
· Парсинг существующих XML-документов в DOM-структуру;
· Навигация по дереву документа с доступом к любому узлу;
· Модификация содержимого, атрибутов и структуры документа;
· Преобразование DOM-документа обратно в текстовое представление XML.
Пример использования:
DECLARE
v_doc DBMS_XMLDOM.DOMDocument;
v_root DBMS_XMLDOM.DOMNode;
v_elem DBMS_XMLDOM.DOMNode;
BEGIN
-- Создание нового документа
v_doc := DBMS_XMLDOM.newDOMDocument;
v_root := DBMS_XMLDOM.makeNode(v_doc);
-- Создание корневого элемента
v_elem := DBMS_XMLDOM.createElement(v_doc, 'employees');
v_root := DBMS_XMLDOM.appendChild(v_root, v_elem);
-- Вывод документа
DBMS_OUTPUT.PUT_LINE(DBMS_XMLDOM.getXMLType(v_doc).getClobVal);
END;
Области применения:
· Формирование сложных XML-отчётов внутри базы данных;
· Генерация XML-файлов для обмена с внешними системами;
· Разбор входящих XML-сообщений без привлечения внешних парсеров;
· Преобразование реляционных данных в иерархические XML-структуры.
DBMS_XMLGEN — преобразование SQL-результатов в XML
Основные возможности:
· Преобразование результатов SELECT в XML любого уровня вложенности;
· Настройка форматирования: имя корневого элемента, кодировка, отступы;
· Поддержка как прямой генерации в память, так и потокового вывода;
· Возможность задавать правила отображения столбцов в XML-элементы.
Пример использования:
-- Простейшая генерация XML из результата запроса
DECLARE
v_ctx DBMS_XMLGEN.ctxHandle;
v_xml XMLType;
BEGIN
v_ctx := DBMS_XMLGEN.newContext('SELECT id, name, salary FROM employees');
v_xml := DBMS_XMLGEN.getXML(v_ctx);
DBMS_OUTPUT.PUT_LINE(v_xml.getClobVal);
DBMS_XMLGEN.closeContext(v_ctx);
END;
-- Генерация XML с настройкой формата
DECLARE
v_ctx DBMS_XMLGEN.ctxHandle;
v_xml CLOB;
BEGIN
v_ctx := DBMS_XMLGEN.newContext('SELECT id, name FROM employees');
DBMS_XMLGEN.setRowSetTag(v_ctx, 'employees_list');
DBMS_XMLGEN.setRowTag(v_ctx, 'employee');
v_xml := DBMS_XMLGEN.getXML(v_ctx);
DBMS_OUTPUT.PUT_LINE(v_xml);
DBMS_XMLGEN.closeContext(v_ctx);
END;
Области применения:
· Экспорт табличных данных в XML для интеграции с внешними системами;
· Создание XML-представлений для веб-сервисов;
· Формирование XML-отчётов по шаблону «запрос — XML»;
· Быстрое прототипирование XML-интерфейсов без написания сложного парсинга.
Please open Telegram to view this post
VIEW IN TELEGRAM
Дорогие подписчики!
✅ Продолжаем рассказывать о встроенных пакетах Digital Q.DataBase, обеспечивающих совместимость с PL/SQL-окружением Oracle.
Сегодня разберём DBMS_CRYPTO и DBMS_REPORT.
DBMS_CRYPTO — криптографические функции
➡️ Пакет DBMS_CRYPTO предоставляет инструменты для хэширования данных.
В текущей реализации поддержана функция HASH, позволяющая вычислять контрольные суммы и хэш-значения для строк, чисел и бинарных данных.
Основные возможности:
· Вычисление хэша алгоритмами MD5, SHA-1, SHA-256;
· Поддержка входных данных типов VARCHAR2, CLOB, RAW, BLOB;
· Совместимость с синтаксисом Oracle DBMS_CRYPTO.HASH;
· Возврат результата в формате RAW.
Пример использования:
Области применения:
· Проверка целостности данных при передаче между системами;
· Создание контрольных сумм для выгрузок и архивов;
· Хэширование паролей и чувствительной информации;
· Обнаружение дубликатов через хэш-индексы.
DBMS_REPORT — формирование отчётов и преобразования
➡️ Пакет DBMS_REPORT предоставляет вспомогательные функции для работы с отчётами и преобразованиями данных. В текущей версии реализованы функции JSON_TO_TEXT и ZLIB2BASE64_CLOB.
JSON_TO_TEXT — преобразование JSON в читаемый текст
➡️ Функция JSON_TO_TEXT преобразует JSON-документ в форматированное текстовое представление, удобное для включения в отчёты и логи.
ZLIB2BASE64_CLOB — распаковка и декодирование
➡️ Функция ZLIB2BASE64_CLOB принимает строку в формате BASE64, сжатую алгоритмом ZLIB, и возвращает распакованный результат в виде CLOB. Полезна для обработки данных, передаваемых в сжатом виде через API и веб-сервисы.
Области применения DBMS_REPORT:
· Формирование удобочитаемых логов из JSON-сообщений;
· Подготовка данных для включения в текстовые отчёты;
· Распаковка сжатых ответов от внешних API;
· Обработка данных, передаваемых в BASE64 через веб-сервисы.
Сегодня разберём DBMS_CRYPTO и DBMS_REPORT.
DBMS_CRYPTO — криптографические функции
В текущей реализации поддержана функция HASH, позволяющая вычислять контрольные суммы и хэш-значения для строк, чисел и бинарных данных.
Основные возможности:
· Вычисление хэша алгоритмами MD5, SHA-1, SHA-256;
· Поддержка входных данных типов VARCHAR2, CLOB, RAW, BLOB;
· Совместимость с синтаксисом Oracle DBMS_CRYPTO.HASH;
· Возврат результата в формате RAW.
Пример использования:
-- Вычисление MD5-хэша для строки
DECLARE
v_hash RAW(16);
BEGIN
v_hash := DBMS_CRYPTO.HASH(
UTL_I18N.STRING_TO_RAW('Hello, Digital Q.DataBase', 'AL32UTF8'),
DBMS_CRYPTO.HASH_MD5
);
DBMS_OUTPUT.PUT_LINE(RAWTOHEX(v_hash));
END;
-- Вычисление SHA-256 для проверки целостности данных
SELECT DBMS_CRYPTO.HASH(
UTL_I18N.STRING_TO_RAW(data_column, 'AL32UTF8'),
DBMS_CRYPTO.HASH_SH256
) AS data_hash
FROM my_table;
Области применения:
· Проверка целостности данных при передаче между системами;
· Создание контрольных сумм для выгрузок и архивов;
· Хэширование паролей и чувствительной информации;
· Обнаружение дубликатов через хэш-индексы.
DBMS_REPORT — формирование отчётов и преобразования
JSON_TO_TEXT — преобразование JSON в читаемый текст
-- Преобразование JSON в текстовый вид
DECLARE
v_json CLOB := '{"employees":[{"id":1,"name":"Иванов"},{"id":2,"name":"Петров"}]}';
v_text CLOB;
BEGIN
v_text := DBMS_REPORT.JSON_TO_TEXT(v_json);
DBMS_OUTPUT.PUT_LINE(v_text);
END;
ZLIB2BASE64_CLOB — распаковка и декодирование
-- Декодирование и распаковка сжатых данных
DECLARE
v_compressed_base64 VARCHAR2(32767); -- сжатые и закодированные данные
v_decompressed CLOB;
BEGIN
v_decompressed := DBMS_REPORT.ZLIB2BASE64_CLOB(v_compressed_base64);
DBMS_OUTPUT.PUT_LINE(v_decompressed);
END;
Области применения DBMS_REPORT:
· Формирование удобочитаемых логов из JSON-сообщений;
· Подготовка данных для включения в текстовые отчёты;
· Распаковка сжатых ответов от внешних API;
· Обработка данных, передаваемых в BASE64 через веб-сервисы.
Please open Telegram to view this post
VIEW IN TELEGRAM
Военные тогда сказали: «Пусть пока работает так, а через полгода мы купим нормальную СУБД». Прошло почти 26 лет, но написанная Хиппом программа до сих пор работает как часы.
Ричард Хипп потом шутил в одном из интервью: «Лучший способ сделать софт вечным — назвать его "временным фиксом". Тогда его никто не тронет».
SQLite настолько мала по размеру и надёжна, что её код встроен в:
· бортовые системы самолетов Airbus и Boeing,
· марсоход NASA Perseverance,
· мультимедиа и телеметрию автомобилей Tesla и большинства китайских автомобилей.
Ричард Хипп не заработал на SQLite миллиарды, но зато получил всемирное признание. На вопрос «А Вам не надоело?» он ответил: «Мне нравится создавать инструмент, который делает людей чуточку счастливее».
Пусть и в Ваших проектах будет такой фундамент. Даже если над ним работает всего один человек. 🌱
Please open Telegram to view this post
VIEW IN TELEGRAM
Дорогие подписчики!
Сегодня , 12 апреля — удивительный день, когда космос и светлая Пасха встретились в одной дате.
С днём космонавтики!
65 лет назад Юрий Гагарин сказал «Поехали!» — и человечество навсегда изменило своё представление о возможном. С тех пор 12 апреля — день, когда мы вспоминаем, что границы существуют только для того, чтобы их раздвигать.
С Пасхой!
В этом году православная Пасха также приходится на 12 апреля. Праздник обновления, надежды и победы жизни.
Две разные высоты. Одна — физическая, за пределами земной атмосферы. Другая — духовная. Но обе напоминают: всегда есть куда расти и во что верить.
С праздниками! Светлой Пасхи и удачного космического полёта по жизни.
Сегодня , 12 апреля — удивительный день, когда космос и светлая Пасха встретились в одной дате.
С днём космонавтики!
65 лет назад Юрий Гагарин сказал «Поехали!» — и человечество навсегда изменило своё представление о возможном. С тех пор 12 апреля — день, когда мы вспоминаем, что границы существуют только для того, чтобы их раздвигать.
С Пасхой!
В этом году православная Пасха также приходится на 12 апреля. Праздник обновления, надежды и победы жизни.
Две разные высоты. Одна — физическая, за пределами земной атмосферы. Другая — духовная. Но обе напоминают: всегда есть куда расти и во что верить.
С праздниками! Светлой Пасхи и удачного космического полёта по жизни.
В этом видео:
Видео пока выходит без звука.
Версия с комментариями будет опубликована отдельно.
Please open Telegram to view this post
VIEW IN TELEGRAM
Дорогие подписчики!
🟣 Продолжаем рассказывать о доработках, вошедших в последний выпуск Digital Q.DataBase. Сегодня — о поддержке методов работы с XML в нашей реализации T-SQL-диалекта. Начнём с метода value().
value() — извлечение скалярных значений из XML
🟣 Метод value() позволяет получить единственное значение из XML-документа по указанному XPath-выражению. Это один из наиболее востребованных методов при работе с XML-данными в MS SQL Server.
Пример использования:
Основные возможности:
· Извлечение скалярных значений по XPath-выражению;
· Поддержка типов VARCHAR, INT, DECIMAL, DATE, DATETIME;
· Работа с элементами и атрибутами;
· Возврат NULL при отсутствии узла.
🟣 Метод value() доступен в Digital Q.DataBese, начиная с версии от 21 марта.
value() — извлечение скалярных значений из XML
Пример использования:
-- Извлечение значения из XML-столбца
SELECT
id,
xml_data.value('(/employee/name)[1]', 'varchar(100)') AS employee_name
FROM employees_xml;
-- Использование в условиях WHERE
SELECT *
FROM orders_xml
WHERE orders_xml.value('(/order/amount)[1]', 'decimal(10,2)') > 10000;
Основные возможности:
· Извлечение скалярных значений по XPath-выражению;
· Поддержка типов VARCHAR, INT, DECIMAL, DATE, DATETIME;
· Работа с элементами и атрибутами;
· Возврат NULL при отсутствии узла.
Please open Telegram to view this post
VIEW IN TELEGRAM
Дорогие подписчики!
🟣 Продолжаем рассказывать о поддержке XML-методов в Digital Q.DataBase. Сегодня — о методе query().
query() — извлечение фрагментов XML
🟣 Метод query() позволяет получить из XML-документа один или несколько узлов в виде отдельного XML-фрагмента. В отличие от value(), возвращающего скаляр, query() сохраняет структуру XML.
Пример использования:
Основные возможности:
· Возврат результата в виде XML-фрагмента;
· Поддержка сложных XPath-выражений с условиями;
· Сохранение иерархической структуры узлов;
· Возможность вложения query() в другие выражения.
🟣 Метод query() доступен в Digital Q.DataBase, начиная с версии от 21 марта.
query() — извлечение фрагментов XML
Пример использования:
-- Извлечение поддерева XML
SELECT
id,
xml_data.query('/employee/address') AS address_xml
FROM employees_xml;
-- Получение нескольких узлов
SELECT
xml_data.query('/order/items/item[@quantity > 1]') AS important_items
FROM orders_xml;
Основные возможности:
· Возврат результата в виде XML-фрагмента;
· Поддержка сложных XPath-выражений с условиями;
· Сохранение иерархической структуры узлов;
· Возможность вложения query() в другие выражения.
Please open Telegram to view this post
VIEW IN TELEGRAM
Дорогие подписчики!
🟣 Продолжаем рассказывать о поддержке XML-методов в Digital Q.DataBase. Сегодня — о методе nodes().
nodes() — развертывание XML в реляционные строки
🟣 Метод nodes() позволяет преобразовать XML-документ в набор строк, где каждая строка соответствует одному узлу. Это особенно полезно, когда в XML-документе содержится несколько однотипных элементов (например, список сотрудников или товаров).
Пример использования:
Основные возможности:
· Преобразование XML-документа в реляционное представление;
· Работа с CROSS APPLY и OUTER APPLY;
· Поддержка XPath-выражений для отбора узлов;
· Комбинирование с другими XML-методами.
nodes() — развертывание XML в реляционные строки
Пример использования:
-- Развертывание списка сотрудников в строки
SELECT
id AS parent_id,
node.value('(name)[1]', 'varchar(100)') AS name,
node.value('(salary)[1]', 'int') AS salary
FROM departments_xml
CROSS APPLY xml_data.nodes('/department/employees/employee') AS ref(node);
-- Развертывание с фильтрацией
SELECT
node.value('(@id)[1]', 'int') AS product_id,
node.value('(price)[1]', 'decimal(10,2)') AS price
FROM products_xml
CROSS APPLY xml_data.nodes('/catalog/product[price > 1000]') AS ref(node);
Основные возможности:
· Преобразование XML-документа в реляционное представление;
· Работа с CROSS APPLY и OUTER APPLY;
· Поддержка XPath-выражений для отбора узлов;
· Комбинирование с другими XML-методами.
Please open Telegram to view this post
VIEW IN TELEGRAM
2 3 2 2
📅 21 апреля 2026 — встреча для тех, кто принимает решения в области данных и инфраструктуры.
Если вы работаете с высоконагруженными системами, думаете об импортозамещении или ищете устойчивые архитектурные решения — это мероприятие точно стоит вашего времени.
На конференции разберём:
До встречи!
Please open Telegram to view this post
VIEW IN TELEGRAM
1 7 5 5
Сегодня в "посте выходного дня" мы поговорим о том, как слон по имени Слоник (Slonik) стал логотипом PostgreSQL
Большинство современных систем на базе PostgreSQL используют изображение слона как часть своего логотипа. Тем самым они подчеркивают свою связь с проектом PostgreSQL, логотипом которого в настоящее время является голова слона.
Некоторые даже знают, что у этого логотипа есть собственное имя - Slonik, что происходит от русского слова "слоник", то есть маленький слон.
Почему именно слон был выбран в качестве логотипа? Считается, что это отсылка к детективу Агаты Кристи «Слоны умеют помнить». Символизм заключается в том, что хорошая база данных (как и слон) не забывает информацию и хранит её вечно.
Но всегда ли слон был логотипом PostgreSQL? Оказывается нет.
Самым первым логотипом PostgreSQL (использованный вскоре после переименования проекта) была надпись PostgreSQL, которая пробивается к зрителю из космоса сквозь разлетающуюся на куски кирпичную стену. Одновременно с ним использовалось изображение гепарда, разместившегося на первых буквах названия, в сочетании с надписью "Empowered".
Новый логотип придумывали и обсуждали довольно долго. В качестве идей для логотипа рассматривались аллигатор, гепард, лев или львица, тигрица, газель, орел, слон и даже собака. Были и совсем странные варианты, например, рыцарский меч, миска супа (с плавающими в ней буквами PostgreSQL), каменный мост и даже револьвер наёмного убийцы. Однако идея со слоном оказалась самой удачной.
Изображение "слона в алмазе", помещенное в файл slonik.gif, в сообщество PostgreSQL прислал Дмитрий Самерсов из Санкт-Петербурга. По его словам реальным автором этой картинки была его подруга.
Позже швед Daniel Lundin убрал алмаз и именно в таком виде изображение и стало новым официальным логотипом проекта.
Однако не во всех странах именно оно олицетворяет проект PostgreSQL. Так, например, в Японии принято использовать изображение черепахи.
Почему черепаха стала логотипом японского сообщества пользователей PostgreSQL?
Дело в том, что еще в 1970-х годах черепаха использовалась в качестве талисмана INGRES. Ее выбрали потому что "она медленная, но всегда добирается, куда нужно". И она была сохранена как талисман POSTGRES по сентиментальным причинам. Сделав её логотипом своего сообщества, японские пользователи подчеркнули связь PostgreSQL с этим проектами.
Наверное, японцы что-то знают? 🤣
Большинство современных систем на базе PostgreSQL используют изображение слона как часть своего логотипа. Тем самым они подчеркивают свою связь с проектом PostgreSQL, логотипом которого в настоящее время является голова слона.
Некоторые даже знают, что у этого логотипа есть собственное имя - Slonik, что происходит от русского слова "слоник", то есть маленький слон.
Почему именно слон был выбран в качестве логотипа? Считается, что это отсылка к детективу Агаты Кристи «Слоны умеют помнить». Символизм заключается в том, что хорошая база данных (как и слон) не забывает информацию и хранит её вечно.
Но всегда ли слон был логотипом PostgreSQL? Оказывается нет.
Самым первым логотипом PostgreSQL (использованный вскоре после переименования проекта) была надпись PostgreSQL, которая пробивается к зрителю из космоса сквозь разлетающуюся на куски кирпичную стену. Одновременно с ним использовалось изображение гепарда, разместившегося на первых буквах названия, в сочетании с надписью "Empowered".
Новый логотип придумывали и обсуждали довольно долго. В качестве идей для логотипа рассматривались аллигатор, гепард, лев или львица, тигрица, газель, орел, слон и даже собака. Были и совсем странные варианты, например, рыцарский меч, миска супа (с плавающими в ней буквами PostgreSQL), каменный мост и даже револьвер наёмного убийцы. Однако идея со слоном оказалась самой удачной.
Изображение "слона в алмазе", помещенное в файл slonik.gif, в сообщество PostgreSQL прислал Дмитрий Самерсов из Санкт-Петербурга. По его словам реальным автором этой картинки была его подруга.
Позже швед Daniel Lundin убрал алмаз и именно в таком виде изображение и стало новым официальным логотипом проекта.
Однако не во всех странах именно оно олицетворяет проект PostgreSQL. Так, например, в Японии принято использовать изображение черепахи.
Почему черепаха стала логотипом японского сообщества пользователей PostgreSQL?
Дело в том, что еще в 1970-х годах черепаха использовалась в качестве талисмана INGRES. Ее выбрали потому что "она медленная, но всегда добирается, куда нужно". И она была сохранена как талисман POSTGRES по сентиментальным причинам. Сделав её логотипом своего сообщества, японские пользователи подчеркнули связь PostgreSQL с этим проектами.
Наверное, японцы что-то знают? 🤣
1 7 5 4
Друзья, сегодня в рубрике «Пост выходного дня» — история одного из самых известных (и хорошо задокументированных) "маркетинговых ходов" в истории СУБД.
⛔️ Версия, которой не было
В 1979 году вышла Oracle V2.
Версии 1 не существовало в принципе.
Логика была простая: никто не захочет покупать «сырую первую версию». Поэтому продукт сразу назвали «второй версией» — чтобы он выглядел более зрелым и проверенным.
Вот только зрелости в нём не было. Один из первых сотрудников компании Oracle - Стюарт Фейгин позже вспоминал:
«Наша версия два была как минимум такой же глючной, как у кого-либо версия один».
Сами разработчики называли её «мотелем для тараканов».
❗️ Чем это обернулось к 1990 году
Такая "лихая" тактика продаж едва не уничтожила компанию. Её продукты не соответствовали обещаниям маркетинга. А выход особенно сырой шестой версии окончательно добил доверие клиентов.
Спасла ситуацию только седьмая версия Oracle, увидевшая свет в 1992 году — благодаря своему высокому качеству она действительно стала прорывом и уже в первый год после выпуска заняла 50% рынка баз данных для UNIX-систем.
В 1979 году вышла Oracle V2.
Версии 1 не существовало в принципе.
Логика была простая: никто не захочет покупать «сырую первую версию». Поэтому продукт сразу назвали «второй версией» — чтобы он выглядел более зрелым и проверенным.
Вот только зрелости в нём не было. Один из первых сотрудников компании Oracle - Стюарт Фейгин позже вспоминал:
«Наша версия два была как минимум такой же глючной, как у кого-либо версия один».
Сами разработчики называли её «мотелем для тараканов».
Такая "лихая" тактика продаж едва не уничтожила компанию. Её продукты не соответствовали обещаниям маркетинга. А выход особенно сырой шестой версии окончательно добил доверие клиентов.
Спасла ситуацию только седьмая версия Oracle, увидевшая свет в 1992 году — благодаря своему высокому качеству она действительно стала прорывом и уже в первый год после выпуска заняла 50% рынка баз данных для UNIX-систем.
Please open Telegram to view this post
VIEW IN TELEGRAM
1 5 4 3
Digital Q.DataBase 🎙
Photo
Дорогие подписчики!
Информирую Вас о том, что на сайте database.diasoft.ru появилась возможность скачать дистрибутивы для установки нашего аналога SQL Server Reporting Services (SSRS).
Перейдите в раздел "скачать бесплатно" и в выпадающем списке выберите "Службы отчётов Digital Q.DataBase".
Электронный адрес службы поддержки: supportqdb@diasoft.ru
Информирую Вас о том, что на сайте database.diasoft.ru появилась возможность скачать дистрибутивы для установки нашего аналога SQL Server Reporting Services (SSRS).
Перейдите в раздел "скачать бесплатно" и в выпадающем списке выберите "Службы отчётов Digital Q.DataBase".
Электронный адрес службы поддержки: supportqdb@diasoft.ru
1 5 4 3
This media is not supported in your browser
VIEW IN TELEGRAM
1 9 3 2
Forwarded from Diasoft о технологиях по-настоящему
This media is not supported in your browser
VIEW IN TELEGRAM
1 5 4 3
Forwarded from Diasoft о технологиях по-настоящему
⚡️День СУБД ➡️ Анонс RuDB
Диасофт (производитель российской СУБД Digital Q.DataBase) и НППКТ (производитель СУБД Лира-Р и ОС Основа) совместно учредили Ассоциацию разработчиков СУБД. В рамках ассоциации была выпущена первая версия российской национальной СУБД RuDB с открытым исходным кодом.
Факты об отечественной СУБД нового поколения:
🟣 она основана на PostgreSQL 18.2 и совместима с ним;
🟣 содержит необходимые доработки по информационной безопасности и выполнению требований ФСТЭК;
🟣 совместима с основными российскими бизнес-приложениями.
⚡️Предлагаем скачать бесплатный дистрибутив уже сейчас и призываем других разработчиков СУБД присоединиться к Ассоциации разработчиков RuDB!
Диасофт (производитель российской СУБД Digital Q.DataBase) и НППКТ (производитель СУБД Лира-Р и ОС Основа) совместно учредили Ассоциацию разработчиков СУБД. В рамках ассоциации была выпущена первая версия российской национальной СУБД RuDB с открытым исходным кодом.
Факты об отечественной СУБД нового поколения:
⚡️Предлагаем скачать бесплатный дистрибутив уже сейчас и призываем других разработчиков СУБД присоединиться к Ассоциации разработчиков RuDB!
Please open Telegram to view this post
VIEW IN TELEGRAM
1 8 5 4
Развенчиваем миф о пределе в 20ТБ при работе на PostgreSQL
Сегодня на совещании в одном из российских банков вновь услышали миф, что PostgreSQL «тормозит» на базах больше 20 ТБ.
Мол, "любой разумный человек должен понимать", что СУБД на базе PostgreSQL "не вывезет больше". Разумеется, это не более чем домыслы, которые легко опровергаются официальной документацией и реальными кейсами, как в РФ, так и за рубежом.
➡️ Официальные пределы:
Максимальный размер базы данных в PostgreSQL официально не ограничен. Есть только лимит на объём одной таблицы — 32 ТБ (и то его можно обойти, используя партиционирование). Сама СУБД спокойно оперирует сотнями терабайт и даже петабайтами.
➡️ Примеры из практики: от 150 ТБ до петабайт
🟣 ГИС ГМП (Россия) — Федеральное казначейство успешно перенесло с Oracle на PostgreSQL около 200 ТБ данных.
🟣 Сервис облачного мониторинга TigerData на базе PostgreSQL (TimescaleDB) хранит 350 ТБ данных и обрабатывает 1,5 триллиона метрик в день.
🟣 Yahoo! — построила на PostgreSQL репозиторий данных объёмом более 2 петабайт.
🟣 Так откуда же миф про 20 ТБ и почему он так живуч?
Вероятнее всего, есть путаница с лимитом PostgreSQL на одну таблицу. Путают размер базы (который ограничен лишь доступными ресурсами для хранения) и максимальный объём на таблицу, точнее один её сегмент (32 ТБ). И мол «надо же оставить запас на рост» — поэтому пусть будет 20 ТБ, а не 32.
А возможно, причина в том, что обслуживать базу в 150+ ТБ традиционными методами действительно непросто. Например, никакого разумного времени не хватит, чтобы создать или восстановить бэкап такой базы стандартным образом. Но это не проблема PostgreSQL — это особенность больших данных. В таких случаях используют специальные решения: реплики в режиме горячего резерва, stage-in, инкрементальные бэкапы и WAL-архивацию.
Итого: PostgreSQL и ряд основанных на этом проекте других СУБД, без проблем держат сотни терабайт и даже петабайты. Вопрос лишь в грамотной архитектуре и правильных подходах к эксплуатации.
Сегодня на совещании в одном из российских банков вновь услышали миф, что PostgreSQL «тормозит» на базах больше 20 ТБ.
Мол, "любой разумный человек должен понимать", что СУБД на базе PostgreSQL "не вывезет больше". Разумеется, это не более чем домыслы, которые легко опровергаются официальной документацией и реальными кейсами, как в РФ, так и за рубежом.
Максимальный размер базы данных в PostgreSQL официально не ограничен. Есть только лимит на объём одной таблицы — 32 ТБ (и то его можно обойти, используя партиционирование). Сама СУБД спокойно оперирует сотнями терабайт и даже петабайтами.
Вероятнее всего, есть путаница с лимитом PostgreSQL на одну таблицу. Путают размер базы (который ограничен лишь доступными ресурсами для хранения) и максимальный объём на таблицу, точнее один её сегмент (32 ТБ). И мол «надо же оставить запас на рост» — поэтому пусть будет 20 ТБ, а не 32.
А возможно, причина в том, что обслуживать базу в 150+ ТБ традиционными методами действительно непросто. Например, никакого разумного времени не хватит, чтобы создать или восстановить бэкап такой базы стандартным образом. Но это не проблема PostgreSQL — это особенность больших данных. В таких случаях используют специальные решения: реплики в режиме горячего резерва, stage-in, инкрементальные бэкапы и WAL-архивацию.
Итого: PostgreSQL и ряд основанных на этом проекте других СУБД, без проблем держат сотни терабайт и даже петабайты. Вопрос лишь в грамотной архитектуре и правильных подходах к эксплуатации.
Please open Telegram to view this post
VIEW IN TELEGRAM
1 5 3 3 1
К хорошему привыкаешь быстро и кажется будто так было всегда.
Но иногда полезно оглянуться назад и вспомнить какой была наша любимая СУБД в прошлом.
Давайте запустим нашу "машину времени" и сделаем несколько остановок в прошлом проекта PostgreSQL, ставшего основой для нашей СУБД Digital Q.DataBase. Поехали!
🕰️ Начало 2025 года:
PostgreSQL 17 работает сильно медленнее привычного. Не удивительно, ведь в нём ещё нет асинхронного I/O (AIO) для параллельного чтения.
Также в нем еще нет:
· виртуальных генерируемых столбцов;
· встроенной uuidv7();
· аутентификации через OAuth 2.0.
🕰️ 2023 год:
В PostgreSQL 15 еще нет пакетной вставки для FDW через COPY.
🕰️ 2022 год.
В PostgreSQL 14 еще нет:
· команды MERGE (условное обновление/вставка);
· сжатия TOAST через LZ4.
🕰️ 2019 год.
PostgreSQL 11 ещё не знает что такое:
· генерируемые столбцы;
· JSON PATH для jsonb;
· хранимые процедуры с транзакциями (только функции);
· JIT-компиляция запросов.
🕰️ 2018 год.
В PostgreSQL 10 еще нет хранимых процедур (CREATE PROCEDURE).
Есть только функции (CREATE FUNCTION). Управлять транзакциями изнутри логики нельзя.
🕰️ 2017 год.
В PostgreSQL 9.6 еще нет:
· логической репликации;
· декларативного секционирования (PARTITION BY).
🕰️ 2016 год.
PostgreSQL 9.5 еще не знает:
· параллельных запросов;
· синхронной репликации с несколькими узлами.
🕰️ 2014 год.
В PostgreSQL 9.3 еще нет:
· типа jsonb;
· команды ALTER SYSTEM (менять настройки без перезапуска сервера нельзя);
Также нет даже зачатков логической репликации данных.
🕰️ 2012 год.
PostgreSQL 9.1 еще не поддерживает JSON. Также в нем еще нет каскадной репликации.
🕰️ 2011 год.
В PostgreSQL 9.0 еще нет:
· знаменитого механизма расширений (CREATE EXTENSION);
· доступа к внешним данным (FDW) в привычном нам виде.
🕰️ 2010 год.
PostgreSQL 8.4 еще не имеет:
· потоковой репликации;
· встроенных средств для кластеров высокой доступности.
🕰️ 2009 год.
В PostgreSQL 8.3 ещё нет:
· оконных функций;
· поддержки Common Table Expression (включая рекурсивные запросы);
· доступа к данным из внешних источников.
🕰️ 2008 год.
В PostgreSQL 8.2 еще нет:
· полнотекстового поиска;
· GIN-индексов.
🕰️ 2005 год.
В PostgreSQL 8.0 еще нет:
· ролей (есть только пользователи и группы);
· двухфазных коммитов (2PC).
🕰️ 2001 год.
PostgreSQL 7.0 ещё не имеет:
· журнала предзаписи (WAL);
· VACUUM без блокировки всей таблицы;
· современного нам EXPLAIN.
🕰️ 2000 год (важная веха).
В PostgreSQL 6.5 еще нет встроенного языка PL/pgSQL. Он появится лишь в PostgreSQL 7.0.
А пока что функции пишутся только на C и "голом" SQL (без переменных, циклов и условий). Полноценной хранимой бизнес-логики нет.
🕰️ 1998 год.
PostgreSQL 6.4 ещё не поддерживает операторы EXCEPT и INTERSECT.
🕰️ 1997 год.
В PostgreSQL 6.2 еще нет триггеров и вложенных подзапросов (Subselects).
🕰️ 1995 год.
Проект называется Postgres95.
Имени «PostgreSQL» ещё нет.
🕰️ 1986 год.
В предшественнике PostgreSQL еще нет языка SQL 😀. Вместо него используется язык POSTQUEL.
🕰️ 1970 год.
Проект Ingres в Беркли — родоначальник всей линейки проектов, приведших к возникновению PostgreSQL, еще не начат.
Ну вот и всё. Наше путешествие во времени подошло к концу. Надеюсь, что Вам понравилась наша "машина времени"!
А теперь давайте вернёмся в настоящее и порадуемся тому, сколько всего умеет современный нам PostgreSQL и основанные на нем проекты.
И заодно оценим, как долго и терпеливо создавался каждый фрагмент функциональности этой удивительной СУБД.
Но иногда полезно оглянуться назад и вспомнить какой была наша любимая СУБД в прошлом.
Давайте запустим нашу "машину времени" и сделаем несколько остановок в прошлом проекта PostgreSQL, ставшего основой для нашей СУБД Digital Q.DataBase. Поехали!
🕰️ Начало 2025 года:
PostgreSQL 17 работает сильно медленнее привычного. Не удивительно, ведь в нём ещё нет асинхронного I/O (AIO) для параллельного чтения.
Также в нем еще нет:
· виртуальных генерируемых столбцов;
· встроенной uuidv7();
· аутентификации через OAuth 2.0.
🕰️ 2023 год:
В PostgreSQL 15 еще нет пакетной вставки для FDW через COPY.
🕰️ 2022 год.
В PostgreSQL 14 еще нет:
· команды MERGE (условное обновление/вставка);
· сжатия TOAST через LZ4.
🕰️ 2019 год.
PostgreSQL 11 ещё не знает что такое:
· генерируемые столбцы;
· JSON PATH для jsonb;
· хранимые процедуры с транзакциями (только функции);
· JIT-компиляция запросов.
🕰️ 2018 год.
В PostgreSQL 10 еще нет хранимых процедур (CREATE PROCEDURE).
Есть только функции (CREATE FUNCTION). Управлять транзакциями изнутри логики нельзя.
🕰️ 2017 год.
В PostgreSQL 9.6 еще нет:
· логической репликации;
· декларативного секционирования (PARTITION BY).
🕰️ 2016 год.
PostgreSQL 9.5 еще не знает:
· параллельных запросов;
· синхронной репликации с несколькими узлами.
🕰️ 2014 год.
В PostgreSQL 9.3 еще нет:
· типа jsonb;
· команды ALTER SYSTEM (менять настройки без перезапуска сервера нельзя);
Также нет даже зачатков логической репликации данных.
🕰️ 2012 год.
PostgreSQL 9.1 еще не поддерживает JSON. Также в нем еще нет каскадной репликации.
🕰️ 2011 год.
В PostgreSQL 9.0 еще нет:
· знаменитого механизма расширений (CREATE EXTENSION);
· доступа к внешним данным (FDW) в привычном нам виде.
🕰️ 2010 год.
PostgreSQL 8.4 еще не имеет:
· потоковой репликации;
· встроенных средств для кластеров высокой доступности.
🕰️ 2009 год.
В PostgreSQL 8.3 ещё нет:
· оконных функций;
· поддержки Common Table Expression (включая рекурсивные запросы);
· доступа к данным из внешних источников.
🕰️ 2008 год.
В PostgreSQL 8.2 еще нет:
· полнотекстового поиска;
· GIN-индексов.
🕰️ 2005 год.
В PostgreSQL 8.0 еще нет:
· ролей (есть только пользователи и группы);
· двухфазных коммитов (2PC).
🕰️ 2001 год.
PostgreSQL 7.0 ещё не имеет:
· журнала предзаписи (WAL);
· VACUUM без блокировки всей таблицы;
· современного нам EXPLAIN.
🕰️ 2000 год (важная веха).
В PostgreSQL 6.5 еще нет встроенного языка PL/pgSQL. Он появится лишь в PostgreSQL 7.0.
А пока что функции пишутся только на C и "голом" SQL (без переменных, циклов и условий). Полноценной хранимой бизнес-логики нет.
🕰️ 1998 год.
PostgreSQL 6.4 ещё не поддерживает операторы EXCEPT и INTERSECT.
🕰️ 1997 год.
В PostgreSQL 6.2 еще нет триггеров и вложенных подзапросов (Subselects).
🕰️ 1995 год.
Проект называется Postgres95.
Имени «PostgreSQL» ещё нет.
🕰️ 1986 год.
В предшественнике PostgreSQL еще нет языка SQL 😀. Вместо него используется язык POSTQUEL.
🕰️ 1970 год.
Проект Ingres в Беркли — родоначальник всей линейки проектов, приведших к возникновению PostgreSQL, еще не начат.
Ну вот и всё. Наше путешествие во времени подошло к концу. Надеюсь, что Вам понравилась наша "машина времени"!
А теперь давайте вернёмся в настоящее и порадуемся тому, сколько всего умеет современный нам PostgreSQL и основанные на нем проекты.
И заодно оценим, как долго и терпеливо создавался каждый фрагмент функциональности этой удивительной СУБД.
1 8 5 5
Сегодня в рубрике «выходного дня» хочу рассказать вам о ярком представителе класса HSAP (Hybrid Serving and Analytical Processing) систем управления базами данных - DingoDB.
Кстати, не путайте HSAP (свежую концепцию, придуманную в Поднебесной в 2020-х) и HTAP (придуманную Gatrner в 2014) - это не опечатка, а дальнейшая эволюция идеи гибридных СУБД.
Итак, DingoDB это китайская СУБД для Linux с открытой лицензией. Она умеет искать по смыслу. И использует для этого обычный SQL.
Представьте: у вас есть корпоративный архив — текстовые протоколы, аудиозаписи, видеоинструкции, сканы договоров. Надо найти всё, что по смыслу близко к фразе «как зарегистрировать предложение о доработке продукта?». Не тег, не ключевое слово — именно смысл документа является критерием поиска.
Обычные СУБД с этим не справляются. А вот HSAP-системы и, в частности, DingoDB — легко.
Любой контент (текст, звук, картинку) эта система превращает в вектор — «цифровой отпечаток» смысла. А дальше два простых SQL-запроса.
INSERT INTO documents (id, title, content_vector)
VALUES (1, 'Заголовок документа', TXT2VEC('Содержимое документа...'));
Функция TXT2VEC() сама создаёт вектор из текста. Также есть функции IMG2VEC() и AUDIO2VEC() для обработки изображений и аудиоконтента.
SELECT title FROM documents
ORDER BY VECTOR_DISTANCE(content_vector, TXT2VEC('как предложить доработку в продукт?'))
LIMIT 5;
Запрос вернёт самые близкие по смыслу документы, даже если там нет тех же слов. И даже если эти документы на другом языке.
SELECT * FROM documents
WHERE doc_type = 'audio' AND date > '2026-01-01'
ORDER BY VECTOR_DISTANCE(content_vector, TXT2VEC('что делать, если появилась идея по развитию продукта'))
LIMIT 10;
Вот это и есть гибридный поиск: точные условия (WHERE) плюс смысловое ранжирование.
DingoDB — одна из первых СУБД класса HSAP. Она идеально подходит под RAG-приложения, корпоративные архивы, медиа-библиотеки.
Но заложенные в ней идеи проникли и в другие СУБД, в частности возможности по векторизации контента уже появились и в Oracle и в MS SQL.
Please open Telegram to view this post
VIEW IN TELEGRAM
1 6 5 5