sl@0: // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // NTT DOCOMO, INC - Fix for Bug 1915 "SQL server panics when using long column type strings" sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #ifndef __SQLSTATEMENTIMPL_H__ sl@0: #define __SQLSTATEMENTIMPL_H__ sl@0: sl@0: #include "SqlBufIterator.h" //TSqlBufFlat, TSqlBufRIterator, TSqlBufWIterator sl@0: #include "SqlDatabaseImpl.h"//CSqlDatabaseImpl sl@0: #include "SqlStmtSession.h" //RSqlStatementSession sl@0: sl@0: //Forward declarations sl@0: class MStreamBuf; sl@0: class CSqlStatementImpl; sl@0: sl@0: #ifdef _DEBUG sl@0: #define LONGCOL_INVARIANT() Invariant() sl@0: #else sl@0: #define LONGCOL_INVARIANT() sl@0: #endif sl@0: sl@0: /** sl@0: RSqlLongColumnColl class represents a collection of long text/binary column values. sl@0: Once a column value is added to the collection, it is guaranteed that the memory address of the sl@0: column value will never change. sl@0: The class was designed to solve one specific problem - to exclude the possibility that SQL clients sl@0: may get a dangling pointer to a block of memory which already has been deleted. sl@0: Without RSqlLongColumnColl class, it may happen for example, when client prepares a SELECT sql sl@0: statement, where the record consists of two long binary/text column values. sl@0: The client calls RSqlStatement::Next() to move to a record. Since the column values are long, they will sl@0: not be transferred on the client side by the Next() call, so the client side row buffer (CSqlStatementImpl::iColumnValueBuf) sl@0: will mark them as "not present". sl@0: Then the client calls RSqlStatement::ColumnBinary(0, TPtrC8&) to get a pointer to the first column value. sl@0: The row buffer is reallocated, and the column value is retrieved from the server and copied into the buffer, the client's pointer sl@0: is set to point to the place in the row buffer, where the column value is. sl@0: While keeping the pointer to the first column value, the client calls again RSqlStatement::ColumnBinary(1, TPtrC8&) to retrieve sl@0: the second column value. In which case, the row buffer may get reallocated again, so the first pointer will point to a sl@0: block of memory, which has been deleted. sl@0: With the implementation and use of RSqlLongColumnColl class, the long column values will be kept in a different place, sl@0: RSqlLongColumnColl's collection, where it is guaranteed that the memory address of the column value is constant. sl@0: sl@0: @internalComponent sl@0: */ sl@0: NONSHARABLE_CLASS(RSqlLongColumnColl) sl@0: { sl@0: public: sl@0: struct TColumnReader sl@0: { sl@0: virtual TInt Read(TInt aColumnIndex, TDes8& aBuf) = 0; sl@0: }; sl@0: sl@0: public: sl@0: inline RSqlLongColumnColl(); sl@0: inline void Close(); sl@0: inline void Reset(); sl@0: TInt Append(TColumnReader& aReader, TInt aColumnIndex, TInt aColumnSize); sl@0: inline TPtrC Text(TInt aColumnIndex) const; sl@0: inline TPtrC8 Binary(TInt aColumnIndex) const; sl@0: inline TBool IsPresent(TInt aColumnIndex) const; sl@0: sl@0: private: sl@0: inline TInt FindValue(TInt aColumnIndex) const; sl@0: #ifdef _DEBUG sl@0: void Invariant() const; sl@0: #endif sl@0: sl@0: private: sl@0: struct TData sl@0: { sl@0: static TBool Compare(const TInt* aIndex, const TData& aData); sl@0: inline TData(TInt aIndex, HBufC8* aData); sl@0: TInt iIndex; sl@0: HBufC8* iData; sl@0: }; sl@0: enum {KLongColumnCollGranularity = 8}; sl@0: RArray iValues; sl@0: sl@0: }; sl@0: sl@0: template TInt SqlCreateStatement(CSqlStatementImpl*& aImpl, CSqlDatabaseImpl& aDatabase, const DES& aSqlStmt); sl@0: sl@0: /** sl@0: CSqlStatementImpl implements RSqlStatement functionality. sl@0: CSqlStatementImpl can prepare and execute parametrized SQL statements and SQL statements without parameters. sl@0: CSqlStatementImpl cannot prepare and execute SQL strings containing more than one SQL statement. sl@0: @internalComponent sl@0: */ sl@0: NONSHARABLE_CLASS(CSqlStatementImpl) : public CBase sl@0: { sl@0: template friend TInt SqlCreateStatement(CSqlStatementImpl*& aImpl, CSqlDatabaseImpl& aDatabase, const DES& aSqlStmt); sl@0: sl@0: public: sl@0: static inline TInt New(CSqlStatementImpl*& aImpl, CSqlDatabaseImpl& aDatabase, const TDesC16& aSqlStmt); sl@0: static inline TInt New(CSqlStatementImpl*& aImpl, CSqlDatabaseImpl& aDatabase, const TDesC8& aSqlStmt); sl@0: virtual ~CSqlStatementImpl(); sl@0: sl@0: inline TBool AtRow() const; sl@0: sl@0: TInt Reset(); sl@0: TInt Exec(); sl@0: void Exec(TRequestStatus& aStatus); sl@0: TInt Next(); sl@0: sl@0: TInt BindNull(TInt aParamIndex); sl@0: TInt BindInt(TInt aParamIndex, TInt aParamValue); sl@0: TInt BindInt64(TInt aParamIndex, TInt64 aParamValue); sl@0: TInt BindReal(TInt aParamIndex, TReal aParamValue); sl@0: TInt BindText(TInt aParamIndex, const TDesC& aParamText); sl@0: TInt BindBinary(TInt aParamIndex, const TDesC8& aParamData); sl@0: TInt BindZeroBlob(TInt aParamIndex, TInt aBlobSize); sl@0: sl@0: inline TInt ColumnCount() const; sl@0: TSqlColumnType ColumnType(TInt aColumnIndex); sl@0: TInt DeclaredColumnType(TInt aColumnIndex, TSqlColumnType& aColumnType); sl@0: TInt ColumnSize(TInt aColumnIndex); sl@0: TInt ColumnInt(TInt aColumnIndex); sl@0: TInt64 ColumnInt64(TInt aColumnIndex); sl@0: TReal ColumnReal(TInt aColumnIndex); sl@0: TInt ColumnText(TInt aColumnIndex, TPtrC& aPtr); sl@0: TInt ColumnText(TInt aColumnIndex, TDes& aDest); sl@0: TInt ColumnBinary(TInt aColumnIndex, TPtrC8& aPtr); sl@0: TInt ColumnBinary(TInt aColumnIndex, TDes8& aDest); sl@0: sl@0: TInt ColumnName(TInt aColumnIndex, TPtrC& aNameDest); sl@0: TInt ParameterName(TInt aParamIndex, TPtrC& aNameDest); sl@0: sl@0: inline TInt ParamIndex(const TDesC& aParamName); sl@0: inline TInt ColumnIndex(const TDesC& aColumnName); sl@0: sl@0: inline MStreamBuf* ColumnSourceL(TInt aColumnIndex); sl@0: inline MStreamBuf* ParamSinkL(TSqlSrvFunction aFunction, TInt aParamIndex); sl@0: sl@0: private: sl@0: inline CSqlStatementImpl(); sl@0: template TInt Construct(CSqlDatabaseImpl& aDatabase, const DES& aSqlStmt); sl@0: TInt Name2Index(const TDesC& aName, RSqlBufFlat& aNameBufFlat, TInt aCount, TSqlSrvFunction aFunction, TBool& aPresent); sl@0: TInt Index2Name(TInt aIndex, RSqlBufFlat& aNameBufFlat, TInt aCount, TSqlSrvFunction aFunction, TBool& aPresent, TPtrC& aColName); sl@0: TInt CheckNameBufPresent(TBool& aPresent, RSqlBufFlat& aNameBufFlat, TInt aCount, TSqlSrvFunction aFunction); sl@0: sl@0: private: sl@0: RSqlStatementSession iSqlStmtSession; sl@0: TBool iBound; sl@0: enum TState {EUnknown, EAtRow}; sl@0: TState iState; sl@0: sl@0: TInt iColumnCnt; sl@0: TBool iColumnNameBufPresent; sl@0: RSqlBufFlat iColumnNameBuf; sl@0: RSqlBufFlat iColumnValueBuf; sl@0: TSqlBufRIterator iColumnValBufIt; sl@0: sl@0: TInt iParamCnt; sl@0: TBool iParamNameBufPresent; sl@0: RSqlBufFlat iParamNameBuf; sl@0: RSqlBufFlat iParamValueBuf; sl@0: TSqlBufWIterator iParamValBufIt; sl@0: sl@0: RSqlLongColumnColl iLongColumnColl; sl@0: sl@0: RArray iDeclaredColumnTypes; //Array of declared column types for current statement. sl@0: }; sl@0: sl@0: #include "SqlStatementImpl.inl" sl@0: sl@0: #endif //__SQLSTATEMENTIMPL_H__