diff --git a/go/cmd/dolt/commands/add.go b/go/cmd/dolt/commands/add.go index 785a358765..8c10f62163 100644 --- a/go/cmd/dolt/commands/add.go +++ b/go/cmd/dolt/commands/add.go @@ -21,10 +21,10 @@ import ( "fmt" "io" "sort" - "strconv" "strings" "github.com/dolthub/go-mysql-server/sql" + gmstypes "github.com/dolthub/go-mysql-server/sql/types" "github.com/dolthub/ishell" "github.com/fatih/color" "golang.org/x/exp/slices" @@ -164,7 +164,9 @@ func (cmd AddCmd) Exec(ctx context.Context, commandStr string, args []string, _ } func patchWorkflow(sqlCtx *sql.Context, queryist cli.Queryist, tables []string) int { - if len(tables) == 0 { + if len(tables) == 0 || (len(tables) == 1 && tables[0] == ".") { + tables = tables[:0] // in the event that the user specified '.' as the only argument, we want to clear the list of tables + // Get the list of tables to patch _, rowIter, _, err := queryist.Query(sqlCtx, "select table_name from dolt_status where not staged") if err != nil { @@ -183,6 +185,12 @@ func patchWorkflow(sqlCtx *sql.Context, queryist cli.Queryist, tables []string) tables = append(tables, tbl) } } + + if len(tables) == 0 { + cli.Println("No changes.") + return 0 + } + sort.Strings(tables) runAddPatchShell(sqlCtx, queryist, tables) @@ -224,12 +232,12 @@ func runAddPatchShell(sqlCtx *sql.Context, queryist cli.Queryist, tables []strin shell.AddCmd(&ishell.Cmd{ Name: "y", Help: "stage the current change", - Func: state.opYes, + Func: state.stageCurrentChange, }) shell.AddCmd(&ishell.Cmd{ Name: "n", Help: "do not stage the current change", - Func: state.opNo, + Func: state.skipCurrentChange, }) shell.AddCmd(&ishell.Cmd{ Name: "q", @@ -241,12 +249,12 @@ func runAddPatchShell(sqlCtx *sql.Context, queryist cli.Queryist, tables []strin shell.AddCmd(&ishell.Cmd{ Name: "a", Help: "add all changes in this table", - Func: state.opAddAllOfTable, + Func: state.addRemainingInTable, }) shell.AddCmd(&ishell.Cmd{ Name: "d", Help: "do not stage any further changes in this table", - Func: state.opSkipTable, + Func: state.skipRemainingInTable, }) shell.AddCmd(&ishell.Cmd{ Name: "s", @@ -287,7 +295,7 @@ func queryForUnstagedChanges(sqlCtx *sql.Context, queryist cli.Queryist, tables } if len(rows) == 0 { - // This can happen if the user has added all changes in a table, thn restarted the workflow. + // This can happen if the user has added all changes in a table, then restarted the workflow. continue } @@ -353,20 +361,11 @@ func queryForUnstagedChanges(sqlCtx *sql.Context, queryist cli.Queryist, tables } func coerceToInt(val interface{}) (int, error) { - switch v := val.(type) { - case int: - return v, nil - case int64: - return int(v), nil - case string: - i, err := strconv.Atoi(v) - if err != nil { - return 0, err - } - return i, nil - default: - return 0, errors.New("Expected int, int64 or string") + val, _, err := gmstypes.Int32.Convert(val) + if err != nil { + return 0, err } + return int(val.(int32)), nil } // queryForSingleChange queries the dolt_workspace_* table for the row with the given ID. @@ -412,8 +411,8 @@ type patchState struct { err error } -// opYes stages the current change. "a" command. -func (ps *patchState) opYes(c *ishell.Context) { +// stageCurrentChange stages the current change. "a" command. +func (ps *patchState) stageCurrentChange(c *ishell.Context) { qry := fmt.Sprintf("UPDATE dolt_workspace_%s SET staged = TRUE WHERE id = %d", ps.currentTable, ps.currentRowId) _, iter, _, err := ps.queryist.Query(ps.sqlCtx, qry) if err != nil { @@ -422,7 +421,7 @@ func (ps *patchState) opYes(c *ishell.Context) { return } - // The Update operation doesn't return any rows, but we need to itterate over it to ensure that the update + // The Update operation doesn't return any rows, but we need to iterate over it to ensure that the update // is made when the queryist we are using for a local query engine. for { _, err = iter.Next(ps.sqlCtx) @@ -451,8 +450,8 @@ func (ps *patchState) opYes(c *ishell.Context) { } } -// opNo does not stage the current change. "n" command. -func (ps *patchState) opNo(c *ishell.Context) { +// skipCurrentChange does not stage the current change. "n" command. +func (ps *patchState) skipCurrentChange(c *ishell.Context) { ps.currentRowId++ if ps.currentRowId <= ps.currentTableLastRowId { ps.setCurrentRowState(c) @@ -461,13 +460,13 @@ func (ps *patchState) opNo(c *ishell.Context) { } } -// opSkipTable skips the current table. "d" command. -func (ps *patchState) opSkipTable(c *ishell.Context) { +// skipRemainingInTable skips the current table. "d" command. +func (ps *patchState) skipRemainingInTable(c *ishell.Context) { ps.nextTable(c) } -// opAddAllOfTable adds all changes in the current table. "a" command. -func (ps *patchState) opAddAllOfTable(c *ishell.Context) { +// addRemainingInTable adds all changes in the current table. "a" command. +func (ps *patchState) addRemainingInTable(c *ishell.Context) { // grab the row id. id, err := coerceToInt(ps.currentRow[0]) if err != nil { @@ -575,7 +574,9 @@ func (ps *patchState) nextTable(c *ishell.Context) { ps.setCurrentRowState(c) } else { - c.Stop() + if c != nil { + c.Stop() + } } } @@ -671,7 +672,7 @@ func printTableSummary(tables []string, counts map[string]*tablePatchInfo) { for _, tbl := range tables { c := counts[tbl] if c == nil { - // This can happen if the user has added all changes in a table, thn restarted the workflow. + // This can happen if the user has added all changes in a table, then restarted the workflow. continue } @@ -684,7 +685,7 @@ func printTableSummary(tables []string, counts map[string]*tablePatchInfo) { totalChgCount += c.total() } - // If the user has a lot of changes, we want to inform the user them may have better options. + // If the user has a lot of changes, we want to inform the user they may have better options. if totalChgCount > 25 { warning := `You have %d changes in total. Consider updating dolt_workspace_* tables directly as 'add --patch' requires you to individually evaluate each changed row. diff --git a/go/cmd/dolt/doltversion/version.go b/go/cmd/dolt/doltversion/version.go index c1dc634048..e7fbd1c30d 100644 --- a/go/cmd/dolt/doltversion/version.go +++ b/go/cmd/dolt/doltversion/version.go @@ -16,5 +16,5 @@ package doltversion const ( - Version = "1.42.19" + Version = "1.42.20" ) diff --git a/go/go.mod b/go/go.mod index f1d658b0a8..1d41e5258e 100644 --- a/go/go.mod +++ b/go/go.mod @@ -15,7 +15,7 @@ require ( github.com/dolthub/fslock v0.0.3 github.com/dolthub/ishell v0.0.0-20240701202509-2b217167d718 github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 - github.com/dolthub/vitess v0.0.0-20240910182452-9291457d0a98 + github.com/dolthub/vitess v0.0.0-20240913073519-a282f4c775fc github.com/dustin/go-humanize v1.0.1 github.com/fatih/color v1.16.0 github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568 @@ -57,7 +57,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 github.com/creasty/defaults v1.6.0 github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 - github.com/dolthub/go-mysql-server v0.18.2-0.20240912201416-87cdecf51cd1 + github.com/dolthub/go-mysql-server v0.18.2-0.20240913084037-b11701419243 github.com/dolthub/gozstd v0.0.0-20240423170813-23a2903bca63 github.com/dolthub/swiss v0.1.0 github.com/goccy/go-json v0.10.2 diff --git a/go/go.sum b/go/go.sum index 64f992ebf4..e861230c3f 100644 --- a/go/go.sum +++ b/go/go.sum @@ -183,8 +183,8 @@ github.com/dolthub/fslock v0.0.3 h1:iLMpUIvJKMKm92+N1fmHVdxJP5NdyDK5bK7z7Ba2s2U= github.com/dolthub/fslock v0.0.3/go.mod h1:QWql+P17oAAMLnL4HGB5tiovtDuAjdDTPbuqx7bYfa0= github.com/dolthub/go-icu-regex v0.0.0-20230524105445-af7e7991c97e h1:kPsT4a47cw1+y/N5SSCkma7FhAPw7KeGmD6c9PBZW9Y= github.com/dolthub/go-icu-regex v0.0.0-20230524105445-af7e7991c97e/go.mod h1:KPUcpx070QOfJK1gNe0zx4pA5sicIK1GMikIGLKC168= -github.com/dolthub/go-mysql-server v0.18.2-0.20240912201416-87cdecf51cd1 h1:w2C4QGnyXtoqya+Ug3G8v63gBLLYGF5HBsEujLVgCtQ= -github.com/dolthub/go-mysql-server v0.18.2-0.20240912201416-87cdecf51cd1/go.mod h1:qG/flwaEzJaI/ZvwlEZyNljSU9UOO54r1Yhv0GnxNgk= +github.com/dolthub/go-mysql-server v0.18.2-0.20240913084037-b11701419243 h1:o1Dz7IKnNdypk8XpvWhgG4lmexggxptFZ1a8baHgpyI= +github.com/dolthub/go-mysql-server v0.18.2-0.20240913084037-b11701419243/go.mod h1:Qw0rloOdFuqoKMJIHtAcThfvJ5OCjG/nEQgoZ0xwbcs= github.com/dolthub/gozstd v0.0.0-20240423170813-23a2903bca63 h1:OAsXLAPL4du6tfbBgK0xXHZkOlos63RdKYS3Sgw/dfI= github.com/dolthub/gozstd v0.0.0-20240423170813-23a2903bca63/go.mod h1:lV7lUeuDhH5thVGDCKXbatwKy2KW80L4rMT46n+Y2/Q= github.com/dolthub/ishell v0.0.0-20240701202509-2b217167d718 h1:lT7hE5k+0nkBdj/1UOSFwjWpNxf+LCApbRHgnCA17XE= @@ -197,8 +197,8 @@ github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 h1:7/v8q9X github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81/go.mod h1:siLfyv2c92W1eN/R4QqG/+RjjX5W2+gCTRjZxBjI3TY= github.com/dolthub/swiss v0.1.0 h1:EaGQct3AqeP/MjASHLiH6i4TAmgbG/c4rA6a1bzCOPc= github.com/dolthub/swiss v0.1.0/go.mod h1:BeucyB08Vb1G9tumVN3Vp/pyY4AMUnr9p7Rz7wJ7kAQ= -github.com/dolthub/vitess v0.0.0-20240910182452-9291457d0a98 h1:f4Y0ZUO3SPsgS88w5X377tYSHVLlA8JzvKbNu2C5uks= -github.com/dolthub/vitess v0.0.0-20240910182452-9291457d0a98/go.mod h1:uBvlRluuL+SbEWTCZ68o0xvsdYZER3CEG/35INdzfJM= +github.com/dolthub/vitess v0.0.0-20240913073519-a282f4c775fc h1:vOtgyBF27SgUQzkaQbFyuaouK0uEWG3ZOC3l8h2K6vs= +github.com/dolthub/vitess v0.0.0-20240913073519-a282f4c775fc/go.mod h1:uBvlRluuL+SbEWTCZ68o0xvsdYZER3CEG/35INdzfJM= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= diff --git a/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go b/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go index 3c50f01d41..3d7dcec8f0 100644 --- a/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go +++ b/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go @@ -15,6 +15,7 @@ package dfunctions import ( + "errors" "fmt" "github.com/dolthub/go-mysql-server/sql" @@ -39,13 +40,6 @@ func NewMergeBase(left, right sql.Expression) sql.Expression { // Eval implements the sql.Expression interface. func (d MergeBase) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { - if _, ok := d.Left().Type().(sql.StringType); !ok { - return nil, sql.ErrInvalidType.New(d.Left().Type()) - } - if _, ok := d.Right().Type().(sql.StringType); !ok { - return nil, sql.ErrInvalidType.New(d.Right().Type()) - } - leftSpec, err := d.Left().Eval(ctx, row) if err != nil { return nil, err @@ -59,7 +53,17 @@ func (d MergeBase) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { return nil, nil } - left, right, err := resolveRefSpecs(ctx, leftSpec.(string), rightSpec.(string)) + leftStr, ok := leftSpec.(string) + if !ok { + return nil, errors.New("left value is not a string") + } + + rightStr, ok := rightSpec.(string) + if !ok { + return nil, errors.New("right value is not a string") + } + + left, right, err := resolveRefSpecs(ctx, leftStr, rightStr) if err != nil { return nil, err } diff --git a/go/libraries/doltcore/sqle/statspro/configure.go b/go/libraries/doltcore/sqle/statspro/configure.go index e03cc19a29..ff384a2fbc 100644 --- a/go/libraries/doltcore/sqle/statspro/configure.go +++ b/go/libraries/doltcore/sqle/statspro/configure.go @@ -147,8 +147,6 @@ func (p *Provider) Load(ctx *sql.Context, fs filesys.Filesys, db dsess.SqlDataba } } - p.mu.Lock() - defer p.mu.Unlock() p.setStatDb(strings.ToLower(db.Name()), statsDb) return } diff --git a/go/libraries/doltcore/sqle/statspro/initdbhook.go b/go/libraries/doltcore/sqle/statspro/initdbhook.go index 3c50776b3c..1a354a2e05 100644 --- a/go/libraries/doltcore/sqle/statspro/initdbhook.go +++ b/go/libraries/doltcore/sqle/statspro/initdbhook.go @@ -37,15 +37,15 @@ func NewStatsInitDatabaseHook( denv *env.DoltEnv, db dsess.SqlDatabase, ) error { - statsDb, err := statsProv.sf.Init(ctx, db, statsProv.pro, denv.FS, env.GetCurrentUserHomeDir) - if err != nil { - ctx.GetLogger().Debugf("statistics load error: %s", err.Error()) - return nil + dbName := strings.ToLower(db.Name()) + if _, ok := statsProv.getStatDb(dbName); !ok { + statsDb, err := statsProv.sf.Init(ctx, db, statsProv.pro, denv.FS, env.GetCurrentUserHomeDir) + if err != nil { + ctx.GetLogger().Debugf("statistics load error: %s", err.Error()) + return nil + } + statsProv.setStatDb(dbName, statsDb) } - statsProv.mu.Lock() - statsProv.setStatDb(strings.ToLower(db.Name()), statsDb) - statsProv.mu.Unlock() - ctx.GetLogger().Debugf("statistics refresh: initialize %s", name) return statsProv.InitAutoRefresh(ctxFactory, name, bThreads) } diff --git a/go/libraries/doltcore/sqle/statspro/stats_provider.go b/go/libraries/doltcore/sqle/statspro/stats_provider.go index 6e7ecd29be..b22e0b48b6 100644 --- a/go/libraries/doltcore/sqle/statspro/stats_provider.go +++ b/go/libraries/doltcore/sqle/statspro/stats_provider.go @@ -186,6 +186,8 @@ func (p *Provider) GetTableDoltStats(ctx *sql.Context, branch, db, table string) } func (p *Provider) setStatDb(name string, db Database) { + p.mu.Lock() + defer p.mu.Unlock() p.statDbs[name] = db } diff --git a/integration-tests/bats/add-patch-expect/all_none.expect b/integration-tests/bats/add-patch-expect/all_none.expect new file mode 100755 index 0000000000..239e3f08fc --- /dev/null +++ b/integration-tests/bats/add-patch-expect/all_none.expect @@ -0,0 +1,18 @@ +#!/usr/bin/expect + +set timeout 5 +set env(NO_COLOR) 1 + +source "$env(BATS_CWD)/helper/common_expect_functions.tcl" + +# Specify tables +spawn dolt add -p coordinates colors + +# colors table will be first (alpha order). Add everything. +expect_with_defaults_2 { Yellow | 255 | 255 } {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "a\r"; } + +# coordinates table is next. +expect_with_defaults_2 {| - | 2 | 3.3 | 4.4 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "d\r"; } + +expect eof +exit diff --git a/integration-tests/bats/add-patch-expect/help_quit.expect b/integration-tests/bats/add-patch-expect/help_quit.expect new file mode 100755 index 0000000000..6bdb62bcae --- /dev/null +++ b/integration-tests/bats/add-patch-expect/help_quit.expect @@ -0,0 +1,15 @@ +#!/usr/bin/expect + +set timeout 5 +set env(NO_COLOR) 1 + +source "$env(BATS_CWD)/helper/common_expect_functions.tcl" + +spawn dolt add -p + +expect_with_defaults {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "?\r"; } + +expect_with_defaults_2 {\? - show this help} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "q\r"; } + +expect eof +exit diff --git a/integration-tests/bats/add-patch-expect/keyless.expect b/integration-tests/bats/add-patch-expect/keyless.expect new file mode 100755 index 0000000000..5d6d2eac25 --- /dev/null +++ b/integration-tests/bats/add-patch-expect/keyless.expect @@ -0,0 +1,22 @@ +#!/usr/bin/expect + +set timeout 5 +set env(NO_COLOR) 1 + +source "$env(BATS_CWD)/helper/common_expect_functions.tcl" + +spawn dolt add --patch + +# Header Regex for: +# Table Added / Modified / Removed +# ===== ===== ======== ======= +# keyless 1 1 1 +set header {.*Table\s+Added\s+/\s+Modified\s+/\s+Removed\s+=+\s+=+\s+=+\s+=+\s+keyless\s+2\s+0\s+2.*} + +expect_with_defaults_2 $header {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } +expect_with_defaults_2 {| - | 1 | 1 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "n\r"; } +expect_with_defaults_2 {| \+ | 4 | 4 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } +expect_with_defaults_2 {| \+ | 4 | 4 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "n\r"; } + +expect eof +exit diff --git a/integration-tests/bats/add-patch-expect/no_then_a.expect b/integration-tests/bats/add-patch-expect/no_then_a.expect new file mode 100755 index 0000000000..e17a84b65a --- /dev/null +++ b/integration-tests/bats/add-patch-expect/no_then_a.expect @@ -0,0 +1,25 @@ +#!/usr/bin/expect + +set timeout 5 +set env(NO_COLOR) 1 + +source "$env(BATS_CWD)/helper/common_expect_functions.tcl" + +spawn dolt add -p + +# This test will reject the first change for each of the 3 tables, then accept the rest. + +expect_with_defaults_2 {| \+ | 0 | Yellow | 255 | 255 | 0 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "n\r"; } + +expect_with_defaults_2 {| - | 2 | Green | 0 | 255 | 0 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "a\r"; } + +expect_with_defaults_2 {| - | 2 | 3.3 | 4.4 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "n\r"; } + +expect_with_defaults_2 {| < | 3 | 5.5 | 6.6 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "a\r"; } + +expect_with_defaults_2 {| < | 1 | neil |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "n\r"; } + +expect_with_defaults_2 {| - | 2 | sami |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "a\r"; } + +expect eof +exit diff --git a/integration-tests/bats/add-patch-expect/restart_multiple_times.expect b/integration-tests/bats/add-patch-expect/restart_multiple_times.expect new file mode 100755 index 0000000000..6f0a7c76ff --- /dev/null +++ b/integration-tests/bats/add-patch-expect/restart_multiple_times.expect @@ -0,0 +1,43 @@ +#!/usr/bin/expect + +set timeout 5 +set env(NO_COLOR) 1 + +source "$env(BATS_CWD)/helper/common_expect_functions.tcl" + +spawn dolt add --patch + +# This is a long script, but the idea is simple. Input y,n,y,s repeatedly and ensure that the right prompts are seen + +expect_with_defaults_2 {| \+ | 0 | Yellow | 255 | 255 | 0 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } + +expect_with_defaults_2 {| - | 2 | Green | 0 | 255 | 0 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "n\r"; } + +expect_with_defaults_2 {| > | 3 | SkyBlue | 0 | 128 | 255 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } + +expect_with_defaults_2 {| - | 2 | 3.3 | 4.4 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "s\r"; } + +expect_with_defaults_2 {| - | 2 | Green | 0 | 255 | 0 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } + +expect_with_defaults_2 {| - | 2 | 3.3 | 4.4 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "n\r"; } + +expect_with_defaults_2 {| > | 3 | 5.5 | 100.001 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } + +expect_with_defaults_2 {| \+ | 4 | 42.24 | 23.32 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "s\r"; } + +expect_with_defaults_2 {| - | 2 | 3.3 | 4.4 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } + +expect_with_defaults_2 {| \+ | 4 | 42.24 | 23.32 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "n\r"; } + +expect_with_defaults_2 {| > | 1 | joey |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } + +expect_with_defaults_2 {| - | 2 | sami |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "s\r"; } + +expect_with_defaults_2 {| \+ | 4 | 42.24 | 23.32 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } + +expect_with_defaults_2 {| - | 2 | sami |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "n\r"; } + +expect_with_defaults_2 {| \+ | 4 | john |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } + +expect eof +exit diff --git a/integration-tests/bats/add-patch-expect/summary_updates.expect b/integration-tests/bats/add-patch-expect/summary_updates.expect new file mode 100755 index 0000000000..5c5708035c --- /dev/null +++ b/integration-tests/bats/add-patch-expect/summary_updates.expect @@ -0,0 +1,60 @@ +#!/usr/bin/expect + +set timeout 5 +set env(NO_COLOR) 1 + +source "$env(BATS_CWD)/helper/common_expect_functions.tcl" + +spawn dolt add --patch + +# Header Regex for: +# Table Added / Modified / Removed +# ===== ===== ======== ======= +# colors 1 1 1 +# coordinates 1 1 1 +# names 1 1 1 +set header {.*Table\s+Added\s+/\s+Modified\s+/\s+Removed\s+=+\s+=+\s+=+\s+=+\s+colors\s+1\s+1\s+1\s+coordinates\s+1\s+1\s+1\s+names\s+1\s+1\s+1.*} + +expect_with_defaults_2 $header {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } +expect_with_defaults_2 {| - | 2 | Green | 0 | 255 | 0 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "n\r"; } +expect_with_defaults_2 {| > | 3 | SkyBlue | 0 | 128 | 255 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } +expect_with_defaults_2 {| - | 2 | 3.3 | 4.4 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "s\r"; } + +# Regex to match updated counts. +# Table Added / Modified / Removed +# ===== ===== ======== ======= +# colors 0 0 1 +# coordinates 1 1 1 +# names 1 1 1 +set header {.*Table\s+Added\s+/\s+Modified\s+/\s+Removed\s+=+\s+=+\s+=+\s+=+\s+colors\s+0\s+0\s+1\s+coordinates\s+1\s+1\s+1\s+names\s+1\s+1\s+1.*} + +expect_with_defaults_2 $header {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } +expect_with_defaults_2 {| - | 2 | 3.3 | 4.4 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "n\r"; } +expect_with_defaults_2 {| > | 3 | 5.5 | 100.001 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } +expect_with_defaults_2 {| \+ | 4 | 42.24 | 23.32 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "s\r"; } + +# Regex to match updated counts, and no colors table: +# Table Added / Modified / Removed +# ===== ===== ======== ======= +# coordinates 1 0 1 +# names 1 1 1 +set header {.*Table\s+Added\s+/\s+Modified\s+/\s+Removed\s+=+\s+=+\s+=+\s+=+\s+coordinates\s+1\s+0\s+1\s+names\s+1\s+1\s+1.*} + +expect_with_defaults_2 $header {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } +expect_with_defaults_2 {| \+ | 4 | 42.24 | 23.32 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "n\r"; } +expect_with_defaults_2 {| > | 1 | joey |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } +expect_with_defaults_2 {| - | 2 | sami |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "s\r"; } + +# Regex for: +# Table Added / Modified / Removed +# ===== ===== ======== ======= +# coordinates 1 0 0 +# names 1 0 1 +set header {.*Table\s+Added\s+/\s+Modified\s+/\s+Removed\s+=+\s+=+\s+=+\s+=+\s+coordinates\s+1\s+0\s+0\s+names\s+1\s+0\s+1.*} + +expect_with_defaults_2 $header {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } +expect_with_defaults_2 {| - | 2 | sami |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "n\r"; } +expect_with_defaults_2 {| \+ | 4 | john |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } + +expect eof +exit diff --git a/integration-tests/bats/add-patch-expect/yes_then_d.expect b/integration-tests/bats/add-patch-expect/yes_then_d.expect new file mode 100755 index 0000000000..ad2662d7c9 --- /dev/null +++ b/integration-tests/bats/add-patch-expect/yes_then_d.expect @@ -0,0 +1,26 @@ +#!/usr/bin/expect + +set timeout 5 +set env(NO_COLOR) 1 + +source "$env(BATS_CWD)/helper/common_expect_functions.tcl" + +# Verify add -p . gets all the tables. +spawn dolt add -p . + +# This test will accept the first change for each of the 3 tables, then skip the rest. + +expect_with_defaults_2 {| \+ | 0 | Yellow | 255 | 255 | 0 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } + +expect_with_defaults_2 {| - | 2 | Green | 0 | 255 | 0 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "d\r"; } + +expect_with_defaults_2 {| - | 2 | 3.3 | 4.4 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } + +expect_with_defaults_2 {| < | 3 | 5.5 | 6.6 |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "d\r"; } + +expect_with_defaults_2 {| < | 1 | neil |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "y\r"; } + +expect_with_defaults_2 {| - | 2 | sami |} {Stage this row \[y,n,q,a,d,s,\?\]\? } { send "d\r"; } + +expect eof +exit diff --git a/integration-tests/bats/add-patch.bats b/integration-tests/bats/add-patch.bats new file mode 100644 index 0000000000..5def10235d --- /dev/null +++ b/integration-tests/bats/add-patch.bats @@ -0,0 +1,326 @@ +#! /usr/bin/env bats +load $BATS_TEST_DIRNAME/helper/common.bash + +setup() { + skiponwindows "Need to install expect and make this script work on windows." + setup_common + + dolt sql < | 3 | SkyBlue | 0 | 128 | 255 | +# +---+----+---------+-----+-------+------+ +# diff --dolt a/coordinates b/coordinates +# --- a/coordinates +# +++ b/coordinates +# +---+----+-------+---------+ +# | | pk | x | y | +# +---+----+-------+---------+ +# | - | 2 | 3.3 | 4.4 | +# | < | 3 | 5.5 | 6.6 | +# | > | 3 | 5.5 | 100.001 | +# | + | 4 | 42.24 | 23.32 | +# +---+----+-------+---------+ +# diff --dolt a/names b/names +# --- a/names +# +++ b/names +# +---+----+------+ +# | | pk | name | +# +---+----+------+ +# | < | 1 | neil | +# | > | 1 | joey | +# | - | 2 | sami | +# | + | 4 | john | +# +---+----+------+ +# + +} + +teardown() { + teardown_common +} + +# bats test_tags=no_lambda +@test "add-patch: clean workspace" { + dolt reset --hard + + run dolt add --patch + + [ "$status" -eq 0 ] + [[ "$output" =~ "No changes." ]] || false +} + +# bats test_tags=no_lambda +@test "add-patch: all changes staged" { + dolt add . + + run dolt add --patch + + [ "$status" -eq 0 ] + [[ "$output" =~ "No changes." ]] || false +} + +# bats test_tags=no_lambda +@test "add-patch: help and quit" { + run dolt sql -r csv -q "select dolt_hashof_db()" + [ $status -eq 0 ] + ORIG_DB_HASH=$(echo "$output" | awk 'NR==2') + + run $BATS_TEST_DIRNAME/add-patch-expect/help_quit.expect + [ $status -eq 0 ] + + run dolt sql -r csv -q "select dolt_hashof_db()" + [ $status -eq 0 ] + DB_HASH=$(echo "$output" | awk 'NR==2') + + # Verify that the state of the database hasn't changed. + [[ "$DB_HASH" == "$ORIG_DB_HASH" ]] || false +} + +# bats test_tags=no_lambda +@test "add-patch: a then d for two tables" { + # This test does: `add -p coordinates colors` -> 'a' -> 'd' + run $BATS_TEST_DIRNAME/add-patch-expect/all_none.expect + [ $status -eq 0 ] + + run dolt sql -q "select name from colors AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "Red" ]] || false + [[ "$output" =~ "SkyBlue" ]] || false + [[ "$output" =~ "Yellow" ]] || false + [[ ! "$output" =~ "Green" ]] || false + + # Should be no changes on coordinates. + run dolt sql -q "select pk, y from coordinates AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "| 1 | 2.2 |" ]] || false + [[ "$output" =~ "| 2 | 4.4 |" ]] || false + [[ "$output" =~ "| 3 | 6.6 |" ]] || false + [[ ! "$output" =~ "23.32" ]] || false # Value for inserted row - should not be there. + + # Should be no changes on names. + run dolt sql -q "select pk, name from names AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "| 1 | neil |" ]] || false + [[ "$output" =~ "| 2 | sami |" ]] || false + [[ "$output" =~ "| 3 | jane |" ]] || false + [[ ! "$output" =~ "john" ]] || false # Value for inserted row - should not be there. +} + +# bats test_tags=no_lambda +@test "add-patch: y/n repeatedly with restarts" { + # This test repeatedly does 'y/n/y/s' until the program exits. + run $BATS_TEST_DIRNAME/add-patch-expect/restart_multiple_times.expect + [ $status -eq 0 ] + + run dolt sql -q "select name from colors AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "Red" ]] || false + [[ "$output" =~ "SkyBlue" ]] || false + [[ "$output" =~ "Yellow" ]] || false + [[ ! "$output" =~ "Green" ]] || false + + run dolt sql -q "select pk, y from coordinates AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "| 1 | 2.2 |" ]] || false + [[ "$output" =~ "| 3 | 100.001 |" ]] || false + [[ "$output" =~ "| 4 | 23.32 |" ]] || false + + run dolt sql -q "select pk, name from names AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "| 1 | joey |" ]] || false + [[ "$output" =~ "| 2 | sami |" ]] || false + [[ "$output" =~ "| 3 | jane |" ]] || false + [[ "$output" =~ "| 4 | john |" ]] || false +} + +# bats test_tags=no_lambda +@test "add-patch: summary updates are correct" { + # Similar to the previous test, but this time we're ensuring that the summary updates are correct. + run $BATS_TEST_DIRNAME/add-patch-expect/summary_updates.expect + [ $status -eq 0 ] + + # Status should be identical to the previous test. + run dolt sql -q "select name from colors AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "Red" ]] || false + [[ "$output" =~ "SkyBlue" ]] || false + [[ "$output" =~ "Yellow" ]] || false + [[ ! "$output" =~ "Green" ]] || false + + run dolt sql -q "select pk, y from coordinates AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "| 1 | 2.2 |" ]] || false + [[ "$output" =~ "| 3 | 100.001 |" ]] || false + [[ "$output" =~ "| 4 | 23.32 |" ]] || false + + run dolt sql -q "select pk, name from names AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "| 1 | joey |" ]] || false + [[ "$output" =~ "| 2 | sami |" ]] || false + [[ "$output" =~ "| 3 | jane |" ]] || false + [[ "$output" =~ "| 4 | john |" ]] || false +} + +# bats test_tags=no_lambda +@test "add-patch: y then d" { + # Accept the first change for each table, then skip the rest. + run $BATS_TEST_DIRNAME/add-patch-expect/yes_then_d.expect + [ $status -eq 0 ] + + run dolt sql -q "select pk,name from colors AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "0 | Yellow" ]] || false + [[ "$output" =~ "1 | Red" ]] || false + [[ "$output" =~ "2 | Green" ]] || false + [[ "$output" =~ "3 | Blue" ]] || false + # verify no extra rows in table we didn't look for. + run dolt sql -q "select sum(pk) as s from colors AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "| 6 |" ]] || false # Yellow added as pk=0, so 0+1+2+3 + + run dolt sql -q "select pk, y from coordinates AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "| 1 | 2.2 |" ]] || false + [[ "$output" =~ "| 3 | 6.6 |" ]] || false + # verify no extra rows in table we didn't look for. + run dolt sql -q "select sum(pk) as s from coordinates AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "| 4 |" ]] || false + + run dolt sql -q "select pk, name from names AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "| 1 | joey |" ]] || false + [[ "$output" =~ "| 2 | sami |" ]] || false + [[ "$output" =~ "| 3 | jane |" ]] || false + run dolt sql -q "select sum(pk) as s from names AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "| 6 |" ]] || false +} + +# bats test_tags=no_lambda +@test "add-patch: n then a" { + # Accept the reject fir change, then accept the rest. + run $BATS_TEST_DIRNAME/add-patch-expect/no_then_a.expect + [ $status -eq 0 ] + + run dolt sql -q "select pk,name from colors AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "| 1 | Red |" ]] || false + [[ "$output" =~ "| 3 | SkyBlue |" ]] || false + # verify no extra rows in table we didn't look for. + run dolt sql -q "select sum(pk) as s from colors AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "| 4 |" ]] || false + + run dolt sql -q "select pk, y from coordinates AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "| 1 | 2.2 |" ]] || false + [[ "$output" =~ "| 2 | 4.4 |" ]] || false + [[ "$output" =~ "| 3 | 100.001 |" ]] || false + [[ "$output" =~ "| 4 | 23.32 |" ]] || false + # verify no extra rows in table we didn't look for. + run dolt sql -q "select sum(pk) as s from coordinates AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "| 10 |" ]] || false + + run dolt sql -q "select pk, name from names AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "| 1 | neil |" ]] || false + [[ "$output" =~ "| 3 | jane |" ]] || false + [[ "$output" =~ "| 4 | john |" ]] || false + run dolt sql -q "select sum(pk) as s from names AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "| 8 |" ]] || false +} + +# bats test_tags=no_lambda +@test "add-patch: keyless table" { + dolt add . + dolt commit -m "make clean workspace" + + dolt sql -q "create table keyless (x int, y int)" + dolt sql -q "insert into keyless values (1,1), (2,2), (3,3), (1,1), (2,2), (3,3)" + dolt commit -A -m "add keyless table with data." + + # This update, while it updates "all rows", the diff will be: + # diff --dolt a/keyless b/keyless + # --- a/keyless + # +++ b/keyless + # +---+---+---+ + # | | x | y | + # +---+---+---+ + # | - | 1 | 1 | + # | - | 1 | 1 | + # | + | 4 | 4 | + # | + | 4 | 4 | + # +---+---+---+ + dolt sql -q "update keyless set x = x + 1, y = y + 1" + + run $BATS_TEST_DIRNAME/add-patch-expect/keyless.expect + [ $status -eq 0 ] + + run dolt sql -q "select * from keyless AS OF STAGED" + # Output should be: + # +---+---+ + # | x | y | + # +---+---+ + # | 3 | 3 | + # | 3 | 3 | + # | 2 | 2 | + # | 2 | 2 | + # | 1 | 1 | + # | 4 | 4 | + # +---+---+ + [ $status -eq 0 ] + [[ "$output" =~ "3 | 3" ]] || false + [[ "$output" =~ "2 | 2" ]] || false + [[ "$output" =~ "1 | 1" ]] || false + [[ "$output" =~ "4 | 4" ]] || false + + # verify no extra rows in table we didn't look for. 3 + 3 + 2 + 2 + 1 + 4 = 15 + run dolt sql -q "select sum(x) as s from keyless AS OF STAGED" + [ $status -eq 0 ] + [[ "$output" =~ "15" ]] || false +} + diff --git a/integration-tests/bats/helper/common_expect_functions.tcl b/integration-tests/bats/helper/common_expect_functions.tcl new file mode 100755 index 0000000000..6c91d5574d --- /dev/null +++ b/integration-tests/bats/helper/common_expect_functions.tcl @@ -0,0 +1,62 @@ + +proc expect_with_defaults {pattern action} { + expect { + -re $pattern { +# puts "Matched pattern: $pattern" + eval $action + } + timeout { + puts "<>"; + exit 1 + } + eof { + puts "<>"; + exit 1 + } + failed { + puts "<>"; + exit 1 + } + } +} + +proc expect_with_defaults_2 {patternA patternB action} { + # First, match patternA + expect { + -re $patternA { + puts "<>" + # Now match patternB + expect { + -re $patternB { + puts "<>" + eval $action + } + timeout { + puts "<>" + exit 1 + } + eof { + puts "<>" + exit 1 + } + failed { + puts "<>" + exit 1 + } + } + } + timeout { + puts "<>" + exit 1 + } + eof { + puts "<>" + exit 1 + } + failed { + puts "<>" + exit 1 + } + } +} + diff --git a/integration-tests/bats/sql-shell-slash-cmds.expect b/integration-tests/bats/sql-shell-slash-cmds.expect index e7a6bc4a7d..63871c3dd4 100755 --- a/integration-tests/bats/sql-shell-slash-cmds.expect +++ b/integration-tests/bats/sql-shell-slash-cmds.expect @@ -3,68 +3,7 @@ set timeout 5 set env(NO_COLOR) 1 - -proc expect_with_defaults {pattern action} { - expect { - -re $pattern { -# puts "Matched pattern: $pattern" - eval $action - } - timeout { - puts "<>"; - exit 1 - } - eof { - puts "<>"; - exit 1 - } - failed { - puts "<>"; - exit 1 - } - } -} - -proc expect_with_defaults_2 {patternA patternB action} { - # First, match patternA - expect { - -re $patternA { - puts "<>" - # Now match patternB - expect { - -re $patternB { - puts "<>" - eval $action - } - timeout { - puts "<>" - exit 1 - } - eof { - puts "<>" - exit 1 - } - failed { - puts "<>" - exit 1 - } - } - } - timeout { - puts "<>" - exit 1 - } - eof { - puts "<>" - exit 1 - } - failed { - puts "<>" - exit 1 - } - } -} - +source "$env(BATS_CWD)/helper/common_expect_functions.tcl" spawn dolt sql diff --git a/integration-tests/bats/stats.bats b/integration-tests/bats/stats.bats index c2fd477128..973d23a794 100644 --- a/integration-tests/bats/stats.bats +++ b/integration-tests/bats/stats.bats @@ -130,6 +130,26 @@ teardown() { [ "$status" -eq 1 ] } +@test "stats: restart in shell doesn't drop db, issue#8345" { + cd repo2 + + dolt sql -q "insert into xy values (0,0), (1,1), (2,2), (3,3), (4,4)" + dolt sql -q "insert into ab values (0,0), (1,1), (2,2), (3,3), (4,4)" + dolt sql -q "ANALYZE table xy, ab" + run dolt sql -r csv <