| Autor |
Beitrag |
jjturbo
      
Beiträge: 516
Win2000 prof., WinXP prof.
D4 Stand., D5 Prof, D7 Prof, D2007 Prof.
|
Verfasst: Fr 09.07.10 09:33
Moin Forum,
ich habe in einem Projekt einen Fehler, den ich vor ein paar Jahren schon einmal in einem anderen Projekt hatte.
Die Funktion die mir den Ärger bereitet (Siehe unten) wird oft aufgerufen, etwa 300 mal pro Stunde.
Ichn habe mir eine Testumgebung geschaffen, in der ich den Fehler in etwa 10 Minuten reproduzieren kann.
Die Fehlermeldung lautet: "Zu viele offene Tabellen vorhanden".
Sie tritt immer auf in einer der Zeilen "MyQuery.Active := True;", ich prüfe noch, ob es evtl. immer in der gleichen Zeile auftritt.
Im Moment wird MyQuery zur Laufzeit erstellt und auch wieder freigegeben. Ich hatte vorher ein Query und eine DataSource verwendet, die auf Form1 verfügbar waren, aber auch mit diesem Fehler.
Hat jemand eine Idee?
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227:
| procedure FA_ZurueckmeldenAnSAP(FA_Rueck:String); var Funct2 :Variant; TableOfConditions :Variant; TableCondRow :Variant; s :String; SQLText :String; Anz :Integer; Erg :Integer; ZeitStempel :String; CounterWert :Integer; DatenAnSapProt :Array of String; Nr :Integer; MyQuery :TQuery; MyDataSource :TDataSource; begin
if FA_Rueck = '' then Exit;
Funct2 := 0; TableOfConditions := 0; TableCondRow := 0;
if not sapConnected then begin Showmessage('Nicht mit SAP verbunden. Abbruch.'); Exit; end;
protokoll(clGreen,'Fertigungsauftrag zurückmelden: ' + FA_Rueck);
MyDataSource := TDataSource.Create(nil);
MyQuery := TQuery.Create(nil); with MyQuery do begin DataSource := MyDataSource; DatabaseName := Dir; end;
s := FA_Rueck; while Length(s) < 12 do s := '0' + s;
Funct2 := Form1.mySAPFunctions.add('Z_RFC_RUECKMELDUNG_SAEGE'); Funct2.exports('Auftrag').value := s;
TableOfConditions := Funct2.tables.item('DATATAB'); TableOfConditions.rows.removeAll;
MyQuery.Active := false; SQLText := 'select * from ' + RueckPufferTabelle + ' WHERE FA=' + FA_Rueck + ' AND NOT status="' + Text_Uebertragung_OK + '" AND Counter_Max_10 < 10'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL; MyQuery.Active := True; Anz := MyQuery.RecordCount;
if Anz = 0 then begin Protokoll(clBlue,'Keine zurückzumeldenden Teile in diesem FA'); MyQuery.Active := false; MyQuery.Free; MyDataSource.Free; Exit; end;
if not NurEinenDatensatzZurueckmelden then begin SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET rueckmeldenaktiv = 1 WHERE FA = ' + FA_Rueck + ' AND NOT status="' + Text_Uebertragung_OK + '" AND Counter_Max_10 < 10'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL; end; if NurEinenDatensatzZurueckmelden then Anz := 1; NurEinenDatensatzZurueckmelden := false;
SetLength(DatenAnSapProt,Anz+4); DatenAnSapProt[0] := 'SAPFunctions.add(Z_RFC_RUECKMELDUNG_SAEGE)'; DatenAnSapProt[1] := 'FA: ' + FA_Rueck; Nr := 2;
SQLText := 'select * from ' + RueckPufferTabelle + ' WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL; MyQuery.Active := True; MyQuery.First; while not MyQuery.Eof do begin TableCondRow := TableOfConditions.rows.add; TableCondRow.Value[1]:= MyQuery.FieldByName('Nacharbeit_J_N').AsString; TableCondRow.Value[2]:= MyQuery.FieldByName('Materialnummer').AsString; TableCondRow.Value[3]:= MyQuery.FieldByName('Aus Lagerort 0100/0200').AsString; TableCondRow.Value[4]:= MyQuery.FieldByName('Länge').AsString; MyQuery.Next; DatenAnSapProt[Nr] := 'DataTab Zeile' + IntToStr(Nr-1) + ': ' + TableCondRow.Value[1] + ';' + TableCondRow.Value[2] + ';' + TableCondRow.Value[3] + ';' + TableCondRow.Value[4]; inc(Nr); end;
Erg := 9999; TRY Erg := Funct2.call; EXCEPT protokoll(clRed,'Fehler in Funct2.call!'); Showmessage('Fehler in Funct2.call!'); END;
DatenAnSapProt[Nr] := 'Ergebnis Funktionsaufruf (32Bit Integer): ' + IntToStr(Erg); inc(Nr); DatenAnSapProt[Nr] := 'Exception-Text des RFC-Bausteins: ' + Funct2.Exception;
if Funct2.Exception = Text_Uebertragung_OK then begin
MyQuery.Active := false;
SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET status = "' + Funct2.Exception + '" WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
ZeitStempel := DateToStr(Now) + ', ' + TimeToStr(Now); SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET zeitpunkt = "' + ZeitStempel + '" WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
Protokoll(clGreen,'Übertragung erfolgreich! Anzahl: ' + IntToStr(Anz)); protokoll(clGreen,'Meldung des RFC-Bausteins: ' + Funct2.Exception); end else begin SQLText := 'SELECT * FROM ' + RueckPufferTabelle + ' WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
MyQuery.Active := True; CounterWert := StrToIntDef(MyQuery.FieldByName('Counter_Max_10').AsString,0)+1; MyQuery.Active := false;
SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET Counter_Max_10 = "' + IntToStr(CounterWert) + '" WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET status = "' + Funct2.Exception + '" WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
protokoll(clRed,'Übertragung nicht erfolgreich! Meldung des RFC-Bausteins: ' + Funct2.Exception); Application.BringToFront; end;
SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET rueckmeldenaktiv = 0 WHERE fa > 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
MyQuery.Active := false; MyQuery.Free; MyDataSource.Free;
end; |
_________________ Windows XP: Für die einen nur ein Betriebssystem - für die anderen der längste Virus der Welt...
|
|
mkinzler
      
