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