summaryrefslogtreecommitdiffstats
path: root/doc/sql.doc
diff options
context:
space:
mode:
authorTimothy Pearson <[email protected]>2011-07-10 15:24:15 -0500
committerTimothy Pearson <[email protected]>2011-07-10 15:24:15 -0500
commitbd0f3345a938b35ce6a12f6150373b0955b8dd12 (patch)
tree7a520322212d48ebcb9fbe1087e7fca28b76185c /doc/sql.doc
downloadqt3-bd0f3345a938b35ce6a12f6150373b0955b8dd12.tar.gz
qt3-bd0f3345a938b35ce6a12f6150373b0955b8dd12.zip
Add Qt3 development HEAD version
Diffstat (limited to 'doc/sql.doc')
-rw-r--r--doc/sql.doc1351
1 files changed, 1351 insertions, 0 deletions
diff --git a/doc/sql.doc b/doc/sql.doc
new file mode 100644
index 0000000..5aa8266
--- /dev/null
+++ b/doc/sql.doc
@@ -0,0 +1,1351 @@
+/****************************************************************************
+**
+** Documentation for sql programming
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at [email protected].
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+/*! \file sql/overview/connect1/main.cpp */
+/*! \file sql/overview/create_connections/main.cpp */
+/*! \file sql/overview/basicbrowsing/main.cpp */
+/*! \file sql/overview/basicbrowsing2/main.cpp */
+/*! \file sql/overview/basicdatamanip/main.cpp */
+/*! \file sql/overview/navigating/main.cpp */
+/*! \file sql/overview/retrieve1/main.cpp */
+/*! \file sql/overview/retrieve2/main.cpp */
+/*! \file sql/overview/order1/main.cpp */
+/*! \file sql/overview/order2/main.cpp */
+/*! \file sql/overview/extract/main.cpp */
+/*! \file sql/overview/insert/main.cpp */
+/*! \file sql/overview/update/main.cpp */
+/*! \file sql/overview/delete/main.cpp */
+/*! \file sql/overview/table1/main.cpp */
+/*! \file sql/overview/table2/main.cpp */
+/*! \file sql/overview/table3/main.h */
+/*! \file sql/overview/table3/main.cpp */
+/*! \file sql/overview/table4/main.h */
+/*! \file sql/overview/table4/main.cpp */
+/*! \file sql/overview/form1/main.cpp */
+/*! \file sql/overview/form2/main.h */
+/*! \file sql/overview/custom1/main.h */
+/*! \file sql/overview/custom1/main.cpp */
+/*! \file sql/overview/subclass1/main.cpp */
+/*! \file sql/overview/subclass2/main.h */
+/*! \file sql/overview/subclass2/main.cpp */
+/*! \file sql/overview/subclass3/main.h */
+/*! \file sql/overview/subclass3/main.cpp */
+/*! \file sql/overview/subclass4/main.h */
+/*! \file sql/overview/subclass4/main.cpp */
+/*! \file sql/overview/subclass5/main.h */
+/*! \file sql/overview/subclass5/main.cpp */
+
+/*! \page sql.html
+
+\title SQL Module
+
+\if defined(commercial)
+This module is part of the \link commercialeditions.html Qt Enterprise Edition
+\endlink.
+\endif
+
+\table
+\row
+\i \l QSql
+\i \l QSqlCursor
+\i \l QSqlDatabase
+\i \l QSqlDriver
+\i \l QSqlDriverPlugin
+\row
+\i \l QSqlEditorFactory
+\i \l QSqlError
+\i \l QSqlField
+\i \l QSqlFieldInfo
+\i \l QSqlForm
+\row
+\i \l QSqlIndex
+\i \l QSqlPropertyMap
+\i \l QSqlQuery
+\i \l QSqlRecord
+\i \l QSqlRecordInfo
+\row
+\i \l QSqlResult
+\i \l QSqlSelectCursor
+\i31 See also: \link sql-driver.html Supported Drivers\endlink
+\endtable
+
+\tableofcontents
+
+\target Introduction
+\section1 Introduction
+
+Qt's SQL classes help you provide seamless database integration to
+your Qt applications.
+
+<blockquote>
+This overview assumes that you have at least a basic knowledge of SQL.
+You should be able to understand simple \c SELECT, \c INSERT, \c UPDATE
+and \c DELETE commands. Although the \l QSqlCursor class provides an
+interface to database browsing and editing that does not \e require a
+knowledge of SQL, a basic understanding of SQL is highly recommended. A
+standard text covering SQL databases is \e {An Introduction to Database
+Systems (7th ed.)} by C. J. Date, ISBN 0201385902.
+</blockquote>
+
+Whilst this module overview presents the classes from a purely
+programmatic point of view the \link designer-manual.book Qt
+Designer\endlink manual's "Creating Database Applications" chapter
+takes a higher-level approach demonstrating how to set up
+master-detail relationships between widgets, perform drilldown and
+handle foreign key lookups.
+
+This document is divided into six sections:
+
+\link #Architecture SQL Module Architecture \endlink. This describes
+how the classes fit together.
+
+\link #Connecting_to_Databases Connecting to Databases \endlink.
+This section explains how to set up database connections using the \l
+QSqlDatabase class.
+
+\link #Executing_SQL_commands Executing SQL Commands \endlink. This
+section demonstrates how to issue the standard data manipulation
+commands, \c SELECT, \c INSERT, \c UPDATE and \c 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 \l
+QSqlQuery.
+
+\link #Using_QSqlCursor Using Cursors \endlink. This section explains
+how to use the QSqlCursor class which provides a simpler API than the
+raw SQL used with \l QSqlQuery.
+
+\link #Data-Aware_Widgets Data-Aware Widgets \endlink. This section shows
+how to programmatically link your database to the user interface. In
+this section we introduce the \l QDataTable, \l QSqlForm, \l
+QSqlPropertyMap and QSqlEditorFactory classes and demonstrate how to
+use custom data-aware widgets. \link designer-manual.book Qt
+Designer\endlink provides an easy visual way of achieving the same
+thing. See the \link designer-manual.book Qt Designer\endlink manual,
+\l QDataBrowser and \l QDataView for more information.
+
+\link #Subclassing_QSqlCursor Subclassing QSqlCursor \endlink. This
+section gives examples of subclassing QSqlCursor. Subclassing can be
+used to provide default and calculated values for fields (such as
+auto-numbered primary index fields), and to display calculated data,
+e.g. showing names rather than ids of foreign keys.
+
+All the examples in this document use the tables defined in the
+\link #Example_Tables Example Tables\endlink section.
+
+\target Architecture
+\section1 SQL Module Architecture
+
+The SQL classes are divided into three layers:
+
+\e {User Interface Layer.} These classes provide data-aware widgets
+that can be connected to tables or views in the database (by using a
+QSqlCursor as a data source). End users can interact directly with
+these widgets to browse or edit data. \link designer-manual.book Qt
+Designer\endlink is fully integrated with the SQL classes and can be
+used to create data-aware forms. The data-aware widgets can also be
+programmed directly with your own C++ code. The classes that support
+this layer include \l QSqlEditorFactory, \l QSqlForm, \l
+QSqlPropertyMap, \l QDataTable, \l QDataBrowser and \l QDataView.
+
+\e {SQL API Layer.} These classes provide access to databases.
+Connections are made using the \l QSqlDatabase class. Database
+interaction is achieved either by using the QSqlQuery class and
+executing SQL commands directly or by using the higher level \l
+QSqlCursor class which composes SQL commands automatically. In
+addition to \l QSqlDatabase, \l QSqlCursor and \l QSqlQuery, the SQL
+API layer is supported by QSqlError, QSqlField, QSqlFieldInfo,
+QSqlIndex, QSqlRecord and QSqlRecordInfo.
+
+\e {Driver Layer.} This comprises three classes, \l QSqlResult, \l
+QSqlDriver and QSqlDriverFactoryInterface. This layer provides the
+low level bridge between the database and the SQL classes. This layer
+is \link sql-driver.html documented separately \endlink since it is
+only relevant to driver writers, and is rarely used in standard
+database application programming. See \link sql-driver.html here
+\endlink for more information on implementing a Qt SQL driver plugin.
+
+\target Plugins
+\section1 SQL Driver Plugins
+
+The Qt SQL module can dynamically load new drivers at runtime using
+the \link plugins-howto.html Plugins \endlink.
+
+The \link sql-driver.html SQL driver documentation\endlink 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).
+
+\target Connecting_to_Databases
+\section1 Connecting to Databases
+
+At least one database connection must be created and opened before the
+\l QSqlQuery or \l QSqlCursor classes can be used.
+
+If the application only needs a single database connection, the \l
+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.
+
+\l QSqlDatabase requires the \c qsqldatabase.h header file.
+
+\target Connecting_to_a_Single_Database
+\section1 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.
+
+\quotefile sql/overview/connect1/main.cpp
+\skipto include
+\printline include
+\printuntil return 0
+\printline
+\caption From \l sql/overview/connect1/main.cpp
+
+First we activate the driver by calling \l 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 Open Source Edition; see
+the \c 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 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.
+
+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 \l QSqlDatabase::lastError().
+
+\target Connecting_to_Multiple_Databases
+\section2 Connecting to Multiple Databases
+
+Connecting to multiple databases is achieved using the two argument form
+of \l QSqlDatabase::addDatabase() where the second argument is a unique
+identifier distinguishing the connection.
+
+In the example below we have moved the connections into their own
+function, \c createConnections(), and added some basic error handling.
+
+\code
+#define DB_SALES_DRIVER "QPSQL7"
+#define DB_SALES_DBNAME "sales"
+#define DB_SALES_USER "salesperson"
+#define DB_SALES_PASSWD "salesperson"
+#define DB_SALES_HOST "database.domain.no"
+
+#define DB_ORDERS_DRIVER "QOCI8"
+#define DB_ORDERS_DBNAME "orders"
+#define DB_ORDERS_USER "orderperson"
+#define DB_ORDERS_PASSWD "orderperson"
+#define DB_ORDERS_HOST "database.domain.no"
+
+bool createConnections();
+\endcode
+
+We set up some constants and also declare the \c createConnections()
+function in \c connection.h.
+
+\quotefile sql/overview/connection.cpp
+\skipto #include
+\printuntil return TRUE
+\printuntil }
+\caption From \l sql/overview/connection.cpp
+
+We've chosen to isolate database connection in our \c
+createConnections() function.cpp.
+
+\target create_connections
+\quotefile sql/overview/create_connections/main.cpp
+\skipto include
+\printline include
+\printuntil return 0
+\printline
+\caption From \l sql/overview/create_connections/main.cpp
+
+The static function \l 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. "ORACLE", in the
+above example, it will return a pointer to the specified connection.
+
+If you create a \c main.cpp using \link designer-manual.book Qt
+Designer\endlink, it will \e not include our example
+createConnections() function. This means that applications that
+preview correctly in \link designer-manual.book Qt Designer\endlink
+will not run unless you implement your own database connections
+function.
+
+Note that in the code above the ODBC connection was not named and is
+therefore used as the default connection. \l QSqlDatabase maintains
+ownership of the pointers returned by the addDatabase() static
+function. To remove a database from the list of maintained
+connections, first close the database with QSqlDatabase::close(), and
+then remove it using the static function
+QSqlDatabase::removeDatabase().
+
+\target Executing_SQL_commands
+\section1 Executing SQL Commands Using QSqlQuery
+
+The \l QSqlQuery class provides an interface for executing SQL commands.
+It also has functions for navigating through the result sets of \c SELECT
+queries and for retrieving individual records and field values.
+
+The \l QSqlCursor class described in the next section inherits from \l
+QSqlQuery and provides a higher level interface that composes SQL
+commands for us. \l QSqlCursor is particularly easy to integrate with
+on-screen widgets. Programmers unfamiliar with SQL can safely skip this
+section and use the \l QSqlCursor class covered in
+\link #Using_QSqlCursor "Using QSqlCursor" \endlink.
+
+\target Transactions
+\section2 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
+\l{QSqlDatabase::rollback()}.
+
+\target Basic_Browsing
+\section2 Basic Browsing
+
+\quotefile sql/overview/basicbrowsing/main.cpp
+\skipto include
+\printline include
+\printuntil return 0
+\printline
+\caption From \l sql/overview/basicbrowsing/main.cpp
+
+In the example above we've added an additional header file,
+\c qsqlquery.h. The first query we create, \c target, uses the default
+database and is initially empty. For the second query, \c q, we specify
+the "ORACLE" database that we want to retrieve records from. Both the
+database connections were set up in the createConnections() function we
+wrote earlier.
+
+After creating the initial \c SELECT statement, isActive() is checked
+to see if the query executed successfully. The next() function is
+used to iterate through the query results. The value() function
+returns the contents of fields as QVariants. The insertions are
+achieved by creating and executing queries against the default
+database using the \c target QSqlQuery.
+
+Note that this example and all the other examples in this document use
+the tables defined in the \link #Example_Tables Example Tables\endlink
+section.
+
+\quotefile sql/overview/basicbrowsing2/main.cpp
+\skipto count
+\printline
+\printuntil numRows
+\printline
+\printline
+\caption From \l sql/overview/basicbrowsing2/main.cpp
+
+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.
+
+\target Basic_Data_Manipulation
+\section2 Basic Data Manipulation
+
+\quotefile sql/overview/basicdatamanip/main.cpp
+\skipto main
+\printline main
+\printuntil return ( rows
+\printline
+\caption From \l sql/overview/basicdatamanip/main.cpp
+
+This example demonstrates straightforward SQL DML (data manipulation
+language) commands. Since we did not specify a database in the \l
+QSqlQuery constructor the default database is used. \l QSqlQuery objects
+can also be used to execute SQL DDL (data definition language) commands
+such as \c{CREATE TABLE} and \c{CREATE INDEX}.
+
+\target Navigating_Result_Sets
+\section2 Navigating Result Sets
+
+Once a \c 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. \l 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
+\c SELECT query and in such cases size() returns -1.
+
+\quotefile sql/overview/navigating/main.cpp
+\skipto if (
+\printline if (
+\printuntil i == 4
+\printline
+\caption From \l sql/overview/navigating/main.cpp
+
+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:
+
+\code
+ QSqlDatabase* defaultDB = QSqlDatabase::database();
+ if ( defaultDB->driver()->hasFeature( QSqlDriver::QuerySize ) ) {
+ // QSqlQuery::size() supported
+ }
+ else {
+ // QSqlQuery::size() cannot be relied upon
+ }
+\endcode
+
+
+Once we have located the record we are interested in we may wish to
+retrieve data from it.
+
+\quotefile sql/overview/retrieve1/main.cpp
+\skipto if (
+\printline if (
+\printuntil qDebug
+\printline
+\printline
+\printline
+\printline
+\caption From \l sql/overview/retrieve1/main.cpp
+
+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.
+
+\target Using_QSqlCursor
+\section1 Using QSqlCursor
+
+The \l QSqlCursor class provides a high level interface to browsing and
+editing records in SQL database tables or views without the need to
+write your own SQL.
+
+QSqlCursor can do almost everything that QSqlQuery can, with two
+exceptions. Since cursors represent tables or views within the
+database, by default, \l QSqlCursor objects retrieve all the fields of
+each record in the table or view whenever navigating to a new
+record. If only some fields are relevant simply confine your
+processing to those and ignore the others. Or, manually disable the
+generation of certain fields using QSqlRecord::setGenerated(). Another
+approach is to create a \c VIEW which only presents the fields you're
+interested in; but note that some databases do not support editable
+views. So if you really don't want to retrieve all the fields in the
+cursor, then you should use a \l QSqlQuery instead, and customize the
+query to suit your needs. You can edit records using a \l QSqlCursor
+providing that the table or view has a primary index that uniquely
+distinguishes each record. If this condition is not met then you'll
+need to use a \l QSqlQuery for edits.
+
+QSqlCursor operates on a single record at a time. Whenever performing
+an insert, update or delete using QSqlCursor, only a single record in
+the database is affected. When navigating through records in the
+cursor, only one record at a time is available in application code.
+In addition, QSqlCursor maintains a separate 'edit buffer' which is
+used to make changes to a single record in the database. The edit
+buffer is maintained in a separate memory area, and is unnaffected by
+the 'navigation buffer' which changes as the cursor moves from record
+to record.
+
+Before we can use \l QSqlCursor objects we must first create and open
+a database connection. Connecting is described in the \link
+#Connecting_to_Databases Connecting to Databases \endlink section
+above. For the examples that follow we will assume that the
+connections have been created using the createConnections() function
+defined in the \link #create_connections QSqlDatabase example \endlink
+presented earlier.
+
+In the \link #Data-Aware_Widgets data-aware widgets \endlink section that
+follows this one we show how to link widgets to database cursors. Once
+we have a knowledge of both cursors and data-aware widgets we can
+discuss \link #Subclassing_QSqlCursor subclassing QSqlCursor \endlink.
+
+The \l QSqlCursor class requires the \c qsqlcursor.h header file.
+
+\target Retrieving_Records
+\section2 Retrieving Records
+
+\quotefile sql/overview/retrieve2/main.cpp
+\skipto include
+\printline include
+\printuntil return 0
+\printline
+\caption From \l sql/overview/retrieve2/main.cpp
+
+We create the \l QSqlCursor object, specifying the table or view to use.
+If we need to use a database other than the default we can specify it
+in the QSqlCursor constructor.
+
+The SQL executed by the cur.select() call is
+
+\code
+ SELECT staff.id, staff.forename, staff.surname, staff.salary, staff.statusid FROM staff
+\endcode
+
+Next, we iterate through the records returned by this select statement
+using cur.next(). Field values are retrieved in in a similar way to
+QSqlQuery, except that we pass field names rather than numeric indexes
+to value() and setValue().
+
+\target Sorting_Data
+\section3 Sorting and Filtering Records
+
+To specify a subset of records to retrieve we can pass filtering
+criteria to the select() function. Each record that is returned will
+meet the criteria of the filter (the filter corresponds to the SQL
+statement's \c WHERE clause).
+
+\code
+ cur.select( "id > 100" );
+\endcode
+
+This select() call will execute the SQL
+\code
+ SELECT staff.id, staff.forename, staff.surname, staff.salary, staff.statusid
+ FROM staff WHERE staff.id > 100
+\endcode
+
+This will retrieve only those staff whose \c id is greater than 100.
+
+In addition to retrieving selected records we often want to specify a
+sort order for the returned records. This is achieved by creating a \l
+QSqlIndex object which contains the names of the field(s) we wish to
+sort by and pass this object to the select() call.
+
+\code
+ QSqlCursor cur( "staff" );
+ QSqlIndex nameIndex = cur.index( "surname" );
+ cur.select( nameIndex );
+\endcode
+
+Here we create a \l QSqlIndex object with one field, "surname". When
+we call the select() function we pass the index object, which
+specifies that the records should be returned sorted by
+staff.surname. Each field in the index object is used in the ORDER BY
+clause of the select statement. The SQL executed here is
+\code
+ SELECT staff.id, staff.forename, staff.surname, staff.salary, staff.statusid
+ FROM staff ORDER BY staff.surname ASC
+\endcode
+
+Combining the retrieval of a subset of records and ordering the results
+is straightforward.
+
+\code
+ cur.select( "staff.surname LIKE 'A%'", nameIndex );
+\endcode
+
+We pass in a filter string (the \c WHERE clause), and the \l QSqlIndex
+object to sort by (the \c{ORDER BY} clause). This produces
+
+\code
+ SELECT staff.id, staff.forename, staff.surname, staff.salary, staff.statusid
+ FROM staff WHERE staff.surname LIKE 'A%' ORDER BY staff.surname ASC
+\endcode
+
+To sort by more than one field, an index can be created which contains
+multiple fields. Ascending and descending order can be set using
+QSqlIndex::setDescending(); the default is ascending.
+
+\quotefile sql/overview/order1/main.cpp
+\skipto QSqlCursor
+\printline QSqlCursor
+\printuntil while
+\caption From \l sql/overview/order1/main.cpp
+
+Here we create a string list containing the fields we wish to sort by,
+in the order they are to be used. Then we create a \l QSqlIndex object
+based on these fields, finally executing the select() call using this
+index. This executes
+\code
+ SELECT staff.id, staff.forename, staff.surname, staff.salary, staff.statusid
+ FROM staff ORDER BY staff.surname ASC, staff.forename ASC
+\endcode
+
+If we need to retrieve records with fields that match specific criteria we
+can create a filter based on an index.
+
+\quotefile sql/overview/order2/main.cpp
+\skipto QSqlCursor
+\printline QSqlCursor
+\printuntil while
+\caption From \l sql/overview/order2/main.cpp
+
+This executes
+\code
+ SELECT staff.id, staff.forename, staff.surname, staff.salary, staff.statusid
+ FROM staff WHERE staff.surname='Bloggs' ORDER BY staff.id ASC, staff.forename ASC
+\endcode
+
+The "order" \l QSqlIndex contains two fields, "id" and "forename"
+which are used to order the results. The "filter" \l QSqlIndex
+contains a single field, "surname". When an index is passed as a
+filter to the select() function, for each field in the filter, a
+\e{fieldname=value} subclause is created where the value
+is taken from the current cursor's value for that field. We use
+setValue() to ensure that the value used is the one we want.
+
+\target Extracting_Data
+\section3 Extracting Data
+
+\quotefile sql/overview/extract/main.cpp
+\skipto QSqlCursor
+\printline QSqlCursor
+\printuntil qDebug
+\printline
+\caption From \l sql/overview/extract/main.cpp
+
+In this example we begin by creating a cursor on the creditors table.
+We create two \l QSqlIndex objects. The first, "order", is created
+from the "orderFields" string list. The second, "filter", is created
+from the "filterFields" string list. We set the values of the two
+fields used in the filter, "surname" and "city", to the values we're
+interested in. Now we call select() which generates and executes the
+following SQL:
+\code
+ SELECT creditors.city, creditors.surname, creditors.forename, creditors.id
+ FROM creditors
+ WHERE creditors.surname = 'Chirac' AND creditors.city = 'Paris'
+ ORDER BY creditors.surname ASC, creditors.forename ASC
+\endcode
+The filter fields are used in the \c WHERE clause. Their values are
+taken from the cursor's current values for those fields; we set these
+values ourselves with the setValue() calls. The order fields are used
+in the \c{ORDER BY} clause.
+
+Now we iterate through each matching record (if any). We retrieve the
+contents of the id, forename and surname fields and pass them on to
+some processing function, in this example a simple qDebug() call.
+
+\target Manipulating_Records
+\section2 Manipulating Records
+
+Records can be inserted, updated or deleted in a table or view using a
+\l QSqlCursor providing that the table or view has a primary index
+that uniquely distinguishes each record. If this is not the case a \l
+QSqlQuery must be used instead. (Note that not all databases support
+editable views.)
+
+Each cursor has an internal 'edit buffer' which is used by all the
+edit operations (insert, update and delete). The editing process is
+the same for each operation: acquire a pointer to the relevant buffer;
+call setValue() to prime the buffer with the values you want; call
+insert() or update() or del() to perform the desired operation. For
+example, when inserting a record using a cursor, you call
+primeInsert() to get a pointer to the edit buffer and then call
+setValue() on this buffer to set each field's value. Then you call
+QSQlCursor::insert() to insert the contents of the edit buffer into
+the database. Similarly, when updating (or deleting) a record, the
+values of the fields in the edit buffer are used to update (or delete)
+the record in the database. The 'edit buffer' is unaffected by any
+\link #Navigating_Result_Sets cursor navigation \endlink functions.
+Note that if you pass a string value to setValue() any single quotes
+will be escaped (turned into a pair of single quotes) since a single
+quote is a special character in SQL.
+
+The primeInsert(), primeUpdate() and primeDelete() methods all return
+a pointer to the internal edit buffer. Each method can potentially
+perform different operations on the edit buffer before returning it.
+By default, QSqlCursor::primeInsert() clears all the field values in
+the edit buffer (see \l QSqlRecord::clearValues()). Both \l
+QSqlCursor::primeUpdate() and QSqlCursor::primeDelete() initialize the
+edit buffer with the current contents of the cursor before returning
+it. All three of these functions are virtual, so you can redefine the
+behavior (for example, reimplementing primeInsert() to auto-number
+fields in the edit buffer). Data-aware user-interface controls emit
+signals, e.g. primeInsert(), that you can connect to; these pass a
+pointer to the appropriate buffer so subclassing may not be necessary.
+See \link #Subclassing_QSqlCursor subclassing QSqlCursor \endlink for
+more information on subclassing; see the \link designer-manual.book Qt
+Designer\endlink manual for more on connecting to the primeInsert()
+signal.
+
+When insert(), update() or del() is called on a cursor, it will be
+invalidated and will no longer be positioned on a valid record. If you
+need to move to another record after performing an insert(), update()
+or del() you must make a fresh select() call. This ensures that
+changes to the database are accurately reflected in the cursor.
+
+\target Inserting_Records
+\section3 Inserting Records
+
+\quotefile sql/overview/insert/main.cpp
+\skipto QSqlCursor
+\printline QSqlCursor
+\printuntil }
+\caption From \l sql/overview/insert/main.cpp
+
+In this example we create a cursor on the "prices" table. Next we
+create a list of product names which we iterate over. For each
+iteration we call the cursor's primeInsert() method. This method
+returns a pointer to a \l QSqlRecord buffer in which all the fields
+are set to \c NULL. (Note that QSqlCursor::primeInsert() is virtual,
+and can be customized by derived classes. See \l QSqlCursor). Next we
+call setValue() for each field that requires a value. Finally we call
+insert() to insert the record. The insert() call returns the number of
+rows inserted.
+
+We obtained a pointer to a \l QSqlRecord object from the primeInsert()
+call. QSqlRecord objects can hold the data for a single record plus some
+meta-data about the record. In practice most interaction with a
+QSqlRecord consists of simple value() and setValue() calls as shown in
+this and the following example.
+
+\target Updating_Records
+\section3 Updating Records
+
+\quotefile sql/overview/update/main.cpp
+\skipto QSqlCursor
+\printline QSqlCursor
+\printuntil update
+\printline
+\caption From \l sql/overview/update/main.cpp
+
+This example begins with the creation of a cursor over the prices table.
+We select the record we wish to update with the select() call and
+move to it with the next() call. We call primeUpdate() to get a \l
+QSqlRecord pointer to a buffer which is populated with the contents of
+the current record. We retrieve the value of the price field, calculate
+a new price, and set the the price field to the newly calculated value.
+Finally we call update() to update the record. The update() call returns
+the number of rows updated.
+
+If many identical updates need to be performed, for example increasing
+the price of every item in the price list, using a single SQL statement
+with \l QSqlQuery is more efficient, e.g.
+
+\code
+ QSqlQuery query( "UPDATE prices SET price = price * 1.05" );
+\endcode
+
+\target Deleting_Records
+\section3 Deleting Records
+
+\quotefile sql/overview/delete/main.cpp
+\skipto QSqlCursor
+\printline QSqlCursor
+\printuntil del
+\caption From \l sql/overview/delete/main.cpp
+
+To delete records, select the record to be deleted and navigate to it.
+Then call primeDelete() to populate the cursor with the primary key
+of the selected record, (in this example, the \c prices.id field), and
+then call QSqlCursor::del() to delete it.
+
+As with update(), if multiple deletions need to be made with some common
+criteria it is more efficient to do so using a single SQL statement,
+e.g.
+
+\code
+ QSqlQuery query( "DELETE FROM prices WHERE id >= 2450 AND id <= 2500" );
+\endcode
+
+\target Data-Aware_Widgets
+\section1 Data-Aware Widgets
+
+Data-Aware Widgets provide a simple yet powerful means of connecting
+databases to Qt user interfaces. The easiest way of creating and
+manipulating data-aware widgets is with \link designer-manual.book Qt
+Designer\endlink. For those who prefer a purely programmatic approach
+the following examples and explanations provide an introduction. Note
+that the "Creating Database Applications" chapter of the \link
+designer-manual.book Qt Designer\endlink manual and its accompanying
+examples provides additional information.
+
+\target Data-Aware_Tables
+\section2 Data-Aware Tables
+
+\quotefile sql/overview/table1/main.cpp
+\skipto include
+\printline include
+\printuntil return 0
+\printline
+\caption From \l sql/overview/table1/main.cpp
+
+Data-Aware tables require the \c qdatatable.h and \c qsqlcursor.h header
+files. We create our application object, call createConnections() and
+create the cursor. We create the \l QDataTable passing it a pointer to
+the cursor, and set the autoPopulate flag to TRUE. Next we make our \l
+QDataTable the main widget and call refresh() to populate it with data
+and call show() to make it visible.
+
+The autoPopulate flag tells the \l QDataTable whether or nor it should
+create columns based on the cursor. autoPopulate does not affect the
+loading of data into the table; that is achieved by the refresh()
+function.
+
+\quotefile sql/overview/table2/main.cpp
+\skipto staffCursor
+\printline staffCursor
+\printuntil show
+\caption From \l sql/overview/table2/main.cpp
+
+We create an empty \l QDataTable which we make into our main widget and
+then we manually add the columns we want in the order we wish them to
+appear. For each column we specify the field name and optionally a
+display label.
+
+We have also opted to sort the rows in the table; this could also have
+been achieved by applying the sort to the cursor itself.
+
+Once everything is set up we call refresh() to load the data from the
+database and show() to make the widget visible.
+
+QDataTables only retrieve visible rows which (depending on the driver)
+allows even large tables to be displayed very quickly with minimal
+memory cost.
+
+\target Creating_Forms
+\section2 Creating Data-Aware Forms
+
+Creating data-aware forms is more involved than using data-aware
+tables because we must take care of each field individually. Most of
+the code below can be automatically generated by \link
+designer-manual.book Qt Designer\endlink. See the \link
+designer-manual.book Qt Designer\endlink manual for more details.
+
+\target Displaying_a_Record
+\section3 Displaying a Record
+
+\quotefile sql/overview/form1/main.cpp
+\skipto include
+\printline include
+\printuntil app.exec
+\printline
+\caption From \l sql/overview/form1/main.cpp
+
+We include the header files for the widgets that we need. We also
+include \c qsqldatabase.h and \c qsqlcursor.h as usual, but we now add
+\c qsqlform.h.
+
+The form will be presented as a dialog so we subclass \l QDialog with
+our own FormDialog class. We use a \l QLineEdit for the salary so that
+the user can change it. All the widgets are laid out using a grid.
+
+We create a cursor on the staff table, select all records and move to
+the first record.
+
+Now we create a \l QSqlForm object and set the QSqlForm's record buffer
+to the cursor's update buffer. For each widget that we wish to make
+data-aware we insert a pointer to the widget and the associated field
+name into the \l QSqlForm. Finally we call readFields() to populate the
+widgets with data from the database via the cursor's buffer.
+
+\target Displaying_a_Record_in_a_DataForm
+\section3 Displaying a Record in a Data Form
+
+\l QDataView is a Widget that can hold a read-only \l QSqlForm. In
+addition to \l QSqlForm it offers the slot refresh( \l QSqlRecord * ) so it
+can easily be linked together with a \l QDataTable to display a detailed
+view of a record:
+
+\code
+ connect( myDataTable, SIGNAL( currentChanged( QSqlRecord* ) ),
+ myDataView, SLOT( refresh( QSqlRecord* ) ) );
+\endcode
+
+\target Editing_a_Record
+\section3 Editing a Record
+
+This example is similar to the previous one so we will focus on the
+differences.
+
+\quotefile sql/overview/form2/main.h
+\skipto class
+\printline class
+\printuntil };
+\caption From \l sql/overview/form2/main.h
+
+The save slot will be used for a button that the user can press to
+confirm their update. We also hold pointers to the \l QSqlCursor and the
+\l QSqlForm since they will need to be accessed outside the constructor.
+
+\quotefile sql/overview/form2/main.cpp
+\skipto setTrimmed
+\printline setTrimmed
+\printline
+
+We call setTrimmed() on the text fields so that any spaces used to
+right pad the fields are removed when the fields are retrieved.
+
+Properties that we might wish to apply to fields, such as alignment
+and validation are achieved in the conventional way, for example, by
+calling QLineEdit::setAlignment() and QLineEdit::setValidator().
+
+\skipto forenameEdit
+\printline forenameEdit
+
+\skipto saveButton
+\printline saveButton
+\printline connect
+
+The FormDialog constructor is similar to the one in the previous
+example. We have changed the forename and surname widgets to
+\l{QLineEdit}s to make them editable and have added a \l QPushButton
+the user can click to save their updates.
+
+\skipto saveButton
+\printline saveButton
+
+We add an extra row to the grid containing the save button.
+
+\skipto staffCursor
+\printline staffCursor
+\printuntil first
+
+We create a \l QSqlIndex object and then execute a select() using the
+index. We then move to the first record in the result set.
+
+\skipto new QSqlForm
+\printline
+\printline
+
+We create a new QSqlForm object and set it's record buffer to the
+cursor's update buffer.
+
+\skipto insert
+\printline insert
+\printuntil readFields
+
+Now we link the buffer's fields to the \l QLineEdit controls. (In the
+previous example we linked the cursor's fields.) The edit controls are
+populated by the readFields() call as before.
+
+\skipto FormDialog::
+\printline FormDialog::
+\printuntil }
+
+In the destructor we don't have to worry about the widgets or QSqlForm
+since they are children of the form and will be deleted by Qt at the
+right time.
+
+\skipto save
+\printline save
+\printuntil }
+
+Finally we add the save functionality for when the user presses the
+save button. We write back the data from the widgets to the \l
+QSqlRecord buffer with the writeFields() call. Then we update the
+database with the updated version of the record with the cursor's
+update() function. At this point the cursor is no longer positioned at
+a valid record so we reissue the select() call using our \l QSqlIndex
+and move to the first record.
+
+QDataBrowser and QDataView are widgets which provide a great deal of
+the above functionality. \l QDataBrowser provides a data form which
+allows editing of and navigation through a cursor's records. \l
+QDataView provides a read only form for data in a cursor or database
+record. See the class documentation or the \link designer-manual.book
+Qt Designer\endlink manual for more information on using these
+widgets.
+
+Link to \l sql/overview/form2/main.cpp
+
+\target Custom_Editor_Widgets
+\section2 Custom Editor Widgets
+
+QSqlForm uses QSqlPropertyMap to handle the transfer of data between
+widgets and database fields. Custom widgets can also be used in a form
+by installing a property map that contains information about the
+properties of the custom widget which should be used to transfer the
+data.
+
+This example is based on the form2 example in the previous section so
+we will only cover the differences here. The full source is in \l
+sql/overview/custom1/main.h and \l sql/overview/custom1/main.cpp
+
+\quotefile sql/overview/custom1/main.h
+\skipto CustomEdit
+\printline CustomEdit
+\printuntil };
+
+We've created a simple subclass of QLineEdit and added a property,
+upperLineText, which will hold an uppercase version of the text. We
+also created a slot, changed().
+
+\skipto propMap
+\printline propMap
+
+We will be using a property map so we add a pointer to a property map
+to our FormDialog's private data.
+
+\quotefile sql/overview/custom1/main.cpp
+\skipto CustomEdit
+\printline CustomEdit
+\printuntil }
+
+In the CustomEdit constructor we use the QLineEdit constructor and add
+a connection between the textChanged signal and our own changed slot.
+
+\skipto changed
+\printline changed
+\printuntil }
+
+The changed() slot calls our setUpperLine() function.
+
+\skipto setUpperLine
+\printline setUpperLine
+\printuntil }
+
+The setUpperLine() function places an uppercase copy of the text in the
+upperLineText buffer and then sets the text of the widget to this text.
+
+Our CustomEdit class ensures that the text entered is always uppercase
+and provides a property that can be used with a property map to link
+CustomEdit instances directly to database fields.
+
+\skipto FormDialog
+\skipto CustomEdit
+\printline CustomEdit
+
+\skipto CustomEdit
+\printline CustomEdit
+
+We use the same FormDialog as we did before, but this time replace two
+of the QLineEdit widgets with our own CustomEdit widgets.
+
+Laying out the grid and setting up the cursor is the same as before.
+
+\skipto propMap
+\printline propMap
+\printline propMap
+
+We create a new property map on the heap and register our CustomEdit
+class and its upperLine property with the property map.
+
+\skipto QSqlForm
+\printline QSqlForm
+\printline
+\printline propMap
+
+The final change is to install the property map into the QSqlForm once
+the QSqlForm has been created. This passes responsibility for the
+property map's memory to QSqlForm which itself is owned by the
+FormDialog, so Qt will delete them at the right time.
+
+The behaviour of this example is identical to the previous one except
+that the forename and surname fields will be uppercase since they use
+our CustomEdit widget.
+
+\target Custom_Editor_Widgets_for_Tables
+\section3 Custom Editor Widgets for Tables
+
+We must reimpliment QSqlEditorFactory to use custom editor widgets in
+tables. In the following example we will create a custom editor based
+on QComboBox and a QSqlEditorFactory subclass to show how a QDataTable
+can use a custom editor.
+
+\quotefile sql/overview/table3/main.h
+\skipto StatusPicker
+\printline StatusPicker
+\printuntil };
+\caption From \l sql/overview/table3/main.h
+
+We create a property, statusid, and define our READ and WRITE methods
+for it. The statusid's in the status table will probably be different
+from the combobox's indexes so we create a QMap to map combobox indexes
+to/from the statusids that we will list in the combobox.
+
+\skipto CustomSqlEditor
+\printline CustomSqlEditor
+\printuntil };
+
+We also need to subclass QSqlEditorFactory declaring a createEditor()
+function since that is the only function we need to reimplement.
+
+\quotefile sql/overview/table3/main.cpp
+\skipto StatusPicker
+\printline StatusPicker
+\printuntil index2id
+\printline
+\printline
+\caption From \l sql/overview/table3/main.cpp
+
+In the StatusPicker's constructor we create a cursor over the status
+table indexed by the name field. We then iterate over each record in the
+status table inserting each name into the combobox. We store the
+statusid for each name in the index2id QMap using the same QMap index as
+the combobox index.
+
+\skipto StatusPicker
+\printline StatusPicker
+\printuntil }
+
+The statusid property READ function simply involves looking up the
+combobox's index for the currently selected item in the index2id QMap
+which maps combobox indexes to statusids.
+
+\skipto StatusPicker
+\printline StatusPicker
+\printuntil }
+\printline
+\printline
+
+The statusId() function implements the statusid property's WRITE
+function. We create an iterator over a QMap and iterate over the
+index2id QMap. We compare each index2id element's data (statusid) to
+the id parameter's value. If we have a match we set the combobox's
+current item to the index2id element's key (the combobox index), and
+leave the loop.
+
+When the user edits the status field in the QDataTable they will be
+presented with a combobox of valid status names taken from the status
+table. However the status displayed is still the raw statusid. To
+display the status name when the field isn't being edited requires us
+to subclass QDataTable and reimplement the paintField() function.
+
+\quotefile sql/overview/table4/main.h
+\skipto CustomTable
+\printline CustomTable
+\printuntil };
+\caption From \l sql/overview/table4/main.h
+
+We simply call the original QDataTable constructor without changing
+anything. We also declare the paintField function.
+
+\quotefile sql/overview/table4/main.cpp
+\skipto CustomTable
+\printline CustomTable
+\printuntil QDataTable
+\printline
+\caption From \l sql/overview/table4/main.cpp
+
+The paintField code is based on QDataTable's source code. We need to
+make three changes. Firstly add an if clause \c{field->name() ==
+"statusid"} and look up the textual value for the id with a
+straighforward QSqlQuery. Secondly call the superclass to handle other
+fields. The last change is in our main function where we change
+staffTable from being a QDataTable to being a CustomTable.
+
+\target Subclassing_QSqlCursor
+\section1 Subclassing QSqlCursor
+
+\quotefile sql/overview/subclass1/main.cpp
+\skipto include
+\printline include
+\printuntil return 1
+\printline
+\caption From \l sql/overview/subclass1/main.cpp
+
+This example is very similar to the table1 example presented earlier. We
+create a cursor, add the fields and their display labels to a QDataTable,
+call refresh() to load the data and call show() to show the widget.
+
+Unfortunately this example is unsatisfactory. It is tedious to set the
+table name and any custom characteristics for the fields every time we
+need a cursor over this table. And it would be far better if we
+displayed the name of the product rather than its pricesid. Since we
+know the price of the product and the quantity we could also show the
+product cost and the cost of each invoiceitem. Finally it would be
+useful (or even essential for primary keys) if we could default some of
+the values when the user adds a new record.
+
+\quotefile sql/overview/subclass2/main.h
+\skipto InvoiceItem
+\printline InvoiceItem
+\printuntil };
+\caption From \l sql/overview/subclass2/main.h
+
+We have created a separate header file and subclassed QSqlCursor.
+
+\quotefile sql/overview/subclass2/main.cpp
+\skipto InvoiceItem
+\printline InvoiceItem
+\printuntil }
+\caption From \l sql/overview/subclass2/main.cpp
+
+In our class's constructor we call the QSqlCursor constructor with the
+name of the table. We don't have any other characteristics to add at
+this stage.
+
+\skipto InvoiceItemCursor
+\printline InvoiceItemCursor
+
+Whenever we require a cursor over the invoiceitem table we can create
+an InvoiceItemCursor instead of a generic QSqlCursor.
+
+We still need to show the product name rather than the pricesid.
+
+\quotefile sql/overview/subclass3/main.h
+\skipto protected
+\printline protected
+\printline
+\caption From \l sql/overview/subclass3/main.h
+
+The change in the header file is minimal: we simply add the signature
+of the calculateField() function since we will be reimplementing it.
+
+\quotefile sql/overview/subclass3/main.cpp
+\skipto InvoiceItem
+\printline InvoiceItem
+\printuntil return QVariant
+\printline
+\caption From \l sql/overview/subclass3/main.cpp
+
+We have changed the InvoiceItemCursor constructor. We now create a new
+QSqlField called productname and append this to the
+InvoiceItemCursor's set of fields. We call setCalculated() on
+productname to identify it as a calculated field. The first argument
+to setCalculated() is the field name, the second a bool which if TRUE
+signifies that calculateField() must be called to get the field's
+value.
+
+\skipto addColumn
+\printline addColumn
+
+We add our new fields with addColumn() which adds them to the form and
+sets their display names.
+
+We have to define our own calculateField() function. In our example
+database the pricesid in the invoiceitem table is a foreign key into
+the prices table. We find the name of the product by executing a query
+on the prices table using the pricesid. This returns the product's
+name.
+
+We are now able to extend the example to include calculated fields
+which perform real calculations.
+
+The header file, \l sql/overview/subclass4/main.h, remains unchanged
+from the previous example, but the constructor and calculateField()
+function require some simple expansion. We'll look at each in turn.
+
+\quotefile sql/overview/subclass4/main.cpp
+\skipto InvoiceItem
+\printline InvoiceItem
+\printuntil }
+\caption From \l sql/overview/subclass4/main.cpp
+
+We create two extra fields, price and cost, and append them to the
+cursor's set of fields. Both are registered as calculated fields with
+calls to setCalculated().
+
+\skipto InvoiceItem
+\printline InvoiceItem
+\printuntil QString::null
+\printline
+\caption From \l sql/overview/subclass4/main.cpp
+
+The calculateField() function has expanded slightly because now we
+must calculate the value of three different fields. The productname
+and price fields are produced by looking up the corresponding values
+in the prices table keyed by pricesid. The cost field is calculated
+simply by multiplying the price by the quantity. Note that we cast the
+cost to a QVariant since that is the type that calculateField() must
+return.
+
+We've written three separate queries rather than one to make the
+example more like a real application where it is more likely that each
+calculated field would be a lookup against a different table or view.
+
+The last feature that we need to add is defaulting values when the
+user attempts to insert a new record.
+
+\quotefile sql/overview/subclass5/main.h
+\skipto primeInsert
+\printline primeInsert
+\caption From \l sql/overview/subclass5/main.h
+
+We declare our own primeInsert() function since we will need to
+reimplement this.
+
+The constructor and the calculateField() function remain unchanged.
+
+\quotefile sql/overview/subclass5/main.cpp
+\skipto primeInsert
+\printline primeInsert
+\printuntil }
+\caption From \l sql/overview/subclass5/main.cpp
+
+We get a pointer to the internal edit buffer that the cursor uses for
+inserts and updates. The id field is a unique integer that we generate
+using the invoiceitem_seq. We default the value of the paiddate field
+to today's date and default the quantity to 1. Finally we return a
+pointer to the buffer. The rest of the code is unchanged from the
+previous version.
+
+\target Example_Tables
+\section1 The Example Tables
+
+The example tables used can be recreated with the following standard
+SQL. You may need to modify the SQL to match that used by your
+particular database.
+
+\code
+create table people (id integer primary key, name char(40))
+
+create table staff (id integer primary key, forename char(40),
+ surname char(40), salary float, statusid integer)
+
+create table status (id integer primary key, name char(30))
+
+create table creditors (id integer primary key, forename char(40),
+ surname char(40), city char(30))
+
+create table prices (id integer primary key, name char(40), price float)
+
+create table invoiceitem (id integer primary key,
+ pricesid integer, quantity integer,
+ paiddate date)
+\endcode
+
+A sequence was used in the calculateField() example above. Note that
+sequences are not supported in all databases.
+
+\code
+create sequence invoiceitem_seq
+\endcode
+
+*/