Exemple #1
0
        private void ResolveSuggestedKeywords()
        {
            var aggregateFunctionCallNode = EffectiveTerminal.GetPathFilterAncestor(
                n => !String.Equals(n.Id, NonTerminals.QueryBlock),
                n => String.Equals(n.Id, NonTerminals.AggregateFunctionCall) ||
                (String.Equals(n.Id, NonTerminals.ColumnReference) && n[NonTerminals.ParenthesisEnclosedAggregationFunctionParameters] != null));

            var supportDistinct = EffectiveTerminal.ParentNode.GetPathFilterAncestor(n => !String.Equals(n.Id, NonTerminals.QueryBlock), n => String.Equals(n.Id, NonTerminals.AggregateFunctionCall) || String.Equals(n.Id, NonTerminals.ColumnReference)) == null;

            if (aggregateFunctionCallNode != null)
            {
                var programReference = SemanticModel.GetProgramReference(aggregateFunctionCallNode.FirstTerminalNode);
                supportDistinct = programReference?.Metadata != null && programReference.Metadata.IsAggregate;
            }

            var keywordClauses =
                TerminalCandidates
                .Where(c => AvailableKeywordsToSuggest.Contains(c.Id) || (InSelectList && String.Equals(c.Id, Terminals.Partition)) || (supportDistinct && c.Id.In(Terminals.Distinct, Terminals.Unique)))
                .Select(CreateKeywordClause);

            _keywordsClauses.AddRange(keywordClauses);
        }
Exemple #2
0
        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();
        }