ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/FBAttachment.pas
(Generate patch)

Comparing ibx/branches/udr/client/FBAttachment.pas (file contents):
Revision 370 by tony, Wed Jan 5 14:59:15 2022 UTC vs.
Revision 389 by tony, Thu Jan 20 23:33:40 2022 UTC

# Line 16 | Line 16
16   *
17   *  The Initial Developer of the Original Code is Tony Whyman.
18   *
19 < *  The Original Code is (C) 2016 Tony Whyman, MWA Software
19 > *  The Original Code is (C) 2016-2021 Tony Whyman, MWA Software
20   *  (http://www.mwasoftware.co.uk).
21   *
22   *  All Rights Reserved.
# Line 69 | Line 69 | type
69      Syntax:
70  
71      Transaction Start:
72 <    *S:<date/time>,<session id>,<transaction no.>,<string length>:<transaction Name>,<string length>:<TPB>,<default Completion>
72 >    *S:<date/time>,<attachmentid>,<session id>,<transaction no.>,<string length>:<transaction Name>,<string length>:<TPB>,<default Completion>
73  
74      Transaction Commit:
75 <    *C:<date/time>,<session id>,<transaction no.>
75 >    *C:<date/time>,<attachmentid>,<session id>,<transaction no.>
76  
77      Transaction Commit retaining :
78 <    *c:<date/time>,<session id>,<transaction no.><old transaction no.>
78 >    *c:<date/time>,<attachmentid>,<session id>,<transaction no.><old transaction no.>
79  
80      Transaction Rollback:
81 <    *R:<date/time>,<session id>,<transaction no.>
81 >    *R:<date/time>,<attachmentid>,<session id>,<transaction no.>
82  
83      Transaction Rollback retaining:
84 <    *r:<date/time>,<session id>,<transaction no.><old transaction no.>
84 >    *r:<date/time>,<attachmentid>,<session id>,<transaction no.><old transaction no.>
85  
86      Update/Insert/Delete
87 <    *Q:<date/time>,<session id>,<transaction no.>,<length of query text in bytes>:<query text>
87 >    *Q:<date/time>,<attachmentid>,<session id>,<transaction no.>,<length of query text in bytes>:<query text>
88  
89    }
90  
# Line 93 | Line 93 | type
93    TFBJournaling = class(TActivityHandler, IJournallingHook)
94    private
95      {Logfile}
96 <    const sQueryJournal          = '*Q:''%s'',%d,%d,%d:%s' + LineEnding;
97 <    const sTransStartJnl         = '*S:''%s'',%d,%d,%d:%s,%d:%s,%d' + LineEnding;
98 <    const sTransCommitJnl        = '*C:''%s'',%d,%d' + LineEnding;
99 <    const sTransCommitRetJnl     = '*c:''%s'',%d,%d,%d' + LineEnding;
100 <    const sTransRollBackJnl      = '*R:''%s'',%d,%d' + LineEnding;
101 <    const sTransRollBackRetJnl   = '*r:''%s'',%d,%d,%d' + LineEnding;
96 >    const sQueryJournal          = '*Q:''%s'',%d,%d,%d,%d:%s' + LineEnding;
97 >    const sTransStartJnl         = '*S:''%s'',%d,%d,%d,%d:%s,%d:%s,%d' + LineEnding;
98 >    const sTransCommitJnl        = '*C:''%s'',%d,%d,%d' + LineEnding;
99 >    const sTransCommitFailJnl    = '*F:''%s'',%d,%d,%d' + LineEnding;
100 >    const sTransCommitRetJnl     = '*c:''%s'',%d,%d,%d,%d' + LineEnding;
101 >    const sTransRollBackJnl      = '*R:''%s'',%d,%d,%d' + LineEnding;
102 >    const sTransRollBackFailJnl  = '*f:''%s'',%d,%d,%d' + LineEnding;
103 >    const sTransRollBackRetJnl   = '*r:''%s'',%d,%d,%d,%d' + LineEnding;
104    private
105      FOptions: TJournalOptions;
106      FJournalFilePath: string;
# Line 115 | Line 117 | type
117    public
118      {IJournallingHook}
119      procedure TransactionStart(Tr: ITransaction);
120 <    function TransactionEnd( TransactionID: integer; Action: TTransactionAction): boolean;
120 >    function TransactionEnd( TransactionID: integer; Completion: TTrCompletionState): boolean;
121      procedure TransactionRetained(Tr: ITransaction; OldTransactionID: integer;
122        Action: TTransactionAction);
123      procedure ExecQuery(Stmt: IStatement);
124 +    procedure ExecImmediateJnl(sql: AnsiString; tr: ITransaction);
125    public
126      {Client side Journaling}
127      function JournalingActive: boolean;
128      function GetJournalOptions: TJournalOptions;
129      function StartJournaling(aJournalLogFile: AnsiString): integer; overload;
130      function StartJournaling(aJournalLogFile: AnsiString; Options: TJournalOptions): integer; overload;
131 +    function StartJournaling(S: TStream; Options: TJournalOptions): integer; overload;
132      procedure StopJournaling(RetainJournal: boolean);
133    end;
134  
# Line 139 | Line 143 | type
143      FUserCharSetMap: array of TCharSetMap;
144      FSecDatabase: AnsiString;
145      FInlineBlobLimit: integer;
146 <  protected
143 <    FDatabaseName: AnsiString;
144 <    FRaiseExceptionOnConnectError: boolean;
146 >    FAttachmentID: integer;
147      FSQLDialect: integer;
148      FHasDefaultCharSet: boolean;
149      FCharSetID: integer;
150      FCodePage: TSystemCodePage;
151      FRemoteProtocol: AnsiString;
152      FAuthMethod: AnsiString;
153 +    FHasConnectionInfo: boolean;
154 +    procedure NeedDBInfo;
155 +    procedure NeedConnectionInfo;
156 +  protected
157 +    FDatabaseName: AnsiString;
158 +    FRaiseExceptionOnConnectError: boolean;
159      constructor Create(api: TFBClientAPI; DatabaseName: AnsiString; DPB: IDPB;
160        RaiseExceptionOnConnectError: boolean);
161      procedure CheckHandle; virtual; abstract;
162 +    procedure ClearCachedInfo;
163      function GenerateCreateDatabaseSQL(DatabaseName: AnsiString; aDPB: IDPB): AnsiString;
155    procedure GetODSAndConnectionInfo;
164      function GetDBInfo(ReqBuffer: PByte; ReqBufLen: integer): IDBInformation; virtual; abstract;
165      function IsConnected: boolean; virtual; abstract;
166      procedure EndAllTransactions;
167      procedure DPBFromCreateSQL(CreateSQL: AnsiString);
168      procedure SetParameters(SQLParams: ISQLParams; params: array of const);
169 +    procedure SetSQLDialect(aValue: integer);
170      procedure UseServerICUChanged; virtual;
171    public
172      destructor Destroy; override;
173 +    procedure Disconnect(Force: boolean); override;
174      function getFirebirdAPI: IFirebirdAPI;
175      function getDPB: IDPB;
176      function AllocateBPB: IBPB;
# Line 217 | Line 227 | type
227      function GetEventHandler(Event: AnsiString): IEvents; overload;
228  
229      function GetSQLDialect: integer;
230 +    function GetAttachmentID: integer;
231      function CreateBlob(transaction: ITransaction; RelationName, ColumnName: AnsiString; BPB: IBPB=nil): IBlob; overload;
232      function CreateBlob(transaction: ITransaction; BlobMetaData: IBlobMetaData; BPB: IBPB=nil): IBlob; overload; virtual; abstract;
233      function OpenBlob(transaction: ITransaction; BlobMetaData: IBlobMetaData; BlobID: TISC_QUAD; BPB: IBPB=nil): IBlob; overload; virtual; abstract;
# Line 227 | Line 238 | type
238      function CreateArray(transaction: ITransaction; ArrayMetaData: IArrayMetaData): IArray; overload; virtual; abstract;
239      function OpenArray(transaction: ITransaction; RelationName, ColumnName: AnsiString; ArrayID: TISC_QUAD): IArray; overload;
240      function OpenArray(transaction: ITransaction; ArrayMetaData: IArrayMetaData; ArrayID: TISC_QUAD): IArray; overload; virtual; abstract;
241 <    property SQLDialect: integer read FSQLDialect;
241 >    property SQLDialect: integer read GetSQLDialect;
242      property DPB: IDPB read FDPB;
243    public
244      function GetDBInformation(Requests: array of byte): IDBInformation; overload;
245      function GetDBInformation(Request: byte): IDBInformation; overload;
246      function GetDBInformation(Requests: IDIRB): IDBInformation; overload;
236    function GetAttachmentID: integer;
247      function GetConnectString: AnsiString;
248      function GetRemoteProtocol: AnsiString;
249      function GetAuthenticationMethod: AnsiString;
250      function GetSecurityDatabase: AnsiString;
251      function GetODSMajorVersion: integer;
252      function GetODSMinorVersion: integer;
253 +    function GetCharSetID: integer;
254      function HasDecFloatSupport: boolean; virtual;
255      function GetInlineBlobLimit: integer;
256      procedure SetInlineBlobLimit(limit: integer);
257      function HasBatchMode: boolean; virtual;
258      function HasTable(aTableName: AnsiString): boolean;
259 +    function HasFunction(aFunctionName: AnsiString): boolean;
260 +    function HasProcedure(aProcName: AnsiString): boolean;
261  
262    public
263      {Character Sets}
# Line 259 | Line 272 | type
272        AllowReverseLookup:boolean; out CharSetID: integer);
273      function GetBlobMetaData(Transaction: ITransaction; tableName, columnName: AnsiString): IBlobMetaData; virtual; abstract;
274      function GetArrayMetaData(Transaction: ITransaction; tableName, columnName: AnsiString): IArrayMetaData; virtual; abstract;
275 <    property CharSetID: integer read FCharSetID;
275 >    property CharSetID: integer read GetCharSetID;
276      property CodePage: TSystemCodePage read FCodePage;
277  
278    public
# Line 473 | Line 486 | const
486      'process_name',
487      'trusted_role',
488      'org_filename',
489 <    'utf8_ilename',
489 >    'utf8_filename',
490      'ext_call_depth',
491      'auth_block',
492      'client_version',
# Line 610 | Line 623 | end;
623  
624   procedure TFBJournaling.EndSession(RetainJournal: boolean);
625   begin
626 <  if JournalingActive then
626 >  if JournalingActive and (FJournalFilePath <> '') then
627    begin
628      FreeAndNil(FJournalFileStream);
629 <    if not RetainJournal then
629 >    if not (joNoServerTable in FOptions) and not RetainJournal then
630      try
631          GetAttachment.ExecuteSQL([isc_tpb_write,isc_tpb_wait,isc_tpb_consistency],
632               sqlCleanUpSession,[FSessionID]);
# Line 637 | Line 650 | procedure TFBJournaling.TransactionStart
650   var LogEntry: AnsiString;
651      TPBText: AnsiString;
652   begin
653 <  FDoNotJournal := true;
653 >  if not (joNoServerTable in FOptions) then
654    try
655 +    FDoNotJournal := true;
656      GetAttachment.ExecuteSQL(Tr,sqlRecordJournalEntry,[FSessionID,Tr.GetTransactionID,NULL]);
657    finally
658      FDoNotJournal := false;
659    end;
660    TPBText := Tr.getTPB.AsText;
661    LogEntry := Format(sTransStartJnl,[FBFormatDateTime(GetDateTimeFmt,Now),
662 +                                     GetAttachment.GetAttachmentID,
663                                       FSessionID,
664                                       Tr.GetTransactionID,
665                                       Length(Tr.TransactionName),
# Line 656 | Line 671 | begin
671   end;
672  
673   function TFBJournaling.TransactionEnd(TransactionID: integer;
674 <  Action: TTransactionAction): boolean;
674 >  Completion: TTrCompletionState): boolean;
675  
676   var LogEntry: AnsiString;
677   begin
678    Result := false;
679 <    case Action of
680 <    TARollback:
679 >    case Completion of
680 >    trRolledback:
681        begin
682 <        LogEntry := Format(sTransRollbackJnl,[FBFormatDateTime(GetDateTimeFmt,Now),FSessionID,TransactionID]);
682 >        LogEntry := Format(sTransRollbackJnl,[FBFormatDateTime(GetDateTimeFmt,Now),
683 >                                              GetAttachment.GetAttachmentID,
684 >                                              FSessionID,TransactionID]);
685          Result := true;
686        end;
687 <    TACommit:
687 >
688 >    trRollbackFailed:
689        begin
690 <        LogEntry := Format(sTransCommitJnl,[FBFormatDateTime(GetDateTimeFmt,Now),FSessionID,TransactionID]);
690 >        LogEntry := Format(sTransRollbackFailJnl,[FBFormatDateTime(GetDateTimeFmt,Now),
691 >                                              GetAttachment.GetAttachmentID,
692 >                                              FSessionID,TransactionID]);
693 >        Result := true;
694 >      end;
695 >
696 >    trCommitted:
697 >      begin
698 >        LogEntry := Format(sTransCommitJnl,[FBFormatDateTime(GetDateTimeFmt,Now),
699 >                                            GetAttachment.GetAttachmentID,
700 >                                            FSessionID,TransactionID]);
701 >        Result := true;
702 >      end;
703 >
704 >    trCommitFailed:
705 >      begin
706 >        LogEntry := Format(sTransCommitFailJnl,[FBFormatDateTime(GetDateTimeFmt,Now),
707 >                                            GetAttachment.GetAttachmentID,
708 >                                            FSessionID,TransactionID]);
709          Result := true;
710        end;
711      end;
# Line 684 | Line 720 | begin
720      case Action of
721        TACommitRetaining:
722            LogEntry := Format(sTransCommitRetJnl,[FBFormatDateTime(GetDateTimeFmt,Now),
723 +                                  GetAttachment.GetAttachmentID,
724                                    FSessionID,Tr.GetTransactionID,OldTransactionID]);
725        TARollbackRetaining:
726            LogEntry := Format(sTransRollbackRetJnl,[FBFormatDateTime(GetDateTimeFmt,Now),
727 +                                      GetAttachment.GetAttachmentID,
728                                        FSessionID,Tr.GetTransactionID,OldTransactionID]);
729      end;
730      if assigned(FJournalFileStream) then
731        FJournalFileStream.Write(LogEntry[1],Length(LogEntry));
732  
733 <    FDoNotJournal := true;
733 >    if not (joNoServerTable in FOptions) then
734      try
735 +      FDoNotJournal := true;
736        GetAttachment.ExecuteSQL(Tr,sqlRecordJournalEntry,[FSessionID,Tr.GetTransactionID,OldTransactionID]);
737      finally
738        FDoNotJournal := false;
# Line 706 | Line 745 | var SQL: AnsiString;
745   begin
746    SQL := TQueryProcessor.Execute(Stmt);
747    LogEntry := Format(sQueryJournal,[FBFormatDateTime(GetDateTimeFmt,Now),
748 +                                      GetAttachment.GetAttachmentID,
749                                        FSessionID,
750                                        Stmt.GetTransaction.GetTransactionID,
751                                        Length(SQL),SQL]);
# Line 713 | Line 753 | begin
753      FJournalFileStream.Write(LogEntry[1],Length(LogEntry));
754   end;
755  
756 + procedure TFBJournaling.ExecImmediateJnl(sql: AnsiString; tr: ITransaction);
757 + var LogEntry: AnsiString;
758 + begin
759 +  LogEntry := Format(sQueryJournal,[FBFormatDateTime(GetDateTimeFmt,Now),
760 +                                      GetAttachment.GetAttachmentID,
761 +                                      FSessionID,
762 +                                      tr.GetTransactionID,
763 +                                      Length(sql),sql]);
764 +  if assigned(FJournalFileStream) then
765 +    FJournalFileStream.Write(LogEntry[1],Length(LogEntry));
766 + end;
767 +
768   function TFBJournaling.JournalingActive: boolean;
769   begin
770    Result := (FJournalFileStream <> nil) and not FDoNotJournal;
# Line 731 | Line 783 | end;
783   function TFBJournaling.StartJournaling(aJournalLogFile: AnsiString;
784    Options: TJournalOptions): integer;
785   begin
786 +  try
787 +    StartJournaling(TFileStream.Create(aJournalLogFile,fmCreate),Options);
788 +  finally
789 +    FJournalFilePath := aJournalLogFile;
790 +  end;
791 + end;
792 +
793 + function TFBJournaling.StartJournaling(S: TStream; Options: TJournalOptions
794 +  ): integer;
795 + begin
796    FOptions := Options;
797 +  if not (joNoServerTable in FOptions) then
798    with GetAttachment do
799    begin
800 <    if not HasTable(sJournalTableName) then
800 >    if  not HasTable(sJournalTableName) then
801      begin
802        ExecImmediate([isc_tpb_write,isc_tpb_wait,isc_tpb_consistency],sqlCreateJournalTable);
803        ExecImmediate([isc_tpb_write,isc_tpb_wait,isc_tpb_consistency],sqlCreateSequence);
804      end;
805      FSessionID := OpenCursorAtStart(sqlGetNextSessionID)[0].AsInteger;
806    end;
807 <  FJournalFilePath := aJournalLogFile;
745 <  FJournalFileStream := TFileStream.Create(FJournalFilePath,fmCreate);
807 >  FJournalFileStream := S;
808    Result := FSessionID;
809   end;
810  
# Line 751 | Line 813 | begin
813    EndSession(RetainJournal);
814   end;
815  
754
755
756
816   { TFBAttachment }
817  
818 < procedure TFBAttachment.GetODSAndConnectionInfo;
819 < var DBInfo: IDBInformation;
761 <    i: integer;
762 <    Stmt: IStatement;
818 > procedure TFBAttachment.NeedConnectionInfo;
819 > var Stmt: IStatement;
820      ResultSet: IResultSet;
821      Param: IDPBItem;
822   begin
823 <  if not IsConnected then Exit;
824 <  DBInfo := GetDBInformation([isc_info_db_id,isc_info_ods_version,isc_info_ods_minor_version,
768 <                               isc_info_db_SQL_Dialect]);
769 <  for i := 0 to DBInfo.GetCount - 1 do
770 <    with DBInfo[i] do
771 <      case getItemType of
772 <      isc_info_ods_minor_version:
773 <        FODSMinorVersion := getAsInteger;
774 <      isc_info_ods_version:
775 <        FODSMajorVersion := getAsInteger;
776 <      isc_info_db_SQL_Dialect:
777 <        FSQLDialect := getAsInteger;
778 <      end;
779 <
823 >  if not IsConnected or FHasConnectionInfo then Exit;
824 >  NeedDBInfo;
825    FCharSetID := 0;
826    FRemoteProtocol := '';
827    FAuthMethod := 'Legacy_Auth';
# Line 822 | Line 867 | begin
867      end;
868    end;
869    FHasDefaultCharSet := CharSetID2CodePage(FCharSetID,FCodePage) and (FCharSetID > 1);
870 +  FHasConnectionInfo := true;
871 + end;
872 +
873 + procedure TFBAttachment.NeedDBInfo;
874 + var DBInfo: IDBInformation;
875 +    i: integer;
876 + begin
877 +  if not IsConnected or (FAttachmentID > 0) then Exit;
878 +  DBInfo := GetDBInformation([isc_info_db_id,isc_info_ods_version,isc_info_ods_minor_version,
879 +                               isc_info_db_SQL_Dialect, isc_info_attachment_id]);
880 +  for i := 0 to DBInfo.GetCount - 1 do
881 +    with DBInfo[i] do
882 +      case getItemType of
883 +      isc_info_ods_minor_version:
884 +        FODSMinorVersion := getAsInteger;
885 +      isc_info_ods_version:
886 +        FODSMajorVersion := getAsInteger;
887 +      isc_info_db_SQL_Dialect:
888 +        FSQLDialect := getAsInteger;
889 +      isc_info_attachment_id:
890 +        FAttachmentID := getAsInteger;
891 +      end;
892   end;
893  
894   constructor TFBAttachment.Create(api: TFBClientAPI; DatabaseName: AnsiString;
# Line 831 | Line 898 | begin
898    FFirebirdAPI := api.GetAPI; {Keep reference to interface}
899    FSQLDialect := 3;
900    FDatabaseName := DatabaseName;
834  FDPB := DPB;
901    SetLength(FUserCharSetMap,0);
902 +  ClearCachedInfo;
903 +  FInlineBlobLimit := DefaultMaxInlineBlobLimit;
904 +  FDPB := DPB;
905    FRaiseExceptionOnConnectError := RaiseExceptionOnConnectError;
906 + end;
907 +
908 + procedure TFBAttachment.ClearCachedInfo;
909 + begin
910 +  FHasDefaultCharSet := false;
911 +  FAttachmentID := 0;
912    FODSMajorVersion := 0;
913    FODSMinorVersion := 0;
914 <  FInlineBlobLimit := DefaultMaxInlineBlobLimit;
914 >  FCodePage := CP_NONE;
915 >  FCharSetID := 0;
916 >  FRemoteProtocol := '';
917 >  FAuthMethod := '';
918 >  FSecDatabase := '';
919 >  FHasConnectionInfo := false;
920   end;
921  
922   function TFBAttachment.GenerateCreateDatabaseSQL(DatabaseName: AnsiString;  aDPB: IDPB): AnsiString;
# Line 970 | Line 1050 | begin
1050    end;
1051   end;
1052  
1053 + procedure TFBAttachment.SetSQLDialect(aValue: integer);
1054 + begin
1055 +  FSQLDialect := aValue;
1056 + end;
1057 +
1058   procedure TFBAttachment.UseServerICUChanged;
1059   begin
1060    // Do nothing by default
# Line 981 | Line 1066 | begin
1066    inherited Destroy;
1067   end;
1068  
1069 + procedure TFBAttachment.Disconnect(Force: boolean);
1070 + begin
1071 +  inherited Disconnect(Force);
1072 +  ClearCachedInfo;
1073 + end;
1074 +
1075   function TFBAttachment.getFirebirdAPI: IFirebirdAPI;
1076   begin
1077    Result := FFirebirdAPI;
# Line 1003 | Line 1094 | end;
1094  
1095   procedure TFBAttachment.ExecImmediate(TPB: array of byte; sql: AnsiString;
1096    aSQLDialect: integer);
1097 + var tr: ITransaction;
1098   begin
1099 <  ExecImmediate(StartTransaction(TPB,taCommit),sql,aSQLDialect);
1099 >  tr := StartTransaction(TPB,taCommit);
1100 >  try
1101 >    ExecImmediate(tr,sql,aSQLDialect);
1102 >    tr.Commit;
1103 >  except
1104 >    tr.Rollback(true);
1105 >    raise;
1106 >  end;
1107   end;
1108  
1109   procedure TFBAttachment.ExecImmediate(transaction: ITransaction; sql: AnsiString);
# Line 1014 | Line 1113 | end;
1113  
1114   procedure TFBAttachment.ExecImmediate(TPB: array of byte; sql: AnsiString);
1115   begin
1116 <  ExecImmediate(StartTransaction(TPB,taCommit),sql,FSQLDialect);
1116 >  ExecImmediate(TPB,sql,FSQLDialect);
1117   end;
1118  
1119   function TFBAttachment.ExecuteSQL(TPB: array of byte; sql: AnsiString;
1120    SQLDialect: integer; params: array of const): IResults;
1121 + var tr: ITransaction;
1122   begin
1123 <  Result := ExecuteSQL(StartTransaction(TPB,taCommit),sql,SQLDialect,params);
1123 >  tr := StartTransaction(TPB,taCommit);
1124 >  try
1125 >    Result := ExecuteSQL(tr,sql,SQLDialect,params);
1126 >  except
1127 >    tr.Rollback(true);
1128 >    raise;
1129 >  end;
1130   end;
1131  
1132   function TFBAttachment.ExecuteSQL(transaction: ITransaction; sql: AnsiString;
# Line 1036 | Line 1142 | end;
1142   function TFBAttachment.ExecuteSQL(TPB: array of byte; sql: AnsiString;
1143    params: array of const): IResults;
1144   begin
1145 <   Result := ExecuteSQL(StartTransaction(TPB,taCommit),sql,params);
1145 >   Result := ExecuteSQL(TPB,sql,FSQLDialect,params);
1146   end;
1147  
1148   function TFBAttachment.ExecuteSQL(transaction: ITransaction; sql: AnsiString;
1149    params: array of const): IResults;
1150   begin
1151 <  with Prepare(transaction,sql,FSQLDialect) do
1046 <  begin
1047 <    SetParameters(SQLParams,params);
1048 <    Result := Execute;
1049 <  end;
1151 >  Result := ExecuteSQL(transaction,sql,FSQLDialect,params);
1152   end;
1153  
1154   function TFBAttachment.OpenCursor(transaction: ITransaction; sql: AnsiString;
# Line 1139 | Line 1241 | end;
1241  
1242   function TFBAttachment.OpenCursorAtStart(sql: AnsiString; Scrollable: boolean;
1243    params: array of const): IResultSet;
1244 + var tr: ITransaction;
1245   begin
1246 <  Result := OpenCursorAtStart(StartTransaction([isc_tpb_read,isc_tpb_wait,isc_tpb_concurrency],taCommit),sql,FSQLDialect,
1247 <                   Scrollable,params);
1246 >  tr := StartTransaction([isc_tpb_read,isc_tpb_wait,isc_tpb_concurrency],taCommit);
1247 >  try
1248 >    Result := OpenCursorAtStart(tr,sql,FSQLDialect,Scrollable,params);
1249 >  except
1250 >    tr.Rollback(true);
1251 >    raise;
1252 >  end;
1253   end;
1254  
1255   function TFBAttachment.OpenCursorAtStart(sql: AnsiString;
1256    params: array of const): IResultSet;
1257   begin
1258 <  Result := OpenCursorAtStart(StartTransaction([isc_tpb_read,isc_tpb_wait,isc_tpb_concurrency],taCommit),sql,FSQLDialect,
1151 <                   false,params);
1258 >  Result := OpenCursorAtStart(sql,false,params);
1259   end;
1260  
1261   function TFBAttachment.Prepare(transaction: ITransaction; sql: AnsiString;
# Line 1178 | Line 1285 | end;
1285  
1286   function TFBAttachment.GetSQLDialect: integer;
1287   begin
1288 +  NeedDBInfo;
1289    Result := FSQLDialect;
1290   end;
1291  
1292 + function TFBAttachment.GetAttachmentID: integer;
1293 + begin
1294 +  NeedDBInfo;
1295 +  Result := FAttachmentID;
1296 + end;
1297 +
1298   function TFBAttachment.CreateBlob(transaction: ITransaction; RelationName,
1299    ColumnName: AnsiString; BPB: IBPB): IBlob;
1300   begin
# Line 1250 | Line 1364 | begin
1364      Result := GetDBInfo(getBuffer,getDataLength);
1365   end;
1366  
1253 function TFBAttachment.GetAttachmentID: integer;
1254 var Info: IDBInformation;
1255 begin
1256  Info := GetDBInformation(isc_info_attachment_id);
1257  if (Info.Count > 0) and (Info[0].getItemType = isc_info_attachment_id) then
1258    Result := Info[0].getAsInteger
1259  else
1260    Result := -1;
1261 end;
1262
1367   function TFBAttachment.GetConnectString: AnsiString;
1368   begin
1369    Result := FDatabaseName;
# Line 1267 | Line 1371 | end;
1371  
1372   function TFBAttachment.GetRemoteProtocol: AnsiString;
1373   begin
1374 +  NeedConnectionInfo;
1375    Result := FRemoteProtocol;
1376   end;
1377  
1378   function TFBAttachment.GetAuthenticationMethod: AnsiString;
1379   begin
1380 +  NeedConnectionInfo;
1381    Result := FAuthMethod;
1382   end;
1383  
1384   function TFBAttachment.GetSecurityDatabase: AnsiString;
1385   begin
1386 +  NeedConnectionInfo;
1387    Result := FSecDatabase;
1388   end;
1389  
1390   function TFBAttachment.GetODSMajorVersion: integer;
1391   begin
1392 +  NeedDBInfo;
1393    Result := FODSMajorVersion;
1394   end;
1395  
1396   function TFBAttachment.GetODSMinorVersion: integer;
1397   begin
1398 +  NeedDBInfo;
1399    Result := FODSMinorVersion;
1400   end;
1401  
1402 + function TFBAttachment.GetCharSetID: integer;
1403 + begin
1404 +  NeedConnectionInfo;
1405 +  Result := FCharSetID;
1406 + end;
1407 +
1408   function TFBAttachment.HasDecFloatSupport: boolean;
1409   begin
1410    Result := false;
# Line 1320 | Line 1435 | begin
1435            [aTableName])[0].AsInteger > 0;
1436   end;
1437  
1438 + function TFBAttachment.HasFunction(aFunctionName: AnsiString): boolean;
1439 + begin
1440 +  Result := OpenCursorAtStart(
1441 +       'Select count(*) From RDB$FUNCTIONS Where RDB$FUNCTION_NAME = ?',
1442 +          [aFunctionName])[0].AsInteger > 0;
1443 + end;
1444 +
1445 + function TFBAttachment.HasProcedure(aProcName: AnsiString): boolean;
1446 + begin
1447 +  Result := OpenCursorAtStart(
1448 +       'Select count(*) From RDB$PROCEDURES Where RDB$PROCEDURE_NAME = ?',
1449 +          [aProcName])[0].AsInteger > 0;
1450 + end;
1451 +
1452   function TFBAttachment.HasDefaultCharSet: boolean;
1453   begin
1454 +  NeedConnectionInfo;
1455    Result := FHasDefaultCharSet
1456   end;
1457  
1458   function TFBAttachment.GetDefaultCharSetID: integer;
1459   begin
1460 +  NeedConnectionInfo;
1461    Result := FCharsetID;
1462   end;
1463  

Comparing ibx/branches/udr/client/FBAttachment.pas (property svn:eol-style):
Revision 370 by tony, Wed Jan 5 14:59:15 2022 UTC vs.
Revision 389 by tony, Thu Jan 20 23:33:40 2022 UTC

# Line 0 | Line 1
1 + native

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines