123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505 |
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "prprf.h"
- #include "nsIDOMNodeList.h"
- #include "nsUnicharUtils.h"
- #include "nsArrayUtils.h"
- #include "nsVariant.h"
- #include "nsAppDirectoryServiceDefs.h"
- #include "nsIURI.h"
- #include "nsIFileChannel.h"
- #include "nsIFile.h"
- #include "nsGkAtoms.h"
- #include "nsContentUtils.h"
- #include "nsXULTemplateBuilder.h"
- #include "nsXULTemplateResultStorage.h"
- #include "nsXULContentUtils.h"
- #include "nsXULSortService.h"
- #include "mozIStorageService.h"
- #include "nsIChannel.h"
- #include "nsIDocument.h"
- #include "nsNetUtil.h"
- using mozilla::fallible;
- //----------------------------------------------------------------------
- //
- // nsXULTemplateResultSetStorage
- //
- NS_IMPL_ISUPPORTS(nsXULTemplateResultSetStorage, nsISimpleEnumerator)
- nsXULTemplateResultSetStorage::nsXULTemplateResultSetStorage(mozIStorageStatement* aStatement)
- : mStatement(aStatement)
- {
- uint32_t count;
- nsresult rv = aStatement->GetColumnCount(&count);
- if (NS_FAILED(rv)) {
- mStatement = nullptr;
- return;
- }
- for (uint32_t c = 0; c < count; c++) {
- nsAutoCString name;
- rv = aStatement->GetColumnName(c, name);
- if (NS_SUCCEEDED(rv)) {
- nsCOMPtr<nsIAtom> columnName = NS_Atomize(NS_LITERAL_CSTRING("?") + name);
- mColumnNames.AppendObject(columnName);
- }
- }
- }
- NS_IMETHODIMP
- nsXULTemplateResultSetStorage::HasMoreElements(bool *aResult)
- {
- if (!mStatement) {
- *aResult = false;
- return NS_OK;
- }
- nsresult rv = mStatement->ExecuteStep(aResult);
- NS_ENSURE_SUCCESS(rv, rv);
- // Because the nsXULTemplateResultSetStorage is owned by many nsXULTemplateResultStorage objects,
- // it could live longer than it needed to get results.
- // So we destroy the statement to free resources when all results are fetched
- if (!*aResult) {
- mStatement = nullptr;
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsXULTemplateResultSetStorage::GetNext(nsISupports **aResult)
- {
- nsXULTemplateResultStorage* result =
- new nsXULTemplateResultStorage(this);
- *aResult = result;
- NS_ADDREF(result);
- return NS_OK;
- }
- int32_t
- nsXULTemplateResultSetStorage::GetColumnIndex(nsIAtom* aColumnName)
- {
- int32_t count = mColumnNames.Count();
- for (int32_t c = 0; c < count; c++) {
- if (mColumnNames[c] == aColumnName)
- return c;
- }
- return -1;
- }
- void
- nsXULTemplateResultSetStorage::FillColumnValues(nsCOMArray<nsIVariant>& aArray)
- {
- if (!mStatement)
- return;
- int32_t count = mColumnNames.Count();
- for (int32_t c = 0; c < count; c++) {
- RefPtr<nsVariant> value = new nsVariant();
- int32_t type;
- mStatement->GetTypeOfIndex(c, &type);
- if (type == mStatement->VALUE_TYPE_INTEGER) {
- int64_t val = mStatement->AsInt64(c);
- value->SetAsInt64(val);
- }
- else if (type == mStatement->VALUE_TYPE_FLOAT) {
- double val = mStatement->AsDouble(c);
- value->SetAsDouble(val);
- }
- else {
- nsAutoString val;
- nsresult rv = mStatement->GetString(c, val);
- if (NS_FAILED(rv))
- value->SetAsAString(EmptyString());
- else
- value->SetAsAString(val);
- }
- aArray.AppendObject(value);
- }
- }
- //----------------------------------------------------------------------
- //
- // nsXULTemplateQueryProcessorStorage
- //
- NS_IMPL_ISUPPORTS(nsXULTemplateQueryProcessorStorage,
- nsIXULTemplateQueryProcessor)
- nsXULTemplateQueryProcessorStorage::nsXULTemplateQueryProcessorStorage()
- : mGenerationStarted(false)
- {
- }
- NS_IMETHODIMP
- nsXULTemplateQueryProcessorStorage::GetDatasource(nsIArray* aDataSources,
- nsIDOMNode* aRootNode,
- bool aIsTrusted,
- nsIXULTemplateBuilder* aBuilder,
- bool* aShouldDelayBuilding,
- nsISupports** aReturn)
- {
- *aReturn = nullptr;
- *aShouldDelayBuilding = false;
- if (!aIsTrusted) {
- return NS_OK;
- }
- uint32_t length;
- nsresult rv = aDataSources->GetLength(&length);
- NS_ENSURE_SUCCESS(rv, rv);
- if (length == 0) {
- return NS_OK;
- }
- // We get only the first uri. This query processor supports
- // only one database at a time.
- nsCOMPtr<nsIURI> uri;
- uri = do_QueryElementAt(aDataSources, 0);
- if (!uri) {
- // No uri in the list of datasources
- return NS_OK;
- }
- nsCOMPtr<mozIStorageService> storage =
- do_GetService("@mozilla.org/storage/service;1", &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIFile> databaseFile;
- nsAutoCString scheme;
- rv = uri->GetScheme(scheme);
- NS_ENSURE_SUCCESS(rv, rv);
- if (scheme.EqualsLiteral("profile")) {
- nsAutoCString path;
- rv = uri->GetPath(path);
- NS_ENSURE_SUCCESS(rv, rv);
- if (path.IsEmpty()) {
- return NS_ERROR_FAILURE;
- }
- rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
- getter_AddRefs(databaseFile));
- NS_ENSURE_SUCCESS(rv, rv);
- rv = databaseFile->AppendNative(path);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- else {
- nsCOMPtr<nsIChannel> channel;
- nsCOMPtr<nsINode> node = do_QueryInterface(aRootNode);
- // The following channel is never openend, so it does not matter what
- // securityFlags we pass; let's follow the principle of least privilege.
- rv = NS_NewChannel(getter_AddRefs(channel),
- uri,
- node,
- nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
- nsIContentPolicy::TYPE_OTHER);
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(channel, &rv);
- if (NS_FAILED(rv)) { // if it fails, not a file url
- nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_BAD_URI);
- return rv;
- }
- rv = fileChannel->GetFile(getter_AddRefs(databaseFile));
- NS_ENSURE_SUCCESS(rv, rv);
- }
- // ok now we have an URI of a sqlite file
- nsCOMPtr<mozIStorageConnection> connection;
- rv = storage->OpenDatabase(databaseFile, getter_AddRefs(connection));
- if (NS_FAILED(rv)) {
- nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_CANNOT_OPEN_DATABASE);
- return rv;
- }
- connection.forget(aReturn);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsXULTemplateQueryProcessorStorage::InitializeForBuilding(nsISupports* aDatasource,
- nsIXULTemplateBuilder* aBuilder,
- nsIDOMNode* aRootNode)
- {
- NS_ENSURE_STATE(!mGenerationStarted);
- mStorageConnection = do_QueryInterface(aDatasource);
- if (!mStorageConnection)
- return NS_ERROR_INVALID_ARG;
- bool ready;
- mStorageConnection->GetConnectionReady(&ready);
- if (!ready)
- return NS_ERROR_UNEXPECTED;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsXULTemplateQueryProcessorStorage::Done()
- {
- mGenerationStarted = false;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsXULTemplateQueryProcessorStorage::CompileQuery(nsIXULTemplateBuilder* aBuilder,
- nsIDOMNode* aQueryNode,
- nsIAtom* aRefVariable,
- nsIAtom* aMemberVariable,
- nsISupports** aReturn)
- {
- nsCOMPtr<nsIDOMNodeList> childNodes;
- aQueryNode->GetChildNodes(getter_AddRefs(childNodes));
- uint32_t length;
- childNodes->GetLength(&length);
- nsCOMPtr<mozIStorageStatement> statement;
- nsCOMPtr<nsIContent> queryContent = do_QueryInterface(aQueryNode);
- nsAutoString sqlQuery;
- // Let's get all text nodes (which should be the query)
- if (!nsContentUtils::GetNodeTextContent(queryContent, false, sqlQuery, fallible)) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- nsresult rv = mStorageConnection->CreateStatement(NS_ConvertUTF16toUTF8(sqlQuery),
- getter_AddRefs(statement));
- if (NS_FAILED(rv)) {
- nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_BAD_QUERY);
- return rv;
- }
- uint32_t parameterCount = 0;
- for (nsIContent* child = queryContent->GetFirstChild();
- child;
- child = child->GetNextSibling()) {
- if (child->NodeInfo()->Equals(nsGkAtoms::param, kNameSpaceID_XUL)) {
- nsAutoString value;
- if (!nsContentUtils::GetNodeTextContent(child, false, value, fallible)) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- uint32_t index = parameterCount;
- nsAutoString name, indexValue;
- if (child->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name)) {
- rv = statement->GetParameterIndex(NS_ConvertUTF16toUTF8(name),
- &index);
- if (NS_FAILED(rv)) {
- nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_UNKNOWN_QUERY_PARAMETER);
- return rv;
- }
- parameterCount++;
- }
- else if (child->GetAttr(kNameSpaceID_None, nsGkAtoms::index, indexValue)) {
- PR_sscanf(NS_ConvertUTF16toUTF8(indexValue).get(),"%d",&index);
- if (index > 0)
- index--;
- }
- else {
- parameterCount++;
- }
- static nsIContent::AttrValuesArray sTypeValues[] =
- { &nsGkAtoms::int32, &nsGkAtoms::integer, &nsGkAtoms::int64,
- &nsGkAtoms::null, &nsGkAtoms::double_, &nsGkAtoms::string, nullptr };
- int32_t typeError = 1;
- int32_t typeValue = child->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
- sTypeValues, eCaseMatters);
- rv = NS_ERROR_ILLEGAL_VALUE;
- int32_t valInt32 = 0;
- int64_t valInt64 = 0;
- double valFloat = 0;
- switch (typeValue) {
- case 0:
- case 1:
- typeError = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(),"%d",&valInt32);
- if (typeError > 0)
- rv = statement->BindInt32ByIndex(index, valInt32);
- break;
- case 2:
- typeError = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(),"%lld",&valInt64);
- if (typeError > 0)
- rv = statement->BindInt64ByIndex(index, valInt64);
- break;
- case 3:
- rv = statement->BindNullByIndex(index);
- break;
- case 4:
- typeError = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(),"%lf",&valFloat);
- if (typeError > 0)
- rv = statement->BindDoubleByIndex(index, valFloat);
- break;
- case 5:
- case nsIContent::ATTR_MISSING:
- rv = statement->BindStringByIndex(index, value);
- break;
- default:
- typeError = 0;
- }
- if (typeError <= 0) {
- nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_WRONG_TYPE_QUERY_PARAMETER);
- return rv;
- }
- if (NS_FAILED(rv)) {
- nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_QUERY_PARAMETER_NOT_BOUND);
- return rv;
- }
- }
- }
- *aReturn = statement;
- NS_IF_ADDREF(*aReturn);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsXULTemplateQueryProcessorStorage::GenerateResults(nsISupports* aDatasource,
- nsIXULTemplateResult* aRef,
- nsISupports* aQuery,
- nsISimpleEnumerator** aResults)
- {
- mGenerationStarted = true;
- nsCOMPtr<mozIStorageStatement> statement = do_QueryInterface(aQuery);
- if (!statement)
- return NS_ERROR_FAILURE;
- nsXULTemplateResultSetStorage* results =
- new nsXULTemplateResultSetStorage(statement);
- *aResults = results;
- NS_ADDREF(*aResults);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsXULTemplateQueryProcessorStorage::AddBinding(nsIDOMNode* aRuleNode,
- nsIAtom* aVar,
- nsIAtom* aRef,
- const nsAString& aExpr)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- nsXULTemplateQueryProcessorStorage::TranslateRef(nsISupports* aDatasource,
- const nsAString& aRefString,
- nsIXULTemplateResult** aRef)
- {
- nsXULTemplateResultStorage* result =
- new nsXULTemplateResultStorage(nullptr);
- *aRef = result;
- NS_ADDREF(*aRef);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsXULTemplateQueryProcessorStorage::CompareResults(nsIXULTemplateResult* aLeft,
- nsIXULTemplateResult* aRight,
- nsIAtom* aVar,
- uint32_t aSortHints,
- int32_t* aResult)
- {
- *aResult = 0;
- if (!aVar)
- return NS_OK;
- // We're going to see if values are integers or float, to perform
- // a suitable comparison
- nsCOMPtr<nsISupports> leftValue, rightValue;
- if (aLeft)
- aLeft->GetBindingObjectFor(aVar, getter_AddRefs(leftValue));
- if (aRight)
- aRight->GetBindingObjectFor(aVar, getter_AddRefs(rightValue));
- if (leftValue && rightValue) {
- nsCOMPtr<nsIVariant> vLeftValue = do_QueryInterface(leftValue);
- nsCOMPtr<nsIVariant> vRightValue = do_QueryInterface(rightValue);
- if (vLeftValue && vRightValue) {
- nsresult rv1, rv2;
- uint16_t vtypeL, vtypeR;
- vLeftValue->GetDataType(&vtypeL);
- vRightValue->GetDataType(&vtypeR);
- if (vtypeL == vtypeR) {
- if (vtypeL == nsIDataType::VTYPE_INT64) {
- int64_t leftValue, rightValue;
- rv1 = vLeftValue->GetAsInt64(&leftValue);
- rv2 = vRightValue->GetAsInt64(&rightValue);
- if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
- if (leftValue > rightValue)
- *aResult = 1;
- else if (leftValue < rightValue)
- *aResult = -1;
- return NS_OK;
- }
- }
- else if (vtypeL == nsIDataType::VTYPE_DOUBLE) {
- double leftValue, rightValue;
- rv1 = vLeftValue->GetAsDouble(&leftValue);
- rv2 = vRightValue->GetAsDouble(&rightValue);
- if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
- if (leftValue > rightValue)
- *aResult = 1;
- else if (leftValue < rightValue)
- *aResult = -1;
- return NS_OK;
- }
- }
- }
- }
- }
- // Values are not integers or floats, so we just compare them as simple strings
- nsAutoString leftVal;
- if (aLeft)
- aLeft->GetBindingFor(aVar, leftVal);
- nsAutoString rightVal;
- if (aRight)
- aRight->GetBindingFor(aVar, rightVal);
- *aResult = XULSortServiceImpl::CompareValues(leftVal, rightVal, aSortHints);
- return NS_OK;
- }
|