Konkatenation von Strings einer ADO-Query verursacht unverständlichen Fehler



  • Der folgende Code verursacht bei mir eine EAccessViolation im Debugger, die Anwendung gibt eine "Abnormal program termination" aus.
    Was mich sehr verwundert, ist das der catch-Block nicht durchlaufen wird, so daß ich keine ordentliche Fehlermeldung ausgeben kann.

    Der Fehler, der gefangen werden soll, ist der, daß das Feld in der Datenbank nicht vorhanden ist.

    AnsiString sqlstring;
    try
    {
       sqlstring = qryIrgendwas->FieldByName("VorhandenesFeld")->AsString 
                 + qryIrgendwas->FieldByName("FehlendesFeld")->AsString;
    }
    catch (Exception &e)
    {
       //Die Exeption kommt hier nicht an!
       Application->MessageBox(e.Message.c_str(), "Fehler...", MB_OK | MB_ICONERROR);
       return;
    }
    

    Baue ich den Code wie folgt um, dann bekomme ich eine ordentliche Exeption mit der Meldung "qryIrgendwas: Das Feld "FehlendesFeld" wurde nicht gefunden", so wie es sein sollte.

    AnsiString sqlstring;
    try
    {
       sqlstring = qryIrgendwas->FieldByName("VorhandenesFeld")->AsString;
       sqlstring = sqlstring + qryIrgendwas->FieldByName("FehlendesFeld")->AsString;
    }
    catch (Exception &e)
    {
       //So kommt der Fehler hier an.
       Application->MessageBox(e.Message.c_str(), "Fehler...", MB_OK | MB_ICONERROR);
       return;
    }
    

    Der einzige Unterschied zwischen den zwei Codebeispielen ist, daß ich bei der ersten Version die Zeichenkettenverkettung mit einem Befehl mache.

    Vielleicht hat ja irgendjemand eine Erklärung für dieses Phänomen, oder sogar eine Lösung bei der ich nicht meinen gesamten Code umbauen muss. Solche Syntaxkonstruktionen benutze ich nämlich ständig.

    Noch ein paar Infos: Ich arbeite mit ADO-Objekten und qryIrgendwas ist vom Typ TAdoQuery. EDIT: Ich entwickle mit dem BCB6.



  • Hallo

    Also meine Empfehlung ist ganz klar, gar nicht erst fehlende Felder abzufragen.
    Wenn du eine Abfrage mit dynamischen Feldnamen hast, verwende entweder die SPaltenindexe anstelle der Feldnamen. Oder du überprüfst erstmal mit ::FindField, ob das gesuchte Feld überhaupt da ist.
    Exceptions sollten eher für wirklich nicht zu erwartende Fehler verwendet werden. Besteht bei deinem Konzept die Möglichkeit, das ein Feld nicht vorhanden ist, solltest du besser eigene Ablauflogik verwenden.

    bis bald
    akari



  • akari schrieb:

    Hallo

    Also meine Empfehlung ist ganz klar, gar nicht erst fehlende Felder abzufragen.
    Wenn du eine Abfrage mit dynamischen Feldnamen hast, verwende entweder die SPaltenindexe anstelle der Feldnamen. Oder du überprüfst erstmal mit ::FindField, ob das gesuchte Feld überhaupt da ist.
    Exceptions sollten eher für wirklich nicht zu erwartende Fehler verwendet werden. Besteht bei deinem Konzept die Möglichkeit, das ein Feld nicht vorhanden ist, solltest du besser eigene Ablauflogik verwenden.

    bis bald
    akari

    Fehlende Felder müssen aus dem Grund abgefangen werden, da gelegentlich unsere bestehenden Tabellen um zusätzliche Felder erweitert werden. Bekommt ein Kunde dann ein Programmupdate und es wird vergessen das Datenbankmodify zu fahren, dann muss eine verwertebare Fehlermeldung erscheinen.
    Das ist eigentlich also ein nicht erwarteter Fehler, der aber gelegentlich auftritt.



  • Hallo

    Da wäre wohl eine Versionkontrolle sinnvoller 😉
    Zumindestens kann ich dein Problem mit dem Builder 5 und TQuery nicht nachvollziehen. Ich habe ein TQuery auf die Paradox-Tabelle "animals" und dann folgenden Code ausgeführt :

    try
      {
        AnsiString Buffer = Query1->FieldByName("name")->AsString
          + Query1->FieldByName("size11")->AsString;
        ShowMessage(Buffer);
      }
      catch (Exception& e)
      {
        ShowMessage(e.Message);
      }
    

    size11 ist nicht vorhanden, und das wird auch sauber von der Exception angezeigt. Da ich vermute das die Implementation von FieldByName bereits in TDataSet komplett ist, kann ich mir nicht vorstellen das bei der ADO-Query-Komponente da anderer Code vorhanden ist. Außerdem kann ich auch aus meiner Erfahrung heraus nicht den von dir genannten Unterschied in der Exceptionbehandlung erklären. Vielleicht kann ja jemand mit einem moderneren Builder was dazu sagen.

    bis bald
    akari



  • Das Beispiel aus meinem letzten Post war nicht ganz treffend, da ein solcher Fall schon beim select einen Fehler bringen würde. Aber egal...

    Das was mich am meisten stört, ist das die Exeption nicht gefangen wird. So kann man in der Fehlerbehandlung nicht die verursachende Programmstelle ausgeben. Wenn ich mich nicht täusche, wurden auch die Destruktoren nach dem Fehler nicht durchlaufen.

    Ich bin mir sicher, daß bei den BDE-Komponenten der Fehler nicht aufgetreten ist, sonst hätte ich das früher schon gemerkt. Vielleicht liegt es an der Oracle-Datenbank, oder an der MDAC-Version (darauf baut ADO auf, ich hab noch V2.5 drauf). Trotzdem sollte doch jeder Fehler gefangen werden können, oder?

    Gibt es eigentlich noch mehr Fälle, in denen eine Exeption nicht gefangen wird, sondern "durchrasselt"?



  • Hallo

    Wenn eine Exception innerhalb eines try/catch-Blockes geworfen wird, wird sie auch gefangen. Das heißt nur Fehler die keine Exception verursachen "rasseln durch". Das sind zum Beispeil Speicherfehler. Das säre dann so aus wie von dir beschrieben mit dem kompletten Programmabruch wegen Speicherschutzverletzung. Dazu kommt es weil AsString auf eine ungültigen Feldinstanz zugreifen soll. Allerdings sollte die Methode FieldByName schon vorher die Exception werfen, weil das Feld ja nicht vorhanden ist. Es gibt jedenfalls keinen plausiblen Grund warum bei der einen Variante eine geworfen wird und bei der andern nicht.

    bis bald
    akari


Log in to reply