MsSql auslesen bei Type 'DBTYPE_BYTES'



  • Hallo Community

    Das auslesen von Daten aus meiner Datenbank funktioniert soweit alles einwandfrei. Dennoch habe ich bei manchen Feldtypen noch so meine Probleme.
    Wenn ich versuche z.B. den Feldtype 'IMAGE' stürzt das Programm ab. Bzw. ich erhalte Speicherschutzverletzungen weil über meine Buffer hinausgeschrieben wurde.

    Ich lege in meinem Programm meine Bindings fest nach dem Muster von:
    http://msdn.microsoft.com/en-us/library/ms721163(v=VS.85).aspx

    for (ULONG j=0; j < r->colsMaxAnzahl; j++)
        {
    	   r->pBindings[j].iOrdinal		= r->pDBColumnInfo[j].iOrdinal;
    	   r->pBindings[j].dwPart		= DBPART_VALUE|DBPART_LENGTH|DBPART_STATUS;
    	   r->pBindings[j].obStatus		= cbColOffset;
           r->pBindings[j].obLength		= cbColOffset + sizeof(DBSTATUS);
           r->pBindings[j].obValue		= cbColOffset + sizeof(DBSTATUS) + sizeof(ULONG);
    	   r->pBindings[j].dwMemOwner	= DBMEMOWNER_CLIENTOWNED;
    	   r->pBindings[j].eParamIO		= DBPARAMIO_NOTPARAM;
    	   r->pBindings[j].bPrecision	= r->pDBColumnInfo[j].bPrecision;
           r->pBindings[j].bScale		= r->pDBColumnInfo[j].bScale;
    	   r->pBindings[j].wType		= DBTYPE_STR;
    	   r->pBindings[j].cbMaxLen		= 0;
    	   switch( r->pDBColumnInfo[j].wType )
          {
             case DBTYPE_NULL:
             case DBTYPE_EMPTY:
             case DBTYPE_I1:
             case DBTYPE_I2:
             case DBTYPE_I4:
             case DBTYPE_UI1:
             case DBTYPE_UI2:
             case DBTYPE_UI4:
             case DBTYPE_R4:
             case DBTYPE_BOOL:
             case DBTYPE_I8:
             case DBTYPE_UI8:
             case DBTYPE_R8:
             case DBTYPE_CY:
             case DBTYPE_ERROR:
    			 // Da wir die Rückgabe immer als String nehmen, reichen 25 Stellen aus um all diese Typen zu convertieren plus das End-Zeichen
                r->pBindings[j].cbMaxLen = (25 + 1) * sizeof(WCHAR);
                break;
    
             case DBTYPE_DECIMAL:
             case DBTYPE_NUMERIC:
             case DBTYPE_DATE:
             case DBTYPE_DBDATE:
             case DBTYPE_DBTIMESTAMP:
             case DBTYPE_GUID:
    			 // Wie oben, hier reichen 50 Zeichen plus das End-Zeichen
                r->pBindings[j].cbMaxLen = (50 + 1) * sizeof(WCHAR);
                break;
    
             case DBTYPE_BYTES:
    			 // Bei Bytes, die länge der Zeile mal 2 plus das End-Zeichen
                r->pBindings[j].cbMaxLen = (r->pDBColumnInfo[j].ulColumnSize * 2 + 1) * sizeof(WCHAR);
                break;
    
             case DBTYPE_STR:
             case DBTYPE_WSTR:
             case DBTYPE_BSTR:
    			 // Wenn strings gegeben sind, dann die Länge der Zeile plus das End-Zeichen
                r->pBindings[j].cbMaxLen = (r->pDBColumnInfo[j].ulColumnSize + 1) * sizeof(WCHAR);
                break;
    
             default:
    			 // Wenn kein Type festegestellt ist, max. Anzahl verwenden
                r->pBindings[j].cbMaxLen = 255; // = MAX_TYPE (festlegen)
                break;
    	   };
    	   cbColOffset = r->pBindings[j].cbMaxLen + r->pBindings[j].obValue;
    	} // ENDE - FOR-Schleife
    

    Die Stelle in meinem Code an der ich Versuche meine Daten aus dem Rowset zu erhalten

    // ....
                    if (numRows > 0)
    		{
    			// ColumnOffsetWert auslesen (max. Länge der Zeile) -> Der Max. Wert steht in der letzten Vorhanden SpaltenInformation
    			ULONG offSetSize = itLineGet->second->pBindings[itLineGet->second->colsMaxAnzahl-1].cbMaxLen + itLineGet->second->pBindings[itLineGet->second->colsMaxAnzahl-1].obValue;
    
    			char* puffer = new char[offSetSize];
    			for (ULONG j=0; j<numRows; j++)
    			{
    				std::fill(puffer, puffer+offSetSize, 0); // macht das selbe wie 'memset(buf, 0, NMP_NETWORK_MSG_SIZE +1);' -> but savely
    
    				hr = itLineGet->second->pIRowset->GetData(hRows[j], itLineGet->second->hAccessor, puffer);
    				if (!FAILED(hr))
    				{
    					unsigned int sp = 0;
    					while (sp != itLineGet->second->colsMaxAnzahl)
    					{
    						nmpCDataset data;
    						data.ValueSet(wxString::FromAscii(&puffer[itLineGet->second->pBindings[sp].obValue]));
    						r[itLineGet->second->pDBColumnInfo[sp].pwszName] = data;
    						sp++;
    					}
    					itLineGet->second->resultCache.push_back(r);
    				}
    			}
    			delete puffer;
    		}
    // ....
    

    Wenn er beim 'Imagefeld' ankommt wandert er in den Bereich 'DBTYPE_BYTES' der Switch-Anweisung wie es sein soll. Anschließend kommt allerdings das Problem egal ob mein Image-Feld in MsSql leer ist oder ich Werte mit einer bestimmten Länge darin stehen habe (im aktuellen Fall immer so ca. 50000 Zeichen) die Länge der Variable 'r->pDBColumnInfo[j].ulColumnSize' ist immer '2.147.483.647'. Das gibt natürlich das Problem wenn er diese mal 2 nimmt eins dazu zählt und mal dem sizeof (in dem Fall 2) nimmt irgendwo der Wert '8.589.934.590' rauskommen müsste. Kann er aber nicht weil 'r->pBindings[j].cbMaxLen' als 'ULONG' (unsingned long) deklariert ist und somit maximal den Wert '4.294.967.295' annehmen kamm. Richtiger Weise kommt dabei ein falscher Wert herraus.

    Nun stellt sich für mich die Frage wie ich es schaffe in meinen Binding's in der 'cbMaxLen' den richtigen Wert hineinzubekommen. Damit dann auch mein 'cbColOffset' die richte Größe hat und ich den benötigten Speicher richtig reservieren kann..!! Ist das in der Dokumentation auf der MSDN irgendwie falsch beschrieben?? Oder kann ich diese Daten nur abholen wenn ich dies über ein Streaming mache ??

    Mfg Ollow


  • Mod

    Löst primäres Dein Problem nicht, aber zumindest musst Du nicht mit Faktor 2 rechnen. Hier geht es um BYTES!

    Könntest Du einen OLEDB für diese Spalte Stream anbieten. Dann ist MYSQL für die Allokation verantwortlich.


Anmelden zum Antworten