/** Data type resolver */
public class SQLDataTypeResolver extends TemplateVariableResolver {

  private static final Log log = Log.getLog(SQLDataTypeResolver.class);

  public SQLDataTypeResolver() {
    super("type", "Data type");
  }

  @Override
  protected String[] resolveAll(final TemplateContext context) {
    final DBCExecutionContext executionContext =
        ((DBPContextProvider) context).getExecutionContext();
    if (executionContext == null) {
      return super.resolveAll(context);
    }

    DBPDataTypeProvider dataTypeProvider =
        DBUtils.getAdapter(DBPDataTypeProvider.class, executionContext.getDataSource());
    if (dataTypeProvider != null) {
      final Collection<? extends DBSDataType> localDataTypes = dataTypeProvider.getLocalDataTypes();
      if (!CommonUtils.isEmpty(localDataTypes)) {
        String[] result = new String[localDataTypes.size()];
        int index = 0;
        for (DBSDataType dataType : localDataTypes) {
          result[index++] = dataType.getName();
        }
        return result;
      }
    }
    return super.resolveAll(context);
  }
}
/** Entity resolver */
public class SQLAttributeResolver extends TemplateVariableResolver {

  private static final Log log = Log.getLog(SQLAttributeResolver.class);

  public SQLAttributeResolver() {
    super("column", "Table column");
  }

  @Override
  protected String[] resolveAll(final TemplateContext context) {
    final DBCExecutionContext executionContext =
        ((DBPContextProvider) context).getExecutionContext();
    if (executionContext == null) {
      return super.resolveAll(context);
    }

    TemplateVariable tableVariable = ((SQLContext) context).getTemplateVariable("table");
    final String tableName = tableVariable == null ? null : tableVariable.getDefaultValue();
    if (!CommonUtils.isEmpty(tableName)) {
      final List<DBSEntityAttribute> attributes = new ArrayList<>();
      DBRRunnableWithProgress runnable =
          new DBRRunnableWithProgress() {
            @Override
            public void run(DBRProgressMonitor monitor)
                throws InvocationTargetException, InterruptedException {
              try {
                List<DBSEntity> entities = new ArrayList<>();
                SQLEntityResolver.resolveTables(monitor, executionContext, context, entities);
                if (!CommonUtils.isEmpty(entities)) {
                  DBSEntity table = DBUtils.findObject(entities, tableName);
                  if (table != null) {
                    attributes.addAll(CommonUtils.safeCollection(table.getAttributes(monitor)));
                  }
                }
              } catch (DBException e) {
                throw new InvocationTargetException(e);
              }
            }
          };
      RuntimeUtils.runTask(runnable, "Resolve attributes", 1000);
      if (!CommonUtils.isEmpty(attributes)) {
        String[] result = new String[attributes.size()];
        for (int i = 0; i < attributes.size(); i++) {
          DBSEntityAttribute entity = attributes.get(i);
          result[i] = entity.getName();
        }
        return result;
      }
    }
    return super.resolveAll(context);
  }

  @Override
  public void resolve(TemplateVariable variable, TemplateContext context) {
    super.resolve(variable, context);
    if (variable instanceof SQLVariable) {
      ((SQLVariable) variable).setResolver(this);
    }
  }
}
Exemple #3
0
  static class LoadingUIJob<RESULT> extends AbstractUIJob {
    private static final Log log = Log.getLog(LoadingUIJob.class);

    private static final long DELAY = 200;

    private ILoadService<RESULT> loadService;
    private ILoadVisualizer<RESULT> visualizer;
    private DBRProgressMonitor mainMonitor;

    LoadingUIJob(LoadingJob<RESULT> loadingJob, DBRProgressMonitor mainMonitor) {
      super(loadingJob.getName());
      this.loadService = loadingJob.getLoadingService();
      this.visualizer = loadingJob.getVisualizer();
      this.mainMonitor = mainMonitor;
      setSystem(true);
    }

    @Override
    public IStatus runInUIThread(DBRProgressMonitor monitor) {
      /*
              if (mainMonitor.isCanceled()) {
                  // Try to cancel current load service
                  try {
                      loadService.cancel();
                  }
                  catch (InvocationTargetException e) {
                      log.warn("Error while canceling service", e.getTargetException());
                  }
                  return Status.CANCEL_STATUS;
              } else {
      */
      if (!visualizer.isCompleted()) {
        visualizer.visualizeLoading();
        schedule(DELAY);
      }
      // }
      return Status.OK_STATUS;
    }

    @Override
    public boolean belongsTo(Object family) {
      return family == LOADING_FAMILY;
    }

    @Override
    protected void canceling() {
      super.canceling();
    }
  }
/** Abstract oracle schema object */
public abstract class OracleGlobalObject implements DBSObject, DBPSaveableObject {
  static final Log log = Log.getLog(OracleGlobalObject.class);

  private final OracleDataSource dataSource;
  private boolean persisted;

  protected OracleGlobalObject(OracleDataSource dataSource, boolean persisted) {
    this.dataSource = dataSource;
    this.persisted = persisted;
  }

  @Nullable
  @Override
  public String getDescription() {
    return null;
  }

  @Override
  public DBSObject getParentObject() {
    return dataSource.getContainer();
  }

  @NotNull
  @Override
  public OracleDataSource getDataSource() {
    return dataSource;
  }

  @Override
  public boolean isPersisted() {
    return persisted;
  }

  @Override
  public void setPersisted(boolean persisted) {
    this.persisted = persisted;
  }
}
/** PostgreDatabase */
public class PostgreDatabase
    implements DBSInstance,
        DBSCatalog,
        DBPRefreshableObject,
        DBPStatefulObject,
        PostgreObject,
        DBSObjectSelector {

  private static final Log log = Log.getLog(PostgreDatabase.class);

  private PostgreDataSource dataSource;
  private long oid;
  private String name;
  private long ownerId;
  private long encodingId;
  private String collate;
  private String ctype;
  private boolean isTemplate;
  private boolean allowConnect;
  private int connectionLimit;
  private long tablespaceId;

  public final AuthIdCache authIdCache = new AuthIdCache();
  public final AccessMethodCache accessMethodCache = new AccessMethodCache();
  public final ForeignDataWrapperCache foreignDataWrapperCache = new ForeignDataWrapperCache();
  public final ForeignServerCache foreignServerCache = new ForeignServerCache();
  public final LanguageCache languageCache = new LanguageCache();
  public final EncodingCache encodingCache = new EncodingCache();
  public final TablespaceCache tablespaceCache = new TablespaceCache();
  public final SchemaCache schemaCache = new SchemaCache();
  public final LongKeyMap<PostgreDataType> dataTypeCache = new LongKeyMap<>();

  public PostgreDatabase(PostgreDataSource dataSource, JDBCResultSet dbResult) throws SQLException {
    this.dataSource = dataSource;
    this.loadInfo(dbResult);
  }

  private void loadInfo(JDBCResultSet dbResult) throws SQLException {
    this.oid = JDBCUtils.safeGetLong(dbResult, "oid");
    this.name = JDBCUtils.safeGetString(dbResult, "datname");
    this.ownerId = JDBCUtils.safeGetLong(dbResult, "datdba");
    this.encodingId = JDBCUtils.safeGetLong(dbResult, "encoding");
    this.collate = JDBCUtils.safeGetString(dbResult, "datcollate");
    this.ctype = JDBCUtils.safeGetString(dbResult, "datctype");
    this.isTemplate = JDBCUtils.safeGetBoolean(dbResult, "datistemplate");
    this.allowConnect = JDBCUtils.safeGetBoolean(dbResult, "datallowconn");
    this.connectionLimit = JDBCUtils.safeGetInt(dbResult, "datconnlimit");
    this.tablespaceId = JDBCUtils.safeGetLong(dbResult, "dattablespace");
  }

  @NotNull
  @Override
  public PostgreDatabase getDatabase() {
    return this;
  }

  @Override
  public long getObjectId() {
    return this.oid;
  }

  @NotNull
  @Override
  @Property(viewable = true, order = 2)
  public String getName() {
    return name;
  }

  @Nullable
  @Override
  public String getDescription() {
    return null;
  }

  @Override
  public DBSObject getParentObject() {
    return dataSource.getContainer();
  }

  @NotNull
  @Override
  public PostgreDataSource getDataSource() {
    return dataSource;
  }

  @Override
  public boolean isPersisted() {
    return true;
  }

  ///////////////////////////////////////////////////
  // Properties

  @Property(viewable = false, order = 3)
  public PostgreAuthId getDBA(DBRProgressMonitor monitor) throws DBException {
    return PostgreUtils.getObjectById(monitor, authIdCache, this, ownerId);
  }

  @Property(viewable = false, order = 4)
  public PostgreTablespace getDefaultTablespace(DBRProgressMonitor monitor) throws DBException {
    return PostgreUtils.getObjectById(monitor, tablespaceCache, this, tablespaceId);
  }

  @Property(viewable = false, order = 5)
  public PostgreCharset getDefaultEncoding(DBRProgressMonitor monitor) throws DBException {
    return PostgreUtils.getObjectById(monitor, encodingCache, this, encodingId);
  }

  @Property(viewable = false, order = 10)
  public String getCollate() {
    return collate;
  }

  @Property(viewable = false, order = 11)
  public String getCtype() {
    return ctype;
  }

  @Property(viewable = false, order = 12)
  public boolean isTemplate() {
    return isTemplate;
  }

  @Property(viewable = false, order = 13)
  public boolean isAllowConnect() {
    return allowConnect;
  }

  @Property(viewable = false, order = 14)
  public int getConnectionLimit() {
    return connectionLimit;
  }
  ///////////////////////////////////////////////////
  // Instance methods

  @NotNull
  @Override
  public DBCExecutionContext getDefaultContext(boolean meta) {
    return dataSource.getDefaultContext(meta);
  }

  @NotNull
  @Override
  public DBCExecutionContext[] getAllContexts() {
    return dataSource.getAllContexts();
  }

  @NotNull
  @Override
  public DBCExecutionContext openIsolatedContext(
      @NotNull DBRProgressMonitor monitor, @NotNull String purpose) throws DBException {
    return dataSource.openIsolatedContext(monitor, purpose);
  }

  @Override
  public void close() {}

  ///////////////////////////////////////////////
  // Infos

  @Association
  public Collection<PostgreAuthId> getAuthIds(DBRProgressMonitor monitor) throws DBException {
    return authIdCache.getAllObjects(monitor, this);
  }

  @Association
  public Collection<PostgreAccessMethod> getAccessMethods(DBRProgressMonitor monitor)
      throws DBException {
    return accessMethodCache.getAllObjects(monitor, this);
  }

  @Association
  public Collection<PostgreForeignDataWrapper> getForeignDataWrappers(DBRProgressMonitor monitor)
      throws DBException {
    return foreignDataWrapperCache.getAllObjects(monitor, this);
  }

  @Association
  public Collection<PostgreForeignServer> getForeignServers(DBRProgressMonitor monitor)
      throws DBException {
    return foreignServerCache.getAllObjects(monitor, this);
  }

  @Association
  public Collection<PostgreLanguage> getLanguages(DBRProgressMonitor monitor) throws DBException {
    return languageCache.getAllObjects(monitor, this);
  }

  @Association
  public Collection<PostgreCharset> getEncodings(DBRProgressMonitor monitor) throws DBException {
    return encodingCache.getAllObjects(monitor, this);
  }

  @Association
  public Collection<PostgreTablespace> getTablespaces(DBRProgressMonitor monitor)
      throws DBException {
    return tablespaceCache.getAllObjects(monitor, this);
  }

  ///////////////////////////////////////////////
  // Object container

  @Association
  public Collection<PostgreSchema> getSchemas(DBRProgressMonitor monitor) throws DBException {
    if (this != dataSource.getDefaultInstance()) {
      throw new DBException("Can't access non-default database");
    }
    // Get all schemas
    return schemaCache.getAllObjects(monitor, this);
  }

  @Nullable
  public PostgreSchema getCatalogSchema(DBRProgressMonitor monitor) throws DBException {
    return getSchema(monitor, PostgreConstants.CATALOG_SCHEMA_NAME);
  }

  @Nullable
  PostgreSchema getCatalogSchema() {
    return schemaCache.getCachedObject(PostgreConstants.CATALOG_SCHEMA_NAME);
  }

  void cacheDataTypes(DBRProgressMonitor monitor) throws DBException {
    dataTypeCache.clear();
    // Cache data types
    for (final PostgreSchema pgSchema : getSchemas(monitor)) {
      pgSchema.getDataTypes(monitor);
    }
  }

  public PostgreSchema getSchema(DBRProgressMonitor monitor, String name) throws DBException {
    if (this != dataSource.getDefaultInstance()) {
      throw new DBException("Can't access non-default database");
    }
    return schemaCache.getObject(monitor, this, name);
  }

  public PostgreSchema getSchema(DBRProgressMonitor monitor, long oid) throws DBException {
    if (this != dataSource.getDefaultInstance()) {
      throw new DBException("Can't access non-default database");
    }
    for (PostgreSchema schema : schemaCache.getAllObjects(monitor, this)) {
      if (schema.getObjectId() == oid) {
        return schema;
      }
    }
    return null;
  }

  PostgreTableBase findTable(DBRProgressMonitor monitor, long schemaId, long tableId)
      throws DBException {
    PostgreSchema schema = getSchema(monitor, schemaId);
    if (schema == null) {
      log.error("Catalog " + schemaId + " not found");
      return null;
    }
    return schema.getTable(monitor, tableId);
  }

  @Override
  public Collection<? extends DBSObject> getChildren(@NotNull DBRProgressMonitor monitor)
      throws DBException {
    return getSchemas(monitor);
  }

  @Override
  public DBSObject getChild(@NotNull DBRProgressMonitor monitor, @NotNull String childName)
      throws DBException {
    return getSchema(monitor, childName);
  }

  @Override
  public Class<? extends DBSObject> getChildType(@NotNull DBRProgressMonitor monitor)
      throws DBException {
    return PostgreSchema.class;
  }

  @Override
  public void cacheStructure(@NotNull DBRProgressMonitor monitor, int scope) throws DBException {}

  @Override
  public DBSObjectState getObjectState() {
    if (this == dataSource.getDefaultInstance()) {
      return DBSObjectState.NORMAL;
    } else {
      return PostgreConstants.STATE_UNAVAILABLE;
    }
  }

  @Override
  public void refreshObjectState(@NotNull DBRProgressMonitor monitor) throws DBCException {}

  @Override
  public DBSObject refreshObject(@NotNull DBRProgressMonitor monitor) throws DBException {
    authIdCache.clearCache();
    accessMethodCache.clearCache();
    languageCache.clearCache();
    encodingCache.clearCache();
    tablespaceCache.clearCache();
    schemaCache.clearCache();

    cacheDataTypes(monitor);
    return this;
  }

  public Collection<PostgreAuthId> getUsers(DBRProgressMonitor monitor) throws DBException {
    return authIdCache.getAllObjects(monitor, this);
  }

  @Override
  public boolean supportsDefaultChange() {
    return true;
  }

  @Nullable
  @Override
  public PostgreSchema getDefaultObject() {
    return schemaCache.getCachedObject(dataSource.getActiveSchemaName());
  }

  @Override
  public void setDefaultObject(@NotNull DBRProgressMonitor monitor, @NotNull DBSObject object)
      throws DBException {
    if (object instanceof PostgreSchema) {
      PostgreSchema oldActive = getDefaultObject();
      if (oldActive == object) {
        return;
      }

      for (JDBCExecutionContext context : dataSource.getAllContexts()) {
        setSearchPath(monitor, (PostgreSchema) object, context);
      }
      dataSource.setActiveSchemaName(object.getName());
      dataSource.setSearchPath(object.getName());

      if (oldActive != null) {
        DBUtils.fireObjectSelect(oldActive, false);
      }
      DBUtils.fireObjectSelect(object, true);
    }
  }

  @Override
  public boolean refreshDefaultObject(@NotNull DBCSession session) throws DBException {
    return dataSource.refreshDefaultObject(session);
  }

  void setSearchPath(DBRProgressMonitor monitor, PostgreSchema schema, JDBCExecutionContext context)
      throws DBCException {
    try (JDBCSession session =
        context.openSession(monitor, DBCExecutionPurpose.UTIL, "Change search path")) {
      JDBCUtils.executeSQL(
          session, "SET search_path = \"$user\"," + DBUtils.getQuotedIdentifier(schema));
    } catch (SQLException e) {
      throw new DBCException("Error setting search path", e, dataSource);
    }
  }

  public PostgreProcedure getProcedure(DBRProgressMonitor monitor, long schemaId, long procId)
      throws DBException {
    final PostgreSchema schema = getSchema(monitor, schemaId);
    if (schema != null) {
      return PostgreUtils.getObjectById(monitor, schema.proceduresCache, schema, procId);
    }
    return null;
  }

  public PostgreDataType getDataType(long typeId) {
    if (typeId <= 0) {
      return null;
    }
    PostgreDataType dataType = dataTypeCache.get(typeId);
    if (dataType != null) {
      return dataType;
    }
    for (PostgreSchema schema : getDatabase().schemaCache.getCachedObjects()) {
      dataType = schema.dataTypeCache.getDataType(typeId);
      if (dataType != null) {
        dataTypeCache.put(typeId, dataType);
        return dataType;
      }
    }
    log.debug("Data type '" + typeId + "' not found");
    return null;
  }

  public PostgreDataType getDataType(String typeName) {
    if (typeName.endsWith("[]")) {
      // In some cases ResultSetMetadata returns it as []
      typeName = "_" + typeName.substring(0, typeName.length() - 2);
    }
    String alias = PostgreConstants.DATA_TYPE_ALIASES.get(typeName);
    if (alias != null) {
      typeName = alias;
    }
    {
      // First check system catalog
      final PostgreSchema schema = getCatalogSchema();
      if (schema != null) {
        final PostgreDataType dataType = schema.dataTypeCache.getCachedObject(typeName);
        if (dataType != null) {
          return dataType;
        }
      }
    }

    // Check schemas in search path
    final List<String> searchPath = dataSource.getSearchPath();
    for (String schemaName : searchPath) {
      final PostgreSchema schema = schemaCache.getCachedObject(schemaName);
      if (schema != null) {
        final PostgreDataType dataType = schema.dataTypeCache.getCachedObject(typeName);
        if (dataType != null) {
          return dataType;
        }
      }
    }
    // Check the rest
    for (PostgreSchema schema : schemaCache.getCachedObjects()) {
      if (searchPath.contains(schema.getName())) {
        continue;
      }
      final PostgreDataType dataType = schema.dataTypeCache.getCachedObject(typeName);
      if (dataType != null) {
        return dataType;
      }
    }
    log.debug("Data type '" + typeName + "' not found in database '" + getName() + "'");
    return null;
  }

  @Override
  public String toString() {
    return name;
  }

  class AuthIdCache extends JDBCObjectCache<PostgreDatabase, PostgreAuthId> {

    @Override
    protected JDBCStatement prepareObjectsStatement(
        @NotNull JDBCSession session, @NotNull PostgreDatabase owner) throws SQLException {
      return session.prepareStatement(
          "SELECT a.oid,a.* FROM pg_catalog.pg_authid a " + "\nORDER BY a.oid");
    }

    @Override
    protected PostgreAuthId fetchObject(
        @NotNull JDBCSession session,
        @NotNull PostgreDatabase owner,
        @NotNull JDBCResultSet dbResult)
        throws SQLException, DBException {
      return new PostgreAuthId(owner, dbResult);
    }

    @Override
    protected boolean handleCacheReadError(DBException error) {
      // #271, #501: in some databases (AWS?) pg_authid is not accessible
      // FIXME: maybe some better workaround?
      if (PostgreConstants.EC_PERMISSION_DENIED.equals(error.getDatabaseState())) {
        log.warn(error);
        setCache(Collections.<PostgreAuthId>emptyList());
        return true;
      }
      return false;
    }
  }

  class AccessMethodCache extends JDBCObjectCache<PostgreDatabase, PostgreAccessMethod> {

    @Override
    protected JDBCStatement prepareObjectsStatement(
        @NotNull JDBCSession session, @NotNull PostgreDatabase owner) throws SQLException {
      return session.prepareStatement(
          "SELECT am.oid,am.* FROM pg_catalog.pg_am am " + "\nORDER BY am.oid");
    }

    @Override
    protected PostgreAccessMethod fetchObject(
        @NotNull JDBCSession session,
        @NotNull PostgreDatabase owner,
        @NotNull JDBCResultSet dbResult)
        throws SQLException, DBException {
      return new PostgreAccessMethod(owner, dbResult);
    }
  }

  class EncodingCache extends JDBCObjectCache<PostgreDatabase, PostgreCharset> {

    @Override
    protected JDBCStatement prepareObjectsStatement(
        @NotNull JDBCSession session, @NotNull PostgreDatabase owner) throws SQLException {
      return session.prepareStatement(
          "SELECT c.contoencoding as encid,pg_catalog.pg_encoding_to_char(c.contoencoding) as encname\n"
              + "FROM pg_catalog.pg_conversion c\n"
              + "GROUP BY c.contoencoding\n"
              + "ORDER BY 2\n");
    }

    @Override
    protected PostgreCharset fetchObject(
        @NotNull JDBCSession session,
        @NotNull PostgreDatabase owner,
        @NotNull JDBCResultSet dbResult)
        throws SQLException, DBException {
      return new PostgreCharset(owner, dbResult);
    }
  }

  class LanguageCache extends JDBCObjectCache<PostgreDatabase, PostgreLanguage> {

    @Override
    protected JDBCStatement prepareObjectsStatement(
        @NotNull JDBCSession session, @NotNull PostgreDatabase owner) throws SQLException {
      return session.prepareStatement(
          "SELECT l.oid,l.* FROM pg_catalog.pg_language l " + "\nORDER BY l.oid");
    }

    @Override
    protected PostgreLanguage fetchObject(
        @NotNull JDBCSession session,
        @NotNull PostgreDatabase owner,
        @NotNull JDBCResultSet dbResult)
        throws SQLException, DBException {
      return new PostgreLanguage(owner, dbResult);
    }
  }

  class ForeignDataWrapperCache
      extends JDBCObjectCache<PostgreDatabase, PostgreForeignDataWrapper> {

    @Override
    protected JDBCStatement prepareObjectsStatement(
        @NotNull JDBCSession session, @NotNull PostgreDatabase owner) throws SQLException {
      return session.prepareStatement(
          "SELECT l.oid,l.*,p.pronamespace as handler_schema_id "
              + "\nFROM pg_catalog.pg_foreign_data_wrapper l"
              + "\nLEFT OUTER JOIN pg_catalog.pg_proc p ON p.oid=l.fdwhandler "
              + "\nORDER BY l.fdwname");
    }

    @Override
    protected PostgreForeignDataWrapper fetchObject(
        @NotNull JDBCSession session,
        @NotNull PostgreDatabase owner,
        @NotNull JDBCResultSet dbResult)
        throws SQLException, DBException {
      return new PostgreForeignDataWrapper(owner, dbResult);
    }
  }

  class ForeignServerCache extends JDBCObjectCache<PostgreDatabase, PostgreForeignServer> {

    @Override
    protected JDBCStatement prepareObjectsStatement(
        @NotNull JDBCSession session, @NotNull PostgreDatabase owner) throws SQLException {
      return session.prepareStatement(
          "SELECT l.oid,l.* FROM pg_catalog.pg_foreign_server l" + "\nORDER BY l.srvname");
    }

    @Override
    protected PostgreForeignServer fetchObject(
        @NotNull JDBCSession session,
        @NotNull PostgreDatabase owner,
        @NotNull JDBCResultSet dbResult)
        throws SQLException, DBException {
      return new PostgreForeignServer(owner, dbResult);
    }
  }

  class TablespaceCache extends JDBCObjectCache<PostgreDatabase, PostgreTablespace> {

    @Override
    protected JDBCStatement prepareObjectsStatement(
        @NotNull JDBCSession session, @NotNull PostgreDatabase owner) throws SQLException {
      return session.prepareStatement(
          "SELECT t.oid,t.* FROM pg_catalog.pg_tablespace t " + "\nORDER BY t.oid");
    }

    @Override
    protected PostgreTablespace fetchObject(
        @NotNull JDBCSession session,
        @NotNull PostgreDatabase owner,
        @NotNull JDBCResultSet dbResult)
        throws SQLException, DBException {
      return new PostgreTablespace(owner, dbResult);
    }
  }

  static class SchemaCache extends JDBCObjectLookupCache<PostgreDatabase, PostgreSchema> {
    @NotNull
    @Override
    public JDBCStatement prepareLookupStatement(
        @NotNull JDBCSession session,
        @NotNull PostgreDatabase database,
        @Nullable PostgreSchema object,
        @Nullable String objectName)
        throws SQLException {
      /*
                  // Do not apply filters
                  // We need all schemas to have access to types
                  return session.prepareStatement(
                      "SELECT n.oid,n.* FROM pg_catalog.pg_namespace n ORDER BY nspname");
      */
      StringBuilder catalogQuery =
          new StringBuilder("SELECT n.oid,n.* FROM pg_catalog.pg_namespace n");
      DBSObjectFilter catalogFilters =
          database.getDataSource().getContainer().getObjectFilter(PostgreSchema.class, null, false);
      if ((catalogFilters != null && !catalogFilters.isNotApplicable())
          || object != null
          || objectName != null) {
        if (object != null || objectName != null) {
          catalogFilters = new DBSObjectFilter();
          catalogFilters.addInclude(object != null ? object.getName() : objectName);
        } else {
          catalogFilters = new DBSObjectFilter(catalogFilters);
          // Always read catalog schema
          catalogFilters.addInclude(PostgreConstants.CATALOG_SCHEMA_NAME);
        }
        JDBCUtils.appendFilterClause(catalogQuery, catalogFilters, "nspname", true);
      }
      catalogQuery.append(" ORDER BY nspname");
      JDBCPreparedStatement dbStat = session.prepareStatement(catalogQuery.toString());
      if (catalogFilters != null) {
        JDBCUtils.setFilterParameters(dbStat, 1, catalogFilters);
      }
      return dbStat;
    }

    @Override
    protected PostgreSchema fetchObject(
        @NotNull JDBCSession session,
        @NotNull PostgreDatabase owner,
        @NotNull JDBCResultSet resultSet)
        throws SQLException, DBException {
      String name = JDBCUtils.safeGetString(resultSet, "nspname");
      if (name == null) {
        return null;
      }
      if (PostgreSchema.isUtilitySchema(name)
          && !owner.getDataSource().getContainer().isShowUtilityObjects()) {
        return null;
      }
      return new PostgreSchema(owner, name, resultSet);
    }
  }
}
Exemple #6
0
/** DBeaver UI core */
public class DBeaverUI implements DBUICallback {

