Index: trunk/ippTools/src/pztool.c
===================================================================
--- trunk/ippTools/src/pztool.c	(revision 17611)
+++ trunk/ippTools/src/pztool.c	(revision 17655)
@@ -2,5 +2,5 @@
  * pztool.c
  *
- * Copyright (C) 2006  Joshua Hoblitt
+ * Copyright (C) 2006-2008  Joshua Hoblitt
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -27,4 +27,5 @@
 #include <inttypes.h>
 
+#include "pslib.h"
 #include "pxtools.h"
 #include "pxdata.h"
@@ -41,4 +42,5 @@
 static bool updatecopiedMode(pxConfig *config);
 static bool revertcopiedMode(pxConfig *config);
+static bool advanceMode(pxConfig *config);
 
 static bool copydoneCompleteExp(pxConfig *config, const char *exp_name, const char *camera, const char *telescope);
@@ -75,4 +77,5 @@
         MODECASE(PZTOOL_MODE_UPDATECOPIED, updatecopiedMode);
         MODECASE(PZTOOL_MODE_REVERTCOPIED, revertcopiedMode);
+        MODECASE(PZTOOL_MODE_ADVANCE, advanceMode);
         default:
             psAbort("invalid option (this should not happen)");
@@ -360,6 +363,16 @@
     PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
 
-    // need to know exp_name, camera, telescope, class, class_id (to find the
-    // pzDownloadImfile entry and the URI for the newImfile entry.
+    if (!pzDownloadImfileInsert(config->dbh,
+            exp_name,
+            camera,
+            telescope,
+            class,
+            class_id,
+            uri,
+            code
+    )) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
 
     // start a transaction so it's all rows or nothing
@@ -367,45 +380,4 @@
         psError(PS_ERR_UNKNOWN, false, "database error");
         return false;
-    }
-
-    // cp the imfile into pzDownloadImfile
-    {
-        char *query =
-            "INSERT INTO pzDownloadImfile"
-            "   SELECT"
-            "       exp_name,"
-            "       camera,"
-            "       telescope,"
-            "       class,"
-            "       class_id,"
-            "       '%s'," // uri of downloaded file
-            "       '%d'" // fault code
-            "   FROM summitImfile"
-            "   WHERE"
-            "       summitImfile.exp_name = '%s'"
-            "       AND summitImfile.camera = '%s'"
-            "       AND summitImfile.telescope = '%s'"
-            "       AND summitImfile.class = '%s'"
-            "       AND summitImfile.class_id = '%s'";
-
-        if (!p_psDBRunQuery(config->dbh, query, uri, code, exp_name, camera, telescope, class, class_id)) {
-            // rollback
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            psError(PS_ERR_UNKNOWN, false, "database error");
-            return false;
-        } 
-
-        // sanity check: we should have inserted only one row
-        psU64 affected = psDBAffectedRows(config->dbh);
-        if (psDBAffectedRows(config->dbh) != 1) {
-            // rollback
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            psError(PS_ERR_UNKNOWN, false, "should have affected 1 row but %" PRIu64 " rows were modified", affected);
-            return false;
-        }
     }
 
@@ -434,4 +406,6 @@
 static bool copydoneCompleteExp(pxConfig *config, const char *exp_name, const char *camera, const char *telescope)
 {
+    // THIS FUNCTION MUST BE INVOKED FROM INSIDE A TRANSACTION!!!
+    
     PS_ASSERT_PTR_NON_NULL(config, false);
 
@@ -440,5 +414,4 @@
     // these options are thrown away unless we just -copydone'd the last imfile
     // in an exp.  
-    // This function MUST NOT be invoked from anywhere but copydoneMode().
  
     // optional
@@ -457,6 +430,35 @@
     }
 
-    psStringAppend(&query, "WHERE exp_name = '%s' AND telescope = '%s' AND camera = '%s'",
-                          exp_name, telescope, camera);
+    psMetadata *where = psMetadataAlloc();
+    if (exp_name) {
+        if (!psMetadataAddStr(where, PS_LIST_TAIL, "exp_name", 0, "==", exp_name)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to add item exp_name");
+            psFree(where);
+            return false;
+        }
+    }
+
+    if (camera) {
+        if (!psMetadataAddStr(where, PS_LIST_TAIL, "camera", 0, "==", camera)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to add item camera");
+            psFree(where);
+            return false;
+        }
+    }
+
+    if (telescope) {
+        if (!psMetadataAddStr(where, PS_LIST_TAIL, "telescope", 0, "==", telescope)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to add item telescope");
+            psFree(where);
+            return false;
+        }
+    }
+
+    if (config->where) {
+        psString whereClause = psDBGenerateWhereSQL(where, NULL);
+        psStringAppend(&query, " %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
 
     if (!p_psDBRunQuery(config->dbh, query)) {
@@ -736,4 +738,38 @@
 
 
+static bool advanceMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    // start a transaction so it's all rows or nothing
+    if (!psDBTransaction(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    if (!copydoneCompleteExp(config, NULL, NULL, NULL)) {
+        // rollback
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
+        psError(PS_ERR_UNKNOWN, false, "copydoneCompleteExp() failed");
+        return false;
+    }
+
+    // point of no return
+    if (!psDBCommit(config->dbh)) {
+        // rollback
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+
+    return true;
+}
+
+
 static bool pzDownloadExpSetState(pxConfig *config, const char *exp_name, const char *camera, const char *telescope, const char *state)
 {
