@NotNull
    public SQLQueryCompletionContext obtainCompletionContext(DBRProgressMonitor monitor, @NotNull Position completionRequestPosition) {
        SQLScriptItemAtOffset scriptItem = null;
        do {
            final long requestStamp = System.currentTimeMillis();
            CompletableFuture<Long> expectedParsingSessionFinishStamp;
            synchronized (this.syncRoot) {
                if (scriptItem == null || this.queuedForReparse.size() == 0) {
                    int requestOffset = completionRequestPosition.getOffset();
                    // the offset may be covered by adjacent scriptItem but still queued due to actual scriptItem being temporarily dropped
                    NodesIterator<QueuedRegionInfo> qit = this.queuedForReparse.nodesIteratorAt(requestOffset);
                    QueuedRegionInfo region = qit.getCurrValue() != null ? qit.getCurrValue() : (qit.prev() ? qit.getCurrValue() : null);
                    boolean positionIsQueued = region != null && (qit.getCurrOffset() + region.length >= requestOffset || region.length == Integer.MAX_VALUE);
                    if (!positionIsQueued) {
                        scriptItem = this.context.findScriptItem(requestOffset - 1);
                        if (scriptItem != null) { // TODO consider statements separation which is ignored for now
                            if (scriptItem.item.isDirty()) {
                                // awaiting reparse, so proceed to release lock and wait for the job to finish, then retry
                                if (DEBUG) {
                                    log.debug("awaiting reparse");
                                }
                            } else {
                                if (DEBUG) {
                                    log.debug("obtained model for " + scriptItem.item.getOriginalText());
                                }
                                DBCExecutionContext executionContext = this.editor.getExecutionContext();
                                SQLDialect dialect = this.obtainCurrentSqlDialect(executionContext);
                                return SQLQueryCompletionContext.prepareCompletionContext(
                                    scriptItem,
                                    completionRequestPosition.getOffset(),
                                    executionContext,
                                    dialect
                                );
                            }
                        } else if (this.queuedForReparse.size() <= 0) {
                            // no script items here, so fallback to offquery context
                            if (DEBUG) {
                                log.debug("fallback to offquery context");
                            }
                            return SQLQueryCompletionContext.prepareOffquery(0, completionRequestPosition.getOffset());
                        }
                    }
                }
                expectedParsingSessionFinishStamp = this.lastParsingFinishStamp;
            }

            try {
                // job.join() cannot be used here because completion request is being submitted at before-change event,
                // when the job is not scheduled yet (so join returns immediately)
                // job.schedule() performed only after the series of keypresses at after-change event
                if (getFutureOrCancel(expectedParsingSessionFinishStamp, monitor.getNestedMonitor()) < requestStamp) {
                    return SQLQueryCompletionContext.prepareEmpty(0, completionRequestPosition.getOffset());
                }
            } catch (InterruptedException | ExecutionException e) {
                break;
            }
        } while (!completionRequestPosition.isDeleted());
        return SQLQueryCompletionContext.prepareEmpty(0, completionRequestPosition.getOffset());
    }
Prepare completion context for the specified position in the text
plugins/org.jkiss.dbeaver.ui.editors.sql/src/org/jkiss/dbeaver/ui/editors/sql/semantics/SQLBackgroundParsingJob.java