sqldb.pp 65 KB

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