  static final Log log = Log.getLog(DBeaverUI.class);

  private static DBeaverUI instance;

  private SharedTextColors sharedTextColors;
  private TrayIconHandler trayItem;
  private final List<IDisposable> globalDisposables = new ArrayList<>();

  public static DBeaverUI getInstance() {
    if (instance == null) {
      instance = new DBeaverUI();
      instance.initialize();
    }
    return instance;
  }

  static void disposeUI() {
    if (instance != null) {
      instance.dispose();
    }
  }

  public static ISharedTextColors getSharedTextColors() {
    return getInstance().sharedTextColors;
  }

  private void dispose() {
    // this.trayItem.dispose();
    this.sharedTextColors.dispose();

    if (trayItem != null) {
      trayItem.hide();
    }

    List<IDisposable> dispList = new ArrayList<>(globalDisposables);
    Collections.reverse(dispList);
    for (IDisposable disp : dispList) {
      try {
        disp.dispose();
      } catch (Exception e) {
        log.error(e);
      }
      globalDisposables.remove(disp);
    }
  }

  private void initialize() {
    this.sharedTextColors = new SharedTextColors();
    this.trayItem = new TrayIconHandler();
    DBUserInterface.setInstance(this);

    // Register context listener
    WorkbenchContextListener.registerInWorkbench();

    /*      // Global focus lister for debug
            Display.getCurrent().addFilter(SWT.FocusIn, new Listener() {
                @Override
                public void handleEvent(Event event) {
                    System.out.println("FOCUS TO: " + event.widget);
                }
            });
    */
  }

  public static AbstractUIJob runUIJob(
      String jobName, final DBRRunnableWithProgress runnableWithProgress) {
    return runUIJob(jobName, 0, runnableWithProgress);
  }

  public static AbstractUIJob runUIJob(
      String jobName, int timeout, final DBRRunnableWithProgress runnableWithProgress) {
    AbstractUIJob job =
        new AbstractUIJob(jobName) {
          @Override
          public IStatus runInUIThread(DBRProgressMonitor monitor) {
            try {
              runnableWithProgress.run(monitor);
            } catch (InvocationTargetException e) {
              return GeneralUtils.makeExceptionStatus(e);
            } catch (InterruptedException e) {
              return Status.CANCEL_STATUS;
            }
            return Status.OK_STATUS;
          }
        };
    job.setSystem(true);
    job.schedule(timeout);
    return job;
  }

  @NotNull
  public static IWorkbenchWindow getActiveWorkbenchWindow() {
    IWorkbench workbench = PlatformUI.getWorkbench();
    IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
    if (window != null) {
      return window;
    }
    IWorkbenchWindow[] windows = workbench.getWorkbenchWindows();
    if (windows.length > 0) {
      return windows[0];
    }
    throw new IllegalStateException("No workbench window");
  }

  public static Shell getActiveWorkbenchShell() {
    return getActiveWorkbenchWindow().getShell();
  }

  public static Display getDisplay() {
    Shell shell = getActiveWorkbenchShell();
    if (shell != null) return shell.getDisplay();
    else return Display.getDefault();
  }

  /*
      public static void runWithProgress(IWorkbenchPartSite site, final DBRRunnableWithProgress runnable)
          throws InvocationTargetException, InterruptedException
      {
          IActionBars actionBars = null;
          if (site instanceof IViewSite) {
              actionBars = ((IViewSite) site).getActionBars();
          } else if (site instanceof IEditorSite) {
              actionBars = ((IEditorSite) site).getActionBars();
          }
          IStatusLineManager statusLineManager = null;
          if (actionBars != null) {
              statusLineManager = actionBars.getStatusLineManager();
          }
          if (statusLineManager == null) {
              runInProgressService(runnable);
          } else {
              IProgressMonitor progressMonitor = statusLineManager.getProgressMonitor();
              runnable.run(new DefaultProgressMonitor(progressMonitor));
          }
      }
  */

  public static DBRRunnableContext getDefaultRunnableContext() {
    IWorkbench workbench = PlatformUI.getWorkbench();
    if (workbench != null && workbench.getActiveWorkbenchWindow() != null) {
      return new RunnableContextDelegate(workbench.getActiveWorkbenchWindow());
    } else {
      return new DBRRunnableContext() {
        @Override
        public void run(boolean fork, boolean cancelable, DBRRunnableWithProgress runnable)
            throws InvocationTargetException, InterruptedException {
          runnable.run(VoidProgressMonitor.INSTANCE);
        }
      };
    }
  }

  /**
   * Runs task in Eclipse progress service. NOTE: this call can't be canceled if it will block in IO
   */
  public static void runInProgressService(final DBRRunnableWithProgress runnable)
      throws InvocationTargetException, InterruptedException {
    getDefaultRunnableContext()
        .run(
            true,
            true,
            new DBRRunnableWithProgress() {
              @Override
              public void run(DBRProgressMonitor monitor)
                  throws InvocationTargetException, InterruptedException {
                runnable.run(monitor);
              }
            });
  }

  /**
   * Runs task in Eclipse progress dialog. NOTE: this call can't be canceled if it will block in IO
   */
  public static void runInProgressDialog(final DBRRunnableWithProgress runnable)
      throws InvocationTargetException {
    try {
      IRunnableContext runnableContext;
      IWorkbench workbench = PlatformUI.getWorkbench();
      IWorkbenchWindow workbenchWindow = workbench.getActiveWorkbenchWindow();
      if (workbenchWindow != null) {
        runnableContext =
            new ProgressMonitorDialog(workbench.getActiveWorkbenchWindow().getShell());
      } else {
        runnableContext = workbench.getProgressService();
      }
      runnableContext.run(
          true,
          true,
          new IRunnableWithProgress() {
            @Override
            public void run(IProgressMonitor monitor)
                throws InvocationTargetException, InterruptedException {
              runnable.run(RuntimeUtils.makeMonitor(monitor));
            }
          });
    } catch (InterruptedException e) {
      // do nothing
    }
  }

  public static void runInUI(IRunnableContext context, final DBRRunnableWithProgress runnable) {
    try {
      PlatformUI.getWorkbench()
          .getProgressService()
          .runInUI(
              context,
              new IRunnableWithProgress() {
                @Override
                public void run(IProgressMonitor monitor)
                    throws InvocationTargetException, InterruptedException {
                  runnable.run(RuntimeUtils.makeMonitor(monitor));
                }
              },
              DBeaverActivator.getWorkspace().getRoot());
    } catch (InvocationTargetException e) {
      UIUtils.showErrorDialog(null, null, null, e.getTargetException());
    } catch (InterruptedException e) {
      // do nothing
    }
  }

  public static void notifyAgent(String message, int status) {
    if (!DBeaverCore.getGlobalPreferenceStore()
        .getBoolean(DBeaverPreferences.AGENT_LONG_OPERATION_NOTIFY)) {
      // Notifications disabled
      return;
    }
    getInstance().trayItem.notify(message, status);
  }

  @Override
  public void showError(@NotNull String title, @Nullable String message, @NotNull IStatus status) {
    UIUtils.showErrorDialog(null, title, message, status);
  }

  @Override
  public void showError(@NotNull String title, @Nullable String message, @NotNull Throwable e) {
    UIUtils.showErrorDialog(null, title, message, e);
  }

  @Override
  public void showError(@NotNull String title, @Nullable String message) {
    UIUtils.showErrorDialog(null, title, message);
  }

  @Override
  public DBAAuthInfo promptUserCredentials(String prompt, String userName, String userPassword) {
    // Ask user
    final Shell shell = DBeaverUI.getActiveWorkbenchShell();
    final BaseAuthDialog authDialog = new BaseAuthDialog(shell, prompt);
    authDialog.setUserName(userName);
    authDialog.setUserPassword(userPassword);
    final RunnableWithResult<Boolean> binder =
        new RunnableWithResult<Boolean>() {
          @Override
          public void run() {
            result = (authDialog.open() == IDialogConstants.OK_ID);
          }
        };
    UIUtils.runInUI(shell, binder);
    if (binder.getResult() != null && binder.getResult()) {
      return authDialog.getAuthInfo();
    } else {
      return null;
    }
  }

  @Override
  public void executeProcess(final DBRProcessDescriptor processDescriptor) {
    processDescriptor.setProcessListener(
        new DBRProcessListener() {
          @Override
          public void onProcessStarted() {
            ProcessPropertyTester.firePropertyChange(ProcessPropertyTester.PROP_RUNNING);
          }

          @Override
          public void onProcessTerminated(int resultCode) {
            ProcessPropertyTester.firePropertyChange(ProcessPropertyTester.PROP_RUNNING);
          }
        });
    // Direct execute
    try {
      processDescriptor.execute();
    } catch (DBException e) {
      showError("Execute process", processDescriptor.getName(), e);
    }
    if (processDescriptor.getCommand().isShowProcessPanel()) {
      getActiveWorkbenchShell()
          .getDisplay()
          .asyncExec(
              new Runnable() {
                @Override
                public void run() {
                  try {
                    final ShellProcessView processView =
                        (ShellProcessView)
                            DBeaverUI.getActiveWorkbenchWindow()
                                .getActivePage()
                                .showView(
                                    ShellProcessView.VIEW_ID,
                                    ShellProcessView.getNextId(),
                                    IWorkbenchPage.VIEW_VISIBLE);
                    processView.initProcess(processDescriptor);
                  } catch (PartInitException e) {
                    log.error(e);
                  }
                }
              });
    }
  }
}
/** Table collector */
public class DiagramObjectCollector {

  private static final Log log = Log.getLog(DiagramObjectCollector.class);

  private final EntityDiagram diagram;
  private final List<ERDEntity> erdEntities = new ArrayList<>();
  private final Map<DBSEntity, ERDEntity> tableMap = new HashMap<>();

  public DiagramObjectCollector(EntityDiagram diagram) {
    this.diagram = diagram;
    this.tableMap.putAll(diagram.getTableMap());
  }

  public static Collection<DBSEntity> collectTables(
      DBRProgressMonitor monitor, Collection<? extends DBSObject> roots) throws DBException {
    Set<DBSEntity> tables = new LinkedHashSet<>();
    collectTables(monitor, roots, tables);
    return tables;
  }

  private static void collectTables(
      DBRProgressMonitor monitor, Collection<? extends DBSObject> roots, Set<DBSEntity> tables)
      throws DBException {
    for (DBSObject root : roots) {
      if (monitor.isCanceled()) {
        break;
      }
      if (root instanceof DBSFolder) {
        collectTables(monitor, ((DBSFolder) root).getChildrenObjects(monitor), tables);
      } else if (root instanceof DBSEntity) {
        tables.add((DBSEntity) root);
      }
      if (root instanceof DBSObjectContainer) {
        collectTables(monitor, (DBSObjectContainer) root, tables);
      }
    }
  }

  private static void collectTables(
      DBRProgressMonitor monitor, DBSObjectContainer container, Set<DBSEntity> tables)
      throws DBException {
    if (monitor.isCanceled()) {
      return;
    }
    container.cacheStructure(monitor, DBSObjectContainer.STRUCT_ALL);
    final Collection<? extends DBSObject> children = container.getChildren(monitor);
    if (!CommonUtils.isEmpty(children)) {
      Class<? extends DBSObject> childType = container.getChildType(monitor);
      DBSObjectFilter objectFilter =
          container.getDataSource().getContainer().getObjectFilter(childType, container, true);
      for (DBSObject entity : children) {
        if (monitor.isCanceled()) {
          break;
        }
        if (objectFilter != null && !objectFilter.matches(entity.getName())) {
          continue;
        }
        if (entity instanceof DBSEntity) {
          tables.add((DBSEntity) entity);
        } else if (entity instanceof DBSObjectContainer) {
          collectTables(monitor, (DBSObjectContainer) entity, tables);
        }
      }
    }
  }

  public void generateDiagramObjects(
      DBRProgressMonitor monitor, Collection<? extends DBSObject> roots) throws DBException {
    boolean showViews =
        ERDActivator.getDefault()
            .getPreferenceStore()
            .getBoolean(ERDConstants.PREF_DIAGRAM_SHOW_VIEWS);
    Collection<DBSEntity> tables = collectTables(monitor, roots);
    for (DBSEntity table : tables) {
      if (DBUtils.isHiddenObject(table)) {
        // Skip hidden tables
        continue;
      }
      if (!showViews && table instanceof DBSTable && ((DBSTable) table).isView()) {
        // Skip views
        continue;
      }
      addDiagramEntity(monitor, table);
    }

    // Add new relations
    for (ERDEntity erdEntity : erdEntities) {
      erdEntity.addRelations(monitor, tableMap, false);
    }
  }

  private void addDiagramEntity(DBRProgressMonitor monitor, DBSEntity table) {
    if (diagram.containsTable(table)) {
      // Avoid duplicates
      return;
    }
    ERDEntity erdEntity = ERDEntity.fromObject(monitor, diagram, table);
    if (erdEntity != null) {
      erdEntities.add(erdEntity);
      tableMap.put(table, erdEntity);
    }
  }

  public List<ERDEntity> getDiagramEntities() {
    return erdEntities;
  }

  public static List<ERDEntity> generateEntityList(
      final EntityDiagram diagram, Collection<DBPNamedObject> objects) {
    final List<DBSObject> roots = new ArrayList<>();
    for (DBPNamedObject object : objects) {
      if (object instanceof DBSObject) {
        roots.add((DBSObject) object);
      }
    }

    final List<ERDEntity> entities = new ArrayList<>();

    try {
      DBeaverUI.runInProgressService(
          new DBRRunnableWithProgress() {
            @Override
            public void run(DBRProgressMonitor monitor)
                throws InvocationTargetException, InterruptedException {
              DiagramObjectCollector collector = new DiagramObjectCollector(diagram);
              try {
                collector.generateDiagramObjects(monitor, roots);
              } catch (DBException e) {
                throw new InvocationTargetException(e);
              }
              entities.addAll(collector.getDiagramEntities());
            }
          });
    } catch (InvocationTargetException e) {
      log.error(e.getTargetException());
    } catch (InterruptedException e) {
      // interrupted
    }
    return entities;
  }
}
Exemple #8
0
/**
 * DB2 Index
 *
 * @author Denis Forveille
 */
public class DB2Index extends JDBCTableIndex<DB2Schema, DB2TableBase> {

  private static final Log LOG = Log.getLog(DB2Index.class);

  // Structure
  private DB2UniqueRule uniqueRule;
  private Integer colCount;
  private Integer uniqueColCount;
  private DB2IndexType db2IndexType;
  private Integer pctFree;
  private Integer indexId;
  private Integer minPctUsed;
  private Boolean reverseScans;
  private Integer tablespaceId;
  private DB2IndexPageSplit pageSplit;
  private Boolean compression;
  private String remarks;

  // Derived
  private Timestamp createTime;
  private Boolean madeUnique;

  // Stats
  private Timestamp statsTime;
  private Long fullKeycard;
  private Long firstKeycard;
  private Long first2Keycard;
  private Long first3Keycard;
  private Long first4Keycard;
  private Integer clusterRatio;

  // -----------------
  // Constructors
  // -----------------
  public DB2Index(
      DBRProgressMonitor monitor, DB2Schema schema, DB2TableBase table, ResultSet dbResult) {
    super(schema, table, JDBCUtils.safeGetStringTrimmed(dbResult, "INDNAME"), null, true);

    DB2DataSource db2DataSource = (DB2DataSource) schema.getDataSource();

    this.uniqueRule =
        CommonUtils.valueOf(DB2UniqueRule.class, JDBCUtils.safeGetString(dbResult, "UNIQUERULE"));
    this.colCount = JDBCUtils.safeGetInteger(dbResult, "COLCOUNT");
    this.uniqueColCount = JDBCUtils.safeGetInteger(dbResult, "UNIQUE_COLCOUNT");
    this.pctFree = JDBCUtils.safeGetInteger(dbResult, "PCTFREE");
    this.indexId = JDBCUtils.safeGetInteger(dbResult, "IID");
    this.minPctUsed = JDBCUtils.safeGetInteger(dbResult, "MINPCTUSED");
    this.reverseScans = JDBCUtils.safeGetBoolean(dbResult, "REVERSE_SCANS", DB2YesNo.Y.name());
    this.tablespaceId = JDBCUtils.safeGetInteger(dbResult, "TBSPACEID");
    this.pageSplit =
        CommonUtils.valueOf(
            DB2IndexPageSplit.class, JDBCUtils.safeGetStringTrimmed(dbResult, "PAGESPLIT"));
    this.remarks = JDBCUtils.safeGetString(dbResult, "REMARKS");

    this.createTime = JDBCUtils.safeGetTimestamp(dbResult, "CREATE_TIME");
    this.madeUnique = JDBCUtils.safeGetBoolean(dbResult, "MADE_UNIQUE");

    this.statsTime = JDBCUtils.safeGetTimestamp(dbResult, "STATS_TIME");
    this.fullKeycard = JDBCUtils.safeGetLong(dbResult, "FULLKEYCARD");
    this.firstKeycard = JDBCUtils.safeGetLong(dbResult, "FIRSTKEYCARD");
    this.first2Keycard = JDBCUtils.safeGetLong(dbResult, "FIRST2KEYCARD");
    this.first3Keycard = JDBCUtils.safeGetLong(dbResult, "FIRST3KEYCARD");
    this.first4Keycard = JDBCUtils.safeGetLong(dbResult, "FIRST4KEYCARD");
    this.clusterRatio = JDBCUtils.safeGetInteger(dbResult, "CLUSTERRATIO");

    if (db2DataSource.isAtLeastV9_5()) {
      this.compression = JDBCUtils.safeGetBoolean(dbResult, "COMPRESSION", DB2YesNo.Y.name());
    }

    // DF: Could have been done in constructor. More "readable" to do it here
    this.db2IndexType =
        CommonUtils.valueOf(
            DB2IndexType.class, JDBCUtils.safeGetStringTrimmed(dbResult, "INDEXTYPE"));
    this.indexType = db2IndexType.getDBSIndexType();
  }

  public DB2Index(DB2TableBase db2Table, String indexName, DBSIndexType indexType) {
    super(db2Table.getSchema(), db2Table, indexName, indexType, false);
  }

  // -----------------
  // Business Contract
  // -----------------
  @Override
  public boolean isUnique() {
    return (uniqueRule.isUnique());
  }

  @NotNull
  @Override
  public DB2DataSource getDataSource() {
    return getTable().getDataSource();
  }

  @Override
  public String getFullQualifiedName() {
    return getContainer().getName() + "." + getName();
  }

  // -----------------
  // Columns
  // -----------------

  @Override
  public List<DB2IndexColumn> getAttributeReferences(DBRProgressMonitor monitor) {
    try {
      return getContainer().getIndexCache().getChildren(monitor, getContainer(), this);
    } catch (DBException e) {
      // DF: Don't know what to do with this exception except log it
      LOG.error("DBException swallowed during getAttributeReferences", e);
      return null;
    }
  }

  public void addColumn(DB2IndexColumn ixColumn) {
    DBSObjectCache<DB2Index, DB2IndexColumn> cols =
        getContainer().getIndexCache().getChildrenCache(this);
    cols.cacheObject(ixColumn);
  }

  // -----------------
  // Properties
  // -----------------

  @NotNull
  @Override
  @Property(
      viewable = true,
      editable = true,
      valueTransformer = DBObjectNameCaseTransformer.class,
      order = 1)
  public String getName() {
    return super.getName();
  }

  @Property(viewable = true, editable = false, order = 2)
  public DB2Schema getIndSchema() {
    return getContainer();
  }

  @Property(viewable = true, editable = false, order = 5)
  public DB2UniqueRule getUniqueRule() {
    return uniqueRule;
  }

  @Property(viewable = false, editable = false, order = 10)
  public Boolean getMadeUnique() {
    return madeUnique;
  }

  @Property(viewable = false, editable = false, order = 11)
  public Integer getColCount() {
    return colCount;
  }

  @Property(viewable = false, editable = false, order = 12)
  public Integer getUniqueColCount() {
    return uniqueColCount;
  }

  @Property(viewable = false, editable = false, order = 70)
  public Integer getIndexId() {
    return indexId;
  }

  @Property(viewable = false, editable = false, order = 71)
  public Integer getTablespaceId() {
    return tablespaceId;
  }

  @Property(viewable = false, order = 20, editable = false)
  public Integer getPctFree() {
    return pctFree;
  }

  @Property(viewable = false, order = 21, editable = false)
  public Integer getMinPctUsed() {
    return minPctUsed;
  }

  @Property(viewable = false, order = 22, editable = false)
  public Boolean getReverseScans() {
    return reverseScans;
  }

  @Property(viewable = false, order = 23, editable = false)
  public DB2IndexPageSplit getPageSplit() {
    return pageSplit;
  }

  @Property(viewable = false, order = 24, editable = false)
  public Boolean getCompression() {
    return compression;
  }

  @Nullable
  @Override
  @Property(viewable = false, editable = false)
  public String getDescription() {
    return remarks;
  }

  @Property(viewable = false, editable = false, category = DB2Constants.CAT_DATETIME)
  public Timestamp getCreateTime() {
    return createTime;
  }

  @Property(viewable = false, editable = false, order = 30, category = DB2Constants.CAT_STATS)
  public Timestamp getStatsTime() {
    return statsTime;
  }

  @Property(viewable = true, editable = false, order = 31, category = DB2Constants.CAT_STATS)
  public Long getFullKeycard() {
    return fullKeycard;
  }

  @Property(viewable = false, editable = false, order = 32, category = DB2Constants.CAT_STATS)
  public Long getFirstKeycard() {
    return firstKeycard;
  }

  @Property(viewable = false, editable = false, order = 33, category = DB2Constants.CAT_STATS)
  public Long getFirst2Keycard() {
    return first2Keycard;
  }

  @Property(viewable = false, editable = false, order = 34, category = DB2Constants.CAT_STATS)
  public Long getFirst3Keycard() {
    return first3Keycard;
  }

  @Property(viewable = false, editable = false, order = 35, category = DB2Constants.CAT_STATS)
  public Long getFirst4Keycard() {
    return first4Keycard;
  }

  @Property(viewable = false, editable = false, order = 36, category = DB2Constants.CAT_STATS)
  public Integer getClusterRatio() {
    return clusterRatio;
  }
}
Exemple #9
0
/** DBNProject */
public class DBNProject extends DBNResource {
  private static final Log log = Log.getLog(DBNProject.class);

