sqldb.pp 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883
  1. {
  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, bufdataset;
  16. type TSchemaType = (stNoSchema, stTables, stSysTables, stProcedures, stColumns, stProcedureParams, stIndexes, stPackages);
  17. TConnOption = (sqSupportParams,sqEscapeSlash,sqEscapeRepeat);
  18. TConnOptions= set of TConnOption;
  19. type
  20. TSQLConnection = class;
  21. TSQLTransaction = class;
  22. TCustomSQLQuery = class;
  23. TSQLQuery = class;
  24. TSQLScript = class;
  25. TStatementType = (stNone, stSelect, stInsert, stUpdate, stDelete,
  26. stDDL, stGetSegment, stPutSegment, stExecProcedure,
  27. stStartTrans, stCommit, stRollback, stSelectForUpd);
  28. TSQLHandle = Class(TObject)
  29. end;
  30. { TSQLCursor }
  31. TSQLCursor = Class(TSQLHandle)
  32. public
  33. FPrepared : Boolean;
  34. FInitFieldDef : Boolean;
  35. FStatementType : TStatementType;
  36. end;
  37. const
  38. StatementTokens : Array[TStatementType] of string = ('(none)', 'select',
  39. 'insert', 'update', 'delete',
  40. 'create', 'get', 'put', 'execute',
  41. 'start','commit','rollback', '?'
  42. );
  43. { TSQLConnection }
  44. type
  45. { TSQLConnection }
  46. TSQLConnection = class (TDatabase)
  47. private
  48. FPassword : string;
  49. FTransaction : TSQLTransaction;
  50. FUserName : string;
  51. FHostName : string;
  52. FCharSet : string;
  53. FRole : String;
  54. procedure GetDBInfo(const SchemaType : TSchemaType; const SchemaObjectName, ReturnField : string; List: TStrings);
  55. protected
  56. FConnOptions : TConnOptions;
  57. procedure SetTransaction(Value : TSQLTransaction);virtual;
  58. function StrToStatementType(s : string) : TStatementType; virtual;
  59. procedure DoInternalConnect; override;
  60. procedure DoInternalDisconnect; override;
  61. function GetAsSQLText(Field : TField) : string; overload; virtual;
  62. function GetAsSQLText(Param : TParam) : string; overload; virtual;
  63. function GetHandle : pointer; virtual; virtual;
  64. Function AllocateCursorHandle : TSQLCursor; virtual; abstract;
  65. Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); virtual; abstract;
  66. Function AllocateTransactionHandle : TSQLHandle; virtual; abstract;
  67. procedure PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams); virtual; abstract;
  68. procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams); virtual; abstract;
  69. function Fetch(cursor : TSQLCursor) : boolean; virtual; abstract;
  70. procedure AddFieldDefs(cursor: TSQLCursor; FieldDefs : TfieldDefs); virtual; abstract;
  71. procedure UnPrepareStatement(cursor : TSQLCursor); virtual; abstract;
  72. procedure FreeFldBuffers(cursor : TSQLCursor); virtual;
  73. function LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; virtual; abstract;
  74. function GetTransactionHandle(trans : TSQLHandle): pointer; virtual; abstract;
  75. function Commit(trans : TSQLHandle) : boolean; virtual; abstract;
  76. function RollBack(trans : TSQLHandle) : boolean; virtual; abstract;
  77. function StartdbTransaction(trans : TSQLHandle; aParams : string) : boolean; virtual; abstract;
  78. procedure CommitRetaining(trans : TSQLHandle); virtual; abstract;
  79. procedure RollBackRetaining(trans : TSQLHandle); virtual; abstract;
  80. procedure UpdateIndexDefs(var IndexDefs : TIndexDefs;TableName : string); virtual;
  81. function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; virtual;
  82. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction : TSQLTransaction); virtual; abstract;
  83. public
  84. property Handle: Pointer read GetHandle;
  85. destructor Destroy; override;
  86. procedure StartTransaction; override;
  87. procedure EndTransaction; override;
  88. property ConnOptions: TConnOptions read FConnOptions;
  89. procedure ExecuteDirect(SQL : String); overload; virtual;
  90. procedure ExecuteDirect(SQL : String; ATransaction : TSQLTransaction); overload; virtual;
  91. procedure GetTableNames(List : TStrings; SystemTables : Boolean = false); virtual;
  92. procedure GetProcedureNames(List : TStrings); virtual;
  93. procedure GetFieldNames(const TableName : string; List : TStrings); virtual;
  94. procedure CreateDB; virtual;
  95. procedure DropDB; virtual;
  96. published
  97. property Password : string read FPassword write FPassword;
  98. property Transaction : TSQLTransaction read FTransaction write SetTransaction;
  99. property UserName : string read FUserName write FUserName;
  100. property CharSet : string read FCharSet write FCharSet;
  101. property HostName : string Read FHostName Write FHostName;
  102. property Connected;
  103. Property Role : String read FRole write FRole;
  104. property DatabaseName;
  105. property KeepConnection;
  106. property LoginPrompt;
  107. property Params;
  108. property OnLogin;
  109. end;
  110. { TSQLTransaction }
  111. TCommitRollbackAction = (caNone, caCommit, caCommitRetaining, caRollback,
  112. caRollbackRetaining);
  113. TSQLTransaction = class (TDBTransaction)
  114. private
  115. FTrans : TSQLHandle;
  116. FAction : TCommitRollbackAction;
  117. FParams : TStringList;
  118. protected
  119. function GetHandle : Pointer; virtual;
  120. Procedure SetDatabase (Value : TDatabase); override;
  121. public
  122. procedure Commit; virtual;
  123. procedure CommitRetaining; virtual;
  124. procedure Rollback; virtual;
  125. procedure RollbackRetaining; virtual;
  126. procedure StartTransaction; override;
  127. constructor Create(AOwner : TComponent); override;
  128. destructor Destroy; override;
  129. property Handle: Pointer read GetHandle;
  130. procedure EndTransaction; override;
  131. published
  132. property Action : TCommitRollbackAction read FAction write FAction;
  133. property Database;
  134. property Params : TStringList read FParams write FParams;
  135. end;
  136. { TCustomSQLQuery }
  137. TCustomSQLQuery = class (Tbufdataset)
  138. private
  139. FCursor : TSQLCursor;
  140. FUpdateable : boolean;
  141. FTableName : string;
  142. FSQL : TStringList;
  143. FUpdateSQL,
  144. FInsertSQL,
  145. FDeleteSQL : TStringList;
  146. FIsEOF : boolean;
  147. FLoadingFieldDefs : boolean;
  148. FIndexDefs : TIndexDefs;
  149. FReadOnly : boolean;
  150. FUpdateMode : TUpdateMode;
  151. FParams : TParams;
  152. FusePrimaryKeyAsKey : Boolean;
  153. FSQLBuf : String;
  154. FFromPart : String;
  155. FWhereStartPos : integer;
  156. FWhereStopPos : integer;
  157. FParseSQL : boolean;
  158. FMasterLink : TMasterParamsDatalink;
  159. // FSchemaInfo : TSchemaInfo;
  160. FServerFilterText : string;
  161. FServerFiltered : Boolean;
  162. FUpdateQry,
  163. FDeleteQry,
  164. FInsertQry : TCustomSQLQuery;
  165. procedure FreeFldBuffers;
  166. procedure InitUpdates(ASQL : string);
  167. function GetIndexDefs : TIndexDefs;
  168. function GetStatementType : TStatementType;
  169. procedure SetIndexDefs(AValue : TIndexDefs);
  170. procedure SetReadOnly(AValue : Boolean);
  171. procedure SetParseSQL(AValue : Boolean);
  172. procedure SetUsePrimaryKeyAsKey(AValue : Boolean);
  173. procedure SetUpdateMode(AValue : TUpdateMode);
  174. procedure OnChangeSQL(Sender : TObject);
  175. procedure OnChangeModifySQL(Sender : TObject);
  176. procedure Execute;
  177. Procedure SQLParser(var ASQL : string);
  178. procedure ApplyFilter;
  179. Function AddFilter(SQLstr : string) : string;
  180. protected
  181. // abstract & virtual methods of TBufDataset
  182. function Fetch : boolean; override;
  183. function LoadField(FieldDef : TFieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; override;
  184. // abstract & virtual methods of TDataset
  185. procedure UpdateIndexDefs; override;
  186. procedure SetDatabase(Value : TDatabase); override;
  187. Procedure SetTransaction(Value : TDBTransaction); override;
  188. procedure InternalAddRecord(Buffer: Pointer; AAppend: Boolean); override;
  189. procedure InternalClose; override;
  190. procedure InternalInitFieldDefs; override;
  191. procedure InternalOpen; override;
  192. function GetCanModify: Boolean; override;
  193. procedure ApplyRecUpdate(UpdateKind : TUpdateKind); override;
  194. Function IsPrepared : Boolean; virtual;
  195. Procedure SetActive (Value : Boolean); override;
  196. procedure SetServerFiltered(Value: Boolean); virtual;
  197. procedure SetServerFilterText(const Value: string); virtual;
  198. Function GetDataSource : TDatasource; override;
  199. Procedure SetDataSource(AValue : TDatasource);
  200. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField); override;
  201. public
  202. procedure Prepare; virtual;
  203. procedure UnPrepare; virtual;
  204. procedure ExecSQL; virtual;
  205. constructor Create(AOwner : TComponent); override;
  206. destructor Destroy; override;
  207. procedure SetSchemaInfo( SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string); virtual;
  208. property Prepared : boolean read IsPrepared;
  209. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  210. protected
  211. // redeclared data set properties
  212. property Active;
  213. property Filter;
  214. property Filtered;
  215. // property FilterOptions;
  216. property BeforeOpen;
  217. property AfterOpen;
  218. property BeforeClose;
  219. property AfterClose;
  220. property BeforeInsert;
  221. property AfterInsert;
  222. property BeforeEdit;
  223. property AfterEdit;
  224. property BeforePost;
  225. property AfterPost;
  226. property BeforeCancel;
  227. property AfterCancel;
  228. property BeforeDelete;
  229. property AfterDelete;
  230. property BeforeScroll;
  231. property AfterScroll;
  232. property OnCalcFields;
  233. property OnDeleteError;
  234. property OnEditError;
  235. property OnFilterRecord;
  236. property OnNewRecord;
  237. property OnPostError;
  238. property AutoCalcFields;
  239. property Database;
  240. // protected
  241. // property SchemaInfo : TSchemaInfo read FSchemaInfo default stNoSchema;
  242. property Transaction;
  243. property ReadOnly : Boolean read FReadOnly write SetReadOnly;
  244. property SQL : TStringlist read FSQL write FSQL;
  245. property UpdateSQL : TStringlist read FUpdateSQL write FUpdateSQL;
  246. property InsertSQL : TStringlist read FInsertSQL write FInsertSQL;
  247. property DeleteSQL : TStringlist read FDeleteSQL write FDeleteSQL;
  248. property IndexDefs : TIndexDefs read GetIndexDefs;
  249. property Params : TParams read FParams write FParams;
  250. property UpdateMode : TUpdateMode read FUpdateMode write SetUpdateMode;
  251. property UsePrimaryKeyAsKey : boolean read FUsePrimaryKeyAsKey write SetUsePrimaryKeyAsKey;
  252. property StatementType : TStatementType read GetStatementType;
  253. property ParseSQL : Boolean read FParseSQL write SetParseSQL;
  254. Property DataSource : TDatasource Read GetDataSource Write SetDatasource;
  255. property ServerFilter: string read FServerFilterText write SetServerFilterText;
  256. property ServerFiltered: Boolean read FServerFiltered write SetServerFiltered default False;
  257. end;
  258. { TSQLQuery }
  259. TSQLQuery = Class(TCustomSQLQuery)
  260. Published
  261. // TDataset stuff
  262. Property Active;
  263. Property AutoCalcFields;
  264. Property Filter;
  265. Property Filtered;
  266. Property AfterCancel;
  267. Property AfterClose;
  268. Property AfterDelete;
  269. Property AfterEdit;
  270. Property AfterInsert;
  271. Property AfterOpen;
  272. Property AfterPost;
  273. Property AfterScroll;
  274. Property BeforeCancel;
  275. Property BeforeClose;
  276. Property BeforeDelete;
  277. Property BeforeEdit;
  278. Property BeforeInsert;
  279. Property BeforeOpen;
  280. Property BeforePost;
  281. Property BeforeScroll;
  282. Property OnCalcFields;
  283. Property OnDeleteError;
  284. Property OnEditError;
  285. Property OnFilterRecord;
  286. Property OnNewRecord;
  287. Property OnPostError;
  288. // property SchemaInfo default stNoSchema;
  289. property Database;
  290. property Transaction;
  291. property ReadOnly;
  292. property SQL;
  293. property UpdateSQL;
  294. property InsertSQL;
  295. property DeleteSQL;
  296. property IndexDefs;
  297. property Params;
  298. property UpdateMode;
  299. property UsePrimaryKeyAsKey;
  300. property StatementType;
  301. property ParseSQL;
  302. Property DataSource;
  303. property ServerFilter;
  304. property ServerFiltered;
  305. end;
  306. { TSQLScript }
  307. TSQLScript = class (Tcomponent)
  308. private
  309. FScript : TStrings;
  310. FQuery : TCustomSQLQuery;
  311. FDatabase : TDatabase;
  312. FTransaction : TDBTransaction;
  313. protected
  314. procedure SetScript(const AValue: TStrings);
  315. Procedure SetDatabase (Value : TDatabase); virtual;
  316. Procedure SetTransaction(Value : TDBTransaction); virtual;
  317. Procedure CheckDatabase;
  318. public
  319. constructor Create(AOwner : TComponent); override;
  320. destructor Destroy; override;
  321. procedure ExecuteScript;
  322. Property Script : TStrings Read FScript Write SetScript;
  323. Property DataBase : TDatabase Read FDatabase Write SetDatabase;
  324. Property Transaction : TDBTransaction Read FTransaction Write SetTransaction;
  325. end;
  326. { TSQLConnector }
  327. TSQLConnector = Class(TSQLConnection)
  328. private
  329. FProxy : TSQLConnection;
  330. FConnectorType: String;
  331. procedure SetConnectorType(const AValue: String);
  332. protected
  333. procedure SetTransaction(Value : TSQLTransaction);override;
  334. procedure DoInternalConnect; override;
  335. procedure DoInternalDisconnect; override;
  336. Procedure CheckProxy;
  337. Procedure CreateProxy; virtual;
  338. Procedure FreeProxy; virtual;
  339. function StrToStatementType(s : string) : TStatementType; override;
  340. function GetAsSQLText(Field : TField) : string; overload; override;
  341. function GetAsSQLText(Param : TParam) : string; overload; override;
  342. function GetHandle : pointer; override;
  343. Function AllocateCursorHandle : TSQLCursor; override;
  344. Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); override;
  345. Function AllocateTransactionHandle : TSQLHandle; override;
  346. procedure PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams); override;
  347. procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams); override;
  348. function Fetch(cursor : TSQLCursor) : boolean; override;
  349. procedure AddFieldDefs(cursor: TSQLCursor; FieldDefs : TfieldDefs); override;
  350. procedure UnPrepareStatement(cursor : TSQLCursor); override;
  351. procedure FreeFldBuffers(cursor : TSQLCursor); override;
  352. function LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; override;
  353. function GetTransactionHandle(trans : TSQLHandle): pointer; override;
  354. function Commit(trans : TSQLHandle) : boolean; override;
  355. function RollBack(trans : TSQLHandle) : boolean; override;
  356. function StartdbTransaction(trans : TSQLHandle; aParams : string) : boolean; override;
  357. procedure CommitRetaining(trans : TSQLHandle); override;
  358. procedure RollBackRetaining(trans : TSQLHandle); override;
  359. procedure UpdateIndexDefs(var IndexDefs : TIndexDefs;TableName : string); override;
  360. function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; override;
  361. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction : TSQLTransaction); override;
  362. Property Proxy : TSQLConnection Read FProxy;
  363. Published
  364. Property ConnectorType : String Read FConnectorType Write SetConnectorType;
  365. end;
  366. TSQLConnectionClass = Class of TSQLConnection;
  367. { TConnectionDef }
  368. TConnectionDef = Class(TPersistent)
  369. Class Function TypeName : String; virtual;
  370. Class Function ConnectionClass : TSQLConnectionClass; virtual;
  371. Class Function Description : String; virtual;
  372. Procedure ApplyParams(Params : TStrings; AConnection : TSQLConnection); virtual;
  373. end;
  374. TConnectionDefClass = class of TConnectionDef;
  375. Procedure RegisterConnection(Def : TConnectionDefClass);
  376. Procedure UnRegisterConnection(Def : TConnectionDefClass);
  377. Procedure UnRegisterConnection(ConnectionName : String);
  378. Function GetConnectionDef(ConnectorName : String) : TConnectionDef;
  379. Procedure GetConnectionList(List : TSTrings);
  380. implementation
  381. uses dbconst, strutils;
  382. { TSQLConnection }
  383. function TSQLConnection.StrToStatementType(s : string) : TStatementType;
  384. var T : TStatementType;
  385. begin
  386. S:=Lowercase(s);
  387. For t:=stselect to strollback do
  388. if (S=StatementTokens[t]) then
  389. Exit(t);
  390. end;
  391. procedure TSQLConnection.SetTransaction(Value : TSQLTransaction);
  392. begin
  393. if FTransaction<>value then
  394. begin
  395. if Assigned(FTransaction) and FTransaction.Active then
  396. DatabaseError(SErrAssTransaction);
  397. if Assigned(Value) then
  398. Value.Database := Self;
  399. FTransaction := Value;
  400. end;
  401. end;
  402. procedure TSQLConnection.UpdateIndexDefs(var IndexDefs : TIndexDefs;TableName : string);
  403. begin
  404. // Empty abstract
  405. end;
  406. procedure TSQLConnection.DoInternalConnect;
  407. begin
  408. if (DatabaseName = '') then
  409. DatabaseError(SErrNoDatabaseName,self);
  410. end;
  411. procedure TSQLConnection.DoInternalDisconnect;
  412. begin
  413. end;
  414. destructor TSQLConnection.Destroy;
  415. begin
  416. inherited Destroy;
  417. end;
  418. procedure TSQLConnection.StartTransaction;
  419. begin
  420. if not assigned(Transaction) then
  421. DatabaseError(SErrConnTransactionnSet)
  422. else
  423. Transaction.StartTransaction;
  424. end;
  425. procedure TSQLConnection.EndTransaction;
  426. begin
  427. if not assigned(Transaction) then
  428. DatabaseError(SErrConnTransactionnSet)
  429. else
  430. Transaction.EndTransaction;
  431. end;
  432. Procedure TSQLConnection.ExecuteDirect(SQL: String);
  433. begin
  434. ExecuteDirect(SQL,FTransaction);
  435. end;
  436. Procedure TSQLConnection.ExecuteDirect(SQL: String; ATransaction : TSQLTransaction);
  437. var Cursor : TSQLCursor;
  438. begin
  439. if not assigned(ATransaction) then
  440. DatabaseError(SErrTransactionnSet);
  441. if not Connected then Open;
  442. if not ATransaction.Active then ATransaction.StartTransaction;
  443. try
  444. Cursor := AllocateCursorHandle;
  445. SQL := TrimRight(SQL);
  446. if SQL = '' then
  447. DatabaseError(SErrNoStatement);
  448. Cursor.FStatementType := stNone;
  449. PrepareStatement(cursor,ATransaction,SQL,Nil);
  450. execute(cursor,ATransaction, Nil);
  451. UnPrepareStatement(Cursor);
  452. finally;
  453. DeAllocateCursorHandle(Cursor);
  454. end;
  455. end;
  456. procedure TSQLConnection.GetDBInfo(const SchemaType : TSchemaType; const SchemaObjectName, ReturnField : string; List: TStrings);
  457. var qry : TCustomSQLQuery;
  458. begin
  459. if not assigned(Transaction) then
  460. DatabaseError(SErrConnTransactionnSet);
  461. qry := TCustomSQLQuery.Create(nil);
  462. qry.transaction := Transaction;
  463. qry.database := Self;
  464. with qry do
  465. begin
  466. ParseSQL := False;
  467. SetSchemaInfo(SchemaType,SchemaObjectName,'');
  468. open;
  469. List.Clear;
  470. while not eof do
  471. begin
  472. List.Append(fieldbyname(ReturnField).asstring);
  473. Next;
  474. end;
  475. end;
  476. qry.free;
  477. end;
  478. procedure TSQLConnection.GetTableNames(List: TStrings; SystemTables: Boolean);
  479. begin
  480. if not systemtables then GetDBInfo(stTables,'','table_name',List)
  481. else GetDBInfo(stSysTables,'','table_name',List);
  482. end;
  483. procedure TSQLConnection.GetProcedureNames(List: TStrings);
  484. begin
  485. GetDBInfo(stProcedures,'','proc_name',List);
  486. end;
  487. procedure TSQLConnection.GetFieldNames(const TableName: string; List: TStrings);
  488. begin
  489. GetDBInfo(stColumns,TableName,'column_name',List);
  490. end;
  491. function TSQLConnection.GetAsSQLText(Field : TField) : string;
  492. begin
  493. if (not assigned(field)) or field.IsNull then Result := 'Null'
  494. else case field.DataType of
  495. ftString : Result := '''' + field.asstring + '''';
  496. ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Field.AsDateTime) + '''';
  497. ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:mm:ss',Field.AsDateTime) + ''''
  498. else
  499. Result := field.asstring;
  500. end; {case}
  501. end;
  502. function TSQLConnection.GetAsSQLText(Param: TParam) : string;
  503. begin
  504. if (not assigned(param)) or param.IsNull then Result := 'Null'
  505. else case param.DataType of
  506. ftString : Result := '''' + param.asstring + '''';
  507. ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Param.AsDateTime) + '''';
  508. ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:mm:ss',Param.AsDateTime) + ''''
  509. else
  510. Result := Param.asstring;
  511. end; {case}
  512. end;
  513. function TSQLConnection.GetHandle: pointer;
  514. begin
  515. Result := nil;
  516. end;
  517. procedure TSQLConnection.FreeFldBuffers(cursor: TSQLCursor);
  518. begin
  519. // empty
  520. end;
  521. function TSQLConnection.GetSchemaInfoSQL( SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string;
  522. begin
  523. DatabaseError(SMetadataUnavailable);
  524. end;
  525. procedure TSQLConnection.CreateDB;
  526. begin
  527. DatabaseError(SNotSupported);
  528. end;
  529. procedure TSQLConnection.DropDB;
  530. begin
  531. DatabaseError(SNotSupported);
  532. end;
  533. { TSQLTransaction }
  534. procedure TSQLTransaction.EndTransaction;
  535. begin
  536. rollback;
  537. end;
  538. function TSQLTransaction.GetHandle: pointer;
  539. begin
  540. Result := (Database as tsqlconnection).GetTransactionHandle(FTrans);
  541. end;
  542. procedure TSQLTransaction.Commit;
  543. begin
  544. if active then
  545. begin
  546. closedatasets;
  547. if (Database as tsqlconnection).commit(FTrans) then
  548. begin
  549. closeTrans;
  550. FreeAndNil(FTrans);
  551. end;
  552. end;
  553. end;
  554. procedure TSQLTransaction.CommitRetaining;
  555. begin
  556. if active then
  557. (Database as tsqlconnection).commitRetaining(FTrans);
  558. end;
  559. procedure TSQLTransaction.Rollback;
  560. begin
  561. if active then
  562. begin
  563. closedatasets;
  564. if (Database as tsqlconnection).RollBack(FTrans) then
  565. begin
  566. CloseTrans;
  567. FreeAndNil(FTrans);
  568. end;
  569. end;
  570. end;
  571. procedure TSQLTransaction.RollbackRetaining;
  572. begin
  573. if active then
  574. (Database as tsqlconnection).RollBackRetaining(FTrans);
  575. end;
  576. procedure TSQLTransaction.StartTransaction;
  577. var db : TSQLConnection;
  578. begin
  579. if Active then
  580. DatabaseError(SErrTransAlreadyActive);
  581. db := (Database as tsqlconnection);
  582. if Db = nil then
  583. DatabaseError(SErrDatabasenAssigned);
  584. if not Db.Connected then
  585. Db.Open;
  586. if not assigned(FTrans) then FTrans := Db.AllocateTransactionHandle;
  587. if Db.StartdbTransaction(FTrans,FParams.CommaText) then OpenTrans;
  588. end;
  589. constructor TSQLTransaction.Create(AOwner : TComponent);
  590. begin
  591. inherited Create(AOwner);
  592. FParams := TStringList.Create;
  593. end;
  594. destructor TSQLTransaction.Destroy;
  595. begin
  596. Rollback;
  597. FreeAndNil(FParams);
  598. inherited Destroy;
  599. end;
  600. Procedure TSQLTransaction.SetDatabase(Value : TDatabase);
  601. begin
  602. If Value<>Database then
  603. begin
  604. CheckInactive;
  605. If Assigned(Database) then
  606. with Database as TSqlConnection do
  607. if Transaction = self then Transaction := nil;
  608. inherited SetDatabase(Value);
  609. end;
  610. end;
  611. { TCustomSQLQuery }
  612. procedure TCustomSQLQuery.OnChangeSQL(Sender : TObject);
  613. var ConnOptions : TConnOptions;
  614. begin
  615. UnPrepare;
  616. if (FSQL <> nil) then
  617. begin
  618. if assigned(DataBase) then
  619. ConnOptions := (DataBase as TSQLConnection).ConnOptions
  620. else
  621. ConnOptions := [sqEscapeRepeat,sqEscapeSlash];
  622. Fparams.ParseSQL(FSQL.Text,True, sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions,psInterbase);
  623. If Assigned(FMasterLink) then
  624. FMasterLink.RefreshParamNames;
  625. end;
  626. end;
  627. procedure TCustomSQLQuery.OnChangeModifySQL(Sender : TObject);
  628. begin
  629. CheckInactive;
  630. end;
  631. Procedure TCustomSQLQuery.SetTransaction(Value : TDBTransaction);
  632. begin
  633. UnPrepare;
  634. inherited;
  635. end;
  636. procedure TCustomSQLQuery.SetDatabase(Value : TDatabase);
  637. var db : tsqlconnection;
  638. begin
  639. if (Database <> Value) then
  640. begin
  641. UnPrepare;
  642. if assigned(FCursor) then (Database as TSQLConnection).DeAllocateCursorHandle(FCursor);
  643. db := value as tsqlconnection;
  644. inherited setdatabase(value);
  645. if assigned(value) and (Transaction = nil) and (Assigned(db.Transaction)) then
  646. transaction := Db.Transaction;
  647. OnChangeSQL(Self);
  648. end;
  649. end;
  650. Function TCustomSQLQuery.IsPrepared : Boolean;
  651. begin
  652. Result := Assigned(FCursor) and FCursor.FPrepared;
  653. end;
  654. Function TCustomSQLQuery.AddFilter(SQLstr : string) : string;
  655. begin
  656. if FWhereStartPos = 0 then
  657. SQLstr := SQLstr + ' where (' + Filter + ')'
  658. else if FWhereStopPos > 0 then
  659. system.insert(' and ('+ServerFilter+') ',SQLstr,FWhereStopPos+1)
  660. else
  661. system.insert(' where ('+ServerFilter+') ',SQLstr,FWhereStartPos);
  662. Result := SQLstr;
  663. end;
  664. procedure TCustomSQLQuery.ApplyFilter;
  665. var S : String;
  666. begin
  667. FreeFldBuffers;
  668. (Database as tsqlconnection).UnPrepareStatement(FCursor);
  669. FIsEOF := False;
  670. inherited internalclose;
  671. s := FSQLBuf;
  672. if ServerFiltered then s := AddFilter(s);
  673. (Database as tsqlconnection).PrepareStatement(Fcursor,(transaction as tsqltransaction),S,FParams);
  674. Execute;
  675. inherited InternalOpen;
  676. First;
  677. end;
  678. Procedure TCustomSQLQuery.SetActive (Value : Boolean);
  679. begin
  680. inherited SetActive(Value);
  681. // The query is UnPrepared, so that if a transaction closes all datasets
  682. // they also get unprepared
  683. if not Value and IsPrepared then UnPrepare;
  684. end;
  685. procedure TCustomSQLQuery.SetServerFiltered(Value: Boolean);
  686. begin
  687. if Value and not FParseSQL then DatabaseErrorFmt(SNoParseSQL,['Filtering ']);
  688. if (ServerFiltered <> Value) then
  689. begin
  690. FServerFiltered := Value;
  691. if active then ApplyFilter;
  692. end;
  693. end;
  694. procedure TCustomSQLQuery.SetServerFilterText(const Value: string);
  695. begin
  696. if Value <> ServerFilter then
  697. begin
  698. FServerFilterText := Value;
  699. if active then ApplyFilter;
  700. end;
  701. end;
  702. procedure TCustomSQLQuery.Prepare;
  703. var
  704. db : tsqlconnection;
  705. sqltr : tsqltransaction;
  706. begin
  707. if not IsPrepared then
  708. begin
  709. db := (Database as tsqlconnection);
  710. sqltr := (transaction as tsqltransaction);
  711. if not assigned(Db) then
  712. DatabaseError(SErrDatabasenAssigned);
  713. if not assigned(sqltr) then
  714. DatabaseError(SErrTransactionnSet);
  715. if not Db.Connected then db.Open;
  716. if not sqltr.Active then sqltr.StartTransaction;
  717. // if assigned(fcursor) then FreeAndNil(fcursor);
  718. if not assigned(fcursor) then
  719. FCursor := Db.AllocateCursorHandle;
  720. FSQLBuf := TrimRight(FSQL.Text);
  721. if FSQLBuf = '' then
  722. DatabaseError(SErrNoStatement);
  723. SQLParser(FSQLBuf);
  724. if ServerFiltered then
  725. Db.PrepareStatement(Fcursor,sqltr,AddFilter(FSQLBuf),FParams)
  726. else
  727. Db.PrepareStatement(Fcursor,sqltr,FSQLBuf,FParams);
  728. if (FCursor.FStatementType = stSelect) then
  729. begin
  730. FCursor.FInitFieldDef := True;
  731. if not ReadOnly then InitUpdates(FSQLBuf);
  732. end;
  733. end;
  734. end;
  735. procedure TCustomSQLQuery.UnPrepare;
  736. begin
  737. CheckInactive;
  738. if IsPrepared then with Database as TSQLConnection do
  739. UnPrepareStatement(FCursor);
  740. end;
  741. procedure TCustomSQLQuery.FreeFldBuffers;
  742. begin
  743. if assigned(FCursor) then (Database as tsqlconnection).FreeFldBuffers(FCursor);
  744. end;
  745. function TCustomSQLQuery.Fetch : boolean;
  746. begin
  747. if not (Fcursor.FStatementType in [stSelect]) then
  748. Exit;
  749. if not FIsEof then FIsEOF := not (Database as tsqlconnection).Fetch(Fcursor);
  750. Result := not FIsEOF;
  751. end;
  752. procedure TCustomSQLQuery.Execute;
  753. begin
  754. If (FParams.Count>0) and Assigned(FMasterLink) then
  755. FMasterLink.CopyParamsFromMaster(False);
  756. (Database as tsqlconnection).execute(Fcursor,Transaction as tsqltransaction, FParams);
  757. end;
  758. function TCustomSQLQuery.LoadField(FieldDef : TFieldDef;buffer : pointer; out CreateBlob : boolean) : boolean;
  759. begin
  760. result := (Database as tSQLConnection).LoadField(FCursor,FieldDef,buffer, Createblob)
  761. end;
  762. procedure TCustomSQLQuery.InternalAddRecord(Buffer: Pointer; AAppend: Boolean);
  763. begin
  764. // not implemented - sql dataset
  765. end;
  766. procedure TCustomSQLQuery.InternalClose;
  767. begin
  768. if StatementType = stSelect then FreeFldBuffers;
  769. // Database and FCursor could be nil, for example if the database is not assigned, and .open is called
  770. if (not IsPrepared) and (assigned(database)) and (assigned(FCursor)) then (database as TSQLconnection).UnPrepareStatement(FCursor);
  771. if DefaultFields then
  772. DestroyFields;
  773. FIsEOF := False;
  774. if assigned(FUpdateQry) then FreeAndNil(FUpdateQry);
  775. if assigned(FInsertQry) then FreeAndNil(FInsertQry);
  776. if assigned(FDeleteQry) then FreeAndNil(FDeleteQry);
  777. // FRecordSize := 0;
  778. inherited internalclose;
  779. end;
  780. procedure TCustomSQLQuery.InternalInitFieldDefs;
  781. begin
  782. if FLoadingFieldDefs then
  783. Exit;
  784. FLoadingFieldDefs := True;
  785. try
  786. FieldDefs.Clear;
  787. (Database as tsqlconnection).AddFieldDefs(fcursor,FieldDefs);
  788. finally
  789. FLoadingFieldDefs := False;
  790. FCursor.FInitFieldDef := false;
  791. end;
  792. end;
  793. procedure TCustomSQLQuery.SQLParser(var ASQL : string);
  794. type TParsePart = (ppStart,ppSelect,ppWhere,ppFrom,ppOrder,ppComment,ppGroup,ppBogus);
  795. Var
  796. PSQL,CurrentP,
  797. PhraseP, PStatementPart : pchar;
  798. S : string;
  799. ParsePart : TParsePart;
  800. StrLength : Integer;
  801. EndOfComment : Boolean;
  802. BracketCount : Integer;
  803. ConnOptions : TConnOptions;
  804. begin
  805. PSQL:=Pchar(ASQL);
  806. ParsePart := ppStart;
  807. CurrentP := PSQL-1;
  808. PhraseP := PSQL;
  809. FWhereStartPos := 0;
  810. FWhereStopPos := 0;
  811. ConnOptions := (DataBase as TSQLConnection).ConnOptions;
  812. repeat
  813. begin
  814. inc(CurrentP);
  815. EndOfComment := SkipComments(CurrentP,sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions);
  816. if EndOfcomment then dec(currentp);
  817. if EndOfComment and (ParsePart = ppStart) then PhraseP := CurrentP;
  818. // skip everything between bracket, since it could be a sub-select, and
  819. // further nothing between brackets could be interesting for the parser.
  820. if currentp^='(' then
  821. begin
  822. inc(currentp);
  823. BracketCount := 0;
  824. while (currentp^ <> #0) and ((currentp^ <> ')') or (BracketCount > 0 )) do
  825. begin
  826. if currentp^ = '(' then inc(bracketcount)
  827. else if currentp^ = ')' then dec(bracketcount);
  828. inc(currentp);
  829. end;
  830. EndOfComment := True;
  831. end;
  832. if EndOfComment or (CurrentP^ in [' ',#13,#10,#9,#0,';']) then
  833. begin
  834. if (CurrentP-PhraseP > 0) or (CurrentP^ in [';',#0]) then
  835. begin
  836. strLength := CurrentP-PhraseP;
  837. Setlength(S,strLength);
  838. if strLength > 0 then Move(PhraseP^,S[1],(strLength));
  839. s := uppercase(s);
  840. case ParsePart of
  841. ppStart : begin
  842. FCursor.FStatementType := (Database as tsqlconnection).StrToStatementType(s);
  843. if FCursor.FStatementType = stSelect then ParsePart := ppSelect
  844. else break;
  845. if not FParseSQL then break;
  846. PStatementPart := CurrentP;
  847. end;
  848. ppSelect : begin
  849. if s = 'FROM' then
  850. begin
  851. ParsePart := ppFrom;
  852. PhraseP := CurrentP;
  853. PStatementPart := CurrentP;
  854. end;
  855. end;
  856. ppFrom : begin
  857. if (s = 'WHERE') or (s = 'ORDER') or (s = 'GROUP') or (CurrentP^=#0) or (CurrentP^=';') then
  858. begin
  859. if (s = 'WHERE') then
  860. begin
  861. ParsePart := ppWhere;
  862. StrLength := PhraseP-PStatementPart;
  863. end
  864. else if (s = 'GROUP') then
  865. begin
  866. ParsePart := ppGroup;
  867. StrLength := PhraseP-PStatementPart;
  868. end
  869. else if (s = 'ORDER') then
  870. begin
  871. ParsePart := ppOrder;
  872. StrLength := PhraseP-PStatementPart
  873. end
  874. else
  875. begin
  876. ParsePart := ppBogus;
  877. StrLength := CurrentP-PStatementPart;
  878. end;
  879. Setlength(FFromPart,StrLength);
  880. Move(PStatementPart^,FFromPart[1],(StrLength));
  881. FFrompart := trim(FFrompart);
  882. FWhereStartPos := PStatementPart-PSQL+StrLength+1;
  883. PStatementPart := CurrentP;
  884. end;
  885. end;
  886. ppWhere : begin
  887. if (s = 'ORDER') or (s = 'GROUP') or (CurrentP^=#0) or (CurrentP^=';') then
  888. begin
  889. ParsePart := ppBogus;
  890. FWhereStartPos := PStatementPart-PSQL;
  891. if (s = 'ORDER') or (s = 'GROUP') then
  892. FWhereStopPos := PhraseP-PSQL+1
  893. else
  894. FWhereStopPos := CurrentP-PSQL+1;
  895. end;
  896. end;
  897. end; {case}
  898. end;
  899. PhraseP := CurrentP+1;
  900. end
  901. end;
  902. until CurrentP^=#0;
  903. if (FWhereStartPos > 0) and (FWhereStopPos > 0) then
  904. begin
  905. system.insert('(',ASQL,FWhereStartPos+1);
  906. inc(FWhereStopPos);
  907. system.insert(')',ASQL,FWhereStopPos);
  908. end
  909. end;
  910. procedure TCustomSQLQuery.InitUpdates(ASQL : string);
  911. begin
  912. if pos(',',FFromPart) > 0 then
  913. FUpdateable := False // select-statements from more then one table are not updateable
  914. else
  915. begin
  916. FUpdateable := True;
  917. FTableName := FFromPart;
  918. end;
  919. end;
  920. procedure TCustomSQLQuery.InternalOpen;
  921. procedure InitialiseModifyQuery(var qry : TCustomSQLQuery; aSQL: TSTringList);
  922. begin
  923. qry := TCustomSQLQuery.Create(nil);
  924. with qry do
  925. begin
  926. ParseSQL := False;
  927. DataBase := Self.DataBase;
  928. Transaction := Self.Transaction;
  929. SQL.Assign(aSQL);
  930. end;
  931. end;
  932. var tel, fieldc : integer;
  933. f : TField;
  934. s : string;
  935. IndexFields : TStrings;
  936. begin
  937. try
  938. Prepare;
  939. if FCursor.FStatementType in [stSelect] then
  940. begin
  941. Execute;
  942. // InternalInitFieldDef is only called after a prepare. i.e. not twice if
  943. // a dataset is opened - closed - opened.
  944. if FCursor.FInitFieldDef then InternalInitFieldDefs;
  945. if DefaultFields then
  946. begin
  947. CreateFields;
  948. if FUpdateable then
  949. begin
  950. if FusePrimaryKeyAsKey then
  951. begin
  952. UpdateIndexDefs;
  953. for tel := 0 to indexdefs.count-1 do {with indexdefs[tel] do}
  954. begin
  955. if ixPrimary in indexdefs[tel].options then
  956. begin
  957. // Todo: If there is more then one field in the key, that must be parsed
  958. IndexFields := TStringList.Create;
  959. ExtractStrings([';'],[' '],pchar(indexdefs[tel].fields),IndexFields);
  960. for fieldc := 0 to IndexFields.Count-1 do
  961. begin
  962. F := Findfield(IndexFields[fieldc]);
  963. if F <> nil then
  964. F.ProviderFlags := F.ProviderFlags + [pfInKey];
  965. end;
  966. IndexFields.Free;
  967. end;
  968. end;
  969. end;
  970. end;
  971. end
  972. else
  973. BindFields(True);
  974. if FUpdateable then
  975. begin
  976. InitialiseModifyQuery(FDeleteQry,FDeleteSQL);
  977. InitialiseModifyQuery(FUpdateQry,FUpdateSQL);
  978. InitialiseModifyQuery(FInsertQry,FInsertSQL);
  979. end;
  980. end
  981. else
  982. DatabaseError(SErrNoSelectStatement,Self);
  983. except
  984. on E:Exception do
  985. raise;
  986. end;
  987. inherited InternalOpen;
  988. end;
  989. // public part
  990. procedure TCustomSQLQuery.ExecSQL;
  991. begin
  992. try
  993. Prepare;
  994. Execute;
  995. finally
  996. // FCursor has to be assigned, or else the prepare went wrong before PrepareStatment was
  997. // called, so UnPrepareStatement shoudn't be called either
  998. if (not IsPrepared) and (assigned(database)) and (assigned(FCursor)) then (database as TSQLConnection).UnPrepareStatement(Fcursor);
  999. end;
  1000. end;
  1001. constructor TCustomSQLQuery.Create(AOwner : TComponent);
  1002. begin
  1003. inherited Create(AOwner);
  1004. FParams := TParams.create(self);
  1005. FSQL := TStringList.Create;
  1006. FSQL.OnChange := @OnChangeSQL;
  1007. FUpdateSQL := TStringList.Create;
  1008. FUpdateSQL.OnChange := @OnChangeModifySQL;
  1009. FInsertSQL := TStringList.Create;
  1010. FInsertSQL.OnChange := @OnChangeModifySQL;
  1011. FDeleteSQL := TStringList.Create;
  1012. FDeleteSQL.OnChange := @OnChangeModifySQL;
  1013. FIndexDefs := TIndexDefs.Create(Self);
  1014. FReadOnly := false;
  1015. FParseSQL := True;
  1016. FServerFiltered := False;
  1017. FServerFilterText := '';
  1018. // Delphi has upWhereAll as default, but since strings and oldvalue's don't work yet
  1019. // (variants) set it to upWhereKeyOnly
  1020. FUpdateMode := upWhereKeyOnly;
  1021. FUsePrimaryKeyAsKey := True;
  1022. end;
  1023. destructor TCustomSQLQuery.Destroy;
  1024. begin
  1025. if Active then Close;
  1026. UnPrepare;
  1027. if assigned(FCursor) then (Database as TSQLConnection).DeAllocateCursorHandle(FCursor);
  1028. FreeAndNil(FMasterLink);
  1029. FreeAndNil(FParams);
  1030. FreeAndNil(FSQL);
  1031. FreeAndNil(FInsertSQL);
  1032. FreeAndNil(FDeleteSQL);
  1033. FreeAndNil(FUpdateSQL);
  1034. FreeAndNil(FIndexDefs);
  1035. inherited Destroy;
  1036. end;
  1037. procedure TCustomSQLQuery.SetReadOnly(AValue : Boolean);
  1038. begin
  1039. CheckInactive;
  1040. if not AValue then
  1041. begin
  1042. if FParseSQL then FReadOnly := False
  1043. else DatabaseErrorFmt(SNoParseSQL,['Updating ']);
  1044. end
  1045. else FReadOnly := True;
  1046. end;
  1047. procedure TCustomSQLQuery.SetParseSQL(AValue : Boolean);
  1048. begin
  1049. CheckInactive;
  1050. if not AValue then
  1051. begin
  1052. FReadOnly := True;
  1053. FServerFiltered := False;
  1054. FParseSQL := False;
  1055. end
  1056. else
  1057. FParseSQL := True;
  1058. end;
  1059. procedure TCustomSQLQuery.SetUsePrimaryKeyAsKey(AValue : Boolean);
  1060. begin
  1061. if not Active then FusePrimaryKeyAsKey := AValue
  1062. else
  1063. begin
  1064. // Just temporary, this should be possible in the future
  1065. DatabaseError(SActiveDataset);
  1066. end;
  1067. end;
  1068. Procedure TCustomSQLQuery.UpdateIndexDefs;
  1069. begin
  1070. if assigned(DataBase) then
  1071. (DataBase as TSQLConnection).UpdateIndexDefs(FIndexDefs,FTableName);
  1072. end;
  1073. Procedure TCustomSQLQuery.ApplyRecUpdate(UpdateKind : TUpdateKind);
  1074. procedure UpdateWherePart(var sql_where : string;x : integer);
  1075. begin
  1076. if (pfInKey in Fields[x].ProviderFlags) or
  1077. ((FUpdateMode = upWhereAll) and (pfInWhere in Fields[x].ProviderFlags)) or
  1078. ((FUpdateMode = UpWhereChanged) and (pfInWhere in Fields[x].ProviderFlags) and (fields[x].value <> fields[x].oldvalue)) then
  1079. sql_where := sql_where + '(' + fields[x].FieldName + '= :OLD_' + fields[x].FieldName + ') and ';
  1080. end;
  1081. function ModifyRecQuery : string;
  1082. var x : integer;
  1083. sql_set : string;
  1084. sql_where : string;
  1085. begin
  1086. sql_set := '';
  1087. sql_where := '';
  1088. for x := 0 to Fields.Count -1 do
  1089. begin
  1090. UpdateWherePart(sql_where,x);
  1091. if (pfInUpdate in Fields[x].ProviderFlags) then
  1092. sql_set := sql_set + fields[x].FieldName + '=:' + fields[x].FieldName + ',';
  1093. end;
  1094. if length(sql_set) = 0 then DatabaseError(sNoUpdateFields,self);
  1095. setlength(sql_set,length(sql_set)-1);
  1096. if length(sql_where) = 0 then DatabaseError(sNoWhereFields,self);
  1097. setlength(sql_where,length(sql_where)-5);
  1098. result := 'update ' + FTableName + ' set ' + sql_set + ' where ' + sql_where;
  1099. end;
  1100. function InsertRecQuery : string;
  1101. var x : integer;
  1102. sql_fields : string;
  1103. sql_values : string;
  1104. begin
  1105. sql_fields := '';
  1106. sql_values := '';
  1107. for x := 0 to Fields.Count -1 do
  1108. begin
  1109. if (not fields[x].IsNull) and (pfInUpdate in Fields[x].ProviderFlags) then
  1110. begin
  1111. sql_fields := sql_fields + fields[x].FieldName + ',';
  1112. sql_values := sql_values + ':' + fields[x].FieldName + ',';
  1113. end;
  1114. end;
  1115. if length(sql_fields) = 0 then DatabaseError(sNoUpdateFields,self);
  1116. setlength(sql_fields,length(sql_fields)-1);
  1117. setlength(sql_values,length(sql_values)-1);
  1118. result := 'insert into ' + FTableName + ' (' + sql_fields + ') values (' + sql_values + ')';
  1119. end;
  1120. function DeleteRecQuery : string;
  1121. var x : integer;
  1122. sql_where : string;
  1123. begin
  1124. sql_where := '';
  1125. for x := 0 to Fields.Count -1 do
  1126. UpdateWherePart(sql_where,x);
  1127. if length(sql_where) = 0 then DatabaseError(sNoWhereFields,self);
  1128. setlength(sql_where,length(sql_where)-5);
  1129. result := 'delete from ' + FTableName + ' where ' + sql_where;
  1130. end;
  1131. var qry : TCustomSQLQuery;
  1132. x : integer;
  1133. Fld : TField;
  1134. begin
  1135. case UpdateKind of
  1136. ukModify : begin
  1137. qry := FUpdateQry;
  1138. if trim(qry.sql.Text) = '' then qry.SQL.Add(ModifyRecQuery);
  1139. end;
  1140. ukInsert : begin
  1141. qry := FInsertQry;
  1142. if trim(qry.sql.Text) = '' then qry.SQL.Add(InsertRecQuery);
  1143. end;
  1144. ukDelete : begin
  1145. qry := FDeleteQry;
  1146. if trim(qry.sql.Text) = '' then qry.SQL.Add(DeleteRecQuery);
  1147. end;
  1148. end;
  1149. with qry do
  1150. begin
  1151. for x := 0 to Params.Count-1 do with params[x] do if leftstr(name,4)='OLD_' then
  1152. begin
  1153. Fld := self.FieldByName(copy(name,5,length(name)-4));
  1154. AssignFieldValue(Fld,Fld.OldValue);
  1155. end
  1156. else
  1157. begin
  1158. Fld := self.FieldByName(name);
  1159. AssignFieldValue(Fld,Fld.Value);
  1160. end;
  1161. execsql;
  1162. end;
  1163. end;
  1164. Function TCustomSQLQuery.GetCanModify: Boolean;
  1165. begin
  1166. // the test for assigned(FCursor) is needed for the case that the dataset isn't opened
  1167. if assigned(FCursor) and (FCursor.FStatementType = stSelect) then
  1168. Result:= FUpdateable and (not FReadOnly)
  1169. else
  1170. Result := False;
  1171. end;
  1172. function TCustomSQLQuery.GetIndexDefs : TIndexDefs;
  1173. begin
  1174. Result := FIndexDefs;
  1175. end;
  1176. procedure TCustomSQLQuery.SetIndexDefs(AValue : TIndexDefs);
  1177. begin
  1178. FIndexDefs := AValue;
  1179. end;
  1180. procedure TCustomSQLQuery.SetUpdateMode(AValue : TUpdateMode);
  1181. begin
  1182. FUpdateMode := AValue;
  1183. end;
  1184. procedure TCustomSQLQuery.SetSchemaInfo( SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string);
  1185. begin
  1186. ReadOnly := True;
  1187. SQL.Clear;
  1188. SQL.Add((DataBase as tsqlconnection).GetSchemaInfoSQL(SchemaType, SchemaObjectName, SchemaPattern));
  1189. end;
  1190. procedure TCustomSQLQuery.LoadBlobIntoBuffer(FieldDef: TFieldDef;
  1191. ABlobBuf: PBufBlobField);
  1192. begin
  1193. (DataBase as tsqlconnection).LoadBlobIntoBuffer(FieldDef, ABlobBuf, FCursor,(Transaction as tsqltransaction));
  1194. end;
  1195. function TCustomSQLQuery.GetStatementType : TStatementType;
  1196. begin
  1197. if assigned(FCursor) then Result := FCursor.FStatementType
  1198. else Result := stNone;
  1199. end;
  1200. Procedure TCustomSQLQuery.SetDataSource(AVAlue : TDatasource);
  1201. Var
  1202. DS : TDatasource;
  1203. begin
  1204. DS:=DataSource;
  1205. If (AValue<>DS) then
  1206. begin
  1207. If Assigned(AValue) and (AValue.Dataset=Self) then
  1208. DatabaseError(SErrCircularDataSourceReferenceNotAllowed,Self);
  1209. If Assigned(DS) then
  1210. DS.RemoveFreeNotification(Self);
  1211. If Assigned(AValue) then
  1212. begin
  1213. AValue.FreeNotification(Self);
  1214. FMasterLink:=TMasterParamsDataLink.Create(Self);
  1215. FMasterLink.Datasource:=AValue;
  1216. end
  1217. else
  1218. FreeAndNil(FMasterLink);
  1219. end;
  1220. end;
  1221. Function TCustomSQLQuery.GetDataSource : TDatasource;
  1222. begin
  1223. If Assigned(FMasterLink) then
  1224. Result:=FMasterLink.DataSource
  1225. else
  1226. Result:=Nil;
  1227. end;
  1228. procedure TCustomSQLQuery.Notification(AComponent: TComponent; Operation: TOperation);
  1229. begin
  1230. Inherited;
  1231. If (Operation=opRemove) and (AComponent=DataSource) then
  1232. DataSource:=Nil;
  1233. end;
  1234. { TSQLScript }
  1235. procedure TSQLScript.SetScript(const AValue: TStrings);
  1236. begin
  1237. FScript.assign(AValue);
  1238. end;
  1239. procedure TSQLScript.SetDatabase(Value: TDatabase);
  1240. begin
  1241. FDatabase := Value;
  1242. end;
  1243. procedure TSQLScript.SetTransaction(Value: TDBTransaction);
  1244. begin
  1245. FTransaction := Value;
  1246. end;
  1247. procedure TSQLScript.CheckDatabase;
  1248. begin
  1249. If (FDatabase=Nil) then
  1250. DatabaseError(SErrNoDatabaseAvailable,Self)
  1251. end;
  1252. constructor TSQLScript.Create(AOwner: TComponent);
  1253. begin
  1254. inherited Create(AOwner);
  1255. FScript := TStringList.Create;
  1256. FQuery := TCustomSQLQuery.Create(nil);
  1257. end;
  1258. destructor TSQLScript.Destroy;
  1259. begin
  1260. FScript.Free;
  1261. FQuery.Free;
  1262. inherited Destroy;
  1263. end;
  1264. procedure TSQLScript.ExecuteScript;
  1265. var BufStr : String;
  1266. pBufStatStart,
  1267. pBufPos : PChar;
  1268. Statement : String;
  1269. begin
  1270. FQuery.DataBase := FDatabase;
  1271. FQuery.Transaction := FTransaction;
  1272. BufStr := FScript.Text;
  1273. pBufPos := @BufStr[1];
  1274. repeat
  1275. pBufStatStart := pBufPos;
  1276. repeat
  1277. inc(pBufPos);
  1278. until (pBufPos^ = ';') or (pBufPos^ = #0);
  1279. SetLength(statement,pbufpos-pBufStatStart);
  1280. move(pBufStatStart^,Statement[1],pbufpos-pBufStatStart);
  1281. if trim(statement) <> '' then
  1282. begin
  1283. fquery.SQL.Text := Statement;
  1284. fquery.ExecSQL;
  1285. inc(pBufPos);
  1286. end;
  1287. until pBufPos^ = #0;
  1288. end;
  1289. { Connection definitions }
  1290. Var
  1291. ConnDefs : TStringList;
  1292. Procedure CheckDefs;
  1293. begin
  1294. If (ConnDefs=Nil) then
  1295. begin
  1296. ConnDefs:=TStringList.Create;
  1297. ConnDefs.Sorted:=True;
  1298. ConnDefs.Duplicates:=dupError;
  1299. end;
  1300. end;
  1301. Procedure DoneDefs;
  1302. Var
  1303. I : Integer;
  1304. begin
  1305. If Assigned(ConnDefs) then
  1306. begin
  1307. For I:=ConnDefs.Count-1 downto 0 do
  1308. begin
  1309. ConnDefs.Objects[i].Free;
  1310. ConnDefs.Delete(I);
  1311. end;
  1312. FreeAndNil(ConnDefs);
  1313. end;
  1314. end;
  1315. Function GetConnectionDef(ConnectorName : String) : TConnectionDef;
  1316. Var
  1317. I : Integer;
  1318. begin
  1319. CheckDefs;
  1320. I:=ConnDefs.IndexOf(ConnectorName);
  1321. If (I<>-1) then
  1322. Result:=TConnectionDef(ConnDefs.Objects[i])
  1323. else
  1324. Result:=Nil;
  1325. end;
  1326. procedure RegisterConnection(Def: TConnectionDefClass);
  1327. Var
  1328. I : Integer;
  1329. begin
  1330. CheckDefs;
  1331. I:=ConnDefs.IndexOf(Def.TypeName);
  1332. If (I=-1) then
  1333. ConnDefs.AddObject(Def.TypeName,Def.Create)
  1334. else
  1335. begin
  1336. ConnDefs.Objects[I].Free;
  1337. ConnDefs.Objects[I]:=Def.Create;
  1338. end;
  1339. end;
  1340. procedure UnRegisterConnection(Def: TConnectionDefClass);
  1341. begin
  1342. UnRegisterConnection(Def.TypeName);
  1343. end;
  1344. procedure UnRegisterConnection(ConnectionName: String);
  1345. Var
  1346. I : Integer;
  1347. begin
  1348. if (ConnDefs<>Nil) then
  1349. begin
  1350. I:=ConnDefs.IndexOf(ConnectionName);
  1351. If (I<>-1) then
  1352. begin
  1353. ConnDefs.Objects[I].Free;
  1354. ConnDefs.Delete(I);
  1355. end;
  1356. end;
  1357. end;
  1358. procedure GetConnectionList(List: TSTrings);
  1359. begin
  1360. CheckDefs;
  1361. List.Text:=ConnDefs.Text;
  1362. end;
  1363. { TSQLConnector }
  1364. procedure TSQLConnector.SetConnectorType(const AValue: String);
  1365. begin
  1366. if FConnectorType<>AValue then
  1367. begin
  1368. CheckDisconnected;
  1369. If Assigned(FProxy) then
  1370. FreeProxy;
  1371. FConnectorType:=AValue;
  1372. end;
  1373. end;
  1374. procedure TSQLConnector.SetTransaction(Value: TSQLTransaction);
  1375. begin
  1376. inherited SetTransaction(Value);
  1377. If Assigned(FProxy) and (FProxy.Transaction<>Value) then
  1378. FProxy.Transaction:=Value;
  1379. end;
  1380. procedure TSQLConnector.DoInternalConnect;
  1381. Var
  1382. D : TConnectionDef;
  1383. begin
  1384. inherited DoInternalConnect;
  1385. CreateProxy;
  1386. FProxy.DatabaseName:=Self.DatabaseName;
  1387. FProxy.HostName:=Self.HostName;
  1388. FProxy.UserName:=Self.UserName;
  1389. FProxy.Password:=Self.Password;
  1390. FProxy.Transaction:=Self.Transaction;
  1391. D:=GetConnectionDef(ConnectorType);
  1392. D.ApplyParams(Params,FProxy);
  1393. FProxy.Connected:=True;
  1394. end;
  1395. procedure TSQLConnector.DoInternalDisconnect;
  1396. begin
  1397. FProxy.Connected:=False;
  1398. inherited DoInternalDisconnect;
  1399. end;
  1400. procedure TSQLConnector.CheckProxy;
  1401. begin
  1402. If (FProxy=Nil) then
  1403. CreateProxy;
  1404. end;
  1405. procedure TSQLConnector.CreateProxy;
  1406. Var
  1407. D : TConnectionDef;
  1408. begin
  1409. D:=GetConnectionDef(ConnectorType);
  1410. If (D=Nil) then
  1411. DatabaseErrorFmt(SErrUnknownConnectorType,[ConnectorType],Self);
  1412. FProxy:=D.ConnectionClass.Create(Self);
  1413. end;
  1414. procedure TSQLConnector.FreeProxy;
  1415. begin
  1416. FProxy.Connected:=False;
  1417. FreeAndNil(FProxy);
  1418. end;
  1419. function TSQLConnector.StrToStatementType(s: string): TStatementType;
  1420. begin
  1421. CheckProxy;
  1422. Result:=FProxy.StrToStatementType(s);
  1423. end;
  1424. function TSQLConnector.GetAsSQLText(Field: TField): string;
  1425. begin
  1426. CheckProxy;
  1427. Result:=FProxy.GetAsSQLText(Field);
  1428. end;
  1429. function TSQLConnector.GetAsSQLText(Param: TParam): string;
  1430. begin
  1431. CheckProxy;
  1432. Result:=FProxy.GetAsSQLText(Param);
  1433. end;
  1434. function TSQLConnector.GetHandle: pointer;
  1435. begin
  1436. CheckProxy;
  1437. Result:=FProxy.GetHandle;
  1438. end;
  1439. function TSQLConnector.AllocateCursorHandle: TSQLCursor;
  1440. begin
  1441. CheckProxy;
  1442. Result:=FProxy.AllocateCursorHandle;
  1443. end;
  1444. procedure TSQLConnector.DeAllocateCursorHandle(var cursor: TSQLCursor);
  1445. begin
  1446. CheckProxy;
  1447. FProxy.DeAllocateCursorHandle(cursor);
  1448. end;
  1449. function TSQLConnector.AllocateTransactionHandle: TSQLHandle;
  1450. begin
  1451. CheckProxy;
  1452. Result:=FProxy.AllocateTransactionHandle;
  1453. end;
  1454. procedure TSQLConnector.PrepareStatement(cursor: TSQLCursor;
  1455. ATransaction: TSQLTransaction; buf: string; AParams: TParams);
  1456. begin
  1457. CheckProxy;
  1458. FProxy.PrepareStatement(cursor, ATransaction, buf, AParams);
  1459. end;
  1460. procedure TSQLConnector.Execute(cursor: TSQLCursor;
  1461. atransaction: tSQLtransaction; AParams: TParams);
  1462. begin
  1463. CheckProxy;
  1464. FProxy.Execute(cursor, atransaction, AParams);
  1465. end;
  1466. function TSQLConnector.Fetch(cursor: TSQLCursor): boolean;
  1467. begin
  1468. CheckProxy;
  1469. Result:=FProxy.Fetch(cursor);
  1470. end;
  1471. procedure TSQLConnector.AddFieldDefs(cursor: TSQLCursor; FieldDefs: TfieldDefs
  1472. );
  1473. begin
  1474. CheckProxy;
  1475. FProxy.AddFieldDefs(cursor, FieldDefs);
  1476. end;
  1477. procedure TSQLConnector.UnPrepareStatement(cursor: TSQLCursor);
  1478. begin
  1479. CheckProxy;
  1480. FProxy.UnPrepareStatement(cursor);
  1481. end;
  1482. procedure TSQLConnector.FreeFldBuffers(cursor: TSQLCursor);
  1483. begin
  1484. CheckProxy;
  1485. FProxy.FreeFldBuffers(cursor);
  1486. end;
  1487. function TSQLConnector.LoadField(cursor: TSQLCursor; FieldDef: TfieldDef;
  1488. buffer: pointer; out CreateBlob: boolean): boolean;
  1489. begin
  1490. CheckProxy;
  1491. Result:=FProxy.LoadField(cursor, FieldDef, buffer, CreateBlob);
  1492. end;
  1493. function TSQLConnector.GetTransactionHandle(trans: TSQLHandle): pointer;
  1494. begin
  1495. CheckProxy;
  1496. Result:=FProxy.GetTransactionHandle(trans);
  1497. end;
  1498. function TSQLConnector.Commit(trans: TSQLHandle): boolean;
  1499. begin
  1500. CheckProxy;
  1501. Result:=FProxy.Commit(trans);
  1502. end;
  1503. function TSQLConnector.RollBack(trans: TSQLHandle): boolean;
  1504. begin
  1505. CheckProxy;
  1506. Result:=FProxy.RollBack(trans);
  1507. end;
  1508. function TSQLConnector.StartdbTransaction(trans: TSQLHandle; aParams: string
  1509. ): boolean;
  1510. begin
  1511. CheckProxy;
  1512. Result:=FProxy.StartdbTransaction(trans, aParams);
  1513. end;
  1514. procedure TSQLConnector.CommitRetaining(trans: TSQLHandle);
  1515. begin
  1516. CheckProxy;
  1517. FProxy.CommitRetaining(trans);
  1518. end;
  1519. procedure TSQLConnector.RollBackRetaining(trans: TSQLHandle);
  1520. begin
  1521. CheckProxy;
  1522. FProxy.RollBackRetaining(trans);
  1523. end;
  1524. procedure TSQLConnector.UpdateIndexDefs(var IndexDefs: TIndexDefs;
  1525. TableName: string);
  1526. begin
  1527. CheckProxy;
  1528. FProxy.UpdateIndexDefs(IndexDefs, TableName);
  1529. end;
  1530. function TSQLConnector.GetSchemaInfoSQL(SchemaType: TSchemaType;
  1531. SchemaObjectName, SchemaPattern: string): string;
  1532. begin
  1533. CheckProxy;
  1534. Result:=FProxy.GetSchemaInfoSQL(SchemaType, SchemaObjectName, SchemaPattern
  1535. );
  1536. end;
  1537. procedure TSQLConnector.LoadBlobIntoBuffer(FieldDef: TFieldDef;
  1538. ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction);
  1539. begin
  1540. CheckProxy;
  1541. FProxy.LoadBlobIntoBuffer(FieldDef, ABlobBuf, cursor, ATransaction);
  1542. end;
  1543. { TConnectionDef }
  1544. class function TConnectionDef.TypeName: String;
  1545. begin
  1546. Result:='';
  1547. end;
  1548. class function TConnectionDef.ConnectionClass: TSQLConnectionClass;
  1549. begin
  1550. Result:=Nil;
  1551. end;
  1552. class function TConnectionDef.Description: String;
  1553. begin
  1554. Result:='';
  1555. end;
  1556. procedure TConnectionDef.ApplyParams(Params: TStrings;
  1557. AConnection: TSQLConnection);
  1558. begin
  1559. AConnection.Params.Assign(Params);
  1560. end;
  1561. Initialization
  1562. Finalization
  1563. DoneDefs;
  1564. end.