1{ 2 This file is part of the Free Pascal run time library. 3 Copyright (c) 1999-2000 by Michael Van Canneyt, member of the 4 Free Pascal development team 5 6 TDatabase and related objects implementation 7 8 See the file COPYING.FPC, included in this distribution, 9 for details about the copyright. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 15 **********************************************************************} 16 17{ --------------------------------------------------------------------- 18 TDatabase 19 ---------------------------------------------------------------------} 20 21Procedure TDatabase.CheckConnected; 22 23begin 24 If Not Connected Then 25 DatabaseError(SNotConnected,Self); 26end; 27 28 29Procedure TDatabase.CheckDisConnected; 30begin 31 If Connected Then 32 DatabaseError(SConnected,Self); 33end; 34 35procedure TDatabase.DoConnect; 36begin 37 DoInternalConnect; 38 FConnected := True; 39end; 40 41procedure TDatabase.DoDisconnect; 42begin 43 CloseDatasets; 44 CloseTransactions; 45 DoInternalDisConnect; 46 if csLoading in ComponentState then 47 FOpenAfterRead := false; 48 FConnected := False; 49end; 50 51function TDatabase.GetConnected: boolean; 52begin 53 Result:= FConnected; 54end; 55 56constructor TDatabase.Create(AOwner: TComponent); 57 58begin 59 Inherited Create(AOwner); 60 FParams:=TStringlist.Create; 61 FDatasets:=TThreadList.Create; 62 FTransactions:=TThreadList.Create; 63 FConnected:=False; 64end; 65 66destructor TDatabase.Destroy; 67 68begin 69 Connected:=False; 70 RemoveDatasets; 71 RemoveTransactions; 72 FDatasets.Free; 73 FTransactions.Free; 74 FParams.Free; 75 Inherited Destroy; 76end; 77 78procedure TDatabase.CloseDataSets; 79 80Var 81 I : longint; 82 L : TList; 83 84begin 85 If Assigned(FDatasets) then 86 begin 87 L:=FDatasets.LockList; 88 try 89 For I:=L.Count-1 downto 0 do 90 TDataset(L[i]).Close; 91 finally 92 FDatasets.UnlockList; 93 end; 94 end; 95end; 96 97procedure TDatabase.CloseTransactions; 98 99Var 100 I : longint; 101 L : TList; 102 103begin 104 If Assigned(FTransactions) then 105 begin 106 L:=FTransactions.LockList; 107 try 108 For I:=L.Count-1 downto 0 do 109 try 110 TDBTransaction(L[i]).EndTransaction; 111 except 112 if not ForcedClose then 113 Raise; 114 end; 115 finally 116 FTransactions.UnlockList 117 end; 118 end; 119end; 120 121procedure TDatabase.RemoveDataSets; 122 123Var 124 I : longint; 125 L : TList; 126begin 127 If Assigned(FDatasets) then 128 begin 129 L:=FDatasets.LockList; 130 try 131 For I:=L.Count-1 downto 0 do 132 TDBDataset(L[i]).Database:=Nil; 133 finally 134 FDatasets.UnlockList; 135 end; 136 end; 137end; 138 139procedure TDatabase.RemoveTransactions; 140 141Var 142 I : longint; 143 L : TList; 144begin 145 If Assigned(FTransactions) then 146 begin 147 L:=FTransactions.LockList; 148 try 149 For I:=L.Count-1 downto 0 do 150 TDBTransaction(L[i]).Database:=Nil; 151 finally 152 FTransactions.UnlockList 153 end; 154 end; 155end; 156 157procedure TDatabase.SetParams(AValue: TStrings); 158begin 159 if AValue<>nil then 160 FParams.Assign(AValue); 161end; 162 163Function TDatabase.GetDataSetCount : Longint; 164 165Var 166 L : TList; 167 168begin 169 Result:=0; 170 If Assigned(FDatasets) Then 171 begin 172 L:=FDatasets.LockList; 173 try 174 Result:=L.Count; 175 finally 176 FDatasets.Unlocklist; 177 end; 178 end; 179end; 180 181Function TDatabase.GetTransactionCount : Longint; 182 183Var 184 L : TList; 185 186begin 187 Result:=0; 188 If Assigned(FTransactions) Then 189 begin 190 L:=FTransactions.LockList; 191 try 192 Result:=L.Count; 193 finally 194 FTransactions.UnlockList; 195 end; 196 end; 197end; 198 199Function TDatabase.GetDataset(Index : longint) : TDataset; 200 201Var 202 L : TList; 203 204begin 205 If Not Assigned(FDatasets) then 206 begin 207 result := nil; 208 DatabaseError(SNoDatasets); 209 end 210 else 211 begin 212 L:=FDatasets.LockList; 213 try 214 Result:=TDataset(L[Index]) 215 finally 216 FDatasets.UnlockList; 217 end; 218 end; 219end; 220 221Function TDatabase.GetTransaction(Index : longint) : TDBtransaction; 222 223Var 224 L : TList; 225 226begin 227 If Not Assigned(FTransactions) then 228 begin 229 result := nil; 230 DatabaseError(SNoTransactions); 231 end 232 else 233 begin 234 L:=FTransactions.LockList; 235 try 236 Result:=TDBTransaction(L[Index]) 237 finally 238 FTransactions.UnlockList; 239 end; 240 end; 241end; 242 243procedure TDatabase.RegisterDataset (DS : TDBDataset); 244 245Var 246 I : longint; 247 L : TList; 248begin 249 L:=FDatasets.LockList; 250 try 251 I:=L.IndexOf(DS); 252 If I=-1 then 253 L.Add(DS) 254 else 255 DatabaseErrorFmt(SDatasetRegistered,[DS.Name]); 256 finally 257 FDatasets.UnlockList; 258 end; 259end; 260 261procedure TDatabase.RegisterTransaction (TA : TDBTransaction); 262 263Var 264 I : longint; 265 L : TList; 266 267begin 268 L:=FTransactions.LockList; 269 try 270 I:=L.IndexOf(TA); 271 If I=-1 then 272 L.Add(TA) 273 else 274 DatabaseErrorFmt(STransactionRegistered,[TA.Name]); 275 finally 276 FTransactions.UnlockList; 277 end; 278end; 279 280procedure TDatabase.UnRegisterDataset (DS : TDBDataset); 281 282Var 283 I : longint; 284 L : TList; 285 286begin 287 L:=FDatasets.LockList; 288 try 289 I:=L.IndexOf(DS); 290 If I<>-1 then 291 L.Delete(I) 292 else 293 DatabaseErrorFmt(SNoDatasetRegistered,[DS.Name]); 294 finally 295 FDatasets.UnlockList; 296 end; 297end; 298 299procedure TDatabase.UnRegisterTransaction (TA : TDBTransaction); 300 301Var 302 I : longint; 303 L : TList; 304 305begin 306 L:=FTransactions.LockList; 307 try 308 I:=L.IndexOf(TA); 309 If I<>-1 then 310 L.Delete(I) 311 else 312 DatabaseErrorFmt(SNoTransactionRegistered,[TA.Name]); 313 finally 314 FTransactions.UnlockList; 315 end; 316end; 317 318 319{ --------------------------------------------------------------------- 320 TDBDataset 321 ---------------------------------------------------------------------} 322 323Procedure TDBDataset.SetDatabase (Value : TDatabase); 324 325begin 326 If Value<>FDatabase then 327 begin 328 CheckInactive; 329 If Assigned(FDatabase) then 330 FDatabase.UnregisterDataset(Self); 331 If Value<>Nil Then 332 Value.RegisterDataset(Self); 333 FDatabase:=Value; 334 end; 335end; 336 337Procedure TDBDataset.SetTransaction (Value : TDBTransaction); 338 339begin 340 CheckInactive; 341 If Value<>FTransaction then 342 begin 343 If Assigned(FTransaction) then 344 FTransaction.UnregisterDataset(Self); 345 If Value<>Nil Then 346 Value.RegisterDataset(Self); 347 FTransaction:=Value; 348 end; 349end; 350 351Procedure TDBDataset.CheckDatabase; 352 353begin 354 If (FDatabase=Nil) then 355 DatabaseError(SErrNoDatabaseAvailable,Self) 356end; 357 358Destructor TDBDataset.Destroy; 359 360begin 361 Database:=Nil; 362 Transaction:=Nil; 363 Inherited; 364end; 365 366{ --------------------------------------------------------------------- 367 TDBTransaction 368 ---------------------------------------------------------------------} 369procedure TDBTransaction.SetActive(Value : boolean); 370begin 371 if FActive and (not Value) then 372 EndTransaction 373 else if (not FActive) and Value then 374 if csLoading in ComponentState then 375 begin 376 FOpenAfterRead := true; 377 exit; 378 end 379 else 380 StartTransaction; 381end; 382 383procedure TDBTransaction.Loaded; 384 385begin 386 inherited; 387 try 388 if FOpenAfterRead then SetActive(true); 389 except 390 if csDesigning in Componentstate then 391 InternalHandleException 392 else 393 raise; 394 end; 395end; 396 397procedure TDBTransaction.InternalHandleException; 398 399begin 400 if assigned(classes.ApplicationHandleException) then 401 classes.ApplicationHandleException(self) 402 else 403 ShowException(ExceptObject,ExceptAddr); 404end; 405 406procedure TDBTransaction.CheckActive; 407 408begin 409 If not FActive Then 410 DatabaseError(STransNotActive,Self); 411end; 412 413procedure TDBTransaction.CheckInactive; 414 415begin 416 If FActive Then 417 DatabaseError(STransActive,Self); 418end; 419 420procedure TDBTransaction.Commit; 421begin 422 EndTransaction; 423end; 424 425procedure TDBTransaction.CommitRetaining; 426begin 427 Commit; 428 StartTransaction; 429end; 430 431procedure TDBTransaction.Rollback; 432begin 433 EndTransaction; 434end; 435 436procedure TDBTransaction.RollbackRetaining; 437begin 438 RollBack; 439 StartTransaction; 440end; 441 442procedure TDBTransaction.CloseTrans; 443 444begin 445 FActive := false; 446end; 447 448procedure TDBTransaction.OpenTrans; 449 450begin 451 FActive := true; 452end; 453 454procedure TDBTransaction.SetDatabase(Value: TDatabase); 455 456begin 457 If Value<>FDatabase then 458 begin 459 CheckInactive; 460 If Assigned(FDatabase) then 461 FDatabase.UnregisterTransaction(Self); 462 If Value<>Nil Then 463 Value.RegisterTransaction(Self); 464 FDatabase:=Value; 465 end; 466end; 467 468constructor TDBTransaction.Create(AOwner: TComponent); 469 470begin 471 inherited Create(AOwner); 472 FDatasets:=TThreadList.Create; 473end; 474 475procedure TDBTransaction.CheckDatabase; 476 477begin 478 If (FDatabase=Nil) then 479 DatabaseError(SErrNoDatabaseAvailable,Self) 480end; 481 482Function TDBTransaction.AllowClose(DS : TDBDataset) : Boolean; 483 484begin 485 Result:=Assigned(DS); 486end; 487 488procedure TDBTransaction.CloseDataSets; 489 490Var 491 I : longint; 492 L : TList; 493 DS : TDBDataset; 494 495begin 496 If Assigned(FDatasets) then 497 begin 498 L:=FDatasets.LockList; 499 try 500 For I:=L.Count-1 downto 0 do 501 begin 502 DS:=TDBDataset(L[i]); 503 If AllowClose(DS) then 504 DS.Close; 505 end; 506 finally 507 FDatasets.UnlockList; 508 end; 509 end; 510end; 511 512destructor TDBTransaction.Destroy; 513 514begin 515 Database:=Nil; 516 CloseDataSets; 517 RemoveDatasets; 518 FDatasets.Free; 519 Inherited; 520end; 521 522procedure TDBTransaction.RemoveDataSets; 523 524Var 525 I : longint; 526 L : TList; 527 528begin 529 If Not Assigned(FDatasets) then 530 exit; 531 L:=FDatasets.LockList; 532 try 533 For I:=L.Count-1 downto 0 do 534 TDBDataset(L[i]).Transaction:=Nil; 535 finally 536 FDatasets.unlockList; 537 end; 538end; 539 540function TDBTransaction.GetDataset(Index: longint): TDBDataset; 541 542Var 543 L : TList; 544 545 546begin 547 If Not Assigned(FDatasets) then 548 DatabaseError(SNoDatasets); 549 L:=FDatasets.LockList; 550 try 551 Result:=TDBDataset(L[Index]) 552 finally 553 FDatasets.UnlockList; 554 end; 555end; 556 557function TDBTransaction.GetDataSetCount: Longint; 558 559Var 560 L : TList; 561 562begin 563 Result:=0; 564 If Not Assigned(FDatasets) Then 565 exit; 566 L:=FDatasets.lockList; 567 try 568 Result:=L.Count 569 finally 570 FDatasets.UnlockList; 571 end; 572end; 573 574procedure TDBTransaction.RegisterDataset (DS : TDBDataset); 575 576Var 577 I : longint; 578 L : TList; 579begin 580 L:=FDatasets.LockList; 581 try 582 I:=L.IndexOf(DS); 583 If I=-1 then 584 L.Add(DS) 585 else 586 DatabaseErrorFmt(SDatasetRegistered,[DS.Name]); 587 finally 588 FDatasets.UnlockList; 589 end; 590end; 591 592procedure TDBTransaction.UnRegisterDataset (DS : TDBDataset); 593 594Var 595 I : longint; 596 L : TList; 597 598begin 599 L:=FDatasets.LockList; 600 try 601 I:=L.IndexOf(DS); 602 If I<>-1 then 603 L.Delete(I) 604 else 605 DatabaseErrorFmt(SNoDatasetRegistered,[DS.Name]); 606 finally 607 FDatasets.UnlockList; 608 end; 609end; 610 611{ --------------------------------------------------------------------- 612 TCustomConnection 613 ---------------------------------------------------------------------} 614 615function TCustomConnection.GetDataSet(Index: Longint): TDataSet; 616begin 617 Result := nil; 618end; 619 620function TCustomConnection.GetDataSetCount: Longint; 621begin 622 Result := 0; 623end; 624 625procedure TCustomConnection.InternalHandleException; 626begin 627 if assigned(classes.ApplicationHandleException) then 628 classes.ApplicationHandleException(self) 629 else 630 ShowException(ExceptObject,ExceptAddr); 631end; 632 633procedure TCustomConnection.SetAfterConnect(const AValue: TNotifyEvent); 634begin 635 FAfterConnect:=AValue; 636end; 637 638procedure TCustomConnection.SetAfterDisconnect(const AValue: TNotifyEvent); 639begin 640 FAfterDisconnect:=AValue; 641end; 642 643procedure TCustomConnection.SetBeforeConnect(const AValue: TNotifyEvent); 644begin 645 FBeforeConnect:=AValue; 646end; 647 648procedure TCustomConnection.SetBeforeDisconnect(const AValue: TNotifyEvent); 649begin 650 FBeforeDisconnect:=AValue; 651end; 652 653procedure TCustomConnection.DoLoginPrompt; 654 655var 656 ADatabaseName, AUserName, APassword: string; 657 658begin 659 if FLoginPrompt then 660 begin 661 GetLoginParams(ADatabaseName, AUserName, APassword); 662 if Assigned(FOnLogin) then 663 FOnLogin(Self, AUserName, APassword) // by value 664 else if Assigned(LoginDialogExProc) then 665 begin 666 LoginDialogExProc(ADatabaseName, AUserName, APassword, False); // by reference 667 SetLoginParams(ADatabaseName, AUserName, APassword); 668 end; 669 end; 670end; 671 672procedure TCustomConnection.SetConnected(Value: boolean); 673 674begin 675 If Value<>Connected then 676 begin 677 If Value then 678 begin 679 if csReading in ComponentState then 680 begin 681 FStreamedConnected := true; 682 exit; 683 end 684 else 685 begin 686 if Assigned(BeforeConnect) then 687 BeforeConnect(self); 688 DoLoginPrompt; 689 DoConnect; 690 if Assigned(AfterConnect) then 691 AfterConnect(self); 692 end; 693 end 694 else 695 begin 696 if Assigned(BeforeDisconnect) then 697 BeforeDisconnect(self); 698 DoDisconnect; 699 if Assigned(AfterDisconnect) then 700 AfterDisconnect(self); 701 end; 702 end; 703end; 704 705procedure TCustomConnection.GetLoginParams(out ADatabaseName, AUserName, APassword: string); 706begin 707 if IsPublishedProp(Self,'DatabaseName') then 708 ADatabaseName := GetStrProp(Self,'DatabaseName'); 709 if IsPublishedProp(Self,'UserName') then 710 AUserName := GetStrProp(Self,'UserName'); 711 if IsPublishedProp(Self,'Password') then 712 APassword := GetStrProp(Self,'Password'); 713end; 714 715procedure TCustomConnection.SetLoginParams(const ADatabaseName, AUserName, APassword: string); 716begin 717 if IsPublishedProp(Self,'DatabaseName') then 718 SetStrProp(Self,'DatabaseName',ADatabaseName); 719 if IsPublishedProp(Self,'UserName') then 720 SetStrProp(Self,'UserName',AUserName); 721 if IsPublishedProp(Self,'Password') then 722 SetStrProp(Self,'Password',APassword); 723end; 724 725procedure TCustomConnection.DoConnect; 726 727begin 728 // Do nothing yet 729end; 730 731procedure TCustomConnection.DoDisconnect; 732 733begin 734 // Do nothing yet 735end; 736 737function TCustomConnection.GetConnected: boolean; 738 739begin 740 Result := False; 741end; 742 743procedure TCustomConnection.Loaded; 744begin 745 inherited Loaded; 746 try 747 if FStreamedConnected then 748 SetConnected(true); 749 except 750 if csDesigning in Componentstate then 751 InternalHandleException 752 else 753 raise; 754 end; 755end; 756 757procedure TCustomConnection.Close(ForceClose : Boolean = False); 758begin 759 try 760 ForcedClose:=ForceClose; 761 Connected := False; 762 finally 763 ForcedClose:=false; 764 end; 765end; 766 767destructor TCustomConnection.Destroy; 768begin 769 Connected:=False; 770 Inherited Destroy; 771end; 772 773procedure TCustomConnection.Open; 774begin 775 Connected := True; 776end; 777 778