открыть существующую базу данных sqlite3 под QT

Я очень новичок в СУБД QT и SQLite. Я пытаюсь открыть существующую базу данных, созданную с помощью программы командной строки sqlite3 под Ubuntu Linux. К той же базе данных я пытаюсь получить доступ из QT, используя следующий код:

void MainWindow::func()
{
    QSqlQuery query;
    accounts_db = new QSqlDatabase();
    *accounts_db = QSqlDatabase::addDatabase("QSQLITE");
    perror("? ");
accounts_db->setDatabaseName("/home/user/xyz.db");
QSqlError *a = new QSqlError();
*a = accounts_db->lastError();
perror(a->text().toLatin1());
if (!accounts_db->open()) {
    perror("database open error :");
}
if ( !accounts_db->isOpen() ) {
    perror("database is not open");
}
query.exec("select accno,branchcode,fname,lname,curbalance,accdate from accounts");
while(query.next()) {
    QString str = query.value(0).toString();
    std::cerr << qPrintable(str) << std::endl;
}
end:
;
}

Это не удается со следующими ошибками...

No such file or directory
: Invalid argument
QSqlQuery::exec: database not open

Обратите внимание, что я получаю «Нет такого файла или каталога» после adddatabase(), понятия не имею, о каком файле идет речь. Также обратите внимание, что isOpen() и open() возвращают "true" (???). Ошибка «база данных не открыта» возникает из-за вызова db.exec() (... я полагаю...).

Отчаянно нуждается в руководстве...


person aditya    schedule 19.10.2011    source источник
comment
Проверьте результат exec, если база данных открыта правильно. Затем проверьте с помощью lastError().   -  person Luca Carlon    schedule 19.10.2011
comment
Я сделал это, вызов exec() выводит ошибку database not open, третью ошибку, которую я указал в вопросе (выше). И lastError() возвращает ошибку Invalid arguments.   -  person aditya    schedule 19.10.2011


Ответы (3)


Конструктор QSqlQuery без параметров использует базу данных по умолчанию для вашего приложения. Возможно, он еще не установлен. Используйте конструктор, указав базу данных, которую должен использовать запрос:

QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "connection_name");
// Open db...
QSqlQuery query(db);
if (!query.exec(...)) {
   // ...
}
// ...

Обратите внимание на то, как вы потом закроете соединение.

РЕДАКТИРОВАТЬ: Это тест, который я только что написал, и он работает в моей системе. Возможно, вы захотите попробовать.

#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QVariant>

int main(int argc, char *argv[])
{
    // Create database.
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "Connection");
    db.setDatabaseName("/tmp/test.db");
    if (!db.open()) {
        qDebug("Error occurred opening the database.");
        qDebug("%s.", qPrintable(db.lastError().text()));
        return -1;
    }

    // Insert table.
    QSqlQuery query(db);
    query.prepare("CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, text TEXT)");
    if (!query.exec()) {
        qDebug("Error occurred creating table.");
        qDebug("%s.", qPrintable(db.lastError().text()));
        return -1;
    }

    // Insert row.
    query.prepare("INSERT INTO test VALUES (null, ?)");
    query.addBindValue("Some text");
    if (!query.exec()) {
        qDebug("Error occurred inserting.");
        qDebug("%s.", qPrintable(db.lastError().text()));
        return -1;
    }

    // Query.
    query.prepare("SELECT * FROM test");
    if (!query.exec()) {
        qDebug("Error occurred querying.");
        qDebug("%s.", qPrintable(db.lastError().text()));
        return -1;
    }
    while (query.next()) {
        qDebug("id = %d, text = %s.", query.value(0).toInt(),
               qPrintable(query.value(1).toString()));
    }

    return 0;
}
person Luca Carlon    schedule 19.10.2011
comment
Я весьма озадачен. Возможно, вы захотите попробовать код, который я добавил к ответу. Это создает базу данных, создает таблицу, вставляет образец строки и запросы. Пожалуйста, сообщите о выходе. - person Luca Carlon; 20.10.2011
comment
попробовал, в результате печатается id = 1, text = Some text. Это правильно? Я все еще новичок, поэтому я еще не понимаю, как работает addBindValue(), поэтому я не понял напечатанный результат. - person aditya; 20.10.2011
comment
Да это верно. Если вы запустите его снова, вы увидите еще одну строку для каждого выполнения. Текст постоянный, целое число всегда будет увеличиваться. Так что все работает нормально. Попробуйте использовать этот код, чтобы открыть базу данных, удалив часть, которая создает новую таблицу, и часть, которая вставляет новую строку. Замените test в запросе на имя вашей таблицы и повторите test. - person Luca Carlon; 20.10.2011
comment
работает безупречный человек !!!. Просто любопытно... Почему нехорошо обращаться к базе данных с помощью указателя? - person aditya; 20.10.2011
comment
Вы имеете в виду QSqlDatabase? Я не думаю, что это проблема, никогда не использовал его таким образом, насколько я помню, но я думаю, что это нормально. Просто правильно обработайте удаление соединения. Это довольно деликатный момент. Обратитесь к removeDatabase в документации Qt за объяснением. - person Luca Carlon; 20.10.2011

В основном это предположение, поскольку ваш код неверен во многих вещах, включая сообщения об ошибках.

