Skip to content

Commit

Permalink
Special case for search_path in user options.
Browse files Browse the repository at this point in the history
- search_path accepts a list of values that cannot be quoted, as
  quoting would make PostgreSQL interpret the result as a single
  value. Since we require quoting of values with commas in the
  operator's configMap in order to avoid confusing them with the
  separate map entities, we need to strip those quotes before
  passing the value to PostgreSQL.
- make ftm run
  • Loading branch information
alexeyklyukin committed Nov 8, 2017
1 parent 49582dd commit 1f2c19f
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 17 deletions.
9 changes: 4 additions & 5 deletions pkg/util/config/config_test.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
package config

import (
"testing"
"reflect"
"fmt"
"reflect"
"testing"
)

var getMapPairsFromStringTest = []struct {
in string
in string
expected []string
err error
}{
{"log_statement:all, work_mem:'4GB'", []string{"log_statement:all", "work_mem:'4GB'"}, nil},
{`log_statement:none, search_path:'"$user", public'`, []string{"log_statement:none", `search_path:'"$user", public'`}, nil},
{`search_path:'"$user"`, nil, fmt.Errorf("unclosed quote starting at position 13")},
{"", []string{""}, nil},
{",,log_statement:all ,", []string{"","","log_statement:all", ""}, nil},
{",,log_statement:all ,", []string{"", "", "log_statement:all", ""}, nil},
}

func TestGetMapPairsFromString(t *testing.T) {
Expand All @@ -29,4 +29,3 @@ func TestGetMapPairsFromString(t *testing.T) {
}
}
}

12 changes: 6 additions & 6 deletions pkg/util/config/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,23 +169,23 @@ func processField(value string, field reflect.Value) error {
return nil
}


type parserState int

const (
Plain parserState = iota
Plain parserState = iota
DoubleQuoted
SingleQuoted
)

// Split the pair candidates by commas not located inside open quotes
// Escape characters are not supported for simplicity, as we don't
// expect to find them inside the map values for our use cases
func getMapPairsFromString(value string) (pairs []string , err error) {
func getMapPairsFromString(value string) (pairs []string, err error) {
pairs = make([]string, 0)
state := Plain
var start, quote int

for i, ch := range(strings.Split(value, "")) {
for i, ch := range strings.Split(value, "") {
if ch == `"` {
if state == Plain {
state = DoubleQuoted
Expand All @@ -205,12 +205,12 @@ func getMapPairsFromString(value string) (pairs []string , err error) {
}
}
if ch == "," && state == Plain {
pairs = append(pairs, strings.Trim(value[start:i]," \t"))
pairs = append(pairs, strings.Trim(value[start:i], " \t"))
start = i + 1
}
}
if state != Plain {
err = fmt.Errorf("unclosed quote starting at position %d", quote + 1)
err = fmt.Errorf("unclosed quote starting at position %d", quote+1)
pairs = nil
} else {
pairs = append(pairs, strings.Trim(value[start:], " \t"))
Expand Down
27 changes: 21 additions & 6 deletions pkg/util/users/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ func produceAlterStmt(user spec.PgUser) string {
func produceAlterRoleSetStmts(user spec.PgUser) []string {
result := make([]string, 0)
result = append(result, fmt.Sprintf(alterRoleResetAllSQL, user.Name))
for key, value := range user.Parameters {
result = append(result, fmt.Sprintf(alterRoleSetSQL, user.Name, key, quoteValue(value)))
for name, value := range user.Parameters {
result = append(result, fmt.Sprintf(alterRoleSetSQL, user.Name, name, quoteParameterValue(name, value)))
}
return result
}
Expand All @@ -193,10 +193,25 @@ func quoteMemberList(user spec.PgUser) string {
}

// quoteVal quotes values to be used at ALTER ROLE SET param = value if necessary
func quoteValue(val string) string {
if (strings.HasPrefix(val, `"`) && strings.HasSuffix(val, `"`)) ||
(strings.HasPrefix(val, `'`) && strings.HasSuffix(val, `'`)) {
func quoteParameterValue(name, val string) string {
start := val[0]
end := val[len(val)-1]
if name == "search_path" {
// strip single quotes from the search_path. Those are required in the YAML configuration
// to quote values containing commas, as otherwise NewFromMap would treat each comma-separated
// part of such string as a separate map entry. However, a search_path is interpreted as a list
// only if it is not quoted, otherwise it is treated as a single value. Therefore, we strip
// single quotes here. Note that you can still use double quotes in order to escape schemas
// containing spaces (but something more complex, like double quotes inside double quotes or spaces
// in the schema name would break the parsing code in the operator.)
if start == '\'' && end == '\'' {
return fmt.Sprintf("%s", val[1:len(val)-1])
} else {
return val
}
}
if (start == '"' && end == '"') || (start == '\'' && end == '\'') {
return val
}
return fmt.Sprintf(`"%s"`, strings.Trim(val, " "))
return fmt.Sprintf(`'%s'`, strings.Trim(val, " "))
}

0 comments on commit 1f2c19f

Please sign in to comment.