فهرست منبع

chore(datax): 清 generator 配套死代码——template_constants + datax_utils + mysql DDL 方法

scope 收紧版(mysql 整体作为运行时同步代码保留):
- 整文件删 dw_base/common/template_constants.py(kb/90:120 规划,
  仅 mysql_reader 那两方法用其常量)
- 整文件删 dw_base/datax/datax_utils.py(仅含 convert_mysql_column_types,
  零外部引用)
- mysql_reader.py 删 generate_hive_ddl + generate_hive_over_hbase_ddl
  两方法 + 顶部 template_constants import
- 保留 mysql_data_source / mysql_reader 整文件 / mysql_writer /
  factory mysql 分支 / MYSQL_KEYWORDS / generate_definition
  (mysql 运行时同步与 PG 同等地位,scope 收紧 vs kb/90 §2.7 老清单)
- kb/90 §2.7 标完成 + 拆除清单划掉 + 注明保留项;§1.3 行 120/121 标 ✅
- kb/92 阶段 1 datax-gc-generator 行 [x] + 加 2026-04-29 changelog
tianyu.chu 1 هفته پیش
والد
کامیت
1fea2eed97
5فایلهای تغییر یافته به همراه12 افزوده شده و 129 حذف شده
  1. 0 20
      dw_base/common/template_constants.py
  2. 0 40
      dw_base/datax/datax_utils.py
  3. 0 58
      dw_base/datax/plugins/reader/mysql_reader.py
  4. 10 10
      kb/90-重构路线.md
  5. 2 1
      kb/92-重构进度.md

+ 0 - 20
dw_base/common/template_constants.py

@@ -1,20 +0,0 @@
-#!/usr/bin/env /usr/bin/python3
-# -*- coding:utf-8 -*-
-
-
-ES_MAPPING_DDL_TEMPLATE = 'conf/template/hive/es-mapping-table-ddl-template.sql'
-HIVE_ODS_DWD_FU_TEMPLATE = 'conf/template/hive/ods-dwd-full-update-template.sql'
-HIVE_RAW_ODS_V_TEMPLATE = 'conf/template/hive/raw-ods-validate-template.sql'
-HIVE_STOCK_V_TEMPLATE = 'conf/template/hive/stock-validate-template.sql'
-MYSQL_HIVE_CREATE_TABLE_TEMPLATE = 'conf/template/hive/mysql-hive-create-table-template.sql'
-MYSQL_HIVE_HBASE_CREATE_TABLE_TEMPLATE = 'conf/template/hive/mysql-hbase-create-table-template.sql'
-SPARK_NEW_RAW_ODS_V_TEMPLATE = 'conf/template/spark/new-raw-ods-validate-template.sql'
-SPARK_ODS_DWD_FU_TEMPLATE = 'conf/template/spark/ods-dwd-full-update-template.sql'
-SPARK_DWS_ES_TEMPLATE = 'conf/template/spark/dws_es_update_repair_template.sql'
-SPARK_DWS_ES_TEMPLATE_SJT = 'conf/template/spark/dws_es_update_repair_template_sjt.sql'
-SPARK_SOP_ODS_DWD_FU_TEMPLATE = 'conf/template/spark/sop-ods-dwd-full-update-template.sql'
-SPARK_RAW_ODS_V_TEMPLATE = 'conf/template/spark/raw-ods-validat。,3e-template.sql'
-SPARK_RAW_SOP_V_TEMPLATE = 'conf/template/spark/raw-sop-template.sql'
-SPARK_STOCK_V_TEMPLATE = 'conf/template/spark/stock-validate-template.sql'
-TFC_TEMPLATE = 'conf/template/hive/tiny-file-combine-template.sql'
-SPARK_ES_QUALITY_VERIFICATION_TEMPLATE = 'conf/template/spark/es-data-quality-verification-template.sql'

+ 0 - 40
dw_base/datax/datax_utils.py

