Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Redshift Serverless #107

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions redshift/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ type Config struct {
Database string
SSLMode string
MaxConns int

isServerless bool
checkedForServerless bool
}

// Client struct holding connection string
Expand All @@ -48,6 +51,29 @@ func (c *Config) NewClient(database string) *Client {
}
}

func (c *Config) IsServerless(db *DBConnection) (bool, error) {
if c.checkedForServerless {
return c.isServerless, nil
}

c.checkedForServerless = true

_, err := db.Query("SELECT 1 FROM SYS_SERVERLESS_USAGE")
// No error means we have accessed the view and are running Redshift Serverless
if err == nil {
c.isServerless = true
return true, nil
}

// Insuficcient privileges means we do not have access to this view ergo we run on Redshift classic
if isPqErrorWithCode(err, pgErrorCodeInsufficientPrivileges) {
c.isServerless = false
return false, nil
}

return false, err
}

// Connect returns a copy to an sql.Open()'ed database connection wrapped in a DBConnection struct.
// Callers must return their database resources. Use of QueryRow() or Exec() is encouraged.
// Query() must have their rows.Close()'ed.
Expand Down
6 changes: 6 additions & 0 deletions redshift/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const (
pqErrorCodeDeadlock = "40P01"
pqErrorCodeFailedTransaction = "25P02"
pqErrorCodeDuplicateSchema = "42P06"

pgErrorCodeInsufficientPrivileges = "42501"
)

// startTransaction starts a new DB transaction on the specified database.
Expand Down Expand Up @@ -134,6 +136,10 @@ func isRetryablePQError(code string) bool {
return ok
}

func isPqErrorWithCode(err error, code string) bool {
return string(err.(*pq.Error).Code) == code
}

func splitCsvAndTrim(raw string) ([]string, error) {
if raw == "" {
return []string{}, nil
Expand Down
26 changes: 14 additions & 12 deletions redshift/resource_redshift_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,21 +449,23 @@ func resourceRedshiftSchemaReadImpl(db *DBConnection, d *schema.ResourceData) er
}

func resourceRedshiftSchemaReadLocal(db *DBConnection, d *schema.ResourceData) error {
var schemaQuota int

err := db.QueryRow(`
SELECT
COALESCE(quota, 0)
FROM svv_schema_quota_state
WHERE schema_id = $1
`, d.Id()).Scan(&schemaQuota)
switch {
case err == sql.ErrNoRows:
schemaQuota = 0
case err != nil:
var schemaQuota int = 0
isServerless, err := db.client.config.IsServerless(db)
if err != nil {
return err
}

if !isServerless {
err := db.QueryRow(`
SELECT
COALESCE(quota, 0)
FROM svv_schema_quota_state
WHERE schema_id = $1
`, d.Id()).Scan(&schemaQuota)
if err != nil && err != sql.ErrNoRows {
return err
}
}
d.Set(schemaQuotaAttr, schemaQuota)
d.Set(schemaExternalSchemaAttr, nil)

Expand Down
14 changes: 7 additions & 7 deletions redshift/resource_redshift_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,12 +274,12 @@ func resourceRedshiftUserReadImpl(db *DBConnection, d *schema.ResourceData) erro
var userSuperuser, userCreateDB bool

columns := []string{
"usename",
"usecreatedb",
"usesuper",
"syslogaccess",
`COALESCE(useconnlimit::TEXT, 'UNLIMITED')`,
"sessiontimeout",
"user_name",
"createdb",
"superuser",
"syslog_access",
`COALESCE(connection_limit::TEXT, 'UNLIMITED')`,
"session_timeout",
}

values := []interface{}{
Expand All @@ -293,7 +293,7 @@ func resourceRedshiftUserReadImpl(db *DBConnection, d *schema.ResourceData) erro

useSysID := d.Id()

userSQL := fmt.Sprintf("SELECT %s FROM svl_user_info WHERE usesysid = $1", strings.Join(columns, ","))
userSQL := fmt.Sprintf("SELECT %s FROM svv_user_info WHERE user_id = $1", strings.Join(columns, ","))
err := db.QueryRow(userSQL, useSysID).Scan(values...)
switch {
case err == sql.ErrNoRows:
Expand Down