sqldb.pp 82 KB

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