-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdenodo.go
100 lines (89 loc) · 3.34 KB
/
denodo.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
package sql
import (
"context"
"errors"
"fmt"
// Use PostgreSQL driver for Denodo
_ "github.com/lib/pq"
)
const (
RepoTypeDenodo = "denodo"
// denodoIntrospectQuery is the SQL query used to introspect the database.
// For Denodo, the object hierarchy is (database > views). When querying
// Denodo, the database corresponds to a schema, and the view corresponds to
// a table.
denodoIntrospectQuery = "SELECT " +
"database_name AS table_schema, " +
"view_name AS table_name, " +
"column_name, " +
"column_type_name AS data_type " +
"FROM " +
"CATALOG_VDP_METADATA_VIEWS()"
)
// DenodoRepository is a Repository implementation for Denodo.
type DenodoRepository struct {
// The majority of the Repository functionality is delegated to
// a generic SQL repository instance.
generic *GenericRepository
}
// DenodoRepository implements sql.Repository
var _ Repository = (*DenodoRepository)(nil)
// NewDenodoRepository is the constructor for sql.
func NewDenodoRepository(cfg RepoConfig) (*DenodoRepository, error) {
if cfg.Database == "" {
return nil, errors.New("database name is mandatory for Denodo repositories")
}
connStr := fmt.Sprintf(
"postgresql://%s:%s@%s:%d/%s",
cfg.User,
cfg.Password,
cfg.Host,
cfg.Port,
cfg.Database,
)
generic, err := NewGenericRepository(RepoTypePostgres, cfg.Database, connStr, cfg.MaxOpenConns)
if err != nil {
return nil, fmt.Errorf("could not instantiate generic sql repository: %w", err)
}
return &DenodoRepository{generic: generic}, nil
}
// ListDatabases is left unimplemented for Denodo, because Denodo doesn't have
// the concept of databases.
func (r *DenodoRepository) ListDatabases(_ context.Context) ([]string, error) {
return nil, errors.New("ListDatabases is not implemented for Denodo repositories")
}
// Introspect delegates introspection to GenericRepository. See
// Repository.Introspect and GenericRepository.IntrospectWithQuery for more
// details.
func (r *DenodoRepository) Introspect(ctx context.Context, params IntrospectParameters) (*Metadata, error) {
return r.generic.IntrospectWithQuery(ctx, denodoIntrospectQuery, params)
}
// SampleTable delegates sampling to GenericRepository, using a Denodo-specific
// table sample query. See Repository.SampleTable and
// GenericRepository.SampleTableWithQuery for more details.
func (r *DenodoRepository) SampleTable(
ctx context.Context,
params SampleParameters,
) (Sample, error) {
// Denodo uses double-quotes to quote identifiers
attrStr := params.Metadata.QuotedAttributeNamesString("\"")
// The postgres driver is currently unable to properly send the
// parameters of a prepared statement to Denodo. Therefore, instead of
// building a prepared statement, we populate the query string before
// sending it to the driver.
query := fmt.Sprintf(
"SELECT %s FROM %s.%s OFFSET %d ROWS LIMIT %d",
attrStr, params.Metadata.Schema, params.Metadata.Name, params.Offset, params.SampleSize,
)
return r.generic.SampleTableWithQuery(ctx, query, params)
}
// Ping delegates the ping to GenericRepository. See Repository.Ping and
// GenericRepository.Ping for more details.
func (r *DenodoRepository) Ping(ctx context.Context) error {
return r.generic.Ping(ctx)
}
// Close delegates the close to GenericRepository. See Repository.Close and
// GenericRepository.Close for more details.
func (r *DenodoRepository) Close() error {
return r.generic.Close()
}