Skip to content

Commit bbbcc3e

Browse files
committed
Merge branch '193-settings-to-explain' into 'master'
feat: Add SETTINGS to EXPLAIN (#193) Closes #193 See merge request postgres-ai/joe!184
2 parents 5b8d35d + 1870e05 commit bbbcc3e

File tree

5 files changed

+68
-13
lines changed

5 files changed

+68
-13
lines changed

pkg/bot/command/explain.go

+16-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ const (
3131

3232
// Query Explain prefixes.
3333
queryExplain = "EXPLAIN (FORMAT TEXT) "
34-
queryExplainAnalyze = "EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON) "
34+
queryExplainAnalyze = "EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON %s) "
35+
settingsExplain = ", SETTINGS TRUE"
36+
37+
postgresNumDiv = 10000 // Divider to get version from server_version_num.
38+
pgVersion12 = 12 // Explain Settings are available starting with Postgres 12.
3539

3640
// locksTitle shows locks for a single query analyzed with EXPLAIN.
3741
// locksTitle = "*Query heavy locks:*\n".
@@ -82,7 +86,7 @@ func Explain(ctx context.Context, msgSvc connection.Messenger, command *platform
8286
return errors.Wrap(err, "failed to run explain without execution")
8387
}
8488

85-
explainAnalyze, err := querier.DBQueryWithResponse(ctx, tx, queryExplainAnalyze+command.Query)
89+
explainAnalyze, err := querier.DBQueryWithResponse(ctx, tx, analyzePrefix(session.DBVersion)+command.Query)
8690
if err != nil {
8791
return err
8892
}
@@ -191,6 +195,16 @@ func Explain(ctx context.Context, msgSvc connection.Messenger, command *platform
191195
return nil
192196
}
193197

198+
func analyzePrefix(dbVersionNum int) string {
199+
settingsValue := ""
200+
201+
if (dbVersionNum / postgresNumDiv) >= pgVersion12 {
202+
settingsValue = settingsExplain
203+
}
204+
205+
return fmt.Sprintf(queryExplainAnalyze, settingsValue)
206+
}
207+
194208
func observeLocks(ctx context.Context, db *pgxpool.Pool, txPID int) ([][]string, error) {
195209
observeConn, err := getConn(ctx, db)
196210
if err != nil {

pkg/bot/command/explain_test.go

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package command
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestAnalyzePrefix(t *testing.T) {
10+
testCases := []struct {
11+
input int
12+
expectedOutput string
13+
}{
14+
{
15+
input: 0,
16+
expectedOutput: "EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON ) ",
17+
},
18+
{
19+
input: 90600,
20+
expectedOutput: "EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON ) ",
21+
},
22+
{
23+
input: 120000,
24+
expectedOutput: "EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON , SETTINGS TRUE) ",
25+
},
26+
{
27+
input: 160000,
28+
expectedOutput: "EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON , SETTINGS TRUE) ",
29+
},
30+
}
31+
32+
for _, tc := range testCases {
33+
output := analyzePrefix(tc.input)
34+
assert.Equal(t, tc.expectedOutput, output)
35+
}
36+
}

pkg/foreword/foreword.go

+14-11
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,25 @@ Database state at: %s (%s ago)
3232

3333
// Content defines data for a foreword message.
3434
type Content struct {
35-
Duration time.Duration
36-
SessionID string
37-
AppVersion string
38-
Edition string
39-
DBName string
40-
DSA string
41-
DSADiff string
42-
DBSize string
43-
DBVersion string
35+
Duration time.Duration
36+
SessionID string
37+
AppVersion string
38+
Edition string
39+
DBName string
40+
DSA string
41+
DSADiff string
42+
DBSize string
43+
DBVersion string
44+
DBVersionNum int
4445
}
4546

4647
// EnrichForewordInfo adds database details to foreword data.
4748
func (f *Content) EnrichForewordInfo(ctx context.Context, db *pgxpool.Pool) error {
48-
r := db.QueryRow(ctx, "select current_setting('server_version'), pg_size_pretty(pg_database_size($1))", f.DBName)
49+
r := db.QueryRow(ctx,
50+
"select current_setting('server_version'), current_setting('server_version_num')::int, pg_size_pretty(pg_database_size($1))",
51+
f.DBName)
4952

50-
if err := r.Scan(&f.DBVersion, &f.DBSize); err != nil {
53+
if err := r.Scan(&f.DBVersion, &f.DBVersionNum, &f.DBSize); err != nil {
5154
return errors.Wrap(err, "failed to retrieve database meta info")
5255
}
5356

pkg/services/msgproc/dblab.go

+1
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ func (s *ProcessingService) runSession(ctx context.Context, user *usermanager.Us
144144
user.Session.CloneConnection = userConn
145145
user.Session.LastActionTs = time.Now()
146146
user.Session.ChannelID = incomingMessage.ChannelID
147+
user.Session.DBVersion = fwData.DBVersionNum
147148

148149
if s.config.Platform.HistoryEnabled && incomingMessage.SessionID == "" {
149150
if err := s.createPlatformSession(ctx, user, sMsg.ChannelID); err != nil {

pkg/services/usermanager/user.go

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ type UserSession struct {
4040
ConnParams models.Clone
4141
Pool *pgxpool.Pool `json:"-"`
4242
CloneConnection *pgx.Conn `json:"-"`
43+
DBVersion int `json:"-"`
4344
}
4445

4546
// Quota defines a user quota for requests.

0 commit comments

Comments
 (0)