@Override
  protected void doExecute() throws Exception {
    final boolean permission = config.getBoolean(getPropertyName("permission.upgrade-db"), false);
    if (!permission) {
      throw new MojoExecutionException("No permission to run this task!");
    }

    final Map<String, String> databases = extractDatabases(migrations);

    for (Map.Entry<String, String> database : databases.entrySet()) {
      final String databaseName = database.getKey();

      final DBIConfig databaseConfig = getDBIConfigFor(databaseName);
      final DBI rootDbDbi =
          new DBI(
              databaseConfig.getDBUrl(), rootDBIConfig.getDBUser(), rootDBIConfig.getDBPassword());
      final DBI dbi = getDBIFor(databaseName);

      try {
        final MigrationPlan rootMigrationPlan = createMigrationPlan(database);
        if (!rootMigrationPlan.isEmpty()) {
          LOG.info("Migrating {} ...", databaseName);

          Migratory migratory = new Migratory(migratoryConfig, dbi, rootDbDbi);
          migratory.addLocator(new MojoLocator(migratory, manifestUrl));
          migratory.dbMigrate(rootMigrationPlan, optionList);
        }
      } catch (MigratoryException me) {
        LOG.warn(
            String.format(
                "While creating '%s': %s, Reason: %s",
                databaseName, me.getMessage(), me.getReason()));
      }
      LOG.info("... done");
    }
  }
  @Override
  protected void doExecute() throws Exception {
    final List<String> databaseList = expandDatabaseList(databases);

    final boolean permission = config.getBoolean(getPropertyName("permission.create-db"), false);
    if (!permission) {
      throw new MojoExecutionException("No permission to run this task!");
    }

    final DBI rootDbi = getDBIFor(rootDBIConfig);

    final StatementLocator statementLocator =
        new TemplatingStatementLocator("/sql/", loaderManager);
    rootDbi.setStatementLocator(statementLocator);

    for (final String database : databaseList) {
      final DBIConfig databaseConfig = getDBIConfigFor(database);
      final String user = databaseConfig.getDBUser();

      // Language and schema creation runs as root user, but connected to the actual database.
      final DBI rootDbDbi =
          new DBI(
              databaseConfig.getDBUrl(), rootDBIConfig.getDBUser(), rootDBIConfig.getDBPassword());
      rootDbDbi.setStatementLocator(statementLocator);

      if (MigratoryOption.containsOption(MigratoryOption.DRY_RUN, optionList)) {
        CONSOLE.info("Dry run for database {} activated!", database);
      } else {
        // User and Database creation runs as root user connected to the root db
        try {
          boolean userExists =
              rootDbi.withHandle(
                  new HandleCallback<Boolean>() {
                    @Override
                    public Boolean withHandle(final Handle handle) {
                      return handle
                              .createQuery("#mojo:detect_user")
                              .bind("user", user)
                              .map(IntegerMapper.FIRST)
                              .first()
                          != 0;
                    }
                  });

          if (userExists) {
            CONSOLE.info("... User {} already exists ...", user);
          } else {
            CONSOLE.info("... creating User {} ...", user);

            rootDbi.withHandle(
                new HandleCallback<Void>() {
                  @Override
                  public Void withHandle(final Handle handle) {
                    handle
                        .createStatement("#mojo:create_user")
                        .define("user", user)
                        .define("password", databaseConfig.getDBPassword())
                        .execute();
                    return null;
                  }
                });
          }

          boolean databaseExists =
              rootDbi.withHandle(
                  new HandleCallback<Boolean>() {
                    @Override
                    public Boolean withHandle(final Handle handle) {
                      return handle
                              .createQuery("#mojo:detect_database")
                              .bind("database", database)
                              .map(IntegerMapper.FIRST)
                              .first()
                          != 0;
                    }
                  });

          if (databaseExists) {
            CONSOLE.info("... Database {} already exists ...", database);
          } else {
            CONSOLE.info("... creating Database {}...", database);

            final String tablespace;

            if (databaseConfig.getDBTablespace() != null) {
              boolean tablespaceExists =
                  rootDbi.withHandle(
                      new HandleCallback<Boolean>() {
                        @Override
                        public Boolean withHandle(final Handle handle) {
                          return handle
                                  .createQuery("#mojo:detect_tablespace")
                                  .bind("table_space", databaseConfig.getDBTablespace())
                                  .map(IntegerMapper.FIRST)
                                  .first()
                              != 0;
                        }
                      });

              if (tablespaceExists) {
                tablespace = databaseConfig.getDBTablespace();
              } else {
                CONSOLE.warn(
                    "Tablespace '{}' does not exist, falling back to default!",
                    databaseConfig.getDBTablespace());
                tablespace = null;
              }
            } else {
              tablespace = null;
            }

            rootDbi.withHandle(
                new HandleCallback<Void>() {
                  @Override
                  public Void withHandle(final Handle handle) {
                    handle
                        .createStatement("#mojo:create_database")
                        .define("database", database)
                        .define("owner", databaseConfig.getDBUser())
                        .define("tablespace", tablespace)
                        .execute();
                    return null;
                  }
                });
          }

        } catch (DBIException de) {
          throw new MojoExecutionException(String.format("While creating %s", database), de);
        }

        try {
          boolean languageExists =
              rootDbDbi.withHandle(
                  new HandleCallback<Boolean>() {
                    @Override
                    public Boolean withHandle(final Handle handle) {
                      return handle
                              .createQuery("#mojo:detect_language")
                              .map(IntegerMapper.FIRST)
                              .first()
                          != 0;
                    }
                  });

          if (languageExists) {
            CONSOLE.trace("Language plpgsql exists");
          } else {
            CONSOLE.info("... creating plpgsql language...");

            rootDbDbi.withHandle(
                new HandleCallback<Void>() {
                  @Override
                  public Void withHandle(final Handle handle) {
                    handle.createStatement("#mojo:create_language").execute();
                    return null;
                  }
                });
          }
        } catch (DBIException de) {
          throw new MojoExecutionException(String.format("While creating %s", database), de);
        }

        final boolean createSchema = config.getBoolean(getPropertyName("schema.create"), false);

        if (createSchema) {
          final String schemaName = databaseConfig.getDBUser();
          try {
            if (detectSchema(rootDbDbi, schemaName)) {
              CONSOLE.trace("Schema {} exists", schemaName);
            } else {
              CONSOLE.info("... creating Schema {} ...", schemaName);

              rootDbDbi.withHandle(
                  new HandleCallback<Void>() {
                    @Override
                    public Void withHandle(final Handle handle) {
                      handle
                          .createStatement("#mojo:create_schema")
                          .define("schema_name", schemaName)
                          .execute();
                      return null;
                    }
                  });
            }
          } catch (DBIException de) {
            throw new MojoExecutionException(
                String.format("While creating schema %s", schemaName), de);
          }

          final boolean enforceSchema = config.getBoolean(getPropertyName("schema.enforce"), false);

          if (enforceSchema) {
            try {
              if (!detectSchema(rootDbDbi, "public")) {
                CONSOLE.trace("public schema does not exist");
              } else {
                CONSOLE.info("... dropping public schema ...");

                rootDbDbi.withHandle(
                    new HandleCallback<Void>() {
                      @Override
                      public Void withHandle(final Handle handle) {
                        handle
                            .createStatement("#mojo:drop_schema")
                            .define("schema_name", "public")
                            .execute();
                        return null;
                      }
                    });
              }
            } catch (DBIException de) {
              throw new MojoExecutionException(
                  String.format("While dropping public schema: %s", schemaName), de);
            }
          }
        } else {
          CONSOLE.info("... not creating schema ...");
        }

        try {
          // Finally metadata is created as the database owner connected to the database.
          final DBI dbi = getDBIFor(database);

          Migratory migratory = new Migratory(migratoryConfig, dbi);
          final List<MetadataInfo> result = migratory.dbInit();
          if (result != null) {
            final MigrationState state = MetadataInfo.determineMigrationState(result);
            if (state != MigrationState.OK) {
              throw new MojoExecutionException(
                  String.format("Could not initialize metadata, returned status %s", state));
            }
            CONSOLE.info("... initialized metadata ...");
          } else {
            CONSOLE.info("... metadata already exists...");
          }
        } catch (DBIException de) {
          throw new MojoExecutionException(String.format("While creating %s", database), de);
        } catch (MigratoryException me) {
          throw new MojoExecutionException(String.format("While creating %s", database), me);
        }
      }
      CONSOLE.info("... done");
    }
  }