  public DBNProject(DBNNode parentNode, IProject project, DBPResourceHandler handler) {
    super(parentNode, project, handler);
    getModel().getApplication().getProjectManager().addProject(project);
  }

  @Override
  protected void dispose(boolean reflect) {
    IProject project = getProject();
    super.dispose(reflect);
    getModel().getApplication().getProjectManager().removeProject(project);
  }

  public IProject getProject() {
    return (IProject) getResource();
  }

  public DBNProjectDatabases getDatabases() {
    try {
      for (DBNNode db : getChildren(VoidProgressMonitor.INSTANCE)) {
        if (db instanceof DBNProjectDatabases) {
          return (DBNProjectDatabases) db;
        }
      }
    } catch (DBException e) {
      throw new IllegalStateException("Can't read project contents", e);
    }
    throw new IllegalStateException("No databases resource in project");
  }

  @Override
  public String getNodeDescription() {
    try {
      final IProject project = getProject();
      return project == null ? null : project.getDescription().getComment();
    } catch (CoreException e) {
      log.debug(e);
      return null;
    }
  }

  @Override
  public DBPImage getNodeIcon() {
    return DBIcon.PROJECT;
  }

  @Override
  public boolean allowsOpen() {
    return false;
  }

  @Override
  public <T> T getAdapter(Class<T> adapter) {
    if (adapter == DBNProject.class) {
      return adapter.cast(this);
    }
    return super.getAdapter(adapter);
  }

  @Override
  public boolean supportsRename() {
    // Do not rename active projects
    return getModel().getApplication().getProjectManager().getActiveProject() != getProject();
  }

  @Override
  public void rename(DBRProgressMonitor monitor, String newName) throws DBException {
    try {
      final IProjectDescription description = getProject().getDescription();
      description.setName(newName);
      getProject().move(description, true, monitor.getNestedMonitor());
    } catch (CoreException e) {
      throw new DBException("Can't rename project", e);
    }
  }

  @Override
  protected DBNNode[] readChildNodes(DBRProgressMonitor monitor) throws DBException {
    if (!getProject().isOpen()) {
      try {
        getProject().open(monitor.getNestedMonitor());
        getProject().refreshLocal(IFile.DEPTH_ONE, monitor.getNestedMonitor());
      } catch (CoreException e) {
        throw new DBException("Can't open project '" + getProject().getName() + "'", e);
      }
    }
    DBPDataSourceRegistry dataSourceRegistry =
        getModel().getApplication().getProjectManager().getDataSourceRegistry(getProject());
    DBNNode[] children = super.readChildNodes(monitor);
    if (dataSourceRegistry != null) {
      children =
          ArrayUtils.add(
              DBNNode.class, children, new DBNProjectDatabases(this, dataSourceRegistry));
    }
    return children;
  }

  public DBNResource findResource(IResource resource) {
    List<IResource> path = new ArrayList<>();
    for (IResource parent = resource; !(parent instanceof IProject); parent = parent.getParent()) {
      path.add(0, parent);
    }

    DBNResource resNode = this;
    for (IResource res : path) {
      try {
        resNode.getChildren(VoidProgressMonitor.INSTANCE);
      } catch (DBException e) {
        log.error(e);
      }
      resNode = resNode.getChild(res);
      if (resNode == null) {
        return null;
      }
    }
    return resNode;
  }

  @Override
  protected void handleChildResourceChange(IResourceDelta delta) {
    final String name = delta.getResource().getName();
    if (name.startsWith(DBPDataSourceRegistry.CONFIG_FILE_PREFIX)
        && name.endsWith(DBPDataSourceRegistry.CONFIG_FILE_EXT)) {
      // DS registry configuration changed
      getDatabases().getDataSourceRegistry().refreshConfig();
    } else {
      super.handleChildResourceChange(delta);
    }
  }

  public void openProject() {
    final DBNProjectDatabases databases = getDatabases();
    if (databases != null) {
      databases.getDataSourceRegistry().refreshConfig();
    }
  }
}
/** Data pump for SQL queries */
class ResultSetDataReceiver implements DBDDataReceiver {

  static final Log log = Log.getLog(ResultSetDataReceiver.class);

  private ResultSetViewer resultSetViewer;
  private int columnsCount;
  private DBDAttributeBindingMeta[] metaColumns;
  private List<Object[]> rows = new ArrayList<>();
  private boolean hasMoreData;
  private boolean nextSegmentRead;
  private long offset;
  private long maxRows;

  private Map<DBCAttributeMetaData, List<DBCException>> errors = new HashMap<>();

  ResultSetDataReceiver(ResultSetViewer resultSetViewer) {
    this.resultSetViewer = resultSetViewer;
  }

  boolean isHasMoreData() {
    return hasMoreData;
  }

  void setHasMoreData(boolean hasMoreData) {
    this.hasMoreData = hasMoreData;
  }

  void setNextSegmentRead(boolean nextSegmentRead) {
    this.nextSegmentRead = nextSegmentRead;
  }

  @Override
  public void fetchStart(
      DBCSession session, final DBCResultSet resultSet, long offset, long maxRows)
      throws DBCException {
    this.rows.clear();
    this.offset = offset;
    this.maxRows = maxRows;

    if (!nextSegmentRead) {
      // Get columns metadata
      DBCResultSetMetaData metaData = resultSet.getMeta();

      List<DBCAttributeMetaData> rsAttributes = metaData.getAttributes();
      columnsCount = rsAttributes.size();

      // Extract column info
      metaColumns = new DBDAttributeBindingMeta[columnsCount];
      for (int i = 0; i < columnsCount; i++) {
        metaColumns[i] = DBUtils.getAttributeBinding(session, rsAttributes.get(i));
      }

      resultSetViewer.setMetaData(metaColumns);
    }
  }

  @Override
  public void fetchRow(DBCSession session, DBCResultSet resultSet) throws DBCException {
    Object[] row = new Object[columnsCount];
    for (int i = 0; i < columnsCount; i++) {
      try {
        row[i] =
            metaColumns[i]
                .getValueHandler()
                .fetchValueObject(
                    session,
                    resultSet,
                    metaColumns[i].getAttribute(),
                    metaColumns[i].getOrdinalPosition());
      } catch (DBCException e) {
        // Do not reports the same error multiple times
        // There are a lot of error could occur during result set fetch
        // We report certain error only once
        List<DBCException> errorList = errors.get(metaColumns[i].getMetaAttribute());
        if (errorList == null) {
          errorList = new ArrayList<>();
          errors.put(metaColumns[i].getMetaAttribute(), errorList);
        }
        if (!errorList.contains(e)) {
          log.warn("Can't read column '" + metaColumns[i].getName() + "' value", e);
          errorList.add(e);
        }
      }
    }
    rows.add(row);
  }

  @Override
  public void fetchEnd(DBCSession session, final DBCResultSet resultSet) throws DBCException {
    if (!nextSegmentRead) {
      // Read locators' metadata
      ResultSetUtils.bindAttributes(session, resultSet, metaColumns, rows);
    }

    final List<Object[]> tmpRows = rows;

    final boolean nextSegmentRead = this.nextSegmentRead;
    runInUI(
        new Runnable() {
          @Override
          public void run() {
            // Push data into viewer
            if (!nextSegmentRead) {
              resultSetViewer.updatePresentation(resultSet);
              resultSetViewer.setData(tmpRows);
            } else {
              resultSetViewer.appendData(tmpRows);
            }
            // Check for more data
            hasMoreData = maxRows > 0 && tmpRows.size() >= maxRows;
          }
        });
  }

  @Override
  public void close() {
    nextSegmentRead = false;

    errors.clear();
    rows = new ArrayList<>();
  }

  private void runInUI(Runnable runnable) {
    Control control = resultSetViewer.getControl();
    if (!control.isDisposed()) {
      control.getDisplay().asyncExec(runnable);
    }
  }
}
Exemple #11
0
public class CompileHandler extends AbstractHandler implements IElementUpdater {
  static final Log log = Log.getLog(CompileHandler.class);

  @Override
  public Object execute(ExecutionEvent event) throws ExecutionException {
    final List<OracleSourceObject> objects = getSelectedObjects(event);
    if (!objects.isEmpty()) {
      final Shell activeShell = HandlerUtil.getActiveShell(event);
      if (objects.size() == 1) {
        final OracleSourceObject unit = objects.get(0);

        DBCSourceHost sourceHost = null;
        final IWorkbenchPart activePart = HandlerUtil.getActiveEditor(event);
        if (activePart != null) {
          sourceHost = RuntimeUtils.getObjectAdapter(activePart, DBCSourceHost.class);
          if (sourceHost == null) {
            sourceHost = activePart.getAdapter(DBCSourceHost.class);
          }
        }
        if (sourceHost != null && sourceHost.getSourceObject() != unit) {
          sourceHost = null;
        }

        final DBCCompileLog compileLog =
            sourceHost == null ? new DBCCompileLogBase() : sourceHost.getCompileLog();
        compileLog.clearLog();
        Throwable error = null;
        try {
          DBeaverUI.runInProgressService(
              new DBRRunnableWithProgress() {
                @Override
                public void run(DBRProgressMonitor monitor)
                    throws InvocationTargetException, InterruptedException {
                  try {
                    compileUnit(monitor, compileLog, unit);
                  } catch (DBCException e) {
                    throw new InvocationTargetException(e);
                  }
                }
              });
          if (compileLog.getError() != null) {
            error = compileLog.getError();
          }
        } catch (InvocationTargetException e) {
          error = e.getTargetException();
        } catch (InterruptedException e) {
          return null;
        }
        if (error != null) {
          UIUtils.showErrorDialog(activeShell, "Unexpected compilation error", null, error);
        } else if (!CommonUtils.isEmpty(compileLog.getErrorStack())) {
          // Show compile errors
          int line = -1, position = -1;
          StringBuilder fullMessage = new StringBuilder();
          for (DBCCompileError oce : compileLog.getErrorStack()) {
            fullMessage.append(oce.toString()).append(GeneralUtils.getDefaultLineSeparator());
            if (line < 0) {
              line = oce.getLine();
              position = oce.getPosition();
            }
          }

          // If compiled object is currently open in editor - try to position on error line
          if (sourceHost != null
              && sourceHost.getSourceObject() == unit
              && line > 0
              && position > 0) {
            sourceHost.positionSource(line, position);
            activePart.getSite().getPage().activate(activePart);
          }

          String errorTitle = unit.getName() + " compilation failed";
          if (sourceHost != null) {
            sourceHost.setCompileInfo(errorTitle, true);
            sourceHost.showCompileLog();
          }
          UIUtils.showErrorDialog(activeShell, errorTitle, fullMessage.toString());
        } else {
          String message = unit.getName() + " compiled successfully";
          if (sourceHost != null) {
            sourceHost.setCompileInfo(message, true);
          }
          UIUtils.showMessageBox(activeShell, "Done", message, SWT.ICON_INFORMATION);
        }
      } else {
        OracleCompilerDialog dialog = new OracleCompilerDialog(activeShell, objects);
        dialog.open();
      }
    }
    return null;
  }

  private List<OracleSourceObject> getSelectedObjects(ExecutionEvent event) {
    List<OracleSourceObject> objects = new ArrayList<>();
    final ISelection currentSelection = HandlerUtil.getCurrentSelection(event);
    if (currentSelection instanceof IStructuredSelection && !currentSelection.isEmpty()) {
      for (Iterator<?> iter = ((IStructuredSelection) currentSelection).iterator();
          iter.hasNext(); ) {
        final Object element = iter.next();
        final OracleSourceObject sourceObject =
            RuntimeUtils.getObjectAdapter(element, OracleSourceObject.class);
        if (sourceObject != null) {
          objects.add(sourceObject);
        }
      }
    }
    if (objects.isEmpty()) {
      final IWorkbenchPart activePart = HandlerUtil.getActivePart(event);
      final OracleSourceObject sourceObject =
          RuntimeUtils.getObjectAdapter(activePart, OracleSourceObject.class);
      if (sourceObject != null) {
        objects.add(sourceObject);
      }
    }
    return objects;
  }

  @Override
  public void updateElement(UIElement element, Map parameters) {
    List<OracleSourceObject> objects = new ArrayList<>();
    IWorkbenchPartSite partSite = UIUtils.getWorkbenchPartSite(element.getServiceLocator());
    if (partSite != null) {
      final ISelectionProvider selectionProvider = partSite.getSelectionProvider();
      if (selectionProvider != null) {
        ISelection selection = selectionProvider.getSelection();
        if (selection instanceof IStructuredSelection && !selection.isEmpty()) {
          for (Iterator<?> iter = ((IStructuredSelection) selection).iterator(); iter.hasNext(); ) {
            final Object item = iter.next();
            final OracleSourceObject sourceObject =
                RuntimeUtils.getObjectAdapter(item, OracleSourceObject.class);
            if (sourceObject != null) {
              objects.add(sourceObject);
            }
          }
        }
      }
      if (objects.isEmpty()) {
        final IWorkbenchPart activePart = partSite.getPart();
        final OracleSourceObject sourceObject =
            RuntimeUtils.getObjectAdapter(activePart, OracleSourceObject.class);
        if (sourceObject != null) {
          objects.add(sourceObject);
        }
      }
    }
    if (!objects.isEmpty()) {
      if (objects.size() > 1) {
        element.setText("Compile " + objects.size() + " objects");
      } else {
        final OracleSourceObject sourceObject = objects.get(0);
        String objectType = TextUtils.formatWord(sourceObject.getSourceType().name());
        element.setText("Compile " + objectType /* + " '" + sourceObject.getName() + "'"*/);
      }
    }
  }

  public static boolean compileUnit(
      DBRProgressMonitor monitor, DBCCompileLog compileLog, OracleSourceObject unit)
      throws DBCException {
    final DBEPersistAction[] compileActions = unit.getCompileActions();
    if (ArrayUtils.isEmpty(compileActions)) {
      return true;
    }

    try (JDBCSession session =
        DBUtils.openUtilSession(
            monitor, unit.getDataSource(), "Compile '" + unit.getName() + "'")) {
      boolean success = true;
      for (DBEPersistAction action : compileActions) {
        final String script = action.getScript();
        compileLog.trace(script);

        if (monitor.isCanceled()) {
          break;
        }
        try {
          try (DBCStatement dbStat =
              session.prepareStatement(DBCStatementType.QUERY, script, false, false, false)) {
            dbStat.executeStatement();
          }
          action.handleExecute(null);
        } catch (DBCException e) {
          action.handleExecute(e);
          throw e;
        }
        if (action instanceof OracleObjectPersistAction) {
          if (!logObjectErrors(
              session, compileLog, unit, ((OracleObjectPersistAction) action).getObjectType())) {
            success = false;
          }
        }
      }
      final DBSObjectState oldState = unit.getObjectState();
      unit.refreshObjectState(monitor);
      if (unit.getObjectState() != oldState) {
        unit.getDataSource()
            .getContainer()
            .fireEvent(new DBPEvent(DBPEvent.Action.OBJECT_UPDATE, unit));
      }

      return success;
    }
  }

  public static boolean logObjectErrors(
      JDBCSession session,
      DBCCompileLog compileLog,
      OracleSourceObject unit,
      OracleObjectType objectType) {
    try {
      try (JDBCPreparedStatement dbStat =
          session.prepareStatement(
              "SELECT * FROM SYS.ALL_ERRORS WHERE OWNER=? AND NAME=? AND TYPE=? ORDER BY SEQUENCE")) {
        dbStat.setString(1, unit.getSchema().getName());
        dbStat.setString(2, unit.getName());
        dbStat.setString(3, objectType.getTypeName());
        try (ResultSet dbResult = dbStat.executeQuery()) {
          boolean hasErrors = false;
          while (dbResult.next()) {
            DBCCompileError error =
                new DBCCompileError(
                    "ERROR".equals(dbResult.getString("ATTRIBUTE")),
                    dbResult.getString("TEXT"),
                    dbResult.getInt("LINE"),
                    dbResult.getInt("POSITION"));
            hasErrors = true;
            if (error.isError()) {
              compileLog.error(error);
            } else {
              compileLog.warn(error);
            }
          }
          return !hasErrors;
        }
      }
    } catch (Exception e) {
      log.error("Can't read user errors", e);
      return false;
    }
  }
}
Exemple #12
0
/**
 * SQLQueryJob
 *
 * @author Serge Rider
 */
public class SQLQueryJob extends DataSourceJob {
  static final Log log = Log.getLog(SQLQueryJob.class);

  public static final Object STATS_RESULTS = new Object();

  private final DBSDataContainer dataContainer;
  private final List<SQLQuery> queries;
  private final SQLResultsConsumer resultsConsumer;
  private final SQLQueryListener listener;
  private final IWorkbenchPartSite partSite;

  private DBDDataFilter dataFilter;
  private boolean connectionInvalidated = false;

  private SQLScriptCommitType commitType;
  private SQLScriptErrorHandling errorHandling;
  private boolean fetchResultSets;
  private long rsOffset;
  private long rsMaxRows;

  private DBCStatement curStatement;
  private final List<DBCResultSet> curResultSets = new ArrayList<>();
  private Throwable lastError = null;

  private DBCStatistics statistics;
  private int fetchResultSetNumber;
  private int resultSetNumber;
  private SQLQuery lastGoodQuery;

  public SQLQueryJob(
      @NotNull IWorkbenchPartSite partSite,
      @NotNull String name,
      @NotNull DBCExecutionContext executionContext,
      @NotNull DBSDataContainer dataContainer,
      @NotNull List<SQLQuery> queries,
      @NotNull SQLResultsConsumer resultsConsumer,
      @Nullable SQLQueryListener listener) {
    super(name, DBeaverIcons.getImageDescriptor(UIIcon.SQL_SCRIPT_EXECUTE), executionContext);
    this.dataContainer = dataContainer;
    this.partSite = partSite;
    this.queries = queries;
    this.resultsConsumer = resultsConsumer;
    this.listener = listener;

    {
      // Read config form preference store
      DBPPreferenceStore preferenceStore = getDataSourceContainer().getPreferenceStore();
      this.commitType =
          SQLScriptCommitType.valueOf(
              preferenceStore.getString(DBeaverPreferences.SCRIPT_COMMIT_TYPE));
      this.errorHandling =
          SQLScriptErrorHandling.valueOf(
              preferenceStore.getString(DBeaverPreferences.SCRIPT_ERROR_HANDLING));
      this.fetchResultSets =
          queries.size() == 1
              || preferenceStore.getBoolean(DBeaverPreferences.SCRIPT_FETCH_RESULT_SETS);
      this.rsMaxRows = preferenceStore.getInt(DBeaverPreferences.RESULT_SET_MAX_ROWS);
    }
  }

  public void setFetchResultSets(boolean fetchResultSets) {
    this.fetchResultSets = fetchResultSets;
  }

  public SQLQuery getLastQuery() {
    return queries.isEmpty() ? null : queries.get(0);
  }

  public SQLQuery getLastGoodQuery() {
    return lastGoodQuery;
  }

  public boolean hasLimits() {
    return rsOffset >= 0 && rsMaxRows > 0;
  }

  public void setResultSetLimit(long offset, long maxRows) {
    this.rsOffset = offset;
    this.rsMaxRows = maxRows;
  }

  @Override
  protected IStatus run(DBRProgressMonitor monitor) {
    RuntimeUtils.setThreadName("SQL script execution");
    statistics = new DBCStatistics();
    try {
      DBCExecutionContext context = getExecutionContext();
      DBCTransactionManager txnManager = DBUtils.getTransactionManager(context);
      DBCExecutionPurpose purpose =
          queries.size() > 1 ? DBCExecutionPurpose.USER_SCRIPT : DBCExecutionPurpose.USER;
      try (DBCSession session = context.openSession(monitor, purpose, "SQL Query")) {
        // Set transaction settings (only if autocommit is off)
        QMUtils.getDefaultHandler().handleScriptBegin(session);

        boolean oldAutoCommit = txnManager == null || txnManager.isAutoCommit();
        boolean newAutoCommit = (commitType == SQLScriptCommitType.AUTOCOMMIT);
        if (txnManager != null && !oldAutoCommit && newAutoCommit) {
          txnManager.setAutoCommit(monitor, true);
        }

        monitor.beginTask(this.getName(), queries.size());

        // Notify job start
        if (listener != null) {
          listener.onStartScript();
        }

        resultSetNumber = 0;
        for (int queryNum = 0; queryNum < queries.size(); ) {
          // Execute query
          SQLQuery query = queries.get(queryNum);

          fetchResultSetNumber = resultSetNumber;
          boolean runNext = executeSingleQuery(session, query, true);
          if (!runNext) {
            // Ask to continue
            if (lastError != null) {
              log.error(lastError);
            }
            boolean isQueue = queryNum < queries.size() - 1;
            ExecutionQueueErrorResponse response =
                ExecutionQueueErrorJob.showError(
                    isQueue ? "SQL script execution" : "SQL query execution", lastError, isQueue);

            boolean stopScript = false;
            switch (response) {
              case STOP:
                // just stop execution
                stopScript = true;
                break;
              case RETRY:
                // just make it again
                continue;
              case IGNORE:
                // Just do nothing
                break;
              case IGNORE_ALL:
                errorHandling = SQLScriptErrorHandling.IGNORE;
                break;
            }

            if (stopScript) {
              break;
            }
          }

          // Check monitor
          if (monitor.isCanceled()) {
            break;
          }
          monitor.worked(1);
          queryNum++;
        }
        showExecutionResult(session);
        monitor.done();

        // Commit data
        if (txnManager != null && !oldAutoCommit && commitType != SQLScriptCommitType.AUTOCOMMIT) {
          if (lastError == null || errorHandling == SQLScriptErrorHandling.STOP_COMMIT) {
            if (commitType != SQLScriptCommitType.NO_COMMIT) {
              monitor.beginTask("Commit data", 1);
              txnManager.commit(session);
              monitor.done();
            }
          } else {
            monitor.beginTask("Rollback data", 1);
            txnManager.rollback(session, null);
            monitor.done();
          }
        }

        // Restore transactions settings
        if (txnManager != null && !oldAutoCommit && newAutoCommit) {
          txnManager.setAutoCommit(monitor, false);
        }

        QMUtils.getDefaultHandler().handleScriptEnd(session);

        // Return success
        return new Status(Status.OK, DBeaverCore.getCorePluginID(), "SQL job completed");
      }
    } catch (Throwable ex) {
      return new Status(
          Status.ERROR,
          DBeaverCore.getCorePluginID(),
          "Error during SQL job execution: " + ex.getMessage());
    } finally {
      // Notify job end
      if (listener != null) {
        listener.onEndScript(statistics, lastError != null);
      }
    }
  }

