epoc32/include/sqldb.h
author William Roberts <williamr@symbian.org>
Tue, 16 Mar 2010 16:12:26 +0000
branchSymbian2
changeset 2 2fe1408b6811
parent 0 061f57f2323e
child 4 837f303aceeb
permissions -rw-r--r--
Final list of Symbian^2 public API header files

// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Symbian Foundation License v1.0" to Symbian Foundation members and "Symbian Foundation End User License Agreement v1.0" to non-members
// which accompanies this distribution, and is available
// at the URL "http://www.symbianfoundation.org/legal/licencesv10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// SQL Client side API header
// 
//



/**
 @file
 @publishedAll
 @released
*/
#ifndef __SQLDB_H__
#define __SQLDB_H__

#ifndef __S32STD_H__
#include <s32std.h>	//RReadStream, RWriteStream
#endif

//Forward declarations
class CSqlSecurityPolicy;
class RSqlDatabase;
class CSqlDatabaseImpl;
class RSqlStatement;
class CSqlStatementImpl;
class RSqlColumnReadStream;
class RSqlParamWriteStream;
class TSqlScalarFullSelectQuery;

/**
A container for the security policies for a shared SQL database.

The container can contain:
- security policies that apply to the database.
- security policies that apply to individual database objects, i.e. database tables.

For the database, you use RSqlSecurityPolicy::SetDbPolicy() to apply a separate
security policy to:
- the database schema.
- read activity on the database.
- write activity on the database.

For database tables, you use RSqlSecurityPolicy::SetPolicy() to apply a separate
security policy to:
- write activity on each named database table.
- read activity on each named database table.

A client uses a RSqlSecurityPolicy object to create a secure database. It does this by:
- creating a RSqlSecurityPolicy object.
- setting all the appropriate security policies into it.
- passing the object as an argument to RSqlDatabase::Create().
- closing the RSqlSecurityPolicy object on return from RSqlDatabase::Create().

Once a secure shared database has been created with specific security policies,
these policies are made persistent and cannot be changed during the life of
that database.

Security policies are encapsulated by TSecurityPolicy objects.
The general usage pattern is to create the security policies container object
(RSqlSecurityPolicy) using a default security policy (TSecurityPolicy), and then
to assign more specific 'overriding' security policies.

The following code fragment shows how you do this:
   
@code
TSecurityPolicy defaultPolicy;
RSqlSecurityPolicy securityPolicy;
RSqlDatabase database;
TInt err;

// Create security policies container object using a default security policy.
securityPolicy.Create(defaultPolicy); 

// Set up policy to apply to database schema
// and assign it
TSecurityPolicy schemaPolicy;
...
err = securityPolicy.SetDbPolicy(RSqlSecurityPolicy::ESchemaPolicy, schemaPolicy);

// Set up policy to apply to write activity on the database
// and assign it
TSecurityPolicy writePolicy;
...
err = securityPolicy.SetDbPolicy(RSqlSecurityPolicy::EWritePolicy, writePolicy);

// Set up policy to apply to write activity to the database table named "Table1"
// and assign it
TSecurityPolicy tablePolicy1;
...
err = securityPolicy.SetPolicy(RSqlSecurityPolicy::ETable, _L("Table1"), RSqlSecurityPolicy::EWritePolicy, tablePolicy1);

// Set up policy to apply to read activity to the database table named "Table2"
TSecurityPolicy tablePolicy2;
err = securityPolicy.SetPolicy(RSqlSecurityPolicy::ETable, _L("Table2"), RSqlSecurityPolicy::EReadPolicy, tablePolicy2);

// Create the database, passing the security policies
err = database.Create(KDatabaseName, securityPolicy);

// We can close the RSqlSecurityPolicy object.
securityPolicy.Close();
@endcode

Note that in this example code fragment, the client has not assigned specific
overriding policies for all possible cases; for example, no overriding policy
has been assigned to control read activity on the database, read activity
on "Table1", nor write activity on "Table2".
For these cases, the default security policy will apply.

A client can also retrieve a database's security policies by calling
RSqlDatabase::GetSecurityPolicy(); this returns a RSqlSecurityPolicy object
containing the security policies. Note that it is the client's responsibility
to close the RSqlSecurityPolicy object when the client no longer needs it. The
following code fragment suggests how you might do this:

@code
RSqlDatabase database;
RSqlSecurityPolicy securityPolicy;

// Retrieve the security policies; on return from the call to 
// GetSecurityPolicy(), the RSqlSecurityPolicy object passed 
// to this function will contain the security policies.
database.GetSecurityPolicy(securityPolicy);
...
// This is the security policy that applies to database schema
TSecurityPolicy schemaPolicy = securityPolicy.DbPolicy(RSqlSecurityPolicy::ESchemaPolicy);
...
// This is the security policy that applies to write activity to the database
// table named "Table1".
TSecurityPolicy writePolicy = securityPolicy.Policy(RSqlSecurityPolicy::ETable, _L("Table1"), RSqlSecurityPolicy::EWritePolicy);
...
// Close the RSqlSecurityPolicy object when no longer needed.
securityPolicy.Close();
@endcode

Note that in the cases where an 'overriding' security policy was not originally assigned,
then the security policy returned will simply be the default security policy.

@see TSecurityPolicy
@see RSqlDatabase
@see RSqlSecurityPolicy::SetDbPolicy()
@see RSqlSecurityPolicy::SetPolicy()

@publishedAll
@released
*/
class RSqlSecurityPolicy
	{
	friend class RSqlDatabase;
	
public:
	/**
	Defines a set of values that represents the database security policy types.
	Each database security policy type refers to a set of capabilities encapsulated in 
	a TSecurityPolicy object. The TSecurityPolicy object defines what capabilities the calling
	application must have in order to perform partiqular database operation.
	@see TSecurityPolicy
	*/
	enum TPolicyType 
		{
		/**
		Schema database security policy. An application with schema database security policy can 
		modify the database schema, write to database, read from database.
		*/
		ESchemaPolicy, 
		/**
		Read database security policy. An application with read database security policy can 
		read from database.
		*/
		EReadPolicy, 
		/**
		Write database security policy. An application with write database security policy can 
		write to database.
		*/
		EWritePolicy
		};
	/**
	Not currently supported.

	Defines a set of values that represents the database objects which can be protected by 
	database security policy types.
	*/
	enum TObjectType 
		{
		ETable
		};
	IMPORT_C RSqlSecurityPolicy();
	IMPORT_C TInt Create(const TSecurityPolicy& aDefaultPolicy);
	IMPORT_C void CreateL(const TSecurityPolicy& aDefaultPolicy);
	IMPORT_C void Close();
	IMPORT_C TInt SetDbPolicy(TPolicyType aPolicyType, const TSecurityPolicy& aPolicy);
	IMPORT_C TInt SetPolicy(TObjectType aObjectType, const TDesC& aObjectName, TPolicyType aPolicyType, const TSecurityPolicy& aPolicy);
	IMPORT_C TSecurityPolicy DefaultPolicy() const;
	IMPORT_C TSecurityPolicy DbPolicy(TPolicyType aPolicyType) const;
	IMPORT_C TSecurityPolicy Policy(TObjectType aObjectType, const TDesC& aObjectName, TPolicyType aPolicyType) const;
	
	IMPORT_C void ExternalizeL(RWriteStream& aStream) const;
	IMPORT_C void InternalizeL(RReadStream& aStream);
		
private:	
	void Set(CSqlSecurityPolicy& aImpl);
	CSqlSecurityPolicy& Impl() const;
					
private:
	CSqlSecurityPolicy* iImpl;
	};
	
/**
A handle to a SQL database.

A RSqlDatabase object is, in effect, a handle to the SQL database. A client can:
- create a SQL database by calling RSqlDatabase::Create().
- open an existing SQL database by calling RSqlDatabase::Open().
- close a SQL database by calling RSqlDatabase::Close().
- copy a SQL database by calling RSqlDatabase::Copy().
- delete a SQL database by calling RSqlDatabase::Delete().
- attach a SQL database to current database connection by calling RSqlDatabase::Attach().
- detach a SQL database from current database connection by calling RSqlDatabase::Detach().

A client can create either a non-secure database or a secure database,
depending on the variant of RSqlDatabase::Create() that is used.
- a non-secure database is created if the RSqlDatabase::Create(const TDesC&) variant is used.
- a secure database is created if the RSqlDatabase::Create(const TDesC&, const RSqlSecurityPolicy&)
variant is used. In this case, a container containing a collection of security
policies needs to be set up first and passed to this Create() function.
See references to RSqlSecurityPolicy for more information on security policies.

A client can also specify how it wants a transaction to interact with
other transactions that may be running concurrently. The various ways in which
transactions can interact (i.e. how one transaction can affect another) are
referred to as "transaction isolation levels", and are defined by the values
of the TIsolationLevel enum. A client specifies this by calling RSqlDatabase::SetIsolationLevel().

Each of the various flavours of Open and Create allows the optional provision of a
configuration string. It is acceptable for this string to be missing.
In the case where the string is missing, the config in the SqlServer.sql file
will be used. If that does not exist then the MMH macro definitions will be used.

The config string is in the format PARAM=VALUE; PARAM=VALUE;...

Allowed parameters are:
	cache_size=nnnn
	page_size=nnnn
	encoding=UTF8|UTF16

Badly formed config strings are reported as KErrArgument

The string may not exceed 255 characters.

Please note that a database can only be accessed within the thread where it has been created. It is then not possible
to create a database from thread1 and access it from thread2.

A client calls RSqlDatabase::Exec() to execute SQL statements.
@see RSqlDatabase::Create()
@see RSqlDatabase::Open()
@see RSqlDatabase::Close()
@see RSqlDatabase::Copy()
@see RSqlDatabase::Delete()
@see RSqlDatabase::Attach()
@see RSqlDatabase::Detach()
@see RSqlDatabase::SetIsolationLevel()
@see RSqlDatabase::Exec()
@see TIsolationLevel
@see RSqlSecurityPolicy

@publishedAll
@released
*/
class RSqlDatabase
	{
	friend class RSqlStatement;
	friend class TSqlScalarFullSelectQuery;
	
public:
	/**
	Defines a set of values that represents the transaction isolation level.
	
	A transaction isolation level defines the way in which a transaction
	interacts with other transactions that may be in progress concurrently.
	
	A client sets the transaction isolation level by calling SetIsolationLevel()
	
	@see RSqlDatabase::SetIsolationLevel()
	*/
	enum TIsolationLevel 
		{
		/**
		A transaction can read uncommitted data, i.e. data that is being changed
		by another transaction, which is still in progress.
		
		This means that
		- a 'database read' transaction will not block 'database write' transactions
		being performed by different database connections on the same shared database.
		- a 'database read' transaction will not be blocked by 'database write'
		transactions performed by the same database connection.
		- concurrent 'database write' transactions are prevented.
		
		This transaction isolation level can be set at any time during
		the lifetime of the database.
		
		@see TIsolationLevel
		@see RSqlDatabase::SetIsolationLevel()
		*/
		EReadUncommitted, 

		/**
		Not currently supported.
		
		A transaction cannot read uncommitted data. "Dirty reads" are prevented.
		
		"Dirty read" is a data inconsistency type which can be described with the following example:
		- Transaction A updates TableA.Column1 value from 1 to 2;
		- Transaction B reads TableA.Column1 value;
		- Transaction A rolls back and restores the original value of TableA.Column1 (1);
		- Transaction B ends showing that TableA.Column1 value is 2, even though, logically and transactionally, 
		  this data never really even existed in the database because Transaction A never committed that change 
		  to the database;
		
		@see TIsolationLevel
		@see RSqlDatabase::SetIsolationLevel()
		*/
		EReadCommitted, 
		
		/**
		Not currently supported.
		
		A transaction cannot change data that is being read by a different transaction. 
		"Dirty reads" and "non-repeatable reads" are prevented.

		"Non-repeatable reads" is a data inconsistency type which can be described with the following example:
		- Transaction A reads TableA.Column1 value which is 1;
		- Transaction B updates TableA.Column1 value from 1 to 2;
		- Transaction B commits the chages;
		- Transaction A reads TableA.Column1 value again. Transaction A has inconsistent data because TableA.Column1 
		  value now is 2 instead of 1, all within the scope of the same Transaction A;
		
		@see TIsolationLevel
		@see RSqlDatabase::SetIsolationLevel()
		*/
		ERepeatableRead, 
		
		/**
		Any number of 'database read' transactions can be performed concurrently
		by different database connections on the same shared database.
		
		Only one 'database write' transaction can be performed at any one time. If a
		'database write' transaction is in progress, then any attempt to start
		another 'database read' or 'database write' transaction will be blocked
		until the first 'database write' transaction has completed.
		
		This is the default isolation level, if no isolation level is
		explicitly set.
		
		"Dirty reads", "non-repeatable" reads and "phantom reads" are prevented.
		
		"Phantom reads" is a data inconsistency type which can be described with the following example:
		- Transaction A reads all rows that have Column1 = 1;
		- Transaction B inserts a new row which has Column1 = 1;
		- Transaction B commits;
		- Transaction A updates all rows that have Column1 = 1. This will also update the row that 
		  Transaction B inserted, because Transaction A must read the data again in order to update it.
		- Transaction A commits;
		
		@see TIsolationLevel
		@see RSqlDatabase::SetIsolationLevel()
		*/
		ESerializable
		};
		
	IMPORT_C RSqlDatabase();
	
	IMPORT_C TInt Create(const TDesC& aDbFileName, const TDesC8* aConfig=NULL);
	IMPORT_C TInt Create(const TDesC& aDbFileName,
			const RSqlSecurityPolicy& aSecurityPolicy, const TDesC8* aConfig=NULL);
	IMPORT_C TInt Open(const TDesC& aDbFileName, const TDesC8* aConfig=NULL);
	IMPORT_C void CreateL(const TDesC& aDbFileName, const TDesC8* aConfig=NULL);
	IMPORT_C void CreateL(const TDesC& aDbFileName,
			const RSqlSecurityPolicy& aSecurityPolicy, const TDesC8* aConfig=NULL);
	IMPORT_C void OpenL(const TDesC& aDbFileName, const TDesC8* aConfig=NULL);
	
	IMPORT_C void Close();
	
	IMPORT_C TInt Attach(const TDesC& aDbFileName, const TDesC& aDbName);
	IMPORT_C TInt Detach(const TDesC& aDbName);
	
	IMPORT_C static TInt Copy(const TDesC& aSrcDbFileName, const TDesC& aDestDbFileName);
	IMPORT_C static TInt Delete(const TDesC& aDbFileName);
	
	IMPORT_C TInt GetSecurityPolicy(RSqlSecurityPolicy& aSecurityPolicy) const;
	IMPORT_C void GetSecurityPolicyL(RSqlSecurityPolicy& aSecurityPolicy) const;
	
	IMPORT_C TInt SetIsolationLevel(TIsolationLevel aIsolationLevel);
	
	IMPORT_C TInt Exec(const TDesC& aSqlStmt);
	IMPORT_C TInt Exec(const TDesC8& aSqlStmt);
	
	IMPORT_C void Exec(const TDesC& aSqlStmt, TRequestStatus& aStatus);
	IMPORT_C void Exec(const TDesC8& aSqlStmt, TRequestStatus& aStatus);
	
	IMPORT_C TPtrC LastErrorMessage() const;
	
	IMPORT_C TBool InTransaction() const;
	IMPORT_C TInt Size() const;
	
	IMPORT_C TInt ReserveDriveSpace(TInt aSize);
	IMPORT_C void FreeReservedSpace();
	IMPORT_C TInt GetReserveAccess();
	IMPORT_C void ReleaseReserveAccess();
	
private:
	CSqlDatabaseImpl& Impl() const;

private:
	CSqlDatabaseImpl* iImpl;
	};

