nsresult CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection) { nsCString table; if (mIndex->IsUnique()) { table.AssignLiteral("unique_index_data"); } else { table.AssignLiteral("index_data"); } NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key"); NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key"); NS_NAMED_LITERAL_CSTRING(value, "value"); nsCAutoString keyRangeClause; if (mKeyRange) { if (!mKeyRange->Lower().IsUnset()) { AppendConditionClause(value, lowerKeyName, false, !mKeyRange->IsLowerOpen(), keyRangeClause); } if (!mKeyRange->Upper().IsUnset()) { AppendConditionClause(value, upperKeyName, true, !mKeyRange->IsUpperOpen(), keyRangeClause); } } nsCString query = NS_LITERAL_CSTRING("SELECT count(*) FROM ") + table + NS_LITERAL_CSTRING(" WHERE index_id = :id") + keyRangeClause; 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("id"), mIndex->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (mKeyRange) { if (!mKeyRange->Lower().IsUnset()) { rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName); NS_ENSURE_SUCCESS(rv, rv); } if (!mKeyRange->Upper().IsUnset()) { rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName); NS_ENSURE_SUCCESS(rv, rv); } } bool hasResult; rv = stmt->ExecuteStep(&hasResult); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ENSURE_TRUE(hasResult, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); mCount = stmt->AsInt64(0); 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 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; }