Index: trunk/ippdb/src/ippdb.c
===================================================================
--- trunk/ippdb/src/ippdb.c	(revision 8228)
+++ trunk/ippdb/src/ippdb.c	(revision 8266)
@@ -718,4 +718,22 @@
     return returnSet;
 }
+bool weatherDeleteObject(psDB *dbh, const weatherRow *object)
+{
+    psMetadata *where = weatherMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, WEATHER_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from weather");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "weatherRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long weatherDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -1248,4 +1266,22 @@
     return returnSet;
 }
+bool skyp_transparencyDeleteObject(psDB *dbh, const skyp_transparencyRow *object)
+{
+    psMetadata *where = skyp_transparencyMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, SKYP_TRANSPARENCY_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from skyp_transparency");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "skyp_transparencyRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long skyp_transparencyDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -1836,4 +1872,22 @@
     return returnSet;
 }
+bool skyp_absorptionDeleteObject(psDB *dbh, const skyp_absorptionRow *object)
+{
+    psMetadata *where = skyp_absorptionMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, SKYP_ABSORPTION_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from skyp_absorption");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "skyp_absorptionRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long skyp_absorptionDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -2337,4 +2391,22 @@
     return returnSet;
 }
+bool skyp_emissionDeleteObject(psDB *dbh, const skyp_emissionRow *object)
+{
+    psMetadata *where = skyp_emissionMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, SKYP_EMISSION_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from skyp_emission");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "skyp_emissionRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long skyp_emissionDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -2867,4 +2939,22 @@
     return returnSet;
 }
+bool dimmDeleteObject(psDB *dbh, const dimmRow *object)
+{
+    psMetadata *where = dimmMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, DIMM_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from dimm");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "dimmRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long dimmDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -3367,4 +3457,22 @@
     return returnSet;
 }
+bool skyp_irDeleteObject(psDB *dbh, const skyp_irRow *object)
+{
+    psMetadata *where = skyp_irMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, SKYP_IR_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from skyp_ir");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "skyp_irRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long skyp_irDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -3809,4 +3917,22 @@
     return returnSet;
 }
+bool domeDeleteObject(psDB *dbh, const domeRow *object)
+{
+    psMetadata *where = domeMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, DOME_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from dome");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "domeRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long domeDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -4281,4 +4407,22 @@
     return returnSet;
 }
+bool telescopeDeleteObject(psDB *dbh, const telescopeRow *object)
+{
+    psMetadata *where = telescopeMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, TELESCOPE_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from telescope");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "telescopeRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long telescopeDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -4757,4 +4901,22 @@
     return returnSet;
 }
+bool summitExpDeleteObject(psDB *dbh, const summitExpRow *object)
+{
+    psMetadata *where = summitExpMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, SUMMITEXP_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from summitExp");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "summitExpRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long summitExpDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -5232,4 +5394,22 @@
     return returnSet;
 }
+bool pzPendingExpDeleteObject(psDB *dbh, const pzPendingExpRow *object)
+{
+    psMetadata *where = pzPendingExpMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, PZPENDINGEXP_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from pzPendingExp");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "pzPendingExpRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long pzPendingExpDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -5737,4 +5917,22 @@
     return returnSet;
 }
+bool pzPendingImfileDeleteObject(psDB *dbh, const pzPendingImfileRow *object)
+{
+    psMetadata *where = pzPendingImfileMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, PZPENDINGIMFILE_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from pzPendingImfile");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "pzPendingImfileRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long pzPendingImfileDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -6212,4 +6410,22 @@
     return returnSet;
 }
+bool newExpDeleteObject(psDB *dbh, const newExpRow *object)
+{
+    psMetadata *where = newExpMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, NEWEXP_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from newExp");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "newExpRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long newExpDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -6658,4 +6874,22 @@
     return returnSet;
 }
+bool newImfileDeleteObject(psDB *dbh, const newImfileRow *object)
+{
+    psMetadata *where = newImfileMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, NEWIMFILE_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from newImfile");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "newImfileRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long newImfileDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -7308,4 +7542,22 @@
     return returnSet;
 }
+bool rawDetrendExpDeleteObject(psDB *dbh, const rawDetrendExpRow *object)
+{
+    psMetadata *where = rawDetrendExpMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, RAWDETRENDEXP_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from rawDetrendExp");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "rawDetrendExpRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long rawDetrendExpDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -7957,4 +8209,22 @@
 
     return returnSet;
+}
+bool rawScienceExpDeleteObject(psDB *dbh, const rawScienceExpRow *object)
+{
+    psMetadata *where = rawScienceExpMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, RAWSCIENCEEXP_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from rawScienceExp");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "rawScienceExpRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
 }
 long long rawScienceExpDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
@@ -8753,4 +9023,22 @@
     return returnSet;
 }
+bool rawImfileDeleteObject(psDB *dbh, const rawImfileRow *object)
+{
+    psMetadata *where = rawImfileMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, RAWIMFILE_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from rawImfile");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "rawImfileRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long rawImfileDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -9462,4 +9750,22 @@
     return returnSet;
 }
