Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

builtins: use IdentityReturnType when possible #70469

Merged
merged 2 commits into from
Sep 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
8 changes: 4 additions & 4 deletions pkg/sql/sem/builtins/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -3434,7 +3434,7 @@ value if you rely on the HLC for accuracy.`,
"array_append": setProps(arrayPropsNullableArgs(), arrayBuiltin(func(typ *types.T) tree.Overload {
return tree.Overload{
Types: tree.ArgTypes{{"array", types.MakeArray(typ)}, {"elem", typ}},
ReturnType: tree.FixedReturnType(types.MakeArray(typ)),
ReturnType: tree.IdentityReturnType(0),
Fn: func(_ *tree.EvalContext, args tree.Datums) (tree.Datum, error) {
return tree.AppendToMaybeNullArray(typ, args[0], args[1])
},
Expand All @@ -3446,7 +3446,7 @@ value if you rely on the HLC for accuracy.`,
"array_prepend": setProps(arrayPropsNullableArgs(), arrayBuiltin(func(typ *types.T) tree.Overload {
return tree.Overload{
Types: tree.ArgTypes{{"elem", typ}, {"array", types.MakeArray(typ)}},
ReturnType: tree.FixedReturnType(types.MakeArray(typ)),
ReturnType: tree.IdentityReturnType(1),
Fn: func(_ *tree.EvalContext, args tree.Datums) (tree.Datum, error) {
return tree.PrependToMaybeNullArray(typ, args[0], args[1])
},
Expand All @@ -3470,7 +3470,7 @@ value if you rely on the HLC for accuracy.`,
"array_remove": setProps(arrayPropsNullableArgs(), arrayBuiltin(func(typ *types.T) tree.Overload {
return tree.Overload{
Types: tree.ArgTypes{{"array", types.MakeArray(typ)}, {"elem", typ}},
ReturnType: tree.FixedReturnType(types.MakeArray(typ)),
ReturnType: tree.IdentityReturnType(0),
Fn: func(ctx *tree.EvalContext, args tree.Datums) (tree.Datum, error) {
if args[0] == tree.DNull {
return tree.DNull, nil
Expand All @@ -3493,7 +3493,7 @@ value if you rely on the HLC for accuracy.`,
"array_replace": setProps(arrayPropsNullableArgs(), arrayBuiltin(func(typ *types.T) tree.Overload {
return tree.Overload{
Types: tree.ArgTypes{{"array", types.MakeArray(typ)}, {"toreplace", typ}, {"replacewith", typ}},
ReturnType: tree.FixedReturnType(types.MakeArray(typ)),
ReturnType: tree.IdentityReturnType(0),
Fn: func(ctx *tree.EvalContext, args tree.Datums) (tree.Datum, error) {
if args[0] == tree.DNull {
return tree.DNull, nil
Expand Down
19 changes: 11 additions & 8 deletions 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 All @@ -1261,13 +1263,8 @@ func makeJSONPopulateImpl(gen tree.GeneratorWithExprsFactory, info string) tree.
// the default values of each field will be NULL.
// The second argument can also be null, in which case the first argument
// is returned as-is.
Types: tree.ArgTypes{{"base", types.Any}, {"from_json", types.Jsonb}},
ReturnType: func(args []tree.TypedExpr) *types.T {
if len(args) != 2 {
return tree.UnknownReturnType
}
return args[0].ResolvedType()
},
Types: tree.ArgTypes{{"base", types.Any}, {"from_json", types.Jsonb}},
ReturnType: tree.IdentityReturnType(0),
GeneratorWithExprs: gen,
Info: info,
Volatility: tree.VolatilityStable,
Expand Down Expand Up @@ -1311,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