aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Data/PGSQL/PGSQLAssetData.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Data/PGSQL/PGSQLAssetData.cs')
-rw-r--r--OpenSim/Data/PGSQL/PGSQLAssetData.cs316
1 files changed, 316 insertions, 0 deletions
diff --git a/OpenSim/Data/PGSQL/PGSQLAssetData.cs b/OpenSim/Data/PGSQL/PGSQLAssetData.cs
new file mode 100644
index 0000000..5d8b0a2
--- /dev/null
+++ b/OpenSim/Data/PGSQL/PGSQLAssetData.cs
@@ -0,0 +1,316 @@
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
28using System;
29using System.Data;
30using System.Reflection;
31using System.Collections.Generic;
32using OpenMetaverse;
33using log4net;
34using OpenSim.Framework;
35using Npgsql;
36using NpgsqlTypes;
37
38namespace OpenSim.Data.PGSQL
39{
40 /// <summary>
41 /// A PGSQL Interface for the Asset server
42 /// </summary>
43 public class PGSQLAssetData : AssetDataBase
44 {
45 private const string _migrationStore = "AssetStore";
46
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 private long m_ticksToEpoch;
49 /// <summary>
50 /// Database manager
51 /// </summary>
52 private PGSQLManager m_database;
53 private string m_connectionString;
54
55 protected virtual Assembly Assembly
56 {
57 get { return GetType().Assembly; }
58 }
59
60 #region IPlugin Members
61
62 override public void Dispose() { }
63
64 /// <summary>
65 /// <para>Initialises asset interface</para>
66 /// </summary>
67 // [Obsolete("Cannot be default-initialized!")]
68 override public void Initialise()
69 {
70 m_log.Info("[PGSQLAssetData]: " + Name + " cannot be default-initialized!");
71 throw new PluginNotInitialisedException(Name);
72 }
73
74 /// <summary>
75 /// Initialises asset interface
76 /// </summary>
77 /// <para>
78 /// a string instead of file, if someone writes the support
79 /// </para>
80 /// <param name="connectionString">connect string</param>
81 override public void Initialise(string connectionString)
82 {
83 m_ticksToEpoch = new System.DateTime(1970, 1, 1).Ticks;
84
85 m_database = new PGSQLManager(connectionString);
86 m_connectionString = connectionString;
87
88 //New migration to check for DB changes
89 m_database.CheckMigration(_migrationStore);
90 }
91
92 /// <summary>
93 /// Database provider version.
94 /// </summary>
95 override public string Version
96 {
97 get { return m_database.getVersion(); }
98 }
99
100 /// <summary>
101 /// The name of this DB provider.
102 /// </summary>
103 override public string Name
104 {
105 get { return "PGSQL Asset storage engine"; }
106 }
107
108 #endregion
109
110 #region IAssetDataPlugin Members
111
112 /// <summary>
113 /// Fetch Asset from m_database
114 /// </summary>
115 /// <param name="assetID">the asset UUID</param>
116 /// <returns></returns>
117 override public AssetBase GetAsset(UUID assetID)
118 {
119 string sql = "SELECT * FROM assets WHERE id = :id";
120 using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
121 using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
122 {
123 cmd.Parameters.Add(m_database.CreateParameter("id", assetID));
124 conn.Open();
125 using (NpgsqlDataReader reader = cmd.ExecuteReader())
126 {
127 if (reader.Read())
128 {
129 AssetBase asset = new AssetBase(
130 DBGuid.FromDB(reader["id"]),
131 (string)reader["name"],
132 Convert.ToSByte(reader["assetType"]),
133 reader["creatorid"].ToString()
134 );
135 // Region Main
136 asset.Description = (string)reader["description"];
137 asset.Local = Convert.ToBoolean(reader["local"]);
138 asset.Temporary = Convert.ToBoolean(reader["temporary"]);
139 asset.Flags = (AssetFlags)(Convert.ToInt32(reader["asset_flags"]));
140 asset.Data = (byte[])reader["data"];
141 return asset;
142 }
143 return null; // throw new Exception("No rows to return");
144 }
145 }
146 }
147
148 /// <summary>
149 /// Create asset in m_database
150 /// </summary>
151 /// <param name="asset">the asset</param>
152 override public void StoreAsset(AssetBase asset)
153 {
154
155 string sql =
156 @"UPDATE assets set name = :name, description = :description, " + "\"assetType\" " + @" = :assetType,
157 local = :local, temporary = :temporary, creatorid = :creatorid, data = :data
158 WHERE id=:id;
159
160 INSERT INTO assets
161 (id, name, description, " + "\"assetType\" " + @", local,
162 temporary, create_time, access_time, creatorid, asset_flags, data)
163 Select :id, :name, :description, :assetType, :local,
164 :temporary, :create_time, :access_time, :creatorid, :asset_flags, :data
165 Where not EXISTS(SELECT * FROM assets WHERE id=:id)
166 ";
167
168 string assetName = asset.Name;
169 if (asset.Name.Length > AssetBase.MAX_ASSET_NAME)
170 {
171 assetName = asset.Name.Substring(0, AssetBase.MAX_ASSET_NAME);
172 m_log.WarnFormat(
173 "[ASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add",
174 asset.Name, asset.ID, asset.Name.Length, assetName.Length);
175 }
176
177 string assetDescription = asset.Description;
178 if (asset.Description.Length > AssetBase.MAX_ASSET_DESC)
179 {
180 assetDescription = asset.Description.Substring(0, AssetBase.MAX_ASSET_DESC);
181 m_log.WarnFormat(
182 "[ASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add",
183 asset.Description, asset.ID, asset.Description.Length, assetDescription.Length);
184 }
185
186 using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
187 using (NpgsqlCommand command = new NpgsqlCommand(sql, conn))
188 {
189 int now = (int)((System.DateTime.Now.Ticks - m_ticksToEpoch) / 10000000);
190 command.Parameters.Add(m_database.CreateParameter("id", asset.FullID));
191 command.Parameters.Add(m_database.CreateParameter("name", assetName));
192 command.Parameters.Add(m_database.CreateParameter("description", assetDescription));
193 command.Parameters.Add(m_database.CreateParameter("assetType", asset.Type));
194 command.Parameters.Add(m_database.CreateParameter("local", asset.Local));
195 command.Parameters.Add(m_database.CreateParameter("temporary", asset.Temporary));
196 command.Parameters.Add(m_database.CreateParameter("access_time", now));
197 command.Parameters.Add(m_database.CreateParameter("create_time", now));
198 command.Parameters.Add(m_database.CreateParameter("asset_flags", (int)asset.Flags));
199 command.Parameters.Add(m_database.CreateParameter("creatorid", asset.Metadata.CreatorID));
200 command.Parameters.Add(m_database.CreateParameter("data", asset.Data));
201 conn.Open();
202 try
203 {
204 command.ExecuteNonQuery();
205 }
206 catch(Exception e)
207 {
208 m_log.Error("[ASSET DB]: Error storing item :" + e.Message + " sql "+sql);
209 }
210 }
211 }
212
213
214// Commented out since currently unused - this probably should be called in GetAsset()
215// private void UpdateAccessTime(AssetBase asset)
216// {
217// using (AutoClosingSqlCommand cmd = m_database.Query("UPDATE assets SET access_time = :access_time WHERE id=:id"))
218// {
219// int now = (int)((System.DateTime.Now.Ticks - m_ticksToEpoch) / 10000000);
220// cmd.Parameters.AddWithValue(":id", asset.FullID.ToString());
221// cmd.Parameters.AddWithValue(":access_time", now);
222// try
223// {
224// cmd.ExecuteNonQuery();
225// }
226// catch (Exception e)
227// {
228// m_log.Error(e.ToString());
229// }
230// }
231// }
232
233 /// <summary>
234 /// Check if the assets exist in the database.
235 /// </summary>
236 /// <param name="uuids">The assets' IDs</param>
237 /// <returns>For each asset: true if it exists, false otherwise</returns>
238 public override bool[] AssetsExist(UUID[] uuids)
239 {
240 if (uuids.Length == 0)
241 return new bool[0];
242
243 HashSet<UUID> exist = new HashSet<UUID>();
244
245 string ids = "'" + string.Join("','", uuids) + "'";
246 string sql = string.Format("SELECT id FROM assets WHERE id IN ({0})", ids);
247
248 using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
249 using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
250 {
251 conn.Open();
252 using (NpgsqlDataReader reader = cmd.ExecuteReader())
253 {
254 while (reader.Read())
255 {
256 UUID id = DBGuid.FromDB(reader["id"]);
257 exist.Add(id);
258 }
259 }
260 }
261
262 bool[] results = new bool[uuids.Length];
263 for (int i = 0; i < uuids.Length; i++)
264 results[i] = exist.Contains(uuids[i]);
265 return results;
266 }
267
268 /// <summary>
269 /// Returns a list of AssetMetadata objects. The list is a subset of
270 /// the entire data set offset by <paramref name="start" /> containing
271 /// <paramref name="count" /> elements.
272 /// </summary>
273 /// <param name="start">The number of results to discard from the total data set.</param>
274 /// <param name="count">The number of rows the returned list should contain.</param>
275 /// <returns>A list of AssetMetadata objects.</returns>
276 public override List<AssetMetadata> FetchAssetMetadataSet(int start, int count)
277 {
278 List<AssetMetadata> retList = new List<AssetMetadata>(count);
279 string sql = @" SELECT id, name, description, " + "\"assetType\"" + @", temporary, creatorid
280 FROM assets
281 order by id
282 limit :stop
283 offset :start;";
284
285 using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
286 using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
287 {
288 cmd.Parameters.Add(m_database.CreateParameter("start", start));
289 cmd.Parameters.Add(m_database.CreateParameter("stop", start + count - 1));
290 conn.Open();
291 using (NpgsqlDataReader reader = cmd.ExecuteReader())
292 {
293 while (reader.Read())
294 {
295 AssetMetadata metadata = new AssetMetadata();
296 metadata.FullID = DBGuid.FromDB(reader["id"]);
297 metadata.Name = (string)reader["name"];
298 metadata.Description = (string)reader["description"];
299 metadata.Type = Convert.ToSByte(reader["assetType"]);
300 metadata.Temporary = Convert.ToBoolean(reader["temporary"]);
301 metadata.CreatorID = (string)reader["creatorid"];
302 retList.Add(metadata);
303 }
304 }
305 }
306
307 return retList;
308 }
309
310 public override bool Delete(string id)
311 {
312 return false;
313 }
314 #endregion
315 }
316}