sqldb.pp 112 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029
  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. try
  1222. Connected:=False; // needed because we want to de-allocate statements
  1223. Finally
  1224. FreeAndNil(FStatements);
  1225. inherited Destroy;
  1226. end;
  1227. end;
  1228. function TSQLConnection.StrToStatementType(s : string) : TStatementType;
  1229. var T : TStatementType;
  1230. begin
  1231. S:=Lowercase(s);
  1232. for T:=stSelect to stRollback do
  1233. if (S=StatementTokens[T]) then
  1234. Exit(T);
  1235. Result:=stUnknown;
  1236. end;
  1237. procedure TSQLConnection.SetTransaction(Value : TSQLTransaction);
  1238. begin
  1239. if FTransaction<>value then
  1240. begin
  1241. if Assigned(FTransaction) and FTransaction.Active then
  1242. DatabaseError(SErrAssTransaction);
  1243. if Assigned(Value) then
  1244. Value.Database := Self;
  1245. FTransaction := Value;
  1246. If Assigned(FTransaction) and (FTransaction.Database=Nil) then
  1247. FTransaction.Database:=Self;
  1248. end;
  1249. end;
  1250. procedure TSQLConnection.UpdateIndexDefs(IndexDefs : TIndexDefs; TableName : string);
  1251. begin
  1252. // Empty abstract
  1253. end;
  1254. procedure TSQLConnection.DoConnect;
  1255. var ConnectionCharSet: string;
  1256. begin
  1257. inherited;
  1258. // map connection CharSet to corresponding local CodePage
  1259. // do not set FCodePage to CP_ACP if FCodePage = DefaultSystemCodePage
  1260. // aliases listed here are commonly used, but not recognized by CodePageNameToCodePage()
  1261. ConnectionCharSet := LowerCase(GetConnectionCharSet);
  1262. case ConnectionCharSet of
  1263. 'utf8','utf-8','utf8mb4':
  1264. FCodePage := CP_UTF8;
  1265. 'win1250','cp1250':
  1266. FCodePage := 1250;
  1267. 'win1251','cp1251':
  1268. FCodePage := 1251;
  1269. 'win1252','cp1252','latin1','iso8859_1':
  1270. FCodePage := 1252;
  1271. else
  1272. begin
  1273. FCodePage := CodePageNameToCodePage(ConnectionCharSet);
  1274. if FCodePage = CP_NONE then
  1275. FCodePage := CP_ACP;
  1276. end;
  1277. end;
  1278. end;
  1279. procedure TSQLConnection.DoInternalConnect;
  1280. begin
  1281. if (DatabaseName = '') and not(sqSupportEmptyDatabaseName in FConnOptions) then
  1282. DatabaseError(SErrNoDatabaseName,Self);
  1283. end;
  1284. procedure TSQLConnection.DoInternalDisconnect;
  1285. Var
  1286. I : integer;
  1287. L : TList;
  1288. begin
  1289. L:=FStatements.LockList;
  1290. try
  1291. For I:=0 to L.Count-1 do
  1292. TCustomSQLStatement(L[i]).Unprepare;
  1293. L.Clear;
  1294. finally
  1295. FStatements.UnlockList;
  1296. end;
  1297. end;
  1298. procedure TSQLConnection.StartTransaction;
  1299. begin
  1300. if not assigned(Transaction) then
  1301. DatabaseError(SErrConnTransactionnSet)
  1302. else
  1303. Transaction.StartTransaction;
  1304. end;
  1305. procedure TSQLConnection.EndTransaction;
  1306. begin
  1307. if not assigned(Transaction) then
  1308. DatabaseError(SErrConnTransactionnSet)
  1309. else
  1310. Transaction.EndTransaction;
  1311. end;
  1312. procedure TSQLConnection.ExecuteDirect(SQL: String);
  1313. begin
  1314. ExecuteDirect(SQL,FTransaction);
  1315. end;
  1316. procedure TSQLConnection.ExecuteDirect(SQL: String;
  1317. ATransaction: TSQLTransaction);
  1318. var Cursor : TSQLCursor;
  1319. begin
  1320. if not assigned(ATransaction) then
  1321. DatabaseError(SErrTransactionnSet);
  1322. if not Connected then Open;
  1323. if not ATransaction.Active then
  1324. ATransaction.MaybeStartTransaction;
  1325. SQL := TrimRight(SQL);
  1326. if SQL = '' then
  1327. DatabaseError(SErrNoStatement);
  1328. try
  1329. Cursor := AllocateCursorHandle;
  1330. Cursor.FStatementType := stUnknown;
  1331. If LogEvent(detPrepare) then
  1332. Log(detPrepare,SQL);
  1333. PrepareStatement(Cursor,ATransaction,SQL,Nil);
  1334. try
  1335. If LogEvent(detExecute) then
  1336. Log(detExecute,SQL);
  1337. Execute(Cursor,ATransaction, Nil);
  1338. finally
  1339. UnPrepareStatement(Cursor);
  1340. end;
  1341. finally;
  1342. DeAllocateCursorHandle(Cursor);
  1343. end;
  1344. end;
  1345. function TSQLConnection.GetPort: cardinal;
  1346. begin
  1347. result := StrToIntDef(Params.Values['Port'],0);
  1348. end;
  1349. procedure TSQLConnection.SetOptions(AValue: TSQLConnectionOptions);
  1350. begin
  1351. if FOptions=AValue then Exit;
  1352. FOptions:=AValue;
  1353. end;
  1354. procedure TSQLConnection.SetPort(const AValue: cardinal);
  1355. begin
  1356. if AValue<>0 then
  1357. Params.Values['Port']:=IntToStr(AValue)
  1358. else with params do if IndexOfName('Port') > -1 then
  1359. Delete(IndexOfName('Port'));
  1360. end;
  1361. function TSQLConnection.AttemptCommit(trans: TSQLHandle): boolean;
  1362. begin
  1363. try
  1364. Result:=Commit(trans);
  1365. except
  1366. if ForcedClose then
  1367. Result:=True
  1368. else
  1369. Raise;
  1370. end;
  1371. end;
  1372. function TSQLConnection.AttemptRollBack(trans: TSQLHandle): boolean;
  1373. begin
  1374. try
  1375. Result:=Rollback(trans);
  1376. except
  1377. if ForcedClose then
  1378. Result:=True
  1379. else
  1380. Raise;
  1381. end;
  1382. end;
  1383. procedure TSQLConnection.GetDBInfo(const ASchemaType : TSchemaType; const ASchemaObjectName, AReturnField : string; AList: TStrings);
  1384. var qry : TCustomSQLQuery;
  1385. begin
  1386. if not assigned(Transaction) then
  1387. DatabaseError(SErrConnTransactionnSet);
  1388. qry := TCustomSQLQuery.Create(nil);
  1389. try
  1390. qry.transaction := Transaction;
  1391. qry.database := Self;
  1392. with qry do
  1393. begin
  1394. ParseSQL := False;
  1395. SetSchemaInfo(ASchemaType,ASchemaObjectName,'');
  1396. open;
  1397. AList.Clear;
  1398. while not eof do
  1399. begin
  1400. AList.Append(trim(fieldbyname(AReturnField).asstring));
  1401. Next;
  1402. end;
  1403. end;
  1404. finally
  1405. qry.free;
  1406. end;
  1407. end;
  1408. function TSQLConnection.GetConnectionCharSet: string;
  1409. begin
  1410. // default implementation returns user supplied FCharSet
  1411. // (can be overriden by descendants, which are able retrieve current connection charset using client API)
  1412. Result := LowerCase(FCharSet);
  1413. end;
  1414. function TSQLConnection.RowsAffected(cursor: TSQLCursor): TRowsCount;
  1415. begin
  1416. Result := -1;
  1417. end;
  1418. function TSQLConnection.AddFieldDef(AFieldDefs: TFieldDefs; AFieldNo: Longint;
  1419. const AName: string; ADataType: TFieldType; ASize, APrecision: Integer;
  1420. AByteSize, ARequired, AReadOnly: Boolean): TFieldDef;
  1421. var
  1422. ACodePage: TSystemCodePage;
  1423. begin
  1424. // helper function used by descendants
  1425. if ADataType in [ftString, ftFixedChar, ftMemo] then
  1426. begin
  1427. ACodePage := FCodePage;
  1428. // if ASize of character data is passed as "byte length",
  1429. // translate it to "character length" as expected by TFieldDef
  1430. if AByteSize and (ACodePage = CP_UTF8) then
  1431. ASize := ASize div 4;
  1432. end
  1433. else
  1434. ACodePage := 0;
  1435. Result := AFieldDefs.Add(AName, ADataType, ASize, APrecision, ARequired, AReadOnly, AFieldNo, ACodePage);
  1436. end;
  1437. procedure TSQLConnection.GetTableNames(List: TStrings; SystemTables: Boolean);
  1438. begin
  1439. if not SystemTables then
  1440. GetDBInfo(stTables,'','table_name',List)
  1441. else
  1442. GetDBInfo(stSysTables,'','table_name',List);
  1443. end;
  1444. procedure TSQLConnection.GetProcedureNames(List: TStrings);
  1445. begin
  1446. GetDBInfo(stProcedures,'','procedure_name',List);
  1447. end;
  1448. procedure TSQLConnection.GetFieldNames(const TableName: string; List: TStrings);
  1449. begin
  1450. GetDBInfo(stColumns,TableName,'column_name',List);
  1451. end;
  1452. procedure TSQLConnection.GetSchemaNames(List: TStrings);
  1453. begin
  1454. GetDBInfo(stSchemata,'','SCHEMA_NAME',List);
  1455. end;
  1456. procedure TSQLConnection.GetSequenceNames(List: TStrings);
  1457. begin
  1458. GetDBInfo(stSequences,'','SEQUENCE_NAME',List);
  1459. end;
  1460. {
  1461. See if we can integrate/merge this with GetDBInfo. They are virtually identical
  1462. }
  1463. Function TSQLConnection.GetObjectNames(ASchemaType: TSchemaType; AList : TSqlObjectIdentifierList) : Integer;
  1464. var
  1465. qry : TCustomSQLQuery;
  1466. vSchemaName, vObjectName: String;
  1467. f: TField;
  1468. begin
  1469. Result:=0;
  1470. if not assigned(Transaction) then
  1471. DatabaseError(SErrConnTransactionnSet);
  1472. qry := TCustomSQLQuery.Create(nil);
  1473. try
  1474. qry.transaction := Transaction;
  1475. qry.database := Self;
  1476. with qry do
  1477. begin
  1478. ParseSQL := False;
  1479. SetSchemaInfo(ASchemaType,TSchemaObjectNames[ASchemaType],'');
  1480. open;
  1481. f:=FindField(TSchemaObjectNames[stSchemata]);
  1482. while not eof do
  1483. begin
  1484. vSchemaName:='';
  1485. if Assigned(f) then
  1486. vSchemaName:=f.AsString;
  1487. vObjectName:=FieldByName(FSchemaObjectName).AsString;
  1488. AList.AddIdentifier(vObjectName, vSchemaName);
  1489. Next;
  1490. Inc(Result);
  1491. end;
  1492. end;
  1493. finally
  1494. qry.free;
  1495. end;
  1496. end;
  1497. function TSQLConnection.GetConnectionInfo(InfoType: TConnInfoType): string;
  1498. var i: TConnInfoType;
  1499. begin
  1500. Result:='';
  1501. if InfoType = citAll then
  1502. for i:=citServerType to citClientVersion do
  1503. begin
  1504. if Result<>'' then Result:=Result+',';
  1505. Result:=Result+'"'+GetConnectionInfo(i)+'"';
  1506. end;
  1507. end;
  1508. function TSQLConnection.GetStatementInfo(const ASQL: string): TSQLStatementInfo;
  1509. type
  1510. TParsePart = (ppStart,ppWith,ppSelect,ppTableName,ppFrom,ppWhere,ppGroup,ppOrder,ppBogus);
  1511. TPhraseSeparator = (sepNone, sepWhiteSpace, sepComma, sepComment, sepParentheses, sepDoubleQuote, sepEnd);
  1512. TKeyword = (kwWITH, kwSELECT, kwINSERT, kwUPDATE, kwDELETE, kwFROM, kwJOIN, kwWHERE, kwGROUP, kwORDER, kwUNION, kwROWS, kwLIMIT, kwUnknown);
  1513. const
  1514. KeywordNames: array[TKeyword] of string =
  1515. ('WITH', 'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'FROM', 'JOIN', 'WHERE', 'GROUP', 'ORDER', 'UNION', 'ROWS', 'LIMIT', '');
  1516. var
  1517. PSQL, CurrentP, SavedP,
  1518. PhraseP, PStatementPart : pchar;
  1519. S : string;
  1520. ParsePart : TParsePart;
  1521. BracketCount : Integer;
  1522. Separator : TPhraseSeparator;
  1523. Keyword, K : TKeyword;
  1524. begin
  1525. PSQL:=PChar(ASQL);
  1526. ParsePart := ppStart;
  1527. CurrentP := PSQL-1;
  1528. PhraseP := PSQL;
  1529. Result.TableName := '';
  1530. Result.Updateable := False;
  1531. Result.WhereStartPos := 0;
  1532. Result.WhereStopPos := 0;
  1533. repeat
  1534. inc(CurrentP);
  1535. SavedP := CurrentP;
  1536. case CurrentP^ of
  1537. ' ', #9..#13:
  1538. Separator := sepWhiteSpace;
  1539. ',':
  1540. Separator := sepComma;
  1541. #0, ';':
  1542. Separator := sepEnd;
  1543. '(':
  1544. begin
  1545. Separator := sepParentheses;
  1546. // skip everything between brackets, since it could be a sub-select, and
  1547. // further nothing between brackets could be interesting for the parser.
  1548. BracketCount := 1;
  1549. repeat
  1550. inc(CurrentP);
  1551. if CurrentP^ = '(' then inc(BracketCount)
  1552. else if CurrentP^ = ')' then dec(BracketCount);
  1553. until (CurrentP^ = #0) or (BracketCount = 0);
  1554. if CurrentP^ <> #0 then inc(CurrentP);
  1555. end;
  1556. '"','`':
  1557. if SkipComments(CurrentP, sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions) then
  1558. Separator := sepDoubleQuote;
  1559. else
  1560. if SkipComments(CurrentP, sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions) then
  1561. Separator := sepComment
  1562. else
  1563. Separator := sepNone;
  1564. end;
  1565. if Separator <> sepNone then
  1566. begin
  1567. if (CurrentP > SavedP) and (SavedP > PhraseP) then
  1568. CurrentP := SavedP; // there is something before comment or left parenthesis or double quote
  1569. if (Separator in [sepWhitespace,sepComment]) and (SavedP = PhraseP) then
  1570. PhraseP := CurrentP; // skip comments (but not parentheses) and white spaces
  1571. if (CurrentP-PhraseP > 0) or (Separator = sepEnd) then
  1572. begin
  1573. SetString(s, PhraseP, CurrentP-PhraseP);
  1574. Keyword := kwUnknown;
  1575. for K in TKeyword do
  1576. if SameText(s, KeywordNames[K]) then
  1577. begin
  1578. Keyword := K;
  1579. break;
  1580. end;
  1581. case ParsePart of
  1582. ppStart : begin
  1583. Result.StatementType := StrToStatementType(s);
  1584. case Keyword of
  1585. kwWITH : ParsePart := ppWith;
  1586. kwSELECT: ParsePart := ppSelect;
  1587. else break;
  1588. end;
  1589. end;
  1590. ppWith : begin
  1591. // WITH [RECURSIVE] CTE_name [ ( column_names ) ] AS ( CTE_query_definition ) [, ...]
  1592. // { SELECT | INSERT | UPDATE | DELETE } ...
  1593. case Keyword of
  1594. kwSELECT: Result.StatementType := stSelect;
  1595. kwINSERT: Result.StatementType := stInsert;
  1596. kwUPDATE: Result.StatementType := stUpdate;
  1597. kwDELETE: Result.StatementType := stDelete;
  1598. end;
  1599. if Result.StatementType <> stUnknown then break;
  1600. end;
  1601. ppSelect : begin
  1602. if Keyword = kwFROM then
  1603. ParsePart := ppTableName;
  1604. end;
  1605. ppTableName:
  1606. begin
  1607. // Meta-data requests are never updateable
  1608. // and select statements from more than one table
  1609. // and/or derived tables are also not updateable
  1610. if Separator in [sepWhitespace, sepComment, sepDoubleQuote, sepEnd] then
  1611. begin
  1612. Result.TableName := Result.TableName + s;
  1613. Result.Updateable := True;
  1614. end;
  1615. // compound delimited classifier like: "schema name"."table name"
  1616. if not (CurrentP^ in ['.','"']) then
  1617. ParsePart := ppFrom;
  1618. end;
  1619. ppFrom : begin
  1620. if (Keyword in [kwWHERE, kwGROUP, kwORDER, kwLIMIT, kwROWS]) or
  1621. (Separator = sepEnd) then
  1622. begin
  1623. case Keyword of
  1624. kwWHERE: ParsePart := ppWhere;
  1625. kwGROUP: ParsePart := ppGroup;
  1626. kwORDER: ParsePart := ppOrder;
  1627. else ParsePart := ppBogus;
  1628. end;
  1629. Result.WhereStartPos := PhraseP-PSQL+1;
  1630. PStatementPart := CurrentP;
  1631. end
  1632. else
  1633. // joined table or user_defined_function (...)
  1634. if (Keyword = kwJOIN) or (Separator in [sepComma, sepParentheses]) then
  1635. begin
  1636. Result.TableName := '';
  1637. Result.Updateable := False;
  1638. end;
  1639. end;
  1640. ppWhere : begin
  1641. if (Keyword in [kwGROUP, kwORDER, kwLIMIT, kwROWS]) or
  1642. (Separator = sepEnd) then
  1643. begin
  1644. ParsePart := ppBogus;
  1645. Result.WhereStartPos := PStatementPart-PSQL;
  1646. if (Separator = sepEnd) then
  1647. Result.WhereStopPos := CurrentP-PSQL+1
  1648. else
  1649. Result.WhereStopPos := PhraseP-PSQL+1;
  1650. end
  1651. else if (Keyword = kwUNION) then
  1652. begin
  1653. ParsePart := ppBogus;
  1654. Result.Updateable := False;
  1655. end;
  1656. end;
  1657. end; {case}
  1658. end;
  1659. if Separator in [sepComment, sepParentheses, sepDoubleQuote] then
  1660. dec(CurrentP);
  1661. PhraseP := CurrentP+1;
  1662. end
  1663. until CurrentP^=#0;
  1664. end;
  1665. function TSQLConnection.GetAsString(Param: TParam): RawByteString;
  1666. begin
  1667. // converts parameter value to connection charset
  1668. if FCodePage = CP_UTF8 then
  1669. Result := Param.AsUTF8String
  1670. else if (FCodePage = DefaultSystemCodePage) or
  1671. (FCodePage = CP_ACP) or (FCodePage = CP_NONE) then
  1672. Result := Param.AsAnsiString
  1673. else
  1674. begin
  1675. Result := Param.AsAnsiString;
  1676. SetCodePage(Result, FCodePage, True);
  1677. end;
  1678. end;
  1679. function TSQLConnection.GetAsSQLText(Field : TField) : string;
  1680. begin
  1681. if (not assigned(Field)) or Field.IsNull then Result := 'Null'
  1682. else case Field.DataType of
  1683. ftString : Result := QuotedStr(Field.AsString);
  1684. ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Field.AsDateTime,FSQLFormatSettings) + '''';
  1685. ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz',Field.AsDateTime,FSQLFormatSettings) + '''';
  1686. ftTime : Result := '''' + TimeIntervalToString(Field.AsDateTime) + '''';
  1687. else
  1688. Result := Field.AsString;
  1689. end; {case}
  1690. end;
  1691. function TSQLConnection.GetAsSQLText(Param: TParam) : string;
  1692. begin
  1693. if (not assigned(Param)) or Param.IsNull then Result := 'Null'
  1694. else case Param.DataType of
  1695. ftGuid,
  1696. ftMemo,
  1697. ftFixedChar,
  1698. ftString : Result := QuotedStr(GetAsString(Param));
  1699. ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd', Param.AsDateTime, FSQLFormatSettings) + '''';
  1700. ftTime : Result := '''' + TimeIntervalToString(Param.AsDateTime) + '''';
  1701. ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', Param.AsDateTime, FSQLFormatSettings) + '''';
  1702. ftCurrency,
  1703. ftBcd : Result := CurrToStr(Param.AsCurrency, FSQLFormatSettings);
  1704. ftFloat : Result := FloatToStr(Param.AsFloat, FSQLFormatSettings);
  1705. ftFMTBcd : Result := StringReplace(Param.AsString, DefaultFormatSettings.DecimalSeparator, FSQLFormatSettings.DecimalSeparator, []);
  1706. else
  1707. Result := Param.AsString;
  1708. end; {case}
  1709. end;
  1710. function TSQLConnection.GetHandle: pointer;
  1711. begin
  1712. Result := nil;
  1713. end;
  1714. function TSQLConnection.LogEvent(EventType: TDBEventType): Boolean;
  1715. begin
  1716. Result:=(Assigned(FOnLog) or Assigned(GlobalDBLogHook)) and (EventType in LogEvents);
  1717. end;
  1718. procedure TSQLConnection.LogParams(const AParams: TParams);
  1719. Var
  1720. S : String;
  1721. P : TParam;
  1722. begin
  1723. if not LogEvent(detParamValue) or not Assigned(AParams) then
  1724. Exit;
  1725. For P in AParams do
  1726. begin
  1727. if P.IsNull then
  1728. S:='<NULL>'
  1729. else if (P.DataType in ftBlobTypes) and not (P.DataType in [ftMemo, ftFmtMemo,ftWideMemo]) then
  1730. S:='<BLOB>'
  1731. else
  1732. S:=P.AsString;
  1733. Log(detParamValue,Format(SLogParamValue,[P.Name,S]));
  1734. end;
  1735. end;
  1736. procedure TSQLConnection.Log(EventType: TDBEventType; const Msg: String);
  1737. Var
  1738. M : String;
  1739. begin
  1740. If LogEvent(EventType) then
  1741. begin
  1742. If Assigned(FonLog) then
  1743. FOnLog(Self,EventType,Msg);
  1744. If Assigned(GlobalDBLogHook) then
  1745. begin
  1746. If (Name<>'') then
  1747. M:=Name+' : '+Msg
  1748. else
  1749. M:=ClassName+' : '+Msg;
  1750. GlobalDBLogHook(Self,EventType,M);
  1751. end;
  1752. end;
  1753. end;
  1754. procedure TSQLConnection.RegisterStatement(S: TCustomSQLStatement);
  1755. begin
  1756. FStatements.Add(S);
  1757. end;
  1758. procedure TSQLConnection.UnRegisterStatement(S: TCustomSQLStatement);
  1759. begin
  1760. if Assigned(FStatements) then // Can be nil, when we are destroying and datasets are uncoupled.
  1761. FStatements.Remove(S);
  1762. end;
  1763. function TSQLConnection.CreateCustomQuery(aOwner : TComponent) : TCustomSQLQuery;
  1764. begin
  1765. Result:=TCustomSQLQuery.Create(AOwner);
  1766. end;
  1767. function TSQLConnection.InitialiseUpdateStatement(Query : TCustomSQLQuery; var qry : TCustomSQLQuery): TCustomSQLQuery;
  1768. begin
  1769. if not assigned(qry) then
  1770. begin
  1771. qry := TCustomSQLQuery(TComponentClass(Query.ClassType).Create(Nil));
  1772. qry.ParseSQL := False;
  1773. qry.DataBase := Self;
  1774. qry.Transaction := Query.SQLTransaction;
  1775. qry.Unidirectional:=True;
  1776. qry.UsePrimaryKeyAsKey:=False;
  1777. qry.PacketRecords:=1;
  1778. end;
  1779. Result:=qry;
  1780. end;
  1781. procedure TSQLConnection.AddFieldToUpdateWherePart(var sql_where : string;UpdateMode : TUpdateMode; F : TField);
  1782. begin
  1783. if (pfInKey in F.ProviderFlags)
  1784. or ((UpdateMode = upWhereAll) and (pfInWhere in F.ProviderFlags))
  1785. or ((UpdateMode = UpWhereChanged) and (pfInWhere in F.ProviderFlags) and (F.Value <> F.OldValue)) then
  1786. begin
  1787. if (sql_where<>'') then
  1788. sql_where:=sql_where + ' and ';
  1789. sql_where:= sql_where + '(' + FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1];
  1790. // primary key normally cannot be null
  1791. if Assigned(F.Dataset) and F.Dataset.Active and (F.OldValue = NULL) then
  1792. sql_where := sql_where + ' is null '
  1793. else
  1794. sql_where := sql_where +'= :"' + 'OLD_' + F.FieldName + '"';
  1795. sql_where:=sql_where+') ';
  1796. end;
  1797. end;
  1798. function TSQLConnection.ConstructInsertSQL(Query: TCustomSQLQuery;
  1799. var ReturningClause: Boolean): string;
  1800. var x : integer;
  1801. sql_fields : string;
  1802. sql_values : string;
  1803. returning_fields : String;
  1804. F : TField;
  1805. begin
  1806. sql_fields := '';
  1807. sql_values := '';
  1808. returning_fields := '';
  1809. for x := 0 to Query.Fields.Count -1 do
  1810. begin
  1811. F:=Query.Fields[x];
  1812. if (not F.IsNull) and (pfInUpdate in F.ProviderFlags) and (not F.ReadOnly) then
  1813. begin
  1814. sql_fields := sql_fields + FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1] + ',';
  1815. sql_values := sql_values + ':"' + F.FieldName + '",';
  1816. end;
  1817. if ReturningClause and (pfRefreshOnInsert in F.ProviderFlags) then
  1818. returning_fields := returning_fields + FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1] + ',';
  1819. end;
  1820. if length(sql_fields) = 0 then
  1821. DatabaseErrorFmt(sNoUpdateFields,['insert'],self);
  1822. setlength(sql_fields,length(sql_fields)-1);
  1823. setlength(sql_values,length(sql_values)-1);
  1824. result := 'insert into ' + Query.FTableName + ' (' + sql_fields + ') values (' + sql_values + ')';
  1825. if ReturningClause then
  1826. begin
  1827. ReturningClause:=length(returning_fields) <> 0 ;
  1828. if ReturningClause then
  1829. begin
  1830. setlength(returning_fields,length(returning_fields)-1);
  1831. Result := Result + ' returning ' + returning_fields;
  1832. end;
  1833. end;
  1834. end;
  1835. function TSQLConnection.ConstructUpdateSQL(Query: TCustomSQLQuery;
  1836. var ReturningClause: Boolean): string;
  1837. var x : integer;
  1838. F : TField;
  1839. sql_set : string;
  1840. sql_where : string;
  1841. returning_fields : String;
  1842. begin
  1843. sql_set := '';
  1844. sql_where := '';
  1845. returning_fields := '';
  1846. for x := 0 to Query.Fields.Count -1 do
  1847. begin
  1848. F:=Query.Fields[x];
  1849. AddFieldToUpdateWherePart(sql_where,Query.UpdateMode,F);
  1850. if (pfInUpdate in F.ProviderFlags) and (not F.ReadOnly) then
  1851. sql_set := sql_set +FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1] +'=:"' + F.FieldName + '",';
  1852. if ReturningClause and (pfRefreshOnUpdate in F.ProviderFlags) then
  1853. returning_fields := returning_fields + FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1] + ',';
  1854. end;
  1855. if length(sql_set) = 0 then DatabaseErrorFmt(sNoUpdateFields,['update'],self);
  1856. setlength(sql_set,length(sql_set)-1);
  1857. if length(sql_where) = 0 then DatabaseErrorFmt(sNoWhereFields,['update'],self);
  1858. result := 'update ' + Query.FTableName + ' set ' + sql_set + ' where ' + sql_where;
  1859. if ReturningClause then
  1860. begin
  1861. ReturningClause:=length(returning_fields) <> 0 ;
  1862. if ReturningClause then
  1863. begin
  1864. setlength(returning_fields,length(returning_fields)-1);
  1865. Result := Result + ' returning ' + returning_fields;
  1866. end;
  1867. end;
  1868. end;
  1869. function TSQLConnection.ConstructDeleteSQL(Query : TCustomSQLQuery) : string;
  1870. var
  1871. x : integer;
  1872. sql_where : string;
  1873. begin
  1874. sql_where := '';
  1875. for x := 0 to Query.Fields.Count -1 do
  1876. AddFieldToUpdateWherePart(sql_where,Query.UpdateMode, Query.Fields[x]);
  1877. if length(sql_where) = 0 then
  1878. DatabaseErrorFmt(sNoWhereFields,['delete'],self);
  1879. result := 'delete from ' + Query.FTableName + ' where ' + sql_where;
  1880. end;
  1881. function TSQLConnection.ConstructRefreshSQL(Query: TCustomSQLQuery; UpdateKind: TUpdateKind): string;
  1882. Var
  1883. F : TField;
  1884. PF : TProviderFlag;
  1885. Where : String;
  1886. begin
  1887. Result:=Trim(Query.RefreshSQL.Text);
  1888. if (Result='') then
  1889. begin
  1890. Where:='';
  1891. PF:=RefreshFlags[UpdateKind];
  1892. For F in Query.Fields do
  1893. begin
  1894. if PF in F.ProviderFlags then
  1895. begin
  1896. if (Result<>'') then
  1897. Result:=Result+', ';
  1898. if (F.Origin<>'') and (F.Origin<>F.FieldName) then
  1899. Result:=Result+F.Origin+' AS '+F.FieldName
  1900. else
  1901. Result:=Result+FieldNameQuoteChars[0]+F.FieldName+FieldNameQuoteChars[1]
  1902. end;
  1903. if pfInkey in F.ProviderFlags then
  1904. begin
  1905. if (Where<>'') then
  1906. Where:=Where+' AND ';
  1907. Where:=Where+'('+FieldNameQuoteChars[0]+F.FieldName+FieldNameQuoteChars[1]+' = :'+F.FieldName+')';
  1908. end;
  1909. end;
  1910. if (Where='') then
  1911. DatabaseError(SErrNoKeyFieldForRefreshClause,Query);
  1912. Result:='SELECT '+Result+' FROM '+Query.FTableName+' WHERE '+Where;
  1913. end;
  1914. end;
  1915. procedure TSQLConnection.ApplyFieldUpdate(C : TSQLCursor; P : TSQLDBParam; F : TField; UseOldValue : Boolean);
  1916. begin
  1917. if UseOldValue then
  1918. P.AssignFieldValue(F,F.OldValue)
  1919. else
  1920. P.AssignFieldValue(F,F.Value);
  1921. P.FFieldDef:=F.FieldDef;
  1922. end;
  1923. procedure TSQLConnection.ApplyRecUpdate(Query: TCustomSQLQuery; UpdateKind: TUpdateKind);
  1924. var
  1925. qry : TCustomSQLQuery;
  1926. s : string;
  1927. x : integer;
  1928. Fld : TField;
  1929. Par, P : TParam;
  1930. UseOldValue, HasReturningClause : Boolean;
  1931. begin
  1932. qry:=Nil;
  1933. HasReturningClause:=(sqSupportReturning in ConnOptions) and not (sqoRefreshUsingSelect in Query.Options) and (Trim(Query.RefreshSQL.Text)='');
  1934. case UpdateKind of
  1935. ukInsert : begin
  1936. s := Trim(Query.FInsertSQL.Text);
  1937. if s = '' then
  1938. s := ConstructInsertSQL(Query, HasReturningClause)
  1939. else
  1940. HasReturningClause := False;
  1941. qry := InitialiseUpdateStatement(Query, Query.FInsertQry);
  1942. end;
  1943. ukModify : begin
  1944. s := Trim(Query.FUpdateSQL.Text);
  1945. if s = '' then begin
  1946. //if not assigned(Query.FUpdateQry) or (Query.UpdateMode<>upWhereKeyOnly) then // first time or dynamic where part
  1947. s := ConstructUpdateSQL(Query, HasReturningClause);
  1948. end
  1949. else
  1950. HasReturningClause := False;
  1951. qry := InitialiseUpdateStatement(Query, Query.FUpdateQry);
  1952. end;
  1953. ukDelete : begin
  1954. s := Trim(Query.FDeleteSQL.Text);
  1955. if (s='') and (not assigned(Query.FDeleteQry) or (Query.UpdateMode<>upWhereKeyOnly)) then
  1956. s := ConstructDeleteSQL(Query);
  1957. HasReturningClause := False;
  1958. qry := InitialiseUpdateStatement(Query, Query.FDeleteQry);
  1959. end;
  1960. end;
  1961. if (s<>'') and (qry.SQL.Text<>s) then
  1962. qry.SQL.Text:=s; //assign only when changed, to avoid UnPrepare/Prepare
  1963. Assert(qry.SQL.Text<>'');
  1964. for x:=0 to Qry.Params.Count-1 do
  1965. begin
  1966. P:=Qry.Params[x];
  1967. S:=P.Name;
  1968. UseOldValue:=SameText(Copy(S,1,4),'OLD_');
  1969. if UseOldValue then
  1970. begin
  1971. Delete(S,1,4);
  1972. Fld:=Query.FieldByName(S);
  1973. end
  1974. else
  1975. Fld:=Query.FindField(S);
  1976. if Assigned(Fld) then
  1977. ApplyFieldUpdate(Query.Cursor, P as TSQLDBParam, Fld, UseOldValue)
  1978. else
  1979. begin
  1980. // if does not exists field with given name, try look for param
  1981. Par:=Query.Params.FindParam(S);
  1982. if Assigned(Par) then
  1983. P.Assign(Par)
  1984. else
  1985. DatabaseErrorFmt(SFieldNotFound,[S],Query); // same error as raised by FieldByName()
  1986. end;
  1987. end;
  1988. if HasReturningClause then
  1989. begin
  1990. Qry.Close;
  1991. Qry.Open
  1992. end
  1993. else
  1994. Qry.ExecSQL;
  1995. if (scoApplyUpdatesChecksRowsAffected in Options) and (Qry.RowsAffected<>1) then
  1996. begin
  1997. Qry.Close;
  1998. DatabaseErrorFmt(SErrFailedToUpdateRecord, [Qry.RowsAffected], Query);
  1999. end;
  2000. if HasReturningClause then
  2001. Query.ApplyReturningResult(Qry,UpdateKind);
  2002. end;
  2003. function TSQLConnection.RefreshLastInsertID(Query: TCustomSQLQuery; Field: TField): Boolean;
  2004. begin
  2005. Result:=False;
  2006. end;
  2007. procedure TSQLConnection.FreeFldBuffers(cursor: TSQLCursor);
  2008. begin
  2009. // empty
  2010. end;
  2011. function TSQLConnection.StartImplicitTransaction(trans: TSQLHandle; aParams: string): boolean;
  2012. begin
  2013. Result:=False;
  2014. end;
  2015. function TSQLConnection.GetSchemaInfoSQL( SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string;
  2016. begin
  2017. case SchemaType of
  2018. stTables : Result := 'SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE=''BASE TABLE''';
  2019. stColumns : Result := 'SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='+QuotedStr(SchemaObjectName);
  2020. stProcedures: Result := 'SELECT *, ROUTINE_NAME AS PROCEDURE_NAME FROM INFORMATION_SCHEMA.ROUTINES';
  2021. stSchemata : Result := 'SELECT * FROM INFORMATION_SCHEMA.SCHEMATA';
  2022. stSequences : Result := 'SELECT * FROM INFORMATION_SCHEMA.SEQUENCES';
  2023. else DatabaseError(SMetadataUnavailable);
  2024. end;
  2025. end;
  2026. function TSQLConnection.GetNextValueSQL(const SequenceName: string; IncrementBy: Integer): string;
  2027. begin
  2028. Result := 'SELECT NEXT VALUE FOR ' + SequenceName;
  2029. end;
  2030. function TSQLConnection.GetNextValue(const SequenceName: string; IncrementBy: integer): Int64;
  2031. var
  2032. Q: TCustomSQLQuery;
  2033. begin
  2034. Result := 0;
  2035. Q := TCustomSQLQuery.Create(nil);
  2036. try
  2037. Q.DataBase := Self;
  2038. Q.Transaction := Transaction;
  2039. Q.SQL.Text := GetNextValueSQL(SequenceName, IncrementBy);
  2040. Q.Open;
  2041. if not Q.Eof then
  2042. Result := Q.Fields[0].AsLargeInt;
  2043. Q.Close;
  2044. finally
  2045. FreeAndNil(Q);
  2046. end;
  2047. end;
  2048. procedure TSQLConnection.MaybeConnect;
  2049. begin
  2050. If Not Connected then
  2051. begin
  2052. If (scoExplicitConnect in Options) then
  2053. DatabaseErrorFmt(SErrImplicitConnect,[Name]);
  2054. Connected:=True;
  2055. end;
  2056. end;
  2057. procedure TSQLConnection.CreateDB;
  2058. begin
  2059. DatabaseError(SNotSupported);
  2060. end;
  2061. procedure TSQLConnection.DropDB;
  2062. begin
  2063. DatabaseError(SNotSupported);
  2064. end;
  2065. { TSQLTransaction }
  2066. constructor TSQLTransaction.Create(AOwner : TComponent);
  2067. begin
  2068. inherited Create(AOwner);
  2069. FParams := TStringList.Create;
  2070. Action := caRollBack;
  2071. end;
  2072. destructor TSQLTransaction.Destroy;
  2073. begin
  2074. EndTransaction;
  2075. FreeAndNil(FTrans);
  2076. FreeAndNil(FParams);
  2077. inherited Destroy;
  2078. end;
  2079. procedure TSQLTransaction.EndTransaction;
  2080. begin
  2081. Case Action of
  2082. caCommit, caCommitRetaining :
  2083. Commit;
  2084. caNone,
  2085. caRollback, caRollbackRetaining :
  2086. if not (stoUseImplicit in Options) then
  2087. RollBack
  2088. else
  2089. CloseTrans;
  2090. end;
  2091. end;
  2092. procedure TSQLTransaction.SetParams(const AValue: TStringList);
  2093. begin
  2094. FParams.Assign(AValue);
  2095. end;
  2096. function TSQLTransaction.GetSQLConnection: TSQLConnection;
  2097. begin
  2098. Result:=Database as TSQLConnection;
  2099. end;
  2100. procedure TSQLTransaction.SetOptions(AValue: TSQLTransactionOptions);
  2101. begin
  2102. if FOptions=AValue then Exit;
  2103. if (stoUseImplicit in Avalue) and Assigned(SQLConnection) And Not (sqImplicitTransaction in SQLConnection.ConnOptions) then
  2104. DatabaseErrorFmt(SErrNoImplicitTransaction, [SQLConnection.ClassName]);
  2105. FOptions:=AValue;
  2106. end;
  2107. procedure TSQLTransaction.SetSQLConnection(AValue: TSQLConnection);
  2108. begin
  2109. Database:=AValue;
  2110. end;
  2111. Procedure TSQLTransaction.MaybeStartTransaction;
  2112. begin
  2113. if not Active then
  2114. begin
  2115. if (stoExplicitStart in Options) then
  2116. DatabaseErrorFmt(SErrImplictTransactionStart, [Database.Name,Name]);
  2117. StartTransaction;
  2118. end;
  2119. end;
  2120. function TSQLTransaction.GetHandle: Pointer;
  2121. begin
  2122. Result := SQLConnection.GetTransactionHandle(FTrans);
  2123. end;
  2124. Function TSQLTransaction.AllowClose(DS: TDBDataset): Boolean;
  2125. begin
  2126. if (DS is TSQLQuery) then
  2127. Result:=not (sqoKeepOpenOnCommit in TSQLQuery(DS).Options)
  2128. else
  2129. Result:=Inherited AllowClose(DS);
  2130. end;
  2131. procedure TSQLTransaction.Commit;
  2132. begin
  2133. if Active then
  2134. begin
  2135. CloseDataSets;
  2136. If LogEvent(detCommit) then
  2137. Log(detCommit,SCommitting);
  2138. // The inherited closetrans must always be called.
  2139. // So the last (FTrans=Nil) is for the case of forced close. (Bug IDs 35246 and 33737)
  2140. // Order is important:
  2141. // some connections do not have FTrans, but they must still go through AttemptCommit.
  2142. if (stoUseImplicit in Options) or SQLConnection.AttemptCommit(FTrans) or (FTrans=Nil) then
  2143. begin
  2144. CloseTrans;
  2145. FreeAndNil(FTrans);
  2146. end;
  2147. end;
  2148. end;
  2149. procedure TSQLTransaction.CommitRetaining;
  2150. begin
  2151. if Active then
  2152. begin
  2153. If LogEvent(detCommit) then
  2154. Log(detCommit,SCommitRetaining);
  2155. SQLConnection.CommitRetaining(FTrans);
  2156. end;
  2157. end;
  2158. procedure TSQLTransaction.Rollback;
  2159. begin
  2160. if Active then
  2161. begin
  2162. if (stoUseImplicit in Options) then
  2163. DatabaseError(SErrImplicitNoRollBack);
  2164. CloseDataSets;
  2165. If LogEvent(detRollback) then
  2166. Log(detRollback,SRollingBack);
  2167. // The inherited closetrans must always be called.
  2168. // So the last (FTrans=Nil) is for the case of forced close. (Bug IDs 35246 and 33737)
  2169. // Order is important:
  2170. // some connections do not have FTrans, but they must still go through AttemptCommit.
  2171. // FTrans=Nil for the case of forced close.
  2172. if SQLConnection.AttemptRollBack(FTrans) or (FTrans=Nil) then
  2173. begin
  2174. CloseTrans;
  2175. FreeAndNil(FTrans);
  2176. end;
  2177. end;
  2178. end;
  2179. procedure TSQLTransaction.RollbackRetaining;
  2180. begin
  2181. if Active then
  2182. begin
  2183. if (stoUseImplicit in Options) then
  2184. DatabaseError(SErrImplicitNoRollBack);
  2185. If LogEvent(detRollback) then
  2186. Log(detRollback,SRollBackRetaining);
  2187. SQLConnection.RollBackRetaining(FTrans);
  2188. end;
  2189. end;
  2190. procedure TSQLTransaction.StartTransaction;
  2191. var db : TSQLConnection;
  2192. begin
  2193. if Active then
  2194. DatabaseError(SErrTransAlreadyActive);
  2195. db := SQLConnection;
  2196. if Db = nil then
  2197. DatabaseError(SErrDatabasenAssigned);
  2198. Db.MaybeConnect;
  2199. if not assigned(FTrans) then FTrans := Db.AllocateTransactionHandle;
  2200. if (stoUseImplicit in Options) then
  2201. begin
  2202. if Db.StartImplicitTransaction(FTrans,FParams.CommaText) then
  2203. OpenTrans
  2204. end
  2205. else
  2206. begin
  2207. if Db.StartDBTransaction(FTrans,FParams.CommaText) then
  2208. OpenTrans
  2209. end;
  2210. end;
  2211. Procedure TSQLTransaction.SetDatabase(Value: TDatabase);
  2212. begin
  2213. If Value<>Database then
  2214. begin
  2215. if Assigned(Value) and not (Value is TSQLConnection) then
  2216. DatabaseErrorFmt(SErrNotASQLConnection, [Value.Name], Self);
  2217. CheckInactive;
  2218. if (stoUseImplicit in Options) and Assigned(Value) and Not (sqImplicitTransaction in TSQLConnection(Value).ConnOptions) then
  2219. DatabaseErrorFmt(SErrNoImplicitTransaction, [Value.ClassName]);
  2220. If Assigned(Database) then
  2221. if SQLConnection.Transaction = Self then SQLConnection.Transaction := nil;
  2222. inherited;
  2223. If Assigned(Database) and not (csLoading in ComponentState) then
  2224. If SQLConnection.Transaction = Nil then SQLConnection.Transaction := Self;
  2225. end;
  2226. end;
  2227. Function TSQLTransaction.LogEvent(EventType: TDBEventType): Boolean;
  2228. begin
  2229. Result:=Assigned(Database) and SQLConnection.LogEvent(EventType);
  2230. end;
  2231. Procedure TSQLTransaction.Log(EventType: TDBEventType; Const Msg: String);
  2232. Var
  2233. M : String;
  2234. begin
  2235. If LogEvent(EventType) then
  2236. begin
  2237. If (Name<>'') then
  2238. M:=Name+' : '+Msg
  2239. else
  2240. M:=Msg;
  2241. SQLConnection.Log(EventType,M);
  2242. end;
  2243. end;
  2244. { TSQLSequence }
  2245. constructor TSQLSequence.Create(AQuery: TCustomSQLQuery);
  2246. begin
  2247. inherited Create;
  2248. FQuery := AQuery;
  2249. FApplyEvent := saeOnNewRecord;
  2250. FIncrementBy := 1;
  2251. end;
  2252. procedure TSQLSequence.Assign(Source: TPersistent);
  2253. var SourceSequence: TSQLSequence;
  2254. begin
  2255. if Source is TSQLSequence then
  2256. begin
  2257. SourceSequence := TSQLSequence(Source);
  2258. FFieldName := SourceSequence.FieldName;
  2259. FSequenceName := SourceSequence.SequenceName;
  2260. FIncrementBy := SourceSequence.IncrementBy;
  2261. FApplyEvent := SourceSequence.ApplyEvent;
  2262. end
  2263. else
  2264. inherited;
  2265. end;
  2266. procedure TSQLSequence.Apply;
  2267. var Field: TField;
  2268. begin
  2269. if Assigned(FQuery) and (FSequenceName<>'') and (FFieldName<>'') then
  2270. begin
  2271. Field := FQuery.FindField(FFieldName);
  2272. if Assigned(Field) and Field.IsNull then
  2273. Field.AsLargeInt := GetNextValue;
  2274. end;
  2275. end;
  2276. function TSQLSequence.GetNextValue: Int64;
  2277. begin
  2278. if (FQuery=Nil) or (FQuery.SQLConnection=Nil) then
  2279. DatabaseError(SErrDatabasenAssigned);
  2280. Result := FQuery.SQLConnection.GetNextValue(FSequenceName, FIncrementBy);
  2281. end;
  2282. Type
  2283. { TQuerySQLStatement }
  2284. TQuerySQLStatement = Class(TCustomSQLStatement)
  2285. protected
  2286. FQuery : TCustomSQLQuery;
  2287. function CreateParams: TSQLDBParams; override;
  2288. Function CreateDataLink : TDataLink; override;
  2289. Function GetSchemaType : TSchemaType; override;
  2290. Function GetSchemaObjectName : String; override;
  2291. Function GetSchemaPattern: String; override;
  2292. procedure GetStatementInfo(var ASQL: String; out Info: TSQLStatementInfo); override;
  2293. procedure OnChangeSQL(Sender : TObject); override;
  2294. public
  2295. constructor Create(AOwner: TComponent); override;
  2296. end;
  2297. { TQuerySQLStatement }
  2298. constructor TQuerySQLStatement.Create(AOwner: TComponent);
  2299. begin
  2300. FQuery:=TCustomSQLQuery(AOwner);
  2301. inherited Create(AOwner);
  2302. end;
  2303. function TQuerySQLStatement.CreateDataLink: TDataLink;
  2304. begin
  2305. Result:=TMasterParamsDataLink.Create(FQuery);
  2306. end;
  2307. function TQuerySQLStatement.CreateParams: TSQLDBParams;
  2308. begin
  2309. Result:=FQuery.CreateParams;
  2310. end;
  2311. function TQuerySQLStatement.GetSchemaType: TSchemaType;
  2312. begin
  2313. if Assigned(FQuery) then
  2314. Result:=FQuery.FSchemaType
  2315. else
  2316. Result:=stNoSchema;
  2317. end;
  2318. function TQuerySQLStatement.GetSchemaObjectName: String;
  2319. begin
  2320. if Assigned(FQuery) then
  2321. Result:=FQuery.FSchemaObjectname
  2322. else
  2323. Result:=inherited GetSchemaObjectName;
  2324. end;
  2325. function TQuerySQLStatement.GetSchemaPattern: String;
  2326. begin
  2327. if Assigned(FQuery) then
  2328. Result:=FQuery.FSchemaPattern
  2329. else
  2330. Result:=inherited GetSchemaPattern;
  2331. end;
  2332. procedure TQuerySQLStatement.GetStatementInfo(var ASQL: String; out Info: TSQLStatementInfo);
  2333. begin
  2334. inherited GetStatementInfo(ASQL, Info);
  2335. If Assigned(FQuery) then
  2336. // Note: practical side effect of switch off ParseSQL is that UpdateServerIndexDefs is bypassed
  2337. // which is used as performance tuning option
  2338. if (FQuery.FSchemaType = stNoSchema) and FParseSQL then
  2339. begin
  2340. FQuery.FUpdateable:=Info.Updateable;
  2341. FQuery.FTableName:=Info.TableName;
  2342. FQuery.FWhereStartPos:=Info.WhereStartPos;
  2343. FQuery.FWhereStopPos:=Info.WhereStopPos;
  2344. if FQuery.ServerFiltered then
  2345. ASQL:=FQuery.AddFilter(ASQL);
  2346. end
  2347. else
  2348. begin
  2349. FQuery.FUpdateable:=false;
  2350. FQuery.FTableName:='';
  2351. FQuery.FWhereStartPos:=0;
  2352. FQuery.FWhereStopPos:=0;
  2353. end;
  2354. end;
  2355. procedure TQuerySQLStatement.OnChangeSQL(Sender: TObject);
  2356. begin
  2357. UnPrepare;
  2358. inherited OnChangeSQL(Sender);
  2359. If ParamCheck and Assigned(FDataLink) then
  2360. (FDataLink as TMasterParamsDataLink).RefreshParamNames;
  2361. FQuery.ServerIndexDefs.Updated:=false;
  2362. end;
  2363. { TCustomSQLQuery }
  2364. function TCustomSQLQuery.CreateSQLStatement(aOwner: TComponent
  2365. ): TCustomSQLStatement;
  2366. begin
  2367. Result:=TQuerySQLStatement.Create(Self);
  2368. end;
  2369. constructor TCustomSQLQuery.Create(AOwner : TComponent);
  2370. begin
  2371. inherited Create(AOwner);
  2372. FStatement:=CreateSQLStatement(Self);
  2373. FInsertSQL := TStringList.Create;
  2374. FInsertSQL.OnChange := @OnChangeModifySQL;
  2375. FUpdateSQL := TStringList.Create;
  2376. FUpdateSQL.OnChange := @OnChangeModifySQL;
  2377. FDeleteSQL := TStringList.Create;
  2378. FDeleteSQL.OnChange := @OnChangeModifySQL;
  2379. FRefreshSQL := TStringList.Create;
  2380. FRefreshSQL.OnChange := @OnChangeModifySQL;
  2381. FSequence := TSQLSequence.Create(Self);
  2382. FServerIndexDefs := TServerIndexDefs.Create(Self);
  2383. FServerFiltered := False;
  2384. FServerFilterText := '';
  2385. FSchemaType:=stNoSchema;
  2386. FSchemaObjectName:='';
  2387. FSchemaPattern:='';
  2388. // Delphi has upWhereAll as default, but since strings and oldvalue's don't work yet
  2389. // (variants) set it to upWhereKeyOnly
  2390. FUpdateMode := upWhereKeyOnly;
  2391. FUsePrimaryKeyAsKey := True;
  2392. end;
  2393. destructor TCustomSQLQuery.Destroy;
  2394. begin
  2395. if Active then Close;
  2396. UnPrepare;
  2397. FreeAndNil(FStatement);
  2398. FreeAndNil(FInsertSQL);
  2399. FreeAndNil(FUpdateSQL);
  2400. FreeAndNil(FDeleteSQL);
  2401. FreeAndNil(FRefreshSQL);
  2402. FreeAndNil(FSequence);
  2403. FreeAndNil(FServerIndexDefs);
  2404. inherited Destroy;
  2405. end;
  2406. function TCustomSQLQuery.ParamByName(const AParamName: String): TParam;
  2407. begin
  2408. Result:=Params.ParamByName(AParamName);
  2409. end;
  2410. function TCustomSQLQuery.MacroByName(const AParamName: String): TParam;
  2411. begin
  2412. Result:=Macros.ParamByName(AParamName);
  2413. end;
  2414. procedure TCustomSQLQuery.OnChangeModifySQL(Sender : TObject);
  2415. begin
  2416. CheckInactive;
  2417. end;
  2418. procedure TCustomSQLQuery.SetDatabase(Value : TDatabase);
  2419. var DB : TSQLConnection;
  2420. begin
  2421. if Database = Value then Exit;
  2422. if Assigned(Value) and not (Value is TSQLConnection) then
  2423. DatabaseErrorFmt(SErrNotASQLConnection, [Value.Name], Self);
  2424. UnPrepare;
  2425. DB := TSQLConnection(Value);
  2426. If Assigned(FStatement) then
  2427. FStatement.Database := DB;
  2428. inherited;
  2429. if Assigned(DB) and Assigned(DB.Transaction) and (not Assigned(Transaction) or (Transaction.DataBase<>Database)) then
  2430. Transaction := DB.Transaction;
  2431. end;
  2432. procedure TCustomSQLQuery.SetTransaction(Value: TDBTransaction);
  2433. begin
  2434. if Transaction = Value then Exit;
  2435. UnPrepare;
  2436. inherited;
  2437. If Assigned(FStatement) then
  2438. FStatement.Transaction := TSQLTransaction(Value);
  2439. If Assigned(Transaction) and Assigned(Transaction.DataBase) and (Database<>Transaction.DataBase) then
  2440. Database := Transaction.Database;
  2441. end;
  2442. function TCustomSQLQuery.IsPrepared: Boolean;
  2443. begin
  2444. if Assigned(Fstatement) then
  2445. Result := FStatement.Prepared
  2446. else
  2447. Result := False;
  2448. end;
  2449. function TCustomSQLQuery.AddFilter(SQLstr: string): string;
  2450. begin
  2451. if (FWhereStartPos > 0) and (FWhereStopPos > 0) then
  2452. begin
  2453. system.insert('(',SQLstr,FWhereStartPos+1);
  2454. system.insert(')',SQLstr,FWhereStopPos+1);
  2455. end;
  2456. if FWhereStartPos = 0 then
  2457. SQLstr := SQLstr + ' where (' + ServerFilter + ')'
  2458. else if FWhereStopPos > 0 then
  2459. system.insert(' and ('+ServerFilter+') ',SQLstr,FWhereStopPos+2)
  2460. else
  2461. system.insert(' where ('+ServerFilter+') ',SQLstr,FWhereStartPos);
  2462. Result := SQLstr;
  2463. end;
  2464. procedure TCustomSQLQuery.OpenCursor(InfoQuery: Boolean);
  2465. begin
  2466. if InfoQuery then
  2467. CheckPrepare;
  2468. try
  2469. inherited OpenCursor(InfoQuery);
  2470. finally
  2471. if InfoQuery then
  2472. CheckUnPrepare;
  2473. end;
  2474. end;
  2475. function TCustomSQLQuery.NeedRefreshRecord(UpdateKind: TUpdateKind): Boolean;
  2476. Var
  2477. PF : TProviderFlag;
  2478. I : Integer;
  2479. DoReturning : Boolean;
  2480. begin
  2481. Result:=(Trim(FRefreshSQL.Text)<>'');
  2482. DoReturning:=(sqSupportReturning in SQLConnection.ConnOptions) and not (sqoRefreshUsingSelect in Options);
  2483. if Not (Result or DoReturning) then
  2484. begin
  2485. PF:=RefreshFlags[UpdateKind];
  2486. I:=0;
  2487. While (Not Result) and (I<Fields.Count) do
  2488. begin
  2489. Result:=PF in Fields[i].ProviderFlags;
  2490. Inc(I);
  2491. end;
  2492. end;
  2493. end;
  2494. function TCustomSQLQuery.RefreshRecord(UpdateKind: TUpdateKind): Boolean;
  2495. Var
  2496. Q : TCustomSQLQuery;
  2497. P : TParam;
  2498. F,FD : TField;
  2499. N : String;
  2500. begin
  2501. Result:=False;
  2502. Q:=TCustomSQLQuery.Create(Nil);
  2503. try
  2504. Q.Database:=Self.Database;
  2505. Q.Transaction:=Self.Transaction;
  2506. Q.SQL.Text:=SQLConnection.ConstructRefreshSQL(Self,UpdateKind);
  2507. For P in Q.Params do
  2508. begin
  2509. N:=P.Name;
  2510. If CompareText(Copy(N,1,4),'OLD_')=0 then
  2511. system.Delete(N,1,4);
  2512. F:=Fields.FindField(N);
  2513. if Assigned(F) then
  2514. P.AssignField(F);
  2515. end;
  2516. Q.Open;
  2517. try
  2518. if (Q.EOF and Q.BOF) then
  2519. DatabaseError(SErrRefreshEmptyResult,Self)
  2520. else
  2521. begin
  2522. if Q.RecordCount<>1 then
  2523. DatabaseErrorFmt(SErrRefreshNotSingleton,[Q.RecordCount],Self);
  2524. For F in Q.Fields do
  2525. begin
  2526. FD:=Fields.FindField(F.FieldName);
  2527. if Assigned(FD) then
  2528. begin
  2529. FD.Assign(F);
  2530. Result:=True; // We could check if the new value differs from the old, but we won't.
  2531. end;
  2532. end;
  2533. end
  2534. finally
  2535. Q.Close;
  2536. end;
  2537. finally
  2538. Q.Free;
  2539. end;
  2540. end;
  2541. procedure TCustomSQLQuery.ApplyReturningResult(Q: TCustomSQLQuery; UpdateKind : TUpdateKind);
  2542. Var
  2543. S : TDataSetState;
  2544. refreshFlag : TProviderFlag;
  2545. F : TField;
  2546. begin
  2547. RefreshFlag:=RefreshFlags[UpdateKind];
  2548. S:=SetTempState(dsRefreshFields);
  2549. try
  2550. For F in Fields do
  2551. if RefreshFlag in F.ProviderFlags then
  2552. F.Assign(Q.FieldByName(F.FieldName));
  2553. finally
  2554. RestoreState(S);
  2555. end;
  2556. end;
  2557. procedure TCustomSQLQuery.ApplyFilter;
  2558. begin
  2559. if Prepared then
  2560. FStatement.Unprepare;
  2561. InternalRefresh;
  2562. First;
  2563. end;
  2564. procedure TCustomSQLQuery.SetServerFiltered(Value: Boolean);
  2565. begin
  2566. if Value and not ParseSQL then
  2567. DatabaseErrorFmt(SNoParseSQL,['Filtering ']);
  2568. if (ServerFiltered <> Value) then
  2569. begin
  2570. FServerFiltered := Value;
  2571. if Active then ApplyFilter;
  2572. end;
  2573. end;
  2574. procedure TCustomSQLQuery.SetServerFilterText(const Value: string);
  2575. begin
  2576. if Value <> ServerFilter then
  2577. begin
  2578. FServerFilterText := Value;
  2579. if Active then ApplyFilter;
  2580. end;
  2581. end;
  2582. procedure TCustomSQLQuery.Prepare;
  2583. begin
  2584. FStatement.Prepare;
  2585. end;
  2586. procedure TCustomSQLQuery.UnPrepare;
  2587. begin
  2588. if Not Refreshing then
  2589. CheckInactive;
  2590. If Assigned(FStatement) then
  2591. FStatement.Unprepare;
  2592. end;
  2593. procedure TCustomSQLQuery.FreeFldBuffers;
  2594. begin
  2595. if assigned(Cursor) then
  2596. SQLConnection.FreeFldBuffers(Cursor);
  2597. end;
  2598. function TCustomSQLQuery.GetMacroChar: Char;
  2599. begin
  2600. Result := FStatement.MacroChar;
  2601. end;
  2602. function TCustomSQLQuery.GetParamCheck: Boolean;
  2603. begin
  2604. Result:=FStatement.ParamCheck;
  2605. end;
  2606. function TCustomSQLQuery.GetParams: TParams;
  2607. begin
  2608. Result:=FStatement.Params;
  2609. end;
  2610. function TCustomSQLQuery.GetMacroCheck: Boolean;
  2611. begin
  2612. Result:=FStatement.MacroCheck;
  2613. end;
  2614. function TCustomSQLQuery.GetMacros: TParams;
  2615. begin
  2616. Result:=FStatement.Macros;
  2617. end;
  2618. function TCustomSQLQuery.GetParseSQL: Boolean;
  2619. begin
  2620. Result:=FStatement.ParseSQL;
  2621. end;
  2622. function TCustomSQLQuery.GetServerIndexDefs: TServerIndexDefs;
  2623. begin
  2624. Result := FServerIndexDefs;
  2625. end;
  2626. function TCustomSQLQuery.GetSQL: TStringList;
  2627. begin
  2628. Result:=TStringList(Fstatement.SQL);
  2629. end;
  2630. function TCustomSQLQuery.GetSQLConnection: TSQLConnection;
  2631. begin
  2632. Result:=Database as TSQLConnection;
  2633. end;
  2634. function TCustomSQLQuery.GetSQLTransaction: TSQLTransaction;
  2635. begin
  2636. Result:=Transaction as TSQLTransaction;
  2637. end;
  2638. function TCustomSQLQuery.Cursor: TSQLCursor;
  2639. begin
  2640. Result:=FStatement.Cursor;
  2641. end;
  2642. function TCustomSQLQuery.Fetch : boolean;
  2643. begin
  2644. if Not Assigned(Cursor) then
  2645. Exit;
  2646. if not Cursor.FSelectable then
  2647. Exit;
  2648. If LogEvent(detFetch) then
  2649. Log(detFetch,FStatement.FServerSQL);
  2650. if not FIsEof then FIsEOF := not SQLConnection.Fetch(Cursor);
  2651. Result := not FIsEOF;
  2652. end;
  2653. procedure TCustomSQLQuery.Execute;
  2654. begin
  2655. FStatement.DoExecute;
  2656. end;
  2657. function TCustomSQLQuery.RowsAffected: TRowsCount;
  2658. begin
  2659. Result:=FStatement.RowsAffected;
  2660. end;
  2661. function TCustomSQLQuery.LoadField(FieldDef : TFieldDef; buffer : pointer; out CreateBlob : boolean) : boolean;
  2662. begin
  2663. Result := SQLConnection.LoadField(Cursor, FieldDef, buffer, CreateBlob);
  2664. // disable deferred blob loading for "disconnected" datasets
  2665. if Result and (FieldDef.DataType in ftBlobTypes) and (sqoKeepOpenOnCommit in Options) then
  2666. CreateBlob:=True
  2667. end;
  2668. procedure TCustomSQLQuery.LoadBlobIntoBuffer(FieldDef: TFieldDef;
  2669. ABlobBuf: PBufBlobField);
  2670. begin
  2671. SQLConnection.LoadBlobIntoBuffer(FieldDef, ABlobBuf, Cursor,SQLTransaction);
  2672. end;
  2673. procedure TCustomSQLQuery.InternalAddRecord(Buffer: Pointer; AAppend: Boolean);
  2674. begin
  2675. // not implemented - sql dataset
  2676. end;
  2677. procedure TCustomSQLQuery.InternalClose;
  2678. begin
  2679. if assigned(Cursor) then
  2680. begin
  2681. if Cursor.FSelectable then
  2682. FreeFldBuffers;
  2683. CheckUnPrepare;
  2684. // Some SQLConnections does not support statement [un]preparation,
  2685. // so let them do cleanup f.e. cancel pending queries and/or free resultset
  2686. // if not Prepared then
  2687. // FStatement.DoUnprepare;
  2688. end;
  2689. if DefaultFields then
  2690. DestroyFields;
  2691. FIsEOF := False;
  2692. if assigned(FUpdateQry) then FreeAndNil(FUpdateQry);
  2693. if assigned(FInsertQry) then FreeAndNil(FInsertQry);
  2694. if assigned(FDeleteQry) then FreeAndNil(FDeleteQry);
  2695. // FRecordSize := 0;
  2696. inherited InternalClose;
  2697. end;
  2698. procedure TCustomSQLQuery.InternalInitFieldDefs;
  2699. begin
  2700. if FLoadingFieldDefs then
  2701. Exit;
  2702. FLoadingFieldDefs := True;
  2703. try
  2704. FieldDefs.Clear;
  2705. SQLConnection.AddFieldDefs(Cursor,FieldDefs);
  2706. finally
  2707. FLoadingFieldDefs := False;
  2708. if assigned(Cursor) then Cursor.FInitFieldDef := False;
  2709. end;
  2710. end;
  2711. procedure TCustomSQLQuery.InternalOpen;
  2712. var counter, fieldc : integer;
  2713. F : TField;
  2714. IndexFields : TStrings;
  2715. begin
  2716. if IsReadFromPacket then
  2717. begin
  2718. // When we read from file there is no need for Cursor, also note that Database may not be assigned
  2719. //FStatement.AllocateCursor;
  2720. //Cursor.FSelectable:=True;
  2721. //Cursor.FStatementType:=stSelect;
  2722. FUpdateable:=True;
  2723. end
  2724. else
  2725. begin
  2726. CheckPrepare;
  2727. if not Cursor.FSelectable then
  2728. DatabaseError(SErrNoSelectStatement,Self);
  2729. // Call UpdateServerIndexDefs before Execute, to avoid problems with connections
  2730. // which do not allow processing multiple recordsets at a time. (Microsoft
  2731. // calls this MARS, see bug 13241)
  2732. if DefaultFields and FUpdateable and FusePrimaryKeyAsKey and (not IsUniDirectional) then
  2733. UpdateServerIndexDefs;
  2734. FStatement.Execute;
  2735. if not Cursor.FSelectable then
  2736. DatabaseError(SErrNoSelectStatement,Self);
  2737. // InternalInitFieldDef is only called after a prepare. i.e. not twice if
  2738. // a dataset is opened - closed - opened.
  2739. if Cursor.FInitFieldDef then
  2740. InternalInitFieldDefs;
  2741. if DefaultFields then
  2742. begin
  2743. CreateFields;
  2744. if FUpdateable and FusePrimaryKeyAsKey and (not IsUniDirectional) then
  2745. for counter := 0 to ServerIndexDefs.Count-1 do
  2746. if ixPrimary in ServerIndexDefs[counter].Options then
  2747. begin
  2748. IndexFields := TStringList.Create;
  2749. ExtractStrings([';'],[' '],pchar(ServerIndexDefs[counter].Fields),IndexFields);
  2750. for fieldc := 0 to IndexFields.Count-1 do
  2751. begin
  2752. F := FindField(IndexFields[fieldc]);
  2753. if F <> nil then
  2754. F.ProviderFlags := F.ProviderFlags + [pfInKey];
  2755. end;
  2756. IndexFields.Free;
  2757. end;
  2758. end;
  2759. end;
  2760. BindFields(True);
  2761. if not ReadOnly and not FUpdateable and (FSchemaType=stNoSchema) then
  2762. begin
  2763. if (trim(FDeleteSQL.Text) <> '') or (trim(FUpdateSQL.Text) <> '') or
  2764. (trim(FInsertSQL.Text) <> '') then FUpdateable := True;
  2765. end;
  2766. inherited InternalOpen;
  2767. end;
  2768. procedure TCustomSQLQuery.InternalRefresh;
  2769. begin
  2770. if (ChangeCount>0) and (sqoCancelUpdatesOnRefresh in Options) then
  2771. CancelUpdates;
  2772. inherited InternalRefresh;
  2773. end;
  2774. // public part
  2775. procedure TCustomSQLQuery.CheckPrepare;
  2776. begin
  2777. if Not IsPrepared then
  2778. begin
  2779. Prepare;
  2780. FDoUnPrepare:=True;
  2781. end;
  2782. end;
  2783. procedure TCustomSQLQuery.CheckUnPrepare;
  2784. begin
  2785. if FDoUnPrepare then
  2786. begin
  2787. FDoUnPrepare:=False;
  2788. UnPrepare;
  2789. end;
  2790. end;
  2791. procedure TCustomSQLQuery.ExecSQL;
  2792. begin
  2793. CheckPrepare;
  2794. try
  2795. Execute;
  2796. // Always retrieve rows affected
  2797. FStatement.RowsAffected;
  2798. If sqoAutoCommit in Options then
  2799. SQLTransaction.Commit;
  2800. finally
  2801. CheckUnPrepare;
  2802. // if not Prepared and (assigned(Database)) and (assigned(Cursor)) then SQLConnection.UnPrepareStatement(Cursor);
  2803. end;
  2804. end;
  2805. procedure TCustomSQLQuery.ApplyUpdates(MaxErrors: Integer);
  2806. begin
  2807. inherited ApplyUpdates(MaxErrors);
  2808. If sqoAutoCommit in Options then
  2809. begin
  2810. // Retrieve rows affected for last update.
  2811. FStatement.RowsAffected;
  2812. SQLTransaction.Commit;
  2813. end;
  2814. end;
  2815. procedure TCustomSQLQuery.Post;
  2816. begin
  2817. inherited Post;
  2818. If (sqoAutoApplyUpdates in Options) then
  2819. ApplyUpdates;
  2820. end;
  2821. procedure TCustomSQLQuery.Delete;
  2822. begin
  2823. inherited Delete;
  2824. If (sqoAutoApplyUpdates in Options) then
  2825. ApplyUpdates;
  2826. end;
  2827. procedure TCustomSQLQuery.SetReadOnly(AValue : Boolean);
  2828. begin
  2829. CheckInactive;
  2830. inherited SetReadOnly(AValue);
  2831. end;
  2832. procedure TCustomSQLQuery.SetParseSQL(AValue : Boolean);
  2833. begin
  2834. CheckInactive;
  2835. FStatement.ParseSQL:=AValue;
  2836. if not AValue then
  2837. FServerFiltered := False;
  2838. end;
  2839. procedure TCustomSQLQuery.SetSQL(const AValue: TStringList);
  2840. begin
  2841. FStatement.SQL.Assign(AValue);
  2842. end;
  2843. procedure TCustomSQLQuery.SetUsePrimaryKeyAsKey(AValue : Boolean);
  2844. begin
  2845. if not Active then FusePrimaryKeyAsKey := AValue
  2846. else
  2847. begin
  2848. // Just temporary, this should be possible in the future
  2849. DatabaseError(SActiveDataset);
  2850. end;
  2851. end;
  2852. procedure TCustomSQLQuery.UpdateServerIndexDefs;
  2853. begin
  2854. FServerIndexDefs.Clear;
  2855. if assigned(DataBase) and (FTableName<>'') then
  2856. SQLConnection.UpdateIndexDefs(ServerIndexDefs,FTableName);
  2857. end;
  2858. function TCustomSQLQuery.NeedLastInsertID: TField;
  2859. Var
  2860. I : Integer;
  2861. begin
  2862. Result:=Nil;
  2863. if sqLastInsertID in SQLConnection.ConnOptions then
  2864. begin
  2865. I:=0;
  2866. While (Result=Nil) and (I<Fields.Count) do
  2867. begin
  2868. Result:=Fields[i];
  2869. if (Result.DataType<>ftAutoInc) or not Result.IsNull then
  2870. Result:=Nil;
  2871. Inc(I);
  2872. end;
  2873. end
  2874. end;
  2875. procedure TCustomSQLQuery.SetMacroChar(AValue: Char);
  2876. begin
  2877. FStatement.MacroChar:=AValue;
  2878. end;
  2879. function TCustomSQLQuery.RefreshLastInsertID(Field: TField): Boolean;
  2880. begin
  2881. Result:=SQLConnection.RefreshLastInsertID(Self, Field);
  2882. end;
  2883. procedure TCustomSQLQuery.ApplyRecUpdate(UpdateKind: TUpdateKind);
  2884. Var
  2885. DoRefresh : Boolean;
  2886. LastIDField : TField;
  2887. S : TDataSetState;
  2888. begin
  2889. // Moved to connection: the SQLConnection always has more information about types etc.
  2890. // than SQLQuery itself.
  2891. SQLConnection.ApplyRecUpdate(Self,UpdateKind);
  2892. if UpdateKind=ukInsert then
  2893. LastIDField:=NeedLastInsertID
  2894. else
  2895. LastIDField:=nil;
  2896. DoRefresh:=(UpdateKind in [ukModify,ukInsert]) and NeedRefreshRecord(UpdateKind);
  2897. if assigned(LastIDField) or DoRefresh then
  2898. begin
  2899. // updates fields directly in record buffer of TBufDataSet
  2900. // TDataSet buffers are resynchronized at end of ApplyUpdates process
  2901. S:=SetTempState(dsRefreshFields);
  2902. try
  2903. if assigned(LastIDField) then
  2904. RefreshLastInsertID(LastIDField);
  2905. if DoRefresh then
  2906. RefreshRecord(UpdateKind);
  2907. finally
  2908. RestoreState(S);
  2909. end;
  2910. end;
  2911. end;
  2912. procedure TCustomSQLQuery.SetPacketRecords(aValue: integer);
  2913. begin
  2914. if (AValue=PacketRecords) then exit;
  2915. if (AValue<>-1) and (sqoKeepOpenOnCommit in Options) then
  2916. DatabaseError(SErrDisconnectedPacketRecords);
  2917. Inherited SetPacketRecords(aValue);
  2918. end;
  2919. function TCustomSQLQuery.GetCanModify: Boolean;
  2920. begin
  2921. // the test for assigned(Cursor) is needed for the case that the dataset isn't opened
  2922. if assigned(Cursor) and (Cursor.FStatementType = stSelect) then
  2923. Result:= FUpdateable and (not ReadOnly) and (not IsUniDirectional)
  2924. else
  2925. Result := False;
  2926. end;
  2927. procedure TCustomSQLQuery.SetUpdateMode(AValue : TUpdateMode);
  2928. begin
  2929. FUpdateMode := AValue;
  2930. end;
  2931. procedure TCustomSQLQuery.SetSchemaInfo( ASchemaType : TSchemaType; ASchemaObjectName, ASchemaPattern : string);
  2932. begin
  2933. FSchemaType:=ASchemaType;
  2934. FSchemaObjectName:=ASchemaObjectName;
  2935. FSchemaPattern:=ASchemaPattern;
  2936. end;
  2937. procedure TCustomSQLQuery.BeforeRefreshOpenCursor;
  2938. begin
  2939. // This is only necessary because TIBConnection can not re-open a
  2940. // prepared cursor. In fact this is wrong, but has never led to
  2941. // problems because in SetActive(false) queries are always
  2942. // unprepared. (which is also wrong, but has to be fixed later)
  2943. if IsPrepared then with SQLConnection do
  2944. UnPrepareStatement(Cursor);
  2945. end;
  2946. function TCustomSQLQuery.CreateParams: TSQLDBParams;
  2947. begin
  2948. Result:=TSQLDBParams.Create(Nil);
  2949. end;
  2950. function TCustomSQLQuery.LogEvent(EventType: TDBEventType): Boolean;
  2951. begin
  2952. Result:=Assigned(Database) and SQLConnection.LogEvent(EventType);
  2953. end;
  2954. procedure TCustomSQLQuery.Log(EventType: TDBEventType; const Msg: String);
  2955. Var
  2956. M : String;
  2957. begin
  2958. If LogEvent(EventType) then
  2959. begin
  2960. M:=Msg;
  2961. If (Name<>'') then
  2962. M:=Name+' : '+M;
  2963. SQLConnection.Log(EventType,M);
  2964. end;
  2965. end;
  2966. class function TCustomSQLQuery.FieldDefsClass: TFieldDefsClass;
  2967. begin
  2968. Result:=TSQLDBFieldDefs;
  2969. end;
  2970. function TCustomSQLQuery.GetStatementType : TStatementType;
  2971. begin
  2972. if Assigned(Cursor) then
  2973. Result:=Cursor.FStatementType
  2974. else
  2975. Result:=stUnknown;
  2976. end;
  2977. procedure TCustomSQLQuery.SetParamCheck(AValue: Boolean);
  2978. begin
  2979. FStatement.ParamCheck:=AValue;
  2980. end;
  2981. procedure TCustomSQLQuery.SetMacroCheck(AValue: Boolean);
  2982. begin
  2983. FStatement.MacroCheck:=AValue;
  2984. end;
  2985. procedure TCustomSQLQuery.SetOptions(AValue: TSQLQueryOptions);
  2986. begin
  2987. if FOptions=AValue then Exit;
  2988. CheckInactive;
  2989. FOptions:=AValue;
  2990. if sqoKeepOpenOnCommit in FOptions then
  2991. PacketRecords:=-1;
  2992. end;
  2993. procedure TCustomSQLQuery.SetSQLConnection(AValue: TSQLConnection);
  2994. begin
  2995. Database:=AValue;
  2996. end;
  2997. procedure TCustomSQLQuery.SetSQLTransaction(AValue: TSQLTransaction);
  2998. begin
  2999. Transaction:=AValue;
  3000. end;
  3001. procedure TCustomSQLQuery.SetInsertSQL(const AValue: TStringList);
  3002. begin
  3003. FInsertSQL.Assign(AValue);
  3004. end;
  3005. procedure TCustomSQLQuery.SetUpdateSQL(const AValue: TStringList);
  3006. begin
  3007. FUpdateSQL.Assign(AValue);
  3008. end;
  3009. procedure TCustomSQLQuery.SetDeleteSQL(const AValue: TStringList);
  3010. begin
  3011. FDeleteSQL.Assign(AValue);
  3012. end;
  3013. procedure TCustomSQLQuery.SetRefreshSQL(const AValue: TStringList);
  3014. begin
  3015. FRefreshSQL.Assign(AValue);
  3016. end;
  3017. procedure TCustomSQLQuery.SetParams(AValue: TParams);
  3018. begin
  3019. FStatement.Params.Assign(AValue);
  3020. end;
  3021. procedure TCustomSQLQuery.SetMacros(AValue: TParams);
  3022. begin
  3023. FStatement.Macros.Assign(AValue);
  3024. end;
  3025. procedure TCustomSQLQuery.SetDataSource(AValue: TDataSource);
  3026. Var
  3027. DS : TDataSource;
  3028. begin
  3029. DS:=DataSource;
  3030. If (AValue<>DS) then
  3031. begin
  3032. If Assigned(AValue) and (AValue.Dataset=Self) then
  3033. DatabaseError(SErrCircularDataSourceReferenceNotAllowed,Self);
  3034. If Assigned(DS) then
  3035. DS.RemoveFreeNotification(Self);
  3036. FStatement.DataSource:=AValue;
  3037. end;
  3038. end;
  3039. function TCustomSQLQuery.GetDataSource: TDataSource;
  3040. begin
  3041. If Assigned(FStatement) then
  3042. Result:=FStatement.DataSource
  3043. else
  3044. Result:=Nil;
  3045. end;
  3046. procedure TCustomSQLQuery.Notification(AComponent: TComponent; Operation: TOperation);
  3047. begin
  3048. Inherited;
  3049. If (Operation=opRemove) and (AComponent=DataSource) then
  3050. DataSource:=Nil;
  3051. end;
  3052. procedure TCustomSQLQuery.DoOnNewRecord;
  3053. begin
  3054. inherited;
  3055. if FSequence.ApplyEvent = saeOnNewRecord then
  3056. FSequence.Apply;
  3057. end;
  3058. procedure TCustomSQLQuery.DoBeforePost;
  3059. begin
  3060. if (State = dsInsert) and (FSequence.ApplyEvent = saeOnPost) then
  3061. FSequence.Apply;
  3062. inherited;
  3063. end;
  3064. function TCustomSQLQuery.PSGetUpdateException(E: Exception; Prev: EUpdateError): EUpdateError;
  3065. var
  3066. PrevErrorCode, ErrorCode: Integer;
  3067. begin
  3068. if Assigned(Prev) then
  3069. PrevErrorCode := Prev.ErrorCode
  3070. else
  3071. PrevErrorCode := 0;
  3072. if E is ESQLDatabaseError then
  3073. ErrorCode := ESQLDatabaseError(E).ErrorCode
  3074. else
  3075. ErrorCode := 0;
  3076. Result := EUpdateError.Create(SOnUpdateError, E.Message, ErrorCode, PrevErrorCode, E);
  3077. end;
  3078. function TCustomSQLQuery.PSGetTableName: string;
  3079. begin
  3080. Result := FTableName;
  3081. end;
  3082. { TSQLScript }
  3083. procedure TSQLScript.ExecuteStatement(SQLStatement: TStrings;
  3084. var StopExecution: Boolean);
  3085. begin
  3086. fquery.SQL.assign(SQLStatement);
  3087. fquery.ExecSQL;
  3088. end;
  3089. procedure TSQLScript.ExecuteDirective(Directive, Argument: String;
  3090. var StopExecution: Boolean);
  3091. begin
  3092. if assigned (FOnDirective) then
  3093. FOnDirective (Self, Directive, Argument, StopExecution);
  3094. end;
  3095. procedure TSQLScript.ExecuteCommit(CommitRetaining: boolean=true);
  3096. begin
  3097. if FTransaction is TSQLTransaction then
  3098. if CommitRetaining then
  3099. TSQLTransaction(FTransaction).CommitRetaining
  3100. else
  3101. begin
  3102. TSQLTransaction(FTransaction).Commit;
  3103. TSQLTransaction(FTransaction).StartTransaction;
  3104. end
  3105. else
  3106. begin
  3107. FTransaction.Active := false;
  3108. FTransaction.Active := true;
  3109. end;
  3110. end;
  3111. procedure TSQLScript.SetDatabase(Value: TDatabase);
  3112. begin
  3113. FDatabase := Value;
  3114. end;
  3115. procedure TSQLScript.SetTransaction(Value: TDBTransaction);
  3116. begin
  3117. FTransaction := Value;
  3118. end;
  3119. procedure TSQLScript.CheckDatabase;
  3120. begin
  3121. If (FDatabase=Nil) then
  3122. DatabaseError(SErrNoDatabaseAvailable,Self)
  3123. end;
  3124. function TSQLScript.CreateQuery: TCustomSQLQuery;
  3125. begin
  3126. Result := TCustomSQLQuery.Create(nil);
  3127. Result.ParamCheck := false; // Do not parse for parameters; breaks use of e.g. select bla into :bla in Firebird procedures
  3128. end;
  3129. constructor TSQLScript.Create(AOwner: TComponent);
  3130. begin
  3131. inherited Create(AOwner);
  3132. FQuery := CreateQuery;
  3133. end;
  3134. destructor TSQLScript.Destroy;
  3135. begin
  3136. FQuery.Free;
  3137. inherited Destroy;
  3138. end;
  3139. procedure TSQLScript.Execute;
  3140. begin
  3141. FQuery.DataBase := FDatabase;
  3142. FQuery.Transaction := FTransaction;
  3143. inherited Execute;
  3144. end;
  3145. procedure TSQLScript.ExecuteScript;
  3146. begin
  3147. Execute;
  3148. end;
  3149. { Connection definitions }
  3150. Var
  3151. ConnDefs : TStringList;
  3152. Procedure CheckDefs;
  3153. begin
  3154. If (ConnDefs=Nil) then
  3155. begin
  3156. ConnDefs:=TStringList.Create;
  3157. ConnDefs.Sorted:=True;
  3158. ConnDefs.Duplicates:=dupError;
  3159. end;
  3160. end;
  3161. Procedure DoneDefs;
  3162. Var
  3163. I : Integer;
  3164. begin
  3165. If Assigned(ConnDefs) then
  3166. begin
  3167. For I:=ConnDefs.Count-1 downto 0 do
  3168. begin
  3169. ConnDefs.Objects[i].Free;
  3170. ConnDefs.Delete(I);
  3171. end;
  3172. FreeAndNil(ConnDefs);
  3173. end;
  3174. end;
  3175. Function GetConnectionDef(ConnectorName : String) : TConnectionDef;
  3176. Var
  3177. I : Integer;
  3178. begin
  3179. CheckDefs;
  3180. I:=ConnDefs.IndexOf(ConnectorName);
  3181. If (I<>-1) then
  3182. Result:=TConnectionDef(ConnDefs.Objects[i])
  3183. else
  3184. Result:=Nil;
  3185. end;
  3186. procedure RegisterConnection(Def: TConnectionDefClass);
  3187. Var
  3188. I : Integer;
  3189. begin
  3190. CheckDefs;
  3191. I:=ConnDefs.IndexOf(Def.TypeName);
  3192. If (I=-1) then
  3193. ConnDefs.AddObject(Def.TypeName,Def.Create)
  3194. else
  3195. begin
  3196. ConnDefs.Objects[I].Free;
  3197. ConnDefs.Objects[I]:=Def.Create;
  3198. end;
  3199. end;
  3200. procedure UnRegisterConnection(Def: TConnectionDefClass);
  3201. begin
  3202. UnRegisterConnection(Def.TypeName);
  3203. end;
  3204. procedure UnRegisterConnection(ConnectionName: String);
  3205. Var
  3206. I : Integer;
  3207. begin
  3208. if (ConnDefs<>Nil) then
  3209. begin
  3210. I:=ConnDefs.IndexOf(ConnectionName);
  3211. If (I<>-1) then
  3212. begin
  3213. ConnDefs.Objects[I].Free;
  3214. ConnDefs.Delete(I);
  3215. end;
  3216. end;
  3217. end;
  3218. procedure GetConnectionList(List: TSTrings);
  3219. begin
  3220. CheckDefs;
  3221. List.Text:=ConnDefs.Text;
  3222. end;
  3223. { TSQLConnector }
  3224. procedure TSQLConnector.SetConnectorType(const AValue: String);
  3225. begin
  3226. if FConnectorType<>AValue then
  3227. begin
  3228. CheckDisconnected;
  3229. If Assigned(FProxy) then
  3230. FreeProxy;
  3231. FConnectorType:=AValue;
  3232. CreateProxy;
  3233. end;
  3234. end;
  3235. procedure TSQLConnector.SetTransaction(Value: TSQLTransaction);
  3236. begin
  3237. inherited SetTransaction(Value);
  3238. If Assigned(FProxy) and (FProxy.Transaction<>Value) then
  3239. FProxy.FTransaction:=Value;
  3240. end;
  3241. procedure TSQLConnector.DoInternalConnect;
  3242. Var
  3243. D : TConnectionDef;
  3244. begin
  3245. inherited DoInternalConnect;
  3246. CheckProxy;
  3247. FProxy.CharSet:=Self.CharSet;
  3248. FProxy.DatabaseName:=Self.DatabaseName;
  3249. FProxy.HostName:=Self.HostName;
  3250. FProxy.LogEvents:=Self.LogEvents;
  3251. FProxy.Password:=Self.Password;
  3252. FProxy.Role:=Self.Role;
  3253. FProxy.UserName:=Self.UserName;
  3254. FProxy.FTransaction:=Self.Transaction;
  3255. FProxy.LogEvents:=Self.LogEvents;
  3256. FProxy.OnLog:=Self.OnLog;
  3257. FProxy.Options:=Self.Options;
  3258. D:=GetConnectionDef(ConnectorType);
  3259. D.ApplyParams(Params,FProxy);
  3260. FProxy.Connected:=True;
  3261. end;
  3262. procedure TSQLConnector.DoInternalDisconnect;
  3263. begin
  3264. FProxy.Connected:=False;
  3265. inherited DoInternalDisconnect;
  3266. end;
  3267. procedure TSQLConnector.CheckProxy;
  3268. begin
  3269. If (FProxy=Nil) then
  3270. CreateProxy;
  3271. end;
  3272. procedure TSQLConnector.CreateProxy;
  3273. Var
  3274. D : TConnectionDef;
  3275. begin
  3276. D:=GetConnectionDef(ConnectorType);
  3277. If (D=Nil) then
  3278. DatabaseErrorFmt(SErrUnknownConnectorType,[ConnectorType],Self);
  3279. FProxy:=D.ConnectionClass.Create(Self);
  3280. FFieldNameQuoteChars := FProxy.FieldNameQuoteChars;
  3281. FConnOptions := FProxy.ConnOptions;
  3282. end;
  3283. procedure TSQLConnector.FreeProxy;
  3284. begin
  3285. FProxy.Connected:=False;
  3286. FreeAndNil(FProxy);
  3287. end;
  3288. function TSQLConnector.StrToStatementType(s: string): TStatementType;
  3289. begin
  3290. CheckProxy;
  3291. Result:=FProxy.StrToStatementType(s);
  3292. end;
  3293. function TSQLConnector.GetAsSQLText(Field: TField): string;
  3294. begin
  3295. CheckProxy;
  3296. Result:=FProxy.GetAsSQLText(Field);
  3297. end;
  3298. function TSQLConnector.GetAsSQLText(Param: TParam): string;
  3299. begin
  3300. CheckProxy;
  3301. Result:=FProxy.GetAsSQLText(Param);
  3302. end;
  3303. function TSQLConnector.GetHandle: pointer;
  3304. begin
  3305. CheckProxy;
  3306. Result:=FProxy.GetHandle;
  3307. end;
  3308. function TSQLConnector.AllocateCursorHandle: TSQLCursor;
  3309. begin
  3310. CheckProxy;
  3311. Result:=FProxy.AllocateCursorHandle;
  3312. end;
  3313. procedure TSQLConnector.DeAllocateCursorHandle(var cursor: TSQLCursor);
  3314. begin
  3315. CheckProxy;
  3316. FProxy.DeAllocateCursorHandle(cursor);
  3317. end;
  3318. function TSQLConnector.AllocateTransactionHandle: TSQLHandle;
  3319. begin
  3320. CheckProxy;
  3321. Result:=FProxy.AllocateTransactionHandle;
  3322. end;
  3323. procedure TSQLConnector.PrepareStatement(cursor: TSQLCursor;
  3324. ATransaction: TSQLTransaction; buf: string; AParams: TParams);
  3325. begin
  3326. CheckProxy;
  3327. FProxy.PrepareStatement(cursor, ATransaction, buf, AParams);
  3328. end;
  3329. procedure TSQLConnector.Execute(cursor: TSQLCursor;
  3330. atransaction: tSQLtransaction; AParams: TParams);
  3331. begin
  3332. CheckProxy;
  3333. FProxy.Execute(cursor, atransaction, AParams);
  3334. end;
  3335. function TSQLConnector.Fetch(cursor: TSQLCursor): boolean;
  3336. begin
  3337. CheckProxy;
  3338. Result:=FProxy.Fetch(cursor);
  3339. end;
  3340. procedure TSQLConnector.AddFieldDefs(cursor: TSQLCursor; FieldDefs: TfieldDefs
  3341. );
  3342. begin
  3343. CheckProxy;
  3344. FProxy.AddFieldDefs(cursor, FieldDefs);
  3345. end;
  3346. procedure TSQLConnector.UnPrepareStatement(cursor: TSQLCursor);
  3347. begin
  3348. CheckProxy;
  3349. FProxy.UnPrepareStatement(cursor);
  3350. end;
  3351. procedure TSQLConnector.FreeFldBuffers(cursor: TSQLCursor);
  3352. begin
  3353. CheckProxy;
  3354. FProxy.FreeFldBuffers(cursor);
  3355. end;
  3356. function TSQLConnector.GetNextValueSQL(const SequenceName: string; IncrementBy: Integer): string;
  3357. begin
  3358. Result:=Proxy.GetNextValueSQL(SequenceName, IncrementBy);
  3359. end;
  3360. function TSQLConnector.LoadField(cursor: TSQLCursor; FieldDef: TFieldDef;
  3361. buffer: pointer; out CreateBlob: boolean): boolean;
  3362. begin
  3363. CheckProxy;
  3364. Result:=FProxy.LoadField(cursor, FieldDef, buffer, CreateBlob);
  3365. end;
  3366. procedure TSQLConnector.LoadBlobIntoBuffer(FieldDef: TFieldDef;
  3367. ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction);
  3368. begin
  3369. CheckProxy;
  3370. FProxy.LoadBlobIntoBuffer(FieldDef, ABlobBuf, cursor, ATransaction);
  3371. end;
  3372. function TSQLConnector.RowsAffected(cursor: TSQLCursor): TRowsCount;
  3373. begin
  3374. CheckProxy;
  3375. Result := FProxy.RowsAffected(cursor);
  3376. end;
  3377. function TSQLConnector.GetTransactionHandle(trans: TSQLHandle): pointer;
  3378. begin
  3379. CheckProxy;
  3380. Result:=FProxy.GetTransactionHandle(trans);
  3381. end;
  3382. function TSQLConnector.Commit(trans: TSQLHandle): boolean;
  3383. begin
  3384. CheckProxy;
  3385. Result:=FProxy.Commit(trans);
  3386. end;
  3387. function TSQLConnector.RollBack(trans: TSQLHandle): boolean;
  3388. begin
  3389. CheckProxy;
  3390. Result:=FProxy.RollBack(trans);
  3391. end;
  3392. function TSQLConnector.StartDBTransaction(trans: TSQLHandle; aParams: string): boolean;
  3393. begin
  3394. CheckProxy;
  3395. Result:=FProxy.StartDBTransaction(trans, aParams);
  3396. end;
  3397. procedure TSQLConnector.CommitRetaining(trans: TSQLHandle);
  3398. begin
  3399. CheckProxy;
  3400. FProxy.CommitRetaining(trans);
  3401. end;
  3402. procedure TSQLConnector.RollBackRetaining(trans: TSQLHandle);
  3403. begin
  3404. CheckProxy;
  3405. FProxy.RollBackRetaining(trans);
  3406. end;
  3407. procedure TSQLConnector.UpdateIndexDefs(IndexDefs: TIndexDefs;
  3408. TableName: string);
  3409. begin
  3410. CheckProxy;
  3411. FProxy.UpdateIndexDefs(IndexDefs, TableName);
  3412. end;
  3413. function TSQLConnector.GetSchemaInfoSQL(SchemaType: TSchemaType;
  3414. SchemaObjectName, SchemaPattern: string): string;
  3415. begin
  3416. CheckProxy;
  3417. Result:=FProxy.GetSchemaInfoSQL(SchemaType, SchemaObjectName, SchemaPattern);
  3418. end;
  3419. { TConnectionDef }
  3420. class function TConnectionDef.TypeName: String;
  3421. begin
  3422. Result:='';
  3423. end;
  3424. class function TConnectionDef.ConnectionClass: TSQLConnectionClass;
  3425. begin
  3426. Result:=Nil;
  3427. end;
  3428. class function TConnectionDef.Description: String;
  3429. begin
  3430. Result:='';
  3431. end;
  3432. class function TConnectionDef.DefaultLibraryName: String;
  3433. begin
  3434. Result:='';
  3435. end;
  3436. class function TConnectionDef.LoadFunction: TLibraryLoadFunction;
  3437. begin
  3438. Result:=Nil;
  3439. end;
  3440. class function TConnectionDef.UnLoadFunction: TLibraryUnLoadFunction;
  3441. begin
  3442. Result:=Nil;
  3443. end;
  3444. class function TConnectionDef.LoadedLibraryName: string;
  3445. begin
  3446. Result:='';
  3447. end;
  3448. procedure TConnectionDef.ApplyParams(Params: TStrings;
  3449. AConnection: TSQLConnection);
  3450. begin
  3451. AConnection.Params.Assign(Params);
  3452. end;
  3453. { TServerIndexDefs }
  3454. constructor TServerIndexDefs.create(ADataset: TDataset);
  3455. begin
  3456. if not (ADataset is TCustomSQLQuery) then
  3457. DatabaseErrorFmt(SErrNotASQLQuery,[ADataset.Name]);
  3458. inherited create(ADataset);
  3459. end;
  3460. procedure TServerIndexDefs.Update;
  3461. begin
  3462. if (not updated) and assigned(Dataset) then
  3463. begin
  3464. TCustomSQLQuery(Dataset).UpdateServerIndexDefs;
  3465. updated := True;
  3466. end;
  3467. end;
  3468. Initialization
  3469. Finalization
  3470. DoneDefs;
  3471. end.