From 6b2f5071f7f237bd0354394eb2fc1bdc0fde1b39 Mon Sep 17 00:00:00 2001 From: Oleksii Kliukin Date: Wed, 8 Nov 2017 15:38:43 +0100 Subject: [PATCH] Special case for search_path in user options. - 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 --- pkg/util/config/config_test.go | 9 ++++----- pkg/util/config/util.go | 12 ++++++------ pkg/util/users/users.go | 27 +++++++++++++++++++++------ 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/pkg/util/config/config_test.go b/pkg/util/config/config_test.go index f6e2c374c..d5d5730c5 100644 --- a/pkg/util/config/config_test.go +++ b/pkg/util/config/config_test.go @@ -1,13 +1,13 @@ package config import ( - "testing" - "reflect" "fmt" + "reflect" + "testing" ) var getMapPairsFromStringTest = []struct { - in string + in string expected []string err error }{ @@ -15,7 +15,7 @@ var getMapPairsFromStringTest = []struct { {`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) { @@ -29,4 +29,3 @@ func TestGetMapPairsFromString(t *testing.T) { } } } - diff --git a/pkg/util/config/util.go b/pkg/util/config/util.go index e07001381..05a956c3e 100644 --- a/pkg/util/config/util.go +++ b/pkg/util/config/util.go @@ -169,10 +169,10 @@ func processField(value string, field reflect.Value) error { return nil } - type parserState int + const ( - Plain parserState = iota + Plain parserState = iota DoubleQuoted SingleQuoted ) @@ -180,12 +180,12 @@ const ( // 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 @@ -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")) diff --git a/pkg/util/users/users.go b/pkg/util/users/users.go index f4e41e8e8..1f83706fe 100644 --- a/pkg/util/users/users.go +++ b/pkg/util/users/users.go @@ -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 } @@ -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, " ")) }