@Override
  public TaskReport run(TaskSource taskSource, Schema schema, int taskIndex, PageOutput output) {
    PluginTask task = taskSource.loadTask(getTaskClass());

    JdbcSchema querySchema = task.getQuerySchema();
    BufferAllocator allocator = task.getBufferAllocator();
    PageBuilder pageBuilder = new PageBuilder(allocator, schema, output);

    try {
      List<ColumnGetter> getters = newColumnGetters(task, querySchema, pageBuilder);

      try (JdbcInputConnection con = newConnection(task)) {
        try (BatchSelect cursor =
            con.newSelectCursor(
                getQuery(task, con), task.getFetchRows(), task.getSocketTimeout())) {
          while (true) {
            // TODO run fetch() in another thread asynchronously
            // TODO retry fetch() if it failed (maybe order_by is required and unique_column(s)
            // option is also required)
            boolean cont = fetch(cursor, getters, pageBuilder);
            if (!cont) {
              break;
            }
          }
        }
      }

    } catch (SQLException ex) {
      throw Throwables.propagate(ex);
    }
    pageBuilder.finish();

    TaskReport report = Exec.newTaskReport();
    // TODO
    // if (orderByColumn != null) {
    //    report.set("last_value", lastValue);
    // }
    return report;
  }
 private String getQuery(PluginTask task, JdbcInputConnection con) {
   if (task.getQuery().isPresent()) {
     if (task.getTable().isPresent()
         || task.getSelect().isPresent()
         || task.getWhere().isPresent()
         || task.getOrderBy().isPresent()) {
       throw new ConfigException(
           "'table', 'select', 'where' and 'order_by' parameters are unnecessary if 'query' parameter is set.");
     }
     return task.getQuery().get();
   } else if (task.getTable().isPresent()) {
     return con.buildSelectQuery(
         task.getTable().get(), task.getSelect(), task.getWhere(), task.getOrderBy());
   } else {
     throw new ConfigException("'table' parameter is required (if 'query' parameter is not set)");
   }
 }
  private Schema setupTask(JdbcInputConnection con, PluginTask task) throws SQLException {
    // build SELECT query and gets schema of its result
    String query = getQuery(task, con);
    logger.info("SQL: " + query);
    JdbcSchema querySchema = con.getSchemaOfQuery(query);
    task.setQuerySchema(querySchema);

    // validate column_options
    newColumnGetters(task, querySchema, null);

    ColumnGetterFactory factory = newColumnGetterFactory(null, task.getDefaultTimeZone());
    ImmutableList.Builder<Column> columns = ImmutableList.builder();
    for (int i = 0; i < querySchema.getCount(); i++) {
      JdbcColumn column = querySchema.getColumn(i);
      JdbcColumnOption columnOption = columnOptionOf(task.getColumnOptions(), column);
      columns.add(
          new Column(
              i, column.getName(), factory.newColumnGetter(column, columnOption).getToType()));
    }
    return new Schema(columns.build());
  }