跳转至

数据库迁移1 --- 将MySQL的数据迁移至金仓

一. 环境准备

主机名 IP地址 服务器配置 数据库 端口
Rocky7 192.168.100.106 2C2G MySql 3306
OE2 192.168.100.110 4C4G 金仓 54321

二. 在Rocky7上安装MySQL数据库

0. 事先准备

# 设置服务器名称
hostnamectl set-hostname Rocky7
# 关闭防火墙
systemctl disable --now firewalld
# 关闭selinux并永久生效
setenforce 0
# 永久生效(改配置文件,重启后仍生效)
sed -i 's/^SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config
# 安装依赖
dnf -y install cmake make gcc gcc-c++ bison libaio libaio-devel rpcgen ncurses ncurses-devel openssl openssl-devel wget

1. 安装MySQL

1) 从官网下载mysql-8.4.10

wget https://dev.mysql.com/get/Downloads/MySQL-8.4/mysql-8.4.10-linux-glibc2.28-x86_64.tar.xz

2) 解压到/usr/local

tar -xf mysql-8.4.10-linux-glibc2.28-x86_64.tar.xz -C /usr/local
mv /usr/local/mysql-8.4.10-linux-glibc2.28-x86_64 /usr/local/mysql

3) 创建mysql用户与同名组

groupadd -r mysql
useradd -r -M -g mysql -s /bin/false mysql

4) 创建存放MySQL的数据和日志目录,然后修改目录权限

mkdir -p /data/mysql/{data,log}
chown -R mysql.mysql /data/mysql
chown -R mysql:mysql /usr/local/mysql/

5) 编写配置文件my.cnf

vi /etc/my.cnf
[client]
socket = /usr/local/mysql/mysql.sock        

[mysqld]
server_id=10
port = 3306
user = mysql
character-set-server = utf8mb4
default_storage_engine = innodb
log_timestamps = SYSTEM
socket = /usr/local/mysql/mysql.sock
basedir = /usr/local/mysql
datadir = /data/mysql/data
pid-file = /usr/local/mysql/mysql.pid
log_error = /data/mysql/log/mysql-error.log
sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'
skip-name-resolve

6) 初始化数据库

/usr/local/mysql/bin/mysqld \
  --initialize-insecure \
  --user=mysql \
  --basedir=/usr/local/mysql \
  --datadir=/data/mysql/data

7) 查看验证

[root@Rocky7 ~]# ls /data/mysql/data
 auto.cnf          client-key.pem       ibdata1         mysql.ibd               public_key.pem    undo_001
 ca-key.pem       '#ib_16384_0.dblwr'  '#innodb_redo'   mysql_upgrade_history   server-cert.pem   undo_002
 ca.pem           '#ib_16384_1.dblwr'  '#innodb_temp'   performance_schema      server-key.pem
 client-cert.pem   ib_buffer_pool       mysql           private_key.pem         sys
[root@Rocky7 ~]# ls /data/mysql/log
mysql-error.log

8) 写systemd启动服务

vi /lib/systemd/system/mysqld.service
[Unit]
Description=MySQL Server
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/mysql/bin/mysqld  --defaults-file=/etc/my.cnf
User=mysql
Group=mysql
TimeoutSec=300
PrivateTmp=true

[Install]
WantedBy=multi-user.target

9) 重载后启动服务,然后设置开机自动启动并验证

systemctl daemon-reload
systemctl start mysqld
systemctl enable mysqld
[root@Rocky7 ~]# ss -tuanp|grep mysql
tcp   LISTEN 0      70                   *:33060               *:*     users:(("mysqld",pid=1443,fd=18))                    
tcp   LISTEN 0      151                  *:3306                *:*     users:(("mysqld",pid=1443,fd=20))                    
[root@Rocky7 ~]# systemctl status mysqld
● mysqld.service - MySQL Server
     Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; preset: disabled)
     Active: active (running) since Tue 2026-09-15 08:39:46 CST; 3min 28s ago
   Main PID: 1443 (mysqld)
      Tasks: 34 (limit: 10844)
     Memory: 434.5M
        CPU: 2.219s
     CGroup: /system.slice/mysqld.service
             └─1443 /usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf

9月 15 08:39:46 Rocky7 systemd[1]: Started MySQL Server.

10) 配置环境变量

echo "export PATH=/usr/local/mysql/bin:$PATH">>/etc/profile.d/mysql.sh
#配置环境变量
source /etc/profile               #让环境变量生效

三. 在欧拉上安装金仓数据库

注: 国产数据库占用较大,建议改成4核4G

0. 环境准备

# 设置服务器名称
hostnamectl set-hostname OE2
# 关闭防火墙
systemctl disable --now firewalld
# 关闭selinux并永久生效
setenforce 0
# 永久生效(改配置文件,重启后仍生效)
sed -i 's/^SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config
# RemoveIPC=no
sed -i 's/^#RemoveIPC=no/RemoveIPC=no/' /etc/systemd/logind.conf
systemctl restart systemd-logind
# 修改文件句柄数
cat >> /etc/security/limits.conf <<'EOF'
kingbase soft nofile 65536
kingbase hard nofile 65536
kingbase soft nproc  65536
kingbase hard nproc  65536
EOF
# 修改内核参数
cat >> /etc/sysctl.conf <<'EOF'
vm.swappiness = 10
fs.aio-max-nr = 1048576
EOF
sysctl -p

1. 安装金仓

1) 下载数据库

官网的数据库需要输入个人信息,不能直接wget拉,这里我们就提前下好传过来了

alt textalt text

[root@OE2 ~]# ls -lh
总计 176M
-rw-------. 1 root root 1.1K  9月14日 17:33 anaconda-ks.cfg
-rw-r--r--. 1 root root 176M  9月15日 09:17 KingbaseES-Server-V009R002-C016B0006.x86_64.rpm
# .rpm结尾的就是我们所需要的数据库

2) 安装

[root@OE2 ~]# ls
anaconda-ks.cfg  KingbaseES-Server-V009R002-C016B0006.x86_64.rpm
[root@OE2 ~]# rpm -ivh KingbaseES-Server-V009R002-C016B0006.x86_64.rpm 
Verifying...                          ################################# [100%]
准备中...                          ################################# [100%]
Locale zh_CN.UTF-8 exist.
block size is 8k.
正在升级/安装...
   1:KingbaseES-Server-1:V009R002-C016################################# [100%]
数据库簇将使用本地化语言 "zh_CN.UTF-8"进行初始化.
属于此数据库系统的文件宿主为用户 "kingbase".
此用户也必须为服务器进程的宿主.
initdb: could not find suitable text search configuration for locale "zh_CN.UTF-8"
缺省的文本搜索配置将会被设置到"simple"

