/SmarterSql/SmarterSql/Parsing/Keywords/KeywordDerivedTable.cs

# · C# · 183 lines · 140 code · 15 blank · 28 comment · 44 complexity · 93526685dddb2f9c7c974f7e7de4cafa MD5 · raw file

  1. // ---------------------------------
  2. // SmarterSql (c) Johan Sassner 2008
  3. // ---------------------------------
  4. using System.Collections.Generic;
  5. using Sassner.SmarterSql.Objects;
  6. using Sassner.SmarterSql.Parsing.Predicates;
  7. using Sassner.SmarterSql.Parsing.SelectItems;
  8. using Sassner.SmarterSql.ParsingUtils;
  9. using Sassner.SmarterSql.Tree;
  10. using Sassner.SmarterSql.Utils;
  11. namespace Sassner.SmarterSql.Parsing.Keywords {
  12. public class KeywordDerivedTable {
  13. #region Derived tables parsing functions
  14. /// <summary>
  15. /// Parse a derived table
  16. /// </summary>
  17. /// <param name="parser"></param>
  18. /// <param name="currentStartSpan"></param>
  19. /// <param name="lstTokens"></param>
  20. /// <param name="i"></param>
  21. /// <param name="lstSysObjects"></param>
  22. /// <param name="startIndex"></param>
  23. /// <param name="sysObjectId"></param>
  24. /// <param name="addedSysObject"></param>
  25. /// <param name="addedTableSource"></param>
  26. /// <param name="startToken"></param>
  27. public static bool ParseDerivedTable(Parser parser, StatementSpans currentStartSpan, List<TokenInfo> lstTokens, ref int i,
  28. List<SysObject> lstSysObjects, int startIndex, ref int sysObjectId, out SysObject addedSysObject, out TableSource addedTableSource,
  29. TokenInfo startToken) {
  30. TokenInfo nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  31. if (null == nextToken || nextToken.Kind != TokenKind.LeftParenthesis) {
  32. addedSysObject = null;
  33. addedTableSource = null;
  34. return false;
  35. }
  36. int offset = nextToken.MatchingParenToken;
  37. nextToken = InStatement.GetNextNonCommentToken(lstTokens, offset);
  38. if (null != nextToken && nextToken.Kind == TokenKind.RightParenthesis && offset + 1 < lstTokens.Count) {
  39. int startSubSelect = InStatement.GetNextNonCommentToken(lstTokens, i + 1, i + 1);
  40. int endSubSelect = offset - 1;
  41. if (startSubSelect > endSubSelect) {
  42. addedSysObject = null;
  43. addedTableSource = null;
  44. return false;
  45. }
  46. // Parse sub select
  47. parser.ParseTokenRange(currentStartSpan, startSubSelect, endSubSelect, lstSysObjects);
  48. StatementSpans ss = parser.SegmentUtils.GetStatementSpan(startSubSelect);
  49. List<SysObjectColumn> lstSysObjectColumn = new List<SysObjectColumn>();
  50. if (null != ss && null != ss.SelectItems) {
  51. // Set the new sysobject for the columns
  52. foreach (SelectItem selectItem in ss.SelectItems) {
  53. foreach (SysObjectColumn sysObjectColumn in selectItem.SysObjectColumns) {
  54. if (null != sysObjectColumn) {
  55. lstSysObjectColumn.Add(sysObjectColumn);
  56. }
  57. }
  58. }
  59. }
  60. int statementStartIndex = i;
  61. int statementEndIndex = offset;
  62. int tableStartIndex = startSubSelect;
  63. int realEndIndex;
  64. if (GetAliasAndSearchCondition(parser, statementStartIndex, tableStartIndex, statementEndIndex, out realEndIndex, lstTokens, lstSysObjects,
  65. startSubSelect, currentStartSpan, startToken, Common.enSqlTypes.DerivedTable, ref sysObjectId, out addedSysObject,
  66. out addedTableSource, startIndex, lstSysObjectColumn)) {
  67. i = realEndIndex;
  68. return true;
  69. }
  70. }
  71. addedSysObject = null;
  72. addedTableSource = null;
  73. return false;
  74. }
  75. public static bool GetAliasAndSearchCondition(Parser parser, int startStatementIndex, int startTableIndex, int endStatementIndex, out int realEndIndex,
  76. List<TokenInfo> lstTokens, List<SysObject> lstSysObjects, int statementStartIndex, StatementSpans currentStartSpan,
  77. TokenInfo startToken, Common.enSqlTypes sqlType, ref int sysObjectId, out SysObject addedSysObject,
  78. out TableSource addedTableSource, int startIndex, List<SysObjectColumn> lstSysObjectColumn) {
  79. TokenInfo nextToken;
  80. string Table = string.Empty;
  81. string Alias;
  82. int endTableIndex = endStatementIndex + 1;
  83. if (parser.ExtractTableAlias(endTableIndex, ref endTableIndex, out Alias)) {
  84. Table = Alias;
  85. }
  86. realEndIndex = endTableIndex;
  87. List<string> lstNewColumNames = null;
  88. if (sqlType == Common.enSqlTypes.DerivedTable) {
  89. lstNewColumNames = GetDerivedTableNewColumnNames(lstTokens, ref realEndIndex);
  90. }
  91. int startSearchCondition = realEndIndex;
  92. List<Predicate> predicates;
  93. if (startToken.Kind == TokenKind.KeywordJoin) {
  94. realEndIndex = KeywordSearchCondition.FindLengthOfSearchCondition(parser, lstTokens, startSearchCondition);
  95. while (startSearchCondition < realEndIndex) {
  96. nextToken = InStatement.GetNextNonCommentToken(lstTokens, startSearchCondition);
  97. if (null == nextToken) {
  98. addedSysObject = null;
  99. addedTableSource = null;
  100. realEndIndex = 0;
  101. return false;
  102. }
  103. if (nextToken.Kind == TokenKind.KeywordOn) {
  104. startSearchCondition++;
  105. break;
  106. }
  107. startSearchCondition++;
  108. }
  109. }
  110. // Create a SysObject object
  111. addedSysObject = SysObject.CreateTemporarySysObject(Table, sqlType, ref sysObjectId);
  112. lstSysObjects.Add(addedSysObject);
  113. foreach (SysObjectColumn sysObjectColumn in lstSysObjectColumn) {
  114. sysObjectColumn.ParentSysObject = addedSysObject;
  115. addedSysObject.AddColumn(sysObjectColumn);
  116. }
  117. // If we have matching new column names, set them
  118. if (null != lstNewColumNames && lstNewColumNames.Count == addedSysObject.Columns.Count) {
  119. for (int j = 0; j < addedSysObject.Columns.Count; j++) {
  120. addedSysObject.Columns[j].ColumnName = lstNewColumNames[j];
  121. }
  122. }
  123. // Create the table source
  124. StatementSpans ss = parser.SegmentUtils.GetStatementSpan(startTableIndex);
  125. Table table = new Table("", "", "", Table, Alias, addedSysObject, ss, startTableIndex, endTableIndex, true);
  126. addedTableSource = new TableSource(lstTokens[startTableIndex].Token, table, startIndex, realEndIndex);
  127. parser.TableSources.Add(addedTableSource);
  128. if (null != currentStartSpan) {
  129. currentStartSpan.AddTableSource(addedTableSource);
  130. }
  131. // Find the search conditions and parse them
  132. KeywordSearchCondition.ParseSearchCondition(parser, lstTokens, startSearchCondition, realEndIndex, lstSysObjects, out predicates);
  133. return true;
  134. }
  135. /// <summary>
  136. /// Get new column aliases for a derived table
  137. /// </summary>
  138. /// <param name="lstTokens"></param>
  139. /// <param name="i"></param>
  140. /// <returns></returns>
  141. private static List<string> GetDerivedTableNewColumnNames(List<TokenInfo> lstTokens, ref int i) {
  142. TokenInfo token;
  143. if (!InStatement.GetIfAllNextValidToken(lstTokens, ref i, out token, TokenKind.LeftParenthesis)) {
  144. return null;
  145. }
  146. if (-1 == token.MatchingParenToken || i > token.MatchingParenToken) {
  147. return null;
  148. }
  149. int matchingParenIndex = token.MatchingParenToken;
  150. List<string> lstNewColumNames = new List<string>();
  151. i++;
  152. while (i < matchingParenIndex) {
  153. token = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  154. if (null != token) {
  155. if (token.Type == TokenType.Identifier) {
  156. lstNewColumNames.Add(token.Token.UnqoutedImage);
  157. token.TokenContextType = TokenContextType.NewColumnAlias;
  158. }
  159. } else {
  160. break;
  161. }
  162. i++;
  163. }
  164. return lstNewColumNames;
  165. }
  166. #endregion
  167. }
  168. }