Inno Setup执行SQL脚本的方法

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 原文: Inno Setup执行SQL脚本的方法 作为和NSIS并立的、两个最流行的免费Windows应用程序安装包制作工具之一,Inno在学习难度上相对要低一些,非常适合对一些简单的桌面程序打包。
原文: Inno Setup执行SQL脚本的方法

作为和NSIS并立的、两个最流行的免费Windows应用程序安装包制作工具之一,Inno在学习难度上相对要低一些,非常适合对一些简单的桌面程序打包。但对于较复杂的安装过程,或者Web应用程序来说,我个人觉得不是Inno的强项。当然,既然Inno内嵌了Pascal语言用以扩展功能,理论上不是不可以应付复杂的安装过程,但实现起来要复杂一些。

比如对于在安装过程中连接数据库并执行SQL脚本这样的需求,使用InstallShield应该会简单地多,而Inno却不支持直接操作数据库,并且相关的资料说明少之又少,还不如NSIS丰富,以至于我踏破铁鞋无觅处,最终却在NSIS的资料中找到了思路。

主要的思路是,在安装过程中,调用数据库客户端连接数据库并执行SQL脚本,然后将执行结果或错误信息输出到文件中,最后通过分析这个文件来判断命令执行的结果。但是,既然是调用特定的客户端,那么对不同数据库的操作自然就有所区别,具体情况如下所述。

首先在打包脚本的[Files]段将必需的文件包含进来:

[Files]
Source: "D:/Development/MyDemoApp/code/*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs

;osql.exe在SQL Server2000安装目录中
Source: "D:/Development/MyDemoApp/osql.exe"; Flags: dontcopy
Source: "D:/Development/MyDemoApp/mysql.exe"; Flags: dontcopy
Source: "D:/Development/MyDemoApp/script_mssql.sql"; Flags: dontcopy
Source: "D:/Development/MyDemoApp/script_mysql.sql"; Flags: dontcopy
Source: "D:/Development/MyDemoApp/script_oracle.sql"; Flags: dontcopy

在SQL Server中执行脚本的代码片断:

function ExecScriptInMSSQL(DBHost, DBLogin, DBPass, DBName: String): Boolean;
var
 ConnectExe: String;
 ConnectParam: String;
