From 3efdccbb12fc2d5339870ade39e1b1d54da4fe9b Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Wed, 26 Nov 2008 07:34:38 +0000 Subject: Committing the LCO database layer. Native MySQL, no ADO. New reconnect mechanism to prevent prim loss. Preserve link order on sim restart and drag copy. Fix drag-copied prims' inventories. Fix persistence of child prim inventories. --- OpenSim/Data/MySQL/MySQLRegionData.cs | 2212 +++++++------------- OpenSim/Data/MySQL/Resources/023_RegionStore.sql | 6 + OpenSim/Framework/TaskInventoryItem.cs | 1 + .../Region/Environment/Scenes/SceneObjectGroup.cs | 20 +- .../Region/Environment/Scenes/SceneObjectPart.cs | 10 +- .../Environment/Scenes/SceneObjectPartInventory.cs | 8 +- 6 files changed, 778 insertions(+), 1479 deletions(-) create mode 100644 OpenSim/Data/MySQL/Resources/023_RegionStore.sql (limited to 'OpenSim') diff --git a/OpenSim/Data/MySQL/MySQLRegionData.cs b/OpenSim/Data/MySQL/MySQLRegionData.cs index 2e36123..743c0d9 100644 --- a/OpenSim/Data/MySQL/MySQLRegionData.cs +++ b/OpenSim/Data/MySQL/MySQLRegionData.cs @@ -48,1107 +48,678 @@ namespace OpenSim.Data.MySQL { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private const string m_primSelect = "select * from prims"; - private const string m_shapeSelect = "select * from primshapes"; - private const string m_itemsSelect = "select * from primitems"; - private const string m_terrainSelect = "select * from terrain limit 1"; - private const string m_landSelect = "select * from land"; - private const string m_landAccessListSelect = "select * from landaccesslist"; - private const string m_regionSettingsSelect = "select * from regionsettings"; - private const string m_waitTimeoutSelect = "select @@wait_timeout"; - - private MySqlConnection m_connection; - private string m_connectionString; + private string m_ConnectionString; - /// - /// Wait timeout for our connection in ticks. - /// - private long m_waitTimeout; - - /// - /// Make our storage of the timeout this amount smaller than it actually is, to give us a margin on long - /// running database operations. - /// - private long m_waitTimeoutLeeway = 60 * TimeSpan.TicksPerSecond; - - /// - /// Holds the last tick time that the connection was used. - /// - private long m_lastConnectionUse; - - private DataSet m_dataSet; - private MySqlDataAdapter m_primDataAdapter; - private MySqlDataAdapter m_shapeDataAdapter; - private MySqlDataAdapter m_itemsDataAdapter; - private MySqlDataAdapter m_terrainDataAdapter; - private MySqlDataAdapter m_landDataAdapter; - private MySqlDataAdapter m_landAccessListDataAdapter; - private MySqlDataAdapter m_regionSettingsDataAdapter; - - private DataTable m_primTable; - private DataTable m_shapeTable; - private DataTable m_itemsTable; - private DataTable m_terrainTable; - private DataTable m_landTable; - private DataTable m_landAccessListTable; - private DataTable m_regionSettingsTable; - - /*********************************************************************** - * - * Public Interface Functions - * - **********************************************************************/ + private MySqlConnection m_Connection = null; - /// - /// see IRegionDataStore - /// - /// public void Initialise(string connectionString) { - m_connectionString = connectionString; + m_ConnectionString = connectionString; - m_dataSet = new DataSet(); + m_Connection = new MySqlConnection(m_ConnectionString); - int passPosition = 0; - int passEndPosition = 0; - string displayConnectionString = null; - - try - { // hide the password in the connection string - passPosition = m_connectionString.IndexOf("password", StringComparison.OrdinalIgnoreCase); - passPosition = m_connectionString.IndexOf("=", passPosition); - if (passPosition < m_connectionString.Length) - passPosition += 1; - passEndPosition = m_connectionString.IndexOf(";", passPosition); - - displayConnectionString = m_connectionString.Substring(0, passPosition); - displayConnectionString += "***"; - displayConnectionString += m_connectionString.Substring(passEndPosition, m_connectionString.Length - passEndPosition); - } - catch (Exception e ) - { - m_log.Debug("Exception: password not found in connection string\n" + e.ToString()); - } + m_Connection.Open(); - m_log.Info("[REGION DB]: MySql - connecting: " + displayConnectionString); - m_connection = new MySqlConnection(m_connectionString); - m_connection.Open(); - - GetWaitTimeout(); - - // This actually does the roll forward assembly stuff + // Apply new Migrations + // Assembly assem = GetType().Assembly; - Migration m = new Migration(m_connection, assem, "RegionStore"); + Migration m = new Migration(m_Connection, assem, "RegionStore"); m.Update(); - - MySqlCommand primSelectCmd = new MySqlCommand(m_primSelect, m_connection); - m_primDataAdapter = new MySqlDataAdapter(primSelectCmd); - - MySqlCommand shapeSelectCmd = new MySqlCommand(m_shapeSelect, m_connection); - m_shapeDataAdapter = new MySqlDataAdapter(shapeSelectCmd); - - MySqlCommand itemsSelectCmd = new MySqlCommand(m_itemsSelect, m_connection); - m_itemsDataAdapter = new MySqlDataAdapter(itemsSelectCmd); - - MySqlCommand terrainSelectCmd = new MySqlCommand(m_terrainSelect, m_connection); - m_terrainDataAdapter = new MySqlDataAdapter(terrainSelectCmd); - - MySqlCommand landSelectCmd = new MySqlCommand(m_landSelect, m_connection); - m_landDataAdapter = new MySqlDataAdapter(landSelectCmd); - - MySqlCommand landAccessListSelectCmd = new MySqlCommand(m_landAccessListSelect, m_connection); - m_landAccessListDataAdapter = new MySqlDataAdapter(landAccessListSelectCmd); - - MySqlCommand regionSettingsSelectCmd = new MySqlCommand(m_regionSettingsSelect, m_connection); - m_regionSettingsDataAdapter = new MySqlDataAdapter(regionSettingsSelectCmd); - - // TODO: move out the ADO.NET pieces here and just go to the db directly - lock (m_dataSet) - { - m_primTable = createPrimTable(); - m_dataSet.Tables.Add(m_primTable); - SetupPrimCommands(m_primDataAdapter, m_connection); - m_primDataAdapter.Fill(m_primTable); - - m_shapeTable = createShapeTable(); - m_dataSet.Tables.Add(m_shapeTable); - SetupShapeCommands(m_shapeDataAdapter, m_connection); - m_shapeDataAdapter.Fill(m_shapeTable); - - m_itemsTable = createItemsTable(); - m_dataSet.Tables.Add(m_itemsTable); - SetupItemsCommands(m_itemsDataAdapter, m_connection); - m_itemsDataAdapter.Fill(m_itemsTable); - - m_terrainTable = createTerrainTable(); - m_dataSet.Tables.Add(m_terrainTable); - SetupTerrainCommands(m_terrainDataAdapter, m_connection); - m_terrainDataAdapter.Fill(m_terrainTable); - - m_landTable = createLandTable(); - m_dataSet.Tables.Add(m_landTable); - setupLandCommands(m_landDataAdapter, m_connection); - m_landDataAdapter.Fill(m_landTable); - - m_landAccessListTable = createLandAccessListTable(); - m_dataSet.Tables.Add(m_landAccessListTable); - setupLandAccessCommands(m_landAccessListDataAdapter, m_connection); - m_landAccessListDataAdapter.Fill(m_landAccessListTable); - - m_regionSettingsTable = createRegionSettingsTable(); - m_dataSet.Tables.Add(m_regionSettingsTable); - SetupRegionSettingsCommands(m_regionSettingsDataAdapter, m_connection); - m_regionSettingsDataAdapter.Fill(m_regionSettingsTable); - } + // Clean dropped attachments + // + MySqlCommand cmd = m_Connection.CreateCommand(); + cmd.CommandText = "delete from prims, primshapes using prims " + + "left join primshapes on prims.uuid = primshapes.uuid " + + "where PCode = 9 and State <> 0"; + ExecuteNonQuery(cmd); } - public void Dispose() {} - - /// - /// Get the wait_timeout value for our connection - /// - protected void GetWaitTimeout() + private IDataReader ExecuteReader(MySqlCommand c) { - MySqlCommand cmd = new MySqlCommand(m_waitTimeoutSelect, m_connection); + IDataReader r = null; + bool errorSeen = false; - lock (m_dataSet) + while (true) { - MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow); try { - if (dbReader.Read()) - { - m_waitTimeout - = Convert.ToInt32(dbReader["@@wait_timeout"]) * TimeSpan.TicksPerSecond + m_waitTimeoutLeeway; - } - - cmd.Dispose(); + r = c.ExecuteReader(); } - finally + catch (MySqlException) { - dbReader.Close(); + System.Threading.Thread.Sleep(500); + + m_Connection.Close(); + m_Connection.Open(); + + if (!errorSeen) + { + errorSeen = true; + continue; + continue; + } + throw; } - } - m_lastConnectionUse = System.DateTime.Now.Ticks; + break; + } - m_log.DebugFormat( - "[REGION DB]: Connection wait timeout {0} seconds", m_waitTimeout / TimeSpan.TicksPerSecond); + return r; } - /// - /// Should be called before any db operation. This checks to see if the connection has not timed out - /// - protected void CheckConnection() + private void ExecuteNonQuery(MySqlCommand c) { - //m_log.Debug("[REGION DB]: Checking connection"); + bool errorSeen = false; - long timeNow = System.DateTime.Now.Ticks; - if (timeNow - m_lastConnectionUse > m_waitTimeout || m_connection.State != ConnectionState.Open) + while (true) { - m_log.DebugFormat("[REGION DB]: Database connection has gone away - reconnecting"); - - lock (m_connection) + try { - m_connection.Close(); - m_connection = new MySqlConnection(m_connectionString); - m_connection.Open(); + c.ExecuteNonQuery(); } - } - - // Strictly, we should set this after the actual db operation. But it's more convenient to set here rather - // than require the code to call another method - the timeout leeway should be large enough to cover the - // inaccuracy. - m_lastConnectionUse = timeNow; - } - - /// - /// Execute a SQL statement stored in a resource, as a string - /// - /// the ressource name - /// The database connection handler - public void ExecuteResourceSql(string name, MySqlConnection dbcon) - { - MySqlCommand cmd = new MySqlCommand(getResourceString(name), dbcon); - cmd.ExecuteNonQuery(); - } + catch (MySqlException) + { + System.Threading.Thread.Sleep(500); - /// - /// Extract a named string resource from the embedded resources - /// - /// name of embedded resource - /// string contained within the embedded resource - private string getResourceString(string name) - { - Assembly assem = GetType().Assembly; - string[] names = assem.GetManifestResourceNames(); + m_Connection.Close(); + m_Connection.Open(); - foreach (string s in names) - { - if (s.EndsWith(name)) - { - using (Stream resource = assem.GetManifestResourceStream(s)) + if (!errorSeen) { - using (StreamReader resourceReader = new StreamReader(resource)) - { - string resourceString = resourceReader.ReadToEnd(); - return resourceString; - } + errorSeen = true; + continue; } + throw; } + + break; } - throw new Exception(string.Format("Resource '{0}' was not found", name)); } - /// - /// Adds an object into region storage - /// - /// The object - /// The region UUID + public void Dispose() {} + public void StoreObject(SceneObjectGroup obj, UUID regionUUID) { - lock (m_dataSet) + uint flags = obj.RootPart.GetEffectiveObjectFlags(); + + // Eligibility check + // + if ((flags & (uint)PrimFlags.Temporary) != 0) + return; + if ((flags & (uint)PrimFlags.TemporaryOnRez) != 0) + return; + + lock (m_Connection) { + MySqlCommand cmd = m_Connection.CreateCommand(); + foreach (SceneObjectPart prim in obj.Children.Values) { - if ((prim.GetEffectiveObjectFlags() & (uint)PrimFlags.Temporary) == 0 - && (prim.GetEffectiveObjectFlags() & (uint)PrimFlags.TemporaryOnRez) == 0) - { - //m_log.Info("[REGION DB]: Adding obj: " + obj.UUID + " to region: " + regionUUID); - addPrim(prim, obj.UUID, regionUUID); - } - else - { - // m_log.Info("[DATASTORE]: Ignoring Physical obj: " + obj.UUID + " in region: " + regionUUID); - } + cmd.Parameters.Clear(); + + cmd.CommandText = "replace into prims ("+ + "UUID, ParentID, CreationDate, "+ + "Name, Text, Description, "+ + "SitName, TouchName, ObjectFlags, "+ + "OwnerMask, NextOwnerMask, GroupMask, "+ + "EveryoneMask, BaseMask, PositionX, "+ + "PositionY, PositionZ, GroupPositionX, "+ + "GroupPositionY, GroupPositionZ, VelocityX, "+ + "VelocityY, VelocityZ, AngularVelocityX, "+ + "AngularVelocityY, AngularVelocityZ, "+ + "AccelerationX, AccelerationY, "+ + "AccelerationZ, RotationX, "+ + "RotationY, RotationZ, "+ + "RotationW, SitTargetOffsetX, "+ + "SitTargetOffsetY, SitTargetOffsetZ, "+ + "SitTargetOrientW, SitTargetOrientX, "+ + "SitTargetOrientY, SitTargetOrientZ, "+ + "RegionUUID, CreatorID, "+ + "OwnerID, GroupID, "+ + "LastOwnerID, SceneGroupID, "+ + "PayPrice, PayButton1, "+ + "PayButton2, PayButton3, "+ + "PayButton4, LoopedSound, "+ + "LoopedSoundGain, TextureAnimation, "+ + "OmegaX, OmegaY, OmegaZ, "+ + "CameraEyeOffsetX, CameraEyeOffsetY, "+ + "CameraEyeOffsetZ, CameraAtOffsetX, "+ + "CameraAtOffsetY, CameraAtOffsetZ, "+ + "ForceMouselook, ScriptAccessPin, "+ + "AllowedDrop, DieAtEdge, "+ + "SalePrice, SaleType, "+ + "ColorR, ColorG, ColorB, ColorA, "+ + "ParticleSystem, ClickAction, Material, "+ + "CollisionSound, CollisionSoundVolume, "+ + "LinkNumber) values (" + "?UUID, ?ParentID, "+ + "?CreationDate, ?Name, ?Text, "+ + "?Description, ?SitName, ?TouchName, "+ + "?ObjectFlags, ?OwnerMask, ?NextOwnerMask, "+ + "?GroupMask, ?EveryoneMask, ?BaseMask, "+ + "?PositionX, ?PositionY, ?PositionZ, "+ + "?GroupPositionX, ?GroupPositionY, "+ + "?GroupPositionZ, ?VelocityX, "+ + "?VelocityY, ?VelocityZ, ?AngularVelocityX, "+ + "?AngularVelocityY, ?AngularVelocityZ, "+ + "?AccelerationX, ?AccelerationY, "+ + "?AccelerationZ, ?RotationX, "+ + "?RotationY, ?RotationZ, "+ + "?RotationW, ?SitTargetOffsetX, "+ + "?SitTargetOffsetY, ?SitTargetOffsetZ, "+ + "?SitTargetOrientW, ?SitTargetOrientX, "+ + "?SitTargetOrientY, ?SitTargetOrientZ, "+ + "?RegionUUID, ?CreatorID, ?OwnerID, "+ + "?GroupID, ?LastOwnerID, ?SceneGroupID, "+ + "?PayPrice, ?PayButton1, ?PayButton2, "+ + "?PayButton3, ?PayButton4, ?LoopedSound, "+ + "?LoopedSoundGain, ?TextureAnimation, "+ + "?OmegaX, ?OmegaY, ?OmegaZ, "+ + "?CameraEyeOffsetX, ?CameraEyeOffsetY, "+ + "?CameraEyeOffsetZ, ?CameraAtOffsetX, "+ + "?CameraAtOffsetY, ?CameraAtOffsetZ, "+ + "?ForceMouselook, ?ScriptAccessPin, "+ + "?AllowedDrop, ?DieAtEdge, ?SalePrice, "+ + "?SaleType, ?ColorR, ?ColorG, "+ + "?ColorB, ?ColorA, ?ParticleSystem, "+ + "?ClickAction, ?Material, ?CollisionSound, "+ + "?CollisionSoundVolume, ?LinkNumber)"; + + FillPrimCommand(cmd, prim, obj.UUID, regionUUID); + + ExecuteNonQuery(cmd); + + cmd.Parameters.Clear(); + + cmd.CommandText = "replace into primshapes ("+ + "UUID, Shape, ScaleX, ScaleY, "+ + "ScaleZ, PCode, PathBegin, PathEnd, "+ + "PathScaleX, PathScaleY, PathShearX, "+ + "PathShearY, PathSkew, PathCurve, "+ + "PathRadiusOffset, PathRevolutions, "+ + "PathTaperX, PathTaperY, PathTwist, "+ + "PathTwistBegin, ProfileBegin, ProfileEnd, "+ + "ProfileCurve, ProfileHollow, Texture, "+ + "ExtraParams, State) values (?UUID, "+ + "?Shape, ?ScaleX, ?ScaleY, ?ScaleZ, "+ + "?PCode, ?PathBegin, ?PathEnd, "+ + "?PathScaleX, ?PathScaleY, "+ + "?PathShearX, ?PathShearY, "+ + "?PathSkew, ?PathCurve, ?PathRadiusOffset, "+ + "?PathRevolutions, ?PathTaperX, "+ + "?PathTaperY, ?PathTwist, "+ + "?PathTwistBegin, ?ProfileBegin, "+ + "?ProfileEnd, ?ProfileCurve, "+ + "?ProfileHollow, ?Texture, ?ExtraParams, "+ + "?State)"; + + FillShapeCommand(cmd, prim); + + ExecuteNonQuery(cmd); } - Commit(); } } - /// - /// removes an object from region storage - /// - /// The object - /// The Region UUID public void RemoveObject(UUID obj, UUID regionUUID) { - m_log.InfoFormat("[REGION DB]: Removing obj: {0} from region: {1}", obj, regionUUID); + // Formerly, this used to check the region UUID. + // That makes no sense, as we remove the contents of a prim + // unconditionally, but the prim dependent on the region ID. + // So, we would destroy an object and cause hard to detect + // issues if we delete the contents only. Deleting it all may + // cause the loss of a prim, but is cleaner. + // It's also faster because it uses the primary key. + // + lock (m_Connection) + { + MySqlCommand cmd = m_Connection.CreateCommand(); - DataTable prims = m_primTable; - DataTable shapes = m_shapeTable; + cmd.CommandText = "select UUID from prims where "+ + "SceneGroupID= ?UUID"; - string selectExp = "SceneGroupID = '" + Util.ToRawUuidString(obj) + "' and RegionUUID = '" + Util.ToRawUuidString(regionUUID) + "'"; - lock (m_dataSet) - { - DataRow[] primRows = prims.Select(selectExp); - foreach (DataRow row in primRows) + cmd.Parameters.AddWithValue("UUID", Util.ToRawUuidString(obj)); + + List uuids = new List(); + + IDataReader reader = ExecuteReader(cmd); + + try { - // Remove shapes row - UUID uuid = new UUID((string) row["UUID"]); - DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(uuid)); - if (shapeRow != null) + while(reader.Read()) { - shapeRow.Delete(); + uuids.Add(new UUID(reader["UUID"].ToString())); } + } + finally + { + reader.Close(); + } + foreach (UUID uuid in uuids) RemoveItems(uuid); - // Remove prim row - row.Delete(); - } - Commit(); + cmd.CommandText = "delete from prims where SceneGroupID= ?UUID"; + + ExecuteNonQuery(cmd); + + cmd.CommandText = "delete from primshapes where UUID = ?UUID"; + + ExecuteNonQuery(cmd); } } - /// - /// Remove all persisted items of the given prim. - /// The caller must acquire the necessrary synchronization locks and commit or rollback changes. - /// - /// the Item UUID private void RemoveItems(UUID uuid) { - String sql = String.Format("primID = '{0}'", uuid); - DataRow[] itemRows = m_itemsTable.Select(sql); - - foreach (DataRow itemRow in itemRows) + lock (m_Connection) { - itemRow.Delete(); + MySqlCommand cmd = m_Connection.CreateCommand(); + + cmd.CommandText = "delete from primitems where " + + "PrimID = ?PrimID"; + + cmd.Parameters.AddWithValue("PrimID", uuid.ToString()); + + ExecuteNonQuery(cmd); } } - /// - /// Load persisted objects from region storage. - /// - /// the Region UUID - /// List of loaded groups public List LoadObjects(UUID regionUUID) { - Dictionary createdObjects = new Dictionary(); - - List retvals = new List(); - - DataTable prims = m_primTable; - DataTable shapes = m_shapeTable; + UUID lastGroupID = UUID.Zero; + List objects = new List(); + List prims = new List(); + SceneObjectGroup grp = null; - string byRegion = "RegionUUID = '" + Util.ToRawUuidString(regionUUID) + "'"; - string orderByParent = "ParentID ASC"; - - lock (m_dataSet) + lock (m_Connection) { - CheckConnection(); - DataRow[] primsForRegion = prims.Select(byRegion, orderByParent); - m_log.Info("[REGION DB]: " + - "Loaded " + primsForRegion.Length + " prims for region: " + regionUUID); + MySqlCommand cmd = m_Connection.CreateCommand(); + + cmd.CommandText = "select *, " + + "case when prims.UUID = SceneGroupID " + + "then 0 else 1 end as sort from prims " + + "left join primshapes on prims.UUID = primshapes.UUID "+ + "where RegionUUID = ?RegionUUID " + + "order by SceneGroupID asc, sort asc, LinkNumber asc"; - // First, create all groups - foreach (DataRow primRow in primsForRegion) + cmd.Parameters.AddWithValue("RegionUUID", + Util.ToRawUuidString(regionUUID)); + + IDataReader reader = ExecuteReader(cmd); + + try { - try + while (reader.Read()) { - string uuid = (string) primRow["UUID"]; - string objID = (string) primRow["SceneGroupID"]; + SceneObjectPart prim = BuildPrim(reader); + if (reader["Shape"] is DBNull) + prim.Shape = PrimitiveBaseShape.Default; + else + prim.Shape = BuildShape(reader); - SceneObjectPart prim = buildPrim(primRow); + prim.FolderID = prim.UUID; // A relic from when we + // we thought prims contained + // folder objects. In + // reality, prim == folder + prims.Add(prim); - if (uuid == objID) //is new SceneObjectGroup ? - { - SceneObjectGroup group = new SceneObjectGroup(); + UUID groupID = new UUID(reader["SceneGroupID"].ToString()); - DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID)); - if (shapeRow != null) - { - prim.Shape = buildShape(shapeRow); - } - else - { - m_log.Info( - "No shape found for prim in storage, so setting default box shape"); - prim.Shape = PrimitiveBaseShape.Default; - } - - group.SetRootPart(prim); - createdObjects.Add(group.UUID, group); - retvals.Add(group); - LoadItems(prim); - } - } - catch (Exception e) - { - m_log.Error("[REGION DB]: Failed create prim object, exception and data follows"); - m_log.Info("[REGION DB]: " + e.ToString()); - foreach (DataColumn col in prims.Columns) + if (groupID != lastGroupID) // New SOG { - m_log.Info("[REGION DB]: Col: " + col.ColumnName + " => " + primRow[col]); - } - } - } - - // Now fill the groups with part data - foreach (DataRow primRow in primsForRegion) - { - try - { - string uuid = (string) primRow["UUID"]; - string objID = (string) primRow["SceneGroupID"]; + if (grp != null) + objects.Add(grp); - SceneObjectPart prim = buildPrim(primRow); + lastGroupID = groupID; - if (uuid != objID) //is new SceneObjectGroup ? - { - DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID)); - if (shapeRow != null) - { - prim.Shape = buildShape(shapeRow); - } - else - { - m_log.Info( - "No shape found for prim in storage, so setting default box shape"); - prim.Shape = PrimitiveBaseShape.Default; - } - createdObjects[new UUID(objID)].AddPart(prim); - LoadItems(prim); + grp = new SceneObjectGroup(prim); } - } - catch (Exception e) - { - m_log.Error("[REGION DB]: Failed create prim object, exception and data follows"); - m_log.Info("[REGION DB]: " + e.ToString()); - foreach (DataColumn col in prims.Columns) + else { - m_log.Info("[REGION DB]: Col: " + col.ColumnName + " => " + primRow[col]); + // Black magic to preserve link numbers + // + int link = prim.LinkNum; + + grp.AddPart(prim); + + if (link != 0) + prim.LinkNum = link; } } } + finally + { + reader.Close(); + } + + if (grp != null) + objects.Add(grp); } - return retvals; + + foreach (SceneObjectPart part in prims) + LoadItems(part); + + m_log.DebugFormat("[DATABASE] Loaded {0} objects using {1} prims", objects.Count, prims.Count); + + return objects; } - /// - /// Load in a prim's persisted inventory. - /// - /// The prim private void LoadItems(SceneObjectPart prim) { - lock (m_dataSet) + lock (m_Connection) { - CheckConnection(); - //m_log.InfoFormat("[DATASTORE]: Loading inventory for {0}, {1}", prim.Name, prim.UUID); + MySqlCommand cmd = m_Connection.CreateCommand(); - DataTable dbItems = m_itemsTable; + cmd.CommandText = "select * from primitems where "+ + "PrimID = ?PrimID"; - String sql = String.Format("primID = '{0}'", prim.UUID.ToString()); - DataRow[] dbItemRows = dbItems.Select(sql); - IList inventory = new List(); + cmd.Parameters.AddWithValue("PrimID", prim.UUID.ToString()); - foreach (DataRow row in dbItemRows) + IDataReader reader = ExecuteReader(cmd); + List inventory = + new List(); + + try { - TaskInventoryItem item = buildItem(row); - inventory.Add(item); + while (reader.Read()) + { + TaskInventoryItem item = BuildItem(reader); - //m_log.DebugFormat("[DATASTORE]: Restored item {0}, {1}", item.Name, item.ItemID); + item.ParentID = prim.UUID; // Values in database are + // often wrong + inventory.Add(item); + } } - - prim.Inventory.RestoreInventoryItems(inventory); - - // XXX A nasty little hack to recover the folder id for the prim (which is currently stored in - // every item). This data should really be stored in the prim table itself. - if (dbItemRows.Length > 0) + finally { - prim.FolderID = inventory[0].ParentID; + reader.Close(); } + + prim.Inventory.RestoreInventoryItems(inventory); } } - /// - /// Store a terrain revision in region storage - /// - /// HeightField data - /// region UUID public void StoreTerrain(double[,] ter, UUID regionID) { - int revision = 1; - m_log.Info("[REGION DB]: Storing terrain revision r" + revision.ToString()); + m_log.Info("[REGION DB]: Storing terrain"); - lock (m_dataSet) + lock (m_Connection) { - MySqlCommand delete = new MySqlCommand("delete from terrain where RegionUUID=?RegionUUID", m_connection); - MySqlCommand cmd = new MySqlCommand("insert into terrain(RegionUUID, Revision, Heightfield)" + - " values(?RegionUUID, ?Revision, ?Heightfield)", m_connection); - using (cmd) - { - delete.Parameters.Add(new MySqlParameter("?RegionUUID", Util.ToRawUuidString(regionID))); + MySqlCommand cmd = m_Connection.CreateCommand(); - CheckConnection(); - delete.ExecuteNonQuery(); + cmd.CommandText = "delete from terrain where " + + "RegionUUID = ?RegionUUID"; + cmd.Parameters.AddWithValue("RegionUUID", + Util.ToRawUuidString(regionID)); - cmd.Parameters.Add(new MySqlParameter("?RegionUUID", Util.ToRawUuidString(regionID))); - cmd.Parameters.Add(new MySqlParameter("?Revision", revision)); - cmd.Parameters.Add(new MySqlParameter("?Heightfield", serializeTerrain(ter))); - cmd.ExecuteNonQuery(); - } + ExecuteNonQuery(cmd); + + cmd.CommandText = "insert into terrain (RegionUUID, " + + "Revision, Heightfield) values (?RegionUUID, " + + "1, ?Heightfield)"; + + cmd.Parameters.AddWithValue("Heightfield", + SerializeTerrain(ter)); + + ExecuteNonQuery(cmd); } } - /// - /// Load the latest terrain revision from region storage - /// - /// the region UUID - /// Heightfield data public double[,] LoadTerrain(UUID regionID) { - double[,] terret = new double[256,256]; - terret.Initialize(); + double[,] terrain = new double[256,256]; + terrain.Initialize(); - MySqlCommand cmd = new MySqlCommand( - @"select RegionUUID, Revision, Heightfield from terrain - where RegionUUID=?RegionUUID order by Revision desc limit 1" - , m_connection); - - // MySqlParameter param = new MySqlParameter(); - cmd.Parameters.Add(new MySqlParameter("?RegionUUID", Util.ToRawUuidString(regionID))); - - if (m_connection.State != ConnectionState.Open) + lock (m_Connection) { - m_connection.Open(); - } + MySqlCommand cmd = m_Connection.CreateCommand(); + cmd.CommandText = "select RegionUUID, Revision, Heightfield " + + "from terrain where RegionUUID = ?RegionUUID "+ + "order by Revision desc limit 1"; + cmd.Parameters.AddWithValue("RegionUUID", Util.ToRawUuidString(regionID)); + + IDataReader reader = ExecuteReader(cmd); - lock (m_dataSet) - { - CheckConnection(); - MySqlDataReader row = cmd.ExecuteReader(); try { - int rev = 0; - if (row.Read()) + while (reader.Read()) { - MemoryStream str = new MemoryStream((byte[]) row["Heightfield"]); - BinaryReader br = new BinaryReader(str); + MemoryStream mstr = new MemoryStream((byte[]) reader["Heightfield"]); + int rev = 0; + + BinaryReader br = new BinaryReader(mstr); for (int x = 0; x < 256; x++) { for (int y = 0; y < 256; y++) { - terret[x, y] = br.ReadDouble(); + terrain[x, y] = br.ReadDouble(); } + rev = Convert.ToInt32(reader["Revision"]); } - rev = (int) row["Revision"]; - } - else - { - m_log.Info("[REGION DB]: No terrain found for region"); - return null; - } + m_log.InfoFormat("[REGION DB]: Loaded terrain " + + "revision r{0}", rev); - m_log.Info("[REGION DB]: Loaded terrain revision r" + rev.ToString()); + return terrain; + } } finally { - row.Close(); + reader.Close(); } } - return terret; + + return terrain; } - /// - /// - /// delete from land where UUID=globalID - /// delete from landaccesslist where LandUUID=globalID - /// - /// - /// public void RemoveLandObject(UUID globalID) { - lock (m_dataSet) + lock (m_Connection) { - CheckConnection(); - using (MySqlCommand cmd = new MySqlCommand("delete from land where UUID=?UUID", m_connection)) - { - cmd.Parameters.Add(new MySqlParameter("?UUID", Util.ToRawUuidString(globalID))); - cmd.ExecuteNonQuery(); - } + MySqlCommand cmd = m_Connection.CreateCommand(); - using ( - MySqlCommand cmd = new MySqlCommand("delete from landaccesslist where LandUUID=?UUID", m_connection) - ) - { - cmd.Parameters.Add(new MySqlParameter("?UUID", Util.ToRawUuidString(globalID))); - cmd.ExecuteNonQuery(); - } + cmd.CommandText = "delete from land where UUID = ?UUID"; + + cmd.Parameters.AddWithValue("UUID", Util.ToRawUuidString(globalID)); + + ExecuteNonQuery(cmd); } } - /// - /// - /// public void StoreLandObject(ILandObject parcel) { - lock (m_dataSet) + lock (m_Connection) { - CheckConnection(); - DataTable land = m_landTable; - DataTable landaccesslist = m_landAccessListTable; - - DataRow landRow = land.Rows.Find(Util.ToRawUuidString(parcel.landData.GlobalID)); - if (landRow == null) - { - landRow = land.NewRow(); - fillLandRow(landRow, parcel.landData, parcel.regionUUID); - land.Rows.Add(landRow); - } - else - { - fillLandRow(landRow, parcel.landData, parcel.regionUUID); - } - - using ( - MySqlCommand cmd = - new MySqlCommand("delete from landaccesslist where LandUUID=?LandUUID", m_connection)) + MySqlCommand cmd = m_Connection.CreateCommand(); + + cmd.CommandText = "replace into land (UUID, RegionUUID, " + + "LocalLandID, Bitmap, Name, Description, " + + "OwnerUUID, IsGroupOwned, Area, AuctionID, " + + "Category, ClaimDate, ClaimPrice, GroupUUID, " + + "SalePrice, LandStatus, LandFlags, LandingType, " + + "MediaAutoScale, MediaTextureUUID, MediaURL, " + + "MusicURL, PassHours, PassPrice, SnapshotUUID, " + + "UserLocationX, UserLocationY, UserLocationZ, " + + "UserLookAtX, UserLookAtY, UserLookAtZ, " + + "AuthbuyerID, OtherCleanTime, Dwell) values (" + + "?UUID, ?RegionUUID, " + + "?LocalLandID, ?Bitmap, ?Name, ?Description, " + + "?OwnerUUID, ?IsGroupOwned, ?Area, ?AuctionID, " + + "?Category, ?ClaimDate, ?ClaimPrice, ?GroupUUID, " + + "?SalePrice, ?LandStatus, ?LandFlags, ?LandingType, " + + "?MediaAutoScale, ?MediaTextureUUID, ?MediaURL, " + + "?MusicURL, ?PassHours, ?PassPrice, ?SnapshotUUID, " + + "?UserLocationX, ?UserLocationY, ?UserLocationZ, " + + "?UserLookAtX, ?UserLookAtY, ?UserLookAtZ, " + + "?AuthbuyerID, ?OtherCleanTime, ?Dwell)"; + + FillLandCommand(cmd, parcel.landData, parcel.regionUUID); + + ExecuteNonQuery(cmd); + + cmd.CommandText = "delete from landaccesslist where " + + "LandUUID = ?UUID"; + + ExecuteNonQuery(cmd); + + cmd.Parameters.Clear(); + cmd.CommandText = "insert into landaccesslist (LandUUID, " + + "AccessUUID, Flags) values (?LandUUID, ?AccessUUID, " + + "?Flags)"; + + foreach (ParcelManager.ParcelAccessEntry entry in + parcel.landData.ParcelAccessList) { - cmd.Parameters.Add(new MySqlParameter("?LandUUID", Util.ToRawUuidString(parcel.landData.GlobalID))); - cmd.ExecuteNonQuery(); + FillLandAccessCommand(cmd, entry, parcel.landData.GlobalID); + ExecuteNonQuery(cmd); + cmd.Parameters.Clear(); } - - foreach (ParcelManager.ParcelAccessEntry entry in parcel.landData.ParcelAccessList) - { - DataRow newAccessRow = landaccesslist.NewRow(); - fillLandAccessRow(newAccessRow, entry, parcel.landData.GlobalID); - landaccesslist.Rows.Add(newAccessRow); - } - - Commit(); } } public RegionSettings LoadRegionSettings(UUID regionUUID) { - lock (m_dataSet) - { - CheckConnection(); - DataTable regionsettings = m_regionSettingsTable; - string searchExp = "regionUUID = '" + regionUUID.ToString() + "'"; - DataRow[] rawsettings = regionsettings.Select(searchExp); - if (rawsettings.Length == 0) - { - RegionSettings rs = new RegionSettings(); - rs.RegionUUID = regionUUID; - rs.OnSave += StoreRegionSettings; - - StoreRegionSettings(rs); + RegionSettings rs = null; - return rs; - } - DataRow row = rawsettings[0]; - - RegionSettings newSettings = buildRegionSettings(row); - newSettings.OnSave += StoreRegionSettings; - - return newSettings; - } - } - - public void StoreRegionSettings(RegionSettings rs) - { - lock (m_dataSet) + lock (m_Connection) { - CheckConnection(); - DataTable regionsettings = m_dataSet.Tables["regionsettings"]; + MySqlCommand cmd = m_Connection.CreateCommand(); - DataRow settingsRow = regionsettings.Rows.Find(rs.RegionUUID.ToString()); - if (settingsRow == null) - { - settingsRow = regionsettings.NewRow(); - fillRegionSettingsRow(settingsRow, rs); - regionsettings.Rows.Add(settingsRow); - } - else - { - fillRegionSettingsRow(settingsRow, rs); - } + cmd.CommandText = "select * from regionsettings where " + + "regionUUID = ?RegionUUID"; + cmd.Parameters.AddWithValue("regionUUID", regionUUID); - Commit(); - } - } + IDataReader reader = ExecuteReader(cmd); - /// - /// - /// - /// - /// - public List LoadLandObjects(UUID regionUUID) - { - List landDataForRegion = new List(); - lock (m_dataSet) - { - CheckConnection(); - DataTable land = m_landTable; - DataTable landaccesslist = m_landAccessListTable; - string searchExp = "RegionUUID = '" + Util.ToRawUuidString(regionUUID) + "'"; - DataRow[] rawDataForRegion = land.Select(searchExp); - foreach (DataRow rawDataLand in rawDataForRegion) + try { - LandData newLand = buildLandData(rawDataLand); - string accessListSearchExp = "LandUUID = '" + Util.ToRawUuidString(newLand.GlobalID) + "'"; - DataRow[] rawDataForLandAccessList = landaccesslist.Select(accessListSearchExp); - foreach (DataRow rawDataLandAccess in rawDataForLandAccessList) + if (reader.Read()) { - newLand.ParcelAccessList.Add(buildLandAccessData(rawDataLandAccess)); + rs = BuildRegionSettings(reader); + rs.OnSave += StoreRegionSettings; } + else + { + rs = new RegionSettings(); + rs.RegionUUID = regionUUID; + rs.OnSave += StoreRegionSettings; - landDataForRegion.Add(newLand); + StoreRegionSettings(rs); + } + } + finally + { + reader.Close(); } } - return landDataForRegion; + + return rs; } - /// - /// - /// - public void Commit() + public void StoreRegionSettings(RegionSettings rs) { - lock (m_dataSet) + lock (m_Connection) { - CheckConnection(); - // DisplayDataSet(m_dataSet, "Region DataSet"); - - m_primDataAdapter.Update(m_primTable); - m_shapeDataAdapter.Update(m_shapeTable); - - m_itemsDataAdapter.Update(m_itemsTable); - - m_terrainDataAdapter.Update(m_terrainTable); - m_landDataAdapter.Update(m_landTable); - m_landAccessListDataAdapter.Update(m_landAccessListTable); - m_regionSettingsDataAdapter.Update(m_regionSettingsTable); - - m_dataSet.AcceptChanges(); + MySqlCommand cmd = m_Connection.CreateCommand(); + + cmd.CommandText = "replace into regionsettings (regionUUID, " + + "block_terraform, block_fly, allow_damage, " + + "restrict_pushing, allow_land_resell, " + + "allow_land_join_divide, block_show_in_search, " + + "agent_limit, object_bonus, maturity, " + + "disable_scripts, disable_collisions, " + + "disable_physics, terrain_texture_1, " + + "terrain_texture_2, terrain_texture_3, " + + "terrain_texture_4, elevation_1_nw, " + + "elevation_2_nw, elevation_1_ne, " + + "elevation_2_ne, elevation_1_se, "+ + "elevation_2_se, elevation_1_sw, "+ + "elevation_2_sw, water_height, " + + "terrain_raise_limit, terrain_lower_limit, " + + "use_estate_sun, fixed_sun, sun_position, " + + "covenant, Sandbox, sunvectorx, sunvectory, " + + "sunvectorz) values ( ?RegionUUID, ?BlockTerraform, " + + "?BlockFly, ?AllowDamage, ?RestrictPushing, " + + "?AllowLandResell, ?AllowLandJoinDivide, " + + "?BlockShowInSearch, ?AgentLimit, ?ObjectBonus, " + + "?Maturity, ?DisableScripts, ?DisableCollisions, " + + "?DisablePhysics, ?TerrainTexture1, " + + "?TerrainTexture2, ?TerrainTexture3, " + + "?TerrainTexture4, ?Elevation1NW, ?Elevation2NW, " + + "?Elevation1NE, ?Elevation2NE, ?Elevation1SE, " + + "?Elevation2SE, ?Elevation1SW, ?Elevation2SW, " + + "?WaterHeight, ?TerrainRaiseLimit, " + + "?TerrainLowerLimit, ?UseEstateSun, ?FixedSun, " + + "?SunPosition, ?Covenant, ?Sandbox, " + + "?SunVectorX, ?SunVectorY, ?SunVectorZ)"; + + FillRegionSettingsCommand(cmd, rs); + + ExecuteNonQuery(cmd); } } - /// - /// See - /// - public void Shutdown() - { - Commit(); - } - - /*********************************************************************** - * - * Database Definition Functions - * - * This should be db agnostic as we define them in ADO.NET terms - * - **********************************************************************/ - - /// - /// - /// - /// - /// - /// - /// - private static DataColumn createCol(DataTable dt, string name, Type type) - { - DataColumn col = new DataColumn(name, type); - dt.Columns.Add(col); - return col; - } - - /// - /// Create the "terrain" table - /// - /// - private static DataTable createTerrainTable() - { - DataTable terrain = new DataTable("terrain"); - - createCol(terrain, "RegionUUID", typeof (String)); - createCol(terrain, "Revision", typeof (Int32)); - createCol(terrain, "Heightfield", typeof (Byte[])); - return terrain; - } - - /// - /// Create the "regionsettings" table - /// - /// - private static DataTable createRegionSettingsTable() - { - DataTable regionsettings = new DataTable("regionsettings"); - createCol(regionsettings, "regionUUID", typeof(String)); - createCol(regionsettings, "block_terraform", typeof (Int32)); - createCol(regionsettings, "block_fly", typeof (Int32)); - createCol(regionsettings, "allow_damage", typeof (Int32)); - createCol(regionsettings, "restrict_pushing", typeof (Int32)); - createCol(regionsettings, "allow_land_resell", typeof (Int32)); - createCol(regionsettings, "allow_land_join_divide", typeof (Int32)); - createCol(regionsettings, "block_show_in_search", typeof (Int32)); - createCol(regionsettings, "agent_limit", typeof (Int32)); - createCol(regionsettings, "object_bonus", typeof (Double)); - createCol(regionsettings, "maturity", typeof (Int32)); - createCol(regionsettings, "disable_scripts", typeof (Int32)); - createCol(regionsettings, "disable_collisions", typeof (Int32)); - createCol(regionsettings, "disable_physics", typeof (Int32)); - createCol(regionsettings, "terrain_texture_1", typeof(String)); - createCol(regionsettings, "terrain_texture_2", typeof(String)); - createCol(regionsettings, "terrain_texture_3", typeof(String)); - createCol(regionsettings, "terrain_texture_4", typeof(String)); - createCol(regionsettings, "elevation_1_nw", typeof (Double)); - createCol(regionsettings, "elevation_2_nw", typeof (Double)); - createCol(regionsettings, "elevation_1_ne", typeof (Double)); - createCol(regionsettings, "elevation_2_ne", typeof (Double)); - createCol(regionsettings, "elevation_1_se", typeof (Double)); - createCol(regionsettings, "elevation_2_se", typeof (Double)); - createCol(regionsettings, "elevation_1_sw", typeof (Double)); - createCol(regionsettings, "elevation_2_sw", typeof (Double)); - createCol(regionsettings, "water_height", typeof (Double)); - createCol(regionsettings, "terrain_raise_limit", typeof (Double)); - createCol(regionsettings, "terrain_lower_limit", typeof (Double)); - createCol(regionsettings, "use_estate_sun", typeof (Int32)); - createCol(regionsettings, "sandbox", typeof (Int32)); - createCol(regionsettings, "sunvectorx",typeof (Double)); - createCol(regionsettings, "sunvectory",typeof (Double)); - createCol(regionsettings, "sunvectorz",typeof (Double)); - createCol(regionsettings, "fixed_sun", typeof (Int32)); - createCol(regionsettings, "sun_position", typeof (Double)); - createCol(regionsettings, "covenant", typeof(String)); - - regionsettings.PrimaryKey = new DataColumn[] {regionsettings.Columns["RegionUUID"]}; - - return regionsettings; - } - - /// - /// Create the "prims" table - /// - /// - private static DataTable createPrimTable() + public List LoadLandObjects(UUID regionUUID) { - DataTable prims = new DataTable("prims"); - - createCol(prims, "UUID", typeof (String)); - createCol(prims, "RegionUUID", typeof (String)); - createCol(prims, "ParentID", typeof (Int32)); - createCol(prims, "CreationDate", typeof (Int32)); - createCol(prims, "Name", typeof (String)); - createCol(prims, "SceneGroupID", typeof (String)); - // various text fields - createCol(prims, "Text", typeof (String)); - createCol(prims, "ColorR", typeof (Int32)); - createCol(prims, "ColorG", typeof (Int32)); - createCol(prims, "ColorB", typeof (Int32)); - createCol(prims, "ColorA", typeof (Int32)); - createCol(prims, "Description", typeof (String)); - createCol(prims, "SitName", typeof (String)); - createCol(prims, "TouchName", typeof (String)); - // permissions - createCol(prims, "ObjectFlags", typeof (Int32)); - createCol(prims, "CreatorID", typeof (String)); - createCol(prims, "OwnerID", typeof (String)); - createCol(prims, "GroupID", typeof (String)); - createCol(prims, "LastOwnerID", typeof (String)); - createCol(prims, "OwnerMask", typeof (Int32)); - createCol(prims, "NextOwnerMask", typeof (Int32)); - createCol(prims, "GroupMask", typeof (Int32)); - createCol(prims, "EveryoneMask", typeof (Int32)); - createCol(prims, "BaseMask", typeof (Int32)); - // vectors - createCol(prims, "PositionX", typeof (Double)); - createCol(prims, "PositionY", typeof (Double)); - createCol(prims, "PositionZ", typeof (Double)); - createCol(prims, "GroupPositionX", typeof (Double)); - createCol(prims, "GroupPositionY", typeof (Double)); - createCol(prims, "GroupPositionZ", typeof (Double)); - createCol(prims, "VelocityX", typeof (Double)); - createCol(prims, "VelocityY", typeof (Double)); - createCol(prims, "VelocityZ", typeof (Double)); - createCol(prims, "AngularVelocityX", typeof (Double)); - createCol(prims, "AngularVelocityY", typeof (Double)); - createCol(prims, "AngularVelocityZ", typeof (Double)); - createCol(prims, "AccelerationX", typeof (Double)); - createCol(prims, "AccelerationY", typeof (Double)); - createCol(prims, "AccelerationZ", typeof (Double)); - // quaternions - createCol(prims, "RotationX", typeof (Double)); - createCol(prims, "RotationY", typeof (Double)); - createCol(prims, "RotationZ", typeof (Double)); - createCol(prims, "RotationW", typeof (Double)); - // sit target - createCol(prims, "SitTargetOffsetX", typeof (Double)); - createCol(prims, "SitTargetOffsetY", typeof (Double)); - createCol(prims, "SitTargetOffsetZ", typeof (Double)); - - createCol(prims, "SitTargetOrientW", typeof (Double)); - createCol(prims, "SitTargetOrientX", typeof (Double)); - createCol(prims, "SitTargetOrientY", typeof (Double)); - createCol(prims, "SitTargetOrientZ", typeof (Double)); - - createCol(prims, "PayPrice", typeof(Int32)); - createCol(prims, "PayButton1", typeof(Int32)); - createCol(prims, "PayButton2", typeof(Int32)); - createCol(prims, "PayButton3", typeof(Int32)); - createCol(prims, "PayButton4", typeof(Int32)); - - createCol(prims, "LoopedSound", typeof(String)); - createCol(prims, "LoopedSoundGain", typeof(Double)); - createCol(prims, "TextureAnimation", typeof(Byte[])); - createCol(prims, "ParticleSystem", typeof(Byte[])); - - createCol(prims, "OmegaX", typeof (Double)); - createCol(prims, "OmegaY", typeof (Double)); - createCol(prims, "OmegaZ", typeof (Double)); - - createCol(prims, "CameraEyeOffsetX", typeof (Double)); - createCol(prims, "CameraEyeOffsetY", typeof (Double)); - createCol(prims, "CameraEyeOffsetZ", typeof (Double)); + List landData = new List(); - createCol(prims, "CameraAtOffsetX", typeof (Double)); - createCol(prims, "CameraAtOffsetY", typeof (Double)); - createCol(prims, "CameraAtOffsetZ", typeof (Double)); - - createCol(prims, "ForceMouselook", typeof (Int16)); - - createCol(prims, "ScriptAccessPin", typeof(Int32)); - - createCol(prims, "AllowedDrop", typeof (Int16)); - createCol(prims, "DieAtEdge", typeof (Int16)); - - createCol(prims, "SalePrice", typeof(Int32)); - createCol(prims, "SaleType", typeof (Int16)); - - createCol(prims, "ClickAction", typeof (Byte)); - createCol(prims, "Material", typeof (Byte)); + lock (m_Connection) + { + MySqlCommand cmd = m_Connection.CreateCommand(); - createCol(prims, "CollisionSound", typeof(String)); - createCol(prims, "CollisionSoundVolume", typeof(Double)); + cmd.CommandText = "select * from land where " + + "RegionUUID = ?RegionUUID"; - // Add in contraints - prims.PrimaryKey = new DataColumn[] {prims.Columns["UUID"]}; + cmd.Parameters.AddWithValue("RegionUUID", + Util.ToRawUuidString(regionUUID)); - return prims; - } + IDataReader reader = ExecuteReader(cmd); - /// - /// Create the "land" table - /// - /// - private static DataTable createLandTable() - { - DataTable land = new DataTable("land"); - createCol(land, "UUID", typeof (String)); - createCol(land, "RegionUUID", typeof (String)); - createCol(land, "LocalLandID", typeof (Int32)); + try + { + while (reader.Read()) + { + LandData newLand = BuildLandData(reader); + landData.Add(newLand); + } + } + finally + { + reader.Close(); + } - // Bitmap is a byte[512] - createCol(land, "Bitmap", typeof (Byte[])); - - createCol(land, "Name", typeof (String)); - createCol(land, "Description", typeof (String)); - createCol(land, "OwnerUUID", typeof (String)); - createCol(land, "IsGroupOwned", typeof (Int32)); - createCol(land, "Area", typeof (Int32)); - createCol(land, "AuctionID", typeof (Int32)); //Unemplemented - createCol(land, "Category", typeof (Int32)); //Enum libsecondlife.Parcel.ParcelCategory - createCol(land, "ClaimDate", typeof (Int32)); - createCol(land, "ClaimPrice", typeof (Int32)); - createCol(land, "GroupUUID", typeof (String)); - createCol(land, "SalePrice", typeof (Int32)); - createCol(land, "LandStatus", typeof (Int32)); //Enum. libsecondlife.Parcel.ParcelStatus - createCol(land, "LandFlags", typeof (UInt32)); - createCol(land, "LandingType", typeof (Int32)); - createCol(land, "MediaAutoScale", typeof (Int32)); - createCol(land, "MediaTextureUUID", typeof (String)); - createCol(land, "MediaURL", typeof (String)); - createCol(land, "MusicURL", typeof (String)); - createCol(land, "PassHours", typeof (Double)); - createCol(land, "PassPrice", typeof (Int32)); - createCol(land, "SnapshotUUID", typeof (String)); - createCol(land, "UserLocationX", typeof (Double)); - createCol(land, "UserLocationY", typeof (Double)); - createCol(land, "UserLocationZ", typeof (Double)); - createCol(land, "UserLookAtX", typeof (Double)); - createCol(land, "UserLookAtY", typeof (Double)); - createCol(land, "UserLookAtZ", typeof (Double)); - createCol(land, "AuthBuyerID", typeof (String)); - createCol(land, "OtherCleanTime", typeof(Int32)); - createCol(land, "Dwell", typeof(Int32)); - - land.PrimaryKey = new DataColumn[] {land.Columns["UUID"]}; - - return land; - } + foreach (LandData land in landData) + { + cmd.Parameters.Clear(); - /// - /// Create the "landaccesslist" table - /// - /// - private static DataTable createLandAccessListTable() - { - DataTable landaccess = new DataTable("landaccesslist"); - createCol(landaccess, "LandUUID", typeof (String)); - createCol(landaccess, "AccessUUID", typeof (String)); - createCol(landaccess, "Flags", typeof (Int32)); + cmd.CommandText = "select * from landaccesslist " + + "where LandUUID = ?LandUUID"; - return landaccess; - } + cmd.Parameters.AddWithValue("LandUUID", + Util.ToRawUuidString(land.GlobalID)); - /// - /// Create the "primshapes" table - /// - /// - private static DataTable createShapeTable() - { - DataTable shapes = new DataTable("primshapes"); - createCol(shapes, "UUID", typeof (String)); - // shape is an enum - createCol(shapes, "Shape", typeof (Int32)); - // vectors - createCol(shapes, "ScaleX", typeof (Double)); - createCol(shapes, "ScaleY", typeof (Double)); - createCol(shapes, "ScaleZ", typeof (Double)); - // paths - createCol(shapes, "PCode", typeof (Int32)); - createCol(shapes, "PathBegin", typeof (Int32)); - createCol(shapes, "PathEnd", typeof (Int32)); - createCol(shapes, "PathScaleX", typeof (Int32)); - createCol(shapes, "PathScaleY", typeof (Int32)); - createCol(shapes, "PathShearX", typeof (Int32)); - createCol(shapes, "PathShearY", typeof (Int32)); - createCol(shapes, "PathSkew", typeof (Int32)); - createCol(shapes, "PathCurve", typeof (Int32)); - createCol(shapes, "PathRadiusOffset", typeof (Int32)); - createCol(shapes, "PathRevolutions", typeof (Int32)); - createCol(shapes, "PathTaperX", typeof (Int32)); - createCol(shapes, "PathTaperY", typeof (Int32)); - createCol(shapes, "PathTwist", typeof (Int32)); - createCol(shapes, "PathTwistBegin", typeof (Int32)); - // profile - createCol(shapes, "ProfileBegin", typeof (Int32)); - createCol(shapes, "ProfileEnd", typeof (Int32)); - createCol(shapes, "ProfileCurve", typeof (Int32)); - createCol(shapes, "ProfileHollow", typeof (Int32)); - createCol(shapes, "State", typeof(Int32)); - createCol(shapes, "Texture", typeof (Byte[])); - createCol(shapes, "ExtraParams", typeof (Byte[])); + reader = ExecuteReader(cmd); - shapes.PrimaryKey = new DataColumn[] {shapes.Columns["UUID"]}; + try + { + while (reader.Read()) + { + land.ParcelAccessList.Add(BuildLandAccessData(reader)); + } + } + finally + { + reader.Close(); + } + } + } - return shapes; + return landData; } - /// - /// Create the "primitems" table - /// - /// - private static DataTable createItemsTable() + public void Shutdown() { - DataTable items = new DataTable("primitems"); - - createCol(items, "itemID", typeof (String)); - createCol(items, "primID", typeof (String)); - createCol(items, "assetID", typeof (String)); - createCol(items, "parentFolderID", typeof (String)); - - createCol(items, "invType", typeof (Int32)); - createCol(items, "assetType", typeof (Int32)); - - createCol(items, "name", typeof (String)); - createCol(items, "description", typeof (String)); - - createCol(items, "creationDate", typeof (Int64)); - createCol(items, "creatorID", typeof (String)); - createCol(items, "ownerID", typeof (String)); - createCol(items, "lastOwnerID", typeof (String)); - createCol(items, "groupID", typeof (String)); - - createCol(items, "nextPermissions", typeof (Int32)); - createCol(items, "currentPermissions", typeof (Int32)); - createCol(items, "basePermissions", typeof (Int32)); - createCol(items, "everyonePermissions", typeof (Int32)); - createCol(items, "groupPermissions", typeof (Int32)); - createCol(items, "flags", typeof (Int32)); - - items.PrimaryKey = new DataColumn[] {items.Columns["itemID"]}; - - return items; } - /*********************************************************************** - * - * Convert between ADO.NET <=> OpenSim Objects - * - * These should be database independant - * - **********************************************************************/ - - /// - /// - /// - /// - /// - private SceneObjectPart buildPrim(DataRow row) + private SceneObjectPart BuildPrim(IDataReader row) { SceneObjectPart prim = new SceneObjectPart(); prim.UUID = new UUID((String) row["UUID"]); @@ -1232,9 +803,9 @@ namespace OpenSim.Data.MySQL prim.SoundGain = Convert.ToSingle(row["LoopedSoundGain"]); prim.SoundFlags = 1; // If it's persisted at all, it's looped - if (!row.IsNull("TextureAnimation")) + if (!(row["TextureAnimation"] is DBNull)) prim.TextureAnimation = (Byte[])row["TextureAnimation"]; - if (!row.IsNull("ParticleSystem")) + if (!(row["ParticleSystem"] is DBNull)) prim.ParticleSystem = (Byte[])row["ParticleSystem"]; prim.RotationalVelocity = new Vector3( @@ -1271,11 +842,12 @@ namespace OpenSim.Data.MySQL prim.Material = Convert.ToByte(row["Material"]); - if (!row.IsNull("ClickAction")) - prim.ClickAction = Convert.ToByte(row["ClickAction"]); + if (!(row["ClickAction"] is DBNull)) + prim.ClickAction = (byte)Convert.ToByte(row["ClickAction"]); prim.CollisionSound = new UUID(row["CollisionSound"].ToString()); prim.CollisionSoundVolume = Convert.ToSingle(row["CollisionSoundVolume"]); + prim.LinkNum = Convert.ToInt32(row["LinkNumber"]); return prim; } @@ -1286,7 +858,7 @@ namespace OpenSim.Data.MySQL /// /// /// - private static TaskInventoryItem buildItem(DataRow row) + private static TaskInventoryItem BuildItem(IDataReader row) { TaskInventoryItem taskItem = new TaskInventoryItem(); @@ -1316,7 +888,7 @@ namespace OpenSim.Data.MySQL return taskItem; } - private static RegionSettings buildRegionSettings(DataRow row) + private static RegionSettings BuildRegionSettings(IDataReader row) { RegionSettings newSettings = new RegionSettings(); @@ -1368,7 +940,7 @@ namespace OpenSim.Data.MySQL /// /// /// - private static LandData buildLandData(DataRow row) + private static LandData BuildLandData(IDataReader row) { LandData newData = new LandData(); @@ -1436,7 +1008,7 @@ namespace OpenSim.Data.MySQL /// /// /// - private static ParcelManager.ParcelAccessEntry buildLandAccessData(DataRow row) + private static ParcelManager.ParcelAccessEntry BuildLandAccessData(IDataReader row) { ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry(); entry.AgentID = new UUID((string) row["AccessUUID"]); @@ -1450,7 +1022,7 @@ namespace OpenSim.Data.MySQL /// /// /// - private static Array serializeTerrain(double[,] val) + private static Array SerializeTerrain(double[,] val) { MemoryStream str = new MemoryStream(65536*sizeof (double)); BinaryWriter bw = new BinaryWriter(str); @@ -1476,128 +1048,129 @@ namespace OpenSim.Data.MySQL /// /// /// - private void fillPrimRow(DataRow row, SceneObjectPart prim, UUID sceneGroupID, UUID regionUUID) + private void FillPrimCommand(MySqlCommand cmd, SceneObjectPart prim, UUID sceneGroupID, UUID regionUUID) { - row["UUID"] = Util.ToRawUuidString(prim.UUID); - row["RegionUUID"] = Util.ToRawUuidString(regionUUID); - row["ParentID"] = prim.ParentID; - row["CreationDate"] = prim.CreationDate; - row["Name"] = prim.Name; - row["SceneGroupID"] = Util.ToRawUuidString(sceneGroupID); + cmd.Parameters.AddWithValue("UUID", Util.ToRawUuidString(prim.UUID)); + cmd.Parameters.AddWithValue("RegionUUID", Util.ToRawUuidString(regionUUID)); + cmd.Parameters.AddWithValue("ParentID", prim.ParentID); + cmd.Parameters.AddWithValue("CreationDate", prim.CreationDate); + cmd.Parameters.AddWithValue("Name", prim.Name); + cmd.Parameters.AddWithValue("SceneGroupID", Util.ToRawUuidString(sceneGroupID)); // the UUID of the root part for this SceneObjectGroup // various text fields - row["Text"] = prim.Text; - row["ColorR"] = prim.Color.R; - row["ColorG"] = prim.Color.G; - row["ColorB"] = prim.Color.B; - row["ColorA"] = prim.Color.A; - row["Description"] = prim.Description; - row["SitName"] = prim.SitName; - row["TouchName"] = prim.TouchName; + cmd.Parameters.AddWithValue("Text", prim.Text); + cmd.Parameters.AddWithValue("ColorR", prim.Color.R); + cmd.Parameters.AddWithValue("ColorG", prim.Color.G); + cmd.Parameters.AddWithValue("ColorB", prim.Color.B); + cmd.Parameters.AddWithValue("ColorA", prim.Color.A); + cmd.Parameters.AddWithValue("Description", prim.Description); + cmd.Parameters.AddWithValue("SitName", prim.SitName); + cmd.Parameters.AddWithValue("TouchName", prim.TouchName); // permissions - row["ObjectFlags"] = prim.ObjectFlags; - row["CreatorID"] = Util.ToRawUuidString(prim.CreatorID); - row["OwnerID"] = Util.ToRawUuidString(prim.OwnerID); - row["GroupID"] = Util.ToRawUuidString(prim.GroupID); - row["LastOwnerID"] = Util.ToRawUuidString(prim.LastOwnerID); - row["OwnerMask"] = prim.OwnerMask; - row["NextOwnerMask"] = prim.NextOwnerMask; - row["GroupMask"] = prim.GroupMask; - row["EveryoneMask"] = prim.EveryoneMask; - row["BaseMask"] = prim.BaseMask; + cmd.Parameters.AddWithValue("ObjectFlags", prim.ObjectFlags); + cmd.Parameters.AddWithValue("CreatorID", Util.ToRawUuidString(prim.CreatorID)); + cmd.Parameters.AddWithValue("OwnerID", Util.ToRawUuidString(prim.OwnerID)); + cmd.Parameters.AddWithValue("GroupID", Util.ToRawUuidString(prim.GroupID)); + cmd.Parameters.AddWithValue("LastOwnerID", Util.ToRawUuidString(prim.LastOwnerID)); + cmd.Parameters.AddWithValue("OwnerMask", prim.OwnerMask); + cmd.Parameters.AddWithValue("NextOwnerMask", prim.NextOwnerMask); + cmd.Parameters.AddWithValue("GroupMask", prim.GroupMask); + cmd.Parameters.AddWithValue("EveryoneMask", prim.EveryoneMask); + cmd.Parameters.AddWithValue("BaseMask", prim.BaseMask); // vectors - row["PositionX"] = prim.OffsetPosition.X; - row["PositionY"] = prim.OffsetPosition.Y; - row["PositionZ"] = prim.OffsetPosition.Z; - row["GroupPositionX"] = prim.GroupPosition.X; - row["GroupPositionY"] = prim.GroupPosition.Y; - row["GroupPositionZ"] = prim.GroupPosition.Z; - row["VelocityX"] = prim.Velocity.X; - row["VelocityY"] = prim.Velocity.Y; - row["VelocityZ"] = prim.Velocity.Z; - row["AngularVelocityX"] = prim.AngularVelocity.X; - row["AngularVelocityY"] = prim.AngularVelocity.Y; - row["AngularVelocityZ"] = prim.AngularVelocity.Z; - row["AccelerationX"] = prim.Acceleration.X; - row["AccelerationY"] = prim.Acceleration.Y; - row["AccelerationZ"] = prim.Acceleration.Z; + cmd.Parameters.AddWithValue("PositionX", prim.OffsetPosition.X); + cmd.Parameters.AddWithValue("PositionY", prim.OffsetPosition.Y); + cmd.Parameters.AddWithValue("PositionZ", prim.OffsetPosition.Z); + cmd.Parameters.AddWithValue("GroupPositionX", prim.GroupPosition.X); + cmd.Parameters.AddWithValue("GroupPositionY", prim.GroupPosition.Y); + cmd.Parameters.AddWithValue("GroupPositionZ", prim.GroupPosition.Z); + cmd.Parameters.AddWithValue("VelocityX", prim.Velocity.X); + cmd.Parameters.AddWithValue("VelocityY", prim.Velocity.Y); + cmd.Parameters.AddWithValue("VelocityZ", prim.Velocity.Z); + cmd.Parameters.AddWithValue("AngularVelocityX", prim.AngularVelocity.X); + cmd.Parameters.AddWithValue("AngularVelocityY", prim.AngularVelocity.Y); + cmd.Parameters.AddWithValue("AngularVelocityZ", prim.AngularVelocity.Z); + cmd.Parameters.AddWithValue("AccelerationX", prim.Acceleration.X); + cmd.Parameters.AddWithValue("AccelerationY", prim.Acceleration.Y); + cmd.Parameters.AddWithValue("AccelerationZ", prim.Acceleration.Z); // quaternions - row["RotationX"] = prim.RotationOffset.X; - row["RotationY"] = prim.RotationOffset.Y; - row["RotationZ"] = prim.RotationOffset.Z; - row["RotationW"] = prim.RotationOffset.W; + cmd.Parameters.AddWithValue("RotationX", prim.RotationOffset.X); + cmd.Parameters.AddWithValue("RotationY", prim.RotationOffset.Y); + cmd.Parameters.AddWithValue("RotationZ", prim.RotationOffset.Z); + cmd.Parameters.AddWithValue("RotationW", prim.RotationOffset.W); // Sit target Vector3 sitTargetPos = prim.SitTargetPositionLL; - row["SitTargetOffsetX"] = sitTargetPos.X; - row["SitTargetOffsetY"] = sitTargetPos.Y; - row["SitTargetOffsetZ"] = sitTargetPos.Z; + cmd.Parameters.AddWithValue("SitTargetOffsetX", sitTargetPos.X); + cmd.Parameters.AddWithValue("SitTargetOffsetY", sitTargetPos.Y); + cmd.Parameters.AddWithValue("SitTargetOffsetZ", sitTargetPos.Z); Quaternion sitTargetOrient = prim.SitTargetOrientationLL; - row["SitTargetOrientW"] = sitTargetOrient.W; - row["SitTargetOrientX"] = sitTargetOrient.X; - row["SitTargetOrientY"] = sitTargetOrient.Y; - row["SitTargetOrientZ"] = sitTargetOrient.Z; + cmd.Parameters.AddWithValue("SitTargetOrientW", sitTargetOrient.W); + cmd.Parameters.AddWithValue("SitTargetOrientX", sitTargetOrient.X); + cmd.Parameters.AddWithValue("SitTargetOrientY", sitTargetOrient.Y); + cmd.Parameters.AddWithValue("SitTargetOrientZ", sitTargetOrient.Z); - row["PayPrice"] = prim.PayPrice[0]; - row["PayButton1"] = prim.PayPrice[1]; - row["PayButton2"] = prim.PayPrice[2]; - row["PayButton3"] = prim.PayPrice[3]; - row["PayButton4"] = prim.PayPrice[4]; + cmd.Parameters.AddWithValue("PayPrice", prim.PayPrice[0]); + cmd.Parameters.AddWithValue("PayButton1", prim.PayPrice[1]); + cmd.Parameters.AddWithValue("PayButton2", prim.PayPrice[2]); + cmd.Parameters.AddWithValue("PayButton3", prim.PayPrice[3]); + cmd.Parameters.AddWithValue("PayButton4", prim.PayPrice[4]); if ((prim.SoundFlags & 1) != 0) // Looped { - row["LoopedSound"] = prim.Sound.ToString(); - row["LoopedSoundGain"] = prim.SoundGain; + cmd.Parameters.AddWithValue("LoopedSound", prim.Sound.ToString()); + cmd.Parameters.AddWithValue("LoopedSoundGain", prim.SoundGain); } else { - row["LoopedSound"] = UUID.Zero; - row["LoopedSoundGain"] = 0.0f; + cmd.Parameters.AddWithValue("LoopedSound", UUID.Zero); + cmd.Parameters.AddWithValue("LoopedSoundGain", 0.0f); } - row["TextureAnimation"] = prim.TextureAnimation; - row["ParticleSystem"] = prim.ParticleSystem; + cmd.Parameters.AddWithValue("TextureAnimation", prim.TextureAnimation); + cmd.Parameters.AddWithValue("ParticleSystem", prim.ParticleSystem); - row["OmegaX"] = prim.RotationalVelocity.X; - row["OmegaY"] = prim.RotationalVelocity.Y; - row["OmegaZ"] = prim.RotationalVelocity.Z; + cmd.Parameters.AddWithValue("OmegaX", prim.RotationalVelocity.X); + cmd.Parameters.AddWithValue("OmegaY", prim.RotationalVelocity.Y); + cmd.Parameters.AddWithValue("OmegaZ", prim.RotationalVelocity.Z); - row["CameraEyeOffsetX"] = prim.GetCameraEyeOffset().X; - row["CameraEyeOffsetY"] = prim.GetCameraEyeOffset().Y; - row["CameraEyeOffsetZ"] = prim.GetCameraEyeOffset().Z; + cmd.Parameters.AddWithValue("CameraEyeOffsetX", prim.GetCameraEyeOffset().X); + cmd.Parameters.AddWithValue("CameraEyeOffsetY", prim.GetCameraEyeOffset().Y); + cmd.Parameters.AddWithValue("CameraEyeOffsetZ", prim.GetCameraEyeOffset().Z); - row["CameraAtOffsetX"] = prim.GetCameraAtOffset().X; - row["CameraAtOffsetY"] = prim.GetCameraAtOffset().Y; - row["CameraAtOffsetZ"] = prim.GetCameraAtOffset().Z; + cmd.Parameters.AddWithValue("CameraAtOffsetX", prim.GetCameraAtOffset().X); + cmd.Parameters.AddWithValue("CameraAtOffsetY", prim.GetCameraAtOffset().Y); + cmd.Parameters.AddWithValue("CameraAtOffsetZ", prim.GetCameraAtOffset().Z); if (prim.GetForceMouselook()) - row["ForceMouselook"] = 1; + cmd.Parameters.AddWithValue("ForceMouselook", 1); else - row["ForceMouselook"] = 0; + cmd.Parameters.AddWithValue("ForceMouselook", 0); - row["ScriptAccessPin"] = prim.ScriptAccessPin; + cmd.Parameters.AddWithValue("ScriptAccessPin", prim.ScriptAccessPin); if (prim.AllowedDrop) - row["AllowedDrop"] = 1; + cmd.Parameters.AddWithValue("AllowedDrop", 1); else - row["AllowedDrop"] = 0; + cmd.Parameters.AddWithValue("AllowedDrop", 0); if (prim.DIE_AT_EDGE) - row["DieAtEdge"] = 1; + cmd.Parameters.AddWithValue("DieAtEdge", 1); else - row["DieAtEdge"] = 0; + cmd.Parameters.AddWithValue("DieAtEdge", 0); - row["SalePrice"] = prim.SalePrice; - row["SaleType"] = Convert.ToInt16(prim.ObjectSaleType); + cmd.Parameters.AddWithValue("SalePrice", prim.SalePrice); + cmd.Parameters.AddWithValue("SaleType", Convert.ToInt16(prim.ObjectSaleType)); byte clickAction = prim.ClickAction; - row["ClickAction"] = clickAction; + cmd.Parameters.AddWithValue("ClickAction", clickAction); - row["Material"] = prim.Material; + cmd.Parameters.AddWithValue("Material", prim.Material); - row["CollisionSound"] = prim.CollisionSound.ToString(); - row["CollisionSoundVolume"] = prim.CollisionSoundVolume; + cmd.Parameters.AddWithValue("CollisionSound", prim.CollisionSound.ToString()); + cmd.Parameters.AddWithValue("CollisionSoundVolume", prim.CollisionSoundVolume); + cmd.Parameters.AddWithValue("LinkNumber", prim.LinkNum); } /// @@ -1605,73 +1178,73 @@ namespace OpenSim.Data.MySQL /// /// /// - private static void fillItemRow(DataRow row, TaskInventoryItem taskItem) + private static void FillItemCommand(MySqlCommand cmd, TaskInventoryItem taskItem) { - row["itemID"] = taskItem.ItemID; - row["primID"] = taskItem.ParentPartID; - row["assetID"] = taskItem.AssetID; - row["parentFolderID"] = taskItem.ParentID; - - row["invType"] = taskItem.InvType; - row["assetType"] = taskItem.Type; - - row["name"] = taskItem.Name; - row["description"] = taskItem.Description; - row["creationDate"] = taskItem.CreationDate; - row["creatorID"] = taskItem.CreatorID; - row["ownerID"] = taskItem.OwnerID; - row["lastOwnerID"] = taskItem.LastOwnerID; - row["groupID"] = taskItem.GroupID; - row["nextPermissions"] = taskItem.NextPermissions; - row["currentPermissions"] = taskItem.CurrentPermissions; - row["basePermissions"] = taskItem.BasePermissions; - row["everyonePermissions"] = taskItem.EveryonePermissions; - row["groupPermissions"] = taskItem.GroupPermissions; - row["flags"] = taskItem.Flags; + cmd.Parameters.AddWithValue("itemID", taskItem.ItemID); + cmd.Parameters.AddWithValue("primID", taskItem.ParentPartID); + cmd.Parameters.AddWithValue("assetID", taskItem.AssetID); + cmd.Parameters.AddWithValue("parentFolderID", taskItem.ParentID); + + cmd.Parameters.AddWithValue("invType", taskItem.InvType); + cmd.Parameters.AddWithValue("assetType", taskItem.Type); + + cmd.Parameters.AddWithValue("name", taskItem.Name); + cmd.Parameters.AddWithValue("description", taskItem.Description); + cmd.Parameters.AddWithValue("creationDate", taskItem.CreationDate); + cmd.Parameters.AddWithValue("creatorID", taskItem.CreatorID); + cmd.Parameters.AddWithValue("ownerID", taskItem.OwnerID); + cmd.Parameters.AddWithValue("lastOwnerID", taskItem.LastOwnerID); + cmd.Parameters.AddWithValue("groupID", taskItem.GroupID); + cmd.Parameters.AddWithValue("nextPermissions", taskItem.NextPermissions); + cmd.Parameters.AddWithValue("currentPermissions", taskItem.CurrentPermissions); + cmd.Parameters.AddWithValue("basePermissions", taskItem.BasePermissions); + cmd.Parameters.AddWithValue("everyonePermissions", taskItem.EveryonePermissions); + cmd.Parameters.AddWithValue("groupPermissions", taskItem.GroupPermissions); + cmd.Parameters.AddWithValue("flags", taskItem.Flags); } /// /// /// - private static void fillRegionSettingsRow(DataRow row, RegionSettings settings) + private static void FillRegionSettingsCommand(MySqlCommand cmd, RegionSettings settings) { - row["regionUUID"] = settings.RegionUUID.ToString(); - row["block_terraform"] = settings.BlockTerraform; - row["block_fly"] = settings.BlockFly; - row["allow_damage"] = settings.AllowDamage; - row["restrict_pushing"] = settings.RestrictPushing; - row["allow_land_resell"] = settings.AllowLandResell; - row["allow_land_join_divide"] = settings.AllowLandJoinDivide; - row["block_show_in_search"] = settings.BlockShowInSearch; - row["agent_limit"] = settings.AgentLimit; - row["object_bonus"] = settings.ObjectBonus; - row["maturity"] = settings.Maturity; - row["disable_scripts"] = settings.DisableScripts; - row["disable_collisions"] = settings.DisableCollisions; - row["disable_physics"] = settings.DisablePhysics; - row["terrain_texture_1"] = settings.TerrainTexture1.ToString(); - row["terrain_texture_2"] = settings.TerrainTexture2.ToString(); - row["terrain_texture_3"] = settings.TerrainTexture3.ToString(); - row["terrain_texture_4"] = settings.TerrainTexture4.ToString(); - row["elevation_1_nw"] = settings.Elevation1NW; - row["elevation_2_nw"] = settings.Elevation2NW; - row["elevation_1_ne"] = settings.Elevation1NE; - row["elevation_2_ne"] = settings.Elevation2NE; - row["elevation_1_se"] = settings.Elevation1SE; - row["elevation_2_se"] = settings.Elevation2SE; - row["elevation_1_sw"] = settings.Elevation1SW; - row["elevation_2_sw"] = settings.Elevation2SW; - row["water_height"] = settings.WaterHeight; - row["terrain_raise_limit"] = settings.TerrainRaiseLimit; - row["terrain_lower_limit"] = settings.TerrainLowerLimit; - row["use_estate_sun"] = settings.UseEstateSun; - row["sandbox"] = settings.Sandbox; - row["sunvectorx"] = settings.SunVector.X; - row["sunvectory"] = settings.SunVector.Y; - row["sunvectorz"] = settings.SunVector.Z; - row["fixed_sun"] = settings.FixedSun; - row["sun_position"] = settings.SunPosition; - row["covenant"] = settings.Covenant.ToString(); + cmd.Parameters.AddWithValue("RegionUUID", settings.RegionUUID.ToString()); + cmd.Parameters.AddWithValue("BlockTerraform", settings.BlockTerraform); + cmd.Parameters.AddWithValue("BlockFly", settings.BlockFly); + cmd.Parameters.AddWithValue("AllowDamage", settings.AllowDamage); + cmd.Parameters.AddWithValue("RestrictPushing", settings.RestrictPushing); + cmd.Parameters.AddWithValue("AllowLandResell", settings.AllowLandResell); + cmd.Parameters.AddWithValue("AllowLandJoinDivide", settings.AllowLandJoinDivide); + cmd.Parameters.AddWithValue("BlockShowInSearch", settings.BlockShowInSearch); + cmd.Parameters.AddWithValue("AgentLimit", settings.AgentLimit); + cmd.Parameters.AddWithValue("ObjectBonus", settings.ObjectBonus); + cmd.Parameters.AddWithValue("Maturity", settings.Maturity); + cmd.Parameters.AddWithValue("DisableScripts", settings.DisableScripts); + cmd.Parameters.AddWithValue("DisableCollisions", settings.DisableCollisions); + cmd.Parameters.AddWithValue("DisablePhysics", settings.DisablePhysics); + cmd.Parameters.AddWithValue("TerrainTexture1", settings.TerrainTexture1.ToString()); + cmd.Parameters.AddWithValue("TerrainTexture2", settings.TerrainTexture2.ToString()); + cmd.Parameters.AddWithValue("TerrainTexture3", settings.TerrainTexture3.ToString()); + cmd.Parameters.AddWithValue("TerrainTexture4", settings.TerrainTexture4.ToString()); + cmd.Parameters.AddWithValue("Elevation1NW", settings.Elevation1NW); + cmd.Parameters.AddWithValue("Elevation2NW", settings.Elevation2NW); + cmd.Parameters.AddWithValue("Elevation1NE", settings.Elevation1NE); + cmd.Parameters.AddWithValue("Elevation2NE", settings.Elevation2NE); + cmd.Parameters.AddWithValue("Elevation1SE", settings.Elevation1SE); + cmd.Parameters.AddWithValue("Elevation2SE", settings.Elevation2SE); + cmd.Parameters.AddWithValue("Elevation1SW", settings.Elevation1SW); + cmd.Parameters.AddWithValue("Elevation2SW", settings.Elevation2SW); + cmd.Parameters.AddWithValue("WaterHeight", settings.WaterHeight); + cmd.Parameters.AddWithValue("TerrainRaiseLimit", settings.TerrainRaiseLimit); + cmd.Parameters.AddWithValue("TerrainLowerLimit", settings.TerrainLowerLimit); + cmd.Parameters.AddWithValue("UseEstateSun", settings.UseEstateSun); + cmd.Parameters.AddWithValue("Sandbox", settings.Sandbox); + cmd.Parameters.AddWithValue("SunVectorX", settings.SunVector.X); + cmd.Parameters.AddWithValue("SunVectorY", settings.SunVector.Y); + cmd.Parameters.AddWithValue("SunVectorZ", settings.SunVector.Z); + cmd.Parameters.AddWithValue("FixedSun", settings.FixedSun); + cmd.Parameters.AddWithValue("SunPosition", settings.SunPosition); + cmd.Parameters.AddWithValue("Covenant", settings.Covenant.ToString()); } /// @@ -1680,45 +1253,45 @@ namespace OpenSim.Data.MySQL /// /// /// - private static void fillLandRow(DataRow row, LandData land, UUID regionUUID) + private static void FillLandCommand(MySqlCommand cmd, LandData land, UUID regionUUID) { - row["UUID"] = Util.ToRawUuidString(land.GlobalID); - row["RegionUUID"] = Util.ToRawUuidString(regionUUID); - row["LocalLandID"] = land.LocalID; + cmd.Parameters.AddWithValue("UUID", Util.ToRawUuidString(land.GlobalID)); + cmd.Parameters.AddWithValue("RegionUUID", Util.ToRawUuidString(regionUUID)); + cmd.Parameters.AddWithValue("LocalLandID", land.LocalID); // Bitmap is a byte[512] - row["Bitmap"] = land.Bitmap; - - row["Name"] = land.Name; - row["Description"] = land.Description; - row["OwnerUUID"] = Util.ToRawUuidString(land.OwnerID); - row["IsGroupOwned"] = land.IsGroupOwned; - row["Area"] = land.Area; - row["AuctionID"] = land.AuctionID; //Unemplemented - row["Category"] = land.Category; //Enum libsecondlife.Parcel.ParcelCategory - row["ClaimDate"] = land.ClaimDate; - row["ClaimPrice"] = land.ClaimPrice; - row["GroupUUID"] = Util.ToRawUuidString(land.GroupID); - row["SalePrice"] = land.SalePrice; - row["LandStatus"] = land.Status; //Enum. libsecondlife.Parcel.ParcelStatus - row["LandFlags"] = land.Flags; - row["LandingType"] = land.LandingType; - row["MediaAutoScale"] = land.MediaAutoScale; - row["MediaTextureUUID"] = Util.ToRawUuidString(land.MediaID); - row["MediaURL"] = land.MediaURL; - row["MusicURL"] = land.MusicURL; - row["PassHours"] = land.PassHours; - row["PassPrice"] = land.PassPrice; - row["SnapshotUUID"] = Util.ToRawUuidString(land.SnapshotID); - row["UserLocationX"] = land.UserLocation.X; - row["UserLocationY"] = land.UserLocation.Y; - row["UserLocationZ"] = land.UserLocation.Z; - row["UserLookAtX"] = land.UserLookAt.X; - row["UserLookAtY"] = land.UserLookAt.Y; - row["UserLookAtZ"] = land.UserLookAt.Z; - row["AuthBuyerID"] = land.AuthBuyerID; - row["OtherCleanTime"] = land.OtherCleanTime; - row["Dwell"] = land.Dwell; + cmd.Parameters.AddWithValue("Bitmap", land.Bitmap); + + cmd.Parameters.AddWithValue("Name", land.Name); + cmd.Parameters.AddWithValue("Description", land.Description); + cmd.Parameters.AddWithValue("OwnerUUID", Util.ToRawUuidString(land.OwnerID)); + cmd.Parameters.AddWithValue("IsGroupOwned", land.IsGroupOwned); + cmd.Parameters.AddWithValue("Area", land.Area); + cmd.Parameters.AddWithValue("AuctionID", land.AuctionID); //Unemplemented + cmd.Parameters.AddWithValue("Category", land.Category); //Enum libsecondlife.Parcel.ParcelCategory + cmd.Parameters.AddWithValue("ClaimDate", land.ClaimDate); + cmd.Parameters.AddWithValue("ClaimPrice", land.ClaimPrice); + cmd.Parameters.AddWithValue("GroupUUID", Util.ToRawUuidString(land.GroupID)); + cmd.Parameters.AddWithValue("SalePrice", land.SalePrice); + cmd.Parameters.AddWithValue("LandStatus", land.Status); //Enum. libsecondlife.Parcel.ParcelStatus + cmd.Parameters.AddWithValue("LandFlags", land.Flags); + cmd.Parameters.AddWithValue("LandingType", land.LandingType); + cmd.Parameters.AddWithValue("MediaAutoScale", land.MediaAutoScale); + cmd.Parameters.AddWithValue("MediaTextureUUID", Util.ToRawUuidString(land.MediaID)); + cmd.Parameters.AddWithValue("MediaURL", land.MediaURL); + cmd.Parameters.AddWithValue("MusicURL", land.MusicURL); + cmd.Parameters.AddWithValue("PassHours", land.PassHours); + cmd.Parameters.AddWithValue("PassPrice", land.PassPrice); + cmd.Parameters.AddWithValue("SnapshotUUID", Util.ToRawUuidString(land.SnapshotID)); + cmd.Parameters.AddWithValue("UserLocationX", land.UserLocation.X); + cmd.Parameters.AddWithValue("UserLocationY", land.UserLocation.Y); + cmd.Parameters.AddWithValue("UserLocationZ", land.UserLocation.Z); + cmd.Parameters.AddWithValue("UserLookAtX", land.UserLookAt.X); + cmd.Parameters.AddWithValue("UserLookAtY", land.UserLookAt.Y); + cmd.Parameters.AddWithValue("UserLookAtZ", land.UserLookAt.Z); + cmd.Parameters.AddWithValue("AuthBuyerID", land.AuthBuyerID); + cmd.Parameters.AddWithValue("OtherCleanTime", land.OtherCleanTime); + cmd.Parameters.AddWithValue("Dwell", land.Dwell); } /// @@ -1727,11 +1300,11 @@ namespace OpenSim.Data.MySQL /// /// /// - private static void fillLandAccessRow(DataRow row, ParcelManager.ParcelAccessEntry entry, UUID parcelID) + private static void FillLandAccessCommand(MySqlCommand cmd, ParcelManager.ParcelAccessEntry entry, UUID parcelID) { - row["LandUUID"] = Util.ToRawUuidString(parcelID); - row["AccessUUID"] = Util.ToRawUuidString(entry.AgentID); - row["Flags"] = entry.Flags; + cmd.Parameters.AddWithValue("LandUUID", Util.ToRawUuidString(parcelID)); + cmd.Parameters.AddWithValue("AccessUUID", Util.ToRawUuidString(entry.AgentID)); + cmd.Parameters.AddWithValue("Flags", entry.Flags); } /// @@ -1739,7 +1312,7 @@ namespace OpenSim.Data.MySQL /// /// /// - private PrimitiveBaseShape buildShape(DataRow row) + private PrimitiveBaseShape BuildShape(IDataReader row) { PrimitiveBaseShape s = new PrimitiveBaseShape(); s.Scale = new Vector3( @@ -1768,8 +1341,7 @@ namespace OpenSim.Data.MySQL s.ProfileEnd = Convert.ToUInt16(row["ProfileEnd"]); s.ProfileCurve = Convert.ToByte(row["ProfileCurve"]); s.ProfileHollow = Convert.ToUInt16(row["ProfileHollow"]); - - byte[] textureEntry = (byte[]) row["Texture"]; +byte[] textureEntry = (byte[]) row["Texture"]; s.TextureEntry = textureEntry; s.ExtraParams = (byte[]) row["ExtraParams"]; @@ -1784,382 +1356,78 @@ namespace OpenSim.Data.MySQL /// /// /// - private void fillShapeRow(DataRow row, SceneObjectPart prim) + private void FillShapeCommand(MySqlCommand cmd, SceneObjectPart prim) { PrimitiveBaseShape s = prim.Shape; - row["UUID"] = Util.ToRawUuidString(prim.UUID); + cmd.Parameters.AddWithValue("UUID", Util.ToRawUuidString(prim.UUID)); // shape is an enum - row["Shape"] = 0; + cmd.Parameters.AddWithValue("Shape", 0); // vectors - row["ScaleX"] = s.Scale.X; - row["ScaleY"] = s.Scale.Y; - row["ScaleZ"] = s.Scale.Z; + cmd.Parameters.AddWithValue("ScaleX", s.Scale.X); + cmd.Parameters.AddWithValue("ScaleY", s.Scale.Y); + cmd.Parameters.AddWithValue("ScaleZ", s.Scale.Z); // paths - row["PCode"] = s.PCode; - row["PathBegin"] = s.PathBegin; - row["PathEnd"] = s.PathEnd; - row["PathScaleX"] = s.PathScaleX; - row["PathScaleY"] = s.PathScaleY; - row["PathShearX"] = s.PathShearX; - row["PathShearY"] = s.PathShearY; - row["PathSkew"] = s.PathSkew; - row["PathCurve"] = s.PathCurve; - row["PathRadiusOffset"] = s.PathRadiusOffset; - row["PathRevolutions"] = s.PathRevolutions; - row["PathTaperX"] = s.PathTaperX; - row["PathTaperY"] = s.PathTaperY; - row["PathTwist"] = s.PathTwist; - row["PathTwistBegin"] = s.PathTwistBegin; + cmd.Parameters.AddWithValue("PCode", s.PCode); + cmd.Parameters.AddWithValue("PathBegin", s.PathBegin); + cmd.Parameters.AddWithValue("PathEnd", s.PathEnd); + cmd.Parameters.AddWithValue("PathScaleX", s.PathScaleX); + cmd.Parameters.AddWithValue("PathScaleY", s.PathScaleY); + cmd.Parameters.AddWithValue("PathShearX", s.PathShearX); + cmd.Parameters.AddWithValue("PathShearY", s.PathShearY); + cmd.Parameters.AddWithValue("PathSkew", s.PathSkew); + cmd.Parameters.AddWithValue("PathCurve", s.PathCurve); + cmd.Parameters.AddWithValue("PathRadiusOffset", s.PathRadiusOffset); + cmd.Parameters.AddWithValue("PathRevolutions", s.PathRevolutions); + cmd.Parameters.AddWithValue("PathTaperX", s.PathTaperX); + cmd.Parameters.AddWithValue("PathTaperY", s.PathTaperY); + cmd.Parameters.AddWithValue("PathTwist", s.PathTwist); + cmd.Parameters.AddWithValue("PathTwistBegin", s.PathTwistBegin); // profile - row["ProfileBegin"] = s.ProfileBegin; - row["ProfileEnd"] = s.ProfileEnd; - row["ProfileCurve"] = s.ProfileCurve; - row["ProfileHollow"] = s.ProfileHollow; - row["Texture"] = s.TextureEntry; - row["ExtraParams"] = s.ExtraParams; - row["State"] = s.State; + cmd.Parameters.AddWithValue("ProfileBegin", s.ProfileBegin); + cmd.Parameters.AddWithValue("ProfileEnd", s.ProfileEnd); + cmd.Parameters.AddWithValue("ProfileCurve", s.ProfileCurve); + cmd.Parameters.AddWithValue("ProfileHollow", s.ProfileHollow); + cmd.Parameters.AddWithValue("Texture", s.TextureEntry); + cmd.Parameters.AddWithValue("ExtraParams", s.ExtraParams); + cmd.Parameters.AddWithValue("State", s.State); } - /// - /// - /// - /// - /// - /// - private void addPrim(SceneObjectPart prim, UUID sceneGroupID, UUID regionUUID) - { - lock (m_dataSet) - { - DataTable prims = m_dataSet.Tables["prims"]; - DataTable shapes = m_dataSet.Tables["primshapes"]; - - DataRow primRow = prims.Rows.Find(Util.ToRawUuidString(prim.UUID)); - if (primRow == null) - { - primRow = prims.NewRow(); - fillPrimRow(primRow, prim, sceneGroupID, regionUUID); - prims.Rows.Add(primRow); - } - else - { - fillPrimRow(primRow, prim, sceneGroupID, regionUUID); - } - - DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID)); - if (shapeRow == null) - { - shapeRow = shapes.NewRow(); - fillShapeRow(shapeRow, prim); - shapes.Rows.Add(shapeRow); - } - else - { - fillShapeRow(shapeRow, prim); - } - } - } - - /// - /// see IRegionDatastore - /// - /// - /// public void StorePrimInventory(UUID primID, ICollection items) { - //m_log.InfoFormat("[REGION DB]: Persisting Prim Inventory with prim ID {0}", primID); - - // For now, we're just going to crudely remove all the previous inventory items - // no matter whether they have changed or not, and replace them with the current set. - lock (m_dataSet) + lock (m_Connection) { RemoveItems(primID); - // repalce with current inventory details - foreach (TaskInventoryItem newItem in items) + MySqlCommand cmd = m_Connection.CreateCommand(); + + if (items.Count == 0) + return; + + cmd.CommandText = "insert into primitems ("+ + "invType, assetType, name, "+ + "description, creationDate, nextPermissions, "+ + "currentPermissions, basePermissions, "+ + "everyonePermissions, groupPermissions, "+ + "flags, itemID, primID, assetID, "+ + "parentFolderID, creatorID, ownerID, "+ + "groupID, lastOwnerID) values (?invType, "+ + "?assetType, ?name, ?description, "+ + "?creationDate, ?nextPermissions, "+ + "?currentPermissions, ?basePermissions, "+ + "?everyonePermissions, ?groupPermissions, "+ + "?flags, ?itemID, ?primID, ?assetID, "+ + "?parentFolderID, ?creatorID, ?ownerID, "+ + "?groupID, ?lastOwnerID)"; + + foreach (TaskInventoryItem item in items) { -// m_log.InfoFormat( -// "[REGION DB]: " + -// "Adding item {0}, {1} to prim ID {2}", -// newItem.Name, newItem.ItemID, newItem.ParentPartID); - - DataRow newItemRow = m_itemsTable.NewRow(); - fillItemRow(newItemRow, newItem); - m_itemsTable.Rows.Add(newItemRow); - } - } - - Commit(); - } - - /*********************************************************************** - * - * SQL Statement Creation Functions - * - * These functions create SQL statements for update, insert, and create. - * They can probably be factored later to have a db independant - * portion and a db specific portion - * - **********************************************************************/ - - /// - /// Create a MySQL insert command - /// - /// - /// - /// - /// - /// This is subtle enough to deserve some commentary. - /// Instead of doing *lots* and *lots of hardcoded strings - /// for database definitions we'll use the fact that - /// realistically all insert statements look like "insert - /// into A(b, c) values(:b, :c) on the parameterized query - /// front. If we just have a list of b, c, etc... we can - /// generate these strings instead of typing them out. - /// - private static MySqlCommand createInsertCommand(string table, DataTable dt) - { + cmd.Parameters.Clear(); - string[] cols = new string[dt.Columns.Count]; - for (int i = 0; i < dt.Columns.Count; i++) - { - DataColumn col = dt.Columns[i]; - cols[i] = col.ColumnName; - } + FillItemCommand(cmd, item); - string sql = "insert into " + table + "("; - sql += String.Join(", ", cols); - // important, the first ':' needs to be here, the rest get added in the join - sql += ") values (?"; - sql += String.Join(", ?", cols); - sql += ")"; - MySqlCommand cmd = new MySqlCommand(sql); - - // this provides the binding for all our parameters, so - // much less code than it used to be - foreach (DataColumn col in dt.Columns) - { - cmd.Parameters.Add(createMySqlParameter(col.ColumnName, col.DataType)); - } - return cmd; - } - - /// - /// Create a MySQL update command - /// - /// - /// - /// - /// - private static MySqlCommand createUpdateCommand(string table, string pk, DataTable dt) - { - string sql = "update " + table + " set "; - string subsql = String.Empty; - foreach (DataColumn col in dt.Columns) - { - if (subsql.Length > 0) - { - // a map function would rock so much here - subsql += ", "; + ExecuteNonQuery(cmd); } - subsql += col.ColumnName + "=?" + col.ColumnName; - } - sql += subsql; - sql += " where " + pk; - MySqlCommand cmd = new MySqlCommand(sql); - - // this provides the binding for all our parameters, so - // much less code than it used to be - - foreach (DataColumn col in dt.Columns) - { - cmd.Parameters.Add(createMySqlParameter(col.ColumnName, col.DataType)); - } - return cmd; - } - - /*********************************************************************** - * - * Database Binding functions - * - * These will be db specific due to typing, and minor differences - * in databases. - * - **********************************************************************/ - - /// - /// This is a convenience function that collapses 5 repetitive - /// lines for defining MySqlParameters to 2 parameters: - /// column name and database type. - /// - /// - /// It assumes certain conventions like ?param as the param - /// name to replace in parametrized queries, and that source - /// version is always current version, both of which are fine - /// for us. - /// - /// - /// a built MySql parameter - private static MySqlParameter createMySqlParameter(string name, Type type) - { - MySqlParameter param = new MySqlParameter(); - param.ParameterName = "?" + name; - param.DbType = dbtypeFromType(type); - param.SourceColumn = name; - param.SourceVersion = DataRowVersion.Current; - return param; - } - - /// - /// - /// - /// - /// - private void SetupPrimCommands(MySqlDataAdapter da, MySqlConnection conn) - { - MySqlCommand insertCommand = createInsertCommand("prims", m_primTable); - insertCommand.Connection = conn; - da.InsertCommand = insertCommand; - - MySqlCommand updateCommand = createUpdateCommand("prims", "UUID=?UUID", m_primTable); - updateCommand.Connection = conn; - da.UpdateCommand = updateCommand; - - MySqlCommand delete = new MySqlCommand("delete from prims where UUID=?UUID"); - delete.Parameters.Add(createMySqlParameter("UUID", typeof (String))); - delete.Connection = conn; - da.DeleteCommand = delete; - } - - /// - /// - /// - /// - /// - private void SetupItemsCommands(MySqlDataAdapter da, MySqlConnection conn) - { - da.InsertCommand = createInsertCommand("primitems", m_itemsTable); - da.InsertCommand.Connection = conn; - - da.UpdateCommand = createUpdateCommand("primitems", "itemID = ?itemID", m_itemsTable); - da.UpdateCommand.Connection = conn; - - MySqlCommand delete = new MySqlCommand("delete from primitems where itemID = ?itemID"); - delete.Parameters.Add(createMySqlParameter("itemID", typeof (String))); - delete.Connection = conn; - da.DeleteCommand = delete; - } - - private void SetupRegionSettingsCommands(MySqlDataAdapter da, MySqlConnection conn) - { - da.InsertCommand = createInsertCommand("regionsettings", m_regionSettingsTable); - da.InsertCommand.Connection = conn; - - da.UpdateCommand = createUpdateCommand("regionsettings", "regionUUID = ?regionUUID", m_regionSettingsTable); - da.UpdateCommand.Connection = conn; - - MySqlCommand delete = new MySqlCommand("delete from regionsettings where regionUUID = ?regionUUID"); - delete.Parameters.Add(createMySqlParameter("regionUUID", typeof(String))); - delete.Connection = conn; - da.DeleteCommand = delete; - } - - /// - /// - /// - /// - /// - private void SetupTerrainCommands(MySqlDataAdapter da, MySqlConnection conn) - { - da.InsertCommand = createInsertCommand("terrain", m_dataSet.Tables["terrain"]); - da.InsertCommand.Connection = conn; - } - - /// - /// - /// - /// - /// - private void setupLandCommands(MySqlDataAdapter da, MySqlConnection conn) - { - da.InsertCommand = createInsertCommand("land", m_dataSet.Tables["land"]); - da.InsertCommand.Connection = conn; - - da.UpdateCommand = createUpdateCommand("land", "UUID=?UUID", m_dataSet.Tables["land"]); - da.UpdateCommand.Connection = conn; - } - - /// - /// - /// - /// - /// - private void setupLandAccessCommands(MySqlDataAdapter da, MySqlConnection conn) - { - da.InsertCommand = createInsertCommand("landaccesslist", m_dataSet.Tables["landaccesslist"]); - da.InsertCommand.Connection = conn; - } - - /// - /// - /// - /// - /// - private void SetupShapeCommands(MySqlDataAdapter da, MySqlConnection conn) - { - da.InsertCommand = createInsertCommand("primshapes", m_dataSet.Tables["primshapes"]); - da.InsertCommand.Connection = conn; - - da.UpdateCommand = createUpdateCommand("primshapes", "UUID=?UUID", m_dataSet.Tables["primshapes"]); - da.UpdateCommand.Connection = conn; - - MySqlCommand delete = new MySqlCommand("delete from primshapes where UUID = ?UUID"); - delete.Parameters.Add(createMySqlParameter("UUID", typeof (String))); - delete.Connection = conn; - da.DeleteCommand = delete; - } - - /*********************************************************************** - * - * Type conversion functions - * - **********************************************************************/ - - /// - /// Type conversion functions - /// - /// - /// - private static DbType dbtypeFromType(Type type) - { - if (type == typeof (String)) - { - return DbType.String; - } - else if (type == typeof (Int32)) - { - return DbType.Int32; - } - else if (type == typeof (Double)) - { - return DbType.Double; - } - else if (type == typeof (Byte)) - { - return DbType.Byte; - } - else if (type == typeof (Double)) - { - return DbType.Double; - } - else if (type == typeof (Byte[])) - { - return DbType.Binary; - } - else - { - return DbType.String; } } - } } diff --git a/OpenSim/Data/MySQL/Resources/023_RegionStore.sql b/OpenSim/Data/MySQL/Resources/023_RegionStore.sql new file mode 100644 index 0000000..559591f --- /dev/null +++ b/OpenSim/Data/MySQL/Resources/023_RegionStore.sql @@ -0,0 +1,6 @@ +BEGIN; + +ALTER TABLE prims ADD COLUMN LinkNumber integer not null default 0; + +COMMIT; + diff --git a/OpenSim/Framework/TaskInventoryItem.cs b/OpenSim/Framework/TaskInventoryItem.cs index 1443e74..43d28e7 100644 --- a/OpenSim/Framework/TaskInventoryItem.cs +++ b/OpenSim/Framework/TaskInventoryItem.cs @@ -329,6 +329,7 @@ namespace OpenSim.Framework { _itemID = UUID.Random(); _parentPartID = partID; + _parentID = partID; } public TaskInventoryItem() diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs index 9839126..7bdcb5c 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs @@ -1336,6 +1336,8 @@ namespace OpenSim.Region.Environment.Scenes dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); + dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; + if (userExposed) dupe.m_rootPart.TrimPermissions(); @@ -1368,16 +1370,25 @@ namespace OpenSim.Region.Environment.Scenes } List partList = new List(m_parts.Values); + partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) + { + return p1.LinkNum.CompareTo(p2.LinkNum); + } + ); + foreach (SceneObjectPart part in partList) { if (part.UUID != m_rootPart.UUID) { - dupe.CopyPart(part, OwnerID, GroupID, userExposed); + SceneObjectPart newPart = + dupe.CopyPart(part, OwnerID, GroupID, userExposed); + + newPart.LinkNum = part.LinkNum; if (userExposed) { - SetPartOwner(part, cAgentID, cGroupID); - part.ScheduleFullUpdate(); + SetPartOwner(newPart, cAgentID, cGroupID); + newPart.ScheduleFullUpdate(); } } } @@ -1507,7 +1518,7 @@ namespace OpenSim.Region.Environment.Scenes /// /// /// - public void CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) + public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) { SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); newPart.SetParent(this); @@ -1519,6 +1530,7 @@ namespace OpenSim.Region.Environment.Scenes SetPartAsNonRoot(newPart); + return newPart; } /// diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs index e97b99f..5b494d3 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs @@ -1263,10 +1263,18 @@ if (m_shape != null) { dupe._category = _category; dupe.m_rezzed = m_rezzed; - dupe.m_inventory.Items = (TaskInventoryDictionary)dupe.m_inventory.Items.Clone(); + dupe.m_inventory = new SceneObjectPartInventory(dupe); + dupe.m_inventory.Items = (TaskInventoryDictionary)m_inventory.Items.Clone(); if (userExposed) + { dupe.ResetIDs(linkNum); + dupe.m_inventory.HasInventoryChanged = true; + } + else + { + dupe.m_inventory.HasInventoryChanged = m_inventory.HasInventoryChanged; + } // Move afterwards ResetIDs as it clears the localID dupe.LocalId = localID; diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Environment/Scenes/SceneObjectPartInventory.cs index ae43c5e..3f94a7e 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectPartInventory.cs @@ -64,7 +64,7 @@ namespace OpenSim.Region.Environment.Scenes /// /// Tracks whether inventory has changed since the last persistent backup /// - protected bool HasInventoryChanged; + internal bool HasInventoryChanged; /// /// Inventory serial number @@ -81,7 +81,11 @@ namespace OpenSim.Region.Environment.Scenes protected internal TaskInventoryDictionary Items { get { return m_items; } - set { m_items = value; } + set + { + m_items = value; + m_inventorySerial++; + } } /// -- cgit v1.1