sqldb.pp 99 KB

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