PageRenderTime 106ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/SmarterSql/SmarterSql/Utils/Segment/SegmentUtils.cs

#
C# | 975 lines | 779 code | 113 blank | 83 comment | 314 complexity | 01a4971b6a9db2bee0cceaafe56f6766 MD5 | raw file
  1. // ---------------------------------
  2. // SmarterSql (c) Johan Sassner 2008
  3. // ---------------------------------
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using Microsoft.VisualStudio.TextManager.Interop;
  8. using Sassner.SmarterSql.Objects;
  9. using Sassner.SmarterSql.Parsing;
  10. using Sassner.SmarterSql.ParsingUtils;
  11. using Sassner.SmarterSql.Tree;
  12. using Sassner.SmarterSql.Utils.Marker;
  13. namespace Sassner.SmarterSql.Utils.Segment {
  14. public class SegmentUtils : IDisposable {
  15. #region Member variables
  16. private const string ClassName = "SegmentUtils";
  17. // TODO: Retrieve user settings for the BatchSeparator
  18. private const string BatchSeparator = "go";
  19. private readonly List<StatementSpans> lstCaseSS = new List<StatementSpans>();
  20. private readonly List<StatementSpans> lstIFSS = new List<StatementSpans>();
  21. private readonly List<BatchSegment> batchSegments = new List<BatchSegment>();
  22. private readonly StaticData objStaticData;
  23. private readonly List<StatementSpans> startTokenIndexes = new List<StatementSpans>();
  24. private readonly List<StatementSpans> startTokenIndexesSortByInnerLevel = new List<StatementSpans>();
  25. #endregion
  26. public SegmentUtils(StaticData objStaticData) {
  27. this.objStaticData = objStaticData;
  28. }
  29. #region public properties
  30. public List<BatchSegment> BatchSegments {
  31. [DebuggerStepThrough]
  32. get { return batchSegments; }
  33. }
  34. public List<StatementSpans> StartTokenIndexesSortByInnerLevel {
  35. [DebuggerStepThrough]
  36. get { return startTokenIndexesSortByInnerLevel; }
  37. }
  38. public List<StatementSpans> StartTokenIndexes {
  39. [DebuggerStepThrough]
  40. get { return startTokenIndexes; }
  41. }
  42. public List<StatementSpans> CaseStartTokenIndexes {
  43. [DebuggerStepThrough]
  44. get { return lstCaseSS; }
  45. }
  46. public List<StatementSpans> IfStartTokenIndexes {
  47. [DebuggerStepThrough]
  48. get { return lstIFSS; }
  49. }
  50. #endregion
  51. #region Parse and find segments
  52. /// <summary>
  53. /// Parse all tokens and find segments
  54. /// </summary>
  55. /// <param name="lstTokens"></param>
  56. /// <returns></returns>
  57. public bool ParseSegments(List<TokenInfo> lstTokens) {
  58. try {
  59. startTokenIndexes.Clear();
  60. startTokenIndexesSortByInnerLevel.Clear();
  61. FindCaseAndIfSegments(lstTokens);
  62. if (FindRawSegments(lstTokens)) {
  63. // Find all not completed segments, and set it to the last token in the scope
  64. // The user needs to fix this to be able to run it
  65. for (int i = StartTokenIndexes.Count - 1; i >= 0; i--) {
  66. StatementSpans ss = StartTokenIndexes[i];
  67. if (null == ss.End) {
  68. ss.EndIndex = lstTokens.Count - 1;
  69. ss.End = lstTokens[ss.EndIndex];
  70. }
  71. }
  72. // Add sub statements to the parent statement
  73. for (int i = 0; i < startTokenIndexes.Count; i++) {
  74. StatementSpans span1 = startTokenIndexes[i];
  75. for (int j = i + 1; j < startTokenIndexes.Count; j++) {
  76. StatementSpans span2 = startTokenIndexes[j];
  77. if (span1.StartIndex <= span2.StartIndex && span1.EndIndex >= span2.EndIndex) {
  78. span2.ParentStatmentSpan = span1;
  79. span1.AddsubStatementSpans(span2);
  80. }
  81. }
  82. }
  83. // Find CURSOR declarations & join select statments
  84. for (int i = StartTokenIndexes.Count - 1; i >= 0; i--) {
  85. StatementSpans spans1 = StartTokenIndexes[i];
  86. if (null != spans1.SegmentStartToken && null != spans1.SegmentStartToken.StartToken && spans1.SegmentStartToken.StartToken.Kind == TokenKind.KeywordDeclare && spans1.End.Kind == TokenKind.KeywordFor && i + 1 < StartTokenIndexes.Count) {
  87. StatementSpans spans2 = StartTokenIndexes[i + 1];
  88. if (null != spans2.SegmentStartToken && null != spans2.SegmentStartToken.StartToken && spans2.SegmentStartToken.StartToken.Kind == TokenKind.KeywordSelect) {
  89. StatementSpans spans3 = null;
  90. if (i + 2 < StartTokenIndexes.Count) {
  91. spans3 = StartTokenIndexes[i + 2];
  92. if (!(null != spans3.SegmentStartToken && spans3.SegmentStartToken.StartToken.Kind == TokenKind.KeywordUpdate && lstTokens[spans2.EndIndex].Kind == TokenKind.KeywordFor)) {
  93. spans3 = null;
  94. }
  95. }
  96. spans2.StartIndex = spans1.StartIndex;
  97. spans2.Start = spans1.Start;
  98. if (null != spans3) {
  99. spans2.EndIndex = spans3.EndIndex;
  100. spans2.End = spans3.End;
  101. StartTokenIndexes.RemoveAt(i + 2);
  102. }
  103. StartTokenIndexes.RemoveAt(i);
  104. }
  105. }
  106. }
  107. // Join TRIGGER and INSERT/UPDATE/DELETE segments
  108. for (int i = StartTokenIndexes.Count - 1; i >= 0; i--) {
  109. StatementSpans spans1 = StartTokenIndexes[i];
  110. if (null != spans1.SegmentStartToken && null != spans1.SegmentStartToken.StartToken && i + 1 < StartTokenIndexes.Count) {
  111. if (spans1.SegmentStartToken.StartToken.Kind == TokenKind.KeywordCreate || spans1.SegmentStartToken.StartToken.Kind == TokenKind.KeywordAlter) {
  112. TokenInfo token = InStatement.GetNextNonCommentToken(lstTokens, spans1.StartIndex + 1);
  113. if (token.Kind == TokenKind.KeywordTrigger) {
  114. while (i < StartTokenIndexes.Count) {
  115. StatementSpans spans2 = StartTokenIndexes[i + 1];
  116. if (null != spans2.SegmentStartToken && null != spans2.SegmentStartToken.StartToken && (spans2.End.Kind == TokenKind.KeywordAs || spans2.End.Kind == TokenKind.Comma)) {
  117. if (spans2.SegmentStartToken.StartToken.Kind == TokenKind.KeywordInsert || spans2.SegmentStartToken.StartToken.Kind == TokenKind.KeywordUpdate || spans2.SegmentStartToken.StartToken.Kind == TokenKind.KeywordDelete) {
  118. spans1.EndIndex = spans2.EndIndex;
  119. spans1.End = spans2.End;
  120. StartTokenIndexes.RemoveAt(i + 1);
  121. } else {
  122. break;
  123. }
  124. } else {
  125. break;
  126. }
  127. }
  128. }
  129. }
  130. }
  131. }
  132. // Join UPDATE and SET segments
  133. for (int i = StartTokenIndexes.Count - 1; i >= 0; i--) {
  134. StatementSpans spans1 = StartTokenIndexes[i];
  135. if (null != spans1.SegmentStartToken && null != spans1.SegmentStartToken.StartToken && spans1.SegmentStartToken.StartToken.Kind == TokenKind.KeywordUpdate && i + 1 < StartTokenIndexes.Count) {
  136. StatementSpans spans2 = StartTokenIndexes[i + 1];
  137. if (null != spans2.SegmentStartToken && null != spans2.SegmentStartToken.StartToken && spans2.SegmentStartToken.StartToken.Kind == TokenKind.KeywordSet) {
  138. spans1.EndIndex = spans2.EndIndex;
  139. spans1.End = spans2.End;
  140. StartTokenIndexes.RemoveAt(i + 1);
  141. }
  142. }
  143. }
  144. // Find segments where a Common Table Expression (CTE) precedes a SELECT/INSERT/UPDATE/DELETE statment
  145. for (int i = StartTokenIndexes.Count - 1; i >= 0; i--) {
  146. StatementSpans ssMain = StartTokenIndexes[i];
  147. TokenInfo token = InStatement.GetNextNonCommentToken(lstTokens, ssMain.StartIndex);
  148. if (null != token && token.Kind == TokenKind.KeywordWith) {
  149. for (int j = i + 1; j < StartTokenIndexes.Count; j++) {
  150. StatementSpans ssNext = StartTokenIndexes[j];
  151. if (ssMain.ParenLevel == ssNext.ParenLevel) {
  152. TokenInfo nextSegmentToken = InStatement.GetNextNonCommentToken(lstTokens, ssNext.StartIndex);
  153. if (nextSegmentToken.Kind == TokenKind.KeywordSelect || nextSegmentToken.Kind == TokenKind.KeywordInsert || nextSegmentToken.Kind == TokenKind.KeywordUpdate || nextSegmentToken.Kind == TokenKind.KeywordDelete) {
  154. ssMain.JoinedSpanNext = ssNext;
  155. ssNext.JoinedSpanPrev = ssMain;
  156. break;
  157. }
  158. }
  159. }
  160. }
  161. }
  162. // Join segments that are joined with a UNION
  163. for (int i = StartTokenIndexes.Count - 1; i >= 0; i--) {
  164. StatementSpans ssMain = StartTokenIndexes[i];
  165. TokenInfo tokenStart = InStatement.GetNextNonCommentToken(lstTokens, ssMain.StartIndex);
  166. if (null != tokenStart && tokenStart.Kind == TokenKind.KeywordSelect) {
  167. int endIndex = ssMain.EndIndex + 1;
  168. TokenInfo tokenEnd = InStatement.GetNextNonCommentToken(lstTokens, ref endIndex);
  169. if (null != tokenEnd) {
  170. if (tokenEnd.Kind == TokenKind.RightParenthesis) {
  171. endIndex++;
  172. tokenEnd = InStatement.GetNextNonCommentToken(lstTokens, ref endIndex);
  173. }
  174. // Search for UNION [ALL]
  175. if (null != tokenEnd && tokenEnd.Kind == TokenKind.KeywordUnion) {
  176. if (i + 1 < StartTokenIndexes.Count) {
  177. StatementSpans ssNext = StartTokenIndexes[i + 1];
  178. tokenStart = InStatement.GetNextNonCommentToken(lstTokens, ssNext.StartIndex);
  179. if (null != tokenStart && tokenStart.Kind == TokenKind.KeywordSelect) {
  180. ssMain.JoinedSpanNext = ssNext;
  181. ssNext.JoinedSpanPrev = ssMain;
  182. }
  183. }
  184. }
  185. }
  186. }
  187. }
  188. // Find INTO, FROM, WHERE, GROUP, HAVING and ORDER keywords and mark them
  189. foreach (StatementSpans spans in StartTokenIndexes) {
  190. int i = spans.StartIndex;
  191. while (i <= spans.EndIndex) {
  192. TokenInfo token = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  193. if (spans.ParenLevel == token.ParenLevel) {
  194. if (token.Kind == TokenKind.KeywordFrom) {
  195. spans.FromIndex = i;
  196. spans.From = token;
  197. } else if (token.Kind == TokenKind.KeywordInto) {
  198. spans.IntoIndex = i;
  199. spans.Into = token;
  200. } else if (token.Kind == TokenKind.KeywordWhere) {
  201. spans.WhereIndex = i;
  202. spans.Where = token;
  203. } else if (token.Kind == TokenKind.KeywordGroup) {
  204. spans.GroupIndex = i;
  205. spans.Group = token;
  206. } else if (token.Kind == TokenKind.KeywordHaving) {
  207. spans.HavingIndex = i;
  208. spans.Having = token;
  209. } else if (token.Kind == TokenKind.KeywordOrder) {
  210. spans.OrderbyIndex = i;
  211. spans.Orderby = token;
  212. }
  213. }
  214. i++;
  215. }
  216. }
  217. foreach (StatementSpans span in startTokenIndexes) {
  218. startTokenIndexesSortByInnerLevel.Add(span);
  219. }
  220. startTokenIndexesSortByInnerLevel.Sort(SortByMostInnerLevel);
  221. return true;
  222. }
  223. } catch (Exception e) {
  224. Common.LogEntry(ClassName, "ParseSegments", e, Common.enErrorLvl.Error);
  225. }
  226. return false;
  227. }
  228. /// <summary>
  229. /// Find segments using start tokens
  230. /// </summary>
  231. /// <param name="lstTokens"></param>
  232. /// <returns></returns>
  233. private bool FindRawSegments(List<TokenInfo> lstTokens) {
  234. try {
  235. int i = 0;
  236. TokenInfo tiStart = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  237. int parenLevel = (null != tiStart ? tiStart.ParenLevel : 0);
  238. int batchStart = 0;
  239. batchSegments.Clear();
  240. while (i < lstTokens.Count) {
  241. TokenInfo token = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  242. TokenInfo nextToken = InStatement.GetNextNonCommentToken(lstTokens, i + 1);
  243. if (token.Token.UnqoutedImage.Equals(BatchSeparator, StringComparison.OrdinalIgnoreCase)) {
  244. batchSegments.Add(new BatchSegment(batchStart, i - 1));
  245. batchStart = i;
  246. }
  247. // Any start token indexes to close? i.e. that are finished?
  248. if (token.ParenLevel < parenLevel) {
  249. foreach (StatementSpans ss in StartTokenIndexes) {
  250. if (null == ss.End && ss.ParenLevel == parenLevel) {
  251. int endIndex = InStatement.GetPreviousNonCommentToken(lstTokens, i - 1, i - 1);
  252. ss.End = (i - 1 >= 0 ? lstTokens[endIndex] : token);
  253. ss.EndIndex = (i - 1 >= 0 ? endIndex : 0);
  254. break;
  255. }
  256. }
  257. }
  258. parenLevel = token.ParenLevel;
  259. // Is this token an end token?
  260. SegmentEndToken segmentEndToken;
  261. if (token != tiStart && SegmentEndToken.isEndSegmentToken(objStaticData, token, out segmentEndToken)) {
  262. if (segmentEndToken.Match(token)) {
  263. foreach (StatementSpans ss in StartTokenIndexes) {
  264. if (null == ss.End && ss.ParenLevel == parenLevel) {
  265. if (segmentEndToken.IncludeTokenInStatement) {
  266. ss.End = token;
  267. ss.EndIndex = i;
  268. } else {
  269. int endIndex = InStatement.GetPreviousNonCommentToken(lstTokens, i - 1, i - 1);
  270. ss.End = (i - 1 >= 0 ? lstTokens[endIndex] : tiStart);
  271. ss.EndIndex = endIndex;
  272. }
  273. break;
  274. }
  275. }
  276. }
  277. }
  278. // Is this token an start token?
  279. SegmentStartToken segmentStartToken;
  280. if (SegmentStartToken.isStartSegmentToken(objStaticData, token, out segmentStartToken)) {
  281. if (segmentStartToken.Match(token, nextToken)) {
  282. foreach (StatementSpans ss in StartTokenIndexes) {
  283. if (null == ss.End && ss.ParenLevel == parenLevel) {
  284. int endIndex = InStatement.GetPreviousNonCommentToken(lstTokens, i - 1, i - 1);
  285. ss.End = (i - 1 >= 0 ? lstTokens[endIndex] : tiStart);
  286. ss.EndIndex = endIndex;
  287. break;
  288. }
  289. }
  290. // Create a new StatementSpans
  291. StatementSpans ssNew = new StatementSpans(token, i, null, -1, parenLevel, true) {
  292. SegmentStartToken = segmentStartToken
  293. };
  294. StartTokenIndexes.Add(ssNew);
  295. }
  296. }
  297. i++;
  298. }
  299. // Add the last batchsegment
  300. batchSegments.Add(new BatchSegment(batchStart, lstTokens.Count - 1));
  301. if (null != tiStart) {
  302. foreach (StatementSpans ss in StartTokenIndexes) {
  303. if (null == ss.End && ss.ParenLevel == parenLevel) {
  304. int endIndex = InStatement.GetPreviousNonCommentToken(lstTokens, lstTokens.Count - 1, lstTokens.Count - 1);
  305. ss.End = lstTokens[endIndex];
  306. ss.EndIndex = endIndex;
  307. break;
  308. }
  309. }
  310. }
  311. if (StartTokenIndexes.Count > 0) {
  312. // If the last segment is open, complete it
  313. StatementSpans ssLast = StartTokenIndexes[StartTokenIndexes.Count - 1];
  314. if (null == ssLast.End && lstTokens.Count > 0) {
  315. int endIndex = InStatement.GetPreviousNonCommentToken(lstTokens, lstTokens.Count - 1, lstTokens.Count - 1);
  316. ssLast.End = lstTokens[endIndex];
  317. ssLast.EndIndex = endIndex;
  318. }
  319. }
  320. return true;
  321. } catch (Exception e) {
  322. Common.LogEntry(ClassName, "FindRawSegments", e, Common.enErrorLvl.Error);
  323. return false;
  324. }
  325. }
  326. private void FindCaseAndIfSegments(List<TokenInfo> lstTokens) {
  327. try {
  328. List<int> lstStartPositions = new List<int>();
  329. List<int> lstWhenIndexes = new List<int>();
  330. List<int> lstThenIndexes = new List<int>();
  331. List<int> lstElseIndexes = new List<int>();
  332. lstCaseSS.Clear();
  333. lstIFSS.Clear();
  334. // CASE
  335. int i = 0;
  336. while (i < lstTokens.Count) {
  337. TokenInfo token = lstTokens[i];
  338. switch (token.Kind) {
  339. case TokenKind.KeywordCase:
  340. lstStartPositions.Add(i);
  341. token.TokenContextType = TokenContextType.CaseStart;
  342. break;
  343. case TokenKind.KeywordWhen:
  344. lstWhenIndexes.Add(i);
  345. break;
  346. case TokenKind.KeywordThen:
  347. lstThenIndexes.Add(i);
  348. break;
  349. case TokenKind.KeywordElse:
  350. lstElseIndexes.Add(i);
  351. break;
  352. case TokenKind.KeywordEnd:
  353. if (lstStartPositions.Count > 0) {
  354. token.TokenContextType = TokenContextType.CaseEnd;
  355. int startIndex = lstStartPositions[lstStartPositions.Count - 1];
  356. lstStartPositions.RemoveAt(lstStartPositions.Count - 1);
  357. lstCaseSS.Add(new StatementSpans(lstTokens[startIndex], startIndex, lstTokens[i], i, token.ParenLevel, false));
  358. }
  359. break;
  360. }
  361. i++;
  362. }
  363. // Match WHEN, THEN and ELSE to their correct CASE-END's
  364. for (i = 0; i < lstCaseSS.Count; i++) {
  365. StatementSpans span = lstCaseSS[i];
  366. // WHEN
  367. for (int j = lstWhenIndexes.Count - 1; j >= 0; j--) {
  368. int index = lstWhenIndexes[j];
  369. if (span.StartIndex < index && index < span.EndIndex) {
  370. span.AddWhenIndexFirst(index);
  371. lstWhenIndexes.RemoveAt(j);
  372. lstTokens[index].TokenContextType = TokenContextType.CaseWhen;
  373. }
  374. }
  375. // THEN
  376. for (int j = lstThenIndexes.Count - 1; j >= 0; j--) {
  377. int index = lstThenIndexes[j];
  378. if (span.StartIndex < index && index < span.EndIndex) {
  379. span.AddThenIndexFirst(index);
  380. lstThenIndexes.RemoveAt(j);
  381. lstTokens[index].TokenContextType = TokenContextType.CaseThen;
  382. }
  383. }
  384. // ELSE
  385. for (int j = lstElseIndexes.Count - 1; j >= 0; j--) {
  386. int index = lstElseIndexes[j];
  387. if (span.StartIndex < index && index < span.EndIndex) {
  388. span.AddElseIndexFirst(index);
  389. lstElseIndexes.RemoveAt(j);
  390. lstTokens[index].TokenContextType = TokenContextType.CaseElse;
  391. break;
  392. }
  393. }
  394. }
  395. // IF
  396. lstStartPositions.Clear();
  397. i = 0;
  398. while (i < lstTokens.Count) {
  399. TokenInfo token = lstTokens[i];
  400. switch (token.Kind) {
  401. case TokenKind.KeywordIf:
  402. lstStartPositions.Add(i);
  403. token.TokenContextType = TokenContextType.IfStart;
  404. break;
  405. case TokenKind.KeywordEnd:
  406. if (token.TokenContextType != TokenContextType.CaseEnd) {
  407. token.TokenContextType = TokenContextType.IfEnd;
  408. if (lstStartPositions.Count > 0) {
  409. TokenInfo nextToken = InStatement.GetNextNonCommentToken(lstTokens, i + 1);
  410. if (null != nextToken) {
  411. if (nextToken.Kind != TokenKind.KeywordElse) {
  412. int startIndex = lstStartPositions[lstStartPositions.Count - 1];
  413. lstStartPositions.RemoveAt(lstStartPositions.Count - 1);
  414. lstIFSS.Add(new StatementSpans(lstTokens[startIndex], startIndex, lstTokens[i], i, token.ParenLevel, false));
  415. } else {
  416. nextToken.TokenContextType = TokenContextType.IfElse;
  417. }
  418. }
  419. }
  420. }
  421. break;
  422. case TokenKind.KeywordElse:
  423. if (token.TokenContextType != TokenContextType.CaseElse) {
  424. token.TokenContextType = TokenContextType.IfElse;
  425. }
  426. break;
  427. }
  428. i++;
  429. }
  430. } catch (Exception e) {
  431. Common.LogEntry(ClassName, "FindRawSegments", e, Common.enErrorLvl.Error);
  432. }
  433. }
  434. #endregion
  435. #region Get statements
  436. /// <summary>
  437. /// Retrieve the statementsegment containing the supplied index in the list of tokens.
  438. /// Get the inner most segment first
  439. /// </summary>
  440. /// <param name="startIndex"></param>
  441. /// <returns></returns>
  442. public StatementSpans GetStatementSpan(int startIndex) {
  443. foreach (StatementSpans span in startTokenIndexesSortByInnerLevel) {
  444. if (span.StartIndex <= startIndex && startIndex <= span.EndIndex) {
  445. return span;
  446. }
  447. }
  448. return null;
  449. }
  450. /// <summary>
  451. /// Retrieve the CASE/END statementsegment containing the supplied index in the list of tokens.
  452. /// </summary>
  453. /// <param name="startIndex"></param>
  454. /// <returns></returns>
  455. public StatementSpans GetCaseStatementSpan(int startIndex) {
  456. foreach (StatementSpans span in lstCaseSS) {
  457. if (span.StartIndex <= startIndex && startIndex <= span.EndIndex) {
  458. return span;
  459. }
  460. }
  461. return null;
  462. }
  463. /// <summary>
  464. /// Retrieve next statementsegment starting from the supplied index
  465. /// </summary>
  466. /// <param name="currentIndex"></param>
  467. /// <returns></returns>
  468. public StatementSpans GetNextStatementSpanStart(int currentIndex) {
  469. StatementSpans firstSpan = null;
  470. foreach (StatementSpans span in startTokenIndexes) {
  471. if (span.StartIndex >= currentIndex) {
  472. if (null == firstSpan) {
  473. firstSpan = span;
  474. }
  475. if (firstSpan.StartIndex > span.StartIndex) {
  476. firstSpan = span;
  477. }
  478. }
  479. }
  480. return firstSpan;
  481. }
  482. #endregion
  483. #region Get table sources
  484. public bool GetUniqueStatementSpanTablesources(int currentIndex, out List<TableSource> lstFoundTableSources, out StatementSpans currentSpan, bool ignoreAlias) {
  485. currentSpan = GetStatementSpan(currentIndex);
  486. if (GetStatementSpanTablesources(currentSpan, out lstFoundTableSources)) {
  487. lstFoundTableSources = (ignoreAlias ? TableSource.GetUniqueTableSourceSysObjects(currentSpan, lstFoundTableSources) : TableSource.GetUniqueTableSources(currentSpan, lstFoundTableSources));
  488. return true;
  489. }
  490. return false;
  491. }
  492. public bool GetStatementSpanTablesources(int currentIndex, out List<TableSource> lstFoundTablesources, out StatementSpans currentSpan) {
  493. currentSpan = GetStatementSpan(currentIndex);
  494. return GetStatementSpanTablesources(currentSpan, out lstFoundTablesources);
  495. }
  496. public bool GetUniqueStatementSpanTablesources(StatementSpans currentSpan, out List<TableSource> lstFoundTableSources, bool ignoreAlias) {
  497. if (GetStatementSpanTablesources(currentSpan, out lstFoundTableSources)) {
  498. lstFoundTableSources = (ignoreAlias ? TableSource.GetUniqueTableSourceSysObjects(currentSpan, lstFoundTableSources) : TableSource.GetUniqueTableSources(currentSpan, lstFoundTableSources));
  499. return true;
  500. }
  501. return false;
  502. }
  503. public bool GetStatementSpanTablesources(StatementSpans currentSpan, out List<TableSource> lstFoundTablesources) {
  504. if (null == currentSpan) {
  505. lstFoundTablesources = new List<TableSource>();
  506. return false;
  507. }
  508. if (null != currentSpan.NearbyTableSources) {
  509. lstFoundTablesources = currentSpan.NearbyTableSources;
  510. return true;
  511. }
  512. bool subselectExists = currentSpan.IsSubSelect && null != currentSpan.ParentStatmentSpan;
  513. // Fetch the capacity needed for this list
  514. int capacity = currentSpan.TableSources.Count + 10;
  515. if (subselectExists) {
  516. capacity += currentSpan.ParentStatmentSpan.TableSources.Count;
  517. }
  518. StatementSpans joinedSpan = currentSpan.JoinedSpanPrev;
  519. while (null != joinedSpan) {
  520. capacity += joinedSpan.TableSources.Count;
  521. joinedSpan = joinedSpan.JoinedSpanPrev;
  522. }
  523. // Check all next StatementSpans
  524. joinedSpan = currentSpan.JoinedSpanNext;
  525. while (null != joinedSpan) {
  526. capacity += joinedSpan.TableSources.Count; joinedSpan = joinedSpan.JoinedSpanNext;
  527. }
  528. // Allocate the list of tablesources
  529. lstFoundTablesources = new List<TableSource>(capacity);
  530. try {
  531. // Add matching tablesources
  532. foreach (TableSource tableSource in currentSpan.TableSources) {
  533. lstFoundTablesources.Add(tableSource);
  534. }
  535. // If it's an subselect, add the parent matching tablesources
  536. if (subselectExists) {
  537. foreach (TableSource tableSource in currentSpan.ParentStatmentSpan.TableSources) {
  538. lstFoundTablesources.Add(tableSource);
  539. }
  540. }
  541. // Check all previous StatementSpans
  542. joinedSpan = currentSpan.JoinedSpanPrev;
  543. while (null != joinedSpan) {
  544. foreach (TableSource tableSource in joinedSpan.TableSources) {
  545. lstFoundTablesources.Add(tableSource);
  546. }
  547. joinedSpan = joinedSpan.JoinedSpanPrev;
  548. }
  549. // Check all next StatementSpans
  550. joinedSpan = currentSpan.JoinedSpanNext;
  551. while (null != joinedSpan) {
  552. foreach (TableSource tableSource in joinedSpan.TableSources) {
  553. lstFoundTablesources.Add(tableSource);
  554. }
  555. joinedSpan = joinedSpan.JoinedSpanNext;
  556. }
  557. currentSpan.NearbyTableSources = lstFoundTablesources;
  558. } catch (Exception e) {
  559. Common.LogEntry(ClassName, "GetStatementSpanTablesources", e, Common.enErrorLvl.Error);
  560. return false;
  561. }
  562. return true;
  563. }
  564. #endregion
  565. #region Misc methods
  566. private static int SortByMostInnerLevel(StatementSpans statementSpan1, StatementSpans statementSpan2) {
  567. if (statementSpan2.ParenLevel == statementSpan1.ParenLevel) {
  568. return statementSpan2.StartIndex - statementSpan1.StartIndex;
  569. }
  570. return statementSpan2.ParenLevel - statementSpan1.ParenLevel;
  571. }
  572. /// <summary>
  573. /// Get the type of segment the supplied index of tokens are of
  574. /// </summary>
  575. /// <param name="ss"></param>
  576. /// <param name="startIndex"></param>
  577. /// <returns></returns>
  578. public Common.SegmentType GetCurrentSegmentType(StatementSpans ss, int startIndex) {
  579. Common.SegmentType segmentType = Common.SegmentType.UNKNOWN;
  580. if (null == ss) {
  581. ss = GetStatementSpan(startIndex);
  582. }
  583. if (null == ss) {
  584. return segmentType;
  585. }
  586. if (ss.SegmentStartToken.StartToken == Tokens.kwSelectToken) {
  587. segmentType = Common.SegmentType.SELECT;
  588. } else if (ss.SegmentStartToken.StartToken == Tokens.kwInsertToken) {
  589. segmentType = Common.SegmentType.INSERT;
  590. } else if (ss.SegmentStartToken.StartToken == Tokens.kwUpdateToken) {
  591. segmentType = Common.SegmentType.UPDATE;
  592. } else if (ss.SegmentStartToken.StartToken == Tokens.kwCreateToken) {
  593. return Common.SegmentType.CREATE;
  594. } else if (ss.SegmentStartToken.StartToken == Tokens.kwAlterToken) {
  595. return Common.SegmentType.ALTER;
  596. }
  597. if (-1 != ss.FromIndex && ss.FromIndex <= startIndex) {
  598. segmentType = Common.SegmentType.FROM;
  599. }
  600. if (-1 != ss.WhereIndex && ss.WhereIndex <= startIndex) {
  601. segmentType = Common.SegmentType.WHERE;
  602. }
  603. if (-1 != ss.GroupIndex && ss.GroupIndex <= startIndex) {
  604. segmentType = Common.SegmentType.GROUP;
  605. }
  606. if (-1 != ss.HavingIndex && ss.HavingIndex <= startIndex) {
  607. segmentType = Common.SegmentType.HAVING;
  608. }
  609. if (-1 != ss.OrderbyIndex && ss.OrderbyIndex <= startIndex) {
  610. segmentType = Common.SegmentType.ORDER;
  611. }
  612. return segmentType;
  613. }
  614. /// <summary>
  615. /// Return the index of the next "main" token later than the supplied startIndex
  616. /// </summary>
  617. /// <param name="ss"></param>
  618. /// <param name="startIndex"></param>
  619. /// <returns></returns>
  620. public int GetNextMainTokenEnd(StatementSpans ss, int startIndex) {
  621. if (null == ss) {
  622. ss = GetStatementSpan(startIndex);
  623. }
  624. if (null == ss) {
  625. return startIndex;
  626. }
  627. if (-1 != ss.FromIndex && ss.FromIndex > startIndex) {
  628. return ss.FromIndex;
  629. }
  630. if (-1 != ss.WhereIndex && ss.WhereIndex > startIndex) {
  631. return ss.WhereIndex;
  632. }
  633. if (-1 != ss.GroupIndex && ss.GroupIndex > startIndex) {
  634. return ss.GroupIndex;
  635. }
  636. if (-1 != ss.HavingIndex && ss.HavingIndex > startIndex) {
  637. return ss.HavingIndex;
  638. }
  639. if (-1 != ss.OrderbyIndex && ss.OrderbyIndex > startIndex) {
  640. return ss.OrderbyIndex;
  641. }
  642. return ss.EndIndex;
  643. }
  644. /// <summary>
  645. /// Retrieve the indexes of tokens that resides in a StatementSpans, excluding sub statements
  646. /// </summary>
  647. /// <param name="ss"></param>
  648. /// <returns></returns>
  649. public List<int> GetTokenIndexesForStatementSpan(StatementSpans ss) {
  650. List<int> lstIndexes = new List<int>();
  651. try {
  652. // Add the supplied StatementSpan indexes
  653. for (int i = ss.StartIndex; i <= ss.EndIndex; i++) {
  654. lstIndexes.Add(i);
  655. }
  656. int indexBeforeFrom = ss.FromIndex;
  657. int indexAfterFrom = ss.EndIndex;
  658. if (-1 != ss.WhereIndex && ss.WhereIndex < indexAfterFrom) {
  659. indexAfterFrom = ss.WhereIndex - 1;
  660. }
  661. if (-1 != ss.GroupIndex && ss.GroupIndex < indexAfterFrom) {
  662. indexAfterFrom = ss.GroupIndex - 1;
  663. }
  664. if (-1 != ss.HavingIndex && ss.HavingIndex < indexAfterFrom) {
  665. indexAfterFrom = ss.HavingIndex - 1;
  666. }
  667. if (-1 != ss.OrderbyIndex && ss.OrderbyIndex < indexAfterFrom) {
  668. indexAfterFrom = ss.OrderbyIndex - 1;
  669. }
  670. foreach (StatementSpans spans in StartTokenIndexes) {
  671. if (spans.StartIndex > ss.StartIndex && spans.EndIndex < ss.EndIndex && !(spans.StartIndex < indexBeforeFrom || spans.StartIndex > indexAfterFrom)) {
  672. for (int i = spans.StartIndex; i <= spans.EndIndex; i++) {
  673. lstIndexes.Remove(i);
  674. }
  675. }
  676. }
  677. } catch (Exception e) {
  678. Common.LogEntry(ClassName, "GetTokenIndexesForStatementSpan", e, Common.enErrorLvl.Error);
  679. lstIndexes.Clear();
  680. }
  681. return lstIndexes;
  682. }
  683. #endregion
  684. #region Segment markers (debug)
  685. private readonly Markers segmentMarkers = new Markers();
  686. public void clearSegment() {
  687. try {
  688. InvalidateSegmentSquiggle();
  689. } catch (Exception e) {
  690. Common.LogEntry(ClassName, "clearSegment", e, Common.enErrorLvl.Error);
  691. }
  692. }
  693. public void selectTokensInSegment(int selectedIndex, List<TokenInfo> lstTokens) {
  694. if (selectedIndex < StartTokenIndexes.Count) {
  695. try {
  696. InvalidateSegmentSquiggle();
  697. StatementSpans ss = StartTokenIndexes[selectedIndex];
  698. List<int> lstIndexes = GetTokenIndexesForStatementSpan(ss);
  699. if (lstIndexes.Count > 0) {
  700. IVsTextLines ppBuffer;
  701. TextEditor.CurrentWindowData.ActiveView.GetBuffer(out ppBuffer);
  702. int startIndex = lstIndexes[0];
  703. int previous = lstIndexes[0] - 1;
  704. foreach (int i in lstIndexes) {
  705. if (previous + 1 != i) {
  706. Squiggle squiggleSegment = segmentMarkers.CreateMarker(ppBuffer, "Statement" + startIndex, lstTokens, startIndex, previous, "Segment" + startIndex, null, (int)MARKERTYPE.MARKER_CODESENSE_ERROR);
  707. squiggleSegment.Marker.SetVisualStyle((uint)(MARKERVISUAL.MV_BORDER));
  708. startIndex = i;
  709. }
  710. previous = i;
  711. }
  712. Squiggle squiggleSegment2 = segmentMarkers.CreateMarker(ppBuffer, "Statement" + startIndex, lstTokens, startIndex, previous, "Segment" + startIndex, null, (int)MARKERTYPE.MARKER_CODESENSE_ERROR);
  713. squiggleSegment2.Marker.SetVisualStyle((uint)(MARKERVISUAL.MV_BORDER));
  714. }
  715. } catch (Exception e) {
  716. Common.ErrorMsg(e.ToString());
  717. }
  718. }
  719. }
  720. public void selectSegment(int selectedIndex, List<TokenInfo> RawTokens) {
  721. if (selectedIndex < StartTokenIndexes.Count) {
  722. try {
  723. InvalidateSegmentSquiggle();
  724. StatementSpans ss = StartTokenIndexes[selectedIndex];
  725. IVsTextLines ppBuffer;
  726. TextEditor.CurrentWindowData.ActiveView.GetBuffer(out ppBuffer);
  727. // Retrieve the markers
  728. Guid pguidMarkerGreen = new Guid("{CCB8B9D5-1643-4B41-8395-53C5B5ED5284}");
  729. int piMarkerTypeIDGreen;
  730. Instance.VsTextMgr.GetRegisteredMarkerTypeID(ref pguidMarkerGreen, out piMarkerTypeIDGreen);
  731. Squiggle squiggleSegment = segmentMarkers.CreateMarker(ppBuffer, "Statement", RawTokens, ss.StartIndex, ss.EndIndex, "Segment", null, (int)MARKERTYPE.MARKER_CODESENSE_ERROR);
  732. squiggleSegment.Marker.SetVisualStyle((uint)(MARKERVISUAL.MV_BORDER));
  733. if (-1 != ss.FromIndex) {
  734. squiggleSegment = segmentMarkers.CreateMarker(ppBuffer, "StatementFrom", RawTokens, ss.FromIndex, ss.FromIndex, "SegmentFrom", null, piMarkerTypeIDGreen);
  735. squiggleSegment.Marker.SetVisualStyle((uint)(MARKERVISUAL.MV_BORDER));
  736. uint pwdFlags;
  737. squiggleSegment.Marker.GetVisualStyle(out pwdFlags);
  738. squiggleSegment.Marker.SetVisualStyle((pwdFlags & ~(uint)MARKERVISUAL.MV_GLYPH));
  739. }
  740. if (-1 != ss.WhereIndex) {
  741. squiggleSegment = segmentMarkers.CreateMarker(ppBuffer, "StatementWhere", RawTokens, ss.WhereIndex, ss.WhereIndex, "SegmentWhere", null, piMarkerTypeIDGreen);
  742. squiggleSegment.Marker.SetVisualStyle((uint)(MARKERVISUAL.MV_BORDER));
  743. uint pwdFlags;
  744. squiggleSegment.Marker.GetVisualStyle(out pwdFlags);
  745. squiggleSegment.Marker.SetVisualStyle((pwdFlags & ~(uint)MARKERVISUAL.MV_GLYPH));
  746. }
  747. if (-1 != ss.GroupIndex) {
  748. squiggleSegment = segmentMarkers.CreateMarker(ppBuffer, "StatemenGroup", RawTokens, ss.GroupIndex, ss.GroupIndex, "StatemenGroup", null, piMarkerTypeIDGreen);
  749. squiggleSegment.Marker.SetVisualStyle((uint)(MARKERVISUAL.MV_BORDER));
  750. uint pwdFlags;
  751. squiggleSegment.Marker.GetVisualStyle(out pwdFlags);
  752. squiggleSegment.Marker.SetVisualStyle((pwdFlags & ~(uint)MARKERVISUAL.MV_GLYPH));
  753. }
  754. if (-1 != ss.HavingIndex) {
  755. squiggleSegment = segmentMarkers.CreateMarker(ppBuffer, "StatementHaving", RawTokens, ss.HavingIndex, ss.HavingIndex, "StatementHaving", null, piMarkerTypeIDGreen);
  756. squiggleSegment.Marker.SetVisualStyle((uint)(MARKERVISUAL.MV_BORDER));
  757. uint pwdFlags;
  758. squiggleSegment.Marker.GetVisualStyle(out pwdFlags);
  759. squiggleSegment.Marker.SetVisualStyle((pwdFlags & ~(uint)MARKERVISUAL.MV_GLYPH));
  760. }
  761. if (-1 != ss.OrderbyIndex) {
  762. squiggleSegment = segmentMarkers.CreateMarker(ppBuffer, "SegmentOrderby", RawTokens, ss.OrderbyIndex, ss.OrderbyIndex, "SegmentOrderby", null, piMarkerTypeIDGreen);
  763. squiggleSegment.Marker.SetVisualStyle((uint)(MARKERVISUAL.MV_BORDER));
  764. uint pwdFlags;
  765. squiggleSegment.Marker.GetVisualStyle(out pwdFlags);
  766. squiggleSegment.Marker.SetVisualStyle((pwdFlags & ~(uint)MARKERVISUAL.MV_GLYPH));
  767. }
  768. Common.MakeSureCursorIsVisible(TextEditor.CurrentWindowData.ActiveView, RawTokens[ss.StartIndex].Span.iStartLine, Common.enPosition.Center);
  769. } catch (Exception e) {
  770. Common.ErrorMsg(e.ToString());
  771. }
  772. }
  773. }
  774. public void InvalidateSegmentSquiggle() {
  775. segmentMarkers.RemoveAll();
  776. }
  777. #endregion
  778. #region Case segment markers (debug)
  779. private readonly Markers caseSegmentMarkers = new Markers();
  780. public void ClearCaseSegment() {
  781. try {
  782. InvalidateCaseSegmentSquiggle();
  783. } catch (Exception e) {
  784. Common.LogEntry(ClassName, "clearCaseSegment", e, Common.enErrorLvl.Error);
  785. }
  786. }
  787. public void SelectCaseSegment(int selectedIndex, List<TokenInfo> RawTokens) {
  788. if (selectedIndex < StartTokenIndexes.Count) {
  789. try {
  790. InvalidateCaseSegmentSquiggle();
  791. StatementSpans ss = CaseStartTokenIndexes[selectedIndex];
  792. IVsTextLines ppBuffer;
  793. TextEditor.CurrentWindowData.ActiveView.GetBuffer(out ppBuffer);
  794. // Retrieve the markers
  795. Guid pguidMarkerGreen = new Guid("{CCB8B9D5-1643-4B41-8395-53C5B5ED5284}");
  796. int piMarkerTypeIDGreen;
  797. Instance.VsTextMgr.GetRegisteredMarkerTypeID(ref pguidMarkerGreen, out piMarkerTypeIDGreen);
  798. Squiggle squigglecaseSegment = caseSegmentMarkers.CreateMarker(ppBuffer, "Statement", RawTokens, ss.StartIndex, ss.EndIndex, "caseSegment", null, (int)MARKERTYPE.MARKER_CODESENSE_ERROR);
  799. squigglecaseSegment.Marker.SetVisualStyle((uint)(MARKERVISUAL.MV_BORDER));
  800. if (-1 != ss.FromIndex) {
  801. squigglecaseSegment = caseSegmentMarkers.CreateMarker(ppBuffer, "StatementFrom", RawTokens, ss.FromIndex, ss.FromIndex, "caseSegmentFrom", null, piMarkerTypeIDGreen);
  802. squigglecaseSegment.Marker.SetVisualStyle((uint)(MARKERVISUAL.MV_BORDER));
  803. uint pwdFlags;
  804. squigglecaseSegment.Marker.GetVisualStyle(out pwdFlags);
  805. squigglecaseSegment.Marker.SetVisualStyle((pwdFlags & ~(uint)MARKERVISUAL.MV_GLYPH));
  806. }
  807. if (-1 != ss.WhereIndex) {
  808. squigglecaseSegment = caseSegmentMarkers.CreateMarker(ppBuffer, "StatementWhere", RawTokens, ss.WhereIndex, ss.WhereIndex, "caseSegmentWhere", null, piMarkerTypeIDGreen);
  809. squigglecaseSegment.Marker.SetVisualStyle((uint)(MARKERVISUAL.MV_BORDER));
  810. uint pwdFlags;
  811. squigglecaseSegment.Marker.GetVisualStyle(out pwdFlags);
  812. squigglecaseSegment.Marker.SetVisualStyle((pwdFlags & ~(uint)MARKERVISUAL.MV_GLYPH));
  813. }
  814. if (-1 != ss.GroupIndex) {
  815. squigglecaseSegment = caseSegmentMarkers.CreateMarker(ppBuffer, "StatemenGroup", RawTokens, ss.GroupIndex, ss.GroupIndex, "StatemenGroup", null, piMarkerTypeIDGreen);
  816. squigglecaseSegment.Marker.SetVisualStyle((uint)(MARKERVISUAL.MV_BORDER));
  817. uint pwdFlags;
  818. squigglecaseSegment.Marker.GetVisualStyle(out pwdFlags);
  819. squigglecaseSegment.Marker.SetVisualStyle((pwdFlags & ~(uint)MARKERVISUAL.MV_GLYPH));
  820. }
  821. if (-1 != ss.HavingIndex) {
  822. squigglecaseSegment = caseSegmentMarkers.CreateMarker(ppBuffer, "StatementHaving", RawTokens, ss.HavingIndex, ss.HavingIndex, "StatementHaving", null, piMarkerTypeIDGreen);
  823. squigglecaseSegment.Marker.SetVisualStyle((uint)(MARKERVISUAL.MV_BORDER));
  824. uint pwdFlags;
  825. squigglecaseSegment.Marker.GetVisualStyle(out pwdFlags);
  826. squigglecaseSegment.Marker.SetVisualStyle((pwdFlags & ~(uint)MARKERVISUAL.MV_GLYPH));
  827. }
  828. if (-1 != ss.OrderbyIndex) {
  829. squigglecaseSegment = caseSegmentMarkers.CreateMarker(ppBuffer, "caseSegmentOrderby", RawTokens, ss.OrderbyIndex, ss.OrderbyIndex, "caseSegmentOrderby", null, piMarkerTypeIDGreen);
  830. squigglecaseSegment.Marker.SetVisualStyle((uint)(MARKERVISUAL.MV_BORDER));
  831. uint pwdFlags;
  832. squigglecaseSegment.Marker.GetVisualStyle(out pwdFlags);
  833. squigglecaseSegment.Marker.SetVisualStyle((pwdFlags & ~(uint)MARKERVISUAL.MV_GLYPH));
  834. }
  835. Common.MakeSureCursorIsVisible(TextEditor.CurrentWindowData.ActiveView, RawTokens[ss.StartIndex].Span.iStartLine, Common.enPosition.Center);
  836. } catch (Exception e) {
  837. Common.ErrorMsg(e.ToString());
  838. }
  839. }
  840. }
  841. public void InvalidateCaseSegmentSquiggle() {
  842. caseSegmentMarkers.RemoveAll();
  843. }
  844. #endregion
  845. #region IDisposable Members
  846. ///<summary>
  847. ///Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
  848. ///</summary>
  849. ///<filterpriority>2</filterpriority>
  850. public void Dispose() {
  851. }
  852. #endregion
  853. public BatchSegment GetBatchSegment(int tokenIndex) {
  854. foreach (BatchSegment segment in batchSegments) {
  855. if (segment.IsInSegment(tokenIndex)) {
  856. return segment;
  857. }
  858. }
  859. return null;
  860. }
  861. }
  862. }