@Override
    public ICompletionProposal[] computeCompletionProposals(
        ITextViewer viewer,
        int documentOffset
    ) {
        IDocument document = editor.getDocument();
        if (document == null) {
            return new ICompletionProposal[0];
        }
        // This method blocks UI thread to prepare proposals, but in our implementation actual analysis performed in background jobs
        // asynchronously with the editor's state modifications due to waitJobCompletion(..) usage, which forcibly pumps UI event loop.
        // Accurate proposals preparation requires cursor position of where the user stops editing the text,
        // so we are synchronously creating a position object to track the location of interest, instead of the documentOffset
        // (which is where the proposals computation was initially triggered, not where it is really expected to get them).
        Position completionRequestPosition = new Position(documentOffset);
        try {
            IRegion line = document.getLineInformationOfOffset(documentOffset);
            if (documentOffset <= line.getLength() + line.getOffset() && line.getLength() > 0) { // we are in the nonempty line
                String typeAtLine = TextUtilities.getContentType(document, SQLParserPartitions.SQL_PARTITIONING, documentOffset - 1, true);
                // and previous position belongs to the single-line comment
                if (SQLParserPartitions.CONTENT_TYPE_SQL_COMMENT.equals(typeAtLine)) {
                    return new ICompletionProposal[0];
                }
            }
        } catch (BadLocationException e) {
            log.debug(e);
            return new ICompletionProposal[0];
        }

        final SQLCompletionRequest request = new SQLCompletionRequest(
            editor.getCompletionContext(),
            document,
            documentOffset,
            editor.extractQueryAtPos(documentOffset),
            simpleMode
        );
        SQLWordPartDetector wordDetector = request.getWordDetector();


        String contentType;
        try {
            // Check that word start position is in default partition (#5994)
            contentType = TextUtilities.getContentType(document, SQLParserPartitions.SQL_PARTITIONING, documentOffset, true);
        } catch (BadLocationException e) {
            log.debug(e);
            return new ICompletionProposal[0];
        }

        if (contentType == null) {
            return new ICompletionProposal[0];
        }

        request.setContentType(contentType);

        List<?> proposals;
        try {
            switch (contentType) {
                case IDocument.DEFAULT_CONTENT_TYPE:
                case SQLParserPartitions.CONTENT_TYPE_SQL_STRING:
                case SQLParserPartitions.CONTENT_TYPE_SQL_QUOTED:
                    if (lookupTemplates) {
                        return makeTemplateProposals(viewer, request);
                    }

                    try {
                        String commandPrefix = editor.getSyntaxManager().getControlCommandPrefix();
                        if (commandPrefix != null && wordDetector.getStartOffset() >= commandPrefix.length() &&
                            viewer.getDocument().get(wordDetector.getStartOffset() - commandPrefix.length(), commandPrefix.length()).equals(commandPrefix)
                        ) {
                            return makeCommandProposals(request, request.getWordPart());
                        }
                        document.addPosition(completionRequestPosition);
                    } catch (BadLocationException e) {
                        log.debug(e);
                    }

                    DBPDataSource dataSource = editor.getDataSource();

                    DBPPreferenceStore store = this.editor.getActivePreferenceStore();
                    SQLAutocompletionMode mode = SQLAutocompletionMode.fromPreferences(store);
                    boolean useNewCompletionEngine = mode.useNewAnalyzer
                        && store.getBoolean(SQLPreferenceConstants.ADVANCED_HIGHLIGHTING_ENABLE)
                        && store.getBoolean(SQLPreferenceConstants.READ_METADATA_FOR_SEMANTIC_ANALYSIS)
                        && dataSource != null && dataSource.getSQLDialect() instanceof BasicSQLDialect;

                    // UIUtils.waitJobCompletion(..) uses job.isFinished() which is not dropped on reschedule,
                    // so we should be able to recreate the whole job object including all its non-reusable dependencies.
                    List<Supplier<ProposalsComputationJobHolder>> completionJobSuppliers = new ArrayList<>();

                    if (useNewCompletionEngine) {
                        // new analyzer is reusable
                        SQLEditorQueryCompletionAnalyzer newAnalyzer = new SQLEditorQueryCompletionAnalyzer(
                            monitor -> this.editor.obtainCompletionContext(monitor, completionRequestPosition),
                            request,
                            () -> completionRequestPosition.getOffset()
                        );
                        completionJobSuppliers.add(() -> new ProposalsComputationJobHolder(new NewProposalSearchJob(newAnalyzer)) {
                            @Override
                            public List<?> getProposals() {
                                return newAnalyzer.getResult();
                            }

                            @Override
                            public Integer getProposalsOriginOffset() {
                                return newAnalyzer.getActualContextOffset();
                            }
                        });
                    }

                    if (request.getWordPart() != null && mode.useOldAnalyzer || !useNewCompletionEngine) {
                        if (dataSource != null) {
                            completionJobSuppliers.add(() -> {
                                // old analyzer is not reusable, but it doesn't matter because see the next comment below
                                SQLCompletionAnalyzer analyzer = new SQLCompletionAnalyzer(request);
                                return new ProposalsComputationJobHolder(new ProposalSearchJob(analyzer)) {
                                    @Override
                                    public List<?> getProposals() {
                                        return analyzer.getProposals();
                                    }

                                    @Override
                                    public Integer getProposalsOriginOffset() {
                                        // Actual origin for old analyzer's proposals is always request.getDocumentOffset(),
                                        // which may be out of sync with cursor position at the time of analysis being accomplished.
                                        // This is wrong, but old implementation ignores this fact,
                                        // so for now we explicitly pretend that it is always in sync with current cursor position.
                                        // Possible solution: support request object recreation when job restart needed.
                                        return null;
                                    }
                                };
                            });
                        }
                    }

                    proposals = this.computeProposalsWithJobs(request, completionRequestPosition, completionJobSuppliers);
                    break;
                default:
                    proposals = Collections.emptyList();
                    break;
            }

            int actualCompletionOffset = completionRequestPosition.getOffset();
            LinkedHashSet<ICompletionProposal> result = new LinkedHashSet<>(proposals.size());
            if (actualCompletionOffset != request.getDocumentOffset()) {
                for (Object cp : proposals) {
                    if (cp instanceof ICompletionProposal proposal && (
                        (cp instanceof ICompletionProposalExtension2 exp && exp.validate(request.getDocument(), completionRequestPosition.getOffset(), null))
                        || !(cp instanceof ICompletionProposalExtension2)
                    )) {
                        result.add(proposal);
                    }
                }
            } else {
                for (Object cp : proposals) {
                    if (cp instanceof ICompletionProposal proposal) {
                        result.add(proposal);
                    }
                }
            }
            this.contentAssistant.setLastCompletionOffset(actualCompletionOffset);
            return ArrayUtils.toArray(ICompletionProposal.class, result);
        } finally {
            document.removePosition(completionRequestPosition);
        }
    }
The SQL content assist processor. This content assist processor proposes text
completions and computes context information for a SQL content type.
plugins/org.jkiss.dbeaver.ui.editors.sql/src/org/jkiss/dbeaver/ui/editors/sql/syntax/SQLCompletionProcessor.java