pbl_blueprint/sql/m1b_ddl.sql
2026-09-16 17:17:53 +08:00

184 lines
16 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- =============================================================================
-- pbl_blueprint M1b DDL —— 模板平台公共部分 / 子对象扩展 / 关联表判定
-- =============================================================================
-- 覆盖 4 张表(与 pbl_blueprint/models/m1b/*.json 四段式表模型一一对应):
-- 1) pbl_blueprint_template 模板表tenant_id NULL = 平台公共模板)
-- 2) pbl_ext_field_def 子对象扩展字段定义表元数据字典fail-closed 校验依据)
-- 3) pbl_subobject_ext 子对象扩展值表EAV一行一键值
-- 4) pbl_blueprint_ref 蓝图外部关联表Q-OPEN-3 裁决物理落地)
--
-- 设计铁律:
-- * 全部 CREATE TABLE IF NOT EXISTS / CREATE INDEX 幂等可重复执行build.sh 与
-- m1b_init.ensure_m1b_tables 双入口均执行本文件);
-- * 无 FOREIGN KEY跨模块/可能跨库,有效性由 m1b_ref.resolve_refs() 主动判定);
-- * 无 ENUM一律 varchar + 字典 codes见 models/m1b/*.json 的 codes 段);
-- * 无 TIMESTAMP一律 datetime避免 2038 与隐式时区转换);
-- * 租户列索引打头:所有业务索引首列为 tenant_key= COALESCE(tenant_id,'__PLATFORM__')
-- 或 tenant_id唯一键以 tenant_key 打头,规避 MariaDB 唯一索引不对 NULL 去重
-- 导致平台公共行tenant_id IS NULL可重复插入的问题
-- * Q-OPEN-3本文件**不含**任何针对 world / scene / entity / script 等复用域基表的
-- CREATE / ALTER / UPDATE / DELETE 语句——蓝图对外部对象的引用单向落在
-- pbl_blueprint_refref_mode 恒为 'readonly'。
-- =============================================================================
SET NAMES utf8mb4;
-- -----------------------------------------------------------------------------
-- 1) pbl_blueprint_template —— PBL 蓝图模板表M1b
-- tenant_id IS NULL 且 platform_flag='Y' → 平台公共模板,对全部租户可见
-- tenant_id 非空 → 租户私有模板
-- 模板升级 append 新版本行、不覆盖旧版本Q-OPEN-9
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `pbl_blueprint_template` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '物理主键 AUTO_INCREMENT',
`tenant_key` varchar(32) NOT NULL COMMENT '= COALESCE(tenant_id,''__PLATFORM__'');索引打头列;应用层计算,不接受外部传入',
`tenant_id` varchar(32) DEFAULT NULL COMMENT 'NULL = 平台公共模板M1b 模板平台公共部分);非空 = 租户私有模板',
`template_code` varchar(32) NOT NULL COMMENT '业务主键pbl_common.gen_code(''TPL'', tenant_id) 生成',
`template_version` int NOT NULL DEFAULT 1 COMMENT '模板版本,升级 append 新版本不覆盖旧行',
`template_name` varchar(128) NOT NULL COMMENT '模板名称',
`subject` varchar(32) DEFAULT NULL COMMENT '学科,字典 pbl_subject',
`grade` varchar(16) DEFAULT NULL COMMENT '学段,字典 pbl_grade',
`category` varchar(32) DEFAULT NULL COMMENT '模板分类,字典 pbl_tpl_category',
`tpl_json` longtext NOT NULL COMMENT '7 类子对象数组 + 模板内临时 ID 父子引用',
`tpl_hash` varchar(64) NOT NULL COMMENT 'sha256(canonical_json(tpl_json)),确定性实例化校验',
`offline_flag` varchar(1) NOT NULL DEFAULT 'N' COMMENT 'Y=build.sh 种子落库的内置离线兜底模板',
`platform_flag` varchar(1) NOT NULL DEFAULT 'N' COMMENT 'Y=平台公共模板(此时 tenant_id 必须为 NULL字典 pbl_yes_no',
`ref_policy` varchar(16) NOT NULL DEFAULT 'warn' COMMENT 'strict=引用缺失阻断回滚warn=落库并标记 ref_unresolvedQ-OPEN-4字典 pbl_ref_policy',
`tpl_status` varchar(16) NOT NULL DEFAULT 'active' COMMENT '模板状态,字典 pbl_tpl_status',
`usage_count` int NOT NULL DEFAULT 0 COMMENT '实例化次数(供 M10 分析,非权威计数)',
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
`creator_id` varchar(32) DEFAULT NULL COMMENT '创建人 rbac 用户ID',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tpl_code_ver` (`tenant_key`, `template_code`, `template_version`),
KEY `idx_tpl_status` (`tenant_key`, `tpl_status`, `subject`, `grade`),
KEY `idx_tpl_offline` (`tenant_key`, `offline_flag`),
KEY `idx_tpl_hash` (`tenant_key`, `tpl_hash`),
KEY `idx_tpl_platform` (`platform_flag`, `tpl_status`),
KEY `idx_tpl_tenant` (`tenant_id`, `tpl_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='PBL 蓝图模板表M1b含平台公共模板 tenant_id NULL';
-- -----------------------------------------------------------------------------
-- 2) pbl_ext_field_def —— PBL 子对象扩展字段定义表M1b
-- 扩展字段元数据字典:某类子对象允许挂哪些扩展键、类型、必填、默认值、
-- 枚举候选、长度上限、正则校验。
-- m1b_subobject.set_ext / bulk_set_ext 写 pbl_subobject_ext 前必须先按本表
-- fail-closed 校验:未定义键 → PBL_EXT_FIELD_UNDEFINED
-- 类型/长度/枚举/正则不符 → PBL_EXT_VALUE_INVALID。
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `pbl_ext_field_def` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '物理主键 AUTO_INCREMENT',
`tenant_key` varchar(32) NOT NULL COMMENT '= COALESCE(tenant_id,''__PLATFORM__'');索引打头列;应用层计算',
`tenant_id` varchar(32) DEFAULT NULL COMMENT 'NULL = 平台内置字段定义;非空 = 租户自有字段定义',
`def_code` varchar(32) NOT NULL COMMENT '业务主键pbl_common.gen_code(''EFD'', tenant_id) 生成',
`subobject_type` varchar(32) NOT NULL COMMENT '字典 pbl_subobject_type 的 7 类之一;''*'' 表示全部类型通用',
`field_key` varchar(64) NOT NULL COMMENT '写入 pbl_subobject_ext.ext_key 的键名;^[a-z][a-z0-9_]{0,63}$',
`field_label` varchar(128) NOT NULL COMMENT '字段显示名',
`value_type` varchar(16) NOT NULL DEFAULT 'string' COMMENT '字典 pbl_ext_value_typestring/int/float/bool/json/date/enum',
`required_flag` varchar(1) NOT NULL DEFAULT 'N' COMMENT 'Y=保存该子对象扩展时此键必须出现且非空;字典 pbl_yes_no',
`default_value` varchar(512) DEFAULT NULL COMMENT '调用方未传该键时按 value_type 强转后落库',
`enum_options` text DEFAULT NULL COMMENT 'value_type=enum 时必填JSON 数组字符串,如 ["easy","normal","hard"]',
`max_length` int NOT NULL DEFAULT 0 COMMENT '0=不限制;>0 时对 string/json/enum 序列化长度做上限校验',
`validate_regex` varchar(256) DEFAULT NULL COMMENT '非空时对 string 值做 re.fullmatch 校验,不符则 PBL_EXT_VALUE_INVALID',
`platform_flag` varchar(1) NOT NULL DEFAULT 'N' COMMENT 'Y=平台内置定义(此时 tenant_id 必须为 NULL字典 pbl_yes_no',
`def_status` varchar(16) NOT NULL DEFAULT 'active' COMMENT '字典 pbl_ext_def_statusdisabled 不参与校验且拒绝新值写入(历史值只读保留)',
`sort_no` int NOT NULL DEFAULT 0 COMMENT '排序号',
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
`creator_id` varchar(32) DEFAULT NULL COMMENT '创建人',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_def_code` (`tenant_key`, `def_code`),
UNIQUE KEY `uk_def_type_key` (`tenant_key`, `subobject_type`, `field_key`),
KEY `idx_def_lookup` (`tenant_key`, `def_status`, `subobject_type`, `sort_no`),
KEY `idx_def_platform` (`platform_flag`, `def_status`),
KEY `idx_def_tenant` (`tenant_id`, `subobject_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='PBL 子对象扩展字段定义表M1b扩展字段元数据字典';
-- -----------------------------------------------------------------------------
-- 3) pbl_subobject_ext —— PBL 子对象扩展表M1bEAV
-- M1a 的 pbl_bp_subobject 契约已冻结M1b 零改动 M1a 基表,
-- 扩展属性一律外挂到本表M1b-annex §7 对 M1a 在途代码零改动要求)。
-- owner_kind=blueprint → subobject_ref 取 M1a subobject_id
-- owner_kind=template → subobject_ref 取 tpl_json 内模板临时 ID
-- 实例化时由 m1b_subobject.remap_subobject_ref 重映射。
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `pbl_subobject_ext` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '物理主键 AUTO_INCREMENT',
`tenant_key` varchar(32) NOT NULL COMMENT '= COALESCE(tenant_id,''__PLATFORM__'');索引打头列;应用层计算',
`tenant_id` varchar(32) DEFAULT NULL COMMENT 'NULL = 平台公共模板的子对象扩展;非空 = 租户数据',
`ext_code` varchar(32) NOT NULL COMMENT '业务主键pbl_common.gen_code(''SXE'', tenant_id) 生成',
`owner_kind` varchar(16) NOT NULL COMMENT '字典 pbl_ext_owner_kindblueprint / template',
`owner_id` varchar(32) NOT NULL COMMENT 'owner_kind=blueprint 时为 blueprint_id=template 时为 template_code',
`owner_version` int NOT NULL DEFAULT 1 COMMENT 'blueprint→蓝图版本号template→template_version版本隔离避免跨版本串数据',
`subobject_type` varchar(32) NOT NULL COMMENT '字典 pbl_subobject_type 的 7 类之一',
`subobject_ref` varchar(64) NOT NULL COMMENT '非空归一列blueprint→M1A subobject_idtemplate→模板内临时 ID。参与唯一键杜绝 NULL 造成重复行',
`subobject_id` varchar(32) DEFAULT NULL COMMENT '冗余列owner_kind=blueprint 时与 subobject_ref 同值,便于按 M1A 子对象直查',
`ext_key` varchar(64) NOT NULL COMMENT '必须在 pbl_ext_field_def 中存在且 def_status=active',
`ext_value` longtext DEFAULT NULL COMMENT '统一字符串形态json/bool/date 按 value_type 序列化',
`value_type` varchar(16) NOT NULL DEFAULT 'string' COMMENT '写入时从 pbl_ext_field_def.value_type 快照,保证历史值可按当时类型解读;字典 pbl_ext_value_type',
`field_def_id` bigint DEFAULT NULL COMMENT '指向 pbl_ext_field_def.id逻辑关联无 FK',
`sort_no` int NOT NULL DEFAULT 0 COMMENT '排序号',
`creator_id` varchar(32) DEFAULT NULL COMMENT '创建人',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_ext_code` (`tenant_key`, `ext_code`),
UNIQUE KEY `uk_ext_slot` (`tenant_key`, `owner_kind`, `owner_id`, `owner_version`,
`subobject_type`, `subobject_ref`, `ext_key`),
KEY `idx_ext_owner` (`tenant_key`, `owner_kind`, `owner_id`, `owner_version`, `subobject_type`),
KEY `idx_ext_subobject` (`tenant_key`, `subobject_id`),
KEY `idx_ext_key` (`tenant_key`, `ext_key`),
KEY `idx_ext_tenant` (`tenant_id`, `owner_kind`, `owner_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='PBL 子对象扩展表M1bEAV 一行一键值)';
-- -----------------------------------------------------------------------------
-- 4) pbl_blueprint_ref —— PBL 蓝图外部关联表M1bQ-OPEN-3 裁决物理落地)
-- 裁决结论:『不改 world 表』(含 scene / entity / script 等复用域基表一律
-- 零改动、零加列、零回写)。蓝图与复用域对象的全部关联单向落在本表:
-- * ref_target_code 指向外部对象业务编码(逻辑关联,无 FOREIGN KEY
-- * ref_mode 恒为 'readonly',由 m1b_ref.assert_writable() 与
-- WRITE_PROTECTED_TABLES 双重闸门强制(任何针对 world/scene/entity/script
-- 的 INSERT/UPDATE/DELETE 在 SQL 执行前被拦截并抛 PBL_DB_WRITE_PROTECTED
-- * resolve_refs() 仅做只读存在性校验并把结果写回本表 ref_status
-- resolved / unresolved / invalid校验策略 strict/warn 由
-- pbl_blueprint_template.ref_policy 决定Q-OPEN-4 阈值可配);
-- * snapshot_json 保存解析时刻只读快照,避免运行期跨库联查。
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `pbl_blueprint_ref` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '物理主键 AUTO_INCREMENT',
`tenant_key` varchar(32) NOT NULL COMMENT '= COALESCE(tenant_id,''__PLATFORM__'');索引打头列;应用层计算',
`tenant_id` varchar(32) DEFAULT NULL COMMENT 'NULL = 平台公共模板携带的关联;非空 = 租户蓝图关联',
`ref_code` varchar(32) NOT NULL COMMENT '业务主键pbl_common.gen_code(''BPR'', tenant_id) 生成',
`owner_kind` varchar(16) NOT NULL DEFAULT 'blueprint' COMMENT '字典 pbl_ext_owner_kindblueprint / template',
`blueprint_id` varchar(32) NOT NULL COMMENT 'owner_kind=blueprint 时为 M1A blueprint_id=template 时复用本列存 template_code取值由 owner_kind 判定)',
`subobject_id` varchar(32) DEFAULT NULL COMMENT '关联所属的 *_ref 类子对象ID模板态存模板临时ID',
`ref_kind` varchar(16) NOT NULL COMMENT '字典 pbl_ref_kindworld / scene / entity / script',
`ref_target_code` varchar(64) NOT NULL COMMENT '复用域对象业务编码(只读引用,无 FK不反查基表写操作',
`ref_target_id` varchar(64) DEFAULT NULL COMMENT '解析成功时回填的对方物理ID快照',
`ref_mode` varchar(16) NOT NULL DEFAULT 'readonly' COMMENT '恒为 readonlyQ-OPEN-3不改 world 表,只读引用);字典 pbl_ref_mode写入非 readonly 值将被 m1b_ref 拒绝',
`ref_status` varchar(16) NOT NULL DEFAULT 'unresolved' COMMENT '字典 pbl_ref_statusunresolved 待解析 / resolved 已解析 / invalid 目标不存在或不可用',
`resolve_time` datetime DEFAULT NULL COMMENT '解析时间',
`resolve_msg` varchar(512) DEFAULT NULL COMMENT 'invalid 时记录原因,供 M2 校验与教师端提示',
`snapshot_json` text DEFAULT NULL COMMENT '解析时刻外部对象关键字段快照JSON运行期免跨库联查',
`sort_no` int NOT NULL DEFAULT 0 COMMENT '排序号',
`creator_id` varchar(32) DEFAULT NULL COMMENT '创建人',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_ref_code` (`tenant_key`, `ref_code`),
UNIQUE KEY `uk_ref_slot` (`tenant_key`, `owner_kind`, `blueprint_id`, `ref_kind`, `ref_target_code`),
KEY `idx_ref_blueprint` (`tenant_key`, `owner_kind`, `blueprint_id`, `ref_kind`),
KEY `idx_ref_target` (`tenant_key`, `ref_kind`, `ref_target_code`),
KEY `idx_ref_status` (`tenant_key`, `ref_status`),
KEY `idx_ref_tenant` (`tenant_id`, `blueprint_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='PBL 蓝图外部关联表M1bQ-OPEN-3 不改 world 表的只读关联落地)';
-- =============================================================================
-- 幂等性说明:以上 4 段均为 CREATE TABLE IF NOT EXISTS索引随表定义一并创建
-- 重复执行不报错、不产生重复索引。m1b_init.ensure_m1b_tables() 按 ';' 切分本文件
-- 逐条 sor.sqlExe(dbname, stmt) 执行(库名来自 ServerEnv().get_module_dbname
-- 本文件与本模块任何代码均不硬编码库名)。
-- =============================================================================