Forráskód Böngészése

- Updated mmo_char_tosql and memitemdata_to_sql to keep a count of errors while saving a character. If there are any errors, the in-memory copy (cp) will not be updated. Should fix dupes that can happen when a intermediary save fails because of sql access being down.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@14949 54d463be-8e91-2dee-dedb-b68131a5f0ec
Skotlex 13 éve
szülő
commit
4fed311425
2 módosított fájl, 63 hozzáadás és 24 törlés
  1. 2 0
      Changelog-Trunk.txt
  2. 61 24
      src/char_sql/char.c

+ 2 - 0
Changelog-Trunk.txt

@@ -1,5 +1,7 @@
 Date	Added
 
+2011/08/30
+	* Corrected SQL saving so that the server won't update the 'saved' data if there is an SQL error. It should fix possible dupes and other data synch issues when the SQL server is temporarily down during save. [Skotlex]
 2011/08/23
 	* Rewrote the combo logic. Now it uses packet 0x7e1 to signal skill state changes rather than resending the whole skill list. [Skotlex]
 2011/08/21

+ 61 - 24
src/char_sql/char.c

@@ -409,6 +409,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 	int diff = 0;
 	char save_status[128]; //For displaying save information. [Skotlex]
 	struct mmo_charstatus *cp;
+	int errors = 0; //If there are any errors while saving, "cp" will not be updated at the end.
 	StringBuf buf;
 
 	if (char_id!=p->char_id) return 0;
@@ -425,22 +426,28 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 	//map inventory data
 	if( memcmp(p->inventory, cp->inventory, sizeof(p->inventory)) )
 	{
-		memitemdata_to_sql(p->inventory, MAX_INVENTORY, p->char_id, TABLE_INVENTORY);
-		strcat(save_status, " inventory");
+		if (!memitemdata_to_sql(p->inventory, MAX_INVENTORY, p->char_id, TABLE_INVENTORY))
+			strcat(save_status, " inventory");
+		else
+			errors++;
 	}
 
 	//map cart data
 	if( memcmp(p->cart, cp->cart, sizeof(p->cart)) )
 	{
-		memitemdata_to_sql(p->cart, MAX_CART, p->char_id, TABLE_CART);
-		strcat(save_status, " cart");
+		if (!memitemdata_to_sql(p->cart, MAX_CART, p->char_id, TABLE_CART))
+			strcat(save_status, " cart");
+		else
+			errors++;
 	}
 
 	//map storage data
 	if( memcmp(p->storage.items, cp->storage.items, sizeof(p->storage.items)) )
 	{
-		memitemdata_to_sql(p->storage.items, MAX_STORAGE, p->account_id, TABLE_STORAGE);
-		strcat(save_status, " storage");
+		if (!memitemdata_to_sql(p->storage.items, MAX_STORAGE, p->account_id, TABLE_STORAGE))
+			strcat(save_status, " storage");
+		else
+			errors++;
 	}
 
 #ifdef TXT_SQL_CONVERT
@@ -452,9 +459,9 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 		char_db, p->char_id, p->account_id, p->slot, esc_name) )
 	{
 		Sql_ShowDebug(sql_handle);
-	}
-
-	strcat(save_status, " creation");
+		errors++;
+	} else
+		strcat(save_status, " creation");
 }
 #endif
 
@@ -499,8 +506,9 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 			p->account_id, p->char_id) )
 		{
 			Sql_ShowDebug(sql_handle);
-		}
-		strcat(save_status, " status");
+			errors++;
+		} else
+			strcat(save_status, " status");
 	}
 
 	//Values that will seldom change (to speed up saving)
@@ -525,9 +533,9 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 			p->account_id, p->char_id) )
 		{
 			Sql_ShowDebug(sql_handle);
-		}
-
-		strcat(save_status, " status2");
+			errors++;
+		} else
+			strcat(save_status, " status2");
 	}
 
 	/* Mercenary Owner */
