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.

282 lines
8.0 KiB

4 years ago
  1. #if MYSQL_6_10
  2. // Copyright ?2004, 2016, Oracle and/or its affiliates. All rights reserved.
  3. //
  4. // MySQL Connector/NET is licensed under the terms of the GPLv2
  5. // <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
  6. // MySQL Connectors. There are special exceptions to the terms and
  7. // conditions of the GPLv2 as it is applied to this software, see the
  8. // FLOSS License Exception
  9. // <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
  10. //
  11. // This program is free software; you can redistribute it and/or modify
  12. // it under the terms of the GNU General Public License as published
  13. // by the Free Software Foundation; version 2 of the License.
  14. //
  15. // This program is distributed in the hope that it will be useful, but
  16. // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  17. // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  18. // for more details.
  19. //
  20. // You should have received a copy of the GNU General Public License along
  21. // with this program; if not, write to the Free Software Foundation, Inc.,
  22. // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  23. using System;
  24. using System.Collections.Generic;
  25. using System.Diagnostics;
  26. using System.Text;
  27. namespace Externals.MySql.Data.Common
  28. {
  29. internal class MySqlTokenizer
  30. {
  31. private string _sql;
  32. public MySqlTokenizer()
  33. {
  34. BackslashEscapes = true;
  35. MultiLine = true;
  36. Position = 0;
  37. }
  38. public MySqlTokenizer(string input)
  39. : this()
  40. {
  41. _sql = input;
  42. }
  43. #region Properties
  44. public string Text
  45. {
  46. get { return _sql; }
  47. set { _sql = value; Position = 0; }
  48. }
  49. public bool AnsiQuotes { get; set; }
  50. public bool BackslashEscapes { get; set; }
  51. public bool MultiLine { get; set; }
  52. public bool SqlServerMode { get; set; }
  53. public bool Quoted { get; private set; }
  54. public bool IsComment { get; private set; }
  55. public int StartIndex { get; set; }
  56. public int StopIndex { get; set; }
  57. public int Position { get; set; }
  58. public bool ReturnComments { get; set; }
  59. #endregion
  60. public List<string> GetAllTokens()
  61. {
  62. List<string> tokens = new List<string>();
  63. string token = NextToken();
  64. while (token != null)
  65. {
  66. tokens.Add(token);
  67. token = NextToken();
  68. }
  69. return tokens;
  70. }
  71. public string NextToken()
  72. {
  73. while (FindToken())
  74. {
  75. string token = _sql.Substring(StartIndex, StopIndex - StartIndex);
  76. return token;
  77. }
  78. return null;
  79. }
  80. public static bool IsParameter(string s)
  81. {
  82. if (String.IsNullOrEmpty(s)) return false;
  83. if (s[0] == '?') return true;
  84. return s.Length > 1 && s[0] == '@' && s[1] != '@';
  85. }
  86. public string NextParameter()
  87. {
  88. while (FindToken())
  89. {
  90. if ((StopIndex - StartIndex) < 2) continue;
  91. char c1 = _sql[StartIndex];
  92. char c2 = _sql[StartIndex + 1];
  93. if (c1 == '?' ||
  94. (c1 == '@' && c2 != '@'))
  95. return _sql.Substring(StartIndex, StopIndex - StartIndex);
  96. }
  97. return null;
  98. }
  99. public bool FindToken()
  100. {
  101. IsComment = Quoted = false; // reset our flags
  102. StartIndex = StopIndex = -1;
  103. while (Position < _sql.Length)
  104. {
  105. char c = _sql[Position++];
  106. if (Char.IsWhiteSpace(c)) continue;
  107. if (c == '`' || c == '\'' || c == '"' || (c == '[' && SqlServerMode))
  108. ReadQuotedToken(c);
  109. else if (c == '#' || c == '-' || c == '/')
  110. {
  111. if (!ReadComment(c))
  112. ReadSpecialToken();
  113. }
  114. else
  115. ReadUnquotedToken();
  116. if (StartIndex != -1) return true;
  117. }
  118. return false;
  119. }
  120. public string ReadParenthesis()
  121. {
  122. StringBuilder sb = new StringBuilder("(");
  123. int start = StartIndex;
  124. string token = NextToken();
  125. while (true)
  126. {
  127. if (token == null)
  128. throw new InvalidOperationException("Unable to parse SQL");
  129. sb.Append(token);
  130. if (token == ")" && !Quoted) break;
  131. token = NextToken();
  132. }
  133. return sb.ToString();
  134. }
  135. private bool ReadComment(char c)
  136. {
  137. // make sure the comment starts correctly
  138. if (c == '/' && (Position >= _sql.Length || _sql[Position] != '*')) return false;
  139. if (c == '-' && ((Position + 1) >= _sql.Length || _sql[Position] != '-' || _sql[Position + 1] != ' ')) return false;
  140. string endingPattern = "\n";
  141. if (_sql[Position] == '*')
  142. endingPattern = "*/";
  143. int startingIndex = Position - 1;
  144. int index = _sql.IndexOf(endingPattern, Position);
  145. if (endingPattern == "\n")
  146. index = _sql.IndexOf('\n', Position);
  147. if (index == -1)
  148. index = _sql.Length - 1;
  149. else
  150. index += endingPattern.Length;
  151. Position = index;
  152. if (ReturnComments)
  153. {
  154. StartIndex = startingIndex;
  155. StopIndex = index;
  156. IsComment = true;
  157. }
  158. return true;
  159. }
  160. private void CalculatePosition(int start, int stop)
  161. {
  162. StartIndex = start;
  163. StopIndex = stop;
  164. if (!MultiLine) return;
  165. }
  166. private void ReadUnquotedToken()
  167. {
  168. StartIndex = Position - 1;
  169. if (!IsSpecialCharacter(_sql[StartIndex]))
  170. {
  171. while (Position < _sql.Length)
  172. {
  173. char c = _sql[Position];
  174. if (Char.IsWhiteSpace(c)) break;
  175. if (IsSpecialCharacter(c)) break;
  176. Position++;
  177. }
  178. }
  179. Quoted = false;
  180. StopIndex = Position;
  181. }
  182. private void ReadSpecialToken()
  183. {
  184. StartIndex = Position - 1;
  185. Debug.Assert(IsSpecialCharacter(_sql[StartIndex]));
  186. StopIndex = Position;
  187. Quoted = false;
  188. }
  189. /// <summary>
  190. /// Read a single quoted identifier from the stream
  191. /// </summary>
  192. /// <param name="quoteChar"></param>
  193. /// <returns></returns>
  194. private void ReadQuotedToken(char quoteChar)
  195. {
  196. if (quoteChar == '[')
  197. quoteChar = ']';
  198. StartIndex = Position - 1;
  199. bool escaped = false;
  200. bool found = false;
  201. while (Position < _sql.Length)
  202. {
  203. char c = _sql[Position];
  204. if (c == quoteChar && !escaped)
  205. {
  206. found = true;
  207. break;
  208. }
  209. if (escaped)
  210. escaped = false;
  211. else if (c == '\\' && BackslashEscapes)
  212. escaped = true;
  213. Position++;
  214. }
  215. if (found) Position++;
  216. Quoted = found;
  217. StopIndex = Position;
  218. }
  219. private bool IsQuoteChar(char c)
  220. {
  221. return c == '`' || c == '\'' || c == '\"';
  222. }
  223. private bool IsParameterMarker(char c)
  224. {
  225. return c == '@' || c == '?';
  226. }
  227. private bool IsSpecialCharacter(char c)
  228. {
  229. if (Char.IsLetterOrDigit(c) ||
  230. c == '$' || c == '_' || c == '.') return false;
  231. if (IsParameterMarker(c)) return false;
  232. return true;
  233. }
  234. }
  235. }
  236. #endif