1
0
mirror of https://github.com/minio/mc.git synced 2025-11-10 13:42:32 +03:00
Files
mc/cmd/sql-main.go
2019-01-04 11:56:43 -08:00

143 lines
3.8 KiB
Go

/*
* Minio Client, (C) 2018 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cmd
import (
"io"
"os"
"path/filepath"
"strings"
"github.com/minio/cli"
"github.com/minio/mc/pkg/probe"
"github.com/minio/minio/pkg/mimedb"
)
var (
sqlFlags = []cli.Flag{
cli.StringFlag{
Name: "query, e",
Usage: "sql query expression",
},
cli.BoolFlag{
Name: "recursive, r",
Usage: "sql query recursively",
},
}
)
// Display contents of a file.
var sqlCmd = cli.Command{
Name: "sql",
Usage: "run sql queries on objects",
Action: mainSQL,
Before: setGlobalsFromContext,
Flags: append(append(sqlFlags, ioFlags...), globalFlags...),
CustomHelpTemplate: `NAME:
{{.HelpName}} - {{.Usage}}
USAGE:
{{.HelpName}} [FLAGS] TARGET [TARGET...]
FLAGS:
{{range .VisibleFlags}}{{.}}
{{end}}
EXAMPLES:
1. Run a query on a set of objects recursively on s3 account.
$ {{.HelpName}} --recursive --query "select * from S3Object" s3/personalbucket/my-large-csvs/
2. Run a query on an object on minio account.
$ {{.HelpName}} --query "select count(s.power) from S3Object" myminio/iot-devices/power-ratio.csv
3. Run a query on an encrypted object with customer provided keys.
$ {{.HelpName}} --encrypt-key "myminio/iot-devices=32byteslongsecretkeymustbegiven1" \
--query "select count(s.power) from S3Object" myminio/iot-devices/power-ratio-encrypted.csv
`,
}
func sqlSelect(targetURL, expression string, encKeyDB map[string][]prefixSSEPair) *probe.Error {
alias, _, _, err := expandAlias(targetURL)
if err != nil {
return err.Trace(targetURL)
}
targetClnt, err := newClient(targetURL)
if err != nil {
return err.Trace(targetURL)
}
sseKey := getSSE(targetURL, encKeyDB[alias])
outputer, err := targetClnt.Select(expression, sseKey)
if err != nil {
return err.Trace(targetURL, expression)
}
defer outputer.Close()
_, e := io.Copy(os.Stdout, outputer)
return probe.NewError(e)
}
// check sql input arguments.
func checkSQLSyntax(ctx *cli.Context) {
if !ctx.Args().Present() {
cli.ShowCommandHelpAndExit(ctx, "sql", 1) // last argument is exit code.
}
}
// mainSQL is the main entry point for sql command.
func mainSQL(ctx *cli.Context) error {
// Parse encryption keys per command.
encKeyDB, err := getEncKeys(ctx)
fatalIf(err, "Unable to parse encryption keys.")
// validate sql input arguments.
checkSQLSyntax(ctx)
// extract URLs.
URLs := ctx.Args()
query := ctx.String("query")
for _, url := range URLs {
if !isAliasURLDir(url, encKeyDB) {
errorIf(sqlSelect(url, query, encKeyDB).Trace(url), "Unable to run sql")
continue
}
targetAlias, targetURL, _ := mustExpandAlias(url)
clnt, err := newClientFromAlias(targetAlias, targetURL)
if err != nil {
errorIf(err.Trace(url), "Unable to initialize target `"+url+"`.")
continue
}
for content := range clnt.List(ctx.Bool("recursive"), false, DirNone) {
if content.Err != nil {
errorIf(content.Err.Trace(url), "Unable to list on target `"+url+"`.")
continue
}
contentType := mimedb.TypeByExtension(filepath.Ext(content.URL.Path))
for _, cTypeSuffix := range supportedContentTypes {
if strings.Contains(contentType, cTypeSuffix) {
errorIf(sqlSelect(targetAlias+content.URL.Path, query,
encKeyDB).Trace(content.URL.String()), "Unable to run sql")
}
}
}
}
// Done.
return nil
}