Inno Setup执行SQL脚本的方法

原文: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;

 

 

时间: 2024-10-03 12:30:35

Inno Setup执行SQL脚本的方法的相关文章

java用ant.jar工具类执行sql脚本遇到问题

问题描述 java用ant.jar工具类执行sql脚本遇到问题 最近在研究用工具类ant.jar执行sql脚本文件,一般对数据和字段的操作都无问题,但当要执行生成触发器或者存储过程时却出错,有大神做过这方面的吗?或者用其他方法可以执行能生成存储过程和触发器的sql脚本?求解!新人无币,望见谅~ Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an

mysql批量执行sql文件的方法_Mysql

1.待执行的sql文件为1.sql.2.sql.3.sql.4.sql等 2.写一个batch.sql文件: source 1.sql; source 2.sql; source 3.sql; source 4.sql; 3.在mysql下执行source /batch文件所在目录/batch.sql; 以上就是小编为大家带来的mysql批量执行sql文件的方法全部内容了,希望大家多多支持~ 以上是小编为您精心准备的的内容,在的博客.问答.公众号.人物.课程等栏目也有的相关内容,欢迎继续使用右上

SQL Server中使用外部命令执行sql脚本

server|脚本|执行 Author:David EulerDate: 2004/09/28Email:de_euler-david@yahoo.com.cn 有任何问题,请与我联系:)    有时候我们需要多次运行一个文件夹下所有的sql脚本(可能时txt或者sql等文本文件)来更新Schema,文件多的时候需要多次执行,那么可以使用多条语句来执行sql脚本.--下面的查询语句在SQL Query中运行,将执行d:\vss下面的指定sql脚本,这些脚本的后缀都是txtexec master.

在.net执行sql脚本的简单实现

脚本|执行 在.net执行sql脚本的简单实现 郑佐2004-12-25 看到csdn社区经常有人问在.net中如果执行sql脚本,下面是使用C#调用cmd来执行osql实现脚本的执行. using System; using System.Data; using System.Collections; using System.Xml; using System.IO; using System.Text; using System.Diagnostics; namespace ZZ { pu

java执行SQL脚本的一个问题

问题描述 今天准备在java中,利用ant来执行sql脚本,进行数据相关脚本部署,如存储过程,建表等.运行过程中,出现了特别常见的sql语法错误.可以经过检查没有错误,为了保证没有错误,还特地在sqlserver的控制台直接用source来执行了一次,同样没有错误.sqlExec.setDriver(driver);sqlExec.setUrl(db);sqlExec.setUserid(user);sqlExec.setPassword(password);//有出错的语句该如何处理sqlEx

java-操作数据库的.exe程序,可以批量执行sql脚本文件

问题描述 操作数据库的.exe程序,可以批量执行sql脚本文件 求大神帮忙啊~用java可以做这个东西吗?完全没有思路啊,要求是可以操作局域网内的另一台电脑上的mysql数据库 解决方案 如果有访问权限的话,直接运行Runtime.getRuntime().exec("远程IP文件路径exe文件");如果没有,那可以先用java进行telnet连接到那台机器,然后调用exe程序,再不行就只能在远程机器上写webservice服务然后调用了. 解决方案二: 批量执行SQL脚本 解决方案三

java sql 脚本-java执行SQL脚本!!!!!

问题描述 java执行SQL脚本!!!!! 今天第一次用 java 执行sql脚本,是不是sql.out里边如果没东西就意味着成功?可我执行完成后表数据全都建好了 但是 sql.out里边显示的内容是这些 我需要做个判断 显示 是否成功 ,这个判断要怎么做?(重点是怎么才能根据sql.out里边的信息 来判断是否执行成功 ) 解决方案 sql.out 的显示信息 解决方案二: 看一下下面的代码处理方式http://mxm910821.iteye.com/blog/1701822

Ant 执行sql脚本 出现语法错误

问题描述 今天准备在java中,利用ant来执行sql脚本,进行数据相关脚本部署,如存储过程,建表等.运行过程中,出现了特别常见的sql语法错误.可以经过检查没有错误,为了保证没有错误,还特地在sqlserver的控制台直接用source来执行了一次,同样没有错误.sqlExec.setDriver(driver);sqlExec.setUrl(db);sqlExec.setUserid(user);sqlExec.setPassword(password);//有出错的语句该如何处理sqlEx

Yii使用migrate命令执行sql语句的方法_php实例

本文实例讲述了Yii使用migrate命令执行sql语句的方法.分享给大家供大家参考,具体如下: Yii2自带一个强大的命令行管理工具,在windows下打卡cmd命令窗口,切换到Yii项目所在目录(包含Yii.bat),就可以在cmd中运行Yii命令了. 使用Yii migrate命令执行sql语句: 如在路径为/console/migrations/m130524_201442_init.php这个文件定义了一张User表的sql,我们要执行这个sql来生成数据表,就运行: yii migr