8b8805e978d9f3082c09351ee19bbad1ca09cac2 angie Tue May 14 10:38:44 2019 -0700 When saving a session, if a table is not in customTrash then check whether it has already been saved to a customData* db. If not, just move on instead of aborting. refs #22440 diff --git src/hg/hgSession/sessionData.c src/hg/hgSession/sessionData.c index 46469e6..8e8acc0 100644 --- src/hg/hgSession/sessionData.c +++ src/hg/hgSession/sessionData.c @@ -188,41 +188,61 @@ freeMem(encTrashPath); freeMem(newPath); } if (urlEncoded) freeMem(trashDirPrefix); } } static char *sessionDataDbTableName(char *tableName, char *sessionDataDbPrefix, char *dbSuffix) /* Alloc and return a new table name that includes a db derived from sessionDataDbPrefix. */ { struct dyString *dy = dyStringCreate("%s%s.%s", sessionDataDbPrefix, dbSuffix, tableName); return dyStringCannibalize(&dy); } +static char *findTableInSessionDataDbs(struct sqlConnection *conn, char *sessionDataDbPrefix, + char *tableName) +/* Given a tableName (no db. prefix), if it exists in any of the sessionDataPrefix* dbs + * then return the full db.tableName, otherwise NULL. */ +{ +int day; +for (day = 1; day <= 31; day++) + { + char dbDotTable[strlen(sessionDataDbPrefix) + 3 + strlen(tableName) + 1]; + safef(dbDotTable, sizeof dbDotTable, "%s%02d.%s", sessionDataDbPrefix, day, tableName); + if (sqlTableExists(conn, dbDotTable)) + return cloneString(dbDotTable); + } +return NULL; +} + static char *saveTrashTable(char *tableName, char *sessionDataDbPrefix, char *dbSuffix) /* Move trash tableName out of customTrash to a sessionDataDbPrefix database, unless that - * has been done already. Return the new database.table name. */ + * has been done already. If table does not exist in either customTrash or customData*, + * then return NULL; otherwise return the new database.table name. */ { char *newDbTableName = sessionDataDbTableName(tableName, sessionDataDbPrefix, dbSuffix); struct sqlConnection *conn = hAllocConn(CUSTOM_TRASH); if (! sqlTableExists(conn, newDbTableName)) { if (! sqlTableExists(conn, tableName)) - errAbort("saveTrashTable: neither "CUSTOM_TRASH".%s nor %s exist", - tableName, newDbTableName); + { + // It's possible that this table was already saved and moved out of customTrash as part + // of some other saved session. We don't have a way of leaving a symlink in customTrash. + return findTableInSessionDataDbs(conn, sessionDataDbPrefix, tableName); + } struct dyString *dy = sqlDyStringCreate("rename table %s to %s", tableName, newDbTableName); sqlUpdate(conn, dy->string); dyStringFree(&dy); } else if (sqlTableExists(conn, tableName)) errAbort("saveTrashTable: both %s and %s exist", tableName, newDbTableName); hFreeConn(&conn); return newDbTableName; } static void replaceColumnValue(struct sqlConnection *conn, char *tableName, char *columnName, char *newVal) /* Replace all tableName.columnName values with newVal. */ { struct dyString *dy = sqlDyStringCreate("update %s set %s = '%s'", @@ -292,36 +312,39 @@ char quote = *start; if (quote == '\'' || quote == '"') start++; else quote = '\0'; char *end = start; while (*end && ((quote && *end != quote) || (!quote && !isspace(*end)))) end++; if (stringIn(prefix, end)) errAbort("saveDbTableName: encountered two instances of '%s', expected 0 or 1", prefix); char *tableName = cloneStringZ(start, (end - start)); if (!startsWith(sessionDataDbPrefix, tableName)) { char *newDbTableName = saveTrashTable(tableName, sessionDataDbPrefix, dbSuffix); + if (newDbTableName) + { updateSessionDataTablePaths(newDbTableName, sessionDir); char *newString = replaceChars(*retString, tableName, newDbTableName); freez(retString); *retString = newString; freeMem(newDbTableName); } + } freeMem(tableName); } } } static char *newCtTrashFile() /* Alloc and return the name of a new trash file to hold custom track metadata. */ { struct tempName tn; trashDirFile(&tn, "ct", CT_PREFIX, ".ctfile"); return cloneString(tn.forCgi); } static char *saveTrackFile(struct cart *cart, char *varName, char *oldFile, char *sessionDataDbPrefix, char *dbSuffix, char *sessionDir)