sqldb.pp 99 KB

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