sqldb.pp 82 KB

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