/**
TSqlScalarFullSelectQuery interface is used for executing SELECT sql queries, which 
return a single row consisting of a single column value.

Examples.

CASE 1 - retrieving records count of a table:
@code
RSqlDatabase db;
//initialize db object....
.......
TSqlScalarFullSelectQuery fullSelectQuery(db);
TInt recCnt = fullSelectQuery.SelectIntL(_L("SELECT COUNT(*) FROM PersonTbl"));
@endcode

CASE 2 - retrieving specific column value using a condition in the SELECT statement:
@code
RSqlDatabase db;
//initialize db object....
.......
TSqlScalarFullSelectQuery fullSelectQuery(db);
TInt personId = fullSelectQuery.SelectIntL(_L("SELECT ID FROM PersonTbl WHERE Name = 'John'"));
@endcode

CASE 3 - retrieving a text column value, the receiving buffer is not big enough:
@code
RSqlDatabase db;
//initialize db object....
.......
TSqlScalarFullSelectQuery fullSelectQuery(db);
HBufC* buf = HBufC::NewLC(20);
TPtr name = buf->Des();
TInt rc = fullSelectQuery.SelectTextL(_L("SELECT Name FROM PersonTbl WHERE Id = 1"), name);
TEST(rc >= 0); //the function may return only non-negative values
if(rc > 0)
	{
	buf = buf->ReAllocL(rc);
	CleanupStack::Pop();	
	CleanupStack::PushL(buf);
	name.Set(buf->Des());
	rc = fullSelectQuery.SelectTextL(_L("SELECT Name FROM PersonTbl WHERE Id = 1"), name);
	TEST(rc == 0);
	}
CleanupStack::PopAndDestroy();//buf
@endcode

@see RSqlDatabase

@publishedAll
@released
*/
class TSqlScalarFullSelectQuery
	{
public:
	IMPORT_C TSqlScalarFullSelectQuery();
	IMPORT_C TSqlScalarFullSelectQuery(RSqlDatabase& aDatabase);
	IMPORT_C void SetDatabase(RSqlDatabase& aDatabase);

	IMPORT_C TInt SelectIntL(const TDesC& aSqlStmt);
	IMPORT_C TInt64 SelectInt64L(const TDesC& aSqlStmt);
	IMPORT_C TReal SelectRealL(const TDesC& aSqlStmt);
	IMPORT_C TInt SelectTextL(const TDesC& aSqlStmt, TDes& aDest);
	IMPORT_C TInt SelectBinaryL(const TDesC& aSqlStmt, TDes8& aDest);

	IMPORT_C TInt SelectIntL(const TDesC8& aSqlStmt);
	IMPORT_C TInt64 SelectInt64L(const TDesC8& aSqlStmt);
	IMPORT_C TReal SelectRealL(const TDesC8& aSqlStmt);
	IMPORT_C TInt SelectTextL(const TDesC8& aSqlStmt, TDes& aDest);
	IMPORT_C TInt SelectBinaryL(const TDesC8& aSqlStmt, TDes8& aDest);
	
private:
	inline CSqlDatabaseImpl& Impl() const;
	
private:	
	CSqlDatabaseImpl* iDatabaseImpl;
	};

