184 lines
16 KiB
SQL
184 lines
16 KiB
SQL
-- =============================================================================
|
||
-- 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_ref,ref_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_unresolved(Q-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_type:string/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_status;disabled 不参与校验且拒绝新值写入(历史值只读保留)',
|
||
`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 子对象扩展表(M1b,EAV)
|
||
-- 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_kind:blueprint / 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_id;template→模板内临时 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 子对象扩展表(M1b,EAV 一行一键值)';
|
||
|
||
-- -----------------------------------------------------------------------------
|
||
-- 4) pbl_blueprint_ref —— PBL 蓝图外部关联表(M1b,Q-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_kind:blueprint / 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_kind:world / 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 '恒为 readonly(Q-OPEN-3:不改 world 表,只读引用);字典 pbl_ref_mode;写入非 readonly 值将被 m1b_ref 拒绝',
|
||
`ref_status` varchar(16) NOT NULL DEFAULT 'unresolved' COMMENT '字典 pbl_ref_status:unresolved 待解析 / 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 蓝图外部关联表(M1b,Q-OPEN-3 不改 world 表的只读关联落地)';
|
||
|
||
-- =============================================================================
|
||
-- 幂等性说明:以上 4 段均为 CREATE TABLE IF NOT EXISTS,索引随表定义一并创建,
|
||
-- 重复执行不报错、不产生重复索引。m1b_init.ensure_m1b_tables() 按 ';' 切分本文件
|
||
-- 逐条 sor.sqlExe(dbname, stmt) 执行(库名来自 ServerEnv().get_module_dbname,
|
||
-- 本文件与本模块任何代码均不硬编码库名)。
|
||
-- =============================================================================
|