Bug 1401528 - do not access aAttrDef.special if not defined in gloda.js. r=asuth
--- 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;
}
}