aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Data/MySQL/MySQLXAssetData.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Data/MySQL/MySQLXAssetData.cs')
-rw-r--r--OpenSim/Data/MySQL/MySQLXAssetData.cs384
1 files changed, 182 insertions, 202 deletions
diff --git a/OpenSim/Data/MySQL/MySQLXAssetData.cs b/OpenSim/Data/MySQL/MySQLXAssetData.cs
index 5f1d2ee..68e1a5a 100644
--- a/OpenSim/Data/MySQL/MySQLXAssetData.cs
+++ b/OpenSim/Data/MySQL/MySQLXAssetData.cs
@@ -57,7 +57,6 @@ namespace OpenSim.Data.MySQL
57 57
58 private bool m_enableCompression = false; 58 private bool m_enableCompression = false;
59 private string m_connectionString; 59 private string m_connectionString;
60 private object m_dbLock = new object();
61 60
62 /// <summary> 61 /// <summary>
63 /// We can reuse this for all hashing since all methods are single-threaded through m_dbBLock 62 /// We can reuse this for all hashing since all methods are single-threaded through m_dbBLock
@@ -131,60 +130,58 @@ namespace OpenSim.Data.MySQL
131// m_log.DebugFormat("[MYSQL XASSET DATA]: Looking for asset {0}", assetID); 130// m_log.DebugFormat("[MYSQL XASSET DATA]: Looking for asset {0}", assetID);
132 131
133 AssetBase asset = null; 132 AssetBase asset = null;
134 lock (m_dbLock) 133
134 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
135 { 135 {
136 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) 136 dbcon.Open();
137
138 using (MySqlCommand cmd = new MySqlCommand(
139 "SELECT Name, Description, AccessTime, AssetType, Local, Temporary, AssetFlags, CreatorID, Data FROM XAssetsMeta JOIN XAssetsData ON XAssetsMeta.Hash = XAssetsData.Hash WHERE ID=?ID",
140 dbcon))
137 { 141 {
138 dbcon.Open(); 142 cmd.Parameters.AddWithValue("?ID", assetID.ToString());
139 143
140 using (MySqlCommand cmd = new MySqlCommand( 144 try
141 "SELECT Name, Description, AccessTime, AssetType, Local, Temporary, AssetFlags, CreatorID, Data FROM XAssetsMeta JOIN XAssetsData ON XAssetsMeta.Hash = XAssetsData.Hash WHERE ID=?ID",
142 dbcon))
143 { 145 {
144 cmd.Parameters.AddWithValue("?ID", assetID.ToString()); 146 using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow))
145
146 try
147 { 147 {
148 using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) 148 if (dbReader.Read())
149 { 149 {
150 if (dbReader.Read()) 150 asset = new AssetBase(assetID, (string)dbReader["Name"], (sbyte)dbReader["AssetType"], dbReader["CreatorID"].ToString());
151 { 151 asset.Data = (byte[])dbReader["Data"];
152 asset = new AssetBase(assetID, (string)dbReader["Name"], (sbyte)dbReader["AssetType"], dbReader["CreatorID"].ToString()); 152 asset.Description = (string)dbReader["Description"];
153 asset.Data = (byte[])dbReader["Data"];
154 asset.Description = (string)dbReader["Description"];
155 153
156 string local = dbReader["Local"].ToString(); 154 string local = dbReader["Local"].ToString();
157 if (local.Equals("1") || local.Equals("true", StringComparison.InvariantCultureIgnoreCase)) 155 if (local.Equals("1") || local.Equals("true", StringComparison.InvariantCultureIgnoreCase))
158 asset.Local = true; 156 asset.Local = true;
159 else 157 else
160 asset.Local = false; 158 asset.Local = false;
161 159
162 asset.Temporary = Convert.ToBoolean(dbReader["Temporary"]); 160 asset.Temporary = Convert.ToBoolean(dbReader["Temporary"]);
163 asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]); 161 asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]);
164 162
165 if (m_enableCompression) 163 if (m_enableCompression)
164 {
165 using (GZipStream decompressionStream = new GZipStream(new MemoryStream(asset.Data), CompressionMode.Decompress))
166 { 166 {
167 using (GZipStream decompressionStream = new GZipStream(new MemoryStream(asset.Data), CompressionMode.Decompress)) 167 MemoryStream outputStream = new MemoryStream();
168 { 168 WebUtil.CopyStream(decompressionStream, outputStream, int.MaxValue);
169 MemoryStream outputStream = new MemoryStream(); 169// int compressedLength = asset.Data.Length;
170 WebUtil.CopyStream(decompressionStream, outputStream, int.MaxValue); 170 asset.Data = outputStream.ToArray();
171 // int compressedLength = asset.Data.Length; 171
172 asset.Data = outputStream.ToArray(); 172// m_log.DebugFormat(
173 173// "[XASSET DB]: Decompressed {0} {1} to {2} bytes from {3}",
174 // m_log.DebugFormat( 174// asset.ID, asset.Name, asset.Data.Length, compressedLength);
175 // "[XASSET DB]: Decompressed {0} {1} to {2} bytes from {3}",
176 // asset.ID, asset.Name, asset.Data.Length, compressedLength);
177 }
178 } 175 }
179
180 UpdateAccessTime(asset.Metadata, (int)dbReader["AccessTime"]);
181 } 176 }
177
178 UpdateAccessTime(asset.Metadata, (int)dbReader["AccessTime"]);
182 } 179 }
183 } 180 }
184 catch (Exception e) 181 }
185 { 182 catch (Exception e)
186 m_log.Error(string.Format("[MYSQL XASSET DATA]: Failure fetching asset {0}", assetID), e); 183 {
187 } 184 m_log.Error(string.Format("[MYSQL XASSET DATA]: Failure fetching asset {0}", assetID), e);
188 } 185 }
189 } 186 }
190 } 187 }
@@ -201,113 +198,110 @@ namespace OpenSim.Data.MySQL
201 { 198 {
202// m_log.DebugFormat("[XASSETS DB]: Storing asset {0} {1}", asset.Name, asset.ID); 199// m_log.DebugFormat("[XASSETS DB]: Storing asset {0} {1}", asset.Name, asset.ID);
203 200
204 lock (m_dbLock) 201 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
205 { 202 {
206 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) 203 dbcon.Open();
204
205 using (MySqlTransaction transaction = dbcon.BeginTransaction())
207 { 206 {
208 dbcon.Open(); 207 string assetName = asset.Name;
208 if (asset.Name.Length > AssetBase.MAX_ASSET_NAME)
209 {
210 assetName = asset.Name.Substring(0, AssetBase.MAX_ASSET_NAME);
211 m_log.WarnFormat(
212 "[XASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add",
213 asset.Name, asset.ID, asset.Name.Length, assetName.Length);
214 }
209 215
210 using (MySqlTransaction transaction = dbcon.BeginTransaction()) 216 string assetDescription = asset.Description;
217 if (asset.Description.Length > AssetBase.MAX_ASSET_DESC)
211 { 218 {
212 string assetName = asset.Name; 219 assetDescription = asset.Description.Substring(0, AssetBase.MAX_ASSET_DESC);
213 if (asset.Name.Length > 64) 220 m_log.WarnFormat(
214 { 221 "[XASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add",
215 assetName = asset.Name.Substring(0, 64); 222 asset.Description, asset.ID, asset.Description.Length, assetDescription.Length);
216 m_log.WarnFormat( 223 }
217 "[XASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add",
218 asset.Name, asset.ID, asset.Name.Length, assetName.Length);
219 }
220
221 string assetDescription = asset.Description;
222 if (asset.Description.Length > 64)
223 {
224 assetDescription = asset.Description.Substring(0, 64);
225 m_log.WarnFormat(
226 "[XASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add",
227 asset.Description, asset.ID, asset.Description.Length, assetDescription.Length);
228 }
229 224
230 if (m_enableCompression) 225 if (m_enableCompression)
231 { 226 {
232 MemoryStream outputStream = new MemoryStream(); 227 MemoryStream outputStream = new MemoryStream();
233 228
234 using (GZipStream compressionStream = new GZipStream(outputStream, CompressionMode.Compress, false)) 229 using (GZipStream compressionStream = new GZipStream(outputStream, CompressionMode.Compress, false))
235 { 230 {
236 // Console.WriteLine(WebUtil.CopyTo(new MemoryStream(asset.Data), compressionStream, int.MaxValue)); 231// Console.WriteLine(WebUtil.CopyTo(new MemoryStream(asset.Data), compressionStream, int.MaxValue));
237 // We have to close the compression stream in order to make sure it writes everything out to the underlying memory output stream. 232 // We have to close the compression stream in order to make sure it writes everything out to the underlying memory output stream.
238 compressionStream.Close(); 233 compressionStream.Close();
239 byte[] compressedData = outputStream.ToArray(); 234 byte[] compressedData = outputStream.ToArray();
240 asset.Data = compressedData; 235 asset.Data = compressedData;
241 }
242 } 236 }
237 }
243 238
244 byte[] hash = hasher.ComputeHash(asset.Data); 239 byte[] hash = hasher.ComputeHash(asset.Data);
245 240
246// m_log.DebugFormat( 241// m_log.DebugFormat(
247// "[XASSET DB]: Compressed data size for {0} {1}, hash {2} is {3}", 242// "[XASSET DB]: Compressed data size for {0} {1}, hash {2} is {3}",
248// asset.ID, asset.Name, hash, compressedData.Length); 243// asset.ID, asset.Name, hash, compressedData.Length);
249 244
245 try
246 {
247 using (MySqlCommand cmd =
248 new MySqlCommand(
249 "replace INTO XAssetsMeta(ID, Hash, Name, Description, AssetType, Local, Temporary, CreateTime, AccessTime, AssetFlags, CreatorID)" +
250 "VALUES(?ID, ?Hash, ?Name, ?Description, ?AssetType, ?Local, ?Temporary, ?CreateTime, ?AccessTime, ?AssetFlags, ?CreatorID)",
251 dbcon))
252 {
253 // create unix epoch time
254 int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow);
255 cmd.Parameters.AddWithValue("?ID", asset.ID);
256 cmd.Parameters.AddWithValue("?Hash", hash);
257 cmd.Parameters.AddWithValue("?Name", assetName);
258 cmd.Parameters.AddWithValue("?Description", assetDescription);
259 cmd.Parameters.AddWithValue("?AssetType", asset.Type);
260 cmd.Parameters.AddWithValue("?Local", asset.Local);
261 cmd.Parameters.AddWithValue("?Temporary", asset.Temporary);
262 cmd.Parameters.AddWithValue("?CreateTime", now);
263 cmd.Parameters.AddWithValue("?AccessTime", now);
264 cmd.Parameters.AddWithValue("?CreatorID", asset.Metadata.CreatorID);
265 cmd.Parameters.AddWithValue("?AssetFlags", (int)asset.Flags);
266 cmd.ExecuteNonQuery();
267 }
268 }
269 catch (Exception e)
270 {
271 m_log.ErrorFormat("[ASSET DB]: MySQL failure creating asset metadata {0} with name \"{1}\". Error: {2}",
272 asset.FullID, asset.Name, e.Message);
273
274 transaction.Rollback();
275
276 return;
277 }
278
279 if (!ExistsData(dbcon, transaction, hash))
280 {
250 try 281 try
251 { 282 {
252 using (MySqlCommand cmd = 283 using (MySqlCommand cmd =
253 new MySqlCommand( 284 new MySqlCommand(
254 "replace INTO XAssetsMeta(ID, Hash, Name, Description, AssetType, Local, Temporary, CreateTime, AccessTime, AssetFlags, CreatorID)" + 285 "INSERT INTO XAssetsData(Hash, Data) VALUES(?Hash, ?Data)",
255 "VALUES(?ID, ?Hash, ?Name, ?Description, ?AssetType, ?Local, ?Temporary, ?CreateTime, ?AccessTime, ?AssetFlags, ?CreatorID)",
256 dbcon)) 286 dbcon))
257 { 287 {
258 // create unix epoch time
259 int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow);
260 cmd.Parameters.AddWithValue("?ID", asset.ID);
261 cmd.Parameters.AddWithValue("?Hash", hash); 288 cmd.Parameters.AddWithValue("?Hash", hash);
262 cmd.Parameters.AddWithValue("?Name", assetName); 289 cmd.Parameters.AddWithValue("?Data", asset.Data);
263 cmd.Parameters.AddWithValue("?Description", assetDescription);
264 cmd.Parameters.AddWithValue("?AssetType", asset.Type);
265 cmd.Parameters.AddWithValue("?Local", asset.Local);
266 cmd.Parameters.AddWithValue("?Temporary", asset.Temporary);
267 cmd.Parameters.AddWithValue("?CreateTime", now);
268 cmd.Parameters.AddWithValue("?AccessTime", now);
269 cmd.Parameters.AddWithValue("?CreatorID", asset.Metadata.CreatorID);
270 cmd.Parameters.AddWithValue("?AssetFlags", (int)asset.Flags);
271 cmd.ExecuteNonQuery(); 290 cmd.ExecuteNonQuery();
272 } 291 }
273 } 292 }
274 catch (Exception e) 293 catch (Exception e)
275 { 294 {
276 m_log.ErrorFormat("[ASSET DB]: MySQL failure creating asset metadata {0} with name \"{1}\". Error: {2}", 295 m_log.ErrorFormat("[XASSET DB]: MySQL failure creating asset data {0} with name \"{1}\". Error: {2}",
277 asset.FullID, asset.Name, e.Message); 296 asset.FullID, asset.Name, e.Message);
278 297
279 transaction.Rollback(); 298 transaction.Rollback();
280 299
281 return; 300 return;
282 } 301 }
283
284 if (!ExistsData(dbcon, transaction, hash))
285 {
286 try
287 {
288 using (MySqlCommand cmd =
289 new MySqlCommand(
290 "INSERT INTO XAssetsData(Hash, Data) VALUES(?Hash, ?Data)",
291 dbcon))
292 {
293 cmd.Parameters.AddWithValue("?Hash", hash);
294 cmd.Parameters.AddWithValue("?Data", asset.Data);
295 cmd.ExecuteNonQuery();
296 }
297 }
298 catch (Exception e)
299 {
300 m_log.ErrorFormat("[XASSET DB]: MySQL failure creating asset data {0} with name \"{1}\". Error: {2}",
301 asset.FullID, asset.Name, e.Message);
302
303 transaction.Rollback();
304
305 return;
306 }
307 }
308
309 transaction.Commit();
310 } 302 }
303
304 transaction.Commit();
311 } 305 }
312 } 306 }
313 } 307 }
@@ -328,31 +322,28 @@ namespace OpenSim.Data.MySQL
328 if ((now - Utils.UnixTimeToDateTime(accessTime)).TotalDays < DaysBetweenAccessTimeUpdates) 322 if ((now - Utils.UnixTimeToDateTime(accessTime)).TotalDays < DaysBetweenAccessTimeUpdates)
329 return; 323 return;
330 324
331 lock (m_dbLock) 325 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
332 { 326 {
333 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) 327 dbcon.Open();
334 { 328 MySqlCommand cmd =
335 dbcon.Open(); 329 new MySqlCommand("update XAssetsMeta set AccessTime=?AccessTime where ID=?ID", dbcon);
336 MySqlCommand cmd =
337 new MySqlCommand("update XAssetsMeta set AccessTime=?AccessTime where ID=?ID", dbcon);
338 330
339 try 331 try
340 { 332 {
341 using (cmd) 333 using (cmd)
342 {
343 // create unix epoch time
344 cmd.Parameters.AddWithValue("?ID", assetMetadata.ID);
345 cmd.Parameters.AddWithValue("?AccessTime", (int)Utils.DateTimeToUnixTime(now));
346 cmd.ExecuteNonQuery();
347 }
348 }
349 catch (Exception e)
350 { 334 {
351 m_log.ErrorFormat( 335 // create unix epoch time
352 "[XASSET MYSQL DB]: Failure updating access_time for asset {0} with name {1}", 336 cmd.Parameters.AddWithValue("?ID", assetMetadata.ID);
353 assetMetadata.ID, assetMetadata.Name); 337 cmd.Parameters.AddWithValue("?AccessTime", (int)Utils.DateTimeToUnixTime(now));
338 cmd.ExecuteNonQuery();
354 } 339 }
355 } 340 }
341 catch (Exception)
342 {
343 m_log.ErrorFormat(
344 "[XASSET MYSQL DB]: Failure updating access_time for asset {0} with name {1}",
345 assetMetadata.ID, assetMetadata.Name);
346 }
356 } 347 }
357 } 348 }
358 349
@@ -397,45 +388,40 @@ namespace OpenSim.Data.MySQL
397 } 388 }
398 389
399 /// <summary> 390 /// <summary>
400 /// Check if the asset exists in the database 391 /// Check if the assets exist in the database.
401 /// </summary> 392 /// </summary>
402 /// <param name="uuid">The asset UUID</param> 393 /// <param name="uuids">The asset UUID's</param>
403 /// <returns>true if it exists, false otherwise.</returns> 394 /// <returns>For each asset: true if it exists, false otherwise</returns>
404 public bool ExistsAsset(UUID uuid) 395 public bool[] AssetsExist(UUID[] uuids)
405 { 396 {
406// m_log.DebugFormat("[ASSETS DB]: Checking for asset {0}", uuid); 397 if (uuids.Length == 0)
398 return new bool[0];
399
400 HashSet<UUID> exists = new HashSet<UUID>();
407 401
408 bool assetExists = false; 402 string ids = "'" + string.Join("','", uuids) + "'";
403 string sql = string.Format("SELECT ID FROM assets WHERE ID IN ({0})", ids);
409 404
410 lock (m_dbLock) 405 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
411 { 406 {
412 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) 407 dbcon.Open();
408 using (MySqlCommand cmd = new MySqlCommand(sql, dbcon))
413 { 409 {
414 dbcon.Open(); 410 using (MySqlDataReader dbReader = cmd.ExecuteReader())
415 using (MySqlCommand cmd = new MySqlCommand("SELECT ID FROM XAssetsMeta WHERE ID=?ID", dbcon))
416 { 411 {
417 cmd.Parameters.AddWithValue("?ID", uuid.ToString()); 412 while (dbReader.Read())
418
419 try
420 { 413 {
421 using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) 414 UUID id = DBGuid.FromDB(dbReader["ID"]);
422 { 415 exists.Add(id);
423 if (dbReader.Read())
424 {
425// m_log.DebugFormat("[ASSETS DB]: Found asset {0}", uuid);
426 assetExists = true;
427 }
428 }
429 }
430 catch (Exception e)
431 {
432 m_log.Error(string.Format("[XASSETS DB]: MySql failure fetching asset {0}", uuid), e);
433 } 416 }
434 } 417 }
435 } 418 }
436 } 419 }
437 420
438 return assetExists; 421 bool[] results = new bool[uuids.Length];
422 for (int i = 0; i < uuids.Length; i++)
423 results[i] = exists.Contains(uuids[i]);
424 return results;
439 } 425 }
440 426
441 427
@@ -451,43 +437,40 @@ namespace OpenSim.Data.MySQL
451 { 437 {
452 List<AssetMetadata> retList = new List<AssetMetadata>(count); 438 List<AssetMetadata> retList = new List<AssetMetadata>(count);
453 439
454 lock (m_dbLock) 440 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
455 { 441 {
456 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) 442 dbcon.Open();
457 { 443 MySqlCommand cmd = new MySqlCommand("SELECT Name, Description, AccessTime, AssetType, Temporary, ID, AssetFlags, CreatorID FROM XAssetsMeta LIMIT ?start, ?count", dbcon);
458 dbcon.Open(); 444 cmd.Parameters.AddWithValue("?start", start);
459 MySqlCommand cmd = new MySqlCommand("SELECT Name, Description, AccessTime, AssetType, Temporary, ID, AssetFlags, CreatorID FROM XAssetsMeta LIMIT ?start, ?count", dbcon); 445 cmd.Parameters.AddWithValue("?count", count);
460 cmd.Parameters.AddWithValue("?start", start);
461 cmd.Parameters.AddWithValue("?count", count);
462 446
463 try 447 try
448 {
449 using (MySqlDataReader dbReader = cmd.ExecuteReader())
464 { 450 {
465 using (MySqlDataReader dbReader = cmd.ExecuteReader()) 451 while (dbReader.Read())
466 { 452 {
467 while (dbReader.Read()) 453 AssetMetadata metadata = new AssetMetadata();
468 { 454 metadata.Name = (string)dbReader["Name"];
469 AssetMetadata metadata = new AssetMetadata(); 455 metadata.Description = (string)dbReader["Description"];
470 metadata.Name = (string)dbReader["Name"]; 456 metadata.Type = (sbyte)dbReader["AssetType"];
471 metadata.Description = (string)dbReader["Description"]; 457 metadata.Temporary = Convert.ToBoolean(dbReader["Temporary"]); // Not sure if this is correct.
472 metadata.Type = (sbyte)dbReader["AssetType"]; 458 metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]);
473 metadata.Temporary = Convert.ToBoolean(dbReader["Temporary"]); // Not sure if this is correct. 459 metadata.FullID = DBGuid.FromDB(dbReader["ID"]);
474 metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]); 460 metadata.CreatorID = dbReader["CreatorID"].ToString();
475 metadata.FullID = DBGuid.FromDB(dbReader["ID"]); 461
476 metadata.CreatorID = dbReader["CreatorID"].ToString(); 462 // We'll ignore this for now - it appears unused!
477
478 // We'll ignore this for now - it appears unused!
479// metadata.SHA1 = dbReader["hash"]); 463// metadata.SHA1 = dbReader["hash"]);
480 464
481 UpdateAccessTime(metadata, (int)dbReader["AccessTime"]); 465 UpdateAccessTime(metadata, (int)dbReader["AccessTime"]);
482 466
483 retList.Add(metadata); 467 retList.Add(metadata);
484 }
485 } 468 }
486 } 469 }
487 catch (Exception e) 470 }
488 { 471 catch (Exception e)
489 m_log.Error("[XASSETS DB]: MySql failure fetching asset set" + Environment.NewLine + e.ToString()); 472 {
490 } 473 m_log.Error("[XASSETS DB]: MySql failure fetching asset set" + Environment.NewLine + e.ToString());
491 } 474 }
492 } 475 }
493 476
@@ -498,21 +481,18 @@ namespace OpenSim.Data.MySQL
498 { 481 {
499// m_log.DebugFormat("[XASSETS DB]: Deleting asset {0}", id); 482// m_log.DebugFormat("[XASSETS DB]: Deleting asset {0}", id);
500 483
501 lock (m_dbLock) 484 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
502 { 485 {
503 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) 486 dbcon.Open();
504 {
505 dbcon.Open();
506
507 using (MySqlCommand cmd = new MySqlCommand("delete from XAssetsMeta where ID=?ID", dbcon))
508 {
509 cmd.Parameters.AddWithValue("?ID", id);
510 cmd.ExecuteNonQuery();
511 }
512 487
513 // TODO: How do we deal with data from deleted assets? Probably not easily reapable unless we 488 using (MySqlCommand cmd = new MySqlCommand("delete from XAssetsMeta where ID=?ID", dbcon))
514 // keep a reference count (?) 489 {
490 cmd.Parameters.AddWithValue("?ID", id);
491 cmd.ExecuteNonQuery();
515 } 492 }
493
494 // TODO: How do we deal with data from deleted assets? Probably not easily reapable unless we
495 // keep a reference count (?)
516 } 496 }
517 497
518 return true; 498 return true;