+bool p1PendingExpDeleteObject(psDB *dbh, const p1PendingExpRow *object)
+{
+    psMetadata *where = p1PendingExpMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, P1PENDINGEXP_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p1PendingExp");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "p1PendingExpRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long p1PendingExpDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -10200,4 +10506,22 @@
     return returnSet;
 }
+bool p2PendingExpDeleteObject(psDB *dbh, const p2PendingExpRow *object)
+{
+    psMetadata *where = p2PendingExpMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, P2PENDINGEXP_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p2PendingExp");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "p2PendingExpRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long p2PendingExpDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -10704,4 +11028,22 @@
     return returnSet;
 }
+bool p2PendingImfileDeleteObject(psDB *dbh, const p2PendingImfileRow *object)
+{
+    psMetadata *where = p2PendingImfileMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, P2PENDINGIMFILE_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p2PendingImfile");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "p2PendingImfileRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long p2PendingImfileDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -11442,4 +11784,22 @@
     return returnSet;
 }
+bool p2DoneExpDeleteObject(psDB *dbh, const p2DoneExpRow *object)
+{
+    psMetadata *where = p2DoneExpMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, P2DONEEXP_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p2DoneExp");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "p2DoneExpRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long p2DoneExpDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -11946,4 +12306,22 @@
     return returnSet;
 }
+bool p2DoneImfileDeleteObject(psDB *dbh, const p2DoneImfileRow *object)
+{
+    psMetadata *where = p2DoneImfileMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, P2DONEIMFILE_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p2DoneImfile");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "p2DoneImfileRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long p2DoneImfileDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -12654,4 +13032,22 @@
     return returnSet;
 }
+bool p3PendingExpDeleteObject(psDB *dbh, const p3PendingExpRow *object)
+{
+    psMetadata *where = p3PendingExpMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, P3PENDINGEXP_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p3PendingExp");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "p3PendingExpRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long p3PendingExpDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -13039,4 +13435,22 @@
     return returnSet;
 }
+bool detRunDeleteObject(psDB *dbh, const detRunRow *object)
+{
+    psMetadata *where = detRunMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, DETRUN_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from detRun");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "detRunRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long detRunDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -13747,4 +14161,22 @@
     return returnSet;
 }
+bool detInputExpDeleteObject(psDB *dbh, const detInputExpRow *object)
+{
+    psMetadata *where = detInputExpMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, DETINPUTEXP_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from detInputExp");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "detInputExpRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long detInputExpDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -14222,4 +14654,22 @@
     return returnSet;
 }
+bool detProcessedImfileDeleteObject(psDB *dbh, const detProcessedImfileRow *object)
+{
+    psMetadata *where = detProcessedImfileMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, DETPROCESSEDIMFILE_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from detProcessedImfile");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "detProcessedImfileRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long detProcessedImfileDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -14696,4 +15146,22 @@
     return returnSet;
 }
+bool detStackedImfileDeleteObject(psDB *dbh, const detStackedImfileRow *object)
+{
+    psMetadata *where = detStackedImfileMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, DETSTACKEDIMFILE_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from detStackedImfile");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "detStackedImfileRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long detStackedImfileDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -15170,4 +15638,22 @@
     return returnSet;
 }
+bool detNormalizedImfileDeleteObject(psDB *dbh, const detNormalizedImfileRow *object)
+{
+    psMetadata *where = detNormalizedImfileMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, DETNORMALIZEDIMFILE_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from detNormalizedImfile");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "detNormalizedImfileRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long detNormalizedImfileDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -15584,4 +16070,22 @@
     return returnSet;
 }
+bool detMasterFrameDeleteObject(psDB *dbh, const detMasterFrameRow *object)
+{
+    psMetadata *where = detMasterFrameMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, DETMASTERFRAME_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from detMasterFrame");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "detMasterFrameRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long detMasterFrameDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -16029,4 +16533,22 @@
     return returnSet;
 }
+bool detMasterImfileDeleteObject(psDB *dbh, const detMasterImfileRow *object)
+{
+    psMetadata *where = detMasterImfileMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, DETMASTERIMFILE_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from detMasterImfile");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "detMasterImfileRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long detMasterImfileDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -16593,4 +17115,22 @@
     return returnSet;
 }
+bool detResidImfileAnalysisDeleteObject(psDB *dbh, const detResidImfileAnalysisRow *object)
+{
+    psMetadata *where = detResidImfileAnalysisMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, DETRESIDIMFILEANALYSIS_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from detResidImfileAnalysis");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "detResidImfileAnalysisRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
 long long detResidImfileAnalysisDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
@@ -16645,5 +17185,5 @@
 static void detResidExpAnalysisRowFree(detResidExpAnalysisRow *object);
 
-detResidExpAnalysisRow *detResidExpAnalysisRowAlloc(psS32 det_id, psS32 iteration, const char *exp_id, const char *recipe, bool accept)
+detResidExpAnalysisRow *detResidExpAnalysisRowAlloc(psS32 det_id, psS32 iteration, const char *exp_id, const char *recipe, bool keep, bool accept)
 {
     detResidExpAnalysisRow *object;
@@ -16656,4 +17196,5 @@
     object->exp_id = psStringCopy(exp_id);
     object->recipe = psStringCopy(recipe);
+    object->keep = keep;
     object->accept = accept;
 
@@ -16698,4 +17239,9 @@
         return false;
     }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "keep", PS_DATA_BOOL, NULL, false)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item keep");
+        psFree(md);
+        return false;
+    }
     if (!psMetadataAdd(md, PS_LIST_TAIL, "accept", PS_DATA_BOOL, NULL, false)) {
         psError(PS_ERR_UNKNOWN, false, "failed to add item accept");
@@ -16716,5 +17262,5 @@
 }
 
-bool detResidExpAnalysisInsert(psDB * dbh, psS32 det_id, psS32 iteration, const char *exp_id, const char *recipe, bool accept)
+bool detResidExpAnalysisInsert(psDB * dbh, psS32 det_id, psS32 iteration, const char *exp_id, const char *recipe, bool keep, bool accept)
 {
     psMetadata      *md;
@@ -16739,4 +17285,9 @@
     if (!psMetadataAddStr(md, PS_LIST_TAIL, "recipe", 0, NULL, recipe)) {
         psError(PS_ERR_UNKNOWN, false, "failed to add item recipe");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "keep", PS_DATA_BOOL, NULL, keep)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item keep");
         psFree(md);
         return false;
@@ -16768,5 +17319,5 @@
     return deleted;
 }
-bool detResidExpAnalysisPop(psDB *dbh, psS32 *det_id, psS32 *iteration, char **exp_id, char **recipe, bool *accept)
+bool detResidExpAnalysisPop(psDB *dbh, psS32 *det_id, psS32 *iteration, char **exp_id, char **recipe, bool *keep, bool *accept)
 {
     psArray         *rowSet;
@@ -16836,4 +17387,10 @@
         return false;
     }
+    *keep = psMetadataLookupBool(&status, row, "keep");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item keep");
+        psFree(row);
+        return false;
+    }
     *accept = psMetadataLookupBool(&status, row, "accept");
     if (!status) {
@@ -16850,5 +17407,5 @@
 bool detResidExpAnalysisInsertObject(psDB *dbh, detResidExpAnalysisRow *object)
 {
-    return detResidExpAnalysisInsert(dbh, object->det_id, object->iteration, object->exp_id, object->recipe, object->accept);
+    return detResidExpAnalysisInsert(dbh, object->det_id, object->iteration, object->exp_id, object->recipe, object->keep, object->accept);
 }
 
@@ -16859,12 +17416,13 @@
     char            exp_id[256];
     char            recipe[256];
+    bool            keep;
     bool            accept;
 
-    if (!detResidExpAnalysisPop(dbh, &det_id, &iteration, (char **)&exp_id, (char **)&recipe, &accept)) {
+    if (!detResidExpAnalysisPop(dbh, &det_id, &iteration, (char **)&exp_id, (char **)&recipe, &keep, &accept)) {
         psError(PS_ERR_UNKNOWN, false, "failed to pop a database row");
         return NULL;
     }
 
-    return detResidExpAnalysisRowAlloc(det_id, iteration, exp_id, recipe, accept);
+    return detResidExpAnalysisRowAlloc(det_id, iteration, exp_id, recipe, keep, accept);
 }
 
@@ -16985,4 +17543,9 @@
         return NULL;
     }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "keep", PS_DATA_BOOL, NULL, object->keep)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item keep");
+        psFree(md);
+        return NULL;
+    }
     if (!psMetadataAdd(md, PS_LIST_TAIL, "accept", PS_DATA_BOOL, NULL, object->accept)) {
         psError(PS_ERR_UNKNOWN, false, "failed to add item accept");
@@ -17001,4 +17564,5 @@
     char            *exp_id;
     char            *recipe;
+    bool            keep;
     bool            accept;
 
@@ -17023,4 +17587,9 @@
         return false;
     }
+    keep = psMetadataLookupBool(&status, md, "keep");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item keep");
+        return false;
+    }
     accept = psMetadataLookupBool(&status, md, "accept");
     if (!status) {
@@ -17029,5 +17598,5 @@
     }
 
-    return detResidExpAnalysisRowAlloc(det_id, iteration, exp_id, recipe, accept);
+    return detResidExpAnalysisRowAlloc(det_id, iteration, exp_id, recipe, keep, accept);
 }
 psArray *detResidExpAnalysisSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
@@ -17065,4 +17634,22 @@
 
     return returnSet;
+}
+bool detResidExpAnalysisDeleteObject(psDB *dbh, const detResidExpAnalysisRow *object)
+{
+    psMetadata *where = detResidExpAnalysisMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, DETRESIDEXPANALYSIS_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from detResidExpAnalysis");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "detResidExpAnalysisRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
 }
 long long detResidExpAnalysisDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
