none
SQLPutData -> Fehler 22001 (String data right truncation) RRS feed

  • Frage

  • Guten Tag Zusammen,

    ich implementiere in einem ANSI C Programm Lesen und Schreiben der BLOB-Felder von unbekannter Größe (Tabellen-Feld: VARBINARY(MAX)). Die Idee ist - lesen und schreiben in Segmenten und im Programm Speicher nach dem Bedarf allozieren.

    Habe die Benutzeranleitung zu den Funktionen SQLBindParameter, SQLParamData, SQLPutData (fürs Schreiben) und SQLGetData (fürs Lesen) mehr oder weniger verstanden. Als Erstes habe ich versucht, ein 40K array mit Ziffern 0-9 zu füllen, in 1К-Segmenten mit SQLPutData zu schreiben, dann Lesen und wieder schreiben - alles funktionierte. Als 2. Schritt habe ich die realen Daten (gespeichertes Bild) gelesen. Größe mit DATALENGTH() geprüft -7233. Beim Lesen - kein Problem. Beim Schreiben auch - solange ich die ersten 7 Segmente schreibe. Aber beim Rest von 233 Bytes kommt ein Fehler 22001 (String data right truncation). Durch Lesen der Fehlerbeschreibung in Microsoft-Doku wurde ich nicht  wirklich schlau. Rest vom array nach 7233 Bytes ist mit 0 (binär) gefüllt - warum meint der ODBC-Driver, dass "more data was send for a long parameter... than was specified in the length buffer"??? Ich habe schon alles mögliche versucht - komme aber nicht weiter. Hat jemand eine Idee?
    Freitag, 18. Dezember 2020 11:45

Antworten

Alle Antworten

  • Ich weiß gar nicht, warum du das segmentierst.
    Du kannst einen Puffer und die Länge des Inhaltes genau angeben und an den Treiber übergeben, eine Segmentierung ist nicht erforderlich.

    Auch per SQLBindParameter übergibst du einen Zeiger für die Länge, sodass die Länge für jeden Aufruf genau angegeben werden kann. Der Pointer zu den Daten ist beim Bind allerdings statisch, so dass du da bereits die max. Länge anlegen musst.

    Nachtrag: Ggf. hast du noch den falschen SQL-Typ verwendet:
    https://docs.microsoft.com/de-de/sql/odbc/reference/syntax/sqlputdata-function?view=sql-server-ver15

    Siehe: SQL_LONGVARBINARY

    Aber trotzdem mal die Frage:
    Warum machst du das Ganze nicht in C#? Da ist das alles sehr viel einfacher.


    Freitag, 18. Dezember 2020 12:59
  • Ich weiß gar nicht, warum du das segmentierst.
    Du kannst einen Puffer und die Länge des Inhaltes genau angeben und an den Treiber übergeben, eine Segmentierung ist nicht erforderlich.

    Auch per SQLBindParameter übergibst du einen Zeiger für die Länge, sodass die Länge für jeden Aufruf genau angegeben werden kann. Der Pointer zu den Daten ist beim Bind allerdings statisch, so dass du da bereits die max. Länge anlegen musst.

    Siehe: SQL_LONGVARBINARY

    Aber trotzdem mal die Frage:
    Warum machst du das Ganze nicht in C#? Da ist das alles sehr viel einfacher.


    Danke für die schnelle Antwort! Implementierung in C# kommt leider nicht in Frage, weil Framework in C geschrieben ist - ich darf meine Anwendung nur nach diesen Spielregeln implementieren. Warum ich segmentiere - das ist eine gute Frage. Irgendwie habe ich bei der Suche nach einer effizienten Lösung für BLOB-Felder über ein Beispiel mit Segmentierung gestolpert. Aber wenn ich mir jetzt überlege - du hast Recht, es muss nicht unbedingt sein. Ich werde mal ohne ausprobieren!
    Freitag, 18. Dezember 2020 13:38
  • Hier noch mal einen Link, wie korrekt segmentiert werden muss:
    https://docs.actian.com/ingres/10.2/index.html#page/Connectivity/SQLPutData()--Send_Data_in_Segments.htm

    Was bei einer 32-Bit-Anwendung dann Sinn macht, wenn man mehr Daten senden muss, als mein Prozessspeicher (ca. 1,4GB) überhaupt hergibt.
    Bei 64-Bit braucht man das i.d.R. nicht mehr.

    Dienstag, 22. Dezember 2020 21:53