Bug 1401528 - do not access aAttrDef.special if not defined in gloda.js. r=asuth
authoraceman <acelists@atlas.sk>
Mon, 25 Sep 2017 13:49:00 +0200
changeset 29243 5f5b8b76159a35ed3d17ffa2a0b8c72a3419c310
parent 29242 c82304da41745162f4d7c0d71b150ca78bbae9d4
child 29244 2ae6e4e072d564323bdff269b3ac37a5cfc1873f
push id2068
push userclokep@gmail.com
push dateMon, 13 Nov 2017 19:02:14 +0000
treeherdercomm-beta@9c7e7ce8672b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1401528
Bug 1401528 - do not access aAttrDef.special if not defined in gloda.js. r=asuth
mailnews/db/gloda/modules/datastore.js
mailnews/db/gloda/modules/gloda.js
--- a/mailnews/db/gloda/modules/datastore.js
+++ b/mailnews/db/gloda/modules/datastore.js
@@ -331,42 +331,46 @@ QueryFromQueryCallback.prototype = {
             if (notFoundCount === 0) {
               this.collection.resolvedCount++;
             }
             else {
               this.collection.deferredCount++;
               let query = new nounDef.queryClass();
               query.id.apply(query, Object.keys(notFound));
 
+              // we fully expect/allow for there being no such subcollection yet.
+              let subCollection = (nounDef.id in this.collection.masterCollection.subCollections) ?
+                                  this.collection.masterCollection.subCollections[nounDef.id] : undefined;
               this.collection.masterCollection.subCollections[nounDef.id] =
                 GlodaDatastore.queryFromQuery(query, QueryFromQueryResolver,
                   this.collection,
-                  // we fully expect/allow for there being no such subcollection yet.
-                  this.collection.masterCollection.subCollections[nounDef.id],
+                  subCollection,
                   this.collection.masterCollection,
                   {becomeExplicit: true});
             }
           }
 
           for (let nounID in this.inverseReferencesByNounID) {
             let inverseReferences = this.inverseReferencesByNounID[nounID];
             this.collection.deferredCount++;
             let nounDef = GlodaDatastore._nounIDToDef[nounID];
 
             //QFQ_LOG.debug("Want to load inverse via " + nounDef.parentColumnAttr.boundName);
 
             let query = new nounDef.queryClass();
             // we want to constrain using the parent column
             let queryConstrainer = query[nounDef.parentColumnAttr.boundName];
             queryConstrainer.apply(query, Object.keys(inverseReferences));
+            // we fully expect/allow for there being no such subcollection yet.
+            let subCollection = (nounDef.id in this.collection.masterCollection.subCollections) ?
+                                this.collection.masterCollection.subCollections[nounDef.id] : undefined;
             this.collection.masterCollection.subCollections[nounDef.id] =
               GlodaDatastore.queryFromQuery(query, QueryFromQueryResolver,
                 this.collection,
-                // we fully expect/allow for there being no such subcollection yet.
-                this.collection.masterCollection.subCollections[nounDef.id],
+                subCollection,
                 this.collection.masterCollection,
                 {becomeExplicit: true});
           }
         }
         else {
           this.collection.deferredCount--;
           this.collection.resolvedCount++;
         }
