--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/sql/SRC/Server/SqlSrvStatement.h Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,255 @@
+// 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 "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#ifndef __SQLSRVSTATEMENT_H__
+#define __SQLSRVSTATEMENT_H__
+
+#include <e32base.h>
+#include <s32mem.h> //TBufBuf
+#include "SqlUtil.h" //Sql2OsErrCode()
+#include "SqlBufFlat.h" //RSqlBufFlat
+#include "SqlSrvStatementUtil.h" //Global SQL statement related functions
+
+//Forward declarations
+struct sqlite3;
+struct sqlite3_stmt;
+class RWriteStream;
+class CSqlSrvStatement;
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////// HSqlSrvStmtParamBuf //////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+Buffer for storing binary/text parameter values (an input from client side write stream objects or bound text/binary parameters).
+Every CSqlSrvStatement object maintains a collection of HSqlSrvStmtParamBuf objects.
+
+Please, note that:
+
+ - The life-time of the HSqlSrvStmtParamBuf objects is controlled by a set of flags:
+ = iStatementFinalized - False by default, set to true if the bound statement has been finalized.
+ When DoRelease() is called, the method checks this poreperty and if the statement has been finalized,
+ then obviously no more parameter binding operations can be performed and it is safe to destroy the
+ current HSqlSrvStmtParamBuf object. Otherwise the HSqlSrvStmtParamBuf object won't be destroyed,
+ it will be marked as "dead" - see the "iAlive" property;
+ = iAlive - True by default, set to false by the DoRelease() call, if the object cannot be destroyed because
+ the bound statement is not finalized yet;
+ = iBufType - EBufIpcStream if the current HSqlSrvStmtParamBuf object is an IPC stream buffer, EBufSimpleBind
+ if the object holds a parameter value, that has been bound not using an IPC stream. This property
+ is checked when the bound statement gets finalized - inside the NotifyStatementFinalized() function.
+ If the current object is not an IPC stream buffer, then it is safe to destroy the object because
+ the bound statement is finalized;
+
+ All these checks allow keeping the buffer object alive when it is needed and code like the code bellow should work without problems:
+@code
+ RSqlStatement stmt; //Prepare a statement with a binary/text parameter
+ ....
+ RSqlParamWriteStream strm;
+ strm.BindBinary(stmt,...); //Use a stream object to bind the parameter value
+ strm.WriteL(...);
+ strm.CommitL(); //The stream commit call will bind the streamed parameter value to the statement
+ strm.Close(); //The stream close operation should not destroy the HSqlSrvStmtParamBuf object, because the parameter
+ //value is kept in the buffer, and when that value was bound to the statement, the
+ //SQLITE_STATIC constant was used, which means - SQLite won't make a copy of the parameter value,
+ //SQLite will keep a pointer to the parameter value and use it for the Exec() operation.
+ stmt.Exec(); //At this point the SQLite library should be able to get the parameter data and use it.
+@endcode
+
+ - Another reason for keeping the HSqlSrvStmtParamBuf object alive during the life-time of the CSqlSrvStatement object is that
+ the RSqlStatement::Reset() call should not destroy the buffer. The client should be able to resuse
+ the buffered parameter data for the next RSqlStatement::Exec() call. For example:
+@code
+ RSqlStatement stmt; //Prepare a statement with two binary parameters
+ ....
+ RSqlParamWriteStream strm1, strm2;
+
+ strm1.BindBinary(stmt,...); //Use a stream object to bind the 1st parameter value
+ strm1.WriteL(...);
+ strm1.CommitL();
+ strm1.Close();
+
+ strm2.BindBinary(stmt,...); //Use a stream object to bind the 2nd parameter value
+ strm2.WriteL(...);
+ strm2.CommitL();
+ strm2.Close();
+
+ stmt.Exec(); //Do the operation using the bound parameter values
+ stmt.Reset(); //This call should not destroy the HSqlSrvStmtParamBuf objects that keep the parameter values
+
+ strm2.BindBinary(stmt,...); //Use a stream object to bind the 2nd parameter value
+ strm2.WriteL(...);
+ strm2.CommitL();
+ strm2.Close();
+
+ stmt.Exec(); //Do the operation using the bound parameter values.
+ //The operation should be able to use the old 1st parameter value without any problems,
+ //and also the new 2nd parameter value.
+@endcode
+
+ - The HSqlSrvStmtParamBuf object can be synch-ed just once. The reason for that is to prevent the double commit-s,
+ that will occur as a result of MStreamBuf::Close() calls on the client side, where the Close() method will try to sync the buffer.
+ The single sync will prevent the SQL server from crashing, if the order of the RSqlStatement::Close() and
+ RSqlParamWriteStream::Close() calls is reversed, e.g.:
+@code
+ RSqlStatement stmt;
+ ....
+ RSqlParamWriteStream strm;
+ strm.BindBinary(stmt,...);
+ strm.WriteL(...);
+ strm.CommitL();
+ stmt.Exec();
+ stmt.Close();
+ strm.Close();
+@endcode
+
+ - For BC reasons, even though the HSqlSrvStmtParamBuf object can be synch-ed just once (the operation is controlled by the iSynchDone
+ flag), the client side still will be able to update the buffer content, because the related HIpcStream stream object keeps a copy
+ of the buffer's base address. Since the parameter is bound using the SQLITE_STATIC constant (SQLite won't make a copy of the
+ parameter value), at the moment of the Exec() call, SQLite will use the give pointer to the parameter value and will pick up
+ the updated buffer even without a commit call;
+
+@endcode
+
+ - The iSynchDone flag controls the number of buffer commit operations. It is false by default,
+ set to true by the DoSynchL() call. The HSqlSrvStmtParamBuf object can be synch-ed just once, because DoSynchL()
+ calls sqlite3_bind_text/binary() and the expectation is that the whole buffer with the parameter data is ready for binding;
+ If the buffer is not commited by calling DoSynchL(), the buffer still will be commited by the DoSynchL() call performed from
+ MStreamBuf::Close(). But in a case of a sync failure, no error will be reported to the client side;
+
+@see HIpcStream
+@see CSqlSrvStatement
+
+@internalComponent
+*/
+NONSHARABLE_CLASS(HSqlSrvStmtParamBuf) : public TBufBuf
+ {
+public:
+ enum TDataType {EBinary, EText16};
+ enum TBufType {EBufSimpleBind, EBufIpcStream};
+
+ static inline HSqlSrvStmtParamBuf* NewL(CSqlSrvStatement& aStatement, TInt aParamIndex, HSqlSrvStmtParamBuf::TDataType aDataType,
+ HSqlSrvStmtParamBuf::TBufType aBufType);
+ inline void Reset(HSqlSrvStmtParamBuf::TDataType aDataType, HSqlSrvStmtParamBuf::TBufType aBufType);
+
+ inline const TPtrC8 SetDataL(const TDesC8& aData);
+ inline const TPtrC8 Data() const;
+ inline HSqlSrvStmtParamBuf::TDataType DataType() const;
+
+ void NotifyStatementFinalized();
+ inline TInt ParamIndex() const;
+
+private:
+ inline HSqlSrvStmtParamBuf(CSqlSrvStatement& aStatement, TInt aParamIndex, HSqlSrvStmtParamBuf::TDataType aDataType,
+ HSqlSrvStmtParamBuf::TBufType aBufType);
+ virtual ~HSqlSrvStmtParamBuf();
+ inline void ConstructL();
+ virtual void DoSynchL();
+ virtual void DoRelease();
+
+private:
+ enum {EExpandSize = 512};
+
+ CSqlSrvStatement& iStatement; //The bound CSqlSrvStatement object
+ CBufFlat* iBuf; //Parameter buffer - not owned by HSqlSrvStmtParamBuf
+ TInt iParamIndex; //The parameter index
+ TBool iStatementFinalized;//True if the bound statement object has been finalized
+ TBool iAlive; //True if DoRelease() has not been called yet
+ HSqlSrvStmtParamBuf::TDataType iDataType;//The parameter type
+ HSqlSrvStmtParamBuf::TBufType iBufType; //IPC stream buf or a simple "bind param" buf
+ TBool iSynchDone; //True if the buffer data has been bound to the statement
+ };
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////// CSqlSrvStatement //////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+SQL statement handle.
+
+CSqlSrvStatement is a server side class which processes the client side requests for:
+ - preparing 16-bit and 8-bit SQL statements;
+ - executing prepared SQL statement;
+ - retrieving parameter names and column names;
+ - binding SQL parameters;
+ - retrieving column values;
+ - reseting the prepared SQL statement;
+ - moving the cursor to the next record;
+
+@see CSqlSrvStatement::NewLC()
+@see CSqlSrvStatement::NewLC()
+@see CSqlSrvStatement::BindL()
+@see CSqlSrvStatement::Next()
+@see CSqlSrvStatement::Reset()
+@see CSqlSrvStatement::Exec()
+@see CSqlSrvStatement::ColumnNamesL()
+@see CSqlSrvStatement::ParamNamesL()
+@see CSqlSrvStatement::ColumnValuesL()
+@see CSqlSrvStatement::ColumnSource()
+
+@see HSqlSrvStmtParamBuf
+
+@internalComponent
+*/
+NONSHARABLE_CLASS(CSqlSrvStatement) : public CBase
+ {
+public:
+ static CSqlSrvStatement* NewLC(sqlite3* aDbHandle, const TDesC16& aSqlStmt, TInt& aColumnCount, TInt& aParamCount);
+ static CSqlSrvStatement* NewLC(sqlite3* aDbHandle, const TDesC8& aSqlStmt, TInt& aColumnCount, TInt& aParamCount);
+ virtual ~CSqlSrvStatement();
+
+ void BindL(const RSqlBufFlat& aParamBuf);
+ inline TInt Next();
+ inline TInt Reset();
+ inline TInt Exec();
+
+ inline const RSqlBufFlat& BufFlatL(TSqlBufFlatType aWhat) const;
+ const RSqlBufFlat& ColumnNamesL();
+ const RSqlBufFlat& ParamNamesL();
+ const RSqlBufFlat& ColumnValuesL();
+ TInt ColumnSource(TInt aColumnIndex, TPtrC8& aColumnSource) const;
+
+ TInt ColumnInt(TInt aColIdx) const;
+ TInt64 ColumnInt64(TInt aColIdx) const;
+ TReal ColumnReal(TInt aColIdx) const;
+ TPtrC ColumnText(TInt aColIdx) const;
+ TPtrC8 ColumnBinary(TInt aColIdx) const;
+
+ HBufC* GetDeclColumnTypesL();
+
+ HSqlSrvStmtParamBuf* GetParamBufL(TInt aParamIndex, HSqlSrvStmtParamBuf::TDataType aDataType, HSqlSrvStmtParamBuf::TBufType aBufType);
+ void BindParamBufL(TInt aParamIndex);
+
+private:
+ inline CSqlSrvStatement();
+ inline void ConstructL(sqlite3* aDbHandle, const TDesC16& aSqlStmt);
+ inline void ConstructL(sqlite3* aDbHandle, const TDesC8& aSqlStmt);
+ void DoCommonConstructL();
+ void DestroyParamBufArray();
+ void ExtendParamBufArrayL(TInt aParamIndex);
+ TPtrC8 CopyAndStoreParamL(TInt aParamIndex, HSqlSrvStmtParamBuf::TDataType aDataType, const TDesC8& aParamValue);
+
+private:
+ sqlite3_stmt* iStmtHandle; //SQL statement handle
+ TInt iColumnCount;
+ TInt iParamCount;
+ TSqlBufFlatType iBufFlatType; //What is in iFlatBuf data member
+ RSqlBufFlat iBufFlat; //Flat buffer used for: column names, parameter names, column values
+ RArray<HSqlSrvStmtParamBuf*> iParamBufArray;//An array with pointers to HSqlSrvStmtParamBuf buffers for the text/binary parameters
+
+ };
+
+#include "SqlSrvStatement.inl"
+
+#endif//__SQLSRVSTATEMENT_H__