@@ -1,40 +0,0 @@
-# -*- coding:utf-8 -*-
-
-from typing import Dict, List
-
-from dw_base import NORM_GRN, NORM_YEL
-from dw_base.database.mysql_utils import MySQLColumn
-from dw_base.utils.log_utils import pretty_print
-
-
-def convert_mysql_column_types(columns: List[MySQLColumn]) -> Dict[str, str]:
-    column_types = {}
-    bool_types = ['bool', 'bit']
-    double_types = ['float', 'double']
-    string_types = ['text', 'longtext', 'mediumtext', 'time']
-    timestamp_types = ['datetime', 'timestamp']
-    for mysql_column in columns:
-        column_name = mysql_column.COLUMN_NAME
-        origin_type = mysql_column.COLUMN_TYPE
-        datax_type = None
-        if origin_type.startswith('bigint'):
-            datax_type = 'bigint'
-        elif origin_type.__contains__('int'):
-            datax_type = 'int'
-        elif timestamp_types.__contains__(origin_type):
-            datax_type = 'timestamp'
-        elif origin_type == 'date':
-            datax_type = 'date'
-        elif bool_types.__contains__(origin_type):
-            datax_type = 'boolean'
-        elif double_types.__contains__(origin_type) or origin_type.startswith('decimal'):
-            datax_type = 'double'
-        elif string_types.__contains__(origin_type) or origin_type.startswith('varchar') or origin_type.startswith(
-                'char') or origin_type.startswith('enum'):
-            # string不用管
-            pass
-        else:
-            pretty_print(f'{NORM_YEL}遇到了未处理MySQL——DataX类型映射的MySQL类型:{NORM_GRN}{origin_type}')
-        if datax_type is not None:
-            column_types[column_name] = datax_type
-    return column_types

+ 0 - 58
dw_base/datax/plugins/reader/mysql_reader.py

@@ -4,11 +4,9 @@ import re
 from configparser import ConfigParser
 from typing import Dict, List
 
-from dw_base.common.template_constants import MYSQL_HIVE_CREATE_TABLE_TEMPLATE, MYSQL_HIVE_HBASE_CREATE_TABLE_TEMPLATE
 from dw_base.datax.datax_constants import *
 from dw_base.datax.plugins.reader.reader import Reader
 from dw_base.utils.datetime_utils import local_2_utc, parse_datetime
-from dw_base.utils.file_utils import read_file_content
 
 # mysql reader
 MYSQL_READER_NAME = 'mysqlreader'
@@ -190,59 +188,3 @@ class MySQLReader(Reader):
         definition.append('utc =')
         return '\n'.join(definition)
 
-    @staticmethod
-    def generate_hive_ddl(hive_database_name: str,
-                          hive_table_name: str,
-                          table_comment: str,
-                          partitioned: bool,
-                          columns: List,
-                          column_types: Dict[str, str]) -> str:
-        columns_definition = []
-        partition_def = ''
-        for column in columns:
-            column_name = column.COLUMN_NAME
-            column_comment = column.COLUMN_COMMENT
-            if MYSQL_KEYWORDS.__contains__(column_name):
-                column_name = str(f'`{column_name}`')
-            if column_types.__contains__(column_name):
-                column_type = str(column_types[column_name]).upper()
-            else:
-                column_type = "STRING"
-            columns_definition.append(f"{column_name} {column_type} COMMENT '{column_comment}'")
-        if partitioned is not None and partitioned:
-            partition_def = '\nPARTITIONED BY (dt STRING)'
-        ddl = read_file_content(MYSQL_HIVE_CREATE_TABLE_TEMPLATE).format(
-            hive_database_name, hive_table_name, hive_database_name, hive_table_name,
-            ',\n'.join(columns_definition), table_comment, partition_def
-        )
-        return ddl
-
-    @staticmethod
-    def generate_hive_over_hbase_ddl(hive_database_name: str,
-                                     hive_table_name: str,
-                                     table_comment: str,
-                                     hbase_namespace: str,
-                                     hbase_table_name: str,
-                                     columns: List,
-                                     column_types: Dict[str, str]) -> str:
-        columns_definition = []
-        hbase_column_mapping_definition = []
-        partition_def = ''
-        for column in columns:
-            column_name = column.COLUMN_NAME
-            column_comment = column.COLUMN_COMMENT
-            if MYSQL_KEYWORDS.__contains__(column_name):
-                column_name = str(f'`{column_name}`')
-            if column_types.__contains__(column_name):
-                column_type = str(column_types[column_name]).upper()
-            else:
-                column_type = "STRING"
-            columns_definition.append(f"{column_name} {column_type} COMMENT '{column_comment}'")
-            hbase_column_mapping_definition.append(f"cf:{column_name}")
-        ddl_template = read_file_content(MYSQL_HIVE_HBASE_CREATE_TABLE_TEMPLATE)
-        ddl = ddl_template.format(
-            hive_database_name, hive_table_name, hive_database_name, hive_table_name,
-            ',\n'.join(columns_definition), table_comment, partition_def,
-            ',\n'.join(hbase_column_mapping_definition), hbase_namespace, hbase_table_name
-        )
-        return ddl

