sqlite3_step() gibt sqlite_nomem zurück



  • Hallo zusammen,

    ich bin relativ neu beim Programmieren und erst recht mit Sqlite :p

    Jetzt hab ich folgendes Problem und meine zweitägige Googlesuche hat leider nichts ergeben:

    Ich hab Textdateien eingelesen und in meine Datenbank geschrieben, um später mehrere Tabellen zu joinen und die gewollten Daten wieder in anderem Format in Textdateien zu exportieren. Am Ende sollen 6 Dateien rauskommen.

    Jetzt ist es so, dass es bei 5 auch ohne Probleme klappt, diese Dateien sind aber auch alle sehr klein mit max 35.000 Zeilen, bei der 6. ist dann nach ungefähr 720.000 Zeilen aber schluss. Sqlite3_step() gibt statt sqlite_row sqlite_nomem zurück, meine Schleife bricht ab und in der Textdatei fehlen 1/4 der Daten.

    Ich hab bei Google gelesen, dass man es vielleicht mit pragma cache_size oder page_size lösen kann, aber da bin ich leider auf nichts genaues gestoßen...

    Ich bin für jede Hilfe und jeden Tipp total dankbar!

    Und gern reich ich alle möglichen Codestücke oder was auch immer gebraucht wird noch nach. Leider hab ich echt keinen wirklichen Plan hiervon...



  • Allozierst Du Speicher pro ausgelesenem Datensatz, den Du nicht wieder freigibst?
    Wird Dein Programm im Speicher immer größer während es läuft?

    Ich tippe mal auf ein Speicherleck.



  • Das ist jetzt peinlich, aber ich hab keine Ahnung...

    Also explizit mit new oder so mach ich nichts.Wie seh ich, ob das immer größer wird?



  • Also laut Taskmanager wirds tatsächlich immer größer.

    Es ist so dass ich zwei Zeilen aus der Datenbank hole, noch was daraus berechne und dann direkt in meine Textdatei schreibe bevor ich die nächsten Zeilen lese.

    Explizit hab ich nichts alloziert, aber wie gesagt bin ich noch recht neu und weiß nicht genau ob es dann vielleicht mit dem Schreiben in die Datei zu tun hat oder so...



  • cefi schrieb:

    Also explizit mit new oder so mach ich nichts.

    Das ist doch schon mal was.
    C++ also.

    Ein Memory leak koenntest Du u.U. mit Valgrind oder so - jedenfalls auf Linux finden.

    Du bereitest ein prepared statement vor, "sqlite3_step()st" durch die einzelnen Zeilen und schreibst die einfach in die Datei?



  • Ja C++ in Visual Studio 2010 auf Windows 7

    Also ganz grob ist der Ablauf so:

    sqlite3_open
    f.open
    sqlite3_prepare_v2
    while(rückgabe von sqlite3_step == sqlite_row){
    sqlite3_step
    speichern der datenbankwerte
    berechnungen
    f << alle Daten rein in die Textdatei
    }
    sqlite3_finalize
    sqlite3_close



  • Wir können hier jetzt herumraten bis du zufällig den Fehler findest. Oder du veröffentlichst einfach den Code.



  • Wenn's nicht zuviel ist...:)



  • Ich fürchte der Code ist nicht sehr übersichtlich, aber hier ist der betroffene Abschnitt:

    if(sqlite3_open(dbName, &database) != SQLITE_OK)
    cout << "Fehler beim Oeffnen der Datenbank" << endl;

    qry = "select distinct a.LI_LFD_NR, a.ORT_NR, b.FRT_FID, b.FRT_START, b.FGR_NR, c.frt_hzt_zeit from rec_frt b join lid_verlauf a on a.LI_NR=b.LI_NR and a.STR_LI_VAR = b.STR_LI_VAR left join rec_frt_hzt c on b.FRT_FID = c.FRT_FID and a.ORT_NR = c.ORT_NR;";

    f.open("GTFS/stop_times.txt", ios::out);

    if(! f.is_open())
    cout << "Datei routes konnte nicht geschrieben werden" << endl;

    f << "trip_id,arrival_time,departure_time,stop_id,stop_sequence" << endl;

    sqlite3_prepare_v2(database, ((char*)qry.c_str()), -1, &statement, 0);

    result = sqlite3_step(statement);

    do{

    sequence = sqlite3_column_int(statement, 0);
    ort = (char*)sqlite3_column_text(statement, 1);
    fid = (char*)sqlite3_column_text(statement, 2);
    ankunft = sqlite3_column_int(statement, 3);
    fgr_nr= (char*)sqlite3_column_text(statement, 4);

    if(sqlite3_column_int(statement, 5) != NULL)
    halt = sqlite3_column_int(statement, 5);
    else
    halt = 0;

    if(sequence == 1 && anfang == true){
    abfahrt_sekunden = 0;
    start = uhrzeit(ankunft);
    abfahrt_sekunden = ankunft + halt;
    abfahrt = uhrzeit(abfahrt_sekunden);
    f << fid << "," << start << "," << abfahrt << "," << ort << "," << sequence << endl;
    anfang = false;
    }

    else{
    qry1 = "";
    result = sqlite3_step(statement);

    if(result == SQLITE_ROW){
    fid1=(char*)sqlite3_column_text(statement, 2);

    if(fid1 == fid){
    gruppe = (char*)sqlite3_column_text(statement, 4);
    ziel =(char*)sqlite3_column_text(statement, 1);

    if(sqlite3_column_int(statement, 5) != NULL)
    halt = sqlite3_column_int(statement, 5);
    else
    halt = 0;

    qry1 = "select sel_fzt from sel_fzt_feld where fgr_nr = " + gruppe + " and ort_nr = " + ort + " and sel_ziel = " + ziel + ";";

    sqlite3_prepare_v2(database, ((char*)qry1.c_str()), -1, &statement1, 0);
    result1 = sqlite3_step(statement1);
    fahrzeit = 0;

    if(result1 == SQLITE_ROW)
    if(sqlite3_column_int(statement1, 0) != NULL)
    fahrzeit = sqlite3_column_int(statement1, 0);

    abfahrt_sekunden += fahrzeit;
    zwischenstop = uhrzeit(abfahrt_sekunden);
    abfahrt_sekunden += halt;
    abfahrt = uhrzeit(abfahrt_sekunden);

    f << fid << "," << zwischenstop << "," << abfahrt << "," << ziel << "," << sequence+1 << endl;

    anfang = true;
    }
    }
    }

    }while(result == SQLITE_ROW);

    sqlite3_finalize(statement);
    sqlite3_close(database);

    f.close();



  • Und jetzt noch einmal in C++-Tags, damit man es lesen kann.



  • if(sqlite3_open(dbName, &database) != SQLITE_OK) 
    cout << "Fehler beim Oeffnen der Datenbank" << endl; 
    
    qry = "select distinct a.LI_LFD_NR, a.ORT_NR, b.FRT_FID, b.FRT_START, b.FGR_NR, c.frt_hzt_zeit from rec_frt b join lid_verlauf a on a.LI_NR=b.LI_NR and a.STR_LI_VAR = b.STR_LI_VAR left join rec_frt_hzt c on b.FRT_FID = c.FRT_FID and a.ORT_NR = c.ORT_NR;"; 
    
    f.open("GTFS/stop_times.txt", ios::out); 
    
    if(! f.is_open()) 
        cout << "Datei routes konnte nicht geschrieben werden" << endl; 
    
    f << "trip_id,arrival_time,departure_time,stop_id,stop_sequence" << endl; 
    
    sqlite3_prepare_v2(database, ((char*)qry.c_str()), -1, &statement, 0); 
    
    result = sqlite3_step(statement); 
    
    do{ 
    
        sequence = sqlite3_column_int(statement, 0); 
        ort = (char*)sqlite3_column_text(statement, 1); 
        fid = (char*)sqlite3_column_text(statement, 2); 
        ankunft = sqlite3_column_int(statement, 3); 
        fgr_nr= (char*)sqlite3_column_text(statement, 4); 
    
        if(sqlite3_column_int(statement, 5) != NULL) 
            halt = sqlite3_column_int(statement, 5); 
        else 
            halt = 0; 
    
        if(sequence == 1 && anfang == true){ 
            abfahrt_sekunden = 0; 
    
        start = uhrzeit(ankunft); 
        abfahrt_sekunden = ankunft + halt; 
        abfahrt = uhrzeit(abfahrt_sekunden); 
    
        f << fid << "," << start << "," << abfahrt << "," << ort << "," << sequence << endl; 
    
        anfang = false; 
        } 
    
        else{ 
            qry1 = "";	
            result = sqlite3_step(statement); 
    
            if(result == SQLITE_ROW){ 
                fid1=(char*)sqlite3_column_text(statement, 2); 
    
            if(fid1 == fid){ 
                gruppe = (char*)sqlite3_column_text(statement, 4); 
                ziel =(char*)sqlite3_column_text(statement, 1); 
    
                if(sqlite3_column_int(statement, 5) != NULL) 
                    halt = sqlite3_column_int(statement, 5); 
                else 
                    halt = 0; 
    
                qry1 = "select sel_fzt from sel_fzt_feld where fgr_nr = " + gruppe + " and ort_nr = " + ort + " and sel_ziel = " + ziel + ";"; 
    
                sqlite3_prepare_v2(database, ((char*)qry1.c_str()), -1, &statement1, 0); 
                result1 = sqlite3_step(statement1); 
                fahrzeit = 0; 
    
                if(result1 == SQLITE_ROW) 
                    if(sqlite3_column_int(statement1, 0) != NULL) 
                        fahrzeit = sqlite3_column_int(statement1, 0); 
    
                abfahrt_sekunden += fahrzeit; 
                zwischenstop = uhrzeit(abfahrt_sekunden); 
                abfahrt_sekunden += halt; 
                abfahrt = uhrzeit(abfahrt_sekunden); 
    
                f << fid << "," << zwischenstop << "," << abfahrt << "," << ziel << "," << sequence+1 << endl; 
    
                anfang = true; 
                } 
            } 
        } 
    
    }while(result == SQLITE_ROW); 
    
    sqlite3_finalize(statement); 
    sqlite3_close(database); 
    
    f.close();
    


  • Du finalisierst statement1 nie, oder?

    Ansonsten: Du sollst auch nicht immer das statement neu kompilieren.
    Ohne jetzt den großen Plan zu haben muss das irgendwie so aussehen:

    void f(){
      const char qry1[] =
        "select sel_fzt from sel_fzt_feld where fgr_nr = ?"
        "and ort_nr = ? and sel_ziel = ?";
      // einmal compilen:
      sqlite3_prepare_v2(database, qry1, -1, &statement1, 0);
      //...
      while(bedingung){
        int sqlite3_reset(statemen1);
        int sqlite3_bind_text(statement1, 0, gruppe.c_str(), nullptr);
        int sqlite3_bind_text(statement1, 1, ort.c_str(), nullptr);
        int sqlite3_bind_text(statement1, 2, ziel.c_str(), nullptr);
        sqlite3_step(statement);
        //...
      }
      //...
    }
    


  • Ähm...da war ein klitzekleiner copy&paste Fehler, ausserdem fängt die Nummerierung der Parameter bei 1 an:

    void f(){
      const char qry1[] =
        "select sel_fzt from sel_fzt_feld where fgr_nr = ?"
        "and ort_nr = ? and sel_ziel = ?";
      // einmal compilen:
      sqlite3_prepare_v2(database, qry1, -1, &statement1, 0);
      //...
      while(bedingung){
        sqlite3_reset(statemen1);
        sqlite3_bind_text(statement1, 1, gruppe.c_str(), nullptr);
        sqlite3_bind_text(statement1, 2, ort.c_str(), nullptr);
        sqlite3_bind_text(statement1, 3, ziel.c_str(), nullptr);
        sqlite3_step(statement);
        //...
      }
      //...
    }
    


  • Schon mal vielen Dank! Ich werd es mal ausprobieren 🙂



  • Ich während des WM-Spiels mal ein funktionierendes Beispiel erstellt:

    #include <iostream>
    #include <string>
    #include <vector>
    #include <cassert>
    
    #include <sqlite3.h>
    
    struct person{
      std::string name, vorname;
    };
    
    std::ostream& operator<<(std::ostream& out, const person& p){
      return out << p.name << ", " << p.vorname;
    }
    
    sqlite3* open(){
      sqlite3 *p;
      int stat = sqlite3_open(":memory:", &p);
      assert(stat==SQLITE_OK);
      return p;
    }
    
    void create(sqlite3* db){
      const char sql[] = "CREATE TABLE person(name TEXT, vorname TEXT)";
      sqlite3_stmt *stmt;
      sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
      sqlite3_step(stmt);
      sqlite3_finalize(stmt);
    }
    
    void insert(const std::vector<person>& v, sqlite3* db){
      const char sql[] = "INSERT INTO person(name, vorname) VALUES ( ?, ? )";
      sqlite3_stmt *stmt;
      sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
      for(const auto& p : v){
        sqlite3_bind_text(stmt, 1, p.name.c_str(), -1, nullptr);
        sqlite3_bind_text(stmt, 2, p.vorname.c_str(), -1, nullptr);
        sqlite3_step(stmt);
        sqlite3_reset(stmt);
      }
      sqlite3_finalize(stmt);
    }
    
    std::vector<person> get(const std::string& name, sqlite3* db){
      const char sql[] = "SELECT name, vorname FROM  person WHERE name = ? ORDER BY vorname ASC";
      sqlite3_stmt *stmt;
      sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
      sqlite3_bind_text(stmt, 1, name.c_str(), -1, nullptr);
      std::vector<person> result;
      while(sqlite3_step(stmt)==SQLITE_ROW){
        person p{(char*)sqlite3_column_text(stmt, 0), (char*)sqlite3_column_text(stmt, 1)};
        result.push_back(p);
      }
      sqlite3_finalize(stmt);
      return result;
    }
    
    int main()
    {
      auto db = open();
      create(db);
      {
        std::vector<person> v = {{"Wurble", "Furble"},
    			     {"Meier", "Rolf"},
    			     {"Meier", "Ralf"},
    			     {"Mueller", "Gabi"},
    			     {"Meier", "Rudolf"}};
        insert(v, db);
      }
      auto v = get("Meier", db);
      for(const auto& p : v)
        std::cout << p << '\n';
      sqlite3_close(db);
    }
    

    Die Funktion insert() ist ein Beispiel für bind in einer Schleife mit reset() und allem Pi-Pa-Po.

    sqlite3_bind_*() ist übrigens auch ein Schutz vor SQL-Injections.



  • Wow vielen Dank! Du hast mir echt wahnsinnig weitergeholfen!

    Jetzt kann ich auch alle Daten aus der DB auslesen ohne den Speicherfehler und meine Textdatei ist endlich vollständig 🙂

    Mit dem Beispiel werd ich jetzt noch mal den Rest von meinem Kuddel-Muddel überarbeiten. Das importieren in die DB ist nämlich noch super lahm...

    Vielen lieben Dank noch mal 🙂



  • Zwei Fragen:

    1. Wieso machst du ein SELECT DISTINCT statt einfach nur SELECT ?
    2. Wieso holst du die Daten aus der sel_fzt_feld Tabelle nicht einfach über einen (LEFT) JOIN dazu?
      Mir ist schon klar dass du die nur bei jeder 2. Zeile brauchst. SQLite wird aber schlau genug sein dass keinen wesentlichen Unterschied in der Ausführungszeit der Query macht. Bzw. ich schätze es wird dadurch sogar schneller werden, da du dann nicht mehr für jede 2. Zeile ein eigenes Statement vorbereiten und ausführen musst.


  • Das Select Distinct ist überflüssig geworden. Noch ein altes Überbleibsel. Danke für den Hinweis.

    sel_fzt ist nicht nur abhängig von ort_nr und fgr_nr der aktuellen Zeile sondern auch von sel_ziel, dass erst in der nächsten Zeile steht. Wenn ich nen join mach kann ich sel_ziel aber nicht berücksichtigen oder? Dann mach ich den join doch nur anhand von ort_nr und fgr_nr oder hab ich da nen Denkfehler?



  • Oh Shit.
    Du verwendest "lid_verlauf.ort_nr" einmal als "sel_fzt_feld.ort_nr" und einmal als "sel_fzt_feld.sel_ziel"?
    Hab ich übersehen. Dann geht das natürlich wirklich nicht über nen einfachen JOIN.

    Und ich wüsste auch keine andere einfache Möglichkeit das zu joinen.

    ps: Du hast da übrigens auch noch nen anderen Bug drin:
    Du machst kein ORDER BY , verlässt dich aber trotzdem auf die Reihenfolge der Datensätze.


Anmelden zum Antworten