aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs')
-rw-r--r--OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs359
1 files changed, 359 insertions, 0 deletions
diff --git a/OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs b/OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs
new file mode 100644
index 0000000..506056d
--- /dev/null
+++ b/OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs
@@ -0,0 +1,359 @@
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.Collections.Generic;
30using System.Data;
31using System.Reflection;
32using log4net;
33using System.Data.SqlClient;
34using OpenMetaverse;
35using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces;
37using System.Text;
38
39namespace OpenSim.Data.MSSQL
40{
41 public class MSSQLGenericTableHandler<T> where T : class, new()
42 {
43 private static readonly ILog m_log =
44 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 protected string m_ConnectionString;
47 protected MSSQLManager m_database; //used for parameter type translation
48 protected Dictionary<string, FieldInfo> m_Fields =
49 new Dictionary<string, FieldInfo>();
50
51 protected List<string> m_ColumnNames = null;
52 protected string m_Realm;
53 protected FieldInfo m_DataField = null;
54
55 public MSSQLGenericTableHandler(string connectionString,
56 string realm, string storeName)
57 {
58 m_Realm = realm;
59
60 if (storeName != String.Empty)
61 {
62 Assembly assem = GetType().Assembly;
63 m_ConnectionString = connectionString;
64 using (SqlConnection conn = new SqlConnection(m_ConnectionString))
65 {
66 conn.Open();
67 Migration m = new Migration(conn, assem, storeName);
68 m.Update();
69 }
70
71 }
72 m_database = new MSSQLManager(m_ConnectionString);
73
74 Type t = typeof(T);
75 FieldInfo[] fields = t.GetFields(BindingFlags.Public |
76 BindingFlags.Instance |
77 BindingFlags.DeclaredOnly);
78
79 if (fields.Length == 0)
80 return;
81
82 foreach (FieldInfo f in fields)
83 {
84 if (f.Name != "Data")
85 m_Fields[f.Name] = f;
86 else
87 m_DataField = f;
88 }
89
90 }
91
92 private void CheckColumnNames(SqlDataReader reader)
93 {
94 if (m_ColumnNames != null)
95 return;
96
97 m_ColumnNames = new List<string>();
98
99 DataTable schemaTable = reader.GetSchemaTable();
100 foreach (DataRow row in schemaTable.Rows)
101 {
102 if (row["ColumnName"] != null &&
103 (!m_Fields.ContainsKey(row["ColumnName"].ToString())))
104 m_ColumnNames.Add(row["ColumnName"].ToString());
105
106 }
107 }
108
109 private List<string> GetConstraints()
110 {
111 List<string> constraints = new List<string>();
112 string query = string.Format(@"SELECT
113 COL_NAME(ic.object_id,ic.column_id) AS column_name
114 FROM sys.indexes AS i
115 INNER JOIN sys.index_columns AS ic
116 ON i.object_id = ic.object_id AND i.index_id = ic.index_id
117 WHERE i.is_primary_key = 1
118 AND i.object_id = OBJECT_ID('{0}');", m_Realm);
119 using (SqlConnection conn = new SqlConnection(m_ConnectionString))
120 using (SqlCommand cmd = new SqlCommand(query, conn))
121 {
122 conn.Open();
123 using (SqlDataReader rdr = cmd.ExecuteReader())
124 {
125 while (rdr.Read())
126 {
127 // query produces 0 to many rows of single column, so always add the first item in each row
128 constraints.Add((string)rdr[0]);
129 }
130 }
131 return constraints;
132 }
133 }
134
135 public virtual T[] Get(string field, string key)
136 {
137 return Get(new string[] { field }, new string[] { key });
138 }
139
140 public virtual T[] Get(string[] fields, string[] keys)
141 {
142 if (fields.Length != keys.Length)
143 return new T[0];
144
145 List<string> terms = new List<string>();
146
147 using (SqlConnection conn = new SqlConnection(m_ConnectionString))
148 using (SqlCommand cmd = new SqlCommand())
149 {
150
151 for (int i = 0; i < fields.Length; i++)
152 {
153 cmd.Parameters.Add(m_database.CreateParameter(fields[i], keys[i]));
154 terms.Add("[" + fields[i] + "] = @" + fields[i]);
155 }
156
157 string where = String.Join(" AND ", terms.ToArray());
158
159 string query = String.Format("SELECT * FROM {0} WHERE {1}",
160 m_Realm, where);
161
162 cmd.Connection = conn;
163 cmd.CommandText = query;
164 conn.Open();
165 return DoQuery(cmd);
166 }
167 }
168
169 protected T[] DoQuery(SqlCommand cmd)
170 {
171 using (SqlDataReader reader = cmd.ExecuteReader())
172 {
173 if (reader == null)
174 return new T[0];
175
176 CheckColumnNames(reader);
177
178 List<T> result = new List<T>();
179
180 while (reader.Read())
181 {
182 T row = new T();
183
184 foreach (string name in m_Fields.Keys)
185 {
186 if (m_Fields[name].GetValue(row) is bool)
187 {
188 int v = Convert.ToInt32(reader[name]);
189 m_Fields[name].SetValue(row, v != 0 ? true : false);
190 }
191 else if (m_Fields[name].GetValue(row) is UUID)
192 {
193 UUID uuid = UUID.Zero;
194
195 UUID.TryParse(reader[name].ToString(), out uuid);
196 m_Fields[name].SetValue(row, uuid);
197 }
198 else if (m_Fields[name].GetValue(row) is int)
199 {
200 int v = Convert.ToInt32(reader[name]);
201 m_Fields[name].SetValue(row, v);
202 }
203 else
204 {
205 m_Fields[name].SetValue(row, reader[name]);
206 }
207 }
208
209 if (m_DataField != null)
210 {
211 Dictionary<string, string> data =
212 new Dictionary<string, string>();
213
214 foreach (string col in m_ColumnNames)
215 {
216 data[col] = reader[col].ToString();
217 if (data[col] == null)
218 data[col] = String.Empty;
219 }
220
221 m_DataField.SetValue(row, data);
222 }
223
224 result.Add(row);
225 }
226 return result.ToArray();
227 }
228 }
229
230 public virtual T[] Get(string where)
231 {
232 using (SqlConnection conn = new SqlConnection(m_ConnectionString))
233 using (SqlCommand cmd = new SqlCommand())
234 {
235
236 string query = String.Format("SELECT * FROM {0} WHERE {1}",
237 m_Realm, where);
238 cmd.Connection = conn;
239 cmd.CommandText = query;
240
241 //m_log.WarnFormat("[MSSQLGenericTable]: SELECT {0} WHERE {1}", m_Realm, where);
242
243 conn.Open();
244 return DoQuery(cmd);
245 }
246 }
247
248 public virtual bool Store(T row)
249 {
250 List<string> constraintFields = GetConstraints();
251 List<KeyValuePair<string, string>> constraints = new List<KeyValuePair<string, string>>();
252
253 using (SqlConnection conn = new SqlConnection(m_ConnectionString))
254 using (SqlCommand cmd = new SqlCommand())
255 {
256
257 StringBuilder query = new StringBuilder();
258 List<String> names = new List<String>();
259 List<String> values = new List<String>();
260
261 foreach (FieldInfo fi in m_Fields.Values)
262 {
263 names.Add(fi.Name);
264 values.Add("@" + fi.Name);
265 if (constraintFields.Count > 0 && constraintFields.Contains(fi.Name))
266 {
267 constraints.Add(new KeyValuePair<string, string>(fi.Name, fi.GetValue(row).ToString()));
268 }
269 cmd.Parameters.Add(m_database.CreateParameter(fi.Name, fi.GetValue(row).ToString()));
270 }
271
272 if (m_DataField != null)
273 {
274 Dictionary<string, string> data =
275 (Dictionary<string, string>)m_DataField.GetValue(row);
276
277 foreach (KeyValuePair<string, string> kvp in data)
278 {
279 if (constraintFields.Count > 0 && constraintFields.Contains(kvp.Key))
280 {
281 constraints.Add(new KeyValuePair<string, string>(kvp.Key, kvp.Key));
282 }
283 names.Add(kvp.Key);
284 values.Add("@" + kvp.Key);
285 cmd.Parameters.Add(m_database.CreateParameter("@" + kvp.Key, kvp.Value));
286 }
287
288 }
289
290 query.AppendFormat("UPDATE {0} SET ", m_Realm);
291 int i = 0;
292 for (i = 0; i < names.Count - 1; i++)
293 {
294 query.AppendFormat("[{0}] = {1}, ", names[i], values[i]);
295 }
296 query.AppendFormat("[{0}] = {1} ", names[i], values[i]);
297 if (constraints.Count > 0)
298 {
299 List<string> terms = new List<string>();
300 for (int j = 0; j < constraints.Count; j++)
301 {
302 terms.Add(" [" + constraints[j].Key + "] = @" + constraints[j].Key);
303 }
304 string where = String.Join(" AND ", terms.ToArray());
305 query.AppendFormat(" WHERE {0} ", where);
306
307 }
308 cmd.Connection = conn;
309 cmd.CommandText = query.ToString();
310
311 conn.Open();
312 if (cmd.ExecuteNonQuery() > 0)
313 {
314 //m_log.WarnFormat("[MSSQLGenericTable]: Updating {0}", m_Realm);
315 return true;
316 }
317 else
318 {
319 // assume record has not yet been inserted
320
321 query = new StringBuilder();
322 query.AppendFormat("INSERT INTO {0} ([", m_Realm);
323 query.Append(String.Join("],[", names.ToArray()));
324 query.Append("]) values (" + String.Join(",", values.ToArray()) + ")");
325 cmd.Connection = conn;
326 cmd.CommandText = query.ToString();
327 //m_log.WarnFormat("[MSSQLGenericTable]: Inserting into {0}", m_Realm);
328 if (conn.State != ConnectionState.Open)
329 conn.Open();
330 if (cmd.ExecuteNonQuery() > 0)
331 return true;
332 }
333
334 return false;
335 }
336 }
337
338 public virtual bool Delete(string field, string val)
339 {
340 using (SqlConnection conn = new SqlConnection(m_ConnectionString))
341 using (SqlCommand cmd = new SqlCommand())
342 {
343 string deleteCommand = String.Format("DELETE FROM {0} WHERE [{1}] = @{1}", m_Realm, field);
344 cmd.CommandText = deleteCommand;
345
346 cmd.Parameters.Add(m_database.CreateParameter(field, val));
347 cmd.Connection = conn;
348 conn.Open();
349
350 if (cmd.ExecuteNonQuery() > 0)
351 {
352 //m_log.Warn("[MSSQLGenericTable]: " + deleteCommand);
353 return true;
354 }
355 return false;
356 }
357 }
358 }
359}