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