我正在开发一个inno安装程序安装程序,我需要使用' GO'来执行多个SQL-Management Studio脚本。声明。我的方法是打开数据库连接,循环遍历文件,将它们分成GO块并执行每个块。第一个文件按预期运行。在第二个文件中,当涉及到执行时,我在方法" ExecSQLMulti"中得到访问冲突。在这一行:
ADOCommand.ActiveConnection := DBConnection;
我认为问题在于DBConnection对象仍然被前一个ADOCommand对象引用。但是当我尝试这个时:
ADOCommand.ActiveConnection := null();
我收到错误:参数类型错误,超出可接受的范围,或者彼此冲突......
"主"方法,遍历sql文件:
function NKInstall_CreateDatabase: boolean;
var
SQLScripts: TArrayOfString;
ScriptTransactions: TStringList;
i,ItemCount: integer;
myDBConnection: Variant;
begin
if not _PreconditionsOK_CreateDB() then begin
Result := True;
exit;
end;
if not ConnectToDatabase(SQLServerInstance.Text,myDBConnection) then exit;
SQLScripts := CollectSQLScripts();
ItemCount := GetArrayLength(SQLScripts)-1;
ScriptTransactions := TStringList.Create();
for I := 0 to ItemCount do begin
SetProgressText('Datenbank wird erstellt...','Script: '+SQLScripts[i]);
if LoadSQLScript(ExpandConstant('{app}\NKHLP\DB\'+SQLScripts[i]), ScriptTransactions) then begin
if not ExecSQLMulti(myDBConnection,ScriptTransactions) then begin
InstallSummary.Lines.Add('- DB Erstellung: Script '+SQLScripts[i]+' konnte nicht (komplett) ausgeführt werden.');
//Result := False; //*** Für Testphase des installers auskommentiert, damit Installation nicht abbricht.
Result := True;
gDBCreated := False;
exit;
end;
ScriptTransactions.Clear();
end
else begin
MsgBox('SQL Script '+ExpandConstant('{app}\NKHLP\DB\'+SQLScripts[i])+' konnte nicht eingelesen werden!',mbError,MB_OK);
InstallSummary.Lines.Add('- DB Erstellung: Script '+SQLScripts[i]+' konnte nicht eingelesen werden.');
//result := false; //*** Für Testphase auskommentiert, damit Installation nicht abbricht.
result := True;
gDBCreated := False;
exit;
end;
//Log('File done...'); //Debug
end;
gDBCreated := True;
Result := True;
end;
建立与DB的连接:
function ConnectToDatabase(DataSourceName: string; var Connection: Variant): boolean;
begin
log('Connecting...');
try
Connection := CreateOleObject('ADODB.Connection');
Connection.CursorLocation := 3;
Connection.ConnectionString := 'Provider=SQLOLEDB;' + // provider
'Data Source=' + DataSourceName +';' + // server name
'Initial Catalog=master;' + // default database
'Integrated Security=SSPI;'; // Use Windows Authentication
Connection.Open;
Result := True;
except
Connection := Null();
MsgBox('Die Verbindung zur Instanz "'+DataSourceName+'" konnte nicht hergestellt werden: '+#10#13+#10#13+GetExceptionMessage,mbError,MB_OK);
Result := False;
end
end;
执行所有GO块:
function ExecSQLMulti(var DBConnection: Variant; Transactions: TStringList): boolean;
var
ADOCommand: Variant;
i: integer;
CurrentQuery: string;
begin
if Transactions.Count = 0 then begin
Result := True;
exit;
end;
try
ADOCommand := CreateOleObject('ADODB.Command');
ADOCommand.CommandType := adCmdText;
ADOCommand.ActiveConnection := DBConnection;
for i := 0 to Transactions.Count-1 do begin
CurrentQuery := Transactions[i];
if Length(CurrentQuery) > 0 then begin
ADOCommand.CommandText := CurrentQuery;
ADOCommand.Execute(NULL,NULL,adExecuteNoRecords);
end;
end;
result := True;
except
MsgBox('Fehler beim ausführen eines SQL Befehls: '+GetExceptionMessage()+#10#13#10#13+
'Query: '+CurrentQuery,
mbError,
MB_OK);
end;
end;
答案 0 :(得分:1)
似乎我的创建和传递连接对象的方法是错误的或者只是不起作用。我已经对此进行了重构:
function RunSQLScript(ScriptPath: String; SQLInstance: String; DBName: string; CommandTimeout: integer): boolean;
var
ScriptTransactions: TStringList;
ADOCommand: Variant;
myDBConnection: Variant;
begin
ScriptTransactions := TStringList.Create();
if not ConnectToDatabase(SQLInstance, DBName, myDBConnection) then exit;
ADOCommand := CreateOleObject('ADODB.Command');
ADOCommand.ActiveConnection := myDBConnection;
ADOCommand.CommandTimeout := CommandTimeout;
ADOCommand.CommandType := adCmdText;
if LoadSQLScript(ScriptPath, ScriptTransactions) then begin
log('Executing Transactions...');
if not ExecMultiTransaction(ADOCommand, ScriptTransactions) then begin
MsgBox('SQL Script '+ScriptPath+' konnte nicht (komplett) ausgeführt werden!',mbError,MB_OK);
Result := False;
end
else begin
log('Sucessful');
Result := True;
end;
end
else begin
MsgBox('SQL Script '+ScriptPath+' konnte nicht eingelesen werden!',mbError,MB_OK);
result := False;
end;
end;
function ExecMultiTransaction(var ADOCommand: Variant; Transactions: TStringList): boolean;
var
i: integer;
CurrentQuery: string;
begin
if Transactions.Count = 0 then begin
Result := True;
exit;
end;
try
for i := 0 to Transactions.Count-1 do begin
CurrentQuery := Transactions[i];
if Length(CurrentQuery) > 0 then begin
ADOCommand.CommandText := CurrentQuery;
ADOCommand.Execute(NULL,NULL,adExecuteNoRecords);
end;
end;
result := True;
except
MsgBox('Fehler beim ausführen eines SQL Befehls: '+GetExceptionMessage()+#13#10#13#10+
'Query: '+CurrentQuery,
mbError,
MB_OK);
end;
end;
在RunSQLScript
函数中,我现在创建连接并仅将ADOCommand
对象传递给ExecMultiTransaction
函数,我在其中更改ADOCommand.CommandText
属性并执行命令。这样我每个脚本就有一个连接。
答案 1 :(得分:0)
也许会很有用。创建多个连接时,还会出现错误“访问冲突”。我在主脚本中编写了一些用于使用SQL数据库的函数(可能不是最佳函数,但它们满足了我的目标):
procedure LogPrint(TlogFile, TlogText: String);
begin
SaveStringToFile(TlogFile, GetDateTimeString('dd/mm/yyyy hh:nn:ss', '.', ':') + ' ' + TlogText + #13#10, True);
end;
//Function for write ADO errors to log
function ADOErrorPrintFunc(ADOConnection: Variant; FuncNameForLog, logFile: String): Boolean;
var
ADOError: Variant;
I : Integer;
begin
if VarIsEmpty(ADOConnection) or (ADOConnection.Errors.Count = 0) then begin
LogPrint(logFile, FuncNameForLog + ': ' + GetExceptionMessage);
Result := False;
end else begin
for I := 0 to ADOConnection.Errors.Count - 1 do
begin
ADOError := ADOConnection.Errors.Item(I);
LogPrint(logFile, FuncNameForLog + ' (error) err#: ' + IntToStr(ADOError.Number) + '; ' + 'Source: ' + ADOError.Source + '; ' + 'Description: ' + ADOError.Description);
end;
Result := True;
end;
end;
//Function for create ADODB.Connection once
//Example: SQLobj := _SQL_CreateADOConnection(logFile);
function _SQL_CreateADOConnection(logFile: String): Variant;
var
ADOConnection: Variant;
begin
try
ADOConnection := CreateOleObject('ADODB.Connection'); //create the ADO connection object
LogPrint(logFile, '_SQL_CreateADOConnection (success)');
except
ADOErrorPrintFunc(ADOConnection, '_SQL_CreateADOConnection', logFile);
end;
Result := ADOConnection;
end;
//Function for open connection. Must used after _SQL_CreateADOConnection
//For example, ConnectionString for connect to SQL database: 'DRIVER=SQL Server;SERVER=localhost\SQLEXPRESS;DATABASE=master;UID=login;PWD=password;'
//ConnectionString for connect to Interbase database: 'DRIVER={Easysoft IB6 ODBC};SERVER=localhost;DATABASE=localhost:c:\PathToDb\DBName.gdb;UID=login;PWD=password;'
//Example: SQLobj := _SQL_OpenConnection(ADOConnection, ConnectionString, logFile);
function _SQL_OpenConnection(ADOConnection: Variant; ConnectionString, logFile: String): Boolean;
begin
try
ADOConnection.ConnectionString := ConnectionString;
ADOConnection.Open;
LogPrint(logFile, '_SQL_OpenConnection (success)');
Result := True;
except
ADOErrorPrintFunc(ADOConnection, '_SQL_OpenConnection', logFile);
ADOConnection := Null();
Result := False;
end;
end;
//Function for create ADODB.Command object with activate previously opened connection. Use it after function _SQL_OpenConnection return True value.
//Example: SQLobjCmd := _SQL_CreateADOCommand(ADOConnection, logFile);
function _SQL_CreateADOCommand(ADOConnection: Variant; logFile: String): Variant;
var
ADOCommand: Variant;
begin
try
ADOCommand := CreateOleObject('ADODB.Command');
ADOCommand.ActiveConnection := ADOConnection;
LogPrint(logFile, '_SQL_CreateADOCommand (success)');
except
ADOErrorPrintFunc(ADOConnection, '_SQL_CreateADOCommand', logFile);
end;
Result := ADOCommand;
end;
//Function for use "select" query. Reads from the database values from the table and returns an array of column "ResultField".
//SQLresArr[0] from example - number of elements. If SQLresArr[0] = '' or SQLresArr[0] = '-1' this means error in your SQL query.
//Example: SQLresArr := _SQL_Select(ADOConnection, ADOCommand, 'select * from RDB$ROLES', 'RDB$ROLE_NAME', logFile);
function _SQL_Select(ADOConnection, ADOCommand: Variant; SQLQuery: AnsiString; ResultField, logFile: String): TArrayOfString;
var
ADORecordset: Variant;
tmpArray : TArrayOfString;
i : Integer;
begin
SetArrayLength(tmpArray, 1);
tmpArray[0] := '';
try
ADOCommand.CommandText := SQLQuery;
ADOCommand.Execute(NULL, NULL, adCmdText or adExecuteNoRecords);
ADOCommand.CommandType := adCmdText;
ADORecordset := ADOCommand.Execute;
if ADORecordset.EOF then begin
tmpArray[0] := '0';
end else begin
i := 0;
while not ADORecordset.eof do begin
i := i + 1;
tmpArray[0] := IntToStr(i);
SetArrayLength(tmpArray, i + 1);
tmpArray[i] := ADORecordset.Fields(ResultField).Value;
ADORecordset.MoveNext;
end;
end;
LogPrint(logFile, '_SQL_Select (success): ' + SQLQuery);
except
ADOErrorPrintFunc(ADOConnection, '_SQL_Select', logFile);
tmpArray[0] := '-1';
end;
Result := tmpArray;
end;
//Function for execute SQL query like "update", "alter", etc
//Example: _SQL_Query(ADOConnection, ADOCommand, 'update TABLE set FIELD1 = 1 where FIELD2 = 2', logFile)
function _SQL_Query(ADOConnection, ADOCommand: Variant; SQLQuery, logFile: String): Boolean;
var
ADORecordset: Variant;
begin
try
ADOCommand.CommandText := SQLQuery;
ADOCommand.Execute(NULL, NULL, adCmdText or adExecuteNoRecords);
ADOCommand.CommandType := adCmdText;
ADORecordset := ADOCommand.Execute;
LogPrint(logFile, '_SQL_Query (success): ' + SQLQuery);
Result := True;
except
LogPrint(logFile, '_SQL_Query(' + SQLQuery + '): ' + GetExceptionMessage);
Result := False;
end;
end;
//Function for close connection.
//Example: _SQL_Disconnect(ADOConnection, logFile);
function _SQL_Disconnect(ADOConnection: Variant; logFile: String): Boolean;
begin
Result := True;
try
ADOConnection.Close;
LogPrint(logFile, '_SQL_Disconnect (success)');
except
ADOErrorPrintFunc(ADOConnection, '_SQL_Disconnect', logFile);
Result := False;
end;
end;
Interbase数据库示例:
[CODE]
var
I : Integer;
logFile: string;
IBDriver, IBServer, IBDatabase, IBLogin, IBPassword, IBPasswordReserved,
ADO_IB_Obj_ConnectionString: string;
ADO_IB_Obj_Connected: Boolean;
SQLresArr: TArrayOfString;
ADO_IB_Obj, ADO_IB_ObjCmd: Variant;
begin
IBDriver := '{Easysoft IB6 ODBC}'
IBServer := 'localhost'
IBDatabase := 'C:\Path\DbName.gdb'
IBLogin := 'SYSDBA';
IBPassword := 'masterkey';
IBPasswordReserved := 'tttttttt';
logFile := 'C:\SQLlog.txt';
ADO_IB_Obj_Connected := False;
ADO_IB_Obj := _SQL_CreateADOConnection(logFile);
// try connect to database with standard password
ADO_IB_Obj_ConnectionString := 'DRIVER=' + IBDriver + ';SERVER=' + IBServer + ';DATABASE=' + IBServer + ':' + IBDatabase + ';UID=' + IBLogin + ';PWD=' + IBPassword + ';'
if _SQL_OpenConnection(ADO_IB_Obj, ADO_IB_Obj_ConnectionString, logFile) then begin
ADO_IB_Obj_Connected := True;
end else begin
//try connect to database with other password
ADO_IB_Obj_ConnectionString := 'DRIVER=' + IBDriver + ';SERVER=' + IBServer + ';DATABASE=' + IBServer + ':' + IBDatabase + ';UID=' + IBLogin + ';PWD=' + IBPasswordReserved + ';'
if _SQL_OpenConnection(ADO_IB_Obj, ADO_IB_Obj_ConnectionString, logFile) then begin
ADO_IB_Obj_Connected := True;
end;
end;
//working with database only if connection is opened successfully
if ADO_IB_Obj_Connected then begin
ADO_IB_ObjCmd :=_SQL_CreateADOCommand(ADO_IB_Obj, logFile); //create once
_SQL_Query(ADO_IB_Obj, ADO_IB_ObjCmd, 'update TABLE1 set FIELD1 = 1 where FIELD2 = 2', logFile);
SQLresArr := _SQL_Select(ADO_IB_Obj, ADO_IB_ObjCmd, 'select RDB$RELATION_NAME from RDB$RELATIONS', 'RDB$RELATION_NAME', logFile);
For i := 1 to GetArrayLength(SQLresArr) - 1 do begin
LogPrint(logFile, 'Table ' + IntToStr(i) + ' = "' + Trim(SQLresArr[i]) + '"; Tables count = ' + SQLresArr[0]);
end;
_SQL_Disconnect(ADO_IB_Obj, logFile);
end;
end;