Beiträge: 4106
Erhaltene Danke: 13
Delphi 2010 Pro; Delphi.Prism 2011 pro
|
Verfasst: Fr 09.07.10 09:37
Ich würde mir an deiner Stelle überlegen, ob ich weiter mit der BDE arbeiten würde. Du scheinst ja sowieso über ODBC o.ä. auf SAP zuzugreifen.
Das wären dann 2 bremsende Krücken.
_________________ Markus Kinzler.
|
|
jjturbo 
      
Beiträge: 516
Win2000 prof., WinXP prof.
D4 Stand., D5 Prof, D7 Prof, D2007 Prof.
|
Verfasst: Fr 09.07.10 09:46
Könnte ich auf meine Paradox-Tabellen z.B. auch einfach mit Zeos zugreifen?
_________________ Windows XP: Für die einen nur ein Betriebssystem - für die anderen der längste Virus der Welt...
|
|
mkinzler
      
Beiträge: 4106
Erhaltene Danke: 13
Delphi 2010 Pro; Delphi.Prism 2011 pro
|
Verfasst: Fr 09.07.10 09:53
Ach das sind Paradox-Tabellen. Dann würde ich Paradox auch gegen ein zeitgemässes DBMS ersetzen.
Für Paradox und dBase ist die BDE mehr als eine Zugriffskomponente, deshalb geht Zeos nicht
_________________ Markus Kinzler.
|
|
jjturbo 
      
Beiträge: 516
Win2000 prof., WinXP prof.
D4 Stand., D5 Prof, D7 Prof, D2007 Prof.
|
Verfasst: Fr 09.07.10 09:56
Was kannst Du denn als Ersatz empfehlen? Ich hättet gerne nach wie vor lokale Tabellen ohne einen Datenbankserver.
_________________ Windows XP: Für die einen nur ein Betriebssystem - für die anderen der längste Virus der Welt...
|
|
mkinzler
      
Beiträge: 4106
Erhaltene Danke: 13
Delphi 2010 Pro; Delphi.Prism 2011 pro
|
Verfasst: Fr 09.07.10 10:01
Ich persönlich würde dir dann zu FireBird (embedded) raten. Zum Entwickeln mit Server und später dann die embedded (Server)Client Lösung.
_________________ Markus Kinzler.
|
|
jjturbo 
      
Beiträge: 516
Win2000 prof., WinXP prof.
D4 Stand., D5 Prof, D7 Prof, D2007 Prof.
|
Verfasst: Fr 09.07.10 10:05
Bei den neueren Projekten nehmen wir Firebird mit Zeos.
ich denke mal drüber nach.
Aber zurück zu meinem Problem: Wenn die Funktion das 126. Mal aufgerufen wirds, dann passierts.
_________________ Windows XP: Für die einen nur ein Betriebssystem - für die anderen der längste Virus der Welt...
|
|
mkinzler
      
