c68067f0a368163016f57cf9f5230f838f7a83fd
jcasper
  Thu Mar 10 19:52:36 2022 -0800
Re-saving over a session shouldn't destroy the description, refs #22901

diff --git src/hg/hgSession/hgSession.c src/hg/hgSession/hgSession.c
index af8d649..d524fcb 100644
--- src/hg/hgSession/hgSession.c
+++ src/hg/hgSession/hgSession.c
@@ -795,72 +795,93 @@
     printf("%s on", CART_HAS_DEFAULT_VISIBILITY);
 }
 
 #define INITIAL_USE_COUNT 0
 static int saveCartAsSession(struct sqlConnection *conn, char *encUserName, char *encSessionName,
                              int sharingLevel)
 /* Save all settings in cart, either adding a new session or overwriting an existing session.
  * Return useCount so that the caller can distinguish between adding and overWriting. */
 {
 struct sqlResult *sr = NULL;
 struct dyString *dy = dyStringNew(16 * 1024);
 char **row;
 char *firstUse = "now()";
 int useCount = INITIAL_USE_COUNT;
 char firstUseBuf[32];
+char *settings = NULL;
+
+boolean gotSettings = (sqlFieldIndex(conn, namedSessionTable, "settings") >= 0);
 
-/* If this session already existed, preserve its firstUse and useCount. */
+/* If this session already existed, preserve its firstUse, useCount,
+ * and settings (if available). */
+if (gotSettings)
+    sqlDyStringPrintf(dy, "SELECT firstUse, useCount, settings FROM %s "
+                  "WHERE userName = '%s' AND sessionName = '%s';",
+                  namedSessionTable, encUserName, encSessionName);
+else
     sqlDyStringPrintf(dy, "SELECT firstUse, useCount FROM %s "
                   "WHERE userName = '%s' AND sessionName = '%s';",
                   namedSessionTable, encUserName, encSessionName);
 sr = sqlGetResult(conn, dy->string);
 if ((row = sqlNextRow(sr)) != NULL)
     {
     safef(firstUseBuf, sizeof(firstUseBuf), "'%s'", row[0]);
     firstUse = firstUseBuf;
     useCount = atoi(row[1]) + 1;
+    if (gotSettings)
+        {
+        settings = cloneString(row[2]);
+        if (settings == NULL)
+            settings = "";
+        }
     }
 sqlFreeResult(&sr);
 
 saveSessionData(cart, encUserName, encSessionName,
                 cgiOptionalString(hgsSessionDataDbSuffix));
 
 /* Remove pre-existing session (if any) before updating. */
 dyStringClear(dy);
 sqlDyStringPrintf(dy, "DELETE FROM %s WHERE userName = '%s' AND "
                   "sessionName = '%s';",
                   namedSessionTable, encUserName, encSessionName);
 sqlUpdate(conn, dy->string);
 
 dyStringClear(dy);
 sqlDyStringPrintf(dy, "INSERT INTO %s ", namedSessionTable);
 dyStringAppend(dy, "(userName, sessionName, contents, shared, "
-               "firstUse, lastUse, useCount, settings) VALUES (");
+               "firstUse, lastUse, useCount");
+if (gotSettings)
+    dyStringAppend(dy, ", settings");
+dyStringAppend(dy, ") VALUES (");
 dyStringPrintf(dy, "'%s', '%s', ", encUserName, encSessionName);
 dyStringAppend(dy, "'");
 cleanHgSessionFromCart(cart);
 struct dyString *encoded = newDyString(4096);
 cartEncodeState(cart, encoded);
 
 // Now add all the default visibilities to output.
 outDefaultTracks(cart, encoded);
 
 sqlDyAppendEscaped(dy, encoded->string);
 dyStringFree(&encoded);
 dyStringAppend(dy, "', ");
 dyStringPrintf(dy, "%d, ", sharingLevel);
-dyStringPrintf(dy, "%s, now(), %d, '');", firstUse, useCount);
+dyStringPrintf(dy, "%s, now(), %d, '", firstUse, useCount);
+if (gotSettings)
+    dyStringPrintf(dy, ", '%s'", settings);
+dyStringPrintf(dy, ");");
 sqlUpdate(conn, dy->string);
 dyStringFree(&dy);
 
 /* Prevent modification of custom track collections just saved to namedSessionDb: */
 cartCopyCustomComposites(cart);
 return useCount;
 }
 
 char *doNewSession(char *userName)
 /* Save current settings in a new named session.
  * Return a message confirming what we did. */
 {
 if (userName == NULL)
     return "Unable to save session -- please log in and try again.";
 struct dyString *dyMessage = dyStringNew(2048);