sqldb.pp 95 KB

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