aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimMySQLStorage.cs
diff options
context:
space:
mode:
authorMike Mazur2009-02-16 02:25:44 +0000
committerMike Mazur2009-02-16 02:25:44 +0000
commit16fa7f516a484e9f21fac34262214b3d9d761823 (patch)
tree925c10831c04d053b707857ffa785482316d4dcb /OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimMySQLStorage.cs
parentAdded OpenSim asset frontend plugin. (diff)
downloadopensim-SC_OLD-16fa7f516a484e9f21fac34262214b3d9d761823.zip
opensim-SC_OLD-16fa7f516a484e9f21fac34262214b3d9d761823.tar.gz
opensim-SC_OLD-16fa7f516a484e9f21fac34262214b3d9d761823.tar.bz2
opensim-SC_OLD-16fa7f516a484e9f21fac34262214b3d9d761823.tar.xz
Converted to Linux newlines.
Diffstat (limited to 'OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimMySQLStorage.cs')
-rw-r--r--OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimMySQLStorage.cs622
1 files changed, 311 insertions, 311 deletions
diff --git a/OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimMySQLStorage.cs b/OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimMySQLStorage.cs
index 36528b0..48fa25b 100644
--- a/OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimMySQLStorage.cs
+++ b/OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimMySQLStorage.cs
@@ -1,311 +1,311 @@
1/* 1/*
2 * Copyright (c) 2008 Intel Corporation 2 * Copyright (c) 2008 Intel Corporation
3 * All rights reserved. 3 * All rights reserved.
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 7 *
8 * -- Redistributions of source code must retain the above copyright 8 * -- Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * -- Redistributions in binary form must reproduce the above copyright 10 * -- Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the 11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution. 12 * documentation and/or other materials provided with the distribution.
13 * -- Neither the name of the Intel Corporation nor the names of its 13 * -- Neither the name of the Intel Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from 14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission. 15 * this software without specific prior written permission.
16 * 16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS 20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */ 28 */
29 29
30using System; 30using System;
31using System.Collections.Generic; 31using System.Collections.Generic;
32using System.Net; 32using System.Net;
33using System.Data; 33using System.Data;
34using MySql.Data.MySqlClient; 34using MySql.Data.MySqlClient;
35using ExtensionLoader; 35using ExtensionLoader;
36using ExtensionLoader.Config; 36using ExtensionLoader.Config;
37using OpenMetaverse; 37using OpenMetaverse;
38using OpenMetaverse.StructuredData; 38using OpenMetaverse.StructuredData;
39 39
40namespace OpenSim.Grid.AssetInventoryServer.Extensions 40namespace OpenSim.Grid.AssetInventoryServer.Extensions
41{ 41{
42 public class OpenSimMySQLStorage : IExtension<AssetInventoryServer>, IStorageProvider 42 public class OpenSimMySQLStorage : IExtension<AssetInventoryServer>, IStorageProvider
43 { 43 {
44 const string EXTENSION_NAME = "OpenSimMySQLStorage"; // Used in metrics reporting 44 const string EXTENSION_NAME = "OpenSimMySQLStorage"; // Used in metrics reporting
45 45
46 AssetInventoryServer server; 46 AssetInventoryServer server;
47 47
48 public OpenSimMySQLStorage() 48 public OpenSimMySQLStorage()
49 { 49 {
50 } 50 }
51 51
52 #region Required Interfaces 52 #region Required Interfaces
53 53
54 public void Start(AssetInventoryServer server) 54 public void Start(AssetInventoryServer server)
55 { 55 {
56 this.server = server; 56 this.server = server;
57 57
58 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) 58 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
59 { 59 {
60 try 60 try
61 { 61 {
62 dbConnection.Open(); 62 dbConnection.Open();
63 Logger.Log.Info("Connected to MySQL storage backend: " + dbConnection.ServerVersion); 63 Logger.Log.Info("Connected to MySQL storage backend: " + dbConnection.ServerVersion);
64 } 64 }
65 catch (MySqlException ex) 65 catch (MySqlException ex)
66 { 66 {
67 Logger.Log.Error("Connection to MySQL storage backend failed: " + ex.Message); 67 Logger.Log.Error("Connection to MySQL storage backend failed: " + ex.Message);
68 } 68 }
69 } 69 }
70 } 70 }
71 71
72 public void Stop() 72 public void Stop()
73 { 73 {
74 } 74 }
75 75
76 public BackendResponse TryFetchMetadata(UUID assetID, out Metadata metadata) 76 public BackendResponse TryFetchMetadata(UUID assetID, out Metadata metadata)
77 { 77 {
78 metadata = null; 78 metadata = null;
79 BackendResponse ret; 79 BackendResponse ret;
80 80
81 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) 81 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
82 { 82 {
83 IDataReader reader; 83 IDataReader reader;
84 84
85 try 85 try
86 { 86 {
87 dbConnection.Open(); 87 dbConnection.Open();
88 88
89 IDbCommand command = dbConnection.CreateCommand(); 89 IDbCommand command = dbConnection.CreateCommand();
90 command.CommandText = String.Format("SELECT name,description,assetType,temporary FROM assets WHERE id='{0}'", assetID.ToString()); 90 command.CommandText = String.Format("SELECT name,description,assetType,temporary FROM assets WHERE id='{0}'", assetID.ToString());
91 reader = command.ExecuteReader(); 91 reader = command.ExecuteReader();
92 92
93 if (reader.Read()) 93 if (reader.Read())
94 { 94 {
95 metadata = new Metadata(); 95 metadata = new Metadata();
96 metadata.CreationDate = OpenMetaverse.Utils.Epoch; 96 metadata.CreationDate = OpenMetaverse.Utils.Epoch;
97 metadata.SHA1 = null; 97 metadata.SHA1 = null;
98 metadata.ID = assetID; 98 metadata.ID = assetID;
99 metadata.Name = reader.GetString(0); 99 metadata.Name = reader.GetString(0);
100 metadata.Description = reader.GetString(1); 100 metadata.Description = reader.GetString(1);
101 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2)); 101 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2));
102 metadata.Temporary = reader.GetBoolean(3); 102 metadata.Temporary = reader.GetBoolean(3);
103 103
104 ret = BackendResponse.Success; 104 ret = BackendResponse.Success;
105 } 105 }
106 else 106 else
107 { 107 {
108 ret = BackendResponse.NotFound; 108 ret = BackendResponse.NotFound;
109 } 109 }
110 } 110 }
111 catch (MySqlException ex) 111 catch (MySqlException ex)
112 { 112 {
113 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); 113 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
114 ret = BackendResponse.Failure; 114 ret = BackendResponse.Failure;
115 } 115 }
116 } 116 }
117 117
118 server.MetricsProvider.LogAssetMetadataFetch(EXTENSION_NAME, ret, assetID, DateTime.Now); 118 server.MetricsProvider.LogAssetMetadataFetch(EXTENSION_NAME, ret, assetID, DateTime.Now);
119 return ret; 119 return ret;
120 } 120 }
121 121
122 public BackendResponse TryFetchData(UUID assetID, out byte[] assetData) 122 public BackendResponse TryFetchData(UUID assetID, out byte[] assetData)
123 { 123 {
124 assetData = null; 124 assetData = null;
125 BackendResponse ret; 125 BackendResponse ret;
126 126
127 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) 127 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
128 { 128 {
129 IDataReader reader; 129 IDataReader reader;
130 130
131 try 131 try
132 { 132 {
133 dbConnection.Open(); 133 dbConnection.Open();
134 134
135 IDbCommand command = dbConnection.CreateCommand(); 135 IDbCommand command = dbConnection.CreateCommand();
136 command.CommandText = String.Format("SELECT data FROM assets WHERE id='{0}'", assetID.ToString()); 136 command.CommandText = String.Format("SELECT data FROM assets WHERE id='{0}'", assetID.ToString());
137 reader = command.ExecuteReader(); 137 reader = command.ExecuteReader();
138 138
139 if (reader.Read()) 139 if (reader.Read())
140 { 140 {
141 assetData = (byte[])reader.GetValue(0); 141 assetData = (byte[])reader.GetValue(0);
142 ret = BackendResponse.Success; 142 ret = BackendResponse.Success;
143 } 143 }
144 else 144 else
145 { 145 {
146 ret = BackendResponse.NotFound; 146 ret = BackendResponse.NotFound;
147 } 147 }
148 } 148 }
149 catch (MySqlException ex) 149 catch (MySqlException ex)
150 { 150 {
151 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); 151 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
152 ret = BackendResponse.Failure; 152 ret = BackendResponse.Failure;
153 } 153 }
154 } 154 }
155 155
156 server.MetricsProvider.LogAssetDataFetch(EXTENSION_NAME, ret, assetID, (assetData != null ? assetData.Length : 0), DateTime.Now); 156 server.MetricsProvider.LogAssetDataFetch(EXTENSION_NAME, ret, assetID, (assetData != null ? assetData.Length : 0), DateTime.Now);
157 return ret; 157 return ret;
158 } 158 }
159 159
160 public BackendResponse TryFetchDataMetadata(UUID assetID, out Metadata metadata, out byte[] assetData) 160 public BackendResponse TryFetchDataMetadata(UUID assetID, out Metadata metadata, out byte[] assetData)
161 { 161 {
162 metadata = null; 162 metadata = null;
163 assetData = null; 163 assetData = null;
164 BackendResponse ret; 164 BackendResponse ret;
165 165
166 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) 166 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
167 { 167 {
168 IDataReader reader; 168 IDataReader reader;
169 169
170 try 170 try
171 { 171 {
172 dbConnection.Open(); 172 dbConnection.Open();
173 173
174 IDbCommand command = dbConnection.CreateCommand(); 174 IDbCommand command = dbConnection.CreateCommand();
175 command.CommandText = String.Format("SELECT name,description,assetType,temporary,data FROM assets WHERE id='{0}'", assetID.ToString()); 175 command.CommandText = String.Format("SELECT name,description,assetType,temporary,data FROM assets WHERE id='{0}'", assetID.ToString());
176 reader = command.ExecuteReader(); 176 reader = command.ExecuteReader();
177 177
178 if (reader.Read()) 178 if (reader.Read())
179 { 179 {
180 metadata = new Metadata(); 180 metadata = new Metadata();
181 metadata.CreationDate = OpenMetaverse.Utils.Epoch; 181 metadata.CreationDate = OpenMetaverse.Utils.Epoch;
182 metadata.SHA1 = null; 182 metadata.SHA1 = null;
183 metadata.ID = assetID; 183 metadata.ID = assetID;
184 metadata.Name = reader.GetString(0); 184 metadata.Name = reader.GetString(0);
185 metadata.Description = reader.GetString(1); 185 metadata.Description = reader.GetString(1);
186 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2)); 186 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2));
187 metadata.Temporary = reader.GetBoolean(3); 187 metadata.Temporary = reader.GetBoolean(3);
188 188
189 assetData = (byte[])reader.GetValue(4); 189 assetData = (byte[])reader.GetValue(4);
190 190
191 ret = BackendResponse.Success; 191 ret = BackendResponse.Success;
192 } 192 }
193 else 193 else
194 { 194 {
195 ret = BackendResponse.NotFound; 195 ret = BackendResponse.NotFound;
196 } 196 }
197 } 197 }
198 catch (MySqlException ex) 198 catch (MySqlException ex)
199 { 199 {
200 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); 200 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
201 ret = BackendResponse.Failure; 201 ret = BackendResponse.Failure;
202 } 202 }
203 } 203 }
204 204
205 server.MetricsProvider.LogAssetMetadataFetch(EXTENSION_NAME, ret, assetID, DateTime.Now); 205 server.MetricsProvider.LogAssetMetadataFetch(EXTENSION_NAME, ret, assetID, DateTime.Now);
206 server.MetricsProvider.LogAssetDataFetch(EXTENSION_NAME, ret, assetID, (assetData != null ? assetData.Length : 0), DateTime.Now); 206 server.MetricsProvider.LogAssetDataFetch(EXTENSION_NAME, ret, assetID, (assetData != null ? assetData.Length : 0), DateTime.Now);
207 return ret; 207 return ret;
208 } 208 }
209 209
210 public BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData, out UUID assetID) 210 public BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData, out UUID assetID)
211 { 211 {
212 assetID = metadata.ID = UUID.Random(); 212 assetID = metadata.ID = UUID.Random();
213 return TryCreateAsset(metadata, assetData); 213 return TryCreateAsset(metadata, assetData);
214 } 214 }
215 215
216 public BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData) 216 public BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData)
217 { 217 {
218 BackendResponse ret; 218 BackendResponse ret;
219 219
220 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) 220 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
221 { 221 {
222 try 222 try
223 { 223 {
224 dbConnection.Open(); 224 dbConnection.Open();
225 225
226 MySqlCommand command = new MySqlCommand( 226 MySqlCommand command = new MySqlCommand(
227 "REPLACE INTO assets (name,description,assetType,local,temporary,data,id) VALUES " + 227 "REPLACE INTO assets (name,description,assetType,local,temporary,data,id) VALUES " +
228 "(?name,?description,?assetType,?local,?temporary,?data,?id)", dbConnection); 228 "(?name,?description,?assetType,?local,?temporary,?data,?id)", dbConnection);
229 229
230 command.Parameters.AddWithValue("?name", metadata.Name); 230 command.Parameters.AddWithValue("?name", metadata.Name);
231 command.Parameters.AddWithValue("?description", metadata.Description); 231 command.Parameters.AddWithValue("?description", metadata.Description);
232 command.Parameters.AddWithValue("?assetType", Utils.ContentTypeToSLAssetType(metadata.ContentType)); 232 command.Parameters.AddWithValue("?assetType", Utils.ContentTypeToSLAssetType(metadata.ContentType));
233 command.Parameters.AddWithValue("?local", 0); 233 command.Parameters.AddWithValue("?local", 0);
234 command.Parameters.AddWithValue("?temporary", metadata.Temporary); 234 command.Parameters.AddWithValue("?temporary", metadata.Temporary);
235 command.Parameters.AddWithValue("?data", assetData); 235 command.Parameters.AddWithValue("?data", assetData);
236 command.Parameters.AddWithValue("?id", metadata.ID.ToString()); 236 command.Parameters.AddWithValue("?id", metadata.ID.ToString());
237 237
238 int rowsAffected = command.ExecuteNonQuery(); 238 int rowsAffected = command.ExecuteNonQuery();
239 if (rowsAffected == 1) 239 if (rowsAffected == 1)
240 { 240 {
241 ret = BackendResponse.Success; 241 ret = BackendResponse.Success;
242 } 242 }
243 else if (rowsAffected == 2) 243 else if (rowsAffected == 2)
244 { 244 {
245 Logger.Log.Info("Replaced asset " + metadata.ID.ToString()); 245 Logger.Log.Info("Replaced asset " + metadata.ID.ToString());
246 ret = BackendResponse.Success; 246 ret = BackendResponse.Success;
247 } 247 }
248 else 248 else
249 { 249 {
250 Logger.Log.ErrorFormat("MySQL REPLACE query affected {0} rows", rowsAffected); 250 Logger.Log.ErrorFormat("MySQL REPLACE query affected {0} rows", rowsAffected);
251 ret = BackendResponse.Failure; 251 ret = BackendResponse.Failure;
252 } 252 }
253 } 253 }
254 catch (MySqlException ex) 254 catch (MySqlException ex)
255 { 255 {
256 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); 256 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
257 ret = BackendResponse.Failure; 257 ret = BackendResponse.Failure;
258 } 258 }
259 } 259 }
260 260
261 server.MetricsProvider.LogAssetCreate(EXTENSION_NAME, ret, metadata.ID, assetData.Length, DateTime.Now); 261 server.MetricsProvider.LogAssetCreate(EXTENSION_NAME, ret, metadata.ID, assetData.Length, DateTime.Now);
262 return ret; 262 return ret;
263 } 263 }
264 264
265 public int ForEach(Action<Metadata> action, int start, int count) 265 public int ForEach(Action<Metadata> action, int start, int count)
266 { 266 {
267 int rowCount = 0; 267 int rowCount = 0;
268 268
269 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) 269 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
270 { 270 {
271 MySqlDataReader reader; 271 MySqlDataReader reader;
272 272
273 try 273 try
274 { 274 {
275 dbConnection.Open(); 275 dbConnection.Open();
276 276
277 MySqlCommand command = dbConnection.CreateCommand(); 277 MySqlCommand command = dbConnection.CreateCommand();
278 command.CommandText = String.Format("SELECT name,description,assetType,temporary,data,id FROM assets LIMIT {0}, {1}", 278 command.CommandText = String.Format("SELECT name,description,assetType,temporary,data,id FROM assets LIMIT {0}, {1}",
279 start, count); 279 start, count);
280 reader = command.ExecuteReader(); 280 reader = command.ExecuteReader();
281 } 281 }
282 catch (MySqlException ex) 282 catch (MySqlException ex)
283 { 283 {
284 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); 284 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
285 return 0; 285 return 0;
286 } 286 }
287 287
288 while (reader.Read()) 288 while (reader.Read())
289 { 289 {
290 Metadata metadata = new Metadata(); 290 Metadata metadata = new Metadata();
291 metadata.CreationDate = OpenMetaverse.Utils.Epoch; 291 metadata.CreationDate = OpenMetaverse.Utils.Epoch;
292 metadata.Description = reader.GetString(1); 292 metadata.Description = reader.GetString(1);
293 metadata.ID = UUID.Parse(reader.GetString(5)); 293 metadata.ID = UUID.Parse(reader.GetString(5));
294 metadata.Name = reader.GetString(0); 294 metadata.Name = reader.GetString(0);
295 metadata.SHA1 = OpenMetaverse.Utils.SHA1((byte[])reader.GetValue(4)); 295 metadata.SHA1 = OpenMetaverse.Utils.SHA1((byte[])reader.GetValue(4));
296 metadata.Temporary = reader.GetBoolean(3); 296 metadata.Temporary = reader.GetBoolean(3);
297 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2)); 297 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2));
298 298
299 action(metadata); 299 action(metadata);
300 ++rowCount; 300 ++rowCount;
301 } 301 }
302 302
303 reader.Close(); 303 reader.Close();
304 } 304 }
305 305
306 return rowCount; 306 return rowCount;
307 } 307 }
308 308
309 #endregion Required Interfaces 309 #endregion Required Interfaces
310 } 310 }
311} 311}