222 lines
7.0 KiB
Go
222 lines
7.0 KiB
Go
// Copyright 2019 Dolthub, 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 commands
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/dolthub/go-mysql-server/sql"
|
|
"github.com/gocraft/dbr/v2"
|
|
"github.com/gocraft/dbr/v2/dialect"
|
|
|
|
"github.com/dolthub/dolt/go/cmd/dolt/cli"
|
|
"github.com/dolthub/dolt/go/cmd/dolt/errhand"
|
|
"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
|
|
"github.com/dolthub/dolt/go/libraries/doltcore/env"
|
|
"github.com/dolthub/dolt/go/libraries/utils/argparser"
|
|
eventsapi "github.com/dolthub/eventsapi_schema/dolt/services/eventsapi/v1alpha1"
|
|
)
|
|
|
|
var lsDocs = cli.CommandDocumentationContent{
|
|
ShortDesc: "List tables",
|
|
LongDesc: `With no arguments lists the tables in the current working set but if a commit is specified it will list the tables in that commit. If the {{.EmphasisLeft}}--verbose{{.EmphasisRight}} flag is provided a row count of the table will also be displayed.
|
|
|
|
If the {{.EmphasisLeft}}--system{{.EmphasisRight}} flag is supplied this will show the dolt system tables which are queryable with SQL.
|
|
|
|
If the {{.EmphasisLeft}}--all{{.EmphasisRight}} flag is supplied both user and system tables will be printed.
|
|
`,
|
|
|
|
Synopsis: []string{
|
|
"[--options] [{{.LessThan}}commit{{.GreaterThan}}]",
|
|
},
|
|
}
|
|
|
|
type LsCmd struct{}
|
|
|
|
// Name is returns the name of the Dolt cli command. This is what is used on the command line to invoke the command
|
|
func (cmd LsCmd) Name() string {
|
|
return "ls"
|
|
}
|
|
|
|
// Description returns a description of the command
|
|
func (cmd LsCmd) Description() string {
|
|
return "List tables in the working set."
|
|
}
|
|
|
|
func (cmd LsCmd) Docs() *cli.CommandDocumentation {
|
|
ap := cmd.ArgParser()
|
|
return cli.NewCommandDocumentation(lsDocs, ap)
|
|
}
|
|
|
|
func (cmd LsCmd) ArgParser() *argparser.ArgParser {
|
|
ap := argparser.NewArgParserWithMaxArgs(cmd.Name(), 1)
|
|
ap.SupportsFlag(cli.VerboseFlag, "v", "show the hash of the table and row count")
|
|
ap.SupportsFlag(cli.SystemFlag, "s", "show system tables")
|
|
ap.SupportsFlag(cli.AllFlag, "a", "show user and system tables")
|
|
return ap
|
|
}
|
|
|
|
// EventType returns the type of the event to log
|
|
func (cmd LsCmd) EventType() eventsapi.ClientEventType {
|
|
return eventsapi.ClientEventType_LS
|
|
}
|
|
|
|
// Exec executes the command
|
|
func (cmd LsCmd) Exec(ctx context.Context, commandStr string, args []string, dEnv *env.DoltEnv, cliCtx cli.CliContext) int {
|
|
ap := cmd.ArgParser()
|
|
help, usage := cli.HelpAndUsagePrinters(cli.CommandDocsForCommandString(commandStr, lsDocs, ap))
|
|
apr := cli.ParseArgsOrDie(ap, args, help)
|
|
|
|
if apr.Contains(cli.SystemFlag) && apr.Contains(cli.AllFlag) {
|
|
verr := errhand.BuildDError("--%s and --%s are mutually exclusive", cli.SystemFlag, cli.AllFlag).SetPrintUsage().Build()
|
|
return HandleVErrAndExitCode(verr, usage)
|
|
}
|
|
|
|
queryist, err := cliCtx.QueryEngine(ctx)
|
|
if err != nil {
|
|
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
|
|
}
|
|
|
|
query, err := constructInterpolatedDoltLsQuery(apr)
|
|
if err != nil {
|
|
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
|
|
}
|
|
|
|
_, _, _, err = queryist.Queryist.Query(queryist.Context, "set @@dolt_show_system_tables = 1")
|
|
if err != nil {
|
|
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
|
|
}
|
|
rows, err := cli.GetRowsForSql(queryist.Queryist, queryist.Context, query)
|
|
if err != nil {
|
|
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
|
|
}
|
|
_, _, _, err = queryist.Queryist.Query(queryist.Context, "set @@dolt_show_system_tables = 0")
|
|
if err != nil {
|
|
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
|
|
}
|
|
|
|
var userTables []string
|
|
var systemTables []string
|
|
for _, row := range rows {
|
|
tableName := row[0].(string)
|
|
if doltdb.HasDoltPrefix(tableName) || doltdb.HasDoltCIPrefix(tableName) {
|
|
systemTables = append(systemTables, tableName)
|
|
} else {
|
|
userTables = append(userTables, tableName)
|
|
}
|
|
}
|
|
|
|
if apr.Contains(cli.AllFlag) {
|
|
err = printUserTables(userTables, apr, queryist.Queryist, queryist.Context)
|
|
if err != nil {
|
|
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
|
|
}
|
|
err = printSystemTables(systemTables)
|
|
if err != nil {
|
|
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
|
|
}
|
|
} else if apr.Contains(cli.SystemFlag) {
|
|
err = printSystemTables(systemTables)
|
|
if err != nil {
|
|
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
|
|
}
|
|
} else {
|
|
err = printUserTables(userTables, apr, queryist.Queryist, queryist.Context)
|
|
if err != nil {
|
|
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
|
|
}
|
|
}
|
|
|
|
return HandleVErrAndExitCode(nil, usage)
|
|
}
|
|
|
|
// constructInterpolatedDoltLsQuery generates the sql query necessary to list all tables and interpolates this query
|
|
// to prevent sql injection
|
|
func constructInterpolatedDoltLsQuery(apr *argparser.ArgParseResults) (string, error) {
|
|
query := "show tables"
|
|
if apr.NArg() == 1 {
|
|
query += " as of ?"
|
|
interpolatedQuery, err := dbr.InterpolateForDialect(query, []interface{}{apr.Arg(0)}, dialect.MySQL)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return interpolatedQuery, nil
|
|
} else {
|
|
return query, nil
|
|
}
|
|
}
|
|
|
|
func printUserTables(tableNames []string, apr *argparser.ArgParseResults, queryist cli.Queryist, sqlCtx *sql.Context) error {
|
|
var label string
|
|
if apr.NArg() == 0 {
|
|
label = "working set"
|
|
} else {
|
|
query := fmt.Sprintf("select hashof('%s')", apr.Arg(0))
|
|
row, err := cli.GetRowsForSql(queryist, sqlCtx, query)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
label = row[0][0].(string)
|
|
}
|
|
|
|
if len(tableNames) == 0 {
|
|
cli.Printf("No tables in %s\n", label)
|
|
return nil
|
|
}
|
|
|
|
cli.Printf("Tables in %s:\n", label)
|
|
for _, tbl := range tableNames {
|
|
if apr.Contains(cli.VerboseFlag) {
|
|
err := printTableVerbose(tbl, queryist, sqlCtx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
cli.Println("\t", tbl)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func printTableVerbose(table string, queryist cli.Queryist, sqlCtx *sql.Context) error {
|
|
query := fmt.Sprintf("select count(*) from `%s`", table)
|
|
row, err := cli.GetRowsForSql(queryist, sqlCtx, query)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if cnt, ok := row[0][0].(int64); ok {
|
|
cli.Println(fmt.Sprintf("\t%-20s %d rows", table, cnt))
|
|
} else if cnt, ok := row[0][0].(string); ok {
|
|
// remote execution returns result as a string
|
|
cli.Println(fmt.Sprintf("\t%-20s %s rows", table, cnt))
|
|
} else {
|
|
return fmt.Errorf("unexpected type for count: %T", row[0][0])
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func printSystemTables(tableNames []string) error {
|
|
cli.Println("System tables:")
|
|
for _, tbl := range tableNames {
|
|
cli.Println("\t", tbl)
|
|
}
|
|
|
|
return nil
|
|
}
|