/**
An enumeration whose values represent the supported database column types.


@see RSqlStatement::ColumnType()

@publishedAll
@released
*/
enum TSqlColumnType 
	{
	/**
	Null column value.
	*/
	ESqlNull,
	
 	/**
 	32-bit integer column value.
 	*/  
	ESqlInt, 
	
 	/**
 	64-bit integer column value.
 	*/
	ESqlInt64, 
	
	/**
	64-bit floating point column value.
	*/
	ESqlReal, 
	
	/**
	Unicode text, a sequence of 16-bit character codes.
	*/
	ESqlText, 
	
	/**
	Binary data, a sequence of bytes.
	*/
	ESqlBinary 
	};

/**
Represents an SQL statement.

An object of this type can be used to execute all types of SQL statements; this
includes SQL statements with parameters.

If a SELECT statament is passed to RSqlStatement::Prepare(), then the returned record set 
is forward only, non-updateable.

There are a number of ways that this object is used; here are some examples.

CASE 1 - the execution of a SQL statement, which does not return record set:

@code
RSqlDatabase database;
.........
RSqlStatement stmt;
TInt err = stmt.Prepare(database, _L("INSERT INTO Tbl1(Fld1) VALUES(:Val)"));
TInt paramIndex = stmt.ParameterIndex(_L(":Val"));
for(TInt i=1;i<=10;++i)
	{
	err = stmt.BindInt(paramIndex, i);
	err = stmt.Exec();
	err = stmt.Reset();
	}
stmt.Close();
@endcode

The following pseudo code shows the general pattern:

@code
<RSqlStatement::Prepare()>
[begin:]
<RSqlStatement::Bind<param_type>()>
<RSqlStatement::Exec()>
[<RSqlStatement::Reset()>]
[<RSqlStatement::Bind<param_type>()>]
[<Goto :begin>]
@endcode

CASE 2 - the execution of a SQL statement, which returns a record set:

@code
RSqlDatabase database;
.........
RSqlStatement stmt;
TInt err = stmt.Prepare(database, _L("SELECT Fld1 FROM Tbl1 WHERE Fld1 > :Val"));
TInt paramIndex = stmt.ParameterIndex(_L(":Val"));
err = stmt.BindInt(paramIndex, 5);
TInt columnIndex = stmt.ColumnIndex(_L("Fld1"));
while((err = stmt.Next()) == KSqlAtRow)
	{
	TInt val = stmt.ColumnInt(columnIndex);
	RDebug::Print(_L("val=%d\n"), val);
	}
if(err == KSqlAtEnd)
	<OK - no more records>;
else
	<process the error>;
stmt.Close();
@endcode

The following pseudo code shows the general pattern:

@code
<RSqlStatement::Prepare()>
[begin:]
<while (RSqlStatement::Next() == KSqlAtRow)>
	<do something with the records>
if(err == KSqlAtEnd)
	<OK - no more records>;
else
	<process the error>;
[<RSqlStatement::Reset()>]
[<RSqlStatement::Bind<param_type>()>]
[<Goto begin>]
@endcode

CASE 3.1 - SELECT statements: large column data processing, where the data is
copied into a buffer supplied by the client:

@code
RSqlDatabase database;
.........
RSqlStatement stmt;
TInt err = stmt.Prepare(database, _L("SELECT BinaryField FROM Tbl1"));
TInt columnIndex = stmt.ColumnIndex(_L("BinaryField"));
while((err = stmt.Next()) == KSqlAtRow)
	{
	TInt size = stmt. ColumnSize(columnIndex);
	HBufC8* buf = HBufC8::NewL(size);
	err = stmt.ColumnBinary(columnIndex, buf->Ptr());
	<do something with the data>;
	delete buf;
	}
if(err == KSqlAtEnd)
	<OK - no more records>;
else
	<process the error>;
stmt.Close();
@endcode

CASE 3.2 - SELECT statements: large column data processing, where the data is
accessed by the client without copying:

@code
RSqlDatabase database;
.........
RSqlStatement stmt;
TInt err = stmt.Prepare(database, _L("SELECT BinaryField FROM Tbl1"));
TInt columnIndex = stmt.ColumnIndex(_L("BinaryField"));
while((err = stmt.Next()) == KSqlAtRow)
	{
	TPtrC8 data = stmt.ColumnBinaryL(columnIndex);
	<do something with the data>;
	}
if(err == KSqlAtEnd)
	<OK - no more records>;
else
	<process the error>;
stmt.Close();
@endcode

CASE 3.3 - SELECT statements, large column data processing (the data is accessed by 
the client without copying), leaving-safe processing:

@code
RSqlDatabase database;
.........
RSqlStatement stmt;
TInt err = stmt.Prepare(database, _L("SELECT BinaryField FROM Tbl1"));
TInt columnIndex = stmt.ColumnIndex(_L("BinaryField"));
while((err = stmt.Next()) == KSqlAtRow)
	{
	TPtrC8 data;
	TInt err = stmt.ColumnBinary(columnIndex, data);
	if(err == KErrNone)
		{
		<do something with the data>;
		}
	}
if(err == KSqlAtEnd)
	<OK - no more records>;
else
	<process the error>;
stmt.Close();
@endcode

CASE 3.4 - SELECT statements: large column data processing, where the data is
accessed by the client using a stream:

@code
RSqlDatabase database;
.........
RSqlStatement stmt;
TInt err = stmt.Prepare(database, _L("SELECT BinaryField FROM Tbl1"));
TInt columnIndex = stmt.ColumnIndex(_L("BinaryField"));
while((err = stmt.Next()) == KSqlAtRow)
	{
	RSqlColumnReadStream stream;
	err = stream.ColumnBinary(stmt, columnIndex);
	<do something with the data in the stream>;
	stream.Close();
	}
if(err == KSqlAtEnd)
	<OK - no more records>;
else
	<process the error>;
stmt.Close();
@endcode

CASE 4 - the execution of a SQL statement with parameter(s), some of which may
be large text or binary values:

@code
RSqlDatabase database;
.........
RSqlStatement stmt;
TInt err = 
	stmt.Prepare(database, _L("UPDATE Tbl1 SET LargeTextField = :LargeTextVal WHERE IdxField = :KeyVal"));
TInt paramIndex1 = stmt.ParameterIndex(_L(":LargeTextVal"));
TInt paramIndex2 = stmt.ParameterIndex(_L(":KeyVal"));
for(TInt i=1;i<=10;++i)
	{
	RSqlParamWriteStream stream;
	err = stream.BindText(stmt, paramIndex1);
	<insert large text data into the stream>;
	stream.Close();
	err = stmt.BindInt(paramIndex2, i);
	err = stmt.Exec();
	stmt.Reset();
	}
stmt.Close();
@endcode

The following table shows what is returned when the caller uses a specific
column data retrieving function on a specific column type.

@code
--------------------------------------------------------------------------------
Column type | ColumnInt() ColumnInt64() ColumnReal() ColumnText() ColumnBinary()
--------------------------------------------------------------------------------
Null........|.0...........0.............0.0..........KNullDesC....KNullDesC8
Int.........|.Int.........Int64.........Real.........KNullDesC....KNullDesC8 
Int64.......|.clamp.......Int64.........Real.........KNullDesC....KNullDesC8 
Real........|.round.......round.........Real.........KNullDesC....KNullDesC8 
Text........|.0...........0.............0.0..........Text.........KNullDesC8   
Binary......|.0...........0.............0.0..........KNullDesC....Binary
--------------------------------------------------------------------------------
@endcode
Note the following definitions:
- "clamp": return KMinTInt or KMaxTInt if the value is outside the range that can be 
represented by the type returned by the accessor function.
- "round": the floating point value will be rounded up to the nearest integer.
If the result is outside the range that can be represented by the type returned
by the accessor function, then it will be clamped.

@see KMinTInt
@see KMaxTInt
@see KNullDesC
@see KNullDesC8

@publishedAll
@released
*/
class RSqlStatement
	{
	friend class RSqlColumnReadStream;
	friend class RSqlParamWriteStream;

public:
	IMPORT_C RSqlStatement();
	IMPORT_C TInt Prepare(RSqlDatabase& aDatabase, const TDesC& aSqlStmt);
	IMPORT_C TInt Prepare(RSqlDatabase& aDatabase, const TDesC8& aSqlStmt);
	IMPORT_C void PrepareL(RSqlDatabase& aDatabase, const TDesC& aSqlStmt);
	IMPORT_C void PrepareL(RSqlDatabase& aDatabase, const TDesC8& aSqlStmt);
	IMPORT_C void Close();
	IMPORT_C TBool AtRow() const;
	IMPORT_C TInt Reset();
	IMPORT_C TInt Exec();
	IMPORT_C void Exec(TRequestStatus& aStatus);
	IMPORT_C TInt Next();
	
	IMPORT_C TInt ParameterIndex(const TDesC& aParameterName) const;
	IMPORT_C TInt ColumnCount() const;
	IMPORT_C TInt ColumnIndex(const TDesC& aColumnName) const;
	IMPORT_C TSqlColumnType ColumnType(TInt aColumnIndex) const;
	IMPORT_C TInt DeclaredColumnType(TInt aColumnIndex, TSqlColumnType& aColumnType) const;
	IMPORT_C TInt ColumnSize(TInt aColumnIndex) const;
	
	IMPORT_C TInt BindNull(TInt aParameterIndex);
	IMPORT_C TInt BindInt(TInt aParameterIndex, TInt aParameterValue);
	IMPORT_C TInt BindInt64(TInt aParameterIndex, TInt64 aParameterValue);
	IMPORT_C TInt BindReal(TInt aParameterIndex, TReal aParameterValue);
	IMPORT_C TInt BindText(TInt aParameterIndex, const TDesC& aParameterText);
	IMPORT_C TInt BindBinary(TInt aParameterIndex, const TDesC8& aParameterData);
	
	IMPORT_C TBool IsNull(TInt aColumnIndex) const;
	IMPORT_C TInt ColumnInt(TInt aColumnIndex) const;
	IMPORT_C TInt64 ColumnInt64(TInt aColumnIndex) const;
	IMPORT_C TReal ColumnReal(TInt aColumnIndex) const;
	
	IMPORT_C TPtrC ColumnTextL(TInt aColumnIndex) const;
	IMPORT_C TInt ColumnText(TInt aColumnIndex, TPtrC& aPtr) const;
	IMPORT_C TInt ColumnText(TInt aColumnIndex, TDes& aDest) const;
	
	IMPORT_C TPtrC8 ColumnBinaryL(TInt aColumnIndex) const;
	IMPORT_C TInt ColumnBinary(TInt aColumnIndex, TPtrC8& aPtr) const;
	IMPORT_C TInt ColumnBinary(TInt aColumnIndex, TDes8& aDest) const;
	
private:
	CSqlStatementImpl& Impl() const;
	
private:
	CSqlStatementImpl* 	iImpl;
	
	};

