NS_IMETHODIMP nsFaviconService::SetFaviconData(nsIURI* aFaviconURI, const PRUint8* aData, PRUint32 aDataLen, const nsACString& aMimeType, PRTime aExpiration) { nsresult rv; PRUint32 dataLen = aDataLen; const PRUint8* data = aData; const nsACString* mimeType = &aMimeType; nsCString newData, newMimeType; // If the page provided a large image for the favicon (eg, a highres image // or a multiresolution .ico file), we don't want to store more data than // needed. An uncompressed 16x16 RGBA image is 1024 bytes, and almost all // sensible 16x16 icons are under 1024 bytes. if (aDataLen > 1024) { rv = OptimizeFaviconImage(aData, aDataLen, aMimeType, newData, newMimeType); if (NS_SUCCEEDED(rv) && newData.Length() < aDataLen) { data = reinterpret_cast<PRUint8*>(const_cast<char*>(newData.get())), dataLen = newData.Length(); mimeType = &newMimeType; } } mozIStorageStatement* statement; { // this block forces the scoper to reset our statement: necessary for the // next statement mozStorageStatementScoper scoper(mDBGetIconInfo); rv = BindStatementURI(mDBGetIconInfo, 0, aFaviconURI); NS_ENSURE_SUCCESS(rv, rv); PRBool hasResult; rv = mDBGetIconInfo->ExecuteStep(&hasResult); NS_ENSURE_SUCCESS(rv, rv); if (hasResult) { // update old one (statement parameter 0 = ID) PRInt64 id; rv = mDBGetIconInfo->GetInt64(0, &id); NS_ENSURE_SUCCESS(rv, rv); statement = mDBUpdateIcon; rv = statement->BindInt64Parameter(0, id); } else { // insert new one (statement parameter 0 = favicon URL) statement = mDBInsertIcon; rv = BindStatementURI(statement, 0, aFaviconURI); } NS_ENSURE_SUCCESS(rv, rv); } mozStorageStatementScoper scoper(statement); // the insert and update statements share all but the 0th parameter rv = statement->BindBlobParameter(1, data, dataLen); NS_ENSURE_SUCCESS(rv, rv); rv = statement->BindUTF8StringParameter(2, *mimeType); NS_ENSURE_SUCCESS(rv, rv); rv = statement->BindInt64Parameter(3, aExpiration); NS_ENSURE_SUCCESS(rv, rv); return statement->Execute(); }
RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool notifyRenderer) { ASSERT(oldChild->parent() == owner); if (oldChild->isFloatingOrOutOfFlowPositioned()) toRenderBox(oldChild)->removeFloatingOrPositionedChildFromBlockLists(); { // FIXME: We should not be allowing repaint during layout. crbug.com/336250 AllowPaintInvalidationScope scoper(owner->frameView()); // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or // that a positioned child got yanked). We also repaint, so that the area exposed when the child // disappears gets repainted properly. if (!owner->documentBeingDestroyed() && notifyRenderer && oldChild->everHadLayout()) { oldChild->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); // We only repaint |oldChild| if we have a RenderLayer as its visual overflow may not be tracked by its parent. if (oldChild->isBody()) owner->view()->paintInvalidationForWholeRenderer(); else oldChild->paintInvalidationForWholeRenderer(); } } // If we have a line box wrapper, delete it. if (oldChild->isBox()) toRenderBox(oldChild)->deleteLineBoxWrapper(); // If oldChild is the start or end of the selection, then clear the selection to // avoid problems of invalid pointers. // FIXME: The FrameSelection should be responsible for this when it // is notified of DOM mutations. if (!owner->documentBeingDestroyed() && oldChild->isSelectionBorder()) owner->view()->clearSelection(); if (!owner->documentBeingDestroyed() && notifyRenderer) oldChild->willBeRemovedFromTree(); // WARNING: There should be no code running between willBeRemovedFromTree and the actual removal below. // This is needed to avoid race conditions where willBeRemovedFromTree would dirty the tree's structure // and the code running here would force an untimely rebuilding, leaving |oldChild| dangling. if (oldChild->previousSibling()) oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); if (oldChild->nextSibling()) oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); if (firstChild() == oldChild) setFirstChild(oldChild->nextSibling()); if (lastChild() == oldChild) setLastChild(oldChild->previousSibling()); oldChild->setPreviousSibling(0); oldChild->setNextSibling(0); oldChild->setParent(0); // rendererRemovedFromTree walks the whole subtree. We can improve performance // by skipping this step when destroying the entire tree. if (!owner->documentBeingDestroyed()) RenderCounter::rendererRemovedFromTree(oldChild); if (AXObjectCache* cache = owner->document().existingAXObjectCache()) cache->childrenChanged(owner); return oldChild; }
nsresult nsFaviconService::SetFaviconUrlForPageInternal(nsIURI* aPageURI, nsIURI* aFaviconURI, PRBool* aHasData, PRTime* aExpiration) { nsresult rv; PRInt64 iconId = -1; mozStorageTransaction transaction(mDBConn, PR_FALSE); { mozStorageStatementScoper scoper(mDBGetIconInfo); rv = BindStatementURI(mDBGetIconInfo, 0, aFaviconURI); NS_ENSURE_SUCCESS(rv, rv); PRBool hasResult = PR_FALSE; if (NS_SUCCEEDED(mDBGetIconInfo->ExecuteStep(&hasResult)) && hasResult) { // We already have an entry for this icon, just get the stats rv = mDBGetIconInfo->GetInt64(0, &iconId); NS_ENSURE_SUCCESS(rv, rv); // see if this icon has data already PRInt32 dataSize; rv = mDBGetIconInfo->GetInt32(1, &dataSize); NS_ENSURE_SUCCESS(rv, rv); if (dataSize > 0) *aHasData = PR_TRUE; // expiration rv = mDBGetIconInfo->GetInt64(2, aExpiration); NS_ENSURE_SUCCESS(rv, rv); } } if (iconId == -1) { // We did not find any entry, so create a new one *aHasData = PR_FALSE; *aExpiration = 0; // not-binded params are automatically nullified by mozStorage mozStorageStatementScoper scoper(mDBInsertIcon); rv = BindStatementURI(mDBInsertIcon, 0, aFaviconURI); NS_ENSURE_SUCCESS(rv, rv); rv = mDBInsertIcon->Execute(); NS_ENSURE_SUCCESS(rv, rv); rv = mDBConn->GetLastInsertRowID(&iconId); NS_ENSURE_SUCCESS(rv, rv); } // now link our icon entry with the page nsNavHistory* historyService = nsNavHistory::GetHistoryService(); NS_ENSURE_TRUE(historyService, NS_ERROR_OUT_OF_MEMORY); PRInt64 pageId; rv = historyService->GetUrlIdFor(aPageURI, &pageId, PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); mozStorageStatementScoper scoper(mDBSetPageFavicon); rv = mDBSetPageFavicon->BindInt64Parameter(0, pageId); NS_ENSURE_SUCCESS(rv, rv); rv = mDBSetPageFavicon->BindInt64Parameter(1, iconId); NS_ENSURE_SUCCESS(rv, rv); rv = mDBSetPageFavicon->Execute(); NS_ENSURE_SUCCESS(rv, rv); rv = transaction.Commit(); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
nsresult nsFaviconService::DoSetAndLoadFaviconForPage(nsIURI* aPageURI, nsIURI* aFaviconURI, PRBool aForceReload) { nsCOMPtr<nsIURI> page(aPageURI); // don't load favicons when history is disabled nsNavHistory* history = nsNavHistory::GetHistoryService(); NS_ENSURE_TRUE(history, NS_ERROR_FAILURE); if (history->IsHistoryDisabled()) { // history is disabled - check to see if this favicon could be for a // bookmark nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService(); NS_ENSURE_TRUE(bookmarks, NS_ERROR_UNEXPECTED); nsCOMPtr<nsIURI> bookmarkURI; nsresult rv = bookmarks->GetBookmarkedURIFor(aPageURI, getter_AddRefs(bookmarkURI)); NS_ENSURE_SUCCESS(rv, rv); if (! bookmarkURI) { // page is not bookmarked, don't save favicon return NS_OK; } // page is bookmarked, set the URI to be the bookmark, the bookmark URI // might be different than our input URI if there was a redirect, so // always use the bookmark URI here to avoid setting the favicon for // non-bookmarked pages. page = bookmarkURI; } // check the failed favicon cache PRBool previouslyFailed; nsresult rv = IsFailedFavicon(aFaviconURI, &previouslyFailed); NS_ENSURE_SUCCESS(rv, rv); if (previouslyFailed) { if (aForceReload) RemoveFailedFavicon(aFaviconURI); // force reload clears from failed cache else return NS_OK; // ignore previously failed favicons } // filter out bad URLs PRBool canAdd; rv = history->CanAddURI(page, &canAdd); NS_ENSURE_SUCCESS(rv, rv); if (! canAdd) return NS_OK; // ignore favicons for this url // If have an image loaded in the main frame, that image will get set as its // own favicon. It would be nice to store a resampled version of the image, // but that's prohibitive for now. This workaround just refuses to save the // favicon in this case. PRBool pageEqualsFavicon; rv = page->Equals(aFaviconURI, &pageEqualsFavicon); NS_ENSURE_SUCCESS(rv, rv); if (pageEqualsFavicon) return NS_OK; // ignore error page favicons. nsCOMPtr<nsIURI> errorPageFavicon; rv = NS_NewURI(getter_AddRefs(errorPageFavicon), NS_LITERAL_CSTRING(FAVICON_ERRORPAGE_URL)); NS_ENSURE_SUCCESS(rv, rv); PRBool isErrorPage; rv = aFaviconURI->Equals(errorPageFavicon, &isErrorPage); NS_ENSURE_SUCCESS(rv, rv); if (isErrorPage) return NS_OK; // See if we have data and get the expiration time for this favicon. It might // be nice to say SetFaviconUrlForPageInternal here but we DON'T want to set // the favicon for the page unless we know we have it. For example, if I go // to random site x.com, the browser will still tell us that the favicon is // x.com/favicon.ico even if there is no such file. We don't want to pollute // our tables with this useless data. PRBool hasData = PR_FALSE; PRTime expiration = 0; { // scope for statement mozStorageStatementScoper scoper(mDBGetIconInfo); rv = BindStatementURI(mDBGetIconInfo, 0, aFaviconURI); NS_ENSURE_SUCCESS(rv, rv); PRBool hasMatch; rv = mDBGetIconInfo->ExecuteStep(&hasMatch); NS_ENSURE_SUCCESS(rv, rv); if (hasMatch) { PRInt32 dataSize; mDBGetIconInfo->GetInt32(1, &dataSize); hasData = dataSize > 0; mDBGetIconInfo->GetInt64(2, &expiration); } } // See if this favicon has expired yet. We don't want to waste time reloading // from the web or cache if we have a recent version. PRTime now = PR_Now(); if (hasData && now < expiration && ! aForceReload) { // data still valid, no need to reload // For page revisits (pretty common) we DON'T want to send out any // notifications if we've already set the favicon. These notifications will // cause parts of the UI to update and will be slow. This also saves us a // database write in these cases. nsCOMPtr<nsIURI> oldFavicon; PRBool faviconsEqual; if (NS_SUCCEEDED(GetFaviconForPage(page, getter_AddRefs(oldFavicon))) && NS_SUCCEEDED(aFaviconURI->Equals(oldFavicon, &faviconsEqual)) && faviconsEqual) return NS_OK; // already set // This will associate the favicon URL with the page. rv = SetFaviconUrlForPageInternal(page, aFaviconURI, &hasData, &expiration); NS_ENSURE_SUCCESS(rv, rv); SendFaviconNotifications(page, aFaviconURI); UpdateBookmarkRedirectFavicon(page, aFaviconURI); return NS_OK; } nsCOMPtr<nsIIOService> ioservice = do_GetIOService(&rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIChannel> channel; rv = ioservice->NewChannelFromURI(aFaviconURI, getter_AddRefs(channel)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIStreamListener> listener = new FaviconLoadListener(this, page, aFaviconURI, channel); NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY); nsCOMPtr<nsIInterfaceRequestor> listenerRequestor = do_QueryInterface(listener, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = channel->SetNotificationCallbacks(listenerRequestor); NS_ENSURE_SUCCESS(rv, rv); rv = channel->AsyncOpen(listener, nsnull); NS_ENSURE_SUCCESS(rv, rv); // DB will be update and observers will be notified when the data has // finished loading return NS_OK; }
nsresult GetAllHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) { nsCString indexTable; if (mIndex->IsUnique()) { indexTable.AssignLiteral("unique_index_data"); } else { indexTable.AssignLiteral("index_data"); } nsCString keyRangeClause; if (mKeyRange) { mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("value"), keyRangeClause); } nsCString limitClause; if (mLimit != PR_UINT32_MAX) { limitClause = NS_LITERAL_CSTRING(" LIMIT "); limitClause.AppendInt(mLimit); } nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data " "INNER JOIN ") + indexTable + NS_LITERAL_CSTRING(" AS index_table ON object_data.id = " "index_table.object_data_id " "WHERE index_id = :index_id") + keyRangeClause + limitClause; nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query); NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); mozStorageStatementScoper scoper(stmt); nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"), mIndex->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (mKeyRange) { rv = mKeyRange->BindToStatement(stmt); NS_ENSURE_SUCCESS(rv, rv); } mCloneReadInfos.SetCapacity(50); bool hasResult; while(NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) { if (mCloneReadInfos.Capacity() == mCloneReadInfos.Length()) { mCloneReadInfos.SetCapacity(mCloneReadInfos.Capacity() * 2); } StructuredCloneReadInfo* readInfo = mCloneReadInfos.AppendElement(); NS_ASSERTION(readInfo, "This shouldn't fail!"); rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1, mDatabase->Manager(), *readInfo); NS_ENSURE_SUCCESS(rv, rv); } NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); return NS_OK; }
nsresult purpleDNSRequest::OnLookupComplete(nsICancelable *request, nsIDNSRecord *record, nsresult status) { NS_ASSERTION(NS_IsMainThread(), "wrong thread"); NS_ASSERTION(request == asyncResolv, "wrong request"); purpleAccountScoper scoper(mAccountId); if (NS_FAILED(status)) { Failed("DNS query failed\n"); return NS_OK; } GSList *hosts = NULL; bool more; record->HasMore(&more); if (!more) { Failed("Not found\n"); return NS_OK; } if (NS_FAILED(purpleDNS::Remove(query_data))) { LOG(("DNS resolution completed but result discarded because it was cancelled")); return NS_OK; } mozilla::net::NetAddr netAddr; for (; more; record->HasMore(&more)) { unsigned short port = purple_dnsquery_get_port(query_data); if (NS_FAILED(record->GetNextAddr(port, &netAddr))) { Failed("GetNextAddr failed\n"); return NS_OK; } socklen_t addrlen; struct sockaddr *addr; if (netAddr.raw.family == AF_INET) { addrlen = sizeof(struct sockaddr_in); struct sockaddr_in *s_in = (struct sockaddr_in *)g_malloc0(addrlen); s_in->sin_port = netAddr.inet.port; memcpy(&s_in->sin_addr, &netAddr.inet.ip, sizeof(netAddr.inet.ip)); addr = (struct sockaddr *)s_in; LOG(("Found ip v4 address")); } else if (netAddr.raw.family == AF_INET6) { addrlen = sizeof(struct sockaddr_in6); struct sockaddr_in6 *s_in6 = (struct sockaddr_in6 *)g_malloc0(addrlen); s_in6->sin6_port = netAddr.inet6.port; s_in6->sin6_flowinfo = netAddr.inet6.flowinfo; memcpy(&s_in6->sin6_addr, &netAddr.inet6.ip, sizeof(netAddr.inet6.ip.u8)); s_in6->sin6_scope_id = netAddr.inet6.scope_id; addr = (struct sockaddr *)s_in6; LOG(("Found ip v6 address")); } #ifndef XP_WIN else if (netAddr.raw.family == AF_LOCAL) { addrlen = sizeof(struct sockaddr_un); struct sockaddr_un *s_un = (struct sockaddr_un *)g_malloc0(addrlen); memcpy(&s_un->sun_path, netAddr.local.path, sizeof(netAddr.local.path)); addr = (struct sockaddr *)s_un; LOG(("Found local address")); } #endif else { NS_NOTREACHED("Unknown address type..."); continue; } addr->sa_family = netAddr.raw.family; hosts = g_slist_append(hosts, GINT_TO_POINTER(addrlen)); hosts = g_slist_append(hosts, addr); } LOG(("DNS resolution done")); resolved_cb(query_data, hosts); return NS_OK; }
nsresult OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) { NS_ASSERTION(aConnection, "Passed a null connection!"); nsCString indexTable; if (mIndex->IsUnique()) { indexTable.AssignLiteral("unique_index_data"); } else { indexTable.AssignLiteral("index_data"); } NS_NAMED_LITERAL_CSTRING(value, "index_table.value"); nsCString keyRangeClause; if (mKeyRange) { mKeyRange->GetBindingClause(value, keyRangeClause); } nsCAutoString directionClause(" ORDER BY index_table.value "); switch (mDirection) { case nsIIDBCursor::NEXT: case nsIIDBCursor::NEXT_NO_DUPLICATE: directionClause += NS_LITERAL_CSTRING("ASC, index_table.object_data_key ASC"); break; case nsIIDBCursor::PREV: directionClause += NS_LITERAL_CSTRING("DESC, index_table.object_data_key DESC"); break; case nsIIDBCursor::PREV_NO_DUPLICATE: directionClause += NS_LITERAL_CSTRING("DESC, index_table.object_data_key ASC"); break; default: NS_NOTREACHED("Unknown direction!"); } nsCString firstQuery = NS_LITERAL_CSTRING("SELECT index_table.value, " "index_table.object_data_key, object_data.data, " "object_data.file_ids FROM ") + indexTable + NS_LITERAL_CSTRING(" AS index_table INNER JOIN object_data ON " "index_table.object_data_id = object_data.id " "WHERE index_table.index_id = :id") + keyRangeClause + directionClause + NS_LITERAL_CSTRING(" LIMIT 1"); nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(firstQuery); NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); mozStorageStatementScoper scoper(stmt); nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mIndex->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (mKeyRange) { rv = mKeyRange->BindToStatement(stmt); NS_ENSURE_SUCCESS(rv, rv); } bool hasResult; rv = stmt->ExecuteStep(&hasResult); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (!hasResult) { mKey.Unset(); return NS_OK; } rv = mKey.SetFromStatement(stmt, 0); NS_ENSURE_SUCCESS(rv, rv); rv = mObjectKey.SetFromStatement(stmt, 1); NS_ENSURE_SUCCESS(rv, rv); rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 2, 3, mDatabase->Manager(), mCloneReadInfo); NS_ENSURE_SUCCESS(rv, rv); // Now we need to make the query to get the next match. nsCAutoString queryStart = NS_LITERAL_CSTRING("SELECT index_table.value, " "index_table.object_data_key, object_data.data, " "object_data.file_ids FROM ") + indexTable + NS_LITERAL_CSTRING(" AS index_table INNER JOIN object_data ON " "index_table.object_data_id = object_data.id " "WHERE index_table.index_id = :id"); NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key"); NS_NAMED_LITERAL_CSTRING(limit, " LIMIT "); switch (mDirection) { case nsIIDBCursor::NEXT: if (mKeyRange && !mKeyRange->Upper().IsUnset()) { AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(), queryStart); mRangeKey = mKeyRange->Upper(); } mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND index_table.value >= :current_key AND " "( index_table.value > :current_key OR " " index_table.object_data_key > :object_key ) ") + directionClause + limit; mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND index_table.value >= :current_key") + directionClause + limit; break; case nsIIDBCursor::NEXT_NO_DUPLICATE: if (mKeyRange && !mKeyRange->Upper().IsUnset()) { AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(), queryStart); mRangeKey = mKeyRange->Upper(); } mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND index_table.value > :current_key") + directionClause + limit; mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND index_table.value >= :current_key") + directionClause + limit; break; case nsIIDBCursor::PREV: if (mKeyRange && !mKeyRange->Lower().IsUnset()) { AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(), queryStart); mRangeKey = mKeyRange->Lower(); } mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND index_table.value <= :current_key AND " "( index_table.value < :current_key OR " " index_table.object_data_key < :object_key ) ") + directionClause + limit; mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND index_table.value <= :current_key") + directionClause + limit; break; case nsIIDBCursor::PREV_NO_DUPLICATE: if (mKeyRange && !mKeyRange->Lower().IsUnset()) { AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(), queryStart); mRangeKey = mKeyRange->Lower(); } mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND index_table.value < :current_key") + directionClause + limit; mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND index_table.value <= :current_key") + directionClause + limit; break; default: NS_NOTREACHED("Unknown direction type!"); } return NS_OK; }
nsresult GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection) { NS_ASSERTION(aConnection, "Passed a null connection!"); if (!mCloneBuffers.SetCapacity(50)) { NS_ERROR("Out of memory!"); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } nsCString dataTableName; nsCString objectDataId; nsCString indexTableName; if (mIndex->IsAutoIncrement()) { dataTableName.AssignLiteral("ai_object_data"); objectDataId.AssignLiteral("ai_object_data_id"); if (mIndex->IsUnique()) { indexTableName.AssignLiteral("ai_unique_index_data"); } else { indexTableName.AssignLiteral("ai_index_data"); } } else { dataTableName.AssignLiteral("object_data"); objectDataId.AssignLiteral("object_data_id"); if (mIndex->IsUnique()) { indexTableName.AssignLiteral("unique_index_data"); } else { indexTableName.AssignLiteral("index_data"); } } NS_NAMED_LITERAL_CSTRING(indexId, "index_id"); NS_NAMED_LITERAL_CSTRING(value, "value"); nsCString keyClause; if (!mKey.IsUnset()) { keyClause = NS_LITERAL_CSTRING(" AND ") + value + NS_LITERAL_CSTRING(" = :") + value; } nsCString limitClause; if (mLimit != PR_UINT32_MAX) { limitClause = NS_LITERAL_CSTRING(" LIMIT "); limitClause.AppendInt(mLimit); } nsCString query = NS_LITERAL_CSTRING("SELECT data FROM ") + dataTableName + NS_LITERAL_CSTRING(" INNER JOIN ") + indexTableName + NS_LITERAL_CSTRING(" ON ") + dataTableName + NS_LITERAL_CSTRING(".id = ") + indexTableName + NS_LITERAL_CSTRING(".") + objectDataId + NS_LITERAL_CSTRING(" WHERE ") + indexId + NS_LITERAL_CSTRING(" = :") + indexId + keyClause + limitClause; nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query); NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); mozStorageStatementScoper scoper(stmt); nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (!mKey.IsUnset()) { if (mKey.IsInt()) { rv = stmt->BindInt64ByName(value, mKey.IntValue()); } else if (mKey.IsString()) { rv = stmt->BindStringByName(value, mKey.StringValue()); } else { NS_NOTREACHED("Bad key type!"); } NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); } PRBool hasResult; while(NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) { if (mCloneBuffers.Capacity() == mCloneBuffers.Length()) { if (!mCloneBuffers.SetCapacity(mCloneBuffers.Capacity() * 2)) { NS_ERROR("Out of memory!"); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } } JSAutoStructuredCloneBuffer* buffer = mCloneBuffers.AppendElement(); NS_ASSERTION(buffer, "This shouldn't fail!"); rv = IDBObjectStore::GetStructuredCloneDataFromStatement(stmt, 0, *buffer); NS_ENSURE_SUCCESS(rv, rv); } NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); return NS_OK; }
nsresult GetAllKeysHelper::DoDatabaseWork(mozIStorageConnection* aConnection) { NS_ASSERTION(aConnection, "Passed a null connection!"); if (!mKeys.SetCapacity(50)) { NS_ERROR("Out of memory!"); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } nsCString keyColumn; nsCString tableName; if (mIndex->IsAutoIncrement()) { keyColumn.AssignLiteral("ai_object_data_id"); if (mIndex->IsUnique()) { tableName.AssignLiteral("ai_unique_index_data"); } else { tableName.AssignLiteral("ai_index_data"); } } else { keyColumn.AssignLiteral("object_data_key"); if (mIndex->IsUnique()) { tableName.AssignLiteral("unique_index_data"); } else { tableName.AssignLiteral("index_data"); } } NS_NAMED_LITERAL_CSTRING(indexId, "index_id"); NS_NAMED_LITERAL_CSTRING(value, "value"); nsCString keyClause; if (!mKey.IsUnset()) { keyClause = NS_LITERAL_CSTRING(" AND ") + value + NS_LITERAL_CSTRING(" = :") + value; } nsCString limitClause; if (mLimit != PR_UINT32_MAX) { limitClause = NS_LITERAL_CSTRING(" LIMIT "); limitClause.AppendInt(mLimit); } nsCString query = NS_LITERAL_CSTRING("SELECT ") + keyColumn + NS_LITERAL_CSTRING(" FROM ") + tableName + NS_LITERAL_CSTRING(" WHERE ") + indexId + NS_LITERAL_CSTRING(" = :") + indexId + keyClause + limitClause; nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query); NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); mozStorageStatementScoper scoper(stmt); nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (!mKey.IsUnset()) { if (mKey.IsInt()) { rv = stmt->BindInt64ByName(value, mKey.IntValue()); } else if (mKey.IsString()) { rv = stmt->BindStringByName(value, mKey.StringValue()); } else { NS_NOTREACHED("Bad key type!"); } NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); } PRBool hasResult; while(NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) { if (mKeys.Capacity() == mKeys.Length()) { if (!mKeys.SetCapacity(mKeys.Capacity() * 2)) { NS_ERROR("Out of memory!"); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } } Key* key = mKeys.AppendElement(); NS_ASSERTION(key, "This shouldn't fail!"); PRInt32 keyType; rv = stmt->GetTypeOfIndex(0, &keyType); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ASSERTION(keyType == mozIStorageStatement::VALUE_TYPE_INTEGER || keyType == mozIStorageStatement::VALUE_TYPE_TEXT, "Bad key type!"); if (keyType == mozIStorageStatement::VALUE_TYPE_INTEGER) { *key = stmt->AsInt64(0); } else if (keyType == mozIStorageStatement::VALUE_TYPE_TEXT) { rv = stmt->GetString(0, key->ToString()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); } else { NS_NOTREACHED("Bad SQLite type!"); } } NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); return NS_OK; }
nsresult OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) { NS_ASSERTION(aConnection, "Passed a null connection!"); nsCString indexTable; nsCString objectTable; nsCString objectDataIdColumn; nsCString keyValueColumn; if (mIndex->IsAutoIncrement()) { objectTable.AssignLiteral("ai_object_data"); objectDataIdColumn.AssignLiteral("ai_object_data_id"); keyValueColumn.AssignLiteral("id"); if (mIndex->IsUnique()) { indexTable.AssignLiteral("ai_unique_index_data"); } else { indexTable.AssignLiteral("ai_index_data"); } } else { objectTable.AssignLiteral("object_data"); objectDataIdColumn.AssignLiteral("object_data_id"); keyValueColumn.AssignLiteral("key_value"); if (mIndex->IsUnique()) { indexTable.AssignLiteral("unique_index_data"); } else { indexTable.AssignLiteral("index_data"); } } NS_NAMED_LITERAL_CSTRING(id, "id"); NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key"); NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key"); nsCString value = indexTable + NS_LITERAL_CSTRING(".value"); nsCString data = objectTable + NS_LITERAL_CSTRING(".data"); nsCString keyValue = objectTable + NS_LITERAL_CSTRING(".") + keyValueColumn; nsCAutoString keyRangeClause; if (!mLowerKey.IsUnset()) { AppendConditionClause(value, lowerKeyName, false, !mLowerOpen, keyRangeClause); } if (!mUpperKey.IsUnset()) { AppendConditionClause(value, upperKeyName, true, !mUpperOpen, keyRangeClause); } nsCAutoString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + value; switch (mDirection) { case nsIIDBCursor::NEXT: case nsIIDBCursor::NEXT_NO_DUPLICATE: directionClause.AppendLiteral(" ASC"); break; case nsIIDBCursor::PREV: case nsIIDBCursor::PREV_NO_DUPLICATE: directionClause.AppendLiteral(" DESC"); break; default: NS_NOTREACHED("Unknown direction!"); } directionClause += NS_LITERAL_CSTRING(", ") + keyValue + NS_LITERAL_CSTRING(" ASC"); nsCString firstQuery = NS_LITERAL_CSTRING("SELECT ") + value + NS_LITERAL_CSTRING(", ") + keyValue + NS_LITERAL_CSTRING(", ") + data + NS_LITERAL_CSTRING(" FROM ") + objectTable + NS_LITERAL_CSTRING(" INNER JOIN ") + indexTable + NS_LITERAL_CSTRING(" ON ") + indexTable + NS_LITERAL_CSTRING(".") + objectDataIdColumn + NS_LITERAL_CSTRING(" = ") + objectTable + NS_LITERAL_CSTRING(".id WHERE ") + indexTable + NS_LITERAL_CSTRING(".index_id = :id") + keyRangeClause + directionClause + NS_LITERAL_CSTRING(" LIMIT 1"); nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(firstQuery); NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); mozStorageStatementScoper scoper(stmt); nsresult rv = stmt->BindInt64ByName(id, mIndex->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (!mLowerKey.IsUnset()) { if (mLowerKey.IsString()) { rv = stmt->BindStringByName(lowerKeyName, mLowerKey.StringValue()); } else if (mLowerKey.IsInt()) { rv = stmt->BindInt64ByName(lowerKeyName, mLowerKey.IntValue()); } else { NS_NOTREACHED("Bad key!"); } NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); } if (!mUpperKey.IsUnset()) { if (mUpperKey.IsString()) { rv = stmt->BindStringByName(upperKeyName, mUpperKey.StringValue()); } else if (mUpperKey.IsInt()) { rv = stmt->BindInt64ByName(upperKeyName, mUpperKey.IntValue()); } else { NS_NOTREACHED("Bad key!"); } NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); } PRBool hasResult; rv = stmt->ExecuteStep(&hasResult); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (!hasResult) { mKey = Key::UNSETKEY; return NS_OK; } PRInt32 keyType; rv = stmt->GetTypeOfIndex(0, &keyType); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ASSERTION(keyType == mozIStorageStatement::VALUE_TYPE_INTEGER || keyType == mozIStorageStatement::VALUE_TYPE_TEXT, "Bad key type!"); if (keyType == mozIStorageStatement::VALUE_TYPE_INTEGER) { mKey = stmt->AsInt64(0); } else if (keyType == mozIStorageStatement::VALUE_TYPE_TEXT) { rv = stmt->GetString(0, mKey.ToString()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); } else { NS_NOTREACHED("Bad SQLite type!"); } rv = stmt->GetTypeOfIndex(1, &keyType); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ASSERTION(keyType == mozIStorageStatement::VALUE_TYPE_INTEGER || keyType == mozIStorageStatement::VALUE_TYPE_TEXT, "Bad key type!"); if (keyType == mozIStorageStatement::VALUE_TYPE_INTEGER) { mObjectKey = stmt->AsInt64(1); } else if (keyType == mozIStorageStatement::VALUE_TYPE_TEXT) { rv = stmt->GetString(1, mObjectKey.ToString()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); } else { NS_NOTREACHED("Bad SQLite type!"); } rv = IDBObjectStore::GetStructuredCloneDataFromStatement(stmt, 2, mCloneBuffer); NS_ENSURE_SUCCESS(rv, rv); // Now we need to make the query to get the next match. nsCAutoString queryStart = NS_LITERAL_CSTRING("SELECT ") + value + NS_LITERAL_CSTRING(", ") + keyValue + NS_LITERAL_CSTRING(", ") + data + NS_LITERAL_CSTRING(" FROM ") + objectTable + NS_LITERAL_CSTRING(" INNER JOIN ") + indexTable + NS_LITERAL_CSTRING(" ON ") + indexTable + NS_LITERAL_CSTRING(".") + objectDataIdColumn + NS_LITERAL_CSTRING(" = ") + objectTable + NS_LITERAL_CSTRING(".id WHERE ") + indexTable + NS_LITERAL_CSTRING(".index_id = :id"); NS_NAMED_LITERAL_CSTRING(currentKey, "current_key"); NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key"); NS_NAMED_LITERAL_CSTRING(objectKey, "object_key"); switch (mDirection) { case nsIIDBCursor::NEXT: if (!mUpperKey.IsUnset()) { AppendConditionClause(value, rangeKey, true, !mUpperOpen, queryStart); mRangeKey = mUpperKey; } mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND ( ( ") + value + NS_LITERAL_CSTRING(" = :") + currentKey + NS_LITERAL_CSTRING(" AND ") + keyValue + NS_LITERAL_CSTRING(" > :") + objectKey + NS_LITERAL_CSTRING(" ) OR ( ") + value + NS_LITERAL_CSTRING(" > :") + currentKey + NS_LITERAL_CSTRING(" ) )") + directionClause + NS_LITERAL_CSTRING(" LIMIT 1"); mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND ") + value + NS_LITERAL_CSTRING(" >= :") + currentKey + directionClause + NS_LITERAL_CSTRING(" LIMIT 1"); break; case nsIIDBCursor::NEXT_NO_DUPLICATE: if (!mUpperKey.IsUnset()) { AppendConditionClause(value, rangeKey, true, !mUpperOpen, queryStart); mRangeKey = mUpperKey; } mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND ") + value + NS_LITERAL_CSTRING(" > :") + currentKey + directionClause + NS_LITERAL_CSTRING(" LIMIT 1"); mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND ") + value + NS_LITERAL_CSTRING(" >= :") + currentKey + directionClause + NS_LITERAL_CSTRING(" LIMIT 1"); break; case nsIIDBCursor::PREV: if (!mLowerKey.IsUnset()) { AppendConditionClause(value, rangeKey, false, !mLowerOpen, queryStart); mRangeKey = mLowerKey; } mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND ( ( ") + value + NS_LITERAL_CSTRING(" = :") + currentKey + NS_LITERAL_CSTRING(" AND ") + keyValue + NS_LITERAL_CSTRING(" < :") + objectKey + NS_LITERAL_CSTRING(" ) OR ( ") + value + NS_LITERAL_CSTRING(" < :") + currentKey + NS_LITERAL_CSTRING(" ) )") + directionClause + NS_LITERAL_CSTRING(" LIMIT 1"); mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND ") + value + NS_LITERAL_CSTRING(" <= :") + currentKey + directionClause + NS_LITERAL_CSTRING(" LIMIT 1"); break; case nsIIDBCursor::PREV_NO_DUPLICATE: if (!mLowerKey.IsUnset()) { AppendConditionClause(value, rangeKey, false, !mLowerOpen, queryStart); mRangeKey = mLowerKey; } mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND ") + value + NS_LITERAL_CSTRING(" < :") + currentKey + directionClause + NS_LITERAL_CSTRING(" LIMIT 1"); mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND ") + value + NS_LITERAL_CSTRING(" <= :") + currentKey + directionClause + NS_LITERAL_CSTRING(" LIMIT 1"); break; default: NS_NOTREACHED("Unknown direction type!"); } return NS_OK; }
void test_UTFStrings() { nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); // Create table with a single string column. (void)db->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "CREATE TABLE test (str STRING)" )); // Create statements to INSERT and SELECT the string. nsCOMPtr<mozIStorageStatement> insert, select; (void)db->CreateStatement(NS_LITERAL_CSTRING( "INSERT INTO test (str) VALUES (?1)" ), getter_AddRefs(insert)); (void)db->CreateStatement(NS_LITERAL_CSTRING( "SELECT str FROM test" ), getter_AddRefs(select)); // Roundtrip a UTF8 string through the table, using UTF8 input and output. static const char sCharArray[] = "I'm a \xc3\xbb\xc3\xbc\xc3\xa2\xc3\xa4\xc3\xa7 UTF8 string!"; nsCAutoString insertedUTF8(sCharArray, NS_ARRAY_LENGTH(sCharArray) - 1); do_check_true(insertedUTF8.Length() == NS_ARRAY_LENGTH(sCharArray) - 1); NS_ConvertUTF8toUTF16 insertedUTF16(insertedUTF8); do_check_true(insertedUTF8 == NS_ConvertUTF16toUTF8(insertedUTF16)); { mozStorageStatementScoper scoper(insert); bool hasResult; do_check_true(NS_SUCCEEDED(insert->BindUTF8StringByIndex(0, insertedUTF8))); do_check_true(NS_SUCCEEDED(insert->ExecuteStep(&hasResult))); do_check_false(hasResult); } { nsCAutoString result; mozStorageStatementScoper scoper(select); bool hasResult; do_check_true(NS_SUCCEEDED(select->ExecuteStep(&hasResult))); do_check_true(hasResult); do_check_true(NS_SUCCEEDED(select->GetUTF8String(0, result))); do_check_true(result == insertedUTF8); } // Use UTF8 input and UTF16 output. { nsAutoString result; mozStorageStatementScoper scoper(select); bool hasResult; do_check_true(NS_SUCCEEDED(select->ExecuteStep(&hasResult))); do_check_true(hasResult); do_check_true(NS_SUCCEEDED(select->GetString(0, result))); do_check_true(result == insertedUTF16); } (void)db->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DELETE FROM test")); // Roundtrip the same string using UTF16 input and UTF8 output. { mozStorageStatementScoper scoper(insert); bool hasResult; do_check_true(NS_SUCCEEDED(insert->BindStringByIndex(0, insertedUTF16))); do_check_true(NS_SUCCEEDED(insert->ExecuteStep(&hasResult))); do_check_false(hasResult); } { nsCAutoString result; mozStorageStatementScoper scoper(select); bool hasResult; do_check_true(NS_SUCCEEDED(select->ExecuteStep(&hasResult))); do_check_true(hasResult); do_check_true(NS_SUCCEEDED(select->GetUTF8String(0, result))); do_check_true(result == insertedUTF8); } // Use UTF16 input and UTF16 output. { nsAutoString result; mozStorageStatementScoper scoper(select); bool hasResult; do_check_true(NS_SUCCEEDED(select->ExecuteStep(&hasResult))); do_check_true(hasResult); do_check_true(NS_SUCCEEDED(select->GetString(0, result))); do_check_true(result == insertedUTF16); } (void)db->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DELETE FROM test")); }