Beiträge: 4106
Erhaltene Danke: 13
Delphi 2010 Pro; Delphi.Prism 2011 pro
|
Verfasst: Fr 09.07.10 10:10
Du scheinst den Query nur im Fehlerfall zu schliessen ( oder ich habe es übersehen)
_________________ Markus Kinzler.
|
|
jjturbo 
      
Beiträge: 516
Win2000 prof., WinXP prof.
D4 Stand., D5 Prof, D7 Prof, D2007 Prof.
|
Verfasst: Fr 09.07.10 10:14
Du meinst mit MyQuery.Active := false?
Habe ich es irgendwo vergessen? Wenn, dann sehe ich die Stelle nicht.
--- Moderiert von Narses: Beiträge zusammengefasst---
Korrektur: Immer im 125. Aufruf, immer an der zweiten Stelle mit MyQuery.Active := True;
_________________ Windows XP: Für die einen nur ein Betriebssystem - für die anderen der längste Virus der Welt...
|
|
mkinzler
      
Beiträge: 4106
Erhaltene Danke: 13
Delphi 2010 Pro; Delphi.Prism 2011 pro
|
Verfasst: Fr 09.07.10 10:25
In Zeile 98 verwendest du das bestehende Queryobjekt ohne das offene DataSet zu schliessen
In Zeile 198 ist ExecuteSQL falsch ( da Abfrage nicht DML)
Statt .Active auf True/False zu setzen würde ich .Open / .Close verwenden
_________________ Markus Kinzler.
|
|
jjturbo 
      
Beiträge: 516
Win2000 prof., WinXP prof.
D4 Stand., D5 Prof, D7 Prof, D2007 Prof.
|
Verfasst: Fr 09.07.10 10:36
Zu Zeile 98: Muß ich vor jedem ExecSQL MyQuery.Active := false setzen?
Worin unterscheiden sich denn .Active True/false und .Open/.Close
_________________ Windows XP: Für die einen nur ein Betriebssystem - für die anderen der längste Virus der Welt...
|
|
mkinzler
      
Beiträge: 4106
Erhaltene Danke: 13
Delphi 2010 Pro; Delphi.Prism 2011 pro
|
Verfasst: Fr 09.07.10 10:43
Jein. Es kommt adrauf an, was vorher gemacht wurde. Nach .ExecSQL ist es imho nicht notwendig, aber nach einer Abfrage, welche ja eine Datenmenge zurückliefert ( auch eine leere Datenmenge ist eine).
.Active := True ruft .Open bzw. .ExecuteSQL auf auf, ich bevorzuge es aber selbst zu machen
_________________ Markus Kinzler.
|
|
jjturbo 
      
