sqldb.pp 112 KB

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