/**
The read stream interface.

The class is used for reading the content of a column containing a large
amount of either binary data or text data.

The class derives from RReadStream, which means that all RReadStream public
member functions and predefined stream operators \>\> can be used to deal
with column data.

The following two cases are typical:

CASE 1 - processing large binary column data.

@code
RSqlDatabase db;
<open/create "db" object>;
RSqlStatement stmt;
<prepare "stmt" object>;
TInt rc = stmt.Next();
if(rc == KSqlAtRow)
	{
	RSqlColumnReadStream colStream;
	CleanupClosePushL(colStream);
	User::LeaveIfError(colStream.ColumnBinary(stmt, <column_number>));
	TInt size = stmt.ColumnSize(<column_number>);
	//read the column data in a buffer ("buf" variable).
	//(or the column data can be retrieved in a smaller portions)
	colStream.ReadL(buf, size);
	//Close the stream
	CleanupStack::PopAndDestroy(&colStream);
	}
else
	{
	...
	}
@endcode

CASE 2 - processing large text column data.

@code
RSqlDatabase db;
<open/create "db" object>;
RSqlStatement stmt;
<prepare "stmt" object>;
TInt rc = stmt.Next();
if(rc == KSqlAtRow)
	{
	RSqlColumnReadStream colStream;
	CleanupClosePushL(colStream);
	User::LeaveIfError(colStream.ColumnText(stmt, <column_number>));
	TInt size = stmt.ColumnSize(<column_number>);
	//read the column data in a buffer ("buf" variable).
	//(or the column data can be retrieved in a smaller portions)
	colStream.ReadL(buf, size);
	//Close the stream
	CleanupStack::PopAndDestroy(&colStream);
	}
else
	{
	...
	}
@endcode

@publishedAll
@released
*/
class RSqlColumnReadStream : public RReadStream
	{
public:	
	IMPORT_C TInt ColumnText(RSqlStatement& aStmt, TInt aColumnIndex);
	IMPORT_C TInt ColumnBinary(RSqlStatement& aStmt, TInt aColumnIndex);
	IMPORT_C void ColumnTextL(RSqlStatement& aStmt, TInt aColumnIndex);
	IMPORT_C void ColumnBinaryL(RSqlStatement& aStmt, TInt aColumnIndex);

	};

