Skip to content

Commit

Permalink
Merge pull request #4382 from dolthub/dhruv/update-tag
Browse files Browse the repository at this point in the history
Add dolt schema update-tag
  • Loading branch information
Dhruv Sringari committed Nov 18, 2022
2 parents d376474 + b1e80b6 commit a1be091
Show file tree
Hide file tree
Showing 3 changed files with 248 additions and 0 deletions.
1 change: 1 addition & 0 deletions go/cmd/dolt/commands/schcmds/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ var Commands = cli.NewSubCommandHandler("schema", "Commands for showing and impo
ImportCmd{},
ShowCmd{},
TagsCmd{},
UpdateTagCmd{},
})

// ValidateTableNameForCreate validates the given table name for creation as a user table, returning an error if the
Expand Down
161 changes: 161 additions & 0 deletions go/cmd/dolt/commands/schcmds/update-tag.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// Copyright 2022 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package schcmds

import (
"context"
"fmt"
"strconv"

"github.com/dolthub/dolt/go/cmd/dolt/cli"
"github.com/dolthub/dolt/go/cmd/dolt/commands"
"github.com/dolthub/dolt/go/cmd/dolt/errhand"
"github.com/dolthub/dolt/go/libraries/doltcore/env"
"github.com/dolthub/dolt/go/libraries/doltcore/schema"
"github.com/dolthub/dolt/go/libraries/utils/argparser"
"github.com/dolthub/dolt/go/store/types"
)

var updateTagDocs = cli.CommandDocumentationContent{
ShortDesc: "Update the tag of the specified column",
LongDesc: `{{.EmphasisLeft}}dolt schema update-tag{{.EmphasisRight}}
Update tag of the specified column. Useful to fix a merge that is throwing a
schema tag conflict.
`,
Synopsis: []string{
"{{.LessThan}}table{{.GreaterThan}} {{.LessThan}}column{{.GreaterThan}} {{.LessThan}}tag{{.GreaterThan}}",
},
}

type UpdateTagCmd struct{}

var _ cli.Command = UpdateTagCmd{}

func (cmd UpdateTagCmd) Name() string {
return "update-tag"
}

func (cmd UpdateTagCmd) Description() string {
return "Update a column's tag"
}

func (cmd UpdateTagCmd) Docs() *cli.CommandDocumentation {
ap := cmd.ArgParser()
return cli.NewCommandDocumentation(updateTagDocs, ap)
}

func (cmd UpdateTagCmd) ArgParser() *argparser.ArgParser {
ap := argparser.NewArgParser()
ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"table", "The name of the table"})
ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"column", "The name of the column"})
ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"tag", "The new tag value"})
return ap
}

func (cmd UpdateTagCmd) Exec(ctx context.Context, commandStr string, args []string, dEnv *env.DoltEnv) int {
ap := cmd.ArgParser()
help, usage := cli.HelpAndUsagePrinters(cli.CommandDocsForCommandString(commandStr, updateTagDocs, ap))
apr := cli.ParseArgsOrDie(ap, args, help)

if !types.IsFormat_DOLT(dEnv.DoltDB.Format()) {
verr := errhand.BuildDError("update-tag is only available in storage format __DOLT__").Build()
return commands.HandleVErrAndExitCode(verr, usage)
}

if len(apr.Args) != 3 {
verr := errhand.BuildDError("must provide <table> <column> <tag>").Build()
return commands.HandleVErrAndExitCode(verr, usage)
}

tableName, columnName, tagStr := apr.Args[0], apr.Args[1], apr.Args[2]

tag, err := strconv.ParseUint(tagStr, 10, 64)
if err != nil {
verr := errhand.BuildDError("failed to parse tag").AddCause(err).Build()
return commands.HandleVErrAndExitCode(verr, usage)
}

root, verr := commands.GetWorkingWithVErr(dEnv)
if verr != nil {
return commands.HandleVErrAndExitCode(verr, usage)
}

tbl, tName, ok, err := root.GetTableInsensitive(ctx, tableName)
if err != nil {
return commands.HandleVErrAndExitCode(errhand.BuildDError("failed to get table").Build(), usage)
}
if !ok {
return commands.HandleVErrAndExitCode(errhand.BuildDError("table %s does not exist", tableName).Build(), usage)
}

sch, err := tbl.GetSchema(ctx)
if err != nil {
return commands.HandleVErrAndExitCode(errhand.BuildDError("failed to get schema").Build(), usage)
}

newSch, err := updateColumnTag(sch, columnName, tag)
if err != nil {
return commands.HandleVErrAndExitCode(errhand.BuildDError("failed to update column tag").AddCause(err).Build(), usage)
}

tbl, err = tbl.UpdateSchema(ctx, newSch)
if err != nil {
return commands.HandleVErrAndExitCode(errhand.BuildDError("failed to update table schema").AddCause(err).Build(), usage)
}

root, err = root.PutTable(ctx, tName, tbl)
if err != nil {
return commands.HandleVErrAndExitCode(errhand.BuildDError("failed to put table in root").AddCause(err).Build(), usage)
}

verr = commands.UpdateWorkingWithVErr(dEnv, root)
if verr != nil {
return commands.HandleVErrAndExitCode(verr, usage)
}

return commands.HandleVErrAndExitCode(nil, usage)
}

