aws-sdk-goを使ってAthenaの実行結果を取得する

[別の記事](https://qiita.com/chisso/items/beaf10fbdfd61e31b168)で、aws-sdk-goからAthenaのクエリを実行しました。
その際結果取得はaws-sdk-goのathena使わずに、s3経由でDLしちゃったほうがいいと書いたんですが、やはり使おうかなと思ったので、メモ代わりに簡単な解説とサンプルを残しておきます。

#前提
aws-sdk-go (1.12.44)

#GetQueryResults
[公式ドキュメント](https://docs.aws.amazon.com/sdk-for-go/api/service/athena/#Athena.GetQueryResults)の通り、GetQueryResultsInputを作って呼び出します。
最大取得件数を設定できて、かつページングが実行できるためなかなか便利です。

##GetQueryResultsInput（引数のstruct）
``QueryExecutionId``, ``NextToken``, ``MaxResults``を設定します。
``NextToken``に前回のAPI呼び出しで返却されたtokenを渡すと、自動でページングして次の結果を``MaxResults``分返却してくれます。

##GetQueryResultsOutput（返り値のstruct）
``NextToken``, ``ResultSet``が含まれます。
``ResultSet``は前回の記事で記載したとおり、なかなか厄介な形になっています。

```go:公式ドキュメントより
type ResultSet struct {

    // The metadata that describes the column structure and data types of a table
    // of query results.
    ResultSetMetadata *ResultSetMetadata `type:"structure"`

    // The rows in the table.
    Rows []*Row `type:"list"`
    // contains filtered or unexported fields
}

type Row struct {

    // The data that populates a row in a query result table.
    Data []*Datum `type:"list"`
    // contains filtered or unexported fields
}

type Datum struct {

    // The value of the datum.
    VarCharValue *string `type:"string"`
    // contains filtered or unexported fields
}
```

下記のような関係です。

|struct|property|中身|
|:-----|:-----|:--|
|ResultSet|Rows: []Row|CSVのカラム数 x MaxResults分のデータ|
|Row|Data: []Datum|1行分のデータ|
|Datum|VarCharValue: *string|1カラムのデータ|

#注意点
##1.Datumがnilの場合がある
下記のように、``[]string``に入れ替えようとするとpanic起こす場合があります。

```go:ダメな例
// rowはRow
sl := make([]string, len(row.Data))
for i, val := range row.Data {
    sl[i] = *va.VarCharValue
}
```

```go:安全策
sl := make([]string, len(row.Data))
for i, val := range row.Data {
    if val == nil || val.VarCharValue == nil {
        sl[i] = ""
    } else {
        sl[i] = *val.VarCharValue
    }
}
```

##2.一番最初のレスポンスの一行目がheaderになる
tokenなしでの初回リクエスト時、最初のRowはCSVのheaderが返ってきます。
https://stackoverflow.com/questions/45075754/amazon-athena-how-to-store-results-after-querying-with-skipping-column-headers

将来的にはきっとAPIのパラメータで制御できるようになるはず、、


#サンプルまとめ
packageの全体は[前記事](https://qiita.com/chisso/items/beaf10fbdfd61e31b168)を参照してください。

```go
var GetAthenaQueryResult = func(id *string, token *string, hits int64) ([][]string, *string, error) {
    input := &athena.GetQueryResultsInput{
        QueryExecutionId: id,
        NextToken:        token,
        MaxResults:       &hits,
    }

    output, err := athenaClient.GetQueryResults(input)
    if err != nil {
        return nil, nil, err
    }

    ret := make([][]string, hits)
    index := 0

    for i, row := range output.ResultSet.Rows {
        if i == 0 && token == nil {
            // tokenなし（初回）リクエストの場合、
            // csvのheaderが最初に返ってくるため無視する
            continue
        }
        line := make([]string, len(row.Data))

        for j, val := range row.Data {
            if val == nil || val.VarCharValue == nil {
                line[j] = ""
            } else {
                line[j] = *val.VarCharValue
            }
        }

        ret[index] = line
        index++
    }

    return ret, output.NextToken, nil
}
```

呼び出し元はこんな感じです。

```go
var rows [][]string
var token *string
var err error

queryId := "hogehoge"
hits := 100

for {
    rows, token, err = client.GetAthenaQueryResult(&queryId, token, hits)
    if err != nil {
        return err
    }

    fmt.Println(rows)

    // dataがもうなければ終了
    if token == nil {
        return nil
    }
}
```