diff --git a/pkg/sql/logictest/testdata/logic_test/geospatial b/pkg/sql/logictest/testdata/logic_test/geospatial index 405461e790d4..77815ee0c769 100644 --- a/pkg/sql/logictest/testdata/logic_test/geospatial +++ b/pkg/sql/logictest/testdata/logic_test/geospatial @@ -6333,3 +6333,19 @@ SELECT st_asgeojson(tbl.*, 'g', 4)::JSONB->'geometry'->'coordinates' FROM (VALUES ('SRID=4326;POINT (-123.45678901234 12.3456789012)'::GEOMETRY)) tbl(g); ---- [-123.4568, 12.3457] + +# Regression test for parsing arrays of spatial types. Arrays for these types +# are special since they use ':' as a delimiter instead of ','. +subtest array_delimiter + +query T +SELECT '{0101000020e6100000cdcccccccc4c1b40cdcccccccc8c4740:0101000020e6100000333333333333fd3fcdcccccccc0c4640}'::geometry[]; +---- +{0101000020E6100000CDCCCCCCCC4C1B40CDCCCCCCCC8C4740:0101000020E6100000333333333333FD3FCDCCCCCCCC0C4640} + +query T +SELECT '{0101000020e6100000cdcccccccc4c1b40cdcccccccc8c4740:0101000020e6100000333333333333fd3fcdcccccccc0c4640}'::geography[]; +---- +{0101000020E6100000CDCCCCCCCC4C1B40CDCCCCCCCC8C4740:0101000020E6100000333333333333FD3FCDCCCCCCCC0C4640} + +subtest end diff --git a/pkg/sql/sem/tree/parse_array.go b/pkg/sql/sem/tree/parse_array.go index 09840addaeaa..32b50563bff5 100644 --- a/pkg/sql/sem/tree/parse_array.go +++ b/pkg/sql/sem/tree/parse_array.go @@ -26,14 +26,6 @@ func isQuoteChar(ch byte) bool { return ch == '"' } -func isControlChar(ch byte) bool { - return ch == '{' || ch == '}' || ch == ',' || ch == '"' -} - -func isElementChar(r rune) bool { - return r != '{' && r != '}' && r != ',' -} - // isSpaceInParseArray returns true if the rune is a space. To match Postgres, // 0x85 and 0xA0 are not treated as whitespace. func isSpaceInParseArray(r rune) bool { @@ -81,6 +73,16 @@ func trimSpaceInParseArray(s string) string { return s[start:stop] } +func (p *parseState) isControlChar(ch byte) bool { + delim := p.t.Delimiter()[0] + return ch == '{' || ch == '}' || ch == delim || ch == '"' +} + +func (p *parseState) isElementChar(r rune) bool { + delim, _ := utf8.DecodeRuneInString(p.t.Delimiter()) + return r != '{' && r != '}' && r != delim +} + // gobbleString advances the parser for the remainder of the current string // until it sees a non-escaped termination character, as specified by // isTerminatingChar, returning the resulting string, not including the @@ -145,7 +147,7 @@ func (p *parseState) parseQuotedString() (string, error) { } func (p *parseState) parseUnquotedString() (string, error) { - out, err := p.gobbleString(isControlChar) + out, err := p.gobbleString(p.isControlChar) if err != nil { return "", err } @@ -167,7 +169,7 @@ func (p *parseState) parseElement() error { } p.advance() default: - if !isElementChar(r) { + if !p.isElementChar(r) { return malformedError } next, err = p.parseUnquotedString()