/**
The write stream interface.

The class is used to set a large amount of either binary data or text data
into a parameter. This is a also known as binding a parameter.

The class derives from RWriteStream, which means that all RWriteStream public
member functions and predefined stream operators \<\< can be used to deal with
the parameter data.

The following two cases are typical:

CASE 1 - binding a large binary parameter.

@code
RSqlDatabase db;
<open/create "db" object>;
RSqlStatement stmt;
<prepare "stmt" object>;//The SQL statement references large binary parameter
RSqlParamWriteStream paramStream;
CleanupClosePushL(paramStream);
User::LeaveIfError(paramStream.BindBinary(stmt, <parameter_number>));
//Write out the parameter data
paramStream.WriteL(..);
paramStream << <data>;
...
//Commit the stream
paramStream.CommitL();
//Continue with the statement processing issuing Next() or Exec().
TInt rc = stmt.Next();//rc = stmt.Exec()
//Close the stream
CleanupStack::PopAndDestroy(&paramStream);
@endcode

CASE 2 - binding a large text parameter.

@code
RSqlDatabase db;
<open/create "db" object>;
RSqlStatement stmt;
<prepare "stmt" object>;//The SQL statement references large text parameter
RSqlParamWriteStream paramStream;
CleanupClosePushL(paramStream);
User::LeaveIfError(paramStream.BindText(stmt, <parameter_number>));
//Write out the parameter data
paramStream.WriteL(..);
paramStream << <data>;
...
//Commit the stream
paramStream.CommitL();
//Continue with the statement processing issuing Next() or Exec().
TInt rc = stmt.Next();//rc = stmt.Exec()
//Close the stream
CleanupStack::PopAndDestroy(&paramStream);
@endcode

@publishedAll
@released
*/
class RSqlParamWriteStream : public RWriteStream
	{
public:	
	IMPORT_C TInt BindText(RSqlStatement& aStmt, TInt aParameterIndex);
	IMPORT_C TInt BindBinary(RSqlStatement& aStmt, TInt aParameterIndex);
	IMPORT_C void BindTextL(RSqlStatement& aStmt, TInt aParameterIndex);
	IMPORT_C void BindBinaryL(RSqlStatement& aStmt, TInt aParameterIndex);

	};

