PageRenderTime 58ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/Aurora/DataManagerPlugins/SQLite/SQLiteDataManager.cs

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

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