sqlite3_step() gibt sqlite_nomem zurück



  • 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