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