|
7 | 7 | *
|
8 | 8 | *
|
9 | 9 | * IDENTIFICATION
|
10 |
| - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.39 1999/02/02 17:46:14 momjian Exp $ |
| 10 | + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.40 1999/02/03 19:31:24 wieck Exp $ |
11 | 11 | *
|
12 | 12 | *-------------------------------------------------------------------------
|
13 | 13 | */
|
|
50 | 50 |
|
51 | 51 | #include"executor/executor.h"
|
52 | 52 |
|
| 53 | +#include"utils/builtins.h" |
| 54 | +#include"utils/syscache.h" |
| 55 | +#include"access/genam.h" |
| 56 | +#include"parser/parse_oper.h" |
| 57 | + |
| 58 | +staticboolneed_sortplan(List*sortcls,Plan*plan); |
53 | 59 | staticPlan*make_sortplan(List*tlist,List*sortcls,Plan*plannode);
|
54 | 60 | externPlan*make_groupPlan(List**tlist,booltuplePerGroup,
|
55 | 61 | List*groupClause,Plan*subplan);
|
@@ -344,7 +350,7 @@ union_planner(Query *parse)
|
344 | 350 | }
|
345 | 351 | else
|
346 | 352 | {
|
347 |
| -if (parse->sortClause) |
| 353 | +if (parse->sortClause&&need_sortplan(parse->sortClause,result_plan)) |
348 | 354 | return (make_sortplan(tlist,parse->sortClause,result_plan));
|
349 | 355 | else
|
350 | 356 | return ((Plan*)result_plan);
|
@@ -572,3 +578,170 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
|
572 | 578 | /* success */
|
573 | 579 | return;
|
574 | 580 | }
|
| 581 | + |
| 582 | + |
| 583 | +/* ---------- |
| 584 | + * Support function for need_sortplan |
| 585 | + * ---------- |
| 586 | + */ |
| 587 | +staticTargetEntry* |
| 588 | +get_matching_tle(Plan*plan,Resdom*resdom) |
| 589 | +{ |
| 590 | +List*i; |
| 591 | +TargetEntry*tle; |
| 592 | + |
| 593 | +foreach (i,plan->targetlist) { |
| 594 | +tle= (TargetEntry*)lfirst(i); |
| 595 | +if (tle->resdom->resno==resdom->resno) |
| 596 | +returntle; |
| 597 | +} |
| 598 | +returnNULL; |
| 599 | +} |
| 600 | + |
| 601 | + |
| 602 | +/* ---------- |
| 603 | + * Check if a user requested ORDER BY is already satisfied by |
| 604 | + * the choosen index scan. |
| 605 | + * |
| 606 | + * Returns TRUE if sort is required, FALSE if can be omitted. |
| 607 | + * ---------- |
| 608 | + */ |
| 609 | +staticbool |
| 610 | +need_sortplan(List*sortcls,Plan*plan) |
| 611 | +{ |
| 612 | +RelationindexRel; |
| 613 | +IndexScan*indexScan; |
| 614 | +OidindexId; |
| 615 | +List*i; |
| 616 | +HeapTuplehtup; |
| 617 | +Form_pg_indexindex_tup; |
| 618 | +intkey_no=0; |
| 619 | + |
| 620 | +/* ---------- |
| 621 | + * Must be an IndexScan |
| 622 | + * ---------- |
| 623 | + */ |
| 624 | +if (nodeTag(plan)!=T_IndexScan) { |
| 625 | +return TRUE; |
| 626 | +} |
| 627 | + |
| 628 | +indexScan= (IndexScan*)plan; |
| 629 | + |
| 630 | +/* ---------- |
| 631 | + * Should not have left- or righttree |
| 632 | + * ---------- |
| 633 | + */ |
| 634 | +if (plan->lefttree!=NULL) { |
| 635 | +return TRUE; |
| 636 | +} |
| 637 | +if (plan->righttree!=NULL) { |
| 638 | +return TRUE; |
| 639 | +} |
| 640 | + |
| 641 | +/* ---------- |
| 642 | + * Must be a single index scan |
| 643 | + * ---------- |
| 644 | + */ |
| 645 | +if (length(indexScan->indxid)!=1) { |
| 646 | +return TRUE; |
| 647 | +} |
| 648 | + |
| 649 | +/* ---------- |
| 650 | + * Indices can only have up to 8 attributes. So an ORDER BY using |
| 651 | + * more that 8 attributes could never be satisfied by an index. |
| 652 | + * ---------- |
| 653 | + */ |
| 654 | +if (length(sortcls)>8) { |
| 655 | +return TRUE; |
| 656 | +} |
| 657 | + |
| 658 | +/* ---------- |
| 659 | + * The choosen Index must be a btree |
| 660 | + * ---------- |
| 661 | + */ |
| 662 | +indexId=lfirsti(indexScan->indxid); |
| 663 | + |
| 664 | +indexRel=index_open(indexId); |
| 665 | +if (strcmp(nameout(&(indexRel->rd_am->amname)),"btree")!=0) { |
| 666 | +heap_close(indexRel); |
| 667 | +return TRUE; |
| 668 | +} |
| 669 | +heap_close(indexRel); |
| 670 | + |
| 671 | +/* ---------- |
| 672 | + * Fetch the index tuple |
| 673 | + * ---------- |
| 674 | + */ |
| 675 | +htup=SearchSysCacheTuple(INDEXRELID, |
| 676 | +ObjectIdGetDatum(indexId),0,0,0); |
| 677 | +if (!HeapTupleIsValid(htup)) { |
| 678 | +elog(ERROR,"cache lookup for index %d failed",indexId); |
| 679 | +} |
| 680 | +index_tup= (Form_pg_index)GETSTRUCT(htup); |
| 681 | + |
| 682 | +/* ---------- |
| 683 | + * Check if all the sort clauses match the attributes in the index |
| 684 | + * ---------- |
| 685 | + */ |
| 686 | +foreach (i,sortcls) { |
| 687 | +SortClause*sortcl; |
| 688 | +Resdom*resdom; |
| 689 | +TargetEntry*tle; |
| 690 | +Var*var; |
| 691 | + |
| 692 | +sortcl= (SortClause*)lfirst(i); |
| 693 | + |
| 694 | +resdom=sortcl->resdom; |
| 695 | +tle=get_matching_tle(plan,resdom); |
| 696 | +if (tle==NULL) { |
| 697 | +/* ---------- |
| 698 | + * Could this happen? |
| 699 | + * ---------- |
| 700 | + */ |
| 701 | +return TRUE; |
| 702 | +} |
| 703 | +if (nodeTag(tle->expr)!=T_Var) { |
| 704 | +/* ---------- |
| 705 | + * The target list expression isn't a var, so it |
| 706 | + * cannot be the indexed attribute |
| 707 | + * ---------- |
| 708 | + */ |
| 709 | +return TRUE; |
| 710 | +} |
| 711 | +var= (Var*)(tle->expr); |
| 712 | + |
| 713 | +if (var->varno!=indexScan->scan.scanrelid) { |
| 714 | +/* ---------- |
| 715 | + * This Var isn't from the scan relation. So it isn't |
| 716 | + * that of the index |
| 717 | + * ---------- |
| 718 | + */ |
| 719 | +return TRUE; |
| 720 | +} |
| 721 | + |
| 722 | +if (var->varattno!=index_tup->indkey[key_no]) { |
| 723 | +/* ---------- |
| 724 | + * It isn't the indexed attribute. |
| 725 | + * ---------- |
| 726 | + */ |
| 727 | +return TRUE; |
| 728 | +} |
| 729 | + |
| 730 | +if (oprid(oper("<",resdom->restype,resdom->restype, FALSE))!=sortcl->opoid) { |
| 731 | +/* ---------- |
| 732 | + * Sort order isn't in ascending order. |
| 733 | + * ---------- |
| 734 | + */ |
| 735 | +return TRUE; |
| 736 | +} |
| 737 | + |
| 738 | +key_no++; |
| 739 | +} |
| 740 | + |
| 741 | +/* ---------- |
| 742 | + * Index matches ORDER BY - sort not required |
| 743 | + * ---------- |
| 744 | + */ |
| 745 | +return FALSE; |
| 746 | +} |
| 747 | + |