59 lines
1.7 KiB
Go
59 lines
1.7 KiB
Go
package repo
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/ClickHouse/clickhouse-go/v2"
|
|
"github.com/ClickHouse/clickhouse-go/v2/lib/driver"
|
|
)
|
|
|
|
// NewClickHouse opens a native-protocol ClickHouse connection. The returned
|
|
// driver.Conn is safe for concurrent use. Caller owns Close().
|
|
func NewClickHouse(ctx context.Context, addr, db, user, password string) (driver.Conn, error) {
|
|
conn, err := clickhouse.Open(&clickhouse.Options{
|
|
Addr: []string{addr},
|
|
Auth: clickhouse.Auth{
|
|
Database: db,
|
|
Username: user,
|
|
Password: password,
|
|
},
|
|
Settings: clickhouse.Settings{
|
|
"readonly": 0, // analytics queries; per-user read-only enforced for /query/sql separately
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("open clickhouse: %w", err)
|
|
}
|
|
if err := conn.Ping(ctx); err != nil {
|
|
_ = conn.Close()
|
|
return nil, fmt.Errorf("ping clickhouse: %w", err)
|
|
}
|
|
return conn, nil
|
|
}
|
|
|
|
// NewClickHouseReadOnly opens a ClickHouse connection using a SELECT-only
|
|
// account. Used to back the /query/sql sandbox: DDL/DML are rejected at the DB
|
|
// level even if the app-level keyword guard is bypassed.
|
|
func NewClickHouseReadOnly(ctx context.Context, addr, db, user, password string) (driver.Conn, error) {
|
|
conn, err := clickhouse.Open(&clickhouse.Options{
|
|
Addr: []string{addr},
|
|
Auth: clickhouse.Auth{
|
|
Database: db,
|
|
Username: user,
|
|
Password: password,
|
|
},
|
|
Settings: clickhouse.Settings{
|
|
"readonly": 2, // belt-and-braces: server-side enforce read-only
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("open clickhouse (ro): %w", err)
|
|
}
|
|
if err := conn.Ping(ctx); err != nil {
|
|
_ = conn.Close()
|
|
return nil, fmt.Errorf("ping clickhouse (ro): %w", err)
|
|
}
|
|
return conn, nil
|
|
}
|