From 5f2d070d3cc47f7461d1474a5fe18e905243b31b Mon Sep 17 00:00:00 2001 From: jian he Date: Mon, 1 Jul 2024 14:26:09 +0800 Subject: [PATCH v1 1/1] hanlde types that have type modifier for json on error, on empty --- src/backend/parser/parse_expr.c | 83 ++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 18 deletions(-) diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 560b3606..15cdea1c 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -3582,7 +3582,7 @@ coerceJsonFuncExpr(ParseState *pstate, Node *expr, Node *res; int location; Oid exprtype = exprType(expr); - int32 baseTypmod = returning->typmod; + int32 baseTypmod = -1; /* if output type is not specified or equals to function type, return */ if (!OidIsValid(returning->typid) || returning->typid == exprtype) @@ -3615,8 +3615,10 @@ coerceJsonFuncExpr(ParseState *pstate, Node *expr, * For domains, consider the base type's typmod to decide whether to setup * an implicit or explicit cast. */ - if (get_typtype(returning->typid) == TYPTYPE_DOMAIN) + if (returning->typmod < 0) (void) getBaseTypeAndTypmod(returning->typid, &baseTypmod); + else + baseTypmod = returning->typmod; /* try to coerce expression to the output type */ res = coerce_to_target_type(pstate, expr, exprtype, @@ -3649,7 +3651,7 @@ makeJsonConstructorExpr(ParseState *pstate, JsonConstructorType type, JsonConstructorExpr *jsctor = makeNode(JsonConstructorExpr); Node *placeholder; Node *coercion; - int32 baseTypmod = returning->typmod; + int32 baseTypmod = -1; jsctor->args = args; jsctor->func = fexpr; @@ -3693,8 +3695,10 @@ makeJsonConstructorExpr(ParseState *pstate, JsonConstructorType type, * there are no implicit casts from json(b) to such types. For domains, * the base type's typmod will be considered, so do so here too. */ - if (get_typtype(returning->typid) == TYPTYPE_DOMAIN) + if (returning->typmod < 0) (void) getBaseTypeAndTypmod(returning->typid, &baseTypmod); + else + baseTypmod = returning->typmod; if (baseTypmod > 0) placeholder = coerce_to_specific_type(pstate, placeholder, TEXTOID, "JSON_CONSTRUCTOR()"); @@ -4718,22 +4722,65 @@ transformJsonBehavior(ParseState *pstate, JsonBehavior *behavior, coerce_at_runtime = true; else { - int32 baseTypmod = returning->typmod; - - if (get_typtype(returning->typid) == TYPTYPE_DOMAIN) + int32 baseTypmod = -1; + char typcategory; + bool typispreferred; + get_type_category_preferred(returning->typid, &typcategory, &typispreferred); + if (returning->typmod < 0) (void) getBaseTypeAndTypmod(returning->typid, &baseTypmod); + else + baseTypmod = returning->typmod; - if (baseTypmod > 0) - expr = coerce_to_specific_type(pstate, expr, TEXTOID, - "JSON_FUNCTION()"); - coerced_expr = - coerce_to_target_type(pstate, expr, exprType(expr), - returning->typid, baseTypmod, - baseTypmod > 0 ? COERCION_IMPLICIT : - COERCION_EXPLICIT, - baseTypmod > 0 ? COERCE_IMPLICIT_CAST : - COERCE_EXPLICIT_CAST, - exprLocation((Node *) behavior)); + if (typcategory == TYPCATEGORY_STRING) + { + if (baseTypmod > 0) + expr = coerce_to_specific_type(pstate, expr, TEXTOID, + "JSON_FUNCTION()"); + coerced_expr = + coerce_to_target_type(pstate, expr, exprType(expr), + returning->typid, baseTypmod, + baseTypmod > 0 ? COERCION_IMPLICIT : + COERCION_EXPLICIT, + baseTypmod > 0 ? COERCE_IMPLICIT_CAST : + COERCE_EXPLICIT_CAST, + exprLocation((Node *) behavior)); + } + else if (typcategory == TYPCATEGORY_BITSTRING) + { + CoercionContext ccontext; + CoercionForm cformat; + + /* + * pg_cast don't have bit & text entry, so in function can_coerce_type + * cannot implilcit cast to text then cast to varbit. + * but we can unknown cast to bit via implilcit cast. + * select '21'::text::bit(2); --fail + * select 21::int4::bit(2); --ok + * so DEFAULT 21 ON ERROR, DEFAULT 11 ON ERROR should be fine; + */ + if(baseTypmod > 0 && ((exprType(expr) != INT4OID && exprType(expr) != INT8OID))) + { + ccontext = COERCION_IMPLICIT; + cformat = COERCE_IMPLICIT_CAST; + } + else + { + ccontext = COERCION_EXPLICIT; + cformat = COERCE_EXPLICIT_CAST; + } + coerced_expr = + coerce_to_target_type(pstate, expr, exprType(expr), + returning->typid, returning->typmod, + ccontext, + cformat, + exprLocation((Node *) behavior)); + } + else + coerced_expr = + coerce_to_target_type(pstate, expr, exprType(expr), + returning->typid, returning->typmod, + COERCION_EXPLICIT, COERCE_EXPLICIT_CAST, + exprLocation((Node *) behavior)); } if (coerced_expr == NULL) -- 2.34.1