/**
TSqlResourceTester class is used internally by the SQL server out of memory and resource leaking
tests. 
It provides methods for heap allocation failure simulation and resource checking and counting.

@internalAll
@released
*/
class TSqlResourceTester
	{
public:	
	IMPORT_C static void Mark();
	IMPORT_C static void Check();
	IMPORT_C static TInt Count();
	IMPORT_C static void SetDbHeapFailure(TInt aAllocFailType,TInt aRate);
	IMPORT_C static void SetHeapFailure(TInt aAllocFailType,TInt aRate);

	};

/**
Defines a set of categories for the values returned by the SQL API.

A call to an SQL API may complete with a non-zero return code indicating that some
unexpected behaviour has occurred. This can be categorised in a number of ways,
for example, as a Symbian OS error, or as a database error etc. 

Callers to the SQL API may not want to be concerned with the detailed meaning of
a specific return code value, and may find it sufficient just to know the category
of the error.

The category associated with a specific return code can be found by passing the 
return code value to the function SqlRetCodeClass().

@publishedAll
@released
*/
enum TSqlRetCodeClass 
	{
	/**
	Indicates that a return code is just for information.
	
	This category corresponds to the SQL API return codes: KSqlAtRow and KSqlAtEnd. 
	
	@see SqlRetCodeClass()
	@see TSqlRetCodeClass
	@see KSqlAtRow 
	@see KSqlAtEnd
	*/
	ESqlInformation, 
	
	/**
	Indicates that a return code represents a database-specific error.
	
	This category corresponds to SQL API return codes in the range KSqlErrGeneral to KSqlErrStmtExpired.
	
	@see SqlRetCodeClass()
	@see TSqlRetCodeClass
	@see KSqlErrGeneral
	@see KSqlErrStmtExpired
	*/
	ESqlDbError,
	
	/**
	Indicates that a return code represents a Symbian OS error.
	
	This category corresponds to SQL API return codes in the range KErrPermissionDenied to KErrNone,
	
	@see SqlRetCodeClass()
	@see TSqlRetCodeClass
	@see KErrPermissionDenied
	@see KErrNone
	*/
	ESqlOsError 
	};

