sqldbwebdata.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. unit sqldbwebdata;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, fphttp, fpwebdata, DB, SQLDB;
  6. Type
  7. { TCustomSQLDBWebDataProvider }
  8. TNewIDEvent = Procedure(Sender : TObject; Out AID : String) of object;
  9. TGetParamTypeEvent = Procedure (Sender : TObject; Const ParamName,AValue : String; Var AType : TFieldtype) of object;
  10. TCustomSQLDBWebDataProvider = Class(TFPCustomWebDataProvider)
  11. private
  12. FIDFieldName: String;
  13. FOnGetNewID: TNewIDEvent;
  14. FSQLS : Array[0..3] of TStringList;
  15. FConnection: TSQLConnection;
  16. FQuery : TSQLQuery;
  17. FLastNewID : String;
  18. FOnGetParamType : TGetParamTypeEvent;
  19. procedure CheckDataset;
  20. function GetS(AIndex: integer): TStrings;
  21. procedure SetConnection(const AValue: TSQLConnection);
  22. procedure SetS(AIndex: integer; const AValue: TStrings);
  23. Protected
  24. function CreateQuery(AOwner: TComponent; ATransaction: TSQLTransaction; ASQL: Tstrings): TSQLQuery;
  25. function GetParamType(P: TParam; const AValue: String): TFieldType; virtual;
  26. procedure SetTypedParam(P: TParam; Const AValue: String); virtual;
  27. procedure ExecuteSQL(ASQL: TStrings; Msg: String=''; DoNewID : Boolean = False); virtual;
  28. procedure ApplySQLParams(AQuery: TSQLQuery; DoNewID : Boolean = False); virtual;
  29. Procedure SQLChanged(Sender : TObject); virtual;
  30. Procedure DoUpdate; override;
  31. Procedure DoDelete; override;
  32. Procedure DoInsert; override;
  33. Procedure DoApplyParams; override;
  34. Function GetDataset : TDataset; override;
  35. Function GetNewID : String;
  36. Function IDFieldValue : String; override;
  37. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  38. Property SelectSQL : TStrings Index 0 Read GetS Write SetS;
  39. Property UpdateSQL : TStrings Index 1 Read GetS Write SetS;
  40. Property DeleteSQL : TStrings Index 2 Read GetS Write SetS;
  41. Property InsertSQL : TStrings Index 3 Read GetS Write SetS;
  42. Property Connection : TSQLConnection Read FConnection Write SetConnection;
  43. Property OnGetNewID : TNewIDEvent Read FOnGetNewID Write FOnGetNewID;
  44. property OnGetParameterType : TGetParamTypeEvent Read FOnGetParamType Write FOnGetParamType;
  45. Public
  46. Constructor Create(AOwner : TComponent); override;
  47. Destructor Destroy; override;
  48. end;
  49. TSQLDBWebDataProvider = Class(TCustomSQLDBWebDataProvider)
  50. Published
  51. Property SelectSQL;
  52. Property UpdateSQL;
  53. Property DeleteSQL;
  54. Property InsertSQL;
  55. Property Connection;
  56. Property IDFieldName;
  57. Property OnGetNewID;
  58. property OnGetParameterType;
  59. Property Options;
  60. end;
  61. implementation
  62. { $define wmdebug}
  63. {$ifdef wmdebug}
  64. uses dbugintf;
  65. {$endif}
  66. resourcestring
  67. SErrNoSelectSQL = '%s: No select SQL statement provided.';
  68. SErrNoUpdateSQL = '%s: No update SQL statement provided.';
  69. SErrNoInsertSQL = '%s: No insert SQL statement provided.';
  70. SErrNoDeleteSQL = '%s: No delete SQL statement provided.';
  71. SErrUpdating = '%s: An error occurred during the update operation: %s';
  72. SErrDeleting = '%s: An error occurred during the delete operation: %s';
  73. SErrInserting = '%s: An error occurred during the insert operation: %s';
  74. SErrNoNewIDEvent = '%s : Cannot generate ID: No OnGetNewID event assigned.';
  75. { TCustomSQLDBWebDataProvider }
  76. function TCustomSQLDBWebDataProvider.GetS(AIndex: integer): TStrings;
  77. begin
  78. Result:=FSQLS[AIndex];
  79. end;
  80. procedure TCustomSQLDBWebDataProvider.SetConnection(const AValue: TSQLConnection
  81. );
  82. begin
  83. if (FConnection=AValue) then exit;
  84. If Assigned(FConnection) then
  85. FConnection.RemoveFreeNotification(Self);
  86. FConnection:=AValue;
  87. If Assigned(FConnection) then
  88. FConnection.FreeNotification(Self);
  89. end;
  90. procedure TCustomSQLDBWebDataProvider.SetS(AIndex: integer;
  91. const AValue: TStrings);
  92. begin
  93. FSQLS[AIndex].Assign(AValue);
  94. end;
  95. procedure TCustomSQLDBWebDataProvider.SQLChanged(Sender: TObject);
  96. begin
  97. If (Sender=SelectSQL) and Assigned(FQuery) then
  98. begin
  99. FQuery.Close;
  100. FQuery.SQL.Assign(SelectSQL);
  101. end;
  102. end;
  103. procedure TCustomSQLDBWebDataProvider.ExecuteSQL(ASQL : TStrings; Msg : String = ''; DoNewID : Boolean = False);
  104. Var
  105. Q : TSQLQuery;
  106. begin
  107. {$ifdef wmdebug}SendDebug('Entering TCustomSQLDBWebDataProvider.ExecuteSQL');{$endif}
  108. Q:=CreateQuery(Nil,Nil,ASQL);
  109. try
  110. Q.Transaction.Active:=True;
  111. try
  112. ApplySQLParams(Q,DoNewID);
  113. Q.ExecSQL;
  114. (Q.Transaction as TSQLTransaction).Commit;
  115. except
  116. On E : Exception do
  117. begin
  118. (Q.Transaction as TSQLTransaction).Rollback;
  119. If (Msg<>'') then
  120. E.Message:=Format(Msg,[Self.Name,E.Message]);
  121. Raise;
  122. end;
  123. end
  124. finally
  125. Q.Free;
  126. end;
  127. {$ifdef wmdebug}SendDebug('Exiting TCustomSQLDBWebDataProvider.ExecuteSQL');{$endif}
  128. end;
  129. procedure TCustomSQLDBWebDataProvider.DoUpdate;
  130. begin
  131. {$ifdef wmdebug}SendDebug('Entering TCustomSQLDBWebDataProvider.DoUpdate');{$endif}
  132. If (Trim(UpdateSQL.Text)='') then
  133. Raise EFPHTTPError.CreateFmt(SErrNoUpdateSQL,[Self.Name]);
  134. FLastNewID:='';
  135. ExecuteSQL(UpdateSQL,SErrUpdating);
  136. {$ifdef wmdebug}SendDebug('Exiting TCustomSQLDBWebDataProvider.DoUpdate');{$endif}
  137. end;
  138. procedure TCustomSQLDBWebDataProvider.DoDelete;
  139. begin
  140. {$ifdef wmdebug}SendDebug('Entering TCustomSQLDBWebDataProvider.DoDelete');{$endif}
  141. If (Trim(DeleteSQL.Text)='') then
  142. Raise EFPHTTPError.CreateFmt(SErrNoDeleteSQL,[Self.Name]);
  143. FLastNewID:='';
  144. ExecuteSQL(DeleteSQL,SErrDeleting);
  145. {$ifdef wmdebug}SendDebug('Exiting TCustomSQLDBWebDataProvider.DoDelete');{$endif}
  146. end;
  147. procedure TCustomSQLDBWebDataProvider.DoInsert;
  148. begin
  149. {$ifdef wmdebug}SendDebug('Entering TCustomSQLDBWebDataProvider.DoInsert');{$endif}
  150. If (Trim(InsertSQL.Text)='') then
  151. Raise EFPHTTPError.CreateFmt(SErrNoInsertSQL,[Self.Name]);
  152. FLastNewID:='';
  153. ExecuteSQL(InsertSQL,SErrInserting,(IDFieldName<>''));
  154. {$ifdef wmdebug}SendDebug('Exiting TCustomSQLDBWebDataProvider.DoInsert');{$endif}
  155. end;
  156. procedure TCustomSQLDBWebDataProvider.Notification(AComponent: TComponent;
  157. Operation: TOperation);
  158. begin
  159. inherited;
  160. If (Operation=opRemove) then
  161. begin
  162. If (AComponent=FQuery) then
  163. FQuery:=Nil
  164. else if (AComponent=FConnection) then
  165. FConnection:=Nil;
  166. end;
  167. end;
  168. Function TCustomSQLDBWebDataProvider.CreateQuery(AOwner : TComponent; ATransaction : TSQLTransaction; ASQL : Tstrings) : TSQLQuery;
  169. begin
  170. Result:=TSQLQuery.Create(AOwner);
  171. If (AOwner<>Self) then
  172. Result.FreeNotification(Self);
  173. Result.DataBase:=Connection;
  174. If ATransaction=Nil then
  175. begin
  176. ATransaction:=TSQLTransaction.Create(Result);
  177. ATransaction.DataBase:=Connection;
  178. end;
  179. Result.Transaction:=ATransaction;
  180. Result.SQL.Assign(ASQL);
  181. end;
  182. procedure TCustomSQLDBWebDataProvider.CheckDataset;
  183. begin
  184. {$ifdef wmdebug}SendDebug('Entering CheckDataset');{$endif}
  185. If (Trim(SelectSQL.Text)='') then
  186. Raise EFPHTTPError.CreateFmt(SErrNoSelectSQL,[Self.Name]);
  187. If (FQuery=Nil) then
  188. FQuery:=CreateQuery(Nil,Nil,SelectSQL)
  189. else if not FQuery.Active then
  190. FQuery.SQL.Assign(SelectSQL);
  191. {$ifdef wmdebug}SendDebug('Exiting CheckDataset');{$endif}
  192. end;
  193. Function TCustomSQLDBWebDataProvider.GetParamType(P : TParam; Const AValue : String) : TFieldType;
  194. begin
  195. Result:=ftunknown;
  196. If Assigned(FOnGetParamType) then
  197. FOnGetParamType(Self,P.Name,AValue,Result);
  198. end;
  199. procedure TCustomSQLDBWebDataProvider.SetTypedParam(P : TParam; Const AValue : String);
  200. Var
  201. I : Integer;
  202. Q : Int64;
  203. D : TDateTime;
  204. ft : TFieldType;
  205. F : Double;
  206. B : Boolean;
  207. C : Currency;
  208. begin
  209. ft:=GetParamtype(P,AValue);
  210. If ft<>ftUnknown then
  211. begin
  212. try
  213. case ft of
  214. ftInteger,
  215. ftword,
  216. ftsmallint : I:=StrToInt(AValue);
  217. ftDate : D:=StrToDate(AValue);
  218. ftDateTime,
  219. ftTimestamp : D:=StrToDateTime(AValue);
  220. ftBoolean : B:=StrToBool(AValue);
  221. ftTime : D:=StrToTime(AValue);
  222. ftLargeint : Q:=StrToInt64(AValue);
  223. ftCurrency : C:=StrToCurr(Avalue);
  224. else
  225. ft:=ftString
  226. end
  227. except
  228. ft:=ftUnknown
  229. end;
  230. end;
  231. If (ft=ftUnknown) and (Length(AValue)<30) then
  232. begin
  233. if TryStrToInt(Avalue,I) then
  234. ft:=ftInteger
  235. else if TryStrToInt64(Avalue,Q) then
  236. ft:=ftInteger
  237. else if (Pos(DateSeparator,AValue)<>0) then
  238. begin
  239. if (Pos(TimeSeparator,AValue)<>0) and TryStrToDateTime(Avalue,D) then
  240. ft:=ftDateTime
  241. else if TryStrToDate(Avalue,D) then
  242. ft:=ftDate
  243. end
  244. else If (Pos(TimeSeparator,AValue)<>0) and TryStrToTime(Avalue,D) then
  245. ft:=ftTime
  246. else if (Pos(DecimalSeparator,AValue)<>0) then
  247. begin
  248. if trystrtofloat(AValue,F) then
  249. ft:=ftFloat
  250. else if TryStrToCurr(Avalue,C) then
  251. ft:=ftCurrency
  252. end
  253. else if TryStrToBool(Avalue,B) then
  254. ft:=ftBoolean
  255. end;
  256. Case ft of
  257. ftInteger,
  258. ftword,
  259. ftsmallint : P.AsInteger:=I;
  260. ftBoolean : P.AsBoolean:=B;
  261. ftLargeInt : P.AsLargeInt:=Q;
  262. ftDate : P.AsDate:=D;
  263. ftDateTime,
  264. ftTimestamp : P.AsDateTime:=D;
  265. ftTime : P.AsTime:=D;
  266. ftFloat,
  267. ftBCD,
  268. ftFMTBCD : P.AsFloat:=F;
  269. ftCurrency : P.AsCurrency:=F;
  270. else
  271. P.AsString:=AValue;
  272. end;
  273. end;
  274. procedure TCustomSQLDBWebDataProvider.ApplySQLParams(AQuery : TSQLQuery; DoNewID : Boolean = False);
  275. var
  276. I: Integer;
  277. P : TParam;
  278. S : String;
  279. begin
  280. {$ifdef wmdebug}SendDebug('Entering ApplySQLPArams');{$endif}
  281. For I:=0 to AQuery.Params.Count-1 do
  282. begin
  283. P:=AQuery.Params[i];
  284. If (P.Name=IDFieldName) and DoNewID then
  285. SetTypedParam(P,GetNewID)
  286. else If Adaptor.TryFieldValue(P.Name,S) then
  287. SetTypedParam(P,S)
  288. else If Adaptor.TryParamValue(P.Name,S) then
  289. SetTypedParam(P,S)
  290. else
  291. P.Clear;
  292. end;
  293. {$ifdef wmdebug}SendDebug('Exiting ApplySQLPArams');{$endif}
  294. end;
  295. procedure TCustomSQLDBWebDataProvider.DoApplyParams;
  296. begin
  297. CheckDataset;
  298. ApplySQLParams(FQuery);
  299. end;
  300. function TCustomSQLDBWebDataProvider.GetDataset: TDataset;
  301. begin
  302. {$ifdef wmdebug}SendDebug('Get dataset: checking dataset');{$endif}
  303. CheckDataset;
  304. FLastNewID:='';
  305. Result:=FQuery;
  306. {$ifdef wmdebug}SendDebug('Get dataset: activating transaction');{$endif}
  307. If Not FQuery.Transaction.Active then
  308. FQuery.Transaction.Active:=True;
  309. {$ifdef wmdebug}SendDebug('Get dataset: done');{$endif}
  310. end;
  311. function TCustomSQLDBWebDataProvider.GetNewID: String;
  312. begin
  313. If Not Assigned(FOnGetNewID) then
  314. Raise EFPHTTPError.CreateFmt(SErrNoNewIDEvent,[Self.Name]);
  315. FOnGetNewID(Self,Result);
  316. FLastNewID:=Result;
  317. end;
  318. function TCustomSQLDBWebDataProvider.IDFieldValue: String;
  319. begin
  320. {$ifdef wmdebug}SendDebug('Entering IDFieldValue');{$endif}
  321. If (FLastNewID<>'') then
  322. Result:=FLastNewID
  323. else If (IDFieldName<>'') then
  324. begin
  325. If not Adaptor.TryParamValue(IDFieldName,Result) then
  326. If not Adaptor.TryFieldValue(IDFieldName,Result) then
  327. Result:=inherited IDFieldValue;
  328. end
  329. else
  330. Result:=inherited IDFieldValue;
  331. {$ifdef wmdebug}SendDebug('Exiting IDFieldValue : '+Result);{$endif}
  332. end;
  333. constructor TCustomSQLDBWebDataProvider.Create(AOwner: TComponent);
  334. Var
  335. I : Integer;
  336. L : TStringList;
  337. begin
  338. inherited Create(AOwner);
  339. For I:=0 to 3 do
  340. begin
  341. L:=TStringList.Create;
  342. L.OnChange:=@SQLChanged;
  343. FSQLS[i]:=L;
  344. end;
  345. end;
  346. destructor TCustomSQLDBWebDataProvider.Destroy;
  347. Var
  348. I: Integer;
  349. begin
  350. For I:=0 to 3 do
  351. FreeAndNil(FSQLS[i]);
  352. Connection:=Nil;
  353. FreeAndNil(FQuery);
  354. inherited Destroy;
  355. end;
  356. end.