+ 10 - 10
kb/90-重构路线.md

@@ -117,8 +117,8 @@ D 基础设施 ─────┘
 | JOB_NAME / JSON 文件名的 `ini→json` 转换逻辑重复实现 | Python 侧 `bin/datax-job-config-generator.py:126`(`os.path.basename(gcf).replace('.ini', '.json')`)+ Bash 侧 `bin/datax-single-job-starter.sh:88`(`basename .ini`) | 合一到 `dw_base.datax.path_utils.job_name_from_ini()`(或类似工具);Bash 侧通过 `python3 -c` 调用或在 `bin/common/init.sh` 定义等价 shell 函数,单一来源 |
 | ini 里 `dataSource` 字段拼接环境后缀 | 老项目写法 `dataSource = pg-hobby-prod` | 改为 `dataSource = {db_type}/{env}-{实例简称}`,代码按首段斜杠判 db_type(即父目录名);source ini 落位 `datasource/{db_type}/{env}-{实例简称}.ini`,无 env 子目录。已于 2026-04-22 落地(`dw_base/datax/plugins/plugin.py:37`、`plugin_factory.py:34`) ✅ |
 | 导出类 ini 扇出撞名风险 | `jobs/ads/{域}/` 下 ini 若都以源 Hive 表名命名,同一张 ads 表扇出到多个目标库时会重名覆盖 | 命名规则改为 `{源 Hive 表名}__{目标 db_type}_{目标 instance}.ini`(双下划线分隔源/目标) |
-| `dw_base/common/template_constants.py` 大量死代码 | 定义了 20+ 个 SQL 模板路径常量,实际只有 2 个(`MYSQL_HIVE_CREATE_TABLE_TEMPLATE` / `MYSQL_HIVE_HBASE_CREATE_TABLE_TEMPLATE`)被引用,其余 18 个零 import | 整个文件删除;连带废弃下一条 |
-| `MySQLReader.generate_hive_ddl()` / `generate_hive_over_hbase_ddl()` 自动建表 DDL 路径 | `dw_base/datax/plugins/reader/mysql_reader.py:195/222`,被 `bin/datax-gc-generator.py:616/728` 调用;且 `conf/template/` 目录在新项目根本不存在,真调用会 FileNotFoundError | 整段路径废弃——与 CLAUDE.md 约定的 `manual/ddl/` 是 DDL 唯一来源相冲突。`datax-gc-generator.py` 仅生成 ini 配置,不再输出 CREATE TABLE DDL;DDL 由开发者按 `21-命名规范.md` 手写到 `manual/ddl/` |
+| `dw_base/common/template_constants.py` 大量死代码 | 定义了 20+ 个 SQL 模板路径常量,实际只有 2 个(`MYSQL_HIVE_CREATE_TABLE_TEMPLATE` / `MYSQL_HIVE_HBASE_CREATE_TABLE_TEMPLATE`)被引用,其余 18 个零 import | 整个文件删除;连带废弃下一条 ✅ 2026-04-29 整文件删 |
+| `MySQLReader.generate_hive_ddl()` / `generate_hive_over_hbase_ddl()` 自动建表 DDL 路径 | `dw_base/datax/plugins/reader/mysql_reader.py:195/222`,被 `bin/datax-gc-generator.py:616/728` 调用;且 `conf/template/` 目录在新项目根本不存在,真调用会 FileNotFoundError | 整段路径废弃——与 CLAUDE.md 约定的 `manual/ddl/` 是 DDL 唯一来源相冲突。`datax-gc-generator.py` 仅生成 ini 配置,不再输出 CREATE TABLE DDL;DDL 由开发者按 `21-命名规范.md` 手写到 `manual/ddl/` ✅ 2026-04-29 两方法删 |
 | 缺少集中的开发者参考模板目录 | —(新增) | 已建 `conf/templates/{datax/{datasource,sync},spark/{sql,ddl}}/`,模板用 `*.template.{ini,sql}` 双扩展名。与上条废弃的运行时模板完全不同:这里的模板不被任何代码读取,只供开发者对照写新文件;入口见 `kb/30-开发规范.md §6` |
 
 ### 2.2 建议的配置结构
