PGSQLEstateData.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  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. using System;
  28. using System.Collections.Generic;
  29. using System.Reflection;
  30. using log4net;
  31. using OpenMetaverse;
  32. using OpenSim.Framework;
  33. using OpenSim.Region.Framework.Interfaces;
  34. using System.Data;
  35. using Npgsql;
  36. using NpgsqlTypes;
  37. namespace OpenSim.Data.PGSQL
  38. {
  39. public class PGSQLEstateStore : IEstateDataStore
  40. {
  41. private const string _migrationStore = "EstateStore";
  42. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  43. private PGSQLManager _Database;
  44. private string m_connectionString;
  45. private FieldInfo[] _Fields;
  46. private Dictionary<string, FieldInfo> _FieldMap = new Dictionary<string, FieldInfo>();
  47. #region Public methods
  48. public PGSQLEstateStore()
  49. {
  50. }
  51. public PGSQLEstateStore(string connectionString)
  52. {
  53. Initialise(connectionString);
  54. }
  55. protected virtual Assembly Assembly
  56. {
  57. get { return GetType().Assembly; }
  58. }
  59. /// <summary>
  60. /// Initialises the estatedata class.
  61. /// </summary>
  62. /// <param name="connectionString">connectionString.</param>
  63. public void Initialise(string connectionString)
  64. {
  65. if (!string.IsNullOrEmpty(connectionString))
  66. {
  67. m_connectionString = connectionString;
  68. _Database = new PGSQLManager(connectionString);
  69. }
  70. //Migration settings
  71. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  72. {
  73. conn.Open();
  74. Migration m = new Migration(conn, GetType().Assembly, "EstateStore");
  75. m.Update();
  76. }
  77. //Interesting way to get parameters! Maybe implement that also with other types
  78. Type t = typeof(EstateSettings);
  79. _Fields = t.GetFields(BindingFlags.NonPublic |
  80. BindingFlags.Instance |
  81. BindingFlags.DeclaredOnly);
  82. foreach (FieldInfo f in _Fields)
  83. {
  84. if (f.Name.Substring(0, 2) == "m_")
  85. _FieldMap[f.Name.Substring(2)] = f;
  86. }
  87. }
  88. /// <summary>
  89. /// Loads the estate settings.
  90. /// </summary>
  91. /// <param name="regionID">region ID.</param>
  92. /// <returns></returns>
  93. public EstateSettings LoadEstateSettings(UUID regionID, bool create)
  94. {
  95. EstateSettings es = new EstateSettings();
  96. string sql = "select estate_settings.\"" + String.Join("\",estate_settings.\"", FieldList) +
  97. "\" from estate_map left join estate_settings on estate_map.\"EstateID\" = estate_settings.\"EstateID\" " +
  98. " where estate_settings.\"EstateID\" is not null and \"RegionID\" = :RegionID";
  99. bool insertEstate = false;
  100. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  101. using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
  102. {
  103. cmd.Parameters.Add(_Database.CreateParameter("RegionID", regionID));
  104. conn.Open();
  105. using (NpgsqlDataReader reader = cmd.ExecuteReader())
  106. {
  107. if (reader.Read())
  108. {
  109. foreach (string name in FieldList)
  110. {
  111. FieldInfo f = _FieldMap[name];
  112. object v = reader[name];
  113. if (f.FieldType == typeof(bool))
  114. {
  115. f.SetValue(es, v);
  116. }
  117. else if (f.FieldType == typeof(UUID))
  118. {
  119. UUID estUUID = UUID.Zero;
  120. UUID.TryParse(v.ToString(), out estUUID);
  121. f.SetValue(es, estUUID);
  122. }
  123. else if (f.FieldType == typeof(string))
  124. {
  125. f.SetValue(es, v.ToString());
  126. }
  127. else if (f.FieldType == typeof(UInt32))
  128. {
  129. f.SetValue(es, Convert.ToUInt32(v));
  130. }
  131. else if (f.FieldType == typeof(Single))
  132. {
  133. f.SetValue(es, Convert.ToSingle(v));
  134. }
  135. else
  136. f.SetValue(es, v);
  137. }
  138. }
  139. else
  140. {
  141. insertEstate = true;
  142. }
  143. }
  144. }
  145. if (insertEstate && create)
  146. {
  147. DoCreate(es);
  148. LinkRegion(regionID, (int)es.EstateID);
  149. }
  150. LoadBanList(es);
  151. es.EstateManagers = LoadUUIDList(es.EstateID, "estate_managers");
  152. es.EstateAccess = LoadUUIDList(es.EstateID, "estate_users");
  153. es.EstateGroups = LoadUUIDList(es.EstateID, "estate_groups");
  154. //Set event
  155. es.OnSave += StoreEstateSettings;
  156. return es;
  157. }
  158. public EstateSettings CreateNewEstate(int estateID)
  159. {
  160. EstateSettings es = new EstateSettings();
  161. es.OnSave += StoreEstateSettings;
  162. es.EstateID = Convert.ToUInt32(estateID);
  163. DoCreate(es);
  164. LoadBanList(es);
  165. es.EstateManagers = LoadUUIDList(es.EstateID, "estate_managers");
  166. es.EstateAccess = LoadUUIDList(es.EstateID, "estate_users");
  167. es.EstateGroups = LoadUUIDList(es.EstateID, "estate_groups");
  168. return es;
  169. }
  170. private void DoCreate(EstateSettings es)
  171. {
  172. List<string> names = new List<string>(FieldList);
  173. // Remove EstateID and use AutoIncrement
  174. if (es.EstateID < 100)
  175. names.Remove("EstateID");
  176. string sql = string.Format("insert into estate_settings (\"{0}\") values ( :{1} )", String.Join("\",\"", names.ToArray()), String.Join(", :", names.ToArray()));
  177. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  178. using (NpgsqlCommand insertCommand = new NpgsqlCommand(sql, conn))
  179. {
  180. insertCommand.CommandText = sql;
  181. foreach (string name in names)
  182. {
  183. insertCommand.Parameters.Add(_Database.CreateParameter("" + name, _FieldMap[name].GetValue(es)));
  184. }
  185. //NpgsqlParameter idParameter = new NpgsqlParameter("ID", SqlDbType.Int);
  186. //idParameter.Direction = ParameterDirection.Output;
  187. //insertCommand.Parameters.Add(idParameter);
  188. conn.Open();
  189. if (insertCommand.ExecuteNonQuery() > 0 && es.EstateID < 100)
  190. {
  191. // Only get Auto ID if we actually used it
  192. insertCommand.CommandText = "Select cast(lastval() as int) as ID ;";
  193. using (NpgsqlDataReader result = insertCommand.ExecuteReader())
  194. {
  195. if (result.Read())
  196. {
  197. es.EstateID = (uint)result.GetInt32(0);
  198. }
  199. }
  200. }
  201. }
  202. //TODO check if this is needed??
  203. es.Save();
  204. }
  205. /// <summary>
  206. /// Stores the estate settings.
  207. /// </summary>
  208. /// <param name="es">estate settings</param>
  209. public void StoreEstateSettings(EstateSettings es)
  210. {
  211. List<string> names = new List<string>(FieldList);
  212. names.Remove("EstateID");
  213. string sql = string.Format("UPDATE estate_settings SET ");
  214. foreach (string name in names)
  215. {
  216. sql += "\"" + name + "\" = :" + name + ", ";
  217. }
  218. sql = sql.Remove(sql.LastIndexOf(","));
  219. sql += " WHERE \"EstateID\" = :EstateID";
  220. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  221. using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
  222. {
  223. foreach (string name in names)
  224. {
  225. cmd.Parameters.Add(_Database.CreateParameter("" + name, _FieldMap[name].GetValue(es)));
  226. }
  227. cmd.Parameters.Add(_Database.CreateParameter("EstateID", es.EstateID));
  228. conn.Open();
  229. cmd.ExecuteNonQuery();
  230. }
  231. SaveBanList(es);
  232. SaveUUIDList(es.EstateID, "estate_managers", es.EstateManagers);
  233. SaveUUIDList(es.EstateID, "estate_users", es.EstateAccess);
  234. SaveUUIDList(es.EstateID, "estate_groups", es.EstateGroups);
  235. }
  236. #endregion
  237. #region Private methods
  238. private string[] FieldList
  239. {
  240. get { return new List<string>(_FieldMap.Keys).ToArray(); }
  241. }
  242. private void LoadBanList(EstateSettings es)
  243. {
  244. es.ClearBans();
  245. string sql = "select * from estateban where \"EstateID\" = :EstateID";
  246. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  247. using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
  248. {
  249. NpgsqlParameter idParameter = new NpgsqlParameter("EstateID", DbType.Int32);
  250. idParameter.Value = es.EstateID;
  251. cmd.Parameters.Add(idParameter);
  252. conn.Open();
  253. using (NpgsqlDataReader reader = cmd.ExecuteReader())
  254. {
  255. while (reader.Read())
  256. {
  257. EstateBan eb = new EstateBan();
  258. eb.BannedUserID = new UUID((Guid)reader["bannedUUID"]); //uuid;
  259. eb.BanningUserID = new UUID((Guid)reader["banningUUID"]); //uuid;
  260. eb.BanTime = Convert.ToInt32(reader["banTime"]);
  261. eb.BannedHostAddress = "0.0.0.0";
  262. eb.BannedHostIPMask = "0.0.0.0";
  263. es.AddBan(eb);
  264. }
  265. }
  266. }
  267. }
  268. private UUID[] LoadUUIDList(uint estateID, string table)
  269. {
  270. List<UUID> uuids = new List<UUID>();
  271. string sql = string.Format("select uuid from {0} where \"EstateID\" = :EstateID", table);
  272. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  273. using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
  274. {
  275. cmd.Parameters.Add(_Database.CreateParameter("EstateID", estateID));
  276. conn.Open();
  277. using (NpgsqlDataReader reader = cmd.ExecuteReader())
  278. {
  279. while (reader.Read())
  280. {
  281. uuids.Add(new UUID((Guid)reader["uuid"])); //uuid);
  282. }
  283. }
  284. }
  285. return uuids.ToArray();
  286. }
  287. private void SaveBanList(EstateSettings es)
  288. {
  289. //Delete first
  290. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  291. {
  292. conn.Open();
  293. using (NpgsqlCommand cmd = conn.CreateCommand())
  294. {
  295. cmd.CommandText = "delete from estateban where \"EstateID\" = :EstateID";
  296. cmd.Parameters.AddWithValue("EstateID", (int)es.EstateID);
  297. cmd.ExecuteNonQuery();
  298. //Insert after
  299. cmd.CommandText = "insert into estateban (\"EstateID\", \"bannedUUID\",\"bannedIp\", \"bannedIpHostMask\", \"bannedNameMask\", \"banningUUID\",\"banTime\" ) values ( :EstateID, :bannedUUID, '','','', :banningUUID, :banTime )";
  300. cmd.Parameters.AddWithValue("bannedUUID", Guid.Empty);
  301. foreach (EstateBan b in es.EstateBans)
  302. {
  303. cmd.Parameters["EstateID"].Value = b.EstateID;
  304. cmd.Parameters["bannedUUID"].Value = b.BannedUserID.Guid;
  305. cmd.Parameters["banningUUID"].Value = b.BanningUserID.Guid;
  306. cmd.Parameters["banTime"].Value = b.BanTime;
  307. cmd.ExecuteNonQuery();
  308. }
  309. }
  310. }
  311. }
  312. private void SaveUUIDList(uint estateID, string table, UUID[] data)
  313. {
  314. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  315. {
  316. conn.Open();
  317. using (NpgsqlCommand cmd = conn.CreateCommand())
  318. {
  319. cmd.Parameters.AddWithValue("EstateID", (int)estateID);
  320. cmd.CommandText = string.Format("delete from {0} where \"EstateID\" = :EstateID", table);
  321. cmd.ExecuteNonQuery();
  322. cmd.CommandText = string.Format("insert into {0} (\"EstateID\", uuid) values ( :EstateID, :uuid )", table);
  323. cmd.Parameters.AddWithValue("uuid", Guid.Empty);
  324. foreach (UUID uuid in data)
  325. {
  326. cmd.Parameters["uuid"].Value = uuid.Guid; //.ToString(); //TODO check if this works
  327. cmd.ExecuteNonQuery();
  328. }
  329. }
  330. }
  331. }
  332. public EstateSettings LoadEstateSettings(int estateID)
  333. {
  334. EstateSettings es = new EstateSettings();
  335. string sql = "select estate_settings.\"" + String.Join("\",estate_settings.\"", FieldList) + "\" from estate_settings where \"EstateID\" = :EstateID";
  336. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  337. {
  338. conn.Open();
  339. using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
  340. {
  341. cmd.Parameters.AddWithValue("EstateID", (int)estateID);
  342. using (NpgsqlDataReader reader = cmd.ExecuteReader())
  343. {
  344. if (reader.Read())
  345. {
  346. foreach (string name in FieldList)
  347. {
  348. FieldInfo f = _FieldMap[name];
  349. object v = reader[name];
  350. if (f.FieldType == typeof(bool))
  351. {
  352. f.SetValue(es, Convert.ToInt32(v) != 0);
  353. }
  354. else if (f.FieldType == typeof(UUID))
  355. {
  356. f.SetValue(es, new UUID((Guid)v)); // uuid);
  357. }
  358. else if (f.FieldType == typeof(string))
  359. {
  360. f.SetValue(es, v.ToString());
  361. }
  362. else if (f.FieldType == typeof(UInt32))
  363. {
  364. f.SetValue(es, Convert.ToUInt32(v));
  365. }
  366. else if (f.FieldType == typeof(Single))
  367. {
  368. f.SetValue(es, Convert.ToSingle(v));
  369. }
  370. else
  371. f.SetValue(es, v);
  372. }
  373. }
  374. }
  375. }
  376. }
  377. LoadBanList(es);
  378. es.EstateManagers = LoadUUIDList(es.EstateID, "estate_managers");
  379. es.EstateAccess = LoadUUIDList(es.EstateID, "estate_users");
  380. es.EstateGroups = LoadUUIDList(es.EstateID, "estate_groups");
  381. //Set event
  382. es.OnSave += StoreEstateSettings;
  383. return es;
  384. }
  385. public List<EstateSettings> LoadEstateSettingsAll()
  386. {
  387. List<EstateSettings> allEstateSettings = new List<EstateSettings>();
  388. List<int> allEstateIds = GetEstatesAll();
  389. foreach (int estateId in allEstateIds)
  390. allEstateSettings.Add(LoadEstateSettings(estateId));
  391. return allEstateSettings;
  392. }
  393. public List<int> GetEstates(string search)
  394. {
  395. List<int> result = new List<int>();
  396. string sql = "select \"EstateID\" from estate_settings where lower(\"EstateName\") = lower(:EstateName)";
  397. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  398. {
  399. conn.Open();
  400. using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
  401. {
  402. cmd.Parameters.AddWithValue("EstateName", search);
  403. using (IDataReader reader = cmd.ExecuteReader())
  404. {
  405. while (reader.Read())
  406. {
  407. result.Add(Convert.ToInt32(reader["EstateID"]));
  408. }
  409. reader.Close();
  410. }
  411. }
  412. }
  413. return result;
  414. }
  415. public List<int> GetEstatesAll()
  416. {
  417. List<int> result = new List<int>();
  418. string sql = "select \"EstateID\" from estate_settings";
  419. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  420. {
  421. conn.Open();
  422. using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
  423. {
  424. using (IDataReader reader = cmd.ExecuteReader())
  425. {
  426. while (reader.Read())
  427. {
  428. result.Add(Convert.ToInt32(reader["EstateID"]));
  429. }
  430. reader.Close();
  431. }
  432. }
  433. }
  434. return result;
  435. }
  436. public List<int> GetEstatesByOwner(UUID ownerID)
  437. {
  438. List<int> result = new List<int>();
  439. string sql = "select \"EstateID\" from estate_settings where \"EstateOwner\" = :EstateOwner";
  440. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  441. {
  442. conn.Open();
  443. using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
  444. {
  445. cmd.Parameters.AddWithValue("EstateOwner", ownerID);
  446. using (IDataReader reader = cmd.ExecuteReader())
  447. {
  448. while (reader.Read())
  449. {
  450. result.Add(Convert.ToInt32(reader["EstateID"]));
  451. }
  452. reader.Close();
  453. }
  454. }
  455. }
  456. return result;
  457. }
  458. public bool LinkRegion(UUID regionID, int estateID)
  459. {
  460. string deleteSQL = "delete from estate_map where \"RegionID\" = :RegionID";
  461. string insertSQL = "insert into estate_map values (:RegionID, :EstateID)";
  462. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  463. {
  464. conn.Open();
  465. NpgsqlTransaction transaction = conn.BeginTransaction();
  466. try
  467. {
  468. using (NpgsqlCommand cmd = new NpgsqlCommand(deleteSQL, conn))
  469. {
  470. cmd.Transaction = transaction;
  471. cmd.Parameters.AddWithValue("RegionID", regionID.Guid);
  472. cmd.ExecuteNonQuery();
  473. }
  474. using (NpgsqlCommand cmd = new NpgsqlCommand(insertSQL, conn))
  475. {
  476. cmd.Transaction = transaction;
  477. cmd.Parameters.AddWithValue("RegionID", regionID.Guid);
  478. cmd.Parameters.AddWithValue("EstateID", estateID);
  479. int ret = cmd.ExecuteNonQuery();
  480. if (ret != 0)
  481. transaction.Commit();
  482. else
  483. transaction.Rollback();
  484. return (ret != 0);
  485. }
  486. }
  487. catch (Exception ex)
  488. {
  489. m_log.Error("[REGION DB]: LinkRegion failed: " + ex.Message);
  490. transaction.Rollback();
  491. }
  492. }
  493. return false;
  494. }
  495. public List<UUID> GetRegions(int estateID)
  496. {
  497. List<UUID> result = new List<UUID>();
  498. string sql = "select \"RegionID\" from estate_map where \"EstateID\" = :EstateID";
  499. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  500. {
  501. conn.Open();
  502. using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
  503. {
  504. cmd.Parameters.AddWithValue("EstateID", estateID);
  505. using (IDataReader reader = cmd.ExecuteReader())
  506. {
  507. while (reader.Read())
  508. {
  509. result.Add(DBGuid.FromDB(reader["RegionID"]));
  510. }
  511. reader.Close();
  512. }
  513. }
  514. }
  515. return result;
  516. }
  517. public bool DeleteEstate(int estateID)
  518. {
  519. // TODO: Implementation!
  520. return false;
  521. }
  522. #endregion
  523. }
  524. }