|
1 // Copyright (c) 2005-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 #include <e32base.h> |
|
17 #include "IPCBuf.h" |
|
18 #include "SqlPanic.h" |
|
19 #include "SqlDbSession.h" |
|
20 |
|
21 /** |
|
22 Standard, phase-one HIpcBuf factory method. |
|
23 Created HIpcBuf instance will be used for transfering large text or binary objects from/to SQL server. |
|
24 The created HIpcBuf instance will be placed in the cleanup stack. |
|
25 |
|
26 @param aSession A reference to RSqlDbSession instance. |
|
27 @param aFunction Prepared function code (with all statement handle bits set) |
|
28 @param aArgs A set of IPC arguments to be sent to the SQL server. |
|
29 |
|
30 @return A pointer to the created HIpcBuf instance |
|
31 |
|
32 @leave KErrNoMemory Out of memory. |
|
33 */ |
|
34 HIpcBuf* HIpcBuf::NewLC(RSqlDbSession& aSession, TInt aFunction, TIpcArgs& aArgs) |
|
35 { |
|
36 HIpcBuf* self = new (ELeave) HIpcBuf(aSession); |
|
37 self->PushL(); |
|
38 self->ConstructL(aFunction, aArgs); |
|
39 return self; |
|
40 } |
|
41 |
|
42 /** |
|
43 Standard, phase-one HIpcBuf factory method. |
|
44 Created HIpcBuf instance will be used for transfering large text or binary objects from/to SQL server. |
|
45 |
|
46 @param aSession A reference to RSqlDbSession instance. |
|
47 @param aFunction Prepared function code (with all statement handle bits set) |
|
48 @param aArgs A set of IPC arguments to be sent to the SQL server. |
|
49 |
|
50 @return A pointer to the created HIpcBuf instance |
|
51 |
|
52 @leave KErrNoMemory Out of memory. |
|
53 */ |
|
54 HIpcBuf* HIpcBuf::NewL(RSqlDbSession& aSession, TInt aFunction, TIpcArgs& aArgs) |
|
55 { |
|
56 HIpcBuf* self = NewLC(aSession, aFunction, aArgs); |
|
57 CleanupStack::Pop(); |
|
58 return self; |
|
59 } |
|
60 |
|
61 /** |
|
62 Standard, phase-two HIpcBuf construction method. |
|
63 |
|
64 @param aFunction The command code which will be sent to the SQL server |
|
65 @param aArgs A set of IPC arguments to be sent to the SQL server. |
|
66 |
|
67 @leave KErrNoMemory Out of memory. |
|
68 |
|
69 Usage of the IPC call arguments: |
|
70 Arg 2: [in/out] IPC buffer |
|
71 iBuf.iExt: [in] stream size in bytes |
|
72 */ |
|
73 void HIpcBuf::ConstructL(TInt aFunction, TIpcArgs& aArgs) |
|
74 { |
|
75 TPckg<TIpcStreamBuf> pckg(iBuf); |
|
76 aArgs.Set(2, &pckg); |
|
77 __SQLLEAVE_IF_ERROR(iHandle = iSession.SendReceive(aFunction, aArgs)); |
|
78 TUint8* base = iBuf.iData; |
|
79 // if reading we already have one buffer-full of data |
|
80 TInt avail = Max(0, Min(iBuf.iExt, KIpcBufSize)); |
|
81 SetBuf(ERead, base, base + avail); |
|
82 SetPos(ERead, avail); |
|
83 SetBuf(EWrite, base, base); |
|
84 SetPos(EWrite, 0); |
|
85 } |
|
86 |
|
87 /** |
|
88 @param aSession A reference to a sesion object. |
|
89 */ |
|
90 HIpcBuf::HIpcBuf(RSqlDbSession& aSession) : |
|
91 iSession(aSession), |
|
92 iHandle(0), |
|
93 iRPos(0), |
|
94 iWPos(0) |
|
95 { |
|
96 iBuf.iExt = -1; |
|
97 } |
|
98 |
|
99 /** |
|
100 */ |
|
101 HIpcBuf::~HIpcBuf() |
|
102 { |
|
103 if(iHandle > 0) //iHandle is valid only when > 0. |
|
104 { |
|
105 (void)iSession.SendReceive(::MakeMsgCode(ESqlSrvStreamClose, ESqlSrvStreamHandle, iHandle)); |
|
106 } |
|
107 } |
|
108 |
|
109 /** |
|
110 Fill the buffer's read area. |
|
111 */ |
|
112 TInt HIpcBuf::UnderflowL(TInt) |
|
113 { |
|
114 // when handle is null there is no data to read from server |
|
115 if(!iHandle) |
|
116 { |
|
117 return 0; |
|
118 } |
|
119 __SQLASSERT(Avail(ERead) == 0, ESqlPanicInternalError); |
|
120 TUint8* base=iBuf.iData; |
|
121 IpcWriteL(base,Lag(EWrite)); |
|
122 SetBuf(EWrite,base,base); |
|
123 |
|
124 TInt len=IpcReadL(base,iBuf.ESize); |
|
125 SetBuf(ERead,base,base+len); |
|
126 return len; |
|
127 } |
|
128 |
|
129 /** |
|
130 Set up the buffer's write area. |
|
131 */ |
|
132 void HIpcBuf::OverflowL() |
|
133 { |
|
134 __SQLASSERT(Avail(EWrite) == 0, ESqlPanicInternalError); |
|
135 |
|
136 TUint8* base = iBuf.iData; |
|
137 MovePos(ERead, Lag(ERead)); |
|
138 SetBuf(ERead, base, base); |
|
139 |
|
140 IpcWriteL(base, Lag(EWrite)); |
|
141 SetBuf(EWrite, base, base + iBuf.ESize); |
|
142 } |
|
143 |
|
144 /** |
|
145 Destroys HIpcBuf instance. |
|
146 */ |
|
147 void HIpcBuf::DoRelease() |
|
148 { |
|
149 delete this; |
|
150 } |
|
151 |
|
152 /** |
|
153 Synchronise this buffer with its file, giving up on outstanding writes in case of failure. |
|
154 */ |
|
155 void HIpcBuf::DoSynchL() |
|
156 { |
|
157 TUint8* base = iBuf.iData; |
|
158 MovePos(ERead, Lag(ERead)); |
|
159 TInt lag = Lag(EWrite); |
|
160 SetBuf(ERead | EWrite, base, base); |
|
161 iBuf.iExt = -1; |
|
162 IpcWriteL(base, lag); |
|
163 __SQLLEAVE_IF_ERROR(iSession.SendReceive(::MakeMsgCode(ESqlSrvStreamSynch, ESqlSrvStreamHandle, iHandle))); |
|
164 } |
|
165 |
|
166 /** |
|
167 Read direct from ipc if asked to transfer more than a bufferful. |
|
168 */ |
|
169 TInt HIpcBuf::DoReadL(TAny* aPtr, TInt aMaxLength) |
|
170 { |
|
171 __SQLASSERT(aMaxLength > 0, ESqlPanicInternalError); |
|
172 TInt avail = Avail(ERead); |
|
173 __SQLASSERT(avail >= 0 && Avail(EWrite) >= 0, ESqlPanicInternalError); |
|
174 if(avail > 0) |
|
175 { |
|
176 TInt len = Min(aMaxLength, avail); |
|
177 TUint8* ptr = Ptr(ERead); |
|
178 aPtr = Mem::Copy(aPtr, ptr, len); |
|
179 SetPtr(ERead, ptr + len); |
|
180 aMaxLength -= len; |
|
181 if(aMaxLength == 0) |
|
182 return len; // that's it |
|
183 } |
|
184 __SQLASSERT(Avail(ERead) == 0, ESqlPanicInternalError); |
|
185 if(aMaxLength < iBuf.ESize) |
|
186 return avail + TStreamBuf::DoReadL(aPtr, aMaxLength); |
|
187 |
|
188 // when handle is null there is no more data to read from server |
|
189 if(!iHandle) |
|
190 { |
|
191 return 0; |
|
192 } |
|
193 |
|
194 TUint8* base = iBuf.iData; |
|
195 IpcWriteL(base, Lag(EWrite)); |
|
196 SetBuf(ERead | EWrite, base, base); |
|
197 return avail + IpcReadL(aPtr, aMaxLength); |
|
198 } |
|
199 |
|
200 /** |
|
201 Write direct to ipc if asked to transfer more than a bufferful. |
|
202 */ |
|
203 void HIpcBuf::DoWriteL(const TAny* aPtr,TInt aLength) |
|
204 { |
|
205 __SQLASSERT(aLength > 0, ESqlPanicInternalError); |
|
206 TInt avail = Avail(EWrite); |
|
207 __SQLASSERT(Avail(ERead) >= 0 && avail >= 0, ESqlPanicInternalError); |
|
208 if(avail > 0) |
|
209 { |
|
210 TInt len = Min(aLength, avail); |
|
211 SetPtr(EWrite, Mem::Copy(Ptr(EWrite), aPtr, len)); |
|
212 aLength -= len; |
|
213 if(aLength == 0) |
|
214 return; // done |
|
215 |
|
216 aPtr = (TUint8*)aPtr + len; |
|
217 } |
|
218 __SQLASSERT(Avail(EWrite) == 0, ESqlPanicInternalError); |
|
219 if(aLength < iBuf.ESize) |
|
220 TStreamBuf::DoWriteL(aPtr, aLength); |
|
221 else |
|
222 { |
|
223 TUint8* base = iBuf.iData; |
|
224 IpcWriteL(base, Lag(EWrite)); |
|
225 MovePos(ERead, Lag(ERead)); |
|
226 SetBuf(ERead | EWrite, base, base); |
|
227 IpcWriteL(aPtr, aLength); |
|
228 } |
|
229 } |
|
230 |
|
231 /** |
|
232 Position the mark(s) indicated by aMark at aOffset from aLocation. |
|
233 */ |
|
234 TStreamPos HIpcBuf::DoSeekL(TMark aMark, TStreamLocation aLocation, TInt aOffset) |
|
235 { |
|
236 TUint8* base = iBuf.iData; |
|
237 TInt end = EndL(); |
|
238 |
|
239 switch(aLocation) |
|
240 { |
|
241 case EStreamBeginning: |
|
242 break; |
|
243 case EStreamMark: |
|
244 switch(aMark) |
|
245 { |
|
246 case ERead: |
|
247 aOffset += Mark(ERead); |
|
248 break; |
|
249 case EWrite: |
|
250 aOffset += Mark(EWrite); |
|
251 break; |
|
252 default: |
|
253 __SQLASSERT_ALWAYS(0, ESqlPanicStreamMarkInvalid); |
|
254 break; |
|
255 } |
|
256 break; |
|
257 case EStreamEnd: |
|
258 aOffset += end; |
|
259 break; |
|
260 default: |
|
261 __SQLASSERT_ALWAYS(0, ESqlPanicStreamLocationInvalid); |
|
262 break; |
|
263 } |
|
264 TInt r = KErrNone; |
|
265 if(aOffset < 0) |
|
266 { |
|
267 aOffset = 0; |
|
268 r = KErrEof; |
|
269 } |
|
270 else if(aOffset > end) |
|
271 { |
|
272 aOffset = end; |
|
273 r = KErrEof; |
|
274 } |
|
275 |
|
276 __SQLASSERT_ALWAYS(!(aMark & ~(ERead | EWrite)), ESqlPanicStreamMarkInvalid); |
|
277 if(aMark & ERead) |
|
278 { |
|
279 TInt lag = aOffset - Pos(ERead); |
|
280 if(lag >= base - End(ERead) && lag <= 0) |
|
281 SetPtr(ERead, End(ERead) + lag); |
|
282 else |
|
283 { |
|
284 SetPos(ERead, aOffset); |
|
285 SetBuf(ERead, base, base); |
|
286 } |
|
287 } |
|
288 if(aMark & EWrite && aOffset != Mark(EWrite)) |
|
289 { |
|
290 IpcWriteL(base, Lag(EWrite)); |
|
291 SetPos(EWrite, aOffset); |
|
292 SetBuf(EWrite, base, base); |
|
293 } |
|
294 __SQLLEAVE_IF_ERROR(r); |
|
295 return TStreamPos(aOffset); |
|
296 } |
|
297 |
|
298 /** |
|
299 Read from the server at the current read position. |
|
300 Arg 0: not used |
|
301 Arg 1: [out] from which position to read |
|
302 Arg 2: [in/out] IPC buffer |
|
303 Arg 3: [out] max length of the requested data |
|
304 */ |
|
305 TInt HIpcBuf::IpcReadL(TAny* aPtr, TInt aMaxLength) |
|
306 { |
|
307 __SQLASSERT(aMaxLength >= 0, ESqlPanicInternalError); |
|
308 if(aMaxLength == 0) |
|
309 return 0; |
|
310 |
|
311 TPtr8 des((TUint8*)aPtr, aMaxLength); |
|
312 TInt pos = Pos(ERead); |
|
313 |
|
314 TInt len = __SQLLEAVE_IF_ERROR(iSession.SendReceive(::MakeMsgCode(ESqlSrvStreamRead, ESqlSrvStreamHandle, iHandle), TIpcArgs(0, pos, &des, aMaxLength))); |
|
315 pos += len; |
|
316 if(len < aMaxLength) |
|
317 iBuf.iExt = pos; // end-of-file encountered |
|
318 SetPos(ERead, pos); |
|
319 return len; |
|
320 } |
|
321 |
|
322 /** |
|
323 Write to the server at the current write position. |
|
324 Arg 0: not used |
|
325 Arg 1: [out] from which position to write |
|
326 Arg 2: [in/out] IPC buffer |
|
327 */ |
|
328 void HIpcBuf::IpcWriteL(const TAny* aPtr, TInt aLength) |
|
329 { |
|
330 __SQLASSERT(aLength >= 0, ESqlPanicInternalError); |
|
331 if(aLength == 0) |
|
332 return; |
|
333 |
|
334 TPtrC8 ptr((TUint8*)aPtr, aLength); |
|
335 TInt ext = iBuf.iExt; |
|
336 iBuf.iExt = -1; |
|
337 TInt pos = Pos(EWrite); |
|
338 __SQLLEAVE_IF_ERROR(iSession.SendReceive(::MakeMsgCode(ESqlSrvStreamWrite, ESqlSrvStreamHandle, iHandle), TIpcArgs(0, pos, &ptr))); |
|
339 pos += aLength; |
|
340 if(ext >=0 && pos > ext) |
|
341 iBuf.iExt = pos; |
|
342 SetPos(EWrite, pos); |
|
343 } |
|
344 |
|
345 /** |
|
346 Determine the end of the stream |
|
347 */ |
|
348 TInt HIpcBuf::EndL() |
|
349 { |
|
350 TInt ext = iBuf.iExt; |
|
351 if(ext < 0) |
|
352 { |
|
353 iBuf.iExt = ext = __SQLLEAVE_IF_ERROR(iSession.SendReceive(::MakeMsgCode(ESqlSrvStreamSize, ESqlSrvStreamHandle, iHandle))); |
|
354 } |
|
355 return Max(ext, Mark(EWrite)); |
|
356 } |
|
357 |