Skip to content

Commit

Permalink
Allows multiple queries.
Browse files Browse the repository at this point in the history
Allows multiple queries to return multiple results.
Multiple queries are split and sent to the database.
Therefore, it works even if the driver does not specify support
for multiple queries.
Supports SELECT after UPDATE.

This is an implementation of #184.
  • Loading branch information
noborus committed Dec 6, 2023
1 parent 0c2ad5c commit fa9622c
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 41 deletions.
3 changes: 3 additions & 0 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ func (cli Cli) Run(args []string) int {
trdsql.EnableDebug()
}

// MultipleQueries is enabled by default.
trdsql.EnableMultipleQueries()

cfgFile := configOpen(config)
cfg, err := loadConfig(cfgFile)
if err != nil && config != "" {
Expand Down
29 changes: 24 additions & 5 deletions exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ package trdsql
import (
"context"
"log"

"github.com/noborus/sqlss"
)

// Exporter is the interface for processing query results.
// Exporter executes SQL and outputs to Writer.
type Exporter interface {
Export(db *DB, query string) error
ExportContext(ctx context.Context, db *DB, query string) error
Export(db *DB, sql string) error
ExportContext(ctx context.Context, db *DB, sql string) error
}

// WriteFormat represents a structure that satisfies Exporter.
Expand All @@ -26,14 +28,27 @@ func NewExporter(writer Writer) *WriteFormat {

// Export is execute SQL(Select) and the result is written out by the writer.
// Export is called from Exec.
func (e *WriteFormat) Export(db *DB, query string) error {
func (e *WriteFormat) Export(db *DB, sql string) error {
ctx := context.Background()
return e.ExportContext(ctx, db, query)
return e.ExportContext(ctx, db, sql)
}

// ExportContext is execute SQL(Select) and the result is written out by the writer.
// ExportContext is called from ExecContext.
func (e *WriteFormat) ExportContext(ctx context.Context, db *DB, query string) error {
func (e *WriteFormat) ExportContext(ctx context.Context, db *DB, sql string) error {
queries := sqlss.SplitQueries(sql)
if !multi || len(queries) == 1 {
return e.exportContext(ctx, db, false, sql)
}
for _, query := range queries {
if err := e.exportContext(ctx, db, true, query); err != nil {
return err
}
}
return nil
}

func (e *WriteFormat) exportContext(ctx context.Context, db *DB, multi bool, query string) error {
rows, err := db.SelectContext(ctx, query)
if err != nil {
return err
Expand All @@ -50,6 +65,10 @@ func (e *WriteFormat) ExportContext(ctx context.Context, db *DB, query string) e
}
}()

// No data is not output for multiple queries.
if multi && len(columns) == 0 {
return nil
}
values := make([]interface{}, len(columns))
scanArgs := make([]interface{}, len(columns))
for i := range values {
Expand Down
15 changes: 8 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@ require (
github.com/go-sql-driver/mysql v1.7.1
github.com/goccy/go-yaml v1.11.2
github.com/iancoleman/orderedmap v0.3.0
github.com/itchyny/gojq v0.12.13
github.com/itchyny/gojq v0.12.14
github.com/jwalton/gchalk v1.3.0
github.com/klauspost/compress v1.17.2
github.com/klauspost/compress v1.17.4
github.com/lib/pq v1.10.9
github.com/mattn/go-runewidth v0.0.15
github.com/mattn/go-sqlite3 v1.14.18
github.com/multiprocessio/go-sqlite3-stdlib v0.0.0-20220822170115-9f6825a1cd25
github.com/noborus/guesswidth v0.3.4
github.com/noborus/sqlss v0.0.0-20231204225649-d757e7878afc
github.com/noborus/tbln v0.0.2
github.com/olekukonko/tablewriter v0.0.5
github.com/pierrec/lz4 v2.6.1+incompatible
github.com/ulikunitz/xz v0.5.11
golang.org/x/term v0.14.0
golang.org/x/term v0.15.0
modernc.org/sqlite v1.27.0
)

Expand All @@ -34,16 +35,16 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.4 // indirect
golang.org/x/crypto v0.15.0 // indirect
golang.org/x/crypto v0.16.0 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/sys v0.14.0 // indirect
golang.org/x/tools v0.15.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/tools v0.16.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
gonum.org/v1/gonum v0.14.0 // indirect
lukechampine.com/uint128 v1.3.0 // indirect
modernc.org/cc/v3 v3.41.0 // indirect
modernc.org/ccgo/v3 v3.16.15 // indirect
modernc.org/libc v1.31.0 // indirect
modernc.org/libc v1.36.0 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.7.2 // indirect
modernc.org/opt v0.1.3 // indirect
Expand Down
32 changes: 18 additions & 14 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc=
github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE=
github.com/itchyny/gojq v0.12.13 h1:IxyYlHYIlspQHHTE0f3cJF0NKDMfajxViuhBLnHd/QU=
github.com/itchyny/gojq v0.12.13/go.mod h1:JzwzAqenfhrPUuwbmEz3nu3JQmFLlQTQMUcOdnu/Sf4=
github.com/itchyny/gojq v0.12.14 h1:6k8vVtsrhQSYgSGg827AD+PVVaB1NLXEdX+dda2oZCc=
github.com/itchyny/gojq v0.12.14/go.mod h1:y1G7oO7XkcR1LPZO59KyoCRy08T3j9vDYRV0GgYSS+s=
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
github.com/jwalton/gchalk v1.3.0 h1:uTfAaNexN8r0I9bioRTksuT8VGjrPs9YIXR1PQbtX/Q=
Expand All @@ -37,8 +37,8 @@ github.com/jwalton/go-supportscolor v1.2.0/go.mod h1:hFVUAZV2cWg+WFFC4v8pT2X/S2q
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
Expand All @@ -63,6 +63,8 @@ github.com/multiprocessio/go-sqlite3-stdlib v0.0.0-20220822170115-9f6825a1cd25 h
github.com/multiprocessio/go-sqlite3-stdlib v0.0.0-20220822170115-9f6825a1cd25/go.mod h1:RrGEZqqiyEcLyTVLDSgtNZVLqJykj0F4vwuuqvMdT60=
github.com/noborus/guesswidth v0.3.4 h1:+iKmbm0iFTS3pksIOKQQvLVZVOKNZHavqJoFK2mPoTQ=
github.com/noborus/guesswidth v0.3.4/go.mod h1:2F1sqiazKIwuSRjQTweQHPFJcjV5375jYUrTik9/V5k=
github.com/noborus/sqlss v0.0.0-20231204225649-d757e7878afc h1:QqMWyLgZcwRfDJ85xqzZCRgJI5+rPeg93wddxZ6cOo8=
github.com/noborus/sqlss v0.0.0-20231204225649-d757e7878afc/go.mod h1:34KdYx3QxMFfD05RhUi7Uw5M1i6KOBQ1NHtMIuNVnWM=
github.com/noborus/tbln v0.0.2 h1:pQIv+ZO38KPz52FOuhs/W3inpgmd5qwL8XFDqI+KKyY=
github.com/noborus/tbln v0.0.2/go.mod h1:kS3WhEDRJhNwF3+aRGl9iaUzu/r3lExDagcPPENtNQ0=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
Expand All @@ -85,8 +87,8 @@ github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4A
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
Expand All @@ -99,17 +101,17 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
Expand All @@ -125,8 +127,10 @@ modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0=
modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/libc v1.31.0 h1:bAbB8WgH0quiCpXjPu90TZkjDdZUFKEstNtSn+e6ntk=
modernc.org/libc v1.31.0/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE=
modernc.org/libc v1.35.0 h1:EQ4szx6Q/QLZuysmAnI4dfRnKbAbNlENp23ruvTJ2nE=
modernc.org/libc v1.35.0/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE=
modernc.org/libc v1.36.0 h1:J5UW1tOzu8d2NY8XtQ/tAHJuCcn0b062EkCY91drjX4=
modernc.org/libc v1.36.0/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
Expand Down
4 changes: 3 additions & 1 deletion importer.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ func TableNames(parsedQuery []string) (map[string]string, []int) {
continue
case strings.EqualFold(w, "FROM"),
strings.EqualFold(w, "JOIN"),
strings.EqualFold(w, "TABLE"):
strings.EqualFold(w, "TABLE"),
strings.EqualFold(w, "INTO"),
strings.EqualFold(w, "UPDATE"):
tableFlag = true
frontFlag = true
case isSQLKeyWords(w):
Expand Down
26 changes: 14 additions & 12 deletions output_tablewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,18 @@ import (

// TWWriter provides methods of the Writer interface.
type TWWriter struct {
writer *tablewriter.Table
outNULL string
results []string
needNULL bool
markdown bool
writeOpts *WriteOpts
writer *tablewriter.Table
outNULL string
results []string
needNULL bool
markdown bool
}

// NewTWWriter returns TWWriter.
func NewTWWriter(writeOpts *WriteOpts, markdown bool) *TWWriter {
w := &TWWriter{}
w.writer = tablewriter.NewWriter(writeOpts.OutStream)
w.writer.SetAutoFormatHeaders(false)
w.writer.SetAutoWrapText(!writeOpts.OutNoWrap)
if markdown {
w.writer.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
w.writer.SetCenterSeparator("|")
}
w.writeOpts = writeOpts
w.needNULL = writeOpts.OutNeedNULL
w.outNULL = writeOpts.OutNULL
w.markdown = markdown
Expand All @@ -33,6 +28,13 @@ func NewTWWriter(writeOpts *WriteOpts, markdown bool) *TWWriter {

// PreWrite is preparation.
func (w *TWWriter) PreWrite(columns []string, types []string) error {
w.writer = tablewriter.NewWriter(w.writeOpts.OutStream)
w.writer.SetAutoFormatHeaders(false)
w.writer.SetAutoWrapText(!w.writeOpts.OutNoWrap)
if w.markdown {
w.writer.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
w.writer.SetCenterSeparator("|")
}
w.writer.SetHeader(columns)
w.results = make([]string, len(columns))

Expand Down
1 change: 1 addition & 0 deletions output_vertical.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func NewVFWriter(writeOpts *WriteOpts) *VFWriter {

// PreWrite is preparation.
func (w *VFWriter) PreWrite(columns []string, types []string) error {
w.count = 0
w.header = make([]string, len(columns))
w.hSize = 0
for i, col := range columns {
Expand Down
16 changes: 14 additions & 2 deletions trdsql.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,27 @@ import (
// AppName is used for command names.
var AppName = "trdsql"

// multiT is a flag for multiple queries.
type multiT bool

// multi is a flag for multiple queries.
var multi = multiT(false)

// EnableMultipleQueries enables multiple queries.
func EnableMultipleQueries() {
multi = true
}

// TRDSQL represents DB definition and Importer/Exporter interface.
type TRDSQL struct {
// Importer is interface of processing to
// import(create/insert) data.
Importer Importer
// Exporter is interface export to the process of
// export(select) from the database.
// export(select) from the database.
Exporter Exporter

// Driver is database driver name(sqlite3/mysql/postgres).
// Driver is database driver name(sqlite3/sqlite/mysql/postgres).
Driver string
// Dsn is data source name.
Dsn string
Expand Down Expand Up @@ -100,6 +111,7 @@ const (
PSV
)

// String returns the string representation of the Format.
func (f Format) String() string {
switch f {
case GUESS:
Expand Down

0 comments on commit fa9622c

Please sign in to comment.