diff options
Diffstat (limited to 'OpenSim/Data/MSSQL/MSSQLRegionData.cs')
-rw-r--r-- | OpenSim/Data/MSSQL/MSSQLRegionData.cs | 1840 |
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Data; | ||
31 | using System.Data.SqlClient; | ||
32 | using System.IO; | ||
33 | using System.Reflection; | ||
34 | using libsecondlife; | ||
35 | using log4net; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Environment.Interfaces; | ||
38 | using OpenSim.Region.Environment.Scenes; | ||
39 | |||
40 | namespace 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 | } | ||