sqldb.pp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930
  1. { $Id$
  2. Copyright (c) 2004 by Joost van der Sluis
  3. SQL database & dataset
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. unit sqldb;
  11. {$mode objfpc}
  12. {$H+}
  13. {$M+} // ### remove this!!!
  14. interface
  15. uses SysUtils, Classes, DB;
  16. type TSchemaType = (stNoSchema, stTables, stSysTables, stProcedures, stColumns, stProcedureParams, stIndexes, stPackages);
  17. type
  18. TSQLConnection = class;
  19. TSQLTransaction = class;
  20. TSQLQuery = class;
  21. TStatementType = (stNone, stSelect, stInsert, stUpdate, stDelete,
  22. stDDL, stGetSegment, stPutSegment, stExecProcedure,
  23. stStartTrans, stCommit, stRollback, stSelectForUpd);
  24. TSQLHandle = Class(TObject)
  25. protected
  26. StatementType : TStatementType;
  27. end;
  28. const
  29. StatementTokens : Array[TStatementType] of string = ('(none)', 'select',
  30. 'insert', 'update', 'delete',
  31. 'create', 'get', 'put', 'execute',
  32. 'start','commit','rollback', '?'
  33. );
  34. { TSQLConnection }
  35. type
  36. TSQLConnection = class (TDatabase)
  37. private
  38. FPassword : string;
  39. FTransaction : TSQLTransaction;
  40. FUserName : string;
  41. FHostName : string;
  42. FCharSet : string;
  43. FRole : String;
  44. procedure SetTransaction(Value : TSQLTransaction);
  45. protected
  46. function StrToStatementType(s : string) : TStatementType; virtual;
  47. procedure DoInternalConnect; override;
  48. procedure DoInternalDisconnect; override;
  49. function GetAsSQLText(Field : TField) : string; virtual;
  50. function GetHandle : pointer; virtual; abstract;
  51. Function AllocateCursorHandle : TSQLHandle; virtual; abstract;
  52. Function AllocateTransactionHandle : TSQLHandle; virtual; abstract;
  53. procedure FreeStatement(cursor : TSQLHandle); virtual; abstract;
  54. procedure PrepareStatement(cursor: TSQLHandle;ATransaction : TSQLTransaction;buf : string); virtual; abstract;
  55. procedure FreeFldBuffers(cursor : TSQLHandle); virtual; abstract;
  56. procedure Execute(cursor: TSQLHandle;atransaction:tSQLtransaction); virtual; abstract;
  57. procedure AddFieldDefs(cursor: TSQLHandle; FieldDefs : TfieldDefs); virtual; abstract;
  58. function Fetch(cursor : TSQLHandle) : boolean; virtual; abstract;
  59. function LoadField(cursor : TSQLHandle;FieldDef : TfieldDef;buffer : pointer) : boolean; virtual; abstract;
  60. function GetTransactionHandle(trans : TSQLHandle): pointer; virtual; abstract;
  61. function Commit(trans : TSQLHandle) : boolean; virtual; abstract;
  62. function RollBack(trans : TSQLHandle) : boolean; virtual; abstract;
  63. function StartdbTransaction(trans : TSQLHandle) : boolean; virtual; abstract;
  64. procedure CommitRetaining(trans : TSQLHandle); virtual; abstract;
  65. procedure RollBackRetaining(trans : TSQLHandle); virtual; abstract;
  66. procedure UpdateIndexDefs(var IndexDefs : TIndexDefs;TableName : string); virtual;
  67. function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; virtual;
  68. function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; virtual;abstract;
  69. public
  70. property Handle: Pointer read GetHandle;
  71. destructor Destroy; override;
  72. published
  73. property Password : string read FPassword write FPassword;
  74. property Transaction : TSQLTransaction read FTransaction write SetTransaction;
  75. property UserName : string read FUserName write FUserName;
  76. property CharSet : string read FCharSet write FCharSet;
  77. property HostName : string Read FHostName Write FHostName;
  78. property Connected;
  79. Property Role : String read FRole write FRole;
  80. property DatabaseName;
  81. property KeepConnection;
  82. property LoginPrompt;
  83. property Params;
  84. property OnLogin;
  85. end;
  86. { TSQLTransaction }
  87. TCommitRollbackAction = (caNone, caCommit, caCommitRetaining, caRollback,
  88. caRollbackRetaining);
  89. TSQLTransaction = class (TDBTransaction)
  90. private
  91. FTrans : TSQLHandle;
  92. FAction : TCommitRollbackAction;
  93. protected
  94. function GetHandle : Pointer; virtual;
  95. public
  96. procedure Commit; virtual;
  97. procedure CommitRetaining; virtual;
  98. procedure Rollback; virtual;
  99. procedure RollbackRetaining; virtual;
  100. procedure StartTransaction; override;
  101. constructor Create(AOwner : TComponent); override;
  102. destructor Destroy; override;
  103. property Handle: Pointer read GetHandle;
  104. procedure EndTransaction; override;
  105. published
  106. property Action : TCommitRollbackAction read FAction write FAction;
  107. property Database;
  108. end;
  109. { TSQLQuery }
  110. TSQLQuery = class (Tbufdataset)
  111. private
  112. FCursor : TSQLHandle;
  113. FUpdateable : boolean;
  114. FTableName : string;
  115. FSQL : TStrings;
  116. FIsEOF : boolean;
  117. FLoadingFieldDefs : boolean;
  118. FIndexDefs : TIndexDefs;
  119. FReadOnly : boolean;
  120. FUpdateMode : TUpdateMode;
  121. FusePrimaryKeyAsKey : Boolean;
  122. // FSchemaInfo : TSchemaInfo;
  123. procedure FreeStatement;
  124. procedure PrepareStatement;
  125. procedure FreeFldBuffers;
  126. procedure InitUpdates(SQL : string);
  127. function GetIndexDefs : TIndexDefs;
  128. procedure SetIndexDefs(AValue : TIndexDefs);
  129. procedure SetReadOnly(AValue : Boolean);
  130. procedure SetUsePrimaryKeyAsKey(AValue : Boolean);
  131. procedure SetUpdateMode(AValue : TUpdateMode);
  132. procedure Execute;
  133. protected
  134. // abstract & virtual methods of TBufDataset
  135. function Fetch : boolean; override;
  136. function LoadField(FieldDef : TFieldDef;buffer : pointer) : boolean; override;
  137. // abstract & virtual methods of TDataset
  138. procedure UpdateIndexDefs; override;
  139. procedure SetDatabase(Value : TDatabase); override;
  140. procedure InternalAddRecord(Buffer: Pointer; AAppend: Boolean); override;
  141. procedure InternalClose; override;
  142. procedure InternalHandleException; override;
  143. procedure InternalInitFieldDefs; override;
  144. procedure InternalOpen; override;
  145. function GetCanModify: Boolean; override;
  146. Function GetSQLStatementType(SQL : String) : TStatementType; virtual;
  147. function ApplyRecUpdate(UpdateKind : TUpdateKind) : boolean; override;
  148. public
  149. procedure ExecSQL; virtual;
  150. constructor Create(AOwner : TComponent); override;
  151. destructor Destroy; override;
  152. procedure SetSchemaInfo( SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string); virtual;
  153. function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; override;
  154. published
  155. // redeclared data set properties
  156. property Active;
  157. // property Filter;
  158. // property Filtered;
  159. // property FilterOptions;
  160. property BeforeOpen;
  161. property AfterOpen;
  162. property BeforeClose;
  163. property AfterClose;
  164. property BeforeInsert;
  165. property AfterInsert;
  166. property BeforeEdit;
  167. property AfterEdit;
  168. property BeforePost;
  169. property AfterPost;
  170. property BeforeCancel;
  171. property AfterCancel;
  172. property BeforeDelete;
  173. property AfterDelete;
  174. property BeforeScroll;
  175. property AfterScroll;
  176. property OnCalcFields;
  177. property OnDeleteError;
  178. property OnEditError;
  179. property OnFilterRecord;
  180. property OnNewRecord;
  181. property OnPostError;
  182. property AutoCalcFields;
  183. property Database;
  184. property Transaction;
  185. property ReadOnly : Boolean read FReadOnly write SetReadOnly;
  186. property SQL : TStrings read FSQL write FSQL;
  187. property IndexDefs : TIndexDefs read GetIndexDefs;
  188. property UpdateMode : TUpdateMode read FUpdateMode write SetUpdateMode;
  189. property UsePrimaryKeyAsKey : boolean read FUsePrimaryKeyAsKey write SetUsePrimaryKeyAsKey;
  190. // property SchemaInfo : TSchemaInfo read FSchemaInfo default stNoSchema;
  191. end;
  192. implementation
  193. uses dbconst;
  194. { TSQLConnection }
  195. function TSQLConnection.StrToStatementType(s : string) : TStatementType;
  196. var T : TStatementType;
  197. begin
  198. S:=Lowercase(s);
  199. For t:=stselect to strollback do
  200. if (S=StatementTokens[t]) then
  201. Exit(t);
  202. end;
  203. procedure TSQLConnection.SetTransaction(Value : TSQLTransaction);
  204. begin
  205. if FTransaction = nil then
  206. begin
  207. FTransaction := Value;
  208. if Assigned(FTransaction) then
  209. FTransaction.Database := Self;
  210. exit;
  211. end;
  212. if (Value <> FTransaction) and (Value <> nil) then
  213. if (not FTransaction.Active) then
  214. begin
  215. FTransaction := Value;
  216. FTransaction.Database := Self;
  217. end
  218. else
  219. DatabaseError(SErrAssTransaction);
  220. end;
  221. procedure TSQLConnection.UpdateIndexDefs(var IndexDefs : TIndexDefs;TableName : string);
  222. begin
  223. // Empty abstract
  224. end;
  225. procedure TSQLConnection.DoInternalConnect;
  226. begin
  227. // Empty abstract
  228. end;
  229. procedure TSQLConnection.DoInternalDisconnect;
  230. begin
  231. end;
  232. destructor TSQLConnection.Destroy;
  233. begin
  234. inherited Destroy;
  235. end;
  236. function TSQLConnection.GetAsSQLText(Field : TField) : string;
  237. begin
  238. if not assigned(field) then Result := 'Null'
  239. else case field.DataType of
  240. ftString : Result := '''' + field.asstring + '''';
  241. ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Field.AsDateTime) + '''';
  242. ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:mm:ss',Field.AsDateTime) + ''''
  243. else
  244. Result := field.asstring;
  245. end; {case}
  246. end;
  247. function TSQLConnection.GetSchemaInfoSQL( SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string;
  248. begin
  249. DatabaseError(SMetadataUnavailable);
  250. end;
  251. { TSQLTransaction }
  252. procedure TSQLTransaction.EndTransaction;
  253. begin
  254. rollback;
  255. end;
  256. function TSQLTransaction.GetHandle: pointer;
  257. begin
  258. Result := (Database as tsqlconnection).GetTransactionHandle(FTrans);
  259. end;
  260. procedure TSQLTransaction.Commit;
  261. begin
  262. if active then
  263. begin
  264. closedatasets;
  265. if (Database as tsqlconnection).commit(FTrans) then
  266. begin
  267. closeTrans;
  268. FreeAndNil(FTrans);
  269. end;
  270. end;
  271. end;
  272. procedure TSQLTransaction.CommitRetaining;
  273. begin
  274. if active then
  275. (Database as tsqlconnection).commitRetaining(FTrans);
  276. end;
  277. procedure TSQLTransaction.Rollback;
  278. begin
  279. if active then
  280. begin
  281. closedatasets;
  282. if (Database as tsqlconnection).RollBack(FTrans) then
  283. begin
  284. CloseTrans;
  285. FreeAndNil(FTrans);
  286. end;
  287. end;
  288. end;
  289. procedure TSQLTransaction.RollbackRetaining;
  290. begin
  291. if active then
  292. (Database as tsqlconnection).RollBackRetaining(FTrans);
  293. end;
  294. procedure TSQLTransaction.StartTransaction;
  295. var db : TSQLConnection;
  296. begin
  297. if Active then
  298. DatabaseError(SErrTransAlreadyActive);
  299. db := (Database as tsqlconnection);
  300. if Db = nil then
  301. DatabaseError(SErrDatabasenAssigned);
  302. if not Db.Connected then
  303. Db.Open;
  304. if not assigned(FTrans) then FTrans := Db.AllocateTransactionHandle;
  305. if Db.StartdbTransaction(FTrans) then OpenTrans;
  306. end;
  307. constructor TSQLTransaction.Create(AOwner : TComponent);
  308. begin
  309. inherited Create(AOwner);
  310. end;
  311. destructor TSQLTransaction.Destroy;
  312. begin
  313. Rollback;
  314. inherited Destroy;
  315. end;
  316. { TSQLQuery }
  317. procedure TSQLQuery.SetDatabase(Value : TDatabase);
  318. var db : tsqlconnection;
  319. begin
  320. if (Database <> Value) then
  321. begin
  322. db := value as tsqlconnection;
  323. inherited setdatabase(value);
  324. if assigned(value) and (Transaction = nil) and (Assigned(db.Transaction)) then
  325. transaction := Db.Transaction;
  326. end;
  327. end;
  328. procedure TSQLQuery.FreeStatement;
  329. begin
  330. if assigned(FCursor) then
  331. begin
  332. (Database as tsqlconnection).FreeStatement(FCursor);
  333. // FreeAndNil(FCursor);
  334. end;
  335. end;
  336. procedure TSQLQuery.PrepareStatement;
  337. var
  338. Buf : string;
  339. x : integer;
  340. db : tsqlconnection;
  341. sqltr : tsqltransaction;
  342. begin
  343. db := (Database as tsqlconnection);
  344. if not assigned(Db) then
  345. DatabaseError(SErrDatabasenAssigned);
  346. if not Db.Connected then
  347. db.Open;
  348. if not assigned(Transaction) then
  349. DatabaseError(SErrTransactionnSet);
  350. sqltr := (transaction as tsqltransaction);
  351. if not sqltr.Active then sqltr.StartTransaction;
  352. if assigned(fcursor) then FreeAndNil(fcursor);
  353. FCursor := Db.AllocateCursorHandle;
  354. Buf := '';
  355. for x := 0 to FSQL.Count - 1 do
  356. Buf := Buf + FSQL[x] + ' '#10; // multiline SQl. Provides line info in sqlErrors and allows single line comments
  357. if Buf='' then
  358. begin
  359. DatabaseError(SErrNoStatement);
  360. exit;
  361. end;
  362. FCursor.StatementType := GetSQLStatementType(buf);
  363. if (FCursor.StatementType = stSelect) and not ReadOnly then InitUpdates(Buf);
  364. Db.PrepareStatement(Fcursor,sqltr,buf);
  365. end;
  366. procedure TSQLQuery.FreeFldBuffers;
  367. begin
  368. if assigned(FCursor) then (Database as tsqlconnection).FreeFldBuffers(FCursor);
  369. end;
  370. function TSQLQuery.Fetch : boolean;
  371. begin
  372. if not (Fcursor.StatementType in [stSelect]) then
  373. Exit;
  374. if not FIsEof then FIsEOF := not (Database as tsqlconnection).Fetch(Fcursor);
  375. Result := not FIsEOF;
  376. end;
  377. procedure TSQLQuery.Execute;
  378. begin
  379. (Database as tsqlconnection).execute(Fcursor,Transaction as tsqltransaction);
  380. end;
  381. function TSQLQuery.LoadField(FieldDef : TFieldDef;buffer : pointer) : boolean;
  382. begin
  383. result := (Database as tSQLConnection).LoadField(FCursor,FieldDef,buffer)
  384. end;
  385. procedure TSQLQuery.InternalAddRecord(Buffer: Pointer; AAppend: Boolean);
  386. begin
  387. // not implemented - sql dataset
  388. end;
  389. procedure TSQLQuery.InternalClose;
  390. begin
  391. FreeFldBuffers;
  392. FreeStatement;
  393. if DefaultFields then
  394. DestroyFields;
  395. FIsEOF := False;
  396. // FRecordSize := 0;
  397. inherited internalclose;
  398. end;
  399. procedure TSQLQuery.InternalHandleException;
  400. begin
  401. end;
  402. procedure TSQLQuery.InternalInitFieldDefs;
  403. begin
  404. if FLoadingFieldDefs then
  405. Exit;
  406. FLoadingFieldDefs := True;
  407. try
  408. FieldDefs.Clear;
  409. (Database as tsqlconnection).AddFieldDefs(fcursor,FieldDefs);
  410. finally
  411. FLoadingFieldDefs := False;
  412. end;
  413. end;
  414. procedure TSQLQuery.InitUpdates(SQL : string);
  415. Var
  416. L : Integer;
  417. P,PP : PChar;
  418. PS: PChar;
  419. S : string;
  420. function GetStatement(var StartP : PChar) : PChar;
  421. var p : pchar;
  422. Cmt, Stm : boolean;
  423. begin
  424. p := StartP;
  425. Cmt := false;
  426. Stm := False;
  427. While ((P-PP)<L) do
  428. begin
  429. if Cmt then
  430. begin
  431. end
  432. else if (p^ in [',',' ','(',')',#13,#10,#9]) then
  433. begin
  434. if stm then break;
  435. end
  436. else if not stm then
  437. begin
  438. StartP := p;
  439. stm := true;
  440. end;
  441. inc(p);
  442. end;
  443. Result := P;
  444. end;
  445. begin
  446. FUpdateable := False;
  447. L:=Length(SQL);
  448. PP:=Pchar(SQL);
  449. P := pp;
  450. PS := pp;
  451. // select-keyword
  452. P := GetStatement(PS);
  453. Setlength(S,P-PS);
  454. Move(PS^,S[1],(P-PS));
  455. S:=Lowercase(S);
  456. if (S) <> 'select' then exit;
  457. // select-part
  458. While ((P-PP)<L) and (S <> 'from') do
  459. begin
  460. repeat
  461. PS := P;
  462. P := GetStatement(PS);
  463. until P^ <> ',';
  464. Setlength(S,P-PS);
  465. Move(PS^,S[1],(P-PS));
  466. S:=Lowercase(S);
  467. end;
  468. // from-part
  469. PS := P;
  470. P := GetStatement(PS);
  471. Setlength(FTableName,P-PS);
  472. Move(PS^,FTableName[1],(P-PS));
  473. While ((P-PP)<L) do
  474. begin
  475. PS := P;
  476. P := GetStatement(PS);
  477. if P^ = ',' then exit; // select-statements from more then one table are not updateable
  478. Setlength(S,P-PS);
  479. Move(PS^,S[1],(P-PS));
  480. S:=Lowercase(S);
  481. if (s = 'where') or (s='order') then break;
  482. end;
  483. FUpdateable := True;
  484. end;
  485. procedure TSQLQuery.InternalOpen;
  486. var tel : integer;
  487. f : TField;
  488. s : string;
  489. begin
  490. try
  491. PrepareStatement;
  492. if Fcursor.StatementType in [stSelect] then
  493. begin
  494. Execute;
  495. InternalInitFieldDefs;
  496. if DefaultFields then
  497. begin
  498. CreateFields;
  499. if FUpdateable and FusePrimaryKeyAsKey then
  500. begin
  501. UpdateIndexDefs;
  502. for tel := 0 to indexdefs.count-1 do {with indexdefs[tel] do}
  503. begin
  504. if ixPrimary in indexdefs[tel].options then
  505. begin
  506. // Todo: If there is more then one field in the key, that must be parsed
  507. s := indexdefs[tel].fields;
  508. F := Findfield(s);
  509. if F <> nil then
  510. F.ProviderFlags := F.ProviderFlags + [pfInKey];
  511. end;
  512. end;
  513. end;
  514. end;
  515. end
  516. else
  517. DatabaseError(SErrNoSelectStatement,Self);
  518. except
  519. on E:Exception do
  520. raise;
  521. end;
  522. inherited InternalOpen;
  523. end;
  524. // public part
  525. procedure TSQLQuery.ExecSQL;
  526. begin
  527. try
  528. PrepareStatement;
  529. Execute;
  530. finally
  531. FreeStatement;
  532. end;
  533. end;
  534. constructor TSQLQuery.Create(AOwner : TComponent);
  535. begin
  536. inherited Create(AOwner);
  537. FSQL := TStringList.Create;
  538. FIndexDefs := TIndexDefs.Create(Self);
  539. FReadOnly := false;
  540. // Delphi has upWhereAll as default, but since strings and oldvalue's don't work yet
  541. // (variants) set it to upWhereKeyOnly
  542. FUpdateMode := upWhereKeyOnly;
  543. FUsePrimaryKeyAsKey := True;
  544. end;
  545. destructor TSQLQuery.Destroy;
  546. begin
  547. if Active then Close;
  548. // if assigned(FCursor) then FCursor.destroy;
  549. FreeAndNil(FSQL);
  550. inherited Destroy;
  551. end;
  552. Function TSQLQuery.GetSQLStatementType(SQL : String) : TStatementType;
  553. Var
  554. L : Integer;
  555. cmt : boolean;
  556. P,PE,PP : PChar;
  557. S : string;
  558. begin
  559. Result:=stNone;
  560. L:=Length(SQL);
  561. If (L=0) then
  562. Exit;
  563. P:=Pchar(SQL);
  564. PP:=P;
  565. Cmt:=False;
  566. While ((P-PP)<L) do
  567. begin
  568. if not (P^ in [' ',#13,#10,#9]) then
  569. begin
  570. if not Cmt then
  571. begin
  572. // Check for comment.
  573. Cmt:=(P^='/') and (((P-PP)<=L) and (P[1]='*'));
  574. if not (cmt) then
  575. Break;
  576. end
  577. else
  578. begin
  579. // Check for end of comment.
  580. Cmt:=Not( (P^='*') and (((P-PP)<=L) and (P[1]='/')) );
  581. If not cmt then
  582. Inc(p);
  583. end;
  584. end;
  585. inc(P);
  586. end;
  587. PE:=P+1;
  588. While ((PE-PP)<L) and (PE^ in ['0'..'9','a'..'z','A'..'Z','_']) do
  589. Inc(PE);
  590. Setlength(S,PE-P);
  591. Move(P^,S[1],(PE-P));
  592. result := (DataBase as TSQLConnection).StrToStatementType(s);
  593. end;
  594. procedure TSQLQuery.SetReadOnly(AValue : Boolean);
  595. begin
  596. if not Active then FReadOnly := AValue
  597. else
  598. begin
  599. // Just temporary, this should be possible in the future
  600. DatabaseError(SActiveDataset);
  601. end;
  602. end;
  603. procedure TSQLQuery.SetUsePrimaryKeyAsKey(AValue : Boolean);
  604. begin
  605. if not Active then FusePrimaryKeyAsKey := AValue
  606. else
  607. begin
  608. // Just temporary, this should be possible in the future
  609. DatabaseError(SActiveDataset);
  610. end;
  611. end;
  612. Procedure TSQLQuery.UpdateIndexDefs;
  613. begin
  614. if assigned(DataBase) then
  615. (DataBase as TSQLConnection).UpdateIndexDefs(FIndexDefs,FTableName);
  616. end;
  617. function TSQLQuery.ApplyRecUpdate(UpdateKind : TUpdateKind) : boolean;
  618. var
  619. sql_tables : string;
  620. s : string;
  621. procedure UpdateWherePart(var sql_where : string;x : integer);
  622. begin
  623. if (pfInKey in Fields[x].ProviderFlags) or
  624. ((FUpdateMode = upWhereAll) and (pfInWhere in Fields[x].ProviderFlags)) or
  625. ((FUpdateMode = UpWhereChanged) and (pfInWhere in Fields[x].ProviderFlags) and (fields[x].value <> fields[x].oldvalue)) then
  626. begin
  627. // This should be converted to something like GetAsSQLText, but better wait until variants (oldvalue) are working for strings
  628. s := fields[x].oldvalue; // This directly int the line below raises a variant-error
  629. sql_where := sql_where + '(' + fields[x].FieldName + '=' + s + ') and ';
  630. end;
  631. end;
  632. function ModifyRecQuery : string;
  633. var x : integer;
  634. sql_set : string;
  635. sql_where : string;
  636. begin
  637. sql_tables := FTableName;
  638. sql_set := '';
  639. sql_where := '';
  640. for x := 0 to Fields.Count -1 do
  641. begin
  642. UpdateWherePart(sql_where,x);
  643. if (pfInUpdate in Fields[x].ProviderFlags) then
  644. if fields[x].IsNull then // check for null
  645. sql_set := sql_set + fields[x].FieldName + '=' + (Database as TSQLConnection).GetAsSQLText(nil) + ','
  646. else
  647. sql_set := sql_set + fields[x].FieldName + '=' + (Database as TSQLConnection).GetAsSQLText(fields[x]) + ',';
  648. end;
  649. setlength(sql_set,length(sql_set)-1);
  650. setlength(sql_where,length(sql_where)-5);
  651. result := 'update ' + sql_tables + ' set ' + sql_set + ' where ' + sql_where;
  652. end;
  653. function InsertRecQuery : string;
  654. var x : integer;
  655. sql_fields : string;
  656. sql_values : string;
  657. begin
  658. sql_tables := FTableName;
  659. sql_fields := '';
  660. sql_values := '';
  661. for x := 0 to Fields.Count -1 do
  662. begin
  663. if not fields[x].IsNull then
  664. begin
  665. sql_fields := sql_fields + fields[x].DisplayName + ',';
  666. sql_values := sql_values + (Database as TSQLConnection).GetAsSQLText(fields[x]) + ',';
  667. end;
  668. end;
  669. setlength(sql_fields,length(sql_fields)-1);
  670. setlength(sql_values,length(sql_values)-1);
  671. result := 'insert into ' + sql_tables + ' (' + sql_fields + ') values (' + sql_values + ')';
  672. end;
  673. function DeleteRecQuery : string;
  674. var x : integer;
  675. sql_where : string;
  676. begin
  677. sql_tables := FTableName;
  678. sql_where := '';
  679. for x := 0 to Fields.Count -1 do
  680. UpdateWherePart(sql_where,x);
  681. setlength(sql_where,length(sql_where)-5);
  682. result := 'delete from ' + sql_tables + ' where ' + sql_where;
  683. end;
  684. begin
  685. Result := False;
  686. with tsqlquery.Create(nil) do
  687. begin
  688. DataBase := self.Database;
  689. transaction := self.transaction;
  690. sql.clear;
  691. case UpdateKind of
  692. ukModify : s := ModifyRecQuery;
  693. ukInsert : s := InsertRecQuery;
  694. ukDelete : s := DeleteRecQuery;
  695. end; {case}
  696. sql.add(s);
  697. ExecSQL;
  698. Result := true;
  699. Free;
  700. end;
  701. end;
  702. Function TSQLQuery.GetCanModify: Boolean;
  703. begin
  704. if FCursor.StatementType = stSelect then
  705. Result:= Active and FUpdateable and (not FReadOnly)
  706. else
  707. Result := False;
  708. end;
  709. function TSQLQuery.GetIndexDefs : TIndexDefs;
  710. begin
  711. Result := FIndexDefs;
  712. end;
  713. procedure TSQLQuery.SetIndexDefs(AValue : TIndexDefs);
  714. begin
  715. FIndexDefs := AValue;
  716. end;
  717. procedure TSQLQuery.SetUpdateMode(AValue : TUpdateMode);
  718. begin
  719. FUpdateMode := AValue;
  720. end;
  721. procedure TSQLQuery.SetSchemaInfo( SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string);
  722. begin
  723. SQL.Clear;
  724. SQL.Add((DataBase as tsqlconnection).GetSchemaInfoSQL(SchemaType, SchemaObjectName, SchemaPattern));
  725. end;
  726. function TSQLQuery.CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream;
  727. begin
  728. result := (DataBase as tsqlconnection).CreateBlobStream(Field, Mode);
  729. end;
  730. end.
  731. {
  732. $Log$
  733. Revision 1.15 2005-03-23 08:17:51 michael
  734. + Several patches from Jose A. Rimon
  735. # Prevents "field not found" error, when use a query without the primary key
  736. Set SQLlen of different data types
  737. Use AliasName instead of SQLname to avoid "duplicate field name" error, for
  738. example when using "coalesce" more than once
  739. use SQLScale in ftLargeInt to get actual values
  740. Send query to server with different lines. Provides line info in sqlErrors
  741. and allows single line comments
  742. Revision 1.14 2005/02/14 17:13:12 peter
  743. * truncate log
  744. Revision 1.13 2005/02/07 11:23:41 joost
  745. - implemented TSQLQuery.SetSchemaInfo
  746. - added support for delete and insert
  747. Revision 1.12 2005/01/24 10:52:43 michael
  748. * Patch from Joost van der Sluis
  749. - Made it possible to run 'show' queries for MySQL
  750. Revision 1.11 2005/01/12 10:30:33 michael
  751. * Patch from Joost Van der Sluis:
  752. - implemented TSQLQuery.UpdateIndexDefs
  753. - implemented TSQLQuery.ReadOnly
  754. - implemented TSQLQuery.IndexDefs
  755. - implemented TSQLQuery.UpdateMode
  756. - implemented TSQLQuery.UsePrimaryKeyAsKey (Set pfInKey in the
  757. providerflags
  758. of fields that are in the primary index of the underlying table)
  759. - Added support for updates on date-fields
  760. }