|
|
|
/****************************************************************************
|
|
|
|
**
|
|
|
|
** Implementation of TQSqlCursor class
|
|
|
|
**
|
|
|
|
** Created : 2000-11-03
|
|
|
|
**
|
|
|
|
** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
|
|
|
|
**
|
|
|
|
** This file is part of the sql module of the TQt 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 TQt 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 sales@trolltech.com.
|
|
|
|
**
|
|
|
|
** This file may be used under the terms of the Q Public License as
|
|
|
|
** defined by Trolltech ASA and appearing in the file LICENSE.TQPL
|
|
|
|
** included in the packaging of this file. Licensees holding valid TQt
|
|
|
|
** Commercial licenses may use this file in accordance with the TQt
|
|
|
|
** 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.
|
|
|
|
**
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
#include "qsqlcursor.h"
|
|
|
|
|
|
|
|
#ifndef QT_NO_SQL
|
|
|
|
|
|
|
|
#include "qsqldriver.h"
|
|
|
|
#include "qsqlresult.h"
|
|
|
|
#include "qdatetime.h"
|
|
|
|
#include "qsqldatabase.h"
|
|
|
|
#include "qsql.h"
|
|
|
|
|
|
|
|
class TQSqlCursorPrivate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
TQSqlCursorPrivate( const TQString& name, TQSqlDatabase* sdb )
|
|
|
|
: lastAt( TQSql::BeforeFirst ), nm( name ), srt( name ), md( 0 ), db( sdb ), q( 0 )
|
|
|
|
{}
|
|
|
|
~TQSqlCursorPrivate()
|
|
|
|
{
|
|
|
|
delete q;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQSqlQuery* query()
|
|
|
|
{
|
|
|
|
if ( !q )
|
|
|
|
q = new TQSqlQuery( 0, db );
|
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
|
|
|
int lastAt;
|
|
|
|
TQString nm; //name
|
|
|
|
TQSqlIndex srt; //sort
|
|
|
|
TQString ftr; //filter
|
|
|
|
int md; //mode
|
|
|
|
TQSqlIndex priIndx; //primary index
|
|
|
|
TQSqlRecord editBuffer;
|
|
|
|
// the primary index as it was before the user changed the values in editBuffer
|
|
|
|
TQString editIndex;
|
|
|
|
TQSqlRecordInfo infoBuffer;
|
|
|
|
TQSqlDatabase* db;
|
|
|
|
TQSqlQuery* q;
|
|
|
|
};
|
|
|
|
|
|
|
|
TQString qOrderByClause( const TQSqlIndex & i, const TQString& prefix = TQString::null )
|
|
|
|
{
|
|
|
|
TQString str;
|
|
|
|
int k = i.count();
|
|
|
|
if( k == 0 ) return TQString::null;
|
|
|
|
str = " order by " + i.toString( prefix );
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString qWhereClause( const TQString& prefix, TQSqlField* field, const TQSqlDriver* driver )
|
|
|
|
{
|
|
|
|
TQString f;
|
|
|
|
if ( field && driver ) {
|
|
|
|
f = ( prefix.length() > 0 ? prefix + TQString(".") : TQString::null ) + field->name();
|
|
|
|
if ( field->isNull() ) {
|
|
|
|
f += " IS NULL";
|
|
|
|
} else {
|
|
|
|
f += " = " + driver->formatValue( field );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString qWhereClause( TQSqlRecord* rec, const TQString& prefix, const TQString& sep,
|
|
|
|
const TQSqlDriver* driver )
|
|
|
|
{
|
|
|
|
static TQString blank( " " );
|
|
|
|
TQString filter;
|
|
|
|
bool separator = FALSE;
|
|
|
|
for ( uint j = 0; j < rec->count(); ++j ) {
|
|
|
|
TQSqlField* f = rec->field( j );
|
|
|
|
if ( rec->isGenerated( j ) ) {
|
|
|
|
if ( separator )
|
|
|
|
filter += sep + blank;
|
|
|
|
filter += qWhereClause( prefix, f, driver );
|
|
|
|
filter += blank;
|
|
|
|
separator = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return filter;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\class TQSqlCursor qsqlcursor.h
|
|
|
|
\brief The TQSqlCursor class provides browsing and editing of SQL
|
|
|
|
tables and views.
|
|
|
|
|
|
|
|
\ingroup database
|
|
|
|
\module sql
|
|
|
|
|
|
|
|
A TQSqlCursor is a database record (see \l TQSqlRecord) that
|
|
|
|
corresponds to a table or view within an SQL database (see \l
|
|
|
|
TQSqlDatabase). There are two buffers in a cursor, one used for
|
|
|
|
browsing and one used for editing records. Each buffer contains a
|
|
|
|
list of fields which correspond to the fields in the table or
|
|
|
|
view.
|
|
|
|
|
|
|
|
When positioned on a valid record, the browse buffer contains the
|
|
|
|
values of the current record's fields from the database. The edit
|
|
|
|
buffer is separate, and is used for editing existing records and
|
|
|
|
inserting new records.
|
|
|
|
|
|
|
|
For browsing data, a cursor must first select() data from the
|
|
|
|
database. After a successful select() the cursor is active
|
|
|
|
(isActive() returns TRUE), but is initially not positioned on a
|
|
|
|
valid record (isValid() returns FALSE). To position the cursor on
|
|
|
|
a valid record, use one of the navigation functions, next(),
|
|
|
|
prev(), first(), last(), or seek(). Once positioned on a valid
|
|
|
|
record, data can be retrieved from the browse buffer using
|
|
|
|
value(). If a navigation function is not successful, it returns
|
|
|
|
FALSE, the cursor will no longer be positioned on a valid record
|
|
|
|
and the values returned by value() are undefined.
|
|
|
|
|
|
|
|
For example:
|
|
|
|
|
|
|
|
\quotefile sql/overview/retrieve2/main.cpp
|
|
|
|
\skipto TQSqlCursor
|
|
|
|
\printline TQSqlCursor
|
|
|
|
\printuntil }
|
|
|
|
|
|
|
|
In the above example, a cursor is created specifying a table or
|
|
|
|
view name in the database. Then, select() is called, which can be
|
|
|
|
optionally parameterised to filter and order the records
|
|
|
|
retrieved. Each record in the cursor is retrieved using next().
|
|
|
|
When next() returns FALSE, there are no more records to process,
|
|
|
|
and the loop terminates.
|
|
|
|
|
|
|
|
For editing records (rows of data), a cursor contains a separate
|
|
|
|
edit buffer which is independent of the fields used when browsing.
|
|
|
|
The functions insert(), update() and del() operate on the edit
|
|
|
|
buffer. This allows the cursor to be repositioned to other
|
|
|
|
records while simultaneously maintaining a separate buffer for
|
|
|
|
edits. You can get a pointer to the edit buffer using
|
|
|
|
editBuffer(). The primeInsert(), primeUpdate() and primeDelete()
|
|
|
|
functions also return a pointer to the edit buffer and prepare it
|
|
|
|
for insert, update and delete respectively. Edit operations only
|
|
|
|
affect a single row at a time. Note that update() and del()
|
|
|
|
require that the table or view contain a primaryIndex() to ensure
|
|
|
|
that edit operations affect a unique record within the database.
|
|
|
|
|
|
|
|
For example:
|
|
|
|
|
|
|
|
\quotefile sql/overview/update/main.cpp
|
|
|
|
\skipto prices
|
|
|
|
\printline prices
|
|
|
|
\printuntil update
|
|
|
|
\printline
|
|
|
|
|
|
|
|
To edit an existing database record, first move to the record you
|
|
|
|
wish to update. Call primeUpdate() to get the pointer to the
|
|
|
|
cursor's edit buffer. Then use this pointer to modify the values
|
|
|
|
in the edit buffer. Finally, call update() to save the changes to
|
|
|
|
the database. The values in the edit buffer will be used to
|
|
|
|
locate the appropriate record when updating the database (see
|
|
|
|
primaryIndex()).
|
|
|
|
|
|
|
|
Similarly, when deleting an existing database record, first move
|
|
|
|
to the record you wish to delete. Then, call primeDelete() to get
|
|
|
|
the pointer to the edit buffer. Finally, call del() to delete the
|
|
|
|
record from the database. Again, the values in the edit buffer
|
|
|
|
will be used to locate and delete the appropriate record.
|
|
|
|
|
|
|
|
To insert a new record, call primeInsert() to get the pointer to
|
|
|
|
the edit buffer. Use this pointer to populate the edit buffer
|
|
|
|
with new values and then insert() the record into the database.
|
|
|
|
|
|
|
|
After calling insert(), update() or del(), the cursor is no longer
|
|
|
|
positioned on a valid record and can no longer be navigated
|
|
|
|
(isValid() return FALSE). The reason for this is that any changes
|
|
|
|
made to the database will not be visible until select() is called
|
|
|
|
to refresh the cursor. You can change this behavior by passing
|
|
|
|
FALSE to insert(), update() or del() which will prevent the cursor
|
|
|
|
from becoming invalid. The edits will still not be visible when
|
|
|
|
navigating the cursor until select() is called.
|
|
|
|
|
|
|
|
TQSqlCursor contains virtual methods which allow editing behavior
|
|
|
|
to be customized by subclasses. This allows custom cursors to be
|
|
|
|
created that encapsulate the editing behavior of a database table
|
|
|
|
for an entire application. For example, a cursor can be customized
|
|
|
|
to always auto-number primary index fields, or provide fields with
|
|
|
|
suitable default values, when inserting new records. TQSqlCursor
|
|
|
|
generates SQL statements which are sent to the database engine;
|
|
|
|
you can control which fields are included in these statements
|
|
|
|
using setGenerated().
|
|
|
|
|
|
|
|
Note that TQSqlCursor does not inherit from TQObject. This means
|
|
|
|
that you are responsible for destroying instances of this class
|
|
|
|
yourself. However if you create a TQSqlCursor and use it in a
|
|
|
|
\l TQDataTable, \l TQDataBrowser or a \l TQDataView these classes will
|
|
|
|
usually take ownership of the cursor and destroy it when they
|
|
|
|
don't need it anymore. The documentation for TQDataTable,
|
|
|
|
TQDataBrowser and TQDataView explicitly states which calls take
|
|
|
|
ownership of the cursor.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\enum TQSqlCursor::Mode
|
|
|
|
|
|
|
|
This enum type describes how TQSqlCursor operates on records in the
|
|
|
|
database.
|
|
|
|
|
|
|
|
\value ReadOnly the cursor can only SELECT records from the
|
|
|
|
database.
|
|
|
|
|
|
|
|
\value Insert the cursor can INSERT records into the database.
|
|
|
|
|
|
|
|
\value Update the cursor can UPDATE records in the database.
|
|
|
|
|
|
|
|
\value Delete the cursor can DELETE records from the database.
|
|
|
|
|
|
|
|
\value Writable the cursor can INSERT, UPDATE and DELETE records
|
|
|
|
in the database.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Constructs a cursor on database \a db using table or view \a name.
|
|
|
|
|
|
|
|
If \a autopopulate is TRUE (the default), the \a name of the
|
|
|
|
cursor must correspond to an existing table or view name in the
|
|
|
|
database so that field information can be automatically created.
|
|
|
|
If the table or view does not exist, the cursor will not be
|
|
|
|
functional.
|
|
|
|
|
|
|
|
The cursor is created with an initial mode of TQSqlCursor::Writable
|
|
|
|
(meaning that records can be inserted, updated or deleted using
|
|
|
|
the cursor). If the cursor does not have a unique primary index,
|
|
|
|
update and deletes cannot be performed.
|
|
|
|
|
|
|
|
Note that \a autopopulate refers to populating the cursor with
|
|
|
|
meta-data, e.g. the names of the table's fields, not with
|
|
|
|
retrieving data. The select() function is used to populate the
|
|
|
|
cursor with data.
|
|
|
|
|
|
|
|
\sa setName() setMode()
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQSqlCursor::TQSqlCursor( const TQString & name, bool autopopulate, TQSqlDatabase* db )
|
|
|
|
: TQSqlRecord(), TQSqlQuery( TQString::null, db )
|
|
|
|
{
|
|
|
|
d = new TQSqlCursorPrivate( name, db );
|
|
|
|
setMode( Writable );
|
|
|
|
if ( !d->nm.isNull() )
|
|
|
|
setName( d->nm, autopopulate );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Constructs a copy of \a other.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQSqlCursor::TQSqlCursor( const TQSqlCursor & other )
|
|
|
|
: TQSqlRecord( other ), TQSqlQuery( other )
|
|
|
|
{
|
|
|
|
d = new TQSqlCursorPrivate( other.d->nm, other.d->db );
|
|
|
|
d->lastAt = other.d->lastAt;
|
|
|
|
d->nm = other.d->nm;
|
|
|
|
d->srt = other.d->srt;
|
|
|
|
d->ftr = other.d->ftr;
|
|
|
|
d->priIndx = other.d->priIndx;
|
|
|
|
d->editBuffer = other.d->editBuffer;
|
|
|
|
d->infoBuffer = other.d->infoBuffer;
|
|
|
|
d->q = 0; // do not share queries
|
|
|
|
setMode( other.mode() );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Destroys the object and frees any allocated resources.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQSqlCursor::~TQSqlCursor()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Sets the cursor equal to \a other.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQSqlCursor& TQSqlCursor::operator=( const TQSqlCursor& other )
|
|
|
|
{
|
|
|
|
TQSqlRecord::operator=( other );
|
|
|
|
TQSqlQuery::operator=( other );
|
|
|
|
delete d;
|
|
|
|
d = new TQSqlCursorPrivate( other.d->nm, other.d->db );
|
|
|
|
d->lastAt = other.d->lastAt;
|
|
|
|
d->nm = other.d->nm;
|
|
|
|
d->srt = other.d->srt;
|
|
|
|
d->ftr = other.d->ftr;
|
|
|
|
d->priIndx = other.d->priIndx;
|
|
|
|
d->editBuffer = other.d->editBuffer;
|
|
|
|
d->infoBuffer = other.d->infoBuffer;
|
|
|
|
d->q = 0; // do not share queries
|
|
|
|
setMode( other.mode() );
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Sets the current sort to \a sort. Note that no new records are
|
|
|
|
selected. To select new records, use select(). The \a sort will
|
|
|
|
apply to any subsequent select() calls that do not explicitly
|
|
|
|
specify a sort.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void TQSqlCursor::setSort( const TQSqlIndex& sort )
|
|
|
|
{
|
|
|
|
d->srt = sort;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns the current sort, or an empty index if there is no current
|
|
|
|
sort.
|
|
|
|
*/
|
|
|
|
TQSqlIndex TQSqlCursor::sort() const
|
|
|
|
{
|
|
|
|
return d->srt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Sets the current filter to \a filter. Note that no new records are
|
|
|
|
selected. To select new records, use select(). The \a filter will
|
|
|
|
apply to any subsequent select() calls that do not explicitly
|
|
|
|
specify a filter.
|
|
|
|
|
|
|
|
The filter is a SQL \c WHERE clause without the keyword 'WHERE',
|
|
|
|
e.g. \c{name='Dave'} which will be processed by the DBMS.
|
|
|
|
*/
|
|
|
|
void TQSqlCursor::setFilter( const TQString& filter )
|
|
|
|
{
|
|
|
|
d->ftr = filter;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns the current filter, or an empty string if there is no
|
|
|
|
current filter.
|
|
|
|
*/
|
|
|
|
TQString TQSqlCursor::filter() const
|
|
|
|
{
|
|
|
|
return d->ftr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Sets the name of the cursor to \a name. If \a autopopulate is TRUE
|
|
|
|
(the default), the \a name must correspond to a valid table or
|
|
|
|
view name in the database. Also, note that all references to the
|
|
|
|
cursor edit buffer become invalidated when fields are
|
|
|
|
auto-populated. See the TQSqlCursor constructor documentation for
|
|
|
|
more information.
|
|
|
|
*/
|
|
|
|
void TQSqlCursor::setName( const TQString& name, bool autopopulate )
|
|
|
|
{
|
|
|
|
d->nm = name;
|
|
|
|
if ( autopopulate ) {
|
|
|
|
if ( driver() ) {
|
|
|
|
d->infoBuffer = driver()->recordInfo( name );
|
|
|
|
*this = d->infoBuffer.toRecord();
|
|
|
|
d->editBuffer = *this;
|
|
|
|
d->priIndx = driver()->primaryIndex( name );
|
|
|
|
}
|
|
|
|
#ifdef QT_CHECK_RANGE
|
|
|
|
if ( isEmpty() )
|
|
|
|
qWarning("TQSqlCursor::setName: unable to build record, does '%s' exist?", name.latin1() );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns the name of the cursor.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQString TQSqlCursor::name() const
|
|
|
|
{
|
|
|
|
return d->nm;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \reimp
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQString TQSqlCursor::toString( const TQString& prefix, const TQString& sep ) const
|
|
|
|
{
|
|
|
|
TQString pflist;
|
|
|
|
TQString pfix = prefix.isEmpty() ? TQString::null : prefix + ".";
|
|
|
|
bool comma = FALSE;
|
|
|
|
|
|
|
|
for ( uint i = 0; i < count(); ++i ) {
|
|
|
|
const TQString fname = fieldName( i );
|
|
|
|
if ( isGenerated( i ) ) {
|
|
|
|
if( comma )
|
|
|
|
pflist += sep + " ";
|
|
|
|
pflist += pfix + fname;
|
|
|
|
comma = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return pflist;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\internal
|
|
|
|
|
|
|
|
Assigns the record \a list.
|
|
|
|
|
|
|
|
*/
|
|
|
|
TQSqlRecord & TQSqlCursor::operator=( const TQSqlRecord & list )
|
|
|
|
{
|
|
|
|
return TQSqlRecord::operator=( list );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Append a copy of field \a fieldInfo to the end of the cursor. Note
|
|
|
|
that all references to the cursor edit buffer become invalidated.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void TQSqlCursor::append( const TQSqlFieldInfo& fieldInfo )
|
|
|
|
{
|
|
|
|
d->editBuffer.append( fieldInfo.toField() );
|
|
|
|
d->editBuffer.setGenerated( d->editBuffer.count() - 1, fieldInfo.isGenerated() );
|
|
|
|
d->infoBuffer.append( fieldInfo );
|
|
|
|
TQSqlRecord::append( fieldInfo.toField() );
|
|
|
|
TQSqlRecord::setGenerated( TQSqlRecord::count() - 1, fieldInfo.isGenerated() );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Removes all fields from the cursor. Note that all references to
|
|
|
|
the cursor edit buffer become invalidated.
|
|
|
|
*/
|
|
|
|
void TQSqlCursor::clear()
|
|
|
|
{
|
|
|
|
d->editBuffer.clear();
|
|
|
|
d->infoBuffer.clear();
|
|
|
|
TQSqlRecord::clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Insert a copy of \a fieldInfo at position \a pos. If a field
|
|
|
|
already exists at \a pos, it is removed. Note that all references
|
|
|
|
to the cursor edit buffer become invalidated.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void TQSqlCursor::insert( int pos, const TQSqlFieldInfo& fieldInfo )
|
|
|
|
{
|
|
|
|
d->editBuffer.insert( pos, fieldInfo.toField() );
|
|
|
|
d->editBuffer.setGenerated( pos, fieldInfo.isGenerated() );
|
|
|
|
d->infoBuffer[ pos ] = fieldInfo;
|
|
|
|
TQSqlRecord::insert( pos, fieldInfo.toField() );
|
|
|
|
TQSqlRecord::setGenerated( pos, fieldInfo.isGenerated() );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Removes the field at \a pos. If \a pos does not exist, nothing
|
|
|
|
happens. Note that all references to the cursor edit buffer become
|
|
|
|
invalidated.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void TQSqlCursor::remove( int pos )
|
|
|
|
{
|
|
|
|
d->editBuffer.remove( pos );
|
|
|
|
d->infoBuffer[ pos ] = TQSqlFieldInfo();
|
|
|
|
TQSqlRecord::remove( pos );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Sets the generated flag for the field \a name to \a generated. If
|
|
|
|
the field does not exist, nothing happens. Only fields that have
|
|
|
|
\a generated set to TRUE are included in the SQL that is
|
|
|
|
generated by insert(), update() or del().
|
|
|
|
|
|
|
|
\sa isGenerated()
|
|
|
|
*/
|
|
|
|
|
|
|
|
void TQSqlCursor::setGenerated( const TQString& name, bool generated )
|
|
|
|
{
|
|
|
|
int pos = position( name );
|
|
|
|
if ( pos == -1 )
|
|
|
|
return;
|
|
|
|
TQSqlRecord::setGenerated( name, generated );
|
|
|
|
d->editBuffer.setGenerated( name, generated );
|
|
|
|
d->infoBuffer[ pos ].setGenerated( generated );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\overload
|
|
|
|
|
|
|
|
Sets the generated flag for the field \a i to \a generated.
|
|
|
|
|
|
|
|
\sa isGenerated()
|
|
|
|
*/
|
|
|
|
void TQSqlCursor::setGenerated( int i, bool generated )
|
|
|
|
{
|
|
|
|
if ( i < 0 || i >= (int)d->infoBuffer.count() )
|
|
|
|
return;
|
|
|
|
TQSqlRecord::setGenerated( i, generated );
|
|
|
|
d->editBuffer.setGenerated( i, generated );
|
|
|
|
d->infoBuffer[i].setGenerated( generated );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns the primary index associated with the cursor as defined in
|
|
|
|
the database, or an empty index if there is no primary index. If
|
|
|
|
\a setFromCursor is TRUE (the default), the index fields are
|
|
|
|
populated with the corresponding values in the cursor's current
|
|
|
|
record.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQSqlIndex TQSqlCursor::primaryIndex( bool setFromCursor ) const
|
|
|
|
{
|
|
|
|
if ( setFromCursor ) {
|
|
|
|
for ( uint i = 0; i < d->priIndx.count(); ++i ) {
|
|
|
|
const TQString fn = d->priIndx.fieldName( i );
|
|
|
|
if ( contains( fn ) )
|
|
|
|
d->priIndx.setValue( i, value( fn ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return d->priIndx;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Sets the primary index associated with the cursor to the index \a
|
|
|
|
idx. Note that this index must contain a field or set of fields
|
|
|
|
which identify a unique record within the underlying database
|
|
|
|
table or view so that update() and del() will execute as expected.
|
|
|
|
|
|
|
|
\sa update() del()
|
|
|
|
*/
|
|
|
|
|
|
|
|
void TQSqlCursor::setPrimaryIndex( const TQSqlIndex& idx )
|
|
|
|
{
|
|
|
|
d->priIndx = idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns an index composed of \a fieldNames, all in ASCending
|
|
|
|
order. Note that all field names must exist in the cursor,
|
|
|
|
otherwise an empty index is returned.
|
|
|
|
|
|
|
|
\sa TQSqlIndex
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQSqlIndex TQSqlCursor::index( const TQStringList& fieldNames ) const
|
|
|
|
{
|
|
|
|
TQSqlIndex idx;
|
|
|
|
for ( TQStringList::ConstIterator it = fieldNames.begin(); it != fieldNames.end(); ++it ) {
|
|
|
|
const TQSqlField* f = field( (*it) );
|
|
|
|
if ( !f ) { /* all fields must exist */
|
|
|
|
idx.clear();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
idx.append( *f );
|
|
|
|
}
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\overload
|
|
|
|
|
|
|
|
Returns an index based on \a fieldName.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQSqlIndex TQSqlCursor::index( const TQString& fieldName ) const
|
|
|
|
{
|
|
|
|
TQStringList fl( fieldName );
|
|
|
|
return index( fl );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\overload
|
|
|
|
|
|
|
|
Returns an index based on \a fieldName.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQSqlIndex TQSqlCursor::index( const char* fieldName ) const
|
|
|
|
{
|
|
|
|
return index( TQStringList( TQString( fieldName ) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Selects all fields in the cursor from the database matching the
|
|
|
|
filter criteria \a filter. The data is returned in the order
|
|
|
|
specified by the index \a sort. Returns TRUE if the data was
|
|
|
|
successfully selected; otherwise returns FALSE.
|
|
|
|
|
|
|
|
The \a filter is a string containing a SQL \c WHERE clause but
|
|
|
|
without the 'WHERE' keyword. The cursor is initially positioned at
|
|
|
|
an invalid row after this function is called. To move to a valid
|
|
|
|
row, use seek(), first(), last(), prev() or next().
|
|
|
|
|
|
|
|
Example:
|
|
|
|
\code
|
|
|
|
TQSqlCursor cur( "Employee" ); // Use the Employee table or view
|
|
|
|
cur.select( "deptno=10" ); // select all records in department 10
|
|
|
|
while( cur.next() ) {
|
|
|
|
... // process data
|
|
|
|
}
|
|
|
|
...
|
|
|
|
// select records in other departments, ordered by department number
|
|
|
|
cur.select( "deptno>10", cur.index( "deptno" ) );
|
|
|
|
...
|
|
|
|
\endcode
|
|
|
|
|
|
|
|
The filter will apply to any subsequent select() calls that do not
|
|
|
|
explicitly specify another filter. Similarly the sort will apply
|
|
|
|
to any subsequent select() calls that do not explicitly specify
|
|
|
|
another sort.
|
|
|
|
|
|
|
|
\code
|
|
|
|
TQSqlCursor cur( "Employee" );
|
|
|
|
cur.select( "deptno=10" ); // select all records in department 10
|
|
|
|
while( cur.next() ) {
|
|
|
|
... // process data
|
|
|
|
}
|
|
|
|
...
|
|
|
|
cur.select(); // re-selects all records in department 10
|
|
|
|
...
|
|
|
|
\endcode
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool TQSqlCursor::select( const TQString & filter, const TQSqlIndex & sort )
|
|
|
|
{
|
|
|
|
TQString fieldList = toString( d->nm );
|
|
|
|
if ( fieldList.isEmpty() )
|
|
|
|
return FALSE;
|
|
|
|
TQString str= "select " + fieldList;
|
|
|
|
str += " from " + d->nm;
|
|
|
|
if ( !filter.isEmpty() ) {
|
|
|
|
d->ftr = filter;
|
|
|
|
str += " where " + filter;
|
|
|
|
} else
|
|
|
|
d->ftr = TQString::null;
|
|
|
|
if ( sort.count() > 0 )
|
|
|
|
str += " order by " + sort.toString( d->nm );
|
|
|
|
d->srt = sort;
|
|
|
|
return exec( str );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\overload
|
|
|
|
|
|
|
|
Selects all fields in the cursor from the database. The rows are
|
|
|
|
returned in the order specified by the last call to setSort() or
|
|
|
|
the last call to select() that specified a sort, whichever is the
|
|
|
|
most recent. If there is no current sort, the order in which the
|
|
|
|
rows are returned is undefined. The records are filtered according
|
|
|
|
to the filter specified by the last call to setFilter() or the
|
|
|
|
last call to select() that specified a filter, whichever is the
|
|
|
|
most recent. If there is no current filter, all records are
|
|
|
|
returned. The cursor is initially positioned at an invalid row. To
|
|
|
|
move to a valid row, use seek(), first(), last(), prev() or
|
|
|
|
next().
|
|
|
|
|
|
|
|
\sa setSort() setFilter()
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool TQSqlCursor::select()
|
|
|
|
{
|
|
|
|
return select( filter(), sort() );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\overload
|
|
|
|
|
|
|
|
Selects all fields in the cursor from the database. The data is
|
|
|
|
returned in the order specified by the index \a sort. The records
|
|
|
|
are filtered according to the filter specified by the last call to
|
|
|
|
setFilter() or the last call to select() that specified a filter,
|
|
|
|
whichever is the most recent. The cursor is initially positioned
|
|
|
|
at an invalid row. To move to a valid row, use seek(), first(),
|
|
|
|
last(), prev() or next().
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool TQSqlCursor::select( const TQSqlIndex& sort )
|
|
|
|
{
|
|
|
|
return select( filter(), sort );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\overload
|
|
|
|
|
|
|
|
Selects all fields in the cursor matching the filter index \a
|
|
|
|
filter. The data is returned in the order specified by the index
|
|
|
|
\a sort. The \a filter index works by constructing a WHERE clause
|
|
|
|
using the names of the fields from the \a filter and their values
|
|
|
|
from the current cursor record. The cursor is initially positioned
|
|
|
|
at an invalid row. To move to a valid row, use seek(), first(),
|
|
|
|
last(), prev() or next(). This function is useful, for example,
|
|
|
|
for retrieving data based upon a table's primary index:
|
|
|
|
|
|
|
|
\code
|
|
|
|
TQSqlCursor cur( "Employee" );
|
|
|
|
TQSqlIndex pk = cur.primaryIndex();
|
|
|
|
cur.setValue( "id", 10 );
|
|
|
|
cur.select( pk, pk ); // generates "SELECT ... FROM Employee WHERE id=10 ORDER BY id"
|
|
|
|
...
|
|
|
|
\endcode
|
|
|
|
|
|
|
|
In this example the TQSqlIndex, pk, is used for two different
|
|
|
|
purposes. When used as the filter (first) argument, the field
|
|
|
|
names it contains are used to construct the WHERE clause, each set
|
|
|
|
to the current cursor value, \c{WHERE id=10}, in this case. When
|
|
|
|
used as the sort (second) argument the field names it contains are
|
|
|
|
used for the ORDER BY clause, \c{ORDER BY id} in this example.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool TQSqlCursor::select( const TQSqlIndex & filter, const TQSqlIndex & sort )
|
|
|
|
{
|
|
|
|
return select( toString( filter, this, d->nm, "=", "and" ), sort );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Sets the cursor mode to \a mode. This value can be an OR'ed
|
|
|
|
combination of \l TQSqlCursor::Mode values. The default mode for a
|
|
|
|
cursor is \c TQSqlCursor::Writable.
|
|
|
|
|
|
|
|
\code
|
|
|
|
TQSqlCursor cur( "Employee" );
|
|
|
|
cur.setMode( TQSqlCursor::Writable ); // allow insert/update/delete
|
|
|
|
...
|
|
|
|
cur.setMode( TQSqlCursor::Insert | TQSqlCursor::Update ); // allow inserts and updates only
|
|
|
|
...
|
|
|
|
cur.setMode( TQSqlCursor::ReadOnly ); // no inserts/updates/deletes allowed
|
|
|
|
|
|
|
|
\endcode
|
|
|
|
*/
|
|
|
|
|
|
|
|
void TQSqlCursor::setMode( int mode )
|
|
|
|
{
|
|
|
|
d->md = mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns the current cursor mode.
|
|
|
|
|
|
|
|
\sa setMode()
|
|
|
|
*/
|
|
|
|
|
|
|
|
int TQSqlCursor::mode() const
|
|
|
|
{
|
|
|
|
return d->md;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Sets field \a name to \a calculated. If the field \a name does not
|
|
|
|
exist, nothing happens. The value of a calculated field is set by
|
|
|
|
the calculateField() virtual function which you must reimplement
|
|
|
|
(or the field value will be an invalid TQVariant). Calculated
|
|
|
|
fields do not appear in generated SQL statements sent to the
|
|
|
|
database.
|
|
|
|
|
|
|
|
\sa calculateField() TQSqlRecord::setGenerated()
|
|
|
|
*/
|
|
|
|
|
|
|
|
void TQSqlCursor::setCalculated( const TQString& name, bool calculated )
|
|
|
|
{
|
|
|
|
int pos = position( name );
|
|
|
|
if ( pos < 0 )
|
|
|
|
return;
|
|
|
|
d->infoBuffer[ pos ].setCalculated( calculated );
|
|
|
|
if ( calculated )
|
|
|
|
setGenerated( pos, FALSE );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns TRUE if the field \a name exists and is calculated;
|
|
|
|
otherwise returns FALSE.
|
|
|
|
|
|
|
|
\sa setCalculated()
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool TQSqlCursor::isCalculated( const TQString& name ) const
|
|
|
|
{
|
|
|
|
int pos = position( name );
|
|
|
|
if ( pos < 0 )
|
|
|
|
return FALSE;
|
|
|
|
return d->infoBuffer[ pos ].isCalculated();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Sets field \a{name}'s trimmed status to \a trim. If the field \a
|
|
|
|
name does not exist, nothing happens.
|
|
|
|
|
|
|
|
When a trimmed field of type string or cstring is read from the
|
|
|
|
database any trailing (right-most) spaces are removed.
|
|
|
|
|
|
|
|
\sa isTrimmed() TQVariant
|
|
|
|
*/
|
|
|
|
|
|
|
|
void TQSqlCursor::setTrimmed( const TQString& name, bool trim )
|
|
|
|
{
|
|
|
|
int pos = position( name );
|
|
|
|
if ( pos < 0 )
|
|
|
|
return;
|
|
|
|
d->infoBuffer[ pos ].setTrim( trim );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns TRUE if the field \a name exists and is trimmed; otherwise
|
|
|
|
returns FALSE.
|
|
|
|
|
|
|
|
When a trimmed field of type string or cstring is read from the
|
|
|
|
database any trailing (right-most) spaces are removed.
|
|
|
|
|
|
|
|
\sa setTrimmed()
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool TQSqlCursor::isTrimmed( const TQString& name ) const
|
|
|
|
{
|
|
|
|
int pos = position( name );
|
|
|
|
if ( pos < 0 )
|
|
|
|
return FALSE;
|
|
|
|
return d->infoBuffer[ pos ].isTrim();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns TRUE if the cursor is read-only; otherwise returns FALSE.
|
|
|
|
The default is FALSE. Read-only cursors cannot be edited using
|
|
|
|
insert(), update() or del().
|
|
|
|
|
|
|
|
\sa setMode()
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool TQSqlCursor::isReadOnly() const
|
|
|
|
{
|
|
|
|
return d->md == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns TRUE if the cursor will perform inserts; otherwise returns
|
|
|
|
FALSE.
|
|
|
|
|
|
|
|
\sa setMode()
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool TQSqlCursor::canInsert() const
|
|
|
|
{
|
|
|
|
return ( ( d->md & Insert ) == Insert ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns TRUE if the cursor will perform updates; otherwise returns
|
|
|
|
FALSE.
|
|
|
|
|
|
|
|
\sa setMode()
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool TQSqlCursor::canUpdate() const
|
|
|
|
{
|
|
|
|
return ( ( d->md & Update ) == Update ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns TRUE if the cursor will perform deletes; otherwise returns
|
|
|
|
FALSE.
|
|
|
|
|
|
|
|
\sa setMode()
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool TQSqlCursor::canDelete() const
|
|
|
|
{
|
|
|
|
return ( ( d->md & Delete ) == Delete ) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\overload
|
|
|
|
|
|
|
|
Returns a formatted string composed of the \a prefix (e.g. table
|
|
|
|
or view name), ".", the \a field name, the \a fieldSep and the
|
|
|
|
field value. If the \a prefix is empty then the string will begin
|
|
|
|
with the \a field name. This function is useful for generating SQL
|
|
|
|
statements.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQString TQSqlCursor::toString( const TQString& prefix, TQSqlField* field, const TQString& fieldSep ) const
|
|
|
|
{
|
|
|
|
TQString f;
|
|
|
|
if ( field && driver() ) {
|
|
|
|
f = ( prefix.length() > 0 ? prefix + TQString(".") : TQString::null ) + field->name();
|
|
|
|
f += " " + fieldSep + " ";
|
|
|
|
if ( field->isNull() ) {
|
|
|
|
f += "NULL";
|
|
|
|
} else {
|
|
|
|
f += driver()->formatValue( field );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns a formatted string composed of all the fields in \a rec.
|
|
|
|
Each field is composed of the \a prefix (e.g. table or view name),
|
|
|
|
".", the field name, the \a fieldSep and the field value. If the
|
|
|
|
\a prefix is empty then each field will begin with the field name.
|
|
|
|
The fields are then joined together separated by \a sep. Fields
|
|
|
|
where isGenerated() returns FALSE are not included. This function
|
|
|
|
is useful for generating SQL statements.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQString TQSqlCursor::toString( TQSqlRecord* rec, const TQString& prefix, const TQString& fieldSep,
|
|
|
|
const TQString& sep ) const
|
|
|
|
{
|
|
|
|
static TQString blank( " " );
|
|
|
|
TQString filter;
|
|
|
|
bool separator = FALSE;
|
|
|
|
for ( uint j = 0; j < count(); ++j ) {
|
|
|
|
TQSqlField* f = rec->field( j );
|
|
|
|
if ( rec->isGenerated( j ) ) {
|
|
|
|
if ( separator )
|
|
|
|
filter += sep + blank;
|
|
|
|
filter += toString( prefix, f, fieldSep );
|
|
|
|
filter += blank;
|
|
|
|
separator = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return filter;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\overload
|
|
|
|
|
|
|
|
Returns a formatted string composed of all the fields in the index
|
|
|
|
\a i. Each field is composed of the \a prefix (e.g. table or view
|
|
|
|
name), ".", the field name, the \a fieldSep and the field value.
|
|
|
|
If the \a prefix is empty then each field will begin with the field
|
|
|
|
name. The field values are taken from \a rec. The fields are then
|
|
|
|
joined together separated by \a sep. Fields where isGenerated()
|
|
|
|
returns FALSE are ignored. This function is useful for generating
|
|
|
|
SQL statements.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQString TQSqlCursor::toString( const TQSqlIndex& i, TQSqlRecord* rec, const TQString& prefix,
|
|
|
|
const TQString& fieldSep, const TQString& sep ) const
|
|
|
|
{
|
|
|
|
TQString filter;
|
|
|
|
bool separator = FALSE;
|
|
|
|
for( uint j = 0; j < i.count(); ++j ){
|
|
|
|
if ( rec->isGenerated( j ) ) {
|
|
|
|
if( separator ) {
|
|
|
|
filter += " " + sep + " " ;
|
|
|
|
}
|
|
|
|
TQString fn = i.fieldName( j );
|
|
|
|
TQSqlField* f = rec->field( fn );
|
|
|
|
filter += toString( prefix, f, fieldSep );
|
|
|
|
separator = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return filter;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\overload
|
|
|
|
|
|
|
|
Inserts the current contents of the cursor's edit record buffer
|
|
|
|
into the database, if the cursor allows inserts. Returns the
|
|
|
|
number of rows affected by the insert. For error information, use
|
|
|
|
lastError().
|
|
|
|
|
|
|
|
If \a invalidate is TRUE (the default), the cursor will no longer
|
|
|
|
be positioned on a valid record and can no longer be navigated. A
|
|
|
|
new select() call must be made before navigating to a valid
|
|
|
|
record.
|
|
|
|
|
|
|
|
\quotefile sql/overview/insert2/main.cpp
|
|
|
|
\skipto prices
|
|
|
|
\printline prices
|
|
|
|
\printuntil insert
|
|
|
|
|
|
|
|
In the above example, a cursor is created on the 'prices' table
|
|
|
|
and a pointer to the insert buffer is atquired using primeInsert().
|
|
|
|
Each field's value is set to the desired value and then insert()
|
|
|
|
is called to insert the data into the database. Remember: all edit
|
|
|
|
operations (insert(), update() and delete()) operate on the
|
|
|
|
contents of the cursor edit buffer and not on the contents of the
|
|
|
|
cursor itself.
|
|
|
|
|
|
|
|
\sa setMode() lastError()
|
|
|
|
*/
|
|
|
|
|
|
|
|
int TQSqlCursor::insert( bool invalidate )
|
|
|
|
{
|
|
|
|
if ( ( d->md & Insert ) != Insert || !driver() )
|
|
|
|
return FALSE;
|
|
|
|
int k = d->editBuffer.count();
|
|
|
|
if ( k == 0 )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
TQString fList;
|
|
|
|
TQString vList;
|
|
|
|
bool comma = FALSE;
|
|
|
|
// use a prepared query if the driver supports it
|
|
|
|
if ( driver()->hasFeature( TQSqlDriver::PreparedQueries ) ) {
|
|
|
|
int cnt = 0;
|
|
|
|
bool oraStyle = driver()->hasFeature( TQSqlDriver::NamedPlaceholders );
|
|
|
|
for( int j = 0; j < k; ++j ) {
|
|
|
|
TQSqlField* f = d->editBuffer.field( j );
|
|
|
|
if ( d->editBuffer.isGenerated( j ) ) {
|
|
|
|
if ( comma ) {
|
|
|
|
fList += ",";
|
|
|
|
vList += ",";
|
|
|
|
}
|
|
|
|
fList += f->name();
|
|
|
|
vList += (oraStyle == TRUE) ? ":f" + TQString::number(cnt) : TQString("?");
|
|
|
|
cnt++;
|
|
|
|
comma = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !comma ) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
TQString str;
|
|
|
|
str.append( "insert into " ).append( name() ).append( "(" ).append( fList ).append( ") values (" ).append( vList ). append ( ")" );
|
|
|
|
return applyPrepared( str, invalidate );
|
|
|
|
} else {
|
|
|
|
for( int j = 0; j < k; ++j ) {
|
|
|
|
TQSqlField* f = d->editBuffer.field( j );
|
|
|
|
if ( d->editBuffer.isGenerated( j ) ) {
|
|
|
|
if ( comma ) {
|
|
|
|
fList += ",";
|
|
|
|
vList += ",";
|
|
|
|
}
|
|
|
|
fList += f->name();
|
|
|
|
vList += driver()->formatValue( f );
|
|
|
|
comma = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !comma ) {
|
|
|
|
// no valid fields found
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
TQString str;
|
|
|
|
str.append( "insert into " ).append( name() ).append( "(" ).append( fList ).append( ") values (" ).append( vList ). append ( ")" );
|
|
|
|
return apply( str, invalidate );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns the current internal edit buffer. If \a copy is TRUE (the
|
|
|
|
default is FALSE), the current cursor field values are first
|
|
|
|
copied into the edit buffer. The edit buffer is valid as long as
|
|
|
|
the cursor remains valid. The cursor retains ownership of the
|
|
|
|
returned pointer, so it must not be deleted or modified.
|
|
|
|
|
|
|
|
\sa primeInsert(), primeUpdate() primeDelete()
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQSqlRecord* TQSqlCursor::editBuffer( bool copy )
|
|
|
|
{
|
|
|
|
if ( copy ) {
|
|
|
|
for(uint i = 0; i < d->editBuffer.count(); i++) {
|
|
|
|
if ( TQSqlRecord::isNull( i ) ) {
|
|
|
|
d->editBuffer.setNull( i );
|
|
|
|
} else {
|
|
|
|
d->editBuffer.setValue( i, value( i ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return &d->editBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
This function primes the edit buffer's field values for update and
|
|
|
|
returns the edit buffer. The default implementation copies the
|
|
|
|
field values from the current cursor record into the edit buffer
|
|
|
|
(therefore, this function is equivalent to calling editBuffer(
|
|
|
|
TRUE ) ). The cursor retains ownership of the returned pointer, so
|
|
|
|
it must not be deleted or modified.
|
|
|
|
|
|
|
|
\sa editBuffer() update()
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQSqlRecord* TQSqlCursor::primeUpdate()
|
|
|
|
{
|
|
|
|
// memorize the primary keys as they were before the user changed the values in editBuffer
|
|
|
|
TQSqlRecord* buf = editBuffer( TRUE );
|
|
|
|
TQSqlIndex idx = primaryIndex( FALSE );
|
|
|
|
if ( !idx.isEmpty() )
|
|
|
|
d->editIndex = toString( idx, buf, d->nm, "=", "and" );
|
|
|
|
else
|
|
|
|
d->editIndex = qWhereClause( buf, d->nm, "and", driver() );
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
This function primes the edit buffer's field values for delete and
|
|
|
|
returns the edit buffer. The default implementation copies the
|
|
|
|
field values from the current cursor record into the edit buffer
|
|
|
|
(therefore, this function is equivalent to calling editBuffer(
|
|
|
|
TRUE ) ). The cursor retains ownership of the returned pointer, so
|
|
|
|
it must not be deleted or modified.
|
|
|
|
|
|
|
|
\sa editBuffer() del()
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQSqlRecord* TQSqlCursor::primeDelete()
|
|
|
|
{
|
|
|
|
return editBuffer( TRUE );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
This function primes the edit buffer's field values for insert and
|
|
|
|
returns the edit buffer. The default implementation clears all
|
|
|
|
field values in the edit buffer. The cursor retains ownership of
|
|
|
|
the returned pointer, so it must not be deleted or modified.
|
|
|
|
|
|
|
|
\sa editBuffer() insert()
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQSqlRecord* TQSqlCursor::primeInsert()
|
|
|
|
{
|
|
|
|
d->editBuffer.clearValues();
|
|
|
|
return &d->editBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Updates the database with the current contents of the edit buffer.
|
|
|
|
Returns the number of records which were updated.
|
|
|
|
For error information, use lastError().
|
|
|
|
|
|
|
|
Only records which meet the filter criteria specified by the
|
|
|
|
cursor's primary index are updated. If the cursor does not contain
|
|
|
|
a primary index, no update is performed and 0 is returned.
|
|
|
|
|
|
|
|
If \a invalidate is TRUE (the default), the current cursor can no
|
|
|
|
longer be navigated. A new select() call must be made before you
|
|
|
|
can move to a valid record. For example:
|
|
|
|
|
|
|
|
\quotefile sql/overview/update/main.cpp
|
|
|
|
\skipto prices
|
|
|
|
\printline prices
|
|
|
|
\printuntil update
|
|
|
|
\printline
|
|
|
|
|
|
|
|
In the above example, a cursor is created on the 'prices' table
|
|
|
|
and is positioned on the record to be updated. Then a pointer to
|
|
|
|
the cursor's edit buffer is actquired using primeUpdate(). A new
|
|
|
|
value is calculated and placed into the edit buffer with the
|
|
|
|
setValue() call. Finally, an update() call is made on the cursor
|
|
|
|
which uses the tables's primary index to update the record in the
|
|
|
|
database with the contents of the cursor's edit buffer. Remember:
|
|
|
|
all edit operations (insert(), update() and delete()) operate on
|
|
|
|
the contents of the cursor edit buffer and not on the contents of
|
|
|
|
the cursor itself.
|
|
|
|
|
|
|
|
Note that if the primary index does not uniquely distinguish
|
|
|
|
records the database may be changed into an inconsistent state.
|
|
|
|
|
|
|
|
\sa setMode() lastError()
|
|
|
|
*/
|
|
|
|
|
|
|
|
int TQSqlCursor::update( bool invalidate )
|
|
|
|
{
|
|
|
|
if ( d->editIndex.isEmpty() )
|
|
|
|
return 0;
|
|
|
|
return update( d->editIndex, invalidate );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\overload
|
|
|
|
|
|
|
|
Updates the database with the current contents of the cursor edit
|
|
|
|
buffer using the specified \a filter. Returns the number of
|
|
|
|
records which were updated.
|
|
|
|
For error information, use lastError().
|
|
|
|
|
|
|
|
Only records which meet the filter criteria are updated, otherwise
|
|
|
|
all records in the table are updated.
|
|
|
|
|
|
|
|
If \a invalidate is TRUE (the default), the cursor can no longer
|
|
|
|
be navigated. A new select() call must be made before you can move
|
|
|
|
to a valid record.
|
|
|
|
|
|
|
|
\sa primeUpdate() setMode() lastError()
|
|
|
|
*/
|
|
|
|
|
|
|
|
int TQSqlCursor::update( const TQString & filter, bool invalidate )
|
|
|
|
{
|
|
|
|
if ( ( d->md & Update ) != Update ) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
int k = count();
|
|
|
|
if ( k == 0 ) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// use a prepared query if the driver supports it
|
|
|
|
if ( driver()->hasFeature( TQSqlDriver::PreparedQueries ) ) {
|
|
|
|
TQString fList;
|
|
|
|
bool comma = FALSE;
|
|
|
|
int cnt = 0;
|
|
|
|
bool oraStyle = driver()->hasFeature( TQSqlDriver::NamedPlaceholders );
|
|
|
|
for( int j = 0; j < k; ++j ) {
|
|
|
|
TQSqlField* f = d->editBuffer.field( j );
|
|
|
|
if ( d->editBuffer.isGenerated( j ) ) {
|
|
|
|
if ( comma ) {
|
|
|
|
fList += ",";
|
|
|
|
}
|
|
|
|
fList += f->name() + " = " + (oraStyle == TRUE ? ":f" + TQString::number(cnt) : TQString("?"));
|
|
|
|
cnt++;
|
|
|
|
comma = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !comma ) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
TQString str = "update " + name() + " set " + fList;
|
|
|
|
if ( filter.length() ) {
|
|
|
|
str+= " where " + filter;
|
|
|
|
}
|
|
|
|
return applyPrepared( str, invalidate );
|
|
|
|
} else {
|
|
|
|
TQString str = "update " + name();
|
|
|
|
str += " set " + toString( &d->editBuffer, TQString::null, "=", "," );
|
|
|
|
if ( filter.length() ) {
|
|
|
|
str+= " where " + filter;
|
|
|
|
}
|
|
|
|
return apply( str, invalidate );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Deletes a record from the database using the cursor's primary
|
|
|
|
index and the contents of the cursor edit buffer. Returns the
|
|
|
|
number of records which were deleted.
|
|
|
|
For error information, use lastError().
|
|
|
|
|
|
|
|
Only records which meet the filter criteria specified by the
|
|
|
|
cursor's primary index are deleted. If the cursor does not contain
|
|
|
|
a primary index, no delete is performed and 0 is returned. If \a
|
|
|
|
invalidate is TRUE (the default), the current cursor can no longer
|
|
|
|
be navigated. A new select() call must be made before you can move
|
|
|
|
to a valid record. For example:
|
|
|
|
|
|
|
|
\quotefile sql/overview/delete/main.cpp
|
|
|
|
\skipto prices
|
|
|
|
\printline prices
|
|
|
|
\printuntil }
|
|
|
|
|
|
|
|
In the above example, a cursor is created on the 'prices' table
|
|
|
|
and positioned to the record to be deleted. First primeDelete() is
|
|
|
|
called to populate the edit buffer with the current cursor values,
|
|
|
|
e.g. with an id of 999, and then del() is called to actually
|
|
|
|
delete the record from the database. Remember: all edit operations
|
|
|
|
(insert(), update() and delete()) operate on the contents of the
|
|
|
|
cursor edit buffer and not on the contents of the cursor itself.
|
|
|
|
|
|
|
|
\sa primeDelete() setMode() lastError()
|
|
|
|
*/
|
|
|
|
|
|
|
|
int TQSqlCursor::del( bool invalidate )
|
|
|
|
{
|
|
|
|
TQSqlIndex idx = primaryIndex( FALSE );
|
|
|
|
if ( idx.isEmpty() )
|
|
|
|
return del( qWhereClause( &d->editBuffer, d->nm, "and", driver() ), invalidate );
|
|
|
|
else
|
|
|
|
return del( toString( primaryIndex(), &d->editBuffer, d->nm,
|
|
|
|
"=", "and" ), invalidate );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\overload
|
|
|
|
|
|
|
|
Deletes the current cursor record from the database using the
|
|
|
|
filter \a filter. Only records which meet the filter criteria are
|
|
|
|
deleted. Returns the number of records which were deleted. If \a
|
|
|
|
invalidate is TRUE (the default), the current cursor can no longer
|
|
|
|
be navigated. A new select() call must be made before you can move
|
|
|
|
to a valid record. For error information, use lastError().
|
|
|
|
|
|
|
|
The \a filter is an SQL \c WHERE clause, e.g. \c{id=500}.
|
|
|
|
|
|
|
|
\sa setMode() lastError()
|
|
|
|
*/
|
|
|
|
|
|
|
|
int TQSqlCursor::del( const TQString & filter, bool invalidate )
|
|
|
|
{
|
|
|
|
if ( ( d->md & Delete ) != Delete )
|
|
|
|
return 0;
|
|
|
|
int k = count();
|
|
|
|
if( k == 0 ) return 0;
|
|
|
|
TQString str = "delete from " + name();
|
|
|
|
if ( filter.length() )
|
|
|
|
str+= " where " + filter;
|
|
|
|
return apply( str, invalidate );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
\internal
|
|
|
|
*/
|
|
|
|
|
|
|
|
int TQSqlCursor::apply( const TQString& q, bool invalidate )
|
|
|
|
{
|
|
|
|
int ar = 0;
|
|
|
|
if ( invalidate ) {
|
|
|
|
if ( exec( q ) )
|
|
|
|
ar = numRowsAffected();
|
|
|
|
} else if ( driver() ) {
|
|
|
|
TQSqlQuery* sql = d->query();
|
|
|
|
if ( sql && sql->exec( q ) )
|
|
|
|
ar = sql->numRowsAffected();
|
|
|
|
}
|
|
|
|
return ar;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
\internal
|
|
|
|
*/
|
|
|
|
|
|
|
|
int TQSqlCursor::applyPrepared( const TQString& q, bool invalidate )
|
|
|
|
{
|
|
|
|
int ar = 0;
|
|
|
|
TQSqlQuery* sql = 0;
|
|
|
|
|
|
|
|
if ( invalidate ) {
|
|
|
|
sql = (TQSqlQuery*)this;
|
|
|
|
d->lastAt = TQSql::BeforeFirst;
|
|
|
|
} else {
|
|
|
|
sql = d->query();
|
|
|
|
}
|
|
|
|
if ( !sql )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if ( invalidate || sql->lastQuery() != q ) {
|
|
|
|
if ( !sql->prepare( q ) )
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cnt = 0;
|
|
|
|
int fieldCount = (int)count();
|
|
|
|
for ( int j = 0; j < fieldCount; ++j ) {
|
|
|
|
const TQSqlField* f = d->editBuffer.field( j );
|
|
|
|
if ( d->editBuffer.isGenerated( j ) ) {
|
|
|
|
sql->bindValue( cnt, f->value() );
|
|
|
|
cnt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( sql->exec() ) {
|
|
|
|
ar = sql->numRowsAffected();
|
|
|
|
}
|
|
|
|
return ar;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \reimp
|
|
|
|
|
|
|
|
Executes the SQL query \a sql. Returns TRUE of the cursor is
|
|
|
|
active, otherwise returns FALSE.
|
|
|
|
|
|
|
|
*/
|
|
|
|
bool TQSqlCursor::exec( const TQString & sql )
|
|
|
|
{
|
|
|
|
d->lastAt = TQSql::BeforeFirst;
|
|
|
|
TQSqlQuery::exec( sql );
|
|
|
|
return isActive();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Protected virtual function which is called whenever a field needs
|
|
|
|
to be calculated. If calculated fields are being used, derived
|
|
|
|
classes must reimplement this function and return the appropriate
|
|
|
|
value for field \a name. The default implementation returns an
|
|
|
|
invalid TQVariant.
|
|
|
|
|
|
|
|
\sa setCalculated()
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQVariant TQSqlCursor::calculateField( const TQString& )
|
|
|
|
{
|
|
|
|
return TQVariant();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \internal
|
|
|
|
Ensure fieldlist is synced with query.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
static TQString qTrim( const TQString& s )
|
|
|
|
{
|
|
|
|
TQString result = s;
|
|
|
|
int end = result.length() - 1;
|
|
|
|
while ( end >= 0 && result[end].isSpace() ) // skip white space from end
|
|
|
|
end--;
|
|
|
|
result.truncate( end + 1 );
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \internal
|
|
|
|
*/
|
|
|
|
|
|
|
|
void TQSqlCursor::sync()
|
|
|
|
{
|
|
|
|
if ( isActive() && isValid() && d->lastAt != at() ) {
|
|
|
|
d->lastAt = at();
|
|
|
|
uint i = 0;
|
|
|
|
uint j = 0;
|
|
|
|
bool haveCalculatedFields = FALSE;
|
|
|
|
for ( ; i < count(); ++i ) {
|
|
|
|
if ( !haveCalculatedFields && d->infoBuffer[i].isCalculated() ) {
|
|
|
|
haveCalculatedFields = TRUE;
|
|
|
|
}
|
|
|
|
if ( TQSqlRecord::isGenerated( i ) ) {
|
|
|
|
TQVariant v = TQSqlQuery::value( j );
|
|
|
|
if ( ( v.type() == TQVariant::String || v.type() == TQVariant::CString ) &&
|
|
|
|
d->infoBuffer[ i ].isTrim() ) {
|
|
|
|
v = qTrim( v.toString() );
|
|
|
|
}
|
|
|
|
TQSqlRecord::setValue( i, v );
|
|
|
|
if ( TQSqlQuery::isNull( j ) )
|
|
|
|
TQSqlRecord::field( i )->setNull();
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( haveCalculatedFields ) {
|
|
|
|
for ( i = 0; i < count(); ++i ) {
|
|
|
|
if ( d->infoBuffer[i].isCalculated() )
|
|
|
|
TQSqlRecord::setValue( i, calculateField( fieldName( i ) ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \reimp
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
void TQSqlCursor::afterSeek()
|
|
|
|
{
|
|
|
|
sync();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\reimp
|
|
|
|
|
|
|
|
Returns the value of field number \a i.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQVariant TQSqlCursor::value( int i ) const
|
|
|
|
{
|
|
|
|
return TQSqlRecord::value( i );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\reimp
|
|
|
|
|
|
|
|
Returns the value of the field called \a name.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TQVariant TQSqlCursor::value( const TQString& name ) const
|
|
|
|
{
|
|
|
|
return TQSqlRecord::value( name );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \internal
|
|
|
|
cursors should be filled with TQSqlFieldInfos...
|
|
|
|
*/
|
|
|
|
void TQSqlCursor::append( const TQSqlField& field )
|
|
|
|
{
|
|
|
|
append( TQSqlFieldInfo( field ) );
|
|
|
|
}
|
|
|
|
/*! \internal
|
|
|
|
cursors should be filled with TQSqlFieldInfos...
|
|
|
|
*/
|
|
|
|
void TQSqlCursor::insert( int pos, const TQSqlField& field )
|
|
|
|
{
|
|
|
|
insert( pos, TQSqlFieldInfo( field ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns TRUE if the field \a i is NULL or if there is no field at
|
|
|
|
position \a i; otherwise returns FALSE.
|
|
|
|
|
|
|
|
This is the same as calling TQSqlRecord::isNull( \a i )
|
|
|
|
*/
|
|
|
|
bool TQSqlCursor::isNull( int i ) const
|
|
|
|
{
|
|
|
|
return TQSqlRecord::isNull( i );
|
|
|
|
}
|
|
|
|
/*!
|
|
|
|
\overload
|
|
|
|
|
|
|
|
Returns TRUE if the field called \a name is NULL or if there is no
|
|
|
|
field called \a name; otherwise returns FALSE.
|
|
|
|
|
|
|
|
This is the same as calling TQSqlRecord::isNull( \a name )
|
|
|
|
*/
|
|
|
|
bool TQSqlCursor::isNull( const TQString& name ) const
|
|
|
|
{
|
|
|
|
return TQSqlRecord::isNull( name );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \reimp */
|
|
|
|
void TQSqlCursor::setValue( int i, const TQVariant& val )
|
|
|
|
{
|
|
|
|
#ifdef QT_DEBUG
|
|
|
|
qDebug("TQSqlCursor::setValue(): This will not affect actual database values. Use primeInsert(), primeUpdate() or primeDelete().");
|
|
|
|
#endif
|
|
|
|
TQSqlRecord::setValue( i, val );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \reimp */
|
|
|
|
void TQSqlCursor::setValue( const TQString& name, const TQVariant& val )
|
|
|
|
{
|
|
|
|
#ifdef QT_DEBUG
|
|
|
|
qDebug("TQSqlCursor::setValue(): This will not affect actual database values. Use primeInsert(), primeUpdate() or primeDelete().");
|
|
|
|
#endif
|
|
|
|
TQSqlRecord::setValue( name, val );
|
|
|
|
}
|
|
|
|
#endif
|