sqldb.pp 102 KB

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