PageRenderTime 69ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 1ms

/UDbSaver.pas

https://code.google.com/
Pascal | 488 lines | 433 code | 29 blank | 26 comment | 55 complexity | f4d2e1f378bda7dfb382f65eb715daa2 MD5 | raw file
  1. unit UDbSaver;
  2. interface
  3. uses UDbStructure, Ora, SysUtils, Db {$IFDEF VER150},Variants{$ENDIF}, Classes;
  4. type
  5. TSqlItem = class(TCollectionItem)
  6. public
  7. Table: string;
  8. Fields: string;
  9. Key1Null: boolean;
  10. Query: TOraQuery;
  11. constructor Create(Collection: TCollection); override;
  12. end;
  13. TSqlItems = class(TCollection)
  14. private
  15. function GetItem(Index: integer): TSqlItem;
  16. procedure SetItem(Index: integer; Value: TSqlItem);
  17. function Add(
  18. ATable, AFields: string; AKey1Null: boolean; AQuery: TOraQuery): TSqlItem;
  19. function FindItem(ATable, AFields: string; AKey1Null: boolean): TSqlItem;
  20. public
  21. constructor Create;
  22. property Items[Index: integer]: TSqlItem read GetItem write SetItem; default;
  23. end;
  24. TDbSaver=class
  25. public
  26. DBS: TDbStructure;
  27. OS: TOraSession;
  28. Key2Default: integer;
  29. function SaveRecord(p_Table: string; p_Values: array of variant; p_Commit: Boolean = false): integer;
  30. procedure SetState(p_Table: string; p_Id,p_Inst: integer; p_State: string);
  31. procedure StartTransaction;
  32. procedure Commit;
  33. procedure Rollback;
  34. function GetSQLValue(p_Sql:string; p_Field:string=''):variant;
  35. procedure ExecSql(p_Sql: string); overload;
  36. procedure ExecSql(p_Sql: string; p_ParValues:array of variant); overload;
  37. constructor Create(p_ConnectString: string); overload;
  38. constructor Create(p_OS: TOraSession); overload;
  39. constructor Create(p_OS: TOraSession; p_DBS: TDbStructure); overload;
  40. constructor Create(p_DBS: TDbStructure); overload;
  41. destructor Destroy; override;
  42. private
  43. OSCreated, DBSCreated: Boolean;
  44. LastTable, LastFields: string;
  45. q: TOraQuery;
  46. SqlList: TSqlItems;
  47. procedure ExecSQL(p_Q:TOraQuery); overload;
  48. procedure DefineQParams(var p_Q:TOraQuery;p_ParValues:array of variant);
  49. function SetLocalSeparator(AVar: string): string;
  50. end;
  51. implementation
  52. //==============================================================================
  53. constructor TDbSaver.Create(p_ConnectString: string);
  54. begin
  55. OS := TOraSession.Create(nil);
  56. OS.ConnectPrompt:=false;
  57. OS.ConnectString:=p_ConnectString;
  58. try
  59. OS.Connect;
  60. except
  61. on E:Exception do
  62. raise exception.create('TDbSaver: ?? ??????? ?????????????? ??????'+#13#10+E.Message);
  63. end;
  64. DBS := TDbStructure.Create(OS);
  65. OSCreated := true; DBSCreated := true;
  66. q := TOraQuery.Create(nil);
  67. q.Session := OS;
  68. Self.SqlList := TSqlItems.Create;
  69. end;
  70. //==============================================================================
  71. constructor TDbSaver.Create(p_OS: TOraSession);
  72. begin
  73. OS := p_OS;
  74. DBS := TDbStructure.Create(OS);
  75. OSCreated := false; DBSCreated := true;
  76. q := TOraQuery.Create(nil);
  77. q.Session := OS;
  78. Self.SqlList := TSqlItems.Create;
  79. end;
  80. //==============================================================================
  81. constructor TDbSaver.Create(p_OS: TOraSession; p_DBS: TDbStructure);
  82. begin
  83. OSCreated := false; DBSCreated := false;
  84. q := TOraQuery.Create(nil);
  85. OS := p_OS;
  86. DBS := p_DBS;
  87. q.Session:=OS;
  88. Self.SqlList := TSqlItems.Create;
  89. end;
  90. //==============================================================================
  91. constructor TDbSaver.Create(p_DBS: TDbStructure);
  92. begin
  93. OSCreated := true; DBSCreated := false;
  94. OS := TOraSession.Create(nil);
  95. OS.Username := p_DBS.OraUser;
  96. OS.Password := p_DBS.OraPassword;
  97. OS.Server := p_DBS.OraServer;
  98. OS.Connect;
  99. q := TOraQuery.Create(nil);
  100. q.Session := OS;
  101. DBS := p_DBS;
  102. Self.SqlList := TSqlItems.Create;
  103. end;
  104. //==============================================================================
  105. destructor TDbSaver.Destroy;
  106. begin
  107. q.Close;
  108. q.Free;
  109. if DBSCreated then DBS.Free;
  110. if OSCreated then OS.Free;
  111. SqlList.Free;
  112. end;
  113. //==============================================================================
  114. function TDbSaver.SaveRecord(p_Table: string; p_Values: array of variant; p_Commit: Boolean = false): integer;
  115. var
  116. vFields,Key1,Key2: string;
  117. Key1Exists, Key2Exists, Key1Null: Boolean;
  118. Key1Value,Key2Value: Variant;
  119. i: integer;
  120. vSqlItem: TSqlItem;
  121. //****************************************************************************
  122. procedure PreProcessValues;
  123. var i: integer;
  124. begin
  125. Key1 := DBS.Key1(p_Table);
  126. Key2 := DBS.Key2(p_Table);
  127. if Key1='' then
  128. raise exception.create('?? ??????? ??????????/??????????? ?????');
  129. vFields := '';
  130. Key1Exists := false;
  131. Key1Null := false;
  132. Key2Exists := false;
  133. for i:=0 to High(p_Values) div 2 do
  134. begin
  135. vFields:=vFields+VarToStr(p_Values[i*2])+',';
  136. if p_Values[i*2]=Key1 then
  137. begin
  138. Key1Exists:=true;
  139. Key1Value:=p_Values[i*2+1];
  140. Key1Null := (VarToStr(Key1Value) = '0') or VarIsNull(Key1Value);
  141. end;
  142. if p_Values[i*2]=Key2 then
  143. begin
  144. Key2Exists:=true;
  145. Key2Value:=p_Values[i*2+1];
  146. end;
  147. end;
  148. if not Key1Exists and (DBS.ColumnOraType(p_Table,Key1)<>'NUMBER') then
  149. raise exception.create('??? ??????? ? ?????????? ?????????? ?????? ???????? ????? ?????? ???? ??????? ????');
  150. if not Key2Exists and (Key2<>'') and (Key2Default=0) then
  151. raise exception.create('???????? ??????? ????????? ???? ?? ??????? ? ?? ??????????? ?? ?????????');
  152. end;
  153. //****************************************************************************
  154. procedure CreateSql;
  155. var
  156. i: integer;
  157. s,vValues: string;
  158. begin
  159. q.Sql.Text:='begin'+#13#10;
  160. if Key1Exists and (not Key1Null) then
  161. begin
  162. q.Sql.Add('update '+DBS.OraUser+'.'+p_Table+' set');
  163. for i:=0 to High(p_Values) div 2 do
  164. if (p_Values[i*2]<>Key1) and (p_Values[i*2]<>Key2) then
  165. q.Sql.Add(Format('%s=:%s,',[p_Values[i*2],p_Values[i*2]]));
  166. q.Sql.Text:=copy(q.Sql.Text,1,length(q.Sql.Text)-3);
  167. q.Sql.Add('where '+Key1+'=:'+Key1);
  168. if Key2<>'' then
  169. q.Sql.Add('and '+Key2+'=:'+Key2);
  170. q.Sql.Add(';');
  171. q.Sql.Add('if sql%notfound then');
  172. end;
  173. vValues:='';
  174. q.Sql.Add('insert into '+DBS.OraUser+'.'+p_Table+'(');
  175. if (not Key1Exists) or Key1Null then
  176. begin
  177. q.Sql.Add(Key1 +',');
  178. vValues := vValues + DBS.OraUser +'.'+ DBS.SeqByTable(p_Table) +'.nextval,';
  179. end;
  180. if not Key2Exists and (Key2<>'') then begin
  181. q.Sql.Add(Key2+',');
  182. vValues:=vValues+':'+Key2+',';
  183. end;
  184. for i := 0 to High(p_Values) div 2 do
  185. if not ((p_Values[i*2] = Key1) and Key1Null) then
  186. begin
  187. s:=p_Values[i*2];
  188. if i<>High(p_Values) div 2 then s:=s+',';
  189. q.Sql.Add(s);
  190. vValues:=vValues+':'+s;
  191. end;
  192. q.Sql.Add(') values ('+vValues+');');
  193. if Key1Exists and (not Key1Null) then
  194. q.Sql.Add('end if;');
  195. q.SQL.Add('end;');
  196. q.Prepare;
  197. for i:=0 to q.Params.Count-1 do
  198. begin
  199. q.Params[i].ParamType := ptInput;
  200. q.Params[i].DataType := DBS.ColumnParamType(p_Table,q.Params[i].Name);
  201. end;
  202. end;
  203. //****************************************************************************
  204. function GetSeqValue: integer;
  205. var
  206. qSeq: TOraQuery;
  207. vSeqName: string;
  208. begin
  209. vSeqName := DBS.SeqByTable(p_Table);
  210. if vSeqName = '' then
  211. raise exception.create('???????? ??????? ???? ????? ?? ???????, ??? ???? ??????? ?? ??????');
  212. qSeq := TOraQuery.Create(nil);
  213. try
  214. qSeq.Session := OS;
  215. qSeq.Sql.Text := ' select '+DBS.OraUser+'.'+vSeqName+'.nextval from dual';
  216. qSeq.Open;
  217. result := qSeq.Fields[0].AsInteger;
  218. qSeq.Close;
  219. finally
  220. qSeq.Free;
  221. end;
  222. end;
  223. //****************************************************************************
  224. procedure Save;
  225. var
  226. i: integer;
  227. begin
  228. if q.Active then q.Close;
  229. if not Key2Exists and (Key2<>'') then
  230. q.ParamByName(Key2).AsInteger:=Key2Default;
  231. for i := 0 to High(p_Values) div 2 do
  232. if not ((p_Values[i*2] = Key1) and Key1Null) then
  233. begin
  234. if (DBS.ColumnOraType(p_Table,p_Values[i*2]) = 'NUMBER') and (p_Values[i*2+1] <> null) then
  235. q.ParamByName(p_Values[i*2]).Value := SetLocalSeparator(p_Values[i*2+1])
  236. else
  237. q.ParamByName(p_Values[i*2]).Value := p_Values[i*2+1];
  238. end;
  239. //q.SQL.SaveToFile('d:\1.sql');
  240. q.ExecSql;
  241. end;
  242. //****************************************************************************
  243. begin
  244. try
  245. if High(p_Values) mod 2 = 0 then
  246. raise exception.Create('???????? p_Values ?????? ????????? ?????? ????? ????????');
  247. if not DBS.TableExists(p_Table) then
  248. raise exception.create('??????? ?? ???????');
  249. for i:=0 to High(p_Values) div 2 do
  250. p_Values[i*2]:=ANSIUpperCase(VarToStr(p_Values[i*2]));
  251. PreProcessValues;
  252. // ???? ?????????? ??????? ? ???? ?????????, ?? ?? ????????????? ??????
  253. if (p_Table<>LastTable) or (vFields<>LastFields) then
  254. begin
  255. vSqlItem := SqlList.FindItem(p_Table, vFields, Key1Null);
  256. if vSqlItem = nil then
  257. begin
  258. CreateSql;
  259. SqlList.Add(p_Table, vFields, Key1Null, q);
  260. end
  261. else
  262. q.Assign(vSqlItem.Query);
  263. end;
  264. //if p_Commit then OS.StartTransaction;
  265. Save;
  266. if DBS.ColumnOraType(p_Table, Key1)='NUMBER' then
  267. begin
  268. if (not Key1Exists) or Key1Null then
  269. result := GetSQLValue('select '+ DBS.OraUser +'.'+ DBS.SeqByTable(p_Table) +'.currval from dual')
  270. else
  271. result := q.ParamByName(Key1).AsInteger;
  272. end
  273. else
  274. result := -1;
  275. if p_Commit then
  276. OS.Commit;
  277. except
  278. on E:Exception do
  279. raise exception.create(
  280. 'TDbSaver.SaveRecord('+p_Table+',...): '+#13#10+E.Message);
  281. end;
  282. end;
  283. //==============================================================================
  284. procedure TDbSaver.SetState(p_Table: string; p_Id,p_Inst: integer; p_State: string);
  285. var
  286. q: TOraQuery;
  287. vKey2: string;
  288. begin
  289. if not DBS.ColumnExists(p_Table,'STATE') then
  290. raise exception.create('TDbSaver.SetState: ??????? '+p_Table+' ?? ????? ???? STATE');
  291. q:=TOraQuery.Create(nil);
  292. q.Session:=OS;
  293. try
  294. q.Sql.Text:=
  295. ' update '+DBS.OraUser+'.'+p_Table+' set state='''+p_State+''' where '+DBS.Key1(p_Table)+'='+IntToStr(p_Id);
  296. vKey2:=DBS.Key2(p_Table);
  297. if vKey2<>'' then
  298. q.Sql.Add(' and '+vKey2+'='+IntToStr(p_Inst));
  299. try
  300. q.ExecSql;
  301. except
  302. on E:Exception do
  303. raise exception.create('TDbSaver.SetState: '+E.Message);
  304. end;
  305. q.Close;
  306. finally
  307. q.Free;
  308. end;
  309. end;
  310. //==============================================================================
  311. function TDbSaver.GetSQLValue(p_Sql:string; p_Field:string=''):variant;
  312. var q: TOraQuery;
  313. begin
  314. q:=TOraQuery.Create(nil);
  315. q.Session := OS;
  316. try
  317. q.Sql.Text:=p_Sql;
  318. //q.Prepare;
  319. if q.Macros.FindMacro('user')<>nil then
  320. q.Macros.MacroByName('user').Value:=DBS.OraUser;
  321. q.Open;
  322. if q.IsEmpty then result:=null
  323. else if q.RecordCount>1 then raise exception.Create('TDbSaver.GetSqlValue: ???????? ????? ????? ??????')
  324. else
  325. if p_Field='' then result:=q.Fields[0].Value
  326. else result:=q.FieldByName(p_Field).Value;
  327. q.Close;
  328. finally
  329. q.Free;
  330. end;
  331. end;
  332. //==============================================================================
  333. procedure TDbSaver.ExecSql(p_Sql: string);
  334. var q:TOraQuery;
  335. begin
  336. q:=TOraQuery.Create(nil);
  337. q.Session:=OS;
  338. q.SQL.Text:=p_SQL;
  339. if q.Macros.FindMacro('user')<>nil then
  340. q.Macros.MacroByName('user').Value:=DBS.OraUser;
  341. try
  342. ExecSQL(q);
  343. q.Close;
  344. finally
  345. q.Free;
  346. end;
  347. end;
  348. //==============================================================================
  349. procedure TDbSaver.ExecSql(p_Sql: string; p_ParValues:array of variant);
  350. var q:TOraQuery;
  351. begin
  352. q:=TOraQuery.Create(nil);
  353. q.Session:=OS;
  354. q.SQL.Text:=p_SQL;
  355. DefineQParams(q,p_ParValues);
  356. if q.Macros.FindMacro('user')<>nil then
  357. q.Macros.MacroByName('user').Value:=DBS.OraUser;
  358. try
  359. ExecSQL(q);
  360. q.Close;
  361. finally
  362. q.Free;
  363. end;
  364. end;
  365. //==============================================================================
  366. procedure TDbSaver.ExecSql(p_Q: TOraQuery);
  367. var InsideTransaction:Boolean;
  368. begin
  369. InsideTransaction:=os.InTransaction;
  370. if not InsideTransaction then os.StartTransaction;
  371. p_Q.ExecSql;
  372. if not InsideTransaction then os.Commit;
  373. end;
  374. //==============================================================================
  375. procedure TDbSaver.DefineQParams(var p_Q:TOraQuery;p_ParValues:array of variant);
  376. var i:integer;
  377. begin
  378. if high(p_ParValues) mod 2 = 0 then
  379. Raise Exception.Create('TDbSaver.DefineQParams: ???????? ????? ????????? ? p_ParValues');
  380. for i:=0 to (high(p_ParValues) div 2) do
  381. p_Q.ParamByName(p_ParValues[i*2]).Value:=p_ParValues[i*2+1];
  382. end;
  383. //==============================================================================
  384. procedure TDbSaver.StartTransaction;
  385. begin
  386. if not os.InTransaction then
  387. os.StartTransaction;
  388. end;
  389. //==============================================================================
  390. procedure TDbSaver.Commit;
  391. begin
  392. if os.InTransaction then
  393. os.Commit;
  394. end;
  395. //==============================================================================
  396. procedure TDbSaver.Rollback;
  397. begin
  398. if os.InTransaction then
  399. os.Rollback;
  400. end;
  401. //==============================================================================
  402. constructor TSqlItem.Create(Collection: TCollection);
  403. begin
  404. inherited;
  405. Query := TOraQuery.Create(nil);
  406. end;
  407. {TSqlItems}
  408. constructor TSqlItems.Create;
  409. begin
  410. inherited Create(TSqlItem);
  411. end;
  412. function TSqlItems.GetItem(Index: Integer): TSqlItem;
  413. begin
  414. Result := TSqlItem(inherited Items[Index]);
  415. end;
  416. procedure TSqlItems.SetItem(Index: Integer; Value: TSqlItem);
  417. begin
  418. inherited SetItem(Index, TSqlItem(Value));
  419. end;
  420. function TSqlItems.Add(
  421. ATable, AFields: string; AKey1Null: boolean; AQuery: TOraQuery): TSqlItem;
  422. begin
  423. Result := FindItem(ATable, AFields, AKey1Null);
  424. if Result = nil then
  425. begin
  426. Result := TSqlItem(inherited Add);
  427. Result.Table := ATable;
  428. Result.Fields := AFields;
  429. Result.Key1Null := AKey1Null;
  430. Result.Query.Assign(AQuery);
  431. end;
  432. end;
  433. function TSqlItems.FindItem(ATable, AFields: string; AKey1Null: boolean): TSqlItem;
  434. var
  435. i: integer;
  436. begin
  437. Result := nil;
  438. for i := 0 to Count - 1 do
  439. begin
  440. if (Self.Items[i].Table = ATable) and (Self.Items[i].Fields = AFields)
  441. and (Self.Items[i].Key1Null = AKey1Null) then
  442. begin
  443. Result := Self.Items[i];
  444. Break;
  445. end;
  446. end;
  447. end;
  448. function TDbSaver.SetLocalSeparator(AVar: string): string;
  449. var
  450. s: string;
  451. begin
  452. s := AVar;
  453. case DecimalSeparator of
  454. '.': if pos(',', s) > 0 then s[pos(',', s)] := DecimalSeparator;
  455. ',': if pos('.', s) > 0 then s[pos('.', s)] := DecimalSeparator;
  456. end;
  457. Result := s;
  458. end;
  459. end.