Home | All Classes | Main Classes | Annotated | Grouped Classes | Functions

SQL Module

QSqlQSqlDatabaseQSqlDriverQSqlDriverPlugin
QSqlEditorFactoryQSqlErrorQSqlFieldQSqlForm
QSqlIndexQSqlPropertyMapQSqlQueryQSqlRecord
QSqlResultQSqlModelQSqlTableModel
See also: Supported Drivers

Introduction

Qt's SQL classes help you provide seamless database integration to your Qt applications.

This overview assumes that you have at least a basic knowledge of SQL. You should be able to understand simple SELECT, INSERT, UPDATE and DELETE commands. Although the QSqlTableModel class provides an interface to database browsing and editing that does not require a knowledge of SQL, a basic understanding of SQL is highly recommended. A standard text covering SQL databases is An Introduction to Database Systems (7th ed.) by C. J. Date, ISBN 0201385902.

This document is divided into six sections:

SQL Module Architecture. This describes how the classes fit together.

Connecting to Databases. This section explains how to set up database connections using the QSqlDatabase class.

Executing SQL Commands. This section demonstrates how to issue the standard data manipulation commands, SELECT, INSERT, UPDATE and DELETE on tables in the database (although any valid SQL statement can be sent to the database). The focus is purely on database interaction using QSqlQuery.

Using Model classes. This section explains how to use the QSqlModel and QSqlTableModel classes which provide a simpler API than the raw SQL used with QSqlQuery.

Data-Aware Widgets. This section shows how to programmatically link your database to the user interface.

All the examples in this document use the tables defined in the Example Tables section.

SQL Module Architecture

The SQL classes are divided into three layers:

User Interface Layer. These classes link the data from a database to data-aware widgets. These classes include QSqlModel and QSqlTableModel.

SQL API Layer. These classes provide access to databases. Connections are made using the QSqlDatabase class. Database interaction is achieved by using the QSqlQuery class. In addition to QSqlDatabase and QSqlQuery, the SQL API layer is supported by QSqlError, QSqlField, QSqlIndex, and QSqlRecord.

Driver Layer. This comprises three classes, QSqlResult, QSqlDriver and QSqlDriverFactoryInterface. This layer provides the low level bridge between the database and the SQL classes. This layer is documented separately since it is only relevant to driver writers, and is rarely used in standard database application programming. See here for more information on implementing a Qt SQL driver plugin.

SQL Driver Plugins

The Qt SQL module can dynamically load new drivers at runtime using the Plugins.

The SQL driver documentation describes how to build plugins for specific database management systems.

Once a plugin is built, Qt will automatically load it, and the driver will be available for use by QSqlDatabase (see QSqlDatabase::drivers() for more information).

Connecting to Databases

At least one database connection must be created and opened before the QSqlQuery or QSqlModel classes can be used.

If the application only needs a single database connection, the QSqlDatabase class can create a connection which is used by default for all SQL operations. If multiple database connections are required these can easily be set up.

QSqlDatabase requires the qsqldatabase.h header file.

Connecting to a Single Database

Making a database connection is a simple three step process: activate the driver, set up the connection information, and open the connection.


From sql/connection.h

First we activate the driver by calling QSqlDatabase::addDatabase(), passing the name of the driver we wish to use for this connection. At the time of writing the available drivers are: QODBC3 (Open Database Connectivity, includes Microsoft SQL Server support), QOCI8 (Oracle 8 and 9), QTDS7 (Sybase Adaptive Server), QPSQL7 (PostgreSQL 6 and 7), QMYSQL3 (MySQL), QDB2 (IBM DB2), QSQLITE (SQLite) and QIBASE (Interbase). Note that some of these drivers aren't included in the Qt Free Edition; see the README files for details.

The connection which is created becomes the application's default database connection and will be used by the Qt SQL classes if no other database is specified.

Second we can call setDatabaseName(), setUserName(), setPassword() and setHostName() to initialize the connection information. Note that for the QOCI8 (Oracle 8 and 9) driver the TNS Service Name must be passed to setDatbaseName(). When connecting to ODBC data sources the Data Source Name (DSN) should be used in the setDatabaseName() call. In this example we use an in-memory database, setting the user name or password is not neccessary.

Third we call open() to open the database and give us access to the data. If this call fails it will return false; error information can be obtained from QSqlDatabase::lastError().

Connecting to Multiple Databases