字符串的比较区分大小写.
禁止为数据页生成校验和.

创建目录 /opt/Kingbase/ES/Server/data ... 成功
正在创建子目录 ... 成功
选择动态共享内存实现 ......posix
选择默认最大连接数 (max_connections) ... 100
选择默认共享缓冲区大小 (shared_buffers) ... 128MB
选择默认时区...Asia/Shanghai
创建配置文件 ... 成功
开始设置加密设备
正在初始化加密设备...成功
开始初始化撤销子系统元数据
初始化撤销子系统元数据 ... 成功
正在运行自举脚本 ...成功
正在执行自举后初始化 ...成功
创建安全数据库...成功
加载安全数据库...成功
同步数据到磁盘...成功

成功。您现在可以用下面的命令开启数据库服务器:

    /opt/Kingbase/ES/Server/bin/sys_ctl -D /opt/Kingbase/ES/Server/data -l 日志文件 start

Using the following command can start the Kingbase system service: 
    systemctl enable kingbased.service
    systemctl start kingbased.service

2. 启动服务并设置开机自启动

systemctl daemon-reload
systemctl enable --now kingbased.service

验证

[root@OE2 ~]# systemctl status kingbased --no-pager | head -10
● kingbased.service - KingbaseES Service
     Loaded: loaded (/usr/lib/systemd/system/kingbased.service; enabled; preset: disabled)
     Active: active (running) since Tue 2026-09-15 09:26:52 CST; 58s ago
    Process: 2863 ExecStart=/opt/Kingbase/ES/Server/bin/sys_ctl start -D /opt/Kingbase/ES/Server/data -l /opt/Kingbase/ES/Server/data/startup.log (code=exited, status=0/SUCCESS)
   Main PID: 2865 (kingbase)
      Tasks: 13 (limit: 21362)
     Memory: 483.6M ()
     CGroup: /system.slice/kingbased.service
             ├─2865 /opt/Kingbase/ES/Server/bin/kingbase -D /opt/Kingbase/ES/Server/data
             ├─2867 "kingbase: logger   "
[root@OE2 ~]# ss -tlnp | grep 54321
LISTEN 0      324          0.0.0.0:54321      0.0.0.0:*    users:(("kingbase",pid=2865,fd=17))
LISTEN 0      324             [::]:54321         [::]:*    users:(("kingbase",pid=2865,fd=18))

3. 连接数据库

[root@OE2 ~]# su - kingbase
上一次登录: 2026年09月15日 星期二 09:17:57 CST


Welcome to 6.6.0-98.0.0.103.oe2403sp2.x86_64

System information as of time:  2026年 09月 15日 星期二 09:29:17 CST

System load:    0.00
Memory used:    9.8%
Swap used:      0%
Usage On:       8%
IP address:     192.168.100.110
Users online:   2
To run a command as administrator(user "root"),use "sudo <command>".
[kingbase@OE2 ~]$ /opt/Kingbase/ES/Server/bin/ksql -U system -l -p 54321
用户 system 的口令:12345678ab
                                  数据库列表
   名称    | 拥有者 | 字元编码 |  校对规则   |    Ct
ype    |     存取权限      
-----------+--------+----------+-------------+------
-------+-------------------
 kingbase  | system | UTF8     | zh_CN.UTF-8 | zh_CN
.UTF-8 | 
 security  | system | UTF8     | zh_CN.UTF-8 | zh_CN
.UTF-8 | 
 template0 | system | UTF8     | zh_CN.UTF-8 | zh_CN
.UTF-8 | =c/system        +
           |        |          |             |      
       | system=CTc/system
 template1 | system | UTF8     | zh_CN.UTF-8 | zh_CN
.UTF-8 | =c/system        +
           |        |          |             |      
       | system=CTc/system
 test      | system | UTF8     | zh_CN.UTF-8 | zh_CN
.UTF-8 | 
(5 行记录)
# 列出库之后进默认库:
[kingbase@OE2 ~]$ /opt/Kingbase/ES/Server/bin/ksql -U system -d test -p 54321
用户 system 的口令:
授权类型: 企业版.
输入 "help" 来获取帮助信息.

test=# 

4. 设置数据库

-- 先改口令
test=# ALTER USER system WITH PASSWORD 'Kingbase@2026';
ALTER ROLE
-- 确认迁移相关事项
test=# SELECT version();
         version         
-------------------------
 KingbaseES V009R002C016
(1 行记录)

test=# SHOW server_encoding;
 server_encoding 
-----------------
 UTF8
(1 行记录)

test=# SELECT name, setting FROM sys_settings WHERE name LIKE '%mode%';                     
          name          |            setting             
------------------------+--------------------------------
 archive_mode           | always
 copy_mode              | kes
 data_directory_mode    | 0700
 database_mode          | oracle
 force_parallel_mode    | off
 log_file_mode          | 0600
 pg_enable_param_mode   | off
 plan_cache_mode        | auto
 simple_plan_cache_mode | off
 sql_mode               | ONLY_FULL_GROUP_BY,ANSI_QUOTES
(10 行记录)
项目 结果 判断
版本 KingbaseES V009R002C016 ✅ 就是 V9R2
server_encoding UTF8 ✅ 中文迁移的前提满足
database_mode oracle ✅ 与预期一致(rpm 默认值)
口令 已改成 Kingbase@2026 ✅ 默认口令隐患已消除

5. 建目标库与用户

test=# -CREATE USER migadm WITH PASSWORD 'Mig@2026' LOGIN;
CREATE ROLE
test=# CREATE DATABASE shop OWNER migadm;
CREATE DATABASE
test=# \l                                                                                                                                                                
                                  数据库列表
   名称    | 拥有者 | 字元编码 |  校对规则   |    Ctype    |     存取权限      
-----------+--------+----------+-------------+-------------+-------------------
 kingbase  | system | UTF8     | zh_CN.UTF-8 | zh_CN.UTF-8 | 
 security  | system | UTF8     | zh_CN.UTF-8 | zh_CN.UTF-8 | 
 shop      | migadm | UTF8     | zh_CN.UTF-8 | zh_CN.UTF-8 | 
 template0 | system | UTF8     | zh_CN.UTF-8 | zh_CN.UTF-8 | =c/system        +
           |        |          |             |             | system=CTc/system
 template1 | system | UTF8     | zh_CN.UTF-8 | zh_CN.UTF-8 | =c/system        +
           |        |          |             |             | system=CTc/system
 test      | system | UTF8     | zh_CN.UTF-8 | zh_CN.UTF-8 | 
(6 行记录)

6. 兼容性探针

