aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Data/MSSQL/MSSQLRegionData.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Data/MSSQL/MSSQLRegionData.cs')
-rw-r--r--OpenSim/Data/MSSQL/MSSQLRegionData.cs1840
1 files changed, 1840 insertions, 0 deletions
diff --git a/OpenSim/Data/MSSQL/MSSQLRegionData.cs b/OpenSim/Data/MSSQL/MSSQLRegionData.cs
new file mode 100644
index 0000000..3f85fef
--- /dev/null
+++ b/OpenSim/Data/MSSQL/MSSQLRegionData.cs
@@ -0,0 +1,1840 @@
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 OpenSim 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.Data.SqlClient;
32using System.IO;
33using System.Reflection;
34using libsecondlife;
35using log4net;
36using OpenSim.Framework;
37using OpenSim.Region.Environment.Interfaces;
38using OpenSim.Region.Environment.Scenes;
39
40namespace OpenSim.Data.MSSQL
41{
42 /// <summary>
43 /// A MSSQL Interface for the Region Server.
44 /// </summary>
45 public class MSSQLDataStore : IRegionDataStore
46 {
47 // private static FileSystemDataStore Instance = new FileSystemDataStore();
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50 private const string m_primSelect = "select * from prims";
51 private const string m_shapeSelect = "select * from primshapes";
52 private const string m_itemsSelect = "select * from primitems";
53 private const string m_terrainSelect = "select top 1 * from terrain";
54 private const string m_landSelect = "select * from land";
55 private const string m_landAccessListSelect = "select * from landaccesslist";
56
57 private DataSet m_dataSet;
58 private SqlDataAdapter m_primDataAdapter;
59 private SqlDataAdapter m_shapeDataAdapter;
60 private SqlDataAdapter m_itemsDataAdapter;
61 private SqlConnection m_connection;
62 private SqlDataAdapter m_terrainDataAdapter;
63 private SqlDataAdapter m_landDataAdapter;
64 private SqlDataAdapter m_landAccessListDataAdapter;
65
66 private DataTable m_primTable;
67 private DataTable m_shapeTable;
68 private DataTable m_itemsTable;
69 private DataTable m_terrainTable;
70 private DataTable m_landTable;
71 private DataTable m_landAccessListTable;
72
73 /// <summary>Temporary attribute while this is experimental</summary>
74
75 /***********************************************************************
76 *
77 * Public Interface Functions
78 *
79 **********************************************************************/
80
81 /// <summary>
82 /// see IRegionDataStore
83 /// </summary>
84 /// <param name="connectionString"></param>
85 public void Initialise(string connectionString)
86 {
87 // Instance.Initialise("", true);
88
89 m_dataSet = new DataSet();
90
91 m_log.Info("[REGION DB]: MSSql - connecting: " + connectionString);
92 m_connection = new SqlConnection(connectionString);
93
94 SqlCommand primSelectCmd = new SqlCommand(m_primSelect, m_connection);
95 m_primDataAdapter = new SqlDataAdapter(primSelectCmd);
96
97 SqlCommand shapeSelectCmd = new SqlCommand(m_shapeSelect, m_connection);
98 m_shapeDataAdapter = new SqlDataAdapter(shapeSelectCmd);
99
100 SqlCommand itemsSelectCmd = new SqlCommand(m_itemsSelect, m_connection);
101 m_itemsDataAdapter = new SqlDataAdapter(itemsSelectCmd);
102
103 SqlCommand terrainSelectCmd = new SqlCommand(m_terrainSelect, m_connection);
104 m_terrainDataAdapter = new SqlDataAdapter(terrainSelectCmd);
105
106 SqlCommand landSelectCmd = new SqlCommand(m_landSelect, m_connection);
107 m_landDataAdapter = new SqlDataAdapter(landSelectCmd);
108
109 SqlCommand landAccessListSelectCmd = new SqlCommand(m_landAccessListSelect, m_connection);
110 m_landAccessListDataAdapter = new SqlDataAdapter(landAccessListSelectCmd);
111
112 TestTables(m_connection);
113
114 lock (m_dataSet)
115 {
116 m_primTable = createPrimTable();
117 m_dataSet.Tables.Add(m_primTable);
118 setupPrimCommands(m_primDataAdapter, m_connection);
119 m_primDataAdapter.Fill(m_primTable);
120
121 m_shapeTable = createShapeTable();
122 m_dataSet.Tables.Add(m_shapeTable);
123 setupShapeCommands(m_shapeDataAdapter, m_connection);
124 m_shapeDataAdapter.Fill(m_shapeTable);
125
126 m_itemsTable = createItemsTable();
127 m_dataSet.Tables.Add(m_itemsTable);
128 SetupItemsCommands(m_itemsDataAdapter, m_connection);
129 m_itemsDataAdapter.Fill(m_itemsTable);
130
131 m_terrainTable = createTerrainTable();
132 m_dataSet.Tables.Add(m_terrainTable);
133 setupTerrainCommands(m_terrainDataAdapter, m_connection);
134 m_terrainDataAdapter.Fill(m_terrainTable);
135
136 m_landTable = createLandTable();
137 m_dataSet.Tables.Add(m_landTable);
138 setupLandCommands(m_landDataAdapter, m_connection);
139 m_landDataAdapter.Fill(m_landTable);
140
141 m_landAccessListTable = createLandAccessListTable();
142 m_dataSet.Tables.Add(m_landAccessListTable);
143 setupLandAccessCommands(m_landAccessListDataAdapter, m_connection);
144 m_landAccessListDataAdapter.Fill(m_landAccessListTable);
145 }
146 }
147
148 public void StoreRegionSettings(RegionSettings rs)
149 {
150 }
151
152 public RegionSettings LoadRegionSettings(LLUUID regionUUID)
153 {
154 return null;
155 }
156
157 /// <summary>
158 ///
159 /// </summary>
160 /// <param name="obj"></param>
161 /// <param name="regionUUID"></param>
162 public void StoreObject(SceneObjectGroup obj, LLUUID regionUUID)
163 {
164 // Instance.StoreObject(obj, regionUUID);
165
166 lock (m_dataSet)
167 {
168 foreach (SceneObjectPart prim in obj.Children.Values)
169 {
170 if ((prim.GetEffectiveObjectFlags() & (uint)LLObject.ObjectFlags.Physics) == 0
171 && (prim.GetEffectiveObjectFlags() & (uint)LLObject.ObjectFlags.Temporary) == 0
172 && (prim.GetEffectiveObjectFlags() & (uint)LLObject.ObjectFlags.TemporaryOnRez) == 0)
173 {
174 //m_log.Info("[REGION DB]: Adding obj: " + obj.UUID + " to region: " + regionUUID);
175 addPrim(prim, obj.UUID, regionUUID);
176 }
177 else
178 {
179 // m_log.Info("[DATASTORE]: Ignoring Physical obj: " + obj.UUID + " in region: " + regionUUID);
180 }
181 }
182 }
183
184 Commit();
185 }
186
187 /// <summary>
188 ///
189 /// </summary>
190 /// <param name="obj"></param>
191 /// <param name="regionUUID"></param>
192 public void RemoveObject(LLUUID obj, LLUUID regionUUID)
193 {
194 // Instance.RemoveObject(obj, regionUUID);
195
196 m_log.InfoFormat("[REGION DB]: Removing obj: {0} from region: {1}", obj.UUID, regionUUID);
197
198 DataTable prims = m_primTable;
199 DataTable shapes = m_shapeTable;
200
201 string selectExp = "SceneGroupID = '" + obj.ToString() + "'";
202 lock (m_dataSet)
203 {
204 foreach (DataRow row in prims.Select(selectExp))
205 {
206 // Remove shapes row
207 LLUUID uuid = new LLUUID((string)row["UUID"]);
208
209 DataRow shapeRow = shapes.Rows.Find(uuid.UUID);
210 if (shapeRow != null)
211 {
212 shapeRow.Delete();
213 }
214
215 RemoveItems(new LLUUID((string)row["UUID"]));
216
217 // Remove prim row
218 row.Delete();
219 }
220 }
221
222 Commit();
223 }
224
225 /// <summary>
226 /// Remove all persisted items of the given prim.
227 /// The caller must acquire the necessrary synchronization locks and commit or rollback changes.
228 /// </summary>
229 /// <param name="uuid">The item UUID</param>
230 private void RemoveItems(LLUUID uuid)
231 {
232 String sql = String.Format("primID = '{0}'", uuid);
233 DataRow[] itemRows = m_itemsTable.Select(sql);
234
235 foreach (DataRow itemRow in itemRows)
236 {
237 itemRow.Delete();
238 }
239 }
240
241 /// <summary>
242 /// Load persisted objects from region storage.
243 /// </summary>
244 /// <param name="regionUUID">The region UUID</param>
245 public List<SceneObjectGroup> LoadObjects(LLUUID regionUUID)
246 {
247 // return Instance.LoadObjects(regionUUID);
248
249 Dictionary<LLUUID, SceneObjectGroup> createdObjects = new Dictionary<LLUUID, SceneObjectGroup>();
250
251 List<SceneObjectGroup> retvals = new List<SceneObjectGroup>();
252
253 DataTable prims = m_primTable;
254 DataTable shapes = m_shapeTable;
255
256 string byRegion = "RegionUUID = '" + regionUUID.ToString() + "'";
257 string orderByParent = "ParentID ASC";
258
259 lock (m_dataSet)
260 {
261 DataRow[] primsForRegion = prims.Select(byRegion, orderByParent);
262 m_log.Info("[REGION DB]: " +
263 "Loaded " + primsForRegion.Length + " prims for region: " + regionUUID);
264
265 foreach (DataRow primRow in primsForRegion)
266 {
267 try
268 {
269 string uuid = (string)primRow["UUID"];
270 string objID = (string)primRow["SceneGroupID"];
271
272 SceneObjectPart prim = buildPrim(primRow);
273
274 if (uuid == objID) //is new SceneObjectGroup ?
275 {
276 SceneObjectGroup group = new SceneObjectGroup();
277
278 DataRow shapeRow = shapes.Rows.Find(prim.UUID);
279 if (shapeRow != null)
280 {
281 prim.Shape = buildShape(shapeRow);
282 }
283 else
284 {
285 m_log.Info(
286 "No shape found for prim in storage, so setting default box shape");
287 prim.Shape = PrimitiveBaseShape.Default;
288 }
289 group.AddPart(prim);
290 group.RootPart = prim;
291
292 createdObjects.Add(group.UUID, group);
293 retvals.Add(group);
294 }
295 else
296 {
297 DataRow shapeRow = shapes.Rows.Find(prim.UUID);
298 if (shapeRow != null)
299 {
300 prim.Shape = buildShape(shapeRow);
301 }
302 else
303 {
304 m_log.Info(
305 "No shape found for prim in storage, so setting default box shape");
306 prim.Shape = PrimitiveBaseShape.Default;
307 }
308 createdObjects[new LLUUID(objID)].AddPart(prim);
309 }
310
311 LoadItems(prim);
312 }
313 catch (Exception e)
314 {
315 m_log.Error("[DATASTORE]: Failed create prim object, exception and data follows");
316 m_log.Info("[DATASTORE]: " + e.ToString());
317 foreach (DataColumn col in prims.Columns)
318 {
319 m_log.Info("[DATASTORE]: Col: " + col.ColumnName + " => " + primRow[col]);
320 }
321 }
322 }
323 }
324 return retvals;
325 }
326
327 /// <summary>
328 /// Load in a prim's persisted inventory.
329 /// </summary>
330 /// <param name="prim"></param>
331 private void LoadItems(SceneObjectPart prim)
332 {
333 //m_log.InfoFormat("[DATASTORE]: Loading inventory for {0}, {1}", prim.Name, prim.UUID);
334
335 DataTable dbItems = m_itemsTable;
336
337 String sql = String.Format("primID = '{0}'", prim.UUID.ToString());
338 DataRow[] dbItemRows = dbItems.Select(sql);
339
340 IList<TaskInventoryItem> inventory = new List<TaskInventoryItem>();
341
342 foreach (DataRow row in dbItemRows)
343 {
344 TaskInventoryItem item = buildItem(row);
345 inventory.Add(item);
346
347 //m_log.DebugFormat("[DATASTORE]: Restored item {0}, {1}", item.Name, item.ItemID);
348 }
349
350 prim.RestoreInventoryItems(inventory);
351
352 // XXX A nasty little hack to recover the folder id for the prim (which is currently stored in
353 // every item). This data should really be stored in the prim table itself.
354 if (dbItemRows.Length > 0)
355 {
356 prim.FolderID = inventory[0].ParentID;
357 }
358 }
359
360 /// <summary>
361 /// Store a terrain revision in region storage.
362 /// </summary>
363 /// <param name="ter">HeightField data</param>
364 /// <param name="regionID">Region UUID</param>
365 public void StoreTerrain(double[,] ter, LLUUID regionID)
366 {
367 int revision = Util.UnixTimeSinceEpoch();
368 m_log.Info("[REGION DB]: Storing terrain revision r" + revision.ToString());
369
370 // DataTable terrain = m_dataSet.Tables["terrain"];
371 lock (m_dataSet)
372 {
373 SqlCommand cmd = new SqlCommand("insert into terrain(RegionUUID, Revision, Heightfield)" +
374 " values(@RegionUUID, @Revision, @Heightfield)", m_connection);
375 using (cmd)
376 {
377 cmd.Parameters.Add(new SqlParameter("@RegionUUID", regionID.UUID));
378 cmd.Parameters.Add(new SqlParameter("@Revision", revision));
379 cmd.Parameters.Add(new SqlParameter("@Heightfield", serializeTerrain(ter)));
380 cmd.ExecuteNonQuery();
381 }
382 }
383 }
384
385 /// <summary>
386 /// Load the latest terrain revision from region storage.
387 /// </summary>
388 /// <param name="regionID">The Region UUID</param>
389 /// <returns>HeightField Data</returns>
390 public double[,] LoadTerrain(LLUUID regionID)
391 {
392 double[,] terret = new double[256, 256];
393 terret.Initialize();
394
395 SqlCommand cmd = new SqlCommand(
396 @"select top 1 RegionUUID, Revision, Heightfield from terrain
397 where RegionUUID=@RegionUUID order by Revision desc"
398 , m_connection);
399
400 // SqlParameter param = new SqlParameter();
401 cmd.Parameters.Add(new SqlParameter("@RegionUUID", regionID.UUID));
402
403 if (m_connection.State != ConnectionState.Open)
404 {
405 m_connection.Open();
406 }
407
408 using (SqlDataReader row = cmd.ExecuteReader())
409 {
410 int rev = 0;
411 if (row.Read())
412 {
413 MemoryStream str = new MemoryStream((byte[])row["Heightfield"]);
414 BinaryReader br = new BinaryReader(str);
415 for (int x = 0; x < 256; x++)
416 {
417 for (int y = 0; y < 256; y++)
418 {
419 terret[x, y] = br.ReadDouble();
420 }
421 }
422 rev = (int)row["Revision"];
423 }
424 else
425 {
426 m_log.Info("[REGION DB]: No terrain found for region");
427 return null;
428 }
429
430 m_log.Info("[REGION DB]: Loaded terrain revision r" + rev.ToString());
431 }
432
433 return terret;
434 }
435
436 /// <summary>
437 ///
438 /// </summary>
439 /// <param name="globalID"></param>
440 public void RemoveLandObject(LLUUID globalID)
441 {
442 // Instance.RemoveLandObject(globalID);
443
444 lock (m_dataSet)
445 {
446 using (SqlCommand cmd = new SqlCommand("delete from land where UUID=@UUID", m_connection))
447 {
448 cmd.Parameters.Add(new SqlParameter("@UUID", globalID.UUID));
449 cmd.ExecuteNonQuery();
450 }
451
452 using (
453 SqlCommand cmd = new SqlCommand("delete from landaccesslist where LandUUID=@UUID", m_connection)
454 )
455 {
456 cmd.Parameters.Add(new SqlParameter("@UUID", globalID.UUID));
457 cmd.ExecuteNonQuery();
458 }
459 }
460 }
461
462 /// <summary>
463 ///
464 /// </summary>
465 /// <param name="parcel"></param>
466 public void StoreLandObject(ILandObject parcel)
467 {
468 lock (m_dataSet)
469 {
470 DataTable land = m_landTable;
471 DataTable landaccesslist = m_landAccessListTable;
472
473 DataRow landRow = land.Rows.Find(parcel.landData.GlobalID.UUID);
474 if (landRow == null)
475 {
476 landRow = land.NewRow();
477 fillLandRow(landRow, parcel.landData, parcel.regionUUID);
478 land.Rows.Add(landRow);
479 }
480 else
481 {
482 fillLandRow(landRow, parcel.landData, parcel.regionUUID);
483 }
484
485 using (
486 SqlCommand cmd =
487 new SqlCommand("delete from landaccesslist where LandUUID=@LandUUID", m_connection))
488 {
489 cmd.Parameters.Add(new SqlParameter("@LandUUID", parcel.landData.GlobalID.UUID));
490 cmd.ExecuteNonQuery();
491 }
492
493 foreach (ParcelManager.ParcelAccessEntry entry in parcel.landData.ParcelAccessList)
494 {
495 DataRow newAccessRow = landaccesslist.NewRow();
496 fillLandAccessRow(newAccessRow, entry, parcel.landData.GlobalID);
497 landaccesslist.Rows.Add(newAccessRow);
498 }
499
500 }
501 Commit();
502 }
503
504 /// <summary>
505 ///
506 /// </summary>
507 /// <param name="regionUUID">The region UUID</param>
508 /// <returns></returns>
509 public List<LandData> LoadLandObjects(LLUUID regionUUID)
510 {
511 List<LandData> landDataForRegion = new List<LandData>();
512 lock (m_dataSet)
513 {
514 DataTable land = m_landTable;
515 DataTable landaccesslist = m_landAccessListTable;
516 string searchExp = "RegionUUID = '" + regionUUID.UUID + "'";
517 DataRow[] rawDataForRegion = land.Select(searchExp);
518 foreach (DataRow rawDataLand in rawDataForRegion)
519 {
520 LandData newLand = buildLandData(rawDataLand);
521 string accessListSearchExp = "LandUUID = '" + newLand.GlobalID.UUID + "'";
522 DataRow[] rawDataForLandAccessList = landaccesslist.Select(accessListSearchExp);
523 foreach (DataRow rawDataLandAccess in rawDataForLandAccessList)
524 {
525 newLand.ParcelAccessList.Add(buildLandAccessData(rawDataLandAccess));
526 }
527
528 landDataForRegion.Add(newLand);
529 }
530 }
531 return landDataForRegion;
532 }
533
534 /// <summary>
535 /// Load (fetch?) the region banlist
536 /// </summary>
537 /// <param name="regionUUID">the region UUID</param>
538 /// <returns>the banlist list</returns>
539 public List<EstateBan> LoadRegionBanList(LLUUID regionUUID)
540 {
541 List<EstateBan> regionbanlist = new List<EstateBan>();
542 return regionbanlist;
543 }
544
545 /// <summary>
546 /// STUB, add an item into region banlist
547 /// </summary>
548 /// <param name="item">the item</param>
549 public void AddToRegionBanlist(EstateBan item)
550 {
551
552 }
553
554 /// <summary>
555 /// STUB, remove an item from region banlist
556 /// </summary>
557 /// <param name="item"></param>
558 public void RemoveFromRegionBanlist(EstateBan item)
559 {
560
561 }
562
563 /// <summary>
564 /// Commit
565 /// </summary>
566 public void Commit()
567 {
568 if (m_connection.State != ConnectionState.Open)
569 {
570 m_connection.Open();
571 }
572
573 lock (m_dataSet)
574 {
575 // DisplayDataSet(m_dataSet, "Region DataSet");
576
577 m_primDataAdapter.Update(m_primTable);
578 m_shapeDataAdapter.Update(m_shapeTable);
579
580 m_itemsDataAdapter.Update(m_itemsTable);
581
582 m_terrainDataAdapter.Update(m_terrainTable);
583 m_landDataAdapter.Update(m_landTable);
584 m_landAccessListDataAdapter.Update(m_landAccessListTable);
585
586 m_dataSet.AcceptChanges();
587 }
588 }
589
590 /// <summary>
591 /// See <see cref="Commit"/>
592 /// </summary>
593 public void Shutdown()
594 {
595 Commit();
596 }
597
598 /***********************************************************************
599 *
600 * Database Definition Functions
601 *
602 * This should be db agnostic as we define them in ADO.NET terms
603 *
604 **********************************************************************/
605
606 /// <summary>
607 ///
608 /// </summary>
609 /// <param name="dt"></param>
610 /// <param name="name"></param>
611 /// <param name="type"></param>
612 /// <returns></returns>
613 private static DataColumn createCol(DataTable dt, string name, Type type)
614 {
615 DataColumn col = new DataColumn(name, type);
616 dt.Columns.Add(col);
617 return col;
618 }
619
620 /// <summary>
621 /// Create the "terrain" table
622 /// </summary>
623 /// <returns>the datatable</returns>
624 private static DataTable createTerrainTable()
625 {
626 DataTable terrain = new DataTable("terrain");
627
628 createCol(terrain, "RegionUUID", typeof(String));
629 createCol(terrain, "Revision", typeof(Int32));
630 createCol(terrain, "Heightfield", typeof(Byte[]));
631
632 return terrain;
633 }
634
635 /// <summary>
636 /// Create the "prims" table
637 /// </summary>
638 /// <returns>the datatable</returns>
639 private static DataTable createPrimTable()
640 {
641 DataTable prims = new DataTable("prims");
642
643 createCol(prims, "UUID", typeof(String));
644 createCol(prims, "RegionUUID", typeof(String));
645 createCol(prims, "ParentID", typeof(Int32));
646 createCol(prims, "CreationDate", typeof(Int32));
647 createCol(prims, "Name", typeof(String));
648 createCol(prims, "SceneGroupID", typeof(String));
649 // various text fields
650 createCol(prims, "Text", typeof(String));
651 createCol(prims, "Description", typeof(String));
652 createCol(prims, "SitName", typeof(String));
653 createCol(prims, "TouchName", typeof(String));
654 // permissions
655 createCol(prims, "ObjectFlags", typeof(Int32));
656 createCol(prims, "CreatorID", typeof(String));
657 createCol(prims, "OwnerID", typeof(String));
658 createCol(prims, "GroupID", typeof(String));
659 createCol(prims, "LastOwnerID", typeof(String));
660 createCol(prims, "OwnerMask", typeof(Int32));
661 createCol(prims, "NextOwnerMask", typeof(Int32));
662 createCol(prims, "GroupMask", typeof(Int32));
663 createCol(prims, "EveryoneMask", typeof(Int32));
664 createCol(prims, "BaseMask", typeof(Int32));
665 // vectors
666 createCol(prims, "PositionX", typeof(Double));
667 createCol(prims, "PositionY", typeof(Double));
668 createCol(prims, "PositionZ", typeof(Double));
669 createCol(prims, "GroupPositionX", typeof(Double));
670 createCol(prims, "GroupPositionY", typeof(Double));
671 createCol(prims, "GroupPositionZ", typeof(Double));
672 createCol(prims, "VelocityX", typeof(Double));
673 createCol(prims, "VelocityY", typeof(Double));
674 createCol(prims, "VelocityZ", typeof(Double));
675 createCol(prims, "AngularVelocityX", typeof(Double));
676 createCol(prims, "AngularVelocityY", typeof(Double));
677 createCol(prims, "AngularVelocityZ", typeof(Double));
678 createCol(prims, "AccelerationX", typeof(Double));
679 createCol(prims, "AccelerationY", typeof(Double));
680 createCol(prims, "AccelerationZ", typeof(Double));
681 // quaternions
682 createCol(prims, "RotationX", typeof(Double));
683 createCol(prims, "RotationY", typeof(Double));
684 createCol(prims, "RotationZ", typeof(Double));
685 createCol(prims, "RotationW", typeof(Double));
686
687 // sit target
688 createCol(prims, "SitTargetOffsetX", typeof(Double));
689 createCol(prims, "SitTargetOffsetY", typeof(Double));
690 createCol(prims, "SitTargetOffsetZ", typeof(Double));
691
692 createCol(prims, "SitTargetOrientW", typeof(Double));
693 createCol(prims, "SitTargetOrientX", typeof(Double));
694 createCol(prims, "SitTargetOrientY", typeof(Double));
695 createCol(prims, "SitTargetOrientZ", typeof(Double));
696
697 // Add in contraints
698 prims.PrimaryKey = new DataColumn[] { prims.Columns["UUID"] };
699
700 return prims;
701 }
702
703 /// <summary>
704 /// Create the "land" table
705 /// </summary>
706 /// <returns>the datatable</returns>
707 private static DataTable createLandTable()
708 {
709 DataTable land = new DataTable("land");
710 createCol(land, "UUID", typeof(String));
711 createCol(land, "RegionUUID", typeof(String));
712 createCol(land, "LocalLandID", typeof(Int32));
713
714 // Bitmap is a byte[512]
715 createCol(land, "Bitmap", typeof(Byte[]));
716
717 createCol(land, "Name", typeof(String));
718 createCol(land, "Description", typeof(String));
719 createCol(land, "OwnerUUID", typeof(String));
720 createCol(land, "IsGroupOwned", typeof(Int32));
721 createCol(land, "Area", typeof(Int32));
722 createCol(land, "AuctionID", typeof(Int32)); //Unemplemented
723 createCol(land, "Category", typeof(Int32)); //Enum libsecondlife.Parcel.ParcelCategory
724 createCol(land, "ClaimDate", typeof(Int32));
725 createCol(land, "ClaimPrice", typeof(Int32));
726 createCol(land, "GroupUUID", typeof(String));
727 createCol(land, "SalePrice", typeof(Int32));
728 createCol(land, "LandStatus", typeof(Int32)); //Enum. libsecondlife.Parcel.ParcelStatus
729 createCol(land, "LandFlags", typeof(Int32));
730 createCol(land, "LandingType", typeof(Int32));
731 createCol(land, "MediaAutoScale", typeof(Int32));
732 createCol(land, "MediaTextureUUID", typeof(String));
733 createCol(land, "MediaURL", typeof(String));
734 createCol(land, "MusicURL", typeof(String));
735 createCol(land, "PassHours", typeof(Double));
736 createCol(land, "PassPrice", typeof(Int32));
737 createCol(land, "SnapshotUUID", typeof(String));
738 createCol(land, "UserLocationX", typeof(Double));
739 createCol(land, "UserLocationY", typeof(Double));
740 createCol(land, "UserLocationZ", typeof(Double));
741 createCol(land, "UserLookAtX", typeof(Double));
742 createCol(land, "UserLookAtY", typeof(Double));
743 createCol(land, "UserLookAtZ", typeof(Double));
744
745 land.PrimaryKey = new DataColumn[] { land.Columns["UUID"] };
746
747 return land;
748 }
749
750 /// <summary>
751 /// Create "landacceslist" table
752 /// </summary>
753 /// <returns>the datatable</returns>
754 private static DataTable createLandAccessListTable()
755 {
756 DataTable landaccess = new DataTable("landaccesslist");
757 createCol(landaccess, "LandUUID", typeof(String));
758 createCol(landaccess, "AccessUUID", typeof(String));
759 createCol(landaccess, "Flags", typeof(Int32));
760
761 return landaccess;
762 }
763
764 /// <summary>
765 /// Create "primsshapes" table
766 /// </summary>
767 /// <returns>the datatable</returns>
768 private static DataTable createShapeTable()
769 {
770 DataTable shapes = new DataTable("primshapes");
771 createCol(shapes, "UUID", typeof(String));
772 // shape is an enum
773 createCol(shapes, "Shape", typeof(Int32));
774 // vectors
775 createCol(shapes, "ScaleX", typeof(Double));
776 createCol(shapes, "ScaleY", typeof(Double));
777 createCol(shapes, "ScaleZ", typeof(Double));
778 // paths
779 createCol(shapes, "PCode", typeof(Int32));
780 createCol(shapes, "PathBegin", typeof(Int32));
781 createCol(shapes, "PathEnd", typeof(Int32));
782 createCol(shapes, "PathScaleX", typeof(Int32));
783 createCol(shapes, "PathScaleY", typeof(Int32));
784 createCol(shapes, "PathShearX", typeof(Int32));
785 createCol(shapes, "PathShearY", typeof(Int32));
786 createCol(shapes, "PathSkew", typeof(Int32));
787 createCol(shapes, "PathCurve", typeof(Int32));
788 createCol(shapes, "PathRadiusOffset", typeof(Int32));
789 createCol(shapes, "PathRevolutions", typeof(Int32));
790 createCol(shapes, "PathTaperX", typeof(Int32));
791 createCol(shapes, "PathTaperY", typeof(Int32));
792 createCol(shapes, "PathTwist", typeof(Int32));
793 createCol(shapes, "PathTwistBegin", typeof(Int32));
794 // profile
795 createCol(shapes, "ProfileBegin", typeof(Int32));
796 createCol(shapes, "ProfileEnd", typeof(Int32));
797 createCol(shapes, "ProfileCurve", typeof(Int32));
798 createCol(shapes, "ProfileHollow", typeof(Int32));
799 createCol(shapes, "State", typeof(Int32));
800 // text TODO: this isn't right, but I'm not sure the right
801 // way to specify this as a blob atm
802 createCol(shapes, "Texture", typeof(Byte[]));
803 createCol(shapes, "ExtraParams", typeof(Byte[]));
804
805 shapes.PrimaryKey = new DataColumn[] { shapes.Columns["UUID"] };
806
807 return shapes;
808 }
809
810 /// <summary>
811 /// Create "primitems" table
812 /// </summary>
813 /// <returns>the datatable</returns>
814 private static DataTable createItemsTable()
815 {
816 DataTable items = new DataTable("primitems");
817
818 createCol(items, "itemID", typeof(String));
819 createCol(items, "primID", typeof(String));
820 createCol(items, "assetID", typeof(String));
821 createCol(items, "parentFolderID", typeof(String));
822
823 createCol(items, "invType", typeof(Int32));
824 createCol(items, "assetType", typeof(Int32));
825
826 createCol(items, "name", typeof(String));
827 createCol(items, "description", typeof(String));
828
829 createCol(items, "creationDate", typeof(Int64));
830 createCol(items, "creatorID", typeof(String));
831 createCol(items, "ownerID", typeof(String));
832 createCol(items, "lastOwnerID", typeof(String));
833 createCol(items, "groupID", typeof(String));
834
835 createCol(items, "nextPermissions", typeof(Int32));
836 createCol(items, "currentPermissions", typeof(Int32));
837 createCol(items, "basePermissions", typeof(Int32));
838 createCol(items, "everyonePermissions", typeof(Int32));
839 createCol(items, "groupPermissions", typeof(Int32));
840// createCol(items, "flags", typeof(Int32));
841
842 items.PrimaryKey = new DataColumn[] { items.Columns["itemID"] };
843
844 return items;
845 }
846
847 /***********************************************************************
848 *
849 * Convert between ADO.NET <=> OpenSim Objects
850 *
851 * These should be database independant
852 *
853 **********************************************************************/
854
855 /// <summary>
856 ///
857 /// </summary>
858 /// <param name="row"></param>
859 /// <returns></returns>
860 private SceneObjectPart buildPrim(DataRow row)
861 {
862 SceneObjectPart prim = new SceneObjectPart();
863 prim.UUID = new LLUUID((String)row["UUID"]);
864 // explicit conversion of integers is required, which sort
865 // of sucks. No idea if there is a shortcut here or not.
866 prim.ParentID = Convert.ToUInt32(row["ParentID"]);
867 prim.CreationDate = Convert.ToInt32(row["CreationDate"]);
868 prim.Name = (String)row["Name"];
869 // various text fields
870 prim.Text = (String)row["Text"];
871 prim.Description = (String)row["Description"];
872 prim.SitName = (String)row["SitName"];
873 prim.TouchName = (String)row["TouchName"];
874 // permissions
875 prim.ObjectFlags = Convert.ToUInt32(row["ObjectFlags"]);
876 prim.CreatorID = new LLUUID((String)row["CreatorID"]);
877 prim.OwnerID = new LLUUID((String)row["OwnerID"]);
878 prim.GroupID = new LLUUID((String)row["GroupID"]);
879 prim.LastOwnerID = new LLUUID((String)row["LastOwnerID"]);
880 prim.OwnerMask = Convert.ToUInt32(row["OwnerMask"]);
881 prim.NextOwnerMask = Convert.ToUInt32(row["NextOwnerMask"]);
882 prim.GroupMask = Convert.ToUInt32(row["GroupMask"]);
883 prim.EveryoneMask = Convert.ToUInt32(row["EveryoneMask"]);
884 prim.BaseMask = Convert.ToUInt32(row["BaseMask"]);
885 // vectors
886 prim.OffsetPosition = new LLVector3(
887 Convert.ToSingle(row["PositionX"]),
888 Convert.ToSingle(row["PositionY"]),
889 Convert.ToSingle(row["PositionZ"])
890 );
891 prim.GroupPosition = new LLVector3(
892 Convert.ToSingle(row["GroupPositionX"]),
893 Convert.ToSingle(row["GroupPositionY"]),
894 Convert.ToSingle(row["GroupPositionZ"])
895 );
896 prim.Velocity = new LLVector3(
897 Convert.ToSingle(row["VelocityX"]),
898 Convert.ToSingle(row["VelocityY"]),
899 Convert.ToSingle(row["VelocityZ"])
900 );
901 prim.AngularVelocity = new LLVector3(
902 Convert.ToSingle(row["AngularVelocityX"]),
903 Convert.ToSingle(row["AngularVelocityY"]),
904 Convert.ToSingle(row["AngularVelocityZ"])
905 );
906 prim.Acceleration = new LLVector3(
907 Convert.ToSingle(row["AccelerationX"]),
908 Convert.ToSingle(row["AccelerationY"]),
909 Convert.ToSingle(row["AccelerationZ"])
910 );
911 // quaternions
912 prim.RotationOffset = new LLQuaternion(
913 Convert.ToSingle(row["RotationX"]),
914 Convert.ToSingle(row["RotationY"]),
915 Convert.ToSingle(row["RotationZ"]),
916 Convert.ToSingle(row["RotationW"])
917 );
918 try
919 {
920 prim.SitTargetPositionLL = new LLVector3(
921 Convert.ToSingle(row["SitTargetOffsetX"]),
922 Convert.ToSingle(row["SitTargetOffsetY"]),
923 Convert.ToSingle(row["SitTargetOffsetZ"]));
924 prim.SitTargetOrientationLL = new LLQuaternion(
925 Convert.ToSingle(
926 row["SitTargetOrientX"]),
927 Convert.ToSingle(
928 row["SitTargetOrientY"]),
929 Convert.ToSingle(
930 row["SitTargetOrientZ"]),
931 Convert.ToSingle(
932 row["SitTargetOrientW"]));
933 }
934 catch (InvalidCastException)
935 {
936 // Database table was created before we got here and now has null values :P
937
938 using (
939 SqlCommand cmd =
940 new SqlCommand(
941 "ALTER TABLE [prims] ADD COLUMN [SitTargetOffsetX] float NOT NULL default 0, ADD COLUMN [SitTargetOffsetY] float NOT NULL default 0, ADD COLUMN [SitTargetOffsetZ] float NOT NULL default 0, ADD COLUMN [SitTargetOrientW] float NOT NULL default 0, ADD COLUMN [SitTargetOrientX] float NOT NULL default 0, ADD COLUMN [SitTargetOrientY] float NOT NULL default 0, ADD COLUMN [SitTargetOrientZ] float NOT NULL default 0;",
942 m_connection))
943 {
944 cmd.ExecuteNonQuery();
945 }
946 }
947
948 return prim;
949 }
950
951 /// <summary>
952 /// Build a prim inventory item from the persisted data.
953 /// </summary>
954 /// <param name="row"></param>
955 /// <returns></returns>
956 private static TaskInventoryItem buildItem(DataRow row)
957 {
958 TaskInventoryItem taskItem = new TaskInventoryItem();
959
960 taskItem.ItemID = new LLUUID((String)row["itemID"]);
961 taskItem.ParentPartID = new LLUUID((String)row["primID"]);
962 taskItem.AssetID = new LLUUID((String)row["assetID"]);
963 taskItem.ParentID = new LLUUID((String)row["parentFolderID"]);
964
965 taskItem.InvType = Convert.ToInt32(row["invType"]);
966 taskItem.Type = Convert.ToInt32(row["assetType"]);
967
968 taskItem.Name = (String)row["name"];
969 taskItem.Description = (String)row["description"];
970 taskItem.CreationDate = Convert.ToUInt32(row["creationDate"]);
971 taskItem.CreatorID = new LLUUID((String)row["creatorID"]);
972 taskItem.OwnerID = new LLUUID((String)row["ownerID"]);
973 taskItem.LastOwnerID = new LLUUID((String)row["lastOwnerID"]);
974 taskItem.GroupID = new LLUUID((String)row["groupID"]);
975
976 taskItem.NextPermissions = Convert.ToUInt32(row["nextPermissions"]);
977 taskItem.CurrentPermissions = Convert.ToUInt32(row["currentPermissions"]);
978 taskItem.BasePermissions = Convert.ToUInt32(row["basePermissions"]);
979 taskItem.EveryonePermissions = Convert.ToUInt32(row["everyonePermissions"]);
980 taskItem.GroupPermissions = Convert.ToUInt32(row["groupPermissions"]);
981// taskItem.Flags = Convert.ToUInt32(row["flags"]);
982
983 return taskItem;
984 }
985
986 /// <summary>
987 ///
988 /// </summary>
989 /// <param name="row"></param>
990 /// <returns></returns>
991 private static LandData buildLandData(DataRow row)
992 {
993 LandData newData = new LandData();
994
995 newData.GlobalID = new LLUUID((String)row["UUID"]);
996 newData.LocalID = Convert.ToInt32(row["LocalLandID"]);
997
998 // Bitmap is a byte[512]
999 newData.Bitmap = (Byte[])row["Bitmap"];
1000
1001 newData.Name = (String)row["Name"];
1002 newData.Description = (String)row["Description"];
1003 newData.OwnerID = (String)row["OwnerUUID"];
1004 newData.IsGroupOwned = Convert.ToBoolean(row["IsGroupOwned"]);
1005 newData.Area = Convert.ToInt32(row["Area"]);
1006 newData.AuctionID = Convert.ToUInt32(row["AuctionID"]); //Unemplemented
1007 newData.Category = (Parcel.ParcelCategory)Convert.ToInt32(row["Category"]);
1008 //Enum libsecondlife.Parcel.ParcelCategory
1009 newData.ClaimDate = Convert.ToInt32(row["ClaimDate"]);
1010 newData.ClaimPrice = Convert.ToInt32(row["ClaimPrice"]);
1011 newData.GroupID = new LLUUID((String)row["GroupUUID"]);
1012 newData.SalePrice = Convert.ToInt32(row["SalePrice"]);
1013 newData.Status = (Parcel.ParcelStatus)Convert.ToInt32(row["LandStatus"]);
1014 //Enum. libsecondlife.Parcel.ParcelStatus
1015 newData.Flags = Convert.ToUInt32(row["LandFlags"]);
1016 newData.LandingType = Convert.ToByte(row["LandingType"]);
1017 newData.MediaAutoScale = Convert.ToByte(row["MediaAutoScale"]);
1018 newData.MediaID = new LLUUID((String)row["MediaTextureUUID"]);
1019 newData.MediaURL = (String)row["MediaURL"];
1020 newData.MusicURL = (String)row["MusicURL"];
1021 newData.PassHours = Convert.ToSingle(row["PassHours"]);
1022 newData.PassPrice = Convert.ToInt32(row["PassPrice"]);
1023 newData.SnapshotID = (String)row["SnapshotUUID"];
1024
1025 newData.UserLocation =
1026 new LLVector3(Convert.ToSingle(row["UserLocationX"]), Convert.ToSingle(row["UserLocationY"]),
1027 Convert.ToSingle(row["UserLocationZ"]));
1028 newData.UserLookAt =
1029 new LLVector3(Convert.ToSingle(row["UserLookAtX"]), Convert.ToSingle(row["UserLookAtY"]),
1030 Convert.ToSingle(row["UserLookAtZ"]));
1031 newData.ParcelAccessList = new List<ParcelManager.ParcelAccessEntry>();
1032
1033 return newData;
1034 }
1035
1036 /// <summary>
1037 ///
1038 /// </summary>
1039 /// <param name="row"></param>
1040 /// <returns></returns>
1041 private static ParcelManager.ParcelAccessEntry buildLandAccessData(DataRow row)
1042 {
1043 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
1044 entry.AgentID = new LLUUID((string)row["AccessUUID"]);
1045 entry.Flags = (ParcelManager.AccessList)Convert.ToInt32(row["Flags"]);
1046 entry.Time = new DateTime();
1047 return entry;
1048 }
1049
1050 /// <summary>
1051 /// Serialize terrain HeightField
1052 /// </summary>
1053 /// <param name="val">the terrain heightfield</param>
1054 /// <returns></returns>
1055 private static Array serializeTerrain(double[,] val)
1056 {
1057 MemoryStream str = new MemoryStream(65536 * sizeof(double));
1058 BinaryWriter bw = new BinaryWriter(str);
1059
1060 // TODO: COMPATIBILITY - Add byte-order conversions
1061 for (int x = 0; x < 256; x++)
1062 for (int y = 0; y < 256; y++)
1063 bw.Write(val[x, y]);
1064
1065 return str.ToArray();
1066 }
1067
1068 /// <summary>
1069 ///
1070 /// </summary>
1071 /// <param name="row"></param>
1072 /// <param name="prim"></param>
1073 /// <param name="sceneGroupID"></param>
1074 /// <param name="regionUUID"></param>
1075 private void fillPrimRow(DataRow row, SceneObjectPart prim, LLUUID sceneGroupID, LLUUID regionUUID)
1076 {
1077 row["UUID"] = prim.UUID;
1078 row["RegionUUID"] = regionUUID;
1079 row["ParentID"] = prim.ParentID;
1080 row["CreationDate"] = prim.CreationDate;
1081 row["Name"] = prim.Name;
1082 row["SceneGroupID"] = sceneGroupID;
1083 // the UUID of the root part for this SceneObjectGroup
1084 // various text fields
1085 row["Text"] = prim.Text;
1086 row["Description"] = prim.Description;
1087 row["SitName"] = prim.SitName;
1088 row["TouchName"] = prim.TouchName;
1089 // permissions
1090 row["ObjectFlags"] = prim.ObjectFlags;
1091 row["CreatorID"] = prim.CreatorID;
1092 row["OwnerID"] = prim.OwnerID;
1093 row["GroupID"] = prim.GroupID;
1094 row["LastOwnerID"] = prim.LastOwnerID;
1095 row["OwnerMask"] = prim.OwnerMask;
1096 row["NextOwnerMask"] = prim.NextOwnerMask;
1097 row["GroupMask"] = prim.GroupMask;
1098 row["EveryoneMask"] = prim.EveryoneMask;
1099 row["BaseMask"] = prim.BaseMask;
1100 // vectors
1101 row["PositionX"] = prim.OffsetPosition.X;
1102 row["PositionY"] = prim.OffsetPosition.Y;
1103 row["PositionZ"] = prim.OffsetPosition.Z;
1104 row["GroupPositionX"] = prim.GroupPosition.X;
1105 row["GroupPositionY"] = prim.GroupPosition.Y;
1106 row["GroupPositionZ"] = prim.GroupPosition.Z;
1107 row["VelocityX"] = prim.Velocity.X;
1108 row["VelocityY"] = prim.Velocity.Y;
1109 row["VelocityZ"] = prim.Velocity.Z;
1110 row["AngularVelocityX"] = prim.AngularVelocity.X;
1111 row["AngularVelocityY"] = prim.AngularVelocity.Y;
1112 row["AngularVelocityZ"] = prim.AngularVelocity.Z;
1113 row["AccelerationX"] = prim.Acceleration.X;
1114 row["AccelerationY"] = prim.Acceleration.Y;
1115 row["AccelerationZ"] = prim.Acceleration.Z;
1116 // quaternions
1117 row["RotationX"] = prim.RotationOffset.X;
1118 row["RotationY"] = prim.RotationOffset.Y;
1119 row["RotationZ"] = prim.RotationOffset.Z;
1120 row["RotationW"] = prim.RotationOffset.W;
1121
1122 try
1123 {
1124 // Sit target
1125 LLVector3 sitTargetPos = prim.SitTargetPositionLL;
1126 row["SitTargetOffsetX"] = sitTargetPos.X;
1127 row["SitTargetOffsetY"] = sitTargetPos.Y;
1128 row["SitTargetOffsetZ"] = sitTargetPos.Z;
1129
1130 LLQuaternion sitTargetOrient = prim.SitTargetOrientationLL;
1131 row["SitTargetOrientW"] = sitTargetOrient.W;
1132 row["SitTargetOrientX"] = sitTargetOrient.X;
1133 row["SitTargetOrientY"] = sitTargetOrient.Y;
1134 row["SitTargetOrientZ"] = sitTargetOrient.Z;
1135 }
1136 catch (Exception)
1137 {
1138 // Database table was created before we got here and needs to be created! :P
1139
1140 using (
1141 SqlCommand cmd =
1142 new SqlCommand(
1143 "ALTER TABLE [prims] ADD COLUMN [SitTargetOffsetX] float NOT NULL default 0, ADD COLUMN [SitTargetOffsetY] float NOT NULL default 0, ADD COLUMN [SitTargetOffsetZ] float NOT NULL default 0, ADD COLUMN [SitTargetOrientW] float NOT NULL default 0, ADD COLUMN [SitTargetOrientX] float NOT NULL default 0, ADD COLUMN [SitTargetOrientY] float NOT NULL default 0, ADD COLUMN [SitTargetOrientZ] float NOT NULL default 0;",
1144 m_connection))
1145 {
1146 cmd.ExecuteNonQuery();
1147 }
1148 }
1149 }
1150
1151 /// <summary>
1152 ///
1153 /// </summary>
1154 /// <param name="row"></param>
1155 /// <param name="taskItem"></param>
1156 private static void fillItemRow(DataRow row, TaskInventoryItem taskItem)
1157 {
1158 row["itemID"] = taskItem.ItemID;
1159 row["primID"] = taskItem.ParentPartID;
1160 row["assetID"] = taskItem.AssetID;
1161 row["parentFolderID"] = taskItem.ParentID;
1162
1163 row["invType"] = taskItem.InvType;
1164 row["assetType"] = taskItem.Type;
1165
1166 row["name"] = taskItem.Name;
1167 row["description"] = taskItem.Description;
1168 row["creationDate"] = taskItem.CreationDate;
1169 row["creatorID"] = taskItem.CreatorID;
1170 row["ownerID"] = taskItem.OwnerID;
1171 row["lastOwnerID"] = taskItem.LastOwnerID;
1172 row["groupID"] = taskItem.GroupID;
1173 row["nextPermissions"] = taskItem.NextPermissions;
1174 row["currentPermissions"] = taskItem.CurrentPermissions;
1175 row["basePermissions"] = taskItem.BasePermissions;
1176 row["everyonePermissions"] = taskItem.EveryonePermissions;
1177 row["groupPermissions"] = taskItem.GroupPermissions;
1178// row["flags"] = taskItem.Flags;
1179 }
1180
1181 /// <summary>
1182 ///
1183 /// </summary>
1184 /// <param name="row"></param>
1185 /// <param name="land"></param>
1186 /// <param name="regionUUID"></param>
1187 private static void fillLandRow(DataRow row, LandData land, LLUUID regionUUID)
1188 {
1189 row["UUID"] = land.GlobalID.UUID;
1190 row["RegionUUID"] = regionUUID.UUID;
1191 row["LocalLandID"] = land.LocalID;
1192
1193 // Bitmap is a byte[512]
1194 row["Bitmap"] = land.Bitmap;
1195
1196 row["Name"] = land.Name;
1197 row["Description"] = land.Description;
1198 row["OwnerUUID"] = land.OwnerID.UUID;
1199 row["IsGroupOwned"] = land.IsGroupOwned;
1200 row["Area"] = land.Area;
1201 row["AuctionID"] = land.AuctionID; //Unemplemented
1202 row["Category"] = land.Category; //Enum libsecondlife.Parcel.ParcelCategory
1203 row["ClaimDate"] = land.ClaimDate;
1204 row["ClaimPrice"] = land.ClaimPrice;
1205 row["GroupUUID"] = land.GroupID.UUID;
1206 row["SalePrice"] = land.SalePrice;
1207 row["LandStatus"] = land.Status; //Enum. libsecondlife.Parcel.ParcelStatus
1208 row["LandFlags"] = land.Flags;
1209 row["LandingType"] = land.LandingType;
1210 row["MediaAutoScale"] = land.MediaAutoScale;
1211 row["MediaTextureUUID"] = land.MediaID.UUID;
1212 row["MediaURL"] = land.MediaURL;
1213 row["MusicURL"] = land.MusicURL;
1214 row["PassHours"] = land.PassHours;
1215 row["PassPrice"] = land.PassPrice;
1216 row["SnapshotUUID"] = land.SnapshotID.UUID;
1217 row["UserLocationX"] = land.UserLocation.X;
1218 row["UserLocationY"] = land.UserLocation.Y;
1219 row["UserLocationZ"] = land.UserLocation.Z;
1220 row["UserLookAtX"] = land.UserLookAt.X;
1221 row["UserLookAtY"] = land.UserLookAt.Y;
1222 row["UserLookAtZ"] = land.UserLookAt.Z;
1223 }
1224
1225 /// <summary>
1226 ///
1227 /// </summary>
1228 /// <param name="row"></param>
1229 /// <param name="entry"></param>
1230 /// <param name="parcelID"></param>
1231 private static void fillLandAccessRow(DataRow row, ParcelManager.ParcelAccessEntry entry, LLUUID parcelID)
1232 {
1233 row["LandUUID"] = parcelID.UUID;
1234 row["AccessUUID"] = entry.AgentID.UUID;
1235 row["Flags"] = entry.Flags;
1236 }
1237
1238 /// <summary>
1239 ///
1240 /// </summary>
1241 /// <param name="row"></param>
1242 /// <returns></returns>
1243 private static PrimitiveBaseShape buildShape(DataRow row)
1244 {
1245 PrimitiveBaseShape s = new PrimitiveBaseShape();
1246 s.Scale = new LLVector3(
1247 Convert.ToSingle(row["ScaleX"]),
1248 Convert.ToSingle(row["ScaleY"]),
1249 Convert.ToSingle(row["ScaleZ"])
1250 );
1251 // paths
1252 s.PCode = Convert.ToByte(row["PCode"]);
1253 s.PathBegin = Convert.ToUInt16(row["PathBegin"]);
1254 s.PathEnd = Convert.ToUInt16(row["PathEnd"]);
1255 s.PathScaleX = Convert.ToByte(row["PathScaleX"]);
1256 s.PathScaleY = Convert.ToByte(row["PathScaleY"]);
1257 s.PathShearX = Convert.ToByte(row["PathShearX"]);
1258 s.PathShearY = Convert.ToByte(row["PathShearY"]);
1259 s.PathSkew = Convert.ToSByte(row["PathSkew"]);
1260 s.PathCurve = Convert.ToByte(row["PathCurve"]);
1261 s.PathRadiusOffset = Convert.ToSByte(row["PathRadiusOffset"]);
1262 s.PathRevolutions = Convert.ToByte(row["PathRevolutions"]);
1263 s.PathTaperX = Convert.ToSByte(row["PathTaperX"]);
1264 s.PathTaperY = Convert.ToSByte(row["PathTaperY"]);
1265 s.PathTwist = Convert.ToSByte(row["PathTwist"]);
1266 s.PathTwistBegin = Convert.ToSByte(row["PathTwistBegin"]);
1267 // profile
1268 s.ProfileBegin = Convert.ToUInt16(row["ProfileBegin"]);
1269 s.ProfileEnd = Convert.ToUInt16(row["ProfileEnd"]);
1270 s.ProfileCurve = Convert.ToByte(row["ProfileCurve"]);
1271 s.ProfileHollow = Convert.ToUInt16(row["ProfileHollow"]);
1272 s.State = Convert.ToByte(row["State"]);
1273
1274 byte[] textureEntry = (byte[])row["Texture"];
1275 s.TextureEntry = textureEntry;
1276
1277 s.ExtraParams = (byte[])row["ExtraParams"];
1278
1279 return s;
1280 }
1281
1282 /// <summary>
1283 ///
1284 /// </summary>
1285 /// <param name="row"></param>
1286 /// <param name="prim"></param>
1287 private static void fillShapeRow(DataRow row, SceneObjectPart prim)
1288 {
1289 PrimitiveBaseShape s = prim.Shape;
1290 row["UUID"] = prim.UUID;
1291 // shape is an enum
1292 row["Shape"] = 0;
1293 // vectors
1294 row["ScaleX"] = s.Scale.X;
1295 row["ScaleY"] = s.Scale.Y;
1296 row["ScaleZ"] = s.Scale.Z;
1297 // paths
1298 row["PCode"] = s.PCode;
1299 row["PathBegin"] = s.PathBegin;
1300 row["PathEnd"] = s.PathEnd;
1301 row["PathScaleX"] = s.PathScaleX;
1302 row["PathScaleY"] = s.PathScaleY;
1303 row["PathShearX"] = s.PathShearX;
1304 row["PathShearY"] = s.PathShearY;
1305 row["PathSkew"] = s.PathSkew;
1306 row["PathCurve"] = s.PathCurve;
1307 row["PathRadiusOffset"] = s.PathRadiusOffset;
1308 row["PathRevolutions"] = s.PathRevolutions;
1309 row["PathTaperX"] = s.PathTaperX;
1310 row["PathTaperY"] = s.PathTaperY;
1311 row["PathTwist"] = s.PathTwist;
1312 row["PathTwistBegin"] = s.PathTwistBegin;
1313 // profile
1314 row["ProfileBegin"] = s.ProfileBegin;
1315 row["ProfileEnd"] = s.ProfileEnd;
1316 row["ProfileCurve"] = s.ProfileCurve;
1317 row["ProfileHollow"] = s.ProfileHollow;
1318 row["State"] = s.State;
1319 row["Texture"] = s.TextureEntry;
1320 row["ExtraParams"] = s.ExtraParams;
1321 }
1322
1323 /// <summary>
1324 ///
1325 /// </summary>
1326 /// <param name="prim"></param>
1327 /// <param name="sceneGroupID"></param>
1328 /// <param name="regionUUID"></param>
1329 private void addPrim(SceneObjectPart prim, LLUUID sceneGroupID, LLUUID regionUUID)
1330 {
1331 DataTable prims = m_dataSet.Tables["prims"];
1332 DataTable shapes = m_dataSet.Tables["primshapes"];
1333
1334 DataRow primRow = prims.Rows.Find(prim.UUID);
1335 if (primRow == null)
1336 {
1337 primRow = prims.NewRow();
1338 fillPrimRow(primRow, prim, sceneGroupID, regionUUID);
1339 prims.Rows.Add(primRow);
1340 }
1341 else
1342 {
1343 fillPrimRow(primRow, prim, sceneGroupID, regionUUID);
1344 }
1345
1346 DataRow shapeRow = shapes.Rows.Find(prim.UUID);
1347 if (shapeRow == null)
1348 {
1349 shapeRow = shapes.NewRow();
1350 fillShapeRow(shapeRow, prim);
1351 shapes.Rows.Add(shapeRow);
1352 }
1353 else
1354 {
1355 fillShapeRow(shapeRow, prim);
1356 }
1357 }
1358
1359 /// <summary>
1360 /// See <see cref="IRegionDatastore"/>
1361 /// </summary>
1362 /// <param name="primID"></param>
1363 /// <param name="items"></param>
1364 public void StorePrimInventory(LLUUID primID, ICollection<TaskInventoryItem> items)
1365 {
1366 m_log.InfoFormat("[REGION DB]: Persisting Prim Inventory with prim ID {0}", primID);
1367
1368 // For now, we're just going to crudely remove all the previous inventory items
1369 // no matter whether they have changed or not, and replace them with the current set.
1370 lock (m_dataSet)
1371 {
1372 RemoveItems(primID);
1373
1374 // repalce with current inventory details
1375 foreach (TaskInventoryItem newItem in items)
1376 {
1377 // m_log.InfoFormat(
1378 // "[REGION DB]: " +
1379 // "Adding item {0}, {1} to prim ID {2}",
1380 // newItem.Name, newItem.ItemID, newItem.ParentPartID);
1381
1382 DataRow newItemRow = m_itemsTable.NewRow();
1383 fillItemRow(newItemRow, newItem);
1384 m_itemsTable.Rows.Add(newItemRow);
1385 }
1386 }
1387
1388 Commit();
1389 }
1390
1391 /***********************************************************************
1392 *
1393 * SQL Statement Creation Functions
1394 *
1395 * These functions create SQL statements for update, insert, and create.
1396 * They can probably be factored later to have a db independant
1397 * portion and a db specific portion
1398 *
1399 **********************************************************************/
1400
1401 /// <summary>
1402 /// Create an Insert command
1403 /// </summary>
1404 /// <param name="table"></param>
1405 /// <param name="dt"></param>
1406 /// <returns>the sql command</returns>
1407 private static SqlCommand createInsertCommand(string table, DataTable dt)
1408 {
1409 /**
1410 * This is subtle enough to deserve some commentary.
1411 * Instead of doing *lots* and *lots of hardcoded strings
1412 * for database definitions we'll use the fact that
1413 * realistically all insert statements look like "insert
1414 * into A(b, c) values(:b, :c) on the parameterized query
1415 * front. If we just have a list of b, c, etc... we can
1416 * generate these strings instead of typing them out.
1417 */
1418 string[] cols = new string[dt.Columns.Count];
1419 for (int i = 0; i < dt.Columns.Count; i++)
1420 {
1421 DataColumn col = dt.Columns[i];
1422 cols[i] = col.ColumnName;
1423 }
1424
1425 string sql = "insert into " + table + "(";
1426 sql += String.Join(", ", cols);
1427 // important, the first ':' needs to be here, the rest get added in the join
1428 sql += ") values (@";
1429 sql += String.Join(", @", cols);
1430 sql += ")";
1431 SqlCommand cmd = new SqlCommand(sql);
1432
1433 // this provides the binding for all our parameters, so
1434 // much less code than it used to be
1435 foreach (DataColumn col in dt.Columns)
1436 {
1437 cmd.Parameters.Add(createSqlParameter(col.ColumnName, col.DataType));
1438 }
1439 return cmd;
1440 }
1441
1442 /// <summary>
1443 /// Create an update command
1444 /// </summary>
1445 /// <param name="table"></param>
1446 /// <param name="pk"></param>
1447 /// <param name="dt"></param>
1448 /// <returns>the sql command</returns>
1449 private static SqlCommand createUpdateCommand(string table, string pk, DataTable dt)
1450 {
1451 string sql = "update " + table + " set ";
1452 string subsql = String.Empty;
1453 foreach (DataColumn col in dt.Columns)
1454 {
1455 if (subsql.Length > 0)
1456 {
1457 // a map function would rock so much here
1458 subsql += ", ";
1459 }
1460 subsql += col.ColumnName + "= @" + col.ColumnName;
1461 }
1462 sql += subsql;
1463 sql += " where " + pk;
1464 SqlCommand cmd = new SqlCommand(sql);
1465
1466 // this provides the binding for all our parameters, so
1467 // much less code than it used to be
1468
1469 foreach (DataColumn col in dt.Columns)
1470 {
1471 cmd.Parameters.Add(createSqlParameter(col.ColumnName, col.DataType));
1472 }
1473 return cmd;
1474 }
1475
1476 /// <summary>
1477 ///
1478 /// </summary>
1479 /// <param name="dt"></param>
1480 /// <returns></returns>
1481 private static string defineTable(DataTable dt)
1482 {
1483 string sql = "create table " + dt.TableName + "(";
1484 string subsql = String.Empty;
1485 foreach (DataColumn col in dt.Columns)
1486 {
1487 if (subsql.Length > 0)
1488 {
1489 // a map function would rock so much here
1490 subsql += ",\n";
1491 }
1492 subsql += col.ColumnName + " " + MSSQLManager.SqlType(col.DataType);
1493 if (dt.PrimaryKey.Length > 0 && col == dt.PrimaryKey[0])
1494 {
1495 subsql += " primary key";
1496 }
1497 }
1498 sql += subsql;
1499 sql += ")";
1500
1501 return sql;
1502 }
1503
1504 /***********************************************************************
1505 *
1506 * Database Binding functions
1507 *
1508 * These will be db specific due to typing, and minor differences
1509 * in databases.
1510 *
1511 **********************************************************************/
1512
1513 ///<summary>
1514 /// <para>
1515 /// This is a convenience function that collapses 5 repetitive
1516 /// lines for defining SqlParameters to 2 parameters:
1517 /// column name and database type.
1518 /// </para>
1519 ///
1520 /// <para>
1521 /// It assumes certain conventions like :param as the param
1522 /// name to replace in parametrized queries, and that source
1523 /// version is always current version, both of which are fine
1524 /// for us.
1525 /// </para>
1526 ///</summary>
1527 ///<returns>a built Sql parameter</returns>
1528 private static SqlParameter createSqlParameter(string name, Type type)
1529 {
1530 SqlParameter param = new SqlParameter();
1531 param.ParameterName = "@" + name;
1532 param.DbType = dbtypeFromType(type);
1533 param.SourceColumn = name;
1534 param.SourceVersion = DataRowVersion.Current;
1535 return param;
1536 }
1537
1538 /// <summary>
1539 ///
1540 /// </summary>
1541 /// <param name="da"></param>
1542 /// <param name="conn"></param>
1543 private void setupPrimCommands(SqlDataAdapter da, SqlConnection conn)
1544 {
1545 da.InsertCommand = createInsertCommand("prims", m_dataSet.Tables["prims"]);
1546 da.InsertCommand.Connection = conn;
1547
1548 da.UpdateCommand = createUpdateCommand("prims", "UUID=@UUID", m_dataSet.Tables["prims"]);
1549 da.UpdateCommand.Connection = conn;
1550
1551 SqlCommand delete = new SqlCommand("delete from prims where UUID = @UUID");
1552 delete.Parameters.Add(createSqlParameter("UUID", typeof(String)));
1553 delete.Connection = conn;
1554 da.DeleteCommand = delete;
1555 }
1556
1557 /// <summary>
1558 ///
1559 /// </summary>
1560 /// <param name="da"></param>
1561 /// <param name="conn"></param>
1562 private void SetupItemsCommands(SqlDataAdapter da, SqlConnection conn)
1563 {
1564 da.InsertCommand = createInsertCommand("primitems", m_itemsTable);
1565 da.InsertCommand.Connection = conn;
1566
1567 da.UpdateCommand = createUpdateCommand("primitems", "itemID = @itemID", m_itemsTable);
1568 da.UpdateCommand.Connection = conn;
1569
1570 SqlCommand delete = new SqlCommand("delete from primitems where itemID = @itemID");
1571 delete.Parameters.Add(createSqlParameter("itemID", typeof(String)));
1572 delete.Connection = conn;
1573 da.DeleteCommand = delete;
1574 }
1575
1576 /// <summary>
1577 ///
1578 /// </summary>
1579 /// <param name="da"></param>
1580 /// <param name="conn"></param>
1581 private void setupTerrainCommands(SqlDataAdapter da, SqlConnection conn)
1582 {
1583 da.InsertCommand = createInsertCommand("terrain", m_dataSet.Tables["terrain"]);
1584 da.InsertCommand.Connection = conn;
1585 }
1586
1587 /// <summary>
1588 ///
1589 /// </summary>
1590 /// <param name="da"></param>
1591 /// <param name="conn"></param>
1592 private void setupLandCommands(SqlDataAdapter da, SqlConnection conn)
1593 {
1594 da.InsertCommand = createInsertCommand("land", m_dataSet.Tables["land"]);
1595 da.InsertCommand.Connection = conn;
1596
1597 da.UpdateCommand = createUpdateCommand("land", "UUID=@UUID", m_dataSet.Tables["land"]);
1598 da.UpdateCommand.Connection = conn;
1599 }
1600
1601 /// <summary>
1602 ///
1603 /// </summary>
1604 /// <param name="da"></param>
1605 /// <param name="conn"></param>
1606 private void setupLandAccessCommands(SqlDataAdapter da, SqlConnection conn)
1607 {
1608 da.InsertCommand = createInsertCommand("landaccesslist", m_dataSet.Tables["landaccesslist"]);
1609 da.InsertCommand.Connection = conn;
1610 }
1611
1612 /// <summary>
1613 ///
1614 /// </summary>
1615 /// <param name="da"></param>
1616 /// <param name="conn"></param>
1617 private void setupShapeCommands(SqlDataAdapter da, SqlConnection conn)
1618 {
1619 da.InsertCommand = createInsertCommand("primshapes", m_dataSet.Tables["primshapes"]);
1620 da.InsertCommand.Connection = conn;
1621
1622 da.UpdateCommand = createUpdateCommand("primshapes", "UUID=@UUID", m_dataSet.Tables["primshapes"]);
1623 da.UpdateCommand.Connection = conn;
1624
1625 SqlCommand delete = new SqlCommand("delete from primshapes where UUID = @UUID");
1626 delete.Parameters.Add(createSqlParameter("UUID", typeof(String)));
1627 delete.Connection = conn;
1628 da.DeleteCommand = delete;
1629 }
1630
1631 /// <summary>
1632 ///
1633 /// </summary>
1634 /// <param name="conn"></param>
1635 private static void InitDB(SqlConnection conn)
1636 {
1637 string createPrims = defineTable(createPrimTable());
1638 string createShapes = defineTable(createShapeTable());
1639 string createItems = defineTable(createItemsTable());
1640 string createTerrain = defineTable(createTerrainTable());
1641 string createLand = defineTable(createLandTable());
1642 string createLandAccessList = defineTable(createLandAccessListTable());
1643
1644 SqlCommand pcmd = new SqlCommand(createPrims, conn);
1645 SqlCommand scmd = new SqlCommand(createShapes, conn);
1646 SqlCommand icmd = new SqlCommand(createItems, conn);
1647 SqlCommand tcmd = new SqlCommand(createTerrain, conn);
1648 SqlCommand lcmd = new SqlCommand(createLand, conn);
1649 SqlCommand lalcmd = new SqlCommand(createLandAccessList, conn);
1650
1651 conn.Open();
1652 try
1653 {
1654 pcmd.ExecuteNonQuery();
1655 }
1656 catch (SqlException e)
1657 {
1658 m_log.WarnFormat("[MSSql]: Primitives Table Already Exists: {0}", e);
1659 }
1660
1661 try
1662 {
1663 scmd.ExecuteNonQuery();
1664 }
1665 catch (SqlException e)
1666 {
1667 m_log.WarnFormat("[MSSql]: Shapes Table Already Exists: {0}", e);
1668 }
1669
1670 try
1671 {
1672 icmd.ExecuteNonQuery();
1673 }
1674 catch (SqlException e)
1675 {
1676 m_log.WarnFormat("[MSSql]: Items Table Already Exists: {0}", e);
1677 }
1678
1679 try
1680 {
1681 tcmd.ExecuteNonQuery();
1682 }
1683 catch (SqlException e)
1684 {
1685 m_log.WarnFormat("[MSSql]: Terrain Table Already Exists: {0}", e);
1686 }
1687
1688 try
1689 {
1690 lcmd.ExecuteNonQuery();
1691 }
1692 catch (SqlException e)
1693 {
1694 m_log.WarnFormat("[MSSql]: Land Table Already Exists: {0}", e);
1695 }
1696
1697 try
1698 {
1699 lalcmd.ExecuteNonQuery();
1700 }
1701 catch (SqlException e)
1702 {
1703 m_log.WarnFormat("[MSSql]: LandAccessList Table Already Exists: {0}", e);
1704 }
1705 conn.Close();
1706 }
1707
1708 /// <summary>
1709 ///
1710 /// </summary>
1711 /// <param name="conn"></param>
1712 /// <returns></returns>
1713 private bool TestTables(SqlConnection conn)
1714 {
1715 SqlCommand primSelectCmd = new SqlCommand(m_primSelect, conn);
1716 SqlDataAdapter pDa = new SqlDataAdapter(primSelectCmd);
1717 SqlCommand shapeSelectCmd = new SqlCommand(m_shapeSelect, conn);
1718 SqlDataAdapter sDa = new SqlDataAdapter(shapeSelectCmd);
1719 SqlCommand itemsSelectCmd = new SqlCommand(m_itemsSelect, conn);
1720 SqlDataAdapter iDa = new SqlDataAdapter(itemsSelectCmd);
1721 SqlCommand terrainSelectCmd = new SqlCommand(m_terrainSelect, conn);
1722 SqlDataAdapter tDa = new SqlDataAdapter(terrainSelectCmd);
1723 SqlCommand landSelectCmd = new SqlCommand(m_landSelect, conn);
1724 SqlDataAdapter lDa = new SqlDataAdapter(landSelectCmd);
1725 SqlCommand landAccessListSelectCmd = new SqlCommand(m_landAccessListSelect, conn);
1726 SqlDataAdapter lalDa = new SqlDataAdapter(landAccessListSelectCmd);
1727
1728 DataSet tmpDS = new DataSet();
1729 try
1730 {
1731 pDa.Fill(tmpDS, "prims");
1732 sDa.Fill(tmpDS, "primshapes");
1733
1734 iDa.Fill(tmpDS, "primitems");
1735
1736 tDa.Fill(tmpDS, "terrain");
1737 lDa.Fill(tmpDS, "land");
1738 lalDa.Fill(tmpDS, "landaccesslist");
1739 }
1740 catch (SqlException)
1741 {
1742 m_log.Info("[REGION DB]: MS Sql Database doesn't exist... creating");
1743 InitDB(conn);
1744 }
1745
1746 pDa.Fill(tmpDS, "prims");
1747 sDa.Fill(tmpDS, "primshapes");
1748
1749 iDa.Fill(tmpDS, "primitems");
1750
1751 tDa.Fill(tmpDS, "terrain");
1752 lDa.Fill(tmpDS, "land");
1753 lalDa.Fill(tmpDS, "landaccesslist");
1754
1755 foreach (DataColumn col in createPrimTable().Columns)
1756 {
1757 if (!tmpDS.Tables["prims"].Columns.Contains(col.ColumnName))
1758 {
1759 m_log.Info("[REGION DB]: Missing required column:" + col.ColumnName);
1760 return false;
1761 }
1762 }
1763
1764 foreach (DataColumn col in createShapeTable().Columns)
1765 {
1766 if (!tmpDS.Tables["primshapes"].Columns.Contains(col.ColumnName))
1767 {
1768 m_log.Info("[REGION DB]: Missing required column:" + col.ColumnName);
1769 return false;
1770 }
1771 }
1772
1773 // XXX primitems should probably go here eventually
1774
1775 foreach (DataColumn col in createTerrainTable().Columns)
1776 {
1777 if (!tmpDS.Tables["terrain"].Columns.Contains(col.ColumnName))
1778 {
1779 m_log.Info("[REGION DB]: Missing require column:" + col.ColumnName);
1780 return false;
1781 }
1782 }
1783
1784 foreach (DataColumn col in createLandTable().Columns)
1785 {
1786 if (!tmpDS.Tables["land"].Columns.Contains(col.ColumnName))
1787 {
1788 m_log.Info("[REGION DB]: Missing require column:" + col.ColumnName);
1789 return false;
1790 }
1791 }
1792
1793 foreach (DataColumn col in createLandAccessListTable().Columns)
1794 {
1795 if (!tmpDS.Tables["landaccesslist"].Columns.Contains(col.ColumnName))
1796 {
1797 m_log.Info("[REGION DB]: Missing require column:" + col.ColumnName);
1798 return false;
1799 }
1800 }
1801
1802 return true;
1803 }
1804
1805 /***********************************************************************
1806 *
1807 * Type conversion functions
1808 *
1809 **********************************************************************/
1810
1811 /// <summary>
1812 /// Type conversion function
1813 /// </summary>
1814 /// <param name="type">a Type</param>
1815 /// <returns>a DbType</returns>
1816 private static DbType dbtypeFromType(Type type)
1817 {
1818 if (type == typeof(String))
1819 {
1820 return DbType.String;
1821 }
1822 else if (type == typeof(Int32))
1823 {
1824 return DbType.Int32;
1825 }
1826 else if (type == typeof(Double))
1827 {
1828 return DbType.Double;
1829 }
1830 else if (type == typeof(Byte[]))
1831 {
1832 return DbType.Binary;
1833 }
1834 else
1835 {
1836 return DbType.String;
1837 }
1838 }
1839 }
1840}