DbAppend()

Zugriff, Engines, Konvertierung. Von ADS über DBF bis zu SQL.

Moderator: Moderatoren

Antworten
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14641
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 87 Mal
Kontaktdaten:

DbAppend()

Beitrag von Jan »

Moin,

ab und an, recht selten, passiert etwas merkwürdiges:

Code: Alles auswählen

IF cAlias->(DbAppend())
   cAlias->Feldname := wert
Das ergibt einen Laufzeitfehler:
oError:args :
-> VALTYPE: N VALUE:1289
oError:canDefault : .F.
oError:canRetry : .F.
oError:canSubstitute: .T.
oError:cargo : NIL
oError:description : Datei oder Datensatz mu▀ f³r Operation gesperrt sein
oError:filename :
oError:genCode : 76
oError:operation : <FELDNAME>:=<1289>
oError:osCode : 0
oError:severity : 2
oError:subCode : 8043
oError:subSystem : BASE
oError:thread : 1
oError:tries : 0
Wie gesagt, das klappt fast immer. Aber manchmal hat der anscheinend beim appenden kein Locking gemacht. Obwohl ich dachte, das ich mit der IF-Abfrage ein sauberes appenden inkl. Locking ja abfange.

Hat jemand eine Idee, was da passiert?

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
ramses
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2513
Registriert: Mi, 28. Jul 2010 17:16
Hat sich bedankt: 12 Mal
Danksagung erhalten: 77 Mal

Re: DbAppend()

Beitrag von ramses »

Hallo Jan

dbAppend() gibt immer NIL zurück.
Ob ein neuer Satz angefügt werden konnte musst du immer mit neterr() prüfen!
Sonst geht dein zugriff auf den aktuellen bestehenden (nicht gelockten) Datensatz und führt zum RunTime Fehler.
Valar Morghulis

Gruss Carlo
Benutzeravatar
Koverhage
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2470
Registriert: Fr, 23. Dez 2005 8:00
Wohnort: Aalen
Hat sich bedankt: 102 Mal
Danksagung erhalten: 3 Mal
Kontaktdaten:

Re: DbAppend()

Beitrag von Koverhage »

Jan,
Ab und an haben unsere Kunden diesen Fehler auch.
Das Problem ist die Index (CDX) Datei.
Gruß
Klaus
ramses
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2513
Registriert: Mi, 28. Jul 2010 17:16
Hat sich bedankt: 12 Mal
Danksagung erhalten: 77 Mal

Re: DbAppend()

Beitrag von ramses »

Jan's Code ist eigentlich falsch. Es müsste

Code: Alles auswählen

cAlias->(DbAppend())
IF !neterr()
   cAlias->Feldname := wert
sein.
Valar Morghulis

Gruss Carlo
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9345
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 100 Mal
Danksagung erhalten: 359 Mal
Kontaktdaten:

Re: DbAppend()

Beitrag von Tom »

Nee, Klaus, Jan hat das Problem, das Carlo skizziert hat. "IF NIL" läuft manchmal durch, und DbAppend() retourniert eben NIL. Wenn es fehlgeschlagen ist, bekommt Jan anschließend den Fehler, weil eben kein Locking vorliegt, da ja das DbAppend() fehlschlug.
Herzlich,
Tom
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14641
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 87 Mal
Kontaktdaten:

Re: DbAppend()

Beitrag von Jan »

Hallo,

Danke für die vielen Antworten. Die mir zeigen, das mein Codebeispiel leider, nun ja, unvollständig ist. Ich mach nämlich an dieser Stelle kein DbAppend(). Sondern rufe eine eigene Funktion auf, die so aussieht:

Code: Alles auswählen

UNCTION MyDbAppend

LOCAL lReturn := .F.
LOCAL bOldError := NIL
LOCAL nRetry := 0
LOCAL lExit := .F.
LOCAL e := NIL
LOCAL cStack := ""

UnUsed(e)

bOldError := ErrorBlock( {|e| MyDbSeekErrorblock(e, @lExit)})                                      // Original-Fehler-Codeblock sichern, eigenen installieren

DO WHILE .T.                                                                                       // So lange laufen lassen, bis ein kontrolliertes "Exit" kommt
   BEGIN SEQUENCE                                                                                  // Eigene Laufzeitfehler-Behandlung starten
   DbAppend()                                                                                      // Den Lock versuchen, Ergebnis speichern
   nRetry ++                                                                                       // Gleich hochzählen, auch wenn gültiiger versuch. Später aufwändiger

    RECOVER USING bOldError                                                                        // Was tun bei einem Laufzeitfehler
     lReturn := NIL
     nRetry ++
   END SEQUENCE
   ErrorBlock(bOldError)                                                                           // Original-Fehler-Codeblock wiederherstellen

   IF ValType(lReturn) # "U"                                                                       // Wenn Sperre erfolgreich ...
      lReturn := .T.
      Exit                                                                                         // ... raus aus der Schleife

    ELSEIF nRetry > 10                                                                             // Nach 10 vergeblichen Sperrversuchen
      cStack := "Funktion " + ProcName(1) + ;                                                      // Um die Codezeile und den Datensatz zu identifizieren
                " Zeile " + Var2Char(ProcLine(1)) + crlf + ;
                "Datenbank " + Alias() + ;
                " RecNo " + Var2Char(RecNo())

      IF ConfirmBox(MEMVAR->oXbp, ;                                                                // Weiteres Vorgehen abfragen
                    "Ein Datensatz konnte nicht angehängt werden." + crlf + crlf +  ;
                    cStack + crlf + crlf + ;
                    "Noch einmal versuchen?", ;
                    "Neuer datensatz", ;
                    XBPMB_YESNO, ;
                    XBPMB_QUESTION, ;
                    XBPMB_DEFBUTTON1) == XBPMB_RET_NO
         IF hatRechte(MEMVAR->aAktMitarbeiter, "Vertrieb") >= 7                                    // Nur Admins dürfen unkontrolliert  abbrechen
            EXIT                                                                                   // Wenn "Noch einmal versuchen" mit "Nein" beantwortet wurde -> unkontrolliertes Ende!

          ELSE
            MsgBox("Sie haben keine ausreichenden Rechte, ein unkontrolliertes Beenden auszuwählen." + crlf + crlf + ;
                   "Bitte einen Admin informieren", ;
                   "Datensatzsperre fehlgeschlagen")
         ENDIF
      ENDIF
      nRetry := 0                                                                                  // Zähler zurück setzeen
   ENDIF

   Sleep(10)                                                                                       // 10/100 Sekunden warten
ENDDO

RETURN lReturn
Damit bekomme ich dann eben kein NIL zurück. Sorry, das ich das erst verschwiegen hatte. Für mich war meine Funktion schon so selbstverständlich geworden das ich nicht mehr an den Unterschied in der Rückgabe

De Funktion hatte ich mal vor ein paar Jahren bei meinem Kunden geschrieben, als dort nach dem Einbau neuer schneller Server kaum noch eine Db-Funktion sauber lief. Ich weiß nicht ob das noch DBFNTX oder schon FOXCDX war. Auf jeden Fall gab es plötzlich stapelweise Laufzeitfehler und Datenmurks. Nachdem ich dann die relevanten Funktionen (DbSkip, DbAppend, DbRLock, DbRUnLock, DbClose, DbSeek) auf solch ein Muster umgeschrieben hab, lief alles wieder sauber und stabil.

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15688
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: DbAppend()

Beitrag von brandelh »

dbAppend() und Append Blank, geben keine Laufzeitfehler, sondern setzen nur NETERR(), ähnlich dem USE der fehlschlägt, weil eben ein anderer schon den Satz hat.
Soweit ich deine Funktion überflogen habe nutzt du das Errorsystem um auf eventuelle Laufzeitfehler zu reagieren, aber hier gibt es keine !
Gruß
Hubert
Benutzeravatar
Werner_Bayern
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2120
Registriert: Sa, 30. Jan 2010 22:58
Wohnort: Niederbayern
Hat sich bedankt: 29 Mal
Danksagung erhalten: 70 Mal

Re: DbAppend()

Beitrag von Werner_Bayern »

Code: Alles auswählen

    RECOVER USING bOldError                                                                        // Was tun bei einem Laufzeitfehler
     lReturn := NIL
     nRetry ++
   END SEQUENCE
   ErrorBlock(bOldError)                                                                           // Original-Fehler-Codeblock wiederherstellen

   IF ValType(lReturn) # "U"                                                                       // Wenn Sperre erfolgreich ...
      lReturn := .T.
      Exit         
Macht das Sinn? Im Fehlerfall belegst Du lReturn doch mit NIL und danach prüfst Du auf ValType?
es grüßt

Werner

<when the music is over, turn off the lights!>
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9345
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 100 Mal
Danksagung erhalten: 359 Mal
Kontaktdaten:

Re: DbAppend()

Beitrag von Tom »

Hubert hat recht.
Herzlich,
Tom
ramses
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2513
Registriert: Mi, 28. Jul 2010 17:16
Hat sich bedankt: 12 Mal
Danksagung erhalten: 77 Mal

Re: DbAppend()

Beitrag von ramses »

Es fehlt noch immer die Abfrage von netErr() als einzig mögliche Art zu erkennen ob dbAppend() erfolgreich war und ggf. ein neuer Versuch
Valar Morghulis

Gruss Carlo
Antworten