Probleme beim Debuggen von Stringoperationen

Sancho

Level-1
Beiträge
30
Reaktionspunkte
1
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

ich komme gerade beim debuggen einer Funktion nicht weiter weil meine Wago 750-880 gleich die Kommunikation beim Starten des Programms beendet. Den Fehler konnte ich jedoch schon auf eine von mir geschriebene Funktion eingrenzen.
Ich möchte Daten in eine MySQL Datenbank schreiben. Das funktioniert vom Prinzip auch. Jetzt hab ich aber einen großen Datensatz mit über 20 Werten, dadurch wird der String den ich zusammenbasteln muss sehr lang. Stringoperationen gehen ja nur bis 255 Zeichen.
Der Baustein MySql_Execute aus der WagoLibMySql_03.lib ja ein Array of String. Vorher hatte ich eine Funktion am laufen, die das SQL Kommando zu einem String zusammengesetzt hat. Anschließend habe ich mit LEFT und MID den String auf das Array of String verteilt und versendet. Hat auch einwandfrei funktioniert bis mein Kommando String zu lange wurde.
Meine Idee war dann, meiner Funktion als Rückgabewert direkt das Array of String zu übergeben. In der Funktion prüfe ich dann während der Zusammenstellung des Kommandos immer ob die Stringlänge größer 100 ist, wenn ja kopiere ich die ersten 100 Zeichen auf die erste Position des Arrays und lösche 100 Positionen in meinem temporären Kommandostring usw...

Wenn ich jetzt die Funktion einspiele geht die SPS sofort auf Störung und es wird ausgeloggt. Ich kann keinen Fehler im Code erkennen. Fällt jemand von euch was auf?
Gibt es überhaupt eine Möglichkeit sowas zu debuggen? Ich sehe keine Diagnosemöglichkeit?

Code:
FUNCTION SQL_Insert :ARRAY[0..10] OF  STRING(100)
VAR_INPUT
    sTable         :STRING;
    asColumns    :ARRAY[0..30] OF STRING;
    asValues       :ARRAY[0..30] OF STRING;
    iAmount        :INT;
END_VAR
VAR
    sTemp        :STRING(500) := 'INSERT INTO ';
    i    : INT;
    j    :INT := 0;
END_VAR

j:= 0;

(*Tabellenname einfügen *)
sTemp := CONCAT(sTemp, sTable);
sTemp := CONCAT(sTemp, ' (');


(*Spaltennamen einfügen *)
FOR i := 0 TO iAmount DO
    sTemp := CONCAT(sTemp, asColumns[i]);
    (* Wenn Stringlänge größer gleich 100 umkopieren *)
    IF LEN(sTemp) >= 100 THEN;
        SQL_Insert[j] := LEFT(sTemp,100);
        DELETE(sTemp,100,0);
        j := j +1;
    END_IF;


    (* Solange noch nicht letzter Wert erreicht Trennzeichen ergänzen *)
    IF i < iAmount THEN
        sTemp := CONCAT(sTemp, ', ');
    END_IF;
END_FOR;


sTemp := CONCAT(sTemp, ') VALUES (');


(* Wenn Stringlänge größer gleich 100 umkopieren *)
IF LEN(sTemp) >= 100 THEN;
    SQL_Insert[j] := LEFT(sTemp,100);
    DELETE(sTemp,100,0);
    j := j +1;
END_IF;


(* Werte einfügen *)
FOR i := 0 TO iAmount DO
    sTemp := CONCAT(sTemp, asValues[i]);


    (* Wenn Stringlänge größer gleich 100 umkopieren *)
    IF LEN(sTemp) >= 100 THEN;
        SQL_Insert[j] := LEFT(sTemp,100);
        DELETE(sTemp,100,0);
        j := j +1;
    END_IF;


    IF i < iAmount THEN
        sTemp := CONCAT(sTemp, ', ');
    END_IF;
END_FOR;


(* Kommando fertig stellen *)
sTemp := CONCAT(sTemp, ')' );


    (* Wenn Stringlänge größer gleich 100 umkopieren *)
IF LEN(sTemp) >= 100 THEN;
    SQL_Insert[j] := LEFT(sTemp,100);
    DELETE(sTemp,100,0);
    j := j +1;
ELSE
    SQL_Insert[j] := sTemp;
END_IF;
 
Zuletzt bearbeitet:
Vielleicht stört er sich daran, dass Du in der vorletzten Anweisung dem Rückgabewert der 100 Zeichen enthalten kann eine Variable übergibst die 500 Zeichen enthalten kann. Du fragst zwar vorher ab, ob in sTemp mehr als 100 Zeichen sind, aber ich weiß nicht wie Codesys intern vorgeht wenn Du anstatt der Stringfunktionen einfach den Zuweisungsoperator nimmst. Vielleicht nutzt Codesys intern ein Memcopy über die Länge der Quellvariable und dann muss es krachen.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Oliver,

das ist kein Problem. Die Strings sind maximal 10 Zeichen lang. Hat vorher auch schon funktioniert. Ursprünglich hatte die Funktion einen String(500) als Rückgabewert. Dann hab ich umgebaut auf Array of String und die Schleifen eingefügt die die Stringlänge auf 100 begrenzen und umkopieren. Seitdem gehts gar nicht mehr.
 