/**
An information type return code from a call to RSqlStatement::Next().

It means that the RSqlStatement object points to a valid row, and that
the user can access the column data using the appropriate RSqlStatement
member functions.

@see RSqlStatement::Next()
@see RSqlStatement
@see ESqlInformation
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlAtRow = 1;

/**
An information type return code from a call to RSqlStatement::Next().

It means that the RSqlStatement object does not point to a valid row,
and that column data accessors cannot be used.

@see RSqlStatement::Next()
@see RSqlStatement
@see ESqlInformation
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlAtEnd = 2;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates a general SQL error or a missing database.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrGeneral		= -311;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates an internal logic error in the SQL database engine, and specifically
that an internal consistency check within the SQL database engine has failed.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrInternal		= -312;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates that access permission has been denied.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrPermission	= -313;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates an internal logic error in the SQL database engine, and specifically
that a callback routine requested an abort.

@publishedAll
@released
*/
const TInt KSqlErrAbort			= -314;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates that the database file is locked.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrBusy			= -315;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates that a table in the database is locked.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrLocked		= -316;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates an attempt to write to a database that is read-only.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrReadOnly		= -318;

/**
SQL database-specific error type. Operation terminated.

@publishedAll
@released
*/
const TInt KSqlErrInterrupt		= -319;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates that a disk I/O error has occurred.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrIO			= -320;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates that the database disk image is malformed.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrCorrupt		= -321;

/**
SQL database-specific error type. Table or record not found.

@publishedAll
@released
*/
const TInt KSqlErrNotFound		= -322;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates that an insertion operation has failed because an autoincrement column used up 
all awailable rowids.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrFull			= -323;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates a failure to open the database file.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrCantOpen		= -324;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates a database lock protocol error.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrProtocol		= -325;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates that the database is empty.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrEmpty			= -326;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates that a prepared SQL statement is no longer valid 
and cannot be executed.

The most common reason for this return code is that the database schema was modified after
the SQL statement was prepared. The SQL statement must be prepared again
using the RSqlStatement::Prepare() member functions.

Another possible reason for this return code is a detached database.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrSchema		= -327;

/**
SQL database-specific error type. Too much data for one row.

@publishedAll
@released
*/
const TInt KSqlErrTooBig		= -328;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates an abort due to constraint violation.

"Constraint violation" means violation of one or more column constraints ("NOT NULL", "PRIMARY KEY",
"UNIQUE", "CHECK", "DEFAULT", "COLLATE" SQL keywords) or table constraints ("PRIMARY KEY", "UNIQUE", 
"CHECK" SQL keywords).

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrConstraint	= -329;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates a data type mismatch.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrMismatch		= -330;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates an internal logic error in the SQL database engine.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrMisuse		= -331;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates that a parameter index value is out of range.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrRange			= -335;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates that the file that has been opened is not a database file.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrNotDb			= -336;

/**
An SQL database-specific error type return code from a call to the SQL API.

It indicates that an SQL statement has expired, and needs to be prepared again.

@see RSqlStatement
@see ESqlDbError
@see TSqlRetCodeClass

@publishedAll
@released
*/
const TInt KSqlErrStmtExpired	= -360;

IMPORT_C TSqlRetCodeClass SqlRetCodeClass(TInt aSqlRetCode);

#endif //__SQLDB_H__