diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/FodyWeavers.xml b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN.Abp.Quartz.MySqlInstaller.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN.Abp.Quartz.MySqlInstaller.csproj
new file mode 100644
index 000000000..7f15d10c2
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN.Abp.Quartz.MySqlInstaller.csproj
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+ netstandard2.0;netstandard2.1;net8.0;net9.0
+ LINGYUN.Abp.Quartz.MySqlInstaller
+ LINGYUN.Abp.Quartz.MySqlInstaller
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/AbpQuartzMySqlInstallerModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/AbpQuartzMySqlInstallerModule.cs
new file mode 100644
index 000000000..b7878f537
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/AbpQuartzMySqlInstallerModule.cs
@@ -0,0 +1,30 @@
+using Microsoft.Extensions.DependencyInjection;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Modularity;
+using Volo.Abp.Quartz;
+using Volo.Abp.VirtualFileSystem;
+
+namespace LINGYUN.Abp.Quartz.MySqlInstaller;
+
+[DependsOn(
+ typeof(AbpQuartzModule),
+ typeof(AbpVirtualFileSystemModule))]
+public class AbpQuartzMySqlInstallerModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.FileSets.AddEmbedded();
+ });
+ }
+
+ public async override Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context)
+ {
+ // 初始化 Quartz Mysql 数据库
+ await context.ServiceProvider
+ .GetRequiredService()
+ .InstallAsync();
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/QuartzMySqlInstaller.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/QuartzMySqlInstaller.cs
new file mode 100644
index 000000000..40e6dfb22
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/QuartzMySqlInstaller.cs
@@ -0,0 +1,136 @@
+using Microsoft.Extensions.FileProviders;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Options;
+using MySqlConnector;
+using System;
+using System.Data;
+using System.Threading.Tasks;
+using Volo.Abp.Quartz;
+using Volo.Abp.VirtualFileSystem;
+using static Quartz.SchedulerBuilder;
+
+namespace LINGYUN.Abp.Quartz.MySqlInstaller;
+
+public class QuartzMySqlInstaller
+{
+ public ILogger Logger { protected get; set; }
+
+ private readonly IVirtualFileProvider _virtualFileProvider;
+ private readonly AbpQuartzOptions _quartzOptions;
+
+ public QuartzMySqlInstaller(
+ IVirtualFileProvider virtualFileProvider,
+ IOptions quartzOptions)
+ {
+ _quartzOptions = quartzOptions.Value;
+ _virtualFileProvider = virtualFileProvider;
+
+ Logger = NullLogger.Instance;
+ }
+
+ public async virtual Task InstallAsync()
+ {
+ var dataSource = _quartzOptions.Properties["quartz.jobStore.dataSource"] ?? AdoProviderOptions.DefaultDataSourceName;
+ var connectionString = _quartzOptions.Properties[$"quartz.dataSource.{dataSource}.connectionString"];
+ var tablePrefix = _quartzOptions.Properties["quartz.jobStore.tablePrefix"] ?? "QRTZ_";
+
+ if (connectionString.IsNullOrWhiteSpace())
+ {
+ Logger.LogWarning($"Please configure the `{dataSource}` database connection string in `quartz.jobStore.dataSource`!");
+ throw new ArgumentNullException(nameof(connectionString));
+ }
+
+ Logger.LogInformation("Install Quartz MySql...");
+
+ var builder = new MySqlConnectionStringBuilder(connectionString);
+
+ var dataBaseName = await CreateDataBaseIfNotExists(builder.Database, builder);
+
+ builder.Database = dataBaseName;
+
+ using var mySqlConnection = new MySqlConnection(builder.ConnectionString);
+
+ if (mySqlConnection.State == ConnectionState.Closed)
+ {
+ await mySqlConnection.OpenAsync();
+ }
+
+ using (var mySqlCommand = new MySqlCommand("SELECT COUNT(1) FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA` = @DataBaseName;", mySqlConnection))
+ {
+ mySqlCommand.Parameters.Add("@DataBaseName", MySqlDbType.String).Value = dataBaseName;
+
+ var rowsAffects = await mySqlCommand.ExecuteScalarAsync() as long?;
+ if (rowsAffects > 0)
+ {
+ Logger.LogInformation($"The `{dataBaseName}` tables has already exists.");
+ return;
+ }
+ }
+
+ var sqlScript = await GetInitSqlScript();
+
+ // USE `${DataBase}` -> USE `Workflow`;
+ sqlScript = sqlScript.ReplaceFirst("${DataBase}", dataBaseName);
+ // CREATE TABLE $(TablePrefix)JOB_DETAILS` -> CREATE TABLE QRTZ_JOB_DETAILS;
+ sqlScript = sqlScript.Replace("${TablePrefix}", tablePrefix);
+
+ using (var mySqlCommand = new MySqlCommand(sqlScript, mySqlConnection))
+ {
+ Logger.LogInformation("The database initialization script `Initial.sql` starts...");
+
+ await mySqlCommand.ExecuteNonQueryAsync();
+ }
+
+ Logger.LogInformation("Database initialization script `Initial.sql` complete!");
+ }
+
+ public async virtual Task CreateDataBaseIfNotExists(string dataBase, MySqlConnectionStringBuilder connectionStringBuilder)
+ {
+ // 切换主数据库查询数据库是否存在
+ connectionStringBuilder.Database = "mysql";
+ using var mySqlConnection = new MySqlConnection(connectionStringBuilder.ConnectionString);
+ if (mySqlConnection.State == ConnectionState.Closed)
+ {
+ await mySqlConnection.OpenAsync();
+ }
+
+ var checkDataBaseName = "";
+ using (var mySqlCommand = new MySqlCommand("SELECT `SCHEMA_NAME` FROM `information_schema`.`SCHEMATA` WHERE `SCHEMA_NAME` = @DataBaseName;", mySqlConnection))
+ {
+ var dataBaseParamter = mySqlCommand.Parameters.Add("DataBaseName", DbType.String);
+ dataBaseParamter.Value = dataBase;
+
+ checkDataBaseName = await mySqlCommand.ExecuteScalarAsync() as string;
+ }
+
+ if (checkDataBaseName.IsNullOrWhiteSpace())
+ {
+ using (var mySqlCommand = new MySqlCommand($"CREATE DATABASE `{dataBase}` CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci';", mySqlConnection))
+ {
+ await mySqlCommand.ExecuteNonQueryAsync();
+ }
+ }
+
+ return dataBase;
+ }
+
+ public async virtual Task GetInitSqlScript()
+ {
+ var sqlScriptFileInfo = _virtualFileProvider.GetFileInfo("/LINGYUN/Abp/Quartz/MySqlInstaller/Scripts/Initial.sql");
+ if (!sqlScriptFileInfo.Exists || sqlScriptFileInfo.IsDirectory)
+ {
+ Logger.LogWarning("Please Check that the `Initial.sql` file exists!");
+ throw new InvalidOperationException("The `Initial.sql` database initialization script file does not exist or is not valid!");
+ }
+
+ var sqlScript = await sqlScriptFileInfo.ReadAsStringAsync();
+ if (sqlScript.IsNullOrWhiteSpace())
+ {
+ Logger.LogWarning("The contents of the `Initial.sql` file are empty or invalid!");
+ throw new InvalidOperationException("The contents of the `Initial.sql` file are empty or invalid!");
+ }
+
+ return sqlScript;
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/Scripts/Initial.sql b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/Scripts/Initial.sql
new file mode 100644
index 000000000..85a70bfff
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/Scripts/Initial.sql
@@ -0,0 +1,181 @@
+# By: Ron Cordell - roncordell
+# I didn't see this anywhere, so I thought I'd post it here. This is the script from Quartz to create the tables in a MySQL database, modified to use INNODB instead of MYISAM.
+
+
+# make sure you have UTF-8 collaction for best .NET interoperability
+# CREATE DATABASE quartznet CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+USE `${DataBase}`;
+
+DROP TABLE IF EXISTS ${TablePrefix}FIRED_TRIGGERS;
+DROP TABLE IF EXISTS ${TablePrefix}PAUSED_TRIGGER_GRPS;
+DROP TABLE IF EXISTS ${TablePrefix}SCHEDULER_STATE;
+DROP TABLE IF EXISTS ${TablePrefix}LOCKS;
+DROP TABLE IF EXISTS ${TablePrefix}SIMPLE_TRIGGERS;
+DROP TABLE IF EXISTS ${TablePrefix}SIMPROP_TRIGGERS;
+DROP TABLE IF EXISTS ${TablePrefix}CRON_TRIGGERS;
+DROP TABLE IF EXISTS ${TablePrefix}BLOB_TRIGGERS;
+DROP TABLE IF EXISTS ${TablePrefix}TRIGGERS;
+DROP TABLE IF EXISTS ${TablePrefix}JOB_DETAILS;
+DROP TABLE IF EXISTS ${TablePrefix}CALENDARS;
+
+CREATE TABLE ${TablePrefix}JOB_DETAILS(
+SCHED_NAME VARCHAR(120) NOT NULL,
+JOB_NAME VARCHAR(200) NOT NULL,
+JOB_GROUP VARCHAR(200) NOT NULL,
+DESCRIPTION VARCHAR(250) NULL,
+JOB_CLASS_NAME VARCHAR(250) NOT NULL,
+IS_DURABLE BOOLEAN NOT NULL,
+IS_NONCONCURRENT BOOLEAN NOT NULL,
+IS_UPDATE_DATA BOOLEAN NOT NULL,
+REQUESTS_RECOVERY BOOLEAN NOT NULL,
+JOB_DATA BLOB NULL,
+PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
+ENGINE=InnoDB;
+
+CREATE TABLE ${TablePrefix}TRIGGERS (
+SCHED_NAME VARCHAR(120) NOT NULL,
+TRIGGER_NAME VARCHAR(200) NOT NULL,
+TRIGGER_GROUP VARCHAR(200) NOT NULL,
+JOB_NAME VARCHAR(200) NOT NULL,
+JOB_GROUP VARCHAR(200) NOT NULL,
+DESCRIPTION VARCHAR(250) NULL,
+NEXT_FIRE_TIME BIGINT(19) NULL,
+PREV_FIRE_TIME BIGINT(19) NULL,
+PRIORITY INTEGER NULL,
+TRIGGER_STATE VARCHAR(16) NOT NULL,
+TRIGGER_TYPE VARCHAR(8) NOT NULL,
+START_TIME BIGINT(19) NOT NULL,
+END_TIME BIGINT(19) NULL,
+CALENDAR_NAME VARCHAR(200) NULL,
+MISFIRE_INSTR SMALLINT(2) NULL,
+JOB_DATA BLOB NULL,
+PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
+FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
+REFERENCES ${TablePrefix}JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))
+ENGINE=InnoDB;
+
+CREATE TABLE ${TablePrefix}SIMPLE_TRIGGERS (
+SCHED_NAME VARCHAR(120) NOT NULL,
+TRIGGER_NAME VARCHAR(200) NOT NULL,
+TRIGGER_GROUP VARCHAR(200) NOT NULL,
+REPEAT_COUNT BIGINT(7) NOT NULL,
+REPEAT_INTERVAL BIGINT(12) NOT NULL,
+TIMES_TRIGGERED BIGINT(10) NOT NULL,
+PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
+FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
+REFERENCES ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
+ENGINE=InnoDB;
+
+CREATE TABLE ${TablePrefix}CRON_TRIGGERS (
+SCHED_NAME VARCHAR(120) NOT NULL,
+TRIGGER_NAME VARCHAR(200) NOT NULL,
+TRIGGER_GROUP VARCHAR(200) NOT NULL,
+CRON_EXPRESSION VARCHAR(120) NOT NULL,
+TIME_ZONE_ID VARCHAR(80),
+PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
+FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
+REFERENCES ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
+ENGINE=InnoDB;
+
+CREATE TABLE ${TablePrefix}SIMPROP_TRIGGERS
+ (
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ STR_PROP_1 VARCHAR(512) NULL,
+ STR_PROP_2 VARCHAR(512) NULL,
+ STR_PROP_3 VARCHAR(512) NULL,
+ INT_PROP_1 INT NULL,
+ INT_PROP_2 INT NULL,
+ LONG_PROP_1 BIGINT NULL,
+ LONG_PROP_2 BIGINT NULL,
+ DEC_PROP_1 NUMERIC(13,4) NULL,
+ DEC_PROP_2 NUMERIC(13,4) NULL,
+ BOOL_PROP_1 BOOLEAN NULL,
+ BOOL_PROP_2 BOOLEAN NULL,
+ TIME_ZONE_ID VARCHAR(80) NULL,
+ PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
+ FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
+ REFERENCES ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
+ENGINE=InnoDB;
+
+CREATE TABLE ${TablePrefix}BLOB_TRIGGERS (
+SCHED_NAME VARCHAR(120) NOT NULL,
+TRIGGER_NAME VARCHAR(200) NOT NULL,
+TRIGGER_GROUP VARCHAR(200) NOT NULL,
+BLOB_DATA BLOB NULL,
+PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
+INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
+FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
+REFERENCES ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
+ENGINE=InnoDB;
+
+CREATE TABLE ${TablePrefix}CALENDARS (
+SCHED_NAME VARCHAR(120) NOT NULL,
+CALENDAR_NAME VARCHAR(200) NOT NULL,
+CALENDAR BLOB NOT NULL,
+PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
+ENGINE=InnoDB;
+
+CREATE TABLE ${TablePrefix}PAUSED_TRIGGER_GRPS (
+SCHED_NAME VARCHAR(120) NOT NULL,
+TRIGGER_GROUP VARCHAR(200) NOT NULL,
+PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
+ENGINE=InnoDB;
+
+CREATE TABLE ${TablePrefix}FIRED_TRIGGERS (
+SCHED_NAME VARCHAR(120) NOT NULL,
+ENTRY_ID VARCHAR(140) NOT NULL,
+TRIGGER_NAME VARCHAR(200) NOT NULL,
+TRIGGER_GROUP VARCHAR(200) NOT NULL,
+INSTANCE_NAME VARCHAR(200) NOT NULL,
+FIRED_TIME BIGINT(19) NOT NULL,
+SCHED_TIME BIGINT(19) NOT NULL,
+PRIORITY INTEGER NOT NULL,
+STATE VARCHAR(16) NOT NULL,
+JOB_NAME VARCHAR(200) NULL,
+JOB_GROUP VARCHAR(200) NULL,
+IS_NONCONCURRENT BOOLEAN NULL,
+REQUESTS_RECOVERY BOOLEAN NULL,
+PRIMARY KEY (SCHED_NAME,ENTRY_ID))
+ENGINE=InnoDB;
+
+CREATE TABLE ${TablePrefix}SCHEDULER_STATE (
+SCHED_NAME VARCHAR(120) NOT NULL,
+INSTANCE_NAME VARCHAR(200) NOT NULL,
+LAST_CHECKIN_TIME BIGINT(19) NOT NULL,
+CHECKIN_INTERVAL BIGINT(19) NOT NULL,
+PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
+ENGINE=InnoDB;
+
+CREATE TABLE ${TablePrefix}LOCKS (
+SCHED_NAME VARCHAR(120) NOT NULL,
+LOCK_NAME VARCHAR(40) NOT NULL,
+PRIMARY KEY (SCHED_NAME,LOCK_NAME))
+ENGINE=InnoDB;
+
+CREATE INDEX IDX_${TablePrefix}J_REQ_RECOVERY ON ${TablePrefix}JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
+CREATE INDEX IDX_${TablePrefix}J_GRP ON ${TablePrefix}JOB_DETAILS(SCHED_NAME,JOB_GROUP);
+
+CREATE INDEX IDX_${TablePrefix}T_J ON ${TablePrefix}TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
+CREATE INDEX IDX_${TablePrefix}T_JG ON ${TablePrefix}TRIGGERS(SCHED_NAME,JOB_GROUP);
+CREATE INDEX IDX_${TablePrefix}T_C ON ${TablePrefix}TRIGGERS(SCHED_NAME,CALENDAR_NAME);
+CREATE INDEX IDX_${TablePrefix}T_G ON ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
+CREATE INDEX IDX_${TablePrefix}T_STATE ON ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_STATE);
+CREATE INDEX IDX_${TablePrefix}T_N_STATE ON ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
+CREATE INDEX IDX_${TablePrefix}T_N_G_STATE ON ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
+CREATE INDEX IDX_${TablePrefix}T_NEXT_FIRE_TIME ON ${TablePrefix}TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
+CREATE INDEX IDX_${TablePrefix}T_NFT_ST ON ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
+CREATE INDEX IDX_${TablePrefix}T_NFT_MISFIRE ON ${TablePrefix}TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
+CREATE INDEX IDX_${TablePrefix}T_NFT_ST_MISFIRE ON ${TablePrefix}TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
+CREATE INDEX IDX_${TablePrefix}T_NFT_ST_MISFIRE_GRP ON ${TablePrefix}TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
+
+CREATE INDEX IDX_${TablePrefix}FT_TRIG_INST_NAME ON ${TablePrefix}FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
+CREATE INDEX IDX_${TablePrefix}FT_INST_JOB_REQ_RCVRY ON ${TablePrefix}FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
+CREATE INDEX IDX_${TablePrefix}FT_J_G ON ${TablePrefix}FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
+CREATE INDEX IDX_${TablePrefix}FT_JG ON ${TablePrefix}FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
+CREATE INDEX IDX_${TablePrefix}FT_T_G ON ${TablePrefix}FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
+CREATE INDEX IDX_${TablePrefix}FT_TG ON ${TablePrefix}FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
+
+commit;
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/FodyWeavers.xml b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN.Abp.Quartz.SqlServerInstaller.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN.Abp.Quartz.SqlServerInstaller.csproj
new file mode 100644
index 000000000..e8ae8b21b
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN.Abp.Quartz.SqlServerInstaller.csproj
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+ netstandard2.0;netstandard2.1;net8.0;net9.0
+ LINGYUN.Abp.Quartz.SqlServerInstaller
+ LINGYUN.Abp.Quartz.SqlServerInstaller
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/AbpQuartzSqlServerInstallerModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/AbpQuartzSqlServerInstallerModule.cs
new file mode 100644
index 000000000..c3c69701e
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/AbpQuartzSqlServerInstallerModule.cs
@@ -0,0 +1,30 @@
+using Microsoft.Extensions.DependencyInjection;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Modularity;
+using Volo.Abp.Quartz;
+using Volo.Abp.VirtualFileSystem;
+
+namespace LINGYUN.Abp.Quartz.SqlServerInstaller;
+
+[DependsOn(
+ typeof(AbpQuartzModule),
+ typeof(AbpVirtualFileSystemModule))]
+public class AbpQuartzSqlServerInstallerModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.FileSets.AddEmbedded();
+ });
+ }
+
+ public async override Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context)
+ {
+ // 初始化 Quartz SqlServer 数据库
+ await context.ServiceProvider
+ .GetRequiredService()
+ .InstallAsync();
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/QuartzSqlServerInstaller.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/QuartzSqlServerInstaller.cs
new file mode 100644
index 000000000..5d4ac3166
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/QuartzSqlServerInstaller.cs
@@ -0,0 +1,136 @@
+using Microsoft.Data.SqlClient;
+using Microsoft.Extensions.FileProviders;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Options;
+using System;
+using System.Data;
+using System.Threading.Tasks;
+using Volo.Abp.Quartz;
+using Volo.Abp.VirtualFileSystem;
+using static Quartz.SchedulerBuilder;
+
+namespace LINGYUN.Abp.Quartz.SqlServerInstaller;
+
+public class QuartzSqlServerInstaller
+{
+ public ILogger Logger { protected get; set; }
+
+ private readonly IVirtualFileProvider _virtualFileProvider;
+ private readonly AbpQuartzOptions _quartzOptions;
+
+ public QuartzSqlServerInstaller(
+ IVirtualFileProvider virtualFileProvider,
+ IOptions quartzOptions)
+ {
+ _quartzOptions = quartzOptions.Value;
+ _virtualFileProvider = virtualFileProvider;
+
+ Logger = NullLogger.Instance;
+ }
+
+ public async virtual Task InstallAsync()
+ {
+ var dataSource = _quartzOptions.Properties["quartz.jobStore.dataSource"] ?? AdoProviderOptions.DefaultDataSourceName;
+ var connectionString = _quartzOptions.Properties[$"quartz.dataSource.{dataSource}.connectionString"];
+ var tablePrefix = _quartzOptions.Properties["quartz.jobStore.tablePrefix"] ?? "QRTZ_";
+
+ if (connectionString.IsNullOrWhiteSpace())
+ {
+ Logger.LogWarning($"Please configure the `{dataSource}` database connection string in `quartz.jobStore.dataSource`!");
+ throw new ArgumentNullException(nameof(connectionString));
+ }
+
+ Logger.LogInformation("Install Quartz SqlServer...");
+
+ var builder = new SqlConnectionStringBuilder(connectionString);
+
+ var dataBaseName = await CreateDataBaseIfNotExists(builder.InitialCatalog, builder);
+
+ builder.InitialCatalog = dataBaseName;
+
+ using var sqlConnection = new SqlConnection(builder.ConnectionString);
+
+ if (sqlConnection.State == ConnectionState.Closed)
+ {
+ await sqlConnection.OpenAsync();
+ }
+
+ using (var sqlCommand = new SqlCommand("SELECT COUNT(1) FROM [sys].[objects] WHERE type=N'U'", sqlConnection))
+ {
+ sqlCommand.Parameters.Add("@DataBaseName", SqlDbType.NVarChar).Value = dataBaseName;
+
+ var rowsAffects = await sqlCommand.ExecuteScalarAsync() as long?;
+ if (rowsAffects > 0)
+ {
+ Logger.LogInformation($"The `{dataBaseName}` tables has already exists.");
+ return;
+ }
+ }
+
+ var sqlScript = await GetInitSqlScript();
+
+ // USE `${DataBase}` -> USE `Workflow`;
+ sqlScript = sqlScript.ReplaceFirst("${DataBase}", dataBaseName);
+ // CREATE TABLE $(TablePrefix)JOB_DETAILS` -> CREATE TABLE QRTZ_JOB_DETAILS;
+ sqlScript = sqlScript.Replace("${TablePrefix}", tablePrefix);
+
+ using (var sqlCommand = new SqlCommand(sqlScript, sqlConnection))
+ {
+ Logger.LogInformation("The database initialization script `Initial.sql` starts...");
+
+ await sqlCommand.ExecuteNonQueryAsync();
+ }
+
+ Logger.LogInformation("Database initialization script `Initial.sql` complete!");
+ }
+
+ public async virtual Task CreateDataBaseIfNotExists(string dataBase, SqlConnectionStringBuilder connectionStringBuilder)
+ {
+ // 切换主数据库查询数据库是否存在
+ connectionStringBuilder.InitialCatalog = "master";
+ using var sqlConnection = new SqlConnection(connectionStringBuilder.ConnectionString);
+ if (sqlConnection.State == ConnectionState.Closed)
+ {
+ await sqlConnection.OpenAsync();
+ }
+
+ var checkDataBaseName = "";
+ using (var sqlCommand = new SqlCommand("SELECT [name] FROM [master].[dbo].[sysdatabases] WHERE [name] = @DataBaseName;", sqlConnection))
+ {
+ var dataBaseParamter = sqlCommand.Parameters.Add("DataBaseName", SqlDbType.NVarChar);
+ dataBaseParamter.Value = dataBase;
+
+ checkDataBaseName = await sqlCommand.ExecuteScalarAsync() as string;
+ }
+
+ if (checkDataBaseName.IsNullOrWhiteSpace())
+ {
+ using (var sqlCommand = new SqlCommand($"CREATE DATABASE {dataBase};", sqlConnection))
+ {
+ await sqlCommand.ExecuteNonQueryAsync();
+ }
+ }
+
+ return dataBase;
+ }
+
+ public async virtual Task GetInitSqlScript()
+ {
+ var sqlScriptFileInfo = _virtualFileProvider.GetFileInfo("/LINGYUN/Abp/Quartz/SqlServerInstaller/Scripts/Initial.sql");
+ if (!sqlScriptFileInfo.Exists || sqlScriptFileInfo.IsDirectory)
+ {
+ Logger.LogWarning("Please Check that the `Initial.sql` file exists!");
+ throw new InvalidOperationException("The `Initial.sql` database initialization script file does not exist or is not valid!");
+ }
+
+ var sqlScript = await sqlScriptFileInfo.ReadAsStringAsync();
+ if (sqlScript.IsNullOrWhiteSpace())
+ {
+ Logger.LogWarning("The contents of the `Initial.sql` file are empty or invalid!");
+ throw new InvalidOperationException("The contents of the `Initial.sql` file are empty or invalid!");
+ }
+
+ return sqlScript;
+ }
+}
diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/Scripts/Initial.sql b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/Scripts/Initial.sql
new file mode 100644
index 000000000..5c4478d7d
--- /dev/null
+++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/Scripts/Initial.sql
@@ -0,0 +1,370 @@
+-- this script is for SQL Server and Azure SQL
+
+-- This initializes the database to pristine for Quartz, by first removing any existing Quartz tables
+-- and then recreating them from scratch.
+-- Should you only require it to create the tables, set @DropDb to 0.
+
+USE [${DataBase}];
+GO
+
+DECLARE @DropDb BIT = 1; -- Set this to 0 to skip DROP statements, 1 to include them
+
+IF @DropDb = 1
+BEGIN
+ -- drop indexes if they exist and rebuild if current ones
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}T_J] ON [dbo].[${TablePrefix}TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}T_JG] ON [dbo].[${TablePrefix}TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}T_C] ON [dbo].[${TablePrefix}TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}T_G] ON [dbo].[${TablePrefix}TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}T_G_J] ON [dbo].[${TablePrefix}TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}T_STATE] ON [dbo].[${TablePrefix}TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}T_N_STATE] ON [dbo].[${TablePrefix}TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}T_N_G_STATE] ON [dbo].[${TablePrefix}TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}T_NEXT_FIRE_TIME] ON [dbo].[${TablePrefix}TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}T_NFT_ST] ON [dbo].[${TablePrefix}TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}T_NFT_MISFIRE] ON [dbo].[${TablePrefix}TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}T_NFT_ST_MISFIRE] ON [dbo].[${TablePrefix}TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}T_NFT_ST_MISFIRE_GRP] ON [dbo].[${TablePrefix}TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}FT_TRIG_INST_NAME] ON [dbo].[${TablePrefix}FIRED_TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}FT_INST_JOB_REQ_RCVRY] ON [dbo].[${TablePrefix}FIRED_TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}FT_J_G] ON [dbo].[${TablePrefix}FIRED_TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}FT_JG] ON [dbo].[${TablePrefix}FIRED_TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}FT_T_G] ON [dbo].[${TablePrefix}FIRED_TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}FT_TG] ON [dbo].[${TablePrefix}FIRED_TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}FT_G_J] ON [dbo].[${TablePrefix}FIRED_TRIGGERS];
+ DROP INDEX IF EXISTS [IDX_${TablePrefix}FT_G_T] ON [dbo].[${TablePrefix}FIRED_TRIGGERS];
+
+ IF OBJECT_ID(N'[dbo].[FK_${TablePrefix}TRIGGERS_${TablePrefix}JOB_DETAILS]', N'F') IS NOT NULL
+ ALTER TABLE [dbo].[${TablePrefix}TRIGGERS] DROP CONSTRAINT [FK_${TablePrefix}TRIGGERS_${TablePrefix}JOB_DETAILS];
+
+ IF OBJECT_ID(N'[dbo].[FK_${TablePrefix}CRON_TRIGGERS_${TablePrefix}TRIGGERS]', N'F') IS NOT NULL
+ ALTER TABLE [dbo].[${TablePrefix}CRON_TRIGGERS] DROP CONSTRAINT [FK_${TablePrefix}CRON_TRIGGERS_${TablePrefix}TRIGGERS];
+
+ IF OBJECT_ID(N'[dbo].[FK_${TablePrefix}SIMPLE_TRIGGERS_${TablePrefix}TRIGGERS]', N'F') IS NOT NULL
+ ALTER TABLE [dbo].[${TablePrefix}SIMPLE_TRIGGERS] DROP CONSTRAINT [FK_${TablePrefix}SIMPLE_TRIGGERS_${TablePrefix}TRIGGERS];
+
+ IF OBJECT_ID(N'[dbo].[FK_${TablePrefix}SIMPROP_TRIGGERS_${TablePrefix}TRIGGERS]', N'F') IS NOT NULL
+ ALTER TABLE [dbo].[${TablePrefix}SIMPROP_TRIGGERS] DROP CONSTRAINT [FK_${TablePrefix}SIMPROP_TRIGGERS_${TablePrefix}TRIGGERS];
+
+ IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_${TablePrefix}JOB_LISTENERS_${TablePrefix}JOB_DETAILS]') AND parent_object_id = OBJECT_ID(N'[dbo].[${TablePrefix}JOB_LISTENERS]'))
+ ALTER TABLE [dbo].[${TablePrefix}JOB_LISTENERS] DROP CONSTRAINT [FK_${TablePrefix}JOB_LISTENERS_${TablePrefix}JOB_DETAILS];
+
+ IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_${TablePrefix}TRIGGER_LISTENERS_${TablePrefix}TRIGGERS]') AND parent_object_id = OBJECT_ID(N'[dbo].[${TablePrefix}TRIGGER_LISTENERS]'))
+ ALTER TABLE [dbo].[${TablePrefix}TRIGGER_LISTENERS] DROP CONSTRAINT [FK_${TablePrefix}TRIGGER_LISTENERS_${TablePrefix}TRIGGERS];
+
+ IF OBJECT_ID(N'[dbo].[${TablePrefix}CALENDARS]', N'U') IS NOT NULL
+ DROP TABLE [dbo].[${TablePrefix}CALENDARS];
+
+ IF OBJECT_ID(N'[dbo].[${TablePrefix}CRON_TRIGGERS]', N'U') IS NOT NULL
+ DROP TABLE [dbo].[${TablePrefix}CRON_TRIGGERS];
+
+ IF OBJECT_ID(N'[dbo].[${TablePrefix}BLOB_TRIGGERS]', N'U') IS NOT NULL
+ DROP TABLE [dbo].[${TablePrefix}BLOB_TRIGGERS];
+
+ IF OBJECT_ID(N'[dbo].[${TablePrefix}FIRED_TRIGGERS]', N'U') IS NOT NULL
+ DROP TABLE [dbo].[${TablePrefix}FIRED_TRIGGERS];
+
+ IF OBJECT_ID(N'[dbo].[${TablePrefix}PAUSED_TRIGGER_GRPS]', N'U') IS NOT NULL
+ DROP TABLE [dbo].[${TablePrefix}PAUSED_TRIGGER_GRPS];
+
+ IF OBJECT_ID(N'[dbo].[${TablePrefix}JOB_LISTENERS]', N'U') IS NOT NULL
+ DROP TABLE [dbo].[${TablePrefix}JOB_LISTENERS];
+
+ IF OBJECT_ID(N'[dbo].[${TablePrefix}SCHEDULER_STATE]', N'U') IS NOT NULL
+ DROP TABLE [dbo].[${TablePrefix}SCHEDULER_STATE];
+
+ IF OBJECT_ID(N'[dbo].[${TablePrefix}LOCKS]', N'U') IS NOT NULL
+ DROP TABLE [dbo].[${TablePrefix}LOCKS];
+
+ IF OBJECT_ID(N'[dbo].[${TablePrefix}TRIGGER_LISTENERS]', N'U') IS NOT NULL
+ DROP TABLE [dbo].[${TablePrefix}TRIGGER_LISTENERS];
+
+ IF OBJECT_ID(N'[dbo].[${TablePrefix}JOB_DETAILS]', N'U') IS NOT NULL
+ DROP TABLE [dbo].[${TablePrefix}JOB_DETAILS];
+
+ IF OBJECT_ID(N'[dbo].[${TablePrefix}SIMPLE_TRIGGERS]', N'U') IS NOT NULL
+ DROP TABLE [dbo].[${TablePrefix}SIMPLE_TRIGGERS];
+
+ IF OBJECT_ID(N'[dbo].[${TablePrefix}SIMPROP_TRIGGERS]', N'U') IS NOT NULL
+ DROP TABLE [dbo].[${TablePrefix}SIMPROP_TRIGGERS];
+
+ IF OBJECT_ID(N'[dbo].[${TablePrefix}TRIGGERS]', N'U') IS NOT NULL
+ DROP TABLE [dbo].[${TablePrefix}TRIGGERS];
+END
+
+CREATE TABLE [dbo].[${TablePrefix}CALENDARS] (
+ [SCHED_NAME] nvarchar(120) NOT NULL,
+ [CALENDAR_NAME] nvarchar(200) NOT NULL,
+ [CALENDAR] varbinary(max) NOT NULL
+);
+
+CREATE TABLE [dbo].[${TablePrefix}CRON_TRIGGERS] (
+ [SCHED_NAME] nvarchar(120) NOT NULL,
+ [TRIGGER_NAME] nvarchar(150) NOT NULL,
+ [TRIGGER_GROUP] nvarchar(150) NOT NULL,
+ [CRON_EXPRESSION] nvarchar(120) NOT NULL,
+ [TIME_ZONE_ID] nvarchar(80)
+);
+
+CREATE TABLE [dbo].[${TablePrefix}FIRED_TRIGGERS] (
+ [SCHED_NAME] nvarchar(120) NOT NULL,
+ [ENTRY_ID] nvarchar(140) NOT NULL,
+ [TRIGGER_NAME] nvarchar(150) NOT NULL,
+ [TRIGGER_GROUP] nvarchar(150) NOT NULL,
+ [INSTANCE_NAME] nvarchar(200) NOT NULL,
+ [FIRED_TIME] bigint NOT NULL,
+ [SCHED_TIME] bigint NOT NULL,
+ [PRIORITY] int NOT NULL,
+ [STATE] nvarchar(16) NOT NULL,
+ [JOB_NAME] nvarchar(150) NULL,
+ [JOB_GROUP] nvarchar(150) NULL,
+ [IS_NONCONCURRENT] bit NULL,
+ [REQUESTS_RECOVERY] bit NULL
+);
+
+CREATE TABLE [dbo].[${TablePrefix}PAUSED_TRIGGER_GRPS] (
+ [SCHED_NAME] nvarchar(120) NOT NULL,
+ [TRIGGER_GROUP] nvarchar(150) NOT NULL
+);
+
+CREATE TABLE [dbo].[${TablePrefix}SCHEDULER_STATE] (
+ [SCHED_NAME] nvarchar(120) NOT NULL,
+ [INSTANCE_NAME] nvarchar(200) NOT NULL,
+ [LAST_CHECKIN_TIME] bigint NOT NULL,
+ [CHECKIN_INTERVAL] bigint NOT NULL
+);
+
+CREATE TABLE [dbo].[${TablePrefix}LOCKS] (
+ [SCHED_NAME] nvarchar(120) NOT NULL,
+ [LOCK_NAME] nvarchar(40) NOT NULL
+);
+
+CREATE TABLE [dbo].[${TablePrefix}JOB_DETAILS] (
+ [SCHED_NAME] nvarchar(120) NOT NULL,
+ [JOB_NAME] nvarchar(150) NOT NULL,
+ [JOB_GROUP] nvarchar(150) NOT NULL,
+ [DESCRIPTION] nvarchar(250) NULL,
+ [JOB_CLASS_NAME] nvarchar(250) NOT NULL,
+ [IS_DURABLE] bit NOT NULL,
+ [IS_NONCONCURRENT] bit NOT NULL,
+ [IS_UPDATE_DATA] bit NOT NULL,
+ [REQUESTS_RECOVERY] bit NOT NULL,
+ [JOB_DATA] varbinary(max) NULL
+);
+
+CREATE TABLE [dbo].[${TablePrefix}SIMPLE_TRIGGERS] (
+ [SCHED_NAME] nvarchar(120) NOT NULL,
+ [TRIGGER_NAME] nvarchar(150) NOT NULL,
+ [TRIGGER_GROUP] nvarchar(150) NOT NULL,
+ [REPEAT_COUNT] int NOT NULL,
+ [REPEAT_INTERVAL] bigint NOT NULL,
+ [TIMES_TRIGGERED] int NOT NULL
+);
+
+CREATE TABLE [dbo].[${TablePrefix}SIMPROP_TRIGGERS] (
+ [SCHED_NAME] nvarchar(120) NOT NULL,
+ [TRIGGER_NAME] nvarchar(150) NOT NULL,
+ [TRIGGER_GROUP] nvarchar(150) NOT NULL,
+ [STR_PROP_1] nvarchar(512) NULL,
+ [STR_PROP_2] nvarchar(512) NULL,
+ [STR_PROP_3] nvarchar(512) NULL,
+ [INT_PROP_1] int NULL,
+ [INT_PROP_2] int NULL,
+ [LONG_PROP_1] bigint NULL,
+ [LONG_PROP_2] bigint NULL,
+ [DEC_PROP_1] numeric(13,4) NULL,
+ [DEC_PROP_2] numeric(13,4) NULL,
+ [BOOL_PROP_1] bit NULL,
+ [BOOL_PROP_2] bit NULL,
+ [TIME_ZONE_ID] nvarchar(80) NULL
+);
+
+CREATE TABLE [dbo].[${TablePrefix}BLOB_TRIGGERS] (
+ [SCHED_NAME] nvarchar(120) NOT NULL,
+ [TRIGGER_NAME] nvarchar(150) NOT NULL,
+ [TRIGGER_GROUP] nvarchar(150) NOT NULL,
+ [BLOB_DATA] varbinary(max) NULL
+);
+
+CREATE TABLE [dbo].[${TablePrefix}TRIGGERS] (
+ [SCHED_NAME] nvarchar(120) NOT NULL,
+ [TRIGGER_NAME] nvarchar(150) NOT NULL,
+ [TRIGGER_GROUP] nvarchar(150) NOT NULL,
+ [JOB_NAME] nvarchar(150) NOT NULL,
+ [JOB_GROUP] nvarchar(150) NOT NULL,
+ [DESCRIPTION] nvarchar(250) NULL,
+ [NEXT_FIRE_TIME] bigint NULL,
+ [PREV_FIRE_TIME] bigint NULL,
+ [PRIORITY] int NULL,
+ [TRIGGER_STATE] nvarchar(16) NOT NULL,
+ [TRIGGER_TYPE] nvarchar(8) NOT NULL,
+ [START_TIME] bigint NOT NULL,
+ [END_TIME] bigint NULL,
+ [CALENDAR_NAME] nvarchar(200) NULL,
+ [MISFIRE_INSTR] int NULL,
+ [JOB_DATA] varbinary(max) NULL
+);
+GO
+
+ALTER TABLE [dbo].[${TablePrefix}CALENDARS] WITH NOCHECK ADD
+ CONSTRAINT [PK_${TablePrefix}CALENDARS] PRIMARY KEY CLUSTERED
+ (
+ [SCHED_NAME],
+ [CALENDAR_NAME]
+ );
+GO
+
+ALTER TABLE [dbo].[${TablePrefix}CRON_TRIGGERS] WITH NOCHECK ADD
+ CONSTRAINT [PK_${TablePrefix}CRON_TRIGGERS] PRIMARY KEY CLUSTERED
+ (
+ [SCHED_NAME],
+ [TRIGGER_NAME],
+ [TRIGGER_GROUP]
+ );
+GO
+
+ALTER TABLE [dbo].[${TablePrefix}FIRED_TRIGGERS] WITH NOCHECK ADD
+ CONSTRAINT [PK_${TablePrefix}FIRED_TRIGGERS] PRIMARY KEY CLUSTERED
+ (
+ [SCHED_NAME],
+ [ENTRY_ID]
+ );
+GO
+
+ALTER TABLE [dbo].[${TablePrefix}PAUSED_TRIGGER_GRPS] WITH NOCHECK ADD
+ CONSTRAINT [PK_${TablePrefix}PAUSED_TRIGGER_GRPS] PRIMARY KEY CLUSTERED
+ (
+ [SCHED_NAME],
+ [TRIGGER_GROUP]
+ );
+GO
+
+ALTER TABLE [dbo].[${TablePrefix}SCHEDULER_STATE] WITH NOCHECK ADD
+ CONSTRAINT [PK_${TablePrefix}SCHEDULER_STATE] PRIMARY KEY CLUSTERED
+ (
+ [SCHED_NAME],
+ [INSTANCE_NAME]
+ );
+GO
+
+ALTER TABLE [dbo].[${TablePrefix}LOCKS] WITH NOCHECK ADD
+ CONSTRAINT [PK_${TablePrefix}LOCKS] PRIMARY KEY CLUSTERED
+ (
+ [SCHED_NAME],
+ [LOCK_NAME]
+ );
+GO
+
+ALTER TABLE [dbo].[${TablePrefix}JOB_DETAILS] WITH NOCHECK ADD
+ CONSTRAINT [PK_${TablePrefix}JOB_DETAILS] PRIMARY KEY CLUSTERED
+ (
+ [SCHED_NAME],
+ [JOB_NAME],
+ [JOB_GROUP]
+ );
+GO
+
+ALTER TABLE [dbo].[${TablePrefix}SIMPLE_TRIGGERS] WITH NOCHECK ADD
+ CONSTRAINT [PK_${TablePrefix}SIMPLE_TRIGGERS] PRIMARY KEY CLUSTERED
+ (
+ [SCHED_NAME],
+ [TRIGGER_NAME],
+ [TRIGGER_GROUP]
+ );
+GO
+
+ALTER TABLE [dbo].[${TablePrefix}SIMPROP_TRIGGERS] WITH NOCHECK ADD
+ CONSTRAINT [PK_${TablePrefix}SIMPROP_TRIGGERS] PRIMARY KEY CLUSTERED
+ (
+ [SCHED_NAME],
+ [TRIGGER_NAME],
+ [TRIGGER_GROUP]
+ );
+GO
+
+ALTER TABLE [dbo].[${TablePrefix}TRIGGERS] WITH NOCHECK ADD
+ CONSTRAINT [PK_${TablePrefix}TRIGGERS] PRIMARY KEY CLUSTERED
+ (
+ [SCHED_NAME],
+ [TRIGGER_NAME],
+ [TRIGGER_GROUP]
+ );
+GO
+
+ALTER TABLE [dbo].[${TablePrefix}BLOB_TRIGGERS] WITH NOCHECK ADD
+ CONSTRAINT [PK_${TablePrefix}BLOB_TRIGGERS] PRIMARY KEY CLUSTERED
+ (
+ [SCHED_NAME],
+ [TRIGGER_NAME],
+ [TRIGGER_GROUP]
+ );
+GO
+
+ALTER TABLE [dbo].[${TablePrefix}CRON_TRIGGERS] ADD
+ CONSTRAINT [FK_${TablePrefix}CRON_TRIGGERS_${TablePrefix}TRIGGERS] FOREIGN KEY
+ (
+ [SCHED_NAME],
+ [TRIGGER_NAME],
+ [TRIGGER_GROUP]
+ ) REFERENCES [dbo].[${TablePrefix}TRIGGERS] (
+ [SCHED_NAME],
+ [TRIGGER_NAME],
+ [TRIGGER_GROUP]
+ ) ON DELETE CASCADE;
+GO
+
+ALTER TABLE [dbo].[${TablePrefix}SIMPLE_TRIGGERS] ADD
+ CONSTRAINT [FK_${TablePrefix}SIMPLE_TRIGGERS_${TablePrefix}TRIGGERS] FOREIGN KEY
+ (
+ [SCHED_NAME],
+ [TRIGGER_NAME],
+ [TRIGGER_GROUP]
+ ) REFERENCES [dbo].[${TablePrefix}TRIGGERS] (
+ [SCHED_NAME],
+ [TRIGGER_NAME],
+ [TRIGGER_GROUP]
+ ) ON DELETE CASCADE;
+GO
+
+ALTER TABLE [dbo].[${TablePrefix}SIMPROP_TRIGGERS] ADD
+ CONSTRAINT [FK_${TablePrefix}SIMPROP_TRIGGERS_${TablePrefix}TRIGGERS] FOREIGN KEY
+ (
+ [SCHED_NAME],
+ [TRIGGER_NAME],
+ [TRIGGER_GROUP]
+ ) REFERENCES [dbo].[${TablePrefix}TRIGGERS] (
+ [SCHED_NAME],
+ [TRIGGER_NAME],
+ [TRIGGER_GROUP]
+ ) ON DELETE CASCADE;
+GO
+
+ALTER TABLE [dbo].[${TablePrefix}TRIGGERS] ADD
+ CONSTRAINT [FK_${TablePrefix}TRIGGERS_${TablePrefix}JOB_DETAILS] FOREIGN KEY
+ (
+ [SCHED_NAME],
+ [JOB_NAME],
+ [JOB_GROUP]
+ ) REFERENCES [dbo].[${TablePrefix}JOB_DETAILS] (
+ [SCHED_NAME],
+ [JOB_NAME],
+ [JOB_GROUP]
+ );
+GO
+
+-- Create indexes
+CREATE INDEX [IDX_${TablePrefix}T_G_J] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, JOB_GROUP, JOB_NAME);
+CREATE INDEX [IDX_${TablePrefix}T_C] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, CALENDAR_NAME);
+
+CREATE INDEX [IDX_${TablePrefix}T_N_G_STATE] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, TRIGGER_GROUP, TRIGGER_STATE);
+CREATE INDEX [IDX_${TablePrefix}T_STATE] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, TRIGGER_STATE);
+CREATE INDEX [IDX_${TablePrefix}T_N_STATE] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP, TRIGGER_STATE);
+CREATE INDEX [IDX_${TablePrefix}T_NEXT_FIRE_TIME] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, NEXT_FIRE_TIME);
+CREATE INDEX [IDX_${TablePrefix}T_NFT_ST] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, TRIGGER_STATE, NEXT_FIRE_TIME);
+CREATE INDEX [IDX_${TablePrefix}T_NFT_ST_MISFIRE] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_STATE);
+CREATE INDEX [IDX_${TablePrefix}T_NFT_ST_MISFIRE_GRP] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_GROUP, TRIGGER_STATE);
+
+CREATE INDEX [IDX_${TablePrefix}FT_INST_JOB_REQ_RCVRY] ON [dbo].[${TablePrefix}FIRED_TRIGGERS](SCHED_NAME, INSTANCE_NAME, REQUESTS_RECOVERY);
+CREATE INDEX [IDX_${TablePrefix}FT_G_J] ON [dbo].[${TablePrefix}FIRED_TRIGGERS](SCHED_NAME, JOB_GROUP, JOB_NAME);
+CREATE INDEX [IDX_${TablePrefix}FT_G_T] ON [dbo].[${TablePrefix}FIRED_TRIGGERS](SCHED_NAME, TRIGGER_GROUP, TRIGGER_NAME);
+GO
\ No newline at end of file