# 写用于探测的文件
cat > /tmp/probe.sql <<'EOF'
-- ============================================================
-- MySQL → 金仓(KingbaseES V9R2) 兼容性探针 v2(合并修正版)
-- 用法:ksql -U system -d probe_db -p 54321 -f /tmp/probe.sql 2>&1 | tee /tmp/probe_result.txt
--
-- v2 相对 v1 的四处修正:
--   1) 每个建表前加 DROP TABLE IF EXISTS → 可重复执行(v1 重跑报"关系已存在")
--   2) 探针 6 改用【可空列】,并分两次测:默认参数 / 关闭 ora_input_emptystr_isnull 后
--      (v1 用 NOT NULL 列,插入被拦住,只能靠报错间接证明)
--   3) 顺序重排:默认状态的测试全部前置,改参数的补救实验全部后置
--      (v1 里探针 9 关掉 sql_mode 后恢复失败,污染了后面 12a 的前提)
--   4) 新增探针 20~24:内联 KEY / UNIQUE KEY / FOREIGN KEY、SET NAMES、
--      USING BTREE、DISABLE KEYS、INSERT 里的反引号(都是 mysqldump 常见写法)
-- ============================================================

\echo ''
\echo '########## 第 0 部分:基线快照 ##########'
SELECT version() AS 版本;
SHOW server_encoding;
SHOW sql_mode;
SHOW ora_input_emptystr_isnull;

\echo ''
\echo '########## 第 1 部分:默认状态下的语法兼容性 ##########'

\echo ''
\echo '===== 1. 反引号标识符 ====='
DROP TABLE IF EXISTS p1;
CREATE TABLE p1 (`id` int, `name` varchar(20));

\echo ''
\echo '===== 2. AUTO_INCREMENT ====='
DROP TABLE IF EXISTS p2;
CREATE TABLE p2 (id int AUTO_INCREMENT PRIMARY KEY, name varchar(20));

\echo ''
\echo '===== 3. 建表尾缀 ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ====='
DROP TABLE IF EXISTS p3;
CREATE TABLE p3 (id int) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

\echo ''
\echo '===== 4a. 类型 tinyint ====='
DROP TABLE IF EXISTS p4a;
CREATE TABLE p4a (a tinyint);

\echo ''
\echo '===== 4b. 类型 int unsigned ====='
DROP TABLE IF EXISTS p4b;
CREATE TABLE p4b (b int unsigned);

\echo ''
\echo '===== 4c. 类型 datetime ====='
DROP TABLE IF EXISTS p4c;
CREATE TABLE p4c (c datetime);

\echo ''
\echo '===== 4d. 类型 text ====='
DROP TABLE IF EXISTS p4d;
CREATE TABLE p4d (d text);

\echo ''
\echo '===== 4e. 类型 double(10,2) ====='
DROP TABLE IF EXISTS p4e;
CREATE TABLE p4e (e double(10,2));

\echo ''
\echo '===== 5. LIMIT offset,count(MySQL 逗号写法)====='
SELECT * FROM p2 LIMIT 0,10;

\echo ''
\echo '===== 6a. 空串写入【可空列】(默认 ora_input_emptystr_isnull)====='
DROP TABLE IF EXISTS p6;
CREATE TABLE p6 (id int, v varchar(10));
INSERT INTO p6 VALUES (1, '');
SELECT count(*) AS 总行数 FROM p6;
SELECT count(*) AS 空串匹配数 FROM p6 WHERE v = '';
SELECT count(*) AS IS_NULL匹配数 FROM p6 WHERE v IS NULL;
SELECT id, v IS NULL AS 是否为NULL FROM p6;

\echo ''
\echo '===== 7. GROUP BY 宽松写法(默认 sql_mode 严格性)====='
DROP TABLE IF EXISTS p7;
CREATE TABLE p7 (dept varchar(10), name varchar(10));
INSERT INTO p7 VALUES ('a','x'),('a','y');
SELECT dept, name FROM p7 GROUP BY dept;

\echo ''
\echo '===== 8. MySQL 常用函数 IFNULL / NOW / CONCAT ====='
SELECT IFNULL(NULL,'x') AS ifnull结果, NOW() AS now结果, CONCAT('a','b') AS concat结果;

\echo ''
\echo '===== 10. MySQL 专属命令 SHOW TABLES / DESC ====='
SHOW TABLES;
DESC p7;

\echo ''
\echo '===== 11. INSERT ... ON DUPLICATE KEY UPDATE ====='
DROP TABLE IF EXISTS p11;
CREATE TABLE p11 (id int PRIMARY KEY, v varchar(10));
INSERT INTO p11 VALUES (1,'a');
INSERT INTO p11 VALUES (1,'b') ON DUPLICATE KEY UPDATE v='b';
SELECT * FROM p11;

\echo ''
\echo '===== 12a. 双引号语义(默认 sql_mode:ANSI_QUOTES 开启态)====='
SELECT "name" FROM p7;

\echo ''
\echo '===== 13. DEFAULT CHARSET=utf8mb4 + 中文存取 ====='
DROP TABLE IF EXISTS p13;
CREATE TABLE p13 (v varchar(20)) DEFAULT CHARSET=utf8mb4;
INSERT INTO p13 VALUES ('中文测试');
SELECT * FROM p13;

\echo ''
\echo '===== 14. COLLATE 子句 ====='
DROP TABLE IF EXISTS p14;
CREATE TABLE p14 (v varchar(20) COLLATE utf8mb4_unicode_ci);