Наиболее вероятная проблема заключается в том, что ваш путь к файлу просто неверен, или пользователь, с которым вы запускаете свое приложение, не имеет соответствующих разрешений для файла и/или каталога. (Примечание: в Linux файлы и каталоги чувствительны к регистру.)

perror следует использовать только после вызова системной функции, которая фактически не удалась и которая устанавливает errno, когда это происходит. Qt этого не делает.

Попробуйте запустить это и обновите свой вопрос, если вы все еще не можете решить проблему:

void MainWindow::func()
{
    // Note: no pointer!
    QSqlDatabase accounts_db = QSqlDatabase::addDatabase("QSQLITE");
    accounts_db.setDatabaseName("/home/user/xyz.db");
    if (!accounts_db.open())
    {
        qDebug() << "Could not open database file:";
        qDebug() << accounts_db.lastError();
        return;
    }
    // Note: don't construct queries before you have a database!
    QSqlQuery query;
    if (!query.exec("select accno,branchcode,fname,lname,curbalance,accdate from accounts"))   
    {
        qDebug() << "Query failed:";
        qDebug() << query.lastError();
        return;
    }
    while(query.next()) {
      QString str = query.value(0).toString();
      std::cerr << qPrintable(str) << std::endl;
    }
}

(Я даже не пытался это скомпилировать, так что YMMV.)

Посмотрите также примеры SQL и посмотрите, как они обрабатывают все это там.

person Mat    schedule 19.10.2011
comment
Спасибо, чувак... Я попробовал. qDebug() ‹‹ db.lastError(); продолжает печатать QSqlError(-1, , ) . На самом деле все вызовы lastError() печатают одно и то же, кроме query.exec(). Этот печатает QSqlError(1, Невозможно выполнить оператор, нет такого столбца: accdate) . Но, конечно, эти столбцы существуют, я проверил с помощью программы cmdline sqlite3. В примерах SQL не используются файлы базы данных, они используют :memry: вместо пути к файлу базы данных. - person aditya; 20.10.2011

Хорошо, я создал новый файл базы данных с помощью команды sqlite3, теперь та же программа, что и в моем вопросе, работает!!!.

Я также пробовал это раньше, но в тот раз это не сработало (... я ненавижу, когда это происходит). Я предполагаю, что предыдущий файл может быть поврежден. Но к предыдущему файлу базы данных можно было получить доступ из программы cmdline sqlite3, поэтому я предполагал, что файл в порядке, но, по-видимому, нет.

В любом случае, большое спасибо, ребята, что уделили мне время, и очень жаль, если я потратил его впустую :( .

Я отмечаю это как ответ только для ясности, что на этот вопрос дан ответ. Но это не совсем ответ (... потому что я до сих пор не понимаю, что происходит !? )

Еще раз спасибо...

РЕДАКТИРОВАТЬ :

Вот код

QSqlError *a = new QSqlError();

accounts_db = new QSqlDatabase();
*accounts_db = QSqlDatabase::addDatabase("QSQLITE");

accounts_db->setDatabaseName("/home/user/test.db");

if ( !accounts_db->open() ) {
    qDebug() << accounts_db->lastError();
    qDebug() << "Could not open database file:";
}
QSqlQuery query;

if ( !(accounts_db->isOpen()) ) {
    qDebug() << accounts_db->lastError();
    qDebug() << ": Could not open database file:";
    goto end;   // quit if not successful
}

query.exec("select * from accounts");

while(query.next()) {
    // loop for i columns
    QString str = query.value(i).toString();
    std::cerr << qPrintable(str) << std::endl ;
    // loop
}
end:
;
person aditya    schedule 20.10.2011
comment
Пожалуйста, опубликуйте свой исправленный код без всего материала (особенно материала perror) в вашем ответе, если вы планируете его принять, иначе другие люди могут подумать, что код в вашем вопросе действителен, что нет случай. - person Mat; 20.10.2011
comment
На самом деле это ЕСТЬ, мой предыдущий код ЕСТЬ работает. Все, что я сделал, это попробовал тот же код в другом файле базы данных :). Но я публикую код на всякий случай.... во избежание путаницы. - person aditya; 20.10.2011
comment
Извините, ваш код не подходит. Вы выделяете QSqlDatabase, а затем сразу же выбрасываете ее (утечка). То же самое с QSqlError. Вы используете QSqlDatabase через указатель, который вы не должны использовать. Вы не проверяете возвращаемое значение query.execute(), что является плохой практикой. У вас есть бесполезный goto, который является действительно плохой практикой, особенно в C++. Вы не прерываете свой программный поток, если база данных не открывается, что является плохой практикой. Извините, -1 от меня. - person Mat; 20.10.2011
comment
Ну, я разместил только те части кода, которые были полезны в ответе. Я согласен, GOTO опасны, я ДОЛЖЕН их избегать. Но я использовал его, чтобы выйти из вышеупомянутой функции, метка end: в нижней части кода — это место, где я прыгал, освобождал ресурсы и затем выходил. Как я уже сказал, я новичок в C++ и ООП. Кстати, почему неправильно обращаться к базе данных с помощью указателя? - person aditya; 20.10.2011
comment
Это не неправильно, это не обычно. Это не так, как это делается в образцах. Это приводит к утечкам (как в вашем коде). В C++ труднее получить правильные результаты, чем в C, нет смысла выполнять переход в конец функции, если вы не выполняете там очистку. - person Mat; 20.10.2011