Загрузить файлы в «/»

This commit is contained in:
2025-12-18 10:04:29 +03:00
parent 6b549235fd
commit 8202e03367
2 changed files with 1845 additions and 0 deletions
+728
View File
@@ -0,0 +1,728 @@
-- Создание схемы для модуля вычисляемых полей
CREATE SCHEMA IF NOT EXISTS computed_fields_system;
-- ============================================================================
-- РАЗДЕЛ 1: СЛУЖЕБНЫЕ ТАБЛИЦЫ
-- ============================================================================
-- Таблица конфигурации вычисляемых полей (реестр правил)
CREATE TABLE IF NOT EXISTS computed_fields_system.computed_fields_config (
id SERIAL PRIMARY KEY,
table_schema VARCHAR(63) NOT NULL DEFAULT 'public',
table_name VARCHAR(63) NOT NULL,
column_name VARCHAR(63) NOT NULL,
column_type VARCHAR(50) NOT NULL,
expression TEXT NOT NULL,
implementation_type VARCHAR(10) NOT NULL DEFAULT 'AUTO'
CHECK (implementation_type IN ('AUTO', 'NATIVE', 'TRIGGER')),
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
description TEXT,
UNIQUE (table_schema, table_name, column_name)
);
COMMENT ON TABLE computed_fields_system.computed_fields_config IS
'Реестр конфигурации вычисляемых полей для автоматической генерации';
-- Таблица логов применения правил
CREATE TABLE IF NOT EXISTS computed_fields_system.application_log (
id SERIAL PRIMARY KEY,
config_id INTEGER REFERENCES computed_fields_system.computed_fields_config(id),
action VARCHAR(20) NOT NULL,
implementation_method VARCHAR(10) NOT NULL,
status VARCHAR(10) NOT NULL CHECK (status IN ('SUCCESS', 'ERROR')),
error_message TEXT,
executed_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- Таблица результатов валидации
CREATE TABLE IF NOT EXISTS computed_fields_system.validation_results (
id SERIAL PRIMARY KEY,
table_schema VARCHAR(63) NOT NULL,
table_name VARCHAR(63) NOT NULL,
column_name VARCHAR(63) NOT NULL,
validation_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
total_rows BIGINT NOT NULL,
invalid_rows BIGINT NOT NULL,
invalid_row_ids TEXT
);
-- ============================================================================
-- РАЗДЕЛ 2: ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ
-- ============================================================================
-- Функция для определения версии PostgreSQL
CREATE OR REPLACE FUNCTION computed_fields_system.get_pg_version_num()
RETURNS INTEGER
LANGUAGE plpgsql STABLE
AS $$
DECLARE
v_version INTEGER;
BEGIN
SELECT current_setting('server_version_num')::INTEGER INTO v_version;
RETURN v_version;
END;
$$;
-- Функция проверки поддержки GENERATED COLUMNS
CREATE OR REPLACE FUNCTION computed_fields_system.supports_generated_columns()
RETURNS BOOLEAN
LANGUAGE plpgsql STABLE
AS $$
BEGIN
-- PostgreSQL 12+ (версия >= 120000) поддерживает GENERATED COLUMNS
RETURN computed_fields_system.get_pg_version_num() >= 120000;
END;
$$;
-- Функция проверки существования столбца
CREATE OR REPLACE FUNCTION computed_fields_system.column_exists(
p_schema VARCHAR,
p_table VARCHAR,
p_column VARCHAR
)
RETURNS BOOLEAN
LANGUAGE plpgsql STABLE
AS $$
DECLARE
v_exists BOOLEAN;
BEGIN
SELECT EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = p_schema
AND table_name = p_table
AND column_name = p_column
) INTO v_exists;
RETURN v_exists;
END;
$$;
-- ============================================================================
-- РАЗДЕЛ 3: ОСНОВНЫЕ ПРОЦЕДУРЫ ГЕНЕРАЦИИ
-- ============================================================================
-- Процедура создания вычисляемого поля через GENERATED COLUMN (нативный метод)
CREATE OR REPLACE FUNCTION computed_fields_system.create_generated_column(
p_schema VARCHAR,
p_table VARCHAR,
p_column VARCHAR,
p_type VARCHAR,
p_expression TEXT
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
v_sql TEXT;
BEGIN
-- Формирование DDL-команды для GENERATED ALWAYS AS
v_sql := format(
'ALTER TABLE %I.%I ADD COLUMN %I %s GENERATED ALWAYS AS (%s) STORED',
p_schema, p_table, p_column, p_type, p_expression
);
RAISE NOTICE 'Executing: %', v_sql;
EXECUTE v_sql;
RAISE NOTICE 'Generated column %.%.% created successfully',
p_schema, p_table, p_column;
END;
$$;
-- Процедура создания вычисляемого поля через TRIGGER (триггерный метод)
CREATE OR REPLACE FUNCTION computed_fields_system.create_trigger_computed_field(
p_schema VARCHAR,
p_table VARCHAR,
p_column VARCHAR,
p_type VARCHAR,
p_expression TEXT
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
v_function_name VARCHAR;
v_trigger_name VARCHAR;
v_sql TEXT;
BEGIN
-- Генерация уникальных имен для функции и триггера
v_function_name := format('trg_fn_%s_%s_compute', p_table, p_column);
v_trigger_name := format('trg_%s_%s_compute', p_table, p_column);
-- 1. Добавляем столбец (если не существует)
IF NOT computed_fields_system.column_exists(p_schema, p_table, p_column) THEN
v_sql := format(
'ALTER TABLE %I.%I ADD COLUMN %I %s',
p_schema, p_table, p_column, p_type
);
EXECUTE v_sql;
END IF;
-- 2. Создаем триггерную функцию
v_sql := format($FUNC$
CREATE OR REPLACE FUNCTION %I.%I()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $TRG$
BEGIN
-- Вычисление значения с обработкой NULL
BEGIN
NEW.%I := (%s)::%s;
EXCEPTION WHEN OTHERS THEN
-- Логирование ошибки, но не прерываем транзакцию
RAISE WARNING 'Error computing field %%.%%: %%',
TG_TABLE_SCHEMA, TG_TABLE_NAME, SQLERRM;
NEW.%I := NULL;
END;
RETURN NEW;
END;
$TRG$;
$FUNC$,
p_schema, v_function_name,
p_column, p_expression, p_type,
p_column
);
EXECUTE v_sql;
-- 3. Создаем триггер
v_sql := format($TRIG$
DROP TRIGGER IF EXISTS %I ON %I.%I;
CREATE TRIGGER %I
BEFORE INSERT OR UPDATE ON %I.%I
FOR EACH ROW
EXECUTE FUNCTION %I.%I();
$TRIG$,
v_trigger_name, p_schema, p_table,
v_trigger_name,
p_schema, p_table,
p_schema, v_function_name
);
EXECUTE v_sql;
RAISE NOTICE 'Trigger-based computed field %.%.% created successfully',
p_schema, p_table, p_column;
END;
$$;
-- ============================================================================
-- РАЗДЕЛ 4: ОРКЕСТРАТОР - ПРИМЕНЕНИЕ ПРАВИЛ
-- ============================================================================
CREATE OR REPLACE FUNCTION computed_fields_system.apply_computed_fields_rules()
RETURNS TABLE (
config_id INTEGER,
table_full_name TEXT,
column_name TEXT,
method_used VARCHAR,
status TEXT
)
LANGUAGE plpgsql
AS $$
DECLARE
v_config RECORD;
v_implementation_method VARCHAR(10);
v_supports_native BOOLEAN;
v_error_msg TEXT;
BEGIN
-- Проверка поддержки нативных GENERATED COLUMNS
v_supports_native := computed_fields_system.supports_generated_columns();
RAISE NOTICE 'PostgreSQL version: %, Native GENERATED COLUMNS support: %',
computed_fields_system.get_pg_version_num(), v_supports_native;
-- Обработка каждого правила из конфигурации
FOR v_config IN
SELECT c.id, c.table_schema, c.table_name, c.column_name,
c.column_type, c.expression, c.implementation_type
FROM computed_fields_system.computed_fields_config c
WHERE c.is_active = TRUE
ORDER BY c.id
LOOP
BEGIN
-- Определение метода реализации
IF v_config.implementation_type = 'AUTO' THEN
v_implementation_method := CASE
WHEN v_supports_native THEN 'NATIVE'
ELSE 'TRIGGER'
END;
ELSE
v_implementation_method := v_config.implementation_type;
END IF;
-- Проверка возможности использования выбранного метода
IF v_implementation_method = 'NATIVE' AND NOT v_supports_native THEN
RAISE EXCEPTION 'NATIVE method requested but PostgreSQL version < 12';
END IF;
-- Проверка существования столбца
IF computed_fields_system.column_exists(
v_config.table_schema,
v_config.table_name,
v_config.column_name
) THEN
RAISE NOTICE 'Column %.%.% already exists, skipping',
v_config.table_schema, v_config.table_name, v_config.column_name;
CONTINUE;
END IF;
-- Применение выбранного метода
IF v_implementation_method = 'NATIVE' THEN
PERFORM computed_fields_system.create_generated_column(
v_config.table_schema,
v_config.table_name,
v_config.column_name,
v_config.column_type,
v_config.expression
);
ELSE
PERFORM computed_fields_system.create_trigger_computed_field(
v_config.table_schema,
v_config.table_name,
v_config.column_name,
v_config.column_type,
v_config.expression
);
END IF;
-- Логирование успешного применения
INSERT INTO computed_fields_system.application_log
(config_id, action, implementation_method, status)
VALUES
(v_config.id, 'CREATE', v_implementation_method, 'SUCCESS');
-- Возврат результата
RETURN QUERY SELECT
v_config.id,
v_config.table_schema || '.' || v_config.table_name,
v_config.column_name,
v_implementation_method,
'SUCCESS'::TEXT;
EXCEPTION WHEN OTHERS THEN
v_error_msg := SQLERRM;
-- Логирование ошибки
INSERT INTO computed_fields_system.application_log
(config_id, action, implementation_method, status, error_message)
VALUES
(v_config.id, 'CREATE', v_implementation_method, 'ERROR', v_error_msg);
RAISE WARNING 'Failed to create computed field %.%.%: %',
v_config.table_schema, v_config.table_name,
v_config.column_name, v_error_msg;
RETURN QUERY SELECT
v_config.id,
v_config.table_schema || '.' || v_config.table_name,
v_config.column_name,
v_implementation_method,
'ERROR: ' || v_error_msg;
END;
END LOOP;
END;
$$;
-- ============================================================================
-- РАЗДЕЛ 5: ВАЛИДАЦИЯ ЦЕЛОСТНОСТИ
-- ============================================================================
CREATE OR REPLACE FUNCTION computed_fields_system.validate_computed_fields(
p_table_schema VARCHAR DEFAULT 'public',
p_table_name VARCHAR DEFAULT NULL
)
RETURNS TABLE (
table_name TEXT,
column_name TEXT,
total_rows BIGINT,
invalid_rows BIGINT,
is_valid BOOLEAN
)
LANGUAGE plpgsql
AS $$
DECLARE
v_config RECORD;
v_sql TEXT;
v_total_rows BIGINT;
v_invalid_rows BIGINT;
v_invalid_ids TEXT;
BEGIN
-- Обработка каждого активного правила
FOR v_config IN
SELECT c.table_schema, c.table_name, c.column_name,
c.expression, c.column_type
FROM computed_fields_system.computed_fields_config c
WHERE c.is_active = TRUE
AND c.table_schema = p_table_schema
AND (p_table_name IS NULL OR c.table_name = p_table_name)
ORDER BY c.table_name, c.column_name
LOOP
-- Проверка существования столбца
IF NOT computed_fields_system.column_exists(
v_config.table_schema,
v_config.table_name,
v_config.column_name
) THEN
RAISE WARNING 'Column %.%.% does not exist, skipping validation',
v_config.table_schema, v_config.table_name, v_config.column_name;
CONTINUE;
END IF;
-- Подсчет общего количества строк
v_sql := format(
'SELECT COUNT(*) FROM %I.%I',
v_config.table_schema, v_config.table_name
);
EXECUTE v_sql INTO v_total_rows;
-- Подсчет строк с расхождениями
v_sql := format($VAL$
SELECT COUNT(*),
STRING_AGG(id::TEXT, ', ')
FROM (
SELECT
CASE
WHEN pg_typeof(id) = 'integer'::regtype THEN id::INTEGER
WHEN pg_typeof(id) = 'bigint'::regtype THEN id::BIGINT
ELSE id::INTEGER
END as id
FROM %I.%I
WHERE %I IS DISTINCT FROM ((%s)::%s)
LIMIT 100
) subq
$VAL$,
v_config.table_schema, v_config.table_name,
v_config.column_name, v_config.expression, v_config.column_type
);
BEGIN
EXECUTE v_sql INTO v_invalid_rows, v_invalid_ids;
EXCEPTION WHEN OTHERS THEN
RAISE WARNING 'Validation error for %.%.%: %',
v_config.table_schema, v_config.table_name,
v_config.column_name, SQLERRM;
v_invalid_rows := -1;
v_invalid_ids := 'ERROR: ' || SQLERRM;
END;
-- Сохранение результатов валидации
INSERT INTO computed_fields_system.validation_results
(table_schema, table_name, column_name, total_rows,
invalid_rows, invalid_row_ids)
VALUES
(v_config.table_schema, v_config.table_name, v_config.column_name,
v_total_rows, v_invalid_rows, v_invalid_ids);
-- Возврат результата
RETURN QUERY SELECT
v_config.table_schema || '.' || v_config.table_name,
v_config.column_name,
v_total_rows,
v_invalid_rows,
(v_invalid_rows = 0);
END LOOP;
END;
$$;
-- Процедура принудительного пересчета значений
CREATE OR REPLACE FUNCTION computed_fields_system.force_recompute(
p_table_schema VARCHAR,
p_table_name VARCHAR,
p_column_name VARCHAR
)
RETURNS BIGINT
LANGUAGE plpgsql
AS $$
DECLARE
v_config RECORD;
v_sql TEXT;
v_updated_rows BIGINT;
BEGIN
-- Получение конфигурации поля
SELECT c.expression, c.column_type
INTO v_config
FROM computed_fields_system.computed_fields_config c
WHERE c.table_schema = p_table_schema
AND c.table_name = p_table_name
AND c.column_name = p_column_name
AND c.is_active = TRUE;
IF NOT FOUND THEN
RAISE EXCEPTION 'Configuration not found for %.%.%',
p_table_schema, p_table_name, p_column_name;
END IF;
-- Массовое обновление
v_sql := format($UPD$
UPDATE %I.%I
SET %I = (%s)::%s
$UPD$,
p_table_schema, p_table_name,
p_column_name, v_config.expression, v_config.column_type
);
EXECUTE v_sql;
GET DIAGNOSTICS v_updated_rows = ROW_COUNT;
RAISE NOTICE 'Force recompute: % rows updated in %.%.%',
v_updated_rows, p_table_schema, p_table_name, p_column_name;
RETURN v_updated_rows;
END;
$$;
-- ============================================================================
-- РАЗДЕЛ 6: ДЕМОНСТРАЦИОННЫЕ ПРИМЕРЫ
-- ============================================================================
-- Пример 1: Таблица заказов (order_items)
CREATE TABLE IF NOT EXISTS order_items (
id SERIAL PRIMARY KEY,
order_id INTEGER NOT NULL,
product_name VARCHAR(255) NOT NULL,
quantity INTEGER NOT NULL CHECK (quantity > 0),
unit_price NUMERIC(10,2) NOT NULL CHECK (unit_price >= 0),
discount_percent NUMERIC(5,2) DEFAULT 0 CHECK (discount_percent BETWEEN 0 AND 100),
tax_rate NUMERIC(5,2) DEFAULT 0 CHECK (tax_rate >= 0),
order_date DATE DEFAULT CURRENT_DATE
);
-- Пример 2: Таблица комнат (rooms)
CREATE TABLE IF NOT EXISTS rooms (
id SERIAL PRIMARY KEY,
room_number VARCHAR(10) NOT NULL,
length NUMERIC(10,2) NOT NULL CHECK (length > 0),
width NUMERIC(10,2) NOT NULL CHECK (width > 0)
);
-- Пример 3: Таблица пользователей (users)
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
middle_name VARCHAR(100),
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Пример 4: Таблица логов с JSON (users_log)
CREATE TABLE IF NOT EXISTS users_log (
id SERIAL PRIMARY KEY,
payload JSONB NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- ============================================================================
-- РАЗДЕЛ 7: КОНФИГУРАЦИЯ ВЫЧИСЛЯЕМЫХ ПОЛЕЙ
-- ============================================================================
-- Добавление правил для вычисляемых полей
INSERT INTO computed_fields_system.computed_fields_config
(table_schema, table_name, column_name, column_type, expression,
implementation_type, description)
VALUES
-- Пример 1: Итоговая стоимость позиции заказа
('public', 'order_items', 'final_price', 'NUMERIC(10,2)',
'(quantity * unit_price) * (1 - discount_percent / 100.0) * (1 + tax_rate / 100.0)',
'AUTO',
'Финальная стоимость с учетом скидки и налога'),
-- Пример 2: Площадь комнаты
('public', 'rooms', 'total_area', 'NUMERIC(10,2)',
'length * width',
'AUTO',
'Площадь комнаты в квадратных метрах'),
-- Пример 3: Полное имя пользователя
('public', 'users', 'full_name', 'TEXT',
'CONCAT_WS('' '', last_name, first_name, middle_name)',
'AUTO',
'ФИО пользователя для поиска и отображения'),
-- Пример 4: Поисковая строка (нормализованная)
('public', 'users', 'search_string', 'TEXT',
'LOWER(CONCAT_WS('' '', last_name, first_name, middle_name, email))',
'AUTO',
'Нормализованная строка для полнотекстового поиска'),
-- Пример 5: Email из JSON
('public', 'users_log', 'email_extracted', 'TEXT',
'payload ->> ''email''',
'AUTO',
'Email извлеченный из JSON для быстрого доступа')
ON CONFLICT (table_schema, table_name, column_name) DO NOTHING;
-- ============================================================================
-- РАЗДЕЛ 8: ТЕСТОВЫЕ ДАННЫЕ
-- ============================================================================
-- Вставка тестовых данных в order_items
INSERT INTO order_items (order_id, product_name, quantity, unit_price, discount_percent, tax_rate)
VALUES
(1, 'Ноутбук Lenovo ThinkPad', 2, 75000.00, 5.00, 20.00),
(1, 'Мышь Logitech MX Master', 2, 7500.00, 10.00, 20.00),
(2, 'Монитор Dell UltraSharp', 1, 45000.00, 0.00, 20.00),
(3, 'Клавиатура Mechanical', 3, 12000.00, 15.00, 20.00);
-- Вставка тестовых данных в rooms
INSERT INTO rooms (room_number, length, width)
VALUES
('A101', 5.5, 4.2),
('A102', 6.0, 5.0),
('B201', 4.5, 3.8),
('B202', 7.2, 6.5);
-- Вставка тестовых данных в users
INSERT INTO users (first_name, last_name, middle_name, email)
VALUES
('Арина', 'Полякова', 'Витальевна', 'polyakova.av@example.com'),
('Иван', 'Иванов', 'Петрович', 'ivanov.ip@example.com'),
('Мария', 'Сидорова', NULL, 'sidorova.m@example.com'),
('Петр', 'Петров', 'Сергеевич', 'petrov.ps@example.com');
-- Вставка тестовых данных в users_log
INSERT INTO users_log (payload)
VALUES
('{"email": "test1@example.com", "action": "login", "timestamp": "2025-12-15T10:00:00Z"}'::jsonb),
('{"email": "test2@example.com", "action": "logout", "timestamp": "2025-12-15T11:00:00Z"}'::jsonb),
('{"email": "admin@example.com", "action": "update", "timestamp": "2025-12-15T12:00:00Z"}'::jsonb);
-- ============================================================================
-- РАЗДЕЛ 9: ПРИМЕНЕНИЕ ПРАВИЛ И ТЕСТИРОВАНИЕ
-- ============================================================================
-- Применение всех правил
SELECT * FROM computed_fields_system.apply_computed_fields_rules();
-- Проверка созданных полей
SELECT
table_name,
column_name,
data_type,
is_generated,
generation_expression
FROM information_schema.columns
WHERE table_schema = 'public'
AND column_name IN ('final_price', 'total_area', 'full_name',
'search_string', 'email_extracted')
ORDER BY table_name, ordinal_position;
-- Проверка триггеров
SELECT
trigger_schema,
trigger_name,
event_object_table,
action_statement
FROM information_schema.triggers
WHERE trigger_name LIKE 'trg_%_compute'
ORDER BY event_object_table;
-- Валидация целостности всех полей
SELECT * FROM computed_fields_system.validate_computed_fields();
-- Просмотр результатов в таблицах
SELECT id, product_name, quantity, unit_price,
discount_percent, tax_rate, final_price
FROM order_items;
SELECT id, room_number, length, width, total_area
FROM rooms;
SELECT id, last_name, first_name, middle_name,
full_name, search_string
FROM users;
SELECT id, payload, email_extracted
FROM users_log;
-- ============================================================================
-- РАЗДЕЛ 10: УТИЛИТЫ ДЛЯ УПРАВЛЕНИЯ
-- ============================================================================
-- Просмотр логов применения правил
CREATE OR REPLACE VIEW computed_fields_system.v_application_log AS
SELECT
l.id,
l.executed_at,
c.table_schema || '.' || c.table_name as table_full_name,
c.column_name,
l.action,
l.implementation_method,
l.status,
l.error_message
FROM computed_fields_system.application_log l
JOIN computed_fields_system.computed_fields_config c ON c.id = l.config_id
ORDER BY l.executed_at DESC;
-- Просмотр последних результатов валидации
CREATE OR REPLACE VIEW computed_fields_system.v_latest_validation AS
SELECT DISTINCT ON (table_schema, table_name, column_name)
table_schema || '.' || table_name as table_full_name,
column_name,
validation_time,
total_rows,
invalid_rows,
CASE
WHEN invalid_rows = 0 THEN 'VALID'
WHEN invalid_rows > 0 THEN 'INVALID'
ELSE 'ERROR'
END as validation_status
FROM computed_fields_system.validation_results
ORDER BY table_schema, table_name, column_name, validation_time DESC;
-- Процедура деактивации правила
CREATE OR REPLACE FUNCTION computed_fields_system.deactivate_rule(
p_table_schema VARCHAR,
p_table_name VARCHAR,
p_column_name VARCHAR
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
BEGIN
UPDATE computed_fields_system.computed_fields_config
SET is_active = FALSE,
updated_at = CURRENT_TIMESTAMP
WHERE table_schema = p_table_schema
AND table_name = p_table_name
AND column_name = p_column_name;
IF NOT FOUND THEN
RAISE EXCEPTION 'Rule not found for %.%.%',
p_table_schema, p_table_name, p_column_name;
END IF;
RAISE NOTICE 'Rule deactivated for %.%.%',
p_table_schema, p_table_name, p_column_name;
END;
$$;
-- ============================================================================
-- РАЗДЕЛ 11: ДОКУМЕНТАЦИЯ И СПРАВКА
-- ============================================================================
COMMENT ON SCHEMA computed_fields_system IS
'Система автоматической генерации вычисляемых полей в PostgreSQL';
COMMENT ON FUNCTION computed_fields_system.apply_computed_fields_rules() IS
'Оркестратор применения правил: сканирует конфигурацию и создает вычисляемые поля';
COMMENT ON FUNCTION computed_fields_system.validate_computed_fields(VARCHAR, VARCHAR) IS
'Валидация целостности: проверяет соответствие сохраненных значений формулам';
COMMENT ON FUNCTION computed_fields_system.force_recompute(VARCHAR, VARCHAR, VARCHAR) IS
'Принудительный пересчет всех значений вычисляемого поля';
-- Итоговый отчет
SELECT 'Модуль успешно установлен!' as status,
computed_fields_system.get_pg_version_num() as pg_version,
computed_fields_system.supports_generated_columns() as native_support,
(SELECT COUNT(*) FROM computed_fields_system.computed_fields_config WHERE is_active = TRUE) as active_rules;
-- ============================================================================
-- КОНЕЦ СКРИПТА
-- ============================================================================
File diff suppressed because it is too large Load Diff