sqldb.pp 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242
  1. {
  2. Copyright (c) 2004 by Joost van der Sluis
  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 TSchemaType = (stNoSchema, stTables, stSysTables, stProcedures, stColumns, stProcedureParams, stIndexes, stPackages);
  17. TConnOption = (sqSupportParams,sqEscapeSlash,sqEscapeRepeat);
  18. TConnOptions= set of TConnOption;
  19. TRowsCount = LargeInt;
  20. type
  21. TSQLConnection = class;
  22. TSQLTransaction = class;
  23. TCustomSQLQuery = class;
  24. TSQLQuery = class;
  25. TSQLScript = class;
  26. TStatementType = (stNone, stSelect, stInsert, stUpdate, stDelete,
  27. stDDL, stGetSegment, stPutSegment, stExecProcedure,
  28. stStartTrans, stCommit, stRollback, stSelectForUpd);
  29. TDBEventType = (detCustom, detPrepare, detExecute, detFetch, detCommit,detRollBack);
  30. TDBEventTypes = set of TDBEventType;
  31. TDBLogNotifyEvent = Procedure (Sender : TSQLConnection; EventType : TDBEventType; Const Msg : String) of object;
  32. TSQLHandle = Class(TObject)
  33. end;
  34. { TSQLCursor }
  35. TSQLCursor = Class(TSQLHandle)
  36. public
  37. FPrepared : Boolean;
  38. FInitFieldDef : Boolean;
  39. FStatementType : TStatementType;
  40. FSchemaType : TSchemaType;
  41. end;
  42. type TQuoteChars = array[0..1] of char;
  43. const
  44. SingleQuotes : TQuoteChars = ('''','''');
  45. DoubleQuotes : TQuoteChars = ('"','"');
  46. LogAllEvents = [detCustom, detPrepare, detExecute, detFetch, detCommit, detRollBack];
  47. StatementTokens : Array[TStatementType] of string = ('(none)', 'select',
  48. 'insert', 'update', 'delete',
  49. 'create', 'get', 'put', 'execute',
  50. 'start','commit','rollback', '?'
  51. );
  52. type
  53. { TServerIndexDefs }
  54. TServerIndexDefs = class(TIndexDefs)
  55. Private
  56. public
  57. constructor Create(ADataSet: TDataSet); override;
  58. procedure Update; override;
  59. end;
  60. type
  61. { TSQLConnection }
  62. TSQLConnection = class (TDatabase)
  63. private
  64. FFieldNameQuoteChars : TQuoteChars;
  65. FLogEvents: TDBEventTypes;
  66. FOnLog: TDBLogNotifyEvent;
  67. FPassword : string;
  68. FTransaction : TSQLTransaction;
  69. FUserName : string;
  70. FHostName : string;
  71. FCharSet : string;
  72. FRole : String;
  73. function GetPort: cardinal;
  74. procedure Setport(const AValue: cardinal);
  75. protected
  76. FConnOptions : TConnOptions;
  77. FSQLFormatSettings : TFormatSettings;
  78. procedure GetDBInfo(const ASchemaType : TSchemaType; const ASchemaObjectName, AReturnField : string; AList: TStrings);
  79. procedure SetTransaction(Value : TSQLTransaction);virtual;
  80. function StrToStatementType(s : string) : TStatementType; virtual;
  81. procedure DoInternalConnect; override;
  82. procedure DoInternalDisconnect; override;
  83. function GetAsSQLText(Field : TField) : string; overload; virtual;
  84. function GetAsSQLText(Param : TParam) : string; overload; virtual;
  85. function GetHandle : pointer; virtual; virtual;
  86. Function LogEvent(EventType : TDBEventType) : Boolean;
  87. Procedure Log(EventType : TDBEventType; Const Msg : String); virtual;
  88. Function AllocateCursorHandle : TSQLCursor; virtual; abstract;
  89. Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); virtual; abstract;
  90. Function AllocateTransactionHandle : TSQLHandle; virtual; abstract;
  91. procedure PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams); virtual; abstract;
  92. procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams); virtual; abstract;
  93. function Fetch(cursor : TSQLCursor) : boolean; virtual; abstract;
  94. procedure AddFieldDefs(cursor: TSQLCursor; FieldDefs : TfieldDefs); virtual; abstract;
  95. procedure UnPrepareStatement(cursor : TSQLCursor); virtual; abstract;
  96. procedure FreeFldBuffers(cursor : TSQLCursor); virtual;
  97. function LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; virtual; abstract;
  98. function GetTransactionHandle(trans : TSQLHandle): pointer; virtual; abstract;
  99. function Commit(trans : TSQLHandle) : boolean; virtual; abstract;
  100. function RollBack(trans : TSQLHandle) : boolean; virtual; abstract;
  101. function StartdbTransaction(trans : TSQLHandle; aParams : string) : boolean; virtual; abstract;
  102. procedure CommitRetaining(trans : TSQLHandle); virtual; abstract;
  103. procedure RollBackRetaining(trans : TSQLHandle); virtual; abstract;
  104. procedure UpdateIndexDefs(IndexDefs : TIndexDefs;TableName : string); virtual;
  105. function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; virtual;
  106. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction : TSQLTransaction); virtual; abstract;
  107. function RowsAffected(cursor: TSQLCursor): TRowsCount; virtual;
  108. property port: cardinal read GetPort write Setport;
  109. public
  110. property Handle: Pointer read GetHandle;
  111. property FieldNameQuoteChars: TQuoteChars read FFieldNameQuoteChars write FFieldNameQuoteChars;
  112. constructor Create(AOwner: TComponent); override;
  113. destructor Destroy; override;
  114. procedure StartTransaction; override;
  115. procedure EndTransaction; override;
  116. property ConnOptions: TConnOptions read FConnOptions;
  117. procedure ExecuteDirect(SQL : String); overload; virtual;
  118. procedure ExecuteDirect(SQL : String; ATransaction : TSQLTransaction); overload; virtual;
  119. procedure GetTableNames(List : TStrings; SystemTables : Boolean = false); virtual;
  120. procedure GetProcedureNames(List : TStrings); virtual;
  121. procedure GetFieldNames(const TableName : string; List : TStrings); virtual;
  122. procedure CreateDB; virtual;
  123. procedure DropDB; virtual;
  124. published
  125. property Password : string read FPassword write FPassword;
  126. property Transaction : TSQLTransaction read FTransaction write SetTransaction;
  127. property UserName : string read FUserName write FUserName;
  128. property CharSet : string read FCharSet write FCharSet;
  129. property HostName : string Read FHostName Write FHostName;
  130. Property OnLog : TDBLogNotifyEvent Read FOnLog Write FOnLog;
  131. Property LogEvents : TDBEventTypes Read FLogEvents Write FLogEvents Default LogAllEvents;
  132. property Connected;
  133. Property Role : String read FRole write FRole;
  134. property DatabaseName;
  135. property KeepConnection;
  136. property LoginPrompt;
  137. property Params;
  138. property OnLogin;
  139. end;
  140. { TSQLTransaction }
  141. TCommitRollbackAction = (caNone, caCommit, caCommitRetaining, caRollback,
  142. caRollbackRetaining);
  143. TSQLTransaction = class (TDBTransaction)
  144. private
  145. FTrans : TSQLHandle;
  146. FAction : TCommitRollbackAction;
  147. FParams : TStringList;
  148. procedure SetParams(const AValue: TStringList);
  149. protected
  150. function GetHandle : Pointer; virtual;
  151. Procedure SetDatabase (Value : TDatabase); override;
  152. Function LogEvent(EventType : TDBEventType) : Boolean;
  153. Procedure Log(EventType : TDBEventType; Const Msg : String); virtual;
  154. public
  155. procedure Commit; virtual;
  156. procedure CommitRetaining; virtual;
  157. procedure Rollback; virtual;
  158. procedure RollbackRetaining; virtual;
  159. procedure StartTransaction; override;
  160. constructor Create(AOwner : TComponent); override;
  161. destructor Destroy; override;
  162. property Handle: Pointer read GetHandle;
  163. procedure EndTransaction; override;
  164. published
  165. property Action : TCommitRollbackAction read FAction write FAction;
  166. property Database;
  167. property Params : TStringList read FParams write SetParams;
  168. end;
  169. { TCustomSQLQuery }
  170. TCustomSQLQuery = class (TCustomBufDataset)
  171. private
  172. FCursor : TSQLCursor;
  173. FUpdateable : boolean;
  174. FTableName : string;
  175. FSQL : TStringList;
  176. FUpdateSQL,
  177. FInsertSQL,
  178. FDeleteSQL : TStringList;
  179. FIsEOF : boolean;
  180. FLoadingFieldDefs : boolean;
  181. FReadOnly : boolean;
  182. FUpdateMode : TUpdateMode;
  183. FParams : TParams;
  184. FusePrimaryKeyAsKey : Boolean;
  185. FSQLBuf : String;
  186. FWhereStartPos : integer;
  187. FWhereStopPos : integer;
  188. FParseSQL : boolean;
  189. FMasterLink : TMasterParamsDatalink;
  190. // FSchemaInfo : TSchemaInfo;
  191. FServerFilterText : string;
  192. FServerFiltered : Boolean;
  193. FServerIndexDefs : TServerIndexDefs;
  194. // Used by SetSchemaType
  195. FSchemaType : TSchemaType;
  196. FSchemaObjectName : string;
  197. FSchemaPattern : string;
  198. FUpdateQry,
  199. FDeleteQry,
  200. FInsertQry : TCustomSQLQuery;
  201. procedure FreeFldBuffers;
  202. function GetServerIndexDefs: TServerIndexDefs;
  203. function GetStatementType : TStatementType;
  204. procedure SetDeleteSQL(const AValue: TStringlist);
  205. procedure SetInsertSQL(const AValue: TStringlist);
  206. procedure SetReadOnly(AValue : Boolean);
  207. procedure SetParseSQL(AValue : Boolean);
  208. procedure SetSQL(const AValue: TStringlist);
  209. procedure SetUpdateSQL(const AValue: TStringlist);
  210. procedure SetUsePrimaryKeyAsKey(AValue : Boolean);
  211. procedure SetUpdateMode(AValue : TUpdateMode);
  212. procedure OnChangeSQL(Sender : TObject);
  213. procedure OnChangeModifySQL(Sender : TObject);
  214. procedure Execute;
  215. Function SQLParser(const ASQL : string) : TStatementType;
  216. procedure ApplyFilter;
  217. Function AddFilter(SQLstr : string) : string;
  218. protected
  219. // abstract & virtual methods of TBufDataset
  220. function Fetch : boolean; override;
  221. function LoadField(FieldDef : TFieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; override;
  222. // abstract & virtual methods of TDataset
  223. procedure UpdateServerIndexDefs; virtual;
  224. procedure SetDatabase(Value : TDatabase); override;
  225. Procedure SetTransaction(Value : TDBTransaction); override;
  226. procedure InternalAddRecord(Buffer: Pointer; AAppend: Boolean); override;
  227. procedure InternalClose; override;
  228. procedure InternalInitFieldDefs; override;
  229. procedure InternalOpen; override;
  230. function GetCanModify: Boolean; override;
  231. procedure ApplyRecUpdate(UpdateKind : TUpdateKind); override;
  232. Function IsPrepared : Boolean; virtual;
  233. Procedure SetActive (Value : Boolean); override;
  234. procedure SetServerFiltered(Value: Boolean); virtual;
  235. procedure SetServerFilterText(const Value: string); virtual;
  236. Function GetDataSource : TDatasource; override;
  237. Procedure SetDataSource(AValue : TDatasource);
  238. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField); override;
  239. procedure BeforeRefreshOpenCursor; override;
  240. Function LogEvent(EventType : TDBEventType) : Boolean;
  241. Procedure Log(EventType : TDBEventType; Const Msg : String); virtual;
  242. public
  243. procedure Prepare; virtual;
  244. procedure UnPrepare; virtual;
  245. procedure ExecSQL; virtual;
  246. constructor Create(AOwner : TComponent); override;
  247. destructor Destroy; override;
  248. procedure SetSchemaInfo( ASchemaType : TSchemaType; ASchemaObjectName, ASchemaPattern : string); virtual;
  249. property Prepared : boolean read IsPrepared;
  250. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  251. function RowsAffected: TRowsCount; virtual;
  252. function ParamByName(Const AParamName : String) : TParam;
  253. protected
  254. // redeclared data set properties
  255. property Active;
  256. property Filter;
  257. property Filtered;
  258. // property FilterOptions;
  259. property BeforeOpen;
  260. property AfterOpen;
  261. property BeforeClose;
  262. property AfterClose;
  263. property BeforeInsert;
  264. property AfterInsert;
  265. property BeforeEdit;
  266. property AfterEdit;
  267. property BeforePost;
  268. property AfterPost;
  269. property BeforeCancel;
  270. property AfterCancel;
  271. property BeforeDelete;
  272. property AfterDelete;
  273. property BeforeScroll;
  274. property AfterScroll;
  275. property OnCalcFields;
  276. property OnDeleteError;
  277. property OnEditError;
  278. property OnFilterRecord;
  279. property OnNewRecord;
  280. property OnPostError;
  281. property AutoCalcFields;
  282. property Database;
  283. // protected
  284. property SchemaType : TSchemaType read FSchemaType default stNoSchema;
  285. property Transaction;
  286. property ReadOnly : Boolean read FReadOnly write SetReadOnly default false;
  287. property SQL : TStringlist read FSQL write SetSQL;
  288. property UpdateSQL : TStringlist read FUpdateSQL write SetUpdateSQL;
  289. property InsertSQL : TStringlist read FInsertSQL write SetInsertSQL;
  290. property DeleteSQL : TStringlist read FDeleteSQL write SetDeleteSQL;
  291. property Params : TParams read FParams write FParams;
  292. property UpdateMode : TUpdateMode read FUpdateMode write SetUpdateMode default upWhereKeyOnly;
  293. property UsePrimaryKeyAsKey : boolean read FUsePrimaryKeyAsKey write SetUsePrimaryKeyAsKey default true;
  294. property StatementType : TStatementType read GetStatementType;
  295. property ParseSQL : Boolean read FParseSQL write SetParseSQL default true;
  296. Property DataSource : TDatasource Read GetDataSource Write SetDatasource;
  297. property ServerFilter: string read FServerFilterText write SetServerFilterText;
  298. property ServerFiltered: Boolean read FServerFiltered write SetServerFiltered default False;
  299. property ServerIndexDefs : TServerIndexDefs read GetServerIndexDefs;
  300. end;
  301. { TSQLQuery }
  302. TSQLQuery = Class(TCustomSQLQuery)
  303. public
  304. property SchemaType;
  305. Published
  306. property MaxIndexesCount;
  307. // TDataset stuff
  308. property FieldDefs;
  309. Property Active;
  310. Property AutoCalcFields;
  311. Property Filter;
  312. Property Filtered;
  313. Property AfterCancel;
  314. Property AfterClose;
  315. Property AfterDelete;
  316. Property AfterEdit;
  317. Property AfterInsert;
  318. Property AfterOpen;
  319. Property AfterPost;
  320. Property AfterScroll;
  321. Property BeforeCancel;
  322. Property BeforeClose;
  323. Property BeforeDelete;
  324. Property BeforeEdit;
  325. Property BeforeInsert;
  326. Property BeforeOpen;
  327. Property BeforePost;
  328. Property BeforeScroll;
  329. Property OnCalcFields;
  330. Property OnDeleteError;
  331. Property OnEditError;
  332. Property OnFilterRecord;
  333. Property OnNewRecord;
  334. Property OnPostError;
  335. // property SchemaInfo default stNoSchema;
  336. property Database;
  337. property Transaction;
  338. property ReadOnly;
  339. property SQL;
  340. property UpdateSQL;
  341. property InsertSQL;
  342. property DeleteSQL;
  343. property IndexDefs;
  344. property Params;
  345. property UpdateMode;
  346. property UsePrimaryKeyAsKey;
  347. property ParseSQL;
  348. Property DataSource;
  349. property ServerFilter;
  350. property ServerFiltered;
  351. property ServerIndexDefs;
  352. end;
  353. { TSQLScript }
  354. TSQLScript = class (TCustomSQLscript)
  355. private
  356. FOnDirective: TSQLScriptDirectiveEvent;
  357. FQuery : TCustomSQLQuery;
  358. FDatabase : TDatabase;
  359. FTransaction : TDBTransaction;
  360. protected
  361. procedure ExecuteStatement (SQLStatement: TStrings; var StopExecution: Boolean); override;
  362. procedure ExecuteDirective (Directive, Argument: String; var StopExecution: Boolean); override;
  363. procedure ExecuteCommit; override;
  364. Procedure SetDatabase (Value : TDatabase); virtual;
  365. Procedure SetTransaction(Value : TDBTransaction); virtual;
  366. Procedure CheckDatabase;
  367. public
  368. constructor Create(AOwner : TComponent); override;
  369. destructor Destroy; override;
  370. procedure Execute; override;
  371. procedure ExecuteScript;
  372. published
  373. Property DataBase : TDatabase Read FDatabase Write SetDatabase;
  374. Property Transaction : TDBTransaction Read FTransaction Write SetTransaction;
  375. property OnDirective: TSQLScriptDirectiveEvent read FOnDirective write FOnDirective;
  376. property Directives;
  377. property Defines;
  378. property Script;
  379. property Terminator;
  380. property CommentsinSQL;
  381. property UseSetTerm;
  382. property UseCommit;
  383. property UseDefines;
  384. property OnException;
  385. end;
  386. { TSQLConnector }
  387. TSQLConnector = Class(TSQLConnection)
  388. private
  389. FProxy : TSQLConnection;
  390. FConnectorType: String;
  391. procedure SetConnectorType(const AValue: String);
  392. protected
  393. procedure SetTransaction(Value : TSQLTransaction);override;
  394. procedure DoInternalConnect; override;
  395. procedure DoInternalDisconnect; override;
  396. Procedure CheckProxy;
  397. Procedure CreateProxy; virtual;
  398. Procedure FreeProxy; virtual;
  399. function StrToStatementType(s : string) : TStatementType; override;
  400. function GetAsSQLText(Field : TField) : string; overload; override;
  401. function GetAsSQLText(Param : TParam) : string; overload; override;
  402. function GetHandle : pointer; override;
  403. Function AllocateCursorHandle : TSQLCursor; override;
  404. Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); override;
  405. Function AllocateTransactionHandle : TSQLHandle; override;
  406. procedure PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams); override;
  407. procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams); override;
  408. function Fetch(cursor : TSQLCursor) : boolean; override;
  409. procedure AddFieldDefs(cursor: TSQLCursor; FieldDefs : TfieldDefs); override;
  410. procedure UnPrepareStatement(cursor : TSQLCursor); override;
  411. procedure FreeFldBuffers(cursor : TSQLCursor); override;
  412. function LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; override;
  413. function RowsAffected(cursor: TSQLCursor): TRowsCount; override;
  414. function GetTransactionHandle(trans : TSQLHandle): pointer; override;
  415. function Commit(trans : TSQLHandle) : boolean; override;
  416. function RollBack(trans : TSQLHandle) : boolean; override;
  417. function StartdbTransaction(trans : TSQLHandle; aParams : string) : boolean; override;
  418. procedure CommitRetaining(trans : TSQLHandle); override;
  419. procedure RollBackRetaining(trans : TSQLHandle); override;
  420. procedure UpdateIndexDefs(IndexDefs : TIndexDefs;TableName : string); override;
  421. function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; override;
  422. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction : TSQLTransaction); override;
  423. Property Proxy : TSQLConnection Read FProxy;
  424. Published
  425. Property ConnectorType : String Read FConnectorType Write SetConnectorType;
  426. end;
  427. TSQLConnectionClass = Class of TSQLConnection;
  428. { TConnectionDef }
  429. TConnectionDef = Class(TPersistent)
  430. Class Function TypeName : String; virtual;
  431. Class Function ConnectionClass : TSQLConnectionClass; virtual;
  432. Class Function Description : String; virtual;
  433. Procedure ApplyParams(Params : TStrings; AConnection : TSQLConnection); virtual;
  434. end;
  435. TConnectionDefClass = class of TConnectionDef;
  436. Var
  437. GlobalDBLogHook : TDBLogNotifyEvent;
  438. Procedure RegisterConnection(Def : TConnectionDefClass);
  439. Procedure UnRegisterConnection(Def : TConnectionDefClass);
  440. Procedure UnRegisterConnection(ConnectionName : String);
  441. Function GetConnectionDef(ConnectorName : String) : TConnectionDef;
  442. Procedure GetConnectionList(List : TSTrings);
  443. const DefaultSQLFormatSettings : TFormatSettings = (
  444. CurrencyFormat: 1;
  445. NegCurrFormat: 5;
  446. ThousandSeparator: #0;
  447. DecimalSeparator: '.';
  448. CurrencyDecimals: 2;
  449. DateSeparator: '-';
  450. TimeSeparator: ':';
  451. ListSeparator: ' ';
  452. CurrencyString: '$';
  453. ShortDateFormat: 'yyyy-mm-dd';
  454. LongDateFormat: '';
  455. TimeAMString: '';
  456. TimePMString: '';
  457. ShortTimeFormat: 'hh:nn:ss';
  458. LongTimeFormat: 'hh:nn:ss';
  459. ShortMonthNames: ('','','','','','','','','','','','');
  460. LongMonthNames: ('','','','','','','','','','','','');
  461. ShortDayNames: ('','','','','','','');
  462. LongDayNames: ('','','','','','','');
  463. TwoDigitYearCenturyWindow: 50;
  464. );
  465. implementation
  466. uses dbconst, strutils;
  467. function TimeIntervalToString(Time: TDateTime): string;
  468. var
  469. millisecond: word;
  470. second : word;
  471. minute : word;
  472. hour : word;
  473. begin
  474. DecodeTime(Time,hour,minute,second,millisecond);
  475. hour := hour + (trunc(Time) * 24);
  476. result := Format('%.2d:%.2d:%.2d.%.3d',[hour,minute,second,millisecond]);
  477. end;
  478. { TSQLConnection }
  479. function TSQLConnection.StrToStatementType(s : string) : TStatementType;
  480. var T : TStatementType;
  481. begin
  482. S:=Lowercase(s);
  483. For t:=stselect to strollback do
  484. if (S=StatementTokens[t]) then
  485. Exit(t);
  486. end;
  487. procedure TSQLConnection.SetTransaction(Value : TSQLTransaction);
  488. begin
  489. if FTransaction<>value then
  490. begin
  491. if Assigned(FTransaction) and FTransaction.Active then
  492. DatabaseError(SErrAssTransaction);
  493. if Assigned(Value) then
  494. Value.Database := Self;
  495. FTransaction := Value;
  496. If Assigned(FTransaction) and (FTransaction.Database=Nil) then
  497. FTransaction.Database:=Self;
  498. end;
  499. end;
  500. procedure TSQLConnection.UpdateIndexDefs(IndexDefs : TIndexDefs;TableName : string);
  501. begin
  502. // Empty abstract
  503. end;
  504. procedure TSQLConnection.DoInternalConnect;
  505. begin
  506. if (DatabaseName = '') then
  507. DatabaseError(SErrNoDatabaseName,self);
  508. end;
  509. procedure TSQLConnection.DoInternalDisconnect;
  510. begin
  511. end;
  512. destructor TSQLConnection.Destroy;
  513. begin
  514. inherited Destroy;
  515. end;
  516. procedure TSQLConnection.StartTransaction;
  517. begin
  518. if not assigned(Transaction) then
  519. DatabaseError(SErrConnTransactionnSet)
  520. else
  521. Transaction.StartTransaction;
  522. end;
  523. procedure TSQLConnection.EndTransaction;
  524. begin
  525. if not assigned(Transaction) then
  526. DatabaseError(SErrConnTransactionnSet)
  527. else
  528. Transaction.EndTransaction;
  529. end;
  530. Procedure TSQLConnection.ExecuteDirect(SQL: String);
  531. begin
  532. ExecuteDirect(SQL,FTransaction);
  533. end;
  534. Procedure TSQLConnection.ExecuteDirect(SQL: String; ATransaction : TSQLTransaction);
  535. var Cursor : TSQLCursor;
  536. begin
  537. if not assigned(ATransaction) then
  538. DatabaseError(SErrTransactionnSet);
  539. if not Connected then Open;
  540. if not ATransaction.Active then ATransaction.StartTransaction;
  541. try
  542. SQL := TrimRight(SQL);
  543. if SQL = '' then
  544. DatabaseError(SErrNoStatement);
  545. Cursor := AllocateCursorHandle;
  546. Cursor.FStatementType := stNone;
  547. PrepareStatement(cursor,ATransaction,SQL,Nil);
  548. execute(cursor,ATransaction, Nil);
  549. UnPrepareStatement(Cursor);
  550. finally;
  551. DeAllocateCursorHandle(Cursor);
  552. end;
  553. end;
  554. function TSQLConnection.GetPort: cardinal;
  555. begin
  556. result := StrToIntDef(Params.Values['Port'],0);
  557. end;
  558. procedure TSQLConnection.Setport(const AValue: cardinal);
  559. begin
  560. if AValue<>0 then
  561. params.Values['Port']:=IntToStr(AValue)
  562. else with params do if IndexOfName('Port') > -1 then
  563. Delete(IndexOfName('Port'));
  564. end;
  565. procedure TSQLConnection.GetDBInfo(const ASchemaType : TSchemaType; const ASchemaObjectName, AReturnField : string; AList: TStrings);
  566. var qry : TCustomSQLQuery;
  567. begin
  568. if not assigned(Transaction) then
  569. DatabaseError(SErrConnTransactionnSet);
  570. qry := TCustomSQLQuery.Create(nil);
  571. qry.transaction := Transaction;
  572. qry.database := Self;
  573. with qry do
  574. begin
  575. ParseSQL := False;
  576. SetSchemaInfo(ASchemaType,ASchemaObjectName,'');
  577. open;
  578. AList.Clear;
  579. while not eof do
  580. begin
  581. AList.Append(trim(fieldbyname(AReturnField).asstring));
  582. Next;
  583. end;
  584. end;
  585. qry.free;
  586. end;
  587. function TSQLConnection.RowsAffected(cursor: TSQLCursor): TRowsCount;
  588. begin
  589. Result := -1;
  590. end;
  591. constructor TSQLConnection.Create(AOwner: TComponent);
  592. begin
  593. inherited Create(AOwner);
  594. FSQLFormatSettings:=DefaultSQLFormatSettings;
  595. FFieldNameQuoteChars:=DoubleQuotes;
  596. end;
  597. procedure TSQLConnection.GetTableNames(List: TStrings; SystemTables: Boolean);
  598. begin
  599. if not systemtables then GetDBInfo(stTables,'','table_name',List)
  600. else GetDBInfo(stSysTables,'','table_name',List);
  601. end;
  602. procedure TSQLConnection.GetProcedureNames(List: TStrings);
  603. begin
  604. GetDBInfo(stProcedures,'','proc_name',List);
  605. end;
  606. procedure TSQLConnection.GetFieldNames(const TableName: string; List: TStrings);
  607. begin
  608. GetDBInfo(stColumns,TableName,'column_name',List);
  609. end;
  610. function TSQLConnection.GetAsSQLText(Field : TField) : string;
  611. begin
  612. if (not assigned(field)) or field.IsNull then Result := 'Null'
  613. else case field.DataType of
  614. ftString : Result := '''' + field.asstring + '''';
  615. ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Field.AsDateTime,FSqlFormatSettings) + '''';
  616. ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:nn:ss',Field.AsDateTime,FSqlFormatSettings) + '''';
  617. ftTime : Result := QuotedStr(TimeIntervalToString(Field.AsDateTime));
  618. else
  619. Result := field.asstring;
  620. end; {case}
  621. end;
  622. function TSQLConnection.GetAsSQLText(Param: TParam) : string;
  623. begin
  624. if (not assigned(param)) or param.IsNull then Result := 'Null'
  625. else case param.DataType of
  626. ftGuid,
  627. ftMemo,
  628. ftFixedChar,
  629. ftString : Result := QuotedStr(Param.AsString);
  630. ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Param.AsDateTime,FSQLFormatSettings) + '''';
  631. ftTime : Result := QuotedStr(TimeIntervalToString(Param.AsDateTime));
  632. ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:nn:ss', Param.AsDateTime, FSQLFormatSettings) + '''';
  633. ftCurrency,
  634. ftBcd : Result := CurrToStr(Param.AsCurrency, FSQLFormatSettings);
  635. ftFloat : Result := FloatToStr(Param.AsFloat, FSQLFormatSettings);
  636. ftFMTBcd : Result := stringreplace(Param.AsString, DefaultFormatSettings.DecimalSeparator, FSQLFormatSettings.DecimalSeparator, []);
  637. else
  638. Result := Param.asstring;
  639. end; {case}
  640. end;
  641. function TSQLConnection.GetHandle: pointer;
  642. begin
  643. Result := nil;
  644. end;
  645. function TSQLConnection.LogEvent(EventType: TDBEventType): Boolean;
  646. begin
  647. Result:=(Assigned(FOnLog) or Assigned(GlobalDBLogHook)) and (EventType in LogEvents);
  648. end;
  649. procedure TSQLConnection.Log(EventType: TDBEventType; const Msg: String);
  650. Var
  651. M : String;
  652. begin
  653. If LogEvent(EventType) then
  654. begin
  655. If Assigned(FonLog) then
  656. FOnLog(Self,EventType,Msg);
  657. If Assigned(GlobalDBLogHook) then
  658. begin
  659. If (Name<>'') then
  660. M:=Name+' : '+Msg
  661. else
  662. M:=ClassName+' : '+Msg;
  663. GlobalDBLogHook(Self,EventType,M);
  664. end;
  665. end;
  666. end;
  667. procedure TSQLConnection.FreeFldBuffers(cursor: TSQLCursor);
  668. begin
  669. // empty
  670. end;
  671. function TSQLConnection.GetSchemaInfoSQL( SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string;
  672. begin
  673. DatabaseError(SMetadataUnavailable);
  674. end;
  675. procedure TSQLConnection.CreateDB;
  676. begin
  677. DatabaseError(SNotSupported);
  678. end;
  679. procedure TSQLConnection.DropDB;
  680. begin
  681. DatabaseError(SNotSupported);
  682. end;
  683. { TSQLTransaction }
  684. procedure TSQLTransaction.EndTransaction;
  685. begin
  686. rollback;
  687. end;
  688. procedure TSQLTransaction.SetParams(const AValue: TStringList);
  689. begin
  690. FParams.Assign(AValue);
  691. end;
  692. function TSQLTransaction.GetHandle: pointer;
  693. begin
  694. Result := TSQLConnection(Database).GetTransactionHandle(FTrans);
  695. end;
  696. procedure TSQLTransaction.Commit;
  697. begin
  698. if active then
  699. begin
  700. closedatasets;
  701. If LogEvent(detCommit) then
  702. Log(detCommit,SCommitting);
  703. if TSQLConnection(Database).commit(FTrans) then
  704. begin
  705. closeTrans;
  706. FreeAndNil(FTrans);
  707. end;
  708. end;
  709. end;
  710. procedure TSQLTransaction.CommitRetaining;
  711. begin
  712. if active then
  713. begin
  714. If LogEvent(detCommit) then
  715. Log(detCommit,SCommitRetaining);
  716. TSQLConnection(Database).commitRetaining(FTrans);
  717. end;
  718. end;
  719. procedure TSQLTransaction.Rollback;
  720. begin
  721. if active then
  722. begin
  723. closedatasets;
  724. If LogEvent(detRollback) then
  725. Log(detRollback,SRollingBack);
  726. if TSQLConnection(Database).RollBack(FTrans) then
  727. begin
  728. CloseTrans;
  729. FreeAndNil(FTrans);
  730. end;
  731. end;
  732. end;
  733. procedure TSQLTransaction.RollbackRetaining;
  734. begin
  735. if active then
  736. begin
  737. If LogEvent(detRollback) then
  738. Log(detRollback,SRollBackRetaining);
  739. TSQLConnection(Database).RollBackRetaining(FTrans);
  740. end;
  741. end;
  742. procedure TSQLTransaction.StartTransaction;
  743. var db : TSQLConnection;
  744. begin
  745. if Active then
  746. DatabaseError(SErrTransAlreadyActive);
  747. db := TSQLConnection(Database);
  748. if Db = nil then
  749. DatabaseError(SErrDatabasenAssigned);
  750. if not Db.Connected then
  751. Db.Open;
  752. if not assigned(FTrans) then FTrans := Db.AllocateTransactionHandle;
  753. if Db.StartdbTransaction(FTrans,FParams.CommaText) then OpenTrans;
  754. end;
  755. constructor TSQLTransaction.Create(AOwner : TComponent);
  756. begin
  757. inherited Create(AOwner);
  758. FParams := TStringList.Create;
  759. end;
  760. destructor TSQLTransaction.Destroy;
  761. begin
  762. Rollback;
  763. FreeAndNil(FParams);
  764. inherited Destroy;
  765. end;
  766. Procedure TSQLTransaction.SetDatabase(Value : TDatabase);
  767. begin
  768. If Value<>Database then
  769. begin
  770. if assigned(value) and not (Value is TSQLConnection) then
  771. DatabaseErrorFmt(SErrNotASQLConnection,[value.Name],self);
  772. CheckInactive;
  773. If Assigned(Database) then
  774. with TSQLConnection(DataBase) do
  775. if Transaction = self then Transaction := nil;
  776. inherited SetDatabase(Value);
  777. If Assigned(Database) and not (csLoading in ComponentState) then
  778. If (TSQLConnection(DataBase).Transaction=Nil) then
  779. TSQLConnection(DataBase).Transaction:=Self;
  780. end;
  781. end;
  782. function TSQLTransaction.LogEvent(EventType: TDBEventType): Boolean;
  783. begin
  784. Result:=Assigned(Database) and TSQLConnection(Database).LogEvent(EventType);
  785. end;
  786. procedure TSQLTransaction.Log(EventType: TDBEventType; const Msg: String);
  787. Var
  788. M : String;
  789. begin
  790. If LogEVent(EventType) then
  791. begin
  792. If (Name<>'') then
  793. M:=Name+' : '+Msg
  794. else
  795. M:=Msg;
  796. TSQLConnection(Database).Log(EventType,M);
  797. end;
  798. end;
  799. { TCustomSQLQuery }
  800. procedure TCustomSQLQuery.OnChangeSQL(Sender : TObject);
  801. var ConnOptions : TConnOptions;
  802. NewParams: TParams;
  803. begin
  804. UnPrepare;
  805. FSchemaType:=stNoSchema;
  806. if (FSQL <> nil) then
  807. begin
  808. if assigned(DataBase) then
  809. ConnOptions := TSQLConnection(DataBase).ConnOptions
  810. else
  811. ConnOptions := [sqEscapeRepeat,sqEscapeSlash];
  812. //preserve existing param. values
  813. NewParams := TParams.Create(Self);
  814. try
  815. NewParams.ParseSQL(FSQL.Text, True, sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions, psInterbase);
  816. NewParams.AssignValues(FParams);
  817. FParams.Assign(NewParams);
  818. finally
  819. NewParams.Free;
  820. end;
  821. If Assigned(FMasterLink) then
  822. FMasterLink.RefreshParamNames;
  823. end;
  824. end;
  825. function TCustomSQLQuery.ParamByName(Const AParamName : String) : TParam;
  826. begin
  827. Result:=Params.ParamByName(AParamName);
  828. end;
  829. procedure TCustomSQLQuery.OnChangeModifySQL(Sender : TObject);
  830. begin
  831. CheckInactive;
  832. end;
  833. Procedure TCustomSQLQuery.SetTransaction(Value : TDBTransaction);
  834. begin
  835. UnPrepare;
  836. inherited;
  837. If (Transaction<>Nil) and (Database=Nil) then
  838. Database:=TSQLTransaction(Transaction).Database;
  839. end;
  840. procedure TCustomSQLQuery.SetDatabase(Value : TDatabase);
  841. var db : tsqlconnection;
  842. begin
  843. if (Database <> Value) then
  844. begin
  845. if assigned(value) and not (Value is TSQLConnection) then
  846. DatabaseErrorFmt(SErrNotASQLConnection,[value.Name],self);
  847. UnPrepare;
  848. if assigned(FCursor) then TSQLConnection(DataBase).DeAllocateCursorHandle(FCursor);
  849. db := TSQLConnection(Value);
  850. inherited setdatabase(value);
  851. if assigned(value) and (Transaction = nil) and (Assigned(db.Transaction)) then
  852. transaction := Db.Transaction;
  853. OnChangeSQL(Self);
  854. end;
  855. end;
  856. Function TCustomSQLQuery.IsPrepared : Boolean;
  857. begin
  858. Result := Assigned(FCursor) and FCursor.FPrepared;
  859. end;
  860. Function TCustomSQLQuery.AddFilter(SQLstr : string) : string;
  861. begin
  862. if (FWhereStartPos > 0) and (FWhereStopPos > 0) then
  863. begin
  864. system.insert('(',SQLstr,FWhereStartPos+1);
  865. system.insert(')',SQLstr,FWhereStopPos+1);
  866. end;
  867. if FWhereStartPos = 0 then
  868. SQLstr := SQLstr + ' where (' + Filter + ')'
  869. else if FWhereStopPos > 0 then
  870. system.insert(' and ('+ServerFilter+') ',SQLstr,FWhereStopPos+2)
  871. else
  872. system.insert(' where ('+ServerFilter+') ',SQLstr,FWhereStartPos);
  873. Result := SQLstr;
  874. end;
  875. procedure TCustomSQLQuery.ApplyFilter;
  876. var S : String;
  877. begin
  878. FreeFldBuffers;
  879. TSQLConnection(Database).UnPrepareStatement(FCursor);
  880. FIsEOF := False;
  881. inherited internalclose;
  882. s := FSQLBuf;
  883. if ServerFiltered then s := AddFilter(s);
  884. TSQLConnection(Database).PrepareStatement(Fcursor,(transaction as tsqltransaction),S,FParams);
  885. Execute;
  886. inherited InternalOpen;
  887. First;
  888. end;
  889. Procedure TCustomSQLQuery.SetActive (Value : Boolean);
  890. begin
  891. inherited SetActive(Value);
  892. // The query is UnPrepared, so that if a transaction closes all datasets
  893. // they also get unprepared
  894. if not Value and IsPrepared then UnPrepare;
  895. end;
  896. procedure TCustomSQLQuery.SetServerFiltered(Value: Boolean);
  897. begin
  898. if Value and not FParseSQL then DatabaseErrorFmt(SNoParseSQL,['Filtering ']);
  899. if (ServerFiltered <> Value) then
  900. begin
  901. FServerFiltered := Value;
  902. if active then ApplyFilter;
  903. end;
  904. end;
  905. procedure TCustomSQLQuery.SetServerFilterText(const Value: string);
  906. begin
  907. if Value <> ServerFilter then
  908. begin
  909. FServerFilterText := Value;
  910. if active then ApplyFilter;
  911. end;
  912. end;
  913. procedure TCustomSQLQuery.Prepare;
  914. var
  915. db : tsqlconnection;
  916. sqltr : tsqltransaction;
  917. StmType: TStatementType;
  918. begin
  919. if not IsPrepared then
  920. begin
  921. db := TSQLConnection(Database);
  922. sqltr := (transaction as tsqltransaction);
  923. if not assigned(Db) then
  924. DatabaseError(SErrDatabasenAssigned);
  925. if not assigned(sqltr) then
  926. DatabaseError(SErrTransactionnSet);
  927. if not Db.Connected then db.Open;
  928. if not sqltr.Active then sqltr.StartTransaction;
  929. if FSchemaType=stNoSchema then
  930. FSQLBuf := TrimRight(FSQL.Text)
  931. else
  932. FSQLBuf := db.GetSchemaInfoSQL(FSchemaType, FSchemaObjectName, FSchemaPattern);
  933. if FSQLBuf = '' then
  934. DatabaseError(SErrNoStatement);
  935. StmType:=SQLParser(FSQLBuf);
  936. // There may no error occur between the allocation of the cursor and
  937. // the preparation of the cursor. Because internalclose (which is called in
  938. // case of an exception) assumes that allocated cursors are also prepared,
  939. // and thus calls unprepare.
  940. // A call to unprepare while the cursor is not prepared at all can lead to
  941. // unpredictable results.
  942. if not assigned(fcursor) then
  943. FCursor := Db.AllocateCursorHandle;
  944. FCursor.FStatementType:=StmType;
  945. FCursor.FSchemaType := FSchemaType;
  946. if ServerFiltered then
  947. begin
  948. If LogEvent(detprepare) then
  949. Log(detPrepare,AddFilter(FSQLBuf));
  950. Db.PrepareStatement(Fcursor,sqltr,AddFilter(FSQLBuf),FParams)
  951. end
  952. else
  953. begin
  954. If LogEvent(detprepare) then
  955. Log(detPrepare,FSQLBuf);
  956. Db.PrepareStatement(Fcursor,sqltr,FSQLBuf,FParams);
  957. end;
  958. if (FCursor.FStatementType in [stSelect,stExecProcedure]) then
  959. FCursor.FInitFieldDef := True;
  960. end;
  961. end;
  962. procedure TCustomSQLQuery.UnPrepare;
  963. begin
  964. CheckInactive;
  965. if IsPrepared then with TSQLConnection(DataBase) do
  966. UnPrepareStatement(FCursor);
  967. end;
  968. procedure TCustomSQLQuery.FreeFldBuffers;
  969. begin
  970. if assigned(FCursor) then TSQLConnection(Database).FreeFldBuffers(FCursor);
  971. end;
  972. function TCustomSQLQuery.GetServerIndexDefs: TServerIndexDefs;
  973. begin
  974. Result := FServerIndexDefs;
  975. end;
  976. function TCustomSQLQuery.Fetch : boolean;
  977. begin
  978. if not (Fcursor.FStatementType in [stSelect,stExecProcedure]) then
  979. Exit;
  980. if not FIsEof then FIsEOF := not TSQLConnection(Database).Fetch(Fcursor);
  981. Result := not FIsEOF;
  982. end;
  983. procedure TCustomSQLQuery.Execute;
  984. begin
  985. If (FParams.Count>0) and Assigned(FMasterLink) then
  986. FMasterLink.CopyParamsFromMaster(False);
  987. If LogEvent(detExecute) then
  988. Log(detExecute,FSQLBuf);
  989. TSQLConnection(Database).execute(Fcursor,Transaction as tsqltransaction, FParams);
  990. end;
  991. function TCustomSQLQuery.LoadField(FieldDef : TFieldDef;buffer : pointer; out CreateBlob : boolean) : boolean;
  992. begin
  993. result := TSQLConnection(Database).LoadField(FCursor,FieldDef,buffer, Createblob)
  994. end;
  995. function TCustomSQLQuery.RowsAffected: TRowsCount;
  996. begin
  997. Result := -1;
  998. if not Assigned(Database) then Exit;
  999. //assert(Database is TSQLConnection);
  1000. Result := TSQLConnection(Database).RowsAffected(FCursor);
  1001. end;
  1002. procedure TCustomSQLQuery.InternalAddRecord(Buffer: Pointer; AAppend: Boolean);
  1003. begin
  1004. // not implemented - sql dataset
  1005. end;
  1006. procedure TCustomSQLQuery.InternalClose;
  1007. begin
  1008. if not IsReadFromPacket then
  1009. begin
  1010. if StatementType in [stSelect,stExecProcedure] then FreeFldBuffers;
  1011. // Database and FCursor could be nil, for example if the database is not assigned, and .open is called
  1012. if (not IsPrepared) and (assigned(database)) and (assigned(FCursor)) then TSQLConnection(database).UnPrepareStatement(FCursor);
  1013. end;
  1014. if DefaultFields then
  1015. DestroyFields;
  1016. FIsEOF := False;
  1017. if assigned(FUpdateQry) then FreeAndNil(FUpdateQry);
  1018. if assigned(FInsertQry) then FreeAndNil(FInsertQry);
  1019. if assigned(FDeleteQry) then FreeAndNil(FDeleteQry);
  1020. // FRecordSize := 0;
  1021. inherited internalclose;
  1022. end;
  1023. procedure TCustomSQLQuery.InternalInitFieldDefs;
  1024. begin
  1025. if FLoadingFieldDefs then
  1026. Exit;
  1027. FLoadingFieldDefs := True;
  1028. try
  1029. FieldDefs.Clear;
  1030. if not Assigned(Database) then DatabaseError(SErrDatabasenAssigned);
  1031. TSQLConnection(Database).AddFieldDefs(fcursor,FieldDefs);
  1032. finally
  1033. FLoadingFieldDefs := False;
  1034. if Assigned(FCursor) then FCursor.FInitFieldDef := false;
  1035. end;
  1036. end;
  1037. function TCustomSQLQuery.SQLParser(const ASQL : string) : TStatementType;
  1038. type TParsePart = (ppStart,ppSelect,ppWhere,ppFrom,ppOrder,ppComment,ppGroup,ppBogus);
  1039. Var
  1040. PSQL,CurrentP,
  1041. PhraseP, PStatementPart : pchar;
  1042. S : string;
  1043. ParsePart : TParsePart;
  1044. StrLength : Integer;
  1045. EndOfComment : Boolean;
  1046. BracketCount : Integer;
  1047. ConnOptions : TConnOptions;
  1048. FFromPart : String;
  1049. begin
  1050. PSQL:=Pchar(ASQL);
  1051. ParsePart := ppStart;
  1052. CurrentP := PSQL-1;
  1053. PhraseP := PSQL;
  1054. FWhereStartPos := 0;
  1055. FWhereStopPos := 0;
  1056. ConnOptions := TSQLConnection(DataBase).ConnOptions;
  1057. FUpdateable := False;
  1058. repeat
  1059. begin
  1060. inc(CurrentP);
  1061. EndOfComment := SkipComments(CurrentP,sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions);
  1062. if EndOfcomment then dec(currentp);
  1063. if EndOfComment and (ParsePart = ppStart) then PhraseP := CurrentP;
  1064. // skip everything between bracket, since it could be a sub-select, and
  1065. // further nothing between brackets could be interesting for the parser.
  1066. if currentp^='(' then
  1067. begin
  1068. inc(currentp);
  1069. BracketCount := 0;
  1070. while (currentp^ <> #0) and ((currentp^ <> ')') or (BracketCount > 0 )) do
  1071. begin
  1072. if currentp^ = '(' then inc(bracketcount)
  1073. else if currentp^ = ')' then dec(bracketcount);
  1074. inc(currentp);
  1075. end;
  1076. EndOfComment := True;
  1077. end;
  1078. if EndOfComment or (CurrentP^ in [' ',#13,#10,#9,#0,';']) then
  1079. begin
  1080. if (CurrentP-PhraseP > 0) or (CurrentP^ in [';',#0]) then
  1081. begin
  1082. strLength := CurrentP-PhraseP;
  1083. Setlength(S,strLength);
  1084. if strLength > 0 then Move(PhraseP^,S[1],(strLength));
  1085. s := uppercase(s);
  1086. case ParsePart of
  1087. ppStart : begin
  1088. Result := TSQLConnection(Database).StrToStatementType(s);
  1089. if Result = stSelect then ParsePart := ppSelect
  1090. else break;
  1091. if not FParseSQL then break;
  1092. PStatementPart := CurrentP;
  1093. end;
  1094. ppSelect : begin
  1095. if s = 'FROM' then
  1096. begin
  1097. ParsePart := ppFrom;
  1098. PhraseP := CurrentP;
  1099. PStatementPart := CurrentP;
  1100. end;
  1101. end;
  1102. ppFrom : begin
  1103. if (s = 'WHERE') or (s = 'ORDER') or (s = 'GROUP') or (s = 'LIMIT') or (CurrentP^=#0) or (CurrentP^=';') then
  1104. begin
  1105. if (s = 'WHERE') then
  1106. begin
  1107. ParsePart := ppWhere;
  1108. StrLength := PhraseP-PStatementPart;
  1109. end
  1110. else if (s = 'GROUP') then
  1111. begin
  1112. ParsePart := ppGroup;
  1113. StrLength := PhraseP-PStatementPart;
  1114. end
  1115. else if (s = 'ORDER') then
  1116. begin
  1117. ParsePart := ppOrder;
  1118. StrLength := PhraseP-PStatementPart
  1119. end
  1120. else if (s = 'LIMIT') then
  1121. begin
  1122. ParsePart := ppBogus;
  1123. StrLength := PhraseP-PStatementPart
  1124. end
  1125. else
  1126. begin
  1127. ParsePart := ppBogus;
  1128. StrLength := CurrentP-PStatementPart;
  1129. end;
  1130. if Result = stSelect then
  1131. begin
  1132. Setlength(FFromPart,StrLength);
  1133. Move(PStatementPart^,FFromPart[1],(StrLength));
  1134. FFrompart := trim(FFrompart);
  1135. // Meta-data requests and are never updateable select-statements
  1136. // from more then one table are not updateable
  1137. if (FSchemaType=stNoSchema) and
  1138. (ExtractStrings([',',' '],[],pchar(FFromPart),nil) = 1) then
  1139. begin
  1140. FUpdateable := True;
  1141. FTableName := FFromPart;
  1142. end;
  1143. end;
  1144. FWhereStartPos := PStatementPart-PSQL+StrLength+1;
  1145. PStatementPart := CurrentP;
  1146. end;
  1147. end;
  1148. ppWhere : begin
  1149. if (s = 'ORDER') or (s = 'GROUP') or (s = 'LIMIT') or (CurrentP^=#0) or (CurrentP^=';') then
  1150. begin
  1151. ParsePart := ppBogus;
  1152. FWhereStartPos := PStatementPart-PSQL;
  1153. if (s = 'ORDER') or (s = 'GROUP') or (s = 'LIMIT') then
  1154. FWhereStopPos := PhraseP-PSQL+1
  1155. else
  1156. FWhereStopPos := CurrentP-PSQL+1;
  1157. end
  1158. else if (s = 'UNION') then
  1159. begin
  1160. ParsePart := ppBogus;
  1161. FUpdateable := False;
  1162. end;
  1163. end;
  1164. end; {case}
  1165. end;
  1166. PhraseP := CurrentP+1;
  1167. end
  1168. end;
  1169. until CurrentP^=#0;
  1170. end;
  1171. procedure TCustomSQLQuery.InternalOpen;
  1172. var tel, fieldc : integer;
  1173. f : TField;
  1174. s : string;
  1175. IndexFields : TStrings;
  1176. ReadFromFile: Boolean;
  1177. begin
  1178. ReadFromFile:=IsReadFromPacket;
  1179. if ReadFromFile then
  1180. begin
  1181. if not assigned(fcursor) then
  1182. FCursor := TSQLConnection(Database).AllocateCursorHandle;
  1183. FCursor.FStatementType:=stSelect;
  1184. FUpdateable:=True;
  1185. end
  1186. else
  1187. Prepare;
  1188. if FCursor.FStatementType in [stSelect,stExecProcedure] then
  1189. begin
  1190. if not ReadFromFile then
  1191. begin
  1192. // Call UpdateServerIndexDefs before Execute, to avoid problems with connections
  1193. // which do not allow processing multiple recordsets at a time. (Microsoft
  1194. // calls this MARS, see bug 13241)
  1195. if DefaultFields and FUpdateable and FusePrimaryKeyAsKey and (not IsUniDirectional) then
  1196. UpdateServerIndexDefs;
  1197. Execute;
  1198. // InternalInitFieldDef is only called after a prepare. i.e. not twice if
  1199. // a dataset is opened - closed - opened.
  1200. if FCursor.FInitFieldDef then InternalInitFieldDefs;
  1201. if DefaultFields then
  1202. begin
  1203. CreateFields;
  1204. if FUpdateable and (not IsUniDirectional) then
  1205. begin
  1206. if FusePrimaryKeyAsKey then
  1207. begin
  1208. for tel := 0 to ServerIndexDefs.count-1 do
  1209. begin
  1210. if ixPrimary in ServerIndexDefs[tel].options then
  1211. begin
  1212. IndexFields := TStringList.Create;
  1213. ExtractStrings([';'],[' '],pchar(ServerIndexDefs[tel].fields),IndexFields);
  1214. for fieldc := 0 to IndexFields.Count-1 do
  1215. begin
  1216. F := Findfield(IndexFields[fieldc]);
  1217. if F <> nil then
  1218. F.ProviderFlags := F.ProviderFlags + [pfInKey];
  1219. end;
  1220. IndexFields.Free;
  1221. end;
  1222. end;
  1223. end;
  1224. end;
  1225. end
  1226. else
  1227. BindFields(True);
  1228. end
  1229. else
  1230. BindFields(True);
  1231. if not ReadOnly and not FUpdateable and (FSchemaType=stNoSchema) then
  1232. begin
  1233. if (trim(FDeleteSQL.Text) <> '') or (trim(FUpdateSQL.Text) <> '') or
  1234. (trim(FInsertSQL.Text) <> '') then FUpdateable := True;
  1235. end
  1236. end
  1237. else
  1238. DatabaseError(SErrNoSelectStatement,Self);
  1239. inherited InternalOpen;
  1240. end;
  1241. // public part
  1242. procedure TCustomSQLQuery.ExecSQL;
  1243. begin
  1244. try
  1245. Prepare;
  1246. Execute;
  1247. finally
  1248. // FCursor has to be assigned, or else the prepare went wrong before PrepareStatment was
  1249. // called, so UnPrepareStatement shoudn't be called either
  1250. if (not IsPrepared) and (assigned(database)) and (assigned(FCursor)) then TSQLConnection(database).UnPrepareStatement(Fcursor);
  1251. end;
  1252. end;
  1253. constructor TCustomSQLQuery.Create(AOwner : TComponent);
  1254. begin
  1255. inherited Create(AOwner);
  1256. FParams := TParams.create(self);
  1257. FSQL := TStringList.Create;
  1258. FSQL.OnChange := @OnChangeSQL;
  1259. FUpdateSQL := TStringList.Create;
  1260. FUpdateSQL.OnChange := @OnChangeModifySQL;
  1261. FInsertSQL := TStringList.Create;
  1262. FInsertSQL.OnChange := @OnChangeModifySQL;
  1263. FDeleteSQL := TStringList.Create;
  1264. FDeleteSQL.OnChange := @OnChangeModifySQL;
  1265. FServerIndexDefs := TServerIndexDefs.Create(Self);
  1266. FReadOnly := false;
  1267. FParseSQL := True;
  1268. FServerFiltered := False;
  1269. FServerFilterText := '';
  1270. FSchemaType:=stNoSchema;
  1271. FSchemaObjectName:='';
  1272. FSchemaPattern:='';
  1273. // Delphi has upWhereAll as default, but since strings and oldvalue's don't work yet
  1274. // (variants) set it to upWhereKeyOnly
  1275. FUpdateMode := upWhereKeyOnly;
  1276. FUsePrimaryKeyAsKey := True;
  1277. end;
  1278. destructor TCustomSQLQuery.Destroy;
  1279. begin
  1280. if Active then Close;
  1281. UnPrepare;
  1282. if assigned(FCursor) then TSQLConnection(Database).DeAllocateCursorHandle(FCursor);
  1283. FreeAndNil(FMasterLink);
  1284. FreeAndNil(FParams);
  1285. FreeAndNil(FSQL);
  1286. FreeAndNil(FInsertSQL);
  1287. FreeAndNil(FDeleteSQL);
  1288. FreeAndNil(FUpdateSQL);
  1289. FServerIndexDefs.Free;
  1290. inherited Destroy;
  1291. end;
  1292. procedure TCustomSQLQuery.SetReadOnly(AValue : Boolean);
  1293. begin
  1294. CheckInactive;
  1295. FReadOnly:=AValue;
  1296. end;
  1297. procedure TCustomSQLQuery.SetParseSQL(AValue : Boolean);
  1298. begin
  1299. CheckInactive;
  1300. if not AValue then
  1301. begin
  1302. FServerFiltered := False;
  1303. FParseSQL := False;
  1304. end
  1305. else
  1306. FParseSQL := True;
  1307. end;
  1308. procedure TCustomSQLQuery.SetSQL(const AValue: TStringlist);
  1309. begin
  1310. FSQL.Assign(AValue);
  1311. end;
  1312. procedure TCustomSQLQuery.SetUpdateSQL(const AValue: TStringlist);
  1313. begin
  1314. FUpdateSQL.Assign(AValue);
  1315. end;
  1316. procedure TCustomSQLQuery.SetUsePrimaryKeyAsKey(AValue : Boolean);
  1317. begin
  1318. if not Active then FusePrimaryKeyAsKey := AValue
  1319. else
  1320. begin
  1321. // Just temporary, this should be possible in the future
  1322. DatabaseError(SActiveDataset);
  1323. end;
  1324. end;
  1325. Procedure TCustomSQLQuery.UpdateServerIndexDefs;
  1326. begin
  1327. FServerIndexDefs.Clear;
  1328. if assigned(DataBase) and (FTableName<>'') then
  1329. TSQLConnection(DataBase).UpdateIndexDefs(ServerIndexDefs,FTableName);
  1330. end;
  1331. Procedure TCustomSQLQuery.ApplyRecUpdate(UpdateKind : TUpdateKind);
  1332. var FieldNamesQuoteChars : TQuoteChars;
  1333. function InitialiseModifyQuery(var qry : TCustomSQLQuery): TCustomSQLQuery;
  1334. begin
  1335. if not assigned(qry) then
  1336. begin
  1337. qry := TCustomSQLQuery.Create(nil);
  1338. qry.ParseSQL := False;
  1339. qry.DataBase := Self.DataBase;
  1340. qry.Transaction := Self.Transaction;
  1341. end;
  1342. Result:=qry;
  1343. end;
  1344. procedure UpdateWherePart(var sql_where : string;x : integer);
  1345. begin
  1346. if (pfInKey in Fields[x].ProviderFlags) or
  1347. ((FUpdateMode = upWhereAll) and (pfInWhere in Fields[x].ProviderFlags)) or
  1348. ((FUpdateMode = UpWhereChanged) and (pfInWhere in Fields[x].ProviderFlags) and (Fields[x].Value <> Fields[x].OldValue)) then
  1349. if Fields[x].OldValue = NULL then
  1350. sql_where := sql_where + FieldNamesQuoteChars[0] + Fields[x].FieldName + FieldNamesQuoteChars[1] + ' is null and '
  1351. else
  1352. sql_where := sql_where + '(' + FieldNamesQuoteChars[0] + Fields[x].FieldName + FieldNamesQuoteChars[1] + '= :"' + 'OLD_' + Fields[x].FieldName + '") and ';
  1353. end;
  1354. function ModifyRecQuery : string;
  1355. var x : integer;
  1356. sql_set : string;
  1357. sql_where : string;
  1358. begin
  1359. sql_set := '';
  1360. sql_where := '';
  1361. for x := 0 to Fields.Count -1 do
  1362. begin
  1363. UpdateWherePart(sql_where,x);
  1364. if (pfInUpdate in Fields[x].ProviderFlags) then
  1365. sql_set := sql_set +FieldNamesQuoteChars[0] + fields[x].FieldName + FieldNamesQuoteChars[1] +'=:"' + fields[x].FieldName + '",';
  1366. end;
  1367. if length(sql_set) = 0 then DatabaseErrorFmt(sNoUpdateFields,['update'],self);
  1368. setlength(sql_set,length(sql_set)-1);
  1369. if length(sql_where) = 0 then DatabaseErrorFmt(sNoWhereFields,['update'],self);
  1370. setlength(sql_where,length(sql_where)-5);
  1371. result := 'update ' + FTableName + ' set ' + sql_set + ' where ' + sql_where;
  1372. end;
  1373. function InsertRecQuery : string;
  1374. var x : integer;
  1375. sql_fields : string;
  1376. sql_values : string;
  1377. begin
  1378. sql_fields := '';
  1379. sql_values := '';
  1380. for x := 0 to Fields.Count -1 do
  1381. begin
  1382. if (not fields[x].IsNull) and (pfInUpdate in Fields[x].ProviderFlags) then
  1383. begin
  1384. sql_fields := sql_fields + FieldNamesQuoteChars[0] + fields[x].FieldName + FieldNamesQuoteChars[1] + ',';
  1385. sql_values := sql_values + ':"' + fields[x].FieldName + '",';
  1386. end;
  1387. end;
  1388. if length(sql_fields) = 0 then DatabaseErrorFmt(sNoUpdateFields,['insert'],self);
  1389. setlength(sql_fields,length(sql_fields)-1);
  1390. setlength(sql_values,length(sql_values)-1);
  1391. result := 'insert into ' + FTableName + ' (' + sql_fields + ') values (' + sql_values + ')';
  1392. end;
  1393. function DeleteRecQuery : string;
  1394. var x : integer;
  1395. sql_where : string;
  1396. begin
  1397. sql_where := '';
  1398. for x := 0 to Fields.Count -1 do
  1399. UpdateWherePart(sql_where,x);
  1400. if length(sql_where) = 0 then DatabaseErrorFmt(sNoWhereFields,['delete'],self);
  1401. setlength(sql_where,length(sql_where)-5);
  1402. result := 'delete from ' + FTableName + ' where ' + sql_where;
  1403. end;
  1404. var qry : TCustomSQLQuery;
  1405. s : string;
  1406. x : integer;
  1407. Fld : TField;
  1408. begin
  1409. FieldNamesQuoteChars := TSQLConnection(DataBase).FieldNameQuoteChars;
  1410. case UpdateKind of
  1411. ukInsert : begin
  1412. s := trim(FInsertSQL.Text);
  1413. if s = '' then s := InsertRecQuery;
  1414. qry := InitialiseModifyQuery(FInsertQry);
  1415. end;
  1416. ukModify : begin
  1417. s := trim(FUpdateSQL.Text);
  1418. if (s='') and (not assigned(FUpdateQry) or (UpdateMode<>upWhereKeyOnly)) then //first time or dynamic where part
  1419. s := ModifyRecQuery;
  1420. qry := InitialiseModifyQuery(FUpdateQry);
  1421. end;
  1422. ukDelete : begin
  1423. s := trim(FDeleteSQL.Text);
  1424. if (s='') and (not assigned(FDeleteQry) or (UpdateMode<>upWhereKeyOnly)) then
  1425. s := DeleteRecQuery;
  1426. qry := InitialiseModifyQuery(FDeleteQry);
  1427. end;
  1428. end;
  1429. if (qry.SQL.Text<>s) and (s<>'') then qry.SQL.Text:=s; //assign only when changed, to avoid UnPrepare/Prepare
  1430. assert(qry.sql.Text<>'');
  1431. with qry do
  1432. begin
  1433. for x := 0 to Params.Count-1 do with params[x] do if leftstr(name,4)='OLD_' then
  1434. begin
  1435. Fld := self.FieldByName(copy(name,5,length(name)-4));
  1436. AssignFieldValue(Fld,Fld.OldValue);
  1437. end
  1438. else
  1439. begin
  1440. Fld := self.FieldByName(name);
  1441. AssignFieldValue(Fld,Fld.Value);
  1442. end;
  1443. execsql;
  1444. end;
  1445. end;
  1446. Function TCustomSQLQuery.GetCanModify: Boolean;
  1447. begin
  1448. // the test for assigned(FCursor) is needed for the case that the dataset isn't opened
  1449. if assigned(FCursor) and (FCursor.FStatementType = stSelect) then
  1450. Result:= FUpdateable and (not FReadOnly) and (not IsUniDirectional)
  1451. else
  1452. Result := False;
  1453. end;
  1454. procedure TCustomSQLQuery.SetUpdateMode(AValue : TUpdateMode);
  1455. begin
  1456. FUpdateMode := AValue;
  1457. end;
  1458. procedure TCustomSQLQuery.SetSchemaInfo( ASchemaType : TSchemaType; ASchemaObjectName, ASchemaPattern : string);
  1459. begin
  1460. FSchemaType:=ASchemaType;
  1461. FSchemaObjectName:=ASchemaObjectName;
  1462. FSchemaPattern:=ASchemaPattern;
  1463. end;
  1464. procedure TCustomSQLQuery.LoadBlobIntoBuffer(FieldDef: TFieldDef;
  1465. ABlobBuf: PBufBlobField);
  1466. begin
  1467. TSQLConnection(DataBase).LoadBlobIntoBuffer(FieldDef, ABlobBuf, FCursor,(Transaction as tsqltransaction));
  1468. end;
  1469. procedure TCustomSQLQuery.BeforeRefreshOpenCursor;
  1470. begin
  1471. // This is only necessary because TIBConnection can not re-open a
  1472. // prepared cursor. In fact this is wrong, but has never led to
  1473. // problems because in SetActive(false) queries are always
  1474. // unprepared. (which is also wrong, but has to be fixed later)
  1475. if IsPrepared then with TSQLConnection(DataBase) do
  1476. UnPrepareStatement(FCursor);
  1477. end;
  1478. function TCustomSQLQuery.LogEvent(EventType: TDBEventType): Boolean;
  1479. begin
  1480. Result:=Assigned(Database) and TSQLConnection(Database).LogEvent(EventType);
  1481. end;
  1482. procedure TCustomSQLQuery.Log(EventType: TDBEventType; const Msg: String);
  1483. Var
  1484. M : String;
  1485. begin
  1486. If LogEvent(EventType) then
  1487. begin
  1488. M:=Msg;
  1489. If (Name<>'') then
  1490. M:=Name+' : '+M;
  1491. TSQLConnection(Database).Log(EventType,M);
  1492. end;
  1493. end;
  1494. function TCustomSQLQuery.GetStatementType : TStatementType;
  1495. begin
  1496. if assigned(FCursor) then Result := FCursor.FStatementType
  1497. else Result := stNone;
  1498. end;
  1499. procedure TCustomSQLQuery.SetDeleteSQL(const AValue: TStringlist);
  1500. begin
  1501. FDeleteSQL.Assign(AValue);
  1502. end;
  1503. procedure TCustomSQLQuery.SetInsertSQL(const AValue: TStringlist);
  1504. begin
  1505. FInsertSQL.Assign(AValue);
  1506. end;
  1507. Procedure TCustomSQLQuery.SetDataSource(AVAlue : TDatasource);
  1508. Var
  1509. DS : TDatasource;
  1510. begin
  1511. DS:=DataSource;
  1512. If (AValue<>DS) then
  1513. begin
  1514. If Assigned(AValue) and (AValue.Dataset=Self) then
  1515. DatabaseError(SErrCircularDataSourceReferenceNotAllowed,Self);
  1516. If Assigned(DS) then
  1517. DS.RemoveFreeNotification(Self);
  1518. If Assigned(AValue) then
  1519. begin
  1520. AValue.FreeNotification(Self);
  1521. If (FMasterLink=Nil) then
  1522. FMasterLink:=TMasterParamsDataLink.Create(Self);
  1523. FMasterLink.Datasource:=AValue;
  1524. end
  1525. else
  1526. FreeAndNil(FMasterLink);
  1527. end;
  1528. end;
  1529. Function TCustomSQLQuery.GetDataSource : TDatasource;
  1530. begin
  1531. If Assigned(FMasterLink) then
  1532. Result:=FMasterLink.DataSource
  1533. else
  1534. Result:=Nil;
  1535. end;
  1536. procedure TCustomSQLQuery.Notification(AComponent: TComponent; Operation: TOperation);
  1537. begin
  1538. Inherited;
  1539. If (Operation=opRemove) and (AComponent=DataSource) then
  1540. DataSource:=Nil;
  1541. end;
  1542. { TSQLScript }
  1543. procedure TSQLScript.ExecuteStatement(SQLStatement: TStrings;
  1544. var StopExecution: Boolean);
  1545. begin
  1546. fquery.SQL.assign(SQLStatement);
  1547. fquery.ExecSQL;
  1548. end;
  1549. procedure TSQLScript.ExecuteDirective(Directive, Argument: String;
  1550. var StopExecution: Boolean);
  1551. begin
  1552. if assigned (FOnDirective) then
  1553. FOnDirective (Self, Directive, Argument, StopExecution);
  1554. end;
  1555. procedure TSQLScript.ExecuteCommit;
  1556. begin
  1557. if FTransaction is TSQLTransaction then
  1558. TSQLTransaction(FTransaction).CommitRetaining
  1559. else
  1560. begin
  1561. FTransaction.Active := false;
  1562. FTransaction.Active := true;
  1563. end;
  1564. end;
  1565. procedure TSQLScript.SetDatabase(Value: TDatabase);
  1566. begin
  1567. FDatabase := Value;
  1568. end;
  1569. procedure TSQLScript.SetTransaction(Value: TDBTransaction);
  1570. begin
  1571. FTransaction := Value;
  1572. end;
  1573. procedure TSQLScript.CheckDatabase;
  1574. begin
  1575. If (FDatabase=Nil) then
  1576. DatabaseError(SErrNoDatabaseAvailable,Self)
  1577. end;
  1578. constructor TSQLScript.Create(AOwner: TComponent);
  1579. begin
  1580. inherited Create(AOwner);
  1581. FQuery := TCustomSQLQuery.Create(nil);
  1582. end;
  1583. destructor TSQLScript.Destroy;
  1584. begin
  1585. FQuery.Free;
  1586. inherited Destroy;
  1587. end;
  1588. procedure TSQLScript.Execute;
  1589. begin
  1590. FQuery.DataBase := FDatabase;
  1591. FQuery.Transaction := FTransaction;
  1592. inherited Execute;
  1593. end;
  1594. procedure TSQLScript.ExecuteScript;
  1595. begin
  1596. Execute;
  1597. end;
  1598. { Connection definitions }
  1599. Var
  1600. ConnDefs : TStringList;
  1601. Procedure CheckDefs;
  1602. begin
  1603. If (ConnDefs=Nil) then
  1604. begin
  1605. ConnDefs:=TStringList.Create;
  1606. ConnDefs.Sorted:=True;
  1607. ConnDefs.Duplicates:=dupError;
  1608. end;
  1609. end;
  1610. Procedure DoneDefs;
  1611. Var
  1612. I : Integer;
  1613. begin
  1614. If Assigned(ConnDefs) then
  1615. begin
  1616. For I:=ConnDefs.Count-1 downto 0 do
  1617. begin
  1618. ConnDefs.Objects[i].Free;
  1619. ConnDefs.Delete(I);
  1620. end;
  1621. FreeAndNil(ConnDefs);
  1622. end;
  1623. end;
  1624. Function GetConnectionDef(ConnectorName : String) : TConnectionDef;
  1625. Var
  1626. I : Integer;
  1627. begin
  1628. CheckDefs;
  1629. I:=ConnDefs.IndexOf(ConnectorName);
  1630. If (I<>-1) then
  1631. Result:=TConnectionDef(ConnDefs.Objects[i])
  1632. else
  1633. Result:=Nil;
  1634. end;
  1635. procedure RegisterConnection(Def: TConnectionDefClass);
  1636. Var
  1637. I : Integer;
  1638. begin
  1639. CheckDefs;
  1640. I:=ConnDefs.IndexOf(Def.TypeName);
  1641. If (I=-1) then
  1642. ConnDefs.AddObject(Def.TypeName,Def.Create)
  1643. else
  1644. begin
  1645. ConnDefs.Objects[I].Free;
  1646. ConnDefs.Objects[I]:=Def.Create;
  1647. end;
  1648. end;
  1649. procedure UnRegisterConnection(Def: TConnectionDefClass);
  1650. begin
  1651. UnRegisterConnection(Def.TypeName);
  1652. end;
  1653. procedure UnRegisterConnection(ConnectionName: String);
  1654. Var
  1655. I : Integer;
  1656. begin
  1657. if (ConnDefs<>Nil) then
  1658. begin
  1659. I:=ConnDefs.IndexOf(ConnectionName);
  1660. If (I<>-1) then
  1661. begin
  1662. ConnDefs.Objects[I].Free;
  1663. ConnDefs.Delete(I);
  1664. end;
  1665. end;
  1666. end;
  1667. procedure GetConnectionList(List: TSTrings);
  1668. begin
  1669. CheckDefs;
  1670. List.Text:=ConnDefs.Text;
  1671. end;
  1672. { TSQLConnector }
  1673. procedure TSQLConnector.SetConnectorType(const AValue: String);
  1674. begin
  1675. if FConnectorType<>AValue then
  1676. begin
  1677. CheckDisconnected;
  1678. If Assigned(FProxy) then
  1679. FreeProxy;
  1680. FConnectorType:=AValue;
  1681. end;
  1682. end;
  1683. procedure TSQLConnector.SetTransaction(Value: TSQLTransaction);
  1684. begin
  1685. inherited SetTransaction(Value);
  1686. If Assigned(FProxy) and (FProxy.Transaction<>Value) then
  1687. FProxy.FTransaction:=Value;
  1688. end;
  1689. procedure TSQLConnector.DoInternalConnect;
  1690. Var
  1691. D : TConnectionDef;
  1692. begin
  1693. inherited DoInternalConnect;
  1694. CreateProxy;
  1695. FProxy.CharSet:=Self.CharSet;
  1696. FProxy.Role:=self.Role;
  1697. FProxy.DatabaseName:=Self.DatabaseName;
  1698. FProxy.HostName:=Self.HostName;
  1699. FProxy.UserName:=Self.UserName;
  1700. FProxy.Password:=Self.Password;
  1701. FProxy.FTransaction:=Self.Transaction;
  1702. D:=GetConnectionDef(ConnectorType);
  1703. D.ApplyParams(Params,FProxy);
  1704. FProxy.Connected:=True;
  1705. end;
  1706. procedure TSQLConnector.DoInternalDisconnect;
  1707. begin
  1708. FProxy.Connected:=False;
  1709. inherited DoInternalDisconnect;
  1710. end;
  1711. procedure TSQLConnector.CheckProxy;
  1712. begin
  1713. If (FProxy=Nil) then
  1714. CreateProxy;
  1715. end;
  1716. procedure TSQLConnector.CreateProxy;
  1717. Var
  1718. D : TConnectionDef;
  1719. begin
  1720. D:=GetConnectionDef(ConnectorType);
  1721. If (D=Nil) then
  1722. DatabaseErrorFmt(SErrUnknownConnectorType,[ConnectorType],Self);
  1723. FProxy:=D.ConnectionClass.Create(Self);
  1724. FFieldNameQuoteChars := FProxy.FieldNameQuoteChars;
  1725. end;
  1726. procedure TSQLConnector.FreeProxy;
  1727. begin
  1728. FProxy.Connected:=False;
  1729. FreeAndNil(FProxy);
  1730. end;
  1731. function TSQLConnector.StrToStatementType(s: string): TStatementType;
  1732. begin
  1733. CheckProxy;
  1734. Result:=FProxy.StrToStatementType(s);
  1735. end;
  1736. function TSQLConnector.GetAsSQLText(Field: TField): string;
  1737. begin
  1738. CheckProxy;
  1739. Result:=FProxy.GetAsSQLText(Field);
  1740. end;
  1741. function TSQLConnector.GetAsSQLText(Param: TParam): string;
  1742. begin
  1743. CheckProxy;
  1744. Result:=FProxy.GetAsSQLText(Param);
  1745. end;
  1746. function TSQLConnector.GetHandle: pointer;
  1747. begin
  1748. CheckProxy;
  1749. Result:=FProxy.GetHandle;
  1750. end;
  1751. function TSQLConnector.AllocateCursorHandle: TSQLCursor;
  1752. begin
  1753. CheckProxy;
  1754. Result:=FProxy.AllocateCursorHandle;
  1755. end;
  1756. procedure TSQLConnector.DeAllocateCursorHandle(var cursor: TSQLCursor);
  1757. begin
  1758. CheckProxy;
  1759. FProxy.DeAllocateCursorHandle(cursor);
  1760. end;
  1761. function TSQLConnector.AllocateTransactionHandle: TSQLHandle;
  1762. begin
  1763. CheckProxy;
  1764. Result:=FProxy.AllocateTransactionHandle;
  1765. end;
  1766. procedure TSQLConnector.PrepareStatement(cursor: TSQLCursor;
  1767. ATransaction: TSQLTransaction; buf: string; AParams: TParams);
  1768. begin
  1769. CheckProxy;
  1770. FProxy.PrepareStatement(cursor, ATransaction, buf, AParams);
  1771. end;
  1772. procedure TSQLConnector.Execute(cursor: TSQLCursor;
  1773. atransaction: tSQLtransaction; AParams: TParams);
  1774. begin
  1775. CheckProxy;
  1776. FProxy.Execute(cursor, atransaction, AParams);
  1777. end;
  1778. function TSQLConnector.Fetch(cursor: TSQLCursor): boolean;
  1779. begin
  1780. CheckProxy;
  1781. Result:=FProxy.Fetch(cursor);
  1782. end;
  1783. procedure TSQLConnector.AddFieldDefs(cursor: TSQLCursor; FieldDefs: TfieldDefs
  1784. );
  1785. begin
  1786. CheckProxy;
  1787. FProxy.AddFieldDefs(cursor, FieldDefs);
  1788. end;
  1789. procedure TSQLConnector.UnPrepareStatement(cursor: TSQLCursor);
  1790. begin
  1791. CheckProxy;
  1792. FProxy.UnPrepareStatement(cursor);
  1793. end;
  1794. procedure TSQLConnector.FreeFldBuffers(cursor: TSQLCursor);
  1795. begin
  1796. CheckProxy;
  1797. FProxy.FreeFldBuffers(cursor);
  1798. end;
  1799. function TSQLConnector.LoadField(cursor: TSQLCursor; FieldDef: TfieldDef;
  1800. buffer: pointer; out CreateBlob: boolean): boolean;
  1801. begin
  1802. CheckProxy;
  1803. Result:=FProxy.LoadField(cursor, FieldDef, buffer, CreateBlob);
  1804. end;
  1805. function TSQLConnector.RowsAffected(cursor: TSQLCursor): TRowsCount;
  1806. begin
  1807. CheckProxy;
  1808. Result := FProxy.RowsAffected(cursor);
  1809. end;
  1810. function TSQLConnector.GetTransactionHandle(trans: TSQLHandle): pointer;
  1811. begin
  1812. CheckProxy;
  1813. Result:=FProxy.GetTransactionHandle(trans);
  1814. end;
  1815. function TSQLConnector.Commit(trans: TSQLHandle): boolean;
  1816. begin
  1817. CheckProxy;
  1818. Result:=FProxy.Commit(trans);
  1819. end;
  1820. function TSQLConnector.RollBack(trans: TSQLHandle): boolean;
  1821. begin
  1822. CheckProxy;
  1823. Result:=FProxy.RollBack(trans);
  1824. end;
  1825. function TSQLConnector.StartdbTransaction(trans: TSQLHandle; aParams: string
  1826. ): boolean;
  1827. begin
  1828. CheckProxy;
  1829. Result:=FProxy.StartdbTransaction(trans, aParams);
  1830. end;
  1831. procedure TSQLConnector.CommitRetaining(trans: TSQLHandle);
  1832. begin
  1833. CheckProxy;
  1834. FProxy.CommitRetaining(trans);
  1835. end;
  1836. procedure TSQLConnector.RollBackRetaining(trans: TSQLHandle);
  1837. begin
  1838. CheckProxy;
  1839. FProxy.RollBackRetaining(trans);
  1840. end;
  1841. procedure TSQLConnector.UpdateIndexDefs(IndexDefs: TIndexDefs;
  1842. TableName: string);
  1843. begin
  1844. CheckProxy;
  1845. FProxy.UpdateIndexDefs(IndexDefs, TableName);
  1846. end;
  1847. function TSQLConnector.GetSchemaInfoSQL(SchemaType: TSchemaType;
  1848. SchemaObjectName, SchemaPattern: string): string;
  1849. begin
  1850. CheckProxy;
  1851. Result:=FProxy.GetSchemaInfoSQL(SchemaType, SchemaObjectName, SchemaPattern
  1852. );
  1853. end;
  1854. procedure TSQLConnector.LoadBlobIntoBuffer(FieldDef: TFieldDef;
  1855. ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction);
  1856. begin
  1857. CheckProxy;
  1858. FProxy.LoadBlobIntoBuffer(FieldDef, ABlobBuf, cursor, ATransaction);
  1859. end;
  1860. { TConnectionDef }
  1861. class function TConnectionDef.TypeName: String;
  1862. begin
  1863. Result:='';
  1864. end;
  1865. class function TConnectionDef.ConnectionClass: TSQLConnectionClass;
  1866. begin
  1867. Result:=Nil;
  1868. end;
  1869. class function TConnectionDef.Description: String;
  1870. begin
  1871. Result:='';
  1872. end;
  1873. procedure TConnectionDef.ApplyParams(Params: TStrings;
  1874. AConnection: TSQLConnection);
  1875. begin
  1876. AConnection.Params.Assign(Params);
  1877. end;
  1878. { TServerIndexDefs }
  1879. constructor TServerIndexDefs.create(ADataset: TDataset);
  1880. begin
  1881. if not (ADataset is TCustomSQLQuery) then
  1882. DatabaseErrorFmt(SErrNotASQLQuery,[ADataset.Name]);
  1883. inherited create(ADataset);
  1884. end;
  1885. procedure TServerIndexDefs.Update;
  1886. begin
  1887. if (not updated) and assigned(Dataset) then
  1888. begin
  1889. TCustomSQLQuery(Dataset).UpdateServerIndexDefs;
  1890. updated := True;
  1891. end;
  1892. end;
  1893. Initialization
  1894. Finalization
  1895. DoneDefs;
  1896. end.