Beiträge: 516
Win2000 prof., WinXP prof.
D4 Stand., D5 Prof, D7 Prof, D2007 Prof.
|
Verfasst: Fr 09.07.10 11:03
Habe es mal etwas abgeändert, so läuft es auf jeden schon mal länger, steht jetzt bei etwa 200 Funktionsaufrufen:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220:
| procedure FA_ZurueckmeldenAnSAP(FA_Rueck:String); var Funct2 :Variant; TableOfConditions :Variant; TableCondRow :Variant; s :String; SQLText :String; Anz :Integer; Erg :Integer; ZeitStempel :String; CounterWert :Integer; DatenAnSapProt :Array of String; Nr :Integer; MyQuery :TQuery; MyDataSource :TDataSource; begin
inc(Nummer); form1.caption := IntToStr(nummer); if FA_Rueck = '' then Exit;
Funct2 := 0; TableOfConditions := 0; TableCondRow := 0;
if not sapConnected then begin Showmessage('Nicht mit SAP verbunden. Abbruch.'); Exit; end;
protokoll(clGreen,'Fertigungsauftrag zurückmelden: ' + FA_Rueck);
MyDataSource := TDataSource.Create(nil);
MyQuery := TQuery.Create(nil); with MyQuery do begin DataSource := MyDataSource; DatabaseName := Dir; end;
s := FA_Rueck; while Length(s) < 12 do s := '0' + s;
Funct2 := Form1.mySAPFunctions.add('Z_RFC_RUECKMELDUNG_SAEGE'); Funct2.exports('Auftrag').value := s;
TableOfConditions := Funct2.tables.item('DATATAB'); TableOfConditions.rows.removeAll;
MyQuery.Active := false; SQLText := 'select * from ' + RueckPufferTabelle + ' WHERE FA=' + FA_Rueck + ' AND NOT status="' + Text_Uebertragung_OK + '" AND Counter_Max_10 < 10'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.Active := True; Anz := MyQuery.RecordCount;
if Anz = 0 then begin Protokoll(clBlue,'Keine zurückzumeldenden Teile in diesem FA'); MyQuery.Active := false; MyQuery.Free; MyDataSource.Free; Exit; end;
if not NurEinenDatensatzZurueckmelden then begin SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET rueckmeldenaktiv = 1 WHERE FA = ' + FA_Rueck + ' AND NOT status="' + Text_Uebertragung_OK + '" AND Counter_Max_10 < 10'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL; end; if NurEinenDatensatzZurueckmelden then Anz := 1; NurEinenDatensatzZurueckmelden := false;
SetLength(DatenAnSapProt,Anz+4); DatenAnSapProt[0] := 'SAPFunctions.add(Z_RFC_RUECKMELDUNG_SAEGE)'; DatenAnSapProt[1] := 'FA: ' + FA_Rueck; Nr := 2;
MyQuery.Active := false; SQLText := 'select * from ' + RueckPufferTabelle + ' WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.Active := True; MyQuery.First; while not MyQuery.Eof do begin TableCondRow := TableOfConditions.rows.add; TableCondRow.Value[1]:= MyQuery.FieldByName('Nacharbeit_J_N').AsString; TableCondRow.Value[2]:= MyQuery.FieldByName('Materialnummer').AsString; TableCondRow.Value[3]:= MyQuery.FieldByName('Aus Lagerort 0100/0200').AsString; TableCondRow.Value[4]:= MyQuery.FieldByName('Länge').AsString; MyQuery.Next; DatenAnSapProt[Nr] := 'DataTab Zeile' + IntToStr(Nr-1) + ': ' + TableCondRow.Value[1] + ';' + TableCondRow.Value[2] + ';' + TableCondRow.Value[3] + ';' + TableCondRow.Value[4]; inc(Nr); end; MyQuery.Active := false;
Erg := 9999; TRY Erg := Funct2.call; EXCEPT protokoll(clRed,'Fehler in Funct2.call!'); Showmessage('Fehler in Funct2.call!'); END;
DatenAnSapProt[Nr] := 'Ergebnis Funktionsaufruf (32Bit Integer): ' + IntToStr(Erg); inc(Nr); DatenAnSapProt[Nr] := 'Exception-Text des RFC-Bausteins: ' + Funct2.Exception;
if Funct2.Exception = Text_Uebertragung_OK then begin
MyQuery.Active := false;
SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET status = "' + Funct2.Exception + '" WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
ZeitStempel := DateToStr(Now) + ', ' + TimeToStr(Now); SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET zeitpunkt = "' + ZeitStempel + '" WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
Protokoll(clGreen,'Übertragung erfolgreich! Anzahl: ' + IntToStr(Anz)); protokoll(clGreen,'Meldung des RFC-Bausteins: ' + Funct2.Exception); end else begin SQLText := 'SELECT * FROM ' + RueckPufferTabelle + ' WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.Active := True;
CounterWert := StrToIntDef(MyQuery.FieldByName('Counter_Max_10').AsString,0)+1; MyQuery.Active := false;
SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET Counter_Max_10 = "' + IntToStr(CounterWert) + '" WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET status = "' + Funct2.Exception + '" WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
protokoll(clRed,'Übertragung nicht erfolgreich! Meldung des RFC-Bausteins: ' + Funct2.Exception); Application.BringToFront; end;
SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET rueckmeldenaktiv = 0 WHERE fa > 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
MyQuery.Active := false; MyQuery.Free; MyDataSource.Free;
end; |
_________________ Windows XP: Für die einen nur ein Betriebssystem - für die anderen der längste Virus der Welt...
|
|
mkinzler
      
Beiträge: 4106
Erhaltene Danke: 13
Delphi 2010 Pro; Delphi.Prism 2011 pro
|
Verfasst: Fr 09.07.10 11:10
Nimm mal verschiedene Query-Komponenten. Diese würde ich parametrisieren
_________________ Markus Kinzler.
|
|
jjturbo 
      
Beiträge: 516
Win2000 prof., WinXP prof.
D4 Stand., D5 Prof, D7 Prof, D2007 Prof.
|
Verfasst: Fr 09.07.10 11:20
Wie meinst Du das?
Aber das Problem scheint damit behoben zu sein, die Funktion wurde bis jetzt etwa 700 mal aufgerufen.
Muß man vor jedem ExecSQL Query.Active := false setzen? Bleibt sonst irgendetwas in den Tiefen der BDE geöffnet?
_________________ Windows XP: Für die einen nur ein Betriebssystem - für die anderen der längste Virus der Welt...
|
|
mkinzler
      
Beiträge: 4106
Erhaltene Danke: 13
Delphi 2010 Pro; Delphi.Prism 2011 pro
|
Verfasst: Fr 09.07.10 11:26
Es sieht ja wirklich danach aus
_________________ Markus Kinzler.
|
|