Skip to content

Commit

Permalink
Changed handling of NULL
Browse files Browse the repository at this point in the history
  • Loading branch information
noborus committed Apr 28, 2022
1 parent 70ba63a commit 6a2129a
Show file tree
Hide file tree
Showing 16 changed files with 135 additions and 104 deletions.
9 changes: 5 additions & 4 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func (cli Cli) Run(args []string) int {
outUseCRLF bool
outHeader bool
outNoWrap bool
outNull string
outNull nilString
)

flags := flag.NewFlagSet(trdsql.AppName, flag.ExitOnError)
Expand Down Expand Up @@ -112,7 +112,7 @@ func (cli Cli) Run(args []string) int {
flags.IntVar(&inPreRead, "ir", 1, "number of rows to preread.")
flags.IntVar(&inLimitRead, "ilr", 0, "limited number of rows to read.")
flags.StringVar(&inJQuery, "ijq", "", "jq expression string for input(JSON/JSONL only).")
flags.Var(&inNull, "inull", "null string.")
flags.Var(&inNull, "inull", "input null string.")

flags.BoolVar(&inFlag.CSV, "icsv", false, "CSV format for input.")
flags.BoolVar(&inFlag.LTSV, "iltsv", false, "LTSV format for input.")
Expand All @@ -128,7 +128,7 @@ func (cli Cli) Run(args []string) int {
flags.BoolVar(&outNoWrap, "onowrap", false, "do not wrap long lines(at/md only).")
flags.BoolVar(&outHeader, "oh", false, "output column name as header.")
flags.StringVar(&outCompression, "oz", "", "output compression format. [ gz | bz2 | zstd | lz4 | xz ]")
flags.StringVar(&outNull, "onull", "", "output null string.")
flags.Var(&outNull, "onull", "output null string.")

flags.BoolVar(&outFlag.CSV, "ocsv", false, "CSV format for output.")
flags.BoolVar(&outFlag.LTSV, "oltsv", false, "LTSV format for output.")
Expand Down Expand Up @@ -156,7 +156,8 @@ func (cli Cli) Run(args []string) int {

trdsql.IsImportNULL = inNull.n
trdsql.ImportNULL = strings.Replace(inNull.s, "\\", "\\\\", 1)
trdsql.ExportNULL = outNull
trdsql.IsExportNULL = outNull.n
trdsql.ExportNULL = strings.Replace(outNull.s, "\\", "\\\\", 1)

cfgFile := configOpen(config)
cfg, err := loadConfig(cfgFile)
Expand Down
30 changes: 16 additions & 14 deletions database.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,6 @@ func (db *DB) copyImport(ctx context.Context, table *importTable, reader Reader)
if row == nil {
break
}
debug.Printf("%v\n", row)
if _, err = stmt.ExecContext(ctx, row...); err != nil {
return err
}
Expand All @@ -211,7 +210,6 @@ func (db *DB) copyImport(ctx context.Context, table *importTable, reader Reader)
if len(table.row) == 0 {
continue
}
debug.Printf("%v\n", table.row)
if _, err = stmt.ExecContext(ctx, table.row...); err != nil {
return err
}
Expand Down Expand Up @@ -260,6 +258,9 @@ func (db *DB) insertImport(ctx context.Context, table *importTable, reader Reade
// PreRead
for preCount < preRowNum {
row := preRows[preCount]
if IsImportNULL {
row = replaceImportNull(row)
}
bulk = append(bulk, row...)
table.count++
preCount++
Expand Down Expand Up @@ -315,7 +316,7 @@ func bulkPush(ctx context.Context, table *importTable, input Reader, bulk []inte
}

if IsImportNULL {
row = replaceNull(row)
row = replaceImportNull(row)
}
bulk = append(bulk, row...)
table.count++
Expand All @@ -328,17 +329,6 @@ func bulkPush(ctx context.Context, table *importTable, input Reader, bulk []inte
return bulk, nil
}

func replaceNull(row []interface{}) []interface{} {
rr := make([]interface{}, len(row))
for n, r := range row {
// Leave nil if it is the same string as ImportNULL.
if r != ImportNULL {
rr[n] = r
}
}
return rr
}

func (db *DB) bulkStmtOpen(ctx context.Context, table *importTable, stmt *sql.Stmt) (*sql.Stmt, error) {
if table.lastCount == table.count {
return stmt, nil
Expand Down Expand Up @@ -431,3 +421,15 @@ func (db *DB) SelectContext(ctx context.Context, query string) (*sql.Rows, error
}
return rows, nil
}

//replaceImportNull converts strings that match ImportNULL to nil.
func replaceImportNull(row []interface{}) []interface{} {
rr := make([]interface{}, len(row))
for n, r := range row {
// Leave nil if it is the same string as ImportNULL.
if r != ImportNULL {
rr[n] = r
}
}
return rr
}
30 changes: 0 additions & 30 deletions exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@ package trdsql

import (
"context"
"encoding/hex"
"fmt"
"log"
"strconv"
"time"
"unicode/utf8"
)

// Exporter is the interface for processing query results.
Expand Down Expand Up @@ -90,28 +85,3 @@ func (e *WriteFormat) ExportContext(ctx context.Context, db *DB, query string) e

return e.Writer.PostWrite()
}

// ValString converts database value to string.
func ValString(v interface{}) string {
switch t := v.(type) {
case nil:
return ExportNULL
case string:
return t
case []byte:
if ok := utf8.Valid(t); ok {
return string(t)
}
return `\x` + hex.EncodeToString(t)
case int:
return strconv.Itoa(t)
case int32:
return strconv.FormatInt(int64(t), 10)
case int64:
return strconv.FormatInt(t, 10)
case time.Time:
return t.Format(time.RFC3339)
default:
return fmt.Sprint(v)
}
}
45 changes: 0 additions & 45 deletions exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package trdsql

import (
"testing"
"time"
)

func TestNewExporter(t *testing.T) {
Expand Down Expand Up @@ -63,47 +62,3 @@ func TestWriteFormat_Export(t *testing.T) {
})
}
}

func TestValString(t *testing.T) {
type args struct {
v interface{}
}
tests := []struct {
name string
args args
want string
}{
{
name: "test1",
args: args{v: "test"},
want: "test",
},
{
name: "testTime",
args: args{v: time.Date(2020, 1, 3, 17, 28, 18, 0, time.UTC)},
want: "2020-01-03T17:28:18Z",
},
{
name: "testByte",
args: args{v: []byte("test")},
want: "test",
},
{
name: "testByteHex",
args: args{v: []byte("\xf3\xf2\xff")},
want: "\\xf3f2ff",
},
{
name: "testNil",
args: args{v: nil},
want: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ValString(tt.args.v); got != tt.want {
t.Errorf("ValString() = %v, want %v", got, tt.want)
}
})
}
}
14 changes: 12 additions & 2 deletions input_json.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ func (r *JSONReader) rowParse(row []interface{}, jsonRow interface{}) []interfac
for i := range r.names {
row[i] = nil
}
row[0] = jsonString(jsonRow)
row[0] = jsonNullString(jsonRow)
}
return row
}
Expand All @@ -227,7 +227,7 @@ func objectRow(obj map[string]interface{}) (map[string]interface{}, []string, er
row := make(map[string]interface{})
for k, v := range obj {
names = append(names, k)
row[k] = jsonString(v)
row[k] = jsonNullString(v)
}
return row, names, nil
}
Expand All @@ -244,6 +244,16 @@ func etcRow(val interface{}) (map[string]interface{}, []string, error) {
return row, names, nil
}

