Skip to content

Commit dd8bea8

Browse files
committed
SQL/JSON: Avoid initializing unnecessary ON ERROR / ON EMPTY steps
When the ON ERROR / ON EMPTY behavior is to return NULL, returning NULL directly from ExecEvalJsonExprPath() suffices. Therefore, there's no need to create separate steps to check the error/empty flag or those to evaluate the the constant NULL expression. This speeds up common cases because the default ON ERROR / ON EMPTY behavior for JSON_QUERY() and JSON_VALUE() is to return NULL. However, these steps are necessary if the RETURNING type is a domain, as constraints on the domain may need to be checked. Reported-by: Jian He <jian.universality@gmail.com> Author: Jian He <jian.universality@gmail.com> Author: Amit Langote <amitlangote09@gmail.com> Discussion: https://postgr.es/m/CACJufxEo4sUjKCYtda0_qt9tazqqKPmF1cqhW9KBOUeJFqQd2g@mail.gmail.com Backpatch-through: 17
1 parent 87b6c3c commit dd8bea8

File tree

2 files changed

+34
-12
lines changed

2 files changed

+34
-12
lines changed

src/backend/executor/execExpr.c

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4411,9 +4411,11 @@ ExecInitJsonExpr(JsonExpr *jsexpr, ExprState *state,
44114411
List *jumps_return_null = NIL;
44124412
List *jumps_to_end = NIL;
44134413
ListCell *lc;
4414-
ErrorSaveContext *escontext =
4415-
jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR ?
4416-
&jsestate->escontext : NULL;
4414+
ErrorSaveContext *escontext;
4415+
bool returning_domain =
4416+
get_typtype(jsexpr->returning->typid) == TYPTYPE_DOMAIN;
4417+
4418+
Assert(jsexpr->on_error != NULL);
44174419

44184420
jsestate->jsexpr = jsexpr;
44194421

@@ -4491,6 +4493,9 @@ ExecInitJsonExpr(JsonExpr *jsexpr, ExprState *state,
44914493
scratch->d.constval.isnull = true;
44924494
ExprEvalPushStep(state, scratch);
44934495

4496+
escontext = jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR ?
4497+
&jsestate->escontext : NULL;
4498+
44944499
/*
44954500
* To handle coercion errors softly, use the following ErrorSaveContext to
44964501
* pass to ExecInitExprRec() when initializing the coercion expressions
@@ -4562,9 +4567,18 @@ ExecInitJsonExpr(JsonExpr *jsexpr, ExprState *state,
45624567
* Step to check jsestate->error and return the ON ERROR expression if
45634568
* there is one. This handles both the errors that occur during jsonpath
45644569
* evaluation in EEOP_JSONEXPR_PATH and subsequent coercion evaluation.
4570+
*
4571+
* Speed up common cases by avoiding extra steps for a NULL-valued ON
4572+
* ERROR expression unless RETURNING a domain type, where constraints must
4573+
* be checked. ExecEvalJsonExprPath() already returns NULL on error,
4574+
* making additional steps unnecessary in typical scenarios. Note that the
4575+
* default ON ERROR behavior for JSON_VALUE() and JSON_QUERY() is to
4576+
* return NULL.
45654577
*/
4566-
if (jsexpr->on_error &&
4567-
jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR)
4578+
if (jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR &&
4579+
(!(IsA(jsexpr->on_error->expr, Const) &&
4580+
((Const *) jsexpr->on_error->expr)->constisnull) ||
4581+
returning_domain))
45684582
{
45694583
ErrorSaveContext *saved_escontext;
45704584

@@ -4619,9 +4633,15 @@ ExecInitJsonExpr(JsonExpr *jsexpr, ExprState *state,
46194633
/*
46204634
* Step to check jsestate->empty and return the ON EMPTY expression if
46214635
* there is one.
4636+
*
4637+
* See the comment above for details on the optimization for NULL-valued
4638+
* expressions.
46224639
*/
46234640
if (jsexpr->on_empty != NULL &&
4624-
jsexpr->on_empty->btype != JSON_BEHAVIOR_ERROR)
4641+
jsexpr->on_empty->btype != JSON_BEHAVIOR_ERROR &&
4642+
(!(IsA(jsexpr->on_empty->expr, Const) &&
4643+
((Const *) jsexpr->on_empty->expr)->constisnull) ||
4644+
returning_domain))
46254645
{
46264646
ErrorSaveContext *saved_escontext;
46274647

src/backend/executor/execExprInterp.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4550,8 +4550,8 @@ ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op,
45504550
/* Set up to catch coercion errors of the ON EMPTY value. */
45514551
jsestate->escontext.error_occurred = false;
45524552
jsestate->escontext.details_wanted = true;
4553-
Assert(jsestate->jump_empty >= 0);
4554-
return jsestate->jump_empty;
4553+
/* Jump to end if the ON EMPTY behavior is to return NULL */
4554+
return jsestate->jump_empty >= 0 ? jsestate->jump_empty : jsestate->jump_end;
45554555
}
45564556
}
45574557
else if (jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR)
@@ -4560,8 +4560,9 @@ ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op,
45604560
/* Set up to catch coercion errors of the ON ERROR value. */
45614561
jsestate->escontext.error_occurred = false;
45624562
jsestate->escontext.details_wanted = true;
4563-
Assert(!throw_error && jsestate->jump_error >= 0);
4564-
return jsestate->jump_error;
4563+
Assert(!throw_error);
4564+
/* Jump to end if the ON ERROR behavior is to return NULL */
4565+
return jsestate->jump_error >= 0 ? jsestate->jump_error : jsestate->jump_end;
45654566
}
45664567

45674568
if (jsexpr->column_name)
@@ -4581,14 +4582,15 @@ ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op,
45814582
*/
45824583
if (error)
45834584
{
4584-
Assert(!throw_error && jsestate->jump_error >= 0);
4585+
Assert(!throw_error);
45854586
*op->resvalue = (Datum) 0;
45864587
*op->resnull = true;
45874588
jsestate->error.value = BoolGetDatum(true);
45884589
/* Set up to catch coercion errors of the ON ERROR value. */
45894590
jsestate->escontext.error_occurred = false;
45904591
jsestate->escontext.details_wanted = true;
4591-
return jsestate->jump_error;
4592+
/* Jump to end if the ON ERROR behavior is to return NULL */
4593+
return jsestate->jump_error >= 0 ? jsestate->jump_error : jsestate->jump_end;
45924594
}
45934595

45944596
return jump_eval_coercion >= 0 ? jump_eval_coercion : jsestate->jump_end;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy