metis-desk/docs/architecture/preflight-so/diagnostico-mariadb.sql

162 lines
7.6 KiB
SQL

-- Diagnóstico preparado, NO ejecutado contra ningún destino en este preflight.
-- Solo SELECT. Ejecutar únicamente con autorización de lectura, credenciales de
-- mínimo privilegio y timeout impuesto por el cliente/operador, sin exponerlas.
-- Fase 1: detenerse si faltan tablas/columnas. No ejecutar la fase 2 en legacy/parcial.
SELECT VERSION() AS version,
@@session.foreign_key_checks AS session_fk,
@@global.foreign_key_checks AS global_fk,
@@session.check_constraint_checks AS session_checks,
@@global.check_constraint_checks AS global_checks;
SELECT TABLE_NAME, TABLE_TYPE, ENGINE
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME IN ('resources', 'resource_definitions', 'resource_template_fields',
'resource_characteristics', 'resource_specification_fields',
'resource_specification_field_choices', 'resource_specification_sections', 'resource_revisions',
'resource_revision_characteristics', 'resource_revision_specifications',
'resource_revision_specification_fields', 'resource_revision_specification_choices',
'software_installations', 'software_installation_revisions')
ORDER BY TABLE_NAME;
SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT,
CHARACTER_SET_NAME, COLLATION_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME IN ('resources', 'software_installations', 'software_installation_revisions')
ORDER BY TABLE_NAME, ORDINAL_POSITION;
SELECT TABLE_NAME, CONSTRAINT_NAME, CHECK_CLAUSE
FROM information_schema.CHECK_CONSTRAINTS
WHERE CONSTRAINT_SCHEMA = DATABASE() AND TABLE_NAME = 'resources'
ORDER BY CONSTRAINT_NAME;
SELECT TABLE_NAME, CONSTRAINT_NAME, COLUMN_NAME, ORDINAL_POSITION,
REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
FROM information_schema.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = DATABASE() AND REFERENCED_TABLE_NAME IS NOT NULL
AND TABLE_NAME IN ('resources', 'resource_revisions', 'resource_characteristics',
'resource_specification_fields', 'resource_revision_specifications',
'resource_revision_specification_fields', 'software_installations',
'software_installation_revisions')
ORDER BY TABLE_NAME, CONSTRAINT_NAME, ORDINAL_POSITION;
SELECT TABLE_NAME, INDEX_NAME, NON_UNIQUE, SEQ_IN_INDEX, COLUMN_NAME
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME IN ('resources', 'resource_revisions', 'software_installations',
'software_installation_revisions')
ORDER BY TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX;
-- Fase 2: solo tras confirmar esquema scoped completo y tablas anteriores.
-- Sin nombres de clientes/productos, actores, UUID ni valores de identidad en la salida.
SELECT COUNT(*) AS stock_os_templates
FROM resource_definitions
WHERE stockKey = 'template:os' AND kind = 'template' AND companyId IS NULL;
SELECT field.stockKey, binding.required, binding.position, COUNT(*) AS bindings
FROM resource_definitions template
JOIN resource_template_fields binding ON binding.templateId = template.id
JOIN resource_definitions field ON field.id = binding.fieldId
WHERE template.stockKey = 'template:os' AND template.companyId IS NULL
GROUP BY field.stockKey, binding.required, binding.position
ORDER BY binding.position;
SELECT choice.value, choice.position, COUNT(*) AS definitions
FROM resource_definitions field
JOIN resource_field_choices choice ON choice.fieldId = field.id
WHERE field.stockKey = 'field:os_edition_state' AND field.companyId IS NULL
GROUP BY choice.value, choice.position
ORDER BY choice.position;
SELECT r.scope, r.active,
CASE WHEN template.stockKey = 'template:os' THEN 'stock' ELSE 'custom' END AS template_kind,
COUNT(*) AS os_resources
FROM resources r
JOIN resource_definitions template ON template.id = r.templateId
WHERE template.usage = 'os'
GROUP BY r.scope, r.active, template_kind;
SELECT COUNT(*) AS invalid_scope_owner
FROM resources
WHERE scope IS NULL
OR NOT ((scope = 'company' AND CHAR_LENGTH(scope) = 7 AND companyId IS NOT NULL)
OR (scope = 'global' AND CHAR_LENGTH(scope) = 6 AND companyId IS NULL));
WITH identity_values AS (
SELECT r.id, r.scope, r.active,
MAX(CASE WHEN f.stockKey = 'field:provider' THEN NULLIF(TRIM(c.textValue), '') END) AS provider,
MAX(CASE WHEN f.stockKey = 'field:os_family' THEN NULLIF(TRIM(c.textValue), '') END) AS family,
MAX(CASE WHEN f.stockKey = 'field:os_product_version' THEN NULLIF(TRIM(c.textValue), '') END) AS product_version,
MAX(CASE WHEN f.stockKey = 'field:os_edition_state' THEN c.textValue END) AS edition_state,
MAX(CASE WHEN f.stockKey = 'field:software_edition' THEN NULLIF(TRIM(c.textValue), '') END) AS edition
FROM resources r
JOIN resource_definitions template ON template.id = r.templateId AND template.usage = 'os'
LEFT JOIN resource_characteristics c ON c.resourceId = r.id
LEFT JOIN resource_definitions f ON f.id = c.fieldId
GROUP BY r.id, r.scope, r.active
)
SELECT scope, active, COUNT(*) AS resources,
SUM(provider IS NULL OR family IS NULL OR product_version IS NULL
OR edition_state IS NULL OR edition_state NOT IN ('known', 'not_applicable')
OR (edition_state = 'known' AND edition IS NULL)
OR (edition_state = 'not_applicable' AND edition IS NOT NULL)) AS incomplete_or_inconsistent
FROM identity_values
GROUP BY scope, active;
-- Un particular incompleto o un borrador desconocido no es por sí mismo un error.
-- Esta consulta no implementa toda la policy semántica ni la revisión de duplicados.
SELECT r.scope, r.active, s.state, COUNT(*) AS installations
FROM software_installations s
JOIN resources r ON r.id = s.resourceId
JOIN resource_definitions template ON template.id = r.templateId AND template.usage = 'os'
GROUP BY r.scope, r.active, s.state;
SELECT r.scope, history.state, COUNT(*) AS revisions
FROM software_installation_revisions history
JOIN resources r ON r.id = history.resourceId
JOIN resource_definitions template ON template.id = r.templateId AND template.usage = 'os'
GROUP BY r.scope, history.state;
SELECT installations_per_company, COUNT(*) AS companies
FROM (
SELECT companyId, COUNT(*) AS installations_per_company
FROM software_installations
GROUP BY companyId
) volumes
GROUP BY installations_per_company
ORDER BY installations_per_company;
SELECT COUNT(*) AS invalid_installation_references
FROM software_installations s
LEFT JOIN assets a ON a.id = s.assetId
LEFT JOIN resources r ON r.id = s.resourceId
LEFT JOIN resources license ON license.id = s.licenseResourceId
WHERE a.id IS NULL OR a.companyId <> s.companyId OR r.id IS NULL
OR (r.scope = 'company' AND r.companyId <> s.companyId)
OR (s.licenseResourceId IS NOT NULL AND
(license.id IS NULL OR license.scope <> 'company' OR license.companyId <> s.companyId));
SELECT COUNT(*) AS orphan_resource_revisions
FROM resource_revisions h LEFT JOIN resources r ON r.id = h.resourceId
WHERE r.id IS NULL;
SELECT COUNT(*) AS orphan_installation_revisions
FROM software_installation_revisions h
LEFT JOIN software_installations s ON s.id = h.configurationId
WHERE s.id IS NULL;
SELECT COUNT(*) AS invalid_historical_references
FROM software_installation_revisions h
JOIN software_installations s ON s.id = h.configurationId
LEFT JOIN assets a ON a.id = h.assetId
LEFT JOIN resources r ON r.id = h.resourceId
LEFT JOIN resources license ON license.id = h.licenseResourceId
WHERE a.id IS NULL OR a.companyId <> s.companyId OR r.id IS NULL
OR (r.scope = 'company' AND r.companyId <> s.companyId)
OR (h.licenseResourceId IS NOT NULL AND
(license.id IS NULL OR license.scope <> 'company' OR license.companyId <> s.companyId));