sqldb.pp 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232
  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, sqlscript;
  16. type TSchemaType = (stNoSchema, stTables, stSysTables, stProcedures, stColumns, stProcedureParams, stIndexes, stPackages);
  17. TConnOption = (sqSupportParams,sqEscapeSlash,sqEscapeRepeat);
  18. TConnOptions= set of TConnOption;
  19. TRowsCount = LargeInt;
  20. type
  21. TSQLConnection = class;
  22. TSQLTransaction = class;
  23. TCustomSQLQuery = class;
  24. TSQLQuery = class;
  25. TSQLScript = class;
  26. TStatementType = (stNone, stSelect, stInsert, stUpdate, stDelete,
  27. stDDL, stGetSegment, stPutSegment, stExecProcedure,
  28. stStartTrans, stCommit, stRollback, stSelectForUpd);
  29. TDBEventType = (detCustom, detPrepare, detExecute, detFetch, detCommit,detRollBack);
  30. TDBEventTypes = set of TDBEventType;
  31. TDBLogNotifyEvent = Procedure (Sender : TSQLConnection; EventType : TDBEventType; Const Msg : String) of object;
  32. TSQLHandle = Class(TObject)
  33. end;
  34. { TSQLCursor }
  35. TSQLCursor = Class(TSQLHandle)
  36. public
  37. FPrepared : Boolean;
  38. FInitFieldDef : Boolean;
  39. FStatementType : TStatementType;
  40. FSchemaType : TSchemaType;
  41. end;
  42. type TQuoteChars = array[0..1] of char;
  43. const
  44. SingleQuotes : TQuoteChars = ('''','''');
  45. DoubleQuotes : TQuoteChars = ('"','"');
  46. LogAllEvents = [detCustom, detPrepare, detExecute, detFetch, detCommit, detRollBack];
  47. StatementTokens : Array[TStatementType] of string = ('(none)', 'select',
  48. 'insert', 'update', 'delete',
  49. 'create', 'get', 'put', 'execute',
  50. 'start','commit','rollback', '?'
  51. );
  52. type
  53. { TServerIndexDefs }
  54. TServerIndexDefs = class(TIndexDefs)
  55. Private
  56. public
  57. constructor Create(ADataSet: TDataSet); override;
  58. procedure Update; override;
  59. end;
  60. type
  61. { TSQLConnection }
  62. TSQLConnection = class (TDatabase)
  63. private
  64. FFieldNameQuoteChars : TQuoteChars;
  65. FLogEvents: TDBEventTypes;
  66. FOnLog: TDBLogNotifyEvent;
  67. FPassword : string;
  68. FTransaction : TSQLTransaction;
  69. FUserName : string;
  70. FHostName : string;
  71. FCharSet : string;
  72. FRole : String;
  73. function GetPort: cardinal;
  74. procedure Setport(const AValue: cardinal);
  75. protected
  76. FConnOptions : TConnOptions;
  77. FSQLFormatSettings : TFormatSettings;
  78. procedure GetDBInfo(const ASchemaType : TSchemaType; const ASchemaObjectName, AReturnField : string; AList: TStrings);
  79. procedure SetTransaction(Value : TSQLTransaction);virtual;
  80. function StrToStatementType(s : string) : TStatementType; virtual;
  81. procedure DoInternalConnect; override;
  82. procedure DoInternalDisconnect; override;
  83. function GetAsSQLText(Field : TField) : string; overload; virtual;
  84. function GetAsSQLText(Param : TParam) : string; overload; virtual;
  85. function GetHandle : pointer; virtual; virtual;
  86. Function LogEvent(EventType : TDBEventType) : Boolean;
  87. Procedure Log(EventType : TDBEventType; Const Msg : String); virtual;
  88. Function AllocateCursorHandle : TSQLCursor; virtual; abstract;
  89. Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); virtual; abstract;
  90. Function AllocateTransactionHandle : TSQLHandle; virtual; abstract;
  91. procedure PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams); virtual; abstract;
  92. procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams); virtual; abstract;
  93. function Fetch(cursor : TSQLCursor) : boolean; virtual; abstract;
  94. procedure AddFieldDefs(cursor: TSQLCursor; FieldDefs : TfieldDefs); virtual; abstract;
  95. procedure UnPrepareStatement(cursor : TSQLCursor); virtual; abstract;
  96. procedure FreeFldBuffers(cursor : TSQLCursor); virtual;
  97. function LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; virtual; abstract;
  98. function GetTransactionHandle(trans : TSQLHandle): pointer; virtual; abstract;
  99. function Commit(trans : TSQLHandle) : boolean; virtual; abstract;
  100. function RollBack(trans : TSQLHandle) : boolean; virtual; abstract;
  101. function StartdbTransaction(trans : TSQLHandle; aParams : string) : boolean; virtual; abstract;
  102. procedure CommitRetaining(trans : TSQLHandle); virtual; abstract;
  103. procedure RollBackRetaining(trans : TSQLHandle); virtual; abstract;
  104. procedure UpdateIndexDefs(IndexDefs : TIndexDefs;TableName : string); virtual;
  105. function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; virtual;
  106. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction : TSQLTransaction); virtual; abstract;
  107. function RowsAffected(cursor: TSQLCursor): TRowsCount; virtual;
  108. property port: cardinal read GetPort write Setport;
  109. public
  110. property Handle: Pointer read GetHandle;
  111. property FieldNameQuoteChars: TQuoteChars read FFieldNameQuoteChars write FFieldNameQuoteChars;
  112. constructor Create(AOwner: TComponent); override;
  113. destructor Destroy; override;
  114. procedure StartTransaction; override;
  115. procedure EndTransaction; override;
  116. property ConnOptions: TConnOptions read FConnOptions;
  117. procedure ExecuteDirect(SQL : String); overload; virtual;
  118. procedure ExecuteDirect(SQL : String; ATransaction : TSQLTransaction); overload; virtual;
  119. procedure GetTableNames(List : TStrings; SystemTables : Boolean = false); virtual;
  120. procedure GetProcedureNames(List : TStrings); virtual;
  121. procedure GetFieldNames(const TableName : string; List : TStrings); virtual;
  122. procedure CreateDB; virtual;
  123. procedure DropDB; virtual;
  124. published
  125. property Password : string read FPassword write FPassword;
  126. property Transaction : TSQLTransaction read FTransaction write SetTransaction;
  127. property UserName : string read FUserName write FUserName;
  128. property CharSet : string read FCharSet write FCharSet;
  129. property HostName : string Read FHostName Write FHostName;
  130. Property OnLog : TDBLogNotifyEvent Read FOnLog Write FOnLog;
  131. Property LogEvents : TDBEventTypes Read FLogEvents Write FLogEvents Default LogAllEvents;
  132. property Connected;
  133. Property Role : String read FRole write FRole;
  134. property DatabaseName;
  135. property KeepConnection;
  136. property LoginPrompt;
  137. property Params;
  138. property OnLogin;
  139. end;
  140. { TSQLTransaction }
  141. TCommitRollbackAction = (caNone, caCommit, caCommitRetaining, caRollback,
  142. caRollbackRetaining);
  143. TSQLTransaction = class (TDBTransaction)
  144. private
  145. FTrans : TSQLHandle;
  146. FAction : TCommitRollbackAction;
  147. FParams : TStringList;
  148. procedure SetParams(const AValue: TStringList);
  149. protected
  150. function GetHandle : Pointer; virtual;
  151. Procedure SetDatabase (Value : TDatabase); override;
  152. Function LogEvent(EventType : TDBEventType) : Boolean;
  153. Procedure Log(EventType : TDBEventType; Const Msg : String); virtual;
  154. public
  155. procedure Commit; virtual;
  156. procedure CommitRetaining; virtual;
  157. procedure Rollback; virtual;
  158. procedure RollbackRetaining; virtual;
  159. procedure StartTransaction; override;
  160. constructor Create(AOwner : TComponent); override;
  161. destructor Destroy; override;
  162. property Handle: Pointer read GetHandle;
  163. procedure EndTransaction; override;
  164. published
  165. property Action : TCommitRollbackAction read FAction write FAction;
  166. property Database;
  167. property Params : TStringList read FParams write SetParams;
  168. end;
  169. { TCustomSQLQuery }
  170. TCustomSQLQuery = class (TCustomBufDataset)
  171. private
  172. FCursor : TSQLCursor;
  173. FUpdateable : boolean;
  174. FTableName : string;
  175. FSQL : TStringList;
  176. FUpdateSQL,
  177. FInsertSQL,
  178. FDeleteSQL : TStringList;
  179. FIsEOF : boolean;
  180. FLoadingFieldDefs : boolean;
  181. FReadOnly : boolean;
  182. FUpdateMode : TUpdateMode;
  183. FParams : TParams;
  184. FusePrimaryKeyAsKey : Boolean;
  185. FSQLBuf : String;
  186. FWhereStartPos : integer;
  187. FWhereStopPos : integer;
  188. FParseSQL : boolean;
  189. FMasterLink : TMasterParamsDatalink;
  190. // FSchemaInfo : TSchemaInfo;
  191. FServerFilterText : string;
  192. FServerFiltered : Boolean;
  193. FServerIndexDefs : TServerIndexDefs;
  194. // Used by SetSchemaType
  195. FSchemaType : TSchemaType;
  196. FSchemaObjectName : string;
  197. FSchemaPattern : string;
  198. FUpdateQry,
  199. FDeleteQry,
  200. FInsertQry : TCustomSQLQuery;
  201. procedure FreeFldBuffers;
  202. function GetServerIndexDefs: TServerIndexDefs;
  203. function GetStatementType : TStatementType;
  204. procedure SetDeleteSQL(const AValue: TStringlist);
  205. procedure SetInsertSQL(const AValue: TStringlist);
  206. procedure SetReadOnly(AValue : Boolean);
  207. procedure SetParseSQL(AValue : Boolean);
  208. procedure SetSQL(const AValue: TStringlist);
  209. procedure SetUpdateSQL(const AValue: TStringlist);
  210. procedure SetUsePrimaryKeyAsKey(AValue : Boolean);
  211. procedure SetUpdateMode(AValue : TUpdateMode);
  212. procedure OnChangeSQL(Sender : TObject);
  213. procedure OnChangeModifySQL(Sender : TObject);
  214. procedure Execute;
  215. Function SQLParser(const ASQL : string) : TStatementType;
  216. procedure ApplyFilter;
  217. Function AddFilter(SQLstr : string) : string;
  218. protected
  219. // abstract & virtual methods of TBufDataset
  220. function Fetch : boolean; override;
  221. function LoadField(FieldDef : TFieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; override;
  222. // abstract & virtual methods of TDataset
  223. procedure UpdateServerIndexDefs; virtual;
  224. procedure SetDatabase(Value : TDatabase); override;
  225. Procedure SetTransaction(Value : TDBTransaction); override;
  226. procedure InternalAddRecord(Buffer: Pointer; AAppend: Boolean); override;
  227. procedure InternalClose; override;
  228. procedure InternalInitFieldDefs; override;
  229. procedure InternalOpen; override;
  230. function GetCanModify: Boolean; override;
  231. procedure ApplyRecUpdate(UpdateKind : TUpdateKind); override;
  232. Function IsPrepared : Boolean; virtual;
  233. Procedure SetActive (Value : Boolean); override;
  234. procedure SetServerFiltered(Value: Boolean); virtual;
  235. procedure SetServerFilterText(const Value: string); virtual;
  236. Function GetDataSource : TDatasource; override;
  237. Procedure SetDataSource(AValue : TDatasource);
  238. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField); override;
  239. procedure BeforeRefreshOpenCursor; override;
  240. Function LogEvent(EventType : TDBEventType) : Boolean;
  241. Procedure Log(EventType : TDBEventType; Const Msg : String); virtual;
  242. public
  243. procedure Prepare; virtual;
  244. procedure UnPrepare; virtual;
  245. procedure ExecSQL; virtual;
  246. constructor Create(AOwner : TComponent); override;
  247. destructor Destroy; override;
  248. procedure SetSchemaInfo( ASchemaType : TSchemaType; ASchemaObjectName, ASchemaPattern : string); virtual;
  249. property Prepared : boolean read IsPrepared;
  250. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  251. function RowsAffected: TRowsCount; virtual;
  252. function ParamByName(Const AParamName : String) : TParam;
  253. protected
  254. // redeclared data set properties
  255. property Active;
  256. property Filter;
  257. property Filtered;
  258. // property FilterOptions;
  259. property BeforeOpen;
  260. property AfterOpen;
  261. property BeforeClose;
  262. property AfterClose;
  263. property BeforeInsert;
  264. property AfterInsert;
  265. property BeforeEdit;
  266. property AfterEdit;
  267. property BeforePost;
  268. property AfterPost;
  269. property BeforeCancel;
  270. property AfterCancel;
  271. property BeforeDelete;
  272. property AfterDelete;
  273. property BeforeScroll;
  274. property AfterScroll;
  275. property OnCalcFields;
  276. property OnDeleteError;
  277. property OnEditError;
  278. property OnFilterRecord;
  279. property OnNewRecord;
  280. property OnPostError;
  281. property AutoCalcFields;
  282. property Database;
  283. // protected
  284. property SchemaType : TSchemaType read FSchemaType default stNoSchema;
  285. property Transaction;
  286. property ReadOnly : Boolean read FReadOnly write SetReadOnly default false;
  287. property SQL : TStringlist read FSQL write SetSQL;
  288. property UpdateSQL : TStringlist read FUpdateSQL write SetUpdateSQL;
  289. property InsertSQL : TStringlist read FInsertSQL write SetInsertSQL;
  290. property DeleteSQL : TStringlist read FDeleteSQL write SetDeleteSQL;
  291. property Params : TParams read FParams write FParams;
  292. property UpdateMode : TUpdateMode read FUpdateMode write SetUpdateMode default upWhereKeyOnly;
  293. property UsePrimaryKeyAsKey : boolean read FUsePrimaryKeyAsKey write SetUsePrimaryKeyAsKey default true;
  294. property StatementType : TStatementType read GetStatementType;
  295. property ParseSQL : Boolean read FParseSQL write SetParseSQL default true;
  296. Property DataSource : TDatasource Read GetDataSource Write SetDatasource;
  297. property ServerFilter: string read FServerFilterText write SetServerFilterText;
  298. property ServerFiltered: Boolean read FServerFiltered write SetServerFiltered default False;
  299. property ServerIndexDefs : TServerIndexDefs read GetServerIndexDefs;
  300. end;
  301. { TSQLQuery }
  302. TSQLQuery = Class(TCustomSQLQuery)
  303. public
  304. property SchemaType;
  305. Published
  306. property MaxIndexesCount;
  307. // TDataset stuff
  308. property FieldDefs;
  309. Property Active;
  310. Property AutoCalcFields;
  311. Property Filter;
  312. Property Filtered;
  313. Property AfterCancel;
  314. Property AfterClose;
  315. Property AfterDelete;
  316. Property AfterEdit;
  317. Property AfterInsert;
  318. Property AfterOpen;
  319. Property AfterPost;
  320. Property AfterScroll;
  321. Property BeforeCancel;
  322. Property BeforeClose;
  323. Property BeforeDelete;
  324. Property BeforeEdit;
  325. Property BeforeInsert;
  326. Property BeforeOpen;
  327. Property BeforePost;
  328. Property BeforeScroll;
  329. Property OnCalcFields;
  330. Property OnDeleteError;
  331. Property OnEditError;
  332. Property OnFilterRecord;
  333. Property OnNewRecord;
  334. Property OnPostError;
  335. // property SchemaInfo default stNoSchema;
  336. property Database;
  337. property Transaction;
  338. property ReadOnly;
  339. property SQL;
  340. property UpdateSQL;
  341. property InsertSQL;
  342. property DeleteSQL;
  343. property IndexDefs;
  344. property Params;
  345. property UpdateMode;
  346. property UsePrimaryKeyAsKey;
  347. property ParseSQL;
  348. Property DataSource;
  349. property ServerFilter;
  350. property ServerFiltered;
  351. property ServerIndexDefs;
  352. end;
  353. { TSQLScript }
  354. TSQLScript = class (TCustomSQLscript)
  355. private
  356. FOnDirective: TSQLScriptDirectiveEvent;
  357. FQuery : TCustomSQLQuery;
  358. FDatabase : TDatabase;
  359. FTransaction : TDBTransaction;
  360. protected
  361. procedure ExecuteStatement (SQLStatement: TStrings; var StopExecution: Boolean); override;
  362. procedure ExecuteDirective (Directive, Argument: String; var StopExecution: Boolean); override;
  363. procedure ExecuteCommit; override;
  364. Procedure SetDatabase (Value : TDatabase); virtual;
  365. Procedure SetTransaction(Value : TDBTransaction); virtual;
  366. Procedure CheckDatabase;
  367. public
  368. constructor Create(AOwner : TComponent); override;
  369. destructor Destroy; override;
  370. procedure Execute; override;
  371. procedure ExecuteScript;
  372. published
  373. Property DataBase : TDatabase Read FDatabase Write SetDatabase;
  374. Property Transaction : TDBTransaction Read FTransaction Write SetTransaction;
  375. property OnDirective: TSQLScriptDirectiveEvent read FOnDirective write FOnDirective;
  376. property Directives;
  377. property Defines;
  378. property Script;
  379. property Terminator;
  380. property CommentsinSQL;
  381. property UseSetTerm;
  382. property UseCommit;
  383. property UseDefines;
  384. property OnException;
  385. end;
  386. { TSQLConnector }
  387. TSQLConnector = Class(TSQLConnection)
  388. private
  389. FProxy : TSQLConnection;
  390. FConnectorType: String;
  391. procedure SetConnectorType(const AValue: String);
  392. protected
  393. procedure SetTransaction(Value : TSQLTransaction);override;
  394. procedure DoInternalConnect; override;
  395. procedure DoInternalDisconnect; override;
  396. Procedure CheckProxy;
  397. Procedure CreateProxy; virtual;
  398. Procedure FreeProxy; virtual;
  399. function StrToStatementType(s : string) : TStatementType; override;
  400. function GetAsSQLText(Field : TField) : string; overload; override;
  401. function GetAsSQLText(Param : TParam) : string; overload; override;
  402. function GetHandle : pointer; override;
  403. Function AllocateCursorHandle : TSQLCursor; override;
  404. Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); override;
  405. Function AllocateTransactionHandle : TSQLHandle; override;
  406. procedure PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams); override;
  407. procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams); override;
  408. function Fetch(cursor : TSQLCursor) : boolean; override;
  409. procedure AddFieldDefs(cursor: TSQLCursor; FieldDefs : TfieldDefs); override;
  410. procedure UnPrepareStatement(cursor : TSQLCursor); override;
  411. procedure FreeFldBuffers(cursor : TSQLCursor); override;
  412. function LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; override;
  413. function RowsAffected(cursor: TSQLCursor): TRowsCount; override;
  414. function GetTransactionHandle(trans : TSQLHandle): pointer; override;
  415. function Commit(trans : TSQLHandle) : boolean; override;
  416. function RollBack(trans : TSQLHandle) : boolean; override;
  417. function StartdbTransaction(trans : TSQLHandle; aParams : string) : boolean; override;
  418. procedure CommitRetaining(trans : TSQLHandle); override;
  419. procedure RollBackRetaining(trans : TSQLHandle); override;
  420. procedure UpdateIndexDefs(IndexDefs : TIndexDefs;TableName : string); override;
  421. function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; override;
  422. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction : TSQLTransaction); override;
  423. Property Proxy : TSQLConnection Read FProxy;
  424. Published
  425. Property ConnectorType : String Read FConnectorType Write SetConnectorType;
  426. end;
  427. TSQLConnectionClass = Class of TSQLConnection;
  428. { TConnectionDef }
  429. TConnectionDef = Class(TPersistent)
  430. Class Function TypeName : String; virtual;
  431. Class Function ConnectionClass : TSQLConnectionClass; virtual;
  432. Class Function Description : String; virtual;
  433. Procedure ApplyParams(Params : TStrings; AConnection : TSQLConnection); virtual;
  434. end;
  435. TConnectionDefClass = class of TConnectionDef;
  436. Var
  437. GlobalDBLogHook : TDBLogNotifyEvent;
  438. Procedure RegisterConnection(Def : TConnectionDefClass);
  439. Procedure UnRegisterConnection(Def : TConnectionDefClass);
  440. Procedure UnRegisterConnection(ConnectionName : String);
  441. Function GetConnectionDef(ConnectorName : String) : TConnectionDef;
  442. Procedure GetConnectionList(List : TSTrings);
  443. const DefaultSQLFormatSettings : TFormatSettings = (
  444. CurrencyFormat: 1;
  445. NegCurrFormat: 5;
  446. ThousandSeparator: #0;
  447. DecimalSeparator: '.';
  448. CurrencyDecimals: 2;
  449. DateSeparator: '-';
  450. TimeSeparator: ':';
  451. ListSeparator: ' ';
  452. CurrencyString: '$';
  453. ShortDateFormat: 'yyyy-mm-dd';
  454. LongDateFormat: '';
  455. TimeAMString: '';
  456. TimePMString: '';
  457. ShortTimeFormat: 'hh:nn:ss';
  458. LongTimeFormat: 'hh:nn:ss';
  459. ShortMonthNames: ('','','','','','','','','','','','');
  460. LongMonthNames: ('','','','','','','','','','','','');
  461. ShortDayNames: ('','','','','','','');
  462. LongDayNames: ('','','','','','','');
  463. TwoDigitYearCenturyWindow: 50;
  464. );
  465. implementation
  466. uses dbconst, strutils;
  467. function TimeIntervalToString(Time: TDateTime): string;
  468. var
  469. millisecond: word;
  470. second : word;
  471. minute : word;
  472. hour : word;
  473. begin
  474. DecodeTime(Time,hour,minute,second,millisecond);
  475. hour := hour + (trunc(Time) * 24);
  476. result := Format('%.2d:%.2d:%.2d.%.3d',[hour,minute,second,millisecond]);
  477. end;
  478. { TSQLConnection }
  479. function TSQLConnection.StrToStatementType(s : string) : TStatementType;
  480. var T : TStatementType;
  481. begin
  482. S:=Lowercase(s);
  483. For t:=stselect to strollback do
  484. if (S=StatementTokens[t]) then
  485. Exit(t);
  486. end;
  487. procedure TSQLConnection.SetTransaction(Value : TSQLTransaction);
  488. begin
  489. if FTransaction<>value then
  490. begin
  491. if Assigned(FTransaction) and FTransaction.Active then
  492. DatabaseError(SErrAssTransaction);
  493. if Assigned(Value) then
  494. Value.Database := Self;
  495. FTransaction := Value;
  496. If Assigned(FTransaction) and (FTransaction.Database=Nil) then
  497. FTransaction.Database:=Self;
  498. end;
  499. end;
  500. procedure TSQLConnection.UpdateIndexDefs(IndexDefs : TIndexDefs;TableName : string);
  501. begin
  502. // Empty abstract
  503. end;
  504. procedure TSQLConnection.DoInternalConnect;
  505. begin
  506. if (DatabaseName = '') then
  507. DatabaseError(SErrNoDatabaseName,self);
  508. end;
  509. procedure TSQLConnection.DoInternalDisconnect;
  510. begin
  511. end;
  512. destructor TSQLConnection.Destroy;
  513. begin
  514. inherited Destroy;
  515. end;
  516. procedure TSQLConnection.StartTransaction;
  517. begin
  518. if not assigned(Transaction) then
  519. DatabaseError(SErrConnTransactionnSet)
  520. else
  521. Transaction.StartTransaction;
  522. end;
  523. procedure TSQLConnection.EndTransaction;
  524. begin
  525. if not assigned(Transaction) then
  526. DatabaseError(SErrConnTransactionnSet)
  527. else
  528. Transaction.EndTransaction;
  529. end;
  530. Procedure TSQLConnection.ExecuteDirect(SQL: String);
  531. begin
  532. ExecuteDirect(SQL,FTransaction);
  533. end;
  534. Procedure TSQLConnection.ExecuteDirect(SQL: String; ATransaction : TSQLTransaction);
  535. var Cursor : TSQLCursor;
  536. begin
  537. if not assigned(ATransaction) then
  538. DatabaseError(SErrTransactionnSet);
  539. if not Connected then Open;
  540. if not ATransaction.Active then ATransaction.StartTransaction;
  541. try
  542. SQL := TrimRight(SQL);
  543. if SQL = '' then
  544. DatabaseError(SErrNoStatement);
  545. Cursor := AllocateCursorHandle;
  546. Cursor.FStatementType := stNone;
  547. PrepareStatement(cursor,ATransaction,SQL,Nil);
  548. execute(cursor,ATransaction, Nil);
  549. UnPrepareStatement(Cursor);
  550. finally;
  551. DeAllocateCursorHandle(Cursor);
  552. end;
  553. end;
  554. function TSQLConnection.GetPort: cardinal;
  555. begin
  556. result := StrToIntDef(Params.Values['Port'],0);
  557. end;
  558. procedure TSQLConnection.Setport(const AValue: cardinal);
  559. begin
  560. if AValue<>0 then
  561. params.Values['Port']:=IntToStr(AValue)
  562. else with params do if IndexOfName('Port') > -1 then
  563. Delete(IndexOfName('Port'));
  564. end;
  565. procedure TSQLConnection.GetDBInfo(const ASchemaType : TSchemaType; const ASchemaObjectName, AReturnField : string; AList: TStrings);
  566. var qry : TCustomSQLQuery;
  567. begin
  568. if not assigned(Transaction) then
  569. DatabaseError(SErrConnTransactionnSet);
  570. qry := TCustomSQLQuery.Create(nil);
  571. qry.transaction := Transaction;
  572. qry.database := Self;
  573. with qry do
  574. begin
  575. ParseSQL := False;
  576. SetSchemaInfo(ASchemaType,ASchemaObjectName,'');
  577. open;
  578. AList.Clear;
  579. while not eof do
  580. begin
  581. AList.Append(trim(fieldbyname(AReturnField).asstring));
  582. Next;
  583. end;
  584. end;
  585. qry.free;
  586. end;
  587. function TSQLConnection.RowsAffected(cursor: TSQLCursor): TRowsCount;
  588. begin
  589. Result := -1;
  590. end;
  591. constructor TSQLConnection.Create(AOwner: TComponent);
  592. begin
  593. inherited Create(AOwner);
  594. FSQLFormatSettings:=DefaultSQLFormatSettings;
  595. FFieldNameQuoteChars:=DoubleQuotes;
  596. end;
  597. procedure TSQLConnection.GetTableNames(List: TStrings; SystemTables: Boolean);
  598. begin
  599. if not systemtables then GetDBInfo(stTables,'','table_name',List)
  600. else GetDBInfo(stSysTables,'','table_name',List);
  601. end;
  602. procedure TSQLConnection.GetProcedureNames(List: TStrings);
  603. begin
  604. GetDBInfo(stProcedures,'','proc_name',List);
  605. end;
  606. procedure TSQLConnection.GetFieldNames(const TableName: string; List: TStrings);
  607. begin
  608. GetDBInfo(stColumns,TableName,'column_name',List);
  609. end;
  610. function TSQLConnection.GetAsSQLText(Field : TField) : string;
  611. begin
  612. if (not assigned(field)) or field.IsNull then Result := 'Null'
  613. else case field.DataType of
  614. ftString : Result := '''' + field.asstring + '''';
  615. ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Field.AsDateTime,FSqlFormatSettings) + '''';
  616. ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:nn:ss',Field.AsDateTime,FSqlFormatSettings) + '''';
  617. ftTime : Result := QuotedStr(TimeIntervalToString(Field.AsDateTime));
  618. else
  619. Result := field.asstring;
  620. end; {case}
  621. end;
  622. function TSQLConnection.GetAsSQLText(Param: TParam) : string;
  623. begin
  624. if (not assigned(param)) or param.IsNull then Result := 'Null'
  625. else case param.DataType of
  626. ftGuid,
  627. ftMemo,
  628. ftFixedChar,
  629. ftString : Result := QuotedStr(Param.AsString);
  630. ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Param.AsDateTime,FSQLFormatSettings) + '''';
  631. ftTime : Result := QuotedStr(TimeIntervalToString(Param.AsDateTime));
  632. ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:nn:ss', Param.AsDateTime, FSQLFormatSettings) + '''';
  633. ftCurrency,
  634. ftBcd : Result := CurrToStr(Param.AsCurrency, FSQLFormatSettings);
  635. ftFloat : Result := FloatToStr(Param.AsFloat, FSQLFormatSettings);
  636. ftFMTBcd : Result := stringreplace(Param.AsString, DefaultFormatSettings.DecimalSeparator, FSQLFormatSettings.DecimalSeparator, []);
  637. else
  638. Result := Param.asstring;
  639. end; {case}
  640. end;
  641. function TSQLConnection.GetHandle: pointer;
  642. begin
  643. Result := nil;
  644. end;
  645. function TSQLConnection.LogEvent(EventType: TDBEventType): Boolean;
  646. begin
  647. Result:=(Assigned(FOnLog) or Assigned(GlobalDBLogHook)) and (EventType in LogEvents);
  648. end;
  649. procedure TSQLConnection.Log(EventType: TDBEventType; const Msg: String);
  650. Var
  651. M : String;
  652. begin
  653. If LogEvent(EventType) then
  654. begin
  655. If Assigned(FonLog) then
  656. FOnLog(Self,EventType,Msg);
  657. If Assigned(GlobalDBLogHook) then
  658. begin
  659. If (Name<>'') then
  660. M:=Name+' : '+Msg
  661. else
  662. M:=ClassName+' : '+Msg;
  663. GlobalDBLogHook(Self,EventType,M);
  664. end;
  665. end;
  666. end;
  667. procedure TSQLConnection.FreeFldBuffers(cursor: TSQLCursor);
  668. begin
  669. // empty
  670. end;
  671. function TSQLConnection.GetSchemaInfoSQL( SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string;
  672. begin
  673. DatabaseError(SMetadataUnavailable);
  674. end;
  675. procedure TSQLConnection.CreateDB;
  676. begin
  677. DatabaseError(SNotSupported);
  678. end;
  679. procedure TSQLConnection.DropDB;
  680. begin
  681. DatabaseError(SNotSupported);
  682. end;
  683. { TSQLTransaction }
  684. procedure TSQLTransaction.EndTransaction;
  685. begin
  686. rollback;
  687. end;
  688. procedure TSQLTransaction.SetParams(const AValue: TStringList);
  689. begin
  690. FParams.Assign(AValue);
  691. end;
  692. function TSQLTransaction.GetHandle: pointer;
  693. begin
  694. Result := TSQLConnection(Database).GetTransactionHandle(FTrans);
  695. end;
  696. procedure TSQLTransaction.Commit;
  697. begin
  698. if active then
  699. begin
  700. closedatasets;
  701. If LogEvent(detCommit) then
  702. Log(detCommit,SCommitting);
  703. if TSQLConnection(Database).commit(FTrans) then
  704. begin
  705. closeTrans;
  706. FreeAndNil(FTrans);
  707. end;
  708. end;
  709. end;
  710. procedure TSQLTransaction.CommitRetaining;
  711. begin
  712. if active then
  713. begin
  714. If LogEvent(detCommit) then
  715. Log(detCommit,SCommitRetaining);
  716. TSQLConnection(Database).commitRetaining(FTrans);
  717. end;
  718. end;
  719. procedure TSQLTransaction.Rollback;
  720. begin
  721. if active then
  722. begin
  723. closedatasets;
  724. If LogEvent(detRollback) then
  725. Log(detRollback,SRollingBack);
  726. if TSQLConnection(Database).RollBack(FTrans) then
  727. begin
  728. CloseTrans;
  729. FreeAndNil(FTrans);
  730. end;
  731. end;
  732. end;
  733. procedure TSQLTransaction.RollbackRetaining;
  734. begin
  735. if active then
  736. begin
  737. If LogEvent(detRollback) then
  738. Log(detRollback,SRollBackRetaining);
  739. TSQLConnection(Database).RollBackRetaining(FTrans);
  740. end;
  741. end;
  742. procedure TSQLTransaction.StartTransaction;
  743. var db : TSQLConnection;
  744. begin
  745. if Active then
  746. DatabaseError(SErrTransAlreadyActive);
  747. db := TSQLConnection(Database);
  748. if Db = nil then
  749. DatabaseError(SErrDatabasenAssigned);
  750. if not Db.Connected then
  751. Db.Open;
  752. if not assigned(FTrans) then FTrans := Db.AllocateTransactionHandle;
  753. if Db.StartdbTransaction(FTrans,FParams.CommaText) then OpenTrans;
  754. end;
  755. constructor TSQLTransaction.Create(AOwner : TComponent);
  756. begin
  757. inherited Create(AOwner);
  758. FParams := TStringList.Create;
  759. end;
  760. destructor TSQLTransaction.Destroy;
  761. begin
  762. Rollback;
  763. FreeAndNil(FParams);
  764. inherited Destroy;
  765. end;
  766. Procedure TSQLTransaction.SetDatabase(Value : TDatabase);
  767. begin
  768. If Value<>Database then
  769. begin
  770. if assigned(value) and not (Value is TSQLConnection) then
  771. DatabaseErrorFmt(SErrNotASQLConnection,[value.Name],self);
  772. CheckInactive;
  773. If Assigned(Database) then
  774. with TSQLConnection(DataBase) do
  775. if Transaction = self then Transaction := nil;
  776. inherited SetDatabase(Value);
  777. If Assigned(Database) and not (csLoading in ComponentState) then
  778. If (TSQLConnection(DataBase).Transaction=Nil) then
  779. TSQLConnection(DataBase).Transaction:=Self;
  780. end;
  781. end;
  782. function TSQLTransaction.LogEvent(EventType: TDBEventType): Boolean;
  783. begin
  784. Result:=Assigned(Database) and TSQLConnection(Database).LogEvent(EventType);
  785. end;
  786. procedure TSQLTransaction.Log(EventType: TDBEventType; const Msg: String);
  787. Var
  788. M : String;
  789. begin
  790. If LogEVent(EventType) then
  791. begin
  792. If (Name<>'') then
  793. M:=Name+' : '+Msg
  794. else
  795. M:=Msg;
  796. TSQLConnection(Database).Log(EventType,M);
  797. end;
  798. end;
  799. { TCustomSQLQuery }
  800. procedure TCustomSQLQuery.OnChangeSQL(Sender : TObject);
  801. var ConnOptions : TConnOptions;
  802. begin
  803. UnPrepare;
  804. FSchemaType:=stNoSchema;
  805. if (FSQL <> nil) then
  806. begin
  807. if assigned(DataBase) then
  808. ConnOptions := TSQLConnection(DataBase).ConnOptions
  809. else
  810. ConnOptions := [sqEscapeRepeat,sqEscapeSlash];
  811. Fparams.ParseSQL(FSQL.Text,True, sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions,psInterbase);
  812. If Assigned(FMasterLink) then
  813. FMasterLink.RefreshParamNames;
  814. end;
  815. end;
  816. function TCustomSQLQuery.ParamByName(Const AParamName : String) : TParam;
  817. begin
  818. Result:=Params.ParamByName(AParamName);
  819. end;
  820. procedure TCustomSQLQuery.OnChangeModifySQL(Sender : TObject);
  821. begin
  822. CheckInactive;
  823. end;
  824. Procedure TCustomSQLQuery.SetTransaction(Value : TDBTransaction);
  825. begin
  826. UnPrepare;
  827. inherited;
  828. If (Transaction<>Nil) and (Database=Nil) then
  829. Database:=TSQLTransaction(Transaction).Database;
  830. end;
  831. procedure TCustomSQLQuery.SetDatabase(Value : TDatabase);
  832. var db : tsqlconnection;
  833. begin
  834. if (Database <> Value) then
  835. begin
  836. if assigned(value) and not (Value is TSQLConnection) then
  837. DatabaseErrorFmt(SErrNotASQLConnection,[value.Name],self);
  838. UnPrepare;
  839. if assigned(FCursor) then TSQLConnection(DataBase).DeAllocateCursorHandle(FCursor);
  840. db := TSQLConnection(Value);
  841. inherited setdatabase(value);
  842. if assigned(value) and (Transaction = nil) and (Assigned(db.Transaction)) then
  843. transaction := Db.Transaction;
  844. OnChangeSQL(Self);
  845. end;
  846. end;
  847. Function TCustomSQLQuery.IsPrepared : Boolean;
  848. begin
  849. Result := Assigned(FCursor) and FCursor.FPrepared;
  850. end;
  851. Function TCustomSQLQuery.AddFilter(SQLstr : string) : string;
  852. begin
  853. if (FWhereStartPos > 0) and (FWhereStopPos > 0) then
  854. begin
  855. system.insert('(',SQLstr,FWhereStartPos+1);
  856. system.insert(')',SQLstr,FWhereStopPos+1);
  857. end;
  858. if FWhereStartPos = 0 then
  859. SQLstr := SQLstr + ' where (' + Filter + ')'
  860. else if FWhereStopPos > 0 then
  861. system.insert(' and ('+ServerFilter+') ',SQLstr,FWhereStopPos+2)
  862. else
  863. system.insert(' where ('+ServerFilter+') ',SQLstr,FWhereStartPos);
  864. Result := SQLstr;
  865. end;
  866. procedure TCustomSQLQuery.ApplyFilter;
  867. var S : String;
  868. begin
  869. FreeFldBuffers;
  870. TSQLConnection(Database).UnPrepareStatement(FCursor);
  871. FIsEOF := False;
  872. inherited internalclose;
  873. s := FSQLBuf;
  874. if ServerFiltered then s := AddFilter(s);
  875. TSQLConnection(Database).PrepareStatement(Fcursor,(transaction as tsqltransaction),S,FParams);
  876. Execute;
  877. inherited InternalOpen;
  878. First;
  879. end;
  880. Procedure TCustomSQLQuery.SetActive (Value : Boolean);
  881. begin
  882. inherited SetActive(Value);
  883. // The query is UnPrepared, so that if a transaction closes all datasets
  884. // they also get unprepared
  885. if not Value and IsPrepared then UnPrepare;
  886. end;
  887. procedure TCustomSQLQuery.SetServerFiltered(Value: Boolean);
  888. begin
  889. if Value and not FParseSQL then DatabaseErrorFmt(SNoParseSQL,['Filtering ']);
  890. if (ServerFiltered <> Value) then
  891. begin
  892. FServerFiltered := Value;
  893. if active then ApplyFilter;
  894. end;
  895. end;
  896. procedure TCustomSQLQuery.SetServerFilterText(const Value: string);
  897. begin
  898. if Value <> ServerFilter then
  899. begin
  900. FServerFilterText := Value;
  901. if active then ApplyFilter;
  902. end;
  903. end;
  904. procedure TCustomSQLQuery.Prepare;
  905. var
  906. db : tsqlconnection;
  907. sqltr : tsqltransaction;
  908. StmType: TStatementType;
  909. begin
  910. if not IsPrepared then
  911. begin
  912. db := TSQLConnection(Database);
  913. sqltr := (transaction as tsqltransaction);
  914. if not assigned(Db) then
  915. DatabaseError(SErrDatabasenAssigned);
  916. if not assigned(sqltr) then
  917. DatabaseError(SErrTransactionnSet);
  918. if not Db.Connected then db.Open;
  919. if not sqltr.Active then sqltr.StartTransaction;
  920. if FSchemaType=stNoSchema then
  921. FSQLBuf := TrimRight(FSQL.Text)
  922. else
  923. FSQLBuf := db.GetSchemaInfoSQL(FSchemaType, FSchemaObjectName, FSchemaPattern);
  924. if FSQLBuf = '' then
  925. DatabaseError(SErrNoStatement);
  926. StmType:=SQLParser(FSQLBuf);
  927. // There may no error occur between the allocation of the cursor and
  928. // the preparation of the cursor. Because internalclose (which is called in
  929. // case of an exception) assumes that allocated cursors are also prepared,
  930. // and thus calls unprepare.
  931. // A call to unprepare while the cursor is not prepared at all can lead to
  932. // unpredictable results.
  933. if not assigned(fcursor) then
  934. FCursor := Db.AllocateCursorHandle;
  935. FCursor.FStatementType:=StmType;
  936. FCursor.FSchemaType := FSchemaType;
  937. if ServerFiltered then
  938. begin
  939. If LogEvent(detprepare) then
  940. Log(detPrepare,AddFilter(FSQLBuf));
  941. Db.PrepareStatement(Fcursor,sqltr,AddFilter(FSQLBuf),FParams)
  942. end
  943. else
  944. begin
  945. If LogEvent(detprepare) then
  946. Log(detPrepare,FSQLBuf);
  947. Db.PrepareStatement(Fcursor,sqltr,FSQLBuf,FParams);
  948. end;
  949. if (FCursor.FStatementType in [stSelect,stExecProcedure]) then
  950. FCursor.FInitFieldDef := True;
  951. end;
  952. end;
  953. procedure TCustomSQLQuery.UnPrepare;
  954. begin
  955. CheckInactive;
  956. if IsPrepared then with TSQLConnection(DataBase) do
  957. UnPrepareStatement(FCursor);
  958. end;
  959. procedure TCustomSQLQuery.FreeFldBuffers;
  960. begin
  961. if assigned(FCursor) then TSQLConnection(Database).FreeFldBuffers(FCursor);
  962. end;
  963. function TCustomSQLQuery.GetServerIndexDefs: TServerIndexDefs;
  964. begin
  965. Result := FServerIndexDefs;
  966. end;
  967. function TCustomSQLQuery.Fetch : boolean;
  968. begin
  969. if not (Fcursor.FStatementType in [stSelect,stExecProcedure]) then
  970. Exit;
  971. if not FIsEof then FIsEOF := not TSQLConnection(Database).Fetch(Fcursor);
  972. Result := not FIsEOF;
  973. // A stored procedure is always at EOF after its first fetch
  974. if FCursor.FStatementType = stExecProcedure then FIsEOF := True;
  975. end;
  976. procedure TCustomSQLQuery.Execute;
  977. begin
  978. If (FParams.Count>0) and Assigned(FMasterLink) then
  979. FMasterLink.CopyParamsFromMaster(False);
  980. If LogEvent(detExecute) then
  981. Log(detExecute,FSQLBuf);
  982. TSQLConnection(Database).execute(Fcursor,Transaction as tsqltransaction, FParams);
  983. end;
  984. function TCustomSQLQuery.LoadField(FieldDef : TFieldDef;buffer : pointer; out CreateBlob : boolean) : boolean;
  985. begin
  986. result := TSQLConnection(Database).LoadField(FCursor,FieldDef,buffer, Createblob)
  987. end;
  988. function TCustomSQLQuery.RowsAffected: TRowsCount;
  989. begin
  990. Result := -1;
  991. if not Assigned(Database) then Exit;
  992. //assert(Database is TSQLConnection);
  993. Result := TSQLConnection(Database).RowsAffected(FCursor);
  994. end;
  995. procedure TCustomSQLQuery.InternalAddRecord(Buffer: Pointer; AAppend: Boolean);
  996. begin
  997. // not implemented - sql dataset
  998. end;
  999. procedure TCustomSQLQuery.InternalClose;
  1000. begin
  1001. if not IsReadFromPacket then
  1002. begin
  1003. if StatementType in [stSelect,stExecProcedure] then FreeFldBuffers;
  1004. // Database and FCursor could be nil, for example if the database is not assigned, and .open is called
  1005. if (not IsPrepared) and (assigned(database)) and (assigned(FCursor)) then TSQLConnection(database).UnPrepareStatement(FCursor);
  1006. end;
  1007. if DefaultFields then
  1008. DestroyFields;
  1009. FIsEOF := False;
  1010. if assigned(FUpdateQry) then FreeAndNil(FUpdateQry);
  1011. if assigned(FInsertQry) then FreeAndNil(FInsertQry);
  1012. if assigned(FDeleteQry) then FreeAndNil(FDeleteQry);
  1013. // FRecordSize := 0;
  1014. inherited internalclose;
  1015. end;
  1016. procedure TCustomSQLQuery.InternalInitFieldDefs;
  1017. begin
  1018. if FLoadingFieldDefs then
  1019. Exit;
  1020. FLoadingFieldDefs := True;
  1021. try
  1022. FieldDefs.Clear;
  1023. if not Assigned(Database) then DatabaseError(SErrDatabasenAssigned);
  1024. TSQLConnection(Database).AddFieldDefs(fcursor,FieldDefs);
  1025. finally
  1026. FLoadingFieldDefs := False;
  1027. if Assigned(FCursor) then FCursor.FInitFieldDef := false;
  1028. end;
  1029. end;
  1030. function TCustomSQLQuery.SQLParser(const ASQL : string) : TStatementType;
  1031. type TParsePart = (ppStart,ppSelect,ppWhere,ppFrom,ppOrder,ppComment,ppGroup,ppBogus);
  1032. Var
  1033. PSQL,CurrentP,
  1034. PhraseP, PStatementPart : pchar;
  1035. S : string;
  1036. ParsePart : TParsePart;
  1037. StrLength : Integer;
  1038. EndOfComment : Boolean;
  1039. BracketCount : Integer;
  1040. ConnOptions : TConnOptions;
  1041. FFromPart : String;
  1042. begin
  1043. PSQL:=Pchar(ASQL);
  1044. ParsePart := ppStart;
  1045. CurrentP := PSQL-1;
  1046. PhraseP := PSQL;
  1047. FWhereStartPos := 0;
  1048. FWhereStopPos := 0;
  1049. ConnOptions := TSQLConnection(DataBase).ConnOptions;
  1050. FUpdateable := False;
  1051. repeat
  1052. begin
  1053. inc(CurrentP);
  1054. EndOfComment := SkipComments(CurrentP,sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions);
  1055. if EndOfcomment then dec(currentp);
  1056. if EndOfComment and (ParsePart = ppStart) then PhraseP := CurrentP;
  1057. // skip everything between bracket, since it could be a sub-select, and
  1058. // further nothing between brackets could be interesting for the parser.
  1059. if currentp^='(' then
  1060. begin
  1061. inc(currentp);
  1062. BracketCount := 0;
  1063. while (currentp^ <> #0) and ((currentp^ <> ')') or (BracketCount > 0 )) do
  1064. begin
  1065. if currentp^ = '(' then inc(bracketcount)
  1066. else if currentp^ = ')' then dec(bracketcount);
  1067. inc(currentp);
  1068. end;
  1069. EndOfComment := True;
  1070. end;
  1071. if EndOfComment or (CurrentP^ in [' ',#13,#10,#9,#0,';']) then
  1072. begin
  1073. if (CurrentP-PhraseP > 0) or (CurrentP^ in [';',#0]) then
  1074. begin
  1075. strLength := CurrentP-PhraseP;
  1076. Setlength(S,strLength);
  1077. if strLength > 0 then Move(PhraseP^,S[1],(strLength));
  1078. s := uppercase(s);
  1079. case ParsePart of
  1080. ppStart : begin
  1081. Result := TSQLConnection(Database).StrToStatementType(s);
  1082. if Result = stSelect then ParsePart := ppSelect
  1083. else break;
  1084. if not FParseSQL then break;
  1085. PStatementPart := CurrentP;
  1086. end;
  1087. ppSelect : begin
  1088. if s = 'FROM' then
  1089. begin
  1090. ParsePart := ppFrom;
  1091. PhraseP := CurrentP;
  1092. PStatementPart := CurrentP;
  1093. end;
  1094. end;
  1095. ppFrom : begin
  1096. if (s = 'WHERE') or (s = 'ORDER') or (s = 'GROUP') or (s = 'LIMIT') or (CurrentP^=#0) or (CurrentP^=';') then
  1097. begin
  1098. if (s = 'WHERE') then
  1099. begin
  1100. ParsePart := ppWhere;
  1101. StrLength := PhraseP-PStatementPart;
  1102. end
  1103. else if (s = 'GROUP') then
  1104. begin
  1105. ParsePart := ppGroup;
  1106. StrLength := PhraseP-PStatementPart;
  1107. end
  1108. else if (s = 'ORDER') then
  1109. begin
  1110. ParsePart := ppOrder;
  1111. StrLength := PhraseP-PStatementPart
  1112. end
  1113. else if (s = 'LIMIT') then
  1114. begin
  1115. ParsePart := ppBogus;
  1116. StrLength := PhraseP-PStatementPart
  1117. end
  1118. else
  1119. begin
  1120. ParsePart := ppBogus;
  1121. StrLength := CurrentP-PStatementPart;
  1122. end;
  1123. if Result = stSelect then
  1124. begin
  1125. Setlength(FFromPart,StrLength);
  1126. Move(PStatementPart^,FFromPart[1],(StrLength));
  1127. FFrompart := trim(FFrompart);
  1128. // Meta-data requests and are never updateable select-statements
  1129. // from more then one table are not updateable
  1130. if (FSchemaType=stNoSchema) and
  1131. (ExtractStrings([',',' '],[],pchar(FFromPart),nil) = 1) then
  1132. begin
  1133. FUpdateable := True;
  1134. FTableName := FFromPart;
  1135. end;
  1136. end;
  1137. FWhereStartPos := PStatementPart-PSQL+StrLength+1;
  1138. PStatementPart := CurrentP;
  1139. end;
  1140. end;
  1141. ppWhere : begin
  1142. if (s = 'ORDER') or (s = 'GROUP') or (s = 'LIMIT') or (CurrentP^=#0) or (CurrentP^=';') then
  1143. begin
  1144. ParsePart := ppBogus;
  1145. FWhereStartPos := PStatementPart-PSQL;
  1146. if (s = 'ORDER') or (s = 'GROUP') or (s = 'LIMIT') then
  1147. FWhereStopPos := PhraseP-PSQL+1
  1148. else
  1149. FWhereStopPos := CurrentP-PSQL+1;
  1150. end
  1151. else if (s = 'UNION') then
  1152. begin
  1153. ParsePart := ppBogus;
  1154. FUpdateable := False;
  1155. end;
  1156. end;
  1157. end; {case}
  1158. end;
  1159. PhraseP := CurrentP+1;
  1160. end
  1161. end;
  1162. until CurrentP^=#0;
  1163. end;
  1164. procedure TCustomSQLQuery.InternalOpen;
  1165. var tel, fieldc : integer;
  1166. f : TField;
  1167. s : string;
  1168. IndexFields : TStrings;
  1169. ReadFromFile: Boolean;
  1170. begin
  1171. ReadFromFile:=IsReadFromPacket;
  1172. if ReadFromFile then
  1173. begin
  1174. if not assigned(fcursor) then
  1175. FCursor := TSQLConnection(Database).AllocateCursorHandle;
  1176. FCursor.FStatementType:=stSelect;
  1177. FUpdateable:=True;
  1178. end
  1179. else
  1180. Prepare;
  1181. if FCursor.FStatementType in [stSelect,stExecProcedure] then
  1182. begin
  1183. if not ReadFromFile then
  1184. begin
  1185. // Call UpdateServerIndexDefs before Execute, to avoid problems with connections
  1186. // which do not allow processing multiple recordsets at a time. (Microsoft
  1187. // calls this MARS, see bug 13241)
  1188. if DefaultFields and FUpdateable and FusePrimaryKeyAsKey and (not IsUniDirectional) then
  1189. UpdateServerIndexDefs;
  1190. Execute;
  1191. // InternalInitFieldDef is only called after a prepare. i.e. not twice if
  1192. // a dataset is opened - closed - opened.
  1193. if FCursor.FInitFieldDef then InternalInitFieldDefs;
  1194. if DefaultFields then
  1195. begin
  1196. CreateFields;
  1197. if FUpdateable and (not IsUniDirectional) then
  1198. begin
  1199. if FusePrimaryKeyAsKey then
  1200. begin
  1201. for tel := 0 to ServerIndexDefs.count-1 do
  1202. begin
  1203. if ixPrimary in ServerIndexDefs[tel].options then
  1204. begin
  1205. IndexFields := TStringList.Create;
  1206. ExtractStrings([';'],[' '],pchar(ServerIndexDefs[tel].fields),IndexFields);
  1207. for fieldc := 0 to IndexFields.Count-1 do
  1208. begin
  1209. F := Findfield(IndexFields[fieldc]);
  1210. if F <> nil then
  1211. F.ProviderFlags := F.ProviderFlags + [pfInKey];
  1212. end;
  1213. IndexFields.Free;
  1214. end;
  1215. end;
  1216. end;
  1217. end;
  1218. end
  1219. else
  1220. BindFields(True);
  1221. end
  1222. else
  1223. BindFields(True);
  1224. if not ReadOnly and not FUpdateable and (FSchemaType=stNoSchema) then
  1225. begin
  1226. if (trim(FDeleteSQL.Text) <> '') or (trim(FUpdateSQL.Text) <> '') or
  1227. (trim(FInsertSQL.Text) <> '') then FUpdateable := True;
  1228. end
  1229. end
  1230. else
  1231. DatabaseError(SErrNoSelectStatement,Self);
  1232. inherited InternalOpen;
  1233. end;
  1234. // public part
  1235. procedure TCustomSQLQuery.ExecSQL;
  1236. begin
  1237. try
  1238. Prepare;
  1239. Execute;
  1240. finally
  1241. // FCursor has to be assigned, or else the prepare went wrong before PrepareStatment was
  1242. // called, so UnPrepareStatement shoudn't be called either
  1243. if (not IsPrepared) and (assigned(database)) and (assigned(FCursor)) then TSQLConnection(database).UnPrepareStatement(Fcursor);
  1244. end;
  1245. end;
  1246. constructor TCustomSQLQuery.Create(AOwner : TComponent);
  1247. begin
  1248. inherited Create(AOwner);
  1249. FParams := TParams.create(self);
  1250. FSQL := TStringList.Create;
  1251. FSQL.OnChange := @OnChangeSQL;
  1252. FUpdateSQL := TStringList.Create;
  1253. FUpdateSQL.OnChange := @OnChangeModifySQL;
  1254. FInsertSQL := TStringList.Create;
  1255. FInsertSQL.OnChange := @OnChangeModifySQL;
  1256. FDeleteSQL := TStringList.Create;
  1257. FDeleteSQL.OnChange := @OnChangeModifySQL;
  1258. FServerIndexDefs := TServerIndexDefs.Create(Self);
  1259. FReadOnly := false;
  1260. FParseSQL := True;
  1261. FServerFiltered := False;
  1262. FServerFilterText := '';
  1263. FSchemaType:=stNoSchema;
  1264. FSchemaObjectName:='';
  1265. FSchemaPattern:='';
  1266. // Delphi has upWhereAll as default, but since strings and oldvalue's don't work yet
  1267. // (variants) set it to upWhereKeyOnly
  1268. FUpdateMode := upWhereKeyOnly;
  1269. FUsePrimaryKeyAsKey := True;
  1270. end;
  1271. destructor TCustomSQLQuery.Destroy;
  1272. begin
  1273. if Active then Close;
  1274. UnPrepare;
  1275. if assigned(FCursor) then TSQLConnection(Database).DeAllocateCursorHandle(FCursor);
  1276. FreeAndNil(FMasterLink);
  1277. FreeAndNil(FParams);
  1278. FreeAndNil(FSQL);
  1279. FreeAndNil(FInsertSQL);
  1280. FreeAndNil(FDeleteSQL);
  1281. FreeAndNil(FUpdateSQL);
  1282. FServerIndexDefs.Free;
  1283. inherited Destroy;
  1284. end;
  1285. procedure TCustomSQLQuery.SetReadOnly(AValue : Boolean);
  1286. begin
  1287. CheckInactive;
  1288. FReadOnly:=AValue;
  1289. end;
  1290. procedure TCustomSQLQuery.SetParseSQL(AValue : Boolean);
  1291. begin
  1292. CheckInactive;
  1293. if not AValue then
  1294. begin
  1295. FServerFiltered := False;
  1296. FParseSQL := False;
  1297. end
  1298. else
  1299. FParseSQL := True;
  1300. end;
  1301. procedure TCustomSQLQuery.SetSQL(const AValue: TStringlist);
  1302. begin
  1303. FSQL.Assign(AValue);
  1304. end;
  1305. procedure TCustomSQLQuery.SetUpdateSQL(const AValue: TStringlist);
  1306. begin
  1307. FUpdateSQL.Assign(AValue);
  1308. end;
  1309. procedure TCustomSQLQuery.SetUsePrimaryKeyAsKey(AValue : Boolean);
  1310. begin
  1311. if not Active then FusePrimaryKeyAsKey := AValue
  1312. else
  1313. begin
  1314. // Just temporary, this should be possible in the future
  1315. DatabaseError(SActiveDataset);
  1316. end;
  1317. end;
  1318. Procedure TCustomSQLQuery.UpdateServerIndexDefs;
  1319. begin
  1320. FServerIndexDefs.Clear;
  1321. if assigned(DataBase) and (FTableName<>'') then
  1322. TSQLConnection(DataBase).UpdateIndexDefs(ServerIndexDefs,FTableName);
  1323. end;
  1324. Procedure TCustomSQLQuery.ApplyRecUpdate(UpdateKind : TUpdateKind);
  1325. var FieldNamesQuoteChars : TQuoteChars;
  1326. function InitialiseModifyQuery(var qry : TCustomSQLQuery): TCustomSQLQuery;
  1327. begin
  1328. if not assigned(qry) then
  1329. begin
  1330. qry := TCustomSQLQuery.Create(nil);
  1331. qry.ParseSQL := False;
  1332. qry.DataBase := Self.DataBase;
  1333. qry.Transaction := Self.Transaction;
  1334. end;
  1335. Result:=qry;
  1336. end;
  1337. procedure UpdateWherePart(var sql_where : string;x : integer);
  1338. begin
  1339. if (pfInKey in Fields[x].ProviderFlags) or
  1340. ((FUpdateMode = upWhereAll) and (pfInWhere in Fields[x].ProviderFlags)) or
  1341. ((FUpdateMode = UpWhereChanged) and (pfInWhere in Fields[x].ProviderFlags) and (Fields[x].Value <> Fields[x].OldValue)) then
  1342. if Fields[x].OldValue = NULL then
  1343. sql_where := sql_where + FieldNamesQuoteChars[0] + Fields[x].FieldName + FieldNamesQuoteChars[1] + ' is null and '
  1344. else
  1345. sql_where := sql_where + '(' + FieldNamesQuoteChars[0] + Fields[x].FieldName + FieldNamesQuoteChars[1] + '= :"' + 'OLD_' + Fields[x].FieldName + '") and ';
  1346. end;
  1347. function ModifyRecQuery : string;
  1348. var x : integer;
  1349. sql_set : string;
  1350. sql_where : string;
  1351. begin
  1352. sql_set := '';
  1353. sql_where := '';
  1354. for x := 0 to Fields.Count -1 do
  1355. begin
  1356. UpdateWherePart(sql_where,x);
  1357. if (pfInUpdate in Fields[x].ProviderFlags) then
  1358. sql_set := sql_set +FieldNamesQuoteChars[0] + fields[x].FieldName + FieldNamesQuoteChars[1] +'=:"' + fields[x].FieldName + '",';
  1359. end;
  1360. if length(sql_set) = 0 then DatabaseErrorFmt(sNoUpdateFields,['update'],self);
  1361. setlength(sql_set,length(sql_set)-1);
  1362. if length(sql_where) = 0 then DatabaseErrorFmt(sNoWhereFields,['update'],self);
  1363. setlength(sql_where,length(sql_where)-5);
  1364. result := 'update ' + FTableName + ' set ' + sql_set + ' where ' + sql_where;
  1365. end;
  1366. function InsertRecQuery : string;
  1367. var x : integer;
  1368. sql_fields : string;
  1369. sql_values : string;
  1370. begin
  1371. sql_fields := '';
  1372. sql_values := '';
  1373. for x := 0 to Fields.Count -1 do
  1374. begin
  1375. if (not fields[x].IsNull) and (pfInUpdate in Fields[x].ProviderFlags) then
  1376. begin
  1377. sql_fields := sql_fields + FieldNamesQuoteChars[0] + fields[x].FieldName + FieldNamesQuoteChars[1] + ',';
  1378. sql_values := sql_values + ':"' + fields[x].FieldName + '",';
  1379. end;
  1380. end;
  1381. if length(sql_fields) = 0 then DatabaseErrorFmt(sNoUpdateFields,['insert'],self);
  1382. setlength(sql_fields,length(sql_fields)-1);
  1383. setlength(sql_values,length(sql_values)-1);
  1384. result := 'insert into ' + FTableName + ' (' + sql_fields + ') values (' + sql_values + ')';
  1385. end;
  1386. function DeleteRecQuery : string;
  1387. var x : integer;
  1388. sql_where : string;
  1389. begin
  1390. sql_where := '';
  1391. for x := 0 to Fields.Count -1 do
  1392. UpdateWherePart(sql_where,x);
  1393. if length(sql_where) = 0 then DatabaseErrorFmt(sNoWhereFields,['delete'],self);
  1394. setlength(sql_where,length(sql_where)-5);
  1395. result := 'delete from ' + FTableName + ' where ' + sql_where;
  1396. end;
  1397. var qry : TCustomSQLQuery;
  1398. s : string;
  1399. x : integer;
  1400. Fld : TField;
  1401. begin
  1402. FieldNamesQuoteChars := TSQLConnection(DataBase).FieldNameQuoteChars;
  1403. case UpdateKind of
  1404. ukInsert : begin
  1405. s := trim(FInsertSQL.Text);
  1406. if s = '' then s := InsertRecQuery;
  1407. qry := InitialiseModifyQuery(FInsertQry);
  1408. end;
  1409. ukModify : begin
  1410. s := trim(FUpdateSQL.Text);
  1411. if (s='') and (not assigned(FUpdateQry) or (UpdateMode<>upWhereKeyOnly)) then //first time or dynamic where part
  1412. s := ModifyRecQuery;
  1413. qry := InitialiseModifyQuery(FUpdateQry);
  1414. end;
  1415. ukDelete : begin
  1416. s := trim(FDeleteSQL.Text);
  1417. if (s='') and (not assigned(FDeleteQry) or (UpdateMode<>upWhereKeyOnly)) then
  1418. s := DeleteRecQuery;
  1419. qry := InitialiseModifyQuery(FDeleteQry);
  1420. end;
  1421. end;
  1422. if (qry.SQL.Text<>s) and (s<>'') then qry.SQL.Text:=s; //assign only when changed, to avoid UnPrepare/Prepare
  1423. assert(qry.sql.Text<>'');
  1424. with qry do
  1425. begin
  1426. for x := 0 to Params.Count-1 do with params[x] do if leftstr(name,4)='OLD_' then
  1427. begin
  1428. Fld := self.FieldByName(copy(name,5,length(name)-4));
  1429. AssignFieldValue(Fld,Fld.OldValue);
  1430. end
  1431. else
  1432. begin
  1433. Fld := self.FieldByName(name);
  1434. AssignFieldValue(Fld,Fld.Value);
  1435. end;
  1436. execsql;
  1437. end;
  1438. end;
  1439. Function TCustomSQLQuery.GetCanModify: Boolean;
  1440. begin
  1441. // the test for assigned(FCursor) is needed for the case that the dataset isn't opened
  1442. if assigned(FCursor) and (FCursor.FStatementType = stSelect) then
  1443. Result:= FUpdateable and (not FReadOnly) and (not IsUniDirectional)
  1444. else
  1445. Result := False;
  1446. end;
  1447. procedure TCustomSQLQuery.SetUpdateMode(AValue : TUpdateMode);
  1448. begin
  1449. FUpdateMode := AValue;
  1450. end;
  1451. procedure TCustomSQLQuery.SetSchemaInfo( ASchemaType : TSchemaType; ASchemaObjectName, ASchemaPattern : string);
  1452. begin
  1453. FSchemaType:=ASchemaType;
  1454. FSchemaObjectName:=ASchemaObjectName;
  1455. FSchemaPattern:=ASchemaPattern;
  1456. end;
  1457. procedure TCustomSQLQuery.LoadBlobIntoBuffer(FieldDef: TFieldDef;
  1458. ABlobBuf: PBufBlobField);
  1459. begin
  1460. TSQLConnection(DataBase).LoadBlobIntoBuffer(FieldDef, ABlobBuf, FCursor,(Transaction as tsqltransaction));
  1461. end;
  1462. procedure TCustomSQLQuery.BeforeRefreshOpenCursor;
  1463. begin
  1464. // This is only necessary because TIBConnection can not re-open a
  1465. // prepared cursor. In fact this is wrong, but has never led to
  1466. // problems because in SetActive(false) queries are always
  1467. // unprepared. (which is also wrong, but has to be fixed later)
  1468. if IsPrepared then with TSQLConnection(DataBase) do
  1469. UnPrepareStatement(FCursor);
  1470. end;
  1471. function TCustomSQLQuery.LogEvent(EventType: TDBEventType): Boolean;
  1472. begin
  1473. Result:=Assigned(Database) and TSQLConnection(Database).LogEvent(EventType);
  1474. end;
  1475. procedure TCustomSQLQuery.Log(EventType: TDBEventType; const Msg: String);
  1476. Var
  1477. M : String;
  1478. begin
  1479. If LogEvent(EventType) then
  1480. begin
  1481. M:=Msg;
  1482. If (Name<>'') then
  1483. M:=Name+' : '+M;
  1484. TSQLConnection(Database).Log(EventType,M);
  1485. end;
  1486. end;
  1487. function TCustomSQLQuery.GetStatementType : TStatementType;
  1488. begin
  1489. if assigned(FCursor) then Result := FCursor.FStatementType
  1490. else Result := stNone;
  1491. end;
  1492. procedure TCustomSQLQuery.SetDeleteSQL(const AValue: TStringlist);
  1493. begin
  1494. FDeleteSQL.Assign(AValue);
  1495. end;
  1496. procedure TCustomSQLQuery.SetInsertSQL(const AValue: TStringlist);
  1497. begin
  1498. FInsertSQL.Assign(AValue);
  1499. end;
  1500. Procedure TCustomSQLQuery.SetDataSource(AVAlue : TDatasource);
  1501. Var
  1502. DS : TDatasource;
  1503. begin
  1504. DS:=DataSource;
  1505. If (AValue<>DS) then
  1506. begin
  1507. If Assigned(AValue) and (AValue.Dataset=Self) then
  1508. DatabaseError(SErrCircularDataSourceReferenceNotAllowed,Self);
  1509. If Assigned(DS) then
  1510. DS.RemoveFreeNotification(Self);
  1511. If Assigned(AValue) then
  1512. begin
  1513. AValue.FreeNotification(Self);
  1514. If (FMasterLink=Nil) then
  1515. FMasterLink:=TMasterParamsDataLink.Create(Self);
  1516. FMasterLink.Datasource:=AValue;
  1517. end
  1518. else
  1519. FreeAndNil(FMasterLink);
  1520. end;
  1521. end;
  1522. Function TCustomSQLQuery.GetDataSource : TDatasource;
  1523. begin
  1524. If Assigned(FMasterLink) then
  1525. Result:=FMasterLink.DataSource
  1526. else
  1527. Result:=Nil;
  1528. end;
  1529. procedure TCustomSQLQuery.Notification(AComponent: TComponent; Operation: TOperation);
  1530. begin
  1531. Inherited;
  1532. If (Operation=opRemove) and (AComponent=DataSource) then
  1533. DataSource:=Nil;
  1534. end;
  1535. { TSQLScript }
  1536. procedure TSQLScript.ExecuteStatement(SQLStatement: TStrings;
  1537. var StopExecution: Boolean);
  1538. begin
  1539. fquery.SQL.assign(SQLStatement);
  1540. fquery.ExecSQL;
  1541. end;
  1542. procedure TSQLScript.ExecuteDirective(Directive, Argument: String;
  1543. var StopExecution: Boolean);
  1544. begin
  1545. if assigned (FOnDirective) then
  1546. FOnDirective (Self, Directive, Argument, StopExecution);
  1547. end;
  1548. procedure TSQLScript.ExecuteCommit;
  1549. begin
  1550. if FTransaction is TSQLTransaction then
  1551. TSQLTransaction(FTransaction).CommitRetaining
  1552. else
  1553. begin
  1554. FTransaction.Active := false;
  1555. FTransaction.Active := true;
  1556. end;
  1557. end;
  1558. procedure TSQLScript.SetDatabase(Value: TDatabase);
  1559. begin
  1560. FDatabase := Value;
  1561. end;
  1562. procedure TSQLScript.SetTransaction(Value: TDBTransaction);
  1563. begin
  1564. FTransaction := Value;
  1565. end;
  1566. procedure TSQLScript.CheckDatabase;
  1567. begin
  1568. If (FDatabase=Nil) then
  1569. DatabaseError(SErrNoDatabaseAvailable,Self)
  1570. end;
  1571. constructor TSQLScript.Create(AOwner: TComponent);
  1572. begin
  1573. inherited Create(AOwner);
  1574. FQuery := TCustomSQLQuery.Create(nil);
  1575. end;
  1576. destructor TSQLScript.Destroy;
  1577. begin
  1578. FQuery.Free;
  1579. inherited Destroy;
  1580. end;
  1581. procedure TSQLScript.Execute;
  1582. begin
  1583. FQuery.DataBase := FDatabase;
  1584. FQuery.Transaction := FTransaction;
  1585. inherited Execute;
  1586. end;
  1587. procedure TSQLScript.ExecuteScript;
  1588. begin
  1589. Execute;
  1590. end;
  1591. { Connection definitions }
  1592. Var
  1593. ConnDefs : TStringList;
  1594. Procedure CheckDefs;
  1595. begin
  1596. If (ConnDefs=Nil) then
  1597. begin
  1598. ConnDefs:=TStringList.Create;
  1599. ConnDefs.Sorted:=True;
  1600. ConnDefs.Duplicates:=dupError;
  1601. end;
  1602. end;
  1603. Procedure DoneDefs;
  1604. Var
  1605. I : Integer;
  1606. begin
  1607. If Assigned(ConnDefs) then
  1608. begin
  1609. For I:=ConnDefs.Count-1 downto 0 do
  1610. begin
  1611. ConnDefs.Objects[i].Free;
  1612. ConnDefs.Delete(I);
  1613. end;
  1614. FreeAndNil(ConnDefs);
  1615. end;
  1616. end;
  1617. Function GetConnectionDef(ConnectorName : String) : TConnectionDef;
  1618. Var
  1619. I : Integer;
  1620. begin
  1621. CheckDefs;
  1622. I:=ConnDefs.IndexOf(ConnectorName);
  1623. If (I<>-1) then
  1624. Result:=TConnectionDef(ConnDefs.Objects[i])
  1625. else
  1626. Result:=Nil;
  1627. end;
  1628. procedure RegisterConnection(Def: TConnectionDefClass);
  1629. Var
  1630. I : Integer;
  1631. begin
  1632. CheckDefs;
  1633. I:=ConnDefs.IndexOf(Def.TypeName);
  1634. If (I=-1) then
  1635. ConnDefs.AddObject(Def.TypeName,Def.Create)
  1636. else
  1637. begin
  1638. ConnDefs.Objects[I].Free;
  1639. ConnDefs.Objects[I]:=Def.Create;
  1640. end;
  1641. end;
  1642. procedure UnRegisterConnection(Def: TConnectionDefClass);
  1643. begin
  1644. UnRegisterConnection(Def.TypeName);
  1645. end;
  1646. procedure UnRegisterConnection(ConnectionName: String);
  1647. Var
  1648. I : Integer;
  1649. begin
  1650. if (ConnDefs<>Nil) then
  1651. begin
  1652. I:=ConnDefs.IndexOf(ConnectionName);
  1653. If (I<>-1) then
  1654. begin
  1655. ConnDefs.Objects[I].Free;
  1656. ConnDefs.Delete(I);
  1657. end;
  1658. end;
  1659. end;
  1660. procedure GetConnectionList(List: TSTrings);
  1661. begin
  1662. CheckDefs;
  1663. List.Text:=ConnDefs.Text;
  1664. end;
  1665. { TSQLConnector }
  1666. procedure TSQLConnector.SetConnectorType(const AValue: String);
  1667. begin
  1668. if FConnectorType<>AValue then
  1669. begin
  1670. CheckDisconnected;
  1671. If Assigned(FProxy) then
  1672. FreeProxy;
  1673. FConnectorType:=AValue;
  1674. end;
  1675. end;
  1676. procedure TSQLConnector.SetTransaction(Value: TSQLTransaction);
  1677. begin
  1678. inherited SetTransaction(Value);
  1679. If Assigned(FProxy) and (FProxy.Transaction<>Value) then
  1680. FProxy.Transaction:=Value;
  1681. end;
  1682. procedure TSQLConnector.DoInternalConnect;
  1683. Var
  1684. D : TConnectionDef;
  1685. begin
  1686. inherited DoInternalConnect;
  1687. CreateProxy;
  1688. FProxy.DatabaseName:=Self.DatabaseName;
  1689. FProxy.HostName:=Self.HostName;
  1690. FProxy.UserName:=Self.UserName;
  1691. FProxy.Password:=Self.Password;
  1692. FProxy.Transaction:=Self.Transaction;
  1693. D:=GetConnectionDef(ConnectorType);
  1694. D.ApplyParams(Params,FProxy);
  1695. FProxy.Connected:=True;
  1696. end;
  1697. procedure TSQLConnector.DoInternalDisconnect;
  1698. begin
  1699. FProxy.Connected:=False;
  1700. inherited DoInternalDisconnect;
  1701. end;
  1702. procedure TSQLConnector.CheckProxy;
  1703. begin
  1704. If (FProxy=Nil) then
  1705. CreateProxy;
  1706. end;
  1707. procedure TSQLConnector.CreateProxy;
  1708. Var
  1709. D : TConnectionDef;
  1710. begin
  1711. D:=GetConnectionDef(ConnectorType);
  1712. If (D=Nil) then
  1713. DatabaseErrorFmt(SErrUnknownConnectorType,[ConnectorType],Self);
  1714. FProxy:=D.ConnectionClass.Create(Self);
  1715. end;
  1716. procedure TSQLConnector.FreeProxy;
  1717. begin
  1718. FProxy.Connected:=False;
  1719. FreeAndNil(FProxy);
  1720. end;
  1721. function TSQLConnector.StrToStatementType(s: string): TStatementType;
  1722. begin
  1723. CheckProxy;
  1724. Result:=FProxy.StrToStatementType(s);
  1725. end;
  1726. function TSQLConnector.GetAsSQLText(Field: TField): string;
  1727. begin
  1728. CheckProxy;
  1729. Result:=FProxy.GetAsSQLText(Field);
  1730. end;
  1731. function TSQLConnector.GetAsSQLText(Param: TParam): string;
  1732. begin
  1733. CheckProxy;
  1734. Result:=FProxy.GetAsSQLText(Param);
  1735. end;
  1736. function TSQLConnector.GetHandle: pointer;
  1737. begin
  1738. CheckProxy;
  1739. Result:=FProxy.GetHandle;
  1740. end;
  1741. function TSQLConnector.AllocateCursorHandle: TSQLCursor;
  1742. begin
  1743. CheckProxy;
  1744. Result:=FProxy.AllocateCursorHandle;
  1745. end;
  1746. procedure TSQLConnector.DeAllocateCursorHandle(var cursor: TSQLCursor);
  1747. begin
  1748. CheckProxy;
  1749. FProxy.DeAllocateCursorHandle(cursor);
  1750. end;
  1751. function TSQLConnector.AllocateTransactionHandle: TSQLHandle;
  1752. begin
  1753. CheckProxy;
  1754. Result:=FProxy.AllocateTransactionHandle;
  1755. end;
  1756. procedure TSQLConnector.PrepareStatement(cursor: TSQLCursor;
  1757. ATransaction: TSQLTransaction; buf: string; AParams: TParams);
  1758. begin
  1759. CheckProxy;
  1760. FProxy.PrepareStatement(cursor, ATransaction, buf, AParams);
  1761. end;
  1762. procedure TSQLConnector.Execute(cursor: TSQLCursor;
  1763. atransaction: tSQLtransaction; AParams: TParams);
  1764. begin
  1765. CheckProxy;
  1766. FProxy.Execute(cursor, atransaction, AParams);
  1767. end;
  1768. function TSQLConnector.Fetch(cursor: TSQLCursor): boolean;
  1769. begin
  1770. CheckProxy;
  1771. Result:=FProxy.Fetch(cursor);
  1772. end;
  1773. procedure TSQLConnector.AddFieldDefs(cursor: TSQLCursor; FieldDefs: TfieldDefs
  1774. );
  1775. begin
  1776. CheckProxy;
  1777. FProxy.AddFieldDefs(cursor, FieldDefs);
  1778. end;
  1779. procedure TSQLConnector.UnPrepareStatement(cursor: TSQLCursor);
  1780. begin
  1781. CheckProxy;
  1782. FProxy.UnPrepareStatement(cursor);
  1783. end;
  1784. procedure TSQLConnector.FreeFldBuffers(cursor: TSQLCursor);
  1785. begin
  1786. CheckProxy;
  1787. FProxy.FreeFldBuffers(cursor);
  1788. end;
  1789. function TSQLConnector.LoadField(cursor: TSQLCursor; FieldDef: TfieldDef;
  1790. buffer: pointer; out CreateBlob: boolean): boolean;
  1791. begin
  1792. CheckProxy;
  1793. Result:=FProxy.LoadField(cursor, FieldDef, buffer, CreateBlob);
  1794. end;
  1795. function TSQLConnector.RowsAffected(cursor: TSQLCursor): TRowsCount;
  1796. begin
  1797. CheckProxy;
  1798. Result := FProxy.RowsAffected(cursor);
  1799. end;
  1800. function TSQLConnector.GetTransactionHandle(trans: TSQLHandle): pointer;
  1801. begin
  1802. CheckProxy;
  1803. Result:=FProxy.GetTransactionHandle(trans);
  1804. end;
  1805. function TSQLConnector.Commit(trans: TSQLHandle): boolean;
  1806. begin
  1807. CheckProxy;
  1808. Result:=FProxy.Commit(trans);
  1809. end;
  1810. function TSQLConnector.RollBack(trans: TSQLHandle): boolean;
  1811. begin
  1812. CheckProxy;
  1813. Result:=FProxy.RollBack(trans);
  1814. end;
  1815. function TSQLConnector.StartdbTransaction(trans: TSQLHandle; aParams: string
  1816. ): boolean;
  1817. begin
  1818. CheckProxy;
  1819. Result:=FProxy.StartdbTransaction(trans, aParams);
  1820. end;
  1821. procedure TSQLConnector.CommitRetaining(trans: TSQLHandle);
  1822. begin
  1823. CheckProxy;
  1824. FProxy.CommitRetaining(trans);
  1825. end;
  1826. procedure TSQLConnector.RollBackRetaining(trans: TSQLHandle);
  1827. begin
  1828. CheckProxy;
  1829. FProxy.RollBackRetaining(trans);
  1830. end;
  1831. procedure TSQLConnector.UpdateIndexDefs(IndexDefs: TIndexDefs;
  1832. TableName: string);
  1833. begin
  1834. CheckProxy;
  1835. FProxy.UpdateIndexDefs(IndexDefs, TableName);
  1836. end;
  1837. function TSQLConnector.GetSchemaInfoSQL(SchemaType: TSchemaType;
  1838. SchemaObjectName, SchemaPattern: string): string;
  1839. begin
  1840. CheckProxy;
  1841. Result:=FProxy.GetSchemaInfoSQL(SchemaType, SchemaObjectName, SchemaPattern
  1842. );
  1843. end;
  1844. procedure TSQLConnector.LoadBlobIntoBuffer(FieldDef: TFieldDef;
  1845. ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction);
  1846. begin
  1847. CheckProxy;
  1848. FProxy.LoadBlobIntoBuffer(FieldDef, ABlobBuf, cursor, ATransaction);
  1849. end;
  1850. { TConnectionDef }
  1851. class function TConnectionDef.TypeName: String;
  1852. begin
  1853. Result:='';
  1854. end;
  1855. class function TConnectionDef.ConnectionClass: TSQLConnectionClass;
  1856. begin
  1857. Result:=Nil;
  1858. end;
  1859. class function TConnectionDef.Description: String;
  1860. begin
  1861. Result:='';
  1862. end;
  1863. procedure TConnectionDef.ApplyParams(Params: TStrings;
  1864. AConnection: TSQLConnection);
  1865. begin
  1866. AConnection.Params.Assign(Params);
  1867. end;
  1868. { TServerIndexDefs }
  1869. constructor TServerIndexDefs.create(ADataset: TDataset);
  1870. begin
  1871. if not (ADataset is TCustomSQLQuery) then
  1872. DatabaseErrorFmt(SErrNotASQLQuery,[ADataset.Name]);
  1873. inherited create(ADataset);
  1874. end;
  1875. procedure TServerIndexDefs.Update;
  1876. begin
  1877. if (not updated) and assigned(Dataset) then
  1878. begin
  1879. TCustomSQLQuery(Dataset).UpdateServerIndexDefs;
  1880. updated := True;
  1881. end;
  1882. end;
  1883. Initialization
  1884. Finalization
  1885. DoneDefs;
  1886. end.