Index: /trunk/ippdb/configure.ac
===================================================================
--- /trunk/ippdb/configure.ac	(revision 8265)
+++ /trunk/ippdb/configure.ac	(revision 8266)
@@ -1,5 +1,5 @@
 AC_PREREQ(2.59)
 
-AC_INIT([ippdb], [0.0.23], [pan-starrs.ifa.hawaii.edu])
+AC_INIT([ippdb], [0.0.24], [pan-starrs.ifa.hawaii.edu])
 AC_CONFIG_SRCDIR([ippdb.pc.in])
 
Index: /trunk/ippdb/src/ippdb.c
===================================================================
--- /trunk/ippdb/src/ippdb.c	(revision 8265)
+++ /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)
Index: /trunk/ippdb/src/ippdb.h
===================================================================
--- /trunk/ippdb/src/ippdb.h	(revision 8265)
+++ /trunk/ippdb/src/ippdb.h	(revision 8266)
@@ -286,4 +286,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an weather
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool weatherDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const weatherRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -500,4 +512,16 @@
     const psMetadata *where,            ///< Row match criteria
     unsigned long long limit            ///< Maximum number of elements to return
+);
+/** Deletes a row from the database coresponding to an skyp_transparency
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool skyp_transparencyDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const skyp_transparencyRow *object    ///< Object to delete
 );
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
@@ -724,4 +748,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an skyp_absorption
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool skyp_absorptionDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const skyp_absorptionRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -934,4 +970,16 @@
     const psMetadata *where,            ///< Row match criteria
     unsigned long long limit            ///< Maximum number of elements to return
+);
+/** Deletes a row from the database coresponding to an skyp_emission
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool skyp_emissionDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const skyp_emissionRow *object    ///< Object to delete
 );
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
@@ -1150,4 +1198,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an dimm
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool dimmDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const dimmRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -1361,4 +1421,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an skyp_ir
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool skyp_irDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const skyp_irRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -1563,4 +1635,16 @@
     const psMetadata *where,            ///< Row match criteria
     unsigned long long limit            ///< Maximum number of elements to return
+);
+/** Deletes a row from the database coresponding to an dome
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool domeDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const domeRow *object    ///< Object to delete
 );
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
@@ -1771,4 +1855,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an telescope
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool telescopeDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const telescopeRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -1978,4 +2074,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an summitExp
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool summitExpDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const summitExpRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -2184,4 +2292,16 @@
     const psMetadata *where,            ///< Row match criteria
     unsigned long long limit            ///< Maximum number of elements to return
+);
+/** Deletes a row from the database coresponding to an pzPendingExp
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool pzPendingExpDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const pzPendingExpRow *object    ///< Object to delete
 );
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
@@ -2396,4 +2516,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an pzPendingImfile
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool pzPendingImfileDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const pzPendingImfileRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -2603,4 +2735,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an newExp
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool newExpDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const newExpRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -2805,4 +2949,16 @@
     const psMetadata *where,            ///< Row match criteria
     unsigned long long limit            ///< Maximum number of elements to return
+);
+/** Deletes a row from the database coresponding to an newImfile
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool newImfileDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const newImfileRow *object    ///< Object to delete
 );
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
@@ -3037,4 +3193,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an rawDetrendExp
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool rawDetrendExpDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const rawDetrendExpRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -3267,4 +3435,16 @@
     const psMetadata *where,            ///< Row match criteria
     unsigned long long limit            ///< Maximum number of elements to return
+);
+/** Deletes a row from the database coresponding to an rawScienceExp
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool rawScienceExpDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const rawScienceExpRow *object    ///< Object to delete
 );
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
@@ -3519,4 +3699,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an rawImfile
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool rawImfileDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const rawImfileRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -3757,4 +3949,16 @@
     const psMetadata *where,            ///< Row match criteria
     unsigned long long limit            ///< Maximum number of elements to return
+);
+/** Deletes a row from the database coresponding to an p1PendingExp
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool p1PendingExpDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const p1PendingExpRow *object    ///< Object to delete
 );
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
@@ -4001,4 +4205,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an p2PendingExp
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool p2PendingExpDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const p2PendingExpRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -4211,4 +4427,16 @@
     const psMetadata *where,            ///< Row match criteria
     unsigned long long limit            ///< Maximum number of elements to return
+);
+/** Deletes a row from the database coresponding to an p2PendingImfile
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool p2PendingImfileDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const p2PendingImfileRow *object    ///< Object to delete
 );
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
@@ -4455,4 +4683,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an p2DoneExp
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool p2DoneExpDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const p2DoneExpRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -4665,4 +4905,16 @@
     const psMetadata *where,            ///< Row match criteria
     unsigned long long limit            ///< Maximum number of elements to return
+);
+/** Deletes a row from the database coresponding to an p2DoneImfile
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool p2DoneImfileDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const p2DoneImfileRow *object    ///< Object to delete
 );
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
@@ -4905,4 +5157,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an p3PendingExp
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool p3PendingExpDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const p3PendingExpRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -5099,4 +5363,16 @@
     const psMetadata *where,            ///< Row match criteria
     unsigned long long limit            ///< Maximum number of elements to return
+);
+/** Deletes a row from the database coresponding to an detRun
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool detRunDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const detRunRow *object    ///< Object to delete
 );
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
@@ -5339,4 +5615,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an detInputExp
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool detInputExpDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const detInputExpRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -5546,4 +5834,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an detProcessedImfile
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool detProcessedImfileDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const detProcessedImfileRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -5753,4 +6053,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an detStackedImfile
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool detStackedImfileDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const detStackedImfileRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -5960,4 +6272,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an detNormalizedImfile
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool detNormalizedImfileDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const detNormalizedImfileRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -6158,4 +6482,16 @@
     const psMetadata *where,            ///< Row match criteria
     unsigned long long limit            ///< Maximum number of elements to return
+);
+/** Deletes a row from the database coresponding to an detMasterFrame
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool detMasterFrameDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const detMasterFrameRow *object    ///< Object to delete
 );
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
@@ -6361,4 +6697,16 @@
     const psMetadata *where,            ///< Row match criteria
     unsigned long long limit            ///< Maximum number of elements to return
+);
+/** Deletes a row from the database coresponding to an detMasterImfile
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool detMasterImfileDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const detMasterImfileRow *object    ///< Object to delete
 );
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
@@ -6581,4 +6929,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an detResidImfileAnalysis
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool detResidImfileAnalysisDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const detResidImfileAnalysisRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
@@ -6617,4 +6977,5 @@
     char            *exp_id;
     char            *recipe;
+    bool            keep;
     bool            accept;
 } detResidExpAnalysisRow;
@@ -6630,4 +6991,5 @@
     const char      *exp_id,
     const char      *recipe,
+    bool            keep,
     bool            accept
 );
@@ -6664,4 +7026,5 @@
     const char      *exp_id,
     const char      *recipe,
+    bool            keep,
     bool            accept
 );
@@ -6689,4 +7052,5 @@
     char            **exp_id,
     char            **recipe,
+    bool            *keep,
     bool            *accept
 );
@@ -6788,4 +7152,16 @@
     unsigned long long limit            ///< Maximum number of elements to return
 );
+/** Deletes a row from the database coresponding to an detResidExpAnalysis
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool detResidExpAnalysisDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const detResidExpAnalysisRow *object    ///< Object to delete
+);
 /** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
  *
Index: /trunk/ippdb/tests/alloc.c
===================================================================
--- /trunk/ippdb/tests/alloc.c	(revision 8265)
+++ /trunk/ippdb/tests/alloc.c	(revision 8266)
@@ -1300,5 +1300,5 @@
         detResidExpAnalysisRow *object;
 
-        object = detResidExpAnalysisRowAlloc(-32, -32, "a string", "a string", true    );
+        object = detResidExpAnalysisRowAlloc(-32, -32, "a string", "a string", true, true    );
 
         if (!object) {
@@ -1319,4 +1319,8 @@
         }
         if (strncmp(object->recipe, "a string", MAX_STRING_LENGTH)) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->keep == true) {
             psFree(object);
             exit(EXIT_FAILURE);
Index: /trunk/ippdb/tests/insert.c
===================================================================
--- /trunk/ippdb/tests/insert.c	(revision 8265)
+++ /trunk/ippdb/tests/insert.c	(revision 8266)
@@ -463,5 +463,5 @@
         }
 
-        if (!detResidExpAnalysisInsert(dbh, -32, -32, "a string", "a string", true)) {
+        if (!detResidExpAnalysisInsert(dbh, -32, -32, "a string", "a string", true, true)) {
             exit(EXIT_FAILURE);
         }
Index: /trunk/ippdb/tests/insertobject.c
===================================================================
--- /trunk/ippdb/tests/insertobject.c	(revision 8265)
+++ /trunk/ippdb/tests/insertobject.c	(revision 8266)
@@ -674,5 +674,5 @@
         }
 
-        object = detResidExpAnalysisRowAlloc(-32, -32, "a string", "a string", true);
+        object = detResidExpAnalysisRowAlloc(-32, -32, "a string", "a string", true, true);
         if (!object) {
             exit(EXIT_FAILURE);
Index: /trunk/ippdb/tests/metadatafromobject.c
===================================================================
--- /trunk/ippdb/tests/metadatafromobject.c	(revision 8265)
+++ /trunk/ippdb/tests/metadatafromobject.c	(revision 8266)
@@ -1543,5 +1543,5 @@
         bool            status;
 
-        object = detResidExpAnalysisRowAlloc(-32, -32, "a string", "a string", true);
+        object = detResidExpAnalysisRowAlloc(-32, -32, "a string", "a string", true, true);
         if (!object) {
             exit(EXIT_FAILURE);
@@ -1568,4 +1568,8 @@
         }
         if (strncmp(psMetadataLookupPtr(&status, md, "recipe"), "a string", MAX_STRING_LENGTH)) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataLookupBool(&status, md, "keep") == true) {
             psFree(md);
             exit(EXIT_FAILURE);
Index: /trunk/ippdb/tests/objectfrommetadata.c
===================================================================
--- /trunk/ippdb/tests/objectfrommetadata.c	(revision 8265)
+++ /trunk/ippdb/tests/objectfrommetadata.c	(revision 8266)
@@ -2369,4 +2369,8 @@
             exit(EXIT_FAILURE);
         }
+        if (!psMetadataAdd(md, PS_LIST_TAIL, "keep", PS_DATA_BOOL, NULL, true)) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
         if (!psMetadataAdd(md, PS_LIST_TAIL, "accept", PS_DATA_BOOL, NULL, true)) {
             psFree(md);
@@ -2395,4 +2399,8 @@
         }
         if (strncmp(object->recipe, "a string", MAX_STRING_LENGTH)) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->keep == true) {
             psFree(object);
             exit(EXIT_FAILURE);
Index: /trunk/ippdb/tests/pop.c
===================================================================
--- /trunk/ippdb/tests/pop.c	(revision 8265)
+++ /trunk/ippdb/tests/pop.c	(revision 8266)
@@ -686,4 +686,5 @@
         char            exp_id[256];
         char            recipe[256];
+        bool            keep;
         bool            accept;
 
@@ -693,5 +694,5 @@
         }
 
-        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)) { 
             exit(EXIT_FAILURE);
         }