  private boolean executeSingleQuery(
      @NotNull DBCSession session, @NotNull SQLQuery sqlQuery, boolean fireEvents) {
    lastError = null;

    final String originalQueryText = sqlQuery.getQuery();
    DBCExecutionContext executionContext = getExecutionContext();
    SQLQueryResult curResult = new SQLQueryResult(sqlQuery);
    if (rsOffset > 0) {
      curResult.setRowOffset(rsOffset);
    }
    SQLQuery originalQuery = sqlQuery;
    long startTime = System.currentTimeMillis();

    if (fireEvents && listener != null) {
      // Notify query start
      listener.onStartQuery(sqlQuery);
    }

    try {
      // Prepare statement
      closeStatement();

      // Check and invalidate connection
      DBPDataSource dataSource = executionContext.getDataSource();
      if (!connectionInvalidated
          && dataSource
              .getContainer()
              .getPreferenceStore()
              .getBoolean(DBeaverPreferences.STATEMENT_INVALIDATE_BEFORE_EXECUTE)) {
        executionContext.invalidateContext(session.getProgressMonitor());
        connectionInvalidated = true;
      }

      try {
        // Modify query (filters + parameters)
        if (dataFilter != null && dataFilter.hasFilters() && dataSource instanceof SQLDataSource) {
          String filteredQueryText =
              ((SQLDataSource) dataSource)
                  .getSQLDialect()
                  .addFiltersToQuery(dataSource, originalQueryText, dataFilter);
          sqlQuery = new SQLQuery(filteredQueryText, sqlQuery.getOffset(), sqlQuery.getLength());
        }
      } catch (DBException e) {
        throw new DBCException("Can't apply query filter", e);
      }

      Boolean hasParameters = prepareStatementParameters(sqlQuery);
      if (hasParameters == null) {
        return false;
      }

      statistics.setQueryText(originalQueryText);

      startTime = System.currentTimeMillis();
      DBCExecutionSource source =
          new AbstractExecutionSource(
              dataContainer, executionContext, partSite.getPart(), sqlQuery);
      curStatement =
          DBUtils.prepareStatement(
              source,
              session,
              hasParameters ? DBCStatementType.QUERY : DBCStatementType.SCRIPT,
              sqlQuery,
              rsOffset,
              rsMaxRows);

      if (hasParameters) {
        bindStatementParameters(session, sqlQuery);
      }

      // Execute statement
      try {
        boolean hasResultSet = curStatement.executeStatement();
        curResult.setHasResultSet(hasResultSet);
        statistics.addExecuteTime(System.currentTimeMillis() - startTime);
        statistics.addStatementsCount();

        long updateCount = -1;
        while (hasResultSet || resultSetNumber == 0 || updateCount >= 0) {
          // Fetch data only if we have to fetch all results or if it is rs requested
          if (fetchResultSetNumber < 0 || fetchResultSetNumber == resultSetNumber) {
            if (hasResultSet && fetchResultSets) {
              DBDDataReceiver dataReceiver =
                  resultsConsumer.getDataReceiver(sqlQuery, resultSetNumber);
              if (dataReceiver != null) {
                hasResultSet =
                    fetchQueryData(
                        session, curStatement.openResultSet(), curResult, dataReceiver, true);
              }
            }
          }
          if (!hasResultSet) {
            try {
              updateCount = curStatement.getUpdateRowCount();
              if (updateCount >= 0) {
                curResult.setUpdateCount(updateCount);
                statistics.addRowsUpdated(updateCount);
              }
            } catch (DBCException e) {
              // In some cases we can't read update count
              // This is bad but we can live with it
              // Just print a warning
              log.warn("Can't obtain update count", e);
            }
          }
          if (hasResultSet && fetchResultSets) {
            resultSetNumber++;
            fetchResultSetNumber = resultSetNumber;
          }
          if (!hasResultSet && updateCount < 0) {
            // Nothing else to fetch
            break;
          }

          if (dataSource.getInfo().supportsMultipleResults()) {
            hasResultSet = curStatement.nextResults();
            updateCount = hasResultSet ? -1 : 0;
          } else {
            break;
          }
        }

        try {
          curResult.setWarnings(curStatement.getStatementWarnings());
        } catch (Throwable e) {
          log.warn("Can't read execution warnings", e);
        }
      } finally {
        // monitor.subTask("Close query");
        if (!keepStatementOpen()) {
          closeStatement();
        }

        // Release parameters
        releaseStatementParameters(sqlQuery);
      }
    } catch (Throwable ex) {
      if (!(ex instanceof DBException)) {
        log.error("Unexpected error while processing SQL", ex);
      }
      curResult.setError(ex);
      lastError = ex;
    } finally {
      curResult.setQueryTime(System.currentTimeMillis() - startTime);

      if (fireEvents && listener != null) {
        // Notify query end
        listener.onEndQuery(curResult);
      }
    }

    if (curResult.getError() != null && errorHandling != SQLScriptErrorHandling.IGNORE) {
      return false;
    }
    // Success
    lastGoodQuery = originalQuery;
    return true;
  }

  private void showExecutionResult(DBCSession session) throws DBCException {
    if (statistics.getStatementsCount() > 1 || resultSetNumber == 0) {
      SQLQuery query = new SQLQuery("", -1, -1);
      if (queries.size() == 1) {
        query.setQuery(queries.get(0).getQuery());
      }
      query.setData(STATS_RESULTS); // It will set tab name to "Stats"
      DBDDataReceiver dataReceiver = resultsConsumer.getDataReceiver(query, resultSetNumber);
      if (dataReceiver != null) {
        fetchExecutionResult(session, dataReceiver, query);
      }
    }
  }

  private void fetchExecutionResult(
      @NotNull DBCSession session, @NotNull DBDDataReceiver dataReceiver, @NotNull SQLQuery query)
      throws DBCException {
    // Fetch fake result set
    // DBCStatement statsStatement;
    StatResultSet fakeResultSet = new StatResultSet(session, curStatement);
    SQLQueryResult resultInfo = new SQLQueryResult(query);
    if (statistics.getStatementsCount() > 1) {
      // Multiple statements - show script statistics
      fakeResultSet.addColumn("Queries", DBPDataKind.NUMERIC);
      fakeResultSet.addColumn("Updated Rows", DBPDataKind.NUMERIC);
      fakeResultSet.addColumn("Execute time", DBPDataKind.NUMERIC);
      fakeResultSet.addColumn("Fetch time", DBPDataKind.NUMERIC);
      fakeResultSet.addColumn("Total time", DBPDataKind.NUMERIC);
      fakeResultSet.addRow(
          statistics.getStatementsCount(),
          statistics.getRowsUpdated(),
          statistics.getExecuteTime(),
          statistics.getFetchTime(),
          statistics.getTotalTime());
      resultInfo.setResultSetName("Statistics");
    } else {
      // Single statement
      long updateCount = statistics.getRowsUpdated();
      if (updateCount >= 0) {
        fakeResultSet.addColumn("Query", DBPDataKind.STRING);
        fakeResultSet.addColumn("Updated Rows", DBPDataKind.NUMERIC);
        fakeResultSet.addRow(query.getQuery(), updateCount);
      } else {
        fakeResultSet.addColumn("Result", DBPDataKind.NUMERIC);
      }
      resultInfo.setResultSetName("Result");
    }
    fetchQueryData(session, fakeResultSet, resultInfo, dataReceiver, false);
  }

  private Boolean prepareStatementParameters(SQLQuery sqlStatement) {
    // Bind parameters
    if (!CommonUtils.isEmpty(sqlStatement.getParameters())) {
      List<SQLQueryParameter> unresolvedParams = new ArrayList<>();
      for (SQLQueryParameter param : sqlStatement.getParameters()) {
        if (!param.isResolved()) {
          unresolvedParams.add(param);
        }
      }
      if (!CommonUtils.isEmpty(unresolvedParams)) {
        // Resolve parameters
        if (!fillStatementParameters(unresolvedParams)) {
          return null;
        }
      }
      // Set values for all parameters
      return true;
    }
    return false;
  }

  private boolean fillStatementParameters(final List<SQLQueryParameter> parameters) {
    final RunnableWithResult<Boolean> binder =
        new RunnableWithResult<Boolean>() {
          @Override
          public void run() {
            SQLQueryParameterBindDialog dialog =
                new SQLQueryParameterBindDialog(partSite, getExecutionContext(), parameters);
            result = (dialog.open() == IDialogConstants.OK_ID);
          }
        };
    UIUtils.runInUI(partSite.getShell(), binder);
    Boolean result = binder.getResult();
    return result != null && result;
  }

  private void bindStatementParameters(DBCSession session, SQLQuery sqlStatement)
      throws DBCException {
    // Bind them
    for (SQLQueryParameter param : sqlStatement.getParameters()) {
      if (param.isResolved()) {
        // convert value to native form
        Object realValue =
            param.getValueHandler().getValueFromObject(session, param, param.getValue(), false);
        // bind
        param
            .getValueHandler()
            .bindValueObject(session, curStatement, param, param.getOrdinalPosition(), realValue);
      }
    }
  }

  private void releaseStatementParameters(SQLQuery sqlStatement) {
    if (!CommonUtils.isEmpty(sqlStatement.getParameters())) {
      for (SQLQueryParameter param : sqlStatement.getParameters()) {
        if (param.isResolved()) {
          param.getValueHandler().releaseValueObject(param.getValue());
        }
      }
    }
  }

  private boolean fetchQueryData(
      DBCSession session,
      DBCResultSet resultSet,
      SQLQueryResult result,
      DBDDataReceiver dataReceiver,
      boolean updateStatistics)
      throws DBCException {
    if (dataReceiver == null) {
      // No data pump - skip fetching stage
      return false;
    }
    if (resultSet == null) {
      return false;
    }
    boolean keepCursor = keepStatementOpen();

    if (keepCursor) {
      curResultSets.add(resultSet);
    }
    DBRProgressMonitor monitor = session.getProgressMonitor();
    monitor.subTask("Fetch result set");
    long rowCount = 0;

    dataReceiver.fetchStart(session, resultSet, rsOffset, rsMaxRows);

    try {
      // Retrieve source entity
      if (result != null) {
        DBCResultSetMetaData rsMeta = resultSet.getMeta();
        String sourceName = null; // resultSet.getResultSetName();
        for (DBCAttributeMetaData attr : rsMeta.getAttributes()) {
          String entityName = attr.getEntityName();
          if (!CommonUtils.isEmpty(entityName)) {
            if (sourceName == null) {
              sourceName = entityName;
            } else if (!sourceName.equals(entityName)) {
              // Multiple source entities
              sourceName += "(+)";
              break;
            }
          }
        }
        /*
                        if (CommonUtils.isEmpty(sourceName)) {
                            try {
                                sourceName = resultSet.getResultSetName();
                            } catch (DBCException e) {
                                log.debug(e);
                            }
                        }
        */
        if (CommonUtils.isEmpty(sourceName)) {
          sourceName = "Result";
        }
        result.setResultSetName(sourceName);
      }
      long fetchStartTime = System.currentTimeMillis();

      // Fetch all rows
      while ((!hasLimits() || rowCount < rsMaxRows) && resultSet.nextRow()) {
        if (monitor.isCanceled()) {
          break;
        }
        rowCount++;

        if (rowCount > 0 && rowCount % 100 == 0) {
          monitor.subTask(rowCount + " rows fetched");
          monitor.worked(100);
        }

        dataReceiver.fetchRow(session, resultSet);
      }
      if (updateStatistics) {
        statistics.addFetchTime(System.currentTimeMillis() - fetchStartTime);
      }
    } finally {
      if (!keepCursor) {
        try {
          resultSet.close();
        } catch (Throwable e) {
          log.error("Error while closing resultset", e);
        }
      }
      try {
        dataReceiver.fetchEnd(session, resultSet);
      } catch (Throwable e) {
        log.error("Error while handling end of result set fetch", e);
      }
      dataReceiver.close();
    }

    if (result != null) {
      result.setRowCount(rowCount);
    }
    if (updateStatistics) {
      statistics.setRowsFetched(rowCount);
    }
    monitor.subTask(rowCount + " rows fetched");

    return true;
  }

  private boolean keepStatementOpen() {
    // Only in single query mode and if pref option set to true
    return queries.size() == 1
        && getDataSourceContainer()
            .getPreferenceStore()
            .getBoolean(DBeaverPreferences.KEEP_STATEMENT_OPEN);
  }

  private void closeStatement() {
    if (curStatement != null) {
      for (DBCResultSet resultSet : curResultSets) {
        resultSet.close();
      }
      curResultSets.clear();

      try {
        curStatement.close();
      } catch (Throwable e) {
        log.error("Error closing statement", e);
      }
      curStatement = null;
    }
  }

  /*
  protected void canceling()
  {
      // Cancel statement only for the second time cancel is called
      */
  /*if (!statementCancel) {
      statementCancel = true;
  } else */
  /*

          {
              if (!statementCanceled && curStatement != null) {
                  try {
                      curStatement.cancelBlock();
                  } catch (DBException e) {
                      log.error("Can't cancel execution: " + e.getMessage());
                  }
                  statementCanceled = true;
              }
          }
      }
  */

  public void extractData(DBCSession session) throws DBCException {
    statistics = new DBCStatistics();
    if (queries.size() != 1) {
      throw new DBCException("Invalid state of SQL Query job");
    }
    resultSetNumber = 0;
    SQLQuery query = queries.get(0);
    session.getProgressMonitor().beginTask(query.getQuery(), 1);
    try {
      boolean result = executeSingleQuery(session, query, true);
      if (!result && lastError != null) {
        if (lastError instanceof DBCException) {
          throw (DBCException) lastError;
        } else {
          throw new DBCException(lastError, getExecutionContext().getDataSource());
        }
      } else if (result) {
        showExecutionResult(session);
      }
    } finally {
      session.getProgressMonitor().done();
    }
  }

  public void setDataFilter(DBDDataFilter dataFilter) {
    this.dataFilter = dataFilter;
  }

  public DBCStatistics getStatistics() {
    return statistics;
  }

  public void setFetchResultSetNumber(int fetchResultSetNumber) {
    this.fetchResultSetNumber = fetchResultSetNumber;
  }
}
public abstract class AbstractSearchPage extends DialogPage implements IObjectSearchPage {

  protected static final Log log = Log.getLog(AbstractSearchPage.class);

  protected IObjectSearchContainer container;

  protected AbstractSearchPage(String title) {
    super(title);
  }

  @Override
  public void setSearchContainer(IObjectSearchContainer container) {
    this.container = container;
  }

  @Override
  public void setVisible(boolean visible) {
    super.setVisible(visible);
    if (visible) {
      updateEnablement();
    }
  }

  protected abstract void updateEnablement();

  protected static List<DBNNode> loadTreeState(DBPPreferenceStore store, String propName) {
    final List<DBNNode> result = new ArrayList<>();
    final String sources = store.getString(propName);
    if (!CommonUtils.isEmpty(sources)) {
      try {
        DBeaverUI.runInProgressService(
            new DBRRunnableWithProgress() {
              @Override
              public void run(DBRProgressMonitor monitor) {
                // Keep broken datasources to make connect attempt only once
                Set<DBNDataSource> brokenDataSources = new HashSet<>();

                // Find all nodes
                StringTokenizer st = new StringTokenizer(sources, "|"); // $NON-NLS-1$
                while (st.hasMoreTokens()) {
                  String nodePath = st.nextToken();
                  try {
                    DBNDataSource dsNode =
                        DBeaverCore.getInstance().getNavigatorModel().getDataSourceByPath(nodePath);
                    if (brokenDataSources.contains(dsNode)) {
                      continue;
                    }

                    DBNNode node =
                        DBeaverCore.getInstance()
                            .getNavigatorModel()
                            .getNodeByPath(monitor, nodePath);
                    if (node != null) {
                      result.add(node);
                    } else {
                      brokenDataSources.add(dsNode);
                    }
                  } catch (DBException e) {
                    log.error(e);
                  }
                }
              }
            });
      } catch (InvocationTargetException e) {
        log.error(e.getTargetException());
      } catch (InterruptedException e) {
        // ignore
      }
    }
    return result;
  }
}
/** Abstract connection wizard */
public abstract class ConnectionWizard extends Wizard implements INewWizard {
  private static final Log log = Log.getLog(ConnectionWizard.class);

  // protected final IProject project;
  private final Map<DriverDescriptor, DataSourceDescriptor> infoMap = new HashMap<>();
  private boolean resized = false;

  protected ConnectionWizard() {
    setNeedsProgressMonitor(true);
  }

  @Override
  public void dispose() {
    // Dispose all temp data sources
    for (DataSourceDescriptor dataSource : infoMap.values()) {
      dataSource.dispose();
    }
    super.dispose();
  }

  public abstract DBPDataSourceRegistry getDataSourceRegistry();

  abstract DriverDescriptor getSelectedDriver();

  public abstract ConnectionPageSettings getPageSettings();

  protected abstract void saveSettings(DataSourceDescriptor dataSource);

  @NotNull
  public DataSourceDescriptor getActiveDataSource() {
    DriverDescriptor driver = getSelectedDriver();
    DataSourceDescriptor info = infoMap.get(driver);
    if (info == null) {
      DBPConnectionConfiguration connectionInfo = new DBPConnectionConfiguration();
      info =
          new DataSourceDescriptor(
              getDataSourceRegistry(),
              DataSourceDescriptor.generateNewId(getSelectedDriver()),
              getSelectedDriver(),
              connectionInfo);
      info.getConnectionConfiguration().setClientHomeId(driver.getDefaultClientHomeId());
      infoMap.put(driver, info);
    }
    return info;
  }

  public void testConnection() {
    DataSourceDescriptor dataSource = getPageSettings().getActiveDataSource();
    DataSourceDescriptor testDataSource =
        new DataSourceDescriptor(
            getDataSourceRegistry(),
            dataSource.getId(),
            getSelectedDriver(),
            new DBPConnectionConfiguration(dataSource.getConnectionConfiguration()));
    try {
      saveSettings(testDataSource);

      final ConnectionTester op = new ConnectionTester(testDataSource);

      try {
        getContainer()
            .run(
                true,
                true,
                new IRunnableWithProgress() {
                  @Override
                  public void run(IProgressMonitor monitor)
                      throws InvocationTargetException, InterruptedException {
                    // Wait for job to finish
                    op.ownerMonitor = RuntimeUtils.makeMonitor(monitor);
                    op.schedule();
                    while (op.getState() == Job.WAITING || op.getState() == Job.RUNNING) {
                      if (monitor.isCanceled()) {
                        op.cancel();
                        throw new InterruptedException();
                      }
                      try {
                        Thread.sleep(50);
                      } catch (InterruptedException e) {
                        break;
                      }
                    }
                    if (op.getConnectError() != null) {
                      throw new InvocationTargetException(op.getConnectError());
                    }
                  }
                });

        String message = "";
        if (!CommonUtils.isEmpty(op.productName)) {
          message += "Server: " + op.productName + " " + op.productVersion + "\n";
        }
        if (!CommonUtils.isEmpty(op.driverName)) {
          message += "Driver: " + op.driverName + " " + op.driverVersion + "\n";
        }
        if (!CommonUtils.isEmpty(message)) {
          message += "\n";
        }
        message +=
            NLS.bind(
                CoreMessages.dialog_connection_wizard_start_connection_monitor_connected,
                op.connectTime);

        MessageDialog.openInformation(
            getShell(),
            CoreMessages.dialog_connection_wizard_start_connection_monitor_success,
            message);
      } catch (InterruptedException ex) {
        UIUtils.showErrorDialog(
            getShell(),
            CoreMessages.dialog_connection_wizard_start_dialog_interrupted_title,
            CoreMessages.dialog_connection_wizard_start_dialog_interrupted_message);
      } catch (InvocationTargetException ex) {
        UIUtils.showErrorDialog(
            getShell(),
            CoreMessages.dialog_connection_wizard_start_dialog_error_title,
            null,
            GeneralUtils.makeExceptionStatus(ex.getTargetException()));
      }
    } finally {
      testDataSource.dispose();
    }
  }

  public boolean isNew() {
    return false;
  }

  public void resizeShell() {
    if (!resized) {
      Shell shell = getContainer().getShell();
      Point shellSize = shell.getSize();
      Point compSize = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT);
      if (shellSize.y < compSize.y) {
        shell.setSize(compSize);
        shell.layout(true);
      }
      resized = true;
    }
  }

  private class ConnectionTester extends ConnectJob {
    String productName;
    String productVersion;
    String driverName;
    String driverVersion;
    long connectTime = -1;
    DBRProgressMonitor ownerMonitor;

    public ConnectionTester(DataSourceDescriptor testDataSource) {
      super(testDataSource);
      setSystem(true);
      super.initialize =
          true; // CommonUtils.toBoolean(testDataSource.getDriver().getDriverParameter(DBConstants.PARAM_INIT_ON_TEST));
      productName = null;
      productVersion = null;
    }

    @Override
    public IStatus run(DBRProgressMonitor monitor) {
      if (ownerMonitor != null) {
        monitor = ownerMonitor;
      }
      monitor.beginTask(CoreMessages.dialog_connection_wizard_start_connection_monitor_start, 4);
      Thread.currentThread()
          .setName(CoreMessages.dialog_connection_wizard_start_connection_monitor_thread);

      try {
        container.setName(container.getConnectionConfiguration().getUrl());
        monitor.worked(1);
        long startTime = System.currentTimeMillis();
        super.run(monitor);
        connectTime = (System.currentTimeMillis() - startTime);
        if (connectError != null || monitor.isCanceled()) {
          return Status.OK_STATUS;
        }

        monitor.worked(1);
        DBPDataSource dataSource = container.getDataSource();
        if (dataSource == null) {
          throw new DBException(CoreMessages.editors_sql_status_not_connected_to_database);
        }
        //                monitor.subTask("Initialize connection");
        //                dataSource.initialize(monitor);
        //                monitor.worked(1);
        monitor.subTask(
            CoreMessages.dialog_connection_wizard_start_connection_monitor_subtask_test);

        DBPDataSourceInfo info = dataSource.getInfo();
        if (info != null) {
          try {
            productName = info.getDatabaseProductName();
            productVersion = info.getDatabaseProductVersion();
            driverName = info.getDriverName();
            driverVersion = info.getDriverVersion();
          } catch (Exception e) {
            log.error("Can't obtain connection metadata", e);
          }
        } else {
          try (DBCSession session =
              DBUtils.openUtilSession(monitor, dataSource, "Test connection")) {
            if (session instanceof Connection) {
              try {
                Connection connection = (Connection) session;
                DatabaseMetaData metaData = connection.getMetaData();
                productName = metaData.getDatabaseProductName();
                productVersion = metaData.getDatabaseProductVersion();
                driverName = metaData.getDriverName();
                driverVersion = metaData.getDriverVersion();
              } catch (Exception e) {
                log.error("Can't obtain connection metadata", e);
              }
            }
          }
        }
        new DisconnectJob(container).schedule();
        monitor.subTask(CoreMessages.dialog_connection_wizard_start_connection_monitor_success);
      } catch (DBException ex) {
        connectError = ex;
      }
      monitor.done();
      return Status.OK_STATUS;
    }
  }
}
Exemple #15
0
public class LoadingJob<RESULT> extends AbstractJob {

  private static final Log log = Log.getLog(LoadingJob.class);

  public static final Object LOADING_FAMILY = new Object();

  public static <RESULT> LoadingJob<RESULT> createService(
      ILoadService<RESULT> loadingService, ILoadVisualizer<RESULT> visualizer) {
    return new LoadingJob<RESULT>(loadingService, visualizer);
  }

  private ILoadService<RESULT> loadingService;
  private ILoadVisualizer<RESULT> visualizer;

  public LoadingJob(ILoadService<RESULT> loadingService, ILoadVisualizer<RESULT> visualizer) {
    super(loadingService.getServiceName());
    this.loadingService = loadingService;
    this.visualizer = visualizer;
    setUser(false);
  }

  public ILoadService<RESULT> getLoadingService() {
    return loadingService;
  }

  public ILoadVisualizer<RESULT> getVisualizer() {
    return visualizer;
  }

  @Override
  protected IStatus run(DBRProgressMonitor monitor) {
    return run(monitor, true);
  }

  private IStatus run(DBRProgressMonitor monitor, boolean lazy) {
    monitor = visualizer.overwriteMonitor(monitor);

    LoadingUIJob<RESULT> updateUIJob = new LoadingUIJob<>(this, monitor);
    updateUIJob.schedule();
    this.loadingService.setProgressMonitor(monitor);
    Throwable error = null;
    RESULT result = null;
    try {
      result = this.loadingService.evaluate();
    } catch (InvocationTargetException e) {
      //            log.error(e.getTargetException());
      error = e.getTargetException();
    } catch (InterruptedException e) {
      return new Status(Status.CANCEL, DBeaverCore.PLUGIN_ID, "Loading interrupted");
    } finally {
      UIUtils.runInUI(null, new LoadFinisher(result, error));
    }
    return Status.OK_STATUS;
  }

  @Override
  public boolean belongsTo(Object family) {
    return family == loadingService.getFamily();
  }

  public void syncRun() {
    run(VoidProgressMonitor.INSTANCE, false);
  }

  private class LoadFinisher implements Runnable {
    private final RESULT innerResult;
    private final Throwable innerError;

    public LoadFinisher(RESULT innerResult, Throwable innerError) {
      this.innerResult = innerResult;
      this.innerError = innerError;
    }

    @Override
    public void run() {
      visualizer.completeLoading(innerResult);

      if (innerError != null) {
        log.debug(innerError);
        UIUtils.showErrorDialog(null, getName(), null, innerError);
      }
    }
  }

  static class LoadingUIJob<RESULT> extends AbstractUIJob {
    private static final Log log = Log.getLog(LoadingUIJob.class);

    private static final long DELAY = 200;

    private ILoadService<RESULT> loadService;
    private ILoadVisualizer<RESULT> visualizer;
    private DBRProgressMonitor mainMonitor;

    LoadingUIJob(LoadingJob<RESULT> loadingJob, DBRProgressMonitor mainMonitor) {
      super(loadingJob.getName());
      this.loadService = loadingJob.getLoadingService();
      this.visualizer = loadingJob.getVisualizer();
      this.mainMonitor = mainMonitor;
      setSystem(true);
    }

    @Override
    public IStatus runInUIThread(DBRProgressMonitor monitor) {
      /*
              if (mainMonitor.isCanceled()) {
                  // Try to cancel current load service
                  try {
                      loadService.cancel();
                  }
                  catch (InvocationTargetException e) {
                      log.warn("Error while canceling service", e.getTargetException());
                  }
                  return Status.CANCEL_STATUS;
              } else {
      */
      if (!visualizer.isCompleted()) {
        visualizer.visualizeLoading();
        schedule(DELAY);
      }
      // }
      return Status.OK_STATUS;
    }

