SQLite3 : Ausgabe ist leer



  • Hi !
    Ich versuch gerade, ein MySQL-Plugin für den QtStalker für SQLite3 umzumodeln.
    Jetzt hab ich das soweit, daß ich den Code kompilieren ohne Fehlermeldung und auch laufen lassen kann. Allerdings wird dabei die gewünschte Ausgabedatei angelegt, enthält aber keine Daten.

    Die Fragen, die ich da habe :
    1. liegt das an der Zuweisung der in den Zeilen mit reinterpret ?
    2. Brauch ich die sqlite3_reset Zeile eigentlich ?
    3. Brauch ich statt dessen/zusätzlich eine sqlite3_clear_bindings Zeile ?
    4. sitzt die Sqlite_finalize Zeile an der richtigen Stelle ?

    /**
     * doQuery(sql,db)
     * 
     * Perform sql query and store results in Qtstalker db
     */
    void SQLite3Plugin::doQuery (const QString &sql)
    {
      sqlite3_stmt  *stmt;
    
      if (sqlite3_prepare_v2 (sqlite3db, sql, -1, &stmt, NULL) == SQLITE_OK)
      {
        while (sqlite3_step (stmt) == SQLITE_ROW){
    
          bool with_oi = sqlite3_column_count (stmt) == 7;
    
          QString d = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0 ));
          d = d.remove('-');
          d.append("000000");
    
          Bar bar;
          if (bar.setDate(d))
          {
            QString msg = "Bad date " + d;
            printStatusLogMessage(msg);
            continue;
          }
    
          QString open = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1 ));
          QString high = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2 ));
          QString low = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3 ));
          QString close = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4 ));
          QString volume = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 5 ));
    
          bar.setOpen(open.toDouble());
          bar.setHigh(high.toDouble());
          bar.setLow(low.toDouble());
          bar.setClose(close.toDouble());
          bar.setVolume(volume.toDouble());
    
          if (with_oi) {
            QString oi = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 6));
            bar.setOI(oi.toInt());
          }
    
          qtstalkerdb.setBar(bar);
    
          emit signalWakeup();
        }
    
        sqlite3_reset(stmt);
    
      }
      else 
      {
        QString errstr = "Database query failed.\n";
        errstr.append(sqlite3_errmsg(sqlite3db));
        QMessageBox::critical(0, "Database Query problem", errstr);
        QString errmsg = "Database Query problem: " + errstr;
        printStatusLogMessage(errmsg);
      }
      sqlite3_finalize(stmt);
    
    }
    

    Ich bitte um Nachsicht, da ich noch ziemlich am Anfang mit allem (C++, Qt, SQLite3) stehe..... !



  • Von was für einer Datei sprichst du eigentlich?

    Zum lernen ist QTStalker sicherlich keine gute Wahl - jedenfalls was ich gesehen habe ist ziemlich schrottig - und alt.

    Sei's drum: die ganzen casts und Hilfsvariablen tät ich mir sparen. Teil die Funktion in einzelne Tätigkeiten.
    Wenn Du Dir die sqlite Dokumentation einigermaßen gründlich durchliest, wirst Du feststellen, dass sqlite das parsen von strings in Tabellenspalten auch selbst erledigt.

    Warum benutzt Du nicht die Convenience Funktionen von sqlite?

    Ich habe mal aufgeschrieben, wie ich mir das vorstellen könnte - mit einem Dummy-Bar, dass aber die gleichen Setter besitzt wie das Original. Wie Du siehst schnurrt do_query() ordentlich zusammen - was hoffentlich der Lesbarkeit zugute kommt.
    Und eigentlich ist alles was ich gemacht habe, die Bar Erstellung in eine Funktion auslagern.

    #include <string>
    #include <iostream>
    #include <vector>
    
    #include <sqlite3.h>
    
    // Dummy Bar - nur zur Veranschaulichung
    struct Bar{
      std::string date;
      double open, close;
      double hi, lo;
      double volume;
      int oi;
      void set_date(std::string d) { date=d; }
      void set_high(double v)      { hi=v; }
      void set_low(double v)       { lo=v; }
      void set_open(double v)      { open=v; }
      void set_close(double v)     { close=v; }
      void set_volume(double v)    { volume=v; }
      void set_oi(int v)           { oi=v; }
    };
    
    std::vector<Bar> bars; // global...egal
    
    std::ostream& operator<<(std::ostream& out, const Bar&b){
      return out << b.date << ": "
    	     << "\nopen: " << b.open
    	     << "\nhi/lo: " << b.hi << '/' << b.lo
    	     << "\nclose: " << b.close
    	     << "\nvolume: " << b.volume
      	     << "\noi: " << b.oi;
    }
    
    // "Contructor"
    Bar create_bar(std::string date, double open, double hi, double lo, double close, double volume, int oi){
      Bar b;
      b.set_date(date);
      b.set_open(open);
      b.set_high(hi);
      b.set_low(lo);
      b.set_close(close);
      b.set_volume(volume);
      b.set_oi(oi);
      return b;
    }
    
    Bar create_bar_from_statement(sqlite3_stmt& stmt){
      const std::string date = (const char*)sqlite3_column_text(&stmt, 0);
      const double open=sqlite3_column_double(&stmt, 1);  // sqlite konvertiert text->double
      const double hi=sqlite3_column_double(&stmt, 2);
      const double lo=sqlite3_column_double(&stmt, 3);
      const double close=sqlite3_column_double(&stmt, 4);
      const double volume=sqlite3_column_double(&stmt, 5);
      // das verstehe ich nicht, die Anzahl der Spalten ergibt sich doch aus dem DB-Schema?
      const int oi = sqlite3_column_count(&stmt) == 7 ? sqlite3_column_int(&stmt, 6) : 0;
      return create_bar(date, open, hi, lo, close, volume, oi);
    }
    
    void doQuery(sqlite3& db, const char* sql)
    {
      sqlite3_stmt  *stmt;
    
      int res= sqlite3_prepare_v2 (&db, sql, -1, &stmt, NULL);
      if(res==SQLITE_OK){
        while (sqlite3_step (stmt) == SQLITE_ROW){
          Bar bar = create_bar_from_statement(*stmt);
          bars.push_back(bar);
        }
        sqlite3_reset(stmt);
      }
      else
        std::cerr << "Error!";
      sqlite3_finalize(stmt);
    }
    
    int main(){
      const char* create =
        "CREATE TABLE stocks (date TEXT, open TEXT, high TEXT, low TEXT, close TEXT, volume TEXT, oi TEXT);"
        "INSERT INTO stocks VALUES('01.08.2012', '1.000', '2.000', '3.000', '4.000', '5.000', '0.0');"
        "INSERT INTO stocks VALUES('01.01.1970', '1.000', '2.000', '3.000', '4.000', '5.000', '1.0');";
      sqlite3* db;
      sqlite3_open(":memory:", &db);
      sqlite3_exec(db, create, nullptr, nullptr, nullptr);
      doQuery(*db, "SELECT * FROM stocks;");
      sqlite3_close(db);
      for(const auto& b : bars)
        std::cout << b << '\n';
    }
    


  • Wow -- herzlichen Dank für die Mühe; werd mich gleich dransetzen.

    Furble Wurble schrieb:

    Von was für einer Datei sprichst du eigentlich?

    Die Plugins importieren die Daten nur in QtStalker. Nach dem Import legt QtStalker dann jeweils eine eigene Datei mit den importierten Daten an, die dann als Datenquelle für das Weiterverarbeiten verwendet wird. Is halt so --- ich vermute, das liegt am begrenzten und teuren RAM zu Zeiten der Erstentstehung von QtStalker.

    Zum lernen ist QTStalker sicherlich keine gute Wahl - jedenfalls was ich gesehen habe ist ziemlich schrottig - und alt.

    schrottig -- kann ich nicht beurteilen; die meisten Alternativen, die ich sonst so gesehen habe (geniustrader, merchand_of-venice, filu,..) sind aber entweder unter- oder überdimensioniert bzw. nicht in C/C++ geschrieben.
    Das MySQL-Plugin, das ich als Grundlage verwende, ist aber nicht von den eigentlichen Entwicklern.
    alt -- stimmt schon, allerdings sind die Entwickler wieder dabei, an einer ganz neue Version mit qt4 zu basteln (siehe SVN und Forum bei sourceforge)
    nur zum Lernen ist das wirklich nicht ideal, aber ich will's dann eben auch verwenden. So richtig mit "hello world" will ich auch nicht nochmal starten 😉

    Sei's drum: die ganzen casts und Hilfsvariablen tät ich mir sparen. Teil die Funktion in einzelne Tätigkeiten.
    Wenn Du Dir die sqlite Dokumentation einigermaßen gründlich durchliest, wirst Du feststellen, dass sqlite das parsen von strings in Tabellenspalten auch selbst erledigt.

    (mehrmals) gelesen hab ich's schon, so 100%-ig verstanden wohl noch nicht...
    das macht die Sache einfacher. Wie gesagt: das Plugin ist nicht grundsätzlich neu, sondern nur eine Abwandlung des MySQL-Plugins und da war's halt so.

    Warum benutzt Du nicht die Convenience Funktionen von sqlite?

    bei Stackoverflow wird im Allgemeinen dazu geraten, _exec durch die Einzelschritte zu ersetzen. Die Begründungen sind da aber meist recht schwammig.

    Ich habe mal aufgeschrieben, wie ich mir das vorstellen könnte - mit einem Dummy-Bar, dass aber die gleichen Setter besitzt wie das Original. Wie Du siehst schnurrt do_query() ordentlich zusammen - was hoffentlich der Lesbarkeit zugute kommt.
    Und eigentlich ist alles was ich gemacht habe, die Bar Erstellung in eine Funktion auslagern.

    super -- vielen Dank nochmal.
    falls jemanden interessiert, wie's weitergeht : ich stell das jeweilige Zwischenergebnis bei
    https://gitorious.org/qtstalker_sqlite3-plugin
    rein.



  • delix schrieb:

    Zum lernen ist QTStalker sicherlich keine gute Wahl - jedenfalls was ich gesehen habe ist ziemlich schrottig - und alt.

    schrottig -- kann ich nicht beurteilen; die meisten Alternativen, die ich sonst so gesehen habe (geniustrader, merchand_of-venice, filu,..) sind aber entweder unter- oder überdimensioniert bzw. nicht in C/C++ geschrieben.

    Ich kanns auch nicht beurteilen - ich war nur angepisst, weil Bar keinen ordentlichen C'tor hat, sondern nur einen Standardkonstruktor und dusselige Setter 🙂
    Du scheinst ja erst nach einiger Abwägung zu QTStalker gekommen zu sein. Und wenn du sagst: "Das macht alles was ich brauche.", ist dem so!

    Viel Erfolg! 🙂



  • delix schrieb:

    schrottig -- kann ich nicht beurteilen; die meisten Alternativen, die ich sonst so gesehen habe (geniustrader, merchand_of-venice, filu,..) sind aber entweder unter- oder überdimensioniert bzw. nicht in C/C++ geschrieben.

    Es gibt ja auch kein C/C++. Wenn Du Qt verwendest, bist Du bei C++.


Anmelden zum Antworten