You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

856 lines
31 KiB

  1. #if NET40 || NET461
  2. /* 2019.9.29.0 */
  3. using Apewer;
  4. using Apewer.Source;
  5. using Externals.MySql.Data.MySqlClient;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Data;
  9. using System.Data.SqlClient;
  10. using System.Data.OleDb;
  11. using System.Data.Common;
  12. using System.Text;
  13. namespace Apewer.Source
  14. {
  15. /// <summary></summary>
  16. public class MySql : IDatabase, IDisposable
  17. {
  18. #region fields & properties
  19. private const string EmptyString = TextUtility.EmptyString;
  20. private MySqlConnection _connection = null;
  21. private Timeout _timeout = new Timeout();
  22. private string _address = EmptyString;
  23. private string _store = EmptyString;
  24. private string _user = "root";
  25. private string _pass = EmptyString;
  26. /// <summary></summary>
  27. public string Address { get { return _address; } set { _address = TextUtility.AntiInject(value); } }
  28. /// <summary></summary>
  29. public string Store { get { return _store; } set { _store = TextUtility.AntiInject(value); } }
  30. /// <summary></summary>
  31. public string User { get { return _user; } set { _user = TextUtility.AntiInject(value); } }
  32. /// <summary></summary>
  33. public string Pass { get { return _pass; } set { _pass = TextUtility.AntiInject(value); } }
  34. /// <summary></summary>
  35. public Timeout Timeout { get { return _timeout; } set { _timeout = value; } }
  36. /// <summary></summary>
  37. public bool Online
  38. {
  39. get
  40. {
  41. if (_connection == null) return false;
  42. return _connection.State == ConnectionState.Open;
  43. }
  44. }
  45. #endregion
  46. #region methods
  47. private string CombineString()
  48. {
  49. return TextUtility.Merge("server=", _address, "; database=", _store, "; uid=", _user, "; pwd=", _pass, ";");
  50. }
  51. /// <summary></summary>
  52. public bool Connect()
  53. {
  54. if (_connection == null)
  55. {
  56. _connection = new MySqlConnection();
  57. _connection.ConnectionString = CombineString();
  58. }
  59. else
  60. {
  61. if (_connection.State == ConnectionState.Open) return true;
  62. }
  63. try
  64. {
  65. _connection.Open();
  66. switch (_connection.State)
  67. {
  68. case ConnectionState.Open: return true;
  69. default: return false;
  70. }
  71. }
  72. catch (Exception)
  73. {
  74. Close();
  75. return false;
  76. }
  77. }
  78. /// <summary></summary>
  79. public void Close()
  80. {
  81. if (_connection != null)
  82. {
  83. _connection.Close();
  84. _connection.Dispose();
  85. _connection = null;
  86. }
  87. }
  88. /// <summary></summary>
  89. public void Dispose() { Close(); }
  90. /// <summary></summary>
  91. public IQuery Query(string tsql, IEnumerable<IDataParameter> parameters)
  92. {
  93. if (tsql.IsBlank()) return Example.InvalidQueryStatement;
  94. const string table = "queryresult";
  95. var connected = Connect();
  96. if (!connected) return Example.InvalidQueryConnection;
  97. var query = new Query();
  98. try
  99. {
  100. var command = new MySqlCommand();
  101. command.Connection = _connection;
  102. command.CommandTimeout = _timeout.Query;
  103. command.CommandText = tsql;
  104. if (parameters != null)
  105. {
  106. foreach (var parameter in parameters)
  107. {
  108. if (parameter == null) continue;
  109. command.Parameters.Add(parameter);
  110. }
  111. }
  112. using (var ds = new DataSet())
  113. {
  114. using (var da = new MySqlDataAdapter(tsql, _connection))
  115. {
  116. da.Fill(ds, table);
  117. query.Table = ds.Tables[table];
  118. }
  119. }
  120. command.Dispose();
  121. query.Success = true;
  122. }
  123. catch (Exception exception)
  124. {
  125. query.Success = false;
  126. query.Exception = exception;
  127. }
  128. return query;
  129. }
  130. /// <summary></summary>
  131. public IExecute Execute(string tsql, IEnumerable<IDataParameter> parameters)
  132. {
  133. if (tsql.IsBlank()) return Example.InvalidExecuteStatement;
  134. var connected = Connect();
  135. if (!connected) return Example.InvalidExecuteConnection;
  136. var transaction = _connection.BeginTransaction();
  137. var execute = new Execute();
  138. try
  139. {
  140. var command = new MySqlCommand();
  141. command.Connection = _connection;
  142. command.Transaction = transaction;
  143. command.CommandTimeout = _timeout.Execute;
  144. command.CommandText = tsql;
  145. if (parameters != null)
  146. {
  147. foreach (var parameter in parameters)
  148. {
  149. if (parameter == null) continue;
  150. command.Parameters.Add(parameter);
  151. }
  152. }
  153. execute.Rows += command.ExecuteNonQuery();
  154. transaction.Commit();
  155. command.Dispose();
  156. execute.Success = true;
  157. }
  158. catch (Exception exception)
  159. {
  160. try { transaction.Rollback(); } catch { }
  161. execute.Success = false;
  162. execute.Exception = exception;
  163. }
  164. try { transaction.Dispose(); } catch { }
  165. return execute;
  166. }
  167. /// <summary></summary>
  168. public IQuery Query(string tsql)
  169. {
  170. return Query(tsql, null);
  171. }
  172. /// <summary></summary>
  173. public IExecute Execute(string tsql, IEnumerable<Parameter> parameters)
  174. {
  175. var dps = null as List<IDataParameter>;
  176. if (parameters != null)
  177. {
  178. dps = new List<IDataParameter>();
  179. foreach (var p in parameters)
  180. {
  181. var dp = CreateDataParameter(p);
  182. dps.Add(dp);
  183. }
  184. }
  185. return Execute(tsql, dps);
  186. }
  187. /// <summary></summary>
  188. public IExecute Execute(string tsql)
  189. {
  190. return Execute(tsql, null as IEnumerable<IDataParameter>);
  191. }
  192. #endregion
  193. #region linq
  194. private List<string> QueryFirstColumn(string tsql)
  195. {
  196. var list = new List<string>();
  197. if (Connect())
  198. {
  199. using (var query = Query(tsql, null) as Query)
  200. {
  201. for (int r = 0; r < query.Rows; r++)
  202. {
  203. var cell = query.Text(r, 0);
  204. if (TextUtility.IsBlank(cell)) continue;
  205. list.Add(cell);
  206. }
  207. }
  208. }
  209. return list;
  210. }
  211. /// <summary></summary>
  212. public List<string> QueryAllTableNames()
  213. {
  214. var sql = TextUtility.Merge("select table_name from information_schema.tables where table_schema='", _store, "' and table_type='base table';");
  215. return QueryFirstColumn(sql);
  216. }
  217. /// <summary></summary>
  218. public List<string> QueryAllViewNames()
  219. {
  220. var sql = TextUtility.Merge("select table_name from information_schema.tables where table_schema='", _store, "' and table_type='view';");
  221. return QueryFirstColumn(sql);
  222. }
  223. /// <summary></summary>
  224. public List<string> QueryAllColumnNames(string table)
  225. {
  226. var sql = TextUtility.Merge("select column_name from information_schema.columns where table_schema='", _store, "' and table_name='", TextUtility.AntiInject(table), "';");
  227. return QueryFirstColumn(sql);
  228. }
  229. /// <summary>获取用于创建表的语句。</summary>
  230. private string GetCreateStetement(TableStructure structure)
  231. {
  232. // 检查现存表。
  233. var exists = false;
  234. var tables = QueryAllTableNames();
  235. if (tables.Count > 0)
  236. {
  237. var lower = structure.Table.ToLower();
  238. foreach (var table in tables)
  239. {
  240. if (TextUtility.IsBlank(table)) continue;
  241. if (table.ToLower() == lower)
  242. {
  243. exists = true;
  244. break;
  245. }
  246. }
  247. }
  248. if (exists)
  249. {
  250. var columns = QueryAllColumnNames(structure.Table);
  251. if (columns.Count > 0)
  252. {
  253. var lower = new List<string>();
  254. foreach (var column in columns)
  255. {
  256. if (TextUtility.IsBlank(column)) continue;
  257. lower.Add(column.ToLower());
  258. }
  259. columns = lower;
  260. }
  261. var sqlsb = new StringBuilder();
  262. foreach (var column in structure.Columns.Values)
  263. {
  264. // 检查 Independent 特性。
  265. if (structure.Independent && column.Independent) continue;
  266. // 去重。
  267. var lower = column.Field.ToLower();
  268. if (columns.Contains(lower)) continue;
  269. var type = GetColumnDeclaration(column);
  270. if (type.IsEmpty()) return TextUtility.Merge("类型 ", column.Type.ToString(), " 不受支持。");
  271. // alter table `_record` add column `_index` bigint;
  272. sqlsb.Append("alter table `", structure.Table, "` add column ", type, "; ");
  273. }
  274. var sql = sqlsb.ToString();
  275. return sql;
  276. }
  277. else
  278. {
  279. // create table _record (`_index` bigint, `_key` varchar(255), `_text` longtext) engine=innodb default charset=utf8mb4
  280. var columns = new List<string>();
  281. var primarykey = null as string;
  282. foreach (var kvp in structure.Columns)
  283. {
  284. var property = kvp.Key;
  285. var column = kvp.Value;
  286. // 检查 Independent 特性。
  287. if (structure.Independent && column.Independent) continue;
  288. // 字段。
  289. var type = GetColumnDeclaration(column);
  290. if (type.IsEmpty()) return TextUtility.Merge("类型 ", column.Type.ToString(), " 不受支持。");
  291. columns.Add(type);
  292. // 主键。
  293. if (property == "Key") primarykey = column.Field;
  294. }
  295. var table = structure.Table;
  296. var joined = string.Join(", ", columns);
  297. // 设置主键。
  298. string sql;
  299. if (!structure.Independent && !string.IsNullOrEmpty(primarykey))
  300. {
  301. sql = TextUtility.Merge("create table `", table, "`(", joined, ", primary key (", primarykey, ") ) engine=innodb default charset=utf8mb4; ");
  302. }
  303. else
  304. {
  305. sql = TextUtility.Merge("create table `", table, "`(", joined, ") engine=innodb default charset=utf8mb4; ");
  306. }
  307. return sql;
  308. }
  309. }
  310. /// <summary></summary>
  311. private string CreateTable(Type model, out string sql)
  312. {
  313. if (model == null)
  314. {
  315. sql = "";
  316. return "指定的类型无效。";
  317. }
  318. var structure = null as TableStructure;
  319. try { structure = TableStructure.ParseModel(model); }
  320. catch (Exception exception)
  321. {
  322. sql = "";
  323. return exception.Message;
  324. }
  325. // 连接数据库。
  326. if (!Connect())
  327. {
  328. sql = "";
  329. return "连接数据库失败。";
  330. }
  331. sql = GetCreateStetement(structure);
  332. if (sql.NotEmpty())
  333. {
  334. var execute = Execute(sql);
  335. if (!execute.Success) return execute.Error;
  336. }
  337. return null;
  338. }
  339. /// <summary></summary>
  340. public string CreateTable(Type model)
  341. {
  342. return CreateTable(model, out string sql);
  343. }
  344. /// <summary></summary>
  345. public string CreateTable<T>() where T : Record
  346. {
  347. return CreateTable(typeof(T));
  348. }
  349. /// <summary></summary>
  350. public string CreateTable(Record model)
  351. {
  352. if (model == null) return "参数无效。";
  353. return CreateTable(model.GetType());
  354. }
  355. /// <summary></summary>
  356. /// <summary>插入记录。成功时候返回空字符串,发生异常时返回异常信息。</summary>
  357. public string Insert(Record entity)
  358. {
  359. if (entity == null) return "参数无效。";
  360. entity.FixProperties();
  361. var structure = null as TableStructure;
  362. try { structure = TableStructure.ParseModel(entity); }
  363. catch (Exception exception) { return exception.Message; }
  364. var parameters = structure.CreateDataParameters(entity, CreateDataParameter);
  365. var sql = GenerateInsertStatement(structure.Table, parameters);
  366. var execute = Execute(sql, parameters);
  367. if (execute.Success) return TextUtility.EmptyString;
  368. return execute.Error;
  369. }
  370. /// <summary>
  371. /// <para>更新记录,实体中的 Created 和 Key 属性不被更新。成功时返回空字符串,发生异常时返回异常信息。</para>
  372. /// <para>无法更新拥有 Independent 特性的模型。</para>
  373. /// </summary>
  374. public string Update(Record entity)
  375. {
  376. if (entity == null) return "参数无效。";
  377. entity.FixProperties();
  378. entity.Updated = ClockUtility.Lucid;
  379. var structure = null as TableStructure;
  380. try { structure = TableStructure.ParseModel(entity); }
  381. catch (Exception exception) { return exception.Message; }
  382. // 检查 Independent 特性。
  383. if (structure.Independent) return "无法更新拥有 Independent 特性的模型。";
  384. var parameters = structure.CreateDataParameters(entity, CreateDataParameter, "_created", "_key");
  385. var sql = GenerateUpdateStatement(structure, entity.Key, parameters);
  386. var execute = Execute(sql, parameters);
  387. if (execute.Success) return TextUtility.EmptyString;
  388. return execute.Error;
  389. }
  390. /// <summary></summary>
  391. public Result<List<T>> QueryRecords<T>(string tsql) where T : Record
  392. {
  393. if (tsql.IsEmpty()) return new Result<List<T>>(new ArgumentException());
  394. try
  395. {
  396. // 解析模型,抛出 Exception。
  397. TableStructure.ParseModel(typeof(T));
  398. var query = Query(tsql) as Query;
  399. var list = query.Fill<T>();
  400. query.Dispose();
  401. return new Result<List<T>>(list);
  402. }
  403. catch (Exception exception)
  404. {
  405. return new Result<List<T>>(exception);
  406. }
  407. }
  408. /// <summary></summary>
  409. public Result<T> QueryRecord<T>(string key, long flag = 0) where T : Record
  410. {
  411. var k = TextUtility.RestrictGuid(key);
  412. if (k.IsEmpty()) new Result<T>(new Exception("参数无效。"));
  413. try
  414. {
  415. var structure = TableStructure.ParseModel(typeof(T));
  416. var sqlflag = (flag == 0) ? TextUtility.EmptyString : TextUtility.Merge(" `_flag`=", flag.ToString(), " and");
  417. var sqlkey = TextUtility.Merge(" `_key`='", k, "'");
  418. var sql = TextUtility.Merge("select * from `", structure.Table, "` where ", sqlflag, sqlkey, " limit 1;");
  419. var result = QueryRecords<T>(sql);
  420. var list = result.Entity;
  421. if (list != null && list.Count > 0) return new Result<T>(list[0]);
  422. return new Result<T>(null, "无结果。");
  423. }
  424. catch (Exception exception)
  425. {
  426. return new Result<T>(exception);
  427. }
  428. }
  429. /// <summary>获取所有记录。Flag 为 0 时将忽略 Flag 条件。</summary>
  430. public Result<List<T>> QueryRecords<T>(long flag = 0) where T : Record
  431. {
  432. try
  433. {
  434. var structure = TableStructure.ParseModel(typeof(T));
  435. var sqlflag = (flag == 0) ? TextUtility.EmptyString : TextUtility.Merge(" where `_flag`=", flag.ToString());
  436. var sql = TextUtility.Merge("select * from `", structure.Table, "`", sqlflag, "; ");
  437. return QueryRecords<T>(sql);
  438. }
  439. catch (Exception exception)
  440. {
  441. return new Result<List<T>>(exception);
  442. }
  443. }
  444. /// <summary>查询有效的 Key 值。</summary>
  445. public Result<List<string>> QueryKeys(Type model, long flag = 0)
  446. {
  447. if (model != null)
  448. {
  449. try
  450. {
  451. var type = model;
  452. var list = new List<string>();
  453. var ts = TableStructure.ParseModel(type);
  454. var sqlflag = (flag == 0) ? TextUtility.EmptyString : TextUtility.Merge(" where `_flag`=", flag.ToString());
  455. var sql = TextUtility.Merge("select `_key` from `", ts.Table, "`", sqlflag, "; ");
  456. var query = Query(sql) as Query;
  457. for (var r = 0; r < query.Rows; r++)
  458. {
  459. var cell = TextUtility.Trim(query.Text(r));
  460. if (cell.Length > 0) list.Add(cell);
  461. }
  462. query.Dispose();
  463. return new Result<List<string>>(list);
  464. }
  465. catch (Exception argException)
  466. {
  467. return new Result<List<string>>(argException);
  468. }
  469. }
  470. return new Result<List<string>>(new Exception("参数无效。"));
  471. }
  472. /// <summary>查询有效的 Key 值。</summary>
  473. public Result<List<string>> QueryKeys<T>(long flag = 0) where T : Record
  474. {
  475. try
  476. {
  477. var type = typeof(T);
  478. var ts = TableStructure.ParseModel(type);
  479. var sqlflag = (flag == 0) ? TextUtility.EmptyString : TextUtility.Merge(" where _flag=", flag.ToString());
  480. var sql = TextUtility.Merge("select `_key` from `", ts.Table, "`", sqlflag, "; ");
  481. var query = Query(sql) as Query;
  482. var list = new List<string>();
  483. for (var r = 0; r < query.Rows; r++)
  484. {
  485. var cell = TextUtility.Trim(query.Text(r));
  486. if (cell.Length > 0) list.Add(cell);
  487. }
  488. query.Dispose();
  489. return new Result<List<string>>(list);
  490. }
  491. catch (Exception argException)
  492. {
  493. return new Result<List<string>>(argException);
  494. }
  495. }
  496. #endregion
  497. #region static
  498. /// <summary></summary>
  499. /// <exception cref="ArgumentNullException"></exception>
  500. /// <exception cref="InvalidOperationException"></exception>
  501. internal static MySqlParameter CreateDataParameter(Parameter parameter)
  502. {
  503. if (parameter == null) throw new InvalidOperationException("参数无效。");
  504. return CreateDataParameter(parameter.Name, parameter.Type, parameter.Size, parameter.Value);
  505. }
  506. /// <summary></summary>
  507. internal static MySqlParameter CreateDataParameter(string name, ColumnType type, Int32 size, object value)
  508. {
  509. if (TextUtility.IsBlank(name)) return null;
  510. var dbtype = MySqlDbType.Int64;
  511. switch (type)
  512. {
  513. case ColumnType.Binary:
  514. dbtype = MySqlDbType.LongBlob;
  515. break;
  516. case ColumnType.Integer:
  517. dbtype = MySqlDbType.Int64;
  518. break;
  519. case ColumnType.Float:
  520. dbtype = MySqlDbType.Double;
  521. break;
  522. case ColumnType.DateTime:
  523. dbtype = MySqlDbType.DateTime;
  524. break;
  525. case ColumnType.VarChar:
  526. case ColumnType.VarChar255:
  527. case ColumnType.VarCharMax:
  528. case ColumnType.NVarChar:
  529. case ColumnType.NVarChar255:
  530. case ColumnType.NVarCharMax:
  531. dbtype = MySqlDbType.VarChar;
  532. break;
  533. case ColumnType.Text:
  534. case ColumnType.NText:
  535. dbtype = MySqlDbType.LongText;
  536. break;
  537. default:
  538. throw new InvalidOperationException(TextUtility.Merge("类型 ", type.ToString(), " 不受支持。"));
  539. }
  540. switch (type)
  541. {
  542. case ColumnType.VarChar:
  543. case ColumnType.NVarChar:
  544. size = NumberUtility.RestrictValue(size, 0, 65535);
  545. break;
  546. case ColumnType.VarChar255:
  547. case ColumnType.NVarChar255:
  548. size = NumberUtility.RestrictValue(size, 0, 255);
  549. break;
  550. default:
  551. size = 0;
  552. break;
  553. }
  554. if (value is string && value != null && size > 0)
  555. {
  556. value = TextUtility.RestrictLength((string)value, size);
  557. }
  558. var parameter = new MySqlParameter();
  559. parameter.ParameterName = name;
  560. parameter.MySqlDbType = dbtype;
  561. parameter.Value = value;
  562. if (size > 0) parameter.Size = size;
  563. return parameter;
  564. }
  565. /// <summary></summary>
  566. internal static MySqlParameter CreateDataParameter(string name, MySqlDbType type, object value, Int32 size = 0)
  567. {
  568. var parameter = new MySqlParameter();
  569. parameter.ParameterName = name;
  570. parameter.MySqlDbType = type;
  571. parameter.Value = value;
  572. if (size > 0) parameter.Size = size;
  573. return parameter;
  574. }
  575. private static string GetColumnDeclaration(ColumnAttribute column)
  576. {
  577. var type = TextUtility.EmptyString;
  578. var length = Math.Max(0, (int)column.Length);
  579. switch (column.Type)
  580. {
  581. case ColumnType.Integer:
  582. type = "bigint";
  583. break;
  584. case ColumnType.Float:
  585. type = "double";
  586. break;
  587. case ColumnType.Binary:
  588. type = "longblob";
  589. break;
  590. case ColumnType.DateTime:
  591. type = "datetime";
  592. break;
  593. case ColumnType.VarChar:
  594. type = TextUtility.Merge("varchar(", Math.Max(65535, length).ToString(), ")");
  595. break;
  596. case ColumnType.VarChar255:
  597. type = TextUtility.Merge("varchar(255)");
  598. break;
  599. case ColumnType.VarCharMax:
  600. type = TextUtility.Merge("varchar(max)");
  601. break;
  602. case ColumnType.Text:
  603. type = TextUtility.Merge("longtext");
  604. break;
  605. case ColumnType.NVarChar:
  606. type = TextUtility.Merge("varchar(", Math.Min(65535, length).ToString(), ")");
  607. break;
  608. case ColumnType.NVarChar255:
  609. type = TextUtility.Merge("varchar(255)");
  610. break;
  611. case ColumnType.NVarCharMax:
  612. type = TextUtility.Merge("varchar(65535)");
  613. break;
  614. case ColumnType.NText:
  615. type = TextUtility.Merge("longtext");
  616. break;
  617. default:
  618. return TextUtility.EmptyString;
  619. }
  620. return TextUtility.Merge("`", (string)column.Field, "` ", type);
  621. }
  622. private static string GetParameterName(string argParameter)
  623. {
  624. var name = TextUtility.AntiInject(argParameter, 255);
  625. if (name.StartsWith("@") && name.Length > 1)
  626. {
  627. name = name.Substring(1, name.Length - 1);
  628. }
  629. return name;
  630. }
  631. private static string GetParameterName(IDataParameter argParameter)
  632. {
  633. var name = TextUtility.EmptyString;
  634. if (argParameter != null)
  635. {
  636. name = GetParameterName(argParameter.ParameterName);
  637. }
  638. return name;
  639. }
  640. private static List<string> GetParametersNames(IEnumerable<IDataParameter> argParameters)
  641. {
  642. var columns = new List<string>();
  643. if (argParameters != null)
  644. {
  645. foreach (var parameter in argParameters)
  646. {
  647. var name = GetParameterName(parameter);
  648. var isblank = TextUtility.IsBlank(name);
  649. if (isblank) continue;
  650. columns.Add(name);
  651. }
  652. }
  653. return columns;
  654. }
  655. private static string GenerateInsertStatement(string argTable, List<string> argColumns)
  656. {
  657. var result = TextUtility.EmptyString;
  658. var table = TextUtility.AntiInject(argTable, 255);
  659. if (argColumns != null && !TextUtility.IsBlank(table))
  660. {
  661. var count = 0;
  662. var names = new List<string>();
  663. var values = new List<string>();
  664. foreach (var column in argColumns)
  665. {
  666. //names.Add(TextGenerator.Merge("[", column, "]"));
  667. names.Add(TextUtility.Merge(column));
  668. values.Add("@" + column);
  669. count += 1;
  670. }
  671. var text = new StringBuilder();
  672. if (count > 0)
  673. {
  674. text.Append("insert into `", table, "`(", string.Join(", ", names), ") ");
  675. text.Append("values(", string.Join(", ", values), "); ");
  676. }
  677. result = text.ToString();
  678. }
  679. return result;
  680. }
  681. private static string GenerateUpdateStatement(TableStructure structure, string key, List<string> columns)
  682. {
  683. var result = TextUtility.EmptyString;
  684. var table = TextUtility.AntiInject(structure.Table, 255);
  685. var safekey = TextUtility.AntiInject(key, 255);
  686. if (columns != null && !TextUtility.IsBlank(table) && !TextUtility.IsBlank(safekey))
  687. {
  688. var items = new List<string>();
  689. foreach (var column in columns)
  690. {
  691. items.Add(TextUtility.Merge("`", column, "`=@", column));
  692. }
  693. if (items.Count > 0)
  694. {
  695. result = TextUtility.Merge("update `", table, "` set ", string.Join(", ", items), " where `_key`='", safekey, "'; ");
  696. }
  697. }
  698. return result;
  699. }
  700. /// <summary>生成 INSERT INTO 语句。表名必须有效,无有效参数时将获取空结果。</summary>
  701. /// <exception cref="System.ArgumentException"></exception>
  702. /// <exception cref="System.ArgumentNullException"></exception>
  703. public static string GenerateInsertStatement(string argTable, IEnumerable<IDataParameter> parameters)
  704. {
  705. if (argTable == null) throw new ArgumentNullException("argTable");
  706. var table = TextUtility.AntiInject(argTable, 255);
  707. if (TextUtility.IsBlank(table)) throw new ArgumentException("表名无效。", "argTable");
  708. var columns = GetParametersNames(parameters);
  709. if (columns.Count < 1) return TextUtility.EmptyString;
  710. return GenerateInsertStatement(table, columns);
  711. }
  712. /// <summary>生成 UPDATE 语句,键字段名为“_key”。表名必须有效,键值必须有效,无有效参数时将获取空结果。</summary>
  713. /// <exception cref="System.ArgumentException"></exception>
  714. /// <exception cref="System.ArgumentNullException"></exception>
  715. public static string GenerateUpdateStatement(TableStructure structure, string key, IEnumerable<IDataParameter> parameters)
  716. {
  717. if (structure == null) throw new ArgumentNullException("structure");
  718. if (key == null) throw new ArgumentNullException("key");
  719. var table = TextUtility.AntiInject(structure.Table, 255);
  720. if (TextUtility.IsBlank(table)) throw new ArgumentException("表名无效。", "structure");
  721. var safekey = TextUtility.AntiInject(key, 255);
  722. if (TextUtility.IsBlank(safekey)) throw new ArgumentException("键值无效。", "key");
  723. var columns = GetParametersNames(parameters);
  724. if (columns.Count < 1) return TextUtility.EmptyString;
  725. return GenerateUpdateStatement(structure, safekey, columns);
  726. }
  727. /// <summary>获取每个数据库中,每个表的容量,单位为字节。</summary>
  728. public static Dictionary<string, Dictionary<string, long>> GetTablesCapacity(MySql source)
  729. {
  730. var result = new Dictionary<string, Dictionary<string, long>>();
  731. if (source != null && source.Connect())
  732. {
  733. var sql = "select `table_schema`, `table_name`, `engine`, `data_length`, `index_length` from `information_schema`.tables order by `table_schema`, `table_name`";
  734. using (var query = (Query)source.Query(sql))
  735. {
  736. for (var r = 0; r < query.Rows; r++)
  737. {
  738. var store = query.Text(r, "table_schema");
  739. var table = query.Text(r, "table_name");
  740. var engine = query.Text(r, "engine");
  741. var capacity = TextUtility.GetInt64(query.Text(r, "data_length")) + TextUtility.GetInt64(query.Text(r, "index_length"));
  742. if (store == "mysql") continue;
  743. if (store == "information_schema") continue;
  744. if (store == "performance_schema") continue;
  745. if (engine != "MyISAM" && engine != "InnoDB") continue;
  746. if (!result.ContainsKey(store)) result.Add(store, new Dictionary<string, long>());
  747. if (!result[store].ContainsKey(table)) result[store].Add(table, 0L);
  748. result[store][table] = capacity;
  749. }
  750. }
  751. }
  752. return result;
  753. }
  754. #endregion
  755. }
  756. }
  757. #endif