sqldb.pp 78 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835
  1. {
  2. Copyright (c) 2004-2013 by Joost van der Sluis, FPC contributors
  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
  17. TSchemaType = (stNoSchema, stTables, stSysTables, stProcedures, stColumns, stProcedureParams, stIndexes, stPackages, stSchemata);
  18. TConnOption = (sqSupportParams, sqSupportEmptyDatabaseName, sqEscapeSlash, sqEscapeRepeat);
  19. TConnOptions= set of TConnOption;
  20. TConnInfoType=(citAll=-1, citServerType, citServerVersion, citServerVersionString, citClientName, citClientVersion);
  21. TStatementType = (stUnknown, stSelect, stInsert, stUpdate, stDelete,
  22. stDDL, stGetSegment, stPutSegment, stExecProcedure,
  23. stStartTrans, stCommit, stRollback, stSelectForUpd);
  24. TRowsCount = LargeInt;
  25. TSQLStatementInfo = Record
  26. StatementType : TStatementType;
  27. TableName : String;
  28. Updateable : Boolean;
  29. WhereStartPos ,
  30. WhereStopPos : integer;
  31. end;
  32. type
  33. TSQLConnection = class;
  34. TSQLTransaction = class;
  35. TCustomSQLQuery = class;
  36. TCustomSQLStatement = Class;
  37. TSQLQuery = class;
  38. TSQLScript = class;
  39. TDBEventType = (detCustom, detPrepare, detExecute, detFetch, detCommit,detRollBack);
  40. TDBEventTypes = set of TDBEventType;
  41. TDBLogNotifyEvent = Procedure (Sender : TSQLConnection; EventType : TDBEventType; Const Msg : String) of object;
  42. TSQLHandle = Class(TObject)
  43. end;
  44. { TSQLCursor }
  45. TSQLCursor = Class(TSQLHandle)
  46. public
  47. FPrepared : Boolean;
  48. FSelectable : Boolean;
  49. FInitFieldDef : Boolean;
  50. FStatementType : TStatementType;
  51. FSchemaType : TSchemaType;
  52. end;
  53. type TQuoteChars = array[0..1] of char;
  54. const
  55. SingleQuotes : TQuoteChars = ('''','''');
  56. DoubleQuotes : TQuoteChars = ('"','"');
  57. LogAllEvents = [detCustom, detPrepare, detExecute, detFetch, detCommit, detRollBack];
  58. StatementTokens : Array[TStatementType] of string = ('(unknown)', 'select',
  59. 'insert', 'update', 'delete',
  60. 'create', 'get', 'put', 'execute',
  61. 'start','commit','rollback', '?'
  62. );
  63. type
  64. { TServerIndexDefs }
  65. TServerIndexDefs = class(TIndexDefs)
  66. Private
  67. public
  68. constructor Create(ADataSet: TDataSet); override;
  69. procedure Update; override;
  70. end;
  71. type
  72. { TSQLConnection }
  73. TSQLConnection = class (TDatabase)
  74. private
  75. FFieldNameQuoteChars : TQuoteChars;
  76. FLogEvents: TDBEventTypes;
  77. FOnLog: TDBLogNotifyEvent;
  78. FPassword : string;
  79. FTransaction : TSQLTransaction;
  80. FUserName : string;
  81. FHostName : string;
  82. FCharSet : string;
  83. FRole : String;
  84. FStatements : TFPList;
  85. function GetPort: cardinal;
  86. procedure SetPort(const AValue: cardinal);
  87. protected
  88. FConnOptions : TConnOptions;
  89. FSQLFormatSettings : TFormatSettings;
  90. procedure GetDBInfo(const ASchemaType : TSchemaType; const ASchemaObjectName, AReturnField : string; AList: TStrings);
  91. procedure SetTransaction(Value : TSQLTransaction); virtual;
  92. procedure DoInternalConnect; override;
  93. procedure DoInternalDisconnect; override;
  94. function GetAsSQLText(Field : TField) : string; overload; virtual;
  95. function GetAsSQLText(Param : TParam) : string; overload; virtual;
  96. function GetHandle : pointer; virtual;
  97. Function LogEvent(EventType : TDBEventType) : Boolean;
  98. Procedure Log(EventType : TDBEventType; Const Msg : String); virtual;
  99. Procedure RegisterStatement(S : TCustomSQLStatement);
  100. Procedure UnRegisterStatement(S : TCustomSQLStatement);
  101. Function AllocateCursorHandle : TSQLCursor; virtual; abstract;
  102. Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); virtual; abstract;
  103. function StrToStatementType(s : string) : TStatementType; virtual;
  104. function GetStatementInfo(const ASQL: string; Full: Boolean; ASchema : TSchemaType): TSQLStatementInfo; virtual;
  105. procedure PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams); virtual; abstract;
  106. procedure UnPrepareStatement(cursor : TSQLCursor); virtual; abstract;
  107. procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams); virtual; abstract;
  108. function RowsAffected(cursor: TSQLCursor): TRowsCount; virtual;
  109. function Fetch(cursor : TSQLCursor) : boolean; virtual; abstract;
  110. procedure AddFieldDefs(cursor: TSQLCursor; FieldDefs : TfieldDefs); virtual; abstract;
  111. function LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; virtual; abstract;
  112. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction : TSQLTransaction); virtual; abstract;
  113. procedure FreeFldBuffers(cursor : TSQLCursor); virtual;
  114. Function AllocateTransactionHandle : TSQLHandle; virtual; abstract;
  115. function GetTransactionHandle(trans : TSQLHandle): pointer; virtual; abstract;
  116. function Commit(trans : TSQLHandle) : boolean; virtual; abstract;
  117. function RollBack(trans : TSQLHandle) : boolean; virtual; abstract;
  118. function StartdbTransaction(trans : TSQLHandle; aParams : string) : boolean; virtual; abstract;
  119. procedure CommitRetaining(trans : TSQLHandle); virtual; abstract;
  120. procedure RollBackRetaining(trans : TSQLHandle); virtual; abstract;
  121. procedure UpdateIndexDefs(IndexDefs : TIndexDefs;TableName : string); virtual;
  122. function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; virtual;
  123. Property Statements : TFPList Read FStatements;
  124. property Port: cardinal read GetPort write SetPort;
  125. public
  126. property Handle: Pointer read GetHandle;
  127. property FieldNameQuoteChars: TQuoteChars read FFieldNameQuoteChars write FFieldNameQuoteChars;
  128. constructor Create(AOwner: TComponent); override;
  129. destructor Destroy; override;
  130. procedure StartTransaction; override;
  131. procedure EndTransaction; override;
  132. property ConnOptions: TConnOptions read FConnOptions;
  133. procedure ExecuteDirect(SQL : String); overload; virtual;
  134. procedure ExecuteDirect(SQL : String; ATransaction : TSQLTransaction); overload; virtual;
  135. procedure GetTableNames(List : TStrings; SystemTables : Boolean = false); virtual;
  136. procedure GetProcedureNames(List : TStrings); virtual;
  137. procedure GetFieldNames(const TableName : string; List : TStrings); virtual;
  138. procedure GetSchemaNames(List: TStrings); virtual;
  139. function GetConnectionInfo(InfoType:TConnInfoType): string; virtual;
  140. procedure CreateDB; virtual;
  141. procedure DropDB; virtual;
  142. published
  143. property Password : string read FPassword write FPassword;
  144. property Transaction : TSQLTransaction read FTransaction write SetTransaction;
  145. property UserName : string read FUserName write FUserName;
  146. property CharSet : string read FCharSet write FCharSet;
  147. property HostName : string Read FHostName Write FHostName;
  148. Property OnLog : TDBLogNotifyEvent Read FOnLog Write FOnLog;
  149. Property LogEvents : TDBEventTypes Read FLogEvents Write FLogEvents Default LogAllEvents;
  150. property Connected;
  151. Property Role : String read FRole write FRole;
  152. property DatabaseName;
  153. property KeepConnection;
  154. property LoginPrompt;
  155. property Params;
  156. property OnLogin;
  157. end;
  158. { TSQLTransaction }
  159. TCommitRollbackAction = (caNone, caCommit, caCommitRetaining, caRollback,
  160. caRollbackRetaining);
  161. TSQLTransaction = class (TDBTransaction)
  162. private
  163. FTrans : TSQLHandle;
  164. FAction : TCommitRollbackAction;
  165. FParams : TStringList;
  166. procedure SetParams(const AValue: TStringList);
  167. protected
  168. function GetHandle : Pointer; virtual;
  169. Procedure SetDatabase (Value : TDatabase); override;
  170. Function LogEvent(EventType : TDBEventType) : Boolean;
  171. Procedure Log(EventType : TDBEventType; Const Msg : String); virtual;
  172. public
  173. procedure Commit; virtual;
  174. procedure CommitRetaining; virtual;
  175. procedure Rollback; virtual;
  176. procedure RollbackRetaining; virtual;
  177. procedure StartTransaction; override;
  178. constructor Create(AOwner : TComponent); override;
  179. destructor Destroy; override;
  180. property Handle: Pointer read GetHandle;
  181. procedure EndTransaction; override;
  182. published
  183. property Action : TCommitRollbackAction read FAction write FAction Default caRollBack;
  184. property Database;
  185. property Params : TStringList read FParams write SetParams;
  186. end;
  187. { TCustomSQLStatement }
  188. TCustomSQLStatement = Class(TComponent)
  189. Private
  190. FCursor : TSQLCursor;
  191. FDatabase: TSQLConnection;
  192. FParamCheck: Boolean;
  193. FParams: TParams;
  194. FSQL: TStrings;
  195. FOrigSQL : String;
  196. FServerSQL : String;
  197. FTransaction: TSQLTransaction;
  198. FParseSQL: Boolean;
  199. FDataLink : TDataLink;
  200. procedure SetDatabase(AValue: TSQLConnection);
  201. procedure SetParams(AValue: TParams);
  202. procedure SetSQL(AValue: TStrings);
  203. procedure SetTransaction(AValue: TSQLTransaction);
  204. Function GetPrepared : Boolean;
  205. Protected
  206. Function CreateDataLink : TDataLink; virtual;
  207. procedure OnChangeSQL(Sender : TObject); virtual;
  208. function GetDataSource: TDataSource; Virtual;
  209. procedure SetDataSource(AValue: TDataSource); virtual;
  210. Procedure CopyParamsFromMaster(CopyBound : Boolean); virtual;
  211. procedure AllocateCursor;
  212. procedure DeAllocateCursor;
  213. Function GetSchemaType : TSchemaType; virtual;
  214. Function GetSchemaObjectName : String; virtual;
  215. Function GetSchemaPattern: String; virtual;
  216. Function IsSelectable : Boolean ; virtual;
  217. procedure GetStatementInfo(Var ASQL: String; Full: Boolean; ASchema: TSchemaType; out Info: TSQLStatementInfo); virtual;
  218. Procedure DoExecute; virtual;
  219. procedure DoPrepare; virtual;
  220. procedure DoUnPrepare; virtual;
  221. Function CreateParams : TParams; virtual;
  222. Function LogEvent(EventType : TDBEventType) : Boolean;
  223. Procedure Log(EventType : TDBEventType; Const Msg : String); virtual;
  224. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  225. Property Cursor : TSQLCursor read FCursor;
  226. Property Database : TSQLConnection Read FDatabase Write SetDatabase;
  227. Property Transaction : TSQLTransaction Read FTransaction Write SetTransaction;
  228. Property SQL : TStrings Read FSQL Write SetSQL;
  229. Property Params : TParams Read FParams Write SetParams;
  230. Property DataSource : TDataSource Read GetDataSource Write SetDataSource;
  231. Property ParseSQL : Boolean Read FParseSQL Write FParseSQL;
  232. Property ParamCheck : Boolean Read FParamCheck Write FParamCheck default true;
  233. Public
  234. constructor Create(AOwner : TComponent); override;
  235. destructor Destroy; override;
  236. Procedure Prepare;
  237. Procedure Execute;
  238. Procedure Unprepare;
  239. function ParamByName(Const AParamName : String) : TParam;
  240. function RowsAffected: TRowsCount; virtual;
  241. Property Prepared : boolean read GetPrepared;
  242. end;
  243. TSQLStatement = Class(TCustomSQLStatement)
  244. Published
  245. Property Database;
  246. Property DataSource;
  247. Property ParamCheck;
  248. Property Params;
  249. Property ParseSQL;
  250. Property SQL;
  251. Property Transaction;
  252. end;
  253. { TCustomSQLQuery }
  254. TCustomSQLQuery = class (TCustomBufDataset)
  255. private
  256. // FCursor : TSQLCursor;
  257. FSchemaType: TSchemaType;
  258. // FSQL: TStringlist;
  259. FUpdateable : boolean;
  260. FTableName : string;
  261. FStatement : TCustomSQLStatement;
  262. FUpdateSQL,
  263. FInsertSQL,
  264. FDeleteSQL : TStringList;
  265. FIsEOF : boolean;
  266. FLoadingFieldDefs : boolean;
  267. FUpdateMode : TUpdateMode;
  268. FusePrimaryKeyAsKey : Boolean;
  269. FSQLBuf : String;
  270. FWhereStartPos : integer;
  271. FWhereStopPos : integer;
  272. // FParseSQL : boolean;
  273. // FMasterLink : TMasterParamsDatalink;
  274. // FSchemaInfo : TSchemaInfo;
  275. FServerFilterText : string;
  276. FServerFiltered : Boolean;
  277. FServerIndexDefs : TServerIndexDefs;
  278. // Used by SetSchemaType
  279. FSchemaObjectName : string;
  280. FSchemaPattern : string;
  281. FUpdateQry,
  282. FDeleteQry,
  283. FInsertQry : TCustomSQLQuery;
  284. procedure FreeFldBuffers;
  285. function GetParamCheck: Boolean;
  286. function GetParams: TParams;
  287. function GetParseSQL: Boolean;
  288. function GetServerIndexDefs: TServerIndexDefs;
  289. function GetSQL: TStringlist;
  290. function GetStatementType : TStatementType;
  291. procedure SetParamCheck(AValue: Boolean);
  292. procedure SetUpdateSQL(const AValue: TStringlist);
  293. procedure SetDeleteSQL(const AValue: TStringlist);
  294. procedure SetInsertSQL(const AValue: TStringlist);
  295. procedure SetParams(AValue: TParams);
  296. procedure SetParseSQL(AValue : Boolean);
  297. procedure SetSQL(const AValue: TStringlist);
  298. procedure SetUsePrimaryKeyAsKey(AValue : Boolean);
  299. procedure SetUpdateMode(AValue : TUpdateMode);
  300. // procedure OnChangeSQL(Sender : TObject);
  301. procedure OnChangeModifySQL(Sender : TObject);
  302. procedure Execute;
  303. // Function SQLParser(const ASQL : string) : TStatementType;
  304. procedure ApplyFilter;
  305. Function AddFilter(SQLstr : string) : string;
  306. protected
  307. // abstract & virtual methods of TBufDataset
  308. function Fetch : boolean; override;
  309. Function Cursor : TSQLCursor;
  310. function LoadField(FieldDef : TFieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; override;
  311. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField); override;
  312. // abstract & virtual methods of TDataset
  313. procedure UpdateServerIndexDefs; virtual;
  314. procedure SetDatabase(Value : TDatabase); override;
  315. Procedure SetTransaction(Value : TDBTransaction); override;
  316. procedure InternalAddRecord(Buffer: Pointer; AAppend: Boolean); override;
  317. procedure InternalClose; override;
  318. procedure InternalInitFieldDefs; override;
  319. procedure InternalOpen; override;
  320. function GetCanModify: Boolean; override;
  321. procedure ApplyRecUpdate(UpdateKind : TUpdateKind); override;
  322. Function IsPrepared : Boolean; virtual;
  323. Procedure SetActive (Value : Boolean); override;
  324. procedure SetServerFiltered(Value: Boolean); virtual;
  325. procedure SetServerFilterText(const Value: string); virtual;
  326. Function GetDataSource : TDataSource; override;
  327. Procedure SetDataSource(AValue : TDataSource);
  328. procedure BeforeRefreshOpenCursor; override;
  329. procedure SetReadOnly(AValue : Boolean); override;
  330. Function LogEvent(EventType : TDBEventType) : Boolean;
  331. Procedure Log(EventType : TDBEventType; Const Msg : String); virtual;
  332. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  333. public
  334. procedure Prepare; virtual;
  335. procedure UnPrepare; virtual;
  336. procedure ExecSQL; virtual;
  337. constructor Create(AOwner : TComponent); override;
  338. destructor Destroy; override;
  339. procedure SetSchemaInfo( ASchemaType : TSchemaType; ASchemaObjectName, ASchemaPattern : string); virtual;
  340. property Prepared : boolean read IsPrepared;
  341. function RowsAffected: TRowsCount; virtual;
  342. function ParamByName(Const AParamName : String) : TParam;
  343. protected
  344. // redeclared data set properties
  345. property Active;
  346. property Filter;
  347. property Filtered;
  348. // property FilterOptions;
  349. property BeforeOpen;
  350. property AfterOpen;
  351. property BeforeClose;
  352. property AfterClose;
  353. property BeforeInsert;
  354. property AfterInsert;
  355. property BeforeEdit;
  356. property AfterEdit;
  357. property BeforePost;
  358. property AfterPost;
  359. property BeforeCancel;
  360. property AfterCancel;
  361. property BeforeDelete;
  362. property AfterDelete;
  363. property BeforeScroll;
  364. property AfterScroll;
  365. property OnCalcFields;
  366. property OnDeleteError;
  367. property OnEditError;
  368. property OnFilterRecord;
  369. property OnNewRecord;
  370. property OnPostError;
  371. property AutoCalcFields;
  372. property Database;
  373. // protected
  374. property SchemaType : TSchemaType read FSchemaType default stNoSchema;
  375. property Transaction;
  376. property SQL : TStringlist read GetSQL write SetSQL;
  377. property UpdateSQL : TStringlist read FUpdateSQL write SetUpdateSQL;
  378. property InsertSQL : TStringlist read FInsertSQL write SetInsertSQL;
  379. property DeleteSQL : TStringlist read FDeleteSQL write SetDeleteSQL;
  380. property Params : TParams read GetParams Write SetParams;
  381. Property ParamCheck : Boolean Read GetParamCheck Write SetParamCheck default true;
  382. property ParseSQL : Boolean read GetParseSQL write SetParseSQL default true;
  383. property UpdateMode : TUpdateMode read FUpdateMode write SetUpdateMode default upWhereKeyOnly;
  384. property UsePrimaryKeyAsKey : boolean read FUsePrimaryKeyAsKey write SetUsePrimaryKeyAsKey default true;
  385. property StatementType : TStatementType read GetStatementType;
  386. Property DataSource : TDataSource Read GetDataSource Write SetDataSource;
  387. property ServerFilter: string read FServerFilterText write SetServerFilterText;
  388. property ServerFiltered: Boolean read FServerFiltered write SetServerFiltered default False;
  389. property ServerIndexDefs : TServerIndexDefs read GetServerIndexDefs;
  390. end;
  391. { TSQLQuery }
  392. TSQLQuery = Class(TCustomSQLQuery)
  393. public
  394. property SchemaType;
  395. Property StatementType;
  396. Published
  397. property MaxIndexesCount;
  398. // TDataset stuff
  399. property FieldDefs;
  400. Property Active;
  401. Property AutoCalcFields;
  402. Property Filter;
  403. Property Filtered;
  404. Property AfterCancel;
  405. Property AfterClose;
  406. Property AfterDelete;
  407. Property AfterEdit;
  408. Property AfterInsert;
  409. Property AfterOpen;
  410. Property AfterPost;
  411. Property AfterScroll;
  412. Property BeforeCancel;
  413. Property BeforeClose;
  414. Property BeforeDelete;
  415. Property BeforeEdit;
  416. Property BeforeInsert;
  417. Property BeforeOpen;
  418. Property BeforePost;
  419. Property BeforeScroll;
  420. Property OnCalcFields;
  421. Property OnDeleteError;
  422. Property OnEditError;
  423. Property OnFilterRecord;
  424. Property OnNewRecord;
  425. Property OnPostError;
  426. // property SchemaInfo default stNoSchema;
  427. property Database;
  428. property Transaction;
  429. property ReadOnly;
  430. property SQL;
  431. property UpdateSQL;
  432. property InsertSQL;
  433. property DeleteSQL;
  434. property IndexDefs;
  435. property Params;
  436. Property ParamCheck;
  437. property ParseSQL;
  438. property UpdateMode;
  439. property UsePrimaryKeyAsKey;
  440. Property DataSource;
  441. property ServerFilter;
  442. property ServerFiltered;
  443. property ServerIndexDefs;
  444. end;
  445. { TSQLScript }
  446. TSQLScript = class (TCustomSQLscript)
  447. private
  448. FOnDirective: TSQLScriptDirectiveEvent;
  449. FQuery : TCustomSQLQuery;
  450. FDatabase : TDatabase;
  451. FTransaction : TDBTransaction;
  452. protected
  453. procedure ExecuteStatement (SQLStatement: TStrings; var StopExecution: Boolean); override;
  454. procedure ExecuteDirective (Directive, Argument: String; var StopExecution: Boolean); override;
  455. procedure ExecuteCommit(CommitRetaining: boolean=true); override;
  456. Procedure SetDatabase (Value : TDatabase); virtual;
  457. Procedure SetTransaction(Value : TDBTransaction); virtual;
  458. Procedure CheckDatabase;
  459. public
  460. constructor Create(AOwner : TComponent); override;
  461. destructor Destroy; override;
  462. procedure Execute; override;
  463. procedure ExecuteScript;
  464. published
  465. Property DataBase : TDatabase Read FDatabase Write SetDatabase;
  466. Property Transaction : TDBTransaction Read FTransaction Write SetTransaction;
  467. property OnDirective: TSQLScriptDirectiveEvent read FOnDirective write FOnDirective;
  468. property Directives;
  469. property Defines;
  470. property Script;
  471. property Terminator;
  472. property CommentsinSQL;
  473. property UseSetTerm;
  474. property UseCommit;
  475. property UseDefines;
  476. property OnException;
  477. end;
  478. { TSQLConnector }
  479. TSQLConnector = Class(TSQLConnection)
  480. private
  481. FProxy : TSQLConnection;
  482. FConnectorType: String;
  483. procedure SetConnectorType(const AValue: String);
  484. protected
  485. procedure SetTransaction(Value : TSQLTransaction);override;
  486. procedure DoInternalConnect; override;
  487. procedure DoInternalDisconnect; override;
  488. Procedure CheckProxy;
  489. Procedure CreateProxy; virtual;
  490. Procedure FreeProxy; virtual;
  491. function StrToStatementType(s : string) : TStatementType; override;
  492. function GetAsSQLText(Field : TField) : string; overload; override;
  493. function GetAsSQLText(Param : TParam) : string; overload; override;
  494. function GetHandle : pointer; override;
  495. Function AllocateCursorHandle : TSQLCursor; override;
  496. Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); override;
  497. Function AllocateTransactionHandle : TSQLHandle; override;
  498. procedure PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams); override;
  499. procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams); override;
  500. function RowsAffected(cursor: TSQLCursor): TRowsCount; override;
  501. function Fetch(cursor : TSQLCursor) : boolean; override;
  502. procedure AddFieldDefs(cursor: TSQLCursor; FieldDefs : TfieldDefs); override;
  503. procedure UnPrepareStatement(cursor : TSQLCursor); override;
  504. function LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; override;
  505. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction : TSQLTransaction); override;
  506. procedure FreeFldBuffers(cursor : TSQLCursor); override;
  507. function GetTransactionHandle(trans : TSQLHandle): pointer; override;
  508. function Commit(trans : TSQLHandle) : boolean; override;
  509. function RollBack(trans : TSQLHandle) : boolean; override;
  510. function StartdbTransaction(trans : TSQLHandle; aParams : string) : boolean; override;
  511. procedure CommitRetaining(trans : TSQLHandle); override;
  512. procedure RollBackRetaining(trans : TSQLHandle); override;
  513. procedure UpdateIndexDefs(IndexDefs : TIndexDefs;TableName : string); override;
  514. function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; override;
  515. Property Proxy : TSQLConnection Read FProxy;
  516. Published
  517. Property ConnectorType : String Read FConnectorType Write SetConnectorType;
  518. end;
  519. TSQLConnectionClass = Class of TSQLConnection;
  520. { TConnectionDef }
  521. TLibraryLoadFunction = Function (Const S : AnsiString) : Integer;
  522. TLibraryUnLoadFunction = Procedure;
  523. TConnectionDef = Class(TPersistent)
  524. Class Function TypeName : String; virtual;
  525. Class Function ConnectionClass : TSQLConnectionClass; virtual;
  526. Class Function Description : String; virtual;
  527. Class Function DefaultLibraryName : String; virtual;
  528. Class Function LoadFunction : TLibraryLoadFunction; virtual;
  529. Class Function UnLoadFunction : TLibraryUnLoadFunction; virtual;
  530. Class Function LoadedLibraryName : string; virtual;
  531. Procedure ApplyParams(Params : TStrings; AConnection : TSQLConnection); virtual;
  532. end;
  533. TConnectionDefClass = class of TConnectionDef;
  534. Var
  535. GlobalDBLogHook : TDBLogNotifyEvent;
  536. Procedure RegisterConnection(Def : TConnectionDefClass);
  537. Procedure UnRegisterConnection(Def : TConnectionDefClass);
  538. Procedure UnRegisterConnection(ConnectionName : String);
  539. Function GetConnectionDef(ConnectorName : String) : TConnectionDef;
  540. Procedure GetConnectionList(List : TSTrings);
  541. const DefaultSQLFormatSettings : TFormatSettings = (
  542. CurrencyFormat: 1;
  543. NegCurrFormat: 5;
  544. ThousandSeparator: #0;
  545. DecimalSeparator: '.';
  546. CurrencyDecimals: 2;
  547. DateSeparator: '-';
  548. TimeSeparator: ':';
  549. ListSeparator: ' ';
  550. CurrencyString: '$';
  551. ShortDateFormat: 'yyyy-mm-dd';
  552. LongDateFormat: '';
  553. TimeAMString: '';
  554. TimePMString: '';
  555. ShortTimeFormat: 'hh:nn:ss';
  556. LongTimeFormat: 'hh:nn:ss.zzz';
  557. ShortMonthNames: ('','','','','','','','','','','','');
  558. LongMonthNames: ('','','','','','','','','','','','');
  559. ShortDayNames: ('','','','','','','');
  560. LongDayNames: ('','','','','','','');
  561. TwoDigitYearCenturyWindow: 50;
  562. );
  563. implementation
  564. uses dbconst, strutils;
  565. function TimeIntervalToString(Time: TDateTime): string;
  566. var
  567. millisecond: word;
  568. second : word;
  569. minute : word;
  570. hour : word;
  571. begin
  572. DecodeTime(Time,hour,minute,second,millisecond);
  573. hour := hour + (trunc(Time) * 24);
  574. result := Format('%.2d:%.2d:%.2d.%.3d',[hour,minute,second,millisecond]);
  575. end;
  576. { TCustomSQLStatement }
  577. procedure TCustomSQLStatement.OnChangeSQL(Sender: TObject);
  578. var
  579. ConnOptions : TConnOptions;
  580. NewParams: TParams;
  581. begin
  582. UnPrepare;
  583. if not ParamCheck then
  584. exit;
  585. if assigned(DataBase) then
  586. ConnOptions:=DataBase.ConnOptions
  587. else
  588. ConnOptions := [sqEscapeRepeat,sqEscapeSlash];
  589. NewParams := CreateParams;
  590. try
  591. NewParams.ParseSQL(FSQL.Text, True, sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions, psInterbase);
  592. NewParams.AssignValues(FParams);
  593. FParams.Assign(NewParams);
  594. finally
  595. NewParams.Free;
  596. end;
  597. end;
  598. procedure TCustomSQLStatement.SetDatabase(AValue: TSQLConnection);
  599. begin
  600. if FDatabase=AValue then Exit;
  601. UnPrepare;
  602. If Assigned(FDatabase) then
  603. begin
  604. FDatabase.UnregisterStatement(Self);
  605. FDatabase.RemoveFreeNotification(Self);
  606. end;
  607. FDatabase:=AValue;
  608. If Assigned(FDatabase) then
  609. begin
  610. FDatabase.FreeNotification(Self);
  611. FDatabase.RegisterStatement(Self);
  612. if (Transaction=nil) and (Assigned(FDatabase.Transaction)) then
  613. transaction := FDatabase.Transaction;
  614. OnChangeSQL(Self);
  615. end;
  616. end;
  617. procedure TCustomSQLStatement.SetDataSource(AValue: TDataSource);
  618. begin
  619. if GetDataSource=AValue then Exit;
  620. if (FDataLink=Nil) then
  621. FDataLink:=CreateDataLink;
  622. FDataLink.DataSource:=AValue;
  623. end;
  624. procedure TCustomSQLStatement.CopyParamsFromMaster(CopyBound : Boolean);
  625. begin
  626. if Assigned(DataSource) and Assigned(DataSource.Dataset) then
  627. FParams.CopyParamValuesFromDataset(DataSource.Dataset,CopyBound);
  628. end;
  629. procedure TCustomSQLStatement.SetParams(AValue: TParams);
  630. begin
  631. if FParams=AValue then Exit;
  632. FParams.Assign(AValue);
  633. end;
  634. procedure TCustomSQLStatement.SetSQL(AValue: TStrings);
  635. begin
  636. if FSQL=AValue then Exit;
  637. FSQL.Assign(AValue);
  638. end;
  639. procedure TCustomSQLStatement.SetTransaction(AValue: TSQLTransaction);
  640. begin
  641. if FTransaction=AValue then Exit;
  642. UnPrepare;
  643. if Assigned(FTransaction) then
  644. FTransaction.RemoveFreeNotification(Self);
  645. FTransaction:=AValue;
  646. if Assigned(FTransaction) then
  647. begin
  648. FTransaction.FreeNotification(Self);
  649. If (Database=Nil) then
  650. Database:=Transaction.Database as TSQLConnection;
  651. end;
  652. end;
  653. procedure TCustomSQLStatement.DoExecute;
  654. begin
  655. If (FParams.Count>0) and Assigned(DataSource) then
  656. CopyParamsFromMaster(False);
  657. If LogEvent(detExecute) then
  658. Log(detExecute,FServerSQL);
  659. Database.Execute(FCursor,Transaction, FParams);
  660. end;
  661. function TCustomSQLStatement.GetPrepared: Boolean;
  662. begin
  663. Result := Assigned(FCursor) and FCursor.FPrepared;
  664. end;
  665. function TCustomSQLStatement.CreateDataLink: TDataLink;
  666. begin
  667. Result:=TDataLink.Create;
  668. end;
  669. function TCustomSQLStatement.CreateParams: TParams;
  670. begin
  671. Result:=TParams.Create(Nil);
  672. end;
  673. function TCustomSQLStatement.LogEvent(EventType: TDBEventType): Boolean;
  674. begin
  675. Result:=Assigned(Database) and Database.LogEvent(EventType);
  676. end;
  677. procedure TCustomSQLStatement.Log(EventType: TDBEventType; const Msg: String);
  678. Var
  679. M : String;
  680. begin
  681. If LogEvent(EventType) then
  682. begin
  683. If (Name<>'') then
  684. M:=Name
  685. else
  686. M:=ClassName;
  687. Database.Log(EventType,M+' : '+Msg);
  688. end;
  689. end;
  690. procedure TCustomSQLStatement.Notification(AComponent: TComponent;
  691. Operation: TOperation);
  692. begin
  693. inherited Notification(AComponent, Operation);
  694. if (operation=opRemove) then
  695. If (AComponent=FTransaction) then
  696. FTransaction:=Nil
  697. else if (AComponent=FDatabase) then
  698. begin
  699. UnPrepare;
  700. FDatabase:=Nil;
  701. end;
  702. end;
  703. constructor TCustomSQLStatement.Create(AOwner: TComponent);
  704. begin
  705. inherited Create(AOwner);
  706. FSQL:=TStringList.Create;
  707. TStringList(FSQL).OnChange:=@OnChangeSQL;
  708. FParams:=CreateParams;
  709. FParamCheck:=True;
  710. FParseSQL:=True;
  711. end;
  712. destructor TCustomSQLStatement.Destroy;
  713. begin
  714. UnPrepare;
  715. Transaction:=Nil;
  716. Database:=Nil;
  717. DataSource:=Nil;
  718. FreeAndNil(FDataLink);
  719. FreeAndNil(Fparams);
  720. FreeAndNil(FSQL);
  721. inherited Destroy;
  722. end;
  723. function TCustomSQLStatement.GetSchemaType: TSchemaType;
  724. begin
  725. Result:=stNoSchema
  726. end;
  727. function TCustomSQLStatement.GetSchemaObjectName: String;
  728. begin
  729. Result:='';
  730. end;
  731. function TCustomSQLStatement.GetSchemaPattern: String;
  732. begin
  733. Result:='';
  734. end;
  735. function TCustomSQLStatement.IsSelectable: Boolean;
  736. begin
  737. Result:=False;
  738. end;
  739. procedure TCustomSQLStatement.GetStatementInfo(var ASQL: String; Full: Boolean;
  740. ASchema: TSchemaType; out Info: TSQLStatementInfo);
  741. begin
  742. Info:=Database.GetStatementInfo(ASQL,Full,ASchema);
  743. end;
  744. procedure TCustomSQLStatement.AllocateCursor;
  745. begin
  746. if not assigned(FCursor) then
  747. // Do this as late as possible.
  748. FCursor:=Database.AllocateCursorHandle;
  749. end;
  750. procedure TCustomSQLStatement.DeAllocateCursor;
  751. begin
  752. if Assigned(FCursor) and Assigned(Database) then
  753. DataBase.DeAllocateCursorHandle(FCursor);
  754. end;
  755. procedure TCustomSQLStatement.DoPrepare;
  756. var
  757. StmType: TStatementType;
  758. I : TSQLStatementInfo;
  759. begin
  760. if GetSchemaType=stNoSchema then
  761. FOrigSQL := TrimRight(FSQL.Text)
  762. else
  763. FOrigSQL := Database.GetSchemaInfoSQL(GetSchemaType, GetSchemaObjectName, GetSchemaPattern);
  764. if (FOrigSQL='') then
  765. DatabaseError(SErrNoStatement);
  766. FServerSQL:=FOrigSQL;
  767. GetStatementInfo(FServerSQL,ParseSQL,GetSchemaType,I);
  768. StmType:=I.StatementType;
  769. AllocateCursor;
  770. FCursor.FSelectable:=True; // let PrepareStatement and/or Execute alter it
  771. FCursor.FStatementType:=StmType;
  772. FCursor.FSchemaType:=GetSchemaType;
  773. If LogEvent(detPrepare) then
  774. Log(detPrepare,FServerSQL);
  775. Database.PrepareStatement(FCursor,Transaction,FServerSQL,FParams);
  776. end;
  777. procedure TCustomSQLStatement.Prepare;
  778. begin
  779. if Prepared then exit;
  780. if not assigned(Database) then
  781. DatabaseError(SErrDatabasenAssigned);
  782. if not assigned(Transaction) then
  783. DatabaseError(SErrTransactionnSet);
  784. if not Database.Connected then
  785. Database.Open;
  786. if not Transaction.Active then
  787. Transaction.StartTransaction;
  788. try
  789. DoPrepare;
  790. except
  791. DeAllocateCursor;
  792. Raise;
  793. end;
  794. end;
  795. procedure TCustomSQLStatement.Execute;
  796. begin
  797. Prepare;
  798. DoExecute;
  799. end;
  800. procedure TCustomSQLStatement.DoUnPrepare;
  801. begin
  802. If Assigned(FCursor) then
  803. If Assigned(Database) then
  804. begin
  805. DataBase.UnPrepareStatement(FCursor);
  806. DeAllocateCursor;
  807. end
  808. else // this should never happen. It means a cursor handle leaks in the DB itself.
  809. FreeAndNil(FCursor);
  810. end;
  811. function TCustomSQLStatement.GetDataSource: TDataSource;
  812. begin
  813. if Assigned(FDataLink) then
  814. Result:=FDataLink.DataSource
  815. else
  816. Result:=Nil;
  817. end;
  818. procedure TCustomSQLStatement.Unprepare;
  819. begin
  820. // Some SQLConnections does not support statement [un]preparation, but they have allocated local cursor(s)
  821. // so let them do cleanup f.e. cancel pending queries and/or free resultset
  822. // and also do UnRegisterStatement!
  823. if assigned(FCursor) then
  824. DoUnprepare;
  825. end;
  826. function TCustomSQLStatement.ParamByName(const AParamName: String): TParam;
  827. begin
  828. Result:=FParams.ParamByName(AParamName);
  829. end;
  830. function TCustomSQLStatement.RowsAffected: TRowsCount;
  831. begin
  832. Result := -1;
  833. if not Assigned(Database) then
  834. Exit;
  835. Result:=Database.RowsAffected(FCursor);
  836. end;
  837. { TSQLConnection }
  838. function TSQLConnection.StrToStatementType(s : string) : TStatementType;
  839. var T : TStatementType;
  840. begin
  841. S:=Lowercase(s);
  842. for T:=stSelect to stRollback do
  843. if (S=StatementTokens[T]) then
  844. Exit(T);
  845. Result:=stUnknown;
  846. end;
  847. procedure TSQLConnection.SetTransaction(Value : TSQLTransaction);
  848. begin
  849. if FTransaction<>value then
  850. begin
  851. if Assigned(FTransaction) and FTransaction.Active then
  852. DatabaseError(SErrAssTransaction);
  853. if Assigned(Value) then
  854. Value.Database := Self;
  855. FTransaction := Value;
  856. If Assigned(FTransaction) and (FTransaction.Database=Nil) then
  857. FTransaction.Database:=Self;
  858. end;
  859. end;
  860. procedure TSQLConnection.UpdateIndexDefs(IndexDefs : TIndexDefs;TableName : string);
  861. begin
  862. // Empty abstract
  863. end;
  864. procedure TSQLConnection.DoInternalConnect;
  865. begin
  866. if (DatabaseName = '') and not(sqSupportEmptyDatabaseName in FConnOptions) then
  867. DatabaseError(SErrNoDatabaseName,self);
  868. end;
  869. procedure TSQLConnection.DoInternalDisconnect;
  870. Var
  871. I : integer;
  872. begin
  873. For I:=0 to FStatements.Count-1 do
  874. TCustomSQLStatement(FStatements[i]).Unprepare;
  875. FStatements.Clear;
  876. end;
  877. destructor TSQLConnection.Destroy;
  878. begin
  879. Connected:=False; // needed because we want to de-allocate statements
  880. FreeAndNil(FStatements);
  881. inherited Destroy;
  882. end;
  883. procedure TSQLConnection.StartTransaction;
  884. begin
  885. if not assigned(Transaction) then
  886. DatabaseError(SErrConnTransactionnSet)
  887. else
  888. Transaction.StartTransaction;
  889. end;
  890. procedure TSQLConnection.EndTransaction;
  891. begin
  892. if not assigned(Transaction) then
  893. DatabaseError(SErrConnTransactionnSet)
  894. else
  895. Transaction.EndTransaction;
  896. end;
  897. procedure TSQLConnection.ExecuteDirect(SQL: String);
  898. begin
  899. ExecuteDirect(SQL,FTransaction);
  900. end;
  901. procedure TSQLConnection.ExecuteDirect(SQL: String;
  902. ATransaction: TSQLTransaction);
  903. var Cursor : TSQLCursor;
  904. begin
  905. if not assigned(ATransaction) then
  906. DatabaseError(SErrTransactionnSet);
  907. if not Connected then Open;
  908. if not ATransaction.Active then ATransaction.StartTransaction;
  909. try
  910. SQL := TrimRight(SQL);
  911. if SQL = '' then
  912. DatabaseError(SErrNoStatement);
  913. Cursor := AllocateCursorHandle;
  914. Cursor.FStatementType := stUnknown;
  915. PrepareStatement(Cursor,ATransaction,SQL,Nil);
  916. Execute(Cursor,ATransaction, Nil);
  917. UnPrepareStatement(Cursor);
  918. finally;
  919. DeAllocateCursorHandle(Cursor);
  920. end;
  921. end;
  922. function TSQLConnection.GetPort: cardinal;
  923. begin
  924. result := StrToIntDef(Params.Values['Port'],0);
  925. end;
  926. procedure TSQLConnection.SetPort(const AValue: cardinal);
  927. begin
  928. if AValue<>0 then
  929. Params.Values['Port']:=IntToStr(AValue)
  930. else with params do if IndexOfName('Port') > -1 then
  931. Delete(IndexOfName('Port'));
  932. end;
  933. procedure TSQLConnection.GetDBInfo(const ASchemaType : TSchemaType; const ASchemaObjectName, AReturnField : string; AList: TStrings);
  934. var qry : TCustomSQLQuery;
  935. begin
  936. if not assigned(Transaction) then
  937. DatabaseError(SErrConnTransactionnSet);
  938. qry := TCustomSQLQuery.Create(nil);
  939. try
  940. qry.transaction := Transaction;
  941. qry.database := Self;
  942. with qry do
  943. begin
  944. ParseSQL := False;
  945. SetSchemaInfo(ASchemaType,ASchemaObjectName,'');
  946. open;
  947. AList.Clear;
  948. while not eof do
  949. begin
  950. AList.Append(trim(fieldbyname(AReturnField).asstring));
  951. Next;
  952. end;
  953. end;
  954. finally
  955. qry.free;
  956. end;
  957. end;
  958. function TSQLConnection.RowsAffected(cursor: TSQLCursor): TRowsCount;
  959. begin
  960. Result := -1;
  961. end;
  962. constructor TSQLConnection.Create(AOwner: TComponent);
  963. begin
  964. inherited Create(AOwner);
  965. FSQLFormatSettings:=DefaultSQLFormatSettings;
  966. FFieldNameQuoteChars:=DoubleQuotes;
  967. FStatements:=TFPList.Create;
  968. end;
  969. procedure TSQLConnection.GetTableNames(List: TStrings; SystemTables: Boolean);
  970. begin
  971. if not SystemTables then
  972. GetDBInfo(stTables,'','table_name',List)
  973. else
  974. GetDBInfo(stSysTables,'','table_name',List);
  975. end;
  976. procedure TSQLConnection.GetProcedureNames(List: TStrings);
  977. begin
  978. GetDBInfo(stProcedures,'','proc_name',List);
  979. end;
  980. procedure TSQLConnection.GetFieldNames(const TableName: string; List: TStrings);
  981. begin
  982. GetDBInfo(stColumns,TableName,'column_name',List);
  983. end;
  984. procedure TSQLConnection.GetSchemaNames(List: TStrings);
  985. begin
  986. GetDBInfo(stSchemata,'','SCHEMA_NAME',List);
  987. end;
  988. function TSQLConnection.GetConnectionInfo(InfoType: TConnInfoType): string;
  989. var i: TConnInfoType;
  990. begin
  991. Result:='';
  992. if InfoType = citAll then
  993. for i:=citServerType to citClientVersion do
  994. begin
  995. if Result<>'' then Result:=Result+',';
  996. Result:=Result+'"'+GetConnectionInfo(i)+'"';
  997. end;
  998. end;
  999. function TSQLConnection.GetAsSQLText(Field : TField) : string;
  1000. begin
  1001. if (not assigned(field)) or field.IsNull then Result := 'Null'
  1002. else case field.DataType of
  1003. ftString : Result := QuotedStr(Field.AsString);
  1004. ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Field.AsDateTime,FSqlFormatSettings) + '''';
  1005. ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz',Field.AsDateTime,FSqlFormatSettings) + '''';
  1006. ftTime : Result := QuotedStr(TimeIntervalToString(Field.AsDateTime));
  1007. else
  1008. Result := field.asstring;
  1009. end; {case}
  1010. end;
  1011. function TSQLConnection.GetAsSQLText(Param: TParam) : string;
  1012. begin
  1013. if (not assigned(param)) or param.IsNull then Result := 'Null'
  1014. else case param.DataType of
  1015. ftGuid,
  1016. ftMemo,
  1017. ftFixedChar,
  1018. ftString : Result := QuotedStr(Param.AsString);
  1019. ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Param.AsDateTime,FSQLFormatSettings) + '''';
  1020. ftTime : Result := QuotedStr(TimeIntervalToString(Param.AsDateTime));
  1021. ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', Param.AsDateTime, FSQLFormatSettings) + '''';
  1022. ftCurrency,
  1023. ftBcd : Result := CurrToStr(Param.AsCurrency, FSQLFormatSettings);
  1024. ftFloat : Result := FloatToStr(Param.AsFloat, FSQLFormatSettings);
  1025. ftFMTBcd : Result := stringreplace(Param.AsString, DefaultFormatSettings.DecimalSeparator, FSQLFormatSettings.DecimalSeparator, []);
  1026. else
  1027. Result := Param.asstring;
  1028. end; {case}
  1029. end;
  1030. function TSQLConnection.GetHandle: pointer;
  1031. begin
  1032. Result := nil;
  1033. end;
  1034. function TSQLConnection.LogEvent(EventType: TDBEventType): Boolean;
  1035. begin
  1036. Result:=(Assigned(FOnLog) or Assigned(GlobalDBLogHook)) and (EventType in LogEvents);
  1037. end;
  1038. procedure TSQLConnection.Log(EventType: TDBEventType; const Msg: String);
  1039. Var
  1040. M : String;
  1041. begin
  1042. If LogEvent(EventType) then
  1043. begin
  1044. If Assigned(FonLog) then
  1045. FOnLog(Self,EventType,Msg);
  1046. If Assigned(GlobalDBLogHook) then
  1047. begin
  1048. If (Name<>'') then
  1049. M:=Name+' : '+Msg
  1050. else
  1051. M:=ClassName+' : '+Msg;
  1052. GlobalDBLogHook(Self,EventType,M);
  1053. end;
  1054. end;
  1055. end;
  1056. procedure TSQLConnection.RegisterStatement(S: TCustomSQLStatement);
  1057. begin
  1058. if FStatements.IndexOf(S)=-1 then
  1059. FStatements.Add(S);
  1060. end;
  1061. procedure TSQLConnection.UnRegisterStatement(S: TCustomSQLStatement);
  1062. begin
  1063. if Assigned(FStatements) then // Can be nil, when we are destroying and datasets are uncoupled.
  1064. FStatements.Remove(S);
  1065. end;
  1066. procedure TSQLConnection.FreeFldBuffers(cursor: TSQLCursor);
  1067. begin
  1068. // empty
  1069. end;
  1070. function TSQLConnection.GetSchemaInfoSQL( SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string;
  1071. begin
  1072. case SchemaType of
  1073. stProcedures: Result := 'SELECT * FROM INFORMATION_SCHEMA.ROUTINES';
  1074. stSchemata : Result := 'SELECT * FROM INFORMATION_SCHEMA.SCHEMATA';
  1075. else DatabaseError(SMetadataUnavailable);
  1076. end;
  1077. end;
  1078. procedure TSQLConnection.CreateDB;
  1079. begin
  1080. DatabaseError(SNotSupported);
  1081. end;
  1082. procedure TSQLConnection.DropDB;
  1083. begin
  1084. DatabaseError(SNotSupported);
  1085. end;
  1086. { TSQLTransaction }
  1087. procedure TSQLTransaction.EndTransaction;
  1088. begin
  1089. Case Action of
  1090. caCommit :
  1091. Commit;
  1092. caCommitRetaining :
  1093. CommitRetaining;
  1094. caNone,
  1095. caRollback :
  1096. RollBack;
  1097. caRollbackRetaining :
  1098. RollbackRetaining;
  1099. end;
  1100. end;
  1101. procedure TSQLTransaction.SetParams(const AValue: TStringList);
  1102. begin
  1103. FParams.Assign(AValue);
  1104. end;
  1105. function TSQLTransaction.GetHandle: pointer;
  1106. begin
  1107. Result := TSQLConnection(Database).GetTransactionHandle(FTrans);
  1108. end;
  1109. procedure TSQLTransaction.Commit;
  1110. begin
  1111. if active then
  1112. begin
  1113. closedatasets;
  1114. If LogEvent(detCommit) then
  1115. Log(detCommit,SCommitting);
  1116. if TSQLConnection(Database).commit(FTrans) then
  1117. begin
  1118. closeTrans;
  1119. FreeAndNil(FTrans);
  1120. end;
  1121. end;
  1122. end;
  1123. procedure TSQLTransaction.CommitRetaining;
  1124. begin
  1125. if active then
  1126. begin
  1127. If LogEvent(detCommit) then
  1128. Log(detCommit,SCommitRetaining);
  1129. TSQLConnection(Database).commitRetaining(FTrans);
  1130. end;
  1131. end;
  1132. procedure TSQLTransaction.Rollback;
  1133. begin
  1134. if active then
  1135. begin
  1136. closedatasets;
  1137. If LogEvent(detRollback) then
  1138. Log(detRollback,SRollingBack);
  1139. if TSQLConnection(Database).RollBack(FTrans) then
  1140. begin
  1141. CloseTrans;
  1142. FreeAndNil(FTrans);
  1143. end;
  1144. end;
  1145. end;
  1146. procedure TSQLTransaction.RollbackRetaining;
  1147. begin
  1148. if active then
  1149. begin
  1150. If LogEvent(detRollback) then
  1151. Log(detRollback,SRollBackRetaining);
  1152. TSQLConnection(Database).RollBackRetaining(FTrans);
  1153. end;
  1154. end;
  1155. procedure TSQLTransaction.StartTransaction;
  1156. var db : TSQLConnection;
  1157. begin
  1158. if Active then
  1159. DatabaseError(SErrTransAlreadyActive);
  1160. db := TSQLConnection(Database);
  1161. if Db = nil then
  1162. DatabaseError(SErrDatabasenAssigned);
  1163. if not Db.Connected then
  1164. Db.Open;
  1165. if not assigned(FTrans) then FTrans := Db.AllocateTransactionHandle;
  1166. if Db.StartdbTransaction(FTrans,FParams.CommaText) then OpenTrans;
  1167. end;
  1168. constructor TSQLTransaction.Create(AOwner : TComponent);
  1169. begin
  1170. inherited Create(AOwner);
  1171. FParams := TStringList.Create;
  1172. Action:=caRollBack;
  1173. end;
  1174. destructor TSQLTransaction.Destroy;
  1175. begin
  1176. EndTransaction;
  1177. FreeAndNil(FTrans);
  1178. FreeAndNil(FParams);
  1179. inherited Destroy;
  1180. end;
  1181. Procedure TSQLTransaction.SetDatabase(Value : TDatabase);
  1182. begin
  1183. If Value<>Database then
  1184. begin
  1185. if assigned(value) and not (Value is TSQLConnection) then
  1186. DatabaseErrorFmt(SErrNotASQLConnection,[value.Name],self);
  1187. CheckInactive;
  1188. If Assigned(Database) then
  1189. with TSQLConnection(DataBase) do
  1190. if Transaction = self then Transaction := nil;
  1191. inherited SetDatabase(Value);
  1192. If Assigned(Database) and not (csLoading in ComponentState) then
  1193. If (TSQLConnection(DataBase).Transaction=Nil) then
  1194. TSQLConnection(DataBase).Transaction:=Self;
  1195. end;
  1196. end;
  1197. function TSQLTransaction.LogEvent(EventType: TDBEventType): Boolean;
  1198. begin
  1199. Result:=Assigned(Database) and TSQLConnection(Database).LogEvent(EventType);
  1200. end;
  1201. procedure TSQLTransaction.Log(EventType: TDBEventType; const Msg: String);
  1202. Var
  1203. M : String;
  1204. begin
  1205. If LogEVent(EventType) then
  1206. begin
  1207. If (Name<>'') then
  1208. M:=Name+' : '+Msg
  1209. else
  1210. M:=Msg;
  1211. TSQLConnection(Database).Log(EventType,M);
  1212. end;
  1213. end;
  1214. { TCustomSQLQuery }
  1215. (*
  1216. procedure TCustomSQLQuery.OnChangeSQL(Sender : TObject);
  1217. var ConnOptions : TConnOptions;
  1218. NewParams: TParams;
  1219. begin
  1220. FSchemaType:=stNoSchema;
  1221. if (FSQL <> nil) and ParamCheck then
  1222. begin
  1223. if assigned(DataBase) then
  1224. ConnOptions := TSQLConnection(DataBase).ConnOptions
  1225. else
  1226. ConnOptions := [sqEscapeRepeat,sqEscapeSlash];
  1227. //preserve existing param. values
  1228. NewParams := TParams.Create(Self);
  1229. try
  1230. NewParams.ParseSQL(FSQL.Text, True, sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions, psInterbase);
  1231. NewParams.AssignValues(FParams);
  1232. FParams.Assign(NewParams);
  1233. finally
  1234. NewParams.Free;
  1235. end;
  1236. end;
  1237. end;
  1238. *)
  1239. function TCustomSQLQuery.ParamByName(const AParamName: String): TParam;
  1240. begin
  1241. Result:=Params.ParamByName(AParamName);
  1242. end;
  1243. procedure TCustomSQLQuery.OnChangeModifySQL(Sender : TObject);
  1244. begin
  1245. CheckInactive;
  1246. end;
  1247. procedure TCustomSQLQuery.SetTransaction(Value: TDBTransaction);
  1248. begin
  1249. UnPrepare;
  1250. inherited;
  1251. If Assigned(FStatement) then
  1252. FStatement.Transaction:=TSQLTransaction(Value);
  1253. If (Transaction<>Nil) and (Database=Nil) then
  1254. Database:=TSQLTransaction(Transaction).Database;
  1255. end;
  1256. procedure TCustomSQLQuery.SetDatabase(Value : TDatabase);
  1257. var db : tsqlconnection;
  1258. begin
  1259. if (Database <> Value) then
  1260. begin
  1261. if assigned(value) and not (Value is TSQLConnection) then
  1262. DatabaseErrorFmt(SErrNotASQLConnection,[value.Name],self);
  1263. UnPrepare;
  1264. db := TSQLConnection(Value);
  1265. If Assigned(FStatement) then
  1266. FStatement.Database:=DB;
  1267. inherited setdatabase(value);
  1268. (*
  1269. FStatement.Database:=Db,
  1270. if assigned(FCursor) then TSQLConnection(DataBase).DeAllocateCursorHandle(FCursor);
  1271. *)
  1272. if assigned(value) and (Transaction = nil) and (Assigned(db.Transaction)) then
  1273. transaction := Db.Transaction;
  1274. // FStatement.OnChangeSQL(Self);
  1275. end;
  1276. end;
  1277. function TCustomSQLQuery.IsPrepared: Boolean;
  1278. begin
  1279. if Assigned(Fstatement) then
  1280. Result := FStatement.Prepared
  1281. else
  1282. Result := False;
  1283. end;
  1284. function TCustomSQLQuery.AddFilter(SQLstr: string): string;
  1285. begin
  1286. if (FWhereStartPos > 0) and (FWhereStopPos > 0) then
  1287. begin
  1288. system.insert('(',SQLstr,FWhereStartPos+1);
  1289. system.insert(')',SQLstr,FWhereStopPos+1);
  1290. end;
  1291. if FWhereStartPos = 0 then
  1292. SQLstr := SQLstr + ' where (' + ServerFilter + ')'
  1293. else if FWhereStopPos > 0 then
  1294. system.insert(' and ('+ServerFilter+') ',SQLstr,FWhereStopPos+2)
  1295. else
  1296. system.insert(' where ('+ServerFilter+') ',SQLstr,FWhereStartPos);
  1297. Result := SQLstr;
  1298. end;
  1299. procedure TCustomSQLQuery.ApplyFilter;
  1300. var S : String;
  1301. begin
  1302. FreeFldBuffers;
  1303. FStatement.Unprepare;
  1304. FIsEOF := False;
  1305. inherited InternalClose;
  1306. FStatement.DoPrepare;
  1307. FStatement.DoExecute;
  1308. inherited InternalOpen;
  1309. First;
  1310. end;
  1311. procedure TCustomSQLQuery.SetActive(Value: Boolean);
  1312. begin
  1313. inherited SetActive(Value);
  1314. // The query is UnPrepared, so that if a transaction closes all datasets
  1315. // they also get unprepared
  1316. if not Value and IsPrepared then UnPrepare;
  1317. end;
  1318. procedure TCustomSQLQuery.SetServerFiltered(Value: Boolean);
  1319. begin
  1320. if Value and not ParseSQL then
  1321. DatabaseErrorFmt(SNoParseSQL,['Filtering ']);
  1322. if (ServerFiltered <> Value) then
  1323. begin
  1324. FServerFiltered := Value;
  1325. if active then
  1326. ApplyFilter;
  1327. end;
  1328. end;
  1329. procedure TCustomSQLQuery.SetServerFilterText(const Value: string);
  1330. begin
  1331. if Value <> ServerFilter then
  1332. begin
  1333. FServerFilterText := Value;
  1334. if active then ApplyFilter;
  1335. end;
  1336. end;
  1337. procedure TCustomSQLQuery.Prepare;
  1338. begin
  1339. FStatement.Prepare;
  1340. If Assigned(Fstatement.FCursor) then
  1341. With FStatement.FCursor do
  1342. FInitFieldDef:=FSelectable;
  1343. end;
  1344. procedure TCustomSQLQuery.UnPrepare;
  1345. begin
  1346. CheckInactive;
  1347. If Assigned(FStatement) then
  1348. FStatement.Unprepare;
  1349. end;
  1350. procedure TCustomSQLQuery.FreeFldBuffers;
  1351. begin
  1352. if assigned(Cursor) then
  1353. TSQLConnection(Database).FreeFldBuffers(Cursor);
  1354. end;
  1355. function TCustomSQLQuery.GetParamCheck: Boolean;
  1356. begin
  1357. Result:=FStatement.ParamCheck;
  1358. end;
  1359. function TCustomSQLQuery.GetParams: TParams;
  1360. begin
  1361. Result:=FStatement.Params;
  1362. end;
  1363. function TCustomSQLQuery.GetParseSQL: Boolean;
  1364. begin
  1365. Result:=FStatement.ParseSQL;
  1366. end;
  1367. function TCustomSQLQuery.GetServerIndexDefs: TServerIndexDefs;
  1368. begin
  1369. Result := FServerIndexDefs;
  1370. end;
  1371. function TCustomSQLQuery.GetSQL: TStringlist;
  1372. begin
  1373. Result:=TStringList(Fstatement.SQL);
  1374. end;
  1375. function TCustomSQLQuery.Fetch : boolean;
  1376. begin
  1377. if Not Assigned(Cursor) then
  1378. Exit;
  1379. if not Cursor.FSelectable then
  1380. Exit;
  1381. If LogEvent(detFetch) then
  1382. Log(detFetch,FSQLBuf);
  1383. if not FIsEof then FIsEOF := not TSQLConnection(Database).Fetch(Cursor);
  1384. Result := not FIsEOF;
  1385. end;
  1386. function TCustomSQLQuery.Cursor: TSQLCursor;
  1387. begin
  1388. Result:=FStatement.Cursor;
  1389. end;
  1390. procedure TCustomSQLQuery.Execute;
  1391. begin
  1392. FStatement.Execute;
  1393. end;
  1394. function TCustomSQLQuery.RowsAffected: TRowsCount;
  1395. begin
  1396. Result:=Fstatement.RowsAffected;
  1397. end;
  1398. function TCustomSQLQuery.LoadField(FieldDef : TFieldDef;buffer : pointer; out CreateBlob : boolean) : boolean;
  1399. begin
  1400. result := TSQLConnection(Database).LoadField(Cursor,FieldDef,buffer, Createblob)
  1401. end;
  1402. procedure TCustomSQLQuery.LoadBlobIntoBuffer(FieldDef: TFieldDef;
  1403. ABlobBuf: PBufBlobField);
  1404. begin
  1405. TSQLConnection(DataBase).LoadBlobIntoBuffer(FieldDef, ABlobBuf, Cursor,(Transaction as TSQLTransaction));
  1406. end;
  1407. procedure TCustomSQLQuery.InternalAddRecord(Buffer: Pointer; AAppend: Boolean);
  1408. begin
  1409. // not implemented - sql dataset
  1410. end;
  1411. procedure TCustomSQLQuery.InternalClose;
  1412. begin
  1413. if assigned(Cursor) then
  1414. begin
  1415. if Cursor.FSelectable then
  1416. FreeFldBuffers;
  1417. // Some SQLConnections does not support statement [un]preparation,
  1418. // so let them do cleanup f.e. cancel pending queries and/or free resultset
  1419. if not Prepared then FStatement.DoUnprepare;
  1420. end;
  1421. if DefaultFields then
  1422. DestroyFields;
  1423. FIsEOF := False;
  1424. if assigned(FUpdateQry) then FreeAndNil(FUpdateQry);
  1425. if assigned(FInsertQry) then FreeAndNil(FInsertQry);
  1426. if assigned(FDeleteQry) then FreeAndNil(FDeleteQry);
  1427. // FRecordSize := 0;
  1428. inherited InternalClose;
  1429. end;
  1430. procedure TCustomSQLQuery.InternalInitFieldDefs;
  1431. begin
  1432. if FLoadingFieldDefs then
  1433. Exit;
  1434. FLoadingFieldDefs := True;
  1435. try
  1436. FieldDefs.Clear;
  1437. if not Assigned(Database) then DatabaseError(SErrDatabasenAssigned);
  1438. TSQLConnection(Database).AddFieldDefs(Cursor,FieldDefs);
  1439. finally
  1440. FLoadingFieldDefs := False;
  1441. if Assigned(Cursor) then Cursor.FInitFieldDef := false;
  1442. end;
  1443. end;
  1444. (*
  1445. function TCustomSQLQuery.SQLParser(const ASQL : string) : TStatementType;
  1446. Var
  1447. I : TSQLStatementInfo;
  1448. begin
  1449. I:=(Database as TSQLConnection).GetStatementInfo(ASQL,ParseSQL,SchemaType);
  1450. FTableName:=I.TableName;
  1451. FUpdateable:=I.Updateable;
  1452. FWhereStartPos:=I.WhereStartPos;
  1453. FWhereStopPos:=I.WhereStopPos;
  1454. Result:=I.StatementType;
  1455. end;
  1456. *)
  1457. function TSQLConnection.GetStatementInfo(const ASQL: string; Full: Boolean;
  1458. ASchema: TSchemaType): TSQLStatementInfo;
  1459. type TParsePart = (ppStart,ppWith,ppSelect,ppTableName,ppFrom,ppWhere,ppGroup,ppOrder,ppBogus);
  1460. TPhraseSeparator = (sepNone, sepWhiteSpace, sepComma, sepComment, sepParentheses, sepDoubleQuote, sepEnd);
  1461. TKeyword = (kwWITH, kwSELECT, kwINSERT, kwUPDATE, kwDELETE, kwFROM, kwJOIN, kwWHERE, kwGROUP, kwORDER, kwUNION, kwROWS, kwLIMIT, kwUnknown);
  1462. const
  1463. KeywordNames: array[TKeyword] of string =
  1464. ('WITH', 'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'FROM', 'JOIN', 'WHERE', 'GROUP', 'ORDER', 'UNION', 'ROWS', 'LIMIT', '');
  1465. var
  1466. PSQL, CurrentP, SavedP,
  1467. PhraseP, PStatementPart : pchar;
  1468. S : string;
  1469. ParsePart : TParsePart;
  1470. BracketCount : Integer;
  1471. Separator : TPhraseSeparator;
  1472. Keyword, K : TKeyword;
  1473. begin
  1474. PSQL:=Pchar(ASQL);
  1475. ParsePart := ppStart;
  1476. CurrentP := PSQL-1;
  1477. PhraseP := PSQL;
  1478. Result.TableName := '';
  1479. Result.Updateable := False;
  1480. Result.WhereStartPos := 0;
  1481. Result.WhereStopPos := 0;
  1482. repeat
  1483. begin
  1484. inc(CurrentP);
  1485. SavedP := CurrentP;
  1486. case CurrentP^ of
  1487. ' ', #9..#13:
  1488. Separator := sepWhiteSpace;
  1489. ',':
  1490. Separator := sepComma;
  1491. #0, ';':
  1492. Separator := sepEnd;
  1493. '(':
  1494. begin
  1495. Separator := sepParentheses;
  1496. // skip everything between brackets, since it could be a sub-select, and
  1497. // further nothing between brackets could be interesting for the parser.
  1498. BracketCount := 1;
  1499. repeat
  1500. inc(CurrentP);
  1501. if CurrentP^ = '(' then inc(BracketCount)
  1502. else if CurrentP^ = ')' then dec(BracketCount);
  1503. until (CurrentP^ = #0) or (BracketCount = 0);
  1504. if CurrentP^ <> #0 then inc(CurrentP);
  1505. end;
  1506. '"','`':
  1507. if SkipComments(CurrentP, sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions) then
  1508. Separator := sepDoubleQuote;
  1509. else
  1510. if SkipComments(CurrentP, sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions) then
  1511. Separator := sepComment
  1512. else
  1513. Separator := sepNone;
  1514. end;
  1515. if (CurrentP > SavedP) and (SavedP > PhraseP) then
  1516. CurrentP := SavedP; // there is something before comment or left parenthesis
  1517. if Separator <> sepNone then
  1518. begin
  1519. if ((Separator in [sepWhitespace,sepComment]) and (PhraseP = SavedP)) then
  1520. PhraseP := CurrentP; // skip comments (but not parentheses) and white spaces
  1521. if (CurrentP-PhraseP > 0) or (Separator = sepEnd) then
  1522. begin
  1523. SetString(s, PhraseP, CurrentP-PhraseP);
  1524. Keyword := kwUnknown;
  1525. for K in TKeyword do
  1526. if SameText(s, KeywordNames[K]) then
  1527. begin
  1528. Keyword := K;
  1529. break;
  1530. end;
  1531. case ParsePart of
  1532. ppStart : begin
  1533. Result.StatementType := StrToStatementType(s);
  1534. case Keyword of
  1535. kwWITH : ParsePart := ppWith;
  1536. kwSELECT: ParsePart := ppSelect;
  1537. else break;
  1538. end;
  1539. if not Full then break;
  1540. end;
  1541. ppWith : begin
  1542. // WITH [RECURSIVE] CTE_name [ ( column_names ) ] AS ( CTE_query_definition ) [, ...]
  1543. // { SELECT | INSERT | UPDATE | DELETE } ...
  1544. case Keyword of
  1545. kwSELECT: Result.StatementType := stSelect;
  1546. kwINSERT: Result.StatementType := stInsert;
  1547. kwUPDATE: Result.StatementType := stUpdate;
  1548. kwDELETE: Result.StatementType := stDelete;
  1549. end;
  1550. if Result.StatementType <> stUnknown then break;
  1551. end;
  1552. ppSelect : begin
  1553. if Keyword = kwFROM then
  1554. ParsePart := ppTableName;
  1555. end;
  1556. ppTableName:
  1557. begin
  1558. // Meta-data requests are never updateable
  1559. // and select statements from more than one table
  1560. // and/or derived tables are also not updateable
  1561. if (ASchema = stNoSchema) and
  1562. (Separator in [sepWhitespace, sepComment, sepDoubleQuote, sepEnd]) then
  1563. begin
  1564. Result.TableName := s;
  1565. Result.Updateable := True;
  1566. end;
  1567. ParsePart := ppFrom;
  1568. end;
  1569. ppFrom : begin
  1570. if (Keyword in [kwWHERE, kwGROUP, kwORDER, kwLIMIT, kwROWS]) or
  1571. (Separator = sepEnd) then
  1572. begin
  1573. case Keyword of
  1574. kwWHERE: ParsePart := ppWhere;
  1575. kwGROUP: ParsePart := ppGroup;
  1576. kwORDER: ParsePart := ppOrder;
  1577. else ParsePart := ppBogus;
  1578. end;
  1579. Result.WhereStartPos := PhraseP-PSQL+1;
  1580. PStatementPart := CurrentP;
  1581. end
  1582. else
  1583. // joined table or user_defined_function (...)
  1584. if (Keyword = kwJOIN) or (Separator in [sepComma, sepParentheses]) then
  1585. begin
  1586. Result.TableName := '';
  1587. Result.Updateable := False;
  1588. end;
  1589. end;
  1590. ppWhere : begin
  1591. if (Keyword in [kwGROUP, kwORDER, kwLIMIT, kwROWS]) or
  1592. (Separator = sepEnd) then
  1593. begin
  1594. ParsePart := ppBogus;
  1595. Result.WhereStartPos := PStatementPart-PSQL;
  1596. if (Separator = sepEnd) then
  1597. Result.WhereStopPos := CurrentP-PSQL+1
  1598. else
  1599. Result.WhereStopPos := PhraseP-PSQL+1;
  1600. end
  1601. else if (Keyword = kwUNION) then
  1602. begin
  1603. ParsePart := ppBogus;
  1604. Result.Updateable := False;
  1605. end;
  1606. end;
  1607. end; {case}
  1608. end;
  1609. if Separator in [sepComment, sepParentheses, sepDoubleQuote] then
  1610. dec(CurrentP);
  1611. PhraseP := CurrentP+1;
  1612. end
  1613. end;
  1614. until CurrentP^=#0;
  1615. end;
  1616. procedure TCustomSQLQuery.InternalOpen;
  1617. var counter, fieldc : integer;
  1618. f : TField;
  1619. IndexFields : TStrings;
  1620. begin
  1621. if IsReadFromPacket then
  1622. begin
  1623. // When we read from file there is no need for Cursor, also note that Database may not be assigned
  1624. //FStatement.AllocateCursor;
  1625. //Cursor.FSelectable:=True;
  1626. //Cursor.FStatementType:=stSelect;
  1627. FUpdateable:=True;
  1628. BindFields(True);
  1629. end
  1630. else
  1631. begin
  1632. Prepare;
  1633. if not Cursor.FSelectable then
  1634. DatabaseError(SErrNoSelectStatement,Self);
  1635. // Call UpdateServerIndexDefs before Execute, to avoid problems with connections
  1636. // which do not allow processing multiple recordsets at a time. (Microsoft
  1637. // calls this MARS, see bug 13241)
  1638. if DefaultFields and FUpdateable and FusePrimaryKeyAsKey and (not IsUniDirectional) then
  1639. UpdateServerIndexDefs;
  1640. Execute;
  1641. if not Cursor.FSelectable then
  1642. DatabaseError(SErrNoSelectStatement,Self);
  1643. // InternalInitFieldDef is only called after a prepare. i.e. not twice if
  1644. // a dataset is opened - closed - opened.
  1645. if Cursor.FInitFieldDef then InternalInitFieldDefs;
  1646. if DefaultFields then
  1647. begin
  1648. CreateFields;
  1649. if FUpdateable and (not IsUniDirectional) then
  1650. begin
  1651. if FusePrimaryKeyAsKey then
  1652. begin
  1653. for counter := 0 to ServerIndexDefs.count-1 do
  1654. begin
  1655. if ixPrimary in ServerIndexDefs[counter].options then
  1656. begin
  1657. IndexFields := TStringList.Create;
  1658. ExtractStrings([';'],[' '],pchar(ServerIndexDefs[counter].fields),IndexFields);
  1659. for fieldc := 0 to IndexFields.Count-1 do
  1660. begin
  1661. F := Findfield(IndexFields[fieldc]);
  1662. if F <> nil then
  1663. F.ProviderFlags := F.ProviderFlags + [pfInKey];
  1664. end;
  1665. IndexFields.Free;
  1666. end;
  1667. end;
  1668. end;
  1669. end;
  1670. end
  1671. else
  1672. BindFields(True);
  1673. end;
  1674. if not ReadOnly and not FUpdateable and (FSchemaType=stNoSchema) then
  1675. begin
  1676. if (trim(FDeleteSQL.Text) <> '') or (trim(FUpdateSQL.Text) <> '') or
  1677. (trim(FInsertSQL.Text) <> '') then FUpdateable := True;
  1678. end;
  1679. inherited InternalOpen;
  1680. end;
  1681. // public part
  1682. procedure TCustomSQLQuery.ExecSQL;
  1683. begin
  1684. try
  1685. Prepare;
  1686. Execute;
  1687. finally
  1688. // Cursor has to be assigned, or else the prepare went wrong before PrepareStatment was
  1689. // called, so UnPrepareStatement shoudn't be called either
  1690. // Don't deallocate cursor; f.e. RowsAffected is requested later
  1691. if not Prepared and (assigned(Database)) and (assigned(Cursor)) then TSQLConnection(Database).UnPrepareStatement(Cursor);
  1692. end;
  1693. end;
  1694. Type
  1695. { TQuerySQLStatement }
  1696. TQuerySQLStatement = Class(TCustomSQLStatement)
  1697. protected
  1698. FQuery : TCustomSQLQuery;
  1699. Function CreateDataLink : TDataLink; override;
  1700. Function GetSchemaType : TSchemaType; override;
  1701. Function GetSchemaObjectName : String; override;
  1702. Function GetSchemaPattern: String; override;
  1703. procedure GetStatementInfo(Var ASQL: String; Full: Boolean; ASchema: TSchemaType; out Info: TSQLStatementInfo); override;
  1704. procedure OnChangeSQL(Sender : TObject); override;
  1705. end;
  1706. { TQuerySQLStatement }
  1707. function TQuerySQLStatement.CreateDataLink: TDataLink;
  1708. begin
  1709. Result:=TMasterParamsDataLink.Create(FQuery);
  1710. end;
  1711. function TQuerySQLStatement.GetSchemaType: TSchemaType;
  1712. begin
  1713. if Assigned(FQuery) then
  1714. Result:=FQuery.FSchemaType
  1715. else
  1716. Result:=stNoSchema;
  1717. end;
  1718. function TQuerySQLStatement.GetSchemaObjectName: String;
  1719. begin
  1720. if Assigned(FQuery) then
  1721. Result:=FQuery.FSchemaObjectname
  1722. else
  1723. Result:=inherited GetSchemaObjectName;
  1724. end;
  1725. function TQuerySQLStatement.GetSchemaPattern: String;
  1726. begin
  1727. if Assigned(FQuery) then
  1728. Result:=FQuery.FSchemaPattern
  1729. else
  1730. Result:=inherited GetSchemaPattern;
  1731. end;
  1732. procedure TQuerySQLStatement.GetStatementInfo(var ASQL: String; Full: Boolean;
  1733. ASchema: TSchemaType; out Info: TSQLStatementInfo);
  1734. begin
  1735. inherited GetStatementInfo(ASQL, Full, ASchema, Info);
  1736. If Assigned(FQuery) then
  1737. begin
  1738. FQuery.FWhereStartPos:=Info.WhereStartPos;
  1739. FQuery.FWhereStopPos:=Info.WhereStopPos;
  1740. FQuery.FUpdateable:=info.Updateable;
  1741. FQuery.FTableName:=Info.TableName;
  1742. if FQuery.ServerFiltered then
  1743. ASQL:=FQuery.AddFilter(ASQL);
  1744. end;
  1745. end;
  1746. procedure TQuerySQLStatement.OnChangeSQL(Sender: TObject);
  1747. begin
  1748. UnPrepare;
  1749. inherited OnChangeSQL(Sender);
  1750. If ParamCheck and Assigned(FDataLink) then
  1751. (FDataLink as TMasterParamsDataLink).RefreshParamNames;
  1752. FQuery.ServerIndexDefs.Updated:=false;
  1753. end;
  1754. constructor TCustomSQLQuery.Create(AOwner : TComponent);
  1755. Var
  1756. F : TQuerySQLStatement;
  1757. begin
  1758. inherited Create(AOwner);
  1759. F:=TQuerySQLStatement.Create(Self);
  1760. F.FQuery:=Self;
  1761. FStatement:=F;
  1762. //FSQL := TStringList.Create;
  1763. // FSQL.OnChange := @OnChangeSQL;
  1764. FUpdateSQL := TStringList.Create;
  1765. FUpdateSQL.OnChange := @OnChangeModifySQL;
  1766. FInsertSQL := TStringList.Create;
  1767. FInsertSQL.OnChange := @OnChangeModifySQL;
  1768. FDeleteSQL := TStringList.Create;
  1769. FDeleteSQL.OnChange := @OnChangeModifySQL;
  1770. FServerIndexDefs := TServerIndexDefs.Create(Self);
  1771. FServerFiltered := False;
  1772. FServerFilterText := '';
  1773. FSchemaType:=stNoSchema;
  1774. FSchemaObjectName:='';
  1775. FSchemaPattern:='';
  1776. // Delphi has upWhereAll as default, but since strings and oldvalue's don't work yet
  1777. // (variants) set it to upWhereKeyOnly
  1778. FUpdateMode := upWhereKeyOnly;
  1779. FUsePrimaryKeyAsKey := True;
  1780. end;
  1781. destructor TCustomSQLQuery.Destroy;
  1782. begin
  1783. if Active then Close;
  1784. UnPrepare;
  1785. FreeAndNil(Fstatement);
  1786. // FreeAndNil(FSQL);
  1787. FreeAndNil(FInsertSQL);
  1788. FreeAndNil(FDeleteSQL);
  1789. FreeAndNil(FUpdateSQL);
  1790. FServerIndexDefs.Free;
  1791. inherited Destroy;
  1792. end;
  1793. procedure TCustomSQLQuery.SetReadOnly(AValue : Boolean);
  1794. begin
  1795. CheckInactive;
  1796. inherited SetReadOnly(AValue);
  1797. end;
  1798. procedure TCustomSQLQuery.SetParseSQL(AValue : Boolean);
  1799. begin
  1800. CheckInactive;
  1801. FStatement.ParseSQL:=AValue;
  1802. if not AValue then
  1803. FServerFiltered := False;
  1804. end;
  1805. procedure TCustomSQLQuery.SetSQL(const AValue: TStringlist);
  1806. begin
  1807. FStatement.SQL.Assign(AValue);
  1808. end;
  1809. procedure TCustomSQLQuery.SetUpdateSQL(const AValue: TStringlist);
  1810. begin
  1811. FUpdateSQL.Assign(AValue);
  1812. end;
  1813. procedure TCustomSQLQuery.SetUsePrimaryKeyAsKey(AValue : Boolean);
  1814. begin
  1815. if not Active then FusePrimaryKeyAsKey := AValue
  1816. else
  1817. begin
  1818. // Just temporary, this should be possible in the future
  1819. DatabaseError(SActiveDataset);
  1820. end;
  1821. end;
  1822. procedure TCustomSQLQuery.UpdateServerIndexDefs;
  1823. begin
  1824. FServerIndexDefs.Clear;
  1825. if assigned(DataBase) and (FTableName<>'') then
  1826. TSQLConnection(DataBase).UpdateIndexDefs(ServerIndexDefs,FTableName);
  1827. end;
  1828. procedure TCustomSQLQuery.ApplyRecUpdate(UpdateKind: TUpdateKind);
  1829. var FieldNamesQuoteChars : TQuoteChars;
  1830. function InitialiseModifyQuery(var qry : TCustomSQLQuery): TCustomSQLQuery;
  1831. begin
  1832. if not assigned(qry) then
  1833. begin
  1834. qry := TCustomSQLQuery.Create(nil);
  1835. qry.ParseSQL := False;
  1836. qry.DataBase := Self.DataBase;
  1837. qry.Transaction := Self.Transaction;
  1838. end;
  1839. Result:=qry;
  1840. end;
  1841. procedure UpdateWherePart(var sql_where : string;x : integer);
  1842. begin
  1843. if (pfInKey in Fields[x].ProviderFlags) or
  1844. ((FUpdateMode = upWhereAll) and (pfInWhere in Fields[x].ProviderFlags)) or
  1845. ((FUpdateMode = UpWhereChanged) and (pfInWhere in Fields[x].ProviderFlags) and (Fields[x].Value <> Fields[x].OldValue)) then
  1846. if Fields[x].OldValue = NULL then
  1847. sql_where := sql_where + FieldNamesQuoteChars[0] + Fields[x].FieldName + FieldNamesQuoteChars[1] + ' is null and '
  1848. else
  1849. sql_where := sql_where + '(' + FieldNamesQuoteChars[0] + Fields[x].FieldName + FieldNamesQuoteChars[1] + '= :"' + 'OLD_' + Fields[x].FieldName + '") and ';
  1850. end;
  1851. function ModifyRecQuery : string;
  1852. var x : integer;
  1853. sql_set : string;
  1854. sql_where : string;
  1855. begin
  1856. sql_set := '';
  1857. sql_where := '';
  1858. for x := 0 to Fields.Count -1 do
  1859. begin
  1860. UpdateWherePart(sql_where,x);
  1861. if (pfInUpdate in Fields[x].ProviderFlags) and (not Fields[x].ReadOnly) then
  1862. sql_set := sql_set +FieldNamesQuoteChars[0] + fields[x].FieldName + FieldNamesQuoteChars[1] +'=:"' + fields[x].FieldName + '",';
  1863. end;
  1864. if length(sql_set) = 0 then DatabaseErrorFmt(sNoUpdateFields,['update'],self);
  1865. setlength(sql_set,length(sql_set)-1);
  1866. if length(sql_where) = 0 then DatabaseErrorFmt(sNoWhereFields,['update'],self);
  1867. setlength(sql_where,length(sql_where)-5);
  1868. result := 'update ' + FTableName + ' set ' + sql_set + ' where ' + sql_where;
  1869. end;
  1870. function InsertRecQuery : string;
  1871. var x : integer;
  1872. sql_fields : string;
  1873. sql_values : string;
  1874. begin
  1875. sql_fields := '';
  1876. sql_values := '';
  1877. for x := 0 to Fields.Count -1 do
  1878. begin
  1879. if (not Fields[x].IsNull) and (pfInUpdate in Fields[x].ProviderFlags) and (not Fields[x].ReadOnly) then
  1880. begin
  1881. sql_fields := sql_fields + FieldNamesQuoteChars[0] + fields[x].FieldName + FieldNamesQuoteChars[1] + ',';
  1882. sql_values := sql_values + ':"' + fields[x].FieldName + '",';
  1883. end;
  1884. end;
  1885. if length(sql_fields) = 0 then DatabaseErrorFmt(sNoUpdateFields,['insert'],self);
  1886. setlength(sql_fields,length(sql_fields)-1);
  1887. setlength(sql_values,length(sql_values)-1);
  1888. result := 'insert into ' + FTableName + ' (' + sql_fields + ') values (' + sql_values + ')';
  1889. end;
  1890. function DeleteRecQuery : string;
  1891. var x : integer;
  1892. sql_where : string;
  1893. begin
  1894. sql_where := '';
  1895. for x := 0 to Fields.Count -1 do
  1896. UpdateWherePart(sql_where,x);
  1897. if length(sql_where) = 0 then DatabaseErrorFmt(sNoWhereFields,['delete'],self);
  1898. setlength(sql_where,length(sql_where)-5);
  1899. result := 'delete from ' + FTableName + ' where ' + sql_where;
  1900. end;
  1901. var qry : TCustomSQLQuery;
  1902. s : string;
  1903. x : integer;
  1904. Fld : TField;
  1905. begin
  1906. FieldNamesQuoteChars := TSQLConnection(DataBase).FieldNameQuoteChars;
  1907. case UpdateKind of
  1908. ukInsert : begin
  1909. s := trim(FInsertSQL.Text);
  1910. if s = '' then s := InsertRecQuery;
  1911. qry := InitialiseModifyQuery(FInsertQry);
  1912. end;
  1913. ukModify : begin
  1914. s := trim(FUpdateSQL.Text);
  1915. if (s='') and (not assigned(FUpdateQry) or (UpdateMode<>upWhereKeyOnly)) then //first time or dynamic where part
  1916. s := ModifyRecQuery;
  1917. qry := InitialiseModifyQuery(FUpdateQry);
  1918. end;
  1919. ukDelete : begin
  1920. s := trim(FDeleteSQL.Text);
  1921. if (s='') and (not assigned(FDeleteQry) or (UpdateMode<>upWhereKeyOnly)) then
  1922. s := DeleteRecQuery;
  1923. qry := InitialiseModifyQuery(FDeleteQry);
  1924. end;
  1925. end;
  1926. if (qry.SQL.Text<>s) and (s<>'') then qry.SQL.Text:=s; //assign only when changed, to avoid UnPrepare/Prepare
  1927. assert(qry.sql.Text<>'');
  1928. with qry do
  1929. begin
  1930. for x := 0 to Params.Count-1 do with params[x] do if sametext(leftstr(name,4),'OLD_') then
  1931. begin
  1932. Fld := self.FieldByName(copy(name,5,length(name)-4));
  1933. AssignFieldValue(Fld,Fld.OldValue);
  1934. end
  1935. else
  1936. begin
  1937. Fld := self.FieldByName(name);
  1938. AssignFieldValue(Fld,Fld.Value);
  1939. end;
  1940. execsql;
  1941. end;
  1942. end;
  1943. function TCustomSQLQuery.GetCanModify: Boolean;
  1944. begin
  1945. // the test for assigned(Cursor) is needed for the case that the dataset isn't opened
  1946. if assigned(Cursor) and (Cursor.FStatementType = stSelect) then
  1947. Result:= FUpdateable and (not ReadOnly) and (not IsUniDirectional)
  1948. else
  1949. Result := False;
  1950. end;
  1951. procedure TCustomSQLQuery.SetUpdateMode(AValue : TUpdateMode);
  1952. begin
  1953. FUpdateMode := AValue;
  1954. end;
  1955. procedure TCustomSQLQuery.SetSchemaInfo( ASchemaType : TSchemaType; ASchemaObjectName, ASchemaPattern : string);
  1956. begin
  1957. FSchemaType:=ASchemaType;
  1958. FSchemaObjectName:=ASchemaObjectName;
  1959. FSchemaPattern:=ASchemaPattern;
  1960. end;
  1961. procedure TCustomSQLQuery.BeforeRefreshOpenCursor;
  1962. begin
  1963. // This is only necessary because TIBConnection can not re-open a
  1964. // prepared cursor. In fact this is wrong, but has never led to
  1965. // problems because in SetActive(false) queries are always
  1966. // unprepared. (which is also wrong, but has to be fixed later)
  1967. if IsPrepared then with TSQLConnection(DataBase) do
  1968. UnPrepareStatement(Cursor);
  1969. end;
  1970. function TCustomSQLQuery.LogEvent(EventType: TDBEventType): Boolean;
  1971. begin
  1972. Result:=Assigned(Database) and TSQLConnection(Database).LogEvent(EventType);
  1973. end;
  1974. procedure TCustomSQLQuery.Log(EventType: TDBEventType; const Msg: String);
  1975. Var
  1976. M : String;
  1977. begin
  1978. If LogEvent(EventType) then
  1979. begin
  1980. M:=Msg;
  1981. If (Name<>'') then
  1982. M:=Name+' : '+M;
  1983. TSQLConnection(Database).Log(EventType,M);
  1984. end;
  1985. end;
  1986. function TCustomSQLQuery.GetStatementType : TStatementType;
  1987. begin
  1988. if Assigned(Cursor) then
  1989. Result:=Cursor.FStatementType
  1990. else
  1991. Result:=stUnknown;
  1992. end;
  1993. procedure TCustomSQLQuery.SetParamCheck(AValue: Boolean);
  1994. begin
  1995. FStatement.ParamCheck:=AValue;
  1996. end;
  1997. procedure TCustomSQLQuery.SetDeleteSQL(const AValue: TStringlist);
  1998. begin
  1999. FDeleteSQL.Assign(AValue);
  2000. end;
  2001. procedure TCustomSQLQuery.SetInsertSQL(const AValue: TStringlist);
  2002. begin
  2003. FInsertSQL.Assign(AValue);
  2004. end;
  2005. procedure TCustomSQLQuery.SetParams(AValue: TParams);
  2006. begin
  2007. FStatement.Params.Assign(AValue);
  2008. end;
  2009. procedure TCustomSQLQuery.SetDataSource(AValue: TDataSource);
  2010. Var
  2011. DS : TDataSource;
  2012. begin
  2013. DS:=DataSource;
  2014. If (AValue<>DS) then
  2015. begin
  2016. If Assigned(AValue) and (AValue.Dataset=Self) then
  2017. DatabaseError(SErrCircularDataSourceReferenceNotAllowed,Self);
  2018. If Assigned(DS) then
  2019. DS.RemoveFreeNotification(Self);
  2020. FStatement.DataSource:=AValue;
  2021. end;
  2022. end;
  2023. function TCustomSQLQuery.GetDataSource: TDataSource;
  2024. begin
  2025. If Assigned(FStatement) then
  2026. Result:=FStatement.DataSource
  2027. else
  2028. Result:=Nil;
  2029. end;
  2030. procedure TCustomSQLQuery.Notification(AComponent: TComponent; Operation: TOperation);
  2031. begin
  2032. Inherited;
  2033. If (Operation=opRemove) and (AComponent=DataSource) then
  2034. DataSource:=Nil;
  2035. end;
  2036. { TSQLScript }
  2037. procedure TSQLScript.ExecuteStatement(SQLStatement: TStrings;
  2038. var StopExecution: Boolean);
  2039. begin
  2040. fquery.SQL.assign(SQLStatement);
  2041. fquery.ExecSQL;
  2042. end;
  2043. procedure TSQLScript.ExecuteDirective(Directive, Argument: String;
  2044. var StopExecution: Boolean);
  2045. begin
  2046. if assigned (FOnDirective) then
  2047. FOnDirective (Self, Directive, Argument, StopExecution);
  2048. end;
  2049. procedure TSQLScript.ExecuteCommit(CommitRetaining: boolean=true);
  2050. begin
  2051. if FTransaction is TSQLTransaction then
  2052. if CommitRetaining then
  2053. TSQLTransaction(FTransaction).CommitRetaining
  2054. else
  2055. begin
  2056. TSQLTransaction(FTransaction).Commit;
  2057. TSQLTransaction(FTransaction).StartTransaction;
  2058. end
  2059. else
  2060. begin
  2061. FTransaction.Active := false;
  2062. FTransaction.Active := true;
  2063. end;
  2064. end;
  2065. procedure TSQLScript.SetDatabase(Value: TDatabase);
  2066. begin
  2067. FDatabase := Value;
  2068. end;
  2069. procedure TSQLScript.SetTransaction(Value: TDBTransaction);
  2070. begin
  2071. FTransaction := Value;
  2072. end;
  2073. procedure TSQLScript.CheckDatabase;
  2074. begin
  2075. If (FDatabase=Nil) then
  2076. DatabaseError(SErrNoDatabaseAvailable,Self)
  2077. end;
  2078. constructor TSQLScript.Create(AOwner: TComponent);
  2079. begin
  2080. inherited Create(AOwner);
  2081. FQuery := TCustomSQLQuery.Create(nil);
  2082. FQuery.ParamCheck := false; // Do not parse for parameters; breaks use of e.g. select bla into :bla in Firebird procedures
  2083. end;
  2084. destructor TSQLScript.Destroy;
  2085. begin
  2086. FQuery.Free;
  2087. inherited Destroy;
  2088. end;
  2089. procedure TSQLScript.Execute;
  2090. begin
  2091. FQuery.DataBase := FDatabase;
  2092. FQuery.Transaction := FTransaction;
  2093. inherited Execute;
  2094. end;
  2095. procedure TSQLScript.ExecuteScript;
  2096. begin
  2097. Execute;
  2098. end;
  2099. { Connection definitions }
  2100. Var
  2101. ConnDefs : TStringList;
  2102. Procedure CheckDefs;
  2103. begin
  2104. If (ConnDefs=Nil) then
  2105. begin
  2106. ConnDefs:=TStringList.Create;
  2107. ConnDefs.Sorted:=True;
  2108. ConnDefs.Duplicates:=dupError;
  2109. end;
  2110. end;
  2111. Procedure DoneDefs;
  2112. Var
  2113. I : Integer;
  2114. begin
  2115. If Assigned(ConnDefs) then
  2116. begin
  2117. For I:=ConnDefs.Count-1 downto 0 do
  2118. begin
  2119. ConnDefs.Objects[i].Free;
  2120. ConnDefs.Delete(I);
  2121. end;
  2122. FreeAndNil(ConnDefs);
  2123. end;
  2124. end;
  2125. Function GetConnectionDef(ConnectorName : String) : TConnectionDef;
  2126. Var
  2127. I : Integer;
  2128. begin
  2129. CheckDefs;
  2130. I:=ConnDefs.IndexOf(ConnectorName);
  2131. If (I<>-1) then
  2132. Result:=TConnectionDef(ConnDefs.Objects[i])
  2133. else
  2134. Result:=Nil;
  2135. end;
  2136. procedure RegisterConnection(Def: TConnectionDefClass);
  2137. Var
  2138. I : Integer;
  2139. begin
  2140. CheckDefs;
  2141. I:=ConnDefs.IndexOf(Def.TypeName);
  2142. If (I=-1) then
  2143. ConnDefs.AddObject(Def.TypeName,Def.Create)
  2144. else
  2145. begin
  2146. ConnDefs.Objects[I].Free;
  2147. ConnDefs.Objects[I]:=Def.Create;
  2148. end;
  2149. end;
  2150. procedure UnRegisterConnection(Def: TConnectionDefClass);
  2151. begin
  2152. UnRegisterConnection(Def.TypeName);
  2153. end;
  2154. procedure UnRegisterConnection(ConnectionName: String);
  2155. Var
  2156. I : Integer;
  2157. begin
  2158. if (ConnDefs<>Nil) then
  2159. begin
  2160. I:=ConnDefs.IndexOf(ConnectionName);
  2161. If (I<>-1) then
  2162. begin
  2163. ConnDefs.Objects[I].Free;
  2164. ConnDefs.Delete(I);
  2165. end;
  2166. end;
  2167. end;
  2168. procedure GetConnectionList(List: TSTrings);
  2169. begin
  2170. CheckDefs;
  2171. List.Text:=ConnDefs.Text;
  2172. end;
  2173. { TSQLConnector }
  2174. procedure TSQLConnector.SetConnectorType(const AValue: String);
  2175. begin
  2176. if FConnectorType<>AValue then
  2177. begin
  2178. CheckDisconnected;
  2179. If Assigned(FProxy) then
  2180. FreeProxy;
  2181. FConnectorType:=AValue;
  2182. end;
  2183. end;
  2184. procedure TSQLConnector.SetTransaction(Value: TSQLTransaction);
  2185. begin
  2186. inherited SetTransaction(Value);
  2187. If Assigned(FProxy) and (FProxy.Transaction<>Value) then
  2188. FProxy.FTransaction:=Value;
  2189. end;
  2190. procedure TSQLConnector.DoInternalConnect;
  2191. Var
  2192. D : TConnectionDef;
  2193. begin
  2194. inherited DoInternalConnect;
  2195. CreateProxy;
  2196. FProxy.CharSet:=Self.CharSet;
  2197. FProxy.Role:=Self.Role;
  2198. FProxy.DatabaseName:=Self.DatabaseName;
  2199. FProxy.HostName:=Self.HostName;
  2200. FProxy.UserName:=Self.UserName;
  2201. FProxy.Password:=Self.Password;
  2202. FProxy.FTransaction:=Self.Transaction;
  2203. D:=GetConnectionDef(ConnectorType);
  2204. D.ApplyParams(Params,FProxy);
  2205. FProxy.Connected:=True;
  2206. end;
  2207. procedure TSQLConnector.DoInternalDisconnect;
  2208. begin
  2209. FProxy.Connected:=False;
  2210. inherited DoInternalDisconnect;
  2211. end;
  2212. procedure TSQLConnector.CheckProxy;
  2213. begin
  2214. If (FProxy=Nil) then
  2215. CreateProxy;
  2216. end;
  2217. procedure TSQLConnector.CreateProxy;
  2218. Var
  2219. D : TConnectionDef;
  2220. begin
  2221. D:=GetConnectionDef(ConnectorType);
  2222. If (D=Nil) then
  2223. DatabaseErrorFmt(SErrUnknownConnectorType,[ConnectorType],Self);
  2224. FProxy:=D.ConnectionClass.Create(Self);
  2225. FFieldNameQuoteChars := FProxy.FieldNameQuoteChars;
  2226. end;
  2227. procedure TSQLConnector.FreeProxy;
  2228. begin
  2229. FProxy.Connected:=False;
  2230. FreeAndNil(FProxy);
  2231. end;
  2232. function TSQLConnector.StrToStatementType(s: string): TStatementType;
  2233. begin
  2234. CheckProxy;
  2235. Result:=FProxy.StrToStatementType(s);
  2236. end;
  2237. function TSQLConnector.GetAsSQLText(Field: TField): string;
  2238. begin
  2239. CheckProxy;
  2240. Result:=FProxy.GetAsSQLText(Field);
  2241. end;
  2242. function TSQLConnector.GetAsSQLText(Param: TParam): string;
  2243. begin
  2244. CheckProxy;
  2245. Result:=FProxy.GetAsSQLText(Param);
  2246. end;
  2247. function TSQLConnector.GetHandle: pointer;
  2248. begin
  2249. CheckProxy;
  2250. Result:=FProxy.GetHandle;
  2251. end;
  2252. function TSQLConnector.AllocateCursorHandle: TSQLCursor;
  2253. begin
  2254. CheckProxy;
  2255. Result:=FProxy.AllocateCursorHandle;
  2256. end;
  2257. procedure TSQLConnector.DeAllocateCursorHandle(var cursor: TSQLCursor);
  2258. begin
  2259. CheckProxy;
  2260. FProxy.DeAllocateCursorHandle(cursor);
  2261. end;
  2262. function TSQLConnector.AllocateTransactionHandle: TSQLHandle;
  2263. begin
  2264. CheckProxy;
  2265. Result:=FProxy.AllocateTransactionHandle;
  2266. end;
  2267. procedure TSQLConnector.PrepareStatement(cursor: TSQLCursor;
  2268. ATransaction: TSQLTransaction; buf: string; AParams: TParams);
  2269. begin
  2270. CheckProxy;
  2271. FProxy.PrepareStatement(cursor, ATransaction, buf, AParams);
  2272. end;
  2273. procedure TSQLConnector.Execute(cursor: TSQLCursor;
  2274. atransaction: tSQLtransaction; AParams: TParams);
  2275. begin
  2276. CheckProxy;
  2277. FProxy.Execute(cursor, atransaction, AParams);
  2278. end;
  2279. function TSQLConnector.Fetch(cursor: TSQLCursor): boolean;
  2280. begin
  2281. CheckProxy;
  2282. Result:=FProxy.Fetch(cursor);
  2283. end;
  2284. procedure TSQLConnector.AddFieldDefs(cursor: TSQLCursor; FieldDefs: TfieldDefs
  2285. );
  2286. begin
  2287. CheckProxy;
  2288. FProxy.AddFieldDefs(cursor, FieldDefs);
  2289. end;
  2290. procedure TSQLConnector.UnPrepareStatement(cursor: TSQLCursor);
  2291. begin
  2292. CheckProxy;
  2293. FProxy.UnPrepareStatement(cursor);
  2294. end;
  2295. procedure TSQLConnector.FreeFldBuffers(cursor: TSQLCursor);
  2296. begin
  2297. CheckProxy;
  2298. FProxy.FreeFldBuffers(cursor);
  2299. end;
  2300. function TSQLConnector.LoadField(cursor: TSQLCursor; FieldDef: TfieldDef;
  2301. buffer: pointer; out CreateBlob: boolean): boolean;
  2302. begin
  2303. CheckProxy;
  2304. Result:=FProxy.LoadField(cursor, FieldDef, buffer, CreateBlob);
  2305. end;
  2306. procedure TSQLConnector.LoadBlobIntoBuffer(FieldDef: TFieldDef;
  2307. ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction);
  2308. begin
  2309. CheckProxy;
  2310. FProxy.LoadBlobIntoBuffer(FieldDef, ABlobBuf, cursor, ATransaction);
  2311. end;
  2312. function TSQLConnector.RowsAffected(cursor: TSQLCursor): TRowsCount;
  2313. begin
  2314. CheckProxy;
  2315. Result := FProxy.RowsAffected(cursor);
  2316. end;
  2317. function TSQLConnector.GetTransactionHandle(trans: TSQLHandle): pointer;
  2318. begin
  2319. CheckProxy;
  2320. Result:=FProxy.GetTransactionHandle(trans);
  2321. end;
  2322. function TSQLConnector.Commit(trans: TSQLHandle): boolean;
  2323. begin
  2324. CheckProxy;
  2325. Result:=FProxy.Commit(trans);
  2326. end;
  2327. function TSQLConnector.RollBack(trans: TSQLHandle): boolean;
  2328. begin
  2329. CheckProxy;
  2330. Result:=FProxy.RollBack(trans);
  2331. end;
  2332. function TSQLConnector.StartdbTransaction(trans: TSQLHandle; aParams: string
  2333. ): boolean;
  2334. begin
  2335. CheckProxy;
  2336. Result:=FProxy.StartdbTransaction(trans, aParams);
  2337. end;
  2338. procedure TSQLConnector.CommitRetaining(trans: TSQLHandle);
  2339. begin
  2340. CheckProxy;
  2341. FProxy.CommitRetaining(trans);
  2342. end;
  2343. procedure TSQLConnector.RollBackRetaining(trans: TSQLHandle);
  2344. begin
  2345. CheckProxy;
  2346. FProxy.RollBackRetaining(trans);
  2347. end;
  2348. procedure TSQLConnector.UpdateIndexDefs(IndexDefs: TIndexDefs;
  2349. TableName: string);
  2350. begin
  2351. CheckProxy;
  2352. FProxy.UpdateIndexDefs(IndexDefs, TableName);
  2353. end;
  2354. function TSQLConnector.GetSchemaInfoSQL(SchemaType: TSchemaType;
  2355. SchemaObjectName, SchemaPattern: string): string;
  2356. begin
  2357. CheckProxy;
  2358. Result:=FProxy.GetSchemaInfoSQL(SchemaType, SchemaObjectName, SchemaPattern
  2359. );
  2360. end;
  2361. { TConnectionDef }
  2362. class function TConnectionDef.TypeName: String;
  2363. begin
  2364. Result:='';
  2365. end;
  2366. class function TConnectionDef.ConnectionClass: TSQLConnectionClass;
  2367. begin
  2368. Result:=Nil;
  2369. end;
  2370. class function TConnectionDef.Description: String;
  2371. begin
  2372. Result:='';
  2373. end;
  2374. class function TConnectionDef.DefaultLibraryName: String;
  2375. begin
  2376. Result:='';
  2377. end;
  2378. class function TConnectionDef.LoadFunction: TLibraryLoadFunction;
  2379. begin
  2380. Result:=Nil;
  2381. end;
  2382. class function TConnectionDef.UnLoadFunction: TLibraryUnLoadFunction;
  2383. begin
  2384. Result:=Nil;
  2385. end;
  2386. class function TConnectionDef.LoadedLibraryName: string;
  2387. begin
  2388. Result:='';
  2389. end;
  2390. procedure TConnectionDef.ApplyParams(Params: TStrings;
  2391. AConnection: TSQLConnection);
  2392. begin
  2393. AConnection.Params.Assign(Params);
  2394. end;
  2395. { TServerIndexDefs }
  2396. constructor TServerIndexDefs.create(ADataset: TDataset);
  2397. begin
  2398. if not (ADataset is TCustomSQLQuery) then
  2399. DatabaseErrorFmt(SErrNotASQLQuery,[ADataset.Name]);
  2400. inherited create(ADataset);
  2401. end;
  2402. procedure TServerIndexDefs.Update;
  2403. begin
  2404. if (not updated) and assigned(Dataset) then
  2405. begin
  2406. TCustomSQLQuery(Dataset).UpdateServerIndexDefs;
  2407. updated := True;
  2408. end;
  2409. end;
  2410. Initialization
  2411. Finalization
  2412. DoneDefs;
  2413. end.