PageRenderTime 28ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/SmarterSql/SmarterSql/Parsing/Parser.cs

#
C# | 1549 lines | 1185 code | 192 blank | 172 comment | 631 complexity | 1876bbc3267a2bf58197ceb557700349 MD5 | raw file

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

  1. // ---------------------------------
  2. // SmarterSql (c) Johan Sassner 2008
  3. // ---------------------------------
  4. using System;
  5. using System.Collections.Generic;
  6. using System.ComponentModel;
  7. using System.Diagnostics;
  8. using Microsoft.VisualStudio.TextManager.Interop;
  9. using Sassner.SmarterSql.Objects;
  10. using Sassner.SmarterSql.Parsing.Expressions;
  11. using Sassner.SmarterSql.Parsing.Keywords;
  12. using Sassner.SmarterSql.Parsing.Predicates;
  13. using Sassner.SmarterSql.ParsingObjects;
  14. using Sassner.SmarterSql.ParsingUtils;
  15. using Sassner.SmarterSql.Tree;
  16. using Sassner.SmarterSql.Utils;
  17. using Sassner.SmarterSql.Utils.Helpers;
  18. using Sassner.SmarterSql.Utils.Marker;
  19. using Sassner.SmarterSql.Utils.Segment;
  20. using Sassner.SmarterSql.Utils.SqlErrors;
  21. namespace Sassner.SmarterSql.Parsing {
  22. public class Parser : IDisposable {
  23. #region Member variables
  24. private const string ClassName = "Parser";
  25. private readonly ListOfScannedSqlErrors listOfScannedSqlErrors = new ListOfScannedSqlErrors();
  26. // Tokens
  27. private readonly List<Cursor> calledCursors = new List<Cursor>(50);
  28. private readonly List<ScannedItem> calledLabels = new List<ScannedItem>(100);
  29. private readonly List<LocalVariable> calledLocalVariables = new List<LocalVariable>(150);
  30. private readonly List<ScannedItem> calledTransactions = new List<ScannedItem>(50);
  31. private readonly List<ColumnAlias> declaredColumnAliases = new List<ColumnAlias>(250);
  32. private readonly List<Cursor> declaredCursors = new List<Cursor>(50);
  33. private readonly List<ScannedItem> declaredLabels = new List<ScannedItem>(100);
  34. private readonly List<LocalVariable> declaredLocalVariables = new List<LocalVariable>(150);
  35. private readonly List<ScannedItem> declaredTransactions = new List<ScannedItem>(50);
  36. private readonly List<ScannedTable> lstScannedTables = new List<ScannedTable>(50);
  37. private readonly List<TableSource> lstTableSources = new List<TableSource>(250);
  38. private readonly List<TemporaryTable> lstTemporaryTables = new List<TemporaryTable>(250);
  39. private BackgroundWorker bgWorkerDoFullParse;
  40. private List<TokenInfo> lstTokens = new List<TokenInfo>();
  41. private Markers markers = new Markers();
  42. private int previousTokenRangeStartIndex = -1;
  43. private SegmentUtils segmentUtils = new SegmentUtils(Instance.StaticData);
  44. // Our temporary sysobject id
  45. private int sysObjectId;
  46. #endregion
  47. #region Public properties
  48. public List<TokenInfo> RawTokens {
  49. [DebuggerStepThrough]
  50. get { return lstTokens; }
  51. set { lstTokens = value; }
  52. }
  53. public ListOfScannedSqlErrors ListOfScannedSqlErrors {
  54. [DebuggerStepThrough]
  55. get { return listOfScannedSqlErrors; }
  56. }
  57. public List<ScannedSqlError> ScannedSqlErrors {
  58. [DebuggerStepThrough]
  59. get { return ListOfScannedSqlErrors.ScannedSqlErrors; }
  60. set { ListOfScannedSqlErrors.ScannedSqlErrors = value; }
  61. }
  62. public List<ScannedItem> DeclaredTransactions {
  63. [DebuggerStepThrough]
  64. get { return declaredTransactions; }
  65. }
  66. public List<ScannedItem> CalledTransactions {
  67. [DebuggerStepThrough]
  68. get { return calledTransactions; }
  69. }
  70. public List<ScannedItem> CalledLabels {
  71. [DebuggerStepThrough]
  72. get { return calledLabels; }
  73. }
  74. public List<ScannedItem> DeclaredLabels {
  75. [DebuggerStepThrough]
  76. get { return declaredLabels; }
  77. }
  78. public int SysObjectId {
  79. [DebuggerStepThrough]
  80. get { return sysObjectId; }
  81. }
  82. public List<ScannedTable> ScannedTables {
  83. [DebuggerStepThrough]
  84. get { return lstScannedTables; }
  85. }
  86. public List<Cursor> CalledCursors {
  87. [DebuggerStepThrough]
  88. get { return calledCursors; }
  89. }
  90. public List<Cursor> DeclaredCursors {
  91. [DebuggerStepThrough]
  92. get { return declaredCursors; }
  93. }
  94. public List<ColumnAlias> DeclaredColumnAliases {
  95. [DebuggerStepThrough]
  96. get { return declaredColumnAliases; }
  97. }
  98. public Markers Markers {
  99. [DebuggerStepThrough]
  100. get { return markers; }
  101. set { markers = value; }
  102. }
  103. public List<LocalVariable> DeclaredLocalVariables {
  104. [DebuggerStepThrough]
  105. get { return declaredLocalVariables; }
  106. }
  107. public List<LocalVariable> CalledLocalVariables {
  108. [DebuggerStepThrough]
  109. get { return calledLocalVariables; }
  110. }
  111. public List<TableSource> TableSources {
  112. [DebuggerStepThrough]
  113. get { return lstTableSources; }
  114. }
  115. public List<TemporaryTable> TemporaryTables {
  116. [DebuggerStepThrough]
  117. get { return lstTemporaryTables; }
  118. }
  119. public SegmentUtils SegmentUtils {
  120. get { return segmentUtils; }
  121. set { segmentUtils = value; }
  122. }
  123. #endregion
  124. #region Scan for known tokens
  125. /// <summary>
  126. ///
  127. /// </summary>
  128. /// <param name="lstSysObjects"></param>
  129. /// <param name="bgWorker"></param>
  130. public void ParseTokens(List<SysObject> lstSysObjects, BackgroundWorker bgWorker) {
  131. if (null == segmentUtils) {
  132. return;
  133. }
  134. bgWorkerDoFullParse = bgWorker;
  135. try {
  136. #region Clear lists
  137. calledLocalVariables.Clear();
  138. declaredLocalVariables.Clear();
  139. lstTableSources.Clear();
  140. lstScannedTables.Clear();
  141. lstTemporaryTables.Clear();
  142. calledLabels.Clear();
  143. declaredLabels.Clear();
  144. calledCursors.Clear();
  145. declaredCursors.Clear();
  146. declaredColumnAliases.Clear();
  147. calledTransactions.Clear();
  148. declaredTransactions.Clear();
  149. #endregion
  150. SysObject.RemoveTemporarySysObjects(lstSysObjects);
  151. // Our temporary table id counter
  152. sysObjectId = 0;
  153. previousTokenRangeStartIndex = 0;
  154. ParseTokenRange(null, 0, lstTokens.Count, lstSysObjects);
  155. bgWorkerDoFullParse = null;
  156. #region When all table alias are added, translate the derived tables
  157. // When all table alias are added, translate the derived tables
  158. // First sort the list, deepest table first
  159. lstScannedTables.Sort(ScannedTable.ScannedTableComparison);
  160. foreach (ScannedTable scannedTable in lstScannedTables) {
  161. Token startToken = null;
  162. if (scannedTable.SqlType == Common.enSqlTypes.CTE) {
  163. // For CTE's that are not used, we need to find and correct the tablesource
  164. foreach (TableSource tableSource in lstTableSources) {
  165. if (scannedTable.StartIndex <= tableSource.StartIndex && scannedTable.EndIndex >= tableSource.EndIndex) {
  166. scannedTable.StartTableIndex = tableSource.Table.StartIndex;
  167. scannedTable.EndTableIndex = tableSource.Table.EndIndex;
  168. break;
  169. }
  170. }
  171. } else if (scannedTable.SqlType == Common.enSqlTypes.DerivedTable) {
  172. startToken = lstTokens[scannedTable.StartIndex + 1].Token;
  173. }
  174. CreateScannedTable(startToken, lstSysObjects, scannedTable);
  175. }
  176. #endregion
  177. } catch (Exception e) {
  178. Common.LogEntry(ClassName, "ParseTokens", e, Common.enErrorLvl.Error);
  179. }
  180. }
  181. /// <summary>
  182. /// Parse a range of tokens
  183. /// </summary>
  184. /// <param name="currentStartSpan"></param>
  185. /// <param name="startIndexRange"></param>
  186. /// <param name="endIndexRange"></param>
  187. /// <param name="lstSysObjects"></param>
  188. internal void ParseTokenRange(StatementSpans currentStartSpan, int startIndexRange, int endIndexRange, List<SysObject> lstSysObjects) {
  189. if (startIndexRange < previousTokenRangeStartIndex) {
  190. Common.LogEntry(ClassName, "ParseTokenRange", "Tried to rescan a previous range. startIndexRange=" + startIndexRange + ", endIndexRange=" + endIndexRange + ", previousTokenRangeStartIndex=" + previousTokenRangeStartIndex, Common.enErrorLvl.Warning);
  191. return;
  192. }
  193. previousTokenRangeStartIndex = startIndexRange;
  194. int i = startIndexRange;
  195. while (i < endIndexRange) {
  196. if (null != bgWorkerDoFullParse && bgWorkerDoFullParse.CancellationPending) {
  197. return;
  198. }
  199. int currentI = i;
  200. TokenInfo token = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  201. if (null == token) {
  202. return;
  203. }
  204. if (token.Kind == TokenKind.KeywordSelect) {
  205. #region SELECT
  206. KeywordSelect.ParseSelectForColumns(this, out currentStartSpan, lstSysObjects, ref i, lstTokens, ref sysObjectId);
  207. i++;
  208. #endregion
  209. } else if (token.Kind == TokenKind.KeywordJoin || token.Kind == TokenKind.KeywordFrom) {
  210. #region JOIN & FROM
  211. TableSource.ParseTableSource(this, currentStartSpan, lstSysObjects, ref i, lstTokens, token, ref sysObjectId);
  212. #endregion
  213. } else if (token.Kind == TokenKind.KeywordWhere || token.Kind == TokenKind.KeywordHaving) {
  214. #region WHERE & HAVING
  215. int startIndex = i + 1;
  216. int endIndex = segmentUtils.GetNextMainTokenEnd(currentStartSpan, i);
  217. token = InStatement.GetNextNonCommentToken(lstTokens, startIndex);
  218. if (null == token) {
  219. return;
  220. }
  221. if (token.Kind == TokenKind.KeywordCurrent) {
  222. KeywordUpdate.ParseCurrentOf(this, lstTokens, startIndex, endIndex);
  223. } else {
  224. List<Predicate> predicates;
  225. KeywordSearchCondition.ParseSearchCondition(this, lstTokens, startIndex, endIndex, lstSysObjects, out predicates);
  226. }
  227. i = endIndex;
  228. #endregion
  229. } else if (token.Kind == TokenKind.KeywordGroup) {
  230. #region GROUP BY
  231. int startIndex = i;
  232. int endIndex = segmentUtils.GetNextMainTokenEnd(currentStartSpan, i);
  233. KeywordGroupBy.ParseGroupBy(this, lstTokens, startIndex, endIndex);
  234. i = endIndex;
  235. #endregion
  236. } else if (token.Kind == TokenKind.KeywordOrder) {
  237. #region ORDER BY
  238. int startIndex = i;
  239. int endIndex = segmentUtils.GetNextMainTokenEnd(currentStartSpan, i);
  240. List<Expression> orderByExpressions;
  241. KeywordOrderBy.ParseOrderBy(this, lstTokens, ref startIndex, endIndex, out orderByExpressions);
  242. i = endIndex;
  243. #endregion
  244. } else if (token.Kind == TokenKind.KeywordInsert) {
  245. #region INSERT
  246. KeywordInsert.ParseInsertStatement(this, out currentStartSpan, lstSysObjects, ref i, lstTokens);
  247. #endregion
  248. } else if (token.Kind == TokenKind.KeywordDelete) {
  249. #region DELETE
  250. KeywordDelete.ParseDeleteStatement(this, out currentStartSpan, lstSysObjects, ref i, lstTokens);
  251. #endregion
  252. } else if (token.Kind == TokenKind.KeywordUpdate) {
  253. #region UPDATE
  254. KeywordUpdate.ParseUpdateStatement(this, out currentStartSpan, lstSysObjects, ref i, lstTokens);
  255. #endregion
  256. } else if (token.Kind == TokenKind.KeywordDeclare) {
  257. #region DECLARE
  258. i++;
  259. TokenInfo nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  260. if (null != nextToken) {
  261. if (nextToken.Kind == TokenKind.Name && !nextToken.Token.UnqoutedImage.StartsWith("@")) {
  262. KeywordDeclare.ParseDeclareCursor(this, lstTokens, ref i);
  263. } else {
  264. // Parse a declaration expression
  265. while (true) {
  266. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  267. if (null == nextToken) {
  268. break;
  269. }
  270. TokenInfo startToken = nextToken;
  271. startToken.TokenContextType = TokenContextType.Variable;
  272. int variableIndex = i;
  273. // [ AS ]
  274. InStatement.GetIfAnyNextValidToken(lstTokens, ref i, out nextToken, TokenKind.KeywordAs);
  275. ParsedDataType parsedDataType = ParsedDataType.ParseDataType(lstTokens, ref i);
  276. if (null == parsedDataType) {
  277. break;
  278. }
  279. if (parsedDataType.DataType.Kind == TokenKind.KeywordCursor) {
  280. declaredCursors.Add(new Cursor(startToken.Token.UnqoutedImage, variableIndex));
  281. }
  282. // Create a Variable object
  283. LocalVariable objVariable = new LocalVariable(startToken.Token.UnqoutedImage, variableIndex, parsedDataType);
  284. declaredLocalVariables.Add(objVariable);
  285. // Table datatype?
  286. if (parsedDataType.DataType.Kind == TokenKind.KeywordTable) {
  287. KeywordTable.ParseCreateTable(this, lstTokens, ref variableIndex, lstSysObjects, ref sysObjectId);
  288. break;
  289. }
  290. // More declarations?
  291. int offset2 = i + 1;
  292. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref offset2);
  293. if (null == nextToken || nextToken.Kind != TokenKind.Comma) {
  294. break;
  295. }
  296. i = offset2 + 1;
  297. }
  298. }
  299. }
  300. #endregion
  301. } else if (token.Kind == TokenKind.KeywordFor) {
  302. #region FOR UPDATE (cursor)
  303. // [ FOR UPDATE [ OF column_name [ ,...n ] ] ]
  304. i++;
  305. TokenInfo nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  306. if (null != nextToken && nextToken.Kind == TokenKind.KeywordUpdate) {
  307. i++;
  308. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  309. if (null != nextToken && nextToken.Kind == TokenKind.KeywordOf) {
  310. i++;
  311. }
  312. bool isNextSysColumn = true;
  313. while (isNextSysColumn) {
  314. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  315. if (null != nextToken && nextToken.Type == TokenType.Identifier) {
  316. nextToken.TokenContextType = TokenContextType.CursorColumnUpdatable;
  317. }
  318. i++;
  319. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  320. if (!(null != nextToken && nextToken.Kind == TokenKind.Comma)) {
  321. isNextSysColumn = false;
  322. } else {
  323. i++;
  324. }
  325. }
  326. }
  327. #endregion
  328. } else if (token.Kind == TokenKind.KeywordDeallocate || token.Kind == TokenKind.KeywordOpen || token.Kind == TokenKind.KeywordClose) {
  329. #region DEALLOCATE/OPEN/CLOSE (cursor)
  330. i++;
  331. int offset = i;
  332. TokenInfo nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref offset);
  333. if (null != nextToken && nextToken.Kind == TokenKind.KeywordGlobal) {
  334. offset++;
  335. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref offset);
  336. }
  337. if (null != nextToken && nextToken.Kind == TokenKind.Name) {
  338. nextToken.TokenContextType = TokenContextType.Cursor;
  339. calledCursors.Add(new Cursor(nextToken.Token.UnqoutedImage, offset));
  340. }
  341. #endregion
  342. } else if (token.Kind == TokenKind.KeywordFetch) {
  343. #region FETCH (cursor)
  344. i++;
  345. TokenInfo nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  346. if (null != nextToken) {
  347. if (nextToken.Kind == TokenKind.KeywordNext || nextToken.Kind == TokenKind.KeywordPrior || nextToken.Kind == TokenKind.KeywordFirst || nextToken.Kind == TokenKind.KeywordLast) {
  348. // OK
  349. } else if (nextToken.Kind == TokenKind.KeywordAbsolute || nextToken.Kind == TokenKind.KeywordRelative) {
  350. i++;
  351. InStatement.GetNextNonCommentToken(lstTokens, ref i);
  352. }
  353. i++;
  354. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  355. if (null != nextToken && nextToken.Kind == TokenKind.KeywordFrom) {
  356. i++;
  357. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  358. }
  359. if (null != nextToken && nextToken.Kind == TokenKind.KeywordGlobal) {
  360. i++;
  361. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  362. }
  363. if (null != nextToken && nextToken.Kind == TokenKind.Name) {
  364. nextToken.TokenContextType = TokenContextType.Cursor;
  365. calledCursors.Add(new Cursor(nextToken.Token.UnqoutedImage, i));
  366. i++;
  367. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  368. if (null != nextToken && nextToken.Kind == TokenKind.KeywordInto) {
  369. i++;
  370. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  371. while (null != nextToken && nextToken.Kind == TokenKind.Variable) {
  372. nextToken.TokenContextType = TokenContextType.Variable;
  373. i++;
  374. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  375. if (null == nextToken || nextToken.Kind != TokenKind.Comma) {
  376. break;
  377. }
  378. i++;
  379. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  380. }
  381. }
  382. }
  383. }
  384. #endregion
  385. } else if (token.Kind == TokenKind.SystemVariable) {
  386. #region @@systemvariable usage
  387. token.TokenContextType = TokenContextType.SystemVariable;
  388. i++;
  389. #endregion
  390. } else if (token.Kind == TokenKind.Variable) {
  391. #region @variable usage
  392. token.TokenContextType = TokenContextType.Variable;
  393. LocalVariable.AddCalledVariable(this, token, i);
  394. i++;
  395. #endregion
  396. } else if (token.Kind == TokenKind.KeywordEnable) {
  397. #region Enable Trigger
  398. i++;
  399. TokenInfo nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  400. if (null != nextToken && nextToken.Kind == TokenKind.KeywordTrigger) {
  401. KeywordTrigger.HandleEnableDisableTrigger(lstTokens, ref i);
  402. }
  403. #endregion
  404. } else if (token.Kind == TokenKind.KeywordDisable) {
  405. #region Disable Trigger
  406. i++;
  407. TokenInfo nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  408. if (null != nextToken && nextToken.Kind == TokenKind.KeywordTrigger) {
  409. KeywordTrigger.HandleEnableDisableTrigger(lstTokens, ref i);
  410. }
  411. #endregion
  412. } else if (token.Kind == TokenKind.KeywordCreate) {
  413. #region CREATE TABLE/PROCEDURE/FUNCTION/VIEW/TRIGGER
  414. i++;
  415. TokenInfo nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  416. if (null != nextToken && nextToken.Kind == TokenKind.KeywordTable) {
  417. i++;
  418. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  419. if (null != nextToken && nextToken.Type == TokenType.Identifier) {
  420. KeywordTable.ParseCreateTable(this, lstTokens, ref i, lstSysObjects, ref sysObjectId);
  421. }
  422. } else if (null != nextToken && (nextToken.Kind == TokenKind.KeywordProc || nextToken.Kind == TokenKind.KeywordProcedure)) {
  423. KeywordProcedure.HandleCreateAlterProcedure(this, lstTokens, ref i);
  424. } else if (null != nextToken && nextToken.Kind == TokenKind.KeywordFunction) {
  425. KeywordFunction.HandleCreateAlterFunction(this, lstTokens, ref i);
  426. } else if (null != nextToken && nextToken.Kind == TokenKind.KeywordView) {
  427. KeywordView.HandleCreateAlterView(lstTokens, ref i);
  428. } else if (null != nextToken && nextToken.Kind == TokenKind.KeywordTrigger) {
  429. KeywordTrigger.HandleCreateAlterTrigger(currentStartSpan, lstTokens, ref i, ref sysObjectId, lstSysObjects);
  430. }
  431. #endregion
  432. } else if (token.Kind == TokenKind.KeywordAlter) {
  433. #region ALTER PROCEDURE/FUNCTION/VIEW/TABLE
  434. i++;
  435. TokenInfo nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  436. if (null != nextToken && (nextToken.Kind == TokenKind.KeywordProc || nextToken.Kind == TokenKind.KeywordProcedure)) {
  437. KeywordProcedure.HandleCreateAlterProcedure(this, lstTokens, ref i);
  438. } else if (null != nextToken && nextToken.Kind == TokenKind.KeywordFunction) {
  439. KeywordFunction.HandleCreateAlterFunction(this, lstTokens, ref i);
  440. } else if (null != nextToken && nextToken.Kind == TokenKind.KeywordView) {
  441. KeywordView.HandleCreateAlterView(lstTokens, ref i);
  442. } else if (null != nextToken && nextToken.Kind == TokenKind.KeywordTrigger) {
  443. KeywordTrigger.HandleCreateAlterTrigger(currentStartSpan, lstTokens, ref i, ref sysObjectId, lstSysObjects);
  444. } else if (null != nextToken && nextToken.Kind == TokenKind.KeywordTable) {
  445. KeywordTable.HandleAlterTable(this, lstTokens, ref i, ref sysObjectId, lstSysObjects);
  446. }
  447. #endregion
  448. } else if (token.Kind == TokenKind.KeywordDrop) {
  449. #region DROP TABLE/PROCEDURE
  450. i++;
  451. TokenInfo nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  452. if (null != nextToken && nextToken.Kind == TokenKind.KeywordTable) {
  453. // DROP TABLE [ database_name . [ schema_name ] . | schema_name . ] table_name [ ,...n ] [ ; ]
  454. i++;
  455. bool isNextTableSource = true;
  456. while (isNextTableSource) {
  457. // Normal multi part name
  458. TokenInfo server_name;
  459. TokenInfo database_name;
  460. TokenInfo schema_name;
  461. TokenInfo object_name;
  462. int endTableIndex;
  463. if (ParseTableOrViewName(i, out endTableIndex, out server_name, out database_name, out schema_name, out object_name)) {
  464. // Move the pointer (i) to the token after the table name
  465. i = endTableIndex;
  466. }
  467. i++;
  468. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  469. if (!(null != nextToken && nextToken.Kind == TokenKind.Comma)) {
  470. isNextTableSource = false;
  471. } else {
  472. i++;
  473. }
  474. }
  475. } else if (null != nextToken && (nextToken.Kind == TokenKind.KeywordProc || nextToken.Kind == TokenKind.KeywordProcedure)) {
  476. // DROP { PROC | PROCEDURE } { [ schema_name. ] procedure } [ ,...n ]
  477. i++;
  478. bool isNextSprocName = true;
  479. while (isNextSprocName) {
  480. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  481. if (null != nextToken && nextToken.Type == TokenType.Identifier) {
  482. int index = i + 1;
  483. TokenInfo nextNextToken = InStatement.GetNextNonCommentToken(lstTokens, ref index);
  484. if (null != nextNextToken && nextNextToken.Kind == TokenKind.Dot) {
  485. index++;
  486. nextNextToken = InStatement.GetNextNonCommentToken(lstTokens, ref index);
  487. if (null != nextNextToken && nextNextToken.Type == TokenType.Identifier) {
  488. nextToken.TokenContextType = TokenContextType.SysObjectSchema;
  489. nextNextToken.TokenContextType = TokenContextType.Procedure;
  490. }
  491. } else {
  492. nextToken.TokenContextType = TokenContextType.Procedure;
  493. }
  494. }
  495. i++;
  496. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  497. if (!(null != nextToken && nextToken.Kind == TokenKind.Comma)) {
  498. isNextSprocName = false;
  499. } else {
  500. i++;
  501. }
  502. }
  503. }
  504. #endregion
  505. } else if (token.Kind == TokenKind.KeywordWith) {
  506. #region CTE
  507. KeywordCTE.ParseCTE(this, lstTokens, ref i);
  508. #endregion
  509. } else if (token.Kind == TokenKind.Comma) {
  510. #region a FROM statment or CTE
  511. // If comma, and previous statement was a tablesource try to match the next tokens as a table
  512. if (i > 0) {
  513. int prevIndex = InStatement.GetPreviousNonCommentToken(lstTokens, i - 1, i - 1);
  514. bool isTableToScan = false;
  515. foreach (TableSource tableSource in lstTableSources) {
  516. if (tableSource.EndIndex == prevIndex) {
  517. isTableToScan = true;
  518. break;
  519. }
  520. }
  521. // Either a table as defined above, or NOT a CTE
  522. if (isTableToScan) {
  523. // A tablesource with a comma before
  524. TableSource.ParseTableSource(this, currentStartSpan, lstSysObjects, ref i, lstTokens, token, ref sysObjectId);
  525. } else {
  526. // A possible new CTE. Need to recursivly check backwards for WITH statement
  527. // WITH alias1 (nCol, nCol) AS (SELECT nCol, nCol FROM tablesource), alias2 (nCol, nCol) AS (SELECT nCol, nCol FROM tablesource), alias3 (nCol, nCol) AS (SELECT nCol, nCol FROM tablesource)
  528. int currentIndex = InStatement.GetNextNonCommentToken(lstTokens, i, i);
  529. while (currentIndex > 1) {
  530. currentIndex--;
  531. TokenInfo previoustoken = InStatement.GetPreviousNonCommentToken(lstTokens, ref currentIndex);
  532. if (null != previoustoken && previoustoken.Kind == TokenKind.RightParenthesis) {
  533. currentIndex = previoustoken.MatchingParenToken;
  534. if (currentIndex > 1) {
  535. currentIndex--;
  536. previoustoken = InStatement.GetPreviousNonCommentToken(lstTokens, ref currentIndex);
  537. if (null != previoustoken && previoustoken.Kind == TokenKind.KeywordAs) {
  538. currentIndex--;
  539. previoustoken = InStatement.GetPreviousNonCommentToken(lstTokens, ref currentIndex);
  540. if (null != previoustoken && previoustoken.Kind == TokenKind.RightParenthesis) {
  541. currentIndex = InStatement.GetPreviousNonCommentToken(lstTokens, previoustoken.MatchingParenToken - 1, previoustoken.MatchingParenToken - 1);
  542. }
  543. previoustoken = InStatement.GetPreviousNonCommentToken(lstTokens, ref currentIndex);
  544. if (null != previoustoken && previoustoken.Type == TokenType.Identifier) {
  545. currentIndex--;
  546. previoustoken = InStatement.GetPreviousNonCommentToken(lstTokens, ref currentIndex);
  547. if (null != previoustoken && previoustoken.Kind == TokenKind.KeywordWith) {
  548. KeywordCTE.ParseCTE(this, lstTokens, ref i);
  549. break;
  550. }
  551. if (null != previoustoken && previoustoken.Kind == TokenKind.Comma) {
  552. // It might be another CTE. Continue scanning
  553. } else {
  554. break;
  555. }
  556. }
  557. }
  558. }
  559. } else {
  560. break;
  561. }
  562. }
  563. }
  564. }
  565. i++;
  566. #endregion
  567. } else if (token.Kind == TokenKind.KeywordGoto) {
  568. #region GOTO label
  569. i++;
  570. token = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  571. if (null != token && token.Type == TokenType.Identifier) {
  572. calledLabels.Add(new Label(token.Token.UnqoutedImage, i));
  573. token.TokenContextType = TokenContextType.Label;
  574. }
  575. #endregion
  576. } else if (token.Kind == TokenKind.KeywordUse) {
  577. #region USE databasename
  578. i++;
  579. token = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  580. if (null != token && token.Type == TokenType.Identifier) {
  581. token.TokenContextType = TokenContextType.Database;
  582. }
  583. #endregion
  584. } else if (token.Kind == TokenKind.KeywordExec) {
  585. #region EXECUTE or EXEC
  586. token = InStatement.GetNextNonCommentToken(lstTokens, i + 1);
  587. if (null != token) {
  588. if (token.Kind == TokenKind.LeftParenthesis) {
  589. // <Execute a character string> or <Execute a pass-through command against a linked server>
  590. KeywordExecute.ParseExecuteString(this, lstTokens, ref i);
  591. } else {
  592. // Execute a stored procedure or function
  593. KeywordExecute.ParseExecuteSprocOrFunction(this, lstTokens, ref i);
  594. }
  595. }
  596. i++;
  597. #endregion
  598. } else if (token.Type == TokenType.Label) {
  599. #region Label
  600. declaredLabels.Add(new Label(token.Token.UnqoutedImage, i));
  601. token.TokenContextType = TokenContextType.Label;
  602. i++;
  603. #endregion
  604. } else if (token.Kind == TokenKind.KeywordBegin) {
  605. #region BEGIN
  606. //BEGIN
  607. // {
  608. // sql_statement | statement_block
  609. // }
  610. //END
  611. //BEGIN { TRAN | TRANSACTION }
  612. // [ { transaction_name | @tran_name_variable }
  613. // [ WITH MARK [ 'description' ] ]
  614. // ]
  615. //[ ; ]
  616. //BEGIN DISTRIBUTED { TRAN | TRANSACTION }
  617. // [ transaction_name | @tran_name_variable ]
  618. //[ ; ]
  619. //BEGIN TRY
  620. // { sql_statement | statement_block }
  621. //END TRY
  622. //BEGIN CATCH
  623. // [ { sql_statement | statement_block } ]
  624. //END CATCH
  625. //[ ; ]
  626. InStatement.GetIfAnyNextValidToken(lstTokens, ref i, out token, TokenKind.KeywordDistributed);
  627. if (InStatement.GetIfAnyNextValidToken(lstTokens, ref i, out token, TokenKind.KeywordTransaction)) {
  628. i++;
  629. token = InStatement.GetNextNonCommentToken(lstTokens, i);
  630. if (null != token) {
  631. if (token.Kind == TokenKind.ValueString) {
  632. token.TokenContextType = TokenContextType.TransactionName;
  633. declaredTransactions.Add(new TransactionLabel(token.Token.UnqoutedImage, i));
  634. } else if (token.Kind == TokenKind.Variable) {
  635. token.TokenContextType = TokenContextType.Variable;
  636. calledLocalVariables.Add(new LocalVariable(token.Token.UnqoutedImage, i));
  637. }
  638. if (InStatement.GetIfAllNextValidToken(lstTokens, ref i, out token, TokenKind.KeywordWith, TokenKind.KeywordMark)) {
  639. InStatement.GetIfAnyNextValidToken(lstTokens, ref i, out token, TokenKind.ValueString);
  640. }
  641. }
  642. } else if (InStatement.GetIfAnyNextValidToken(lstTokens, ref i, out token, TokenKind.KeywordTry)) {
  643. } else if (InStatement.GetIfAnyNextValidToken(lstTokens, ref i, out token, TokenKind.KeywordCatch)) {
  644. } else {
  645. i++;
  646. }
  647. #endregion
  648. } else if (token.Kind == TokenKind.KeywordCommit) {
  649. #region COMMIT
  650. //COMMIT { TRAN | TRANSACTION } [ transaction_name | @tran_name_variable ] ]
  651. //[ ; ]
  652. //COMMIT [ WORK ]
  653. //[ ; ]
  654. if (InStatement.GetIfAnyNextValidToken(lstTokens, ref i, out token, TokenKind.KeywordTransaction)) {
  655. i++;
  656. token = InStatement.GetNextNonCommentToken(lstTokens, i);
  657. if (null != token) {
  658. if (token.Kind == TokenKind.ValueString) {
  659. token.TokenContextType = TokenContextType.TransactionName;
  660. calledTransactions.Add(new TransactionLabel(token.Token.UnqoutedImage, i));
  661. } else if (token.Kind == TokenKind.Variable) {
  662. token.TokenContextType = TokenContextType.Variable;
  663. calledLocalVariables.Add(new LocalVariable(token.Token.UnqoutedImage, i));
  664. }
  665. }
  666. } else {
  667. InStatement.GetIfAnyNextValidToken(lstTokens, ref i, out token, TokenKind.KeywordWork);
  668. }
  669. #endregion
  670. } else if (token.Kind == TokenKind.KeywordRollback) {
  671. #region ROLLBACK
  672. //ROLLBACK { TRAN | TRANSACTION }
  673. // [ transaction_name | @tran_name_variable | savepoint_name | @savepoint_variable ]
  674. //[ ; ]
  675. //ROLLBACK [ WORK ]
  676. //[ ; ]
  677. if (InStatement.GetIfAnyNextValidToken(lstTokens, ref i, out token, TokenKind.KeywordTransaction)) {
  678. i++;
  679. token = InStatement.GetNextNonCommentToken(lstTokens, i);
  680. if (null != token) {
  681. if (token.Kind == TokenKind.Name) {
  682. token.TokenContextType = TokenContextType.TransactionName;
  683. calledTransactions.Add(new TransactionLabel(token.Token.UnqoutedImage, i));
  684. } else if (token.Kind == TokenKind.Variable) {
  685. token.TokenContextType = TokenContextType.Variable;
  686. calledLocalVariables.Add(new LocalVariable(token.Token.UnqoutedImage, i));
  687. }
  688. }
  689. } else {
  690. if (!InStatement.GetIfAnyNextValidToken(lstTokens, ref i, out token, TokenKind.KeywordWork)) {
  691. i++;
  692. }
  693. }
  694. #endregion
  695. } else if (token.Kind == TokenKind.KeywordSave) {
  696. #region SAVE
  697. //SAVE { TRAN | TRANSACTION } { savepoint_name | @savepoint_variable }
  698. //[ ; ]
  699. if (InStatement.GetIfAnyNextValidToken(lstTokens, ref i, out token, TokenKind.KeywordTransaction)) {
  700. i++;
  701. token = InStatement.GetNextNonCommentToken(lstTokens, i);
  702. if (null != token) {
  703. if (token.Kind == TokenKind.Name) {
  704. token.TokenContextType = TokenContextType.TransactionName;
  705. declaredTransactions.Add(new TransactionLabel(token.Token.UnqoutedImage, i));
  706. } else if (token.Kind == TokenKind.Variable) {
  707. token.TokenContextType = TokenContextType.Variable;
  708. calledLocalVariables.Add(new LocalVariable(token.Token.UnqoutedImage, i));
  709. }
  710. }
  711. } else {
  712. InStatement.GetIfAnyNextValidToken(lstTokens, ref i, out token, TokenKind.KeywordWork);
  713. }
  714. #endregion
  715. } else if (token.Kind == TokenKind.KeywordTruncate) {
  716. #region TRUNCATE
  717. i++;
  718. TokenInfo nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  719. if (null != nextToken && nextToken.Kind == TokenKind.KeywordTable) {
  720. // TRUNCATE TABLE [ database_name . [ schema_name ] . | schema_name . ] table_name [ ; ]
  721. i++;
  722. // Normal multi part name
  723. TokenInfo server_name;
  724. TokenInfo database_name;
  725. TokenInfo schema_name;
  726. TokenInfo object_name;
  727. int endTableIndex;
  728. if (ParseTableOrViewName(i, out endTableIndex, out server_name, out database_name, out schema_name, out object_name)) {
  729. // Move the pointer (i) to the token after the table name
  730. i = endTableIndex;
  731. }
  732. i++;
  733. }
  734. #endregion
  735. } else {
  736. // Skip to next token
  737. i++;
  738. }
  739. if (i < 0) {
  740. return;
  741. }
  742. // Safety check that we don't get a never-ending loop
  743. if (currentI >= i) {
  744. Common.LogEntry(ClassName, "ParseTokenRange", "Never ending loop detected. previous i=" + currentI + ", and new i=" + i, Common.enErrorLvl.Warning);
  745. i = currentI + 1;
  746. }
  747. }
  748. }
  749. #endregion
  750. #region Debug
  751. internal static void DumpTokens(List<TokenInfo> tokens, int startIndex, int endIndex) {
  752. if (endIndex >= tokens.Count) {
  753. endIndex = tokens.Count - 1;
  754. }
  755. if (startIndex >= tokens.Count) {
  756. startIndex = tokens.Count - 1;
  757. }
  758. string expression = "";
  759. for (int i = startIndex; i <= endIndex; i++) {
  760. expression += tokens[i].Token.UnqoutedImage + " ";
  761. }
  762. // Common.LogEntry(ClassName, "xxx", startIndex + " till " + endIndex + " (" + expression + ")", Common.enErrorLvl.Information);
  763. }
  764. #endregion
  765. #region Create table & sysobject
  766. private void CreateScannedTable(Token startToken, List<SysObject> lstSysObjects, ScannedTable scannedTable) {
  767. try {
  768. // Create a sysObjects entry for dervied/temporary table
  769. SysObject sysObject = SysObject.CreateSysObject(this, lstSysObjects, lstTokens, scannedTable, ref sysObjectId);
  770. if (scannedTable.SqlType == Common.enSqlTypes.DerivedTable || scannedTable.SqlType == Common.enSqlTypes.CTE) {
  771. StatementSpans ss;
  772. Common.GetStatementSpan(scannedTable.Span, segmentUtils.StartTokenIndexes, scannedTable.ParenLevel, out ss);
  773. Table table = new Table(scannedTable.Servername, scannedTable.Databasename, scannedTable.Schema, scannedTable.Name, scannedTable.Alias, sysObject, ss, scannedTable.StartTableIndex, scannedTable.EndTableIndex, false);
  774. int endIndex;
  775. if (scannedTable.SqlType == Common.enSqlTypes.DerivedTable) {
  776. endIndex = scannedTable.EndIndex;
  777. // A derived table can add it's column names after the alias
  778. int index = InStatement.GetNextNonCommentToken(lstTokens, endIndex + 1, endIndex + 1);
  779. TokenInfo token = InStatement.GetNextNonCommentToken(lstTokens, ref index);
  780. if (null != token) {
  781. int matchingParenIndex = token.MatchingParenToken;
  782. if (token.Kind == TokenKind.LeftParenthesis && -1 != matchingParenIndex && matchingParenIndex > index) {
  783. endIndex = matchingParenIndex;
  784. }
  785. }
  786. } else if (scannedTable.SqlType == Common.enSqlTypes.CTE) {
  787. endIndex = scannedTable.EndIndex;
  788. } else {
  789. endIndex = InStatement.GetPreviousNonCommentToken(lstTokens, lstTokens.Count - 1, lstTokens.Count - 1);
  790. Common.LogEntry(ClassName, "CreateScannedTable", "Unhandled sqltype " + scannedTable, Common.enErrorLvl.Error);
  791. }
  792. lstTableSources.Add(new TableSource(startToken, table, scannedTable.StartIndex, endIndex));
  793. } else if (scannedTable.SqlType == Common.enSqlTypes.Temporary) {
  794. // Create temporary table
  795. int startIndex = InStatement.GetNextNonCommentToken(lstTokens, scannedTable.StartIndex + 1, scannedTable.StartIndex + 1);
  796. int endIndex = InStatement.GetNextNonCommentToken(lstTokens, scannedTable.EndIndex + 1, scannedTable.EndIndex + 1);
  797. if (0 == startIndex) {
  798. startIndex = endIndex;
  799. }
  800. TextSpan span = TextSpanHelper.CreateSpanFromTokens(lstTokens[startIndex], lstTokens[endIndex]);
  801. StatementSpans statementSpan = new StatementSpans(lstTokens[startIndex], startIndex, lstTokens[endIndex], endIndex, scannedTable.ParenLevel, true) {
  802. SegmentStartToken = null
  803. };
  804. segmentUtils.StartTokenIndexes.Add(statementSpan);
  805. TemporaryTable tempTable = new TemporaryTable(scannedTable.Name, sysObject, span, scannedTable.ParenLevel, statementSpan, startIndex, endIndex);
  806. lstTemporaryTables.Add(tempTable);
  807. }
  808. } catch (Exception e) {
  809. Common.LogEntry(ClassName, "CreateScannedTable", e, Common.enErrorLvl.Error);
  810. }
  811. }
  812. /// <summary>
  813. /// Create an Table object
  814. /// </summary>
  815. /// <param name="currentStartSpan"></param>
  816. /// <param name="tokenContext"></param>
  817. /// <param name="lstSysObjects"></param>
  818. /// <param name="Servername"></param>
  819. /// <param name="Databasename"></param>
  820. /// <param name="Schema"></param>
  821. /// <param name="Table"></param>
  822. /// <param name="Alias"></param>
  823. /// <param name="startIndex"></param>
  824. /// <param name="endIndex"></param>
  825. /// <param name="startTableIndex"></param>
  826. /// <param name="endTableIndex"></param>
  827. /// <param name="isTemporary"></param>
  828. /// <param name="addedSysObject"></param>
  829. /// <param name="addedTableSource"></param>
  830. internal bool CreateTableEntry(StatementSpans currentStartSpan, Token tokenContext, List<SysObject> lstSysObjects, string Servername, string Databasename, string Schema, string Table, string Alias, int startIndex, int endIndex, int startTableIndex, int endTableIndex, bool isTemporary, out SysObject addedSysObject, out TableSource addedTableSource) {
  831. try {
  832. addedSysObject = null;
  833. // First see if we need to parse a temporary table. Mostly it's from an SELECT.. INTO #temptable
  834. foreach (ScannedTable scannedTable in lstScannedTables) {
  835. if ((scannedTable.SqlType == Common.enSqlTypes.Temporary || scannedTable.SqlType == Common.enSqlTypes.CTE) && Table.Equals(scannedTable.Name, StringComparison.OrdinalIgnoreCase)) {
  836. addedSysObject = SysObject.CreateSysObject(this, lstSysObjects, lstTokens, scannedTable, ref sysObjectId);
  837. lstScannedTables.Remove(scannedTable);
  838. break;
  839. }
  840. }
  841. // Create a Table object
  842. SysObject sysObject;
  843. if (null != Instance.TextEditor.ActiveConnection && Instance.TextEditor.ActiveConnection.SysObjectExists(Table, out sysObject)) {
  844. if (null == addedSysObject) {
  845. addedSysObject = sysObject;
  846. }
  847. StatementSpans ss = segmentUtils.GetStatementSpan(startTableIndex);
  848. Table table = new Table(Servername, Databasename, Schema, Table, Alias, sysObject, ss, startTableIndex, endTableIndex, isTemporary);
  849. addedTableSource = new TableSource(tokenContext, table, startIndex, endIndex);
  850. lstTableSources.Add(addedTableSource);
  851. if (null != currentStartSpan) {
  852. currentStartSpan.AddTableSource(addedTableSource);
  853. }
  854. return true;
  855. }
  856. } catch (Exception e) {
  857. Common.LogEntry(ClassName, "CreateTableEntry", e, Common.enErrorLvl.Error);
  858. }
  859. addedSysObject = null;
  860. addedTableSource = null;
  861. return false;
  862. }
  863. #endregion
  864. #region Scan for errors
  865. /// <summary>
  866. /// Scan for errors. It handles schemas and aliases for:
  867. /// * rowset functions
  868. /// * #temp objects
  869. /// * @table variables
  870. /// * derived tables
  871. /// * cte
  872. /// * tables
  873. /// * views
  874. /// * table valued functions
  875. /// </summary>
  876. /// <param name="bgWorkerScanForErrors"></param>
  877. /// <returns>True if all went well, else false</returns>
  878. public bool ScanForErrors(BackgroundWorker bgWorkerScanForErrors) {
  879. if (null == segmentUtils || null == TextEditor.CurrentWindowData || null == TextEditor.CurrentWindowData.PrimaryActiveView || null == Instance.TextEditor.SysObjects) {
  880. return false;
  881. }
  882. ScannedSqlErrors = new List<ScannedSqlError>();
  883. try {
  884. try {
  885. // Validate sysobject?
  886. if (Instance.Settings.ScanErrorValidateSysObjects) {
  887. ValidateSysObjects();
  888. }
  889. foreach (TableSource tableSource in lstTableSources) {
  890. int startIndex = (tableSource.Table.SysObject.SqlType == Common.enSqlTypes.DerivedTable ? tableSource.Table.EndIndex : tableSource.Table.StartIndex);
  891. int endIndex = tableSource.Table.EndIndex;
  892. int tokenIndex = tableSource.StartIndex;
  893. // Require tablesource alias?
  894. if (Instance.Settings.ScanForErrorRequireTableSourceAlias) {
  895. if (0 == tableSource.Table.Alias.Length) {
  896. if (tableSource.TokenContext != Tokens.kwInsertToken && tableSource.TokenContext != Tokens.kwDeleteToken && tableSource.TokenContext != Tokens.kwUpdateToken && tableSource.TokenContext != Tokens.kwIntoToken) {
  897. ScannedSqlErrors.Add(new ScannedSqlError("No tablesource alias found", new SqlErrorAddSysObjectAlias(this, tableSource), startIndex, endIndex, tokenIndex));
  898. }
  899. }
  900. }
  901. // Require tablesource schema?
  902. if (Instance.Settings.ScanForErrorRequireSchema) {
  903. if (0 == tableSource.Table.Schema.Length && !tableSource.Table.SysObject.IsTemporary) {
  904. ScannedSqlErrors.Add(new ScannedSqlError("No tablesource schema found", new SqlErrorAddSysObjectSchema(tableSource), startIndex, endIndex, tokenIndex));
  905. }
  906. }
  907. // Require AS token?
  908. if (Instance.Settings.ScanForErrorRequireTokenAs) {
  909. if (tableSource.TokenContext != Tokens.kwInsertToken && tableSource.TokenContext != Tokens.kwDeleteToken && tableSource.TokenContext != Tokens.kwUpdateToken) {
  910. if (tableSource.Table.Alias.Length > 0) {
  911. int indexAs = tableSource.Table.EndIndex - 1;
  912. if (indexAs >= tableSource.Table.StartIndex) {
  913. if (lstTokens[indexAs].Kind != TokenKind.KeywordAs) {
  914. ScannedSqlErrors.Add(new ScannedSqlError("No AS keyword found", new SqlErrorAddSysObjectAlias(this, tableSource), startIndex, endIndex, tokenIndex));
  915. }
  916. } else {
  917. ScannedSqlErrors.Add(new ScannedSqlError("No AS keyword found", new SqlErrorAddSysObjectAlias(this, tableSource), startIndex, endIndex, tokenIndex));
  918. }
  919. }
  920. }
  921. }
  922. }
  923. // Require alias on column?
  924. if (Instance.Settings.ScanForErrorRequireColumnTableAlias) {
  925. ValidateColumnAliases();
  926. }
  927. // Unknown tokens creates a squiggle?
  928. if (Instance.Settings.ScanForUnknownTokens) {
  929. ValidateUnknownTokens();
  930. }
  931. // Scan for missing ...
  932. Label.ScanForLabelErrors(this);
  933. TransactionLabel.ScanForTransactionLabelErrors(this);
  934. Cursor.ScanForCursorErrors(this);
  935. LocalVariable.ScanForVariableErrors(this);
  936. ScanForEqualsNull();
  937. } catch (Exception e) {
  938. Common.LogEntry(ClassName, "ScanForErrors", e, Common.enErrorLvl.Error);
  939. }
  940. // Copy errors on same tablesource to all same tablesources
  941. for (int i = 0; i < ScannedSqlErrors.Count; i++) {
  942. ScannedSqlError scannedSqlError1 = ScannedSqlErrors[i];
  943. for (int j = i + 1; j < ScannedSqlErrors.Count; j++) {
  944. ScannedSqlError scannedSqlError2 = ScannedSqlErrors[j];
  945. if (scannedSqlError1.IsSameTableSource(scannedSqlError2)) {
  946. scannedSqlError1.AddScannedSqlError(scannedSqlError2);
  947. scannedSqlError2.AddScannedSqlError(scannedSqlError1);
  948. }
  949. }
  950. }
  951. return true;
  952. } catch (Exception e) {
  953. Common.LogEntry(ClassName, "ScanForErrors", e, Common.enErrorLvl.Error);
  954. return false;
  955. }
  956. }
  957. /// <summary>
  958. /// Scan for "= NULL"
  959. /// </summary>
  960. private void ScanForEqualsNull() {
  961. int index = 0;
  962. while (index < lstTokens.Count) {
  963. TokenInfo token = InStatement.GetNextNonCommentToken(lstTokens, ref index);
  964. index++;
  965. TokenInfo nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref index);
  966. if (null != token && null != nextToken && token.Kind == TokenKind.Assign && nextToken.Kind == TokenKind.KeywordNull) {
  967. Common.SegmentType segmentType = segmentUtils.GetCurrentSegmentType(null, index);
  968. if (segmentType != Common.SegmentType.START) {
  969. ScannedSqlErrors.Add(new ScannedSqlError("Using = NULL is not recommended. Use IS NULL instead", index, index, index));
  970. }
  971. }
  972. index++;
  973. }
  974. }
  975. /// <summary>
  976. /// Scan unknown tokens (from TokenContextType)
  977. /// </summary>
  978. private void ValidateUnknownTokens() {
  979. int index = 0;
  980. while (index < lstTokens.Count) {
  981. TokenInfo token = lstTokens[index];
  982. if (token.Type == TokenType.Identifier && token.TokenContextType == TokenContextType.Unknown) {
  983. foreach (ColumnAlias columnAlias in declaredColumnAliases) {
  984. if (columnAlias.Name.Equals(token.Token.UnqoutedImage, StringComparison.OrdinalIgnoreCase)) {
  985. token.TokenContextType = TokenContextType.ColumnAlias;
  986. break;
  987. }
  988. }
  989. if (token.TokenContextType == TokenContextType.Unknown) {
  990. ScannedSqlErrors.Add(new ScannedSqlError("Unknown token name", index, index, index));
  991. }
  992. }
  993. index++;
  994. }
  995. }
  996. /// <summary>
  997. /// Validate table sources
  998. /// </summary>
  999. private void ValidateSysObjects() {
  1000. int index = 0;
  1001. Connection activeConnection = Instance.TextEditor.ActiveConnection;
  1002. Server activeServer = Instance.TextEditor.ActiveServer;
  1003. if (null == activeConnection || null == activeServer) {
  1004. return;
  1005. }
  1006. while (index < lstTokens.Count) {
  1007. TokenInfo token = lstTokens[index];
  1008. string unqoutedImage = token.Token.UnqoutedImage;
  1009. List<SysObjectSchema> schemas;
  1010. SysObject sysObject;
  1011. switch (token.TokenContextType) {
  1012. case TokenContextType.Unknown:
  1013. if (token.Kind == TokenKind.Name) {
  1014. schemas = activeConnection.GetSysObjectSchemas();
  1015. foreach (SysObjectSchema schema in schemas) {
  1016. if (unqoutedImage.Equals(schema.Schema, StringComparison.OrdinalIgnoreCase)) {
  1017. token.TokenContextType = TokenContextType.SysObjectSchema;
  1018. break;
  1019. }
  1020. }
  1021. if (token.TokenContextType == TokenContextType.Unknown) {
  1022. if (activeConnection.SysObjectExists(unqoutedImage, out sysObject)) {
  1023. token.TokenContextType = TokenContextType.SysObject;
  1024. }
  1025. }
  1026. }
  1027. break;
  1028. case TokenContextType.Server:
  1029. // Validate server name
  1030. bool serverNameIsOk = false;
  1031. List<SysServer> sysServers = activeServer.GetSysServers();
  1032. foreach (SysServer sysServer in sysServers) {
  1033. if (unqoutedImage.Equals(sysServer.ServerName, StringComparison.OrdinalIgnoreCase)) {
  1034. serverNameIsOk = true;
  1035. break;
  1036. }
  1037. }
  1038. if (!serverNameIsOk) {
  1039. ScannedSqlErrors.Add(new ScannedSqlError("Unknown server name", index, index, index));
  1040. }
  1041. break;
  1042. case TokenContextType.Database:
  1043. // Validate database name
  1044. bool databaseNameIsOk = false;
  1045. List<Database> databases = activeServer.GetDataBases();
  1046. foreach (Database database in databases) {
  1047. if (unqoutedImage.Equals(database.DataBaseName, StringComparison.OrdinalIgnoreCase)) {
  1048. databaseNameIsOk = true;
  1049. break;
  1050. }
  1051. }
  1052. if (!databaseNameIsOk) {
  1053. ScannedSqlErrors.Add(new ScannedSqlError("Unknown database name", index, index, index));
  1054. }
  1055. break;
  1056. case TokenContextType.SysObjectSchema:
  1057. // Validate schema name
  1058. bool schemaNameIsOk = false;
  1059. schemas = activeConnection.GetSysObjectSchemas();
  1060. foreach (SysObjectSchema schema in schemas) {
  1061. if (unqoutedImage.Equals(schema.Schema, StringComparison.OrdinalIgnoreCase)) {
  1062. schemaNameIsOk = true;
  1063. break;
  1064. }
  1065. }
  1066. if (!schemaNameIsOk) {
  1067. ScannedSqlErrors.Add(new ScannedSqlError("Unknown schema name", index, index, index));
  1068. }
  1069. break;
  1070. case TokenContextType.TempTable:
  1071. case TokenContextType.SysObject:
  1072. // Validate sysobject name
  1073. if (!activeConnection.SysObjectExists(unqoutedImage, out sysObject)) {
  1074. ScannedSqlErrors.Add(new ScannedSqlError("Unknown sysobject name", index, index, index));
  1075. }
  1076. break;
  1077. }
  1078. index++;
  1079. }
  1080. }
  1081. /// <summary>
  1082. /// Validate that column alias are correct, i.e. that they exists for sysobject columns
  1083. /// </summary>
  1084. private void ValidateColumnAliases() {
  1085. if (null == segmentUtils.StartTokenIndexesSortByInnerLevel) {
  1086. return;
  1087. }
  1088. List<int> handledTokenIndexes = new List<int>();
  1089. foreach (StatementSpans span in segmentUtils.StartTokenIndexesSortByInnerLevel) {
  1090. List<TableSource> lstFoundTableSources;
  1091. if (segmentUtils.GetStatementSpanTablesources(span, out lstFoundTableSources)) {
  1092. int index = span.StartIndex;
  1093. while (index <= span.EndIndex) {
  1094. TokenInfo token = lstTokens[index];
  1095. int arrayIndex;
  1096. if (token.TokenContextType == TokenContextType.SysObjectAlias && (arrayIndex = handledTokenIndexes.BinarySearch(index)) < 0) {
  1097. handledTokenIndexes.Insert(~arrayIndex, index);
  1098. bool foundAlias = false;
  1099. foreach (TableSource tableSource in lstFoundTableSources) {
  1100. if (tableSource.Table.Alias.Equals(token.Token.UnqoutedImage, StringComparison.OrdinalIgnoreCase) || tableSource.Table.Alias.Equals(token.Token.Image, StringComparison.OrdinalIgnoreCase)) {
  1101. foundAlias = true;
  1102. break;
  1103. }
  1104. }
  1105. if (!foundAlias) {
  1106. ScannedSqlErrors.Add(new ScannedSqlError("Unknown sysobject alias '" + token.Token.Image + "'", null, index, index, index));
  1107. }
  1108. } else if (token.TokenContextType == TokenContextType.SysObjectColumn && (arrayIndex = handledTokenIndexes.BinarySearch(index)) < 0) {
  1109. handledTokenIndexes.Insert(~arrayIndex, index);
  1110. int offset = index - 1;
  1111. bool foundCorrectSysobject = false;
  1112. string column = token.Token.UnqoutedImage;
  1113. int nbOfColumnMatches = 0;
  1114. List<TableSource> lstDuplicateTokens = new List<TableSource>();
  1115. string alias = "";
  1116. TokenInfo prevToken = InStatement.GetPrevio

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