OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
PGSQLRegionData.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ''AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections.Generic;
30 using System.Data;
31 using System.Drawing;
32 using System.IO;
33 using System.Reflection;
34 using log4net;
35 using OpenMetaverse;
36 using OpenSim.Framework;
37 using OpenSim.Region.Framework.Interfaces;
38 using OpenSim.Region.Framework.Scenes;
40 using Npgsql;
41 
42 namespace OpenSim.Data.PGSQL
43 {
48  {
49  private string m_Realm;
50  private List<string> m_ColumnNames = null;
51  private string m_ConnectionString;
52  private PGSQLManager m_database;
53  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54 
55  protected Dictionary<string, string> m_FieldTypes = new Dictionary<string, string>();
56 
57  protected virtual Assembly Assembly
58  {
59  get { return GetType().Assembly; }
60  }
61 
62  public PGSQLRegionData(string connectionString, string realm)
63  {
64  m_Realm = realm;
65  m_ConnectionString = connectionString;
66  m_database = new PGSQLManager(connectionString);
67 
68  using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
69  {
70  conn.Open();
71  Migration m = new Migration(conn, GetType().Assembly, "GridStore");
72  m.Update();
73  }
74  LoadFieldTypes();
75  }
76 
77  private void LoadFieldTypes()
78  {
79  m_FieldTypes = new Dictionary<string, string>();
80 
81  string query = string.Format(@"select column_name,data_type
82  from INFORMATION_SCHEMA.COLUMNS
83  where table_name = lower('{0}');
84 
85  ", m_Realm);
86  using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
87  using (NpgsqlCommand cmd = new NpgsqlCommand(query, conn))
88  {
89  conn.Open();
90  using (NpgsqlDataReader rdr = cmd.ExecuteReader())
91  {
92  while (rdr.Read())
93  {
94  // query produces 0 to many rows of single column, so always add the first item in each row
95  m_FieldTypes.Add((string)rdr[0], (string)rdr[1]);
96  }
97  }
98  }
99  }
100 
101  public List<RegionData> Get(string regionName, UUID scopeID)
102  {
103  string sql = "select * from "+m_Realm+" where lower(\"regionName\") like lower(:regionName) ";
104  if (scopeID != UUID.Zero)
105  sql += " and \"ScopeID\" = :scopeID";
106  sql += " order by lower(\"regionName\")";
107 
108  using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
109  using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
110  {
111  cmd.Parameters.Add(m_database.CreateParameter("regionName", regionName));
112  if (scopeID != UUID.Zero)
113  cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID));
114  conn.Open();
115  return RunCommand(cmd);
116  }
117  }
118 
119  public RegionData Get(int posX, int posY, UUID scopeID)
120  {
121  // extend database search for maximum region size area
122  string sql = "select * from "+m_Realm+" where \"locX\" between :startX and :endX and \"locY\" between :startY and :endY";
123  if (scopeID != UUID.Zero)
124  sql += " and \"ScopeID\" = :scopeID";
125 
126  int startX = posX - (int)Constants.MaximumRegionSize;
127  int startY = posY - (int)Constants.MaximumRegionSize;
128  int endX = posX;
129  int endY = posY;
130 
131  List<RegionData> ret;
132  using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
133  using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
134  {
135  cmd.Parameters.Add(m_database.CreateParameter("startX", startX));
136  cmd.Parameters.Add(m_database.CreateParameter("startY", startY));
137  cmd.Parameters.Add(m_database.CreateParameter("endX", endX));
138  cmd.Parameters.Add(m_database.CreateParameter("endY", endY));
139  if (scopeID != UUID.Zero)
140  cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID));
141  conn.Open();
142  ret = RunCommand(cmd);
143  }
144 
145  if (ret.Count == 0)
146  return null;
147 
148  // Find the first that contains pos
149  RegionData rg = null;
150  foreach (RegionData r in ret)
151  {
152  if (posX >= r.posX && posX < r.posX + r.sizeX
153  && posY >= r.posY && posY < r.posY + r.sizeY)
154  {
155  rg = r;
156  break;
157  }
158  }
159 
160  return rg;
161  }
162 
163  public RegionData Get(UUID regionID, UUID scopeID)
164  {
165  string sql = "select * from "+m_Realm+" where uuid = :regionID";
166  if (scopeID != UUID.Zero)
167  sql += " and \"ScopeID\" = :scopeID";
168  using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
169  using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
170  {
171  cmd.Parameters.Add(m_database.CreateParameter("regionID", regionID));
172  if (scopeID != UUID.Zero)
173  cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID));
174  conn.Open();
175  List<RegionData> ret = RunCommand(cmd);
176  if (ret.Count == 0)
177  return null;
178 
179  return ret[0];
180  }
181  }
182 
183  public List<RegionData> Get(int startX, int startY, int endX, int endY, UUID scopeID)
184  {
185  // extend database search for maximum region size area
186  string sql = "select * from "+m_Realm+" where \"locX\" between :startX and :endX and \"locY\" between :startY and :endY";
187  if (scopeID != UUID.Zero)
188  sql += " and \"ScopeID\" = :scopeID";
189 
190  int qstartX = startX - (int)Constants.MaximumRegionSize;
191  int qstartY = startY - (int)Constants.MaximumRegionSize;
192 
193  List<RegionData> dbret;
194  using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
195  using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
196  {
197  cmd.Parameters.Add(m_database.CreateParameter("startX", qstartX));
198  cmd.Parameters.Add(m_database.CreateParameter("startY", qstartY));
199  cmd.Parameters.Add(m_database.CreateParameter("endX", endX));
200  cmd.Parameters.Add(m_database.CreateParameter("endY", endY));
201  if (scopeID != UUID.Zero)
202  cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID));
203  conn.Open();
204 
205  dbret = RunCommand(cmd);
206  }
207 
208  List<RegionData> ret = new List<RegionData>();
209 
210  if(dbret.Count == 0)
211  return ret;
212 
213  foreach (RegionData r in dbret)
214  {
215  if (r.posX + r.sizeX > startX && r.posX <= endX
216  && r.posY + r.sizeX > startY && r.posY <= endY)
217  ret.Add(r);
218  }
219  return ret;
220  }
221 
222  public List<RegionData> RunCommand(NpgsqlCommand cmd)
223  {
224  List<RegionData> retList = new List<RegionData>();
225 
226  NpgsqlDataReader result = cmd.ExecuteReader();
227 
228  while (result.Read())
229  {
230  RegionData ret = new RegionData();
231  ret.Data = new Dictionary<string, object>();
232 
233  UUID regionID;
234  UUID.TryParse(result["uuid"].ToString(), out regionID);
235  ret.RegionID = regionID;
236  UUID scope;
237  UUID.TryParse(result["ScopeID"].ToString(), out scope);
238  ret.ScopeID = scope;
239  ret.RegionName = result["regionName"].ToString();
240  ret.posX = Convert.ToInt32(result["locX"]);
241  ret.posY = Convert.ToInt32(result["locY"]);
242  ret.sizeX = Convert.ToInt32(result["sizeX"]);
243  ret.sizeY = Convert.ToInt32(result["sizeY"]);
244 
245  if (m_ColumnNames == null)
246  {
247  m_ColumnNames = new List<string>();
248 
249  DataTable schemaTable = result.GetSchemaTable();
250  foreach (DataRow row in schemaTable.Rows)
251  m_ColumnNames.Add(row["ColumnName"].ToString());
252  }
253 
254  foreach (string s in m_ColumnNames)
255  {
256  if (s == "uuid")
257  continue;
258  if (s == "ScopeID")
259  continue;
260  if (s == "regionName")
261  continue;
262  if (s == "locX")
263  continue;
264  if (s == "locY")
265  continue;
266 
267  ret.Data[s] = result[s].ToString();
268  }
269 
270  retList.Add(ret);
271  }
272  return retList;
273  }
274 
275  public bool Store(RegionData data)
276  {
277  if (data.Data.ContainsKey("uuid"))
278  data.Data.Remove("uuid");
279  if (data.Data.ContainsKey("ScopeID"))
280  data.Data.Remove("ScopeID");
281  if (data.Data.ContainsKey("regionName"))
282  data.Data.Remove("regionName");
283  if (data.Data.ContainsKey("posX"))
284  data.Data.Remove("posX");
285  if (data.Data.ContainsKey("posY"))
286  data.Data.Remove("posY");
287  if (data.Data.ContainsKey("sizeX"))
288  data.Data.Remove("sizeX");
289  if (data.Data.ContainsKey("sizeY"))
290  data.Data.Remove("sizeY");
291  if (data.Data.ContainsKey("locX"))
292  data.Data.Remove("locX");
293  if (data.Data.ContainsKey("locY"))
294  data.Data.Remove("locY");
295 
296  string[] fields = new List<string>(data.Data.Keys).ToArray();
297 
298  using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
299  using (NpgsqlCommand cmd = new NpgsqlCommand())
300  {
301 
302  string update = "update " + m_Realm + " set \"locX\"=:posX, \"locY\"=:posY, \"sizeX\"=:sizeX, \"sizeY\"=:sizeY ";
303 
304  foreach (string field in fields)
305  {
306 
307  update += ", ";
308  update += " \"" + field + "\" = :" + field;
309 
310  if (m_FieldTypes.ContainsKey(field))
311  cmd.Parameters.Add(m_database.CreateParameter(field, data.Data[field], m_FieldTypes[field]));
312  else
313  cmd.Parameters.Add(m_database.CreateParameter(field, data.Data[field]));
314  }
315 
316  update += " where uuid = :regionID";
317 
318  if (data.ScopeID != UUID.Zero)
319  update += " and \"ScopeID\" = :scopeID";
320 
321  cmd.CommandText = update;
322  cmd.Connection = conn;
323  cmd.Parameters.Add(m_database.CreateParameter("regionID", data.RegionID));
324  cmd.Parameters.Add(m_database.CreateParameter("regionName", data.RegionName));
325  cmd.Parameters.Add(m_database.CreateParameter("scopeID", data.ScopeID));
326  cmd.Parameters.Add(m_database.CreateParameter("posX", data.posX));
327  cmd.Parameters.Add(m_database.CreateParameter("posY", data.posY));
328  cmd.Parameters.Add(m_database.CreateParameter("sizeX", data.sizeX));
329  cmd.Parameters.Add(m_database.CreateParameter("sizeY", data.sizeY));
330  conn.Open();
331  try
332  {
333  if (cmd.ExecuteNonQuery() < 1)
334  {
335  string insert = "insert into " + m_Realm + " (uuid, \"ScopeID\", \"locX\", \"locY\", \"sizeX\", \"sizeY\", \"regionName\", \"" +
336  String.Join("\", \"", fields) +
337  "\") values (:regionID, :scopeID, :posX, :posY, :sizeX, :sizeY, :regionName, :" + String.Join(", :", fields) + ")";
338 
339  cmd.CommandText = insert;
340 
341  try
342  {
343  if (cmd.ExecuteNonQuery() < 1)
344  {
345  return false;
346  }
347  }
348  catch (Exception ex)
349  {
350  m_log.Warn("[PGSQL Grid]: Error inserting into Regions table: " + ex.Message + ", INSERT sql: " + insert);
351  }
352  }
353  }
354  catch (Exception ex)
355  {
356  m_log.Warn("[PGSQL Grid]: Error updating Regions table: " + ex.Message + ", UPDATE sql: " + update);
357  }
358  }
359 
360  return true;
361  }
362 
363  public bool SetDataItem(UUID regionID, string item, string value)
364  {
365  string sql = "update " + m_Realm +
366  " set \"" + item + "\" = :" + item + " where uuid = :UUID";
367 
368  using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
369  using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
370  {
371  cmd.Parameters.Add(m_database.CreateParameter("" + item, value));
372  cmd.Parameters.Add(m_database.CreateParameter("UUID", regionID));
373  conn.Open();
374  if (cmd.ExecuteNonQuery() > 0)
375  return true;
376  }
377  return false;
378  }
379 
380  public bool Delete(UUID regionID)
381  {
382  string sql = "delete from " + m_Realm +
383  " where uuid = :UUID";
384  using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
385  using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
386  {
387  cmd.Parameters.Add(m_database.CreateParameter("UUID", regionID));
388  conn.Open();
389  if (cmd.ExecuteNonQuery() > 0)
390  return true;
391  }
392  return false;
393  }
394 
395  public List<RegionData> GetDefaultRegions(UUID scopeID)
396  {
397  return Get((int)RegionFlags.DefaultRegion, scopeID);
398  }
399 
400  public List<RegionData> GetDefaultHypergridRegions(UUID scopeID)
401  {
402  return Get((int)RegionFlags.DefaultHGRegion, scopeID);
403  }
404 
405  public List<RegionData> GetFallbackRegions(UUID scopeID, int x, int y)
406  {
407  List<RegionData> regions = Get((int)RegionFlags.FallbackRegion, scopeID);
408  RegionDataDistanceCompare distanceComparer = new RegionDataDistanceCompare(x, y);
409  regions.Sort(distanceComparer);
410 
411  return regions;
412  }
413 
414  public List<RegionData> GetHyperlinks(UUID scopeID)
415  {
416  return Get((int)RegionFlags.Hyperlink, scopeID);
417  }
418 
419  private List<RegionData> Get(int regionFlags, UUID scopeID)
420  {
421  string sql = "SELECT * FROM " + m_Realm + " WHERE (\"flags\" & " + regionFlags.ToString() + ") <> 0";
422  if (scopeID != UUID.Zero)
423  sql += " AND \"ScopeID\" = :scopeID";
424 
425  using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
426  using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
427  {
428  cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID));
429  conn.Open();
430  return RunCommand(cmd);
431  }
432  }
433  }
434 }
List< RegionData > GetDefaultHypergridRegions(UUID scopeID)
int posX
The position in meters of this region.
Definition: IRegionData.cs:44
const uint MaximumRegionSize
Definition: Constants.cs:39
An interface for connecting to the authentication datastore
Definition: IRegionData.cs:70
List< RegionData > Get(int startX, int startY, int endX, int endY, UUID scopeID)
RegionData Get(UUID regionID, UUID scopeID)
RegionData Get(int posX, int posY, UUID scopeID)
List< RegionData > GetDefaultRegions(UUID scopeID)
int posY
The position in meters of this region.
Definition: IRegionData.cs:49
A management class for the MS SQL Storage Engine
Definition: PGSQLManager.cs:44
Dictionary< string, object > Data
Definition: IRegionData.cs:64
bool SetDataItem(UUID regionID, string item, string value)
RegionFlags
Region flags used internally by OpenSimulator to store installation specific information about region...
Definition: RegionFlags.cs:40
List< RegionData > GetFallbackRegions(UUID scopeID, int x, int y)
OpenSim.Framework.RegionFlags RegionFlags
List< RegionData > GetHyperlinks(UUID scopeID)
List< RegionData > RunCommand(NpgsqlCommand cmd)
PGSQLRegionData(string connectionString, string realm)
A PGSQL Interface for the Region Server.