\echo ''
\echo '===== 15. 建表尾缀 ENGINE=InnoDB AUTO_INCREMENT=100 ====='
DROP TABLE IF EXISTS p15;
CREATE TABLE p15 (id int AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB AUTO_INCREMENT=100;

\echo ''
\echo '===== 16. LOCK TABLES / UNLOCK TABLES ====='
LOCK TABLES p7 WRITE;
UNLOCK TABLES;

\echo ''
\echo '===== 17. SET @@SESSION.SQL_MODE ====='
SET @@SESSION.SQL_MODE = 'ONLY_FULL_GROUP_BY';

\echo ''
\echo '===== 18. MySQL 条件注释 /*!40101 SET NAMES utf8mb4 */ ====='
/*!40101 SET NAMES utf8mb4 */;

\echo ''
\echo '===== 19. 反引号 + 库名限定 ====='
SELECT * FROM `p7`;

\echo ''
\echo '===== 20a. 内联 KEY(普通索引)====='
DROP TABLE IF EXISTS q20a;
CREATE TABLE q20a (id int, cat_id int, KEY idx_cat (cat_id));

\echo ''
\echo '===== 20b. 内联 UNIQUE KEY ====='
DROP TABLE IF EXISTS q20b;
CREATE TABLE q20b (id int, code varchar(10), UNIQUE KEY uk_code (code));

\echo ''
\echo '===== 20c. 内联 CONSTRAINT FOREIGN KEY ====='
DROP TABLE IF EXISTS q20c;
CREATE TABLE q20c (id int, cat_id int, CONSTRAINT fk_cat FOREIGN KEY (cat_id) REFERENCES p2 (id));

\echo ''
\echo '===== 20d. NOT NULL + AUTO_INCREMENT + PRIMARY KEY 组合 ====='
DROP TABLE IF EXISTS q20d;
CREATE TABLE q20d (id int NOT NULL AUTO_INCREMENT, name varchar(20), PRIMARY KEY (id));

\echo ''
\echo '===== 21. SET NAMES utf8mb4 ====='
SET NAMES utf8mb4;

\echo ''
\echo '===== 22. 索引 USING BTREE ====='
DROP TABLE IF EXISTS q22;
CREATE TABLE q22 (id int, v varchar(10), KEY idx_v (v) USING BTREE);

\echo ''
\echo '===== 23. ALTER TABLE DISABLE KEYS / ENABLE KEYS ====='
ALTER TABLE q22 DISABLE KEYS;
ALTER TABLE q22 ENABLE KEYS;

\echo ''
\echo '===== 24. INSERT 语句里的反引号 ====='
INSERT INTO `p2` (`id`,`name`) VALUES (1,'x');

\echo ''
\echo '########## 第 2 部分:补救方案实验(会改参数,故放在最后)##########'

\echo ''
\echo '===== 6b. 关闭 ora_input_emptystr_isnull 后重试空串(验证补救方案)====='
SET ora_input_emptystr_isnull = off;
SHOW ora_input_emptystr_isnull;
DELETE FROM p6;
INSERT INTO p6 VALUES (2, '');
SELECT count(*) AS 空串匹配数 FROM p6 WHERE v = '';
SELECT count(*) AS IS_NULL匹配数 FROM p6 WHERE v IS NULL;
SELECT id, v IS NULL AS 是否为NULL FROM p6;

\echo ''
\echo '===== 9a. 关闭 sql_mode 后重试宽松 GROUP BY(验证逃生门)====='
SET sql_mode = '';
SELECT dept, name FROM p7 GROUP BY dept;
SHOW sql_mode;

\echo ''
\echo '===== 9b-1. sql_mode 合法取值(enumvals)====='
SELECT name, setting, enumvals FROM sys_settings WHERE name = 'sql_mode';

\echo ''
\echo '===== 9b-2. 单值设置语法 ====='
SET sql_mode = 'ONLY_FULL_GROUP_BY';
SHOW sql_mode;

\echo ''
\echo '===== 9b-3. TO 语法 ====='
SET sql_mode TO 'ANSI_QUOTES';
SHOW sql_mode;

\echo ''
\echo '===== 9b-4. RESET 恢复默认 ====='
RESET sql_mode;
SHOW sql_mode;

\echo ''
\echo '===== 12b. 关闭 ANSI_QUOTES 后双引号语义(与 12a 对比)====='
SET sql_mode = '';
SELECT "name" FROM p7;

\echo ''
\echo '===== 探针 v2 结束:请保存上面全部输出 ====='
EOF
# 先建探针库(用 system 超级用户)
su - kingbase
# 然后执行探针
/opt/Kingbase/ES/Server/bin/ksql -U system -d probe_db -p 54321 -f /tmp/probe.sql 2>&1 | tee /tmp/probe_result.txt
[root@OE2 ~]# cat /tmp/probe_result.txt

########## 第 0 部分:基线快照 ##########
          版本           
-------------------------
 KingbaseES V009R002C016
(1 行记录)

 server_encoding 
-----------------
 UTF8
(1 行记录)

            sql_mode            
--------------------------------
 ONLY_FULL_GROUP_BY,ANSI_QUOTES
(1 行记录)

 ora_input_emptystr_isnull 
---------------------------
 on
(1 行记录)


########## 第 1 部分:默认状态下的语法兼容性 ##########

===== 1. 反引号标识符 =====
ksql:/tmp/probe.sql:27: NOTICE:  table "p1" does not exist, skipping
DROP TABLE
ksql:/tmp/probe.sql:28: ERROR:  语法错误 在 "`" 或附近的
第1行CREATE TABLE p1 (`id` int, `name` varchar(20));
                      ^

===== 2. AUTO_INCREMENT =====
DROP TABLE
CREATE TABLE

===== 3. 建表尾缀 ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 =====
ksql:/tmp/probe.sql:37: NOTICE:  table "p3" does not exist, skipping
DROP TABLE
ksql:/tmp/probe.sql:38: ERROR:  语法错误 在 "ENGINE" 或附近的
第1行CREATE TABLE p3 (id int) ENGINE=InnoDB DEFAULT CHARSET=utf8m...
                              ^

===== 4a. 类型 tinyint =====
DROP TABLE
CREATE TABLE

===== 4b. 类型 int unsigned =====
ksql:/tmp/probe.sql:47: NOTICE:  table "p4b" does not exist, skipping
DROP TABLE
ksql:/tmp/probe.sql:48: ERROR:  语法错误 在 "unsigned" 或附近的
第1行CREATE TABLE p4b (b int unsigned);
                             ^

===== 4c. 类型 datetime =====
DROP TABLE
CREATE TABLE

===== 4d. 类型 text =====
DROP TABLE
CREATE TABLE

===== 4e. 类型 double(10,2) =====
ksql:/tmp/probe.sql:62: NOTICE:  table "p4e" does not exist, skipping
DROP TABLE
ksql:/tmp/probe.sql:63: ERROR:  语法错误 在 "(" 或附近的
第1行CREATE TABLE p4e (e double(10,2));
                               ^

===== 5. LIMIT offset,count(MySQL 逗号写法)=====
 id | name 
----+------
(0 行记录)


===== 6a. 空串写入【可空列】(默认 ora_input_emptystr_isnull)=====
DROP TABLE
CREATE TABLE
INSERT 0 1
 总行数 
--------
      1
(1 行记录)

 空串匹配数 
------------
          0
(1 行记录)

 is_null匹配数 
---------------
             1
(1 行记录)

 id | 是否为null 
----+------------
  1 | t
(1 行记录)


===== 7. GROUP BY 宽松写法(默认 sql_mode 严格性)=====
DROP TABLE
CREATE TABLE
INSERT 0 2
ksql:/tmp/probe.sql:84: ERROR:  字段 "p7.name" 必须出现在 GROUP BY 子句中或者在聚合函数中使用
第1行SELECT dept, name FROM p7 GROUP BY dept;
                  ^

===== 8. MySQL 常用函数 IFNULL / NOW / CONCAT =====
 ifnull结果 |            now结果            | concat结果 
------------+-------------------------------+------------
 x          | 2026-09-15 10:25:01.107064+08 | ab
(1 行记录)


===== 10. MySQL 专属命令 SHOW TABLES / DESC =====
ksql:/tmp/probe.sql:92: ERROR:  unrecognized configuration parameter "tables"
ksql:/tmp/probe.sql:93: ERROR:  语法错误 在 "DESC" 或附近的
第1行DESC p7;
     ^

===== 11. INSERT ... ON DUPLICATE KEY UPDATE =====
DROP TABLE
CREATE TABLE
INSERT 0 1
ksql:/tmp/probe.sql:100: 警告:  当前数据库模式建议使用on conflict子句
INSERT 0 1
 id | v 
----+---
  1 | b
(1 行记录)


===== 12a. 双引号语义(默认 sql_mode:ANSI_QUOTES 开启态)=====
 name 
------
 x
 y
(2 行记录)


===== 13. DEFAULT CHARSET=utf8mb4 + 中文存取 =====
ksql:/tmp/probe.sql:109: NOTICE:  table "p13" does not exist, skipping
DROP TABLE
ksql:/tmp/probe.sql:110: ERROR:  语法错误 在 "DEFAULT" 或附近的
第1行CREATE TABLE p13 (v varchar(20)) DEFAULT CHARSET=utf8mb4;
                                      ^
ksql:/tmp/probe.sql:111: ERROR:  关系 "p13" 不存在
第1行INSERT INTO p13 VALUES ('中文测试');
                 ^
ksql:/tmp/probe.sql:112: ERROR:  关系 "p13" 不存在
第1行SELECT * FROM p13;
                   ^

===== 14. COLLATE 子句 =====
ksql:/tmp/probe.sql:116: NOTICE:  table "p14" does not exist, skipping
DROP TABLE
ksql:/tmp/probe.sql:117: ERROR:  编码 "UTF8" 中的排序规则 "utf8mb4_unicode_ci" 不存在
第1行CREATE TABLE p14 (v varchar(20) COLLATE utf8mb4_unicode_ci);
                                     ^

===== 15. 建表尾缀 ENGINE=InnoDB AUTO_INCREMENT=100 =====
ksql:/tmp/probe.sql:121: NOTICE:  table "p15" does not exist, skipping
DROP TABLE
ksql:/tmp/probe.sql:122: ERROR:  语法错误 在 "ENGINE" 或附近的
第1行...ATE TABLE p15 (id int AUTO_INCREMENT PRIMARY KEY) ENGINE=Inn...
                                                          ^

===== 16. LOCK TABLES / UNLOCK TABLES =====
ksql:/tmp/probe.sql:126: ERROR:  语法错误 在 "p7" 或附近的
第1行LOCK TABLES p7 WRITE;
                 ^
ksql:/tmp/probe.sql:127: ERROR:  语法错误 在 "UNLOCK" 或附近的
第1行UNLOCK TABLES;
     ^

===== 17. SET @@SESSION.SQL_MODE =====
ksql:/tmp/probe.sql:131: ERROR:  语法错误 在 "@@" 或附近的
第1行SET @@SESSION.SQL_MODE = 'ONLY_FULL_GROUP_BY';
         ^

===== 18. MySQL 条件注释 /*!40101 SET NAMES utf8mb4 */ =====

===== 19. 反引号 + 库名限定 =====
ksql:/tmp/probe.sql:139: ERROR:  语法错误 在 "`" 或附近的
第1行SELECT * FROM `p7`;
                   ^

===== 20a. 内联 KEY(普通索引)=====
ksql:/tmp/probe.sql:143: NOTICE:  table "q20a" does not exist, skipping
DROP TABLE
ksql:/tmp/probe.sql:144: ERROR:  类型 "idx_cat" 不存在
第1行CREATE TABLE q20a (id int, cat_id int, KEY idx_cat (cat_id))...
                                                ^

===== 20b. 内联 UNIQUE KEY =====
ksql:/tmp/probe.sql:148: NOTICE:  table "q20b" does not exist, skipping
DROP TABLE
ksql:/tmp/probe.sql:149: ERROR:  语法错误 在 "KEY" 或附近的
第1行...EATE TABLE q20b (id int, code varchar(10), UNIQUE KEY uk_cod...
                                                          ^

===== 20c. 内联 CONSTRAINT FOREIGN KEY =====
ksql:/tmp/probe.sql:153: NOTICE:  table "q20c" does not exist, skipping
DROP TABLE
CREATE TABLE

===== 20d. NOT NULL + AUTO_INCREMENT + PRIMARY KEY 组合 =====
ksql:/tmp/probe.sql:158: NOTICE:  table "q20d" does not exist, skipping
DROP TABLE
CREATE TABLE

===== 21. SET NAMES utf8mb4 =====
ksql:/tmp/probe.sql:163: ERROR:  语法错误 在 "utf8mb4" 或附近的
第1行SET NAMES utf8mb4;
               ^

===== 22. 索引 USING BTREE =====
ksql:/tmp/probe.sql:167: NOTICE:  table "q22" does not exist, skipping
DROP TABLE
ksql:/tmp/probe.sql:168: ERROR:  语法错误 在 "USING" 或附近的
第1行...E TABLE q22 (id int, v varchar(10), KEY idx_v (v) USING BTRE...
                                                          ^

===== 23. ALTER TABLE DISABLE KEYS / ENABLE KEYS =====
ksql:/tmp/probe.sql:172: ERROR:  语法错误 在 "KEYS" 或附近的
第1行ALTER TABLE q22 DISABLE KEYS;
                             ^
ksql:/tmp/probe.sql:173: ERROR:  语法错误 在 "KEYS" 或附近的
第1行ALTER TABLE q22 ENABLE KEYS;
                            ^

===== 24. INSERT 语句里的反引号 =====
ksql:/tmp/probe.sql:177: ERROR:  语法错误 在 "`" 或附近的
第1行INSERT INTO `p2` (`id`,`name`) VALUES (1,'x');
                 ^

########## 第 2 部分:补救方案实验(会改参数,故放在最后)##########

===== 6b. 关闭 ora_input_emptystr_isnull 后重试空串(验证补救方案)=====
SET
 ora_input_emptystr_isnull 
---------------------------
 off
(1 行记录)

DELETE 1
INSERT 0 1
 空串匹配数 
------------
          1
(1 行记录)

 is_null匹配数 
---------------
             0
(1 行记录)

 id | 是否为null 
----+------------
  2 | f
(1 行记录)


===== 9a. 关闭 sql_mode 后重试宽松 GROUP BY(验证逃生门)=====
SET
 dept | name 
------+------
 a    | x
(1 行记录)

 sql_mode 
----------
 ""
(1 行记录)


===== 9b-1. sql_mode 合法取值(enumvals)=====
   name   | setting | enumvals 
----------+---------+----------
 sql_mode | ""      | 
(1 行记录)


===== 9b-2. 单值设置语法 =====
SET
       sql_mode       
----------------------
 "ONLY_FULL_GROUP_BY"
(1 行记录)


===== 9b-3. TO 语法 =====
SET
   sql_mode    
---------------
 "ANSI_QUOTES"
(1 行记录)


===== 9b-4. RESET 恢复默认 =====
RESET
            sql_mode            
--------------------------------
 ONLY_FULL_GROUP_BY,ANSI_QUOTES
(1 行记录)


===== 12b. 关闭 ANSI_QUOTES 后双引号语义(与 12a 对比)=====
SET
 name 
------
 x
 y
(2 行记录)


===== 探针 v2 结束:请保存上面全部输出 =====

7. 探针结论汇总

1) 基线快照

项目 值 说明
版本 KingbaseES V009R002C016 V9R2
服务端编码 UTF8 与 MySQL 的 utf8mb4 对应
默认 sql_mode ONLY_FULL_GROUP_BY,ANSI_QUOTES 与源库 MySQL 的严格性一致
ora_input_emptystr_isnull on ⚠️ 空串会被当作 NULL,见下方关键发现①

2) 结论一:原生支持(不用改造)

探针 MySQL 写法 结果
2 AUTO_INCREMENT 关键字 ✅ 支持
4a tinyint ✅ 支持
4c datetime ✅ 支持
4d text ✅ 支持
5 LIMIT 0,10(MySQL 逗号写法) ✅ 支持
8 IFNULL / NOW / CONCAT ✅ 支持
11 INSERT ... ON DUPLICATE KEY UPDATE ✅ 支持(有警告"建议使用 on conflict 子句",但语句生效)
12c 中文字符串常量 ✅ 支持
18 /*!40101 SET NAMES utf8mb4 */ 条件注释 ✅ 被当普通注释忽略,不报错
20c 内联 CONSTRAINT ... FOREIGN KEY ✅ 支持
20d NOT NULL + AUTO_INCREMENT + PRIMARY KEY 组合 ✅ 支持

注:探针 18 的意义在于 mysqldump 头部有几十行 /*!40101 ... */ 语句,金仓直接忽略不报错,这部分不需要清洗。

3) 结论二:必须改造(直接报错)

