aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Data
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Data')
-rw-r--r--OpenSim/Data/Base/BaseDataReader.cs139
-rw-r--r--OpenSim/Data/Base/BaseDatabaseConnector.cs142
-rw-r--r--OpenSim/Data/Base/BaseFieldMapper.cs168
-rw-r--r--OpenSim/Data/Base/BaseRowMapper.cs61
-rw-r--r--OpenSim/Data/Base/BaseSchema.cs69
-rw-r--r--OpenSim/Data/Base/BaseTableMapper.cs281
-rw-r--r--OpenSim/Data/Base/OpenSim.Framework.Data.Base.snkbin0 -> 596 bytes
-rw-r--r--OpenSim/Data/Base/Properties/AssemblyInfo.cs67
-rw-r--r--OpenSim/Data/DB4o/DB4oGridData.cs182
-rw-r--r--OpenSim/Data/DB4o/DB4oManager.cs170
-rw-r--r--OpenSim/Data/DB4o/DB4oUserData.cs270
-rw-r--r--OpenSim/Data/DB4o/Properties/AssemblyInfo.cs65
-rw-r--r--OpenSim/Data/MSSQL/MSSQLAssetData.cs221
-rw-r--r--OpenSim/Data/MSSQL/MSSQLDataStore.cs1622
-rw-r--r--OpenSim/Data/MSSQL/MSSQLGridData.cs366
-rw-r--r--OpenSim/Data/MSSQL/MSSQLInventoryData.cs728
-rw-r--r--OpenSim/Data/MSSQL/MSSQLLogData.cs120
-rw-r--r--OpenSim/Data/MSSQL/MSSQLManager.cs529
-rw-r--r--OpenSim/Data/MSSQL/MSSQLUserData.cs771
-rw-r--r--OpenSim/Data/MSSQL/Properties/AssemblyInfo.cs65
-rw-r--r--OpenSim/Data/MSSQL/Resources/AvatarAppearance.sql44
-rw-r--r--OpenSim/Data/MSSQL/Resources/CreateAssetsTable.sql19
-rw-r--r--OpenSim/Data/MSSQL/Resources/CreateFoldersTable.sql27
-rw-r--r--OpenSim/Data/MSSQL/Resources/CreateItemsTable.sql39
-rw-r--r--OpenSim/Data/MSSQL/Resources/CreateUserFriendsTable.sql14
-rw-r--r--OpenSim/Data/MSSQL/Resources/Mssql-agents.sql37
-rw-r--r--OpenSim/Data/MSSQL/Resources/Mssql-logs.sql20
-rw-r--r--OpenSim/Data/MSSQL/Resources/Mssql-regions.sql41
-rw-r--r--OpenSim/Data/MSSQL/Resources/Mssql-users.sql42
-rw-r--r--OpenSim/Data/MSSQLMapper/MSSQLDatabaseMapper.cs65
-rw-r--r--OpenSim/Data/MapperFactory/DataMapperFactory.cs27
-rw-r--r--OpenSim/Data/MySQL/MySQLAssetData.cs198
-rw-r--r--OpenSim/Data/MySQL/MySQLDataStore.cs1722
-rw-r--r--OpenSim/Data/MySQL/MySQLGridData.cs402
-rw-r--r--OpenSim/Data/MySQL/MySQLInventoryData.cs648
-rw-r--r--OpenSim/Data/MySQL/MySQLLogData.cs106
-rw-r--r--OpenSim/Data/MySQL/MySQLManager.cs909
-rw-r--r--OpenSim/Data/MySQL/MySQLUserData.cs643
-rw-r--r--OpenSim/Data/MySQL/Properties/AssemblyInfo.cs65
-rw-r--r--OpenSim/Data/MySQL/Resources/AvatarAppearance.sql42
-rw-r--r--OpenSim/Data/MySQL/Resources/CreateAgentsTable.sql24
-rw-r--r--OpenSim/Data/MySQL/Resources/CreateAssetsTable.sql11
-rw-r--r--OpenSim/Data/MySQL/Resources/CreateFoldersTable.sql11
-rw-r--r--OpenSim/Data/MySQL/Resources/CreateItemsTable.sql18
-rw-r--r--OpenSim/Data/MySQL/Resources/CreateLogsTable.sql10
-rw-r--r--OpenSim/Data/MySQL/Resources/CreateRegionsTable.sql32
-rw-r--r--OpenSim/Data/MySQL/Resources/CreateUserFriendsTable.sql11
-rw-r--r--OpenSim/Data/MySQL/Resources/CreateUsersTable.sql35
-rw-r--r--OpenSim/Data/MySQL/Resources/UpgradeFoldersTableToVersion2.sql4
-rw-r--r--OpenSim/Data/MySQL/Resources/UpgradeItemsTableToVersion2.sql9
-rw-r--r--OpenSim/Data/MySQL/Resources/UpgradeRegionsTableToVersion2.sql4
-rw-r--r--OpenSim/Data/MySQL/Resources/UpgradeRegionsTableToVersion3.sql18
-rw-r--r--OpenSim/Data/MySQL/Resources/UpgradeUsersTableToVersion2.sql3
-rw-r--r--OpenSim/Data/MySQLMapper/MySQLDataReader.cs15
-rw-r--r--OpenSim/Data/MySQLMapper/MySQLDatabaseMapper.cs59
-rw-r--r--OpenSim/Data/SQLite/Properties/AssemblyInfo.cs65
-rw-r--r--OpenSim/Data/SQLite/Resources/001_AssetStore.sql13
-rw-r--r--OpenSim/Data/SQLite/Resources/001_InventoryStore.sql26
-rw-r--r--OpenSim/Data/SQLite/Resources/001_RegionStore.sql122
-rw-r--r--OpenSim/Data/SQLite/Resources/001_UserStore.sql37
-rw-r--r--OpenSim/Data/SQLite/SQLiteAssetData.cs301
-rw-r--r--OpenSim/Data/SQLite/SQLiteGridData.cs234
-rw-r--r--OpenSim/Data/SQLite/SQLiteInventoryStore.cs664
-rw-r--r--OpenSim/Data/SQLite/SQLiteManager.cs282
-rw-r--r--OpenSim/Data/SQLite/SQLiteRegionData.cs1741
-rw-r--r--OpenSim/Data/SQLite/SQLiteUserData.cs821
-rw-r--r--OpenSim/Data/SQLite/SQLiteUtils.cs269
67 files changed, 15985 insertions, 0 deletions
diff --git a/OpenSim/Data/Base/BaseDataReader.cs b/OpenSim/Data/Base/BaseDataReader.cs
new file mode 100644
index 0000000..3baefcd
--- /dev/null
+++ b/OpenSim/Data/Base/BaseDataReader.cs
@@ -0,0 +1,139 @@
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 OpenSim 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.IO;
31
32namespace OpenSim.Framework.Data.Base
33{
34 public abstract class BaseDataReader
35 {
36 private readonly IDataReader m_source;
37
38 public BaseDataReader(IDataReader source)
39 {
40 m_source = source;
41 }
42
43 public object Get(string name)
44 {
45 return m_source[name];
46 }
47
48 public ushort GetUShort(string name)
49 {
50 return (ushort)m_source.GetInt32(m_source.GetOrdinal(name));
51 }
52
53 public byte GetByte(string name)
54 {
55 int ordinal = m_source.GetOrdinal(name);
56 byte value = (byte)m_source.GetInt16(ordinal);
57 return value;
58 }
59
60 public sbyte GetSByte(string name)
61 {
62 return (sbyte)m_source.GetInt16(m_source.GetOrdinal(name));
63 }
64
65 public float GetFloat(string name)
66 {
67 return m_source.GetFloat(m_source.GetOrdinal(name));
68 }
69
70 public byte[] GetBytes(string name)
71 {
72 int ordinal = m_source.GetOrdinal(name);
73
74 if (m_source.GetValue(ordinal) == DBNull.Value)
75 {
76 return null;
77 }
78
79 byte[] buffer = new byte[16384];
80
81 MemoryStream memStream = new MemoryStream();
82
83 long totalRead = 0;
84
85 int bytesRead;
86 do
87 {
88 bytesRead = (int)m_source.GetBytes(ordinal, totalRead, buffer, 0, buffer.Length);
89 totalRead += bytesRead;
90
91 memStream.Write(buffer, 0, bytesRead);
92 } while (bytesRead == buffer.Length);
93
94 return memStream.ToArray();
95 }
96
97 public string GetString(string name)
98 {
99 int ordinal = m_source.GetOrdinal(name);
100 object value = m_source.GetValue(ordinal);
101
102 if (value is DBNull)
103 {
104 return null;
105 }
106
107 return (string)value;
108 }
109
110 public bool Read()
111 {
112 return m_source.Read();
113 }
114
115 public virtual Guid GetGuid(string name)
116 {
117 return m_source.GetGuid(m_source.GetOrdinal(name));
118 }
119
120 public UInt32 GetUInt32(string name )
121 {
122 return (UInt32)GetInt32(name);
123 }
124
125 private Int32 GetInt32(string name)
126 {
127 int ordinal = m_source.GetOrdinal(name);
128 int int32 = m_source.GetInt32(ordinal);
129 return int32;
130 }
131
132 public Int64 GetInt64(string name)
133 {
134 int ordinal = m_source.GetOrdinal( name );
135 long int64 = m_source.GetInt64(ordinal);
136 return int64;
137 }
138 }
139}
diff --git a/OpenSim/Data/Base/BaseDatabaseConnector.cs b/OpenSim/Data/Base/BaseDatabaseConnector.cs
new file mode 100644
index 0000000..fa3a6c3
--- /dev/null
+++ b/OpenSim/Data/Base/BaseDatabaseConnector.cs
@@ -0,0 +1,142 @@
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 OpenSim 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.Data.Common;
32
33namespace OpenSim.Framework.Data.Base
34{
35 public abstract class BaseDatabaseConnector
36 {
37 protected string m_connectionString;
38
39 public BaseDatabaseConnector(string connectionString)
40 {
41 m_connectionString = connectionString;
42 }
43
44 public abstract DbConnection GetNewConnection();
45 public abstract string CreateParamName(string fieldName);
46
47 public DbCommand CreateSelectCommand(BaseTableMapper mapper, DbConnection connection, string fieldName, object key)
48 {
49 string table = mapper.TableName;
50
51 DbCommand command = connection.CreateCommand();
52
53 string conditionString = CreateCondition(mapper, command, fieldName, key);
54
55 string query =
56 String.Format("select * from {0} where {1}", table, conditionString);
57
58 command.CommandText = query;
59 command.CommandType = CommandType.Text;
60
61 return command;
62 }
63
64 public string CreateCondition(BaseTableMapper mapper, DbCommand command, string fieldName, object key)
65 {
66 string keyFieldParamName = mapper.CreateParamName(fieldName);
67
68 DbParameter param = command.CreateParameter();
69 param.ParameterName = keyFieldParamName;
70 param.Value = ConvertToDbType(key);
71 command.Parameters.Add(param);
72
73 return String.Format("{0}={1}", fieldName, keyFieldParamName);
74 }
75
76 public DbCommand CreateUpdateCommand(BaseTableMapper mapper, DbConnection connection, object rowMapper, object primaryKey)
77 {
78 string table = mapper.TableName;
79
80 List<string> fieldNames = new List<string>();
81
82 DbCommand command = connection.CreateCommand();
83
84 foreach (BaseFieldMapper fieldMapper in mapper.Schema.Fields.Values)
85 {
86 if (fieldMapper != mapper.KeyFieldMapper)
87 {
88 fieldMapper.ExpandField(rowMapper, command, fieldNames);
89 }
90 }
91
92 List<string> assignments = new List<string>();
93
94 foreach (string field in fieldNames)
95 {
96 assignments.Add(String.Format("{0}={1}", field, mapper.CreateParamName(field)));
97 }
98
99 string conditionString = mapper.CreateCondition(command, mapper.KeyFieldMapper.FieldName, primaryKey);
100
101 command.CommandText =
102 String.Format("update {0} set {1} where {2}", table, String.Join(", ", assignments.ToArray()),
103 conditionString);
104
105 return command;
106 }
107
108 public DbCommand CreateInsertCommand(BaseTableMapper mapper, DbConnection connection, object obj)
109 {
110 string table = mapper.TableName;
111
112 List<string> fieldNames = new List<string>();
113
114 DbCommand command = connection.CreateCommand();
115
116 foreach (BaseFieldMapper fieldMapper in mapper.Schema.Fields.Values)
117 {
118 fieldMapper.ExpandField(obj, command, fieldNames);
119 }
120
121 List<string> paramNames = new List<string>();
122
123 foreach (string field in fieldNames)
124 {
125 paramNames.Add(mapper.CreateParamName(field));
126 }
127
128 command.CommandText =
129 String.Format("insert into {0} ({1}) values ({2})", table, String.Join(", ", fieldNames.ToArray()),
130 String.Join(", ", paramNames.ToArray()));
131
132 return command;
133 }
134
135 public virtual object ConvertToDbType(object value)
136 {
137 return value;
138 }
139
140 public abstract BaseDataReader CreateReader(IDataReader reader);
141 }
142}
diff --git a/OpenSim/Data/Base/BaseFieldMapper.cs b/OpenSim/Data/Base/BaseFieldMapper.cs
new file mode 100644
index 0000000..03c7bfb
--- /dev/null
+++ b/OpenSim/Data/Base/BaseFieldMapper.cs
@@ -0,0 +1,168 @@
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 OpenSim 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.Common;
31
32namespace OpenSim.Framework.Data.Base
33{
34 public delegate TField ObjectGetAccessor<TObj, TField>(TObj obj);
35 public delegate void ObjectSetAccessor<TObj, TField>(TObj obj, TField value);
36
37 public abstract class BaseFieldMapper
38 {
39 private readonly BaseTableMapper m_tableMapper;
40 private readonly string m_fieldName;
41
42 public string FieldName
43 {
44 get { return m_fieldName; }
45 }
46
47 protected Type m_valueType;
48
49 public Type ValueType
50 {
51 get { return m_valueType; }
52 }
53
54 public abstract object GetParamValue(object obj);
55
56 public BaseFieldMapper(BaseTableMapper tableMapper, string fieldName, Type valueType)
57 {
58 m_fieldName = fieldName;
59 m_valueType = valueType;
60 m_tableMapper = tableMapper;
61 }
62
63 public abstract void SetPropertyFromReader(object mapper, BaseDataReader reader);
64
65 public void RawAddParam(DbCommand command, List<string> fieldNames, string fieldName, object value)
66 {
67 string paramName = m_tableMapper.CreateParamName(fieldName);
68 fieldNames.Add(fieldName);
69
70 DbParameter param = command.CreateParameter();
71 param.ParameterName = paramName;
72 param.Value = value;
73
74 command.Parameters.Add(param);
75 }
76
77 public virtual void ExpandField<TObj>(TObj obj, DbCommand command, List<string> fieldNames)
78 {
79 string fieldName = FieldName;
80 object value = GetParamValue(obj);
81
82 RawAddParam(command, fieldNames, fieldName, m_tableMapper.ConvertToDbType(value));
83 }
84
85 protected virtual object GetValue(BaseDataReader reader)
86 {
87 object value;
88
89 if (ValueType == typeof(Guid))
90 {
91 value = reader.GetGuid(m_fieldName);
92 }
93 else if (ValueType == typeof(bool))
94 {
95 uint boolVal = reader.GetUShort(m_fieldName);
96 value = (boolVal == 1);
97 }
98 else
99 if (ValueType == typeof(byte))
100 {
101 value = reader.GetByte(m_fieldName);
102 }
103 else if (ValueType == typeof(sbyte))
104 {
105 value = reader.GetSByte(m_fieldName);
106 }
107 else if (ValueType == typeof(ushort))
108 {
109 value = reader.GetUShort(m_fieldName);
110 }
111 else if (ValueType == typeof(uint))
112 {
113 value = reader.GetUInt32(m_fieldName);
114 }
115 else if (ValueType == typeof(byte[]))
116 {
117 value = reader.GetBytes(m_fieldName);
118 }
119 else
120 {
121 value = reader.Get(m_fieldName);
122 }
123
124 if (value is DBNull)
125 {
126 value = default(ValueType);
127 }
128
129 return value;
130 }
131 }
132
133 public class ObjectField<TObject, TField> : BaseFieldMapper
134 {
135 private readonly ObjectGetAccessor<TObject, TField> m_fieldGetAccessor;
136 private readonly ObjectSetAccessor<TObject, TField> m_fieldSetAccessor;
137
138 public override object GetParamValue(object obj)
139 {
140 return m_fieldGetAccessor((TObject)obj);
141 }
142
143 public override void SetPropertyFromReader(object obj, BaseDataReader reader)
144 {
145 object value;
146
147 value = GetValue(reader);
148
149 if (value == null)
150 {
151 m_fieldSetAccessor((TObject)obj, default(TField));
152 }
153 else
154 {
155 m_fieldSetAccessor((TObject)obj, (TField)value);
156 }
157 }
158
159
160 public ObjectField(BaseTableMapper tableMapper, string fieldName, ObjectGetAccessor<TObject, TField> rowMapperGetAccessor,
161 ObjectSetAccessor<TObject, TField> rowMapperSetAccessor)
162 : base(tableMapper, fieldName, typeof(TField))
163 {
164 m_fieldGetAccessor = rowMapperGetAccessor;
165 m_fieldSetAccessor = rowMapperSetAccessor;
166 }
167 }
168}
diff --git a/OpenSim/Data/Base/BaseRowMapper.cs b/OpenSim/Data/Base/BaseRowMapper.cs
new file mode 100644
index 0000000..b008b86
--- /dev/null
+++ b/OpenSim/Data/Base/BaseRowMapper.cs
@@ -0,0 +1,61 @@
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 OpenSim 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 OpenSim.Framework.Data.Base;
29
30namespace OpenSim.Framework.Data.Base
31{
32 public abstract class BaseRowMapper
33 {
34 public abstract void FillObject(BaseDataReader reader);
35 }
36
37 public class BaseRowMapper<TObj> : BaseRowMapper
38 {
39 private readonly BaseSchema m_schema;
40 private readonly TObj m_obj;
41
42 public TObj Object
43 {
44 get { return m_obj; }
45 }
46
47 public BaseRowMapper(BaseSchema schema, TObj obj)
48 {
49 m_schema = schema;
50 m_obj = obj;
51 }
52
53 public override void FillObject(BaseDataReader reader)
54 {
55 foreach (BaseFieldMapper fieldMapper in m_schema.Fields.Values)
56 {
57 fieldMapper.SetPropertyFromReader(this, reader);
58 }
59 }
60 }
61}
diff --git a/OpenSim/Data/Base/BaseSchema.cs b/OpenSim/Data/Base/BaseSchema.cs
new file mode 100644
index 0000000..8a7ee71
--- /dev/null
+++ b/OpenSim/Data/Base/BaseSchema.cs
@@ -0,0 +1,69 @@
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 OpenSim 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.Collections.Generic;
29using OpenSim.Framework.Data.Base;
30
31namespace OpenSim.Framework.Data.Base
32{
33 public class BaseSchema
34 {
35 protected BaseTableMapper m_tableMapper;
36 protected Dictionary<string, BaseFieldMapper> m_mappings;
37
38 public Dictionary<string, BaseFieldMapper> Fields
39 {
40 get { return m_mappings; }
41 }
42
43 public BaseSchema(BaseTableMapper tableMapper)
44 {
45 m_mappings = new Dictionary<string, BaseFieldMapper>();
46 m_tableMapper = tableMapper;
47 }
48 }
49
50 public class BaseSchema<TObj> : BaseSchema
51 {
52 public BaseSchema(BaseTableMapper tableMapper)
53 : base(tableMapper)
54 {
55 }
56
57 public ObjectField<TObj, TField> AddMapping<TField>(string fieldName,
58 ObjectGetAccessor<TObj, TField> rowMapperGetAccessor,
59 ObjectSetAccessor<TObj, TField> rowMapperSetAccessor)
60 {
61 ObjectField<TObj, TField> rowMapperField =
62 new ObjectField<TObj, TField>(m_tableMapper, fieldName, rowMapperGetAccessor, rowMapperSetAccessor);
63
64 m_mappings.Add(fieldName, rowMapperField);
65
66 return rowMapperField;
67 }
68 }
69}
diff --git a/OpenSim/Data/Base/BaseTableMapper.cs b/OpenSim/Data/Base/BaseTableMapper.cs
new file mode 100644
index 0000000..cad4823
--- /dev/null
+++ b/OpenSim/Data/Base/BaseTableMapper.cs
@@ -0,0 +1,281 @@
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 OpenSim 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.Data.Common;
31using OpenSim.Framework.Data.Base;
32
33namespace OpenSim.Framework.Data.Base
34{
35 public abstract class BaseTableMapper
36 {
37 private readonly BaseDatabaseConnector m_database;
38 private readonly object m_syncRoot = new object();
39
40 protected void WithConnection(Action<DbConnection> action)
41 {
42 lock (m_syncRoot)
43 {
44 DbConnection m_connection = m_database.GetNewConnection();
45
46 if (m_connection.State != ConnectionState.Open)
47 {
48 m_connection.Open();
49 }
50
51 action(m_connection);
52
53 if (m_connection.State == ConnectionState.Open)
54 {
55 m_connection.Close();
56 }
57 }
58 }
59
60 private readonly string m_tableName;
61 public string TableName
62 {
63 get { return m_tableName; }
64 }
65
66 protected BaseSchema m_schema;
67 public BaseSchema Schema
68 {
69 get { return m_schema; }
70 }
71
72 protected BaseFieldMapper m_keyFieldMapper;
73 public BaseFieldMapper KeyFieldMapper
74 {
75 get { return m_keyFieldMapper; }
76 }
77
78 public BaseTableMapper(BaseDatabaseConnector database, string tableName)
79 {
80 m_database = database;
81 m_tableName = tableName.ToLower(); // Stupid MySQL hack.
82 }
83
84 public string CreateParamName(string fieldName)
85 {
86 return m_database.CreateParamName(fieldName);
87 }
88
89 protected DbCommand CreateSelectCommand(DbConnection connection, string fieldName, object primaryKey)
90 {
91 return m_database.CreateSelectCommand(this, connection, fieldName, primaryKey);
92 }
93
94 public string CreateCondition(DbCommand command, string fieldName, object key)
95 {
96 return m_database.CreateCondition(this, command, fieldName, key);
97 }
98
99 public DbCommand CreateInsertCommand(DbConnection connection, object obj)
100 {
101 return m_database.CreateInsertCommand(this, connection, obj);
102 }
103
104 public DbCommand CreateUpdateCommand(DbConnection connection, object rowMapper, object primaryKey)
105 {
106 return m_database.CreateUpdateCommand(this, connection, rowMapper, primaryKey);
107 }
108
109 public object ConvertToDbType(object value)
110 {
111 return m_database.ConvertToDbType(value);
112 }
113
114 protected virtual BaseDataReader CreateReader(IDataReader reader)
115 {
116 return m_database.CreateReader(reader);
117 }
118 }
119
120 public abstract class BaseTableMapper<TRowMapper, TPrimaryKey> : BaseTableMapper
121 {
122 public BaseTableMapper(BaseDatabaseConnector database, string tableName)
123 : base(database, tableName)
124 {
125 }
126
127 // HACK: This is a temporary function used by TryGetValue().
128 // Due to a bug in mono 1.2.6, delegate blocks cannot contain
129 // a using() block. This has been fixed in SVN, so the next
130 // mono release should work.
131 private void TryGetConnectionValue(DbConnection connection, TPrimaryKey primaryKey, ref TRowMapper result, ref bool success)
132 {
133 using (
134 DbCommand command =
135 CreateSelectCommand(connection, KeyFieldMapper.FieldName, primaryKey))
136 {
137 using (IDataReader reader = command.ExecuteReader())
138 {
139 if (reader.Read())
140 {
141 result = FromReader( CreateReader(reader));
142 success = true;
143 }
144 else
145 {
146 success = false;
147 }
148 }
149 }
150 }
151
152 public bool TryGetValue(TPrimaryKey primaryKey, out TRowMapper value)
153 {
154 TRowMapper result = default(TRowMapper);
155 bool success = false;
156
157 WithConnection(delegate(DbConnection connection)
158 {
159 TryGetConnectionValue(connection, primaryKey, ref result, ref success);
160 });
161
162 value = result;
163
164 return success;
165 }
166
167 // HACK: This is a temporary function used by Remove().
168 // Due to a bug in mono 1.2.6, delegate blocks cannot contain
169 // a using() block. This has been fixed in SVN, so the next
170 // mono release should work.
171 protected virtual void TryDelete(DbConnection connection, TPrimaryKey id, ref int deleted)
172 {
173 using (
174 DbCommand command =
175 CreateDeleteCommand(connection, KeyFieldMapper.FieldName, id))
176 {
177 deleted = command.ExecuteNonQuery();
178 }
179 }
180
181 public virtual bool Remove(TPrimaryKey id)
182 {
183 int deleted = 0;
184
185 WithConnection(delegate(DbConnection connection)
186 {
187 TryDelete(connection, id, ref deleted);
188 });
189
190 if (deleted == 1)
191 {
192 return true;
193 }
194 else
195 {
196 return false;
197 }
198 }
199
200 public DbCommand CreateDeleteCommand(DbConnection connection, string fieldName, TPrimaryKey primaryKey)
201 {
202 string table = TableName;
203
204 DbCommand command = connection.CreateCommand();
205
206 string conditionString = CreateCondition(command, fieldName, primaryKey);
207
208 string query =
209 String.Format("delete from {0} where {1}", table, conditionString);
210
211 command.CommandText = query;
212 command.CommandType = CommandType.Text;
213
214 return command;
215 }
216
217 // HACK: This is a temporary function used by Update().
218 // Due to a bug in mono 1.2.6, delegate blocks cannot contain
219 // a using() block. This has been fixed in SVN, so the next
220 // mono release should work.
221 protected void TryUpdate(DbConnection connection, TPrimaryKey primaryKey, TRowMapper value, ref int updated)
222 {
223 using (DbCommand command = CreateUpdateCommand(connection, value, primaryKey))
224 {
225 updated = command.ExecuteNonQuery();
226 }
227 }
228
229 public virtual bool Update(TPrimaryKey primaryKey, TRowMapper value)
230 {
231 int updated = 0;
232
233 WithConnection(delegate(DbConnection connection)
234 {
235 TryUpdate(connection, primaryKey, value, ref updated);
236 });
237
238 if (updated == 1)
239 {
240 return true;
241 }
242 else
243 {
244 return false;
245 }
246 }
247
248 // HACK: This is a temporary function used by Add().
249 // Due to a bug in mono 1.2.6, delegate blocks cannot contain
250 // a using() block. This has been fixed in SVN, so the next
251 // mono release should work.
252 protected void TryAdd(DbConnection connection, TRowMapper value, ref int added)
253 {
254 using (DbCommand command = CreateInsertCommand(connection, value))
255 {
256 added = command.ExecuteNonQuery();
257 }
258 }
259
260 public virtual bool Add(TRowMapper value)
261 {
262 int added = 0;
263
264 WithConnection(delegate(DbConnection connection)
265 {
266 TryAdd(connection, value, ref added);
267 });
268
269 if (added == 1)
270 {
271 return true;
272 }
273 else
274 {
275 return false;
276 }
277 }
278
279 public abstract TRowMapper FromReader(BaseDataReader reader);
280 }
281}
diff --git a/OpenSim/Data/Base/OpenSim.Framework.Data.Base.snk b/OpenSim/Data/Base/OpenSim.Framework.Data.Base.snk
new file mode 100644
index 0000000..fc71027
--- /dev/null
+++ b/OpenSim/Data/Base/OpenSim.Framework.Data.Base.snk
Binary files differ
diff --git a/OpenSim/Data/Base/Properties/AssemblyInfo.cs b/OpenSim/Data/Base/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..ab97490
--- /dev/null
+++ b/OpenSim/Data/Base/Properties/AssemblyInfo.cs
@@ -0,0 +1,67 @@
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 OpenSim 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.Reflection;
29using System.Runtime.InteropServices;
30using System.Security;
31
32// General Information about an assembly is controlled through the following
33// set of attributes. Change these attribute values to modify the information
34// associated with an assembly.
35
36[assembly : AssemblyTitle("OpenSim.Framework.Data.Base")]
37[assembly : AssemblyDescription("Generic Database Abstraction Layer")]
38[assembly : AssemblyConfiguration("")]
39[assembly : AssemblyCompany("OpenSim Project (www.opensimulator.org)")]
40[assembly: AssemblyProduct("OpenSim.Framework.Data.Base")]
41[assembly: AssemblyCopyright("Copyright (c) 2007 OpenSim Project (www.opensimulator.org)")]
42[assembly : AssemblyTrademark("")]
43[assembly : AssemblyCulture("")]
44
45// Setting ComVisible to false makes the types in this assembly not visible
46// to COM components. If you need to access a type in this assembly from
47// COM, set the ComVisible attribute to true on that type.
48
49[assembly : ComVisible(false)]
50
51// The following GUID is for the ID of the typelib if this project is exposed to COM
52
53[assembly : Guid("9269f421-19d9-4eea-bfe3-c0ffe426fada")]
54
55// Version information for an assembly consists of the following four values:
56//
57// Major Version
58// Minor Version
59// Build Number
60// Revision
61//
62// You can specify all the values or you can default the Revision and Build Numbers
63// by using the '*' as shown below:
64
65[assembly : AssemblyVersion("1.0.0.0")]
66[assembly : AssemblyFileVersion("1.0.0.0")]
67[assembly : AllowPartiallyTrustedCallers]
diff --git a/OpenSim/Data/DB4o/DB4oGridData.cs b/OpenSim/Data/DB4o/DB4oGridData.cs
new file mode 100644
index 0000000..31b13e3
--- /dev/null
+++ b/OpenSim/Data/DB4o/DB4oGridData.cs
@@ -0,0 +1,182 @@
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 OpenSim 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 libsecondlife;
31
32namespace OpenSim.Framework.Data.DB4o
33{
34 /// <summary>
35 /// A grid server storage mechanism employing the DB4o database system
36 /// </summary>
37 internal class DB4oGridData : GridDataBase
38 {
39 /// <summary>
40 /// The database manager object
41 /// </summary>
42 private DB4oGridManager manager;
43
44 /// <summary>
45 /// Called when the plugin is first loaded (as constructors are not called)
46 /// </summary>
47 override public void Initialise()
48 {
49 manager = new DB4oGridManager("gridserver.yap");
50 }
51
52 /// <summary>
53 /// Returns a list of regions within the specified ranges
54 /// </summary>
55 /// <param name="a">minimum X coordinate</param>
56 /// <param name="b">minimum Y coordinate</param>
57 /// <param name="c">maximum X coordinate</param>
58 /// <param name="d">maximum Y coordinate</param>
59 /// <returns>An array of region profiles</returns>
60 override public RegionProfileData[] GetProfilesInRange(uint a, uint b, uint c, uint d)
61 {
62 return null;
63 }
64
65 /// <summary>
66 /// Returns a region located at the specified regionHandle (warning multiple regions may occupy the one spot, first found is returned)
67 /// </summary>
68 /// <param name="handle">The handle to search for</param>
69 /// <returns>A region profile</returns>
70 override public RegionProfileData GetProfileByHandle(ulong handle)
71 {
72 lock (manager.simProfiles)
73 {
74 foreach (LLUUID UUID in manager.simProfiles.Keys)
75 {
76 if (manager.simProfiles[UUID].regionHandle == handle)
77 {
78 return manager.simProfiles[UUID];
79 }
80 }
81 }
82 throw new Exception("Unable to find profile with handle (" + handle.ToString() + ")");
83 }
84
85 /// <summary>
86 /// Returns a specific region
87 /// </summary>
88 /// <param name="uuid">The region ID code</param>
89 /// <returns>A region profile</returns>
90 override public RegionProfileData GetProfileByLLUUID(LLUUID uuid)
91 {
92 lock (manager.simProfiles)
93 {
94 if (manager.simProfiles.ContainsKey(uuid))
95 return manager.simProfiles[uuid];
96 }
97 throw new Exception("Unable to find profile with UUID (" + uuid.ToString() +
98 "). Total Registered Regions: " + manager.simProfiles.Count);
99 }
100
101 override public RegionProfileData GetProfileByString(string regionName)
102 {
103 throw new Exception("GetProfileByString Not supported in DB4oGridData");
104 //return null;
105 }
106
107 /// <summary>
108 /// Adds a new specified region to the database
109 /// </summary>
110 /// <param name="profile">The profile to add</param>
111 /// <returns>A dataresponse enum indicating success</returns>
112 override public DataResponse AddProfile(RegionProfileData profile)
113 {
114 lock (manager.simProfiles)
115 {
116 if (manager.AddRow(profile))
117 {
118 return DataResponse.RESPONSE_OK;
119 }
120 else
121 {
122 return DataResponse.RESPONSE_ERROR;
123 }
124 }
125 }
126
127 /// <summary>
128 /// Authenticates a new region using the shared secrets. NOT SECURE.
129 /// </summary>
130 /// <param name="uuid">The UUID the region is authenticating with</param>
131 /// <param name="handle">The location the region is logging into (unused in Db4o)</param>
132 /// <param name="key">The shared secret</param>
133 /// <returns>Authenticated?</returns>
134 override public bool AuthenticateSim(LLUUID uuid, ulong handle, string key)
135 {
136 if (manager.simProfiles[uuid].regionRecvKey == key)
137 return true;
138 return false;
139 }
140
141 /// <summary>
142 /// Shuts down the database
143 /// </summary>
144 override public void Close()
145 {
146 manager = null;
147 }
148
149 /// <summary>
150 /// // Returns a list of avatar and UUIDs that match the query
151 /// </summary>
152 public List<AvatarPickerAvatar> GeneratePickerResults(LLUUID queryID, string query)
153 {
154 //Do nothing yet
155 List<AvatarPickerAvatar> returnlist = new List<AvatarPickerAvatar>();
156 return returnlist;
157 }
158
159 /// <summary>
160 /// Returns the providers name
161 /// </summary>
162 /// <returns>The name of the storage system</returns>
163 override public string getName()
164 {
165 return "DB4o Grid Provider";
166 }
167
168 /// <summary>
169 /// Returns the providers version
170 /// </summary>
171 /// <returns>The version of the storage system</returns>
172 override public string getVersion()
173 {
174 return "0.1";
175 }
176
177 override public ReservationData GetReservationAtPoint(uint x, uint y)
178 {
179 return null;
180 }
181 }
182}
diff --git a/OpenSim/Data/DB4o/DB4oManager.cs b/OpenSim/Data/DB4o/DB4oManager.cs
new file mode 100644
index 0000000..9cacb5e
--- /dev/null
+++ b/OpenSim/Data/DB4o/DB4oManager.cs
@@ -0,0 +1,170 @@
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 OpenSim 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 Db4objects.Db4o;
31using libsecondlife;
32
33namespace OpenSim.Framework.Data.DB4o
34{
35 /// <summary>
36 /// A Database manager for Db4o
37 /// </summary>
38 internal class DB4oGridManager
39 {
40 /// <summary>
41 /// A list of the current regions connected (in-memory cache)
42 /// </summary>
43 public Dictionary<LLUUID, RegionProfileData> simProfiles = new Dictionary<LLUUID, RegionProfileData>();
44
45 /// <summary>
46 /// Database File Name
47 /// </summary>
48 private string dbfl;
49
50 /// <summary>
51 /// Creates a new grid storage manager
52 /// </summary>
53 /// <param name="db4odb">Filename to the database file</param>
54 public DB4oGridManager(string db4odb)
55 {
56 dbfl = db4odb;
57 IObjectContainer database;
58 database = Db4oFactory.OpenFile(dbfl);
59 IObjectSet result = database.Get(typeof (RegionProfileData));
60 // Loads the file into the in-memory cache
61 foreach (RegionProfileData row in result)
62 {
63 simProfiles.Add(row.UUID, row);
64 }
65 database.Close();
66 }
67
68 /// <summary>
69 /// Adds a new profile to the database (Warning: Probably slow.)
70 /// </summary>
71 /// <param name="row">The profile to add</param>
72 /// <returns>Successful?</returns>
73 public bool AddRow(RegionProfileData row)
74 {
75 if (simProfiles.ContainsKey(row.UUID))
76 {
77 simProfiles[row.UUID] = row;
78 }
79 else
80 {
81 simProfiles.Add(row.UUID, row);
82 }
83
84 try
85 {
86 IObjectContainer database;
87 database = Db4oFactory.OpenFile(dbfl);
88 database.Set(row);
89 database.Close();
90 return true;
91 }
92 catch (Exception)
93 {
94 return false;
95 }
96 }
97 }
98
99 /// <summary>
100 /// A manager for the DB4o database (user profiles)
101 /// </summary>
102 internal class DB4oUserManager
103 {
104 /// <summary>
105 /// A list of the user profiles (in memory cache)
106 /// </summary>
107 public Dictionary<LLUUID, UserProfileData> userProfiles = new Dictionary<LLUUID, UserProfileData>();
108
109 /// <summary>
110 /// Database filename
111 /// </summary>
112 private string dbfl;
113
114 /// <summary>
115 /// Initialises a new DB manager
116 /// </summary>
117 /// <param name="db4odb">The filename to the database</param>
118 public DB4oUserManager(string db4odb)
119 {
120 dbfl = db4odb;
121 IObjectContainer database;
122 database = Db4oFactory.OpenFile(dbfl);
123 // Load to cache
124 IObjectSet result = database.Get(typeof (UserProfileData));
125 foreach (UserProfileData row in result)
126 {
127 if (userProfiles.ContainsKey(row.UUID))
128 userProfiles[row.UUID] = row;
129 else
130 userProfiles.Add(row.UUID, row);
131 }
132 database.Close();
133 }
134
135 /// <summary>
136 /// Adds or updates a record to the user database. Do this when changes are needed
137 /// in the user profile that need to be persistant.
138 ///
139 /// TODO: the logic here is not ACID, the local cache will be
140 /// updated even if the persistant data is not. This may lead
141 /// to unexpected results.
142 /// </summary>
143 /// <param name="record">The profile to update</param>
144 /// <returns>true on success, false on fail to persist to db</returns>
145 public bool UpdateRecord(UserProfileData record)
146 {
147 if (userProfiles.ContainsKey(record.UUID))
148 {
149 userProfiles[record.UUID] = record;
150 }
151 else
152 {
153 userProfiles.Add(record.UUID, record);
154 }
155
156 try
157 {
158 IObjectContainer database;
159 database = Db4oFactory.OpenFile(dbfl);
160 database.Set(record);
161 database.Close();
162 return true;
163 }
164 catch (Exception)
165 {
166 return false;
167 }
168 }
169 }
170}
diff --git a/OpenSim/Data/DB4o/DB4oUserData.cs b/OpenSim/Data/DB4o/DB4oUserData.cs
new file mode 100644
index 0000000..3072e81
--- /dev/null
+++ b/OpenSim/Data/DB4o/DB4oUserData.cs
@@ -0,0 +1,270 @@
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 OpenSim 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.IO;
31using libsecondlife;
32
33namespace OpenSim.Framework.Data.DB4o
34{
35 /// <summary>
36 /// A User storage interface for the DB4o database system
37 /// </summary>
38 public class DB4oUserData : IUserData
39 {
40 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
41
42 /// <summary>
43 /// The database manager
44 /// </summary>
45 private DB4oUserManager manager;
46
47 /// <summary>
48 /// Artificial constructor called upon plugin load
49 /// </summary>
50 public void Initialise()
51 {
52 manager = new DB4oUserManager(Path.Combine(Util.dataDir(), "userprofiles.yap"));
53 }
54
55 /// <summary>
56 /// Loads a specified user profile from a UUID
57 /// </summary>
58 /// <param name="uuid">The users UUID</param>
59 /// <returns>A user profile</returns>
60 public UserProfileData GetUserByUUID(LLUUID uuid)
61 {
62 if (manager.userProfiles.ContainsKey(uuid))
63 return manager.userProfiles[uuid];
64 return null;
65 }
66
67 /// <summary>
68 /// Returns a user by searching for its name
69 /// </summary>
70 /// <param name="name">The users account name</param>
71 /// <returns>A matching users profile</returns>
72 public UserProfileData GetUserByName(string name)
73 {
74 return GetUserByName(name.Split(' ')[0], name.Split(' ')[1]);
75 }
76
77 /// <summary>
78 /// Returns a user by searching for its name
79 /// </summary>
80 /// <param name="fname">The first part of the users account name</param>
81 /// <param name="lname">The second part of the users account name</param>
82 /// <returns>A matching users profile</returns>
83 public UserProfileData GetUserByName(string fname, string lname)
84 {
85 foreach (UserProfileData profile in manager.userProfiles.Values)
86 {
87 if (profile.username == fname && profile.surname == lname)
88 return profile;
89 }
90 return null;
91 }
92
93 /// <summary>
94 /// Returns a user by UUID direct
95 /// </summary>
96 /// <param name="uuid">The users account ID</param>
97 /// <returns>A matching users profile</returns>
98 public UserAgentData GetAgentByUUID(LLUUID uuid)
99 {
100 try
101 {
102 return GetUserByUUID(uuid).currentAgent;
103 }
104 catch (Exception)
105 {
106 return null;
107 }
108 }
109
110 /// <summary>
111 /// Returns a session by account name
112 /// </summary>
113 /// <param name="name">The account name</param>
114 /// <returns>The users session agent</returns>
115 public UserAgentData GetAgentByName(string name)
116 {
117 return GetAgentByName(name.Split(' ')[0], name.Split(' ')[1]);
118 }
119
120 /// <summary>
121 /// Returns a session by account name
122 /// </summary>
123 /// <param name="fname">The first part of the users account name</param>
124 /// <param name="lname">The second part of the users account name</param>
125 /// <returns>A user agent</returns>
126 public UserAgentData GetAgentByName(string fname, string lname)
127 {
128 try
129 {
130 return GetUserByName(fname, lname).currentAgent;
131 }
132 catch (Exception)
133 {
134 return null;
135 }
136 }
137 public void StoreWebLoginKey(LLUUID AgentID, LLUUID WebLoginKey)
138 {
139 UserProfileData user = GetUserByUUID(AgentID);
140 user.webLoginKey = WebLoginKey;
141 UpdateUserProfile(user);
142
143 }
144 #region User Friends List Data
145
146 public void AddNewUserFriend(LLUUID friendlistowner, LLUUID friend, uint perms)
147 {
148 //m_log.Info("[FRIEND]: Stub AddNewUserFriend called");
149 }
150
151 public void RemoveUserFriend(LLUUID friendlistowner, LLUUID friend)
152 {
153 //m_log.Info("[FRIEND]: Stub RemoveUserFriend called");
154 }
155 public void UpdateUserFriendPerms(LLUUID friendlistowner, LLUUID friend, uint perms)
156 {
157 //m_log.Info("[FRIEND]: Stub UpdateUserFriendPerms called");
158 }
159
160
161 public List<FriendListItem> GetUserFriendList(LLUUID friendlistowner)
162 {
163 //m_log.Info("[FRIEND]: Stub GetUserFriendList called");
164 return new List<FriendListItem>();
165 }
166
167 #endregion
168
169 public void UpdateUserCurrentRegion(LLUUID avatarid, LLUUID regionuuid)
170 {
171 //m_log.Info("[USER]: Stub UpdateUserCUrrentRegion called");
172 }
173
174
175
176 public List<Framework.AvatarPickerAvatar> GeneratePickerResults(LLUUID queryID, string query)
177 {
178 //Do nothing yet
179 List<Framework.AvatarPickerAvatar> returnlist = new List<Framework.AvatarPickerAvatar>();
180 return returnlist;
181 }
182
183 /// <summary>
184 /// Creates a new user profile
185 /// </summary>
186 /// <param name="user">The profile to add to the database</param>
187 public void AddNewUserProfile(UserProfileData user)
188 {
189 try
190 {
191 manager.UpdateRecord(user);
192 }
193 catch (Exception e)
194 {
195 Console.WriteLine(e.ToString());
196 }
197 }
198
199 /// <summary>
200 /// Creates a new user profile
201 /// </summary>
202 /// <param name="user">The profile to add to the database</param>
203 /// <returns>True on success, false on error</returns>
204 public bool UpdateUserProfile(UserProfileData user)
205 {
206 try
207 {
208 return manager.UpdateRecord(user);
209 }
210 catch (Exception e)
211 {
212 Console.WriteLine(e.ToString());
213 return false;
214 }
215 }
216
217
218 /// <summary>
219 /// Creates a new user agent
220 /// </summary>
221 /// <param name="agent">The agent to add to the database</param>
222 public void AddNewUserAgent(UserAgentData agent)
223 {
224 // Do nothing. yet.
225 }
226
227 /// <summary>
228 /// Transfers money between two user accounts
229 /// </summary>
230 /// <param name="from">Starting account</param>
231 /// <param name="to">End account</param>
232 /// <param name="amount">The amount to move</param>
233 /// <returns>Success?</returns>
234 public bool MoneyTransferRequest(LLUUID from, LLUUID to, uint amount)
235 {
236 return true;
237 }
238
239 /// <summary>
240 /// Transfers inventory between two accounts
241 /// </summary>
242 /// <remarks>Move to inventory server</remarks>
243 /// <param name="from">Senders account</param>
244 /// <param name="to">Receivers account</param>
245 /// <param name="item">Inventory item</param>
246 /// <returns>Success?</returns>
247 public bool InventoryTransferRequest(LLUUID from, LLUUID to, LLUUID item)
248 {
249 return true;
250 }
251
252 /// <summary>
253 /// Returns the name of the storage provider
254 /// </summary>
255 /// <returns>Storage provider name</returns>
256 public string getName()
257 {
258 return "DB4o Userdata";
259 }
260
261 /// <summary>
262 /// Returns the version of the storage provider
263 /// </summary>
264 /// <returns>Storage provider version</returns>
265 public string GetVersion()
266 {
267 return "0.1";
268 }
269 }
270}
diff --git a/OpenSim/Data/DB4o/Properties/AssemblyInfo.cs b/OpenSim/Data/DB4o/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..ee84938
--- /dev/null
+++ b/OpenSim/Data/DB4o/Properties/AssemblyInfo.cs
@@ -0,0 +1,65 @@
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 OpenSim 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.Reflection;
29using System.Runtime.InteropServices;
30
31// General Information about an assembly is controlled through the following
32// set of attributes. Change these attribute values to modify the information
33// associated with an assembly.
34
35[assembly : AssemblyTitle("OpenSim.Framework.Data.DB4o")]
36[assembly : AssemblyDescription("")]
37[assembly : AssemblyConfiguration("")]
38[assembly : AssemblyCompany("")]
39[assembly : AssemblyProduct("OpenSim.Framework.Data.DB4o")]
40[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers 2007-2008")]
41[assembly : AssemblyTrademark("")]
42[assembly : AssemblyCulture("")]
43
44// Setting ComVisible to false makes the types in this assembly not visible
45// to COM components. If you need to access a type in this assembly from
46// COM, set the ComVisible attribute to true on that type.
47
48[assembly : ComVisible(false)]
49
50// The following GUID is for the ID of the typelib if this project is exposed to COM
51
52[assembly : Guid("57991e15-79da-41b7-aa06-2e6b49165a63")]
53
54// Version information for an assembly consists of the following four values:
55//
56// Major Version
57// Minor Version
58// Build Number
59// Revision
60//
61// You can specify all the values or you can default the Revision and Build Numbers
62// by using the '*' as shown below:
63
64[assembly : AssemblyVersion("1.0.0.0")]
65[assembly : AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Data/MSSQL/MSSQLAssetData.cs b/OpenSim/Data/MSSQL/MSSQLAssetData.cs
new file mode 100644
index 0000000..059bb5e
--- /dev/null
+++ b/OpenSim/Data/MSSQL/MSSQLAssetData.cs
@@ -0,0 +1,221 @@
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 OpenSim 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.Data.SqlClient;
32using libsecondlife;
33using OpenSim.Framework.Console;
34
35namespace OpenSim.Framework.Data.MSSQL
36{
37 internal class MSSQLAssetData : AssetDataBase
38 {
39 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
40
41 private MSSQLManager database;
42
43 #region IAssetProvider Members
44
45 private void UpgradeAssetsTable(string tableName)
46 {
47 // null as the version, indicates that the table didn't exist
48 if (tableName == null)
49 {
50 m_log.Info("[ASSETS]: Creating new database tables");
51 database.ExecuteResourceSql("CreateAssetsTable.sql");
52 return;
53 }
54 }
55
56 /// <summary>
57 /// Ensure that the assets related tables exists and are at the latest version
58 /// </summary>
59 private void TestTables()
60 {
61 Dictionary<string, string> tableList = new Dictionary<string, string>();
62
63 tableList["assets"] = null;
64 database.GetTableVersion(tableList);
65
66 UpgradeAssetsTable(tableList["assets"]);
67 }
68
69 override public AssetBase FetchAsset(LLUUID assetID)
70 {
71 AssetBase asset = null;
72
73 Dictionary<string, string> param = new Dictionary<string, string>();
74 param["id"] = assetID.ToString();
75
76 IDbCommand result = database.Query("SELECT * FROM assets WHERE id = @id", param);
77 IDataReader reader = result.ExecuteReader();
78
79 asset = database.getAssetRow(reader);
80 reader.Close();
81 result.Dispose();
82
83 return asset;
84 }
85
86 override public void CreateAsset(AssetBase asset)
87 {
88 if (ExistsAsset((LLUUID) asset.FullID))
89 {
90 return;
91 }
92
93
94 SqlCommand cmd =
95 new SqlCommand(
96 "INSERT INTO assets ([id], [name], [description], [assetType], [invType], [local], [temporary], [data])" +
97 " VALUES " +
98 "(@id, @name, @description, @assetType, @invType, @local, @temporary, @data)",
99 database.getConnection());
100
101 using (cmd)
102 {
103 //SqlParameter p = cmd.Parameters.Add("id", SqlDbType.NVarChar);
104 //p.Value = asset.FullID.ToString();
105 cmd.Parameters.AddWithValue("id", asset.FullID.ToString());
106 cmd.Parameters.AddWithValue("name", asset.Name);
107 cmd.Parameters.AddWithValue("description", asset.Description);
108 SqlParameter e = cmd.Parameters.Add("assetType", SqlDbType.TinyInt);
109 e.Value = asset.Type;
110 SqlParameter f = cmd.Parameters.Add("invType", SqlDbType.TinyInt);
111 f.Value = asset.InvType;
112 SqlParameter g = cmd.Parameters.Add("local", SqlDbType.TinyInt);
113 g.Value = asset.Local;
114 SqlParameter h = cmd.Parameters.Add("temporary", SqlDbType.TinyInt);
115 h.Value = asset.Temporary;
116 SqlParameter i = cmd.Parameters.Add("data", SqlDbType.Image);
117 i.Value = asset.Data;
118 try
119 {
120 cmd.ExecuteNonQuery();
121 }
122 catch (Exception)
123 {
124 throw;
125 }
126
127 cmd.Dispose();
128 }
129 }
130
131
132 override public void UpdateAsset(AssetBase asset)
133 {
134 SqlCommand command = new SqlCommand("UPDATE assets set id = @id, " +
135 "name = @name, " +
136 "description = @description," +
137 "assetType = @assetType," +
138 "invType = @invType," +
139 "local = @local," +
140 "temporary = @temporary," +
141 "data = @data where " +
142 "id = @keyId;", database.getConnection());
143 SqlParameter param1 = new SqlParameter("@id", asset.FullID.ToString());
144 SqlParameter param2 = new SqlParameter("@name", asset.Name);
145 SqlParameter param3 = new SqlParameter("@description", asset.Description);
146 SqlParameter param4 = new SqlParameter("@assetType", asset.Type);
147 SqlParameter param5 = new SqlParameter("@invType", asset.InvType);
148 SqlParameter param6 = new SqlParameter("@local", asset.Local);
149 SqlParameter param7 = new SqlParameter("@temporary", asset.Temporary);
150 SqlParameter param8 = new SqlParameter("@data", asset.Data);
151 SqlParameter param9 = new SqlParameter("@keyId", asset.FullID.ToString());
152 command.Parameters.Add(param1);
153 command.Parameters.Add(param2);
154 command.Parameters.Add(param3);
155 command.Parameters.Add(param4);
156 command.Parameters.Add(param5);
157 command.Parameters.Add(param6);
158 command.Parameters.Add(param7);
159 command.Parameters.Add(param8);
160 command.Parameters.Add(param9);
161
162 try
163 {
164 command.ExecuteNonQuery();
165 }
166 catch (Exception e)
167 {
168 m_log.Error(e.ToString());
169 }
170 }
171
172 override public bool ExistsAsset(LLUUID uuid)
173 {
174 if (FetchAsset(uuid) != null)
175 {
176 return true;
177 }
178 return false;
179 }
180
181 /// <summary>
182 /// All writes are immediately commited to the database, so this is a no-op
183 /// </summary>
184 override public void CommitAssets()
185 {
186 }
187
188 #endregion
189
190 #region IPlugin Members
191
192 override public void Initialise()
193 {
194 IniFile GridDataMySqlFile = new IniFile("mssql_connection.ini");
195 string settingDataSource = GridDataMySqlFile.ParseFileReadValue("data_source");
196 string settingInitialCatalog = GridDataMySqlFile.ParseFileReadValue("initial_catalog");
197 string settingPersistSecurityInfo = GridDataMySqlFile.ParseFileReadValue("persist_security_info");
198 string settingUserId = GridDataMySqlFile.ParseFileReadValue("user_id");
199 string settingPassword = GridDataMySqlFile.ParseFileReadValue("password");
200
201 database =
202 new MSSQLManager(settingDataSource, settingInitialCatalog, settingPersistSecurityInfo, settingUserId,
203 settingPassword);
204
205 TestTables();
206 }
207
208 override public string Version
209 {
210// get { return database.getVersion(); }
211 get { return database.getVersion(); }
212 }
213
214 override public string Name
215 {
216 get { return "MSSQL Asset storage engine"; }
217 }
218
219 #endregion
220 }
221}
diff --git a/OpenSim/Data/MSSQL/MSSQLDataStore.cs b/OpenSim/Data/MSSQL/MSSQLDataStore.cs
new file mode 100644
index 0000000..d34abe3
--- /dev/null
+++ b/OpenSim/Data/MSSQL/MSSQLDataStore.cs
@@ -0,0 +1,1622 @@
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 OpenSim 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.Data.SqlClient;
32using System.IO;
33using libsecondlife;
34using OpenSim.Framework;
35using OpenSim.Framework.Console;
36using OpenSim.Framework.Data;
37using OpenSim.Region.Environment.Interfaces;
38using OpenSim.Region.Environment.Scenes;
39using OpenSim.Framework.Data.MSSQL;
40
41namespace OpenSim.Framework.Data.MSSQL
42{
43 public class MSSQLDataStore : IRegionDataStore
44 {
45 // private static FileSystemDataStore Instance = new FileSystemDataStore();
46 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
47
48 private const string m_primSelect = "select * from prims";
49 private const string m_shapeSelect = "select * from primshapes";
50 private const string m_itemsSelect = "select * from primitems";
51 private const string m_terrainSelect = "select top 1 * from terrain";
52 private const string m_landSelect = "select * from land";
53 private const string m_landAccessListSelect = "select * from landaccesslist";
54
55 private DataSet m_dataSet;
56 private SqlDataAdapter m_primDataAdapter;
57 private SqlDataAdapter m_shapeDataAdapter;
58 private SqlDataAdapter m_itemsDataAdapter;
59 private SqlConnection m_connection;
60 private SqlDataAdapter m_terrainDataAdapter;
61 private SqlDataAdapter m_landDataAdapter;
62 private SqlDataAdapter m_landAccessListDataAdapter;
63
64 private DataTable m_primTable;
65 private DataTable m_shapeTable;
66 private DataTable m_itemsTable;
67 private DataTable m_terrainTable;
68 private DataTable m_landTable;
69 private DataTable m_landAccessListTable;
70
71 // Temporary attribute while this is experimental
72 private bool persistPrimInventories;
73
74 /***********************************************************************
75 *
76 * Public Interface Functions
77 *
78 **********************************************************************/
79
80 // see IRegionDataStore
81 public void Initialise(string connectionString, bool persistPrimInventories)
82 {
83 // Instance.Initialise("", true);
84
85 m_dataSet = new DataSet();
86 this.persistPrimInventories = persistPrimInventories;
87
88 m_log.Info("[DATASTORE]: MSSql - connecting: " + connectionString);
89 m_connection = new SqlConnection(connectionString);
90
91 SqlCommand primSelectCmd = new SqlCommand(m_primSelect, m_connection);
92 m_primDataAdapter = new SqlDataAdapter(primSelectCmd);
93
94 SqlCommand shapeSelectCmd = new SqlCommand(m_shapeSelect, m_connection);
95 m_shapeDataAdapter = new SqlDataAdapter(shapeSelectCmd);
96
97 SqlCommand itemsSelectCmd = new SqlCommand(m_itemsSelect, m_connection);
98 m_itemsDataAdapter = new SqlDataAdapter(itemsSelectCmd);
99
100 SqlCommand terrainSelectCmd = new SqlCommand(m_terrainSelect, m_connection);
101 m_terrainDataAdapter = new SqlDataAdapter(terrainSelectCmd);
102
103 SqlCommand landSelectCmd = new SqlCommand(m_landSelect, m_connection);
104 m_landDataAdapter = new SqlDataAdapter(landSelectCmd);
105
106 SqlCommand landAccessListSelectCmd = new SqlCommand(m_landAccessListSelect, m_connection);
107 m_landAccessListDataAdapter = new SqlDataAdapter(landAccessListSelectCmd);
108
109 TestTables(m_connection);
110
111 lock (m_dataSet)
112 {
113 m_primTable = createPrimTable();
114 m_dataSet.Tables.Add(m_primTable);
115 setupPrimCommands(m_primDataAdapter, m_connection);
116 m_primDataAdapter.Fill(m_primTable);
117
118 m_shapeTable = createShapeTable();
119 m_dataSet.Tables.Add(m_shapeTable);
120 setupShapeCommands(m_shapeDataAdapter, m_connection);
121 m_shapeDataAdapter.Fill(m_shapeTable);
122
123 if (persistPrimInventories)
124 {
125 m_itemsTable = createItemsTable();
126 m_dataSet.Tables.Add(m_itemsTable);
127 SetupItemsCommands(m_itemsDataAdapter, m_connection);
128 m_itemsDataAdapter.Fill(m_itemsTable);
129 }
130
131 m_terrainTable = createTerrainTable();
132 m_dataSet.Tables.Add(m_terrainTable);
133 setupTerrainCommands(m_terrainDataAdapter, m_connection);
134 m_terrainDataAdapter.Fill(m_terrainTable);
135
136 m_landTable = createLandTable();
137 m_dataSet.Tables.Add(m_landTable);
138 setupLandCommands(m_landDataAdapter, m_connection);
139 m_landDataAdapter.Fill(m_landTable);
140
141 m_landAccessListTable = createLandAccessListTable();
142 m_dataSet.Tables.Add(m_landAccessListTable);
143 setupLandAccessCommands(m_landAccessListDataAdapter, m_connection);
144 m_landAccessListDataAdapter.Fill(m_landAccessListTable);
145 }
146 }
147
148 public void StoreObject(SceneObjectGroup obj, LLUUID regionUUID)
149 {
150 // Instance.StoreObject(obj, regionUUID);
151
152 lock (m_dataSet)
153 {
154 foreach (SceneObjectPart prim in obj.Children.Values)
155 {
156 if ((prim.ObjectFlags & (uint)LLObject.ObjectFlags.Physics) == 0)
157 {
158 m_log.Info("[DATASTORE]: Adding obj: " + obj.UUID + " to region: " + regionUUID);
159 addPrim(prim, obj.UUID, regionUUID);
160 }
161 else
162 {
163 // m_log.Info("[DATASTORE]: Ignoring Physical obj: " + obj.UUID + " in region: " + regionUUID);
164 }
165 }
166 }
167
168 Commit();
169 }
170
171 public void RemoveObject(LLUUID obj, LLUUID regionUUID)
172 {
173 // Instance.RemoveObject(obj, regionUUID);
174
175 m_log.InfoFormat("[DATASTORE]: Removing obj: {0} from region: {1}", obj.UUID, regionUUID);
176
177 DataTable prims = m_primTable;
178 DataTable shapes = m_shapeTable;
179
180 string selectExp = "SceneGroupID = '" + obj.ToString() + "'";
181 lock (m_dataSet)
182 {
183 foreach (DataRow row in prims.Select(selectExp))
184 {
185 // Remove shapes row
186 LLUUID uuid = new LLUUID((string)row["UUID"]);
187
188 DataRow shapeRow = shapes.Rows.Find(uuid.UUID);
189 if (shapeRow != null)
190 {
191 shapeRow.Delete();
192 }
193
194 if (persistPrimInventories)
195 {
196 RemoveItems(new LLUUID((string)row["UUID"]));
197 }
198
199 // Remove prim row
200 row.Delete();
201 }
202 }
203
204 Commit();
205 }
206
207 /// <summary>
208 /// Remove all persisted items of the given prim.
209 /// The caller must acquire the necessrary synchronization locks and commit or rollback changes.
210 /// </summary>
211 private void RemoveItems(LLUUID uuid)
212 {
213 String sql = String.Format("primID = '{0}'", uuid);
214 DataRow[] itemRows = m_itemsTable.Select(sql);
215
216 foreach (DataRow itemRow in itemRows)
217 {
218 itemRow.Delete();
219 }
220 }
221
222 /// <summary>
223 /// Load persisted objects from region storage.
224 /// </summary>
225 public List<SceneObjectGroup> LoadObjects(LLUUID regionUUID)
226 {
227 // return Instance.LoadObjects(regionUUID);
228
229 Dictionary<LLUUID, SceneObjectGroup> createdObjects = new Dictionary<LLUUID, SceneObjectGroup>();
230
231 List<SceneObjectGroup> retvals = new List<SceneObjectGroup>();
232
233 DataTable prims = m_primTable;
234 DataTable shapes = m_shapeTable;
235
236 string byRegion = "RegionUUID = '" + regionUUID.ToString() + "'";
237 string orderByParent = "ParentID ASC";
238
239 lock (m_dataSet)
240 {
241 DataRow[] primsForRegion = prims.Select(byRegion, orderByParent);
242 m_log.Info("[DATASTORE]: " +
243 "Loaded " + primsForRegion.Length + " prims for region: " + regionUUID);
244
245 foreach (DataRow primRow in primsForRegion)
246 {
247 try
248 {
249 string uuid = (string)primRow["UUID"];
250 string objID = (string)primRow["SceneGroupID"];
251
252 SceneObjectPart prim = buildPrim(primRow);
253
254 if (uuid == objID) //is new SceneObjectGroup ?
255 {
256 SceneObjectGroup group = new SceneObjectGroup();
257
258 DataRow shapeRow = shapes.Rows.Find(prim.UUID);
259 if (shapeRow != null)
260 {
261 prim.Shape = buildShape(shapeRow);
262 }
263 else
264 {
265 m_log.Info(
266 "No shape found for prim in storage, so setting default box shape");
267 prim.Shape = PrimitiveBaseShape.Default;
268 }
269 group.AddPart(prim);
270 group.RootPart = prim;
271
272 createdObjects.Add(group.UUID, group);
273 retvals.Add(group);
274 }
275 else
276 {
277 DataRow shapeRow = shapes.Rows.Find(prim.UUID);
278 if (shapeRow != null)
279 {
280 prim.Shape = buildShape(shapeRow);
281 }
282 else
283 {
284 m_log.Info(
285 "No shape found for prim in storage, so setting default box shape");
286 prim.Shape = PrimitiveBaseShape.Default;
287 }
288 createdObjects[new LLUUID(objID)].AddPart(prim);
289 }
290
291 if (persistPrimInventories)
292 {
293 LoadItems(prim);
294 }
295 }
296 catch (Exception e)
297 {
298 m_log.Error("[DATASTORE]: Failed create prim object, exception and data follows");
299 m_log.Info("[DATASTORE]: " + e.ToString());
300 foreach (DataColumn col in prims.Columns)
301 {
302 m_log.Info("[DATASTORE]: Col: " + col.ColumnName + " => " + primRow[col]);
303 }
304 }
305 }
306 }
307 return retvals;
308 }
309
310 /// <summary>
311 /// Load in a prim's persisted inventory.
312 /// </summary>
313 /// <param name="prim"></param>
314 private void LoadItems(SceneObjectPart prim)
315 {
316 //m_log.InfoFormat("[DATASTORE]: Loading inventory for {0}, {1}", prim.Name, prim.UUID);
317
318 DataTable dbItems = m_itemsTable;
319
320 String sql = String.Format("primID = '{0}'", prim.UUID.ToString());
321 DataRow[] dbItemRows = dbItems.Select(sql);
322
323 IList<TaskInventoryItem> inventory = new List<TaskInventoryItem>();
324
325 foreach (DataRow row in dbItemRows)
326 {
327 TaskInventoryItem item = buildItem(row);
328 inventory.Add(item);
329
330 //m_log.DebugFormat("[DATASTORE]: Restored item {0}, {1}", item.Name, item.ItemID);
331 }
332
333 prim.RestoreInventoryItems(inventory);
334
335 // XXX A nasty little hack to recover the folder id for the prim (which is currently stored in
336 // every item). This data should really be stored in the prim table itself.
337 if (dbItemRows.Length > 0)
338 {
339 prim.FolderID = inventory[0].ParentID;
340 }
341 }
342
343 public void StoreTerrain(double[,] ter, LLUUID regionID)
344 {
345 int revision = Util.UnixTimeSinceEpoch();
346 m_log.Info("[DATASTORE]: Storing terrain revision r" + revision.ToString());
347
348 DataTable terrain = m_dataSet.Tables["terrain"];
349 lock (m_dataSet)
350 {
351 SqlCommand cmd = new SqlCommand("insert into terrain(RegionUUID, Revision, Heightfield)" +
352 " values(@RegionUUID, @Revision, @Heightfield)", m_connection);
353 using (cmd)
354 {
355 cmd.Parameters.Add(new SqlParameter("@RegionUUID", regionID.UUID));
356 cmd.Parameters.Add(new SqlParameter("@Revision", revision));
357 cmd.Parameters.Add(new SqlParameter("@Heightfield", serializeTerrain(ter)));
358 cmd.ExecuteNonQuery();
359 }
360 }
361 }
362
363 public double[,] LoadTerrain(LLUUID regionID)
364 {
365 double[,] terret = new double[256, 256];
366 terret.Initialize();
367
368 SqlCommand cmd = new SqlCommand(
369 @"select top 1 RegionUUID, Revision, Heightfield from terrain
370 where RegionUUID=@RegionUUID order by Revision desc"
371 , m_connection);
372
373 SqlParameter param = new SqlParameter();
374 cmd.Parameters.Add(new SqlParameter("@RegionUUID", regionID.UUID));
375
376 if (m_connection.State != ConnectionState.Open)
377 {
378 m_connection.Open();
379 }
380
381 using (SqlDataReader row = cmd.ExecuteReader())
382 {
383 int rev = 0;
384 if (row.Read())
385 {
386 MemoryStream str = new MemoryStream((byte[])row["Heightfield"]);
387 BinaryReader br = new BinaryReader(str);
388 for (int x = 0; x < 256; x++)
389 {
390 for (int y = 0; y < 256; y++)
391 {
392 terret[x, y] = br.ReadDouble();
393 }
394 }
395 rev = (int)row["Revision"];
396 }
397 else
398 {
399 m_log.Info("[DATASTORE]: No terrain found for region");
400 return null;
401 }
402
403 m_log.Info("[DATASTORE]: Loaded terrain revision r" + rev.ToString());
404 }
405
406 return terret;
407 }
408
409 public void RemoveLandObject(LLUUID globalID)
410 {
411 // Instance.RemoveLandObject(globalID);
412
413 lock (m_dataSet)
414 {
415 using (SqlCommand cmd = new SqlCommand("delete from land where UUID=@UUID", m_connection))
416 {
417 cmd.Parameters.Add(new SqlParameter("@UUID", globalID.UUID));
418 cmd.ExecuteNonQuery();
419 }
420
421 using (
422 SqlCommand cmd = new SqlCommand("delete from landaccesslist where LandUUID=@UUID", m_connection)
423 )
424 {
425 cmd.Parameters.Add(new SqlParameter("@UUID", globalID.UUID));
426 cmd.ExecuteNonQuery();
427 }
428 }
429 }
430
431 public void StoreLandObject(ILandObject parcel)
432 {
433 // Instance.StoreLandObject(parcel, regionUUID);
434
435 // Does the new locking fix it?
436 // m_log.Info("[DATASTORE]: Tedds temp fix: Waiting 3 seconds to avoid others writing to table while we hold a dataset of it. (Someone please fix! :))");
437 // System.Threading.Thread.Sleep(2500 + rnd.Next(0, 1000));
438
439 lock (m_dataSet)
440 {
441 DataTable land = m_landTable;
442 DataTable landaccesslist = m_landAccessListTable;
443
444 DataRow landRow = land.Rows.Find(parcel.landData.globalID.UUID);
445 if (landRow == null)
446 {
447 landRow = land.NewRow();
448 fillLandRow(landRow, parcel.landData, parcel.regionUUID);
449 land.Rows.Add(landRow);
450 }
451 else
452 {
453 fillLandRow(landRow, parcel.landData, parcel.regionUUID);
454 }
455
456 using (
457 SqlCommand cmd =
458 new SqlCommand("delete from landaccesslist where LandUUID=@LandUUID", m_connection))
459 {
460 cmd.Parameters.Add(new SqlParameter("@LandUUID", parcel.landData.globalID.UUID));
461 cmd.ExecuteNonQuery();
462 }
463
464 foreach (ParcelManager.ParcelAccessEntry entry in parcel.landData.parcelAccessList)
465 {
466 DataRow newAccessRow = landaccesslist.NewRow();
467 fillLandAccessRow(newAccessRow, entry, parcel.landData.globalID);
468 landaccesslist.Rows.Add(newAccessRow);
469 }
470
471 }
472 Commit();
473 }
474
475 public List<LandData> LoadLandObjects(LLUUID regionUUID)
476 {
477 List<LandData> landDataForRegion = new List<LandData>();
478 lock (m_dataSet)
479 {
480 DataTable land = m_landTable;
481 DataTable landaccesslist = m_landAccessListTable;
482 string searchExp = "RegionUUID = '" + regionUUID.UUID + "'";
483 DataRow[] rawDataForRegion = land.Select(searchExp);
484 foreach (DataRow rawDataLand in rawDataForRegion)
485 {
486 LandData newLand = buildLandData(rawDataLand);
487 string accessListSearchExp = "LandUUID = '" + newLand.globalID.UUID + "'";
488 DataRow[] rawDataForLandAccessList = landaccesslist.Select(accessListSearchExp);
489 foreach (DataRow rawDataLandAccess in rawDataForLandAccessList)
490 {
491 newLand.parcelAccessList.Add(buildLandAccessData(rawDataLandAccess));
492 }
493
494 landDataForRegion.Add(newLand);
495 }
496 }
497 return landDataForRegion;
498 }
499
500 public void Commit()
501 {
502 if (m_connection.State != ConnectionState.Open)
503 {
504 m_connection.Open();
505 }
506
507 lock (m_dataSet)
508 {
509 // DisplayDataSet(m_dataSet, "Region DataSet");
510
511 m_primDataAdapter.Update(m_primTable);
512 m_shapeDataAdapter.Update(m_shapeTable);
513
514 if (persistPrimInventories)
515 {
516 m_itemsDataAdapter.Update(m_itemsTable);
517 }
518
519 m_terrainDataAdapter.Update(m_terrainTable);
520 m_landDataAdapter.Update(m_landTable);
521 m_landAccessListDataAdapter.Update(m_landAccessListTable);
522
523 m_dataSet.AcceptChanges();
524 }
525 }
526
527 public void Shutdown()
528 {
529 Commit();
530 }
531
532 /***********************************************************************
533 *
534 * Database Definition Functions
535 *
536 * This should be db agnostic as we define them in ADO.NET terms
537 *
538 **********************************************************************/
539
540 private DataColumn createCol(DataTable dt, string name, Type type)
541 {
542 DataColumn col = new DataColumn(name, type);
543 dt.Columns.Add(col);
544 return col;
545 }
546
547 private DataTable createTerrainTable()
548 {
549 DataTable terrain = new DataTable("terrain");
550
551 createCol(terrain, "RegionUUID", typeof(String));
552 createCol(terrain, "Revision", typeof(Int32));
553 createCol(terrain, "Heightfield", typeof(Byte[]));
554
555 return terrain;
556 }
557
558 private DataTable createPrimTable()
559 {
560 DataTable prims = new DataTable("prims");
561
562 createCol(prims, "UUID", typeof(String));
563 createCol(prims, "RegionUUID", typeof(String));
564 createCol(prims, "ParentID", typeof(Int32));
565 createCol(prims, "CreationDate", typeof(Int32));
566 createCol(prims, "Name", typeof(String));
567 createCol(prims, "SceneGroupID", typeof(String));
568 // various text fields
569 createCol(prims, "Text", typeof(String));
570 createCol(prims, "Description", typeof(String));
571 createCol(prims, "SitName", typeof(String));
572 createCol(prims, "TouchName", typeof(String));
573 // permissions
574 createCol(prims, "ObjectFlags", typeof(Int32));
575 createCol(prims, "CreatorID", typeof(String));
576 createCol(prims, "OwnerID", typeof(String));
577 createCol(prims, "GroupID", typeof(String));
578 createCol(prims, "LastOwnerID", typeof(String));
579 createCol(prims, "OwnerMask", typeof(Int32));
580 createCol(prims, "NextOwnerMask", typeof(Int32));
581 createCol(prims, "GroupMask", typeof(Int32));
582 createCol(prims, "EveryoneMask", typeof(Int32));
583 createCol(prims, "BaseMask", typeof(Int32));
584 // vectors
585 createCol(prims, "PositionX", typeof(Double));
586 createCol(prims, "PositionY", typeof(Double));
587 createCol(prims, "PositionZ", typeof(Double));
588 createCol(prims, "GroupPositionX", typeof(Double));
589 createCol(prims, "GroupPositionY", typeof(Double));
590 createCol(prims, "GroupPositionZ", typeof(Double));
591 createCol(prims, "VelocityX", typeof(Double));
592 createCol(prims, "VelocityY", typeof(Double));
593 createCol(prims, "VelocityZ", typeof(Double));
594 createCol(prims, "AngularVelocityX", typeof(Double));
595 createCol(prims, "AngularVelocityY", typeof(Double));
596 createCol(prims, "AngularVelocityZ", typeof(Double));
597 createCol(prims, "AccelerationX", typeof(Double));
598 createCol(prims, "AccelerationY", typeof(Double));
599 createCol(prims, "AccelerationZ", typeof(Double));
600 // quaternions
601 createCol(prims, "RotationX", typeof(Double));
602 createCol(prims, "RotationY", typeof(Double));
603 createCol(prims, "RotationZ", typeof(Double));
604 createCol(prims, "RotationW", typeof(Double));
605
606 // sit target
607 createCol(prims, "SitTargetOffsetX", typeof(Double));
608 createCol(prims, "SitTargetOffsetY", typeof(Double));
609 createCol(prims, "SitTargetOffsetZ", typeof(Double));
610
611 createCol(prims, "SitTargetOrientW", typeof(Double));
612 createCol(prims, "SitTargetOrientX", typeof(Double));
613 createCol(prims, "SitTargetOrientY", typeof(Double));
614 createCol(prims, "SitTargetOrientZ", typeof(Double));
615
616 // Add in contraints
617 prims.PrimaryKey = new DataColumn[] { prims.Columns["UUID"] };
618
619 return prims;
620 }
621
622 private DataTable createLandTable()
623 {
624 DataTable land = new DataTable("land");
625 createCol(land, "UUID", typeof(String));
626 createCol(land, "RegionUUID", typeof(String));
627 createCol(land, "LocalLandID", typeof(Int32));
628
629 // Bitmap is a byte[512]
630 createCol(land, "Bitmap", typeof(Byte[]));
631
632 createCol(land, "Name", typeof(String));
633 createCol(land, "Description", typeof(String));
634 createCol(land, "OwnerUUID", typeof(String));
635 createCol(land, "IsGroupOwned", typeof(Int32));
636 createCol(land, "Area", typeof(Int32));
637 createCol(land, "AuctionID", typeof(Int32)); //Unemplemented
638 createCol(land, "Category", typeof(Int32)); //Enum libsecondlife.Parcel.ParcelCategory
639 createCol(land, "ClaimDate", typeof(Int32));
640 createCol(land, "ClaimPrice", typeof(Int32));
641 createCol(land, "GroupUUID", typeof(String));
642 createCol(land, "SalePrice", typeof(Int32));
643 createCol(land, "LandStatus", typeof(Int32)); //Enum. libsecondlife.Parcel.ParcelStatus
644 createCol(land, "LandFlags", typeof(Int32));
645 createCol(land, "LandingType", typeof(Int32));
646 createCol(land, "MediaAutoScale", typeof(Int32));
647 createCol(land, "MediaTextureUUID", typeof(String));
648 createCol(land, "MediaURL", typeof(String));
649 createCol(land, "MusicURL", typeof(String));
650 createCol(land, "PassHours", typeof(Double));
651 createCol(land, "PassPrice", typeof(Int32));
652 createCol(land, "SnapshotUUID", typeof(String));
653 createCol(land, "UserLocationX", typeof(Double));
654 createCol(land, "UserLocationY", typeof(Double));
655 createCol(land, "UserLocationZ", typeof(Double));
656 createCol(land, "UserLookAtX", typeof(Double));
657 createCol(land, "UserLookAtY", typeof(Double));
658 createCol(land, "UserLookAtZ", typeof(Double));
659
660 land.PrimaryKey = new DataColumn[] { land.Columns["UUID"] };
661
662 return land;
663 }
664
665 private DataTable createLandAccessListTable()
666 {
667 DataTable landaccess = new DataTable("landaccesslist");
668 createCol(landaccess, "LandUUID", typeof(String));
669 createCol(landaccess, "AccessUUID", typeof(String));
670 createCol(landaccess, "Flags", typeof(Int32));
671
672 return landaccess;
673 }
674
675 private DataTable createShapeTable()
676 {
677 DataTable shapes = new DataTable("primshapes");
678 createCol(shapes, "UUID", typeof(String));
679 // shape is an enum
680 createCol(shapes, "Shape", typeof(Int32));
681 // vectors
682 createCol(shapes, "ScaleX", typeof(Double));
683 createCol(shapes, "ScaleY", typeof(Double));
684 createCol(shapes, "ScaleZ", typeof(Double));
685 // paths
686 createCol(shapes, "PCode", typeof(Int32));
687 createCol(shapes, "PathBegin", typeof(Int32));
688 createCol(shapes, "PathEnd", typeof(Int32));
689 createCol(shapes, "PathScaleX", typeof(Int32));
690 createCol(shapes, "PathScaleY", typeof(Int32));
691 createCol(shapes, "PathShearX", typeof(Int32));
692 createCol(shapes, "PathShearY", typeof(Int32));
693 createCol(shapes, "PathSkew", typeof(Int32));
694 createCol(shapes, "PathCurve", typeof(Int32));
695 createCol(shapes, "PathRadiusOffset", typeof(Int32));
696 createCol(shapes, "PathRevolutions", typeof(Int32));
697 createCol(shapes, "PathTaperX", typeof(Int32));
698 createCol(shapes, "PathTaperY", typeof(Int32));
699 createCol(shapes, "PathTwist", typeof(Int32));
700 createCol(shapes, "PathTwistBegin", typeof(Int32));
701 // profile
702 createCol(shapes, "ProfileBegin", typeof(Int32));
703 createCol(shapes, "ProfileEnd", typeof(Int32));
704 createCol(shapes, "ProfileCurve", typeof(Int32));
705 createCol(shapes, "ProfileHollow", typeof(Int32));
706 createCol(shapes, "State", typeof(Int32));
707 // text TODO: this isn't right, but I'm not sure the right
708 // way to specify this as a blob atm
709 createCol(shapes, "Texture", typeof(Byte[]));
710 createCol(shapes, "ExtraParams", typeof(Byte[]));
711
712 shapes.PrimaryKey = new DataColumn[] { shapes.Columns["UUID"] };
713
714 return shapes;
715 }
716
717 private DataTable createItemsTable()
718 {
719 DataTable items = new DataTable("primitems");
720
721 createCol(items, "itemID", typeof(String));
722 createCol(items, "primID", typeof(String));
723 createCol(items, "assetID", typeof(String));
724 createCol(items, "parentFolderID", typeof(String));
725
726 createCol(items, "invType", typeof(Int32));
727 createCol(items, "assetType", typeof(Int32));
728
729 createCol(items, "name", typeof(String));
730 createCol(items, "description", typeof(String));
731
732 createCol(items, "creationDate", typeof(Int64));
733 createCol(items, "creatorID", typeof(String));
734 createCol(items, "ownerID", typeof(String));
735 createCol(items, "lastOwnerID", typeof(String));
736 createCol(items, "groupID", typeof(String));
737
738 createCol(items, "nextPermissions", typeof(Int32));
739 createCol(items, "currentPermissions", typeof(Int32));
740 createCol(items, "basePermissions", typeof(Int32));
741 createCol(items, "everyonePermissions", typeof(Int32));
742 createCol(items, "groupPermissions", typeof(Int32));
743
744 items.PrimaryKey = new DataColumn[] { items.Columns["itemID"] };
745
746 return items;
747 }
748
749 /***********************************************************************
750 *
751 * Convert between ADO.NET <=> OpenSim Objects
752 *
753 * These should be database independant
754 *
755 **********************************************************************/
756
757 private SceneObjectPart buildPrim(DataRow row)
758 {
759 SceneObjectPart prim = new SceneObjectPart();
760 prim.UUID = new LLUUID((String)row["UUID"]);
761 // explicit conversion of integers is required, which sort
762 // of sucks. No idea if there is a shortcut here or not.
763 prim.ParentID = Convert.ToUInt32(row["ParentID"]);
764 prim.CreationDate = Convert.ToInt32(row["CreationDate"]);
765 prim.Name = (String)row["Name"];
766 // various text fields
767 prim.Text = (String)row["Text"];
768 prim.Description = (String)row["Description"];
769 prim.SitName = (String)row["SitName"];
770 prim.TouchName = (String)row["TouchName"];
771 // permissions
772 prim.ObjectFlags = Convert.ToUInt32(row["ObjectFlags"]);
773 prim.CreatorID = new LLUUID((String)row["CreatorID"]);
774 prim.OwnerID = new LLUUID((String)row["OwnerID"]);
775 prim.GroupID = new LLUUID((String)row["GroupID"]);
776 prim.LastOwnerID = new LLUUID((String)row["LastOwnerID"]);
777 prim.OwnerMask = Convert.ToUInt32(row["OwnerMask"]);
778 prim.NextOwnerMask = Convert.ToUInt32(row["NextOwnerMask"]);
779 prim.GroupMask = Convert.ToUInt32(row["GroupMask"]);
780 prim.EveryoneMask = Convert.ToUInt32(row["EveryoneMask"]);
781 prim.BaseMask = Convert.ToUInt32(row["BaseMask"]);
782 // vectors
783 prim.OffsetPosition = new LLVector3(
784 Convert.ToSingle(row["PositionX"]),
785 Convert.ToSingle(row["PositionY"]),
786 Convert.ToSingle(row["PositionZ"])
787 );
788 prim.GroupPosition = new LLVector3(
789 Convert.ToSingle(row["GroupPositionX"]),
790 Convert.ToSingle(row["GroupPositionY"]),
791 Convert.ToSingle(row["GroupPositionZ"])
792 );
793 prim.Velocity = new LLVector3(
794 Convert.ToSingle(row["VelocityX"]),
795 Convert.ToSingle(row["VelocityY"]),
796 Convert.ToSingle(row["VelocityZ"])
797 );
798 prim.AngularVelocity = new LLVector3(
799 Convert.ToSingle(row["AngularVelocityX"]),
800 Convert.ToSingle(row["AngularVelocityY"]),
801 Convert.ToSingle(row["AngularVelocityZ"])
802 );
803 prim.Acceleration = new LLVector3(
804 Convert.ToSingle(row["AccelerationX"]),
805 Convert.ToSingle(row["AccelerationY"]),
806 Convert.ToSingle(row["AccelerationZ"])
807 );
808 // quaternions
809 prim.RotationOffset = new LLQuaternion(
810 Convert.ToSingle(row["RotationX"]),
811 Convert.ToSingle(row["RotationY"]),
812 Convert.ToSingle(row["RotationZ"]),
813 Convert.ToSingle(row["RotationW"])
814 );
815 try
816 {
817 prim.SetSitTargetLL(new LLVector3(
818 Convert.ToSingle(row["SitTargetOffsetX"]),
819 Convert.ToSingle(row["SitTargetOffsetY"]),
820 Convert.ToSingle(row["SitTargetOffsetZ"])), new LLQuaternion(
821 Convert.ToSingle(
822 row["SitTargetOrientX"]),
823 Convert.ToSingle(
824 row["SitTargetOrientY"]),
825 Convert.ToSingle(
826 row["SitTargetOrientZ"]),
827 Convert.ToSingle(
828 row["SitTargetOrientW"])));
829 }
830 catch (InvalidCastException)
831 {
832 // Database table was created before we got here and now has null values :P
833
834 using (
835 SqlCommand cmd =
836 new SqlCommand(
837 "ALTER TABLE [prims] ADD COLUMN [SitTargetOffsetX] float NOT NULL default 0, ADD COLUMN [SitTargetOffsetY] float NOT NULL default 0, ADD COLUMN [SitTargetOffsetZ] float NOT NULL default 0, ADD COLUMN [SitTargetOrientW] float NOT NULL default 0, ADD COLUMN [SitTargetOrientX] float NOT NULL default 0, ADD COLUMN [SitTargetOrientY] float NOT NULL default 0, ADD COLUMN [SitTargetOrientZ] float NOT NULL default 0;",
838 m_connection))
839 {
840 cmd.ExecuteNonQuery();
841 }
842 }
843
844 return prim;
845 }
846
847 /// <summary>
848 /// Build a prim inventory item from the persisted data.
849 /// </summary>
850 /// <param name="row"></param>
851 /// <returns></returns>
852 private TaskInventoryItem buildItem(DataRow row)
853 {
854 TaskInventoryItem taskItem = new TaskInventoryItem();
855
856 taskItem.ItemID = new LLUUID((String)row["itemID"]);
857 taskItem.ParentPartID = new LLUUID((String)row["primID"]);
858 taskItem.AssetID = new LLUUID((String)row["assetID"]);
859 taskItem.ParentID = new LLUUID((String)row["parentFolderID"]);
860
861 taskItem.InvType = Convert.ToInt32(row["invType"]);
862 taskItem.Type = Convert.ToInt32(row["assetType"]);
863
864 taskItem.Name = (String)row["name"];
865 taskItem.Description = (String)row["description"];
866 taskItem.CreationDate = Convert.ToUInt32(row["creationDate"]);
867 taskItem.CreatorID = new LLUUID((String)row["creatorID"]);
868 taskItem.OwnerID = new LLUUID((String)row["ownerID"]);
869 taskItem.LastOwnerID = new LLUUID((String)row["lastOwnerID"]);
870 taskItem.GroupID = new LLUUID((String)row["groupID"]);
871
872 taskItem.NextOwnerMask = Convert.ToUInt32(row["nextPermissions"]);
873 taskItem.OwnerMask = Convert.ToUInt32(row["currentPermissions"]);
874 taskItem.BaseMask = Convert.ToUInt32(row["basePermissions"]);
875 taskItem.EveryoneMask = Convert.ToUInt32(row["everyonePermissions"]);
876 taskItem.GroupMask = Convert.ToUInt32(row["groupPermissions"]);
877
878 return taskItem;
879 }
880
881 private LandData buildLandData(DataRow row)
882 {
883 LandData newData = new LandData();
884
885 newData.globalID = new LLUUID((String)row["UUID"]);
886 newData.localID = Convert.ToInt32(row["LocalLandID"]);
887
888 // Bitmap is a byte[512]
889 newData.landBitmapByteArray = (Byte[])row["Bitmap"];
890
891 newData.landName = (String)row["Name"];
892 newData.landDesc = (String)row["Description"];
893 newData.ownerID = (String)row["OwnerUUID"];
894 newData.isGroupOwned = Convert.ToBoolean(row["IsGroupOwned"]);
895 newData.area = Convert.ToInt32(row["Area"]);
896 newData.auctionID = Convert.ToUInt32(row["AuctionID"]); //Unemplemented
897 newData.category = (Parcel.ParcelCategory)Convert.ToInt32(row["Category"]);
898 //Enum libsecondlife.Parcel.ParcelCategory
899 newData.claimDate = Convert.ToInt32(row["ClaimDate"]);
900 newData.claimPrice = Convert.ToInt32(row["ClaimPrice"]);
901 newData.groupID = new LLUUID((String)row["GroupUUID"]);
902 newData.salePrice = Convert.ToInt32(row["SalePrice"]);
903 newData.landStatus = (Parcel.ParcelStatus)Convert.ToInt32(row["LandStatus"]);
904 //Enum. libsecondlife.Parcel.ParcelStatus
905 newData.landFlags = Convert.ToUInt32(row["LandFlags"]);
906 newData.landingType = Convert.ToByte(row["LandingType"]);
907 newData.mediaAutoScale = Convert.ToByte(row["MediaAutoScale"]);
908 newData.mediaID = new LLUUID((String)row["MediaTextureUUID"]);
909 newData.mediaURL = (String)row["MediaURL"];
910 newData.musicURL = (String)row["MusicURL"];
911 newData.passHours = Convert.ToSingle(row["PassHours"]);
912 newData.passPrice = Convert.ToInt32(row["PassPrice"]);
913 newData.snapshotID = (String)row["SnapshotUUID"];
914
915 newData.userLocation =
916 new LLVector3(Convert.ToSingle(row["UserLocationX"]), Convert.ToSingle(row["UserLocationY"]),
917 Convert.ToSingle(row["UserLocationZ"]));
918 newData.userLookAt =
919 new LLVector3(Convert.ToSingle(row["UserLookAtX"]), Convert.ToSingle(row["UserLookAtY"]),
920 Convert.ToSingle(row["UserLookAtZ"]));
921 newData.parcelAccessList = new List<ParcelManager.ParcelAccessEntry>();
922
923 return newData;
924 }
925
926 private ParcelManager.ParcelAccessEntry buildLandAccessData(DataRow row)
927 {
928 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
929 entry.AgentID = new LLUUID((string)row["AccessUUID"]);
930 entry.Flags = (ParcelManager.AccessList)Convert.ToInt32(row["Flags"]);
931 entry.Time = new DateTime();
932 return entry;
933 }
934
935 private Array serializeTerrain(double[,] val)
936 {
937 MemoryStream str = new MemoryStream(65536 * sizeof(double));
938 BinaryWriter bw = new BinaryWriter(str);
939
940 // TODO: COMPATIBILITY - Add byte-order conversions
941 for (int x = 0; x < 256; x++)
942 for (int y = 0; y < 256; y++)
943 bw.Write(val[x, y]);
944
945 return str.ToArray();
946 }
947
948 private void fillPrimRow(DataRow row, SceneObjectPart prim, LLUUID sceneGroupID, LLUUID regionUUID)
949 {
950 row["UUID"] = prim.UUID;
951 row["RegionUUID"] = regionUUID;
952 row["ParentID"] = prim.ParentID;
953 row["CreationDate"] = prim.CreationDate;
954 row["Name"] = prim.Name;
955 row["SceneGroupID"] = sceneGroupID;
956 // the UUID of the root part for this SceneObjectGroup
957 // various text fields
958 row["Text"] = prim.Text;
959 row["Description"] = prim.Description;
960 row["SitName"] = prim.SitName;
961 row["TouchName"] = prim.TouchName;
962 // permissions
963 row["ObjectFlags"] = prim.ObjectFlags;
964 row["CreatorID"] = prim.CreatorID;
965 row["OwnerID"] = prim.OwnerID;
966 row["GroupID"] = prim.GroupID;
967 row["LastOwnerID"] = prim.LastOwnerID;
968 row["OwnerMask"] = prim.OwnerMask;
969 row["NextOwnerMask"] = prim.NextOwnerMask;
970 row["GroupMask"] = prim.GroupMask;
971 row["EveryoneMask"] = prim.EveryoneMask;
972 row["BaseMask"] = prim.BaseMask;
973 // vectors
974 row["PositionX"] = prim.OffsetPosition.X;
975 row["PositionY"] = prim.OffsetPosition.Y;
976 row["PositionZ"] = prim.OffsetPosition.Z;
977 row["GroupPositionX"] = prim.GroupPosition.X;
978 row["GroupPositionY"] = prim.GroupPosition.Y;
979 row["GroupPositionZ"] = prim.GroupPosition.Z;
980 row["VelocityX"] = prim.Velocity.X;
981 row["VelocityY"] = prim.Velocity.Y;
982 row["VelocityZ"] = prim.Velocity.Z;
983 row["AngularVelocityX"] = prim.AngularVelocity.X;
984 row["AngularVelocityY"] = prim.AngularVelocity.Y;
985 row["AngularVelocityZ"] = prim.AngularVelocity.Z;
986 row["AccelerationX"] = prim.Acceleration.X;
987 row["AccelerationY"] = prim.Acceleration.Y;
988 row["AccelerationZ"] = prim.Acceleration.Z;
989 // quaternions
990 row["RotationX"] = prim.RotationOffset.X;
991 row["RotationY"] = prim.RotationOffset.Y;
992 row["RotationZ"] = prim.RotationOffset.Z;
993 row["RotationW"] = prim.RotationOffset.W;
994
995 try
996 {
997 // Sit target
998 LLVector3 sitTargetPos = prim.GetSitTargetPositionLL();
999 row["SitTargetOffsetX"] = sitTargetPos.X;
1000 row["SitTargetOffsetY"] = sitTargetPos.Y;
1001 row["SitTargetOffsetZ"] = sitTargetPos.Z;
1002
1003 LLQuaternion sitTargetOrient = prim.GetSitTargetOrientationLL();
1004 row["SitTargetOrientW"] = sitTargetOrient.W;
1005 row["SitTargetOrientX"] = sitTargetOrient.X;
1006 row["SitTargetOrientY"] = sitTargetOrient.Y;
1007 row["SitTargetOrientZ"] = sitTargetOrient.Z;
1008 }
1009 catch (Exception)
1010 {
1011 // Database table was created before we got here and needs to be created! :P
1012
1013 using (
1014 SqlCommand cmd =
1015 new SqlCommand(
1016 "ALTER TABLE [prims] ADD COLUMN [SitTargetOffsetX] float NOT NULL default 0, ADD COLUMN [SitTargetOffsetY] float NOT NULL default 0, ADD COLUMN [SitTargetOffsetZ] float NOT NULL default 0, ADD COLUMN [SitTargetOrientW] float NOT NULL default 0, ADD COLUMN [SitTargetOrientX] float NOT NULL default 0, ADD COLUMN [SitTargetOrientY] float NOT NULL default 0, ADD COLUMN [SitTargetOrientZ] float NOT NULL default 0;",
1017 m_connection))
1018 {
1019 cmd.ExecuteNonQuery();
1020 }
1021 }
1022 }
1023
1024 private void fillItemRow(DataRow row, TaskInventoryItem taskItem)
1025 {
1026 row["itemID"] = taskItem.ItemID;
1027 row["primID"] = taskItem.ParentPartID;
1028 row["assetID"] = taskItem.AssetID;
1029 row["parentFolderID"] = taskItem.ParentID;
1030
1031 row["invType"] = taskItem.InvType;
1032 row["assetType"] = taskItem.Type;
1033
1034 row["name"] = taskItem.Name;
1035 row["description"] = taskItem.Description;
1036 row["creationDate"] = taskItem.CreationDate;
1037 row["creatorID"] = taskItem.CreatorID;
1038 row["ownerID"] = taskItem.OwnerID;
1039 row["lastOwnerID"] = taskItem.LastOwnerID;
1040 row["groupID"] = taskItem.GroupID;
1041 row["nextPermissions"] = taskItem.NextOwnerMask;
1042 row["currentPermissions"] = taskItem.OwnerMask;
1043 row["basePermissions"] = taskItem.BaseMask;
1044 row["everyonePermissions"] = taskItem.EveryoneMask;
1045 row["groupPermissions"] = taskItem.GroupMask;
1046 }
1047
1048 private void fillLandRow(DataRow row, LandData land, LLUUID regionUUID)
1049 {
1050 row["UUID"] = land.globalID.UUID;
1051 row["RegionUUID"] = regionUUID.UUID;
1052 row["LocalLandID"] = land.localID;
1053
1054 // Bitmap is a byte[512]
1055 row["Bitmap"] = land.landBitmapByteArray;
1056
1057 row["Name"] = land.landName;
1058 row["Description"] = land.landDesc;
1059 row["OwnerUUID"] = land.ownerID.UUID;
1060 row["IsGroupOwned"] = land.isGroupOwned;
1061 row["Area"] = land.area;
1062 row["AuctionID"] = land.auctionID; //Unemplemented
1063 row["Category"] = land.category; //Enum libsecondlife.Parcel.ParcelCategory
1064 row["ClaimDate"] = land.claimDate;
1065 row["ClaimPrice"] = land.claimPrice;
1066 row["GroupUUID"] = land.groupID.UUID;
1067 row["SalePrice"] = land.salePrice;
1068 row["LandStatus"] = land.landStatus; //Enum. libsecondlife.Parcel.ParcelStatus
1069 row["LandFlags"] = land.landFlags;
1070 row["LandingType"] = land.landingType;
1071 row["MediaAutoScale"] = land.mediaAutoScale;
1072 row["MediaTextureUUID"] = land.mediaID.UUID;
1073 row["MediaURL"] = land.mediaURL;
1074 row["MusicURL"] = land.musicURL;
1075 row["PassHours"] = land.passHours;
1076 row["PassPrice"] = land.passPrice;
1077 row["SnapshotUUID"] = land.snapshotID.UUID;
1078 row["UserLocationX"] = land.userLocation.X;
1079 row["UserLocationY"] = land.userLocation.Y;
1080 row["UserLocationZ"] = land.userLocation.Z;
1081 row["UserLookAtX"] = land.userLookAt.X;
1082 row["UserLookAtY"] = land.userLookAt.Y;
1083 row["UserLookAtZ"] = land.userLookAt.Z;
1084 }
1085
1086 private void fillLandAccessRow(DataRow row, ParcelManager.ParcelAccessEntry entry, LLUUID parcelID)
1087 {
1088 row["LandUUID"] = parcelID.UUID;
1089 row["AccessUUID"] = entry.AgentID.UUID;
1090 row["Flags"] = entry.Flags;
1091 }
1092
1093 private PrimitiveBaseShape buildShape(DataRow row)
1094 {
1095 PrimitiveBaseShape s = new PrimitiveBaseShape();
1096 s.Scale = new LLVector3(
1097 Convert.ToSingle(row["ScaleX"]),
1098 Convert.ToSingle(row["ScaleY"]),
1099 Convert.ToSingle(row["ScaleZ"])
1100 );
1101 // paths
1102 s.PCode = Convert.ToByte(row["PCode"]);
1103 s.PathBegin = Convert.ToUInt16(row["PathBegin"]);
1104 s.PathEnd = Convert.ToUInt16(row["PathEnd"]);
1105 s.PathScaleX = Convert.ToByte(row["PathScaleX"]);
1106 s.PathScaleY = Convert.ToByte(row["PathScaleY"]);
1107 s.PathShearX = Convert.ToByte(row["PathShearX"]);
1108 s.PathShearY = Convert.ToByte(row["PathShearY"]);
1109 s.PathSkew = Convert.ToSByte(row["PathSkew"]);
1110 s.PathCurve = Convert.ToByte(row["PathCurve"]);
1111 s.PathRadiusOffset = Convert.ToSByte(row["PathRadiusOffset"]);
1112 s.PathRevolutions = Convert.ToByte(row["PathRevolutions"]);
1113 s.PathTaperX = Convert.ToSByte(row["PathTaperX"]);
1114 s.PathTaperY = Convert.ToSByte(row["PathTaperY"]);
1115 s.PathTwist = Convert.ToSByte(row["PathTwist"]);
1116 s.PathTwistBegin = Convert.ToSByte(row["PathTwistBegin"]);
1117 // profile
1118 s.ProfileBegin = Convert.ToUInt16(row["ProfileBegin"]);
1119 s.ProfileEnd = Convert.ToUInt16(row["ProfileEnd"]);
1120 s.ProfileCurve = Convert.ToByte(row["ProfileCurve"]);
1121 s.ProfileHollow = Convert.ToUInt16(row["ProfileHollow"]);
1122 s.State = Convert.ToByte(row["State"]);
1123
1124 byte[] textureEntry = (byte[])row["Texture"];
1125 s.TextureEntry = textureEntry;
1126
1127 s.ExtraParams = (byte[])row["ExtraParams"];
1128
1129 return s;
1130 }
1131
1132 private void fillShapeRow(DataRow row, SceneObjectPart prim)
1133 {
1134 PrimitiveBaseShape s = prim.Shape;
1135 row["UUID"] = prim.UUID;
1136 // shape is an enum
1137 row["Shape"] = 0;
1138 // vectors
1139 row["ScaleX"] = s.Scale.X;
1140 row["ScaleY"] = s.Scale.Y;
1141 row["ScaleZ"] = s.Scale.Z;
1142 // paths
1143 row["PCode"] = s.PCode;
1144 row["PathBegin"] = s.PathBegin;
1145 row["PathEnd"] = s.PathEnd;
1146 row["PathScaleX"] = s.PathScaleX;
1147 row["PathScaleY"] = s.PathScaleY;
1148 row["PathShearX"] = s.PathShearX;
1149 row["PathShearY"] = s.PathShearY;
1150 row["PathSkew"] = s.PathSkew;
1151 row["PathCurve"] = s.PathCurve;
1152 row["PathRadiusOffset"] = s.PathRadiusOffset;
1153 row["PathRevolutions"] = s.PathRevolutions;
1154 row["PathTaperX"] = s.PathTaperX;
1155 row["PathTaperY"] = s.PathTaperY;
1156 row["PathTwist"] = s.PathTwist;
1157 row["PathTwistBegin"] = s.PathTwistBegin;
1158 // profile
1159 row["ProfileBegin"] = s.ProfileBegin;
1160 row["ProfileEnd"] = s.ProfileEnd;
1161 row["ProfileCurve"] = s.ProfileCurve;
1162 row["ProfileHollow"] = s.ProfileHollow;
1163 row["State"] = s.State;
1164 row["Texture"] = s.TextureEntry;
1165 row["ExtraParams"] = s.ExtraParams;
1166 }
1167
1168 private void addPrim(SceneObjectPart prim, LLUUID sceneGroupID, LLUUID regionUUID)
1169 {
1170 DataTable prims = m_dataSet.Tables["prims"];
1171 DataTable shapes = m_dataSet.Tables["primshapes"];
1172
1173 DataRow primRow = prims.Rows.Find(prim.UUID);
1174 if (primRow == null)
1175 {
1176 primRow = prims.NewRow();
1177 fillPrimRow(primRow, prim, sceneGroupID, regionUUID);
1178 prims.Rows.Add(primRow);
1179 }
1180 else
1181 {
1182 fillPrimRow(primRow, prim, sceneGroupID, regionUUID);
1183 }
1184
1185 DataRow shapeRow = shapes.Rows.Find(prim.UUID);
1186 if (shapeRow == null)
1187 {
1188 shapeRow = shapes.NewRow();
1189 fillShapeRow(shapeRow, prim);
1190 shapes.Rows.Add(shapeRow);
1191 }
1192 else
1193 {
1194 fillShapeRow(shapeRow, prim);
1195 }
1196 }
1197
1198 // see IRegionDatastore
1199 public void StorePrimInventory(LLUUID primID, ICollection<TaskInventoryItem> items)
1200 {
1201 if (!persistPrimInventories)
1202 return;
1203
1204 m_log.InfoFormat("[DATASTORE]: Persisting Prim Inventory with prim ID {0}", primID);
1205
1206 // For now, we're just going to crudely remove all the previous inventory items
1207 // no matter whether they have changed or not, and replace them with the current set.
1208 lock (m_dataSet)
1209 {
1210 RemoveItems(primID);
1211
1212 // repalce with current inventory details
1213 foreach (TaskInventoryItem newItem in items)
1214 {
1215 // m_log.InfoFormat(
1216 // "[DATASTORE]: " +
1217 // "Adding item {0}, {1} to prim ID {2}",
1218 // newItem.Name, newItem.ItemID, newItem.ParentPartID);
1219
1220 DataRow newItemRow = m_itemsTable.NewRow();
1221 fillItemRow(newItemRow, newItem);
1222 m_itemsTable.Rows.Add(newItemRow);
1223 }
1224 }
1225
1226 Commit();
1227 }
1228
1229 /***********************************************************************
1230 *
1231 * SQL Statement Creation Functions
1232 *
1233 * These functions create SQL statements for update, insert, and create.
1234 * They can probably be factored later to have a db independant
1235 * portion and a db specific portion
1236 *
1237 **********************************************************************/
1238
1239 private SqlCommand createInsertCommand(string table, DataTable dt)
1240 {
1241 /**
1242 * This is subtle enough to deserve some commentary.
1243 * Instead of doing *lots* and *lots of hardcoded strings
1244 * for database definitions we'll use the fact that
1245 * realistically all insert statements look like "insert
1246 * into A(b, c) values(:b, :c) on the parameterized query
1247 * front. If we just have a list of b, c, etc... we can
1248 * generate these strings instead of typing them out.
1249 */
1250 string[] cols = new string[dt.Columns.Count];
1251 for (int i = 0; i < dt.Columns.Count; i++)
1252 {
1253 DataColumn col = dt.Columns[i];
1254 cols[i] = col.ColumnName;
1255 }
1256
1257 string sql = "insert into " + table + "(";
1258 sql += String.Join(", ", cols);
1259 // important, the first ':' needs to be here, the rest get added in the join
1260 sql += ") values (@";
1261 sql += String.Join(", @", cols);
1262 sql += ")";
1263 SqlCommand cmd = new SqlCommand(sql);
1264
1265 // this provides the binding for all our parameters, so
1266 // much less code than it used to be
1267 foreach (DataColumn col in dt.Columns)
1268 {
1269 cmd.Parameters.Add(createSqlParameter(col.ColumnName, col.DataType));
1270 }
1271 return cmd;
1272 }
1273
1274 private SqlCommand createUpdateCommand(string table, string pk, DataTable dt)
1275 {
1276 string sql = "update " + table + " set ";
1277 string subsql = String.Empty;
1278 foreach (DataColumn col in dt.Columns)
1279 {
1280 if (subsql.Length > 0)
1281 {
1282 // a map function would rock so much here
1283 subsql += ", ";
1284 }
1285 subsql += col.ColumnName + "= @" + col.ColumnName;
1286 }
1287 sql += subsql;
1288 sql += " where " + pk;
1289 SqlCommand cmd = new SqlCommand(sql);
1290
1291 // this provides the binding for all our parameters, so
1292 // much less code than it used to be
1293
1294 foreach (DataColumn col in dt.Columns)
1295 {
1296 cmd.Parameters.Add(createSqlParameter(col.ColumnName, col.DataType));
1297 }
1298 return cmd;
1299 }
1300
1301 private string defineTable(DataTable dt)
1302 {
1303 string sql = "create table " + dt.TableName + "(";
1304 string subsql = String.Empty;
1305 foreach (DataColumn col in dt.Columns)
1306 {
1307 if (subsql.Length > 0)
1308 {
1309 // a map function would rock so much here
1310 subsql += ",\n";
1311 }
1312 subsql += col.ColumnName + " " + MSSQLManager.SqlType(col.DataType);
1313 if (dt.PrimaryKey.Length > 0 && col == dt.PrimaryKey[0])
1314 {
1315 subsql += " primary key";
1316 }
1317 }
1318 sql += subsql;
1319 sql += ")";
1320
1321 return sql;
1322 }
1323
1324 /***********************************************************************
1325 *
1326 * Database Binding functions
1327 *
1328 * These will be db specific due to typing, and minor differences
1329 * in databases.
1330 *
1331 **********************************************************************/
1332
1333 ///<summary>
1334 /// This is a convenience function that collapses 5 repetitive
1335 /// lines for defining SqlParameters to 2 parameters:
1336 /// column name and database type.
1337 ///
1338 /// It assumes certain conventions like :param as the param
1339 /// name to replace in parametrized queries, and that source
1340 /// version is always current version, both of which are fine
1341 /// for us.
1342 ///</summary>
1343 ///<returns>a built Sql parameter</returns>
1344 private SqlParameter createSqlParameter(string name, Type type)
1345 {
1346 SqlParameter param = new SqlParameter();
1347 param.ParameterName = "@" + name;
1348 param.DbType = dbtypeFromType(type);
1349 param.SourceColumn = name;
1350 param.SourceVersion = DataRowVersion.Current;
1351 return param;
1352 }
1353
1354// TODO: unused
1355// private SqlParameter createParamWithValue(string name, Type type, Object o)
1356// {
1357// SqlParameter param = createSqlParameter(name, type);
1358// param.Value = o;
1359// return param;
1360// }
1361
1362 private void setupPrimCommands(SqlDataAdapter da, SqlConnection conn)
1363 {
1364 da.InsertCommand = createInsertCommand("prims", m_dataSet.Tables["prims"]);
1365 da.InsertCommand.Connection = conn;
1366
1367 da.UpdateCommand = createUpdateCommand("prims", "UUID=@UUID", m_dataSet.Tables["prims"]);
1368 da.UpdateCommand.Connection = conn;
1369
1370 SqlCommand delete = new SqlCommand("delete from prims where UUID = @UUID");
1371 delete.Parameters.Add(createSqlParameter("UUID", typeof(String)));
1372 delete.Connection = conn;
1373 da.DeleteCommand = delete;
1374 }
1375
1376 private void SetupItemsCommands(SqlDataAdapter da, SqlConnection conn)
1377 {
1378 da.InsertCommand = createInsertCommand("primitems", m_itemsTable);
1379 da.InsertCommand.Connection = conn;
1380
1381 da.UpdateCommand = createUpdateCommand("primitems", "itemID = @itemID", m_itemsTable);
1382 da.UpdateCommand.Connection = conn;
1383
1384 SqlCommand delete = new SqlCommand("delete from primitems where itemID = @itemID");
1385 delete.Parameters.Add(createSqlParameter("itemID", typeof(String)));
1386 delete.Connection = conn;
1387 da.DeleteCommand = delete;
1388 }
1389
1390 private void setupTerrainCommands(SqlDataAdapter da, SqlConnection conn)
1391 {
1392 da.InsertCommand = createInsertCommand("terrain", m_dataSet.Tables["terrain"]);
1393 da.InsertCommand.Connection = conn;
1394 }
1395
1396 private void setupLandCommands(SqlDataAdapter da, SqlConnection conn)
1397 {
1398 da.InsertCommand = createInsertCommand("land", m_dataSet.Tables["land"]);
1399 da.InsertCommand.Connection = conn;
1400
1401 da.UpdateCommand = createUpdateCommand("land", "UUID=@UUID", m_dataSet.Tables["land"]);
1402 da.UpdateCommand.Connection = conn;
1403 }
1404
1405 private void setupLandAccessCommands(SqlDataAdapter da, SqlConnection conn)
1406 {
1407 da.InsertCommand = createInsertCommand("landaccesslist", m_dataSet.Tables["landaccesslist"]);
1408 da.InsertCommand.Connection = conn;
1409 }
1410
1411 private void setupShapeCommands(SqlDataAdapter da, SqlConnection conn)
1412 {
1413 da.InsertCommand = createInsertCommand("primshapes", m_dataSet.Tables["primshapes"]);
1414 da.InsertCommand.Connection = conn;
1415
1416 da.UpdateCommand = createUpdateCommand("primshapes", "UUID=@UUID", m_dataSet.Tables["primshapes"]);
1417 da.UpdateCommand.Connection = conn;
1418
1419 SqlCommand delete = new SqlCommand("delete from primshapes where UUID = @UUID");
1420 delete.Parameters.Add(createSqlParameter("UUID", typeof(String)));
1421 delete.Connection = conn;
1422 da.DeleteCommand = delete;
1423 }
1424
1425 private void InitDB(SqlConnection conn)
1426 {
1427 string createPrims = defineTable(createPrimTable());
1428 string createShapes = defineTable(createShapeTable());
1429 string createItems = defineTable(createItemsTable());
1430 string createTerrain = defineTable(createTerrainTable());
1431 string createLand = defineTable(createLandTable());
1432 string createLandAccessList = defineTable(createLandAccessListTable());
1433
1434 SqlCommand pcmd = new SqlCommand(createPrims, conn);
1435 SqlCommand scmd = new SqlCommand(createShapes, conn);
1436 SqlCommand icmd = new SqlCommand(createItems, conn);
1437 SqlCommand tcmd = new SqlCommand(createTerrain, conn);
1438 SqlCommand lcmd = new SqlCommand(createLand, conn);
1439 SqlCommand lalcmd = new SqlCommand(createLandAccessList, conn);
1440
1441 conn.Open();
1442 try
1443 {
1444 pcmd.ExecuteNonQuery();
1445 }
1446 catch (SqlException e)
1447 {
1448 m_log.WarnFormat("[MSSql]: Primitives Table Already Exists: {0}", e);
1449 }
1450
1451 try
1452 {
1453 scmd.ExecuteNonQuery();
1454 }
1455 catch (SqlException e)
1456 {
1457 m_log.WarnFormat("[MSSql]: Shapes Table Already Exists: {0}", e);
1458 }
1459
1460 try
1461 {
1462 icmd.ExecuteNonQuery();
1463 }
1464 catch (SqlException e)
1465 {
1466 m_log.WarnFormat("[MSSql]: Items Table Already Exists: {0}", e);
1467 }
1468
1469 try
1470 {
1471 tcmd.ExecuteNonQuery();
1472 }
1473 catch (SqlException e)
1474 {
1475 m_log.WarnFormat("[MSSql]: Terrain Table Already Exists: {0}", e);
1476 }
1477
1478 try
1479 {
1480 lcmd.ExecuteNonQuery();
1481 }
1482 catch (SqlException e)
1483 {
1484 m_log.WarnFormat("[MSSql]: Land Table Already Exists: {0}", e);
1485 }
1486
1487 try
1488 {
1489 lalcmd.ExecuteNonQuery();
1490 }
1491 catch (SqlException e)
1492 {
1493 m_log.WarnFormat("[MSSql]: LandAccessList Table Already Exists: {0}", e);
1494 }
1495 conn.Close();
1496 }
1497
1498 private bool TestTables(SqlConnection conn)
1499 {
1500 SqlCommand primSelectCmd = new SqlCommand(m_primSelect, conn);
1501 SqlDataAdapter pDa = new SqlDataAdapter(primSelectCmd);
1502 SqlCommand shapeSelectCmd = new SqlCommand(m_shapeSelect, conn);
1503 SqlDataAdapter sDa = new SqlDataAdapter(shapeSelectCmd);
1504 SqlCommand itemsSelectCmd = new SqlCommand(m_itemsSelect, conn);
1505 SqlDataAdapter iDa = new SqlDataAdapter(itemsSelectCmd);
1506 SqlCommand terrainSelectCmd = new SqlCommand(m_terrainSelect, conn);
1507 SqlDataAdapter tDa = new SqlDataAdapter(terrainSelectCmd);
1508 SqlCommand landSelectCmd = new SqlCommand(m_landSelect, conn);
1509 SqlDataAdapter lDa = new SqlDataAdapter(landSelectCmd);
1510 SqlCommand landAccessListSelectCmd = new SqlCommand(m_landAccessListSelect, conn);
1511 SqlDataAdapter lalDa = new SqlDataAdapter(landAccessListSelectCmd);
1512
1513 DataSet tmpDS = new DataSet();
1514 try
1515 {
1516 pDa.Fill(tmpDS, "prims");
1517 sDa.Fill(tmpDS, "primshapes");
1518
1519 if (persistPrimInventories)
1520 iDa.Fill(tmpDS, "primitems");
1521
1522 tDa.Fill(tmpDS, "terrain");
1523 lDa.Fill(tmpDS, "land");
1524 lalDa.Fill(tmpDS, "landaccesslist");
1525 }
1526 catch (SqlException)
1527 {
1528 m_log.Info("[DATASTORE]: MySql Database doesn't exist... creating");
1529 InitDB(conn);
1530 }
1531
1532 pDa.Fill(tmpDS, "prims");
1533 sDa.Fill(tmpDS, "primshapes");
1534
1535 if (persistPrimInventories)
1536 iDa.Fill(tmpDS, "primitems");
1537
1538 tDa.Fill(tmpDS, "terrain");
1539 lDa.Fill(tmpDS, "land");
1540 lalDa.Fill(tmpDS, "landaccesslist");
1541
1542 foreach (DataColumn col in createPrimTable().Columns)
1543 {
1544 if (!tmpDS.Tables["prims"].Columns.Contains(col.ColumnName))
1545 {
1546 m_log.Info("[DATASTORE]: Missing required column:" + col.ColumnName);
1547 return false;
1548 }
1549 }
1550
1551 foreach (DataColumn col in createShapeTable().Columns)
1552 {
1553 if (!tmpDS.Tables["primshapes"].Columns.Contains(col.ColumnName))
1554 {
1555 m_log.Info("[DATASTORE]: Missing required column:" + col.ColumnName);
1556 return false;
1557 }
1558 }
1559
1560 // XXX primitems should probably go here eventually
1561
1562 foreach (DataColumn col in createTerrainTable().Columns)
1563 {
1564 if (!tmpDS.Tables["terrain"].Columns.Contains(col.ColumnName))
1565 {
1566 m_log.Info("[DATASTORE]: Missing require column:" + col.ColumnName);
1567 return false;
1568 }
1569 }
1570
1571 foreach (DataColumn col in createLandTable().Columns)
1572 {
1573 if (!tmpDS.Tables["land"].Columns.Contains(col.ColumnName))
1574 {
1575 m_log.Info("[DATASTORE]: Missing require column:" + col.ColumnName);
1576 return false;
1577 }
1578 }
1579
1580 foreach (DataColumn col in createLandAccessListTable().Columns)
1581 {
1582 if (!tmpDS.Tables["landaccesslist"].Columns.Contains(col.ColumnName))
1583 {
1584 m_log.Info("[DATASTORE]: Missing require column:" + col.ColumnName);
1585 return false;
1586 }
1587 }
1588
1589 return true;
1590 }
1591
1592 /***********************************************************************
1593 *
1594 * Type conversion functions
1595 *
1596 **********************************************************************/
1597
1598 private DbType dbtypeFromType(Type type)
1599 {
1600 if (type == typeof(String))
1601 {
1602 return DbType.String;
1603 }
1604 else if (type == typeof(Int32))
1605 {
1606 return DbType.Int32;
1607 }
1608 else if (type == typeof(Double))
1609 {
1610 return DbType.Double;
1611 }
1612 else if (type == typeof(Byte[]))
1613 {
1614 return DbType.Binary;
1615 }
1616 else
1617 {
1618 return DbType.String;
1619 }
1620 }
1621 }
1622}
diff --git a/OpenSim/Data/MSSQL/MSSQLGridData.cs b/OpenSim/Data/MSSQL/MSSQLGridData.cs
new file mode 100644
index 0000000..9bd8acc
--- /dev/null
+++ b/OpenSim/Data/MSSQL/MSSQLGridData.cs
@@ -0,0 +1,366 @@
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 OpenSim 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.Security.Cryptography;
32using System.Text;
33using libsecondlife;
34using OpenSim.Framework.Console;
35
36namespace OpenSim.Framework.Data.MSSQL
37{
38 /// <summary>
39 /// A grid data interface for Microsoft SQL Server
40 /// </summary>
41 public class MSSQLGridData : GridDataBase
42 {
43 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
44
45 /// <summary>
46 /// Database manager
47 /// </summary>
48 private MSSQLManager database;
49
50 private string m_regionsTableName;
51
52 /// <summary>
53 /// Initialises the Grid Interface
54 /// </summary>
55 override public void Initialise()
56 {
57 IniFile iniFile = new IniFile("mssql_connection.ini");
58
59 string settingDataSource = iniFile.ParseFileReadValue("data_source");
60 string settingInitialCatalog = iniFile.ParseFileReadValue("initial_catalog");
61 string settingPersistSecurityInfo = iniFile.ParseFileReadValue("persist_security_info");
62 string settingUserId = iniFile.ParseFileReadValue("user_id");
63 string settingPassword = iniFile.ParseFileReadValue("password");
64
65 m_regionsTableName = iniFile.ParseFileReadValue("regionstablename");
66 if (m_regionsTableName == null)
67 {
68 m_regionsTableName = "regions";
69 }
70
71 database =
72 new MSSQLManager(settingDataSource, settingInitialCatalog, settingPersistSecurityInfo, settingUserId,
73 settingPassword);
74
75 TestTables();
76 }
77
78 private void TestTables()
79 {
80 IDbCommand cmd = database.Query("SELECT TOP 1 * FROM "+m_regionsTableName, new Dictionary<string, string>());
81
82 try
83 {
84 cmd.ExecuteNonQuery();
85 cmd.Dispose();
86 }
87 catch (Exception)
88 {
89 m_log.Info("[DATASTORE]: MSSQL Database doesn't exist... creating");
90 database.ExecuteResourceSql("Mssql-regions.sql");
91 }
92 }
93
94 /// <summary>
95 /// Shuts down the grid interface
96 /// </summary>
97 override public void Close()
98 {
99 database.Close();
100 }
101
102 /// <summary>
103 /// Returns the storage system name
104 /// </summary>
105 /// <returns>A string containing the storage system name</returns>
106 override public string getName()
107 {
108 return "Sql OpenGridData";
109 }
110
111 /// <summary>
112 /// Returns the storage system version
113 /// </summary>
114 /// <returns>A string containing the storage system version</returns>
115 override public string getVersion()
116 {
117 return "0.1";
118 }
119
120 /// <summary>
121 /// Returns a list of regions within the specified ranges
122 /// </summary>
123 /// <param name="a">minimum X coordinate</param>
124 /// <param name="b">minimum Y coordinate</param>
125 /// <param name="c">maximum X coordinate</param>
126 /// <param name="d">maximum Y coordinate</param>
127 /// <returns>An array of region profiles</returns>
128 override public RegionProfileData[] GetProfilesInRange(uint a, uint b, uint c, uint d)
129 {
130 return null;
131 }
132
133 /// <summary>
134 /// Returns a sim profile from its location
135 /// </summary>
136 /// <param name="handle">Region location handle</param>
137 /// <returns>Sim profile</returns>
138 override public RegionProfileData GetProfileByHandle(ulong handle)
139 {
140 IDataReader reader = null;
141 try
142 {
143 Dictionary<string, string> param = new Dictionary<string, string>();
144 param["handle"] = handle.ToString();
145 IDbCommand result = database.Query("SELECT * FROM " + m_regionsTableName + " WHERE regionHandle = @handle", param);
146 reader = result.ExecuteReader();
147
148 RegionProfileData row = database.getRegionRow(reader);
149 reader.Close();
150 result.Dispose();
151
152 return row;
153 }
154 catch (Exception)
155 {
156 if (reader != null)
157 {
158 reader.Close();
159 }
160 }
161 return null;
162 }
163
164 /// <summary>
165 /// Returns a sim profile from its UUID
166 /// </summary>
167 /// <param name="uuid">The region UUID</param>
168 /// <returns>The sim profile</returns>
169 override public RegionProfileData GetProfileByLLUUID(LLUUID uuid)
170 {
171 Dictionary<string, string> param = new Dictionary<string, string>();
172 param["uuid"] = uuid.ToString();
173 IDbCommand result = database.Query("SELECT * FROM " + m_regionsTableName + " WHERE uuid = @uuid", param);
174 IDataReader reader = result.ExecuteReader();
175
176 RegionProfileData row = database.getRegionRow(reader);
177 reader.Close();
178 result.Dispose();
179
180 return row;
181 }
182
183 /// <summary>
184 /// Returns a sim profile from it's Region name string
185 /// </summary>
186 /// <param name="uuid">The region name search query</param>
187 /// <returns>The sim profile</returns>
188 override public RegionProfileData GetProfileByString(string regionName)
189 {
190 if (regionName.Length > 2)
191 {
192 try
193 {
194 lock (database)
195 {
196 Dictionary<string, string> param = new Dictionary<string, string>();
197 // Add % because this is a like query.
198 param["?regionName"] = regionName + "%";
199 // Order by statement will return shorter matches first. Only returns one record or no record.
200 IDbCommand result = database.Query("SELECT top 1 * FROM " + m_regionsTableName + " WHERE regionName like ?regionName order by regionName", param);
201 IDataReader reader = result.ExecuteReader();
202
203 RegionProfileData row = database.getRegionRow(reader);
204 reader.Close();
205 result.Dispose();
206
207 return row;
208 }
209 }
210 catch (Exception e)
211 {
212 database.Reconnect();
213 m_log.Error(e.ToString());
214 return null;
215 }
216 }
217 else
218 {
219 m_log.Error("[DATABASE]: Searched for a Region Name shorter then 3 characters");
220 return null;
221 }
222 }
223
224 /// <summary>
225 /// Adds a new specified region to the database
226 /// </summary>
227 /// <param name="profile">The profile to add</param>
228 /// <returns>A dataresponse enum indicating success</returns>
229 override public DataResponse AddProfile(RegionProfileData profile)
230 {
231 try
232 {
233 if (GetProfileByLLUUID(profile.UUID) != null)
234 {
235 return DataResponse.RESPONSE_OK;
236 }
237 }
238 catch (Exception)
239 {
240 System.Console.WriteLine("No regions found. Create new one.");
241 }
242
243 if (insertRegionRow(profile))
244 {
245 return DataResponse.RESPONSE_OK;
246 }
247 else
248 {
249 return DataResponse.RESPONSE_ERROR;
250 }
251 }
252
253 /// <summary>
254 /// Creates a new region in the database
255 /// </summary>
256 /// <param name="profile">The region profile to insert</param>
257 /// <returns>Successful?</returns>
258 public bool insertRegionRow(RegionProfileData profile)
259 {
260 //Insert new region
261 string sql =
262 "INSERT INTO " + m_regionsTableName + " ([regionHandle], [regionName], [uuid], [regionRecvKey], [regionSecret], [regionSendKey], [regionDataURI], ";
263 sql +=
264 "[serverIP], [serverPort], [serverURI], [locX], [locY], [locZ], [eastOverrideHandle], [westOverrideHandle], [southOverrideHandle], [northOverrideHandle], [regionAssetURI], [regionAssetRecvKey], ";
265 sql +=
266 "[regionAssetSendKey], [regionUserURI], [regionUserRecvKey], [regionUserSendKey], [regionMapTexture], [serverHttpPort], [serverRemotingPort], [owner_uuid]) VALUES ";
267
268 sql += "(@regionHandle, @regionName, @uuid, @regionRecvKey, @regionSecret, @regionSendKey, @regionDataURI, ";
269 sql +=
270 "@serverIP, @serverPort, @serverURI, @locX, @locY, @locZ, @eastOverrideHandle, @westOverrideHandle, @southOverrideHandle, @northOverrideHandle, @regionAssetURI, @regionAssetRecvKey, ";
271 sql +=
272 "@regionAssetSendKey, @regionUserURI, @regionUserRecvKey, @regionUserSendKey, @regionMapTexture, @serverHttpPort, @serverRemotingPort, @owner_uuid);";
273
274 Dictionary<string, string> parameters = new Dictionary<string, string>();
275
276 parameters["regionHandle"] = profile.regionHandle.ToString();
277 parameters["regionName"] = profile.regionName;
278 parameters["uuid"] = profile.UUID.ToString();
279 parameters["regionRecvKey"] = profile.regionRecvKey;
280 parameters["regionSecret"] = profile.regionSecret;
281 parameters["regionSendKey"] = profile.regionSendKey;
282 parameters["regionDataURI"] = profile.regionDataURI;
283 parameters["serverIP"] = profile.serverIP;
284 parameters["serverPort"] = profile.serverPort.ToString();
285 parameters["serverURI"] = profile.serverURI;
286 parameters["locX"] = profile.regionLocX.ToString();
287 parameters["locY"] = profile.regionLocY.ToString();
288 parameters["locZ"] = profile.regionLocZ.ToString();
289 parameters["eastOverrideHandle"] = profile.regionEastOverrideHandle.ToString();
290 parameters["westOverrideHandle"] = profile.regionWestOverrideHandle.ToString();
291 parameters["northOverrideHandle"] = profile.regionNorthOverrideHandle.ToString();
292 parameters["southOverrideHandle"] = profile.regionSouthOverrideHandle.ToString();
293 parameters["regionAssetURI"] = profile.regionAssetURI;
294 parameters["regionAssetRecvKey"] = profile.regionAssetRecvKey;
295 parameters["regionAssetSendKey"] = profile.regionAssetSendKey;
296 parameters["regionUserURI"] = profile.regionUserURI;
297 parameters["regionUserRecvKey"] = profile.regionUserRecvKey;
298 parameters["regionUserSendKey"] = profile.regionUserSendKey;
299 parameters["regionMapTexture"] = profile.regionMapTextureID.ToString();
300 parameters["serverHttpPort"] = profile.httpPort.ToString();
301 parameters["serverRemotingPort"] = profile.remotingPort.ToString();
302 parameters["owner_uuid"] = profile.owner_uuid.ToString();
303
304 bool returnval = false;
305
306 try
307 {
308 IDbCommand result = database.Query(sql, parameters);
309
310 if (result.ExecuteNonQuery() == 1)
311 returnval = true;
312
313 result.Dispose();
314 }
315 catch (Exception e)
316 {
317 m_log.Error("MSSQLManager : " + e.ToString());
318 }
319
320 return returnval;
321 }
322
323 /// <summary>
324 /// DEPRECATED. Attempts to authenticate a region by comparing a shared secret.
325 /// </summary>
326 /// <param name="uuid">The UUID of the challenger</param>
327 /// <param name="handle">The attempted regionHandle of the challenger</param>
328 /// <param name="authkey">The secret</param>
329 /// <returns>Whether the secret and regionhandle match the database entry for UUID</returns>
330 override public bool AuthenticateSim(LLUUID uuid, ulong handle, string authkey)
331 {
332 bool throwHissyFit = false; // Should be true by 1.0
333
334 if (throwHissyFit)
335 throw new Exception("CRYPTOWEAK AUTHENTICATE: Refusing to authenticate due to replay potential.");
336
337 RegionProfileData data = GetProfileByLLUUID(uuid);
338
339 return (handle == data.regionHandle && authkey == data.regionSecret);
340 }
341
342 /// <summary>
343 /// NOT YET FUNCTIONAL. Provides a cryptographic authentication of a region
344 /// </summary>
345 /// <remarks>This requires a security audit.</remarks>
346 /// <param name="uuid"></param>
347 /// <param name="handle"></param>
348 /// <param name="authhash"></param>
349 /// <param name="challenge"></param>
350 /// <returns></returns>
351 public bool AuthenticateSim(LLUUID uuid, ulong handle, string authhash, string challenge)
352 {
353 SHA512Managed HashProvider = new SHA512Managed();
354 ASCIIEncoding TextProvider = new ASCIIEncoding();
355
356 byte[] stream = TextProvider.GetBytes(uuid.ToString() + ":" + handle.ToString() + ":" + challenge);
357 byte[] hash = HashProvider.ComputeHash(stream);
358 return false;
359 }
360
361 override public ReservationData GetReservationAtPoint(uint x, uint y)
362 {
363 return null;
364 }
365 }
366}
diff --git a/OpenSim/Data/MSSQL/MSSQLInventoryData.cs b/OpenSim/Data/MSSQL/MSSQLInventoryData.cs
new file mode 100644
index 0000000..1e99e51
--- /dev/null
+++ b/OpenSim/Data/MSSQL/MSSQLInventoryData.cs
@@ -0,0 +1,728 @@
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 OpenSim 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.Data.SqlClient;
32using libsecondlife;
33using OpenSim.Framework.Console;
34
35namespace OpenSim.Framework.Data.MSSQL
36{
37 /// <summary>
38 /// A MySQL interface for the inventory server
39 /// </summary>
40 public class MSSQLInventoryData : IInventoryData
41 {
42 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
43
44 /// <summary>
45 /// The database manager
46 /// </summary>
47 private MSSQLManager database;
48
49 /// <summary>
50 /// Loads and initialises this database plugin
51 /// </summary>
52 public void Initialise()
53 {
54 IniFile GridDataMySqlFile = new IniFile("mssql_connection.ini");
55 string settingDataSource = GridDataMySqlFile.ParseFileReadValue("data_source");
56 string settingInitialCatalog = GridDataMySqlFile.ParseFileReadValue("initial_catalog");
57 string settingPersistSecurityInfo = GridDataMySqlFile.ParseFileReadValue("persist_security_info");
58 string settingUserId = GridDataMySqlFile.ParseFileReadValue("user_id");
59 string settingPassword = GridDataMySqlFile.ParseFileReadValue("password");
60
61 database =
62 new MSSQLManager(settingDataSource, settingInitialCatalog, settingPersistSecurityInfo, settingUserId,
63 settingPassword);
64 TestTables();
65 }
66
67 #region Test and initialization code
68
69 private void UpgradeFoldersTable(string tableName)
70 {
71 // null as the version, indicates that the table didn't exist
72 if (tableName == null)
73 {
74 database.ExecuteResourceSql("CreateFoldersTable.sql");
75 //database.ExecuteResourceSql("UpgradeFoldersTableToVersion2.sql");
76 return;
77 }
78 }
79
80 private void UpgradeItemsTable(string tableName)
81 {
82 // null as the version, indicates that the table didn't exist
83 if (tableName == null)
84 {
85 database.ExecuteResourceSql("CreateItemsTable.sql");
86 //database.ExecuteResourceSql("UpgradeItemsTableToVersion2.sql");
87 return;
88 }
89 }
90
91 private void TestTables()
92 {
93 Dictionary<string, string> tableList = new Dictionary<string, string>();
94
95 tableList["inventoryfolders"] = null;
96 tableList["inventoryitems"] = null;
97
98 database.GetTableVersion(tableList);
99
100 UpgradeFoldersTable(tableList["inventoryfolders"]);
101 UpgradeItemsTable(tableList["inventoryitems"]);
102 }
103
104 #endregion
105
106 /// <summary>
107 /// The name of this DB provider
108 /// </summary>
109 /// <returns>Name of DB provider</returns>
110 public string getName()
111 {
112 return "MSSQL Inventory Data Interface";
113 }
114
115 /// <summary>
116 /// Closes this DB provider
117 /// </summary>
118 public void Close()
119 {
120 // Do nothing.
121 }
122
123 /// <summary>
124 /// Returns the version of this DB provider
125 /// </summary>
126 /// <returns>A string containing the DB provider</returns>
127 public string getVersion()
128 {
129 return database.getVersion();
130 }
131
132 /// <summary>
133 /// Returns a list of items in a specified folder
134 /// </summary>
135 /// <param name="folderID">The folder to search</param>
136 /// <returns>A list containing inventory items</returns>
137 public List<InventoryItemBase> getInventoryInFolder(LLUUID folderID)
138 {
139 try
140 {
141 lock (database)
142 {
143 List<InventoryItemBase> items = new List<InventoryItemBase>();
144
145 Dictionary<string, string> param = new Dictionary<string, string>();
146 param["parentFolderID"] = folderID.ToString();
147
148 IDbCommand result =
149 database.Query("SELECT * FROM inventoryitems WHERE parentFolderID = @parentFolderID", param);
150 IDataReader reader = result.ExecuteReader();
151
152 while (reader.Read())
153 items.Add(readInventoryItem(reader));
154
155 reader.Close();
156 result.Dispose();
157
158 return items;
159 }
160 }
161 catch (Exception e)
162 {
163 database.Reconnect();
164 m_log.Error(e.ToString());
165 return null;
166 }
167 }
168
169 /// <summary>
170 /// Returns a list of the root folders within a users inventory
171 /// </summary>
172 /// <param name="user">The user whos inventory is to be searched</param>
173 /// <returns>A list of folder objects</returns>
174 public List<InventoryFolderBase> getUserRootFolders(LLUUID user)
175 {
176 try
177 {
178 lock (database)
179 {
180 Dictionary<string, string> param = new Dictionary<string, string>();
181 param["uuid"] = user.ToString();
182 param["zero"] = LLUUID.Zero.ToString();
183
184 IDbCommand result =
185 database.Query(
186 "SELECT * FROM inventoryfolders WHERE parentFolderID = @zero AND agentID = @uuid", param);
187 IDataReader reader = result.ExecuteReader();
188
189 List<InventoryFolderBase> items = new List<InventoryFolderBase>();
190 while (reader.Read())
191 items.Add(readInventoryFolder(reader));
192
193
194 reader.Close();
195 result.Dispose();
196
197 return items;
198 }
199 }
200 catch (Exception e)
201 {
202 database.Reconnect();
203 m_log.Error(e.ToString());
204 return null;
205 }
206 }
207
208 // see InventoryItemBase.getUserRootFolder
209 public InventoryFolderBase getUserRootFolder(LLUUID user)
210 {
211 try
212 {
213 lock (database)
214 {
215 Dictionary<string, string> param = new Dictionary<string, string>();
216 param["uuid"] = user.ToString();
217 param["zero"] = LLUUID.Zero.ToString();
218
219 IDbCommand result =
220 database.Query(
221 "SELECT * FROM inventoryfolders WHERE parentFolderID = @zero AND agentID = @uuid", param);
222 IDataReader reader = result.ExecuteReader();
223
224 List<InventoryFolderBase> items = new List<InventoryFolderBase>();
225 while (reader.Read())
226 items.Add(readInventoryFolder(reader));
227
228 InventoryFolderBase rootFolder = null;
229
230 // There should only ever be one root folder for a user. However, if there's more
231 // than one we'll simply use the first one rather than failing. It would be even
232 // nicer to print some message to this effect, but this feels like it's too low a
233 // to put such a message out, and it's too minor right now to spare the time to
234 // suitably refactor.
235 if (items.Count > 0)
236 {
237 rootFolder = items[0];
238 }
239
240 reader.Close();
241 result.Dispose();
242
243 return rootFolder;
244 }
245 }
246 catch (Exception e)
247 {
248 database.Reconnect();
249 m_log.Error(e.ToString());
250 return null;
251 }
252 }
253
254 /// <summary>
255 /// Returns a list of folders in a users inventory contained within the specified folder
256 /// </summary>
257 /// <param name="parentID">The folder to search</param>
258 /// <returns>A list of inventory folders</returns>
259 public List<InventoryFolderBase> getInventoryFolders(LLUUID parentID)
260 {
261 try
262 {
263 lock (database)
264 {
265 Dictionary<string, string> param = new Dictionary<string, string>();
266 param["parentFolderID"] = parentID.ToString();
267
268
269 IDbCommand result =
270 database.Query("SELECT * FROM inventoryfolders WHERE parentFolderID = @parentFolderID", param);
271 IDataReader reader = result.ExecuteReader();
272
273 List<InventoryFolderBase> items = new List<InventoryFolderBase>();
274
275 while (reader.Read())
276 items.Add(readInventoryFolder(reader));
277
278 reader.Close();
279 result.Dispose();
280
281 return items;
282 }
283 }
284 catch (Exception e)
285 {
286 database.Reconnect();
287 m_log.Error(e.ToString());
288 return null;
289 }
290 }
291
292 /// <summary>
293 /// Reads a one item from an SQL result
294 /// </summary>
295 /// <param name="reader">The SQL Result</param>
296 /// <returns>the item read</returns>
297 private InventoryItemBase readInventoryItem(IDataReader reader)
298 {
299 try
300 {
301 InventoryItemBase item = new InventoryItemBase();
302
303 item.inventoryID = new LLUUID((string) reader["inventoryID"]);
304 item.assetID = new LLUUID((string) reader["assetID"]);
305 item.assetType = (int) reader["assetType"];
306 item.parentFolderID = new LLUUID((string) reader["parentFolderID"]);
307 item.avatarID = new LLUUID((string) reader["avatarID"]);
308 item.inventoryName = (string) reader["inventoryName"];
309 item.inventoryDescription = (string) reader["inventoryDescription"];
310 item.inventoryNextPermissions = Convert.ToUInt32(reader["inventoryNextPermissions"]);
311 item.inventoryCurrentPermissions = Convert.ToUInt32(reader["inventoryCurrentPermissions"]);
312 item.invType = (int) reader["invType"];
313 item.creatorsID = new LLUUID((string) reader["creatorID"]);
314 item.inventoryBasePermissions = Convert.ToUInt32(reader["inventoryBasePermissions"]);
315 item.inventoryEveryOnePermissions = Convert.ToUInt32(reader["inventoryEveryOnePermissions"]);
316 return item;
317 }
318 catch (SqlException e)
319 {
320 m_log.Error(e.ToString());
321 }
322
323 return null;
324 }
325
326 /// <summary>
327 /// Returns a specified inventory item
328 /// </summary>
329 /// <param name="item">The item to return</param>
330 /// <returns>An inventory item</returns>
331 public InventoryItemBase getInventoryItem(LLUUID itemID)
332 {
333 try
334 {
335 lock (database)
336 {
337 Dictionary<string, string> param = new Dictionary<string, string>();
338 param["inventoryID"] = itemID.ToString();
339
340 IDbCommand result =
341 database.Query("SELECT * FROM inventoryitems WHERE inventoryID = @inventoryID", param);
342 IDataReader reader = result.ExecuteReader();
343
344 InventoryItemBase item = null;
345 if (reader.Read())
346 item = readInventoryItem(reader);
347
348 reader.Close();
349 result.Dispose();
350
351 return item;
352 }
353 }
354 catch (Exception e)
355 {
356 database.Reconnect();
357 m_log.Error(e.ToString());
358 }
359 return null;
360 }
361
362 /// <summary>
363 /// Reads a list of inventory folders returned by a query.
364 /// </summary>
365 /// <param name="reader">A MySQL Data Reader</param>
366 /// <returns>A List containing inventory folders</returns>
367 protected InventoryFolderBase readInventoryFolder(IDataReader reader)
368 {
369 try
370 {
371 InventoryFolderBase folder = new InventoryFolderBase();
372 folder.agentID = new LLUUID((string) reader["agentID"]);
373 folder.parentID = new LLUUID((string) reader["parentFolderID"]);
374 folder.folderID = new LLUUID((string) reader["folderID"]);
375 folder.name = (string) reader["folderName"];
376 folder.type = (short) reader["type"];
377 folder.version = (ushort) ((int) reader["version"]);
378 return folder;
379 }
380 catch (Exception e)
381 {
382 m_log.Error(e.ToString());
383 }
384
385 return null;
386 }
387
388 /// <summary>
389 /// Returns a specified inventory folder
390 /// </summary>
391 /// <param name="folder">The folder to return</param>
392 /// <returns>A folder class</returns>
393 public InventoryFolderBase getInventoryFolder(LLUUID folderID)
394 {
395 try
396 {
397 lock (database)
398 {
399 Dictionary<string, string> param = new Dictionary<string, string>();
400 param["uuid"] = folderID.ToString();
401
402 IDbCommand result = database.Query("SELECT * FROM inventoryfolders WHERE folderID = @uuid", param);
403 IDataReader reader = result.ExecuteReader();
404
405 reader.Read();
406 InventoryFolderBase folder = readInventoryFolder(reader);
407 reader.Close();
408 result.Dispose();
409
410 return folder;
411 }
412 }
413 catch (Exception e)
414 {
415 database.Reconnect();
416 m_log.Error(e.ToString());
417 return null;
418 }
419 }
420
421 /// <summary>
422 /// Adds a specified item to the database
423 /// </summary>
424 /// <param name="item">The inventory item</param>
425 public void addInventoryItem(InventoryItemBase item)
426 {
427 if (getInventoryItem(item.inventoryID) != null)
428 {
429 updateInventoryItem(item);
430 return;
431 }
432
433 string sql = "INSERT INTO inventoryitems";
434 sql +=
435 "([inventoryID], [assetID], [assetType], [parentFolderID], [avatarID], [inventoryName], [inventoryDescription], [inventoryNextPermissions], [inventoryCurrentPermissions], [invType], [creatorID], [inventoryBasePermissions], [inventoryEveryOnePermissions]) VALUES ";
436 sql +=
437 "(@inventoryID, @assetID, @assetType, @parentFolderID, @avatarID, @inventoryName, @inventoryDescription, @inventoryNextPermissions, @inventoryCurrentPermissions, @invType, @creatorID, @inventoryBasePermissions, @inventoryEveryOnePermissions);";
438
439 try
440 {
441 Dictionary<string, string> param = new Dictionary<string, string>();
442 param["inventoryID"] = item.inventoryID.ToString();
443 param["assetID"] = item.assetID.ToString();
444 param["assetType"] = item.assetType.ToString();
445 param["parentFolderID"] = item.parentFolderID.ToString();
446 param["avatarID"] = item.avatarID.ToString();
447 param["inventoryName"] = item.inventoryName;
448 param["inventoryDescription"] = item.inventoryDescription;
449 param["inventoryNextPermissions"] = item.inventoryNextPermissions.ToString();
450 param["inventoryCurrentPermissions"] = item.inventoryCurrentPermissions.ToString();
451 param["invType"] = Convert.ToString(item.invType);
452 param["creatorID"] = item.creatorsID.ToString();
453 param["inventoryBasePermissions"] = Convert.ToString(item.inventoryBasePermissions);
454 param["inventoryEveryOnePermissions"] = Convert.ToString(item.inventoryEveryOnePermissions);
455
456 IDbCommand result = database.Query(sql, param);
457 result.ExecuteNonQuery();
458 result.Dispose();
459 }
460 catch (SqlException e)
461 {
462 m_log.Error(e.ToString());
463 }
464 }
465
466 /// <summary>
467 /// Updates the specified inventory item
468 /// </summary>
469 /// <param name="item">Inventory item to update</param>
470 public void updateInventoryItem(InventoryItemBase item)
471 {
472 SqlCommand command = new SqlCommand("UPDATE inventoryitems set inventoryID = @inventoryID, " +
473 "assetID = @assetID, " +
474 "assetType = @assetType" +
475 "parentFolderID = @parentFolderID" +
476 "avatarID = @avatarID" +
477 "inventoryName = @inventoryName" +
478 "inventoryDescription = @inventoryDescription" +
479 "inventoryNextPermissions = @inventoryNextPermissions" +
480 "inventoryCurrentPermissions = @inventoryCurrentPermissions" +
481 "invType = @invType" +
482 "creatorID = @creatorID" +
483 "inventoryBasePermissions = @inventoryBasePermissions" +
484 "inventoryEveryOnePermissions = @inventoryEveryOnePermissions) where " +
485 "inventoryID = @keyInventoryID;", database.getConnection());
486 SqlParameter param1 = new SqlParameter("@inventoryID", item.inventoryID.ToString());
487 SqlParameter param2 = new SqlParameter("@assetID", item.assetID);
488 SqlParameter param3 = new SqlParameter("@assetType", item.assetType);
489 SqlParameter param4 = new SqlParameter("@parentFolderID", item.parentFolderID);
490 SqlParameter param5 = new SqlParameter("@avatarID", item.avatarID);
491 SqlParameter param6 = new SqlParameter("@inventoryName", item.inventoryName);
492 SqlParameter param7 = new SqlParameter("@inventoryDescription", item.inventoryDescription);
493 SqlParameter param8 = new SqlParameter("@inventoryNextPermissions", item.inventoryNextPermissions);
494 SqlParameter param9 = new SqlParameter("@inventoryCurrentPermissions", item.inventoryCurrentPermissions);
495 SqlParameter param10 = new SqlParameter("@invType", item.invType);
496 SqlParameter param11 = new SqlParameter("@creatorID", item.creatorsID);
497 SqlParameter param12 = new SqlParameter("@inventoryBasePermissions", item.inventoryBasePermissions);
498 SqlParameter param13 = new SqlParameter("@inventoryEveryOnePermissions", item.inventoryEveryOnePermissions);
499 SqlParameter param14 = new SqlParameter("@keyInventoryID", item.inventoryID.ToString());
500 command.Parameters.Add(param1);
501 command.Parameters.Add(param2);
502 command.Parameters.Add(param3);
503 command.Parameters.Add(param4);
504 command.Parameters.Add(param5);
505 command.Parameters.Add(param6);
506 command.Parameters.Add(param7);
507 command.Parameters.Add(param8);
508 command.Parameters.Add(param9);
509 command.Parameters.Add(param10);
510 command.Parameters.Add(param11);
511 command.Parameters.Add(param12);
512 command.Parameters.Add(param13);
513 command.Parameters.Add(param14);
514
515 try
516 {
517 command.ExecuteNonQuery();
518 }
519 catch (Exception e)
520 {
521 m_log.Error(e.ToString());
522 }
523 }
524
525 /// <summary>
526 ///
527 /// </summary>
528 /// <param name="item"></param>
529 public void deleteInventoryItem(LLUUID itemID)
530 {
531 try
532 {
533 Dictionary<string, string> param = new Dictionary<string, string>();
534 param["uuid"] = itemID.ToString();
535
536 IDbCommand cmd = database.Query("DELETE FROM inventoryitems WHERE inventoryID=@uuid", param);
537 cmd.ExecuteNonQuery();
538 cmd.Dispose();
539 }
540 catch (SqlException e)
541 {
542 database.Reconnect();
543 m_log.Error(e.ToString());
544 }
545 }
546
547 /// <summary>
548 /// Creates a new inventory folder
549 /// </summary>
550 /// <param name="folder">Folder to create</param>
551 public void addInventoryFolder(InventoryFolderBase folder)
552 {
553 string sql =
554 "INSERT INTO inventoryfolders ([folderID], [agentID], [parentFolderID], [folderName], [type], [version]) VALUES ";
555 sql += "(@folderID, @agentID, @parentFolderID, @folderName, @type, @version);";
556
557
558 Dictionary<string, string> param = new Dictionary<string, string>();
559 param["folderID"] = folder.folderID.ToString();
560 param["agentID"] = folder.agentID.ToString();
561 param["parentFolderID"] = folder.parentID.ToString();
562 param["folderName"] = folder.name;
563 param["type"] = Convert.ToString(folder.type);
564 param["version"] = Convert.ToString(folder.version);
565
566 try
567 {
568 IDbCommand result = database.Query(sql, param);
569 result.ExecuteNonQuery();
570 result.Dispose();
571 }
572 catch (Exception e)
573 {
574 m_log.Error(e.ToString());
575 }
576 }
577
578 /// <summary>
579 /// Updates an inventory folder
580 /// </summary>
581 /// <param name="folder">Folder to update</param>
582 public void updateInventoryFolder(InventoryFolderBase folder)
583 {
584 SqlCommand command = new SqlCommand("UPDATE inventoryfolders set folderID = @folderID, " +
585 "agentID = @agentID, " +
586 "parentFolderID = @parentFolderID," +
587 "folderName = @folderName," +
588 "type = @type," +
589 "version = @version where " +
590 "folderID = @keyFolderID;", database.getConnection());
591 SqlParameter param1 = new SqlParameter("@folderID", folder.folderID.ToString());
592 SqlParameter param2 = new SqlParameter("@agentID", folder.agentID.ToString());
593 SqlParameter param3 = new SqlParameter("@parentFolderID", folder.parentID.ToString());
594 SqlParameter param4 = new SqlParameter("@folderName", folder.name);
595 SqlParameter param5 = new SqlParameter("@type", folder.type);
596 SqlParameter param6 = new SqlParameter("@version", folder.version);
597 SqlParameter param7 = new SqlParameter("@keyFolderID", folder.folderID.ToString());
598 command.Parameters.Add(param1);
599 command.Parameters.Add(param2);
600 command.Parameters.Add(param3);
601 command.Parameters.Add(param4);
602 command.Parameters.Add(param5);
603 command.Parameters.Add(param6);
604 command.Parameters.Add(param7);
605
606 try
607 {
608 command.ExecuteNonQuery();
609 }
610 catch (Exception e)
611 {
612 m_log.Error(e.ToString());
613 }
614 }
615
616 /// <summary>
617 /// Updates an inventory folder
618 /// </summary>
619 /// <param name="folder">Folder to update</param>
620 public void moveInventoryFolder(InventoryFolderBase folder)
621 {
622 SqlCommand command = new SqlCommand("UPDATE inventoryfolders set folderID = @folderID, " +
623 "parentFolderID = @parentFolderID," +
624 "folderID = @keyFolderID;", database.getConnection());
625 SqlParameter param1 = new SqlParameter("@folderID", folder.folderID.ToString());
626 SqlParameter param2 = new SqlParameter("@parentFolderID", folder.parentID.ToString());
627 SqlParameter param3 = new SqlParameter("@keyFolderID", folder.folderID.ToString());
628 command.Parameters.Add(param1);
629 command.Parameters.Add(param2);
630 command.Parameters.Add(param3);
631
632 try
633 {
634 command.ExecuteNonQuery();
635 }
636 catch (Exception e)
637 {
638 m_log.Error(e.ToString());
639 }
640 }
641
642 /// <summary>
643 /// Append a list of all the child folders of a parent folder
644 /// </summary>
645 /// <param name="folders">list where folders will be appended</param>
646 /// <param name="parentID">ID of parent</param>
647 protected void getInventoryFolders(ref List<InventoryFolderBase> folders, LLUUID parentID)
648 {
649 List<InventoryFolderBase> subfolderList = getInventoryFolders(parentID);
650
651 foreach (InventoryFolderBase f in subfolderList)
652 folders.Add(f);
653 }
654
655 // See IInventoryData
656 public List<InventoryFolderBase> getFolderHierarchy(LLUUID parentID)
657 {
658 List<InventoryFolderBase> folders = new List<InventoryFolderBase>();
659 getInventoryFolders(ref folders, parentID);
660
661 for (int i = 0; i < folders.Count; i++)
662 getInventoryFolders(ref folders, folders[i].folderID);
663
664 return folders;
665 }
666
667 protected void deleteOneFolder(LLUUID folderID)
668 {
669 try
670 {
671 Dictionary<string, string> param = new Dictionary<string, string>();
672 param["folderID"] = folderID.ToString();
673
674 IDbCommand cmd = database.Query("DELETE FROM inventoryfolders WHERE folderID=@folderID", param);
675 cmd.ExecuteNonQuery();
676 cmd.Dispose();
677 }
678 catch (SqlException e)
679 {
680 database.Reconnect();
681 m_log.Error(e.ToString());
682 }
683 }
684
685 protected void deleteItemsInFolder(LLUUID folderID)
686 {
687 try
688 {
689 Dictionary<string, string> param = new Dictionary<string, string>();
690 param["parentFolderID"] = folderID.ToString();
691
692
693 IDbCommand cmd =
694 database.Query("DELETE FROM inventoryitems WHERE parentFolderID=@parentFolderID", param);
695 cmd.ExecuteNonQuery();
696 cmd.Dispose();
697 }
698 catch (SqlException e)
699 {
700 database.Reconnect();
701 m_log.Error(e.ToString());
702 }
703 }
704
705 /// <summary>
706 /// Delete an inventory folder
707 /// </summary>
708 /// <param name="folderId">Id of folder to delete</param>
709 public void deleteInventoryFolder(LLUUID folderID)
710 {
711 lock (database)
712 {
713 List<InventoryFolderBase> subFolders = getFolderHierarchy(folderID);
714
715 //Delete all sub-folders
716 foreach (InventoryFolderBase f in subFolders)
717 {
718 deleteOneFolder(f.folderID);
719 deleteItemsInFolder(f.folderID);
720 }
721
722 //Delete the actual row
723 deleteOneFolder(folderID);
724 deleteItemsInFolder(folderID);
725 }
726 }
727 }
728}
diff --git a/OpenSim/Data/MSSQL/MSSQLLogData.cs b/OpenSim/Data/MSSQL/MSSQLLogData.cs
new file mode 100644
index 0000000..c76af53
--- /dev/null
+++ b/OpenSim/Data/MSSQL/MSSQLLogData.cs
@@ -0,0 +1,120 @@
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 OpenSim 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.Collections.Generic;
29using System.Data;
30
31namespace OpenSim.Framework.Data.MSSQL
32{
33 /// <summary>
34 /// An interface to the log database for MySQL
35 /// </summary>
36 internal class MSSQLLogData : ILogData
37 {
38 /// <summary>
39 /// The database manager
40 /// </summary>
41 public MSSQLManager database;
42
43 /// <summary>
44 /// Artificial constructor called when the plugin is loaded
45 /// </summary>
46 public void Initialise()
47 {
48 IniFile GridDataMySqlFile = new IniFile("mssql_connection.ini");
49 string settingDataSource = GridDataMySqlFile.ParseFileReadValue("data_source");
50 string settingInitialCatalog = GridDataMySqlFile.ParseFileReadValue("initial_catalog");
51 string settingPersistSecurityInfo = GridDataMySqlFile.ParseFileReadValue("persist_security_info");
52 string settingUserId = GridDataMySqlFile.ParseFileReadValue("user_id");
53 string settingPassword = GridDataMySqlFile.ParseFileReadValue("password");
54
55 database =
56 new MSSQLManager(settingDataSource, settingInitialCatalog, settingPersistSecurityInfo, settingUserId,
57 settingPassword);
58
59 IDbCommand cmd = database.Query("select top 1 * from logs", new Dictionary<string, string>());
60 try
61 {
62 cmd.ExecuteNonQuery();
63 cmd.Dispose();
64 }
65 catch
66 {
67 database.ExecuteResourceSql("Mssql-logs.sql");
68 }
69
70 }
71
72 /// <summary>
73 /// Saves a log item to the database
74 /// </summary>
75 /// <param name="serverDaemon">The daemon triggering the event</param>
76 /// <param name="target">The target of the action (region / agent UUID, etc)</param>
77 /// <param name="methodCall">The method call where the problem occured</param>
78 /// <param name="arguments">The arguments passed to the method</param>
79 /// <param name="priority">How critical is this?</param>
80 /// <param name="logMessage">The message to log</param>
81 public void saveLog(string serverDaemon, string target, string methodCall, string arguments, int priority,
82 string logMessage)
83 {
84 try
85 {
86 database.insertLogRow(serverDaemon, target, methodCall, arguments, priority, logMessage);
87 }
88 catch
89 {
90 database.Reconnect();
91 }
92 }
93
94 /// <summary>
95 /// Returns the name of this DB provider
96 /// </summary>
97 /// <returns>A string containing the DB provider name</returns>
98 public string getName()
99 {
100 return "MSSQL Logdata Interface";
101 }
102
103 /// <summary>
104 /// Closes the database provider
105 /// </summary>
106 public void Close()
107 {
108 // Do nothing.
109 }
110
111 /// <summary>
112 /// Returns the version of this DB provider
113 /// </summary>
114 /// <returns>A string containing the provider version</returns>
115 public string getVersion()
116 {
117 return "0.1";
118 }
119 }
120}
diff --git a/OpenSim/Data/MSSQL/MSSQLManager.cs b/OpenSim/Data/MSSQL/MSSQLManager.cs
new file mode 100644
index 0000000..efe62be
--- /dev/null
+++ b/OpenSim/Data/MSSQL/MSSQLManager.cs
@@ -0,0 +1,529 @@
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 OpenSim 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.Data.SqlClient;
32using System.IO;
33using System.Reflection;
34using libsecondlife;
35using OpenSim.Framework.Console;
36
37namespace OpenSim.Framework.Data.MSSQL
38{
39 /// <summary>
40 /// A management class for the MS SQL Storage Engine
41 /// </summary>
42 public class MSSQLManager
43 {
44 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
45
46 /// <summary>
47 /// The database connection object
48 /// </summary>
49 private IDbConnection dbcon;
50
51 /// <summary>
52 /// Connection string for ADO.net
53 /// </summary>
54 private readonly string connectionString;
55
56 public MSSQLManager(string dataSource, string initialCatalog, string persistSecurityInfo, string userId,
57 string password)
58 {
59 connectionString = "Data Source=" + dataSource + ";Initial Catalog=" + initialCatalog +
60 ";Persist Security Info=" + persistSecurityInfo + ";User ID=" + userId + ";Password=" +
61 password + ";";
62 dbcon = new SqlConnection(connectionString);
63 dbcon.Open();
64 }
65
66 //private DataTable createRegionsTable()
67 //{
68 // DataTable regions = new DataTable("regions");
69
70 // createCol(regions, "regionHandle", typeof (ulong));
71 // createCol(regions, "regionName", typeof (String));
72 // createCol(regions, "uuid", typeof (String));
73
74 // createCol(regions, "regionRecvKey", typeof (String));
75 // createCol(regions, "regionSecret", typeof (String));
76 // createCol(regions, "regionSendKey", typeof (String));
77
78 // createCol(regions, "regionDataURI", typeof (String));
79 // createCol(regions, "serverIP", typeof (String));
80 // createCol(regions, "serverPort", typeof (String));
81 // createCol(regions, "serverURI", typeof (String));
82
83
84 // createCol(regions, "locX", typeof (uint));
85 // createCol(regions, "locY", typeof (uint));
86 // createCol(regions, "locZ", typeof (uint));
87
88 // createCol(regions, "eastOverrideHandle", typeof (ulong));
89 // createCol(regions, "westOverrideHandle", typeof (ulong));
90 // createCol(regions, "southOverrideHandle", typeof (ulong));
91 // createCol(regions, "northOverrideHandle", typeof (ulong));
92
93 // createCol(regions, "regionAssetURI", typeof (String));
94 // createCol(regions, "regionAssetRecvKey", typeof (String));
95 // createCol(regions, "regionAssetSendKey", typeof (String));
96
97 // createCol(regions, "regionUserURI", typeof (String));
98 // createCol(regions, "regionUserRecvKey", typeof (String));
99 // createCol(regions, "regionUserSendKey", typeof (String));
100
101 // createCol(regions, "regionMapTexture", typeof (String));
102 // createCol(regions, "serverHttpPort", typeof (String));
103 // createCol(regions, "serverRemotingPort", typeof (uint));
104
105 // // Add in contraints
106 // regions.PrimaryKey = new DataColumn[] {regions.Columns["UUID"]};
107 // return regions;
108 //}
109
110 protected static void createCol(DataTable dt, string name, Type type)
111 {
112 DataColumn col = new DataColumn(name, type);
113 dt.Columns.Add(col);
114 }
115
116 protected static string defineTable(DataTable dt)
117 {
118 string sql = "create table " + dt.TableName + "(";
119 string subsql = String.Empty;
120 foreach (DataColumn col in dt.Columns)
121 {
122 if (subsql.Length > 0)
123 {
124 // a map function would rock so much here
125 subsql += ",\n";
126 }
127
128 subsql += col.ColumnName + " " + SqlType(col.DataType);
129 if (col == dt.PrimaryKey[0])
130 {
131 subsql += " primary key";
132 }
133 }
134 sql += subsql;
135 sql += ")";
136 return sql;
137 }
138
139
140 // this is something we'll need to implement for each db
141 // slightly differently.
142 public static string SqlType(Type type)
143 {
144 if (type == typeof(String))
145 {
146 return "varchar(255)";
147 }
148 else if (type == typeof(Int32))
149 {
150 return "integer";
151 }
152 else if (type == typeof(Double))
153 {
154 return "float";
155 }
156 else if (type == typeof(Byte[]))
157 {
158 return "image";
159 }
160 else
161 {
162 return "varchar(255)";
163 }
164 }
165
166 /// <summary>
167 /// Shuts down the database connection
168 /// </summary>
169 public void Close()
170 {
171 dbcon.Close();
172 dbcon = null;
173 }
174
175 /// <summary>
176 /// Reconnects to the database
177 /// </summary>
178 public void Reconnect()
179 {
180 lock (dbcon)
181 {
182 try
183 {
184 // Close the DB connection
185 dbcon.Close();
186 // Try reopen it
187 dbcon = new SqlConnection(connectionString);
188 dbcon.Open();
189 }
190 catch (Exception e)
191 {
192 m_log.Error("Unable to reconnect to database " + e.ToString());
193 }
194 }
195 }
196
197 /// <summary>
198 /// Runs a query with protection against SQL Injection by using parameterised input.
199 /// </summary>
200 /// <param name="sql">The SQL string - replace any variables such as WHERE x = "y" with WHERE x = @y</param>
201 /// <param name="parameters">The parameters - index so that @y is indexed as 'y'</param>
202 /// <returns>A Sql DB Command</returns>
203 public IDbCommand Query(string sql, Dictionary<string, string> parameters)
204 {
205 SqlCommand dbcommand = (SqlCommand)dbcon.CreateCommand();
206 dbcommand.CommandText = sql;
207 foreach (KeyValuePair<string, string> param in parameters)
208 {
209 dbcommand.Parameters.AddWithValue(param.Key, param.Value);
210 }
211
212 return (IDbCommand)dbcommand;
213 }
214
215 /// <summary>
216 /// Runs a database reader object and returns a region row
217 /// </summary>
218 /// <param name="reader">An active database reader</param>
219 /// <returns>A region row</returns>
220 public RegionProfileData getRegionRow(IDataReader reader)
221 {
222 RegionProfileData regionprofile = new RegionProfileData();
223
224 if (reader.Read())
225 {
226 // Region Main
227 regionprofile.regionHandle = Convert.ToUInt64(reader["regionHandle"]);
228 regionprofile.regionName = (string)reader["regionName"];
229 regionprofile.UUID = new LLUUID((string)reader["uuid"]);
230
231 // Secrets
232 regionprofile.regionRecvKey = (string)reader["regionRecvKey"];
233 regionprofile.regionSecret = (string)reader["regionSecret"];
234 regionprofile.regionSendKey = (string)reader["regionSendKey"];
235
236 // Region Server
237 regionprofile.regionDataURI = (string)reader["regionDataURI"];
238 regionprofile.regionOnline = false; // Needs to be pinged before this can be set.
239 regionprofile.serverIP = (string)reader["serverIP"];
240 regionprofile.serverPort = Convert.ToUInt32(reader["serverPort"]);
241 regionprofile.serverURI = (string)reader["serverURI"];
242 regionprofile.httpPort = Convert.ToUInt32(reader["serverHttpPort"]);
243 regionprofile.remotingPort = Convert.ToUInt32(reader["serverRemotingPort"]);
244
245
246 // Location
247 regionprofile.regionLocX = Convert.ToUInt32(reader["locX"]);
248 regionprofile.regionLocY = Convert.ToUInt32(reader["locY"]);
249 regionprofile.regionLocZ = Convert.ToUInt32(reader["locZ"]);
250
251 // Neighbours - 0 = No Override
252 regionprofile.regionEastOverrideHandle = Convert.ToUInt64(reader["eastOverrideHandle"]);
253 regionprofile.regionWestOverrideHandle = Convert.ToUInt64(reader["westOverrideHandle"]);
254 regionprofile.regionSouthOverrideHandle = Convert.ToUInt64(reader["southOverrideHandle"]);
255 regionprofile.regionNorthOverrideHandle = Convert.ToUInt64(reader["northOverrideHandle"]);
256
257 // Assets
258 regionprofile.regionAssetURI = (string)reader["regionAssetURI"];
259 regionprofile.regionAssetRecvKey = (string)reader["regionAssetRecvKey"];
260 regionprofile.regionAssetSendKey = (string)reader["regionAssetSendKey"];
261
262 // Userserver
263 regionprofile.regionUserURI = (string)reader["regionUserURI"];
264 regionprofile.regionUserRecvKey = (string)reader["regionUserRecvKey"];
265 regionprofile.regionUserSendKey = (string)reader["regionUserSendKey"];
266 try
267 {
268 regionprofile.owner_uuid = new LLUUID((string)reader["owner_uuid"]);
269 }
270 catch(Exception)
271 {}
272 // World Map Addition
273 string tempRegionMap = reader["regionMapTexture"].ToString();
274 if (tempRegionMap != String.Empty)
275 {
276 regionprofile.regionMapTextureID = new LLUUID(tempRegionMap);
277 }
278 else
279 {
280 regionprofile.regionMapTextureID = new LLUUID();
281 }
282 }
283 else
284 {
285 reader.Close();
286 throw new Exception("No rows to return");
287 }
288 return regionprofile;
289 }
290
291 /// <summary>
292 /// Reads a user profile from an active data reader
293 /// </summary>
294 /// <param name="reader">An active database reader</param>
295 /// <returns>A user profile</returns>
296 public UserProfileData readUserRow(IDataReader reader)
297 {
298 UserProfileData retval = new UserProfileData();
299
300 if (reader.Read())
301 {
302 retval.UUID = new LLUUID((string)reader["UUID"]);
303 retval.username = (string)reader["username"];
304 retval.surname = (string)reader["lastname"];
305
306 retval.passwordHash = (string)reader["passwordHash"];
307 retval.passwordSalt = (string)reader["passwordSalt"];
308
309 retval.homeRegion = Convert.ToUInt64(reader["homeRegion"].ToString());
310 retval.homeLocation = new LLVector3(
311 Convert.ToSingle(reader["homeLocationX"].ToString()),
312 Convert.ToSingle(reader["homeLocationY"].ToString()),
313 Convert.ToSingle(reader["homeLocationZ"].ToString()));
314 retval.homeLookAt = new LLVector3(
315 Convert.ToSingle(reader["homeLookAtX"].ToString()),
316 Convert.ToSingle(reader["homeLookAtY"].ToString()),
317 Convert.ToSingle(reader["homeLookAtZ"].ToString()));
318
319 retval.created = Convert.ToInt32(reader["created"].ToString());
320 retval.lastLogin = Convert.ToInt32(reader["lastLogin"].ToString());
321
322 retval.userInventoryURI = (string)reader["userInventoryURI"];
323 retval.userAssetURI = (string)reader["userAssetURI"];
324
325 retval.profileCanDoMask = Convert.ToUInt32(reader["profileCanDoMask"].ToString());
326 retval.profileWantDoMask = Convert.ToUInt32(reader["profileWantDoMask"].ToString());
327
328 retval.profileAboutText = (string)reader["profileAboutText"];
329 retval.profileFirstText = (string)reader["profileFirstText"];
330
331 retval.profileImage = new LLUUID((string)reader["profileImage"]);
332 retval.profileFirstImage = new LLUUID((string)reader["profileFirstImage"]);
333 retval.webLoginKey = new LLUUID((string)reader["webLoginKey"]);
334 }
335 else
336 {
337 return null;
338 }
339 return retval;
340 }
341
342 /// <summary>
343 /// Reads an agent row from a database reader
344 /// </summary>
345 /// <param name="reader">An active database reader</param>
346 /// <returns>A user session agent</returns>
347 public UserAgentData readAgentRow(IDataReader reader)
348 {
349 UserAgentData retval = new UserAgentData();
350
351 if (reader.Read())
352 {
353 // Agent IDs
354 retval.UUID = new LLUUID((string)reader["UUID"]);
355 retval.sessionID = new LLUUID((string)reader["sessionID"]);
356 retval.secureSessionID = new LLUUID((string)reader["secureSessionID"]);
357
358 // Agent Who?
359 retval.agentIP = (string)reader["agentIP"];
360 retval.agentPort = Convert.ToUInt32(reader["agentPort"].ToString());
361 retval.agentOnline = Convert.ToBoolean(reader["agentOnline"].ToString());
362
363 // Login/Logout times (UNIX Epoch)
364 retval.loginTime = Convert.ToInt32(reader["loginTime"].ToString());
365 retval.logoutTime = Convert.ToInt32(reader["logoutTime"].ToString());
366
367 // Current position
368 retval.currentRegion = (string)reader["currentRegion"];
369 retval.currentHandle = Convert.ToUInt64(reader["currentHandle"].ToString());
370 LLVector3.TryParse((string)reader["currentPos"], out retval.currentPos);
371 }
372 else
373 {
374 return null;
375 }
376 return retval;
377 }
378
379 public AssetBase getAssetRow(IDataReader reader)
380 {
381 AssetBase asset = new AssetBase();
382 if (reader.Read())
383 {
384 // Region Main
385
386 asset = new AssetBase();
387 asset.Data = (byte[])reader["data"];
388 asset.Description = (string)reader["description"];
389 asset.FullID = new LLUUID((string)reader["id"]);
390 asset.InvType = Convert.ToSByte(reader["invType"]);
391 asset.Local = Convert.ToBoolean(reader["local"]); // ((sbyte)reader["local"]) != 0 ? true : false;
392 asset.Name = (string)reader["name"];
393 asset.Type = Convert.ToSByte(reader["assetType"]);
394 }
395 else
396 {
397 return null; // throw new Exception("No rows to return");
398 }
399 return asset;
400 }
401
402
403 /// <summary>
404 /// Inserts a new row into the log database
405 /// </summary>
406 /// <param name="serverDaemon">The daemon which triggered this event</param>
407 /// <param name="target">Who were we operating on when this occured (region UUID, user UUID, etc)</param>
408 /// <param name="methodCall">The method call where the problem occured</param>
409 /// <param name="arguments">The arguments passed to the method</param>
410 /// <param name="priority">How critical is this?</param>
411 /// <param name="logMessage">Extra message info</param>
412 /// <returns>Saved successfully?</returns>
413 public bool insertLogRow(string serverDaemon, string target, string methodCall, string arguments, int priority,
414 string logMessage)
415 {
416 string sql = "INSERT INTO logs ([target], [server], [method], [arguments], [priority], [message]) VALUES ";
417 sql += "(@target, @server, @method, @arguments, @priority, @message);";
418
419 Dictionary<string, string> parameters = new Dictionary<string, string>();
420 parameters["server"] = serverDaemon;
421 parameters["target"] = target;
422 parameters["method"] = methodCall;
423 parameters["arguments"] = arguments;
424 parameters["priority"] = priority.ToString();
425 parameters["message"] = logMessage;
426
427 bool returnval = false;
428
429 try
430 {
431 IDbCommand result = Query(sql, parameters);
432
433 if (result.ExecuteNonQuery() == 1)
434 returnval = true;
435
436 result.Dispose();
437 }
438 catch (Exception e)
439 {
440 m_log.Error(e.ToString());
441 return false;
442 }
443
444 return returnval;
445 }
446
447 /// <summary>
448 /// Execute a SQL statement stored in a resource, as a string
449 /// </summary>
450 /// <param name="name"></param>
451 public void ExecuteResourceSql(string name)
452 {
453 SqlCommand cmd = new SqlCommand(getResourceString(name), (SqlConnection)dbcon);
454 cmd.ExecuteNonQuery();
455 cmd.Dispose();
456 }
457
458 public SqlConnection getConnection()
459 {
460 return (SqlConnection)dbcon;
461 }
462
463 /// <summary>
464 /// Given a list of tables, return the version of the tables, as seen in the database
465 /// </summary>
466 /// <param name="tableList"></param>
467 public void GetTableVersion(Dictionary<string, string> tableList)
468 {
469 lock (dbcon)
470 {
471 Dictionary<string, string> param = new Dictionary<string, string>();
472 param["dbname"] = dbcon.Database;
473 IDbCommand tablesCmd =
474 Query("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_CATALOG=@dbname", param);
475 using (IDataReader tables = tablesCmd.ExecuteReader())
476 {
477 while (tables.Read())
478 {
479 try
480 {
481 string tableName = (string)tables["TABLE_NAME"];
482 if (tableList.ContainsKey(tableName))
483 tableList[tableName] = tableName;
484 }
485 catch (Exception e)
486 {
487 m_log.Error(e.ToString());
488 }
489 }
490 tables.Close();
491 }
492 }
493 }
494
495 private string getResourceString(string name)
496 {
497 Assembly assem = GetType().Assembly;
498 string[] names = assem.GetManifestResourceNames();
499
500 foreach (string s in names)
501 if (s.EndsWith(name))
502 using (Stream resource = assem.GetManifestResourceStream(s))
503 {
504 using (StreamReader resourceReader = new StreamReader(resource))
505 {
506 string resourceString = resourceReader.ReadToEnd();
507 return resourceString;
508 }
509 }
510 throw new Exception(string.Format("Resource '{0}' was not found", name));
511 }
512
513 /// <summary>
514 /// Returns the version of this DB provider
515 /// </summary>
516 /// <returns>A string containing the DB provider</returns>
517 public string getVersion()
518 {
519 Module module = GetType().Module;
520 string dllName = module.Assembly.ManifestModule.Name;
521 Version dllVersion = module.Assembly.GetName().Version;
522
523
524 return
525 string.Format("{0}.{1}.{2}.{3}", dllVersion.Major, dllVersion.Minor, dllVersion.Build,
526 dllVersion.Revision);
527 }
528 }
529}
diff --git a/OpenSim/Data/MSSQL/MSSQLUserData.cs b/OpenSim/Data/MSSQL/MSSQLUserData.cs
new file mode 100644
index 0000000..be0417d
--- /dev/null
+++ b/OpenSim/Data/MSSQL/MSSQLUserData.cs
@@ -0,0 +1,771 @@
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 OpenSim 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.Data.SqlClient;
32using libsecondlife;
33using OpenSim.Framework.Console;
34
35namespace OpenSim.Framework.Data.MSSQL
36{
37 /// <summary>
38 /// A database interface class to a user profile storage system
39 /// </summary>
40 public class MSSQLUserData : UserDataBase
41 {
42 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
43
44 /// <summary>
45 /// Database manager for MySQL
46 /// </summary>
47 public MSSQLManager database;
48
49 private string m_agentsTableName;
50 private string m_usersTableName;
51 private string m_userFriendsTableName;
52
53 /// <summary>
54 /// Loads and initialises the MySQL storage plugin
55 /// </summary>
56 override public void Initialise()
57 {
58 // Load from an INI file connection details
59 // TODO: move this to XML?
60 IniFile iniFile = new IniFile("mssql_connection.ini");
61 string settingDataSource = iniFile.ParseFileReadValue("data_source");
62 string settingInitialCatalog = iniFile.ParseFileReadValue("initial_catalog");
63 string settingPersistSecurityInfo = iniFile.ParseFileReadValue("persist_security_info");
64 string settingUserId = iniFile.ParseFileReadValue("user_id");
65 string settingPassword = iniFile.ParseFileReadValue("password");
66
67 m_usersTableName = iniFile.ParseFileReadValue("userstablename");
68 if (m_usersTableName == null)
69 {
70 m_usersTableName = "users";
71 }
72
73 m_userFriendsTableName = iniFile.ParseFileReadValue("userfriendstablename");
74 if (m_userFriendsTableName == null)
75 {
76 m_userFriendsTableName = "userfriends";
77 }
78
79 m_agentsTableName = iniFile.ParseFileReadValue("agentstablename");
80 if (m_agentsTableName == null)
81 {
82 m_agentsTableName = "agents";
83 }
84
85 database =
86 new MSSQLManager(settingDataSource, settingInitialCatalog, settingPersistSecurityInfo, settingUserId,
87 settingPassword);
88
89 TestTables();
90 }
91
92 private bool TestTables()
93 {
94 IDbCommand cmd;
95
96 cmd = database.Query("select top 1 * from " + m_usersTableName, new Dictionary<string, string>());
97 try
98 {
99 cmd.ExecuteNonQuery();
100 }
101 catch
102 {
103 database.ExecuteResourceSql("Mssql-users.sql");
104 }
105
106 cmd = database.Query("select top 1 * from " + m_agentsTableName, new Dictionary<string, string>());
107 try
108 {
109 cmd.ExecuteNonQuery();
110 }
111 catch
112 {
113 database.ExecuteResourceSql("Mssql-agents.sql");
114 }
115
116 cmd = database.Query("select top 1 * from " + m_userFriendsTableName, new Dictionary<string, string>());
117 try
118 {
119 cmd.ExecuteNonQuery();
120 }
121 catch
122 {
123 database.ExecuteResourceSql("CreateUserFriendsTable.sql");
124 }
125
126 return true;
127 }
128 /// <summary>
129 /// Searches the database for a specified user profile by name components
130 /// </summary>
131 /// <param name="user">The first part of the account name</param>
132 /// <param name="last">The second part of the account name</param>
133 /// <returns>A user profile</returns>
134 override public UserProfileData GetUserByName(string user, string last)
135 {
136 try
137 {
138 lock (database)
139 {
140 Dictionary<string, string> param = new Dictionary<string, string>();
141 param["first"] = user;
142 param["second"] = last;
143
144 IDbCommand result =
145 database.Query("SELECT * FROM " + m_usersTableName + " WHERE username = @first AND lastname = @second", param);
146 IDataReader reader = result.ExecuteReader();
147
148 UserProfileData row = database.readUserRow(reader);
149
150 reader.Close();
151 result.Dispose();
152
153 return row;
154 }
155 }
156 catch (Exception e)
157 {
158 database.Reconnect();
159 m_log.Error(e.ToString());
160 return null;
161 }
162 }
163
164 #region User Friends List Data
165
166 override public void AddNewUserFriend(LLUUID friendlistowner, LLUUID friend, uint perms)
167 {
168 int dtvalue = Util.UnixTimeSinceEpoch();
169
170 Dictionary<string, string> param = new Dictionary<string, string>();
171 param["@ownerID"] = friendlistowner.UUID.ToString();
172 param["@friendID"] = friend.UUID.ToString();
173 param["@friendPerms"] = perms.ToString();
174 param["@datetimestamp"] = dtvalue.ToString();
175
176 try
177 {
178 lock (database)
179 {
180 IDbCommand adder =
181 database.Query(
182 "INSERT INTO " + m_userFriendsTableName + " " +
183 "(ownerID,friendID,friendPerms,datetimestamp) " +
184 "VALUES " +
185 "(@ownerID,@friendID,@friendPerms,@datetimestamp)",
186 param);
187
188 adder.ExecuteNonQuery();
189
190 adder =
191 database.Query(
192 "INSERT INTO " + m_userFriendsTableName + " " +
193 "(ownerID,friendID,friendPerms,datetimestamp) " +
194 "VALUES " +
195 "(@friendID,@ownerID,@friendPerms,@datetimestamp)",
196 param);
197 adder.ExecuteNonQuery();
198
199 }
200 }
201 catch (Exception e)
202 {
203 database.Reconnect();
204 m_log.Error(e.ToString());
205 return;
206 }
207 }
208
209 override public void RemoveUserFriend(LLUUID friendlistowner, LLUUID friend)
210 {
211 Dictionary<string, string> param = new Dictionary<string, string>();
212 param["@ownerID"] = friendlistowner.UUID.ToString();
213 param["@friendID"] = friend.UUID.ToString();
214
215
216 try
217 {
218 lock (database)
219 {
220 IDbCommand updater =
221 database.Query(
222 "delete from " + m_userFriendsTableName + " where ownerID = @ownerID and friendID = @friendID",
223 param);
224 updater.ExecuteNonQuery();
225
226 updater =
227 database.Query(
228 "delete from " + m_userFriendsTableName + " where ownerID = @friendID and friendID = @ownerID",
229 param);
230 updater.ExecuteNonQuery();
231
232 }
233 }
234 catch (Exception e)
235 {
236 database.Reconnect();
237 m_log.Error(e.ToString());
238 return;
239 }
240 }
241
242 override public void UpdateUserFriendPerms(LLUUID friendlistowner, LLUUID friend, uint perms)
243 {
244 Dictionary<string, string> param = new Dictionary<string, string>();
245 param["@ownerID"] = friendlistowner.UUID.ToString();
246 param["@friendID"] = friend.UUID.ToString();
247 param["@friendPerms"] = perms.ToString();
248
249
250 try
251 {
252 lock (database)
253 {
254 IDbCommand updater =
255 database.Query(
256 "update " + m_userFriendsTableName +
257 " SET friendPerms = @friendPerms " +
258 "where ownerID = @ownerID and friendID = @friendID",
259 param);
260
261 updater.ExecuteNonQuery();
262 }
263 }
264 catch (Exception e)
265 {
266 database.Reconnect();
267 m_log.Error(e.ToString());
268 return;
269 }
270 }
271
272
273 override public List<FriendListItem> GetUserFriendList(LLUUID friendlistowner)
274 {
275 List<FriendListItem> Lfli = new List<FriendListItem>();
276
277 Dictionary<string, string> param = new Dictionary<string, string>();
278 param["@ownerID"] = friendlistowner.UUID.ToString();
279
280 try
281 {
282 lock (database)
283 {
284 //Left Join userfriends to itself
285 IDbCommand result =
286 database.Query(
287 "select a.ownerID,a.friendID,a.friendPerms,b.friendPerms as ownerperms from " + m_userFriendsTableName + " as a, " + m_userFriendsTableName + " as b" +
288 " where a.ownerID = @ownerID and b.ownerID = a.friendID and b.friendID = a.ownerID",
289 param);
290 IDataReader reader = result.ExecuteReader();
291
292
293 while (reader.Read())
294 {
295 FriendListItem fli = new FriendListItem();
296 fli.FriendListOwner = new LLUUID((string)reader["ownerID"]);
297 fli.Friend = new LLUUID((string)reader["friendID"]);
298 fli.FriendPerms = (uint)Convert.ToInt32(reader["friendPerms"]);
299
300 // This is not a real column in the database table, it's a joined column from the opposite record
301 fli.FriendListOwnerPerms = (uint)Convert.ToInt32(reader["ownerperms"]);
302
303 Lfli.Add(fli);
304 }
305 reader.Close();
306 result.Dispose();
307 }
308 }
309 catch (Exception e)
310 {
311 database.Reconnect();
312 m_log.Error(e.ToString());
313 return Lfli;
314 }
315
316 return Lfli;
317 }
318
319 #endregion
320
321 override public void UpdateUserCurrentRegion(LLUUID avatarid, LLUUID regionuuid)
322 {
323 m_log.Info("[USER]: Stub UpdateUserCUrrentRegion called");
324 }
325
326
327
328 override public List<Framework.AvatarPickerAvatar> GeneratePickerResults(LLUUID queryID, string query)
329 {
330 List<Framework.AvatarPickerAvatar> returnlist = new List<Framework.AvatarPickerAvatar>();
331 string[] querysplit;
332 querysplit = query.Split(' ');
333 if (querysplit.Length == 2)
334 {
335 try
336 {
337 lock (database)
338 {
339 Dictionary<string, string> param = new Dictionary<string, string>();
340 param["first"] = querysplit[0];
341 param["second"] = querysplit[1];
342
343 IDbCommand result =
344 database.Query(
345 "SELECT UUID,username,lastname FROM " + m_usersTableName + " WHERE username = @first AND lastname = @second",
346 param);
347 IDataReader reader = result.ExecuteReader();
348
349
350 while (reader.Read())
351 {
352 Framework.AvatarPickerAvatar user = new Framework.AvatarPickerAvatar();
353 user.AvatarID = new LLUUID((string)reader["UUID"]);
354 user.firstName = (string)reader["username"];
355 user.lastName = (string)reader["lastname"];
356 returnlist.Add(user);
357 }
358 reader.Close();
359 result.Dispose();
360 }
361 }
362 catch (Exception e)
363 {
364 database.Reconnect();
365 m_log.Error(e.ToString());
366 return returnlist;
367 }
368 }
369 else if (querysplit.Length == 1)
370 {
371 try
372 {
373 lock (database)
374 {
375 Dictionary<string, string> param = new Dictionary<string, string>();
376 param["first"] = querysplit[0];
377
378 IDbCommand result =
379 database.Query(
380 "SELECT UUID,username,lastname FROM " + m_usersTableName + " WHERE username = @first OR lastname = @first",
381 param);
382 IDataReader reader = result.ExecuteReader();
383
384
385 while (reader.Read())
386 {
387 Framework.AvatarPickerAvatar user = new Framework.AvatarPickerAvatar();
388 user.AvatarID = new LLUUID((string)reader["UUID"]);
389 user.firstName = (string)reader["username"];
390 user.lastName = (string)reader["lastname"];
391 returnlist.Add(user);
392 }
393 reader.Close();
394 result.Dispose();
395 }
396 }
397 catch (Exception e)
398 {
399 database.Reconnect();
400 m_log.Error(e.ToString());
401 return returnlist;
402 }
403 }
404 return returnlist;
405 }
406
407 // See IUserData
408 override public UserProfileData GetUserByUUID(LLUUID uuid)
409 {
410 try
411 {
412 lock (database)
413 {
414 Dictionary<string, string> param = new Dictionary<string, string>();
415 param["uuid"] = uuid.ToString();
416
417 IDbCommand result = database.Query("SELECT * FROM " + m_usersTableName + " WHERE UUID = @uuid", param);
418 IDataReader reader = result.ExecuteReader();
419
420 UserProfileData row = database.readUserRow(reader);
421
422 reader.Close();
423 result.Dispose();
424
425 return row;
426 }
427 }
428 catch (Exception e)
429 {
430 database.Reconnect();
431 m_log.Error(e.ToString());
432 return null;
433 }
434 }
435
436 /// <summary>
437 /// Returns a user session searching by name
438 /// </summary>
439 /// <param name="name">The account name</param>
440 /// <returns>The users session</returns>
441 override public UserAgentData GetAgentByName(string name)
442 {
443 return GetAgentByName(name.Split(' ')[0], name.Split(' ')[1]);
444 }
445
446 /// <summary>
447 /// Returns a user session by account name
448 /// </summary>
449 /// <param name="user">First part of the users account name</param>
450 /// <param name="last">Second part of the users account name</param>
451 /// <returns>The users session</returns>
452 override public UserAgentData GetAgentByName(string user, string last)
453 {
454 UserProfileData profile = GetUserByName(user, last);
455 return GetAgentByUUID(profile.UUID);
456 }
457
458 /// <summary>
459 /// Returns an agent session by account UUID
460 /// </summary>
461 /// <param name="uuid">The accounts UUID</param>
462 /// <returns>The users session</returns>
463 override public UserAgentData GetAgentByUUID(LLUUID uuid)
464 {
465 try
466 {
467 lock (database)
468 {
469 Dictionary<string, string> param = new Dictionary<string, string>();
470 param["uuid"] = uuid.ToString();
471
472 IDbCommand result = database.Query("SELECT * FROM " + m_agentsTableName + " WHERE UUID = @uuid", param);
473 IDataReader reader = result.ExecuteReader();
474
475 UserAgentData row = database.readAgentRow(reader);
476
477 reader.Close();
478 result.Dispose();
479
480 return row;
481 }
482 }
483 catch (Exception e)
484 {
485 database.Reconnect();
486 m_log.Error(e.ToString());
487 return null;
488 }
489 }
490 override public void StoreWebLoginKey(LLUUID AgentID, LLUUID WebLoginKey)
491 {
492 UserProfileData user = GetUserByUUID(AgentID);
493 user.webLoginKey = WebLoginKey;
494 UpdateUserProfile(user);
495
496 }
497 /// <summary>
498 /// Creates a new users profile
499 /// </summary>
500 /// <param name="user">The user profile to create</param>
501 override public void AddNewUserProfile(UserProfileData user)
502 {
503 try
504 {
505 lock (database)
506 {
507 InsertUserRow(user.UUID, user.username, user.surname, user.passwordHash, user.passwordSalt,
508 user.homeRegion, user.homeLocation.X, user.homeLocation.Y,
509 user.homeLocation.Z,
510 user.homeLookAt.X, user.homeLookAt.Y, user.homeLookAt.Z, user.created,
511 user.lastLogin, user.userInventoryURI, user.userAssetURI,
512 user.profileCanDoMask, user.profileWantDoMask,
513 user.profileAboutText, user.profileFirstText, user.profileImage,
514 user.profileFirstImage, user.webLoginKey);
515 }
516 }
517 catch (Exception e)
518 {
519 database.Reconnect();
520 m_log.Error(e.ToString());
521 }
522 }
523
524 /// <summary>
525 /// Creates a new user and inserts it into the database
526 /// </summary>
527 /// <param name="uuid">User ID</param>
528 /// <param name="username">First part of the login</param>
529 /// <param name="lastname">Second part of the login</param>
530 /// <param name="passwordHash">A salted hash of the users password</param>
531 /// <param name="passwordSalt">The salt used for the password hash</param>
532 /// <param name="homeRegion">A regionHandle of the users home region</param>
533 /// <param name="homeLocX">Home region position vector</param>
534 /// <param name="homeLocY">Home region position vector</param>
535 /// <param name="homeLocZ">Home region position vector</param>
536 /// <param name="homeLookAtX">Home region 'look at' vector</param>
537 /// <param name="homeLookAtY">Home region 'look at' vector</param>
538 /// <param name="homeLookAtZ">Home region 'look at' vector</param>
539 /// <param name="created">Account created (unix timestamp)</param>
540 /// <param name="lastlogin">Last login (unix timestamp)</param>
541 /// <param name="inventoryURI">Users inventory URI</param>
542 /// <param name="assetURI">Users asset URI</param>
543 /// <param name="canDoMask">I can do mask</param>
544 /// <param name="wantDoMask">I want to do mask</param>
545 /// <param name="aboutText">Profile text</param>
546 /// <param name="firstText">Firstlife text</param>
547 /// <param name="profileImage">UUID for profile image</param>
548 /// <param name="firstImage">UUID for firstlife image</param>
549 /// <returns>Success?</returns>
550 private bool InsertUserRow(LLUUID uuid, string username, string lastname, string passwordHash,
551 string passwordSalt, UInt64 homeRegion, float homeLocX, float homeLocY, float homeLocZ,
552 float homeLookAtX, float homeLookAtY, float homeLookAtZ, int created, int lastlogin,
553 string inventoryURI, string assetURI, uint canDoMask, uint wantDoMask,
554 string aboutText, string firstText,
555 LLUUID profileImage, LLUUID firstImage, LLUUID webLoginKey)
556 {
557 string sql = "INSERT INTO "+m_usersTableName;
558 sql += " ([UUID], [username], [lastname], [passwordHash], [passwordSalt], [homeRegion], ";
559 sql +=
560 "[homeLocationX], [homeLocationY], [homeLocationZ], [homeLookAtX], [homeLookAtY], [homeLookAtZ], [created], ";
561 sql +=
562 "[lastLogin], [userInventoryURI], [userAssetURI], [profileCanDoMask], [profileWantDoMask], [profileAboutText], ";
563 sql += "[profileFirstText], [profileImage], [profileFirstImage], [webLoginKey]) VALUES ";
564
565 sql += "(@UUID, @username, @lastname, @passwordHash, @passwordSalt, @homeRegion, ";
566 sql +=
567 "@homeLocationX, @homeLocationY, @homeLocationZ, @homeLookAtX, @homeLookAtY, @homeLookAtZ, @created, ";
568 sql +=
569 "@lastLogin, @userInventoryURI, @userAssetURI, @profileCanDoMask, @profileWantDoMask, @profileAboutText, ";
570 sql += "@profileFirstText, @profileImage, @profileFirstImage, @webLoginKey);";
571
572 Dictionary<string, string> parameters = new Dictionary<string, string>();
573 parameters["UUID"] = uuid.ToString();
574 parameters["username"] = username.ToString();
575 parameters["lastname"] = lastname.ToString();
576 parameters["passwordHash"] = passwordHash.ToString();
577 parameters["passwordSalt"] = passwordSalt.ToString();
578 parameters["homeRegion"] = homeRegion.ToString();
579 parameters["homeLocationX"] = homeLocX.ToString();
580 parameters["homeLocationY"] = homeLocY.ToString();
581 parameters["homeLocationZ"] = homeLocZ.ToString();
582 parameters["homeLookAtX"] = homeLookAtX.ToString();
583 parameters["homeLookAtY"] = homeLookAtY.ToString();
584 parameters["homeLookAtZ"] = homeLookAtZ.ToString();
585 parameters["created"] = created.ToString();
586 parameters["lastLogin"] = lastlogin.ToString();
587 parameters["userInventoryURI"] = String.Empty;
588 parameters["userAssetURI"] = String.Empty;
589 parameters["profileCanDoMask"] = "0";
590 parameters["profileWantDoMask"] = "0";
591 parameters["profileAboutText"] = aboutText;
592 parameters["profileFirstText"] = firstText;
593 parameters["profileImage"] = profileImage.ToString();
594 parameters["profileFirstImage"] = firstImage.ToString();
595 parameters["webLoginKey"] = LLUUID.Random().ToString();
596
597 bool returnval = false;
598
599 try
600 {
601 IDbCommand result = database.Query(sql, parameters);
602
603 if (result.ExecuteNonQuery() == 1)
604 returnval = true;
605
606 result.Dispose();
607 }
608 catch (Exception e)
609 {
610 m_log.Error(e.ToString());
611 return false;
612 }
613
614 return returnval;
615 }
616
617 /// <summary>
618 /// Creates a new agent
619 /// </summary>
620 /// <param name="agent">The agent to create</param>
621 override public void AddNewUserAgent(UserAgentData agent)
622 {
623 // Do nothing.
624 }
625
626
627 override public bool UpdateUserProfile(UserProfileData user)
628 {
629 SqlCommand command = new SqlCommand("UPDATE " + m_usersTableName + " set UUID = @uuid, " +
630 "username = @username, " +
631 "lastname = @lastname," +
632 "passwordHash = @passwordHash," +
633 "passwordSalt = @passwordSalt," +
634 "homeRegion = @homeRegion," +
635 "homeLocationX = @homeLocationX," +
636 "homeLocationY = @homeLocationY," +
637 "homeLocationZ = @homeLocationZ," +
638 "homeLookAtX = @homeLookAtX," +
639 "homeLookAtY = @homeLookAtY," +
640 "homeLookAtZ = @homeLookAtZ," +
641 "created = @created," +
642 "lastLogin = @lastLogin," +
643 "userInventoryURI = @userInventoryURI," +
644 "userAssetURI = @userAssetURI," +
645 "profileCanDoMask = @profileCanDoMask," +
646 "profileWantDoMask = @profileWantDoMask," +
647 "profileAboutText = @profileAboutText," +
648 "profileFirstText = @profileFirstText," +
649 "profileImage = @profileImage," +
650 "profileFirstImage = @profileFirstImage, " +
651 "webLoginKey = @webLoginKey where " +
652 "UUID = @keyUUUID;", database.getConnection());
653 SqlParameter param1 = new SqlParameter("@uuid", user.UUID.ToString());
654 SqlParameter param2 = new SqlParameter("@username", user.username);
655 SqlParameter param3 = new SqlParameter("@lastname", user.surname);
656 SqlParameter param4 = new SqlParameter("@passwordHash", user.passwordHash);
657 SqlParameter param5 = new SqlParameter("@passwordSalt", user.passwordSalt);
658 SqlParameter param6 = new SqlParameter("@homeRegion", Convert.ToInt64(user.homeRegion));
659 SqlParameter param7 = new SqlParameter("@homeLocationX", user.homeLocation.X);
660 SqlParameter param8 = new SqlParameter("@homeLocationY", user.homeLocation.Y);
661 SqlParameter param9 = new SqlParameter("@homeLocationZ", user.homeLocation.Y);
662 SqlParameter param10 = new SqlParameter("@homeLookAtX", user.homeLookAt.X);
663 SqlParameter param11 = new SqlParameter("@homeLookAtY", user.homeLookAt.Y);
664 SqlParameter param12 = new SqlParameter("@homeLookAtZ", user.homeLookAt.Z);
665 SqlParameter param13 = new SqlParameter("@created", Convert.ToInt32(user.created));
666 SqlParameter param14 = new SqlParameter("@lastLogin", Convert.ToInt32(user.lastLogin));
667 SqlParameter param15 = new SqlParameter("@userInventoryURI", user.userInventoryURI);
668 SqlParameter param16 = new SqlParameter("@userAssetURI", user.userAssetURI);
669 SqlParameter param17 = new SqlParameter("@profileCanDoMask", Convert.ToInt32(user.profileCanDoMask));
670 SqlParameter param18 = new SqlParameter("@profileWantDoMask", Convert.ToInt32(user.profileWantDoMask));
671 SqlParameter param19 = new SqlParameter("@profileAboutText", user.profileAboutText);
672 SqlParameter param20 = new SqlParameter("@profileFirstText", user.profileFirstText);
673 SqlParameter param21 = new SqlParameter("@profileImage", user.profileImage.ToString());
674 SqlParameter param22 = new SqlParameter("@profileFirstImage", user.profileFirstImage.ToString());
675 SqlParameter param23 = new SqlParameter("@keyUUUID", user.UUID.ToString());
676 SqlParameter param24 = new SqlParameter("@webLoginKey", user.webLoginKey.UUID.ToString());
677 command.Parameters.Add(param1);
678 command.Parameters.Add(param2);
679 command.Parameters.Add(param3);
680 command.Parameters.Add(param4);
681 command.Parameters.Add(param5);
682 command.Parameters.Add(param6);
683 command.Parameters.Add(param7);
684 command.Parameters.Add(param8);
685 command.Parameters.Add(param9);
686 command.Parameters.Add(param10);
687 command.Parameters.Add(param11);
688 command.Parameters.Add(param12);
689 command.Parameters.Add(param13);
690 command.Parameters.Add(param14);
691 command.Parameters.Add(param15);
692 command.Parameters.Add(param16);
693 command.Parameters.Add(param17);
694 command.Parameters.Add(param18);
695 command.Parameters.Add(param19);
696 command.Parameters.Add(param20);
697 command.Parameters.Add(param21);
698 command.Parameters.Add(param22);
699 command.Parameters.Add(param23);
700 command.Parameters.Add(param24);
701 try
702 {
703 int affected = command.ExecuteNonQuery();
704 if (affected != 0)
705 {
706 return true;
707 }
708 else
709 {
710 return false;
711 }
712 }
713 catch (Exception e)
714 {
715 m_log.Error(e.ToString());
716 }
717 return false;
718 }
719
720 /// <summary>
721 /// Performs a money transfer request between two accounts
722 /// </summary>
723 /// <param name="from">The senders account ID</param>
724 /// <param name="to">The receivers account ID</param>
725 /// <param name="amount">The amount to transfer</param>
726 /// <returns>Success?</returns>
727 override public bool MoneyTransferRequest(LLUUID from, LLUUID to, uint amount)
728 {
729 return false;
730 }
731
732 /// <summary>
733 /// Performs an inventory transfer request between two accounts
734 /// </summary>
735 /// <remarks>TODO: Move to inventory server</remarks>
736 /// <param name="from">The senders account ID</param>
737 /// <param name="to">The receivers account ID</param>
738 /// <param name="item">The item to transfer</param>
739 /// <returns>Success?</returns>
740 override public bool InventoryTransferRequest(LLUUID from, LLUUID to, LLUUID item)
741 {
742 return false;
743 }
744
745 /// <summary>
746 /// Database provider name
747 /// </summary>
748 /// <returns>Provider name</returns>
749 override public string getName()
750 {
751 return "MSSQL Userdata Interface";
752 }
753
754 /// <summary>
755 /// Database provider version
756 /// </summary>
757 /// <returns>provider version</returns>
758 override public string GetVersion()
759 {
760 return database.getVersion();
761 }
762
763 /// <summary>
764 /// Not implemented
765 /// </summary>
766 /// <param name="query"></param>
767 public void runQuery(string query)
768 {
769 }
770 }
771}
diff --git a/OpenSim/Data/MSSQL/Properties/AssemblyInfo.cs b/OpenSim/Data/MSSQL/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..f6ac328
--- /dev/null
+++ b/OpenSim/Data/MSSQL/Properties/AssemblyInfo.cs
@@ -0,0 +1,65 @@
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 OpenSim 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.Reflection;
29using System.Runtime.InteropServices;
30
31// General Information about an assembly is controlled through the following
32// set of attributes. Change these attribute values to modify the information
33// associated with an assembly.
34
35[assembly : AssemblyTitle("OpenSim.Framework.Data.MSSQL")]
36[assembly : AssemblyDescription("")]
37[assembly : AssemblyConfiguration("")]
38[assembly : AssemblyCompany("")]
39[assembly : AssemblyProduct("OpenSim.Framework.Data.MSSQL")]
40[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers 2007-2008")]
41[assembly : AssemblyTrademark("")]
42[assembly : AssemblyCulture("")]
43
44// Setting ComVisible to false makes the types in this assembly not visible
45// to COM components. If you need to access a type in this assembly from
46// COM, set the ComVisible attribute to true on that type.
47
48[assembly : ComVisible(false)]
49
50// The following GUID is for the ID of the typelib if this project is exposed to COM
51
52[assembly : Guid("0e1c1ca4-2cf2-4315-b0e7-432c02feea8a")]
53
54// Version information for an assembly consists of the following four values:
55//
56// Major Version
57// Minor Version
58// Build Number
59// Revision
60//
61// You can specify all the values or you can default the Revision and Build Numbers
62// by using the '*' as shown below:
63
64[assembly : AssemblyVersion("1.0.0.0")]
65[assembly : AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Data/MSSQL/Resources/AvatarAppearance.sql b/OpenSim/Data/MSSQL/Resources/AvatarAppearance.sql
new file mode 100644
index 0000000..ccefba2
--- /dev/null
+++ b/OpenSim/Data/MSSQL/Resources/AvatarAppearance.sql
@@ -0,0 +1,44 @@
1--
2-- Create schema avatar_appearance
3--
4
5SET ANSI_NULLS ON
6SET QUOTED_IDENTIFIER ON
7SET ANSI_PADDING ON
8
9CREATE TABLE [avatarappearance] (
10 [UUID] uniqueidentifier NOT NULL,
11 [Serial] int NOT NULL,
12 [WearableItem0] uniqueidentifier NOT NULL,
13 [WearableAsset0] uniqueidentifier NOT NULL,
14 [WearableItem1] uniqueidentifier NOT NULL,
15 [WearableAsset1] uniqueidentifier NOT NULL,
16 [WearableItem2] uniqueidentifier NOT NULL,
17 [WearableAsset2] uniqueidentifier NOT NULL,
18 [WearableItem3] uniqueidentifier NOT NULL,
19 [WearableAsset3] uniqueidentifier NOT NULL,
20 [WearableItem4] uniqueidentifier NOT NULL,
21 [WearableAsset4] uniqueidentifier NOT NULL,
22 [WearableItem5] uniqueidentifier NOT NULL,
23 [WearableAsset5] uniqueidentifier NOT NULL,
24 [WearableItem6] uniqueidentifier NOT NULL,
25 [WearableAsset6] uniqueidentifier NOT NULL,
26 [WearableItem7] uniqueidentifier NOT NULL,
27 [WearableAsset7] uniqueidentifier NOT NULL,
28 [WearableItem8] uniqueidentifier NOT NULL,
29 [WearableAsset8] uniqueidentifier NOT NULL,
30 [WearableItem9] uniqueidentifier NOT NULL,
31 [WearableAsset9] uniqueidentifier NOT NULL,
32 [WearableItem10] uniqueidentifier NOT NULL,
33 [WearableAsset10] uniqueidentifier NOT NULL,
34 [WearableItem11] uniqueidentifier NOT NULL,
35 [WearableAsset11] uniqueidentifier NOT NULL,
36 [WearableItem12] uniqueidentifier NOT NULL,
37 [WearableAsset12] uniqueidentifier NOT NULL
38
39 PRIMARY KEY CLUSTERED (
40 [UUID]
41 ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
42) ON [PRIMARY]
43
44SET ANSI_PADDING OFF
diff --git a/OpenSim/Data/MSSQL/Resources/CreateAssetsTable.sql b/OpenSim/Data/MSSQL/Resources/CreateAssetsTable.sql
new file mode 100644
index 0000000..c7cb21a
--- /dev/null
+++ b/OpenSim/Data/MSSQL/Resources/CreateAssetsTable.sql
@@ -0,0 +1,19 @@
1SET ANSI_NULLS ON
2SET QUOTED_IDENTIFIER ON
3SET ANSI_PADDING ON
4CREATE TABLE [assets] (
5 [id] [varchar](36) NOT NULL,
6 [name] [varchar](64) NOT NULL,
7 [description] [varchar](64) NOT NULL,
8 [assetType] [tinyint] NOT NULL,
9 [invType] [tinyint] NOT NULL,
10 [local] [tinyint] NOT NULL,
11 [temporary] [tinyint] NOT NULL,
12 [data] [image] NOT NULL,
13PRIMARY KEY CLUSTERED
14(
15 [id] ASC
16)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
17) ON [PRIMARY]
18
19SET ANSI_PADDING OFF
diff --git a/OpenSim/Data/MSSQL/Resources/CreateFoldersTable.sql b/OpenSim/Data/MSSQL/Resources/CreateFoldersTable.sql
new file mode 100644
index 0000000..95d183a
--- /dev/null
+++ b/OpenSim/Data/MSSQL/Resources/CreateFoldersTable.sql
@@ -0,0 +1,27 @@
1SET ANSI_NULLS ON
2SET QUOTED_IDENTIFIER ON
3SET ANSI_PADDING ON
4CREATE TABLE [inventoryfolders] (
5 [folderID] [varchar](36) NOT NULL default '',
6 [agentID] [varchar](36) default NULL,
7 [parentFolderID] [varchar](36) default NULL,
8 [folderName] [varchar](64) default NULL,
9 [type] [smallint] NOT NULL default 0,
10 [version] [int] NOT NULL default 0,
11 PRIMARY KEY CLUSTERED
12(
13 [folderID] ASC
14)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
15) ON [PRIMARY]
16
17CREATE NONCLUSTERED INDEX [owner] ON [inventoryfolders]
18(
19 [agentID] ASC
20)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
21
22CREATE NONCLUSTERED INDEX [parent] ON [inventoryfolders]
23(
24 [parentFolderID] ASC
25)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
26
27SET ANSI_PADDING OFF
diff --git a/OpenSim/Data/MSSQL/Resources/CreateItemsTable.sql b/OpenSim/Data/MSSQL/Resources/CreateItemsTable.sql
new file mode 100644
index 0000000..5bb27ba
--- /dev/null
+++ b/OpenSim/Data/MSSQL/Resources/CreateItemsTable.sql
@@ -0,0 +1,39 @@
1SET ANSI_NULLS ON
2
3SET QUOTED_IDENTIFIER ON
4
5SET ANSI_PADDING ON
6
7CREATE TABLE [inventoryitems] (
8 [inventoryID] [varchar](36) NOT NULL default '',
9 [assetID] [varchar](36) default NULL,
10 [assetType] [int] default NULL,
11 [parentFolderID] [varchar](36) default NULL,
12 [avatarID] [varchar](36) default NULL,
13 [inventoryName] [varchar](64) default NULL,
14 [inventoryDescription] [varchar](128) default NULL,
15 [inventoryNextPermissions] [int] default NULL,
16 [inventoryCurrentPermissions] [int] default NULL,
17 [invType] [int] default NULL,
18 [creatorID] [varchar](36) default NULL,
19 [inventoryBasePermissions] [int] NOT NULL default 0,
20 [inventoryEveryOnePermissions] [int] NOT NULL default 0,
21 PRIMARY KEY CLUSTERED
22(
23 [inventoryID] ASC
24)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
25) ON [PRIMARY]
26
27
28CREATE NONCLUSTERED INDEX [owner] ON [inventoryitems]
29(
30 [avatarID] ASC
31)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
32
33CREATE NONCLUSTERED INDEX [folder] ON [inventoryitems]
34(
35 [parentFolderID] ASC
36)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
37
38SET ANSI_PADDING OFF
39
diff --git a/OpenSim/Data/MSSQL/Resources/CreateUserFriendsTable.sql b/OpenSim/Data/MSSQL/Resources/CreateUserFriendsTable.sql
new file mode 100644
index 0000000..6f5885e
--- /dev/null
+++ b/OpenSim/Data/MSSQL/Resources/CreateUserFriendsTable.sql
@@ -0,0 +1,14 @@
1SET ANSI_NULLS ON
2
3SET QUOTED_IDENTIFIER ON
4
5SET ANSI_PADDING ON
6
7CREATE TABLE [dbo].[userfriends](
8[ownerID] [varchar](50) COLLATE Latin1_General_CI_AS NOT NULL,
9[friendID] [varchar](50) COLLATE Latin1_General_CI_AS NOT NULL,
10[friendPerms] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
11[datetimestamp] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL
12) ON [PRIMARY]
13
14SET ANSI_PADDING OFF
diff --git a/OpenSim/Data/MSSQL/Resources/Mssql-agents.sql b/OpenSim/Data/MSSQL/Resources/Mssql-agents.sql
new file mode 100644
index 0000000..ad53173
--- /dev/null
+++ b/OpenSim/Data/MSSQL/Resources/Mssql-agents.sql
@@ -0,0 +1,37 @@
1SET ANSI_NULLS ON
2
3SET QUOTED_IDENTIFIER ON
4
5SET ANSI_PADDING ON
6
7CREATE TABLE [agents] (
8 [UUID] [varchar](36) NOT NULL,
9 [sessionID] [varchar](36) NOT NULL,
10 [secureSessionID] [varchar](36) NOT NULL,
11 [agentIP] [varchar](16) NOT NULL,
12 [agentPort] [int] NOT NULL,
13 [agentOnline] [tinyint] NOT NULL,
14 [loginTime] [int] NOT NULL,
15 [logoutTime] [int] NOT NULL,
16 [currentRegion] [varchar](36) NOT NULL,
17 [currentHandle] [bigint] NOT NULL,
18 [currentPos] [varchar](64) NOT NULL,
19 PRIMARY KEY CLUSTERED
20(
21 [UUID] ASC
22)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
23) ON [PRIMARY]
24
25
26CREATE NONCLUSTERED INDEX [session] ON [agents]
27(
28 [sessionID] ASC
29)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
30
31CREATE NONCLUSTERED INDEX [ssession] ON [agents]
32(
33 [secureSessionID] ASC
34)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
35
36SET ANSI_PADDING OFF
37
diff --git a/OpenSim/Data/MSSQL/Resources/Mssql-logs.sql b/OpenSim/Data/MSSQL/Resources/Mssql-logs.sql
new file mode 100644
index 0000000..3b747d8
--- /dev/null
+++ b/OpenSim/Data/MSSQL/Resources/Mssql-logs.sql
@@ -0,0 +1,20 @@
1SET ANSI_NULLS ON
2
3SET QUOTED_IDENTIFIER ON
4
5SET ANSI_PADDING ON
6
7CREATE TABLE [logs] (
8 [logID] [int] NOT NULL,
9 [target] [varchar](36) default NULL,
10 [server] [varchar](64) default NULL,
11 [method] [varchar](64) default NULL,
12 [arguments] [varchar](255) default NULL,
13 [priority] [int] default NULL,
14 [message] [ntext],
15 PRIMARY KEY CLUSTERED
16(
17 [logID] ASC
18)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
19) ON [PRIMARY]
20
diff --git a/OpenSim/Data/MSSQL/Resources/Mssql-regions.sql b/OpenSim/Data/MSSQL/Resources/Mssql-regions.sql
new file mode 100644
index 0000000..b29a2ab
--- /dev/null
+++ b/OpenSim/Data/MSSQL/Resources/Mssql-regions.sql
@@ -0,0 +1,41 @@
1SET ANSI_NULLS ON
2
3SET QUOTED_IDENTIFIER ON
4
5SET ANSI_PADDING ON
6
7CREATE TABLE [dbo].[regions](
8 [regionHandle] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
9 [regionName] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
10 [uuid] [varchar](255) COLLATE Latin1_General_CI_AS NOT NULL,
11 [regionRecvKey] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
12 [regionSecret] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
13 [regionSendKey] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
14 [regionDataURI] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
15 [serverIP] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
16 [serverPort] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
17 [serverURI] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
18 [locX] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
19 [locY] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
20 [locZ] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
21 [eastOverrideHandle] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
22 [westOverrideHandle] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
23 [southOverrideHandle] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
24 [northOverrideHandle] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
25 [regionAssetURI] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
26 [regionAssetRecvKey] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
27 [regionAssetSendKey] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
28 [regionUserURI] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
29 [regionUserRecvKey] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
30 [regionUserSendKey] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
31 [regionMapTexture] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
32 [serverHttpPort] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
33 [serverRemotingPort] [varchar](255) COLLATE Latin1_General_CI_AS NULL,
34 [owner_uuid] [varchar](36) COLLATE Latin1_General_CI_AS NULL,
35PRIMARY KEY CLUSTERED
36(
37 [uuid] ASC
38)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
39) ON [PRIMARY]
40
41SET ANSI_PADDING OFF
diff --git a/OpenSim/Data/MSSQL/Resources/Mssql-users.sql b/OpenSim/Data/MSSQL/Resources/Mssql-users.sql
new file mode 100644
index 0000000..abcc091
--- /dev/null
+++ b/OpenSim/Data/MSSQL/Resources/Mssql-users.sql
@@ -0,0 +1,42 @@
1SET ANSI_NULLS ON
2
3SET QUOTED_IDENTIFIER ON
4
5SET ANSI_PADDING ON
6
7CREATE TABLE [users] (
8 [UUID] [varchar](36) NOT NULL default '',
9 [username] [varchar](32) NOT NULL,
10 [lastname] [varchar](32) NOT NULL,
11 [passwordHash] [varchar](32) NOT NULL,
12 [passwordSalt] [varchar](32) NOT NULL,
13 [homeRegion] [bigint] default NULL,
14 [homeLocationX] [float] default NULL,
15 [homeLocationY] [float] default NULL,
16 [homeLocationZ] [float] default NULL,
17 [homeLookAtX] [float] default NULL,
18 [homeLookAtY] [float] default NULL,
19 [homeLookAtZ] [float] default NULL,
20 [created] [int] NOT NULL,
21 [lastLogin] [int] NOT NULL,
22 [userInventoryURI] [varchar](255) default NULL,
23 [userAssetURI] [varchar](255) default NULL,
24 [profileCanDoMask] [int] default NULL,
25 [profileWantDoMask] [int] default NULL,
26 [profileAboutText] [ntext],
27 [profileFirstText] [ntext],
28 [profileImage] [varchar](36) default NULL,
29 [profileFirstImage] [varchar](36) default NULL,
30 [webLoginKey] [varchar](36) default NULL,
31 PRIMARY KEY CLUSTERED
32(
33 [UUID] ASC
34)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
35) ON [PRIMARY]
36
37
38CREATE NONCLUSTERED INDEX [usernames] ON [users]
39(
40 [username] ASC,
41 [lastname] ASC
42)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
diff --git a/OpenSim/Data/MSSQLMapper/MSSQLDatabaseMapper.cs b/OpenSim/Data/MSSQLMapper/MSSQLDatabaseMapper.cs
new file mode 100644
index 0000000..81f9631
--- /dev/null
+++ b/OpenSim/Data/MSSQLMapper/MSSQLDatabaseMapper.cs
@@ -0,0 +1,65 @@
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 OpenSim 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.Common;
30using System.Data.SqlClient;
31using OpenSim.Framework.Data;
32
33namespace OpenSim.Framework.Data.MSSQLMapper
34{
35 public class MSSQLDatabaseMapper : OpenSimDatabaseConnector
36 {
37 public MSSQLDatabaseMapper(string connectionString)
38 : base(connectionString)
39 {
40 }
41
42 public override DbConnection GetNewConnection()
43 {
44 SqlConnection connection = new SqlConnection(m_connectionString);
45 return connection;
46 }
47
48 public override object ConvertToDbType(object value)
49 {
50 if( value is UInt32 )
51 {
52 UInt32 tmpVal = (UInt32) value;
53 Int64 result = Convert.ToInt64(tmpVal);
54 return result;
55 }
56
57 return base.ConvertToDbType(value);
58 }
59
60 public override string CreateParamName(string fieldName)
61 {
62 return "@" + fieldName;
63 }
64 }
65} \ No newline at end of file
diff --git a/OpenSim/Data/MapperFactory/DataMapperFactory.cs b/OpenSim/Data/MapperFactory/DataMapperFactory.cs
new file mode 100644
index 0000000..8995b9e
--- /dev/null
+++ b/OpenSim/Data/MapperFactory/DataMapperFactory.cs
@@ -0,0 +1,27 @@
1using System;
2using OpenSim.Framework.Data.Base;
3using OpenSim.Framework.Data.MSSQLMapper;
4using OpenSim.Framework.Data.MySQLMapper;
5
6namespace OpenSim.Framework.Data.MapperFactory
7{
8 public class DataMapperFactory
9 {
10 public enum MAPPER_TYPE {
11 MySQL,
12 MSSQL,
13 };
14
15 static public BaseDatabaseConnector GetDataBaseMapper(MAPPER_TYPE type, string connectionString)
16 {
17 switch (type) {
18 case MAPPER_TYPE.MySQL:
19 return new MySQLDatabaseMapper(connectionString);
20 case MAPPER_TYPE.MSSQL:
21 return new MSSQLDatabaseMapper(connectionString);
22 default:
23 throw new ArgumentException("Unknown Database Mapper type [" + type + "].");
24 }
25 }
26 }
27}
diff --git a/OpenSim/Data/MySQL/MySQLAssetData.cs b/OpenSim/Data/MySQL/MySQLAssetData.cs
new file mode 100644
index 0000000..79994ae
--- /dev/null
+++ b/OpenSim/Data/MySQL/MySQLAssetData.cs
@@ -0,0 +1,198 @@
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 OpenSim 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 libsecondlife;
32using MySql.Data.MySqlClient;
33using OpenSim.Framework.Console;
34
35namespace OpenSim.Framework.Data.MySQL
36{
37 internal class MySQLAssetData : AssetDataBase, IPlugin
38 {
39 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
40
41 private MySQLManager _dbConnection;
42
43 #region IAssetProvider Members
44
45 private void UpgradeAssetsTable(string oldVersion)
46 {
47 // null as the version, indicates that the table didn't exist
48 if (oldVersion == null)
49 {
50 m_log.Info("[ASSETS]: Creating new database tables");
51 _dbConnection.ExecuteResourceSql("CreateAssetsTable.sql");
52 return;
53 }
54 }
55
56 /// <summary>
57 /// Ensure that the assets related tables exists and are at the latest version
58 /// </summary>
59 private void TestTables()
60 {
61 Dictionary<string, string> tableList = new Dictionary<string, string>();
62
63 tableList["assets"] = null;
64 _dbConnection.GetTableVersion(tableList);
65
66 UpgradeAssetsTable(tableList["assets"]);
67 }
68
69 override public AssetBase FetchAsset(LLUUID assetID)
70 {
71 AssetBase asset = null;
72 lock (_dbConnection)
73 {
74 MySqlCommand cmd =
75 new MySqlCommand(
76 "SELECT name, description, assetType, invType, local, temporary, data FROM assets WHERE id=?id",
77 _dbConnection.Connection);
78 MySqlParameter p = cmd.Parameters.Add("?id", MySqlDbType.Binary, 16);
79 p.Value = assetID.GetBytes();
80
81 try
82 {
83 using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow))
84 {
85 if (dbReader.Read())
86 {
87 asset = new AssetBase();
88 asset.Data = (byte[]) dbReader["data"];
89 asset.Description = (string) dbReader["description"];
90 asset.FullID = assetID;
91 asset.InvType = (sbyte) dbReader["invType"];
92 asset.Local = ((sbyte) dbReader["local"]) != 0 ? true : false;
93 asset.Name = (string) dbReader["name"];
94 asset.Type = (sbyte) dbReader["assetType"];
95 }
96 dbReader.Close();
97 cmd.Dispose();
98 }
99 }
100 catch (Exception e)
101 {
102 m_log.ErrorFormat(
103 "[ASSETS]: MySql failure fetching asset {0}" + Environment.NewLine + e.ToString()
104 + Environment.NewLine + "Attempting reconnection", assetID);
105 _dbConnection.Reconnect();
106 }
107 }
108 return asset;
109 }
110
111 override public void CreateAsset(AssetBase asset)
112 {
113 lock (_dbConnection)
114 {
115 MySqlCommand cmd =
116 new MySqlCommand(
117 "REPLACE INTO assets(id, name, description, assetType, invType, local, temporary, data)" +
118 "VALUES(?id, ?name, ?description, ?assetType, ?invType, ?local, ?temporary, ?data)",
119 _dbConnection.Connection);
120
121 // need to ensure we dispose
122 try
123 {
124 using (cmd)
125 {
126 MySqlParameter p = cmd.Parameters.Add("?id", MySqlDbType.Binary, 16);
127 p.Value = asset.FullID.GetBytes();
128 cmd.Parameters.AddWithValue("?name", asset.Name);
129 cmd.Parameters.AddWithValue("?description", asset.Description);
130 cmd.Parameters.AddWithValue("?assetType", asset.Type);
131 cmd.Parameters.AddWithValue("?invType", asset.InvType);
132 cmd.Parameters.AddWithValue("?local", asset.Local);
133 cmd.Parameters.AddWithValue("?temporary", asset.Temporary);
134 cmd.Parameters.AddWithValue("?data", asset.Data);
135 cmd.ExecuteNonQuery();
136 cmd.Dispose();
137 }
138 }
139 catch (Exception e)
140 {
141 m_log.ErrorFormat(
142 "[ASSETS]: " +
143 "MySql failure creating asset {0} with name {1}" + Environment.NewLine + e.ToString()
144 + Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name);
145 _dbConnection.Reconnect();
146 }
147 }
148 }
149
150 override public void UpdateAsset(AssetBase asset)
151 {
152 CreateAsset(asset);
153 }
154
155 override public bool ExistsAsset(LLUUID uuid)
156 {
157 throw new Exception("The method or operation is not implemented.");
158 }
159
160 /// <summary>
161 /// All writes are immediately commited to the database, so this is a no-op
162 /// </summary>
163 override public void CommitAssets()
164 {
165 }
166
167 #endregion
168
169 #region IPlugin Members
170
171 override public void Initialise()
172 {
173 IniFile GridDataMySqlFile = new IniFile("mysql_connection.ini");
174 string hostname = GridDataMySqlFile.ParseFileReadValue("hostname");
175 string database = GridDataMySqlFile.ParseFileReadValue("database");
176 string username = GridDataMySqlFile.ParseFileReadValue("username");
177 string password = GridDataMySqlFile.ParseFileReadValue("password");
178 string pooling = GridDataMySqlFile.ParseFileReadValue("pooling");
179 string port = GridDataMySqlFile.ParseFileReadValue("port");
180
181 _dbConnection = new MySQLManager(hostname, database, username, password, pooling, port);
182
183 TestTables();
184 }
185
186 override public string Version
187 {
188 get { return _dbConnection.getVersion(); }
189 }
190
191 override public string Name
192 {
193 get { return "MySQL Asset storage engine"; }
194 }
195
196 #endregion
197 }
198}
diff --git a/OpenSim/Data/MySQL/MySQLDataStore.cs b/OpenSim/Data/MySQL/MySQLDataStore.cs
new file mode 100644
index 0000000..eaa7f14
--- /dev/null
+++ b/OpenSim/Data/MySQL/MySQLDataStore.cs
@@ -0,0 +1,1722 @@
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 OpenSim 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.Diagnostics;
32using System.IO;
33using libsecondlife;
34using MySql.Data.MySqlClient;
35using OpenSim.Framework.Console;
36using OpenSim.Region.Environment.Interfaces;
37using OpenSim.Region.Environment.Scenes;
38
39namespace OpenSim.Framework.Data.MySQL
40{
41 public class MySQLDataStore : IRegionDataStore
42 {
43 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
44
45 private const string m_primSelect = "select * from prims";
46 private const string m_shapeSelect = "select * from primshapes";
47 private const string m_itemsSelect = "select * from primitems";
48 private const string m_terrainSelect = "select * from terrain limit 1";
49 private const string m_landSelect = "select * from land";
50 private const string m_landAccessListSelect = "select * from landaccesslist";
51
52 private DataSet m_dataSet;
53 private MySqlDataAdapter m_primDataAdapter;
54 private MySqlDataAdapter m_shapeDataAdapter;
55 private MySqlDataAdapter m_itemsDataAdapter;
56 private MySqlConnection m_connection;
57 private MySqlDataAdapter m_terrainDataAdapter;
58 private MySqlDataAdapter m_landDataAdapter;
59 private MySqlDataAdapter m_landAccessListDataAdapter;
60
61 private DataTable m_primTable;
62 private DataTable m_shapeTable;
63 private DataTable m_itemsTable;
64 private DataTable m_terrainTable;
65 private DataTable m_landTable;
66 private DataTable m_landAccessListTable;
67
68 // Temporary attribute while this is experimental
69 private bool persistPrimInventories;
70
71 /***********************************************************************
72 *
73 * Public Interface Functions
74 *
75 **********************************************************************/
76
77 // see IRegionDataStore
78 public void Initialise(string connectionstring, bool persistPrimInventories)
79 {
80 m_dataSet = new DataSet();
81 this.persistPrimInventories = persistPrimInventories;
82
83 m_log.Info("[DATASTORE]: MySql - connecting: " + connectionstring);
84 m_connection = new MySqlConnection(connectionstring);
85
86 MySqlCommand primSelectCmd = new MySqlCommand(m_primSelect, m_connection);
87 m_primDataAdapter = new MySqlDataAdapter(primSelectCmd);
88
89 MySqlCommand shapeSelectCmd = new MySqlCommand(m_shapeSelect, m_connection);
90 m_shapeDataAdapter = new MySqlDataAdapter(shapeSelectCmd);
91
92 MySqlCommand itemsSelectCmd = new MySqlCommand(m_itemsSelect, m_connection);
93 m_itemsDataAdapter = new MySqlDataAdapter(itemsSelectCmd);
94
95 MySqlCommand terrainSelectCmd = new MySqlCommand(m_terrainSelect, m_connection);
96 m_terrainDataAdapter = new MySqlDataAdapter(terrainSelectCmd);
97
98 MySqlCommand landSelectCmd = new MySqlCommand(m_landSelect, m_connection);
99 m_landDataAdapter = new MySqlDataAdapter(landSelectCmd);
100
101 MySqlCommand landAccessListSelectCmd = new MySqlCommand(m_landAccessListSelect, m_connection);
102 m_landAccessListDataAdapter = new MySqlDataAdapter(landAccessListSelectCmd);
103
104 TestTables(m_connection);
105
106 lock (m_dataSet)
107 {
108 m_primTable = createPrimTable();
109 m_dataSet.Tables.Add(m_primTable);
110 SetupPrimCommands(m_primDataAdapter, m_connection);
111 m_primDataAdapter.Fill(m_primTable);
112
113 m_shapeTable = createShapeTable();
114 m_dataSet.Tables.Add(m_shapeTable);
115 SetupShapeCommands(m_shapeDataAdapter, m_connection);
116 m_shapeDataAdapter.Fill(m_shapeTable);
117
118 if (persistPrimInventories)
119 {
120 m_itemsTable = createItemsTable();
121 m_dataSet.Tables.Add(m_itemsTable);
122 SetupItemsCommands(m_itemsDataAdapter, m_connection);
123 m_itemsDataAdapter.Fill(m_itemsTable);
124 }
125
126 m_terrainTable = createTerrainTable();
127 m_dataSet.Tables.Add(m_terrainTable);
128 SetupTerrainCommands(m_terrainDataAdapter, m_connection);
129 m_terrainDataAdapter.Fill(m_terrainTable);
130
131 m_landTable = createLandTable();
132 m_dataSet.Tables.Add(m_landTable);
133 setupLandCommands(m_landDataAdapter, m_connection);
134 m_landDataAdapter.Fill(m_landTable);
135
136 m_landAccessListTable = createLandAccessListTable();
137 m_dataSet.Tables.Add(m_landAccessListTable);
138 setupLandAccessCommands(m_landAccessListDataAdapter, m_connection);
139 m_landAccessListDataAdapter.Fill(m_landAccessListTable);
140 }
141 }
142
143 public void StoreObject(SceneObjectGroup obj, LLUUID regionUUID)
144 {
145 lock (m_dataSet)
146 {
147 foreach (SceneObjectPart prim in obj.Children.Values)
148 {
149 if ((prim.ObjectFlags & (uint) LLObject.ObjectFlags.Physics) == 0)
150 {
151 m_log.Info("[DATASTORE]: Adding obj: " + obj.UUID + " to region: " + regionUUID);
152 addPrim(prim, obj.UUID, regionUUID);
153 }
154 else
155 {
156 // m_log.Info("[DATASTORE]: Ignoring Physical obj: " + obj.UUID + " in region: " + regionUUID);
157 }
158 }
159 Commit();
160 }
161 }
162
163 public void RemoveObject(LLUUID obj, LLUUID regionUUID)
164 {
165 m_log.InfoFormat("[DATASTORE]: Removing obj: {0} from region: {1}", obj.UUID, regionUUID);
166
167 DataTable prims = m_primTable;
168 DataTable shapes = m_shapeTable;
169
170 string selectExp = "SceneGroupID = '" + Util.ToRawUuidString(obj) + "'";
171 lock (m_dataSet)
172 {
173 DataRow[] primRows = prims.Select(selectExp);
174 foreach (DataRow row in primRows)
175 {
176 // Remove shapes row
177 LLUUID uuid = new LLUUID((string) row["UUID"]);
178 DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(uuid));
179 if (shapeRow != null)
180 {
181 shapeRow.Delete();
182 }
183
184 if (persistPrimInventories)
185 {
186 RemoveItems(uuid);
187 }
188
189 // Remove prim row
190 row.Delete();
191 }
192 Commit();
193 }
194 }
195
196 /// <summary>
197 /// Remove all persisted items of the given prim.
198 /// The caller must acquire the necessrary synchronization locks and commit or rollback changes.
199 /// </summary>
200 private void RemoveItems(LLUUID uuid)
201 {
202 String sql = String.Format("primID = '{0}'", uuid);
203 DataRow[] itemRows = m_itemsTable.Select(sql);
204
205 foreach (DataRow itemRow in itemRows)
206 {
207 itemRow.Delete();
208 }
209 }
210
211 /// <summary>
212 /// Load persisted objects from region storage.
213 /// </summary>
214 public List<SceneObjectGroup> LoadObjects(LLUUID regionUUID)
215 {
216 Dictionary<LLUUID, SceneObjectGroup> createdObjects = new Dictionary<LLUUID, SceneObjectGroup>();
217
218 List<SceneObjectGroup> retvals = new List<SceneObjectGroup>();
219
220 DataTable prims = m_primTable;
221 DataTable shapes = m_shapeTable;
222
223 string byRegion = "RegionUUID = '" + Util.ToRawUuidString(regionUUID) + "'";
224 string orderByParent = "ParentID ASC";
225
226 lock (m_dataSet)
227 {
228 DataRow[] primsForRegion = prims.Select(byRegion, orderByParent);
229 m_log.Info("[DATASTORE]: " +
230 "Loaded " + primsForRegion.Length + " prims for region: " + regionUUID);
231
232 foreach (DataRow primRow in primsForRegion)
233 {
234 try
235 {
236 string uuid = (string) primRow["UUID"];
237 string objID = (string) primRow["SceneGroupID"];
238
239 SceneObjectPart prim = buildPrim(primRow);
240
241 if (uuid == objID) //is new SceneObjectGroup ?
242 {
243 SceneObjectGroup group = new SceneObjectGroup();
244
245 DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID));
246 if (shapeRow != null)
247 {
248 prim.Shape = buildShape(shapeRow);
249 }
250 else
251 {
252 m_log.Info(
253 "No shape found for prim in storage, so setting default box shape");
254 prim.Shape = PrimitiveBaseShape.Default;
255 }
256 group.AddPart(prim);
257 group.RootPart = prim;
258
259 createdObjects.Add(group.UUID, group);
260 retvals.Add(group);
261 }
262 else
263 {
264 DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID));
265 if (shapeRow != null)
266 {
267 prim.Shape = buildShape(shapeRow);
268 }
269 else
270 {
271 m_log.Info(
272 "No shape found for prim in storage, so setting default box shape");
273 prim.Shape = PrimitiveBaseShape.Default;
274 }
275 createdObjects[new LLUUID(objID)].AddPart(prim);
276 }
277
278 if (persistPrimInventories)
279 {
280 LoadItems(prim);
281 }
282 }
283 catch (Exception e)
284 {
285 m_log.Error("[DATASTORE]: Failed create prim object, exception and data follows");
286 m_log.Info("[DATASTORE]: " + e.ToString());
287 foreach (DataColumn col in prims.Columns)
288 {
289 m_log.Info("[DATASTORE]: Col: " + col.ColumnName + " => " + primRow[col]);
290 }
291 }
292 }
293 }
294 return retvals;
295 }
296
297 /// <summary>
298 /// Load in a prim's persisted inventory.
299 /// </summary>
300 /// <param name="prim"></param>
301 private void LoadItems(SceneObjectPart prim)
302 {
303 //m_log.InfoFormat("[DATASTORE]: Loading inventory for {0}, {1}", prim.Name, prim.UUID);
304
305 DataTable dbItems = m_itemsTable;
306
307 String sql = String.Format("primID = '{0}'", prim.UUID.ToString());
308 DataRow[] dbItemRows = dbItems.Select(sql);
309
310 IList<TaskInventoryItem> inventory = new List<TaskInventoryItem>();
311
312 foreach (DataRow row in dbItemRows)
313 {
314 TaskInventoryItem item = buildItem(row);
315 inventory.Add(item);
316
317 //m_log.DebugFormat("[DATASTORE]: Restored item {0}, {1}", item.Name, item.ItemID);
318 }
319
320 prim.RestoreInventoryItems(inventory);
321
322 // XXX A nasty little hack to recover the folder id for the prim (which is currently stored in
323 // every item). This data should really be stored in the prim table itself.
324 if (dbItemRows.Length > 0)
325 {
326 prim.FolderID = inventory[0].ParentID;
327 }
328 }
329
330 public void StoreTerrain(double[,] ter, LLUUID regionID)
331 {
332 int revision = Util.UnixTimeSinceEpoch();
333 m_log.Info("[DATASTORE]: Storing terrain revision r" + revision.ToString());
334
335 DataTable terrain = m_dataSet.Tables["terrain"];
336 lock (m_dataSet)
337 {
338 MySqlCommand cmd = new MySqlCommand("insert into terrain(RegionUUID, Revision, Heightfield)" +
339 " values(?RegionUUID, ?Revision, ?Heightfield)", m_connection);
340 using (cmd)
341 {
342 cmd.Parameters.Add(new MySqlParameter("?RegionUUID", Util.ToRawUuidString(regionID)));
343 cmd.Parameters.Add(new MySqlParameter("?Revision", revision));
344 cmd.Parameters.Add(new MySqlParameter("?Heightfield", serializeTerrain(ter)));
345 cmd.ExecuteNonQuery();
346 }
347 }
348 }
349
350 public double[,] LoadTerrain(LLUUID regionID)
351 {
352 double[,] terret = new double[256,256];
353 terret.Initialize();
354
355 MySqlCommand cmd = new MySqlCommand(
356 @"select RegionUUID, Revision, Heightfield from terrain
357 where RegionUUID=?RegionUUID order by Revision desc limit 1"
358 , m_connection);
359
360 MySqlParameter param = new MySqlParameter();
361 cmd.Parameters.Add(new MySqlParameter("?RegionUUID", Util.ToRawUuidString(regionID)));
362
363 if (m_connection.State != ConnectionState.Open)
364 {
365 m_connection.Open();
366 }
367
368 lock (m_dataSet)
369 {
370 using (MySqlDataReader row = cmd.ExecuteReader())
371 {
372 int rev = 0;
373 if (row.Read())
374 {
375 MemoryStream str = new MemoryStream((byte[]) row["Heightfield"]);
376 BinaryReader br = new BinaryReader(str);
377 for (int x = 0; x < 256; x++)
378 {
379 for (int y = 0; y < 256; y++)
380 {
381 terret[x, y] = br.ReadDouble();
382 }
383 }
384 rev = (int) row["Revision"];
385 }
386 else
387 {
388 m_log.Info("[DATASTORE]: No terrain found for region");
389 return null;
390 }
391
392 m_log.Info("[DATASTORE]: Loaded terrain revision r" + rev.ToString());
393 }
394 }
395 return terret;
396 }
397
398 public void RemoveLandObject(LLUUID globalID)
399 {
400 lock (m_dataSet)
401 {
402 using (MySqlCommand cmd = new MySqlCommand("delete from land where UUID=?UUID", m_connection))
403 {
404 cmd.Parameters.Add(new MySqlParameter("?UUID", Util.ToRawUuidString(globalID)));
405 cmd.ExecuteNonQuery();
406 }
407
408 using (
409 MySqlCommand cmd = new MySqlCommand("delete from landaccesslist where LandUUID=?UUID", m_connection)
410 )
411 {
412 cmd.Parameters.Add(new MySqlParameter("?UUID", Util.ToRawUuidString(globalID)));
413 cmd.ExecuteNonQuery();
414 }
415 }
416 }
417
418 public void StoreLandObject(ILandObject parcel)
419 {
420 lock (m_dataSet)
421 {
422 DataTable land = m_landTable;
423 DataTable landaccesslist = m_landAccessListTable;
424
425 DataRow landRow = land.Rows.Find(Util.ToRawUuidString(parcel.landData.globalID));
426 if (landRow == null)
427 {
428 landRow = land.NewRow();
429 fillLandRow(landRow, parcel.landData, parcel.regionUUID);
430 land.Rows.Add(landRow);
431 }
432 else
433 {
434 fillLandRow(landRow, parcel.landData, parcel.regionUUID);
435 }
436
437 using (
438 MySqlCommand cmd =
439 new MySqlCommand("delete from landaccesslist where LandUUID=?LandUUID", m_connection))
440 {
441 cmd.Parameters.Add(new MySqlParameter("?LandUUID", Util.ToRawUuidString(parcel.landData.globalID)));
442 cmd.ExecuteNonQuery();
443 }
444
445 foreach (ParcelManager.ParcelAccessEntry entry in parcel.landData.parcelAccessList)
446 {
447 DataRow newAccessRow = landaccesslist.NewRow();
448 fillLandAccessRow(newAccessRow, entry, parcel.landData.globalID);
449 landaccesslist.Rows.Add(newAccessRow);
450 }
451
452 Commit();
453 }
454 }
455
456 public List<LandData> LoadLandObjects(LLUUID regionUUID)
457 {
458 List<LandData> landDataForRegion = new List<LandData>();
459 lock (m_dataSet)
460 {
461 DataTable land = m_landTable;
462 DataTable landaccesslist = m_landAccessListTable;
463 string searchExp = "RegionUUID = '" + Util.ToRawUuidString(regionUUID) + "'";
464 DataRow[] rawDataForRegion = land.Select(searchExp);
465 foreach (DataRow rawDataLand in rawDataForRegion)
466 {
467 LandData newLand = buildLandData(rawDataLand);
468 string accessListSearchExp = "LandUUID = '" + Util.ToRawUuidString(newLand.globalID) + "'";
469 DataRow[] rawDataForLandAccessList = landaccesslist.Select(accessListSearchExp);
470 foreach (DataRow rawDataLandAccess in rawDataForLandAccessList)
471 {
472 newLand.parcelAccessList.Add(buildLandAccessData(rawDataLandAccess));
473 }
474
475 landDataForRegion.Add(newLand);
476 }
477 }
478 return landDataForRegion;
479 }
480
481// TODO: unused
482// private void DisplayDataSet(DataSet ds, string title)
483// {
484// Debug.WriteLine(title);
485// //--- Loop through the DataTables
486// foreach (DataTable table in ds.Tables)
487// {
488// Debug.WriteLine("*** DataTable: " + table.TableName + "***");
489// //--- Loop through each DataTable's DataRows
490// foreach (DataRow row in table.Rows)
491// {
492// //--- Display the original values, if there are any.
493// if (row.HasVersion(DataRowVersion.Original))
494// {
495// Debug.Write("Original Row Values ===> ");
496// foreach (DataColumn column in table.Columns)
497// Debug.Write(column.ColumnName + " = " +
498// row[column, DataRowVersion.Original] + ", ");
499// Debug.WriteLine(String.Empty);
500// }
501// //--- Display the current values, if there are any.
502// if (row.HasVersion(DataRowVersion.Current))
503// {
504// Debug.Write("Current Row Values ====> ");
505// foreach (DataColumn column in table.Columns)
506// Debug.Write(column.ColumnName + " = " +
507// row[column, DataRowVersion.Current] + ", ");
508// Debug.WriteLine(String.Empty);
509// }
510// Debug.WriteLine(String.Empty);
511// }
512// }
513// }
514
515 public void Commit()
516 {
517 if (m_connection.State != ConnectionState.Open)
518 {
519 m_connection.Open();
520 }
521
522 lock (m_dataSet)
523 {
524 // DisplayDataSet(m_dataSet, "Region DataSet");
525
526 m_primDataAdapter.Update(m_primTable);
527 m_shapeDataAdapter.Update(m_shapeTable);
528
529 if (persistPrimInventories)
530 {
531 m_itemsDataAdapter.Update(m_itemsTable);
532 }
533
534 m_terrainDataAdapter.Update(m_terrainTable);
535 m_landDataAdapter.Update(m_landTable);
536 m_landAccessListDataAdapter.Update(m_landAccessListTable);
537
538 m_dataSet.AcceptChanges();
539 }
540 }
541
542
543 public void Shutdown()
544 {
545 Commit();
546 }
547
548 /***********************************************************************
549 *
550 * Database Definition Functions
551 *
552 * This should be db agnostic as we define them in ADO.NET terms
553 *
554 **********************************************************************/
555
556 private DataColumn createCol(DataTable dt, string name, Type type)
557 {
558 DataColumn col = new DataColumn(name, type);
559 dt.Columns.Add(col);
560 return col;
561 }
562
563 private DataTable createTerrainTable()
564 {
565 DataTable terrain = new DataTable("terrain");
566
567 createCol(terrain, "RegionUUID", typeof (String));
568 createCol(terrain, "Revision", typeof (Int32));
569 DataColumn heightField = createCol(terrain, "Heightfield", typeof (Byte[]));
570 return terrain;
571 }
572
573 private DataTable createPrimTable()
574 {
575 DataTable prims = new DataTable("prims");
576
577 createCol(prims, "UUID", typeof (String));
578 createCol(prims, "RegionUUID", typeof (String));
579 createCol(prims, "ParentID", typeof (Int32));
580 createCol(prims, "CreationDate", typeof (Int32));
581 createCol(prims, "Name", typeof (String));
582 createCol(prims, "SceneGroupID", typeof (String));
583 // various text fields
584 createCol(prims, "Text", typeof (String));
585 createCol(prims, "Description", typeof (String));
586 createCol(prims, "SitName", typeof (String));
587 createCol(prims, "TouchName", typeof (String));
588 // permissions
589 createCol(prims, "ObjectFlags", typeof (Int32));
590 createCol(prims, "CreatorID", typeof (String));
591 createCol(prims, "OwnerID", typeof (String));
592 createCol(prims, "GroupID", typeof (String));
593 createCol(prims, "LastOwnerID", typeof (String));
594 createCol(prims, "OwnerMask", typeof (Int32));
595 createCol(prims, "NextOwnerMask", typeof (Int32));
596 createCol(prims, "GroupMask", typeof (Int32));
597 createCol(prims, "EveryoneMask", typeof (Int32));
598 createCol(prims, "BaseMask", typeof (Int32));
599 // vectors
600 createCol(prims, "PositionX", typeof (Double));
601 createCol(prims, "PositionY", typeof (Double));
602 createCol(prims, "PositionZ", typeof (Double));
603 createCol(prims, "GroupPositionX", typeof (Double));
604 createCol(prims, "GroupPositionY", typeof (Double));
605 createCol(prims, "GroupPositionZ", typeof (Double));
606 createCol(prims, "VelocityX", typeof (Double));
607 createCol(prims, "VelocityY", typeof (Double));
608 createCol(prims, "VelocityZ", typeof (Double));
609 createCol(prims, "AngularVelocityX", typeof (Double));
610 createCol(prims, "AngularVelocityY", typeof (Double));
611 createCol(prims, "AngularVelocityZ", typeof (Double));
612 createCol(prims, "AccelerationX", typeof (Double));
613 createCol(prims, "AccelerationY", typeof (Double));
614 createCol(prims, "AccelerationZ", typeof (Double));
615 // quaternions
616 createCol(prims, "RotationX", typeof (Double));
617 createCol(prims, "RotationY", typeof (Double));
618 createCol(prims, "RotationZ", typeof (Double));
619 createCol(prims, "RotationW", typeof (Double));
620 // sit target
621 createCol(prims, "SitTargetOffsetX", typeof (Double));
622 createCol(prims, "SitTargetOffsetY", typeof (Double));
623 createCol(prims, "SitTargetOffsetZ", typeof (Double));
624
625 createCol(prims, "SitTargetOrientW", typeof (Double));
626 createCol(prims, "SitTargetOrientX", typeof (Double));
627 createCol(prims, "SitTargetOrientY", typeof (Double));
628 createCol(prims, "SitTargetOrientZ", typeof (Double));
629
630
631 // Add in contraints
632 prims.PrimaryKey = new DataColumn[] {prims.Columns["UUID"]};
633
634 return prims;
635 }
636
637 private DataTable createLandTable()
638 {
639 DataTable land = new DataTable("land");
640 createCol(land, "UUID", typeof (String));
641 createCol(land, "RegionUUID", typeof (String));
642 createCol(land, "LocalLandID", typeof (Int32));
643
644 // Bitmap is a byte[512]
645 createCol(land, "Bitmap", typeof (Byte[]));
646
647 createCol(land, "Name", typeof (String));
648 createCol(land, "Description", typeof (String));
649 createCol(land, "OwnerUUID", typeof (String));
650 createCol(land, "IsGroupOwned", typeof (Int32));
651 createCol(land, "Area", typeof (Int32));
652 createCol(land, "AuctionID", typeof (Int32)); //Unemplemented
653 createCol(land, "Category", typeof (Int32)); //Enum libsecondlife.Parcel.ParcelCategory
654 createCol(land, "ClaimDate", typeof (Int32));
655 createCol(land, "ClaimPrice", typeof (Int32));
656 createCol(land, "GroupUUID", typeof (String));
657 createCol(land, "SalePrice", typeof (Int32));
658 createCol(land, "LandStatus", typeof (Int32)); //Enum. libsecondlife.Parcel.ParcelStatus
659 createCol(land, "LandFlags", typeof (Int32));
660 createCol(land, "LandingType", typeof (Int32));
661 createCol(land, "MediaAutoScale", typeof (Int32));
662 createCol(land, "MediaTextureUUID", typeof (String));
663 createCol(land, "MediaURL", typeof (String));
664 createCol(land, "MusicURL", typeof (String));
665 createCol(land, "PassHours", typeof (Double));
666 createCol(land, "PassPrice", typeof (Int32));
667 createCol(land, "SnapshotUUID", typeof (String));
668 createCol(land, "UserLocationX", typeof (Double));
669 createCol(land, "UserLocationY", typeof (Double));
670 createCol(land, "UserLocationZ", typeof (Double));
671 createCol(land, "UserLookAtX", typeof (Double));
672 createCol(land, "UserLookAtY", typeof (Double));
673 createCol(land, "UserLookAtZ", typeof (Double));
674
675 land.PrimaryKey = new DataColumn[] {land.Columns["UUID"]};
676
677 return land;
678 }
679
680 private DataTable createLandAccessListTable()
681 {
682 DataTable landaccess = new DataTable("landaccesslist");
683 createCol(landaccess, "LandUUID", typeof (String));
684 createCol(landaccess, "AccessUUID", typeof (String));
685 createCol(landaccess, "Flags", typeof (Int32));
686
687 return landaccess;
688 }
689
690 private DataTable createShapeTable()
691 {
692 DataTable shapes = new DataTable("primshapes");
693 createCol(shapes, "UUID", typeof (String));
694 // shape is an enum
695 createCol(shapes, "Shape", typeof (Int32));
696 // vectors
697 createCol(shapes, "ScaleX", typeof (Double));
698 createCol(shapes, "ScaleY", typeof (Double));
699 createCol(shapes, "ScaleZ", typeof (Double));
700 // paths
701 createCol(shapes, "PCode", typeof (Int32));
702 createCol(shapes, "PathBegin", typeof (Int32));
703 createCol(shapes, "PathEnd", typeof (Int32));
704 createCol(shapes, "PathScaleX", typeof (Int32));
705 createCol(shapes, "PathScaleY", typeof (Int32));
706 createCol(shapes, "PathShearX", typeof (Int32));
707 createCol(shapes, "PathShearY", typeof (Int32));
708 createCol(shapes, "PathSkew", typeof (Int32));
709 createCol(shapes, "PathCurve", typeof (Int32));
710 createCol(shapes, "PathRadiusOffset", typeof (Int32));
711 createCol(shapes, "PathRevolutions", typeof (Int32));
712 createCol(shapes, "PathTaperX", typeof (Int32));
713 createCol(shapes, "PathTaperY", typeof (Int32));
714 createCol(shapes, "PathTwist", typeof (Int32));
715 createCol(shapes, "PathTwistBegin", typeof (Int32));
716 // profile
717 createCol(shapes, "ProfileBegin", typeof (Int32));
718 createCol(shapes, "ProfileEnd", typeof (Int32));
719 createCol(shapes, "ProfileCurve", typeof (Int32));
720 createCol(shapes, "ProfileHollow", typeof (Int32));
721 createCol(shapes, "State", typeof(Int32));
722 createCol(shapes, "Texture", typeof (Byte[]));
723 createCol(shapes, "ExtraParams", typeof (Byte[]));
724
725 shapes.PrimaryKey = new DataColumn[] {shapes.Columns["UUID"]};
726
727 return shapes;
728 }
729
730 private DataTable createItemsTable()
731 {
732 DataTable items = new DataTable("primitems");
733
734 createCol(items, "itemID", typeof (String));
735 createCol(items, "primID", typeof (String));
736 createCol(items, "assetID", typeof (String));
737 createCol(items, "parentFolderID", typeof (String));
738
739 createCol(items, "invType", typeof (Int32));
740 createCol(items, "assetType", typeof (Int32));
741
742 createCol(items, "name", typeof (String));
743 createCol(items, "description", typeof (String));
744
745 createCol(items, "creationDate", typeof (Int64));
746 createCol(items, "creatorID", typeof (String));
747 createCol(items, "ownerID", typeof (String));
748 createCol(items, "lastOwnerID", typeof (String));
749 createCol(items, "groupID", typeof (String));
750
751 createCol(items, "nextPermissions", typeof (Int32));
752 createCol(items, "currentPermissions", typeof (Int32));
753 createCol(items, "basePermissions", typeof (Int32));
754 createCol(items, "everyonePermissions", typeof (Int32));
755 createCol(items, "groupPermissions", typeof (Int32));
756
757 items.PrimaryKey = new DataColumn[] {items.Columns["itemID"]};
758
759 return items;
760 }
761
762 /***********************************************************************
763 *
764 * Convert between ADO.NET <=> OpenSim Objects
765 *
766 * These should be database independant
767 *
768 **********************************************************************/
769
770 private SceneObjectPart buildPrim(DataRow row)
771 {
772 SceneObjectPart prim = new SceneObjectPart();
773 prim.UUID = new LLUUID((String) row["UUID"]);
774 // explicit conversion of integers is required, which sort
775 // of sucks. No idea if there is a shortcut here or not.
776 prim.ParentID = Convert.ToUInt32(row["ParentID"]);
777 prim.CreationDate = Convert.ToInt32(row["CreationDate"]);
778 prim.Name = (String) row["Name"];
779 // various text fields
780 prim.Text = (String) row["Text"];
781 prim.Description = (String) row["Description"];
782 prim.SitName = (String) row["SitName"];
783 prim.TouchName = (String) row["TouchName"];
784 // permissions
785 prim.ObjectFlags = Convert.ToUInt32(row["ObjectFlags"]);
786 prim.CreatorID = new LLUUID((String) row["CreatorID"]);
787 prim.OwnerID = new LLUUID((String) row["OwnerID"]);
788 prim.GroupID = new LLUUID((String) row["GroupID"]);
789 prim.LastOwnerID = new LLUUID((String) row["LastOwnerID"]);
790 prim.OwnerMask = Convert.ToUInt32(row["OwnerMask"]);
791 prim.NextOwnerMask = Convert.ToUInt32(row["NextOwnerMask"]);
792 prim.GroupMask = Convert.ToUInt32(row["GroupMask"]);
793 prim.EveryoneMask = Convert.ToUInt32(row["EveryoneMask"]);
794 prim.BaseMask = Convert.ToUInt32(row["BaseMask"]);
795 // vectors
796 prim.OffsetPosition = new LLVector3(
797 Convert.ToSingle(row["PositionX"]),
798 Convert.ToSingle(row["PositionY"]),
799 Convert.ToSingle(row["PositionZ"])
800 );
801 prim.GroupPosition = new LLVector3(
802 Convert.ToSingle(row["GroupPositionX"]),
803 Convert.ToSingle(row["GroupPositionY"]),
804 Convert.ToSingle(row["GroupPositionZ"])
805 );
806 prim.Velocity = new LLVector3(
807 Convert.ToSingle(row["VelocityX"]),
808 Convert.ToSingle(row["VelocityY"]),
809 Convert.ToSingle(row["VelocityZ"])
810 );
811 prim.AngularVelocity = new LLVector3(
812 Convert.ToSingle(row["AngularVelocityX"]),
813 Convert.ToSingle(row["AngularVelocityY"]),
814 Convert.ToSingle(row["AngularVelocityZ"])
815 );
816 prim.Acceleration = new LLVector3(
817 Convert.ToSingle(row["AccelerationX"]),
818 Convert.ToSingle(row["AccelerationY"]),
819 Convert.ToSingle(row["AccelerationZ"])
820 );
821 // quaternions
822 prim.RotationOffset = new LLQuaternion(
823 Convert.ToSingle(row["RotationX"]),
824 Convert.ToSingle(row["RotationY"]),
825 Convert.ToSingle(row["RotationZ"]),
826 Convert.ToSingle(row["RotationW"])
827 );
828 try
829 {
830 prim.SetSitTargetLL(new LLVector3(
831 Convert.ToSingle(row["SitTargetOffsetX"]),
832 Convert.ToSingle(row["SitTargetOffsetY"]),
833 Convert.ToSingle(row["SitTargetOffsetZ"])), new LLQuaternion(
834 Convert.ToSingle(
835 row["SitTargetOrientX"]),
836 Convert.ToSingle(
837 row["SitTargetOrientY"]),
838 Convert.ToSingle(
839 row["SitTargetOrientZ"]),
840 Convert.ToSingle(
841 row["SitTargetOrientW"])));
842 }
843 catch (InvalidCastException)
844 {
845 // Database table was created before we got here and needs to be created! :P
846
847 using (
848 MySqlCommand cmd =
849 new MySqlCommand(
850 "ALTER TABLE `prims` ADD COLUMN `SitTargetOffsetX` float NOT NULL default 0, ADD COLUMN `SitTargetOffsetY` float NOT NULL default 0, ADD COLUMN `SitTargetOffsetZ` float NOT NULL default 0, ADD COLUMN `SitTargetOrientW` float NOT NULL default 0, ADD COLUMN `SitTargetOrientX` float NOT NULL default 0, ADD COLUMN `SitTargetOrientY` float NOT NULL default 0, ADD COLUMN `SitTargetOrientZ` float NOT NULL default 0;",
851 m_connection))
852 {
853 cmd.ExecuteNonQuery();
854 }
855 }
856 return prim;
857 }
858
859
860 /// <summary>
861 /// Build a prim inventory item from the persisted data.
862 /// </summary>
863 /// <param name="row"></param>
864 /// <returns></returns>
865 private TaskInventoryItem buildItem(DataRow row)
866 {
867 TaskInventoryItem taskItem = new TaskInventoryItem();
868
869 taskItem.ItemID = new LLUUID((String)row["itemID"]);
870 taskItem.ParentPartID = new LLUUID((String)row["primID"]);
871 taskItem.AssetID = new LLUUID((String)row["assetID"]);
872 taskItem.ParentID = new LLUUID((String)row["parentFolderID"]);
873
874 taskItem.InvType = Convert.ToInt32(row["invType"]);
875 taskItem.Type = Convert.ToInt32(row["assetType"]);
876
877 taskItem.Name = (String)row["name"];
878 taskItem.Description = (String)row["description"];
879 taskItem.CreationDate = Convert.ToUInt32(row["creationDate"]);
880 taskItem.CreatorID = new LLUUID((String)row["creatorID"]);
881 taskItem.OwnerID = new LLUUID((String)row["ownerID"]);
882 taskItem.LastOwnerID = new LLUUID((String)row["lastOwnerID"]);
883 taskItem.GroupID = new LLUUID((String)row["groupID"]);
884
885 taskItem.NextOwnerMask = Convert.ToUInt32(row["nextPermissions"]);
886 taskItem.OwnerMask = Convert.ToUInt32(row["currentPermissions"]);
887 taskItem.BaseMask = Convert.ToUInt32(row["basePermissions"]);
888 taskItem.EveryoneMask = Convert.ToUInt32(row["everyonePermissions"]);
889 taskItem.GroupMask = Convert.ToUInt32(row["groupPermissions"]);
890
891 return taskItem;
892 }
893
894 private LandData buildLandData(DataRow row)
895 {
896 LandData newData = new LandData();
897
898 newData.globalID = new LLUUID((String) row["UUID"]);
899 newData.localID = Convert.ToInt32(row["LocalLandID"]);
900
901 // Bitmap is a byte[512]
902 newData.landBitmapByteArray = (Byte[]) row["Bitmap"];
903
904 newData.landName = (String) row["Name"];
905 newData.landDesc = (String) row["Description"];
906 newData.ownerID = (String) row["OwnerUUID"];
907 newData.isGroupOwned = Convert.ToBoolean(row["IsGroupOwned"]);
908 newData.area = Convert.ToInt32(row["Area"]);
909 newData.auctionID = Convert.ToUInt32(row["AuctionID"]); //Unemplemented
910 newData.category = (Parcel.ParcelCategory) Convert.ToInt32(row["Category"]);
911 //Enum libsecondlife.Parcel.ParcelCategory
912 newData.claimDate = Convert.ToInt32(row["ClaimDate"]);
913 newData.claimPrice = Convert.ToInt32(row["ClaimPrice"]);
914 newData.groupID = new LLUUID((String) row["GroupUUID"]);
915 newData.salePrice = Convert.ToInt32(row["SalePrice"]);
916 newData.landStatus = (Parcel.ParcelStatus) Convert.ToInt32(row["LandStatus"]);
917 //Enum. libsecondlife.Parcel.ParcelStatus
918 newData.landFlags = Convert.ToUInt32(row["LandFlags"]);
919 newData.landingType = Convert.ToByte(row["LandingType"]);
920 newData.mediaAutoScale = Convert.ToByte(row["MediaAutoScale"]);
921 newData.mediaID = new LLUUID((String) row["MediaTextureUUID"]);
922 newData.mediaURL = (String) row["MediaURL"];
923 newData.musicURL = (String) row["MusicURL"];
924 newData.passHours = Convert.ToSingle(row["PassHours"]);
925 newData.passPrice = Convert.ToInt32(row["PassPrice"]);
926 newData.snapshotID = (String) row["SnapshotUUID"];
927
928 newData.userLocation =
929 new LLVector3(Convert.ToSingle(row["UserLocationX"]), Convert.ToSingle(row["UserLocationY"]),
930 Convert.ToSingle(row["UserLocationZ"]));
931 newData.userLookAt =
932 new LLVector3(Convert.ToSingle(row["UserLookAtX"]), Convert.ToSingle(row["UserLookAtY"]),
933 Convert.ToSingle(row["UserLookAtZ"]));
934 newData.parcelAccessList = new List<ParcelManager.ParcelAccessEntry>();
935
936 return newData;
937 }
938
939 private ParcelManager.ParcelAccessEntry buildLandAccessData(DataRow row)
940 {
941 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
942 entry.AgentID = new LLUUID((string) row["AccessUUID"]);
943 entry.Flags = (ParcelManager.AccessList) Convert.ToInt32(row["Flags"]);
944 entry.Time = new DateTime();
945 return entry;
946 }
947
948 private Array serializeTerrain(double[,] val)
949 {
950 MemoryStream str = new MemoryStream(65536*sizeof (double));
951 BinaryWriter bw = new BinaryWriter(str);
952
953 // TODO: COMPATIBILITY - Add byte-order conversions
954 for (int x = 0; x < 256; x++)
955 for (int y = 0; y < 256; y++)
956 bw.Write(val[x, y]);
957
958 return str.ToArray();
959 }
960
961 private void fillPrimRow(DataRow row, SceneObjectPart prim, LLUUID sceneGroupID, LLUUID regionUUID)
962 {
963 row["UUID"] = Util.ToRawUuidString(prim.UUID);
964 row["RegionUUID"] = Util.ToRawUuidString(regionUUID);
965 row["ParentID"] = prim.ParentID;
966 row["CreationDate"] = prim.CreationDate;
967 row["Name"] = prim.Name;
968 row["SceneGroupID"] = Util.ToRawUuidString(sceneGroupID);
969 // the UUID of the root part for this SceneObjectGroup
970 // various text fields
971 row["Text"] = prim.Text;
972 row["Description"] = prim.Description;
973 row["SitName"] = prim.SitName;
974 row["TouchName"] = prim.TouchName;
975 // permissions
976 row["ObjectFlags"] = prim.ObjectFlags;
977 row["CreatorID"] = Util.ToRawUuidString(prim.CreatorID);
978 row["OwnerID"] = Util.ToRawUuidString(prim.OwnerID);
979 row["GroupID"] = Util.ToRawUuidString(prim.GroupID);
980 row["LastOwnerID"] = Util.ToRawUuidString(prim.LastOwnerID);
981 row["OwnerMask"] = prim.OwnerMask;
982 row["NextOwnerMask"] = prim.NextOwnerMask;
983 row["GroupMask"] = prim.GroupMask;
984 row["EveryoneMask"] = prim.EveryoneMask;
985 row["BaseMask"] = prim.BaseMask;
986 // vectors
987 row["PositionX"] = prim.OffsetPosition.X;
988 row["PositionY"] = prim.OffsetPosition.Y;
989 row["PositionZ"] = prim.OffsetPosition.Z;
990 row["GroupPositionX"] = prim.GroupPosition.X;
991 row["GroupPositionY"] = prim.GroupPosition.Y;
992 row["GroupPositionZ"] = prim.GroupPosition.Z;
993 row["VelocityX"] = prim.Velocity.X;
994 row["VelocityY"] = prim.Velocity.Y;
995 row["VelocityZ"] = prim.Velocity.Z;
996 row["AngularVelocityX"] = prim.AngularVelocity.X;
997 row["AngularVelocityY"] = prim.AngularVelocity.Y;
998 row["AngularVelocityZ"] = prim.AngularVelocity.Z;
999 row["AccelerationX"] = prim.Acceleration.X;
1000 row["AccelerationY"] = prim.Acceleration.Y;
1001 row["AccelerationZ"] = prim.Acceleration.Z;
1002 // quaternions
1003 row["RotationX"] = prim.RotationOffset.X;
1004 row["RotationY"] = prim.RotationOffset.Y;
1005 row["RotationZ"] = prim.RotationOffset.Z;
1006 row["RotationW"] = prim.RotationOffset.W;
1007
1008 try
1009 {
1010 // Sit target
1011 LLVector3 sitTargetPos = prim.GetSitTargetPositionLL();
1012 row["SitTargetOffsetX"] = sitTargetPos.X;
1013 row["SitTargetOffsetY"] = sitTargetPos.Y;
1014 row["SitTargetOffsetZ"] = sitTargetPos.Z;
1015
1016 LLQuaternion sitTargetOrient = prim.GetSitTargetOrientationLL();
1017 row["SitTargetOrientW"] = sitTargetOrient.W;
1018 row["SitTargetOrientX"] = sitTargetOrient.X;
1019 row["SitTargetOrientY"] = sitTargetOrient.Y;
1020 row["SitTargetOrientZ"] = sitTargetOrient.Z;
1021 }
1022 catch (MySqlException)
1023 {
1024 // Database table was created before we got here and needs to be created! :P
1025
1026 using (
1027 MySqlCommand cmd =
1028 new MySqlCommand(
1029 "ALTER TABLE `prims` ADD COLUMN `SitTargetOffsetX` float NOT NULL default 0, ADD COLUMN `SitTargetOffsetY` float NOT NULL default 0, ADD COLUMN `SitTargetOffsetZ` float NOT NULL default 0, ADD COLUMN `SitTargetOrientW` float NOT NULL default 0, ADD COLUMN `SitTargetOrientX` float NOT NULL default 0, ADD COLUMN `SitTargetOrientY` float NOT NULL default 0, ADD COLUMN `SitTargetOrientZ` float NOT NULL default 0;",
1030 m_connection))
1031 {
1032 cmd.ExecuteNonQuery();
1033 }
1034 }
1035 }
1036
1037 private void fillItemRow(DataRow row, TaskInventoryItem taskItem)
1038 {
1039 row["itemID"] = taskItem.ItemID;
1040 row["primID"] = taskItem.ParentPartID;
1041 row["assetID"] = taskItem.AssetID;
1042 row["parentFolderID"] = taskItem.ParentID;
1043
1044 row["invType"] = taskItem.InvType;
1045 row["assetType"] = taskItem.Type;
1046
1047 row["name"] = taskItem.Name;
1048 row["description"] = taskItem.Description;
1049 row["creationDate"] = taskItem.CreationDate;
1050 row["creatorID"] = taskItem.CreatorID;
1051 row["ownerID"] = taskItem.OwnerID;
1052 row["lastOwnerID"] = taskItem.LastOwnerID;
1053 row["groupID"] = taskItem.GroupID;
1054 row["nextPermissions"] = taskItem.NextOwnerMask;
1055 row["currentPermissions"] = taskItem.OwnerMask;
1056 row["basePermissions"] = taskItem.BaseMask;
1057 row["everyonePermissions"] = taskItem.EveryoneMask;
1058 row["groupPermissions"] = taskItem.GroupMask;
1059 }
1060
1061 private void fillLandRow(DataRow row, LandData land, LLUUID regionUUID)
1062 {
1063 row["UUID"] = Util.ToRawUuidString(land.globalID);
1064 row["RegionUUID"] = Util.ToRawUuidString(regionUUID);
1065 row["LocalLandID"] = land.localID;
1066
1067 // Bitmap is a byte[512]
1068 row["Bitmap"] = land.landBitmapByteArray;
1069
1070 row["Name"] = land.landName;
1071 row["Description"] = land.landDesc;
1072 row["OwnerUUID"] = Util.ToRawUuidString(land.ownerID);
1073 row["IsGroupOwned"] = land.isGroupOwned;
1074 row["Area"] = land.area;
1075 row["AuctionID"] = land.auctionID; //Unemplemented
1076 row["Category"] = land.category; //Enum libsecondlife.Parcel.ParcelCategory
1077 row["ClaimDate"] = land.claimDate;
1078 row["ClaimPrice"] = land.claimPrice;
1079 row["GroupUUID"] = Util.ToRawUuidString(land.groupID);
1080 row["SalePrice"] = land.salePrice;
1081 row["LandStatus"] = land.landStatus; //Enum. libsecondlife.Parcel.ParcelStatus
1082 row["LandFlags"] = land.landFlags;
1083 row["LandingType"] = land.landingType;
1084 row["MediaAutoScale"] = land.mediaAutoScale;
1085 row["MediaTextureUUID"] = Util.ToRawUuidString(land.mediaID);
1086 row["MediaURL"] = land.mediaURL;
1087 row["MusicURL"] = land.musicURL;
1088 row["PassHours"] = land.passHours;
1089 row["PassPrice"] = land.passPrice;
1090 row["SnapshotUUID"] = Util.ToRawUuidString(land.snapshotID);
1091 row["UserLocationX"] = land.userLocation.X;
1092 row["UserLocationY"] = land.userLocation.Y;
1093 row["UserLocationZ"] = land.userLocation.Z;
1094 row["UserLookAtX"] = land.userLookAt.X;
1095 row["UserLookAtY"] = land.userLookAt.Y;
1096 row["UserLookAtZ"] = land.userLookAt.Z;
1097 }
1098
1099 private void fillLandAccessRow(DataRow row, ParcelManager.ParcelAccessEntry entry, LLUUID parcelID)
1100 {
1101 row["LandUUID"] = Util.ToRawUuidString(parcelID);
1102 row["AccessUUID"] = Util.ToRawUuidString(entry.AgentID);
1103 row["Flags"] = entry.Flags;
1104 }
1105
1106 private PrimitiveBaseShape buildShape(DataRow row)
1107 {
1108 PrimitiveBaseShape s = new PrimitiveBaseShape();
1109 s.Scale = new LLVector3(
1110 Convert.ToSingle(row["ScaleX"]),
1111 Convert.ToSingle(row["ScaleY"]),
1112 Convert.ToSingle(row["ScaleZ"])
1113 );
1114 // paths
1115 s.PCode = Convert.ToByte(row["PCode"]);
1116 s.PathBegin = Convert.ToUInt16(row["PathBegin"]);
1117 s.PathEnd = Convert.ToUInt16(row["PathEnd"]);
1118 s.PathScaleX = Convert.ToByte(row["PathScaleX"]);
1119 s.PathScaleY = Convert.ToByte(row["PathScaleY"]);
1120 s.PathShearX = Convert.ToByte(row["PathShearX"]);
1121 s.PathShearY = Convert.ToByte(row["PathShearY"]);
1122 s.PathSkew = Convert.ToSByte(row["PathSkew"]);
1123 s.PathCurve = Convert.ToByte(row["PathCurve"]);
1124 s.PathRadiusOffset = Convert.ToSByte(row["PathRadiusOffset"]);
1125 s.PathRevolutions = Convert.ToByte(row["PathRevolutions"]);
1126 s.PathTaperX = Convert.ToSByte(row["PathTaperX"]);
1127 s.PathTaperY = Convert.ToSByte(row["PathTaperY"]);
1128 s.PathTwist = Convert.ToSByte(row["PathTwist"]);
1129 s.PathTwistBegin = Convert.ToSByte(row["PathTwistBegin"]);
1130 // profile
1131 s.ProfileBegin = Convert.ToUInt16(row["ProfileBegin"]);
1132 s.ProfileEnd = Convert.ToUInt16(row["ProfileEnd"]);
1133 s.ProfileCurve = Convert.ToByte(row["ProfileCurve"]);
1134 s.ProfileHollow = Convert.ToUInt16(row["ProfileHollow"]);
1135
1136 byte[] textureEntry = (byte[]) row["Texture"];
1137 s.TextureEntry = textureEntry;
1138
1139 s.ExtraParams = (byte[]) row["ExtraParams"];
1140
1141 try
1142 {
1143 s.State = Convert.ToByte(row["State"]);
1144 }
1145 catch (InvalidCastException)
1146 {
1147 // Database table was created before we got here and needs to be created! :P
1148
1149 using (
1150 MySqlCommand cmd =
1151 new MySqlCommand(
1152 "ALTER TABLE `primshapes` ADD COLUMN `State` int NOT NULL default 0;",
1153 m_connection))
1154 {
1155 cmd.ExecuteNonQuery();
1156 }
1157 }
1158
1159 return s;
1160 }
1161
1162 private void fillShapeRow(DataRow row, SceneObjectPart prim)
1163 {
1164 PrimitiveBaseShape s = prim.Shape;
1165 row["UUID"] = Util.ToRawUuidString(prim.UUID);
1166 // shape is an enum
1167 row["Shape"] = 0;
1168 // vectors
1169 row["ScaleX"] = s.Scale.X;
1170 row["ScaleY"] = s.Scale.Y;
1171 row["ScaleZ"] = s.Scale.Z;
1172 // paths
1173 row["PCode"] = s.PCode;
1174 row["PathBegin"] = s.PathBegin;
1175 row["PathEnd"] = s.PathEnd;
1176 row["PathScaleX"] = s.PathScaleX;
1177 row["PathScaleY"] = s.PathScaleY;
1178 row["PathShearX"] = s.PathShearX;
1179 row["PathShearY"] = s.PathShearY;
1180 row["PathSkew"] = s.PathSkew;
1181 row["PathCurve"] = s.PathCurve;
1182 row["PathRadiusOffset"] = s.PathRadiusOffset;
1183 row["PathRevolutions"] = s.PathRevolutions;
1184 row["PathTaperX"] = s.PathTaperX;
1185 row["PathTaperY"] = s.PathTaperY;
1186 row["PathTwist"] = s.PathTwist;
1187 row["PathTwistBegin"] = s.PathTwistBegin;
1188 // profile
1189 row["ProfileBegin"] = s.ProfileBegin;
1190 row["ProfileEnd"] = s.ProfileEnd;
1191 row["ProfileCurve"] = s.ProfileCurve;
1192 row["ProfileHollow"] = s.ProfileHollow;
1193 row["Texture"] = s.TextureEntry;
1194 row["ExtraParams"] = s.ExtraParams;
1195 try
1196 {
1197 row["State"] = s.State;
1198 }
1199 catch (MySqlException)
1200 {
1201 // Database table was created before we got here and needs to be created! :P
1202 using (
1203 MySqlCommand cmd =
1204 new MySqlCommand(
1205 "ALTER TABLE `primshapes` ADD COLUMN `State` int NOT NULL default 0;",
1206 m_connection))
1207 {
1208 cmd.ExecuteNonQuery();
1209 }
1210 }
1211 }
1212
1213 private void addPrim(SceneObjectPart prim, LLUUID sceneGroupID, LLUUID regionUUID)
1214 {
1215 DataTable prims = m_dataSet.Tables["prims"];
1216 DataTable shapes = m_dataSet.Tables["primshapes"];
1217
1218 DataRow primRow = prims.Rows.Find(Util.ToRawUuidString(prim.UUID));
1219 if (primRow == null)
1220 {
1221 primRow = prims.NewRow();
1222 fillPrimRow(primRow, prim, sceneGroupID, regionUUID);
1223 prims.Rows.Add(primRow);
1224 }
1225 else
1226 {
1227 fillPrimRow(primRow, prim, sceneGroupID, regionUUID);
1228 }
1229
1230 DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID));
1231 if (shapeRow == null)
1232 {
1233 shapeRow = shapes.NewRow();
1234 fillShapeRow(shapeRow, prim);
1235 shapes.Rows.Add(shapeRow);
1236 }
1237 else
1238 {
1239 fillShapeRow(shapeRow, prim);
1240 }
1241 }
1242
1243 // see IRegionDatastore
1244 public void StorePrimInventory(LLUUID primID, ICollection<TaskInventoryItem> items)
1245 {
1246 if (!persistPrimInventories)
1247 return;
1248
1249 m_log.InfoFormat("[DATASTORE]: Persisting Prim Inventory with prim ID {0}", primID);
1250
1251 // For now, we're just going to crudely remove all the previous inventory items
1252 // no matter whether they have changed or not, and replace them with the current set.
1253 lock (m_dataSet)
1254 {
1255 RemoveItems(primID);
1256
1257 // repalce with current inventory details
1258 foreach (TaskInventoryItem newItem in items)
1259 {
1260// m_log.InfoFormat(
1261// "[DATASTORE]: " +
1262// "Adding item {0}, {1} to prim ID {2}",
1263// newItem.Name, newItem.ItemID, newItem.ParentPartID);
1264
1265 DataRow newItemRow = m_itemsTable.NewRow();
1266 fillItemRow(newItemRow, newItem);
1267 m_itemsTable.Rows.Add(newItemRow);
1268 }
1269 }
1270
1271 Commit();
1272 }
1273
1274 /***********************************************************************
1275 *
1276 * SQL Statement Creation Functions
1277 *
1278 * These functions create SQL statements for update, insert, and create.
1279 * They can probably be factored later to have a db independant
1280 * portion and a db specific portion
1281 *
1282 **********************************************************************/
1283
1284 private MySqlCommand createInsertCommand(string table, DataTable dt)
1285 {
1286 /**
1287 * This is subtle enough to deserve some commentary.
1288 * Instead of doing *lots* and *lots of hardcoded strings
1289 * for database definitions we'll use the fact that
1290 * realistically all insert statements look like "insert
1291 * into A(b, c) values(:b, :c) on the parameterized query
1292 * front. If we just have a list of b, c, etc... we can
1293 * generate these strings instead of typing them out.
1294 */
1295 string[] cols = new string[dt.Columns.Count];
1296 for (int i = 0; i < dt.Columns.Count; i++)
1297 {
1298 DataColumn col = dt.Columns[i];
1299 cols[i] = col.ColumnName;
1300 }
1301
1302 string sql = "insert into " + table + "(";
1303 sql += String.Join(", ", cols);
1304 // important, the first ':' needs to be here, the rest get added in the join
1305 sql += ") values (?";
1306 sql += String.Join(", ?", cols);
1307 sql += ")";
1308 MySqlCommand cmd = new MySqlCommand(sql);
1309
1310 // this provides the binding for all our parameters, so
1311 // much less code than it used to be
1312 foreach (DataColumn col in dt.Columns)
1313 {
1314 cmd.Parameters.Add(createMySqlParameter(col.ColumnName, col.DataType));
1315 }
1316 return cmd;
1317 }
1318
1319 private MySqlCommand createUpdateCommand(string table, string pk, DataTable dt)
1320 {
1321 string sql = "update " + table + " set ";
1322 string subsql = String.Empty;
1323 foreach (DataColumn col in dt.Columns)
1324 {
1325 if (subsql.Length > 0)
1326 {
1327 // a map function would rock so much here
1328 subsql += ", ";
1329 }
1330 subsql += col.ColumnName + "=?" + col.ColumnName;
1331 }
1332 sql += subsql;
1333 sql += " where " + pk;
1334 MySqlCommand cmd = new MySqlCommand(sql);
1335
1336 // this provides the binding for all our parameters, so
1337 // much less code than it used to be
1338
1339 foreach (DataColumn col in dt.Columns)
1340 {
1341 cmd.Parameters.Add(createMySqlParameter(col.ColumnName, col.DataType));
1342 }
1343 return cmd;
1344 }
1345
1346 private string defineTable(DataTable dt)
1347 {
1348 string sql = "create table " + dt.TableName + "(";
1349 string subsql = String.Empty;
1350 foreach (DataColumn col in dt.Columns)
1351 {
1352 if (subsql.Length > 0)
1353 {
1354 // a map function would rock so much here
1355 subsql += ",\n";
1356 }
1357 subsql += col.ColumnName + " " + MySqlType(col.DataType);
1358 if (dt.PrimaryKey.Length > 0 && col == dt.PrimaryKey[0])
1359 {
1360 subsql += " primary key";
1361 }
1362 }
1363 sql += subsql;
1364 sql += ")";
1365
1366 //m_log.InfoFormat("[DATASTORE]: defineTable() sql {0}", sql);
1367
1368 return sql;
1369 }
1370
1371 /***********************************************************************
1372 *
1373 * Database Binding functions
1374 *
1375 * These will be db specific due to typing, and minor differences
1376 * in databases.
1377 *
1378 **********************************************************************/
1379
1380 ///<summary>
1381 /// This is a convenience function that collapses 5 repetitive
1382 /// lines for defining MySqlParameters to 2 parameters:
1383 /// column name and database type.
1384 ///
1385 /// It assumes certain conventions like ?param as the param
1386 /// name to replace in parametrized queries, and that source
1387 /// version is always current version, both of which are fine
1388 /// for us.
1389 ///</summary>
1390 ///<returns>a built MySql parameter</returns>
1391 private MySqlParameter createMySqlParameter(string name, Type type)
1392 {
1393 MySqlParameter param = new MySqlParameter();
1394 param.ParameterName = "?" + name;
1395 param.DbType = dbtypeFromType(type);
1396 param.SourceColumn = name;
1397 param.SourceVersion = DataRowVersion.Current;
1398 return param;
1399 }
1400
1401// TODO: unused
1402// private MySqlParameter createParamWithValue(string name, Type type, Object o)
1403// {
1404// MySqlParameter param = createMySqlParameter(name, type);
1405// param.Value = o;
1406// return param;
1407// }
1408
1409 private void SetupPrimCommands(MySqlDataAdapter da, MySqlConnection conn)
1410 {
1411 MySqlCommand insertCommand = createInsertCommand("prims", m_primTable);
1412 insertCommand.Connection = conn;
1413 da.InsertCommand = insertCommand;
1414
1415 MySqlCommand updateCommand = createUpdateCommand("prims", "UUID=?UUID", m_primTable);
1416 updateCommand.Connection = conn;
1417 da.UpdateCommand = updateCommand;
1418
1419 MySqlCommand delete = new MySqlCommand("delete from prims where UUID=?UUID");
1420 delete.Parameters.Add(createMySqlParameter("UUID", typeof (String)));
1421 delete.Connection = conn;
1422 da.DeleteCommand = delete;
1423 }
1424
1425 private void SetupItemsCommands(MySqlDataAdapter da, MySqlConnection conn)
1426 {
1427 da.InsertCommand = createInsertCommand("primitems", m_itemsTable);
1428 da.InsertCommand.Connection = conn;
1429
1430 da.UpdateCommand = createUpdateCommand("primitems", "itemID = ?itemID", m_itemsTable);
1431 da.UpdateCommand.Connection = conn;
1432
1433 MySqlCommand delete = new MySqlCommand("delete from primitems where itemID = ?itemID");
1434 delete.Parameters.Add(createMySqlParameter("itemID", typeof (String)));
1435 delete.Connection = conn;
1436 da.DeleteCommand = delete;
1437 }
1438
1439 private void SetupTerrainCommands(MySqlDataAdapter da, MySqlConnection conn)
1440 {
1441 da.InsertCommand = createInsertCommand("terrain", m_dataSet.Tables["terrain"]);
1442 da.InsertCommand.Connection = conn;
1443 }
1444
1445 private void setupLandCommands(MySqlDataAdapter da, MySqlConnection conn)
1446 {
1447 da.InsertCommand = createInsertCommand("land", m_dataSet.Tables["land"]);
1448 da.InsertCommand.Connection = conn;
1449
1450 da.UpdateCommand = createUpdateCommand("land", "UUID=?UUID", m_dataSet.Tables["land"]);
1451 da.UpdateCommand.Connection = conn;
1452 }
1453
1454 private void setupLandAccessCommands(MySqlDataAdapter da, MySqlConnection conn)
1455 {
1456 da.InsertCommand = createInsertCommand("landaccesslist", m_dataSet.Tables["landaccesslist"]);
1457 da.InsertCommand.Connection = conn;
1458 }
1459
1460 private void SetupShapeCommands(MySqlDataAdapter da, MySqlConnection conn)
1461 {
1462 da.InsertCommand = createInsertCommand("primshapes", m_dataSet.Tables["primshapes"]);
1463 da.InsertCommand.Connection = conn;
1464
1465 da.UpdateCommand = createUpdateCommand("primshapes", "UUID=?UUID", m_dataSet.Tables["primshapes"]);
1466 da.UpdateCommand.Connection = conn;
1467
1468 MySqlCommand delete = new MySqlCommand("delete from primshapes where UUID = ?UUID");
1469 delete.Parameters.Add(createMySqlParameter("UUID", typeof (String)));
1470 delete.Connection = conn;
1471 da.DeleteCommand = delete;
1472 }
1473
1474 private void InitDB(MySqlConnection conn)
1475 {
1476 string createPrims = defineTable(createPrimTable());
1477 string createShapes = defineTable(createShapeTable());
1478 string createItems = defineTable(createItemsTable());
1479 string createTerrain = defineTable(createTerrainTable());
1480 string createLand = defineTable(createLandTable());
1481 string createLandAccessList = defineTable(createLandAccessListTable());
1482
1483 MySqlCommand pcmd = new MySqlCommand(createPrims, conn);
1484 MySqlCommand scmd = new MySqlCommand(createShapes, conn);
1485 MySqlCommand icmd = new MySqlCommand(createItems, conn);
1486 MySqlCommand tcmd = new MySqlCommand(createTerrain, conn);
1487 MySqlCommand lcmd = new MySqlCommand(createLand, conn);
1488 MySqlCommand lalcmd = new MySqlCommand(createLandAccessList, conn);
1489
1490 if (conn.State != ConnectionState.Open)
1491 {
1492 try
1493 {
1494 conn.Open();
1495 }
1496 catch (Exception ex)
1497 {
1498 m_log.Error("[MySql]: Error connecting to MySQL server: " + ex.Message);
1499 m_log.Error("[MySql]: Application is terminating!");
1500 System.Threading.Thread.CurrentThread.Abort();
1501 }
1502 }
1503
1504 try
1505 {
1506 pcmd.ExecuteNonQuery();
1507 }
1508 catch (MySqlException e)
1509 {
1510 m_log.WarnFormat("[MySql]: Primitives Table Already Exists: {0}", e);
1511 }
1512
1513 try
1514 {
1515 scmd.ExecuteNonQuery();
1516 }
1517 catch (MySqlException e)
1518 {
1519 m_log.WarnFormat("[MySql]: Shapes Table Already Exists: {0}", e);
1520 }
1521
1522 try
1523 {
1524 icmd.ExecuteNonQuery();
1525 }
1526 catch (MySqlException e)
1527 {
1528 m_log.WarnFormat("[MySql]: Items Table Already Exists: {0}", e);
1529 }
1530
1531 try
1532 {
1533 tcmd.ExecuteNonQuery();
1534 }
1535 catch (MySqlException e)
1536 {
1537 m_log.WarnFormat("[MySql]: Terrain Table Already Exists: {0}", e);
1538 }
1539
1540 try
1541 {
1542 lcmd.ExecuteNonQuery();
1543 }
1544 catch (MySqlException e)
1545 {
1546 m_log.WarnFormat("[MySql]: Land Table Already Exists: {0}", e);
1547 }
1548
1549 try
1550 {
1551 lalcmd.ExecuteNonQuery();
1552 }
1553 catch (MySqlException e)
1554 {
1555 m_log.WarnFormat("[MySql]: LandAccessList Table Already Exists: {0}", e);
1556 }
1557 conn.Close();
1558 }
1559
1560 private bool TestTables(MySqlConnection conn)
1561 {
1562 MySqlCommand primSelectCmd = new MySqlCommand(m_primSelect, conn);
1563 MySqlDataAdapter pDa = new MySqlDataAdapter(primSelectCmd);
1564 MySqlCommand shapeSelectCmd = new MySqlCommand(m_shapeSelect, conn);
1565 MySqlDataAdapter sDa = new MySqlDataAdapter(shapeSelectCmd);
1566 MySqlCommand itemsSelectCmd = new MySqlCommand(m_itemsSelect, conn);
1567 MySqlDataAdapter iDa = new MySqlDataAdapter(itemsSelectCmd);
1568 MySqlCommand terrainSelectCmd = new MySqlCommand(m_terrainSelect, conn);
1569 MySqlDataAdapter tDa = new MySqlDataAdapter(terrainSelectCmd);
1570 MySqlCommand landSelectCmd = new MySqlCommand(m_landSelect, conn);
1571 MySqlDataAdapter lDa = new MySqlDataAdapter(landSelectCmd);
1572 MySqlCommand landAccessListSelectCmd = new MySqlCommand(m_landAccessListSelect, conn);
1573 MySqlDataAdapter lalDa = new MySqlDataAdapter(landAccessListSelectCmd);
1574
1575 DataSet tmpDS = new DataSet();
1576 try
1577 {
1578 pDa.Fill(tmpDS, "prims");
1579 sDa.Fill(tmpDS, "primshapes");
1580
1581 if (persistPrimInventories)
1582 iDa.Fill(tmpDS, "primitems");
1583
1584 tDa.Fill(tmpDS, "terrain");
1585 lDa.Fill(tmpDS, "land");
1586 lalDa.Fill(tmpDS, "landaccesslist");
1587 }
1588 catch (MySqlException)
1589 {
1590 m_log.Info("[DATASTORE]: MySql Database doesn't exist... creating");
1591 InitDB(conn);
1592 }
1593
1594 pDa.Fill(tmpDS, "prims");
1595 sDa.Fill(tmpDS, "primshapes");
1596
1597 if (persistPrimInventories)
1598 iDa.Fill(tmpDS, "primitems");
1599
1600 tDa.Fill(tmpDS, "terrain");
1601 lDa.Fill(tmpDS, "land");
1602 lalDa.Fill(tmpDS, "landaccesslist");
1603
1604 foreach (DataColumn col in createPrimTable().Columns)
1605 {
1606 if (!tmpDS.Tables["prims"].Columns.Contains(col.ColumnName))
1607 {
1608 m_log.Info("[DATASTORE]: Missing required column:" + col.ColumnName);
1609 return false;
1610 }
1611 }
1612
1613 foreach (DataColumn col in createShapeTable().Columns)
1614 {
1615 if (!tmpDS.Tables["primshapes"].Columns.Contains(col.ColumnName))
1616 {
1617 m_log.Info("[DATASTORE]: Missing required column:" + col.ColumnName);
1618 return false;
1619 }
1620 }
1621
1622 // XXX primitems should probably go here eventually
1623
1624 foreach (DataColumn col in createTerrainTable().Columns)
1625 {
1626 if (!tmpDS.Tables["terrain"].Columns.Contains(col.ColumnName))
1627 {
1628 m_log.Info("[DATASTORE]: Missing require column:" + col.ColumnName);
1629 return false;
1630 }
1631 }
1632
1633 foreach (DataColumn col in createLandTable().Columns)
1634 {
1635 if (!tmpDS.Tables["land"].Columns.Contains(col.ColumnName))
1636 {
1637 m_log.Info("[DATASTORE]: Missing require column:" + col.ColumnName);
1638 return false;
1639 }
1640 }
1641
1642 foreach (DataColumn col in createLandAccessListTable().Columns)
1643 {
1644 if (!tmpDS.Tables["landaccesslist"].Columns.Contains(col.ColumnName))
1645 {
1646 m_log.Info("[DATASTORE]: Missing require column:" + col.ColumnName);
1647 return false;
1648 }
1649 }
1650
1651 return true;
1652 }
1653
1654 /***********************************************************************
1655 *
1656 * Type conversion functions
1657 *
1658 **********************************************************************/
1659
1660 private DbType dbtypeFromType(Type type)
1661 {
1662 if (type == typeof (String))
1663 {
1664 return DbType.String;
1665 }
1666 else if (type == typeof (Int32))
1667 {
1668 return DbType.Int32;
1669 }
1670 else if (type == typeof (Double))
1671 {
1672 return DbType.Double;
1673 }
1674 else if (type == typeof (Byte))
1675 {
1676 return DbType.Byte;
1677 }
1678 else if (type == typeof (Double))
1679 {
1680 return DbType.Double;
1681 }
1682 else if (type == typeof (Byte[]))
1683 {
1684 return DbType.Binary;
1685 }
1686 else
1687 {
1688 return DbType.String;
1689 }
1690 }
1691
1692 // this is something we'll need to implement for each db
1693 // slightly differently.
1694 private string MySqlType(Type type)
1695 {
1696 if (type == typeof (String))
1697 {
1698 return "varchar(255)";
1699 }
1700 else if (type == typeof (Int32))
1701 {
1702 return "integer";
1703 }
1704 else if (type == typeof (Int64))
1705 {
1706 return "bigint";
1707 }
1708 else if (type == typeof (Double))
1709 {
1710 return "float";
1711 }
1712 else if (type == typeof (Byte[]))
1713 {
1714 return "longblob";
1715 }
1716 else
1717 {
1718 return "string";
1719 }
1720 }
1721 }
1722}
diff --git a/OpenSim/Data/MySQL/MySQLGridData.cs b/OpenSim/Data/MySQL/MySQLGridData.cs
new file mode 100644
index 0000000..61ab067
--- /dev/null
+++ b/OpenSim/Data/MySQL/MySQLGridData.cs
@@ -0,0 +1,402 @@
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 OpenSim 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.Security.Cryptography;
32using System.Text;
33using System.Text.RegularExpressions;
34using libsecondlife;
35using OpenSim.Framework.Console;
36
37namespace OpenSim.Framework.Data.MySQL
38{
39 /// <summary>
40 /// A MySQL Interface for the Grid Server
41 /// </summary>
42 public class MySQLGridData : GridDataBase
43 {
44 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
45
46 /// <summary>
47 /// MySQL Database Manager
48 /// </summary>
49 private MySQLManager database;
50
51 /// <summary>
52 /// Initialises the Grid Interface
53 /// </summary>
54 override public void Initialise()
55 {
56 IniFile GridDataMySqlFile = new IniFile("mysql_connection.ini");
57 string settingHostname = GridDataMySqlFile.ParseFileReadValue("hostname");
58 string settingDatabase = GridDataMySqlFile.ParseFileReadValue("database");
59 string settingUsername = GridDataMySqlFile.ParseFileReadValue("username");
60 string settingPassword = GridDataMySqlFile.ParseFileReadValue("password");
61 string settingPooling = GridDataMySqlFile.ParseFileReadValue("pooling");
62 string settingPort = GridDataMySqlFile.ParseFileReadValue("port");
63
64 database =
65 new MySQLManager(settingHostname, settingDatabase, settingUsername, settingPassword, settingPooling,
66 settingPort);
67
68 TestTables();
69 }
70
71 #region Test and initialization code
72
73 /// <summary>
74 /// Ensure that the user related tables exists and are at the latest version
75 /// </summary>
76 private void TestTables()
77 {
78 Dictionary<string, string> tableList = new Dictionary<string, string>();
79
80 tableList["regions"] = null;
81 database.GetTableVersion(tableList);
82
83 UpgradeRegionsTable(tableList["regions"]);
84 }
85
86 /// <summary>
87 /// Create or upgrade the table if necessary
88 /// </summary>
89 /// <param name="oldVersion">A null indicates that the table does not
90 /// currently exist</param>
91 private void UpgradeRegionsTable(string oldVersion)
92 {
93 // null as the version, indicates that the table didn't exist
94 if (oldVersion == null)
95 {
96 database.ExecuteResourceSql("CreateRegionsTable.sql");
97 return;
98 }
99 if (oldVersion.Contains("Rev. 1"))
100 {
101 database.ExecuteResourceSql("UpgradeRegionsTableToVersion2.sql");
102 return;
103 }
104 if (oldVersion.Contains("Rev. 2"))
105 {
106 database.ExecuteResourceSql("UpgradeRegionsTableToVersion3.sql");
107 return;
108 }
109 }
110
111 #endregion
112
113 /// <summary>
114 /// Shuts down the grid interface
115 /// </summary>
116 override public void Close()
117 {
118 database.Close();
119 }
120
121 /// <summary>
122 /// Returns the plugin name
123 /// </summary>
124 /// <returns>Plugin name</returns>
125 override public string getName()
126 {
127 return "MySql OpenGridData";
128 }
129
130 /// <summary>
131 /// Returns the plugin version
132 /// </summary>
133 /// <returns>Plugin version</returns>
134 override public string getVersion()
135 {
136 return "0.1";
137 }
138
139 /// <summary>
140 /// Returns all the specified region profiles within coordates -- coordinates are inclusive
141 /// </summary>
142 /// <param name="xmin">Minimum X coordinate</param>
143 /// <param name="ymin">Minimum Y coordinate</param>
144 /// <param name="xmax">Maximum X coordinate</param>
145 /// <param name="ymax">Maximum Y coordinate</param>
146 /// <returns></returns>
147 override public RegionProfileData[] GetProfilesInRange(uint xmin, uint ymin, uint xmax, uint ymax)
148 {
149 try
150 {
151 lock (database)
152 {
153 Dictionary<string, string> param = new Dictionary<string, string>();
154 param["?xmin"] = xmin.ToString();
155 param["?ymin"] = ymin.ToString();
156 param["?xmax"] = xmax.ToString();
157 param["?ymax"] = ymax.ToString();
158
159 IDbCommand result =
160 database.Query(
161 "SELECT * FROM regions WHERE locX >= ?xmin AND locX <= ?xmax AND locY >= ?ymin AND locY <= ?ymax",
162 param);
163 IDataReader reader = result.ExecuteReader();
164
165 RegionProfileData row;
166
167 List<RegionProfileData> rows = new List<RegionProfileData>();
168
169 while ((row = database.readSimRow(reader)) != null)
170 {
171 rows.Add(row);
172 }
173 reader.Close();
174 result.Dispose();
175
176 return rows.ToArray();
177 }
178 }
179 catch (Exception e)
180 {
181 database.Reconnect();
182 m_log.Error(e.ToString());
183 return null;
184 }
185 }
186
187 /// <summary>
188 /// Returns a sim profile from it's location
189 /// </summary>
190 /// <param name="handle">Region location handle</param>
191 /// <returns>Sim profile</returns>
192 override public RegionProfileData GetProfileByHandle(ulong handle)
193 {
194 try
195 {
196 lock (database)
197 {
198 Dictionary<string, string> param = new Dictionary<string, string>();
199 param["?handle"] = handle.ToString();
200
201 IDbCommand result = database.Query("SELECT * FROM regions WHERE regionHandle = ?handle", param);
202 IDataReader reader = result.ExecuteReader();
203
204 RegionProfileData row = database.readSimRow(reader);
205 reader.Close();
206 result.Dispose();
207
208 return row;
209 }
210 }
211 catch (Exception e)
212 {
213 database.Reconnect();
214 m_log.Error(e.ToString());
215 return null;
216 }
217 }
218
219 /// <summary>
220 /// Returns a sim profile from it's UUID
221 /// </summary>
222 /// <param name="uuid">The region UUID</param>
223 /// <returns>The sim profile</returns>
224 override public RegionProfileData GetProfileByLLUUID(LLUUID uuid)
225 {
226 try
227 {
228 lock (database)
229 {
230 Dictionary<string, string> param = new Dictionary<string, string>();
231 param["?uuid"] = uuid.ToString();
232
233 IDbCommand result = database.Query("SELECT * FROM regions WHERE uuid = ?uuid", param);
234 IDataReader reader = result.ExecuteReader();
235
236 RegionProfileData row = database.readSimRow(reader);
237 reader.Close();
238 result.Dispose();
239
240 return row;
241 }
242 }
243 catch (Exception e)
244 {
245 database.Reconnect();
246 m_log.Error(e.ToString());
247 return null;
248 }
249 }
250
251 /// <summary>
252 /// Returns a sim profile from it's Region name string
253 /// </summary>
254 /// <param name="uuid">The region name search query</param>
255 /// <returns>The sim profile</returns>
256 override public RegionProfileData GetProfileByString(string regionName)
257 {
258 if (regionName.Length > 2)
259 {
260 try
261 {
262 lock (database)
263 {
264 Dictionary<string, string> param = new Dictionary<string, string>();
265 // Add % because this is a like query.
266 param["?regionName"] = regionName + "%";
267 // Order by statement will return shorter matches first. Only returns one record or no record.
268 IDbCommand result = database.Query("SELECT * FROM regions WHERE regionName like ?regionName order by LENGTH(regionName) asc LIMIT 1", param);
269 IDataReader reader = result.ExecuteReader();
270
271 RegionProfileData row = database.readSimRow(reader);
272 reader.Close();
273 result.Dispose();
274
275 return row;
276 }
277 }
278 catch (Exception e)
279 {
280 database.Reconnect();
281 m_log.Error(e.ToString());
282 return null;
283 }
284 }
285 else
286 {
287 m_log.Error("[DATABASE]: Searched for a Region Name shorter then 3 characters");
288 return null;
289 }
290 }
291
292 /// <summary>
293 /// Adds a new profile to the database
294 /// </summary>
295 /// <param name="profile">The profile to add</param>
296 /// <returns>Successful?</returns>
297 override public DataResponse AddProfile(RegionProfileData profile)
298 {
299 lock (database)
300 {
301 if (database.insertRegion(profile))
302 {
303 return DataResponse.RESPONSE_OK;
304 }
305 else
306 {
307 return DataResponse.RESPONSE_ERROR;
308 }
309 }
310 }
311
312 /// <summary>
313 /// Deletes a profile from the database
314 /// </summary>
315 /// <param name="profile">The profile to delete</param>
316 /// <returns>Successful?</returns>
317 //public DataResponse DeleteProfile(RegionProfileData profile)
318 public DataResponse DeleteProfile(string uuid)
319 {
320 lock (database)
321 {
322 if (database.deleteRegion(uuid))
323 {
324 return DataResponse.RESPONSE_OK;
325 }
326 else
327 {
328 return DataResponse.RESPONSE_ERROR;
329 }
330 }
331 }
332
333 /// <summary>
334 /// DEPRECATED. Attempts to authenticate a region by comparing a shared secret.
335 /// </summary>
336 /// <param name="uuid">The UUID of the challenger</param>
337 /// <param name="handle">The attempted regionHandle of the challenger</param>
338 /// <param name="authkey">The secret</param>
339 /// <returns>Whether the secret and regionhandle match the database entry for UUID</returns>
340 override public bool AuthenticateSim(LLUUID uuid, ulong handle, string authkey)
341 {
342 bool throwHissyFit = false; // Should be true by 1.0
343
344 if (throwHissyFit)
345 throw new Exception("CRYPTOWEAK AUTHENTICATE: Refusing to authenticate due to replay potential.");
346
347 RegionProfileData data = GetProfileByLLUUID(uuid);
348
349 return (handle == data.regionHandle && authkey == data.regionSecret);
350 }
351
352 /// <summary>
353 /// NOT YET FUNCTIONAL. Provides a cryptographic authentication of a region
354 /// </summary>
355 /// <remarks>This requires a security audit.</remarks>
356 /// <param name="uuid"></param>
357 /// <param name="handle"></param>
358 /// <param name="authhash"></param>
359 /// <param name="challenge"></param>
360 /// <returns></returns>
361 public bool AuthenticateSim(LLUUID uuid, ulong handle, string authhash, string challenge)
362 {
363 SHA512Managed HashProvider = new SHA512Managed();
364 ASCIIEncoding TextProvider = new ASCIIEncoding();
365
366 byte[] stream = TextProvider.GetBytes(uuid.ToString() + ":" + handle.ToString() + ":" + challenge);
367 byte[] hash = HashProvider.ComputeHash(stream);
368
369 return false;
370 }
371
372 override public ReservationData GetReservationAtPoint(uint x, uint y)
373 {
374 try
375 {
376 lock (database)
377 {
378 Dictionary<string, string> param = new Dictionary<string, string>();
379 param["?x"] = x.ToString();
380 param["?y"] = y.ToString();
381 IDbCommand result =
382 database.Query(
383 "SELECT * FROM reservations WHERE resXMin <= ?x AND resXMax >= ?x AND resYMin <= ?y AND resYMax >= ?y",
384 param);
385 IDataReader reader = result.ExecuteReader();
386
387 ReservationData row = database.readReservationRow(reader);
388 reader.Close();
389 result.Dispose();
390
391 return row;
392 }
393 }
394 catch (Exception e)
395 {
396 database.Reconnect();
397 m_log.Error(e.ToString());
398 return null;
399 }
400 }
401 }
402}
diff --git a/OpenSim/Data/MySQL/MySQLInventoryData.cs b/OpenSim/Data/MySQL/MySQLInventoryData.cs
new file mode 100644
index 0000000..4165d8f
--- /dev/null
+++ b/OpenSim/Data/MySQL/MySQLInventoryData.cs
@@ -0,0 +1,648 @@
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 OpenSim 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 libsecondlife;
31using MySql.Data.MySqlClient;
32using OpenSim.Framework.Console;
33
34namespace OpenSim.Framework.Data.MySQL
35{
36 /// <summary>
37 /// A MySQL interface for the inventory server
38 /// </summary>
39 public class MySQLInventoryData : IInventoryData
40 {
41 private static readonly log4net.ILog m_log
42 = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
43
44 /// <summary>
45 /// The database manager
46 /// </summary>
47 private MySQLManager database;
48
49 /// <summary>
50 /// Loads and initialises this database plugin
51 /// </summary>
52 public void Initialise()
53 {
54 IniFile GridDataMySqlFile = new IniFile("mysql_connection.ini");
55 string settingHostname = GridDataMySqlFile.ParseFileReadValue("hostname");
56 string settingDatabase = GridDataMySqlFile.ParseFileReadValue("database");
57 string settingUsername = GridDataMySqlFile.ParseFileReadValue("username");
58 string settingPassword = GridDataMySqlFile.ParseFileReadValue("password");
59 string settingPooling = GridDataMySqlFile.ParseFileReadValue("pooling");
60 string settingPort = GridDataMySqlFile.ParseFileReadValue("port");
61
62 database =
63 new MySQLManager(settingHostname, settingDatabase, settingUsername, settingPassword, settingPooling,
64 settingPort);
65 TestTables(database.Connection);
66 }
67
68 #region Test and initialization code
69
70 private void UpgradeFoldersTable(string oldVersion)
71 {
72 // null as the version, indicates that the table didn't exist
73 if (oldVersion == null)
74 {
75 database.ExecuteResourceSql("CreateFoldersTable.sql");
76 return;
77 }
78
79 // if the table is already at the current version, then we can exit immediately
80// if (oldVersion == "Rev. 2")
81// return;
82
83// database.ExecuteResourceSql("UpgradeFoldersTableToVersion2.sql");
84 }
85
86 private void UpgradeItemsTable(string oldVersion)
87 {
88 // null as the version, indicates that the table didn't exist
89 if (oldVersion == null)
90 {
91 database.ExecuteResourceSql("CreateItemsTable.sql");
92 return;
93 }
94
95 // if the table is already at the current version, then we can exit immediately
96// if (oldVersion == "Rev. 2")
97// return;
98
99// database.ExecuteResourceSql("UpgradeItemsTableToVersion2.sql");
100 }
101
102 private void TestTables(MySqlConnection conn)
103 {
104 Dictionary<string, string> tableList = new Dictionary<string, string>();
105
106 tableList["inventoryfolders"] = null;
107 tableList["inventoryitems"] = null;
108
109 database.GetTableVersion(tableList);
110 m_log.Info("[MYSQL]: Inventory Folder Version: " + tableList["inventoryfolders"]);
111 m_log.Info("[MYSQL]: Inventory Items Version: " + tableList["inventoryitems"]);
112
113 UpgradeFoldersTable(tableList["inventoryfolders"]);
114 UpgradeItemsTable(tableList["inventoryitems"]);
115 }
116
117 #endregion
118
119 /// <summary>
120 /// The name of this DB provider
121 /// </summary>
122 /// <returns>Name of DB provider</returns>
123 public string getName()
124 {
125 return "MySQL Inventory Data Interface";
126 }
127
128 /// <summary>
129 /// Closes this DB provider
130 /// </summary>
131 public void Close()
132 {
133 // Do nothing.
134 }
135
136 /// <summary>
137 /// Returns the version of this DB provider
138 /// </summary>
139 /// <returns>A string containing the DB provider</returns>
140 public string getVersion()
141 {
142 return database.getVersion();
143 }
144
145 /// <summary>
146 /// Returns a list of items in a specified folder
147 /// </summary>
148 /// <param name="folderID">The folder to search</param>
149 /// <returns>A list containing inventory items</returns>
150 public List<InventoryItemBase> getInventoryInFolder(LLUUID folderID)
151 {
152 try
153 {
154 lock (database)
155 {
156 List<InventoryItemBase> items = new List<InventoryItemBase>();
157
158 MySqlCommand result =
159 new MySqlCommand("SELECT * FROM inventoryitems WHERE parentFolderID = ?uuid",
160 database.Connection);
161 result.Parameters.AddWithValue("?uuid", folderID.ToString());
162 MySqlDataReader reader = result.ExecuteReader();
163
164 while (reader.Read())
165 items.Add(readInventoryItem(reader));
166
167 reader.Close();
168 result.Dispose();
169
170 return items;
171 }
172 }
173 catch (Exception e)
174 {
175 database.Reconnect();
176 m_log.Error(e.ToString());
177 return null;
178 }
179 }
180
181 /// <summary>
182 /// Returns a list of the root folders within a users inventory
183 /// </summary>
184 /// <param name="user">The user whos inventory is to be searched</param>
185 /// <returns>A list of folder objects</returns>
186 public List<InventoryFolderBase> getUserRootFolders(LLUUID user)
187 {
188 try
189 {
190 lock (database)
191 {
192 MySqlCommand result =
193 new MySqlCommand(
194 "SELECT * FROM inventoryfolders WHERE parentFolderID = ?zero AND agentID = ?uuid",
195 database.Connection);
196 result.Parameters.AddWithValue("?uuid", user.ToString());
197 result.Parameters.AddWithValue("?zero", LLUUID.Zero.ToString());
198 MySqlDataReader reader = result.ExecuteReader();
199
200 List<InventoryFolderBase> items = new List<InventoryFolderBase>();
201 while (reader.Read())
202 items.Add(readInventoryFolder(reader));
203
204
205 reader.Close();
206 result.Dispose();
207
208 return items;
209 }
210 }
211 catch (Exception e)
212 {
213 database.Reconnect();
214 m_log.Error(e.ToString());
215 return null;
216 }
217 }
218
219 // see InventoryItemBase.getUserRootFolder
220 public InventoryFolderBase getUserRootFolder(LLUUID user)
221 {
222 try
223 {
224 lock (database)
225 {
226 MySqlCommand result =
227 new MySqlCommand(
228 "SELECT * FROM inventoryfolders WHERE parentFolderID = ?zero AND agentID = ?uuid",
229 database.Connection);
230 result.Parameters.AddWithValue("?uuid", user.ToString());
231 result.Parameters.AddWithValue("?zero", LLUUID.Zero.ToString());
232
233 MySqlDataReader reader = result.ExecuteReader();
234
235 List<InventoryFolderBase> items = new List<InventoryFolderBase>();
236 while (reader.Read())
237 items.Add(readInventoryFolder(reader));
238
239 InventoryFolderBase rootFolder = null;
240
241 // There should only ever be one root folder for a user. However, if there's more
242 // than one we'll simply use the first one rather than failing. It would be even
243 // nicer to print some message to this effect, but this feels like it's too low a
244 // to put such a message out, and it's too minor right now to spare the time to
245 // suitably refactor.
246 if (items.Count > 0)
247 {
248 rootFolder = items[0];
249 }
250
251 reader.Close();
252 result.Dispose();
253
254 return rootFolder;
255 }
256 }
257 catch (Exception e)
258 {
259 database.Reconnect();
260 m_log.Error(e.ToString());
261 return null;
262 }
263 }
264
265 /// <summary>
266 /// Return a list of folders in a users inventory contained within the specified folder.
267 /// This method is only used in tests - in normal operation the user always have one,
268 /// and only one, root folder.
269 /// </summary>
270 /// <param name="parentID">The folder to search</param>
271 /// <returns>A list of inventory folders</returns>
272 public List<InventoryFolderBase> getInventoryFolders(LLUUID parentID)
273 {
274 try
275 {
276 lock (database)
277 {
278 MySqlCommand result =
279 new MySqlCommand("SELECT * FROM inventoryfolders WHERE parentFolderID = ?uuid",
280 database.Connection);
281 result.Parameters.AddWithValue("?uuid", parentID.ToString());
282 MySqlDataReader reader = result.ExecuteReader();
283
284 List<InventoryFolderBase> items = new List<InventoryFolderBase>();
285
286 while (reader.Read())
287 items.Add(readInventoryFolder(reader));
288
289 reader.Close();
290 result.Dispose();
291
292 return items;
293 }
294 }
295 catch (Exception e)
296 {
297 database.Reconnect();
298 m_log.Error(e.ToString());
299 return null;
300 }
301 }
302
303 /// <summary>
304 /// Reads a one item from an SQL result
305 /// </summary>
306 /// <param name="reader">The SQL Result</param>
307 /// <returns>the item read</returns>
308 private InventoryItemBase readInventoryItem(MySqlDataReader reader)
309 {
310 try
311 {
312 InventoryItemBase item = new InventoryItemBase();
313
314 item.inventoryID = new LLUUID((string) reader["inventoryID"]);
315 item.assetID = new LLUUID((string) reader["assetID"]);
316 item.assetType = (int) reader["assetType"];
317 item.parentFolderID = new LLUUID((string) reader["parentFolderID"]);
318 item.avatarID = new LLUUID((string) reader["avatarID"]);
319 item.inventoryName = (string) reader["inventoryName"];
320 item.inventoryDescription = (string) reader["inventoryDescription"];
321 item.inventoryNextPermissions = (uint) reader["inventoryNextPermissions"];
322 item.inventoryCurrentPermissions = (uint) reader["inventoryCurrentPermissions"];
323 item.invType = (int) reader["invType"];
324 item.creatorsID = new LLUUID((string) reader["creatorID"]);
325 item.inventoryBasePermissions = (uint) reader["inventoryBasePermissions"];
326 item.inventoryEveryOnePermissions = (uint) reader["inventoryEveryOnePermissions"];
327 return item;
328 }
329 catch (MySqlException e)
330 {
331 m_log.Error(e.ToString());
332 }
333
334 return null;
335 }
336
337 /// <summary>
338 /// Returns a specified inventory item
339 /// </summary>
340 /// <param name="item">The item to return</param>
341 /// <returns>An inventory item</returns>
342 public InventoryItemBase getInventoryItem(LLUUID itemID)
343 {
344 try
345 {
346 lock (database)
347 {
348 Dictionary<string, string> param = new Dictionary<string, string>();
349
350 MySqlCommand result =
351 new MySqlCommand("SELECT * FROM inventoryitems WHERE inventoryID = ?uuid", database.Connection);
352 result.Parameters.AddWithValue("?uuid", itemID.ToString());
353 MySqlDataReader reader = result.ExecuteReader();
354
355 InventoryItemBase item = null;
356 if (reader.Read())
357 item = readInventoryItem(reader);
358
359 reader.Close();
360 result.Dispose();
361
362 return item;
363 }
364 }
365 catch (Exception e)
366 {
367 database.Reconnect();
368 m_log.Error(e.ToString());
369 }
370 return null;
371 }
372
373 /// <summary>
374 /// Reads a list of inventory folders returned by a query.
375 /// </summary>
376 /// <param name="reader">A MySQL Data Reader</param>
377 /// <returns>A List containing inventory folders</returns>
378 protected InventoryFolderBase readInventoryFolder(MySqlDataReader reader)
379 {
380 try
381 {
382 InventoryFolderBase folder = new InventoryFolderBase();
383 folder.agentID = new LLUUID((string) reader["agentID"]);
384 folder.parentID = new LLUUID((string) reader["parentFolderID"]);
385 folder.folderID = new LLUUID((string) reader["folderID"]);
386 folder.name = (string) reader["folderName"];
387 folder.type = (short) reader["type"];
388 folder.version = (ushort) ((int) reader["version"]);
389 return folder;
390 }
391 catch (Exception e)
392 {
393 m_log.Error(e.ToString());
394 }
395
396 return null;
397 }
398
399
400 /// <summary>
401 /// Returns a specified inventory folder
402 /// </summary>
403 /// <param name="folder">The folder to return</param>
404 /// <returns>A folder class</returns>
405 public InventoryFolderBase getInventoryFolder(LLUUID folderID)
406 {
407 try
408 {
409 lock (database)
410 {
411 MySqlCommand result =
412 new MySqlCommand("SELECT * FROM inventoryfolders WHERE folderID = ?uuid", database.Connection);
413 result.Parameters.AddWithValue("?uuid", folderID.ToString());
414 MySqlDataReader reader = result.ExecuteReader();
415
416 reader.Read();
417 InventoryFolderBase folder = readInventoryFolder(reader);
418 reader.Close();
419 result.Dispose();
420
421 return folder;
422 }
423 }
424 catch (Exception e)
425 {
426 database.Reconnect();
427 m_log.Error(e.ToString());
428 return null;
429 }
430 }
431
432 /// <summary>
433 /// Adds a specified item to the database
434 /// </summary>
435 /// <param name="item">The inventory item</param>
436 public void addInventoryItem(InventoryItemBase item)
437 {
438 string sql =
439 "REPLACE INTO inventoryitems (inventoryID, assetID, assetType, parentFolderID, avatarID, inventoryName, inventoryDescription, inventoryNextPermissions, inventoryCurrentPermissions, invType, creatorID, inventoryBasePermissions, inventoryEveryOnePermissions) VALUES ";
440 sql +=
441 "(?inventoryID, ?assetID, ?assetType, ?parentFolderID, ?avatarID, ?inventoryName, ?inventoryDescription, ?inventoryNextPermissions, ?inventoryCurrentPermissions, ?invType, ?creatorID, ?inventoryBasePermissions, ?inventoryEveryOnePermissions)";
442
443 try
444 {
445 MySqlCommand result = new MySqlCommand(sql, database.Connection);
446 result.Parameters.AddWithValue("?inventoryID", item.inventoryID.ToString());
447 result.Parameters.AddWithValue("?assetID", item.assetID.ToString());
448 result.Parameters.AddWithValue("?assetType", item.assetType.ToString());
449 result.Parameters.AddWithValue("?parentFolderID", item.parentFolderID.ToString());
450 result.Parameters.AddWithValue("?avatarID", item.avatarID.ToString());
451 result.Parameters.AddWithValue("?inventoryName", item.inventoryName);
452 result.Parameters.AddWithValue("?inventoryDescription", item.inventoryDescription);
453 result.Parameters.AddWithValue("?inventoryNextPermissions", item.inventoryNextPermissions.ToString());
454 result.Parameters.AddWithValue("?inventoryCurrentPermissions",
455 item.inventoryCurrentPermissions.ToString());
456 result.Parameters.AddWithValue("?invType", item.invType);
457 result.Parameters.AddWithValue("?creatorID", item.creatorsID.ToString());
458 result.Parameters.AddWithValue("?inventoryBasePermissions", item.inventoryBasePermissions);
459 result.Parameters.AddWithValue("?inventoryEveryOnePermissions", item.inventoryEveryOnePermissions);
460 result.ExecuteNonQuery();
461 result.Dispose();
462 }
463 catch (MySqlException e)
464 {
465 m_log.Error(e.ToString());
466 }
467 }
468
469 /// <summary>
470 /// Updates the specified inventory item
471 /// </summary>
472 /// <param name="item">Inventory item to update</param>
473 public void updateInventoryItem(InventoryItemBase item)
474 {
475 addInventoryItem(item);
476 }
477
478 /// <summary>
479 ///
480 /// </summary>
481 /// <param name="item"></param>
482 public void deleteInventoryItem(LLUUID itemID)
483 {
484 try
485 {
486 MySqlCommand cmd =
487 new MySqlCommand("DELETE FROM inventoryitems WHERE inventoryID=?uuid", database.Connection);
488 cmd.Parameters.AddWithValue("?uuid", itemID.ToString());
489 cmd.ExecuteNonQuery();
490 }
491 catch (MySqlException e)
492 {
493 database.Reconnect();
494 m_log.Error(e.ToString());
495 }
496 }
497
498 /// <summary>
499 /// Creates a new inventory folder
500 /// </summary>
501 /// <param name="folder">Folder to create</param>
502 public void addInventoryFolder(InventoryFolderBase folder)
503 {
504 string sql =
505 "REPLACE INTO inventoryfolders (folderID, agentID, parentFolderID, folderName, type, version) VALUES ";
506 sql += "(?folderID, ?agentID, ?parentFolderID, ?folderName, ?type, ?version)";
507
508 MySqlCommand cmd = new MySqlCommand(sql, database.Connection);
509 cmd.Parameters.AddWithValue("?folderID", folder.folderID.ToString());
510 cmd.Parameters.AddWithValue("?agentID", folder.agentID.ToString());
511 cmd.Parameters.AddWithValue("?parentFolderID", folder.parentID.ToString());
512 cmd.Parameters.AddWithValue("?folderName", folder.name);
513 cmd.Parameters.AddWithValue("?type", (short) folder.type);
514 cmd.Parameters.AddWithValue("?version", folder.version);
515
516 try
517 {
518 lock (database)
519 {
520 cmd.ExecuteNonQuery();
521 }
522 }
523 catch (Exception e)
524 {
525 m_log.Error(e.ToString());
526 }
527 }
528
529 /// <summary>
530 /// Updates an inventory folder
531 /// </summary>
532 /// <param name="folder">Folder to update</param>
533 public void updateInventoryFolder(InventoryFolderBase folder)
534 {
535 addInventoryFolder(folder);
536 }
537
538 /// Creates a new inventory folder
539 /// </summary>
540 /// <param name="folder">Folder to create</param>
541 public void moveInventoryFolder(InventoryFolderBase folder)
542 {
543 string sql =
544 "UPDATE inventoryfolders SET parentFolderID=?parentFolderID WHERE folderID=?folderID";
545
546 MySqlCommand cmd = new MySqlCommand(sql, database.Connection);
547 cmd.Parameters.AddWithValue("?folderID", folder.folderID.ToString());
548 cmd.Parameters.AddWithValue("?parentFolderID", folder.parentID.ToString());
549
550 try
551 {
552 lock (database)
553 {
554 cmd.ExecuteNonQuery();
555 }
556 }
557 catch (Exception e)
558 {
559 m_log.Error(e.ToString());
560 }
561 }
562
563 /// <summary>
564 /// Append a list of all the child folders of a parent folder
565 /// </summary>
566 /// <param name="folders">list where folders will be appended</param>
567 /// <param name="parentID">ID of parent</param>
568 protected void getInventoryFolders(ref List<InventoryFolderBase> folders, LLUUID parentID)
569 {
570 List<InventoryFolderBase> subfolderList = getInventoryFolders(parentID);
571
572 foreach (InventoryFolderBase f in subfolderList)
573 folders.Add(f);
574 }
575
576 // See IInventoryData
577 public List<InventoryFolderBase> getFolderHierarchy(LLUUID parentID)
578 {
579 List<InventoryFolderBase> folders = new List<InventoryFolderBase>();
580 getInventoryFolders(ref folders, parentID);
581
582 for (int i = 0; i < folders.Count; i++)
583 getInventoryFolders(ref folders, folders[i].folderID);
584
585 return folders;
586 }
587
588 protected void deleteOneFolder(LLUUID folderID)
589 {
590 try
591 {
592 MySqlCommand cmd =
593 new MySqlCommand("DELETE FROM inventoryfolders WHERE folderID=?uuid", database.Connection);
594 cmd.Parameters.AddWithValue("?uuid", folderID.ToString());
595
596 lock (database)
597 {
598 cmd.ExecuteNonQuery();
599 }
600 }
601 catch (MySqlException e)
602 {
603 database.Reconnect();
604 m_log.Error(e.ToString());
605 }
606 }
607
608 protected void deleteItemsInFolder(LLUUID folderID)
609 {
610 try
611 {
612 MySqlCommand cmd =
613 new MySqlCommand("DELETE FROM inventoryitems WHERE parentFolderID=?uuid", database.Connection);
614 cmd.Parameters.AddWithValue("?uuid", folderID.ToString());
615
616 lock (database)
617 {
618 cmd.ExecuteNonQuery();
619 }
620 }
621 catch (MySqlException e)
622 {
623 database.Reconnect();
624 m_log.Error(e.ToString());
625 }
626 }
627
628 /// <summary>
629 /// Delete an inventory folder
630 /// </summary>
631 /// <param name="folderId">Id of folder to delete</param>
632 public void deleteInventoryFolder(LLUUID folderID)
633 {
634 List<InventoryFolderBase> subFolders = getFolderHierarchy(folderID);
635
636 //Delete all sub-folders
637 foreach (InventoryFolderBase f in subFolders)
638 {
639 deleteOneFolder(f.folderID);
640 deleteItemsInFolder(f.folderID);
641 }
642
643 //Delete the actual row
644 deleteOneFolder(folderID);
645 deleteItemsInFolder(folderID);
646 }
647 }
648}
diff --git a/OpenSim/Data/MySQL/MySQLLogData.cs b/OpenSim/Data/MySQL/MySQLLogData.cs
new file mode 100644
index 0000000..480446f
--- /dev/null
+++ b/OpenSim/Data/MySQL/MySQLLogData.cs
@@ -0,0 +1,106 @@
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 OpenSim 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
28namespace OpenSim.Framework.Data.MySQL
29{
30 /// <summary>
31 /// An interface to the log database for MySQL
32 /// </summary>
33 internal class MySQLLogData : ILogData
34 {
35 /// <summary>
36 /// The database manager
37 /// </summary>
38 public MySQLManager database;
39
40 /// <summary>
41 /// Artificial constructor called when the plugin is loaded
42 /// </summary>
43 public void Initialise()
44 {
45 IniFile GridDataMySqlFile = new IniFile("mysql_connection.ini");
46 string settingHostname = GridDataMySqlFile.ParseFileReadValue("hostname");
47 string settingDatabase = GridDataMySqlFile.ParseFileReadValue("database");
48 string settingUsername = GridDataMySqlFile.ParseFileReadValue("username");
49 string settingPassword = GridDataMySqlFile.ParseFileReadValue("password");
50 string settingPooling = GridDataMySqlFile.ParseFileReadValue("pooling");
51 string settingPort = GridDataMySqlFile.ParseFileReadValue("port");
52
53 database =
54 new MySQLManager(settingHostname, settingDatabase, settingUsername, settingPassword, settingPooling,
55 settingPort);
56 }
57
58 /// <summary>
59 /// Saves a log item to the database
60 /// </summary>
61 /// <param name="serverDaemon">The daemon triggering the event</param>
62 /// <param name="target">The target of the action (region / agent UUID, etc)</param>
63 /// <param name="methodCall">The method call where the problem occured</param>
64 /// <param name="arguments">The arguments passed to the method</param>
65 /// <param name="priority">How critical is this?</param>
66 /// <param name="logMessage">The message to log</param>
67 public void saveLog(string serverDaemon, string target, string methodCall, string arguments, int priority,
68 string logMessage)
69 {
70 try
71 {
72 database.insertLogRow(serverDaemon, target, methodCall, arguments, priority, logMessage);
73 }
74 catch
75 {
76 database.Reconnect();
77 }
78 }
79
80 /// <summary>
81 /// Returns the name of this DB provider
82 /// </summary>
83 /// <returns>A string containing the DB provider name</returns>
84 public string getName()
85 {
86 return "MySQL Logdata Interface";
87 }
88
89 /// <summary>
90 /// Closes the database provider
91 /// </summary>
92 public void Close()
93 {
94 // Do nothing.
95 }
96
97 /// <summary>
98 /// Returns the version of this DB provider
99 /// </summary>
100 /// <returns>A string containing the provider version</returns>
101 public string getVersion()
102 {
103 return "0.1";
104 }
105 }
106}
diff --git a/OpenSim/Data/MySQL/MySQLManager.cs b/OpenSim/Data/MySQL/MySQLManager.cs
new file mode 100644
index 0000000..579667b
--- /dev/null
+++ b/OpenSim/Data/MySQL/MySQLManager.cs
@@ -0,0 +1,909 @@
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 OpenSim 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.Data.SqlClient;
32using System.IO;
33using System.Reflection;
34using libsecondlife;
35using MySql.Data.MySqlClient;
36using OpenSim.Framework.Console;
37
38namespace OpenSim.Framework.Data.MySQL
39{
40 /// <summary>
41 /// A MySQL Database manager
42 /// </summary>
43 internal class MySQLManager
44 {
45 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
46
47 /// <summary>
48 /// The database connection object
49 /// </summary>
50 private MySqlConnection dbcon;
51
52 /// <summary>
53 /// Connection string for ADO.net
54 /// </summary>
55 private string connectionString;
56
57 /// <summary>
58 /// Initialises and creates a new MySQL connection and maintains it.
59 /// </summary>
60 /// <param name="hostname">The MySQL server being connected to</param>
61 /// <param name="database">The name of the MySQL database being used</param>
62 /// <param name="username">The username logging into the database</param>
63 /// <param name="password">The password for the user logging in</param>
64 /// <param name="cpooling">Whether to use connection pooling or not, can be one of the following: 'yes', 'true', 'no' or 'false', if unsure use 'false'.</param>
65 public MySQLManager(string hostname, string database, string username, string password, string cpooling,
66 string port)
67 {
68 try
69 {
70 connectionString = "Server=" + hostname + ";Port=" + port + ";Database=" + database + ";User ID=" +
71 username + ";Password=" + password + ";Pooling=" + cpooling + ";";
72 dbcon = new MySqlConnection(connectionString);
73
74 try
75 {
76 dbcon.Open();
77 }
78 catch(Exception e)
79 {
80 throw new Exception( "Connection error while using connection string ["+connectionString+"]", e );
81 }
82
83 m_log.Info("[MYSQL]: Connection established");
84 }
85 catch (Exception e)
86 {
87 throw new Exception("Error initialising MySql Database: " + e.ToString());
88 }
89 }
90
91 /// <summary>
92 /// Get the connection being used
93 /// </summary>
94 public MySqlConnection Connection
95 {
96 get { return dbcon; }
97 }
98
99 /// <summary>
100 /// Shuts down the database connection
101 /// </summary>
102 public void Close()
103 {
104 dbcon.Close();
105 dbcon = null;
106 }
107
108 /// <summary>
109 /// Reconnects to the database
110 /// </summary>
111 public void Reconnect()
112 {
113 lock (dbcon)
114 {
115 try
116 {
117 // Close the DB connection
118 dbcon.Close();
119 // Try reopen it
120 dbcon = new MySqlConnection(connectionString);
121 dbcon.Open();
122 }
123 catch (Exception e)
124 {
125 m_log.Error("Unable to reconnect to database " + e.ToString());
126 }
127 }
128 }
129
130 /// <summary>
131 /// Returns the version of this DB provider
132 /// </summary>
133 /// <returns>A string containing the DB provider</returns>
134 public string getVersion()
135 {
136 Module module = GetType().Module;
137 string dllName = module.Assembly.ManifestModule.Name;
138 Version dllVersion = module.Assembly.GetName().Version;
139
140 return
141 string.Format("{0}.{1}.{2}.{3}", dllVersion.Major, dllVersion.Minor, dllVersion.Build,
142 dllVersion.Revision);
143 }
144
145 /// <summary>
146 /// Extract a named string resource from the embedded resources
147 /// </summary>
148 /// <param name="name">name of embedded resource</param>
149 /// <returns>string contained within the embedded resource</returns>
150 private string getResourceString(string name)
151 {
152 Assembly assem = GetType().Assembly;
153 string[] names = assem.GetManifestResourceNames();
154
155 foreach (string s in names)
156 {
157 if (s.EndsWith(name))
158 {
159 using (Stream resource = assem.GetManifestResourceStream(s))
160 {
161 using (StreamReader resourceReader = new StreamReader(resource))
162 {
163 string resourceString = resourceReader.ReadToEnd();
164 return resourceString;
165 }
166 }
167 }
168 }
169 throw new Exception(string.Format("Resource '{0}' was not found", name));
170 }
171
172 /// <summary>
173 /// Execute a SQL statement stored in a resource, as a string
174 /// </summary>
175 /// <param name="name"></param>
176 public void ExecuteResourceSql(string name)
177 {
178 MySqlCommand cmd = new MySqlCommand(getResourceString(name), dbcon);
179 cmd.ExecuteNonQuery();
180 }
181
182 /// <summary>
183 /// Given a list of tables, return the version of the tables, as seen in the database
184 /// </summary>
185 /// <param name="tableList"></param>
186 public void GetTableVersion(Dictionary<string, string> tableList)
187 {
188 lock (dbcon)
189 {
190 MySqlCommand tablesCmd =
191 new MySqlCommand(
192 "SELECT TABLE_NAME, TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=?dbname",
193 dbcon);
194 tablesCmd.Parameters.AddWithValue("?dbname", dbcon.Database);
195 using (MySqlDataReader tables = tablesCmd.ExecuteReader())
196 {
197 while (tables.Read())
198 {
199 try
200 {
201 string tableName = (string) tables["TABLE_NAME"];
202 string comment = (string) tables["TABLE_COMMENT"];
203 if (tableList.ContainsKey(tableName))
204 {
205 tableList[tableName] = comment;
206 }
207 }
208 catch (Exception e)
209 {
210 m_log.Error(e.ToString());
211 }
212 }
213 tables.Close();
214 }
215 }
216 }
217
218 // TODO: at some time this code should be cleaned up
219
220 /// <summary>
221 /// Runs a query with protection against SQL Injection by using parameterised input.
222 /// </summary>
223 /// <param name="sql">The SQL string - replace any variables such as WHERE x = "y" with WHERE x = @y</param>
224 /// <param name="parameters">The parameters - index so that @y is indexed as 'y'</param>
225 /// <returns>A MySQL DB Command</returns>
226 public IDbCommand Query(string sql, Dictionary<string, string> parameters)
227 {
228 try
229 {
230 MySqlCommand dbcommand = (MySqlCommand) dbcon.CreateCommand();
231 dbcommand.CommandText = sql;
232 foreach (KeyValuePair<string, string> param in parameters)
233 {
234 dbcommand.Parameters.AddWithValue(param.Key, param.Value);
235 }
236
237 return (IDbCommand) dbcommand;
238 }
239 catch
240 {
241 lock (dbcon)
242 {
243 // Close the DB connection
244 try
245 {
246 dbcon.Close();
247 }
248 catch
249 {
250 }
251
252 // Try to reopen it
253 try
254 {
255 dbcon = new MySqlConnection(connectionString);
256 dbcon.Open();
257 }
258 catch (Exception e)
259 {
260 m_log.Error("Unable to reconnect to database " + e.ToString());
261 }
262
263 // Run the query again
264 try
265 {
266 MySqlCommand dbcommand = (MySqlCommand) dbcon.CreateCommand();
267 dbcommand.CommandText = sql;
268 foreach (KeyValuePair<string, string> param in parameters)
269 {
270 dbcommand.Parameters.AddWithValue(param.Key, param.Value);
271 }
272
273 return (IDbCommand) dbcommand;
274 }
275 catch (Exception e)
276 {
277 // Return null if it fails.
278 m_log.Error("Failed during Query generation: " + e.ToString());
279 return null;
280 }
281 }
282 }
283 }
284
285 /// <summary>
286 /// Reads a region row from a database reader
287 /// </summary>
288 /// <param name="reader">An active database reader</param>
289 /// <returns>A region profile</returns>
290 public RegionProfileData readSimRow(IDataReader reader)
291 {
292 RegionProfileData retval = new RegionProfileData();
293
294 if (reader.Read())
295 {
296 // Region Main gotta-have-or-we-return-null parts
297 if (!UInt64.TryParse(reader["regionHandle"].ToString(), out retval.regionHandle))
298 return null;
299 if (!LLUUID.TryParse((string)reader["uuid"], out retval.UUID))
300 return null;
301
302 // non-critical parts
303 retval.regionName = (string)reader["regionName"];
304 retval.originUUID = new LLUUID((string) reader["originUUID"]);
305
306 // Secrets
307 retval.regionRecvKey = (string) reader["regionRecvKey"];
308 retval.regionSecret = (string) reader["regionSecret"];
309 retval.regionSendKey = (string) reader["regionSendKey"];
310
311 // Region Server
312 retval.regionDataURI = (string) reader["regionDataURI"];
313 retval.regionOnline = false; // Needs to be pinged before this can be set.
314 retval.serverIP = (string) reader["serverIP"];
315 retval.serverPort = (uint) reader["serverPort"];
316 retval.serverURI = (string) reader["serverURI"];
317 retval.httpPort = Convert.ToUInt32(reader["serverHttpPort"].ToString());
318 retval.remotingPort = Convert.ToUInt32(reader["serverRemotingPort"].ToString());
319
320 // Location
321 retval.regionLocX = Convert.ToUInt32(reader["locX"].ToString());
322 retval.regionLocY = Convert.ToUInt32(reader["locY"].ToString());
323 retval.regionLocZ = Convert.ToUInt32(reader["locZ"].ToString());
324
325 // Neighbours - 0 = No Override
326 retval.regionEastOverrideHandle = Convert.ToUInt64(reader["eastOverrideHandle"].ToString());
327 retval.regionWestOverrideHandle = Convert.ToUInt64(reader["westOverrideHandle"].ToString());
328 retval.regionSouthOverrideHandle = Convert.ToUInt64(reader["southOverrideHandle"].ToString());
329 retval.regionNorthOverrideHandle = Convert.ToUInt64(reader["northOverrideHandle"].ToString());
330
331 // Assets
332 retval.regionAssetURI = (string) reader["regionAssetURI"];
333 retval.regionAssetRecvKey = (string) reader["regionAssetRecvKey"];
334 retval.regionAssetSendKey = (string) reader["regionAssetSendKey"];
335
336 // Userserver
337 retval.regionUserURI = (string) reader["regionUserURI"];
338 retval.regionUserRecvKey = (string) reader["regionUserRecvKey"];
339 retval.regionUserSendKey = (string) reader["regionUserSendKey"];
340
341 // World Map Addition
342 LLUUID.TryParse((string)reader["regionMapTexture"], out retval.regionMapTextureID);
343 LLUUID.TryParse((string)reader["owner_uuid"], out retval.owner_uuid);
344 }
345 else
346 {
347 return null;
348 }
349 return retval;
350 }
351
352 /// <summary>
353 /// Reads a reservation row from a database reader
354 /// </summary>
355 /// <param name="reader">An active database reader</param>
356 /// <returns>A reservation data object</returns>
357 public ReservationData readReservationRow(IDataReader reader)
358 {
359 ReservationData retval = new ReservationData();
360 if (reader.Read())
361 {
362 retval.gridRecvKey = (string) reader["gridRecvKey"];
363 retval.gridSendKey = (string) reader["gridSendKey"];
364 retval.reservationCompany = (string) reader["resCompany"];
365 retval.reservationMaxX = Convert.ToInt32(reader["resXMax"].ToString());
366 retval.reservationMaxY = Convert.ToInt32(reader["resYMax"].ToString());
367 retval.reservationMinX = Convert.ToInt32(reader["resXMin"].ToString());
368 retval.reservationMinY = Convert.ToInt32(reader["resYMin"].ToString());
369 retval.reservationName = (string) reader["resName"];
370 retval.status = Convert.ToInt32(reader["status"].ToString()) == 1;
371 LLUUID.TryParse((string) reader["userUUID"], out retval.userUUID);
372 }
373 else
374 {
375 return null;
376 }
377 return retval;
378 }
379
380 /// <summary>
381 /// Reads an agent row from a database reader
382 /// </summary>
383 /// <param name="reader">An active database reader</param>
384 /// <returns>A user session agent</returns>
385 public UserAgentData readAgentRow(IDataReader reader)
386 {
387 UserAgentData retval = new UserAgentData();
388
389 if (reader.Read())
390 {
391 // Agent IDs
392 if (!LLUUID.TryParse((string)reader["UUID"], out retval.UUID))
393 return null;
394 LLUUID.TryParse((string) reader["sessionID"], out retval.sessionID);
395 LLUUID.TryParse((string)reader["secureSessionID"], out retval.secureSessionID);
396
397 // Agent Who?
398 retval.agentIP = (string) reader["agentIP"];
399 retval.agentPort = Convert.ToUInt32(reader["agentPort"].ToString());
400 retval.agentOnline = Convert.ToBoolean(Convert.ToInt16(reader["agentOnline"].ToString()));
401
402 // Login/Logout times (UNIX Epoch)
403 retval.loginTime = Convert.ToInt32(reader["loginTime"].ToString());
404 retval.logoutTime = Convert.ToInt32(reader["logoutTime"].ToString());
405
406 // Current position
407 retval.currentRegion = new LLUUID((string)reader["currentRegion"]);
408 retval.currentHandle = Convert.ToUInt64(reader["currentHandle"].ToString());
409 LLVector3.TryParse((string) reader["currentPos"], out retval.currentPos);
410 }
411 else
412 {
413 return null;
414 }
415 return retval;
416 }
417
418 /// <summary>
419 /// Reads a user profile from an active data reader
420 /// </summary>
421 /// <param name="reader">An active database reader</param>
422 /// <returns>A user profile</returns>
423 public UserProfileData readUserRow(IDataReader reader)
424 {
425 UserProfileData retval = new UserProfileData();
426
427 if (reader.Read())
428 {
429 if (!LLUUID.TryParse((string)reader["UUID"], out retval.UUID))
430 return null;
431 retval.username = (string) reader["username"];
432 retval.surname = (string) reader["lastname"];
433
434 retval.passwordHash = (string) reader["passwordHash"];
435 retval.passwordSalt = (string) reader["passwordSalt"];
436
437 retval.homeRegion = Convert.ToUInt64(reader["homeRegion"].ToString());
438 retval.homeLocation = new LLVector3(
439 Convert.ToSingle(reader["homeLocationX"].ToString()),
440 Convert.ToSingle(reader["homeLocationY"].ToString()),
441 Convert.ToSingle(reader["homeLocationZ"].ToString()));
442 retval.homeLookAt = new LLVector3(
443 Convert.ToSingle(reader["homeLookAtX"].ToString()),
444 Convert.ToSingle(reader["homeLookAtY"].ToString()),
445 Convert.ToSingle(reader["homeLookAtZ"].ToString()));
446
447 retval.created = Convert.ToInt32(reader["created"].ToString());
448 retval.lastLogin = Convert.ToInt32(reader["lastLogin"].ToString());
449
450 retval.userInventoryURI = (string) reader["userInventoryURI"];
451 retval.userAssetURI = (string) reader["userAssetURI"];
452
453 retval.profileCanDoMask = Convert.ToUInt32(reader["profileCanDoMask"].ToString());
454 retval.profileWantDoMask = Convert.ToUInt32(reader["profileWantDoMask"].ToString());
455
456 if (reader.IsDBNull(reader.GetOrdinal("profileAboutText")))
457 retval.profileAboutText = "";
458 else
459 retval.profileAboutText = (string) reader["profileAboutText"];
460
461 if (reader.IsDBNull(reader.GetOrdinal("profileFirstText")))
462 retval.profileFirstText = "";
463 else
464 retval.profileFirstText = (string)reader["profileFirstText"];
465
466 if (reader.IsDBNull(reader.GetOrdinal("profileImage")))
467 retval.profileImage = LLUUID.Zero;
468 else
469 LLUUID.TryParse((string)reader["profileImage"], out retval.profileImage);
470
471 if (reader.IsDBNull(reader.GetOrdinal("profileFirstImage")))
472 retval.profileFirstImage = LLUUID.Zero;
473 else
474 LLUUID.TryParse((string)reader["profileFirstImage"], out retval.profileFirstImage);
475
476 if(reader.IsDBNull(reader.GetOrdinal("webLoginKey")))
477 {
478 retval.webLoginKey = LLUUID.Zero;
479 }
480 else
481 {
482 LLUUID.TryParse((string)reader["webLoginKey"], out retval.webLoginKey);
483 }
484 }
485 else
486 {
487 return null;
488 }
489 return retval;
490 }
491
492 /// <summary>
493 /// Inserts a new row into the log database
494 /// </summary>
495 /// <param name="serverDaemon">The daemon which triggered this event</param>
496 /// <param name="target">Who were we operating on when this occured (region UUID, user UUID, etc)</param>
497 /// <param name="methodCall">The method call where the problem occured</param>
498 /// <param name="arguments">The arguments passed to the method</param>
499 /// <param name="priority">How critical is this?</param>
500 /// <param name="logMessage">Extra message info</param>
501 /// <returns>Saved successfully?</returns>
502 public bool insertLogRow(string serverDaemon, string target, string methodCall, string arguments, int priority,
503 string logMessage)
504 {
505 string sql = "INSERT INTO logs (`target`, `server`, `method`, `arguments`, `priority`, `message`) VALUES ";
506 sql += "(?target, ?server, ?method, ?arguments, ?priority, ?message)";
507
508 Dictionary<string, string> parameters = new Dictionary<string, string>();
509 parameters["?server"] = serverDaemon;
510 parameters["?target"] = target;
511 parameters["?method"] = methodCall;
512 parameters["?arguments"] = arguments;
513 parameters["?priority"] = priority.ToString();
514 parameters["?message"] = logMessage;
515
516 bool returnval = false;
517
518 try
519 {
520 IDbCommand result = Query(sql, parameters);
521
522 if (result.ExecuteNonQuery() == 1)
523 returnval = true;
524
525 result.Dispose();
526 }
527 catch (Exception e)
528 {
529 m_log.Error(e.ToString());
530 return false;
531 }
532
533 return returnval;
534 }
535
536 /// <summary>
537 /// Creates a new user and inserts it into the database
538 /// </summary>
539 /// <param name="uuid">User ID</param>
540 /// <param name="username">First part of the login</param>
541 /// <param name="lastname">Second part of the login</param>
542 /// <param name="passwordHash">A salted hash of the users password</param>
543 /// <param name="passwordSalt">The salt used for the password hash</param>
544 /// <param name="homeRegion">A regionHandle of the users home region</param>
545 /// <param name="homeLocX">Home region position vector</param>
546 /// <param name="homeLocY">Home region position vector</param>
547 /// <param name="homeLocZ">Home region position vector</param>
548 /// <param name="homeLookAtX">Home region 'look at' vector</param>
549 /// <param name="homeLookAtY">Home region 'look at' vector</param>
550 /// <param name="homeLookAtZ">Home region 'look at' vector</param>
551 /// <param name="created">Account created (unix timestamp)</param>
552 /// <param name="lastlogin">Last login (unix timestamp)</param>
553 /// <param name="inventoryURI">Users inventory URI</param>
554 /// <param name="assetURI">Users asset URI</param>
555 /// <param name="canDoMask">I can do mask</param>
556 /// <param name="wantDoMask">I want to do mask</param>
557 /// <param name="aboutText">Profile text</param>
558 /// <param name="firstText">Firstlife text</param>
559 /// <param name="profileImage">UUID for profile image</param>
560 /// <param name="firstImage">UUID for firstlife image</param>
561 /// <returns>Success?</returns>
562 public bool insertUserRow(LLUUID uuid, string username, string lastname, string passwordHash,
563 string passwordSalt, UInt64 homeRegion, float homeLocX, float homeLocY, float homeLocZ,
564 float homeLookAtX, float homeLookAtY, float homeLookAtZ, int created, int lastlogin,
565 string inventoryURI, string assetURI, uint canDoMask, uint wantDoMask,
566 string aboutText, string firstText,
567 LLUUID profileImage, LLUUID firstImage, LLUUID webLoginKey)
568 {
569 m_log.Debug("[MySQLManager]: Fetching profile for " + uuid.ToString());
570 string sql =
571 "INSERT INTO users (`UUID`, `username`, `lastname`, `passwordHash`, `passwordSalt`, `homeRegion`, ";
572 sql +=
573 "`homeLocationX`, `homeLocationY`, `homeLocationZ`, `homeLookAtX`, `homeLookAtY`, `homeLookAtZ`, `created`, ";
574 sql +=
575 "`lastLogin`, `userInventoryURI`, `userAssetURI`, `profileCanDoMask`, `profileWantDoMask`, `profileAboutText`, ";
576 sql += "`profileFirstText`, `profileImage`, `profileFirstImage`, `webLoginKey`) VALUES ";
577
578 sql += "(?UUID, ?username, ?lastname, ?passwordHash, ?passwordSalt, ?homeRegion, ";
579 sql +=
580 "?homeLocationX, ?homeLocationY, ?homeLocationZ, ?homeLookAtX, ?homeLookAtY, ?homeLookAtZ, ?created, ";
581 sql +=
582 "?lastLogin, ?userInventoryURI, ?userAssetURI, ?profileCanDoMask, ?profileWantDoMask, ?profileAboutText, ";
583 sql += "?profileFirstText, ?profileImage, ?profileFirstImage, ?webLoginKey)";
584
585 Dictionary<string, string> parameters = new Dictionary<string, string>();
586 parameters["?UUID"] = uuid.ToString();
587 parameters["?username"] = username.ToString();
588 parameters["?lastname"] = lastname.ToString();
589 parameters["?passwordHash"] = passwordHash.ToString();
590 parameters["?passwordSalt"] = passwordSalt.ToString();
591 parameters["?homeRegion"] = homeRegion.ToString();
592 parameters["?homeLocationX"] = homeLocX.ToString();
593 parameters["?homeLocationY"] = homeLocY.ToString();
594 parameters["?homeLocationZ"] = homeLocZ.ToString();
595 parameters["?homeLookAtX"] = homeLookAtX.ToString();
596 parameters["?homeLookAtY"] = homeLookAtY.ToString();
597 parameters["?homeLookAtZ"] = homeLookAtZ.ToString();
598 parameters["?created"] = created.ToString();
599 parameters["?lastLogin"] = lastlogin.ToString();
600 parameters["?userInventoryURI"] = String.Empty;
601 parameters["?userAssetURI"] = String.Empty;
602 parameters["?profileCanDoMask"] = "0";
603 parameters["?profileWantDoMask"] = "0";
604 parameters["?profileAboutText"] = aboutText;
605 parameters["?profileFirstText"] = firstText;
606 parameters["?profileImage"] = profileImage.ToString();
607 parameters["?profileFirstImage"] = firstImage.ToString();
608 parameters["?webLoginKey"] = string.Empty;
609
610 bool returnval = false;
611
612 try
613 {
614 IDbCommand result = Query(sql, parameters);
615
616 if (result.ExecuteNonQuery() == 1)
617 returnval = true;
618
619 result.Dispose();
620 }
621 catch (Exception e)
622 {
623 m_log.Error(e.ToString());
624 return false;
625 }
626
627 m_log.Debug("[MySQLManager]: Fetch user retval == " + returnval.ToString());
628 return returnval;
629 }
630
631 /// <summary>
632 /// Creates a new user and inserts it into the database
633 /// </summary>
634 /// <param name="uuid">User ID</param>
635 /// <param name="username">First part of the login</param>
636 /// <param name="lastname">Second part of the login</param>
637 /// <param name="passwordHash">A salted hash of the users password</param>
638 /// <param name="passwordSalt">The salt used for the password hash</param>
639 /// <param name="homeRegion">A regionHandle of the users home region</param>
640 /// <param name="homeLocX">Home region position vector</param>
641 /// <param name="homeLocY">Home region position vector</param>
642 /// <param name="homeLocZ">Home region position vector</param>
643 /// <param name="homeLookAtX">Home region 'look at' vector</param>
644 /// <param name="homeLookAtY">Home region 'look at' vector</param>
645 /// <param name="homeLookAtZ">Home region 'look at' vector</param>
646 /// <param name="created">Account created (unix timestamp)</param>
647 /// <param name="lastlogin">Last login (unix timestamp)</param>
648 /// <param name="inventoryURI">Users inventory URI</param>
649 /// <param name="assetURI">Users asset URI</param>
650 /// <param name="canDoMask">I can do mask</param>
651 /// <param name="wantDoMask">I want to do mask</param>
652 /// <param name="aboutText">Profile text</param>
653 /// <param name="firstText">Firstlife text</param>
654 /// <param name="profileImage">UUID for profile image</param>
655 /// <param name="firstImage">UUID for firstlife image</param>
656 /// <returns>Success?</returns>
657 public bool updateUserRow(LLUUID uuid, string username, string lastname, string passwordHash,
658 string passwordSalt, UInt64 homeRegion, float homeLocX, float homeLocY, float homeLocZ,
659 float homeLookAtX, float homeLookAtY, float homeLookAtZ, int created, int lastlogin,
660 string inventoryURI, string assetURI, uint canDoMask, uint wantDoMask,
661 string aboutText, string firstText,
662 LLUUID profileImage, LLUUID firstImage, LLUUID webLoginKey)
663 {
664 string sql = "UPDATE users SET `username` = ?username , `lastname` = ?lastname ";
665 sql += ", `passwordHash` = ?passwordHash , `passwordSalt` = ?passwordSalt , ";
666 sql += "`homeRegion` = ?homeRegion , `homeLocationX` = ?homeLocationX , ";
667 sql += "`homeLocationY` = ?homeLocationY , `homeLocationZ` = ?homeLocationZ , ";
668 sql += "`homeLookAtX` = ?homeLookAtX , `homeLookAtY` = ?homeLookAtY , ";
669 sql += "`homeLookAtZ` = ?homeLookAtZ , `created` = ?created , `lastLogin` = ?lastLogin , ";
670 sql += "`userInventoryURI` = ?userInventoryURI , `userAssetURI` = ?userAssetURI , ";
671 sql += "`profileCanDoMask` = ?profileCanDoMask , `profileWantDoMask` = ?profileWantDoMask , ";
672 sql += "`profileAboutText` = ?profileAboutText , `profileFirstText` = ?profileFirstText, ";
673 sql += "`profileImage` = ?profileImage , `profileFirstImage` = ?profileFirstImage , ";
674 sql += "`webLoginKey` = ?webLoginKey WHERE UUID = ?UUID";
675
676 Dictionary<string, string> parameters = new Dictionary<string, string>();
677 parameters["?UUID"] = uuid.ToString();
678 parameters["?username"] = username.ToString();
679 parameters["?lastname"] = lastname.ToString();
680 parameters["?passwordHash"] = passwordHash.ToString();
681 parameters["?passwordSalt"] = passwordSalt.ToString();
682 parameters["?homeRegion"] = homeRegion.ToString();
683 parameters["?homeLocationX"] = homeLocX.ToString();
684 parameters["?homeLocationY"] = homeLocY.ToString();
685 parameters["?homeLocationZ"] = homeLocZ.ToString();
686 parameters["?homeLookAtX"] = homeLookAtX.ToString();
687 parameters["?homeLookAtY"] = homeLookAtY.ToString();
688 parameters["?homeLookAtZ"] = homeLookAtZ.ToString();
689 parameters["?created"] = created.ToString();
690 parameters["?lastLogin"] = lastlogin.ToString();
691 parameters["?userInventoryURI"] = inventoryURI;
692 parameters["?userAssetURI"] = assetURI;
693 parameters["?profileCanDoMask"] = "0";
694 parameters["?profileWantDoMask"] = "0";
695 parameters["?profileAboutText"] = aboutText;
696 parameters["?profileFirstText"] = firstText;
697 parameters["?profileImage"] = profileImage.ToString();
698 parameters["?profileFirstImage"] = firstImage.ToString();
699 parameters["?webLoginKey"] = webLoginKey.ToString();
700
701 bool returnval = false;
702 try
703 {
704 IDbCommand result = Query(sql, parameters);
705
706 if (result.ExecuteNonQuery() == 1)
707 returnval = true;
708
709 result.Dispose();
710 }
711 catch (Exception e)
712 {
713 m_log.Error(e.ToString());
714 return false;
715 }
716
717 m_log.Debug("[MySQLManager]: update user retval == " + returnval.ToString());
718 return returnval;
719 }
720
721 /// <summary>
722 /// Inserts a new region into the database
723 /// </summary>
724 /// <param name="profile">The region to insert</param>
725 /// <returns>Success?</returns>
726 public bool insertRegion(RegionProfileData regiondata)
727 {
728 bool GRID_ONLY_UPDATE_NECESSARY_DATA = false;
729
730 string sql = String.Empty;
731 if (GRID_ONLY_UPDATE_NECESSARY_DATA)
732 {
733 sql += "INSERT INTO ";
734 }
735 else
736 {
737 sql += "REPLACE INTO ";
738 }
739
740 sql += "regions (regionHandle, regionName, uuid, regionRecvKey, regionSecret, regionSendKey, regionDataURI, ";
741 sql +=
742 "serverIP, serverPort, serverURI, locX, locY, locZ, eastOverrideHandle, westOverrideHandle, southOverrideHandle, northOverrideHandle, regionAssetURI, regionAssetRecvKey, ";
743
744 // part of an initial brutish effort to provide accurate information (as per the xml region spec)
745 // wrt the ownership of a given region
746 // the (very bad) assumption is that this value is being read and handled inconsistently or
747 // not at all. Current strategy is to put the code in place to support the validity of this information
748 // and to roll forward debugging any issues from that point
749 //
750 // this particular section of the mod attempts to implement the commit of a supplied value
751 // server for the UUID of the region's owner (master avatar). It consists of the addition of the column and value to the relevant sql,
752 // as well as the related parameterization
753 sql +=
754 "regionAssetSendKey, regionUserURI, regionUserRecvKey, regionUserSendKey, regionMapTexture, serverHttpPort, serverRemotingPort, owner_uuid, originUUID) VALUES ";
755
756 sql += "(?regionHandle, ?regionName, ?uuid, ?regionRecvKey, ?regionSecret, ?regionSendKey, ?regionDataURI, ";
757 sql +=
758 "?serverIP, ?serverPort, ?serverURI, ?locX, ?locY, ?locZ, ?eastOverrideHandle, ?westOverrideHandle, ?southOverrideHandle, ?northOverrideHandle, ?regionAssetURI, ?regionAssetRecvKey, ";
759 sql +=
760 "?regionAssetSendKey, ?regionUserURI, ?regionUserRecvKey, ?regionUserSendKey, ?regionMapTexture, ?serverHttpPort, ?serverRemotingPort, ?owner_uuid, ?originUUID)";
761
762 if (GRID_ONLY_UPDATE_NECESSARY_DATA)
763 {
764 sql += "ON DUPLICATE KEY UPDATE serverIP = ?serverIP, serverPort = ?serverPort, serverURI = ?serverURI, owner_uuid - ?owner_uuid;";
765 }
766 else
767 {
768 sql += ";";
769 }
770
771 Dictionary<string, string> parameters = new Dictionary<string, string>();
772
773 parameters["?regionHandle"] = regiondata.regionHandle.ToString();
774 parameters["?regionName"] = regiondata.regionName.ToString();
775 parameters["?uuid"] = regiondata.UUID.ToString();
776 parameters["?regionRecvKey"] = regiondata.regionRecvKey.ToString();
777 parameters["?regionSecret"] = regiondata.regionSecret.ToString();
778 parameters["?regionSendKey"] = regiondata.regionSendKey.ToString();
779 parameters["?regionDataURI"] = regiondata.regionDataURI.ToString();
780 parameters["?serverIP"] = regiondata.serverIP.ToString();
781 parameters["?serverPort"] = regiondata.serverPort.ToString();
782 parameters["?serverURI"] = regiondata.serverURI.ToString();
783 parameters["?locX"] = regiondata.regionLocX.ToString();
784 parameters["?locY"] = regiondata.regionLocY.ToString();
785 parameters["?locZ"] = regiondata.regionLocZ.ToString();
786 parameters["?eastOverrideHandle"] = regiondata.regionEastOverrideHandle.ToString();
787 parameters["?westOverrideHandle"] = regiondata.regionWestOverrideHandle.ToString();
788 parameters["?northOverrideHandle"] = regiondata.regionNorthOverrideHandle.ToString();
789 parameters["?southOverrideHandle"] = regiondata.regionSouthOverrideHandle.ToString();
790 parameters["?regionAssetURI"] = regiondata.regionAssetURI.ToString();
791 parameters["?regionAssetRecvKey"] = regiondata.regionAssetRecvKey.ToString();
792 parameters["?regionAssetSendKey"] = regiondata.regionAssetSendKey.ToString();
793 parameters["?regionUserURI"] = regiondata.regionUserURI.ToString();
794 parameters["?regionUserRecvKey"] = regiondata.regionUserRecvKey.ToString();
795 parameters["?regionUserSendKey"] = regiondata.regionUserSendKey.ToString();
796 parameters["?regionMapTexture"] = regiondata.regionMapTextureID.ToString();
797 parameters["?serverHttpPort"] = regiondata.httpPort.ToString();
798 parameters["?serverRemotingPort"] = regiondata.remotingPort.ToString();
799 parameters["?owner_uuid"] = regiondata.owner_uuid.ToString();
800 parameters["?originUUID"] = regiondata.originUUID.ToString();
801
802 bool returnval = false;
803
804 try
805 {
806 IDbCommand result = Query(sql, parameters);
807
808 //Console.WriteLine(result.CommandText);
809 int x;
810 if ((x = result.ExecuteNonQuery()) > 0)
811 {
812 returnval = true;
813 }
814 result.Dispose();
815 }
816 catch (Exception e)
817 {
818 m_log.Error(e.ToString());
819 return false;
820 }
821
822 return returnval;
823 }
824
825 /// <summary>
826 /// Delete a region from the database
827 /// </summary>
828 /// <param name="profile">The region to insert</param>
829 /// <returns>Success?</returns>
830 //public bool deleteRegion(RegionProfileData regiondata)
831 public bool deleteRegion(string uuid)
832 {
833 bool returnval = false;
834
835 string sql = "DELETE FROM regions WHERE uuid = ?uuid;";
836
837 Dictionary<string, string> parameters = new Dictionary<string, string>();
838
839 try
840 {
841 parameters["?uuid"] = uuid;
842
843 IDbCommand result = Query(sql, parameters);
844
845 int x;
846 if ((x = result.ExecuteNonQuery()) > 0)
847 {
848 returnval = true;
849 }
850 result.Dispose();
851 }
852 catch (Exception e)
853 {
854 m_log.Error(e.ToString());
855 return false;
856 }
857
858 return returnval;
859 }
860
861 /// <summary>
862 /// Creates a new agent and inserts it into the database
863 /// </summary>
864 /// <param name="agentdata">The agent data to be inserted</param>
865 /// <returns>Success?</returns>
866 public bool insertAgentRow(UserAgentData agentdata)
867 {
868 string sql = String.Empty;
869 sql += "REPLACE INTO ";
870 sql += "agents (UUID, sessionID, secureSessionID, agentIP, agentPort, agentOnline, loginTime, logoutTime, currentRegion, currentHandle, currentPos) VALUES ";
871 sql += "(?UUID, ?sessionID, ?secureSessionID, ?agentIP, ?agentPort, ?agentOnline, ?loginTime, ?logoutTime, ?currentRegion, ?currentHandle, ?currentPos);";
872 Dictionary<string, string> parameters = new Dictionary<string, string>();
873
874 parameters["?UUID"] = agentdata.UUID.ToString();
875 parameters["?sessionID"] = agentdata.sessionID.ToString();
876 parameters["?secureSessionID"] = agentdata.secureSessionID.ToString();
877 parameters["?agentIP"] = agentdata.agentIP.ToString();
878 parameters["?agentPort"] = agentdata.agentPort.ToString();
879 parameters["?agentOnline"] = (agentdata.agentOnline == true) ? "1" : "0";
880 parameters["?loginTime"] = agentdata.loginTime.ToString();
881 parameters["?logoutTime"] = agentdata.logoutTime.ToString();
882 parameters["?currentRegion"] = agentdata.currentRegion.ToString();
883 parameters["?currentHandle"] = agentdata.currentHandle.ToString();
884 parameters["?currentPos"] = "<" + ((int)agentdata.currentPos.X).ToString() + "," + ((int)agentdata.currentPos.Y).ToString() + "," + ((int)agentdata.currentPos.Z).ToString() + ">";
885
886 bool returnval = false;
887
888 try
889 {
890 IDbCommand result = Query(sql, parameters);
891
892 //Console.WriteLine(result.CommandText);
893 int x;
894 if ((x = result.ExecuteNonQuery()) > 0)
895 {
896 returnval = true;
897 }
898 result.Dispose();
899 }
900 catch (Exception e)
901 {
902 m_log.Error(e.ToString());
903 return false;
904 }
905
906 return returnval;
907 }
908 }
909}
diff --git a/OpenSim/Data/MySQL/MySQLUserData.cs b/OpenSim/Data/MySQL/MySQLUserData.cs
new file mode 100644
index 0000000..fd640ec
--- /dev/null
+++ b/OpenSim/Data/MySQL/MySQLUserData.cs
@@ -0,0 +1,643 @@
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 OpenSim 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.Text.RegularExpressions;
32using libsecondlife;
33using OpenSim.Framework.Console;
34
35namespace OpenSim.Framework.Data.MySQL
36{
37 /// <summary>
38 /// A database interface class to a user profile storage system
39 /// </summary>
40 internal class MySQLUserData : UserDataBase
41 {
42 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
43
44 /// <summary>
45 /// Database manager for MySQL
46 /// </summary>
47 public MySQLManager database;
48
49 private string m_agentsTableName;
50 private string m_usersTableName;
51 private string m_userFriendsTableName;
52
53 /// <summary>
54 /// Loads and initialises the MySQL storage plugin
55 /// </summary>
56 override public void Initialise()
57 {
58 // Load from an INI file connection details
59 // TODO: move this to XML? Yes, PLEASE!
60
61 IniFile iniFile = new IniFile("mysql_connection.ini");
62 string settingHostname = iniFile.ParseFileReadValue("hostname");
63 string settingDatabase = iniFile.ParseFileReadValue("database");
64 string settingUsername = iniFile.ParseFileReadValue("username");
65 string settingPassword = iniFile.ParseFileReadValue("password");
66 string settingPooling = iniFile.ParseFileReadValue("pooling");
67 string settingPort = iniFile.ParseFileReadValue("port");
68
69 m_usersTableName = iniFile.ParseFileReadValue("userstablename");
70 if( m_usersTableName == null )
71 {
72 m_usersTableName = "users";
73 }
74
75 m_userFriendsTableName = iniFile.ParseFileReadValue("userfriendstablename");
76 if (m_userFriendsTableName == null)
77 {
78 m_userFriendsTableName = "userfriends";
79 }
80
81 m_agentsTableName = iniFile.ParseFileReadValue("agentstablename");
82 if (m_agentsTableName == null)
83 {
84 m_agentsTableName = "agents";
85 }
86
87 database =
88 new MySQLManager(settingHostname, settingDatabase, settingUsername, settingPassword, settingPooling,
89 settingPort);
90
91 TestTables();
92 }
93
94 #region Test and initialization code
95
96 /// <summary>
97 /// Ensure that the user related tables exists and are at the latest version
98 /// </summary>
99 private void TestTables()
100 {
101 Dictionary<string, string> tableList = new Dictionary<string, string>();
102
103 tableList[m_agentsTableName] = null;
104 tableList[m_usersTableName] = null;
105 tableList[m_userFriendsTableName] = null;
106 database.GetTableVersion(tableList);
107
108 UpgradeAgentsTable(tableList[m_agentsTableName]);
109 UpgradeUsersTable(tableList[m_usersTableName]);
110 UpgradeFriendsTable(tableList[m_userFriendsTableName]);
111 }
112
113 /// <summary>
114 /// Create or upgrade the table if necessary
115 /// </summary>
116 /// <param name="oldVersion">A null indicates that the table does not
117 /// currently exist</param>
118 private void UpgradeAgentsTable(string oldVersion)
119 {
120 // null as the version, indicates that the table didn't exist
121 if (oldVersion == null)
122 {
123 database.ExecuteResourceSql("CreateAgentsTable.sql");
124 return;
125 }
126 }
127
128 /// <summary>
129 /// Create or upgrade the table if necessary
130 /// </summary>
131 /// <param name="oldVersion">A null indicates that the table does not
132 /// currently exist</param>
133 private void UpgradeUsersTable(string oldVersion)
134 {
135 // null as the version, indicates that the table didn't exist
136 if (oldVersion == null)
137 {
138 database.ExecuteResourceSql("CreateUsersTable.sql");
139 return;
140 }
141 else if (oldVersion.Contains("Rev. 1"))
142 {
143 database.ExecuteResourceSql("UpgradeUsersTableToVersion2.sql");
144 return;
145 }
146 //m_log.Info("[DB]: DBVers:" + oldVersion);
147 }
148
149 /// <summary>
150 /// Create or upgrade the table if necessary
151 /// </summary>
152 /// <param name="oldVersion">A null indicates that the table does not
153 /// currently exist</param>
154 private void UpgradeFriendsTable(string oldVersion)
155 {
156 // null as the version, indicates that the table didn't exist
157 if (oldVersion == null)
158 {
159 database.ExecuteResourceSql("CreateUserFriendsTable.sql");
160 return;
161 }
162 }
163
164 #endregion
165
166 // see IUserData
167 override public UserProfileData GetUserByName(string user, string last)
168 {
169 try
170 {
171 lock (database)
172 {
173 Dictionary<string, string> param = new Dictionary<string, string>();
174 param["?first"] = user;
175 param["?second"] = last;
176
177 IDbCommand result =
178 database.Query("SELECT * FROM " + m_usersTableName + " WHERE username = ?first AND lastname = ?second", param);
179 IDataReader reader = result.ExecuteReader();
180
181 UserProfileData row = database.readUserRow(reader);
182
183 reader.Close();
184 result.Dispose();
185 return row;
186 }
187 }
188 catch (Exception e)
189 {
190 database.Reconnect();
191 m_log.Error(e.ToString());
192 return null;
193 }
194 }
195
196 #region User Friends List Data
197
198 override public void AddNewUserFriend(LLUUID friendlistowner, LLUUID friend, uint perms)
199 {
200 int dtvalue = Util.UnixTimeSinceEpoch();
201
202 Dictionary<string, string> param = new Dictionary<string, string>();
203 param["?ownerID"] = friendlistowner.UUID.ToString();
204 param["?friendID"] = friend.UUID.ToString();
205 param["?friendPerms"] = perms.ToString();
206 param["?datetimestamp"] = dtvalue.ToString();
207
208 try
209 {
210 lock (database)
211 {
212 IDbCommand adder =
213 database.Query(
214 "INSERT INTO `" + m_userFriendsTableName + "` " +
215 "(`ownerID`,`friendID`,`friendPerms`,`datetimestamp`) " +
216 "VALUES " +
217 "(?ownerID,?friendID,?friendPerms,?datetimestamp)",
218 param);
219 adder.ExecuteNonQuery();
220
221 adder =
222 database.Query(
223 "INSERT INTO `" + m_userFriendsTableName + "` " +
224 "(`ownerID`,`friendID`,`friendPerms`,`datetimestamp`) " +
225 "VALUES " +
226 "(?friendID,?ownerID,?friendPerms,?datetimestamp)",
227 param);
228 adder.ExecuteNonQuery();
229 }
230 }
231 catch (Exception e)
232 {
233 database.Reconnect();
234 m_log.Error(e.ToString());
235 return;
236 }
237 }
238
239 override public void RemoveUserFriend(LLUUID friendlistowner, LLUUID friend)
240 {
241 Dictionary<string, string> param = new Dictionary<string, string>();
242 param["?ownerID"] = friendlistowner.UUID.ToString();
243 param["?friendID"] = friend.UUID.ToString();
244
245 try
246 {
247 lock (database)
248 {
249 IDbCommand updater =
250 database.Query(
251 "delete from " + m_userFriendsTableName + " where ownerID = ?ownerID and friendID = ?friendID",
252 param);
253 updater.ExecuteNonQuery();
254
255 updater =
256 database.Query(
257 "delete from " + m_userFriendsTableName + " where ownerID = ?friendID and friendID = ?ownerID",
258 param);
259 updater.ExecuteNonQuery();
260 }
261 }
262 catch (Exception e)
263 {
264 database.Reconnect();
265 m_log.Error(e.ToString());
266 return;
267 }
268 }
269
270 override public void UpdateUserFriendPerms(LLUUID friendlistowner, LLUUID friend, uint perms)
271 {
272 Dictionary<string, string> param = new Dictionary<string, string>();
273 param["?ownerID"] = friendlistowner.UUID.ToString();
274 param["?friendID"] = friend.UUID.ToString();
275 param["?friendPerms"] = perms.ToString();
276
277 try
278 {
279 lock (database)
280 {
281 IDbCommand updater =
282 database.Query(
283 "update " + m_userFriendsTableName +
284 " SET friendPerms = ?friendPerms " +
285 "where ownerID = ?ownerID and friendID = ?friendID",
286 param);
287 updater.ExecuteNonQuery();
288 }
289 }
290 catch (Exception e)
291 {
292 database.Reconnect();
293 m_log.Error(e.ToString());
294 return;
295 }
296 }
297
298 override public List<FriendListItem> GetUserFriendList(LLUUID friendlistowner)
299 {
300 List<FriendListItem> Lfli = new List<FriendListItem>();
301
302 Dictionary<string, string> param = new Dictionary<string, string>();
303 param["?ownerID"] = friendlistowner.UUID.ToString();
304
305 try
306 {
307 lock (database)
308 {
309 //Left Join userfriends to itself
310 IDbCommand result =
311 database.Query(
312 "select a.ownerID,a.friendID,a.friendPerms,b.friendPerms as ownerperms from " + m_userFriendsTableName + " as a, " + m_userFriendsTableName + " as b" +
313 " where a.ownerID = ?ownerID and b.ownerID = a.friendID and b.friendID = a.ownerID",
314 param);
315 IDataReader reader = result.ExecuteReader();
316
317 while (reader.Read())
318 {
319 FriendListItem fli = new FriendListItem();
320 fli.FriendListOwner = new LLUUID((string)reader["ownerID"]);
321 fli.Friend = new LLUUID((string)reader["friendID"]);
322 fli.FriendPerms = (uint)Convert.ToInt32(reader["friendPerms"]);
323
324 // This is not a real column in the database table, it's a joined column from the opposite record
325 fli.FriendListOwnerPerms = (uint)Convert.ToInt32(reader["ownerperms"]);
326
327 Lfli.Add(fli);
328 }
329 reader.Close();
330 result.Dispose();
331 }
332 }
333 catch (Exception e)
334 {
335 database.Reconnect();
336 m_log.Error(e.ToString());
337 return Lfli;
338 }
339
340 return Lfli;
341 }
342
343 #endregion
344
345 override public void UpdateUserCurrentRegion(LLUUID avatarid, LLUUID regionuuid)
346 {
347 m_log.Info("[USER]: Stub UpdateUserCUrrentRegion called");
348 }
349
350 override public List<Framework.AvatarPickerAvatar> GeneratePickerResults(LLUUID queryID, string query)
351 {
352 List<Framework.AvatarPickerAvatar> returnlist = new List<Framework.AvatarPickerAvatar>();
353
354 Regex objAlphaNumericPattern = new Regex("[^a-zA-Z0-9]");
355
356 string[] querysplit;
357 querysplit = query.Split(' ');
358 if (querysplit.Length == 2)
359 {
360 Dictionary<string, string> param = new Dictionary<string, string>();
361 param["?first"] = objAlphaNumericPattern.Replace(querysplit[0], String.Empty) + "%";
362 param["?second"] = objAlphaNumericPattern.Replace(querysplit[1], String.Empty) + "%";
363 try
364 {
365 lock (database)
366 {
367 IDbCommand result =
368 database.Query(
369 "SELECT UUID,username,lastname FROM " + m_usersTableName + " WHERE username like ?first AND lastname like ?second LIMIT 100",
370 param);
371 IDataReader reader = result.ExecuteReader();
372
373 while (reader.Read())
374 {
375 Framework.AvatarPickerAvatar user = new Framework.AvatarPickerAvatar();
376 user.AvatarID = new LLUUID((string) reader["UUID"]);
377 user.firstName = (string) reader["username"];
378 user.lastName = (string) reader["lastname"];
379 returnlist.Add(user);
380 }
381 reader.Close();
382 result.Dispose();
383 }
384 }
385 catch (Exception e)
386 {
387 database.Reconnect();
388 m_log.Error(e.ToString());
389 return returnlist;
390 }
391 }
392 else if (querysplit.Length == 1)
393 {
394 try
395 {
396 lock (database)
397 {
398 Dictionary<string, string> param = new Dictionary<string, string>();
399 param["?first"] = objAlphaNumericPattern.Replace(querysplit[0], String.Empty) + "%";
400
401 IDbCommand result =
402 database.Query(
403 "SELECT UUID,username,lastname FROM " + m_usersTableName + " WHERE username like ?first OR lastname like ?first LIMIT 100",
404 param);
405 IDataReader reader = result.ExecuteReader();
406
407 while (reader.Read())
408 {
409 Framework.AvatarPickerAvatar user = new Framework.AvatarPickerAvatar();
410 user.AvatarID = new LLUUID((string) reader["UUID"]);
411 user.firstName = (string) reader["username"];
412 user.lastName = (string) reader["lastname"];
413 returnlist.Add(user);
414 }
415 reader.Close();
416 result.Dispose();
417 }
418 }
419 catch (Exception e)
420 {
421 database.Reconnect();
422 m_log.Error(e.ToString());
423 return returnlist;
424 }
425 }
426 return returnlist;
427 }
428
429 // see IUserData
430 override public UserProfileData GetUserByUUID(LLUUID uuid)
431 {
432 try
433 {
434 lock (database)
435 {
436 Dictionary<string, string> param = new Dictionary<string, string>();
437 param["?uuid"] = uuid.ToString();
438
439 IDbCommand result = database.Query("SELECT * FROM " + m_usersTableName + " WHERE UUID = ?uuid", param);
440 IDataReader reader = result.ExecuteReader();
441
442 UserProfileData row = database.readUserRow(reader);
443
444 reader.Close();
445 result.Dispose();
446
447 return row;
448 }
449 }
450 catch (Exception e)
451 {
452 database.Reconnect();
453 m_log.Error(e.ToString());
454 return null;
455 }
456 }
457
458 /// <summary>
459 /// Returns a user session searching by name
460 /// </summary>
461 /// <param name="name">The account name</param>
462 /// <returns>The users session</returns>
463 override public UserAgentData GetAgentByName(string name)
464 {
465 return GetAgentByName(name.Split(' ')[0], name.Split(' ')[1]);
466 }
467
468 /// <summary>
469 /// Returns a user session by account name
470 /// </summary>
471 /// <param name="user">First part of the users account name</param>
472 /// <param name="last">Second part of the users account name</param>
473 /// <returns>The users session</returns>
474 override public UserAgentData GetAgentByName(string user, string last)
475 {
476 UserProfileData profile = GetUserByName(user, last);
477 return GetAgentByUUID(profile.UUID);
478 }
479
480 override public void StoreWebLoginKey(LLUUID AgentID, LLUUID WebLoginKey)
481 {
482 Dictionary<string, string> param = new Dictionary<string, string>();
483 param["?UUID"] = AgentID.UUID.ToString();
484 param["?webLoginKey"] = WebLoginKey.UUID.ToString();
485
486 try
487 {
488 lock (database)
489 {
490 IDbCommand updater =
491 database.Query(
492 "update " + m_usersTableName + " SET webLoginKey = ?webLoginKey " +
493 "where UUID = ?UUID",
494 param);
495 updater.ExecuteNonQuery();
496 }
497 }
498 catch (Exception e)
499 {
500 database.Reconnect();
501 m_log.Error(e.ToString());
502 return;
503 }
504 }
505
506 /// <summary>
507 /// Returns an agent session by account UUID
508 /// </summary>
509 /// <param name="uuid">The accounts UUID</param>
510 /// <returns>The users session</returns>
511 override public UserAgentData GetAgentByUUID(LLUUID uuid)
512 {
513 try
514 {
515 lock (database)
516 {
517 Dictionary<string, string> param = new Dictionary<string, string>();
518 param["?uuid"] = uuid.ToString();
519
520 IDbCommand result = database.Query("SELECT * FROM " + m_agentsTableName + " WHERE UUID = ?uuid", param);
521 IDataReader reader = result.ExecuteReader();
522
523 UserAgentData row = database.readAgentRow(reader);
524
525 reader.Close();
526 result.Dispose();
527
528 return row;
529 }
530 }
531 catch (Exception e)
532 {
533 database.Reconnect();
534 m_log.Error(e.ToString());
535 return null;
536 }
537 }
538
539 /// <summary>
540 /// Creates a new users profile
541 /// </summary>
542 /// <param name="user">The user profile to create</param>
543 override public void AddNewUserProfile(UserProfileData user)
544 {
545 try
546 {
547 lock (database)
548 {
549 database.insertUserRow(user.UUID, user.username, user.surname, user.passwordHash, user.passwordSalt,
550 user.homeRegion, user.homeLocation.X, user.homeLocation.Y,
551 user.homeLocation.Z,
552 user.homeLookAt.X, user.homeLookAt.Y, user.homeLookAt.Z, user.created,
553 user.lastLogin, user.userInventoryURI, user.userAssetURI,
554 user.profileCanDoMask, user.profileWantDoMask,
555 user.profileAboutText, user.profileFirstText, user.profileImage,
556 user.profileFirstImage, user.webLoginKey);
557 }
558 }
559 catch (Exception e)
560 {
561 database.Reconnect();
562 m_log.Error(e.ToString());
563 }
564 }
565
566 /// <summary>
567 /// Creates a new agent
568 /// </summary>
569 /// <param name="agent">The agent to create</param>
570 override public void AddNewUserAgent(UserAgentData agent)
571 {
572 try
573 {
574 lock (database)
575 {
576 database.insertAgentRow(agent);
577 }
578 }
579 catch (Exception e)
580 {
581 database.Reconnect();
582 m_log.Error(e.ToString());
583 }
584 }
585
586 /// <summary>
587 /// Updates a user profile stored in the DB
588 /// </summary>
589 /// <param name="user">The profile data to use to update the DB</param>
590 override public bool UpdateUserProfile(UserProfileData user)
591 {
592 database.updateUserRow(user.UUID, user.username, user.surname, user.passwordHash, user.passwordSalt,
593 user.homeRegion, user.homeLocation.X, user.homeLocation.Y, user.homeLocation.Z, user.homeLookAt.X,
594 user.homeLookAt.Y, user.homeLookAt.Z, user.created, user.lastLogin, user.userInventoryURI,
595 user.userAssetURI, user.profileCanDoMask, user.profileWantDoMask, user.profileAboutText,
596 user.profileFirstText, user.profileImage, user.profileFirstImage, user.webLoginKey);
597 return true;
598 }
599
600 /// <summary>
601 /// Performs a money transfer request between two accounts
602 /// </summary>
603 /// <param name="from">The senders account ID</param>
604 /// <param name="to">The receivers account ID</param>
605 /// <param name="amount">The amount to transfer</param>
606 /// <returns>Success?</returns>
607 override public bool MoneyTransferRequest(LLUUID from, LLUUID to, uint amount)
608 {
609 return false;
610 }
611
612 /// <summary>
613 /// Performs an inventory transfer request between two accounts
614 /// </summary>
615 /// <remarks>TODO: Move to inventory server</remarks>
616 /// <param name="from">The senders account ID</param>
617 /// <param name="to">The receivers account ID</param>
618 /// <param name="item">The item to transfer</param>
619 /// <returns>Success?</returns>
620 override public bool InventoryTransferRequest(LLUUID from, LLUUID to, LLUUID item)
621 {
622 return false;
623 }
624
625 /// <summary>
626 /// Database provider name
627 /// </summary>
628 /// <returns>Provider name</returns>
629 override public string getName()
630 {
631 return "MySQL Userdata Interface";
632 }
633
634 /// <summary>
635 /// Database provider version
636 /// </summary>
637 /// <returns>provider version</returns>
638 override public string GetVersion()
639 {
640 return "0.1";
641 }
642 }
643}
diff --git a/OpenSim/Data/MySQL/Properties/AssemblyInfo.cs b/OpenSim/Data/MySQL/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..060e26c
--- /dev/null
+++ b/OpenSim/Data/MySQL/Properties/AssemblyInfo.cs
@@ -0,0 +1,65 @@
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 OpenSim 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.Reflection;
29using System.Runtime.InteropServices;
30
31// General Information about an assembly is controlled through the following
32// set of attributes. Change these attribute values to modify the information
33// associated with an assembly.
34
35[assembly : AssemblyTitle("OpenSim.Framework.Data.MySQL")]
36[assembly : AssemblyDescription("")]
37[assembly : AssemblyConfiguration("")]
38[assembly : AssemblyCompany("")]
39[assembly : AssemblyProduct("OpenSim.Framework.Data.MySQL")]
40[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers 2007-2008")]
41[assembly : AssemblyTrademark("")]
42[assembly : AssemblyCulture("")]
43
44// Setting ComVisible to false makes the types in this assembly not visible
45// to COM components. If you need to access a type in this assembly from
46// COM, set the ComVisible attribute to true on that type.
47
48[assembly : ComVisible(false)]
49
50// The following GUID is for the ID of the typelib if this project is exposed to COM
51
52[assembly : Guid("e49826b2-dcef-41be-a5bd-596733fa3304")]
53
54// Version information for an assembly consists of the following four values:
55//
56// Major Version
57// Minor Version
58// Build Number
59// Revision
60//
61// You can specify all the values or you can default the Revision and Build Numbers
62// by using the '*' as shown below:
63
64[assembly : AssemblyVersion("1.0.0.0")]
65[assembly : AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Data/MySQL/Resources/AvatarAppearance.sql b/OpenSim/Data/MySQL/Resources/AvatarAppearance.sql
new file mode 100644
index 0000000..b638ee2
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/AvatarAppearance.sql
@@ -0,0 +1,42 @@
1--
2-- Create schema avatar_appearance
3--
4
5CREATE DATABASE IF NOT EXISTS avatar_appearance;
6USE avatar_appearance;
7
8DROP TABLE IF EXISTS `avatarappearance`;
9CREATE TABLE `avatarappearance` (
10 `UUID` char(36) NOT NULL,
11 `Serial` int(10) unsigned NOT NULL,
12 `WearableItem0` char(36) NOT NULL,
13 `WearableAsset0` char(36) NOT NULL,
14 `WearableItem1` char(36) NOT NULL,
15 `WearableAsset1` char(36) NOT NULL,
16 `WearableItem2` char(36) NOT NULL,
17 `WearableAsset2` char(36) NOT NULL,
18 `WearableItem3` char(36) NOT NULL,
19 `WearableAsset3` char(36) NOT NULL,
20 `WearableItem4` char(36) NOT NULL,
21 `WearableAsset4` char(36) NOT NULL,
22 `WearableItem5` char(36) NOT NULL,
23 `WearableAsset5` char(36) NOT NULL,
24 `WearableItem6` char(36) NOT NULL,
25 `WearableAsset6` char(36) NOT NULL,
26 `WearableItem7` char(36) NOT NULL,
27 `WearableAsset7` char(36) NOT NULL,
28 `WearableItem8` char(36) NOT NULL,
29 `WearableAsset8` char(36) NOT NULL,
30 `WearableItem9` char(36) NOT NULL,
31 `WearableAsset9` char(36) NOT NULL,
32 `WearableItem10` char(36) NOT NULL,
33 `WearableAsset10` char(36) NOT NULL,
34 `WearableItem11` char(36) NOT NULL,
35 `WearableAsset11` char(36) NOT NULL,
36 `WearableItem12` char(36) NOT NULL,
37 `WearableAsset12` char(36) NOT NULL,
38
39
40 PRIMARY KEY (`UUID`)
41) ENGINE=InnoDB DEFAULT CHARSET=utf8;
42
diff --git a/OpenSim/Data/MySQL/Resources/CreateAgentsTable.sql b/OpenSim/Data/MySQL/Resources/CreateAgentsTable.sql
new file mode 100644
index 0000000..3ef7bc9
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/CreateAgentsTable.sql
@@ -0,0 +1,24 @@
1SET FOREIGN_KEY_CHECKS=0;
2-- ----------------------------
3-- Table structure for agents
4-- ----------------------------
5CREATE TABLE `agents` (
6 `UUID` varchar(36) NOT NULL,
7 `sessionID` varchar(36) NOT NULL,
8 `secureSessionID` varchar(36) NOT NULL,
9 `agentIP` varchar(16) NOT NULL,
10 `agentPort` int(11) NOT NULL,
11 `agentOnline` tinyint(4) NOT NULL,
12 `loginTime` int(11) NOT NULL,
13 `logoutTime` int(11) NOT NULL,
14 `currentRegion` varchar(36) NOT NULL,
15 `currentHandle` bigint(20) unsigned NOT NULL,
16 `currentPos` varchar(64) NOT NULL,
17 PRIMARY KEY (`UUID`),
18 UNIQUE KEY `session` (`sessionID`),
19 UNIQUE KEY `ssession` (`secureSessionID`)
20) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Rev. 1';
21
22-- ----------------------------
23-- Records
24-- ----------------------------
diff --git a/OpenSim/Data/MySQL/Resources/CreateAssetsTable.sql b/OpenSim/Data/MySQL/Resources/CreateAssetsTable.sql
new file mode 100644
index 0000000..2c750fe
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/CreateAssetsTable.sql
@@ -0,0 +1,11 @@
1CREATE TABLE `assets` (
2 `id` binary(16) NOT NULL,
3 `name` varchar(64) NOT NULL,
4 `description` varchar(64) NOT NULL,
5 `assetType` tinyint(4) NOT NULL,
6 `invType` tinyint(4) NOT NULL,
7 `local` tinyint(1) NOT NULL,
8 `temporary` tinyint(1) NOT NULL,
9 `data` longblob NOT NULL,
10 PRIMARY KEY (`id`)
11) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Rev. 1'; \ No newline at end of file
diff --git a/OpenSim/Data/MySQL/Resources/CreateFoldersTable.sql b/OpenSim/Data/MySQL/Resources/CreateFoldersTable.sql
new file mode 100644
index 0000000..b5bddde
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/CreateFoldersTable.sql
@@ -0,0 +1,11 @@
1CREATE TABLE `inventoryfolders` (
2 `folderID` varchar(36) NOT NULL default '',
3 `agentID` varchar(36) default NULL,
4 `parentFolderID` varchar(36) default NULL,
5 `folderName` varchar(64) default NULL,
6 `type` smallint NOT NULL default 0,
7 `version` int NOT NULL default 0,
8 PRIMARY KEY (`folderID`),
9 KEY `owner` (`agentID`),
10 KEY `parent` (`parentFolderID`)
11) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Rev. 2';
diff --git a/OpenSim/Data/MySQL/Resources/CreateItemsTable.sql b/OpenSim/Data/MySQL/Resources/CreateItemsTable.sql
new file mode 100644
index 0000000..1723ee3
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/CreateItemsTable.sql
@@ -0,0 +1,18 @@
1CREATE TABLE `inventoryitems` (
2 `inventoryID` varchar(36) NOT NULL default '',
3 `assetID` varchar(36) default NULL,
4 `assetType` int(11) default NULL,
5 `parentFolderID` varchar(36) default NULL,
6 `avatarID` varchar(36) default NULL,
7 `inventoryName` varchar(64) default NULL,
8 `inventoryDescription` varchar(128) default NULL,
9 `inventoryNextPermissions` int(10) unsigned default NULL,
10 `inventoryCurrentPermissions` int(10) unsigned default NULL,
11 `invType` int(11) default NULL,
12 `creatorID` varchar(36) default NULL,
13 `inventoryBasePermissions` int(10) unsigned NOT NULL default 0,
14 `inventoryEveryOnePermissions` int(10) unsigned NOT NULL default 0,
15 PRIMARY KEY (`inventoryID`),
16 KEY `owner` (`avatarID`),
17 KEY `folder` (`parentFolderID`)
18) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Rev. 2';
diff --git a/OpenSim/Data/MySQL/Resources/CreateLogsTable.sql b/OpenSim/Data/MySQL/Resources/CreateLogsTable.sql
new file mode 100644
index 0000000..64b3a80
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/CreateLogsTable.sql
@@ -0,0 +1,10 @@
1CREATE TABLE `logs` (
2 `logID` int(10) unsigned NOT NULL auto_increment,
3 `target` varchar(36) default NULL,
4 `server` varchar(64) default NULL,
5 `method` varchar(64) default NULL,
6 `arguments` varchar(255) default NULL,
7 `priority` int(11) default NULL,
8 `message` text,
9 PRIMARY KEY (`logID`)
10) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Rev. 1';
diff --git a/OpenSim/Data/MySQL/Resources/CreateRegionsTable.sql b/OpenSim/Data/MySQL/Resources/CreateRegionsTable.sql
new file mode 100644
index 0000000..cb0f9bd
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/CreateRegionsTable.sql
@@ -0,0 +1,32 @@
1CREATE TABLE `regions` (
2 `uuid` varchar(36) NOT NULL,
3 `regionHandle` bigint(20) unsigned NOT NULL,
4 `regionName` varchar(32) default NULL,
5 `regionRecvKey` varchar(128) default NULL,
6 `regionSendKey` varchar(128) default NULL,
7 `regionSecret` varchar(128) default NULL,
8 `regionDataURI` varchar(255) default NULL,
9 `serverIP` varchar(64) default NULL,
10 `serverPort` int(10) unsigned default NULL,
11 `serverURI` varchar(255) default NULL,
12 `locX` int(10) unsigned default NULL,
13 `locY` int(10) unsigned default NULL,
14 `locZ` int(10) unsigned default NULL,
15 `eastOverrideHandle` bigint(20) unsigned default NULL,
16 `westOverrideHandle` bigint(20) unsigned default NULL,
17 `southOverrideHandle` bigint(20) unsigned default NULL,
18 `northOverrideHandle` bigint(20) unsigned default NULL,
19 `regionAssetURI` varchar(255) default NULL,
20 `regionAssetRecvKey` varchar(128) default NULL,
21 `regionAssetSendKey` varchar(128) default NULL,
22 `regionUserURI` varchar(255) default NULL,
23 `regionUserRecvKey` varchar(128) default NULL,
24 `regionUserSendKey` varchar(128) default NULL, `regionMapTexture` varchar(36) default NULL,
25 `serverHttpPort` int(10) default NULL, `serverRemotingPort` int(10) default NULL,
26 `owner_uuid` varchar(36) default '00000000-0000-0000-0000-000000000000' not null,
27 `originUUID` varchar(36),
28 PRIMARY KEY (`uuid`),
29 KEY `regionName` (`regionName`),
30 KEY `regionHandle` (`regionHandle`),
31 KEY `overrideHandles` (`eastOverrideHandle`,`westOverrideHandle`,`southOverrideHandle`,`northOverrideHandle`)
32) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Rev. 3';
diff --git a/OpenSim/Data/MySQL/Resources/CreateUserFriendsTable.sql b/OpenSim/Data/MySQL/Resources/CreateUserFriendsTable.sql
new file mode 100644
index 0000000..8480d48
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/CreateUserFriendsTable.sql
@@ -0,0 +1,11 @@
1SET FOREIGN_KEY_CHECKS=0;
2-- ----------------------------
3-- Table structure for users
4-- ----------------------------
5CREATE TABLE `userfriends` (
6 `ownerID` VARCHAR(37) NOT NULL,
7 `friendID` VARCHAR(37) NOT NULL,
8 `friendPerms` INT NOT NULL,
9 `datetimestamp` INT NOT NULL,
10 UNIQUE KEY (`ownerID`, `friendID`)
11) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Rev.1'; \ No newline at end of file
diff --git a/OpenSim/Data/MySQL/Resources/CreateUsersTable.sql b/OpenSim/Data/MySQL/Resources/CreateUsersTable.sql
new file mode 100644
index 0000000..d9e8ae2
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/CreateUsersTable.sql
@@ -0,0 +1,35 @@
1SET FOREIGN_KEY_CHECKS=0;
2-- ----------------------------
3-- Table structure for users
4-- ----------------------------
5CREATE TABLE `users` (
6 `UUID` varchar(36) NOT NULL default '',
7 `username` varchar(32) NOT NULL,
8 `lastname` varchar(32) NOT NULL,
9 `passwordHash` varchar(32) NOT NULL,
10 `passwordSalt` varchar(32) NOT NULL,
11 `homeRegion` bigint(20) unsigned default NULL,
12 `homeLocationX` float default NULL,
13 `homeLocationY` float default NULL,
14 `homeLocationZ` float default NULL,
15 `homeLookAtX` float default NULL,
16 `homeLookAtY` float default NULL,
17 `homeLookAtZ` float default NULL,
18 `created` int(11) NOT NULL,
19 `lastLogin` int(11) NOT NULL,
20 `userInventoryURI` varchar(255) default NULL,
21 `userAssetURI` varchar(255) default NULL,
22 `profileCanDoMask` int(10) unsigned default NULL,
23 `profileWantDoMask` int(10) unsigned default NULL,
24 `profileAboutText` text,
25 `profileFirstText` text,
26 `profileImage` varchar(36) default NULL,
27 `profileFirstImage` varchar(36) default NULL,
28 `webLoginKey` varchar(36) default NULL,
29 PRIMARY KEY (`UUID`),
30 UNIQUE KEY `usernames` (`username`,`lastname`)
31) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Rev. 2';
32
33-- ----------------------------
34-- Records
35-- ----------------------------
diff --git a/OpenSim/Data/MySQL/Resources/UpgradeFoldersTableToVersion2.sql b/OpenSim/Data/MySQL/Resources/UpgradeFoldersTableToVersion2.sql
new file mode 100644
index 0000000..b5a7964
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/UpgradeFoldersTableToVersion2.sql
@@ -0,0 +1,4 @@
1ALTER TABLE `inventoryfolders`
2 ADD COLUMN `type` smallint NOT NULL default 0,
3 ADD COLUMN `version` int NOT NULL default 0,
4COMMENT='Rev. 2';
diff --git a/OpenSim/Data/MySQL/Resources/UpgradeItemsTableToVersion2.sql b/OpenSim/Data/MySQL/Resources/UpgradeItemsTableToVersion2.sql
new file mode 100644
index 0000000..d1ef504
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/UpgradeItemsTableToVersion2.sql
@@ -0,0 +1,9 @@
1ALTER TABLE `inventoryitems`
2 CHANGE COLUMN `type` `assetType` int(11) default NULL,
3 ADD COLUMN `invType` int(11) default NULL,
4 ADD COLUMN `creatorID` varchar(36) default NULL,
5 ADD COLUMN `inventoryBasePermissions` int(10) unsigned NOT NULL default 0,
6 ADD COLUMN `inventoryEveryOnePermissions` int(10) unsigned NOT NULL default 0,
7COMMENT='Rev. 2';
8
9UPDATE `inventoryitems` SET invType=assetType;
diff --git a/OpenSim/Data/MySQL/Resources/UpgradeRegionsTableToVersion2.sql b/OpenSim/Data/MySQL/Resources/UpgradeRegionsTableToVersion2.sql
new file mode 100644
index 0000000..034b755
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/UpgradeRegionsTableToVersion2.sql
@@ -0,0 +1,4 @@
1ALTER TABLE `regions`
2 ADD COLUMN `originUUID` varchar(36),
3COMMENT='Rev. 2';
4UPDATE `regions` SET originUUID=uuid;
diff --git a/OpenSim/Data/MySQL/Resources/UpgradeRegionsTableToVersion3.sql b/OpenSim/Data/MySQL/Resources/UpgradeRegionsTableToVersion3.sql
new file mode 100644
index 0000000..b48afec
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/UpgradeRegionsTableToVersion3.sql
@@ -0,0 +1,18 @@
1DROP PROCEDURE IF EXISTS upgraderegions3;
2
3create procedure upgraderegions3()
4BEGIN
5DECLARE db_name varchar(64);
6select database() into db_name;
7IF ((select count(*) from information_schema.columns where table_name='regions' and column_name='owner_uuid' and table_schema=db_name) > 0)
8THEN
9 ALTER TABLE `regions`, COMMENT='Rev. 3';
10ELSE
11 ALTER TABLE `regions`
12 ADD COLUMN `owner_uuid` varchar(36) default '00000000-0000-0000-0000-000000000000' not null after serverRemotingPort, COMMENT='Rev. 3';
13END IF;
14END;
15
16call upgraderegions3();
17
18
diff --git a/OpenSim/Data/MySQL/Resources/UpgradeUsersTableToVersion2.sql b/OpenSim/Data/MySQL/Resources/UpgradeUsersTableToVersion2.sql
new file mode 100644
index 0000000..dd21a66
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/UpgradeUsersTableToVersion2.sql
@@ -0,0 +1,3 @@
1ALTER TABLE `users`
2 ADD COLUMN `webLoginKey` varchar(36) default '00000000-0000-0000-0000-000000000000' NOT NULL,
3COMMENT='Rev. 2'; \ No newline at end of file
diff --git a/OpenSim/Data/MySQLMapper/MySQLDataReader.cs b/OpenSim/Data/MySQLMapper/MySQLDataReader.cs
new file mode 100644
index 0000000..9fd50f6
--- /dev/null
+++ b/OpenSim/Data/MySQLMapper/MySQLDataReader.cs
@@ -0,0 +1,15 @@
1using System;
2using System.Collections.Generic;
3using System.Data;
4using System.Text;
5using OpenSim.Framework.Data.Base;
6
7namespace OpenSim.Framework.Data.MySQLMapper
8{
9 public class MySQLDataReader : OpenSimDataReader
10 {
11 public MySQLDataReader(IDataReader source) : base(source)
12 {
13 }
14 }
15}
diff --git a/OpenSim/Data/MySQLMapper/MySQLDatabaseMapper.cs b/OpenSim/Data/MySQLMapper/MySQLDatabaseMapper.cs
new file mode 100644
index 0000000..3f5b18f
--- /dev/null
+++ b/OpenSim/Data/MySQLMapper/MySQLDatabaseMapper.cs
@@ -0,0 +1,59 @@
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 OpenSim 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.Data;
29using System.Data.Common;
30using MySql.Data.MySqlClient;
31using OpenSim.Framework.Data;
32using OpenSim.Framework.Data.Base;
33
34namespace OpenSim.Framework.Data.MySQLMapper
35{
36 public class MySQLDatabaseMapper : OpenSimDatabaseConnector
37 {
38 public MySQLDatabaseMapper(string connectionString)
39 : base(connectionString)
40 {
41 }
42
43 public override DbConnection GetNewConnection()
44 {
45 MySqlConnection connection = new MySqlConnection(m_connectionString);
46 return connection;
47 }
48
49 public override string CreateParamName(string fieldName)
50 {
51 return "?" + fieldName;
52 }
53
54 public override BaseDataReader CreateReader(IDataReader reader)
55 {
56 return new MySQLDataReader( reader );
57 }
58 }
59} \ No newline at end of file
diff --git a/OpenSim/Data/SQLite/Properties/AssemblyInfo.cs b/OpenSim/Data/SQLite/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..600405e
--- /dev/null
+++ b/OpenSim/Data/SQLite/Properties/AssemblyInfo.cs
@@ -0,0 +1,65 @@
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 OpenSim 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.Reflection;
29using System.Runtime.InteropServices;
30
31// General Information about an assembly is controlled through the following
32// set of attributes. Change these attribute values to modify the information
33// associated with an assembly.
34
35[assembly : AssemblyTitle("OpenSim.Framework.Data.SQLite")]
36[assembly : AssemblyDescription("")]
37[assembly : AssemblyConfiguration("")]
38[assembly : AssemblyCompany("")]
39[assembly : AssemblyProduct("OpenSim.Framework.Data.SQLite")]
40[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers 2007-2008")]
41[assembly : AssemblyTrademark("")]
42[assembly : AssemblyCulture("")]
43
44// Setting ComVisible to false makes the types in this assembly not visible
45// to COM components. If you need to access a type in this assembly from
46// COM, set the ComVisible attribute to true on that type.
47
48[assembly : ComVisible(false)]
49
50// The following GUID is for the ID of the typelib if this project is exposed to COM
51
52[assembly : Guid("6113d5ce-4547-49f4-9236-0dcc503457b1")]
53
54// Version information for an assembly consists of the following four values:
55//
56// Major Version
57// Minor Version
58// Build Number
59// Revision
60//
61// You can specify all the values or you can default the Revision and Build Numbers
62// by using the '*' as shown below:
63
64[assembly : AssemblyVersion("1.0.0.0")]
65[assembly : AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Data/SQLite/Resources/001_AssetStore.sql b/OpenSim/Data/SQLite/Resources/001_AssetStore.sql
new file mode 100644
index 0000000..1dc05d8
--- /dev/null
+++ b/OpenSim/Data/SQLite/Resources/001_AssetStore.sql
@@ -0,0 +1,13 @@
1BEGIN TRANSACTION;
2
3CREATE TABLE assets(
4 UUID varchar(255) primary key,
5 Name varchar(255),
6 Description varchar(255),
7 Type integer,
8 InvType integer,
9 Local integer,
10 Temporary integer,
11 Data blob);
12
13COMMIT;
diff --git a/OpenSim/Data/SQLite/Resources/001_InventoryStore.sql b/OpenSim/Data/SQLite/Resources/001_InventoryStore.sql
new file mode 100644
index 0000000..e4951b0
--- /dev/null
+++ b/OpenSim/Data/SQLite/Resources/001_InventoryStore.sql
@@ -0,0 +1,26 @@
1BEGIN TRANSACTION;
2
3CREATE TABLE inventoryitems(
4 UUID varchar(255) primary key,
5 assetID varchar(255),
6 assetType integer,
7 invType integer,
8 parentFolderID varchar(255),
9 avatarID varchar(255),
10 creatorsID varchar(255),
11 inventoryName varchar(255),
12 inventoryDescription varchar(255),
13 inventoryNextPermissions integer,
14 inventoryCurrentPermissions integer,
15 inventoryBasePermissions integer,
16 inventoryEveryOnePermissions integer);
17
18CREATE TABLE inventoryfolders(
19 UUID varchar(255) primary key,
20 name varchar(255),
21 agentID varchar(255),
22 parentID varchar(255),
23 type integer,
24 version integer);
25
26COMMIT;
diff --git a/OpenSim/Data/SQLite/Resources/001_RegionStore.sql b/OpenSim/Data/SQLite/Resources/001_RegionStore.sql
new file mode 100644
index 0000000..15f3d9f
--- /dev/null
+++ b/OpenSim/Data/SQLite/Resources/001_RegionStore.sql
@@ -0,0 +1,122 @@
1BEGIN TRANSACTION;
2
3CREATE TABLE prims(
4 UUID varchar(255) primary key,
5 RegionUUID varchar(255),
6 ParentID integer,
7 CreationDate integer,
8 Name varchar(255),
9 SceneGroupID varchar(255),
10 Text varchar(255),
11 Description varchar(255),
12 SitName varchar(255),
13 TouchName varchar(255),
14 CreatorID varchar(255),
15 OwnerID varchar(255),
16 GroupID varchar(255),
17 LastOwnerID varchar(255),
18 OwnerMask integer,
19 NextOwnerMask integer,
20 GroupMask integer,
21 EveryoneMask integer,
22 BaseMask integer,
23 PositionX float,
24 PositionY float,
25 PositionZ float,
26 GroupPositionX float,
27 GroupPositionY float,
28 GroupPositionZ float,
29 VelocityX float,
30 VelocityY float,
31 VelocityZ float,
32 AngularVelocityX float,
33 AngularVelocityY float,
34 AngularVelocityZ float,
35 AccelerationX float,
36 AccelerationY float,
37 AccelerationZ float,
38 RotationX float,
39 RotationY float,
40 RotationZ float,
41 RotationW float,
42 ObjectFlags integer,
43 SitTargetOffsetX float NOT NULL default 0,
44 SitTargetOffsetY float NOT NULL default 0,
45 SitTargetOffsetZ float NOT NULL default 0,
46 SitTargetOrientW float NOT NULL default 0,
47 SitTargetOrientX float NOT NULL default 0,
48 SitTargetOrientY float NOT NULL default 0,
49 SitTargetOrientZ float NOT NULL default 0);
50
51CREATE TABLE primshapes(UUID varchar(255) primary key,
52 Shape integer,
53 ScaleX float,
54 ScaleY float,
55 ScaleZ float,
56 PCode integer,
57 PathBegin integer,
58 PathEnd integer,
59 PathScaleX integer,
60 PathScaleY integer,
61 PathShearX integer,
62 PathShearY integer,
63 PathSkew integer,
64 PathCurve integer,
65 PathRadiusOffset integer,
66 PathRevolutions integer,
67 PathTaperX integer,
68 PathTaperY integer,
69 PathTwist integer,
70 PathTwistBegin integer,
71 ProfileBegin integer,
72 ProfileEnd integer,
73 ProfileCurve integer,
74 ProfileHollow integer,
75 State integer,
76 Texture blob,
77 ExtraParams blob);
78
79CREATE TABLE terrain(
80 RegionUUID varchar(255),
81 Revision integer,
82 Heightfield blob);
83
84CREATE TABLE land(
85 UUID varchar(255) primary key,
86 RegionUUID varchar(255),
87 LocalLandID string,
88 Bitmap blob,
89 Name varchar(255),
90 Desc varchar(255),
91 OwnerUUID varchar(36),
92 IsGroupOwned string,
93 Area integer,
94 AuctionID integer,
95 Category integer,
96 ClaimDate integer,
97 ClaimPrice integer,
98 GroupUUID varchar(255),
99 SalePrice integer,
100 LandStatus integer,
101 LandFlags string,
102 LandingType string,
103 MediaAutoScale string,
104 MediaTextureUUID varchar(255),
105 MediaURL varchar(255),
106 MusicURL varchar(255),
107 PassHours float,
108 PassPrice string,
109 SnapshotUUID varchar(255),
110 UserLocationX float,
111 UserLocationY float,
112 UserLocationZ float,
113 UserLookAtX float,
114 UserLookAtY float,
115 UserLookAtZ float);
116
117CREATE TABLE landaccesslist(
118 LandUUID varchar(255),
119 AccessUUID varchar(255),
120 Flags string);
121
122COMMIT;
diff --git a/OpenSim/Data/SQLite/Resources/001_UserStore.sql b/OpenSim/Data/SQLite/Resources/001_UserStore.sql
new file mode 100644
index 0000000..070e340
--- /dev/null
+++ b/OpenSim/Data/SQLite/Resources/001_UserStore.sql
@@ -0,0 +1,37 @@
1BEGIN TRANSACTION;
2
3CREATE TABLE users(
4 UUID varchar(255) primary key,
5 username varchar(255),
6 surname varchar(255),
7 passwordHash varchar(255),
8 passwordSalt varchar(255),
9 homeRegionX integer,
10 homeRegionY integer,
11 homeLocationX float,
12 homeLocationY float,
13 homeLocationZ float,
14 homeLookAtX float,
15 homeLookAtY float,
16 homeLookAtZ float,
17 created integer,
18 lastLogin integer,
19 rootInventoryFolderID varchar(255),
20 userInventoryURI varchar(255),
21 userAssetURI varchar(255),
22 profileCanDoMask integer,
23 profileWantDoMask integer,
24 profileAboutText varchar(255),
25 profileFirstText varchar(255),
26 profileImage varchar(255),
27 profileFirstImage varchar(255),
28 webLoginKey text default '00000000-0000-0000-0000-000000000000');
29
30CREATE TABLE userfriends(
31 ownerID varchar(255),
32 friendID varchar(255),
33 friendPerms integer,
34 ownerPerms integer,
35 datetimestamp integer);
36
37COMMIT;
diff --git a/OpenSim/Data/SQLite/SQLiteAssetData.cs b/OpenSim/Data/SQLite/SQLiteAssetData.cs
new file mode 100644
index 0000000..afa73b1
--- /dev/null
+++ b/OpenSim/Data/SQLite/SQLiteAssetData.cs
@@ -0,0 +1,301 @@
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 OpenSim 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 libsecondlife;
32using Mono.Data.SqliteClient;
33using OpenSim.Framework.Console;
34
35namespace OpenSim.Framework.Data.SQLite
36{
37 /// <summary>
38 /// A User storage interface for the DB4o database system
39 /// </summary>
40 public class SQLiteAssetData : AssetDataBase
41 {
42 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
43
44 /// <summary>
45 /// The database manager
46 /// </summary>
47 /// <summary>
48 /// Artificial constructor called upon plugin load
49 /// </summary>
50 private const string SelectAssetSQL = "select * from assets where UUID=:UUID";
51 private const string DeleteAssetSQL = "delete from assets where UUID=:UUID";
52 private const string InsertAssetSQL = "insert into assets(UUID, Name, Description, Type, InvType, Local, Temporary, Data) values(:UUID, :Name, :Description, :Type, :InvType, :Local, :Temporary, :Data)";
53 private const string UpdateAssetSQL = "update assets set Name=:Name, Description=:Description, Type=:Type, InvType=:InvType, Local=:Local, Temporary=:Temporary, Data=:Data where UUID=:UUID";
54 private const string assetSelect = "select * from assets";
55
56 private SqliteConnection m_conn;
57
58 public void Initialise(string dbfile, string dbname)
59 {
60 m_conn = new SqliteConnection("URI=file:" + dbfile + ",version=3");
61 m_conn.Open();
62 TestTables(m_conn);
63 return;
64 }
65
66 override public AssetBase FetchAsset(LLUUID uuid)
67 {
68
69 using (SqliteCommand cmd = new SqliteCommand(SelectAssetSQL, m_conn))
70 {
71 cmd.Parameters.Add(new SqliteParameter(":UUID", Util.ToRawUuidString(uuid)));
72 using (IDataReader reader = cmd.ExecuteReader())
73 {
74 if (reader.Read())
75 {
76 AssetBase asset = buildAsset(reader);
77 reader.Close();
78 return asset;
79 }
80 else
81 {
82 reader.Close();
83 return null;
84 }
85 }
86 }
87 }
88
89 override public void CreateAsset(AssetBase asset)
90 {
91 m_log.Info("[SQLITE]: Creating Asset " + Util.ToRawUuidString(asset.FullID));
92 if (ExistsAsset(asset.FullID))
93 {
94 m_log.Info("[SQLITE]: Asset exists already, ignoring.");
95 }
96 else
97 {
98 using (SqliteCommand cmd = new SqliteCommand(InsertAssetSQL, m_conn))
99 {
100 cmd.Parameters.Add(new SqliteParameter(":UUID", Util.ToRawUuidString(asset.FullID)));
101 cmd.Parameters.Add(new SqliteParameter(":Name", asset.Name));
102 cmd.Parameters.Add(new SqliteParameter(":Description", asset.Description));
103 cmd.Parameters.Add(new SqliteParameter(":Type", asset.Type));
104 cmd.Parameters.Add(new SqliteParameter(":InvType", asset.InvType));
105 cmd.Parameters.Add(new SqliteParameter(":Local", asset.Local));
106 cmd.Parameters.Add(new SqliteParameter(":Temporary", asset.Temporary));
107 cmd.Parameters.Add(new SqliteParameter(":Data", asset.Data));
108
109 cmd.ExecuteNonQuery();
110 }
111 }
112 }
113
114 override public void UpdateAsset(AssetBase asset)
115 {
116 LogAssetLoad(asset);
117
118 using (SqliteCommand cmd = new SqliteCommand(UpdateAssetSQL, m_conn))
119 {
120 cmd.Parameters.Add(new SqliteParameter(":UUID", Util.ToRawUuidString(asset.FullID)));
121 cmd.Parameters.Add(new SqliteParameter(":Name", asset.Name));
122 cmd.Parameters.Add(new SqliteParameter(":Description", asset.Description));
123 cmd.Parameters.Add(new SqliteParameter(":Type", asset.Type));
124 cmd.Parameters.Add(new SqliteParameter(":InvType", asset.InvType));
125 cmd.Parameters.Add(new SqliteParameter(":Local", asset.Local));
126 cmd.Parameters.Add(new SqliteParameter(":Temporary", asset.Temporary));
127 cmd.Parameters.Add(new SqliteParameter(":Data", asset.Data));
128
129 cmd.ExecuteNonQuery();
130 }
131
132 }
133
134 private void LogAssetLoad(AssetBase asset)
135 {
136 string temporary = asset.Temporary ? "Temporary" : "Stored";
137 string local = asset.Local ? "Local" : "Remote";
138
139 int assetLength = (asset.Data != null) ? asset.Data.Length : 0;
140
141 m_log.Info("[SQLITE]: " +
142 string.Format("Loaded {6} {5} Asset: [{0}][{3}/{4}] \"{1}\":{2} ({7} bytes)",
143 asset.FullID, asset.Name, asset.Description, asset.Type,
144 asset.InvType, temporary, local, assetLength));
145 }
146
147 override public bool ExistsAsset(LLUUID uuid)
148 {
149 using (SqliteCommand cmd = new SqliteCommand(SelectAssetSQL, m_conn))
150 {
151 cmd.Parameters.Add(new SqliteParameter(":UUID", Util.ToRawUuidString(uuid)));
152 using (IDataReader reader = cmd.ExecuteReader())
153 {
154 if(reader.Read())
155 {
156 reader.Close();
157 return true;
158 }
159 else
160 {
161 reader.Close();
162 return false;
163 }
164 }
165 }
166 }
167
168 public void DeleteAsset(LLUUID uuid)
169 {
170 using (SqliteCommand cmd = new SqliteCommand(DeleteAssetSQL, m_conn))
171 {
172 cmd.Parameters.Add(new SqliteParameter(":UUID", Util.ToRawUuidString(uuid)));
173
174 cmd.ExecuteNonQuery();
175 }
176 }
177
178 override public void CommitAssets() // force a sync to the database
179 {
180 m_log.Info("[SQLITE]: Attempting commit");
181 // lock (ds)
182 // {
183 // da.Update(ds, "assets");
184 // ds.AcceptChanges();
185 // }
186 }
187
188 /***********************************************************************
189 *
190 * Database Definition Functions
191 *
192 * This should be db agnostic as we define them in ADO.NET terms
193 *
194 **********************************************************************/
195
196 private DataTable createAssetsTable()
197 {
198 DataTable assets = new DataTable("assets");
199
200 SQLiteUtil.createCol(assets, "UUID", typeof (String));
201 SQLiteUtil.createCol(assets, "Name", typeof (String));
202 SQLiteUtil.createCol(assets, "Description", typeof (String));
203 SQLiteUtil.createCol(assets, "Type", typeof (Int32));
204 SQLiteUtil.createCol(assets, "InvType", typeof (Int32));
205 SQLiteUtil.createCol(assets, "Local", typeof (Boolean));
206 SQLiteUtil.createCol(assets, "Temporary", typeof (Boolean));
207 SQLiteUtil.createCol(assets, "Data", typeof (Byte[]));
208 // Add in contraints
209 assets.PrimaryKey = new DataColumn[] {assets.Columns["UUID"]};
210 return assets;
211 }
212
213 /***********************************************************************
214 *
215 * Convert between ADO.NET <=> OpenSim Objects
216 *
217 * These should be database independant
218 *
219 **********************************************************************/
220
221 private AssetBase buildAsset(IDataReader row)
222 {
223 // TODO: this doesn't work yet because something more
224 // interesting has to be done to actually get these values
225 // back out. Not enough time to figure it out yet.
226 AssetBase asset = new AssetBase();
227
228 asset.FullID = new LLUUID((String) row["UUID"]);
229 asset.Name = (String) row["Name"];
230 asset.Description = (String) row["Description"];
231 asset.Type = Convert.ToSByte(row["Type"]);
232 asset.InvType = Convert.ToSByte(row["InvType"]);
233 asset.Local = Convert.ToBoolean(row["Local"]);
234 asset.Temporary = Convert.ToBoolean(row["Temporary"]);
235 asset.Data = (byte[]) row["Data"];
236 return asset;
237 }
238
239
240 /***********************************************************************
241 *
242 * Database Binding functions
243 *
244 * These will be db specific due to typing, and minor differences
245 * in databases.
246 *
247 **********************************************************************/
248
249 private void InitDB(SqliteConnection conn)
250 {
251 string createAssets = SQLiteUtil.defineTable(createAssetsTable());
252 SqliteCommand pcmd = new SqliteCommand(createAssets, conn);
253 pcmd.ExecuteNonQuery();
254 }
255
256 private bool TestTables(SqliteConnection conn)
257 {
258 SqliteCommand cmd = new SqliteCommand(assetSelect, conn);
259 SqliteDataAdapter pDa = new SqliteDataAdapter(cmd);
260 DataSet tmpDS = new DataSet();
261 try
262 {
263 pDa.Fill(tmpDS, "assets");
264 }
265 catch (SqliteSyntaxException)
266 {
267 m_log.Info("[SQLITE]: SQLite Database doesn't exist... creating");
268 InitDB(conn);
269 }
270 return true;
271 }
272
273 #region IPlugin interface
274
275 override public string Version
276 {
277 get
278 {
279 Module module = GetType().Module;
280 string dllName = module.Assembly.ManifestModule.Name;
281 Version dllVersion = module.Assembly.GetName().Version;
282
283 return
284 string.Format("{0}.{1}.{2}.{3}", dllVersion.Major, dllVersion.Minor, dllVersion.Build,
285 dllVersion.Revision);
286 }
287 }
288
289 override public void Initialise()
290 {
291 Initialise("AssetStorage.db", "");
292 }
293
294 override public string Name
295 {
296 get { return "SQLite Asset storage engine"; }
297 }
298
299 #endregion
300 }
301}
diff --git a/OpenSim/Data/SQLite/SQLiteGridData.cs b/OpenSim/Data/SQLite/SQLiteGridData.cs
new file mode 100644
index 0000000..94e8e50
--- /dev/null
+++ b/OpenSim/Data/SQLite/SQLiteGridData.cs
@@ -0,0 +1,234 @@
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 OpenSim 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.Security.Cryptography;
32using System.Text;
33using libsecondlife;
34
35namespace OpenSim.Framework.Data.SQLite
36{
37 /// <summary>
38 /// A Grid Interface to the SQLite database
39 /// </summary>
40 public class SQLiteGridData : GridDataBase
41 {
42 /// <summary>
43 /// A database manager
44 /// </summary>
45 private SQLiteManager database;
46
47 /// <summary>
48 /// Initialises the Grid Interface
49 /// </summary>
50 override public void Initialise()
51 {
52 database = new SQLiteManager("localhost", "db", "user", "password", "false");
53 }
54
55 /// <summary>
56 /// Shuts down the grid interface
57 /// </summary>
58 override public void Close()
59 {
60 database.Close();
61 }
62
63 /// <summary>
64 /// Returns the name of this grid interface
65 /// </summary>
66 /// <returns>A string containing the grid interface</returns>
67 override public string getName()
68 {
69 return "SQLite OpenGridData";
70 }
71
72 /// <summary>
73 /// Returns the version of this grid interface
74 /// </summary>
75 /// <returns>A string containing the version</returns>
76 override public string getVersion()
77 {
78 return "0.1";
79 }
80
81 /// <summary>
82 /// Returns a list of regions within the specified ranges
83 /// </summary>
84 /// <param name="a">minimum X coordinate</param>
85 /// <param name="b">minimum Y coordinate</param>
86 /// <param name="c">maximum X coordinate</param>
87 /// <param name="d">maximum Y coordinate</param>
88 /// <returns>An array of region profiles</returns>
89 override public RegionProfileData[] GetProfilesInRange(uint a, uint b, uint c, uint d)
90 {
91 return null;
92 }
93
94 /// <summary>
95 /// Returns a sim profile from it's location
96 /// </summary>
97 /// <param name="handle">Region location handle</param>
98 /// <returns>Sim profile</returns>
99 override public RegionProfileData GetProfileByHandle(ulong handle)
100 {
101 Dictionary<string, string> param = new Dictionary<string, string>();
102 param["handle"] = handle.ToString();
103
104 IDbCommand result = database.Query("SELECT * FROM regions WHERE handle = @handle", param);
105 IDataReader reader = result.ExecuteReader();
106
107 RegionProfileData row = database.getRow(reader);
108 reader.Close();
109 result.Dispose();
110
111 return row;
112 }
113
114 /// <summary>
115 /// Returns a sim profile from it's Region name string
116 /// </summary>
117 /// <param name="regionName">The region name search query</param>
118 /// <returns>The sim profile</returns>
119 override public RegionProfileData GetProfileByString(string regionName)
120 {
121 if (regionName.Length > 2)
122 {
123 Dictionary<string, string> param = new Dictionary<string, string>();
124 // Add % because this is a like query.
125 param["?regionName"] = regionName + "%";
126 // Only returns one record or no record.
127 IDbCommand result = database.Query("SELECT * FROM regions WHERE regionName like ?regionName LIMIT 1", param);
128 IDataReader reader = result.ExecuteReader();
129
130 RegionProfileData row = database.getRow(reader);
131 reader.Close();
132 result.Dispose();
133
134 return row;
135 }
136 else
137 {
138 //m_log.Error("[DATABASE]: Searched for a Region Name shorter then 3 characters");
139 return null;
140 }
141 }
142
143 /// <summary>
144 /// Returns a sim profile from it's UUID
145 /// </summary>
146 /// <param name="uuid">The region UUID</param>
147 /// <returns>The sim profile</returns>
148 override public RegionProfileData GetProfileByLLUUID(LLUUID uuid)
149 {
150 Dictionary<string, string> param = new Dictionary<string, string>();
151 param["uuid"] = uuid.ToString();
152
153 IDbCommand result = database.Query("SELECT * FROM regions WHERE uuid = @uuid", param);
154 IDataReader reader = result.ExecuteReader();
155
156 RegionProfileData row = database.getRow(reader);
157 reader.Close();
158 result.Dispose();
159
160 return row;
161 }
162
163 /// <summary>
164 /// // Returns a list of avatar and UUIDs that match the query
165 /// </summary>
166 public List<AvatarPickerAvatar> GeneratePickerResults(LLUUID queryID, string query)
167 {
168 //Do nothing yet
169 List<AvatarPickerAvatar> returnlist = new List<AvatarPickerAvatar>();
170 return returnlist;
171 }
172
173 /// <summary>
174 /// Adds a new specified region to the database
175 /// </summary>
176 /// <param name="profile">The profile to add</param>
177 /// <returns>A dataresponse enum indicating success</returns>
178 override public DataResponse AddProfile(RegionProfileData profile)
179 {
180 if (database.insertRow(profile))
181 {
182 return DataResponse.RESPONSE_OK;
183 }
184 else
185 {
186 return DataResponse.RESPONSE_ERROR;
187 }
188 }
189
190 /// <summary>
191 /// DEPRECATED. Attempts to authenticate a region by comparing a shared secret.
192 /// </summary>
193 /// <param name="uuid">The UUID of the challenger</param>
194 /// <param name="handle">The attempted regionHandle of the challenger</param>
195 /// <param name="authkey">The secret</param>
196 /// <returns>Whether the secret and regionhandle match the database entry for UUID</returns>
197 override public bool AuthenticateSim(LLUUID uuid, ulong handle, string authkey)
198 {
199 bool throwHissyFit = false; // Should be true by 1.0
200
201 if (throwHissyFit)
202 throw new Exception("CRYPTOWEAK AUTHENTICATE: Refusing to authenticate due to replay potential.");
203
204 RegionProfileData data = GetProfileByLLUUID(uuid);
205
206 return (handle == data.regionHandle && authkey == data.regionSecret);
207 }
208
209 /// <summary>
210 /// NOT YET FUNCTIONAL. Provides a cryptographic authentication of a region
211 /// </summary>
212 /// <remarks>This requires a security audit.</remarks>
213 /// <param name="uuid"></param>
214 /// <param name="handle"></param>
215 /// <param name="authhash"></param>
216 /// <param name="challenge"></param>
217 /// <returns></returns>
218 public bool AuthenticateSim(LLUUID uuid, ulong handle, string authhash, string challenge)
219 {
220 SHA512Managed HashProvider = new SHA512Managed();
221 ASCIIEncoding TextProvider = new ASCIIEncoding();
222
223 byte[] stream = TextProvider.GetBytes(uuid.ToString() + ":" + handle.ToString() + ":" + challenge);
224 byte[] hash = HashProvider.ComputeHash(stream);
225
226 return false;
227 }
228
229 override public ReservationData GetReservationAtPoint(uint x, uint y)
230 {
231 return null;
232 }
233 }
234}
diff --git a/OpenSim/Data/SQLite/SQLiteInventoryStore.cs b/OpenSim/Data/SQLite/SQLiteInventoryStore.cs
new file mode 100644
index 0000000..d31863f
--- /dev/null
+++ b/OpenSim/Data/SQLite/SQLiteInventoryStore.cs
@@ -0,0 +1,664 @@
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 OpenSim 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 libsecondlife;
33using Mono.Data.SqliteClient;
34using OpenSim.Framework.Console;
35
36namespace OpenSim.Framework.Data.SQLite
37{
38 public class SQLiteInventoryStore : SQLiteUtil, IInventoryData
39 {
40 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
41
42 private const string invItemsSelect = "select * from inventoryitems";
43 private const string invFoldersSelect = "select * from inventoryfolders";
44
45 private DataSet ds;
46 private SqliteDataAdapter invItemsDa;
47 private SqliteDataAdapter invFoldersDa;
48
49 /// <summary>
50 /// Initialises the interface
51 /// </summary>
52 public void Initialise()
53 {
54 Initialise("inventoryStore.db", "inventoryDatabase");
55 }
56
57 public void Initialise(string dbfile, string dbname)
58 {
59 string connectionString = "URI=file:" + dbfile + ",version=3";
60
61 m_log.Info("[Inventory]: Sqlite - connecting: " + dbfile);
62 SqliteConnection conn = new SqliteConnection(connectionString);
63
64 conn.Open();
65
66 TestTables(conn);
67
68 SqliteCommand itemsSelectCmd = new SqliteCommand(invItemsSelect, conn);
69 invItemsDa = new SqliteDataAdapter(itemsSelectCmd);
70 // SqliteCommandBuilder primCb = new SqliteCommandBuilder(primDa);
71
72 SqliteCommand foldersSelectCmd = new SqliteCommand(invFoldersSelect, conn);
73 invFoldersDa = new SqliteDataAdapter(foldersSelectCmd);
74
75 ds = new DataSet();
76
77 ds.Tables.Add(createInventoryFoldersTable());
78 invFoldersDa.Fill(ds.Tables["inventoryfolders"]);
79 setupFoldersCommands(invFoldersDa, conn);
80 m_log.Info("[DATASTORE]: Populated Intentory Folders Definitions");
81
82 ds.Tables.Add(createInventoryItemsTable());
83 invItemsDa.Fill(ds.Tables["inventoryitems"]);
84 setupItemsCommands(invItemsDa, conn);
85 m_log.Info("[DATASTORE]: Populated Intentory Items Definitions");
86
87 ds.AcceptChanges();
88 }
89
90 public InventoryItemBase buildItem(DataRow row)
91 {
92 InventoryItemBase item = new InventoryItemBase();
93 item.inventoryID = new LLUUID((string) row["UUID"]);
94 item.assetID = new LLUUID((string) row["assetID"]);
95 item.assetType = Convert.ToInt32(row["assetType"]);
96 item.invType = Convert.ToInt32(row["invType"]);
97 item.parentFolderID = new LLUUID((string) row["parentFolderID"]);
98 item.avatarID = new LLUUID((string) row["avatarID"]);
99 item.creatorsID = new LLUUID((string) row["creatorsID"]);
100 item.inventoryName = (string) row["inventoryName"];
101 item.inventoryDescription = (string) row["inventoryDescription"];
102
103 item.inventoryNextPermissions = Convert.ToUInt32(row["inventoryNextPermissions"]);
104 item.inventoryCurrentPermissions = Convert.ToUInt32(row["inventoryCurrentPermissions"]);
105 item.inventoryBasePermissions = Convert.ToUInt32(row["inventoryBasePermissions"]);
106 item.inventoryEveryOnePermissions = Convert.ToUInt32(row["inventoryEveryOnePermissions"]);
107 return item;
108 }
109
110 private void fillItemRow(DataRow row, InventoryItemBase item)
111 {
112 row["UUID"] = Util.ToRawUuidString(item.inventoryID);
113 row["assetID"] = Util.ToRawUuidString(item.assetID);
114 row["assetType"] = item.assetType;
115 row["invType"] = item.invType;
116 row["parentFolderID"] = Util.ToRawUuidString(item.parentFolderID);
117 row["avatarID"] = Util.ToRawUuidString(item.avatarID);
118 row["creatorsID"] = Util.ToRawUuidString(item.creatorsID);
119 row["inventoryName"] = item.inventoryName;
120 row["inventoryDescription"] = item.inventoryDescription;
121
122 row["inventoryNextPermissions"] = item.inventoryNextPermissions;
123 row["inventoryCurrentPermissions"] = item.inventoryCurrentPermissions;
124 row["inventoryBasePermissions"] = item.inventoryBasePermissions;
125 row["inventoryEveryOnePermissions"] = item.inventoryEveryOnePermissions;
126 }
127
128 private void addFolder(InventoryFolderBase folder)
129 {
130 lock (ds)
131 {
132 DataTable inventoryFolderTable = ds.Tables["inventoryfolders"];
133
134 DataRow inventoryRow = inventoryFolderTable.Rows.Find(Util.ToRawUuidString(folder.folderID));
135 if (inventoryRow == null)
136 {
137 inventoryRow = inventoryFolderTable.NewRow();
138 fillFolderRow(inventoryRow, folder);
139 inventoryFolderTable.Rows.Add(inventoryRow);
140 }
141 else
142 {
143 fillFolderRow(inventoryRow, folder);
144 }
145
146 invFoldersDa.Update(ds, "inventoryfolders");
147 }
148 }
149
150 private void moveFolder(InventoryFolderBase folder)
151 {
152 lock (ds)
153 {
154 DataTable inventoryFolderTable = ds.Tables["inventoryfolders"];
155
156 DataRow inventoryRow = inventoryFolderTable.Rows.Find(Util.ToRawUuidString(folder.folderID));
157 if (inventoryRow == null)
158 {
159 inventoryRow = inventoryFolderTable.NewRow();
160 fillFolderRow(inventoryRow, folder);
161 inventoryFolderTable.Rows.Add(inventoryRow);
162 }
163 else
164 {
165 moveFolderRow(inventoryRow, folder);
166 }
167
168 invFoldersDa.Update(ds, "inventoryfolders");
169 }
170 }
171
172 private void addItem(InventoryItemBase item)
173 {
174 lock (ds)
175 {
176 DataTable inventoryItemTable = ds.Tables["inventoryitems"];
177
178 DataRow inventoryRow = inventoryItemTable.Rows.Find(Util.ToRawUuidString(item.inventoryID));
179 if (inventoryRow == null)
180 {
181 inventoryRow = inventoryItemTable.NewRow();
182 fillItemRow(inventoryRow, item);
183 inventoryItemTable.Rows.Add(inventoryRow);
184 }
185 else
186 {
187 fillItemRow(inventoryRow, item);
188 }
189 invItemsDa.Update(ds, "inventoryitems");
190 }
191 }
192
193 public void Shutdown()
194 {
195 // TODO: DataSet commit
196 }
197
198 /// <summary>
199 /// Closes the interface
200 /// </summary>
201 public void Close()
202 {
203 }
204
205 /// <summary>
206 /// The plugin being loaded
207 /// </summary>
208 /// <returns>A string containing the plugin name</returns>
209 public string getName()
210 {
211 return "SQLite Inventory Data Interface";
212 }
213
214 /// <summary>
215 /// The plugins version
216 /// </summary>
217 /// <returns>A string containing the plugin version</returns>
218 public string getVersion()
219 {
220 Module module = GetType().Module;
221 string dllName = module.Assembly.ManifestModule.Name;
222 Version dllVersion = module.Assembly.GetName().Version;
223
224
225 return
226 string.Format("{0}.{1}.{2}.{3}", dllVersion.Major, dllVersion.Minor, dllVersion.Build,
227 dllVersion.Revision);
228 }
229
230 /// <summary>
231 /// Returns a list of inventory items contained within the specified folder
232 /// </summary>
233 /// <param name="folderID">The UUID of the target folder</param>
234 /// <returns>A List of InventoryItemBase items</returns>
235 public List<InventoryItemBase> getInventoryInFolder(LLUUID folderID)
236 {
237 lock (ds)
238 {
239 List<InventoryItemBase> retval = new List<InventoryItemBase>();
240 DataTable inventoryItemTable = ds.Tables["inventoryitems"];
241 string selectExp = "parentFolderID = '" + Util.ToRawUuidString(folderID) + "'";
242 DataRow[] rows = inventoryItemTable.Select(selectExp);
243 foreach (DataRow row in rows)
244 {
245 retval.Add(buildItem(row));
246 }
247
248 return retval;
249 }
250 }
251
252 /// <summary>
253 /// Returns a list of the root folders within a users inventory
254 /// </summary>
255 /// <param name="user">The user whos inventory is to be searched</param>
256 /// <returns>A list of folder objects</returns>
257 public List<InventoryFolderBase> getUserRootFolders(LLUUID user)
258 {
259 return new List<InventoryFolderBase>();
260 }
261
262 // see InventoryItemBase.getUserRootFolder
263 public InventoryFolderBase getUserRootFolder(LLUUID user)
264 {
265 lock (ds)
266 {
267 List<InventoryFolderBase> folders = new List<InventoryFolderBase>();
268 DataTable inventoryFolderTable = ds.Tables["inventoryfolders"];
269 string selectExp = "agentID = '" + Util.ToRawUuidString(user) + "' AND parentID = '" +
270 Util.ToRawUuidString(LLUUID.Zero) + "'";
271 DataRow[] rows = inventoryFolderTable.Select(selectExp);
272 foreach (DataRow row in rows)
273 {
274 folders.Add(buildFolder(row));
275 }
276
277 // There should only ever be one root folder for a user. However, if there's more
278 // than one we'll simply use the first one rather than failing. It would be even
279 // nicer to print some message to this effect, but this feels like it's too low a
280 // to put such a message out, and it's too minor right now to spare the time to
281 // suitably refactor.
282 if (folders.Count > 0)
283 {
284 return folders[0];
285 }
286
287 return null;
288 }
289 }
290
291 /// <summary>
292 /// Append a list of all the child folders of a parent folder
293 /// </summary>
294 /// <param name="folders">list where folders will be appended</param>
295 /// <param name="parentID">ID of parent</param>
296 protected void getInventoryFolders(ref List<InventoryFolderBase> folders, LLUUID parentID)
297 {
298 lock (ds)
299 {
300 DataTable inventoryFolderTable = ds.Tables["inventoryfolders"];
301 string selectExp = "parentID = '" + Util.ToRawUuidString(parentID) + "'";
302 DataRow[] rows = inventoryFolderTable.Select(selectExp);
303 foreach (DataRow row in rows)
304 {
305 folders.Add(buildFolder(row));
306 }
307 }
308 }
309
310 /// <summary>
311 /// Returns a list of inventory folders contained in the folder 'parentID'
312 /// </summary>
313 /// <param name="parentID">The folder to get subfolders for</param>
314 /// <returns>A list of inventory folders</returns>
315 public List<InventoryFolderBase> getInventoryFolders(LLUUID parentID)
316 {
317 List<InventoryFolderBase> folders = new List<InventoryFolderBase>();
318 getInventoryFolders(ref folders, Util.ToRawUuidString(parentID));
319 return folders;
320 }
321
322 // See IInventoryData
323 public List<InventoryFolderBase> getFolderHierarchy(LLUUID parentID)
324 {
325 List<InventoryFolderBase> folders = new List<InventoryFolderBase>();
326 getInventoryFolders(ref folders, Util.ToRawUuidString(parentID));
327
328 for (int i = 0; i < folders.Count; i++)
329 getInventoryFolders(ref folders, Util.ToRawUuidString(folders[i].folderID));
330
331 return folders;
332 }
333
334 /// <summary>
335 /// Returns an inventory item by its UUID
336 /// </summary>
337 /// <param name="item">The UUID of the item to be returned</param>
338 /// <returns>A class containing item information</returns>
339 public InventoryItemBase getInventoryItem(LLUUID item)
340 {
341 lock (ds)
342 {
343 DataRow row = ds.Tables["inventoryitems"].Rows.Find(Util.ToRawUuidString(item));
344 if (row != null)
345 {
346 return buildItem(row);
347 }
348 else
349 {
350 return null;
351 }
352 }
353 }
354
355 /// <summary>
356 /// Returns a specified inventory folder by its UUID
357 /// </summary>
358 /// <param name="folder">The UUID of the folder to be returned</param>
359 /// <returns>A class containing folder information</returns>
360 public InventoryFolderBase getInventoryFolder(LLUUID folder)
361 {
362 // TODO: Deep voodoo here. If you enable this code then
363 // multi region breaks. No idea why, but I figured it was
364 // better to leave multi region at this point. It does mean
365 // that you don't get to see system textures why creating
366 // clothes and the like. :(
367 lock (ds)
368 {
369 DataRow row = ds.Tables["inventoryfolders"].Rows.Find(Util.ToRawUuidString(folder));
370 if (row != null)
371 {
372 return buildFolder(row);
373 }
374 else
375 {
376 return null;
377 }
378 }
379 }
380
381 /// <summary>
382 /// Creates a new inventory item based on item
383 /// </summary>
384 /// <param name="item">The item to be created</param>
385 public void addInventoryItem(InventoryItemBase item)
386 {
387 addItem(item);
388 }
389
390 /// <summary>
391 /// Updates an inventory item with item (updates based on ID)
392 /// </summary>
393 /// <param name="item">The updated item</param>
394 public void updateInventoryItem(InventoryItemBase item)
395 {
396 addItem(item);
397 }
398
399 /// <summary>
400 ///
401 /// </summary>
402 /// <param name="item"></param>
403 public void deleteInventoryItem(LLUUID itemID)
404 {
405 lock (ds)
406 {
407 DataTable inventoryItemTable = ds.Tables["inventoryitems"];
408
409 DataRow inventoryRow = inventoryItemTable.Rows.Find(Util.ToRawUuidString(itemID));
410 if (inventoryRow != null)
411 {
412 inventoryRow.Delete();
413 }
414
415 invItemsDa.Update(ds, "inventoryitems");
416 }
417 }
418
419 /// <summary>
420 /// Delete all items in the specified folder
421 /// </summary>
422 /// <param name="folderId">id of the folder, whose item content should be deleted</param>
423 //!TODO, this is horribly inefficient, but I don't want to ruin the overall structure of this implementation
424 private void deleteItemsInFolder(LLUUID folderId)
425 {
426 List<InventoryItemBase> items = getInventoryInFolder(Util.ToRawUuidString(folderId));
427
428 foreach (InventoryItemBase i in items)
429 deleteInventoryItem(Util.ToRawUuidString(i.inventoryID));
430 }
431
432 /// <summary>
433 /// Adds a new folder specified by folder
434 /// </summary>
435 /// <param name="folder">The inventory folder</param>
436 public void addInventoryFolder(InventoryFolderBase folder)
437 {
438 addFolder(folder);
439 }
440
441 /// <summary>
442 /// Updates a folder based on its ID with folder
443 /// </summary>
444 /// <param name="folder">The inventory folder</param>
445 public void updateInventoryFolder(InventoryFolderBase folder)
446 {
447 addFolder(folder);
448 }
449
450 /// <summary>
451 /// Moves a folder based on its ID with folder
452 /// </summary>
453 /// <param name="folder">The inventory folder</param>
454 public void moveInventoryFolder(InventoryFolderBase folder)
455 {
456 moveFolder(folder);
457 }
458
459 /// <summary>
460 /// Delete a folder
461 /// </summary>
462 /// <remarks>
463 /// This will clean-up any child folders and child items as well
464 /// </remarks>
465 /// <param name="item"></param>
466 public void deleteInventoryFolder(LLUUID folderID)
467 {
468 lock (ds)
469 {
470 List<InventoryFolderBase> subFolders = getFolderHierarchy(Util.ToRawUuidString(folderID));
471
472 DataTable inventoryFolderTable = ds.Tables["inventoryfolders"];
473 DataRow inventoryRow;
474
475 //Delete all sub-folders
476 foreach (InventoryFolderBase f in subFolders)
477 {
478 inventoryRow = inventoryFolderTable.Rows.Find(Util.ToRawUuidString(f.folderID));
479 if (inventoryRow != null)
480 {
481 deleteItemsInFolder(Util.ToRawUuidString(f.folderID));
482 inventoryRow.Delete();
483 }
484 }
485
486 //Delete the actual row
487 inventoryRow = inventoryFolderTable.Rows.Find(Util.ToRawUuidString(folderID));
488 if (inventoryRow != null)
489 {
490 deleteItemsInFolder(Util.ToRawUuidString(folderID));
491 inventoryRow.Delete();
492 }
493
494 invFoldersDa.Update(ds, "inventoryfolders");
495 }
496 }
497
498 /***********************************************************************
499 *
500 * Data Table definitions
501 *
502 **********************************************************************/
503
504 private static DataTable createInventoryItemsTable()
505 {
506 DataTable inv = new DataTable("inventoryitems");
507
508 createCol(inv, "UUID", typeof (String)); //inventoryID
509 createCol(inv, "assetID", typeof (String));
510 createCol(inv, "assetType", typeof (Int32));
511 createCol(inv, "invType", typeof (Int32));
512 createCol(inv, "parentFolderID", typeof (String));
513 createCol(inv, "avatarID", typeof (String));
514 createCol(inv, "creatorsID", typeof (String));
515
516 createCol(inv, "inventoryName", typeof (String));
517 createCol(inv, "inventoryDescription", typeof (String));
518 // permissions
519 createCol(inv, "inventoryNextPermissions", typeof (Int32));
520 createCol(inv, "inventoryCurrentPermissions", typeof (Int32));
521 createCol(inv, "inventoryBasePermissions", typeof (Int32));
522 createCol(inv, "inventoryEveryOnePermissions", typeof (Int32));
523
524 inv.PrimaryKey = new DataColumn[] {inv.Columns["UUID"]};
525 return inv;
526 }
527
528 private DataTable createInventoryFoldersTable()
529 {
530 DataTable fol = new DataTable("inventoryfolders");
531
532 createCol(fol, "UUID", typeof (String)); //folderID
533 createCol(fol, "name", typeof (String));
534 createCol(fol, "agentID", typeof (String));
535 createCol(fol, "parentID", typeof (String));
536 createCol(fol, "type", typeof (Int32));
537 createCol(fol, "version", typeof (Int32));
538
539 fol.PrimaryKey = new DataColumn[] {fol.Columns["UUID"]};
540 return fol;
541 }
542
543 private void setupItemsCommands(SqliteDataAdapter da, SqliteConnection conn)
544 {
545 lock (ds)
546 {
547 da.InsertCommand = createInsertCommand("inventoryitems", ds.Tables["inventoryitems"]);
548 da.InsertCommand.Connection = conn;
549
550 da.UpdateCommand = createUpdateCommand("inventoryitems", "UUID=:UUID", ds.Tables["inventoryitems"]);
551 da.UpdateCommand.Connection = conn;
552
553 SqliteCommand delete = new SqliteCommand("delete from inventoryitems where UUID = :UUID");
554 delete.Parameters.Add(createSqliteParameter("UUID", typeof(String)));
555 delete.Connection = conn;
556 da.DeleteCommand = delete;
557 }
558 }
559
560 private void setupFoldersCommands(SqliteDataAdapter da, SqliteConnection conn)
561 {
562 lock (ds)
563 {
564 da.InsertCommand = createInsertCommand("inventoryfolders", ds.Tables["inventoryfolders"]);
565 da.InsertCommand.Connection = conn;
566
567 da.UpdateCommand = createUpdateCommand("inventoryfolders", "UUID=:UUID", ds.Tables["inventoryfolders"]);
568 da.UpdateCommand.Connection = conn;
569
570 SqliteCommand delete = new SqliteCommand("delete from inventoryfolders where UUID = :UUID");
571 delete.Parameters.Add(createSqliteParameter("UUID", typeof(String)));
572 delete.Connection = conn;
573 da.DeleteCommand = delete;
574 }
575 }
576
577 private InventoryFolderBase buildFolder(DataRow row)
578 {
579 InventoryFolderBase folder = new InventoryFolderBase();
580 folder.folderID = new LLUUID((string) row["UUID"]);
581 folder.name = (string) row["name"];
582 folder.agentID = new LLUUID((string) row["agentID"]);
583 folder.parentID = new LLUUID((string) row["parentID"]);
584 folder.type = Convert.ToInt16(row["type"]);
585 folder.version = Convert.ToUInt16(row["version"]);
586 return folder;
587 }
588
589 private void fillFolderRow(DataRow row, InventoryFolderBase folder)
590 {
591 row["UUID"] = Util.ToRawUuidString(folder.folderID);
592 row["name"] = folder.name;
593 row["agentID"] = Util.ToRawUuidString(folder.agentID);
594 row["parentID"] = Util.ToRawUuidString(folder.parentID);
595 row["type"] = folder.type;
596 row["version"] = folder.version;
597 }
598
599 private void moveFolderRow(DataRow row, InventoryFolderBase folder)
600 {
601 row["UUID"] = Util.ToRawUuidString(folder.folderID);
602 row["parentID"] = Util.ToRawUuidString(folder.parentID);
603 }
604
605 /***********************************************************************
606 *
607 * Test and Initialization code
608 *
609 **********************************************************************/
610
611 private void InitDB(SqliteConnection conn)
612 {
613 string createInventoryItems = defineTable(createInventoryItemsTable());
614 string createInventoryFolders = defineTable(createInventoryFoldersTable());
615
616 SqliteCommand pcmd = new SqliteCommand(createInventoryItems, conn);
617 SqliteCommand scmd = new SqliteCommand(createInventoryFolders, conn);
618
619 pcmd.ExecuteNonQuery();
620 scmd.ExecuteNonQuery();
621 }
622
623 private bool TestTables(SqliteConnection conn)
624 {
625 SqliteCommand invItemsSelectCmd = new SqliteCommand(invItemsSelect, conn);
626 SqliteDataAdapter pDa = new SqliteDataAdapter(invItemsSelectCmd);
627 SqliteCommand invFoldersSelectCmd = new SqliteCommand(invFoldersSelect, conn);
628 SqliteDataAdapter sDa = new SqliteDataAdapter(invFoldersSelectCmd);
629
630 DataSet tmpDS = new DataSet();
631 try
632 {
633 pDa.Fill(tmpDS, "inventoryitems");
634 sDa.Fill(tmpDS, "inventoryfolders");
635 }
636 catch (SqliteSyntaxException)
637 {
638 m_log.Info("[DATASTORE]: SQLite Database doesn't exist... creating");
639 InitDB(conn);
640 }
641
642 pDa.Fill(tmpDS, "inventoryitems");
643 sDa.Fill(tmpDS, "inventoryfolders");
644
645 foreach (DataColumn col in createInventoryItemsTable().Columns)
646 {
647 if (! tmpDS.Tables["inventoryitems"].Columns.Contains(col.ColumnName))
648 {
649 m_log.Info("[DATASTORE]: Missing required column:" + col.ColumnName);
650 return false;
651 }
652 }
653 foreach (DataColumn col in createInventoryFoldersTable().Columns)
654 {
655 if (! tmpDS.Tables["inventoryfolders"].Columns.Contains(col.ColumnName))
656 {
657 m_log.Info("[DATASTORE]: Missing required column:" + col.ColumnName);
658 return false;
659 }
660 }
661 return true;
662 }
663 }
664}
diff --git a/OpenSim/Data/SQLite/SQLiteManager.cs b/OpenSim/Data/SQLite/SQLiteManager.cs
new file mode 100644
index 0000000..b383b0d
--- /dev/null
+++ b/OpenSim/Data/SQLite/SQLiteManager.cs
@@ -0,0 +1,282 @@
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 OpenSim 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.Data.SQLite;
32using libsecondlife;
33using Mono.Data.SqliteClient;
34using OpenSim.Framework.Console;
35
36namespace OpenSim.Framework.Data.SQLite
37{
38 internal class SQLiteManager : SQLiteUtil
39 {
40 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
41
42 private IDbConnection dbcon;
43
44 /// <summary>
45 /// Initialises and creates a new SQLite connection and maintains it.
46 /// </summary>
47 /// <param name="hostname">The SQLite server being connected to</param>
48 /// <param name="database">The name of the SQLite database being used</param>
49 /// <param name="username">The username logging into the database</param>
50 /// <param name="password">The password for the user logging in</param>
51 /// <param name="cpooling">Whether to use connection pooling or not, can be one of the following: 'yes', 'true', 'no' or 'false', if unsure use 'false'.</param>
52 public SQLiteManager(string hostname, string database, string username, string password, string cpooling)
53 {
54 try
55 {
56 string connectionString = "URI=file:GridServerSqlite.db;";
57 dbcon = new SQLiteConnection(connectionString);
58
59 dbcon.Open();
60 }
61 catch (Exception e)
62 {
63 throw new Exception("Error initialising SQLite Database: " + e.ToString());
64 }
65 }
66
67 /// <summary>
68 /// Shuts down the database connection
69 /// </summary>
70 public void Close()
71 {
72 dbcon.Close();
73 dbcon = null;
74 }
75
76 /// <summary>
77 /// Runs a query with protection against SQL Injection by using parameterised input.
78 /// </summary>
79 /// <param name="sql">The SQL string - replace any variables such as WHERE x = "y" with WHERE x = @y</param>
80 /// <param name="parameters">The parameters - index so that @y is indexed as 'y'</param>
81 /// <returns>A SQLite DB Command</returns>
82 public IDbCommand Query(string sql, Dictionary<string, string> parameters)
83 {
84 SQLiteCommand dbcommand = (SQLiteCommand) dbcon.CreateCommand();
85 dbcommand.CommandText = sql;
86 foreach (KeyValuePair<string, string> param in parameters)
87 {
88 SQLiteParameter paramx = new SQLiteParameter(param.Key, param.Value);
89 dbcommand.Parameters.Add(paramx);
90 }
91
92 return (IDbCommand) dbcommand;
93 }
94
95// TODO: unused
96// private bool TestTables(SQLiteConnection conn)
97// {
98// SQLiteCommand cmd = new SQLiteCommand("SELECT * FROM regions", conn);
99// SQLiteDataAdapter pDa = new SQLiteDataAdapter(cmd);
100// DataSet tmpDS = new DataSet();
101// try
102// {
103// pDa.Fill(tmpDS, "regions");
104// }
105// catch (SqliteSyntaxException)
106// {
107// m_log.Info("[DATASTORE]: SQLite Database doesn't exist... creating");
108// InitDB(conn);
109// }
110// return true;
111// }
112
113// TODO: unused
114// private DataTable createRegionsTable()
115// {
116// DataTable regions = new DataTable("regions");
117
118// createCol(regions, "regionHandle", typeof (ulong));
119// createCol(regions, "regionName", typeof (String));
120// createCol(regions, "uuid", typeof (String));
121
122// createCol(regions, "regionRecvKey", typeof (String));
123// createCol(regions, "regionSecret", typeof (String));
124// createCol(regions, "regionSendKey", typeof (String));
125
126// createCol(regions, "regionDataURI", typeof (String));
127// createCol(regions, "serverIP", typeof (String));
128// createCol(regions, "serverPort", typeof (String));
129// createCol(regions, "serverURI", typeof (String));
130
131
132// createCol(regions, "locX", typeof (uint));
133// createCol(regions, "locY", typeof (uint));
134// createCol(regions, "locZ", typeof (uint));
135
136// createCol(regions, "eastOverrideHandle", typeof (ulong));
137// createCol(regions, "westOverrideHandle", typeof (ulong));
138// createCol(regions, "southOverrideHandle", typeof (ulong));
139// createCol(regions, "northOverrideHandle", typeof (ulong));
140
141// createCol(regions, "regionAssetURI", typeof (String));
142// createCol(regions, "regionAssetRecvKey", typeof (String));
143// createCol(regions, "regionAssetSendKey", typeof (String));
144
145// createCol(regions, "regionUserURI", typeof (String));
146// createCol(regions, "regionUserRecvKey", typeof (String));
147// createCol(regions, "regionUserSendKey", typeof (String));
148
149// // Add in contraints
150// regions.PrimaryKey = new DataColumn[] {regions.Columns["UUID"]};
151// return regions;
152// }
153
154// TODO: unused
155// private void InitDB(SQLiteConnection conn)
156// {
157// string createUsers = defineTable(createRegionsTable());
158// SQLiteCommand pcmd = new SQLiteCommand(createUsers, conn);
159// conn.Open();
160// pcmd.ExecuteNonQuery();
161// conn.Close();
162// }
163
164 /// <summary>
165 /// Reads a region row from a database reader
166 /// </summary>
167 /// <param name="reader">An active database reader</param>
168 /// <returns>A region profile</returns>
169 public RegionProfileData getRow(IDataReader reader)
170 {
171 RegionProfileData retval = new RegionProfileData();
172
173 if (reader.Read())
174 {
175 // Region Main
176 retval.regionHandle = (ulong) reader["regionHandle"];
177 retval.regionName = (string) reader["regionName"];
178 retval.UUID = new LLUUID((string) reader["uuid"]);
179
180 // Secrets
181 retval.regionRecvKey = (string) reader["regionRecvKey"];
182 retval.regionSecret = (string) reader["regionSecret"];
183 retval.regionSendKey = (string) reader["regionSendKey"];
184
185 // Region Server
186 retval.regionDataURI = (string) reader["regionDataURI"];
187 retval.regionOnline = false; // Needs to be pinged before this can be set.
188 retval.serverIP = (string) reader["serverIP"];
189 retval.serverPort = (uint) reader["serverPort"];
190 retval.serverURI = (string) reader["serverURI"];
191
192 // Location
193 retval.regionLocX = (uint) ((int) reader["locX"]);
194 retval.regionLocY = (uint) ((int) reader["locY"]);
195 retval.regionLocZ = (uint) ((int) reader["locZ"]);
196
197 // Neighbours - 0 = No Override
198 retval.regionEastOverrideHandle = (ulong) reader["eastOverrideHandle"];
199 retval.regionWestOverrideHandle = (ulong) reader["westOverrideHandle"];
200 retval.regionSouthOverrideHandle = (ulong) reader["southOverrideHandle"];
201 retval.regionNorthOverrideHandle = (ulong) reader["northOverrideHandle"];
202
203 // Assets
204 retval.regionAssetURI = (string) reader["regionAssetURI"];
205 retval.regionAssetRecvKey = (string) reader["regionAssetRecvKey"];
206 retval.regionAssetSendKey = (string) reader["regionAssetSendKey"];
207
208 // Userserver
209 retval.regionUserURI = (string) reader["regionUserURI"];
210 retval.regionUserRecvKey = (string) reader["regionUserRecvKey"];
211 retval.regionUserSendKey = (string) reader["regionUserSendKey"];
212 }
213 else
214 {
215 throw new Exception("No rows to return");
216 }
217 return retval;
218 }
219
220 /// <summary>
221 /// Inserts a new region into the database
222 /// </summary>
223 /// <param name="profile">The region to insert</param>
224 /// <returns>Success?</returns>
225 public bool insertRow(RegionProfileData profile)
226 {
227 string sql =
228 "REPLACE INTO regions VALUES (regionHandle, regionName, uuid, regionRecvKey, regionSecret, regionSendKey, regionDataURI, ";
229 sql +=
230 "serverIP, serverPort, serverURI, locX, locY, locZ, eastOverrideHandle, westOverrideHandle, southOverrideHandle, northOverrideHandle, regionAssetURI, regionAssetRecvKey, ";
231 sql += "regionAssetSendKey, regionUserURI, regionUserRecvKey, regionUserSendKey) VALUES ";
232
233 sql += "(@regionHandle, @regionName, @uuid, @regionRecvKey, @regionSecret, @regionSendKey, @regionDataURI, ";
234 sql +=
235 "@serverIP, @serverPort, @serverURI, @locX, @locY, @locZ, @eastOverrideHandle, @westOverrideHandle, @southOverrideHandle, @northOverrideHandle, @regionAssetURI, @regionAssetRecvKey, ";
236 sql += "@regionAssetSendKey, @regionUserURI, @regionUserRecvKey, @regionUserSendKey);";
237
238 Dictionary<string, string> parameters = new Dictionary<string, string>();
239
240 parameters["regionHandle"] = profile.regionHandle.ToString();
241 parameters["regionName"] = profile.regionName;
242 parameters["uuid"] = profile.UUID.ToString();
243 parameters["regionRecvKey"] = profile.regionRecvKey;
244 parameters["regionSendKey"] = profile.regionSendKey;
245 parameters["regionDataURI"] = profile.regionDataURI;
246 parameters["serverIP"] = profile.serverIP;
247 parameters["serverPort"] = profile.serverPort.ToString();
248 parameters["serverURI"] = profile.serverURI;
249 parameters["locX"] = profile.regionLocX.ToString();
250 parameters["locY"] = profile.regionLocY.ToString();
251 parameters["locZ"] = profile.regionLocZ.ToString();
252 parameters["eastOverrideHandle"] = profile.regionEastOverrideHandle.ToString();
253 parameters["westOverrideHandle"] = profile.regionWestOverrideHandle.ToString();
254 parameters["northOverrideHandle"] = profile.regionNorthOverrideHandle.ToString();
255 parameters["southOverrideHandle"] = profile.regionSouthOverrideHandle.ToString();
256 parameters["regionAssetURI"] = profile.regionAssetURI;
257 parameters["regionAssetRecvKey"] = profile.regionAssetRecvKey;
258 parameters["regionAssetSendKey"] = profile.regionAssetSendKey;
259 parameters["regionUserURI"] = profile.regionUserURI;
260 parameters["regionUserRecvKey"] = profile.regionUserRecvKey;
261 parameters["regionUserSendKey"] = profile.regionUserSendKey;
262
263 bool returnval = false;
264
265 try
266 {
267 IDbCommand result = Query(sql, parameters);
268
269 if (result.ExecuteNonQuery() == 1)
270 returnval = true;
271
272 result.Dispose();
273 }
274 catch (Exception)
275 {
276 return false;
277 }
278
279 return returnval;
280 }
281 }
282}
diff --git a/OpenSim/Data/SQLite/SQLiteRegionData.cs b/OpenSim/Data/SQLite/SQLiteRegionData.cs
new file mode 100644
index 0000000..77161a4
--- /dev/null
+++ b/OpenSim/Data/SQLite/SQLiteRegionData.cs
@@ -0,0 +1,1741 @@
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 OpenSim 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.IO;
32using libsecondlife;
33using Mono.Data.SqliteClient;
34using OpenSim.Framework;
35using OpenSim.Framework.Console;
36using OpenSim.Region.Environment.Interfaces;
37using OpenSim.Region.Environment.Scenes;
38
39namespace OpenSim.Framework.Data.SQLite
40{
41 public class SQLiteRegionData : IRegionDataStore
42 {
43 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
44
45 private const string primSelect = "select * from prims";
46 private const string shapeSelect = "select * from primshapes";
47 private const string itemsSelect = "select * from primitems";
48 private const string terrainSelect = "select * from terrain limit 1";
49 private const string landSelect = "select * from land";
50 private const string landAccessListSelect = "select distinct * from landaccesslist";
51
52 private DataSet ds;
53 private SqliteDataAdapter primDa;
54 private SqliteDataAdapter shapeDa;
55 private SqliteDataAdapter itemsDa;
56 private SqliteDataAdapter terrainDa;
57 private SqliteDataAdapter landDa;
58 private SqliteDataAdapter landAccessListDa;
59
60 private SqliteConnection m_conn;
61
62 private String m_connectionString;
63
64 // Temporary attribute while this is experimental
65 private bool persistPrimInventories;
66
67 /***********************************************************************
68 *
69 * Public Interface Functions
70 *
71 **********************************************************************/
72
73 // see IRegionDataStore
74 public void Initialise(string connectionString, bool persistPrimInventories)
75 {
76 m_connectionString = connectionString;
77 this.persistPrimInventories = persistPrimInventories;
78
79 ds = new DataSet();
80
81 m_log.Info("[DATASTORE]: Sqlite - connecting: " + connectionString);
82 m_conn = new SqliteConnection(m_connectionString);
83 m_conn.Open();
84
85 SqliteCommand primSelectCmd = new SqliteCommand(primSelect, m_conn);
86 primDa = new SqliteDataAdapter(primSelectCmd);
87 // SqliteCommandBuilder primCb = new SqliteCommandBuilder(primDa);
88
89 SqliteCommand shapeSelectCmd = new SqliteCommand(shapeSelect, m_conn);
90 shapeDa = new SqliteDataAdapter(shapeSelectCmd);
91 // SqliteCommandBuilder shapeCb = new SqliteCommandBuilder(shapeDa);
92
93 SqliteCommand itemsSelectCmd = new SqliteCommand(itemsSelect, m_conn);
94 itemsDa = new SqliteDataAdapter(itemsSelectCmd);
95
96 SqliteCommand terrainSelectCmd = new SqliteCommand(terrainSelect, m_conn);
97 terrainDa = new SqliteDataAdapter(terrainSelectCmd);
98
99 SqliteCommand landSelectCmd = new SqliteCommand(landSelect, m_conn);
100 landDa = new SqliteDataAdapter(landSelectCmd);
101
102 SqliteCommand landAccessListSelectCmd = new SqliteCommand(landAccessListSelect, m_conn);
103 landAccessListDa = new SqliteDataAdapter(landAccessListSelectCmd);
104
105 // We fill the data set, now we've got copies in memory for the information
106 // TODO: see if the linkage actually holds.
107 // primDa.FillSchema(ds, SchemaType.Source, "PrimSchema");
108 TestTables(m_conn);
109
110 lock (ds)
111 {
112 ds.Tables.Add(createPrimTable());
113 setupPrimCommands(primDa, m_conn);
114 primDa.Fill(ds.Tables["prims"]);
115
116 ds.Tables.Add(createShapeTable());
117 setupShapeCommands(shapeDa, m_conn);
118
119 if (persistPrimInventories)
120 {
121 ds.Tables.Add(createItemsTable());
122 setupItemsCommands(itemsDa, m_conn);
123 itemsDa.Fill(ds.Tables["primitems"]);
124 }
125
126 ds.Tables.Add(createTerrainTable());
127 setupTerrainCommands(terrainDa, m_conn);
128
129 ds.Tables.Add(createLandTable());
130 setupLandCommands(landDa, m_conn);
131
132 ds.Tables.Add(createLandAccessListTable());
133 setupLandAccessCommands(landAccessListDa, m_conn);
134
135 // WORKAROUND: This is a work around for sqlite on
136 // windows, which gets really unhappy with blob columns
137 // that have no sample data in them. At some point we
138 // need to actually find a proper way to handle this.
139 try
140 {
141 shapeDa.Fill(ds.Tables["primshapes"]);
142 }
143 catch (Exception)
144 {
145 m_log.Info("[DATASTORE]: Caught fill error on primshapes table");
146 }
147
148 try
149 {
150 terrainDa.Fill(ds.Tables["terrain"]);
151 }
152 catch (Exception)
153 {
154 m_log.Info("[DATASTORE]: Caught fill error on terrain table");
155 }
156
157 try
158 {
159 landDa.Fill(ds.Tables["land"]);
160 }
161 catch (Exception)
162 {
163 m_log.Info("[DATASTORE]: Caught fill error on land table");
164 }
165
166 try
167 {
168 landAccessListDa.Fill(ds.Tables["landaccesslist"]);
169 }
170 catch (Exception)
171 {
172 m_log.Info("[DATASTORE]: Caught fill error on landaccesslist table");
173 }
174 return;
175 }
176 }
177
178 public void StoreObject(SceneObjectGroup obj, LLUUID regionUUID)
179 {
180 lock (ds)
181 {
182 foreach (SceneObjectPart prim in obj.Children.Values)
183 {
184 if ((prim.ObjectFlags & (uint) LLObject.ObjectFlags.Physics) == 0)
185 {
186 m_log.Info("[DATASTORE]: Adding obj: " + obj.UUID + " to region: " + regionUUID);
187 addPrim(prim, Util.ToRawUuidString(obj.UUID), Util.ToRawUuidString(regionUUID));
188 }
189 else if (prim.Stopped)
190 {
191 //m_log.Info("[DATASTORE]: " +
192 //"Adding stopped obj: " + obj.UUID + " to region: " + regionUUID);
193 //addPrim(prim, Util.ToRawUuidString(obj.UUID), Util.ToRawUuidString(regionUUID));
194 }
195 else
196 {
197 // m_log.Info("[DATASTORE]: Ignoring Physical obj: " + obj.UUID + " in region: " + regionUUID);
198 }
199 }
200 }
201
202 Commit();
203 // m_log.Info("[Dump of prims]: " + ds.GetXml());
204 }
205
206 public void RemoveObject(LLUUID obj, LLUUID regionUUID)
207 {
208 m_log.InfoFormat("[DATASTORE]: Removing obj: {0} from region: {1}", obj.UUID, regionUUID);
209
210 DataTable prims = ds.Tables["prims"];
211 DataTable shapes = ds.Tables["primshapes"];
212
213 string selectExp = "SceneGroupID = '" + Util.ToRawUuidString(obj) + "'";
214 lock (ds)
215 {
216 DataRow[] primRows = prims.Select(selectExp);
217 foreach (DataRow row in primRows)
218 {
219 // Remove shape rows
220 LLUUID uuid = new LLUUID((string) row["UUID"]);
221 DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(uuid));
222 if (shapeRow != null)
223 {
224 shapeRow.Delete();
225 }
226
227 if (persistPrimInventories)
228 {
229 RemoveItems(uuid);
230 }
231
232 // Remove prim row
233 row.Delete();
234 }
235 }
236
237 Commit();
238 }
239
240 /// <summary>
241 /// Remove all persisted items of the given prim.
242 /// The caller must acquire the necessrary synchronization locks and commit or rollback changes.
243 /// </summary>
244 private void RemoveItems(LLUUID uuid)
245 {
246 DataTable items = ds.Tables["primitems"];
247
248 String sql = String.Format("primID = '{0}'", uuid);
249 DataRow[] itemRows = items.Select(sql);
250
251 foreach (DataRow itemRow in itemRows)
252 {
253 itemRow.Delete();
254 }
255 }
256
257 /// <summary>
258 /// Load persisted objects from region storage.
259 /// </summary>
260 /// <param name="regionUUID"></param>
261 /// <returns>List of loaded groups</returns>
262 public List<SceneObjectGroup> LoadObjects(LLUUID regionUUID)
263 {
264 Dictionary<LLUUID, SceneObjectGroup> createdObjects = new Dictionary<LLUUID, SceneObjectGroup>();
265
266 List<SceneObjectGroup> retvals = new List<SceneObjectGroup>();
267
268 DataTable prims = ds.Tables["prims"];
269 DataTable shapes = ds.Tables["primshapes"];
270
271 string byRegion = "RegionUUID = '" + Util.ToRawUuidString(regionUUID) + "'";
272 string orderByParent = "ParentID ASC";
273
274 lock (ds)
275 {
276 DataRow[] primsForRegion = prims.Select(byRegion, orderByParent);
277 m_log.Info("[DATASTORE]: " +
278 "Loaded " + primsForRegion.Length + " prims for region: " + regionUUID);
279
280 foreach (DataRow primRow in primsForRegion)
281 {
282 try
283 {
284 SceneObjectPart prim = null;
285
286 string uuid = (string) primRow["UUID"];
287 string objID = (string) primRow["SceneGroupID"];
288 if (uuid == objID) //is new SceneObjectGroup ?
289 {
290 SceneObjectGroup group = new SceneObjectGroup();
291 prim = buildPrim(primRow);
292 DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID));
293 if (shapeRow != null)
294 {
295 prim.Shape = buildShape(shapeRow);
296 }
297 else
298 {
299 m_log.Info(
300 "No shape found for prim in storage, so setting default box shape");
301 prim.Shape = PrimitiveBaseShape.Default;
302 }
303 group.AddPart(prim);
304 group.RootPart = prim;
305
306 createdObjects.Add(Util.ToRawUuidString(group.UUID), group);
307 retvals.Add(group);
308 }
309 else
310 {
311 prim = buildPrim(primRow);
312 DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID));
313 if (shapeRow != null)
314 {
315 prim.Shape = buildShape(shapeRow);
316 }
317 else
318 {
319 m_log.Info(
320 "No shape found for prim in storage, so setting default box shape");
321 prim.Shape = PrimitiveBaseShape.Default;
322 }
323 createdObjects[new LLUUID(objID)].AddPart(prim);
324 }
325
326 if (persistPrimInventories)
327 {
328 LoadItems(prim);
329 }
330 }
331 catch (Exception e)
332 {
333 m_log.Error("[DATASTORE]: Failed create prim object, exception and data follows");
334 m_log.Info("[DATASTORE]: " + e.ToString());
335 foreach (DataColumn col in prims.Columns)
336 {
337 m_log.Info("[DATASTORE]: Col: " + col.ColumnName + " => " + primRow[col]);
338 }
339 }
340 }
341 }
342 return retvals;
343 }
344
345 /// <summary>
346 /// Load in a prim's persisted inventory.
347 /// </summary>
348 /// <param name="prim"></param>
349 private void LoadItems(SceneObjectPart prim)
350 {
351 //m_log.DebugFormat("[DATASTORE]: Loading inventory for {0}, {1}", prim.Name, prim.UUID);
352
353 DataTable dbItems = ds.Tables["primitems"];
354
355 String sql = String.Format("primID = '{0}'", prim.UUID.ToString());
356 DataRow[] dbItemRows = dbItems.Select(sql);
357
358 IList<TaskInventoryItem> inventory = new List<TaskInventoryItem>();
359
360 foreach (DataRow row in dbItemRows)
361 {
362 TaskInventoryItem item = buildItem(row);
363 inventory.Add(item);
364
365 //m_log.DebugFormat("[DATASTORE]: Restored item {0}, {1}", item.Name, item.ItemID);
366 }
367
368 prim.RestoreInventoryItems(inventory);
369
370 // XXX A nasty little hack to recover the folder id for the prim (which is currently stored in
371 // every item). This data should really be stored in the prim table itself.
372 if (dbItemRows.Length > 0)
373 {
374 prim.FolderID = inventory[0].ParentID;
375 }
376 }
377
378 public void StoreTerrain(double[,] ter, LLUUID regionID)
379 {
380 lock (ds)
381 {
382 int revision = Util.UnixTimeSinceEpoch();
383
384 // the following is an work around for .NET. The perf
385 // issues associated with it aren't as bad as you think.
386 m_log.Info("[DATASTORE]: Storing terrain revision r" + revision.ToString());
387 String sql = "insert into terrain(RegionUUID, Revision, Heightfield)" +
388 " values(:RegionUUID, :Revision, :Heightfield)";
389
390 using (SqliteCommand cmd = new SqliteCommand(sql, m_conn))
391 {
392 cmd.Parameters.Add(new SqliteParameter(":RegionUUID", Util.ToRawUuidString(regionID)));
393 cmd.Parameters.Add(new SqliteParameter(":Revision", revision));
394 cmd.Parameters.Add(new SqliteParameter(":Heightfield", serializeTerrain(ter)));
395 cmd.ExecuteNonQuery();
396 }
397
398 // This is added to get rid of the infinitely growing
399 // terrain databases which negatively impact on SQLite
400 // over time. Before reenabling this feature there
401 // needs to be a limitter put on the number of
402 // revisions in the database, as this old
403 // implementation is a DOS attack waiting to happen.
404
405 using (
406 SqliteCommand cmd =
407 new SqliteCommand("delete from terrain where RegionUUID=:RegionUUID and Revision < :Revision",
408 m_conn))
409 {
410 cmd.Parameters.Add(new SqliteParameter(":RegionUUID", Util.ToRawUuidString(regionID)));
411 cmd.Parameters.Add(new SqliteParameter(":Revision", revision));
412 cmd.ExecuteNonQuery();
413 }
414 }
415 }
416
417 public double[,] LoadTerrain(LLUUID regionID)
418 {
419 lock (ds)
420 {
421 double[,] terret = new double[256,256];
422 terret.Initialize();
423
424 String sql = "select RegionUUID, Revision, Heightfield from terrain" +
425 " where RegionUUID=:RegionUUID order by Revision desc";
426
427 using (SqliteCommand cmd = new SqliteCommand(sql, m_conn))
428 {
429 cmd.Parameters.Add(new SqliteParameter(":RegionUUID", Util.ToRawUuidString(regionID)));
430
431 using (IDataReader row = cmd.ExecuteReader())
432 {
433 int rev = 0;
434 if (row.Read())
435 {
436 // TODO: put this into a function
437 MemoryStream str = new MemoryStream((byte[]) row["Heightfield"]);
438 BinaryReader br = new BinaryReader(str);
439 for (int x = 0; x < 256; x++)
440 {
441 for (int y = 0; y < 256; y++)
442 {
443 terret[x, y] = br.ReadDouble();
444 }
445 }
446 rev = (int) row["Revision"];
447 }
448 else
449 {
450 m_log.Info("[DATASTORE]: No terrain found for region");
451 return null;
452 }
453
454 m_log.Info("[DATASTORE]: Loaded terrain revision r" + rev.ToString());
455 }
456 }
457 return terret;
458 }
459 }
460
461 public void RemoveLandObject(LLUUID globalID)
462 {
463 lock (ds)
464 {
465 using (SqliteCommand cmd = new SqliteCommand("delete from land where UUID=:UUID", m_conn))
466 {
467 cmd.Parameters.Add(new SqliteParameter(":UUID", Util.ToRawUuidString(globalID)));
468 cmd.ExecuteNonQuery();
469 }
470
471 using (SqliteCommand cmd = new SqliteCommand("delete from landaccesslist where LandUUID=:UUID", m_conn))
472 {
473 cmd.Parameters.Add(new SqliteParameter(":UUID", Util.ToRawUuidString(globalID)));
474 cmd.ExecuteNonQuery();
475 }
476 }
477 }
478
479 public void StoreLandObject(ILandObject parcel)
480 {
481 lock (ds)
482 {
483 DataTable land = ds.Tables["land"];
484 DataTable landaccesslist = ds.Tables["landaccesslist"];
485
486 DataRow landRow = land.Rows.Find(Util.ToRawUuidString(parcel.landData.globalID));
487 if (landRow == null)
488 {
489 landRow = land.NewRow();
490 fillLandRow(landRow, parcel.landData, parcel.regionUUID);
491 land.Rows.Add(landRow);
492 }
493 else
494 {
495 fillLandRow(landRow, parcel.landData, parcel.regionUUID);
496 }
497
498 // I know this caused someone issues before, but OpenSim is unusable if we leave this stuff around
499 using (SqliteCommand cmd = new SqliteCommand("delete from landaccesslist where LandUUID=:LandUUID", m_conn))
500 {
501 cmd.Parameters.Add(new SqliteParameter(":LandUUID", Util.ToRawUuidString(parcel.landData.globalID)));
502 cmd.ExecuteNonQuery();
503 }
504
505 foreach (ParcelManager.ParcelAccessEntry entry in parcel.landData.parcelAccessList)
506 {
507 DataRow newAccessRow = landaccesslist.NewRow();
508 fillLandAccessRow(newAccessRow, entry, parcel.landData.globalID);
509 landaccesslist.Rows.Add(newAccessRow);
510 }
511 }
512
513 Commit();
514 }
515
516 public List<LandData> LoadLandObjects(LLUUID regionUUID)
517 {
518 List<LandData> landDataForRegion = new List<LandData>();
519 lock (ds)
520 {
521 DataTable land = ds.Tables["land"];
522 DataTable landaccesslist = ds.Tables["landaccesslist"];
523 string searchExp = "RegionUUID = '" + Util.ToRawUuidString(regionUUID) + "'";
524 DataRow[] rawDataForRegion = land.Select(searchExp);
525 foreach (DataRow rawDataLand in rawDataForRegion)
526 {
527 LandData newLand = buildLandData(rawDataLand);
528 string accessListSearchExp = "LandUUID = '" + Util.ToRawUuidString(newLand.globalID) + "'";
529 DataRow[] rawDataForLandAccessList = landaccesslist.Select(accessListSearchExp);
530 foreach (DataRow rawDataLandAccess in rawDataForLandAccessList)
531 {
532 newLand.parcelAccessList.Add(buildLandAccessData(rawDataLandAccess));
533 }
534
535 landDataForRegion.Add(newLand);
536 }
537 }
538 return landDataForRegion;
539 }
540
541 public void Commit()
542 {
543 lock (ds)
544 {
545 primDa.Update(ds, "prims");
546 shapeDa.Update(ds, "primshapes");
547
548 if (persistPrimInventories)
549 {
550 itemsDa.Update(ds, "primitems");
551 }
552
553 terrainDa.Update(ds, "terrain");
554 landDa.Update(ds, "land");
555 landAccessListDa.Update(ds, "landaccesslist");
556 ds.AcceptChanges();
557 }
558 }
559
560 public void Shutdown()
561 {
562 Commit();
563 }
564
565 /***********************************************************************
566 *
567 * Database Definition Functions
568 *
569 * This should be db agnostic as we define them in ADO.NET terms
570 *
571 **********************************************************************/
572
573 private void createCol(DataTable dt, string name, Type type)
574 {
575 DataColumn col = new DataColumn(name, type);
576 dt.Columns.Add(col);
577 }
578
579 private DataTable createTerrainTable()
580 {
581 DataTable terrain = new DataTable("terrain");
582
583 createCol(terrain, "RegionUUID", typeof (String));
584 createCol(terrain, "Revision", typeof (Int32));
585 createCol(terrain, "Heightfield", typeof (Byte[]));
586
587 return terrain;
588 }
589
590 private DataTable createPrimTable()
591 {
592 DataTable prims = new DataTable("prims");
593
594 createCol(prims, "UUID", typeof (String));
595 createCol(prims, "RegionUUID", typeof (String));
596 createCol(prims, "ParentID", typeof (Int32));
597 createCol(prims, "CreationDate", typeof (Int32));
598 createCol(prims, "Name", typeof (String));
599 createCol(prims, "SceneGroupID", typeof (String));
600 // various text fields
601 createCol(prims, "Text", typeof (String));
602 createCol(prims, "Description", typeof (String));
603 createCol(prims, "SitName", typeof (String));
604 createCol(prims, "TouchName", typeof (String));
605 // permissions
606 createCol(prims, "ObjectFlags", typeof (Int32));
607 createCol(prims, "CreatorID", typeof (String));
608 createCol(prims, "OwnerID", typeof (String));
609 createCol(prims, "GroupID", typeof (String));
610 createCol(prims, "LastOwnerID", typeof (String));
611 createCol(prims, "OwnerMask", typeof (Int32));
612 createCol(prims, "NextOwnerMask", typeof (Int32));
613 createCol(prims, "GroupMask", typeof (Int32));
614 createCol(prims, "EveryoneMask", typeof (Int32));
615 createCol(prims, "BaseMask", typeof (Int32));
616 // vectors
617 createCol(prims, "PositionX", typeof (Double));
618 createCol(prims, "PositionY", typeof (Double));
619 createCol(prims, "PositionZ", typeof (Double));
620 createCol(prims, "GroupPositionX", typeof (Double));
621 createCol(prims, "GroupPositionY", typeof (Double));
622 createCol(prims, "GroupPositionZ", typeof (Double));
623 createCol(prims, "VelocityX", typeof (Double));
624 createCol(prims, "VelocityY", typeof (Double));
625 createCol(prims, "VelocityZ", typeof (Double));
626 createCol(prims, "AngularVelocityX", typeof (Double));
627 createCol(prims, "AngularVelocityY", typeof (Double));
628 createCol(prims, "AngularVelocityZ", typeof (Double));
629 createCol(prims, "AccelerationX", typeof (Double));
630 createCol(prims, "AccelerationY", typeof (Double));
631 createCol(prims, "AccelerationZ", typeof (Double));
632 // quaternions
633 createCol(prims, "RotationX", typeof (Double));
634 createCol(prims, "RotationY", typeof (Double));
635 createCol(prims, "RotationZ", typeof (Double));
636 createCol(prims, "RotationW", typeof (Double));
637
638 // sit target
639 createCol(prims, "SitTargetOffsetX", typeof (Double));
640 createCol(prims, "SitTargetOffsetY", typeof (Double));
641 createCol(prims, "SitTargetOffsetZ", typeof (Double));
642
643 createCol(prims, "SitTargetOrientW", typeof (Double));
644 createCol(prims, "SitTargetOrientX", typeof (Double));
645 createCol(prims, "SitTargetOrientY", typeof (Double));
646 createCol(prims, "SitTargetOrientZ", typeof (Double));
647
648 // Add in contraints
649 prims.PrimaryKey = new DataColumn[] {prims.Columns["UUID"]};
650
651 return prims;
652 }
653
654 private DataTable createShapeTable()
655 {
656 DataTable shapes = new DataTable("primshapes");
657 createCol(shapes, "UUID", typeof (String));
658 // shape is an enum
659 createCol(shapes, "Shape", typeof (Int32));
660 // vectors
661 createCol(shapes, "ScaleX", typeof (Double));
662 createCol(shapes, "ScaleY", typeof (Double));
663 createCol(shapes, "ScaleZ", typeof (Double));
664 // paths
665 createCol(shapes, "PCode", typeof (Int32));
666 createCol(shapes, "PathBegin", typeof (Int32));
667 createCol(shapes, "PathEnd", typeof (Int32));
668 createCol(shapes, "PathScaleX", typeof (Int32));
669 createCol(shapes, "PathScaleY", typeof (Int32));
670 createCol(shapes, "PathShearX", typeof (Int32));
671 createCol(shapes, "PathShearY", typeof (Int32));
672 createCol(shapes, "PathSkew", typeof (Int32));
673 createCol(shapes, "PathCurve", typeof (Int32));
674 createCol(shapes, "PathRadiusOffset", typeof (Int32));
675 createCol(shapes, "PathRevolutions", typeof (Int32));
676 createCol(shapes, "PathTaperX", typeof (Int32));
677 createCol(shapes, "PathTaperY", typeof (Int32));
678 createCol(shapes, "PathTwist", typeof (Int32));
679 createCol(shapes, "PathTwistBegin", typeof (Int32));
680 // profile
681 createCol(shapes, "ProfileBegin", typeof (Int32));
682 createCol(shapes, "ProfileEnd", typeof (Int32));
683 createCol(shapes, "ProfileCurve", typeof (Int32));
684 createCol(shapes, "ProfileHollow", typeof (Int32));
685 createCol(shapes, "State", typeof(Int32));
686 // text TODO: this isn't right, but I'm not sure the right
687 // way to specify this as a blob atm
688 createCol(shapes, "Texture", typeof (Byte[]));
689 createCol(shapes, "ExtraParams", typeof (Byte[]));
690
691 shapes.PrimaryKey = new DataColumn[] {shapes.Columns["UUID"]};
692
693 return shapes;
694 }
695
696 private DataTable createItemsTable()
697 {
698 DataTable items = new DataTable("primitems");
699
700 createCol(items, "itemID", typeof (String));
701 createCol(items, "primID", typeof (String));
702 createCol(items, "assetID", typeof (String));
703 createCol(items, "parentFolderID", typeof (String));
704
705 createCol(items, "invType", typeof (Int32));
706 createCol(items, "assetType", typeof (Int32));
707
708 createCol(items, "name", typeof (String));
709 createCol(items, "description", typeof (String));
710
711 createCol(items, "creationDate", typeof (Int64));
712 createCol(items, "creatorID", typeof (String));
713 createCol(items, "ownerID", typeof (String));
714 createCol(items, "lastOwnerID", typeof (String));
715 createCol(items, "groupID", typeof (String));
716
717 createCol(items, "nextPermissions", typeof (UInt32));
718 createCol(items, "currentPermissions", typeof (UInt32));
719 createCol(items, "basePermissions", typeof (UInt32));
720 createCol(items, "everyonePermissions", typeof (UInt32));
721 createCol(items, "groupPermissions", typeof (UInt32));
722
723 items.PrimaryKey = new DataColumn[] {items.Columns["itemID"]};
724
725 return items;
726 }
727
728 private DataTable createLandTable()
729 {
730 DataTable land = new DataTable("land");
731 createCol(land, "UUID", typeof (String));
732 createCol(land, "RegionUUID", typeof (String));
733 createCol(land, "LocalLandID", typeof (UInt32));
734
735 // Bitmap is a byte[512]
736 createCol(land, "Bitmap", typeof (Byte[]));
737
738 createCol(land, "Name", typeof (String));
739 createCol(land, "Desc", typeof (String));
740 createCol(land, "OwnerUUID", typeof (String));
741 createCol(land, "IsGroupOwned", typeof (Boolean));
742 createCol(land, "Area", typeof (Int32));
743 createCol(land, "AuctionID", typeof (Int32)); //Unemplemented
744 createCol(land, "Category", typeof (Int32)); //Enum libsecondlife.Parcel.ParcelCategory
745 createCol(land, "ClaimDate", typeof (Int32));
746 createCol(land, "ClaimPrice", typeof (Int32));
747 createCol(land, "GroupUUID", typeof (string));
748 createCol(land, "SalePrice", typeof (Int32));
749 createCol(land, "LandStatus", typeof (Int32)); //Enum. libsecondlife.Parcel.ParcelStatus
750 createCol(land, "LandFlags", typeof (UInt32));
751 createCol(land, "LandingType", typeof (Byte));
752 createCol(land, "MediaAutoScale", typeof (Byte));
753 createCol(land, "MediaTextureUUID", typeof (String));
754 createCol(land, "MediaURL", typeof (String));
755 createCol(land, "MusicURL", typeof (String));
756 createCol(land, "PassHours", typeof (Double));
757 createCol(land, "PassPrice", typeof (UInt32));
758 createCol(land, "SnapshotUUID", typeof (String));
759 createCol(land, "UserLocationX", typeof (Double));
760 createCol(land, "UserLocationY", typeof (Double));
761 createCol(land, "UserLocationZ", typeof (Double));
762 createCol(land, "UserLookAtX", typeof (Double));
763 createCol(land, "UserLookAtY", typeof (Double));
764 createCol(land, "UserLookAtZ", typeof (Double));
765
766 land.PrimaryKey = new DataColumn[] {land.Columns["UUID"]};
767
768 return land;
769 }
770
771 private DataTable createLandAccessListTable()
772 {
773 DataTable landaccess = new DataTable("landaccesslist");
774 createCol(landaccess, "LandUUID", typeof (String));
775 createCol(landaccess, "AccessUUID", typeof (String));
776 createCol(landaccess, "Flags", typeof (UInt32));
777
778 return landaccess;
779 }
780
781 /***********************************************************************
782 *
783 * Convert between ADO.NET <=> OpenSim Objects
784 *
785 * These should be database independant
786 *
787 **********************************************************************/
788
789 private SceneObjectPart buildPrim(DataRow row)
790 {
791 // TODO: this doesn't work yet because something more
792 // interesting has to be done to actually get these values
793 // back out. Not enough time to figure it out yet.
794 SceneObjectPart prim = new SceneObjectPart();
795 prim.UUID = new LLUUID((String) row["UUID"]);
796 // explicit conversion of integers is required, which sort
797 // of sucks. No idea if there is a shortcut here or not.
798 prim.ParentID = Convert.ToUInt32(row["ParentID"]);
799 prim.CreationDate = Convert.ToInt32(row["CreationDate"]);
800 prim.Name = (String) row["Name"];
801 // various text fields
802 prim.Text = (String) row["Text"];
803 prim.Description = (String) row["Description"];
804 prim.SitName = (String) row["SitName"];
805 prim.TouchName = (String) row["TouchName"];
806 // permissions
807 prim.ObjectFlags = Convert.ToUInt32(row["ObjectFlags"]);
808 prim.CreatorID = new LLUUID((String) row["CreatorID"]);
809 prim.OwnerID = new LLUUID((String) row["OwnerID"]);
810 prim.GroupID = new LLUUID((String) row["GroupID"]);
811 prim.LastOwnerID = new LLUUID((String) row["LastOwnerID"]);
812 prim.OwnerMask = Convert.ToUInt32(row["OwnerMask"]);
813 prim.NextOwnerMask = Convert.ToUInt32(row["NextOwnerMask"]);
814 prim.GroupMask = Convert.ToUInt32(row["GroupMask"]);
815 prim.EveryoneMask = Convert.ToUInt32(row["EveryoneMask"]);
816 prim.BaseMask = Convert.ToUInt32(row["BaseMask"]);
817 // vectors
818 prim.OffsetPosition = new LLVector3(
819 Convert.ToSingle(row["PositionX"]),
820 Convert.ToSingle(row["PositionY"]),
821 Convert.ToSingle(row["PositionZ"])
822 );
823 prim.GroupPosition = new LLVector3(
824 Convert.ToSingle(row["GroupPositionX"]),
825 Convert.ToSingle(row["GroupPositionY"]),
826 Convert.ToSingle(row["GroupPositionZ"])
827 );
828 prim.Velocity = new LLVector3(
829 Convert.ToSingle(row["VelocityX"]),
830 Convert.ToSingle(row["VelocityY"]),
831 Convert.ToSingle(row["VelocityZ"])
832 );
833 prim.AngularVelocity = new LLVector3(
834 Convert.ToSingle(row["AngularVelocityX"]),
835 Convert.ToSingle(row["AngularVelocityY"]),
836 Convert.ToSingle(row["AngularVelocityZ"])
837 );
838 prim.Acceleration = new LLVector3(
839 Convert.ToSingle(row["AccelerationX"]),
840 Convert.ToSingle(row["AccelerationY"]),
841 Convert.ToSingle(row["AccelerationZ"])
842 );
843 // quaternions
844 prim.RotationOffset = new LLQuaternion(
845 Convert.ToSingle(row["RotationX"]),
846 Convert.ToSingle(row["RotationY"]),
847 Convert.ToSingle(row["RotationZ"]),
848 Convert.ToSingle(row["RotationW"])
849 );
850
851 try
852 {
853 prim.SetSitTargetLL(new LLVector3(
854 Convert.ToSingle(row["SitTargetOffsetX"]),
855 Convert.ToSingle(row["SitTargetOffsetY"]),
856 Convert.ToSingle(row["SitTargetOffsetZ"])), new LLQuaternion(
857 Convert.ToSingle(
858 row["SitTargetOrientX"]),
859 Convert.ToSingle(
860 row["SitTargetOrientY"]),
861 Convert.ToSingle(
862 row["SitTargetOrientZ"]),
863 Convert.ToSingle(
864 row["SitTargetOrientW"])));
865 }
866 catch (InvalidCastException)
867 {
868 // Database table was created before we got here and now has null values :P
869 m_conn.Open();
870 SqliteCommand cmd =
871 new SqliteCommand("ALTER TABLE prims ADD COLUMN SitTargetOffsetX float NOT NULL default 0;", m_conn);
872 cmd.ExecuteNonQuery();
873 cmd =
874 new SqliteCommand("ALTER TABLE prims ADD COLUMN SitTargetOffsetY float NOT NULL default 0;", m_conn);
875 cmd.ExecuteNonQuery();
876 cmd =
877 new SqliteCommand("ALTER TABLE prims ADD COLUMN SitTargetOffsetZ float NOT NULL default 0;", m_conn);
878 cmd.ExecuteNonQuery();
879 cmd =
880 new SqliteCommand("ALTER TABLE prims ADD COLUMN SitTargetOrientW float NOT NULL default 0;", m_conn);
881 cmd.ExecuteNonQuery();
882 cmd =
883 new SqliteCommand("ALTER TABLE prims ADD COLUMN SitTargetOrientX float NOT NULL default 0;", m_conn);
884 cmd.ExecuteNonQuery();
885 cmd =
886 new SqliteCommand("ALTER TABLE prims ADD COLUMN SitTargetOrientY float NOT NULL default 0;", m_conn);
887 cmd.ExecuteNonQuery();
888 cmd =
889 new SqliteCommand("ALTER TABLE prims ADD COLUMN SitTargetOrientZ float NOT NULL default 0;", m_conn);
890 cmd.ExecuteNonQuery();
891 }
892
893 return prim;
894 }
895
896 /// <summary>
897 /// Build a prim inventory item from the persisted data.
898 /// </summary>
899 /// <param name="row"></param>
900 /// <returns></returns>
901 private TaskInventoryItem buildItem(DataRow row)
902 {
903 TaskInventoryItem taskItem = new TaskInventoryItem();
904
905 taskItem.ItemID = new LLUUID((String)row["itemID"]);
906 taskItem.ParentPartID = new LLUUID((String)row["primID"]);
907 taskItem.AssetID = new LLUUID((String)row["assetID"]);
908 taskItem.ParentID = new LLUUID((String)row["parentFolderID"]);
909
910 taskItem.InvType = Convert.ToInt32(row["invType"]);
911 taskItem.Type = Convert.ToInt32(row["assetType"]);
912
913 taskItem.Name = (String)row["name"];
914 taskItem.Description = (String)row["description"];
915 taskItem.CreationDate = Convert.ToUInt32(row["creationDate"]);
916 taskItem.CreatorID = new LLUUID((String)row["creatorID"]);
917 taskItem.OwnerID = new LLUUID((String)row["ownerID"]);
918 taskItem.LastOwnerID = new LLUUID((String)row["lastOwnerID"]);
919 taskItem.GroupID = new LLUUID((String)row["groupID"]);
920
921 taskItem.NextOwnerMask = Convert.ToUInt32(row["nextPermissions"]);
922 taskItem.OwnerMask = Convert.ToUInt32(row["currentPermissions"]);
923 taskItem.BaseMask = Convert.ToUInt32(row["basePermissions"]);
924 taskItem.EveryoneMask = Convert.ToUInt32(row["everyonePermissions"]);
925 taskItem.GroupMask = Convert.ToUInt32(row["groupPermissions"]);
926
927 return taskItem;
928 }
929
930 private LandData buildLandData(DataRow row)
931 {
932 LandData newData = new LandData();
933
934 newData.globalID = new LLUUID((String) row["UUID"]);
935 newData.localID = Convert.ToInt32(row["LocalLandID"]);
936
937 // Bitmap is a byte[512]
938 newData.landBitmapByteArray = (Byte[]) row["Bitmap"];
939
940 newData.landName = (String) row["Name"];
941 newData.landDesc = (String) row["Desc"];
942 newData.ownerID = (String) row["OwnerUUID"];
943 newData.isGroupOwned = (Boolean) row["IsGroupOwned"];
944 newData.area = Convert.ToInt32(row["Area"]);
945 newData.auctionID = Convert.ToUInt32(row["AuctionID"]); //Unemplemented
946 newData.category = (Parcel.ParcelCategory) Convert.ToInt32(row["Category"]);
947 //Enum libsecondlife.Parcel.ParcelCategory
948 newData.claimDate = Convert.ToInt32(row["ClaimDate"]);
949 newData.claimPrice = Convert.ToInt32(row["ClaimPrice"]);
950 newData.groupID = new LLUUID((String) row["GroupUUID"]);
951 newData.salePrice = Convert.ToInt32(row["SalePrice"]);
952 newData.landStatus = (Parcel.ParcelStatus) Convert.ToInt32(row["LandStatus"]);
953 //Enum. libsecondlife.Parcel.ParcelStatus
954 newData.landFlags = Convert.ToUInt32(row["LandFlags"]);
955 newData.landingType = (Byte) row["LandingType"];
956 newData.mediaAutoScale = (Byte) row["MediaAutoScale"];
957 newData.mediaID = new LLUUID((String) row["MediaTextureUUID"]);
958 newData.mediaURL = (String) row["MediaURL"];
959 newData.musicURL = (String) row["MusicURL"];
960 newData.passHours = Convert.ToSingle(row["PassHours"]);
961 newData.passPrice = Convert.ToInt32(row["PassPrice"]);
962 newData.snapshotID = (String) row["SnapshotUUID"];
963
964 newData.userLocation =
965 new LLVector3(Convert.ToSingle(row["UserLocationX"]), Convert.ToSingle(row["UserLocationY"]),
966 Convert.ToSingle(row["UserLocationZ"]));
967 newData.userLookAt =
968 new LLVector3(Convert.ToSingle(row["UserLookAtX"]), Convert.ToSingle(row["UserLookAtY"]),
969 Convert.ToSingle(row["UserLookAtZ"]));
970 newData.parcelAccessList = new List<ParcelManager.ParcelAccessEntry>();
971
972 return newData;
973 }
974
975 private ParcelManager.ParcelAccessEntry buildLandAccessData(DataRow row)
976 {
977 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
978 entry.AgentID = new LLUUID((string) row["AccessUUID"]);
979 entry.Flags = (ParcelManager.AccessList) row["Flags"];
980 entry.Time = new DateTime();
981 return entry;
982 }
983
984 private Array serializeTerrain(double[,] val)
985 {
986 MemoryStream str = new MemoryStream(65536*sizeof (double));
987 BinaryWriter bw = new BinaryWriter(str);
988
989 // TODO: COMPATIBILITY - Add byte-order conversions
990 for (int x = 0; x < 256; x++)
991 for (int y = 0; y < 256; y++)
992 bw.Write(val[x, y]);
993
994 return str.ToArray();
995 }
996
997// private void fillTerrainRow(DataRow row, LLUUID regionUUID, int rev, double[,] val)
998// {
999// row["RegionUUID"] = regionUUID;
1000// row["Revision"] = rev;
1001
1002// MemoryStream str = new MemoryStream(65536*sizeof (double));
1003// BinaryWriter bw = new BinaryWriter(str);
1004
1005// // TODO: COMPATIBILITY - Add byte-order conversions
1006// for (int x = 0; x < 256; x++)
1007// for (int y = 0; y < 256; y++)
1008// bw.Write(val[x, y]);
1009
1010// row["Heightfield"] = str.ToArray();
1011// }
1012
1013 private void fillPrimRow(DataRow row, SceneObjectPart prim, LLUUID sceneGroupID, LLUUID regionUUID)
1014 {
1015 row["UUID"] = Util.ToRawUuidString(prim.UUID);
1016 row["RegionUUID"] = Util.ToRawUuidString(regionUUID);
1017 row["ParentID"] = prim.ParentID;
1018 row["CreationDate"] = prim.CreationDate;
1019 row["Name"] = prim.Name;
1020 row["SceneGroupID"] = Util.ToRawUuidString(sceneGroupID);
1021 // the UUID of the root part for this SceneObjectGroup
1022 // various text fields
1023 row["Text"] = prim.Text;
1024 row["Description"] = prim.Description;
1025 row["SitName"] = prim.SitName;
1026 row["TouchName"] = prim.TouchName;
1027 // permissions
1028 row["ObjectFlags"] = prim.ObjectFlags;
1029 row["CreatorID"] = Util.ToRawUuidString(prim.CreatorID);
1030 row["OwnerID"] = Util.ToRawUuidString(prim.OwnerID);
1031 row["GroupID"] = Util.ToRawUuidString(prim.GroupID);
1032 row["LastOwnerID"] = Util.ToRawUuidString(prim.LastOwnerID);
1033 row["OwnerMask"] = prim.OwnerMask;
1034 row["NextOwnerMask"] = prim.NextOwnerMask;
1035 row["GroupMask"] = prim.GroupMask;
1036 row["EveryoneMask"] = prim.EveryoneMask;
1037 row["BaseMask"] = prim.BaseMask;
1038 // vectors
1039 row["PositionX"] = prim.OffsetPosition.X;
1040 row["PositionY"] = prim.OffsetPosition.Y;
1041 row["PositionZ"] = prim.OffsetPosition.Z;
1042 row["GroupPositionX"] = prim.GroupPosition.X;
1043 row["GroupPositionY"] = prim.GroupPosition.Y;
1044 row["GroupPositionZ"] = prim.GroupPosition.Z;
1045 row["VelocityX"] = prim.Velocity.X;
1046 row["VelocityY"] = prim.Velocity.Y;
1047 row["VelocityZ"] = prim.Velocity.Z;
1048 row["AngularVelocityX"] = prim.AngularVelocity.X;
1049 row["AngularVelocityY"] = prim.AngularVelocity.Y;
1050 row["AngularVelocityZ"] = prim.AngularVelocity.Z;
1051 row["AccelerationX"] = prim.Acceleration.X;
1052 row["AccelerationY"] = prim.Acceleration.Y;
1053 row["AccelerationZ"] = prim.Acceleration.Z;
1054 // quaternions
1055 row["RotationX"] = prim.RotationOffset.X;
1056 row["RotationY"] = prim.RotationOffset.Y;
1057 row["RotationZ"] = prim.RotationOffset.Z;
1058 row["RotationW"] = prim.RotationOffset.W;
1059
1060 // Sit target
1061 LLVector3 sitTargetPos = prim.GetSitTargetPositionLL();
1062 row["SitTargetOffsetX"] = sitTargetPos.X;
1063 row["SitTargetOffsetY"] = sitTargetPos.Y;
1064 row["SitTargetOffsetZ"] = sitTargetPos.Z;
1065
1066 LLQuaternion sitTargetOrient = prim.GetSitTargetOrientationLL();
1067 row["SitTargetOrientW"] = sitTargetOrient.W;
1068 row["SitTargetOrientX"] = sitTargetOrient.X;
1069 row["SitTargetOrientY"] = sitTargetOrient.Y;
1070 row["SitTargetOrientZ"] = sitTargetOrient.Z;
1071 }
1072
1073 private void fillItemRow(DataRow row, TaskInventoryItem taskItem)
1074 {
1075 row["itemID"] = taskItem.ItemID;
1076 row["primID"] = taskItem.ParentPartID;
1077 row["assetID"] = taskItem.AssetID;
1078 row["parentFolderID"] = taskItem.ParentID;
1079
1080 row["invType"] = taskItem.InvType;
1081 row["assetType"] = taskItem.Type;
1082
1083 row["name"] = taskItem.Name;
1084 row["description"] = taskItem.Description;
1085 row["creationDate"] = taskItem.CreationDate;
1086 row["creatorID"] = taskItem.CreatorID;
1087 row["ownerID"] = taskItem.OwnerID;
1088 row["lastOwnerID"] = taskItem.LastOwnerID;
1089 row["groupID"] = taskItem.GroupID;
1090 row["nextPermissions"] = taskItem.NextOwnerMask;
1091 row["currentPermissions"] = taskItem.OwnerMask;
1092 row["basePermissions"] = taskItem.BaseMask;
1093 row["everyonePermissions"] = taskItem.EveryoneMask;
1094 row["groupPermissions"] = taskItem.GroupMask;
1095 }
1096
1097 private void fillLandRow(DataRow row, LandData land, LLUUID regionUUID)
1098 {
1099 row["UUID"] = Util.ToRawUuidString(land.globalID);
1100 row["RegionUUID"] = Util.ToRawUuidString(regionUUID);
1101 row["LocalLandID"] = land.localID;
1102
1103 // Bitmap is a byte[512]
1104 row["Bitmap"] = land.landBitmapByteArray;
1105
1106 row["Name"] = land.landName;
1107 row["Desc"] = land.landDesc;
1108 row["OwnerUUID"] = Util.ToRawUuidString(land.ownerID);
1109 row["IsGroupOwned"] = land.isGroupOwned;
1110 row["Area"] = land.area;
1111 row["AuctionID"] = land.auctionID; //Unemplemented
1112 row["Category"] = land.category; //Enum libsecondlife.Parcel.ParcelCategory
1113 row["ClaimDate"] = land.claimDate;
1114 row["ClaimPrice"] = land.claimPrice;
1115 row["GroupUUID"] = Util.ToRawUuidString(land.groupID);
1116 row["SalePrice"] = land.salePrice;
1117 row["LandStatus"] = land.landStatus; //Enum. libsecondlife.Parcel.ParcelStatus
1118 row["LandFlags"] = land.landFlags;
1119 row["LandingType"] = land.landingType;
1120 row["MediaAutoScale"] = land.mediaAutoScale;
1121 row["MediaTextureUUID"] = Util.ToRawUuidString(land.mediaID);
1122 row["MediaURL"] = land.mediaURL;
1123 row["MusicURL"] = land.musicURL;
1124 row["PassHours"] = land.passHours;
1125 row["PassPrice"] = land.passPrice;
1126 row["SnapshotUUID"] = Util.ToRawUuidString(land.snapshotID);
1127 row["UserLocationX"] = land.userLocation.X;
1128 row["UserLocationY"] = land.userLocation.Y;
1129 row["UserLocationZ"] = land.userLocation.Z;
1130 row["UserLookAtX"] = land.userLookAt.X;
1131 row["UserLookAtY"] = land.userLookAt.Y;
1132 row["UserLookAtZ"] = land.userLookAt.Z;
1133 }
1134
1135 private void fillLandAccessRow(DataRow row, ParcelManager.ParcelAccessEntry entry, LLUUID parcelID)
1136 {
1137 row["LandUUID"] = Util.ToRawUuidString(parcelID);
1138 row["AccessUUID"] = Util.ToRawUuidString(entry.AgentID);
1139 row["Flags"] = entry.Flags;
1140 }
1141
1142 private PrimitiveBaseShape buildShape(DataRow row)
1143 {
1144 PrimitiveBaseShape s = new PrimitiveBaseShape();
1145 s.Scale = new LLVector3(
1146 Convert.ToSingle(row["ScaleX"]),
1147 Convert.ToSingle(row["ScaleY"]),
1148 Convert.ToSingle(row["ScaleZ"])
1149 );
1150 // paths
1151 s.PCode = Convert.ToByte(row["PCode"]);
1152 s.PathBegin = Convert.ToUInt16(row["PathBegin"]);
1153 s.PathEnd = Convert.ToUInt16(row["PathEnd"]);
1154 s.PathScaleX = Convert.ToByte(row["PathScaleX"]);
1155 s.PathScaleY = Convert.ToByte(row["PathScaleY"]);
1156 s.PathShearX = Convert.ToByte(row["PathShearX"]);
1157 s.PathShearY = Convert.ToByte(row["PathShearY"]);
1158 s.PathSkew = Convert.ToSByte(row["PathSkew"]);
1159 s.PathCurve = Convert.ToByte(row["PathCurve"]);
1160 s.PathRadiusOffset = Convert.ToSByte(row["PathRadiusOffset"]);
1161 s.PathRevolutions = Convert.ToByte(row["PathRevolutions"]);
1162 s.PathTaperX = Convert.ToSByte(row["PathTaperX"]);
1163 s.PathTaperY = Convert.ToSByte(row["PathTaperY"]);
1164 s.PathTwist = Convert.ToSByte(row["PathTwist"]);
1165 s.PathTwistBegin = Convert.ToSByte(row["PathTwistBegin"]);
1166 // profile
1167 s.ProfileBegin = Convert.ToUInt16(row["ProfileBegin"]);
1168 s.ProfileEnd = Convert.ToUInt16(row["ProfileEnd"]);
1169 s.ProfileCurve = Convert.ToByte(row["ProfileCurve"]);
1170 s.ProfileHollow = Convert.ToUInt16(row["ProfileHollow"]);
1171 try
1172 {
1173 s.State = Convert.ToByte(row["State"]);
1174 }
1175 catch (InvalidCastException)
1176 {
1177 m_conn.Open();
1178 SqliteCommand cmd =
1179 new SqliteCommand("ALTER TABLE primshapes ADD COLUMN State Integer NOT NULL default 0;", m_conn);
1180 cmd.ExecuteNonQuery();
1181 }
1182 // text TODO: this isn't right] = but I'm not sure the right
1183 // way to specify this as a blob atm
1184
1185 byte[] textureEntry = (byte[]) row["Texture"];
1186 s.TextureEntry = textureEntry;
1187
1188 s.ExtraParams = (byte[]) row["ExtraParams"];
1189 // System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
1190 // string texture = encoding.GetString((Byte[])row["Texture"]);
1191 // if (!texture.StartsWith("<"))
1192 // {
1193 // //here so that we can still work with old format database files (ie from before I added xml serialization)
1194 // LLObject.TextureEntry textureEntry = null;
1195 // textureEntry = new LLObject.TextureEntry(new LLUUID(texture));
1196 // s.TextureEntry = textureEntry.ToBytes();
1197 // }
1198 // else
1199 // {
1200 // TextureBlock textureEntry = TextureBlock.FromXmlString(texture);
1201 // s.TextureEntry = textureEntry.TextureData;
1202 // s.ExtraParams = textureEntry.ExtraParams;
1203 // }
1204
1205 return s;
1206 }
1207
1208 private void fillShapeRow(DataRow row, SceneObjectPart prim)
1209 {
1210 PrimitiveBaseShape s = prim.Shape;
1211 row["UUID"] = Util.ToRawUuidString(prim.UUID);
1212 // shape is an enum
1213 row["Shape"] = 0;
1214 // vectors
1215 row["ScaleX"] = s.Scale.X;
1216 row["ScaleY"] = s.Scale.Y;
1217 row["ScaleZ"] = s.Scale.Z;
1218 // paths
1219 row["PCode"] = s.PCode;
1220 row["PathBegin"] = s.PathBegin;
1221 row["PathEnd"] = s.PathEnd;
1222 row["PathScaleX"] = s.PathScaleX;
1223 row["PathScaleY"] = s.PathScaleY;
1224 row["PathShearX"] = s.PathShearX;
1225 row["PathShearY"] = s.PathShearY;
1226 row["PathSkew"] = s.PathSkew;
1227 row["PathCurve"] = s.PathCurve;
1228 row["PathRadiusOffset"] = s.PathRadiusOffset;
1229 row["PathRevolutions"] = s.PathRevolutions;
1230 row["PathTaperX"] = s.PathTaperX;
1231 row["PathTaperY"] = s.PathTaperY;
1232 row["PathTwist"] = s.PathTwist;
1233 row["PathTwistBegin"] = s.PathTwistBegin;
1234 // profile
1235 row["ProfileBegin"] = s.ProfileBegin;
1236 row["ProfileEnd"] = s.ProfileEnd;
1237 row["ProfileCurve"] = s.ProfileCurve;
1238 row["ProfileHollow"] = s.ProfileHollow;
1239 row["State"] = s.State;
1240
1241 row["Texture"] = s.TextureEntry;
1242 row["ExtraParams"] = s.ExtraParams;
1243 }
1244
1245 private void addPrim(SceneObjectPart prim, LLUUID sceneGroupID, LLUUID regionUUID)
1246 {
1247 DataTable prims = ds.Tables["prims"];
1248 DataTable shapes = ds.Tables["primshapes"];
1249
1250 DataRow primRow = prims.Rows.Find(Util.ToRawUuidString(prim.UUID));
1251 if (primRow == null)
1252 {
1253 primRow = prims.NewRow();
1254 fillPrimRow(primRow, prim, sceneGroupID, regionUUID);
1255 prims.Rows.Add(primRow);
1256 }
1257 else
1258 {
1259 fillPrimRow(primRow, prim, sceneGroupID, regionUUID);
1260 }
1261
1262 DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID));
1263 if (shapeRow == null)
1264 {
1265 shapeRow = shapes.NewRow();
1266 fillShapeRow(shapeRow, prim);
1267 shapes.Rows.Add(shapeRow);
1268 }
1269 else
1270 {
1271 fillShapeRow(shapeRow, prim);
1272 }
1273 }
1274
1275 // see IRegionDatastore
1276 public void StorePrimInventory(LLUUID primID, ICollection<TaskInventoryItem> items)
1277 {
1278 if (!persistPrimInventories)
1279 return;
1280
1281 m_log.InfoFormat("[DATASTORE]: Entered StorePrimInventory with prim ID {0}", primID);
1282
1283 DataTable dbItems = ds.Tables["primitems"];
1284
1285 // For now, we're just going to crudely remove all the previous inventory items
1286 // no matter whether they have changed or not, and replace them with the current set.
1287 lock (ds)
1288 {
1289 RemoveItems(primID);
1290
1291 // repalce with current inventory details
1292 foreach (TaskInventoryItem newItem in items)
1293 {
1294// m_log.InfoFormat(
1295// "[DATASTORE]: ",
1296// "Adding item {0}, {1} to prim ID {2}",
1297// newItem.Name, newItem.ItemID, newItem.ParentPartID);
1298
1299 DataRow newItemRow = dbItems.NewRow();
1300 fillItemRow(newItemRow, newItem);
1301 dbItems.Rows.Add(newItemRow);
1302 }
1303 }
1304
1305 Commit();
1306 }
1307
1308 /***********************************************************************
1309 *
1310 * SQL Statement Creation Functions
1311 *
1312 * These functions create SQL statements for update, insert, and create.
1313 * They can probably be factored later to have a db independant
1314 * portion and a db specific portion
1315 *
1316 **********************************************************************/
1317
1318 private SqliteCommand createInsertCommand(string table, DataTable dt)
1319 {
1320 /**
1321 * This is subtle enough to deserve some commentary.
1322 * Instead of doing *lots* and *lots of hardcoded strings
1323 * for database definitions we'll use the fact that
1324 * realistically all insert statements look like "insert
1325 * into A(b, c) values(:b, :c) on the parameterized query
1326 * front. If we just have a list of b, c, etc... we can
1327 * generate these strings instead of typing them out.
1328 */
1329 string[] cols = new string[dt.Columns.Count];
1330 for (int i = 0; i < dt.Columns.Count; i++)
1331 {
1332 DataColumn col = dt.Columns[i];
1333 cols[i] = col.ColumnName;
1334 }
1335
1336 string sql = "insert into " + table + "(";
1337 sql += String.Join(", ", cols);
1338 // important, the first ':' needs to be here, the rest get added in the join
1339 sql += ") values (:";
1340 sql += String.Join(", :", cols);
1341 sql += ")";
1342 SqliteCommand cmd = new SqliteCommand(sql);
1343
1344 // this provides the binding for all our parameters, so
1345 // much less code than it used to be
1346 foreach (DataColumn col in dt.Columns)
1347 {
1348 cmd.Parameters.Add(createSqliteParameter(col.ColumnName, col.DataType));
1349 }
1350 return cmd;
1351 }
1352
1353 private SqliteCommand createUpdateCommand(string table, string pk, DataTable dt)
1354 {
1355 string sql = "update " + table + " set ";
1356 string subsql = String.Empty;
1357 foreach (DataColumn col in dt.Columns)
1358 {
1359 if (subsql.Length > 0)
1360 {
1361 // a map function would rock so much here
1362 subsql += ", ";
1363 }
1364 subsql += col.ColumnName + "= :" + col.ColumnName;
1365 }
1366 sql += subsql;
1367 sql += " where " + pk;
1368 SqliteCommand cmd = new SqliteCommand(sql);
1369
1370 // this provides the binding for all our parameters, so
1371 // much less code than it used to be
1372
1373 foreach (DataColumn col in dt.Columns)
1374 {
1375 cmd.Parameters.Add(createSqliteParameter(col.ColumnName, col.DataType));
1376 }
1377 return cmd;
1378 }
1379
1380
1381 private string defineTable(DataTable dt)
1382 {
1383 string sql = "create table " + dt.TableName + "(";
1384 string subsql = String.Empty;
1385 foreach (DataColumn col in dt.Columns)
1386 {
1387 if (subsql.Length > 0)
1388 {
1389 // a map function would rock so much here
1390 subsql += ",\n";
1391 }
1392 subsql += col.ColumnName + " " + sqliteType(col.DataType);
1393 if (dt.PrimaryKey.Length > 0 && col == dt.PrimaryKey[0])
1394 {
1395 subsql += " primary key";
1396 }
1397 }
1398 sql += subsql;
1399 sql += ")";
1400 return sql;
1401 }
1402
1403 /***********************************************************************
1404 *
1405 * Database Binding functions
1406 *
1407 * These will be db specific due to typing, and minor differences
1408 * in databases.
1409 *
1410 **********************************************************************/
1411
1412 ///<summary>
1413 /// This is a convenience function that collapses 5 repetitive
1414 /// lines for defining SqliteParameters to 2 parameters:
1415 /// column name and database type.
1416 ///
1417 /// It assumes certain conventions like :param as the param
1418 /// name to replace in parametrized queries, and that source
1419 /// version is always current version, both of which are fine
1420 /// for us.
1421 ///</summary>
1422 ///<returns>a built sqlite parameter</returns>
1423 private SqliteParameter createSqliteParameter(string name, Type type)
1424 {
1425 SqliteParameter param = new SqliteParameter();
1426 param.ParameterName = ":" + name;
1427 param.DbType = dbtypeFromType(type);
1428 param.SourceColumn = name;
1429 param.SourceVersion = DataRowVersion.Current;
1430 return param;
1431 }
1432
1433 private void setupPrimCommands(SqliteDataAdapter da, SqliteConnection conn)
1434 {
1435 da.InsertCommand = createInsertCommand("prims", ds.Tables["prims"]);
1436 da.InsertCommand.Connection = conn;
1437
1438 da.UpdateCommand = createUpdateCommand("prims", "UUID=:UUID", ds.Tables["prims"]);
1439 da.UpdateCommand.Connection = conn;
1440
1441 SqliteCommand delete = new SqliteCommand("delete from prims where UUID = :UUID");
1442 delete.Parameters.Add(createSqliteParameter("UUID", typeof (String)));
1443 delete.Connection = conn;
1444 da.DeleteCommand = delete;
1445 }
1446
1447 private void setupItemsCommands(SqliteDataAdapter da, SqliteConnection conn)
1448 {
1449 da.InsertCommand = createInsertCommand("primitems", ds.Tables["primitems"]);
1450 da.InsertCommand.Connection = conn;
1451
1452 da.UpdateCommand = createUpdateCommand("primitems", "itemID = :itemID", ds.Tables["primitems"]);
1453 da.UpdateCommand.Connection = conn;
1454
1455 SqliteCommand delete = new SqliteCommand("delete from primitems where itemID = :itemID");
1456 delete.Parameters.Add(createSqliteParameter("itemID", typeof (String)));
1457 delete.Connection = conn;
1458 da.DeleteCommand = delete;
1459 }
1460
1461 private void setupTerrainCommands(SqliteDataAdapter da, SqliteConnection conn)
1462 {
1463 da.InsertCommand = createInsertCommand("terrain", ds.Tables["terrain"]);
1464 da.InsertCommand.Connection = conn;
1465 }
1466
1467 private void setupLandCommands(SqliteDataAdapter da, SqliteConnection conn)
1468 {
1469 da.InsertCommand = createInsertCommand("land", ds.Tables["land"]);
1470 da.InsertCommand.Connection = conn;
1471
1472 da.UpdateCommand = createUpdateCommand("land", "UUID=:UUID", ds.Tables["land"]);
1473 da.UpdateCommand.Connection = conn;
1474 }
1475
1476 private void setupLandAccessCommands(SqliteDataAdapter da, SqliteConnection conn)
1477 {
1478 da.InsertCommand = createInsertCommand("landaccesslist", ds.Tables["landaccesslist"]);
1479 da.InsertCommand.Connection = conn;
1480 }
1481
1482 private void setupShapeCommands(SqliteDataAdapter da, SqliteConnection conn)
1483 {
1484 da.InsertCommand = createInsertCommand("primshapes", ds.Tables["primshapes"]);
1485 da.InsertCommand.Connection = conn;
1486
1487 da.UpdateCommand = createUpdateCommand("primshapes", "UUID=:UUID", ds.Tables["primshapes"]);
1488 da.UpdateCommand.Connection = conn;
1489
1490 SqliteCommand delete = new SqliteCommand("delete from primshapes where UUID = :UUID");
1491 delete.Parameters.Add(createSqliteParameter("UUID", typeof (String)));
1492 delete.Connection = conn;
1493 da.DeleteCommand = delete;
1494 }
1495
1496 /// <summary>
1497 /// Create the necessary database tables.
1498 /// </summary>
1499 /// <param name="conn"></param>
1500 private void InitDB(SqliteConnection conn)
1501 {
1502 string createPrims = defineTable(createPrimTable());
1503 string createShapes = defineTable(createShapeTable());
1504 string createItems = defineTable(createItemsTable());
1505 string createTerrain = defineTable(createTerrainTable());
1506 string createLand = defineTable(createLandTable());
1507 string createLandAccessList = defineTable(createLandAccessListTable());
1508
1509 SqliteCommand pcmd = new SqliteCommand(createPrims, conn);
1510 SqliteCommand scmd = new SqliteCommand(createShapes, conn);
1511 SqliteCommand icmd = new SqliteCommand(createItems, conn);
1512 SqliteCommand tcmd = new SqliteCommand(createTerrain, conn);
1513 SqliteCommand lcmd = new SqliteCommand(createLand, conn);
1514 SqliteCommand lalcmd = new SqliteCommand(createLandAccessList, conn);
1515
1516 try
1517 {
1518 pcmd.ExecuteNonQuery();
1519 }
1520 catch (SqliteSyntaxException)
1521 {
1522 m_log.Warn("[SQLITE]: Primitives Table Already Exists");
1523 }
1524
1525 try
1526 {
1527 scmd.ExecuteNonQuery();
1528 }
1529 catch (SqliteSyntaxException)
1530 {
1531 m_log.Warn("[SQLITE]: Shapes Table Already Exists");
1532 }
1533
1534 if (persistPrimInventories)
1535 {
1536 try
1537 {
1538 icmd.ExecuteNonQuery();
1539 }
1540 catch (SqliteSyntaxException)
1541 {
1542 m_log.Warn("[SQLITE]: Primitives Inventory Table Already Exists");
1543 }
1544 }
1545
1546 try
1547 {
1548 tcmd.ExecuteNonQuery();
1549 }
1550 catch (SqliteSyntaxException)
1551 {
1552 m_log.Warn("[SQLITE]: Terrain Table Already Exists");
1553 }
1554
1555 try
1556 {
1557 lcmd.ExecuteNonQuery();
1558 }
1559 catch (SqliteSyntaxException)
1560 {
1561 m_log.Warn("[SQLITE]: Land Table Already Exists");
1562 }
1563
1564 try
1565 {
1566 lalcmd.ExecuteNonQuery();
1567 }
1568 catch (SqliteSyntaxException)
1569 {
1570 m_log.Warn("[SQLITE]: LandAccessList Table Already Exists");
1571 }
1572 }
1573
1574 private bool TestTables(SqliteConnection conn)
1575 {
1576 SqliteCommand primSelectCmd = new SqliteCommand(primSelect, conn);
1577 SqliteDataAdapter pDa = new SqliteDataAdapter(primSelectCmd);
1578
1579 SqliteCommand shapeSelectCmd = new SqliteCommand(shapeSelect, conn);
1580 SqliteDataAdapter sDa = new SqliteDataAdapter(shapeSelectCmd);
1581
1582 SqliteCommand itemsSelectCmd = new SqliteCommand(itemsSelect, conn);
1583 SqliteDataAdapter iDa = new SqliteDataAdapter(itemsSelectCmd);
1584
1585 SqliteCommand terrainSelectCmd = new SqliteCommand(terrainSelect, conn);
1586 SqliteDataAdapter tDa = new SqliteDataAdapter(terrainSelectCmd);
1587
1588 SqliteCommand landSelectCmd = new SqliteCommand(landSelect, conn);
1589 SqliteDataAdapter lDa = new SqliteDataAdapter(landSelectCmd);
1590
1591 SqliteCommand landAccessListSelectCmd = new SqliteCommand(landAccessListSelect, conn);
1592 SqliteDataAdapter lalDa = new SqliteDataAdapter(landAccessListSelectCmd);
1593
1594 DataSet tmpDS = new DataSet();
1595 try
1596 {
1597 pDa.Fill(tmpDS, "prims");
1598 sDa.Fill(tmpDS, "primshapes");
1599
1600 if (persistPrimInventories)
1601 iDa.Fill(tmpDS, "primitems");
1602
1603 tDa.Fill(tmpDS, "terrain");
1604 lDa.Fill(tmpDS, "land");
1605 lalDa.Fill(tmpDS, "landaccesslist");
1606 }
1607 catch (SqliteSyntaxException)
1608 {
1609 m_log.Info("[DATASTORE]: SQLite Database doesn't exist... creating");
1610 InitDB(conn);
1611 }
1612
1613 pDa.Fill(tmpDS, "prims");
1614 sDa.Fill(tmpDS, "primshapes");
1615
1616 if (persistPrimInventories)
1617 iDa.Fill(tmpDS, "primitems");
1618
1619 tDa.Fill(tmpDS, "terrain");
1620 lDa.Fill(tmpDS, "land");
1621 lalDa.Fill(tmpDS, "landaccesslist");
1622
1623 foreach (DataColumn col in createPrimTable().Columns)
1624 {
1625 if (!tmpDS.Tables["prims"].Columns.Contains(col.ColumnName))
1626 {
1627 m_log.Info("[DATASTORE]: Missing required column:" + col.ColumnName);
1628 return false;
1629 }
1630 }
1631
1632 foreach (DataColumn col in createShapeTable().Columns)
1633 {
1634 if (!tmpDS.Tables["primshapes"].Columns.Contains(col.ColumnName))
1635 {
1636 m_log.Info("[DATASTORE]: Missing required column:" + col.ColumnName);
1637 return false;
1638 }
1639 }
1640
1641 // XXX primitems should probably go here eventually
1642
1643 foreach (DataColumn col in createTerrainTable().Columns)
1644 {
1645 if (!tmpDS.Tables["terrain"].Columns.Contains(col.ColumnName))
1646 {
1647 m_log.Info("[DATASTORE]: Missing require column:" + col.ColumnName);
1648 return false;
1649 }
1650 }
1651
1652 foreach (DataColumn col in createLandTable().Columns)
1653 {
1654 if (!tmpDS.Tables["land"].Columns.Contains(col.ColumnName))
1655 {
1656 m_log.Info("[DATASTORE]: Missing require column:" + col.ColumnName);
1657 return false;
1658 }
1659 }
1660
1661 foreach (DataColumn col in createLandAccessListTable().Columns)
1662 {
1663 if (!tmpDS.Tables["landaccesslist"].Columns.Contains(col.ColumnName))
1664 {
1665 m_log.Info("[DATASTORE]: Missing require column:" + col.ColumnName);
1666 return false;
1667 }
1668 }
1669
1670 return true;
1671 }
1672
1673 /***********************************************************************
1674 *
1675 * Type conversion functions
1676 *
1677 **********************************************************************/
1678
1679 private DbType dbtypeFromType(Type type)
1680 {
1681 if (type == typeof (String))
1682 {
1683 return DbType.String;
1684 }
1685 else if (type == typeof (Int32))
1686 {
1687 return DbType.Int32;
1688 }
1689 else if (type == typeof (Double))
1690 {
1691 return DbType.Double;
1692 }
1693 else if (type == typeof (Byte))
1694 {
1695 return DbType.Byte;
1696 }
1697 else if (type == typeof (Double))
1698 {
1699 return DbType.Double;
1700 }
1701 else if (type == typeof (Byte[]))
1702 {
1703 return DbType.Binary;
1704 }
1705 else
1706 {
1707 return DbType.String;
1708 }
1709 }
1710
1711 // this is something we'll need to implement for each db
1712 // slightly differently.
1713 private string sqliteType(Type type)
1714 {
1715 if (type == typeof (String))
1716 {
1717 return "varchar(255)";
1718 }
1719 else if (type == typeof (Int32))
1720 {
1721 return "integer";
1722 }
1723 else if (type == typeof (Int64))
1724 {
1725 return "integer";
1726 }
1727 else if (type == typeof (Double))
1728 {
1729 return "float";
1730 }
1731 else if (type == typeof (Byte[]))
1732 {
1733 return "blob";
1734 }
1735 else
1736 {
1737 return "string";
1738 }
1739 }
1740 }
1741}
diff --git a/OpenSim/Data/SQLite/SQLiteUserData.cs b/OpenSim/Data/SQLite/SQLiteUserData.cs
new file mode 100644
index 0000000..2efd4aa
--- /dev/null
+++ b/OpenSim/Data/SQLite/SQLiteUserData.cs
@@ -0,0 +1,821 @@
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 OpenSim 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 libsecondlife;
32using Mono.Data.SqliteClient;
33using OpenSim.Framework.Console;
34
35namespace OpenSim.Framework.Data.SQLite
36{
37 /// <summary>
38 /// A User storage interface for the SQLite database system
39 /// </summary>
40 public class SQLiteUserData : UserDataBase
41 {
42 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
43
44 /// <summary>
45 /// The database manager
46 /// </summary>
47 /// <summary>
48 /// Artificial constructor called upon plugin load
49 /// </summary>
50 private const string SelectUserByUUID = "select * from users where UUID=:UUID";
51 private const string SelectUserByName = "select * from users where username=:username and surname=:surname";
52 private const string SelectFriendsByUUID = "select a.friendID, a.friendPerms, b.friendPerms from userfriends as a, userfriends as b where a.ownerID=:ownerID and b.ownerID=a.friendID and b.friendID=a.ownerID";
53
54 private const string userSelect = "select * from users";
55 private const string userFriendsSelect = "select a.ownerID as ownerID,a.friendID as friendID,a.friendPerms as friendPerms,b.friendPerms as ownerperms, b.ownerID as fownerID, b.friendID as ffriendID from userfriends as a, userfriends as b";
56
57 private const string AvatarPickerAndSQL = "select * from users where username like :username and surname like :surname";
58 private const string AvatarPickerOrSQL = "select * from users where username like :username or surname like :surname";
59
60 private DataSet ds;
61 private SqliteDataAdapter da;
62 private SqliteDataAdapter daf;
63 SqliteConnection g_conn;
64
65 override public void Initialise()
66 {
67 SqliteConnection conn = new SqliteConnection("URI=file:userprofiles.db,version=3");
68 TestTables(conn);
69
70 // This sucks, but It doesn't seem to work with the dataset Syncing :P
71 g_conn = conn;
72 g_conn.Open();
73
74 ds = new DataSet();
75 da = new SqliteDataAdapter(new SqliteCommand(userSelect, conn));
76 daf = new SqliteDataAdapter(new SqliteCommand(userFriendsSelect, conn));
77
78 lock (ds)
79 {
80 ds.Tables.Add(createUsersTable());
81 ds.Tables.Add(createUserAgentsTable());
82 ds.Tables.Add(createUserFriendsTable());
83
84 setupUserCommands(da, conn);
85 da.Fill(ds.Tables["users"]);
86
87 setupUserFriendsCommands(daf, conn);
88 try
89 {
90 daf.Fill(ds.Tables["userfriends"]);
91 }
92 catch (SqliteSyntaxException)
93 {
94 m_log.Info("[SQLITE]: userfriends table not found, creating.... ");
95 InitDB(conn);
96 daf.Fill(ds.Tables["userfriends"]);
97 }
98
99 }
100
101 return;
102 }
103
104 // see IUserData
105 override public UserProfileData GetUserByUUID(LLUUID uuid)
106 {
107 lock (ds)
108 {
109 DataRow row = ds.Tables["users"].Rows.Find(Util.ToRawUuidString(uuid));
110 if (row != null)
111 {
112 UserProfileData user = buildUserProfile(row);
113 row = ds.Tables["useragents"].Rows.Find(Util.ToRawUuidString(uuid));
114 if (row != null)
115 {
116 user.currentAgent = buildUserAgent(row);
117 }
118 return user;
119 }
120 else
121 {
122 return null;
123 }
124 }
125 }
126
127 // see IUserData
128 override public UserProfileData GetUserByName(string fname, string lname)
129 {
130 string select = "surname = '" + lname + "' and username = '" + fname + "'";
131 lock (ds)
132 {
133 DataRow[] rows = ds.Tables["users"].Select(select);
134 if (rows.Length > 0)
135 {
136 UserProfileData user = buildUserProfile(rows[0]);
137 DataRow row = ds.Tables["useragents"].Rows.Find(Util.ToRawUuidString(user.UUID));
138 if (row != null)
139 {
140 user.currentAgent = buildUserAgent(row);
141 }
142 return user;
143 }
144 else
145 {
146 return null;
147 }
148 }
149 }
150
151 #region User Friends List Data
152
153 override public void AddNewUserFriend(LLUUID friendlistowner, LLUUID friend, uint perms)
154 {
155 string InsertFriends = "insert into userfriends(ownerID, friendID, friendPerms) values(:ownerID, :friendID, :perms)";
156
157 using (SqliteCommand cmd = new SqliteCommand(InsertFriends, g_conn))
158 {
159 cmd.Parameters.Add(new SqliteParameter(":ownerID", friendlistowner.UUID.ToString()));
160 cmd.Parameters.Add(new SqliteParameter(":friendID", friend.UUID.ToString()));
161 cmd.Parameters.Add(new SqliteParameter(":perms", perms));
162 cmd.ExecuteNonQuery();
163 }
164 using (SqliteCommand cmd = new SqliteCommand(InsertFriends, g_conn))
165 {
166 cmd.Parameters.Add(new SqliteParameter(":ownerID", friend.UUID.ToString()));
167 cmd.Parameters.Add(new SqliteParameter(":friendID", friendlistowner.UUID.ToString()));
168 cmd.Parameters.Add(new SqliteParameter(":perms", perms));
169 cmd.ExecuteNonQuery();
170 }
171 }
172
173 override public void RemoveUserFriend(LLUUID friendlistowner, LLUUID friend)
174 {
175 string DeletePerms = "delete from friendlist where (ownerID=:ownerID and friendID=:friendID) or (ownerID=:friendID and friendID=:ownerID)";
176 using (SqliteCommand cmd = new SqliteCommand(DeletePerms, g_conn))
177 {
178 cmd.Parameters.Add(new SqliteParameter(":ownerID", friendlistowner.UUID.ToString()));
179 cmd.Parameters.Add(new SqliteParameter(":friendID", friend.UUID.ToString()));
180 cmd.ExecuteNonQuery();
181 }
182 }
183
184 override public void UpdateUserFriendPerms(LLUUID friendlistowner, LLUUID friend, uint perms)
185 {
186 string UpdatePerms = "update friendlist set perms=:perms where ownerID=:ownerID and friendID=:friendID";
187 using (SqliteCommand cmd = new SqliteCommand(UpdatePerms, g_conn))
188 {
189 cmd.Parameters.Add(new SqliteParameter(":perms", perms));
190 cmd.Parameters.Add(new SqliteParameter(":ownerID", friendlistowner.UUID.ToString()));
191 cmd.Parameters.Add(new SqliteParameter(":friendID", friend.UUID.ToString()));
192 cmd.ExecuteNonQuery();
193 }
194 }
195
196 override public List<FriendListItem> GetUserFriendList(LLUUID friendlistowner)
197 {
198 List<FriendListItem> returnlist = new List<FriendListItem>();
199
200 using (SqliteCommand cmd = new SqliteCommand(SelectFriendsByUUID, g_conn))
201 {
202 cmd.Parameters.Add(new SqliteParameter(":ownerID", friendlistowner.UUID.ToString()));
203
204 try
205 {
206 using (IDataReader reader = cmd.ExecuteReader())
207 {
208 while (reader.Read())
209 {
210 FriendListItem user = new FriendListItem();
211 user.FriendListOwner = friendlistowner;
212 user.Friend = new LLUUID((string)reader[0]);
213 user.FriendPerms = Convert.ToUInt32(reader[1]);
214 user.FriendListOwnerPerms = Convert.ToUInt32(reader[2]);
215 returnlist.Add(user);
216 }
217 reader.Close();
218 }
219 }
220 catch (Exception ex)
221 {
222 m_log.Error("[USER]: Exception getting friends list for user: " + ex.ToString());
223 }
224 }
225
226 return returnlist;
227 }
228
229
230
231
232 #endregion
233
234 override public void UpdateUserCurrentRegion(LLUUID avatarid, LLUUID regionuuid)
235 {
236 m_log.Info("[USER]: Stub UpdateUserCUrrentRegion called");
237 }
238
239
240 override public List<Framework.AvatarPickerAvatar> GeneratePickerResults(LLUUID queryID, string query)
241 {
242 List<Framework.AvatarPickerAvatar> returnlist = new List<Framework.AvatarPickerAvatar>();
243 string[] querysplit;
244 querysplit = query.Split(' ');
245 if (querysplit.Length == 2)
246 {
247 using (SqliteCommand cmd = new SqliteCommand(AvatarPickerAndSQL, g_conn))
248 {
249 cmd.Parameters.Add(new SqliteParameter(":username", querysplit[0] + "%"));
250 cmd.Parameters.Add(new SqliteParameter(":surname", querysplit[1] + "%"));
251
252 using (IDataReader reader = cmd.ExecuteReader())
253 {
254 while (reader.Read())
255 {
256 Framework.AvatarPickerAvatar user = new Framework.AvatarPickerAvatar();
257 user.AvatarID = new LLUUID((string) reader["UUID"]);
258 user.firstName = (string) reader["username"];
259 user.lastName = (string) reader["surname"];
260 returnlist.Add(user);
261 }
262 reader.Close();
263 }
264 }
265 }
266 else if (querysplit.Length == 1)
267 {
268 using (SqliteCommand cmd = new SqliteCommand(AvatarPickerOrSQL, g_conn))
269 {
270 cmd.Parameters.Add(new SqliteParameter(":username", querysplit[0] + "%"));
271 cmd.Parameters.Add(new SqliteParameter(":surname", querysplit[0] + "%"));
272
273 using (IDataReader reader = cmd.ExecuteReader())
274 {
275 while (reader.Read())
276 {
277 Framework.AvatarPickerAvatar user = new Framework.AvatarPickerAvatar();
278 user.AvatarID = new LLUUID((string) reader["UUID"]);
279 user.firstName = (string) reader["username"];
280 user.lastName = (string) reader["surname"];
281 returnlist.Add(user);
282 }
283 reader.Close();
284 }
285 }
286 }
287 return returnlist;
288 }
289
290 /// <summary>
291 /// Returns a user by UUID direct
292 /// </summary>
293 /// <param name="uuid">The user's account ID</param>
294 /// <returns>A matching user profile</returns>
295 override public UserAgentData GetAgentByUUID(LLUUID uuid)
296 {
297 try
298 {
299 return GetUserByUUID(uuid).currentAgent;
300 }
301 catch (Exception)
302 {
303 return null;
304 }
305 }
306
307 /// <summary>
308 /// Returns a session by account name
309 /// </summary>
310 /// <param name="name">The account name</param>
311 /// <returns>The user's session agent</returns>
312 override public UserAgentData GetAgentByName(string name)
313 {
314 return GetAgentByName(name.Split(' ')[0], name.Split(' ')[1]);
315 }
316
317 /// <summary>
318 /// Returns a session by account name
319 /// </summary>
320 /// <param name="fname">The first part of the user's account name</param>
321 /// <param name="lname">The second part of the user's account name</param>
322 /// <returns>A user agent</returns>
323 override public UserAgentData GetAgentByName(string fname, string lname)
324 {
325 try
326 {
327 return GetUserByName(fname, lname).currentAgent;
328 }
329 catch (Exception)
330 {
331 return null;
332 }
333 }
334
335
336 override public void StoreWebLoginKey(LLUUID AgentID, LLUUID WebLoginKey)
337 {
338 DataTable users = ds.Tables["users"];
339 lock (ds)
340 {
341 DataRow row = users.Rows.Find(Util.ToRawUuidString(AgentID));
342 if (row == null)
343 {
344 m_log.Warn("[WEBLOGIN]: Unable to store new web login key for non-existant user");
345 }
346 else
347 {
348 UserProfileData user = GetUserByUUID(AgentID);
349 user.webLoginKey = WebLoginKey;
350 fillUserRow(row, user);
351 da.Update(ds, "users");
352
353 }
354 }
355
356 }
357
358 /// <summary>
359 /// Creates a new user profile
360 /// </summary>
361 /// <param name="user">The profile to add to the database</param>
362 override public void AddNewUserProfile(UserProfileData user)
363 {
364 DataTable users = ds.Tables["users"];
365 lock (ds)
366 {
367 DataRow row = users.Rows.Find(Util.ToRawUuidString(user.UUID));
368 if (row == null)
369 {
370 row = users.NewRow();
371 fillUserRow(row, user);
372 users.Rows.Add(row);
373 }
374 else
375 {
376 fillUserRow(row, user);
377
378 }
379 // This is why we're getting the 'logins never log-off'.. because It isn't clearing the
380 // useragents table once the useragent is null
381 //
382 // A database guy should look at this and figure out the best way to clear the useragents table.
383 if (user.currentAgent != null)
384 {
385 DataTable ua = ds.Tables["useragents"];
386 row = ua.Rows.Find(Util.ToRawUuidString(user.UUID));
387 if (row == null)
388 {
389 row = ua.NewRow();
390 fillUserAgentRow(row, user.currentAgent);
391 ua.Rows.Add(row);
392 }
393 else
394 {
395 fillUserAgentRow(row, user.currentAgent);
396 }
397 }
398 else
399 {
400 // I just added this to help the standalone login situation.
401 //It still needs to be looked at by a Database guy
402 DataTable ua = ds.Tables["useragents"];
403 row = ua.Rows.Find(Util.ToRawUuidString(user.UUID));
404
405 if (row == null)
406 {
407 // do nothing
408 }
409 else
410 {
411 row.Delete();
412 ua.AcceptChanges();
413 }
414 }
415
416 m_log.Info("[SQLITE]: " +
417 "Syncing user database: " + ds.Tables["users"].Rows.Count + " users stored");
418 // save changes off to disk
419 da.Update(ds, "users");
420 }
421 }
422
423 /// <summary>
424 /// Creates a new user profile
425 /// </summary>
426 /// <param name="user">The profile to add to the database</param>
427 /// <returns>True on success, false on error</returns>
428 override public bool UpdateUserProfile(UserProfileData user)
429 {
430 try
431 {
432 AddNewUserProfile(user);
433 return true;
434 }
435 catch (Exception)
436 {
437 return false;
438 }
439 }
440
441 /// <summary>
442 /// Creates a new user agent
443 /// </summary>
444 /// <param name="agent">The agent to add to the database</param>
445 override public void AddNewUserAgent(UserAgentData agent)
446 {
447 // Do nothing. yet.
448 }
449
450 /// <summary>
451 /// Transfers money between two user accounts
452 /// </summary>
453 /// <param name="from">Starting account</param>
454 /// <param name="to">End account</param>
455 /// <param name="amount">The amount to move</param>
456 /// <returns>Success?</returns>
457 override public bool MoneyTransferRequest(LLUUID from, LLUUID to, uint amount)
458 {
459 return true;
460 }
461
462 /// <summary>
463 /// Transfers inventory between two accounts
464 /// </summary>
465 /// <remarks>Move to inventory server</remarks>
466 /// <param name="from">Senders account</param>
467 /// <param name="to">Receivers account</param>
468 /// <param name="item">Inventory item</param>
469 /// <returns>Success?</returns>
470 override public bool InventoryTransferRequest(LLUUID from, LLUUID to, LLUUID item)
471 {
472 return true;
473 }
474
475 /// <summary>
476 /// Returns the name of the storage provider
477 /// </summary>
478 /// <returns>Storage provider name</returns>
479 override public string getName()
480 {
481 return "Sqlite Userdata";
482 }
483
484 /// <summary>
485 /// Returns the version of the storage provider
486 /// </summary>
487 /// <returns>Storage provider version</returns>
488 override public string GetVersion()
489 {
490 return "0.1";
491 }
492
493 /***********************************************************************
494 *
495 * DataTable creation
496 *
497 **********************************************************************/
498 /***********************************************************************
499 *
500 * Database Definition Functions
501 *
502 * This should be db agnostic as we define them in ADO.NET terms
503 *
504 **********************************************************************/
505
506 private static DataTable createUsersTable()
507 {
508 DataTable users = new DataTable("users");
509
510 SQLiteUtil.createCol(users, "UUID", typeof (String));
511 SQLiteUtil.createCol(users, "username", typeof (String));
512 SQLiteUtil.createCol(users, "surname", typeof (String));
513 SQLiteUtil.createCol(users, "passwordHash", typeof (String));
514 SQLiteUtil.createCol(users, "passwordSalt", typeof (String));
515
516 SQLiteUtil.createCol(users, "homeRegionX", typeof (Int32));
517 SQLiteUtil.createCol(users, "homeRegionY", typeof (Int32));
518 SQLiteUtil.createCol(users, "homeLocationX", typeof (Double));
519 SQLiteUtil.createCol(users, "homeLocationY", typeof (Double));
520 SQLiteUtil.createCol(users, "homeLocationZ", typeof (Double));
521 SQLiteUtil.createCol(users, "homeLookAtX", typeof (Double));
522 SQLiteUtil.createCol(users, "homeLookAtY", typeof (Double));
523 SQLiteUtil.createCol(users, "homeLookAtZ", typeof (Double));
524 SQLiteUtil.createCol(users, "created", typeof (Int32));
525 SQLiteUtil.createCol(users, "lastLogin", typeof (Int32));
526 SQLiteUtil.createCol(users, "rootInventoryFolderID", typeof (String));
527 SQLiteUtil.createCol(users, "userInventoryURI", typeof (String));
528 SQLiteUtil.createCol(users, "userAssetURI", typeof (String));
529 SQLiteUtil.createCol(users, "profileCanDoMask", typeof (Int32));
530 SQLiteUtil.createCol(users, "profileWantDoMask", typeof (Int32));
531 SQLiteUtil.createCol(users, "profileAboutText", typeof (String));
532 SQLiteUtil.createCol(users, "profileFirstText", typeof (String));
533 SQLiteUtil.createCol(users, "profileImage", typeof (String));
534 SQLiteUtil.createCol(users, "profileFirstImage", typeof (String));
535 SQLiteUtil.createCol(users, "webLoginKey", typeof(String));
536 // Add in contraints
537 users.PrimaryKey = new DataColumn[] {users.Columns["UUID"]};
538 return users;
539 }
540
541 private static DataTable createUserAgentsTable()
542 {
543 DataTable ua = new DataTable("useragents");
544 // this is the UUID of the user
545 SQLiteUtil.createCol(ua, "UUID", typeof (String));
546 SQLiteUtil.createCol(ua, "agentIP", typeof (String));
547 SQLiteUtil.createCol(ua, "agentPort", typeof (Int32));
548 SQLiteUtil.createCol(ua, "agentOnline", typeof (Boolean));
549 SQLiteUtil.createCol(ua, "sessionID", typeof (String));
550 SQLiteUtil.createCol(ua, "secureSessionID", typeof (String));
551 SQLiteUtil.createCol(ua, "regionID", typeof (String));
552 SQLiteUtil.createCol(ua, "loginTime", typeof (Int32));
553 SQLiteUtil.createCol(ua, "logoutTime", typeof (Int32));
554 SQLiteUtil.createCol(ua, "currentRegion", typeof (String));
555 SQLiteUtil.createCol(ua, "currentHandle", typeof (String));
556 // vectors
557 SQLiteUtil.createCol(ua, "currentPosX", typeof (Double));
558 SQLiteUtil.createCol(ua, "currentPosY", typeof (Double));
559 SQLiteUtil.createCol(ua, "currentPosZ", typeof (Double));
560 // constraints
561 ua.PrimaryKey = new DataColumn[] {ua.Columns["UUID"]};
562
563 return ua;
564 }
565
566 private static DataTable createUserFriendsTable()
567 {
568 DataTable ua = new DataTable("userfriends");
569 // table contains user <----> user relationship with perms
570 SQLiteUtil.createCol(ua, "ownerID", typeof(String));
571 SQLiteUtil.createCol(ua, "friendID", typeof(String));
572 SQLiteUtil.createCol(ua, "friendPerms", typeof(Int32));
573 SQLiteUtil.createCol(ua, "ownerPerms", typeof(Int32));
574 SQLiteUtil.createCol(ua, "datetimestamp", typeof(Int32));
575
576 return ua;
577 }
578
579 /***********************************************************************
580 *
581 * Convert between ADO.NET <=> OpenSim Objects
582 *
583 * These should be database independant
584 *
585 **********************************************************************/
586
587 private static UserProfileData buildUserProfile(DataRow row)
588 {
589 // TODO: this doesn't work yet because something more
590 // interesting has to be done to actually get these values
591 // back out. Not enough time to figure it out yet.
592 UserProfileData user = new UserProfileData();
593 LLUUID.TryParse((String)row["UUID"], out user.UUID);
594 user.username = (String) row["username"];
595 user.surname = (String) row["surname"];
596 user.passwordHash = (String) row["passwordHash"];
597 user.passwordSalt = (String) row["passwordSalt"];
598
599 user.homeRegionX = Convert.ToUInt32(row["homeRegionX"]);
600 user.homeRegionY = Convert.ToUInt32(row["homeRegionY"]);
601 user.homeLocation = new LLVector3(
602 Convert.ToSingle(row["homeLocationX"]),
603 Convert.ToSingle(row["homeLocationY"]),
604 Convert.ToSingle(row["homeLocationZ"])
605 );
606 user.homeLookAt = new LLVector3(
607 Convert.ToSingle(row["homeLookAtX"]),
608 Convert.ToSingle(row["homeLookAtY"]),
609 Convert.ToSingle(row["homeLookAtZ"])
610 );
611 user.created = Convert.ToInt32(row["created"]);
612 user.lastLogin = Convert.ToInt32(row["lastLogin"]);
613 user.rootInventoryFolderID = new LLUUID((String) row["rootInventoryFolderID"]);
614 user.userInventoryURI = (String) row["userInventoryURI"];
615 user.userAssetURI = (String) row["userAssetURI"];
616 user.profileCanDoMask = Convert.ToUInt32(row["profileCanDoMask"]);
617 user.profileWantDoMask = Convert.ToUInt32(row["profileWantDoMask"]);
618 user.profileAboutText = (String) row["profileAboutText"];
619 user.profileFirstText = (String) row["profileFirstText"];
620 LLUUID.TryParse((String)row["profileImage"], out user.profileImage);
621 LLUUID.TryParse((String)row["profileFirstImage"], out user.profileFirstImage);
622 user.webLoginKey = new LLUUID((String) row["webLoginKey"]);
623
624 return user;
625 }
626
627 private void fillUserRow(DataRow row, UserProfileData user)
628 {
629 row["UUID"] = Util.ToRawUuidString(user.UUID);
630 row["username"] = user.username;
631 row["surname"] = user.surname;
632 row["passwordHash"] = user.passwordHash;
633 row["passwordSalt"] = user.passwordSalt;
634
635
636 row["homeRegionX"] = user.homeRegionX;
637 row["homeRegionY"] = user.homeRegionY;
638 row["homeLocationX"] = user.homeLocation.X;
639 row["homeLocationY"] = user.homeLocation.Y;
640 row["homeLocationZ"] = user.homeLocation.Z;
641 row["homeLookAtX"] = user.homeLookAt.X;
642 row["homeLookAtY"] = user.homeLookAt.Y;
643 row["homeLookAtZ"] = user.homeLookAt.Z;
644
645 row["created"] = user.created;
646 row["lastLogin"] = user.lastLogin;
647 row["rootInventoryFolderID"] = user.rootInventoryFolderID;
648 row["userInventoryURI"] = user.userInventoryURI;
649 row["userAssetURI"] = user.userAssetURI;
650 row["profileCanDoMask"] = user.profileCanDoMask;
651 row["profileWantDoMask"] = user.profileWantDoMask;
652 row["profileAboutText"] = user.profileAboutText;
653 row["profileFirstText"] = user.profileFirstText;
654 row["profileImage"] = user.profileImage;
655 row["profileFirstImage"] = user.profileFirstImage;
656 row["webLoginKey"] = user.webLoginKey;
657
658 // ADO.NET doesn't handle NULL very well
659 foreach (DataColumn col in ds.Tables["users"].Columns)
660 {
661 if (row[col] == null)
662 {
663 row[col] = String.Empty;
664 }
665 }
666 }
667
668 private static UserAgentData buildUserAgent(DataRow row)
669 {
670 UserAgentData ua = new UserAgentData();
671
672 ua.UUID = new LLUUID((String) row["UUID"]);
673 ua.agentIP = (String) row["agentIP"];
674 ua.agentPort = Convert.ToUInt32(row["agentPort"]);
675 ua.agentOnline = Convert.ToBoolean(row["agentOnline"]);
676 ua.sessionID = new LLUUID((String) row["sessionID"]);
677 ua.secureSessionID = new LLUUID((String) row["secureSessionID"]);
678 ua.regionID = new LLUUID((String) row["regionID"]);
679 ua.loginTime = Convert.ToInt32(row["loginTime"]);
680 ua.logoutTime = Convert.ToInt32(row["logoutTime"]);
681 ua.currentRegion = new LLUUID((String) row["currentRegion"]);
682 ua.currentHandle = Convert.ToUInt64(row["currentHandle"]);
683 ua.currentPos = new LLVector3(
684 Convert.ToSingle(row["currentPosX"]),
685 Convert.ToSingle(row["currentPosY"]),
686 Convert.ToSingle(row["currentPosZ"])
687 );
688 return ua;
689 }
690
691 private static void fillUserAgentRow(DataRow row, UserAgentData ua)
692 {
693 row["UUID"] = ua.UUID;
694 row["agentIP"] = ua.agentIP;
695 row["agentPort"] = ua.agentPort;
696 row["agentOnline"] = ua.agentOnline;
697 row["sessionID"] = ua.sessionID;
698 row["secureSessionID"] = ua.secureSessionID;
699 row["regionID"] = ua.regionID;
700 row["loginTime"] = ua.loginTime;
701 row["logoutTime"] = ua.logoutTime;
702 row["currentRegion"] = ua.currentRegion;
703 row["currentHandle"] = ua.currentHandle.ToString();
704 // vectors
705 row["currentPosX"] = ua.currentPos.X;
706 row["currentPosY"] = ua.currentPos.Y;
707 row["currentPosZ"] = ua.currentPos.Z;
708 }
709
710 /***********************************************************************
711 *
712 * Database Binding functions
713 *
714 * These will be db specific due to typing, and minor differences
715 * in databases.
716 *
717 **********************************************************************/
718
719 private void setupUserCommands(SqliteDataAdapter da, SqliteConnection conn)
720 {
721 da.InsertCommand = SQLiteUtil.createInsertCommand("users", ds.Tables["users"]);
722 da.InsertCommand.Connection = conn;
723
724 da.UpdateCommand = SQLiteUtil.createUpdateCommand("users", "UUID=:UUID", ds.Tables["users"]);
725 da.UpdateCommand.Connection = conn;
726
727 SqliteCommand delete = new SqliteCommand("delete from users where UUID = :UUID");
728 delete.Parameters.Add(SQLiteUtil.createSqliteParameter("UUID", typeof(String)));
729 delete.Connection = conn;
730 da.DeleteCommand = delete;
731 }
732
733 private void setupUserFriendsCommands(SqliteDataAdapter daf, SqliteConnection conn)
734 {
735 daf.InsertCommand = SQLiteUtil.createInsertCommand("userfriends", ds.Tables["userfriends"]);
736 daf.InsertCommand.Connection = conn;
737
738 daf.UpdateCommand = SQLiteUtil.createUpdateCommand("userfriends", "ownerID=:ownerID and friendID=:friendID", ds.Tables["userfriends"]);
739 daf.UpdateCommand.Connection = conn;
740
741 SqliteCommand delete = new SqliteCommand("delete from userfriends where ownerID=:ownerID and friendID=:friendID");
742 delete.Parameters.Add(SQLiteUtil.createSqliteParameter("ownerID", typeof(String)));
743 delete.Parameters.Add(SQLiteUtil.createSqliteParameter("friendID", typeof(String)));
744 delete.Connection = conn;
745 daf.DeleteCommand = delete;
746
747 }
748
749 private void InitDB(SqliteConnection conn)
750 {
751 string createUsers = SQLiteUtil.defineTable(createUsersTable());
752 string createFriends = SQLiteUtil.defineTable(createUserFriendsTable());
753
754 SqliteCommand pcmd = new SqliteCommand(createUsers, conn);
755 SqliteCommand fcmd = new SqliteCommand(createFriends, conn);
756
757 conn.Open();
758
759 try
760 {
761
762 pcmd.ExecuteNonQuery();
763 }
764 catch (System.Exception)
765 {
766 m_log.Info("[USERS]: users table already exists");
767 }
768
769 try
770 {
771 fcmd.ExecuteNonQuery();
772 }
773 catch (System.Exception)
774 {
775 m_log.Info("[USERS]: userfriends table already exists");
776 }
777
778 conn.Close();
779 }
780
781 private bool TestTables(SqliteConnection conn)
782 {
783 SqliteCommand cmd = new SqliteCommand(userSelect, conn);
784 SqliteCommand fcmd = new SqliteCommand(userFriendsSelect, conn);
785 SqliteDataAdapter pDa = new SqliteDataAdapter(cmd);
786 SqliteDataAdapter fDa = new SqliteDataAdapter(cmd);
787
788 DataSet tmpDS = new DataSet();
789 DataSet tmpDS2 = new DataSet();
790
791 try
792 {
793 pDa.Fill(tmpDS, "users");
794 fDa.Fill(tmpDS2, "userfriends");
795 }
796 catch (SqliteSyntaxException)
797 {
798 m_log.Info("[DATASTORE]: SQLite Database doesn't exist... creating");
799 InitDB(conn);
800 }
801 conn.Open();
802 try
803 {
804 cmd = new SqliteCommand("select webLoginKey from users limit 1;", conn);
805 cmd.ExecuteNonQuery();
806 }
807 catch (SqliteSyntaxException)
808 {
809 cmd = new SqliteCommand("alter table users add column webLoginKey text default '00000000-0000-0000-0000-000000000000';", conn);
810 cmd.ExecuteNonQuery();
811 pDa.Fill(tmpDS, "users");
812 }
813 finally
814 {
815 conn.Close();
816 }
817
818 return true;
819 }
820 }
821}
diff --git a/OpenSim/Data/SQLite/SQLiteUtils.cs b/OpenSim/Data/SQLite/SQLiteUtils.cs
new file mode 100644
index 0000000..1334e53
--- /dev/null
+++ b/OpenSim/Data/SQLite/SQLiteUtils.cs
@@ -0,0 +1,269 @@
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 OpenSim 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 Mono.Data.SqliteClient;
31
32namespace OpenSim.Framework.Data.SQLite
33{
34 /// <summary>
35 /// A base class for methods needed by all SQLite database classes
36 /// </summary>
37 public class SQLiteUtil
38 {
39 /***********************************************************************
40 *
41 * Database Definition Helper Functions
42 *
43 * This should be db agnostic as we define them in ADO.NET terms
44 *
45 **********************************************************************/
46
47 public static void createCol(DataTable dt, string name, Type type)
48 {
49 DataColumn col = new DataColumn(name, type);
50 dt.Columns.Add(col);
51 }
52
53 /***********************************************************************
54 *
55 * SQL Statement Creation Functions
56 *
57 * These functions create SQL statements for update, insert, and create.
58 * They can probably be factored later to have a db independant
59 * portion and a db specific portion
60 *
61 **********************************************************************/
62
63 public static SqliteCommand createInsertCommand(string table, DataTable dt)
64 {
65 /**
66 * This is subtle enough to deserve some commentary.
67 * Instead of doing *lots* and *lots of hardcoded strings
68 * for database definitions we'll use the fact that
69 * realistically all insert statements look like "insert
70 * into A(b, c) values(:b, :c) on the parameterized query
71 * front. If we just have a list of b, c, etc... we can
72 * generate these strings instead of typing them out.
73 */
74 string[] cols = new string[dt.Columns.Count];
75 for (int i = 0; i < dt.Columns.Count; i++)
76 {
77 DataColumn col = dt.Columns[i];
78 cols[i] = col.ColumnName;
79 }
80
81 string sql = "insert into " + table + "(";
82 sql += String.Join(", ", cols);
83 // important, the first ':' needs to be here, the rest get added in the join
84 sql += ") values (:";
85 sql += String.Join(", :", cols);
86 sql += ")";
87 SqliteCommand cmd = new SqliteCommand(sql);
88
89 // this provides the binding for all our parameters, so
90 // much less code than it used to be
91 foreach (DataColumn col in dt.Columns)
92 {
93 cmd.Parameters.Add(createSqliteParameter(col.ColumnName, col.DataType));
94 }
95 return cmd;
96 }
97
98 public static SqliteCommand createUpdateCommand(string table, string pk, DataTable dt)
99 {
100 string sql = "update " + table + " set ";
101 string subsql = String.Empty;
102 foreach (DataColumn col in dt.Columns)
103 {
104 if (subsql.Length > 0)
105 {
106 // a map function would rock so much here
107 subsql += ", ";
108 }
109 subsql += col.ColumnName + "= :" + col.ColumnName;
110 }
111 sql += subsql;
112 sql += " where " + pk;
113 SqliteCommand cmd = new SqliteCommand(sql);
114
115 // this provides the binding for all our parameters, so
116 // much less code than it used to be
117
118 foreach (DataColumn col in dt.Columns)
119 {
120 cmd.Parameters.Add(createSqliteParameter(col.ColumnName, col.DataType));
121 }
122 return cmd;
123 }
124
125
126 public static string defineTable(DataTable dt)
127 {
128 string sql = "create table " + dt.TableName + "(";
129 string subsql = String.Empty;
130 foreach (DataColumn col in dt.Columns)
131 {
132 if (subsql.Length > 0)
133 {
134 // a map function would rock so much here
135 subsql += ",\n";
136 }
137 subsql += col.ColumnName + " " + sqliteType(col.DataType);
138 if (dt.PrimaryKey.Length > 0)
139 {
140 if (col == dt.PrimaryKey[0])
141 {
142 subsql += " primary key";
143 }
144 }
145 }
146 sql += subsql;
147 sql += ")";
148 return sql;
149 }
150
151 /***********************************************************************
152 *
153 * Database Binding functions
154 *
155 * These will be db specific due to typing, and minor differences
156 * in databases.
157 *
158 **********************************************************************/
159
160 ///<summary>
161 /// This is a convenience function that collapses 5 repetitive
162 /// lines for defining SqliteParameters to 2 parameters:
163 /// column name and database type.
164 ///
165 /// It assumes certain conventions like :param as the param
166 /// name to replace in parametrized queries, and that source
167 /// version is always current version, both of which are fine
168 /// for us.
169 ///</summary>
170 ///<returns>a built sqlite parameter</returns>
171 public static SqliteParameter createSqliteParameter(string name, Type type)
172 {
173 SqliteParameter param = new SqliteParameter();
174 param.ParameterName = ":" + name;
175 param.DbType = dbtypeFromType(type);
176 param.SourceColumn = name;
177 param.SourceVersion = DataRowVersion.Current;
178 return param;
179 }
180
181 /***********************************************************************
182 *
183 * Type conversion functions
184 *
185 **********************************************************************/
186
187 public static DbType dbtypeFromType(Type type)
188 {
189 if (type == typeof (String))
190 {
191 return DbType.String;
192 }
193 else if (type == typeof (Int32))
194 {
195 return DbType.Int32;
196 }
197 else if (type == typeof (UInt32))
198 {
199 return DbType.UInt32;
200 }
201 else if (type == typeof (Int64))
202 {
203 return DbType.Int64;
204 }
205 else if (type == typeof (UInt64))
206 {
207 return DbType.UInt64;
208 }
209 else if (type == typeof (Double))
210 {
211 return DbType.Double;
212 }
213 else if (type == typeof (Boolean))
214 {
215 return DbType.Boolean;
216 }
217 else if (type == typeof (Byte[]))
218 {
219 return DbType.Binary;
220 }
221 else
222 {
223 return DbType.String;
224 }
225 }
226
227 // this is something we'll need to implement for each db
228 // slightly differently.
229 public static string sqliteType(Type type)
230 {
231 if (type == typeof (String))
232 {
233 return "varchar(255)";
234 }
235 else if (type == typeof (Int32))
236 {
237 return "integer";
238 }
239 else if (type == typeof (UInt32))
240 {
241 return "integer";
242 }
243 else if (type == typeof (Int64))
244 {
245 return "varchar(255)";
246 }
247 else if (type == typeof (UInt64))
248 {
249 return "varchar(255)";
250 }
251 else if (type == typeof (Double))
252 {
253 return "float";
254 }
255 else if (type == typeof (Boolean))
256 {
257 return "integer";
258 }
259 else if (type == typeof (Byte[]))
260 {
261 return "blob";
262 }
263 else
264 {
265 return "string";
266 }
267 }
268 }
269}