OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
MySQLGenericTableHandler.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.Reflection;
32 using log4net;
33 using MySql.Data.MySqlClient;
34 using OpenMetaverse;
35 using OpenSim.Framework;
36 using OpenSim.Region.Framework.Interfaces;
37 
38 namespace OpenSim.Data.MySQL
39 {
40  public class MySQLGenericTableHandler<T> : MySqlFramework where T: class, new()
41  {
42 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43 
44  protected Dictionary<string, FieldInfo> m_Fields =
45  new Dictionary<string, FieldInfo>();
46 
47  protected List<string> m_ColumnNames = null;
48  protected string m_Realm;
49  protected FieldInfo m_DataField = null;
50 
51  protected virtual Assembly Assembly
52  {
53  get { return GetType().Assembly; }
54  }
55 
56  public MySQLGenericTableHandler(string connectionString,
57  string realm, string storeName) : base(connectionString)
58  {
59  m_Realm = realm;
60  m_connectionString = connectionString;
61 
62  if (storeName != String.Empty)
63  {
64  using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
65  {
66  dbcon.Open();
67  Migration m = new Migration(dbcon, Assembly, storeName);
68  m.Update();
69  }
70  }
71 
72  Type t = typeof(T);
73  FieldInfo[] fields = t.GetFields(BindingFlags.Public |
74  BindingFlags.Instance |
75  BindingFlags.DeclaredOnly);
76 
77  if (fields.Length == 0)
78  return;
79 
80  foreach (FieldInfo f in fields)
81  {
82  if (f.Name != "Data")
83  m_Fields[f.Name] = f;
84  else
85  m_DataField = f;
86  }
87  }
88 
89  private void CheckColumnNames(IDataReader reader)
90  {
91  if (m_ColumnNames != null)
92  return;
93 
94  List<string> columnNames = new List<string>();
95 
96  DataTable schemaTable = reader.GetSchemaTable();
97  foreach (DataRow row in schemaTable.Rows)
98  {
99  if (row["ColumnName"] != null &&
100  (!m_Fields.ContainsKey(row["ColumnName"].ToString())))
101  columnNames.Add(row["ColumnName"].ToString());
102  }
103 
104  m_ColumnNames = columnNames;
105  }
106 
107  public virtual T[] Get(string field, string key)
108  {
109  return Get(new string[] { field }, new string[] { key });
110  }
111 
112  public virtual T[] Get(string[] fields, string[] keys)
113  {
114  if (fields.Length != keys.Length)
115  return new T[0];
116 
117  List<string> terms = new List<string>();
118 
119  using (MySqlCommand cmd = new MySqlCommand())
120  {
121  for (int i = 0 ; i < fields.Length ; i++)
122  {
123  cmd.Parameters.AddWithValue(fields[i], keys[i]);
124  terms.Add("`" + fields[i] + "` = ?" + fields[i]);
125  }
126 
127  string where = String.Join(" and ", terms.ToArray());
128 
129  string query = String.Format("select * from {0} where {1}",
130  m_Realm, where);
131 
132  cmd.CommandText = query;
133 
134  return DoQuery(cmd);
135  }
136  }
137 
138  protected T[] DoQuery(MySqlCommand cmd)
139  {
140  List<T> result = new List<T>();
141 
142  using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
143  {
144  dbcon.Open();
145  cmd.Connection = dbcon;
146 
147  using (IDataReader reader = cmd.ExecuteReader())
148  {
149  if (reader == null)
150  return new T[0];
151 
152  CheckColumnNames(reader);
153 
154  while (reader.Read())
155  {
156  T row = new T();
157 
158  foreach (string name in m_Fields.Keys)
159  {
160  if (reader[name] is DBNull)
161  {
162  continue;
163  }
164  if (m_Fields[name].FieldType == typeof(bool))
165  {
166  int v = Convert.ToInt32(reader[name]);
167  m_Fields[name].SetValue(row, v != 0 ? true : false);
168  }
169  else if (m_Fields[name].FieldType == typeof(UUID))
170  {
171  m_Fields[name].SetValue(row, DBGuid.FromDB(reader[name]));
172  }
173  else if (m_Fields[name].FieldType == typeof(int))
174  {
175  int v = Convert.ToInt32(reader[name]);
176  m_Fields[name].SetValue(row, v);
177  }
178  else if (m_Fields[name].FieldType == typeof(uint))
179  {
180  uint v = Convert.ToUInt32(reader[name]);
181  m_Fields[name].SetValue(row, v);
182  }
183  else
184  {
185  m_Fields[name].SetValue(row, reader[name]);
186  }
187  }
188 
189  if (m_DataField != null)
190  {
191  Dictionary<string, string> data =
192  new Dictionary<string, string>();
193 
194  foreach (string col in m_ColumnNames)
195  {
196  data[col] = reader[col].ToString();
197  if (data[col] == null)
198  data[col] = String.Empty;
199  }
200 
201  m_DataField.SetValue(row, data);
202  }
203 
204  result.Add(row);
205  }
206  }
207  }
208 
209  return result.ToArray();
210  }
211 
212  public virtual T[] Get(string where)
213  {
214  using (MySqlCommand cmd = new MySqlCommand())
215  {
216  string query = String.Format("select * from {0} where {1}",
217  m_Realm, where);
218 
219  cmd.CommandText = query;
220 
221  return DoQuery(cmd);
222  }
223  }
224 
225  public virtual bool Store(T row)
226  {
227 // m_log.DebugFormat("[MYSQL GENERIC TABLE HANDLER]: Store(T row) invoked");
228 
229  using (MySqlCommand cmd = new MySqlCommand())
230  {
231  string query = "";
232  List<String> names = new List<String>();
233  List<String> values = new List<String>();
234 
235  foreach (FieldInfo fi in m_Fields.Values)
236  {
237  names.Add(fi.Name);
238  values.Add("?" + fi.Name);
239 
240  // Temporarily return more information about what field is unexpectedly null for
241  // http://opensimulator.org/mantis/view.php?id=5403. This might be due to a bug in the
242  // InventoryTransferModule or we may be required to substitute a DBNull here.
243  if (fi.GetValue(row) == null)
244  throw new NullReferenceException(
245  string.Format(
246  "[MYSQL GENERIC TABLE HANDLER]: Trying to store field {0} for {1} which is unexpectedly null",
247  fi.Name, row));
248 
249  cmd.Parameters.AddWithValue(fi.Name, fi.GetValue(row).ToString());
250  }
251 
252  if (m_DataField != null)
253  {
254  Dictionary<string, string> data =
255  (Dictionary<string, string>)m_DataField.GetValue(row);
256 
257  foreach (KeyValuePair<string, string> kvp in data)
258  {
259  names.Add(kvp.Key);
260  values.Add("?" + kvp.Key);
261  cmd.Parameters.AddWithValue("?" + kvp.Key, kvp.Value);
262  }
263  }
264 
265  query = String.Format("replace into {0} (`", m_Realm) + String.Join("`,`", names.ToArray()) + "`) values (" + String.Join(",", values.ToArray()) + ")";
266 
267  cmd.CommandText = query;
268 
269  if (ExecuteNonQuery(cmd) > 0)
270  return true;
271 
272  return false;
273  }
274  }
275 
276  public virtual bool Delete(string field, string key)
277  {
278  return Delete(new string[] { field }, new string[] { key });
279  }
280 
281  public virtual bool Delete(string[] fields, string[] keys)
282  {
283 // m_log.DebugFormat(
284 // "[MYSQL GENERIC TABLE HANDLER]: Delete(string[] fields, string[] keys) invoked with {0}:{1}",
285 // string.Join(",", fields), string.Join(",", keys));
286 
287  if (fields.Length != keys.Length)
288  return false;
289 
290  List<string> terms = new List<string>();
291 
292  using (MySqlCommand cmd = new MySqlCommand())
293  {
294  for (int i = 0 ; i < fields.Length ; i++)
295  {
296  cmd.Parameters.AddWithValue(fields[i], keys[i]);
297  terms.Add("`" + fields[i] + "` = ?" + fields[i]);
298  }
299 
300  string where = String.Join(" and ", terms.ToArray());
301 
302  string query = String.Format("delete from {0} where {1}", m_Realm, where);
303 
304  cmd.CommandText = query;
305 
306  return ExecuteNonQuery(cmd) > 0;
307  }
308  }
309 
310  public long GetCount(string field, string key)
311  {
312  return GetCount(new string[] { field }, new string[] { key });
313  }
314 
315  public long GetCount(string[] fields, string[] keys)
316  {
317  if (fields.Length != keys.Length)
318  return 0;
319 
320  List<string> terms = new List<string>();
321 
322  using (MySqlCommand cmd = new MySqlCommand())
323  {
324  for (int i = 0; i < fields.Length; i++)
325  {
326  cmd.Parameters.AddWithValue(fields[i], keys[i]);
327  terms.Add("`" + fields[i] + "` = ?" + fields[i]);
328  }
329 
330  string where = String.Join(" and ", terms.ToArray());
331 
332  string query = String.Format("select count(*) from {0} where {1}",
333  m_Realm, where);
334 
335  cmd.CommandText = query;
336 
337  Object result = DoQueryScalar(cmd);
338 
339  return Convert.ToInt64(result);
340  }
341  }
342 
343  public long GetCount(string where)
344  {
345  using (MySqlCommand cmd = new MySqlCommand())
346  {
347  string query = String.Format("select count(*) from {0} where {1}",
348  m_Realm, where);
349 
350  cmd.CommandText = query;
351 
352  object result = DoQueryScalar(cmd);
353 
354  return Convert.ToInt64(result);
355  }
356  }
357 
358  public object DoQueryScalar(MySqlCommand cmd)
359  {
360  using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
361  {
362  dbcon.Open();
363  cmd.Connection = dbcon;
364 
365  return cmd.ExecuteScalar();
366  }
367  }
368 
369  }
370 }
A database interface class to a user profile storage system
virtual bool Delete(string[] fields, string[] keys)
OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString key
Definition: ICM_Api.cs:31
MySQLGenericTableHandler(string connectionString, string realm, string storeName)
virtual T[] Get(string[] fields, string[] keys)