diff options
author | Melanie Thielker | 2008-11-26 07:34:38 +0000 |
---|---|---|
committer | Melanie Thielker | 2008-11-26 07:34:38 +0000 |
commit | 3efdccbb12fc2d5339870ade39e1b1d54da4fe9b (patch) | |
tree | 5fd5d0e9c802da79aed0579718211507945699cc /OpenSim/Data/MySQL/MySQLRegionData.cs | |
parent | Next step of the PresenceModule. Still not complete; local optimizations and the (diff) | |
download | opensim-SC_OLD-3efdccbb12fc2d5339870ade39e1b1d54da4fe9b.zip opensim-SC_OLD-3efdccbb12fc2d5339870ade39e1b1d54da4fe9b.tar.gz opensim-SC_OLD-3efdccbb12fc2d5339870ade39e1b1d54da4fe9b.tar.bz2 opensim-SC_OLD-3efdccbb12fc2d5339870ade39e1b1d54da4fe9b.tar.xz |
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.
Diffstat (limited to 'OpenSim/Data/MySQL/MySQLRegionData.cs')
-rw-r--r-- | OpenSim/Data/MySQL/MySQLRegionData.cs | 2212 |
1 files changed, 740 insertions, 1472 deletions
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 | |||
48 | { | 48 | { |
49 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 49 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
50 | 50 | ||
51 | private const string m_primSelect = "select * from prims"; | 51 | private string m_ConnectionString; |
52 | private const string m_shapeSelect = "select * from primshapes"; | ||
53 | private const string m_itemsSelect = "select * from primitems"; | ||
54 | private const string m_terrainSelect = "select * from terrain limit 1"; | ||
55 | private const string m_landSelect = "select * from land"; | ||
56 | private const string m_landAccessListSelect = "select * from landaccesslist"; | ||
57 | private const string m_regionSettingsSelect = "select * from regionsettings"; | ||
58 | private const string m_waitTimeoutSelect = "select @@wait_timeout"; | ||
59 | |||
60 | private MySqlConnection m_connection; | ||
61 | private string m_connectionString; | ||
62 | 52 | ||
63 | /// <summary> | 53 | private MySqlConnection m_Connection = null; |
64 | /// Wait timeout for our connection in ticks. | ||
65 | /// </summary> | ||
66 | private long m_waitTimeout; | ||
67 | |||
68 | /// <summary> | ||
69 | /// Make our storage of the timeout this amount smaller than it actually is, to give us a margin on long | ||
70 | /// running database operations. | ||
71 | /// </summary> | ||
72 | private long m_waitTimeoutLeeway = 60 * TimeSpan.TicksPerSecond; | ||
73 | |||
74 | /// <summary> | ||
75 | /// Holds the last tick time that the connection was used. | ||
76 | /// </summary> | ||
77 | private long m_lastConnectionUse; | ||
78 | |||
79 | private DataSet m_dataSet; | ||
80 | private MySqlDataAdapter m_primDataAdapter; | ||
81 | private MySqlDataAdapter m_shapeDataAdapter; | ||
82 | private MySqlDataAdapter m_itemsDataAdapter; | ||
83 | private MySqlDataAdapter m_terrainDataAdapter; | ||
84 | private MySqlDataAdapter m_landDataAdapter; | ||
85 | private MySqlDataAdapter m_landAccessListDataAdapter; | ||
86 | private MySqlDataAdapter m_regionSettingsDataAdapter; | ||
87 | |||
88 | private DataTable m_primTable; | ||
89 | private DataTable m_shapeTable; | ||
90 | private DataTable m_itemsTable; | ||
91 | private DataTable m_terrainTable; | ||
92 | private DataTable m_landTable; | ||
93 | private DataTable m_landAccessListTable; | ||
94 | private DataTable m_regionSettingsTable; | ||
95 | |||
96 | /*********************************************************************** | ||
97 | * | ||
98 | * Public Interface Functions | ||
99 | * | ||
100 | **********************************************************************/ | ||
101 | 54 | ||
102 | /// <summary> | ||
103 | /// see IRegionDataStore | ||
104 | /// </summary> | ||
105 | /// <param name="connectionstring"></param> | ||
106 | public void Initialise(string connectionString) | 55 | public void Initialise(string connectionString) |
107 | { | 56 | { |
108 | m_connectionString = connectionString; | 57 | m_ConnectionString = connectionString; |
109 | 58 | ||
110 | m_dataSet = new DataSet(); | 59 | m_Connection = new MySqlConnection(m_ConnectionString); |
111 | 60 | ||
112 | int passPosition = 0; | 61 | m_Connection.Open(); |
113 | int passEndPosition = 0; | ||
114 | string displayConnectionString = null; | ||
115 | |||
116 | try | ||
117 | { // hide the password in the connection string | ||
118 | passPosition = m_connectionString.IndexOf("password", StringComparison.OrdinalIgnoreCase); | ||
119 | passPosition = m_connectionString.IndexOf("=", passPosition); | ||
120 | if (passPosition < m_connectionString.Length) | ||
121 | passPosition += 1; | ||
122 | passEndPosition = m_connectionString.IndexOf(";", passPosition); | ||
123 | |||
124 | displayConnectionString = m_connectionString.Substring(0, passPosition); | ||
125 | displayConnectionString += "***"; | ||
126 | displayConnectionString += m_connectionString.Substring(passEndPosition, m_connectionString.Length - passEndPosition); | ||
127 | } | ||
128 | catch (Exception e ) | ||
129 | { | ||
130 | m_log.Debug("Exception: password not found in connection string\n" + e.ToString()); | ||
131 | } | ||
132 | 62 | ||
133 | m_log.Info("[REGION DB]: MySql - connecting: " + displayConnectionString); | 63 | // Apply new Migrations |
134 | m_connection = new MySqlConnection(m_connectionString); | 64 | // |
135 | m_connection.Open(); | ||
136 | |||
137 | GetWaitTimeout(); | ||
138 | |||
139 | // This actually does the roll forward assembly stuff | ||
140 | Assembly assem = GetType().Assembly; | 65 | Assembly assem = GetType().Assembly; |
141 | Migration m = new Migration(m_connection, assem, "RegionStore"); | 66 | Migration m = new Migration(m_Connection, assem, "RegionStore"); |
142 | m.Update(); | 67 | m.Update(); |
143 | 68 | ||
144 | 69 | // Clean dropped attachments | |
145 | MySqlCommand primSelectCmd = new MySqlCommand(m_primSelect, m_connection); | 70 | // |
146 | m_primDataAdapter = new MySqlDataAdapter(primSelectCmd); | 71 | MySqlCommand cmd = m_Connection.CreateCommand(); |
147 | 72 | cmd.CommandText = "delete from prims, primshapes using prims " + | |
148 | MySqlCommand shapeSelectCmd = new MySqlCommand(m_shapeSelect, m_connection); | 73 | "left join primshapes on prims.uuid = primshapes.uuid " + |
149 | m_shapeDataAdapter = new MySqlDataAdapter(shapeSelectCmd); | 74 | "where PCode = 9 and State <> 0"; |
150 | 75 | ExecuteNonQuery(cmd); | |
151 | MySqlCommand itemsSelectCmd = new MySqlCommand(m_itemsSelect, m_connection); | ||
152 | m_itemsDataAdapter = new MySqlDataAdapter(itemsSelectCmd); | ||
153 | |||
154 | MySqlCommand terrainSelectCmd = new MySqlCommand(m_terrainSelect, m_connection); | ||
155 | m_terrainDataAdapter = new MySqlDataAdapter(terrainSelectCmd); | ||
156 | |||
157 | MySqlCommand landSelectCmd = new MySqlCommand(m_landSelect, m_connection); | ||
158 | m_landDataAdapter = new MySqlDataAdapter(landSelectCmd); | ||
159 | |||
160 | MySqlCommand landAccessListSelectCmd = new MySqlCommand(m_landAccessListSelect, m_connection); | ||
161 | m_landAccessListDataAdapter = new MySqlDataAdapter(landAccessListSelectCmd); | ||
162 | |||
163 | MySqlCommand regionSettingsSelectCmd = new MySqlCommand(m_regionSettingsSelect, m_connection); | ||
164 | m_regionSettingsDataAdapter = new MySqlDataAdapter(regionSettingsSelectCmd); | ||
165 | |||
166 | // TODO: move out the ADO.NET pieces here and just go to the db directly | ||
167 | lock (m_dataSet) | ||
168 | { | ||
169 | m_primTable = createPrimTable(); | ||
170 | m_dataSet.Tables.Add(m_primTable); | ||
171 | SetupPrimCommands(m_primDataAdapter, m_connection); | ||
172 | m_primDataAdapter.Fill(m_primTable); | ||
173 | |||
174 | m_shapeTable = createShapeTable(); | ||
175 | m_dataSet.Tables.Add(m_shapeTable); | ||
176 | SetupShapeCommands(m_shapeDataAdapter, m_connection); | ||
177 | m_shapeDataAdapter.Fill(m_shapeTable); | ||
178 | |||
179 | m_itemsTable = createItemsTable(); | ||
180 | m_dataSet.Tables.Add(m_itemsTable); | ||
181 | SetupItemsCommands(m_itemsDataAdapter, m_connection); | ||
182 | m_itemsDataAdapter.Fill(m_itemsTable); | ||
183 | |||
184 | m_terrainTable = createTerrainTable(); | ||
185 | m_dataSet.Tables.Add(m_terrainTable); | ||
186 | SetupTerrainCommands(m_terrainDataAdapter, m_connection); | ||
187 | m_terrainDataAdapter.Fill(m_terrainTable); | ||
188 | |||
189 | m_landTable = createLandTable(); | ||
190 | m_dataSet.Tables.Add(m_landTable); | ||
191 | setupLandCommands(m_landDataAdapter, m_connection); | ||
192 | m_landDataAdapter.Fill(m_landTable); | ||
193 | |||
194 | m_landAccessListTable = createLandAccessListTable(); | ||
195 | m_dataSet.Tables.Add(m_landAccessListTable); | ||
196 | setupLandAccessCommands(m_landAccessListDataAdapter, m_connection); | ||
197 | m_landAccessListDataAdapter.Fill(m_landAccessListTable); | ||
198 | |||
199 | m_regionSettingsTable = createRegionSettingsTable(); | ||
200 | m_dataSet.Tables.Add(m_regionSettingsTable); | ||
201 | SetupRegionSettingsCommands(m_regionSettingsDataAdapter, m_connection); | ||
202 | m_regionSettingsDataAdapter.Fill(m_regionSettingsTable); | ||
203 | } | ||
204 | } | 76 | } |
205 | 77 | ||
206 | public void Dispose() {} | 78 | private IDataReader ExecuteReader(MySqlCommand c) |
207 | |||
208 | /// <summary> | ||
209 | /// Get the wait_timeout value for our connection | ||
210 | /// </summary> | ||
211 | protected void GetWaitTimeout() | ||
212 | { | 79 | { |
213 | MySqlCommand cmd = new MySqlCommand(m_waitTimeoutSelect, m_connection); | 80 | IDataReader r = null; |
81 | bool errorSeen = false; | ||
214 | 82 | ||
215 | lock (m_dataSet) | 83 | while (true) |
216 | { | 84 | { |
217 | MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow); | ||
218 | try | 85 | try |
219 | { | 86 | { |
220 | if (dbReader.Read()) | 87 | r = c.ExecuteReader(); |
221 | { | ||
222 | m_waitTimeout | ||
223 | = Convert.ToInt32(dbReader["@@wait_timeout"]) * TimeSpan.TicksPerSecond + m_waitTimeoutLeeway; | ||
224 | } | ||
225 | |||
226 | cmd.Dispose(); | ||
227 | } | 88 | } |
228 | finally | 89 | catch (MySqlException) |
229 | { | 90 | { |
230 | dbReader.Close(); | 91 | System.Threading.Thread.Sleep(500); |
92 | |||
93 | m_Connection.Close(); | ||
94 | m_Connection.Open(); | ||
95 | |||
96 | if (!errorSeen) | ||
97 | { | ||
98 | errorSeen = true; | ||
99 | continue; | ||
100 | continue; | ||
101 | } | ||
102 | throw; | ||
231 | } | 103 | } |
232 | } | ||
233 | 104 | ||
234 | m_lastConnectionUse = System.DateTime.Now.Ticks; | 105 | break; |
106 | } | ||
235 | 107 | ||
236 | m_log.DebugFormat( | 108 | return r; |
237 | "[REGION DB]: Connection wait timeout {0} seconds", m_waitTimeout / TimeSpan.TicksPerSecond); | ||
238 | } | 109 | } |
239 | 110 | ||
240 | /// <summary> | 111 | private void ExecuteNonQuery(MySqlCommand c) |
241 | /// Should be called before any db operation. This checks to see if the connection has not timed out | ||
242 | /// </summary> | ||
243 | protected void CheckConnection() | ||
244 | { | 112 | { |
245 | //m_log.Debug("[REGION DB]: Checking connection"); | 113 | bool errorSeen = false; |
246 | 114 | ||
247 | long timeNow = System.DateTime.Now.Ticks; | 115 | while (true) |
248 | if (timeNow - m_lastConnectionUse > m_waitTimeout || m_connection.State != ConnectionState.Open) | ||
249 | { | 116 | { |
250 | m_log.DebugFormat("[REGION DB]: Database connection has gone away - reconnecting"); | 117 | try |
251 | |||
252 | lock (m_connection) | ||
253 | { | 118 | { |
254 | m_connection.Close(); | 119 | c.ExecuteNonQuery(); |
255 | m_connection = new MySqlConnection(m_connectionString); | ||
256 | m_connection.Open(); | ||
257 | } | 120 | } |
258 | } | 121 | catch (MySqlException) |
259 | 122 | { | |
260 | // Strictly, we should set this after the actual db operation. But it's more convenient to set here rather | 123 | System.Threading.Thread.Sleep(500); |
261 | // than require the code to call another method - the timeout leeway should be large enough to cover the | ||
262 | // inaccuracy. | ||
263 | m_lastConnectionUse = timeNow; | ||
264 | } | ||
265 | |||
266 | /// <summary> | ||
267 | /// Execute a SQL statement stored in a resource, as a string | ||
268 | /// </summary> | ||
269 | /// <param name="name">the ressource name</param> | ||
270 | /// <param name="dbcon">The database connection handler</param> | ||
271 | public void ExecuteResourceSql(string name, MySqlConnection dbcon) | ||
272 | { | ||
273 | MySqlCommand cmd = new MySqlCommand(getResourceString(name), dbcon); | ||
274 | cmd.ExecuteNonQuery(); | ||
275 | } | ||
276 | 124 | ||
277 | /// <summary> | 125 | m_Connection.Close(); |
278 | /// Extract a named string resource from the embedded resources | 126 | m_Connection.Open(); |
279 | /// </summary> | ||
280 | /// <param name="name">name of embedded resource</param> | ||
281 | /// <returns>string contained within the embedded resource</returns> | ||
282 | private string getResourceString(string name) | ||
283 | { | ||
284 | Assembly assem = GetType().Assembly; | ||
285 | string[] names = assem.GetManifestResourceNames(); | ||
286 | 127 | ||
287 | foreach (string s in names) | 128 | if (!errorSeen) |
288 | { | ||
289 | if (s.EndsWith(name)) | ||
290 | { | ||
291 | using (Stream resource = assem.GetManifestResourceStream(s)) | ||
292 | { | 129 | { |
293 | using (StreamReader resourceReader = new StreamReader(resource)) | 130 | errorSeen = true; |
294 | { | 131 | continue; |
295 | string resourceString = resourceReader.ReadToEnd(); | ||
296 | return resourceString; | ||
297 | } | ||
298 | } | 132 | } |
133 | throw; | ||
299 | } | 134 | } |
135 | |||
136 | break; | ||
300 | } | 137 | } |
301 | throw new Exception(string.Format("Resource '{0}' was not found", name)); | ||
302 | } | 138 | } |
303 | 139 | ||
304 | /// <summary> | 140 | public void Dispose() {} |
305 | /// Adds an object into region storage | 141 | |
306 | /// </summary> | ||
307 | /// <param name="obj">The object</param> | ||
308 | /// <param name="regionUUID">The region UUID</param> | ||
309 | public void StoreObject(SceneObjectGroup obj, UUID regionUUID) | 142 | public void StoreObject(SceneObjectGroup obj, UUID regionUUID) |
310 | { | 143 | { |
311 | lock (m_dataSet) | 144 | uint flags = obj.RootPart.GetEffectiveObjectFlags(); |
145 | |||
146 | // Eligibility check | ||
147 | // | ||
148 | if ((flags & (uint)PrimFlags.Temporary) != 0) | ||
149 | return; | ||
150 | if ((flags & (uint)PrimFlags.TemporaryOnRez) != 0) | ||
151 | return; | ||
152 | |||
153 | lock (m_Connection) | ||
312 | { | 154 | { |
155 | MySqlCommand cmd = m_Connection.CreateCommand(); | ||
156 | |||
313 | foreach (SceneObjectPart prim in obj.Children.Values) | 157 | foreach (SceneObjectPart prim in obj.Children.Values) |
314 | { | 158 | { |
315 | if ((prim.GetEffectiveObjectFlags() & (uint)PrimFlags.Temporary) == 0 | 159 | cmd.Parameters.Clear(); |
316 | && (prim.GetEffectiveObjectFlags() & (uint)PrimFlags.TemporaryOnRez) == 0) | 160 | |
317 | { | 161 | cmd.CommandText = "replace into prims ("+ |
318 | //m_log.Info("[REGION DB]: Adding obj: " + obj.UUID + " to region: " + regionUUID); | 162 | "UUID, ParentID, CreationDate, "+ |
319 | addPrim(prim, obj.UUID, regionUUID); | 163 | "Name, Text, Description, "+ |
320 | } | 164 | "SitName, TouchName, ObjectFlags, "+ |
321 | else | 165 | "OwnerMask, NextOwnerMask, GroupMask, "+ |
322 | { | 166 | "EveryoneMask, BaseMask, PositionX, "+ |
323 | // m_log.Info("[DATASTORE]: Ignoring Physical obj: " + obj.UUID + " in region: " + regionUUID); | 167 | "PositionY, PositionZ, GroupPositionX, "+ |
324 | } | 168 | "GroupPositionY, GroupPositionZ, VelocityX, "+ |
169 | "VelocityY, VelocityZ, AngularVelocityX, "+ | ||
170 | "AngularVelocityY, AngularVelocityZ, "+ | ||
171 | "AccelerationX, AccelerationY, "+ | ||
172 | "AccelerationZ, RotationX, "+ | ||
173 | "RotationY, RotationZ, "+ | ||
174 | "RotationW, SitTargetOffsetX, "+ | ||
175 | "SitTargetOffsetY, SitTargetOffsetZ, "+ | ||
176 | "SitTargetOrientW, SitTargetOrientX, "+ | ||
177 | "SitTargetOrientY, SitTargetOrientZ, "+ | ||
178 | "RegionUUID, CreatorID, "+ | ||
179 | "OwnerID, GroupID, "+ | ||
180 | "LastOwnerID, SceneGroupID, "+ | ||
181 | "PayPrice, PayButton1, "+ | ||
182 | "PayButton2, PayButton3, "+ | ||
183 | "PayButton4, LoopedSound, "+ | ||
184 | "LoopedSoundGain, TextureAnimation, "+ | ||
185 | "OmegaX, OmegaY, OmegaZ, "+ | ||
186 | "CameraEyeOffsetX, CameraEyeOffsetY, "+ | ||
187 | "CameraEyeOffsetZ, CameraAtOffsetX, "+ | ||
188 | "CameraAtOffsetY, CameraAtOffsetZ, "+ | ||
189 | "ForceMouselook, ScriptAccessPin, "+ | ||
190 | "AllowedDrop, DieAtEdge, "+ | ||
191 | "SalePrice, SaleType, "+ | ||
192 | "ColorR, ColorG, ColorB, ColorA, "+ | ||
193 | "ParticleSystem, ClickAction, Material, "+ | ||
194 | "CollisionSound, CollisionSoundVolume, "+ | ||
195 | "LinkNumber) values (" + "?UUID, ?ParentID, "+ | ||
196 | "?CreationDate, ?Name, ?Text, "+ | ||
197 | "?Description, ?SitName, ?TouchName, "+ | ||
198 | "?ObjectFlags, ?OwnerMask, ?NextOwnerMask, "+ | ||
199 | "?GroupMask, ?EveryoneMask, ?BaseMask, "+ | ||
200 | "?PositionX, ?PositionY, ?PositionZ, "+ | ||
201 | "?GroupPositionX, ?GroupPositionY, "+ | ||
202 | "?GroupPositionZ, ?VelocityX, "+ | ||
203 | "?VelocityY, ?VelocityZ, ?AngularVelocityX, "+ | ||
204 | "?AngularVelocityY, ?AngularVelocityZ, "+ | ||
205 | "?AccelerationX, ?AccelerationY, "+ | ||
206 | "?AccelerationZ, ?RotationX, "+ | ||
207 | "?RotationY, ?RotationZ, "+ | ||
208 | "?RotationW, ?SitTargetOffsetX, "+ | ||
209 | "?SitTargetOffsetY, ?SitTargetOffsetZ, "+ | ||
210 | "?SitTargetOrientW, ?SitTargetOrientX, "+ | ||
211 | "?SitTargetOrientY, ?SitTargetOrientZ, "+ | ||
212 | "?RegionUUID, ?CreatorID, ?OwnerID, "+ | ||
213 | "?GroupID, ?LastOwnerID, ?SceneGroupID, "+ | ||
214 | "?PayPrice, ?PayButton1, ?PayButton2, "+ | ||
215 | "?PayButton3, ?PayButton4, ?LoopedSound, "+ | ||
216 | "?LoopedSoundGain, ?TextureAnimation, "+ | ||
217 | "?OmegaX, ?OmegaY, ?OmegaZ, "+ | ||
218 | "?CameraEyeOffsetX, ?CameraEyeOffsetY, "+ | ||
219 | "?CameraEyeOffsetZ, ?CameraAtOffsetX, "+ | ||
220 | "?CameraAtOffsetY, ?CameraAtOffsetZ, "+ | ||
221 | "?ForceMouselook, ?ScriptAccessPin, "+ | ||
222 | "?AllowedDrop, ?DieAtEdge, ?SalePrice, "+ | ||
223 | "?SaleType, ?ColorR, ?ColorG, "+ | ||
224 | "?ColorB, ?ColorA, ?ParticleSystem, "+ | ||
225 | "?ClickAction, ?Material, ?CollisionSound, "+ | ||
226 | "?CollisionSoundVolume, ?LinkNumber)"; | ||
227 | |||
228 | FillPrimCommand(cmd, prim, obj.UUID, regionUUID); | ||
229 | |||
230 | ExecuteNonQuery(cmd); | ||
231 | |||
232 | cmd.Parameters.Clear(); | ||
233 | |||
234 | cmd.CommandText = "replace into primshapes ("+ | ||
235 | "UUID, Shape, ScaleX, ScaleY, "+ | ||
236 | "ScaleZ, PCode, PathBegin, PathEnd, "+ | ||
237 | "PathScaleX, PathScaleY, PathShearX, "+ | ||
238 | "PathShearY, PathSkew, PathCurve, "+ | ||
239 | "PathRadiusOffset, PathRevolutions, "+ | ||
240 | "PathTaperX, PathTaperY, PathTwist, "+ | ||
241 | "PathTwistBegin, ProfileBegin, ProfileEnd, "+ | ||
242 | "ProfileCurve, ProfileHollow, Texture, "+ | ||
243 | "ExtraParams, State) values (?UUID, "+ | ||
244 | "?Shape, ?ScaleX, ?ScaleY, ?ScaleZ, "+ | ||
245 | "?PCode, ?PathBegin, ?PathEnd, "+ | ||
246 | "?PathScaleX, ?PathScaleY, "+ | ||
247 | "?PathShearX, ?PathShearY, "+ | ||
248 | "?PathSkew, ?PathCurve, ?PathRadiusOffset, "+ | ||
249 | "?PathRevolutions, ?PathTaperX, "+ | ||
250 | "?PathTaperY, ?PathTwist, "+ | ||
251 | "?PathTwistBegin, ?ProfileBegin, "+ | ||
252 | "?ProfileEnd, ?ProfileCurve, "+ | ||
253 | "?ProfileHollow, ?Texture, ?ExtraParams, "+ | ||
254 | "?State)"; | ||
255 | |||
256 | FillShapeCommand(cmd, prim); | ||
257 | |||
258 | ExecuteNonQuery(cmd); | ||
325 | } | 259 | } |
326 | Commit(); | ||
327 | } | 260 | } |
328 | } | 261 | } |
329 | 262 | ||
330 | /// <summary> | ||
331 | /// removes an object from region storage | ||
332 | /// </summary> | ||
333 | /// <param name="obj">The object</param> | ||
334 | /// <param name="regionUUID">The Region UUID</param> | ||
335 | public void RemoveObject(UUID obj, UUID regionUUID) | 263 | public void RemoveObject(UUID obj, UUID regionUUID) |
336 | { | 264 | { |
337 | m_log.InfoFormat("[REGION DB]: Removing obj: {0} from region: {1}", obj, regionUUID); | 265 | // Formerly, this used to check the region UUID. |
266 | // That makes no sense, as we remove the contents of a prim | ||
267 | // unconditionally, but the prim dependent on the region ID. | ||
268 | // So, we would destroy an object and cause hard to detect | ||
269 | // issues if we delete the contents only. Deleting it all may | ||
270 | // cause the loss of a prim, but is cleaner. | ||
271 | // It's also faster because it uses the primary key. | ||
272 | // | ||
273 | lock (m_Connection) | ||
274 | { | ||
275 | MySqlCommand cmd = m_Connection.CreateCommand(); | ||
338 | 276 | ||
339 | DataTable prims = m_primTable; | 277 | cmd.CommandText = "select UUID from prims where "+ |
340 | DataTable shapes = m_shapeTable; | 278 | "SceneGroupID= ?UUID"; |
341 | 279 | ||
342 | string selectExp = "SceneGroupID = '" + Util.ToRawUuidString(obj) + "' and RegionUUID = '" + Util.ToRawUuidString(regionUUID) + "'"; | 280 | cmd.Parameters.AddWithValue("UUID", Util.ToRawUuidString(obj)); |
343 | lock (m_dataSet) | 281 | |
344 | { | 282 | List<UUID> uuids = new List<UUID>(); |
345 | DataRow[] primRows = prims.Select(selectExp); | 283 | |
346 | foreach (DataRow row in primRows) | 284 | IDataReader reader = ExecuteReader(cmd); |
285 | |||
286 | try | ||
347 | { | 287 | { |
348 | // Remove shapes row | 288 | while(reader.Read()) |
349 | UUID uuid = new UUID((string) row["UUID"]); | ||
350 | DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(uuid)); | ||
351 | if (shapeRow != null) | ||
352 | { | 289 | { |
353 | shapeRow.Delete(); | 290 | uuids.Add(new UUID(reader["UUID"].ToString())); |
354 | } | 291 | } |
292 | } | ||
293 | finally | ||
294 | { | ||
295 | reader.Close(); | ||
296 | } | ||
355 | 297 | ||
298 | foreach (UUID uuid in uuids) | ||
356 | RemoveItems(uuid); | 299 | RemoveItems(uuid); |
357 | 300 | ||
358 | // Remove prim row | 301 | cmd.CommandText = "delete from prims where SceneGroupID= ?UUID"; |
359 | row.Delete(); | 302 | |
360 | } | 303 | ExecuteNonQuery(cmd); |
361 | Commit(); | 304 | |
305 | cmd.CommandText = "delete from primshapes where UUID = ?UUID"; | ||
306 | |||
307 | ExecuteNonQuery(cmd); | ||
362 | } | 308 | } |
363 | } | 309 | } |
364 | 310 | ||
365 | /// <summary> | ||
366 | /// Remove all persisted items of the given prim. | ||
367 | /// The caller must acquire the necessrary synchronization locks and commit or rollback changes. | ||
368 | /// </summary> | ||
369 | /// <param name="uuid">the Item UUID</param> | ||
370 | private void RemoveItems(UUID uuid) | 311 | private void RemoveItems(UUID uuid) |
371 | { | 312 | { |
372 | String sql = String.Format("primID = '{0}'", uuid); | 313 | lock (m_Connection) |
373 | DataRow[] itemRows = m_itemsTable.Select(sql); | ||
374 | |||
375 | foreach (DataRow itemRow in itemRows) | ||
376 | { | 314 | { |
377 | itemRow.Delete(); | 315 | MySqlCommand cmd = m_Connection.CreateCommand(); |
316 | |||
317 | cmd.CommandText = "delete from primitems where " + | ||
318 | "PrimID = ?PrimID"; | ||
319 | |||
320 | cmd.Parameters.AddWithValue("PrimID", uuid.ToString()); | ||
321 | |||
322 | ExecuteNonQuery(cmd); | ||
378 | } | 323 | } |
379 | } | 324 | } |
380 | 325 | ||
381 | /// <summary> | ||
382 | /// Load persisted objects from region storage. | ||
383 | /// </summary> | ||
384 | /// <param name="regionUUID">the Region UUID</param> | ||
385 | /// <returns>List of loaded groups</returns> | ||
386 | public List<SceneObjectGroup> LoadObjects(UUID regionUUID) | 326 | public List<SceneObjectGroup> LoadObjects(UUID regionUUID) |
387 | { | 327 | { |
388 | Dictionary<UUID, SceneObjectGroup> createdObjects = new Dictionary<UUID, SceneObjectGroup>(); | 328 | UUID lastGroupID = UUID.Zero; |
389 | 329 | List<SceneObjectGroup> objects = new List<SceneObjectGroup>(); | |
390 | List<SceneObjectGroup> retvals = new List<SceneObjectGroup>(); | 330 | List<SceneObjectPart> prims = new List<SceneObjectPart>(); |
391 | 331 | SceneObjectGroup grp = null; | |
392 | DataTable prims = m_primTable; | ||
393 | DataTable shapes = m_shapeTable; | ||
394 | 332 | ||
395 | string byRegion = "RegionUUID = '" + Util.ToRawUuidString(regionUUID) + "'"; | 333 | lock (m_Connection) |
396 | string orderByParent = "ParentID ASC"; | ||
397 | |||
398 | lock (m_dataSet) | ||
399 | { | 334 | { |
400 | CheckConnection(); | 335 | MySqlCommand cmd = m_Connection.CreateCommand(); |
401 | DataRow[] primsForRegion = prims.Select(byRegion, orderByParent); | 336 | |
402 | m_log.Info("[REGION DB]: " + | 337 | cmd.CommandText = "select *, " + |
403 | "Loaded " + primsForRegion.Length + " prims for region: " + regionUUID); | 338 | "case when prims.UUID = SceneGroupID " + |
339 | "then 0 else 1 end as sort from prims " + | ||
340 | "left join primshapes on prims.UUID = primshapes.UUID "+ | ||
341 | "where RegionUUID = ?RegionUUID " + | ||
342 | "order by SceneGroupID asc, sort asc, LinkNumber asc"; | ||
404 | 343 | ||
405 | // First, create all groups | 344 | cmd.Parameters.AddWithValue("RegionUUID", |
406 | foreach (DataRow primRow in primsForRegion) | 345 | Util.ToRawUuidString(regionUUID)); |
346 | |||
347 | IDataReader reader = ExecuteReader(cmd); | ||
348 | |||
349 | try | ||
407 | { | 350 | { |
408 | try | 351 | while (reader.Read()) |
409 | { | 352 | { |
410 | string uuid = (string) primRow["UUID"]; | 353 | SceneObjectPart prim = BuildPrim(reader); |
411 | string objID = (string) primRow["SceneGroupID"]; | 354 | if (reader["Shape"] is DBNull) |
355 | prim.Shape = PrimitiveBaseShape.Default; | ||
356 | else | ||
357 | prim.Shape = BuildShape(reader); | ||
412 | 358 | ||
413 | SceneObjectPart prim = buildPrim(primRow); | 359 | prim.FolderID = prim.UUID; // A relic from when we |
360 | // we thought prims contained | ||
361 | // folder objects. In | ||
362 | // reality, prim == folder | ||
363 | prims.Add(prim); | ||
414 | 364 | ||
415 | if (uuid == objID) //is new SceneObjectGroup ? | 365 | UUID groupID = new UUID(reader["SceneGroupID"].ToString()); |
416 | { | ||
417 | SceneObjectGroup group = new SceneObjectGroup(); | ||
418 | 366 | ||
419 | DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID)); | 367 | if (groupID != lastGroupID) // New SOG |
420 | if (shapeRow != null) | ||
421 | { | ||
422 | prim.Shape = buildShape(shapeRow); | ||
423 | } | ||
424 | else | ||
425 | { | ||
426 | m_log.Info( | ||
427 | "No shape found for prim in storage, so setting default box shape"); | ||
428 | prim.Shape = PrimitiveBaseShape.Default; | ||
429 | } | ||
430 | |||
431 | group.SetRootPart(prim); | ||
432 | createdObjects.Add(group.UUID, group); | ||
433 | retvals.Add(group); | ||
434 | LoadItems(prim); | ||
435 | } | ||
436 | } | ||
437 | catch (Exception e) | ||
438 | { | ||
439 | m_log.Error("[REGION DB]: Failed create prim object, exception and data follows"); | ||
440 | m_log.Info("[REGION DB]: " + e.ToString()); | ||
441 | foreach (DataColumn col in prims.Columns) | ||
442 | { | 368 | { |
443 | m_log.Info("[REGION DB]: Col: " + col.ColumnName + " => " + primRow[col]); | 369 | if (grp != null) |
444 | } | 370 | objects.Add(grp); |
445 | } | ||
446 | } | ||
447 | |||
448 | // Now fill the groups with part data | ||
449 | foreach (DataRow primRow in primsForRegion) | ||
450 | { | ||
451 | try | ||
452 | { | ||
453 | string uuid = (string) primRow["UUID"]; | ||
454 | string objID = (string) primRow["SceneGroupID"]; | ||
455 | 371 | ||
456 | SceneObjectPart prim = buildPrim(primRow); | 372 | lastGroupID = groupID; |
457 | 373 | ||
458 | if (uuid != objID) //is new SceneObjectGroup ? | 374 | grp = new SceneObjectGroup(prim); |
459 | { | ||
460 | DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID)); | ||
461 | if (shapeRow != null) | ||
462 | { | ||
463 | prim.Shape = buildShape(shapeRow); | ||
464 | } | ||
465 | else | ||
466 | { | ||
467 | m_log.Info( | ||
468 | "No shape found for prim in storage, so setting default box shape"); | ||
469 | prim.Shape = PrimitiveBaseShape.Default; | ||
470 | } | ||
471 | createdObjects[new UUID(objID)].AddPart(prim); | ||
472 | LoadItems(prim); | ||
473 | } | 375 | } |
474 | } | 376 | else |
475 | catch (Exception e) | ||
476 | { | ||
477 | m_log.Error("[REGION DB]: Failed create prim object, exception and data follows"); | ||
478 | m_log.Info("[REGION DB]: " + e.ToString()); | ||
479 | foreach (DataColumn col in prims.Columns) | ||
480 | { | 377 | { |
481 | m_log.Info("[REGION DB]: Col: " + col.ColumnName + " => " + primRow[col]); | 378 | // Black magic to preserve link numbers |
379 | // | ||
380 | int link = prim.LinkNum; | ||
381 | |||
382 | grp.AddPart(prim); | ||
383 | |||
384 | if (link != 0) | ||
385 | prim.LinkNum = link; | ||
482 | } | 386 | } |
483 | } | 387 | } |
484 | } | 388 | } |
389 | finally | ||
390 | { | ||
391 | reader.Close(); | ||
392 | } | ||
393 | |||
394 | if (grp != null) | ||
395 | objects.Add(grp); | ||
485 | } | 396 | } |
486 | return retvals; | 397 | |
398 | foreach (SceneObjectPart part in prims) | ||
399 | LoadItems(part); | ||
400 | |||
401 | m_log.DebugFormat("[DATABASE] Loaded {0} objects using {1} prims", objects.Count, prims.Count); | ||
402 | |||
403 | return objects; | ||
487 | } | 404 | } |
488 | 405 | ||
489 | /// <summary> | ||
490 | /// Load in a prim's persisted inventory. | ||
491 | /// </summary> | ||
492 | /// <param name="prim">The prim</param> | ||
493 | private void LoadItems(SceneObjectPart prim) | 406 | private void LoadItems(SceneObjectPart prim) |
494 | { | 407 | { |
495 | lock (m_dataSet) | 408 | lock (m_Connection) |
496 | { | 409 | { |
497 | CheckConnection(); | 410 | MySqlCommand cmd = m_Connection.CreateCommand(); |
498 | //m_log.InfoFormat("[DATASTORE]: Loading inventory for {0}, {1}", prim.Name, prim.UUID); | ||
499 | 411 | ||
500 | DataTable dbItems = m_itemsTable; | 412 | cmd.CommandText = "select * from primitems where "+ |
413 | "PrimID = ?PrimID"; | ||
501 | 414 | ||
502 | String sql = String.Format("primID = '{0}'", prim.UUID.ToString()); | 415 | cmd.Parameters.AddWithValue("PrimID", prim.UUID.ToString()); |
503 | DataRow[] dbItemRows = dbItems.Select(sql); | ||
504 | IList<TaskInventoryItem> inventory = new List<TaskInventoryItem>(); | ||
505 | 416 | ||
506 | foreach (DataRow row in dbItemRows) | 417 | IDataReader reader = ExecuteReader(cmd); |
418 | List<TaskInventoryItem> inventory = | ||
419 | new List<TaskInventoryItem>(); | ||
420 | |||
421 | try | ||
507 | { | 422 | { |
508 | TaskInventoryItem item = buildItem(row); | 423 | while (reader.Read()) |
509 | inventory.Add(item); | 424 | { |
425 | TaskInventoryItem item = BuildItem(reader); | ||
510 | 426 | ||
511 | //m_log.DebugFormat("[DATASTORE]: Restored item {0}, {1}", item.Name, item.ItemID); | 427 | item.ParentID = prim.UUID; // Values in database are |
428 | // often wrong | ||
429 | inventory.Add(item); | ||
430 | } | ||
512 | } | 431 | } |
513 | 432 | finally | |
514 | prim.Inventory.RestoreInventoryItems(inventory); | ||
515 | |||
516 | // XXX A nasty little hack to recover the folder id for the prim (which is currently stored in | ||
517 | // every item). This data should really be stored in the prim table itself. | ||
518 | if (dbItemRows.Length > 0) | ||
519 | { | 433 | { |
520 | prim.FolderID = inventory[0].ParentID; | 434 | reader.Close(); |
521 | } | 435 | } |
436 | |||
437 | prim.Inventory.RestoreInventoryItems(inventory); | ||
522 | } | 438 | } |
523 | } | 439 | } |
524 | 440 | ||
525 | /// <summary> | ||
526 | /// Store a terrain revision in region storage | ||
527 | /// </summary> | ||
528 | /// <param name="ter">HeightField data</param> | ||
529 | /// <param name="regionID">region UUID</param> | ||
530 | public void StoreTerrain(double[,] ter, UUID regionID) | 441 | public void StoreTerrain(double[,] ter, UUID regionID) |
531 | { | 442 | { |
532 | int revision = 1; | 443 | m_log.Info("[REGION DB]: Storing terrain"); |
533 | m_log.Info("[REGION DB]: Storing terrain revision r" + revision.ToString()); | ||
534 | 444 | ||
535 | lock (m_dataSet) | 445 | lock (m_Connection) |
536 | { | 446 | { |
537 | MySqlCommand delete = new MySqlCommand("delete from terrain where RegionUUID=?RegionUUID", m_connection); | 447 | MySqlCommand cmd = m_Connection.CreateCommand(); |
538 | MySqlCommand cmd = new MySqlCommand("insert into terrain(RegionUUID, Revision, Heightfield)" + | ||
539 | " values(?RegionUUID, ?Revision, ?Heightfield)", m_connection); | ||
540 | using (cmd) | ||
541 | { | ||
542 | delete.Parameters.Add(new MySqlParameter("?RegionUUID", Util.ToRawUuidString(regionID))); | ||
543 | 448 | ||
544 | CheckConnection(); | 449 | cmd.CommandText = "delete from terrain where " + |
545 | delete.ExecuteNonQuery(); | 450 | "RegionUUID = ?RegionUUID"; |
451 | cmd.Parameters.AddWithValue("RegionUUID", | ||
452 | Util.ToRawUuidString(regionID)); | ||
546 | 453 | ||
547 | cmd.Parameters.Add(new MySqlParameter("?RegionUUID", Util.ToRawUuidString(regionID))); | 454 | ExecuteNonQuery(cmd); |
548 | cmd.Parameters.Add(new MySqlParameter("?Revision", revision)); | 455 | |
549 | cmd.Parameters.Add(new MySqlParameter("?Heightfield", serializeTerrain(ter))); | 456 | cmd.CommandText = "insert into terrain (RegionUUID, " + |
550 | cmd.ExecuteNonQuery(); | 457 | "Revision, Heightfield) values (?RegionUUID, " + |
551 | } | 458 | "1, ?Heightfield)"; |
459 | |||
460 | cmd.Parameters.AddWithValue("Heightfield", | ||
461 | SerializeTerrain(ter)); | ||
462 | |||
463 | ExecuteNonQuery(cmd); | ||
552 | } | 464 | } |
553 | } | 465 | } |
554 | 466 | ||
555 | /// <summary> | ||
556 | /// Load the latest terrain revision from region storage | ||
557 | /// </summary> | ||
558 | /// <param name="regionID">the region UUID</param> | ||
559 | /// <returns>Heightfield data</returns> | ||
560 | public double[,] LoadTerrain(UUID regionID) | 467 | public double[,] LoadTerrain(UUID regionID) |
561 | { | 468 | { |
562 | double[,] terret = new double[256,256]; | 469 | double[,] terrain = new double[256,256]; |
563 | terret.Initialize(); | 470 | terrain.Initialize(); |
564 | 471 | ||
565 | MySqlCommand cmd = new MySqlCommand( | 472 | lock (m_Connection) |
566 | @"select RegionUUID, Revision, Heightfield from terrain | ||
567 | where RegionUUID=?RegionUUID order by Revision desc limit 1" | ||
568 | , m_connection); | ||
569 | |||
570 | // MySqlParameter param = new MySqlParameter(); | ||
571 | cmd.Parameters.Add(new MySqlParameter("?RegionUUID", Util.ToRawUuidString(regionID))); | ||
572 | |||
573 | if (m_connection.State != ConnectionState.Open) | ||
574 | { | 473 | { |
575 | m_connection.Open(); | 474 | MySqlCommand cmd = m_Connection.CreateCommand(); |
576 | } | 475 | cmd.CommandText = "select RegionUUID, Revision, Heightfield " + |
476 | "from terrain where RegionUUID = ?RegionUUID "+ | ||
477 | "order by Revision desc limit 1"; | ||
478 | cmd.Parameters.AddWithValue("RegionUUID", Util.ToRawUuidString(regionID)); | ||
479 | |||
480 | IDataReader reader = ExecuteReader(cmd); | ||
577 | 481 | ||
578 | lock (m_dataSet) | ||
579 | { | ||
580 | CheckConnection(); | ||
581 | MySqlDataReader row = cmd.ExecuteReader(); | ||
582 | try | 482 | try |
583 | { | 483 | { |
584 | int rev = 0; | 484 | while (reader.Read()) |
585 | if (row.Read()) | ||
586 | { | 485 | { |
587 | MemoryStream str = new MemoryStream((byte[]) row["Heightfield"]); | 486 | MemoryStream mstr = new MemoryStream((byte[]) reader["Heightfield"]); |
588 | BinaryReader br = new BinaryReader(str); | 487 | int rev = 0; |
488 | |||
489 | BinaryReader br = new BinaryReader(mstr); | ||
589 | for (int x = 0; x < 256; x++) | 490 | for (int x = 0; x < 256; x++) |
590 | { | 491 | { |
591 | for (int y = 0; y < 256; y++) | 492 | for (int y = 0; y < 256; y++) |
592 | { | 493 | { |
593 | terret[x, y] = br.ReadDouble(); | 494 | terrain[x, y] = br.ReadDouble(); |
594 | } | 495 | } |
496 | rev = Convert.ToInt32(reader["Revision"]); | ||
595 | } | 497 | } |
596 | rev = (int) row["Revision"]; | 498 | m_log.InfoFormat("[REGION DB]: Loaded terrain " + |
597 | } | 499 | "revision r{0}", rev); |
598 | else | ||
599 | { | ||
600 | m_log.Info("[REGION DB]: No terrain found for region"); | ||
601 | return null; | ||
602 | } | ||
603 | 500 | ||
604 | m_log.Info("[REGION DB]: Loaded terrain revision r" + rev.ToString()); | 501 | return terrain; |
502 | } | ||
605 | } | 503 | } |
606 | finally | 504 | finally |
607 | { | 505 | { |
608 | row.Close(); | 506 | reader.Close(); |
609 | } | 507 | } |
610 | } | 508 | } |
611 | return terret; | 509 | |
510 | return terrain; | ||
612 | } | 511 | } |
613 | 512 | ||
614 | /// <summary> | ||
615 | /// <list type="bullet"> | ||
616 | /// <item>delete from land where UUID=globalID</item> | ||
617 | /// <item>delete from landaccesslist where LandUUID=globalID</item> | ||
618 | /// </list> | ||
619 | /// </summary> | ||
620 | /// <param name="globalID"></param> | ||
621 | public void RemoveLandObject(UUID globalID) | 513 | public void RemoveLandObject(UUID globalID) |
622 | { | 514 | { |
623 | lock (m_dataSet) | 515 | lock (m_Connection) |
624 | { | 516 | { |
625 | CheckConnection(); | 517 | MySqlCommand cmd = m_Connection.CreateCommand(); |
626 | using (MySqlCommand cmd = new MySqlCommand("delete from land where UUID=?UUID", m_connection)) | ||
627 | { | ||
628 | cmd.Parameters.Add(new MySqlParameter("?UUID", Util.ToRawUuidString(globalID))); | ||
629 | cmd.ExecuteNonQuery(); | ||
630 | } | ||
631 | 518 | ||
632 | using ( | 519 | cmd.CommandText = "delete from land where UUID = ?UUID"; |
633 | MySqlCommand cmd = new MySqlCommand("delete from landaccesslist where LandUUID=?UUID", m_connection) | 520 | |
634 | ) | 521 | cmd.Parameters.AddWithValue("UUID", Util.ToRawUuidString(globalID)); |
635 | { | 522 | |
636 | cmd.Parameters.Add(new MySqlParameter("?UUID", Util.ToRawUuidString(globalID))); | 523 | ExecuteNonQuery(cmd); |
637 | cmd.ExecuteNonQuery(); | ||
638 | } | ||
639 | } | 524 | } |
640 | } | 525 | } |
641 | 526 | ||
642 | /// <summary> | ||
643 | /// </summary> | ||
644 | /// <param name="parcel"></param> | ||
645 | public void StoreLandObject(ILandObject parcel) | 527 | public void StoreLandObject(ILandObject parcel) |
646 | { | 528 | { |
647 | lock (m_dataSet) | 529 | lock (m_Connection) |
648 | { | 530 | { |
649 | CheckConnection(); | 531 | MySqlCommand cmd = m_Connection.CreateCommand(); |
650 | DataTable land = m_landTable; | 532 | |
651 | DataTable landaccesslist = m_landAccessListTable; | 533 | cmd.CommandText = "replace into land (UUID, RegionUUID, " + |
652 | 534 | "LocalLandID, Bitmap, Name, Description, " + | |
653 | DataRow landRow = land.Rows.Find(Util.ToRawUuidString(parcel.landData.GlobalID)); | 535 | "OwnerUUID, IsGroupOwned, Area, AuctionID, " + |
654 | if (landRow == null) | 536 | "Category, ClaimDate, ClaimPrice, GroupUUID, " + |
655 | { | 537 | "SalePrice, LandStatus, LandFlags, LandingType, " + |
656 | landRow = land.NewRow(); | 538 | "MediaAutoScale, MediaTextureUUID, MediaURL, " + |
657 | fillLandRow(landRow, parcel.landData, parcel.regionUUID); | 539 | "MusicURL, PassHours, PassPrice, SnapshotUUID, " + |
658 | land.Rows.Add(landRow); | 540 | "UserLocationX, UserLocationY, UserLocationZ, " + |
659 | } | 541 | "UserLookAtX, UserLookAtY, UserLookAtZ, " + |
660 | else | 542 | "AuthbuyerID, OtherCleanTime, Dwell) values (" + |
661 | { | 543 | "?UUID, ?RegionUUID, " + |
662 | fillLandRow(landRow, parcel.landData, parcel.regionUUID); | 544 | "?LocalLandID, ?Bitmap, ?Name, ?Description, " + |
663 | } | 545 | "?OwnerUUID, ?IsGroupOwned, ?Area, ?AuctionID, " + |
664 | 546 | "?Category, ?ClaimDate, ?ClaimPrice, ?GroupUUID, " + | |
665 | using ( | 547 | "?SalePrice, ?LandStatus, ?LandFlags, ?LandingType, " + |
666 | MySqlCommand cmd = | 548 | "?MediaAutoScale, ?MediaTextureUUID, ?MediaURL, " + |
667 | new MySqlCommand("delete from landaccesslist where LandUUID=?LandUUID", m_connection)) | 549 | "?MusicURL, ?PassHours, ?PassPrice, ?SnapshotUUID, " + |
550 | "?UserLocationX, ?UserLocationY, ?UserLocationZ, " + | ||
551 | "?UserLookAtX, ?UserLookAtY, ?UserLookAtZ, " + | ||
552 | "?AuthbuyerID, ?OtherCleanTime, ?Dwell)"; | ||
553 | |||
554 | FillLandCommand(cmd, parcel.landData, parcel.regionUUID); | ||
555 | |||
556 | ExecuteNonQuery(cmd); | ||
557 | |||
558 | cmd.CommandText = "delete from landaccesslist where " + | ||
559 | "LandUUID = ?UUID"; | ||
560 | |||
561 | ExecuteNonQuery(cmd); | ||
562 | |||
563 | cmd.Parameters.Clear(); | ||
564 | cmd.CommandText = "insert into landaccesslist (LandUUID, " + | ||
565 | "AccessUUID, Flags) values (?LandUUID, ?AccessUUID, " + | ||
566 | "?Flags)"; | ||
567 | |||
568 | foreach (ParcelManager.ParcelAccessEntry entry in | ||
569 | parcel.landData.ParcelAccessList) | ||
668 | { | 570 | { |
669 | cmd.Parameters.Add(new MySqlParameter("?LandUUID", Util.ToRawUuidString(parcel.landData.GlobalID))); | 571 | FillLandAccessCommand(cmd, entry, parcel.landData.GlobalID); |
670 | cmd.ExecuteNonQuery(); | 572 | ExecuteNonQuery(cmd); |
573 | cmd.Parameters.Clear(); | ||
671 | } | 574 | } |
672 | |||
673 | foreach (ParcelManager.ParcelAccessEntry entry in parcel.landData.ParcelAccessList) | ||
674 | { | ||
675 | DataRow newAccessRow = landaccesslist.NewRow(); | ||
676 | fillLandAccessRow(newAccessRow, entry, parcel.landData.GlobalID); | ||
677 | landaccesslist.Rows.Add(newAccessRow); | ||
678 | } | ||
679 | |||
680 | Commit(); | ||
681 | } | 575 | } |
682 | } | 576 | } |
683 | 577 | ||
684 | public RegionSettings LoadRegionSettings(UUID regionUUID) | 578 | public RegionSettings LoadRegionSettings(UUID regionUUID) |
685 | { | 579 | { |
686 | lock (m_dataSet) | 580 | RegionSettings rs = null; |
687 | { | ||
688 | CheckConnection(); | ||
689 | DataTable regionsettings = m_regionSettingsTable; | ||
690 | string searchExp = "regionUUID = '" + regionUUID.ToString() + "'"; | ||
691 | DataRow[] rawsettings = regionsettings.Select(searchExp); | ||
692 | if (rawsettings.Length == 0) | ||
693 | { | ||
694 | RegionSettings rs = new RegionSettings(); | ||
695 | rs.RegionUUID = regionUUID; | ||
696 | rs.OnSave += StoreRegionSettings; | ||
697 | |||
698 | StoreRegionSettings(rs); | ||
699 | 581 | ||
700 | return rs; | 582 | lock (m_Connection) |
701 | } | ||
702 | DataRow row = rawsettings[0]; | ||
703 | |||
704 | RegionSettings newSettings = buildRegionSettings(row); | ||
705 | newSettings.OnSave += StoreRegionSettings; | ||
706 | |||
707 | return newSettings; | ||
708 | } | ||
709 | } | ||
710 | |||
711 | public void StoreRegionSettings(RegionSettings rs) | ||
712 | { | ||
713 | lock (m_dataSet) | ||
714 | { | 583 | { |
715 | CheckConnection(); | 584 | MySqlCommand cmd = m_Connection.CreateCommand(); |
716 | DataTable regionsettings = m_dataSet.Tables["regionsettings"]; | ||
717 | 585 | ||
718 | DataRow settingsRow = regionsettings.Rows.Find(rs.RegionUUID.ToString()); | 586 | cmd.CommandText = "select * from regionsettings where " + |
719 | if (settingsRow == null) | 587 | "regionUUID = ?RegionUUID"; |
720 | { | 588 | cmd.Parameters.AddWithValue("regionUUID", regionUUID); |
721 | settingsRow = regionsettings.NewRow(); | ||
722 | fillRegionSettingsRow(settingsRow, rs); | ||
723 | regionsettings.Rows.Add(settingsRow); | ||
724 | } | ||
725 | else | ||
726 | { | ||
727 | fillRegionSettingsRow(settingsRow, rs); | ||
728 | } | ||
729 | 589 | ||
730 | Commit(); | 590 | IDataReader reader = ExecuteReader(cmd); |
731 | } | ||
732 | } | ||
733 | 591 | ||
734 | /// <summary> | 592 | try |
735 | /// | ||
736 | /// </summary> | ||
737 | /// <param name="regionUUID"></param> | ||
738 | /// <returns></returns> | ||
739 | public List<LandData> LoadLandObjects(UUID regionUUID) | ||
740 | { | ||
741 | List<LandData> landDataForRegion = new List<LandData>(); | ||
742 | lock (m_dataSet) | ||
743 | { | ||
744 | CheckConnection(); | ||
745 | DataTable land = m_landTable; | ||
746 | DataTable landaccesslist = m_landAccessListTable; | ||
747 | string searchExp = "RegionUUID = '" + Util.ToRawUuidString(regionUUID) + "'"; | ||
748 | DataRow[] rawDataForRegion = land.Select(searchExp); | ||
749 | foreach (DataRow rawDataLand in rawDataForRegion) | ||
750 | { | 593 | { |
751 | LandData newLand = buildLandData(rawDataLand); | 594 | if (reader.Read()) |
752 | string accessListSearchExp = "LandUUID = '" + Util.ToRawUuidString(newLand.GlobalID) + "'"; | ||
753 | DataRow[] rawDataForLandAccessList = landaccesslist.Select(accessListSearchExp); | ||
754 | foreach (DataRow rawDataLandAccess in rawDataForLandAccessList) | ||
755 | { | 595 | { |
756 | newLand.ParcelAccessList.Add(buildLandAccessData(rawDataLandAccess)); | 596 | rs = BuildRegionSettings(reader); |
597 | rs.OnSave += StoreRegionSettings; | ||
757 | } | 598 | } |
599 | else | ||
600 | { | ||
601 | rs = new RegionSettings(); | ||
602 | rs.RegionUUID = regionUUID; | ||
603 | rs.OnSave += StoreRegionSettings; | ||
758 | 604 | ||
759 | landDataForRegion.Add(newLand); | 605 | StoreRegionSettings(rs); |
606 | } | ||
607 | } | ||
608 | finally | ||
609 | { | ||
610 | reader.Close(); | ||
760 | } | 611 | } |
761 | } | 612 | } |
762 | return landDataForRegion; | 613 | |
614 | return rs; | ||
763 | } | 615 | } |
764 | 616 | ||
765 | /// <summary> | 617 | public void StoreRegionSettings(RegionSettings rs) |
766 | /// | ||
767 | /// </summary> | ||
768 | public void Commit() | ||
769 | { | 618 | { |
770 | lock (m_dataSet) | 619 | lock (m_Connection) |
771 | { | 620 | { |
772 | CheckConnection(); | 621 | MySqlCommand cmd = m_Connection.CreateCommand(); |
773 | // DisplayDataSet(m_dataSet, "Region DataSet"); | 622 | |
774 | 623 | cmd.CommandText = "replace into regionsettings (regionUUID, " + | |
775 | m_primDataAdapter.Update(m_primTable); | 624 | "block_terraform, block_fly, allow_damage, " + |
776 | m_shapeDataAdapter.Update(m_shapeTable); | 625 | "restrict_pushing, allow_land_resell, " + |
777 | 626 | "allow_land_join_divide, block_show_in_search, " + | |
778 | m_itemsDataAdapter.Update(m_itemsTable); | 627 | "agent_limit, object_bonus, maturity, " + |
779 | 628 | "disable_scripts, disable_collisions, " + | |
780 | m_terrainDataAdapter.Update(m_terrainTable); | 629 | "disable_physics, terrain_texture_1, " + |
781 | m_landDataAdapter.Update(m_landTable); | 630 | "terrain_texture_2, terrain_texture_3, " + |
782 | m_landAccessListDataAdapter.Update(m_landAccessListTable); | 631 | "terrain_texture_4, elevation_1_nw, " + |
783 | m_regionSettingsDataAdapter.Update(m_regionSettingsTable); | 632 | "elevation_2_nw, elevation_1_ne, " + |
784 | 633 | "elevation_2_ne, elevation_1_se, "+ | |
785 | m_dataSet.AcceptChanges(); | 634 | "elevation_2_se, elevation_1_sw, "+ |
635 | "elevation_2_sw, water_height, " + | ||
636 | "terrain_raise_limit, terrain_lower_limit, " + | ||
637 | "use_estate_sun, fixed_sun, sun_position, " + | ||
638 | "covenant, Sandbox, sunvectorx, sunvectory, " + | ||
639 | "sunvectorz) values ( ?RegionUUID, ?BlockTerraform, " + | ||
640 | "?BlockFly, ?AllowDamage, ?RestrictPushing, " + | ||
641 | "?AllowLandResell, ?AllowLandJoinDivide, " + | ||
642 | "?BlockShowInSearch, ?AgentLimit, ?ObjectBonus, " + | ||
643 | "?Maturity, ?DisableScripts, ?DisableCollisions, " + | ||
644 | "?DisablePhysics, ?TerrainTexture1, " + | ||
645 | "?TerrainTexture2, ?TerrainTexture3, " + | ||
646 | "?TerrainTexture4, ?Elevation1NW, ?Elevation2NW, " + | ||
647 | "?Elevation1NE, ?Elevation2NE, ?Elevation1SE, " + | ||
648 | "?Elevation2SE, ?Elevation1SW, ?Elevation2SW, " + | ||
649 | "?WaterHeight, ?TerrainRaiseLimit, " + | ||
650 | "?TerrainLowerLimit, ?UseEstateSun, ?FixedSun, " + | ||
651 | "?SunPosition, ?Covenant, ?Sandbox, " + | ||
652 | "?SunVectorX, ?SunVectorY, ?SunVectorZ)"; | ||
653 | |||
654 | FillRegionSettingsCommand(cmd, rs); | ||
655 | |||
656 | ExecuteNonQuery(cmd); | ||
786 | } | 657 | } |
787 | } | 658 | } |
788 | 659 | ||
789 | /// <summary> | 660 | public List<LandData> LoadLandObjects(UUID regionUUID) |
790 | /// See <see cref="Commit"/> | ||
791 | /// </summary> | ||
792 | public void Shutdown() | ||
793 | { | ||
794 | Commit(); | ||
795 | } | ||
796 | |||
797 | /*********************************************************************** | ||
798 | * | ||
799 | * Database Definition Functions | ||
800 | * | ||
801 | * This should be db agnostic as we define them in ADO.NET terms | ||
802 | * | ||
803 | **********************************************************************/ | ||
804 | |||
805 | /// <summary> | ||
806 | /// | ||
807 | /// </summary> | ||
808 | /// <param name="dt"></param> | ||
809 | /// <param name="name"></param> | ||
810 | /// <param name="type"></param> | ||
811 | /// <returns></returns> | ||
812 | private static DataColumn createCol(DataTable dt, string name, Type type) | ||
813 | { | ||
814 | DataColumn col = new DataColumn(name, type); | ||
815 | dt.Columns.Add(col); | ||
816 | return col; | ||
817 | } | ||
818 | |||
819 | /// <summary> | ||
820 | /// Create the "terrain" table | ||
821 | /// </summary> | ||
822 | /// <returns></returns> | ||
823 | private static DataTable createTerrainTable() | ||
824 | { | ||
825 | DataTable terrain = new DataTable("terrain"); | ||
826 | |||
827 | createCol(terrain, "RegionUUID", typeof (String)); | ||
828 | createCol(terrain, "Revision", typeof (Int32)); | ||
829 | createCol(terrain, "Heightfield", typeof (Byte[])); | ||
830 | return terrain; | ||
831 | } | ||
832 | |||
833 | /// <summary> | ||
834 | /// Create the "regionsettings" table | ||
835 | /// </summary> | ||
836 | /// <returns></returns> | ||
837 | private static DataTable createRegionSettingsTable() | ||
838 | { | ||
839 | DataTable regionsettings = new DataTable("regionsettings"); | ||
840 | createCol(regionsettings, "regionUUID", typeof(String)); | ||
841 | createCol(regionsettings, "block_terraform", typeof (Int32)); | ||
842 | createCol(regionsettings, "block_fly", typeof (Int32)); | ||
843 | createCol(regionsettings, "allow_damage", typeof (Int32)); | ||
844 | createCol(regionsettings, "restrict_pushing", typeof (Int32)); | ||
845 | createCol(regionsettings, "allow_land_resell", typeof (Int32)); | ||
846 | createCol(regionsettings, "allow_land_join_divide", typeof (Int32)); | ||
847 | createCol(regionsettings, "block_show_in_search", typeof (Int32)); | ||
848 | createCol(regionsettings, "agent_limit", typeof (Int32)); | ||
849 | createCol(regionsettings, "object_bonus", typeof (Double)); | ||
850 | createCol(regionsettings, "maturity", typeof (Int32)); | ||
851 | createCol(regionsettings, "disable_scripts", typeof (Int32)); | ||
852 | createCol(regionsettings, "disable_collisions", typeof (Int32)); | ||
853 | createCol(regionsettings, "disable_physics", typeof (Int32)); | ||
854 | createCol(regionsettings, "terrain_texture_1", typeof(String)); | ||
855 | createCol(regionsettings, "terrain_texture_2", typeof(String)); | ||
856 | createCol(regionsettings, "terrain_texture_3", typeof(String)); | ||
857 | createCol(regionsettings, "terrain_texture_4", typeof(String)); | ||
858 | createCol(regionsettings, "elevation_1_nw", typeof (Double)); | ||
859 | createCol(regionsettings, "elevation_2_nw", typeof (Double)); | ||
860 | createCol(regionsettings, "elevation_1_ne", typeof (Double)); | ||
861 | createCol(regionsettings, "elevation_2_ne", typeof (Double)); | ||
862 | createCol(regionsettings, "elevation_1_se", typeof (Double)); | ||
863 | createCol(regionsettings, "elevation_2_se", typeof (Double)); | ||
864 | createCol(regionsettings, "elevation_1_sw", typeof (Double)); | ||
865 | createCol(regionsettings, "elevation_2_sw", typeof (Double)); | ||
866 | createCol(regionsettings, "water_height", typeof (Double)); | ||
867 | createCol(regionsettings, "terrain_raise_limit", typeof (Double)); | ||
868 | createCol(regionsettings, "terrain_lower_limit", typeof (Double)); | ||
869 | createCol(regionsettings, "use_estate_sun", typeof (Int32)); | ||
870 | createCol(regionsettings, "sandbox", typeof (Int32)); | ||
871 | createCol(regionsettings, "sunvectorx",typeof (Double)); | ||
872 | createCol(regionsettings, "sunvectory",typeof (Double)); | ||
873 | createCol(regionsettings, "sunvectorz",typeof (Double)); | ||
874 | createCol(regionsettings, "fixed_sun", typeof (Int32)); | ||
875 | createCol(regionsettings, "sun_position", typeof (Double)); | ||
876 | createCol(regionsettings, "covenant", typeof(String)); | ||
877 | |||
878 | regionsettings.PrimaryKey = new DataColumn[] {regionsettings.Columns["RegionUUID"]}; | ||
879 | |||
880 | return regionsettings; | ||
881 | } | ||
882 | |||
883 | /// <summary> | ||
884 | /// Create the "prims" table | ||
885 | /// </summary> | ||
886 | /// <returns></returns> | ||
887 | private static DataTable createPrimTable() | ||
888 | { | 661 | { |
889 | DataTable prims = new DataTable("prims"); | 662 | List<LandData> landData = new List<LandData>(); |
890 | |||
891 | createCol(prims, "UUID", typeof (String)); | ||
892 | createCol(prims, "RegionUUID", typeof (String)); | ||
893 | createCol(prims, "ParentID", typeof (Int32)); | ||
894 | createCol(prims, "CreationDate", typeof (Int32)); | ||
895 | createCol(prims, "Name", typeof (String)); | ||
896 | createCol(prims, "SceneGroupID", typeof (String)); | ||
897 | // various text fields | ||
898 | createCol(prims, "Text", typeof (String)); | ||
899 | createCol(prims, "ColorR", typeof (Int32)); | ||
900 | createCol(prims, "ColorG", typeof (Int32)); | ||
901 | createCol(prims, "ColorB", typeof (Int32)); | ||
902 | createCol(prims, "ColorA", typeof (Int32)); | ||
903 | createCol(prims, "Description", typeof (String)); | ||
904 | createCol(prims, "SitName", typeof (String)); | ||
905 | createCol(prims, "TouchName", typeof (String)); | ||
906 | // permissions | ||
907 | createCol(prims, "ObjectFlags", typeof (Int32)); | ||
908 | createCol(prims, "CreatorID", typeof (String)); | ||
909 | createCol(prims, "OwnerID", typeof (String)); | ||
910 | createCol(prims, "GroupID", typeof (String)); | ||
911 | createCol(prims, "LastOwnerID", typeof (String)); | ||
912 | createCol(prims, "OwnerMask", typeof (Int32)); | ||
913 | createCol(prims, "NextOwnerMask", typeof (Int32)); | ||
914 | createCol(prims, "GroupMask", typeof (Int32)); | ||
915 | createCol(prims, "EveryoneMask", typeof (Int32)); | ||
916 | createCol(prims, "BaseMask", typeof (Int32)); | ||
917 | // vectors | ||
918 | createCol(prims, "PositionX", typeof (Double)); | ||
919 | createCol(prims, "PositionY", typeof (Double)); | ||
920 | createCol(prims, "PositionZ", typeof (Double)); | ||
921 | createCol(prims, "GroupPositionX", typeof (Double)); | ||
922 | createCol(prims, "GroupPositionY", typeof (Double)); | ||
923 | createCol(prims, "GroupPositionZ", typeof (Double)); | ||
924 | createCol(prims, "VelocityX", typeof (Double)); | ||
925 | createCol(prims, "VelocityY", typeof (Double)); | ||
926 | createCol(prims, "VelocityZ", typeof (Double)); | ||
927 | createCol(prims, "AngularVelocityX", typeof (Double)); | ||
928 | createCol(prims, "AngularVelocityY", typeof (Double)); | ||
929 | createCol(prims, "AngularVelocityZ", typeof (Double)); | ||
930 | createCol(prims, "AccelerationX", typeof (Double)); | ||
931 | createCol(prims, "AccelerationY", typeof (Double)); | ||
932 | createCol(prims, "AccelerationZ", typeof (Double)); | ||
933 | // quaternions | ||
934 | createCol(prims, "RotationX", typeof (Double)); | ||
935 | createCol(prims, "RotationY", typeof (Double)); | ||
936 | createCol(prims, "RotationZ", typeof (Double)); | ||
937 | createCol(prims, "RotationW", typeof (Double)); | ||
938 | // sit target | ||
939 | createCol(prims, "SitTargetOffsetX", typeof (Double)); | ||
940 | createCol(prims, "SitTargetOffsetY", typeof (Double)); | ||
941 | createCol(prims, "SitTargetOffsetZ", typeof (Double)); | ||
942 | |||
943 | createCol(prims, "SitTargetOrientW", typeof (Double)); | ||
944 | createCol(prims, "SitTargetOrientX", typeof (Double)); | ||
945 | createCol(prims, "SitTargetOrientY", typeof (Double)); | ||
946 | createCol(prims, "SitTargetOrientZ", typeof (Double)); | ||
947 | |||
948 | createCol(prims, "PayPrice", typeof(Int32)); | ||
949 | createCol(prims, "PayButton1", typeof(Int32)); | ||
950 | createCol(prims, "PayButton2", typeof(Int32)); | ||
951 | createCol(prims, "PayButton3", typeof(Int32)); | ||
952 | createCol(prims, "PayButton4", typeof(Int32)); | ||
953 | |||
954 | createCol(prims, "LoopedSound", typeof(String)); | ||
955 | createCol(prims, "LoopedSoundGain", typeof(Double)); | ||
956 | createCol(prims, "TextureAnimation", typeof(Byte[])); | ||
957 | createCol(prims, "ParticleSystem", typeof(Byte[])); | ||
958 | |||
959 | createCol(prims, "OmegaX", typeof (Double)); | ||
960 | createCol(prims, "OmegaY", typeof (Double)); | ||
961 | createCol(prims, "OmegaZ", typeof (Double)); | ||
962 | |||
963 | createCol(prims, "CameraEyeOffsetX", typeof (Double)); | ||
964 | createCol(prims, "CameraEyeOffsetY", typeof (Double)); | ||
965 | createCol(prims, "CameraEyeOffsetZ", typeof (Double)); | ||
966 | 663 | ||
967 | createCol(prims, "CameraAtOffsetX", typeof (Double)); | 664 | lock (m_Connection) |
968 | createCol(prims, "CameraAtOffsetY", typeof (Double)); | 665 | { |
969 | createCol(prims, "CameraAtOffsetZ", typeof (Double)); | 666 | MySqlCommand cmd = m_Connection.CreateCommand(); |
970 | |||
971 | createCol(prims, "ForceMouselook", typeof (Int16)); | ||
972 | |||
973 | createCol(prims, "ScriptAccessPin", typeof(Int32)); | ||
974 | |||
975 | createCol(prims, "AllowedDrop", typeof (Int16)); | ||
976 | createCol(prims, "DieAtEdge", typeof (Int16)); | ||
977 | |||
978 | createCol(prims, "SalePrice", typeof(Int32)); | ||
979 | createCol(prims, "SaleType", typeof (Int16)); | ||
980 | |||
981 | createCol(prims, "ClickAction", typeof (Byte)); | ||
982 | createCol(prims, "Material", typeof (Byte)); | ||
983 | 667 | ||
984 | createCol(prims, "CollisionSound", typeof(String)); | 668 | cmd.CommandText = "select * from land where " + |
985 | createCol(prims, "CollisionSoundVolume", typeof(Double)); | 669 | "RegionUUID = ?RegionUUID"; |
986 | 670 | ||
987 | // Add in contraints | 671 | cmd.Parameters.AddWithValue("RegionUUID", |
988 | prims.PrimaryKey = new DataColumn[] {prims.Columns["UUID"]}; | 672 | Util.ToRawUuidString(regionUUID)); |
989 | 673 | ||
990 | return prims; | 674 | IDataReader reader = ExecuteReader(cmd); |
991 | } | ||
992 | 675 | ||
993 | /// <summary> | 676 | try |
994 | /// Create the "land" table | 677 | { |
995 | /// </summary> | 678 | while (reader.Read()) |
996 | /// <returns></returns> | 679 | { |
997 | private static DataTable createLandTable() | 680 | LandData newLand = BuildLandData(reader); |
998 | { | 681 | landData.Add(newLand); |
999 | DataTable land = new DataTable("land"); | 682 | } |
1000 | createCol(land, "UUID", typeof (String)); | 683 | } |
1001 | createCol(land, "RegionUUID", typeof (String)); | 684 | finally |
1002 | createCol(land, "LocalLandID", typeof (Int32)); | 685 | { |
686 | reader.Close(); | ||
687 | } | ||
1003 | 688 | ||
1004 | // Bitmap is a byte[512] | 689 | foreach (LandData land in landData) |
1005 | createCol(land, "Bitmap", typeof (Byte[])); | 690 | { |
1006 | 691 | cmd.Parameters.Clear(); | |
1007 | createCol(land, "Name", typeof (String)); | ||
1008 | createCol(land, "Description", typeof (String)); | ||
1009 | createCol(land, "OwnerUUID", typeof (String)); | ||
1010 | createCol(land, "IsGroupOwned", typeof (Int32)); | ||
1011 | createCol(land, "Area", typeof (Int32)); | ||
1012 | createCol(land, "AuctionID", typeof (Int32)); //Unemplemented | ||
1013 | createCol(land, "Category", typeof (Int32)); //Enum libsecondlife.Parcel.ParcelCategory | ||
1014 | createCol(land, "ClaimDate", typeof (Int32)); | ||
1015 | createCol(land, "ClaimPrice", typeof (Int32)); | ||
1016 | createCol(land, "GroupUUID", typeof (String)); | ||
1017 | createCol(land, "SalePrice", typeof (Int32)); | ||
1018 | createCol(land, "LandStatus", typeof (Int32)); //Enum. libsecondlife.Parcel.ParcelStatus | ||
1019 | createCol(land, "LandFlags", typeof (UInt32)); | ||
1020 | createCol(land, "LandingType", typeof (Int32)); | ||
1021 | createCol(land, "MediaAutoScale", typeof (Int32)); | ||
1022 | createCol(land, "MediaTextureUUID", typeof (String)); | ||
1023 | createCol(land, "MediaURL", typeof (String)); | ||
1024 | createCol(land, "MusicURL", typeof (String)); | ||
1025 | createCol(land, "PassHours", typeof (Double)); | ||
1026 | createCol(land, "PassPrice", typeof (Int32)); | ||
1027 | createCol(land, "SnapshotUUID", typeof (String)); | ||
1028 | createCol(land, "UserLocationX", typeof (Double)); | ||
1029 | createCol(land, "UserLocationY", typeof (Double)); | ||
1030 | createCol(land, "UserLocationZ", typeof (Double)); | ||
1031 | createCol(land, "UserLookAtX", typeof (Double)); | ||
1032 | createCol(land, "UserLookAtY", typeof (Double)); | ||
1033 | createCol(land, "UserLookAtZ", typeof (Double)); | ||
1034 | createCol(land, "AuthBuyerID", typeof (String)); | ||
1035 | createCol(land, "OtherCleanTime", typeof(Int32)); | ||
1036 | createCol(land, "Dwell", typeof(Int32)); | ||
1037 | |||
1038 | land.PrimaryKey = new DataColumn[] {land.Columns["UUID"]}; | ||
1039 | |||
1040 | return land; | ||
1041 | } | ||
1042 | 692 | ||
1043 | /// <summary> | 693 | cmd.CommandText = "select * from landaccesslist " + |
1044 | /// Create the "landaccesslist" table | 694 | "where LandUUID = ?LandUUID"; |
1045 | /// </summary> | ||
1046 | /// <returns></returns> | ||
1047 | private static DataTable createLandAccessListTable() | ||
1048 | { | ||
1049 | DataTable landaccess = new DataTable("landaccesslist"); | ||
1050 | createCol(landaccess, "LandUUID", typeof (String)); | ||
1051 | createCol(landaccess, "AccessUUID", typeof (String)); | ||
1052 | createCol(landaccess, "Flags", typeof (Int32)); | ||
1053 | 695 | ||
1054 | return landaccess; | 696 | cmd.Parameters.AddWithValue("LandUUID", |
1055 | } | 697 | Util.ToRawUuidString(land.GlobalID)); |
1056 | 698 | ||
1057 | /// <summary> | 699 | reader = ExecuteReader(cmd); |
1058 | /// Create the "primshapes" table | ||
1059 | /// </summary> | ||
1060 | /// <returns></returns> | ||
1061 | private static DataTable createShapeTable() | ||
1062 | { | ||
1063 | DataTable shapes = new DataTable("primshapes"); | ||
1064 | createCol(shapes, "UUID", typeof (String)); | ||
1065 | // shape is an enum | ||
1066 | createCol(shapes, "Shape", typeof (Int32)); | ||
1067 | // vectors | ||
1068 | createCol(shapes, "ScaleX", typeof (Double)); | ||
1069 | createCol(shapes, "ScaleY", typeof (Double)); | ||
1070 | createCol(shapes, "ScaleZ", typeof (Double)); | ||
1071 | // paths | ||
1072 | createCol(shapes, "PCode", typeof (Int32)); | ||
1073 | createCol(shapes, "PathBegin", typeof (Int32)); | ||
1074 | createCol(shapes, "PathEnd", typeof (Int32)); | ||
1075 | createCol(shapes, "PathScaleX", typeof (Int32)); | ||
1076 | createCol(shapes, "PathScaleY", typeof (Int32)); | ||
1077 | createCol(shapes, "PathShearX", typeof (Int32)); | ||
1078 | createCol(shapes, "PathShearY", typeof (Int32)); | ||
1079 | createCol(shapes, "PathSkew", typeof (Int32)); | ||
1080 | createCol(shapes, "PathCurve", typeof (Int32)); | ||
1081 | createCol(shapes, "PathRadiusOffset", typeof (Int32)); | ||
1082 | createCol(shapes, "PathRevolutions", typeof (Int32)); | ||
1083 | createCol(shapes, "PathTaperX", typeof (Int32)); | ||
1084 | createCol(shapes, "PathTaperY", typeof (Int32)); | ||
1085 | createCol(shapes, "PathTwist", typeof (Int32)); | ||
1086 | createCol(shapes, "PathTwistBegin", typeof (Int32)); | ||
1087 | // profile | ||
1088 | createCol(shapes, "ProfileBegin", typeof (Int32)); | ||
1089 | createCol(shapes, "ProfileEnd", typeof (Int32)); | ||
1090 | createCol(shapes, "ProfileCurve", typeof (Int32)); | ||
1091 | createCol(shapes, "ProfileHollow", typeof (Int32)); | ||
1092 | createCol(shapes, "State", typeof(Int32)); | ||
1093 | createCol(shapes, "Texture", typeof (Byte[])); | ||
1094 | createCol(shapes, "ExtraParams", typeof (Byte[])); | ||
1095 | 700 | ||
1096 | shapes.PrimaryKey = new DataColumn[] {shapes.Columns["UUID"]}; | 701 | try |
702 | { | ||
703 | while (reader.Read()) | ||
704 | { | ||
705 | land.ParcelAccessList.Add(BuildLandAccessData(reader)); | ||
706 | } | ||
707 | } | ||
708 | finally | ||
709 | { | ||
710 | reader.Close(); | ||
711 | } | ||
712 | } | ||
713 | } | ||
1097 | 714 | ||
1098 | return shapes; | 715 | return landData; |
1099 | } | 716 | } |
1100 | 717 | ||
1101 | /// <summary> | 718 | public void Shutdown() |
1102 | /// Create the "primitems" table | ||
1103 | /// </summary> | ||
1104 | /// <returns></returns> | ||
1105 | private static DataTable createItemsTable() | ||
1106 | { | 719 | { |
1107 | DataTable items = new DataTable("primitems"); | ||
1108 | |||
1109 | createCol(items, "itemID", typeof (String)); | ||
1110 | createCol(items, "primID", typeof (String)); | ||
1111 | createCol(items, "assetID", typeof (String)); | ||
1112 | createCol(items, "parentFolderID", typeof (String)); | ||
1113 | |||
1114 | createCol(items, "invType", typeof (Int32)); | ||
1115 | createCol(items, "assetType", typeof (Int32)); | ||
1116 | |||
1117 | createCol(items, "name", typeof (String)); | ||
1118 | createCol(items, "description", typeof (String)); | ||
1119 | |||
1120 | createCol(items, "creationDate", typeof (Int64)); | ||
1121 | createCol(items, "creatorID", typeof (String)); | ||
1122 | createCol(items, "ownerID", typeof (String)); | ||
1123 | createCol(items, "lastOwnerID", typeof (String)); | ||
1124 | createCol(items, "groupID", typeof (String)); | ||
1125 | |||
1126 | createCol(items, "nextPermissions", typeof (Int32)); | ||
1127 | createCol(items, "currentPermissions", typeof (Int32)); | ||
1128 | createCol(items, "basePermissions", typeof (Int32)); | ||
1129 | createCol(items, "everyonePermissions", typeof (Int32)); | ||
1130 | createCol(items, "groupPermissions", typeof (Int32)); | ||
1131 | createCol(items, "flags", typeof (Int32)); | ||
1132 | |||
1133 | items.PrimaryKey = new DataColumn[] {items.Columns["itemID"]}; | ||
1134 | |||
1135 | return items; | ||
1136 | } | 720 | } |
1137 | 721 | ||
1138 | /*********************************************************************** | 722 | private SceneObjectPart BuildPrim(IDataReader row) |
1139 | * | ||
1140 | * Convert between ADO.NET <=> OpenSim Objects | ||
1141 | * | ||
1142 | * These should be database independant | ||
1143 | * | ||
1144 | **********************************************************************/ | ||
1145 | |||
1146 | /// <summary> | ||
1147 | /// | ||
1148 | /// </summary> | ||
1149 | /// <param name="row"></param> | ||
1150 | /// <returns></returns> | ||
1151 | private SceneObjectPart buildPrim(DataRow row) | ||
1152 | { | 723 | { |
1153 | SceneObjectPart prim = new SceneObjectPart(); | 724 | SceneObjectPart prim = new SceneObjectPart(); |
1154 | prim.UUID = new UUID((String) row["UUID"]); | 725 | prim.UUID = new UUID((String) row["UUID"]); |
@@ -1232,9 +803,9 @@ namespace OpenSim.Data.MySQL | |||
1232 | prim.SoundGain = Convert.ToSingle(row["LoopedSoundGain"]); | 803 | prim.SoundGain = Convert.ToSingle(row["LoopedSoundGain"]); |
1233 | prim.SoundFlags = 1; // If it's persisted at all, it's looped | 804 | prim.SoundFlags = 1; // If it's persisted at all, it's looped |
1234 | 805 | ||
1235 | if (!row.IsNull("TextureAnimation")) | 806 | if (!(row["TextureAnimation"] is DBNull)) |
1236 | prim.TextureAnimation = (Byte[])row["TextureAnimation"]; | 807 | prim.TextureAnimation = (Byte[])row["TextureAnimation"]; |
1237 | if (!row.IsNull("ParticleSystem")) | 808 | if (!(row["ParticleSystem"] is DBNull)) |
1238 | prim.ParticleSystem = (Byte[])row["ParticleSystem"]; | 809 | prim.ParticleSystem = (Byte[])row["ParticleSystem"]; |
1239 | 810 | ||
1240 | prim.RotationalVelocity = new Vector3( | 811 | prim.RotationalVelocity = new Vector3( |
@@ -1271,11 +842,12 @@ namespace OpenSim.Data.MySQL | |||
1271 | 842 | ||
1272 | prim.Material = Convert.ToByte(row["Material"]); | 843 | prim.Material = Convert.ToByte(row["Material"]); |
1273 | 844 | ||
1274 | if (!row.IsNull("ClickAction")) | 845 | if (!(row["ClickAction"] is DBNull)) |
1275 | prim.ClickAction = Convert.ToByte(row["ClickAction"]); | 846 | prim.ClickAction = (byte)Convert.ToByte(row["ClickAction"]); |
1276 | 847 | ||
1277 | prim.CollisionSound = new UUID(row["CollisionSound"].ToString()); | 848 | prim.CollisionSound = new UUID(row["CollisionSound"].ToString()); |
1278 | prim.CollisionSoundVolume = Convert.ToSingle(row["CollisionSoundVolume"]); | 849 | prim.CollisionSoundVolume = Convert.ToSingle(row["CollisionSoundVolume"]); |
850 | prim.LinkNum = Convert.ToInt32(row["LinkNumber"]); | ||
1279 | 851 | ||
1280 | return prim; | 852 | return prim; |
1281 | } | 853 | } |
@@ -1286,7 +858,7 @@ namespace OpenSim.Data.MySQL | |||
1286 | /// </summary> | 858 | /// </summary> |
1287 | /// <param name="row"></param> | 859 | /// <param name="row"></param> |
1288 | /// <returns></returns> | 860 | /// <returns></returns> |
1289 | private static TaskInventoryItem buildItem(DataRow row) | 861 | private static TaskInventoryItem BuildItem(IDataReader row) |
1290 | { | 862 | { |
1291 | TaskInventoryItem taskItem = new TaskInventoryItem(); | 863 | TaskInventoryItem taskItem = new TaskInventoryItem(); |
1292 | 864 | ||
@@ -1316,7 +888,7 @@ namespace OpenSim.Data.MySQL | |||
1316 | return taskItem; | 888 | return taskItem; |
1317 | } | 889 | } |
1318 | 890 | ||
1319 | private static RegionSettings buildRegionSettings(DataRow row) | 891 | private static RegionSettings BuildRegionSettings(IDataReader row) |
1320 | { | 892 | { |
1321 | RegionSettings newSettings = new RegionSettings(); | 893 | RegionSettings newSettings = new RegionSettings(); |
1322 | 894 | ||
@@ -1368,7 +940,7 @@ namespace OpenSim.Data.MySQL | |||
1368 | /// </summary> | 940 | /// </summary> |
1369 | /// <param name="row"></param> | 941 | /// <param name="row"></param> |
1370 | /// <returns></returns> | 942 | /// <returns></returns> |
1371 | private static LandData buildLandData(DataRow row) | 943 | private static LandData BuildLandData(IDataReader row) |
1372 | { | 944 | { |
1373 | LandData newData = new LandData(); | 945 | LandData newData = new LandData(); |
1374 | 946 | ||
@@ -1436,7 +1008,7 @@ namespace OpenSim.Data.MySQL | |||
1436 | /// </summary> | 1008 | /// </summary> |
1437 | /// <param name="row"></param> | 1009 | /// <param name="row"></param> |
1438 | /// <returns></returns> | 1010 | /// <returns></returns> |
1439 | private static ParcelManager.ParcelAccessEntry buildLandAccessData(DataRow row) | 1011 | private static ParcelManager.ParcelAccessEntry BuildLandAccessData(IDataReader row) |
1440 | { | 1012 | { |
1441 | ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry(); | 1013 | ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry(); |
1442 | entry.AgentID = new UUID((string) row["AccessUUID"]); | 1014 | entry.AgentID = new UUID((string) row["AccessUUID"]); |
@@ -1450,7 +1022,7 @@ namespace OpenSim.Data.MySQL | |||
1450 | /// </summary> | 1022 | /// </summary> |
1451 | /// <param name="val"></param> | 1023 | /// <param name="val"></param> |
1452 | /// <returns></returns> | 1024 | /// <returns></returns> |
1453 | private static Array serializeTerrain(double[,] val) | 1025 | private static Array SerializeTerrain(double[,] val) |
1454 | { | 1026 | { |
1455 | MemoryStream str = new MemoryStream(65536*sizeof (double)); | 1027 | MemoryStream str = new MemoryStream(65536*sizeof (double)); |
1456 | BinaryWriter bw = new BinaryWriter(str); | 1028 | BinaryWriter bw = new BinaryWriter(str); |
@@ -1476,128 +1048,129 @@ namespace OpenSim.Data.MySQL | |||
1476 | /// <param name="prim"></param> | 1048 | /// <param name="prim"></param> |
1477 | /// <param name="sceneGroupID"></param> | 1049 | /// <param name="sceneGroupID"></param> |
1478 | /// <param name="regionUUID"></param> | 1050 | /// <param name="regionUUID"></param> |
1479 | private void fillPrimRow(DataRow row, SceneObjectPart prim, UUID sceneGroupID, UUID regionUUID) | 1051 | private void FillPrimCommand(MySqlCommand cmd, SceneObjectPart prim, UUID sceneGroupID, UUID regionUUID) |
1480 | { | 1052 | { |
1481 | row["UUID"] = Util.ToRawUuidString(prim.UUID); | 1053 | cmd.Parameters.AddWithValue("UUID", Util.ToRawUuidString(prim.UUID)); |
1482 | row["RegionUUID"] = Util.ToRawUuidString(regionUUID); | 1054 | cmd.Parameters.AddWithValue("RegionUUID", Util.ToRawUuidString(regionUUID)); |
1483 | row["ParentID"] = prim.ParentID; | 1055 | cmd.Parameters.AddWithValue("ParentID", prim.ParentID); |
1484 | row["CreationDate"] = prim.CreationDate; | 1056 | cmd.Parameters.AddWithValue("CreationDate", prim.CreationDate); |
1485 | row["Name"] = prim.Name; | 1057 | cmd.Parameters.AddWithValue("Name", prim.Name); |
1486 | row["SceneGroupID"] = Util.ToRawUuidString(sceneGroupID); | 1058 | cmd.Parameters.AddWithValue("SceneGroupID", Util.ToRawUuidString(sceneGroupID)); |
1487 | // the UUID of the root part for this SceneObjectGroup | 1059 | // the UUID of the root part for this SceneObjectGroup |
1488 | // various text fields | 1060 | // various text fields |
1489 | row["Text"] = prim.Text; | 1061 | cmd.Parameters.AddWithValue("Text", prim.Text); |
1490 | row["ColorR"] = prim.Color.R; | 1062 | cmd.Parameters.AddWithValue("ColorR", prim.Color.R); |
1491 | row["ColorG"] = prim.Color.G; | 1063 | cmd.Parameters.AddWithValue("ColorG", prim.Color.G); |
1492 | row["ColorB"] = prim.Color.B; | 1064 | cmd.Parameters.AddWithValue("ColorB", prim.Color.B); |
1493 | row["ColorA"] = prim.Color.A; | 1065 | cmd.Parameters.AddWithValue("ColorA", prim.Color.A); |
1494 | row["Description"] = prim.Description; | 1066 | cmd.Parameters.AddWithValue("Description", prim.Description); |
1495 | row["SitName"] = prim.SitName; | 1067 | cmd.Parameters.AddWithValue("SitName", prim.SitName); |
1496 | row["TouchName"] = prim.TouchName; | 1068 | cmd.Parameters.AddWithValue("TouchName", prim.TouchName); |
1497 | // permissions | 1069 | // permissions |
1498 | row["ObjectFlags"] = prim.ObjectFlags; | 1070 | cmd.Parameters.AddWithValue("ObjectFlags", prim.ObjectFlags); |
1499 | row["CreatorID"] = Util.ToRawUuidString(prim.CreatorID); | 1071 | cmd.Parameters.AddWithValue("CreatorID", Util.ToRawUuidString(prim.CreatorID)); |
1500 | row["OwnerID"] = Util.ToRawUuidString(prim.OwnerID); | 1072 | cmd.Parameters.AddWithValue("OwnerID", Util.ToRawUuidString(prim.OwnerID)); |
1501 | row["GroupID"] = Util.ToRawUuidString(prim.GroupID); | 1073 | cmd.Parameters.AddWithValue("GroupID", Util.ToRawUuidString(prim.GroupID)); |
1502 | row["LastOwnerID"] = Util.ToRawUuidString(prim.LastOwnerID); | 1074 | cmd.Parameters.AddWithValue("LastOwnerID", Util.ToRawUuidString(prim.LastOwnerID)); |
1503 | row["OwnerMask"] = prim.OwnerMask; | 1075 | cmd.Parameters.AddWithValue("OwnerMask", prim.OwnerMask); |
1504 | row["NextOwnerMask"] = prim.NextOwnerMask; | 1076 | cmd.Parameters.AddWithValue("NextOwnerMask", prim.NextOwnerMask); |
1505 | row["GroupMask"] = prim.GroupMask; | 1077 | cmd.Parameters.AddWithValue("GroupMask", prim.GroupMask); |
1506 | row["EveryoneMask"] = prim.EveryoneMask; | 1078 | cmd.Parameters.AddWithValue("EveryoneMask", prim.EveryoneMask); |
1507 | row["BaseMask"] = prim.BaseMask; | 1079 | cmd.Parameters.AddWithValue("BaseMask", prim.BaseMask); |
1508 | // vectors | 1080 | // vectors |
1509 | row["PositionX"] = prim.OffsetPosition.X; | 1081 | cmd.Parameters.AddWithValue("PositionX", prim.OffsetPosition.X); |
1510 | row["PositionY"] = prim.OffsetPosition.Y; | 1082 | cmd.Parameters.AddWithValue("PositionY", prim.OffsetPosition.Y); |
1511 | row["PositionZ"] = prim.OffsetPosition.Z; | 1083 | cmd.Parameters.AddWithValue("PositionZ", prim.OffsetPosition.Z); |
1512 | row["GroupPositionX"] = prim.GroupPosition.X; | 1084 | cmd.Parameters.AddWithValue("GroupPositionX", prim.GroupPosition.X); |
1513 | row["GroupPositionY"] = prim.GroupPosition.Y; | 1085 | cmd.Parameters.AddWithValue("GroupPositionY", prim.GroupPosition.Y); |
1514 | row["GroupPositionZ"] = prim.GroupPosition.Z; | 1086 | cmd.Parameters.AddWithValue("GroupPositionZ", prim.GroupPosition.Z); |
1515 | row["VelocityX"] = prim.Velocity.X; | 1087 | cmd.Parameters.AddWithValue("VelocityX", prim.Velocity.X); |
1516 | row["VelocityY"] = prim.Velocity.Y; | 1088 | cmd.Parameters.AddWithValue("VelocityY", prim.Velocity.Y); |
1517 | row["VelocityZ"] = prim.Velocity.Z; | 1089 | cmd.Parameters.AddWithValue("VelocityZ", prim.Velocity.Z); |
1518 | row["AngularVelocityX"] = prim.AngularVelocity.X; | 1090 | cmd.Parameters.AddWithValue("AngularVelocityX", prim.AngularVelocity.X); |
1519 | row["AngularVelocityY"] = prim.AngularVelocity.Y; | 1091 | cmd.Parameters.AddWithValue("AngularVelocityY", prim.AngularVelocity.Y); |
1520 | row["AngularVelocityZ"] = prim.AngularVelocity.Z; | 1092 | cmd.Parameters.AddWithValue("AngularVelocityZ", prim.AngularVelocity.Z); |
1521 | row["AccelerationX"] = prim.Acceleration.X; | 1093 | cmd.Parameters.AddWithValue("AccelerationX", prim.Acceleration.X); |
1522 | row["AccelerationY"] = prim.Acceleration.Y; | 1094 | cmd.Parameters.AddWithValue("AccelerationY", prim.Acceleration.Y); |
1523 | row["AccelerationZ"] = prim.Acceleration.Z; | 1095 | cmd.Parameters.AddWithValue("AccelerationZ", prim.Acceleration.Z); |
1524 | // quaternions | 1096 | // quaternions |
1525 | row["RotationX"] = prim.RotationOffset.X; | 1097 | cmd.Parameters.AddWithValue("RotationX", prim.RotationOffset.X); |
1526 | row["RotationY"] = prim.RotationOffset.Y; | 1098 | cmd.Parameters.AddWithValue("RotationY", prim.RotationOffset.Y); |
1527 | row["RotationZ"] = prim.RotationOffset.Z; | 1099 | cmd.Parameters.AddWithValue("RotationZ", prim.RotationOffset.Z); |
1528 | row["RotationW"] = prim.RotationOffset.W; | 1100 | cmd.Parameters.AddWithValue("RotationW", prim.RotationOffset.W); |
1529 | 1101 | ||
1530 | // Sit target | 1102 | // Sit target |
1531 | Vector3 sitTargetPos = prim.SitTargetPositionLL; | 1103 | Vector3 sitTargetPos = prim.SitTargetPositionLL; |
1532 | row["SitTargetOffsetX"] = sitTargetPos.X; | 1104 | cmd.Parameters.AddWithValue("SitTargetOffsetX", sitTargetPos.X); |
1533 | row["SitTargetOffsetY"] = sitTargetPos.Y; | 1105 | cmd.Parameters.AddWithValue("SitTargetOffsetY", sitTargetPos.Y); |
1534 | row["SitTargetOffsetZ"] = sitTargetPos.Z; | 1106 | cmd.Parameters.AddWithValue("SitTargetOffsetZ", sitTargetPos.Z); |
1535 | 1107 | ||
1536 | Quaternion sitTargetOrient = prim.SitTargetOrientationLL; | 1108 | Quaternion sitTargetOrient = prim.SitTargetOrientationLL; |
1537 | row["SitTargetOrientW"] = sitTargetOrient.W; | 1109 | cmd.Parameters.AddWithValue("SitTargetOrientW", sitTargetOrient.W); |
1538 | row["SitTargetOrientX"] = sitTargetOrient.X; | 1110 | cmd.Parameters.AddWithValue("SitTargetOrientX", sitTargetOrient.X); |
1539 | row["SitTargetOrientY"] = sitTargetOrient.Y; | 1111 | cmd.Parameters.AddWithValue("SitTargetOrientY", sitTargetOrient.Y); |
1540 | row["SitTargetOrientZ"] = sitTargetOrient.Z; | 1112 | cmd.Parameters.AddWithValue("SitTargetOrientZ", sitTargetOrient.Z); |
1541 | 1113 | ||
1542 | row["PayPrice"] = prim.PayPrice[0]; | 1114 | cmd.Parameters.AddWithValue("PayPrice", prim.PayPrice[0]); |
1543 | row["PayButton1"] = prim.PayPrice[1]; | 1115 | cmd.Parameters.AddWithValue("PayButton1", prim.PayPrice[1]); |
1544 | row["PayButton2"] = prim.PayPrice[2]; | 1116 | cmd.Parameters.AddWithValue("PayButton2", prim.PayPrice[2]); |
1545 | row["PayButton3"] = prim.PayPrice[3]; | 1117 | cmd.Parameters.AddWithValue("PayButton3", prim.PayPrice[3]); |
1546 | row["PayButton4"] = prim.PayPrice[4]; | 1118 | cmd.Parameters.AddWithValue("PayButton4", prim.PayPrice[4]); |
1547 | 1119 | ||
1548 | if ((prim.SoundFlags & 1) != 0) // Looped | 1120 | if ((prim.SoundFlags & 1) != 0) // Looped |
1549 | { | 1121 | { |
1550 | row["LoopedSound"] = prim.Sound.ToString(); | 1122 | cmd.Parameters.AddWithValue("LoopedSound", prim.Sound.ToString()); |
1551 | row["LoopedSoundGain"] = prim.SoundGain; | 1123 | cmd.Parameters.AddWithValue("LoopedSoundGain", prim.SoundGain); |
1552 | } | 1124 | } |
1553 | else | 1125 | else |
1554 | { | 1126 | { |
1555 | row["LoopedSound"] = UUID.Zero; | 1127 | cmd.Parameters.AddWithValue("LoopedSound", UUID.Zero); |
1556 | row["LoopedSoundGain"] = 0.0f; | 1128 | cmd.Parameters.AddWithValue("LoopedSoundGain", 0.0f); |
1557 | } | 1129 | } |
1558 | 1130 | ||
1559 | row["TextureAnimation"] = prim.TextureAnimation; | 1131 | cmd.Parameters.AddWithValue("TextureAnimation", prim.TextureAnimation); |
1560 | row["ParticleSystem"] = prim.ParticleSystem; | 1132 | cmd.Parameters.AddWithValue("ParticleSystem", prim.ParticleSystem); |
1561 | 1133 | ||
1562 | row["OmegaX"] = prim.RotationalVelocity.X; | 1134 | cmd.Parameters.AddWithValue("OmegaX", prim.RotationalVelocity.X); |
1563 | row["OmegaY"] = prim.RotationalVelocity.Y; | 1135 | cmd.Parameters.AddWithValue("OmegaY", prim.RotationalVelocity.Y); |
1564 | row["OmegaZ"] = prim.RotationalVelocity.Z; | 1136 | cmd.Parameters.AddWithValue("OmegaZ", prim.RotationalVelocity.Z); |
1565 | 1137 | ||
1566 | row["CameraEyeOffsetX"] = prim.GetCameraEyeOffset().X; | 1138 | cmd.Parameters.AddWithValue("CameraEyeOffsetX", prim.GetCameraEyeOffset().X); |
1567 | row["CameraEyeOffsetY"] = prim.GetCameraEyeOffset().Y; | 1139 | cmd.Parameters.AddWithValue("CameraEyeOffsetY", prim.GetCameraEyeOffset().Y); |
1568 | row["CameraEyeOffsetZ"] = prim.GetCameraEyeOffset().Z; | 1140 | cmd.Parameters.AddWithValue("CameraEyeOffsetZ", prim.GetCameraEyeOffset().Z); |
1569 | 1141 | ||
1570 | row["CameraAtOffsetX"] = prim.GetCameraAtOffset().X; | 1142 | cmd.Parameters.AddWithValue("CameraAtOffsetX", prim.GetCameraAtOffset().X); |
1571 | row["CameraAtOffsetY"] = prim.GetCameraAtOffset().Y; | 1143 | cmd.Parameters.AddWithValue("CameraAtOffsetY", prim.GetCameraAtOffset().Y); |
1572 | row["CameraAtOffsetZ"] = prim.GetCameraAtOffset().Z; | 1144 | cmd.Parameters.AddWithValue("CameraAtOffsetZ", prim.GetCameraAtOffset().Z); |
1573 | 1145 | ||
1574 | if (prim.GetForceMouselook()) | 1146 | if (prim.GetForceMouselook()) |
1575 | row["ForceMouselook"] = 1; | 1147 | cmd.Parameters.AddWithValue("ForceMouselook", 1); |
1576 | else | 1148 | else |
1577 | row["ForceMouselook"] = 0; | 1149 | cmd.Parameters.AddWithValue("ForceMouselook", 0); |
1578 | 1150 | ||
1579 | row["ScriptAccessPin"] = prim.ScriptAccessPin; | 1151 | cmd.Parameters.AddWithValue("ScriptAccessPin", prim.ScriptAccessPin); |
1580 | 1152 | ||
1581 | if (prim.AllowedDrop) | 1153 | if (prim.AllowedDrop) |
1582 | row["AllowedDrop"] = 1; | 1154 | cmd.Parameters.AddWithValue("AllowedDrop", 1); |
1583 | else | 1155 | else |
1584 | row["AllowedDrop"] = 0; | 1156 | cmd.Parameters.AddWithValue("AllowedDrop", 0); |
1585 | 1157 | ||
1586 | if (prim.DIE_AT_EDGE) | 1158 | if (prim.DIE_AT_EDGE) |
1587 | row["DieAtEdge"] = 1; | 1159 | cmd.Parameters.AddWithValue("DieAtEdge", 1); |
1588 | else | 1160 | else |
1589 | row["DieAtEdge"] = 0; | 1161 | cmd.Parameters.AddWithValue("DieAtEdge", 0); |
1590 | 1162 | ||
1591 | row["SalePrice"] = prim.SalePrice; | 1163 | cmd.Parameters.AddWithValue("SalePrice", prim.SalePrice); |
1592 | row["SaleType"] = Convert.ToInt16(prim.ObjectSaleType); | 1164 | cmd.Parameters.AddWithValue("SaleType", Convert.ToInt16(prim.ObjectSaleType)); |
1593 | 1165 | ||
1594 | byte clickAction = prim.ClickAction; | 1166 | byte clickAction = prim.ClickAction; |
1595 | row["ClickAction"] = clickAction; | 1167 | cmd.Parameters.AddWithValue("ClickAction", clickAction); |
1596 | 1168 | ||
1597 | row["Material"] = prim.Material; | 1169 | cmd.Parameters.AddWithValue("Material", prim.Material); |
1598 | 1170 | ||
1599 | row["CollisionSound"] = prim.CollisionSound.ToString(); | 1171 | cmd.Parameters.AddWithValue("CollisionSound", prim.CollisionSound.ToString()); |
1600 | row["CollisionSoundVolume"] = prim.CollisionSoundVolume; | 1172 | cmd.Parameters.AddWithValue("CollisionSoundVolume", prim.CollisionSoundVolume); |
1173 | cmd.Parameters.AddWithValue("LinkNumber", prim.LinkNum); | ||
1601 | } | 1174 | } |
1602 | 1175 | ||
1603 | /// <summary> | 1176 | /// <summary> |
@@ -1605,73 +1178,73 @@ namespace OpenSim.Data.MySQL | |||
1605 | /// </summary> | 1178 | /// </summary> |
1606 | /// <param name="row"></param> | 1179 | /// <param name="row"></param> |
1607 | /// <param name="taskItem"></param> | 1180 | /// <param name="taskItem"></param> |
1608 | private static void fillItemRow(DataRow row, TaskInventoryItem taskItem) | 1181 | private static void FillItemCommand(MySqlCommand cmd, TaskInventoryItem taskItem) |
1609 | { | 1182 | { |
1610 | row["itemID"] = taskItem.ItemID; | 1183 | cmd.Parameters.AddWithValue("itemID", taskItem.ItemID); |
1611 | row["primID"] = taskItem.ParentPartID; | 1184 | cmd.Parameters.AddWithValue("primID", taskItem.ParentPartID); |
1612 | row["assetID"] = taskItem.AssetID; | 1185 | cmd.Parameters.AddWithValue("assetID", taskItem.AssetID); |
1613 | row["parentFolderID"] = taskItem.ParentID; | 1186 | cmd.Parameters.AddWithValue("parentFolderID", taskItem.ParentID); |
1614 | 1187 | ||
1615 | row["invType"] = taskItem.InvType; | 1188 | cmd.Parameters.AddWithValue("invType", taskItem.InvType); |
1616 | row["assetType"] = taskItem.Type; | 1189 | cmd.Parameters.AddWithValue("assetType", taskItem.Type); |
1617 | 1190 | ||
1618 | row["name"] = taskItem.Name; | 1191 | cmd.Parameters.AddWithValue("name", taskItem.Name); |
1619 | row["description"] = taskItem.Description; | 1192 | cmd.Parameters.AddWithValue("description", taskItem.Description); |
1620 | row["creationDate"] = taskItem.CreationDate; | 1193 | cmd.Parameters.AddWithValue("creationDate", taskItem.CreationDate); |
1621 | row["creatorID"] = taskItem.CreatorID; | 1194 | cmd.Parameters.AddWithValue("creatorID", taskItem.CreatorID); |
1622 | row["ownerID"] = taskItem.OwnerID; | 1195 | cmd.Parameters.AddWithValue("ownerID", taskItem.OwnerID); |
1623 | row["lastOwnerID"] = taskItem.LastOwnerID; | 1196 | cmd.Parameters.AddWithValue("lastOwnerID", taskItem.LastOwnerID); |
1624 | row["groupID"] = taskItem.GroupID; | 1197 | cmd.Parameters.AddWithValue("groupID", taskItem.GroupID); |
1625 | row["nextPermissions"] = taskItem.NextPermissions; | 1198 | cmd.Parameters.AddWithValue("nextPermissions", taskItem.NextPermissions); |
1626 | row["currentPermissions"] = taskItem.CurrentPermissions; | 1199 | cmd.Parameters.AddWithValue("currentPermissions", taskItem.CurrentPermissions); |
1627 | row["basePermissions"] = taskItem.BasePermissions; | 1200 | cmd.Parameters.AddWithValue("basePermissions", taskItem.BasePermissions); |
1628 | row["everyonePermissions"] = taskItem.EveryonePermissions; | 1201 | cmd.Parameters.AddWithValue("everyonePermissions", taskItem.EveryonePermissions); |
1629 | row["groupPermissions"] = taskItem.GroupPermissions; | 1202 | cmd.Parameters.AddWithValue("groupPermissions", taskItem.GroupPermissions); |
1630 | row["flags"] = taskItem.Flags; | 1203 | cmd.Parameters.AddWithValue("flags", taskItem.Flags); |
1631 | } | 1204 | } |
1632 | 1205 | ||
1633 | /// <summary> | 1206 | /// <summary> |
1634 | /// | 1207 | /// |
1635 | /// </summary> | 1208 | /// </summary> |
1636 | private static void fillRegionSettingsRow(DataRow row, RegionSettings settings) | 1209 | private static void FillRegionSettingsCommand(MySqlCommand cmd, RegionSettings settings) |
1637 | { | 1210 | { |
1638 | row["regionUUID"] = settings.RegionUUID.ToString(); | 1211 | cmd.Parameters.AddWithValue("RegionUUID", settings.RegionUUID.ToString()); |
1639 | row["block_terraform"] = settings.BlockTerraform; | 1212 | cmd.Parameters.AddWithValue("BlockTerraform", settings.BlockTerraform); |
1640 | row["block_fly"] = settings.BlockFly; | 1213 | cmd.Parameters.AddWithValue("BlockFly", settings.BlockFly); |
1641 | row["allow_damage"] = settings.AllowDamage; | 1214 | cmd.Parameters.AddWithValue("AllowDamage", settings.AllowDamage); |
1642 | row["restrict_pushing"] = settings.RestrictPushing; | 1215 | cmd.Parameters.AddWithValue("RestrictPushing", settings.RestrictPushing); |
1643 | row["allow_land_resell"] = settings.AllowLandResell; | 1216 | cmd.Parameters.AddWithValue("AllowLandResell", settings.AllowLandResell); |
1644 | row["allow_land_join_divide"] = settings.AllowLandJoinDivide; | 1217 | cmd.Parameters.AddWithValue("AllowLandJoinDivide", settings.AllowLandJoinDivide); |
1645 | row["block_show_in_search"] = settings.BlockShowInSearch; | 1218 | cmd.Parameters.AddWithValue("BlockShowInSearch", settings.BlockShowInSearch); |
1646 | row["agent_limit"] = settings.AgentLimit; | 1219 | cmd.Parameters.AddWithValue("AgentLimit", settings.AgentLimit); |
1647 | row["object_bonus"] = settings.ObjectBonus; | 1220 | cmd.Parameters.AddWithValue("ObjectBonus", settings.ObjectBonus); |
1648 | row["maturity"] = settings.Maturity; | 1221 | cmd.Parameters.AddWithValue("Maturity", settings.Maturity); |
1649 | row["disable_scripts"] = settings.DisableScripts; | 1222 | cmd.Parameters.AddWithValue("DisableScripts", settings.DisableScripts); |
1650 | row["disable_collisions"] = settings.DisableCollisions; | 1223 | cmd.Parameters.AddWithValue("DisableCollisions", settings.DisableCollisions); |
1651 | row["disable_physics"] = settings.DisablePhysics; | 1224 | cmd.Parameters.AddWithValue("DisablePhysics", settings.DisablePhysics); |
1652 | row["terrain_texture_1"] = settings.TerrainTexture1.ToString(); | 1225 | cmd.Parameters.AddWithValue("TerrainTexture1", settings.TerrainTexture1.ToString()); |
1653 | row["terrain_texture_2"] = settings.TerrainTexture2.ToString(); | 1226 | cmd.Parameters.AddWithValue("TerrainTexture2", settings.TerrainTexture2.ToString()); |
1654 | row["terrain_texture_3"] = settings.TerrainTexture3.ToString(); | 1227 | cmd.Parameters.AddWithValue("TerrainTexture3", settings.TerrainTexture3.ToString()); |
1655 | row["terrain_texture_4"] = settings.TerrainTexture4.ToString(); | 1228 | cmd.Parameters.AddWithValue("TerrainTexture4", settings.TerrainTexture4.ToString()); |
1656 | row["elevation_1_nw"] = settings.Elevation1NW; | 1229 | cmd.Parameters.AddWithValue("Elevation1NW", settings.Elevation1NW); |
1657 | row["elevation_2_nw"] = settings.Elevation2NW; | 1230 | cmd.Parameters.AddWithValue("Elevation2NW", settings.Elevation2NW); |
1658 | row["elevation_1_ne"] = settings.Elevation1NE; | 1231 | cmd.Parameters.AddWithValue("Elevation1NE", settings.Elevation1NE); |
1659 | row["elevation_2_ne"] = settings.Elevation2NE; | 1232 | cmd.Parameters.AddWithValue("Elevation2NE", settings.Elevation2NE); |
1660 | row["elevation_1_se"] = settings.Elevation1SE; | 1233 | cmd.Parameters.AddWithValue("Elevation1SE", settings.Elevation1SE); |
1661 | row["elevation_2_se"] = settings.Elevation2SE; | 1234 | cmd.Parameters.AddWithValue("Elevation2SE", settings.Elevation2SE); |
1662 | row["elevation_1_sw"] = settings.Elevation1SW; | 1235 | cmd.Parameters.AddWithValue("Elevation1SW", settings.Elevation1SW); |
1663 | row["elevation_2_sw"] = settings.Elevation2SW; | 1236 | cmd.Parameters.AddWithValue("Elevation2SW", settings.Elevation2SW); |
1664 | row["water_height"] = settings.WaterHeight; | 1237 | cmd.Parameters.AddWithValue("WaterHeight", settings.WaterHeight); |
1665 | row["terrain_raise_limit"] = settings.TerrainRaiseLimit; | 1238 | cmd.Parameters.AddWithValue("TerrainRaiseLimit", settings.TerrainRaiseLimit); |
1666 | row["terrain_lower_limit"] = settings.TerrainLowerLimit; | 1239 | cmd.Parameters.AddWithValue("TerrainLowerLimit", settings.TerrainLowerLimit); |
1667 | row["use_estate_sun"] = settings.UseEstateSun; | 1240 | cmd.Parameters.AddWithValue("UseEstateSun", settings.UseEstateSun); |
1668 | row["sandbox"] = settings.Sandbox; | 1241 | cmd.Parameters.AddWithValue("Sandbox", settings.Sandbox); |
1669 | row["sunvectorx"] = settings.SunVector.X; | 1242 | cmd.Parameters.AddWithValue("SunVectorX", settings.SunVector.X); |
1670 | row["sunvectory"] = settings.SunVector.Y; | 1243 | cmd.Parameters.AddWithValue("SunVectorY", settings.SunVector.Y); |
1671 | row["sunvectorz"] = settings.SunVector.Z; | 1244 | cmd.Parameters.AddWithValue("SunVectorZ", settings.SunVector.Z); |
1672 | row["fixed_sun"] = settings.FixedSun; | 1245 | cmd.Parameters.AddWithValue("FixedSun", settings.FixedSun); |
1673 | row["sun_position"] = settings.SunPosition; | 1246 | cmd.Parameters.AddWithValue("SunPosition", settings.SunPosition); |
1674 | row["covenant"] = settings.Covenant.ToString(); | 1247 | cmd.Parameters.AddWithValue("Covenant", settings.Covenant.ToString()); |
1675 | } | 1248 | } |
1676 | 1249 | ||
1677 | /// <summary> | 1250 | /// <summary> |
@@ -1680,45 +1253,45 @@ namespace OpenSim.Data.MySQL | |||
1680 | /// <param name="row"></param> | 1253 | /// <param name="row"></param> |
1681 | /// <param name="land"></param> | 1254 | /// <param name="land"></param> |
1682 | /// <param name="regionUUID"></param> | 1255 | /// <param name="regionUUID"></param> |
1683 | private static void fillLandRow(DataRow row, LandData land, UUID regionUUID) | 1256 | private static void FillLandCommand(MySqlCommand cmd, LandData land, UUID regionUUID) |
1684 | { | 1257 | { |
1685 | row["UUID"] = Util.ToRawUuidString(land.GlobalID); | 1258 | cmd.Parameters.AddWithValue("UUID", Util.ToRawUuidString(land.GlobalID)); |
1686 | row["RegionUUID"] = Util.ToRawUuidString(regionUUID); | 1259 | cmd.Parameters.AddWithValue("RegionUUID", Util.ToRawUuidString(regionUUID)); |
1687 | row["LocalLandID"] = land.LocalID; | 1260 | cmd.Parameters.AddWithValue("LocalLandID", land.LocalID); |
1688 | 1261 | ||
1689 | // Bitmap is a byte[512] | 1262 | // Bitmap is a byte[512] |
1690 | row["Bitmap"] = land.Bitmap; | 1263 | cmd.Parameters.AddWithValue("Bitmap", land.Bitmap); |
1691 | 1264 | ||
1692 | row["Name"] = land.Name; | 1265 | cmd.Parameters.AddWithValue("Name", land.Name); |
1693 | row["Description"] = land.Description; | 1266 | cmd.Parameters.AddWithValue("Description", land.Description); |
1694 | row["OwnerUUID"] = Util.ToRawUuidString(land.OwnerID); | 1267 | cmd.Parameters.AddWithValue("OwnerUUID", Util.ToRawUuidString(land.OwnerID)); |
1695 | row["IsGroupOwned"] = land.IsGroupOwned; | 1268 | cmd.Parameters.AddWithValue("IsGroupOwned", land.IsGroupOwned); |
1696 | row["Area"] = land.Area; | 1269 | cmd.Parameters.AddWithValue("Area", land.Area); |
1697 | row["AuctionID"] = land.AuctionID; //Unemplemented | 1270 | cmd.Parameters.AddWithValue("AuctionID", land.AuctionID); //Unemplemented |
1698 | row["Category"] = land.Category; //Enum libsecondlife.Parcel.ParcelCategory | 1271 | cmd.Parameters.AddWithValue("Category", land.Category); //Enum libsecondlife.Parcel.ParcelCategory |
1699 | row["ClaimDate"] = land.ClaimDate; | 1272 | cmd.Parameters.AddWithValue("ClaimDate", land.ClaimDate); |
1700 | row["ClaimPrice"] = land.ClaimPrice; | 1273 | cmd.Parameters.AddWithValue("ClaimPrice", land.ClaimPrice); |
1701 | row["GroupUUID"] = Util.ToRawUuidString(land.GroupID); | 1274 | cmd.Parameters.AddWithValue("GroupUUID", Util.ToRawUuidString(land.GroupID)); |
1702 | row["SalePrice"] = land.SalePrice; | 1275 | cmd.Parameters.AddWithValue("SalePrice", land.SalePrice); |
1703 | row["LandStatus"] = land.Status; //Enum. libsecondlife.Parcel.ParcelStatus | 1276 | cmd.Parameters.AddWithValue("LandStatus", land.Status); //Enum. libsecondlife.Parcel.ParcelStatus |
1704 | row["LandFlags"] = land.Flags; | 1277 | cmd.Parameters.AddWithValue("LandFlags", land.Flags); |
1705 | row["LandingType"] = land.LandingType; | 1278 | cmd.Parameters.AddWithValue("LandingType", land.LandingType); |
1706 | row["MediaAutoScale"] = land.MediaAutoScale; | 1279 | cmd.Parameters.AddWithValue("MediaAutoScale", land.MediaAutoScale); |
1707 | row["MediaTextureUUID"] = Util.ToRawUuidString(land.MediaID); | 1280 | cmd.Parameters.AddWithValue("MediaTextureUUID", Util.ToRawUuidString(land.MediaID)); |
1708 | row["MediaURL"] = land.MediaURL; | 1281 | cmd.Parameters.AddWithValue("MediaURL", land.MediaURL); |
1709 | row["MusicURL"] = land.MusicURL; | 1282 | cmd.Parameters.AddWithValue("MusicURL", land.MusicURL); |
1710 | row["PassHours"] = land.PassHours; | 1283 | cmd.Parameters.AddWithValue("PassHours", land.PassHours); |
1711 | row["PassPrice"] = land.PassPrice; | 1284 | cmd.Parameters.AddWithValue("PassPrice", land.PassPrice); |
1712 | row["SnapshotUUID"] = Util.ToRawUuidString(land.SnapshotID); | 1285 | cmd.Parameters.AddWithValue("SnapshotUUID", Util.ToRawUuidString(land.SnapshotID)); |
1713 | row["UserLocationX"] = land.UserLocation.X; | 1286 | cmd.Parameters.AddWithValue("UserLocationX", land.UserLocation.X); |
1714 | row["UserLocationY"] = land.UserLocation.Y; | 1287 | cmd.Parameters.AddWithValue("UserLocationY", land.UserLocation.Y); |
1715 | row["UserLocationZ"] = land.UserLocation.Z; | 1288 | cmd.Parameters.AddWithValue("UserLocationZ", land.UserLocation.Z); |
1716 | row["UserLookAtX"] = land.UserLookAt.X; | 1289 | cmd.Parameters.AddWithValue("UserLookAtX", land.UserLookAt.X); |
1717 | row["UserLookAtY"] = land.UserLookAt.Y; | 1290 | cmd.Parameters.AddWithValue("UserLookAtY", land.UserLookAt.Y); |
1718 | row["UserLookAtZ"] = land.UserLookAt.Z; | 1291 | cmd.Parameters.AddWithValue("UserLookAtZ", land.UserLookAt.Z); |
1719 | row["AuthBuyerID"] = land.AuthBuyerID; | 1292 | cmd.Parameters.AddWithValue("AuthBuyerID", land.AuthBuyerID); |
1720 | row["OtherCleanTime"] = land.OtherCleanTime; | 1293 | cmd.Parameters.AddWithValue("OtherCleanTime", land.OtherCleanTime); |
1721 | row["Dwell"] = land.Dwell; | 1294 | cmd.Parameters.AddWithValue("Dwell", land.Dwell); |
1722 | } | 1295 | } |
1723 | 1296 | ||
1724 | /// <summary> | 1297 | /// <summary> |
@@ -1727,11 +1300,11 @@ namespace OpenSim.Data.MySQL | |||
1727 | /// <param name="row"></param> | 1300 | /// <param name="row"></param> |
1728 | /// <param name="entry"></param> | 1301 | /// <param name="entry"></param> |
1729 | /// <param name="parcelID"></param> | 1302 | /// <param name="parcelID"></param> |
1730 | private static void fillLandAccessRow(DataRow row, ParcelManager.ParcelAccessEntry entry, UUID parcelID) | 1303 | private static void FillLandAccessCommand(MySqlCommand cmd, ParcelManager.ParcelAccessEntry entry, UUID parcelID) |
1731 | { | 1304 | { |
1732 | row["LandUUID"] = Util.ToRawUuidString(parcelID); | 1305 | cmd.Parameters.AddWithValue("LandUUID", Util.ToRawUuidString(parcelID)); |
1733 | row["AccessUUID"] = Util.ToRawUuidString(entry.AgentID); | 1306 | cmd.Parameters.AddWithValue("AccessUUID", Util.ToRawUuidString(entry.AgentID)); |
1734 | row["Flags"] = entry.Flags; | 1307 | cmd.Parameters.AddWithValue("Flags", entry.Flags); |
1735 | } | 1308 | } |
1736 | 1309 | ||
1737 | /// <summary> | 1310 | /// <summary> |
@@ -1739,7 +1312,7 @@ namespace OpenSim.Data.MySQL | |||
1739 | /// </summary> | 1312 | /// </summary> |
1740 | /// <param name="row"></param> | 1313 | /// <param name="row"></param> |
1741 | /// <returns></returns> | 1314 | /// <returns></returns> |
1742 | private PrimitiveBaseShape buildShape(DataRow row) | 1315 | private PrimitiveBaseShape BuildShape(IDataReader row) |
1743 | { | 1316 | { |
1744 | PrimitiveBaseShape s = new PrimitiveBaseShape(); | 1317 | PrimitiveBaseShape s = new PrimitiveBaseShape(); |
1745 | s.Scale = new Vector3( | 1318 | s.Scale = new Vector3( |
@@ -1768,8 +1341,7 @@ namespace OpenSim.Data.MySQL | |||
1768 | s.ProfileEnd = Convert.ToUInt16(row["ProfileEnd"]); | 1341 | s.ProfileEnd = Convert.ToUInt16(row["ProfileEnd"]); |
1769 | s.ProfileCurve = Convert.ToByte(row["ProfileCurve"]); | 1342 | s.ProfileCurve = Convert.ToByte(row["ProfileCurve"]); |
1770 | s.ProfileHollow = Convert.ToUInt16(row["ProfileHollow"]); | 1343 | s.ProfileHollow = Convert.ToUInt16(row["ProfileHollow"]); |
1771 | 1344 | byte[] textureEntry = (byte[]) row["Texture"]; | |
1772 | byte[] textureEntry = (byte[]) row["Texture"]; | ||
1773 | s.TextureEntry = textureEntry; | 1345 | s.TextureEntry = textureEntry; |
1774 | 1346 | ||
1775 | s.ExtraParams = (byte[]) row["ExtraParams"]; | 1347 | s.ExtraParams = (byte[]) row["ExtraParams"]; |
@@ -1784,382 +1356,78 @@ namespace OpenSim.Data.MySQL | |||
1784 | /// </summary> | 1356 | /// </summary> |
1785 | /// <param name="row"></param> | 1357 | /// <param name="row"></param> |
1786 | /// <param name="prim"></param> | 1358 | /// <param name="prim"></param> |
1787 | private void fillShapeRow(DataRow row, SceneObjectPart prim) | 1359 | private void FillShapeCommand(MySqlCommand cmd, SceneObjectPart prim) |
1788 | { | 1360 | { |
1789 | PrimitiveBaseShape s = prim.Shape; | 1361 | PrimitiveBaseShape s = prim.Shape; |
1790 | row["UUID"] = Util.ToRawUuidString(prim.UUID); | 1362 | cmd.Parameters.AddWithValue("UUID", Util.ToRawUuidString(prim.UUID)); |
1791 | // shape is an enum | 1363 | // shape is an enum |
1792 | row["Shape"] = 0; | 1364 | cmd.Parameters.AddWithValue("Shape", 0); |
1793 | // vectors | 1365 | // vectors |
1794 | row["ScaleX"] = s.Scale.X; | 1366 | cmd.Parameters.AddWithValue("ScaleX", s.Scale.X); |
1795 | row["ScaleY"] = s.Scale.Y; | 1367 | cmd.Parameters.AddWithValue("ScaleY", s.Scale.Y); |
1796 | row["ScaleZ"] = s.Scale.Z; | 1368 | cmd.Parameters.AddWithValue("ScaleZ", s.Scale.Z); |
1797 | // paths | 1369 | // paths |
1798 | row["PCode"] = s.PCode; | 1370 | cmd.Parameters.AddWithValue("PCode", s.PCode); |
1799 | row["PathBegin"] = s.PathBegin; | 1371 | cmd.Parameters.AddWithValue("PathBegin", s.PathBegin); |
1800 | row["PathEnd"] = s.PathEnd; | 1372 | cmd.Parameters.AddWithValue("PathEnd", s.PathEnd); |
1801 | row["PathScaleX"] = s.PathScaleX; | 1373 | cmd.Parameters.AddWithValue("PathScaleX", s.PathScaleX); |
1802 | row["PathScaleY"] = s.PathScaleY; | 1374 | cmd.Parameters.AddWithValue("PathScaleY", s.PathScaleY); |
1803 | row["PathShearX"] = s.PathShearX; | 1375 | cmd.Parameters.AddWithValue("PathShearX", s.PathShearX); |
1804 | row["PathShearY"] = s.PathShearY; | 1376 | cmd.Parameters.AddWithValue("PathShearY", s.PathShearY); |
1805 | row["PathSkew"] = s.PathSkew; | 1377 | cmd.Parameters.AddWithValue("PathSkew", s.PathSkew); |
1806 | row["PathCurve"] = s.PathCurve; | 1378 | cmd.Parameters.AddWithValue("PathCurve", s.PathCurve); |
1807 | row["PathRadiusOffset"] = s.PathRadiusOffset; | 1379 | cmd.Parameters.AddWithValue("PathRadiusOffset", s.PathRadiusOffset); |
1808 | row["PathRevolutions"] = s.PathRevolutions; | 1380 | cmd.Parameters.AddWithValue("PathRevolutions", s.PathRevolutions); |
1809 | row["PathTaperX"] = s.PathTaperX; | 1381 | cmd.Parameters.AddWithValue("PathTaperX", s.PathTaperX); |
1810 | row["PathTaperY"] = s.PathTaperY; | 1382 | cmd.Parameters.AddWithValue("PathTaperY", s.PathTaperY); |
1811 | row["PathTwist"] = s.PathTwist; | 1383 | cmd.Parameters.AddWithValue("PathTwist", s.PathTwist); |
1812 | row["PathTwistBegin"] = s.PathTwistBegin; | 1384 | cmd.Parameters.AddWithValue("PathTwistBegin", s.PathTwistBegin); |
1813 | // profile | 1385 | // profile |
1814 | row["ProfileBegin"] = s.ProfileBegin; | 1386 | cmd.Parameters.AddWithValue("ProfileBegin", s.ProfileBegin); |
1815 | row["ProfileEnd"] = s.ProfileEnd; | 1387 | cmd.Parameters.AddWithValue("ProfileEnd", s.ProfileEnd); |
1816 | row["ProfileCurve"] = s.ProfileCurve; | 1388 | cmd.Parameters.AddWithValue("ProfileCurve", s.ProfileCurve); |
1817 | row["ProfileHollow"] = s.ProfileHollow; | 1389 | cmd.Parameters.AddWithValue("ProfileHollow", s.ProfileHollow); |
1818 | row["Texture"] = s.TextureEntry; | 1390 | cmd.Parameters.AddWithValue("Texture", s.TextureEntry); |
1819 | row["ExtraParams"] = s.ExtraParams; | 1391 | cmd.Parameters.AddWithValue("ExtraParams", s.ExtraParams); |
1820 | row["State"] = s.State; | 1392 | cmd.Parameters.AddWithValue("State", s.State); |
1821 | } | 1393 | } |
1822 | 1394 | ||
1823 | /// <summary> | ||
1824 | /// | ||
1825 | /// </summary> | ||
1826 | /// <param name="prim"></param> | ||
1827 | /// <param name="sceneGroupID"></param> | ||
1828 | /// <param name="regionUUID"></param> | ||
1829 | private void addPrim(SceneObjectPart prim, UUID sceneGroupID, UUID regionUUID) | ||
1830 | { | ||
1831 | lock (m_dataSet) | ||
1832 | { | ||
1833 | DataTable prims = m_dataSet.Tables["prims"]; | ||
1834 | DataTable shapes = m_dataSet.Tables["primshapes"]; | ||
1835 | |||
1836 | DataRow primRow = prims.Rows.Find(Util.ToRawUuidString(prim.UUID)); | ||
1837 | if (primRow == null) | ||
1838 | { | ||
1839 | primRow = prims.NewRow(); | ||
1840 | fillPrimRow(primRow, prim, sceneGroupID, regionUUID); | ||
1841 | prims.Rows.Add(primRow); | ||
1842 | } | ||
1843 | else | ||
1844 | { | ||
1845 | fillPrimRow(primRow, prim, sceneGroupID, regionUUID); | ||
1846 | } | ||
1847 | |||
1848 | DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID)); | ||
1849 | if (shapeRow == null) | ||
1850 | { | ||
1851 | shapeRow = shapes.NewRow(); | ||
1852 | fillShapeRow(shapeRow, prim); | ||
1853 | shapes.Rows.Add(shapeRow); | ||
1854 | } | ||
1855 | else | ||
1856 | { | ||
1857 | fillShapeRow(shapeRow, prim); | ||
1858 | } | ||
1859 | } | ||
1860 | } | ||
1861 | |||
1862 | /// <summary> | ||
1863 | /// see IRegionDatastore | ||
1864 | /// </summary> | ||
1865 | /// <param name="primID"></param> | ||
1866 | /// <param name="items"></param> | ||
1867 | public void StorePrimInventory(UUID primID, ICollection<TaskInventoryItem> items) | 1395 | public void StorePrimInventory(UUID primID, ICollection<TaskInventoryItem> items) |
1868 | { | 1396 | { |
1869 | //m_log.InfoFormat("[REGION DB]: Persisting Prim Inventory with prim ID {0}", primID); | 1397 | lock (m_Connection) |
1870 | |||
1871 | // For now, we're just going to crudely remove all the previous inventory items | ||
1872 | // no matter whether they have changed or not, and replace them with the current set. | ||
1873 | lock (m_dataSet) | ||
1874 | { | 1398 | { |
1875 | RemoveItems(primID); | 1399 | RemoveItems(primID); |
1876 | 1400 | ||
1877 | // repalce with current inventory details | 1401 | MySqlCommand cmd = m_Connection.CreateCommand(); |
1878 | foreach (TaskInventoryItem newItem in items) | 1402 | |
1403 | if (items.Count == 0) | ||
1404 | return; | ||
1405 | |||
1406 | cmd.CommandText = "insert into primitems ("+ | ||
1407 | "invType, assetType, name, "+ | ||
1408 | "description, creationDate, nextPermissions, "+ | ||
1409 | "currentPermissions, basePermissions, "+ | ||
1410 | "everyonePermissions, groupPermissions, "+ | ||
1411 | "flags, itemID, primID, assetID, "+ | ||
1412 | "parentFolderID, creatorID, ownerID, "+ | ||
1413 | "groupID, lastOwnerID) values (?invType, "+ | ||
1414 | "?assetType, ?name, ?description, "+ | ||
1415 | "?creationDate, ?nextPermissions, "+ | ||
1416 | "?currentPermissions, ?basePermissions, "+ | ||
1417 | "?everyonePermissions, ?groupPermissions, "+ | ||
1418 | "?flags, ?itemID, ?primID, ?assetID, "+ | ||
1419 | "?parentFolderID, ?creatorID, ?ownerID, "+ | ||
1420 | "?groupID, ?lastOwnerID)"; | ||
1421 | |||
1422 | foreach (TaskInventoryItem item in items) | ||
1879 | { | 1423 | { |
1880 | // m_log.InfoFormat( | 1424 | cmd.Parameters.Clear(); |
1881 | // "[REGION DB]: " + | ||
1882 | // "Adding item {0}, {1} to prim ID {2}", | ||
1883 | // newItem.Name, newItem.ItemID, newItem.ParentPartID); | ||
1884 | |||
1885 | DataRow newItemRow = m_itemsTable.NewRow(); | ||
1886 | fillItemRow(newItemRow, newItem); | ||
1887 | m_itemsTable.Rows.Add(newItemRow); | ||
1888 | } | ||
1889 | } | ||
1890 | |||
1891 | Commit(); | ||
1892 | } | ||
1893 | |||
1894 | /*********************************************************************** | ||
1895 | * | ||
1896 | * SQL Statement Creation Functions | ||
1897 | * | ||
1898 | * These functions create SQL statements for update, insert, and create. | ||
1899 | * They can probably be factored later to have a db independant | ||
1900 | * portion and a db specific portion | ||
1901 | * | ||
1902 | **********************************************************************/ | ||
1903 | |||
1904 | /// <summary> | ||
1905 | /// Create a MySQL insert command | ||
1906 | /// </summary> | ||
1907 | /// <param name="table"></param> | ||
1908 | /// <param name="dt"></param> | ||
1909 | /// <returns></returns> | ||
1910 | /// <remarks> | ||
1911 | /// This is subtle enough to deserve some commentary. | ||
1912 | /// Instead of doing *lots* and *lots of hardcoded strings | ||
1913 | /// for database definitions we'll use the fact that | ||
1914 | /// realistically all insert statements look like "insert | ||
1915 | /// into A(b, c) values(:b, :c) on the parameterized query | ||
1916 | /// front. If we just have a list of b, c, etc... we can | ||
1917 | /// generate these strings instead of typing them out. | ||
1918 | /// </remarks> | ||
1919 | private static MySqlCommand createInsertCommand(string table, DataTable dt) | ||
1920 | { | ||
1921 | 1425 | ||
1922 | string[] cols = new string[dt.Columns.Count]; | 1426 | FillItemCommand(cmd, item); |
1923 | for (int i = 0; i < dt.Columns.Count; i++) | ||
1924 | { | ||
1925 | DataColumn col = dt.Columns[i]; | ||
1926 | cols[i] = col.ColumnName; | ||
1927 | } | ||
1928 | 1427 | ||
1929 | string sql = "insert into " + table + "("; | 1428 | ExecuteNonQuery(cmd); |
1930 | sql += String.Join(", ", cols); | ||
1931 | // important, the first ':' needs to be here, the rest get added in the join | ||
1932 | sql += ") values (?"; | ||
1933 | sql += String.Join(", ?", cols); | ||
1934 | sql += ")"; | ||
1935 | MySqlCommand cmd = new MySqlCommand(sql); | ||
1936 | |||
1937 | // this provides the binding for all our parameters, so | ||
1938 | // much less code than it used to be | ||
1939 | foreach (DataColumn col in dt.Columns) | ||
1940 | { | ||
1941 | cmd.Parameters.Add(createMySqlParameter(col.ColumnName, col.DataType)); | ||
1942 | } | ||
1943 | return cmd; | ||
1944 | } | ||
1945 | |||
1946 | /// <summary> | ||
1947 | /// Create a MySQL update command | ||
1948 | /// </summary> | ||
1949 | /// <param name="table"></param> | ||
1950 | /// <param name="pk"></param> | ||
1951 | /// <param name="dt"></param> | ||
1952 | /// <returns></returns> | ||
1953 | private static MySqlCommand createUpdateCommand(string table, string pk, DataTable dt) | ||
1954 | { | ||
1955 | string sql = "update " + table + " set "; | ||
1956 | string subsql = String.Empty; | ||
1957 | foreach (DataColumn col in dt.Columns) | ||
1958 | { | ||
1959 | if (subsql.Length > 0) | ||
1960 | { | ||
1961 | // a map function would rock so much here | ||
1962 | subsql += ", "; | ||
1963 | } | 1429 | } |
1964 | subsql += col.ColumnName + "=?" + col.ColumnName; | ||
1965 | } | ||
1966 | sql += subsql; | ||
1967 | sql += " where " + pk; | ||
1968 | MySqlCommand cmd = new MySqlCommand(sql); | ||
1969 | |||
1970 | // this provides the binding for all our parameters, so | ||
1971 | // much less code than it used to be | ||
1972 | |||
1973 | foreach (DataColumn col in dt.Columns) | ||
1974 | { | ||
1975 | cmd.Parameters.Add(createMySqlParameter(col.ColumnName, col.DataType)); | ||
1976 | } | ||
1977 | return cmd; | ||
1978 | } | ||
1979 | |||
1980 | /*********************************************************************** | ||
1981 | * | ||
1982 | * Database Binding functions | ||
1983 | * | ||
1984 | * These will be db specific due to typing, and minor differences | ||
1985 | * in databases. | ||
1986 | * | ||
1987 | **********************************************************************/ | ||
1988 | |||
1989 | ///<summary> | ||
1990 | /// <para>This is a convenience function that collapses 5 repetitive | ||
1991 | /// lines for defining MySqlParameters to 2 parameters: | ||
1992 | /// column name and database type. | ||
1993 | /// </para> | ||
1994 | /// <para> | ||
1995 | /// It assumes certain conventions like ?param as the param | ||
1996 | /// name to replace in parametrized queries, and that source | ||
1997 | /// version is always current version, both of which are fine | ||
1998 | /// for us. | ||
1999 | /// </para> | ||
2000 | /// </summary> | ||
2001 | /// <returns>a built MySql parameter</returns> | ||
2002 | private static MySqlParameter createMySqlParameter(string name, Type type) | ||
2003 | { | ||
2004 | MySqlParameter param = new MySqlParameter(); | ||
2005 | param.ParameterName = "?" + name; | ||
2006 | param.DbType = dbtypeFromType(type); | ||
2007 | param.SourceColumn = name; | ||
2008 | param.SourceVersion = DataRowVersion.Current; | ||
2009 | return param; | ||
2010 | } | ||
2011 | |||
2012 | /// <summary> | ||
2013 | /// | ||
2014 | /// </summary> | ||
2015 | /// <param name="da"></param> | ||
2016 | /// <param name="conn"></param> | ||
2017 | private void SetupPrimCommands(MySqlDataAdapter da, MySqlConnection conn) | ||
2018 | { | ||
2019 | MySqlCommand insertCommand = createInsertCommand("prims", m_primTable); | ||
2020 | insertCommand.Connection = conn; | ||
2021 | da.InsertCommand = insertCommand; | ||
2022 | |||
2023 | MySqlCommand updateCommand = createUpdateCommand("prims", "UUID=?UUID", m_primTable); | ||
2024 | updateCommand.Connection = conn; | ||
2025 | da.UpdateCommand = updateCommand; | ||
2026 | |||
2027 | MySqlCommand delete = new MySqlCommand("delete from prims where UUID=?UUID"); | ||
2028 | delete.Parameters.Add(createMySqlParameter("UUID", typeof (String))); | ||
2029 | delete.Connection = conn; | ||
2030 | da.DeleteCommand = delete; | ||
2031 | } | ||
2032 | |||
2033 | /// <summary> | ||
2034 | /// | ||
2035 | /// </summary> | ||
2036 | /// <param name="da"></param> | ||
2037 | /// <param name="conn"></param> | ||
2038 | private void SetupItemsCommands(MySqlDataAdapter da, MySqlConnection conn) | ||
2039 | { | ||
2040 | da.InsertCommand = createInsertCommand("primitems", m_itemsTable); | ||
2041 | da.InsertCommand.Connection = conn; | ||
2042 | |||
2043 | da.UpdateCommand = createUpdateCommand("primitems", "itemID = ?itemID", m_itemsTable); | ||
2044 | da.UpdateCommand.Connection = conn; | ||
2045 | |||
2046 | MySqlCommand delete = new MySqlCommand("delete from primitems where itemID = ?itemID"); | ||
2047 | delete.Parameters.Add(createMySqlParameter("itemID", typeof (String))); | ||
2048 | delete.Connection = conn; | ||
2049 | da.DeleteCommand = delete; | ||
2050 | } | ||
2051 | |||
2052 | private void SetupRegionSettingsCommands(MySqlDataAdapter da, MySqlConnection conn) | ||
2053 | { | ||
2054 | da.InsertCommand = createInsertCommand("regionsettings", m_regionSettingsTable); | ||
2055 | da.InsertCommand.Connection = conn; | ||
2056 | |||
2057 | da.UpdateCommand = createUpdateCommand("regionsettings", "regionUUID = ?regionUUID", m_regionSettingsTable); | ||
2058 | da.UpdateCommand.Connection = conn; | ||
2059 | |||
2060 | MySqlCommand delete = new MySqlCommand("delete from regionsettings where regionUUID = ?regionUUID"); | ||
2061 | delete.Parameters.Add(createMySqlParameter("regionUUID", typeof(String))); | ||
2062 | delete.Connection = conn; | ||
2063 | da.DeleteCommand = delete; | ||
2064 | } | ||
2065 | |||
2066 | /// <summary> | ||
2067 | /// | ||
2068 | /// </summary> | ||
2069 | /// <param name="da"></param> | ||
2070 | /// <param name="conn"></param> | ||
2071 | private void SetupTerrainCommands(MySqlDataAdapter da, MySqlConnection conn) | ||
2072 | { | ||
2073 | da.InsertCommand = createInsertCommand("terrain", m_dataSet.Tables["terrain"]); | ||
2074 | da.InsertCommand.Connection = conn; | ||
2075 | } | ||
2076 | |||
2077 | /// <summary> | ||
2078 | /// | ||
2079 | /// </summary> | ||
2080 | /// <param name="da"></param> | ||
2081 | /// <param name="conn"></param> | ||
2082 | private void setupLandCommands(MySqlDataAdapter da, MySqlConnection conn) | ||
2083 | { | ||
2084 | da.InsertCommand = createInsertCommand("land", m_dataSet.Tables["land"]); | ||
2085 | da.InsertCommand.Connection = conn; | ||
2086 | |||
2087 | da.UpdateCommand = createUpdateCommand("land", "UUID=?UUID", m_dataSet.Tables["land"]); | ||
2088 | da.UpdateCommand.Connection = conn; | ||
2089 | } | ||
2090 | |||
2091 | /// <summary> | ||
2092 | /// | ||
2093 | /// </summary> | ||
2094 | /// <param name="da"></param> | ||
2095 | /// <param name="conn"></param> | ||
2096 | private void setupLandAccessCommands(MySqlDataAdapter da, MySqlConnection conn) | ||
2097 | { | ||
2098 | da.InsertCommand = createInsertCommand("landaccesslist", m_dataSet.Tables["landaccesslist"]); | ||
2099 | da.InsertCommand.Connection = conn; | ||
2100 | } | ||
2101 | |||
2102 | /// <summary> | ||
2103 | /// | ||
2104 | /// </summary> | ||
2105 | /// <param name="da"></param> | ||
2106 | /// <param name="conn"></param> | ||
2107 | private void SetupShapeCommands(MySqlDataAdapter da, MySqlConnection conn) | ||
2108 | { | ||
2109 | da.InsertCommand = createInsertCommand("primshapes", m_dataSet.Tables["primshapes"]); | ||
2110 | da.InsertCommand.Connection = conn; | ||
2111 | |||
2112 | da.UpdateCommand = createUpdateCommand("primshapes", "UUID=?UUID", m_dataSet.Tables["primshapes"]); | ||
2113 | da.UpdateCommand.Connection = conn; | ||
2114 | |||
2115 | MySqlCommand delete = new MySqlCommand("delete from primshapes where UUID = ?UUID"); | ||
2116 | delete.Parameters.Add(createMySqlParameter("UUID", typeof (String))); | ||
2117 | delete.Connection = conn; | ||
2118 | da.DeleteCommand = delete; | ||
2119 | } | ||
2120 | |||
2121 | /*********************************************************************** | ||
2122 | * | ||
2123 | * Type conversion functions | ||
2124 | * | ||
2125 | **********************************************************************/ | ||
2126 | |||
2127 | /// <summary> | ||
2128 | /// Type conversion functions | ||
2129 | /// </summary> | ||
2130 | /// <param name="type"></param> | ||
2131 | /// <returns></returns> | ||
2132 | private static DbType dbtypeFromType(Type type) | ||
2133 | { | ||
2134 | if (type == typeof (String)) | ||
2135 | { | ||
2136 | return DbType.String; | ||
2137 | } | ||
2138 | else if (type == typeof (Int32)) | ||
2139 | { | ||
2140 | return DbType.Int32; | ||
2141 | } | ||
2142 | else if (type == typeof (Double)) | ||
2143 | { | ||
2144 | return DbType.Double; | ||
2145 | } | ||
2146 | else if (type == typeof (Byte)) | ||
2147 | { | ||
2148 | return DbType.Byte; | ||
2149 | } | ||
2150 | else if (type == typeof (Double)) | ||
2151 | { | ||
2152 | return DbType.Double; | ||
2153 | } | ||
2154 | else if (type == typeof (Byte[])) | ||
2155 | { | ||
2156 | return DbType.Binary; | ||
2157 | } | ||
2158 | else | ||
2159 | { | ||
2160 | return DbType.String; | ||
2161 | } | 1430 | } |
2162 | } | 1431 | } |
2163 | |||
2164 | } | 1432 | } |
2165 | } | 1433 | } |