private string GetIdentifierCandidate() { return(TerminalCandidates.Contains(Terminals.Identifier) ? Terminals.Identifier : TerminalCandidates.Contains(Terminals.ObjectIdentifier) ? Terminals.ObjectIdentifier : TerminalCandidates.Contains(Terminals.SchemaIdentifier) ? Terminals.SchemaIdentifier : null); }
public OracleCodeCompletionType(SqlDocumentRepository documentRepository, string statementText, int cursorPosition) { CursorPosition = cursorPosition; Statement = (OracleStatement)(documentRepository.Statements.GetStatementAtPosition(cursorPosition) ?? documentRepository.Statements.LastOrDefault()); if (Statement == null) { return; } if (Statement.TerminatorNode != null && Statement.TerminatorNode.SourcePosition.IndexStart < cursorPosition) { return; } var nearestTerminal = Statement.GetNearestTerminalToPosition(cursorPosition); if (nearestTerminal == null) { return; } var precedingTerminal = nearestTerminal.PrecedingTerminal; InComment = Statement.Comments.Any(c => c.SourcePosition.ContainsIndex(cursorPosition)); if (!documentRepository.ValidationModels.TryGetValue(Statement, out IValidationModel validationModel)) { return; } SemanticModel = (OracleStatementSemanticModel)validationModel.SemanticModel; var requiredOffsetAfterToken = nearestTerminal.Id.IsZeroOffsetTerminalId() ? 0 : 1; var isCursorAfterToken = nearestTerminal.SourcePosition.IndexEnd + requiredOffsetAfterToken < cursorPosition; var atAdHocTemporaryTerminal = false; if (isCursorAfterToken) { var unparsedTextBetweenTokenAndCursor = statementText.Substring(nearestTerminal.SourcePosition.IndexEnd + 1, cursorPosition - nearestTerminal.SourcePosition.IndexEnd - 1); var unparsedEndTrimmedTextBetweenTokenAndCursor = unparsedTextBetweenTokenAndCursor.TrimEnd(); OracleToken[] extraUnparsedTokens; using (var tokenReader = OracleTokenReader.Create(unparsedEndTrimmedTextBetweenTokenAndCursor)) { extraUnparsedTokens = tokenReader.GetTokens(true).ToArray(); } if (extraUnparsedTokens.Length > 0) { TerminalCandidates = OracleSqlParser.Instance.GetTerminalCandidates(nearestTerminal); if (TerminalCandidates.Count == 0 || extraUnparsedTokens.Length > 1 || unparsedEndTrimmedTextBetweenTokenAndCursor.Length < unparsedTextBetweenTokenAndCursor.Length) { InUnparsedData = true; return; } } TerminalValueUnderCursor = extraUnparsedTokens.FirstOrDefault().Value; if (TerminalValueUnderCursor != null) { TerminalValuePartUntilCaret = TerminalValueUnderCursor; precedingTerminal = nearestTerminal; nearestTerminal = CurrentTerminal = new StatementGrammarNode(NodeType.Terminal, Statement, new OracleToken(TerminalValueUnderCursor, cursorPosition - TerminalValuePartUntilCaret.Length)); precedingTerminal.ParentNode.Clone().AddChildNodes(nearestTerminal); atAdHocTemporaryTerminal = true; nearestTerminal.Id = nearestTerminal.Token.Value[0] == '"' ? Terminals.Identifier : GetIdentifierCandidate(); if (nearestTerminal.Id != null) { ReferenceIdentifier = BuildReferenceIdentifier(nearestTerminal.ParentNode.GetDescendants(Terminals.SchemaIdentifier, Terminals.ObjectIdentifier, Terminals.Identifier).ToArray()); } if (!String.IsNullOrEmpty(TerminalValueUnderCursor) && nearestTerminal.SourcePosition.ContainsIndex(cursorPosition)) { isCursorAfterToken = false; } TerminalValueUnderCursor = TerminalValueUnderCursor.Trim('"'); } } else { CurrentTerminal = nearestTerminal; ResolveCurrentTerminalValue(nearestTerminal); } var effectiveTerminal = Statement.GetNearestTerminalToPosition(cursorPosition, n => !n.Id.In(Terminals.LeftParenthesis, Terminals.RightParenthesis, Terminals.Comma, Terminals.Semicolon)) ?? nearestTerminal; CurrentQueryBlock = SemanticModel.GetQueryBlock(effectiveTerminal); AnalyzeObjectReferencePrefixes(effectiveTerminal); var isCursorAfterEffectiveTerminal = cursorPosition > effectiveTerminal.SourcePosition.IndexEnd + 1; if (precedingTerminal == null && nearestTerminal != Statement.RootNode.FirstTerminalNode) { precedingTerminal = nearestTerminal; } var isCursorTouchingTwoTerminals = nearestTerminal.SourcePosition.IndexStart == cursorPosition && precedingTerminal != null && precedingTerminal.SourcePosition.IndexEnd + 1 == cursorPosition; if (isCursorTouchingTwoTerminals && !String.Equals(nearestTerminal.Id, Terminals.Identifier)) { IsCursorTouchingIdentifier = String.Equals(precedingTerminal.Id, Terminals.Identifier); EffectiveTerminal = precedingTerminal; } else { EffectiveTerminal = nearestTerminal; } var isColon = String.Equals(EffectiveTerminal.Id, Terminals.Colon); if (!String.Equals(Statement.RootNode.Id, NonTerminals.CreatePlSqlStatement)) { BindVariable = isColon && (String.Equals(EffectiveTerminal.ParentNode.Id, NonTerminals.AssignmentTriggerReferenceTarget) || String.Equals(EffectiveTerminal.ParentNode.Id, NonTerminals.BindVariableExpression)); BindVariable |= String.Equals(EffectiveTerminal.Id, Terminals.BindVariableIdentifier); } var terminalCandidateSourceToken = isCursorAfterToken || isColon ? nearestTerminal : precedingTerminal; if (nearestTerminal.Id.In(Terminals.RightParenthesis, Terminals.Comma, Terminals.Dot, Terminals.Semicolon) && isCursorTouchingTwoTerminals && precedingTerminal.Id.IsIdentifier()) { terminalCandidateSourceToken = precedingTerminal.PrecedingTerminal; ResolveCurrentTerminalValue(precedingTerminal); } if (TerminalCandidates == null) { TerminalCandidates = OracleSqlParser.Instance.GetTerminalCandidates(terminalCandidateSourceToken); } InSelectList = (atAdHocTemporaryTerminal ? precedingTerminal : EffectiveTerminal).GetPathFilterAncestor(n => !String.Equals(n.Id, NonTerminals.QueryBlock), NonTerminals.SelectList) != null; var invalidGrammarFilteredNearestTerminal = Statement.GetNearestTerminalToPosition(cursorPosition, n => !String.Equals(n.Id, Terminals.ObjectAlias)); var isWithinExplicitPartitionClause = invalidGrammarFilteredNearestTerminal != null && String.Equals(invalidGrammarFilteredNearestTerminal.ParentNode.Id, NonTerminals.PartitionNameOrKeySet) && (invalidGrammarFilteredNearestTerminal != nearestTerminal || TerminalCandidates.Contains(Terminals.ObjectIdentifier)); ExplicitPartition = isWithinExplicitPartitionClause && String.Equals(invalidGrammarFilteredNearestTerminal.ParentNode.ParentNode.FirstTerminalNode.Id, Terminals.Partition); ExplicitSubPartition = isWithinExplicitPartitionClause && String.Equals(invalidGrammarFilteredNearestTerminal.ParentNode.ParentNode.FirstTerminalNode.Id, Terminals.Subpartition); if (isWithinExplicitPartitionClause) { if (String.Equals(EffectiveTerminal.Id, Terminals.ObjectIdentifier)) { ReferenceIdentifier = BuildReferenceIdentifier(new[] { EffectiveTerminal }); } if (invalidGrammarFilteredNearestTerminal != nearestTerminal) { EffectiveTerminal = invalidGrammarFilteredNearestTerminal; TerminalValuePartUntilCaret = null; } } if (!isWithinExplicitPartitionClause) { ResolveSuggestedKeywords(); } var isCursorBetweenTwoTerminalsWithPrecedingIdentifierWithoutPrefix = IsCursorTouchingIdentifier && !ReferenceIdentifier.HasObjectIdentifier; Schema = TerminalCandidates.Contains(Terminals.SchemaIdentifier) || (String.Equals(EffectiveTerminal.Id, Terminals.SchemaIdentifier) && String.Equals(nearestTerminal.Id, Terminals.Dot)); var isCurrentClauseSupported = EffectiveTerminal.IsWithinSelectClauseOrExpression() || EffectiveTerminal.ParentNode.Id.In(NonTerminals.WhereClause, NonTerminals.GroupByClause, NonTerminals.HavingClause, NonTerminals.OrderByClause) || EffectiveTerminal.GetPathFilterAncestor(n => !String.Equals(n.Id, NonTerminals.NestedQuery), NonTerminals.WhereClause) != null; var isCandidateIdentifier = TerminalCandidates.Contains(Terminals.Identifier); if (isCurrentClauseSupported) { SchemaProgram = Column = isCandidateIdentifier || isCursorBetweenTwoTerminalsWithPrecedingIdentifierWithoutPrefix; var functionParameterOptionalExpression = EffectiveTerminal.GetPathFilterAncestor(n => !String.Equals(n.Id, NonTerminals.OptionalParameterExpressionList), NonTerminals.OptionalParameterExpression); if (functionParameterOptionalExpression != null) { var functionParameterExpression = functionParameterOptionalExpression[NonTerminals.Expression]; SpecialFunctionParameter = functionParameterExpression != null && functionParameterExpression.TerminalCount == 1 && (functionParameterExpression.FirstTerminalNode.Id.IsLiteral() || String.Equals(functionParameterExpression.FirstTerminalNode.Id, Terminals.Identifier)); } } DatabaseLink = TerminalCandidates.Contains(Terminals.DatabaseLinkIdentifier); JoinType = (!isCursorTouchingTwoTerminals || nearestTerminal.Id.In(Terminals.Comma, Terminals.RightParenthesis)) && !isWithinExplicitPartitionClause && TerminalCandidates.Contains(Terminals.Join); DataType = TerminalCandidates.Contains(Terminals.DataTypeIdentifier); InQueryBlockFromClause = effectiveTerminal.GetPathFilterAncestor(n => !String.Equals(n.Id, NonTerminals.QueryBlock), NonTerminals.FromClause) != null || (effectiveTerminal.Id == Terminals.From && effectiveTerminal.ParentNode.Id == NonTerminals.QueryBlock); var isWithinJoinCondition = effectiveTerminal.GetPathFilterAncestor(n => !String.Equals(n.Id, NonTerminals.JoinClause) && !String.Equals(n.Id, NonTerminals.NestedQuery), NonTerminals.JoinColumnsOrCondition) != null; var isAfterUpdateOrDeleteTerminal = (nearestTerminal.Id.In(Terminals.Update, Terminals.Delete) || (String.Equals(nearestTerminal.Id, Terminals.From) && nearestTerminal.PrecedingTerminal != null && String.Equals(nearestTerminal.PrecedingTerminal.Id, Terminals.Delete))) && isCursorAfterToken; var isWithinQueryBlock = nearestTerminal.GetAncestor(NonTerminals.QueryBlock) != null; var isWithinMainObjectReference = nearestTerminal.GetAncestor(NonTerminals.TableReference) != null && !isWithinQueryBlock; var isInInsertIntoTableReference = nearestTerminal.GetPathFilterAncestor(NodeFilters.BreakAtNestedQueryBlock, NonTerminals.DmlTableExpressionClause) != null || (nearestTerminal.GetPathFilterAncestor(NodeFilters.BreakAtNestedQueryBlock, NonTerminals.InsertIntoClause) != null && nearestTerminal.Id == Terminals.Into && isCursorAfterToken); SchemaDataObject = (InQueryBlockFromClause || isAfterUpdateOrDeleteTerminal || isWithinMainObjectReference || isInInsertIntoTableReference) && !isWithinJoinCondition && !isWithinExplicitPartitionClause && TerminalCandidates.Contains(Terminals.ObjectIdentifier); var isWithinJoinClause = effectiveTerminal.GetPathFilterAncestor(n => !String.Equals(n.Id, NonTerminals.FromClause), NonTerminals.JoinClause) != null; JoinCondition = isWithinJoinClause && isCursorAfterEffectiveTerminal && (TerminalCandidates.Contains(Terminals.On) || String.Equals(nearestTerminal.Id, Terminals.On)); var isWithinSelectList = (String.Equals(nearestTerminal.Id, Terminals.Select) && isCursorAfterToken) || nearestTerminal.GetPathFilterAncestor(n => !String.Equals(n.Id, NonTerminals.QueryBlock), NonTerminals.SelectList) != null; AllColumns = isWithinSelectList && TerminalCandidates.Contains(Terminals.Asterisk); SchemaDataObjectReference = !InQueryBlockFromClause && (TerminalCandidates.Contains(Terminals.ObjectIdentifier) || isCursorBetweenTwoTerminalsWithPrecedingIdentifierWithoutPrefix); PackageFunction = !String.IsNullOrEmpty(ReferenceIdentifier.ObjectIdentifierOriginalValue) && (isCandidateIdentifier || isCursorTouchingTwoTerminals); var inMainQueryBlockOrMainObjectReference = CurrentQueryBlock == SemanticModel.MainQueryBlock || (CurrentQueryBlock == null && SemanticModel.MainObjectReferenceContainer.MainObjectReference != null); Sequence = inMainQueryBlockOrMainObjectReference && (nearestTerminal.IsWithinSelectClause() || !nearestTerminal.IsWithinExpression() || nearestTerminal.GetPathFilterAncestor(n => n.Id != NonTerminals.QueryBlock, NonTerminals.InsertValuesClause) != null); var isWithinUpdateSetNonTerminal = String.Equals(nearestTerminal.ParentNode.Id, NonTerminals.PrefixedIdentifier) || nearestTerminal.GetPathFilterAncestor(NodeFilters.BreakAtNestedQueryBlock, NonTerminals.SetColumnListEqualsNestedQuery) != null; var isAfterSetTerminal = isCursorAfterToken && String.Equals(nearestTerminal.Id, Terminals.Set); var isAfterCommaInChainedUpdateSetClause = isCursorAfterToken && String.Equals(nearestTerminal.Id, Terminals.Comma) && String.Equals(nearestTerminal.ParentNode.Id, NonTerminals.UpdateSetColumnOrColumnListChainedList); UpdateSetColumn = isCandidateIdentifier && (isWithinUpdateSetNonTerminal || isAfterSetTerminal || isAfterCommaInChainedUpdateSetClause); var columnList = nearestTerminal.GetAncestor(NonTerminals.ParenthesisEnclosedPrefixedIdentifierList); InsertIntoColumn = isCandidateIdentifier && String.Equals(columnList?.ParentNode?.Id, NonTerminals.InsertIntoClause); ColumnAlias = Column && nearestTerminal.IsWithinOrderByClause(); }