private void makeStructureProposals(
     final DBRProgressMonitor monitor,
     final List<SQLCompletionProposal> proposals,
     final String wordPart,
     final QueryType queryType) {
   DBPDataSource dataSource = editor.getDataSource();
   if (dataSource == null) {
     return;
   }
   if (queryType != null) {
     // Try to determine which object is queried (if wordPart is not empty)
     // or get list of root database objects
     if (wordPart.length() == 0) {
       // Get root objects
       DBSObject rootObject = null;
       if (queryType == QueryType.COLUMN && dataSource instanceof DBSObjectContainer) {
         // Try to detect current table
         rootObject = getTableFromAlias(monitor, (DBSObjectContainer) dataSource, null);
       } else if (dataSource instanceof DBSObjectContainer) {
         // Try to get from active object
         DBSObject selectedObject = getSelectedObject(dataSource);
         if (selectedObject != null) {
           makeProposalsFromChildren(monitor, selectedObject, null, proposals);
         }
         rootObject = (DBSObjectContainer) dataSource;
       }
       if (rootObject != null) {
         makeProposalsFromChildren(monitor, rootObject, null, proposals);
       }
     } else {
       DBSObject rootObject = null;
       if (queryType == QueryType.COLUMN && dataSource instanceof DBSObjectContainer) {
         // Part of column name
         // Try to get from active object
         DBSObjectContainer sc = (DBSObjectContainer) dataSource;
         DBSObject selectedObject = getSelectedObject(dataSource);
         if (selectedObject instanceof DBSObjectContainer) {
           sc = (DBSObjectContainer) selectedObject;
         }
         int divPos = wordPart.indexOf(editor.getSyntaxManager().getStructSeparator());
         String tableAlias = divPos == -1 ? null : wordPart.substring(0, divPos);
         rootObject = getTableFromAlias(monitor, sc, tableAlias);
       }
       if (rootObject != null) {
         makeProposalsFromChildren(monitor, rootObject, wordPart, proposals);
       } else {
         // Get root object or objects from active database (if any)
         makeStructureProposals(monitor, dataSource, proposals);
       }
     }
   } else {
     // Get list of sub-objects (filtered by wordPart)
     makeStructureProposals(monitor, dataSource, proposals);
   }
 }
  /*
   * Turns the vector into an Array of ICompletionProposal objects
   */
  protected SQLCompletionProposal createCompletionProposal(
      String replaceString,
      String displayString,
      String description,
      @Nullable DBPImage image,
      boolean isObject,
      @Nullable DBPNamedObject object) {
    DBPPreferenceStore store = getPreferences();
    DBPDataSource dataSource = editor.getDataSource();
    if (dataSource != null) {
      if (isObject) {
        // Escape replace string if required
        replaceString = DBUtils.getQuotedIdentifier(dataSource, replaceString);
      }
    }

    // If we have quoted string then ignore pref settings
    boolean quotedString = wordDetector.isQuoted(replaceString);
    final int proposalCase =
        quotedString
            ? SQLPreferenceConstants.PROPOSAL_CASE_DEFAULT
            : store.getInt(SQLPreferenceConstants.PROPOSAL_INSERT_CASE);
    switch (proposalCase) {
      case SQLPreferenceConstants.PROPOSAL_CASE_UPPER:
        replaceString = replaceString.toUpperCase();
        break;
      case SQLPreferenceConstants.PROPOSAL_CASE_LOWER:
        replaceString = replaceString.toLowerCase();
        break;
      default:
        DBPIdentifierCase convertCase =
            quotedString && dataSource instanceof SQLDataSource
                ? ((SQLDataSource) dataSource).getSQLDialect().storesQuotedCase()
                : DBPIdentifierCase.MIXED;
        replaceString = convertCase.transform(replaceString);
        break;
    }

    Image img = image == null ? null : DBeaverIcons.getImage(image);
    return new SQLCompletionProposal(
        editor.getSyntaxManager(),
        displayString,
        replaceString, // replacementString
        wordDetector, // wordDetector
        replaceString.length(), // cursorPosition the position of the cursor following the insert
        // relative to replacementOffset
        img, // image to display
        new ContextInformation(
            img,
            displayString,
            displayString), // the context information associated with this proposal
        description,
        object);
  }
  private SQLCompletionProposal makeProposalsFromObject(
      DBPNamedObject object, @Nullable DBPImage objectIcon) {
    String objectName = DBUtils.getObjectFullName(object);

    StringBuilder info = new StringBuilder();
    PropertyCollector collector = new PropertyCollector(object, false);
    collector.collectProperties();
    for (DBPPropertyDescriptor descriptor : collector.getPropertyDescriptors2()) {
      Object propValue = collector.getPropertyValue(descriptor.getId());
      if (propValue == null) {
        continue;
      }
      String propString = propValue.toString();
      info.append("<b>").append(descriptor.getDisplayName()).append(":  </b>");
      info.append(propString);
      info.append("<br>");
    }

    boolean isSingleObject = true;
    String replaceString = null;
    DBPDataSource dataSource = editor.getDataSource();
    if (dataSource != null) {
      // If we replace short name with referenced object
      // and current active schema (catalog) is not this object's container then
      // replace with full qualified name
      if (!getPreferences().getBoolean(SQLPreferenceConstants.PROPOSAL_SHORT_NAME)
          && object instanceof DBSObjectReference) {
        if (wordDetector.getFullWord().indexOf(editor.getSyntaxManager().getStructSeparator())
            == -1) {
          DBSObjectReference structObject = (DBSObjectReference) object;
          if (structObject.getContainer() != null) {
            DBSObject selectedObject = getSelectedObject(dataSource);
            if (selectedObject != structObject.getContainer()) {
              replaceString =
                  DBUtils.getFullQualifiedName(dataSource, structObject.getContainer(), object);
              isSingleObject = false;
            }
          }
        }
      }
      if (replaceString == null) {
        replaceString = DBUtils.getQuotedIdentifier(dataSource, object.getName());
      }
    } else {
      replaceString = DBUtils.getObjectShortName(object);
    }
    return createCompletionProposal(
        replaceString, objectName, info.toString(), objectIcon, isSingleObject, object);
  }
 private void makeProposalsFromChildren(
     DBRProgressMonitor monitor,
     DBSObject parent,
     @Nullable String startPart,
     List<SQLCompletionProposal> proposals) {
   if (startPart != null) {
     startPart = wordDetector.removeQuotes(startPart).toUpperCase();
     int divPos = startPart.lastIndexOf(editor.getSyntaxManager().getStructSeparator());
     if (divPos != -1) {
       startPart = startPart.substring(divPos + 1);
     }
   }
   try {
     Collection<? extends DBSObject> children = null;
     if (parent instanceof DBSObjectContainer) {
       children = ((DBSObjectContainer) parent).getChildren(monitor);
     } else if (parent instanceof DBSEntity) {
       children = ((DBSEntity) parent).getAttributes(monitor);
     }
     if (children != null && !children.isEmpty()) {
       for (DBSObject child : children) {
         if (startPart != null && !child.getName().toUpperCase().startsWith(startPart)) {
           continue;
         }
         proposals.add(makeProposalsFromObject(monitor, child));
       }
     }
   } catch (DBException e) {
     log.error(e);
   }
 }
 private DBPPreferenceStore getPreferences() {
   DBPPreferenceStore store = null;
   DBPDataSource dataSource = editor.getDataSource();
   if (dataSource != null) {
     store = dataSource.getContainer().getPreferenceStore();
   }
   if (store == null) {
     store = DBeaverCore.getGlobalPreferenceStore();
   }
   return store;
 }
  /**
   * This method is incomplete in that it does not implement logic to produce some context help
   * relevant to SQL. It just hard codes two strings to demonstrate the action
   *
   * @see
   *     org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeContextInformation(ITextViewer,
   *     int)
   */
  @Nullable
  @Override
  public IContextInformation[] computeContextInformation(ITextViewer viewer, int documentOffset) {
    SQLQuery statementInfo = editor.extractQueryAtPos(documentOffset);
    if (statementInfo == null || CommonUtils.isEmpty(statementInfo.getQuery())) {
      return null;
    }

    IContextInformation[] result = new IContextInformation[1];
    result[0] = new ContextInformation(statementInfo.getQuery(), statementInfo.getQuery());
    return result;
  }
 @NotNull
 private ICompletionProposal[] makeTemplateProposals(
     ITextViewer viewer, int documentOffset, String wordPart) {
   wordPart = wordPart.toLowerCase();
   final List<SQLTemplateCompletionProposal> templateProposals = new ArrayList<>();
   // Templates
   for (Template template : editor.getTemplatesPage().getTemplateStore().getTemplates()) {
     if (template.getName().toLowerCase().startsWith(wordPart)) {
       templateProposals.add(
           new SQLTemplateCompletionProposal(
               template,
               new SQLContext(
                   SQLTemplatesRegistry.getInstance()
                       .getTemplateContextRegistry()
                       .getContextType(template.getContextTypeId()),
                   viewer.getDocument(),
                   new Position(wordDetector.getStartOffset(), wordDetector.getLength()),
                   editor),
               new Region(documentOffset, 0),
               null));
     }
   }
   return templateProposals.toArray(new ICompletionProposal[templateProposals.size()]);
 }
  @Nullable
  private DBSObject getTableFromAlias(
      DBRProgressMonitor monitor, DBSObjectContainer sc, @Nullable String token) {
    final DBPDataSource dataSource = editor.getDataSource();
    if (!(dataSource instanceof SQLDataSource)) {
      return null;
    }
    if (activeQuery == null) {
      activeQuery = editor.extractQueryAtPos(documentOffset).getQuery() + " ";
    }

    final List<String> nameList = new ArrayList<>();
    if (token == null) {
      token = "";
    }

    {
      Matcher matcher;
      Pattern aliasPattern;
      SQLDialect sqlDialect = ((SQLDataSource) dataSource).getSQLDialect();
      String quoteString = sqlDialect.getIdentifierQuoteString();
      String quote =
          quoteString == null
              ? SQLConstants.STR_QUOTE_DOUBLE
              : SQLConstants.STR_QUOTE_DOUBLE.equals(quoteString)
                  ? quoteString
                  : Pattern.quote(quoteString);
      String catalogSeparator = sqlDialect.getCatalogSeparator();
      while (token.endsWith(catalogSeparator)) token = token.substring(0, token.length() - 1);

      String tableNamePattern =
          "((?:"
              + quote
              + "(?:[.[^"
              + quote
              + "]]+)"
              + quote
              + ")|(?:[\\w"
              + Pattern.quote(catalogSeparator)
              + "]+))";
      String structNamePattern;
      if (CommonUtils.isEmpty(token)) {
        structNamePattern = "(?:from|update|join|into)\\s*" + tableNamePattern;
      } else {
        structNamePattern =
            tableNamePattern
                + "(?:\\s*\\.\\s*"
                + tableNamePattern
                + ")?"
                + "\\s+(?:(?:AS)\\s)?"
                + token
                + "[\\s,]+";
      }

      try {
        aliasPattern = Pattern.compile(structNamePattern, Pattern.CASE_INSENSITIVE);
      } catch (PatternSyntaxException e) {
        // Bad pattern - seems to be a bad token
        return null;
      }
      matcher = aliasPattern.matcher(activeQuery);
      if (!matcher.find()) {
        return null;
      }

      int groupCount = matcher.groupCount();
      for (int i = 1; i <= groupCount; i++) {
        String group = matcher.group(i);
        if (!CommonUtils.isEmpty(group)) {
          String[] allNames = group.split(Pattern.quote(catalogSeparator));
          for (String name : allNames) {
            if (quoteString != null && name.startsWith(quoteString) && name.endsWith(quoteString)) {
              name = name.substring(1, name.length() - 1);
            }
            nameList.add(name);
          }
        }
      }
    }

    if (nameList.isEmpty()) {
      return null;
    }

    for (int i = 0; i < nameList.size(); i++) {
      nameList.set(
          i, DBObjectNameCaseTransformer.transformName(sc.getDataSource(), nameList.get(i)));
    }

    try {
      DBSObject childObject = null;
      while (childObject == null) {
        childObject = DBUtils.findNestedObject(monitor, sc, nameList);
        if (childObject == null) {
          DBSObjectContainer parentSc = DBUtils.getParentAdapter(DBSObjectContainer.class, sc);
          if (parentSc == null) {
            break;
          }
          sc = parentSc;
        }
      }
      if (childObject == null && nameList.size() <= 1) {
        // No such object found - may be it's start of table name
        DBSStructureAssistant structureAssistant =
            DBUtils.getAdapter(DBSStructureAssistant.class, sc);
        if (structureAssistant != null) {
          String objectNameMask = nameList.get(0);
          Collection<DBSObjectReference> tables =
              structureAssistant.findObjectsByMask(
                  monitor,
                  sc,
                  structureAssistant.getAutoCompleteObjectTypes(),
                  wordDetector.removeQuotes(objectNameMask),
                  wordDetector.isQuoted(objectNameMask),
                  2);
          if (!tables.isEmpty()) {
            return tables.iterator().next().resolveObject(monitor);
          }
        }
        return null;
      } else {
        return childObject;
      }
    } catch (DBException e) {
      log.error(e);
      return null;
    }
  }
  /**
   * This method returns a list of completion proposals as ICompletionProposal objects. The
   * proposals are based on the word at the offset in the document where the cursor is positioned.
   * In this implementation, we find the word at the document offset and compare it to our list of
   * SQL reserved words. The list is a subset, of those words that match what the user has entered.
   * For example, the text or proposes the SQL keywords OR and ORDER. The list is returned as an
   * array of completion proposals.
   *
   * @see
   *     org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeCompletionProposals(ITextViewer,
   *     int)
   */
  @Override
  public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int documentOffset) {
    this.documentOffset = documentOffset;
    this.activeQuery = null;

    this.wordDetector =
        new SQLWordPartDetector(viewer.getDocument(), editor.getSyntaxManager(), documentOffset);
    final String wordPart = wordDetector.getWordPart();

    if (lookupTemplates) {
      return makeTemplateProposals(viewer, documentOffset, wordPart);
    }

    final List<SQLCompletionProposal> proposals = new ArrayList<>();
    QueryType queryType = null;
    {
      final String prevKeyWord = wordDetector.getPrevKeyWord();
      if (!CommonUtils.isEmpty(prevKeyWord)) {
        if (editor.getSyntaxManager().getDialect().isEntityQueryWord(prevKeyWord)) {
          queryType = QueryType.TABLE;
        } else if (editor.getSyntaxManager().getDialect().isAttributeQueryWord(prevKeyWord)) {
          queryType = QueryType.COLUMN;
        }
      }
    }
    if (queryType != null) {
      if (editor.getDataSource() != null) {
        try {
          final QueryType qt = queryType;
          DBeaverUI.runInProgressService(
              new DBRRunnableWithProgress() {
                @Override
                public void run(DBRProgressMonitor monitor)
                    throws InvocationTargetException, InterruptedException {
                  monitor.beginTask("Seeking for completion proposals", 1);
                  try {
                    monitor.subTask("Make structure proposals");
                    makeStructureProposals(monitor, proposals, wordPart, qt);
                  } finally {
                    monitor.done();
                  }
                }
              });
        } catch (InvocationTargetException e) {
          log.warn("Error while seeking for structure proposals", e.getTargetException());
        } catch (InterruptedException e) {
          // interrupted - do nothing
        }
      }
    }

    if (proposals.isEmpty() || !wordPart.isEmpty()) {
      // Keyword assist
      List<String> matchedKeywords =
          editor.getSyntaxManager().getDialect().getMatchedKeywords(wordPart);
      for (String keyWord : matchedKeywords) {
        DBPKeywordType keywordType = editor.getSyntaxManager().getDialect().getKeywordType(keyWord);
        if (keywordType != null) {
          proposals.add(
              createCompletionProposal(
                  keyWord, keyWord, keyWord + " (" + keywordType.name() + ")", null, false, null));
        }
      }
    }

    // Remove duplications
    for (int i = 0; i < proposals.size(); i++) {
      SQLCompletionProposal proposal = proposals.get(i);
      for (int j = i + 1; j < proposals.size(); ) {
        SQLCompletionProposal proposal2 = proposals.get(j);
        if (proposal.getDisplayString().equals(proposal2.getDisplayString())) {
          proposals.remove(j);
        } else {
          j++;
        }
      }
    }
    DBSObject selectedObject = getSelectedObject(editor.getDataSource());
    boolean hideDups =
        getPreferences().getBoolean(SQLPreferenceConstants.HIDE_DUPLICATE_PROPOSALS)
            && selectedObject != null;
    if (hideDups) {
      for (int i = 0; i < proposals.size(); i++) {
        SQLCompletionProposal proposal = proposals.get(i);
        for (int j = 0; j < proposals.size(); ) {
          SQLCompletionProposal proposal2 = proposals.get(j);
          if (i != j
              && proposal.hasStructObject()
              && proposal2.hasStructObject()
              && CommonUtils.equalObjects(
                  proposal.getObject().getName(), proposal2.getObject().getName())
              && proposal.getObjectContainer() == selectedObject) {
            proposals.remove(j);
          } else {
            j++;
          }
        }
      }
    }

    if (hideDups) {
      // Remove duplicates from non-active schema

      if (selectedObject instanceof DBSObjectContainer) {
        // List<ICompletionProposal>
      }
    }
    return proposals.toArray(new ICompletionProposal[proposals.size()]);
  }