@@ -211,7 +211,7 @@ L3   SparkSQL(...) 显式传参  +  extra_spark_config  +  命令行 -sc
 
 **第三条命令 `datax-gc-generator`(ini 元生成器)独立保留**:用户已确认。职责是"从 PG 扫 schema 生成 ini 参考模板",和"执行 ini"不是一回事,不收口到上面两条里。详见 §2.7。
 
-### 2.7 `datax-gc-generator` 从零重写(中优先级)
+### 2.7 `datax-gc-generator` 从零重写 ✅ 2026-04-29
 
 **现状**(凭查证 2026-04-18):`bin/datax-gc-generator.py` 支持 `from ∈ {mysql, hdfs}` × `to ∈ {elasticsearch, hbase, hdfs, kafka, mongo, mysql}`,覆盖面大、代码沉重,且:
 
@@ -221,7 +221,7 @@ L3   SparkSQL(...) 显式传参  +  extra_spark_config  +  命令行 -sc
 
 **定位**:**参考模板生成器**,不是"一键出可用 ini"。产物是开发者人工调整的起点 —— 常见修改包括字段剪裁(只同步用到的列)、WHERE 过滤条件、hivePartitions 配置、大表拆分策略等。开发者 diff 参考模板和自己的需求,改完再把成品 ini 提交到 `jobs/raw/{domain}/`。
 
