ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBDatabase.pas
Revision: 45
Committed: Tue Dec 6 10:33:46 2016 UTC (7 years, 11 months ago) by tony
Content type: text/x-pascal
File size: 61732 byte(s)
Log Message:
Committing updates for Release R2-0-0

File Contents

# Content
1 {************************************************************************}
2 { }
3 { Borland Delphi Visual Component Library }
4 { InterBase Express core components }
5 { }
6 { Copyright (c) 1998-2000 Inprise Corporation }
7 { }
8 { InterBase Express is based in part on the product }
9 { Free IB Components, written by Gregory H. Deatz for }
10 { Hoagland, Longo, Moran, Dunst & Doukas Company. }
11 { Free IB Components is used under license. }
12 { }
13 { The contents of this file are subject to the InterBase }
14 { Public License Version 1.0 (the "License"); you may not }
15 { use this file except in compliance with the License. You }
16 { may obtain a copy of the License at http://www.Inprise.com/IPL.html }
17 { Software distributed under the License is distributed on }
18 { an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either }
19 { express or implied. See the License for the specific language }
20 { governing rights and limitations under the License. }
21 { The Original Code was created by InterBase Software Corporation }
22 { and its successors. }
23 { Portions created by Inprise Corporation are Copyright (C) Inprise }
24 { Corporation. All Rights Reserved. }
25 { Contributor(s): Jeff Overcash }
26 { }
27 { IBX For Lazarus (Firebird Express) }
28 { Contributor: Tony Whyman, MWA Software http://www.mwasoftware.co.uk }
29 { Portions created by MWA Software are copyright McCallum Whyman }
30 { Associates Ltd 2011 }
31 { }
32 {************************************************************************}
33
34 unit IBDatabase;
35
36 {$Mode Delphi}
37
38 {$codepage UTF8}
39
40 interface
41
42 uses
43 {$IFDEF WINDOWS }
44 Windows,
45 {$ELSE}
46 unix,
47 {$ENDIF}
48 SysUtils, Classes, FPTimer, IBExternals, DB, IB, CustApp, IBTypes;
49
50 const
51 DPBPrefix = 'isc_dpb_';
52 DPBConstantNames: array[1..isc_dpb_last_dpb_constant] of string = (
53 'cdd_pathname',
54 'allocation',
55 'journal',
56 'page_size',
57 'num_buffers',
58 'buffer_length',
59 'debug',
60 'garbage_collect',
61 'verify',
62 'sweep',
63 'enable_journal',
64 'disable_journal',
65 'dbkey_scope',
66 'number_of_users',
67 'trace',
68 'no_garbage_collect',
69 'damaged',
70 'license',
71 'sys_user_name',
72 'encrypt_key',
73 'activate_shadow',
74 'sweep_interval',
75 'delete_shadow',
76 'force_write',
77 'begin_log',
78 'quit_log',
79 'no_reserve',
80 'user_name',
81 'password',
82 'password_enc',
83 'sys_user_name_enc',
84 'interp',
85 'online_dump',
86 'old_file_size',
87 'old_num_files',
88 'old_file',
89 'old_start_page',
90 'old_start_seqno',
91 'old_start_file',
92 'drop_walfile',
93 'old_dump_id',
94 'wal_backup_dir',
95 'wal_chkptlen',
96 'wal_numbufs',
97 'wal_bufsize',
98 'wal_grp_cmt_wait',
99 'lc_messages',
100 'lc_ctype',
101 'cache_manager',
102 'shutdown',
103 'online',
104 'shutdown_delay',
105 'reserved',
106 'overwrite',
107 'sec_attach',
108 'disable_wal',
109 'connect_timeout',
110 'dummy_packet_interval',
111 'gbak_attach',
112 'sql_role_name',
113 'set_page_buffers',
114 'working_directory',
115 'sql_dialect',
116 'set_db_readonly',
117 'set_db_sql_dialect',
118 'gfix_attach',
119 'gstat_attach',
120 'set_db_charset',
121 'gsec_attach',
122 'address_path' ,
123 'process_id',
124 'no_db_triggers',
125 'trusted_auth',
126 'process_name',
127 'trusted_role',
128 'org_filename',
129 'utf8_ilename',
130 'ext_call_depth'
131 );
132
133 TPBPrefix = 'isc_tpb_';
134 TPBConstantNames: array[1..isc_tpb_last_tpb_constant] of string = (
135 'consistency',
136 'concurrency',
137 'shared',
138 'protected',
139 'exclusive',
140 'wait',
141 'nowait',
142 'read',
143 'write',
144 'lock_read',
145 'lock_write',
146 'verb_time',
147 'commit_time',
148 'ignore_limbo',
149 'read_committed',
150 'autocommit',
151 'rec_version',
152 'no_rec_version',
153 'restart_requests',
154 'no_auto_undo',
155 'lock_timeout'
156 );
157
158 type
159
160 TIBDatabase = class;
161 TIBTransaction = class;
162 TIBBase = class;
163
164 TIBDatabaseLoginEvent = procedure(Database: TIBDatabase;
165 LoginParams: TStrings) of object;
166
167 TIBFileName = type string;
168 { TIBDatabase }
169 TIBDataBase = class(TCustomConnection)
170 private
171 FAttachment: IAttachment;
172 FCreateDatabase: boolean;
173 FCreateIfNotExists: boolean;
174 FDefaultCharSetID: integer;
175 FDefaultCharSetName: RawByteString;
176 FDefaultCodePage: TSystemCodePage;
177 FDPB: IDPB;
178 FAllowStreamedConnected: boolean;
179 FHiddenPassword: string;
180 FOnCreateDatabase: TNotifyEvent;
181 FOnLogin: TIBDatabaseLoginEvent;
182 FSQLHourGlass: Boolean;
183 FTraceFlags: TTraceFlags;
184 FDBSQLDialect: Integer;
185 FSQLDialect: Integer;
186 FOnDialectDowngradeWarning: TNotifyEvent;
187 FSQLObjects: TList;
188 FTransactions: TList;
189 FDBName: TIBFileName;
190 FDBParams: TStrings;
191 FDBParamsChanged: Boolean;
192 FOnIdleTimer: TNotifyEvent;
193 FDefaultTransaction: TIBTransaction;
194 FInternalTransaction: TIBTransaction;
195 FTimer: TFPTimer;
196 FUserNames: TStringList;
197 FDataSets: TList;
198 FLoginCalled: boolean;
199 FUseDefaultSystemCodePage: boolean;
200 procedure EnsureInactive;
201 function GetDBSQLDialect: Integer;
202 function GetSQLDialect: Integer;
203 procedure SetSQLDialect(const Value: Integer);
204 procedure ValidateClientSQLDialect;
205 procedure DBParamsChange(Sender: TObject);
206 procedure DBParamsChanging(Sender: TObject);
207 function GetSQLObject(Index: Integer): TIBBase;
208 function GetSQLObjectCount: Integer;
209 function GetIdleTimer: Integer;
210 function GetTransaction(Index: Integer): TIBTransaction;
211 function GetTransactionCount: Integer;
212 function Login(var aDatabaseName: string): Boolean;
213 procedure SetDatabaseName(const Value: TIBFileName);
214 procedure SetDBParamByDPB(const Idx: Integer; Value: String);
215 procedure SetDBParams(Value: TStrings);
216 procedure SetDefaultTransaction(Value: TIBTransaction);
217 procedure SetIdleTimer(Value: Integer);
218 procedure TimeoutConnection(Sender: TObject);
219 function GetIsReadOnly: Boolean;
220 function AddSQLObject(ds: TIBBase): Integer;
221 procedure RemoveSQLObject(Idx: Integer);
222 procedure RemoveSQLObjects;
223 procedure InternalClose(Force: Boolean);
224
225 protected
226 procedure DoConnect; override;
227 procedure DoDisconnect; override;
228 function GetConnected: Boolean; override;
229 procedure CheckStreamConnect;
230 procedure HandleException(Sender: TObject);
231 procedure Notification( AComponent: TComponent; Operation: TOperation); override;
232 function GetDataset(Index : longint) : TDataset; override;
233 function GetDataSetCount : Longint; override;
234 procedure ReadState(Reader: TReader); override;
235 procedure SetConnected (Value : boolean); override;
236 public
237 constructor Create(AOwner: TComponent); override;
238 destructor Destroy; override;
239 procedure ApplyUpdates(const DataSets: array of TDataSet);
240 procedure CloseDataSets;
241 procedure CheckActive;
242 procedure CheckInactive;
243 procedure CreateDatabase;
244 procedure DropDatabase;
245 procedure ForceClose;
246 procedure GetFieldNames(const TableName: string; List: TStrings);
247 procedure GetTableNames(List: TStrings; SystemTables: Boolean = False);
248 function IndexOfDBConst(st: String): Integer;
249 function TestConnected: Boolean;
250 procedure CheckDatabaseName;
251 function AddTransaction(TR: TIBTransaction): Integer;
252 function FindTransaction(TR: TIBTransaction): Integer;
253 function FindDefaultTransaction(): TIBTransaction;
254 procedure RemoveTransaction(Idx: Integer);
255 procedure RemoveTransactions;
256
257 property Attachment: IAttachment read FAttachment;
258 property DBSQLDialect : Integer read FDBSQLDialect;
259 property IsReadOnly: Boolean read GetIsReadOnly;
260 property SQLObjectCount: Integer read GetSQLObjectCount;
261 property SQLObjects[Index: Integer]: TIBBase read GetSQLObject;
262 property TransactionCount: Integer read GetTransactionCount;
263 property Transactions[Index: Integer]: TIBTransaction read GetTransaction;
264 property InternalTransaction: TIBTransaction read FInternalTransaction;
265 property DefaultCharSetName: RawByteString read FDefaultCharSetName;
266 property DefaultCharSetID: integer read FDefaultCharSetID;
267 property DefaultCodePage: TSystemCodePage read FDefaultCodePage;
268
269 published
270 property Connected;
271 property CreateIfNotExists: boolean read FCreateIfNotExists write FCreateIfNotExists;
272 property AllowStreamedConnected: boolean read FAllowStreamedConnected
273 write FAllowStreamedConnected;
274 property DatabaseName: TIBFileName read FDBName write SetDatabaseName;
275 property Params: TStrings read FDBParams write SetDBParams;
276 property LoginPrompt default True;
277 property DefaultTransaction: TIBTransaction read FDefaultTransaction
278 write SetDefaultTransaction;
279 property IdleTimer: Integer read GetIdleTimer write SetIdleTimer;
280 property SQLDialect : Integer read GetSQLDialect write SetSQLDialect default 3;
281 property SQLHourGlass: Boolean read FSQLHourGlass write FSQLHourGlass default true;
282 property TraceFlags: TTraceFlags read FTraceFlags write FTraceFlags;
283 property UseDefaultSystemCodePage: boolean read FUseDefaultSystemCodePage
284 write FUseDefaultSystemCodePage;
285 property AfterConnect;
286 property AfterDisconnect;
287 property BeforeConnect;
288 property BeforeDisconnect;
289 property OnCreateDatabase: TNotifyEvent read FOnCreateDatabase write FOnCreateDatabase;
290 property OnLogin: TIBDatabaseLoginEvent read FOnLogin write FOnLogin;
291 property OnIdleTimer: TNotifyEvent read FOnIdleTimer write FOnIdleTimer;
292 property OnDialectDowngradeWarning: TNotifyEvent read FOnDialectDowngradeWarning write FOnDialectDowngradeWarning;
293 end;
294
295 TDefaultEndAction = TARollback..TACommit;
296
297 { TIBTransaction }
298
299 TIBTransaction = class(TComponent)
300 private
301 FTransactionIntf: ITransaction;
302 FAfterDelete: TNotifyEvent;
303 FAfterEdit: TNotifyEvent;
304 FAfterExecQuery: TNotifyEvent;
305 FAfterInsert: TNotifyEvent;
306 FAfterPost: TNotifyEvent;
307 FAfterTransactionEnd: TNotifyEvent;
308 FBeforeTransactionEnd: TNotifyEvent;
309 FDatabases : TList;
310 FOnStartTransaction: TNotifyEvent;
311 FSQLObjects : TList;
312 FDefaultDatabase : TIBDatabase;
313 FOnIdleTimer : TNotifyEvent;
314 FStreamedActive : Boolean;
315 FTPB : ITPB;
316 FTimer : TFPTimer;
317 FDefaultAction : TDefaultEndAction;
318 FTRParams : TStrings;
319 FTRParamsChanged : Boolean;
320 FInEndTransaction : boolean;
321 FEndAction : TTransactionAction;
322 procedure DoBeforeTransactionEnd;
323 procedure DoAfterTransactionEnd;
324 procedure DoOnStartTransaction;
325 procedure DoAfterExecQuery(Sender: TObject);
326 procedure DoAfterEdit(Sender: TObject);
327 procedure DoAfterDelete(Sender: TObject);
328 procedure DoAfterInsert(Sender: TObject);
329 procedure DoAfterPost(Sender: TObject);
330 procedure EnsureNotInTransaction;
331 procedure EndTransaction(Action: TTransactionAction; Force: Boolean);
332 function GetDatabase(Index: Integer): TIBDatabase;
333 function GetDatabaseCount: Integer;
334 function GetSQLObject(Index: Integer): TIBBase;
335 function GetSQLObjectCount: Integer;
336 function GetInTransaction: Boolean;
337 function GetIdleTimer: Integer;
338 procedure BeforeDatabaseDisconnect(DB: TIBDatabase);
339 procedure SetActive(Value: Boolean);
340 procedure SetDefaultDatabase(Value: TIBDatabase);
341 procedure SetIdleTimer(Value: Integer);
342 procedure SetTRParams(Value: TStrings);
343 procedure TimeoutTransaction(Sender: TObject);
344 procedure TRParamsChange(Sender: TObject);
345 procedure TRParamsChanging(Sender: TObject);
346 function AddSQLObject(ds: TIBBase): Integer;
347 procedure RemoveSQLObject(Idx: Integer);
348 procedure RemoveSQLObjects;
349
350 protected
351 procedure Loaded; override;
352 procedure Notification( AComponent: TComponent; Operation: TOperation); override;
353
354 public
355 constructor Create(AOwner: TComponent); override;
356 destructor Destroy; override;
357 procedure Commit;
358 procedure CommitRetaining;
359 procedure Rollback;
360 procedure RollbackRetaining;
361 procedure StartTransaction;
362 procedure CheckInTransaction;
363 procedure CheckNotInTransaction;
364
365 function AddDatabase(db: TIBDatabase): Integer;
366 function FindDatabase(db: TIBDatabase): Integer;
367 function FindDefaultDatabase: TIBDatabase;
368 function GetEndAction: TTransactionAction;
369 procedure RemoveDatabase(Idx: Integer);
370 procedure RemoveDatabases;
371 procedure CheckDatabasesInList;
372
373 property DatabaseCount: Integer read GetDatabaseCount;
374 property Databases[Index: Integer]: TIBDatabase read GetDatabase;
375 property SQLObjectCount: Integer read GetSQLObjectCount;
376 property SQLObjects[Index: Integer]: TIBBase read GetSQLObject;
377 property InTransaction: Boolean read GetInTransaction;
378 property TransactionIntf: ITransaction read FTransactionIntf;
379 property TPB: ITPB read FTPB;
380 published
381 property Active: Boolean read GetInTransaction write SetActive;
382 property DefaultDatabase: TIBDatabase read FDefaultDatabase
383 write SetDefaultDatabase;
384 property IdleTimer: Integer read GetIdleTimer write SetIdleTimer default 0;
385 property DefaultAction: TDefaultEndAction read FDefaultAction write FDefaultAction default taCommit;
386 property Params: TStrings read FTRParams write SetTRParams;
387 property OnIdleTimer: TNotifyEvent read FOnIdleTimer write FOnIdleTimer;
388 property BeforeTransactionEnd: TNotifyEvent read FBeforeTransactionEnd
389 write FBeforeTransactionEnd;
390 property AfterTransactionEnd: TNotifyEvent read FAfterTransactionEnd
391 write FAfterTransactionEnd;
392 property OnStartTransaction: TNotifyEvent read FOnStartTransaction
393 write FOnStartTransaction;
394 property AfterExecQuery: TNotifyEvent read FAfterExecQuery
395 write FAfterExecQuery;
396 property AfterEdit: TNotifyEvent read FAfterEdit write FAfterEdit;
397 property AfterDelete: TNotifyEvent read FAfterDelete write FAfterDelete;
398 property AfterInsert: TNotifyEvent read FAfterInsert write FAfterInsert;
399 property AfterPost: TNotifyEvent read FAfterPost write FAfterPost;
400 end;
401
402 TTransactionEndEvent = procedure(Sender:TObject; Action: TTransactionAction) of object;
403 TBeforeDatabaseConnectEvent = procedure (Sender: TObject; DBParams: TStrings;
404 var DBName: string) of object;
405
406 { TIBBase }
407
408 { Virtually all components in IB are "descendents" of TIBBase.
409 It is to more easily manage the database and transaction
410 connections. }
411 TIBBase = class(TObject)
412 protected
413 FBeforeDatabaseConnect: TBeforeDatabaseConnectEvent;
414 FDatabase: TIBDatabase;
415 FIndexInDatabase: Integer;
416 FTransaction: TIBTransaction;
417 FIndexInTransaction: Integer;
418 FOwner: TObject;
419 FBeforeDatabaseDisconnect: TNotifyEvent;
420 FAfterDatabaseDisconnect: TNotifyEvent;
421 FAfterDatabaseConnect: TNotifyEvent;
422 FOnDatabaseFree: TNotifyEvent;
423 FBeforeTransactionEnd: TTransactionEndEvent;
424 FAfterTransactionEnd: TNotifyEvent;
425 FOnTransactionFree: TNotifyEvent;
426
427 procedure DoBeforeDatabaseConnect(DBParams: TStrings;
428 var DBName: string); virtual;
429 procedure DoAfterDatabaseConnect; virtual;
430 procedure DoBeforeDatabaseDisconnect; virtual;
431 procedure DoAfterDatabaseDisconnect; virtual;
432 procedure DoDatabaseFree; virtual;
433 procedure DoBeforeTransactionEnd(Action: TTransactionAction); virtual;
434 procedure DoAfterTransactionEnd; virtual;
435 procedure DoTransactionFree; virtual;
436 procedure SetDatabase(Value: TIBDatabase); virtual;
437 procedure SetTransaction(Value: TIBTransaction); virtual;
438 public
439 constructor Create(AOwner: TObject);
440 destructor Destroy; override;
441 procedure CheckDatabase; virtual;
442 procedure CheckTransaction; virtual;
443 procedure DoAfterExecQuery(Sender: TObject); virtual;
444 procedure DoAfterEdit(Sender: TObject); virtual;
445 procedure DoAfterDelete(Sender: TObject); virtual;
446 procedure DoAfterInsert(Sender: TObject); virtual;
447 procedure DoAfterPost(Sender: TObject); virtual;
448 procedure HandleException(Sender: TObject);
449 procedure SetCursor;
450 procedure RestoreCursor;
451 public
452 property BeforeDatabaseConnect: TBeforeDatabaseConnectEvent read FBeforeDatabaseConnect
453 write FBeforeDatabaseConnect;
454 property AfterDatabaseConnect: TNotifyEvent read FAfterDatabaseConnect
455 write FAfterDatabaseConnect;
456 property BeforeDatabaseDisconnect: TNotifyEvent read FBeforeDatabaseDisconnect
457 write FBeforeDatabaseDisconnect;
458 property AfterDatabaseDisconnect: TNotifyEvent read FAfterDatabaseDisconnect
459 write FAfterDatabaseDisconnect;
460 property OnDatabaseFree: TNotifyEvent read FOnDatabaseFree write FOnDatabaseFree;
461 property BeforeTransactionEnd: TTransactionEndEvent read FBeforeTransactionEnd write FBeforeTransactionEnd;
462 property AfterTransactionEnd: TNotifyEvent read FAfterTransactionEnd write FAfterTransactionEnd;
463 property OnTransactionFree: TNotifyEvent read FOnTransactionFree write FOnTransactionFree;
464 property Database: TIBDatabase read FDatabase
465 write SetDatabase;
466 property Owner: TObject read FOwner;
467 property Transaction: TIBTransaction read FTransaction
468 write SetTransaction;
469 end;
470
471 function GenerateDPB(sl: TStrings): IDPB;
472 function GenerateTPB(sl: TStrings): ITPB;
473
474
475 implementation
476
477 uses IBSQLMonitor, IBCustomDataSet, IBDatabaseInfo, IBSQL, IBUtils,
478 typInfo, FBMessages, IBErrorCodes;
479
480 { TIBDatabase }
481
482 constructor TIBDataBase.Create(AOwner: TComponent);
483 begin
484 inherited Create(AOwner);
485 LoginPrompt := True;
486 FSQLObjects := TList.Create;
487 FTransactions := TList.Create;
488 FDBName := '';
489 FDBParams := TStringList.Create;
490 FSQLHourGlass := true;
491 if (AOwner <> nil) and
492 (AOwner is TCustomApplication) and
493 TCustomApplication(AOWner).ConsoleApplication then
494 LoginPrompt := false;
495 FDBParamsChanged := True;
496 TStringList(FDBParams).OnChange := DBParamsChange;
497 TStringList(FDBParams).OnChanging := DBParamsChanging;
498 FDPB := nil;
499 FUserNames := nil;
500 FInternalTransaction := TIBTransaction.Create(self);
501 FInternalTransaction.DefaultDatabase := Self;
502 FTimer := TFPTimer.Create(Self);
503 FTimer.Enabled := False;
504 FTimer.Interval := 0;
505 FTimer.OnTimer := TimeoutConnection;
506 FDBSQLDialect := 1;
507 FSQLDialect := 3;
508 FTraceFlags := [];
509 FDataSets := TList.Create;
510 CheckStreamConnect;
511 end;
512
513 destructor TIBDataBase.Destroy;
514 var
515 i: Integer;
516 begin
517 IdleTimer := 0;
518 if FAttachment <> nil then
519 ForceClose;
520 for i := 0 to FSQLObjects.Count - 1 do
521 if FSQLObjects[i] <> nil then
522 SQLObjects[i].DoDatabaseFree;
523 RemoveSQLObjects;
524 RemoveTransactions;
525 FInternalTransaction.Free;
526 FDPB := nil;
527 FDBParams.Free;
528 FSQLObjects.Free;
529 FUserNames.Free;
530 FTransactions.Free;
531 FDataSets.Free;
532 inherited Destroy;
533 end;
534
535 procedure TIBDataBase.CheckActive;
536 begin
537 if StreamedConnected and (not Connected) then
538 Loaded;
539 if FAttachment = nil then
540 IBError(ibxeDatabaseClosed, [nil]);
541 end;
542
543 procedure TIBDataBase.EnsureInactive;
544 begin
545 if csDesigning in ComponentState then
546 begin
547 if FAttachment <> nil then
548 Close;
549 end
550 end;
551
552 procedure TIBDataBase.CheckInactive;
553 begin
554 if FAttachment <> nil then
555 IBError(ibxeDatabaseOpen, [nil]);
556 end;
557
558 procedure TIBDataBase.CheckDatabaseName;
559 begin
560 if (Trim(FDBName) = '') then
561 IBError(ibxeDatabaseNameMissing, [nil]);
562 end;
563
564 function TIBDataBase.AddSQLObject(ds: TIBBase): Integer;
565 begin
566 result := 0;
567 if (ds.Owner is TIBCustomDataSet) then
568 FDataSets.Add(ds.Owner);
569 while (result < FSQLObjects.Count) and (FSQLObjects[result] <> nil) do
570 Inc(result);
571 if (result = FSQLObjects.Count) then
572 FSQLObjects.Add(ds)
573 else
574 FSQLObjects[result] := ds;
575 end;
576
577 function TIBDataBase.AddTransaction(TR: TIBTransaction): Integer;
578 begin
579 result := FindTransaction(TR);
580 if result <> -1 then
581 begin
582 result := -1;
583 exit;
584 end;
585 result := 0;
586 while (result < FTransactions.Count) and (FTransactions[result] <> nil) do
587 Inc(result);
588 if (result = FTransactions.Count) then
589 FTransactions.Add(TR)
590 else
591 FTransactions[result] := TR;
592 end;
593
594 procedure TIBDataBase.DoDisconnect;
595 begin
596 if Connected then
597 InternalClose(False);
598 FDBSQLDialect := 1;
599 FDefaultCharSetName := '';
600 FDefaultCharSetID := 0;
601 FDefaultCodePage := CP_NONE;
602 end;
603
604 procedure TIBDataBase.CreateDatabase;
605 begin
606 CheckInactive;
607 CheckDatabaseName;
608 FCreateDatabase := true;
609 Connected := true;
610 end;
611
612 procedure TIBDataBase.DropDatabase;
613 begin
614 CheckActive;
615 FAttachment.DropDatabase;
616 FAttachment := nil;
617 end;
618
619 procedure TIBDataBase.DBParamsChange(Sender: TObject);
620 begin
621 FDBParamsChanged := True;
622 end;
623
624 procedure TIBDataBase.DBParamsChanging(Sender: TObject);
625 begin
626 EnsureInactive;
627 CheckInactive;
628 end;
629
630 function TIBDataBase.FindTransaction(TR: TIBTransaction): Integer;
631 var
632 i: Integer;
633 begin
634 result := -1;
635 for i := 0 to FTransactions.Count - 1 do
636 if TR = Transactions[i] then
637 begin
638 result := i;
639 break;
640 end;
641 end;
642
643 function TIBDataBase.FindDefaultTransaction: TIBTransaction;
644 var
645 i: Integer;
646 begin
647 result := FDefaultTransaction;
648 if result = nil then
649 begin
650 for i := 0 to FTransactions.Count - 1 do
651 if (Transactions[i] <> nil) and
652 (TIBTransaction(Transactions[i]).DefaultDatabase = self) and
653 (TIBTransaction(Transactions[i]) <> FInternalTransaction) then
654 begin
655 result := TIBTransaction(Transactions[i]);
656 break;
657 end;
658 end;
659 end;
660
661 procedure TIBDataBase.ForceClose;
662 begin
663 if Connected then
664 InternalClose(True);
665 end;
666
667 function TIBDataBase.GetConnected: Boolean;
668 begin
669 result := (FAttachment <> nil) and FAttachment.IsConnected;
670 end;
671
672 function TIBDataBase.GetSQLObject(Index: Integer): TIBBase;
673 begin
674 result := FSQLObjects[Index];
675 end;
676
677 function TIBDataBase.GetSQLObjectCount: Integer;
678 var
679 i: Integer;
680 begin
681 result := 0;
682 for i := 0 to FSQLObjects.Count - 1 do if FSQLObjects[i] <> nil then
683 Inc(result);
684 end;
685
686 function TIBDataBase.GetIdleTimer: Integer;
687 begin
688 result := FTimer.Interval;
689 end;
690
691 function TIBDataBase.GetTransaction(Index: Integer): TIBTransaction;
692 begin
693 result := FTransactions[Index];
694 end;
695
696 function TIBDataBase.GetTransactionCount: Integer;
697 var
698 i: Integer;
699 begin
700 result := 0;
701 for i := 0 to FTransactions.Count - 1 do
702 if FTransactions[i] <> nil then
703 Inc(result);
704 end;
705
706 function TIBDataBase.IndexOfDBConst(st: String): Integer;
707 var
708 i, pos_of_str: Integer;
709 begin
710 result := -1;
711 for i := 0 to Params.Count - 1 do
712 begin
713 pos_of_str := Pos(st, AnsiLowerCase(Params[i])); {mbcs ok}
714 if (pos_of_str = 1) or (pos_of_str = Length(DPBPrefix) + 1) then
715 begin
716 result := i;
717 break;
718 end;
719 end;
720 end;
721
722 procedure TIBDataBase.InternalClose(Force: Boolean);
723 var
724 i: Integer;
725 begin
726 CheckActive;
727 { Tell all connected transactions that we're disconnecting.
728 This is so transactions can commit/rollback, accordingly
729 }
730 for i := 0 to FTransactions.Count - 1 do
731 begin
732 try
733 if FTransactions[i] <> nil then
734 Transactions[i].BeforeDatabaseDisconnect(Self);
735 except
736 if not Force then
737 raise;
738 end;
739 end;
740 for i := 0 to FSQLObjects.Count - 1 do
741 begin
742 try
743 if FSQLObjects[i] <> nil then
744 SQLObjects[i].DoBeforeDatabaseDisconnect;
745 except
746 if not Force then
747 raise;
748 end;
749 end;
750
751 FAttachment.Disconnect(Force);
752 FAttachment := nil;
753
754 if not (csDesigning in ComponentState) then
755 MonitorHook.DBDisconnect(Self);
756
757 for i := 0 to FSQLObjects.Count - 1 do
758 if FSQLObjects[i] <> nil then
759 SQLObjects[i].DoAfterDatabaseDisconnect;
760 end;
761
762 procedure TIBDataBase.CheckStreamConnect;
763 var
764 i: integer;
765 begin
766 try
767 if not (csDesigning in ComponentState) and StreamedConnected and (not Connected) then
768 begin
769 for i := 0 to FTransactions.Count - 1 do
770 if FTransactions[i] <> nil then
771 begin
772 with TIBTransaction(FTransactions[i]) do
773 if not Active then
774 if FStreamedActive and not InTransaction then
775 begin
776 StartTransaction;
777 FStreamedActive := False;
778 end;
779 end;
780 if (FDefaultTransaction <> nil) and
781 (FDefaultTransaction.FStreamedActive) and
782 (not FDefaultTransaction.InTransaction) then
783 FDefaultTransaction.StartTransaction;
784 StreamedConnected := False;
785 end;
786 except
787 if csDesigning in ComponentState then
788 HandleException(Self)
789 else
790 raise;
791 end;
792 end;
793
794 procedure TIBDataBase.HandleException(Sender: TObject);
795 var aParent: TComponent;
796 begin
797 aParent := Owner;
798 while aParent <> nil do
799 begin
800 if aParent is TCustomApplication then
801 begin
802 TCustomApplication(aParent).HandleException(Sender);
803 Exit;
804 end;
805 aParent := aParent.Owner;
806 end;
807 SysUtils.ShowException(ExceptObject,ExceptAddr);
808 end;
809
810 procedure TIBDataBase.Notification(AComponent: TComponent;
811 Operation: TOperation);
812 var
813 i: Integer;
814 begin
815 inherited Notification( AComponent, Operation);
816 if (Operation = opRemove) and (AComponent = FDefaultTransaction) then
817 begin
818 i := FindTransaction(FDefaultTransaction);
819 if (i <> -1) then
820 RemoveTransaction(i);
821 FDefaultTransaction := nil;
822 end;
823 end;
824
825 function TIBDataBase.Login(var aDatabaseName: string): Boolean;
826 var
827 IndexOfUser, IndexOfPassword: Integer;
828 Username, Password, OldPassword: String;
829 LoginParams: TStrings;
830
831 procedure HidePassword;
832 var
833 I: Integer;
834 IndexAt: Integer;
835 begin
836 IndexAt := 0;
837 for I := 0 to Params.Count -1 do
838 if Pos('password', LowerCase(Trim(Params.Names[i]))) = 1 then {mbcs ok}
839 begin
840 FHiddenPassword := Params.Values[Params.Names[i]];
841 IndexAt := I;
842 break;
843 end;
844 if IndexAt <> 0 then
845 Params.Delete(IndexAt);
846 end;
847
848 begin
849 Result := false;
850 if FLoginCalled then Exit;
851 FLoginCalled := true;
852 try
853 if Assigned(FOnLogin) and not (csDesigning in ComponentState) then
854 begin
855 result := True;
856 LoginParams := TStringList.Create;
857 try
858 LoginParams.Assign(Params);
859 FOnLogin(Self, LoginParams);
860 Params.Assign (LoginParams);
861 aDatabaseName := FDBName;
862 HidePassword;
863 finally
864 LoginParams.Free;
865 end;
866 end
867 else
868 if assigned(IBGUIInterface) then
869 begin
870 IndexOfUser := IndexOfDBConst(DPBConstantNames[isc_dpb_user_name]);
871 if IndexOfUser <> -1 then
872 Username := Copy(Params[IndexOfUser],
873 Pos('=', Params[IndexOfUser]) + 1, {mbcs ok}
874 Length(Params[IndexOfUser]));
875 IndexOfPassword := IndexOfDBConst(DPBConstantNames[isc_dpb_password]);
876 if IndexOfPassword <> -1 then
877 begin
878 Password := Copy(Params[IndexOfPassword],
879 Pos('=', Params[IndexOfPassword]) + 1, {mbcs ok}
880 Length(Params[IndexOfPassword]));
881 OldPassword := password;
882 end;
883
884 result := IBGUIInterface.LoginDialogEx(aDatabaseName, Username, Password, False);
885 if result then
886 begin
887 if Username <> '' then
888 begin
889 if IndexOfUser = -1 then
890 Params.Add(DPBConstantNames[isc_dpb_user_name] + '=' + Username)
891 else
892 Params[IndexOfUser] := DPBConstantNames[isc_dpb_user_name] +
893 '=' + Username;
894 end
895 else
896 if IndexOfUser <> -1 then
897 Params.Delete(IndexOfUser);
898 if (Password = OldPassword) then
899 FHiddenPassword := ''
900 else
901 begin
902 FHiddenPassword := Password;
903 if OldPassword <> '' then
904 HidePassword;
905 end;
906 end;
907 end
908 else
909 if LoginPrompt then
910 IBError(ibxeNoLoginDialog,[]);
911 finally
912 FLoginCalled := false
913 end;
914 end;
915
916 procedure TIBDataBase.DoConnect;
917 var
918 TempDBParams: TStrings;
919 I: integer;
920 aDBName: string;
921 Status: IStatus;
922 CharSetID: integer;
923 begin
924 CheckInactive;
925 CheckDatabaseName;
926 if (not LoginPrompt) and (FHiddenPassword <> '') then
927 begin
928 FHiddenPassword := '';
929 FDBParamsChanged := True;
930 end;
931 { Use builtin login prompt if requested }
932 aDBName := FDBName;
933 if (LoginPrompt or (csDesigning in ComponentState)) and not Login(aDBName) then
934 IBError(ibxeOperationCancelled, [nil]);
935
936 TempDBParams := TStringList.Create;
937 try
938 TempDBParams.Assign(FDBParams);
939 if UseDefaultSystemCodePage then
940 begin
941 {$ifdef WINDOWS}
942 if FirebirdAPI.CodePage2CharSetID(GetACP,CharSetID) then
943 TempDBParams.Values['lc_ctype'] := FirebirdAPI.GetCharsetName(CharSetID)
944 {$else}
945 if FirebirdAPI.CodePage2CharSetID(DefaultSystemCodePage,CharSetID) then
946 TempDBParams.Values['lc_ctype'] := FirebirdAPI.GetCharsetName(CharSetID)
947 {$endif}
948 else
949 TempDBParams.Values['lc_ctype'] :='UTF8';
950 end;
951 {Opportunity to override defaults}
952 for i := 0 to FSQLObjects.Count - 1 do
953 begin
954 if FSQLObjects[i] <> nil then
955 SQLObjects[i].DoBeforeDatabaseConnect(TempDBParams,aDBName);
956 end;
957
958 FDefaultCharSetName := AnsiUpperCase(TempDBParams.Values['lc_ctype']);
959 if FDefaultCharSetName <> '' then
960 FirebirdAPI.CharSetName2CharSetID(FDefaultCharSetName,FDefaultCharSetID);
961 FirebirdAPI.CharSetID2CodePage(FDefaultCharSetID,FDefaultCodePage);
962 { Generate a new DPB if necessary }
963 if (FDBParamsChanged or (TempDBParams.Text <> FDBParams.Text)) then
964 begin
965 FDBParamsChanged := False;
966 if (not LoginPrompt and not (csDesigning in ComponentState)) or (FHiddenPassword = '') then
967 FDPB := GenerateDPB(TempDBParams)
968 else
969 begin
970 TempDBParams.Add('password=' + FHiddenPassword);
971 FDPB := GenerateDPB(TempDBParams);
972 end;
973 end;
974 finally
975 TempDBParams.Free;
976 end;
977
978 repeat
979 if FCreateDatabase then
980 begin
981 FCreateDatabase := false;
982 FAttachment := FirebirdAPI.CreateDatabase(aDBName,FDPB, false);
983 if assigned(FOnCreateDatabase) and (FAttachment <> nil) then
984 OnCreateDatabase(self);
985 end
986 else
987 FAttachment := FirebirdAPI.OpenDatabase(aDBName,FDPB,false);
988 if FAttachment = nil then
989 begin
990 Status := FirebirdAPI.GetStatus;
991 {$IFDEF UNIX}
992 if Pos(':',aDBName) = 0 then
993 begin
994 if ((Status.GetSQLCode = -901) and (Status.GetIBErrorCode = isc_random)) {Access permissions on firebird temp}
995 or
996 ((Status.GetSQLCode = -902) and (Status.GetIBErrorCode = isc_sys_request)) {Security DB Problem}
997 or
998 ((Status.GetSQLCode = -902) and (Status.GetIBErrorCode = isc_psw_attach)) {Security DB Problem}
999 or
1000 ((Status.GetSQLCode = -904) and (Status.GetIBErrorCode = isc_lock_dir_access)) {Lock File Problem}
1001 then
1002 begin
1003 aDBName := 'localhost:' + aDBName;
1004 Continue;
1005 end
1006 end;
1007 {$ENDIF}
1008 if ((Status.GetSQLCode = -902) and (Status.GetIBErrorCode = isc_io_error)) {Database not found}
1009 and CreateIfNotExists and not (csDesigning in ComponentState) then
1010 FCreateDatabase := true
1011 else
1012 raise EIBInterBaseError.Create(Status);
1013 end;
1014 until FAttachment <> nil;
1015 if not (csDesigning in ComponentState) then
1016 FDBName := aDBName; {Synchronise at run time}
1017 FDBSQLDialect := GetDBSQLDialect;
1018 ValidateClientSQLDialect;
1019 for i := 0 to FSQLObjects.Count - 1 do
1020 begin
1021 if FSQLObjects[i] <> nil then
1022 SQLObjects[i].DoAfterDatabaseConnect;
1023 end;
1024 if not (csDesigning in ComponentState) then
1025 MonitorHook.DBConnect(Self);
1026 end;
1027
1028 procedure TIBDataBase.RemoveSQLObject(Idx: Integer);
1029 var
1030 ds: TIBBase;
1031 begin
1032 if (Idx >= 0) and (FSQLObjects[Idx] <> nil) then
1033 begin
1034 ds := SQLObjects[Idx];
1035 FSQLObjects[Idx] := nil;
1036 ds.Database := nil;
1037 if (ds.owner is TDataSet) then
1038 FDataSets.Remove(TDataSet(ds.Owner));
1039 end;
1040 end;
1041
1042 procedure TIBDataBase.RemoveSQLObjects;
1043 var
1044 i: Integer;
1045 begin
1046 for i := 0 to FSQLObjects.Count - 1 do if FSQLObjects[i] <> nil then
1047 begin
1048 RemoveSQLObject(i);
1049 if (TIBBase(FSQLObjects[i]).owner is TDataSet) then
1050 FDataSets.Remove(TDataSet(TIBBase(FSQLObjects[i]).owner));
1051 end;
1052 end;
1053
1054 procedure TIBDataBase.RemoveTransaction(Idx: Integer);
1055 var
1056 TR: TIBTransaction;
1057 begin
1058 if ((Idx >= 0) and (FTransactions[Idx] <> nil)) then
1059 begin
1060 TR := Transactions[Idx];
1061 FTransactions[Idx] := nil;
1062 TR.RemoveDatabase(TR.FindDatabase(Self));
1063 if TR = FDefaultTransaction then
1064 FDefaultTransaction := nil;
1065 end;
1066 end;
1067
1068 procedure TIBDataBase.RemoveTransactions;
1069 var
1070 i: Integer;
1071 begin
1072 for i := 0 to FTransactions.Count - 1 do if FTransactions[i] <> nil then
1073 RemoveTransaction(i);
1074 end;
1075
1076 procedure TIBDataBase.SetDatabaseName( const Value: TIBFileName);
1077 begin
1078 if FDBName <> Value then
1079 begin
1080 EnsureInactive;
1081 CheckInactive;
1082 FDBName := Value;
1083 end;
1084 end;
1085
1086 procedure TIBDataBase.SetDBParamByDPB( const Idx: Integer; Value: String);
1087 var
1088 ConstIdx: Integer;
1089 begin
1090 ConstIdx := IndexOfDBConst(DPBConstantNames[Idx]);
1091 if (Value = '') then
1092 begin
1093 if ConstIdx <> -1 then
1094 Params.Delete(ConstIdx);
1095 end
1096 else
1097 begin
1098 if (ConstIdx = -1) then
1099 Params.Add(DPBConstantNames[Idx] + '=' + Value)
1100 else
1101 Params[ConstIdx] := DPBConstantNames[Idx] + '=' + Value;
1102 end;
1103 end;
1104
1105 procedure TIBDataBase.SetDBParams(Value: TStrings);
1106 begin
1107 FDBParams.Assign(Value);
1108 end;
1109
1110 procedure TIBDataBase.SetDefaultTransaction(Value: TIBTransaction);
1111 var
1112 i: Integer;
1113 begin
1114 if (FDefaultTransaction <> nil) and (FDefaultTransaction <> Value) then
1115 begin
1116 i := FindTransaction(FDefaultTransaction);
1117 if (i <> -1) and (FDefaultTransaction.DefaultDatabase <> self) then
1118 RemoveTransaction(i);
1119 end;
1120 if (Value <> nil) and (FDefaultTransaction <> Value) then
1121 begin
1122 Value.AddDatabase(Self);
1123 AddTransaction(Value);
1124 end;
1125 FDefaultTransaction := Value;
1126 end;
1127
1128 procedure TIBDataBase.SetIdleTimer(Value: Integer);
1129 begin
1130 if Value < 0 then
1131 IBError(ibxeTimeoutNegative, [nil])
1132 else
1133 if (Value = 0) then
1134 begin
1135 FTimer.Enabled := False;
1136 FTimer.Interval := 0;
1137 end
1138 else
1139 if (Value > 0) then
1140 begin
1141 FTimer.Interval := Value;
1142 if not (csDesigning in ComponentState) then
1143 FTimer.Enabled := True;
1144 end;
1145 end;
1146
1147 function TIBDataBase.TestConnected: Boolean;
1148 var
1149 DatabaseInfo: TIBDatabaseInfo;
1150 begin
1151 result := Connected;
1152 if result then
1153 begin
1154 DatabaseInfo := TIBDatabaseInfo.Create(self);
1155 try
1156 DatabaseInfo.Database := self;
1157 { poke the server to see if connected }
1158 if DatabaseInfo.BaseLevel = 0 then ;
1159 DatabaseInfo.Free;
1160 except
1161 ForceClose;
1162 result := False;
1163 DatabaseInfo.Free;
1164 end;
1165 end;
1166 end;
1167
1168 procedure TIBDataBase.TimeoutConnection(Sender: TObject);
1169 begin
1170 if Connected then
1171 begin
1172 if not FAttachment.HasActivity then
1173 begin
1174 ForceClose;
1175 if Assigned(FOnIdleTimer) then
1176 FOnIdleTimer(Self);
1177 end
1178 end;
1179 end;
1180
1181 function TIBDataBase.GetIsReadOnly: Boolean;
1182 var
1183 DatabaseInfo: TIBDatabaseInfo;
1184 begin
1185 DatabaseInfo := TIBDatabaseInfo.Create(self);
1186 DatabaseInfo.Database := self;
1187 if (DatabaseInfo.ODSMajorVersion < 10) then
1188 result := false
1189 else
1190 begin
1191 if (DatabaseInfo.ReadOnly = 0) then
1192 result := false
1193 else
1194 result := true;
1195 end;
1196 DatabaseInfo.Free;
1197 end;
1198
1199 function TIBDataBase.GetSQLDialect: Integer;
1200 begin
1201 Result := FSQLDialect;
1202 end;
1203
1204
1205 procedure TIBDataBase.SetSQLDialect( const Value: Integer);
1206 begin
1207 if (Value < 1) then IBError(ibxeSQLDialectInvalid, [nil]);
1208 if ((FAttachment = nil) or (Value <= FDBSQLDialect)) then
1209 FSQLDialect := Value
1210 else
1211 IBError(ibxeSQLDialectInvalid, [nil]);
1212 end;
1213
1214 function TIBDataBase.GetDBSQLDialect: Integer;
1215 var
1216 DatabaseInfo: TIBDatabaseInfo;
1217 begin
1218 DatabaseInfo := TIBDatabaseInfo.Create(self);
1219 DatabaseInfo.Database := self;
1220 result := DatabaseInfo.DBSQLDialect;
1221 DatabaseInfo.Free;
1222 end;
1223
1224 procedure TIBDataBase.ValidateClientSQLDialect;
1225 begin
1226 if (FDBSQLDialect < FSQLDialect) then
1227 begin
1228 FSQLDialect := FDBSQLDialect;
1229 if Assigned (FOnDialectDowngradeWarning) then
1230 FOnDialectDowngradeWarning(self);
1231 end;
1232 end;
1233
1234 procedure TIBDataBase.ApplyUpdates( const DataSets: array of TDataSet);
1235 var
1236 I: Integer;
1237 DS: TIBCustomDataSet;
1238 TR: TIBTransaction;
1239 begin
1240 TR := nil;
1241 for I := 0 to High(DataSets) do
1242 begin
1243 DS := TIBCustomDataSet(DataSets[I]);
1244 if DS.Database <> Self then
1245 IBError(ibxeUpdateWrongDB, [nil]);
1246 if TR = nil then
1247 TR := DS.Transaction;
1248 if (DS.Transaction <> TR) or (TR = nil) then
1249 IBError(ibxeUpdateWrongTR, [nil]);
1250 end;
1251 TR.CheckInTransaction;
1252 for I := 0 to High(DataSets) do
1253 begin
1254 DS := TIBCustomDataSet(DataSets[I]);
1255 DS.ApplyUpdates;
1256 end;
1257 TR.CommitRetaining;
1258 end;
1259
1260 procedure TIBDataBase.CloseDataSets;
1261 var
1262 i: Integer;
1263 begin
1264 for i := 0 to DataSetCount - 1 do
1265 if (DataSets[i] <> nil) then
1266 DataSets[i].close;
1267 end;
1268
1269 function TIBDataBase.GetDataset(Index: longint): TDataset;
1270 begin
1271 if (Index >= 0) and (Index < FDataSets.Count) then
1272 Result := TDataSet(FDataSets[Index])
1273 else
1274 raise Exception.Create('Invalid Index to DataSets');
1275 end;
1276
1277 function TIBDataBase.GetDataSetCount: Longint;
1278 begin
1279 Result := FDataSets.Count;
1280 end;
1281
1282 procedure TIBDataBase.ReadState(Reader: TReader);
1283 begin
1284 FDBParams.Clear;
1285 inherited ReadState(Reader);
1286 end;
1287
1288 procedure TIBDataBase.SetConnected(Value: boolean);
1289 begin
1290 if StreamedConnected and not AllowStreamedConnected then
1291 begin
1292 StreamedConnected := false;
1293 Value := false
1294 end;
1295 inherited SetConnected(Value);
1296 end;
1297
1298 procedure TIBDataBase.GetFieldNames( const TableName: string; List: TStrings);
1299 var
1300 Query: TIBSQL;
1301 begin
1302 if TableName = '' then
1303 IBError(ibxeNoTableName, [nil]);
1304 if not Connected then
1305 Open;
1306 if not FInternalTransaction.Active then
1307 FInternalTransaction.StartTransaction;
1308 Query := TIBSQL.Create(self);
1309 try
1310 Query.GoToFirstRecordOnExecute := False;
1311 Query.Database := Self;
1312 Query.Transaction := FInternalTransaction;
1313 Query.SQL.Text := 'Select R.RDB$FIELD_NAME ' + {do not localize}
1314 'from RDB$RELATION_FIELDS R, RDB$FIELDS F ' + {do not localize}
1315 'where R.RDB$RELATION_NAME = ' + {do not localize}
1316 '''' +
1317 FormatIdentifierValue(SQLDialect, TableName) +
1318 ''' ' +
1319 'and R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME '; {do not localize}
1320 Query.Prepare;
1321 Query.ExecQuery;
1322 with List do
1323 begin
1324 BeginUpdate;
1325 try
1326 Clear;
1327 while (not Query.EOF) and Query.Next do
1328 List.Add(TrimRight(Query.FieldByName('RDB$FIELD_NAME').AsString)); {do not localize}
1329 finally
1330 EndUpdate;
1331 end;
1332 end;
1333 finally
1334 Query.free;
1335 FInternalTransaction.Commit;
1336 end;
1337 end;
1338
1339 procedure TIBDataBase.GetTableNames(List: TStrings; SystemTables: Boolean);
1340 var
1341 Query : TIBSQL;
1342 begin
1343 if not (csReading in ComponentState) then
1344 begin
1345 if not Connected then
1346 Open;
1347 if not FInternalTransaction.Active then
1348 FInternalTransaction.StartTransaction;
1349 Query := TIBSQL.Create(self);
1350 try
1351 Query.GoToFirstRecordOnExecute := False;
1352 Query.Database := Self;
1353 Query.Transaction := FInternalTransaction;
1354 if SystemTables then
1355 Query.SQL.Text := 'Select RDB$RELATION_NAME from RDB$RELATIONS' + {do not localize}
1356 ' where RDB$VIEW_BLR is NULL' {do not localize}
1357 else
1358 Query.SQL.Text := 'Select RDB$RELATION_NAME from RDB$RELATIONS' + {do not localize}
1359 ' where RDB$VIEW_BLR is NULL and RDB$SYSTEM_FLAG = 0'; {do not localize}
1360 Query.Prepare;
1361 Query.ExecQuery;
1362 with List do
1363 begin
1364 BeginUpdate;
1365 try
1366 Clear;
1367 while (not Query.EOF) and Query.Next do
1368 List.Add(TrimRight(Query.Fields[0].AsString));
1369 finally
1370 EndUpdate;
1371 end;
1372 end;
1373 finally
1374 Query.Free;
1375 FInternalTransaction.Commit;
1376 end;
1377 end;
1378 end;
1379
1380 { TIBTransaction }
1381
1382 constructor TIBTransaction.Create(AOwner: TComponent);
1383 begin
1384 inherited Create(AOwner);
1385 FDatabases := TList.Create;
1386 FSQLObjects := TList.Create;
1387 FTPB := nil;
1388 FTRParams := TStringList.Create;
1389 FTRParamsChanged := True;
1390 TStringList(FTRParams).OnChange := TRParamsChange;
1391 TStringList(FTRParams).OnChanging := TRParamsChanging;
1392 FTimer := TFPTimer.Create(Self);
1393 FTimer.Enabled := False;
1394 FTimer.Interval := 0;
1395 FTimer.OnTimer := TimeoutTransaction;
1396 FDefaultAction := taCommit;
1397 end;
1398
1399 destructor TIBTransaction.Destroy;
1400 var
1401 i: Integer;
1402 begin
1403 if InTransaction then
1404 EndTransaction(FDefaultAction, True);
1405 for i := 0 to FSQLObjects.Count - 1 do
1406 if FSQLObjects[i] <> nil then
1407 SQLObjects[i].DoTransactionFree;
1408 RemoveSQLObjects;
1409 RemoveDatabases;
1410 FTPB := nil;
1411 FTRParams.Free;
1412 FSQLObjects.Free;
1413 FDatabases.Free;
1414 inherited Destroy;
1415 end;
1416
1417 procedure TIBTransaction.CheckDatabasesInList;
1418 begin
1419 if GetDatabaseCount = 0 then
1420 IBError(ibxeNoDatabasesInTransaction, [nil]);
1421 end;
1422
1423 procedure TIBTransaction.CheckInTransaction;
1424 begin
1425 if FStreamedActive and (not InTransaction) then
1426 Loaded;
1427 if (TransactionIntf = nil) then
1428 IBError(ibxeNotInTransaction, [nil]);
1429 end;
1430
1431 procedure TIBTransaction.DoBeforeTransactionEnd;
1432 begin
1433 if Assigned(FBeforeTransactionEnd) then
1434 FBeforeTransactionEnd(self);
1435 end;
1436
1437 procedure TIBTransaction.DoAfterTransactionEnd;
1438 begin
1439 if Assigned(FAfterTransactionEnd) then
1440 FAfterTransactionEnd(self);
1441 end;
1442
1443 procedure TIBTransaction.DoOnStartTransaction;
1444 begin
1445 if assigned(FOnStartTransaction) then
1446 OnStartTransaction(self);
1447 end;
1448
1449 procedure TIBTransaction.DoAfterExecQuery(Sender: TObject);
1450 begin
1451 if assigned(FAfterExecQuery) then
1452 AfterExecQuery(Sender);
1453 end;
1454
1455 procedure TIBTransaction.DoAfterEdit(Sender: TObject);
1456 begin
1457 if assigned(FAfterEdit) then
1458 AfterEdit(Sender);
1459 end;
1460
1461 procedure TIBTransaction.DoAfterDelete(Sender: TObject);
1462 begin
1463 if assigned(FAfterDelete) then
1464 AfterDelete(Sender);
1465 end;
1466
1467 procedure TIBTransaction.DoAfterInsert(Sender: TObject);
1468 begin
1469 if assigned(FAfterInsert) then
1470 AfterInsert(Sender);
1471 end;
1472
1473 procedure TIBTransaction.DoAfterPost(Sender: TObject);
1474 begin
1475 if assigned(FAfterPost) then
1476 AfterPost(Sender);
1477 end;
1478
1479 procedure TIBTransaction.EnsureNotInTransaction;
1480 begin
1481 if csDesigning in ComponentState then
1482 begin
1483 if TransactionIntf <> nil then
1484 Rollback;
1485 end;
1486 end;
1487
1488 procedure TIBTransaction.CheckNotInTransaction;
1489 begin
1490 if (TransactionIntf <> nil) and TransactionIntf.InTransaction then
1491 IBError(ibxeInTransaction, [nil]);
1492 end;
1493
1494 function TIBTransaction.AddDatabase(db: TIBDatabase): Integer;
1495 var
1496 i: Integer;
1497 NilFound: Boolean;
1498 begin
1499 EnsureNotInTransaction;
1500 CheckNotInTransaction;
1501 FTransactionIntf := nil;
1502
1503 i := FindDatabase(db);
1504 if i <> -1 then
1505 begin
1506 result := i;
1507 exit;
1508 end;
1509 NilFound := False;
1510 i := 0;
1511 while (not NilFound) and (i < FDatabases.Count) do
1512 begin
1513 NilFound := (FDatabases[i] = nil);
1514 if (not NilFound) then
1515 Inc(i);
1516 end;
1517 if (NilFound) then
1518 begin
1519 FDatabases[i] := db;
1520 result := i;
1521 end
1522 else
1523 begin
1524 result := FDatabases.Count;
1525 FDatabases.Add(db);
1526 end;
1527 end;
1528
1529 function TIBTransaction.AddSQLObject(ds: TIBBase): Integer;
1530 begin
1531 result := 0;
1532 while (result < FSQLObjects.Count) and (FSQLObjects[result] <> nil) do
1533 Inc(result);
1534 if (result = FSQLObjects.Count) then
1535 FSQLObjects.Add(ds)
1536 else
1537 FSQLObjects[result] := ds;
1538 end;
1539
1540 procedure TIBTransaction.Commit;
1541 begin
1542 EndTransaction(TACommit, False);
1543 end;
1544
1545 procedure TIBTransaction.CommitRetaining;
1546 begin
1547 EndTransaction(TACommitRetaining, False);
1548 end;
1549
1550 procedure TIBTransaction.EndTransaction(Action: TTransactionAction;
1551 Force: Boolean);
1552 var
1553 i: Integer;
1554 begin
1555 CheckInTransaction;
1556 if FInEndTransaction then Exit;
1557 FInEndTransaction := true;
1558 FEndAction := Action;
1559 try
1560 case Action of
1561 TARollback, TACommit:
1562 begin
1563 DoBeforeTransactionEnd;
1564 for i := 0 to FSQLObjects.Count - 1 do if FSQLObjects[i] <> nil then
1565 SQLObjects[i].DoBeforeTransactionEnd(Action);
1566 if InTransaction then
1567 begin
1568 if (Action = TARollback) then
1569 FTransactionIntf.Rollback(Force)
1570 else
1571 try
1572 FTransactionIntf.Commit;
1573 except on E: EIBInterBaseError do
1574 begin
1575 if Force then
1576 FTransactionIntf.Rollback(Force)
1577 else
1578 raise;
1579 end;
1580 end;
1581
1582 for i := 0 to FSQLObjects.Count - 1 do if FSQLObjects[i] <> nil then
1583 SQLObjects[i].DoAfterTransactionEnd;
1584 DoAfterTransactionEnd;
1585 end;
1586 end;
1587 TACommitRetaining:
1588 FTransactionIntf.CommitRetaining;
1589
1590 TARollbackRetaining:
1591 FTransactionIntf.RollbackRetaining;
1592 end;
1593 if not (csDesigning in ComponentState) then
1594 begin
1595 case Action of
1596 TACommit:
1597 MonitorHook.TRCommit(Self);
1598 TARollback:
1599 MonitorHook.TRRollback(Self);
1600 TACommitRetaining:
1601 MonitorHook.TRCommitRetaining(Self);
1602 TARollbackRetaining:
1603 MonitorHook.TRRollbackRetaining(Self);
1604 end;
1605 end;
1606 finally
1607 FInEndTransaction := false
1608 end;
1609 end;
1610
1611 function TIBTransaction.GetDatabase(Index: Integer): TIBDatabase;
1612 begin
1613 result := FDatabases[Index];
1614 end;
1615
1616 function TIBTransaction.GetDatabaseCount: Integer;
1617 var
1618 i, Cnt: Integer;
1619 begin
1620 result := 0;
1621 Cnt := FDatabases.Count - 1;
1622 for i := 0 to Cnt do if FDatabases[i] <> nil then
1623 Inc(result);
1624 end;
1625
1626 function TIBTransaction.GetSQLObject(Index: Integer): TIBBase;
1627 begin
1628 result := FSQLObjects[Index];
1629 end;
1630
1631 function TIBTransaction.GetSQLObjectCount: Integer;
1632 var
1633 i, Cnt: Integer;
1634 begin
1635 result := 0;
1636 Cnt := FSQLObjects.Count - 1;
1637 for i := 0 to Cnt do if FSQLObjects[i] <> nil then
1638 Inc(result);
1639 end;
1640
1641 function TIBTransaction.GetInTransaction: Boolean;
1642 begin
1643 result := (TransactionIntf <> nil) and TransactionIntf.InTransaction;
1644 end;
1645
1646 function TIBTransaction.FindDatabase(db: TIBDatabase): Integer;
1647 var
1648 i: Integer;
1649 begin
1650 result := -1;
1651 for i := 0 to FDatabases.Count - 1 do
1652 if db = TIBDatabase(FDatabases[i]) then
1653 begin
1654 result := i;
1655 break;
1656 end;
1657 end;
1658
1659 function TIBTransaction.FindDefaultDatabase: TIBDatabase;
1660 var
1661 i: Integer;
1662 begin
1663 result := FDefaultDatabase;
1664 if result = nil then
1665 begin
1666 for i := 0 to FDatabases.Count - 1 do
1667 if (TIBDatabase(FDatabases[i]) <> nil) and
1668 (TIBDatabase(FDatabases[i]).DefaultTransaction = self) then
1669 begin
1670 result := TIBDatabase(FDatabases[i]);
1671 break;
1672 end;
1673 end;
1674 end;
1675
1676 function TIBTransaction.GetEndAction: TTransactionAction;
1677 begin
1678 if FInEndTransaction then
1679 Result := FEndAction
1680 else
1681 IBError(ibxeIB60feature, [nil])
1682 end;
1683
1684
1685 function TIBTransaction.GetIdleTimer: Integer;
1686 begin
1687 result := FTimer.Interval;
1688 end;
1689
1690 procedure TIBTransaction.Loaded;
1691 begin
1692 inherited Loaded;
1693 end;
1694
1695 procedure TIBTransaction.BeforeDatabaseDisconnect(DB: TIBDatabase);
1696 begin
1697 if InTransaction then
1698 EndTransaction(FDefaultAction, True);
1699 FTransactionIntf := nil;
1700 end;
1701
1702 procedure TIBTransaction.RemoveDatabase(Idx: Integer);
1703 var
1704 DB: TIBDatabase;
1705 begin
1706 if ((Idx >= 0) and (FDatabases[Idx] <> nil)) then
1707 begin
1708 EnsureNotInTransaction;
1709 CheckNotInTransaction;
1710 FTransactionIntf := nil;
1711
1712 DB := Databases[Idx];
1713 FDatabases[Idx] := nil;
1714 DB.RemoveTransaction(DB.FindTransaction(Self));
1715 if DB = FDefaultDatabase then
1716 FDefaultDatabase := nil;
1717 end;
1718 end;
1719
1720 procedure TIBTransaction.RemoveDatabases;
1721 var
1722 i: Integer;
1723 begin
1724 EnsureNotInTransaction;
1725 CheckNotInTransaction;
1726 FTransactionIntf := nil;
1727
1728 for i := 0 to FDatabases.Count - 1 do if FDatabases[i] <> nil then
1729 RemoveDatabase(i);
1730 end;
1731
1732 procedure TIBTransaction.RemoveSQLObject(Idx: Integer);
1733 var
1734 ds: TIBBase;
1735 begin
1736 if ((Idx >= 0) and (FSQLObjects[Idx] <> nil)) then
1737 begin
1738 ds := SQLObjects[Idx];
1739 FSQLObjects[Idx] := nil;
1740 ds.Transaction := nil;
1741 end;
1742 end;
1743
1744 procedure TIBTransaction.RemoveSQLObjects;
1745 var
1746 i: Integer;
1747 begin
1748 for i := 0 to FSQLObjects.Count - 1 do if FSQLObjects[i] <> nil then
1749 RemoveSQLObject(i);
1750 end;
1751
1752 procedure TIBTransaction.Rollback;
1753 begin
1754 EndTransaction(TARollback, False);
1755 end;
1756
1757 procedure TIBTransaction.RollbackRetaining;
1758 begin
1759 EndTransaction(TARollbackRetaining, False);
1760 end;
1761
1762 procedure TIBTransaction.SetActive(Value: Boolean);
1763 begin
1764 if csReading in ComponentState then
1765 FStreamedActive := Value
1766 else
1767 if Value and not InTransaction then
1768 StartTransaction
1769 else
1770 if not Value and InTransaction then
1771 Rollback;
1772 end;
1773
1774 procedure TIBTransaction.SetDefaultDatabase(Value: TIBDatabase);
1775 var
1776 i: integer;
1777 begin
1778 if (FDefaultDatabase <> nil) and (FDefaultDatabase <> Value) then
1779 begin
1780 i := FDefaultDatabase.FindTransaction(self);
1781 if (i <> -1) then
1782 FDefaultDatabase.RemoveTransaction(i);
1783 end;
1784 if (Value <> nil) and (FDefaultDatabase <> Value) then
1785 begin
1786 Value.AddTransaction(Self);
1787 AddDatabase(Value);
1788 for i := 0 to FSQLObjects.Count - 1 do
1789 if (FSQLObjects[i] <> nil) and
1790 (TIBBase(FSQLObjects[i]).Database = nil) then
1791 SetObjectProp(TIBBase(FSQLObjects[i]).Owner, 'Database', Value);
1792 end;
1793 FDefaultDatabase := Value;
1794 end;
1795
1796 procedure TIBTransaction.Notification( AComponent: TComponent;
1797 Operation: TOperation);
1798 var
1799 i: Integer;
1800 begin
1801 inherited Notification( AComponent, Operation);
1802 if (Operation = opRemove) and (AComponent = FDefaultDatabase) then
1803 begin
1804 i := FindDatabase(FDefaultDatabase);
1805 if (i <> -1) then
1806 RemoveDatabase(i);
1807 FDefaultDatabase := nil;
1808 end;
1809 end;
1810
1811 procedure TIBTransaction.SetIdleTimer(Value: Integer);
1812 begin
1813 if Value < 0 then
1814 IBError(ibxeTimeoutNegative, [nil])
1815 else
1816 if (Value = 0) then
1817 begin
1818 FTimer.Enabled := False;
1819 FTimer.Interval := 0;
1820 end
1821 else
1822 if (Value > 0) then
1823 begin
1824 FTimer.Interval := Value;
1825 if not (csDesigning in ComponentState) then
1826 FTimer.Enabled := True;
1827 end;
1828 end;
1829
1830 procedure TIBTransaction.SetTRParams(Value: TStrings);
1831 begin
1832 FTRParams.Assign(Value);
1833 end;
1834
1835 procedure TIBTransaction.StartTransaction;
1836 var
1837 i: Integer;
1838 Attachments: array of IAttachment;
1839 ValidDatabaseCount: integer;
1840 begin
1841 CheckNotInTransaction;
1842 CheckDatabasesInList;
1843 if TransactionIntf <> nil then
1844 begin
1845 TransactionIntf.Start(DefaultAction);
1846 Exit;
1847 end;
1848
1849 for i := 0 to FDatabases.Count - 1 do
1850 if FDatabases[i] <> nil then
1851 begin
1852 with TIBDatabase(FDatabases[i]) do
1853 if not Connected then
1854 if StreamedConnected then
1855 begin
1856 Open;
1857 StreamedConnected := False;
1858 end
1859 else
1860 IBError(ibxeDatabaseClosed, [nil]);
1861 end;
1862 if FTRParamsChanged then
1863 begin
1864 FTRParamsChanged := False;
1865 FTPB := GenerateTPB(FTRParams);
1866 end;
1867
1868 ValidDatabaseCount := 0;
1869 for i := 0 to DatabaseCount - 1 do
1870 if Databases[i] <> nil then Inc(ValidDatabaseCount);
1871
1872 if ValidDatabaseCount = 1 then
1873 FTransactionIntf := Databases[0].Attachment.StartTransaction(FTPB,DefaultAction)
1874 else
1875 begin
1876 SetLength(Attachments,ValidDatabaseCount);
1877 for i := 0 to DatabaseCount - 1 do
1878 if Databases[i] <> nil then
1879 Attachments[i] := Databases[i].Attachment;
1880
1881 FTransactionIntf := FirebirdAPI.StartTransaction(Attachments,FTPB,DefaultAction);
1882 end;
1883
1884 if not (csDesigning in ComponentState) then
1885 MonitorHook.TRStart(Self);
1886 DoOnStartTransaction;
1887 end;
1888
1889 procedure TIBTransaction.TimeoutTransaction(Sender: TObject);
1890 begin
1891 if InTransaction then
1892 begin
1893 if not TransactionIntf.HasActivity then
1894 begin
1895 EndTransaction(FDefaultAction, True);
1896 if Assigned(FOnIdleTimer) then
1897 FOnIdleTimer(Self);
1898 end
1899 end;
1900 end;
1901
1902 procedure TIBTransaction.TRParamsChange(Sender: TObject);
1903 begin
1904 FTRParamsChanged := True;
1905 end;
1906
1907 procedure TIBTransaction.TRParamsChanging(Sender: TObject);
1908 begin
1909 EnsureNotInTransaction;
1910 CheckNotInTransaction;
1911 FTransactionIntf := nil;
1912 end;
1913
1914 { TIBBase }
1915 constructor TIBBase.Create(AOwner: TObject);
1916 begin
1917 FOwner := AOwner;
1918 end;
1919
1920 destructor TIBBase.Destroy;
1921 begin
1922 SetDatabase(nil);
1923 SetTransaction(nil);
1924 inherited Destroy;
1925 end;
1926
1927 procedure TIBBase.HandleException(Sender: TObject);
1928 begin
1929 if assigned(Database) then
1930 Database.HandleException(Sender)
1931 else
1932 SysUtils.ShowException(ExceptObject,ExceptAddr);
1933 end;
1934
1935 procedure TIBBase.SetCursor;
1936 begin
1937 if Assigned(Database) and not Database.SQLHourGlass then
1938 Exit;
1939 if assigned(IBGUIInterface) then
1940 IBGUIInterface.SetCursor;
1941 end;
1942
1943 procedure TIBBase.RestoreCursor;
1944 begin
1945 if Assigned(Database) and not Database.SQLHourGlass then
1946 Exit;
1947 if assigned(IBGUIInterface) then
1948 IBGUIInterface.RestoreCursor;
1949 end;
1950
1951 procedure TIBBase.CheckDatabase;
1952 begin
1953 if (FDatabase = nil) then
1954 IBError(ibxeDatabaseNotAssigned, [nil]);
1955 FDatabase.CheckActive;
1956 end;
1957
1958 procedure TIBBase.CheckTransaction;
1959 begin
1960 if FTransaction = nil then
1961 IBError(ibxeTransactionNotAssigned, [nil]);
1962 FTransaction.CheckInTransaction;
1963 end;
1964
1965 procedure TIBBase.DoBeforeDatabaseConnect(DBParams: TStrings; var DBName: string
1966 );
1967 begin
1968 if assigned(FBeforeDatabaseConnect) then
1969 BeforeDatabaseConnect(self,DBParams,DBName);
1970 end;
1971
1972 procedure TIBBase.DoAfterDatabaseConnect;
1973 begin
1974 if assigned(FAfterDatabaseConnect) then
1975 AfterDatabaseConnect(self);
1976 end;
1977
1978 procedure TIBBase.DoBeforeDatabaseDisconnect;
1979 begin
1980 if Assigned(BeforeDatabaseDisconnect) then
1981 BeforeDatabaseDisconnect(Self);
1982 end;
1983
1984 procedure TIBBase.DoAfterDatabaseDisconnect;
1985 begin
1986 if Assigned(AfterDatabaseDisconnect) then
1987 AfterDatabaseDisconnect(Self);
1988 end;
1989
1990 procedure TIBBase.DoDatabaseFree;
1991 begin
1992 if Assigned(OnDatabaseFree) then
1993 OnDatabaseFree(Self);
1994 SetDatabase(nil);
1995 SetTransaction(nil);
1996 end;
1997
1998 procedure TIBBase.DoBeforeTransactionEnd(Action: TTransactionAction);
1999 begin
2000 if Assigned(BeforeTransactionEnd) then
2001 BeforeTransactionEnd(Self,Action);
2002 end;
2003
2004 procedure TIBBase.DoAfterTransactionEnd;
2005 begin
2006 if Assigned(AfterTransactionEnd) then
2007 AfterTransactionEnd(Self);
2008 end;
2009
2010 procedure TIBBase.DoTransactionFree;
2011 begin
2012 if Assigned(OnTransactionFree) then
2013 OnTransactionFree(Self);
2014 FTransaction := nil;
2015 end;
2016
2017 procedure TIBBase.DoAfterExecQuery(Sender: TObject);
2018 begin
2019 if FTransaction <> nil then
2020 FTransaction.DoAfterExecQuery(Sender);
2021 end;
2022
2023 procedure TIBBase.DoAfterEdit(Sender: TObject);
2024 begin
2025 if FTransaction <> nil then
2026 FTransaction.DoAfterEdit(Sender);
2027 end;
2028
2029 procedure TIBBase.DoAfterDelete(Sender: TObject);
2030 begin
2031 if FTransaction <> nil then
2032 FTransaction.DoAfterDelete(Sender);
2033 end;
2034
2035 procedure TIBBase.DoAfterInsert(Sender: TObject);
2036 begin
2037 if FTransaction <> nil then
2038 FTransaction.DoAfterInsert(Sender);
2039 end;
2040
2041 procedure TIBBase.DoAfterPost(Sender: TObject);
2042 begin
2043 if FTransaction <> nil then
2044 FTransaction.DoAfterPost(Sender);
2045 end;
2046
2047 procedure TIBBase.SetDatabase(Value: TIBDatabase);
2048 begin
2049 if (FDatabase <> nil) then
2050 FDatabase.RemoveSQLObject(FIndexInDatabase);
2051 FDatabase := Value;
2052 if (FDatabase <> nil) then
2053 begin
2054 FIndexInDatabase := FDatabase.AddSQLObject(Self);
2055 if (FTransaction = nil) then
2056 Transaction := FDatabase.FindDefaultTransaction;
2057 end;
2058 end;
2059
2060 procedure TIBBase.SetTransaction(Value: TIBTransaction);
2061 begin
2062 if (FTransaction <> nil) then
2063 FTransaction.RemoveSQLObject(FIndexInTransaction);
2064 FTransaction := Value;
2065 if (FTransaction <> nil) then
2066 begin
2067 FIndexInTransaction := FTransaction.AddSQLObject(Self);
2068 if (FDatabase = nil) then
2069 Database := FTransaction.FindDefaultDatabase;
2070 end;
2071 end;
2072
2073 { GenerateDPB -
2074 Given a string containing a textual representation
2075 of the database parameters, generate a database
2076 parameter buffer, and return it and its length
2077 in DPB and DPBLength, respectively. }
2078
2079 function GenerateDPB(sl: TStrings): IDPB;
2080 var
2081 i, j: Integer;
2082 DPBVal: UShort;
2083 ParamName, ParamValue: string;
2084 begin
2085 Result := FirebirdAPI.AllocateDPB;
2086
2087 {Iterate through the textual database parameters, constructing
2088 a DPB on-the-fly }
2089 for i := 0 to sl.Count - 1 do
2090 begin
2091 { Get the parameter's name and value from the list,
2092 and make sure that the name is all lowercase with
2093 no leading 'isc_dpb_' prefix
2094 }
2095 if (Trim(sl.Names[i]) = '') then
2096 continue;
2097 ParamName := LowerCase(sl.Names[i]); {mbcs ok}
2098 ParamValue := Copy(sl[i], Pos('=', sl[i]) + 1, Length(sl[i])); {mbcs ok}
2099 if (Pos(DPBPrefix, ParamName) = 1) then {mbcs ok}
2100 Delete(ParamName, 1, Length(DPBPrefix));
2101 { We want to translate the parameter name to some Integer
2102 value. We do this by scanning through a list of known
2103 database parameter names (DPBConstantNames, defined above) }
2104 DPBVal := 0;
2105 { Find the parameter }
2106 for j := 1 to isc_dpb_last_dpb_constant do
2107 if (ParamName = DPBConstantNames[j]) then
2108 begin
2109 DPBVal := j;
2110 break;
2111 end;
2112 { A database parameter either contains a string value (case 1)
2113 or an Integer value (case 2)
2114 or no value at all (case 3)
2115 or an error needs to be generated (case else) }
2116 case DPBVal of
2117 isc_dpb_user_name, isc_dpb_password, isc_dpb_password_enc,
2118 isc_dpb_sys_user_name, isc_dpb_license, isc_dpb_encrypt_key,
2119 isc_dpb_lc_messages, isc_dpb_lc_ctype,
2120 isc_dpb_sql_role_name, isc_dpb_sql_dialect:
2121 begin
2122 if DPBVal = isc_dpb_sql_dialect then
2123 ParamValue[1] := Char(Ord(ParamValue[1]) - 48);
2124 Result.Add(DPBVal).SetAsString(ParamValue);
2125 end;
2126
2127 isc_dpb_num_buffers, isc_dpb_dbkey_scope, isc_dpb_force_write,
2128 isc_dpb_no_reserve, isc_dpb_damaged, isc_dpb_verify:
2129 Result.Add(DPBVal).SetAsByte(byte(ParamValue[1]));
2130
2131 isc_dpb_sweep:
2132 Result.Add(DPBVal).SetAsByte(isc_dpb_records);
2133
2134 isc_dpb_sweep_interval:
2135 Result.Add(DPBVal).SetAsInteger(StrToInt(ParamValue));
2136
2137 isc_dpb_activate_shadow, isc_dpb_delete_shadow, isc_dpb_begin_log,
2138 isc_dpb_quit_log:
2139 Result.Add(DPBVal).SetAsByte(0);
2140 else
2141 begin
2142 if (DPBVal > 0) and
2143 (DPBVal <= isc_dpb_last_dpb_constant) then
2144 IBError(ibxeDPBConstantNotSupported, [DPBConstantNames[DPBVal]])
2145 else
2146 IBError(ibxeDPBConstantUnknownEx, [sl.Names[i]]);
2147 end;
2148 end;
2149 end;
2150 end;
2151
2152 { GenerateTPB -
2153 Given a string containing a textual representation
2154 of the transaction parameters, generate a transaction
2155 parameter buffer, and return it and its length in
2156 TPB and TPBLength, respectively. }
2157 function GenerateTPB(sl: TStrings): ITPB;
2158 var
2159 i, j, TPBVal: Integer;
2160 ParamName, ParamValue: string;
2161 begin
2162 Result := FirebirdAPI.AllocateTPB;
2163 for i := 0 to sl.Count - 1 do
2164 begin
2165 if (Trim(sl[i]) = '') then
2166 Continue;
2167
2168 if (Pos('=', sl[i]) = 0) then {mbcs ok}
2169 ParamName := LowerCase(sl[i]) {mbcs ok}
2170 else
2171 begin
2172 ParamName := LowerCase(sl.Names[i]); {mbcs ok}
2173 ParamValue := Copy(sl[i], Pos('=', sl[i]) + 1, Length(sl[i])); {mbcs ok}
2174 end;
2175 if (Pos(TPBPrefix, ParamName) = 1) then {mbcs ok}
2176 Delete(ParamName, 1, Length(TPBPrefix));
2177 TPBVal := 0;
2178 { Find the parameter }
2179 for j := 1 to isc_tpb_last_tpb_constant do
2180 if (ParamName = TPBConstantNames[j]) then
2181 begin
2182 TPBVal := j;
2183 break;
2184 end;
2185 { Now act on it }
2186 case TPBVal of
2187 isc_tpb_consistency, isc_tpb_exclusive, isc_tpb_protected,
2188 isc_tpb_concurrency, isc_tpb_shared, isc_tpb_wait, isc_tpb_nowait,
2189 isc_tpb_read, isc_tpb_write, isc_tpb_ignore_limbo,
2190 isc_tpb_read_committed, isc_tpb_rec_version, isc_tpb_no_rec_version:
2191 Result.Add(TPBVal);
2192
2193 isc_tpb_lock_read, isc_tpb_lock_write:
2194 Result.Add(TPBVal).SetAsString(ParamValue);
2195
2196 else
2197 begin
2198 if (TPBVal > 0) and
2199 (TPBVal <= isc_tpb_last_tpb_constant) then
2200 IBError(ibxeTPBConstantNotSupported, [TPBConstantNames[TPBVal]])
2201 else
2202 IBError(ibxeTPBConstantUnknownEx, [sl.Names[i]]);
2203 end;
2204 end;
2205 end;
2206 end;
2207
2208 end.
2209
2210
2211
2212
2213