35 #include <nsIAppStartup.h>
37 #include <nsILocalFile.h>
38 #include <nsStringGlue.h>
39 #include <nsIObserverService.h>
40 #include <nsISimpleEnumerator.h>
41 #include <nsDirectoryServiceDefs.h>
42 #include <nsAppDirectoryServiceDefs.h>
43 #include <nsDirectoryServiceUtils.h>
44 #include <nsUnicharUtils.h>
46 #include <nsNetUtil.h>
48 #include <nsIPrefService.h>
49 #include <nsIPrefBranch.h>
50 #include <nsXPFEComponentsCID.h>
61 #include <nsIScriptError.h>
62 #include <nsIConsoleService.h>
63 #include <nsIConsoleMessage.h>
65 #include <nsCOMArray.h>
67 #ifdef METRICS_ENABLED
68 #include <sbIMetrics.h>
70 #include <sbIPrompter.h>
81 #define strnicmp strncasecmp
86 #define min(a,b) (((a) < (b)) ? (a) : (b))
89 #define USE_SQLITE_FULL_DISK_CACHING
90 #define USE_SQLITE_READ_UNCOMMITTED
91 #define USE_SQLITE_MEMORY_TEMP_STORE
92 #define USE_SQLITE_BUSY_TIMEOUT
108 #define PREF_BRANCH_BASE "songbird.dbengine."
109 #define PREF_DB_PAGE_SIZE "pageSize"
110 #define PREF_DB_CACHE_SIZE "cacheSize"
111 #define PREF_DB_PREALLOCCACHE_SIZE "preAllocCacheSize"
112 #define PREF_DB_PREALLOCSCRATCH_SIZE "preAllocScratchSize"
113 #define PREF_DB_SOFT_LIMIT "softHeapLimit"
118 #define PREF_SCAN_COMPLETE "songbird.firstrun.scancomplete"
119 #define PREF_BRANCH_LIBRARY_LOADER "songbird.library.loader."
120 #define PREF_MAIN_LIBRARY "songbird.library.main"
121 #define PREF_WEB_LIBRARY "songbird.library.web"
122 #define PREF_DOWNLOAD_LIST "songbird.library.download"
123 #define PREF_PLAYQUEUE_LIBRARY "songbird.library.playqueue"
126 #define PREF_LOADER_DBGUID "databaseGUID"
127 #define PREF_LOADER_DBLOCATION "databaseLocation"
130 #define DBENGINE_GUID_MAIN_LIBRARY "main@library.songbirdnest.com"
131 #define DBENGINE_GUID_WEB_LIBRARY "web@library.songbirdnest.com"
132 #define DBENGINE_GUID_PLAYQUEUE_LIBRARY "playqueue@library.songbirdnest.com"
136 #define DEFAULT_PAGE_SIZE 16384
137 #define DEFAULT_CACHE_SIZE 16000
140 #define DEFAULT_PREALLOCCACHE_SIZE 0
142 #define DEFAULT_PREALLOCSCRATCH_SIZE 0
144 #define SQLITE_MAX_RETRIES 666
145 #define MAX_BUSY_RETRY_CLOSE_DB 10
151 #define IDLE_SERVICE_TIMEOUT (5 * 60)
153 #define ANALYZE_QUERY_THRESHOLD (800)
155 #if defined(_DEBUG) || defined(DEBUG)
159 #define HARD_SANITY_CHECK 1
162 #ifdef USE_PERF_LOGGING
164 class sbDatabaseEnginePerformanceLogger
167 sbDatabaseEnginePerformanceLogger(
const nsAString& aQuery,
168 const nsAString& aGuid);
169 ~sbDatabaseEnginePerformanceLogger();
177 #define BEGIN_PERFORMANCE_LOG(_strQuery, _dbName) \
178 sbDatabaseEnginePerformanceLogger _performanceLogger(_strQuery, _dbName)
180 #define BEGIN_PERFORMANCE_LOG(_strQuery, _dbName)
183 #define NS_FINAL_UI_STARTUP_CATEGORY "final-ui-startup"
198 const char* end = start + length;
199 if (*pos == end || *pos == NULL) {
236 num = (num * 10) + (c -
'0');
251 const char* cA = (
const char*) zA;
252 const char* cB = (
const char*) zB;
253 char* pA = (
char*) cA;
254 char* pB = (
char*) cB;
256 int width = eTextRep == SQLITE_UTF8 ? 1 : 2;
265 while (pA != NULL && pB != NULL) {
267 return a < b ? -1 : 1;
283 return nA > nB ? -1 : 1;
317 const NATIVE_CHAR_TYPE *
p = s;
326 return (*s1 - *(s2 - 1));
344 const NATIVE_CHAR_TYPE *zA,
345 const NATIVE_CHAR_TYPE *zB)
360 return db->
Collate(cBuffers, zA, zB);
365 char *
d = (
char *)aStr;
367 for (
int i=0;
i<len;
i++) {
398 #endif // ifdef LITTLEENDIAN
400 #if defined(XP_UNIX) && !defined(XP_MACOSX)
405 NATIVE_CHAR_TYPE *a =
406 (NATIVE_CHAR_TYPE *)g_utf16_to_ucs4(
414 NATIVE_CHAR_TYPE *b =
415 (NATIVE_CHAR_TYPE *)g_utf16_to_ucs4(
423 #else // XP_UNIX && !XP_MACOSX
434 #if defined(XP_UNIX) && !defined(XP_MACOSX)
468 #endif // ifdef LITTLEENDIAN
470 #if defined(XP_UNIX) && !defined(XP_MACOSX)
475 NATIVE_CHAR_TYPE *a =
476 (NATIVE_CHAR_TYPE *)g_utf16_to_ucs4(
484 NATIVE_CHAR_TYPE *b =
485 (NATIVE_CHAR_TYPE *)g_utf16_to_ucs4(
493 #else // XP_UNIX && !XP_MACOSX
504 #if defined(XP_UNIX) && !defined(XP_MACOSX)
545 CFStringRef cA = CFStringCreateWithBytes(NULL,
548 kCFStringEncodingUTF8,
550 CFStringRef cB = CFStringCreateWithBytes(NULL,
553 kCFStringEncodingUTF8,
556 CFStringGetCharacters(cA, CFRangeMake(0, CFStringGetLength(cA)), a);
557 CFStringGetCharacters(cB, CFRangeMake(0, CFStringGetLength(cB)), b);
559 a[CFStringGetLength(cA)] = 0;
560 b[CFStringGetLength(cB)] = 0;
567 a = (NATIVE_CHAR_TYPE *)g_utf8_to_ucs4((
const gchar *)zA,
572 b = (NATIVE_CHAR_TYPE *)g_utf8_to_ucs4((
const gchar *)zB,
583 PRInt32 cnA = MultiByteToWideChar(CP_UTF8,
591 PRInt32 cnB = MultiByteToWideChar(CP_UTF8,
604 (
const NATIVE_CHAR_TYPE *)a,
605 (
const NATIVE_CHAR_TYPE *)b);
607 #if defined(XP_UNIX) && !defined(XP_MACOSX)
625 nsIFile *aOutputFile);
636 char **azArg,
const char **azCol);
637 static char *
appendText(
char *zIn,
char const *zAppend,
653 nsIFile *aOutputFile)
654 : mOutputFile(aOutputFile)
655 , mEngineCallback(aCallback)
656 , mQueryProcessorQueue(aQueryProcessorQueue)
665 CDatabaseDumpProcessor::Run()
669 do_CreateInstance(
"@mozilla.org/network/file-output-stream;1", &rv);
670 NS_ENSURE_SUCCESS(rv, rv);
673 NS_ENSURE_SUCCESS(rv, rv);
680 nsCString schemaDump;
681 schemaDump.AppendLiteral(
"SELECT name, type, sql FROM sqlite_master "
682 "WHERE sql NOT NULL and type=='table'");
684 if (rc != SQLITE_OK) {
685 return NS_ERROR_FAILURE;
690 tableDump.AppendLiteral(
"SELECT sql FROM sqlite_master "
691 "WHERE sql NOT NULL AND type IN ('index', 'trigger', 'view')");
693 if (rc != SQLITE_OK) {
694 return NS_ERROR_FAILURE;
704 NS_ENSURE_ARG_POINTER(aBuffer);
707 nsCString buffer(aBuffer);
708 if (buffer.Length() > 0) {
710 rv =
mOutputStream->Write(buffer.get(), buffer.Length(), &writeCount);
711 NS_ENSURE_SUCCESS(rv, rv);
725 nsCString query(aQuery);
731 if (rc == SQLITE_CORRUPT) {
732 char *zQ2 = (
char *)malloc(query.Length() + 100);
737 sqlite3_snprintf(
sizeof(zQ2), zQ2,
"%s ORDER BY rowid DESC", query.get());
752 nsCString
select(aSelect);
753 sqlite3_stmt *pSelect;
759 if (rc != SQLITE_OK || !pSelect) {
764 rc = sqlite3_step(pSelect);
765 while (rc == SQLITE_ROW) {
766 rv =
OutputBuffer((
const char *)sqlite3_column_text(pSelect, 0));
767 NS_ENSURE_SUCCESS(rv, rv);
769 NS_ENSURE_SUCCESS(rv, rv);
771 rc = sqlite3_step(pSelect);
774 return sqlite3_finalize(pSelect);
800 if (strcmp(zTable,
"sqlite_sequence") == 0) {
801 dumpProcessor->
OutputBuffer(
"DELETE FROM sqlite_sequence;\n");
803 else if (strcmp(zTable,
"sqlite_stat1") == 0) {
804 dumpProcessor->
OutputBuffer(
"ANALYZE sqlite_master;\n");
806 else if (strncmp(zTable,
"sqlite_", 7) == 0) {
809 else if (strncmp(zSql,
"CREATE VIRTUAL TABLE", 20) == 0) {
812 dumpProcessor->
OutputBuffer(
"PRAGMA writable_schema=ON;\n");
815 zIns = sqlite3_mprintf(
816 "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
817 "VALUES('table','%q','%q',0,'%q');",
818 zTable, zTable, zSql);
829 if (strcmp(zType,
"table") == 0) {
830 sqlite3_stmt *pTableInfo = 0;
832 char *zTableInfo = 0;
835 zTableInfo =
appendText(zTableInfo,
"PRAGMA table_info(", 0);
836 zTableInfo =
appendText(zTableInfo, zTable,
'"');
840 zTableInfo, -1, &pTableInfo, 0);
844 if (rc != SQLITE_OK || !pTableInfo) {
848 zSelect =
appendText(zSelect,
"SELECT 'INSERT INTO ' || ", 0);
853 zSelect =
appendText(zSelect,
" || ' VALUES(' || ", 0);
854 rc = sqlite3_step(pTableInfo);
855 while (rc == SQLITE_ROW) {
856 const char *zText = (
const char *)sqlite3_column_text(pTableInfo, 1);
859 rc = sqlite3_step(pTableInfo);
860 if (rc == SQLITE_ROW) {
861 zSelect =
appendText(zSelect,
") || ',' || ", 0);
867 rc = sqlite3_finalize(pTableInfo);
868 if (rc != SQLITE_OK) {
874 zSelect =
appendText(zSelect,
"|| ')' FROM ", 0);
878 if (rc == SQLITE_CORRUPT) {
879 zSelect =
appendText(zSelect,
" ORDER BY rowid DESC", 0);
900 int nAppend = strlen(zAppend);
901 int nIn = (zIn ? strlen(zIn) : 0);
903 len = nAppend + nIn + 1;
906 for (i = 0; i < nAppend; i++) {
907 if (zAppend[i] == quote) {
913 zIn = (
char *)realloc(zIn, len);
919 char *zCsr = &zIn[nIn];
921 for (i = 0; i < nAppend; i++) {
922 *zCsr++ = zAppend[
i];
923 if (zAppend[i] == quote) {
929 assert((zCsr - zIn) == len);
932 memcpy(&zIn[nIn], zAppend, nAppend);
949 : m_pDBStorePathLock(nsnull)
950 , m_pThreadMonitor(nsnull)
951 , m_CollationBuffersMapMonitor(nsnull)
952 , m_AttemptShutdownOnDestruction(PR_FALSE)
953 , m_IsShutDown(PR_FALSE)
954 , m_MemoryConstraintsSet(PR_FALSE)
955 , m_PromptForDelete(PR_FALSE)
956 , m_DeleteDatabases(PR_FALSE)
957 , m_AddedIdleObserver(PR_FALSE)
958 , m_pPageSpace(nsnull)
959 , m_pScratchSpace(nsnull)
970 if (m_AttemptShutdownOnDestruction)
972 if (m_pDBStorePathLock)
973 PR_DestroyLock(m_pDBStorePathLock);
974 if (m_pThreadMonitor)
975 nsAutoMonitor::DestroyMonitor(m_pThreadMonitor);
976 if (m_CollationBuffersMapMonitor)
977 nsAutoMonitor::DestroyMonitor(m_CollationBuffersMapMonitor);
979 if (m_MemoryConstraintsSet) {
981 NS_Free(m_pPageSpace);
983 if (m_pScratchSpace) {
984 NS_Free(m_pScratchSpace);
1006 NS_ERROR(
"Failed to Init CDatabaseEngine!");
1019 LOG(
"CDatabaseEngine[0x%.8x] - Init() - sqlite version %s",
1020 this, sqlite3_libversion());
1022 PRBool success = m_QueuePool.Init();
1023 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
1026 nsAutoMonitor::NewMonitor(
"CDatabaseEngine.m_pThreadMonitor");
1028 NS_ENSURE_TRUE(m_pThreadMonitor, NS_ERROR_OUT_OF_MEMORY);
1030 m_CollationBuffersMapMonitor =
1031 nsAutoMonitor::NewMonitor(
"CDatabaseEngine.m_CollationBuffersMapMonitor");
1033 NS_ENSURE_TRUE(m_CollationBuffersMapMonitor, NS_ERROR_OUT_OF_MEMORY);
1035 m_pDBStorePathLock = PR_NewLock();
1036 NS_ENSURE_TRUE(m_pDBStorePathLock, NS_ERROR_OUT_OF_MEMORY);
1038 nsresult rv = CreateDBStorePath();
1039 NS_ASSERTION(NS_SUCCEEDED(rv),
"Unable to create db store folder in profile!");
1042 do_GetService(
"@mozilla.org/observer-service;1", &rv);
1043 if(NS_SUCCEEDED(rv)) {
1044 rv = observerService->AddObserver(
this, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
1054 NS_ERROR(
"Unable to register xpcom-shutdown observer");
1055 m_AttemptShutdownOnDestruction = PR_TRUE;
1060 rv = GetCurrentCollationLocale(mCollationLocale);
1065 ::LocaleRefFromLocaleString(mCollationLocale.get(), &l);
1067 ::UCCreateCollator(l,
1068 kUnicodeCollationClass,
1069 kUCCollateStandardOptions |
1070 kUCCollatePunctuationSignificantMask,
1073 setlocale(LC_COLLATE, mCollationLocale.get());
1076 m_pThreadPool = do_CreateInstance(
"@mozilla.org/thread-pool;1", &rv);
1077 NS_ENSURE_SUCCESS(rv, rv);
1079 rv = m_pThreadPool->SetThreadLimit(4);
1080 NS_ENSURE_SUCCESS(rv, rv);
1082 rv = m_pThreadPool->SetIdleThreadLimit(1);
1083 NS_ENSURE_SUCCESS(rv, rv);
1085 rv = m_pThreadPool->SetIdleThreadTimeout(30000);
1086 NS_ENSURE_SUCCESS(rv, rv);
1088 nsCOMPtr<nsIIdleService> idleService =
1089 do_GetService(
"@mozilla.org/widget/idleservice;1", &rv);
1091 if(NS_SUCCEEDED(rv)) {
1093 m_AddedIdleObserver = NS_SUCCEEDED(rv) ? PR_TRUE : PR_FALSE;
1103 NS_ASSERTION(aQueue,
"aQueue is null");
1104 NS_ASSERTION(aClosure,
"aClosure is null");
1107 NS_ENSURE_TRUE(aQueue, PL_DHASH_STOP);
1111 NS_ENSURE_TRUE(aClosure, PL_DHASH_STOP);
1114 PRUint32 *op =
static_cast<PRUint32 *
>(
aClosure);
1118 rv = aQueue->PrepareForShutdown();
1119 NS_ASSERTION(NS_SUCCEEDED(rv),
"Failed to prepare worker thread for shutdown.");
1123 rv = aQueue->Shutdown();
1124 NS_ASSERTION(NS_SUCCEEDED(rv),
"Failed to shut down processor queue.");
1131 return PL_DHASH_NEXT;
1137 m_IsShutDown = PR_TRUE;
1145 m_QueuePool.Clear();
1147 nsresult rv = m_pThreadPool->Shutdown();
1148 NS_ENSURE_SUCCESS(rv, rv);
1150 if(m_AddedIdleObserver) {
1151 nsCOMPtr<nsIIdleService> idleService =
1152 do_GetService(
"@mozilla.org/widget/idleservice;1", &rv);
1153 if(NS_SUCCEEDED(rv)) {
1155 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
1156 "Failed to remove idle service observer.");
1162 ::UCDisposeCollator(&m_Collator);
1165 if(m_PromptForDeleteTimer) {
1166 rv = m_PromptForDeleteTimer->Cancel();
1167 NS_ENSURE_SUCCESS(rv, rv);
1169 m_PromptForDeleteTimer = nsnull;
1176 NS_IMETHODIMP CDatabaseEngine::Observe(
nsISupports *aSubject,
1178 const PRUnichar *
aData)
1180 nsresult rv = NS_ERROR_UNEXPECTED;
1184 do_GetService(
"@mozilla.org/observer-service;1", &rv);
1185 NS_ENSURE_SUCCESS(rv, rv);
1188 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"Remove Observer Failed!");
1190 nsAutoMonitor mon(m_pThreadMonitor);
1191 if(m_PromptForDelete) {
1194 rv = PromptToDeleteDatabases();
1195 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"Prompting to Delete Databases Failed!");
1200 m_PromptForDeleteTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
1201 NS_ENSURE_SUCCESS(rv, rv);
1204 nsAutoMonitor mon(m_pThreadMonitor);
1205 if(m_PromptForDelete) {
1208 rv = PromptToDeleteDatabases();
1209 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"Prompting to Delete Databases Failed!");
1214 else if(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
1215 nsCOMPtr<nsIObserverService> observerService =
1216 do_GetService(
"@mozilla.org/observer-service;1", &rv);
1217 NS_ENSURE_SUCCESS(rv, rv);
1219 rv = observerService->RemoveObserver(
this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
1220 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"Remove Observer Failed!");
1224 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"Shutdown Failed!");
1227 rv = DeleteMarkedDatabases();
1228 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"Failed to delete bad databases!");
1230 else if(!strcmp(aTopic,
"idle")) {
1232 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"Failed to run ANALYZE on Databases.");
1241 nsresult CDatabaseEngine::InitMemoryConstraints()
1243 if (m_MemoryConstraintsSet)
1244 return NS_ERROR_ALREADY_INITIALIZED;
1246 nsresult rv =
NS_OK;
1248 PRInt32 preAllocCache;
1249 PRInt32 preAllocScratch;
1254 nsCOMPtr<nsIPrefService> prefService =
1256 NS_ENSURE_SUCCESS(rv, rv);
1257 nsCOMPtr<nsIPrefBranch> prefBranch;
1259 if (NS_FAILED(rv) ||
1262 NS_WARNING(
"DBEngine failed to get preAllocCache pref. Using default.");
1265 if (NS_FAILED(rv) ||
1267 &preAllocScratch))) {
1268 NS_WARNING(
"DBEngine failed to get preAllocScratch pref. Using default.");
1273 NS_WARNING(
"DBEngine failed to get soft heap limit pref. Using default.");
1278 NS_WARNING(
"DBEngine failed to get page size pref. Using default.");
1284 if (preAllocCache > 0) {
1285 m_pPageSpace = NS_Alloc(pageSize * preAllocCache);
1286 if (!m_pPageSpace) {
1287 return NS_ERROR_OUT_OF_MEMORY;
1289 ret = sqlite3_config(SQLITE_CONFIG_PAGECACHE, m_pPageSpace,
1290 pageSize, preAllocCache);
1291 NS_ENSURE_TRUE(ret == SQLITE_OK, NS_ERROR_FAILURE);
1294 if (preAllocScratch > 0) {
1297 PRInt32 scratchSlotSize = pageSize * 6;
1298 m_pScratchSpace = NS_Alloc(scratchSlotSize * preAllocScratch);
1299 if (!m_pScratchSpace) {
1300 return NS_ERROR_OUT_OF_MEMORY;
1302 ret = sqlite3_config(SQLITE_CONFIG_SCRATCH, m_pScratchSpace,
1303 scratchSlotSize, preAllocScratch);
1304 NS_ENSURE_TRUE(ret == SQLITE_OK, NS_ERROR_FAILURE);
1308 if (softLimit > 0) {
1309 sqlite3_soft_heap_limit(softLimit);
1313 m_MemoryConstraintsSet = PR_TRUE;
1319 nsresult CDatabaseEngine::GetDBPrefs(
const nsAString &dbGUID,
1323 nsresult rv =
NS_OK;
1325 nsCOMPtr<nsIPrefService> prefService =
1327 NS_ENSURE_SUCCESS(rv, rv);
1328 nsCOMPtr<nsIPrefBranch> prefBranch;
1333 NS_WARNING(
"DBEngine failed to get cache size pref. Using default.");
1339 NS_WARNING(
"DBEngine failed to get page size pref. Using default.");
1346 dbBranch.Append(NS_ConvertUTF16toUTF8(dbGUID));
1347 dbBranch.Append(NS_LITERAL_CSTRING(
"."));
1348 if (NS_SUCCEEDED(prefService->GetBranch(dbBranch.get(),
1349 getter_AddRefs(prefBranch)))) {
1360 sqlite3 ** ppHandle)
1362 sqlite3 *pHandle = nsnull;
1364 nsAutoString strFilename;
1365 GetDBStorePath(dbGUID, pQuery, strFilename);
1367 #if defined(USE_SQLITE_SHARED_CACHE)
1368 sqlite3_enable_shared_cache(1);
1372 if (!m_MemoryConstraintsSet) {
1373 if (NS_FAILED(InitMemoryConstraints())) {
1374 NS_WARNING(
"DBEngine failed to set memory usage constraints.");
1378 PRInt32 ret = sqlite3_open(NS_ConvertUTF16toUTF8(strFilename).
get(), &pHandle);
1379 NS_ASSERTION(ret == SQLITE_OK,
"Failed to open database: sqlite_open failed!");
1380 NS_ENSURE_TRUE(ret == SQLITE_OK, NS_ERROR_UNEXPECTED);
1382 ret = sqlite3_create_collation(pHandle,
1387 NS_ASSERTION(ret == SQLITE_OK,
"Failed to set tree collate function: utf16-be!");
1388 NS_ENSURE_TRUE(ret == SQLITE_OK, NS_ERROR_UNEXPECTED);
1390 ret = sqlite3_create_collation(pHandle,
1395 NS_ASSERTION(ret == SQLITE_OK,
"Failed to set tree collate function: utf16-le!");
1396 NS_ENSURE_TRUE(ret == SQLITE_OK, NS_ERROR_UNEXPECTED);
1398 ret = sqlite3_create_collation(pHandle,
1403 NS_ASSERTION(ret == SQLITE_OK,
"Failed to set tree collate function: utf8!");
1404 NS_ENSURE_TRUE(ret == SQLITE_OK, NS_ERROR_UNEXPECTED);
1409 nsAutoMonitor mon(m_CollationBuffersMapMonitor);
1410 m_CollationBuffersMap[pHandle] = collationBuffersEntry;
1413 ret = sqlite3_create_collation(pHandle,
1416 collationBuffersEntry,
1418 NS_ASSERTION(ret == SQLITE_OK,
"Failed to set library collate function: utf8!");
1419 NS_ENSURE_TRUE(ret == SQLITE_OK, NS_ERROR_UNEXPECTED);
1421 ret = sqlite3_create_collation(pHandle,
1424 collationBuffersEntry,
1426 NS_ASSERTION(ret == SQLITE_OK,
"Failed to set library collate function: utf16le!");
1427 NS_ENSURE_TRUE(ret == SQLITE_OK, NS_ERROR_UNEXPECTED);
1429 ret = sqlite3_create_collation(pHandle,
1432 collationBuffersEntry,
1434 NS_ASSERTION(ret == SQLITE_OK,
"Failed to set library collate function: utf16be!");
1435 NS_ENSURE_TRUE(ret == SQLITE_OK, NS_ERROR_UNEXPECTED);
1441 if (NS_FAILED(GetDBPrefs(dbGUID, &cacheSize, &pageSize))) {
1442 NS_WARNING(
"DBEngine failed to get memory prefs. Using default.");
1448 char *strErr = nsnull;
1449 query = NS_LITERAL_CSTRING(
"PRAGMA page_size = ");
1450 query.AppendInt(pageSize);
1451 sqlite3_exec(pHandle, query.get(), nsnull, nsnull, &strErr);
1454 sqlite3_free(strErr);
1459 char *strErr = nsnull;
1460 query = NS_LITERAL_CSTRING(
"PRAGMA cache_size = ");
1461 query.AppendInt(cacheSize);
1462 sqlite3_exec(pHandle, query.get(), nsnull, nsnull, &strErr);
1465 sqlite3_free(strErr);
1469 #if defined(USE_SQLITE_FULL_DISK_CACHING)
1471 char *strErr = nsnull;
1472 sqlite3_exec(pHandle,
"PRAGMA synchronous = 0", nsnull, nsnull, &strErr);
1475 sqlite3_free(strErr);
1480 #if defined(USE_SQLITE_READ_UNCOMMITTED)
1482 char *strErr = nsnull;
1483 sqlite3_exec(pHandle,
"PRAGMA read_uncommitted = 1", nsnull, nsnull, &strErr);
1486 sqlite3_free(strErr);
1491 #if defined(USE_SQLITE_MEMORY_TEMP_STORE)
1493 char *strErr = nsnull;
1494 sqlite3_exec(pHandle,
"PRAGMA temp_store = 2", nsnull, nsnull, &strErr);
1497 sqlite3_free(strErr);
1502 #if defined(USE_SQLITE_BUSY_TIMEOUT)
1503 sqlite3_busy_timeout(pHandle, 120000);
1506 *ppHandle = pHandle;
1515 PRInt32 ret = SQLITE_BUSY;
1518 sqlite3_interrupt(pHandle);
1519 if((ret = sqlite3_close(pHandle)) == SQLITE_BUSY) {
1520 PR_Sleep(PR_MillisecondsToInterval(50));
1523 while(ret == SQLITE_BUSY &&
1527 nsAutoMonitor mon(m_CollationBuffersMapMonitor);
1528 collationMap_t::const_iterator found = m_CollationBuffersMap.find(pHandle);
1529 if (found != m_CollationBuffersMap.end()) {
1530 delete found->second;
1531 m_CollationBuffersMap.erase(pHandle);
1535 NS_ASSERTION(ret == SQLITE_OK,
"");
1536 NS_ENSURE_TRUE(ret == SQLITE_OK, NS_ERROR_UNEXPECTED);
1542 NS_IMETHODIMP CDatabaseEngine::CloseDatabase(
const nsAString &aDatabaseGUID)
1544 nsAutoMonitor mon(m_pThreadMonitor);
1546 nsRefPtr<QueryProcessorQueue> pQueue;
1547 if(m_QueuePool.Get(aDatabaseGUID, getter_AddRefs(pQueue))) {
1549 nsresult rv = pQueue->PrepareForShutdown();
1550 NS_ENSURE_SUCCESS(rv, rv);
1552 rv = pQueue->Shutdown();
1553 NS_ENSURE_SUCCESS(rv, rv);
1555 m_QueuePool.Remove(aDatabaseGUID);
1566 NS_WARNING(
"Don't submit queries after the DBEngine is shut down!");
1567 return NS_ERROR_FAILURE;
1579 NS_WARNING(
"A null queury was submitted to the database engine");
1588 PRBool isExecuting = PR_FALSE;
1589 pQuery->IsExecuting(&isExecuting);
1596 nsRefPtr<QueryProcessorQueue> pQueue =
GetQueueByQuery(pQuery, PR_TRUE);
1597 NS_ENSURE_TRUE(pQueue, 1);
1599 nsresult rv = pQueue->PushQueryToQueue(pQuery);
1600 NS_ENSURE_SUCCESS(rv, 1);
1607 rv = pQueue->RunQueue();
1608 NS_ENSURE_SUCCESS(rv, 1);
1610 PRBool bAsyncQuery = PR_FALSE;
1611 pQuery->IsAyncQuery(&bAsyncQuery);
1615 pQuery->WaitForCompletion(&result);
1616 pQuery->GetLastError(&result);
1624 CDatabaseEngine::DumpDatabase(
const nsAString & aDatabaseGUID, nsIFile *aOutFile)
1626 NS_ENSURE_ARG_POINTER(aOutFile);
1629 NS_ENSURE_TRUE(dummyQuery, NS_ERROR_OUT_OF_MEMORY);
1631 nsresult rv = dummyQuery->SetDatabaseGUID(aDatabaseGUID);
1632 NS_ENSURE_SUCCESS(rv, rv);
1634 rv = dummyQuery->Init();
1635 NS_ENSURE_SUCCESS(rv, rv);
1637 nsRefPtr<QueryProcessorQueue> pQueue =
GetQueueByQuery(dummyQuery, PR_TRUE);
1638 NS_ENSURE_TRUE(pQueue, NS_ERROR_FAILURE);
1640 nsRefPtr<CDatabaseDumpProcessor> dumpProcessor =
1643 return dumpProcessor->Run();
1647 NS_IMETHODIMP CDatabaseEngine::DumpMemoryStatistics()
1652 printf(
"DumpMemoryStatistics() format\tCurrent\tHighwater\n");
1654 sqlite3_status(SQLITE_STATUS_MEMORY_USED, ¤t, &highwater, 0);
1655 printf(
"SQLITE_STATUS_MEMORY_USED:\t%d\t%d\n", current, highwater);
1656 sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, ¤t, &highwater, 0);
1657 printf(
"SQLITE_STATUS_PAGECACHE_USED:\t%d\t%d\n", current, highwater);
1658 sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, ¤t, &highwater, 0);
1659 printf(
"SQLITE_STATUS_PAGECACHE_OVERFLOW:\t%d\t%d\n", current, highwater);
1660 sqlite3_status(SQLITE_STATUS_SCRATCH_USED, ¤t, &highwater, 0);
1661 printf(
"SQLITE_STATUS_SCRATCH_USED:\t%d\t%d\n", current, highwater);
1662 sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, ¤t, &highwater, 0);
1663 printf(
"SQLITE_STATUS_SCRATCH_OVERFLOW:\t%d\t%d\n", current, highwater);
1664 sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, ¤t, &highwater, 0);
1665 printf(
"SQLITE_STATUS_MALLOC_SIZE\t%d\t%d\n", current, highwater);
1666 sqlite3_status(SQLITE_STATUS_PARSER_STACK, ¤t, &highwater, 0);
1667 printf(
"SQLITE_STATUS_PARSER_STACK\t%d\t%d\n", current, highwater);
1668 sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, ¤t, &highwater, 0);
1669 printf(
"SQLITE_STATUS_PAGECACHE_SIZE\t%d\t%d\n", current, highwater);
1670 sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, ¤t, &highwater, 0);
1671 printf(
"SQLITE_STATUS_SCRATCH_SIZE\t%d\t%d\n", current, highwater);
1673 printf(
"DumpMemoryStatistics() finished. "
1674 "See dbengine/src/sqlite3.h#6168\n");
1680 NS_IMETHODIMP CDatabaseEngine::GetCurrentMemoryUsage(PRInt32 flag, PRInt32 *_retval)
1683 sqlite3_status((
int)flag, (
int*)_retval, &disused, 0);
1688 NS_IMETHODIMP CDatabaseEngine::GetHighWaterMemoryUsage(PRInt32 flag, PRInt32 *_retval)
1691 sqlite3_status((
int)flag, &disused, (
int*)_retval, 0);
1696 NS_IMETHODIMP CDatabaseEngine::ReleaseMemory()
1701 LOG(
"CDatabaseEngine::ReleaseMemory() managed to release %d bytes\n", memReleased);
1710 NS_ENSURE_TRUE(pQuery, nsnull);
1712 nsAutoString strGUID;
1713 nsAutoMonitor mon(m_pThreadMonitor);
1715 nsRefPtr<QueryProcessorQueue> pQueue;
1717 nsresult rv = pQuery->GetDatabaseGUID(strGUID);
1718 NS_ENSURE_SUCCESS(rv, nsnull);
1720 if(!m_QueuePool.Get(strGUID, getter_AddRefs(pQueue))) {
1724 NS_ENSURE_TRUE(pQueue, nsnull);
1726 QueryProcessorQueue *
p = pQueue.get();
1735 nsAutoString strGUID;
1736 nsAutoMonitor mon(m_pThreadMonitor);
1738 nsresult rv = pQuery->GetDatabaseGUID(strGUID);
1739 NS_ENSURE_SUCCESS(rv, nsnull);
1742 NS_ENSURE_TRUE(pQueue, nsnull);
1744 sqlite3 *pHandle = nsnull;
1745 rv =
OpenDB(strGUID, pQuery, &pHandle);
1746 NS_ENSURE_SUCCESS(rv, nsnull);
1748 rv = pQueue->Init(
this, strGUID, pHandle);
1749 NS_ENSURE_SUCCESS(rv, nsnull);
1751 PRBool success = m_QueuePool.Put(strGUID, pQueue);
1752 NS_ENSURE_TRUE(success, nsnull);
1754 QueryProcessorQueue *
p = pQueue.get();
1761 CDatabaseEngine::MarkDatabaseForPotentialDeletion(
const nsAString &aDatabaseGUID,
1764 nsAutoMonitor mon(m_pThreadMonitor);
1766 m_PromptForDelete = PR_TRUE;
1767 m_DatabasesToDelete.insert(std::make_pair(
1768 nsString(aDatabaseGUID), nsRefPtr<CDatabaseQuery>(pQuery)));
1770 if(m_PromptForDeleteTimer) {
1771 nsresult rv = m_PromptForDeleteTimer->Init(
this, nsITimer::TYPE_ONE_SHOT, 100);
1772 NS_ENSURE_SUCCESS(rv, rv);
1779 CDatabaseEngine::PromptToDeleteDatabases()
1783 nsAutoMonitor mon(m_pThreadMonitor);
1784 if(!m_PromptForDelete || m_DatabasesToDelete.empty()) {
1791 NS_ENSURE_SUCCESS(rv, rv);
1793 PRUint32 buttons = nsIPromptService::BUTTON_POS_0 * nsIPromptService::BUTTON_TITLE_IS_STRING +
1794 nsIPromptService::BUTTON_POS_1 * nsIPromptService::BUTTON_TITLE_IS_STRING +
1795 nsIPromptService::BUTTON_POS_1_DEFAULT;
1796 PRInt32 promptResult = 0;
1800 nsString dialogTitle = bundle.
Get(
"corruptdatabase.dialog.title");
1801 nsString dialogText = bundle.
Get(
"corruptdatabase.dialog.text");
1802 nsString deleteText = bundle.
Get(
"corruptdatabase.dialog.buttons.delete");
1803 nsString continueText = bundle.
Get(
"corruptdatabase.dialog.buttons.cancel");
1807 rv = promptService->ConfirmEx(nsnull,
1808 dialogTitle.BeginReading(),
1809 dialogText.BeginReading(),
1811 deleteText.BeginReading(),
1812 continueText.BeginReading(),
1817 NS_ENSURE_SUCCESS(rv, rv);
1820 m_PromptForDelete = PR_FALSE;
1825 if (promptResult == 0) {
1827 #ifdef METRICS_ENABLED
1829 nsCOMPtr<sbIMetrics> metrics =
1830 do_CreateInstance(
"@songbirdnest.com/Songbird/Metrics;1", &rv);
1832 if(NS_SUCCEEDED(rv)) {
1833 rv = metrics->MetricsInc(NS_LITERAL_STRING(
"app"), \
1834 NS_LITERAL_STRING(
"library.error.reset"),
1836 NS_ENSURE_SUCCESS(rv, rv);
1838 #endif // METRICS_ENABLED
1841 m_DeleteDatabases = PR_TRUE;
1845 nsCOMPtr<nsIAppStartup> appStartup =
1846 (do_GetService(NS_APPSTARTUP_CONTRACTID, &rv));
1847 NS_ENSURE_SUCCESS(rv, rv);
1849 rv = appStartup->Quit(nsIAppStartup::eForceQuit | nsIAppStartup::eRestart);
1850 NS_ENSURE_SUCCESS(rv, rv);
1857 CDatabaseEngine::DeleteMarkedDatabases()
1860 nsCOMPtr<nsIPrefService> prefService =
1862 NS_ENSURE_SUCCESS(rv, rv);
1864 nsAutoMonitor mon(m_pThreadMonitor);
1866 if(!m_DeleteDatabases)
1869 deleteDatabaseMap_t::const_iterator cit = m_DatabasesToDelete.begin();
1870 deleteDatabaseMap_t::const_iterator citEnd = m_DatabasesToDelete.end();
1872 for(; cit != citEnd; ++cit) {
1873 nsString strFilename;
1874 GetDBStorePath(cit->first, cit->second, strFilename);
1876 nsCOMPtr<nsILocalFile> databaseFile;
1877 rv = NS_NewLocalFile(strFilename,
1879 getter_AddRefs(databaseFile));
1881 NS_WARNING(
"Failed to get local file for database!");
1885 rv = databaseFile->Remove(PR_FALSE);
1886 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"Failed to delete corrupted database file!");
1896 nsCOMPtr<nsIPrefBranch> loaderPrefBranch;
1898 rv = prefService->GetBranch(prefBranchRoot.get(), getter_AddRefs(loaderPrefBranch));
1899 NS_ENSURE_SUCCESS(rv, rv);
1901 PRUint32 libraryKeysCount;
1904 rv = loaderPrefBranch->GetChildList(
"", &libraryKeysCount, &libraryKeys);
1905 NS_ENSURE_SUCCESS(rv, rv);
1909 for (PRUint32 index = 0; index < libraryKeysCount; index++) {
1910 nsCString
pref(libraryKeys[index]);
1912 PRInt32 firstDotIndex =
pref.FindChar(
'.');
1914 if(firstDotIndex == -1) {
1918 PRUint32 keyLength = firstDotIndex;
1919 if(keyLength == 0) {
1925 branchString += Substring(
pref, 0, keyLength + 1);
1926 if(!StringEndsWith(branchString, NS_LITERAL_CSTRING(
"."))) {
1930 nsCOMPtr<nsIPrefBranch> innerBranch;
1931 rv = prefService->GetBranch(branchString.get(), getter_AddRefs(innerBranch));
1932 NS_ENSURE_SUCCESS(rv, rv);
1934 PRInt32 prefType = nsIPrefBranch::PREF_INVALID;
1936 NS_ENSURE_SUCCESS(rv, rv);
1938 if(prefType != nsIPrefBranch::PREF_STRING) {
1942 nsCString loaderDbGuid;
1944 NS_ENSURE_SUCCESS(rv, rv);
1947 NS_ENSURE_SUCCESS(rv, rv);
1949 if(prefType != nsIPrefBranch::PREF_STRING) {
1953 nsCString loaderDbLocation;
1955 NS_ENSURE_SUCCESS(rv, rv);
1957 deleteDatabaseMap_t::const_iterator citD =
1958 m_DatabasesToDelete.find(NS_ConvertUTF8toUTF16(loaderDbGuid));
1960 if(citD != m_DatabasesToDelete.end()) {
1961 nsString strFilename;
1962 GetDBStorePath(citD->first, citD->second, strFilename);
1964 if(strFilename.EqualsLiteral(loaderDbLocation.get())) {
1965 rv = innerBranch->DeleteBranch(
"");
1966 NS_ENSURE_SUCCESS(rv, rv);
1968 rv = prefService->SavePrefFile(nsnull);
1969 NS_ENSURE_SUCCESS(rv, rv);
1973 nsCOMPtr<nsIPrefBranch> doomedBranch;
1975 NS_ENSURE_SUCCESS(rv, rv);
1977 rv = doomedBranch->DeleteBranch(
"");
1978 NS_ENSURE_SUCCESS(rv, rv);
1981 NS_ENSURE_SUCCESS(rv, rv);
1983 rv = doomedBranch->DeleteBranch(
"");
1984 NS_ENSURE_SUCCESS(rv, rv);
1987 NS_ENSURE_SUCCESS(rv, rv);
1989 rv = doomedBranch->DeleteBranch(
"");
1990 NS_ENSURE_SUCCESS(rv, rv);
1992 rv = prefService->SavePrefFile(nsnull);
1993 NS_ENSURE_SUCCESS(rv, rv);
1996 nsCOMPtr<nsIPrefBranch> doomedBranch;
1997 rv = prefService->GetBranch(
PREF_WEB_LIBRARY, getter_AddRefs(doomedBranch));
1998 NS_ENSURE_SUCCESS(rv, rv);
2000 rv = doomedBranch->DeleteBranch(
"");
2001 NS_ENSURE_SUCCESS(rv, rv);
2003 rv = prefService->SavePrefFile(nsnull);
2004 NS_ENSURE_SUCCESS(rv, rv);
2007 nsCOMPtr<nsIPrefBranch> doomedBranch;
2009 getter_AddRefs(doomedBranch));
2010 NS_ENSURE_SUCCESS(rv, rv);
2012 rv = doomedBranch->DeleteBranch(
"");
2013 NS_ENSURE_SUCCESS(rv, rv);
2015 rv = prefService->SavePrefFile(nsnull);
2016 NS_ENSURE_SUCCESS(rv, rv);
2021 m_DatabasesToDelete.clear();
2022 m_DeleteDatabases = PR_FALSE;
2028 PLDHashOperator CDatabaseEngine::EnumerateIntoArrayStringKey(
2029 const nsAString& aKey,
2033 nsTArray<nsString> *stringArray =
2034 reinterpret_cast< nsTArray<nsString>*
>(aArray);
2040 aQueue->m_AnalyzeCount = 0;
2041 stringArray->AppendElement(aKey);
2044 return PL_DHASH_NEXT;
2048 CDatabaseEngine::RunAnalyze()
2050 nsAutoMonitor mon(m_pThreadMonitor);
2052 nsTArray<nsString> dbGUIDs;
2053 m_QueuePool.EnumerateRead(EnumerateIntoArrayStringKey, &dbGUIDs);
2057 nsresult rv = NS_ERROR_UNEXPECTED;
2059 PRUint32 current = 0;
2060 PRUint32 length = dbGUIDs.Length();
2062 for(; current < length; current++) {
2063 nsRefPtr<CDatabaseQuery> query;
2067 rv = query->SetDatabaseGUID(dbGUIDs[current]);
2070 rv = query->AddQuery(NS_LITERAL_STRING(
"ANALYZE"));
2073 rv = query->SetAsyncQuery(PR_TRUE);
2077 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"Failed to submit ANALYZE query.");
2085 QueryProcessorQueue *pQueue)
2089 NS_WARNING(
"Called QueryProcessor without an engine or thread!!!!");
2106 PRUint32 queueSize = 0;
2108 NS_ASSERTION(NS_SUCCEEDED(rv),
"Couldn't get queue size.");
2117 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"No query to pop from queue.");
2132 LOG(
"DBE: Process Start, thread 0x%x query 0x%x",
2133 PR_GetCurrentThread(), pQuery);
2135 PRUint32 nQueryCount = 0;
2136 PRBool bFirstRow = PR_TRUE;
2139 pQuery->SetLastError(SQLITE_ERROR);
2140 pQuery->GetQueryCount(&nQueryCount);
2143 nsRefPtr<CDatabaseResult> databaseResult =
2147 if(NS_UNLIKELY(!databaseResult)) {
2153 for(PRUint32 currentQuery = 0; currentQuery < nQueryCount && !pQuery->
m_IsAborting; ++currentQuery)
2155 nsAutoPtr<bindParameterArray_t> pParameters;
2159 nsCOMPtr<sbIDatabasePreparedStatement> preparedStatement;
2160 nsresult rv = pQuery->
PopQuery(getter_AddRefs(preparedStatement));
2161 if (NS_FAILED(rv)) {
2162 LOG(
"DBE: Failed to get a prepared statement from the Query object.");
2166 preparedStatement->GetQueryString(strQuery);
2171 sqlite3_stmt *pStmt =
2175 LOG(
"DBE: Failed to create a prepared statement from the Query object.");
2185 nsAutoString dbName;
2186 pQuery->GetDatabaseGUID(dbName);
2190 LOG(
"DBE: '%s' on '%s'\n",
2191 NS_ConvertUTF16toUTF8(dbName).
get(),
2192 NS_ConvertUTF16toUTF8(strQuery).
get());
2196 bindParameterArray_t::const_iterator
const end = pParameters->end();
2197 for (bindParameterArray_t::const_iterator paramIter = pParameters->begin();
2204 sqlite3_bind_null(pStmt, i + 1);
2205 LOG(
"DBE: Parameter %d is 'NULL'", i);
2208 sqlite3_bind_text(pStmt, i + 1,
2216 sqlite3_bind_text16(pStmt, i + 1,
2220 LOG(
"DBE: Parameter %d is '%s'", i, NS_ConvertUTF16toUTF8(p.
stringValue).get());
2228 sqlite3_bind_int(pStmt, i + 1, p.
int32Value);
2232 sqlite3_bind_int64(pStmt, i + 1, p.
int64Value);
2238 PRInt32 totalRows = 0;
2240 PRUint64 rollingSum = 0;
2241 PRUint64 rollingLimit = 0;
2242 PRUint32 rollingLimitColumnIndex = 0;
2243 PRUint32 rollingRowCount = 0;
2244 pQuery->GetRollingLimit(&rollingLimit);
2245 pQuery->GetRollingLimitColumnIndex(&rollingLimitColumnIndex);
2247 PRBool finishEarly = PR_FALSE;
2250 retDB = sqlite3_step(pStmt);
2256 int nCount = sqlite3_column_count(pStmt);
2259 bFirstRow = PR_FALSE;
2261 std::vector<nsString> vColumnNames;
2262 vColumnNames.reserve(nCount);
2265 for(; j < nCount; j++) {
2266 const char *
p = (
const char *)sqlite3_column_name(pStmt, j);
2268 vColumnNames.push_back(NS_ConvertUTF8toUTF16(p));
2271 nsAutoString strColumnName;
2272 strColumnName.SetIsVoid(PR_TRUE);
2273 vColumnNames.push_back(strColumnName);
2276 databaseResult->SetColumnNames(vColumnNames);
2279 std::vector<nsString> vCellValues;
2280 vCellValues.reserve(nCount);
2282 TRACE(
"DBE: Result row %d:", totalRows);
2287 if (rollingLimit > 0) {
2288 rollingSum += sqlite3_column_int64(pStmt, rollingLimitColumnIndex);
2295 if (rollingLimit == 0 || rollingSum >= rollingLimit) {
2296 for(; k < nCount; k++)
2298 const char *
p = (
const char *)sqlite3_column_text(pStmt, k);
2299 nsString strCellValue;
2301 strCellValue = NS_ConvertUTF8toUTF16(p);
2304 strCellValue.SetIsVoid(PR_TRUE);
2307 vCellValues.push_back(strCellValue);
2308 TRACE(
"Column %d: '%s' ", k,
2309 NS_ConvertUTF16toUTF8(strCellValue).
get());
2313 databaseResult->AddRow(vCellValues);
2316 if (rollingLimit > 0) {
2317 pQuery->SetRollingLimitResult(rollingRowCount);
2318 pQuery->SetLastError(SQLITE_OK);
2319 TRACE(
"Rolling limit query complete, %d rows", totalRows);
2320 finishEarly = PR_TRUE;
2328 pQuery->SetLastError(SQLITE_OK);
2329 TRACE(
"Query complete, %d rows", totalRows);
2335 sqlite3_reset(pStmt);
2342 case SQLITE_CORRUPT:
2344 pEngine->ReportError(pDB, pStmt);
2348 rv = pEngine->MarkDatabaseForPotentialDeletion(dbName, pQuery);
2349 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"Failed to mark database for deletion!");
2356 pEngine->ReportError(pDB, pStmt);
2357 pQuery->SetLastError(retDB);
2361 while(retDB == SQLITE_ROW &&
2371 sqlite3_reset(pStmt);
2382 LOG(
"DBE: Notified query monitor.");
2385 pEngine->DoSimpleCallback(pQuery);
2386 LOG(
"DBE: Simple query listeners have been processed.");
2388 LOG(
"DBE: Process End");
2399 already_AddRefed<nsIEventTarget>
2402 NS_ENSURE_TRUE(m_pThreadPool, nsnull);
2404 nsresult rv = NS_ERROR_UNEXPECTED;
2405 nsCOMPtr<nsIEventTarget>
eventTarget = do_QueryInterface(m_pThreadPool, &rv);
2406 NS_ENSURE_SUCCESS(rv, nsnull);
2408 return eventTarget.forget();
2412 void CDatabaseEngine::ReportError(sqlite3* db, sqlite3_stmt* stmt) {
2413 const char *sql = sqlite3_sql(stmt);
2414 const char *errMsg = sqlite3_errmsg(db);
2417 log.AppendLiteral(
"SQLite execution error: \n");
2418 log.Append(NS_ConvertUTF8toUTF16(sql));
2419 log.AppendLiteral(
"\nresulted in the error\n");
2420 log.Append(NS_ConvertUTF8toUTF16(errMsg));
2421 log.AppendLiteral(
"\n");
2424 nsCOMPtr<nsIConsoleService> consoleService = do_GetService(
"@mozilla.org/consoleservice;1", &rv);
2426 nsCOMPtr<nsIScriptError> scriptError = do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
2428 nsresult rv = scriptError->Init(log.get(),
2429 EmptyString().get(),
2430 EmptyString().get(),
2434 "DBEngine:StatementExecution");
2435 if (NS_SUCCEEDED(rv)) {
2436 rv = consoleService->LogMessage(scriptError);
2444 nsCOMArray<sbIDatabaseSimpleQueryCallback> *
array =
static_cast<nsCOMArray<sbIDatabaseSimpleQueryCallback> *
>(closure);
2445 array->AppendObject(data);
2446 return PL_DHASH_NEXT;
2452 PRUint32 callbackCount = 0;
2453 nsCOMArray<sbIDatabaseSimpleQueryCallback> callbackSnapshot;
2455 nsCOMPtr<sbIDatabaseResult> pDBResult;
2456 nsAutoString strGUID;
2459 pQuery->GetDatabaseGUID(strGUID);
2463 callbackCount = callbackSnapshot.Count();
2467 nsString strQuery = NS_LITERAL_STRING(
"UNIMPLEMENTED");
2469 for(PRUint32
i = 0;
i < callbackCount;
i++)
2471 nsCOMPtr<sbIDatabaseSimpleQueryCallback>
callback = callbackSnapshot.ObjectAt(
i);
2476 callback->OnQueryEnd(pDBResult, strGUID, strQuery);
2486 nsresult CDatabaseEngine::CreateDBStorePath()
2488 nsresult rv = NS_ERROR_FAILURE;
2491 nsCOMPtr<nsIFile> f;
2494 if(NS_FAILED(rv))
return rv;
2496 rv = f->Append(NS_LITERAL_STRING(
"db"));
2497 if(NS_FAILED(rv))
return rv;
2499 PRBool dirExists = PR_FALSE;
2500 rv = f->Exists(&dirExists);
2501 if(NS_FAILED(rv))
return rv;
2505 rv = f->Create(nsIFile::DIRECTORY_TYPE, 0700);
2506 if(NS_FAILED(rv))
return rv;
2509 rv = f->GetPath(m_DBStorePath);
2510 if(NS_FAILED(rv))
return rv;
2516 nsresult CDatabaseEngine::GetDBStorePath(
const nsAString &dbGUID,
CDatabaseQuery *pQuery, nsAString &strPath)
2518 nsresult rv = NS_ERROR_FAILURE;
2519 nsCOMPtr<nsILocalFile> f;
2521 nsAutoString strDBFile(dbGUID);
2524 NS_ENSURE_SUCCESS(rv, rv);
2528 nsCOMPtr<nsIFile>
file;
2529 rv = NS_GetFileFromURLSpec(spec, getter_AddRefs(file));
2530 NS_ENSURE_SUCCESS(rv, rv);
2533 rv = file->GetPath(path);
2534 NS_ENSURE_SUCCESS(rv, rv);
2536 rv = NS_NewLocalFile(path, PR_FALSE, getter_AddRefs(f));
2537 NS_ENSURE_SUCCESS(rv, rv);
2541 PR_Lock(m_pDBStorePathLock);
2542 rv = NS_NewLocalFile(m_DBStorePath, PR_FALSE, getter_AddRefs(f));
2543 PR_Unlock(m_pDBStorePathLock);
2544 NS_ENSURE_SUCCESS(rv, rv);
2547 strDBFile.AppendLiteral(
".db");
2548 rv = f->Append(strDBFile);
2549 if(NS_FAILED(rv))
return rv;
2550 rv = f->GetPath(strPath);
2551 if(NS_FAILED(rv))
return rv;
2556 NS_IMETHODIMP CDatabaseEngine::GetLocaleCollationEnabled(PRBool *aEnabled)
2558 NS_ENSURE_ARG_POINTER(aEnabled);
2563 NS_IMETHODIMP CDatabaseEngine::SetLocaleCollationEnabled(PRBool aEnabled)
2569 PRInt32 CDatabaseEngine::CollateForCurrentLocale(
collationBuffers *aCollationBuffers,
2570 const NATIVE_CHAR_TYPE *aStr1,
2571 const NATIVE_CHAR_TYPE *aStr2) {
2573 if (!aStr1 && !aStr2)
2604 ::UCCompareTextDefault(kUCCollateStandardOptions,
2612 ::UCCompareText(m_Collator,
2623 retval = wcscoll((
const wchar_t *)aStr1, (
const wchar_t *)aStr2);
2625 #endif // ifdef XP_MACOSX
2632 #define LEADING_NUMBERS_SORTPOSITION -1
2634 PRInt32 CDatabaseEngine::CollateWithLeadingNumbers(
collationBuffers *aCollationBuffers,
2635 const NATIVE_CHAR_TYPE *aStr1,
2636 PRInt32 *number1Length,
2637 const NATIVE_CHAR_TYPE *aStr2,
2638 PRInt32 *number2Length) {
2639 PRBool hasLeadingNumberA = PR_FALSE;
2640 PRBool hasLeadingNumberB = PR_FALSE;
2642 PRFloat64 leadingNumberA;
2643 PRFloat64 leadingNumberB;
2656 if (hasLeadingNumberA && !hasLeadingNumberB) {
2658 }
else if (!hasLeadingNumberA && hasLeadingNumberB) {
2660 }
else if (hasLeadingNumberA && hasLeadingNumberB) {
2661 if (leadingNumberA > leadingNumberB)
2663 else if (leadingNumberA < leadingNumberB)
2670 aStr1 += *number1Length;
2671 aStr2 += *number2Length;
2673 return CollateForCurrentLocale(aCollationBuffers, aStr1, aStr2);
2677 const NATIVE_CHAR_TYPE *aStr1,
2678 const NATIVE_CHAR_TYPE *aStr2) {
2680 const NATIVE_CHAR_TYPE *remainderA = aStr1;
2681 const NATIVE_CHAR_TYPE *remainderB = aStr2;
2694 if (nextNumberPosA == -1 ||
2695 nextNumberPosB == -1) {
2704 if (nextNumberPosA == 0 && nextNumberPosB != 0) {
2706 }
else if (nextNumberPosA != 0 && nextNumberPosB == 0) {
2718 PRInt32 substringCollate =
2719 CollateForCurrentLocale(aCollationBuffers,
2723 if (substringCollate != 0) {
2724 return substringCollate;
2732 remainderA += nextNumberPosA;
2733 remainderB += nextNumberPosB;
2735 PRInt32 numberALength;
2736 PRInt32 numberBLength;
2738 PRInt32 leadingNumbersCollate =
2739 CollateWithLeadingNumbers(aCollationBuffers,
2747 if (leadingNumbersCollate != 0) {
2748 return leadingNumbersCollate;
2752 remainderA += numberALength;
2753 remainderB += numberBLength;;
2764 if (numberALength == 0 &&
2765 numberBLength == 0) {
2786 PRInt32 numberALength;
2787 PRInt32 numberBLength;
2789 return CollateWithLeadingNumbers(aCollationBuffers,
2797 CDatabaseEngine::GetCurrentCollationLocale(nsCString &aCollationLocale) {
2801 CFStringRef collationIdentifier = NULL;
2808 CFPropertyListRef pl =
2809 CFPreferencesCopyAppValue(CFSTR(
"AppleCollationOrder"),
2810 kCFPreferencesCurrentApplication);
2814 CFGetTypeID(pl) == CFStringGetTypeID()) {
2815 collationIdentifier = (CFStringRef)pl;
2819 CFPropertyListRef al =
2820 CFPreferencesCopyAppValue(CFSTR(
"AppleLanguages"),
2821 kCFPreferencesCurrentApplication);
2824 CFGetTypeID(al) == CFArrayGetTypeID()) {
2825 CFArrayRef ar = (CFArrayRef)al;
2826 if (CFArrayGetCount(ar) > 0) {
2827 CFTypeRef lang = CFArrayGetValueAtIndex(ar, 0);
2829 CFGetTypeID(lang) == CFStringGetTypeID()) {
2830 collationIdentifier = (CFStringRef)lang;
2844 if (collationIdentifier) {
2846 CFStringGetCString(collationIdentifier,
2849 kCFStringEncodingASCII);
2850 buf[
sizeof(buf)-1] = 0;
2852 aCollationLocale = buf;
2855 LOG(
"Could not retrieve the collation locale identifier");
2860 nsCString curCollate(setlocale(LC_COLLATE, NULL));
2864 aCollationLocale = setlocale(LC_COLLATE,
"");
2867 setlocale(LC_COLLATE, curCollate.get());
2874 NS_IMETHODIMP CDatabaseEngine::GetLocaleCollationID(nsAString &aID) {
2875 aID = NS_ConvertASCIItoUTF16(mCollationLocale);
2879 #ifdef USE_PERF_LOGGING
2881 sbDatabaseEnginePerformanceLogger::sbDatabaseEnginePerformanceLogger(
const nsAString& aQuery,
2882 const nsAString& aGuid) :
2889 sbDatabaseEnginePerformanceLogger::~sbDatabaseEnginePerformanceLogger()
2891 PRUint32
total = PR_Now() - mStart;
2893 nsString consoleMessageStr;
2894 consoleMessageStr.AppendLiteral(
"sbDatabaseEnginePerformanceLogger\n\t");
2895 consoleMessageStr.AppendLiteral(
"DB GUID: ");
2896 consoleMessageStr.Append(mGuid);
2897 consoleMessageStr.AppendLiteral(
" -- Execution Time: ");
2898 consoleMessageStr.AppendInt(total / PR_USEC_PER_MSEC);
2899 consoleMessageStr.AppendLiteral(
"ms\nQuery:\n\t");
2900 consoleMessageStr.Append(mQuery);
2902 nsCOMPtr<nsIConsoleService> consoleService =
2903 do_GetService(
"@mozilla.org/consoleservice;1");
2905 if(consoleService) {
2906 consoleService->LogStringMessage(consoleMessageStr.get());
nsRefPtr< QueryProcessorQueue > mQueryProcessorQueue
NATIVE_CHAR_TYPE * buffer()
static int library_collate_func_utf8(void *pCtx, int nA, const void *zA, int nB, const void *zB)
static int tree_collate_func_utf16be(void *pCtx, int nA, const void *zA, int nB, const void *zB)
static int tree_collate_func(void *pCtx, int nA, const void *zA, int nB, const void *zB, int eTextRep)
#define SB_PRLOG_SETUP(x)
#define PREF_DB_PAGE_SIZE
#define DBENGINE_GUID_MAIN_LIBRARY
EnumSimpleCallback(nsISupports *key, sbIDatabaseSimpleQueryCallback *data, void *closure)
static nsCOMPtr< nsIObserverService > observerService
#define MAX_BUSY_RETRY_CLOSE_DB
#define DBENGINE_GUID_WEB_LIBRARY
PRInt32 SB_FindNextNumber(const CHARTYPE *aStr)
PR_STATIC_CALLBACK(PRBool) FindElementCallback(void *aElement
#define DEFAULT_PREALLOCSCRATCH_SIZE
void swap_utf16_bytes(const void *aStr, int len)
const NS_PREFSERVICE_CONTRACTID
#define PREF_LOADER_DBLOCATION
CDatabaseDumpProcessor(CDatabaseEngine *aCallback, QueryProcessorQueue *aQueryProcessorQueue, nsIFile *aOutputFile)
already_AddRefed< QueryProcessorQueue > GetQueueByQuery(CDatabaseQuery *pQuery, PRBool bCreate=PR_FALSE)
#define PREF_DOWNLOAD_LIST
nsString Get(const nsAString &aKey, const nsAString &aDefault=SBVoidString())
fastString encodingConversionBuffer2
#define DEFAULT_PAGE_SIZE
fastString substringExtractionBuffer1
static int library_collate_func_utf16le(void *pCtx, int nA, const void *zA, int nB, const void *zB)
#define PREF_PLAYQUEUE_LIBRARY
static char * appendText(char *zIn, char const *zAppend, char quote)
#define IDLE_SERVICE_TIMEOUT
nsresult OutputBuffer(const char *aBuffer)
nsCOMPtr< nsIFileOutputStream > mOutputStream
PRInt32 RunSchemaDumpQuery(const nsACString &aQuery)
#define SONGBIRD_PROMPTER_CONTRACTID
#define PREF_DB_PREALLOCCACHE_SIZE
static int tree_collate_func_utf16le(void *pCtx, int nA, const void *zA, int nB, const void *zB)
PRBool m_QueryHasCompleted
PRInt32 SubmitQueryPrivate(CDatabaseQuery *pQuery)
#define DBENGINE_GUID_PLAYQUEUE_LIBRARY
#define PREF_MAIN_LIBRARY
EnumQueuesOperate(nsStringHashKey::KeyType aKey, QueryProcessorQueue *aQueue, void *aClosure)
[USER CODE SHOULD NOT REFERENCE THIS CLASS]
#define BEGIN_PERFORMANCE_LOG(_strQuery, _dbName)
static CDatabaseEngine * GetSingleton()
fastString substringExtractionBuffer2
#define DEFAULT_PREALLOCCACHE_SIZE
nsresult GetDatabaseLocation(nsACString &aURISpec)
PRMonitor * m_pQueueMonitor
virtual ~CDatabaseEngine()
NS_IMPL_THREADSAFE_ISUPPORTS1(sbDeviceCapsCompatibility, sbIDeviceCapsCompatibility) sbDeviceCapsCompatibility
void SB_ExtractLeadingNumber(const CHARTYPE *str, PRBool *hasLeadingNumber, PRFloat64 *leadingNumber, PRInt32 *numberLength)
#define LEADING_NUMBERS_SORTPOSITION
PRMonitor * m_pQueryRunningMonitor
void SetResultObject(CDatabaseResult *aResultObject)
nsCString utf8StringValue
static PRInt32 gLocaleCollationEnabled
nsCOMPtr< nsIFile > mOutputFile
nsresult PopQuery(sbIDatabasePreparedStatement **_retval)
virtual ~CDatabaseDumpProcessor()
static int DumpCallback(void *pArg, int inArg, char **azArg, const char **azCol)
nsInterfaceHashtableMT< nsISupportsHashKey, sbIDatabaseSimpleQueryCallback > m_CallbackList
already_AddRefed< nsIEventTarget > GetEventTarget()
#define PREF_SCAN_COMPLETE
#define NS_FINAL_UI_STARTUP_CATEGORY
#define DEFAULT_CACHE_SIZE
const NS_TIMER_CALLBACK_TOPIC
static int library_collate_func(collationBuffers *cBuffers, const NATIVE_CHAR_TYPE *zA, const NATIVE_CHAR_TYPE *zB)
A callback object used to inform client code that a query has completed.
#define PREF_LOADER_DBGUID
NS_IMPL_THREADSAFE_ISUPPORTS2(sbDeviceCapabilities, sbIDeviceCapabilities, nsIClassInfo) NS_IMPL_CI_INTERFACE_GETTER2(sbDeviceCapabilities
#define ANALYZE_QUERY_THRESHOLD
Songbird String Bundle Definitions.
int native_wcscmp(const NATIVE_CHAR_TYPE *s1, const NATIVE_CHAR_TYPE *s2)
#define PREF_DB_SOFT_LIMIT
#define PREF_BRANCH_LIBRARY_LOADER
already_AddRefed< QueryProcessorQueue > CreateQueueFromQuery(CDatabaseQuery *pQuery)
void grow_native(PRInt32 aLength)
int native_wcslen(const NATIVE_CHAR_TYPE *s)
PRInt32 SubmitQuery(in CDatabaseQueryPtr aDBQuery)
Submit a query to the database engine for processing.
void copy_native(const NATIVE_CHAR_TYPE *aFrom, PRInt32 aSize)
static int tree_collate_func_utf8(void *pCtx, int nA, const void *zA, int nB, const void *zB)
PRInt32 RunTableDumpQuery(const nsACString &aSelect)
Songbird Database Prepared Query.
#define PREF_DB_PREALLOCSCRATCH_SIZE
nsresult OpenDB(const nsAString &dbGUID, CDatabaseQuery *pQuery, sqlite3 **ppHandle)
sqlite3_stmt * GetStatement(sqlite3 *db)
void copy_utf16(const UTF16_CHARTYPE *aFrom, PRInt32 aSize)
friend class QueryProcessorQueue
static void PR_CALLBACK QueryProcessor(CDatabaseEngine *pEngine, QueryProcessorQueue *pQueue)
static int library_collate_func_utf16be(void *pCtx, int nA, const void *zA, int nB, const void *zB)
fastString encodingConversionBuffer1
nsresult PopQueryFromQueue(CDatabaseQuery **ppQuery)
static int tree_collate_func_next_num(const char *start, char **pos, int length, int eTextRep, int width)
_getSelectedPageStyle s i
nsRefPtr< CDatabaseEngine > mEngineCallback
nsresult GetQueueSize(PRUint32 &aSize)
CDatabaseEngine * gEngine
PRInt32 Collate(collationBuffers *aCollationBuffers, const NATIVE_CHAR_TYPE *aStr1, const NATIVE_CHAR_TYPE *aStr2)
#define SB_UNUSED_IN_RELEASE(decl)
static nsModuleComponentInfo sbDatabaseEngine[]
CDatabaseResult * GetResultObject()
#define PREF_DB_CACHE_SIZE
_updateTextAndScrollDataForFrame aData
nsresult CloseDB(sqlite3 *pHandle)
bindParameterArray_t * PopQueryParameters()