20260804223152

This commit is contained in:
oneao committed 2026-08-04 22:31:52 +08:00
1 parent 75b1ccaa6d
commit 7c9761a4fc
71 files changed
+5534 -9113

No files matched your search

View File
Whitespace-only changes.
-65
View File
@@ -1,65 +0,0 @@
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------------< cn.g3soft:fms-api >--------------------------
[INFO] Building fms-api 0.0.1-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:4.1.0:run (default-cli) > test-compile @ fms-api >>>
[INFO]
[INFO] --- maven-resources-plugin:3.5.0:resources (default-resources) @ fms-api ---
[INFO] Copying 1 resource from src\main\resources to target\classes
[INFO] Copying 0 resource from src\main\resources to target\classes
[INFO]
[INFO] --- maven-compiler-plugin:3.15.0:compile (default-compile) @ fms-api ---
[INFO] Nothing to compile - all classes are up to date.
[INFO]
[INFO] --- maven-resources-plugin:3.5.0:testResources (default-testResources) @ fms-api ---
[INFO] skip non existing resourceDirectory D:\workspace\code\fms\fms-api\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.15.0:testCompile (default-testCompile) @ fms-api ---
[INFO] Nothing to compile - all classes are up to date.
[INFO]
[INFO] <<< spring-boot-maven-plugin:4.1.0:run (default-cli) < test-compile @ fms-api <<<
[INFO]
[INFO]
[INFO] --- spring-boot-maven-plugin:4.1.0:run (default-cli) @ fms-api ---
[INFO] Attaching agents: []
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v4.1.0)
2026-08-04T15:49:27.744+08:00 INFO 10960 --- [fms-api] [ restartedMain] cn.g3soft.fmsapi.FmsApiApplication : Starting FmsApiApplication using Java 21 with PID 10960 (D:\workspace\code\fms\fms-api\target\classes started by Administrator in D:\workspace\code\fms\fms-api)
2026-08-04T15:49:27.753+08:00 INFO 10960 --- [fms-api] [ restartedMain] cn.g3soft.fmsapi.FmsApiApplication : No active profile set, falling back to 1 default profile: "default"
2026-08-04T15:49:27.901+08:00 INFO 10960 --- [fms-api] [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2026-08-04T15:49:27.902+08:00 INFO 10960 --- [fms-api] [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2026-08-04T15:49:29.777+08:00 INFO 10960 --- [fms-api] [ restartedMain] o.s.boot.tomcat.TomcatWebServer : Tomcat initialized with port 8088 (http)
2026-08-04T15:49:29.805+08:00 INFO 10960 --- [fms-api] [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2026-08-04T15:49:29.807+08:00 INFO 10960 --- [fms-api] [ restartedMain] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/11.0.22]
2026-08-04T15:49:29.858+08:00 INFO 10960 --- [fms-api] [ restartedMain] b.w.c.s.WebApplicationContextInitializer : Root WebApplicationContext: initialization completed in 1954 ms
2026-08-04T15:49:30.455+08:00 INFO 10960 --- [fms-api] [ restartedMain] c.g3soft.fmsapi.utils.IpRegionSearcher : ip2region Searcher 初始化完成,数据大小 11114380 字节
2026-08-04T15:49:31.639+08:00 INFO 10960 --- [fms-api] [ restartedMain] o.s.boot.tomcat.TomcatWebServer : Tomcat started on port 8088 (http) with context path '/api'
2026-08-04T15:49:31.656+08:00 INFO 10960 --- [fms-api] [ restartedMain] cn.g3soft.fmsapi.FmsApiApplication : Started FmsApiApplication in 5.07 seconds (process running for 7.639)
2026-08-04T15:50:46.035+08:00 INFO 10960 --- [fms-api] [nio-8088-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/api] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2026-08-04T15:50:46.038+08:00 INFO 10960 --- [fms-api] [nio-8088-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2026-08-04T15:50:46.039+08:00 INFO 10960 --- [fms-api] [nio-8088-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
2026-08-04T15:50:46.425+08:00 INFO 10960 --- [fms-api] [nio-8088-exec-1] com.alibaba.druid.pool.DruidDataSource : {dataSource-1,G3HD} inited
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:37 h
[INFO] Finished at: 2026-08-04T17:27:10+08:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:4.1.0:run (default-cli) on project fms-api: Process terminated with exit code: -1 -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
@@ -1,934 +0,0 @@
/*
One-time cutover from the original mixed module tree to the resource model.
This migration intentionally does not keep compatibility tables or dual writes.
Existing module, field, action and grant IDs are preserved where the entity keeps
the same meaning. IDs only need to be unique inside their owning table.
*/
SET NOCOUNT ON;
SET XACT_ABORT ON;
IF DB_NAME() <> N'FMS'
THROW 53300, N'This migration can only run against the FMS database.', 1;
/* CUTOVER_INSTALLED_GUARD_START */
IF OBJECT_ID(N'dbo.s_module_page', N'U') IS NOT NULL
BEGIN
PRINT N'Module architecture already installed.';
RETURN;
END;
/* CUTOVER_INSTALLED_GUARD_END */
IF OBJECT_ID(N'dbo.s_module', N'U') IS NULL
THROW 53301, N'dbo.s_module does not exist.', 1;
DECLARE @HasPartialArchitecture bit = CASE WHEN
OBJECT_ID(N'dbo.s_module_profile', N'U') IS NOT NULL
OR OBJECT_ID(N'dbo.s_function_node', N'U') IS NOT NULL
OR OBJECT_ID(N'dbo.s_page_node', N'U') IS NOT NULL
THEN 1 ELSE 0 END;
IF @HasPartialArchitecture = 1 AND (
COL_LENGTH(N'dbo.s_module', N'b_parent_id') IS NULL
OR OBJECT_ID(N'dbo.s_module_field_list', N'U') IS NULL
OR OBJECT_ID(N'dbo.s_module_field_edit', N'U') IS NULL
OR OBJECT_ID(N'dbo.s_module_field_query', N'U') IS NULL
OR OBJECT_ID(N'dbo.s_module_field_group', N'U') IS NULL
OR OBJECT_ID(N'dbo.s_module_power', N'U') IS NULL
OR OBJECT_ID(N'dbo.s_module_field', N'U') IS NULL
OR OBJECT_ID(N'dbo.b_user_power', N'U') IS NULL
OR OBJECT_ID(N'dbo.b_user_module', N'U') IS NULL
)
THROW 53302, N'Unsafe partial module architecture detected. Restore the database before retrying.', 1;
BEGIN TRANSACTION;
/*
Earlier implementation work may have created these three derived tables while
the original module tables were still authoritative. They are regenerated below
from the validated source model, so remove them inside this transaction only.
*/
IF @HasPartialArchitecture = 1
BEGIN
IF OBJECT_ID(N'dbo.s_page_node', N'U') IS NOT NULL DROP TABLE dbo.s_page_node;
IF OBJECT_ID(N'dbo.s_function_node', N'U') IS NOT NULL DROP TABLE dbo.s_function_node;
IF OBJECT_ID(N'dbo.s_module_profile', N'U') IS NOT NULL DROP TABLE dbo.s_module_profile;
END;
GO
/* RETURN in the first batch means the architecture was already installed. */
IF @@TRANCOUNT = 0
RETURN;
/* Preserve the source tables only for the duration of this transaction. */
DECLARE @LegacyTables TABLE (b_old sysname NOT NULL, b_legacy sysname NOT NULL, b_xh int NOT NULL);
INSERT INTO @LegacyTables VALUES
(N's_module_field_list', N'z_legacy_module_field_list', 10),
(N's_module_field_edit', N'z_legacy_module_field_edit', 20),
(N's_module_field_query', N'z_legacy_module_field_query', 30),
(N's_module_field_group', N'z_legacy_module_field_group', 40),
(N's_module_auto_code', N'z_legacy_module_auto_code', 50),
(N's_module_power', N'z_legacy_module_power', 60),
(N's_module_field', N'z_legacy_module_field', 70),
(N'b_user_power', N'z_legacy_user_power', 80),
(N'b_user_module', N'z_legacy_user_module', 90),
(N's_module', N'z_legacy_module', 100);
IF EXISTS (
SELECT 1 FROM @LegacyTables
WHERE OBJECT_ID(N'dbo.' + b_old, N'U') IS NOT NULL
AND OBJECT_ID(N'dbo.' + b_legacy, N'U') IS NOT NULL
)
THROW 53303, N'Legacy staging tables already exist.', 1;
DECLARE @OldName sysname;
DECLARE @LegacyName sysname;
DECLARE @QualifiedOldName nvarchar(517);
DECLARE table_cursor CURSOR LOCAL FAST_FORWARD FOR
SELECT b_old, b_legacy FROM @LegacyTables ORDER BY b_xh;
OPEN table_cursor;
FETCH NEXT FROM table_cursor INTO @OldName, @LegacyName;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @QualifiedOldName = QUOTENAME(N'dbo') + N'.' + QUOTENAME(@OldName);
IF OBJECT_ID(@QualifiedOldName, N'U') IS NOT NULL
EXEC sys.sp_rename @QualifiedOldName, @LegacyName, N'OBJECT';
FETCH NEXT FROM table_cursor INTO @OldName, @LegacyName;
END;
CLOSE table_cursor;
DEALLOCATE table_cursor;
/* Constraint names are schema-wide and sp_rename does not change them with the table. */
DECLARE @ConstraintName sysname;
DECLARE @LegacyConstraintName sysname;
DECLARE @QualifiedConstraintName nvarchar(517);
DECLARE constraint_cursor CURSOR LOCAL FAST_FORWARD FOR
SELECT object_row.name,
CONVERT(sysname, N'z_legacy_c_' + CONVERT(varchar(20), object_row.object_id))
FROM sys.objects AS object_row
INNER JOIN sys.tables AS table_row ON table_row.object_id = object_row.parent_object_id
INNER JOIN @LegacyTables AS legacy_row ON legacy_row.b_legacy = table_row.name
WHERE table_row.schema_id = SCHEMA_ID(N'dbo')
AND object_row.type IN (N'C', N'D', N'F', N'PK', N'UQ');
OPEN constraint_cursor;
FETCH NEXT FROM constraint_cursor INTO @ConstraintName, @LegacyConstraintName;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @QualifiedConstraintName = QUOTENAME(N'dbo') + N'.' + QUOTENAME(@ConstraintName);
EXEC sys.sp_rename @QualifiedConstraintName, @LegacyConstraintName, N'OBJECT';
FETCH NEXT FROM constraint_cursor INTO @ConstraintName, @LegacyConstraintName;
END;
CLOSE constraint_cursor;
DEALLOCATE constraint_cursor;
CREATE TABLE dbo.s_module (
b_id bigint NOT NULL,
b_code varchar(50) NOT NULL,
b_name nvarchar(100) NOT NULL,
b_i18n varchar(150) NOT NULL,
b_module_type varchar(20) NOT NULL,
b_canuse int NOT NULL CONSTRAINT DF_s_module_canuse DEFAULT (1),
CONSTRAINT PK_s_module PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_code UNIQUE (b_code),
CONSTRAINT UQ_s_module_id_type UNIQUE (b_id, b_module_type),
CONSTRAINT CK_s_module_type CHECK (b_module_type IN ('page', 'data', 'report', 'dashboard', 'workflow')),
CONSTRAINT CK_s_module_canuse CHECK (b_canuse IN (0, 1))
);
CREATE TABLE dbo.s_module_page (
b_module_id bigint NOT NULL,
b_module_type varchar(20) NOT NULL CONSTRAINT DF_s_module_page_type DEFAULT ('page'),
b_route varchar(200) NOT NULL,
b_page_mode varchar(20) NOT NULL CONSTRAINT DF_s_module_page_mode DEFAULT ('custom'),
b_component_key varchar(100) NOT NULL,
CONSTRAINT PK_s_module_page PRIMARY KEY (b_module_id),
CONSTRAINT UQ_s_module_page_route UNIQUE (b_route),
CONSTRAINT CK_s_module_page_type CHECK (b_module_type = 'page'),
CONSTRAINT CK_s_module_page_mode CHECK (b_page_mode IN ('generic', 'custom')),
CONSTRAINT FK_s_module_page_module FOREIGN KEY (b_module_id, b_module_type)
REFERENCES dbo.s_module (b_id, b_module_type)
);
CREATE TABLE dbo.s_module_data (
b_module_id bigint NOT NULL,
b_module_type varchar(20) NOT NULL CONSTRAINT DF_s_module_data_type DEFAULT ('data'),
b_viewtable varchar(128) NOT NULL,
b_savetable varchar(128) NULL,
b_keyfield varchar(50) NOT NULL,
b_orderfield varchar(500) NULL,
CONSTRAINT PK_s_module_data PRIMARY KEY (b_module_id),
CONSTRAINT CK_s_module_data_type CHECK (b_module_type = 'data'),
CONSTRAINT FK_s_module_data_module FOREIGN KEY (b_module_id, b_module_type)
REFERENCES dbo.s_module (b_id, b_module_type)
);
CREATE TABLE dbo.s_module_report (
b_module_id bigint NOT NULL,
b_module_type varchar(20) NOT NULL CONSTRAINT DF_s_module_report_type DEFAULT ('report'),
b_data_module_id bigint NOT NULL,
b_profile_id bigint NOT NULL,
b_renderer_key varchar(100) NOT NULL,
b_options nvarchar(max) NULL,
CONSTRAINT PK_s_module_report PRIMARY KEY (b_module_id),
CONSTRAINT CK_s_module_report_type CHECK (b_module_type = 'report'),
CONSTRAINT FK_s_module_report_module FOREIGN KEY (b_module_id, b_module_type)
REFERENCES dbo.s_module (b_id, b_module_type)
);
CREATE TABLE dbo.s_module_dashboard (
b_module_id bigint NOT NULL,
b_module_type varchar(20) NOT NULL CONSTRAINT DF_s_module_dashboard_type DEFAULT ('dashboard'),
b_component_key varchar(100) NOT NULL,
b_options nvarchar(max) NULL,
CONSTRAINT PK_s_module_dashboard PRIMARY KEY (b_module_id),
CONSTRAINT CK_s_module_dashboard_type CHECK (b_module_type = 'dashboard'),
CONSTRAINT FK_s_module_dashboard_module FOREIGN KEY (b_module_id, b_module_type)
REFERENCES dbo.s_module (b_id, b_module_type)
);
CREATE TABLE dbo.s_module_workflow (
b_module_id bigint NOT NULL,
b_module_type varchar(20) NOT NULL CONSTRAINT DF_s_module_workflow_type DEFAULT ('workflow'),
b_engine_key varchar(100) NOT NULL,
b_options nvarchar(max) NULL,
CONSTRAINT PK_s_module_workflow PRIMARY KEY (b_module_id),
CONSTRAINT CK_s_module_workflow_type CHECK (b_module_type = 'workflow'),
CONSTRAINT FK_s_module_workflow_module FOREIGN KEY (b_module_id, b_module_type)
REFERENCES dbo.s_module (b_id, b_module_type)
);
CREATE TABLE dbo.s_module_profile (
b_id bigint NOT NULL,
b_module_id bigint NOT NULL,
b_module_type varchar(20) NOT NULL CONSTRAINT DF_s_module_profile_type DEFAULT ('data'),
b_code varchar(50) NOT NULL,
b_name nvarchar(100) NOT NULL,
b_i18n varchar(150) NOT NULL,
b_default int NOT NULL CONSTRAINT DF_s_module_profile_default DEFAULT (0),
b_canuse int NOT NULL CONSTRAINT DF_s_module_profile_canuse DEFAULT (1),
b_xh int NOT NULL CONSTRAINT DF_s_module_profile_xh DEFAULT (0),
CONSTRAINT PK_s_module_profile PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_profile_code UNIQUE (b_module_id, b_code),
CONSTRAINT UQ_s_module_profile_module_id UNIQUE (b_module_id, b_id),
CONSTRAINT CK_s_module_profile_type CHECK (b_module_type = 'data'),
CONSTRAINT CK_s_module_profile_flags CHECK (b_default IN (0, 1) AND b_canuse IN (0, 1)),
CONSTRAINT FK_s_module_profile_module FOREIGN KEY (b_module_id, b_module_type)
REFERENCES dbo.s_module (b_id, b_module_type)
);
CREATE UNIQUE INDEX UX_s_module_profile_default
ON dbo.s_module_profile (b_module_id) WHERE b_default = 1;
CREATE INDEX IX_s_module_profile_module
ON dbo.s_module_profile (b_module_id, b_canuse, b_xh, b_id);
ALTER TABLE dbo.s_module_report
ADD CONSTRAINT FK_s_module_report_profile
FOREIGN KEY (b_data_module_id, b_profile_id)
REFERENCES dbo.s_module_profile (b_module_id, b_id);
CREATE TABLE dbo.s_function_node (
b_id bigint NOT NULL,
b_code varchar(50) NOT NULL,
b_parent_id bigint NULL,
b_node_type varchar(20) NOT NULL,
b_module_id bigint NULL,
b_module_type varchar(20) NULL,
b_name nvarchar(150) NOT NULL,
b_i18n varchar(150) NOT NULL,
b_canmenu int NOT NULL CONSTRAINT DF_s_function_node_canmenu DEFAULT (1),
b_canuse int NOT NULL CONSTRAINT DF_s_function_node_canuse DEFAULT (1),
b_xh int NOT NULL CONSTRAINT DF_s_function_node_xh DEFAULT (0),
CONSTRAINT PK_s_function_node PRIMARY KEY (b_id),
CONSTRAINT UQ_s_function_node_code UNIQUE (b_code),
CONSTRAINT CK_s_function_node_type CHECK (b_node_type IN ('directory', 'entry')),
CONSTRAINT CK_s_function_node_parent CHECK (b_parent_id IS NULL OR b_parent_id <> b_id),
CONSTRAINT CK_s_function_node_target CHECK (
(b_node_type = 'directory' AND b_module_id IS NULL AND b_module_type IS NULL)
OR (b_node_type = 'entry' AND b_module_id IS NOT NULL AND b_module_type = 'page')
),
CONSTRAINT CK_s_function_node_flags CHECK (b_canmenu IN (0, 1) AND b_canuse IN (0, 1)),
CONSTRAINT FK_s_function_node_module FOREIGN KEY (b_module_id, b_module_type)
REFERENCES dbo.s_module (b_id, b_module_type)
);
CREATE INDEX IX_s_function_node_parent
ON dbo.s_function_node (b_parent_id, b_canuse, b_xh, b_id);
CREATE INDEX IX_s_function_node_module
ON dbo.s_function_node (b_module_id, b_canuse, b_id);
CREATE TABLE dbo.s_page_node (
b_id bigint NOT NULL,
b_code varchar(50) NOT NULL,
b_page_module_id bigint NOT NULL,
b_page_module_type varchar(20) NOT NULL CONSTRAINT DF_s_page_node_page_type DEFAULT ('page'),
b_parent_id bigint NULL,
b_node_type varchar(20) NOT NULL,
b_module_id bigint NULL,
b_module_type varchar(20) NULL,
b_profile_id bigint NULL,
b_name nvarchar(150) NOT NULL,
b_i18n varchar(150) NOT NULL,
b_fixed_condition nvarchar(max) NULL,
b_param_mapping nvarchar(max) NULL,
b_permission_required int NOT NULL CONSTRAINT DF_s_page_node_permission DEFAULT (0),
b_canuse int NOT NULL CONSTRAINT DF_s_page_node_canuse DEFAULT (1),
b_xh int NOT NULL CONSTRAINT DF_s_page_node_xh DEFAULT (0),
CONSTRAINT PK_s_page_node PRIMARY KEY (b_id),
CONSTRAINT UQ_s_page_node_code UNIQUE (b_page_module_id, b_code),
CONSTRAINT UQ_s_page_node_page_id UNIQUE (b_page_module_id, b_id),
CONSTRAINT CK_s_page_node_page_type CHECK (b_page_module_type = 'page'),
CONSTRAINT CK_s_page_node_type CHECK (b_node_type IN ('group', 'tab', 'section', 'module_ref')),
CONSTRAINT CK_s_page_node_parent CHECK (b_parent_id IS NULL OR b_parent_id <> b_id),
CONSTRAINT CK_s_page_node_target CHECK (
(b_node_type IN ('group', 'tab', 'section')
AND b_module_id IS NULL AND b_module_type IS NULL AND b_profile_id IS NULL)
OR (b_node_type = 'module_ref' AND b_module_id IS NOT NULL
AND b_module_type IN ('data', 'report', 'dashboard', 'workflow')
AND ((b_module_type = 'data' AND b_profile_id IS NOT NULL)
OR (b_module_type <> 'data' AND b_profile_id IS NULL)))
),
CONSTRAINT CK_s_page_node_flags CHECK (b_permission_required IN (0, 1) AND b_canuse IN (0, 1)),
CONSTRAINT FK_s_page_node_page FOREIGN KEY (b_page_module_id, b_page_module_type)
REFERENCES dbo.s_module (b_id, b_module_type),
CONSTRAINT FK_s_page_node_module FOREIGN KEY (b_module_id, b_module_type)
REFERENCES dbo.s_module (b_id, b_module_type),
CONSTRAINT FK_s_page_node_profile FOREIGN KEY (b_module_id, b_profile_id)
REFERENCES dbo.s_module_profile (b_module_id, b_id)
);
CREATE INDEX IX_s_page_node_tree
ON dbo.s_page_node (b_page_module_id, b_parent_id, b_canuse, b_xh, b_id);
CREATE INDEX IX_s_page_node_module
ON dbo.s_page_node (b_module_id, b_profile_id, b_page_module_id, b_canuse);
CREATE TABLE dbo.s_module_field (
b_id bigint NOT NULL,
b_module_id bigint NOT NULL,
b_module_type varchar(20) NOT NULL CONSTRAINT DF_s_module_field_type DEFAULT ('data'),
b_field varchar(50) NOT NULL,
b_name nvarchar(100) NOT NULL,
b_i18n varchar(150) NOT NULL,
b_type varchar(30) NOT NULL,
b_default_value nvarchar(500) NULL,
b_options nvarchar(max) NULL,
b_canuse int NOT NULL CONSTRAINT DF_s_module_field_canuse DEFAULT (1),
CONSTRAINT PK_s_module_field PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_field UNIQUE (b_module_id, b_field),
CONSTRAINT UQ_s_module_field_module_id UNIQUE (b_module_id, b_id),
CONSTRAINT CK_s_module_field_type CHECK (b_module_type = 'data'),
CONSTRAINT CK_s_module_field_canuse CHECK (b_canuse IN (0, 1)),
CONSTRAINT FK_s_module_field_module FOREIGN KEY (b_module_id, b_module_type)
REFERENCES dbo.s_module (b_id, b_module_type)
);
CREATE INDEX IX_s_module_field_module ON dbo.s_module_field (b_module_id, b_canuse, b_id);
CREATE TABLE dbo.s_module_layout_group (
b_id bigint NOT NULL,
b_module_id bigint NOT NULL,
b_profile_id bigint NOT NULL,
b_parent_id bigint NULL,
b_scene varchar(20) NOT NULL,
b_name nvarchar(100) NOT NULL,
b_i18n varchar(150) NOT NULL,
b_xh int NOT NULL CONSTRAINT DF_s_module_layout_group_xh DEFAULT (0),
b_canuse int NOT NULL CONSTRAINT DF_s_module_layout_group_canuse DEFAULT (1),
CONSTRAINT PK_s_module_layout_group PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_layout_group_profile_id UNIQUE (b_profile_id, b_id),
CONSTRAINT CK_s_module_layout_group_scene CHECK (b_scene IN ('list', 'form', 'shared')),
CONSTRAINT CK_s_module_layout_group_parent CHECK (b_parent_id IS NULL OR b_parent_id <> b_id),
CONSTRAINT CK_s_module_layout_group_canuse CHECK (b_canuse IN (0, 1)),
CONSTRAINT FK_s_module_layout_group_profile FOREIGN KEY (b_module_id, b_profile_id)
REFERENCES dbo.s_module_profile (b_module_id, b_id),
CONSTRAINT FK_s_module_layout_group_parent FOREIGN KEY (b_profile_id, b_parent_id)
REFERENCES dbo.s_module_layout_group (b_profile_id, b_id)
);
CREATE INDEX IX_s_module_layout_group_tree
ON dbo.s_module_layout_group (b_profile_id, b_scene, b_parent_id, b_xh, b_id);
CREATE TABLE dbo.s_module_field_list (
b_id bigint NOT NULL,
b_module_id bigint NOT NULL,
b_profile_id bigint NOT NULL,
b_field_id bigint NOT NULL,
b_group_id bigint NULL,
b_i18n varchar(150) NULL,
b_visible int NOT NULL CONSTRAINT DF_s_module_field_list_visible DEFAULT (1),
b_xh int NOT NULL CONSTRAINT DF_s_module_field_list_xh DEFAULT (0),
b_width int NULL,
CONSTRAINT PK_s_module_field_list PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_field_list UNIQUE (b_profile_id, b_field_id),
CONSTRAINT CK_s_module_field_list_visible CHECK (b_visible IN (0, 1)),
CONSTRAINT FK_s_module_field_list_profile FOREIGN KEY (b_module_id, b_profile_id)
REFERENCES dbo.s_module_profile (b_module_id, b_id),
CONSTRAINT FK_s_module_field_list_field FOREIGN KEY (b_module_id, b_field_id)
REFERENCES dbo.s_module_field (b_module_id, b_id),
CONSTRAINT FK_s_module_field_list_group FOREIGN KEY (b_profile_id, b_group_id)
REFERENCES dbo.s_module_layout_group (b_profile_id, b_id)
);
CREATE INDEX IX_s_module_field_list_order
ON dbo.s_module_field_list (b_profile_id, b_group_id, b_xh, b_id);
CREATE TABLE dbo.s_module_field_form (
b_id bigint NOT NULL,
b_module_id bigint NOT NULL,
b_profile_id bigint NOT NULL,
b_field_id bigint NOT NULL,
b_group_id bigint NULL,
b_required int NOT NULL CONSTRAINT DF_s_module_field_form_required DEFAULT (0),
b_readonly int NOT NULL CONSTRAINT DF_s_module_field_form_readonly DEFAULT (0),
b_disabled int NOT NULL CONSTRAINT DF_s_module_field_form_disabled DEFAULT (0),
b_visible int NOT NULL CONSTRAINT DF_s_module_field_form_visible DEFAULT (1),
b_xh int NOT NULL CONSTRAINT DF_s_module_field_form_xh DEFAULT (0),
CONSTRAINT PK_s_module_field_form PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_field_form UNIQUE (b_profile_id, b_field_id),
CONSTRAINT CK_s_module_field_form_flags CHECK (
b_required IN (0, 1) AND b_readonly IN (0, 1)
AND b_disabled IN (0, 1) AND b_visible IN (0, 1)
),
CONSTRAINT FK_s_module_field_form_profile FOREIGN KEY (b_module_id, b_profile_id)
REFERENCES dbo.s_module_profile (b_module_id, b_id),
CONSTRAINT FK_s_module_field_form_field FOREIGN KEY (b_module_id, b_field_id)
REFERENCES dbo.s_module_field (b_module_id, b_id),
CONSTRAINT FK_s_module_field_form_group FOREIGN KEY (b_profile_id, b_group_id)
REFERENCES dbo.s_module_layout_group (b_profile_id, b_id)
);
CREATE INDEX IX_s_module_field_form_order
ON dbo.s_module_field_form (b_profile_id, b_group_id, b_xh, b_id);
CREATE TABLE dbo.s_module_field_query (
b_id bigint NOT NULL,
b_module_id bigint NOT NULL,
b_profile_id bigint NOT NULL,
b_field_id bigint NOT NULL,
b_component varchar(30) NOT NULL,
b_operator varchar(20) NOT NULL,
b_default_value nvarchar(500) NULL,
b_xh int NOT NULL CONSTRAINT DF_s_module_field_query_xh DEFAULT (0),
b_canuse int NOT NULL CONSTRAINT DF_s_module_field_query_canuse DEFAULT (1),
CONSTRAINT PK_s_module_field_query PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_field_query UNIQUE (b_profile_id, b_field_id),
CONSTRAINT CK_s_module_field_query_operator CHECK (b_operator IN ('=', 'like', 'between', 'in')),
CONSTRAINT CK_s_module_field_query_canuse CHECK (b_canuse IN (0, 1)),
CONSTRAINT FK_s_module_field_query_profile FOREIGN KEY (b_module_id, b_profile_id)
REFERENCES dbo.s_module_profile (b_module_id, b_id),
CONSTRAINT FK_s_module_field_query_field FOREIGN KEY (b_module_id, b_field_id)
REFERENCES dbo.s_module_field (b_module_id, b_id)
);
CREATE INDEX IX_s_module_field_query_order
ON dbo.s_module_field_query (b_profile_id, b_canuse, b_xh, b_id);
CREATE TABLE dbo.s_module_action (
b_id bigint NOT NULL,
b_module_id bigint NOT NULL,
b_code varchar(50) NOT NULL,
b_name nvarchar(100) NOT NULL,
b_i18n varchar(150) NOT NULL,
b_xh int NOT NULL CONSTRAINT DF_s_module_action_xh DEFAULT (0),
b_canuse int NOT NULL CONSTRAINT DF_s_module_action_canuse DEFAULT (1),
CONSTRAINT PK_s_module_action PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_action UNIQUE (b_module_id, b_code),
CONSTRAINT UQ_s_module_action_module_id UNIQUE (b_module_id, b_id),
CONSTRAINT CK_s_module_action_canuse CHECK (b_canuse IN (0, 1)),
CONSTRAINT FK_s_module_action_module FOREIGN KEY (b_module_id) REFERENCES dbo.s_module (b_id)
);
CREATE INDEX IX_s_module_action_order ON dbo.s_module_action (b_module_id, b_canuse, b_xh, b_id);
CREATE TABLE dbo.s_module_relation (
b_id bigint NOT NULL,
b_code varchar(50) NOT NULL,
b_name nvarchar(100) NOT NULL,
b_i18n varchar(150) NOT NULL,
b_parent_module_id bigint NOT NULL,
b_parent_field_id bigint NOT NULL,
b_child_module_id bigint NOT NULL,
b_child_field_id bigint NOT NULL,
b_relation_type varchar(20) NOT NULL,
b_canuse int NOT NULL CONSTRAINT DF_s_module_relation_canuse DEFAULT (1),
CONSTRAINT PK_s_module_relation PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_relation_code UNIQUE (b_parent_module_id, b_code),
CONSTRAINT CK_s_module_relation_type CHECK (b_relation_type IN ('one_to_one', 'one_to_many')),
CONSTRAINT CK_s_module_relation_modules CHECK (b_parent_module_id <> b_child_module_id),
CONSTRAINT FK_s_module_relation_parent_field FOREIGN KEY (b_parent_module_id, b_parent_field_id)
REFERENCES dbo.s_module_field (b_module_id, b_id),
CONSTRAINT FK_s_module_relation_child_field FOREIGN KEY (b_child_module_id, b_child_field_id)
REFERENCES dbo.s_module_field (b_module_id, b_id)
);
CREATE INDEX IX_s_module_relation_child ON dbo.s_module_relation (b_child_module_id, b_canuse, b_id);
CREATE TABLE dbo.s_module_auto_code (
b_id bigint NOT NULL,
b_module_id bigint NOT NULL,
b_field_id bigint NOT NULL,
b_prefix nvarchar(100) NOT NULL CONSTRAINT DF_s_module_auto_code_prefix DEFAULT (N''),
b_date_format varchar(30) NOT NULL CONSTRAINT DF_s_module_auto_code_date_format DEFAULT ('yyyyMM'),
b_separator nvarchar(10) NOT NULL CONSTRAINT DF_s_module_auto_code_separator DEFAULT (N'-'),
b_sequence_width int NOT NULL CONSTRAINT DF_s_module_auto_code_width DEFAULT (5),
b_reset_type varchar(10) NOT NULL CONSTRAINT DF_s_module_auto_code_reset DEFAULT ('month'),
b_start_value bigint NOT NULL CONSTRAINT DF_s_module_auto_code_start DEFAULT (1),
b_current_period varchar(8) NULL,
b_current_value bigint NOT NULL CONSTRAINT DF_s_module_auto_code_current DEFAULT (0),
b_canuse int NOT NULL CONSTRAINT DF_s_module_auto_code_canuse DEFAULT (1),
CONSTRAINT PK_s_module_auto_code PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_auto_code_module UNIQUE (b_module_id),
CONSTRAINT CK_s_module_auto_code_reset CHECK (b_reset_type IN ('none', 'year', 'month', 'day')),
CONSTRAINT FK_s_module_auto_code_field FOREIGN KEY (b_module_id, b_field_id)
REFERENCES dbo.s_module_field (b_module_id, b_id)
);
CREATE TABLE dbo.s_module_import (
b_id bigint NOT NULL,
b_module_id bigint NOT NULL,
b_profile_id bigint NOT NULL,
b_mode varchar(30) NOT NULL,
b_options nvarchar(max) NULL,
b_canuse int NOT NULL CONSTRAINT DF_s_module_import_canuse DEFAULT (1),
CONSTRAINT PK_s_module_import PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_import_profile UNIQUE (b_profile_id),
CONSTRAINT FK_s_module_import_profile FOREIGN KEY (b_module_id, b_profile_id)
REFERENCES dbo.s_module_profile (b_module_id, b_id)
);
CREATE TABLE dbo.s_module_export (
b_id bigint NOT NULL,
b_module_id bigint NOT NULL,
b_profile_id bigint NOT NULL,
b_mode varchar(30) NOT NULL,
b_options nvarchar(max) NULL,
b_canuse int NOT NULL CONSTRAINT DF_s_module_export_canuse DEFAULT (1),
CONSTRAINT PK_s_module_export PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_export_profile UNIQUE (b_profile_id),
CONSTRAINT FK_s_module_export_profile FOREIGN KEY (b_module_id, b_profile_id)
REFERENCES dbo.s_module_profile (b_module_id, b_id)
);
CREATE TABLE dbo.s_module_file (
b_id bigint NOT NULL,
b_module_id bigint NOT NULL,
b_category_mode varchar(30) NOT NULL,
b_options nvarchar(max) NULL,
b_canuse int NOT NULL CONSTRAINT DF_s_module_file_canuse DEFAULT (1),
CONSTRAINT PK_s_module_file PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_file_module UNIQUE (b_module_id),
CONSTRAINT FK_s_module_file_module FOREIGN KEY (b_module_id) REFERENCES dbo.s_module (b_id)
);
CREATE TABLE dbo.s_module_workflow_binding (
b_id bigint NOT NULL,
b_module_id bigint NOT NULL,
b_action_id bigint NULL,
b_workflow_module_id bigint NOT NULL,
b_workflow_module_type varchar(20) NOT NULL CONSTRAINT DF_s_module_workflow_binding_type DEFAULT ('workflow'),
b_event_code varchar(50) NOT NULL,
b_xh int NOT NULL CONSTRAINT DF_s_module_workflow_binding_xh DEFAULT (0),
b_canuse int NOT NULL CONSTRAINT DF_s_module_workflow_binding_canuse DEFAULT (1),
CONSTRAINT PK_s_module_workflow_binding PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_workflow_binding UNIQUE (b_module_id, b_event_code, b_workflow_module_id),
CONSTRAINT CK_s_module_workflow_binding_type CHECK (b_workflow_module_type = 'workflow'),
CONSTRAINT FK_s_module_workflow_binding_module FOREIGN KEY (b_module_id) REFERENCES dbo.s_module (b_id),
CONSTRAINT FK_s_module_workflow_binding_action FOREIGN KEY (b_module_id, b_action_id)
REFERENCES dbo.s_module_action (b_module_id, b_id),
CONSTRAINT FK_s_module_workflow_binding_workflow FOREIGN KEY (b_workflow_module_id, b_workflow_module_type)
REFERENCES dbo.s_module (b_id, b_module_type)
);
CREATE TABLE dbo.b_role (
b_id bigint NOT NULL,
b_code varchar(50) NOT NULL,
b_name nvarchar(100) NOT NULL,
b_i18n varchar(150) NOT NULL,
b_is_super int NOT NULL CONSTRAINT DF_b_role_super DEFAULT (0),
b_canuse int NOT NULL CONSTRAINT DF_b_role_canuse DEFAULT (1),
b_xh int NOT NULL CONSTRAINT DF_b_role_xh DEFAULT (0),
CONSTRAINT PK_b_role PRIMARY KEY (b_id),
CONSTRAINT UQ_b_role_code UNIQUE (b_code),
CONSTRAINT CK_b_role_flags CHECK (b_is_super IN (0, 1) AND b_canuse IN (0, 1))
);
CREATE TABLE dbo.b_user_role (
b_id bigint NOT NULL,
b_user_id bigint NOT NULL,
b_role_id bigint NOT NULL,
b_inputuser_id bigint NOT NULL,
b_inputdatetime datetime2 NOT NULL CONSTRAINT DF_b_user_role_time DEFAULT (SYSDATETIME()),
CONSTRAINT PK_b_user_role PRIMARY KEY (b_id),
CONSTRAINT UQ_b_user_role UNIQUE (b_user_id, b_role_id),
CONSTRAINT FK_b_user_role_user FOREIGN KEY (b_user_id) REFERENCES dbo.b_user (b_id),
CONSTRAINT FK_b_user_role_role FOREIGN KEY (b_role_id) REFERENCES dbo.b_role (b_id)
);
CREATE TABLE dbo.b_role_function_node (
b_id bigint NOT NULL,
b_role_id bigint NOT NULL,
b_function_node_id bigint NOT NULL,
CONSTRAINT PK_b_role_function_node PRIMARY KEY (b_id),
CONSTRAINT UQ_b_role_function_node UNIQUE (b_role_id, b_function_node_id),
CONSTRAINT FK_b_role_function_node_role FOREIGN KEY (b_role_id) REFERENCES dbo.b_role (b_id),
CONSTRAINT FK_b_role_function_node_node FOREIGN KEY (b_function_node_id) REFERENCES dbo.s_function_node (b_id)
);
CREATE TABLE dbo.b_role_page_node (
b_id bigint NOT NULL,
b_role_id bigint NOT NULL,
b_page_node_id bigint NOT NULL,
CONSTRAINT PK_b_role_page_node PRIMARY KEY (b_id),
CONSTRAINT UQ_b_role_page_node UNIQUE (b_role_id, b_page_node_id),
CONSTRAINT FK_b_role_page_node_role FOREIGN KEY (b_role_id) REFERENCES dbo.b_role (b_id),
CONSTRAINT FK_b_role_page_node_node FOREIGN KEY (b_page_node_id) REFERENCES dbo.s_page_node (b_id)
);
CREATE TABLE dbo.b_role_action (
b_id bigint NOT NULL,
b_role_id bigint NOT NULL,
b_action_id bigint NOT NULL,
CONSTRAINT PK_b_role_action PRIMARY KEY (b_id),
CONSTRAINT UQ_b_role_action UNIQUE (b_role_id, b_action_id),
CONSTRAINT FK_b_role_action_role FOREIGN KEY (b_role_id) REFERENCES dbo.b_role (b_id),
CONSTRAINT FK_b_role_action_action FOREIGN KEY (b_action_id) REFERENCES dbo.s_module_action (b_id)
);
/* Reserved contract for later backend row-scope enforcement. */
CREATE TABLE dbo.b_role_data_scope (
b_id bigint NOT NULL,
b_role_id bigint NOT NULL,
b_module_id bigint NOT NULL,
b_scope_type varchar(20) NOT NULL,
b_options nvarchar(max) NULL,
CONSTRAINT PK_b_role_data_scope PRIMARY KEY (b_id),
CONSTRAINT UQ_b_role_data_scope UNIQUE (b_role_id, b_module_id),
CONSTRAINT CK_b_role_data_scope_type CHECK (
b_scope_type IN ('all', 'self', 'department', 'custom')
),
CONSTRAINT FK_b_role_data_scope_role FOREIGN KEY (b_role_id) REFERENCES dbo.b_role (b_id),
CONSTRAINT FK_b_role_data_scope_module FOREIGN KEY (b_module_id) REFERENCES dbo.s_module (b_id)
);
CREATE INDEX IX_b_role_data_scope_module
ON dbo.b_role_data_scope (b_module_id, b_role_id);
CREATE TABLE dbo.b_user_function_node (
b_id bigint NOT NULL,
b_user_id bigint NOT NULL,
b_function_node_id bigint NOT NULL,
b_inputuser_id bigint NOT NULL,
b_inputdatetime datetime2 NOT NULL CONSTRAINT DF_b_user_function_node_time DEFAULT (SYSDATETIME()),
CONSTRAINT PK_b_user_function_node PRIMARY KEY (b_id),
CONSTRAINT UQ_b_user_function_node UNIQUE (b_user_id, b_function_node_id),
CONSTRAINT FK_b_user_function_node_user FOREIGN KEY (b_user_id) REFERENCES dbo.b_user (b_id),
CONSTRAINT FK_b_user_function_node_node FOREIGN KEY (b_function_node_id) REFERENCES dbo.s_function_node (b_id)
);
CREATE TABLE dbo.b_user_page_node (
b_id bigint NOT NULL,
b_user_id bigint NOT NULL,
b_page_node_id bigint NOT NULL,
b_inputuser_id bigint NOT NULL,
b_inputdatetime datetime2 NOT NULL CONSTRAINT DF_b_user_page_node_time DEFAULT (SYSDATETIME()),
CONSTRAINT PK_b_user_page_node PRIMARY KEY (b_id),
CONSTRAINT UQ_b_user_page_node UNIQUE (b_user_id, b_page_node_id),
CONSTRAINT FK_b_user_page_node_user FOREIGN KEY (b_user_id) REFERENCES dbo.b_user (b_id),
CONSTRAINT FK_b_user_page_node_node FOREIGN KEY (b_page_node_id) REFERENCES dbo.s_page_node (b_id)
);
CREATE TABLE dbo.b_user_action (
b_id bigint NOT NULL,
b_user_id bigint NOT NULL,
b_action_id bigint NOT NULL,
b_inputuser_id bigint NOT NULL,
b_inputdatetime datetime2 NOT NULL CONSTRAINT DF_b_user_action_time DEFAULT (SYSDATETIME()),
CONSTRAINT PK_b_user_action PRIMARY KEY (b_id),
CONSTRAINT UQ_b_user_action UNIQUE (b_user_id, b_action_id),
CONSTRAINT FK_b_user_action_user FOREIGN KEY (b_user_id) REFERENCES dbo.b_user (b_id),
CONSTRAINT FK_b_user_action_action FOREIGN KEY (b_action_id) REFERENCES dbo.s_module_action (b_id)
);
CREATE INDEX IX_b_user_role_user ON dbo.b_user_role (b_user_id, b_role_id);
CREATE INDEX IX_b_user_function_node_user ON dbo.b_user_function_node (b_user_id, b_function_node_id);
CREATE INDEX IX_b_user_page_node_user ON dbo.b_user_page_node (b_user_id, b_page_node_id);
CREATE INDEX IX_b_user_action_user ON dbo.b_user_action (b_user_id, b_action_id);
/* Convert resources. Directories move exclusively to the function tree. */
INSERT INTO dbo.s_module (b_id, b_code, b_name, b_i18n, b_module_type, b_canuse)
SELECT b_id, b_code, b_name, 'meta.module.' + CONVERT(varchar(30), b_id), b_module_type, b_canuse
FROM dbo.z_legacy_module
WHERE b_module_type IN ('page', 'data');
INSERT INTO dbo.s_module_page (b_module_id, b_route, b_page_mode, b_component_key)
SELECT
b_id,
CASE WHEN b_code = 'm_metadata' THEN '/system/module-management' ELSE b_route END,
'custom',
CASE b_route
WHEN '/base/othercompany' THEN 'base_othercompany'
WHEN '/base/contact' THEN 'base_contact'
WHEN '/base/otherdata' THEN 'base_otherdata'
WHEN '/system/metadata' THEN 'module_management'
WHEN '/system/module-management' THEN 'module_management'
WHEN '/system/i18n-type' THEN 'i18n_type'
WHEN '/system/login-log' THEN 'login_log'
WHEN '/system/user' THEN 'user_management'
ELSE b_code
END
FROM dbo.z_legacy_module
WHERE b_module_type = 'page';
INSERT INTO dbo.s_module_data (b_module_id, b_viewtable, b_savetable, b_keyfield, b_orderfield)
SELECT b_id, b_viewtable, b_savetable, ISNULL(NULLIF(b_keyfield, ''), 'b_id'), b_orderfield
FROM dbo.z_legacy_module
WHERE b_module_type = 'data';
INSERT INTO dbo.s_module_profile (
b_id, b_module_id, b_code, b_name, b_i18n, b_default, b_canuse, b_xh
)
SELECT b_id, b_id, 'default', N'默认', 'meta.profile.' + CONVERT(varchar(30), b_id), 1, 1, 10
FROM dbo.z_legacy_module
WHERE b_module_type = 'data';
INSERT INTO dbo.s_function_node (
b_id, b_code, b_parent_id, b_node_type, b_module_id, b_module_type,
b_name, b_i18n, b_canmenu, b_canuse, b_xh
)
SELECT
b_id, b_code, b_parent_id,
CASE WHEN b_module_type = 'directory' THEN 'directory' ELSE 'entry' END,
CASE WHEN b_module_type = 'page' THEN b_id ELSE NULL END,
CASE WHEN b_module_type = 'page' THEN 'page' ELSE NULL END,
b_name, 'meta.node.' + CONVERT(varchar(30), b_id), b_canmenu, b_canuse, b_xh
FROM dbo.z_legacy_module
WHERE b_module_type IN ('directory', 'page');
IF OBJECT_ID(N'dbo.b_other_bmfl', N'U') IS NOT NULL
BEGIN
DECLARE @OtherDataPageId bigint;
SELECT @OtherDataPageId = b_id FROM dbo.z_legacy_module
WHERE b_code = 'base_otherdata' AND b_module_type = 'page';
IF @OtherDataPageId IS NOT NULL
BEGIN
IF EXISTS (
SELECT 1
FROM dbo.b_other_bmfl source_row
LEFT JOIN dbo.z_legacy_module module_row
ON module_row.b_code = source_row.b_module_code
AND module_row.b_module_type = 'data'
WHERE source_row.b_node_type = 'module' AND module_row.b_id IS NULL
)
THROW 53304, N'b_other_bmfl contains unresolved module references.', 1;
INSERT INTO dbo.s_page_node (
b_id, b_code, b_page_module_id, b_parent_id, b_node_type,
b_module_id, b_module_type, b_profile_id, b_name, b_i18n, b_canuse, b_xh
)
SELECT
source_row.b_id,
'node_' + CONVERT(varchar(30), source_row.b_id),
@OtherDataPageId,
source_row.b_parent_id,
CASE WHEN source_row.b_node_type = 'module' THEN 'module_ref' ELSE 'group' END,
module_row.b_id,
CASE WHEN module_row.b_id IS NULL THEN NULL ELSE 'data' END,
module_row.b_id,
source_row.b_name,
'meta.node.' + CONVERT(varchar(30), source_row.b_id),
source_row.b_canuse,
source_row.b_xh
FROM dbo.b_other_bmfl source_row
LEFT JOIN dbo.z_legacy_module module_row
ON module_row.b_code = source_row.b_module_code
AND module_row.b_module_type = 'data';
END;
END;
INSERT INTO dbo.s_page_node (
b_id, b_code, b_page_module_id, b_parent_id, b_node_type,
b_module_id, b_module_type, b_profile_id, b_name, b_i18n, b_canuse, b_xh
)
SELECT
data_module.b_id,
'module_' + data_module.b_code,
data_module.b_parent_id,
NULL,
'module_ref',
data_module.b_id,
'data',
data_module.b_id,
data_module.b_name,
'meta.node.' + CONVERT(varchar(30), data_module.b_id),
data_module.b_canuse,
data_module.b_xh
FROM dbo.z_legacy_module data_module
INNER JOIN dbo.z_legacy_module page_module
ON page_module.b_id = data_module.b_parent_id AND page_module.b_module_type = 'page'
WHERE data_module.b_module_type = 'data'
AND NOT EXISTS (
SELECT 1 FROM dbo.s_page_node node WHERE node.b_module_id = data_module.b_id
);
INSERT INTO dbo.s_module_field (
b_id, b_module_id, b_field, b_name, b_i18n, b_type,
b_default_value, b_options, b_canuse
)
SELECT
b_id, b_module_id, b_field, b_name,
'meta.field.' + CONVERT(varchar(30), b_id), b_type,
b_default_value, b_options, b_canuse
FROM dbo.z_legacy_module_field;
INSERT INTO dbo.s_module_layout_group (
b_id, b_module_id, b_profile_id, b_parent_id, b_scene,
b_name, b_i18n, b_xh, b_canuse
)
SELECT
b_id, b_module_id, b_module_id, b_parent_id, 'shared',
b_title, 'meta.group.' + CONVERT(varchar(30), b_id), b_xh, b_canuse
FROM dbo.z_legacy_module_field_group;
INSERT INTO dbo.s_module_field_list (
b_id, b_module_id, b_profile_id, b_field_id, b_group_id,
b_i18n, b_visible, b_xh, b_width
)
SELECT b_id, b_module_id, b_module_id, b_field_id, b_group_id,
b_i18n, b_visible, b_xh, b_width
FROM dbo.z_legacy_module_field_list
WHERE b_field_id IS NOT NULL;
INSERT INTO dbo.s_module_field_form (
b_id, b_module_id, b_profile_id, b_field_id, b_group_id,
b_required, b_readonly, b_disabled, b_visible, b_xh
)
SELECT b_id, b_module_id, b_module_id, b_field_id, b_group_id,
b_required, b_readonly, b_disabled, b_visible, b_xh
FROM dbo.z_legacy_module_field_edit;
INSERT INTO dbo.s_module_field_query (
b_id, b_module_id, b_profile_id, b_field_id, b_component,
b_operator, b_default_value, b_xh, b_canuse
)
SELECT b_id, b_module_id, b_module_id, b_field_id, b_component,
b_operator, b_default_value, b_xh, b_canuse
FROM dbo.z_legacy_module_field_query;
INSERT INTO dbo.s_module_action (
b_id, b_module_id, b_code, b_name, b_i18n, b_xh, b_canuse
)
SELECT b_id, b_module_id, b_code, b_name,
'meta.action.' + CONVERT(varchar(30), b_id), b_xh, b_canuse
FROM dbo.z_legacy_module_power
WHERE b_module_id IN (SELECT b_id FROM dbo.s_module);
ALTER TABLE dbo.s_function_node
ADD CONSTRAINT FK_s_function_node_parent
FOREIGN KEY (b_parent_id) REFERENCES dbo.s_function_node (b_id);
ALTER TABLE dbo.s_page_node
ADD CONSTRAINT FK_s_page_node_parent
FOREIGN KEY (b_page_module_id, b_parent_id)
REFERENCES dbo.s_page_node (b_page_module_id, b_id);
IF OBJECT_ID(N'dbo.z_legacy_module_auto_code', N'U') IS NOT NULL
BEGIN
INSERT INTO dbo.s_module_auto_code (
b_id, b_module_id, b_field_id, b_prefix, b_date_format, b_separator,
b_sequence_width, b_reset_type, b_start_value, b_current_period,
b_current_value, b_canuse
)
SELECT b_id, b_module_id, b_field_id, b_prefix, b_date_format, b_separator,
b_sequence_width, b_reset_type, b_start_value, b_current_period,
b_current_value, b_canuse
FROM dbo.z_legacy_module_auto_code;
END;
DECLARE @AdminId bigint;
SELECT TOP (1) @AdminId = b_id FROM dbo.b_user
WHERE b_canuse = 1
ORDER BY CASE WHEN b_account = N'g3soft' THEN 0 ELSE 1 END, b_id;
IF @AdminId IS NULL
THROW 53305, N'Enabled administrator user not found.', 1;
INSERT INTO dbo.b_role (b_id, b_code, b_name, b_i18n, b_is_super, b_canuse, b_xh)
VALUES (@AdminId, 'system_admin', N'系统管理员', 'meta.role.' + CONVERT(varchar(30), @AdminId), 1, 1, 0);
INSERT INTO dbo.b_user_role (b_id, b_user_id, b_role_id, b_inputuser_id)
VALUES (@AdminId, @AdminId, @AdminId, @AdminId);
;WITH function_grants AS (
SELECT
MIN(grant_row.b_id) AS b_id,
grant_row.b_user_id,
COALESCE(page_module.b_id, data_parent.b_id) AS b_function_node_id,
MIN(grant_row.b_inputuser_id) AS b_inputuser_id,
MIN(grant_row.b_inputdatetime) AS b_inputdatetime
FROM dbo.z_legacy_user_module grant_row
INNER JOIN dbo.z_legacy_module granted_module ON granted_module.b_id = grant_row.b_module_id
LEFT JOIN dbo.z_legacy_module page_module
ON page_module.b_id = granted_module.b_id AND granted_module.b_module_type = 'page'
LEFT JOIN dbo.z_legacy_module data_parent
ON data_parent.b_id = granted_module.b_parent_id
AND granted_module.b_module_type = 'data'
AND data_parent.b_module_type = 'page'
GROUP BY grant_row.b_user_id, COALESCE(page_module.b_id, data_parent.b_id)
)
INSERT INTO dbo.b_user_function_node (
b_id, b_user_id, b_function_node_id, b_inputuser_id, b_inputdatetime
)
SELECT b_id, b_user_id, b_function_node_id, b_inputuser_id, b_inputdatetime
FROM function_grants
WHERE b_function_node_id IS NOT NULL AND b_user_id <> @AdminId;
INSERT INTO dbo.b_user_action (
b_id, b_user_id, b_action_id, b_inputuser_id, b_inputdatetime
)
SELECT grant_row.b_id, grant_row.b_user_id, grant_row.b_power_id,
grant_row.b_inputuser_id, grant_row.b_inputdatetime
FROM dbo.z_legacy_user_power grant_row
INNER JOIN dbo.s_module_action action_row ON action_row.b_id = grant_row.b_power_id
WHERE grant_row.b_user_id <> @AdminId;
/* Keep existing translated values while moving managed entities to ID-based keys. */
UPDATE i18n
SET b_key = 'meta.module.' + CONVERT(varchar(30), module_row.b_id)
FROM dbo.b_i18n i18n
INNER JOIN dbo.z_legacy_module module_row ON module_row.b_i18n = i18n.b_key
WHERE module_row.b_module_type IN ('page', 'data');
UPDATE i18n
SET b_key = 'meta.node.' + CONVERT(varchar(30), module_row.b_id)
FROM dbo.b_i18n i18n
INNER JOIN dbo.z_legacy_module module_row ON module_row.b_i18n = i18n.b_key
WHERE module_row.b_module_type = 'directory';
UPDATE i18n
SET b_key = 'meta.field.' + CONVERT(varchar(30), field_row.b_id)
FROM dbo.b_i18n i18n
INNER JOIN dbo.z_legacy_module_field field_row ON field_row.b_i18n = i18n.b_key;
UPDATE i18n
SET b_key = 'meta.action.' + CONVERT(varchar(30), action_row.b_id)
FROM dbo.b_i18n i18n
INNER JOIN dbo.z_legacy_module_power action_row ON action_row.b_i18n = i18n.b_key;
IF EXISTS (
SELECT 1 FROM dbo.s_module module_row
LEFT JOIN dbo.s_module_page page_row ON page_row.b_module_id = module_row.b_id
LEFT JOIN dbo.s_module_data data_row ON data_row.b_module_id = module_row.b_id
WHERE (module_row.b_module_type = 'page' AND page_row.b_module_id IS NULL)
OR (module_row.b_module_type = 'data' AND data_row.b_module_id IS NULL)
)
THROW 53306, N'Module subtype conversion is incomplete.', 1;
IF EXISTS (
SELECT 1 FROM dbo.s_page_node node
LEFT JOIN dbo.s_module_profile profile_row ON profile_row.b_id = node.b_profile_id
WHERE node.b_module_type = 'data'
AND (profile_row.b_id IS NULL OR profile_row.b_module_id <> node.b_module_id)
)
THROW 53307, N'Page node profile conversion is invalid.', 1;
/* Remove the source model only after every conversion check succeeds. */
DROP TABLE dbo.z_legacy_user_power;
DROP TABLE dbo.z_legacy_user_module;
IF OBJECT_ID(N'dbo.z_legacy_module_auto_code', N'U') IS NOT NULL DROP TABLE dbo.z_legacy_module_auto_code;
DROP TABLE dbo.z_legacy_module_field_list;
DROP TABLE dbo.z_legacy_module_field_edit;
DROP TABLE dbo.z_legacy_module_field_query;
DROP TABLE dbo.z_legacy_module_field_group;
DROP TABLE dbo.z_legacy_module_power;
DROP TABLE dbo.z_legacy_module_field;
DROP TABLE dbo.z_legacy_module;
IF OBJECT_ID(N'dbo.b_other_bmfl', N'U') IS NOT NULL DROP TABLE dbo.b_other_bmfl;
COMMIT TRANSACTION;
@@ -0,0 +1,14 @@
/* 删除 b_other_bmfl 分类树表。
其他数据分类树已完全迁移至 s_module(b_module_type = 'data_category'),
前端不再读写此表。 */
SET NOCOUNT ON;
SET XACT_ABORT ON;
BEGIN TRANSACTION;
IF OBJECT_ID(N'dbo.b_other_bmfl', N'U') IS NOT NULL
BEGIN
DROP TABLE dbo.b_other_bmfl;
END;
COMMIT TRANSACTION;
@@ -1,468 +0,0 @@
/* Runtime read contracts for the module architecture. */
SET NOCOUNT ON;
SET XACT_ABORT ON;
IF EXISTS (
SELECT required.name
FROM (VALUES
(N's_module'), (N's_module_page'), (N's_module_data'), (N's_module_report'),
(N's_module_dashboard'), (N's_module_workflow'), (N's_function_node'),
(N's_page_node'), (N's_module_profile'), (N's_module_field'),
(N's_module_field_list'), (N's_module_field_form'), (N's_module_field_query'),
(N's_module_action'), (N'b_role'), (N'b_user_role'),
(N'b_role_function_node'), (N'b_role_page_node'), (N'b_role_action'),
(N'b_user_function_node'), (N'b_user_page_node'), (N'b_user_action')
) AS required(name)
LEFT JOIN sys.tables AS actual
ON actual.name = required.name AND actual.schema_id = SCHEMA_ID(N'dbo')
WHERE actual.object_id IS NULL
)
THROW 53400, N'Module architecture is incomplete. Run migration 033 first.', 1;
GO
CREATE OR ALTER VIEW dbo.v_s_function_node
AS
SELECT
node.b_id,
node.b_code,
node.b_parent_id,
node.b_node_type,
node.b_module_id,
node.b_name,
node.b_i18n,
node.b_canmenu,
node.b_canuse,
node.b_xh,
module_row.b_code AS b_module_code,
module_row.b_name AS b_module_name,
module_row.b_i18n AS b_module_i18n,
page_row.b_route,
page_row.b_page_mode,
page_row.b_component_key
FROM dbo.s_function_node AS node
LEFT JOIN dbo.s_module AS module_row ON module_row.b_id = node.b_module_id
LEFT JOIN dbo.s_module_page AS page_row ON page_row.b_module_id = node.b_module_id;
GO
CREATE OR ALTER VIEW dbo.v_s_page_node
AS
SELECT
node.b_id,
node.b_code,
node.b_page_module_id,
node.b_parent_id,
node.b_node_type,
node.b_module_id,
node.b_profile_id,
node.b_name,
node.b_i18n,
node.b_fixed_condition,
node.b_param_mapping,
node.b_permission_required,
node.b_canuse,
node.b_xh,
page_module.b_code AS b_page_code,
page_module.b_name AS b_page_name,
page_module.b_i18n AS b_page_i18n,
ref_module.b_code AS b_module_code,
ref_module.b_name AS b_module_name,
ref_module.b_i18n AS b_module_i18n,
profile_row.b_code AS b_profile_code,
profile_row.b_name AS b_profile_name,
profile_row.b_i18n AS b_profile_i18n
FROM dbo.s_page_node AS node
INNER JOIN dbo.s_module AS page_module ON page_module.b_id = node.b_page_module_id
LEFT JOIN dbo.s_module AS ref_module ON ref_module.b_id = node.b_module_id
LEFT JOIN dbo.s_module_profile AS profile_row ON profile_row.b_id = node.b_profile_id;
GO
CREATE OR ALTER VIEW dbo.v_s_module_profile
AS
SELECT
profile_row.b_id,
profile_row.b_module_id,
profile_row.b_code,
profile_row.b_name,
profile_row.b_i18n,
profile_row.b_default,
profile_row.b_canuse,
profile_row.b_xh,
module_row.b_code AS b_module_code,
module_row.b_name AS b_module_name,
module_row.b_i18n AS b_module_i18n,
module_row.b_module_type
FROM dbo.s_module_profile AS profile_row
INNER JOIN dbo.s_module AS module_row ON module_row.b_id = profile_row.b_module_id;
GO
CREATE OR ALTER VIEW dbo.v_s_module_runtime
AS
SELECT
module_row.b_id AS b_module_id,
module_row.b_code AS b_module_code,
module_row.b_name AS b_module_name,
module_row.b_i18n AS b_module_i18n,
module_row.b_module_type,
profile_row.b_id AS b_profile_id,
profile_row.b_code AS b_profile_code,
profile_row.b_name AS b_profile_name,
profile_row.b_i18n AS b_profile_i18n,
profile_row.b_default,
module_data.b_viewtable,
module_data.b_savetable,
module_data.b_keyfield,
module_data.b_orderfield,
module_page.b_route,
module_page.b_page_mode,
module_page.b_component_key,
module_report.b_renderer_key,
module_report.b_options AS b_report_options,
module_dashboard.b_options AS b_dashboard_options,
module_workflow.b_options AS b_workflow_options,
module_row.b_canuse,
profile_row.b_canuse AS b_profile_canuse
FROM dbo.s_module AS module_row
LEFT JOIN dbo.s_module_profile AS profile_row
ON profile_row.b_module_id = module_row.b_id
LEFT JOIN dbo.s_module_data AS module_data
ON module_data.b_module_id = module_row.b_id
LEFT JOIN dbo.s_module_page AS module_page
ON module_page.b_module_id = module_row.b_id
LEFT JOIN dbo.s_module_report AS module_report
ON module_report.b_module_id = module_row.b_id
LEFT JOIN dbo.s_module_dashboard AS module_dashboard
ON module_dashboard.b_module_id = module_row.b_id
LEFT JOIN dbo.s_module_workflow AS module_workflow
ON module_workflow.b_module_id = module_row.b_id
WHERE module_row.b_module_type <> 'data'
OR profile_row.b_id IS NOT NULL;
GO
CREATE OR ALTER VIEW dbo.v_s_module_field_list
AS
SELECT
config_row.b_id,
config_row.b_module_id,
config_row.b_profile_id,
config_row.b_field_id,
config_row.b_group_id,
config_row.b_i18n AS b_list_i18n,
config_row.b_visible,
config_row.b_xh,
config_row.b_width,
field_row.b_field,
field_row.b_name,
field_row.b_i18n,
field_row.b_type,
field_row.b_default_value,
field_row.b_options,
field_row.b_canuse AS b_field_canuse,
group_row.b_name AS b_group_name,
group_row.b_i18n AS b_group_i18n
FROM dbo.s_module_field_list AS config_row
INNER JOIN dbo.s_module_field AS field_row ON field_row.b_id = config_row.b_field_id
LEFT JOIN dbo.s_module_layout_group AS group_row ON group_row.b_id = config_row.b_group_id;
GO
CREATE OR ALTER VIEW dbo.v_s_module_field_form
AS
SELECT
config_row.b_id,
config_row.b_module_id,
config_row.b_profile_id,
config_row.b_field_id,
config_row.b_group_id,
config_row.b_required,
config_row.b_readonly,
config_row.b_disabled,
config_row.b_visible,
config_row.b_xh,
field_row.b_field,
field_row.b_name,
field_row.b_i18n,
field_row.b_type,
field_row.b_default_value,
field_row.b_options,
field_row.b_canuse AS b_field_canuse,
group_row.b_name AS b_group_name,
group_row.b_i18n AS b_group_i18n
FROM dbo.s_module_field_form AS config_row
INNER JOIN dbo.s_module_field AS field_row ON field_row.b_id = config_row.b_field_id
LEFT JOIN dbo.s_module_layout_group AS group_row ON group_row.b_id = config_row.b_group_id;
GO
CREATE OR ALTER VIEW dbo.v_s_module_field_query
AS
SELECT
config_row.b_id,
config_row.b_module_id,
config_row.b_profile_id,
config_row.b_field_id,
config_row.b_component,
config_row.b_operator,
config_row.b_default_value,
config_row.b_xh,
config_row.b_canuse,
field_row.b_field,
field_row.b_name,
field_row.b_i18n,
field_row.b_type,
field_row.b_options,
field_row.b_canuse AS b_field_canuse
FROM dbo.s_module_field_query AS config_row
INNER JOIN dbo.s_module_field AS field_row ON field_row.b_id = config_row.b_field_id;
GO
CREATE OR ALTER VIEW dbo.v_s_module_action
AS
SELECT
action_row.b_id,
action_row.b_module_id,
action_row.b_code,
action_row.b_name,
action_row.b_i18n,
action_row.b_xh,
action_row.b_canuse,
module_row.b_code AS b_module_code,
module_row.b_name AS b_module_name,
module_row.b_i18n AS b_module_i18n
FROM dbo.s_module_action AS action_row
INNER JOIN dbo.s_module AS module_row ON module_row.b_id = action_row.b_module_id;
GO
CREATE OR ALTER VIEW dbo.v_s_user_function_permission
AS
SELECT user_grant.b_user_id, user_grant.b_function_node_id
FROM dbo.b_user_function_node AS user_grant
UNION
SELECT role_user.b_user_id, role_grant.b_function_node_id
FROM dbo.b_user_role AS role_user
INNER JOIN dbo.b_role AS role_row ON role_row.b_id = role_user.b_role_id AND role_row.b_canuse = 1
INNER JOIN dbo.b_role_function_node AS role_grant ON role_grant.b_role_id = role_row.b_id
UNION
SELECT role_user.b_user_id, node.b_id
FROM dbo.b_user_role AS role_user
INNER JOIN dbo.b_role AS role_row ON role_row.b_id = role_user.b_role_id AND role_row.b_canuse = 1 AND role_row.b_is_super = 1
INNER JOIN dbo.s_function_node AS node ON node.b_canuse = 1;
GO
CREATE OR ALTER VIEW dbo.v_s_user_page_permission
AS
SELECT user_grant.b_user_id, user_grant.b_page_node_id
FROM dbo.b_user_page_node AS user_grant
UNION
SELECT role_user.b_user_id, role_grant.b_page_node_id
FROM dbo.b_user_role AS role_user
INNER JOIN dbo.b_role AS role_row ON role_row.b_id = role_user.b_role_id AND role_row.b_canuse = 1
INNER JOIN dbo.b_role_page_node AS role_grant ON role_grant.b_role_id = role_row.b_id
UNION
SELECT role_user.b_user_id, node.b_id
FROM dbo.b_user_role AS role_user
INNER JOIN dbo.b_role AS role_row ON role_row.b_id = role_user.b_role_id AND role_row.b_canuse = 1 AND role_row.b_is_super = 1
INNER JOIN dbo.s_page_node AS node ON node.b_canuse = 1 AND node.b_permission_required = 1;
GO
CREATE OR ALTER VIEW dbo.v_s_user_action_permission
AS
SELECT user_grant.b_user_id, user_grant.b_action_id
FROM dbo.b_user_action AS user_grant
UNION
SELECT role_user.b_user_id, role_grant.b_action_id
FROM dbo.b_user_role AS role_user
INNER JOIN dbo.b_role AS role_row ON role_row.b_id = role_user.b_role_id AND role_row.b_canuse = 1
INNER JOIN dbo.b_role_action AS role_grant ON role_grant.b_role_id = role_row.b_id
UNION
SELECT role_user.b_user_id, action_row.b_id
FROM dbo.b_user_role AS role_user
INNER JOIN dbo.b_role AS role_row ON role_row.b_id = role_user.b_role_id AND role_row.b_canuse = 1 AND role_row.b_is_super = 1
INNER JOIN dbo.s_module_action AS action_row ON action_row.b_canuse = 1;
GO
/* Tree cycles and technical-code changes are domain constraints not expressible by CHECK. */
CREATE OR ALTER TRIGGER dbo.TR_s_function_node_tree
ON dbo.s_function_node
AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (
SELECT 1
FROM inserted AS child
INNER JOIN dbo.s_function_node AS parent_row ON parent_row.b_id = child.b_parent_id
WHERE parent_row.b_node_type <> 'directory'
)
THROW 53408, N'Function nodes can only be placed below a directory.', 1;
IF EXISTS (
SELECT 1
FROM inserted AS parent_row
INNER JOIN dbo.s_function_node AS child ON child.b_parent_id = parent_row.b_id
WHERE parent_row.b_node_type <> 'directory'
)
THROW 53409, N'Function entries cannot contain child nodes.', 1;
DECLARE @Cycle bit = 0;
;WITH tree AS (
SELECT i.b_id AS origin_id, i.b_parent_id AS current_id
FROM inserted AS i
WHERE i.b_parent_id IS NOT NULL
UNION ALL
SELECT tree.origin_id, parent_row.b_parent_id
FROM tree
INNER JOIN dbo.s_function_node AS parent_row ON parent_row.b_id = tree.current_id
WHERE tree.current_id IS NOT NULL
)
SELECT TOP (1) @Cycle = 1 FROM tree WHERE current_id = origin_id OPTION (MAXRECURSION 32767);
IF @Cycle = 1 THROW 53401, N'Function node parent cycle detected.', 1;
END;
GO
CREATE OR ALTER TRIGGER dbo.TR_s_page_node_tree
ON dbo.s_page_node
AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (
SELECT 1
FROM inserted AS child
INNER JOIN dbo.s_page_node AS parent_row
ON parent_row.b_page_module_id = child.b_page_module_id
AND parent_row.b_id = child.b_parent_id
WHERE parent_row.b_node_type = 'module_ref'
)
THROW 53410, N'Page module references cannot contain child nodes.', 1;
IF EXISTS (
SELECT 1
FROM inserted AS parent_row
INNER JOIN dbo.s_page_node AS child
ON child.b_page_module_id = parent_row.b_page_module_id
AND child.b_parent_id = parent_row.b_id
WHERE parent_row.b_node_type = 'module_ref'
)
THROW 53411, N'Page module references cannot contain child nodes.', 1;
DECLARE @Cycle bit = 0;
;WITH tree AS (
SELECT i.b_page_module_id AS page_id, i.b_id AS origin_id, i.b_parent_id AS current_id
FROM inserted AS i
WHERE i.b_parent_id IS NOT NULL
UNION ALL
SELECT tree.page_id, tree.origin_id, parent_row.b_parent_id
FROM tree
INNER JOIN dbo.s_page_node AS parent_row
ON parent_row.b_page_module_id = tree.page_id AND parent_row.b_id = tree.current_id
WHERE tree.current_id IS NOT NULL
)
SELECT TOP (1) @Cycle = 1 FROM tree WHERE current_id = origin_id OPTION (MAXRECURSION 32767);
IF @Cycle = 1 THROW 53402, N'Page node parent cycle detected.', 1;
END;
GO
CREATE OR ALTER TRIGGER dbo.TR_s_module_immutable_code
ON dbo.s_module
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF UPDATE(b_code) OR UPDATE(b_module_type)
BEGIN
IF EXISTS (
SELECT 1 FROM inserted i INNER JOIN deleted d ON d.b_id = i.b_id
WHERE i.b_code <> d.b_code OR i.b_module_type <> d.b_module_type
)
THROW 53403, N'Module technical code and type are immutable.', 1;
END;
END;
GO
CREATE OR ALTER TRIGGER dbo.TR_s_function_node_immutable_code
ON dbo.s_function_node
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF (UPDATE(b_code) OR UPDATE(b_node_type)) AND EXISTS (
SELECT 1 FROM inserted i INNER JOIN deleted d ON d.b_id = i.b_id
WHERE i.b_code <> d.b_code OR i.b_node_type <> d.b_node_type
) THROW 53404, N'Function node technical code and type are immutable.', 1;
END;
GO
CREATE OR ALTER TRIGGER dbo.TR_s_page_node_immutable_code
ON dbo.s_page_node
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF (UPDATE(b_code) OR UPDATE(b_node_type) OR UPDATE(b_page_module_id)) AND EXISTS (
SELECT 1 FROM inserted i INNER JOIN deleted d ON d.b_id = i.b_id
WHERE i.b_code <> d.b_code OR i.b_node_type <> d.b_node_type
OR i.b_page_module_id <> d.b_page_module_id
) THROW 53405, N'Page node technical code, type and owning page are immutable.', 1;
END;
GO
CREATE OR ALTER TRIGGER dbo.TR_s_module_profile_immutable_code
ON dbo.s_module_profile
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF (UPDATE(b_code) OR UPDATE(b_module_id)) AND EXISTS (
SELECT 1
FROM inserted i
INNER JOIN deleted d ON d.b_id = i.b_id
WHERE i.b_code <> d.b_code OR i.b_module_id <> d.b_module_id
) THROW 53412, N'Profile technical code and owning module are immutable.', 1;
END;
GO
CREATE OR ALTER TRIGGER dbo.TR_s_module_field_immutable_code
ON dbo.s_module_field
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF (UPDATE(b_field) OR UPDATE(b_module_id)) AND EXISTS (
SELECT 1 FROM inserted i INNER JOIN deleted d ON d.b_id = i.b_id
WHERE i.b_field <> d.b_field OR i.b_module_id <> d.b_module_id
) THROW 53406, N'Field technical code and owning module are immutable.', 1;
END;
GO
CREATE OR ALTER TRIGGER dbo.TR_s_module_action_immutable_code
ON dbo.s_module_action
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF (UPDATE(b_code) OR UPDATE(b_module_id)) AND EXISTS (
SELECT 1 FROM inserted i INNER JOIN deleted d ON d.b_id = i.b_id
WHERE i.b_code <> d.b_code OR i.b_module_id <> d.b_module_id
) THROW 53407, N'Action technical code and owning module are immutable.', 1;
END;
GO
CREATE OR ALTER TRIGGER dbo.TR_s_module_relation_immutable_code
ON dbo.s_module_relation
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF (UPDATE(b_code) OR UPDATE(b_parent_module_id)) AND EXISTS (
SELECT 1 FROM inserted i INNER JOIN deleted d ON d.b_id = i.b_id
WHERE i.b_code <> d.b_code OR i.b_parent_module_id <> d.b_parent_module_id
) THROW 53413, N'Relation technical code and owning module are immutable.', 1;
END;
GO
CREATE OR ALTER TRIGGER dbo.TR_b_role_immutable_code
ON dbo.b_role
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF UPDATE(b_code) AND EXISTS (
SELECT 1 FROM inserted i INNER JOIN deleted d ON d.b_id = i.b_id
WHERE i.b_code <> d.b_code
) THROW 53414, N'Role technical code is immutable.', 1;
END;
GO
@@ -0,0 +1,563 @@
/*
Restore the pre-2026-08-03 module model and keep one intentional extension:
s_module.b_module_type = 'data_category'. Data categories belong to a page or
another data category, so arbitrary nesting needs no separate composition model.
This script is executed by ApplySimpleModuleRestore in one JDBC transaction.
*/
SET NOCOUNT ON;
SET XACT_ABORT ON;
IF DB_NAME() <> N'FMS'
THROW 53500, N'This migration can only run against the FMS database.', 1;
IF OBJECT_ID(N'dbo.s_module_page', N'U') IS NULL
THROW 53501, N'The split module architecture is not installed.', 1;
IF COL_LENGTH(N'dbo.s_module', N'b_parent_id') IS NOT NULL
THROW 53502, N'The simple module tree is already installed.', 1;
IF OBJECT_ID(N'dbo.z_restore_module', N'U') IS NOT NULL
THROW 53503, N'A previous restore staging table exists.', 1;
DECLARE @AdminId bigint = (
SELECT TOP (1) b_id
FROM dbo.b_user
WHERE b_canuse = 1
ORDER BY CASE WHEN b_account = N'g3soft' THEN 0 ELSE 1 END, b_id
);
IF @AdminId IS NULL
THROW 53504, N'Enabled administrator user not found.', 1;
CREATE TABLE dbo.z_restore_module (
b_id bigint NOT NULL,
b_code varchar(50) NOT NULL,
b_parent_id bigint NULL,
b_name nvarchar(100) NOT NULL,
b_i18n varchar(150) NULL,
b_module_type varchar(20) NOT NULL,
b_route varchar(200) NULL,
b_viewtable varchar(128) NULL,
b_savetable varchar(128) NULL,
b_keyfield varchar(50) NULL,
b_orderfield varchar(500) NULL,
b_canmenu int NOT NULL,
b_canuse int NOT NULL,
b_xh int NOT NULL
);
CREATE TABLE dbo.z_restore_i18n_map (
b_new_key varchar(150) NOT NULL,
b_old_key varchar(150) NOT NULL,
CONSTRAINT PK_z_restore_i18n_map PRIMARY KEY (b_new_key)
);
/* Menu directories remain ordinary tree nodes. */
INSERT INTO dbo.z_restore_module
SELECT node.b_id, node.b_code, node.b_parent_id, node.b_name,
'menu.' + node.b_code, 'directory', NULL, NULL, NULL, NULL, NULL,
node.b_canmenu, node.b_canuse, node.b_xh
FROM dbo.s_function_node AS node
WHERE node.b_node_type = 'directory';
INSERT INTO dbo.z_restore_i18n_map
SELECT node.b_i18n, 'menu.' + node.b_code
FROM dbo.s_function_node AS node
WHERE node.b_node_type = 'directory';
/* A page module and its function entry collapse back into one row. */
;WITH page_entry AS (
SELECT node.*,
ROW_NUMBER() OVER (PARTITION BY node.b_module_id ORDER BY node.b_id) AS rn
FROM dbo.s_function_node AS node
WHERE node.b_node_type = 'entry'
)
INSERT INTO dbo.z_restore_module
SELECT module_row.b_id, module_row.b_code, entry.b_parent_id, module_row.b_name,
'menu.' + module_row.b_code, 'page', page_row.b_route,
NULL, NULL, NULL, NULL,
COALESCE(entry.b_canmenu, 0),
CASE WHEN module_row.b_canuse = 1 AND COALESCE(entry.b_canuse, 1) = 1 THEN 1 ELSE 0 END,
COALESCE(entry.b_xh, 0)
FROM dbo.s_module AS module_row
INNER JOIN dbo.s_module_page AS page_row ON page_row.b_module_id = module_row.b_id
LEFT JOIN page_entry AS entry ON entry.b_module_id = module_row.b_id AND entry.rn = 1;
INSERT INTO dbo.z_restore_i18n_map
SELECT module_row.b_i18n, 'menu.' + module_row.b_code
FROM dbo.s_module AS module_row
WHERE module_row.b_module_type = 'page';
/* Page containers become lightweight, arbitrarily nested data categories. */
INSERT INTO dbo.z_restore_module
SELECT node.b_id,
CONVERT(varchar(50), 'data_category_' + CONVERT(varchar(30), node.b_id)),
COALESCE(node.b_parent_id, node.b_page_module_id),
node.b_name,
CONVERT(varchar(150), 'menu.data_category_' + CONVERT(varchar(30), node.b_id)),
'data_category', NULL, NULL, NULL, NULL, NULL,
0, node.b_canuse, node.b_xh
FROM dbo.s_page_node AS node
WHERE node.b_node_type IN ('group', 'tab', 'section');
INSERT INTO dbo.z_restore_i18n_map
SELECT node.b_i18n,
CONVERT(varchar(150), 'menu.data_category_' + CONVERT(varchar(30), node.b_id))
FROM dbo.s_page_node AS node
WHERE node.b_node_type IN ('group', 'tab', 'section');
/* A data module has one owning parent again. Prefer its first active page reference. */
;WITH module_reference AS (
SELECT node.*,
ROW_NUMBER() OVER (
PARTITION BY node.b_module_id
ORDER BY node.b_canuse DESC, node.b_page_module_id, node.b_xh, node.b_id
) AS rn
FROM dbo.s_page_node AS node
WHERE node.b_node_type = 'module_ref' AND node.b_module_type = 'data'
)
INSERT INTO dbo.z_restore_module
SELECT module_row.b_id, module_row.b_code,
COALESCE(reference.b_parent_id, reference.b_page_module_id),
module_row.b_name, 'module.' + module_row.b_code, 'data', NULL,
data_row.b_viewtable, data_row.b_savetable, data_row.b_keyfield, data_row.b_orderfield,
0, module_row.b_canuse, COALESCE(reference.b_xh, 0)
FROM dbo.s_module AS module_row
INNER JOIN dbo.s_module_data AS data_row ON data_row.b_module_id = module_row.b_id
LEFT JOIN module_reference AS reference
ON reference.b_module_id = module_row.b_id AND reference.rn = 1;
INSERT INTO dbo.z_restore_i18n_map
SELECT module_row.b_i18n, 'module.' + module_row.b_code
FROM dbo.s_module AS module_row
WHERE module_row.b_module_type = 'data';
IF EXISTS (
SELECT b_id FROM dbo.z_restore_module GROUP BY b_id HAVING COUNT(*) > 1
)
THROW 53505, N'Module IDs collide while restoring the simple tree.', 1;
IF EXISTS (
SELECT b_code FROM dbo.z_restore_module GROUP BY b_code HAVING COUNT(*) > 1
)
THROW 53506, N'Module codes collide while restoring the simple tree.', 1;
IF EXISTS (
SELECT 1
FROM dbo.z_restore_module AS child
LEFT JOIN dbo.z_restore_module AS parent_row ON parent_row.b_id = child.b_parent_id
WHERE child.b_parent_id IS NOT NULL AND parent_row.b_id IS NULL
)
THROW 53507, N'A restored module has an unresolved parent.', 1;
/* Flatten the default Profile back to the original module-owned configuration. */
SELECT field_row.b_id, field_row.b_module_id, field_row.b_field, field_row.b_name,
CONVERT(varchar(150), 'field.' + module_row.b_code + '.' + field_row.b_field) AS b_i18n,
field_row.b_type, field_row.b_default_value, field_row.b_options, field_row.b_canuse
INTO dbo.z_restore_module_field
FROM dbo.s_module_field AS field_row
INNER JOIN dbo.s_module AS module_row ON module_row.b_id = field_row.b_module_id;
INSERT INTO dbo.z_restore_i18n_map
SELECT field_row.b_i18n,
CONVERT(varchar(150), 'field.' + module_row.b_code + '.' + field_row.b_field)
FROM dbo.s_module_field AS field_row
INNER JOIN dbo.s_module AS module_row ON module_row.b_id = field_row.b_module_id;
SELECT auto_row.b_id, auto_row.b_module_id, auto_row.b_field_id, auto_row.b_prefix,
auto_row.b_date_format, auto_row.b_separator, auto_row.b_sequence_width,
auto_row.b_reset_type, auto_row.b_start_value, auto_row.b_current_period,
auto_row.b_current_value, auto_row.b_canuse
INTO dbo.z_restore_module_auto_code
FROM dbo.s_module_auto_code AS auto_row;
SELECT group_row.b_id, group_row.b_module_id, group_row.b_parent_id,
group_row.b_name AS b_title, group_row.b_i18n, group_row.b_xh, group_row.b_canuse
INTO dbo.z_restore_module_field_group
FROM dbo.s_module_layout_group AS group_row
INNER JOIN dbo.s_module_profile AS profile_row
ON profile_row.b_id = group_row.b_profile_id AND profile_row.b_default = 1;
SELECT config.b_id, config.b_module_id, config.b_field_id, config.b_group_id,
config.b_i18n, config.b_visible, config.b_xh, config.b_width
INTO dbo.z_restore_module_field_list
FROM dbo.s_module_field_list AS config
INNER JOIN dbo.s_module_profile AS profile_row
ON profile_row.b_id = config.b_profile_id AND profile_row.b_default = 1;
SELECT config.b_id, config.b_module_id, config.b_field_id, config.b_required,
config.b_readonly, config.b_disabled, config.b_visible, config.b_group_id, config.b_xh
INTO dbo.z_restore_module_field_edit
FROM dbo.s_module_field_form AS config
INNER JOIN dbo.s_module_profile AS profile_row
ON profile_row.b_id = config.b_profile_id AND profile_row.b_default = 1;
SELECT config.b_id, config.b_module_id, config.b_field_id, config.b_component,
config.b_operator, config.b_default_value, config.b_xh, config.b_canuse
INTO dbo.z_restore_module_field_query
FROM dbo.s_module_field_query AS config
INNER JOIN dbo.s_module_profile AS profile_row
ON profile_row.b_id = config.b_profile_id AND profile_row.b_default = 1;
SELECT action_row.b_id, action_row.b_module_id, action_row.b_code, action_row.b_name,
CONVERT(varchar(150), 'power.' + module_row.b_code + '.' + action_row.b_code) AS b_i18n,
action_row.b_xh, action_row.b_canuse
INTO dbo.z_restore_module_power
FROM dbo.s_module_action AS action_row
INNER JOIN dbo.s_module AS module_row ON module_row.b_id = action_row.b_module_id;
INSERT INTO dbo.z_restore_i18n_map
SELECT action_row.b_i18n,
CONVERT(varchar(150), 'power.' + module_row.b_code + '.' + action_row.b_code)
FROM dbo.s_module_action AS action_row
INNER JOIN dbo.s_module AS module_row ON module_row.b_id = action_row.b_module_id;
CREATE TABLE dbo.z_restore_user_module (
b_user_id bigint NOT NULL,
b_module_id bigint NOT NULL,
CONSTRAINT PK_z_restore_user_module PRIMARY KEY (b_user_id, b_module_id)
);
;WITH allowed_page AS (
SELECT permission.b_user_id, node.b_module_id
FROM dbo.v_s_user_function_permission AS permission
INNER JOIN dbo.s_function_node AS node
ON node.b_id = permission.b_function_node_id AND node.b_node_type = 'entry'
), allowed_module AS (
SELECT b_user_id, b_module_id FROM allowed_page
UNION
SELECT page_permission.b_user_id, page_node.b_module_id
FROM allowed_page AS page_permission
INNER JOIN dbo.s_page_node AS page_node
ON page_node.b_page_module_id = page_permission.b_module_id
AND page_node.b_node_type = 'module_ref'
LEFT JOIN dbo.v_s_user_page_permission AS node_permission
ON node_permission.b_user_id = page_permission.b_user_id
AND node_permission.b_page_node_id = page_node.b_id
WHERE page_node.b_permission_required = 0 OR node_permission.b_page_node_id IS NOT NULL
UNION
SELECT permission.b_user_id, action_row.b_module_id
FROM dbo.v_s_user_action_permission AS permission
INNER JOIN dbo.s_module_action AS action_row ON action_row.b_id = permission.b_action_id
)
INSERT INTO dbo.z_restore_user_module (b_user_id, b_module_id)
SELECT DISTINCT allowed_module.b_user_id, allowed_module.b_module_id
FROM allowed_module
INNER JOIN dbo.z_restore_module AS module_row ON module_row.b_id = allowed_module.b_module_id;
SELECT permission.b_user_id, action_row.b_module_id, permission.b_action_id AS b_power_id
INTO dbo.z_restore_user_power
FROM dbo.v_s_user_action_permission AS permission
INNER JOIN dbo.s_module_action AS action_row ON action_row.b_id = permission.b_action_id
INNER JOIN dbo.z_restore_module AS module_row ON module_row.b_id = action_row.b_module_id;
/* Preserve translations while returning generated keys to their old code-based form. */
UPDATE old_translation
SET old_translation.b_value = new_translation.b_value
FROM dbo.b_i18n AS old_translation
INNER JOIN dbo.z_restore_i18n_map AS key_map ON key_map.b_old_key = old_translation.b_key
INNER JOIN dbo.b_i18n AS new_translation
ON new_translation.b_key = key_map.b_new_key
AND new_translation.b_locale = old_translation.b_locale;
DELETE new_translation
FROM dbo.b_i18n AS new_translation
INNER JOIN dbo.z_restore_i18n_map AS key_map ON key_map.b_new_key = new_translation.b_key
WHERE EXISTS (
SELECT 1 FROM dbo.b_i18n AS old_translation
WHERE old_translation.b_key = key_map.b_old_key
AND old_translation.b_locale = new_translation.b_locale
);
UPDATE translation
SET translation.b_key = key_map.b_old_key
FROM dbo.b_i18n AS translation
INNER JOIN dbo.z_restore_i18n_map AS key_map ON key_map.b_new_key = translation.b_key;
GO
/* Remove runtime views before replacing their source tables. */
IF OBJECT_ID(N'dbo.v_s_user_action_permission', N'V') IS NOT NULL DROP VIEW dbo.v_s_user_action_permission;
IF OBJECT_ID(N'dbo.v_s_user_page_permission', N'V') IS NOT NULL DROP VIEW dbo.v_s_user_page_permission;
IF OBJECT_ID(N'dbo.v_s_user_function_permission', N'V') IS NOT NULL DROP VIEW dbo.v_s_user_function_permission;
IF OBJECT_ID(N'dbo.v_s_module_action', N'V') IS NOT NULL DROP VIEW dbo.v_s_module_action;
IF OBJECT_ID(N'dbo.v_s_module_field_query', N'V') IS NOT NULL DROP VIEW dbo.v_s_module_field_query;
IF OBJECT_ID(N'dbo.v_s_module_field_form', N'V') IS NOT NULL DROP VIEW dbo.v_s_module_field_form;
IF OBJECT_ID(N'dbo.v_s_module_field_list', N'V') IS NOT NULL DROP VIEW dbo.v_s_module_field_list;
IF OBJECT_ID(N'dbo.v_s_module_runtime', N'V') IS NOT NULL DROP VIEW dbo.v_s_module_runtime;
IF OBJECT_ID(N'dbo.v_s_module_profile', N'V') IS NOT NULL DROP VIEW dbo.v_s_module_profile;
IF OBJECT_ID(N'dbo.v_s_page_node', N'V') IS NOT NULL DROP VIEW dbo.v_s_page_node;
IF OBJECT_ID(N'dbo.v_s_function_node', N'V') IS NOT NULL DROP VIEW dbo.v_s_function_node;
/* Drop all foreign keys owned by or referencing the split architecture. */
DECLARE @DropForeignKeys nvarchar(max) = N'';
SELECT @DropForeignKeys = @DropForeignKeys
+ N'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id)) + N'.'
+ QUOTENAME(OBJECT_NAME(fk.parent_object_id)) + N' DROP CONSTRAINT ' + QUOTENAME(fk.name) + N';'
FROM sys.foreign_keys AS fk
WHERE OBJECT_SCHEMA_NAME(fk.parent_object_id) = N'dbo'
AND (
OBJECT_NAME(fk.parent_object_id) IN (
N's_module', N's_module_page', N's_module_data', N's_module_report',
N's_module_dashboard', N's_module_workflow', N's_module_profile',
N's_function_node', N's_page_node', N's_module_field', N's_module_layout_group',
N's_module_field_list', N's_module_field_form', N's_module_field_query',
N's_module_action', N's_module_relation', N's_module_auto_code',
N's_module_import', N's_module_export', N's_module_file',
N's_module_workflow_binding', N'b_role', N'b_user_role',
N'b_role_function_node', N'b_role_page_node', N'b_role_action',
N'b_role_data_scope', N'b_user_function_node', N'b_user_page_node', N'b_user_action'
)
OR OBJECT_NAME(fk.referenced_object_id) IN (
N's_module', N's_module_profile', N's_function_node', N's_page_node',
N's_module_field', N's_module_layout_group', N's_module_action', N'b_role'
)
);
IF @DropForeignKeys <> N'' EXEC sys.sp_executesql @DropForeignKeys;
DROP TABLE dbo.s_module_workflow_binding;
DROP TABLE dbo.s_module_relation;
DROP TABLE dbo.s_module_import;
DROP TABLE dbo.s_module_export;
DROP TABLE dbo.s_module_file;
DROP TABLE dbo.s_module_field_list;
DROP TABLE dbo.s_module_field_form;
DROP TABLE dbo.s_module_field_query;
DROP TABLE dbo.s_module_layout_group;
DROP TABLE dbo.s_module_auto_code;
DROP TABLE dbo.b_user_action;
DROP TABLE dbo.b_user_page_node;
DROP TABLE dbo.b_user_function_node;
DROP TABLE dbo.b_role_data_scope;
DROP TABLE dbo.b_role_action;
DROP TABLE dbo.b_role_page_node;
DROP TABLE dbo.b_role_function_node;
DROP TABLE dbo.b_user_role;
DROP TABLE dbo.b_role;
DROP TABLE dbo.s_page_node;
DROP TABLE dbo.s_function_node;
DROP TABLE dbo.s_module_action;
DROP TABLE dbo.s_module_field;
DROP TABLE dbo.s_module_report;
DROP TABLE dbo.s_module_dashboard;
DROP TABLE dbo.s_module_workflow;
DROP TABLE dbo.s_module_page;
DROP TABLE dbo.s_module_data;
DROP TABLE dbo.s_module_profile;
DROP TABLE dbo.s_module;
GO
/* Recreate the compact pre-refactor model. */
DECLARE @AdminId bigint = (
SELECT TOP (1) b_id
FROM dbo.b_user
WHERE b_canuse = 1
ORDER BY CASE WHEN b_account = N'g3soft' THEN 0 ELSE 1 END, b_id
);
CREATE TABLE dbo.s_module (
b_id bigint NOT NULL,
b_code varchar(50) NOT NULL,
b_parent_id bigint NULL,
b_name nvarchar(100) NOT NULL,
b_i18n varchar(150) NULL,
b_module_type varchar(20) NOT NULL,
b_route varchar(200) NULL,
b_viewtable varchar(128) NULL,
b_savetable varchar(128) NULL,
b_keyfield varchar(50) NULL,
b_orderfield varchar(500) NULL,
b_canmenu int NOT NULL CONSTRAINT DF_s_module_canmenu DEFAULT (0),
b_canuse int NOT NULL CONSTRAINT DF_s_module_canuse DEFAULT (1),
b_xh int NOT NULL CONSTRAINT DF_s_module_xh DEFAULT (0),
CONSTRAINT PK_s_module PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_code UNIQUE (b_code),
CONSTRAINT CK_s_module_type CHECK (b_module_type IN ('directory', 'page', 'data_category', 'data')),
CONSTRAINT CK_s_module_flags CHECK (b_canmenu IN (0, 1) AND b_canuse IN (0, 1)),
CONSTRAINT CK_s_module_parent CHECK (b_parent_id IS NULL OR b_parent_id <> b_id),
CONSTRAINT FK_s_module_parent FOREIGN KEY (b_parent_id) REFERENCES dbo.s_module (b_id)
);
CREATE UNIQUE INDEX UX_s_module_route ON dbo.s_module (b_route) WHERE b_route IS NOT NULL;
CREATE INDEX IX_s_module_parent ON dbo.s_module (b_parent_id, b_xh, b_id);
CREATE TABLE dbo.s_module_field (
b_id bigint NOT NULL, b_module_id bigint NOT NULL, b_field varchar(50) NOT NULL,
b_name nvarchar(100) NOT NULL, b_i18n varchar(150) NULL, b_type varchar(30) NOT NULL,
b_default_value nvarchar(500) NULL, b_options nvarchar(max) NULL,
b_canuse int NOT NULL CONSTRAINT DF_s_module_field_canuse DEFAULT (1),
CONSTRAINT PK_s_module_field PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_field UNIQUE (b_module_id, b_field),
CONSTRAINT FK_s_module_field_module FOREIGN KEY (b_module_id) REFERENCES dbo.s_module (b_id)
);
CREATE INDEX IX_s_module_field_module ON dbo.s_module_field (b_module_id, b_canuse, b_id);
CREATE TABLE dbo.s_module_auto_code (
b_id bigint NOT NULL, b_module_id bigint NOT NULL, b_field_id bigint NOT NULL,
b_prefix nvarchar(100) NOT NULL CONSTRAINT DF_s_module_auto_code_prefix DEFAULT (N''),
b_date_format varchar(30) NOT NULL CONSTRAINT DF_s_module_auto_code_date_format DEFAULT ('yyyyMM'),
b_separator nvarchar(10) NOT NULL CONSTRAINT DF_s_module_auto_code_separator DEFAULT (N'-'),
b_sequence_width int NOT NULL CONSTRAINT DF_s_module_auto_code_sequence_width DEFAULT (5),
b_reset_type varchar(10) NOT NULL CONSTRAINT DF_s_module_auto_code_reset_type DEFAULT ('month'),
b_start_value bigint NOT NULL CONSTRAINT DF_s_module_auto_code_start_value DEFAULT (1),
b_current_period varchar(8) NULL,
b_current_value bigint NOT NULL CONSTRAINT DF_s_module_auto_code_current_value DEFAULT (0),
b_canuse int NOT NULL CONSTRAINT DF_s_module_auto_code_canuse DEFAULT (1),
CONSTRAINT PK_s_module_auto_code PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_auto_code_module UNIQUE (b_module_id),
CONSTRAINT FK_s_module_auto_code_module FOREIGN KEY (b_module_id) REFERENCES dbo.s_module (b_id),
CONSTRAINT FK_s_module_auto_code_field FOREIGN KEY (b_field_id) REFERENCES dbo.s_module_field (b_id)
);
CREATE INDEX IX_s_module_auto_code_field ON dbo.s_module_auto_code (b_field_id);
CREATE TABLE dbo.s_module_field_group (
b_id bigint NOT NULL, b_module_id bigint NOT NULL, b_parent_id bigint NULL,
b_title nvarchar(100) NOT NULL, b_i18n varchar(150) NULL,
b_xh int NOT NULL CONSTRAINT DF_s_module_field_group_xh DEFAULT (0),
b_canuse int NOT NULL CONSTRAINT DF_s_module_field_group_canuse DEFAULT (1),
CONSTRAINT PK_s_module_field_group PRIMARY KEY (b_id),
CONSTRAINT FK_s_module_field_group_module FOREIGN KEY (b_module_id) REFERENCES dbo.s_module (b_id)
);
CREATE INDEX IX_s_module_field_group_module ON dbo.s_module_field_group (b_module_id, b_canuse, b_xh, b_id);
CREATE TABLE dbo.s_module_field_list (
b_id bigint NOT NULL, b_module_id bigint NOT NULL, b_field_id bigint NULL,
b_group_id bigint NULL, b_i18n varchar(150) NULL,
b_visible int NOT NULL CONSTRAINT DF_s_module_field_list_visible DEFAULT (1),
b_xh int NOT NULL CONSTRAINT DF_s_module_field_list_xh DEFAULT (0), b_width int NULL,
CONSTRAINT PK_s_module_field_list PRIMARY KEY (b_id),
CONSTRAINT FK_s_module_field_list_module FOREIGN KEY (b_module_id) REFERENCES dbo.s_module (b_id),
CONSTRAINT FK_s_module_field_list_field FOREIGN KEY (b_field_id) REFERENCES dbo.s_module_field (b_id),
CONSTRAINT FK_s_module_field_list_group FOREIGN KEY (b_group_id) REFERENCES dbo.s_module_field_group (b_id)
);
CREATE UNIQUE INDEX UX_s_module_field_list_field ON dbo.s_module_field_list (b_module_id, b_field_id) WHERE b_field_id IS NOT NULL;
CREATE INDEX IX_s_module_field_list_tree ON dbo.s_module_field_list (b_module_id, b_group_id, b_xh, b_id);
CREATE TABLE dbo.s_module_field_edit (
b_id bigint NOT NULL, b_module_id bigint NOT NULL, b_field_id bigint NOT NULL,
b_required int NOT NULL CONSTRAINT DF_s_module_field_edit_required DEFAULT (0),
b_readonly int NOT NULL CONSTRAINT DF_s_module_field_edit_readonly DEFAULT (0),
b_disabled int NOT NULL CONSTRAINT DF_s_module_field_edit_disabled DEFAULT (0),
b_visible int NOT NULL CONSTRAINT DF_s_module_field_edit_visible DEFAULT (1),
b_group_id bigint NULL, b_xh int NOT NULL CONSTRAINT DF_s_module_field_edit_xh DEFAULT (0),
CONSTRAINT PK_s_module_field_edit PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_field_edit UNIQUE (b_module_id, b_field_id),
CONSTRAINT FK_s_module_field_edit_module FOREIGN KEY (b_module_id) REFERENCES dbo.s_module (b_id),
CONSTRAINT FK_s_module_field_edit_field FOREIGN KEY (b_field_id) REFERENCES dbo.s_module_field (b_id),
CONSTRAINT FK_s_module_field_edit_group FOREIGN KEY (b_group_id) REFERENCES dbo.s_module_field_group (b_id)
);
CREATE INDEX IX_s_module_field_edit_module ON dbo.s_module_field_edit (b_module_id, b_xh, b_id);
CREATE TABLE dbo.s_module_field_query (
b_id bigint NOT NULL, b_module_id bigint NOT NULL, b_field_id bigint NOT NULL,
b_component varchar(30) NOT NULL, b_operator varchar(20) NOT NULL,
b_default_value nvarchar(500) NULL,
b_xh int NOT NULL CONSTRAINT DF_s_module_field_query_xh DEFAULT (0),
b_canuse int NOT NULL CONSTRAINT DF_s_module_field_query_canuse DEFAULT (1),
CONSTRAINT PK_s_module_field_query PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_field_query UNIQUE (b_module_id, b_field_id),
CONSTRAINT FK_s_module_field_query_module FOREIGN KEY (b_module_id) REFERENCES dbo.s_module (b_id),
CONSTRAINT FK_s_module_field_query_field FOREIGN KEY (b_field_id) REFERENCES dbo.s_module_field (b_id)
);
CREATE INDEX IX_s_module_field_query_module ON dbo.s_module_field_query (b_module_id, b_canuse, b_xh, b_id);
CREATE TABLE dbo.s_module_power (
b_id bigint NOT NULL, b_module_id bigint NOT NULL, b_code varchar(50) NOT NULL,
b_name nvarchar(100) NOT NULL, b_i18n varchar(150) NULL,
b_xh int NOT NULL CONSTRAINT DF_s_module_power_xh DEFAULT (0),
b_canuse int NOT NULL CONSTRAINT DF_s_module_power_canuse DEFAULT (1),
CONSTRAINT PK_s_module_power PRIMARY KEY (b_id),
CONSTRAINT UQ_s_module_power UNIQUE (b_module_id, b_code),
CONSTRAINT FK_s_module_power_module FOREIGN KEY (b_module_id) REFERENCES dbo.s_module (b_id)
);
CREATE TABLE dbo.b_user_module (
b_id bigint NOT NULL, b_user_id bigint NOT NULL, b_module_id bigint NOT NULL,
b_inputuser_id bigint NOT NULL,
b_inputdatetime datetime NOT NULL CONSTRAINT DF_b_user_module_inputdatetime DEFAULT (GETDATE()),
CONSTRAINT PK_b_user_module PRIMARY KEY (b_id),
CONSTRAINT UQ_b_user_module UNIQUE (b_user_id, b_module_id),
CONSTRAINT FK_b_user_module_user FOREIGN KEY (b_user_id) REFERENCES dbo.b_user (b_id),
CONSTRAINT FK_b_user_module_module FOREIGN KEY (b_module_id) REFERENCES dbo.s_module (b_id)
);
CREATE TABLE dbo.b_user_power (
b_id bigint NOT NULL, b_user_id bigint NOT NULL, b_module_id bigint NOT NULL,
b_power_id bigint NOT NULL, b_inputuser_id bigint NOT NULL,
b_inputdatetime datetime NOT NULL CONSTRAINT DF_b_user_power_inputdatetime DEFAULT (GETDATE()),
CONSTRAINT PK_b_user_power PRIMARY KEY (b_id),
CONSTRAINT UQ_b_user_power UNIQUE (b_user_id, b_power_id),
CONSTRAINT FK_b_user_power_user FOREIGN KEY (b_user_id) REFERENCES dbo.b_user (b_id),
CONSTRAINT FK_b_user_power_module FOREIGN KEY (b_module_id) REFERENCES dbo.s_module (b_id),
CONSTRAINT FK_b_user_power_power FOREIGN KEY (b_power_id) REFERENCES dbo.s_module_power (b_id)
);
CREATE INDEX IX_b_user_power_module ON dbo.b_user_power (b_module_id, b_user_id);
INSERT INTO dbo.s_module SELECT * FROM dbo.z_restore_module;
INSERT INTO dbo.s_module_field SELECT * FROM dbo.z_restore_module_field;
INSERT INTO dbo.s_module_auto_code SELECT * FROM dbo.z_restore_module_auto_code;
INSERT INTO dbo.s_module_field_group SELECT * FROM dbo.z_restore_module_field_group;
INSERT INTO dbo.s_module_field_list SELECT * FROM dbo.z_restore_module_field_list;
INSERT INTO dbo.s_module_field_edit SELECT * FROM dbo.z_restore_module_field_edit;
INSERT INTO dbo.s_module_field_query SELECT * FROM dbo.z_restore_module_field_query;
INSERT INTO dbo.s_module_power SELECT * FROM dbo.z_restore_module_power;
INSERT INTO dbo.b_user_module (b_id, b_user_id, b_module_id, b_inputuser_id)
SELECT 860000000000000000 + ROW_NUMBER() OVER (ORDER BY b_user_id, b_module_id),
b_user_id, b_module_id, @AdminId
FROM dbo.z_restore_user_module;
INSERT INTO dbo.b_user_power (b_id, b_user_id, b_module_id, b_power_id, b_inputuser_id)
SELECT 870000000000000000 + ROW_NUMBER() OVER (ORDER BY b_user_id, b_power_id),
b_user_id, b_module_id, b_power_id, @AdminId
FROM dbo.z_restore_user_power;
DROP TABLE dbo.z_restore_user_power;
DROP TABLE dbo.z_restore_user_module;
DROP TABLE dbo.z_restore_module_power;
DROP TABLE dbo.z_restore_module_field_query;
DROP TABLE dbo.z_restore_module_field_edit;
DROP TABLE dbo.z_restore_module_field_list;
DROP TABLE dbo.z_restore_module_field_group;
DROP TABLE dbo.z_restore_module_auto_code;
DROP TABLE dbo.z_restore_module_field;
DROP TABLE dbo.z_restore_i18n_map;
DROP TABLE dbo.z_restore_module;
GO
CREATE OR ALTER TRIGGER dbo.TR_s_module_simple_tree
ON dbo.s_module
AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (
SELECT 1
FROM inserted AS child
INNER JOIN dbo.s_module AS parent_row ON parent_row.b_id = child.b_parent_id
WHERE (child.b_module_type = 'directory' AND parent_row.b_module_type <> 'directory')
OR (child.b_module_type = 'page' AND parent_row.b_module_type <> 'directory')
OR (child.b_module_type = 'data_category' AND parent_row.b_module_type NOT IN ('page', 'data_category'))
OR (child.b_module_type = 'data' AND parent_row.b_module_type NOT IN ('page', 'data_category'))
)
THROW 53508, N'Invalid parent type in the simple module tree.', 1;
IF EXISTS (
SELECT 1 FROM inserted
WHERE b_module_type IN ('data_category', 'data') AND b_parent_id IS NULL
)
THROW 53509, N'Data categories and data modules require a page parent.', 1;
DECLARE @Cycle bit = 0;
;WITH tree AS (
SELECT child.b_id AS origin_id, child.b_parent_id AS current_id
FROM inserted AS child
WHERE child.b_parent_id IS NOT NULL
UNION ALL
SELECT tree.origin_id, parent_row.b_parent_id
FROM tree
INNER JOIN dbo.s_module AS parent_row ON parent_row.b_id = tree.current_id
WHERE tree.current_id IS NOT NULL
)
SELECT TOP (1) @Cycle = 1 FROM tree WHERE current_id = origin_id OPTION (MAXRECURSION 32767);
IF @Cycle = 1 THROW 53510, N'Module tree cycle detected.', 1;
END;
@@ -1,28 +0,0 @@
# Database migrations
Module architecture cutover is manual and is not run during application startup.
Run against a backed-up `FMS` database in this order:
1. `033_create_module_structure.sql`
2. `034_module_runtime_views.sql`
3. `verify_module_architecture.sql`
`033` is a one-time transaction: it migrates valid metadata and removes the old metadata tables only after conversion checks pass. It intentionally does not create compatibility views or dual writes.
If the earlier intermediate implementation created only `s_module_profile`, `s_function_node`, or `s_page_node`, `033` verifies that the complete source model still exists and regenerates those derived tables inside the same transaction. Other partial target states are rejected.
`033` and `034` use SQL Server `GO` batch separators. Use SSMS, Azure Data Studio, `sqlcmd`, or another runner that understands `GO`.
`verify_module_architecture.sql` is a target-schema verification script. It does not modify application tables.
To check and conditionally apply `034` with the repository JDBC driver on Windows:
```powershell
$jdk = "D:\devtool\jdk\jdk-21\bin"
$driver = "tools\migration\mssql-jdbc-13.4.0.jre11.jar"
& "$jdk\javac.exe" -encoding UTF-8 -cp $driver -d $env:TEMP config\migrations\tools\ApplyModuleRuntimeViews.java
& "$jdk\java.exe" -cp "$env:TEMP;$driver" ApplyModuleRuntimeViews
```
The tool refuses non-`FMS` catalogs and executes `034` only when a required runtime view is missing.
For a database in the validated intermediate state, run `ApplyModuleRuntimeViews --dry-run-cutover` first. After verifying a database backup, `ApplyModuleRuntimeViews --apply-cutover` executes `033`, then conditionally executes `034` and verifies all required runtime views.
@@ -1,302 +0,0 @@
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.HashSet;
/** Applies the module cutover and runtime views with prerequisite and completion checks. */
public final class ApplyModuleRuntimeViews {
private static final List<String> REQUIRED_TABLES = List.of(
"s_module",
"s_module_page",
"s_module_data",
"s_module_report",
"s_module_dashboard",
"s_module_workflow",
"s_function_node",
"s_page_node",
"s_module_profile",
"s_module_field",
"s_module_field_list",
"s_module_field_form",
"s_module_field_query",
"s_module_action",
"b_role",
"b_user_role",
"b_role_function_node",
"b_role_page_node",
"b_role_action",
"b_user_function_node",
"b_user_page_node",
"b_user_action"
);
private static final List<String> REQUIRED_VIEWS = List.of(
"v_s_function_node",
"v_s_page_node",
"v_s_module_profile",
"v_s_module_runtime",
"v_s_module_field_list",
"v_s_module_field_form",
"v_s_module_field_query",
"v_s_module_action",
"v_s_user_function_permission",
"v_s_user_page_permission",
"v_s_user_action_permission"
);
private static final List<String> INSPECTION_TABLES = List.of(
"s_module",
"s_module_profile",
"s_function_node",
"s_page_node",
"s_module_field",
"s_module_field_list",
"s_module_field_edit",
"s_module_field_query",
"s_module_field_group",
"s_module_power",
"b_user_module",
"b_user_power"
);
public static void main(String[] args) throws Exception {
Path apiRoot = Path.of("").toAbsolutePath().normalize();
boolean hasModeArgument = args.length > 0 && args[0].startsWith("--");
String mode = hasModeArgument ? args[0] : "--views-only";
int configIndex = hasModeArgument ? 1 : 0;
Path configPath = args.length > configIndex
? apiRoot.resolve(args[configIndex]).normalize()
: apiRoot.resolve("config/dbconfigs/g3hd.properties");
Path cutoverPath = apiRoot.resolve("config/migrations/033_create_module_structure.sql");
Path migrationPath = apiRoot.resolve("config/migrations/034_module_runtime_views.sql");
requirePathWithin(apiRoot, configPath);
requirePathWithin(apiRoot, cutoverPath);
requirePathWithin(apiRoot, migrationPath);
Properties properties = new Properties();
try (InputStream input = Files.newInputStream(configPath)) {
properties.load(input);
}
try (Connection connection = DriverManager.getConnection(
required(properties, "url"),
required(properties, "username"),
required(properties, "password")
)) {
if (!"FMS".equalsIgnoreCase(connection.getCatalog())) {
throw new IllegalStateException("Refusing to migrate database: " + connection.getCatalog());
}
if (mode.equals("--dry-run-cutover")) {
List<String> cutoverTables = missingObjects(connection, "sys.tables", REQUIRED_TABLES);
if (!cutoverTables.isEmpty()) {
executeCutover(connection, cutoverPath, true);
}
System.out.println("PASS|033_create_module_structure.sql|dry_run=true|committed=false");
return;
}
if (mode.equals("--apply-cutover")) {
List<String> cutoverTables = missingObjects(connection, "sys.tables", REQUIRED_TABLES);
if (cutoverTables.isEmpty()) {
System.out.println("PASS|033_create_module_structure.sql|applied=false");
} else {
executeCutover(connection, cutoverPath, false);
cutoverTables = missingObjects(connection, "sys.tables", REQUIRED_TABLES);
if (!cutoverTables.isEmpty()) {
throw new IllegalStateException(
"Migration 033 did not complete; tables remain missing: "
+ String.join(",", cutoverTables)
);
}
System.out.println("APPLIED|033_create_module_structure.sql");
}
} else if (!mode.equals("--views-only")) {
throw new IllegalArgumentException("Unknown mode: " + mode);
}
List<String> missingTables = missingObjects(connection, "sys.tables", REQUIRED_TABLES);
if (!missingTables.isEmpty()) {
System.out.println("MISSING_PREREQUISITE_TABLES|" + String.join(",", missingTables));
printPartialState(connection);
throw new IllegalStateException("Run migration 033 before migration 034");
}
List<String> missingBefore = missingViews(connection);
if (missingBefore.isEmpty()) {
System.out.println("PASS|required_module_views=present|applied=false");
return;
}
System.out.println("MISSING|" + String.join(",", missingBefore));
connection.setAutoCommit(false);
try {
String migration = Files.readString(migrationPath, StandardCharsets.UTF_8);
int batches = executeBatches(connection, migration);
List<String> missingAfter = missingViews(connection);
if (!missingAfter.isEmpty()) {
throw new IllegalStateException(
"Required views remain missing: " + String.join(",", missingAfter)
);
}
connection.commit();
System.out.println("APPLIED|034_module_runtime_views.sql|batches=" + batches);
System.out.println("PASS|required_module_views=present|applied=true");
} catch (Exception exception) {
connection.rollback();
throw exception;
} finally {
connection.setAutoCommit(true);
}
}
}
private static List<String> missingViews(Connection connection) throws Exception {
return missingObjects(connection, "sys.views", REQUIRED_VIEWS);
}
private static List<String> missingObjects(
Connection connection,
String catalogView,
List<String> requiredObjects
) throws Exception {
Set<String> existing = new HashSet<>();
try (Statement statement = connection.createStatement(); ResultSet rows = statement.executeQuery(
"SELECT name FROM " + catalogView + " WHERE schema_id = SCHEMA_ID(N'dbo')"
)) {
while (rows.next()) existing.add(rows.getString(1));
}
List<String> missing = new ArrayList<>();
for (String required : requiredObjects) {
if (!existing.contains(required)) missing.add(required);
}
return missing;
}
private static int executeBatches(Connection connection, String migration) throws Exception {
String[] batches = migration.split("(?im)^\\s*GO\\s*(?:--.*)?$");
int executed = 0;
for (String batch : batches) {
if (batch.isBlank()) continue;
try (Statement statement = connection.createStatement()) {
boolean hasResult = statement.execute(batch);
while (true) {
if (hasResult) {
try (ResultSet rows = statement.getResultSet()) {
while (rows.next()) {
// Drain server results so the complete SQL batch finishes.
}
}
} else if (statement.getUpdateCount() == -1) {
break;
}
hasResult = statement.getMoreResults();
}
}
executed++;
}
return executed;
}
private static void executeCutover(Connection connection, Path migrationPath, boolean dryRun)
throws Exception {
connection.setAutoCommit(false);
String migration = Files.readString(migrationPath, StandardCharsets.UTF_8);
migration = migration.replaceAll(
"(?s)/\\* CUTOVER_INSTALLED_GUARD_START \\*/.*?"
+ "/\\* CUTOVER_INSTALLED_GUARD_END \\*/",
""
);
migration = migration.replaceAll(
"(?s)/\\* RETURN in the first batch means the architecture was already installed\\. \\*/"
+ "\\s*IF @@TRANCOUNT = 0\\s*RETURN;",
""
);
migration = migration.replaceAll("(?im)^\\s*BEGIN TRANSACTION;\\s*$", "");
migration = migration.replaceAll("(?im)^\\s*COMMIT TRANSACTION;\\s*$", "");
try {
printCutoverState(connection, "before");
int batches = executeBatches(connection, migration);
printCutoverState(connection, "after-sql");
List<String> missingTables = missingObjects(connection, "sys.tables", REQUIRED_TABLES);
if (!missingTables.isEmpty()) {
throw new IllegalStateException(
"Migration 033 did not create required tables: " + String.join(",", missingTables)
);
}
if (dryRun) {
connection.rollback();
} else {
connection.commit();
}
printCutoverState(connection, "after-jdbc");
System.out.println("CUTOVER_SQL|dry_run=" + dryRun + "|batches=" + batches);
} catch (Exception exception) {
try (Statement statement = connection.createStatement()) {
statement.execute("IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION");
}
connection.rollback();
throw exception;
} finally {
connection.setAutoCommit(true);
}
}
private static void printCutoverState(Connection connection, String phase) throws Exception {
try (Statement statement = connection.createStatement(); ResultSet rows = statement.executeQuery(
"SELECT @@TRANCOUNT, CASE WHEN OBJECT_ID(N'dbo.s_module_page', N'U') IS NULL THEN 0 ELSE 1 END"
)) {
rows.next();
System.out.println("CUTOVER_STATE|" + phase + "|trancount=" + rows.getInt(1)
+ "|s_module_page=" + (rows.getInt(2) == 1));
}
}
private static void printPartialState(Connection connection) throws Exception {
Set<String> existing = new HashSet<>();
try (Statement statement = connection.createStatement(); ResultSet rows = statement.executeQuery(
"SELECT name FROM sys.tables WHERE schema_id = SCHEMA_ID(N'dbo')"
)) {
while (rows.next()) existing.add(rows.getString(1));
}
for (String table : INSPECTION_TABLES) {
if (!existing.contains(table)) continue;
try (Statement statement = connection.createStatement(); ResultSet rows = statement.executeQuery(
"SELECT COUNT_BIG(*) FROM dbo.[" + table.replace("]", "]]" ) + "]"
)) {
rows.next();
System.out.println("TABLE_STATE|" + table + "|rows=" + rows.getLong(1));
}
List<String> columns = new ArrayList<>();
try (Statement statement = connection.createStatement(); ResultSet rows = statement.executeQuery(
"SELECT column_row.name, TYPE_NAME(column_row.user_type_id), column_row.is_nullable "
+ "FROM sys.columns AS column_row "
+ "WHERE column_row.object_id = OBJECT_ID(N'dbo.["
+ table.replace("]", "]]" )
+ "]') ORDER BY column_row.column_id"
)) {
while (rows.next()) {
columns.add(rows.getString(1) + ":" + rows.getString(2)
+ (rows.getBoolean(3) ? "?" : ""));
}
}
System.out.println("TABLE_COLUMNS|" + table + "|" + String.join(",", columns));
}
}
private static String required(Properties properties, String key) {
String value = properties.getProperty(key);
if (value == null || value.isBlank()) throw new IllegalStateException("Missing property: " + key);
return value.trim();
}
private static void requirePathWithin(Path root, Path path) {
if (!path.startsWith(root)) throw new IllegalArgumentException("Path is outside API root: " + path);
}
}
@@ -0,0 +1,90 @@
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
public final class ApplySimpleModuleRestore {
public static void main(String[] args) throws Exception {
Path apiRoot = Path.of("").toAbsolutePath().normalize();
Path configPath = apiRoot.resolve("config/dbconfigs/g3hd.properties").normalize();
Path migrationPath = apiRoot.resolve("config/migrations/035_restore_simple_module_tree.sql").normalize();
Properties properties = new Properties();
try (InputStream input = Files.newInputStream(configPath)) {
properties.load(input);
}
try (Connection connection = DriverManager.getConnection(
required(properties, "url"),
required(properties, "username"),
required(properties, "password"))) {
if (!"FMS".equalsIgnoreCase(connection.getCatalog())) {
throw new IllegalStateException("Refusing to restore database: " + connection.getCatalog());
}
if (args.length == 1 && "--verify-only".equals(args[0])) {
verify(connection);
return;
}
connection.setAutoCommit(false);
try {
String migration = Files.readString(migrationPath, StandardCharsets.UTF_8);
int batches = executeBatches(connection, migration);
verify(connection);
connection.commit();
System.out.println("APPLIED|035_restore_simple_module_tree.sql|batches=" + batches);
} catch (Exception exception) {
connection.rollback();
throw exception;
}
}
}
private static int executeBatches(Connection connection, String migration) throws Exception {
String[] batches = migration.split("(?im)^\\s*GO\\s*(?:--.*)?$");
int count = 0;
for (String batch : batches) {
if (batch.isBlank()) continue;
try (Statement statement = connection.createStatement()) {
statement.execute(batch);
}
count++;
}
return count;
}
private static void verify(Connection connection) throws Exception {
String sql = """
SELECT
CASE WHEN COL_LENGTH(N'dbo.s_module', N'b_parent_id') IS NULL THEN 0 ELSE 1 END,
CASE WHEN OBJECT_ID(N'dbo.s_module_page', N'U') IS NULL THEN 0 ELSE 1 END,
(SELECT COUNT(*) FROM dbo.s_module WHERE b_module_type = 'data_category'),
(SELECT COUNT(*)
FROM dbo.s_module child
LEFT JOIN dbo.s_module parent ON parent.b_id = child.b_parent_id
WHERE (child.b_module_type IN ('directory', 'page')
AND child.b_parent_id IS NOT NULL
AND ISNULL(parent.b_module_type, '') <> 'directory')
OR (child.b_module_type IN ('data_category', 'data')
AND ISNULL(parent.b_module_type, '') NOT IN ('page', 'data_category')))
""";
try (Statement statement = connection.createStatement(); ResultSet rows = statement.executeQuery(sql)) {
rows.next();
if (rows.getInt(1) != 1 || rows.getInt(2) != 0 || rows.getInt(4) != 0) {
throw new IllegalStateException("Simple module tree verification failed");
}
System.out.println(
"PASS|simple_module_tree|data_categories=" + rows.getInt(3) + "|invalid_parents=0");
}
}
private static String required(Properties properties, String key) {
String value = properties.getProperty(key);
if (value == null || value.isBlank()) throw new IllegalStateException("Missing property: " + key);
return value;
}
}
@@ -30,7 +30,7 @@ public final class GenerateBusinessMigrations {
"dtproperties", "log_datas"
);
private static final Set<String> TREE_TABLES = lowerSet(
"b_other_bmfl", "bc_pricelist_bmfl", "oa_title_bmfl"
"bc_pricelist_bmfl", "oa_title_bmfl"
);
private static final Set<String> EXCLUDED_VIEWS = lowerSet(
"v_autoidrule", "v_b_contact", "v_b_employee", "v_b_user_record"
@@ -1,163 +0,0 @@
/* Read-only verification for the module architecture cutover. */
SET NOCOUNT ON;
IF DB_NAME() <> N'FMS'
THROW 53500, N'This verification can only run against the FMS database.', 1;
IF EXISTS (
SELECT required.name
FROM (VALUES
(N's_module'), (N's_module_page'), (N's_module_data'), (N's_module_report'),
(N's_module_dashboard'), (N's_module_workflow'), (N's_function_node'),
(N's_page_node'), (N's_module_profile'), (N's_module_field'),
(N's_module_field_list'), (N's_module_field_form'), (N's_module_field_query'),
(N's_module_action'), (N's_module_relation'), (N'b_role'), (N'b_user_role'),
(N'b_role_data_scope')
) AS required(name)
LEFT JOIN sys.tables AS actual ON actual.name = required.name AND actual.schema_id = SCHEMA_ID(N'dbo')
WHERE actual.object_id IS NULL
)
THROW 53501, N'Required module architecture tables are missing.', 1;
IF EXISTS (
SELECT required.name
FROM (VALUES
(N'v_s_function_node'), (N'v_s_page_node'), (N'v_s_module_runtime'),
(N'v_s_module_profile'), (N'v_s_module_action'),
(N'v_s_user_function_permission'), (N'v_s_user_page_permission'),
(N'v_s_user_action_permission')
) AS required(name)
LEFT JOIN sys.views AS actual ON actual.name = required.name AND actual.schema_id = SCHEMA_ID(N'dbo')
WHERE actual.object_id IS NULL
)
THROW 53502, N'Required module runtime views are missing.', 1;
IF EXISTS (
SELECT 1
FROM (VALUES
(N's_module_field_edit'), (N's_module_power'), (N'b_user_module'),
(N'b_user_power'), (N'b_other_bmfl')
) AS legacy(name)
INNER JOIN sys.tables AS actual ON actual.name = legacy.name AND actual.schema_id = SCHEMA_ID(N'dbo')
)
THROW 53503, N'Legacy module metadata tables still exist.', 1;
IF EXISTS (
SELECT 1
FROM dbo.s_module AS module_row
LEFT JOIN dbo.s_module_page AS page_row ON page_row.b_module_id = module_row.b_id
LEFT JOIN dbo.s_module_data AS data_row ON data_row.b_module_id = module_row.b_id
LEFT JOIN dbo.s_module_report AS report_row ON report_row.b_module_id = module_row.b_id
LEFT JOIN dbo.s_module_dashboard AS dashboard_row ON dashboard_row.b_module_id = module_row.b_id
LEFT JOIN dbo.s_module_workflow AS workflow_row ON workflow_row.b_module_id = module_row.b_id
WHERE (CASE WHEN page_row.b_module_id IS NULL THEN 0 ELSE 1 END
+ CASE WHEN data_row.b_module_id IS NULL THEN 0 ELSE 1 END
+ CASE WHEN report_row.b_module_id IS NULL THEN 0 ELSE 1 END
+ CASE WHEN dashboard_row.b_module_id IS NULL THEN 0 ELSE 1 END
+ CASE WHEN workflow_row.b_module_id IS NULL THEN 0 ELSE 1 END) <> 1
OR (module_row.b_module_type = 'page' AND page_row.b_module_id IS NULL)
OR (module_row.b_module_type = 'data' AND data_row.b_module_id IS NULL)
OR (module_row.b_module_type = 'report' AND report_row.b_module_id IS NULL)
OR (module_row.b_module_type = 'dashboard' AND dashboard_row.b_module_id IS NULL)
OR (module_row.b_module_type = 'workflow' AND workflow_row.b_module_id IS NULL)
)
THROW 53504, N'Module subtype records are incomplete or conflicting.', 1;
IF EXISTS (
SELECT 1
FROM dbo.s_module AS module_row
LEFT JOIN dbo.s_module_profile AS profile_row
ON profile_row.b_module_id = module_row.b_id AND profile_row.b_default = 1
WHERE module_row.b_module_type = 'data' AND profile_row.b_id IS NULL
)
THROW 53505, N'A data module has no default profile.', 1;
IF EXISTS (
SELECT 1
FROM dbo.s_module_profile AS profile_row
INNER JOIN dbo.s_module AS module_row ON module_row.b_id = profile_row.b_module_id
WHERE module_row.b_module_type <> 'data'
)
THROW 53506, N'A profile belongs to a non-data module.', 1;
IF EXISTS (
SELECT 1
FROM dbo.s_function_node AS child
INNER JOIN dbo.s_function_node AS parent_row ON parent_row.b_id = child.b_parent_id
WHERE parent_row.b_node_type <> 'directory'
)
THROW 53507, N'A function node is placed below a non-directory node.', 1;
IF EXISTS (
SELECT 1
FROM dbo.s_page_node AS child
INNER JOIN dbo.s_page_node AS parent_row
ON parent_row.b_page_module_id = child.b_page_module_id
AND parent_row.b_id = child.b_parent_id
WHERE parent_row.b_node_type = 'module_ref'
)
THROW 53508, N'A page node is placed below a module reference.', 1;
DECLARE @FunctionCycle bit = 0;
;WITH function_tree AS (
SELECT b_id AS origin_id, b_parent_id AS current_id,
CAST(N'/' + CONVERT(nvarchar(30), b_id) + N'/' AS nvarchar(max)) AS visited
FROM dbo.s_function_node
WHERE b_parent_id IS NOT NULL
UNION ALL
SELECT tree.origin_id, parent_row.b_parent_id,
tree.visited + CONVERT(nvarchar(30), parent_row.b_id) + N'/'
FROM function_tree AS tree
INNER JOIN dbo.s_function_node AS parent_row ON parent_row.b_id = tree.current_id
WHERE tree.current_id IS NOT NULL
AND tree.visited NOT LIKE N'%/' + CONVERT(nvarchar(30), parent_row.b_id) + N'/%'
)
SELECT TOP (1) @FunctionCycle = 1
FROM function_tree WHERE current_id = origin_id
OPTION (MAXRECURSION 32767);
IF @FunctionCycle = 1
THROW 53509, N'The function tree contains a cycle.', 1;
DECLARE @PageCycle bit = 0;
;WITH page_tree AS (
SELECT b_page_module_id AS page_id, b_id AS origin_id, b_parent_id AS current_id,
CAST(N'/' + CONVERT(nvarchar(30), b_id) + N'/' AS nvarchar(max)) AS visited
FROM dbo.s_page_node
WHERE b_parent_id IS NOT NULL
UNION ALL
SELECT tree.page_id, tree.origin_id, parent_row.b_parent_id,
tree.visited + CONVERT(nvarchar(30), parent_row.b_id) + N'/'
FROM page_tree AS tree
INNER JOIN dbo.s_page_node AS parent_row
ON parent_row.b_page_module_id = tree.page_id AND parent_row.b_id = tree.current_id
WHERE tree.current_id IS NOT NULL
AND tree.visited NOT LIKE N'%/' + CONVERT(nvarchar(30), parent_row.b_id) + N'/%'
)
SELECT TOP (1) @PageCycle = 1
FROM page_tree WHERE current_id = origin_id
OPTION (MAXRECURSION 32767);
IF @PageCycle = 1
THROW 53510, N'The page tree contains a cycle.', 1;
IF EXISTS (SELECT 1 FROM dbo.s_module WHERE b_i18n <> 'meta.module.' + CONVERT(varchar(30), b_id))
THROW 53511, N'Module i18n keys are not ID based.', 1;
IF EXISTS (SELECT 1 FROM dbo.s_function_node WHERE b_i18n <> 'meta.node.' + CONVERT(varchar(30), b_id))
THROW 53512, N'Function node i18n keys are not ID based.', 1;
IF EXISTS (SELECT 1 FROM dbo.s_page_node WHERE b_i18n <> 'meta.node.' + CONVERT(varchar(30), b_id))
THROW 53513, N'Page node i18n keys are not ID based.', 1;
IF EXISTS (SELECT 1 FROM dbo.s_module_profile WHERE b_i18n <> 'meta.profile.' + CONVERT(varchar(30), b_id))
THROW 53514, N'Profile i18n keys are not ID based.', 1;
IF EXISTS (SELECT 1 FROM dbo.s_module_field WHERE b_i18n <> 'meta.field.' + CONVERT(varchar(30), b_id))
THROW 53515, N'Field i18n keys are not ID based.', 1;
IF EXISTS (SELECT 1 FROM dbo.s_module_action WHERE b_i18n <> 'meta.action.' + CONVERT(varchar(30), b_id))
THROW 53516, N'Action i18n keys are not ID based.', 1;
SELECT
(SELECT COUNT(*) FROM dbo.s_module) AS module_count,
(SELECT COUNT(*) FROM dbo.s_function_node) AS function_node_count,
(SELECT COUNT(*) FROM dbo.s_page_node) AS page_node_count,
(SELECT COUNT(*) FROM dbo.s_module_profile) AS profile_count,
(SELECT COUNT(*) FROM dbo.s_module_field) AS field_count,
(SELECT COUNT(*) FROM dbo.s_module_action) AS action_count;
@@ -6,9 +6,7 @@ import cn.g3soft.fmsapi.utils.ApiResponse;
import cn.g3soft.fmsapi.utils.ParamUtils;
import cn.g3soft.fmsapi.utils.snowflake.idgen.IdGenerator;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -57,8 +55,12 @@ public class DataController {
return ApiResponse.success("保存成功", null);
}
@GetMapping("/nextid")
public ApiResponse<?> nextId(@RequestParam(required = false, defaultValue = "1") int count) {
@PostMapping("/nextid")
public ApiResponse<?> nextId(@RequestBody(required = false) Map<String, Object> params) {
int count = 1;
if (params != null && params.get("count") instanceof Number num) {
count = num.intValue();
}
if (count <= 1) {
return ApiResponse.success(IdGenerator.nextId());
}
@@ -69,11 +71,14 @@ public class DataController {
return ApiResponse.success(ids);
}
@GetMapping("/nextcode")
public ApiResponse<?> nextCode(
@RequestParam String moduleId,
@RequestParam(required = false, defaultValue = "1") int count
) throws SQLException {
@PostMapping("/nextcode")
public ApiResponse<?> nextCode(@RequestBody(required = false) Map<String, Object> params)
throws SQLException {
String moduleId = ParamUtils.getRequiredString(params, "moduleId");
int count = 1;
if (params != null && params.get("count") instanceof Number num) {
count = num.intValue();
}
List<String> codes = dataSaveService.nextCode(moduleId, count);
if (codes.size() == 1) {
return ApiResponse.success(codes.get(0));