-**方向**:整个文件废弃 + 从零重写(凭记忆:未完全定稿,待真正开始写代码时再细化
+**方向**:整个文件废弃 + 从零重写 ✅ 2026-04-29 重写为 `bin/datax-sync-template-gen.py`(PG → HDFS sync 模板生成器,全字段参考模板,pg8000 直连查 schema,-o 三态:stdout / workspace 默认 / 自定义目录
 
 **重写目标**:
 - 仅支持 `from=pg to=hdfs`
@@ -234,12 +234,12 @@ L3   SparkSQL(...) 显式传参  +  extra_spark_config  +  命令行 -sc
 - `workspace/{yyyymmdd}/` 按运行日期分子目录,便于开发者看"我今天生成了哪些候选"
 - 与 `manual/imports/{yyyymmdd}/` 的分工:`manual/imports/` 放一次性**执行**的 SQL / ini(会入仓做审计证据,执行完归档),`workspace/` 放自动化工具**未经人工确认**的中间产物(永不入仓)
 
-**拆除清单**(重写时连带删除):
-- `dw_base/database/mysql_utils.py` 的 `list_tables` / `list_columns` 方法(只服务老 generator)
-- `dw_base/datax/datasources/mysql_data_source.py`
-- `dw_base/datax/plugins/reader/mysql_reader.py` 的 `generate_hive_ddl` / `generate_hive_over_hbase_ddl` 方法
-- `dw_base/datax/datax_utils.py` 的 `convert_mysql_column_types`
-- 所有 mongo / kafka / hbase writer 在 generator 里的分支
+**拆除清单**(实际执行时 scope 收紧——mysql 整体作为运行时同步代码保留,仅删纯 generator 死代码):
+- `dw_base/database/mysql_utils.py` 的 `list_tables` / `list_columns` 方法 ✅ 整 `database/` 目录已于 2026-04-20 老业务批清理删除
+- ~~`dw_base/datax/datasources/mysql_data_source.py`~~ **保留**(mysql 同步运行时 DataSource,与 PostgreSQLDataSource 同等地位;未来 mysql 同步可能用)
+- `dw_base/datax/plugins/reader/mysql_reader.py` 的 `generate_hive_ddl` / `generate_hive_over_hbase_ddl` 方法 ✅ 2026-04-29 删
+- `dw_base/datax/datax_utils.py` 的 `convert_mysql_column_types` ✅ 2026-04-29 整文件删(零外部引用)
+- 所有 mongo / kafka / hbase writer 在 generator 里的分支 ✅ 2026-04-29 随 generator 整文件删
 
 **注意**:以上删除范围与 `dw_base/datax/plugins/` 里仍在被真实采集任务调用的 reader/writer 不冲突 —— 真实采集任务只用到 `HDFSReader` / `HDFSWriter` / `MongoWriter`(如果还有 mongo 采集任务)。删之前要用 `grep -r "from dw_base.datax.plugins.reader.mysql_reader"` 再确认一次。
 

+ 2 - 1
kb/92-重构进度.md

@@ -79,7 +79,7 @@
 - [x] **DataX 入口收口为两条命令**(暂称 `datax-import` / `datax-export`,**命名待确认**;见 `90-重构路线.md` §2.6)
 - [x] 导入命令实现分区管理(`-skip-exist` / `-force-overwrite` / `-skip-partitions`)
 - [x] 导出命令实现源 HDFS 路径探测(`-src-check` / `-skip-missing`)
-- [ ] `bin/datax-gc-generator.py` 从零重写:定位为**参考模板生成器**(`from=pg to=hdfs`,输出到开发者本地 `workspace/{yyyymmdd}/{name}.ini`,该目录被 `.gitignore` 排除、不入仓;开发者裁剪后把成品提交到 `jobs/raw/{domain}/`),不再生成 DDL(见 `90-重构路线.md` §2.7)
+- [x] `bin/datax-gc-generator.py` 从零重写为 `bin/datax-sync-template-gen.py`(2026-04-29):PG→HDFS sync 模板生成器,pg8000 直连查 schema,全字段 column + auto-detect 单字段 PK + where 用 update_time + writer.path 用源表名 _TODO_d 占位 + -o 三态(stdout / workspace 默认 / 自定义);配套删 `template_constants.py` + `datax_utils.py` 整文件 + `MySQLReader.generate_hive_ddl/_over_hbase_ddl` 两方法;`mysql_data_source.py` 等 mysql 运行时同步代码保留(见 `90-重构路线.md` §2.7)
 - [x] `.gitignore` 增加 `workspace/` 行(见 `90-重构路线.md` §2.4 清单)
 - [x] 废弃并删除 `mysql_utils`/`MySQLDataSource`/`MySQLReader.generate_hive_ddl*`/`convert_mysql_column_types`(见 §2.7 拆除清单)
 - [x] **HDFS HA 自检(前置决策)**:2026-04-18 新 CDH 环境实测:`HADOOP_CONF_DIR` 未设 + `/opt/datax` 无预置 hdfs-site.xml;手动 `export HADOOP_CONF_DIR=/etc/hadoop/conf` 后跑 DataX 仍 `UnknownHostException: nameservice1`。结论:`HADOOP_CONF_DIR` 对 DataX 无效(`datax.py` 不把 conf 目录入 classpath),**锁定走 Path B**
@@ -198,3 +198,4 @@
 | 2026-04-23 | **工作 3 批次 5 收官:删老 DataX 脚本 + kb 整理(工作 3 整体 ✅)**:新增 `dw_base/datax/cli.py`(`python -m dw_base.datax.cli gen-json` 子命令,内部调 `JobConfigGenerator`)+ 3 条单测;`runner.py` 的 gen 调用从 `bin/datax-job-config-generator.py` 切到 `-m dw_base.datax.cli gen-json`;删 7 个老文件(`bin/datax-{single,multiple,multiple-hive}-job-starter.{sh,py}` + `bin/datax-job-config-generator.py`);顺带清 `dw_base/datax/plugins/plugin.py:4` 死 `import pwd`(Windows 单测 import 阻塞)。联动 kb/90 §2.6 标 ✅(retention 规则保留正文),kb/91 §4.3 老脚本使用说明整段删、保留 §4.4 老分发/日志查证档案给 kb/93 ADR-02 做背景。整套单测 46 条全过。至此工作 3 六批次(批次 0-5)全部完成:术语 memory / §2.6 压缩 → workers 外配 → 冒烟 1 → 脱敏配置化插入 → 工作 3 三聚簇 → 新入口 → 冒烟 2 ✅ → 删老 | — |
 | 2026-04-23 | **工作 3(DataX 改造)完整 E2E 收官**:两条链路端到端验证全部通过。hive-import:PG `public.app_user_cert_info` → Hive `test.raw_usr_app_user_cert_info_inc_d`,62 行数据带 `cert_birthday` `month_trunc` 脱敏生效(源 PG 端 `TO_CHAR` 执行、敏感原值不出业务库)。hdfs-export:Hive raw → PG `test.ads_usr_app_user_cert_info_export`,62 行原样回写、PG 侧 count 一致。新入口 `bin/datax-{hive-import,hdfs-export}-starter.{sh,py}` 接管全部 DataX 调度入口;老 7 脚本已删;`dw_base/datax/` 7 模块(path_utils / worker / partition / runner / batch / entry / cli / mask) + 47 单测。冒烟过程暴露 + 顺手修的 bug:`plugin.py` 死 import pwd、`postgresql_reader` querySql 需 List 格式、`postgresql_writer` writeMode 字段误留(DataX pg writer 不支持)、`runner` PYTHONPATH 注入与远端 cd、`entry` ini 相对路径按 `base_dir` 解析不靠 cwd、`mysql_reader` 残留 import 已删包。插入项并行落地:脱敏配置化(mask 模块 + `[mask]` 声明式 + `kb/90 §2.6` 高优先级标 ✅) + `kb/93` ADR-01/02/03 草案(补数 / 分布式 / 零点漂移) + `kb/94` 新建重构对比文档(首节 DataX 22 项) + `CLAUDE.md` 加 agent commit 后自动 sync 约定。memory 新沉淀 2 条(术语纪律 / 验证前不删) | — |
 | 2026-04-28 | **kb/20 §5.5 整节改写 + §7 并入 inbox 分层分区语义 + §21 + §7.1 配套修正**:(a) §5.5 老"合 vs 拆"二分(含 acc 拼团/订单举例)整节重写为"事件 vs 状态"框架——DWD 默认 `_apd_d` 事件,实体状态进 DIM `_zip_d` 拉链,循环状态机天然支持;末尾留"何时可考虑 acc"小节给固定线性里程碑场景留口子(commits c9b58ba + e3761c2)。(b) `kb/inbox/关于分层的分区语义.md` 整篇并入 §7 新增 §7.2 各层分区语义、§7.3 各层职责与设计要点、§7.4 6 条分区与建模设计原则;inbox 原文保留不删(commit e575250)。(c) 配套 cascading 修正:`kb/21 §2.2` acc 表行加默认 event+zip 标注 + 链 §5.5、zip vs acc 选择依据保留思路并加"暂时默认 zip 路线"标注、删"状态机用 acc"一句、循环 fallback 从 "inc 主表 + apd 流水" 改齐为 "apd 事件 + DIM zip";`kb/21 §3.4` dwd 快照类型表删 "里程碑→acc" 行、加 "严格不循环固定线性里程碑→acc" + 链 §5.5,示例删 `dwd_trd_group_buy_acc_d`、`dwd_trd_order_pay_inc_d` 改 `_apd_d`、加订单履约事件示例;`kb/20 §7.1` 拼团 DWD 快照策略改为 "事件 _apd_d + DIM _zip_d 组合"。**未在本批**:CLAUDE.md 不加 acc 禁用锚定(acc 看情况评估,非禁用) | — |
+| 2026-04-29 | **`datax-gc-generator` 从零重写为 `datax-sync-template-gen`(kb/90 §2.7 完成)**:(a) 老 798 行 `bin/datax-gc-generator.py` 整文件删(mysql 链路 + 6 种 from × to 组合,全项目零外部引用);(b) 新 `bin/datax-sync-template-gen.py`(200+ 行)—— 仅 PG → HDFS,按 sync ini `dataSource` 字段格式 `postgresql/{env}-{instance}` 走 `../datasource/{ref}.ini`,复用 `DataSourceFactory` + `PostgreSQLDataSource` 拿 jdbc/user/pwd,pg8000 直连查 `pg_catalog.pg_attribute` 拿全字段 + 注释,查 `pg_index` 单字段 PK,渲染 sync ini 模板(全字段 column / where 用 update_time / writer.path 用源表名 `_TODO_d` 占位 / `-o` nargs='?' 三态:不传 stdout / 不带值 `workspace/{yyyymmdd}/` / 带值自定义);(c) `requirements.txt` 加 `pg8000~=1.30`;(d) 单测 `tests/unit/datax/test_sync_template_gen.py` 9 条覆盖渲染 + JDBC 解析 + PK auto-detect 边界(mock conn);(e) 配套死代码清理(kb/90 §2.7 拆除清单 scope 收紧):`dw_base/datax/datax_utils.py` + `dw_base/common/template_constants.py` 两整文件删(零外部引用),`mysql_reader.py` 删 `generate_hive_ddl` + `generate_hive_over_hbase_ddl` 两方法 + 顶部 `template_constants` import;**保留**:`mysql_data_source.py` / `mysql_reader.py` 整文件 / `mysql_writer.py` / `data_source_factory.py` mysql 分支 / `plugin_factory.py` mysql 分支 / `MYSQL_KEYWORDS` / `generate_definition`(mysql 运行时同步代码,与 PG 同等地位,未来 mysql 同步可能用,scope 收紧 vs 老拆除清单) | — |