探针 MySQL 写法 金仓报错 改造方式
1 / 19 / 24 反引号 ` 语法错误 在 "" 或附近的` 全局删除反引号
3 / 15 ENGINE=InnoDB 语法错误 在 "ENGINE" 或附近的 删除
3 / 13 DEFAULT CHARSET=utf8mb4 语法错误 在 "DEFAULT" 或附近的 删除
14 COLLATE utf8mb4_unicode_ci 编码 "UTF8" 中的排序规则 "utf8mb4_unicode_ci" 不存在 删除
15 AUTO_INCREMENT=100 语法错误 在 "ENGINE" 或附近的 删除
4b int unsigned 语法错误 在 "unsigned" 或附近的 改为 bigint(MySQL 无符号 int 上限 42 亿,超出金仓 int4 的 21 亿)
4e double(10,2) 语法错误 在 "(" 或附近的 改为 numeric(10,2)
20a 内联 KEY idx_cat (cat_id) 类型 "idx_cat" 不存在 拆成独立 CREATE INDEX(见关键发现③)
20b 内联 UNIQUE KEY uk_code (code) 语法错误 在 "KEY" 或附近的 拆成独立 CREATE UNIQUE INDEX
22 索引 USING BTREE 语法错误 在 "USING" 或附近的 删除
23 ALTER TABLE ... DISABLE/ENABLE KEYS 语法错误 在 "KEYS" 或附近的 整行删除
16 LOCK TABLES / UNLOCK TABLES 语法错误 在 "p7" 或附近的 整行删除
17 SET @@SESSION.SQL_MODE = ... 语法错误 在 "@@" 或附近的 整行删除
21 SET NAMES utf8mb4; 语法错误 在 "utf8mb4" 或附近的 删除或改写为 SET client_encoding = 'UTF8';
10 SHOW TABLES / DESC unrecognized configuration parameter "tables" / 语法错误 在 "DESC" 手工操作改用 \dt / \d

注:探针 20a 的报错是"类型 idx_cat 不存在"而不是语法错误——说明金仓把索引名当成了列的数据类型来解析,这是内联索引写法不被支持的典型表现。

4) 结论三:语义变化(不报错,但结果不同 —— 最需要警惕的一类)

项目 现象 证据 能否补救
空字符串 '' 被转换成 NULL 探针 6a:插入 '' 后 空串匹配数=0、IS_NULL匹配数=1 ✅ 能,见关键发现①
双引号 "..." 恒被当作标识符(MySQL 默认是字符串) 探针 12a(ANSI_QUOTES 开)与 12b(关)结果相同,都返回列值 x,y ❌ 不能(参数无法改变)
GROUP BY 严格性 非聚合列必须出现在 GROUP BY 中 探针 7:字段 "p7.name" 必须出现在 GROUP BY 子句中 ⚠️ 可用 SET sql_mode = '' 临时放宽,但源库 MySQL 同样是严格模式,两边一致,无需处理

注:双引号这条虽然不能补救,但mysqldump 生成的字符串常量用单引号,所以导入过程不受影响;只有应用程序自己的 SQL 里用双引号当字符串时才会出问题。

5) 关键发现①:空串被转成 NULL —— 已找到补救方案 ⭐

默认状态(探针 6a,ora_input_emptystr_isnull = on):

===== 6a. 空串写入【可空列】(默认 ora_input_emptystr_isnull)=====
INSERT 0 1
 总行数 
--------
      1
 空串匹配数 
------------
          0        ← SELECT ... WHERE v = ''  查不到
 is_null匹配数 
---------------
             1     ← 它变成了 NULL
 id | 是否为null 
----+------------
  1 | t            ← 确认是 NULL

关闭参数后(探针 6b):

===== 6b. 关闭 ora_input_emptystr_isnull 后重试空串 =====
SET
 ora_input_emptystr_isnull 
---------------------------
 off
INSERT 0 1
 空串匹配数 
------------
          1        ← 空串能被查到了
 is_null匹配数 
---------------
             0     ← 不再是 NULL
 id | 是否为null 
----+------------
  2 | f            ← 确认是空串

对比结论:

参数状态 插入 '' 后实际存的值 与 MySQL 语义
ora_input_emptystr_isnull = on(默认) NULL ❌ 不一致
ora_input_emptystr_isnull = off 空串 '' ✅ 完全一致

这意味着:不需要为了这个差异把实例重建为 pg 模式,只需把参数关掉。

迁移前持久化该参数(会话级设置对应用连接无效,必须写配置文件):

sed -i 's/^ora_input_emptystr_isnull.*/ora_input_emptystr_isnull = off/' /opt/Kingbase/ES/Server/data/kingbase.conf
grep -n ora_input_emptystr_isnull /opt/Kingbase/ES/Server/data/kingbase.conf
systemctl restart kingbased

验证(看输出中的值应为 off):

[kingbase@OE2 ~]$ /opt/Kingbase/ES/Server/bin/ksql -U system -d test -p 54321 -c "SHOW ora_input_emptystr_isnull;"
 ora_input_emptystr_isnull 
---------------------------
 off
(1 行记录)

⚠️ 为什么这条最重要:空串变 NULL 不报错,会静默改变数据语义——WHERE x = '' 查不到数据、COUNT(x) 数字变小、'' 的唯一性判断失效。如果不在迁移前处理,迁完之后"数据看起来都在,但业务查询结果不对",排查起来极其困难。

6) 关键发现②:sql_mode 的正确操作法

操作 结论 命令
设为单值 ✅ 可用 SET sql_mode = 'ONLY_FULL_GROUP_BY';
TO 语法 ✅ 也可用 SET sql_mode TO 'ANSI_QUOTES';
恢复默认 ✅ 用 RESET RESET sql_mode;(恢复为 ONLY_FULL_GROUP_BY,ANSI_QUOTES)
设多值 ❌ 报错 未知的关键字: "A,B" 不能照搬 MySQL 的 SET sql_mode = 'A,B'

本环境不需要调整:源库 MySQL 的 my.cnf 中 sql_mode 已包含 ONLY_FULL_GROUP_BY,与金仓默认一致,因此 GROUP BY 行为两边相同。

如果确实需要放宽(老应用 SQL 不合严格模式),用探针 9a 验证过的逃生门:

===== 9a. 关闭 sql_mode 后重试宽松 GROUP BY(验证逃生门)=====
SET
 dept | name 
------+------
 a    | x          ← 关闭后,宽松 GROUP BY 成功执行
(1 行记录)

注:sql_mode 是会话级参数,断开重连即恢复默认值(探针第二轮重新执行时,探针 7 又报了严格模式错误,正好证明这一点)。

7) 关键发现③:内联索引不支持,但外键支持

写法 结果
内联 KEY idx_cat (cat_id) ❌ 类型 "idx_cat" 不存在
内联 UNIQUE KEY uk_code (code) ❌ 语法错误 在 "KEY" 或附近的
内联 CONSTRAINT fk_cat FOREIGN KEY (...) REFERENCES ... ✅ 建表成功

这是本次迁移最大的改造工作量——mysqldump 每张表的索引都要从建表语句里搬出来。改造前后对比:

-- 改造前(mysqldump 原始输出)
CREATE TABLE product (
  id int NOT NULL AUTO_INCREMENT,
  cat_id int NOT NULL,
  code varchar(20) DEFAULT NULL,
  PRIMARY KEY (id),
  KEY idx_cat (cat_id),
  UNIQUE KEY uk_code (code),
  CONSTRAINT fk_cat FOREIGN KEY (cat_id) REFERENCES category (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 改造后(金仓可执行)
CREATE TABLE product (
  id int NOT NULL AUTO_INCREMENT,
  cat_id int NOT NULL,
  code varchar(20) DEFAULT NULL,
  PRIMARY KEY (id),
  CONSTRAINT fk_cat FOREIGN KEY (cat_id) REFERENCES category (id)
);
CREATE INDEX idx_cat ON product (cat_id);
CREATE UNIQUE INDEX uk_code ON product (code);

8) 迁移改造清单(清洗规则)

第一批:可用 sed 批量处理(覆盖大部分改动)

cat > /tmp/fix.sed <<'EOF'
s/`//g
s/ ENGINE=[A-Za-z]+//g
s/ AUTO_INCREMENT=[0-9]+//g
s/ DEFAULT CHARSET[= ][A-Za-z0-9_]+//g
s/ DEFAULT CHARACTER SET[= ][A-Za-z0-9_]+//g
s/ COLLATE[= ][A-Za-z0-9_]+//g
s/ USING BTREE//g
s/\bint unsigned\b/bigint/g
s/\bdouble\(([0-9]+),([0-9]+)\)/numeric(\1,\2)/g
/^LOCK TABLES/d
/^UNLOCK TABLES/d
/^SET @@/d
/^SET NAMES/d
/DISABLE KEYS/d
/ENABLE KEYS/d
EOF

sed -i -E -f /tmp/fix.sed shop.sql

第二批:必须人工或脚本处理

项目 处理方式
内联 KEY / UNIQUE KEY 抽出来改写成独立的 CREATE INDEX / CREATE UNIQUE INDEX 语句(见关键发现③)
SET NAMES utf8mb4; 删除,或改写为 SET client_encoding = 'UTF8';
应用 SQL 里的双引号字符串 无法通过参数补救,需改写为单引号

9) 小结

分类 数量 处理
原生支持 11 项 无需处理
必须改造 15 项 sed 批量清洗 + 内联索引人工搬家
语义变化 3 项 空串靠参数补救(已解决);双引号需改 SQL;GROUP BY 两边一致

结论:金仓(Oracle 兼容模式)对 MySQL 语法的兼容度中等偏上——常用函数、LIMIT 逗号写法、AUTO_INCREMENT、ON DUPLICATE KEY UPDATE、内联外键都能直接用;主要障碍集中在 mysqldump 的建表装饰语(ENGINE/CHARSET/COLLATE)和反引号,这些用 sed 就能批量清理;唯一需要参数层面处理的是空串语义,已在探针 6b 中验证可通过 ora_input_emptystr_isnull = off 解决。

四. 迁移开始

1.先将本地事先准备好的数据文件导入到mysql中

mysql -u root -p < /root/world.sql 

验证

[root@Rocky7 ~]# mysql -u root -p -e 'show databases;'
Enter password: 
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| world              |
+--------------------+

2. 金仓侧改参数

su - kingbase
/opt/Kingbase/ES/Server/bin/ksql -U system -d test -p 54321 -c "ALTER SYSTEM SET ora_input_emptystr_isnull = off;"
exit
systemctl restart kingbased

验证: 需要看到off

[root@OE2 ~]# /opt/Kingbase/ES/Server/bin/ksql -U system -d test -p 54321 -c "SHOW ora_input_emptystr_isnull;"
用户 system 的口令:
 ora_input_emptystr_isnull 
---------------------------
 off
(1 行记录)

ALTER SYSTEM SET 是 PG 风格写法,会把配置写进 kingbase.auto.conf;如果它报错,退回到直接改配置文件:

sed -i 's/^ora_input_emptystr_isnull.*/ora_input_emptystr_isnull = off/' /opt/Kingbase/ES/Server/data/kingbase.conf
systemctl restart kingbased

3. 顺手补测一个探针

world 库有 2 个 enum(...) 列,我们的探针没测过这个类型:

cat > /tmp/probe4.sql <<'EOF'
-- ============================================================
-- 探针 27:列级 CHECK 约束(MySQL enum 的替代方案是否可行)
-- 用法:ksql -U system -d probe_db -p 54321 -f /tmp/probe4.sql
-- ============================================================

\echo ''
\echo '===== 27. 列级 CHECK ... IN (...),替代 MySQL enum ====='
DROP TABLE IF EXISTS q27;
CREATE TABLE q27 (v varchar(50) NOT NULL DEFAULT 'F' CHECK (v IN ('T','F')));
INSERT INTO q27 VALUES ('T');
SELECT * FROM q27;

\echo ''
\echo '----- 27b. 插入非法值 X,应被 CHECK 拒绝(证明约束真的生效)-----'
INSERT INTO q27 VALUES ('X');
SELECT * FROM q27;

\echo ''
\echo '----- 27c. 默认值 DEFAULT 是否生效 -----'
INSERT INTO q27 DEFAULT VALUES;
SELECT * FROM q27 ORDER BY v;

\echo ''
\echo '===== 探针 27 结束 ====='
EOF

su - kingbase
export KINGBASE_PASSWORD='Kingbase@2026'
/opt/Kingbase/ES/Server/bin/ksql -U system -d probe_db -p 54321 -f /tmp/probe4.sql

4. 源端导出

在7上

/usr/local/mysql/bin/mysqldump -uroot \
  --databases world \
  --single-transaction \
  --set-gtid-purged=OFF \
  --default-character-set=utf8mb4 \
  --no-tablespaces \
  --skip-add-locks \
  --skip-comments \
  > /root/world_migrate.sql

5. 写脚本,然后清洗

vi /fix.sed
vi move_index.awk 

这两个脚本分别是

s/`//g
s/ ENGINE=[A-Za-z]+//g
s/ AUTO_INCREMENT=[0-9]+//g
s/ DEFAULT CHARSET[= ][A-Za-z0-9_]+//g
s/ DEFAULT CHARACTER SET[= ][A-Za-z0-9_]+//g
s/ COLLATE[= ][A-Za-z0-9_]+//g
s/ USING BTREE//g
s/\bint unsigned\b/bigint/g
s/\bdouble\(([0-9]+),([0-9]+)\)/numeric(\1,\2)/g
s/^([[:space:]]*)([A-Za-z0-9_]+)[[:space:]]+enum\(([^)]*)\)(.*),$/\1\2 varchar(50)\4 CHECK (\2 IN (\3)),/
s/\)[[:space:]]*;/);/
/^LOCK TABLES/d
/^UNLOCK TABLES/d
/^SET @/d
/^SET @@/d
/^SET autocommit/d
/^SET NAMES/d
/DISABLE KEYS/d
/ENABLE KEYS/d
# ============================================================
# move_index.awk —— 把 CREATE TABLE 内的内联 KEY / UNIQUE KEY 行
# 搬到建表语句之后,改写成独立的 CREATE INDEX 语句
# (金仓 KingbaseES 不支持内联 KEY/UNIQUE KEY —— 探针 20a/20b 实测)
# 用法:awk -f move_index.awk 已用fix.sed清洗过.sql > 最终.sql
# 注意:本脚本按"无反引号"的写法匹配,必须先跑 fix.sed
# ============================================================
BEGIN { inct = 0; nb = 0; nk = 0; tbl = "" }

# ① CREATE TABLE 起始行:抓表名
inct == 0 && /^CREATE TABLE/ {
  inct = 1; nb = 0; nk = 0
  tbl = $0
  sub(/^CREATE TABLE[ \t]+/, "", tbl)
  sub(/[ \t(].*$/, "", tbl)
  print
  next
}

# ② 表内的内联索引行 → 暂存,不输出
inct == 1 && /^[ \t]*(UNIQUE[ \t]+KEY|FULLTEXT[ \t]+KEY|SPATIAL[ \t]+KEY|KEY)[ \t]/ {
  l = $0
  sub(/^[ \t]+/, "", l)
  sub(/,[ \t]*$/, "", l)
  gsub(/[ \t]+USING[ \t]+BTREE/, "", l)
  u = 0
  if (l ~ /^UNIQUE[ \t]+KEY/)        { u = 1; sub(/^UNIQUE[ \t]+KEY[ \t]+/, "", l) }
  else if (l ~ /^FULLTEXT[ \t]+KEY/) {        sub(/^FULLTEXT[ \t]+KEY[ \t]+/, "", l) }
  else if (l ~ /^SPATIAL[ \t]+KEY/)  {        sub(/^SPATIAL[ \t]+KEY[ \t]+/, "", l) }
  else                               {        sub(/^KEY[ \t]+/, "", l) }
  nk++
  nm[nk] = l; sub(/[ \t]*\(.*$/, "", nm[nk])
  co[nk] = l; sub(/^[^(]*\(/, "", co[nk]); sub(/\)[ \t]*$/, "", co[nk])
  uq[nk] = u
  next
}

# ③ 建表结束行:先输出缓冲的列定义(修正末行逗号),再输出独立索引
inct == 1 && /^\)/ {
  if (nb > 0) {
    c = body[nb]
    sub(/,[ \t]*$/, "", c)
    body[nb] = c
    for (i = 1; i <= nb; i++) print body[i]
  }
  print
  for (i = 1; i <= nk; i++) {
    if (uq[i]) printf "CREATE UNIQUE INDEX %s ON %s (%s);\n", nm[i], tbl, co[i]
    else       printf "CREATE INDEX %s ON %s (%s);\n", nm[i], tbl, co[i]
  }
  inct = 0; nb = 0; nk = 0; tbl = ""
  next
}

# ④ 表内其他行 → 缓冲
inct == 1 { nb++; body[nb] = $0; next }

# ⑤ 表外普通行 → 原样输出
{ print }