content/xul/templates/src/nsXULTemplateQueryProcessorStorage.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "prprf.h"
     8 #include "nsIDOMNodeList.h"
     9 #include "nsUnicharUtils.h"
    11 #include "nsArrayUtils.h"
    12 #include "nsIVariant.h"
    13 #include "nsAppDirectoryServiceDefs.h"
    15 #include "nsIURI.h"
    16 #include "nsIIOService.h"
    17 #include "nsIFileChannel.h"
    18 #include "nsIFile.h"
    19 #include "nsGkAtoms.h"
    20 #include "nsContentUtils.h"
    22 #include "nsXULTemplateBuilder.h"
    23 #include "nsXULTemplateResultStorage.h"
    24 #include "nsXULContentUtils.h"
    25 #include "nsXULSortService.h"
    27 #include "mozIStorageService.h"
    28 #include "nsIChannel.h"
    29 #include "nsIDocument.h"
    31 //----------------------------------------------------------------------
    32 //
    33 // nsXULTemplateResultSetStorage
    34 //
    36 NS_IMPL_ISUPPORTS(nsXULTemplateResultSetStorage, nsISimpleEnumerator)
    39 nsXULTemplateResultSetStorage::nsXULTemplateResultSetStorage(mozIStorageStatement* aStatement)
    40         : mStatement(aStatement)
    41 {
    42     uint32_t count;
    43     nsresult rv = aStatement->GetColumnCount(&count);
    44     if (NS_FAILED(rv)) {
    45         mStatement = nullptr;
    46         return;
    47     }
    48     for (uint32_t c = 0; c < count; c++) {
    49         nsAutoCString name;
    50         rv = aStatement->GetColumnName(c, name);
    51         if (NS_SUCCEEDED(rv)) {
    52             nsCOMPtr<nsIAtom> columnName = do_GetAtom(NS_LITERAL_CSTRING("?") + name);
    53             mColumnNames.AppendObject(columnName);
    54         }
    55     }
    56 }
    58 NS_IMETHODIMP
    59 nsXULTemplateResultSetStorage::HasMoreElements(bool *aResult)
    60 {
    61     if (!mStatement) {
    62         *aResult = false;
    63         return NS_OK;
    64     }
    66     nsresult rv = mStatement->ExecuteStep(aResult);
    67     NS_ENSURE_SUCCESS(rv, rv);
    68     // Because the nsXULTemplateResultSetStorage is owned by many nsXULTemplateResultStorage objects,
    69     // it could live longer than it needed to get results.
    70     // So we destroy the statement to free resources when all results are fetched
    71     if (!*aResult) {
    72         mStatement = nullptr;
    73     }
    74     return NS_OK;
    75 }
    77 NS_IMETHODIMP
    78 nsXULTemplateResultSetStorage::GetNext(nsISupports **aResult)
    79 {
    80     nsXULTemplateResultStorage* result =
    81         new nsXULTemplateResultStorage(this);
    83     if (!result)
    84         return NS_ERROR_OUT_OF_MEMORY;
    86     *aResult = result;
    87     NS_ADDREF(result);
    88     return NS_OK;
    89 }
    92 int32_t
    93 nsXULTemplateResultSetStorage::GetColumnIndex(nsIAtom* aColumnName)
    94 {
    95     int32_t count = mColumnNames.Count();
    96     for (int32_t c = 0; c < count; c++) {
    97         if (mColumnNames[c] == aColumnName)
    98             return c;
    99     }
   101     return -1;
   102 }
   104 void
   105 nsXULTemplateResultSetStorage::FillColumnValues(nsCOMArray<nsIVariant>& aArray)
   106 {
   107     if (!mStatement)
   108         return;
   110     int32_t count = mColumnNames.Count();
   112     for (int32_t c = 0; c < count; c++) {
   113         nsCOMPtr<nsIWritableVariant> value = do_CreateInstance("@mozilla.org/variant;1");
   115         int32_t type;
   116         mStatement->GetTypeOfIndex(c, &type);
   118         if (type == mStatement->VALUE_TYPE_INTEGER) {
   119             int64_t val = mStatement->AsInt64(c);
   120             value->SetAsInt64(val);
   121         }
   122         else if (type == mStatement->VALUE_TYPE_FLOAT) {
   123             double val = mStatement->AsDouble(c);
   124             value->SetAsDouble(val);
   125         }
   126         else {
   127             nsAutoString val;
   128             nsresult rv = mStatement->GetString(c, val);
   129             if (NS_FAILED(rv))
   130                 value->SetAsAString(EmptyString());
   131             else
   132                 value->SetAsAString(val);
   133         }
   134         aArray.AppendObject(value);
   135     }
   136 }
   140 //----------------------------------------------------------------------
   141 //
   142 // nsXULTemplateQueryProcessorStorage
   143 //
   145 NS_IMPL_ISUPPORTS(nsXULTemplateQueryProcessorStorage,
   146                   nsIXULTemplateQueryProcessor)
   149 nsXULTemplateQueryProcessorStorage::nsXULTemplateQueryProcessorStorage() 
   150     : mGenerationStarted(false)
   151 {
   152 }
   154 NS_IMETHODIMP
   155 nsXULTemplateQueryProcessorStorage::GetDatasource(nsIArray* aDataSources,
   156                                                   nsIDOMNode* aRootNode,
   157                                                   bool aIsTrusted,
   158                                                   nsIXULTemplateBuilder* aBuilder,
   159                                                   bool* aShouldDelayBuilding,
   160                                                   nsISupports** aReturn)
   161 {
   162     *aReturn = nullptr;
   163     *aShouldDelayBuilding = false;
   165     if (!aIsTrusted) {
   166         return NS_OK;
   167     }
   169     uint32_t length;
   170     nsresult rv = aDataSources->GetLength(&length);
   171     NS_ENSURE_SUCCESS(rv, rv);
   173     if (length == 0) {
   174         return NS_OK;
   175     }
   177     // We get only the first uri. This query processor supports
   178     // only one database at a time.
   179     nsCOMPtr<nsIURI> uri;
   180     uri = do_QueryElementAt(aDataSources, 0);
   182     if (!uri) {
   183         // No uri in the list of datasources
   184         return NS_OK;
   185     }
   187     nsCOMPtr<mozIStorageService> storage =
   188         do_GetService("@mozilla.org/storage/service;1", &rv);
   189     NS_ENSURE_SUCCESS(rv, rv);
   191     nsCOMPtr<nsIFile> databaseFile;
   192     nsAutoCString scheme;
   193     rv = uri->GetScheme(scheme);
   194     NS_ENSURE_SUCCESS(rv, rv);
   196     if (scheme.EqualsLiteral("profile")) {
   198         nsAutoCString path;
   199         rv = uri->GetPath(path);
   200         NS_ENSURE_SUCCESS(rv, rv);
   202         if (path.IsEmpty()) {
   203             return NS_ERROR_FAILURE;
   204         }
   206         rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
   207                                              getter_AddRefs(databaseFile));
   208         NS_ENSURE_SUCCESS(rv, rv);
   210         rv = databaseFile->AppendNative(path);
   211         NS_ENSURE_SUCCESS(rv, rv);
   212     }
   213     else {
   214         nsCOMPtr<nsIChannel> channel;
   215         nsCOMPtr<nsIIOService> ioservice =
   216             do_GetService("@mozilla.org/network/io-service;1", &rv);
   217         NS_ENSURE_SUCCESS(rv, rv);
   219         rv = ioservice->NewChannelFromURI(uri, getter_AddRefs(channel));
   220         NS_ENSURE_SUCCESS(rv, rv);
   222         nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(channel, &rv);
   223         if (NS_FAILED(rv)) { // if it fails, not a file url
   224             nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_BAD_URI);
   225             return rv;
   226         }
   228         nsCOMPtr<nsIFile> file;
   229         rv = fileChannel->GetFile(getter_AddRefs(databaseFile));
   230         NS_ENSURE_SUCCESS(rv, rv);
   231     }
   233     // ok now we have an URI of a sqlite file
   234     nsCOMPtr<mozIStorageConnection> connection;
   235     rv = storage->OpenDatabase(databaseFile, getter_AddRefs(connection));
   236     if (NS_FAILED(rv)) {
   237         nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_CANNOT_OPEN_DATABASE);
   238         return rv;
   239     }
   241     NS_ADDREF(*aReturn = connection);
   242     return NS_OK;
   243 }
   247 NS_IMETHODIMP
   248 nsXULTemplateQueryProcessorStorage::InitializeForBuilding(nsISupports* aDatasource,
   249                                                           nsIXULTemplateBuilder* aBuilder,
   250                                                           nsIDOMNode* aRootNode)
   251 {
   252     NS_ENSURE_STATE(!mGenerationStarted);
   254     mStorageConnection = do_QueryInterface(aDatasource);
   255     if (!mStorageConnection)
   256         return NS_ERROR_INVALID_ARG;
   258     bool ready;
   259     mStorageConnection->GetConnectionReady(&ready);
   260     if (!ready)
   261       return NS_ERROR_UNEXPECTED;
   263     return NS_OK;
   264 }
   266 NS_IMETHODIMP
   267 nsXULTemplateQueryProcessorStorage::Done()
   268 {
   269     mGenerationStarted = false;
   270     return NS_OK;
   271 }
   273 NS_IMETHODIMP
   274 nsXULTemplateQueryProcessorStorage::CompileQuery(nsIXULTemplateBuilder* aBuilder,
   275                                                  nsIDOMNode* aQueryNode,
   276                                                  nsIAtom* aRefVariable,
   277                                                  nsIAtom* aMemberVariable,
   278                                                  nsISupports** aReturn)
   279 {
   280     nsCOMPtr<nsIDOMNodeList> childNodes;
   281     aQueryNode->GetChildNodes(getter_AddRefs(childNodes));
   283     uint32_t length;
   284     childNodes->GetLength(&length);
   286     nsCOMPtr<mozIStorageStatement> statement;
   287     nsCOMPtr<nsIContent> queryContent = do_QueryInterface(aQueryNode);
   288     nsAutoString sqlQuery;
   290     // Let's get all text nodes (which should be the query) 
   291     if (!nsContentUtils::GetNodeTextContent(queryContent, false, sqlQuery)) {
   292       return NS_ERROR_OUT_OF_MEMORY;
   293     }
   295     nsresult rv = mStorageConnection->CreateStatement(NS_ConvertUTF16toUTF8(sqlQuery),
   296                                                               getter_AddRefs(statement));
   297     if (NS_FAILED(rv)) {
   298         nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_BAD_QUERY);
   299         return rv;
   300     }
   302     uint32_t parameterCount = 0;
   303     for (nsIContent* child = queryContent->GetFirstChild();
   304          child;
   305          child = child->GetNextSibling()) {
   307         if (child->NodeInfo()->Equals(nsGkAtoms::param, kNameSpaceID_XUL)) {
   308             nsAutoString value;
   309             if (!nsContentUtils::GetNodeTextContent(child, false, value)) {
   310               return NS_ERROR_OUT_OF_MEMORY;
   311             }
   313             uint32_t index = parameterCount;
   314             nsAutoString name, indexValue;
   316             if (child->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name)) {
   317                 rv = statement->GetParameterIndex(NS_ConvertUTF16toUTF8(name),
   318                                                   &index);
   319                 if (NS_FAILED(rv)) {
   320                     nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_UNKNOWN_QUERY_PARAMETER);
   321                     return rv;
   322                 }
   323                 parameterCount++;
   324             }
   325             else if (child->GetAttr(kNameSpaceID_None, nsGkAtoms::index, indexValue)) {
   326                 PR_sscanf(NS_ConvertUTF16toUTF8(indexValue).get(),"%d",&index);
   327                 if (index > 0)
   328                     index--;
   329             }
   330             else {
   331                 parameterCount++;
   332             }
   334             static nsIContent::AttrValuesArray sTypeValues[] =
   335                 { &nsGkAtoms::int32, &nsGkAtoms::integer, &nsGkAtoms::int64,
   336                   &nsGkAtoms::null, &nsGkAtoms::double_, &nsGkAtoms::string, nullptr };
   338             int32_t typeError = 1;
   339             int32_t typeValue = child->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
   340                                                        sTypeValues, eCaseMatters);
   341             rv = NS_ERROR_ILLEGAL_VALUE;
   342             int32_t valInt32 = 0;
   343             int64_t valInt64 = 0;
   344             double valFloat = 0;
   346             switch (typeValue) {
   347               case 0:
   348               case 1:
   349                 typeError = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(),"%d",&valInt32);
   350                 if (typeError > 0)
   351                     rv = statement->BindInt32ByIndex(index, valInt32);
   352                 break;
   353               case 2:
   354                 typeError = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(),"%lld",&valInt64);
   355                 if (typeError > 0)
   356                     rv = statement->BindInt64ByIndex(index, valInt64);
   357                 break;
   358               case 3:
   359                 rv = statement->BindNullByIndex(index);
   360                 break;
   361               case 4:
   362                 typeError = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(),"%lf",&valFloat);
   363                 if (typeError > 0)
   364                     rv = statement->BindDoubleByIndex(index, valFloat);
   365                 break;
   366               case 5:
   367               case nsIContent::ATTR_MISSING:
   368                 rv = statement->BindStringByIndex(index, value);
   369                 break;
   370               default:
   371                 typeError = 0;
   372             }
   374             if (typeError <= 0) {
   375                 nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_WRONG_TYPE_QUERY_PARAMETER);
   376                 return rv;
   377             }
   379             if (NS_FAILED(rv)) {
   380                 nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_QUERY_PARAMETER_NOT_BOUND);
   381                 return rv;
   382             }
   383         }
   384     }
   386     *aReturn = statement;
   387     NS_IF_ADDREF(*aReturn);
   389     return NS_OK;
   390 }
   392 NS_IMETHODIMP
   393 nsXULTemplateQueryProcessorStorage::GenerateResults(nsISupports* aDatasource,
   394                                                     nsIXULTemplateResult* aRef,
   395                                                     nsISupports* aQuery,
   396                                                     nsISimpleEnumerator** aResults)
   397 {
   398     mGenerationStarted = true;
   400     nsCOMPtr<mozIStorageStatement> statement = do_QueryInterface(aQuery);
   401     if (!statement)
   402         return NS_ERROR_FAILURE;
   404     nsXULTemplateResultSetStorage* results =
   405         new nsXULTemplateResultSetStorage(statement);
   407     if (!results)
   408         return NS_ERROR_OUT_OF_MEMORY;
   410     *aResults = results;
   411     NS_ADDREF(*aResults);
   413     return NS_OK;
   414 }
   416 NS_IMETHODIMP
   417 nsXULTemplateQueryProcessorStorage::AddBinding(nsIDOMNode* aRuleNode,
   418                                                nsIAtom* aVar,
   419                                                nsIAtom* aRef,
   420                                                const nsAString& aExpr)
   421 {
   422     return NS_OK;
   423 }
   425 NS_IMETHODIMP
   426 nsXULTemplateQueryProcessorStorage::TranslateRef(nsISupports* aDatasource,
   427                                                  const nsAString& aRefString,
   428                                                  nsIXULTemplateResult** aRef)
   429 {
   430     nsXULTemplateResultStorage* result =
   431         new nsXULTemplateResultStorage(nullptr);
   432     if (!result)
   433         return NS_ERROR_OUT_OF_MEMORY;
   435     *aRef = result;
   436     NS_ADDREF(*aRef);
   437     return NS_OK;
   438 }
   441 NS_IMETHODIMP
   442 nsXULTemplateQueryProcessorStorage::CompareResults(nsIXULTemplateResult* aLeft,
   443                                                    nsIXULTemplateResult* aRight,
   444                                                    nsIAtom* aVar,
   445                                                    uint32_t aSortHints,
   446                                                    int32_t* aResult)
   447 {
   448     *aResult = 0;
   449     if (!aVar)
   450       return NS_OK;
   452     // We're going to see if values are integers or float, to perform
   453     // a suitable comparison
   454     nsCOMPtr<nsISupports> leftValue, rightValue;
   455     if (aLeft)
   456       aLeft->GetBindingObjectFor(aVar, getter_AddRefs(leftValue));
   457     if (aRight)
   458       aRight->GetBindingObjectFor(aVar, getter_AddRefs(rightValue));
   460     if (leftValue && rightValue) {
   461         nsCOMPtr<nsIVariant> vLeftValue = do_QueryInterface(leftValue);
   462         nsCOMPtr<nsIVariant> vRightValue = do_QueryInterface(rightValue);
   464         if (vLeftValue && vRightValue) {
   465             nsresult rv1, rv2;
   466             uint16_t vtypeL, vtypeR;
   467             vLeftValue->GetDataType(&vtypeL);
   468             vRightValue->GetDataType(&vtypeR);
   470             if (vtypeL == vtypeR) {
   471                 if (vtypeL == nsIDataType::VTYPE_INT64) {
   472                     int64_t leftValue, rightValue;
   473                     rv1 = vLeftValue->GetAsInt64(&leftValue);
   474                     rv2 = vRightValue->GetAsInt64(&rightValue);
   475                     if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
   476                         if (leftValue > rightValue)
   477                             *aResult = 1;
   478                         else if (leftValue < rightValue)
   479                             *aResult = -1;
   480                         return NS_OK;
   481                     }
   482                 }
   483                 else if (vtypeL == nsIDataType::VTYPE_DOUBLE) {
   484                     double leftValue, rightValue;
   485                     rv1 = vLeftValue->GetAsDouble(&leftValue);
   486                     rv2 = vRightValue->GetAsDouble(&rightValue);
   487                     if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
   488                         if (leftValue > rightValue)
   489                             *aResult = 1;
   490                         else if (leftValue < rightValue)
   491                             *aResult = -1;
   492                         return NS_OK;
   493                     }
   494                 }
   495             }
   496         }
   497     }
   499     // Values are not integers or floats, so we just compare them as simple strings
   500     nsAutoString leftVal;
   501     if (aLeft)
   502         aLeft->GetBindingFor(aVar, leftVal);
   504     nsAutoString rightVal;
   505     if (aRight)
   506         aRight->GetBindingFor(aVar, rightVal);
   508     *aResult = XULSortServiceImpl::CompareValues(leftVal, rightVal, aSortHints);
   509     return NS_OK;
   510 }

mercurial