    @Override
    public boolean belongsTo(Object family) {
      return family == LOADING_FAMILY;
    }

    @Override
    protected void canceling() {
      super.canceling();
    }
  }
}
public class CompareObjectsWizard extends Wizard implements IExportWizard {

  static final Log log = Log.getLog(CompareObjectsWizard.class);

  private static final String RS_COMPARE_WIZARD_DIALOG_SETTINGS = "CompareWizard"; // $NON-NLS-1$

  private CompareObjectsSettings settings;

  public CompareObjectsWizard(List<DBNDatabaseNode> nodes) {
    this.settings = new CompareObjectsSettings(nodes);
    IDialogSettings section = UIUtils.getDialogSettings(RS_COMPARE_WIZARD_DIALOG_SETTINGS);
    setDialogSettings(section);

    settings.loadFrom(section);
  }

  @Override
  public void dispose() {
    super.dispose();
  }

  public CompareObjectsSettings getSettings() {
    return settings;
  }

  @Override
  public void addPages() {
    super.addPages();
    addPage(new CompareObjectsPageSettings());
    addPage(new CompareObjectsPageOutput());
  }

  @Override
  public void init(IWorkbench workbench, IStructuredSelection currentSelection) {
    setWindowTitle("Compare objects");
    setNeedsProgressMonitor(true);
  }

  private void showError(String error) {
    ((WizardPage) getContainer().getCurrentPage()).setErrorMessage(error);
  }

  @Override
  public boolean performFinish() {
    // Save settings
    getSettings().saveTo(getDialogSettings());
    showError(null);

    // Compare
    final CompareObjectsExecutor executor = new CompareObjectsExecutor(settings);
    try {
      DBeaverUI.run(
          getContainer(),
          true,
          true,
          new DBRRunnableWithProgress() {
            @Override
            public void run(DBRProgressMonitor monitor)
                throws InvocationTargetException, InterruptedException {
              try {
                CompareReport report = generateReport(monitor, executor);

                renderReport(monitor, report);
              } catch (DBException e) {
                throw new InvocationTargetException(e);
              }
            }
          });
      UIUtils.showMessageBox(
          getShell(), "Objects compare", "Objects compare finished", SWT.ICON_INFORMATION);
    } catch (InvocationTargetException e) {
      if (executor.getInitializeError() != null) {
        showError(executor.getInitializeError().getMessage());
      } else {
        log.error(e.getTargetException());
        showError(e.getTargetException().getMessage());
      }
      return false;
    } catch (InterruptedException e) {
      showError("Compare interrupted");
      return false;
    } finally {
      executor.dispose();
    }

    // Done
    return true;
  }

  private CompareReport generateReport(DBRProgressMonitor monitor, CompareObjectsExecutor executor)
      throws DBException, InterruptedException {
    monitor.beginTask("Compare objects", 1000);
    CompareReport report = executor.compareObjects(monitor, getSettings().getNodes());
    monitor.done();
    return report;
  }

  private void renderReport(DBRProgressMonitor monitor, CompareReport report) {
    try {
      File reportFile;
      switch (settings.getOutputType()) {
        case BROWSER:
          reportFile = File.createTempFile("compare-report", ".html");
          break;
        default:
          {
            StringBuilder fileName = new StringBuilder("compare"); // "compare-report.html";
            for (DBNDatabaseNode node : report.getNodes()) {
              fileName.append("-").append(CommonUtils.escapeIdentifier(node.getName()));
            }
            fileName.append("-report.html");
            reportFile = new File(settings.getOutputFolder(), fileName.toString());
            break;
          }
      }

      reportFile.deleteOnExit();
      OutputStream outputStream = new FileOutputStream(reportFile);
      try {
        monitor.beginTask("Render report", report.getReportLines().size());
        CompareReportRenderer reportRenderer = new CompareReportRenderer();
        reportRenderer.renderReport(monitor, report, getSettings(), outputStream);
        monitor.done();
      } finally {
        ContentUtils.close(outputStream);
      }
      UIUtils.launchProgram(reportFile.getAbsolutePath());
    } catch (IOException e) {
      showError(e.getMessage());
      log.error(e);
    }
  }
}
Exemple #17
0
/** UI Utils */
public class UIUtils {

  static final Log log = Log.getLog(UIUtils.class);

  public static final String DEFAULT_TIMESTAMP_PATTERN = "yyyy.MM.dd HH:mm";
  public static final String INLINE_WIDGET_EDITOR_ID = "org.jkiss.dbeaver.ui.InlineWidgetEditor";

