PageRenderTime 60ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/Aurora/DataManagerPlugins/SQLite/SQLiteDataManager.cs

https://bitbucket.org/VirtualReality/software-testing
C# | 1410 lines | 1376 code | 7 blank | 27 comment | 6 complexity | 9f028426089088f6220cd79ea39aba70 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (c) Contributors, http://aurora-sim.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 Aurora-Sim 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. using System;
  28. using System.Collections.Generic;
  29. using System.Data;
  30. using System.IO;
  31. using System.Linq;
  32. using System.Reflection;
  33. using Aurora.DataManager.Migration;
  34. using Aurora.Framework;
  35. using Aurora.Framework.ConsoleFramework;
  36. using Aurora.Framework.Services;
  37. using Aurora.Framework.Utilities;
  38. using Community.CsharpSqlite.SQLiteClient;
  39. using OpenMetaverse;
  40. //using System.Data.Sqlite;
  41. namespace Aurora.DataManager.SQLite
  42. {
  43. public class SQLiteLoader : DataManagerBase
  44. {
  45. protected Dictionary<string, FieldInfo> m_Fields = new Dictionary<string, FieldInfo>();
  46. protected string _connectionString;
  47. protected static bool _hadToConvert = false;
  48. protected static Dictionary<string, object> _locks = new Dictionary<string, object>();
  49. protected string _fileName;
  50. protected object GetLock()
  51. {
  52. lock (_locks)
  53. {
  54. if (!_locks.ContainsKey(_fileName))
  55. _locks.Add(_fileName, new object());
  56. return _locks[_fileName];
  57. }
  58. }
  59. public override string Identifier
  60. {
  61. get { return "SQLiteConnector"; }
  62. }
  63. #region Database
  64. public override void ConnectToDatabase(string connectionString, string migratorName, bool validateTables)
  65. {
  66. _connectionString = connectionString;
  67. string[] s1 = _connectionString.Split(new[] {"Data Source=", ","}, StringSplitOptions.RemoveEmptyEntries);
  68. bool needsUTFConverted = false;
  69. _fileName = Path.GetFileName(s1[0]);
  70. if (s1[0].EndsWith(";"))
  71. {
  72. _fileName = Path.GetFileNameWithoutExtension(s1[1].Substring(7, s1[1].Length - 7)) + "utf8.db";
  73. _connectionString = "Data Source=file://" + _fileName;
  74. s1 = new string[1] {"file://" + _fileName};
  75. needsUTFConverted = true;
  76. _hadToConvert = true;
  77. }
  78. if (_fileName == s1[0]) //Only add this if we arn't an absolute path already
  79. _connectionString = _connectionString.Replace("Data Source=",
  80. "Data Source=" + Util.BasePathCombine("") + "\\");
  81. SqliteConnection connection = new SqliteConnection(_connectionString);
  82. connection.Open();
  83. var migrationManager = new MigrationManager(this, migratorName, validateTables);
  84. migrationManager.DetermineOperation();
  85. migrationManager.ExecuteOperation();
  86. connection.Close();
  87. if (needsUTFConverted && _hadToConvert)
  88. {
  89. string file =
  90. connectionString.Split(new[] {"Data Source=", ","}, StringSplitOptions.RemoveEmptyEntries)[1]
  91. .Substring(7);
  92. if (File.Exists(file))
  93. {
  94. //UTF16 db, gotta convert it
  95. System.Data.SQLite.SQLiteConnection conn =
  96. new System.Data.SQLite.SQLiteConnection("Data Source=" + file +
  97. ";version=3;UseUTF16Encoding=True");
  98. conn.Open();
  99. var RetVal = new List<string>();
  100. using (var cmd = new System.Data.SQLite.SQLiteCommand("SELECT name FROM Sqlite_master", conn))
  101. {
  102. using (IDataReader rdr = cmd.ExecuteReader())
  103. {
  104. while (rdr.Read())
  105. {
  106. for (int i = 0; i < rdr.FieldCount; i++)
  107. {
  108. RetVal.Add(rdr.GetValue(i).ToString());
  109. }
  110. }
  111. }
  112. }
  113. foreach (string table in RetVal)
  114. {
  115. if (TableExists(table) && !table.StartsWith("sqlite") && !table.StartsWith("idx_") &&
  116. table != "aurora_migrator_version")
  117. {
  118. var retVal = new List<object[]>();
  119. using (var cmd = new System.Data.SQLite.SQLiteCommand("SELECT * FROM " + table, conn))
  120. {
  121. using (IDataReader reader = cmd.ExecuteReader())
  122. {
  123. while (reader.Read())
  124. {
  125. List<object> obs = new List<object>();
  126. for (int i = 0; i < reader.FieldCount; i++)
  127. {
  128. Type r = reader[i].GetType();
  129. if (r == typeof (DBNull))
  130. obs.Add(null);
  131. else
  132. obs.Add(reader[i].ToString());
  133. }
  134. retVal.Add(obs.ToArray());
  135. }
  136. }
  137. }
  138. try
  139. {
  140. if (retVal.Count > 0)
  141. InsertMultiple(table, retVal);
  142. }
  143. catch
  144. {
  145. }
  146. }
  147. }
  148. }
  149. }
  150. }
  151. public override void CloseDatabase(DataReaderConnection conn)
  152. {
  153. if (conn == null)
  154. return;
  155. if (conn.DataReader != null)
  156. conn.DataReader.Close();
  157. if (conn != null && conn.Connection != null && conn.Connection is SqliteConnection)
  158. ((SqliteConnection) conn.Connection).Close();
  159. }
  160. #endregion
  161. #region Query
  162. protected void PrepReader(ref SqliteCommand cmd)
  163. {
  164. int retries = 0;
  165. restart:
  166. try
  167. {
  168. SqliteConnection connection = new SqliteConnection(_connectionString);
  169. connection.Open();
  170. cmd.Connection = connection;
  171. }
  172. catch (SqliteBusyException ex)
  173. {
  174. if (retries++ > 5)
  175. MainConsole.Instance.Warn("[SqliteDataManager]: Exception processing command: " + cmd.CommandText +
  176. ", Exception: " +
  177. ex);
  178. else
  179. goto restart;
  180. }
  181. catch (SqliteException ex)
  182. {
  183. MainConsole.Instance.Warn("[SqliteDataManager]: Exception processing command: " + cmd.CommandText +
  184. ", Exception: " +
  185. ex);
  186. //throw ex;
  187. }
  188. catch (Exception ex)
  189. {
  190. MainConsole.Instance.Warn("[SqliteDataManager]: Exception processing command: " + cmd.CommandText +
  191. ", Exception: " +
  192. ex);
  193. throw ex;
  194. }
  195. }
  196. protected SqliteCommand PrepReader(string query)
  197. {
  198. try
  199. {
  200. SqliteConnection connection = new SqliteConnection(_connectionString);
  201. connection.Open();
  202. var cmd = connection.CreateCommand();
  203. cmd.CommandText = query;
  204. return cmd as SqliteCommand;
  205. }
  206. catch (SqliteException)
  207. {
  208. //throw ex;
  209. }
  210. catch (Exception ex)
  211. {
  212. throw ex;
  213. }
  214. return null;
  215. }
  216. protected int ExecuteNonQuery(SqliteCommand cmd)
  217. {
  218. int retries = 0;
  219. restart:
  220. try
  221. {
  222. lock (GetLock())
  223. {
  224. PrepReader(ref cmd);
  225. UnescapeSql(cmd);
  226. var value = cmd.ExecuteNonQuery();
  227. cmd.Connection.Close();
  228. return value;
  229. }
  230. }
  231. catch (SqliteBusyException ex)
  232. {
  233. if (retries++ > 5)
  234. MainConsole.Instance.Warn("[SqliteDataManager]: Exception processing command: " + cmd.CommandText +
  235. ", Exception: " +
  236. ex);
  237. else
  238. goto restart;
  239. return 0;
  240. }
  241. catch (SqliteException ex)
  242. {
  243. MainConsole.Instance.Warn("[SqliteDataManager]: Exception processing command: " + cmd.CommandText +
  244. ", Exception: " +
  245. ex);
  246. }
  247. catch (Exception ex)
  248. {
  249. MainConsole.Instance.Warn("[SqliteDataManager]: Exception processing command: " + cmd.CommandText +
  250. ", Exception: " +
  251. ex);
  252. throw ex;
  253. }
  254. return 0;
  255. }
  256. private static void UnescapeSql(SqliteCommand cmd)
  257. {
  258. foreach (SqliteParameter v in cmd.Parameters)
  259. {
  260. if (v.Value == null)
  261. {
  262. v.Value = "";
  263. }
  264. if (v.Value.ToString().Contains("\\'"))
  265. {
  266. v.Value = v.Value.ToString().Replace("\\'", "\'");
  267. }
  268. if (v.Value.ToString().Contains("\\\""))
  269. {
  270. v.Value = v.Value.ToString().Replace("\\\"", "\"");
  271. }
  272. }
  273. }
  274. protected void CloseReaderCommand(SqliteCommand cmd)
  275. {
  276. cmd.Connection.Close();
  277. cmd.Parameters.Clear();
  278. //cmd.Dispose ();
  279. }
  280. private void AddParams(ref SqliteCommand cmd, Dictionary<string, object> ps)
  281. {
  282. foreach (KeyValuePair<string, object> p in ps)
  283. AddParam(ref cmd, p.Key, p.Value);
  284. }
  285. private void AddParam(ref SqliteCommand cmd, string key, object value)
  286. {
  287. AddParam(ref cmd, key, value, false);
  288. }
  289. private void AddParam(ref SqliteCommand cmd, string key, object value, bool convertByteString)
  290. {
  291. if (value is UUID)
  292. cmd.Parameters.Add(key, value.ToString());
  293. else if (value is Vector3)
  294. cmd.Parameters.Add(key, value.ToString());
  295. else if (value is Quaternion)
  296. cmd.Parameters.Add(key, value.ToString());
  297. else if (value is byte[] && convertByteString)
  298. cmd.Parameters.Add(key, Utils.BytesToString((byte[]) value));
  299. else
  300. cmd.Parameters.Add(key, value);
  301. }
  302. public override List<string> QueryFullData(string whereClause, string table, string wantedValue)
  303. {
  304. string query = String.Format("select {0} from {1} {2} ", wantedValue, table, whereClause);
  305. return QueryFullData2(query);
  306. }
  307. public override List<string> QueryFullData(string whereClause, QueryTables tables, string wantedValue)
  308. {
  309. string query = string.Format("SELECT {0} FROM {1} {2} ", wantedValue, tables.ToSQL(), whereClause);
  310. return QueryFullData2(query);
  311. }
  312. private List<string> QueryFullData2(string query)
  313. {
  314. var cmd = PrepReader(query);
  315. lock (GetLock())
  316. {
  317. using (SqliteDataReader reader = cmd.ExecuteReader())
  318. {
  319. var RetVal = new List<string>();
  320. while (reader.Read())
  321. {
  322. if (reader.HasRows)
  323. {
  324. for (int i = 0; i < reader.FieldCount; i++)
  325. {
  326. RetVal.Add(reader.GetValue(i).ToString());
  327. }
  328. }
  329. }
  330. //reader.Close();
  331. CloseReaderCommand(cmd);
  332. return RetVal;
  333. }
  334. }
  335. }
  336. public override DataReaderConnection QueryData(string whereClause, string table, string wantedValue)
  337. {
  338. string query = String.Format("select {0} from {1} {2}", wantedValue, table, whereClause);
  339. SqliteConnection conn;
  340. var data = QueryData2(query, out conn);
  341. return new DataReaderConnection {DataReader = data, Connection = conn};
  342. }
  343. public override DataReaderConnection QueryData(string whereClause, QueryTables tables, string wantedValue)
  344. {
  345. string query = string.Format("SELECT {0} FROM {1} {2}", wantedValue, tables, whereClause);
  346. SqliteConnection conn;
  347. var data = QueryData2(query, out conn);
  348. return new DataReaderConnection {DataReader = data, Connection = conn};
  349. }
  350. private IDataReader QueryData2(string query, out SqliteConnection conn)
  351. {
  352. var cmd = PrepReader(query);
  353. conn = cmd.Connection;
  354. return cmd.ExecuteReader();
  355. }
  356. public override List<string> Query(string[] wantedValue, string table, QueryFilter queryFilter,
  357. Dictionary<string, bool> sort, uint? start, uint? count)
  358. {
  359. string query = string.Format("SELECT {0} FROM {1}", string.Join(", ", wantedValue), table);
  360. return Query2(query, queryFilter, sort, start, count);
  361. }
  362. public override List<string> Query(string[] wantedValue, QueryTables tables, QueryFilter queryFilter,
  363. Dictionary<string, bool> sort, uint? start, uint? count)
  364. {
  365. string query = string.Format("SELECT {0} FROM {1} ", string.Join(", ", wantedValue), tables.ToSQL());
  366. return Query2(query, queryFilter, sort, start, count);
  367. }
  368. private List<string> Query2(string query, QueryFilter queryFilter, Dictionary<string, bool> sort, uint? start,
  369. uint? count)
  370. {
  371. Dictionary<string, object> ps = new Dictionary<string, object>();
  372. List<string> retVal = new List<string>();
  373. List<string> parts = new List<string>();
  374. if (queryFilter != null && queryFilter.Count > 0)
  375. {
  376. query += " WHERE " + queryFilter.ToSQL(':', out ps);
  377. }
  378. if (sort != null && sort.Count > 0)
  379. {
  380. parts = new List<string>();
  381. foreach (KeyValuePair<string, bool> sortOrder in sort)
  382. {
  383. parts.Add(string.Format("`{0}` {1}", sortOrder.Key, sortOrder.Value ? "ASC" : "DESC"));
  384. }
  385. query += " ORDER BY " + string.Join(", ", parts.ToArray());
  386. }
  387. if (start.HasValue)
  388. {
  389. query += " LIMIT " + start.Value.ToString();
  390. if (count.HasValue)
  391. {
  392. query += ", " + count.Value.ToString();
  393. }
  394. }
  395. int i = 0;
  396. var cmd = PrepReader(query);
  397. AddParams(ref cmd, ps);
  398. lock (GetLock())
  399. {
  400. using (SqliteDataReader reader = cmd.ExecuteReader())
  401. {
  402. var RetVal = new List<string>();
  403. while (reader.Read())
  404. {
  405. if (reader.HasRows)
  406. {
  407. for (i = 0; i < reader.FieldCount; i++)
  408. RetVal.Add(reader[i] == null ? null : reader[i].ToString());
  409. }
  410. }
  411. //reader.Close();
  412. CloseReaderCommand(cmd);
  413. return RetVal;
  414. }
  415. }
  416. }
  417. public override Dictionary<string, List<string>> QueryNames(string[] keyRow, object[] keyValue, string table,
  418. string wantedValue)
  419. {
  420. string query = String.Format("select {0} from {1} where ", wantedValue, table);
  421. return QueryNames2(keyRow, keyValue, query);
  422. }
  423. public override Dictionary<string, List<string>> QueryNames(string[] keyRow, object[] keyValue,
  424. QueryTables tables, string wantedValue)
  425. {
  426. string query = string.Format("SELECT {0} FROM {1} where ", wantedValue, tables.ToSQL());
  427. return QueryNames2(keyRow, keyValue, query);
  428. }
  429. private Dictionary<string, List<string>> QueryNames2(string[] keyRow, object[] keyValue, string query)
  430. {
  431. Dictionary<string, object> ps = new Dictionary<string, object>();
  432. int i = 0;
  433. foreach (object value in keyValue)
  434. {
  435. ps[":" + keyRow[i].Replace("`", "")] = value;
  436. query += String.Format("{0} = :{1} and ", keyRow[i], keyRow[i].Replace("`", ""));
  437. i++;
  438. }
  439. query = query.Remove(query.Length - 5);
  440. var cmd = PrepReader(query);
  441. AddParams(ref cmd, ps);
  442. lock (GetLock())
  443. {
  444. using (SqliteDataReader reader = cmd.ExecuteReader())
  445. {
  446. var RetVal = new Dictionary<string, List<string>>();
  447. while (reader.Read())
  448. {
  449. if (reader.HasRows)
  450. {
  451. for (i = 0; i < reader.FieldCount; i++)
  452. {
  453. Type r = reader[i].GetType();
  454. if (r == typeof (DBNull))
  455. AddValueToList(ref RetVal, reader.GetName(i), null);
  456. else
  457. AddValueToList(ref RetVal, reader.GetName(i), reader[i].ToString());
  458. }
  459. }
  460. }
  461. //reader.Close();
  462. CloseReaderCommand(cmd);
  463. return RetVal;
  464. }
  465. }
  466. }
  467. private void AddValueToList(ref Dictionary<string, List<string>> dic, string key, string value)
  468. {
  469. if (!dic.ContainsKey(key))
  470. dic.Add(key, new List<string>());
  471. dic[key].Add(value);
  472. }
  473. #endregion
  474. #region Update
  475. public override bool Update(string table, Dictionary<string, object> values,
  476. Dictionary<string, int> incrementValues, QueryFilter queryFilter, uint? start,
  477. uint? count)
  478. {
  479. if ((values == null || values.Count < 1) && (incrementValues == null || incrementValues.Count < 1))
  480. {
  481. MainConsole.Instance.Warn("Update attempted with no values");
  482. return false;
  483. }
  484. string query = string.Format("UPDATE {0}", table);
  485. Dictionary<string, object> ps = new Dictionary<string, object>();
  486. string filter = "";
  487. if (queryFilter != null && queryFilter.Count > 0)
  488. {
  489. filter = " WHERE " + queryFilter.ToSQL(':', out ps);
  490. }
  491. List<string> parts = new List<string>();
  492. if (values != null)
  493. {
  494. foreach (KeyValuePair<string, object> value in values)
  495. {
  496. string key = ":updateSet_" + value.Key.Replace("`", "");
  497. ps[key] = value.Value;
  498. parts.Add(string.Format("{0} = {1}", value.Key, key));
  499. }
  500. }
  501. if (incrementValues != null)
  502. {
  503. foreach (KeyValuePair<string, int> value in incrementValues)
  504. {
  505. string key = ":updateSet_increment_" + value.Key.Replace("`", "");
  506. ps[key] = value.Value;
  507. parts.Add(string.Format("{0} = {0} + {1}", value.Key, key));
  508. }
  509. }
  510. query += " SET " + string.Join(", ", parts.ToArray()) + filter;
  511. if (start.HasValue)
  512. {
  513. query += " LIMIT " + start.Value.ToString();
  514. if (count.HasValue)
  515. {
  516. query += ", " + count.Value.ToString();
  517. }
  518. }
  519. SqliteCommand cmd = new SqliteCommand(query);
  520. AddParams(ref cmd, ps);
  521. try
  522. {
  523. ExecuteNonQuery(cmd);
  524. }
  525. catch (SqliteException e)
  526. {
  527. MainConsole.Instance.Error("[SqliteLoader] Update(" + query + "), " + e);
  528. }
  529. CloseReaderCommand(cmd);
  530. return true;
  531. }
  532. #endregion
  533. #region Insert
  534. public override bool InsertMultiple(string table, List<object[]> values)
  535. {
  536. var cmd = new SqliteCommand();
  537. string query = String.Format("insert into {0} select ", table);
  538. int a = 0;
  539. foreach (object[] value in values)
  540. {
  541. foreach (object v in value)
  542. {
  543. query += ":" + Util.ConvertDecString(a) + ",";
  544. AddParam(ref cmd, Util.ConvertDecString(a++), v, true);
  545. }
  546. query = query.Remove(query.Length - 1);
  547. query += " union all select ";
  548. }
  549. query = query.Remove(query.Length - (" union all select ").Length);
  550. cmd.CommandText = query;
  551. ExecuteNonQuery(cmd);
  552. CloseReaderCommand(cmd);
  553. return true;
  554. }
  555. public override bool Insert(string table, object[] values)
  556. {
  557. var cmd = new SqliteCommand();
  558. string query = "";
  559. query = String.Format("insert into {0} values(", table);
  560. int a = 0;
  561. foreach (object value in values)
  562. {
  563. query += ":" + Util.ConvertDecString(a) + ",";
  564. AddParam(ref cmd, Util.ConvertDecString(a++), value, true);
  565. }
  566. query = query.Remove(query.Length - 1);
  567. query += ")";
  568. cmd.CommandText = query;
  569. ExecuteNonQuery(cmd);
  570. CloseReaderCommand(cmd);
  571. return true;
  572. }
  573. private bool InsertOrReplace(string table, Dictionary<string, object> row, bool insert)
  574. {
  575. SqliteCommand cmd = new SqliteCommand();
  576. string query = (insert ? "INSERT" : "REPLACE") + " INTO " + table + " (" +
  577. string.Join(", ", row.Keys.ToArray<string>()) + ")";
  578. List<string> ps = new List<string>();
  579. foreach (KeyValuePair<string, object> field in row)
  580. {
  581. string key = ":" + field.Key.Replace("`", "");
  582. ps.Add(key);
  583. AddParam(ref cmd, key, field.Value);
  584. }
  585. query += " VALUES( " + string.Join(", ", ps.ToArray<string>()) + " )";
  586. cmd.CommandText = query;
  587. try
  588. {
  589. ExecuteNonQuery(cmd);
  590. }
  591. catch (Exception e)
  592. {
  593. MainConsole.Instance.Error("[SqliteLoader] " + (insert ? "Insert" : "Replace") + "(" + query + "), " + e);
  594. }
  595. CloseReaderCommand(cmd);
  596. return true;
  597. }
  598. public override bool Insert(string table, Dictionary<string, object> row)
  599. {
  600. return InsertOrReplace(table, row, true);
  601. }
  602. public override bool Insert(string table, object[] values, string updateKey, object updateValue)
  603. {
  604. var cmd = new SqliteCommand();
  605. Dictionary<string, object> ps = new Dictionary<string, object>();
  606. string query = "";
  607. query = String.Format("insert into {0} values (", table);
  608. int i = 0;
  609. foreach (object value in values)
  610. {
  611. ps[":" + Util.ConvertDecString(i)] = value;
  612. query = String.Format(query + ":{0},", Util.ConvertDecString(i++));
  613. }
  614. query = query.Remove(query.Length - 1);
  615. query += ")";
  616. cmd.CommandText = query;
  617. AddParams(ref cmd, ps);
  618. try
  619. {
  620. ExecuteNonQuery(cmd);
  621. CloseReaderCommand(cmd);
  622. }
  623. //Execute the update then...
  624. catch (Exception)
  625. {
  626. cmd = new SqliteCommand();
  627. query = String.Format("UPDATE {0} SET {1} = '{2}'", table, updateKey, updateValue);
  628. cmd.CommandText = query;
  629. ExecuteNonQuery(cmd);
  630. CloseReaderCommand(cmd);
  631. }
  632. return true;
  633. }
  634. public override bool InsertSelect(string tableA, string[] fieldsA, string tableB, string[] valuesB)
  635. {
  636. SqliteCommand cmd = PrepReader(string.Format("INSERT INTO {0}{1} SELECT {2} FROM {3}",
  637. tableA,
  638. (fieldsA.Length > 0
  639. ? " (" + string.Join(", ", fieldsA) + ")"
  640. : ""),
  641. string.Join(", ", valuesB),
  642. tableB
  643. ));
  644. try
  645. {
  646. ExecuteNonQuery(cmd);
  647. }
  648. catch (Exception e)
  649. {
  650. MainConsole.Instance.Error("[SqliteLoader] INSERT .. SELECT (" + cmd.CommandText + "), " + e);
  651. }
  652. CloseReaderCommand(cmd);
  653. return true;
  654. }
  655. #endregion
  656. #region REPLACE INTO
  657. public override bool Replace(string table, Dictionary<string, object> row)
  658. {
  659. return InsertOrReplace(table, row, false);
  660. }
  661. #endregion
  662. #region Delete
  663. public override bool DeleteByTime(string table, string key)
  664. {
  665. QueryFilter filter = new QueryFilter();
  666. filter.andLessThanEqFilters[
  667. "(datetime(" + key.Replace("`", "") + ", 'localtime') - datetime('now', 'localtime'))"] = 0;
  668. return Delete(table, filter);
  669. }
  670. public override bool Delete(string table, QueryFilter queryFilter)
  671. {
  672. Dictionary<string, object> ps = new Dictionary<string, object>();
  673. string query = "DELETE FROM " + table +
  674. (queryFilter != null ? (" WHERE " + queryFilter.ToSQL(':', out ps)) : "");
  675. SqliteCommand cmd = new SqliteCommand(query);
  676. AddParams(ref cmd, ps);
  677. try
  678. {
  679. ExecuteNonQuery(cmd);
  680. }
  681. catch (Exception e)
  682. {
  683. MainConsole.Instance.Error("[SqliteDataManager] Delete(" + query + "), " + e);
  684. return false;
  685. }
  686. CloseReaderCommand(cmd);
  687. return true;
  688. }
  689. #endregion
  690. public override string ConCat(string[] toConcat)
  691. {
  692. #if (!ISWIN)
  693. string returnValue = "";
  694. foreach (string s in toConcat)
  695. returnValue = returnValue + (s + " || ");
  696. #else
  697. string returnValue = toConcat.Aggregate("", (current, s) => current + (s + " || "));
  698. #endif
  699. return returnValue.Substring(0, returnValue.Length - 4);
  700. }
  701. #region Tables
  702. public override bool TableExists(string tableName)
  703. {
  704. var cmd = PrepReader("SELECT name FROM Sqlite_master WHERE name='" + tableName + "'");
  705. lock (GetLock())
  706. {
  707. using (IDataReader rdr = cmd.ExecuteReader())
  708. {
  709. if (rdr.Read())
  710. {
  711. CloseReaderCommand(cmd);
  712. return true;
  713. }
  714. else
  715. {
  716. CloseReaderCommand(cmd);
  717. return false;
  718. }
  719. }
  720. }
  721. }
  722. public override void CreateTable(string table, ColumnDefinition[] columns, IndexDefinition[] indices)
  723. {
  724. if (TableExists(table))
  725. {
  726. throw new DataManagerException("Trying to create a table with name of one that already exists.");
  727. }
  728. IndexDefinition primary = null;
  729. foreach (IndexDefinition index in indices)
  730. {
  731. if (index.Type == IndexType.Primary)
  732. {
  733. primary = index;
  734. break;
  735. }
  736. }
  737. List<string> columnDefinition = new List<string>();
  738. bool has_auto_increment = false;
  739. foreach (ColumnDefinition column in columns)
  740. {
  741. if (column.Type.auto_increment)
  742. {
  743. has_auto_increment = true;
  744. }
  745. columnDefinition.Add(column.Name + " " + GetColumnTypeStringSymbol(column.Type));
  746. }
  747. if (!has_auto_increment && primary != null && primary.Fields.Length > 0)
  748. {
  749. columnDefinition.Add("PRIMARY KEY (" + string.Join(", ", primary.Fields) + ")");
  750. }
  751. var cmd = new SqliteCommand
  752. {
  753. CommandText =
  754. string.Format("create table " + table + " ({0})",
  755. string.Join(", ", columnDefinition.ToArray()))
  756. };
  757. ExecuteNonQuery(cmd);
  758. CloseReaderCommand(cmd);
  759. if (indices.Length >= 1 && (primary == null || indices.Length >= 2))
  760. {
  761. columnDefinition = new List<string>(primary != null ? indices.Length : indices.Length - 1);
  762. // reusing existing variable for laziness
  763. uint i = 0;
  764. foreach (IndexDefinition index in indices)
  765. {
  766. if (index.Type == IndexType.Primary || index.Fields.Length < 1)
  767. {
  768. continue;
  769. }
  770. i++;
  771. columnDefinition.Add("CREATE " + (index.Type == IndexType.Unique ? "UNIQUE " : string.Empty) +
  772. "INDEX idx_" + table + "_" + i.ToString() + " ON " + table + "(" +
  773. string.Join(", ", index.Fields) + ")");
  774. }
  775. foreach (string query in columnDefinition)
  776. {
  777. cmd = new SqliteCommand
  778. {
  779. CommandText = query
  780. };
  781. ExecuteNonQuery(cmd);
  782. CloseReaderCommand(cmd);
  783. }
  784. }
  785. }
  786. public override void UpdateTable(string table, ColumnDefinition[] columns, IndexDefinition[] indices,
  787. Dictionary<string, string> renameColumns)
  788. {
  789. if (!TableExists(table))
  790. {
  791. throw new DataManagerException("Trying to update a table with name of one that does not exist.");
  792. }
  793. List<ColumnDefinition> oldColumns = ExtractColumnsFromTable(table);
  794. Dictionary<string, ColumnDefinition> sameColumns = new Dictionary<string, ColumnDefinition>();
  795. foreach (ColumnDefinition column in oldColumns)
  796. {
  797. #if (!ISWIN)
  798. foreach (ColumnDefinition innercolumn in columns)
  799. {
  800. if (innercolumn.Name.ToLower() == column.Name.ToLower() || renameColumns.ContainsKey(column.Name) && renameColumns[column.Name].ToLower() == innercolumn.Name.ToLower())
  801. {
  802. sameColumns.Add(column.Name, column);
  803. break;
  804. }
  805. }
  806. #else
  807. if (columns.Any(innercolumn => innercolumn.Name.ToLower() == column.Name.ToLower() ||
  808. renameColumns.ContainsKey(column.Name) &&
  809. renameColumns[column.Name].ToLower() == innercolumn.Name.ToLower()))
  810. {
  811. sameColumns.Add(column.Name, column);
  812. }
  813. #endif
  814. }
  815. string renamedTempTableColumnDefinition = string.Empty;
  816. string renamedTempTableColumn = string.Empty;
  817. foreach (ColumnDefinition column in oldColumns)
  818. {
  819. if (renamedTempTableColumnDefinition != string.Empty)
  820. {
  821. renamedTempTableColumnDefinition += ", ";
  822. renamedTempTableColumn += ", ";
  823. }
  824. renamedTempTableColumn += column.Name;
  825. renamedTempTableColumnDefinition += column.Name + " " + GetColumnTypeStringSymbol(column.Type);
  826. }
  827. var cmd = new SqliteCommand
  828. {
  829. CommandText =
  830. "CREATE TABLE " + table + "__temp(" + renamedTempTableColumnDefinition + ");"
  831. };
  832. ExecuteNonQuery(cmd);
  833. CloseReaderCommand(cmd);
  834. cmd = new SqliteCommand
  835. {
  836. CommandText =
  837. "INSERT INTO " + table + "__temp SELECT " + renamedTempTableColumn + " from " + table +
  838. ";"
  839. };
  840. ExecuteNonQuery(cmd);
  841. CloseReaderCommand(cmd);
  842. cmd = new SqliteCommand
  843. {
  844. CommandText = "drop table " + table
  845. };
  846. ExecuteNonQuery(cmd);
  847. CloseReaderCommand(cmd);
  848. List<string> newTableColumnDefinition = new List<string>(columns.Length);
  849. IndexDefinition primary = null;
  850. foreach (IndexDefinition index in indices)
  851. {
  852. if (index.Type == IndexType.Primary)
  853. {
  854. primary = index;
  855. break;
  856. }
  857. }
  858. bool has_auto_increment = false;
  859. foreach (ColumnDefinition column in columns)
  860. {
  861. if (column.Type.auto_increment)
  862. {
  863. has_auto_increment = true;
  864. }
  865. newTableColumnDefinition.Add(column.Name + " " + GetColumnTypeStringSymbol(column.Type));
  866. }
  867. if (!has_auto_increment && primary != null && primary.Fields.Length > 0)
  868. {
  869. newTableColumnDefinition.Add("PRIMARY KEY (" + string.Join(", ", primary.Fields) + ")");
  870. }
  871. cmd = new SqliteCommand
  872. {
  873. CommandText =
  874. string.Format("create table " + table + " ({0}) ",
  875. string.Join(", ", newTableColumnDefinition.ToArray()))
  876. };
  877. ExecuteNonQuery(cmd);
  878. CloseReaderCommand(cmd);
  879. if (indices.Length >= 1 && (primary == null || indices.Length >= 2))
  880. {
  881. newTableColumnDefinition = new List<string>(primary != null ? indices.Length : indices.Length - 1);
  882. // reusing existing variable for laziness
  883. uint i = 0;
  884. foreach (IndexDefinition index in indices)
  885. {
  886. if (index.Type == IndexType.Primary || index.Fields.Length < 1)
  887. {
  888. continue;
  889. }
  890. i++;
  891. newTableColumnDefinition.Add("CREATE " + (index.Type == IndexType.Unique ? "UNIQUE " : string.Empty) +
  892. "INDEX idx_" + table + "_" + i.ToString() + " ON " + table + "(" +
  893. string.Join(", ", index.Fields) + ")");
  894. }
  895. foreach (string query in newTableColumnDefinition)
  896. {
  897. cmd = new SqliteCommand
  898. {
  899. CommandText = query
  900. };
  901. ExecuteNonQuery(cmd);
  902. CloseReaderCommand(cmd);
  903. }
  904. }
  905. string InsertFromTempTableColumnDefinition = string.Empty;
  906. string InsertIntoFromTempTableColumnDefinition = string.Empty;
  907. foreach (ColumnDefinition column in sameColumns.Values)
  908. {
  909. if (InsertFromTempTableColumnDefinition != string.Empty)
  910. {
  911. InsertFromTempTableColumnDefinition += ", ";
  912. }
  913. if (InsertIntoFromTempTableColumnDefinition != string.Empty)
  914. {
  915. InsertIntoFromTempTableColumnDefinition += ", ";
  916. }
  917. if (renameColumns.ContainsKey(column.Name))
  918. InsertIntoFromTempTableColumnDefinition += renameColumns[column.Name];
  919. else
  920. InsertIntoFromTempTableColumnDefinition += column.Name;
  921. InsertFromTempTableColumnDefinition += column.Name;
  922. }
  923. cmd = new SqliteCommand
  924. {
  925. CommandText =
  926. "INSERT INTO " + table + " (" + InsertIntoFromTempTableColumnDefinition + ") SELECT " +
  927. InsertFromTempTableColumnDefinition + " from " + table + "__temp;"
  928. };
  929. ExecuteNonQuery(cmd);
  930. CloseReaderCommand(cmd);
  931. cmd = new SqliteCommand
  932. {
  933. CommandText = "drop table " + table + "__temp"
  934. };
  935. ExecuteNonQuery(cmd);
  936. CloseReaderCommand(cmd);
  937. }
  938. public override string GetColumnTypeStringSymbol(ColumnTypes type)
  939. {
  940. switch (type)
  941. {
  942. case ColumnTypes.Double:
  943. return "DOUBLE";
  944. case ColumnTypes.Integer11:
  945. return "INT(11)";
  946. case ColumnTypes.Integer30:
  947. return "INT(30)";
  948. case ColumnTypes.UInteger11:
  949. return "INT(11) UNSIGNED";
  950. case ColumnTypes.UInteger30:
  951. return "INT(30) UNSIGNED";
  952. case ColumnTypes.Char36:
  953. return "CHAR(36)";
  954. case ColumnTypes.Char32:
  955. return "CHAR(32)";
  956. case ColumnTypes.Char5:
  957. return "CHAR(5)";
  958. case ColumnTypes.String:
  959. return "TEXT";
  960. case ColumnTypes.String1:
  961. return "VARCHAR(1)";
  962. case ColumnTypes.String2:
  963. return "VARCHAR(2)";
  964. case ColumnTypes.String16:
  965. return "VARCHAR(16)";
  966. case ColumnTypes.String30:
  967. return "VARCHAR(30)";
  968. case ColumnTypes.String32:
  969. return "VARCHAR(32)";
  970. case ColumnTypes.String36:
  971. return "VARCHAR(36)";
  972. case ColumnTypes.String45:
  973. return "VARCHAR(45)";
  974. case ColumnTypes.String50:
  975. return "VARCHAR(50)";
  976. case ColumnTypes.String64:
  977. return "VARCHAR(64)";
  978. case ColumnTypes.String128:
  979. return "VARCHAR(128)";
  980. case ColumnTypes.String100:
  981. return "VARCHAR(100)";
  982. case ColumnTypes.String10:
  983. return "VARCHAR(10)";
  984. case ColumnTypes.String255:
  985. return "VARCHAR(255)";
  986. case ColumnTypes.String512:
  987. return "VARCHAR(512)";
  988. case ColumnTypes.String1024:
  989. return "VARCHAR(1024)";
  990. case ColumnTypes.String8196:
  991. return "VARCHAR(8196)";
  992. case ColumnTypes.Blob:
  993. return "blob";
  994. case ColumnTypes.LongBlob:
  995. return "blob";
  996. case ColumnTypes.Text:
  997. return "VARCHAR(512)";
  998. case ColumnTypes.MediumText:
  999. return "VARCHAR(512)";
  1000. case ColumnTypes.LongText:
  1001. return "VARCHAR(512)";
  1002. case ColumnTypes.Date:
  1003. return "DATE";
  1004. case ColumnTypes.DateTime:
  1005. return "DATETIME";
  1006. case ColumnTypes.Float:
  1007. return "float";
  1008. case ColumnTypes.Unknown:
  1009. return "";
  1010. case ColumnTypes.TinyInt1:
  1011. return "TINYINT(1)";
  1012. case ColumnTypes.TinyInt4:
  1013. return "TINYINT(4)";
  1014. default:
  1015. throw new DataManagerException("Unknown column type.");
  1016. }
  1017. }
  1018. public override string GetColumnTypeStringSymbol(ColumnTypeDef coldef)
  1019. {
  1020. string symbol;
  1021. switch (coldef.Type)
  1022. {
  1023. case ColumnType.Blob:
  1024. case ColumnType.LongBlob:
  1025. symbol = "BLOB";
  1026. break;
  1027. case ColumnType.Boolean:
  1028. symbol = "TINYINT(1)";
  1029. break;
  1030. case ColumnType.Char:
  1031. symbol = "CHAR(" + coldef.Size + ")";
  1032. break;
  1033. case ColumnType.Date:
  1034. symbol = "DATE";
  1035. break;
  1036. case ColumnType.DateTime:
  1037. symbol = "DATETIME";
  1038. break;
  1039. case ColumnType.Double:
  1040. symbol = "DOUBLE";
  1041. break;
  1042. case ColumnType.Float:
  1043. symbol = "FLOAT";
  1044. break;
  1045. case ColumnType.Integer:
  1046. if (!coldef.auto_increment)
  1047. {
  1048. symbol = "INT(" + coldef.Size + ")";
  1049. }
  1050. else
  1051. {
  1052. symbol = "INTEGER PRIMARY KEY AUTOINCREMENT";
  1053. }
  1054. break;
  1055. case ColumnType.TinyInt:
  1056. symbol = "TINYINT(" + coldef.Size + ")";
  1057. break;
  1058. case ColumnType.String:
  1059. symbol = "VARCHAR(" + coldef.Size + ")";
  1060. break;
  1061. case ColumnType.Text:
  1062. case ColumnType.MediumText:
  1063. case ColumnType.LongText:
  1064. symbol = "TEXT";
  1065. break;
  1066. case ColumnType.UUID:
  1067. symbol = "CHAR(36)";
  1068. break;
  1069. default:
  1070. throw new DataManagerException("Unknown column type.");
  1071. }
  1072. return symbol + (coldef.isNull ? " NULL" : " NOT NULL") +
  1073. ((coldef.isNull && coldef.defaultValue == null)
  1074. ? " DEFAULT NULL"
  1075. : (coldef.defaultValue != null
  1076. ? " DEFAULT " +
  1077. (coldef.defaultValue.StartsWith("'") && coldef.defaultValue.EndsWith("'")
  1078. ? coldef.defaultValue
  1079. : "'" + coldef.defaultValue + "'")
  1080. : ""));
  1081. }
  1082. protected override List<ColumnDefinition> ExtractColumnsFromTable(string tableName)
  1083. {
  1084. List<ColumnDefinition> defs = new List<ColumnDefinition>();
  1085. IndexDefinition primary = null;
  1086. bool isFaux = false;
  1087. foreach (KeyValuePair<string, IndexDefinition> index in ExtractIndicesFromTable(tableName))
  1088. {
  1089. if (index.Value.Type == IndexType.Primary)
  1090. {
  1091. isFaux = index.Key == "#fauxprimary#";
  1092. primary = index.Value;
  1093. break;
  1094. }
  1095. }
  1096. var cmd = PrepReader(string.Format("PRAGMA table_info({0})", tableName));
  1097. lock (GetLock())
  1098. {
  1099. using (SqliteDataReader rdr = cmd.ExecuteReader())
  1100. {
  1101. while (rdr.Read())
  1102. {
  1103. if (rdr.HasRows)
  1104. {
  1105. var name = rdr["name"];
  1106. var type = rdr["type"];
  1107. object defaultValue = rdr["dflt_value"];
  1108. ColumnTypeDef typeDef = ConvertTypeToColumnType(type.ToString());
  1109. typeDef.isNull = uint.Parse(rdr["notnull"].ToString()) == 0;
  1110. typeDef.defaultValue = defaultValue == null ||
  1111. defaultValue.GetType() == typeof (System.DBNull)
  1112. ? null
  1113. : defaultValue.ToString();
  1114. if (
  1115. uint.Parse(rdr["pk"].ToString()) == 1 &&
  1116. primary != null &&
  1117. isFaux == true &&
  1118. primary.Fields.Length == 1 &&
  1119. primary.Fields[0].ToLower() == name.ToString().ToLower() &&
  1120. (typeDef.Type == ColumnType.Int

Large files files are truncated, but you can click here to view the full file