github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/cli/cli_test.go (about)

     1  // Copyright 2015 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package cli
    12  
    13  import (
    14  	"bufio"
    15  	"bytes"
    16  	"context"
    17  	"fmt"
    18  	"io"
    19  	"io/ioutil"
    20  	"net"
    21  	"os"
    22  	"path/filepath"
    23  	"reflect"
    24  	"regexp"
    25  	"strconv"
    26  	"strings"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/cockroachdb/cockroach/pkg/base"
    31  	"github.com/cockroachdb/cockroach/pkg/build"
    32  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    33  	"github.com/cockroachdb/cockroach/pkg/security"
    34  	"github.com/cockroachdb/cockroach/pkg/security/securitytest"
    35  	"github.com/cockroachdb/cockroach/pkg/server"
    36  	"github.com/cockroachdb/cockroach/pkg/sql/lex"
    37  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    38  	"github.com/cockroachdb/cockroach/pkg/testutils"
    39  	"github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
    40  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    41  	"github.com/cockroachdb/cockroach/pkg/util/log"
    42  	"github.com/cockroachdb/cockroach/pkg/util/timeutil"
    43  	// register some workloads for TestWorkload
    44  	_ "github.com/cockroachdb/cockroach/pkg/workload/examples"
    45  	"github.com/cockroachdb/errors"
    46  	"github.com/stretchr/testify/assert"
    47  )
    48  
    49  type cliTest struct {
    50  	*server.TestServer
    51  	certsDir    string
    52  	cleanupFunc func() error
    53  
    54  	// t is the testing.T instance used for this test.
    55  	// Example_xxx tests may have this set to nil.
    56  	t *testing.T
    57  	// logScope binds the lifetime of the log files to this test, when t
    58  	// is not nil
    59  	logScope *log.TestLogScope
    60  	// if true, doesn't print args during RunWithArgs
    61  	omitArgs bool
    62  }
    63  
    64  type cliTestParams struct {
    65  	t           *testing.T
    66  	insecure    bool
    67  	noServer    bool
    68  	storeSpecs  []base.StoreSpec
    69  	locality    roachpb.Locality
    70  	noNodelocal bool
    71  }
    72  
    73  func (c *cliTest) fail(err interface{}) {
    74  	if c.t != nil {
    75  		defer c.logScope.Close(c.t)
    76  		c.t.Fatal(err)
    77  	} else {
    78  		panic(err)
    79  	}
    80  }
    81  
    82  func createTestCerts(certsDir string) (cleanup func() error) {
    83  	// Copy these assets to disk from embedded strings, so this test can
    84  	// run from a standalone binary.
    85  	// Disable embedded certs, or the security library will try to load
    86  	// our real files as embedded assets.
    87  	security.ResetAssetLoader()
    88  
    89  	assets := []string{
    90  		filepath.Join(security.EmbeddedCertsDir, security.EmbeddedCACert),
    91  		filepath.Join(security.EmbeddedCertsDir, security.EmbeddedCAKey),
    92  		filepath.Join(security.EmbeddedCertsDir, security.EmbeddedNodeCert),
    93  		filepath.Join(security.EmbeddedCertsDir, security.EmbeddedNodeKey),
    94  		filepath.Join(security.EmbeddedCertsDir, security.EmbeddedRootCert),
    95  		filepath.Join(security.EmbeddedCertsDir, security.EmbeddedRootKey),
    96  	}
    97  
    98  	for _, a := range assets {
    99  		securitytest.RestrictedCopy(nil, a, certsDir, filepath.Base(a))
   100  	}
   101  
   102  	return func() error {
   103  		security.SetAssetLoader(securitytest.EmbeddedAssets)
   104  		return os.RemoveAll(certsDir)
   105  	}
   106  }
   107  
   108  func newCLITest(params cliTestParams) cliTest {
   109  	c := cliTest{t: params.t}
   110  
   111  	certsDir, err := ioutil.TempDir("", "cli-test")
   112  	if err != nil {
   113  		c.fail(err)
   114  	}
   115  	c.certsDir = certsDir
   116  
   117  	if c.t != nil {
   118  		c.logScope = log.Scope(c.t)
   119  	}
   120  
   121  	c.cleanupFunc = func() error { return nil }
   122  
   123  	if !params.noServer {
   124  		if !params.insecure {
   125  			c.cleanupFunc = createTestCerts(certsDir)
   126  			baseCfg.SSLCertsDir = certsDir
   127  		}
   128  
   129  		args := base.TestServerArgs{
   130  			Insecure:      params.insecure,
   131  			SSLCertsDir:   c.certsDir,
   132  			StoreSpecs:    params.storeSpecs,
   133  			Locality:      params.locality,
   134  			ExternalIODir: filepath.Join(certsDir, "extern"),
   135  		}
   136  		if params.noNodelocal {
   137  			args.ExternalIODir = ""
   138  		}
   139  		s, err := serverutils.StartServerRaw(args)
   140  		if err != nil {
   141  			c.fail(err)
   142  		}
   143  		c.TestServer = s.(*server.TestServer)
   144  
   145  		log.Infof(context.Background(), "server started at %s", c.ServingRPCAddr())
   146  		log.Infof(context.Background(), "SQL listener at %s", c.ServingSQLAddr())
   147  	}
   148  
   149  	baseCfg.User = security.NodeUser
   150  
   151  	// Ensure that CLI error messages and anything meant for the
   152  	// original stderr is redirected to stdout, where it can be
   153  	// captured.
   154  	stderr = os.Stdout
   155  
   156  	return c
   157  }
   158  
   159  // setCLIDefaultsForTests invokes initCLIDefaults but pretends the
   160  // output is not a terminal, even if it happens to be. This ensures
   161  // e.g. that tests ran with -v have the same output as those without.
   162  func setCLIDefaultsForTests() {
   163  	initCLIDefaults()
   164  	cliCtx.terminalOutput = false
   165  	sqlCtx.showTimes = false
   166  	// Even though we pretend there is no terminal, most tests want
   167  	// pretty tables.
   168  	cliCtx.tableDisplayFormat = tableDisplayTable
   169  }
   170  
   171  // stopServer stops the test server.
   172  func (c *cliTest) stopServer() {
   173  	if c.TestServer != nil {
   174  		log.Infof(context.Background(), "stopping server at %s / %s",
   175  			c.ServingRPCAddr(), c.ServingSQLAddr())
   176  		select {
   177  		case <-c.Stopper().ShouldStop():
   178  			// If ShouldStop() doesn't block, that means someone has already
   179  			// called Stop(). We just need to wait.
   180  			<-c.Stopper().IsStopped()
   181  		default:
   182  			c.Stopper().Stop(context.Background())
   183  		}
   184  	}
   185  }
   186  
   187  // restartServer stops and restarts the test server. The ServingRPCAddr() may
   188  // have changed after this method returns.
   189  func (c *cliTest) restartServer(params cliTestParams) {
   190  	c.stopServer()
   191  	log.Info(context.Background(), "restarting server")
   192  	s, err := serverutils.StartServerRaw(base.TestServerArgs{
   193  		Insecure:    params.insecure,
   194  		SSLCertsDir: c.certsDir,
   195  		StoreSpecs:  params.storeSpecs,
   196  	})
   197  	if err != nil {
   198  		c.fail(err)
   199  	}
   200  	c.TestServer = s.(*server.TestServer)
   201  	log.Infof(context.Background(), "restarted server at %s / %s",
   202  		c.ServingRPCAddr(), c.ServingSQLAddr())
   203  }
   204  
   205  // cleanup cleans up after the test, stopping the server if necessary.
   206  // The log files are removed if the test has succeeded.
   207  func (c *cliTest) cleanup() {
   208  	if c.t != nil {
   209  		defer c.logScope.Close(c.t)
   210  	}
   211  
   212  	// Restore stderr.
   213  	stderr = log.OrigStderr
   214  
   215  	log.Info(context.Background(), "stopping server and cleaning up CLI test")
   216  
   217  	c.stopServer()
   218  
   219  	if err := c.cleanupFunc(); err != nil {
   220  		panic(err)
   221  	}
   222  }
   223  
   224  func (c cliTest) Run(line string) {
   225  	a := strings.Fields(line)
   226  	c.RunWithArgs(a)
   227  }
   228  
   229  // RunWithCapture runs c and returns a string containing the output of c
   230  // and any error that may have occurred capturing the output. We do not propagate
   231  // errors in executing c, because those will be caught when the test verifies
   232  // the output of c.
   233  func (c cliTest) RunWithCapture(line string) (out string, err error) {
   234  	return captureOutput(func() {
   235  		c.Run(line)
   236  	})
   237  }
   238  
   239  func (c cliTest) RunWithCaptureArgs(args []string) (string, error) {
   240  	return captureOutput(func() {
   241  		c.RunWithArgs(args)
   242  	})
   243  }
   244  
   245  // captureOutput runs f and returns a string containing the output and any
   246  // error that may have occurred capturing the output.
   247  func captureOutput(f func()) (out string, err error) {
   248  	// Heavily inspired by Go's testing/example.go:runExample().
   249  
   250  	// Funnel stdout into a pipe.
   251  	stdoutSave, stderrRedirSave := os.Stdout, stderr
   252  	r, w, err := os.Pipe()
   253  	if err != nil {
   254  		return "", err
   255  	}
   256  	os.Stdout = w
   257  	stderr = w
   258  
   259  	// Send all bytes from piped stdout through the output channel.
   260  	type captureResult struct {
   261  		out string
   262  		err error
   263  	}
   264  	outC := make(chan captureResult)
   265  	go func() {
   266  		var buf bytes.Buffer
   267  		_, err := io.Copy(&buf, r)
   268  		r.Close()
   269  		outC <- captureResult{buf.String(), err}
   270  	}()
   271  
   272  	// Clean up and record output in separate function to handle panics.
   273  	defer func() {
   274  		// Close pipe and restore normal stdout.
   275  		w.Close()
   276  		os.Stdout = stdoutSave
   277  		stderr = stderrRedirSave
   278  		outResult := <-outC
   279  		out, err = outResult.out, outResult.err
   280  		if x := recover(); x != nil {
   281  			err = errors.Errorf("panic: %v", x)
   282  		}
   283  	}()
   284  
   285  	// Run the command. The output will be returned in the defer block.
   286  	f()
   287  	return
   288  }
   289  
   290  func isSQLCommand(args []string) bool {
   291  	if len(args) == 0 {
   292  		return false
   293  	}
   294  	switch args[0] {
   295  	case "sql", "dump", "workload", "nodelocal":
   296  		return true
   297  	case "node":
   298  		if len(args) == 0 {
   299  			return false
   300  		}
   301  		switch args[1] {
   302  		case "status", "ls":
   303  			return true
   304  		default:
   305  			return false
   306  		}
   307  	default:
   308  		return false
   309  	}
   310  }
   311  
   312  func (c cliTest) RunWithArgs(origArgs []string) {
   313  	TestingReset()
   314  
   315  	if err := func() error {
   316  		args := append([]string(nil), origArgs[:1]...)
   317  		if c.TestServer != nil {
   318  			addr := c.ServingRPCAddr()
   319  			if isSQLCommand(origArgs) {
   320  				addr = c.ServingSQLAddr()
   321  			}
   322  			h, p, err := net.SplitHostPort(addr)
   323  			if err != nil {
   324  				return err
   325  			}
   326  			args = append(args, fmt.Sprintf("--host=%s", net.JoinHostPort(h, p)))
   327  			if c.Cfg.Insecure {
   328  				args = append(args, "--insecure=true")
   329  			} else {
   330  				args = append(args, "--insecure=false")
   331  				args = append(args, fmt.Sprintf("--certs-dir=%s", c.certsDir))
   332  			}
   333  		}
   334  		args = append(args, origArgs[1:]...)
   335  
   336  		if !c.omitArgs {
   337  			fmt.Fprintf(os.Stderr, "%s\n", args)
   338  			fmt.Println(strings.Join(origArgs, " "))
   339  		}
   340  
   341  		return Run(args)
   342  	}(); err != nil {
   343  		cliOutputError(os.Stdout, err, true /*showSeverity*/, false /*verbose*/)
   344  	}
   345  }
   346  
   347  func (c cliTest) RunWithCAArgs(origArgs []string) {
   348  	TestingReset()
   349  
   350  	if err := func() error {
   351  		args := append([]string(nil), origArgs[:1]...)
   352  		if c.TestServer != nil {
   353  			args = append(args, fmt.Sprintf("--ca-key=%s", filepath.Join(c.certsDir, security.EmbeddedCAKey)))
   354  			args = append(args, fmt.Sprintf("--certs-dir=%s", c.certsDir))
   355  		}
   356  		args = append(args, origArgs[1:]...)
   357  
   358  		fmt.Fprintf(os.Stderr, "%s\n", args)
   359  		fmt.Println(strings.Join(origArgs, " "))
   360  
   361  		return Run(args)
   362  	}(); err != nil {
   363  		fmt.Println(err)
   364  	}
   365  }
   366  
   367  func TestQuit(t *testing.T) {
   368  	defer leaktest.AfterTest(t)()
   369  
   370  	if testing.Short() {
   371  		t.Skip("short flag")
   372  	}
   373  
   374  	c := newCLITest(cliTestParams{t: t})
   375  	defer c.cleanup()
   376  
   377  	c.Run("quit")
   378  	// Wait until this async command cleanups the server.
   379  	<-c.Stopper().IsStopped()
   380  }
   381  
   382  func Example_logging() {
   383  	c := newCLITest(cliTestParams{})
   384  	defer c.cleanup()
   385  
   386  	c.RunWithArgs([]string{`sql`, `--logtostderr=false`, `-e`, `select 1 as "1"`})
   387  	c.RunWithArgs([]string{`sql`, `--logtostderr=true`, `-e`, `select 1 as "1"`})
   388  	c.RunWithArgs([]string{`sql`, `--vmodule=foo=1`, `-e`, `select 1 as "1"`})
   389  
   390  	// Output:
   391  	// sql --logtostderr=false -e select 1 as "1"
   392  	// 1
   393  	// 1
   394  	// sql --logtostderr=true -e select 1 as "1"
   395  	// 1
   396  	// 1
   397  	// sql --vmodule=foo=1 -e select 1 as "1"
   398  	// 1
   399  	// 1
   400  }
   401  
   402  func Example_demo() {
   403  	c := newCLITest(cliTestParams{noServer: true})
   404  	defer c.cleanup()
   405  
   406  	testData := [][]string{
   407  		{`demo`, `-e`, `show database`},
   408  		{`demo`, `-e`, `show database`, `--empty`},
   409  		{`demo`, `-e`, `show application_name`},
   410  		{`demo`, `--format=table`, `-e`, `show database`},
   411  		{`demo`, `-e`, `select 1 as "1"`, `-e`, `select 3 as "3"`},
   412  		{`demo`, `--echo-sql`, `-e`, `select 1 as "1"`},
   413  		{`demo`, `--set=errexit=0`, `-e`, `select nonexistent`, `-e`, `select 123 as "123"`},
   414  		{`demo`, `startrek`, `-e`, `show databases`},
   415  		{`demo`, `startrek`, `-e`, `show databases`, `--format=table`},
   416  		// Test that if we start with --insecure we cannot perform
   417  		// commands that require a secure cluster.
   418  		{`demo`, `-e`, `CREATE USER test WITH PASSWORD 'testpass'`},
   419  		{`demo`, `--insecure`, `-e`, `CREATE USER test WITH PASSWORD 'testpass'`},
   420  		{`demo`, `--geo-partitioned-replicas`, `--disable-demo-license`},
   421  	}
   422  	setCLIDefaultsForTests()
   423  	// We must reset the security asset loader here, otherwise the dummy
   424  	// asset loader that is set by default in tests will not be able to
   425  	// find the certs that demo sets up.
   426  	security.ResetAssetLoader()
   427  	for _, cmd := range testData {
   428  		c.RunWithArgs(cmd)
   429  	}
   430  
   431  	// Output:
   432  	// demo -e show database
   433  	// database
   434  	// movr
   435  	// demo -e show database --empty
   436  	// database
   437  	// defaultdb
   438  	// demo -e show application_name
   439  	// application_name
   440  	// $ cockroach demo
   441  	// demo --format=table -e show database
   442  	//   database
   443  	// ------------
   444  	//   movr
   445  	// (1 row)
   446  	// demo -e select 1 as "1" -e select 3 as "3"
   447  	// 1
   448  	// 1
   449  	// 3
   450  	// 3
   451  	// demo --echo-sql -e select 1 as "1"
   452  	// > select 1 as "1"
   453  	// 1
   454  	// 1
   455  	// demo --set=errexit=0 -e select nonexistent -e select 123 as "123"
   456  	// ERROR: column "nonexistent" does not exist
   457  	// SQLSTATE: 42703
   458  	// 123
   459  	// 123
   460  	// demo startrek -e show databases
   461  	// database_name
   462  	// defaultdb
   463  	// postgres
   464  	// startrek
   465  	// system
   466  	// demo startrek -e show databases --format=table
   467  	//   database_name
   468  	// -----------------
   469  	//   defaultdb
   470  	//   postgres
   471  	//   startrek
   472  	//   system
   473  	// (4 rows)
   474  	// demo -e CREATE USER test WITH PASSWORD 'testpass'
   475  	// CREATE ROLE
   476  	// demo --insecure -e CREATE USER test WITH PASSWORD 'testpass'
   477  	// ERROR: setting or updating a password is not supported in insecure mode
   478  	// SQLSTATE: 28P01
   479  	// demo --geo-partitioned-replicas --disable-demo-license
   480  	// ERROR: enterprise features are needed for this demo (--geo-partitioned-replicas)
   481  }
   482  
   483  func Example_sql() {
   484  	c := newCLITest(cliTestParams{})
   485  	defer c.cleanup()
   486  
   487  	c.RunWithArgs([]string{`sql`, `-e`, `show application_name`})
   488  	c.RunWithArgs([]string{`sql`, `-e`, `create database t; create table t.f (x int, y int); insert into t.f values (42, 69)`})
   489  	c.RunWithArgs([]string{`sql`, `-e`, `select 3 as "3"`, `-e`, `select * from t.f`})
   490  	c.RunWithArgs([]string{`sql`, `-e`, `begin`, `-e`, `select 3 as "3"`, `-e`, `commit`})
   491  	c.RunWithArgs([]string{`sql`, `-e`, `select * from t.f`})
   492  	c.RunWithArgs([]string{`sql`, `--execute=show databases`})
   493  	c.RunWithArgs([]string{`sql`, `-e`, `select 1 as "1"; select 2 as "2"`})
   494  	c.RunWithArgs([]string{`sql`, `-e`, `select 1 as "1"; select 2 as "@" where false`})
   495  	// CREATE TABLE AS returns a SELECT tag with a row count, check this.
   496  	c.RunWithArgs([]string{`sql`, `-e`, `create table t.g1 (x int)`})
   497  	c.RunWithArgs([]string{`sql`, `-e`, `create table t.g2 as select * from generate_series(1,10)`})
   498  	// It must be possible to access pre-defined/virtual tables even if the current database
   499  	// does not exist yet.
   500  	c.RunWithArgs([]string{`sql`, `-d`, `nonexistent`, `-e`, `select count(*) from "".information_schema.tables limit 0`})
   501  	// It must be possible to create the current database after the
   502  	// connection was established.
   503  	c.RunWithArgs([]string{`sql`, `-d`, `nonexistent`, `-e`, `create database nonexistent; create table foo(x int); select * from foo`})
   504  	// COPY should return an intelligible error message.
   505  	c.RunWithArgs([]string{`sql`, `-e`, `copy t.f from stdin`})
   506  	// --set changes client-side variables before executing commands.
   507  	c.RunWithArgs([]string{`sql`, `--set=errexit=0`, `-e`, `select nonexistent`, `-e`, `select 123 as "123"`})
   508  	c.RunWithArgs([]string{`sql`, `--set`, `echo=true`, `-e`, `select 123 as "123"`})
   509  	c.RunWithArgs([]string{`sql`, `--set`, `unknownoption`, `-e`, `select 123 as "123"`})
   510  	// Check that partial results + error get reported together.
   511  	c.RunWithArgs([]string{`sql`, `-e`, `select 1/(@1-3) from generate_series(1,4)`})
   512  
   513  	// Output:
   514  	// sql -e show application_name
   515  	// application_name
   516  	// $ cockroach sql
   517  	// sql -e create database t; create table t.f (x int, y int); insert into t.f values (42, 69)
   518  	// INSERT 1
   519  	// sql -e select 3 as "3" -e select * from t.f
   520  	// 3
   521  	// 3
   522  	// x	y
   523  	// 42	69
   524  	// sql -e begin -e select 3 as "3" -e commit
   525  	// BEGIN
   526  	// 3
   527  	// 3
   528  	// COMMIT
   529  	// sql -e select * from t.f
   530  	// x	y
   531  	// 42	69
   532  	// sql --execute=show databases
   533  	// database_name
   534  	// defaultdb
   535  	// postgres
   536  	// system
   537  	// t
   538  	// sql -e select 1 as "1"; select 2 as "2"
   539  	// 1
   540  	// 1
   541  	// 2
   542  	// 2
   543  	// sql -e select 1 as "1"; select 2 as "@" where false
   544  	// 1
   545  	// 1
   546  	// @
   547  	// sql -e create table t.g1 (x int)
   548  	// CREATE TABLE
   549  	// sql -e create table t.g2 as select * from generate_series(1,10)
   550  	// CREATE TABLE AS
   551  	// sql -d nonexistent -e select count(*) from "".information_schema.tables limit 0
   552  	// count
   553  	// sql -d nonexistent -e create database nonexistent; create table foo(x int); select * from foo
   554  	// x
   555  	// sql -e copy t.f from stdin
   556  	// ERROR: woops! COPY has confused this client! Suggestion: use 'psql' for COPY
   557  	// sql --set=errexit=0 -e select nonexistent -e select 123 as "123"
   558  	// ERROR: column "nonexistent" does not exist
   559  	// SQLSTATE: 42703
   560  	// 123
   561  	// 123
   562  	// sql --set echo=true -e select 123 as "123"
   563  	// > select 123 as "123"
   564  	// 123
   565  	// 123
   566  	// sql --set unknownoption -e select 123 as "123"
   567  	// invalid syntax: \set unknownoption. Try \? for help.
   568  	// ERROR: invalid syntax
   569  	// sql -e select 1/(@1-3) from generate_series(1,4)
   570  	// ?column?
   571  	// -0.5
   572  	// -1
   573  	// (error encountered after some results were delivered)
   574  	// ERROR: division by zero
   575  	// SQLSTATE: 22012
   576  }
   577  
   578  func Example_sql_watch() {
   579  	c := newCLITest(cliTestParams{})
   580  	defer c.cleanup()
   581  
   582  	c.RunWithArgs([]string{`sql`, `-e`, `create table d(x int); insert into d values(3)`})
   583  	c.RunWithArgs([]string{`sql`, `--watch`, `.1s`, `-e`, `update d set x=x-1 returning 1/x as dec`})
   584  
   585  	// Output:
   586  	// sql -e create table d(x int); insert into d values(3)
   587  	// INSERT 1
   588  	// sql --watch .1s -e update d set x=x-1 returning 1/x as dec
   589  	// dec
   590  	// 0.5
   591  	// dec
   592  	// 1
   593  	// ERROR: division by zero
   594  	// SQLSTATE: 22012
   595  }
   596  
   597  func Example_sql_format() {
   598  	c := newCLITest(cliTestParams{})
   599  	defer c.cleanup()
   600  
   601  	c.RunWithArgs([]string{"sql", "-e", "create database t; create table t.times (bare timestamp, withtz timestamptz)"})
   602  	c.RunWithArgs([]string{"sql", "-e", "insert into t.times values ('2016-01-25 10:10:10', '2016-01-25 10:10:10-05:00')"})
   603  	c.RunWithArgs([]string{"sql", "-e", "select * from t.times"})
   604  
   605  	// Output:
   606  	// sql -e create database t; create table t.times (bare timestamp, withtz timestamptz)
   607  	// CREATE TABLE
   608  	// sql -e insert into t.times values ('2016-01-25 10:10:10', '2016-01-25 10:10:10-05:00')
   609  	// INSERT 1
   610  	// sql -e select * from t.times
   611  	// bare	withtz
   612  	// 2016-01-25 10:10:10+00:00	2016-01-25 15:10:10+00:00
   613  }
   614  
   615  func Example_sql_column_labels() {
   616  	c := newCLITest(cliTestParams{})
   617  	defer c.cleanup()
   618  
   619  	testData := []string{
   620  		`f"oo`,
   621  		`f'oo`,
   622  		`f\oo`,
   623  		`short
   624  very very long
   625  not much`,
   626  		`very very long
   627  thenshort`,
   628  		`κόσμε`,
   629  		`a|b`,
   630  		`܈85`,
   631  	}
   632  
   633  	tdef := make([]string, len(testData))
   634  	var vals bytes.Buffer
   635  	for i, col := range testData {
   636  		tdef[i] = tree.NameString(col) + " int"
   637  		if i > 0 {
   638  			vals.WriteString(", ")
   639  		}
   640  		vals.WriteByte('0')
   641  	}
   642  	c.RunWithArgs([]string{"sql", "-e", "create database t; create table t.u (" + strings.Join(tdef, ", ") + ")"})
   643  	c.RunWithArgs([]string{"sql", "-e", "insert into t.u values (" + vals.String() + ")"})
   644  	c.RunWithArgs([]string{"sql", "-e", "show columns from t.u"})
   645  	c.RunWithArgs([]string{"sql", "-e", "select * from t.u"})
   646  	c.RunWithArgs([]string{"sql", "--format=table", "-e", "show columns from t.u"})
   647  	for i := tableDisplayFormat(0); i < tableDisplayLastFormat; i++ {
   648  		c.RunWithArgs([]string{"sql", "--format=" + i.String(), "-e", "select * from t.u"})
   649  	}
   650  
   651  	// Output
   652  	// sql -e create database t; create table t.u ("f""oo" int, "f'oo" int, "f\oo" int, "short
   653  	// very very long
   654  	// not much" int, "very very long
   655  	// thenshort" int, "κόσμε" int, "a|b" int, ܈85 int)
   656  	// CREATE TABLE
   657  	// sql -e insert into t.u values (0, 0, 0, 0, 0, 0, 0, 0)
   658  	// INSERT 1
   659  	// sql -e show columns from t.u
   660  	// column_name	data_type	is_nullable	column_default	generation_expression	indices
   661  	// "f""oo"	INT	true	NULL		{}
   662  	// f'oo	INT	true	NULL		{}
   663  	// f\oo	INT	true	NULL		{}
   664  	// "short
   665  	// very very long
   666  	// not much"	INT	true	NULL		{}
   667  	// "very very long
   668  	// thenshort"	INT	true	NULL		{}
   669  	// κόσμε	INT	true	NULL		{}
   670  	// a|b	INT	true	NULL		{}
   671  	// ܈85	INT	true	NULL		{}
   672  	// sql -e select * from t.u
   673  	// "f""oo"	f'oo	f\oo	"short
   674  	// very very long
   675  	// not much"	"very very long
   676  	// thenshort"	κόσμε	a|b	܈85
   677  	// 0	0	0	0	0	0	0	0
   678  	// sql --format=table -e show columns from t.u
   679  	//    column_name   | data_type | is_nullable | column_default | generation_expression | indices
   680  	// +----------------+-----------+-------------+----------------+-----------------------+---------+
   681  	//   f"oo           | INT       |    true     | NULL           |                       | {}
   682  	//   f'oo           | INT       |    true     | NULL           |                       | {}
   683  	//   f\oo           | INT       |    true     | NULL           |                       | {}
   684  	//   short          | INT       |    true     | NULL           |                       | {}
   685  	//   very very long |           |             |                |                       |
   686  	//   not much       |           |             |                |                       |
   687  	//   very very long | INT       |    true     | NULL           |                       | {}
   688  	//   thenshort      |           |             |                |                       |
   689  	//   κόσμε          | INT       |    true     | NULL           |                       | {}
   690  	//   a|b            | INT       |    true     | NULL           |                       | {}
   691  	//   ܈85            | INT       |    true     | NULL           |                       | {}
   692  	// (8 rows)
   693  	// sql --format=tsv -e select * from t.u
   694  	// "f""oo"	f'oo	f\oo	"short
   695  	// very very long
   696  	// not much"	"very very long
   697  	// thenshort"	κόσμε	a|b	܈85
   698  	// 0	0	0	0	0	0	0	0
   699  	// sql --format=csv -e select * from t.u
   700  	// "f""oo",f'oo,f\oo,"short
   701  	// very very long
   702  	// not much","very very long
   703  	// thenshort",κόσμε,a|b,܈85
   704  	// 0,0,0,0,0,0,0,0
   705  	// sql --format=table -e select * from t.u
   706  	//   f"oo | f'oo | f\oo |     short      | very very long | κόσμε | a|b | ܈85
   707  	//        |      |      | very very long |   thenshort    |       |     |
   708  	//        |      |      |    not much    |                |       |     |
   709  	// +------+------+------+----------------+----------------+-------+-----+-----+
   710  	//      0 |    0 |    0 |              0 |              0 |     0 |   0 |   0
   711  	// (1 row)
   712  	// sql --format=records -e select * from t.u
   713  	// -[ RECORD 1 ]
   714  	// f"oo           | 0
   715  	// f'oo           | 0
   716  	// f\oo           | 0
   717  	// short         +| 0
   718  	// very very long+|
   719  	// not much       |
   720  	// very very long+| 0
   721  	// thenshort      |
   722  	// κόσμε          | 0
   723  	// a|b            | 0
   724  	// ܈85            | 0
   725  	// sql --format=sql -e select * from t.u
   726  	// CREATE TABLE results (
   727  	//   "f""oo" STRING,
   728  	//   "f'oo" STRING,
   729  	//   "f\oo" STRING,
   730  	//   "short
   731  	// very very long
   732  	// not much" STRING,
   733  	//   "very very long
   734  	// thenshort" STRING,
   735  	//   "κόσμε" STRING,
   736  	//   "a|b" STRING,
   737  	//   ܈85 STRING
   738  	// );
   739  	//
   740  	// INSERT INTO results VALUES ('0', '0', '0', '0', '0', '0', '0', '0');
   741  	// -- 1 row
   742  	// sql --format=html -e select * from t.u
   743  	// <table>
   744  	// <thead><tr><th>row</th><th>f&#34;oo</th><th>f&#39;oo</th><th>f\oo</th><th>short<br/>very very long<br/>not much</th><th>very very long<br/>thenshort</th><th>κόσμε</th><th>a|b</th><th>܈85</th></tr></thead>
   745  	// <tbody>
   746  	// <tr><td>1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td></tr>
   747  	// </tbody>
   748  	// <tfoot><tr><td colspan=9>1 row</td></tr></tfoot></table>
   749  	// sql --format=raw -e select * from t.u
   750  	// # 8 columns
   751  	// # row 1
   752  	// ## 1
   753  	// 0
   754  	// ## 1
   755  	// 0
   756  	// ## 1
   757  	// 0
   758  	// ## 1
   759  	// 0
   760  	// ## 1
   761  	// 0
   762  	// ## 1
   763  	// 0
   764  	// ## 1
   765  	// 0
   766  	// ## 1
   767  	// 0
   768  	// # 1 row
   769  }
   770  
   771  func Example_sql_empty_table() {
   772  	c := newCLITest(cliTestParams{})
   773  	defer c.cleanup()
   774  
   775  	c.RunWithArgs([]string{"sql", "-e", "create database t;" +
   776  		"create table t.norows(x int);" +
   777  		"create table t.nocolsnorows();" +
   778  		"create table t.nocols(); insert into t.nocols(rowid) values (1),(2),(3);"})
   779  	for _, table := range []string{"norows", "nocols", "nocolsnorows"} {
   780  		for format := tableDisplayFormat(0); format < tableDisplayLastFormat; format++ {
   781  			c.RunWithArgs([]string{"sql", "--format=" + format.String(), "-e", "select * from t." + table})
   782  		}
   783  	}
   784  
   785  	// Output:
   786  	// sql -e create database t;create table t.norows(x int);create table t.nocolsnorows();create table t.nocols(); insert into t.nocols(rowid) values (1),(2),(3);
   787  	// INSERT 3
   788  	// sql --format=tsv -e select * from t.norows
   789  	// x
   790  	// sql --format=csv -e select * from t.norows
   791  	// x
   792  	// sql --format=table -e select * from t.norows
   793  	//   x
   794  	// -----
   795  	// (0 rows)
   796  	// sql --format=records -e select * from t.norows
   797  	// sql --format=sql -e select * from t.norows
   798  	// CREATE TABLE results (
   799  	//   x STRING
   800  	// );
   801  	//
   802  	// -- 0 rows
   803  	// sql --format=html -e select * from t.norows
   804  	// <table>
   805  	// <thead><tr><th>row</th><th>x</th></tr></thead>
   806  	// </tbody>
   807  	// <tfoot><tr><td colspan=2>0 rows</td></tr></tfoot></table>
   808  	// sql --format=raw -e select * from t.norows
   809  	// # 1 column
   810  	// # 0 rows
   811  	// sql --format=tsv -e select * from t.nocols
   812  	// # no columns
   813  	// # empty
   814  	// # empty
   815  	// # empty
   816  	// sql --format=csv -e select * from t.nocols
   817  	// # no columns
   818  	// # empty
   819  	// # empty
   820  	// # empty
   821  	// sql --format=table -e select * from t.nocols
   822  	// --
   823  	// (3 rows)
   824  	// sql --format=records -e select * from t.nocols
   825  	// (3 rows)
   826  	// sql --format=sql -e select * from t.nocols
   827  	// CREATE TABLE results (
   828  	// );
   829  	//
   830  	// INSERT INTO results(rowid) VALUES (DEFAULT);
   831  	// INSERT INTO results(rowid) VALUES (DEFAULT);
   832  	// INSERT INTO results(rowid) VALUES (DEFAULT);
   833  	// -- 3 rows
   834  	// sql --format=html -e select * from t.nocols
   835  	// <table>
   836  	// <thead><tr><th>row</th></tr></thead>
   837  	// <tbody>
   838  	// <tr><td>1</td></tr>
   839  	// <tr><td>2</td></tr>
   840  	// <tr><td>3</td></tr>
   841  	// </tbody>
   842  	// <tfoot><tr><td colspan=1>3 rows</td></tr></tfoot></table>
   843  	// sql --format=raw -e select * from t.nocols
   844  	// # 0 columns
   845  	// # row 1
   846  	// # row 2
   847  	// # row 3
   848  	// # 3 rows
   849  	// sql --format=tsv -e select * from t.nocolsnorows
   850  	// # no columns
   851  	// sql --format=csv -e select * from t.nocolsnorows
   852  	// # no columns
   853  	// sql --format=table -e select * from t.nocolsnorows
   854  	// --
   855  	// (0 rows)
   856  	// sql --format=records -e select * from t.nocolsnorows
   857  	// (0 rows)
   858  	// sql --format=sql -e select * from t.nocolsnorows
   859  	// CREATE TABLE results (
   860  	// );
   861  	//
   862  	// -- 0 rows
   863  	// sql --format=html -e select * from t.nocolsnorows
   864  	// <table>
   865  	// <thead><tr><th>row</th></tr></thead>
   866  	// </tbody>
   867  	// <tfoot><tr><td colspan=1>0 rows</td></tr></tfoot></table>
   868  	// sql --format=raw -e select * from t.nocolsnorows
   869  	// # 0 columns
   870  	// # 0 rows
   871  }
   872  
   873  func Example_csv_tsv_quoting() {
   874  	c := newCLITest(cliTestParams{})
   875  	defer c.cleanup()
   876  
   877  	testData := []string{
   878  		`ab`,
   879  		`a b`,
   880  		`a
   881  bc
   882  def`,
   883  		`a, b`,
   884  		`"a", "b"`,
   885  		`'a', 'b'`,
   886  		`a\,b`,
   887  		`a	b`,
   888  	}
   889  
   890  	for _, sqlStr := range testData {
   891  		escaped := lex.EscapeSQLString(sqlStr)
   892  		sql := "select " + escaped + " as s, " + escaped + " as t"
   893  		c.RunWithArgs([]string{"sql", "--format=csv", "-e", sql})
   894  		c.RunWithArgs([]string{"sql", "--format=tsv", "-e", sql})
   895  	}
   896  
   897  	for _, identStr := range testData {
   898  		escaped1 := tree.NameString(identStr + "1")
   899  		escaped2 := tree.NameString(identStr + "2")
   900  		sql := "select 1 as " + escaped1 + ", 2 as " + escaped2
   901  		c.RunWithArgs([]string{"sql", "--format=csv", "-e", sql})
   902  		c.RunWithArgs([]string{"sql", "--format=tsv", "-e", sql})
   903  	}
   904  
   905  	// Output:
   906  	// sql --format=csv -e select 'ab' as s, 'ab' as t
   907  	// s,t
   908  	// ab,ab
   909  	// sql --format=tsv -e select 'ab' as s, 'ab' as t
   910  	// s	t
   911  	// ab	ab
   912  	// sql --format=csv -e select 'a b' as s, 'a b' as t
   913  	// s,t
   914  	// a b,a b
   915  	// sql --format=tsv -e select 'a b' as s, 'a b' as t
   916  	// s	t
   917  	// a b	a b
   918  	// sql --format=csv -e select e'a\nbc\ndef' as s, e'a\nbc\ndef' as t
   919  	// s,t
   920  	// "a
   921  	// bc
   922  	// def","a
   923  	// bc
   924  	// def"
   925  	// sql --format=tsv -e select e'a\nbc\ndef' as s, e'a\nbc\ndef' as t
   926  	// s	t
   927  	// "a
   928  	// bc
   929  	// def"	"a
   930  	// bc
   931  	// def"
   932  	// sql --format=csv -e select 'a, b' as s, 'a, b' as t
   933  	// s,t
   934  	// "a, b","a, b"
   935  	// sql --format=tsv -e select 'a, b' as s, 'a, b' as t
   936  	// s	t
   937  	// a, b	a, b
   938  	// sql --format=csv -e select '"a", "b"' as s, '"a", "b"' as t
   939  	// s,t
   940  	// """a"", ""b""","""a"", ""b"""
   941  	// sql --format=tsv -e select '"a", "b"' as s, '"a", "b"' as t
   942  	// s	t
   943  	// """a"", ""b"""	"""a"", ""b"""
   944  	// sql --format=csv -e select e'\'a\', \'b\'' as s, e'\'a\', \'b\'' as t
   945  	// s,t
   946  	// "'a', 'b'","'a', 'b'"
   947  	// sql --format=tsv -e select e'\'a\', \'b\'' as s, e'\'a\', \'b\'' as t
   948  	// s	t
   949  	// 'a', 'b'	'a', 'b'
   950  	// sql --format=csv -e select e'a\\,b' as s, e'a\\,b' as t
   951  	// s,t
   952  	// "a\,b","a\,b"
   953  	// sql --format=tsv -e select e'a\\,b' as s, e'a\\,b' as t
   954  	// s	t
   955  	// a\,b	a\,b
   956  	// sql --format=csv -e select e'a\tb' as s, e'a\tb' as t
   957  	// s,t
   958  	// a	b,a	b
   959  	// sql --format=tsv -e select e'a\tb' as s, e'a\tb' as t
   960  	// s	t
   961  	// "a	b"	"a	b"
   962  	// sql --format=csv -e select 1 as ab1, 2 as ab2
   963  	// ab1,ab2
   964  	// 1,2
   965  	// sql --format=tsv -e select 1 as ab1, 2 as ab2
   966  	// ab1	ab2
   967  	// 1	2
   968  	// sql --format=csv -e select 1 as "a b1", 2 as "a b2"
   969  	// a b1,a b2
   970  	// 1,2
   971  	// sql --format=tsv -e select 1 as "a b1", 2 as "a b2"
   972  	// a b1	a b2
   973  	// 1	2
   974  	// sql --format=csv -e select 1 as "a
   975  	// bc
   976  	// def1", 2 as "a
   977  	// bc
   978  	// def2"
   979  	// "a
   980  	// bc
   981  	// def1","a
   982  	// bc
   983  	// def2"
   984  	// 1,2
   985  	// sql --format=tsv -e select 1 as "a
   986  	// bc
   987  	// def1", 2 as "a
   988  	// bc
   989  	// def2"
   990  	// "a
   991  	// bc
   992  	// def1"	"a
   993  	// bc
   994  	// def2"
   995  	// 1	2
   996  	// sql --format=csv -e select 1 as "a, b1", 2 as "a, b2"
   997  	// "a, b1","a, b2"
   998  	// 1,2
   999  	// sql --format=tsv -e select 1 as "a, b1", 2 as "a, b2"
  1000  	// a, b1	a, b2
  1001  	// 1	2
  1002  	// sql --format=csv -e select 1 as """a"", ""b""1", 2 as """a"", ""b""2"
  1003  	// """a"", ""b""1","""a"", ""b""2"
  1004  	// 1,2
  1005  	// sql --format=tsv -e select 1 as """a"", ""b""1", 2 as """a"", ""b""2"
  1006  	// """a"", ""b""1"	"""a"", ""b""2"
  1007  	// 1	2
  1008  	// sql --format=csv -e select 1 as "'a', 'b'1", 2 as "'a', 'b'2"
  1009  	// "'a', 'b'1","'a', 'b'2"
  1010  	// 1,2
  1011  	// sql --format=tsv -e select 1 as "'a', 'b'1", 2 as "'a', 'b'2"
  1012  	// 'a', 'b'1	'a', 'b'2
  1013  	// 1	2
  1014  	// sql --format=csv -e select 1 as "a\,b1", 2 as "a\,b2"
  1015  	// "a\,b1","a\,b2"
  1016  	// 1,2
  1017  	// sql --format=tsv -e select 1 as "a\,b1", 2 as "a\,b2"
  1018  	// a\,b1	a\,b2
  1019  	// 1	2
  1020  	// sql --format=csv -e select 1 as "a	b1", 2 as "a	b2"
  1021  	// a	b1,a	b2
  1022  	// 1,2
  1023  	// sql --format=tsv -e select 1 as "a	b1", 2 as "a	b2"
  1024  	// "a	b1"	"a	b2"
  1025  	// 1	2
  1026  }
  1027  
  1028  func Example_sql_table() {
  1029  	c := newCLITest(cliTestParams{})
  1030  	defer c.cleanup()
  1031  
  1032  	testData := []struct {
  1033  		str, desc string
  1034  	}{
  1035  		{"e'foo'", "printable ASCII"},
  1036  		{"e'\"foo'", "printable ASCII with quotes"},
  1037  		{"e'\\\\foo'", "printable ASCII with backslash"},
  1038  		{"e'foo\\x0abar'", "non-printable ASCII"},
  1039  		{"'κόσμε'", "printable UTF8"},
  1040  		{"e'\\xc3\\xb1'", "printable UTF8 using escapes"},
  1041  		{"e'\\x01'", "non-printable UTF8 string"},
  1042  		{"e'\\xdc\\x88\\x38\\x35'", "UTF8 string with RTL char"},
  1043  		{"e'a\\tb\\tc\\n12\\t123123213\\t12313'", "tabs"},
  1044  		{"e'\\xc3\\x28'", "non-UTF8 string"}, // This expects an insert error.
  1045  	}
  1046  
  1047  	c.RunWithArgs([]string{"sql", "-e", "create database t; create table t.t (s string, d string);"})
  1048  	for _, t := range testData {
  1049  		c.RunWithArgs([]string{"sql", "-e", "insert into t.t values (" + t.str + ", '" + t.desc + "')"})
  1050  	}
  1051  	c.RunWithArgs([]string{"sql", "-e", "select * from t.t"})
  1052  	for format := tableDisplayFormat(0); format < tableDisplayLastFormat; format++ {
  1053  		c.RunWithArgs([]string{"sql", "--format=" + format.String(), "-e", "select * from t.t"})
  1054  	}
  1055  
  1056  	// Output:
  1057  	// sql -e create database t; create table t.t (s string, d string);
  1058  	// CREATE TABLE
  1059  	// sql -e insert into t.t values (e'foo', 'printable ASCII')
  1060  	// INSERT 1
  1061  	// sql -e insert into t.t values (e'"foo', 'printable ASCII with quotes')
  1062  	// INSERT 1
  1063  	// sql -e insert into t.t values (e'\\foo', 'printable ASCII with backslash')
  1064  	// INSERT 1
  1065  	// sql -e insert into t.t values (e'foo\x0abar', 'non-printable ASCII')
  1066  	// INSERT 1
  1067  	// sql -e insert into t.t values ('κόσμε', 'printable UTF8')
  1068  	// INSERT 1
  1069  	// sql -e insert into t.t values (e'\xc3\xb1', 'printable UTF8 using escapes')
  1070  	// INSERT 1
  1071  	// sql -e insert into t.t values (e'\x01', 'non-printable UTF8 string')
  1072  	// INSERT 1
  1073  	// sql -e insert into t.t values (e'\xdc\x88\x38\x35', 'UTF8 string with RTL char')
  1074  	// INSERT 1
  1075  	// sql -e insert into t.t values (e'a\tb\tc\n12\t123123213\t12313', 'tabs')
  1076  	// INSERT 1
  1077  	// sql -e insert into t.t values (e'\xc3\x28', 'non-UTF8 string')
  1078  	// ERROR: lexical error: invalid UTF-8 byte sequence
  1079  	// SQLSTATE: 42601
  1080  	// DETAIL: source SQL:
  1081  	// insert into t.t values (e'\xc3\x28', 'non-UTF8 string')
  1082  	//                         ^
  1083  	// HINT: try \h VALUES
  1084  	// sql -e select * from t.t
  1085  	// s	d
  1086  	// foo	printable ASCII
  1087  	// """foo"	printable ASCII with quotes
  1088  	// \foo	printable ASCII with backslash
  1089  	// "foo
  1090  	// bar"	non-printable ASCII
  1091  	// κόσμε	printable UTF8
  1092  	// ñ	printable UTF8 using escapes
  1093  	// \x01	non-printable UTF8 string
  1094  	// ܈85	UTF8 string with RTL char
  1095  	// "a	b	c
  1096  	// 12	123123213	12313"	tabs
  1097  	// sql --format=tsv -e select * from t.t
  1098  	// s	d
  1099  	// foo	printable ASCII
  1100  	// """foo"	printable ASCII with quotes
  1101  	// \foo	printable ASCII with backslash
  1102  	// "foo
  1103  	// bar"	non-printable ASCII
  1104  	// κόσμε	printable UTF8
  1105  	// ñ	printable UTF8 using escapes
  1106  	// \x01	non-printable UTF8 string
  1107  	// ܈85	UTF8 string with RTL char
  1108  	// "a	b	c
  1109  	// 12	123123213	12313"	tabs
  1110  	// sql --format=csv -e select * from t.t
  1111  	// s,d
  1112  	// foo,printable ASCII
  1113  	// """foo",printable ASCII with quotes
  1114  	// \foo,printable ASCII with backslash
  1115  	// "foo
  1116  	// bar",non-printable ASCII
  1117  	// κόσμε,printable UTF8
  1118  	// ñ,printable UTF8 using escapes
  1119  	// \x01,non-printable UTF8 string
  1120  	// ܈85,UTF8 string with RTL char
  1121  	// "a	b	c
  1122  	// 12	123123213	12313",tabs
  1123  	// sql --format=table -e select * from t.t
  1124  	//            s          |               d
  1125  	// ----------------------+---------------------------------
  1126  	//   foo                 | printable ASCII
  1127  	//   "foo                | printable ASCII with quotes
  1128  	//   \foo                | printable ASCII with backslash
  1129  	//   foo                 | non-printable ASCII
  1130  	//   bar                 |
  1131  	//   κόσμε               | printable UTF8
  1132  	//   ñ                   | printable UTF8 using escapes
  1133  	//   \x01                | non-printable UTF8 string
  1134  	//   ܈85                 | UTF8 string with RTL char
  1135  	//   a   b         c     | tabs
  1136  	//   12  123123213 12313 |
  1137  	// (9 rows)
  1138  	// sql --format=records -e select * from t.t
  1139  	// -[ RECORD 1 ]
  1140  	// s | foo
  1141  	// d | printable ASCII
  1142  	// -[ RECORD 2 ]
  1143  	// s | "foo
  1144  	// d | printable ASCII with quotes
  1145  	// -[ RECORD 3 ]
  1146  	// s | \foo
  1147  	// d | printable ASCII with backslash
  1148  	// -[ RECORD 4 ]
  1149  	// s | foo+
  1150  	//   | bar
  1151  	// d | non-printable ASCII
  1152  	// -[ RECORD 5 ]
  1153  	// s | κόσμε
  1154  	// d | printable UTF8
  1155  	// -[ RECORD 6 ]
  1156  	// s | ñ
  1157  	// d | printable UTF8 using escapes
  1158  	// -[ RECORD 7 ]
  1159  	// s | \x01
  1160  	// d | non-printable UTF8 string
  1161  	// -[ RECORD 8 ]
  1162  	// s | ܈85
  1163  	// d | UTF8 string with RTL char
  1164  	// -[ RECORD 9 ]
  1165  	// s | a	b	c+
  1166  	//   | 12	123123213	12313
  1167  	// d | tabs
  1168  	// sql --format=sql -e select * from t.t
  1169  	// CREATE TABLE results (
  1170  	//   s STRING,
  1171  	//   d STRING
  1172  	// );
  1173  	//
  1174  	// INSERT INTO results VALUES ('foo', 'printable ASCII');
  1175  	// INSERT INTO results VALUES ('"foo', 'printable ASCII with quotes');
  1176  	// INSERT INTO results VALUES (e'\\foo', 'printable ASCII with backslash');
  1177  	// INSERT INTO results VALUES (e'foo\nbar', 'non-printable ASCII');
  1178  	// INSERT INTO results VALUES (e'\u03BA\U00001F79\u03C3\u03BC\u03B5', 'printable UTF8');
  1179  	// INSERT INTO results VALUES (e'\u00F1', 'printable UTF8 using escapes');
  1180  	// INSERT INTO results VALUES (e'\\x01', 'non-printable UTF8 string');
  1181  	// INSERT INTO results VALUES (e'\u070885', 'UTF8 string with RTL char');
  1182  	// INSERT INTO results VALUES (e'a\tb\tc\n12\t123123213\t12313', 'tabs');
  1183  	// -- 9 rows
  1184  	// sql --format=html -e select * from t.t
  1185  	// <table>
  1186  	// <thead><tr><th>row</th><th>s</th><th>d</th></tr></thead>
  1187  	// <tbody>
  1188  	// <tr><td>1</td><td>foo</td><td>printable ASCII</td></tr>
  1189  	// <tr><td>2</td><td>&#34;foo</td><td>printable ASCII with quotes</td></tr>
  1190  	// <tr><td>3</td><td>\foo</td><td>printable ASCII with backslash</td></tr>
  1191  	// <tr><td>4</td><td>foo<br/>bar</td><td>non-printable ASCII</td></tr>
  1192  	// <tr><td>5</td><td>κόσμε</td><td>printable UTF8</td></tr>
  1193  	// <tr><td>6</td><td>ñ</td><td>printable UTF8 using escapes</td></tr>
  1194  	// <tr><td>7</td><td>\x01</td><td>non-printable UTF8 string</td></tr>
  1195  	// <tr><td>8</td><td>܈85</td><td>UTF8 string with RTL char</td></tr>
  1196  	// <tr><td>9</td><td>a	b	c<br/>12	123123213	12313</td><td>tabs</td></tr>
  1197  	// </tbody>
  1198  	// <tfoot><tr><td colspan=3>9 rows</td></tr></tfoot></table>
  1199  	// sql --format=raw -e select * from t.t
  1200  	// # 2 columns
  1201  	// # row 1
  1202  	// ## 3
  1203  	// foo
  1204  	// ## 15
  1205  	// printable ASCII
  1206  	// # row 2
  1207  	// ## 4
  1208  	// "foo
  1209  	// ## 27
  1210  	// printable ASCII with quotes
  1211  	// # row 3
  1212  	// ## 4
  1213  	// \foo
  1214  	// ## 30
  1215  	// printable ASCII with backslash
  1216  	// # row 4
  1217  	// ## 7
  1218  	// foo
  1219  	// bar
  1220  	// ## 19
  1221  	// non-printable ASCII
  1222  	// # row 5
  1223  	// ## 11
  1224  	// κόσμε
  1225  	// ## 14
  1226  	// printable UTF8
  1227  	// # row 6
  1228  	// ## 2
  1229  	// ñ
  1230  	// ## 28
  1231  	// printable UTF8 using escapes
  1232  	// # row 7
  1233  	// ## 4
  1234  	// \x01
  1235  	// ## 25
  1236  	// non-printable UTF8 string
  1237  	// # row 8
  1238  	// ## 4
  1239  	// ܈85
  1240  	// ## 25
  1241  	// UTF8 string with RTL char
  1242  	// # row 9
  1243  	// ## 24
  1244  	// a	b	c
  1245  	// 12	123123213	12313
  1246  	// ## 4
  1247  	// tabs
  1248  	// # 9 rows
  1249  }
  1250  
  1251  func TestRenderHTML(t *testing.T) {
  1252  	defer leaktest.AfterTest(t)()
  1253  
  1254  	cols := []string{"colname"}
  1255  	align := "d"
  1256  	rows := [][]string{
  1257  		{"<b>foo</b>"},
  1258  		{"bar"},
  1259  	}
  1260  
  1261  	type testCase struct {
  1262  		reporter htmlReporter
  1263  		out      string
  1264  	}
  1265  
  1266  	testCases := []testCase{
  1267  		{
  1268  			reporter: htmlReporter{},
  1269  			out: `<table>
  1270  <thead><tr><th>colname</th></tr></thead>
  1271  <tbody>
  1272  <tr><td><b>foo</b></td></tr>
  1273  <tr><td>bar</td></tr>
  1274  </tbody>
  1275  </table>
  1276  `,
  1277  		},
  1278  		{
  1279  			reporter: htmlReporter{escape: true},
  1280  			out: `<table>
  1281  <thead><tr><th>colname</th></tr></thead>
  1282  <tbody>
  1283  <tr><td>&lt;b&gt;foo&lt;/b&gt;</td></tr>
  1284  <tr><td>bar</td></tr>
  1285  </tbody>
  1286  </table>
  1287  `,
  1288  		},
  1289  		{
  1290  			reporter: htmlReporter{rowStats: true},
  1291  			out: `<table>
  1292  <thead><tr><th>row</th><th>colname</th></tr></thead>
  1293  <tbody>
  1294  <tr><td>1</td><td><b>foo</b></td></tr>
  1295  <tr><td>2</td><td>bar</td></tr>
  1296  </tbody>
  1297  <tfoot><tr><td colspan=2>2 rows</td></tr></tfoot></table>
  1298  `,
  1299  		},
  1300  		{
  1301  			reporter: htmlReporter{escape: true, rowStats: true},
  1302  			out: `<table>
  1303  <thead><tr><th>row</th><th>colname</th></tr></thead>
  1304  <tbody>
  1305  <tr><td>1</td><td>&lt;b&gt;foo&lt;/b&gt;</td></tr>
  1306  <tr><td>2</td><td>bar</td></tr>
  1307  </tbody>
  1308  <tfoot><tr><td colspan=2>2 rows</td></tr></tfoot></table>
  1309  `,
  1310  		},
  1311  	}
  1312  
  1313  	for _, tc := range testCases {
  1314  		name := fmt.Sprintf("escape=%v/rowStats=%v", tc.reporter.escape, tc.reporter.rowStats)
  1315  		t.Run(name, func(t *testing.T) {
  1316  			var buf bytes.Buffer
  1317  			err := render(&tc.reporter, &buf,
  1318  				cols, newRowSliceIter(rows, align),
  1319  				nil /* completedHook */, nil /* noRowsHook */)
  1320  			if err != nil {
  1321  				t.Fatal(err)
  1322  			}
  1323  			if tc.out != buf.String() {
  1324  				t.Errorf("expected:\n%s\ngot:\n%s", tc.out, buf.String())
  1325  			}
  1326  		})
  1327  	}
  1328  }
  1329  
  1330  func Example_misc_table() {
  1331  	c := newCLITest(cliTestParams{})
  1332  	defer c.cleanup()
  1333  
  1334  	c.RunWithArgs([]string{"sql", "-e", "create database t; create table t.t (s string, d string);"})
  1335  	c.RunWithArgs([]string{"sql", "--format=table", "-e", "select '  hai' as x"})
  1336  	c.RunWithArgs([]string{"sql", "--format=table", "-e", "explain select s, 'foo' from t.t"})
  1337  
  1338  	// Output:
  1339  	// sql -e create database t; create table t.t (s string, d string);
  1340  	// CREATE TABLE
  1341  	// sql --format=table -e select '  hai' as x
  1342  	//     x
  1343  	// ---------
  1344  	//     hai
  1345  	// (1 row)
  1346  	// sql --format=table -e explain select s, 'foo' from t.t
  1347  	//     tree    |    field    | description
  1348  	// ------------+-------------+--------------
  1349  	//             | distributed | true
  1350  	//             | vectorized  | false
  1351  	//   render    |             |
  1352  	//    └── scan |             |
  1353  	//             | table       | t@primary
  1354  	//             | spans       | FULL SCAN
  1355  	// (6 rows)
  1356  }
  1357  
  1358  func Example_cert() {
  1359  	c := newCLITest(cliTestParams{})
  1360  	defer c.cleanup()
  1361  
  1362  	c.RunWithCAArgs([]string{"cert", "create-client", "foo"})
  1363  	c.RunWithCAArgs([]string{"cert", "create-client", "Ομηρος"})
  1364  	c.RunWithCAArgs([]string{"cert", "create-client", "0foo"})
  1365  	c.RunWithCAArgs([]string{"cert", "create-client", ",foo"})
  1366  
  1367  	// Output:
  1368  	// cert create-client foo
  1369  	// cert create-client Ομηρος
  1370  	// cert create-client 0foo
  1371  	// cert create-client ,foo
  1372  	// ERROR: failed to generate client certificate and key: username ",foo" invalid
  1373  	// SQLSTATE: 42602
  1374  	// HINT: Usernames are case insensitive, must start with a letter, digit or underscore, may contain letters, digits, dashes, periods, or underscores, and must not exceed 63 characters.
  1375  }
  1376  
  1377  // TestFlagUsage is a basic test to make sure the fragile
  1378  // help template does not break.
  1379  func TestFlagUsage(t *testing.T) {
  1380  	defer leaktest.AfterTest(t)()
  1381  
  1382  	expUsage := `Usage:
  1383    cockroach [command]
  1384  
  1385  Available Commands:
  1386    start             start a node in a multi-node cluster
  1387    start-single-node start a single-node cluster
  1388    init              initialize a cluster
  1389    cert              create ca, node, and client certs
  1390    quit              drain and shut down a node
  1391  
  1392    sql               open a sql shell
  1393    auth-session      log in and out of HTTP sessions
  1394    node              list, inspect, drain or remove nodes
  1395    dump              dump sql tables
  1396  
  1397    nodelocal         upload and delete nodelocal files
  1398    demo              open a demo sql shell
  1399    gen               generate auxiliary files
  1400    version           output version information
  1401    debug             debugging commands
  1402    sqlfmt            format SQL statements
  1403    workload          [experimental] generators for data and query loads
  1404    systembench       Run systembench
  1405    help              Help about any command
  1406  
  1407  Flags:
  1408    -h, --help                             help for cockroach
  1409        --logtostderr Severity[=DEFAULT]   logs at or above this threshold go to stderr (default NONE)
  1410        --no-color                         disable standard error log colorization
  1411  
  1412  Use "cockroach [command] --help" for more information about a command.
  1413  `
  1414  	helpExpected := fmt.Sprintf("CockroachDB command-line interface and server.\n\n%s", expUsage)
  1415  	badFlagExpected := fmt.Sprintf("%s\nError: unknown flag: --foo\n", expUsage)
  1416  
  1417  	testCases := []struct {
  1418  		flags    []string
  1419  		expErr   bool
  1420  		expected string
  1421  	}{
  1422  		{[]string{"help"}, false, helpExpected},    // request help specifically
  1423  		{[]string{"--foo"}, true, badFlagExpected}, // unknown flag
  1424  	}
  1425  	for _, test := range testCases {
  1426  		t.Run(strings.Join(test.flags, ","), func(t *testing.T) {
  1427  			// Override os.Stdout or os.Stderr with our own.
  1428  			r, w, err := os.Pipe()
  1429  			if err != nil {
  1430  				t.Fatal(err)
  1431  			}
  1432  			cockroachCmd.SetOutput(w)
  1433  			defer cockroachCmd.SetOutput(nil)
  1434  
  1435  			done := make(chan error)
  1436  			var buf bytes.Buffer
  1437  			// copy the output in a separate goroutine so printing can't block indefinitely.
  1438  			go func() {
  1439  				// Copy reads 'r' until EOF is reached.
  1440  				_, err := io.Copy(&buf, r)
  1441  				done <- err
  1442  			}()
  1443  
  1444  			if err := Run(test.flags); err != nil {
  1445  				fmt.Fprintln(w, "Error:", err)
  1446  				if !test.expErr {
  1447  					t.Error(err)
  1448  				}
  1449  			}
  1450  
  1451  			// back to normal state
  1452  			w.Close()
  1453  			if err := <-done; err != nil {
  1454  				t.Fatal(err)
  1455  			}
  1456  
  1457  			// Filter out all test flags.
  1458  			testFlagRE := regexp.MustCompile(`--(test\.|vmodule|rewrite)`)
  1459  			lines := strings.Split(buf.String(), "\n")
  1460  			final := []string{}
  1461  			for _, l := range lines {
  1462  				if testFlagRE.MatchString(l) {
  1463  					continue
  1464  				}
  1465  				final = append(final, l)
  1466  			}
  1467  			got := strings.Join(final, "\n")
  1468  
  1469  			assert.Equal(t, test.expected, got)
  1470  		})
  1471  	}
  1472  }
  1473  
  1474  func Example_node() {
  1475  	c := newCLITest(cliTestParams{})
  1476  	defer c.cleanup()
  1477  
  1478  	// Refresh time series data, which is required to retrieve stats.
  1479  	if err := c.WriteSummaries(); err != nil {
  1480  		log.Fatalf(context.Background(), "Couldn't write stats summaries: %s", err)
  1481  	}
  1482  
  1483  	c.Run("node ls")
  1484  	c.Run("node ls --format=table")
  1485  	c.Run("node status 10000")
  1486  	c.RunWithArgs([]string{"sql", "-e", "drop database defaultdb"})
  1487  	c.Run("node ls")
  1488  
  1489  	// Output:
  1490  	// node ls
  1491  	// id
  1492  	// 1
  1493  	// node ls --format=table
  1494  	//   id
  1495  	// ------
  1496  	//    1
  1497  	// (1 row)
  1498  	// node status 10000
  1499  	// ERROR: node 10000 doesn't exist
  1500  	// sql -e drop database defaultdb
  1501  	// DROP DATABASE
  1502  	// node ls
  1503  	// id
  1504  	// 1
  1505  }
  1506  
  1507  func TestCLITimeout(t *testing.T) {
  1508  	defer leaktest.AfterTest(t)()
  1509  
  1510  	c := newCLITest(cliTestParams{})
  1511  	defer c.cleanup()
  1512  
  1513  	// Wrap the meat of the test in a retry loop. Setting a timeout like this is
  1514  	// racy as the operation may have succeeded by the time the scheduler gives
  1515  	// the timeout a chance to have an effect. We specify --all to include some
  1516  	// slower to access virtual tables in the query.
  1517  	testutils.SucceedsSoon(t, func() error {
  1518  		out, err := c.RunWithCapture("node status 1 --all --timeout 1ns")
  1519  		if err != nil {
  1520  			t.Fatal(err)
  1521  		}
  1522  
  1523  		const exp = `node status 1 --all --timeout 1ns
  1524  ERROR: query execution canceled due to statement timeout
  1525  SQLSTATE: 57014
  1526  `
  1527  		if out != exp {
  1528  			err := errors.Errorf("unexpected output:\n%q\nwanted:\n%q", out, exp)
  1529  			t.Log(err)
  1530  			return err
  1531  		}
  1532  		return nil
  1533  	})
  1534  }
  1535  
  1536  func TestNodeStatus(t *testing.T) {
  1537  	defer leaktest.AfterTest(t)()
  1538  
  1539  	t.Skip("currently flaky: #38151")
  1540  
  1541  	start := timeutil.Now()
  1542  	c := newCLITest(cliTestParams{})
  1543  	defer c.cleanup()
  1544  
  1545  	// Refresh time series data, which is required to retrieve stats.
  1546  	if err := c.WriteSummaries(); err != nil {
  1547  		t.Fatalf("couldn't write stats summaries: %s", err)
  1548  	}
  1549  
  1550  	out, err := c.RunWithCapture("node status 1 --format=table")
  1551  	if err != nil {
  1552  		t.Fatal(err)
  1553  	}
  1554  	checkNodeStatus(t, c, out, start)
  1555  
  1556  	out, err = c.RunWithCapture("node status --ranges --format=table")
  1557  	if err != nil {
  1558  		t.Fatal(err)
  1559  	}
  1560  	checkNodeStatus(t, c, out, start)
  1561  
  1562  	out, err = c.RunWithCapture("node status --stats --format=table")
  1563  	if err != nil {
  1564  		t.Fatal(err)
  1565  	}
  1566  	checkNodeStatus(t, c, out, start)
  1567  
  1568  	out, err = c.RunWithCapture("node status --ranges --stats --format=table")
  1569  	if err != nil {
  1570  		t.Fatal(err)
  1571  	}
  1572  	checkNodeStatus(t, c, out, start)
  1573  
  1574  	out, err = c.RunWithCapture("node status --decommission --format=table")
  1575  	if err != nil {
  1576  		t.Fatal(err)
  1577  	}
  1578  	checkNodeStatus(t, c, out, start)
  1579  
  1580  	out, err = c.RunWithCapture("node status --ranges --stats --decommission --format=table")
  1581  	if err != nil {
  1582  		t.Fatal(err)
  1583  	}
  1584  	checkNodeStatus(t, c, out, start)
  1585  
  1586  	out, err = c.RunWithCapture("node status --all --format=table")
  1587  	if err != nil {
  1588  		t.Fatal(err)
  1589  	}
  1590  	checkNodeStatus(t, c, out, start)
  1591  
  1592  	out, err = c.RunWithCapture("node status --format=table")
  1593  	if err != nil {
  1594  		t.Fatal(err)
  1595  	}
  1596  	checkNodeStatus(t, c, out, start)
  1597  }
  1598  
  1599  func checkNodeStatus(t *testing.T, c cliTest, output string, start time.Time) {
  1600  	buf := bytes.NewBufferString(output)
  1601  	s := bufio.NewScanner(buf)
  1602  
  1603  	type testCase struct {
  1604  		name   string
  1605  		idx    int
  1606  		maxval int64
  1607  	}
  1608  
  1609  	// Skip command line.
  1610  	if !s.Scan() {
  1611  		t.Fatalf("Couldn't skip command line: %s", s.Err())
  1612  	}
  1613  
  1614  	// check column names.
  1615  	if !s.Scan() {
  1616  		t.Fatalf("Error reading column names: %s", s.Err())
  1617  	}
  1618  	cols, err := extractFields(s.Text())
  1619  	if err != nil {
  1620  		t.Fatalf("%s", err)
  1621  	}
  1622  	if !reflect.DeepEqual(cols, getStatusNodeHeaders()) {
  1623  		t.Fatalf("columns (%s) don't match expected (%s)", cols, getStatusNodeHeaders())
  1624  	}
  1625  
  1626  	checkSeparatorLine(t, s)
  1627  
  1628  	// Check node status.
  1629  	if !s.Scan() {
  1630  		t.Fatalf("error reading node status: %s", s.Err())
  1631  	}
  1632  	fields, err := extractFields(s.Text())
  1633  	if err != nil {
  1634  		t.Fatalf("%s", err)
  1635  	}
  1636  
  1637  	nodeID := c.Gossip().NodeID.Get()
  1638  	nodeIDStr := strconv.FormatInt(int64(nodeID), 10)
  1639  	if a, e := fields[0], nodeIDStr; a != e {
  1640  		t.Errorf("node id (%s) != expected (%s)", a, e)
  1641  	}
  1642  
  1643  	nodeAddr, err := c.Gossip().GetNodeIDAddress(nodeID)
  1644  	if err != nil {
  1645  		t.Fatal(err)
  1646  	}
  1647  	if a, e := fields[1], nodeAddr.String(); a != e {
  1648  		t.Errorf("node address (%s) != expected (%s)", a, e)
  1649  	}
  1650  
  1651  	nodeSQLAddr, err := c.Gossip().GetNodeIDSQLAddress(nodeID)
  1652  	if err != nil {
  1653  		t.Fatal(err)
  1654  	}
  1655  	if a, e := fields[2], nodeSQLAddr.String(); a != e {
  1656  		t.Errorf("node SQL address (%s) != expected (%s)", a, e)
  1657  	}
  1658  
  1659  	// Verify Build Tag.
  1660  	if a, e := fields[3], build.GetInfo().Tag; a != e {
  1661  		t.Errorf("build tag (%s) != expected (%s)", a, e)
  1662  	}
  1663  
  1664  	// Verify that updated_at and started_at are reasonably recent.
  1665  	// CircleCI can be very slow. This was flaky at 5s.
  1666  	checkTimeElapsed(t, fields[4], 15*time.Second, start)
  1667  	checkTimeElapsed(t, fields[5], 15*time.Second, start)
  1668  
  1669  	testcases := []testCase{}
  1670  
  1671  	// We're skipping over the first 5 default fields such as node id and
  1672  	// address. They don't need closer checks.
  1673  	baseIdx := len(baseNodeColumnHeaders)
  1674  
  1675  	// Adding fields that need verification for --ranges flag.
  1676  	// We have to allow up to 1 unavailable/underreplicated range because
  1677  	// sometimes we run the `node status` command before the server has fully
  1678  	// initialized itself and it doesn't consider itself live yet. In such cases,
  1679  	// there will only be one range covering the entire keyspace because it won't
  1680  	// have been able to do any splits yet.
  1681  	if nodeCtx.statusShowRanges || nodeCtx.statusShowAll {
  1682  		testcases = append(testcases,
  1683  			testCase{"leader_ranges", baseIdx, 22},
  1684  			testCase{"leaseholder_ranges", baseIdx + 1, 22},
  1685  			testCase{"ranges", baseIdx + 2, 22},
  1686  			testCase{"unavailable_ranges", baseIdx + 3, 1},
  1687  			testCase{"underreplicated_ranges", baseIdx + 4, 1},
  1688  		)
  1689  		baseIdx += len(statusNodesColumnHeadersForRanges)
  1690  	}
  1691  
  1692  	// Adding fields that need verification for --stats flag.
  1693  	if nodeCtx.statusShowStats || nodeCtx.statusShowAll {
  1694  		testcases = append(testcases,
  1695  			testCase{"live_bytes", baseIdx, 100000},
  1696  			testCase{"key_bytes", baseIdx + 1, 50000},
  1697  			testCase{"value_bytes", baseIdx + 2, 100000},
  1698  			testCase{"intent_bytes", baseIdx + 3, 50000},
  1699  			testCase{"system_bytes", baseIdx + 4, 50000},
  1700  		)
  1701  		baseIdx += len(statusNodesColumnHeadersForStats)
  1702  	}
  1703  
  1704  	if nodeCtx.statusShowDecommission || nodeCtx.statusShowAll {
  1705  		testcases = append(testcases,
  1706  			testCase{"gossiped_replicas", baseIdx, 30},
  1707  		)
  1708  		baseIdx++
  1709  	}
  1710  
  1711  	for _, tc := range testcases {
  1712  		val, err := strconv.ParseInt(fields[tc.idx], 10, 64)
  1713  		if err != nil {
  1714  			t.Errorf("couldn't parse %s '%s': %v", tc.name, fields[tc.idx], err)
  1715  			continue
  1716  		}
  1717  		if val < 0 {
  1718  			t.Errorf("value for %s (%d) cannot be less than 0", tc.name, val)
  1719  			continue
  1720  		}
  1721  		if val > tc.maxval {
  1722  			t.Errorf("value for %s (%d) greater than max (%d)", tc.name, val, tc.maxval)
  1723  		}
  1724  	}
  1725  
  1726  	if nodeCtx.statusShowDecommission || nodeCtx.statusShowAll {
  1727  		names := []string{"is_decommissioning", "is_draining"}
  1728  		for i := range names {
  1729  			if fields[baseIdx] != "false" {
  1730  				t.Errorf("value for %s (%s) should be false", names[i], fields[baseIdx])
  1731  			}
  1732  			baseIdx++
  1733  		}
  1734  	}
  1735  }
  1736  
  1737  var separatorLineExp = regexp.MustCompile(`[\+-]+$`)
  1738  
  1739  func checkSeparatorLine(t *testing.T, s *bufio.Scanner) {
  1740  	if !s.Scan() {
  1741  		t.Fatalf("error reading separator line: %s", s.Err())
  1742  	}
  1743  	if !separatorLineExp.MatchString(s.Text()) {
  1744  		t.Fatalf("separator line not found: %s", s.Text())
  1745  	}
  1746  }
  1747  
  1748  // checkRecentTime produces a test error if the time is not within the specified number
  1749  // of seconds of the given start time.
  1750  func checkTimeElapsed(t *testing.T, timeStr string, elapsed time.Duration, start time.Time) {
  1751  	// Truncate start time, because the CLI currently outputs times with a second-level
  1752  	// granularity.
  1753  	start = start.Truncate(time.Second)
  1754  	tm, err := time.ParseInLocation(localTimeFormat, timeStr, start.Location())
  1755  	if err != nil {
  1756  		t.Errorf("couldn't parse time '%s': %s", timeStr, err)
  1757  		return
  1758  	}
  1759  	end := start.Add(elapsed)
  1760  	if tm.Before(start) || tm.After(end) {
  1761  		t.Errorf("time (%s) not within range [%s,%s]", tm, start, end)
  1762  	}
  1763  }
  1764  
  1765  // extractFields extracts the fields from a pretty-printed row of SQL output,
  1766  // discarding excess whitespace and column separators.
  1767  func extractFields(line string) ([]string, error) {
  1768  	fields := strings.Split(line, "|")
  1769  	// fields has two extra entries, one for the empty token to the left of the first
  1770  	// |, and another empty one to the right of the final |. So, we need to take those
  1771  	// out.
  1772  	if a, e := len(fields), len(getStatusNodeHeaders()); a != e {
  1773  		return nil, errors.Errorf("can't extract fields: # of fields (%d) != expected (%d)", a, e)
  1774  	}
  1775  	var r []string
  1776  	for _, f := range fields {
  1777  		r = append(r, strings.TrimSpace(f))
  1778  	}
  1779  	return r, nil
  1780  }
  1781  
  1782  func TestGenMan(t *testing.T) {
  1783  	defer leaktest.AfterTest(t)()
  1784  
  1785  	// Generate man pages in a temp directory.
  1786  	manpath, err := ioutil.TempDir("", "TestGenMan")
  1787  	if err != nil {
  1788  		t.Fatal(err)
  1789  	}
  1790  	defer func() {
  1791  		if err := os.RemoveAll(manpath); err != nil {
  1792  			t.Errorf("couldn't remove temporary directory %s: %s", manpath, err)
  1793  		}
  1794  	}()
  1795  	if err := Run([]string{"gen", "man", "--path=" + manpath}); err != nil {
  1796  		t.Fatal(err)
  1797  	}
  1798  
  1799  	// Ensure we have a sane number of man pages.
  1800  	count := 0
  1801  	err = filepath.Walk(manpath, func(path string, info os.FileInfo, err error) error {
  1802  		if strings.HasSuffix(path, ".1") && !info.IsDir() {
  1803  			count++
  1804  		}
  1805  		return nil
  1806  	})
  1807  	if err != nil {
  1808  		t.Fatal(err)
  1809  	}
  1810  	if min := 20; count < min {
  1811  		t.Errorf("number of man pages (%d) < minimum (%d)", count, min)
  1812  	}
  1813  }
  1814  
  1815  func TestGenAutocomplete(t *testing.T) {
  1816  	defer leaktest.AfterTest(t)()
  1817  
  1818  	// Get a unique path to which we can write our autocomplete files.
  1819  	acdir, err := ioutil.TempDir("", "TestGenAutoComplete")
  1820  	if err != nil {
  1821  		t.Fatal(err)
  1822  	}
  1823  	defer func() {
  1824  		if err := os.RemoveAll(acdir); err != nil {
  1825  			t.Errorf("couldn't remove temporary directory %s: %s", acdir, err)
  1826  		}
  1827  	}()
  1828  
  1829  	for _, tc := range []struct {
  1830  		shell  string
  1831  		expErr string
  1832  	}{
  1833  		{shell: ""},
  1834  		{shell: "bash"},
  1835  		{shell: "zsh"},
  1836  		{shell: "bad", expErr: `invalid argument "bad" for "cockroach gen autocomplete"`},
  1837  	} {
  1838  		t.Run("shell="+tc.shell, func(t *testing.T) {
  1839  			const minsize = 1000
  1840  			acpath := filepath.Join(acdir, "output-"+tc.shell)
  1841  
  1842  			args := []string{"gen", "autocomplete", "--out=" + acpath}
  1843  			if len(tc.shell) > 0 {
  1844  				args = append(args, tc.shell)
  1845  			}
  1846  			err := Run(args)
  1847  			if tc.expErr == "" {
  1848  				if err != nil {
  1849  					t.Fatal(err)
  1850  				}
  1851  			} else {
  1852  				if !testutils.IsError(err, tc.expErr) {
  1853  					t.Fatalf("expected error %s, found %v", tc.expErr, err)
  1854  				}
  1855  				return
  1856  			}
  1857  
  1858  			info, err := os.Stat(acpath)
  1859  			if err != nil {
  1860  				t.Fatal(err)
  1861  			}
  1862  			if size := info.Size(); size < minsize {
  1863  				t.Fatalf("autocomplete file size (%d) < minimum (%d)", size, minsize)
  1864  			}
  1865  		})
  1866  	}
  1867  }
  1868  
  1869  func TestJunkPositionalArguments(t *testing.T) {
  1870  	defer leaktest.AfterTest(t)()
  1871  
  1872  	c := newCLITest(cliTestParams{t: t, noServer: true})
  1873  	defer c.cleanup()
  1874  
  1875  	for i, test := range []string{
  1876  		"start",
  1877  		"sql",
  1878  		"gen man",
  1879  		"gen example-data intro",
  1880  	} {
  1881  		const junk = "junk"
  1882  		line := test + " " + junk
  1883  		out, err := c.RunWithCapture(line)
  1884  		if err != nil {
  1885  			t.Fatalf("%d: %v", i, err)
  1886  		}
  1887  		exp := fmt.Sprintf("%s\nERROR: unknown command %q for \"cockroach %s\"\n", line, junk, test)
  1888  		if exp != out {
  1889  			t.Errorf("%d: expected:\n%s\ngot:\n%s", i, exp, out)
  1890  		}
  1891  	}
  1892  }
  1893  
  1894  func TestWorkload(t *testing.T) {
  1895  	defer leaktest.AfterTest(t)()
  1896  
  1897  	c := newCLITest(cliTestParams{noServer: true})
  1898  	defer c.cleanup()
  1899  
  1900  	out, err := c.RunWithCapture("workload init --help")
  1901  	if err != nil {
  1902  		t.Fatal(err)
  1903  	}
  1904  
  1905  	if !strings.Contains(out, `startrek`) {
  1906  		t.Fatalf(`startrek workload failed to register got: %s`, out)
  1907  	}
  1908  }
  1909  
  1910  func Example_in_memory() {
  1911  	spec, err := base.NewStoreSpec("type=mem,size=1GiB")
  1912  	if err != nil {
  1913  		panic(err)
  1914  	}
  1915  	c := newCLITest(cliTestParams{
  1916  		storeSpecs: []base.StoreSpec{spec},
  1917  	})
  1918  	defer c.cleanup()
  1919  
  1920  	// Test some sql to ensure that the in memory store is working.
  1921  	c.RunWithArgs([]string{"sql", "-e", "create database t; create table t.f (x int, y int); insert into t.f values (42, 69)"})
  1922  	c.RunWithArgs([]string{"node", "ls"})
  1923  
  1924  	// Output:
  1925  	// sql -e create database t; create table t.f (x int, y int); insert into t.f values (42, 69)
  1926  	// INSERT 1
  1927  	// node ls
  1928  	// id
  1929  	// 1
  1930  	//
  1931  }
  1932  
  1933  func Example_pretty_print_numerical_strings() {
  1934  	c := newCLITest(cliTestParams{})
  1935  	defer c.cleanup()
  1936  
  1937  	// All strings in pretty-print output should be aligned to left regardless of their contents
  1938  	c.RunWithArgs([]string{"sql", "-e", "create database t; create table t.t (s string, d string);"})
  1939  	c.RunWithArgs([]string{"sql", "-e", "insert into t.t values (e'0', 'positive numerical string')"})
  1940  	c.RunWithArgs([]string{"sql", "-e", "insert into t.t values (e'-1', 'negative numerical string')"})
  1941  	c.RunWithArgs([]string{"sql", "-e", "insert into t.t values (e'1.0', 'decimal numerical string')"})
  1942  	c.RunWithArgs([]string{"sql", "-e", "insert into t.t values (e'aaaaa', 'non-numerical string')"})
  1943  	c.RunWithArgs([]string{"sql", "--format=table", "-e", "select * from t.t"})
  1944  
  1945  	// Output:
  1946  	// sql -e create database t; create table t.t (s string, d string);
  1947  	// CREATE TABLE
  1948  	// sql -e insert into t.t values (e'0', 'positive numerical string')
  1949  	// INSERT 1
  1950  	// sql -e insert into t.t values (e'-1', 'negative numerical string')
  1951  	// INSERT 1
  1952  	// sql -e insert into t.t values (e'1.0', 'decimal numerical string')
  1953  	// INSERT 1
  1954  	// sql -e insert into t.t values (e'aaaaa', 'non-numerical string')
  1955  	// INSERT 1
  1956  	// sql --format=table -e select * from t.t
  1957  	//     s   |             d
  1958  	// --------+----------------------------
  1959  	//   0     | positive numerical string
  1960  	//   -1    | negative numerical string
  1961  	//   1.0   | decimal numerical string
  1962  	//   aaaaa | non-numerical string
  1963  	// (4 rows)
  1964  }
  1965  
  1966  func Example_sqlfmt() {
  1967  	c := newCLITest(cliTestParams{noServer: true})
  1968  	defer c.cleanup()
  1969  
  1970  	c.RunWithArgs([]string{"sqlfmt", "-e", ";"})
  1971  	c.RunWithArgs([]string{"sqlfmt", "-e", "delete from t"})
  1972  	c.RunWithArgs([]string{"sqlfmt", "-e", "delete from t", "-e", "update t set a = 1"})
  1973  	c.RunWithArgs([]string{"sqlfmt", "--print-width=10", "-e", "select 1,2,3 from a,b,c;;;select 4"})
  1974  	c.RunWithArgs([]string{"sqlfmt", "--print-width=10", "--align", "-e", "select 1,2,3 from a,b,c;;;select 4"})
  1975  	c.RunWithArgs([]string{"sqlfmt", "--print-width=10", "--tab-width=2", "--use-spaces", "-e", "select 1,2,3 from a,b,c;;;select 4"})
  1976  	c.RunWithArgs([]string{"sqlfmt", "-e", "select (1+2)+3"})
  1977  	c.RunWithArgs([]string{"sqlfmt", "--no-simplify", "-e", "select (1+2)+3"})
  1978  
  1979  	// Output:
  1980  	// sqlfmt -e ;
  1981  	// sqlfmt -e delete from t
  1982  	// DELETE FROM t
  1983  	// sqlfmt -e delete from t -e update t set a = 1
  1984  	// DELETE FROM t;
  1985  	// UPDATE t SET a = 1;
  1986  	// sqlfmt --print-width=10 -e select 1,2,3 from a,b,c;;;select 4
  1987  	// SELECT
  1988  	// 	1,
  1989  	// 	2,
  1990  	// 	3
  1991  	// FROM
  1992  	// 	a,
  1993  	// 	b,
  1994  	// 	c;
  1995  	// SELECT 4;
  1996  	// sqlfmt --print-width=10 --align -e select 1,2,3 from a,b,c;;;select 4
  1997  	// SELECT 1,
  1998  	//        2,
  1999  	//        3
  2000  	//   FROM a,
  2001  	//        b,
  2002  	//        c;
  2003  	// SELECT 4;
  2004  	// sqlfmt --print-width=10 --tab-width=2 --use-spaces -e select 1,2,3 from a,b,c;;;select 4
  2005  	// SELECT
  2006  	//   1, 2, 3
  2007  	// FROM
  2008  	//   a, b, c;
  2009  	// SELECT 4;
  2010  	// sqlfmt -e select (1+2)+3
  2011  	// SELECT 1 + 2 + 3
  2012  	// sqlfmt --no-simplify -e select (1+2)+3
  2013  	// SELECT (1 + 2) + 3
  2014  }
  2015  
  2016  func Example_dump_no_visible_columns() {
  2017  	c := newCLITest(cliTestParams{})
  2018  	defer c.cleanup()
  2019  
  2020  	c.RunWithArgs([]string{"sql", "-e", "create table t(x int); set sql_safe_updates=false; alter table t drop x"})
  2021  	c.RunWithArgs([]string{"dump", "defaultdb"})
  2022  
  2023  	// Output:
  2024  	// sql -e create table t(x int); set sql_safe_updates=false; alter table t drop x
  2025  	// ALTER TABLE
  2026  	// dump defaultdb
  2027  	// CREATE TABLE t (FAMILY "primary" (rowid)
  2028  	// );
  2029  }