Connecting to multiple databases is achieved using the two argument form of QSqlDatabase::addDatabase() where the second argument is a unique identifier distinguishing the connection.

    QSqlDatabase db2 = QSqlDatabase::addDatabase("QPSQL7", "SALES");
    QSqlDatabase db3 = QSqlDatabase::addDatabase("QMYSQL3", "ORDERS");

The static function QSqlDatabase::database() can be called from anywhere to provide a pointer to a database connection. If we call it without a parameter it will return the default connection. If called with the identifier we've used for a connection, e.g. "SALES", in the above example, it will return a reference to the specified connection.

Note that QSqlDatabase objects are only smart pointers to a database connection, meaning they are very leightweight and can be passed around on the stack. QSqlDatabase keeps track of the pointers. To remove a database, first close the database with QSqlDatabase::close, and then remove it using the static method QSqlDatabase::removeDatabase(). Note that if you try to remove a database connection that is still in use, QSqlDatabase will issue a warning.

Executing SQL Commands Using QSqlQuery

The QSqlQuery class provides an interface for executing SQL commands. It also has functions for navigating through the result sets of SELECT queries and for retrieving individual records and field values.

The QSqlModel and QSqlTableModel classes described in the next section provide a higher level interface for database access. Programmers unfamiliar with SQL can safely skip this section and use the QSqlTableModel class.

Transactions

If the underlying database engine supports transactions QSqlDriver::hasFeature( QSqlDriver::Transactions ) will return true. You can use QSqlDatabase::transaction() to initiate a transaction, followed by the SQL commands you want to execute within the context of the transaction, and then either QSqlDatabase::commit() or QSqlDatabase::rollback().

Basic Browsing

    QSqlQuery query("SELECT name FROM people");
    while (query.next())
        qDebug("name: %s", query.value(0).toString().ascii());

In the example above we create one query using the default connection that selects the field called name from the table people.

We then iterate over the entire result using the next() function and output each value using the value() function. value() returns all values as QVariant, so we have to call toString() to get the value as a string and ascii() to convert it from unicode to ascii so we can output it with qDebug().

    QSqlQuery query("INSERT INTO people (id, name) values (1, 'Smith')");
    if (query.isActive())
        qDebug("Query ok, number of rows affected: %d", query.numRowsAffected());

The above code introduces a count of how many records are successfully inserted. Note that isActive() returns false if the query, e.g. the insertion, fails. numRowsAffected() returns -1 if the number of rows cannot be determined, e.g. if the query fails.

Navigating Result Sets

Once a SELECT query has been executed successfully we have access to the result set of records that matched the query criteria. We have already used one of the navigation functions, next(), which can be used alone to step sequentially through the records. QSqlQuery also provides first(), last() and prev(). After any of these commands we can check that we are on a valid record by calling isValid().

We can also navigate to any arbitrary record using seek(). The first record in the dataset is zero. The number of the last record is size() - 1. Note that not all databases provide the size of a SELECT query and in such cases size() returns -1.

    QSqlQuery query("SELECT id, name FROM people ORDER BY name");
    if (!query.isActive())
        return; // Query failed
    int i;
    i = query.size();               // In this example we have 9 records; i == 9.
    query.first();                  // Moves to the first record.
    i = query.at();                 // i == 0
    query.last();                   // Moves to the last record.
    i = query.at();                 // i == 8
    query.seek( query.size() / 2 ); // Moves to the middle record.
    i = query.at();                 // i == 4

The example above shows some of the navigation functions in use.

Not all drivers support size(), but we can interrogate the driver to find out:

    QSqlDatabase defaultDB = QSqlDatabase::database();
    if (defaultDB.driver()->hasFeature(QSqlDriver::QuerySize)) {
        // QSqlQuery::size() supported
    } else {
        // QSqlQuery::size() cannot be relied upon
    }

Once we have located the record we are interested in we may wish to retrieve data from it.

    QSqlQuery query("select id, name from person");
    while (query.next()) {
        qDebug("The id is: %d", query.value(0).toInt());
        qDebug("The name is: %s", query.value(1).toString().ascii());
    }

Note that if you wish to iterate through the record set in order the only navigation function you need is next().

Tip: The lastQuery() function returns the text of the last query executed. This can be useful to check that the query you think is being executed is the one actually being executed.


Copyright © 2004 Trolltech. Trademarks
Qt 4.0.0-tp1