forked from marianogappa/sql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.go
More file actions
135 lines (113 loc) · 3.29 KB
/
Copy pathmain.go
File metadata and controls
135 lines (113 loc) · 3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package main
import (
"context"
"flag"
"fmt"
"log"
"os"
"sync"
"golang.org/x/sync/semaphore"
)
type arrayFlags []string
func (i *arrayFlags) String() string {
result := ""
for _, v := range *i {
result = result + " " + v
}
return result
}
func (i *arrayFlags) Set(value string) error {
*i = append(*i, value)
return nil
}
func main() {
var (
flagHelp = flag.Bool("help", false, "shows usage")
flagListDBs = flag.Bool("list-dbs", false, "List all available DBs (used for auto-completion)")
flagListGroups = flag.Bool("list-groups", false, "List all available Groups")
)
var flagGroupExclusion arrayFlags
var flagGroupFilter arrayFlags
var flagGroupSelector arrayFlags
var flagDbExclusion arrayFlags
flag.Var(&flagGroupExclusion, "ge", "DB group exclusion (can be repeated)")
flag.Var(&flagGroupFilter, "gf", "DB group filter (can be repeated, intersection)")
flag.Var(&flagGroupSelector, "gs", "DB group selector (can be repeated, union)")
flag.Var(&flagDbExclusion, "de", "DB exclusion (can be repeated)")
flag.BoolVar(flagHelp, "h", false, "shows usage")
flag.Parse()
if *flagHelp {
usage("")
}
settings := mustReadSettings()
if *flagListDBs { // for auto-completion
for dbName := range settings.Databases {
fmt.Print(dbName, " ")
}
fmt.Println()
os.Exit(0)
}
if *flagListGroups {
for groupName := range settings.DatabaseGroups {
fmt.Print(groupName, " ")
}
fmt.Println()
os.Exit(0)
}
nonFlagArgs := flag.Args()
var query string
var databasesArgs []string
stat, err := os.Stdin.Stat()
if err != nil {
log.Fatalf("Couldn't os.Stdin.Stat(): %v", err)
}
if (stat.Mode() & os.ModeCharDevice) != 0 {
// Stdin is a terminal. The last argument is the SQL.
if len(nonFlagArgs) == 0 {
usage("No SQL to run. Exiting.")
}
query = nonFlagArgs[len(nonFlagArgs)-1]
databasesArgs = nonFlagArgs[:len(nonFlagArgs)-1]
} else {
query = readQuery(os.Stdin)
databasesArgs = nonFlagArgs
}
if len(query) <= 3 {
usage("No SQL to run. Exiting.")
}
targetDatabases := getTargetDatabases(settings, databasesArgs, flagGroupExclusion, flagGroupFilter, flagGroupSelector, flagDbExclusion)
if len(targetDatabases) == 0 {
usage("No database to run. Exiting.")
}
os.Exit(_main(settings, targetDatabases, query, newThreadSafePrintliner(os.Stdout).println))
}
func _main(settings *settings, targetDatabases []string, query string, println func(string)) int {
quitContext, cancel := context.WithCancel(context.Background())
go awaitSignal(cancel)
var wg sync.WaitGroup
wg.Add(len(targetDatabases))
appServerSemaphors := make(map[string]*semaphore.Weighted)
for _, k := range targetDatabases {
var appServer = settings.Databases[k].AppServer
if appServer != "" && appServerSemaphors[appServer] == nil {
appServerSemaphors[appServer] = semaphore.NewWeighted(settings.MaxAppServerConnections)
}
}
sqlRunner := mustNewSQLRunner(quitContext, println, query, len(targetDatabases) > 1)
returnCode := 0
for _, k := range targetDatabases {
go func(db database, k string) {
defer wg.Done()
if db.AppServer != "" {
var sem = appServerSemaphors[db.AppServer]
sem.Acquire(quitContext, 1)
defer sem.Release(1)
}
if r := sqlRunner.runSQL(db, k); !r {
returnCode = 1
}
}(settings.Databases[k], k)
}
wg.Wait()
return returnCode
}