sqldb.pp 82 KB

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