sqldb.pp 92 KB

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