Skip to content

Commit

Permalink
builtins: check type for json{b}_populate_reccord{set} argument
Browse files Browse the repository at this point in the history
The function accepts types.Any, but at execution time it actually
requires a tuple type. This is now checked. The behavior of checking at
execution time matches PostgreSQL.

Release note: None
  • Loading branch information
rafiss committed Sep 23, 2021
1 parent 03641de commit 23f4ee3
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 4 deletions.
19 changes: 17 additions & 2 deletions pkg/sql/logictest/testdata/logic_test/json
Original file line number Diff line number Diff line change
Expand Up @@ -899,12 +899,27 @@ d
query error could not parse \"foo\" as type int
SELECT json_populate_record(((3,) AS a), '{"a": "foo"}')

query error anonymous records cannot be used with json_populate_record
query error anonymous records cannot be used with json{b}_populate_record{set}
SELECT * FROM json_populate_record((1,2,3,4), '{"a": 3, "c": 10, "d": 11.001}')

query error anonymous records cannot be used with json_populate_record
query error anonymous records cannot be used with json{b}_populate_record{set}
SELECT * FROM json_populate_record(NULL, '{"a": 3, "c": 10, "d": 11.001}')

query error first argument of json{b}_populate_record{set} must be a record type
SELECT * FROM json_populate_record(1, '{"a": 3, "c": 10, "d": 11.001}')

query error first argument of json{b}_populate_record{set} must be a record type
SELECT * FROM json_populate_record(NULL::INT, '{"a": 3, "c": 10, "d": 11.001}')

query error anonymous records cannot be used with json{b}_populate_record{set}
SELECT * FROM json_populate_record(NULL::record, '{"a": 3, "c": 10, "d": 11.001}')

query error anonymous records cannot be used with json{b}_populate_record{set}
SELECT * FROM json_populate_recordset(NULL, '[{"a": 3, "c": 10, "d": 11.001}, {}]')

query error first argument of json{b}_populate_record{set} must be a record type
SELECT * FROM json_populate_recordset(NULL::INT, '[{"a": 3, "c": 10, "d": 11.001}, {}]')

query I
SELECT * FROM json_populate_record(((3,) AS a), NULL)
----
Expand Down
10 changes: 9 additions & 1 deletion pkg/sql/sem/builtins/generator_builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -1251,7 +1251,9 @@ func makeJSONPopulateImpl(gen tree.GeneratorWithExprsFactory, info string) tree.
// The json{,b}_populate_record{,set} builtins all have a 2 argument
// structure. The first argument is an arbitrary tuple type, which is used
// to set the columns of the output when the builtin is used as a FROM
// source, or used as-is when it's used as an ordinary projection.
// source, or used as-is when it's used as an ordinary projection. To match
// PostgreSQL, the argument actually is types.Any, and its tuple-ness is
// checked at execution time.
// The second argument is a JSON object or array of objects. The builtin
// transforms the JSON in the second argument into the tuple in the first
// argument, field by field, casting fields in key "k" to the type in the
Expand Down Expand Up @@ -1306,6 +1308,12 @@ func jsonPopulateRecordEvalArgs(
}
}
tupleType := args[0].(tree.TypedExpr).ResolvedType()
if tupleType.Family() != types.TupleFamily && tupleType.Family() != types.UnknownFamily {
return nil, nil, pgerror.New(
pgcode.DatatypeMismatch,
"first argument of json{b}_populate_record{set} must be a record type",
)
}
var defaultElems tree.Datums
if evalled[0] == tree.DNull {
defaultElems = make(tree.Datums, len(tupleType.TupleLabels()))
Expand Down
5 changes: 4 additions & 1 deletion pkg/sql/sem/tree/casts.go
Original file line number Diff line number Diff line change
Expand Up @@ -1498,7 +1498,10 @@ func PopulateRecordWithJSON(
tupleTypes := desiredType.TupleContents()
labels := desiredType.TupleLabels()
if labels == nil {
return pgerror.Newf(pgcode.InvalidParameterValue, "anonymous records cannot be used with json_populate_record")
return pgerror.Newf(
pgcode.InvalidParameterValue,
"anonymous records cannot be used with json{b}_populate_record{set}",
)
}
for i := range tupleTypes {
val, err := j.FetchValKey(labels[i])
Expand Down

0 comments on commit 23f4ee3

Please sign in to comment.