Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1qqsJj-001UB9-1k for pgsql-hackers@arkaria.postgresql.org; Thu, 12 Oct 2023 09:49:19 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1qqsJg-005M7Z-5p for pgsql-hackers@arkaria.postgresql.org; Thu, 12 Oct 2023 09:49:16 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1qqsJf-005M7Q-Pq for pgsql-hackers@lists.postgresql.org; Thu, 12 Oct 2023 09:49:16 +0000 Received: from smtp.outgoing.loopia.se ([93.188.3.37]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1qqsJX-0008y8-SP for pgsql-hackers@lists.postgresql.org; Thu, 12 Oct 2023 09:49:15 +0000 Received: from s807.loopia.se (localhost [127.0.0.1]) by s807.loopia.se (Postfix) with ESMTP id 866E32FB6238 for ; Thu, 12 Oct 2023 11:48:36 +0200 (CEST) Received: from s899.loopia.se (unknown [172.22.191.5]) by s807.loopia.se (Postfix) with ESMTP id 76DC72E28A1B; Thu, 12 Oct 2023 11:48:36 +0200 (CEST) Received: from s471.loopia.se (unknown [172.22.191.5]) by s899.loopia.se (Postfix) with ESMTP id 750D42C8BA72; Thu, 12 Oct 2023 11:48:36 +0200 (CEST) X-Virus-Scanned: amavisd-new at amavis.loopia.se X-Spam-Flag: NO X-Spam-Score: -1 X-Spam-Level: X-Spam-Status: No, score=-1 tagged_above=-999 required=6.2 tests=[ALL_TRUSTED=-1] autolearn=disabled Received: from s980.loopia.se ([172.22.191.5]) by s471.loopia.se (s471.loopia.se [172.22.190.35]) (amavisd-new, port 10024) with UTF8LMTP id SGKtSl1XhkOD; Thu, 12 Oct 2023 11:48:36 +0200 (CEST) X-Loopia-Auth: user X-Loopia-User: daniel@yesql.se X-Loopia-Originating-IP: 89.255.232.193 Received: from smtpclient.apple (customer-89-255-232-193.stosn.net [89.255.232.193]) (Authenticated sender: daniel@yesql.se) by s980.loopia.se (Postfix) with ESMTPSA id 0F3A52201656; Thu, 12 Oct 2023 11:48:36 +0200 (CEST) From: Daniel Gustafsson Content-Type: multipart/mixed; boundary="Apple-Mail=_8699750D-6126-4B55-8029-AEB48AF48DF0" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3696.120.41.1.3\)) Subject: Special-case executor expression steps for common combinations Message-Id: <415721CE-7D2E-4B74-B5D9-1950083BA03E@yesql.se> Date: Thu, 12 Oct 2023 11:48:35 +0200 To: PostgreSQL Hackers , Andres Freund X-Mailer: Apple Mail (2.3696.120.41.1.3) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_8699750D-6126-4B55-8029-AEB48AF48DF0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii The attached patch adds special-case expression steps for common sets of = steps in the executor to shave a few cycles off during execution, and make the = JIT generated code simpler. * Adds EEOP_FUNCEXPR_STRICT_1 and EEOP_FUNCEXPR_STRICT_2 for function = calls of strict functions with 1 or 2 arguments (EEOP_FUNCEXPR_STRICT remains = used for > 2 arguments). * Adds EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1 which is a special case for = the common case of one arg aggs. * Replace EEOP_DONE with EEOP_DONE_RETURN and EEOP_DONE_NO_RETURN to be = able to skip extra setup for steps which are only interested in the side = effects. Stressing the EEOP_FUNCEXPR_STRICT_* steps specifically shows a 1.5% improvement and pgbench over the branch shows a ~1% improvement in TPS = (both measured over 6 runs with outliers removed). EEOP_FUNCEXPR_STRICT_* (10M iterations): master : (7503.317, 7553.691, 7634.524)=20 patched : (7422.756, 7455.120, 7492.393) pgbench: master : (3653.83, 3792.97, 3863.70) patched : (3743.04, 3830.02, 3869.80) This patch was extracted from a larger body of work from Andres [0] = aiming at providing the necessary executor infrastructure for making JIT = expression caching possible. This patch, and more which are to be submitted, is = however separate in the sense that it is not part of the infrastructure, it's an improvements on its own. Thoughts? -- Daniel Gustafsson [0]: = https://postgr.es/m/20191023163849.sosqbfs5yenocez3@alap3.anarazel.de --Apple-Mail=_8699750D-6126-4B55-8029-AEB48AF48DF0 Content-Disposition: attachment; filename=v1-0001-Add-fast-path-expression-steps-for-common-combina.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v1-0001-Add-fast-path-expression-steps-for-common-combina.patch" Content-Transfer-Encoding: quoted-printable =46rom=200935adcda7f9bc62174204f3decb9283b93cfd5a=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Daniel=20Gustafsson=20= =0ADate:=20Thu,=2012=20Oct=202023=2011:33:27=20= +0200=0ASubject:=20[PATCH=20v1]=20Add=20fast-path=20expression=20steps=20= for=20common=20combinations=0A=0AThis=20adds=20special-case=20expression=20= steps=20for=20common=20sets=20of=20steps=0Ain=20the=20executor=20in=20= order=20to=20optimize=20evaluation.=0A=0A*=20EEOP_FUNCEXPR_STRICT_1=20= and=20EEOP_FUNCEXPR_STRICT_2=20for=20function=0A=20=20calls=20of=20= strict=20functions=20with=20one=20or=20two=20arguments=20(the=20older=0A=20= =20EEOP_FUNCEXPR_STRICT=20op=20remains=20used=20for=20>=20two=20= arguments).=0A*=20Adds=20EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1=20which=20is=20= a=20special=20case=0A=20=20for=20the=20common=20case=20of=20one=20arg=20= aggs.=0A*=20Replace=20EEOP_DONE=20with=20EEOP_DONE_RETURN=20and=20= EEOP_DONE_NO_RETURN=0A=20=20to=20be=20able=20to=20skip=20extra=20setup=20= for=20steps=20which=20are=20only=20using=0A=20=20the=20side=20effects.=0A= =0AThis=20patch=20was=20extracted=20from=20a=20larger=20body=20of=20work=20= providing=20the=0Anecessary=20executor=20infrastructure=20for=20JIT=20= expression=20caching.=0A=0AAuthor:=20Andres=20Freund=20= =0AReviewed-by:=20Daniel=20Gustafsson=20= =0ADiscussion:=20= https://postgr.es/m/20191023163849.sosqbfs5yenocez3@alap3.anarazel.de=0A= Discussion:=20https://postgr.es/m/TBD=0A---=0A=20= src/backend/executor/README=20=20=20=20=20=20=20=20=20=20=20|=2011=20++-=0A= =20src/backend/executor/execExpr.c=20=20=20=20=20=20=20|=2033=20= ++++++---=0A=20src/backend/executor/execExprInterp.c=20|=2099=20= ++++++++++++++++++++++++---=0A=20src/backend/executor/nodeAgg.c=20=20=20=20= =20=20=20=20|=20=207=20+-=0A=20src/backend/jit/llvm/llvmjit_expr.c=20=20=20= |=2013=20+++-=0A=20src/include/executor/execExpr.h=20=20=20=20=20=20=20|=20= 14=20++--=0A=20src/include/executor/executor.h=20=20=20=20=20=20=20|=20= 52=20+++++++++++++-=0A=207=20files=20changed,=20192=20insertions(+),=20= 37=20deletions(-)=0A=0Adiff=20--git=20a/src/backend/executor/README=20= b/src/backend/executor/README=0Aindex=20642d63be61..54f4782f31=20100644=0A= ---=20a/src/backend/executor/README=0A+++=20= b/src/backend/executor/README=0A@@=20-133,9=20+133,14=20@@=20is=20used=20= by=20the=20function=20evaluation=20step,=20thus=20avoiding=20extra=20= work=20to=20copy=0A=20the=20result=20values=20around.=0A=20=0A=20The=20= last=20entry=20in=20a=20completed=20ExprState->steps=20array=20is=20= always=20an=0A-EEOP_DONE=20step;=20this=20removes=20the=20need=20to=20= test=20for=20end-of-array=20while=0A-iterating.=20=20Also,=20if=20the=20= expression=20contains=20any=20variable=20references=20(to=0A-user=20= columns=20of=20the=20ExprContext's=20INNER,=20OUTER,=20or=20SCAN=20= tuples),=20the=20steps=0A+EEOP_DONE_RETURN=20or=20EEOP_DONE_NO_RETURN=20= step;=20this=20removes=20the=20need=20to=0A+test=20for=20end-of-array=20= while=20iterating.=20The=20former=20is=20used=20when=20the=0A+expression=20= returns=20a=20value=20directly,=20the=20latter=20when=20side-effects=20= of=0A+expression=20initialization=20are=20the=20goal=20(e.g.=20for=20= projection=20or=0A+aggregate=20transition=20value=20computation).=0A+=0A= +Also,=20if=20the=20expression=20contains=20any=20variable=20references=20= (to=20user=0A+columns=20of=20the=20ExprContext's=20INNER,=20OUTER,=20or=20= SCAN=20tuples),=20the=20steps=0A=20array=20begins=20with=20= EEOP_*_FETCHSOME=20steps=20that=20ensure=20that=20the=20relevant=0A=20= tuples=20have=20been=20deconstructed=20to=20make=20the=20required=20= columns=20directly=0A=20available=20(cf.=20slot_getsomeattrs()).=20=20= This=20allows=20individual=20Var-fetching=0Adiff=20--git=20= a/src/backend/executor/execExpr.c=20b/src/backend/executor/execExpr.c=0A= index=202c62b0c9c8..84a9ecec02=20100644=0A---=20= a/src/backend/executor/execExpr.c=0A+++=20= b/src/backend/executor/execExpr.c=0A@@=20-8,7=20+8,7=20@@=0A=20=20*=09= using=20ExecInitExpr()=20et=20al.=20=20This=20converts=20the=20tree=20= into=20a=20flat=20array=0A=20=20*=09of=20ExprEvalSteps,=20which=20may=20= be=20thought=20of=20as=20instructions=20in=20a=20program.=0A=20=20*=09At=20= runtime,=20we'll=20execute=20steps,=20starting=20with=20the=20first,=20= until=20we=20reach=0A-=20*=09an=20EEOP_DONE=20opcode.=0A+=20*=09an=20= EEOP_DONE_{RETURN|NO_RETURN}=20opcode.=0A=20=20*=0A=20=20*=09This=20file=20= contains=20the=20"compilation"=20logic.=20=20It=20is=20independent=20of=20= the=0A=20=20*=09specific=20execution=20technology=20we=20use=20(switch=20= statement,=20computed=20goto,=0A@@=20-147,7=20+147,7=20@@=20= ExecInitExpr(Expr=20*node,=20PlanState=20*parent)=0A=20=09= ExecInitExprRec(node,=20state,=20&state->resvalue,=20&state->resnull);=0A= =20=0A=20=09/*=20Finally,=20append=20a=20DONE=20step=20*/=0A-=09= scratch.opcode=20=3D=20EEOP_DONE;=0A+=09scratch.opcode=20=3D=20= EEOP_DONE_RETURN;=0A=20=09ExprEvalPushStep(state,=20&scratch);=0A=20=0A=20= =09ExecReadyExpr(state);=0A@@=20-184,7=20+184,7=20@@=20= ExecInitExprWithParams(Expr=20*node,=20ParamListInfo=20ext_params)=0A=20=09= ExecInitExprRec(node,=20state,=20&state->resvalue,=20&state->resnull);=0A= =20=0A=20=09/*=20Finally,=20append=20a=20DONE=20step=20*/=0A-=09= scratch.opcode=20=3D=20EEOP_DONE;=0A+=09scratch.opcode=20=3D=20= EEOP_DONE_RETURN;=0A=20=09ExprEvalPushStep(state,=20&scratch);=0A=20=0A=20= =09ExecReadyExpr(state);=0A@@=20-279,7=20+279,7=20@@=20ExecInitQual(List=20= *qual,=20PlanState=20*parent)=0A=20=09=20*=20have=20yielded=20TRUE,=20= and=20since=20its=20result=20is=20stored=20in=20the=20desired=20output=0A= =20=09=20*=20location,=20we're=20done.=0A=20=09=20*/=0A-=09= scratch.opcode=20=3D=20EEOP_DONE;=0A+=09scratch.opcode=20=3D=20= EEOP_DONE_RETURN;=0A=20=09ExprEvalPushStep(state,=20&scratch);=0A=20=0A=20= =09ExecReadyExpr(state);=0A@@=20-474,7=20+474,7=20@@=20= ExecBuildProjectionInfo(List=20*targetList,=0A=20=09=09}=0A=20=09}=0A=20=0A= -=09scratch.opcode=20=3D=20EEOP_DONE;=0A+=09scratch.opcode=20=3D=20= EEOP_DONE_NO_RETURN;=0A=20=09ExprEvalPushStep(state,=20&scratch);=0A=20=0A= =20=09ExecReadyExpr(state);=0A@@=20-713,7=20+713,7=20@@=20= ExecBuildUpdateProjection(List=20*targetList,=0A=20=09=09}=0A=20=09}=0A=20= =0A-=09scratch.opcode=20=3D=20EEOP_DONE;=0A+=09scratch.opcode=20=3D=20= EEOP_DONE_NO_RETURN;=0A=20=09ExprEvalPushStep(state,=20&scratch);=0A=20=0A= =20=09ExecReadyExpr(state);=0A@@=20-1644,7=20+1644,7=20@@=20= ExecInitExprRec(Expr=20*node,=20ExprState=20*state,=0A=20=09=09=09=09= else=0A=20=09=09=09=09{=0A=20=09=09=09=09=09/*=20Not=20trivial,=20so=20= append=20a=20DONE=20step=20*/=0A-=09=09=09=09=09scratch.opcode=20=3D=20= EEOP_DONE;=0A+=09=09=09=09=09scratch.opcode=20=3D=20EEOP_DONE_RETURN;=0A=20= =09=09=09=09=09ExprEvalPushStep(elemstate,=20&scratch);=0A=20=09=09=09=09= =09/*=20and=20ready=20the=20subexpression=20*/=0A=20=09=09=09=09=09= ExecReadyExpr(elemstate);=0A@@=20-2663,7=20+2663,15=20@@=20= ExecInitFunc(ExprEvalStep=20*scratch,=20Expr=20*node,=20List=20*args,=20= Oid=20funcid,=0A=20=09if=20(pgstat_track_functions=20<=3D=20= flinfo->fn_stats)=0A=20=09{=0A=20=09=09if=20(flinfo->fn_strict=20&&=20= nargs=20>=200)=0A-=09=09=09scratch->opcode=20=3D=20EEOP_FUNCEXPR_STRICT;=0A= +=09=09{=0A+=09=09=09/*=20Choose=20nargs=20optimized=20implementation=20= if=20available.=20*/=0A+=09=09=09if=20(nargs=20=3D=3D=201)=0A+=09=09=09=09= scratch->opcode=20=3D=20EEOP_FUNCEXPR_STRICT_1;=0A+=09=09=09else=20if=20= (nargs=20=3D=3D=202)=0A+=09=09=09=09scratch->opcode=20=3D=20= EEOP_FUNCEXPR_STRICT_2;=0A+=09=09=09else=0A+=09=09=09=09scratch->opcode=20= =3D=20EEOP_FUNCEXPR_STRICT;=0A+=09=09}=0A=20=09=09else=0A=20=09=09=09= scratch->opcode=20=3D=20EEOP_FUNCEXPR;=0A=20=09}=0A@@=20-3674,6=20= +3682,8=20@@=20ExecBuildAggTrans(AggState=20*aggstate,=20= AggStatePerPhase=20phase,=0A=20=09=09{=0A=20=09=09=09if=20(strictnulls)=0A= =20=09=09=09=09scratch.opcode=20=3D=20EEOP_AGG_STRICT_INPUT_CHECK_NULLS;=0A= +=09=09=09else=20if=20(strictargs=20&&=20pertrans->numTransInputs=20=3D=3D= =201)=0A+=09=09=09=09scratch.opcode=20=3D=20= EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1;=0A=20=09=09=09else=0A=20=09=09=09=09= scratch.opcode=20=3D=20EEOP_AGG_STRICT_INPUT_CHECK_ARGS;=0A=20=09=09=09= scratch.d.agg_strict_input_check.nulls=20=3D=20strictnulls;=0A@@=20= -3750,6=20+3760,7=20@@=20ExecBuildAggTrans(AggState=20*aggstate,=20= AggStatePerPhase=20phase,=0A=20=09=09=09=09as->d.jump.jumpdone=20=3D=20= state->steps_len;=0A=20=09=09=09}=0A=20=09=09=09else=20if=20(as->opcode=20= =3D=3D=20EEOP_AGG_STRICT_INPUT_CHECK_ARGS=20||=0A+=09=09=09=09=09=20= as->opcode=20=3D=3D=20EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1=20||=0A=20=09=09= =09=09=09=20as->opcode=20=3D=3D=20EEOP_AGG_STRICT_INPUT_CHECK_NULLS)=0A=20= =09=09=09{=0A=20=09=09=09=09Assert(as->d.agg_strict_input_check.jumpnull=20= =3D=3D=20-1);=0A@@=20-3773,7=20+3784,7=20@@=20ExecBuildAggTrans(AggState=20= *aggstate,=20AggStatePerPhase=20phase,=0A=20=0A=20=09scratch.resvalue=20= =3D=20NULL;=0A=20=09scratch.resnull=20=3D=20NULL;=0A-=09scratch.opcode=20= =3D=20EEOP_DONE;=0A+=09scratch.opcode=20=3D=20EEOP_DONE_NO_RETURN;=0A=20=09= ExprEvalPushStep(state,=20&scratch);=0A=20=0A=20=09ExecReadyExpr(state);=0A= @@=20-4037,7=20+4048,7=20@@=20ExecBuildGroupingEqual(TupleDesc=20ldesc,=20= TupleDesc=20rdesc,=0A=20=0A=20=09scratch.resvalue=20=3D=20NULL;=0A=20=09= scratch.resnull=20=3D=20NULL;=0A-=09scratch.opcode=20=3D=20EEOP_DONE;=0A= +=09scratch.opcode=20=3D=20EEOP_DONE_RETURN;=0A=20=09= ExprEvalPushStep(state,=20&scratch);=0A=20=0A=20=09ExecReadyExpr(state);=0A= @@=20-4171,7=20+4182,7=20@@=20ExecBuildParamSetEqual(TupleDesc=20desc,=0A= =20=0A=20=09scratch.resvalue=20=3D=20NULL;=0A=20=09scratch.resnull=20=3D=20= NULL;=0A-=09scratch.opcode=20=3D=20EEOP_DONE;=0A+=09scratch.opcode=20=3D=20= EEOP_DONE_RETURN;=0A=20=09ExprEvalPushStep(state,=20&scratch);=0A=20=0A=20= =09ExecReadyExpr(state);=0Adiff=20--git=20= a/src/backend/executor/execExprInterp.c=20= b/src/backend/executor/execExprInterp.c=0Aindex=2024c2b60c62..265c201897=20= 100644=0A---=20a/src/backend/executor/execExprInterp.c=0A+++=20= b/src/backend/executor/execExprInterp.c=0A@@=20-239,7=20+239,8=20@@=20= ExecReadyInterpretedExpr(ExprState=20*state)=0A=20=0A=20=09/*=20Simple=20= validity=20checks=20on=20expression=20*/=0A=20=09Assert(state->steps_len=20= >=3D=201);=0A-=09Assert(state->steps[state->steps_len=20-=201].opcode=20= =3D=3D=20EEOP_DONE);=0A+=09Assert(state->steps[state->steps_len=20-=20= 1].opcode=20=3D=3D=20EEOP_DONE_RETURN=20||=0A+=09=09=20=20=20= state->steps[state->steps_len=20-=201].opcode=20=3D=3D=20= EEOP_DONE_NO_RETURN);=0A=20=0A=20=09/*=0A=20=09=20*=20Don't=20perform=20= redundant=20initialization.=20This=20is=20unreachable=20in=20current=0A= @@=20-314,7=20+315,9=20@@=20ExecReadyInterpretedExpr(ExprState=20*state)=0A= =20=09=09=09return;=0A=20=09=09}=0A=20=09=09else=20if=20(step0=20=3D=3D=20= EEOP_CASE_TESTVAL=20&&=0A-=09=09=09=09=20step1=20=3D=3D=20= EEOP_FUNCEXPR_STRICT=20&&=0A+=09=09=09=09=20(step1=20=3D=3D=20= EEOP_FUNCEXPR_STRICT=20||=0A+=09=09=09=09=20=20step1=20=3D=3D=20= EEOP_FUNCEXPR_STRICT_1=20||=0A+=09=09=09=09=20=20step1=20=3D=3D=20= EEOP_FUNCEXPR_STRICT_2)=20&&=0A=20=09=09=09=09=20= state->steps[0].d.casetest.value)=0A=20=09=09{=0A=20=09=09=09= state->evalfunc_private=20=3D=20(void=20*)=20ExecJustApplyFuncToCase;=0A= @@=20-405,7=20+408,8=20@@=20ExecInterpExpr(ExprState=20*state,=20= ExprContext=20*econtext,=20bool=20*isnull)=0A=20=09=20*/=0A=20#if=20= defined(EEO_USE_COMPUTED_GOTO)=0A=20=09static=20const=20void=20*const=20= dispatch_table[]=20=3D=20{=0A-=09=09&&CASE_EEOP_DONE,=0A+=09=09= &&CASE_EEOP_DONE_RETURN,=0A+=09=09&&CASE_EEOP_DONE_NO_RETURN,=0A=20=09=09= &&CASE_EEOP_INNER_FETCHSOME,=0A=20=09=09&&CASE_EEOP_OUTER_FETCHSOME,=0A=20= =09=09&&CASE_EEOP_SCAN_FETCHSOME,=0A@@=20-424,6=20+428,8=20@@=20= ExecInterpExpr(ExprState=20*state,=20ExprContext=20*econtext,=20bool=20= *isnull)=0A=20=09=09&&CASE_EEOP_CONST,=0A=20=09=09&&CASE_EEOP_FUNCEXPR,=0A= =20=09=09&&CASE_EEOP_FUNCEXPR_STRICT,=0A+=09=09= &&CASE_EEOP_FUNCEXPR_STRICT_1,=0A+=09=09&&CASE_EEOP_FUNCEXPR_STRICT_2,=0A= =20=09=09&&CASE_EEOP_FUNCEXPR_FUSAGE,=0A=20=09=09= &&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE,=0A=20=09=09= &&CASE_EEOP_BOOL_AND_STEP_FIRST,=0A@@=20-487,6=20+493,7=20@@=20= ExecInterpExpr(ExprState=20*state,=20ExprContext=20*econtext,=20bool=20= *isnull)=0A=20=09=09&&CASE_EEOP_AGG_STRICT_DESERIALIZE,=0A=20=09=09= &&CASE_EEOP_AGG_DESERIALIZE,=0A=20=09=09= &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,=0A+=09=09= &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1,=0A=20=09=09= &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS,=0A=20=09=09= &&CASE_EEOP_AGG_PLAIN_PERGROUP_NULLCHECK,=0A=20=09=09= &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL,=0A@@=20-524,9=20+531,16=20= @@=20ExecInterpExpr(ExprState=20*state,=20ExprContext=20*econtext,=20= bool=20*isnull)=0A=20=0A=20=09EEO_SWITCH()=0A=20=09{=0A-=09=09= EEO_CASE(EEOP_DONE)=0A+=09=09EEO_CASE(EEOP_DONE_RETURN)=0A=20=09=09{=0A-=09= =09=09goto=20out;=0A+=09=09=09*isnull=20=3D=20state->resnull;=0A+=09=09=09= return=20state->resvalue;=0A+=09=09}=0A+=0A+=09=09= EEO_CASE(EEOP_DONE_NO_RETURN)=0A+=09=09{=0A+=09=09=09Assert(isnull=20=3D=3D= =20NULL);=0A+=09=09=09return=200;=0A=20=09=09}=0A=20=0A=20=09=09= EEO_CASE(EEOP_INNER_FETCHSOME)=0A@@=20-738,6=20+752,7=20@@=20= ExecInterpExpr(ExprState=20*state,=20ExprContext=20*econtext,=20bool=20= *isnull)=0A=20=09=09=09EEO_NEXT();=0A=20=09=09}=0A=20=0A+=09=09/*=20= strict=20function=20call=20with=20more=20than=20two=20arguments=20*/=0A=20= =09=09EEO_CASE(EEOP_FUNCEXPR_STRICT)=0A=20=09=09{=0A=20=09=09=09= FunctionCallInfo=20fcinfo=20=3D=20op->d.func.fcinfo_data;=0A@@=20-745,6=20= +760,8=20@@=20ExecInterpExpr(ExprState=20*state,=20ExprContext=20= *econtext,=20bool=20*isnull)=0A=20=09=09=09int=09=09=09nargs=20=3D=20= op->d.func.nargs;=0A=20=09=09=09Datum=09=09d;=0A=20=0A+=09=09=09= Assert(nargs=20>=202);=0A+=0A=20=09=09=09/*=20strict=20function,=20so=20= check=20for=20NULL=20args=20*/=0A=20=09=09=09for=20(int=20argno=20=3D=20= 0;=20argno=20<=20nargs;=20argno++)=0A=20=09=09=09{=0A@@=20-763,6=20= +780,54=20@@=20ExecInterpExpr(ExprState=20*state,=20ExprContext=20= *econtext,=20bool=20*isnull)=0A=20=09=09=09EEO_NEXT();=0A=20=09=09}=0A=20= =0A+=09=09/*=20strict=20function=20call=20with=20one=20argument=20*/=0A+=09= =09EEO_CASE(EEOP_FUNCEXPR_STRICT_1)=0A+=09=09{=0A+=09=09=09= FunctionCallInfo=20fcinfo=20=3D=20op->d.func.fcinfo_data;=0A+=09=09=09= NullableDatum=20*args=20=3D=20fcinfo->args;=0A+=0A+=09=09=09= Assert(op->d.func.nargs=20=3D=3D=201);=0A+=0A+=09=09=09/*=20strict=20= function,=20so=20check=20for=20NULL=20args=20*/=0A+=09=09=09if=20= (args[0].isnull)=0A+=09=09=09=09*op->resnull=20=3D=20true;=0A+=09=09=09= else=0A+=09=09=09{=0A+=09=09=09=09Datum=09=09d;=0A+=0A+=09=09=09=09= fcinfo->isnull=20=3D=20false;=0A+=09=09=09=09d=20=3D=20= op->d.func.fn_addr(fcinfo);=0A+=09=09=09=09*op->resvalue=20=3D=20d;=0A+=09= =09=09=09*op->resnull=20=3D=20fcinfo->isnull;=0A+=09=09=09}=0A+=0A+=09=09= =09EEO_NEXT();=0A+=09=09}=0A+=0A+=09=09/*=20strict=20function=20call=20= with=20two=20arguments=20*/=0A+=09=09EEO_CASE(EEOP_FUNCEXPR_STRICT_2)=0A= +=09=09{=0A+=09=09=09FunctionCallInfo=20fcinfo=20=3D=20= op->d.func.fcinfo_data;=0A+=09=09=09NullableDatum=20*args=20=3D=20= fcinfo->args;=0A+=0A+=09=09=09Assert(op->d.func.nargs=20=3D=3D=202);=0A+=0A= +=09=09=09/*=20strict=20function,=20so=20check=20for=20NULL=20args=20*/=0A= +=09=09=09if=20(args[0].isnull=20||=20args[1].isnull)=0A+=09=09=09=09= *op->resnull=20=3D=20true;=0A+=09=09=09else=0A+=09=09=09{=0A+=09=09=09=09= Datum=09=09d;=0A+=0A+=09=09=09=09fcinfo->isnull=20=3D=20false;=0A+=09=09=09= =09d=20=3D=20op->d.func.fn_addr(fcinfo);=0A+=09=09=09=09*op->resvalue=20= =3D=20d;=0A+=09=09=09=09*op->resnull=20=3D=20fcinfo->isnull;=0A+=09=09=09= }=0A+=0A+=09=09=09EEO_NEXT();=0A+=09=09}=0A+=0A=20=09=09= EEO_CASE(EEOP_FUNCEXPR_FUSAGE)=0A=20=09=09{=0A=20=09=09=09/*=20not=20= common=20enough=20to=20inline=20*/=0A@@=20-1625,11=20+1690,14=20@@=20= ExecInterpExpr(ExprState=20*state,=20ExprContext=20*econtext,=20bool=20= *isnull)=0A=20=09=09=20*=20input=20is=20not=20NULL.=0A=20=09=09=20*/=0A=20= =0A+=09=09/*=20when=20checking=20more=20than=20one=20argument=20*/=0A=20=09= =09EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS)=0A=20=09=09{=0A=20=09=09=09= NullableDatum=20*args=20=3D=20op->d.agg_strict_input_check.args;=0A=20=09= =09=09int=09=09=09nargs=20=3D=20op->d.agg_strict_input_check.nargs;=0A=20= =0A+=09=09=09Assert(nargs=20>=201);=0A+=0A=20=09=09=09for=20(int=20argno=20= =3D=200;=20argno=20<=20nargs;=20argno++)=0A=20=09=09=09{=0A=20=09=09=09=09= if=20(args[argno].isnull)=0A@@=20-1638,6=20+1706,19=20@@=20= ExecInterpExpr(ExprState=20*state,=20ExprContext=20*econtext,=20bool=20= *isnull)=0A=20=09=09=09EEO_NEXT();=0A=20=09=09}=0A=20=0A+=09=09/*=20= special=20case=20for=20just=20one=20argument=20*/=0A+=09=09= EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1)=0A+=09=09{=0A+=09=09=09= NullableDatum=20*args=20=3D=20op->d.agg_strict_input_check.args;=0A+=09=09= =09PG_USED_FOR_ASSERTS_ONLY=20int=20nargs=20=3D=20= op->d.agg_strict_input_check.nargs;=0A+=0A+=09=09=09Assert(nargs=20=3D=3D=20= 1);=0A+=0A+=09=09=09if=20(args[0].isnull)=0A+=09=09=09=09= EEO_JUMP(op->d.agg_strict_input_check.jumpnull);=0A+=09=09=09EEO_NEXT();=0A= +=09=09}=0A+=0A=20=09=09EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_NULLS)=0A=20= =09=09{=0A=20=09=09=09bool=09=20=20=20*nulls=20=3D=20= op->d.agg_strict_input_check.nulls;=0A@@=20-1840,13=20+1921,13=20@@=20= ExecInterpExpr(ExprState=20*state,=20ExprContext=20*econtext,=20bool=20= *isnull)=0A=20=09=09{=0A=20=09=09=09/*=20unreachable=20*/=0A=20=09=09=09= Assert(false);=0A-=09=09=09goto=20out;=0A+=09=09=09goto=20out_error;=0A=20= =09=09}=0A=20=09}=0A=20=0A-out:=0A-=09*isnull=20=3D=20state->resnull;=0A= -=09return=20state->resvalue;=0A+out_error:=0A+=09pg_unreachable();=0A+=09= return=20(Datum)=200;=0A=20}=0A=20=0A=20/*=0Adiff=20--git=20= a/src/backend/executor/nodeAgg.c=20b/src/backend/executor/nodeAgg.c=0A= index=20f154f28902..85f2bb970c=20100644=0A---=20= a/src/backend/executor/nodeAgg.c=0A+++=20= b/src/backend/executor/nodeAgg.c=0A@@=20-816,11=20+816,8=20@@=20= advance_transition_function(AggState=20*aggstate,=0A=20static=20void=0A=20= advance_aggregates(AggState=20*aggstate)=0A=20{=0A-=09bool=09=09= dummynull;=0A-=0A-=09= ExecEvalExprSwitchContext(aggstate->phase->evaltrans,=0A-=09=09=09=09=09=09= =09=20=20aggstate->tmpcontext,=0A-=09=09=09=09=09=09=09=20=20= &dummynull);=0A+=09= ExecEvalExprNoReturnSwitchContext(aggstate->phase->evaltrans,=0A+=09=09=09= =09=09=09=09=09=09=20=20aggstate->tmpcontext);=0A=20}=0A=20=0A=20/*=0A= diff=20--git=20a/src/backend/jit/llvm/llvmjit_expr.c=20= b/src/backend/jit/llvm/llvmjit_expr.c=0Aindex=204b51aa1ce0..fbf257ddf5=20= 100644=0A---=20a/src/backend/jit/llvm/llvmjit_expr.c=0A+++=20= b/src/backend/jit/llvm/llvmjit_expr.c=0A@@=20-251,7=20+251,7=20@@=20= llvm_compile_expr(ExprState=20*state)=0A=20=0A=20=09=09switch=20(opcode)=0A= =20=09=09{=0A-=09=09=09case=20EEOP_DONE:=0A+=09=09=09case=20= EEOP_DONE_RETURN:=0A=20=09=09=09=09{=0A=20=09=09=09=09=09LLVMValueRef=20= v_tmpisnull;=0A=20=09=09=09=09=09LLVMValueRef=20v_tmpvalue;=0A@@=20= -265,6=20+265,10=20@@=20llvm_compile_expr(ExprState=20*state)=0A=20=09=09= =09=09=09break;=0A=20=09=09=09=09}=0A=20=0A+=09=09=09case=20= EEOP_DONE_NO_RETURN:=0A+=09=09=09=09LLVMBuildRet(b,=20l_sizet_const(0));=0A= +=09=09=09=09break;=0A+=0A=20=09=09=09case=20EEOP_INNER_FETCHSOME:=0A=20=09= =09=09case=20EEOP_OUTER_FETCHSOME:=0A=20=09=09=09case=20= EEOP_SCAN_FETCHSOME:=0A@@=20-542,12=20+546,16=20@@=20= llvm_compile_expr(ExprState=20*state)=0A=20=0A=20=09=09=09case=20= EEOP_FUNCEXPR:=0A=20=09=09=09case=20EEOP_FUNCEXPR_STRICT:=0A+=09=09=09= case=20EEOP_FUNCEXPR_STRICT_1:=0A+=09=09=09case=20= EEOP_FUNCEXPR_STRICT_2:=0A=20=09=09=09=09{=0A=20=09=09=09=09=09= FunctionCallInfo=20fcinfo=20=3D=20op->d.func.fcinfo_data;=0A=20=09=09=09=09= =09LLVMValueRef=20v_fcinfo_isnull;=0A=20=09=09=09=09=09LLVMValueRef=20= v_retval;=0A=20=0A-=09=09=09=09=09if=20(opcode=20=3D=3D=20= EEOP_FUNCEXPR_STRICT)=0A+=09=09=09=09=09if=20(opcode=20=3D=3D=20= EEOP_FUNCEXPR_STRICT=20||=0A+=09=09=09=09=09=09opcode=20=3D=3D=20= EEOP_FUNCEXPR_STRICT_1=20||=0A+=09=09=09=09=09=09opcode=20=3D=3D=20= EEOP_FUNCEXPR_STRICT_2)=0A=20=09=09=09=09=09{=0A=20=09=09=09=09=09=09= LLVMBasicBlockRef=20b_nonull;=0A=20=09=09=09=09=09=09LLVMBasicBlockRef=20= *b_checkargnulls;=0A@@=20-1984,6=20+1992,7=20@@=20= llvm_compile_expr(ExprState=20*state)=0A=20=09=09=09=09}=0A=20=0A=20=09=09= =09case=20EEOP_AGG_STRICT_INPUT_CHECK_ARGS:=0A+=09=09=09case=20= EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1:=0A=20=09=09=09case=20= EEOP_AGG_STRICT_INPUT_CHECK_NULLS:=0A=20=09=09=09=09{=0A=20=09=09=09=09=09= int=09=09=09nargs=20=3D=20op->d.agg_strict_input_check.nargs;=0Adiff=20= --git=20a/src/include/executor/execExpr.h=20= b/src/include/executor/execExpr.h=0Aindex=20048573c2bc..4e6609dd26=20= 100644=0A---=20a/src/include/executor/execExpr.h=0A+++=20= b/src/include/executor/execExpr.h=0A@@=20-64,8=20+64,11=20@@=20typedef=20= struct=20ExprEvalRowtypeCache=0A=20=20*/=0A=20typedef=20enum=20= ExprEvalOp=0A=20{=0A-=09/*=20entire=20expression=20has=20been=20= evaluated=20completely,=20return=20*/=0A-=09EEOP_DONE,=0A+=09/*=20entire=20= expression=20has=20been=20evaluated,=20return=20value=20*/=0A+=09= EEOP_DONE_RETURN,=0A+=0A+=09/*=20entire=20expression=20has=20been=20= evaluated,=20no=20return=20value=20*/=0A+=09EEOP_DONE_NO_RETURN,=0A=20=0A= =20=09/*=20apply=20slot_getsomeattrs=20on=20corresponding=20tuple=20slot=20= */=0A=20=09EEOP_INNER_FETCHSOME,=0A@@=20-104,11=20+107,13=20@@=20typedef=20= enum=20ExprEvalOp=0A=20=0A=20=09/*=0A=20=09=20*=20Evaluate=20function=20= call=20(including=20OpExprs=20etc).=20=20For=20speed,=20we=0A-=09=20*=20= distinguish=20in=20the=20opcode=20whether=20the=20function=20is=20strict=20= and/or=0A-=09=20*=20requires=20usage=20stats=20tracking.=0A+=09=20*=20= distinguish=20in=20the=20opcode=20whether=20the=20function=20is=20strict=20= with=201,=202,=20or=0A+=09=20*=20more=20arguments=20and/or=20requires=20= usage=20stats=20tracking.=0A=20=09=20*/=0A=20=09EEOP_FUNCEXPR,=0A=20=09= EEOP_FUNCEXPR_STRICT,=0A+=09EEOP_FUNCEXPR_STRICT_1,=0A+=09= EEOP_FUNCEXPR_STRICT_2,=0A=20=09EEOP_FUNCEXPR_FUSAGE,=0A=20=09= EEOP_FUNCEXPR_STRICT_FUSAGE,=0A=20=0A@@=20-247,6=20+252,7=20@@=20typedef=20= enum=20ExprEvalOp=0A=20=09EEOP_AGG_STRICT_DESERIALIZE,=0A=20=09= EEOP_AGG_DESERIALIZE,=0A=20=09EEOP_AGG_STRICT_INPUT_CHECK_ARGS,=0A+=09= EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1,=0A=20=09= EEOP_AGG_STRICT_INPUT_CHECK_NULLS,=0A=20=09= EEOP_AGG_PLAIN_PERGROUP_NULLCHECK,=0A=20=09= EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL,=0Adiff=20--git=20= a/src/include/executor/executor.h=20b/src/include/executor/executor.h=0A= index=20e1eefb400b..cc321bbf9e=20100644=0A---=20= a/src/include/executor/executor.h=0A+++=20= b/src/include/executor/executor.h=0A@@=20-337,6=20+337,34=20@@=20= ExecEvalExpr(ExprState=20*state,=0A=20}=0A=20#endif=0A=20=0A+/*=0A+=20*=20= ExecEvalExprNoReturn=0A+=20*=0A+=20*=20Like=20ExecEvalExpr(),=20but=20= for=20cases=20where=20no=20return=20value=20is=20expected,=0A+=20*=20= because=20the=20side-effects=20of=20expression=20evaluation=20are=20= what's=20desired.=20This=0A+=20*=20is=20e.g.=20used=20for=20projection=20= and=20aggregate=20transition=20computation.=0A+=0A+=20*=20Evaluate=20= expression=20identified=20by=20"state"=20in=20the=20execution=20context=0A= +=20*=20given=20by=20"econtext".=0A+=20*=0A+=20*=20The=20caller=20should=20= already=20have=20switched=20into=20the=20temporary=20memory=20context=0A= +=20*=20econtext->ecxt_per_tuple_memory.=20=20The=20convenience=20entry=20= point=0A+=20*=20ExecEvalExprNoReturnSwitchContext()=20is=20provided=20= for=20callers=20who=20don't=0A+=20*=20prefer=20to=20do=20the=20switch=20= in=20an=20outer=20loop.=0A+=20*/=0A+#ifndef=20FRONTEND=0A+static=20= inline=20void=0A+ExecEvalExprNoReturn(ExprState=20*state,=0A+=09=09=09=09= =09=20ExprContext=20*econtext)=0A+{=0A+=09PG_USED_FOR_ASSERTS_ONLY=20= Datum=20retDatum;=0A+=0A+=09retDatum=20=3D=20state->evalfunc(state,=20= econtext,=20NULL);=0A+=0A+=09Assert(retDatum=20=3D=3D=20(Datum)=200);=0A= +}=0A+#endif=0A+=0A=20/*=0A=20=20*=20ExecEvalExprSwitchContext=0A=20=20*=0A= @@=20-358,6=20+386,25=20@@=20ExecEvalExprSwitchContext(ExprState=20= *state,=0A=20}=0A=20#endif=0A=20=0A+/*=0A+=20*=20= ExecEvalExprNoReturnSwitchContext=0A+=20*=0A+=20*=20Same=20as=20= ExecEvalExprNoReturn,=20but=20get=20into=20the=20right=20allocation=20= context=0A+=20*=20explicitly.=0A+=20*/=0A+#ifndef=20FRONTEND=0A+static=20= inline=20void=0A+ExecEvalExprNoReturnSwitchContext(ExprState=20*state,=0A= +=09=09=09=09=09=09=09=09=20=20ExprContext=20*econtext)=0A+{=0A+=09= MemoryContext=20oldContext;=0A+=0A+=09oldContext=20=3D=20= MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);=0A+=09= ExecEvalExprNoReturn(state,=20econtext);=0A+=09= MemoryContextSwitchTo(oldContext);=0A+}=0A+#endif=0A+=0A=20/*=0A=20=20*=20= ExecProject=0A=20=20*=0A@@=20-377,7=20+424,6=20@@=20= ExecProject(ProjectionInfo=20*projInfo)=0A=20=09ExprContext=20*econtext=20= =3D=20projInfo->pi_exprContext;=0A=20=09ExprState=20=20*state=20=3D=20= &projInfo->pi_state;=0A=20=09TupleTableSlot=20*slot=20=3D=20= state->resultslot;=0A-=09bool=09=09isnull;=0A=20=0A=20=09/*=0A=20=09=20*=20= Clear=20any=20former=20contents=20of=20the=20result=20slot.=20=20This=20= makes=20it=20safe=20for=0A@@=20-385,8=20+431,8=20@@=20= ExecProject(ProjectionInfo=20*projInfo)=0A=20=09=20*/=0A=20=09= ExecClearTuple(slot);=0A=20=0A-=09/*=20Run=20the=20expression,=20= discarding=20scalar=20result=20from=20the=20last=20column.=20*/=0A-=09= (void)=20ExecEvalExprSwitchContext(state,=20econtext,=20&isnull);=0A+=09= /*=20Run=20the=20expression=20*/=0A+=09= ExecEvalExprNoReturnSwitchContext(state,=20econtext);=0A=20=0A=20=09/*=0A= =20=09=20*=20Successfully=20formed=20a=20result=20row.=20=20Mark=20the=20= result=20slot=20as=20containing=20a=0A--=20=0A2.32.1=20(Apple=20Git-133)=0A= =0A= --Apple-Mail=_8699750D-6126-4B55-8029-AEB48AF48DF0--