--- a/calendar/providers/storage/calStorageCalendar.js
+++ b/calendar/providers/storage/calStorageCalendar.js
@@ -72,20 +72,21 @@ calStorageCalendar.prototype = {
//
// private members
//
mDB: null,
mItemCache: null,
mRecItemCacheInited: false,
mRecEventCache: null,
mRecTodoCache: null,
+ mLastStatement: null,
//
// nsISupports interface
- //
+ //
QueryInterface: function (aIID) {
return doQueryInterface(this, calStorageCalendar.prototype, aIID,
[Components.interfaces.calICalendarProvider,
Components.interfaces.calISyncWriteCalendar]);
},
//
// calICalendarProvider interface
@@ -101,42 +102,60 @@ calStorageCalendar.prototype = {
createCalendar: function cSC_createCalendar() {
throw NS_ERROR_NOT_IMPLEMENTED;
},
deleteCalendar: function cSC_deleteCalendar(cal, listener) {
cal = cal.wrappedJSObject;
for each (let stmt in this.mDeleteEventExtras) {
- this.prepareStatement(stmt);
- stmt.execute();
- stmt.reset();
+ try {
+ this.prepareStatement(stmt);
+ stmt.execute();
+ } finally {
+ stmt.reset();
+ }
}
for each (let stmt in this.mDeleteTodoExtras) {
- this.prepareStatement(stmt);
- stmt.execute();
- stmt.reset();
+ try {
+ this.prepareStatement(stmt);
+ stmt.execute();
+ } finally {
+ stmt.reset();
+ }
+ }
+
+ try {
+ this.prepareStatement(this.mDeleteAllEvents);
+ this.mDeleteAllEvents.execute();
+ } finally {
+ this.mDeleteAllEvents.reset();
}
- this.prepareStatement(this.mDeleteAllEvents);
- this.mDeleteAllEvents.execute();
- this.mDeleteAllEvents.reset();
-
- this.prepareStatement(this.mDeleteAllTodos);
- this.mDeleteAllTodos.execute();
- this.mDeleteAllTodos.reset();
-
- this.prepareStatement(this.mDeleteAllMetaData);
- this.mDeleteAllMetaData.execute();
- this.mDeleteAllMetaData.reset();
+ try {
+ this.prepareStatement(this.mDeleteAllTodos);
+ this.mDeleteAllTodos.execute();
+ } finally {
+ this.mDeleteAllTodos.reset();
+ }
try {
- listener.onDeleteCalendar(cal, Components.results.NS_OK, null);
+ this.prepareStatement(this.mDeleteAllMetaData);
+ this.mDeleteAllMetaData.execute();
+ } finally {
+ this.mDeleteAllMetaData.reset();
+ }
+
+ try {
+ if (listener) {
+ listener.onDeleteCalendar(cal, Components.results.NS_OK, null);
+ }
} catch (ex) {
+ this.logError("error calling listener.onDeleteCalendar", ex);
}
},
mRelaxedMode: undefined,
get relaxedMode() {
if (this.mRelaxedMode === undefined) {
this.mRelaxedMode = this.getProperty("relaxedMode");
}
@@ -223,17 +242,17 @@ calStorageCalendar.prototype = {
if (this.mDB.tableExists("cal_events")) {
cal.LOG("Storage: Migrating storage.sdb -> local.sqlite");
upgradeDB(this.mDB); // upgrade schema before migating data
let attachStatement = createStatement(this.mDB, "ATTACH DATABASE :file_path AS local_sqlite");
try {
attachStatement.params.file_path = localDB.databaseFile.path;
attachStatement.execute();
} catch (exc) {
- cal.ERROR(exc + ", error: " + this.mDB.lastErrorString);
+ this.logError("prepareInitDB attachStatement.execute exception", exc);
throw exc;
} finally {
attachStatement.reset();
}
try {
// hold lock on storage.sdb until we've migrated data from storage.sdb:
this.mDB.beginTransactionAs(Components.interfaces.mozIStorageConnection.TRANSACTION_EXCLUSIVE);
try {
@@ -246,17 +265,17 @@ calStorageCalendar.prototype = {
"; DROP TABLE IF EXISTS " + table);
}
}
this.mDB.commitTransaction();
} else { // migration done in the meantime
this.mDB.rollbackTransaction();
}
} catch (exc) {
- cal.ERROR(exc + ", error: " + this.mDB.lastErrorString);
+ this.logError("prepareInitDB storage.sdb migration exception", exc);
this.mDB.rollbackTransaction();
throw exc;
}
} finally {
this.mDB.executeSimpleSQL("DETACH DATABASE local_sqlite");
}
}
@@ -340,17 +359,17 @@ calStorageCalendar.prototype = {
// need to move all events with cal_id=0 to this id.
cal.LOG("Storage: Migrating stray cal_id=0 calendar to uuid");
migrateTables(this.mDB, this.id, 0);
this.setProperty("uri", "moz-storage-calendar://");
this.setProperty("old_calendar_id", 0);
this.mDB.commitTransaction();
}
} catch (exc) {
- cal.ERROR(exc + ", error: " + this.mDB.lastErrorString);
+ this.logError("prepareInitDB moz-profile-calendar migration exception", exc);
this.mDB.rollbackTransaction();
throw exc;
}
} else if (this.uri.schemeIs("moz-storage-calendar")) {
// New style uri, no need for migration here
let localDB = cal.getCalendarDirectory();
localDB.append("local.sqlite");
localDB = dbService.openDatabase(localDB);
@@ -366,18 +385,19 @@ calStorageCalendar.prototype = {
/**
* Takes care of necessary preparations for most of our statements.
*
* @param aStmt The statement to prepare.
*/
prepareStatement: function cSC_prepareStatement(aStmt) {
try {
aStmt.params.cal_id = this.id;
+ this.mLastStatement = aStmt;
} catch (e) {
- cal.ERROR(e + "\n" + cal.STACK(10));
+ this.logError("prepareStatement exception", e);
}
},
refresh: function cSC_refresh() {
// no-op
},
// void addItem( in calIItemBase aItem, in calIOperationListener aListener );
@@ -435,16 +455,17 @@ calStorageCalendar.prototype = {
aItem);
// notify observers
this.observers.notify("onAddItem", [aItem]);
},
// void modifyItem( in calIItemBase aNewItem, in calIItemBase aOldItem, in calIOperationListener aListener );
modifyItem: function cSC_modifyItem(aNewItem, aOldItem, aListener) {
+
if (this.readOnly) {
this.notifyOperationComplete(aListener,
Components.interfaces.calIErrors.CAL_IS_READONLY,
Components.interfaces.calIOperationListener.MODIFY,
null,
"Calendar is readonly");
return null;
}
@@ -544,17 +565,17 @@ calStorageCalendar.prototype = {
this.deleteItemById(aItem.id);
this.notifyOperationComplete(aListener,
Components.results.NS_OK,
Components.interfaces.calIOperationListener.DELETE,
aItem.id,
aItem);
- // notify observers
+ // notify observers
this.observers.notify("onDeleteItem", [aItem]);
},
// void getItem( in string id, in calIOperationListener aListener );
getItem: function cSC_getItem(aId, aListener) {
if (!aListener)
return;
@@ -590,17 +611,17 @@ calStorageCalendar.prototype = {
this.notifyOperationComplete(aListener,
Components.results.NS_OK,
Components.interfaces.calIOperationListener.GET,
aId,
null);
},
- // void getItems( in unsigned long aItemFilter, in unsigned long aCount,
+ // void getItems( in unsigned long aItemFilter, in unsigned long aCount,
// in calIDateTime aRangeStart, in calIDateTime aRangeEnd,
// in calIOperationListener aListener );
getItems: function cSC_getItems(aItemFilter, aCount,
aRangeStart, aRangeEnd, aListener) {
let this_ = this;
cal.postPone(function() {
this_.getItems_(aItemFilter, aCount, aRangeStart, aRangeEnd, aListener);
});
@@ -741,31 +762,30 @@ calStorageCalendar.prototype = {
// First fetch all the events
if (wantEvents) {
var sp; // stmt params
var resultItems = [];
// first get non-recurring events that happen to fall within the range
//
- this.prepareStatement(this.mSelectNonRecurringEventsByRange);
- sp = this.mSelectNonRecurringEventsByRange.params;
- sp.range_start = startTime;
- sp.range_end = endTime;
- sp.start_offset = aRangeStart ? aRangeStart.timezoneOffset * USECS_PER_SECOND : 0;
- sp.end_offset = aRangeEnd ? aRangeEnd.timezoneOffset * USECS_PER_SECOND : 0;
+ try {
+ this.prepareStatement(this.mSelectNonRecurringEventsByRange);
+ sp = this.mSelectNonRecurringEventsByRange.params;
+ sp.range_start = startTime;
+ sp.range_end = endTime;
+ sp.start_offset = aRangeStart ? aRangeStart.timezoneOffset * USECS_PER_SECOND : 0;
+ sp.end_offset = aRangeEnd ? aRangeEnd.timezoneOffset * USECS_PER_SECOND : 0;
- try {
while (this.mSelectNonRecurringEventsByRange.step()) {
let row = this.mSelectNonRecurringEventsByRange.row;
resultItems.push(this.getEventFromRow(row, {}));
}
} catch (e) {
- cal.ERROR("Error selecting non recurring events by range!\n" + e +
- "\nDB Error: " + this.mDB.lastErrorString);
+ this.logError("Error selecting non recurring events by range!\n", e);
} finally {
this.mSelectNonRecurringEventsByRange.reset();
}
// process the non-recurring events:
for each (var evitem in resultItems) {
count += handleResultItem(evitem, Components.interfaces.calIEvent);
if (checkCount()) {
@@ -783,31 +803,30 @@ calStorageCalendar.prototype = {
}
// if todos are wanted, do them next
if (wantTodos) {
var sp; // stmt params
var resultItems = [];
// first get non-recurring todos that happen to fall within the range
- this.prepareStatement(this.mSelectNonRecurringTodosByRange);
- sp = this.mSelectNonRecurringTodosByRange.params;
- sp.range_start = startTime;
- sp.range_end = endTime;
- sp.start_offset = aRangeStart ? aRangeStart.timezoneOffset * USECS_PER_SECOND : 0;
- sp.end_offset = aRangeEnd ? aRangeEnd.timezoneOffset * USECS_PER_SECOND : 0;
+ try {
+ this.prepareStatement(this.mSelectNonRecurringTodosByRange);
+ sp = this.mSelectNonRecurringTodosByRange.params;
+ sp.range_start = startTime;
+ sp.range_end = endTime;
+ sp.start_offset = aRangeStart ? aRangeStart.timezoneOffset * USECS_PER_SECOND : 0;
+ sp.end_offset = aRangeEnd ? aRangeEnd.timezoneOffset * USECS_PER_SECOND : 0;
- try {
while (this.mSelectNonRecurringTodosByRange.step()) {
let row = this.mSelectNonRecurringTodosByRange.row;
resultItems.push(this.getTodoFromRow(row, {}));
}
} catch (e) {
- cal.ERROR("Error selecting non recurring todos by range!\n" + e +
- "\nDB Error: " + this.mDB.lastErrorString);
+ this.logError("Error selecting non recurring todos by range", e);
} finally {
this.mSelectNonRecurringTodosByRange.reset();
}
// process the non-recurring todos:
for each (var todoitem in resultItems) {
count += handleResultItem(todoitem, Components.interfaces.calITodo, checkCompleted);
if (checkCount()) {
@@ -868,17 +887,17 @@ calStorageCalendar.prototype = {
"LIMIT 1"
);
// The more readable version of the next where-clause is:
// WHERE ((event_end > :range_start OR
// (event_end = :range_start AND
// event_start = :range_start))
// AND event_start < :range_end)
- //
+ //
// but that doesn't work with floating start or end times. The logic
// is the same though.
// For readability, a few helpers:
var floatingEventStart = "event_start_tz = 'floating' AND event_start"
var nonFloatingEventStart = "event_start_tz != 'floating' AND event_start"
var floatingEventEnd = "event_end_tz = 'floating' AND event_end"
var nonFloatingEventEnd = "event_end_tz != 'floating' AND event_end"
// The query needs to take both floating and non floating into account
@@ -896,17 +915,17 @@ calStorageCalendar.prototype = {
" (("+floatingEventStart+" < :range_end + :end_offset) OR " +
" ("+nonFloatingEventStart+" < :range_end)) " +
" AND cal_id = :cal_id AND flags & 16 == 0 AND recurrence_id IS NULL"
);
/**
* WHERE (due > rangeStart AND start < rangeEnd) OR
* (due = rangeStart AND start = rangeStart) OR
* (due IS NULL AND ((start >= rangeStart AND start < rangeEnd) OR
- * (start IS NULL AND
+ * (start IS NULL AND
* (completed > rangeStart OR completed IS NULL))) OR
* (start IS NULL AND due >= rangeStart AND due < rangeEnd)
*/
var floatingTodoEntry = "todo_entry_tz = 'floating' AND todo_entry";
var nonFloatingTodoEntry = "todo_entry_tz != 'floating' AND todo_entry";
var floatingTodoDue = "todo_due_tz = 'floating' AND todo_due";
var nonFloatingTodoDue = "todo_due_tz != 'floating' AND todo_due";
@@ -1108,24 +1127,24 @@ calStorageCalendar.prototype = {
this.mDB,
"INSERT INTO cal_recurrence " +
" (cal_id, item_id, recur_index, recur_type, is_negative, dates, count, end_date, interval, second, minute, hour, day, monthday, yearday, weekno, month, setpos) " +
"VALUES (:cal_id, :item_id, :recur_index, :recur_type, :is_negative, :dates, :count, :end_date, :interval, :second, :minute, :hour, :day, :monthday, :yearday, :weekno, :month, :setpos)"
);
this.mInsertAttachment = createStatement (
this.mDB,
- "INSERT INTO cal_attachments " +
+ "INSERT INTO cal_attachments " +
" (cal_id, item_id, data, format_type, encoding, recurrence_id, recurrence_id_tz) " +
"VALUES (:cal_id, :item_id, :data, :format_type, :encoding, :recurrence_id, :recurrence_id_tz)"
);
this.mInsertRelation = createStatement (
this.mDB,
- "INSERT INTO cal_relations " +
+ "INSERT INTO cal_relations " +
" (cal_id, item_id, rel_type, rel_id, recurrence_id, recurrence_id_tz) " +
"VALUES (:cal_id, :item_id, :rel_type, :rel_id, :recurrence_id, :recurrence_id_tz)"
);
this.mInsertMetaData = createStatement(
this.mDB,
"INSERT INTO cal_metadata"
+ " (cal_id, item_id, value)"
@@ -1275,42 +1294,40 @@ calStorageCalendar.prototype = {
assureRecurringItemCaches: function cSC_assureRecurringItemCaches() {
if (this.mRecItemCacheInited) {
return;
}
// build up recurring event and todo cache, because we need that on every query:
// for recurring items, we need to query database-wide.. yuck
- this.prepareStatement(this.mSelectEventsWithRecurrence);
- let sp = this.mSelectEventsWithRecurrence.params;
try {
+ this.prepareStatement(this.mSelectEventsWithRecurrence);
+ let sp = this.mSelectEventsWithRecurrence.params;
while (this.mSelectEventsWithRecurrence.step()) {
var row = this.mSelectEventsWithRecurrence.row;
var item = this.getEventFromRow(row, {});
this.mRecEventCache[item.id] = item;
}
} catch (e) {
- cal.ERROR("Error selecting events with recurrence!\n" + e +
- "\nDB Error: " + this.mDB.lastErrorString);
+ this.logError("Error selecting events with recurrence!", e);
} finally {
this.mSelectEventsWithRecurrence.reset();
}
- this.prepareStatement(this.mSelectTodosWithRecurrence);
- sp = this.mSelectTodosWithRecurrence.params;
try {
+ this.prepareStatement(this.mSelectTodosWithRecurrence);
+ sp = this.mSelectTodosWithRecurrence.params;
while (this.mSelectTodosWithRecurrence.step()) {
var row = this.mSelectTodosWithRecurrence.row;
var item = this.getTodoFromRow(row, {});
this.mRecTodoCache[item.id] = item;
}
} catch (e) {
- cal.ERROR("Error selecting todos with recurrence!\n" + e +
- "\nDB Error: " + this.mDB.lastErrorString);
+ this.logError("Error selecting todos with recurrence!", e);
} finally {
this.mSelectTodosWithRecurrence.reset();
}
this.mRecItemCacheInited = true;
},
// xxx todo: consider removing flags parameter
@@ -1380,65 +1397,62 @@ calStorageCalendar.prototype = {
return item;
},
// after we get the base item, we need to check if we need to pull in
// any extra data from other tables. We do that here.
// We used to use mDBTwo for this, so this can be run while a
// select is executing but this no longer seems to be required.
-
+
getAdditionalDataForItem: function cSC_getAdditionalDataForItem(item, flags) {
// This is needed to keep the modification time intact.
var savedLastModifiedTime = item.lastModifiedTime;
if (flags & CAL_ITEM_FLAG.HAS_ATTENDEES) {
var selectItem = null;
if (item.recurrenceId == null)
selectItem = this.mSelectAttendeesForItem;
else {
selectItem = this.mSelectAttendeesForItemWithRecurrenceId;
this.setDateParamHelper(selectItem.params, "recurrence_id", item.recurrenceId);
}
- this.prepareStatement(selectItem);
- selectItem.params.item_id = item.id;
-
try {
+ this.prepareStatement(selectItem);
+ selectItem.params.item_id = item.id;
while (selectItem.step()) {
var attendee = this.getAttendeeFromRow(selectItem.row);
if (attendee.isOrganizer) {
item.organizer = attendee;
} else {
item.addAttendee(attendee);
}
}
} catch (e) {
- cal.ERROR("Error getting attendees for item '" +
- item.title + "' (" + item.id + ")!\n" + e +
- "\nDB Error: " + this.mDB.lastErrorString);
+ this.logError("Error getting attendees for item '" +
+ item.title + "' (" + item.id + ")!", e);
} finally {
selectItem.reset();
}
}
var row;
if (flags & CAL_ITEM_FLAG.HAS_PROPERTIES) {
var selectItem = null;
if (item.recurrenceId == null)
selectItem = this.mSelectPropertiesForItem;
else {
selectItem = this.mSelectPropertiesForItemWithRecurrenceId;
this.setDateParamHelper(selectItem.params, "recurrence_id", item.recurrenceId);
}
-
- this.prepareStatement(selectItem);
- selectItem.params.item_id = item.id;
-
+
try {
+ this.prepareStatement(selectItem);
+ selectItem.params.item_id = item.id;
while (selectItem.step()) {
row = selectItem.row;
var name = row.key;
switch (name) {
case "DURATION":
// for events DTEND/DUE is enforced by calEvent/calTodo, so suppress DURATION:
break;
case "CATEGORIES": {
@@ -1447,34 +1461,33 @@ calStorageCalendar.prototype = {
break;
}
default:
item.setProperty(name, row.value);
break;
}
}
} catch (e) {
- cal.ERROR("Error getting extra properties for item '" +
- item.title + "' (" + item.id + ")!\n" + e +
- "\nDB Error: " + this.mDB.lastErrorString);
+ this.logError("Error getting extra properties for item '" +
+ item.title + "' (" + item.id + ")!", e);
} finally {
selectItem.reset();
}
}
var i;
if (flags & CAL_ITEM_FLAG.HAS_RECURRENCE) {
if (item.recurrenceId)
throw Components.results.NS_ERROR_UNEXPECTED;
var rec = null;
- this.prepareStatement(this.mSelectRecurrenceForItem);
- this.mSelectRecurrenceForItem.params.item_id = item.id;
try {
+ this.prepareStatement(this.mSelectRecurrenceForItem);
+ this.mSelectRecurrenceForItem.params.item_id = item.id;
while (this.mSelectRecurrenceForItem.step()) {
row = this.mSelectRecurrenceForItem.row;
var ritem = null;
if (row.recur_type == null ||
row.recur_type == "x-dateset")
{
@@ -1538,19 +1551,18 @@ calStorageCalendar.prototype = {
if (row.is_negative)
ritem.isNegative = true;
if (rec == null) {
rec = cal.createRecurrenceInfo(item);
}
rec.appendRecurrenceItem(ritem);
}
} catch (e) {
- cal.ERROR("Error getting recurrence for item '" +
- item.title + "' (" + item.id + ")!\n" + e +
- "\nDB Error: " + this.mDB.lastErrorString);
+ this.logError("Error getting recurrence for item '" +
+ item.title + "' (" + item.id + ")!", e);
} finally {
this.mSelectRecurrenceForItem.reset();
}
if (rec == null) {
dump ("XXXX Expected to find recurrence, but got no items!\n");
}
item.recurrenceInfo = rec;
@@ -1571,112 +1583,103 @@ calStorageCalendar.prototype = {
this.prepareStatement(this.mSelectEventExceptions);
try {
while (this.mSelectEventExceptions.step()) {
var row = this.mSelectEventExceptions.row;
var exc = this.getEventFromRow(row, {}, true /*isException*/);
rec.modifyException(exc, true);
}
} catch (e) {
- cal.ERROR("Error getting exceptions for event '" +
- item.title + "' (" + item.id + ")!\n" + e +
- "\nDB Error: " + this.mDB.lastErrorString);
+ this.logError("Error getting exceptions for event '" +
+ item.title + "' (" + item.id + ")!", e);
} finally {
this.mSelectEventExceptions.reset();
}
} else if (cal.isToDo(item)) {
this.mSelectTodoExceptions.params.id = item.id;
this.prepareStatement(this.mSelectTodoExceptions);
try {
while (this.mSelectTodoExceptions.step()) {
var row = this.mSelectTodoExceptions.row;
var exc = this.getTodoFromRow(row, {}, true /*isException*/);
rec.modifyException(exc, true);
}
} catch (e) {
- cal.ERROR("Error getting exceptions for task '" +
- item.title + "' (" + item.id + ")!\n" + e +
- "\nDB Error: " + this.mDB.lastErrorString);
+ this.logError("Error getting exceptions for task '" +
+ item.title + "' (" + item.id + ")!", e);
} finally {
this.mSelectTodoExceptions.reset();
}
} else {
throw Components.results.NS_ERROR_UNEXPECTED;
}
}
if (flags & CAL_ITEM_FLAG.HAS_ATTACHMENTS) {
let selectAttachment = this.mSelectAttachmentsForItem;
if (item.recurrenceId != null) {
selectAttachment = this.mSelectAttachmentsForItemWithRecurrenceId;
this.setDateParamHelper(selectAttachment.params, "recurrence_id", item.recurrenceId);
}
-
- this.prepareStatement(selectAttachment);
- selectAttachment.params.item_id = item.id;
-
try {
+ this.prepareStatement(selectAttachment);
+ selectAttachment.params.item_id = item.id;
while (selectAttachment.step()) {
let row = selectAttachment.row;
let attachment = this.getAttachmentFromRow(row);
item.addAttachment(attachment);
}
} catch (e) {
- cal.ERROR("Error getting attachments for item '" +
- item.title + "' (" + item.id + ")!\n" + e +
- "\nDB Error: " + this.mDB.lastErrorString);
+ this.logError("Error getting attachments for item '" +
+ item.title + "' (" + item.id + ")!", e);
} finally {
selectAttachment.reset();
}
}
if (flags & CAL_ITEM_FLAG.HAS_RELATIONS) {
let selectRelation = this.mSelectRelationsForItem;
if (item.recurrenceId != null) {
selectRelation = this.mSelectRelationsForItemWithRecurrenceId;
this.setDateParamHelper(selectRelation.params, "recurrence_id", item.recurrenceId);
}
-
- this.prepareStatement(selectRelation);
- selectRelation.params.item_id = item.id;
try {
+ this.prepareStatement(selectRelation);
+ selectRelation.params.item_id = item.id;
while (selectRelation.step()) {
let row = selectRelation.row;
let relation = this.getRelationFromRow(row);
item.addRelation(relation);
}
} catch (e) {
- cal.ERROR("Error getting relations for item '" +
- item.title + "' (" + item.id + ")!\n" + e +
- "\nDB Error: " + this.mDB.lastErrorString);
+ this.logError("Error getting relations for item '" +
+ item.title + "' (" + item.id + ")!", e);
} finally {
selectRelation.reset();
}
}
if (flags & CAL_ITEM_FLAG.HAS_ALARMS) {
let selectAlarm = this.mSelectAlarmsForItem;
if (item.recurrenceId != null) {
selectAlarm = this.mSelectAlarmsForItemWithRecurrenceId;
this.setDateParamHelper(selectAlarm.params, "recurrence_id", item.recurrenceId);
}
-
- selectAlarm.params.item_id = item.id;
- this.prepareStatement(selectAlarm);
- try {
+ try {
+ selectAlarm.params.item_id = item.id;
+ this.prepareStatement(selectAlarm);
while (selectAlarm.step()) {
let row = selectAlarm.row;
let alarm = cal.createAlarm();
alarm.icalString = row.icalString;
item.addAlarm(alarm);
}
} catch (e) {
- cal.ERROR("Error getting alarms for item '" +
- item.title + "' (" + item.id + ")!\n" + e +
- "\nDB Error: " + this.mDB.lastErrorString);
+ this.logError("Error getting alarms for item '" +
+ item.title + "' (" + item.id + ")!", e);
} finally {
selectAlarm.reset();
}
}
// Restore the saved modification time
item.setProperty("LAST-MODIFIED", savedLastModifiedTime);
},
@@ -1707,22 +1710,22 @@ calStorageCalendar.prototype = {
}
}
return a;
},
getAttachmentFromRow: function cSC_getAttachmentFromRow(row) {
let a = cal.createAttachment();
-
+
// TODO we don't support binary data here, libical doesn't either.
a.uri = makeURL(row.data);
a.formatType = row.format_type;
a.encoding = row.encoding;
-
+
return a;
},
getRelationFromRow: function cSC_getRelationFromRow(row) {
let r = cal.createRelation();
r.relType = row.rel_type;
r.relId = row.rel_id;
return r;
@@ -1738,41 +1741,39 @@ calStorageCalendar.prototype = {
var item = this.mItemCache[aID];
if (item) {
return item;
}
// not cached; need to read from the db
var flags = {};
- // try events first
- this.prepareStatement(this.mSelectEvent);
- this.mSelectEvent.params.id = aID;
try {
+ // try events first
+ this.prepareStatement(this.mSelectEvent);
+ this.mSelectEvent.params.id = aID;
if (this.mSelectEvent.step()) {
item = this.getEventFromRow(this.mSelectEvent.row, flags);
}
} catch (e) {
- cal.ERROR("Error selecting item by id " + aID + "!\n" + e +
- "\nDB Error: " + this.mDB.lastErrorString);
+ this.logError("Error selecting item by id " + aID + "!", e);
} finally {
this.mSelectEvent.reset();
}
// try todo if event fails
if (!item) {
- this.prepareStatement(this.mSelectTodo);
- this.mSelectTodo.params.id = aID;
try {
+ this.prepareStatement(this.mSelectTodo);
+ this.mSelectTodo.params.id = aID;
if (this.mSelectTodo.step()) {
item = this.getTodoFromRow(this.mSelectTodo.row, flags);
}
} catch (e) {
- cal.ERROR("Error selecting item by id " + aID + "!\n" + e +
- "\nDB Error: " + this.mDB.lastErrorString);
+ this.logError("Error selecting item by id " + aID + "!", e);
} finally {
this.mSelectTodo.reset();
}
}
return item;
},
@@ -1833,62 +1834,68 @@ calStorageCalendar.prototype = {
this.writeEvent(item, olditem, flags);
else if (isToDo(item))
this.writeTodo(item, olditem, flags);
else
throw Components.results.NS_ERROR_UNEXPECTED;
},
writeEvent: function cSC_writeEvent(item, olditem, flags) {
- let ip = this.mInsertEvent.params;
- this.prepareStatement(this.mInsertEvent);
- this.setupItemBaseParams(item, olditem, ip);
+ try {
+ this.prepareStatement(this.mInsertEvent);
+ let ip = this.mInsertEvent.params;
+ this.setupItemBaseParams(item, olditem, ip);
- this.setDateParamHelper(ip, "event_start", item.startDate);
- this.setDateParamHelper(ip, "event_end", item.endDate);
- let dtstamp = item.stampTime;
- if (dtstamp) {
- ip.event_stamp = dtstamp.nativeTime;
+ this.setDateParamHelper(ip, "event_start", item.startDate);
+ this.setDateParamHelper(ip, "event_end", item.endDate);
+ let dtstamp = item.stampTime;
+ if (dtstamp) {
+ ip.event_stamp = dtstamp.nativeTime;
+ }
+
+ if (item.startDate.isDate) {
+ flags |= CAL_ITEM_FLAG.EVENT_ALLDAY;
+ }
+
+ ip.flags = flags;
+
+ this.mInsertEvent.execute();
+ } finally {
+ this.mInsertEvent.reset();
}
-
- if (item.startDate.isDate) {
- flags |= CAL_ITEM_FLAG.EVENT_ALLDAY;
- }
-
- ip.flags = flags;
-
- this.mInsertEvent.execute();
- this.mInsertEvent.reset();
},
writeTodo: function cSC_writeTodo(item, olditem, flags) {
- let ip = this.mInsertTodo.params;
- this.prepareStatement(this.mInsertTodo);
+ try {
+ this.prepareStatement(this.mInsertTodo);
+ let ip = this.mInsertTodo.params;
- this.setupItemBaseParams(item, olditem, ip);
+ this.setupItemBaseParams(item, olditem, ip);
- this.setDateParamHelper(ip, "todo_entry", item.entryDate);
- this.setDateParamHelper(ip, "todo_due", item.dueDate);
- let dtstamp = item.stampTime;
- if (dtstamp) {
- ip.todo_stamp = dtstamp.nativeTime;
+ this.setDateParamHelper(ip, "todo_entry", item.entryDate);
+ this.setDateParamHelper(ip, "todo_due", item.dueDate);
+ let dtstamp = item.stampTime;
+ if (dtstamp) {
+ ip.todo_stamp = dtstamp.nativeTime;
+ }
+ this.setDateParamHelper(ip, "todo_completed", item.getProperty("COMPLETED"));
+
+ ip.todo_complete = item.getProperty("PERCENT-COMPLETED");
+
+ let someDate = (item.entryDate || item.dueDate);
+ if (someDate && someDate.isDate) {
+ flags |= CAL_ITEM_FLAG.EVENT_ALLDAY;
+ }
+
+ ip.flags = flags;
+
+ this.mInsertTodo.execute();
+ } finally {
+ this.mInsertTodo.reset();
}
- this.setDateParamHelper(ip, "todo_completed", item.getProperty("COMPLETED"));
-
- ip.todo_complete = item.getProperty("PERCENT-COMPLETED");
-
- let someDate = (item.entryDate || item.dueDate);
- if (someDate && someDate.isDate) {
- flags |= CAL_ITEM_FLAG.EVENT_ALLDAY;
- }
-
- ip.flags = flags;
-
- this.mInsertTodo.execute();
- this.mInsertTodo.reset();
},
setupItemBaseParams: function cSC_setupItemBaseParams(item, olditem, ip) {
ip.id = item.id;
if (item.recurrenceId) {
this.setDateParamHelper(ip, "recurrence_id", item.recurrenceId);
}
@@ -1915,83 +1922,89 @@ calStorageCalendar.prototype = {
if (item.organizer) {
attendees = attendees.concat([]);
attendees.push(item.organizer);
}
if (attendees.length > 0) {
for each (var att in attendees) {
var ap = this.mInsertAttendee.params;
ap.item_id = item.id;
- this.prepareStatement(this.mInsertAttendee);
- this.setDateParamHelper(ap, "recurrence_id", item.recurrenceId);
- ap.attendee_id = att.id;
- ap.common_name = att.commonName;
- switch (att.rsvp) {
- case "FALSE":
- ap.rsvp = 0;
- break;
- case "TRUE":
- ap.rsvp = 1;
- break;
- default:
- ap.rsvp = 2;
- break;
+ try {
+ this.prepareStatement(this.mInsertAttendee);
+ this.setDateParamHelper(ap, "recurrence_id", item.recurrenceId);
+ ap.attendee_id = att.id;
+ ap.common_name = att.commonName;
+ switch (att.rsvp) {
+ case "FALSE":
+ ap.rsvp = 0;
+ break;
+ case "TRUE":
+ ap.rsvp = 1;
+ break;
+ default:
+ ap.rsvp = 2;
+ break;
+ }
+ ap.role = att.role;
+ ap.status = att.participationStatus;
+ ap.type = att.userType;
+ ap.is_organizer = att.isOrganizer;
+
+ var props = "";
+ var propEnum = att.propertyEnumerator;
+ while (propEnum && propEnum.hasMoreElements()) {
+ var prop = propEnum.getNext().QueryInterface(Components.interfaces.nsIProperty);
+ if (props.length) {
+ props += ",";
+ }
+ props += encodeURIComponent(prop.name);
+ props += ":";
+ props += encodeURIComponent(prop.value);
+ }
+ if (props.length) {
+ ap.properties = props;
+ }
+
+ this.mInsertAttendee.execute();
+ } finally {
+ this.mInsertAttendee.reset();
}
- ap.role = att.role;
- ap.status = att.participationStatus;
- ap.type = att.userType;
- ap.is_organizer = att.isOrganizer;
-
- var props = "";
- var propEnum = att.propertyEnumerator;
- while (propEnum && propEnum.hasMoreElements()) {
- var prop = propEnum.getNext().QueryInterface(Components.interfaces.nsIProperty);
- if (props.length) {
- props += ",";
- }
- props += encodeURIComponent(prop.name);
- props += ":";
- props += encodeURIComponent(prop.value);
- }
- if (props.length) {
- ap.properties = props;
- }
-
- this.mInsertAttendee.execute();
- this.mInsertAttendee.reset();
}
return CAL_ITEM_FLAG.HAS_ATTENDEES;
}
return 0;
},
writeProperty: function cSC_writeProperty(item, propName, propValue) {
- var pp = this.mInsertProperty.params;
- this.prepareStatement(this.mInsertProperty);
- pp.key = propName;
- if (calInstanceOf(propValue, Components.interfaces.calIDateTime)) {
- pp.value = propValue.nativeTime;
- } else {
- try {
- pp.value = propValue;
- } catch (e) {
- // The storage service throws an NS_ERROR_ILLEGAL_VALUE in
- // case pval is something complex (i.e not a string or
- // number). Swallow this error, leaving the value empty.
- if (e.result != Components.results.NS_ERROR_ILLEGAL_VALUE) {
- throw e;
+ try {
+ this.prepareStatement(this.mInsertProperty);
+ var pp = this.mInsertProperty.params;
+ pp.key = propName;
+ if (calInstanceOf(propValue, Components.interfaces.calIDateTime)) {
+ pp.value = propValue.nativeTime;
+ } else {
+ try {
+ pp.value = propValue;
+ } catch (e) {
+ // The storage service throws an NS_ERROR_ILLEGAL_VALUE in
+ // case pval is something complex (i.e not a string or
+ // number). Swallow this error, leaving the value empty.
+ if (e.result != Components.results.NS_ERROR_ILLEGAL_VALUE) {
+ throw e;
+ }
}
}
+ pp.item_id = item.id;
+ this.setDateParamHelper(pp, "recurrence_id", item.recurrenceId);
+ this.mInsertProperty.execute();
+ } finally {
+ this.mInsertProperty.reset();
}
- pp.item_id = item.id;
- this.setDateParamHelper(pp, "recurrence_id", item.recurrenceId);
- this.mInsertProperty.execute();
- this.mInsertProperty.reset();
},
writeProperties: function cSC_writeProperties(item, olditem) {
var ret = 0;
var propEnumerator = item.propertyEnumerator;
while (propEnumerator.hasMoreElements()) {
ret = CAL_ITEM_FLAG.HAS_PROPERTIES;
var prop = propEnumerator.getNext().QueryInterface(Components.interfaces.nsIProperty);
@@ -2014,71 +2027,74 @@ calStorageCalendar.prototype = {
var rec = item.recurrenceInfo;
if (rec) {
flags = CAL_ITEM_FLAG.HAS_RECURRENCE;
var ritems = rec.getRecurrenceItems ({});
for (i in ritems) {
var ritem = ritems[i];
var ap = this.mInsertRecurrence.params;
- this.prepareStatement(this.mInsertRecurrence);
- ap.item_id = item.id;
- ap.recur_index = i;
- ap.is_negative = ritem.isNegative;
- if (calInstanceOf(ritem, Components.interfaces.calIRecurrenceDate)) {
- ap.recur_type = "x-date";
- ap.dates = dateToText(getInUtcOrKeepFloating(ritem.date));
+ try {
+ this.prepareStatement(this.mInsertRecurrence);
+ ap.item_id = item.id;
+ ap.recur_index = i;
+ ap.is_negative = ritem.isNegative;
+ if (calInstanceOf(ritem, Components.interfaces.calIRecurrenceDate)) {
+ ap.recur_type = "x-date";
+ ap.dates = dateToText(getInUtcOrKeepFloating(ritem.date));
+
+ } else if (calInstanceOf(ritem, Components.interfaces.calIRecurrenceDateSet)) {
+ ap.recur_type = "x-dateset";
+
+ var rdates = ritem.getDates({});
+ var datestr = "";
+ for (j in rdates) {
+ if (j != 0)
+ datestr += ",";
+
+ datestr += dateToText(getInUtcOrKeepFloating(rdates[j]));
+ }
+
+ ap.dates = datestr;
+
+ } else if (calInstanceOf(ritem, Components.interfaces.calIRecurrenceRule)) {
+ ap.recur_type = ritem.type;
- } else if (calInstanceOf(ritem, Components.interfaces.calIRecurrenceDateSet)) {
- ap.recur_type = "x-dateset";
+ if (ritem.isByCount)
+ ap.count = ritem.count;
+ else
+ ap.end_date = ritem.untilDate ? ritem.untilDate.nativeTime : null;
+
+ ap.interval = ritem.interval;
- var rdates = ritem.getDates({});
- var datestr = "";
- for (j in rdates) {
- if (j != 0)
- datestr += ",";
-
- datestr += dateToText(getInUtcOrKeepFloating(rdates[j]));
+ var rtypes = ["second",
+ "minute",
+ "hour",
+ "day",
+ "monthday",
+ "yearday",
+ "weekno",
+ "month",
+ "setpos"];
+ for (var j = 0; j < rtypes.length; j++) {
+ var comp = "BY" + rtypes[j].toUpperCase();
+ var comps = ritem.getComponent(comp, {});
+ if (comps && comps.length > 0) {
+ var compstr = comps.join(",");
+ ap[rtypes[j]] = compstr;
+ }
+ }
+ } else {
+ dump ("##### Don't know how to serialize recurrence item " + ritem + "!\n");
}
- ap.dates = datestr;
-
- } else if (calInstanceOf(ritem, Components.interfaces.calIRecurrenceRule)) {
- ap.recur_type = ritem.type;
-
- if (ritem.isByCount)
- ap.count = ritem.count;
- else
- ap.end_date = ritem.untilDate ? ritem.untilDate.nativeTime : null;
-
- ap.interval = ritem.interval;
-
- var rtypes = ["second",
- "minute",
- "hour",
- "day",
- "monthday",
- "yearday",
- "weekno",
- "month",
- "setpos"];
- for (var j = 0; j < rtypes.length; j++) {
- var comp = "BY" + rtypes[j].toUpperCase();
- var comps = ritem.getComponent(comp, {});
- if (comps && comps.length > 0) {
- var compstr = comps.join(",");
- ap[rtypes[j]] = compstr;
- }
- }
- } else {
- dump ("##### Don't know how to serialize recurrence item " + ritem + "!\n");
+ this.mInsertRecurrence.execute();
+ } finally {
+ this.mInsertRecurrence.reset();
}
-
- this.mInsertRecurrence.execute();
- this.mInsertRecurrence.reset();
}
var exceptions = rec.getExceptionIds ({});
if (exceptions.length > 0) {
flags |= CAL_ITEM_FLAG.HAS_EXCEPTIONS;
// we need to serialize each exid as a separate
// event/todo; setupItemBase will handle
@@ -2097,68 +2113,72 @@ calStorageCalendar.prototype = {
return flags;
},
writeAttachments: function cSC_writeAttachments(item, olditem) {
let attachments = item.getAttachments({});
if (attachments && attachments.length > 0) {
for each (att in attachments) {
let ap = this.mInsertAttachment.params;
- this.prepareStatement(this.mInsertAttachment);
- this.setDateParamHelper(ap, "recurrence_id", item.recurrenceId);
- ap.item_id = item.id;
- ap.data = (att.uri ? att.uri.spec : "");
- ap.format_type = att.formatType;
- ap.encoding = att.encoding;
+ try {
+ this.prepareStatement(this.mInsertAttachment);
+ this.setDateParamHelper(ap, "recurrence_id", item.recurrenceId);
+ ap.item_id = item.id;
+ ap.data = (att.uri ? att.uri.spec : "");
+ ap.format_type = att.formatType;
+ ap.encoding = att.encoding;
- this.mInsertAttachment.execute();
- this.mInsertAttachment.reset();
+ this.mInsertAttachment.execute();
+ } finally {
+ this.mInsertAttachment.reset();
+ }
}
return CAL_ITEM_FLAG.HAS_ATTACHMENTS;
}
return 0;
},
writeRelations: function cSC_writeRelations(item, olditem) {
let relations = item.getRelations({});
if (relations && relations.length > 0) {
for each (var rel in relations) {
let rp = this.mInsertRelation.params;
- this.prepareStatement(this.mInsertRelation);
- this.setDateParamHelper(rp, "recurrence_id", item.recurrenceId);
- rp.item_id = item.id;
- rp.rel_type = rel.relType;
- rp.rel_id = rel.relId;
+ try {
+ this.prepareStatement(this.mInsertRelation);
+ this.setDateParamHelper(rp, "recurrence_id", item.recurrenceId);
+ rp.item_id = item.id;
+ rp.rel_type = rel.relType;
+ rp.rel_id = rel.relId;
- this.mInsertRelation.execute();
- this.mInsertRelation.reset();
+ this.mInsertRelation.execute();
+ } finally {
+ this.mInsertRelation.reset();
+ }
}
return CAL_ITEM_FLAG.HAS_RELATIONS;
}
return 0;
- },
+ },
writeAlarms: function cSC_writeAlarms(item, olditem) {
let alarms = item.getAlarms({});
if (alarms.length < 1) {
return 0;
}
for each (let alarm in alarms) {
let pp = this.mInsertAlarm.params;
- this.prepareStatement(this.mInsertAlarm);
try {
+ this.prepareStatement(this.mInsertAlarm);
this.setDateParamHelper(pp, "recurrence_id", item.recurrenceId);
pp.item_id = item.id;
pp.icalString = alarm.icalString;
this.mInsertAlarm.execute();
} catch(e) {
- cal.ERROR("Error writing alarm for item " + item.title + " (" + item.id + ")" +
- "\nDB Error: " + this.mDB.lastErrorString +
- "\nException: " + e);
+ this.logError("Error writing alarm for item " + item.title + " (" + item.id + ")", e);
} finally {
this.mInsertAlarm.reset();
}
}
return CAL_ITEM_FLAG.HAS_ALARMS;
},
@@ -2212,31 +2232,31 @@ calStorageCalendar.prototype = {
* when the transaction count reaches zero, the transaction is rolled back.
*
* @param err (optional) If set, the transaction is set to fail when
* the count reaches zero.
*/
releaseTransaction: function cSC_releaseTransaction(err) {
let calId = this.id;
if (err) {
- cal.ERROR("DB error: " + this.mDB.lastErrorString + "\nexc: " + err);
+ this.logError("releaseTransaction on error", err);
gTransErr[calId] = err;
}
if (gTransCount[calId] > 0) {
if (--gTransCount[calId] == 0) {
if (gTransErr[calId]) {
this.mDB.rollbackTransaction();
delete gTransErr[calId];
} else {
this.mDB.commitTransaction();
}
}
} else {
- ASSERT(gTransCount[calId] > 0, "unexepcted batch count!");
+ ASSERT(gTransCount[calId] > 0, "unexpected batch count!");
}
},
startBatch: function cSC_startBatch() {
this.acquireTransaction();
this.__proto__.__proto__.startBatch.apply(this, arguments);
},
endBatch: function cSC_endBatch() {
@@ -2244,71 +2264,118 @@ calStorageCalendar.prototype = {
this.__proto__.__proto__.endBatch.apply(this, arguments);
},
//
// calISyncWriteCalendar interface
//
setMetaData: function cSC_setMetaData(id, value) {
+
this.mDeleteMetaData(id, this.id);
- this.prepareStatement(this.mInsertMetaData);
- var sp = this.mInsertMetaData.params;
- sp.item_id = id;
- try {
+ try {
+ this.prepareStatement(this.mInsertMetaData);
+ var sp = this.mInsertMetaData.params;
+ sp.item_id = id;
sp.value = value;
+ this.mInsertMetaData.execute();
} catch (e) {
// The storage service throws an NS_ERROR_ILLEGAL_VALUE in
// case pval is something complex (i.e not a string or
// number). Swallow this error, leaving the value empty.
if (e.result != Components.results.NS_ERROR_ILLEGAL_VALUE) {
+ this.logError("Error setting metadata for id " + id + "!", e);
throw e;
}
+ } finally {
+ this.mInsertMetaData.reset();
}
- this.mInsertMetaData.execute();
- this.mInsertMetaData.reset();
},
deleteMetaData: function cSC_deleteMetaData(id) {
this.mDeleteMetaData(id, this.id);
},
getMetaData: function cSC_getMetaData(id) {
let query = this.mSelectMetaData;
- this.prepareStatement(query);
- query.params.item_id = id;
- let value = null;
try {
+ this.prepareStatement(query);
+ query.params.item_id = id;
+ let value = null;
+
if (query.step()) {
value = query.row.value;
}
} catch (e) {
- cal.ERROR("Error getting metadata for id " + id + "!\n" + e +
- "\nDB Error: " + this.mDB.lastErrorString);
+ this.logError("Error getting metadata for id " + id + "!", e);
} finally {
query.reset();
}
return value;
},
getAllMetaData: function cSC_getAllMetaData(out_count,
out_ids,
out_values) {
let query = this.mSelectAllMetaData;
- this.prepareStatement(query);
- let ids = [];
- let values = [];
try {
+ this.prepareStatement(query);
+ let ids = [];
+ let values = [];
while (query.step()) {
ids.push(query.row.item_id);
values.push(query.row.value);
}
+ out_count.value = ids.length;
+ out_ids.value = ids;
+ out_values.value = values;
} catch (e) {
- cal.ERROR("Error getting all metadata!\n" + e +
- "\nDB Error: " + this.mDB.lastErrorString);
+ this.logError("Error getting all metadata!", e);
} finally {
query.reset();
}
- out_count.value = ids.length;
- out_ids.value = ids;
- out_values.value = values;
+ },
+ /**
+ * Internal logging function that should be called on any database error,
+ * it will log as much info as possible about the database context and
+ * last statement so the problem can be investigated more easilly.
+ *
+ * @param message Error message to log.
+ * @param exception Exception that caused the error.
+ */
+ logError: function cSC_logError(message,exception) {
+ let logMessage = "Message: " + message;
+ if (this.mDB) {
+ if (this.mDB.connectionReady) {
+ logMessage += "\nConnection Ready: " + this.mDB.connectionReady;
+ }
+ if (this.mDB.lastError) {
+ logMessage += "\nLast DB Error Number: " + this.mDB.lastError;
+ }
+ if (this.mDB.lastErrorString) {
+ logMessage += "\nLast DB Error Message: " + this.mDB.lastErrorString;
+ }
+ if (this.mDB.databaseFile) {
+ logMessage += "\nDatabase File: " + this.mDB.databaseFile.path;
+ }
+ if (this.mDB.lastInsertRowId) {
+ logMessage += "\nLast Insert Row Id: " + this.mDB.lastInsertRowId;
+ }
+ if (this.mDB.transactionInProgress) {
+ logMessage += "\nTransaction In Progress: " + this.mDB.transactionInProgress;
+ }
+ }
+
+ if (this.mLastStatement) {
+ logMessage += "\nLast DB Statement: " + this.mLastStatement;
+ if (this.mLastStatement.params) {
+ for (let param in this.mLastStatement.params) {
+ logMessage += "\nLast Statement param [" + param + "]: " + this.mLastStatement.params[param];
+ }
+ }
+ }
+
+ if (exception) {
+ logMessage += "\nException: " + exception;
+ }
+ cal.ERROR(logMessage + "\n" + STACK(10));
}
};