Skip to content

Commit df4c05b

Browse files
feat(debug): Add databases=managed debug option (#2898)
* feat(debug): Add databases=managed debug option - Remove the --no-database flag - Refactor the shfmt package --------- Co-authored-by: Andrew Benton <andrew@sqlc.dev>
1 parent 5f87be3 commit df4c05b

File tree

6 files changed

+84
-62
lines changed

6 files changed

+84
-62
lines changed

internal/cmd/cmd.go

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ func Do(args []string, stdin io.Reader, stdout io.Writer, stderr io.Writer) int
3939
rootCmd.PersistentFlags().BoolP("experimental", "x", false, "DEPRECATED: enable experimental features (default: false)")
4040
rootCmd.PersistentFlags().Bool("no-remote", false, "disable remote execution (default: false)")
4141
rootCmd.PersistentFlags().Bool("remote", false, "enable remote execution (default: false)")
42-
rootCmd.PersistentFlags().Bool("no-database", false, "disable database connections (default: false)")
4342

4443
rootCmd.AddCommand(checkCmd)
4544
rootCmd.AddCommand(createDBCmd)
@@ -137,24 +136,21 @@ var initCmd = &cobra.Command{
137136
}
138137

139138
type Env struct {
140-
DryRun bool
141-
Debug opts.Debug
142-
Remote bool
143-
NoRemote bool
144-
NoDatabase bool
139+
DryRun bool
140+
Debug opts.Debug
141+
Remote bool
142+
NoRemote bool
145143
}
146144

147145
func ParseEnv(c *cobra.Command) Env {
148146
dr := c.Flag("dry-run")
149147
r := c.Flag("remote")
150148
nr := c.Flag("no-remote")
151-
nodb := c.Flag("no-database")
152149
return Env{
153-
DryRun: dr != nil && dr.Changed,
154-
Debug: opts.DebugFromEnv(),
155-
Remote: r != nil && nr.Value.String() == "true",
156-
NoRemote: nr != nil && nr.Value.String() == "true",
157-
NoDatabase: nodb != nil && nodb.Value.String() == "true",
150+
DryRun: dr != nil && dr.Changed,
151+
Debug: opts.DebugFromEnv(),
152+
Remote: r != nil && nr.Value.String() == "true",
153+
NoRemote: nr != nil && nr.Value.String() == "true",
158154
}
159155
}
160156

internal/cmd/vet.go

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,13 @@ func Vet(ctx context.Context, dir, filename string, opts *Options) error {
144144
}
145145

146146
c := checker{
147-
Rules: rules,
148-
Conf: conf,
149-
Dir: dir,
150-
Env: env,
151-
Envmap: map[string]string{},
152-
Stderr: stderr,
153-
NoDatabase: e.NoDatabase,
147+
Rules: rules,
148+
Conf: conf,
149+
Dir: dir,
150+
Env: env,
151+
Stderr: stderr,
152+
OnlyManagedDB: e.Debug.OnlyManagedDatabases,
153+
Replacer: shfmt.NewReplacer(nil),
154154
}
155155
errored := false
156156
for _, sql := range conf.SQL {
@@ -379,14 +379,14 @@ type rule struct {
379379
}
380380

381381
type checker struct {
382-
Rules map[string]rule
383-
Conf *config.Config
384-
Dir string
385-
Env *cel.Env
386-
Envmap map[string]string
387-
Stderr io.Writer
388-
NoDatabase bool
389-
Client pb.QuickClient
382+
Rules map[string]rule
383+
Conf *config.Config
384+
Dir string
385+
Env *cel.Env
386+
Stderr io.Writer
387+
OnlyManagedDB bool
388+
Client pb.QuickClient
389+
Replacer *shfmt.Replacer
390390
}
391391

392392
func (c *checker) fetchDatabaseUri(ctx context.Context, s config.SQL) (string, func() error, error) {
@@ -448,14 +448,7 @@ func (c *checker) fetchDatabaseUri(ctx context.Context, s config.SQL) (string, f
448448
}
449449

450450
func (c *checker) DSN(dsn string) (string, error) {
451-
// Populate the environment variable map if it is empty
452-
if len(c.Envmap) == 0 {
453-
for _, e := range os.Environ() {
454-
k, v, _ := strings.Cut(e, "=")
455-
c.Envmap[k] = v
456-
}
457-
}
458-
return shfmt.Replace(dsn, c.Envmap), nil
451+
return c.Replacer.Replace(dsn), nil
459452
}
460453

461454
func (c *checker) checkSQL(ctx context.Context, s config.SQL) error {
@@ -488,8 +481,8 @@ func (c *checker) checkSQL(ctx context.Context, s config.SQL) error {
488481
var prep preparer
489482
var expl explainer
490483
if s.Database != nil { // TODO only set up a database connection if a rule evaluation requires it
491-
if c.NoDatabase {
492-
return fmt.Errorf("database: connections disabled via command line flag")
484+
if s.Database.URI != "" && c.OnlyManagedDB {
485+
return fmt.Errorf("database: connections disabled via SQLCDEBUG=databases=managed")
493486
}
494487
dburl, cleanup, err := c.fetchDatabaseUri(ctx, s)
495488
if err != nil {

internal/engine/postgresql/analyzer/analyze.go

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,31 @@ import (
1313

1414
core "github.com/sqlc-dev/sqlc/internal/analysis"
1515
"github.com/sqlc-dev/sqlc/internal/config"
16+
"github.com/sqlc-dev/sqlc/internal/opts"
1617
pb "github.com/sqlc-dev/sqlc/internal/quickdb/v1"
18+
"github.com/sqlc-dev/sqlc/internal/shfmt"
1719
"github.com/sqlc-dev/sqlc/internal/sql/ast"
1820
"github.com/sqlc-dev/sqlc/internal/sql/named"
1921
"github.com/sqlc-dev/sqlc/internal/sql/sqlerr"
2022
)
2123

2224
type Analyzer struct {
23-
db config.Database
24-
client pb.QuickClient
25-
pool *pgxpool.Pool
26-
27-
formats sync.Map
28-
columns sync.Map
29-
tables sync.Map
25+
db config.Database
26+
client pb.QuickClient
27+
pool *pgxpool.Pool
28+
dbg opts.Debug
29+
replacer *shfmt.Replacer
30+
formats sync.Map
31+
columns sync.Map
32+
tables sync.Map
3033
}
3134

3235
func New(client pb.QuickClient, db config.Database) *Analyzer {
3336
return &Analyzer{
34-
db: db,
35-
client: client,
37+
db: db,
38+
dbg: opts.DebugFromEnv(),
39+
client: client,
40+
replacer: shfmt.NewReplacer(nil),
3641
}
3742
}
3843

@@ -204,8 +209,10 @@ func (a *Analyzer) Analyze(ctx context.Context, n ast.Node, query string, migrat
204209
return nil, err
205210
}
206211
uri = edb.Uri
212+
} else if a.dbg.OnlyManagedDatabases {
213+
return nil, fmt.Errorf("database: connections disabled via SQLCDEBUG=databases=managed")
207214
} else {
208-
uri = a.db.URI
215+
uri = a.replacer.Replace(a.db.URI)
209216
}
210217
conf, err := pgxpool.ParseConfig(uri)
211218
if err != nil {

internal/opts/debug.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,20 @@ import (
1212
// dumpcatalog: setting dumpcatalog=1 will print the parsed database schema
1313
// trace: setting trace=<path> will output a trace
1414
// processplugins: setting processplugins=0 will disable process-based plugins
15+
// databases: setting databases=managed will disable connections to databases via URI
1516
// dumpvetenv: setting dumpvetenv=1 will print the variables available to
1617
// a vet rule during evaluation
1718
// dumpexplain: setting dumpexplain=1 will print the JSON-formatted output
1819
// from executing EXPLAIN ... on a query during vet rule evaluation
1920

2021
type Debug struct {
21-
DumpAST bool
22-
DumpCatalog bool
23-
Trace string
24-
ProcessPlugins bool
25-
DumpVetEnv bool
26-
DumpExplain bool
22+
DumpAST bool
23+
DumpCatalog bool
24+
Trace string
25+
ProcessPlugins bool
26+
OnlyManagedDatabases bool
27+
DumpVetEnv bool
28+
DumpExplain bool
2729
}
2830

2931
func DebugFromEnv() Debug {
@@ -53,6 +55,8 @@ func DebugFromString(val string) Debug {
5355
}
5456
case pair == "processplugins=0":
5557
d.ProcessPlugins = false
58+
case pair == "databases=managed":
59+
d.OnlyManagedDatabases = true
5660
case pair == "dumpvetenv=1":
5761
d.DumpVetEnv = true
5862
case pair == "dumpexplain=1":

internal/shfmt/shfmt.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,38 @@
11
package shfmt
22

33
import (
4+
"os"
45
"regexp"
56
"strings"
67
)
78

89
var pat = regexp.MustCompile(`\$\{[A-Z_]+\}`)
910

10-
func Replace(f string, vars map[string]string) string {
11+
type Replacer struct {
12+
envmap map[string]string
13+
}
14+
15+
func (r *Replacer) Replace(f string) string {
1116
return pat.ReplaceAllStringFunc(f, func(s string) string {
1217
s = strings.TrimPrefix(s, "${")
1318
s = strings.TrimSuffix(s, "}")
14-
return vars[s]
19+
return r.envmap[s]
1520
})
1621
}
22+
23+
func NewReplacer(env []string) *Replacer {
24+
r := Replacer{
25+
envmap: map[string]string{},
26+
}
27+
if env == nil {
28+
env = os.Environ()
29+
}
30+
for _, e := range env {
31+
k, v, _ := strings.Cut(e, "=")
32+
if k == "SQLC_AUTH_TOKEN" {
33+
continue
34+
}
35+
r.envmap[k] = v
36+
}
37+
return &r
38+
}

internal/shfmt/shfmt_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import "testing"
44

55
func TestReplace(t *testing.T) {
66
s := "POSTGRES_SQL://${PG_USER}:${PG_PASSWORD}@${PG_HOST}:${PG_PORT}/AUTHORS"
7-
env := map[string]string{
8-
"PG_USER": "user",
9-
"PG_PASSWORD": "password",
10-
"PG_HOST": "host",
11-
"PG_PORT": "port",
12-
}
7+
r := NewReplacer([]string{
8+
"PG_USER=user",
9+
"PG_PASSWORD=password",
10+
"PG_HOST=host",
11+
"PG_PORT=port",
12+
})
1313
e := "POSTGRES_SQL://user:password@host:port/AUTHORS"
14-
if v := Replace(s, env); v != e {
14+
if v := r.Replace(s); v != e {
1515
t.Errorf("%s != %s", v, e)
1616
}
1717
}

0 commit comments

Comments
 (0)