begin
 {解压临时文件}
 ExtractTemporaryFile('osql.exe');
 ExtractTemporaryFile('script_mssql.sql');
 {构造数据库连接字符串}
 ConnectExe := ExpandConstant('{tmp}') + '/osql.exe';
 ConnectParam := ' -S ' + DBHost
  + ' -U ' + DBLogin
  + ' -P ' + DBPass
  + ' -d ' + DBName
  + ' -i script_mssql.sql -o '
  + ExpandConstant('{tmp}') + '/dbstatus.txt';
 {建立数据库连接并执行脚本}
 if Exec(ConnectExe, ConnectParam, '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then begin
  Result := ResultCode = 0;
  LoadStringFromFile(ExpandConstant('{tmp}') + '/dbstatus.txt', StatusString);
  if StatusString <> '' then begin
   MsgBox(StatusString, mbError, MB_OK);
   Result := False;
  end else begin
   Result := True;
  end;
 end else begin
  MsgBox('Database update failed:'#10#10 + SysErrorMessage(ResultCode), mbError, MB_OK);
  Result := False;
 end;
end;

在MySQL中执行脚本的代码片断:

function ExecScriptInMYSQL(DBHost, DBLogin, DBPass, DBName: String): Boolean;
var
 ConnectExe: String;
 ConnectParam: String;
begin
 {解压临时文件}
 ExtractTemporaryFile('mysql.exe');
 ExtractTemporaryFile('script_mysql.sql');
 {构造数据库连接字符串}
 ConnectExe := ExpandConstant('cmd');
 ConnectParam := ' /c "' + ExpandConstant('{tmp}') + '/mysql.exe'
  + ' -h' + DBHost
  + ' -u' + DBLogin
  + ' -p' + DBPass
  + ' -D' + DBName
  + ' -e "source ' + ExpandConstant('{tmp}') + '/script_mysql.sql""> ' + ExpandConstant('{tmp}') + '/dbstatus.txt 2>&1';
 {建立数据库连接并执行脚本}
 if Exec(ConnectExe, ConnectParam, '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then begin
  Result := ResultCode = 0;
  LoadStringFromFile(ExpandConstant('{tmp}') + '/dbstatus.txt', StatusString);
  if StatusString <> '' then begin
   MsgBox(StatusString, mbError, MB_OK);
   Result := False;
  end else begin
   Result := True;
  end;
 end else begin
  MsgBox('Database update failed:'#10#10 + SysErrorMessage(ResultCode), mbError, MB_OK);
  Result := False;
 end;
end;

由于mysql.exe没有输出结果到文件的参数,故需要使用cmd.exe来运行mysql.exe以便将其输出重定向到文件dbstatus.txt中。此外,在命令的最后加上参数2>&1,将标准错误输出设备也重定向到文件上,否则命令执行的错误信息不会输出到文件中。

在Oracle中执行脚本的代码片断:
function ExecScriptInORACLE(ClientPath, DBInstance, DBLogin, DBPass: String): Boolean;
begin
 {解压临时文件}
 ExtractTemporaryFile('script_oracle.sql');
 {连接数据库并执行脚本}
 if Exec(ExpandConstant('cmd'), ' /c "' + ClientPath + ' -L -S ' + DBLogin
  + '/' + DBPass
  + '@' + DBInstance
  + ' @' + ExpandConstant('{tmp}') + '/script_oracle.sql> ' + ExpandConstant('{tmp}') + '/dbstatus.txt 2>&1',
  '',
  SW_HIDE, ewWaitUntilTerminated, ResultCode)
 then begin
  Result := ResultCode = 0;
  LoadStringFromFile(ExpandConstant('{tmp}') + '/dbstatus.txt', StatusString);
  if Pos('holytail', StatusString) <> 0 then begin
   {若输出信息中有“holytail”的子串,则表示脚本成功执行}
   {若执行有误,提示用户打开日志文件}
   if Pos('ORA-', StatusString) <> 0 then begin
    {提示用户脚本执行出错}
    if MsgBox('数据库更新出错,是否打开日志文件?', mbConfirmation, MB_YESNO) = IDYES then begin
     {打开日志}
     if not ShellExec('', ExpandConstant('{tmp}') + '/dbstatus.txt', '', '', SW_SHOW, ewNoWait, ErrorCode) then begin
      MsgBox('日志文件打开错误!', mbError, MB_OK);
     end;
    end;
    Result := False;
   {若执行无误,返回True}
   end else begin
    Result := True;
   end;
  end else if StatusString <> '' then begin
   MsgBox(StatusString, mbError, MB_OK);
   Result := False;
  end else begin
   Result := True;
  end;
 end else begin
  MsgBox('Database update failed:'#10#10 + SysErrorMessage(ResultCode), mbError, MB_OK);
  Result := False;
 end;
end;
Oracle的客户端太大,不能集成到安装包中,应使用一个TInputFileWizardPage由用户选择sqlplus.exe的安装位置。同时,由于sqlplus.exe也没有输出结果到文件的参数,也须使用cmd.exe来运行它并重定向输出到文件。此外,由于sqlplus.exe执行脚本时无论成功还是失败,都会输出信息,故无法像使用sqlcmd.exe和mysql.exe那样简单地判断脚本是否执行成功,需要在脚本的最后通过select语句输出一个特殊的字符串到文件中,然后通过判断dbstatus.txt中是否存在该字符串来判断脚本的执行情况;且由于sqlplus.exe执行完脚本后不会自动退出,还要在脚本最后加上exit语句;故script_oracle.sql的最后必须是如下内容:

SELECT 'holytail' FROM dual;
exit;

 

 

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
2月前
|
SQL 测试技术 数据库
SQL注入,跨站脚本,跨站请求伪造,傻傻分不清楚
SQL注入,跨站脚本,跨站请求伪造,傻傻分不清楚
|
1月前
|
SQL 关系型数据库 MySQL
【MySQL】— —熟练掌握用SQL语句实现数据库和基本表的创建。熟练掌握MySQL的安装、客户端登录方法;熟练掌握MySQL的编码、数据类型等基础知识;掌握实体完整性的定义和维护方法、掌握参照完整性
【MySQL】— —熟练掌握用SQL语句实现数据库和基本表的创建。熟练掌握MySQL的安装、客户端登录方法;熟练掌握MySQL的编码、数据类型等基础知识;掌握实体完整性的定义和维护方法、掌握参照完整性
99 1
|
5月前
|
SQL 数据库
PowerDesigner导出SQL脚本运行注释出现乱码问题
PowerDesigner导出SQL脚本运行注释出现乱码问题
113 0
|
6月前
|
SQL 数据库 Python
某站点存在SQL注入,直接可进行脱库(实战可参考此方法)
某站点存在SQL注入,直接可进行脱库(实战可参考此方法)
|
5月前
|
SQL 关系型数据库 MySQL
MySql数据库中的视图,索引与数据库sql脚本如何导入与导出---(详细介绍)
MySql数据库中的视图,索引与数据库sql脚本如何导入与导出---(详细介绍)
243 0
|
30天前
|
SQL 存储 BI
sql server 2012远程链接的方法及步骤
sql server 2012远程链接的方法及步骤
17 1
|
17小时前
|
SQL Java 关系型数据库
mybatis-plus启动时自动执行sql脚本
mybatis-plus启动时自动执行sql脚本
5 1
|
1天前
|
SQL 分布式计算 资源调度
一文解析 ODPS SQL 任务优化方法原理
本文重点尝试从ODPS SQL的逻辑执行计划和Logview中的执行计划出发,分析日常数据研发过程中各种优化方法背后的原理,覆盖了部分调优方法的分析,从知道怎么优化,到为什么这样优化,以及还能怎样优化。
|
30天前
|
SQL 存储 Kubernetes
Seata常见问题之mybatisplus的批量插入方法报SQL错误如何解决
Seata 是一个开源的分布式事务解决方案,旨在提供高效且简单的事务协调机制,以解决微服务架构下跨服务调用(分布式场景)的一致性问题。以下是Seata常见问题的一个合集
26 0
|
1月前
|
SQL 存储 关系型数据库
MySQL 常用30种SQL查询语句优化方法
MySQL 常用30种SQL查询语句优化方法
73 0