  public static VerifyListener getIntegerVerifyListener(Locale locale) {
    final DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale);
    return new VerifyListener() {
      @Override
      public void verifyText(VerifyEvent e) {
        for (int i = 0; i < e.text.length(); i++) {
          char ch = e.text.charAt(i);
          if (!Character.isDigit(ch)
              && ch != symbols.getMinusSign()
              && ch != symbols.getGroupingSeparator()) {
            e.doit = false;
            return;
          }
        }
        e.doit = true;
      }
    };
  }

  public static VerifyListener getNumberVerifyListener(Locale locale) {
    DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale);
    final char[] allowedChars =
        new char[] {
          symbols.getDecimalSeparator(),
          symbols.getGroupingSeparator(),
          symbols.getMinusSign(),
          symbols.getZeroDigit(),
          symbols.getMonetaryDecimalSeparator(),
          '+'
        };
    final String exponentSeparator = symbols.getExponentSeparator();
    return new VerifyListener() {
      @Override
      public void verifyText(VerifyEvent e) {
        for (int i = 0; i < e.text.length(); i++) {
          char ch = e.text.charAt(i);
          if (!Character.isDigit(ch)
              && !ArrayUtils.contains(allowedChars, ch)
              && exponentSeparator.indexOf(ch) == -1) {
            e.doit = false;
            return;
          }
        }
        e.doit = true;
      }
    };
  }

  public static ToolItem createToolItem(
      ToolBar toolBar, String text, Image icon, final IAction action) {
    ToolItem item = new ToolItem(toolBar, SWT.PUSH);
    item.setToolTipText(text);
    if (icon != null) {
      item.setImage(icon);
    }
    item.addSelectionListener(
        new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent e) {
            action.run();
          }
        });
    return item;
  }

  public static TableColumn createTableColumn(Table table, int style, String text) {
    TableColumn column = new TableColumn(table, style);
    column.setText(text);
    return column;
  }

  public static TreeColumn createTreeColumn(Tree tree, int style, String text) {
    TreeColumn column = new TreeColumn(tree, style);
    column.setText(text);
    return column;
  }

  public static void packColumns(Table table) {
    packColumns(table, false);
  }

  public static void packColumns(Table table, boolean fit) {
    table.setRedraw(false);
    try {
      int totalWidth = 0;
      final TableColumn[] columns = table.getColumns();
      for (TableColumn column : columns) {
        column.pack();
        totalWidth += column.getWidth();
      }
      final Rectangle clientArea = table.getClientArea();
      if (clientArea.width > 0 && totalWidth > clientArea.width) {
        for (TableColumn column : columns) {
          int colWidth = column.getWidth();
          if (colWidth > totalWidth / 3) {
            // If some columns is too big (more than 33% of total width)
            // Then shrink it to 30%
            column.setWidth(totalWidth / 3);
            totalWidth -= colWidth;
            totalWidth += column.getWidth();
          }
        }
        int extraSpace = totalWidth - clientArea.width;

        for (TableColumn tc : columns) {
          double ratio = (double) tc.getWidth() / totalWidth;
          int newWidth = (int) (tc.getWidth() - extraSpace * ratio);
          tc.setWidth(newWidth);
        }
      }
      if (fit && totalWidth < clientArea.width) {
        int sbWidth = 0;
        if (table.getVerticalBar() != null) {
          sbWidth = table.getVerticalBar().getSize().x;
        }
        if (columns.length > 0) {
          float extraSpace = (clientArea.width - totalWidth - sbWidth) / columns.length;
          for (TableColumn tc : columns) {
            tc.setWidth((int) (tc.getWidth() + extraSpace));
          }
        }
      }
    } finally {
      table.setRedraw(true);
    }
  }

  public static void packColumns(@NotNull Tree tree) {
    packColumns(tree, false, null);
  }

  public static void packColumns(@NotNull Tree tree, boolean fit, @Nullable float[] ratios) {
    tree.setRedraw(false);
    try {
      // Check for disposed items
      // TODO: it looks like SWT error. Sometimes tree items are disposed and NPE is thrown from
      // column.pack
      for (TreeItem item : tree.getItems()) {
        if (item.isDisposed()) {
          return;
        }
      }
      int totalWidth = 0;
      final TreeColumn[] columns = tree.getColumns();
      for (TreeColumn column : columns) {
        column.pack();
        totalWidth += column.getWidth();
      }
      Rectangle clientArea = tree.getClientArea();
      if (clientArea.isEmpty()) {
        return;
      }
      if (fit) {
        int areaWidth = clientArea.width;
        if (tree.getVerticalBar() != null) {
          areaWidth -= tree.getVerticalBar().getSize().x;
        }
        if (totalWidth > areaWidth) {
          int extraSpace = totalWidth - areaWidth;
          for (TreeColumn tc : columns) {
            double ratio = (double) tc.getWidth() / totalWidth;
            tc.setWidth((int) (tc.getWidth() - extraSpace * ratio));
          }
        } else if (totalWidth < areaWidth) {
          float extraSpace = areaWidth - totalWidth;
          if (columns.length > 0) {
            if (ratios == null || ratios.length < columns.length) {
              extraSpace /= columns.length;
              extraSpace--;
              for (TreeColumn tc : columns) {
                tc.setWidth((int) (tc.getWidth() + extraSpace));
              }
            } else {
              for (int i = 0; i < columns.length; i++) {
                TreeColumn tc = columns[i];
                tc.setWidth((int) (tc.getWidth() + extraSpace * ratios[i]));
              }
            }
          }
        }
      }
    } finally {
      tree.setRedraw(true);
    }
  }

  public static void maxTableColumnsWidth(Table table) {
    table.setRedraw(false);
    try {
      int columnCount = table.getColumnCount();
      if (columnCount > 0) {
        int totalWidth = 0;
        final TableColumn[] columns = table.getColumns();
        for (TableColumn tc : columns) {
          tc.pack();
          totalWidth += tc.getWidth();
        }
        final Rectangle clientArea = table.getClientArea();
        if (totalWidth < clientArea.width) {
          int extraSpace = clientArea.width - totalWidth;
          extraSpace /= columnCount;
          for (TableColumn tc : columns) {
            tc.setWidth(tc.getWidth() + extraSpace);
          }
        }
      }
    } finally {
      table.setRedraw(true);
    }
  }

  public static int getColumnAtPos(TableItem item, int x, int y) {
    int columnCount = item.getParent().getColumnCount();
    for (int i = 0; i < columnCount; i++) {
      Rectangle rect = item.getBounds(i);
      if (rect.contains(x, y)) {
        return i;
      }
    }
    return -1;
  }

  public static int getColumnAtPos(TreeItem item, int x, int y) {
    int columnCount = item.getParent().getColumnCount();
    for (int i = 0; i < columnCount; i++) {
      Rectangle rect = item.getBounds(i);
      if (rect.contains(x, y)) {
        return i;
      }
    }
    return -1;
  }

  public static void sortTable(Table table, Comparator<TableItem> comparator) {
    int columnCount = table.getColumnCount();
    String[] values = new String[columnCount];
    TableItem[] items = table.getItems();
    for (int i = 1; i < items.length; i++) {
      for (int j = 0; j < i; j++) {
        TableItem item = items[i];
        if (comparator.compare(item, items[j]) < 0) {
          for (int k = 0; k < columnCount; k++) {
            values[k] = item.getText(k);
          }
          Object data = item.getData();
          boolean checked = item.getChecked();
          item.dispose();

          item = new TableItem(table, SWT.NONE, j);
          item.setText(values);
          item.setData(data);
          item.setChecked(checked);
          items = table.getItems();
          break;
        }
      }
    }
  }

  public static TableItem getNextTableItem(Table table, TableItem item) {
    TableItem[] items = table.getItems();
    for (int i = 0; i < items.length - 1; i++) {
      if (items[i] == item) {
        return items[i + 1];
      }
    }
    return null;
  }

  public static void dispose(Widget widget) {
    if (widget != null && !widget.isDisposed()) {
      try {
        widget.dispose();
      } catch (Exception e) {
        log.debug("widget dispose error", e);
      }
    }
  }

  public static void dispose(Resource resource) {
    if (resource != null && !resource.isDisposed()) {
      try {
        resource.dispose();
      } catch (Exception e) {
        log.debug("Resource dispose error", e);
      }
    }
  }

  public static void showMessageBox(
      final Shell shell, final String title, final String info, final int messageType) {
    Runnable runnable =
        new Runnable() {
          @Override
          public void run() {
            MessageBox messageBox = new MessageBox(shell, messageType | SWT.OK);
            messageBox.setMessage(info);
            messageBox.setText(title);
            messageBox.open();
          }
        };
    runInUI(shell, runnable);
  }

  public static boolean confirmAction(
      final Shell shell, final String title, final String question) {
    RunnableWithResult<Boolean> confirmer =
        new RunnableWithResult<Boolean>() {
          @Override
          public void run() {
            MessageBox messageBox = new MessageBox(shell, SWT.ICON_WARNING | SWT.YES | SWT.NO);
            messageBox.setMessage(question);
            messageBox.setText(title);
            int response = messageBox.open();
            result = (response == SWT.YES);
          }
        };
    runInUI(shell, confirmer);
    return confirmer.getResult();
  }

  public static Font makeBoldFont(Font normalFont) {
    return modifyFont(normalFont, SWT.BOLD);
  }

  public static Font modifyFont(Font normalFont, int style) {
    FontData[] fontData = normalFont.getFontData();
    fontData[0].setStyle(fontData[0].getStyle() | style);
    return new Font(normalFont.getDevice(), fontData[0]);
  }

  public static Group createControlGroup(
      Composite parent, String label, int columns, int layoutStyle, int widthHint) {
    Group group = new Group(parent, SWT.NONE);
    group.setText(label);

    GridData gd = new GridData(layoutStyle);
    if (widthHint > 0) {
      gd.widthHint = widthHint;
    }
    group.setLayoutData(gd);

    GridLayout gl = new GridLayout(columns, false);
    group.setLayout(gl);

    return group;
  }

  public static Label createControlLabel(Composite parent, String label) {
    Label textLabel = new Label(parent, SWT.NONE);
    textLabel.setText(label + ": "); // $NON-NLS-1$

    return textLabel;
  }

  public static Label createTextLabel(Composite parent, String label) {
    Label textLabel = new Label(parent, SWT.NONE);
    textLabel.setText(label);

    return textLabel;
  }

  public static Label createImageLabel(Composite parent, DBPImage image) {
    Label imageLabel = new Label(parent, SWT.NONE);
    imageLabel.setImage(DBeaverIcons.getImage(image));

    return imageLabel;
  }

  public static Text createLabelText(Composite parent, String label, String value) {
    return createLabelText(parent, label, value, SWT.BORDER);
  }

  public static Text createLabelText(Composite parent, String label, String value, int style) {
    return createLabelText(parent, label, value, style, new GridData(GridData.FILL_HORIZONTAL));
  }

  @NotNull
  public static Text createLabelText(
      @NotNull Composite parent,
      @NotNull String label,
      @Nullable String value,
      int style,
      @Nullable Object layoutData) {
    createControlLabel(parent, label);

    Text text = new Text(parent, style);
    if (value != null) {
      text.setText(value);
    }

    if (layoutData != null) {
      text.setLayoutData(layoutData);
    }

    return text;
  }

  @NotNull
  public static Spinner createLabelSpinner(
      @NotNull Composite parent, @NotNull String label, int value, int minimum, int maximum) {
    createControlLabel(parent, label);

    Spinner spinner = new Spinner(parent, SWT.BORDER);
    spinner.setMinimum(minimum);
    spinner.setMaximum(maximum);
    spinner.setSelection(value);

    return spinner;
  }

  @NotNull
  public static Button createLabelCheckbox(Composite parent, String label, boolean checked) {
    return createLabelCheckbox(parent, label, null, checked, SWT.NONE);
  }

  @NotNull
  public static Button createLabelCheckbox(
      Composite parent, String label, String tooltip, boolean checked) {
    return createLabelCheckbox(parent, label, tooltip, checked, SWT.NONE);
  }

  @NotNull
  public static Button createLabelCheckbox(
      @NotNull Composite parent,
      @NotNull String label,
      @Nullable String tooltip,
      boolean checked,
      int style) {
    Label labelControl = createControlLabel(parent, label);
    // labelControl.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

    final Button button = new Button(parent, SWT.CHECK | style);
    if (checked) {
      button.setSelection(true);
    }
    labelControl.addMouseListener(
        new MouseAdapter() {
          @Override
          public void mouseUp(MouseEvent e) {
            if (!button.isDisposed() && button.isVisible() && button.isEnabled()) {
              button.setSelection(!button.getSelection());
              button.notifyListeners(SWT.Selection, new Event());
            }
          }
        });

    if (tooltip != null) {
      labelControl.setToolTipText(tooltip);
      button.setToolTipText(tooltip);
    }
    return button;
  }

  public static Button createCheckbox(Composite parent, String label, boolean checked) {
    final Button button = new Button(parent, SWT.CHECK);
    button.setText(label);
    if (checked) {
      button.setSelection(true);
    }

    return button;
  }

  public static Combo createLabelCombo(Composite parent, String label, int style) {
    Label labelControl = createControlLabel(parent, label);
    // labelControl.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

    final Combo combo = new Combo(parent, style);
    combo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

    return combo;
  }

  public static Button createToolButton(
      Composite parent, String text, SelectionListener selectionListener) {
    Button button = new Button(parent, SWT.PUSH);
    button.setText(text);
    button.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    if (selectionListener != null) {
      button.addSelectionListener(selectionListener);
    }
    return button;
  }

  @Nullable
  public static Shell getActiveShell() {
    IWorkbench workbench = PlatformUI.getWorkbench();
    return workbench == null ? null : getShell(workbench.getActiveWorkbenchWindow());
  }

  @Nullable
  public static Shell getShell(IShellProvider provider) {
    return provider == null ? null : provider.getShell();
  }

  @Nullable
  public static Shell getShell(IWorkbenchPart part) {
    return part == null ? null : getShell(part.getSite());
  }

  @Nullable
  public static Integer getTextInteger(Text text) {
    String str = text.getText();
    str = str.trim();
    if (str.length() == 0) {
      return null;
    }
    try {
      return Integer.valueOf(str);
    } catch (NumberFormatException e) {
      log.debug(e);
      return null;
    }
  }

  @Nullable
  public static IHandlerActivation registerKeyBinding(
      IServiceLocator serviceLocator, IAction action) {
    IHandlerService handlerService = serviceLocator.getService(IHandlerService.class);
    if (handlerService != null) {
      return handlerService.activateHandler(
          action.getActionDefinitionId(), new ActionHandler(action));
    } else {
      return null;
    }
  }

  public static Composite createPlaceholder(Composite parent, int columns) {
    return createPlaceholder(parent, columns, 0);
  }

  public static Composite createPlaceholder(Composite parent, int columns, int spacing) {
    Composite ph = new Composite(parent, SWT.NONE);
    GridLayout gl = new GridLayout(columns, false);
    gl.verticalSpacing = spacing;
    gl.horizontalSpacing = spacing;
    gl.marginHeight = 0;
    gl.marginWidth = 0;
    ph.setLayout(gl);
    return ph;
  }

  public static Label createHorizontalLine(Composite parent) {
    Label horizontalLine = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
    horizontalLine.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false, 1, 1));
    return horizontalLine;
  }

  @Nullable
  public static String getComboSelection(Combo combo) {
    int selectionIndex = combo.getSelectionIndex();
    if (selectionIndex < 0) {
      return null;
    }
    return combo.getItem(selectionIndex);
  }

  public static boolean setComboSelection(Combo combo, String value) {
    if (value == null) {
      return false;
    }
    int count = combo.getItemCount();
    for (int i = 0; i < count; i++) {
      if (value.equals(combo.getItem(i))) {
        combo.select(i);
        return true;
      }
    }
    return false;
  }

  public static Combo createEncodingCombo(Composite parent, String curCharset) {
    if (curCharset == null) {
      curCharset = GeneralUtils.getDefaultFileEncoding();
    }
    Combo encodingCombo = new Combo(parent, SWT.DROP_DOWN);
    encodingCombo.setVisibleItemCount(30);
    SortedMap<String, Charset> charsetMap = Charset.availableCharsets();
    int index = 0;
    int defIndex = -1;
    for (String csName : charsetMap.keySet()) {
      Charset charset = charsetMap.get(csName);
      encodingCombo.add(charset.displayName());
      if (charset.displayName().equalsIgnoreCase(curCharset)) {
        defIndex = index;
      }
      if (defIndex < 0) {
        for (String alias : charset.aliases()) {
          if (alias.equalsIgnoreCase(curCharset)) {
            defIndex = index;
          }
        }
      }
      index++;
    }
    if (defIndex >= 0) {
      encodingCombo.select(defIndex);
    } else {
      log.warn("Charset '" + curCharset + "' is not recognized"); // $NON-NLS-1$ //$NON-NLS-2$
    }
    return encodingCombo;
  }

  @NotNull
  public static SashForm createPartDivider(
      final IWorkbenchPart workbenchPart, Composite parent, int style) {
    final SashForm sash = new SashForm(parent, style);
    /*
     * //sash.setSashWidth(10); final IWorkbenchWindow workbenchWindow = workbenchPart.getSite().getWorkbenchWindow();
     * //sash.setBackground(sashActiveBackground);
     *
     * final IPartListener partListener = new IPartListener() {
     *
     * @Override public void partBroughtToTop(IWorkbenchPart part) { }
     *
     * @Override public void partOpened(IWorkbenchPart part) { }
     *
     * @Override public void partClosed(IWorkbenchPart part) { }
     *
     * @Override
     *
     * @SuppressWarnings("restriction") public void partActivated(IWorkbenchPart part) { if (part == workbenchPart) { Color
     * sashActiveBackground = workbenchWindow.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry().get(
     * IWorkbenchThemeConstants.ACTIVE_TAB_BG_END); if (sashActiveBackground == null) { sashActiveBackground =
     * Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); } sash.setBackground(sashActiveBackground); } }
     *
     * @Override public void partDeactivated(IWorkbenchPart part) { if (part == workbenchPart) {
     * sash.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); } } };
     *
     * final IPageListener pageListener = workbenchWindow.getActivePage() != null ? null : new IPageListener() {
     *
     * @Override public void pageActivated(IWorkbenchPage page) { }
     *
     * @Override public void pageOpened(IWorkbenchPage page) { page.addPartListener(partListener); }
     *
     * @Override public void pageClosed(IWorkbenchPage page) { page.removePartListener(partListener); } }; if (pageListener !=
     * null) { // No active page yet, wait for it in listener workbenchWindow.addPageListener(pageListener); } else { // Add
     * listener to active page workbenchWindow.getActivePage().addPartListener(partListener); }
     *
     * sash.addDisposeListener(new DisposeListener() {
     *
     * @Override public void widgetDisposed(DisposeEvent e) { if (pageListener != null) {
     * workbenchWindow.removePageListener(pageListener); } if (workbenchWindow.getActivePage() != null) {
     * workbenchWindow.getActivePage().removePartListener(partListener); } } });
     */

    return sash;
  }

  public static void showErrorDialog(
      @Nullable Shell shell,
      @NotNull String title,
      @Nullable String message,
      @Nullable Throwable error) {
    if (error != null) {
      log.error(error);
    }

    showErrorDialog(
        shell,
        title,
        error == null ? null : message,
        error == null
            ? new Status(IStatus.ERROR, DBeaverCore.PLUGIN_ID, message)
            : GeneralUtils.makeExceptionStatus(error));
  }

  public static void showErrorDialog(
      @Nullable Shell shell, @NotNull String title, @Nullable String message) {
    showErrorDialog(shell, title, message, (Throwable) null);
  }

  public static void showErrorDialog(
      @Nullable final Shell shell,
      @NotNull final String title,
      @Nullable final String message,
      @NotNull final IStatus status) {
    for (IStatus s = status; s != null; ) {
      if (s.getException() instanceof DBException) {
        if (showDatabaseError(shell, title, message, (DBException) s.getException())) {
          // If this DB error was handled by some DB-specific way then just don't care about it
          return;
        }
        break;
      }
      if (s.getChildren() != null && s.getChildren().length > 0) {
        s = s.getChildren()[0];
      } else {
        break;
      }
    }
    // log.debug(message);
    Runnable runnable =
        new Runnable() {
          @Override
          public void run() {
            // Display the dialog
            StandardErrorDialog dialog =
                new StandardErrorDialog(
                    shell == null ? DBeaverUI.getActiveWorkbenchShell() : shell,
                    title,
                    message,
                    RuntimeUtils.stripStack(status),
                    IStatus.ERROR);
            dialog.open();
          }
        };
    runInUI(shell, runnable);
  }

  public static void runInUI(@Nullable Shell shell, @NotNull Runnable runnable) {
    final Display display =
        shell == null || shell.isDisposed() ? Display.getDefault() : shell.getDisplay();
    if (display.getThread() != Thread.currentThread()) {
      display.syncExec(runnable);
    } else {
      runnable.run();
    }
  }

  public static void runInDetachedUI(@Nullable Shell shell, @NotNull Runnable runnable) {
    if (shell == null) {
      Display.getDefault().asyncExec(runnable);
    } else {
      try {
        shell.getDisplay().asyncExec(runnable);
      } catch (SWTException e) {
        // DF: Widget has been disposed, too late for some processing then..
      }
    }
  }

  @NotNull
  public static String formatMessage(@Nullable String message, @Nullable Object... args) {
    if (message == null) {
      return ""; //$NON-NLS-1$
    } else {
      return MessageFormat.format(message, args);
    }
  }

  @NotNull
  public static Button createPushButton(
      @NotNull Composite parent, @Nullable String label, @Nullable Image image) {
    Button button = new Button(parent, SWT.PUSH);
    if (label != null) {
      button.setText(label);
    }
    if (image != null) {
      button.setImage(image);
    }
    return button;
  }

  public static void setHelp(Control control, String pluginId, String helpContextID) {
    PlatformUI.getWorkbench()
        .getHelpSystem()
        .setHelp(control, pluginId + "." + helpContextID); // $NON-NLS-1$
  }

  public static void setHelp(Control control, String helpContextID) {
    setHelp(control, DBeaverCore.PLUGIN_ID, helpContextID);
  }

  @NotNull
  public static Text createOutputFolderChooser(
      final Composite parent, @Nullable String label, @Nullable ModifyListener changeListener) {
    UIUtils.createControlLabel(
        parent, label != null ? label : CoreMessages.data_transfer_wizard_output_label_directory);
    Composite chooserPlaceholder = UIUtils.createPlaceholder(parent, 2);
    chooserPlaceholder.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    final Text directoryText = new Text(chooserPlaceholder, SWT.BORDER);
    directoryText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    if (changeListener != null) {
      directoryText.addModifyListener(changeListener);
    }

    final Runnable folderChooser =
        new Runnable() {
          @Override
          public void run() {
            DirectoryDialog dialog = new DirectoryDialog(parent.getShell(), SWT.NONE);
            dialog.setMessage(CoreMessages.data_transfer_wizard_output_dialog_directory_message);
            dialog.setText(CoreMessages.data_transfer_wizard_output_dialog_directory_text);
            String directory = directoryText.getText();
            if (!CommonUtils.isEmpty(directory)) {
              dialog.setFilterPath(directory);
            }
            directory = dialog.open();
            if (directory != null) {
              directoryText.setText(directory);
            }
          }
        };
    directoryText.addMouseListener(
        new MouseAdapter() {
          @Override
          public void mouseUp(MouseEvent e) {
            folderChooser.run();
          }
        });

    Button openFolder = new Button(chooserPlaceholder, SWT.PUSH | SWT.FLAT);
    openFolder.setImage(DBeaverIcons.getImage(DBIcon.TREE_FOLDER));
    openFolder.setLayoutData(
        new GridData(GridData.VERTICAL_ALIGN_CENTER | GridData.HORIZONTAL_ALIGN_CENTER));
    openFolder.addSelectionListener(
        new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent e) {
            folderChooser.run();
          }
        });
    return directoryText;
  }

  public static String makeAnchor(String text) {
    return "<a>" + text + "</a>"; // $NON-NLS-1$ //$NON-NLS-2$
  }

  @Nullable
  public static <T> T findView(IWorkbenchWindow workbenchWindow, Class<T> viewClass) {
    IViewReference[] references = workbenchWindow.getActivePage().getViewReferences();
    for (IViewReference ref : references) {
      IViewPart view = ref.getView(false);
      if (view != null && viewClass.isAssignableFrom(view.getClass())) {
        return viewClass.cast(view);
      }
    }
    return null;
  }

  @Nullable
  public static IViewPart findView(IWorkbenchWindow workbenchWindow, String viewId) {
    IViewReference[] references = workbenchWindow.getActivePage().getViewReferences();
    for (IViewReference ref : references) {
      if (ref.getId().equals(viewId)) {
        return ref.getView(false);
      }
    }
    return null;
  }

  public static void setClipboardContents(Display display, Transfer transfer, Object contents) {
    Clipboard clipboard = new Clipboard(display);
    clipboard.setContents(new Object[] {contents}, new Transfer[] {transfer});
    clipboard.dispose();
  }

  public static void updateMainWindowTitle(IWorkbenchWindow window) {
    IProject activeProject = DBeaverCore.getInstance().getProjectRegistry().getActiveProject();
    IProduct product = Platform.getProduct();
    String title = product == null ? "Unknown" : product.getName(); // $NON-NLS-1$
    if (activeProject != null) {
      title += " - " + activeProject.getName(); // $NON-NLS-1$
    }
    IWorkbenchPage activePage = window.getActivePage();
    if (activePage != null) {
      IEditorPart activeEditor = activePage.getActiveEditor();
      if (activeEditor != null) {
        title += " - [ " + activeEditor.getTitle() + " ]";
      }
    }
    window.getShell().setText(title);
  }

  public static void showPreferencesFor(Shell shell, Object element, String defPageID) {
    PreferenceDialog propDialog;
    if (element == null) {
      propDialog =
          PreferencesUtil.createPreferenceDialogOn(
              shell, defPageID, new String[] {defPageID}, null, PreferencesUtil.OPTION_NONE);
    } else {
      propDialog =
          PreferencesUtil.createPropertyDialogOn(
              shell, element, defPageID, null, null, PreferencesUtil.OPTION_NONE);
    }
    if (propDialog != null) {
      propDialog.open();
    }
  }

  public static void addFocusTracker(
      IServiceLocator serviceLocator, String controlID, Control control) {
    final IFocusService focusService = serviceLocator.getService(IFocusService.class);
    if (focusService != null) {
      focusService.addFocusTracker(control, controlID);
    } else {
      log.debug("Focus service not found in " + serviceLocator);
    }
  }

  public static void removeFocusTracker(IServiceLocator serviceLocator, Control control) {
    if (PlatformUI.getWorkbench().isClosing()) {
      // TODO: it is a bug in eclipse. During workbench shutdown disposed service returned.
      return;
    }
    final IFocusService focusService = serviceLocator.getService(IFocusService.class);
    if (focusService != null) {
      focusService.removeFocusTracker(control);
    } else {
      log.debug("Focus service not found in " + serviceLocator);
    }
  }

  public static IDialogSettings getDialogSettings(String dialogId) {
    IDialogSettings workbenchSettings = DBeaverActivator.getInstance().getDialogSettings();
    IDialogSettings section = workbenchSettings.getSection(dialogId);
    if (section == null) {
      section = workbenchSettings.addNewSection(dialogId);
    }
    return section;
  }

  @Nullable
  public static IWorkbenchPartSite getWorkbenchPartSite(IServiceLocator serviceLocator) {
    IWorkbenchPartSite partSite = serviceLocator.getService(IWorkbenchPartSite.class);
    if (partSite == null) {
      IWorkbenchPart activePart = serviceLocator.getService(IWorkbenchPart.class);
      if (activePart == null) {
        IWorkbenchWindow workbenchWindow = DBeaverUI.getActiveWorkbenchWindow();
        if (workbenchWindow != null) {
          IWorkbenchPage activePage = workbenchWindow.getActivePage();
          if (activePage != null) {
            activePart = activePage.getActivePart();
          }
        }
      }
      if (activePart != null) {
        partSite = activePart.getSite();
      }
    }
    return partSite;
  }

  public static boolean isContextActive(String contextId) {
    Collection<?> contextIds =
        PlatformUI.getWorkbench()
            .getActiveWorkbenchWindow()
            .getService(IContextService.class)
            .getActiveContextIds();
    for (Object id : contextIds) {
      if (contextId.equals(id)) {
        return true;
      }
    }
    return false;
  }

  @Nullable
  public static ISelectionProvider getSelectionProvider(IServiceLocator serviceLocator) {
    ISelectionProvider selectionProvider = serviceLocator.getService(ISelectionProvider.class);
    if (selectionProvider != null) {
      return selectionProvider;
    }
    IWorkbenchPartSite partSite = getWorkbenchPartSite(serviceLocator);
    if (partSite == null) {
      IWorkbenchPart activePart = serviceLocator.getService(IWorkbenchPart.class);
      if (activePart == null) {
        IWorkbenchWindow activeWindow = DBeaverUI.getActiveWorkbenchWindow();
        if (activeWindow != null) {
          activePart = activeWindow.getActivePage().getActivePart();
        }
      }
      if (activePart != null) {
        partSite = activePart.getSite();
      }
    }
    if (partSite != null) {
      return partSite.getSelectionProvider();
    } else {
      return null;
    }
  }

  public static void enableWithChildren(Composite composite, boolean enable) {
    composite.setEnabled(enable);
    for (Control child : composite.getChildren()) {
      if (child instanceof Composite) {
        enableWithChildren((Composite) child, enable);
      } else {
        child.setEnabled(enable);
      }
    }
  }

  /**
   * Determine whether this control or any of it's child has focus
   *
   * @param control control to check
   * @return true if it has focus
   */
  public static boolean hasFocus(Control control) {
    Control focusControl = control.getDisplay().getFocusControl();
    if (focusControl == null) {
      return false;
    }
    for (Control fc = focusControl; fc != null; fc = fc.getParent()) {
      if (fc == control) {
        return true;
      }
    }
    return false;
  }

  /**
   * Eclipse hack. Disables/enabled all key bindings in specified site's part. Works only if host
   * editor is extender of AbstractTextEditor Uses reflection because setActionActivation is private
   * method TODO: find better way to disable key bindings or prioritize event handling to widgets
   *
   * @param partSite workbench part site
   * @param enable enable or disable
   */
  @Deprecated
  public static void enableHostEditorKeyBindings(IWorkbenchPartSite partSite, boolean enable) {
    IWorkbenchPart part = partSite.getPart();
    if (part instanceof AbstractTextEditor) {
      AbstractTextEditor hostEditor = (AbstractTextEditor) part;
      if (hostEditor instanceof BaseTextEditor) {
        StyledText textWidget = ((BaseTextEditor) hostEditor).getTextViewer().getTextWidget();
        if (textWidget == null || textWidget.isDisposed()) {
          return;
        }
      }
      try {
        Method activatorMethod =
            AbstractTextEditor.class.getDeclaredMethod("setActionActivation", Boolean.TYPE);
        activatorMethod.setAccessible(true);
        activatorMethod.invoke(hostEditor, enable);
      } catch (Throwable e) {
        if (e instanceof InvocationTargetException) {
          e = ((InvocationTargetException) e).getTargetException();
        }
        log.warn("Can't disable text editor action activations", e);
      }
      // hostEditor.getEditorSite().getActionBarContributor().setActiveEditor(hostEditor);
    }
  }

  public static void enableHostEditorKeyBindingsSupport(
      final IWorkbenchPartSite partSite, Control control) {
    if (!(partSite.getPart() instanceof AbstractTextEditor)) {
      return;
    }

    final boolean[] activated = new boolean[] {false};
    control.addFocusListener(
        new FocusListener() {
          @Override
          public void focusGained(FocusEvent e) {
            if (!activated[0]) {
              UIUtils.enableHostEditorKeyBindings(partSite, false);
              activated[0] = true;
            }
          }

          @Override
          public void focusLost(FocusEvent e) {
            if (activated[0]) {
              UIUtils.enableHostEditorKeyBindings(partSite, true);
              activated[0] = false;
            }
          }
        });
    control.addDisposeListener(
        new DisposeListener() {
          @Override
          public void widgetDisposed(DisposeEvent e) {
            if (activated[0]) {
              UIUtils.enableHostEditorKeyBindings(partSite, true);
              activated[0] = false;
            }
          }
        });
  }

  public static CTabItem getTabItem(CTabFolder tabFolder, Object data) {
    for (CTabItem item : tabFolder.getItems()) {
      if (item.getData() == data) {
        return item;
      }
    }
    return null;
  }

  public static TreeItem getTreeItem(Tree tree, Object data) {
    for (TreeItem item : tree.getItems()) {
      if (item.getData() == data) {
        return item;
      }
    }
    return null;
  }

  public static int blend(int v1, int v2, int ratio) {
    return (ratio * v1 + (100 - ratio) * v2) / 100;
  }

  public static RGB blend(RGB c1, RGB c2, int ratio) {
    int r = blend(c1.red, c2.red, ratio);
    int g = blend(c1.green, c2.green, ratio);
    int b = blend(c1.blue, c2.blue, ratio);
    return new RGB(r, g, b);
  }

  public static boolean isParent(Control parent, Control child) {
    for (Control c = child; c != null; c = c.getParent()) {
      if (c == parent) {
        return true;
      }
    }
    return false;
  }

  public static boolean isInDialog(Control control) {
    return control.getShell().getData() instanceof org.eclipse.jface.dialogs.Dialog;
  }

  public static boolean validateAndSave(DBRProgressMonitor monitor, ISaveablePart saveable) {
    if (!saveable.isDirty()) {
      return true;
    }
    SaveRunner saveRunner = new SaveRunner(monitor, saveable);
    runInUI(null, saveRunner);
    return saveRunner.getResult();
  }

  public static Link createLink(Composite parent, String text, SelectionListener listener) {
    Link link = new Link(parent, SWT.NONE);
    link.setText(text);
    link.addSelectionListener(listener);
    return link;
  }

  public static CellEditor createPropertyEditor(
      final IServiceLocator serviceLocator,
      Composite parent,
      DBPPropertySource source,
      DBPPropertyDescriptor property) {
    if (source == null) {
      return null;
    }
    final Object object = source.getEditableValue();
    if (!property.isEditable(object)) {
      return null;
    }
    CellEditor cellEditor = UIUtils.createCellEditor(parent, object, property);
    if (cellEditor != null) {
      final Control editorControl = cellEditor.getControl();
      UIUtils.addFocusTracker(serviceLocator, UIUtils.INLINE_WIDGET_EDITOR_ID, editorControl);
      editorControl.addDisposeListener(
          new DisposeListener() {
            @Override
            public void widgetDisposed(DisposeEvent e) {
              UIUtils.removeFocusTracker(serviceLocator, editorControl);
            }
          });
    }
    return cellEditor;
  }

  public static CellEditor createCellEditor(
      Composite parent, Object object, DBPPropertyDescriptor property) {
    // List
    if (property instanceof IPropertyValueListProvider) {
      final IPropertyValueListProvider listProvider = (IPropertyValueListProvider) property;
      final Object[] items = listProvider.getPossibleValues(object);
      if (!ArrayUtils.isEmpty(items)) {
        final String[] strings = new String[items.length];
        for (int i = 0, itemsLength = items.length; i < itemsLength; i++) {
          strings[i] =
              items[i] instanceof DBPNamedObject
                  ? ((DBPNamedObject) items[i]).getName()
                  : CommonUtils.toString(items[i]);
        }
        final CustomComboBoxCellEditor editor =
            new CustomComboBoxCellEditor(
                parent,
                strings,
                SWT.DROP_DOWN | (listProvider.allowCustomValue() ? SWT.NONE : SWT.READ_ONLY));
        return editor;
      }
    }
    Class<?> propertyType = property.getDataType();
    if (propertyType == null || CharSequence.class.isAssignableFrom(propertyType)) {
      return new CustomTextCellEditor(parent);
    } else if (BeanUtils.isNumericType(propertyType)) {
      return new CustomNumberCellEditor(parent, propertyType);
    } else if (BeanUtils.isBooleanType(propertyType)) {
      return new CustomCheckboxCellEditor(parent);
      // return new CheckboxCellEditor(parent);
    } else if (propertyType.isEnum()) {
      final Object[] enumConstants = propertyType.getEnumConstants();
      final String[] strings = new String[enumConstants.length];
      for (int i = 0, itemsLength = enumConstants.length; i < itemsLength; i++) {
        strings[i] = ((Enum) enumConstants[i]).name();
      }
      return new CustomComboBoxCellEditor(parent, strings, SWT.DROP_DOWN | SWT.READ_ONLY);
    } else {
      log.warn("Unsupported property type: " + propertyType.getName());
      return null;
    }
  }

  public static boolean showDatabaseError(
      Shell shell, String title, String message, DBException error) {
    DBPDataSource dataSource = error.getDataSource();
    DBPErrorAssistant errorAssistant = DBUtils.getAdapter(DBPErrorAssistant.class, dataSource);
    if (errorAssistant != null) {
      DBPErrorAssistant.ErrorType errorType =
          ((DBPErrorAssistant) dataSource).discoverErrorType(error);
      switch (errorType) {
        case CONNECTION_LOST:
          DataSourceInvalidateHandler.showConnectionLostDialog(shell, message, error);
          return true;
        case DRIVER_CLASS_MISSING:
          DriverEditDialog.showBadConfigDialog(shell, message, error);
          return true;
      }
    }

    return false;
  }

  public static void postEvent(Control ownerControl, final Event event) {
    final Display display = ownerControl.getDisplay();
    display.asyncExec(
        new Runnable() {
          @Override
          public void run() {
            display.post(event);
          }
        });
  }

  public static void drawMessageOverControl(
      Control control, PaintEvent e, String message, int offset) {
    Rectangle bounds = control.getBounds();
    Point ext = e.gc.textExtent(message);
    e.gc.drawText(message, (bounds.width - ext.x) / 2, bounds.height / 3 + offset);
  }

  private static class SaveRunner implements Runnable {
    private final DBRProgressMonitor monitor;
    private final ISaveablePart saveable;
    private boolean result;

    private SaveRunner(DBRProgressMonitor monitor, ISaveablePart saveable) {
      this.monitor = monitor;
      this.saveable = saveable;
    }

    public boolean getResult() {
      return result;
    }

    @Override
    public void run() {
      int choice = -1;
      if (saveable instanceof ISaveablePart2) {
        choice = ((ISaveablePart2) saveable).promptToSaveOnClose();
      }
      if (choice == -1 || choice == ISaveablePart2.DEFAULT) {
        Shell shell;
        String saveableName;
        if (saveable instanceof IWorkbenchPart) {
          shell = ((IWorkbenchPart) saveable).getSite().getShell();
          saveableName = ((IWorkbenchPart) saveable).getTitle();
        } else {
          shell = DBeaverUI.getActiveWorkbenchShell();
          saveableName = CommonUtils.toString(saveable);
        }
        int confirmResult =
            ConfirmationDialog.showConfirmDialog(
                shell,
                DBeaverPreferences.CONFIRM_EDITOR_CLOSE,
                ConfirmationDialog.QUESTION_WITH_CANCEL,
                saveableName);
        switch (confirmResult) {
          case IDialogConstants.YES_ID:
            choice = ISaveablePart2.YES;
            break;
          case IDialogConstants.NO_ID:
            choice = ISaveablePart2.NO;
            break;
          default:
            choice = ISaveablePart2.CANCEL;
            break;
        }
      }
      switch (choice) {
        case ISaveablePart2.YES: // yes
          saveable.doSave(monitor.getNestedMonitor());
          result = !saveable.isDirty();
          break;
        case ISaveablePart2.NO: // no
          result = true;
          break;
        case ISaveablePart2.CANCEL: // cancel
        default:
          result = false;
          break;
      }
    }
  }

  public static Color getConnectionColor(DBPConnectionConfiguration connectionInfo) {
    String rgbString = connectionInfo.getConnectionColor();
    if (CommonUtils.isEmpty(rgbString)) {
      rgbString = connectionInfo.getConnectionType().getColor();
    }
    if (CommonUtils.isEmpty(rgbString)) {
      return null;
    }
    Color connectionColor =
        DBeaverUI.getSharedTextColors().getColor(StringConverter.asRGB(rgbString));
    if (connectionColor.getBlue() == 255
        && connectionColor.getRed() == 255
        && connectionColor.getGreen() == 255) {
      // For white color return just null to avoid explicit color set.
      // It is important for dark themes
      return null;
    }
    return connectionColor;
  }

  public static Color getConnectionTypeColor(DBPConnectionType connectionType) {
    String rgbString = connectionType.getColor();
    if (CommonUtils.isEmpty(rgbString)) {
      return null;
    }
    return DBeaverUI.getSharedTextColors().getColor(StringConverter.asRGB(rgbString));
  }
}
/** CONTENT text editor */
public class ImageEditorPart extends EditorPart implements IResourceChangeListener {

  private static final Log log = Log.getLog(ImageEditorPart.class);

  private ImageEditor imageViewer;
  private boolean contentValid;

  @Override
  public void doSave(IProgressMonitor monitor) {}

  @Override
  public void doSaveAs() {}

  @Override
  public void init(IEditorSite site, IEditorInput input) throws PartInitException {
    setSite(site);
    setInput(input);

    ResourcesPlugin.getWorkspace().addResourceChangeListener(this);
  }

  @Override
  public void dispose() {
    ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
    super.dispose();
  }

  @Override
  public boolean isDirty() {
    return false;
  }

  @Override
  public boolean isSaveAsAllowed() {
    return false;
  }

  @Override
  public void createPartControl(Composite parent) {
    imageViewer = new ImageEditor(parent, SWT.NONE);

    loadImage();
  }

  private void loadImage() {
    if (imageViewer == null || imageViewer.isDisposed()) {
      return;
    }
    if (getEditorInput() instanceof IPathEditorInput) {
      try {
        final IPath absolutePath = ((IPathEditorInput) getEditorInput()).getPath();
        File localFile = absolutePath.toFile();
        if (localFile.exists()) {
          try (InputStream inputStream = new FileInputStream(localFile)) {
            contentValid = imageViewer.loadImage(inputStream);
            imageViewer.update();
          }
        }
      } catch (Exception e) {
        log.error("Can't load image contents", e);
      }
    }
  }

  @Override
  public void setFocus() {
    imageViewer.setFocus();
  }

  @Override
  public String getTitle() {
    return "Image";
  }

  @Override
  public Image getTitleImage() {
    return DBeaverIcons.getImage(DBIcon.TYPE_IMAGE);
  }

  @Override
  public void resourceChanged(IResourceChangeEvent event) {
    IResourceDelta delta = event.getDelta();
    if (delta == null) {
      return;
    }
    IEditorInput input = getEditorInput();
    IPath localPath = null;
    if (input instanceof IPathEditorInput) {
      localPath = ((IPathEditorInput) input).getPath();
    }
    if (localPath == null) {
      return;
    }
    localPath = ContentUtils.convertPathToWorkspacePath(localPath);
    delta = delta.findMember(localPath);
    if (delta == null) {
      return;
    }
    if (delta.getKind() == IResourceDelta.CHANGED) {
      // Refresh editor
      DBeaverUI.asyncExec(
          new Runnable() {
            @Override
            public void run() {
              loadImage();
            }
          });
    }
  }
}
/** ResultSetPresentationDescriptor */
public class ResultSetPresentationDescriptor extends AbstractContextDescriptor {

  private static final Log log = Log.getLog(ResultSetPresentationDescriptor.class);

  public static final String EXTENSION_ID =
      "org.jkiss.dbeaver.resultset.presentation"; // NON-NLS-1 //$NON-NLS-1$

  private static final String CONTENT_TYPE = "contentType";

  private final String id;
  private final String label;
  private final String description;
  private final ObjectType presentationType;
  private final DBPImage icon;
  private final int order;
  private final List<MimeType> contentTypes = new ArrayList<>();

