On Wed, 17 Apr 2024 at 17:17, Andy Fan <zhihuifan1...@163.com> wrote:
> rebase to the latest master again.

There's a lot of complexity in the v18 patch that I don't understand
the need for.

I imagined you'd the patch should create a SupportRequestSimplify
support function for jsonb_numeric() that checks if the input
expression is an OpExpr with funcid of jsonb_object_field().  All you
do then is ditch the cast and change the OpExpr to call a new function
named jsonb_object_field_numeric() which returns the val.numeric
directly.  Likely the same support function could handle jsonb casts
to other types too, in which case you'd just call some other function,
e.g jsonb_object_field_timestamp() or jsonb_object_field_boolean().

Can you explain why the additional complexity is needed over what's in
the attached patch?

David
diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c
index 928552d551..7b60b36189 100644
--- a/src/backend/utils/adt/jsonb.c
+++ b/src/backend/utils/adt/jsonb.c
@@ -18,7 +18,9 @@
 #include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
+#include "nodes/supportnodes.h"
 #include "utils/builtins.h"
+#include "utils/fmgroids.h"
 #include "utils/json.h"
 #include "utils/jsonb.h"
 #include "utils/jsonfuncs.h"
@@ -2069,6 +2071,64 @@ jsonb_numeric(PG_FUNCTION_ARGS)
        PG_RETURN_NUMERIC(retValue);
 }
 
+Datum
+jsonb_object_field_numeric(PG_FUNCTION_ARGS)
+{
+       Jsonb *jb = PG_GETARG_JSONB_P(0);
+       text *key = PG_GETARG_TEXT_PP(1);
+       JsonbValue *v;
+       JsonbValue vbuf;
+
+       if (!JB_ROOT_IS_OBJECT(jb))
+               PG_RETURN_NULL();
+
+       v = getKeyJsonValueFromContainer(&jb->root,
+                                                                        
VARDATA_ANY(key),
+                                                                        
VARSIZE_ANY_EXHDR(key),
+                                                                        &vbuf);
+
+       if (v != NULL)
+       {
+               if (v->type == jbvNumeric)
+                       PG_RETURN_NUMERIC(v->val.numeric);
+
+               cannotCastJsonbValue(v->type, "numeric");
+       }
+
+       PG_RETURN_NULL();
+}
+
+Datum
+jsonb_numeric_support(PG_FUNCTION_ARGS)
+{
+       Node       *rawreq = (Node *) PG_GETARG_POINTER(0);
+       Node *ret = NULL;
+
+       if (IsA(rawreq, SupportRequestSimplify))
+       {
+               SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
+               FuncExpr *func = req->fcall;
+               OpExpr *opexpr = list_nth(func->args, 0);
+
+               /*
+                * Transform jsonb_object_field calls that directly cast to 
numeric
+                * into a direct call to jsonb_object_field_numeric.  This 
allows us
+                * to directly access the numeric field and return it directly 
thus
+                * saving casting from jsonb to numeric.
+                */
+               if (IsA(opexpr, OpExpr) && opexpr->opfuncid == 
F_JSONB_OBJECT_FIELD)
+               {
+                       opexpr->opfuncid = F_JSONB_OBJECT_FIELD_NUMERIC;
+                       PG_RETURN_POINTER(opexpr);
+               }
+
+               PG_RETURN_POINTER(ret);
+       }
+
+       PG_RETURN_POINTER(ret);
+}
+
+
 Datum
 jsonb_int2(PG_FUNCTION_ARGS)
 {
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index ff5436acac..10aed0b0b1 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -4642,8 +4642,12 @@
   proname => 'bool', prorettype => 'bool', proargtypes => 'jsonb',
   prosrc => 'jsonb_bool' },
 { oid => '3449', descr => 'convert jsonb to numeric',
-  proname => 'numeric', prorettype => 'numeric', proargtypes => 'jsonb',
+  proname => 'numeric', prosupport => 'jsonb_numeric_support',
+  prorettype => 'numeric', proargtypes => 'jsonb',
   prosrc => 'jsonb_numeric' },
+{ oid => '8394', descr => 'planner support for jsonb casting support',
+  proname => 'jsonb_numeric_support',  prorettype => 'internal',
+  proargtypes => 'internal', prosrc => 'jsonb_numeric_support' },
 { oid => '3450', descr => 'convert jsonb to int2',
   proname => 'int2', prorettype => 'int2', proargtypes => 'jsonb',
   prosrc => 'jsonb_int2' },
@@ -10083,6 +10087,10 @@
   proargtypes => 'jsonb _text', proallargtypes => '{jsonb,_text}',
   proargmodes => '{i,v}', proargnames => '{from_json,path_elems}',
   prosrc => 'jsonb_extract_path' },
+{ oid => '8395',
+  proname => 'jsonb_object_field_numeric', prorettype => 'numeric',
+  proargtypes => 'jsonb text', proargnames => '{from_json, field_name}',
+  prosrc => 'jsonb_object_field_numeric' },
 { oid => '3940', descr => 'get value from jsonb as text with path elements',
   proname => 'jsonb_extract_path_text', provariadic => 'text',
   prorettype => 'text', proargtypes => 'jsonb _text',

Reply via email to