@@ -26,6 +26,8 @@ type Command struct {
26
26
action func (* Sqlcmd , []string , uint ) error
27
27
// Name of the command
28
28
name string
29
+ // whether the command is a system command
30
+ isSystem bool
29
31
}
30
32
31
33
// Commands is the set of sqlcmd command implementations
@@ -89,9 +91,16 @@ func newCommands() Commands {
89
91
name : "CONNECT" ,
90
92
},
91
93
"EXEC" : {
92
- regex : regexp .MustCompile (`(?im)^[ \t]*?:?!!(?:[ \t]+(.*$)|$)` ),
93
- action : execCommand ,
94
- name : "EXEC" ,
94
+ regex : regexp .MustCompile (`(?im)^[ \t]*?:?!!(?:[ \t]+(.*$)|$)` ),
95
+ action : execCommand ,
96
+ name : "EXEC" ,
97
+ isSystem : true ,
98
+ },
99
+ "EDIT" : {
100
+ regex : regexp .MustCompile (`(?im)^[\t ]*?:?ED(?:[ \t]+(.*$)|$)` ),
101
+ action : editCommand ,
102
+ name : "EDIT" ,
103
+ isSystem : true ,
95
104
},
96
105
}
97
106
}
@@ -103,8 +112,13 @@ func (c Commands) DisableSysCommands(exitOnCall bool) {
103
112
if exitOnCall {
104
113
f = errorDisabled
105
114
}
106
- c ["EXEC" ].action = f
115
+ for _ , cmd := range c {
116
+ if cmd .isSystem {
117
+ cmd .action = f
118
+ }
119
+ }
107
120
}
121
+
108
122
func (c Commands ) matchCommand (line string ) (* Command , []string ) {
109
123
for _ , cmd := range c {
110
124
matchedCommand := cmd .regex .FindStringSubmatch (line )
@@ -411,6 +425,40 @@ func execCommand(s *Sqlcmd, args []string, line uint) error {
411
425
return nil
412
426
}
413
427
428
+ func editCommand (s * Sqlcmd , args []string , line uint ) error {
429
+ if args != nil && strings .TrimSpace (args [0 ]) != "" {
430
+ return InvalidCommandError ("ED" , line )
431
+ }
432
+ file , err := os .CreateTemp ("" , "sq*.sql" )
433
+ if err != nil {
434
+ return err
435
+ }
436
+ fileName := file .Name ()
437
+ defer os .Remove (fileName )
438
+ text := s .batch .String ()
439
+ if s .batch .State () == "-" {
440
+ text = fmt .Sprintf ("%s%s" , text , SqlcmdEol )
441
+ }
442
+ _ , err = file .WriteString (text )
443
+ if err != nil {
444
+ return err
445
+ }
446
+ file .Close ()
447
+ cmd := sysCommand (s .vars .TextEditor () + " " + `"` + fileName + `"` )
448
+ cmd .Stderr = s .GetError ()
449
+ cmd .Stdout = s .GetOutput ()
450
+ err = cmd .Run ()
451
+ if err != nil {
452
+ return err
453
+ }
454
+ wasEcho := s .echoFileLines
455
+ s .echoFileLines = true
456
+ s .batch .Reset (nil )
457
+ _ = s .IncludeFile (fileName , false )
458
+ s .echoFileLines = wasEcho
459
+ return nil
460
+ }
461
+
414
462
func resolveArgumentVariables (s * Sqlcmd , arg []rune , failOnUnresolved bool ) (string , error ) {
415
463
var b * strings.Builder
416
464
end := len (arg )
0 commit comments