ScAutoUpdateUnit.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. {
  2. 单元名: ScAutoUpdateUnit
  3. 作者: 张引
  4. 时间: 2003/12/29
  5. 作用: 升级ACCESS数据库文件
  6. 限制: 1.只能添加字段,修改字段类型,大小(字符串类型),不能删除字段
  7. 2.只支持如下字段:
  8. ftString, ftSmallint, ftInteger, ftBoolean, ftSingle, ftDouble,
  9. ftCurrency, ftDateTime, ftMemo, ftOLEObject
  10. 注意: 必须设置TScUpdater.CurrentFileVer,以实现根据版本号判断自动升级。
  11. }
  12. unit ScAutoUpdateUnit;
  13. interface
  14. uses
  15. SysUtils, DB, ADODB, Classes, ScTablesUnit{, ScFileArchiver, ScFileArchiverConsts};
  16. const
  17. MaxFieldCount = 512;
  18. PrimaryKey = 'PrimaryKey';
  19. type
  20. PFieldDefs = ^TFieldDefs;
  21. TFieldDefs = array [0..MaxFieldCount - 1] of TScFieldDef;
  22. PTableDef = ^TTableDef;
  23. // 表定义结构
  24. TTableDef = record
  25. // 表名
  26. TableName: string;
  27. // 字段数
  28. FieldCount: Integer;
  29. // 字段结构数组
  30. FieldDefs: PFieldDefs;
  31. // 是否需要重新创建
  32. Recreate: Boolean;
  33. // 重新创建主键
  34. RecreatePrimaryKey: Boolean;
  35. end;
  36. TSQLType = (stAlter, stCreate, stReCreate);
  37. TUpdateEventType = (uetAddFields, uetKeys, uetAfterUpdate);
  38. TUpdateEvent = procedure (ATableName: string; AEventType: TUpdateEventType;
  39. ASQLType: TSQLType; AConnection: TADOConnection);
  40. TUpdatedEvent = procedure (AFileVersion, ACurVersion: string;
  41. AConnection: TADOConnection; ASucceed: Boolean);
  42. EScUpdater = class(Exception);
  43. TScUpdater = class(TObject)
  44. private
  45. FTableDefList: TList;
  46. FFileName: string;
  47. FConnection: TADOConnection;
  48. FFileVer: string;
  49. FQuery: TADOQuery;
  50. FForceUpdate: Boolean;
  51. FForceCheck: Boolean;
  52. FCurFileVersion: string;
  53. FOnUpdateData: TUpdateEvent;
  54. FOnUpdated: TUpdatedEvent;
  55. function GetCurFileVersion: string;
  56. // 返回True:表存在,返回False: 表不存在
  57. function CheckTable(ATableName: string): Boolean;
  58. procedure GenerateSQL(ATableDef: PTableDef; ASQLType: TSQLType; ASQLList: TStrings);
  59. procedure InternalExcuteSQL(ASQL: string; AHideException: Boolean = False; AOpen: Boolean = False);
  60. function ExcuteUpdateSQL(ASQLList: TStrings): Boolean;
  61. procedure SetForceUpdate(const Value: Boolean);
  62. procedure SetForceCheck(const Value: Boolean);
  63. // 字符串是否是事件
  64. // 事件字符串格式:"事件名 表名 操作类型"
  65. function CheckEvent(AText: string): Boolean;
  66. public
  67. constructor Create;
  68. destructor Destroy; override;
  69. // 打开(AFileVers:打开文件的版本,程序中最新的文件版本号)
  70. procedure Open(AFileName: string; AConnection: TADOConnection;
  71. AFileVer, ACurrentFileVer: string);
  72. // 关闭
  73. procedure Close;
  74. // 执行升级操作
  75. function ExcuteUpdate: Boolean;
  76. // 执行其他SQL语句(如建立、删除索引)
  77. procedure ExcuteSQL(ASQL: string);
  78. // 添加表定义
  79. function AddTableDef(ATableName: string; AFieldDefs: PFieldDefs; AFieldCount: Integer;
  80. AReCreate, ARecreatePK: Boolean): Integer;
  81. // 文件是否需要升级(根据版本号判断)
  82. function FileNeedUpdate: Boolean;
  83. // 强制进行表和字段的升级检查
  84. property ForceCheck: Boolean read FForceCheck write SetForceCheck;
  85. // 强制升级所有表和字段
  86. property ForceUpdate: Boolean read FForceUpdate write SetForceUpdate;
  87. // 最新文件版本
  88. property CurrentFileVer: string read GetCurFileVersion;
  89. // 事件
  90. // 重建关键字之前
  91. property OnUpdateData: TUpdateEvent read FOnUpdateData
  92. write FOnUpdateData;
  93. // 完成升级后
  94. property OnUpdated: TUpdatedEvent read FOnUpdated
  95. write FOnUpdated;
  96. end;
  97. const
  98. SQLTypeStrs: array [TSQLType] of string = ('Modify', 'Create', 'ReCreate');
  99. SOnUpdateData = 'OnUpdateData';
  100. implementation
  101. uses
  102. ScUtils;
  103. function StrToSQLType(ASQLType: string): TSQLType;
  104. var
  105. I: TSQLType;
  106. begin
  107. Result := stAlter;
  108. for I := Low(SQLTypeStrs) to High(SQLTypeStrs) do
  109. begin
  110. if SameText(ASQLType, SQLTypeStrs[I]) then
  111. begin
  112. Result := I;
  113. Break;
  114. end;
  115. end;
  116. end;
  117. { TScUpdater }
  118. function TScUpdater.AddTableDef(ATableName: string; AFieldDefs: PFieldDefs;
  119. AFieldCount: Integer; AReCreate, ARecreatePK: Boolean): Integer;
  120. var
  121. pRec: PTableDef;
  122. begin
  123. New(pRec);
  124. pRec^.TableName := ATableName;
  125. pRec^.FieldCount := AFieldCount;
  126. pRec^.FieldDefs := AFieldDefs;
  127. pRec^.Recreate := AReCreate;
  128. pRec^.RecreatePrimaryKey := ARecreatePK;
  129. Result := FTableDefList.Add(pRec);
  130. end;
  131. function TScUpdater.CheckEvent(AText: string): Boolean;
  132. var
  133. strText, strEvent, strTableName, strEventType, strSQLType: string;
  134. SQLType: TSQLType;
  135. iPos: Integer;
  136. begin
  137. Result := False;
  138. strText := AText;
  139. // 检查事件名称
  140. iPos := Pos(' ', strText);
  141. if iPos > 0 then
  142. begin
  143. strEvent := Copy(strText, 1, iPos - 1);
  144. Delete(strText, 1, iPos);
  145. if SameText(strEvent, SOnUpdateData) then
  146. begin
  147. // 事件类型
  148. iPos := Pos(' ', strText);
  149. strEventType := Copy(strText, 1, iPos - 1);
  150. Delete(strText, 1, iPos);
  151. // 表名
  152. iPos := Pos(' ', strText);
  153. strTableName := Copy(strText, 1, iPos - 1);
  154. Delete(strText, 1, iPos);
  155. // 操作类型
  156. strSQLType := strText;
  157. SQLType := StrToSQLType(strSQLType);
  158. Result := True;
  159. if Assigned(FOnUpdateData) then
  160. FOnUpdateData(strTableName, TUpdateEventType(StrToInt(strEventType)), SQLType, FConnection);
  161. end;
  162. end;
  163. end;
  164. function TScUpdater.CheckTable(ATableName: string): Boolean;
  165. var
  166. I: Integer;
  167. Names: TStringList;
  168. begin
  169. Names := TStringList.Create;
  170. try
  171. FConnection.GetTableNames(Names);
  172. if Names.IndexOf(ATableName) < 0 then
  173. Result := False
  174. else
  175. Result := True;
  176. finally
  177. Names.Free;
  178. end;
  179. end;
  180. procedure TScUpdater.Close;
  181. begin
  182. FQuery.Close;
  183. end;
  184. constructor TScUpdater.Create;
  185. begin
  186. FForceUpdate := False;
  187. FForceCheck := False;
  188. FTableDefList := TList.Create;
  189. FQuery := TADOQuery.Create(nil);
  190. end;
  191. destructor TScUpdater.Destroy;
  192. begin
  193. Close;
  194. FQuery.Free;
  195. ClearPointerList(FTableDefList);
  196. FTableDefList.Free;
  197. inherited;
  198. end;
  199. procedure TScUpdater.ExcuteSQL(ASQL: string);
  200. begin
  201. InternalExcuteSQL(ASQL);
  202. end;
  203. function TScUpdater.ExcuteUpdate: Boolean;
  204. var
  205. I: Integer;
  206. pRec: PTableDef;
  207. SQLs: TStringList;
  208. SQLType: TSQLType;
  209. bHasError: Boolean;
  210. sError: string;
  211. begin
  212. Result := False;
  213. bHasError := False;
  214. sError := '';
  215. if FileNeedUpdate then
  216. begin
  217. SQLs := TStringList.Create;
  218. try
  219. for I := 0 to FTableDefList.Count - 1 do
  220. begin
  221. pRec := PTableDef(FTableDefList[I]);
  222. if CheckTable(pRec^.TableName) then
  223. begin
  224. if pRec^.Recreate then
  225. SQLType := stReCreate
  226. else
  227. SQLType := stAlter;
  228. end
  229. else
  230. SQLType := stCreate;
  231. GenerateSQL(pRec, SQLType, SQLs);
  232. if SQLs.Count > 0 then
  233. if not ExcuteUpdateSQL(SQLs) then
  234. begin
  235. bHasError := True;
  236. sError := sError + #13#10 + Format('Update operation [%s] on table [%s] can not be executed!', [SQLTypeStrs[SQLType], pRec^.TableName]);
  237. end;
  238. end;
  239. finally
  240. SQLs.Free;
  241. end;
  242. if bHasError then
  243. MessageWarning(0, '升级文件时发生错误,无法完成升级。'#13#10'错误信息:' + sError)
  244. else
  245. Result := True;
  246. if Assigned(FOnUpdated) then
  247. FOnUpdated(FFileVer, CurrentFileVer, FConnection, Result);
  248. end;
  249. end;
  250. function TScUpdater.ExcuteUpdateSQL(ASQLList: TStrings): Boolean;
  251. var
  252. I: Integer;
  253. HideExcption: Boolean;
  254. begin
  255. Result := False;
  256. try
  257. for I := 0 to ASQLList.Count - 1 do
  258. begin
  259. if not CheckEvent(ASQLList[I]) then
  260. begin
  261. HideExcption := ASQLList.Objects[I] <> nil;
  262. if HideExcption then
  263. HideExcption := Boolean(Integer(ASQLList.Objects[I]));
  264. InternalExcuteSQL(ASQLList[I], HideExcption);
  265. end;
  266. end;
  267. Result := True;
  268. except
  269. end;
  270. end;
  271. function TScUpdater.FileNeedUpdate: Boolean;
  272. begin
  273. if GetCurFileVersion = '' then
  274. raise EScUpdater.Create('必须设置TScUpdater.CurrentFileVer!');
  275. Result := (ScCompareFileVer(FFileVer, GetCurFileVersion) < 0) or FForceCheck;
  276. end;
  277. function SameFieldType(AFieldType: TFieldType; AScFieldType: TScMDBFieldType): Boolean;
  278. begin
  279. Result := False;
  280. case AScFieldType of
  281. ftString:
  282. Result := (AFieldType = DB.ftWideString) or (AFieldType = DB.ftString);
  283. ftByte:
  284. Result := AFieldType = DB.ftWord;
  285. ftSmallint:
  286. Result := AFieldType = DB.ftSmallint;
  287. ftInteger:
  288. Result := AFieldType = DB.ftInteger;
  289. ftBoolean:
  290. Result := AFieldType = DB.ftBoolean;
  291. ftSingle:
  292. Result := AFieldType = DB.ftFloat;
  293. ftDouble:
  294. Result := AFieldType = DB.ftFloat;
  295. ftCurrency:
  296. Result := (AFieldType = DB.ftCurrency) or (AFieldType = DB.ftBCD);
  297. ftDateTime:
  298. Result := AFieldType = DB.ftDateTime;
  299. ftMemo:
  300. Result := AFieldType = DB.ftMemo;
  301. ftOLEObject:
  302. Result := AFieldType = DB.ftBlob;
  303. end;
  304. end;
  305. procedure TScUpdater.GenerateSQL(ATableDef: PTableDef; ASQLType: TSQLType; ASQLList: TStrings);
  306. var
  307. bHasKey: Boolean;
  308. function GenerateCreateSQL: string;
  309. var
  310. I: Integer;
  311. Def: TScFieldDef;
  312. strField, strFields, strKeyFields: string;
  313. begin
  314. Result := '';
  315. if ATableDef^.FieldCount > 0 then
  316. begin
  317. // CREATE TABLE table1
  318. Result := Format('CREATE TABLE %s ', [ATableDef^.TableName]);
  319. strFields := '';
  320. strKeyFields := '';
  321. for I := 0 to ATableDef^.FieldCount - 1 do
  322. begin
  323. Def := ATableDef^.FieldDefs[I];
  324. // field1 type
  325. strField := Def.FieldName + ' ' + ScMDBFieldTypeName[Def.FieldType];
  326. case Def.FieldType of
  327. ftString:
  328. // field1 type (size)
  329. strField := strField + Format(' (%d)', [Def.Size]);
  330. ftFMTBCD:
  331. // field1 type (size, Precision)
  332. strField := strField + Format(' (%d,%d)', [Def.Size, Def.Precision]);
  333. end;
  334. if Def.NotNull then
  335. // field1 type (size) NOT NULL
  336. strField := strField + ' ' + 'NOT NULL';
  337. if Def.PrimaryKey then
  338. strKeyFields := strKeyFields + Def.FieldName + ', ';
  339. strFields := strFields + strField + ', ';
  340. end;
  341. if strKeyFields <> '' then
  342. begin
  343. Delete(strKeyFields, Length(strKeyFields) - 1, 2);
  344. // CONSTRAINT PrimaryKey PRIMARY KEY (field1, field2...)
  345. strKeyFields := Format('CONSTRAINT %s PRIMARY KEY (%s)', [PrimaryKey, strKeyFields]);
  346. end
  347. else
  348. Delete(strFields, Length(strFields) - 1, 2);
  349. // (field1 type (size) NOT NULL, field2 type (size) NOT NULL..., CONSTRAINT PrimaryKey PRIMARY KEY (field1, field2...))
  350. strFields := Format('(%s)', [strFields + strKeyFields]);
  351. // CREATE TABLE table1 (field1 type (size) NOT NULL, field2 type (size) NOT NULL..., CONSTRAINT PrimaryKey PRIMARY KEY (field1, field2...))
  352. Result := Result + strFields;
  353. end;
  354. end;
  355. type
  356. TAlterType = (atAddField, atAlterField, atDropField, atAddIndex, atDropIndex);
  357. function GenerateSingleFieldAlterSQL(ATableName: string; AFieldDef: TScFieldDef;
  358. AOp: TAlterType; var ANeedDefault: Boolean): string;
  359. begin
  360. Result := '';
  361. ANeedDefault := False;
  362. case AOp of
  363. atAddField:
  364. begin
  365. Result := Format('ALTER TABLE %s ADD COLUMN %s %s',
  366. [ATableName, AFieldDef.FieldName, ScMDBFieldTypeName[AFieldDef.FieldType]]);
  367. case AFieldDef.FieldType of
  368. ftString:
  369. Result := Result + Format(' (%d)', [AFieldDef.Size]);
  370. ftFMTBCD:
  371. Result := Result + Format(' (%d,%d)', [AFieldDef.Size, AFieldDef.Precision]);
  372. end;
  373. if AFieldDef.NotNull then
  374. begin
  375. Result := Result + ' NOT NULL';
  376. case AFieldDef.FieldType of
  377. ftByte, ftSmallint, ftInteger, ftBoolean, ftSingle, ftDouble,
  378. ftCurrency, ftDateTime, ftFMTBCD:
  379. ANeedDefault := True;
  380. end;
  381. end;
  382. end;
  383. atDropField:
  384. begin
  385. Result := Format('ALTER TABLE %s DROP COLUMN %s', [ATableName, AFieldDef.FieldName]);
  386. end;
  387. atAlterField:
  388. begin
  389. Result := Format('ALTER TABLE %s ALTER COLUMN %s %s',
  390. [ATableName, AFieldDef.FieldName, ScMDBFieldTypeName[AFieldDef.FieldType]]);
  391. case AFieldDef.FieldType of
  392. ftString:
  393. Result := Result + Format(' (%d)', [AFieldDef.Size]);
  394. ftFMTBCD:
  395. Result := Result + Format(' (%d,%d)', [AFieldDef.Size, AFieldDef.Precision]);
  396. end;
  397. if AFieldDef.NotNull then
  398. begin
  399. Result := Result + ' NOT NULL';
  400. case AFieldDef.FieldType of
  401. ftByte, ftSmallint, ftInteger, ftBoolean, ftSingle, ftDouble,
  402. ftCurrency, ftDateTime, ftFMTBCD:
  403. ANeedDefault := True;
  404. end;
  405. end;
  406. end;
  407. end;
  408. end;
  409. function GenerateDefaultValueSQL(ATableName: string; AFieldDef: TScFieldDef): string;
  410. begin
  411. Result := '';
  412. case AFieldDef.FieldType of
  413. ftByte, ftSmallint, ftInteger:
  414. Result := Format('UPDATE %s SET %s = %d WHERE IsNull(%s)',
  415. [ATableName, AFieldDef.FieldName, 0, AFieldDef.FieldName]);
  416. ftSingle, ftDouble, ftCurrency, ftFMTBCD:
  417. Result := Format('UPDATE %s SET %s = %f WHERE IsNull(%s)',
  418. [ATableName, AFieldDef.FieldName, 0.0, AFieldDef.FieldName]);
  419. ftBoolean:
  420. Result := Format('UPDATE %s SET %s = %s WHERE IsNull(%s)',
  421. [ATableName, AFieldDef.FieldName, 'FALSE', AFieldDef.FieldName]);
  422. ftDateTime:
  423. Result := Format('UPDATE %s SET %s = ''%s'' WHERE IsNull(%s)',
  424. [ATableName, AFieldDef.FieldName, '2000-1-1 12:00:00', AFieldDef.FieldName]);
  425. end;
  426. end;
  427. function GenerateSingleKeyAlterSQL(ATableName, AIndexName, AFieldNames: string; AOp: TAlterType): string;
  428. begin
  429. Result := '';
  430. case AOp of
  431. atAddIndex:
  432. begin
  433. Result := Format('ALTER TABLE %s ADD CONSTRAINT %s Primary Key (%s)', [ATableName, AIndexName, AFieldNames]);
  434. end;
  435. atDropIndex:
  436. begin
  437. Result := Format('ALTER TABLE %s DROP CONSTRAINT %s', [ATableName, AIndexName]);
  438. end;
  439. end;
  440. end;
  441. procedure GenerateAlterSQL;
  442. var
  443. I, J: Integer;
  444. Field: TField;
  445. pDef: PScFieldDef;
  446. AddList, ModifyList: TList;
  447. KeyFields: string;
  448. bNeedDefaultValue: Boolean;
  449. begin
  450. InternalExcuteSQL(Format('SELECT * FROM %s WHERE 0=1', [ATableDef^.TableName]), False, True);
  451. AddList := TList.Create;
  452. ModifyList := TList.Create;
  453. try
  454. KeyFields := '';
  455. for I := 0 to ATableDef^.FieldCount - 1 do
  456. begin
  457. pDef := @ATableDef^.FieldDefs^[I];
  458. if (KeyFields <> '') and pDef^.PrimaryKey then
  459. KeyFields := KeyFields + ', ';
  460. if pDef^.PrimaryKey then
  461. KeyFields := KeyFields + pDef^.FieldName;
  462. AddList.Add(pDef);
  463. end;
  464. { if KeyFields <> '' then
  465. Delete(KeyFields, Length(KeyFields) - 1, 2);}
  466. for I := 0 to FQuery.Fields.Count - 1 do
  467. begin
  468. Field := FQuery.Fields[I];
  469. for J := 0 to AddList.Count - 1 do
  470. begin
  471. pDef := PScFieldDef(AddList[J]);
  472. if SameText(Field.FieldName, pDef^.FieldName) then
  473. begin
  474. if FForceUpdate or pDef^.ForceUpdate then
  475. ModifyList.Add(pDef)
  476. else
  477. begin
  478. if not SameFieldType(Field.DataType, pDef^.FieldType) then
  479. ModifyList.Add(pDef)
  480. else if (Field.DataType in [ftWideString]) and (Field.Size <> pDef^.Size) then
  481. ModifyList.Add(pDef)
  482. // ADO读不到数据库中字段的Required,所以这句代码无用
  483. (*
  484. else if Field.Required <> pDef^.NotNull then
  485. ModifyList.Add(pDef)*);
  486. end;
  487. AddList.Remove(pDef);
  488. Break;
  489. end;
  490. end;
  491. end;
  492. for I := 0 to ModifyList.Count - 1 do
  493. begin
  494. pDef := PScFieldDef(ModifyList[I]);
  495. ASQLList.Add(GenerateSingleFieldAlterSQL(ATableDef^.TableName, pDef^, atAlterField, bNeedDefaultValue));
  496. if bNeedDefaultValue then
  497. ASQLList.Add(GenerateDefaultValueSQL(ATableDef^.TableName, pDef^));
  498. end;
  499. for I := 0 to AddList.Count - 1 do
  500. begin
  501. pDef := PScFieldDef(AddList[I]);
  502. ASQLList.Add(GenerateSingleFieldAlterSQL(ATableDef^.TableName, pDef^, atAddField, bNeedDefaultValue));
  503. if bNeedDefaultValue then
  504. ASQLList.Add(GenerateDefaultValueSQL(ATableDef^.TableName, pDef^));
  505. end;
  506. if AddList.Count > 0 then
  507. // 添加事件
  508. ASQLList.Add(Format('%s %d %s %s', [SOnUpdateData, Ord(uetAddFields), ATableDef.TableName, SQLTypeStrs[ASQLType]]));
  509. if ATableDef.RecreatePrimaryKey then
  510. begin
  511. if bHasKey then
  512. ASQLList.AddObject(GenerateSingleKeyAlterSQL(ATableDef^.TableName, PrimaryKey, KeyFields, atDropIndex), TObject(Integer(True)));
  513. // 添加事件
  514. ASQLList.Add(Format('%s %d %s %s', [SOnUpdateData, Ord(uetKeys), ATableDef.TableName, SQLTypeStrs[ASQLType]]));
  515. ASQLList.Add(GenerateSingleKeyAlterSQL(ATableDef^.TableName, PrimaryKey, KeyFields, atAddIndex));
  516. end;
  517. finally
  518. AddList.Free;
  519. ModifyList.Free;
  520. end;
  521. end;
  522. procedure CheckHasKey;
  523. var
  524. Table: TADOTable;
  525. I: Integer;
  526. begin
  527. bHasKey := False;
  528. Table := TADOTable.Create(nil);
  529. try
  530. Table.Connection := FConnection;
  531. Table.TableName := ATableDef^.TableName;
  532. Table.Open;
  533. for I := 0 to Table.FieldCount - 1 do
  534. if pfInKey in Table.Fields[I].ProviderFlags then
  535. begin
  536. bHasKey := True;
  537. Break;
  538. end;
  539. finally
  540. Table.Free;
  541. end;
  542. end;
  543. begin
  544. ASQLList.Clear;
  545. bHasKey := True;
  546. case ASQLType of
  547. stAlter:
  548. begin
  549. // zhangyin 2014-01-26虽然此方法可以避免调试时弹出异常,但是会占用比较长的时间
  550. // (4500行清单的项目会将升级数据库时间加长一倍以上 1s->2.4s)
  551. // 所以还是屏蔽掉。
  552. //CheckHasKey;
  553. GenerateAlterSQL;
  554. end;
  555. stCreate:
  556. ASQLList.Add(GenerateCreateSQL);
  557. stReCreate:
  558. begin
  559. ASQLList.Add(Format('DROP TABLE %s', [ATableDef^.TableName]));
  560. ASQLList.Add(GenerateCreateSQL);
  561. end;
  562. end;
  563. if ASQLList.Count > 0 then
  564. ASQLList.Add(Format('%s %d %s %s', [SOnUpdateData, Ord(uetAfterUpdate), ATableDef^.TableName, SQLTypeStrs[ASQLType]]));
  565. end;
  566. function TScUpdater.GetCurFileVersion: string;
  567. begin
  568. Result := FCurFileVersion;
  569. end;
  570. procedure TScUpdater.InternalExcuteSQL(ASQL: string; AHideException, AOpen: Boolean);
  571. begin
  572. FQuery.Close;
  573. FQuery.SQL.Clear;
  574. FQuery.SQL.Add(ASQL);
  575. try
  576. if AOpen then
  577. FQuery.Open
  578. else
  579. FQuery.ExecSQL;
  580. except
  581. if not AHideException then
  582. raise;
  583. end;
  584. end;
  585. procedure TScUpdater.Open(AFileName: string; AConnection: TADOConnection;
  586. AFileVer, ACurrentFileVer: string);
  587. begin
  588. FFileName := AFileName;
  589. FConnection := AConnection;
  590. FFileVer := AFileVer;
  591. if AFileVer = '' then
  592. FFileVer := '0.0.0.0';
  593. FCurFileVersion := ACurrentFileVer;
  594. // 为空时,设一个很大的当前版本号,强制升级
  595. if FCurFileVersion = '' then
  596. FCurFileVersion := '100000.0.0.0';
  597. FQuery.Connection := AConnection;
  598. ClearPointerList(FTableDefList);
  599. end;
  600. procedure TScUpdater.SetForceCheck(const Value: Boolean);
  601. begin
  602. FForceCheck := Value;
  603. end;
  604. procedure TScUpdater.SetForceUpdate(const Value: Boolean);
  605. begin
  606. FForceUpdate := Value;
  607. end;
  608. end.