|
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 #include <e32debug.h> |
|
17 #include <hal.h> |
|
18 #include <sqldb.h> |
|
19 #include "sqlite3.h" |
|
20 #include "SqlSrvStatementUtil.h" |
|
21 #include "SqlPanic.h" |
|
22 #include "SqlSrvUtil.h" |
|
23 #include "SqlUtil.h" |
|
24 #include "SqliteSymbian.h" //sqlite3SymbianLastOsError() |
|
25 #include "SqlSrvResourceProfiler.h" |
|
26 |
|
27 //The database names in all statements are quoted to avoid the "sql injection" threat. |
|
28 _LIT8(KPageCountPragma, "PRAGMA \"%S\".page_count\x0"); |
|
29 _LIT8(KPageSizePragma, "PRAGMA \"%S\".page_size\x0"); |
|
30 _LIT8(KCacheSizePragma, "PRAGMA \"%S\".cache_size\x0"); |
|
31 _LIT8(KEncodingPragma, "PRAGMA \"%S\".encoding\x0"); |
|
32 _LIT8(KFreePageCountPragma, "PRAGMA \"%S\".freelist_count\x0"); |
|
33 _LIT8(KVacuumModePragma, "PRAGMA \"%S\".auto_vacuum\x0"); |
|
34 _LIT8(KIncrementalVacuumPragma, "PRAGMA \"%S\".incremental_vacuum(%d)\x0"); |
|
35 |
|
36 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
37 |
|
38 #ifdef _NOTIFY |
|
39 static void PrintErrMsg8(TBool aCondition, sqlite3* aDbHandle, const char* aFuncNameZ, const TDesC8& aStmt) |
|
40 { |
|
41 if(!aCondition) |
|
42 { |
|
43 return; |
|
44 } |
|
45 TPtrC8 funcName8(reinterpret_cast <const TUint8*> (aFuncNameZ)); |
|
46 TBuf<32> funcName; |
|
47 funcName.Copy(funcName8); |
|
48 RDebug::Print(_L("###%S\r\n"), &funcName); |
|
49 TInt stmtLen = aStmt.Length(); |
|
50 if(stmtLen > 0) |
|
51 { |
|
52 if(aStmt[stmtLen - 1] == 0) |
|
53 { |
|
54 --stmtLen; |
|
55 } |
|
56 HBufC* buf = HBufC::New(stmtLen); |
|
57 if(buf) |
|
58 { |
|
59 TPtr sqlStmt = buf->Des(); |
|
60 sqlStmt.Copy(aStmt.Left(stmtLen)); |
|
61 if(sqlStmt.Length() > 250) |
|
62 { |
|
63 sqlStmt.SetLength(250); |
|
64 } |
|
65 RDebug::Print(_L("###\"%S\"\r\n"), &sqlStmt); |
|
66 delete buf; |
|
67 } |
|
68 } |
|
69 TBuf<16> tbuf; |
|
70 Util::GetTimeStr(tbuf); |
|
71 const void* errMsg = sqlite3_errmsg16(aDbHandle);//"errMsg" - zero terminated string |
|
72 if(errMsg) |
|
73 { |
|
74 TPtrC msg(reinterpret_cast <const TText16*> (errMsg));//terminating zero character excluded. |
|
75 if(msg.Length() > 230) |
|
76 { |
|
77 msg.Set(msg.Left(230)); |
|
78 } |
|
79 RDebug::Print(_L("##%S#ErrMsg=%S\r\n"), &tbuf, &msg); |
|
80 } |
|
81 else |
|
82 { |
|
83 RDebug::Print(_L("##%S#ErrMsg=null\r\n"), &tbuf); |
|
84 } |
|
85 } |
|
86 |
|
87 static void PrintErrMsg16(TBool aCondition, sqlite3* aDbHandle, const char* aFuncNameZ, const TDesC16& aStmt) |
|
88 { |
|
89 if(!aCondition) |
|
90 { |
|
91 return; |
|
92 } |
|
93 TPtrC8 funcName8(reinterpret_cast <const TUint8*> (aFuncNameZ)); |
|
94 TBuf<32> funcName; |
|
95 funcName.Copy(funcName8); |
|
96 RDebug::Print(_L("###%S\r\n"), &funcName); |
|
97 TInt stmtLen = aStmt.Length(); |
|
98 if(stmtLen > 0) |
|
99 { |
|
100 if(aStmt[stmtLen - 1] == 0) |
|
101 { |
|
102 --stmtLen; |
|
103 } |
|
104 TPtrC sqlStmt(aStmt.Ptr(), stmtLen); |
|
105 if(sqlStmt.Length() > 250) |
|
106 { |
|
107 sqlStmt.Set(sqlStmt.Left(250)); |
|
108 } |
|
109 RDebug::Print(_L("###\"%S\"\r\n"), &sqlStmt); |
|
110 } |
|
111 TBuf<16> tbuf; |
|
112 Util::GetTimeStr(tbuf); |
|
113 const void* errMsg = sqlite3_errmsg16(aDbHandle);//"errMsg" - zero terminated string |
|
114 if(errMsg) |
|
115 { |
|
116 TPtrC msg(reinterpret_cast <const TText16*> (errMsg));//terminating zero character excluded. |
|
117 if(msg.Length() > 230) |
|
118 { |
|
119 msg.Set(msg.Left(230)); |
|
120 } |
|
121 RDebug::Print(_L("##%S#ErrMsg=%S\r\n"), &tbuf, &msg); |
|
122 } |
|
123 else |
|
124 { |
|
125 RDebug::Print(_L("##%S#ErrMsg=null\r\n"), &tbuf); |
|
126 } |
|
127 } |
|
128 |
|
129 #define PRINT_ERRMSG8(Condition, DbHandle, FuncNameZ, Stmt) PrintErrMsg8(Condition, DbHandle, FuncNameZ, Stmt) |
|
130 #define PRINT_ERRMSG16(Condition, DbHandle, FuncNameZ, Stmt) PrintErrMsg16(Condition, DbHandle, FuncNameZ, Stmt) |
|
131 |
|
132 #else //_NOTIFY |
|
133 |
|
134 #define PRINT_ERRMSG8(Condition, DbHandle, FuncNameZ, Stmt) |
|
135 #define PRINT_ERRMSG16(Condition, DbHandle, FuncNameZ, Stmt) |
|
136 |
|
137 #endif //_NOTIFY |
|
138 |
|
139 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
140 |
|
141 //Calls sqlite3_open16() to create or open database file with aFileNameZ. |
|
142 //aFileNameZ is UTF16 encoded, zero-terminated. |
|
143 //The function returns system-wide errors or database specific errors. |
|
144 //The function may panic with code 7 in _DEBUG mode - internal error: the created database handle is NULL. |
|
145 TInt CreateDbHandle16(const TDesC& aFileNameZ, sqlite3*& aDbHandle) |
|
146 { |
|
147 (void)sqlite3SymbianLastOsError();//clear last OS error |
|
148 TInt err = sqlite3_open16(aFileNameZ.Ptr(), &aDbHandle); |
|
149 __SQLASSERT(err == SQLITE_OK ? aDbHandle != NULL : ETrue, ESqlPanicInternalError); |
|
150 if(err == SQLITE_OK) |
|
151 { |
|
152 (void)sqlite3_extended_result_codes(aDbHandle, 0); |
|
153 } |
|
154 //Get the return error code now, because the next "if" may destroy it. |
|
155 TInt rc = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError()); |
|
156 if(err != SQLITE_OK) |
|
157 {//Yes, it is possible error code != SQLITE_OK and aDbHandle != NULL. |
|
158 CloseDbHandle(aDbHandle); |
|
159 aDbHandle = NULL; |
|
160 } |
|
161 return rc; |
|
162 } |
|
163 |
|
164 //Calls sqlite3_open() to create or open database file with aFileNameZ. |
|
165 //aFileNameZ is UTF8 encoded, zero-terminated. |
|
166 //The function returns system-wide errors or database specific errors. |
|
167 //The function may panic with code 7 in _DEBUG mode - internal error: the created database handle is NULL. |
|
168 TInt CreateDbHandle8(const TDesC8& aFileNameZ, sqlite3*& aDbHandle) |
|
169 { |
|
170 (void)sqlite3SymbianLastOsError();//clear last OS error |
|
171 TInt err = sqlite3_open((const char *) aFileNameZ.Ptr(), &aDbHandle); |
|
172 __SQLASSERT(err == SQLITE_OK ? aDbHandle != NULL : ETrue, ESqlPanicInternalError); |
|
173 if(err == SQLITE_OK) |
|
174 { |
|
175 (void)sqlite3_extended_result_codes(aDbHandle, 0); |
|
176 } |
|
177 //Get the return error code now, because the next "if" may destroy it. |
|
178 TInt rc = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError()); |
|
179 if(err != SQLITE_OK) |
|
180 {//Yes, it is possible error code != SQLITE_OK and aDbHandle != NULL. |
|
181 CloseDbHandle(aDbHandle); |
|
182 aDbHandle = NULL; |
|
183 } |
|
184 return rc; |
|
185 } |
|
186 |
|
187 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
188 ///// 16-bit and 8-bit SQL statements execution upon completion //// |
|
189 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
190 |
|
191 //16-bit SQL statement execution. |
|
192 // |
|
193 //aSql - zero-terminated string |
|
194 // |
|
195 //Prepares the supplied as an argument (aSql) 16-bit SQL statement and executes it. |
|
196 //If aSql argument contains more than one SQL statements, separated with ';', then |
|
197 //the function panics in _DEBUG mode (panic code 7). |
|
198 // |
|
199 //The function panics in debug mode (panic code 2) if aDbHandle is NULL. |
|
200 // |
|
201 //If the function completes successfully, it returns SQLITE_ROW or SQLITE_DONE. |
|
202 //If the function fails then it returns one of the SQLITE error codes. |
|
203 static TInt DoSingleStmtExec16(sqlite3 *aDbHandle, const TDesC16& aSql) |
|
204 { |
|
205 __SQLASSERT(aDbHandle != NULL, ESqlPanicInvalidObj); |
|
206 sqlite3_stmt* stmtHandle = NULL; |
|
207 const void* stmtTail = NULL; |
|
208 //sqlite3_prepare16_v2() expects parameter #3 to be one of the following: |
|
209 // - byte length of the sql statement, excluding terminating zero; |
|
210 // - negative value - zero-terminated sql statement; |
|
211 TInt err = sqlite3_prepare16_v2(aDbHandle, aSql.Ptr(), aSql.Length() * sizeof(TUint16) - sizeof(TUint16), &stmtHandle, &stmtTail); |
|
212 __SQLASSERT(err == SQLITE_OK ? !stmtTail || User::StringLength((const TUint16*)stmtTail) == 0 : !stmtHandle, ESqlPanicInternalError); |
|
213 if(stmtHandle) //stmtHandle can be NULL for statements like this: ";". |
|
214 { |
|
215 if(err == SQLITE_OK) |
|
216 { |
|
217 while((err = sqlite3_step(stmtHandle)) == SQLITE_ROW) |
|
218 { |
|
219 } |
|
220 if(err == SQLITE_ERROR) //It may be "out of memory" problem |
|
221 { |
|
222 err = sqlite3_reset(stmtHandle); |
|
223 __SQLASSERT(err != SQLITE_OK, ESqlPanicInternalError); |
|
224 } |
|
225 } |
|
226 TInt err2 = sqlite3_finalize(stmtHandle); |
|
227 if(err == SQLITE_DONE && err2 != SQLITE_OK) |
|
228 {//return the "sqlite3_finalize" error |
|
229 err = err2; |
|
230 } |
|
231 } |
|
232 return err; |
|
233 } |
|
234 |
|
235 /** |
|
236 This function searches aString argument for ';' occurences. |
|
237 Every time when it finds a ';' character, the function places a zero character right after the ';' and |
|
238 tests the just created, zero-terminated substring if it is a comlpete SQL statement. |
|
239 |
|
240 If it is a SQL statement, the function replaces the found ';' character with zero and returns the just created |
|
241 zero-terminated substring.Also the function modifies aString argument to point right after the found |
|
242 SQL string. If it is not SQL statement, the function will continue the searching. |
|
243 |
|
244 If there is no ';' inside aString argument, the function returns the same string as a return result and |
|
245 modifies aString argument - sets it to TPtr(NULL, 0, 0). |
|
246 |
|
247 The function expects aString argument to be zero-terminated. |
|
248 |
|
249 @internalComponent |
|
250 */ |
|
251 TPtrC GetFirstSqlStmt(TPtr& aString) |
|
252 { |
|
253 const TChar KDelimitier(';'); |
|
254 TPtr originalStr(aString); |
|
255 TPtr str(const_cast <TUint16*> (aString.Ptr()), aString.Length(), aString.Length()); |
|
256 TInt afterDelimitierPos = 0; |
|
257 TInt pos; |
|
258 while((pos = str.Locate(KDelimitier) + 1) > 0 && pos < str.Length()) |
|
259 { |
|
260 //There is a possibility that the string, which terminates with the found ';' character, is a SQL statement. |
|
261 //Zero terminate the string placing a zero right after the ';' character and test it using sqlite3_complete16(). |
|
262 //If it is not a SQL string, restore the original character and continue searching. |
|
263 afterDelimitierPos += pos; |
|
264 TChar ch = aString[afterDelimitierPos]; |
|
265 aString[afterDelimitierPos] = 0; |
|
266 TInt res = sqlite3_complete16(aString.Ptr()); |
|
267 aString[afterDelimitierPos] = ch; |
|
268 if(res) |
|
269 { |
|
270 str.Set(const_cast <TUint16*> (aString.Ptr()), afterDelimitierPos, afterDelimitierPos); |
|
271 //Replace the found ';' character with 0. |
|
272 str[afterDelimitierPos - 1] = 0; |
|
273 aString.Set(const_cast <TUint16*> (aString.Ptr()) + afterDelimitierPos, aString.Length() - afterDelimitierPos, aString.Length() - afterDelimitierPos); |
|
274 return str; |
|
275 } |
|
276 str.Set(const_cast <TUint16*> (str.Ptr()) + pos, str.Length() - pos, str.Length() - pos); |
|
277 } |
|
278 //aString argument does not contain valid SQL statement or there is no ';' character inside aString. |
|
279 //Set aString to TPtr(NULL, 0, 0) and return the original string. |
|
280 aString.Set(NULL, 0, 0); |
|
281 str.Set(originalStr); |
|
282 return str; |
|
283 } |
|
284 |
|
285 /** |
|
286 Executes one or more 16-bit SQL statements. SQL statements of any kind can be executed, but the |
|
287 method won't return any record(s) if the SQL statement type is "SELECT". |
|
288 If the SQL statement(s) contains one or more parameters, the method will execute it giving the parameters |
|
289 default NULL values. |
|
290 |
|
291 @param aDbHandle Database handle. Not NULL. |
|
292 @param aSqlStmt String containing one or more 16-bit SQL statements, separated with ';'. Zero-terminated string. |
|
293 Note: The ExecL() call can modify the content of aSqlStmt argument. |
|
294 |
|
295 @return KErrNone, Operation completed successfully; |
|
296 KErrNoMemory, Out of memory; |
|
297 KSqlErrGeneral, Syntax error. A text message describing the problem can be obtained calling |
|
298 RSqlDatabase::LastErrorMessage(); |
|
299 Other system-wide error codes or SQL errors of ESqlDbError type. |
|
300 |
|
301 @panic SqlDb 4 In _DEBUG mode if aSqlStmt is not zero-terminated string |
|
302 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL |
|
303 |
|
304 @internalComponent |
|
305 */ |
|
306 TInt DbExecStmt16(sqlite3 *aDbHandle, TDes16& aSqlStmt) |
|
307 { |
|
308 __SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError); |
|
309 __SQLASSERT(aSqlStmt.Length() > 0 ? (TInt)aSqlStmt[aSqlStmt.Length() - 1] == 0: ETrue, ESqlPanicBadArgument); |
|
310 |
|
311 (void)sqlite3SymbianLastOsError();//clear last OS error |
|
312 |
|
313 TInt err = SQLITE_DONE; |
|
314 //Execute SQL statement(s) |
|
315 //16-bit SQL string - no sqlite3_exec16() function, so the execution is made with |
|
316 //sqlite3_prepare16_v2() and sqlite3_step() functions. |
|
317 TPtr16 sql(const_cast <TUint16*> (aSqlStmt.Ptr()), aSqlStmt.Length(), aSqlStmt.Length()); |
|
318 TPtrC firstSqlStmt(KNullDesC); |
|
319 while(err == SQLITE_DONE && sql.Length() > 1) //"> 1" because it is a zero terminated string |
|
320 { |
|
321 firstSqlStmt.Set(GetFirstSqlStmt(sql)); |
|
322 SQLPROFILER_SQL16_PRINT((TUint)aDbHandle, firstSqlStmt.Left(firstSqlStmt.Length() - 1), EFalse); |
|
323 err = ::DoSingleStmtExec16(aDbHandle, firstSqlStmt); |
|
324 } |
|
325 |
|
326 err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError()); |
|
327 if(err == KSqlAtEnd) |
|
328 { |
|
329 err = KErrNone; |
|
330 } |
|
331 PRINT_ERRMSG16(err <= KSqlErrGeneral, aDbHandle, "DbExecStmt16()", aSqlStmt); |
|
332 return err; |
|
333 } |
|
334 |
|
335 /** |
|
336 Executes one or more 8-bit SQL statements. SQL statements of any kind can be executed, but the |
|
337 method won't return any record(s) if the SQL statement type is "SELECT". |
|
338 If the SQL statement(s) contains one or more parameters, the method will execute it giving the parameters |
|
339 default NULL values. |
|
340 |
|
341 @param aDbHandle Database handle. Not NULL. |
|
342 @param aSqlStmt String containing one or more 8-bit SQL statements, separated with ';'. Zero-terminated string. |
|
343 |
|
344 @return KErrNone, Operation completed successfully; |
|
345 KErrNoMemory, Out of memory; |
|
346 KSqlErrGeneral, Syntax error. A text message describing the problem can be obtained calling |
|
347 RSqlDatabase::LastErrorMessage(); |
|
348 Other system-wide error codes or SQL errors of ESqlDbError type. |
|
349 |
|
350 @panic SqlDb 4 In _DEBUG mode if aSqlStmt is not zero-terminated string |
|
351 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL |
|
352 |
|
353 @internalComponent |
|
354 */ |
|
355 TInt DbExecStmt8(sqlite3 *aDbHandle, const TDesC8& aSqlStmt) |
|
356 { |
|
357 __SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError); |
|
358 __SQLASSERT(aSqlStmt.Length() > 0 ? (TInt)aSqlStmt[aSqlStmt.Length() - 1] == 0: ETrue, ESqlPanicBadArgument); |
|
359 |
|
360 SQLPROFILER_SQL8_PRINT((TUint)aDbHandle, aSqlStmt.Left(aSqlStmt.Length() - 1), EFalse); |
|
361 |
|
362 (void)sqlite3SymbianLastOsError();//clear last OS error |
|
363 |
|
364 TInt err = sqlite3_exec(aDbHandle, reinterpret_cast <const char*> (aSqlStmt.Ptr()), NULL, NULL, NULL); |
|
365 |
|
366 err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError()); |
|
367 if(err == KSqlAtEnd) |
|
368 { |
|
369 err = KErrNone; |
|
370 } |
|
371 PRINT_ERRMSG8(err <= KSqlErrGeneral, aDbHandle, "DbExecStmt8()", aSqlStmt); |
|
372 return err; |
|
373 } |
|
374 |
|
375 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
376 ///// 16-bit and 8-bit SQL statement preparation ///// |
|
377 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
378 |
|
379 //Prepares 16-bit SQL statement, returning in aStmtHandle the statement handle and |
|
380 //setting aHasTail to true, if aStmt contains more than one sql statements. |
|
381 //aStmt - zero-terminated string. |
|
382 //Returns one of SQLITE error codes. |
|
383 static TInt DoPrepareStmt16(sqlite3* aDbHandle, const TDesC& aStmt, sqlite3_stmt** aStmtHandle, TBool& aHasTail) |
|
384 { |
|
385 const void* stmtTail = NULL; |
|
386 //sqlite3_prepare16_v2() expects parameter #3 to be one of the following: |
|
387 // - byte length of the sql statement, excluding terminating zero; |
|
388 // - negative value - zero-terminated sql statement; |
|
389 TInt err = sqlite3_prepare16_v2(aDbHandle, aStmt.Ptr(), aStmt.Length() * sizeof(TUint16) - sizeof(TUint16), aStmtHandle, &stmtTail); |
|
390 aHasTail = stmtTail && static_cast <const TUint16*> (stmtTail)[0] != 0; |
|
391 PRINT_ERRMSG16(err != SQLITE_OK, aDbHandle, "DoPrepareStmt16()", aStmt); |
|
392 __SQLASSERT(err != SQLITE_OK ? !(*aStmtHandle) : ETrue, ESqlPanicInternalError); |
|
393 //(*aStmtHandle) is NULL for ";" statements, when err == SQLITE_OK. Since the server should not panic |
|
394 //that situation is handled later (not inside the assert above) |
|
395 return err; |
|
396 } |
|
397 |
|
398 //Prepares 8-bit SQL statement, returning in aStmtHandle the statement handle and |
|
399 //setting aHasTail to true, if aStmt contains more than one sql statements. |
|
400 //aStmt - zero-terminated string. |
|
401 //Returns one of SQLITE error codes. |
|
402 static TInt DoPrepareStmt8(sqlite3* aDbHandle, const TUint8* aStmt, sqlite3_stmt** aStmtHandle, TBool& aHasTail) |
|
403 { |
|
404 const char* stmtTail = NULL; |
|
405 //sqlite3_prepare_v2() expects parameter #3 to be one of the following: |
|
406 // - byte length of the sql statement; |
|
407 // - negative value - zero-terminated sql statement; |
|
408 TInt err = sqlite3_prepare_v2(aDbHandle, reinterpret_cast <const char*> (aStmt), -1, aStmtHandle, &stmtTail); |
|
409 aHasTail = stmtTail && stmtTail[0] != 0; |
|
410 PRINT_ERRMSG8(err != SQLITE_OK, aDbHandle, "DoPrepareStmt8()", TPtrC8(aStmt, aStmt ? User::StringLength(aStmt) : 0)); |
|
411 __SQLASSERT(err != SQLITE_OK ? !(*aStmtHandle) : ETrue, ESqlPanicInternalError); |
|
412 //(*aStmtHandle) is NULL for ";" statements, when err == SQLITE_OK. Since the server should not panic |
|
413 //that situation is handled later (not inside the assert above) |
|
414 return err; |
|
415 } |
|
416 |
|
417 //This function accepts as arguments the SQLITE error, the length of non-parsed part of the SQL statement |
|
418 //and the statement handle. |
|
419 // |
|
420 //It checks the arguments and returns an error if: |
|
421 // - aSqliteError != SQLITE_OK; |
|
422 // - aHasTail is true (possibly more than one SQL statement, separated with ";"); |
|
423 // - aStmtHandle is NULL; |
|
424 // |
|
425 static TInt ProcessPrepareError(TInt aSqliteError, TBool aHasTail, sqlite3_stmt* aStmtHandle) |
|
426 { |
|
427 if(aSqliteError != SQLITE_OK) |
|
428 { |
|
429 return ::Sql2OsErrCode(aSqliteError, sqlite3SymbianLastOsError()); |
|
430 } |
|
431 else if(aHasTail || !aStmtHandle) |
|
432 {//More than one SQL statement or the SQL string is "" or ";;;" or "; ;; ;". |
|
433 //Report it as an error, because there is no statement handle. |
|
434 return KErrArgument; |
|
435 } |
|
436 return KErrNone; |
|
437 } |
|
438 |
|
439 //This function accepts as arguments the SQLITE error, the length of non-parsed part of the SQL statement |
|
440 //and the statement handle. |
|
441 // |
|
442 //It checks the arguments and leaves if: |
|
443 // - aSqliteError != SQLITE_OK; |
|
444 // - aHasTail is true (possibly more than one SQL statement, separated with ";"); |
|
445 // - aStmtHandle is NULL; |
|
446 // |
|
447 static void LeaveIfPrepareErrorL(TInt aSqliteError, TBool aHasTail, sqlite3_stmt* aStmtHandle) |
|
448 { |
|
449 __SQLLEAVE_IF_ERROR(ProcessPrepareError(aSqliteError, aHasTail, aStmtHandle)); |
|
450 } |
|
451 |
|
452 /** |
|
453 Prepares 16-bit aSqlStmt SQL statement. |
|
454 |
|
455 @param aSqlStmt - zero-terminated string. |
|
456 |
|
457 @leave KErrNoMemory, if there is no memory; |
|
458 KErrArgument, if the SQL string contains more than one SQL statements; |
|
459 One of the error codes in [KSqlErrGeneral..KSqlErrNotDb] range. |
|
460 |
|
461 @return The prepared SQL statement handle. |
|
462 |
|
463 @internalComponent |
|
464 */ |
|
465 sqlite3_stmt* StmtPrepare16L(sqlite3* aDbHandle, const TDesC16& aSqlStmt) |
|
466 { |
|
467 SQLPROFILER_SQL16_PRINT((TUint)aDbHandle, aSqlStmt.Left(aSqlStmt.Length() - 1), ETrue); |
|
468 |
|
469 (void)sqlite3SymbianLastOsError();//clear last OS error |
|
470 TBool hasTail = EFalse; |
|
471 sqlite3_stmt* stmtHandle = NULL; |
|
472 TInt err = DoPrepareStmt16(aDbHandle, aSqlStmt, &stmtHandle, hasTail); |
|
473 LeaveIfPrepareErrorL(err, hasTail, stmtHandle); |
|
474 return stmtHandle; |
|
475 } |
|
476 |
|
477 /** |
|
478 Prepares 8-bit aSqlStmt SQL statement. |
|
479 |
|
480 @param aSqlStmt - zero-terminated string. |
|
481 |
|
482 @leave KErrNoMemory, if there is no memory; |
|
483 KErrArgument, if the SQL string contains more than one SQL statements; |
|
484 One of the error codes in [KSqlErrGeneral..KSqlErrNotDb] range. |
|
485 |
|
486 @return The prepared SQL statement handle. |
|
487 |
|
488 @internalComponent |
|
489 */ |
|
490 TInt StmtPrepare8(sqlite3* aDbHandle, const TDesC8& aSqlStmt, sqlite3_stmt*& aStmtHandle) |
|
491 { |
|
492 SQLPROFILER_SQL8_PRINT((TUint)aDbHandle, aSqlStmt.Left(aSqlStmt.Length() - 1), ETrue); |
|
493 |
|
494 (void)sqlite3SymbianLastOsError();//clear last OS error |
|
495 TBool hasTail = EFalse; |
|
496 TInt err = DoPrepareStmt8(aDbHandle, aSqlStmt.Ptr(), &aStmtHandle, hasTail); |
|
497 return ProcessPrepareError(err, hasTail, aStmtHandle); |
|
498 } |
|
499 |
|
500 /** |
|
501 Prepares 8-bit aSqlStmt SQL statement. |
|
502 |
|
503 @param aSqlStmt - zero-terminated string. |
|
504 |
|
505 @leave KErrNoMemory, if there is no memory; |
|
506 KErrArgument, if the SQL string contains more than one SQL statements; |
|
507 One of the error codes in [KSqlErrGeneral..KSqlErrNotDb] range. |
|
508 |
|
509 @return The prepared SQL statement handle. |
|
510 |
|
511 @internalComponent |
|
512 */ |
|
513 sqlite3_stmt* StmtPrepare8L(sqlite3* aDbHandle, const TDesC8& aSqlStmt) |
|
514 { |
|
515 SQLPROFILER_SQL8_PRINT((TUint)aDbHandle, aSqlStmt.Left(aSqlStmt.Length() - 1), ETrue); |
|
516 |
|
517 (void)sqlite3SymbianLastOsError();//clear last OS error |
|
518 TBool hasTail = EFalse; |
|
519 sqlite3_stmt* stmtHandle = NULL; |
|
520 TInt err = DoPrepareStmt8(aDbHandle, aSqlStmt.Ptr(), &stmtHandle, hasTail); |
|
521 LeaveIfPrepareErrorL(err, hasTail, stmtHandle); |
|
522 return stmtHandle; |
|
523 } |
|
524 |
|
525 /** |
|
526 Executes upon completion the prepared SQL statement. |
|
527 |
|
528 @param aStmtHandle Prepared statement handle |
|
529 |
|
530 @return KSqlErrStmtExpired, Statement expired (if new functions or collating sequences are |
|
531 registered or if an authorizer function is added or changed); |
|
532 KErrNoMemory, Out of memory. The statement will be reset; |
|
533 KErrNone, The reset operation completed successfully. |
|
534 |
|
535 @panic SqlDb 2 In _DEBUG mode. Invalid (NULL) statement handle. |
|
536 @panic SqlDb 7 In _DEBUG mode. SQLITE internal error. (SQLITE_ERROR, followed by a sqlite3_reset(), which returns SQLITE_OK) |
|
537 |
|
538 @internalComponent |
|
539 */ |
|
540 TInt StmtExec(sqlite3_stmt* aStmtHandle) |
|
541 { |
|
542 __SQLASSERT(aStmtHandle != NULL, ESqlPanicInvalidObj); |
|
543 |
|
544 (void)sqlite3SymbianLastOsError();//clear last OS error |
|
545 |
|
546 if(sqlite3_expired(aStmtHandle)) |
|
547 { |
|
548 return KSqlErrStmtExpired; |
|
549 } |
|
550 |
|
551 TInt err; |
|
552 while((err = sqlite3_step(aStmtHandle)) == SQLITE_ROW) |
|
553 { |
|
554 } |
|
555 |
|
556 if(err == SQLITE_ERROR) //It may be "out of memory" problem |
|
557 { |
|
558 err = sqlite3_reset(aStmtHandle); |
|
559 __SQLASSERT(err != SQLITE_OK, ESqlPanicInternalError); |
|
560 } |
|
561 |
|
562 err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError()); |
|
563 if(err == KSqlAtEnd) |
|
564 { |
|
565 err = KErrNone; |
|
566 } |
|
567 |
|
568 PRINT_ERRMSG16(err <= KSqlErrGeneral, sqlite3_db_handle(aStmtHandle), "StmtExec()", _L(" ")); |
|
569 return err; |
|
570 } |
|
571 |
|
572 /** |
|
573 Executes the SQL statement moving it to the next row if available. |
|
574 |
|
575 @return KSqlErrStmtExpired Statement expired (if new functions or collating sequences are |
|
576 registered or if an authorizer function is added or changed) |
|
577 @return KSqlAtRow, The next record data is ready for processing by the caller; |
|
578 KSqlAtEnd, No more record data; |
|
579 KSqlErrBusy, Database file is locked; |
|
580 KSqlErrGeneral, Run-time error. Next() should not be called anymore; |
|
581 KSqlErrMisuse, Next() called after KSqlAtEnd or KSqlErrGeneral returned by the previous Next() call; |
|
582 KErrNoMemory, Out of memory. The statement will be reset. |
|
583 |
|
584 @panic SqlDb 2 In _DEBUG mode. Invalid (NULL) statement handle. |
|
585 @panic SqlDb 7 In _DEBUG mode. SQLITE internal error. (SQLITE_ERROR, followed by a sqlite3_reset(), which returns SQLITE_OK) |
|
586 |
|
587 @internalComponent |
|
588 */ |
|
589 TInt StmtNext(sqlite3_stmt* aStmtHandle) |
|
590 { |
|
591 __SQLASSERT(aStmtHandle != NULL, ESqlPanicInvalidObj); |
|
592 |
|
593 (void)sqlite3SymbianLastOsError();//clear last OS error |
|
594 |
|
595 if(sqlite3_expired(aStmtHandle)) |
|
596 { |
|
597 return KSqlErrStmtExpired; |
|
598 } |
|
599 |
|
600 TInt err = sqlite3_step(aStmtHandle); |
|
601 if(err == SQLITE_ERROR) //It may be "out of memory" problem |
|
602 { |
|
603 err = sqlite3_reset(aStmtHandle); |
|
604 __SQLASSERT(err != SQLITE_OK, ESqlPanicInternalError); |
|
605 } |
|
606 err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError()); |
|
607 PRINT_ERRMSG16(err <= KSqlErrGeneral, sqlite3_db_handle(aStmtHandle), "StmtNext()", _L(" ")); |
|
608 return err; |
|
609 } |
|
610 |
|
611 /** |
|
612 Resets the prepared SQL statement to its initial state and makes it ready to be executed again. |
|
613 Any SQL statement parameters that had values bound to them, retain their values. |
|
614 |
|
615 @return KSqlErrStmtExpired, Statement expired (if new functions or collating sequences are |
|
616 registered or if an authorizer function is added or changed); |
|
617 KErrNone, The reset operation completed successfully. |
|
618 |
|
619 @panic SqlDb 2 In _DEBUG mode. Invalid (NULL) statement handle. |
|
620 |
|
621 @internalComponent |
|
622 */ |
|
623 TInt StmtReset(sqlite3_stmt* aStmtHandle) |
|
624 { |
|
625 __SQLASSERT(aStmtHandle != NULL, ESqlPanicInvalidObj); |
|
626 |
|
627 (void)sqlite3SymbianLastOsError();//clear last OS error |
|
628 |
|
629 if(sqlite3_expired(aStmtHandle)) |
|
630 { |
|
631 return KSqlErrStmtExpired; |
|
632 } |
|
633 |
|
634 TInt err = sqlite3_reset(aStmtHandle); |
|
635 return ::Sql2OsErrCode(err, sqlite3SymbianLastOsError()); |
|
636 } |
|
637 |
|
638 /** |
|
639 Prepares and executes PRAGMA statement and moves the statement cursor on the first row. |
|
640 |
|
641 @param aDbHandle Database handle |
|
642 @param aDbName Attached database name or KNullDesC for the main database |
|
643 @param aPragmaSql Pragma sql statement |
|
644 @param aStmtHandle An output parameter where the statement handle will be stored |
|
645 |
|
646 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL |
|
647 @panic SqlDb 4 In _DEBUG mode if aPragmaSql length is 0 or if the statement is not zero-terminated |
|
648 |
|
649 @return KErrNone, Operation completed successfully; |
|
650 KErrNoMemory, Out of memory; |
|
651 Other system-wide error codes or SQL errors of ESqlDbError type. |
|
652 |
|
653 @internalComponent |
|
654 */ |
|
655 static TInt PreRetrievePragmaValue(sqlite3* aDbHandle, const TDesC& aDbName, const TDesC8& aPragmaSql, sqlite3_stmt*& aStmtHandle) |
|
656 { |
|
657 __SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError); |
|
658 __SQLASSERT(aPragmaSql.Length() > 0, ESqlPanicBadArgument); |
|
659 __SQLASSERT(aPragmaSql[aPragmaSql.Length() - 1] == 0, ESqlPanicBadArgument); |
|
660 TBuf8<KMaxFileName> dbName; |
|
661 if(!UTF16ToUTF8(aDbName, dbName)) |
|
662 { |
|
663 return KErrGeneral; |
|
664 } |
|
665 TBuf8<KMaxFileName + 64> sql;//64 characters is enough for the longest PRAGMA statement |
|
666 if(dbName == KNullDesC8) |
|
667 { |
|
668 sql.Format(aPragmaSql, &KMainDb8); |
|
669 } |
|
670 else |
|
671 { |
|
672 sql.Format(aPragmaSql, &dbName); |
|
673 } |
|
674 aStmtHandle = NULL; |
|
675 TInt err = ::StmtPrepare8(aDbHandle, sql, aStmtHandle); |
|
676 if(err == KErrNone) |
|
677 { |
|
678 __SQLASSERT(aStmtHandle != NULL, ESqlPanicInvalidObj); |
|
679 err = ::StmtNext(aStmtHandle); |
|
680 } |
|
681 PRINT_ERRMSG8(err <= KSqlErrGeneral, aDbHandle, "PreRetrievePragmaValue()", sql); |
|
682 return err; |
|
683 } |
|
684 |
|
685 /** |
|
686 Prepares and executes PRAGMA statement and retrieves the value of column 0 (the pragma value). |
|
687 |
|
688 @param aDbHandle Database handle |
|
689 @param aDbName Attached database name or KNullDesC for the main database |
|
690 @param aPragmaSql Pragma sql statement |
|
691 @param aPragmaValue An output parameter where the pragma value will be stored |
|
692 |
|
693 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL |
|
694 @panic SqlDb 4 In _DEBUG mode if aPragmaSql length is 0 or if the statement is not zero-terminated |
|
695 |
|
696 @return KErrNone, Operation completed successfully; |
|
697 KErrNoMemory, Out of memory; |
|
698 Other system-wide error codes or SQL errors of ESqlDbError type. |
|
699 |
|
700 @internalComponent |
|
701 */ |
|
702 static TInt RetrievePragmaValue(sqlite3* aDbHandle, const TDesC& aDbName, const TDesC8& aPragmaSql, TInt& aPragmaValue) |
|
703 { |
|
704 __SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError); |
|
705 __SQLASSERT(aPragmaSql.Length() > 0, ESqlPanicBadArgument); |
|
706 __SQLASSERT(aPragmaSql[aPragmaSql.Length() - 1] == 0, ESqlPanicBadArgument); |
|
707 sqlite3_stmt* stmtHandle = NULL; |
|
708 TInt err = PreRetrievePragmaValue(aDbHandle, aDbName, aPragmaSql, stmtHandle); |
|
709 if(err == KSqlAtRow) |
|
710 { |
|
711 aPragmaValue = sqlite3_column_int(stmtHandle, 0); |
|
712 __SQLASSERT(aPragmaValue >= 0, ESqlPanicInternalError); |
|
713 err = KErrNone; |
|
714 } |
|
715 TInt err2 = FinalizeStmtHandle(stmtHandle); |
|
716 if(err == KErrNone && err2 != KErrNone) |
|
717 {//FinalizeStmtHandle() has failed |
|
718 err = err2; |
|
719 } |
|
720 return err; |
|
721 } |
|
722 |
|
723 /** |
|
724 Prepares and executes PRAGMA statement and retrieves the value of column 0 (the pragma value) as text. |
|
725 |
|
726 @param aDbHandle Database handle |
|
727 @param aDbName Attached database name or KNullDesC for the main database |
|
728 @param aPragmaSql Pragma sql statement |
|
729 @param aPragmaValue An output parameter where the pragma value will be stored (as text) |
|
730 |
|
731 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL |
|
732 @panic SqlDb 4 In _DEBUG mode if aPragmaSql length is 0 or if the statement is not zero-terminated |
|
733 |
|
734 @return KErrNone, Operation completed successfully; |
|
735 KErrNoMemory, Out of memory; |
|
736 Other system-wide error codes or SQL errors of ESqlDbError type. |
|
737 |
|
738 @internalComponent |
|
739 */ |
|
740 static TInt RetrievePragmaValue(sqlite3* aDbHandle, const TDesC& aDbName, const TDesC8& aPragmaSql, TDes8& aPragmaValue) |
|
741 { |
|
742 __SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError); |
|
743 __SQLASSERT(aPragmaSql.Length() > 0, ESqlPanicBadArgument); |
|
744 __SQLASSERT(aPragmaSql[aPragmaSql.Length() - 1] == 0, ESqlPanicBadArgument); |
|
745 sqlite3_stmt* stmtHandle = NULL; |
|
746 TInt err = PreRetrievePragmaValue(aDbHandle, aDbName, aPragmaSql, stmtHandle); |
|
747 if(err == KSqlAtRow) |
|
748 { |
|
749 TPtrC8 ptr(sqlite3_column_text(stmtHandle, 0)); |
|
750 aPragmaValue.Copy(ptr); |
|
751 err = KErrNone; |
|
752 } |
|
753 TInt err2 = FinalizeStmtHandle(stmtHandle); |
|
754 if(err == KErrNone && err2 != KErrNone) |
|
755 {//::FinalizeStmtHandle() has failed |
|
756 err = err2; |
|
757 } |
|
758 return err; |
|
759 } |
|
760 |
|
761 /** |
|
762 Retrieves the database pages count. |
|
763 |
|
764 @param aDbHandle Database handle |
|
765 @param aDbName Attached database name or KNullDesC for the main database |
|
766 @param aPageCount An output parameter where the database pages count will be stored |
|
767 |
|
768 @return KErrNone, Operation completed successfully; |
|
769 KErrNoMemory, Out of memory; |
|
770 Other system-wide error codes or SQL errors of ESqlDbError type. |
|
771 |
|
772 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL |
|
773 |
|
774 @internalComponent |
|
775 */ |
|
776 TInt DbPageCount(sqlite3* aDbHandle, const TDesC& aDbName, TInt& aPageCount) |
|
777 { |
|
778 __SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError); |
|
779 return RetrievePragmaValue(aDbHandle, aDbName, KPageCountPragma, aPageCount); |
|
780 } |
|
781 |
|
782 /** |
|
783 Retrieves the database page size. |
|
784 |
|
785 @param aDbHandle Database handle |
|
786 @param aDbName Attached database name or KNullDesC for the main database |
|
787 @param aPageSize An output parameter where the page size will be stored |
|
788 |
|
789 @return KErrNone, Operation completed successfully; |
|
790 KErrNoMemory, Out of memory; |
|
791 Other system-wide error codes or SQL errors of ESqlDbError type. |
|
792 |
|
793 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL |
|
794 |
|
795 @internalComponent |
|
796 */ |
|
797 TInt DbPageSize(sqlite3* aDbHandle, const TDesC& aDbName, TInt& aPageSize) |
|
798 { |
|
799 __SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError); |
|
800 return RetrievePragmaValue(aDbHandle, aDbName, KPageSizePragma, aPageSize); |
|
801 } |
|
802 |
|
803 /** |
|
804 Retrieves the database cache size in pages. |
|
805 |
|
806 @param aDbHandle Database handle |
|
807 @param aDbName Attached database name or KNullDesC for the main database |
|
808 @param aCacheSize An output parameter where the cache size will be stored |
|
809 |
|
810 @return KErrNone, Operation completed successfully; |
|
811 KErrNoMemory, Out of memory; |
|
812 Other system-wide error codes or SQL errors of ESqlDbError type. |
|
813 |
|
814 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL |
|
815 |
|
816 @internalComponent |
|
817 */ |
|
818 TInt DbCacheSize(sqlite3* aDbHandle, const TDesC& aDbName, TInt& aCacheSize) |
|
819 { |
|
820 __SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError); |
|
821 return RetrievePragmaValue(aDbHandle, aDbName, KCacheSizePragma, aCacheSize); |
|
822 } |
|
823 |
|
824 /** |
|
825 Retrieves the database encoding. |
|
826 |
|
827 @param aDbHandle Database handle |
|
828 @param aDbName Attached database name or KNullDesC for the main database |
|
829 @param aEncoding An output parameter where the encoding type will be stored (as text) |
|
830 |
|
831 @return KErrNone, Operation completed successfully; |
|
832 KErrNoMemory, Out of memory; |
|
833 Other system-wide error codes or SQL errors of ESqlDbError type. |
|
834 |
|
835 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL |
|
836 |
|
837 @internalComponent |
|
838 */ |
|
839 TInt DbEncoding(sqlite3* aDbHandle, const TDesC& aDbName, TDes8& aEncoding) |
|
840 { |
|
841 __SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError); |
|
842 return RetrievePragmaValue(aDbHandle, aDbName, KEncodingPragma, aEncoding); |
|
843 } |
|
844 |
|
845 /** |
|
846 Retrieves the database free pages count. |
|
847 |
|
848 @param aDbHandle Database handle |
|
849 @param aDbName Attached database name or KNullDesC for the main database |
|
850 @param aPageCount An output parameter where the free pages count will be stored |
|
851 |
|
852 @return KErrNone, Operation completed successfully; |
|
853 KErrNoMemory, Out of memory; |
|
854 Other system-wide error codes or SQL errors of ESqlDbError type. |
|
855 |
|
856 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL |
|
857 |
|
858 @internalComponent |
|
859 */ |
|
860 TInt DbFreePageCount(sqlite3* aDbHandle, const TDesC& aDbName, TInt& aPageCount) |
|
861 { |
|
862 __SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError); |
|
863 return RetrievePragmaValue(aDbHandle, aDbName, KFreePageCountPragma, aPageCount); |
|
864 } |
|
865 |
|
866 /** |
|
867 Retrieves the current vacuum mode of the database. |
|
868 |
|
869 @param aDbHandle Database handle |
|
870 @param aDbName Attached database name or KNullDesC for the main database |
|
871 @param aVacuumMode An output parameter where the current vacuum mode will be stored |
|
872 |
|
873 @return KErrNone, Operation completed successfully; |
|
874 KErrNoMemory, Out of memory; |
|
875 Other system-wide error codes or SQL errors of ESqlDbError type. |
|
876 |
|
877 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL |
|
878 |
|
879 @internalComponent |
|
880 */ |
|
881 TInt DbVacuumMode(sqlite3* aDbHandle, const TDesC& aDbName, TInt& aVacuumMode) |
|
882 { |
|
883 __SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError); |
|
884 return RetrievePragmaValue(aDbHandle, aDbName, KVacuumModePragma, aVacuumMode); |
|
885 } |
|
886 |
|
887 static TBool IsCompactTimeLimitReached(TUint32 aStartTicks, TUint32 aCurrTicks, TInt aMaxTime) |
|
888 { |
|
889 __SQLASSERT(aMaxTime > 0, ESqlPanicBadArgument); |
|
890 TInt64 tickDiff64 = (TInt64)aCurrTicks - (TInt64)aStartTicks; |
|
891 if(tickDiff64 < 0) |
|
892 { |
|
893 tickDiff64 = KMaxTUint32 + tickDiff64 + 1; |
|
894 } |
|
895 static TInt freq = 0; |
|
896 TInt err = KErrNone; |
|
897 if(freq == 0) |
|
898 { |
|
899 err = HAL::Get(HAL::EFastCounterFrequency, freq); |
|
900 } |
|
901 if(err == KErrNone && freq > 0) |
|
902 { |
|
903 const TInt KMicroSecIn1Sec = 1000000; |
|
904 const TInt KMicroSecIn1Ms = 1000; |
|
905 TInt64 usDiff64 = (tickDiff64 * KMicroSecIn1Sec) / freq; |
|
906 if(usDiff64 > aMaxTime * KMicroSecIn1Ms) |
|
907 { |
|
908 return ETrue; |
|
909 } |
|
910 } |
|
911 return EFalse; |
|
912 } |
|
913 |
|
914 /** |
|
915 Compacts the database. |
|
916 |
|
917 @param aDbHandle Database handle. |
|
918 @param aPageCount Count of the free database pages to be removed from the file. |
|
919 @param aProcessedPageCount Output parameter. How many pages actually have been removed from the file. |
|
920 @param aMaxTime The max allowed time in milliseconds for the compact operation. |
|
921 If aMaxTime is zero, then aPageCount pages will be removed regardless the time. |
|
922 |
|
923 @return KErrNone, Operation completed successfully; |
|
924 Other system-wide error codes or SQL errors of ESqlDbError type. |
|
925 |
|
926 @panic SqlDb 4 In _DEBUG mode if aPageCount is negative |
|
927 @panic SqlDb 4 In _DEBUG mode if aMaxTime is negative |
|
928 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL |
|
929 |
|
930 @internalComponent |
|
931 */ |
|
932 TInt DbCompact(sqlite3* aDbHandle, const TDesC& aDbName, TInt aPageCount, TInt& aProcessedPageCount, TInt aMaxTime) |
|
933 { |
|
934 __SQLASSERT(aPageCount >= 0, ESqlPanicBadArgument); |
|
935 __SQLASSERT(aMaxTime >= 0, ESqlPanicBadArgument); |
|
936 __SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError); |
|
937 TBuf8<KMaxFileName> dbName; |
|
938 if(!UTF16ToUTF8(aDbName, dbName)) |
|
939 { |
|
940 return KErrGeneral; |
|
941 } |
|
942 TBuf8<KMaxFileName + sizeof(KIncrementalVacuumPragma) + 1> sql; |
|
943 if(dbName == KNullDesC8) |
|
944 { |
|
945 sql.Format(KIncrementalVacuumPragma, &KMainDb8, aPageCount); |
|
946 } |
|
947 else |
|
948 { |
|
949 sql.Format(KIncrementalVacuumPragma, &dbName, aPageCount); |
|
950 } |
|
951 //Currently there is no way to check how many pages have been compacted without executing a "PRAGMA freelist_count" |
|
952 //statement, if sqlite3_exec() is used. |
|
953 //So, instead of calling sqlite3_exec(), the function prepares and executes the "PRAGMA incremental_vacuum(N)" |
|
954 //statement using sqlite3_step() and counts the steps, because each step compacts one page. |
|
955 (void)sqlite3SymbianLastOsError();//clear last OS error |
|
956 sqlite3_stmt* stmtHandle = NULL; |
|
957 const char* stmtTail = NULL; |
|
958 aProcessedPageCount = 0; |
|
959 //sqlite3_prepare16() expects parameter #3 to be one of the following: |
|
960 // - byte length of the sql statement, excluding terminating zero; |
|
961 // - negative value - zero-terminated sql statement; |
|
962 TInt err = sqlite3_prepare_v2(aDbHandle, (const char*)sql.Ptr(), sql.Length() - sizeof(TUint8), &stmtHandle, &stmtTail); |
|
963 __SQLASSERT(err == SQLITE_OK ? !stmtTail || User::StringLength((const TUint8*)stmtTail) == 0 : !stmtHandle, ESqlPanicInternalError); |
|
964 if(stmtHandle) //stmtHandle can be NULL for statements like this: ";". |
|
965 { |
|
966 if(err == SQLITE_OK) |
|
967 { |
|
968 TUint32 startTicks = 0; |
|
969 if(aMaxTime > 0) |
|
970 { |
|
971 startTicks = User::FastCounter(); |
|
972 } |
|
973 while((err = sqlite3_step(stmtHandle)) == SQLITE_ROW) |
|
974 { |
|
975 ++aProcessedPageCount; |
|
976 if(aMaxTime > 0 && IsCompactTimeLimitReached(startTicks, User::FastCounter(), aMaxTime)) |
|
977 { |
|
978 err = SQLITE_DONE;//The statement execution did not complete because of the time limit |
|
979 break; |
|
980 } |
|
981 } |
|
982 if(err == SQLITE_ERROR) //It may be "out of memory" problem |
|
983 { |
|
984 err = sqlite3_reset(stmtHandle); |
|
985 __SQLASSERT(err != SQLITE_OK, ESqlPanicInternalError); |
|
986 } |
|
987 } |
|
988 TInt err2 = sqlite3_finalize(stmtHandle); |
|
989 if(err == SQLITE_DONE && err2 != SQLITE_OK) |
|
990 {//use the "sqlite3_finalize" error |
|
991 err = err2; |
|
992 } |
|
993 } |
|
994 err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError()); |
|
995 if(err == KSqlAtEnd) |
|
996 { |
|
997 err = KErrNone; |
|
998 } |
|
999 PRINT_ERRMSG8(err <= KSqlErrGeneral, aDbHandle, "DbCompact()", sql); |
|
1000 return err; |
|
1001 } |
|
1002 |
|
1003 /** |
|
1004 Finalizes the statement handle. |
|
1005 |
|
1006 @internalComponent |
|
1007 */ |
|
1008 TInt FinalizeStmtHandle(sqlite3_stmt* aStmtHandle) |
|
1009 { |
|
1010 TInt err = KErrNone; |
|
1011 if(aStmtHandle) |
|
1012 { |
|
1013 (void)sqlite3SymbianLastOsError();//clear last OS error |
|
1014 err = sqlite3_finalize(aStmtHandle); |
|
1015 err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError()); |
|
1016 } |
|
1017 return err; |
|
1018 } |