Oh ja, das wirds sein. Habs auch grad in einer Beschreibung gelesen, dass 1 das erste Zeichen ist. Konnte es noch nicht probieren aber sieht gut aus.

Danke Harald! :)
 
Weil Du mit Deiner Function ein String-Array zurückgibst: müssen die nicht benötigten Array-Elemente initialisiert werden?
(also am Ende von [j+1] bis [10] oder am Anfang von [1] bis [10])
Code:
FOR i := 1 TO 10 DO
    SQL_Insert[i] := '';
END_FOR;

Kann Dein Kommando länger als 1100 Zeichen werden? Du erhöhst j immer ungeprüft - wird j vielleicht größer als 10?

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
So, ich habe jetzt mal die Zählvariable begrenzt auf 8. Normal sollte das nie erreicht werden. Die Steuerung geht nicht mehr in Stop. Das Ergebnis in meinem String Array wundert mich jetzt aber. Es sieht aus, als ob die DELETE Funktion nicht funktioniert?

astr.JPG
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Das mit der Rückgabe "sTemp := DELETE(sTemp,100,1);" habt Ihr nun schon gefunden.

Mir ist außerdem noch ein Fehler in der Programmlogik bei der Rückgabe des letzten Teilstrings aufgefallen:
Code:
(* Kommando fertig stellen *)
sTemp := CONCAT(sTemp, ')' );

(* Wenn Stringlänge größer gleich 100 umkopieren *)
IF LEN(sTemp) >= 100 THEN;
    SQL_Insert[j] := LEFT(sTemp,100);
    sTemp := DELETE(sTemp,100,1);
    j := j + 1;
[COLOR="#FF0000"]ELSE                         >---+  kein ELSE!
    SQL_Insert[j] := sTemp;  >---+} das gehört nicht hierher[/COLOR]
END_IF;                          [COLOR="#FF0000"]|[/COLOR]
                                 [COLOR="#FF0000"]|[/COLOR]
[COLOR="#0000FF"]SQL_Insert[j] := sTemp;[/COLOR]   [COLOR="#FF0000"]<------+  sondern hierher[/COLOR]

Harald
 
... Stringoperationen gehen ja nur bis 255 Zeichen. ...
Ja, ja, diese blöden Beschränkungen. Früher war die max. Länge von 255 (manchmal auch 254) Bytes normal.
Das 1. Byte gibt nämlich die Länge des Strings an und in einem Byte lassen sich nunmal nur die Zahlen 0 bis 255 (oder -128 bis 127) codieren.
D.h. es sind eigentlich nicht die StringOperationen, sondern die StringOperanden, die den Engpass bilden.
Das gilt dann natürlich auch für temporäre Strings, die man aus Strings mit Längen von jeweils weniger als 255 zusammen bastelt - was Du ja auch nicht tust.
Aber vermutlich unterstellst Du, dass Deine SQL-Funktion genau das kann, ohne auf die Schnauze zu fallen.
Ich unterstelle, Du solltest Deine Aufträge an die DatenBank in LOGISCHE Scheibchen unterteilen können, was Du aber mit Sicherheit nicht tust, wenn Du Auftrage unabhängig vom Inhalt in Scheibchen von je 100 Bytes shredderst. Mir fällt - insbesondere, weil ich Deine SQL-Schnittstelle nicht kenne - leider kein sinnvolles Beispiel ein, aber vielleicht verstehst Du trotzdem, was ich meine?
Ich wollte noch auf zwei weitere Punkte hinweisen, finde hier aber momentan Deinen QuellText nicht mehr. Stattdessen sehe ich aber die rege Beteiligung der anderen, also erübrigt es sich wahrscheinlich, dass ich den Faden wieder finde. Da war eine Funktion, die im 3. Operanden eine 0 hatte - könnte ein Fehler sein ...

Hinzugefügt: Ja, genau, der Delete. Wusste nicht die Bedeutung des 3. Operanden, hatte sie aber richtig vermutet - wie ich jetzt weiss.
 
Zuletzt bearbeitet:
Hallo Heinileini,
Das 1. Byte gibt nämlich die Länge des Strings an und in einem Byte lassen sich nunmal nur die Zahlen 0 bis 255 (oder -128 bis 127) codieren.
falscher Film, im Codesys Universum gibt es das nicht. Da wird die Länge nicht mit abgelegt, das Ende vom String wird durch \0 gekennzeichnet.

Von irgendwas mit Internetzugang gesendet
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Mir ist außerdem noch ein Fehler in der Programmlogik bei der Rückgabe des letzten Teilstrings aufgefallen:

Harald

Das war mich auch schon aufgefallen und habe ich schon behoben.

@ Heinileine: Bei der Verwendung der SQL Funktion hab ich mich genau an das Beispiel von Wago gehalten. Der Baustein erwartet ja auch als Eingang ein Array of String. Im Wago Beispiel waren die Strings nicht mal vollständig befüllt sondern nur Teilweise. Anscheinend hat die Funktion kein Problem damit, ich konnte auch noch keins feststellen.
 
D.h. die Beschränkung auf eine Länge von 255 Byte wurde ziemlich willkürlich beibehalten.
Wenn man doch im Sinne der AufwärtsKompatibilität immer so konsequent wäre, wie in diesem Fall im Sinne der AbwärtsKompatibilität.
Sorry, wenn ich auf die falsche Fährte gelockt habe.
 
Zurück
Oben