Restore requested IMAP UIDs through Store WRITE
Debian Trixie package bundle / packages (push) Successful in 21m38s

This commit is contained in:
Mario Fetka
2026-07-23 15:08:46 +02:00
parent 60ce9cd37a
commit 2d27c7da0a
4 changed files with 32 additions and 10 deletions
+9 -4
View File
@@ -1341,12 +1341,12 @@ StoreCommandLoop(StoreClient *client)
case STORE_COMMAND_WRITE:
/* WRITE <collection> <type> <length>
[F<filename>] [G<guid>] [T<timeCreated>]
[I<imapuid>] [F<filename>] [G<guid>] [T<timeCreated>]
[Z<flags>] [L<link guid>] [N]
*/
if (TOKEN_OK != (ccode = RequireStore(client)) ||
TOKEN_OK != (ccode = CheckTokC(client, n, 4, 9)) ||
TOKEN_OK != (ccode = CheckTokC(client, n, 4, 10)) ||
TOKEN_OK != (ccode = ParseCollection(client, tokens[1], &object)) ||
TOKEN_OK != (ccode = ParseDocType(client, tokens[2], &doctype)) ||
TOKEN_OK != (ccode = ParseStreamLength(client, tokens[3], &int1)))
@@ -1357,6 +1357,7 @@ StoreCommandLoop(StoreClient *client)
filename = NULL;
timestamp = 0;
ulong = 0; /* addflags */
ulong2 = 0; /* requested IMAP UID */
guid = 0;
guid2 = 0; /* link guid */
int2 = 0; /* whether or not to process the document */
@@ -1370,6 +1371,8 @@ StoreCommandLoop(StoreClient *client)
filename = tokens[i] + 1;
} else if ('N' == *tokens[i] && tokens[i][1] == '\0') {
int2 = 1;
} else if ('I' == *tokens[i] && !ulong2) {
ccode = ParseUnsignedLong(client, tokens[i] + 1, &ulong2);
} else if ('T' == *tokens[i] && !timestamp) {
ccode = ParseDateTimeToUint64(client, 1 + tokens[i], &timestamp);
} else if ('Z' == *tokens[i] && !ulong) {
@@ -1386,7 +1389,8 @@ StoreCommandLoop(StoreClient *client)
}
ccode = StoreCommandWRITE(client, &object, doctype, int1,
(uint32_t) ulong, guid, filename,
(uint32_t) ulong, (uint32_t) ulong2,
guid, filename,
timestamp, guid2, int2);
break;
@@ -3254,6 +3258,7 @@ StoreCommandWRITE(StoreClient *client,
int doctype,
uint64_t size,
uint32_t addflags,
uint32_t requested_imapuid,
uint64_t guid,
const char *filename,
uint64_t timestamp,
@@ -3354,7 +3359,7 @@ StoreCommandWRITE(StoreClient *client,
ccode = ConnWriteStr(client->conn, MSG4224CANTWRITE);
goto finish;
}
if (StoreObjectUpdateImapUID(client, &newdocument)) {
if (StoreObjectSetImapUID(client, &newdocument, requested_imapuid)) {
LogicalLockRelease(client, collection, LLOCK_READWRITE, "StoreCommandWRITE");
ccode = ConnWriteStr(client->conn, MSG5005DBLIBERR);
goto finish;
+1
View File
@@ -272,6 +272,7 @@ CCode StoreCommandWRITE(StoreClient *client,
int doctype,
uint64_t size,
uint32_t addflags,
uint32_t requested_imapuid,
uint64_t guid,
const char *filename,
uint64_t timestamp,
+20 -6
View File
@@ -1105,12 +1105,20 @@ abort:
// correct value :(
int
StoreObjectUpdateImapUID(StoreClient *client, StoreObject *object)
{
return StoreObjectSetImapUID(client, object, 0);
}
int
StoreObjectSetImapUID(StoreClient *client, StoreObject *object,
uint32_t requested_imapuid)
{
MsgSQLStatement stmt;
MsgSQLStatement *ret;
StoreObject collection;
char *query;
int new_imapuid;
int collection_imapuid;
int status;
if (StoreObjectFind(client, object->collection_guid, &collection)) {
@@ -1121,16 +1129,22 @@ StoreObjectUpdateImapUID(StoreClient *client, StoreObject *object)
memset(&stmt, 0, sizeof(MsgSQLStatement));
MsgSQLBeginTransaction(client->storedb);
// update the imap uid in a transaction to assure atomicity
new_imapuid = ++collection.imap_uid;
query = "UPDATE storeobject SET imap_uid = ?1 WHERE guid IN (?2, ?3);";
// Update the object and collection counter in one transaction. Restore
// operations may request an existing UID, including values with gaps.
new_imapuid = requested_imapuid ?
(int)requested_imapuid : (int)collection.imap_uid + 1;
collection_imapuid = MAX((int)collection.imap_uid, new_imapuid);
query = "UPDATE storeobject SET imap_uid = "
"CASE WHEN guid = ?1 THEN ?2 ELSE ?3 END "
"WHERE guid IN (?1, ?4);";
ret = MsgSQLPrepare(client->storedb, query, &stmt);
if (ret == NULL) goto abort;
MsgSQLBindInt(&stmt, 1, new_imapuid);
MsgSQLBindInt64(&stmt, 2, object->guid);
MsgSQLBindInt64(&stmt, 3, collection.guid);
MsgSQLBindInt64(&stmt, 1, object->guid);
MsgSQLBindInt(&stmt, 2, new_imapuid);
MsgSQLBindInt(&stmt, 3, collection_imapuid);
MsgSQLBindInt64(&stmt, 4, collection.guid);
status = MsgSQLExecute(client->storedb, &stmt);
if (status != 0) {
+2
View File
@@ -107,6 +107,8 @@ void StoreOutputProperty(StoreClient *client, StorePropertyType type, const char
// "dangerous" functions which hit the DB directly
int StoreObjectCopyInfo(StoreClient *client, StoreObject *old, StoreObject *newobj);
int StoreObjectUpdateImapUID(StoreClient *client, StoreObject *object);
int StoreObjectSetImapUID(StoreClient *client, StoreObject *object,
uint32_t requested_imapuid);
int StoreObjectRenameSubobjects(StoreClient *client, StoreObject *container, const char *new_root);
int StoreObjectRemoveCollection(StoreClient *client, StoreObject *collection);