|
1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #ifndef __SQLBUFFLAT_H__ |
|
17 #define __SQLBUFFLAT_H__ |
|
18 |
|
19 #include <e32base.h> |
|
20 #include "SqlPanic.h" |
|
21 |
|
22 //Forward declarations |
|
23 class TSqlBufRIterator; |
|
24 class CSqlSecurityPolicy; |
|
25 class TSqlSecurityPolicyIterator; |
|
26 |
|
27 #ifdef _DEBUG |
|
28 const TUint64 KSqlBufFlatMagicValue = 0xAA11BB44221199EEULL;//TInt64 for 8-byte alignment |
|
29 #define SQLFLATBUF_INVARIANT() Invariant() |
|
30 #else |
|
31 #define SQLFLATBUF_INVARIANT() void(0) |
|
32 #endif |
|
33 |
|
34 /** |
|
35 RSqlBufFlat class manages a flat memory buffer with fixed elements count. |
|
36 Each element (or field) of the flat buffer has a type and variable length data and is accessible using an |
|
37 index. The data may be NULL. |
|
38 The RSqlBufFlat objects are used for sending/receiving data between client dlls and servers, |
|
39 because once the buffer filled, a pointer to the flat buffer data can be used to send the whole buffer in a single |
|
40 IPC call, which is more effective than using a stream like transfer. |
|
41 |
|
42 RSqlBufFlat public functions are not very convenient for storing/retrieving values based on the column type |
|
43 and there are two additional classes which may be used instead of working with the flat buffer directly: |
|
44 TSqlBufRIterator and TSqlBufWIterator. |
|
45 |
|
46 The physical structure of the flat buffer is: |
|
47 --------------------------- |
|
48 | SysData | Header | Data | |
|
49 --------------------------- |
|
50 - "SysData" has fixed length and contains fields with about the buffer used size, elements count, header size; |
|
51 - "Header" has fixed length, which depends of the number of elements and contains cells, one per element. |
|
52 Each cell contains information about: element type, element data length, the start position of the |
|
53 element data in the flat buffer, "present"/"not present" flag. "Not present" means that no memory |
|
54 is reserved for the element data, but the buffer "knows" what is the element type and element data length; |
|
55 (In the current design there is no "Present"/"Not present flag". If the data position is 0, that indicates |
|
56 the element is "Not present"). See RSqlBufFlat::TCell comments for details. |
|
57 - "Data" Is the dynamic part of the buffer which may grow during the operations with the flat buffer (setting |
|
58 element data); |
|
59 |
|
60 "Present"/"Not present" attribute has a key role in the large data transfers between the client and the server. |
|
61 In order to optimize memory usage, usually the client specifies what can be the max field size. The server |
|
62 knows that and when it fills a particular flat buffer, which has to be sent to the client, it puts in the |
|
63 flat buffer only the pieces of data whose size is less than the specified "large data" size. Any data piece whose |
|
64 size is larger will be set as "Not present" in the flat buffer. The "Not present" field will have all the |
|
65 attributes, like type and size, but won't have any data or any allocated flat buffer memory. |
|
66 So the client, when it receives the flat buffer, will know the field type and size and if it wants to get the field data, |
|
67 will have to make an additional call to the server. |
|
68 |
|
69 Note that the fields in the buffer are 8-byte aligned. |
|
70 |
|
71 Typical examples how the buffer can be used: |
|
72 |
|
73 Case 1 - a dll client wants to receive from the server a flat buffer data. |
|
74 |
|
75 @code |
|
76 RSqlBufFlat bufFlat; |
|
77 bufFlat.SetCount(N); //N is the field count |
|
78 .... |
|
79 bufFlat.Reset(); //Clears the content of the buffer without shrinking it. |
|
80 ipcArgs.Set(0, bufFlat.MaxSize()); //Tell the server what is the flat buffer max size |
|
81 ipcArgs.Set(1, &bufFlat.BufPtr()); |
|
82 TInt rc = session.SendReceive(funcNum, ipcArgs); |
|
83 if(rc > KSqlClientBufOverflowCode) |
|
84 { //the client buffer is not big enough and has to be resized |
|
85 rc = bufFlat.ReAlloc(err - KSqlClientBufOverflowCode); |
|
86 if(rc != KErrNone) |
|
87 { |
|
88 return rc; |
|
89 } |
|
90 ipcArgs.Set(0, bufFlat.MaxSize()); |
|
91 ipcArgs.Set(1, &bufFlat.BufPtr()); |
|
92 rc = session.SendReceive(funcNum, ipcArgs); |
|
93 } |
|
94 @endcode |
|
95 |
|
96 Case 2 - a dll client wants to send to the server a flat buffer data. |
|
97 |
|
98 @code |
|
99 RSqlBufFlat bufFlat; |
|
100 bufFlat.SetCount(N); //N is the field count |
|
101 .... |
|
102 TPtrC8 ptr(bufFlat.BufDes()); |
|
103 TInt err = session.SendReceive(funcNum, TIpcArgs(ptr.Length(), &ptr)); |
|
104 @endcode |
|
105 |
|
106 Case 3 - the server wants to return to the client a flat buffer data. |
|
107 @code |
|
108 RSqlBufFlat bufFlat; |
|
109 bufFlat.SetCount(N); //N is the field count |
|
110 .... |
|
111 TInt maxCliBufSize = msg.Int0(); //The max size of the client buffer |
|
112 if(maxCliBufSize < bufFlat.Size()) |
|
113 { |
|
114 return bufFlat.Size() + KSqlClientBufOverflowCode;//Tell the client that its buffer is too small |
|
115 } |
|
116 msg.WriteL(1, bufFlat.BufDes()); |
|
117 @endcode |
|
118 |
|
119 Case 4 - the server wants to receive from the client a flat buffer data. |
|
120 @code |
|
121 RSqlBufFlat bufFlat; |
|
122 bufFlat.SetCount(N); //N is the field count |
|
123 .... |
|
124 TInt cliBufFlatLen = aMessage.Int0(); |
|
125 TInt err = bufFlat.ReAlloc(cliBufFlatLen); //Reallocate memory for the flat buffer |
|
126 if(err != KErrNone) |
|
127 { |
|
128 return err; |
|
129 } |
|
130 msg.ReadL(1, bufFlat.BufPtr()); |
|
131 @endcode |
|
132 |
|
133 Case 5 - the server (or the client) wants to fill the flat buffer with some data. |
|
134 @code |
|
135 RSqlBufFlat bufFlat; |
|
136 bufFlat.SetCount(N); //N is the field count |
|
137 .... |
|
138 TInt err = flatBuf.SetCount(M); //If the field count has to be changed to M |
|
139 if(err != KErrNone) |
|
140 { |
|
141 return err; |
|
142 } |
|
143 //use the TSqlBufWIterator iterator to fill the buffer |
|
144 @endcode |
|
145 |
|
146 @see TSqlBufRIterator |
|
147 @see TSqlBufWIterator |
|
148 @see RSqlBufFlat::TCell |
|
149 @see RSqlBufFlat::TBufFlat |
|
150 |
|
151 @internalComponent |
|
152 */ |
|
153 class RSqlBufFlat |
|
154 { |
|
155 friend class TSqlBufRIterator; |
|
156 friend class CSqlSecurityPolicy; |
|
157 friend class TSqlSecurityPolicyIterator; |
|
158 |
|
159 public: |
|
160 //This enum has to be in the "public" section because it is used by TCell (declared as "private" in RSqlBufFlat) |
|
161 enum |
|
162 { |
|
163 EWidthType = 3, //Bit width of the "Type" field of the header cell |
|
164 EWidthLen = 29 //Bit width of the "Length" field of the header cell |
|
165 }; |
|
166 //This enum has to be in the "public" section because it is used by TCell (declared as "private" in RSqlBufFlat) |
|
167 enum |
|
168 { |
|
169 EMaxType = 1 << EWidthType, //Max allowed flat buffer field type |
|
170 EMaxLength = 1 << EWidthLen //Max allowed flat buffer field length |
|
171 }; |
|
172 |
|
173 RSqlBufFlat(); |
|
174 TInt SetCount(TInt aCount); |
|
175 TInt ReAlloc(TInt aSize); |
|
176 void ResetAndMinimize(); |
|
177 void Reset(); |
|
178 void Close(); |
|
179 inline TInt Count() const; |
|
180 inline TInt Size() const; |
|
181 inline TInt MaxSize() const; |
|
182 |
|
183 TInt SetField(TInt aIndex, TInt aType, const void* aData, TInt aDataLength); |
|
184 |
|
185 inline const TDesC8& BufDes() const; |
|
186 inline TPtr8& BufPtr(); |
|
187 |
|
188 private: //Data type declarations |
|
189 /** |
|
190 TCell represents the structure of header cells. |
|
191 Each cells contains the following fields: |
|
192 - Flat buffer field type; |
|
193 - Flat buffer field length; |
|
194 - Flat buffer field data position; |
|
195 = if 0 then the field is "Not present" (no memory is reserved for the field data, the field data is missing); |
|
196 = if positive - the field data position in the flat buffer (counting from the beginning of the header); |
|
197 = if negative - the field is "Not present", but memory has been reserved for it; |
|
198 |
|
199 RSqlBufFlat class offers fast, indexed access to the header cells. |
|
200 |
|
201 @see RSqlBufFlat |
|
202 */ |
|
203 struct TCell |
|
204 { |
|
205 inline TInt Type() const {return (iBits >> RSqlBufFlat::EWidthLen) & (RSqlBufFlat::EMaxType - 1);} |
|
206 inline TInt Size() const {return (iBits & (RSqlBufFlat::EMaxLength - 1));} |
|
207 TUint32 iBits; //element type: EWidthType bits & element length: EWidthLen bits. |
|
208 TInt32 iPos; //element data position, relative to the beginning of the header. |
|
209 // Zero if the element is not present. |
|
210 // Negative if the element is not present but memory is reserved. |
|
211 }; |
|
212 |
|
213 enum {EExpandSize = 256}; //iBuf min expansion size - it must be a power of 2 and |
|
214 // (EExpandSize % 8) should be 0. |
|
215 /** |
|
216 TBufFlat structure represents the "SysData" part of the flat buffer (see RSqlBufFlat comments), beyond which |
|
217 begins the flat buffer header and "Data" part. |
|
218 |
|
219 TBufFlat structure contains information about: |
|
220 - Flat buffer elements count; |
|
221 - Flat buffer header size; |
|
222 - The size of used part of the flat buffer; |
|
223 |
|
224 @see RSqlBufFlat |
|
225 */ |
|
226 struct TBufFlat |
|
227 { |
|
228 TInt iCount; //element count |
|
229 TInt iHeaderSize; //buffer header size |
|
230 TInt iSize; //used buffer size |
|
231 TInt iReserved; //maintains TBufFlat 8-byte aligned |
|
232 }; |
|
233 |
|
234 private: //Method declarations |
|
235 void DoInit(); |
|
236 TInt DoReAlloc(TInt aSize); |
|
237 inline TInt Available() const; |
|
238 void DoSet(TInt aIndex, TInt aType, const void* aData, TInt aDataLength); |
|
239 TInt Reserve(TInt aLength); |
|
240 void Invariant() const; |
|
241 inline const TCell* Header() const; |
|
242 inline TCell* Header(); |
|
243 inline TInt SysDataSize() const; |
|
244 |
|
245 private: //Data declarations |
|
246 // IPC data |
|
247 TBufFlat* iBuf; |
|
248 // non-IPC data |
|
249 TInt iMaxSize; //max buffer size (allocated memory), not part of RSqlBufFlat data (IPC - sent/received). |
|
250 //iMaxSize can't be part of the IPC data, because it may be overwritten, which leads to |
|
251 //"hard to detect" problems. For example: |
|
252 // - client sends to the server in/out flat buffer with max size 256 bytes (allocated); |
|
253 // - the server has a flat buffer which max size is 512, but the used size is 200; |
|
254 // - the client flat buffer has enough space for those 200 bytes, so the server will |
|
255 // copy its flat buffer content to the client flat buffer. The client's flat buffer |
|
256 // iMaxSize data member will lose its original value (256) and will have new value assigned - |
|
257 // 512. But the client flat buffer does not have 512 bytes allocated! |
|
258 mutable TPtrC8 iBufPtrC; //it is set to point to iBuf. Not part of RSqlBufFlat data (IPC - sent/received) |
|
259 mutable TPtr8 iBufPtr; //it is set to point to iBuf. Not part of RSqlBufFlat data (IPC - sent/received) |
|
260 }; |
|
261 |
|
262 #include "SqlBufFlat.inl" |
|
263 |
|
264 #endif//__SQLBUFFLAT_H__ |