clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Collections.Generic;
30 using System.Data;
31 using System.Reflection;
32 using log4net;
33 #if CSharpSqlite
34 using Community.CsharpSqlite.Sqlite;
35 #else
36 using Mono.Data.Sqlite;
37 #endif
38 using OpenMetaverse;
39 using OpenSim.Framework;
40  
41 namespace OpenSim.Data.SQLite
42 {
43 /// <summary>
44 /// An Inventory Interface to the SQLite database
45 /// </summary>
46 public class SQLiteInventoryStore : SQLiteUtil, IInventoryDataPlugin
47 {
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49  
50 private const string invItemsSelect = "select * from inventoryitems";
51 private const string invFoldersSelect = "select * from inventoryfolders";
52  
53 private static SqliteConnection conn;
54 private static DataSet ds;
55 private static SqliteDataAdapter invItemsDa;
56 private static SqliteDataAdapter invFoldersDa;
57  
58 private static bool m_Initialized = false;
59  
60 public void Initialise()
61 {
62 m_log.Info("[SQLiteInventoryData]: " + Name + " cannot be default-initialized!");
63 throw new PluginNotInitialisedException(Name);
64 }
65  
66 /// <summary>
67 /// <list type="bullet">
68 /// <item>Initialises Inventory interface</item>
69 /// <item>Loads and initialises a new SQLite connection and maintains it.</item>
70 /// <item>use default URI if connect string string is empty.</item>
71 /// </list>
72 /// </summary>
73 /// <param name="dbconnect">connect string</param>
74 public void Initialise(string dbconnect)
75 {
76 if (!m_Initialized)
77 {
78 m_Initialized = true;
79  
80 if (Util.IsWindows())
81 Util.LoadArchSpecificWindowsDll("sqlite3.dll");
82  
83 if (dbconnect == string.Empty)
84 {
85 dbconnect = "URI=file:inventoryStore.db,version=3";
86 }
87 m_log.Info("[INVENTORY DB]: Sqlite - connecting: " + dbconnect);
88 conn = new SqliteConnection(dbconnect);
89  
90 conn.Open();
91  
92 Assembly assem = GetType().Assembly;
93 Migration m = new Migration(conn, assem, "InventoryStore");
94 m.Update();
95  
96 SqliteCommand itemsSelectCmd = new SqliteCommand(invItemsSelect, conn);
97 invItemsDa = new SqliteDataAdapter(itemsSelectCmd);
98 // SqliteCommandBuilder primCb = new SqliteCommandBuilder(primDa);
99  
100 SqliteCommand foldersSelectCmd = new SqliteCommand(invFoldersSelect, conn);
101 invFoldersDa = new SqliteDataAdapter(foldersSelectCmd);
102  
103 ds = new DataSet();
104  
105 ds.Tables.Add(createInventoryFoldersTable());
106 invFoldersDa.Fill(ds.Tables["inventoryfolders"]);
107 setupFoldersCommands(invFoldersDa, conn);
108 CreateDataSetMapping(invFoldersDa, "inventoryfolders");
109 m_log.Info("[INVENTORY DB]: Populated Inventory Folders Definitions");
110  
111 ds.Tables.Add(createInventoryItemsTable());
112 invItemsDa.Fill(ds.Tables["inventoryitems"]);
113 setupItemsCommands(invItemsDa, conn);
114 CreateDataSetMapping(invItemsDa, "inventoryitems");
115 m_log.Info("[INVENTORY DB]: Populated Inventory Items Definitions");
116  
117 ds.AcceptChanges();
118 }
119 }
120  
121 /// <summary>
122 /// Closes the inventory interface
123 /// </summary>
124 public void Dispose()
125 {
126 if (conn != null)
127 {
128 conn.Close();
129 conn = null;
130 }
131 if (invItemsDa != null)
132 {
133 invItemsDa.Dispose();
134 invItemsDa = null;
135 }
136 if (invFoldersDa != null)
137 {
138 invFoldersDa.Dispose();
139 invFoldersDa = null;
140 }
141 if (ds != null)
142 {
143 ds.Dispose();
144 ds = null;
145 }
146 }
147  
148 /// <summary>
149 ///
150 /// </summary>
151 /// <param name="row"></param>
152 /// <returns></returns>
153 public InventoryItemBase buildItem(DataRow row)
154 {
155 InventoryItemBase item = new InventoryItemBase();
156 item.ID = new UUID((string) row["UUID"]);
157 item.AssetID = new UUID((string) row["assetID"]);
158 item.AssetType = Convert.ToInt32(row["assetType"]);
159 item.InvType = Convert.ToInt32(row["invType"]);
160 item.Folder = new UUID((string) row["parentFolderID"]);
161 item.Owner = new UUID((string) row["avatarID"]);
162 item.CreatorIdentification = (string)row["creatorsID"];
163 item.Name = (string) row["inventoryName"];
164 item.Description = (string) row["inventoryDescription"];
165  
166 item.NextPermissions = Convert.ToUInt32(row["inventoryNextPermissions"]);
167 item.CurrentPermissions = Convert.ToUInt32(row["inventoryCurrentPermissions"]);
168 item.BasePermissions = Convert.ToUInt32(row["inventoryBasePermissions"]);
169 item.EveryOnePermissions = Convert.ToUInt32(row["inventoryEveryOnePermissions"]);
170 item.GroupPermissions = Convert.ToUInt32(row["inventoryGroupPermissions"]);
171  
172 // new fields
173 if (!Convert.IsDBNull(row["salePrice"]))
174 item.SalePrice = Convert.ToInt32(row["salePrice"]);
175  
176 if (!Convert.IsDBNull(row["saleType"]))
177 item.SaleType = Convert.ToByte(row["saleType"]);
178  
179 if (!Convert.IsDBNull(row["creationDate"]))
180 item.CreationDate = Convert.ToInt32(row["creationDate"]);
181  
182 if (!Convert.IsDBNull(row["groupID"]))
183 item.GroupID = new UUID((string)row["groupID"]);
184  
185 if (!Convert.IsDBNull(row["groupOwned"]))
186 item.GroupOwned = Convert.ToBoolean(row["groupOwned"]);
187  
188 if (!Convert.IsDBNull(row["Flags"]))
189 item.Flags = Convert.ToUInt32(row["Flags"]);
190  
191 return item;
192 }
193  
194 /// <summary>
195 /// Fill a database row with item data
196 /// </summary>
197 /// <param name="row"></param>
198 /// <param name="item"></param>
199 private static void fillItemRow(DataRow row, InventoryItemBase item)
200 {
201 row["UUID"] = item.ID.ToString();
202 row["assetID"] = item.AssetID.ToString();
203 row["assetType"] = item.AssetType;
204 row["invType"] = item.InvType;
205 row["parentFolderID"] = item.Folder.ToString();
206 row["avatarID"] = item.Owner.ToString();
207 row["creatorsID"] = item.CreatorIdentification.ToString();
208 row["inventoryName"] = item.Name;
209 row["inventoryDescription"] = item.Description;
210  
211 row["inventoryNextPermissions"] = item.NextPermissions;
212 row["inventoryCurrentPermissions"] = item.CurrentPermissions;
213 row["inventoryBasePermissions"] = item.BasePermissions;
214 row["inventoryEveryOnePermissions"] = item.EveryOnePermissions;
215 row["inventoryGroupPermissions"] = item.GroupPermissions;
216  
217 // new fields
218 row["salePrice"] = item.SalePrice;
219 row["saleType"] = item.SaleType;
220 row["creationDate"] = item.CreationDate;
221 row["groupID"] = item.GroupID.ToString();
222 row["groupOwned"] = item.GroupOwned;
223 row["flags"] = item.Flags;
224 }
225  
226 /// <summary>
227 /// Add inventory folder
228 /// </summary>
229 /// <param name="folder">Folder base</param>
230 /// <param name="add">true=create folder. false=update existing folder</param>
231 /// <remarks>nasty</remarks>
232 private void addFolder(InventoryFolderBase folder, bool add)
233 {
234 lock (ds)
235 {
236 DataTable inventoryFolderTable = ds.Tables["inventoryfolders"];
237  
238 DataRow inventoryRow = inventoryFolderTable.Rows.Find(folder.ID.ToString());
239 if (inventoryRow == null)
240 {
241 if (! add)
242 m_log.ErrorFormat("Interface Misuse: Attempting to Update non-existent inventory folder: {0}", folder.ID);
243  
244 inventoryRow = inventoryFolderTable.NewRow();
245 fillFolderRow(inventoryRow, folder);
246 inventoryFolderTable.Rows.Add(inventoryRow);
247 }
248 else
249 {
250 if (add)
251 m_log.ErrorFormat("Interface Misuse: Attempting to Add inventory folder that already exists: {0}", folder.ID);
252  
253 fillFolderRow(inventoryRow, folder);
254 }
255  
256 invFoldersDa.Update(ds, "inventoryfolders");
257 }
258 }
259  
260 /// <summary>
261 /// Move an inventory folder
262 /// </summary>
263 /// <param name="folder">folder base</param>
264 private void moveFolder(InventoryFolderBase folder)
265 {
266 lock (ds)
267 {
268 DataTable inventoryFolderTable = ds.Tables["inventoryfolders"];
269  
270 DataRow inventoryRow = inventoryFolderTable.Rows.Find(folder.ID.ToString());
271 if (inventoryRow == null)
272 {
273 inventoryRow = inventoryFolderTable.NewRow();
274 fillFolderRow(inventoryRow, folder);
275 inventoryFolderTable.Rows.Add(inventoryRow);
276 }
277 else
278 {
279 moveFolderRow(inventoryRow, folder);
280 }
281  
282 invFoldersDa.Update(ds, "inventoryfolders");
283 }
284 }
285  
286 /// <summary>
287 /// add an item in inventory
288 /// </summary>
289 /// <param name="item">the item</param>
290 /// <param name="add">true=add item ; false=update existing item</param>
291 private void addItem(InventoryItemBase item, bool add)
292 {
293 lock (ds)
294 {
295 DataTable inventoryItemTable = ds.Tables["inventoryitems"];
296  
297 DataRow inventoryRow = inventoryItemTable.Rows.Find(item.ID.ToString());
298 if (inventoryRow == null)
299 {
300 if (!add)
301 m_log.ErrorFormat("[INVENTORY DB]: Interface Misuse: Attempting to Update non-existent inventory item: {0}", item.ID);
302  
303 inventoryRow = inventoryItemTable.NewRow();
304 fillItemRow(inventoryRow, item);
305 inventoryItemTable.Rows.Add(inventoryRow);
306 }
307 else
308 {
309 if (add)
310 m_log.ErrorFormat("[INVENTORY DB]: Interface Misuse: Attempting to Add inventory item that already exists: {0}", item.ID);
311  
312 fillItemRow(inventoryRow, item);
313 }
314  
315 invItemsDa.Update(ds, "inventoryitems");
316  
317 DataTable inventoryFolderTable = ds.Tables["inventoryfolders"];
318  
319 inventoryRow = inventoryFolderTable.Rows.Find(item.Folder.ToString());
320 if (inventoryRow != null) //MySQL doesn't throw an exception here, so sqlite shouldn't either.
321 inventoryRow["version"] = (int)inventoryRow["version"] + 1;
322  
323 invFoldersDa.Update(ds, "inventoryfolders");
324 }
325 }
326  
327 /// <summary>
328 /// TODO : DataSet commit
329 /// </summary>
330 public void Shutdown()
331 {
332 // TODO: DataSet commit
333 }
334  
335 /// <summary>
336 /// The name of this DB provider
337 /// </summary>
338 /// <returns>Name of DB provider</returns>
339 public string Name
340 {
341 get { return "SQLite Inventory Data Interface"; }
342 }
343  
344 /// <summary>
345 /// Returns the version of this DB provider
346 /// </summary>
347 /// <returns>A string containing the DB provider version</returns>
348 public string Version
349 {
350 get
351 {
352 Module module = GetType().Module;
353 // string dllName = module.Assembly.ManifestModule.Name;
354 Version dllVersion = module.Assembly.GetName().Version;
355  
356  
357 return
358 string.Format("{0}.{1}.{2}.{3}", dllVersion.Major, dllVersion.Minor, dllVersion.Build,
359 dllVersion.Revision);
360 }
361 }
362  
363 /// <summary>
364 /// Returns a list of inventory items contained within the specified folder
365 /// </summary>
366 /// <param name="folderID">The UUID of the target folder</param>
367 /// <returns>A List of InventoryItemBase items</returns>
368 public List<InventoryItemBase> getInventoryInFolder(UUID folderID)
369 {
370 lock (ds)
371 {
372 List<InventoryItemBase> retval = new List<InventoryItemBase>();
373 DataTable inventoryItemTable = ds.Tables["inventoryitems"];
374 string selectExp = "parentFolderID = '" + folderID + "'";
375 DataRow[] rows = inventoryItemTable.Select(selectExp);
376 foreach (DataRow row in rows)
377 {
378 retval.Add(buildItem(row));
379 }
380  
381 return retval;
382 }
383 }
384  
385 /// <summary>
386 /// Returns a list of the root folders within a users inventory
387 /// </summary>
388 /// <param name="user">The user whos inventory is to be searched</param>
389 /// <returns>A list of folder objects</returns>
390 public List<InventoryFolderBase> getUserRootFolders(UUID user)
391 {
392 return new List<InventoryFolderBase>();
393 }
394  
395 // see InventoryItemBase.getUserRootFolder
396 public InventoryFolderBase getUserRootFolder(UUID user)
397 {
398 lock (ds)
399 {
400 List<InventoryFolderBase> folders = new List<InventoryFolderBase>();
401 DataTable inventoryFolderTable = ds.Tables["inventoryfolders"];
402 string selectExp = "agentID = '" + user + "' AND parentID = '" + UUID.Zero + "'";
403 DataRow[] rows = inventoryFolderTable.Select(selectExp);
404 foreach (DataRow row in rows)
405 {
406 folders.Add(buildFolder(row));
407 }
408  
409 // There should only ever be one root folder for a user. However, if there's more
410 // than one we'll simply use the first one rather than failing. It would be even
411 // nicer to print some message to this effect, but this feels like it's too low a
412 // to put such a message out, and it's too minor right now to spare the time to
413 // suitably refactor.
414 if (folders.Count > 0)
415 {
416 return folders[0];
417 }
418  
419 return null;
420 }
421 }
422  
423 /// <summary>
424 /// Append a list of all the child folders of a parent folder
425 /// </summary>
426 /// <param name="folders">list where folders will be appended</param>
427 /// <param name="parentID">ID of parent</param>
428 protected void getInventoryFolders(ref List<InventoryFolderBase> folders, UUID parentID)
429 {
430 lock (ds)
431 {
432 DataTable inventoryFolderTable = ds.Tables["inventoryfolders"];
433 string selectExp = "parentID = '" + parentID + "'";
434 DataRow[] rows = inventoryFolderTable.Select(selectExp);
435 foreach (DataRow row in rows)
436 {
437 folders.Add(buildFolder(row));
438 }
439  
440 }
441 }
442  
443 /// <summary>
444 /// Returns a list of inventory folders contained in the folder 'parentID'
445 /// </summary>
446 /// <param name="parentID">The folder to get subfolders for</param>
447 /// <returns>A list of inventory folders</returns>
448 public List<InventoryFolderBase> getInventoryFolders(UUID parentID)
449 {
450 List<InventoryFolderBase> folders = new List<InventoryFolderBase>();
451 getInventoryFolders(ref folders, parentID);
452 return folders;
453 }
454  
455 /// <summary>
456 /// See IInventoryDataPlugin
457 /// </summary>
458 /// <param name="parentID"></param>
459 /// <returns></returns>
460 public List<InventoryFolderBase> getFolderHierarchy(UUID parentID)
461 {
462 /* Note: There are subtle changes between this implementation of getFolderHierarchy and the previous one
463 * - We will only need to hit the database twice instead of n times.
464 * - We assume the database is well-formed - no stranded/dangling folders, all folders in heirarchy owned
465 * by the same person, each user only has 1 inventory heirarchy
466 * - The returned list is not ordered, instead of breadth-first ordered
467 There are basically 2 usage cases for getFolderHeirarchy:
468 1) Getting the user's entire inventory heirarchy when they log in
469 2) Finding a subfolder heirarchy to delete when emptying the trash.
470 This implementation will pull all inventory folders from the database, and then prune away any folder that
471 is not part of the requested sub-heirarchy. The theory is that it is cheaper to make 1 request from the
472 database than to make n requests. This pays off only if requested heirarchy is large.
473 By making this choice, we are making the worst case better at the cost of making the best case worse
474 - Francis
475 */
476  
477 List<InventoryFolderBase> folders = new List<InventoryFolderBase>();
478 DataRow[] folderRows = null, parentRow;
479 InventoryFolderBase parentFolder = null;
480 lock (ds)
481 {
482 /* Fetch the parent folder from the database to determine the agent ID.
483 * Then fetch all inventory folders for that agent from the agent ID.
484 */
485 DataTable inventoryFolderTable = ds.Tables["inventoryfolders"];
486 string selectExp = "UUID = '" + parentID + "'";
487 parentRow = inventoryFolderTable.Select(selectExp); // Assume at most 1 result
488 if (parentRow.GetLength(0) >= 1) // No result means parent folder does not exist
489 {
490 parentFolder = buildFolder(parentRow[0]);
491 UUID agentID = parentFolder.Owner;
492 selectExp = "agentID = '" + agentID + "'";
493 folderRows = inventoryFolderTable.Select(selectExp);
494 }
495  
496 if (folderRows != null && folderRows.GetLength(0) >= 1) // No result means parent folder does not exist
497 { // or has no children
498 /* if we're querying the root folder, just return an unordered list of all folders in the user's
499 * inventory
500 */
501 if (parentFolder.ParentID == UUID.Zero)
502 {
503 foreach (DataRow row in folderRows)
504 {
505 InventoryFolderBase curFolder = buildFolder(row);
506 if (curFolder.ID != parentID) // Return all folders except the parent folder of heirarchy
507 folders.Add(buildFolder(row));
508 }
509 } // If requesting root folder
510 /* else we are querying a non-root folder. We currently have a list of all of the user's folders,
511 * we must construct a list of all folders in the heirarchy below parentID.
512 * Our first step will be to construct a hash table of all folders, indexed by parent ID.
513 * Once we have constructed the hash table, we will do a breadth-first traversal on the tree using the
514 * hash table to find child folders.
515 */
516 else
517 { // Querying a non-root folder
518  
519 // Build a hash table of all user's inventory folders, indexed by each folder's parent ID
520 Dictionary<UUID, List<InventoryFolderBase>> hashtable =
521 new Dictionary<UUID, List<InventoryFolderBase>>(folderRows.GetLength(0));
522  
523 foreach (DataRow row in folderRows)
524 {
525 InventoryFolderBase curFolder = buildFolder(row);
526 if (curFolder.ParentID != UUID.Zero) // Discard root of tree - not needed
527 {
528 if (hashtable.ContainsKey(curFolder.ParentID))
529 {
530 // Current folder already has a sibling - append to sibling list
531 hashtable[curFolder.ParentID].Add(curFolder);
532 }
533 else
534 {
535 List<InventoryFolderBase> siblingList = new List<InventoryFolderBase>();
536 siblingList.Add(curFolder);
537 // Current folder has no known (yet) siblings
538 hashtable.Add(curFolder.ParentID, siblingList);
539 }
540 }
541 } // For all inventory folders
542  
543 // Note: Could release the ds lock here - we don't access folderRows or the database anymore.
544 // This is somewhat of a moot point as the callers of this function usually lock db anyways.
545  
546 if (hashtable.ContainsKey(parentID)) // if requested folder does have children
547 folders.AddRange(hashtable[parentID]);
548  
549 // BreadthFirstSearch build inventory tree **Note: folders.Count is *not* static
550 for (int i = 0; i < folders.Count; i++)
551 if (hashtable.ContainsKey(folders[i].ID))
552 folders.AddRange(hashtable[folders[i].ID]);
553  
554 } // if requesting a subfolder heirarchy
555 } // if folder parentID exists and has children
556 } // lock ds
557 return folders;
558 }
559  
560 /// <summary>
561 /// Returns an inventory item by its UUID
562 /// </summary>
563 /// <param name="item">The UUID of the item to be returned</param>
564 /// <returns>A class containing item information</returns>
565 public InventoryItemBase getInventoryItem(UUID item)
566 {
567 lock (ds)
568 {
569 DataRow row = ds.Tables["inventoryitems"].Rows.Find(item.ToString());
570 if (row != null)
571 {
572 return buildItem(row);
573 }
574 else
575 {
576 return null;
577 }
578 }
579 }
580  
581 /// <summary>
582 /// Returns a specified inventory folder by its UUID
583 /// </summary>
584 /// <param name="folder">The UUID of the folder to be returned</param>
585 /// <returns>A class containing folder information</returns>
586 public InventoryFolderBase getInventoryFolder(UUID folder)
587 {
588 // TODO: Deep voodoo here. If you enable this code then
589 // multi region breaks. No idea why, but I figured it was
590 // better to leave multi region at this point. It does mean
591 // that you don't get to see system textures why creating
592 // clothes and the like. :(
593 lock (ds)
594 {
595 DataRow row = ds.Tables["inventoryfolders"].Rows.Find(folder.ToString());
596 if (row != null)
597 {
598 return buildFolder(row);
599 }
600 else
601 {
602 return null;
603 }
604 }
605 }
606  
607 /// <summary>
608 /// Creates a new inventory item based on item
609 /// </summary>
610 /// <param name="item">The item to be created</param>
611 public void addInventoryItem(InventoryItemBase item)
612 {
613 addItem(item, true);
614 }
615  
616 /// <summary>
617 /// Updates an inventory item with item (updates based on ID)
618 /// </summary>
619 /// <param name="item">The updated item</param>
620 public void updateInventoryItem(InventoryItemBase item)
621 {
622 addItem(item, false);
623 }
624  
625 /// <summary>
626 /// Delete an inventory item
627 /// </summary>
628 /// <param name="item">The item UUID</param>
629 public void deleteInventoryItem(UUID itemID)
630 {
631 lock (ds)
632 {
633 DataTable inventoryItemTable = ds.Tables["inventoryitems"];
634  
635 DataRow inventoryRow = inventoryItemTable.Rows.Find(itemID.ToString());
636 if (inventoryRow != null)
637 {
638 inventoryRow.Delete();
639 }
640  
641 invItemsDa.Update(ds, "inventoryitems");
642 }
643 }
644  
645 public InventoryItemBase queryInventoryItem(UUID itemID)
646 {
647 return getInventoryItem(itemID);
648 }
649  
650 public InventoryFolderBase queryInventoryFolder(UUID folderID)
651 {
652 return getInventoryFolder(folderID);
653 }
654  
655 /// <summary>
656 /// Delete all items in the specified folder
657 /// </summary>
658 /// <param name="folderId">id of the folder, whose item content should be deleted</param>
659 /// <todo>this is horribly inefficient, but I don't want to ruin the overall structure of this implementation</todo>
660 private void deleteItemsInFolder(UUID folderId)
661 {
662 List<InventoryItemBase> items = getInventoryInFolder(folderId);
663  
664 foreach (InventoryItemBase i in items)
665 deleteInventoryItem(i.ID);
666 }
667  
668 /// <summary>
669 /// Adds a new folder specified by folder
670 /// </summary>
671 /// <param name="folder">The inventory folder</param>
672 public void addInventoryFolder(InventoryFolderBase folder)
673 {
674 addFolder(folder, true);
675 }
676  
677 /// <summary>
678 /// Updates a folder based on its ID with folder
679 /// </summary>
680 /// <param name="folder">The inventory folder</param>
681 public void updateInventoryFolder(InventoryFolderBase folder)
682 {
683 addFolder(folder, false);
684 }
685  
686 /// <summary>
687 /// Moves a folder based on its ID with folder
688 /// </summary>
689 /// <param name="folder">The inventory folder</param>
690 public void moveInventoryFolder(InventoryFolderBase folder)
691 {
692 moveFolder(folder);
693 }
694  
695 /// <summary>
696 /// Delete a folder
697 /// </summary>
698 /// <remarks>
699 /// This will clean-up any child folders and child items as well
700 /// </remarks>
701 /// <param name="folderID">the folder UUID</param>
702 public void deleteInventoryFolder(UUID folderID)
703 {
704 lock (ds)
705 {
706 List<InventoryFolderBase> subFolders = getFolderHierarchy(folderID);
707  
708 DataTable inventoryFolderTable = ds.Tables["inventoryfolders"];
709 DataRow inventoryRow;
710  
711 //Delete all sub-folders
712 foreach (InventoryFolderBase f in subFolders)
713 {
714 inventoryRow = inventoryFolderTable.Rows.Find(f.ID.ToString());
715 if (inventoryRow != null)
716 {
717 deleteItemsInFolder(f.ID);
718 inventoryRow.Delete();
719 }
720 }
721  
722 //Delete the actual row
723 inventoryRow = inventoryFolderTable.Rows.Find(folderID.ToString());
724 if (inventoryRow != null)
725 {
726 deleteItemsInFolder(folderID);
727 inventoryRow.Delete();
728 }
729  
730 invFoldersDa.Update(ds, "inventoryfolders");
731 }
732 }
733  
734 /***********************************************************************
735 *
736 * Data Table definitions
737 *
738 **********************************************************************/
739  
740 protected void CreateDataSetMapping(IDataAdapter da, string tableName)
741 {
742 ITableMapping dbMapping = da.TableMappings.Add(tableName, tableName);
743 foreach (DataColumn col in ds.Tables[tableName].Columns)
744 {
745 dbMapping.ColumnMappings.Add(col.ColumnName, col.ColumnName);
746 }
747 }
748  
749 /// <summary>
750 /// Create the "inventoryitems" table
751 /// </summary>
752 private static DataTable createInventoryItemsTable()
753 {
754 DataTable inv = new DataTable("inventoryitems");
755  
756 createCol(inv, "UUID", typeof (String)); //inventoryID
757 createCol(inv, "assetID", typeof (String));
758 createCol(inv, "assetType", typeof (Int32));
759 createCol(inv, "invType", typeof (Int32));
760 createCol(inv, "parentFolderID", typeof (String));
761 createCol(inv, "avatarID", typeof (String));
762 createCol(inv, "creatorsID", typeof (String));
763  
764 createCol(inv, "inventoryName", typeof (String));
765 createCol(inv, "inventoryDescription", typeof (String));
766 // permissions
767 createCol(inv, "inventoryNextPermissions", typeof (Int32));
768 createCol(inv, "inventoryCurrentPermissions", typeof (Int32));
769 createCol(inv, "inventoryBasePermissions", typeof (Int32));
770 createCol(inv, "inventoryEveryOnePermissions", typeof (Int32));
771 createCol(inv, "inventoryGroupPermissions", typeof (Int32));
772  
773 // sale info
774 createCol(inv, "salePrice", typeof(Int32));
775 createCol(inv, "saleType", typeof(Byte));
776  
777 // creation date
778 createCol(inv, "creationDate", typeof(Int32));
779  
780 // group info
781 createCol(inv, "groupID", typeof(String));
782 createCol(inv, "groupOwned", typeof(Boolean));
783  
784 // Flags
785 createCol(inv, "flags", typeof(UInt32));
786  
787 inv.PrimaryKey = new DataColumn[] { inv.Columns["UUID"] };
788 return inv;
789 }
790  
791 /// <summary>
792 /// Creates the "inventoryfolders" table
793 /// </summary>
794 /// <returns></returns>
795 private static DataTable createInventoryFoldersTable()
796 {
797 DataTable fol = new DataTable("inventoryfolders");
798  
799 createCol(fol, "UUID", typeof (String)); //folderID
800 createCol(fol, "name", typeof (String));
801 createCol(fol, "agentID", typeof (String));
802 createCol(fol, "parentID", typeof (String));
803 createCol(fol, "type", typeof (Int32));
804 createCol(fol, "version", typeof (Int32));
805  
806 fol.PrimaryKey = new DataColumn[] {fol.Columns["UUID"]};
807 return fol;
808 }
809  
810 /// <summary>
811 ///
812 /// </summary>
813 /// <param name="da"></param>
814 /// <param name="conn"></param>
815 private void setupItemsCommands(SqliteDataAdapter da, SqliteConnection conn)
816 {
817 lock (ds)
818 {
819 da.InsertCommand = createInsertCommand("inventoryitems", ds.Tables["inventoryitems"]);
820 da.InsertCommand.Connection = conn;
821  
822 da.UpdateCommand = createUpdateCommand("inventoryitems", "UUID=:UUID", ds.Tables["inventoryitems"]);
823 da.UpdateCommand.Connection = conn;
824  
825 SqliteCommand delete = new SqliteCommand("delete from inventoryitems where UUID = :UUID");
826 delete.Parameters.Add(createSqliteParameter("UUID", typeof(String)));
827 delete.Connection = conn;
828 da.DeleteCommand = delete;
829 }
830 }
831  
832 /// <summary>
833 ///
834 /// </summary>
835 /// <param name="da"></param>
836 /// <param name="conn"></param>
837 private void setupFoldersCommands(SqliteDataAdapter da, SqliteConnection conn)
838 {
839 lock (ds)
840 {
841 da.InsertCommand = createInsertCommand("inventoryfolders", ds.Tables["inventoryfolders"]);
842 da.InsertCommand.Connection = conn;
843  
844 da.UpdateCommand = createUpdateCommand("inventoryfolders", "UUID=:UUID", ds.Tables["inventoryfolders"]);
845 da.UpdateCommand.Connection = conn;
846  
847 SqliteCommand delete = new SqliteCommand("delete from inventoryfolders where UUID = :UUID");
848 delete.Parameters.Add(createSqliteParameter("UUID", typeof(String)));
849 delete.Connection = conn;
850 da.DeleteCommand = delete;
851 }
852 }
853  
854 /// <summary>
855 ///
856 /// </summary>
857 /// <param name="row"></param>
858 /// <returns></returns>
859 private static InventoryFolderBase buildFolder(DataRow row)
860 {
861 InventoryFolderBase folder = new InventoryFolderBase();
862 folder.ID = new UUID((string) row["UUID"]);
863 folder.Name = (string) row["name"];
864 folder.Owner = new UUID((string) row["agentID"]);
865 folder.ParentID = new UUID((string) row["parentID"]);
866 folder.Type = Convert.ToInt16(row["type"]);
867 folder.Version = Convert.ToUInt16(row["version"]);
868 return folder;
869 }
870  
871 /// <summary>
872 ///
873 /// </summary>
874 /// <param name="row"></param>
875 /// <param name="folder"></param>
876 private static void fillFolderRow(DataRow row, InventoryFolderBase folder)
877 {
878 row["UUID"] = folder.ID.ToString();
879 row["name"] = folder.Name;
880 row["agentID"] = folder.Owner.ToString();
881 row["parentID"] = folder.ParentID.ToString();
882 row["type"] = folder.Type;
883 row["version"] = folder.Version;
884 }
885  
886 /// <summary>
887 ///
888 /// </summary>
889 /// <param name="row"></param>
890 /// <param name="folder"></param>
891 private static void moveFolderRow(DataRow row, InventoryFolderBase folder)
892 {
893 row["UUID"] = folder.ID.ToString();
894 row["parentID"] = folder.ParentID.ToString();
895 }
896  
897 public List<InventoryItemBase> fetchActiveGestures (UUID avatarID)
898 {
899 lock (ds)
900 {
901 List<InventoryItemBase> items = new List<InventoryItemBase>();
902  
903 DataTable inventoryItemTable = ds.Tables["inventoryitems"];
904 string selectExp
905 = "avatarID = '" + avatarID + "' AND assetType = " + (int)AssetType.Gesture + " AND flags = 1";
906 //m_log.DebugFormat("[SQL]: sql = " + selectExp);
907 DataRow[] rows = inventoryItemTable.Select(selectExp);
908 foreach (DataRow row in rows)
909 {
910 items.Add(buildItem(row));
911 }
912 return items;
913 }
914 }
915 }
916 }