PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/Aurora/DataManagerPlugins/MySQL/MySQLDataManager.cs

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