PageRenderTime 50ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/SmarterSql/SmarterSql/Parsing/Keywords/KeywordTable.cs

#
C# | 357 lines | 199 code | 24 blank | 134 comment | 110 complexity | 15e840989c8071234135ba46e2b1e3c0 MD5 | raw file
  1. // ---------------------------------
  2. // SmarterSql (c) Johan Sassner 2008
  3. // ---------------------------------
  4. using System.Collections.Generic;
  5. using Microsoft.VisualStudio.TextManager.Interop;
  6. using Sassner.SmarterSql.Objects;
  7. using Sassner.SmarterSql.ParsingUtils;
  8. using Sassner.SmarterSql.Tree;
  9. using Sassner.SmarterSql.Utils;
  10. using Sassner.SmarterSql.Utils.Helpers;
  11. namespace Sassner.SmarterSql.Parsing.Keywords {
  12. public class KeywordTable {
  13. #region Parse CREATE TABLE
  14. /// <summary>
  15. /// Parse a CREATE TABLE
  16. /// // CREATE TABLE [ database_name . [ schema_name ] . | schema_name . ] table_name
  17. /// ( { <column_definition> | <computed_column_definition> } [ <table_constraint> ] [ ,...n ] )
  18. /// [ ON { partition_scheme_name ( partition_column_name ) | filegroup
  19. /// | "default" } ]
  20. /// [ { TEXTIMAGE_ON { filegroup | "default" } ]
  21. /// [ ; ]
  22. /// </summary>
  23. /// <param name="lstTokens"></param>
  24. /// <param name="i"></param>
  25. public static void ParseCreateTable(Parser parser, List<TokenInfo> lstTokens, ref int i, List<SysObject> lstSysObjects, ref int sysObjectId) {
  26. List<SysObjectColumn> lstColumns = new List<SysObjectColumn>();
  27. int statementStartIndex = i;
  28. // Normal multi part name
  29. TokenInfo server_name;
  30. TokenInfo database_name;
  31. TokenInfo schema_name;
  32. TokenInfo object_name;
  33. int endTableIndex;
  34. if (parser.ParseTableOrViewName(i, out endTableIndex, out server_name, out database_name, out schema_name, out object_name)) {
  35. if (null == object_name) {
  36. return;
  37. }
  38. SysObjectSchema sysObjectSchema;
  39. bool sysObjectExists = Connection.SysObjectExists(server_name, database_name, schema_name, object_name, out sysObjectSchema);
  40. int parenLevelParen = object_name.ParenLevel;
  41. TokenInfo token;
  42. if (object_name.Token.UnqoutedImage.StartsWith("@")) {
  43. object_name.TokenContextType = TokenContextType.TempTable;
  44. // [ AS ]
  45. InStatement.GetIfAnyNextValidToken(lstTokens, ref i, out token, TokenKind.KeywordAs);
  46. // Should be TABLE
  47. if (!InStatement.GetIfAllNextValidToken(lstTokens, ref i, out token, TokenKind.KeywordTable)) {
  48. return;
  49. }
  50. i++;
  51. } else {
  52. i = endTableIndex + 1;
  53. }
  54. token = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  55. if (null == token || token.Kind != TokenKind.LeftParenthesis) {
  56. return;
  57. }
  58. if (-1 == token.MatchingParenToken || i > token.MatchingParenToken) {
  59. return;
  60. }
  61. int parenLevel = token.ParenLevel;
  62. SysObject sysObject = null;
  63. if (!sysObjectExists) {
  64. // Create a temporary table
  65. sysObject = SysObject.CreateTemporarySysObject(sysObjectSchema, object_name.Token.UnqoutedImage, Common.enSqlTypes.Temporary, ref sysObjectId);
  66. }
  67. if (!ParseTableColumns(ref i, lstTokens, parenLevelParen, lstColumns, sysObject)) {
  68. return;
  69. }
  70. if (!sysObjectExists && null != sysObject) {
  71. string tableName = object_name.Token.UnqoutedImage;
  72. foreach (SysObjectColumn column in lstColumns) {
  73. sysObject.AddColumn(column);
  74. }
  75. lstSysObjects.Add(sysObject);
  76. // Create temporary table
  77. TextSpan span = TextSpanHelper.CreateSpanFromTokens(lstTokens[statementStartIndex], lstTokens[i]);
  78. StatementSpans statementSpan = null;
  79. foreach (StatementSpans statementSpans in parser.SegmentUtils.StartTokenIndexesSortByInnerLevel) {
  80. if (statementSpans.StartIndex <= statementStartIndex && statementSpans.EndIndex >= statementStartIndex) {
  81. statementSpan = statementSpans;
  82. break;
  83. }
  84. }
  85. if (null == statementSpan) {
  86. return;
  87. }
  88. TemporaryTable tempTable = new TemporaryTable(tableName, sysObject, span, parenLevel, statementSpan, statementSpan.StartIndex, i);
  89. parser.TemporaryTables.Add(tempTable);
  90. }
  91. }
  92. return;
  93. }
  94. public static bool ParseTableColumns(ref int i, List<TokenInfo> lstTokens, int parenLevelParen, List<SysObjectColumn> lstColumns, SysObject sysObject) {
  95. TokenInfo token = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  96. while (null != token && token.Kind != TokenKind.RightParenthesis) {
  97. string columnName = string.Empty;
  98. ParsedDataType parsedDataType = null;
  99. bool isNullable = true;
  100. bool isIdentity = false;
  101. i++;
  102. token = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  103. if (null != token && token.Kind == TokenKind.Name) {
  104. token.TokenContextType = TokenContextType.TableColumn;
  105. columnName = token.Token.UnqoutedImage;
  106. parsedDataType = ParsedDataType.ParseDataType(lstTokens, ref i);
  107. if (null != parsedDataType) {
  108. // Ok
  109. } else if (token.Kind == TokenKind.KeywordAs) {
  110. // TODO: Handle <computed_column_definition>
  111. } else {
  112. // Unknown token
  113. return false;
  114. }
  115. } else if (null != token && token.Type == TokenType.Keyword) {
  116. // Probably a CONSTRAINT of some kind
  117. // TODO: Parse them?
  118. }
  119. TokenInfo nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  120. int parenLevelColumn = (null != nextToken ? nextToken.ParenLevel : parenLevelParen);
  121. while (null != nextToken) {
  122. if ((nextToken.ParenLevel == parenLevelParen && nextToken.Kind == TokenKind.RightParenthesis) || (nextToken.ParenLevel == parenLevelColumn && nextToken.Kind == TokenKind.Comma)) {
  123. break;
  124. }
  125. if (nextToken.Kind == TokenKind.Name) {
  126. nextToken.TokenContextType = TokenContextType.Known;
  127. } else if (nextToken.Kind == TokenKind.KeywordIdentity) {
  128. isIdentity = true;
  129. isNullable = false;
  130. } else if (nextToken.Kind == TokenKind.KeywordNull) {
  131. TokenInfo prevToken = InStatement.GetPreviousNonCommentToken(lstTokens, i - 1);
  132. isNullable = !(prevToken.Kind == TokenKind.KeywordNot);
  133. }
  134. i++;
  135. nextToken = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  136. }
  137. if (null != nextToken) {
  138. if (nextToken.Kind == TokenKind.RightParenthesis) {
  139. if (null != parsedDataType) {
  140. lstColumns.Add(new SysObjectColumn(sysObject, columnName, parsedDataType, isNullable, isIdentity));
  141. }
  142. // We are done, no more column definitions
  143. break;
  144. }
  145. if (nextToken.Kind != TokenKind.Comma) {
  146. // Expected comma, but got something else
  147. return false;
  148. }
  149. if (null != sysObject && null != parsedDataType) {
  150. lstColumns.Add(new SysObjectColumn(sysObject, columnName, parsedDataType, isNullable, isIdentity));
  151. }
  152. }
  153. }
  154. return true;
  155. }
  156. #endregion
  157. /// <summary>
  158. /// ALTER TABLE [ database_name . [ schema_name ] . | schema_name . ] table_name
  159. ///{
  160. /// ALTER COLUMN column_name
  161. /// {
  162. /// [ type_schema_name. ] type_name [ ( { precision [ , scale ]
  163. /// | max | xml_schema_collection } ) ]
  164. /// [ COLLATE collation_name ]
  165. /// [ NULL | NOT NULL ] [ SPARSE ]
  166. /// | {ADD | DROP }
  167. /// { ROWGUIDCOL | PERSISTED | NOT FOR REPLICATION | SPARSE }
  168. /// }
  169. /// | [ WITH { CHECK | NOCHECK } ]
  170. ///
  171. /// | ADD
  172. /// {
  173. /// <column_definition>
  174. /// | <computed_column_definition>
  175. /// | <table_constraint>
  176. /// | <column_set_definition>
  177. /// } [ ,...n ]
  178. ///
  179. /// | DROP
  180. /// {
  181. /// [ CONSTRAINT ] constraint_name [ WITH ( <drop_clustered_constraint_option> [ ,...n ] ) ]
  182. /// | COLUMN column_name
  183. /// } [ ,...n ]
  184. ///
  185. /// | [ WITH { CHECK | NOCHECK } ] { CHECK | NOCHECK } CONSTRAINT
  186. /// { ALL | constraint_name [ ,...n ] }
  187. ///
  188. /// | { ENABLE | DISABLE } TRIGGER
  189. /// { ALL | trigger_name [ ,...n ] }
  190. ///
  191. /// | { ENABLE | DISABLE } CHANGE_TRACKING
  192. /// [ WITH ( TRACK_COLUMNS_UPDATED = { ON | OFF } ) ]
  193. ///
  194. /// | SWITCH [ PARTITION source_partition_number_expression ]
  195. /// TO target_table
  196. /// [ PARTITION target_partition_number_expression ]
  197. ///
  198. /// | SET ( FILESTREAM_ON = { partition_scheme_name | filegroup |
  199. /// "default" | "NULL" } )
  200. ///
  201. /// | REBUILD
  202. /// [ [PARTITION = ALL]
  203. /// [ WITH ( <rebuild_option> [ ,...n ] ) ]
  204. /// | [ PARTITION = partition_number
  205. /// [ WITH ( <single_partition_rebuild_option> [ ,...n ] )]
  206. /// ]
  207. /// ]
  208. ///
  209. /// | (<table_option>)
  210. ///}
  211. ///[ ; ]
  212. ///
  213. /// <column_set_definition> ::=
  214. /// column_set_name XML COLUMN_SET FOR ALL_SPARSE_COLUMNS
  215. ///
  216. /// <drop_clustered_constraint_option> ::=
  217. /// {
  218. /// MAXDOP = max_degree_of_parallelism
  219. ///
  220. /// | ONLINE = {ON | OFF }
  221. /// | MOVE TO { partition_scheme_name ( column_name ) | filegroup | "default" }
  222. /// }
  223. /// <table_option> ::=
  224. /// {
  225. /// SET ( LOCK_ESCALATION = { AUTO | TABLE | DISABLE } )
  226. /// }
  227. ///
  228. /// <single_partition_rebuild__option> ::=
  229. /// {
  230. /// SORT_IN_TEMPDB = { ON | OFF }
  231. /// | MAXDOP = max_degree_of_parallelism
  232. /// | DATA_COMPRESSION = { NONE | ROW | PAGE} }
  233. /// }
  234. /// </summary>
  235. /// <param name="lstTokens"></param>
  236. /// <param name="i"></param>
  237. /// <param name="sysObjectId"></param>
  238. /// <param name="lstSysObjects"></param>
  239. public static void HandleAlterTable(Parser parser, List<TokenInfo> lstTokens, ref int i, ref int sysObjectId, List<SysObject> lstSysObjects) {
  240. i++;
  241. // ALTER TABLE [ database_name . [ schema_name ] . | schema_name . ] table_name {
  242. TokenInfo server_name;
  243. TokenInfo database_name;
  244. TokenInfo schema_name;
  245. TokenInfo object_name;
  246. int endTableIndex;
  247. if (parser.ParseTableOrViewName(i, out endTableIndex, out server_name, out database_name, out schema_name, out object_name)) {
  248. if (null == object_name) {
  249. return;
  250. }
  251. i++;
  252. TokenInfo token = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  253. if (null == token) {
  254. return;
  255. }
  256. if (token.Kind == TokenKind.KeywordDrop) {
  257. ParseAlterTableDrop(lstTokens, ref i);
  258. }
  259. }
  260. }
  261. /// <summary>
  262. /// | DROP
  263. /// {
  264. /// [ CONSTRAINT ] constraint_name [ WITH ( <drop_clustered_constraint_option> [ ,...n ] ) ]
  265. /// | COLUMN column_name
  266. /// } [ ,...n ]
  267. ///
  268. /// <drop_clustered_constraint_option> ::=
  269. /// {
  270. /// MAXDOP = max_degree_of_parallelism
  271. /// | ONLINE = {ON | OFF }
  272. /// | MOVE TO { partition_scheme_name ( column_name ) | filegroup | "default" }
  273. /// }
  274. /// </summary>
  275. /// <param name="lstTokens"></param>
  276. /// <param name="i"></param>
  277. private static void ParseAlterTableDrop(List<TokenInfo> lstTokens, ref int i) {
  278. TokenInfo token;
  279. do {
  280. i++;
  281. token = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  282. if (null == token) {
  283. return;
  284. }
  285. // COLUMN column_name
  286. if (token.Kind == TokenKind.KeywordColumn) {
  287. token = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  288. if (null == token) {
  289. return;
  290. }
  291. token.TokenContextType = TokenContextType.TableColumn;
  292. } else {
  293. // [ CONSTRAINT ]
  294. if (token.Kind == TokenKind.KeywordConstraint) {
  295. i++;
  296. }
  297. token = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  298. if (null == token) {
  299. return;
  300. }
  301. // constraint_name
  302. token.TokenContextType = TokenContextType.Constraint;
  303. // TODO: handle <drop_clustered_constraint_option>
  304. if (InStatement.GetIfAnyNextValidToken(lstTokens, ref i, out token, TokenKind.KeywordWith, TokenKind.LeftParenthesis)) {
  305. if (-1 == token.MatchingParenToken || i > token.MatchingParenToken) {
  306. return;
  307. }
  308. int startIndex = i;
  309. int endIndex = token.MatchingParenToken;
  310. while (i < endIndex) {
  311. i++;
  312. token = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  313. if (null == token) {
  314. return;
  315. }
  316. if (token.Kind == TokenKind.KeywordMaxDop) {
  317. } else if (token.Kind == TokenKind.KeywordOnline) {
  318. } else if (token.Kind == TokenKind.KeywordMove) {
  319. }
  320. // TokenKind.KeywordOnline
  321. // TokenKind.KeywordOn
  322. // TokenKind.KeywordOff
  323. // TokenKind.KeywordMove
  324. // TokenKind.KeywordTo
  325. }
  326. }
  327. }
  328. i++;
  329. token = InStatement.GetNextNonCommentToken(lstTokens, ref i);
  330. } while (null != token && token.Kind == TokenKind.Comma);
  331. }
  332. }
  333. }