/source/utils/ado/ADOUtilities.pas

http://sales-purchases.googlecode.com/ · Pascal · 829 lines · 628 code · 75 blank · 126 comment · 30 complexity · 348df8eb3dc443bd4ee91727971b751d MD5 · raw file

  1. unit ADOUtilities;
  2. interface
  3. uses SysUtils, Windows, Forms, Controls, Classes, IniFiles, StdCtrls, Variants,
  4. ADODB, ADODB_TLB, ADOX_TLB, JRO_TLB, Registry, FileCtrl, ComObj, Dialogs, DB;
  5. var
  6. sPath : TFileName;
  7. function SQLFormatDateTime(const AValue: TDateTime): String;
  8. function GetADOVersion : String;
  9. function ConnectionStringForMDBFile(aMDBFile : TFileName) : String; overload;
  10. function ConnectionStringForMDBFile(aMDBFile : TFileName; aPassWord : String) : String; overload;
  11. function ConnectionSetStringMDB(DBFile : TFileName; DBConn : TADOConnection) : Boolean;
  12. procedure CompressRepairMDB(DBFile : TFileName); overload;
  13. procedure CompressRepairMDB(DBFile : TFileName; APassword : String); overload;
  14. procedure CreateAccess97MDB(AFileName : TFileName);
  15. procedure CreateAccess2KMDB(AFileName : TFileName);
  16. procedure CreateExcel8XLS(AFileName : TFileName);
  17. procedure CreateCatalog(AFileName : TFileName; AJetEngineType : Word);
  18. function ContainsTableMDB(DBFile : TFileName; DBTable : String) : Boolean; overload;
  19. function ContainsTableMDB(DBConn : TADOConnection; DBTable : String) : Boolean; overload;
  20. function CreateTableMDB(DBConn : TADOConnection; DBTable : String) : Boolean;
  21. function CountConnectedWorkStations_SQLServer(AnADOConnection : TADOConnection) : Integer;
  22. function CountConnectedWorkStations_Access(AnADOConnection : TADOConnection) : Integer;
  23. function SimpleLookup(AKeyField : String; AKeyValue : Variant; AResultField, ATable : String; DBConn : TADOConnection) : Variant;
  24. function DateToSQLStr(dtDate : TDate) : String;
  25. procedure ShowSQL(DataSet : TDataSet);
  26. procedure ShowSQLText(AString, ACaption : String);
  27. procedure ADOExecuteSQLList(AConnectionString : WideString; ASQLCommandList : TStrings; AVerTable, AVerField, AVerValue : String);
  28. procedure ADOExecuteSQLBatchFile(AControlIniFile : TFileName; ADBPath : String); overload;
  29. procedure ADOExecuteSQLBatchFile(AControlIniFile : TFileName; ASQLServer, AUser, APWD : String); overload;
  30. procedure ADOCopyXMLToStringList(ADataSet : TCustomADODataSet; AStrings : TStrings);
  31. Procedure ADOSaveRequery(ADataSet : TCustomADODataSet);
  32. implementation
  33. function SQLFormatDateTime(const AValue: TDateTime): String;
  34. begin
  35. Result := '{ts ' + QuotedStr(FormatDateTime('yyyy-mm-dd hh:nn:ss', AValue)) + '}'; // SQL Server sicheres DATETIME, z.B. {ts '2009-04-06 12:00:00'}
  36. end;
  37. Procedure ADOSaveRequery(ADataSet : TCustomADODataSet);
  38. begin
  39. if Assigned(ADataSet) and ADataSet.Active then ADataSet.Requery();
  40. end;
  41. function GetADOVersion: string;
  42. var
  43. ADO: OLEVariant;
  44. begin
  45. try
  46. ADO := CreateOLEObject('ADODB.Connection');
  47. Result := ADO.Version;
  48. ADO:= null;
  49. except
  50. Result := ' No version';
  51. end;
  52. end;
  53. procedure ShowSQL(DataSet : TDataSet);
  54. begin
  55. if DataSet is TADOQuery then
  56. ShowSQLText(TADOQuery(DataSet).SQL.Text, DataSet.Name);
  57. if DataSet is TADODataSet then
  58. ShowSQLText(TADODataSet(DataSet).CommandText, DataSet.Name);
  59. end;
  60. procedure ShowSQLText(AString, ACaption : String);
  61. var
  62. frm : TForm;
  63. tmem : TMemo;
  64. begin
  65. frm := TForm.Create(nil);
  66. frm.Caption := ACaption;
  67. tmem := TMemo.Create(frm);
  68. tmem.Parent := frm;
  69. tmem.Align := alClient;
  70. tmem.Lines.Text := AString;
  71. frm.ShowModal;
  72. tmem.Free;
  73. frm.Free;
  74. end;
  75. function SimpleLookup(AKeyField : String; AKeyValue : Variant; AResultField, ATable : String; DBConn : TADOConnection) : Variant;
  76. var
  77. tmpSQL : String;
  78. rs : ADODB._RecordSet;
  79. begin
  80. Result := varNull;
  81. tmpSQL := 'SELECT DISTINCT %s FROM %s WHERE %s = %s';
  82. tmpSQL := Format(tmpSQL, [AResultField, ATable, AKeyField, VarToStr(AKeyValue)]);
  83. rs := DBConn.Execute(tmpSQL);
  84. if (rs.RecordCount > 0) then
  85. Result := rs.Fields[0].Value;
  86. rs.Close;
  87. end;
  88. function ConnectionSetStringMDB(DBFile : TFileName; DBConn : TADOConnection) : Boolean;
  89. begin
  90. Result := false;
  91. if ((not FileExists(DBFile)) or (not Assigned(DBConn))) then
  92. Exit;
  93. // Connection-String setzen und Verbindung öffnen
  94. with DBConn do begin
  95. // Connection schließen
  96. Connected := false;
  97. LoginPrompt := false;
  98. // Connection-String aufbauen
  99. ConnectionString := 'Provider=Microsoft.Jet.OLEDB.4.0;';
  100. ConnectionString := ConnectionString + 'Password="";';
  101. ConnectionString := ConnectionString + 'User ID=Admin;';
  102. ConnectionString := ConnectionString + 'Data Source=' + DBFile + ';';
  103. ConnectionString := ConnectionString + 'Mode=ReadWrite;';
  104. ConnectionString := ConnectionString + 'Extended Properties="";';
  105. ConnectionString := ConnectionString + 'Locale Identifier=1033;';
  106. ConnectionString := ConnectionString + 'Jet OLEDB:System database="";';
  107. ConnectionString := ConnectionString + 'Jet OLEDB:Registry Path="";';
  108. ConnectionString := ConnectionString + 'Jet OLEDB:Database Password="";';
  109. ConnectionString := ConnectionString + 'Jet OLEDB:Engine Type=5;';
  110. ConnectionString := ConnectionString + 'Jet OLEDB:Database Locking Mode=1;';
  111. ConnectionString := ConnectionString + 'Jet OLEDB:Global Partial Bulk Ops=2;';
  112. ConnectionString := ConnectionString + 'Jet OLEDB:Global Bulk Transactions=1;';
  113. ConnectionString := ConnectionString + 'Jet OLEDB:New Database Password="";';
  114. ConnectionString := ConnectionString + 'Jet OLEDB:Create System Database=False;';
  115. ConnectionString := ConnectionString + 'Jet OLEDB:Encrypt Database=False;';
  116. ConnectionString := ConnectionString + 'Jet OLEDB:Don''t Copy Locale on Compact=False;';
  117. ConnectionString := ConnectionString + 'Jet OLEDB:Compact Without Replica Repair=False;';
  118. // ConnectionString := ConnectionString + 'Jet OLEDB:Page Timeout=0;';
  119. ConnectionString := ConnectionString + 'Jet OLEDB:SFP=False';
  120. Result := true;
  121. end;
  122. end;
  123. function ConnectionStringForMDBFile(aMDBFile : TFileName) : String;
  124. begin
  125. result := ConnectionStringForMDBFile(aMDBFile, '');
  126. end;
  127. function ConnectionStringForMDBFile(aMDBFile : TFileName; aPassWord : String) : String;
  128. var
  129. cs : String;
  130. begin
  131. cs := '';
  132. if FileExists(aMDBFile) then begin
  133. // Connection-String aufbauen
  134. cs := 'Provider=Microsoft.Jet.OLEDB.4.0;';
  135. cs := cs + 'Password="";';
  136. cs := cs + 'User ID=Admin;';
  137. cs := cs + 'Data Source=' + aMDBFile + ';';
  138. cs := cs + 'Mode=Share Deny None;';
  139. cs := cs + 'Extended Properties="";';
  140. cs := cs + 'Locale Identifier=1033;';
  141. cs := cs + 'Jet OLEDB:System database="";';
  142. cs := cs + 'Jet OLEDB:Registry Path="";';
  143. cs := cs + 'Jet OLEDB:Database Password="' + aPassWord+ '";';
  144. cs := cs + 'Jet OLEDB:Engine Type=5;';
  145. cs := cs + 'Jet OLEDB:Database Locking Mode=1;';
  146. cs := cs + 'Jet OLEDB:Global Partial Bulk Ops=2;';
  147. cs := cs + 'Jet OLEDB:Global Bulk Transactions=1;';
  148. cs := cs + 'Jet OLEDB:New Database Password="";';
  149. cs := cs + 'Jet OLEDB:Create System Database=False;';
  150. cs := cs + 'Jet OLEDB:Encrypt Database=False;';
  151. cs := cs + 'Jet OLEDB:Don''t Copy Locale on Compact=False;';
  152. cs := cs + 'Jet OLEDB:Compact Without Replica Repair=False;';
  153. cs := cs + 'Jet OLEDB:SFP=False';
  154. end;
  155. Result := cs;
  156. end;
  157. function CountConnectedWorkStations_SQLServer(AnADOConnection : TADOConnection) : Integer;
  158. const
  159. SQL = 'SET NOCOUNT ON ' + #13#10 +
  160. 'CREATE TABLE #who (spid int, ecid int, status nvarchar(50), loginname nvarchar(50), hostname nvarchar(50), blk int, dbname nvarchar(50), cmd nvarchar(50), request_id int) ' + #13#10 +
  161. 'INSERT #who EXEC sp_who ' + #13#10 +
  162. 'SELECT Count(*) AS connections FROM #who where dbname = ''%s'' ' + #13#10 +
  163. 'DROP TABLE #who ' + #13#10 +
  164. 'SET NOCOUNT OFF';
  165. var
  166. rs : ADODB._RecordSet;
  167. begin
  168. Result := 0;
  169. rs := AnADOConnection.Execute(Format(SQL, [AnADOConnection.Properties['Initial Catalog'].Value]));
  170. if (rs.RecordCount > 0) then
  171. Result := StrToInt(VarToStr(rs.Fields['connections'].Value));
  172. end;
  173. function CountConnectedWorkStations_Access(AnADOConnection : TADOConnection) : Integer;
  174. const JET_SCHEMA_USERROSTER = '{947bb102-5d43-11d1-bdbf-00c04fb92675}';
  175. var
  176. tmpADODataSet : TADODataSet;
  177. tmpStrLst : TStringList;
  178. begin
  179. Result := 0;
  180. try
  181. tmpADODataSet := TADODataSet.Create(nil);
  182. tmpStrLst := TStringList.Create;
  183. AnADOConnection.OpenSchema(siProviderSpecific, EmptyParam, JET_SCHEMA_USERROSTER, tmpADODataSet);
  184. tmpADODataSet.First;
  185. while not tmpADODataSet.EOF do begin
  186. if (tmpStrLst.IndexOf(tmpADODataSet['COMPUTER_NAME']) = -1) then
  187. tmpStrLst.Add(tmpADODataSet['COMPUTER_NAME']);
  188. tmpADODataSet.Next;
  189. end;
  190. Result := tmpStrLst.Count;
  191. finally
  192. tmpStrLst.Free;
  193. tmpADODataSet.Free;
  194. end;
  195. end;
  196. procedure CreateAccess97MDB(AFileName : TFileName);
  197. begin
  198. CreateCatalog(AFileName, 4);
  199. end;
  200. procedure CreateAccess2KMDB(AFileName : TFileName);
  201. begin
  202. CreateCatalog(AFileName, 5);
  203. end;
  204. procedure CreateExcel8XLS(AFileName : TFileName);
  205. begin
  206. CreateCatalog(AFileName, 23);
  207. end;
  208. procedure CreateCatalog(AFileName : TFileName; AJetEngineType : Word);
  209. var
  210. Catalog : _Catalog; // the database
  211. DataSource : String;
  212. begin
  213. // A spot of housekeeping first up
  214. if FileExists(AFileName) then
  215. DeleteFile(PChar(AFileName));
  216. // Create a catalog (database) object using the provided COM object
  217. // creation method - no need for wrappers and no need for garbage
  218. // collection. All COM objects created will be automatically destroyed
  219. // when they go out of scope. (The OP compiler adds code to decrement
  220. // each object's reference count when they go out of scope. Since creating
  221. // the object in OP automatically increments its reference count to 1, this
  222. // ensures that COM will destroy the object because its reference count
  223. // then equals 0. Note that the scope is defined by the object's
  224. // declaration procedure, which is not necessarily where they are created).
  225. Catalog := CoCatalog.Create;
  226. // Set the connection string.
  227. // Note that properties specified in the connection string, such as
  228. // Jet OLEDB:Engine Type or Jet OLEDB:Encrypt Database are subsequently
  229. // used in the Catalog.Create method, but not all connection properties are
  230. // supported. See the Microsoft Jet 4.0 OLE DB Properties Reference for
  231. // further details.
  232. // BTW, Jet Engine Type 5 = Access 2000; Type 4 = Access 97
  233. { Global Const JET_ENGINETYPE_UNKNOWN = 0
  234. Global Const JET_ENGINETYPE_JET10 = 1
  235. Global Const JET_ENGINETYPE_JET11 = 2
  236. Global Const JET_ENGINETYPE_JET20 = 3
  237. Global Const JET_ENGINETYPE_JET3X = 4
  238. Global Const JET_ENGINETYPE_JET4X = 5
  239. Global Const JET_ENGINETYPE_DBASE3 = 10
  240. Global Const JET_ENGINETYPE_DBASE4 = 11
  241. Global Const JET_ENGINETYPE_DBASE5 = 12
  242. Global Const JET_ENGINETYPE_EXCEL30 = 20
  243. Global Const JET_ENGINETYPE_EXCEL40 = 21
  244. Global Const JET_ENGINETYPE_EXCEL50 = 22
  245. Global Const JET_ENGINETYPE_EXCEL80 = 23
  246. Global Const JET_ENGINETYPE_EXCEL90 = 24
  247. Global Const JET_ENGINETYPE_EXCHANGE4 = 30
  248. Global Const JET_ENGINETYPE_LOTUSWK1 = 40
  249. Global Const JET_ENGINETYPE_LOTUSWK3 = 41
  250. Global Const JET_ENGINETYPE_LOTUSWK4 = 42
  251. Global Const JET_ENGINETYPE_PARADOX3X = 50
  252. Global Const JET_ENGINETYPE_PARADOX4X = 51
  253. Global Const JET_ENGINETYPE_PARADOX5X = 52
  254. Global Const JET_ENGINETYPE_PARADOX7X = 53
  255. Global Const JET_ENGINETYPE_TEXT1X = 60
  256. Global Const JET_ENGINETYPE_HTML1X = 70 }
  257. DataSource := 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' + AFileName + ';Jet OLEDB:Engine Type=' + IntToStr(AJetEngineType);
  258. if AJetEngineType = 23 then
  259. DataSource := DataSource + ';Extended Properties=Excel 8.0';
  260. // Create a new Access database
  261. Catalog.Create(DataSource);
  262. end;
  263. procedure CompressRepairMDB(DBFile : TFileName);
  264. begin
  265. CompressRepairMDB(DBFile, '');
  266. end;
  267. procedure CompressRepairMDB(DBFile : TFileName; APassword : String);
  268. const
  269. tmpDBName = 'compress.mdb';
  270. var
  271. JROJetEngine : TJetEngine;
  272. srcConn,
  273. destConn : String;
  274. begin
  275. JROJetEngine := TJetEngine.Create(nil);
  276. try
  277. srcConn := 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' + DBFile;
  278. destConn := 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' + sPath + tmpDBName;
  279. if APassWord <> '' then begin
  280. srcConn := srcConn + ';Jet OLEDB:Database Password="' + APassWord+ '"';
  281. destConn := destConn + ';Jet OLEDB:Database Password="' + APassWord+ '"';
  282. end;
  283. // Datenbank reparieren & komprimieren
  284. JROJetEngine.CompactDatabase(srcConn, destConn);
  285. if FileExists(sPath + tmpDBName) then begin
  286. // Ausgangsdatenbank löschen
  287. DeleteFile(PChar(DBFile));
  288. // Komprimierte DB anstelle der AusgangsDB kopieren
  289. CopyFile(PChar(sPath + tmpDBName), PChar(DBFile), false);
  290. // Komprimierte DB löschen
  291. DeleteFile(PChar(sPath + tmpDBName));
  292. end;
  293. finally
  294. JROJetEngine.Disconnect;
  295. JROJetEngine.Free;
  296. end;
  297. end;
  298. function ContainsTableMDB(DBFile : TFileName; DBTable : String) : Boolean;
  299. var ADOConnTmp : TADOConnection;
  300. ADOXCatalog : ADOX_TLB.TCatalog;
  301. nCount : LongInt;
  302. begin
  303. Result := false;
  304. ADOConnTmp := TADOConnection.Create(nil);
  305. try
  306. if ConnectionSetStringMDB(DBFile, ADOConnTmp) then begin
  307. ADOConnTmp.Connected := true;
  308. ADOXCatalog := TCatalog.Create(nil);
  309. try
  310. ADOXCatalog.Set_ActiveConnection(ADOConnTmp.ConnectionObject);
  311. for nCount := 0 to ADOXCatalog.Tables.Count - 1 do begin
  312. if (AnsiUpperCase(DBTable) = AnsiUpperCase(ADOXCatalog.Tables.Item[nCount].Name)) then begin
  313. Result := true;
  314. Exit;
  315. end;
  316. end;
  317. finally
  318. ADOXCatalog.Free;
  319. end;
  320. end;
  321. finally
  322. ADOConnTmp.Free;
  323. end;
  324. end;
  325. function ContainsTableMDB(DBConn : TADOConnection; DBTable : String) : Boolean;
  326. var ADOXCatalog : TCatalog;
  327. nCount : LongInt;
  328. begin
  329. Result := false;
  330. DBConn.Connected := true;
  331. ADOXCatalog := TCatalog.Create(nil);
  332. try
  333. ADOXCatalog.Set_ActiveConnection(DBConn.ConnectionObject);
  334. for nCount := 0 to ADOXCatalog.Tables.Count - 1 do begin
  335. if (AnsiUpperCase(DBTable) = AnsiUpperCase(ADOXCatalog.Tables.Item[nCount].Name)) then begin
  336. Result := true;
  337. Exit;
  338. end;
  339. end;
  340. finally
  341. ADOXCatalog.Free;
  342. end;
  343. end;
  344. function CreateTableMDB(DBConn : TADOConnection; DBTable : String) : Boolean;
  345. var ADOXCatalog : TCatalog;
  346. ADOX_Table : _Table;
  347. nCount : LongInt;
  348. begin
  349. Result := false;
  350. DBConn.Connected := true;
  351. ADOXCatalog := TCatalog.Create(nil);
  352. try
  353. ADOXCatalog.Set_ActiveConnection(DBConn.ConnectionObject);
  354. ADOX_Table := {TADOXTable}CoTable.Create;
  355. try
  356. ADOX_Table.Name := DBTable;
  357. ADOXCatalog.Tables.Append(ADOX_Table);
  358. Result := false;
  359. finally
  360. ADOX_Table := nil;
  361. end;
  362. finally
  363. ADOXCatalog.Free;
  364. end;
  365. end;
  366. {
  367. function CreateAndPopulateRemoteTable(DBConnSrc, DBConnDest : TADOConnection; RecordSet : TRecordSet; sName : String) : Boolean;
  368. var
  369. ADOXCatalog : TCatalog;
  370. ADOXTable : TADOXTable;
  371. nFields : Integer;
  372. ADOXRecordSet : TRecordset;
  373. begin
  374. // Open a connection to your Remote Jet Database
  375. ADOXCatalog := TCatalog.Create(nil);
  376. ADOXTable := TADOXTable.Create(nil);
  377. ADOXCatalog.Set_ActiveConnection(DBConn.ConnectionObject);
  378. ADOXTable.Name = sName;
  379. for nFields = 0 to RecordSet.Fields.Count - 1 do begin
  380. case RecordSet.Fields(nFields).Type of
  381. 203, 202, 201, 200 :
  382. ADOXTable.Columns.Append(RecordSet.Fields(nFields).Name, adVarChar, rst.Fields(nFields).DefinedSize;
  383. 135, 134, 133, 7
  384. ADOXTable.Columns.Append RecordSet.Fields(Fields).Name, adDate, RecordSet.Fields(nFields).DefinedSize;
  385. 11
  386. ADOXTable.Columns.Append RecordSet.Fields(nFields).Name, adBoolean, RecordSet.Fields(nFields).DefinedSize;
  387. 131, 14, 6, 5, 4
  388. ADOXTable.Columns.Append RecordSet.Fields(nFields).Name, adDouble;
  389. 20, 19, 18, 17, 16, 3, 2
  390. ADOXTable.Columns.Append RecordSet.Fields(nFields).Name, adInteger;
  391. else
  392. ADOXTable.Columns.Append RecordSet.Fields(nFields).Name, adVarChar, 255;
  393. end;
  394. end;
  395. // Drop Table if it already exists
  396. ADOXCatalog.Tables.Delete(sName)
  397. // Append table to TableDefs collection
  398. ADOXCatalog.Tables.Append(ADOXTable)
  399. ADOXRecordSet.Set_ActiveConnection(DBConn.ConnectionObject);
  400. ADOXRecordSet.Open(sName, DBConn, adOpenDynamic, adLockOptimistic);
  401. if not ADOXRecordSet.BOF then ADOXRecordSet.MoveFirst
  402. while not ADOXRecordSet.EOF do begin
  403. nFields = 0;
  404. ADOXRecordSet.AddNew;
  405. for nFields = 0 to RecordSet.Fields.Count - 1 do
  406. ADOXRecordSet.Fields(ADOXRecordSet.Fields(nFields).Name) = RecordSet.Fields(ADOXRecordSet.Fields(nFields).Name) + '"';
  407. ADOXRecordSet.Update;
  408. RecordSet.MoveNext
  409. end;
  410. ADOXTable.Free;
  411. ADOXCatalog.Free;
  412. end;
  413. }
  414. function CheckUpdateNeeded(theConnectionString, theVerTable, theVerField, theVerValue : String; IgnoreDBPassWordError : Boolean) : Boolean;
  415. var
  416. rs : ADODB._RecordSet;
  417. connVersionTest : TADOConnection;
  418. tmpSQL : String;
  419. begin
  420. Result := true;
  421. if ((theVerTable = '') and (theVerField = '') and (theVerValue = '')) then
  422. Exit;
  423. connVersionTest := TADOConnection.Create(nil);
  424. with connVersionTest do
  425. try
  426. ConnectionString := theConnectionString;
  427. CursorLocation := clUseServer;
  428. LoginPrompt := false;
  429. try
  430. Connected := true;
  431. try
  432. if ContainsTableMDB(connVersionTest, theVerTable) then begin
  433. tmpSQL := 'SELECT * FROM ' + theVerTable + ' WHERE (' + theVerField + ' < ' + theVerValue + ')';
  434. rs := connVersionTest.Execute(tmpSQL);
  435. Result := (Abs(rs.RecordCount) > 0) and (not (rs.EOF or rs.BOF));
  436. end
  437. except
  438. on E : Exception do
  439. raise Exception.Create('Fehler bei Überprüfung der Versionsinformation.'#13#10 + E.Message);
  440. end;
  441. except
  442. on E : EOleException do begin
  443. // Fehler bei falschem Password übergehen ?
  444. if (Errors[Errors.Count-1].SQLState = '3031') and IgnoreDBPassWordError then
  445. Result := false
  446. else
  447. raise E;
  448. end;
  449. end;
  450. Connected := false;
  451. finally
  452. Free;
  453. end;
  454. end;
  455. // führt eine liste von sql-befehlen aus einer ini-datei aus
  456. // ini-datei besitzt dazu eine section connections mit ado-connection strings
  457. // und je connectionstring eine section mit einer liste von sql-statements.
  458. // diese sections tragen jeweils den namen des connectionsstrings.
  459. // um relative pfade im connectionstring und den sql-string zu ermöglichen
  460. // wird die zeichenfolge %APPDIR% generell gegen das Verzeichnis der
  461. // anwendung erstezt.
  462. // Aufruf in etwa :
  463. // if FileExists(FAppPath + 'update.bat') then begin
  464. // ADOExecuteSQLBatchFile(FAppPath + 'update.bat');
  465. // DeleteFile(FAppPath + 'update.bat');
  466. // end;
  467. procedure ADOExecuteSQLBatchFile(AControlIniFile : TFileName; ADBPath : String);
  468. var
  469. nCount,
  470. nConnCount,
  471. nSQLCount : Integer;
  472. ABatchFile : TMemIniFile;
  473. ASQLList,
  474. AConnList : TStringList;
  475. AConnection : WideString;
  476. AppPath : TFileName;
  477. tmpSQL,
  478. tmpConn,
  479. tmpVerTable,
  480. tmpVerField,
  481. tmpVerValue : String;
  482. begin
  483. // pfad der anwendung ohne abschliessenden backslash
  484. AppPath := ExtractFilePath(Application.ExeName);
  485. if AppPath[Length(AppPath)] = '\' then Delete(AppPath, Length(AppPath), 1);
  486. if (ADBPath <> '') and (not DirectoryExists(ADBPath)) then
  487. raise Exception.Create('Fehler bei der Datenbank-Aktualisierung.'#13#10'''' + ADBPath + ''' existiert nicht.')
  488. else
  489. if ADBPath[Length(ADBPath)] = '\' then Delete(ADBPath, Length(ADBPath), 1);
  490. ABatchFile := TMemIniFile.Create(AControlIniFile);
  491. ASQLList := TStringList.Create;
  492. AConnList := TStringList.Create;
  493. try
  494. ABatchFile.ReadSectionValues('Connections', AConnList);
  495. // prüfen ob alle zu aktualisierenden Datenbanken exklusiv geöffnet werden können
  496. nConnCount := 0;
  497. while nConnCount < AConnList.Count do begin
  498. // ersetzen der %APPDIR%'s und %DBDIR%'s im connectionstring
  499. tmpConn := StringReplace(AConnList.Values[AConnList.Names[nConnCount]], '%APPDIR%', AppPath, [rfReplaceAll, rfIgnoreCase]);
  500. tmpConn := StringReplace(tmpConn, '%DBDIR%', ADBPath, [rfReplaceAll, rfIgnoreCase]);
  501. // Information für Versionstabelle, Feld und neuen Wert auslesen
  502. tmpVerTable := ABatchFile.ReadString(AConnList.Names[nConnCount], 'TBL_VER', '');
  503. tmpVerField := ABatchFile.ReadString(AConnList.Names[nConnCount], 'FLD_VER', '');
  504. tmpVerValue := ABatchFile.ReadString(AConnList.Names[nConnCount], 'NEW_VER', '');
  505. // ... wenn die Datenbank aktualisiert werden muss
  506. if ABatchFile.ValueExists(AConnList.Names[nConnCount], 'SQL1') and CheckUpdateNeeded(tmpConn, tmpVerTable, tmpVerField, tmpVerValue, true) then begin
  507. // prüfen ob die Verbindung exklusiv geöffnet werden kann
  508. with TADOConnection.Create(nil) do
  509. try
  510. ConnectionString := tmpConn;
  511. CursorLocation := clUseServer;
  512. Mode := cmShareExclusive;
  513. LoginPrompt := false;
  514. try
  515. Connected := true;
  516. except
  517. on E : EOleException do
  518. if Errors[nCount].SQLState = '3356' then
  519. raise Exception.CreateHelp('Fehler bei der Datenbank-Aktualisierung.'#13#10'''' + ADBPath + ''' kann nicht exklusiv geöffnet werden.'#13#10'Stellen Sie sicher daß die Datenbank nicht genutzt wird.', 3356)
  520. else
  521. raise E;
  522. end;
  523. Connected := false;
  524. finally
  525. Free;
  526. end;
  527. AConnList.Values[AConnList.Names[nConnCount]] := tmpConn;
  528. nConnCount := nConnCount + 1;
  529. end
  530. else
  531. AConnList.Delete(nConnCount);
  532. end; {for - connections}
  533. for nConnCount := 0 to AConnList.Count - 1 do begin
  534. // Information für Versionstabelle, Feld und neuen Wert auslesen
  535. tmpVerTable := ABatchFile.ReadString(AConnList.Names[nConnCount], 'TBL_VER', '');
  536. tmpVerField := ABatchFile.ReadString(AConnList.Names[nConnCount], 'FLD_VER', '');
  537. tmpVerValue := ABatchFile.ReadString(AConnList.Names[nConnCount], 'NEW_VER', '');
  538. ABatchFile.ReadSectionValues(AConnList.Names[nConnCount], ASQLList);
  539. // zugehörige liste der sql-statements ermitteln und %APPDIR%'s und %DBDIR%'s ersetzen
  540. nSQLCount := 0;
  541. while nSQLCount < ASQLList.Count do
  542. if Pos('SQL', ANSIUpperCase(ASQLList.Names[nSQLCount])) = 1 then begin
  543. tmpSQL := StringReplace(ASQLList.Values[ASQLList.Names[nSQLCount]], '%APPDIR%', AppPath, [rfReplaceAll, rfIgnoreCase]);
  544. tmpSQL := StringReplace(tmpSQL, '%DBPATH%', ADBPath, [rfReplaceAll, rfIgnoreCase]);
  545. ASQLList[nSQLCount] := tmpSQL;
  546. nSQLCount := nSQLCount + 1;
  547. end
  548. else
  549. ASQLList.Delete(nSQLCount);
  550. if (ASQLList.Count > 0) then
  551. try
  552. ADOExecuteSQLList(AConnList.Values[AConnList.Names[nConnCount]], ASQLList, tmpVerTable, tmpVerField, tmpVerValue);
  553. finally
  554. end;
  555. end;
  556. finally
  557. ASQLList.Free;
  558. AConnList.Free;
  559. ABatchFile.Free;
  560. end;
  561. end;
  562. procedure ADOExecuteSQLBatchFile(AControlIniFile : TFileName; ASQLServer, AUser, APWD : String);
  563. var
  564. nCount,
  565. nConnCount,
  566. nSQLCount : Integer;
  567. ABatchFile : TMemIniFile;
  568. ASQLList,
  569. AConnList : TStringList;
  570. AConnection : WideString;
  571. AppPath : TFileName;
  572. tmpSQL,
  573. tmpConn,
  574. tmpVerTable,
  575. tmpVerField,
  576. tmpVerValue : String;
  577. begin
  578. // pfad der anwendung ohne abschliessenden backslash
  579. AppPath := ExtractFilePath(Application.ExeName);
  580. if AppPath[Length(AppPath)] = '\' then Delete(AppPath, Length(AppPath), 1);
  581. ABatchFile := TMemIniFile.Create(AControlIniFile);
  582. ASQLList := TStringList.Create;
  583. AConnList := TStringList.Create;
  584. try
  585. ABatchFile.ReadSectionValues('Connections', AConnList);
  586. // prüfen ob alle zu aktualisierenden Datenbanken exklusiv geöffnet werden können
  587. nConnCount := 0;
  588. while nConnCount < AConnList.Count do begin
  589. // ersetzen der %APPDIR%'s und %DBDIR%'s im connectionstring
  590. tmpConn := StringReplace(AConnList.Values[AConnList.Names[nConnCount]], '%APPDIR%', AppPath, [rfReplaceAll, rfIgnoreCase]);
  591. tmpConn := StringReplace(tmpConn, '%SQLSERVER%', ASQLServer, [rfReplaceAll, rfIgnoreCase]);
  592. tmpConn := StringReplace(tmpConn, '%SQLUSER%', AUser, [rfReplaceAll, rfIgnoreCase]);
  593. tmpConn := StringReplace(tmpConn, '%SQLPWD%', APWD, [rfReplaceAll, rfIgnoreCase]);
  594. // Information für Versionstabelle, Feld und neuen Wert auslesen
  595. tmpVerTable := ABatchFile.ReadString(AConnList.Names[nConnCount], 'TBL_VER', '');
  596. tmpVerField := ABatchFile.ReadString(AConnList.Names[nConnCount], 'FLD_VER', '');
  597. tmpVerValue := ABatchFile.ReadString(AConnList.Names[nConnCount], 'NEW_VER', '');
  598. // ... wenn die Datenbank aktualisiert werden muss
  599. if ABatchFile.ValueExists(AConnList.Names[nConnCount], 'SQL1') and CheckUpdateNeeded(tmpConn, tmpVerTable, tmpVerField, tmpVerValue, true) then begin
  600. AConnList.Values[AConnList.Names[nConnCount]] := tmpConn;
  601. nConnCount := nConnCount + 1;
  602. end
  603. else
  604. AConnList.Delete(nConnCount);
  605. end; {for - connections}
  606. for nConnCount := 0 to AConnList.Count - 1 do begin
  607. // Information für Versionstabelle, Feld und neuen Wert auslesen
  608. tmpVerTable := ABatchFile.ReadString(AConnList.Names[nConnCount], 'TBL_VER', '');
  609. tmpVerField := ABatchFile.ReadString(AConnList.Names[nConnCount], 'FLD_VER', '');
  610. tmpVerValue := ABatchFile.ReadString(AConnList.Names[nConnCount], 'NEW_VER', '');
  611. ABatchFile.ReadSectionValues(AConnList.Names[nConnCount], ASQLList);
  612. // zugehörige liste der sql-statements ermitteln und %APPDIR%'s und %DBDIR%'s ersetzen
  613. nSQLCount := 0;
  614. while nSQLCount < ASQLList.Count do
  615. if Pos('SQL', ANSIUpperCase(ASQLList.Names[nSQLCount])) = 1 then begin
  616. tmpSQL := StringReplace(ASQLList.Values[ASQLList.Names[nSQLCount]], '%APPDIR%', AppPath, [rfReplaceAll, rfIgnoreCase]);
  617. tmpSQL := StringReplace(tmpSQL, '%SQLSERVER%', ASQLServer, [rfReplaceAll, rfIgnoreCase]);
  618. tmpSQL := StringReplace(tmpSQL, '%SQLUSER%', AUser, [rfReplaceAll, rfIgnoreCase]);
  619. tmpSQL := StringReplace(tmpSQL, '%SQLPWD%', APWD, [rfReplaceAll, rfIgnoreCase]);
  620. ASQLList[nSQLCount] := tmpSQL;
  621. nSQLCount := nSQLCount + 1;
  622. end
  623. else
  624. ASQLList.Delete(nSQLCount);
  625. if (ASQLList.Count > 0) then
  626. try
  627. ADOExecuteSQLList(AConnList.Values[AConnList.Names[nConnCount]], ASQLList, tmpVerTable, tmpVerField, tmpVerValue);
  628. finally
  629. end;
  630. end;
  631. finally
  632. ASQLList.Free;
  633. AConnList.Free;
  634. ABatchFile.Free;
  635. end;
  636. end;
  637. procedure CreateVersionTable(theConnection : TADOConnection; theVerTable, theVerField, theVerValue : String);
  638. var
  639. tmpSQL : String;
  640. rs : ADODB._RecordSet;
  641. begin
  642. if not ContainsTableMDB(theConnection, theVerTable) then begin
  643. // Tabelle anlegen
  644. tmpSQL := 'CREATE TABLE ' + theVerTable + ' (' + theVerField + ' Double DEFAULT NULL)';
  645. rs := theConnection.Execute(tmpSQL);
  646. // Versionseintrag anlegen
  647. tmpSQL := 'INSERT INTO ' + theVerTable + ' (' + theVerField + ') VALUES (NULL)';
  648. rs := theConnection.Execute(tmpSQL);
  649. end;
  650. end;
  651. procedure UpdateVersionTable(theConnection : TADOConnection; theVerTable, theVerField, theVerValue : String);
  652. var
  653. tmpSQL : String;
  654. begin
  655. // sicherstellen, daß Tabelle für Versionsinformationen vorhanden ist.
  656. CreateVersionTable(theConnection, theVerTable, theVerField, theVerValue);
  657. // neue Versionsinformation schreiben
  658. if ((theVerTable <> '') and (theVerField <> '') and (theVerValue <> '')) then begin
  659. tmpSQL := 'UPDATE ' + theVerTable + ' SET ' + theVerField + ' = ' + theVerValue;
  660. theConnection.Execute(tmpSQL);
  661. end;
  662. end;
  663. // führt im kontext des übergebenen connectionsstrings eine liste von
  664. // sql-statements aus
  665. procedure ADOExecuteSQLList(AConnectionString : WideString; ASQLCommandList : TStrings; AVerTable, AVerField, AVerValue : String);
  666. var
  667. AnAdoConnection : TADOConnection;
  668. outRecAffected : OleVariant;
  669. nCount : Integer;
  670. begin
  671. AnAdoConnection := TADOConnection.Create(nil);
  672. if ASQLCommandList.Count > 0 then
  673. if CheckUpdateNeeded(AConnectionString, AVerTable, AVerField, AVerValue, false) then
  674. try
  675. with AnAdoConnection do begin
  676. ConnectionString := AConnectionString;
  677. LoginPrompt := false;
  678. Mode := cmShareExclusive;
  679. Connected := true;
  680. end;
  681. try
  682. // Liste der SQLs auf Verbindung ausführen.
  683. for nCount := 0 to ASQLCommandList.Count - 1 do
  684. try
  685. AnAdoConnection.Execute(ASQLCommandList[nCount]);
  686. except
  687. end;
  688. finally
  689. if (AVerTable <> '') then
  690. UpdateVersionTable(AnAdoConnection, AVerTable, AVerField, AVerValue);
  691. end;
  692. finally
  693. AnAdoConnection.Connected := false;
  694. AnAdoConnection.Free;
  695. end;
  696. end;
  697. function DateToSQLStr(dtDate : TDate) : String;
  698. begin
  699. Result := FormatDateTime('"#"mm"/"dd"/"yyyy"#"', dtDate);
  700. end;
  701. // kopiert den inhalt eines ado-datasets in eine stringlist ohne
  702. // ohne hierzu eine externe datei anzulegen (vgl. SaveAs Methode)
  703. procedure ADOCopyXMLToStringList(ADataSet : TCustomADODataSet; AStrings : TStrings);
  704. var
  705. ADOXRecordSet : ADODB_TLB.TRecordset;
  706. tempADOStream : ADODB_TLB.TStream;
  707. begin
  708. tempADOStream := ADODB_TLB.TStream.Create(nil);
  709. try
  710. // XML aus ADODataSet in TRecordSet (ADOX) übernehmen
  711. // und via save-Methode direkt in Stream ablegen
  712. ADOXRecordSet := ADODB_TLB.TRecordSet.Create(nil);
  713. try
  714. ADOXRecordSet.ConnectTo(ADataSet.RecordSet as _RecordSet);
  715. ADOXRecordSet.Save(tempADOStream.DefaultInterface, adPersistXML);
  716. AStrings.SetText(PChar(tempADOStream.ReadText(tempADOStream.Size)));
  717. finally
  718. ADOXRecordSet.Free;
  719. end;
  720. finally
  721. tempADOStream.Free;
  722. end;
  723. end;
  724. end.
  725. initialization
  726. sPath := ExtractFilePath(Application.ExeName);