Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commited83f6e

Browse files
committed
When adding a "target IS NOT NULL" indexqual to the plan for an index-optimized
MIN or MAX, we must take care to insert the added qual in a legal place amongthe existing indexquals, if any. The btree index AM requires the quals toappear in index-column order. We didn't have to worry about this beforebecause "target IS NOT NULL" was just treated as a plain scan filter condition;but as of 9.0 it can be an index qual and then it has to follow the rule.Per report from Ian Barwick.
1 parent7fdbb8e commited83f6e

File tree

1 file changed

+166
-19
lines changed

1 file changed

+166
-19
lines changed

‎src/backend/optimizer/plan/planagg.c

Lines changed: 166 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.51 2010/02/14 18:42:15 rhaas Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.52 2010/05/10 16:25:46 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -50,6 +50,7 @@ static bool build_minmax_path(PlannerInfo *root, RelOptInfo *rel,
5050
staticScanDirectionmatch_agg_to_index_col(MinMaxAggInfo*info,
5151
IndexOptInfo*index,intindexcol);
5252
staticvoidmake_agg_subplan(PlannerInfo*root,MinMaxAggInfo*info);
53+
staticvoidattach_notnull_index_qual(MinMaxAggInfo*info,IndexScan*iplan);
5354
staticNode*replace_aggs_with_params_mutator(Node*node,List**context);
5455
staticOidfetch_agg_sort_op(Oidaggfnoid);
5556

@@ -537,9 +538,6 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info)
537538
* The NOT NULL qual has to go on the actual indexscan; create_plan might
538539
* have stuck a gating Result atop that, if there were any pseudoconstant
539540
* quals.
540-
*
541-
* We can skip adding the NOT NULL qual if it duplicates either an
542-
* already-given WHERE condition, or a clause of the index predicate.
543541
*/
544542
plan=create_plan(&subroot, (Path*)info->path);
545543

@@ -552,21 +550,7 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info)
552550
if (!IsA(iplan,IndexScan))
553551
elog(ERROR,"result of create_plan(IndexPath) isn't an IndexScan");
554552

555-
if (!list_member(iplan->indexqualorig,info->notnulltest)&&
556-
!list_member(info->path->indexinfo->indpred,info->notnulltest))
557-
{
558-
NullTest*ntest;
559-
560-
/* Need a "fixed" copy as well as the original */
561-
ntest=copyObject(info->notnulltest);
562-
ntest->arg= (Expr*)fix_indexqual_operand((Node*)ntest->arg,
563-
info->path->indexinfo);
564-
565-
iplan->indexqual=lappend(iplan->indexqual,
566-
ntest);
567-
iplan->indexqualorig=lappend(iplan->indexqualorig,
568-
info->notnulltest);
569-
}
553+
attach_notnull_index_qual(info,iplan);
570554

571555
plan= (Plan*)make_limit(plan,
572556
subparse->limitOffset,
@@ -586,6 +570,169 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info)
586570
root->init_plans=subroot.init_plans;
587571
}
588572

