PGSQLEstateData.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  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()
  159. {
  160. EstateSettings es = new EstateSettings();
  161. es.OnSave += StoreEstateSettings;
  162. DoCreate(es);
  163. LoadBanList(es);
  164. es.EstateManagers = LoadUUIDList(es.EstateID, "estate_managers");
  165. es.EstateAccess = LoadUUIDList(es.EstateID, "estate_users");
  166. es.EstateGroups = LoadUUIDList(es.EstateID, "estate_groups");
  167. return es;
  168. }
  169. private void DoCreate(EstateSettings es)
  170. {
  171. List<string> names = new List<string>(FieldList);
  172. names.Remove("EstateID");
  173. string sql = string.Format("insert into estate_settings (\"{0}\") values ( :{1} )", String.Join("\",\"", names.ToArray()), String.Join(", :", names.ToArray()));
  174. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  175. using (NpgsqlCommand insertCommand = new NpgsqlCommand(sql, conn))
  176. {
  177. insertCommand.CommandText = sql;
  178. foreach (string name in names)
  179. {
  180. insertCommand.Parameters.Add(_Database.CreateParameter("" + name, _FieldMap[name].GetValue(es)));
  181. }
  182. //NpgsqlParameter idParameter = new NpgsqlParameter("ID", SqlDbType.Int);
  183. //idParameter.Direction = ParameterDirection.Output;
  184. //insertCommand.Parameters.Add(idParameter);
  185. conn.Open();
  186. es.EstateID = 100;
  187. if (insertCommand.ExecuteNonQuery() > 0)
  188. {
  189. insertCommand.CommandText = "Select cast(lastval() as int) as ID ;";
  190. using (NpgsqlDataReader result = insertCommand.ExecuteReader())
  191. {
  192. if (result.Read())
  193. {
  194. es.EstateID = (uint)result.GetInt32(0);
  195. }
  196. }
  197. }
  198. }
  199. //TODO check if this is needed??
  200. es.Save();
  201. }
  202. /// <summary>
  203. /// Stores the estate settings.
  204. /// </summary>
  205. /// <param name="es">estate settings</param>
  206. public void StoreEstateSettings(EstateSettings es)
  207. {
  208. List<string> names = new List<string>(FieldList);
  209. names.Remove("EstateID");
  210. string sql = string.Format("UPDATE estate_settings SET ");
  211. foreach (string name in names)
  212. {
  213. sql += "\"" + name + "\" = :" + name + ", ";
  214. }
  215. sql = sql.Remove(sql.LastIndexOf(","));
  216. sql += " WHERE \"EstateID\" = :EstateID";
  217. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  218. using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
  219. {
  220. foreach (string name in names)
  221. {
  222. cmd.Parameters.Add(_Database.CreateParameter("" + name, _FieldMap[name].GetValue(es)));
  223. }
  224. cmd.Parameters.Add(_Database.CreateParameter("EstateID", es.EstateID));
  225. conn.Open();
  226. cmd.ExecuteNonQuery();
  227. }
  228. SaveBanList(es);
  229. SaveUUIDList(es.EstateID, "estate_managers", es.EstateManagers);
  230. SaveUUIDList(es.EstateID, "estate_users", es.EstateAccess);
  231. SaveUUIDList(es.EstateID, "estate_groups", es.EstateGroups);
  232. }
  233. #endregion
  234. #region Private methods
  235. private string[] FieldList
  236. {
  237. get { return new List<string>(_FieldMap.Keys).ToArray(); }
  238. }
  239. private void LoadBanList(EstateSettings es)
  240. {
  241. es.ClearBans();
  242. string sql = "select * from estateban where \"EstateID\" = :EstateID";
  243. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  244. using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
  245. {
  246. NpgsqlParameter idParameter = new NpgsqlParameter("EstateID", DbType.Int32);
  247. idParameter.Value = es.EstateID;
  248. cmd.Parameters.Add(idParameter);
  249. conn.Open();
  250. using (NpgsqlDataReader reader = cmd.ExecuteReader())
  251. {
  252. while (reader.Read())
  253. {
  254. EstateBan eb = new EstateBan();
  255. eb.BannedUserID = new UUID((Guid)reader["bannedUUID"]); //uuid;
  256. eb.BanningUserID = new UUID((Guid)reader["banningUUID"]); //uuid;
  257. eb.BanTime = Convert.ToInt32(reader["banTime"]);
  258. eb.BannedHostAddress = "0.0.0.0";
  259. eb.BannedHostIPMask = "0.0.0.0";
  260. es.AddBan(eb);
  261. }
  262. }
  263. }
  264. }
  265. private UUID[] LoadUUIDList(uint estateID, string table)
  266. {
  267. List<UUID> uuids = new List<UUID>();
  268. string sql = string.Format("select uuid from {0} where \"EstateID\" = :EstateID", table);
  269. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  270. using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
  271. {
  272. cmd.Parameters.Add(_Database.CreateParameter("EstateID", estateID));
  273. conn.Open();
  274. using (NpgsqlDataReader reader = cmd.ExecuteReader())
  275. {
  276. while (reader.Read())
  277. {
  278. uuids.Add(new UUID((Guid)reader["uuid"])); //uuid);
  279. }
  280. }
  281. }
  282. return uuids.ToArray();
  283. }
  284. private void SaveBanList(EstateSettings es)
  285. {
  286. //Delete first
  287. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  288. {
  289. conn.Open();
  290. using (NpgsqlCommand cmd = conn.CreateCommand())
  291. {
  292. cmd.CommandText = "delete from estateban where \"EstateID\" = :EstateID";
  293. cmd.Parameters.AddWithValue("EstateID", (int)es.EstateID);
  294. cmd.ExecuteNonQuery();
  295. //Insert after
  296. cmd.CommandText = "insert into estateban (\"EstateID\", \"bannedUUID\",\"bannedIp\", \"bannedIpHostMask\", \"bannedNameMask\", \"banningUUID\",\"banTime\" ) values ( :EstateID, :bannedUUID, '','','', :banningUUID, :banTime )";
  297. cmd.Parameters.AddWithValue("bannedUUID", Guid.Empty);
  298. foreach (EstateBan b in es.EstateBans)
  299. {
  300. cmd.Parameters["EstateID"].Value = b.EstateID;
  301. cmd.Parameters["bannedUUID"].Value = b.BannedUserID.Guid;
  302. cmd.Parameters["banningUUID"].Value = b.BanningUserID.Guid;
  303. cmd.Parameters["banTime"].Value = b.BanTime;
  304. cmd.ExecuteNonQuery();
  305. }
  306. }
  307. }
  308. }
  309. private void SaveUUIDList(uint estateID, string table, UUID[] data)
  310. {
  311. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  312. {
  313. conn.Open();
  314. using (NpgsqlCommand cmd = conn.CreateCommand())
  315. {
  316. cmd.Parameters.AddWithValue("EstateID", (int)estateID);
  317. cmd.CommandText = string.Format("delete from {0} where \"EstateID\" = :EstateID", table);
  318. cmd.ExecuteNonQuery();
  319. cmd.CommandText = string.Format("insert into {0} (\"EstateID\", uuid) values ( :EstateID, :uuid )", table);
  320. cmd.Parameters.AddWithValue("uuid", Guid.Empty);
  321. foreach (UUID uuid in data)
  322. {
  323. cmd.Parameters["uuid"].Value = uuid.Guid; //.ToString(); //TODO check if this works
  324. cmd.ExecuteNonQuery();
  325. }
  326. }
  327. }
  328. }
  329. public EstateSettings LoadEstateSettings(int estateID)
  330. {
  331. EstateSettings es = new EstateSettings();
  332. string sql = "select estate_settings.\"" + String.Join("\",estate_settings.\"", FieldList) + "\" from estate_settings where \"EstateID\" = :EstateID";
  333. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  334. {
  335. conn.Open();
  336. using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
  337. {
  338. cmd.Parameters.AddWithValue("EstateID", (int)estateID);
  339. using (NpgsqlDataReader reader = cmd.ExecuteReader())
  340. {
  341. if (reader.Read())
  342. {
  343. foreach (string name in FieldList)
  344. {
  345. FieldInfo f = _FieldMap[name];
  346. object v = reader[name];
  347. if (f.FieldType == typeof(bool))
  348. {
  349. f.SetValue(es, Convert.ToInt32(v) != 0);
  350. }
  351. else if (f.FieldType == typeof(UUID))
  352. {
  353. f.SetValue(es, new UUID((Guid)v)); // uuid);
  354. }
  355. else if (f.FieldType == typeof(string))
  356. {
  357. f.SetValue(es, v.ToString());
  358. }
  359. else if (f.FieldType == typeof(UInt32))
  360. {
  361. f.SetValue(es, Convert.ToUInt32(v));
  362. }
  363. else if (f.FieldType == typeof(Single))
  364. {
  365. f.SetValue(es, Convert.ToSingle(v));
  366. }
  367. else
  368. f.SetValue(es, v);
  369. }
  370. }
  371. }
  372. }
  373. }
  374. LoadBanList(es);
  375. es.EstateManagers = LoadUUIDList(es.EstateID, "estate_managers");
  376. es.EstateAccess = LoadUUIDList(es.EstateID, "estate_users");
  377. es.EstateGroups = LoadUUIDList(es.EstateID, "estate_groups");
  378. //Set event
  379. es.OnSave += StoreEstateSettings;
  380. return es;
  381. }
  382. public List<EstateSettings> LoadEstateSettingsAll()
  383. {
  384. List<EstateSettings> allEstateSettings = new List<EstateSettings>();
  385. List<int> allEstateIds = GetEstatesAll();
  386. foreach (int estateId in allEstateIds)
  387. allEstateSettings.Add(LoadEstateSettings(estateId));
  388. return allEstateSettings;
  389. }
  390. public List<int> GetEstates(string search)
  391. {
  392. List<int> result = new List<int>();
  393. string sql = "select \"EstateID\" from estate_settings where lower(\"EstateName\") = lower(:EstateName)";
  394. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  395. {
  396. conn.Open();
  397. using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
  398. {
  399. cmd.Parameters.AddWithValue("EstateName", search);
  400. using (IDataReader reader = cmd.ExecuteReader())
  401. {
  402. while (reader.Read())
  403. {
  404. result.Add(Convert.ToInt32(reader["EstateID"]));
  405. }
  406. reader.Close();
  407. }
  408. }
  409. }
  410. return result;
  411. }
  412. public List<int> GetEstatesAll()
  413. {
  414. List<int> result = new List<int>();
  415. string sql = "select \"EstateID\" from estate_settings";
  416. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  417. {
  418. conn.Open();
  419. using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
  420. {
  421. using (IDataReader reader = cmd.ExecuteReader())
  422. {
  423. while (reader.Read())
  424. {
  425. result.Add(Convert.ToInt32(reader["EstateID"]));
  426. }
  427. reader.Close();
  428. }
  429. }
  430. }
  431. return result;
  432. }
  433. public List<int> GetEstatesByOwner(UUID ownerID)
  434. {
  435. List<int> result = new List<int>();
  436. string sql = "select \"EstateID\" from estate_settings where \"EstateOwner\" = :EstateOwner";
  437. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  438. {
  439. conn.Open();
  440. using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
  441. {
  442. cmd.Parameters.AddWithValue("EstateOwner", ownerID);
  443. using (IDataReader reader = cmd.ExecuteReader())
  444. {
  445. while (reader.Read())
  446. {
  447. result.Add(Convert.ToInt32(reader["EstateID"]));
  448. }
  449. reader.Close();
  450. }
  451. }
  452. }
  453. return result;
  454. }
  455. public bool LinkRegion(UUID regionID, int estateID)
  456. {
  457. string deleteSQL = "delete from estate_map where \"RegionID\" = :RegionID";
  458. string insertSQL = "insert into estate_map values (:RegionID, :EstateID)";
  459. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  460. {
  461. conn.Open();
  462. NpgsqlTransaction transaction = conn.BeginTransaction();
  463. try
  464. {
  465. using (NpgsqlCommand cmd = new NpgsqlCommand(deleteSQL, conn))
  466. {
  467. cmd.Transaction = transaction;
  468. cmd.Parameters.AddWithValue("RegionID", regionID.Guid);
  469. cmd.ExecuteNonQuery();
  470. }
  471. using (NpgsqlCommand cmd = new NpgsqlCommand(insertSQL, conn))
  472. {
  473. cmd.Transaction = transaction;
  474. cmd.Parameters.AddWithValue("RegionID", regionID.Guid);
  475. cmd.Parameters.AddWithValue("EstateID", estateID);
  476. int ret = cmd.ExecuteNonQuery();
  477. if (ret != 0)
  478. transaction.Commit();
  479. else
  480. transaction.Rollback();
  481. return (ret != 0);
  482. }
  483. }
  484. catch (Exception ex)
  485. {
  486. m_log.Error("[REGION DB]: LinkRegion failed: " + ex.Message);
  487. transaction.Rollback();
  488. }
  489. }
  490. return false;
  491. }
  492. public List<UUID> GetRegions(int estateID)
  493. {
  494. List<UUID> result = new List<UUID>();
  495. string sql = "select \"RegionID\" from estate_map where \"EstateID\" = :EstateID";
  496. using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
  497. {
  498. conn.Open();
  499. using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
  500. {
  501. cmd.Parameters.AddWithValue("EstateID", estateID);
  502. using (IDataReader reader = cmd.ExecuteReader())
  503. {
  504. while (reader.Read())
  505. {
  506. result.Add(DBGuid.FromDB(reader["RegionID"]));
  507. }
  508. reader.Close();
  509. }
  510. }
  511. }
  512. return result;
  513. }
  514. public bool DeleteEstate(int estateID)
  515. {
  516. // TODO: Implementation!
  517. return false;
  518. }
  519. #endregion
  520. }
  521. }