sqldb.pp 50 KB

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