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. constructor TSQLConnection.Create(AOwner: TComponent);
  915. begin
  916. inherited Create(AOwner);
  917. FSQLFormatSettings:=DefaultSQLFormatSettings;
  918. FFieldNameQuoteChars:=DoubleQuotes;
  919. FLogEvents:=LogAllEvents; //match Property LogEvents...Default LogAllEvents
  920. FStatements:=TFPList.Create;
  921. end;
  922. destructor TSQLConnection.Destroy;
  923. begin
  924. Connected:=False; // needed because we want to de-allocate statements
  925. FreeAndNil(FStatements);
  926. inherited Destroy;
  927. end;
  928. function TSQLConnection.StrToStatementType(s : string) : TStatementType;
  929. var T : TStatementType;
  930. begin
  931. S:=Lowercase(s);
  932. for T:=stSelect to stRollback do
  933. if (S=StatementTokens[T]) then
  934. Exit(T);
  935. Result:=stUnknown;
  936. end;
  937. procedure TSQLConnection.SetTransaction(Value : TSQLTransaction);
  938. begin
  939. if FTransaction<>value then
  940. begin
  941. if Assigned(FTransaction) and FTransaction.Active then
  942. DatabaseError(SErrAssTransaction);
  943. if Assigned(Value) then
  944. Value.Database := Self;
  945. FTransaction := Value;
  946. If Assigned(FTransaction) and (FTransaction.Database=Nil) then
  947. FTransaction.Database:=Self;
  948. end;
  949. end;
  950. procedure TSQLConnection.UpdateIndexDefs(IndexDefs : TIndexDefs; TableName : string);
  951. begin
  952. // Empty abstract
  953. end;
  954. procedure TSQLConnection.DoInternalConnect;
  955. begin
  956. if (DatabaseName = '') and not(sqSupportEmptyDatabaseName in FConnOptions) then
  957. DatabaseError(SErrNoDatabaseName,self);
  958. end;
  959. procedure TSQLConnection.DoInternalDisconnect;
  960. Var
  961. I : integer;
  962. begin
  963. For I:=0 to FStatements.Count-1 do
  964. TCustomSQLStatement(FStatements[i]).Unprepare;
  965. FStatements.Clear;
  966. end;
  967. procedure TSQLConnection.StartTransaction;
  968. begin
  969. if not assigned(Transaction) then
  970. DatabaseError(SErrConnTransactionnSet)
  971. else
  972. Transaction.StartTransaction;
  973. end;
  974. procedure TSQLConnection.EndTransaction;
  975. begin
  976. if not assigned(Transaction) then
  977. DatabaseError(SErrConnTransactionnSet)
  978. else
  979. Transaction.EndTransaction;
  980. end;
  981. procedure TSQLConnection.ExecuteDirect(SQL: String);
  982. begin
  983. ExecuteDirect(SQL,FTransaction);
  984. end;
  985. procedure TSQLConnection.ExecuteDirect(SQL: String;
  986. ATransaction: TSQLTransaction);
  987. var Cursor : TSQLCursor;
  988. begin
  989. if not assigned(ATransaction) then
  990. DatabaseError(SErrTransactionnSet);
  991. if not Connected then Open;
  992. if not ATransaction.Active then ATransaction.StartTransaction;
  993. try
  994. SQL := TrimRight(SQL);
  995. if SQL = '' then
  996. DatabaseError(SErrNoStatement);
  997. Cursor := AllocateCursorHandle;
  998. Cursor.FStatementType := stUnknown;
  999. If LogEvent(detPrepare) then
  1000. Log(detPrepare,SQL);
  1001. PrepareStatement(Cursor,ATransaction,SQL,Nil);
  1002. If LogEvent(detExecute) then
  1003. Log(detExecute,SQL);
  1004. Execute(Cursor,ATransaction, Nil);
  1005. UnPrepareStatement(Cursor);
  1006. finally;
  1007. DeAllocateCursorHandle(Cursor);
  1008. end;
  1009. end;
  1010. function TSQLConnection.GetPort: cardinal;
  1011. begin
  1012. result := StrToIntDef(Params.Values['Port'],0);
  1013. end;
  1014. procedure TSQLConnection.SetPort(const AValue: cardinal);
  1015. begin
  1016. if AValue<>0 then
  1017. Params.Values['Port']:=IntToStr(AValue)
  1018. else with params do if IndexOfName('Port') > -1 then
  1019. Delete(IndexOfName('Port'));
  1020. end;
  1021. procedure TSQLConnection.GetDBInfo(const ASchemaType : TSchemaType; const ASchemaObjectName, AReturnField : string; AList: TStrings);
  1022. var qry : TCustomSQLQuery;
  1023. begin
  1024. if not assigned(Transaction) then
  1025. DatabaseError(SErrConnTransactionnSet);
  1026. qry := TCustomSQLQuery.Create(nil);
  1027. try
  1028. qry.transaction := Transaction;
  1029. qry.database := Self;
  1030. with qry do
  1031. begin
  1032. ParseSQL := False;
  1033. SetSchemaInfo(ASchemaType,ASchemaObjectName,'');
  1034. open;
  1035. AList.Clear;
  1036. while not eof do
  1037. begin
  1038. AList.Append(trim(fieldbyname(AReturnField).asstring));
  1039. Next;
  1040. end;
  1041. end;
  1042. finally
  1043. qry.free;
  1044. end;
  1045. end;
  1046. function TSQLConnection.RowsAffected(cursor: TSQLCursor): TRowsCount;
  1047. begin
  1048. Result := -1;
  1049. end;
  1050. procedure TSQLConnection.GetTableNames(List: TStrings; SystemTables: Boolean);
  1051. begin
  1052. if not SystemTables then
  1053. GetDBInfo(stTables,'','table_name',List)
  1054. else
  1055. GetDBInfo(stSysTables,'','table_name',List);
  1056. end;
  1057. procedure TSQLConnection.GetProcedureNames(List: TStrings);
  1058. begin
  1059. GetDBInfo(stProcedures,'','proc_name',List);
  1060. end;
  1061. procedure TSQLConnection.GetFieldNames(const TableName: string; List: TStrings);
  1062. begin
  1063. GetDBInfo(stColumns,TableName,'column_name',List);
  1064. end;
  1065. procedure TSQLConnection.GetSchemaNames(List: TStrings);
  1066. begin
  1067. GetDBInfo(stSchemata,'','SCHEMA_NAME',List);
  1068. end;
  1069. function TSQLConnection.GetConnectionInfo(InfoType: TConnInfoType): string;
  1070. var i: TConnInfoType;
  1071. begin
  1072. Result:='';
  1073. if InfoType = citAll then
  1074. for i:=citServerType to citClientVersion do
  1075. begin
  1076. if Result<>'' then Result:=Result+',';
  1077. Result:=Result+'"'+GetConnectionInfo(i)+'"';
  1078. end;
  1079. end;
  1080. function TSQLConnection.GetStatementInfo(const ASQL: string): TSQLStatementInfo;
  1081. type TParsePart = (ppStart,ppWith,ppSelect,ppTableName,ppFrom,ppWhere,ppGroup,ppOrder,ppBogus);
  1082. TPhraseSeparator = (sepNone, sepWhiteSpace, sepComma, sepComment, sepParentheses, sepDoubleQuote, sepEnd);
  1083. TKeyword = (kwWITH, kwSELECT, kwINSERT, kwUPDATE, kwDELETE, kwFROM, kwJOIN, kwWHERE, kwGROUP, kwORDER, kwUNION, kwROWS, kwLIMIT, kwUnknown);
  1084. const
  1085. KeywordNames: array[TKeyword] of string =
  1086. ('WITH', 'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'FROM', 'JOIN', 'WHERE', 'GROUP', 'ORDER', 'UNION', 'ROWS', 'LIMIT', '');
  1087. var
  1088. PSQL, CurrentP, SavedP,
  1089. PhraseP, PStatementPart : pchar;
  1090. S : string;
  1091. ParsePart : TParsePart;
  1092. BracketCount : Integer;
  1093. Separator : TPhraseSeparator;
  1094. Keyword, K : TKeyword;
  1095. begin
  1096. PSQL:=Pchar(ASQL);
  1097. ParsePart := ppStart;
  1098. CurrentP := PSQL-1;
  1099. PhraseP := PSQL;
  1100. Result.TableName := '';
  1101. Result.Updateable := False;
  1102. Result.WhereStartPos := 0;
  1103. Result.WhereStopPos := 0;
  1104. repeat
  1105. begin
  1106. inc(CurrentP);
  1107. SavedP := CurrentP;
  1108. case CurrentP^ of
  1109. ' ', #9..#13:
  1110. Separator := sepWhiteSpace;
  1111. ',':
  1112. Separator := sepComma;
  1113. #0, ';':
  1114. Separator := sepEnd;
  1115. '(':
  1116. begin
  1117. Separator := sepParentheses;
  1118. // skip everything between brackets, since it could be a sub-select, and
  1119. // further nothing between brackets could be interesting for the parser.
  1120. BracketCount := 1;
  1121. repeat
  1122. inc(CurrentP);
  1123. if CurrentP^ = '(' then inc(BracketCount)
  1124. else if CurrentP^ = ')' then dec(BracketCount);
  1125. until (CurrentP^ = #0) or (BracketCount = 0);
  1126. if CurrentP^ <> #0 then inc(CurrentP);
  1127. end;
  1128. '"','`':
  1129. if SkipComments(CurrentP, sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions) then
  1130. Separator := sepDoubleQuote;
  1131. else
  1132. if SkipComments(CurrentP, sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions) then
  1133. Separator := sepComment
  1134. else
  1135. Separator := sepNone;
  1136. end;
  1137. if (CurrentP > SavedP) and (SavedP > PhraseP) then
  1138. CurrentP := SavedP; // there is something before comment or left parenthesis
  1139. if Separator <> sepNone then
  1140. begin
  1141. if ((Separator in [sepWhitespace,sepComment]) and (PhraseP = SavedP)) then
  1142. PhraseP := CurrentP; // skip comments (but not parentheses) and white spaces
  1143. if (CurrentP-PhraseP > 0) or (Separator = sepEnd) then
  1144. begin
  1145. SetString(s, PhraseP, CurrentP-PhraseP);
  1146. Keyword := kwUnknown;
  1147. for K in TKeyword do
  1148. if SameText(s, KeywordNames[K]) then
  1149. begin
  1150. Keyword := K;
  1151. break;
  1152. end;
  1153. case ParsePart of
  1154. ppStart : begin
  1155. Result.StatementType := StrToStatementType(s);
  1156. case Keyword of
  1157. kwWITH : ParsePart := ppWith;
  1158. kwSELECT: ParsePart := ppSelect;
  1159. else break;
  1160. end;
  1161. end;
  1162. ppWith : begin
  1163. // WITH [RECURSIVE] CTE_name [ ( column_names ) ] AS ( CTE_query_definition ) [, ...]
  1164. // { SELECT | INSERT | UPDATE | DELETE } ...
  1165. case Keyword of
  1166. kwSELECT: Result.StatementType := stSelect;
  1167. kwINSERT: Result.StatementType := stInsert;
  1168. kwUPDATE: Result.StatementType := stUpdate;
  1169. kwDELETE: Result.StatementType := stDelete;
  1170. end;
  1171. if Result.StatementType <> stUnknown then break;
  1172. end;
  1173. ppSelect : begin
  1174. if Keyword = kwFROM then
  1175. ParsePart := ppTableName;
  1176. end;
  1177. ppTableName:
  1178. begin
  1179. // Meta-data requests are never updateable
  1180. // and select statements from more than one table
  1181. // and/or derived tables are also not updateable
  1182. if Separator in [sepWhitespace, sepComment, sepDoubleQuote, sepEnd] then
  1183. begin
  1184. Result.TableName := s;
  1185. Result.Updateable := True;
  1186. end;
  1187. ParsePart := ppFrom;
  1188. end;
  1189. ppFrom : begin
  1190. if (Keyword in [kwWHERE, kwGROUP, kwORDER, kwLIMIT, kwROWS]) or
  1191. (Separator = sepEnd) then
  1192. begin
  1193. case Keyword of
  1194. kwWHERE: ParsePart := ppWhere;
  1195. kwGROUP: ParsePart := ppGroup;
  1196. kwORDER: ParsePart := ppOrder;
  1197. else ParsePart := ppBogus;
  1198. end;
  1199. Result.WhereStartPos := PhraseP-PSQL+1;
  1200. PStatementPart := CurrentP;
  1201. end
  1202. else
  1203. // joined table or user_defined_function (...)
  1204. if (Keyword = kwJOIN) or (Separator in [sepComma, sepParentheses]) then
  1205. begin
  1206. Result.TableName := '';
  1207. Result.Updateable := False;
  1208. end;
  1209. end;
  1210. ppWhere : begin
  1211. if (Keyword in [kwGROUP, kwORDER, kwLIMIT, kwROWS]) or
  1212. (Separator = sepEnd) then
  1213. begin
  1214. ParsePart := ppBogus;
  1215. Result.WhereStartPos := PStatementPart-PSQL;
  1216. if (Separator = sepEnd) then
  1217. Result.WhereStopPos := CurrentP-PSQL+1
  1218. else
  1219. Result.WhereStopPos := PhraseP-PSQL+1;
  1220. end
  1221. else if (Keyword = kwUNION) then
  1222. begin
  1223. ParsePart := ppBogus;
  1224. Result.Updateable := False;
  1225. end;
  1226. end;
  1227. end; {case}
  1228. end;
  1229. if Separator in [sepComment, sepParentheses, sepDoubleQuote] then
  1230. dec(CurrentP);
  1231. PhraseP := CurrentP+1;
  1232. end
  1233. end;
  1234. until CurrentP^=#0;
  1235. end;
  1236. function TSQLConnection.GetAsSQLText(Field : TField) : string;
  1237. begin
  1238. if (not assigned(Field)) or Field.IsNull then Result := 'Null'
  1239. else case field.DataType of
  1240. ftString : Result := QuotedStr(Field.AsString);
  1241. ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Field.AsDateTime,FSqlFormatSettings) + '''';
  1242. ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz',Field.AsDateTime,FSqlFormatSettings) + '''';
  1243. ftTime : Result := QuotedStr(TimeIntervalToString(Field.AsDateTime));
  1244. else
  1245. Result := Field.AsString;
  1246. end; {case}
  1247. end;
  1248. function TSQLConnection.GetAsSQLText(Param: TParam) : string;
  1249. begin
  1250. if (not assigned(Param)) or Param.IsNull then Result := 'Null'
  1251. else case Param.DataType of
  1252. ftGuid,
  1253. ftMemo,
  1254. ftFixedChar,
  1255. ftString : Result := QuotedStr(Param.AsString);
  1256. ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Param.AsDateTime,FSQLFormatSettings) + '''';
  1257. ftTime : Result := QuotedStr(TimeIntervalToString(Param.AsDateTime));
  1258. ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', Param.AsDateTime, FSQLFormatSettings) + '''';
  1259. ftCurrency,
  1260. ftBcd : Result := CurrToStr(Param.AsCurrency, FSQLFormatSettings);
  1261. ftFloat : Result := FloatToStr(Param.AsFloat, FSQLFormatSettings);
  1262. ftFMTBcd : Result := stringreplace(Param.AsString, DefaultFormatSettings.DecimalSeparator, FSQLFormatSettings.DecimalSeparator, []);
  1263. else
  1264. Result := Param.AsString;
  1265. end; {case}
  1266. end;
  1267. function TSQLConnection.GetHandle: pointer;
  1268. begin
  1269. Result := nil;
  1270. end;
  1271. function TSQLConnection.LogEvent(EventType: TDBEventType): Boolean;
  1272. begin
  1273. Result:=(Assigned(FOnLog) or Assigned(GlobalDBLogHook)) and (EventType in LogEvents);
  1274. end;
  1275. procedure TSQLConnection.Log(EventType: TDBEventType; const Msg: String);
  1276. Var
  1277. M : String;
  1278. begin
  1279. If LogEvent(EventType) then
  1280. begin
  1281. If Assigned(FonLog) then
  1282. FOnLog(Self,EventType,Msg);
  1283. If Assigned(GlobalDBLogHook) then
  1284. begin
  1285. If (Name<>'') then
  1286. M:=Name+' : '+Msg
  1287. else
  1288. M:=ClassName+' : '+Msg;
  1289. GlobalDBLogHook(Self,EventType,M);
  1290. end;
  1291. end;
  1292. end;
  1293. procedure TSQLConnection.RegisterStatement(S: TCustomSQLStatement);
  1294. begin
  1295. if FStatements.IndexOf(S)=-1 then
  1296. FStatements.Add(S);
  1297. end;
  1298. procedure TSQLConnection.UnRegisterStatement(S: TCustomSQLStatement);
  1299. begin
  1300. if Assigned(FStatements) then // Can be nil, when we are destroying and datasets are uncoupled.
  1301. FStatements.Remove(S);
  1302. end;
  1303. function TSQLConnection.InitialiseUpdateStatement(Query : TCustomSQLQuery; var qry : TCustomSQLStatement): TCustomSQLStatement;
  1304. begin
  1305. if not assigned(qry) then
  1306. begin
  1307. qry := TCustomSQLStatement.Create(nil);
  1308. qry.ParseSQL := False;
  1309. qry.DataBase := Self;
  1310. qry.Transaction := Query.SQLTransaction;
  1311. end;
  1312. Result:=qry;
  1313. end;
  1314. procedure TSQLConnection.AddFieldToUpdateWherePart(var sql_where : string;UpdateMode : TUpdateMode; F : TField);
  1315. begin
  1316. if (pfInKey in F.ProviderFlags)
  1317. or ((UpdateMode = upWhereAll) and (pfInWhere in F.ProviderFlags))
  1318. or ((UpdateMode = UpWhereChanged) and (pfInWhere in F.ProviderFlags) and (F.Value <> F.OldValue)) then
  1319. begin
  1320. if (sql_where<>'') then
  1321. sql_where:=sql_where + ' and ';
  1322. sql_where:= sql_where + '(' + FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1];
  1323. if F.OldValue = NULL then
  1324. sql_where := sql_where + ' is null '
  1325. else
  1326. sql_where := sql_where +'= :"' + 'OLD_' + F.FieldName + '"';
  1327. sql_where:=sql_where+') ';
  1328. end;
  1329. end;
  1330. function TSQLConnection.ConstructUpdateSQL(Query: TCustomSQLQuery): string;
  1331. var x : integer;
  1332. F : TField;
  1333. sql_set : string;
  1334. sql_where : string;
  1335. begin
  1336. sql_set := '';
  1337. sql_where := '';
  1338. for x := 0 to Query.Fields.Count -1 do
  1339. begin
  1340. F:=Query.Fields[x];
  1341. AddFieldToUpdateWherePart(sql_where,Query.UpdateMode,F);
  1342. if (pfInUpdate in F.ProviderFlags) and (not F.ReadOnly) then
  1343. sql_set := sql_set +FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1] +'=:"' + F.FieldName + '",';
  1344. end;
  1345. if length(sql_set) = 0 then DatabaseErrorFmt(sNoUpdateFields,['update'],self);
  1346. setlength(sql_set,length(sql_set)-1);
  1347. if length(sql_where) = 0 then DatabaseErrorFmt(sNoWhereFields,['update'],self);
  1348. result := 'update ' + Query.FTableName + ' set ' + sql_set + ' where ' + sql_where;
  1349. end;
  1350. function TSQLConnection.ConstructInsertSQL(Query : TCustomSQLQuery) : string;
  1351. var x : integer;
  1352. sql_fields : string;
  1353. sql_values : string;
  1354. F : TField;
  1355. begin
  1356. sql_fields := '';
  1357. sql_values := '';
  1358. for x := 0 to Query.Fields.Count -1 do
  1359. begin
  1360. F:=Query.Fields[x];
  1361. if (not F.IsNull) and (pfInUpdate in F.ProviderFlags) and (not F.ReadOnly) then
  1362. begin
  1363. sql_fields := sql_fields + FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1] + ',';
  1364. sql_values := sql_values + ':"' + F.FieldName + '",';
  1365. end;
  1366. end;
  1367. if length(sql_fields) = 0 then
  1368. DatabaseErrorFmt(sNoUpdateFields,['insert'],self);
  1369. setlength(sql_fields,length(sql_fields)-1);
  1370. setlength(sql_values,length(sql_values)-1);
  1371. result := 'insert into ' + Query.FTableName + ' (' + sql_fields + ') values (' + sql_values + ')';
  1372. end;
  1373. function TSQLConnection.ConstructDeleteSQL(Query : TCustomSQLQuery) : string;
  1374. var
  1375. x : integer;
  1376. sql_where : string;
  1377. begin
  1378. sql_where := '';
  1379. for x := 0 to Query.Fields.Count -1 do
  1380. AddFieldToUpdateWherePart(sql_where,Query.UpdateMode, Query.Fields[x]);
  1381. if length(sql_where) = 0 then
  1382. DatabaseErrorFmt(sNoWhereFields,['delete'],self);
  1383. result := 'delete from ' + Query.FTableName + ' where ' + sql_where;
  1384. end;
  1385. procedure TSQLConnection.ApplyFieldUpdate(C : TSQLCursor; P : TSQLDBParam;F : TField; UseOldValue : Boolean);
  1386. begin
  1387. if UseOldValue then
  1388. P.AssignFieldValue(F,F.OldValue)
  1389. else
  1390. P.AssignFieldValue(F,F.Value);
  1391. P.FFieldDef:=F.FieldDef;
  1392. end;
  1393. procedure TSQLConnection.ApplyRecUpdate(Query: TCustomSQLQuery; UpdateKind: TUpdateKind);
  1394. var
  1395. qry : TCustomSQLStatement;
  1396. s : string;
  1397. x : integer;
  1398. Fld : TField;
  1399. P : TParam;
  1400. B : Boolean;
  1401. begin
  1402. case UpdateKind of
  1403. ukInsert : begin
  1404. s := trim(Query.FInsertSQL.Text);
  1405. if s = '' then s := ConstructInsertSQL(Query);
  1406. qry := InitialiseUpdateStatement(Query,Query.FInsertQry);
  1407. end;
  1408. ukModify : begin
  1409. s := trim(Query.FUpdateSQL.Text);
  1410. if (s='') and (not assigned(Query.FUpdateQry) or (Query.UpdateMode<>upWhereKeyOnly)) then //first time or dynamic where part
  1411. s := ConstructUpdateSQL(Query);
  1412. qry := InitialiseUpdateStatement(Query,Query.FUpdateQry);
  1413. end;
  1414. ukDelete : begin
  1415. s := trim(Query.FDeleteSQL.Text);
  1416. if (s='') and (not assigned(Query.FDeleteQry) or (Query.UpdateMode<>upWhereKeyOnly)) then
  1417. s := ConstructDeleteSQL(Query);
  1418. qry := InitialiseUpdateStatement(Query,Query.FDeleteQry);
  1419. end;
  1420. end;
  1421. if (s<>'') and (qry.SQL.Text<>s) then
  1422. qry.SQL.Text:=s; //assign only when changed, to avoid UnPrepare/Prepare
  1423. assert(qry.sql.Text<>'');
  1424. for x:=0 to Qry.Params.Count-1 do
  1425. begin
  1426. P:=Qry.Params[x];
  1427. S:=p.name;
  1428. B:=Sametext(leftstr(S,4),'OLD_');
  1429. if B then
  1430. Delete(S,1,4);
  1431. Fld:=Query.FieldByName(S);
  1432. ApplyFieldUpdate(Query.Cursor,P as TSQLDBParam,Fld,B);
  1433. end;
  1434. Qry.execute;
  1435. end;
  1436. procedure TSQLConnection.FreeFldBuffers(cursor: TSQLCursor);
  1437. begin
  1438. // empty
  1439. end;
  1440. function TSQLConnection.GetSchemaInfoSQL( SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string;
  1441. begin
  1442. case SchemaType of
  1443. stProcedures: Result := 'SELECT * FROM INFORMATION_SCHEMA.ROUTINES';
  1444. stSchemata : Result := 'SELECT * FROM INFORMATION_SCHEMA.SCHEMATA';
  1445. else DatabaseError(SMetadataUnavailable);
  1446. end;
  1447. end;
  1448. procedure TSQLConnection.CreateDB;
  1449. begin
  1450. DatabaseError(SNotSupported);
  1451. end;
  1452. procedure TSQLConnection.DropDB;
  1453. begin
  1454. DatabaseError(SNotSupported);
  1455. end;
  1456. { TSQLTransaction }
  1457. procedure TSQLTransaction.EndTransaction;
  1458. begin
  1459. Case Action of
  1460. caCommit :
  1461. Commit;
  1462. caCommitRetaining :
  1463. CommitRetaining;
  1464. caNone,
  1465. caRollback :
  1466. RollBack;
  1467. caRollbackRetaining :
  1468. RollbackRetaining;
  1469. end;
  1470. end;
  1471. procedure TSQLTransaction.SetParams(const AValue: TStringList);
  1472. begin
  1473. FParams.Assign(AValue);
  1474. end;
  1475. function TSQLTransaction.GetSQLConnection: TSQLConnection;
  1476. begin
  1477. Result:=Database as TSQLConnection;
  1478. end;
  1479. procedure TSQLTransaction.SetSQLConnection(AValue: TSQLConnection);
  1480. begin
  1481. Database:=AValue;
  1482. end;
  1483. function TSQLTransaction.GetHandle: Pointer;
  1484. begin
  1485. Result := SQLConnection.GetTransactionHandle(FTrans);
  1486. end;
  1487. procedure TSQLTransaction.Commit;
  1488. begin
  1489. if active then
  1490. begin
  1491. closedatasets;
  1492. If LogEvent(detCommit) then
  1493. Log(detCommit,SCommitting);
  1494. if SQLConnection.commit(FTrans) then
  1495. begin
  1496. closeTrans;
  1497. FreeAndNil(FTrans);
  1498. end;
  1499. end;
  1500. end;
  1501. procedure TSQLTransaction.CommitRetaining;
  1502. begin
  1503. if active then
  1504. begin
  1505. If LogEvent(detCommit) then
  1506. Log(detCommit,SCommitRetaining);
  1507. SQLConnection.commitRetaining(FTrans);
  1508. end;
  1509. end;
  1510. procedure TSQLTransaction.Rollback;
  1511. begin
  1512. if active then
  1513. begin
  1514. closedatasets;
  1515. If LogEvent(detRollback) then
  1516. Log(detRollback,SRollingBack);
  1517. if SQLConnection.RollBack(FTrans) then
  1518. begin
  1519. CloseTrans;
  1520. FreeAndNil(FTrans);
  1521. end;
  1522. end;
  1523. end;
  1524. procedure TSQLTransaction.RollbackRetaining;
  1525. begin
  1526. if active then
  1527. begin
  1528. If LogEvent(detRollback) then
  1529. Log(detRollback,SRollBackRetaining);
  1530. SQLConnection.RollBackRetaining(FTrans);
  1531. end;
  1532. end;
  1533. procedure TSQLTransaction.StartTransaction;
  1534. var db : TSQLConnection;
  1535. begin
  1536. if Active then
  1537. DatabaseError(SErrTransAlreadyActive);
  1538. db := SQLConnection;
  1539. if Db = nil then
  1540. DatabaseError(SErrDatabasenAssigned);
  1541. if not Db.Connected then
  1542. Db.Open;
  1543. if not assigned(FTrans) then FTrans := Db.AllocateTransactionHandle;
  1544. if Db.StartdbTransaction(FTrans,FParams.CommaText) then OpenTrans;
  1545. end;
  1546. constructor TSQLTransaction.Create(AOwner : TComponent);
  1547. begin
  1548. inherited Create(AOwner);
  1549. FParams := TStringList.Create;
  1550. Action:=caRollBack;
  1551. end;
  1552. destructor TSQLTransaction.Destroy;
  1553. begin
  1554. EndTransaction;
  1555. FreeAndNil(FTrans);
  1556. FreeAndNil(FParams);
  1557. inherited Destroy;
  1558. end;
  1559. procedure TSQLTransaction.SetDatabase(Value: TDatabase);
  1560. begin
  1561. If Value<>Database then
  1562. begin
  1563. if assigned(value) and not (Value is TSQLConnection) then
  1564. DatabaseErrorFmt(SErrNotASQLConnection,[value.Name],self);
  1565. CheckInactive;
  1566. If Assigned(Database) then
  1567. with SQLConnection do
  1568. if Transaction = self then Transaction := nil;
  1569. inherited SetDatabase(Value);
  1570. If Assigned(Database) and not (csLoading in ComponentState) then
  1571. If (SQLConnection.Transaction=Nil) then
  1572. SQLConnection.Transaction:=Self;
  1573. end;
  1574. end;
  1575. function TSQLTransaction.LogEvent(EventType: TDBEventType): Boolean;
  1576. begin
  1577. Result:=Assigned(Database) and SQLConnection.LogEvent(EventType);
  1578. end;
  1579. procedure TSQLTransaction.Log(EventType: TDBEventType; const Msg: String);
  1580. Var
  1581. M : String;
  1582. begin
  1583. If LogEvent(EventType) then
  1584. begin
  1585. If (Name<>'') then
  1586. M:=Name+' : '+Msg
  1587. else
  1588. M:=Msg;
  1589. SQLConnection.Log(EventType,M);
  1590. end;
  1591. end;
  1592. Type
  1593. { TQuerySQLStatement }
  1594. TQuerySQLStatement = Class(TCustomSQLStatement)
  1595. protected
  1596. FQuery : TCustomSQLQuery;
  1597. Function CreateDataLink : TDataLink; override;
  1598. Function GetSchemaType : TSchemaType; override;
  1599. Function GetSchemaObjectName : String; override;
  1600. Function GetSchemaPattern: String; override;
  1601. procedure GetStatementInfo(var ASQL: String; out Info: TSQLStatementInfo); override;
  1602. procedure OnChangeSQL(Sender : TObject); override;
  1603. end;
  1604. { TQuerySQLStatement }
  1605. function TQuerySQLStatement.CreateDataLink: TDataLink;
  1606. begin
  1607. Result:=TMasterParamsDataLink.Create(FQuery);
  1608. end;
  1609. function TQuerySQLStatement.GetSchemaType: TSchemaType;
  1610. begin
  1611. if Assigned(FQuery) then
  1612. Result:=FQuery.FSchemaType
  1613. else
  1614. Result:=stNoSchema;
  1615. end;
  1616. function TQuerySQLStatement.GetSchemaObjectName: String;
  1617. begin
  1618. if Assigned(FQuery) then
  1619. Result:=FQuery.FSchemaObjectname
  1620. else
  1621. Result:=inherited GetSchemaObjectName;
  1622. end;
  1623. function TQuerySQLStatement.GetSchemaPattern: String;
  1624. begin
  1625. if Assigned(FQuery) then
  1626. Result:=FQuery.FSchemaPattern
  1627. else
  1628. Result:=inherited GetSchemaPattern;
  1629. end;
  1630. procedure TQuerySQLStatement.GetStatementInfo(var ASQL: String; out Info: TSQLStatementInfo);
  1631. begin
  1632. inherited GetStatementInfo(ASQL, Info);
  1633. If Assigned(FQuery) then
  1634. // Note: practical side effect of switch off ParseSQL is that UpdateServerIndexDefs is bypassed
  1635. // which is used as performance tuning option
  1636. if (FQuery.FSchemaType = stNoSchema) and FParseSQL then
  1637. begin
  1638. FQuery.FUpdateable:=Info.Updateable;
  1639. FQuery.FTableName:=Info.TableName;
  1640. FQuery.FWhereStartPos:=Info.WhereStartPos;
  1641. FQuery.FWhereStopPos:=Info.WhereStopPos;
  1642. if FQuery.ServerFiltered then
  1643. ASQL:=FQuery.AddFilter(ASQL);
  1644. end
  1645. else
  1646. begin
  1647. FQuery.FUpdateable:=false;
  1648. FQuery.FTableName:='';
  1649. FQuery.FWhereStartPos:=0;
  1650. FQuery.FWhereStopPos:=0;
  1651. end;
  1652. end;
  1653. procedure TQuerySQLStatement.OnChangeSQL(Sender: TObject);
  1654. begin
  1655. UnPrepare;
  1656. inherited OnChangeSQL(Sender);
  1657. If ParamCheck and Assigned(FDataLink) then
  1658. (FDataLink as TMasterParamsDataLink).RefreshParamNames;
  1659. FQuery.ServerIndexDefs.Updated:=false;
  1660. end;
  1661. { TCustomSQLQuery }
  1662. constructor TCustomSQLQuery.Create(AOwner : TComponent);
  1663. Var
  1664. F : TQuerySQLStatement;
  1665. begin
  1666. inherited Create(AOwner);
  1667. F:=TQuerySQLStatement.Create(Self);
  1668. F.FQuery:=Self;
  1669. FStatement:=F;
  1670. FUpdateSQL := TStringList.Create;
  1671. FUpdateSQL.OnChange := @OnChangeModifySQL;
  1672. FInsertSQL := TStringList.Create;
  1673. FInsertSQL.OnChange := @OnChangeModifySQL;
  1674. FDeleteSQL := TStringList.Create;
  1675. FDeleteSQL.OnChange := @OnChangeModifySQL;
  1676. FServerIndexDefs := TServerIndexDefs.Create(Self);
  1677. FServerFiltered := False;
  1678. FServerFilterText := '';
  1679. FSchemaType:=stNoSchema;
  1680. FSchemaObjectName:='';
  1681. FSchemaPattern:='';
  1682. // Delphi has upWhereAll as default, but since strings and oldvalue's don't work yet
  1683. // (variants) set it to upWhereKeyOnly
  1684. FUpdateMode := upWhereKeyOnly;
  1685. FUsePrimaryKeyAsKey := True;
  1686. end;
  1687. destructor TCustomSQLQuery.Destroy;
  1688. begin
  1689. if Active then Close;
  1690. UnPrepare;
  1691. FreeAndNil(FStatement);
  1692. FreeAndNil(FInsertSQL);
  1693. FreeAndNil(FDeleteSQL);
  1694. FreeAndNil(FUpdateSQL);
  1695. FServerIndexDefs.Free;
  1696. inherited Destroy;
  1697. end;
  1698. function TCustomSQLQuery.ParamByName(const AParamName: String): TParam;
  1699. begin
  1700. Result:=Params.ParamByName(AParamName);
  1701. end;
  1702. procedure TCustomSQLQuery.OnChangeModifySQL(Sender : TObject);
  1703. begin
  1704. CheckInactive;
  1705. end;
  1706. procedure TCustomSQLQuery.SetTransaction(Value: TDBTransaction);
  1707. begin
  1708. UnPrepare;
  1709. inherited;
  1710. If Assigned(FStatement) then
  1711. FStatement.Transaction:=TSQLTransaction(Value);
  1712. If (Transaction<>Nil) and (Database=Nil) then
  1713. Database:=SQLTransaction.Database;
  1714. end;
  1715. procedure TCustomSQLQuery.SetDatabase(Value : TDatabase);
  1716. var db : tsqlconnection;
  1717. begin
  1718. if (Database <> Value) then
  1719. begin
  1720. if assigned(value) and not (Value is TSQLConnection) then
  1721. DatabaseErrorFmt(SErrNotASQLConnection,[value.Name],self);
  1722. UnPrepare;
  1723. db := TSQLConnection(Value);
  1724. If Assigned(FStatement) then
  1725. FStatement.Database:=DB;
  1726. inherited setdatabase(value);
  1727. if assigned(value) and (Transaction = nil) and (Assigned(db.Transaction)) then
  1728. transaction := Db.Transaction;
  1729. end;
  1730. end;
  1731. function TCustomSQLQuery.IsPrepared: Boolean;
  1732. begin
  1733. if Assigned(Fstatement) then
  1734. Result := FStatement.Prepared
  1735. else
  1736. Result := False;
  1737. end;
  1738. function TCustomSQLQuery.AddFilter(SQLstr: string): string;
  1739. begin
  1740. if (FWhereStartPos > 0) and (FWhereStopPos > 0) then
  1741. begin
  1742. system.insert('(',SQLstr,FWhereStartPos+1);
  1743. system.insert(')',SQLstr,FWhereStopPos+1);
  1744. end;
  1745. if FWhereStartPos = 0 then
  1746. SQLstr := SQLstr + ' where (' + ServerFilter + ')'
  1747. else if FWhereStopPos > 0 then
  1748. system.insert(' and ('+ServerFilter+') ',SQLstr,FWhereStopPos+2)
  1749. else
  1750. system.insert(' where ('+ServerFilter+') ',SQLstr,FWhereStartPos);
  1751. Result := SQLstr;
  1752. end;
  1753. procedure TCustomSQLQuery.ApplyFilter;
  1754. begin
  1755. FreeFldBuffers;
  1756. FStatement.Unprepare;
  1757. FIsEOF := False;
  1758. inherited InternalClose;
  1759. FStatement.DoPrepare;
  1760. FStatement.DoExecute;
  1761. inherited InternalOpen;
  1762. First;
  1763. end;
  1764. procedure TCustomSQLQuery.SetActive(Value: Boolean);
  1765. begin
  1766. inherited SetActive(Value);
  1767. // The query is UnPrepared, so that if a transaction closes all datasets
  1768. // they also get unprepared
  1769. if not Value and IsPrepared then UnPrepare;
  1770. end;
  1771. procedure TCustomSQLQuery.SetServerFiltered(Value: Boolean);
  1772. begin
  1773. if Value and not ParseSQL then
  1774. DatabaseErrorFmt(SNoParseSQL,['Filtering ']);
  1775. if (ServerFiltered <> Value) then
  1776. begin
  1777. FServerFiltered := Value;
  1778. if Active then ApplyFilter;
  1779. end;
  1780. end;
  1781. procedure TCustomSQLQuery.SetServerFilterText(const Value: string);
  1782. begin
  1783. if Value <> ServerFilter then
  1784. begin
  1785. FServerFilterText := Value;
  1786. if Active then ApplyFilter;
  1787. end;
  1788. end;
  1789. procedure TCustomSQLQuery.Prepare;
  1790. begin
  1791. FStatement.Prepare;
  1792. if Assigned(FStatement.FCursor) then
  1793. with FStatement.FCursor do
  1794. FInitFieldDef := FSelectable;
  1795. end;
  1796. procedure TCustomSQLQuery.UnPrepare;
  1797. begin
  1798. CheckInactive;
  1799. If Assigned(FStatement) then
  1800. FStatement.Unprepare;
  1801. end;
  1802. procedure TCustomSQLQuery.FreeFldBuffers;
  1803. begin
  1804. if assigned(Cursor) then
  1805. SQLConnection.FreeFldBuffers(Cursor);
  1806. end;
  1807. function TCustomSQLQuery.GetParamCheck: Boolean;
  1808. begin
  1809. Result:=FStatement.ParamCheck;
  1810. end;
  1811. function TCustomSQLQuery.GetParams: TParams;
  1812. begin
  1813. Result:=FStatement.Params;
  1814. end;
  1815. function TCustomSQLQuery.GetParseSQL: Boolean;
  1816. begin
  1817. Result:=FStatement.ParseSQL;
  1818. end;
  1819. function TCustomSQLQuery.GetServerIndexDefs: TServerIndexDefs;
  1820. begin
  1821. Result := FServerIndexDefs;
  1822. end;
  1823. function TCustomSQLQuery.GetSQL: TStringlist;
  1824. begin
  1825. Result:=TStringList(Fstatement.SQL);
  1826. end;
  1827. function TCustomSQLQuery.GetSQLConnection: TSQLConnection;
  1828. begin
  1829. Result:=Database as TSQLConnection;
  1830. end;
  1831. function TCustomSQLQuery.GetSQLTransaction: TSQLTransaction;
  1832. begin
  1833. Result:=Transaction as TSQLTransaction;
  1834. end;
  1835. function TCustomSQLQuery.Cursor: TSQLCursor;
  1836. begin
  1837. Result:=FStatement.Cursor;
  1838. end;
  1839. function TCustomSQLQuery.Fetch : boolean;
  1840. begin
  1841. if Not Assigned(Cursor) then
  1842. Exit;
  1843. if not Cursor.FSelectable then
  1844. Exit;
  1845. If LogEvent(detFetch) then
  1846. Log(detFetch,FSQLBuf);
  1847. if not FIsEof then FIsEOF := not SQLConnection.Fetch(Cursor);
  1848. Result := not FIsEOF;
  1849. end;
  1850. procedure TCustomSQLQuery.Execute;
  1851. begin
  1852. FStatement.Execute;
  1853. end;
  1854. function TCustomSQLQuery.RowsAffected: TRowsCount;
  1855. begin
  1856. Result:=Fstatement.RowsAffected;
  1857. end;
  1858. function TCustomSQLQuery.LoadField(FieldDef : TFieldDef;buffer : pointer; out CreateBlob : boolean) : boolean;
  1859. begin
  1860. result := SQLConnection.LoadField(Cursor,FieldDef,buffer, Createblob)
  1861. end;
  1862. procedure TCustomSQLQuery.LoadBlobIntoBuffer(FieldDef: TFieldDef;
  1863. ABlobBuf: PBufBlobField);
  1864. begin
  1865. SQLConnection.LoadBlobIntoBuffer(FieldDef, ABlobBuf, Cursor,SQLTransaction);
  1866. end;
  1867. procedure TCustomSQLQuery.InternalAddRecord(Buffer: Pointer; AAppend: Boolean);
  1868. begin
  1869. // not implemented - sql dataset
  1870. end;
  1871. procedure TCustomSQLQuery.InternalClose;
  1872. begin
  1873. if assigned(Cursor) then
  1874. begin
  1875. if Cursor.FSelectable then
  1876. FreeFldBuffers;
  1877. // Some SQLConnections does not support statement [un]preparation,
  1878. // so let them do cleanup f.e. cancel pending queries and/or free resultset
  1879. if not Prepared then FStatement.DoUnprepare;
  1880. end;
  1881. if DefaultFields then
  1882. DestroyFields;
  1883. FIsEOF := False;
  1884. if assigned(FUpdateQry) then FreeAndNil(FUpdateQry);
  1885. if assigned(FInsertQry) then FreeAndNil(FInsertQry);
  1886. if assigned(FDeleteQry) then FreeAndNil(FDeleteQry);
  1887. // FRecordSize := 0;
  1888. inherited InternalClose;
  1889. end;
  1890. procedure TCustomSQLQuery.InternalInitFieldDefs;
  1891. begin
  1892. if FLoadingFieldDefs then
  1893. Exit;
  1894. FLoadingFieldDefs := True;
  1895. try
  1896. FieldDefs.Clear;
  1897. Prepare;
  1898. SQLConnection.AddFieldDefs(Cursor,FieldDefs);
  1899. finally
  1900. FLoadingFieldDefs := False;
  1901. if assigned(Cursor) then Cursor.FInitFieldDef := False;
  1902. end;
  1903. end;
  1904. procedure TCustomSQLQuery.InternalOpen;
  1905. var counter, fieldc : integer;
  1906. F : TField;
  1907. IndexFields : TStrings;
  1908. begin
  1909. if IsReadFromPacket then
  1910. begin
  1911. // When we read from file there is no need for Cursor, also note that Database may not be assigned
  1912. //FStatement.AllocateCursor;
  1913. //Cursor.FSelectable:=True;
  1914. //Cursor.FStatementType:=stSelect;
  1915. FUpdateable:=True;
  1916. BindFields(True);
  1917. end
  1918. else
  1919. begin
  1920. Prepare;
  1921. if not Cursor.FSelectable then
  1922. DatabaseError(SErrNoSelectStatement,Self);
  1923. // Call UpdateServerIndexDefs before Execute, to avoid problems with connections
  1924. // which do not allow processing multiple recordsets at a time. (Microsoft
  1925. // calls this MARS, see bug 13241)
  1926. if DefaultFields and FUpdateable and FusePrimaryKeyAsKey and (not IsUniDirectional) then
  1927. UpdateServerIndexDefs;
  1928. Execute;
  1929. if not Cursor.FSelectable then
  1930. DatabaseError(SErrNoSelectStatement,Self);
  1931. // InternalInitFieldDef is only called after a prepare. i.e. not twice if
  1932. // a dataset is opened - closed - opened.
  1933. if Cursor.FInitFieldDef then InternalInitFieldDefs;
  1934. if DefaultFields then
  1935. begin
  1936. CreateFields;
  1937. if FUpdateable and (not IsUniDirectional) then
  1938. begin
  1939. if FusePrimaryKeyAsKey then
  1940. begin
  1941. for counter := 0 to ServerIndexDefs.count-1 do
  1942. begin
  1943. if ixPrimary in ServerIndexDefs[counter].options then
  1944. begin
  1945. IndexFields := TStringList.Create;
  1946. ExtractStrings([';'],[' '],pchar(ServerIndexDefs[counter].fields),IndexFields);
  1947. for fieldc := 0 to IndexFields.Count-1 do
  1948. begin
  1949. F := FindField(IndexFields[fieldc]);
  1950. if F <> nil then
  1951. F.ProviderFlags := F.ProviderFlags + [pfInKey];
  1952. end;
  1953. IndexFields.Free;
  1954. end;
  1955. end;
  1956. end;
  1957. end;
  1958. end
  1959. else
  1960. BindFields(True);
  1961. end;
  1962. if not ReadOnly and not FUpdateable and (FSchemaType=stNoSchema) then
  1963. begin
  1964. if (trim(FDeleteSQL.Text) <> '') or (trim(FUpdateSQL.Text) <> '') or
  1965. (trim(FInsertSQL.Text) <> '') then FUpdateable := True;
  1966. end;
  1967. inherited InternalOpen;
  1968. end;
  1969. // public part
  1970. procedure TCustomSQLQuery.ExecSQL;
  1971. begin
  1972. try
  1973. Prepare;
  1974. Execute;
  1975. finally
  1976. // Cursor has to be assigned, or else the prepare went wrong before PrepareStatment was
  1977. // called, so UnPrepareStatement shoudn't be called either
  1978. // Don't deallocate cursor; f.e. RowsAffected is requested later
  1979. if not Prepared and (assigned(Database)) and (assigned(Cursor)) then SQLConnection.UnPrepareStatement(Cursor);
  1980. end;
  1981. end;
  1982. procedure TCustomSQLQuery.SetReadOnly(AValue : Boolean);
  1983. begin
  1984. CheckInactive;
  1985. inherited SetReadOnly(AValue);
  1986. end;
  1987. procedure TCustomSQLQuery.SetParseSQL(AValue : Boolean);
  1988. begin
  1989. CheckInactive;
  1990. FStatement.ParseSQL:=AValue;
  1991. if not AValue then
  1992. FServerFiltered := False;
  1993. end;
  1994. procedure TCustomSQLQuery.SetSQL(const AValue: TStringlist);
  1995. begin
  1996. FStatement.SQL.Assign(AValue);
  1997. end;
  1998. procedure TCustomSQLQuery.SetUpdateSQL(const AValue: TStringlist);
  1999. begin
  2000. FUpdateSQL.Assign(AValue);
  2001. end;
  2002. procedure TCustomSQLQuery.SetUsePrimaryKeyAsKey(AValue : Boolean);
  2003. begin
  2004. if not Active then FusePrimaryKeyAsKey := AValue
  2005. else
  2006. begin
  2007. // Just temporary, this should be possible in the future
  2008. DatabaseError(SActiveDataset);
  2009. end;
  2010. end;
  2011. procedure TCustomSQLQuery.UpdateServerIndexDefs;
  2012. begin
  2013. FServerIndexDefs.Clear;
  2014. if assigned(DataBase) and (FTableName<>'') then
  2015. SQLConnection.UpdateIndexDefs(ServerIndexDefs,FTableName);
  2016. end;
  2017. procedure TCustomSQLQuery.ApplyRecUpdate(UpdateKind: TUpdateKind);
  2018. begin
  2019. // Moved to connection: the SQLConnection always has more information about types etc.
  2020. // than SQLQuery itself.
  2021. SQLConnection.ApplyRecupdate(Self,UpdateKind);
  2022. end;
  2023. function TCustomSQLQuery.GetCanModify: Boolean;
  2024. begin
  2025. // the test for assigned(Cursor) is needed for the case that the dataset isn't opened
  2026. if assigned(Cursor) and (Cursor.FStatementType = stSelect) then
  2027. Result:= FUpdateable and (not ReadOnly) and (not IsUniDirectional)
  2028. else
  2029. Result := False;
  2030. end;
  2031. procedure TCustomSQLQuery.SetUpdateMode(AValue : TUpdateMode);
  2032. begin
  2033. FUpdateMode := AValue;
  2034. end;
  2035. procedure TCustomSQLQuery.SetSchemaInfo( ASchemaType : TSchemaType; ASchemaObjectName, ASchemaPattern : string);
  2036. begin
  2037. FSchemaType:=ASchemaType;
  2038. FSchemaObjectName:=ASchemaObjectName;
  2039. FSchemaPattern:=ASchemaPattern;
  2040. end;
  2041. procedure TCustomSQLQuery.BeforeRefreshOpenCursor;
  2042. begin
  2043. // This is only necessary because TIBConnection can not re-open a
  2044. // prepared cursor. In fact this is wrong, but has never led to
  2045. // problems because in SetActive(false) queries are always
  2046. // unprepared. (which is also wrong, but has to be fixed later)
  2047. if IsPrepared then with SQLConnection do
  2048. UnPrepareStatement(Cursor);
  2049. end;
  2050. function TCustomSQLQuery.LogEvent(EventType: TDBEventType): Boolean;
  2051. begin
  2052. Result:=Assigned(Database) and SQLConnection.LogEvent(EventType);
  2053. end;
  2054. procedure TCustomSQLQuery.Log(EventType: TDBEventType; const Msg: String);
  2055. Var
  2056. M : String;
  2057. begin
  2058. If LogEvent(EventType) then
  2059. begin
  2060. M:=Msg;
  2061. If (Name<>'') then
  2062. M:=Name+' : '+M;
  2063. SQLConnection.Log(EventType,M);
  2064. end;
  2065. end;
  2066. class function TCustomSQLQuery.FieldDefsClass: TFieldDefsClass;
  2067. begin
  2068. Result:=TSQLDBFieldDefs;
  2069. end;
  2070. function TCustomSQLQuery.GetStatementType : TStatementType;
  2071. begin
  2072. if Assigned(Cursor) then
  2073. Result:=Cursor.FStatementType
  2074. else
  2075. Result:=stUnknown;
  2076. end;
  2077. procedure TCustomSQLQuery.SetParamCheck(AValue: Boolean);
  2078. begin
  2079. FStatement.ParamCheck:=AValue;
  2080. end;
  2081. procedure TCustomSQLQuery.SetSQLConnection(AValue: TSQLConnection);
  2082. begin
  2083. Database:=AValue;
  2084. end;
  2085. procedure TCustomSQLQuery.SetSQLTransaction(AValue: TSQLTransaction);
  2086. begin
  2087. Transaction:=AValue;
  2088. end;
  2089. procedure TCustomSQLQuery.SetDeleteSQL(const AValue: TStringlist);
  2090. begin
  2091. FDeleteSQL.Assign(AValue);
  2092. end;
  2093. procedure TCustomSQLQuery.SetInsertSQL(const AValue: TStringlist);
  2094. begin
  2095. FInsertSQL.Assign(AValue);
  2096. end;
  2097. procedure TCustomSQLQuery.SetParams(AValue: TParams);
  2098. begin
  2099. FStatement.Params.Assign(AValue);
  2100. end;
  2101. procedure TCustomSQLQuery.SetDataSource(AValue: TDataSource);
  2102. Var
  2103. DS : TDataSource;
  2104. begin
  2105. DS:=DataSource;
  2106. If (AValue<>DS) then
  2107. begin
  2108. If Assigned(AValue) and (AValue.Dataset=Self) then
  2109. DatabaseError(SErrCircularDataSourceReferenceNotAllowed,Self);
  2110. If Assigned(DS) then
  2111. DS.RemoveFreeNotification(Self);
  2112. FStatement.DataSource:=AValue;
  2113. end;
  2114. end;
  2115. function TCustomSQLQuery.GetDataSource: TDataSource;
  2116. begin
  2117. If Assigned(FStatement) then
  2118. Result:=FStatement.DataSource
  2119. else
  2120. Result:=Nil;
  2121. end;
  2122. procedure TCustomSQLQuery.Notification(AComponent: TComponent; Operation: TOperation);
  2123. begin
  2124. Inherited;
  2125. If (Operation=opRemove) and (AComponent=DataSource) then
  2126. DataSource:=Nil;
  2127. end;
  2128. function TCustomSQLQuery.PSGetUpdateException(E: Exception; Prev: EUpdateError): EUpdateError;
  2129. var
  2130. PrevErrorCode, ErrorCode: Integer;
  2131. begin
  2132. if Assigned(Prev) then
  2133. PrevErrorCode := Prev.ErrorCode
  2134. else
  2135. PrevErrorCode := 0;
  2136. if E is ESQLDatabaseError then
  2137. ErrorCode := ESQLDatabaseError(E).ErrorCode
  2138. else
  2139. ErrorCode := 0;
  2140. Result := EUpdateError.Create(SOnUpdateError, E.Message, ErrorCode, PrevErrorCode, E);
  2141. end;
  2142. function TCustomSQLQuery.PSGetTableName: string;
  2143. begin
  2144. Result := FTableName;
  2145. end;
  2146. { TSQLScript }
  2147. procedure TSQLScript.ExecuteStatement(SQLStatement: TStrings;
  2148. var StopExecution: Boolean);
  2149. begin
  2150. fquery.SQL.assign(SQLStatement);
  2151. fquery.ExecSQL;
  2152. end;
  2153. procedure TSQLScript.ExecuteDirective(Directive, Argument: String;
  2154. var StopExecution: Boolean);
  2155. begin
  2156. if assigned (FOnDirective) then
  2157. FOnDirective (Self, Directive, Argument, StopExecution);
  2158. end;
  2159. procedure TSQLScript.ExecuteCommit(CommitRetaining: boolean=true);
  2160. begin
  2161. if FTransaction is TSQLTransaction then
  2162. if CommitRetaining then
  2163. TSQLTransaction(FTransaction).CommitRetaining
  2164. else
  2165. begin
  2166. TSQLTransaction(FTransaction).Commit;
  2167. TSQLTransaction(FTransaction).StartTransaction;
  2168. end
  2169. else
  2170. begin
  2171. FTransaction.Active := false;
  2172. FTransaction.Active := true;
  2173. end;
  2174. end;
  2175. procedure TSQLScript.SetDatabase(Value: TDatabase);
  2176. begin
  2177. FDatabase := Value;
  2178. end;
  2179. procedure TSQLScript.SetTransaction(Value: TDBTransaction);
  2180. begin
  2181. FTransaction := Value;
  2182. end;
  2183. procedure TSQLScript.CheckDatabase;
  2184. begin
  2185. If (FDatabase=Nil) then
  2186. DatabaseError(SErrNoDatabaseAvailable,Self)
  2187. end;
  2188. constructor TSQLScript.Create(AOwner: TComponent);
  2189. begin
  2190. inherited Create(AOwner);
  2191. FQuery := TCustomSQLQuery.Create(nil);
  2192. FQuery.ParamCheck := false; // Do not parse for parameters; breaks use of e.g. select bla into :bla in Firebird procedures
  2193. end;
  2194. destructor TSQLScript.Destroy;
  2195. begin
  2196. FQuery.Free;
  2197. inherited Destroy;
  2198. end;
  2199. procedure TSQLScript.Execute;
  2200. begin
  2201. FQuery.DataBase := FDatabase;
  2202. FQuery.Transaction := FTransaction;
  2203. inherited Execute;
  2204. end;
  2205. procedure TSQLScript.ExecuteScript;
  2206. begin
  2207. Execute;
  2208. end;
  2209. { Connection definitions }
  2210. Var
  2211. ConnDefs : TStringList;
  2212. Procedure CheckDefs;
  2213. begin
  2214. If (ConnDefs=Nil) then
  2215. begin
  2216. ConnDefs:=TStringList.Create;
  2217. ConnDefs.Sorted:=True;
  2218. ConnDefs.Duplicates:=dupError;
  2219. end;
  2220. end;
  2221. Procedure DoneDefs;
  2222. Var
  2223. I : Integer;
  2224. begin
  2225. If Assigned(ConnDefs) then
  2226. begin
  2227. For I:=ConnDefs.Count-1 downto 0 do
  2228. begin
  2229. ConnDefs.Objects[i].Free;
  2230. ConnDefs.Delete(I);
  2231. end;
  2232. FreeAndNil(ConnDefs);
  2233. end;
  2234. end;
  2235. Function GetConnectionDef(ConnectorName : String) : TConnectionDef;
  2236. Var
  2237. I : Integer;
  2238. begin
  2239. CheckDefs;
  2240. I:=ConnDefs.IndexOf(ConnectorName);
  2241. If (I<>-1) then
  2242. Result:=TConnectionDef(ConnDefs.Objects[i])
  2243. else
  2244. Result:=Nil;
  2245. end;
  2246. procedure RegisterConnection(Def: TConnectionDefClass);
  2247. Var
  2248. I : Integer;
  2249. begin
  2250. CheckDefs;
  2251. I:=ConnDefs.IndexOf(Def.TypeName);
  2252. If (I=-1) then
  2253. ConnDefs.AddObject(Def.TypeName,Def.Create)
  2254. else
  2255. begin
  2256. ConnDefs.Objects[I].Free;
  2257. ConnDefs.Objects[I]:=Def.Create;
  2258. end;
  2259. end;
  2260. procedure UnRegisterConnection(Def: TConnectionDefClass);
  2261. begin
  2262. UnRegisterConnection(Def.TypeName);
  2263. end;
  2264. procedure UnRegisterConnection(ConnectionName: String);
  2265. Var
  2266. I : Integer;
  2267. begin
  2268. if (ConnDefs<>Nil) then
  2269. begin
  2270. I:=ConnDefs.IndexOf(ConnectionName);
  2271. If (I<>-1) then
  2272. begin
  2273. ConnDefs.Objects[I].Free;
  2274. ConnDefs.Delete(I);
  2275. end;
  2276. end;
  2277. end;
  2278. procedure GetConnectionList(List: TSTrings);
  2279. begin
  2280. CheckDefs;
  2281. List.Text:=ConnDefs.Text;
  2282. end;
  2283. { TSQLConnector }
  2284. procedure TSQLConnector.SetConnectorType(const AValue: String);
  2285. begin
  2286. if FConnectorType<>AValue then
  2287. begin
  2288. CheckDisconnected;
  2289. If Assigned(FProxy) then
  2290. FreeProxy;
  2291. FConnectorType:=AValue;
  2292. end;
  2293. end;
  2294. procedure TSQLConnector.SetTransaction(Value: TSQLTransaction);
  2295. begin
  2296. inherited SetTransaction(Value);
  2297. If Assigned(FProxy) and (FProxy.Transaction<>Value) then
  2298. FProxy.FTransaction:=Value;
  2299. end;
  2300. procedure TSQLConnector.DoInternalConnect;
  2301. Var
  2302. D : TConnectionDef;
  2303. begin
  2304. inherited DoInternalConnect;
  2305. CreateProxy;
  2306. FProxy.CharSet:=Self.CharSet;
  2307. FProxy.DatabaseName:=Self.DatabaseName;
  2308. FProxy.HostName:=Self.HostName;
  2309. FProxy.LogEvents:=Self.LogEvents;
  2310. FProxy.Password:=Self.Password;
  2311. FProxy.Role:=Self.Role;
  2312. FProxy.UserName:=Self.UserName;
  2313. FProxy.FTransaction:=Self.Transaction;
  2314. D:=GetConnectionDef(ConnectorType);
  2315. D.ApplyParams(Params,FProxy);
  2316. FProxy.Connected:=True;
  2317. end;
  2318. procedure TSQLConnector.DoInternalDisconnect;
  2319. begin
  2320. FProxy.Connected:=False;
  2321. inherited DoInternalDisconnect;
  2322. end;
  2323. procedure TSQLConnector.CheckProxy;
  2324. begin
  2325. If (FProxy=Nil) then
  2326. CreateProxy;
  2327. end;
  2328. procedure TSQLConnector.CreateProxy;
  2329. Var
  2330. D : TConnectionDef;
  2331. begin
  2332. D:=GetConnectionDef(ConnectorType);
  2333. If (D=Nil) then
  2334. DatabaseErrorFmt(SErrUnknownConnectorType,[ConnectorType],Self);
  2335. FProxy:=D.ConnectionClass.Create(Self);
  2336. FFieldNameQuoteChars := FProxy.FieldNameQuoteChars;
  2337. end;
  2338. procedure TSQLConnector.FreeProxy;
  2339. begin
  2340. FProxy.Connected:=False;
  2341. FreeAndNil(FProxy);
  2342. end;
  2343. function TSQLConnector.StrToStatementType(s: string): TStatementType;
  2344. begin
  2345. CheckProxy;
  2346. Result:=FProxy.StrToStatementType(s);
  2347. end;
  2348. function TSQLConnector.GetAsSQLText(Field: TField): string;
  2349. begin
  2350. CheckProxy;
  2351. Result:=FProxy.GetAsSQLText(Field);
  2352. end;
  2353. function TSQLConnector.GetAsSQLText(Param: TParam): string;
  2354. begin
  2355. CheckProxy;
  2356. Result:=FProxy.GetAsSQLText(Param);
  2357. end;
  2358. function TSQLConnector.GetHandle: pointer;
  2359. begin
  2360. CheckProxy;
  2361. Result:=FProxy.GetHandle;
  2362. end;
  2363. function TSQLConnector.AllocateCursorHandle: TSQLCursor;
  2364. begin
  2365. CheckProxy;
  2366. Result:=FProxy.AllocateCursorHandle;
  2367. end;
  2368. procedure TSQLConnector.DeAllocateCursorHandle(var cursor: TSQLCursor);
  2369. begin
  2370. CheckProxy;
  2371. FProxy.DeAllocateCursorHandle(cursor);
  2372. end;
  2373. function TSQLConnector.AllocateTransactionHandle: TSQLHandle;
  2374. begin
  2375. CheckProxy;
  2376. Result:=FProxy.AllocateTransactionHandle;
  2377. end;
  2378. procedure TSQLConnector.PrepareStatement(cursor: TSQLCursor;
  2379. ATransaction: TSQLTransaction; buf: string; AParams: TParams);
  2380. begin
  2381. CheckProxy;
  2382. FProxy.PrepareStatement(cursor, ATransaction, buf, AParams);
  2383. end;
  2384. procedure TSQLConnector.Execute(cursor: TSQLCursor;
  2385. atransaction: tSQLtransaction; AParams: TParams);
  2386. begin
  2387. CheckProxy;
  2388. FProxy.Execute(cursor, atransaction, AParams);
  2389. end;
  2390. function TSQLConnector.Fetch(cursor: TSQLCursor): boolean;
  2391. begin
  2392. CheckProxy;
  2393. Result:=FProxy.Fetch(cursor);
  2394. end;
  2395. procedure TSQLConnector.AddFieldDefs(cursor: TSQLCursor; FieldDefs: TfieldDefs
  2396. );
  2397. begin
  2398. CheckProxy;
  2399. FProxy.AddFieldDefs(cursor, FieldDefs);
  2400. end;
  2401. procedure TSQLConnector.UnPrepareStatement(cursor: TSQLCursor);
  2402. begin
  2403. CheckProxy;
  2404. FProxy.UnPrepareStatement(cursor);
  2405. end;
  2406. procedure TSQLConnector.FreeFldBuffers(cursor: TSQLCursor);
  2407. begin
  2408. CheckProxy;
  2409. FProxy.FreeFldBuffers(cursor);
  2410. end;
  2411. function TSQLConnector.LoadField(cursor: TSQLCursor; FieldDef: TfieldDef;
  2412. buffer: pointer; out CreateBlob: boolean): boolean;
  2413. begin
  2414. CheckProxy;
  2415. Result:=FProxy.LoadField(cursor, FieldDef, buffer, CreateBlob);
  2416. end;
  2417. procedure TSQLConnector.LoadBlobIntoBuffer(FieldDef: TFieldDef;
  2418. ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction);
  2419. begin
  2420. CheckProxy;
  2421. FProxy.LoadBlobIntoBuffer(FieldDef, ABlobBuf, cursor, ATransaction);
  2422. end;
  2423. function TSQLConnector.RowsAffected(cursor: TSQLCursor): TRowsCount;
  2424. begin
  2425. CheckProxy;
  2426. Result := FProxy.RowsAffected(cursor);
  2427. end;
  2428. function TSQLConnector.GetTransactionHandle(trans: TSQLHandle): pointer;
  2429. begin
  2430. CheckProxy;
  2431. Result:=FProxy.GetTransactionHandle(trans);
  2432. end;
  2433. function TSQLConnector.Commit(trans: TSQLHandle): boolean;
  2434. begin
  2435. CheckProxy;
  2436. Result:=FProxy.Commit(trans);
  2437. end;
  2438. function TSQLConnector.RollBack(trans: TSQLHandle): boolean;
  2439. begin
  2440. CheckProxy;
  2441. Result:=FProxy.RollBack(trans);
  2442. end;
  2443. function TSQLConnector.StartdbTransaction(trans: TSQLHandle; aParams: string
  2444. ): boolean;
  2445. begin
  2446. CheckProxy;
  2447. Result:=FProxy.StartdbTransaction(trans, aParams);
  2448. end;
  2449. procedure TSQLConnector.CommitRetaining(trans: TSQLHandle);
  2450. begin
  2451. CheckProxy;
  2452. FProxy.CommitRetaining(trans);
  2453. end;
  2454. procedure TSQLConnector.RollBackRetaining(trans: TSQLHandle);
  2455. begin
  2456. CheckProxy;
  2457. FProxy.RollBackRetaining(trans);
  2458. end;
  2459. procedure TSQLConnector.UpdateIndexDefs(IndexDefs: TIndexDefs;
  2460. TableName: string);
  2461. begin
  2462. CheckProxy;
  2463. FProxy.UpdateIndexDefs(IndexDefs, TableName);
  2464. end;
  2465. function TSQLConnector.GetSchemaInfoSQL(SchemaType: TSchemaType;
  2466. SchemaObjectName, SchemaPattern: string): string;
  2467. begin
  2468. CheckProxy;
  2469. Result:=FProxy.GetSchemaInfoSQL(SchemaType, SchemaObjectName, SchemaPattern);
  2470. end;
  2471. { TConnectionDef }
  2472. class function TConnectionDef.TypeName: String;
  2473. begin
  2474. Result:='';
  2475. end;
  2476. class function TConnectionDef.ConnectionClass: TSQLConnectionClass;
  2477. begin
  2478. Result:=Nil;
  2479. end;
  2480. class function TConnectionDef.Description: String;
  2481. begin
  2482. Result:='';
  2483. end;
  2484. class function TConnectionDef.DefaultLibraryName: String;
  2485. begin
  2486. Result:='';
  2487. end;
  2488. class function TConnectionDef.LoadFunction: TLibraryLoadFunction;
  2489. begin
  2490. Result:=Nil;
  2491. end;
  2492. class function TConnectionDef.UnLoadFunction: TLibraryUnLoadFunction;
  2493. begin
  2494. Result:=Nil;
  2495. end;
  2496. class function TConnectionDef.LoadedLibraryName: string;
  2497. begin
  2498. Result:='';
  2499. end;
  2500. procedure TConnectionDef.ApplyParams(Params: TStrings;
  2501. AConnection: TSQLConnection);
  2502. begin
  2503. AConnection.Params.Assign(Params);
  2504. end;
  2505. { TServerIndexDefs }
  2506. constructor TServerIndexDefs.create(ADataset: TDataset);
  2507. begin
  2508. if not (ADataset is TCustomSQLQuery) then
  2509. DatabaseErrorFmt(SErrNotASQLQuery,[ADataset.Name]);
  2510. inherited create(ADataset);
  2511. end;
  2512. procedure TServerIndexDefs.Update;
  2513. begin
  2514. if (not updated) and assigned(Dataset) then
  2515. begin
  2516. TCustomSQLQuery(Dataset).UpdateServerIndexDefs;
  2517. updated := True;
  2518. end;
  2519. end;
  2520. Initialization
  2521. Finalization
  2522. DoneDefs;
  2523. end.