AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Datenbanken Datenbank-Metainformationen abfragen schlägt fehl
Thema durchsuchen
Ansicht
Themen-Optionen

Datenbank-Metainformationen abfragen schlägt fehl

Ein Thema von TiGü · begonnen am 16. Mär 2016 · letzter Beitrag vom 16. Mär 2016
Antwort Antwort
Seite 1 von 2  1 2      
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.070 Beiträge
 
Delphi 10.4 Sydney
 
#1

Datenbank-Metainformationen abfragen schlägt fehl

  Alt 16. Mär 2016, 11:41
Datenbank: MS SQL • Version: 2005 • Zugriff über: FireDAC
Hallo Gemeinde,

vorab: ich bin in Sachen Datenbanken relativ unbeleckt.

Ich will von einer Datenbank die Tabellennamen und die Feldinformationen per FireDAC abfragen und als XML-Schema abspeichern.

Delphi-Version ist Seattle Enterprise mit Update 1.
Die Datenbank läuft auf einen MS SQL Server 2005.
Sie hat 96 Tabellen mit verschiedenen vielen Feldern.

Ich befolge den Tipp von Uwe Raabe (http://stackoverflow.com/a/21025749) und hole mir über TFDTable.FieldDefs.Update die Felddefinitionen und möchte sie zunächst per SaveToFile als XML abspeichern.

Jedoch fliegt mir nach ca. fünf bis sechs geholten Tabellen und abgespeicherten XML-Schemta eine EMSSQLNativeException um die Ohren und ich weiß gerade nicht weiter.

Weiß jemand Rat?

Es folgt der Quelltext, Exception und Callstack:

Delphi-Quellcode:
procedure TDbStructureExporter.SaveDatabaseDetails(
  const ACatalogName: string;
  const ASchemaName: string = '';
  const APattern: string = '');
var
  Con: TFDCustomConnection;
  TableList: TStringList;
  TableName, FieldName: string;
begin
  Con := FConnectionWrapper.Connecton;

  TableList := TStringList.Create;
  try
    Con.GetTableNames(ACatalogName, ASchemaName, APattern, TableList);
    for TableName in TableList do
    begin
      ExportTable(TableName);
    end;
  finally
    TableList.Free;
  end;
end;

procedure TDbStructureExporter.ExportTable(const ATableName: string);
var
  LConnection: TFDCustomConnection;
  LTable: TFDTable;
  LTableName: string;
begin
  CoInitialize(nil);
  try
    LTableName := ATableName;

    LConnection := TFDCustomConnection.Create(nil);
    LConnection.ConnectionDefName := cConnectionDef;
    LConnection.Connected := True;
    try
      LTable := TFDTable.Create(nil);
      LTable.Connection := LConnection;
      try
        LTable.Open(LTableName); // <--- hier knallts dann!

        LTable.FieldDefs.Update;
        if LTable.FieldDefs.Updated then
          LTable.SaveToFile('C:\Temp\' + LTableName + '.xml', TFDStorageFormat.sfXML);
      finally
        LTable.Free;
      end;
      LConnection.Connected := False;
    finally
      LConnection.Free;
    end;
  finally
    CoUninitialize;
  end;
end;
Code:
Project DbStructureExportVCL.exe raised exception class EMSSQLNativeException with message '[FireDAC][Phys][ODBC][Microsoft][ODBC SQL Server Driver]Die Verbindung ist mit Ergebnissen von einem anderen hstmt belegt'.



:74e3dad8 KERNELBASE.RaiseException + 0x48
FireDAC.Stan.Error.FDException(???,???,???)
FireDAC.Phys.ODBCWrapper.TODBCHandle.ProcessError(???)
FireDAC.Phys.ODBCWrapper.TODBCHandle.Check(???)
FireDAC.Phys.ODBCWrapper.TODBCMetaInfoStatement.Execute
FireDAC.Phys.ODBCBase.TFDPhysODBCCommand.OpenMetaInfo
FireDAC.Phys.ODBCBase.TFDPhysODBCCommand.InternalOpen
FireDAC.Phys.TFDPhysCommand.OpenBase
FireDAC.Phys.TFDPhysCommandAsyncOpen.Execute
FireDAC.Stan.Async.TFDStanAsyncExecutor.ExecuteOperation(False)
FireDAC.Stan.Async.TFDStanAsyncExecutor.Run
FireDAC.Phys.TFDPhysCommand.ExecuteTask(TFDPhysCommandAsyncOpen($3277210) as IFDStanAsyncOperation,nil,False)
FireDAC.Phys.TFDPhysCommand.Open(False)
FireDAC.Phys.Meta.TFDPhysConnectionMetadata.FetchToCache(mkPrimaryKey,'MyDatabaseName','dbo','','MyTableName',0,$31B8CB0)
FireDAC.Phys.Meta.TFDPhysConnectionMetadata.GetTablePrimaryKey('MyDatabaseName','dbo','MyTableName')
FireDAC.Phys.ODBCBase.TFDPhysODBCCommand.OpenMetaInfo
FireDAC.Phys.ODBCBase.TFDPhysODBCCommand.InternalOpen
FireDAC.Phys.TFDPhysCommand.OpenBase
FireDAC.Phys.TFDPhysCommandAsyncOpen.Execute
FireDAC.Stan.Async.TFDStanAsyncExecutor.ExecuteOperation(False)
FireDAC.Stan.Async.TFDStanAsyncExecutor.Run
FireDAC.Phys.TFDPhysCommand.ExecuteTask(TFDPhysCommandAsyncOpen($3277050) as IFDStanAsyncOperation,nil,False)
FireDAC.Phys.TFDPhysCommand.Open(False)
FireDAC.Phys.Meta.TFDPhysConnectionMetadata.FetchToCache(mkIndexes,'','','','MyTableName',0,$31B8BC0)
FireDAC.Phys.Meta.TFDPhysConnectionMetadata.GetTableIndexes('','','MyTableName','')
FireDAC.Comp.Client.TFDTable.UpdateIndexDefs
Data.DB.TDefCollection.UpdateDefs((FireDAC.Comp.Client.TFDTable.UpdateIndexDefs,$320EB70))
Data.DB.TIndexDefs.Update
FireDAC.Comp.DataSet.TFDDataSet.OpenIndexes
FireDAC.Comp.DataSet.TFDDataSet.InternalOpen
Data.DB.TDataSet.DoInternalOpen
Data.DB.TDataSet.OpenCursor(???)
FireDAC.Comp.DataSet.TFDDataSet.OpenCursor(False)
FireDAC.Comp.Client.TFDRdbmsDataSet.OpenCursor(False)
FireDAC.Comp.Client.TFDTable.OpenCursor(False)
Data.DB.TDataSet.SetActive(???)
FireDAC.Comp.DataSet.TFDDataSet.SetActive(???)
Data.DB.TDataSet.Open
FireDAC.Comp.Client.TFDTable.Open(???)
DbStructureExporter.TDbStructureExporter.ExportTable('MyTableName')
DbStructureExporter.TDbStructureExporter.SaveDatabaseDetails('MyDatabaseName','dbo','')
DbStructureExporter.View.TForm1.Button1Click($31FC9A0)
  Mit Zitat antworten Zitat
Benutzerbild von baumina
baumina

Registriert seit: 5. Mai 2008
Ort: Oberschwaben
1.275 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: Datenbank-Metainformationen abfragen schlägt fehl

  Alt 16. Mär 2016, 12:01
Ich gehe davon aus, dass du einfach zu viele Connections auf die Datenbank hast. Nimm doch einfach immer ein und dieselbe Connection, statt jedesmal eine neue zu machen.
Hinter dir gehts abwärts und vor dir steil bergauf ! (Wolfgang Ambros)
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#3

AW: Datenbank-Metainformationen abfragen schlägt fehl

  Alt 16. Mär 2016, 12:12
Also wenn ich mich da nicht verkuckt habe hat er nur zwei Connections offen.
Eine für die Tabellennamen und eine um die Feldnamen zu holen, die wird aber ordentlich geschlossen nach jeder Abfrage.
Vielleicht wäre es sinnvoll zuerst die Tabellennamen zu holen, und dann die Feldnamen?

Gruß
K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
  Mit Zitat antworten Zitat
Benutzerbild von baumina
baumina

Registriert seit: 5. Mai 2008
Ort: Oberschwaben
1.275 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: Datenbank-Metainformationen abfragen schlägt fehl

  Alt 16. Mär 2016, 13:05
Was ich meinte war: Für jede Tabelle wird eine Connection erzeugt, geöffnet, geschlossen und weggeworfen, keine Ahnung ob der Server das alles so schnell mitbekommt, zudem das unnötig Zeit vergeudet.
Hinter dir gehts abwärts und vor dir steil bergauf ! (Wolfgang Ambros)
  Mit Zitat antworten Zitat
nahpets
(Gast)

n/a Beiträge
 
#5

AW: Datenbank-Metainformationen abfragen schlägt fehl

  Alt 16. Mär 2016, 13:12
Also diesen Teil würde ich erstmal ändern:
Delphi-Quellcode:
      try
        LTable.Open(LTableName); // <--- hier knallts dann!

        LTable.FieldDefs.Update;
        if LTable.FieldDefs.Updated then
          LTable.SaveToFile('C:\Temp\' + LTableName + '.xml', TFDStorageFormat.sfXML);
      finally
        LTable.Free;
      end;
in etwa so:
Delphi-Quellcode:
try
  try
    LTable.Open(LTableName);
    LTable.FieldDefs.Update;
    if LTable.FieldDefs.Updated then
      LTable.SaveToFile('C:\Temp\' + LTableName + '.xml', TFDStorageFormat.sfXML);
  except
    // Die Fehlermeldungen sinnvollerweise irgendwie mitloggen, um dann ggfls. gezielter suchen zu können.
    on e : Exception do ShowMessage(LTableName + #13 + e.Message);
  end;
finally
  LTable.Free;
end;
Und dann schauen wir erstmal, bei welcher Tabelle es kracht.

Meine Erfahrung ist, dass das Auslesen von Tabellendefinitionen nicht immer und unbegrenzt bei allen Datenbank funktioniert. Insbesondere bei Systemtabellen kann es schonmal krachen.

Die meisten Datenbanken haben Views, mit denen man an die Tabellendefinitionen ... kommen kann. Beim SQL-Server ist es das Information Schema.
Sofern Dein Programm nicht mit beliebigen Datenbanken zurechtkommen muss, sondern nur mit SQL-Server würd' ich,
wenn alle Stricke reißen, dort suchen.

Sinngemäß in etwa so:
Delphi-Quellcode:
qry.SQL := Format('SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, COLUMN_DEFAULT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = %s
',[QuotedStr(LTableName)]);
Welche Tabelleninformationen zur Verfügung stehen, erfährt man hier unter Columns.

Das Information-Schema gehört zum Ansi-Standard (https://en.wikipedia.org/wiki/Information_schema) und steht bei ein paar Datenbanken zur Verfügung.

Ist jetzt nur hingedaddelt und nicht getestet.

Wie Baumina schon anmerkt, würde ich Con mit an Exporttable übergeben und dann LTable zuweisen.

Für jede Tabelle eine eigene Verbindung erstellen, aufmachen, Infos holen, Verbindung wegwerfen, halte ich nicht für wirklich sinnvoll.
  Mit Zitat antworten Zitat
Benutzerbild von dataspider
dataspider

Registriert seit: 9. Nov 2003
Ort: 04539 Groitzsch
1.351 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: Datenbank-Metainformationen abfragen schlägt fehl

  Alt 16. Mär 2016, 13:16
Also wenn ich mich da nicht verkuckt habe hat er nur zwei Connections offen.
Die Fehlermeldung würde aber Baumina' s Vermutung stützen.

Das Connect und Disconnect gehört IMHO in die andere Procedure (SaveDatabaseDetails).

Frank
Frank Reim
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.070 Beiträge
 
Delphi 10.4 Sydney
 
#7

AW: Datenbank-Metainformationen abfragen schlägt fehl

  Alt 16. Mär 2016, 13:27
Selbst wenn ich ein- und dieselbe TFDCustomConnection-Instanz verwende, erhalte ich regelmäßig beim Versuch die sechste von 96 Tabellen zu öffnen die oben genannte Exception.

Delphi-Quellcode:
procedure TDbStructureExporter.SaveDatabaseDetails(
  const ACatalogName: string;
  const ASchemaName: string = '';
  const APattern: string = '');
var
  TableList: TStringList;
  TableName: string;
begin
  TableList := TStringList.Create;
  try
    FConnectionWrapper.Connecton.GetTableNames(ACatalogName, ASchemaName, APattern, TableList);
    CoInitialize(nil);
    for TableName in TableList do
    begin
      ExportTable(TableName);
    end;
    CoUninitialize;
  finally
    TableList.Free;
  end;
end;

procedure TDbStructureExporter.ExportTable(const ATableName: string);
var
  LTable: TFDTable;
  LTableName: string;
begin
  LTableName := ATableName;

  LTable := TFDTable.Create(nil);
  LTable.Connection := FConnectionWrapper.Connecton;
  try
    if LTable.Connection.Connected then
    begin
      LTable.Open(LTableName); // <--- hier knallts dann!

      LTable.FieldDefs.Update;
      if LTable.FieldDefs.Updated then
        LTable.SaveToFile('C:\Temp\' + LTableName + '.xml', TFDStorageFormat.sfXML);
    end;
  finally
    LTable.Free;
  end;
end;

Geändert von TiGü (16. Mär 2016 um 13:30 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von baumina
baumina

Registriert seit: 5. Mai 2008
Ort: Oberschwaben
1.275 Beiträge
 
Delphi 11 Alexandria
 
#8

AW: Datenbank-Metainformationen abfragen schlägt fehl

  Alt 16. Mär 2016, 13:37
Wie lautet der Name dieser Tabelle? Name mit Leerzeichen/Sonderzeichen? Systemtabelle?
Hinter dir gehts abwärts und vor dir steil bergauf ! (Wolfgang Ambros)
  Mit Zitat antworten Zitat
nahpets
(Gast)

n/a Beiträge
 
#9

AW: Datenbank-Metainformationen abfragen schlägt fehl

  Alt 16. Mär 2016, 13:41
Und was ist an der sechsten Tabelle anders als an den anderen?
Wenn Du die sechste Tabelle überspringst (Hat sie einen Namen? Was für 'ne Tabelle ist das denn?), kommst Du dann bis zur 96. Tabelle? Oder kommen dann noch weitere Fehler?

Die beiden würd' ich nicht "alle Nase lang" aufrufen, sondern nur einmalig:
Delphi-Quellcode:
Unit irgendwas;

...

initialization
  CoInitialize(nil);

finalization
  CoUninitialize;
end.
Oder wäre das nicht ausreichend?
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.070 Beiträge
 
Delphi 10.4 Sydney
 
#10

AW: Datenbank-Metainformationen abfragen schlägt fehl

  Alt 16. Mär 2016, 13:50
Die sechste Tabelle habe ich schon durch skippen (if TableName = 'GenauDieseTabelle' then exit) ausgeschlossen.
Bei den darauffolgenden Tabellen passiert der Fehler auch und das sind meiner Meinung nach alles normale Tabellen ohne große Besonderheiten.
Die Tabelle heißt 'ItemEntries' und hat 60 Felder.

Vielen Dank aber bis hierhin für eure Mühe, aber ihr braucht euch darüber jetzt nicht weiter den Kopf zerbrechen.
Ich habe das mit der Table sein gelassen und eine Query mit SQL '...where 1=2' verwendet (siehe Quelltext unten).
Damit habe ich mein Ziel erfüllt.
Falls noch jemand einen eleganteren Weg hat, nur her damit!

PS: Das mit den Co(Un)Initialize deswegen, falls das in einen eigenen Threadkontext ausgeführt wird.
Ich hatte nämlich versuchsweise jede Tabellenabfrage in einen eigenen Task und das schreiben der XML per MSXML ging dann nicht mehr.

Delphi-Quellcode:
procedure TDbStructureExporter.SaveDatabaseDetails(
  const ACatalogName: string;
  const ASchemaName: string = '';
  const APattern: string = '');
var
  TableList: TStringList;
  TableName: string;
begin
  TableList := TStringList.Create;
  try
    FConnectionWrapper.Connecton.GetTableNames(ACatalogName, ASchemaName, APattern, TableList);
    CoInitialize(nil);
    try
      for TableName in TableList do
      begin
        ExportTable(TableName);
      end;
    finally
      CoUninitialize;
    end;
  finally
    TableList.Free;
  end;
end;

procedure TDbStructureExporter.ExportTable(const ATableName: string);
var
  LQuery: TFDQuery;
begin
  LQuery := TFDQuery.Create(nil);
  try
    LQuery.Connection := FConnectionWrapper.Connecton;
    LQuery.SQL.Clear;
    LQuery.SQL.Add('select * from ' + ATableName + ' where 1=2');
    LQuery.Active := True;
    LQuery.SaveToFile('C:\Temp\' + ATableName + '.xml', TFDStorageFormat.sfXML);
  finally
    LQuery.Free;
  end;
end;
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:42 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz