-
Notifications
You must be signed in to change notification settings - Fork 3
/
backend.go
123 lines (106 loc) · 3.15 KB
/
backend.go
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
package backend
import (
"context"
"database/sql"
"errors"
"strings"
"github.com/turbot/pipe-fittings/queryresult"
"github.com/turbot/steampipe-plugin-sdk/v5/sperr"
)
var ErrUnknownBackend = errors.New("unknown backend")
type RowReader interface {
Read(columnValues []any, cols []*queryresult.ColumnDef) ([]any, error)
}
type Backend interface {
Connect(context.Context, ...ConnectOption) (*sql.DB, error)
RowReader() RowReader
ConnectionString() string
Name() string
}
type SearchPathProvider interface {
OriginalSearchPath() []string
RequiredSearchPath() []string
ResolvedSearchPath() []string
}
func FromConnectionString(ctx context.Context, str string) (Backend, error) {
switch {
case IsPostgresConnectionString(str):
pgBackend, err := NewPostgresBackend(ctx, str)
if err != nil {
return nil, err
}
// check if this is in fact a steampipe backend
if isSteampipeBackend(ctx, pgBackend) {
return NewSteampipeBackend(ctx, *pgBackend)
}
return pgBackend, nil
case IsMySqlConnectionString(str):
return NewMySQLBackend(str), nil
case IsDuckDBConnectionString(str):
return NewDuckDBBackend(str), nil
case IsSqliteConnectionString(str):
return NewSqliteBackend(str), nil
default:
return nil, sperr.WrapWithMessage(ErrUnknownBackend, "could not evaluate backend: %s", str)
}
}
func HasBackend(str string) bool {
switch {
case
IsPostgresConnectionString(str),
IsMySqlConnectionString(str),
IsDuckDBConnectionString(str),
IsSqliteConnectionString(str):
return true
default:
return false
}
}
func isSteampipeBackend(ctx context.Context, s *PostgresBackend) bool {
db, err := s.Connect(ctx)
if err != nil {
return false
}
defer db.Close()
// Query to check if tables exist
query := `SELECT EXISTS (
SELECT FROM
pg_tables
WHERE
schemaname = 'steampipe_internal' AND
tablename IN ('steampipe_plugin', 'steampipe_connection')
);`
// Execute the query
var exists bool
err = db.QueryRow(query).Scan(&exists)
if err != nil {
return false
}
// Check if tables exist
return exists
}
// IsPostgresConnectionString returns true if the connection string is for postgres
// looks for the postgresql:// or postgres:// prefix
func IsPostgresConnectionString(connString string) bool {
for _, v := range postgresConnectionStringPrefixes {
if strings.HasPrefix(connString, v) {
return true
}
}
return false
}
// IsSqliteConnectionString returns true if the connection string is for sqlite
// looks for the sqlite:// prefix
func IsSqliteConnectionString(connString string) bool {
return strings.HasPrefix(connString, sqliteConnectionStringPrefix)
}
// IsDuckDBConnectionString returns true if the connection string is for duckdb
// looks for the duckdb:// prefix
func IsDuckDBConnectionString(connString string) bool {
return strings.HasPrefix(connString, duckDBConnectionStringPrefix)
}
// IsMySqlConnectionString returns true if the connection string is for mysql
// looks for the mysql:// prefix
func IsMySqlConnectionString(connString string) bool {
return strings.HasPrefix(connString, mysqlConnectionStringPrefix)
}