77 *
88 *
99 * IDENTIFICATION
10- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.66 1999/07/30 00:44:23 tgl Exp $
10+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.67 1999/08/09 01:01:42 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -48,7 +48,11 @@ static MergeJoin *create_mergejoin_node(MergePath *best_path, List *tlist,
4848static HashJoin * create_hashjoin_node (HashPath * best_path ,List * tlist ,
4949List * clauses ,Plan * outer_node ,List * outer_tlist ,
5050Plan * inner_node ,List * inner_tlist );
51- static Node * fix_indxqual_references (Node * clause ,Path * index_path );
51+ static List * fix_indxqual_references (List * indexquals ,IndexPath * index_path );
52+ static List * fix_one_indxqual_sublist (List * indexqual ,IndexPath * index_path ,
53+ Form_pg_index index );
54+ static Node * fix_one_indxqual_operand (Node * node ,IndexPath * index_path ,
55+ Form_pg_index index );
5256static Noname * make_noname (List * tlist ,List * pathkeys ,Oid * operators ,
5357Plan * plan_node ,int nonametype );
5458static IndexScan * make_indexscan (List * qptlist ,List * qpqual ,Index scanrelid ,
@@ -393,8 +397,7 @@ create_indexscan_node(IndexPath *best_path,
393397indxqual = fix_opids (indxqual );
394398
395399/* The executor needs a copy with index attrs substituted for table ones */
396- fixed_indxqual = (List * )fix_indxqual_references ((Node * )indxqual ,
397- (Path * )best_path );
400+ fixed_indxqual = fix_indxqual_references (indxqual ,best_path );
398401
399402scan_node = make_indexscan (tlist ,
400403qpqual ,
@@ -457,24 +460,26 @@ create_nestloop_node(NestPath *best_path,
457460 * the inner(index) scan's qualification so that the var nodes
458461 * refer to the proper outer join relation attributes.
459462 *
460- * XXXRe-moving index clauses doesn't work properly: 1.
463+ * XXXRemoving index clauses doesn't work properly: 1.
461464 * fix_indxqual_references may change varattno-s in
462465 * inner_indxqual; 2. clauses may be commuted I havn't time to fix
463466 * it at the moment. - vadim 04/24/97
464467 */
465468if (found )
466469{
467- List * new_inner_qual = NIL ;
470+ List * new_inner_qual ;
468471
469472clauses = set_difference (clauses ,inner_indxqual );/* XXX */
470- new_inner_qual = index_outerjoin_references (inner_indxqual ,
471- outer_node -> targetlist ,
472- ((Scan * )inner_node )-> scanrelid );
473+ /* only refs to outer vars get changed in the inner indexqual */
474+ new_inner_qual = join_references (inner_indxqual ,
475+ outer_tlist ,
476+ NIL );
473477((IndexScan * )inner_node )-> indxqual = lcons (new_inner_qual ,NIL );
474478}
475479}
476480else if (IsA_Join (inner_node ))
477481{
482+ /* Materialize the inner join for speed reasons */
478483inner_node = (Plan * )make_noname (inner_tlist ,
479484NIL ,
480485NULL ,
@@ -629,160 +634,142 @@ create_hashjoin_node(HashPath *best_path,
629634
630635/*
631636 * fix_indxqual_references
632- *Adjust a qual clause to refer to an index instead of the original relation.
637+ *Adjust indexqual clauses to refer to index attributes instead of the
638+ *attributes of the original relation.
633639 *
634- * Returns a modified copy of the given clause --- the original is not changed.
640+ * This code used to be entirely bogus for multi-index scans. Now it keeps
641+ * track of which index applies to each subgroup of index qual clauses...
642+ *
643+ * Returns a modified copy of the indexqual list --- the original is not
644+ * changed.
635645 */
636646
637- static Node *
638- fix_indxqual_references (Node * clause , Path * index_path )
647+ static List *
648+ fix_indxqual_references (List * indexquals , IndexPath * index_path )
639649{
640- if (clause == NULL )
641- return NULL ;
642- else if (IsA (clause ,Var ))
643- {
644- if (lfirsti (index_path -> parent -> relids )== ((Var * )clause )-> varno )
645- {
646- Node * newclause ;
647- int pos = 0 ;
648- int varatt = ((Var * )clause )-> varattno ;
649- int * indexkeys = ((IndexPath * )index_path )-> indexkeys ;
650+ List * fixed_quals = NIL ;
651+ List * indexids = index_path -> indexid ;
652+ List * i ;
650653
651- if (indexkeys )
652- {
653- while (indexkeys [pos ]!= 0 )
654- {
655- if (varatt == indexkeys [pos ])
656- break ;
657- pos ++ ;
658- }
659- }
660- newclause = copyObject (clause );
661- ((Var * )newclause )-> varattno = pos + 1 ;
662- return newclause ;
663- }
664- /* The Var is not part of the indexed relation, leave it alone */
665- return copyObject (clause );
666- }
667- else if (single_node (clause ))
668- return copyObject (clause );
669- else if (is_opclause (clause )&&
670- is_funcclause ((Node * )get_leftop ((Expr * )clause ))&&
671- ((Func * ) ((Expr * )get_leftop ((Expr * )clause ))-> oper )-> funcisindex )
654+ foreach (i ,indexquals )
672655{
656+ List * indexqual = lfirst (i );
657+ Oid indexid = lfirsti (indexids );
658+ HeapTuple indexTuple ;
659+ Form_pg_index index ;
673660
674- /*
675- * This looks pretty seriously wrong to me, but I'm not sure what
676- * it's supposed to be doing ... tgl 5/99
677- */
678- Var * newvar = makeVar ((Index )lfirsti (index_path -> parent -> relids ),
679- 1 ,/* func indices have one key */
680- ((Func * ) ((Expr * )clause )-> oper )-> functype ,
681- -1 ,
682- 0 ,
683- (Index )lfirsti (index_path -> parent -> relids ),
684- 0 );
685-
686- return ((Node * )make_opclause ((Oper * ) ((Expr * )clause )-> oper ,
687- newvar ,
688- get_rightop ((Expr * )clause )));
661+ indexTuple = SearchSysCacheTuple (INDEXRELID ,
662+ ObjectIdGetDatum (indexid ),
663+ 0 ,0 ,0 );
664+ if (!HeapTupleIsValid (indexTuple ))
665+ elog (ERROR ,"fix_indxqual_references: index %u not found" ,
666+ indexid );
667+ index = (Form_pg_index )GETSTRUCT (indexTuple );
689668
690- }
691- else if (IsA (clause ,Expr ))
692- {
693- Expr * expr = (Expr * )clause ;
694- List * new_subclauses = NIL ;
695- List * i ;
669+ fixed_quals = lappend (fixed_quals ,
670+ fix_one_indxqual_sublist (indexqual ,
671+ index_path ,
672+ index ));
696673
697- foreach (i ,expr -> args )
698- {
699- Node * subclause = lfirst (i );
674+ indexids = lnext (indexids );
675+ }
676+ return fixed_quals ;
677+ }
700678
701- new_subclauses = lappend (new_subclauses ,
702- fix_indxqual_references (subclause ,
703- index_path ));
704- }
679+ /*
680+ * Fix the sublist of indexquals to be used in a particular scan.
681+ *
682+ * All that we need to do is change the left or right operand of the top-level
683+ * operator of each qual clause. Those are the only places that the index
684+ * attribute can appear in a valid indexqual. The other side of the indexqual
685+ * might be a complex function of joined rels; we do not need or want to
686+ * alter such an expression.
687+ */
688+ static List *
689+ fix_one_indxqual_sublist (List * indexqual ,IndexPath * index_path ,
690+ Form_pg_index index )
691+ {
692+ List * fixed_qual = NIL ;
693+ List * i ;
705694
706- return (Node * )make_clause (expr -> opType ,expr -> oper ,new_subclauses );
707- }
708- else if (IsA (clause ,List ))
695+ foreach (i ,indexqual )
709696{
710- List * new_subclauses = NIL ;
711- List * i ;
697+ Node * clause = lfirst (i );
698+ List * args ;
699+ Expr * newclause ;
700+
701+ if (!is_opclause (clause ))
702+ elog (ERROR ,"fix_one_indxqual_sublist: indexqual clause is not opclause" );
703+
704+ /* Copy enough structure to allow replacing left or right operand */
705+ args = listCopy (((Expr * )clause )-> args );
706+ newclause = make_clause (((Expr * )clause )-> opType ,
707+ ((Expr * )clause )-> oper ,
708+ args );
709+
710+ lfirst (args )= fix_one_indxqual_operand (lfirst (args ),
711+ index_path ,
712+ index );
713+ if (lnext (args ))
714+ lfirst (lnext (args ))= fix_one_indxqual_operand (lfirst (lnext (args )),
715+ index_path ,
716+ index );
717+
718+ fixed_qual = lappend (fixed_qual ,newclause );
719+ }
720+ return fixed_qual ;
721+ }
712722
713- foreach (i , (List * )clause )
723+ static Node *
724+ fix_one_indxqual_operand (Node * node ,IndexPath * index_path ,
725+ Form_pg_index index )
726+ {
727+ if (node == NULL )
728+ return NULL ;
729+ if (IsA (node ,Var ))
730+ {
731+ if (((Var * )node )-> varno == lfirsti (index_path -> path .parent -> relids ))
714732{
715- Node * subclause = lfirst (i );
733+ int varatt = ((Var * )node )-> varattno ;
734+ int pos ;
716735
717- new_subclauses = lappend (new_subclauses ,
718- fix_indxqual_references (subclause ,
719- index_path ));
736+ for (pos = 0 ;pos < INDEX_MAX_KEYS ;pos ++ )
737+ {
738+ if (index -> indkey [pos ]== varatt )
739+ {
740+ Node * newnode = copyObject (node );
741+ ((Var * )newnode )-> varattno = pos + 1 ;
742+ return newnode ;
743+ }
744+ }
745+ /*
746+ * We should never see a reference to an attribute of the indexed
747+ * relation that is not one of the indexed attributes.
748+ */
749+ elog (ERROR ,"fix_one_indxqual_operand: failed to find index pos of index attribute" );
720750}
721-
722- return (Node * )new_subclauses ;
723- }
724- else if (IsA (clause ,ArrayRef ))
725- {
726- ArrayRef * oldnode = (ArrayRef * )clause ;
727- ArrayRef * newnode = makeNode (ArrayRef );
728-
729- newnode -> refattrlength = oldnode -> refattrlength ;
730- newnode -> refelemlength = oldnode -> refelemlength ;
731- newnode -> refelemtype = oldnode -> refelemtype ;
732- newnode -> refelembyval = oldnode -> refelembyval ;
733- newnode -> refupperindexpr = (List * )
734- fix_indxqual_references ((Node * )oldnode -> refupperindexpr ,
735- index_path );
736- newnode -> reflowerindexpr = (List * )
737- fix_indxqual_references ((Node * )oldnode -> reflowerindexpr ,
738- index_path );
739- newnode -> refexpr =
740- fix_indxqual_references (oldnode -> refexpr ,index_path );
741- newnode -> refassgnexpr =
742- fix_indxqual_references (oldnode -> refassgnexpr ,index_path );
743-
744- return (Node * )newnode ;
745- }
746- else if (IsA (clause ,CaseExpr ))
747- {
748- CaseExpr * oldnode = (CaseExpr * )clause ;
749- CaseExpr * newnode = makeNode (CaseExpr );
750-
751- newnode -> casetype = oldnode -> casetype ;
752- newnode -> arg = oldnode -> arg ;/* XXX should always be null
753- * anyway ... */
754- newnode -> args = (List * )
755- fix_indxqual_references ((Node * )oldnode -> args ,
756- index_path );
757- newnode -> defresult =
758- fix_indxqual_references (oldnode -> defresult ,
759- index_path );
760-
761- return (Node * )newnode ;
751+ /*
752+ * The Var is not part of the indexed relation, leave it alone.
753+ * This would normally only occur when looking at the other side
754+ * of a join indexqual.
755+ */
756+ return node ;
762757}
763- else if (IsA (clause ,CaseWhen ))
764- {
765- CaseWhen * oldnode = (CaseWhen * )clause ;
766- CaseWhen * newnode = makeNode (CaseWhen );
767758
768- newnode -> expr =
769- fix_indxqual_references (oldnode -> expr ,
770- index_path );
771- newnode -> result =
772- fix_indxqual_references (oldnode -> result ,
773- index_path );
759+ /*
760+ * Note: currently, there is no need for us to do anything here for
761+ * functional indexes. If nodeIndexscan.c sees a func clause as the left
762+ * or right-hand toplevel operand of an indexqual, it assumes that that is
763+ * a reference to the functional index's value and makes the appropriate
764+ * substitution. (It would be cleaner to make the substitution here, I
765+ * think --- suspect this issue if a join clause involving a function call
766+ * misbehaves...)
767+ */
774768
775- return (Node * )newnode ;
776- }
777- else
778- {
779- elog (ERROR ,"fix_indxqual_references: Cannot handle node type %d" ,
780- nodeTag (clause ));
781- return NULL ;
782- }
769+ /* return the unmodified node */
770+ return node ;
783771}
784772
785-
786773/*
787774 * switch_outer
788775 * Given a list of merge clauses, rearranges the elements within the
@@ -794,14 +781,13 @@ static List *
794781switch_outer (List * clauses )
795782{
796783List * t_list = NIL ;
797- Expr * temp ;
798784List * i ;
799- Expr * clause ;
800- Node * op ;
801785
802786foreach (i ,clauses )
803787{
804- clause = lfirst (i );
788+ Expr * clause = lfirst (i );
789+ Node * op ;
790+
805791Assert (is_opclause ((Node * )clause ));
806792op = (Node * )get_rightop (clause );
807793Assert (op != (Node * )NULL );
@@ -810,12 +796,13 @@ switch_outer(List *clauses)
810796Assert (IsA (op ,Var ));
811797if (var_is_outer ((Var * )op ))
812798{
813-
814799/*
815800 * Duplicate just enough of the structure to allow commuting
816801 * the clause without changing the original list. Could use
817802 * copyObject, but a complete deep copy is overkill.
818803 */
804+ Expr * temp ;
805+
819806temp = make_clause (clause -> opType ,clause -> oper ,
820807lcons (get_leftop (clause ),
821808lcons (get_rightop (clause ),