func jsonNullString(val interface{}) interface{} {
if val == nil {
if IsImportNULL {
return ImportNULL
}
return nil
}
return jsonString(val)
}

func jsonString(val interface{}) string {
switch val.(type) {
case map[string]interface{}, []interface{}:
Expand Down
2 changes: 1 addition & 1 deletion output_csv.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func (w *CSVWriter) WriteRow(values []interface{}, _ []string) error {
return err
}
}
if err := w.writeColumn(ValString(field)); err != nil {
if err := w.writeColumn(exportString(field)); err != nil {
return err
}
}
Expand Down
3 changes: 3 additions & 0 deletions output_json.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ func compatibleJSON(v interface{}) interface{} {
}
return v
default:
if IsExportNULL {
return ExportNULL
}
return v
}
}
Expand Down
2 changes: 1 addition & 1 deletion output_ltsv.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (w *LTSVWriter) WriteRow(values []interface{}, labels []string) error {
if err := w.writer.WriteByte(':'); err != nil {
return err
}
if _, err := w.writer.WriteString(ValString(col)); err != nil {
if _, err := w.writer.WriteString(exportString(col)); err != nil {
return err
}
}
Expand Down
2 changes: 1 addition & 1 deletion output_raw.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (w *RAWWriter) WriteRow(values []interface{}, _ []string) error {
return err
}
}
if _, err := w.writer.WriteString(ValString(col)); err != nil {
if _, err := w.writer.WriteString(exportString(col)); err != nil {
return err
}
}
Expand Down
4 changes: 1 addition & 3 deletions output_slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ func (w *SliceWriter) PreWrite(columns []string, types []string) error {
// WriteRow stores the result in Table.
func (w *SliceWriter) WriteRow(values []interface{}, columns []string) error {
row := make([]interface{}, len(values))
for i, v := range values {
row[i] = ValString(v)
}
copy(row, values)
w.Table = append(w.Table, row)
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion output_tablewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (w *TWWriter) PreWrite(columns []string, types []string) error {
// WriteRow is Addition to array.
func (w *TWWriter) WriteRow(values []interface{}, columns []string) error {
for i, col := range values {
w.results[i] = ValString(col)
w.results[i] = exportString(col)
}
w.writer.Append(w.results)
return nil
Expand Down
2 changes: 1 addition & 1 deletion output_tbln.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (w *TBLNWriter) PreWrite(columns []string, types []string) error {
// WriteRow is row write.
func (w *TBLNWriter) WriteRow(values []interface{}, columns []string) error {
for i, col := range values {
str := ValString(col)
str := exportString(col)
w.results[i] = strings.ReplaceAll(str, "\n", "\\n")
}
return w.writer.WriteRow(w.results)
Expand Down
2 changes: 1 addition & 1 deletion output_vertical.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (w *VFWriter) WriteRow(values []interface{}, columns []string) error {
"%s%s | %-s\n",
strings.Repeat(" ", v+2),
col,
ValString(values[i]))
exportString(values[i]))
if err != nil {
debug.Printf("%s\n", err)
}
Expand Down
41 changes: 41 additions & 0 deletions strings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package trdsql

import (
"encoding/hex"
"fmt"
"strconv"
"time"
"unicode/utf8"
)

// ValString converts database value to string.
func ValString(v interface{}) string {
switch t := v.(type) {
case nil:
return ""
case string:
return t
case []byte:
if ok := utf8.Valid(t); ok {
return string(t)
}
return `\x` + hex.EncodeToString(t)
case int:
return strconv.Itoa(t)
case int32:
return strconv.FormatInt(int64(t), 10)
case int64:
return strconv.FormatInt(t, 10)
case time.Time:
return t.Format(time.RFC3339)
default:
return fmt.Sprint(v)
}
}

func exportString(val interface{}) string {
if val == nil {
return ExportNULL
}
return ValString(val)
}
Loading

0 comments on commit 6a2129a

Please sign in to comment.