573+
/*
574+
* Add "target IS NOT NULL" to the quals of the given indexscan.
575+
*
576+
* This is trickier than it sounds because the new qual has to be added at an
577+
* appropriate place in the qual list, to preserve the list's ordering by
578+
* index column position.
579+
*/
580+
staticvoid
581+
attach_notnull_index_qual(MinMaxAggInfo*info,IndexScan*iplan)
582+
{
583+
NullTest*ntest;
584+
List*newindexqual;
585+
List*newindexqualorig;
586+
booldone;
587+
ListCell*lc1;
588+
ListCell*lc2;
589+
Expr*leftop;
590+
AttrNumbertargetattno;
591+
592+
/*
593+
* We can skip adding the NOT NULL qual if it duplicates either an
594+
* already-given WHERE condition, or a clause of the index predicate.
595+
*/
596+
if (list_member(iplan->indexqualorig,info->notnulltest)||
597+
list_member(info->path->indexinfo->indpred,info->notnulltest))
598+
return;
599+
600+
/* Need a "fixed" copy as well as the original */
601+
ntest=copyObject(info->notnulltest);
602+
ntest->arg= (Expr*)fix_indexqual_operand((Node*)ntest->arg,
603+
info->path->indexinfo);
604+
605+
/* Identify the target index column from the "fixed" copy */
606+
leftop=ntest->arg;
607+
608+
if (leftop&&IsA(leftop,RelabelType))
609+
leftop= ((RelabelType*)leftop)->arg;
610+
611+
Assert(leftop!=NULL);
612+
613+
if (!IsA(leftop,Var))
614+
elog(ERROR,"NullTest indexqual has wrong key");
615+
616+
targetattno= ((Var*)leftop)->varattno;
617+
618+
/*
619+
* list.c doesn't expose a primitive to insert a list cell at an arbitrary
620+
* position, so our strategy is to copy the lists and insert the null test
621+
* when we reach an appropriate spot.
622+
*/
623+
newindexqual=newindexqualorig=NIL;
624+
done= false;
625+
626+
forboth(lc1,iplan->indexqual,lc2,iplan->indexqualorig)
627+
{
628+
Expr*qual= (Expr*)lfirst(lc1);
629+
Expr*qualorig= (Expr*)lfirst(lc2);
630+
AttrNumbervarattno;
631+
632+
/*
633+
* Identify which index column this qual is for. This code should
634+
* match the qual disassembly code in ExecIndexBuildScanKeys.
635+
*/
636+
if (IsA(qual,OpExpr))
637+
{
638+
/* indexkey op expression */
639+
leftop= (Expr*)get_leftop(qual);
640+
641+
if (leftop&&IsA(leftop,RelabelType))
642+
leftop= ((RelabelType*)leftop)->arg;
643+
644+
Assert(leftop!=NULL);
645+
646+
if (!IsA(leftop,Var))
647+
elog(ERROR,"indexqual doesn't have key on left side");
648+
649+
varattno= ((Var*)leftop)->varattno;
650+
}
651+
elseif (IsA(qual,RowCompareExpr))
652+
{
653+
/* (indexkey, indexkey, ...) op (expression, expression, ...) */
654+
RowCompareExpr*rc= (RowCompareExpr*)qual;
655+
656+
/*
657+
* Examine just the first column of the rowcompare, which is
658+
* what determines its placement in the overall qual list.
659+
*/
660+
leftop= (Expr*)linitial(rc->largs);
661+
662+
if (leftop&&IsA(leftop,RelabelType))
663+
leftop= ((RelabelType*)leftop)->arg;
664+
665+
Assert(leftop!=NULL);
666+
667+
if (!IsA(leftop,Var))
668+
elog(ERROR,"indexqual doesn't have key on left side");
669+
670+
varattno= ((Var*)leftop)->varattno;
671+
}
672+
elseif (IsA(qual,ScalarArrayOpExpr))
673+
{
674+
/* indexkey op ANY (array-expression) */
675+
ScalarArrayOpExpr*saop= (ScalarArrayOpExpr*)qual;
676+
677+
leftop= (Expr*)linitial(saop->args);
678+
679+
if (leftop&&IsA(leftop,RelabelType))
680+
leftop= ((RelabelType*)leftop)->arg;
681+
682+
Assert(leftop!=NULL);
683+
684+
if (!IsA(leftop,Var))
685+
elog(ERROR,"indexqual doesn't have key on left side");
686+
687+
varattno= ((Var*)leftop)->varattno;
688+
}
689+
elseif (IsA(qual,NullTest))
690+
{
691+
/* indexkey IS NULL or indexkey IS NOT NULL */
692+
NullTest*ntest= (NullTest*)qual;
693+
694+
leftop=ntest->arg;
695+
696+
if (leftop&&IsA(leftop,RelabelType))
697+
leftop= ((RelabelType*)leftop)->arg;
698+
699+
Assert(leftop!=NULL);
700+
701+
if (!IsA(leftop,Var))
702+
elog(ERROR,"NullTest indexqual has wrong key");
703+
704+
varattno= ((Var*)leftop)->varattno;
705+
}
706+
else
707+
{
708+
elog(ERROR,"unsupported indexqual type: %d",
709+
(int)nodeTag(qual));
710+
varattno=0;/* keep compiler quiet */
711+
}
712+
713+
/* Insert the null test at the first place it can legally go */
714+
if (!done&&targetattno <=varattno)
715+
{
716+
newindexqual=lappend(newindexqual,ntest);
717+
newindexqualorig=lappend(newindexqualorig,info->notnulltest);
718+
done= true;
719+
}
720+
721+
newindexqual=lappend(newindexqual,qual);
722+
newindexqualorig=lappend(newindexqualorig,qualorig);
723+
}
724+
725+
/* Add the null test at the end if it must follow all existing quals */
726+
if (!done)
727+
{
728+
newindexqual=lappend(newindexqual,ntest);
729+
newindexqualorig=lappend(newindexqualorig,info->notnulltest);
730+
}
731+
732+
iplan->indexqual=newindexqual;
733+
iplan->indexqualorig=newindexqualorig;
734+
}
735+
589736
/*
590737
* Replace original aggregate calls with subplan output Params
591738
*/

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp