Escape reserved separator identifiers in MySQL SQL

This commit is contained in:
2026-07-20 17:19:09 +08:00 Unverified
parent 1a87e06fc8
commit a30477bb58
4 changed files with 14 additions and 8 deletions
+4 -4
View File
@@ -198,7 +198,7 @@ function buildSeedOperations(state) {
for (const rule of state.admissionNumberRules) { for (const rule of state.admissionNumberRules) {
add( add(
`INSERT INTO admission_number_rules ( `INSERT INTO admission_number_rules (
id, code, name, description, separator, segments_json, example, active, created_at id, code, name, description, \`separator\`, segments_json, example, active, created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
rule.id, rule.code, rule.name, rule.description, rule.separator || '', JSON.stringify(rule.segments || []), rule.id, rule.code, rule.name, rule.description, rule.separator || '', JSON.stringify(rule.segments || []),
rule.example || '', rule.active === false ? 0 : 1, rule.createdAt rule.example || '', rule.active === false ? 0 : 1, rule.createdAt
@@ -267,7 +267,7 @@ function buildSeedOperations(state) {
for (const rule of state.numberRules) { for (const rule of state.numberRules) {
add( add(
'INSERT INTO number_rules (id, name, separator, active, created_by, updated_at) VALUES (?, ?, ?, ?, ?, ?)', 'INSERT INTO number_rules (id, name, `separator`, active, created_by, updated_at) VALUES (?, ?, ?, ?, ?, ?)',
rule.id, rule.name, rule.separator || '', rule.active ? 1 : 0, nullable(rule.createdBy), rule.updatedAt rule.id, rule.name, rule.separator || '', rule.active ? 1 : 0, nullable(rule.createdBy), rule.updatedAt
); );
rule.segments.forEach((segment, index) => add( rule.segments.forEach((segment, index) => add(
@@ -1123,13 +1123,13 @@ function createRepository({ client, location, read, transaction, close }) {
const operations = [operation('UPDATE number_rules SET active = 0 WHERE active = 1')]; const operations = [operation('UPDATE number_rules SET active = 0 WHERE active = 1')];
if (isNew) { if (isNew) {
operations.push(operation( operations.push(operation(
'INSERT INTO number_rules (id, name, separator, active, created_by, updated_at) VALUES (?, ?, ?, ?, ?, ?)', 'INSERT INTO number_rules (id, name, `separator`, active, created_by, updated_at) VALUES (?, ?, ?, ?, ?, ?)',
rule.id, rule.name, rule.separator, rule.active ? 1 : 0, optional(rule.createdBy), rule.updatedAt rule.id, rule.name, rule.separator, rule.active ? 1 : 0, optional(rule.createdBy), rule.updatedAt
)); ));
} else { } else {
operations.push( operations.push(
operation( operation(
'UPDATE number_rules SET name = ?, separator = ?, active = ?, created_by = ?, updated_at = ? WHERE id = ?', 'UPDATE number_rules SET name = ?, `separator` = ?, active = ?, created_by = ?, updated_at = ? WHERE id = ?',
rule.name, rule.separator, rule.active ? 1 : 0, optional(rule.createdBy), rule.updatedAt, rule.id rule.name, rule.separator, rule.active ? 1 : 0, optional(rule.createdBy), rule.updatedAt, rule.id
), ),
operation('DELETE FROM number_rule_segments WHERE rule_id = ?', rule.id) operation('DELETE FROM number_rule_segments WHERE rule_id = ?', rule.id)
+2 -2
View File
@@ -151,7 +151,7 @@ export function createMysqlAdapter(context) {
const extension = seed(); const extension = seed();
for (const rule of extension.admissionNumberRules) await pool.execute( for (const rule of extension.admissionNumberRules) await pool.execute(
`INSERT INTO admission_number_rules ( `INSERT INTO admission_number_rules (
id, code, name, description, separator, segments_json, example, active, created_at id, code, name, description, \`separator\`, segments_json, example, active, created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[rule.id, rule.code, rule.name, rule.description, rule.separator || '', JSON.stringify(rule.segments || []), [rule.id, rule.code, rule.name, rule.description, rule.separator || '', JSON.stringify(rule.segments || []),
rule.example || '', rule.active === false ? 0 : 1, rule.createdAt] rule.example || '', rule.active === false ? 0 : 1, rule.createdAt]
@@ -226,7 +226,7 @@ export function createMysqlAdapter(context) {
const [ruleRows] = await connection.execute('SELECT id FROM number_rules LIMIT 1'); const [ruleRows] = await connection.execute('SELECT id FROM number_rules LIMIT 1');
if (!ruleRows.length) for (const rule of extension.numberRules) { if (!ruleRows.length) for (const rule of extension.numberRules) {
await connection.execute( await connection.execute(
'INSERT INTO number_rules (id, name, separator, active, created_by, updated_at) VALUES (?, ?, ?, ?, ?, ?)', 'INSERT INTO number_rules (id, name, `separator`, active, created_by, updated_at) VALUES (?, ?, ?, ?, ?, ?)',
[rule.id, rule.name, rule.separator || '', rule.active ? 1 : 0, optional(rule.createdBy), rule.updatedAt] [rule.id, rule.name, rule.separator || '', rule.active ? 1 : 0, optional(rule.createdBy), rule.updatedAt]
); );
for (const [index, segment] of rule.segments.entries()) await connection.execute( for (const [index, segment] of rule.segments.entries()) await connection.execute(
+2 -2
View File
@@ -708,7 +708,7 @@ export const mysqlSchema = [
code VARCHAR(80) NOT NULL, code VARCHAR(80) NOT NULL,
name VARCHAR(160) NOT NULL, name VARCHAR(160) NOT NULL,
description VARCHAR(500) NOT NULL, description VARCHAR(500) NOT NULL,
separator VARCHAR(10) NOT NULL DEFAULT '', \`separator\` VARCHAR(10) NOT NULL DEFAULT '',
segments_json JSON NOT NULL, segments_json JSON NOT NULL,
example VARCHAR(120) NOT NULL, example VARCHAR(120) NOT NULL,
active BOOLEAN NOT NULL DEFAULT TRUE, active BOOLEAN NOT NULL DEFAULT TRUE,
@@ -824,7 +824,7 @@ export const mysqlSchema = [
`CREATE TABLE IF NOT EXISTS number_rules ( `CREATE TABLE IF NOT EXISTS number_rules (
id VARCHAR(64) NOT NULL, id VARCHAR(64) NOT NULL,
name VARCHAR(120) NOT NULL, name VARCHAR(120) NOT NULL,
separator VARCHAR(10) NOT NULL DEFAULT '', \`separator\` VARCHAR(10) NOT NULL DEFAULT '',
active BOOLEAN NOT NULL DEFAULT FALSE, active BOOLEAN NOT NULL DEFAULT FALSE,
created_by VARCHAR(64) NULL, created_by VARCHAR(64) NULL,
updated_at VARCHAR(35) NOT NULL, updated_at VARCHAR(35) NOT NULL,
+6
View File
@@ -4,12 +4,18 @@ import { resolve } from 'node:path';
import assert from 'node:assert/strict'; import assert from 'node:assert/strict';
import ExcelJS from 'exceljs'; import ExcelJS from 'exceljs';
import { relationalTables } from '../database.mjs'; import { relationalTables } from '../database.mjs';
import { mysqlSchema } from '../src/database/schema.mjs';
import { buildCenterMaterialsWorkbook, buildWorkbook } from '../excel.mjs'; import { buildCenterMaterialsWorkbook, buildWorkbook } from '../excel.mjs';
const root = resolve(process.cwd()); const root = resolve(process.cwd());
const port = 4182; const port = 4182;
const baseUrl = `http://127.0.0.1:${port}`; const baseUrl = `http://127.0.0.1:${port}`;
const testDb = resolve(root, 'data', 'test-db.sqlite'); const testDb = resolve(root, 'data', 'test-db.sqlite');
const mysqlRuleSchemas = mysqlSchema.filter(statement => /CREATE TABLE IF NOT EXISTS (?:admission_number_rules|number_rules)\b/.test(statement));
assert.equal(mysqlRuleSchemas.length, 2, 'MySQL 应包含两张号码规则表');
for (const statement of mysqlRuleSchemas) {
assert.match(statement, /`separator` VARCHAR\(10\)/, 'MySQL 保留字 separator 必须作为标识符转义');
}
await rm(testDb, { force: true }); await rm(testDb, { force: true });
await rm(`${testDb}-shm`, { force: true }); await rm(`${testDb}-shm`, { force: true });
await rm(`${testDb}-wal`, { force: true }); await rm(`${testDb}-wal`, { force: true });