Datenbankabfrage von SQL-Server
-
Hallo,
wir fragen Daten von einem SQL-Server ab und glauben, dass in der folgenden Funktion ein Fehler ist, welcher eine Access Violation auslöst. Nicht sofort, aber irgendwann nach einigen Stunden, wenn die Funktion laufend aufgerufen wird.
int DB_GetName(char *szQry, int iNr, char *szName) { int iRet = 0; size_t iLen = 0; char szSql[200], *pszName = szName; VARIANT vtVar; if(!gpszDsn) { Disp_Error("Fehler bei Datenbankzugriff DB_Name: Kein DSN!"); return -5; } if(FAILED(::CoInitialize(NULL))) { Disp_Error("Fehler DB_GetName: CoInitialize"); return -1; } _ConnectionPtr pCn(NULL); _RecordsetPtr pRs(NULL); try { if(FAILED(pCn.CreateInstance("ADODB.Connection"))) { ::CoUninitialize(); Disp_Error("Fehler DB_GetName: CreateInstance ADODB.Connection"); return -2; } pCn->Open(gpszDsn, "", "", adConnectUnspecified); if(!pCn->State) { ::CoUninitialize(); Disp_Error("Fehler DB_GetName: Open Connection"); return -4; } if(FAILED(pRs.CreateInstance("ADODB.Recordset"))) { pCn->Close(); ::CoUninitialize(); Disp_Error("Fehler DB_GetName: CreateInstance ADODB.Recordset"); return -3; } pRs->PutRefActiveConnection(pCn); sprintf(szSql, "SELECT Name, %s FROM %s WHERE ID=%d", gszSprache, szQry, iNr); *szName = '\0'; pRs->Open(szSql, vtMissing, adOpenForwardOnly, adLockReadOnly, adCmdText); if(!pRs->EndOfFile) { pRs->MoveFirst(); if(pRs->Fields->Item[_variant_t("Name")]->ActualSize) { // Variant-String auf Text-String kopieren und Länge begrenzen vtVar = pRs->Fields->Item[_variant_t("Name")]->GetValue(); wcstombs(szName, vtVar.bstrVal, TEXT_LEN - 1); } if(pRs->Fields->Item[_variant_t(gszSprache)]->ActualSize) { if(*szName) { iLen = strlen(szName); pszName += iLen++; *pszName++ = ' '; } // Variant-String auf Text-String kopieren und Länge begrenzen vtVar = pRs->Fields->Item[_variant_t(gszSprache)]->GetValue(); wcstombs(pszName, vtVar.bstrVal, TEXT_LEN - 1 - iLen); } iRet = 1; } pRs->Close(); pCn->Close(); if(giLogMode & LOG_DB) { if(!*szName) sprintf(szName, "Nr. %d", iNr); sprintf(gszLogText, "%s: '%s'", szSql, szName); Log_Text(gszLogText); } } catch (_com_error &cErr) { ComErr(cErr, szSql); Disp_Error("Fehler DB_GetName: ComErr"); iRet = -5; if (pRs && pRs->State) pRs->Close(); if (pCn && pCn->State) pCn->Close(); } ::CoUninitialize(); //Log_Text_Tim("DB_GetName"); VariantClear(&vtVar); return iRet; }
Hat jemand einen Tip, was da falsch ist?
-
Ja, dann ist wohl ein Fehler drin wenn es eine Exeption wirft.
Solltest aber selbst Debuggen und sagen in welcher Zeile.
-
Das Problem ist, dass die Exception nicht hier auftritt, sondern irgendwo anders. Ich denke, dass es irgendwo einen Speicherfehler geben muss (Länge eines Strings zu kurz, etc.) Die Exception tritt ja auch nicht sofort auf, fallweise erst nach Stunden, und auch nur dann, wenn der Rechner eher mehr zu tun hat. Ohne ihn aber zu überlasten, es werden einfach nacheinander mehrere Schritte abgearbeitet.
Hat vielleicht jemand ein Beispiel, wo aus einer Datenbank ein String (als wcs)gelesen und in mbc gewandelt wird? Ich meine ein echtes Beispiel aus der Praxis, wo das wirklich evtl seit Jahren funktioniert.
-
Vermutlich wird szName zu klein sein...
Auch rate ich Dir szQry nach "const char*" zu ändern.
Und mit dem "szName" übergebe bitte noch die Puffergröße!Also:
int DB_GetName(const char *szQry, int iNr, char *szName, size_t nNameSize)
Und dann überarbeite die Funktion, damit auf keinen Fall über die Länge von "szName" geschrieben wird...
Alternativ kannst Du noch Produkte wie "Rational Purify" einsetzen, falls Du noch VS2003 verwendet...
Ansonsten kannst Du den Page-heap aktivieren um solche Speicherüberschreiber zu erkennen... das einfachste ist das Application Compatibility Toolkit zu installieren... oder es via gflags aktivieren...