@@ -536,8 +544,10 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 		(p->spear_calls != cp->spear_calls) || (p->spear_faith != cp->spear_faith) ||
 		(p->sword_calls != cp->sword_calls) || (p->sword_faith != cp->sword_faith) )
 	{
-		mercenary_owner_tosql(char_id, p);
-		strcat(save_status, " mercenary");
+		if (mercenary_owner_tosql(char_id, p))
+			strcat(save_status, " mercenary");
+		else
+			errors++;
 	}
 
 	//memo points
@@ -547,7 +557,10 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 
 		//`memo` (`memo_id`,`char_id`,`map`,`x`,`y`)
 		if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, p->char_id) )
+		{
 			Sql_ShowDebug(sql_handle);
+			errors++;
+		}
 
 		//insert here.
 		StringBuf_Clear(&buf);
@@ -566,9 +579,11 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 		if( count )
 		{
 			if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
+			{
 				Sql_ShowDebug(sql_handle);
+				errors++;
+			}
 		}
-		
 		strcat(save_status, " memo");
 	}
 
@@ -583,7 +598,10 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 	{
 		//`skill` (`char_id`, `id`, `lv`)
 		if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, p->char_id) )
+		{
 			Sql_ShowDebug(sql_handle);
+			errors++;
+		}
 
 		StringBuf_Clear(&buf);
 		StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`id`,`lv`) VALUES ", skill_db);
@@ -601,7 +619,10 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 		if( count )
 		{
 			if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
+			{
 				Sql_ShowDebug(sql_handle);
+				errors++;
+			}
 		}
 
 		strcat(save_status, " skills");
@@ -619,7 +640,10 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 	if(diff == 1)
 	{	//Save friends
 		if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", friend_db, char_id) )
+		{
 			Sql_ShowDebug(sql_handle);
+			errors++;
+		}
 
 		StringBuf_Clear(&buf);
 		StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `friend_account`, `friend_id`) VALUES ", friend_db);
@@ -636,12 +660,12 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 		if( count )
 		{
 			if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
+			{
 				Sql_ShowDebug(sql_handle);
-			else
-				strcat(save_status, " friends");
+				errors++;
+			}
 		}
-		else //Friend list cleared.
-			strcat(save_status, " friends");
+		strcat(save_status, " friends");
 	}
 
 #ifdef HOTKEY_SAVING
@@ -660,8 +684,10 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 	}
 	if(diff) {
 		if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
+		{
 			Sql_ShowDebug(sql_handle);
-		else
+			errors++;
+		} else
 			strcat(save_status, " hotkeys");
 	}
 #endif
@@ -669,7 +695,8 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 	if (save_status[0]!='\0' && save_log)
 		ShowInfo("Saved char %d - %s:%s.\n", char_id, p->name, save_status);
 #ifndef TXT_SQL_CONVERT
-	memcpy(cp, p, sizeof(struct mmo_charstatus));
+	if (!errors)
+		memcpy(cp, p, sizeof(struct mmo_charstatus));
 #else
 	aFree(cp);
 #endif
@@ -688,6 +715,7 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
 	struct item item; // temp storage variable
 	bool* flag; // bit array for inventory matching
 	bool found;
+	int errors = 0;
 
 	switch (tableswitch) {
 	case TABLE_INVENTORY:     tablename = inventory_db;     selectoption = "char_id";    break;
@@ -770,7 +798,10 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
 					StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id);
 					
 					if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
+					{
 						Sql_ShowDebug(sql_handle);
+						errors++;
+					}
 				}
 
 				found = flag[i] = true; //Item dealt with,
@@ -780,7 +811,10 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
 		if( !found )
 		{// Item not present in inventory, remove it.
 			if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d'", tablename, item.id) )
+			{
 				Sql_ShowDebug(sql_handle);
+				errors++;
+			}
 		}
 	}
 	SqlStmt_Free(stmt);
@@ -812,12 +846,15 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
 	}
 
 	if( found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
+	{
 		Sql_ShowDebug(sql_handle);
+		errors++;
+	}
 
 	StringBuf_Destroy(&buf);
 	aFree(flag);
 
-	return 0;
+	return errors;
 }
 
 int mmo_char_tobuf(uint8* buf, struct mmo_charstatus* p);