Skip to content

Commit

Permalink
tree: fix parsing of arrays of spatial types
Browse files Browse the repository at this point in the history
Arrays with spatial types are different than other arrays -- they always
use ':' as a delimiter instead of ','.

Release note (bug fix): Queries that perform a cast from the string
representation of an array containing geometry or geography types to a
SQL array type will now succeed.
  • Loading branch information
rafiss committed Jan 8, 2025
1 parent 3770f88 commit f6bfee1
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 10 deletions.
16 changes: 16 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/geospatial
Original file line number Diff line number Diff line change
Expand Up @@ -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
22 changes: 12 additions & 10 deletions pkg/sql/sem/tree/parse_array.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand All @@ -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()
Expand Down

0 comments on commit f6bfee1

Please sign in to comment.