Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ func doDML(ctx context.Context, conn canExec, query string, args []any, w io.Wri
return count, nil
}

func doTCL(ctx context.Context, ss *session, query string) error {
if ss.tx == nil {
return ErrNoActiveTransaction
}
_, err := ss.tx.ExecContext(ctx, query)
if err == nil {
fmt.Fprintln(ss.stdErr, "Ok")
}
return err
}

func (ss *session) commit() error {
var err error
if ss.tx != nil {
Expand Down
25 changes: 12 additions & 13 deletions interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,17 @@ func newReservedWordPattern(list ...string) reserveWordPattern {
var o = struct{}{}

var oneLineCommands = map[string]struct{}{
`COMMIT`: o,
`DESC`: o,
`EDIT`: o,
`EXIT`: o,
`HISTORY`: o,
`HOST`: o,
`QUIT`: o,
`REM`: o,
`ROLLBACK`: o,
`SPOOL`: o,
`START`: o,
`\D`: o,
`COMMIT`: o,
`DESC`: o,
`EDIT`: o,
`EXIT`: o,
`HISTORY`: o,
`HOST`: o,
`QUIT`: o,
`REM`: o,
`SPOOL`: o,
`START`: o,
`\D`: o,
}

func isOneLineCommand(cmdLine string) bool {
Expand Down Expand Up @@ -122,7 +121,7 @@ func (ss *session) newInteractiveIn() *interactiveIn {
editor.ResetColor = "\x1B[0m"
editor.DefaultColor = "\x1B[39;49;1m"
editor.Highlight = []readline.Highlight{
{Pattern: newReservedWordPattern("HOST", "ALTER", "COMMIT", "CREATE", "DELETE", "DESC", "DROP", "EXIT", "HISTORY", "INSERT", "QUIT", "REM", "ROLLBACK", "SELECT", "SPOOL", "START", "TRUNCATE", "UPDATE", "AND", "FROM", "INTO", "OR", "WHERE"), Sequence: "\x1B[36;49;1m"},
{Pattern: newReservedWordPattern("HOST", "ALTER", "COMMIT", "CREATE", "DELETE", "DESC", "DROP", "EXIT", "HISTORY", "INSERT", "QUIT", "REM", "ROLLBACK", "SELECT", "SPOOL", "START", "TRUNCATE", "UPDATE", "AND", "FROM", "INTO", "OR", "WHERE", "SAVEPOINT", "TO", "TRANSACTION"), Sequence: "\x1B[36;49;1m"},
{Pattern: regexp.MustCompile(`[0-9]+`), Sequence: "\x1B[35;49;1m"},
{Pattern: regexp.MustCompile(`/\*.*?\*/`), Sequence: "\x1B[33;49;22m"},
{Pattern: regexp.MustCompile(`"[^"]*"|"[^"]*$`), Sequence: "\x1B[31;49;1m"},
Expand Down
8 changes: 8 additions & 0 deletions internal/sqlcompletion/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func getSqlCommands() []string {
"quit",
"rem",
"rollback",
"savepoint",
"select",
"spool",
"start",
Expand Down Expand Up @@ -108,6 +109,13 @@ func (C *completeType) getCandidates(ctx context.Context, fields []string) ([]st
v, _ := completion.PathComplete(fields[:i+1])
return v
}
} else if strings.EqualFold(word, "rollback") {
tableListNow = false
lastKeywordAt = i
nextKeyword = nil
candidates = func() []string {
return []string{"to", "transaction"}
}
} else {
if tableListNow && i < len(fields)-1 {
tableNameInline = append(tableNameInline, word)
Expand Down
18 changes: 15 additions & 3 deletions loop.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ var (
ErrBeginIsNotSupported = errors.New("'BEGIN' is not supported; transactions are managed automatically")
ErrNoDataFound = errors.New("no data found")
ErrNotSupported = errors.New("not supported")
ErrInvalidRollback = errors.New("invalid ROLLBACK syntax: expected 'TO' or 'TRANSACTION'")
ErrNoActiveTransaction = errors.New("no active transaction")
)

func (ss *session) prompt(w io.Writer, i int) (int, error) {
Expand Down Expand Up @@ -160,6 +162,19 @@ func (ss *session) Loop(ctx context.Context, commandIn commandIn) error {
case "SELECT":
misc.Echo(ss.spool, query)
err = doSelect(ctx, ss, query, nil)
case "ROLLBACK":
misc.Echo(ss.spool, query)
arg, _ = misc.CutField(arg)
if arg == "" {
err = ss.rollback()
} else if strings.EqualFold(arg, "TO") || strings.EqualFold(arg, "TRANSACTION") {
err = doTCL(ctx, ss, query)
} else {
err = ErrInvalidRollback
}
case "SAVEPOINT":
misc.Echo(ss.spool, query)
doTCL(ctx, ss, query)
case "DELETE", "INSERT", "UPDATE", "MERGE":
misc.Echo(ss.spool, query)
isNewTx := (ss.tx == nil)
Expand All @@ -174,9 +189,6 @@ func (ss *session) Loop(ctx context.Context, commandIn commandIn) error {
case "COMMIT":
misc.Echo(ss.spool, query)
err = ss.commit()
case "ROLLBACK":
misc.Echo(ss.spool, query)
err = ss.rollback()
case "EXIT", "QUIT":
if ss.tx == nil || commandIn.CanCloseInTransaction() {
return nil
Expand Down
3 changes: 3 additions & 0 deletions release_note_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

- Refactor `dialect` subpackage: rename fields and methods for clarity (#8)
- Updated `go-readline-ny` to v1.12.2 and `go-ttyadapter` to v0.2.0, and switched API calls to use `go-ttyadapter`.(#9)
- Support `SAVEPOINT` as a TCL command (#11)
- Support `ROLLBACK TO` (or `ROLLBACK TRANSACTION`) as a TCL command (#11)
- Require `;` after `ROLLBACK` to prevent accidental execution (#11)

v0.25.0
=======
Expand Down
3 changes: 3 additions & 0 deletions release_note_ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

- サブパッケージ `dialect` をリファクタリング: フィールド・メソッドを改名 (#8)
- `go-readline-ny` を v1.12.2、`go-ttyadapter` を v0.2.0 に更新し、対応する API 呼び出しを `go-ttyadapter` 側に切り替えた。(#9)
- `SAVEPOINT` を TCL コマンドとしてサポート (#11)
- `ROLLBACK TO`(もしくは `ROLLBACK TRANSACTION`)を TCL コマンドとしてサポート (#11)
- 誤操作による実行を防ぐため、`ROLLBACK` には `;` を必須とした (#11)

v0.25.0
=======
Expand Down