func updateColumnTag(sch schema.Schema, name string, tag uint64) (schema.Schema, error) {
var found bool
columns := sch.GetAllCols().GetColumns()
// Find column and update its tag
for i, col := range columns {
if col.Name == name {
col.Tag = tag
columns[i] = col
found = true
break
}
}

if !found {
return nil, fmt.Errorf("column %s does not exist", name)
}

newSch, err := schema.SchemaFromCols(schema.NewColCollection(columns...))
if err != nil {
return nil, err
}

err = newSch.SetPkOrdinals(sch.GetPkOrdinals())
if err != nil {
return nil, err
}
newSch.SetCollation(sch.GetCollation())

return newSch, nil
}
86 changes: 86 additions & 0 deletions integration-tests/bats/column_tags.bats
Original file line number Diff line number Diff line change
Expand Up @@ -290,3 +290,89 @@ DELIM
[ $status -eq 0 ]
[[ $output =~ "col1 | 10186" ]] || false
}

@test "column_tags: update-tag only available on __DOLT__" {
mkdir ld
mkdir dev

cd ld
DOLT_DEFAULT_BIN_FORMAT=__LD_1__ dolt init
run dolt schema update-tag t col 5
[ $status -ne 0 ]
echo $output
[[ $output =~ "update-tag is only available in storage format __DOLT__" ]] || false

cd ../dev
DOLT_DEFAULT_BIN_FORMAT=__DOLT_DEV__ dolt init
run dolt schema update-tag t col 5
[ $status -ne 0 ]
[[ $output =~ "update-tag is only available in storage format __DOLT__" ]] || false
}

@test "column_tags: update-tag updates a columns tag" {
skip_nbf_not_dolt

dolt sql -q "CREATE TABLE t (pk INT PRIMARY KEY, col1 int);"
run dolt schema tags
[ $status -eq 0 ]
[[ $output =~ "pk | 15476" ]] || false
[[ $output =~ "col1 | 10878" ]] || false

dolt schema update-tag t pk 5
run dolt schema tags
[ $status -eq 0 ]
[[ $output =~ "pk | 5" ]] || false
[[ $output =~ "col1 | 10878" ]] || false

dolt schema update-tag t col1 6
run dolt schema tags
[ $status -eq 0 ]
[[ $output =~ "pk | 5" ]] || false
[[ $output =~ "col1 | 6" ]] || false
}

@test "column_tags: create table on two separate branches, merge them together by updating tags" {
skip_nbf_not_dolt

dolt branch other
dolt sql -q "CREATE TABLE t (pk int PRIMARY KEY, col1 int);"
dolt sql -q "INSERT INTO t VALUES (1, 1);"
dolt commit -Am "unrelated table"

dolt sql -q "CREATE table target (pk int PRIMARY KEY, col1 int);"
dolt sql -q "INSERT into target VALUES (1, 1);"
dolt commit -Am "table target on main branch"

dolt checkout other
dolt sql -q "CREATE table target (pk int PRIMARY KEY, badCol int, col1 int);"
dolt sql -q "INSERT INTO target VALUES (2, 2, 2);"
dolt commit -Am "table target on other branch"
dolt sql -q "ALTER TABLE target DROP COLUMN badCol;"
dolt commit -Am "fixup"

run dolt schema tags
[[ $output =~ "| target | col1 | 14690 |" ]] || false

dolt checkout main

run dolt schema tags
[ $status -eq 0 ]
[[ $output =~ "| target | col1 | 14649 |" ]] || false

run dolt merge other
[ $status -ne 0 ]
[[ $output =~ "table with same name added in 2 commits can't be merged" ]] || false
dolt reset --hard

dolt schema update-tag target col1 14690
dolt commit -am "update tag of col1 of target"

run dolt merge other -m "merge other into main"
[ $status -eq 0 ]
[[ $output =~ "1 tables changed, 1 rows added(+)" ]] || false

run dolt sql -r csv -q "select * from target;"
[ $status -eq 0 ]
[[ $output =~ "1,1" ]] || false
[[ $output =~ "2,2" ]] || false
}

0 comments on commit a1be091

Please sign in to comment.