  protected ResultSetPresentationDescriptor(IConfigurationElement config) {
    super(config);

    this.id = config.getAttribute(RegistryConstants.ATTR_ID);
    this.label = config.getAttribute(RegistryConstants.ATTR_LABEL);
    this.description = config.getAttribute(RegistryConstants.ATTR_DESCRIPTION);
    this.presentationType = new ObjectType(config.getAttribute(RegistryConstants.ATTR_CLASS));
    this.icon = iconToImage(config.getAttribute(RegistryConstants.ATTR_ICON));
    this.order = CommonUtils.toInt(config.getAttribute(RegistryConstants.ATTR_ORDER));

    for (IConfigurationElement typeCfg : config.getChildren(CONTENT_TYPE)) {
      String type = typeCfg.getAttribute(RegistryConstants.ATTR_TYPE);
      try {
        MimeType contentType = new MimeType(type);
        contentTypes.add(contentType);
      } catch (MimeTypeParseException e) {
        log.warn("Invalid content type: " + type, e);
      }
    }
  }

  public String getId() {
    return id;
  }

  public String getLabel() {
    return label;
  }

  public String getDescription() {
    return description;
  }

  public DBPImage getIcon() {
    return icon;
  }

  public int getOrder() {
    return order;
  }

  public boolean supportedBy(DBCResultSet resultSet, IResultSetContext context) {
    return appliesTo(resultSet, context) || matchesContentType(context);
  }

  public IResultSetPresentation createInstance() throws DBException {
    return presentationType.createInstance(IResultSetPresentation.class);
  }

  public boolean matches(Class<? extends IResultSetPresentation> type) {
    return presentationType.matchesType(type);
  }

  private boolean matchesContentType(IResultSetContext context) {
    String documentType = context.getDocumentContentType();
    if (contentTypes.isEmpty() || CommonUtils.isEmpty(documentType)) {
      return false;
    }
    for (MimeType mimeType : contentTypes) {
      try {
        if (mimeType.match(documentType)) {
          return true;
        }
      } catch (MimeTypeParseException e) {
        log.warn("Bad document content type: " + documentType, e);
      }
    }
    return false;
  }
}
/**
 * JDBC Content value handler. Handle LOBs, LONGs and BINARY types.
 *
 * @author Serge Rider
 */
public class ContentValueManager extends BaseValueManager {

  static final Log log = Log.getLog(ContentValueManager.class);

  public static final String PROP_CATEGORY_CONTENT = "CONTENT";

  public static void contributeContentActions(
      @NotNull IContributionManager manager, @NotNull final IValueController controller)
      throws DBCException {
    if (controller.getValue() instanceof DBDContent
        && !((DBDContent) controller.getValue()).isNull()) {
      manager.add(
          new Action(
              CoreMessages.model_jdbc_save_to_file_,
              DBeaverIcons.getImageDescriptor(UIIcon.SAVE_AS)) {
            @Override
            public void run() {
              DialogUtils.saveToFile(controller);
            }
          });
    }
    manager.add(
        new Action(
            CoreMessages.model_jdbc_load_from_file_, DBeaverIcons.getImageDescriptor(UIIcon.LOAD)) {
          @Override
          public void run() {
            DialogUtils.loadFromFile(controller);
          }
        });
  }

  public static IValueEditor openContentEditor(@NotNull IValueController controller) {
    Object value = controller.getValue();
    IValueController.EditType binaryEditType =
        IValueController.EditType.valueOf(
            controller
                .getExecutionContext()
                .getDataSource()
                .getContainer()
                .getPreferenceStore()
                .getString(DBeaverPreferences.RESULT_SET_BINARY_EDITOR_TYPE));
    if (binaryEditType != IValueController.EditType.EDITOR && value instanceof DBDContentCached) {
      // Use string editor for cached content
      return new TextViewDialog(controller);
    } else if (value instanceof DBDContent) {
      DBDContent content = (DBDContent) value;
      boolean isText = ContentUtils.isTextContent(content);
      List<ContentEditorPart> parts = new ArrayList<>();
      if (isText) {
        parts.add(new ContentTextEditorPart());
        if (ContentUtils.isXML(content)) {
          parts.add(new ContentXMLEditorPart());
        }
      } else {
        parts.add(new ContentBinaryEditorPart());
        parts.add(new ContentTextEditorPart());
        parts.add(new ContentImageEditorPart());
      }
      return ContentEditor.openEditor(
          controller, parts.toArray(new ContentEditorPart[parts.size()]));
    } else {
      controller.showMessage(CoreMessages.model_jdbc_unsupported_content_value_type_, true);
      return null;
    }
  }

  @Override
  public void contributeActions(
      @NotNull IContributionManager manager, @NotNull final IValueController controller)
      throws DBCException {
    contributeContentActions(manager, controller);
  }

  @Override
  public void contributeProperties(
      @NotNull DBPPropertyManager propertySource, @NotNull IValueController controller) {
    super.contributeProperties(propertySource, controller);
    try {
      Object value = controller.getValue();
      if (value instanceof DBDContent) {
        propertySource.addProperty(
            PROP_CATEGORY_CONTENT,
            "content_type", //$NON-NLS-1$
            CoreMessages.model_jdbc_content_type,
            ((DBDContent) value).getContentType());
        final long contentLength = ((DBDContent) value).getContentLength();
        if (contentLength >= 0) {
          propertySource.addProperty(
              PROP_CATEGORY_CONTENT,
              "content_length", //$NON-NLS-1$
              CoreMessages.model_jdbc_content_length,
              contentLength);
        }
      }
    } catch (Exception e) {
      log.warn("Can't extract CONTENT value information", e); // $NON-NLS-1$
    }
  }

  @NotNull
  @Override
  public IValueController.EditType[] getSupportedEditTypes() {
    return new IValueController.EditType[] {
      IValueController.EditType.PANEL, IValueController.EditType.EDITOR
    };
  }

  @Override
  public IValueEditor createEditor(@NotNull final IValueController controller) throws DBException {
    switch (controller.getEditType()) {
      case INLINE:
        // Open inline/panel editor
        if (controller.getValue() instanceof DBDContentCached) {
          return new ContentInlineEditor(controller);
        } else {
          return null;
        }
      case EDITOR:
        return openContentEditor(controller);
      case PANEL:
        Object value = controller.getValue();
        if (value instanceof DBDContent && ContentUtils.isXML((DBDContent) value)) {
          return new XMLPanelEditor(controller);
        } else {
          return new ContentPanelEditor(controller);
        }
      default:
        return null;
    }
  }
}
/** FileRefDocumentProvider */
public class FileRefDocumentProvider extends BaseTextDocumentProvider {

  private static final Log log = Log.getLog(FileRefDocumentProvider.class);

  private static final int DEFAULT_BUFFER_SIZE = 10000;

  public FileRefDocumentProvider() {}

  protected IEditorInput createNewEditorInput(IFile newFile) {
    return new ProjectFileEditorInput(newFile);
  }

  @Override
  protected Document createDocument(Object element) throws CoreException {
    Document document = createEmptyDocument();
    IStorage storage = EditorUtils.getStorageFromInput(element);
    if (storage != null) {
      if (setDocumentContent(document, storage)) {
        setupDocument(document);
        return document;
      }
    }
    File file = EditorUtils.getLocalFileFromInput(element);
    if (file != null) {
      try (InputStream stream = new FileInputStream(file)) {
        setDocumentContent(document, stream, null);
        setupDocument(document);
        return document;
      } catch (IOException e) {
        throw new CoreException(GeneralUtils.makeExceptionStatus(e));
      }
    }

    throw new IllegalArgumentException(
        "Project document provider supports only editor inputs which provides IStorage facility");
  }

  protected void setupDocument(IDocument document) {}

  @Override
  public boolean isReadOnly(Object element) {
    IStorage storage = EditorUtils.getStorageFromInput(element);
    if (storage != null) {
      return storage.isReadOnly();
    }
    File file = EditorUtils.getLocalFileFromInput(element);
    if (file != null) {
      return !file.isFile();
    }
    return super.isReadOnly(element);
  }

  @Override
  public boolean isModifiable(Object element) {
    return !isReadOnly(element);
  }

  @Override
  public boolean isDeleted(Object element) {
    IStorage storage = EditorUtils.getStorageFromInput(element);
    if (storage instanceof IResource) {
      return !((IResource) storage).exists();
    }
    File file = EditorUtils.getLocalFileFromInput(element);
    if (file != null) {
      return !file.exists();
    }
    return super.isDeleted(element);
  }

  @Override
  protected void doSaveDocument(
      IProgressMonitor monitor, Object element, IDocument document, boolean overwrite)
      throws CoreException {
    try {
      IStorage storage = EditorUtils.getStorageFromInput(element);
      File localFile = null;
      if (storage == null) {
        localFile = EditorUtils.getLocalFileFromInput(element);
        if (localFile == null) {
          throw new DBException("Can't obtain file from editor input");
        }
      }
      String encoding =
          (storage instanceof IEncodedStorage
              ? ((IEncodedStorage) storage).getCharset()
              : GeneralUtils.DEFAULT_FILE_CHARSET_NAME);

      Charset charset = Charset.forName(encoding);

      CharsetEncoder encoder = charset.newEncoder();
      encoder.onMalformedInput(CodingErrorAction.REPLACE);
      encoder.onUnmappableCharacter(CodingErrorAction.REPORT);

      byte[] bytes;
      ByteBuffer byteBuffer = encoder.encode(CharBuffer.wrap(document.get()));
      if (byteBuffer.hasArray()) {
        bytes = byteBuffer.array();
      } else {
        bytes = new byte[byteBuffer.limit()];
        byteBuffer.get(bytes);
      }
      InputStream stream = new ByteArrayInputStream(bytes, 0, byteBuffer.limit());

      if (storage instanceof IFile) {
        IFile file = (IFile) storage;

        if (file.exists()) {

          // inform about the upcoming content change
          fireElementStateChanging(element);
          try {
            file.setContents(stream, true, true, monitor);
          } catch (CoreException x) {
            // inform about failure
            fireElementStateChangeFailed(element);
            throw x;
          } catch (RuntimeException x) {
            // inform about failure
            fireElementStateChangeFailed(element);
            throw x;
          }

        } else {
          try {
            monitor.beginTask("Save file '" + file.getName() + "'", 2000);
            // ContainerCreator creator = new ContainerCreator(file.getWorkspace(),
            // file.getParent().getFullPath());
            // creator.createContainer(new SubProgressMonitor(monitor, 1000));
            file.create(stream, false, monitor);
          } finally {
            monitor.done();
          }
        }
      } else if (storage instanceof IPersistentStorage) {
        monitor.beginTask("Save document", 1);
        ((IPersistentStorage) storage).setContents(monitor, stream);
      } else if (localFile != null) {
        try (OutputStream os = new FileOutputStream(localFile)) {
          IOUtils.copyStream(stream, os);
        }
      } else {
        throw new DBException("Storage [" + storage + "] doesn't support save");
      }
    } catch (Exception e) {
      if (e instanceof CoreException) {
        throw (CoreException) e;
      } else {
        throw new CoreException(GeneralUtils.makeExceptionStatus(e));
      }
    }
  }

  protected boolean setDocumentContent(IDocument document, IStorage storage) throws CoreException {
    try {
      InputStream contentStream = storage.getContents();
      try {
        String encoding =
            (storage instanceof IEncodedStorage
                ? ((IEncodedStorage) storage).getCharset()
                : GeneralUtils.getDefaultFileEncoding());
        setDocumentContent(document, contentStream, encoding);
      } finally {
        ContentUtils.close(contentStream);
      }
    } catch (IOException e) {
      throw new CoreException(GeneralUtils.makeExceptionStatus(e));
    }
    return true;
  }

  protected void setDocumentContent(IDocument document, InputStream contentStream, String encoding)
      throws IOException {
    Reader in = null;

    try {
      if (encoding == null) {
        encoding = GeneralUtils.DEFAULT_FILE_CHARSET_NAME;
      }

      in = new BufferedReader(new InputStreamReader(contentStream, encoding), DEFAULT_BUFFER_SIZE);
      StringBuilder buffer = new StringBuilder(DEFAULT_BUFFER_SIZE);
      char[] readBuffer = new char[2048];
      int n = in.read(readBuffer);
      while (n > 0) {
        buffer.append(readBuffer, 0, n);
        n = in.read(readBuffer);
      }

      document.set(buffer.toString());

    } finally {
      if (in != null) {
        ContentUtils.close(in);
      } else {
        ContentUtils.close(contentStream);
      }
    }
  }

  protected long computeModificationStamp(IResource resource) {
    long modificationStamp = resource.getModificationStamp();

    IPath path = resource.getLocation();
    if (path == null) {
      return modificationStamp;
    }

    modificationStamp = path.toFile().lastModified();
    return modificationStamp;
  }

  protected void refreshFile(IFile file) throws CoreException {
    refreshFile(file, getProgressMonitor());
  }

  @Override
  protected ElementInfo createElementInfo(Object element) throws CoreException {
    if (element instanceof IEditorInput) {

      IEditorInput input = (IEditorInput) element;
      IStorage storage = EditorUtils.getStorageFromInput(input);
      if (storage instanceof IFile) {
        IFile file = (IFile) storage;
        try {
          refreshFile(file);
        } catch (CoreException x) {
          log.warn("Can't refresh file", x);
        }

        IDocument d;
        IStatus s = null;

        try {
          d = createDocument(element);
        } catch (CoreException x) {
          log.warn("Can't create document", x);
          s = x.getStatus();
          d = createEmptyDocument();
        }

        // Set the initial line delimiter
        String initialLineDelimiter = GeneralUtils.getDefaultLineSeparator();
        if (initialLineDelimiter != null) {
          ((IDocumentExtension4) d).setInitialLineDelimiter(initialLineDelimiter);
        }

        IAnnotationModel m = createAnnotationModel(element);
        FileSynchronizer f = new FileSynchronizer(input);
        f.install();

        FileInfo info = new FileInfo(d, m, f);
        info.modificationStamp = computeModificationStamp(file);
        info.fStatus = s;

        return info;
      }
    }

    return super.createElementInfo(element);
  }

  @Override
  protected void disposeElementInfo(Object element, ElementInfo info) {
    if (info instanceof FileInfo) {
      FileInfo fileInfo = (FileInfo) info;
      if (fileInfo.fileSynchronizer != null) {
        fileInfo.fileSynchronizer.uninstall();
      }
    }

    super.disposeElementInfo(element, info);
  }

  protected void refreshFile(IFile file, IProgressMonitor monitor) throws CoreException {
    if (file != null) {
      try {
        file.refreshLocal(IResource.DEPTH_INFINITE, monitor);
      } catch (OperationCanceledException x) {
        // do nothing
      }
    }
  }

  /**
   * Updates the element info to a change of the file content and sends out appropriate
   * notifications.
   *
   * @param fileEditorInput the input of an text editor
   */
  protected void handleElementContentChanged(IEditorInput fileEditorInput) {
    FileInfo info = (FileInfo) getElementInfo(fileEditorInput);
    if (info == null) {
      return;
    }

    IStorage storage = EditorUtils.getStorageFromInput(fileEditorInput);
    if (storage instanceof IFile) {
      IFile file = (IFile) storage;
      IDocument document = createEmptyDocument();
      IStatus status = null;

      try {

        try {
          refreshFile(file);
        } catch (CoreException x) {
          log.error("handleElementContentChanged", x);
        }

        setDocumentContent(document, file);
      } catch (CoreException x) {
        status = x.getStatus();
      }

      String newContent = document.get();

      if (!newContent.equals(info.fDocument.get())) {

        // set the new content and fire content related events
        fireElementContentAboutToBeReplaced(fileEditorInput);

        removeUnchangedElementListeners(fileEditorInput, info);

        info.fDocument.removeDocumentListener(info);
        info.fDocument.set(newContent);
        info.fCanBeSaved = false;
        info.modificationStamp = computeModificationStamp(file);
        info.fStatus = status;

        addUnchangedElementListeners(fileEditorInput, info);

        fireElementContentReplaced(fileEditorInput);

      } else {

        removeUnchangedElementListeners(fileEditorInput, info);

        // fires only the dirty state related event
        info.fCanBeSaved = false;
        info.modificationStamp = computeModificationStamp(file);
        info.fStatus = status;

        addUnchangedElementListeners(fileEditorInput, info);

        fireElementDirtyStateChanged(fileEditorInput, false);
      }
    }
  }

  /**
   * Sends out the notification that the file serving as document input has been moved.
   *
   * @param fileEditorInput the input of an text editor
   * @param path the path of the new location of the file
   */
  protected void handleElementMoved(IEditorInput fileEditorInput, IPath path) {
    IWorkspace workspace = ResourcesPlugin.getWorkspace();
    IFile newFile = workspace.getRoot().getFile(path);
    fireElementMoved(fileEditorInput, createNewEditorInput(newFile));
  }

  /**
   * Sends out the notification that the file serving as document input has been deleted.
   *
   * @param fileEditorInput the input of an text editor
   */
  protected void handleElementDeleted(IEditorInput fileEditorInput) {
    fireElementDeleted(fileEditorInput);
  }

  protected abstract class SafeChange implements Runnable {

    private IEditorInput editorInput;

    public SafeChange(IEditorInput input) {
      editorInput = input;
    }

    protected abstract void execute(IEditorInput input) throws Exception;

    @Override
    public void run() {

      if (getElementInfo(editorInput) == null) {
        fireElementStateChangeFailed(editorInput);
        return;
      }
      try {
        execute(editorInput);
      } catch (Exception e) {
        fireElementStateChangeFailed(editorInput);
      }
    }
  }

  /** Synchronizes the document with external resource changes. */
  protected class FileSynchronizer implements IResourceChangeListener, IResourceDeltaVisitor {

    protected IEditorInput fileEditorInput;
    protected boolean isInstalled = false;

    /**
     * Creates a new file synchronizer. Is not yet installed on a resource.
     *
     * @param fileEditorInput the editor input to be synchronized
     */
    public FileSynchronizer(IEditorInput fileEditorInput) {
      this.fileEditorInput = fileEditorInput;
    }

    /**
     * Returns the file wrapped by the file editor input.
     *
     * @return the file wrapped by the editor input associated with that synchronizer
     */
    protected IFile getFile() {
      IStorage storage = EditorUtils.getStorageFromInput(fileEditorInput);
      return storage instanceof IFile ? (IFile) storage : null;
    }

    /** Installs the synchronizer on the input's file. */
    public void install() {
      getFile().getWorkspace().addResourceChangeListener(this);
      isInstalled = true;
    }

    /** Uninstalls the synchronizer from the input's file. */
    public void uninstall() {
      getFile().getWorkspace().removeResourceChangeListener(this);
      isInstalled = false;
    }

    @Override
    public void resourceChanged(IResourceChangeEvent e) {
      IResourceDelta delta = e.getDelta();
      try {
        if (delta != null && isInstalled) {
          delta.accept(this);
        }
      } catch (CoreException x) {
        log.warn("Error handling resourceChanged", x);
      }
    }

    @Override
    public boolean visit(IResourceDelta delta) throws CoreException {
      if (delta == null) {
        return false;
      }

      IFile file = getFile();
      if (file == null) {
        return false;
      }

      delta = delta.findMember(file.getFullPath());

      if (delta == null) {
        return false;
      }

      Runnable runnable = null;

      switch (delta.getKind()) {
        case IResourceDelta.CHANGED:
          FileInfo info = (FileInfo) getElementInfo(fileEditorInput);
          if (info == null || !canRefreshFromFile(info)) {
            break;
          }

          boolean isSynchronized = computeModificationStamp(file) == info.modificationStamp;
          if ((IResourceDelta.ENCODING & delta.getFlags()) != 0 && isSynchronized) {
            runnable =
                new SafeChange(fileEditorInput) {
                  @Override
                  protected void execute(IEditorInput input) throws Exception {
                    handleElementContentChanged(input);
                  }
                };
          }

          if (runnable == null
              && (IResourceDelta.CONTENT & delta.getFlags()) != 0
              && !isSynchronized) {
            runnable =
                new SafeChange(fileEditorInput) {
                  @Override
                  protected void execute(IEditorInput input) throws Exception {
                    handleElementContentChanged(input);
                  }
                };
          }
          break;

        case IResourceDelta.REMOVED:
          if ((IResourceDelta.MOVED_TO & delta.getFlags()) != 0) {
            final IPath path = delta.getMovedToPath();
            runnable =
                new SafeChange(fileEditorInput) {
                  @Override
                  protected void execute(IEditorInput input) throws Exception {
                    handleElementMoved(input, path);
                  }
                };
          } else {
            info = (FileInfo) getElementInfo(fileEditorInput);
            if (info != null && canRefreshFromFile(info)) {
              runnable =
                  new SafeChange(fileEditorInput) {
                    @Override
                    protected void execute(IEditorInput input) throws Exception {
                      handleElementDeleted(input);
                    }
                  };
            }
          }
          break;
      }

      if (runnable != null) {
        update(runnable);
      }

      return false;
    }

    private boolean canRefreshFromFile(FileInfo info) {
      // return !info.fCanBeSaved;
      return true;
    }

    /**
     * Posts the update code "behind" the running operation.
     *
     * @param runnable the update code
     */
    protected void update(Runnable runnable) {

      if (runnable instanceof SafeChange) {
        fireElementStateChanging(fileEditorInput);
      }

      IWorkbench workbench = PlatformUI.getWorkbench();
      IWorkbenchWindow[] windows = workbench.getWorkbenchWindows();
      if (windows != null && windows.length > 0) {
        Display display = windows[0].getShell().getDisplay();
        display.asyncExec(runnable);
      } else {
        runnable.run();
      }
    }
  }

  /** Bundle of all required information to allow files as underlying document resources. */
  protected class FileInfo extends ElementInfo {

    /** The file synchronizer. */
    public FileSynchronizer fileSynchronizer;
    /** The time stamp at which this provider changed the file. */
    public long modificationStamp = IResource.NULL_STAMP;

    public FileInfo(IDocument document, IAnnotationModel model, FileSynchronizer fileSynchronizer) {
      super(document, model);
      this.fileSynchronizer = fileSynchronizer;
    }
  }
}
/**
 * Holds and cache current user privileges and authorities
 *
 * @author Denis Forveille
 */
public class DB2CurrentUserPrivileges {

  private static final Log LOG = Log.getLog(DB2CurrentUserPrivileges.class);

  private static final String SYSMON = "SYSMON";
  private static final String SYSMAINT = "SYSMAINT";
  private static final String SYSADM = "SYSADM";
  private static final String SYSCTRL = "SYSCTRL";
  private static final String DATAACCESS = "DATAACCESS";
  private static final String DBADM = "DBADM";
  private static final String SQLADM = "SQLADM";

  private static final String AUTH_APP = "T:SYSIBMADM.APPLICATIONS";
  private static final String AUTH_DBCFG = "T:SYSIBMADM.DBCFG";
  private static final String AUTH_CONTAINER = "R:SYSPROC.SNAP_GET_CONTAINER";

  private static final String SEL_AUTHORITIES;

  static {
    StringBuilder sb = new StringBuilder(256);
    sb.append("SELECT AUTHORITY");
    sb.append("  FROM TABLE (SYSPROC.AUTH_LIST_AUTHORITIES_FOR_AUTHID (?, 'U')) AS T ");
    sb.append(" WHERE 'Y' IN (D_USER,D_GROUP,D_PUBLIC,ROLE_USER,ROLE_GROUP,ROLE_PUBLIC,D_ROLE)");
    sb.append(" WITH UR");
    SEL_AUTHORITIES = sb.toString();
  }

  private static final String SEL_OBJECTS;

  static {
    StringBuilder sb = new StringBuilder(512);
    sb.append("SELECT 'R:' || TRIM(SCHEMA) || '.' || SPECIFICNAME");
    sb.append("  FROM SYSCAT.ROUTINEAUTH");
    sb.append(
        " WHERE ((GRANTEETYPE = 'G' AND GRANTEE = 'PUBLIC') OR (GRANTEETYPE = 'U' AND GRANTEE = ?)) ");
    sb.append(
        "   AND (SCHEMA = 'SYSPROC' AND SPECIFICNAME = 'SNAP_GET_CONTAINER' AND EXECUTEAUTH IN ('Y','G'))");

    sb.append(" UNION ALL ");

    sb.append("SELECT DISTINCT 'T:' || TRIM(TABSCHEMA) || '.' ||TABNAME");
    sb.append("  FROM SYSCAT.TABAUTH");
    sb.append(
        " WHERE ((GRANTEETYPE = 'G' AND GRANTEE = 'PUBLIC') OR (GRANTEETYPE = 'U' AND GRANTEE = ?))");
    sb.append("   AND (");
    sb.append(
        "        (TABSCHEMA = 'SYSIBMADM' AND TABNAME = 'APPLICATIONS' AND 'Y' IN (CONTROLAUTH,SELECTAUTH))");
    sb.append(
        "     OR (TABSCHEMA = 'SYSIBMADM' AND TABNAME = 'DBCFG' AND 'Y' IN (CONTROLAUTH,SELECTAUTH))");
    sb.append("       )");
    sb.append(" WITH UR");
    SEL_OBJECTS = sb.toString();
  }

