diff options
author | Sean Dague | 2007-08-23 15:16:53 +0000 |
---|---|---|
committer | Sean Dague | 2007-08-23 15:16:53 +0000 |
commit | 8c9f006dd322ba3ef053949040d5ac86ce363c95 (patch) | |
tree | 2b411cade3501e125f0013e304e0fef6cdb13063 /OpenSim/Region/Storage/OpenSim.DataStore.MonoSqlite | |
parent | remove this sqlite file as the database is actually autogenerated (diff) | |
download | opensim-SC-8c9f006dd322ba3ef053949040d5ac86ce363c95.zip opensim-SC-8c9f006dd322ba3ef053949040d5ac86ce363c95.tar.gz opensim-SC-8c9f006dd322ba3ef053949040d5ac86ce363c95.tar.bz2 opensim-SC-8c9f006dd322ba3ef053949040d5ac86ce363c95.tar.xz |
grouping of functions to make the overall logic easier to grasp for people,
and start to show how this can be super classed with some common elements.
Diffstat (limited to 'OpenSim/Region/Storage/OpenSim.DataStore.MonoSqlite')
-rw-r--r-- | OpenSim/Region/Storage/OpenSim.DataStore.MonoSqlite/MonoSqliteDataStore.cs | 743 |
1 files changed, 394 insertions, 349 deletions
diff --git a/OpenSim/Region/Storage/OpenSim.DataStore.MonoSqlite/MonoSqliteDataStore.cs b/OpenSim/Region/Storage/OpenSim.DataStore.MonoSqlite/MonoSqliteDataStore.cs index fb4f53f..87df8fb 100644 --- a/OpenSim/Region/Storage/OpenSim.DataStore.MonoSqlite/MonoSqliteDataStore.cs +++ b/OpenSim/Region/Storage/OpenSim.DataStore.MonoSqlite/MonoSqliteDataStore.cs | |||
@@ -31,6 +31,11 @@ namespace OpenSim.DataStore.MonoSqliteStorage | |||
31 | private SqliteDataAdapter primDa; | 31 | private SqliteDataAdapter primDa; |
32 | private SqliteDataAdapter shapeDa; | 32 | private SqliteDataAdapter shapeDa; |
33 | 33 | ||
34 | /*********************************************************************** | ||
35 | * | ||
36 | * Public Interface Functions | ||
37 | * | ||
38 | **********************************************************************/ | ||
34 | public void Initialise(string dbfile, string dbname) | 39 | public void Initialise(string dbfile, string dbname) |
35 | { | 40 | { |
36 | string connectionString = "URI=file:" + dbfile + ",version=3"; | 41 | string connectionString = "URI=file:" + dbfile + ",version=3"; |
@@ -65,129 +70,276 @@ namespace OpenSim.DataStore.MonoSqliteStorage | |||
65 | return; | 70 | return; |
66 | } | 71 | } |
67 | 72 | ||
68 | ///<summary> | 73 | public void StoreObject(SceneObjectGroup obj, LLUUID regionUUID) |
69 | /// This is a convenience function that collapses 5 repetitive | ||
70 | /// lines for defining SqliteParameters to 2 parameters: | ||
71 | /// column name and database type. | ||
72 | /// | ||
73 | /// It assumes certain conventions like :param as the param | ||
74 | /// name to replace in parametrized queries, and that source | ||
75 | /// version is always current version, both of which are fine | ||
76 | /// for us. | ||
77 | ///</summary> | ||
78 | ///<returns>a built sqlite parameter</returns> | ||
79 | private SqliteParameter createSqliteParameter(string name, System.Type type) | ||
80 | { | 74 | { |
81 | SqliteParameter param = new SqliteParameter(); | 75 | foreach (SceneObjectPart prim in obj.Children.Values) |
82 | param.ParameterName = ":" + name; | 76 | { |
83 | param.DbType = dbtypeFromType(type); | 77 | addPrim(prim, obj.UUID); |
84 | param.SourceColumn = name; | 78 | } |
85 | param.SourceVersion = DataRowVersion.Current; | 79 | |
86 | return param; | 80 | // MainLog.Instance.Verbose("Attempting to do database update...."); |
81 | primDa.Update(ds, "prims"); | ||
82 | shapeDa.Update(ds, "primshapes"); | ||
83 | // MainLog.Instance.Verbose("Dump of prims:", ds.GetXml()); | ||
87 | } | 84 | } |
88 | 85 | ||
89 | private DbType dbtypeFromType(Type type) | 86 | public void RemoveObject(LLUUID obj, LLUUID regionUUID) |
90 | { | 87 | { |
91 | if (type == typeof(System.String)) { | 88 | DataTable prims = ds.Tables["prims"]; |
92 | return DbType.String; | 89 | DataTable shapes = ds.Tables["primshapes"]; |
93 | } else if (type == typeof(System.Int32)) { | 90 | |
94 | return DbType.Int32; | 91 | string selectExp = "SceneGroupID = '" + obj.ToString() + "'"; |
95 | } else if (type == typeof(System.Double)) { | 92 | DataRow[] primRows = prims.Select(selectExp); |
96 | return DbType.Double; | 93 | foreach (DataRow row in primRows) |
97 | } else if (type == typeof(System.Byte[])) { | 94 | { |
98 | return DbType.Binary; | 95 | LLUUID uuid = new LLUUID((string)row["UUID"]); |
99 | } else { | 96 | DataRow shapeRow = shapes.Rows.Find(uuid); |
100 | return DbType.String; | 97 | if (shapeRow != null) |
98 | { | ||
99 | shapeRow.Delete(); | ||
100 | } | ||
101 | row.Delete(); | ||
101 | } | 102 | } |
103 | |||
104 | primDa.Update(ds, "prims"); | ||
105 | shapeDa.Update(ds, "primshapes"); | ||
102 | } | 106 | } |
103 | 107 | ||
104 | private SqliteCommand createInsertCommand(string table, DataTable dt) | 108 | public List<SceneObjectGroup> LoadObjects(LLUUID regionUUID) |
105 | { | 109 | { |
106 | /** | 110 | Dictionary<LLUUID, SceneObjectGroup> createdObjects = new Dictionary<LLUUID, SceneObjectGroup>(); |
107 | * This is subtle enough to deserve some commentary. | 111 | List<SceneObjectGroup> retvals = new List<SceneObjectGroup>(); |
108 | * Instead of doing *lots* and *lots of hardcoded strings | ||
109 | * for database definitions we'll use the fact that | ||
110 | * realistically all insert statements look like "insert | ||
111 | * into A(b, c) values(:b, :c) on the parameterized query | ||
112 | * front. If we just have a list of b, c, etc... we can | ||
113 | * generate these strings instead of typing them out. | ||
114 | */ | ||
115 | string[] cols = new string[dt.Columns.Count]; | ||
116 | for (int i = 0; i < dt.Columns.Count; i++) { | ||
117 | DataColumn col = dt.Columns[i]; | ||
118 | cols[i] = col.ColumnName; | ||
119 | } | ||
120 | 112 | ||
121 | string sql = "insert into " + table + "("; | 113 | DataTable prims = ds.Tables["prims"]; |
122 | sql += String.Join(", ", cols); | 114 | DataTable shapes = ds.Tables["primshapes"]; |
123 | // important, the first ':' needs to be here, the rest get added in the join | ||
124 | sql += ") values (:"; | ||
125 | sql += String.Join(", :", cols); | ||
126 | sql += ")"; | ||
127 | SqliteCommand cmd = new SqliteCommand(sql); | ||
128 | 115 | ||
129 | // this provides the binding for all our parameters, so | 116 | foreach (DataRow primRow in prims.Rows) |
130 | // much less code than it used to be | ||
131 | foreach (DataColumn col in dt.Columns) | ||
132 | { | 117 | { |
133 | cmd.Parameters.Add(createSqliteParameter(col.ColumnName, col.DataType)); | 118 | string uuid = (string)primRow["UUID"]; |
119 | string objID = (string)primRow["SceneGroupID"]; | ||
120 | if (uuid == objID) //is new SceneObjectGroup ? | ||
121 | { | ||
122 | SceneObjectGroup group = new SceneObjectGroup(); | ||
123 | SceneObjectPart prim = buildPrim(primRow); | ||
124 | DataRow shapeRow = shapes.Rows.Find(prim.UUID); | ||
125 | if (shapeRow != null) | ||
126 | { | ||
127 | prim.Shape = buildShape(shapeRow); | ||
128 | } | ||
129 | else | ||
130 | { | ||
131 | Console.WriteLine("No shape found for prim in storage, so setting default box shape"); | ||
132 | prim.Shape = BoxShape.Default; | ||
133 | } | ||
134 | group.AddPart(prim); | ||
135 | group.RootPart = prim; | ||
136 | |||
137 | createdObjects.Add(group.UUID, group); | ||
138 | retvals.Add(group); | ||
139 | } | ||
140 | else | ||
141 | { | ||
142 | SceneObjectPart prim = buildPrim(primRow); | ||
143 | DataRow shapeRow = shapes.Rows.Find(prim.UUID); | ||
144 | if (shapeRow != null) | ||
145 | { | ||
146 | prim.Shape = buildShape(shapeRow); | ||
147 | } | ||
148 | else | ||
149 | { | ||
150 | Console.WriteLine("No shape found for prim in storage, so setting default box shape"); | ||
151 | prim.Shape = BoxShape.Default; | ||
152 | } | ||
153 | createdObjects[new LLUUID(objID)].AddPart(prim); | ||
154 | } | ||
134 | } | 155 | } |
135 | return cmd; | 156 | |
157 | MainLog.Instance.Verbose("DATASTORE", "Sqlite - LoadObjects found " + prims.Rows.Count + " primitives"); | ||
158 | |||
159 | return retvals; | ||
136 | } | 160 | } |
137 | 161 | ||
138 | private SqliteCommand createUpdateCommand(string table, string pk, DataTable dt) | 162 | public void StoreTerrain(double[,] ter) |
139 | { | 163 | { |
140 | string sql = "update " + table + " set "; | 164 | |
141 | string subsql = ""; | 165 | } |
142 | foreach (DataColumn col in dt.Columns) | 166 | |
167 | public double[,] LoadTerrain() | ||
168 | { | ||
169 | return null; | ||
170 | } | ||
171 | |||
172 | public void RemoveLandObject(uint id) | ||
173 | { | ||
174 | |||
175 | } | ||
176 | |||
177 | public void StoreParcel(Land parcel) | ||
178 | { | ||
179 | |||
180 | } | ||
181 | |||
182 | public List<Land> LoadLandObjects() | ||
183 | { | ||
184 | return new List<Land>(); | ||
185 | } | ||
186 | |||
187 | public void Shutdown() | ||
188 | { | ||
189 | // TODO: DataSet commit | ||
190 | } | ||
191 | |||
192 | public class TextureBlock | ||
193 | { | ||
194 | public byte[] TextureData; | ||
195 | public byte[] ExtraParams = new byte[1]; | ||
196 | |||
197 | public TextureBlock(byte[] data) | ||
143 | { | 198 | { |
144 | if (subsql.Length > 0) | 199 | TextureData = data; |
145 | { // a map function would rock so much here | ||
146 | subsql += ", "; | ||
147 | } | ||
148 | subsql += col.ColumnName + "= :" + col.ColumnName; | ||
149 | } | 200 | } |
150 | sql += subsql; | ||
151 | sql += " where " + pk; | ||
152 | SqliteCommand cmd = new SqliteCommand(sql); | ||
153 | 201 | ||
154 | // this provides the binding for all our parameters, so | 202 | public TextureBlock() |
155 | // much less code than it used to be | 203 | { |
156 | 204 | ||
157 | foreach (DataColumn col in dt.Columns) | 205 | } |
206 | |||
207 | public string ToXMLString() | ||
158 | { | 208 | { |
159 | cmd.Parameters.Add(createSqliteParameter(col.ColumnName, col.DataType)); | 209 | StringWriter sw = new StringWriter(); |
210 | XmlTextWriter writer = new XmlTextWriter(sw); | ||
211 | XmlSerializer serializer = new XmlSerializer(typeof(TextureBlock)); | ||
212 | serializer.Serialize(writer, this); | ||
213 | return sw.ToString(); | ||
214 | } | ||
215 | |||
216 | public static TextureBlock FromXmlString(string xmlData) | ||
217 | { | ||
218 | TextureBlock textureEntry = null; | ||
219 | StringReader sr = new StringReader(xmlData); | ||
220 | XmlTextReader reader = new XmlTextReader(sr); | ||
221 | XmlSerializer serializer = new XmlSerializer(typeof(TextureBlock)); | ||
222 | textureEntry = (TextureBlock)serializer.Deserialize(reader); | ||
223 | reader.Close(); | ||
224 | sr.Close(); | ||
225 | return textureEntry; | ||
160 | } | 226 | } |
161 | return cmd; | ||
162 | } | 227 | } |
163 | 228 | ||
164 | private void setupPrimCommands(SqliteDataAdapter da, SqliteConnection conn) | 229 | /*********************************************************************** |
230 | * | ||
231 | * Database Definition Functions | ||
232 | * | ||
233 | * This should be db agnostic as we define them in ADO.NET terms | ||
234 | * | ||
235 | **********************************************************************/ | ||
236 | |||
237 | private void createCol(DataTable dt, string name, System.Type type) | ||
165 | { | 238 | { |
166 | da.InsertCommand = createInsertCommand("prims", ds.Tables["prims"]); | 239 | DataColumn col = new DataColumn(name, type); |
167 | da.InsertCommand.Connection = conn; | 240 | dt.Columns.Add(col); |
241 | } | ||
168 | 242 | ||
169 | da.UpdateCommand = createUpdateCommand("prims", "UUID=:UUID", ds.Tables["prims"]); | 243 | private DataTable createPrimTable() |
170 | da.UpdateCommand.Connection = conn; | 244 | { |
245 | DataTable prims = new DataTable("prims"); | ||
171 | 246 | ||
172 | SqliteCommand delete = new SqliteCommand("delete from prims where UUID = :UUID"); | 247 | createCol(prims, "UUID", typeof(System.String)); |
173 | delete.Parameters.Add(createSqliteParameter("UUID", typeof(System.String))); | 248 | createCol(prims, "ParentID", typeof(System.Int32)); |
174 | delete.Connection = conn; | 249 | createCol(prims, "CreationDate", typeof(System.Int32)); |
175 | da.DeleteCommand = delete; | 250 | createCol(prims, "Name", typeof(System.String)); |
251 | createCol(prims, "SceneGroupID", typeof(System.String)); | ||
252 | // various text fields | ||
253 | createCol(prims, "Text", typeof(System.String)); | ||
254 | createCol(prims, "Description", typeof(System.String)); | ||
255 | createCol(prims, "SitName", typeof(System.String)); | ||
256 | createCol(prims, "TouchName", typeof(System.String)); | ||
257 | // permissions | ||
258 | createCol(prims, "CreatorID", typeof(System.String)); | ||
259 | createCol(prims, "OwnerID", typeof(System.String)); | ||
260 | createCol(prims, "GroupID", typeof(System.String)); | ||
261 | createCol(prims, "LastOwnerID", typeof(System.String)); | ||
262 | createCol(prims, "OwnerMask", typeof(System.Int32)); | ||
263 | createCol(prims, "NextOwnerMask", typeof(System.Int32)); | ||
264 | createCol(prims, "GroupMask", typeof(System.Int32)); | ||
265 | createCol(prims, "EveryoneMask", typeof(System.Int32)); | ||
266 | createCol(prims, "BaseMask", typeof(System.Int32)); | ||
267 | // vectors | ||
268 | createCol(prims, "PositionX", typeof(System.Double)); | ||
269 | createCol(prims, "PositionY", typeof(System.Double)); | ||
270 | createCol(prims, "PositionZ", typeof(System.Double)); | ||
271 | createCol(prims, "GroupPositionX", typeof(System.Double)); | ||
272 | createCol(prims, "GroupPositionY", typeof(System.Double)); | ||
273 | createCol(prims, "GroupPositionZ", typeof(System.Double)); | ||
274 | createCol(prims, "VelocityX", typeof(System.Double)); | ||
275 | createCol(prims, "VelocityY", typeof(System.Double)); | ||
276 | createCol(prims, "VelocityZ", typeof(System.Double)); | ||
277 | createCol(prims, "AngularVelocityX", typeof(System.Double)); | ||
278 | createCol(prims, "AngularVelocityY", typeof(System.Double)); | ||
279 | createCol(prims, "AngularVelocityZ", typeof(System.Double)); | ||
280 | createCol(prims, "AccelerationX", typeof(System.Double)); | ||
281 | createCol(prims, "AccelerationY", typeof(System.Double)); | ||
282 | createCol(prims, "AccelerationZ", typeof(System.Double)); | ||
283 | // quaternions | ||
284 | createCol(prims, "RotationX", typeof(System.Double)); | ||
285 | createCol(prims, "RotationY", typeof(System.Double)); | ||
286 | createCol(prims, "RotationZ", typeof(System.Double)); | ||
287 | createCol(prims, "RotationW", typeof(System.Double)); | ||
288 | |||
289 | // Add in contraints | ||
290 | prims.PrimaryKey = new DataColumn[] { prims.Columns["UUID"] }; | ||
291 | |||
292 | return prims; | ||
176 | } | 293 | } |
177 | 294 | ||
178 | private void setupShapeCommands(SqliteDataAdapter da, SqliteConnection conn) | 295 | private DataTable createShapeTable() |
179 | { | 296 | { |
180 | da.InsertCommand = createInsertCommand("primshapes", ds.Tables["primshapes"]); | 297 | DataTable shapes = new DataTable("primshapes"); |
181 | da.InsertCommand.Connection = conn; | 298 | createCol(shapes, "UUID", typeof(System.String)); |
299 | // shape is an enum | ||
300 | createCol(shapes, "Shape", typeof(System.Int32)); | ||
301 | // vectors | ||
302 | createCol(shapes, "ScaleX", typeof(System.Double)); | ||
303 | createCol(shapes, "ScaleY", typeof(System.Double)); | ||
304 | createCol(shapes, "ScaleZ", typeof(System.Double)); | ||
305 | // paths | ||
306 | createCol(shapes, "PCode", typeof(System.Int32)); | ||
307 | createCol(shapes, "PathBegin", typeof(System.Int32)); | ||
308 | createCol(shapes, "PathEnd", typeof(System.Int32)); | ||
309 | createCol(shapes, "PathScaleX", typeof(System.Int32)); | ||
310 | createCol(shapes, "PathScaleY", typeof(System.Int32)); | ||
311 | createCol(shapes, "PathShearX", typeof(System.Int32)); | ||
312 | createCol(shapes, "PathShearY", typeof(System.Int32)); | ||
313 | createCol(shapes, "PathSkew", typeof(System.Int32)); | ||
314 | createCol(shapes, "PathCurve", typeof(System.Int32)); | ||
315 | createCol(shapes, "PathRadiusOffset", typeof(System.Int32)); | ||
316 | createCol(shapes, "PathRevolutions", typeof(System.Int32)); | ||
317 | createCol(shapes, "PathTaperX", typeof(System.Int32)); | ||
318 | createCol(shapes, "PathTaperY", typeof(System.Int32)); | ||
319 | createCol(shapes, "PathTwist", typeof(System.Int32)); | ||
320 | createCol(shapes, "PathTwistBegin", typeof(System.Int32)); | ||
321 | // profile | ||
322 | createCol(shapes, "ProfileBegin", typeof(System.Int32)); | ||
323 | createCol(shapes, "ProfileEnd", typeof(System.Int32)); | ||
324 | createCol(shapes, "ProfileCurve", typeof(System.Int32)); | ||
325 | createCol(shapes, "ProfileHollow", typeof(System.Int32)); | ||
326 | // text TODO: this isn't right, but I'm not sure the right | ||
327 | // way to specify this as a blob atm | ||
328 | createCol(shapes, "Texture", typeof(System.Byte[])); | ||
329 | createCol(shapes, "ExtraParams", typeof(System.Byte[])); | ||
182 | 330 | ||
183 | da.UpdateCommand = createUpdateCommand("primshapes", "UUID=:UUID", ds.Tables["primshapes"]); | 331 | shapes.PrimaryKey = new DataColumn[] { shapes.Columns["UUID"] }; |
184 | da.UpdateCommand.Connection = conn; | ||
185 | 332 | ||
186 | SqliteCommand delete = new SqliteCommand("delete from primshapes where UUID = :UUID"); | 333 | return shapes; |
187 | delete.Parameters.Add(createSqliteParameter("UUID", typeof(System.String))); | ||
188 | delete.Connection = conn; | ||
189 | da.DeleteCommand = delete; | ||
190 | } | 334 | } |
335 | |||
336 | /*********************************************************************** | ||
337 | * | ||
338 | * Convert between ADO.NET <=> OpenSim Objects | ||
339 | * | ||
340 | * These should be database independant | ||
341 | * | ||
342 | **********************************************************************/ | ||
191 | 343 | ||
192 | private SceneObjectPart buildPrim(DataRow row) | 344 | private SceneObjectPart buildPrim(DataRow row) |
193 | { | 345 | { |
@@ -424,163 +576,157 @@ namespace OpenSim.DataStore.MonoSqliteStorage | |||
424 | fillShapeRow(shapeRow, prim); | 576 | fillShapeRow(shapeRow, prim); |
425 | } | 577 | } |
426 | } | 578 | } |
579 | |||
580 | /*********************************************************************** | ||
581 | * | ||
582 | * SQL Statement Creation Functions | ||
583 | * | ||
584 | * These functions create SQL statements for update, insert, and create. | ||
585 | * They can probably be factored later to have a db independant | ||
586 | * portion and a db specific portion | ||
587 | * | ||
588 | **********************************************************************/ | ||
427 | 589 | ||
428 | public void StoreObject(SceneObjectGroup obj, LLUUID regionUUID) | 590 | private SqliteCommand createInsertCommand(string table, DataTable dt) |
429 | { | 591 | { |
430 | foreach (SceneObjectPart prim in obj.Children.Values) | 592 | /** |
431 | { | 593 | * This is subtle enough to deserve some commentary. |
432 | addPrim(prim, obj.UUID); | 594 | * Instead of doing *lots* and *lots of hardcoded strings |
595 | * for database definitions we'll use the fact that | ||
596 | * realistically all insert statements look like "insert | ||
597 | * into A(b, c) values(:b, :c) on the parameterized query | ||
598 | * front. If we just have a list of b, c, etc... we can | ||
599 | * generate these strings instead of typing them out. | ||
600 | */ | ||
601 | string[] cols = new string[dt.Columns.Count]; | ||
602 | for (int i = 0; i < dt.Columns.Count; i++) { | ||
603 | DataColumn col = dt.Columns[i]; | ||
604 | cols[i] = col.ColumnName; | ||
433 | } | 605 | } |
434 | 606 | ||
435 | // MainLog.Instance.Verbose("Attempting to do database update...."); | 607 | string sql = "insert into " + table + "("; |
436 | primDa.Update(ds, "prims"); | 608 | sql += String.Join(", ", cols); |
437 | shapeDa.Update(ds, "primshapes"); | 609 | // important, the first ':' needs to be here, the rest get added in the join |
438 | // MainLog.Instance.Verbose("Dump of prims:", ds.GetXml()); | 610 | sql += ") values (:"; |
611 | sql += String.Join(", :", cols); | ||
612 | sql += ")"; | ||
613 | SqliteCommand cmd = new SqliteCommand(sql); | ||
614 | |||
615 | // this provides the binding for all our parameters, so | ||
616 | // much less code than it used to be | ||
617 | foreach (DataColumn col in dt.Columns) | ||
618 | { | ||
619 | cmd.Parameters.Add(createSqliteParameter(col.ColumnName, col.DataType)); | ||
620 | } | ||
621 | return cmd; | ||
439 | } | 622 | } |
440 | 623 | ||
441 | public void RemoveObject(LLUUID obj, LLUUID regionUUID) | 624 | private SqliteCommand createUpdateCommand(string table, string pk, DataTable dt) |
442 | { | 625 | { |
443 | DataTable prims = ds.Tables["prims"]; | 626 | string sql = "update " + table + " set "; |
444 | DataTable shapes = ds.Tables["primshapes"]; | 627 | string subsql = ""; |
445 | 628 | foreach (DataColumn col in dt.Columns) | |
446 | string selectExp = "SceneGroupID = '" + obj.ToString() + "'"; | ||
447 | DataRow[] primRows = prims.Select(selectExp); | ||
448 | foreach (DataRow row in primRows) | ||
449 | { | 629 | { |
450 | LLUUID uuid = new LLUUID((string)row["UUID"]); | 630 | if (subsql.Length > 0) |
451 | DataRow shapeRow = shapes.Rows.Find(uuid); | 631 | { // a map function would rock so much here |
452 | if (shapeRow != null) | 632 | subsql += ", "; |
453 | { | ||
454 | shapeRow.Delete(); | ||
455 | } | 633 | } |
456 | row.Delete(); | 634 | subsql += col.ColumnName + "= :" + col.ColumnName; |
457 | } | 635 | } |
636 | sql += subsql; | ||
637 | sql += " where " + pk; | ||
638 | SqliteCommand cmd = new SqliteCommand(sql); | ||
458 | 639 | ||
459 | primDa.Update(ds, "prims"); | 640 | // this provides the binding for all our parameters, so |
460 | shapeDa.Update(ds, "primshapes"); | 641 | // much less code than it used to be |
642 | |||
643 | foreach (DataColumn col in dt.Columns) | ||
644 | { | ||
645 | cmd.Parameters.Add(createSqliteParameter(col.ColumnName, col.DataType)); | ||
646 | } | ||
647 | return cmd; | ||
461 | } | 648 | } |
462 | 649 | ||
463 | public List<SceneObjectGroup> LoadObjects(LLUUID regionUUID) | ||
464 | { | ||
465 | Dictionary<LLUUID, SceneObjectGroup> createdObjects = new Dictionary<LLUUID, SceneObjectGroup>(); | ||
466 | List<SceneObjectGroup> retvals = new List<SceneObjectGroup>(); | ||
467 | 650 | ||
468 | DataTable prims = ds.Tables["prims"]; | 651 | private string defineTable(DataTable dt) |
469 | DataTable shapes = ds.Tables["primshapes"]; | 652 | { |
470 | 653 | string sql = "create table " + dt.TableName + "("; | |
471 | foreach (DataRow primRow in prims.Rows) | 654 | string subsql = ""; |
655 | foreach (DataColumn col in dt.Columns) | ||
472 | { | 656 | { |
473 | string uuid = (string)primRow["UUID"]; | 657 | if (subsql.Length > 0) |
474 | string objID = (string)primRow["SceneGroupID"]; | 658 | { // a map function would rock so much here |
475 | if (uuid == objID) //is new SceneObjectGroup ? | 659 | subsql += ",\n"; |
476 | { | ||
477 | SceneObjectGroup group = new SceneObjectGroup(); | ||
478 | SceneObjectPart prim = buildPrim(primRow); | ||
479 | DataRow shapeRow = shapes.Rows.Find(prim.UUID); | ||
480 | if (shapeRow != null) | ||
481 | { | ||
482 | prim.Shape = buildShape(shapeRow); | ||
483 | } | ||
484 | else | ||
485 | { | ||
486 | Console.WriteLine("No shape found for prim in storage, so setting default box shape"); | ||
487 | prim.Shape = BoxShape.Default; | ||
488 | } | ||
489 | group.AddPart(prim); | ||
490 | group.RootPart = prim; | ||
491 | |||
492 | createdObjects.Add(group.UUID, group); | ||
493 | retvals.Add(group); | ||
494 | } | 660 | } |
495 | else | 661 | subsql += col.ColumnName + " " + sqliteType(col.DataType); |
662 | if(col == dt.PrimaryKey[0]) | ||
496 | { | 663 | { |
497 | SceneObjectPart prim = buildPrim(primRow); | 664 | subsql += " primary key"; |
498 | DataRow shapeRow = shapes.Rows.Find(prim.UUID); | ||
499 | if (shapeRow != null) | ||
500 | { | ||
501 | prim.Shape = buildShape(shapeRow); | ||
502 | } | ||
503 | else | ||
504 | { | ||
505 | Console.WriteLine("No shape found for prim in storage, so setting default box shape"); | ||
506 | prim.Shape = BoxShape.Default; | ||
507 | } | ||
508 | createdObjects[new LLUUID(objID)].AddPart(prim); | ||
509 | } | 665 | } |
510 | } | 666 | } |
511 | 667 | sql += subsql; | |
512 | MainLog.Instance.Verbose("DATASTORE", "Sqlite - LoadObjects found " + prims.Rows.Count + " primitives"); | 668 | sql += ")"; |
513 | 669 | return sql; | |
514 | return retvals; | ||
515 | } | ||
516 | |||
517 | public void StoreTerrain(double[,] ter) | ||
518 | { | ||
519 | |||
520 | } | 670 | } |
521 | 671 | ||
522 | public double[,] LoadTerrain() | 672 | /*********************************************************************** |
523 | { | 673 | * |
524 | return null; | 674 | * Database Binding functions |
525 | } | 675 | * |
676 | * These will be db specific due to typing, and minor differences | ||
677 | * in databases. | ||
678 | * | ||
679 | **********************************************************************/ | ||
526 | 680 | ||
527 | public void RemoveLandObject(uint id) | 681 | ///<summary> |
682 | /// This is a convenience function that collapses 5 repetitive | ||
683 | /// lines for defining SqliteParameters to 2 parameters: | ||
684 | /// column name and database type. | ||
685 | /// | ||
686 | /// It assumes certain conventions like :param as the param | ||
687 | /// name to replace in parametrized queries, and that source | ||
688 | /// version is always current version, both of which are fine | ||
689 | /// for us. | ||
690 | ///</summary> | ||
691 | ///<returns>a built sqlite parameter</returns> | ||
692 | private SqliteParameter createSqliteParameter(string name, System.Type type) | ||
528 | { | 693 | { |
529 | 694 | SqliteParameter param = new SqliteParameter(); | |
695 | param.ParameterName = ":" + name; | ||
696 | param.DbType = dbtypeFromType(type); | ||
697 | param.SourceColumn = name; | ||
698 | param.SourceVersion = DataRowVersion.Current; | ||
699 | return param; | ||
530 | } | 700 | } |
531 | 701 | ||
532 | public void StoreParcel(Land parcel) | 702 | private void setupPrimCommands(SqliteDataAdapter da, SqliteConnection conn) |
533 | { | 703 | { |
704 | da.InsertCommand = createInsertCommand("prims", ds.Tables["prims"]); | ||
705 | da.InsertCommand.Connection = conn; | ||
534 | 706 | ||
535 | } | 707 | da.UpdateCommand = createUpdateCommand("prims", "UUID=:UUID", ds.Tables["prims"]); |
536 | 708 | da.UpdateCommand.Connection = conn; | |
537 | public List<Land> LoadLandObjects() | ||
538 | { | ||
539 | return new List<Land>(); | ||
540 | } | ||
541 | 709 | ||
542 | public void Shutdown() | 710 | SqliteCommand delete = new SqliteCommand("delete from prims where UUID = :UUID"); |
543 | { | 711 | delete.Parameters.Add(createSqliteParameter("UUID", typeof(System.String))); |
544 | // TODO: DataSet commit | 712 | delete.Connection = conn; |
713 | da.DeleteCommand = delete; | ||
545 | } | 714 | } |
546 | 715 | ||
547 | public class TextureBlock | 716 | private void setupShapeCommands(SqliteDataAdapter da, SqliteConnection conn) |
548 | { | 717 | { |
549 | public byte[] TextureData; | 718 | da.InsertCommand = createInsertCommand("primshapes", ds.Tables["primshapes"]); |
550 | public byte[] ExtraParams = new byte[1]; | 719 | da.InsertCommand.Connection = conn; |
551 | |||
552 | public TextureBlock(byte[] data) | ||
553 | { | ||
554 | TextureData = data; | ||
555 | } | ||
556 | |||
557 | public TextureBlock() | ||
558 | { | ||
559 | |||
560 | } | ||
561 | 720 | ||
562 | public string ToXMLString() | 721 | da.UpdateCommand = createUpdateCommand("primshapes", "UUID=:UUID", ds.Tables["primshapes"]); |
563 | { | 722 | da.UpdateCommand.Connection = conn; |
564 | StringWriter sw = new StringWriter(); | ||
565 | XmlTextWriter writer = new XmlTextWriter(sw); | ||
566 | XmlSerializer serializer = new XmlSerializer(typeof(TextureBlock)); | ||
567 | serializer.Serialize(writer, this); | ||
568 | return sw.ToString(); | ||
569 | } | ||
570 | 723 | ||
571 | public static TextureBlock FromXmlString(string xmlData) | 724 | SqliteCommand delete = new SqliteCommand("delete from primshapes where UUID = :UUID"); |
572 | { | 725 | delete.Parameters.Add(createSqliteParameter("UUID", typeof(System.String))); |
573 | TextureBlock textureEntry = null; | 726 | delete.Connection = conn; |
574 | StringReader sr = new StringReader(xmlData); | 727 | da.DeleteCommand = delete; |
575 | XmlTextReader reader = new XmlTextReader(sr); | ||
576 | XmlSerializer serializer = new XmlSerializer(typeof(TextureBlock)); | ||
577 | textureEntry = (TextureBlock)serializer.Deserialize(reader); | ||
578 | reader.Close(); | ||
579 | sr.Close(); | ||
580 | return textureEntry; | ||
581 | } | ||
582 | } | 728 | } |
583 | 729 | ||
584 | private void InitDB(SqliteConnection conn) | 730 | private void InitDB(SqliteConnection conn) |
585 | { | 731 | { |
586 | string createPrims = defineTable(createPrimTable()); | 732 | string createPrims = defineTable(createPrimTable()); |
@@ -594,42 +740,6 @@ namespace OpenSim.DataStore.MonoSqliteStorage | |||
594 | conn.Close(); | 740 | conn.Close(); |
595 | } | 741 | } |
596 | 742 | ||
597 | private string defineTable(DataTable dt) | ||
598 | { | ||
599 | string sql = "create table " + dt.TableName + "("; | ||
600 | string subsql = ""; | ||
601 | foreach (DataColumn col in dt.Columns) | ||
602 | { | ||
603 | if (subsql.Length > 0) | ||
604 | { // a map function would rock so much here | ||
605 | subsql += ",\n"; | ||
606 | } | ||
607 | subsql += col.ColumnName + " " + sqliteType(col.DataType); | ||
608 | if(col == dt.PrimaryKey[0]) | ||
609 | { | ||
610 | subsql += " primary key"; | ||
611 | } | ||
612 | } | ||
613 | sql += subsql; | ||
614 | sql += ")"; | ||
615 | return sql; | ||
616 | } | ||
617 | |||
618 | private string sqliteType(Type type) | ||
619 | { | ||
620 | if (type == typeof(System.String)) { | ||
621 | return "varchar(255)"; | ||
622 | } else if (type == typeof(System.Int32)) { | ||
623 | return "integer"; | ||
624 | } else if (type == typeof(System.Double)) { | ||
625 | return "float"; | ||
626 | } else if (type == typeof(System.Byte[])) { | ||
627 | return "blob"; | ||
628 | } else { | ||
629 | return "string"; | ||
630 | } | ||
631 | } | ||
632 | |||
633 | private bool TestTables(SqliteConnection conn) | 743 | private bool TestTables(SqliteConnection conn) |
634 | { | 744 | { |
635 | SqliteCommand primSelectCmd = new SqliteCommand(primSelect, conn); | 745 | SqliteCommand primSelectCmd = new SqliteCommand(primSelect, conn); |
@@ -664,107 +774,42 @@ namespace OpenSim.DataStore.MonoSqliteStorage | |||
664 | return true; | 774 | return true; |
665 | } | 775 | } |
666 | 776 | ||
667 | /// Methods after this point are big data definition | 777 | /*********************************************************************** |
668 | /// methods, and aren't really interesting unless you are | 778 | * |
669 | /// adjusting the schema. | 779 | * Type conversion functions |
670 | 780 | * | |
671 | private void createCol(DataTable dt, string name, System.Type type) | 781 | **********************************************************************/ |
672 | { | 782 | |
673 | DataColumn col = new DataColumn(name, type); | 783 | private DbType dbtypeFromType(Type type) |
674 | dt.Columns.Add(col); | ||
675 | } | ||
676 | |||
677 | private DataTable createPrimTable() | ||
678 | { | 784 | { |
679 | DataTable prims = new DataTable("prims"); | 785 | if (type == typeof(System.String)) { |
680 | 786 | return DbType.String; | |
681 | createCol(prims, "UUID", typeof(System.String)); | 787 | } else if (type == typeof(System.Int32)) { |
682 | createCol(prims, "ParentID", typeof(System.Int32)); | 788 | return DbType.Int32; |
683 | createCol(prims, "CreationDate", typeof(System.Int32)); | 789 | } else if (type == typeof(System.Double)) { |
684 | createCol(prims, "Name", typeof(System.String)); | 790 | return DbType.Double; |
685 | createCol(prims, "SceneGroupID", typeof(System.String)); | 791 | } else if (type == typeof(System.Byte[])) { |
686 | // various text fields | 792 | return DbType.Binary; |
687 | createCol(prims, "Text", typeof(System.String)); | 793 | } else { |
688 | createCol(prims, "Description", typeof(System.String)); | 794 | return DbType.String; |
689 | createCol(prims, "SitName", typeof(System.String)); | 795 | } |
690 | createCol(prims, "TouchName", typeof(System.String)); | ||
691 | // permissions | ||
692 | createCol(prims, "CreatorID", typeof(System.String)); | ||
693 | createCol(prims, "OwnerID", typeof(System.String)); | ||
694 | createCol(prims, "GroupID", typeof(System.String)); | ||
695 | createCol(prims, "LastOwnerID", typeof(System.String)); | ||
696 | createCol(prims, "OwnerMask", typeof(System.Int32)); | ||
697 | createCol(prims, "NextOwnerMask", typeof(System.Int32)); | ||
698 | createCol(prims, "GroupMask", typeof(System.Int32)); | ||
699 | createCol(prims, "EveryoneMask", typeof(System.Int32)); | ||
700 | createCol(prims, "BaseMask", typeof(System.Int32)); | ||
701 | // vectors | ||
702 | createCol(prims, "PositionX", typeof(System.Double)); | ||
703 | createCol(prims, "PositionY", typeof(System.Double)); | ||
704 | createCol(prims, "PositionZ", typeof(System.Double)); | ||
705 | createCol(prims, "GroupPositionX", typeof(System.Double)); | ||
706 | createCol(prims, "GroupPositionY", typeof(System.Double)); | ||
707 | createCol(prims, "GroupPositionZ", typeof(System.Double)); | ||
708 | createCol(prims, "VelocityX", typeof(System.Double)); | ||
709 | createCol(prims, "VelocityY", typeof(System.Double)); | ||
710 | createCol(prims, "VelocityZ", typeof(System.Double)); | ||
711 | createCol(prims, "AngularVelocityX", typeof(System.Double)); | ||
712 | createCol(prims, "AngularVelocityY", typeof(System.Double)); | ||
713 | createCol(prims, "AngularVelocityZ", typeof(System.Double)); | ||
714 | createCol(prims, "AccelerationX", typeof(System.Double)); | ||
715 | createCol(prims, "AccelerationY", typeof(System.Double)); | ||
716 | createCol(prims, "AccelerationZ", typeof(System.Double)); | ||
717 | // quaternions | ||
718 | createCol(prims, "RotationX", typeof(System.Double)); | ||
719 | createCol(prims, "RotationY", typeof(System.Double)); | ||
720 | createCol(prims, "RotationZ", typeof(System.Double)); | ||
721 | createCol(prims, "RotationW", typeof(System.Double)); | ||
722 | |||
723 | // Add in contraints | ||
724 | prims.PrimaryKey = new DataColumn[] { prims.Columns["UUID"] }; | ||
725 | |||
726 | return prims; | ||
727 | } | 796 | } |
728 | 797 | ||
729 | private DataTable createShapeTable() | 798 | // this is something we'll need to implement for each db |
799 | // slightly differently. | ||
800 | private string sqliteType(Type type) | ||
730 | { | 801 | { |
731 | DataTable shapes = new DataTable("primshapes"); | 802 | if (type == typeof(System.String)) { |
732 | createCol(shapes, "UUID", typeof(System.String)); | 803 | return "varchar(255)"; |
733 | // shape is an enum | 804 | } else if (type == typeof(System.Int32)) { |
734 | createCol(shapes, "Shape", typeof(System.Int32)); | 805 | return "integer"; |
735 | // vectors | 806 | } else if (type == typeof(System.Double)) { |
736 | createCol(shapes, "ScaleX", typeof(System.Double)); | 807 | return "float"; |
737 | createCol(shapes, "ScaleY", typeof(System.Double)); | 808 | } else if (type == typeof(System.Byte[])) { |
738 | createCol(shapes, "ScaleZ", typeof(System.Double)); | 809 | return "blob"; |
739 | // paths | 810 | } else { |
740 | createCol(shapes, "PCode", typeof(System.Int32)); | 811 | return "string"; |
741 | createCol(shapes, "PathBegin", typeof(System.Int32)); | 812 | } |
742 | createCol(shapes, "PathEnd", typeof(System.Int32)); | ||
743 | createCol(shapes, "PathScaleX", typeof(System.Int32)); | ||
744 | createCol(shapes, "PathScaleY", typeof(System.Int32)); | ||
745 | createCol(shapes, "PathShearX", typeof(System.Int32)); | ||
746 | createCol(shapes, "PathShearY", typeof(System.Int32)); | ||
747 | createCol(shapes, "PathSkew", typeof(System.Int32)); | ||
748 | createCol(shapes, "PathCurve", typeof(System.Int32)); | ||
749 | createCol(shapes, "PathRadiusOffset", typeof(System.Int32)); | ||
750 | createCol(shapes, "PathRevolutions", typeof(System.Int32)); | ||
751 | createCol(shapes, "PathTaperX", typeof(System.Int32)); | ||
752 | createCol(shapes, "PathTaperY", typeof(System.Int32)); | ||
753 | createCol(shapes, "PathTwist", typeof(System.Int32)); | ||
754 | createCol(shapes, "PathTwistBegin", typeof(System.Int32)); | ||
755 | // profile | ||
756 | createCol(shapes, "ProfileBegin", typeof(System.Int32)); | ||
757 | createCol(shapes, "ProfileEnd", typeof(System.Int32)); | ||
758 | createCol(shapes, "ProfileCurve", typeof(System.Int32)); | ||
759 | createCol(shapes, "ProfileHollow", typeof(System.Int32)); | ||
760 | // text TODO: this isn't right, but I'm not sure the right | ||
761 | // way to specify this as a blob atm | ||
762 | createCol(shapes, "Texture", typeof(System.Byte[])); | ||
763 | createCol(shapes, "ExtraParams", typeof(System.Byte[])); | ||
764 | |||
765 | shapes.PrimaryKey = new DataColumn[] { shapes.Columns["UUID"] }; | ||
766 | |||
767 | return shapes; | ||
768 | } | 813 | } |
769 | } | 814 | } |
770 | } | 815 | } |