diff --git a/go/cmd/dolt/commands/tblcmds/import.go b/go/cmd/dolt/commands/tblcmds/import.go index 0799429199..3263fd45c2 100644 --- a/go/cmd/dolt/commands/tblcmds/import.go +++ b/go/cmd/dolt/commands/tblcmds/import.go @@ -389,10 +389,9 @@ func (cmd ImportCmd) Exec(ctx context.Context, commandStr string, args []string, help, usage := cli.HelpAndUsagePrinters(cli.CommandDocsForCommandString(commandStr, importDocs, ap)) apr := cli.ParseArgsOrDie(ap, args, help) + var verr errhand.VerboseError dEnv, err := commands.MaybeMigrateEnv(ctx, dEnv) - - var verr errhand.VerboseError if err != nil { verr = errhand.BuildDError("could not load manifest for gc").AddCause(err).Build() return commands.HandleVErrAndExitCode(verr, usage) @@ -404,13 +403,11 @@ func (cmd ImportCmd) Exec(ctx context.Context, commandStr string, args []string, } mvOpts, verr := getImportMoveOptions(ctx, apr, dEnv) - if verr != nil { return commands.HandleVErrAndExitCode(verr, usage) } root, err := dEnv.WorkingRoot(ctx) - if err != nil { verr = errhand.BuildDError("Unable to get the working root value for this data repository.").AddCause(err).Build() return commands.HandleVErrAndExitCode(verr, usage) @@ -432,9 +429,7 @@ func (cmd ImportCmd) Exec(ctx context.Context, commandStr string, args []string, if err != nil { bdr := errhand.BuildDError("\nAn error occurred while moving data") bdr.AddCause(err) - bdr.AddDetails("Errors during import can be ignored using '--continue'") - return commands.HandleVErrAndExitCode(bdr.Build(), usage) } @@ -518,7 +513,7 @@ func newImportSqlEngineMover(ctx context.Context, dEnv *env.DoltEnv, rdSchema sc return mv, nil } -type badRowFn func(row sql.Row, err error) (quit bool) +type badRowFn func(row sql.Row, rowSchema sql.PrimaryKeySchema, tableName string, lineNumber int, err error) (quit bool) func move(ctx context.Context, rd table.SqlRowReader, wr *mvdata.SqlEngineTableWriter, options *importOptions) (int64, error) { g, ctx := errgroup.WithContext(ctx) @@ -529,10 +524,20 @@ func move(ctx context.Context, rd table.SqlRowReader, wr *mvdata.SqlEngineTableW var printBadRowsStarted bool var badCount int64 - badRowCB := func(row sql.Row, err error) (quit bool) { + badRowCB := func(row sql.Row, rowSchema sql.PrimaryKeySchema, tableName string, lineNumber int, err error) (quit bool) { // record the first error encountered unless asked to ignore it if row != nil && rowErr == nil && !options.contOnErr { - rowErr = fmt.Errorf("A bad row was encountered: %s: %w", sql.FormatRow(row), err) + var sqlRowWithColumns []string + for i, val := range row { + columnName := "" + if len(rowSchema.Schema) > i { + columnName = rowSchema.Schema[i].Name + } + sqlRowWithColumns = append(sqlRowWithColumns, fmt.Sprintf("\t%s: %v\n", columnName, val)) + } + formattedSqlRow := strings.Join(sqlRowWithColumns, "") + + rowErr = fmt.Errorf("A bad row was encountered inserting into table %s (on line %d):\n%s", tableName, lineNumber, formattedSqlRow) if wie, ok := err.(sql.WrappedInsertError); ok { if e, ok := wie.Cause.(*errors.Error); ok { if ue, ok := e.Cause().(sql.UniqueKeyError); ok { @@ -615,15 +620,18 @@ func moveRows( return err } + line := 1 + for { sqlRow, err := rd.ReadSqlRow(ctx) if err == io.EOF { return nil } + line += 1 if err != nil { if table.IsBadRow(err) { - quit := badRowCb(sqlRow, err) + quit := badRowCb(sqlRow, rdSqlSch, options.destTableName, line, err) if quit { return err } diff --git a/go/libraries/doltcore/mvdata/engine_table_writer.go b/go/libraries/doltcore/mvdata/engine_table_writer.go index 5c3701d9c5..f9b6377ae9 100644 --- a/go/libraries/doltcore/mvdata/engine_table_writer.go +++ b/go/libraries/doltcore/mvdata/engine_table_writer.go @@ -128,7 +128,7 @@ func NewSqlEngineTableWriter(ctx context.Context, dEnv *env.DoltEnv, createTable }, nil } -func (s *SqlEngineTableWriter) WriteRows(ctx context.Context, inputChannel chan sql.Row, badRowCb func(row sql.Row, err error) bool) (err error) { +func (s *SqlEngineTableWriter) WriteRows(ctx context.Context, inputChannel chan sql.Row, badRowCb func(row sql.Row, rowSchema sql.PrimaryKeySchema, tableName string, lineNumber int, err error) bool) (err error) { err = s.forceDropTableIfNeeded() if err != nil { return err @@ -190,6 +190,8 @@ func (s *SqlEngineTableWriter) WriteRows(ctx context.Context, inputChannel chan } }() + line := 1 + for { if s.statsCB != nil && atomic.LoadInt32(&s.statOps) >= tableWriterStatUpdateRate { atomic.StoreInt32(&s.statOps, 0) @@ -197,6 +199,7 @@ func (s *SqlEngineTableWriter) WriteRows(ctx context.Context, inputChannel chan } row, err := iter.Next(s.sqlCtx) + line += 1 // All other errors are handled by the errorHandler if err == nil { @@ -219,7 +222,7 @@ func (s *SqlEngineTableWriter) WriteRows(ctx context.Context, inputChannel chan offendingRow = n.OffendingRow } - quit := badRowCb(offendingRow, err) + quit := badRowCb(offendingRow, s.tableSchema, s.tableName, line, err) if quit { return err } diff --git a/integration-tests/bats/default-values.bats b/integration-tests/bats/default-values.bats index abf661d600..93169c172a 100644 --- a/integration-tests/bats/default-values.bats +++ b/integration-tests/bats/default-values.bats @@ -486,7 +486,9 @@ DELIM run dolt table import -u test bad-update.csv [ "$status" -eq "1" ] [[ "$output" =~ "bad row" ]] || false - [[ "$output" =~ "[5,,5]" ]] || false + [[ "$output" =~ "pk: 5" ]] || false + [[ "$output" =~ "v1: " ]] || false + [[ "$output" =~ "v2: 5" ]] || false [[ "$output" =~ "column name 'v1' is non-nullable but attempted to set a value of null" ]] || false } diff --git a/integration-tests/bats/import-append-tables.bats b/integration-tests/bats/import-append-tables.bats index 7999879420..2182866f98 100644 --- a/integration-tests/bats/import-append-tables.bats +++ b/integration-tests/bats/import-append-tables.bats @@ -26,7 +26,6 @@ CSV [[ "$output" =~ "row [1,1] would be overwritten by [1,2]" ]] || false run dolt sql -q "select * from t" - echo "$output" [ "$status" -eq 0 ] [[ "$output" =~ "| 1 | 1 |" ]] || false [[ ! "$output" =~ "| 1 | 2 |" ]] || false @@ -41,7 +40,6 @@ pk, col1 1, 2 CSV - echo "$output" [ "$status" -eq 1 ] [[ "$output" =~ "An error occurred while moving data" ]] || false [[ "$output" =~ "row [1,1] would be overwritten by [1,2]" ]] || false @@ -102,4 +100,21 @@ CSV [[ "$output" =~ "| 2 | 3 |" ]] || false [[ ! "$output" =~ "| 1 | 2 |" ]] || false [ "${#lines[@]}" -eq 6 ] -} \ No newline at end of file +} + +@test "import-append-tables: import error message contains useful information" { + dolt sql -q "CREATE TABLE shirts (name VARCHAR(40), size ENUM('x-small', 'small', 'medium', 'large', 'x-large'), color ENUM('red', 'blue'));" + run dolt table import -a shirts <