  private final List<String> listAuthorities;
  private final List<String> listObjectPrivileges;

  private final Boolean userIsAuthorisedForApplications;
  private final Boolean userIsAuthorisedForContainers;
  private final Boolean userIsAuthorisedForDBCFG;
  private final Boolean userIsAuthorisedForAdminister;

  // ------------------------
  // Constructors
  // ------------------------
  public DB2CurrentUserPrivileges(
      DBRProgressMonitor monitor,
      JDBCSession session,
      String currentAuthId,
      DB2DataSource db2DataSource)
      throws SQLException {
    // DF: There is no easy way to get this information from DB2 v9.1
    // WE consider the user has no system authorities
    listAuthorities = new ArrayList<>();
    if (db2DataSource.isAtLeastV9_5()) {
      try (JDBCPreparedStatement dbStat = session.prepareStatement(SEL_AUTHORITIES)) {
        dbStat.setString(1, currentAuthId);
        try (JDBCResultSet dbResult = dbStat.executeQuery()) {
          while (dbResult.next()) {
            listAuthorities.add(dbResult.getString(1));
          }
        }
      }
    }

    listObjectPrivileges = new ArrayList<>();
    try (JDBCPreparedStatement dbStat = session.prepareStatement(SEL_OBJECTS)) {
      dbStat.setString(1, currentAuthId);
      dbStat.setString(2, currentAuthId);
      try (JDBCResultSet dbResult = dbStat.executeQuery()) {
        while (dbResult.next()) {
          listObjectPrivileges.add(dbResult.getString(1));
        }
      }
    }

    // Cache Authorities
    userIsAuthorisedForApplications = computeUserIsAuthorisedForApplications();
    userIsAuthorisedForDBCFG = computeUserIsAuthorisedForDBCFG();
    userIsAuthorisedForAdminister = userIsAuthorisedForApplications || userIsAuthorisedForDBCFG;

    userIsAuthorisedForContainers = computeUserIsAuthorisedForContainers();
  }

  // ------------------------
  // Standard Getters
  // ------------------------

  public Boolean userIsAuthorisedForApplications() {
    return userIsAuthorisedForApplications;
  }

  public Boolean userIsAuthorisedForContainers() {
    return userIsAuthorisedForContainers;
  }

  public Boolean userIsAuthorisedForDBCFG() {
    return userIsAuthorisedForDBCFG;
  }

  public Boolean userIsAuthorisedForAdminister() {
    return userIsAuthorisedForAdminister;
  }

  // -------
  // Helpers
  // -------

  private Boolean computeUserIsAuthorisedForApplications() {
    // Must have one of SYSMON, SYSMAINT, SYSADM or SYSCTRL

    if ((listAuthorities.contains(SYSMON))
        || (listAuthorities.contains(SYSMAINT))
        || (listAuthorities.contains(SYSADM))
        || (listAuthorities.contains(SYSCTRL))) {

      // Plus one of DATAACCESS or DBADM or SQLADM or SELECT on SYSIBMADM.APPLICATIONS or CONTROL on
      // SYSIBMADM.APPLICATIONS
      if ((listAuthorities.contains(DATAACCESS))
          || (listAuthorities.contains(DBADM))
          || (listAuthorities.contains(SQLADM))) {
        return true;
      }
      if (listObjectPrivileges.contains(AUTH_APP)) {
        return true;
      }
    }

    LOG.debug("Current User is not authorized to see Applications");
    return false;
  }

  private Boolean computeUserIsAuthorisedForContainers() {
    // Must have one of SYSMON, SYSMAINT, SYSADM or SYSCTRL
    if ((listAuthorities.contains(SYSMON))
        || (listAuthorities.contains(SYSMAINT))
        || (listAuthorities.contains(SYSADM))
        || (listAuthorities.contains(SYSCTRL))) {

      // Plus one of DATAACCESS or EXECUTE on SYSPROC.SNAP_GET_CONTAINER
      if (listAuthorities.contains(DATAACCESS)) {
        return true;
      }
      if (listObjectPrivileges.contains(AUTH_CONTAINER)) {
        return true;
      }
    }

    LOG.debug("Current User is not authorized to see Tablespaces Containers");
    return false;
  }

  private Boolean computeUserIsAuthorisedForDBCFG() {
    // Must have one of DATAACCESS, DBADM, SQLADM or or SELECT on SYSIBMADM.APPLICATIONS or CONTROL
    // on SYSIBMADM.APPLICATIONS
    if ((listAuthorities.contains(DATAACCESS))
        || (listAuthorities.contains(DBADM))
        || (listAuthorities.contains(SQLADM))) {
      return true;
    }
    if (listObjectPrivileges.contains(AUTH_DBCFG)) {
      return true;
    }

    LOG.debug("Current User is not authorized to see DB/DBM Configuration Parameters");
    return false;
  }
}
/**
 * The SQL content assist processor. This content assist processor proposes text completions and
 * computes context information for a SQL content type.
 */
public class SQLCompletionProcessor implements IContentAssistProcessor {
  static final Log log = Log.getLog(SQLCompletionProcessor.class);

  private enum QueryType {
    TABLE,
    COLUMN
  }

  private SQLEditorBase editor;
  private IContextInformationValidator validator = new Validator();
  private int documentOffset;
  private String activeQuery = null;
  private SQLWordPartDetector wordDetector;
  private static boolean lookupTemplates = false;

  public SQLCompletionProcessor(SQLEditorBase editor) {
    this.editor = editor;
  }

  public static boolean isLookupTemplates() {
    return lookupTemplates;
  }

  public static void setLookupTemplates(boolean lookupTemplates) {
    SQLCompletionProcessor.lookupTemplates = lookupTemplates;
  }

  /**
   * 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()]);
  }

  @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()]);
  }

  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);
    }
  }

  private void makeStructureProposals(
      DBRProgressMonitor monitor, DBPDataSource dataSource, List<SQLCompletionProposal> proposals) {
    final DBSObjectContainer rootContainer =
        DBUtils.getAdapter(DBSObjectContainer.class, dataSource);
    if (rootContainer == null) {
      return;
    }
    DBSObjectContainer selectedContainer = null;
    {
      DBSObject selectedObject = getSelectedObject(dataSource);
      if (selectedObject != null) {
        selectedContainer = DBUtils.getAdapter(DBSObjectContainer.class, selectedObject);
      }
    }

    DBSObjectContainer sc = rootContainer;
    DBSObject childObject = sc;
    List<String> tokens = wordDetector.splitWordPart();

    String lastToken = null;
    for (int i = 0; i < tokens.size(); i++) {
      String token = tokens.get(i);
      if (i == tokens.size() - 1 && !wordDetector.getWordPart().endsWith(".")) {
        lastToken = token;
        break;
      }
      if (sc == null) {
        break;
      }
      // Get next structure container
      try {
        String objectName = DBObjectNameCaseTransformer.transformName(dataSource, token);
        childObject = sc.getChild(monitor, objectName);
        if (childObject == null && i == 0 && selectedContainer != null) {
          // Probably it is from selected object, let's try it
          childObject = selectedContainer.getChild(monitor, objectName);
          if (childObject != null) {
            sc = selectedContainer;
          }
        }
        if (childObject == null) {
          if (i == 0) {
            // Assume it's a table alias ?
            childObject = this.getTableFromAlias(monitor, sc, token);
            if (childObject == null) {
              DBSStructureAssistant structureAssistant =
                  DBUtils.getAdapter(DBSStructureAssistant.class, sc);
              if (structureAssistant != null) {
                Collection<DBSObjectReference> references =
                    structureAssistant.findObjectsByMask(
                        monitor,
                        null,
                        structureAssistant.getAutoCompleteObjectTypes(),
                        wordDetector.removeQuotes(token),
                        wordDetector.isQuoted(token),
                        2);
                if (!references.isEmpty()) {
                  childObject = references.iterator().next().resolveObject(monitor);
                }
              }
            }
          } else {
            // Path element not found. Damn - can't do anything.
            return;
          }
        }

        if (childObject instanceof DBSObjectContainer) {
          sc = (DBSObjectContainer) childObject;
        } else {
          sc = null;
        }
      } catch (DBException e) {
        log.error(e);
        return;
      }
    }
    if (childObject == null) {
      return;
    }
    if (lastToken == null) {
      // Get all children objects as proposals
      makeProposalsFromChildren(monitor, childObject, null, proposals);
    } else {
      // Get matched children
      makeProposalsFromChildren(monitor, childObject, lastToken, proposals);
      if (proposals.isEmpty() || tokens.size() == 1) {
        // At last - try to find child tables by pattern
        DBSStructureAssistant structureAssistant = null;
        for (DBSObject object = childObject; object != null; object = object.getParentObject()) {
          structureAssistant = DBUtils.getAdapter(DBSStructureAssistant.class, object);
          if (structureAssistant != null) {
            break;
          }
        }
        if (structureAssistant != null) {
          makeProposalsFromAssistant(monitor, structureAssistant, sc, lastToken, proposals);
        }
      }
    }
  }

  @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;
    }
  }

  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 void makeProposalsFromAssistant(
      DBRProgressMonitor monitor,
      DBSStructureAssistant assistant,
      @Nullable DBSObjectContainer rootSC,
      String objectName,
      List<SQLCompletionProposal> proposals) {
    try {
      Collection<DBSObjectReference> references =
          assistant.findObjectsByMask(
              monitor,
              rootSC,
              assistant.getAutoCompleteObjectTypes(),
              wordDetector.removeQuotes(objectName) + "%",
              wordDetector.isQuoted(objectName),
              100);
      for (DBSObjectReference reference : references) {
        proposals.add(makeProposalsFromObject(reference, reference.getObjectType().getImage()));
      }
    } catch (DBException e) {
      log.error(e);
    }
  }

  private SQLCompletionProposal makeProposalsFromObject(
      DBRProgressMonitor monitor, DBSObject object) {
    DBNNode node =
        DBeaverCore.getInstance().getNavigatorModel().getNodeByObject(monitor, object, false);
    return makeProposalsFromObject(object, node == null ? null : node.getNodeIconDefault());
  }

  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 DBPPreferenceStore getPreferences() {
    DBPPreferenceStore store = null;
    DBPDataSource dataSource = editor.getDataSource();
    if (dataSource != null) {
      store = dataSource.getContainer().getPreferenceStore();
    }
    if (store == null) {
      store = DBeaverCore.getGlobalPreferenceStore();
    }
    return store;
  }

  /*
   * 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);
  }

  /**
   * 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;
  }

  @Override
  public char[] getCompletionProposalAutoActivationCharacters() {
    return new char[] {'.'};
  }

  @Nullable
  @Override
  public char[] getContextInformationAutoActivationCharacters() {
    return null;
  }

  @Nullable
  @Override
  public String getErrorMessage() {
    return null;
  }

  @Override
  public IContextInformationValidator getContextInformationValidator() {
    return validator;
  }

  @Nullable
  private static DBSObject getSelectedObject(DBPDataSource dataSource) {
    DBSObjectSelector objectSelector = DBUtils.getAdapter(DBSObjectSelector.class, dataSource);
    if (objectSelector != null) {
      return objectSelector.getSelectedObject();
    }
    return null;
  }

  /**
   * Simple content assist tip closer. The tip is valid in a range of 5 characters around its popup
   * location.
   */
  protected static class Validator
      implements IContextInformationValidator, IContextInformationPresenter {

    protected int fInstallOffset;

    @Override
    public boolean isContextInformationValid(int offset) {
      return Math.abs(fInstallOffset - offset) < 5;
    }

    @Override
    public void install(IContextInformation info, ITextViewer viewer, int offset) {
      fInstallOffset = offset;
    }

    @Override
    public boolean updatePresentation(int documentPosition, TextPresentation presentation) {
      return false;
    }
  }
}
/** DataTransferSettings */
public class DataTransferSettings {

  private static final Log log = Log.getLog(DataTransferSettings.class);

  private static final int DEFAULT_THREADS_NUM = 1;

  public static class NodeSettings {
    DataTransferNodeDescriptor sourceNode;
    IDataTransferSettings settings;
    IWizardPage[] pages;

    private NodeSettings(DataTransferNodeDescriptor sourceNode) throws DBException {
      this.sourceNode = sourceNode;
      this.settings = sourceNode.createSettings();
      this.pages = sourceNode.createWizardPages();
    }
  }

  private List<DataTransferPipe> dataPipes;

  private DataTransferNodeDescriptor producer;
  private DataTransferNodeDescriptor consumer;

  private DataTransferProcessorDescriptor processor;
  private Map<DataTransferProcessorDescriptor, Map<Object, Object>> processorPropsHistory =
      new HashMap<>();

  private Map<Class, NodeSettings> nodeSettings = new LinkedHashMap<>();

  private boolean consumerOptional;
  private int maxJobCount = DEFAULT_THREADS_NUM;

  private transient int curPipeNum = 0;

  public DataTransferSettings(
      @Nullable IDataTransferProducer[] producers, @Nullable IDataTransferConsumer[] consumers) {
    dataPipes = new ArrayList<>();
    if (!ArrayUtils.isEmpty(producers) && !ArrayUtils.isEmpty(consumers)) {
      if (producers.length != consumers.length) {
        throw new IllegalArgumentException("Producers number must match consumers number");
      }
      // Make pipes
      for (int i = 0; i < producers.length; i++) {
        dataPipes.add(new DataTransferPipe(producers[i], consumers[i]));
      }
      consumerOptional = false;
    } else if (!ArrayUtils.isEmpty(producers)) {
      // Make pipes
      for (IDataTransferProducer source : producers) {
        dataPipes.add(new DataTransferPipe(source, null));
      }
      // Set default producer
      Class<? extends IDataTransferProducer> producerType =
          dataPipes.get(0).getProducer().getClass();
      DataTransferNodeDescriptor producerDesc =
          DataTransferRegistry.getInstance().getNodeByType(producerType);
      if (producerDesc != null) {
        selectProducer(producerDesc);
        consumerOptional = true;
      } else {
        UIUtils.showErrorDialog(
            null, "Can't find producer", "Can't find data propducer descriptor in registry");
      }
    } else if (!ArrayUtils.isEmpty(consumers)) {
      // Make pipes
      for (IDataTransferConsumer target : consumers) {
        dataPipes.add(new DataTransferPipe(null, target));
      }
      // Set default consumer
      Class<? extends IDataTransferConsumer> consumerType =
          dataPipes.get(0).getConsumer().getClass();
      DataTransferNodeDescriptor consumerDesc =
          DataTransferRegistry.getInstance().getNodeByType(consumerType);
      if (consumerDesc != null) {
        selectConsumer(consumerDesc, null);
        consumerOptional = false;
      } else {
        UIUtils.showErrorDialog(
            null, "Can't find producer", "Can't find data propducer descriptor in registry");
      }
    } else {
      throw new IllegalArgumentException("Producers or consumers must be specified");
    }

    Collection<Class<?>> objectTypes = getObjectTypes();
    List<DataTransferNodeDescriptor> nodes = new ArrayList<>();
    DataTransferRegistry registry = DataTransferRegistry.getInstance();
    if (ArrayUtils.isEmpty(producers)) {
      nodes.addAll(registry.getAvailableProducers(objectTypes));
    } else {
      for (IDataTransferProducer source : producers) {
        DataTransferNodeDescriptor node = registry.getNodeByType(source.getClass());
        if (node != null && !nodes.contains(node)) {
          nodes.add(node);
        }
      }
    }
    if (ArrayUtils.isEmpty(consumers)) {
      nodes.addAll(registry.getAvailableConsumers(objectTypes));
    } else {
      for (IDataTransferConsumer target : consumers) {
        DataTransferNodeDescriptor node = registry.getNodeByType(target.getClass());
        if (node != null && !nodes.contains(node)) {
          nodes.add(node);
          this.consumer = node;
        }
      }
    }
    for (DataTransferNodeDescriptor node : nodes) {
      addNodeSettings(node);
    }
  }

  private void addNodeSettings(DataTransferNodeDescriptor node) {
    if (node == null) {
      return;
    }
    Class<? extends IDataTransferNode> nodeClass = node.getNodeClass();
    if (nodeSettings.containsKey(nodeClass)) {
      return;
    }
    try {
      nodeSettings.put(nodeClass, new NodeSettings(node));
    } catch (DBException e) {
      log.error("Can't add node '" + node.getId() + "'", e);
    }
  }

  void addWizardPages(DataTransferWizard wizard) {
    for (NodeSettings nodeSettings : this.nodeSettings.values()) {
      if (nodeSettings.pages != null) {
        for (IWizardPage page : nodeSettings.pages) {
          wizard.addPage(page);
        }
      }
    }
  }

  public boolean isConsumerOptional() {
    return consumerOptional;
  }

  public boolean isPageValid(IWizardPage page) {
    return isPageValid(page, producer) || isPageValid(page, consumer);
  }

  private boolean isPageValid(IWizardPage page, DataTransferNodeDescriptor node) {
    NodeSettings nodeSettings = node == null ? null : this.nodeSettings.get(node.getNodeClass());
    return nodeSettings != null && ArrayUtils.contains(nodeSettings.pages, page);
  }

  public Collection<Class<?>> getObjectTypes() {
    List<DataTransferPipe> dataPipes = getDataPipes();
    Set<Class<?>> objectTypes = new HashSet<>();
    for (DataTransferPipe transferPipe : dataPipes) {
      if (transferPipe.getProducer() != null) {
        objectTypes.add(transferPipe.getProducer().getSourceObject().getClass());
      }
    }
    return objectTypes;
  }

  public IDataTransferSettings getNodeSettings(IWizardPage page) {
    for (NodeSettings nodeSettings : this.nodeSettings.values()) {
      if (nodeSettings.pages != null) {
        for (IWizardPage nodePage : nodeSettings.pages) {
          if (nodePage == page) {
            return nodeSettings.settings;
          }
        }
      }
    }
    return null;
  }

  public IDataTransferSettings getNodeSettings(IDataTransferNode node) {
    NodeSettings nodeSettings = this.nodeSettings.get(node.getClass());
    return nodeSettings == null ? null : nodeSettings.settings;
  }

  public Map<Object, Object> getProcessorProperties() {
    if (processor == null) {
      throw new IllegalStateException("No processor selected");
    }
    return processorPropsHistory.get(processor);
  }

  public void setProcessorProperties(Map<Object, Object> properties) {
    if (processor == null) {
      throw new IllegalStateException("No processor selected");
    }
    processorPropsHistory.put(processor, properties);
  }

  public List<DataTransferPipe> getDataPipes() {
    return dataPipes;
  }

  public synchronized DataTransferPipe acquireDataPipe(DBRProgressMonitor monitor) {
    if (curPipeNum >= dataPipes.size()) {
      // End of transfer
      // Signal last pipe about it
      if (!dataPipes.isEmpty()) {
        dataPipes.get(dataPipes.size() - 1).getConsumer().finishTransfer(monitor, true);
      }
      return null;
    }

    DataTransferPipe result = dataPipes.get(curPipeNum);

    curPipeNum++;
    return result;
  }

  public DataTransferNodeDescriptor getProducer() {
    return producer;
  }

  public DataTransferNodeDescriptor getConsumer() {
    return consumer;
  }

  public DataTransferProcessorDescriptor getProcessor() {
    return processor;
  }

  private void selectProducer(DataTransferNodeDescriptor producer) {
    this.producer = producer;
  }

  void selectConsumer(
      DataTransferNodeDescriptor consumer, DataTransferProcessorDescriptor processor) {
    this.consumer = consumer;
    this.processor = processor;
    if (consumer != null && processor != null) {
      if (!processorPropsHistory.containsKey(processor)) {
        processorPropsHistory.put(processor, new HashMap<>());
      }
    }
    // Configure pipes
    for (DataTransferPipe pipe : dataPipes) {
      if (consumer != null) {
        try {
          pipe.setConsumer((IDataTransferConsumer) consumer.createNode());
        } catch (DBException e) {
          log.error(e);
          pipe.setConsumer(null);
        }
      } else {
        pipe.setConsumer(null);
      }
    }
  }

  public int getMaxJobCount() {
    return maxJobCount;
  }

  public void setMaxJobCount(int maxJobCount) {
    if (maxJobCount > 0) {
      this.maxJobCount = maxJobCount;
    }
  }

  void loadFrom(IRunnableContext runnableContext, IDialogSettings dialogSettings) {
    try {
      maxJobCount = dialogSettings.getInt("maxJobCount");
    } catch (NumberFormatException e) {
      maxJobCount = DEFAULT_THREADS_NUM;
    }
    String producerId = dialogSettings.get("producer");
    if (!CommonUtils.isEmpty(producerId)) {
      DataTransferNodeDescriptor producerNode =
          DataTransferRegistry.getInstance().getNodeById(producerId);
      if (producerNode != null) {
        this.producer = producerNode;
      }
    }

    if (consumerOptional) {
      DataTransferNodeDescriptor savedConsumer = null;
      String consumerId = dialogSettings.get("consumer");
      if (!CommonUtils.isEmpty(consumerId)) {
        DataTransferNodeDescriptor consumerNode =
            DataTransferRegistry.getInstance().getNodeById(consumerId);
        if (consumerNode != null) {
          savedConsumer = consumerNode;
        }
      }

      DataTransferProcessorDescriptor savedProcessor = null;
      if (savedConsumer != null) {
        String processorId = dialogSettings.get("processor");
        if (!CommonUtils.isEmpty(processorId)) {
          savedProcessor = savedConsumer.getProcessor(processorId);
        }
      }
      if (savedConsumer != null) {
        selectConsumer(savedConsumer, savedProcessor);
      }
    }

    // Load nodes' settings
    for (Map.Entry<Class, NodeSettings> entry : nodeSettings.entrySet()) {
      IDialogSettings nodeSection =
          DialogSettings.getOrCreateSection(dialogSettings, entry.getKey().getSimpleName());
      entry.getValue().settings.loadSettings(runnableContext, this, nodeSection);
    }
    IDialogSettings processorsSection = dialogSettings.getSection("processors");
    if (processorsSection != null) {
      for (IDialogSettings procSection : ArrayUtils.safeArray(processorsSection.getSections())) {
        String processorId = procSection.getName();
        String nodeId = procSection.get("@node");
        String propNamesId = procSection.get("@propNames");
        DataTransferNodeDescriptor node = DataTransferRegistry.getInstance().getNodeById(nodeId);
        if (node != null) {
          Map<Object, Object> props = new HashMap<>();
          DataTransferProcessorDescriptor nodeProcessor = node.getProcessor(processorId);
          if (nodeProcessor != null) {
            for (String prop : CommonUtils.splitString(propNamesId, ',')) {
              props.put(prop, procSection.get(prop));
            }
            processorPropsHistory.put(nodeProcessor, props);
            NodeSettings nodeSettings = this.nodeSettings.get(node.getNodeClass());
            if (nodeSettings != null) {}
          }
        }
      }
    }
  }

  void saveTo(IDialogSettings dialogSettings) {
    dialogSettings.put("maxJobCount", maxJobCount);
    // Save nodes' settings
    for (Map.Entry<Class, NodeSettings> entry : nodeSettings.entrySet()) {
      IDialogSettings nodeSection =
          DialogSettings.getOrCreateSection(dialogSettings, entry.getKey().getSimpleName());
      entry.getValue().settings.saveSettings(nodeSection);
    }

    if (producer != null) {
      dialogSettings.put("producer", producer.getId());
    }
    if (consumer != null) {
      dialogSettings.put("consumer", consumer.getId());
    }
    if (processor != null) {
      dialogSettings.put("processor", processor.getId());
    }

    // Save processors' properties
    IDialogSettings processorsSection =
        DialogSettings.getOrCreateSection(dialogSettings, "processors");
    for (DataTransferProcessorDescriptor procDescriptor : processorPropsHistory.keySet()) {
      IDialogSettings procSettings =
          DialogSettings.getOrCreateSection(processorsSection, procDescriptor.getId());
      procSettings.put("@node", procDescriptor.getNode().getId());
      Map<Object, Object> props = processorPropsHistory.get(procDescriptor);
      if (props != null) {
        StringBuilder propNames = new StringBuilder();
        for (Map.Entry<Object, Object> prop : props.entrySet()) {
          propNames.append(prop.getKey()).append(',');
        }
        procSettings.put("@propNames", propNames.toString());
        for (Map.Entry<Object, Object> prop : props.entrySet()) {
          procSettings.put(
              CommonUtils.toString(prop.getKey()), CommonUtils.toString(prop.getValue()));
        }
      }
    }
  }
}