Seite 1 von 1

SQLite Qt4 Windows MinGW mag nicht :-(

Verfasst: 10. Mai 2006 13:32
von Eltharion
Hallo. Ich benötige einen Tipp, warum mein SQLite-Test nicht so wie erwartet funktioniert. Konkret will ich eine DB aufmachen und einfach mal eine Zeile aus einer Tabelle rausholen.

Code: Alles auswählen

QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");

db.setDatabaseName("mudmania.db");
// set Username, Pasword, Hostname alles auch schon probiert.

if (! db.open()) {
    QMessageBox::critical(0, qApp->tr("Cannot open database"),
      qApp->tr("Unable to establish a database connection.\n"
               "MUDmania needs SQLite support, but the database\n"
               "plugin of your Qt is not available.\n\n"
               "Click Cancel to exit."), QMessageBox::Cancel, QMessageBox::NoButton);
}

if (db.isOpenError()) {
	QMessageBox::information(0, "MUDmania DB error 1", db.lastError().text());
}

if (! db.isValid()) {
	QMessageBox::information(0, "MUDmania DB", "error 2");
}

QSqlQuery query("select * from worlds");

// AUch schon so probiert:
//QSqlQuery query("select * from worlds", db);

if (! db.isOpen()) {
    QMessageBox::information(this, "mm", "open err");
}

  if (! query.exec()) {
    QMessageBox::information(this, "mm", "exec");
  }

  if (! query.isActive()) {
    QMessageBox::information(this, "mm", "not active");
  }

  if (! query.isValid()) {
    //QMessageBox::information(this, "mm", "not valid");
  }

// Hier kommt ein Leerstring raus !!!
QMessageBox::information(this, "mm tables", db.tables().join(" "));

// Und hier gibt's eine -1 zurück. War nicht anders zu erwarten...
QMessageBox::information(this, "mm size", QString::number(query.size()));

  int i = query.record().indexOf("name");
  while (query.next()) {
    QString str = query.value(i).toString();

	QMessageBox::information(this, "data", str);

    new QListWidgetItem(str, m_list);    
  }
Die in-Memory-Beispiele ohne richtige Datenbank von Qt funktionieren. Alles andere geht nicht. Hat jemand eine Idee, warum? O.g. Code ist ja sonst nur 5 Zeilen lang, ich hab' nur jede Menge Fehlerabfragen noch zusätzlich eingebaut. Könnte ich noch irgendwas abfragen? Irgendwie muss man doch rausbekommen, _warum_ es nicht geht.

Die DB wird gefunden. Format SQL3. Ist sie nicht vorhanden, legt er an der Stelle eine leere DB an. Also wird der Pfad ok sein.

Kenn jemand ein gutes Beispiel, wie man Sqlite unter Qt programmiert? Abgesehen von den Examples.

Ich benutze die MinGW-Qt Version unter Windows. Kann es daran liegen?

Viele Grüße,

E*

Verfasst: 10. Mai 2006 15:10
von patrik08
schreibe dir doch eine class.....

ich habe es so gemacht....

Code: Alles auswählen

bool Gui_Starter::OpenDB(int modus)
{   /* modus = 0=:memory:  1=STATIC_DB_FILE (copy to this file , empity befor)  404=kill_all */
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    
     switch(modus)
      {
         /* #################open ram db##################  */
         case 0:
              if (db.open()) {
              db.close();
              }
              db.setDatabaseName(":memory:");
              if (!db.open()) {
              is_DB_open = false;
              return false;
              }
              is_DB_open = true;
              return true;
         break;
         /* ###############open file db###################  */
         case 1:
              if (db.open()) {
              db.close();
              }
              db.setDatabaseName( STATIC_DB_FILE );
              if (!db.open()) {
              is_DB_open = false;
              return false;
              }
              is_DB_open = true;
              return true;
         break;
         /* ################close all#####################  */
         default: 
              if (db.open()) {
              db.close();
              }
              if (!db.open()) {
              is_DB_open = false;
              return false;
              } else {
              is_DB_open = true;
              return true;
              }            
      }
}

STATIC_DB_FILE ist ein define wo di db ist .... wenn eine neue db kommt loesche ich die alte .. und kopiere eine neue drauf... so kann ich file und memory db machen....

und die variable is_DB_open hat etweder true/false... in der class oder dort wo sie erweitert ist ....


nicht vergessen:
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QSqlTableModel>
#include <QSqlRelationalTableModel>
#include <QSqlRelationalDelegate>
#include <QHeaderView>
#include <QSqlRecord>

und im pro file ..

QT += sql

Verfasst: 10. Mai 2006 15:24
von Eltharion
Danke für Deinen Beitrag. Mein Problem ist vielmehr, dass alles prima aufzugehen scheint, aber ich bei einem Query oder der Abfrage der Tabellen nichts zurückbekomme. Auch keine Fehlermeldung. Die Datenbank gibt es und selbstredend sind auch die Includes (ich nehme da nur QtSql) und Libs passend. Der Wurm muss irgendwo viel tiefer stecken.

Mein Code ist ziemlich zerpflückt und natürlich wird er - wenn alles geht - reduziert. Zumindest die Qt-API ist in diesem Fall ja schön kurz und fast schon elegant. Aber ich war so genervt, da hab' ich den DB-öffnen-Code gleich mit in den Dialog gelegt. Damit nicht irgendwo noch ein Fehler übersehen wird. Normalerweise soll er im Application-Objekt liegen und die DB wird später nur über die Default-Connection benutzt. Aber erstmal muss es überhaupt laufen.

Ach ja, die Tabellen gibt es schon. Angelegt mit dem Sqlitebrowser von Sourceforge. Ich hoffe mal nicht, dass der irgendwelche inkompatiblen Dinge in die DB schreibt. Probiere ich heute abend mal noch aus.

Vielleicht spielt meine Dateiversion der Datenbank mit dem Plugin von Qt nicht richtig zusammen oder die DLL lässt sich aus irgendeinem Grund nur laden, wenn man nicht auf Dateien zugreift. Ich weiss da nicht mehr weiter (höchstens anderes DBS), aber eigentlich wollte ich die Leute nicht zu MySQL o.ä. zwingen.

E*

Verfasst: 10. Mai 2006 15:27
von oberschlingel
Hier ein etwas gepfuschtes beispiel, aber es funktioniert.

connection.h:

Code: Alles auswählen

#ifndef CONNECTION_H
#define CONNECTION_H

#include <QSqlDatabase>
#include <QMessageBox>
#include <QFile>
#include <QString>

// Database connection to SQLite
static bool createConnection() {
// Filename of the database
QString dbname = "test.db";
// Connection to SQLite
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
// Check wether the database exists to avoid that it
// will be created if it doesn't exist
if (!QFile::exists(dbname)) {
QMessageBox::critical(0, (("Tipp10")),
			("Die SQLite Datenbank konnte leider nicht gefunden werden.\n\nDie Anwendung wird nun beendet."));
return false;
}
// Set database
db.setDatabaseName(dbname);
// Open the database
if (!db.open()) {
QMessageBox::critical(0, ("Tipp10"), ("Die Verbindung zur Datenbank SQLite ist leider fehlgeschlagen.\n"Die Anwendung wird nun beendet."));
        return false;
}
QSqlQuery query;
    query.exec("create table lect (id int primary key, "
               "lect_text varchar(80))");
    query.exec("insert into lect values(101, 'Funktioniert')");
    query.exec("insert into lect values(102, Juhuu)");
    query.exec("insert into lect values(103, 'Test')");
return true;

#endif // CONNECTION_H
Es wird zwar nur in eine Tabelle geschrieben, auslesen funktioniert aber genauso gut.

Verfasst: 10. Mai 2006 15:30
von oberschlingel
Zurückgenommen

Verfasst: 10. Mai 2006 15:52
von Eltharion
Erstmal vielen, vielen Dank. Es klappt nun. Ich habe Dein Stück Code angeschaut und es sah' irgendwie genauso aus wie meins. Ergebnis war ähnlich. DB wird geöffnet, aber eine neue Tabelle erscheint nicht. Dann habe ich mal die DB gelöscht und die Fehlermeldung ("Datei exisitiert nicht") rausgenommen und siehe da, eine 3KB große DB wurde angelegt, wo Deine Daten drin standen. Anscheinend ist das Zeug, was der Sqlitebrowser erstellt nicht ganz kompatibel zu dem, was das Plugin mag. Ich habe als Lösung im Sqlitebrowser die SQL-Dateien exportiert und diese dann zeilenweise dem Query.exec() (Code beim QHotel-Projekt auf SF geklaut) gegeben und siehe da, jetzt geht meine DB!!

Also herzlichen Dank. Du hast mich auf die richtige Idee gebracht!

Viele Grüße,

E*

Verfasst: 10. Mai 2006 16:37
von oberschlingel
Ich habe mal den SQLite-Administrator statt den SQLite-Browser verwendet und festgestellt, dass nach Säuberung der DB, Qt die DB nicht mehr lesen kann. Weiß nicht, ob das an der Version liegt, zumindest verwende ich seit dem wieder den SQlite Database Browser und so sind meine Daten voll kompatibel mit Qt.

Verfasst: 10. Mai 2006 16:39
von oberschlingel
Ach ja: ich verwende Qt 4.1.1 und den SQLite Database Browser 1.2.1.
Alles ist voll kompatibel.

Was passiert den, wenn Du nun die mit Qt erstelle DB jetzt mit dem Browser öffnest? Funktioniert das? Falls ja, änder doch mal einen Eintrag, speicher die DB und versuch sie dann wieder mit Qt zu öffnen. So wirst Du schnell feststellen, ob Du ein Versionsproblem hast bzw. die Ursache beim Browser liegt.

Grüße!

Verfasst: 11. Mai 2006 10:10
von Eltharion
Ich hab's nochmal getestet, eine von Qt angelegte Datenbank im Sqlitebrowser um eine Zeile ergänzt führt dazu, dass die Datenbank unter Qt unbrauchbar wird. Ich verwendet derzeit Qt 4.1.0 Windows/Open Source und den SQLite-Browser 1.3.

Was mich ärgert ist:

- Ein Qt-Plugin, dass die DB statisch einlinkt (mag ja gut sein, damit die Beispiele ordentlich und ohne Aufwand laufen) statt eine vorhandene DLL zu nehmen. Das gleiche macht der SQLite-Browser auch. Nur halt mit einer anderen SQLite-Bibliothek :-( Wo die Idee dazu herkam ist ja klar ...

- Zwei SQLite-Versionen, die angeblich beide eine SQLite-Version 3-Datenbank bearbeiten, nur dass die Datenbanken zueinander inkompatibel sind. Das muss man den SQLite Entwicklern anlasten, dass die unfähig sind, bei Inkompatibilitäten im Speicherformat mal eben die Versionsnummer etwas hochzuzählen.

- Qt-Routinen, die so tun, als wäre die Welt in Ordnung und nichtmal im Rückgabewert mitteilen, dass in der DB was schiefgelaufen ist. Ich habe eigentlich jeden Returncode getestet und ausgegeben und keinen Hinweis auf einen Fehler gehabt. Naja, vielleicht hat auch hier das SQLite-DBS einfach so getan als wäre nichts.

Also danke nochmal, vielleicht kann ich Dir ja das nächste Mal weiterhelfen ;-)

E*

Verfasst: 11. Mai 2006 23:02
von mikro
ja, das wars wonach ich auch gesucht hatte. ich hatte es mit den sqlite-commandlineclients von der sqlite.org webseite und dem SQLite Admin probiert und keine Antwort bekommen. Ist echt fies, dass dieses ***-Teil keine vernünftige Antwort gibt.
Jetzt verwende ich auch den SQLiteBrowser (von hier: http://prdownloads.sourceforge.net/sqli ... fault=mesh und schon klappts.
Danke !

Verfasst: 14. Mai 2006 11:57
von patrik08
Es gibt 2 sorten von Sqlite binary datenbank!
wenn man mit einen reinen text (vim window zb.) editor die db aufmacht ist die erste line

"SQLite format 3"
oder
"** This file contains an SQLite 2.1 database **"

Das plug-in oder besser gesagt die dll qt4 plug-in macht da keine kontrolle .... nimmt einfach alles .... eben mit fehler...

das einzige tool das eine kontrolle macht ist sqlite-browser....
und von mir aus auch eine der beste class um daten in qt4 table zu zeigen....

Ich brauchte einen wochen-ende um diese class von qt3 zu qt4 portieren...
siehe im forum....
http://sourceforge.net/forum/forum.php? ... _id=301849

eine check funktion geht etwa so....
aus meinem svn ( svn co http://ciz.ch/svnciz/dialog_qt/qt4_a/table_update/ test )

cd test && qmake a.pro && make mac/win/linux

Code: Alles auswählen

/* check the file db if is sqlite3 format....  */
bool Sqlitedb::check_file_db()
{
   bool ok=false;
   QString first_line = file_get_line(curDBFilename,1);  /* return QString from first line or "" */
   
     QFile file(curDBFilename);
         /*  check befor sqlite3 write a new file! */
         if (!file.exists()) {
         lastErrorMessage = QString( "File \"%1\" could not be read" ).arg( file.fileName() );
         return ok;   
         }
         if (first_line.size() < 1) {
         lastErrorMessage = QString("File could not be read");
         return ok;  
         }      
         if (!first_line.startsWith("SQLite format 3")) {
         lastErrorMessage = QString("File is not a SQLite 3 database");
         return ok;  
        } 
return true;
}

Verfasst: 22. Mai 2006 13:15
von Eltharion
Danke für Deinen Hinweis. Allerdigns habe ich durchaus schon nachgesehen, welche Versionen ich vorliegen habe. Die beiden Versionen der DB sind tatsächlich 2 zueinander inkompatible Version-3-Datenbanken.

Ich teste ansonsten so auf die richtige Version:

Code: Alles auswählen

bool Database::correctDatabaseFileVersion(const QString &filename)
{
  QFile dbfile(filename);

  if (! dbfile.open(QIODevice::ReadOnly)) {
    QMessageBox::critical(0, qApp->tr("Can't open database"),
        qApp->tr("Unable to open the database file for reading.") + "\n\n" +
                 m_msg_app_exit, QMessageBox::Cancel, QMessageBox::NoButton);
    return false;
  }

  QTextStream in(&dbfile);
  QString contents = QString("");

  if (! in.atEnd())
    contents = in.readLine();  // Unlimited, although only 16 chars needed.

  //QMessageBox::information(0, "db", QString::number(contents.length()) + "\n" + contents);

  dbfile.close();

  if (! contents.startsWith("SQLite format 3")) {
    QMessageBox::critical(0, qApp->tr("Can't open database"),
      qApp->tr("File is not a SQLite 3 database.") + "\n\n" +
               m_msg_app_exit, QMessageBox::Cancel, QMessageBox::NoButton);
    return false;
  }

  return true;
}
Interessant ist, dass "in.readLine(16)", also mit Einlesebegrenzung auf 16 Zeichen nur ein Stück von der ersten Zeile holen, nicht funktioniert (Leerstring als Ergebnis). Die ganze Zeile kriege ich.

E*

Verfasst: 5. Juni 2006 04:09
von Eltharion
Hallo patrik08!

Ich habe eben mal Dein Beispiel durchprobiert und ohne den zwischengeschalteten QTextStream klappt das Einlesen eines begrenzten Teils der ersten Zeile mittels z.B. file.Read(15) auch perfekt. Wollte ich nur mal als Rückmeldung geben. Ich habe den QTextStream eben in einem Anfall von Programmier-Perfektionismus wegoptimiert und es funktioniert besser als vorher ;-) Thx für das Beispiel.

E*

Verfasst: 5. Juni 2006 09:30
von patrik08
Eltharion hat geschrieben:Hallo patrik08!
Ich habe eben mal Dein Beispiel durchprobiert und ohne den zwischengeschalteten QTextStream klappt das Einlesen eines begrenzten Teils der ersten Zeile mittels z.B. file.Read(15) auch perfekt. Wollte ich nur mal als Rückmeldung geben. Ich habe den QTextStream eben in einem Anfall von Programmier-Perfektionismus wegoptimiert und es funktioniert besser als vorher ;-) Thx für das Beispiel.
E*

Die beste Performance die ich rausbekommen habe ist so....
(bei mega files...)

contents =file_get_line("dbfile.db","1");

if (! contents.startsWith("SQLite format 3")) { .....

ist immer zu gebrauchen so eine funktion auch um xml/xhtml file zu testen ob sie utf8 sind oder iso 89... ich habe bemerkt dass utf8 file von qt4 nochmals zu utf8 gewandled werden...

Code: Alles auswählen


QString file_get_line(QString fullFileName,int linenr)
{
    QString result;  
    QFile file( fullFileName );
    if( file.open( QIODevice::ReadOnly | QIODevice::Text ) ) {
       QTextStream in( &file );
       int currentLineNr = 0; // or 1
       while( ! in.atEnd() ) {
          QString line( in.readLine() );
          if( currentLineNr == linenr ) {   /* only rewrite here .. lineNr */
             result = line;
             break;
          }
          currentLineNr += 1;
          /*qDebug() << "### linerr  " << currentLineNr; */
       }
    }
    return result;
}