persistentstorage/sql/SRC/Server/SqlSrvStatement.h
changeset 0 08ec8eefde2f
child 11 211563e4b919
--- /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__