@@ -2564,17 +2568,17 @@ var GlodaDatastore = {
     else
       ums.bindByIndex(5, null);
     ums.bindByIndex(6, aMessage.notability);
     ums.bindByIndex(7, aMessage._isDeleted ? 1 : 0);
 
     ums.executeAsync(this.trackAsync());
 
     if (aMessage.folderID !== null) {
-      if (aMessage._isNew === true)
+      if (("_isNew" in aMessage) && (aMessage._isNew === true))
         this._insertMessageText(aMessage);
       else
         this._updateMessageText(aMessage);
     }
   },
 
   /**
    * Updates the full-text row associated with this message. This only performs
@@ -3345,23 +3349,24 @@ var GlodaDatastore = {
                 (values.length ? " AND " : "");
             else
               clausePart = "(";
             if (values.length) {
               // strings need to be escaped, we would use ? binding, except
               //  that gets mad if we have too many strings... so we use our
               //  own escaping logic.  correctly escaping is easy, but it still
               //  feels wrong to do it. (just double the quote character...)
-              if (attrDef.special == this.kSpecialString)
+              if (("special" in attrDef) && (attrDef.special == this.kSpecialString)) {
                 clausePart += valueColumnName + " IN (" +
                   values.map(v => "'" + v.replace(/\'/g, "''") + "'").
                   join(",") + "))";
-              else
+              } else {
                 clausePart += valueColumnName + " IN (" + values.join(",") +
                               "))";
+              }
             }
             else
               clausePart += ")";
             clauses.push(clausePart);
           }
           test = clauses.join(" OR ");
         }
         // @testpoint gloda.datastore.sqlgen.kConstraintRanges
@@ -3540,30 +3545,30 @@ var GlodaDatastore = {
     let hasDeps = false;
 
     //this._log.debug("  hadDeps: " + hadDeps + " deps: " +
     //    Log4Moz.enumerateProperties(deps).join(","));
 
     for (let attrib of aItem.NOUN_DEF.specialLoadAttribs) {
       let objectNounDef = attrib.objectNounDef;
 
-      if (attrib.special === this.kSpecialColumnChildren) {
+      if (("special" in attrib) && (attrib.special === this.kSpecialColumnChildren)) {
         let invReferences = aInverseReferencesByNounID[objectNounDef.id];
         if (invReferences === undefined)
           invReferences = aInverseReferencesByNounID[objectNounDef.id] = {};
         // only contribute if it's not already pending or there
         if (!(attrib.id in deps) && aItem[attrib.storageAttributeName] == null){
           //this._log.debug("   Adding inv ref for: " + aItem.id);
           if (!(aItem.id in invReferences))
             invReferences[aItem.id] = null;
           deps[attrib.id] = null;
           hasDeps = true;
         }
       }
-      else if (attrib.special === this.kSpecialColumnParent) {
+      else if (("special" in attrib) && (attrib.special === this.kSpecialColumnParent)) {
         let references = aReferencesByNounID[objectNounDef.id];
         if (references === undefined)
           references = aReferencesByNounID[objectNounDef.id] = {};
         // nothing to contribute if it's already there
         if (!(attrib.id in deps) &&
             aItem[attrib.valueStorageAttributeName] == null) {
           let parentID = aItem[attrib.idStorageAttributeName];
           if (!(parentID in references))
--- a/mailnews/db/gloda/modules/gloda.js
+++ b/mailnews/db/gloda/modules/gloda.js
@@ -1504,17 +1504,17 @@ var Gloda = {
    */
   _bindAttribute: function gloda_ns_bindAttr(aAttrDef, aSubjectNounDef) {
     let objectNounDef = aAttrDef.objectNounDef;
 
     // -- the query constraint helpers
     if (aSubjectNounDef.queryClass !== undefined) {
       let constrainer;
       let canQuery = true;
-      if (aAttrDef.special == this.kSpecialFulltext) {
+      if (("special" in aAttrDef) && (aAttrDef.special == this.kSpecialFulltext)) {
         constrainer = function() {
           let constraint = [GlodaDatastore.kConstraintFulltext, aAttrDef];
           for (let iArg = 0; iArg < arguments.length; iArg++) {
             constraint.push(arguments[iArg]);
           }
           this._constraints.push(constraint);
           return this;
         };
@@ -1560,17 +1560,17 @@ var Gloda = {
 
         aSubjectNounDef.queryClass.prototype[aAttrDef.boundName + "Range"] =
           rangedConstrainer;
       }
 
       // - string LIKE helper for special on-row attributes: fooLike
       // (it is impossible to store a string as an indexed attribute, which is
       //  why we do this for on-row only.)
-      if (aAttrDef.special == this.kSpecialString) {
+      if (("special" in aAttrDef) && (aAttrDef.special == this.kSpecialString)) {
         let likeConstrainer = function() {
           let constraint = [GlodaDatastore.kConstraintStringLike, aAttrDef];
           for (let iArg = 0; iArg < arguments.length; iArg++) {
             constraint.push(arguments[iArg]);
           }
           this._constraints.push(constraint);
           return this;
         };
@@ -1810,32 +1810,32 @@ var Gloda = {
       this._bindAttribute(aAttrDef, subjectNounDef);
 
       // update the provider maps...
       if (this._attrProviderOrderByNoun[subjectType]
               .indexOf(aAttrDef.provider) == -1) {
         this._attrProviderOrderByNoun[subjectType].push(aAttrDef.provider);
         if (aAttrDef.provider.optimize)
           this._attrOptimizerOrderByNoun[subjectType].push(aAttrDef.provider);
-        this._attrProvidersByNoun[subjectType][aAttrDef.provider] = [];
+        this._attrProvidersByNoun[subjectType][aAttrDef.provider.providerName] = [];
       }
-      this._attrProvidersByNoun[subjectType][aAttrDef.provider].push(aAttrDef);
+      this._attrProvidersByNoun[subjectType][aAttrDef.provider.providerName].push(aAttrDef);
 
       subjectNounDef.attribsByBoundName[aAttrDef.boundName] = aAttrDef;
       if (aAttrDef.domExpose)
         subjectNounDef.domExposeAttribsByBoundName[aAttrDef.boundName] =
           aAttrDef;
 
-      if (aAttrDef.special & this.kSpecialColumn)
+      if (("special" in aAttrDef) && (aAttrDef.special & this.kSpecialColumn))
         subjectNounDef.specialLoadAttribs.push(aAttrDef);
 
       // if this is a parent column attribute, make note of it so that if we
       //  need to do an inverse references lookup, we know what column we are
       //  issuing against.
-      if (aAttrDef.special === this.kSpecialColumnParent) {
+      if (("special" in aAttrDef) && (aAttrDef.special === this.kSpecialColumnParent)) {
         subjectNounDef.parentColumnAttr = aAttrDef;
       }
 
       if (aAttrDef.objectNounDef.tableName ||
           aAttrDef.objectNounDef.contributeObjDependencies) {
         subjectNounDef.hasObjDependencies = true;
       }
     }