diff --git a/pgtype/hstore.go b/pgtype/hstore.go index 52fe23060..f3ae78380 100644 --- a/pgtype/hstore.go +++ b/pgtype/hstore.go @@ -272,9 +272,15 @@ func (c HstoreCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) ( } func quoteHstoreElementIfNeeded(src string) string { - if src == "" || (len(src) == 4 && strings.ToLower(src) == "null") || strings.ContainsAny(src, ` {},"\=>`) { + // Double-quote keys and values that include whitespace, commas, =s or >s. To include a double + // quote or a backslash in a key or value, escape it with a backslash. + // From: https://www.postgresql.org/docs/current/hstore.html + // whitespace appears to be defined as the isspace() C function: \t\n\v\f\r\n and space + const quoteRequiredChars = `,"\=> ` + "\t\n\v\f\r" + if src == "" || (len(src) == 4 && strings.ToLower(src) == "null") || strings.ContainsAny(src, quoteRequiredChars) { return quoteArrayElement(src) } + return src } diff --git a/pgtype/hstore_test.go b/pgtype/hstore_test.go index 8ad5884a8..3d3e722e1 100644 --- a/pgtype/hstore_test.go +++ b/pgtype/hstore_test.go @@ -122,6 +122,12 @@ func TestHstoreCodec(t *testing.T) { `=>`, ` `, `\ / / \\ => " ' " '`, + "line1\nline2", + "tab\tafter", + "vtab\vafter", + "form\\ffeed", + "carriage\rreturn", + "curly{}braces", } for _, s := range specialStrings { // Special key values