コード例 #1
0
ファイル: opofordr.c プロジェクト: saqibjamil/Ingres
/*{
** Name: opo_fordering	- find or create multi-attribute ordering
**
** Description:
{@comment_line@}...
**
** Inputs:
[@PARAM_DESCR@]...
**
** Outputs:
[@PARAM_DESCR@]...
**	Returns:
**	    {@return_description@}
**	Exceptions:
**	    [@description_or_none@]
**
** Side Effects:
**	    [@description_or_none@]
**
** History:
[@history_template@]...
*/
OPO_ISORT
opo_fordering(
	OPS_SUBQUERY       *subquery,
	OPE_BMEQCLS        *eqcmap)
{
    OPO_ISORT           ordering;	/* number used to represent
					** multi-attribute ordering */
    OPO_SORT		*orderp;        /* ptr to multi-attribute
					** ordering descriptor */
    OPE_IEQCLS		maxeqcls;

    maxeqcls = subquery->ops_eclass.ope_ev;
    ordering = BTnext( (i4)-1, (char *)eqcmap, (i4)maxeqcls);
    if (ordering < 0)
	return(OPE_NOEQCLS);
    if ( BTnext( (i4)ordering, (char *)eqcmap, (i4)maxeqcls) < 0)
	return(ordering);		/* only one equivalence class
					** so use it as the ordering */
    
    if (!subquery->ops_msort.opo_base)
	opo_iobase(subquery);
    {	/* search existing list for the multi-attribute ordering */
	i4		maxorder;

	maxorder = subquery->ops_msort.opo_sv;
	for( ordering = 0; ordering < maxorder; ordering++)
	{
	    orderp = subquery->ops_msort.opo_base->opo_stable[ordering];
	    if ( orderp->opo_stype == OPO_SINEXACT)
	    {
		if (BTsubset((char *)eqcmap, (char *)orderp->opo_bmeqcls,
			(i4)maxeqcls)
		    &&
		    BTsubset((char *)orderp->opo_bmeqcls, (char *)eqcmap,
			(i4)maxeqcls))
		    return((OPO_ISORT)(ordering+maxeqcls)); /* correct ordering found 
						** - FIXME need a bitwise
						** equality */
	    }
	}
    }
    /* create new ordering since current one was not found */
    ordering = opo_gnumber(subquery);	/* get the next multi-attribute
					** ordering number */
    orderp = (OPO_SORT *)opn_memory(subquery->ops_global, (i4)sizeof(*orderp));
    orderp->opo_stype = OPO_SINEXACT;
    orderp->opo_bmeqcls = (OPE_BMEQCLS *)opn_memory(subquery->ops_global, (i4)sizeof(OPE_BMEQCLS));
    MEcopy((PTR)eqcmap, sizeof(OPE_BMEQCLS), (PTR)orderp->opo_bmeqcls);
    orderp->opo_eqlist = NULL;
    subquery->ops_msort.opo_base->opo_stable[ordering] = orderp;
    return((OPO_ISORT)(ordering+maxeqcls));
}
コード例 #2
0
ファイル: opjunion.c プロジェクト: saqibjamil/Ingres
/*{
** Name: opj_union	- optimize unions
**
** Description:
**      The routine determines which qualifications of a parent query 
**      can be copied to the union, so that the union can be more restrictive 
**      or partitions of the union can be eliminated entirely in some cases. 
**
** Inputs:
**      subquery                        ptr to subquery be analyzed
**
** Outputs:
**	Returns:
**	    VOID
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**      21-jun-89 (seputis)
**          initial creation
**	01-Oct-2001 (hanal04) Bug 105464 INGSRV 1517
**	    After calling opv_copytree() mark the target subquery
**	    as non-CNF if the source suquery was non-CNF.
**	11-may-05 (inkdo01)
**	    Don't copy ON clause BFs to union subqueries - fixes 114493.
**	20-apr-07 (hayke02)
**	    Limit the fix for bug 114493 (test for a OPL_NOOUTER pst_joinid)
**	    to those subqueries containing outer joins, otherwise pst_joinid
**	    will be PST_NOJOIN (0). This change fixes bug 118088.
**      27-mar-2009 (huazh01)
**          don't copy OPZ_FANUM, OPZ_SNUM, OPZ_CORRELATED attribute into 
**          'unionbm'. Doing so will cause opj_utree() to convert the  
**          union_subquery->ops_sunion.opu_qual qualification into a 
**          PST_QNODE node containing negative attribute id, and causes 
**          E_OP0384 error. (bug 121602)
[@history_template@]...
*/
VOID
opj_union(
	OPS_SUBQUERY       *subquery)
{
    OPV_IVARS	    lvar;
    for (lvar = subquery->ops_vars.opv_prv; --lvar>=0;)
    {	/* look at the union views referenced in this subquery */
	OPV_VARS    *unionp;
	unionp = subquery->ops_vars.opv_base->opv_rt[lvar];
	if (unionp->opv_grv 
	    && 
	    (unionp->opv_grv->opv_created == OPS_VIEW)
	    &&
	    unionp->opv_grv->opv_gquery
	    &&
	    unionp->opv_grv->opv_gquery->ops_union
	    )
	{   /* a union view has been found, so search the list of boolean
	    ** factors to determine which terms can be placed into the qualifications
	    ** of the union */
	    OPE_BMEQCLS	    unionbm;	/* bitmap of the equivalence classes which
					** are available in the union view */
            OPS_SUBQUERY    *union_subquery;
	    OPB_BMBF	    bfbm;
	    OPB_IBF	    maxbf;	/* current boolean factor number */
	    		    
	    maxbf = BITS_IN(bfbm);
	    union_subquery = unionp->opv_grv->opv_gquery;

	    if (union_subquery->ops_sunion.opu_mask & OPU_QUAL)
	    {
		if (union_subquery->ops_sunion.opu_qual == (PST_QNODE *)NULL)
		    continue;		/* since entire union is required by
					** another subquery, no need to proceed */
		MEfill(sizeof(bfbm), (u_char)0, (PTR)&bfbm);
		BTnot((i4)BITS_IN(bfbm), (char *)&bfbm); /* bits will get
					** reset as identical qualifications are 
					** found */
	    }
	    MEfill(sizeof(unionbm), (u_char)0, (PTR)&unionbm);
	    {	/* search thru list of attributes and mark 
		** appropriate equivalence classes*/
		/* opv_eqcmp not initialized yet */
		OPZ_IATTS	attr;
		OPZ_AT		*abase;
		abase = subquery->ops_attrs.opz_base;   /* ptr to base of array of ptrs
                                            ** to joinop attributes */
		for (attr = subquery->ops_attrs.opz_av; --attr>=0;)
		{   /* opv_eqcmp not initialized yet */
		    OPZ_ATTS	    *attrp;
		    attrp = abase->opz_attnums[attr];
		    if ((attrp->opz_varnm == lvar)
			&&
			(attrp->opz_equcls >= 0)
                        &&
                        attrp->opz_attnm.db_att_id >= 0
                       )
			BTset ((i4)attrp->opz_equcls, (char *)&unionbm);
		}
	    }
	    {	/* search list of conjuncts, boolean factor structure has
		** not been created at this point */
		OPB_IBF	    total_bfs;	/* number of qualifications placed into
					** union view list */
		PST_QNODE   *qual;

		total_bfs = 0;
		for (qual = subquery->ops_root->pst_right;
		    qual->pst_sym.pst_type != PST_QLEND;
		    qual = qual->pst_right)
		{
		    OPE_BMEQCLS	    qual_eqcmp;
		    MEfill(sizeof(qual_eqcmp), (u_char)0, (PTR)&qual_eqcmp);
		    ope_aseqcls(subquery, &qual_eqcmp, qual->pst_left);
					/* assign
                                        ** equivalence classes for vars in
                                        ** the qualification which have not
                                        ** been assigned yet
                                        */
		    if (BTsubset((char *)&qual_eqcmp, (char *)&unionbm, (i4)BITS_IN(unionbm))
			&&
			!(subquery->ops_oj.opl_base &&
			(qual->pst_left->pst_sym.pst_value.pst_s_op.pst_joinid
			!= OPL_NOOUTER)))
		    {	/* this boolean factor contains equivalence classes which
			** are all in the union view, so it can be evaluated inside
			** the union view */
			if (union_subquery->ops_sunion.opu_mask & OPU_QUAL)
			{   /* qualification must already be in the list
			    ** so compare to existing list of entries */
			    PST_QNODE	    *old_qual;
			    OPB_IBF	    bfcount;
			    bfcount = 0;
			    for (old_qual = union_subquery->ops_sunion.opu_qual;
				old_qual; old_qual = old_qual->pst_right)
			    {
				if (BTtest((i4)bfcount, (char *)&bfbm) /* if this
						    ** boolean factor has not been
						    ** matched */
				    &&
				    opj_ctree(subquery, qual->pst_left, lvar,
					union_subquery, old_qual->pst_left) /*
						    ** and if the qualification
						    ** matches the current one */
				    )
				{   /* found a match so mark the boolean
				    ** factor as being in common */
				    BTclear((i4)bfcount, (char *)&bfbm);
				    break;
				}
				bfcount++;
			    }
			}
			else
			{   /* if this is the first time then just copy the
			    ** qualification and place into the list */
			    PST_QNODE	    *and_node;
			    total_bfs++;
			    if (total_bfs >= BITS_IN(unionbm))
				break;		    /* cannot add anymore qualifications
						    ** since the max boolean factor
						    ** count has been reached */
			    and_node = opv_opnode(subquery->ops_global, PST_AND, (ADI_OP_ID)0,
				(OPL_IOUTER)OPL_NOOUTER);
			    and_node->pst_left = qual->pst_left;
			    opv_copytree(subquery->ops_global, &and_node->pst_left);
			    and_node->pst_right = union_subquery->ops_sunion.opu_qual;
			    union_subquery->ops_sunion.opu_qual = and_node;
                            if(subquery->ops_mask & OPS_NONCNF)
                            {
				union_subquery->ops_mask |= OPS_NONCNF;
			    }

			}
		    }
		}
	    }
	    if (union_subquery->ops_sunion.opu_mask & OPU_QUAL)
	    {	/* previous qualification exists so need to get common qualifications,
		** by using boolean factor bitmap of those qualifications which are
		** to be eliminated */
		OPB_IBF		bfno;
		PST_QNODE	**qualpp;
		OPB_IBF		current;

		current = 0;
		qualpp = &union_subquery->ops_sunion.opu_qual;
		for (bfno = -1; (bfno = BTnext((i4)bfno, (char *)&bfbm, (i4)maxbf)) >= 0;)
		{
		    while ((current < bfno) && *qualpp)
		    {	/* find next qualification to eliminate */
			current++;
			qualpp = &(*qualpp)->pst_right;
		    }
		    if (*qualpp)
			*qualpp = (*qualpp)->pst_right; /* remove this qual since
					    ** no match was found for this subquery */
		    else
			break;		    /* end of qual list reached */
		}
	    }
	    else
	    {	/* this is the first qualification in the list, so it can be applied */
		union_subquery->ops_sunion.opu_mask |= OPU_QUAL;
		if (union_subquery->ops_sunion.opu_qual)
		    opj_utree(subquery, union_subquery->ops_sunion.opu_qual, lvar); /* 
					    ** convert the 
					    ** qualification to reference var nodes
					    ** of the union view, so that comparisons
					    ** can be made later */
	    }
	}
    }
}
コード例 #3
0
/*{
** Name: opn_gnperm	- get next valid permutation of relations
**
** Description:
**	A valid permutation of relations is a group of relations
**	that provide the necessary data (eqc classes) to process
**	the query. The equivalence classes provided by the base
**	relations must be provided by this resulting permutiation
**	either through the use of the base relations themselves
**	or through their own secondary indexes.
**
**      Relations move back and forth between the 2 partitions.
**      There must be exactly 2 partitions where partsz[0] is the number of 
**	relations to be considered for enumeration and partsz[1] contain the
**	remainder.  Each call will produce
**      a "new" set (where order does not matter) of relations
**      in the first partition which satisfy the constraints mentioned
**      earlier.
**      
**      FIXME - can make this routine go much faster by calculating which
**      relations can be replaced by indexes and iterating through all
**      combinations of those only i.e. there will be 3 partitions, 1)the
**      primaries, 2)the set of indexes which cannot ever be 
**      used to replace the base
**      relation, and 3)the set of indexes which can.  Iterate through
**      all combinations of (1&3), for each subset of 2
**
**      Also, can decide that if an index was included to replace the
**      base relation, then any indexes on that relation would not be
**      useful if the relation was not included, and eliminate that case here
**      since a scan is required anyways.  An improvement would be to detect
**      that a keyed lookup would be useful on these indexes 
**
** Inputs:
**      subquery                        ptr to current subquery being analyzed
**      permutation                     current permutation of relations
**      numleaves                       number of relations in permutation
**      partsz                          array of partition sizes where partsz[0]
**                                      is the size of the first partition
**                                      "partsz[0]+partsz[1] == numleaves"
**      pr_n_included                   map of base relations not included in
**                                      valid partition
**	firstcomb			TRUE - combination was set by opn_process
**					so we're just checking heuristics
**
** Outputs:
**	Returns:
**	    TRUE if another permutation exists
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**	11-jun-86 (seputis)
**          initial creation
**	29-mar-89 (seputis)
**          gateway additions
**	29-mar-90 (seputis)
**          fix byte alignment problems
**	1-apr-94 (ed)
**	    b60125 - cart prod variable incorrectly eliminated
**	27-aug-02 (inkdo01)
**	    Apply heuristics to initial combination generated by opn_process
**	    so some index heuristics aren't applied to all permutations of a 
**	    bad combination in opn_jintersect.
**	21-mar-06 (dougi)
**	    Verify that current combination satisfies index hints (if any).
[@history_line@]...
*/
bool
opn_gnperm(
	OPS_SUBQUERY       *subquery,
	OPN_STLEAVES	   permutation,
	OPN_LEAVES	   numleaves,
	OPN_PARTSZ         partsz,
	OPV_BMVARS         *pr_n_included,
	bool		   firstcomb)
{
    OPN_CHILD           numpartitions;		/* number of partitions */
    OPV_IVARS           maxprimary;		/* number of primary joinop 
                                                ** range variables in the
                                                ** query */
    OPV_RT              *vbase;			/* ptr to base of array of
                                                ** ptrs to joinop range
                                                ** variables */
    OPN_LEAVES          firstpartsz;		/* number of elements in the
                                                ** first partition */
    OPE_IEQCLS          maxeqcls;		/* number of equivalence classes
                                                ** defined */
    bool		indexes_gateway;	/* TRUE if subquery contains secondaries
						** on restricted gateway tables */

    maxeqcls = subquery->ops_eclass.ope_ev;	/* get number of equivalence
                                                ** classes in subquery */

    maxprimary = subquery->ops_vars.opv_prv;    /* number of primary relations
                                                ** defined */
    numpartitions = 2;                          /* number of partitions of the
                                                ** set of relations is always 2
                                                ** - first partition contains
                                                ** the set of relations which
                                                ** will be considered for 
                                                ** the next enumeration
                                                ** - second partition contains
                                                ** relations which are not being
                                                ** considered for this
                                                ** enumeration */
    vbase = subquery->ops_vars.opv_base;        /* ptr to base of array of ptrs
                                                ** to joinop range variables */
    firstpartsz = partsz[0];                    /* number of elements in first
                                                ** partition */
    indexes_gateway = (subquery->ops_gateway.opg_smask
	& OPG_INDEX) != 0;			/* gateway mask indicates whether
						** indexes need to be checked */
    /* Return when a valid partition has been found */
    for (;;)
    {
	if (!firstcomb && numleaves == firstpartsz)
	    return(FALSE);			/* no combinations and it failed
						** heuristics */
	/* Get next partition */
	if (!firstcomb && !opn_partition(subquery, permutation, numleaves, 
		partsz, numpartitions, FALSE))
	    return(FALSE);			/* no more partitions */

	firstcomb = FALSE;			/* reset for loop */
	MEfill(sizeof(*pr_n_included), (u_char)0, (PTR)pr_n_included);
        BTnot((i4)maxprimary, (char *)pr_n_included); /* all base relations are
                                                ** not included */
	
	{   /* For each element in the partition, find out if it is a 
	    ** base relation */
	    OPV_IVARS          partvarno;	/* joinop range variable in the
                                                ** first partition */
	    OPV_BMVARS          replaced;	/* bitmap of vars that should
                                                ** be replaced */
	    OPV_BMVARS		table_gateway;	/* for gateways, there are tables
						** which cannot accessed by TID joins
						** but secondaries can be used to
						** replace the base relation
						** entirely */
	    bool		skip_gateway;	/* set TRUE if this particular set of
						** relations references both a base table
						** and a secondary index , which is
						** not supported for gateway tables */
	    
	    if (indexes_gateway)
		MEfill(sizeof(table_gateway), (u_char)0, (PTR)&table_gateway);
	    skip_gateway = FALSE;
	    MEfill(sizeof(replaced), (u_char)0, (PTR)&replaced);
	    for (partvarno = 0; partvarno < firstpartsz; partvarno++)
	    {
		OPV_IVARS	vno;		/* variable being analzyed */
		OPV_VARS	*ivarp;		/* ptr to index range variable*/


		vno = permutation[partvarno];
		ivarp = vbase->opv_rt[vno];
		/* if its included, don't worry about it */
		if (vno < maxprimary)
		    BTclear((i4) vno, (char *)pr_n_included);
		else 
		{
		    if ( ivarp->opv_index.opv_eqclass == OPE_NOEQCLS ||
			ivarp->opv_mask & OPV_CINDEX )
			/* set bitmap if index was added only to replace
                        ** base relation */
			BTset ( (i4) ivarp->opv_index.opv_poffset,
			        (char *) &replaced );
		}
		if (indexes_gateway
		    &&
		    ivarp->opv_grv->opv_relation    /* if this is an RDF relation */
		    &&
		    (ivarp->opv_grv->opv_relation->rdr_rel->tbl_status_mask & DMT_GATEWAY) /* is this
						** a gateway table */
		    &&
		    (subquery->ops_global->ops_cb->ops_server->opg_smask & OPF_INDEXSUB)
		    				/* and the gateway relation has index
						** constraints on it */
		    &&
		    (vno != ivarp->opv_index.opv_poffset) /* do not consider the primary
						** relation for this test */
		    )
		{   /* check constraint on secondary index access for gateway */
		    if (BTtest((i4)ivarp->opv_index.opv_poffset, (char *)&table_gateway))
		    {
			skip_gateway = TRUE;	/* this base relation was referenced
						** previously by this set, so this set
						** of relations needs to be skipped */
			break;
		    }
		    BTset((i4)ivarp->opv_index.opv_poffset, (char *)&table_gateway); /*
						** if only one index for this table in this
						** partition then it is legal, so mark
						** base table bit so that 2+ index search
						** space is eliminated */
		}
	    }
            if ((!BTsubset((char *)&replaced, (char *)pr_n_included, (i4)maxprimary))
		||
		skip_gateway)
		continue;			/* this is a useless partition
                                                ** since an index and the 
                                                ** respective base relation it
                                                ** was intended to replace are
                                                ** both included 
						** OR a restricted gateway table
						** was accessed */

	    if ((subquery->ops_mask2 & OPS_IXHINTS) &&
		!opn_index_hint(subquery, permutation, partsz[0]))
		continue;			/* if there are index hints in
						** this subquery and the 
						** current combination doesn't
						** satisfy them, get the next */
	}

	{
	    OPV_IVARS          varno;		/* varno of primary which was
                                                ** not included */
	    bool	       noprimary;       /* TRUE if no primaries were
                                                ** replaced */
	    noprimary = TRUE;
	    for (varno = -1; 
		 (varno = BTnext((i4)varno, 
				 (char *)pr_n_included, 
				 (i4)maxprimary))
		 >= 0;)
	    {	/* initialize temp equivalence class map associated with
                ** primary relations - the map will be used to gather
                ** all equivalence classes which the indexes provide */

		noprimary = FALSE;
		MEfill( sizeof(vbase->opv_rt[varno]->opv_primary.opv_teqcmp),
			(u_char)0,
			(PTR)&vbase->opv_rt[varno]->opv_primary.opv_teqcmp);/* 
						** init temporary work 
                                                ** area of joinop range 
						** variable element */
	    }
	    if (noprimary)
		return(TRUE);			/* no need to check indexes
                                                ** since no primaries were
                                                ** replaced */
	}
	

	{
	    /* For each index being included in the partition, add the available
	    ** equivalence classes to the primary's map
	    */
	    OPV_IVARS          indexvarno;	/* joinop range var number of
                                                ** index being analyzed */

	    for (indexvarno = 0; indexvarno < firstpartsz; indexvarno++)
	    {
		OPV_VARS           *indexp;     /* ptr to joinop range var 
                                                ** element of current index 
                                                ** being analyzed */
		if(permutation[indexvarno] < maxprimary)
		    continue;			/* not an index so continue*/
		indexp = vbase->opv_rt[permutation[indexvarno]]; /* get ptr 
                                                ** to index element */
		BTor( (i4)maxeqcls,
		      (char *)&indexp->opv_maps.opo_eqcmap,
		      (char *)&vbase->opv_rt[indexp->opv_index.opv_poffset]->
			    opv_primary.opv_teqcmp); /* accumulate all
                                                ** all equivalence classes
                                                ** available from indexes in
                                                ** the temp associated with
                                                ** the primary */
	    }
	}

	{
	    /* check if each primary which is replaced has all the necessary
            ** equivalence classes available from the indexes */
	    OPV_IVARS          primvarno;	/* joinop range variable
                                                ** number of primary which
                                                ** is not included */
	    for (primvarno = -1; 
		(primvarno = BTnext((i4)primvarno, 
				    (char *)pr_n_included, 
				    (i4) maxprimary))
		 >= 0;)
	    {
	        OPV_VARS           *primvarp;   /* ptr to primary joinop range
                                                ** var element to be
                                                ** replaced */
		primvarp = vbase->opv_rt[primvarno]; /* get ptr to primary to
                                                ** be replaced */
		if (!BTsubset( (char *)&primvarp->opv_maps.opo_eqcmap,
			       (char *)&primvarp->opv_primary.opv_teqcmp,
			       (i4)maxeqcls)
		    ||
		    (primvarp->opv_mask & OPV_NOATTRIBUTES)) /* check if this
						** is a no attribute cart prod
						** in which case the base relation
						** is not removed */
		    break;			/* if there are equivalence
                                                ** classes in the primary which
                                                ** are not in the set provided
                                                ** by the indexes then exit
                                                ** with primvarno >= 0 */
	    }
	    if (primvarno < 0)
		return (TRUE);			/* all the primaries have been
                                                ** successfully replaced */
	}
    }
}
コード例 #4
0
ファイル: opnjmaps.c プロジェクト: saqibjamil/Ingres
/*{
** Name: opn_jmaps	- set various join operator tree maps
**
** Description:
{@comment_line@}...
**
** Inputs:
**      subquery                        ptr to subquery being analyzed
**      nodep                           ptr to current operator node which
**                                      will have maps initialized
**	ojmap				NULL if no outer joins exist
**					- map of outer joins which are
**					evaluated in parent nodes.
**
** Outputs:
**      nodep->opn_eqm                  set of equivalence class available
**                                      from subtree
**      nodep->opn_rlmap                bitmap of relations in the subtree
**      nodep->opn_rlasg                order in which the relations in
**                                      opn_rlmap are assigned to the leaves
**	Returns:
**	    TRUE if there is a valid placement of subselect nodes with
**          all required equivalence classes available for execution of the
**          boolean factor used for the subselect
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**	11-jun-86 (seputis)
**          initial creation from setjmaps
**      29-mar-90 (seputis)
**          fix byte alignment problems
**	2-apr-91 (seputis)
**	    only partially copied relation assignment causing run_all diffs
**	    fix for b35461, this would cause the OPF cache of query plans
**	    to not be effectively used, and could cause performance problems
**	    on non-VMS systems.  This fix should be used whenever a poor
**	    query plan bug is reported which cannot be reproduced on VMS.
**      15-feb-94 (ed)
**          - bug 59598 - correct mechanism in which boolean factors are
**          evaluated at several join nodes
**      11-apr-94 (ed)
**          - bug 59937 - E_OP0489 consistency check due to inner join ojid
**          not being visible in boolean factor placement maps
**	31-jul-97 (inkdo01)
**	    Fix to force SVAR func atts ref'ed in ON clauses to materialize
**	    just before needed (to incorporate proper null semantics).
**	 9-jul-99 (hayke02 for inkdo01)
**	    Set opn_eqm bits in lower level nodes (e.g. leaf nodes) when
**	    func attrs are found in higher level OJ nodes. This change
**	    fixes bug 92749.
**	20-Mar-02 (wanfr01)
**	    Bug 106678, INGSRV 1633
**	    Confirm function attribute as an ojid before associating it
**	    with an outer join node.
**	16-sep-03 (hayke02)
**	    Check for OPN_OJINNERIDX in nodep->opn_jmask to indicate that
**	    placement of a coverqual inner index outer join needs to be
**	    checked.
**	28-apr-04 (hayke02)
**	    Modify previous change so that we return FALSE and reject the QEP
**	    if the index outer join node (node->LEFT) has a non-zero opn_nchild
**	    for node->LEFT->RIGHT. This will allow only QEPs where the OJ
**	    inner is the index only and not the index joined to another
**	    relation. This change fixes problem INGSRV 2808, bug 112211.
**      05-Oct-2004 (huazh01)
**          Remove the above fix. The fix for 111627 handles b106678
**          as well. This fixes b113160, INGSRV2984. 
**	14-mar-05 (hayke02)
**	    Modify the fix for problem INGSRV 2808, bug 112211 so that we now
**	    check for more than 1 var in the opl_ivmap. This now allows the
**	    correct rejection of plans that have had their opn_child's set up
**	    with left joins 'reversed' into right joins. This change fixes
**	    problems INGSRV 3049 and 3094, bugs 113457 and 113990.
**	23-sep-05 (hayke02)
**	    Check for a WHERE clause (OPL_NOOOUTER opz_ojid) OJSVAR func att,
**	    and make sure that all OJs that this func att is inner to are
**	    executed before the join involving this func att. This change fixes
**	    bug 114912.
**	30-jan-07 (hayke02)
**	    Disable the fix for bug 114912 for cart prod (OPL_BOJCARTPROD) OJs.
**	    This change fixes bug 117513.
**	27-Oct-2009 (kiria01) SIR 121883
**	    Scalar sub-selects - protect subp->opv_eqcrequired from bad de-ref.
[@history_line@]...
*/
bool
opn_jmaps(
	OPS_SUBQUERY       *subquery,
	OPN_JTREE          *nodep,
	OPL_BMOJ	   *ojmap)
{
	OPL_OUTER	    *outerp;

    if (nodep->opn_nleaves == 1)
    {	/* leaf node */
	OPV_IVARS              varno;		/* joinop range variable number
                                                ** of leaf */

	varno = nodep->opn_prb[0];		/* by definition of leaf - only
                                                ** one variable in partition */
	nodep->opn_rlasg[0] = varno;            /* trivial ordering for leaf */
	MEfill( sizeof(nodep->opn_rlmap), (u_char)0, (PTR)&nodep->opn_rlmap );
	if (subquery->ops_oj.opl_lv > 0)
	{
	    MEfill( sizeof(nodep->opn_ojinnermap),
		(u_char)0, (PTR)&nodep->opn_ojinnermap);
	    MEfill( sizeof(nodep->opn_ojevalmap),
		(u_char)0, (PTR)&nodep->opn_ojevalmap);
	    opl_sjij(subquery, varno, &nodep->opn_ojinnermap, ojmap);
	}
	BTset((i4)varno, (char *)&nodep->opn_rlmap); /* only one bit set for leaf*/
	MEcopy ((PTR)&subquery->ops_vars.opv_base->opv_rt[varno]->opv_maps.opo_eqcmap,
	    sizeof(nodep->opn_eqm), (PTR)&nodep->opn_eqm ); /* copy map of
                                                ** equivalence classes 
						** associated with varno of this
                                                ** leaf */

	return(TRUE);
    }
    else
    {	/* non-leaf node */
	OPN_JTREE              *leftchildp;	/* ptr to left child node */
	OPN_JTREE              *rightchildp;	/* ptr to right child node */

	leftchildp = nodep->opn_child[OPN_LEFT];
	rightchildp = nodep->opn_child[OPN_RIGHT];
	if (ojmap)
	{
	    MEfill(sizeof(nodep->opn_ojevalmap), (u_char)0,
		(PTR)&nodep->opn_ojevalmap);
	    if( (nodep->opn_ojid >= 0)
		&&
		!BTtest((i4)nodep->opn_ojid, (char *)ojmap))
	    {   /* setup the outer join map which contains all outer joins
		** which are completely evaluated within this subtree */
		BTset((i4)nodep->opn_ojid, (char *)&nodep->opn_ojevalmap);
		BTset((i4)nodep->opn_ojid, (char *)ojmap);
	    }
	}
	if (!opn_jmaps (subquery, leftchildp, ojmap))	/* get info on left child */
	    return(FALSE);
	if (!opn_jmaps (subquery, rightchildp, ojmap))	/* get info on right child */
	    return(FALSE);

	MEcopy ((PTR)&leftchildp->opn_rlmap,
		sizeof(nodep->opn_rlmap),
		(PTR)&nodep->opn_rlmap );	/* get var bitmap from left
                                                ** child */
	BTor(	(i4)BITS_IN(nodep->opn_rlmap),
		(char *)&rightchildp->opn_rlmap,
		(char *)&nodep->opn_rlmap );	/* "OR" rightchildp->opn_rlmap
						** into nodep->opn_rlmap */
	if (ojmap)
	{   /* setup ojinnermap which contains all outer joins which are
	    ** partially or totally evaluated within this subtree, but 
	    ** not at this node unless it is in the subtree */
	    MEcopy((PTR)&leftchildp->opn_ojinnermap,
		sizeof(leftchildp->opn_ojinnermap),
		(PTR)&nodep->opn_ojinnermap);
	    BTor((i4)BITS_IN(rightchildp->opn_ojinnermap),
                (char *)&rightchildp->opn_ojinnermap,
                (char *)&nodep->opn_ojinnermap);
	    if (leftchildp->opn_ojid >= 0)
		BTset((i4)leftchildp->opn_ojid, (char *)&nodep->opn_ojinnermap);
	    if (rightchildp->opn_ojid >= 0)
		BTset((i4)rightchildp->opn_ojid, (char *)&nodep->opn_ojinnermap);
	    if (subquery->ops_mask & OPS_IJCHECK)
		opl_ijcheck(subquery, &leftchildp->opn_ojinnermap,
		    &rightchildp->opn_ojinnermap, &nodep->opn_ojinnermap,
		    &leftchildp->opn_ojevalmap, &rightchildp->opn_ojevalmap,
		    &nodep->opn_rlmap);
	    /* map of outerjoins which are entirely evaluated within
	    ** this subtree */
	    BTor((i4)BITS_IN(leftchildp->opn_ojevalmap),
                (char *)&leftchildp->opn_ojevalmap,
                (char *)&nodep->opn_ojevalmap);
	    BTor((i4)BITS_IN(rightchildp->opn_ojevalmap),
                (char *)&rightchildp->opn_ojevalmap,
                (char *)&nodep->opn_ojevalmap);
	    if ((nodep->opn_jmask & OPN_OJINNERIDX) &&
		((nodep->opn_ojid != nodep->opn_child[OPN_LEFT]->opn_ojid) ||
		((nodep->opn_ojid == nodep->opn_child[OPN_LEFT]->opn_ojid) &&
		(nodep->opn_ojid >= 0) &&
		(BTcount((char *)subquery->ops_oj.opl_base->opl_ojt
		[nodep->opn_ojid]->opl_ivmap, subquery->ops_vars.opv_rv) > 1))))
		return(FALSE);
	}
	MEcopy ((PTR)leftchildp->opn_rlasg,
		leftchildp->opn_nleaves * sizeof(nodep->opn_rlasg[0]),
		(PTR)nodep->opn_rlasg);		/* get relations from left
                                                ** child */
	MEcopy ((PTR)rightchildp->opn_rlasg,
		rightchildp->opn_nleaves * sizeof(nodep->opn_rlasg[0]),
		(PTR)(nodep->opn_rlasg + leftchildp->opn_nleaves)); /* get
                                                ** relations from right child
                                                ** and place them beside the
                                                ** ones from the left child */

	MEcopy ((PTR)&leftchildp->opn_eqm,
		sizeof(nodep->opn_eqm),
		(PTR)&nodep->opn_eqm );		/* copy equivalence class map
                                                ** from left child to this node 
                                                */
	BTor(	(i4)BITS_IN(nodep->opn_eqm),
		(char *)&rightchildp->opn_eqm,
		(char *)&nodep->opn_eqm );	/* "OR" right child equivalence
                                                ** map into this to produce 
                                                ** map for this node */
	if (subquery->ops_joinop.opj_virtual)
	{   /* there is a subselect in this query so check for availability
            ** of equivalence classes used for evaluation of boolean factors
	    ** containing the subselect
            */
	    OPV_SUBSELECT	*subp;		/* ptr to subselect descriptor
                                                ** for range variable */
	    if  (   (rightchildp->opn_nleaves == 1)
		    &&
		    (
			subp = subquery->ops_vars.opv_base->
			    opv_rt[rightchildp->opn_prb[0]]->opv_subselect
		    )
		)
	    {	/* right child is a subselect so test for correct leaf
                ** placement */
		if (!subp->opv_eqcrequired ||
			!BTsubset(	(char *)subp->opv_eqcrequired,
				(char *)&nodep->opn_eqm,
				(i4)BITS_IN(OPE_BMEQCLS)
			    )
		    )
		    return (FALSE);		/* cannot evaluate all boolean
                                                ** factors with SEJOIN nodes
                                                ** in this configuration */
		else
		{   /* check if all corelated variables are available in the
		    ** outer - FIXME create another pointer field which
                    ** contains this information so this loop is avoided */
		    for (;subp; subp = subp->opv_nsubselect)
		    {
			if (!BTsubset(	(char *)&subp->opv_eqcmp,
					(char *)&leftchildp->opn_eqm,
					(i4)BITS_IN(OPE_BMEQCLS)
				    )
			    )
			    return (FALSE);	/* not all correlated
                                                ** equivalence classes
						** are available from the outer
						** so return */
		    }
		}
	    }
	    if  (   (leftchildp->opn_nleaves == 1)
		    &&
		    (subp = subquery->ops_vars.opv_base->
			opv_rt[leftchildp->opn_prb[0]]->opv_subselect)
		)
	    {
		if (!subp->opv_eqcrequired ||
			!BTsubset(	(char *)subp->opv_eqcrequired,
				(char *)&nodep->opn_eqm,
				(i4)BITS_IN(OPE_BMEQCLS)
			    )
		    )
		    return (FALSE);		/* cannot evaluate all boolean
                                                ** factors with SEJOIN nodes
                                                ** in this configuration */
		else
		{   /* check if all corelated variables are available in the
		    ** outer - FIXME create another pointer field which
                    ** contains this information so this loop is avoided */
		    for (;subp; subp = subp->opv_nsubselect)
		    {
			if (!BTsubset(	(char *)&subp->opv_eqcmp,
					(char *)&rightchildp->opn_eqm,
					(i4)BITS_IN(OPE_BMEQCLS)
				    )
			    )
			    return (FALSE);	/* not all correlated
                                                ** equivalence classes
						** are available from the outer
						** so return */
		    }
		}
	    }
	}
	if ((subquery->ops_oj.opl_lv > 0)
	    &&
	    (nodep->opn_ojid != OPL_NOOUTER))
	{
	    OPV_IVARS	    maxvar;

	    /* this is an outer join function attribute which should
	    ** only appear at the point that the outer join is
	    ** actually performed */
	    maxvar = subquery->ops_vars.opv_rv;
	    outerp = subquery->ops_oj.opl_base->opl_ojt[nodep->opn_ojid];
	    if ((outerp->opl_type == OPL_LEFTJOIN)
		||
		(outerp->opl_type == OPL_FULLJOIN))
	    {
		OPV_BMVARS	tempvmap;
		OPV_IVARS	innervar;

		MEcopy((PTR)outerp->opl_maxojmap, sizeof(tempvmap),
		    (PTR)&tempvmap);
		BTand((i4)BITS_IN(tempvmap), (char *)&nodep->opn_rlmap,
		    (char *)&tempvmap);
		for (innervar = -1; (innervar = BTnext((i4)innervar,
		    (char *)&tempvmap, (i4)maxvar))>=0;)
		{
		    OPE_IEQCLS	    ojeqcls;
		    ojeqcls = subquery->ops_vars.opv_base->opv_rt
			[innervar]->opv_ojeqc;
		    if (ojeqcls != OPE_NOEQCLS)
			BTset((i4)ojeqcls, (char *)&nodep->opn_eqm);
		}
	    }
	}
	{   /* determine multi-variable functions that can first be calculated
            ** at this node 
	    */
	    OPZ_IFATTS         fattr;		/* current function attribute
                                                ** being analyzed */
	    OPZ_IFATTS	       maxfattr;        /* maximum number of function
                                                ** attributes defined */
	    OPZ_FT             *fbase;          /* ptr to base of array of ptrs
                                                ** to function attribute
                                                ** elements */
	    OPZ_AT	       *abase;          /* ptr to base of array of ptrs
                                                ** to joinop attribute elements
                                                */
	    maxfattr = subquery->ops_funcs.opz_fv; /* number of function
                                                ** attributes defined */
	    fbase = subquery->ops_funcs.opz_fbase; /* ptr to base of array
                                                ** of function attributes */
	    abase = subquery->ops_attrs.opz_base; /* ptr to base of array
						** of ptrs to joinop attribute
                                                ** elements */
	    for (fattr = 0; fattr < maxfattr ; fattr++)
	    {
		OPZ_FATTS             *fattrp;	/* ptr to current function
                                                ** attribute being analyzed */
		OPE_IEQCLS            eqcls;    /* equivalence class of the
                                                ** multi-variable function
                                                ** attribute */

		fattrp = fbase->opz_fatts[fattr];
		eqcls = abase->opz_attnums[fattrp->opz_attno]->opz_equcls; /*
						** equivalence class associated
                                                ** with the multi-variable
                                                ** function attribute */
		/* check for WHERE clause (OPL_NOOUTER opz_ojid) OJSVAR func att
		** and then make sure that all OJs that this func att is inner
		** to are executed before the join involving this func att
		*/
		if (fattrp->opz_type == OPZ_SVAR
		    &&
		    (fattrp->opz_mask & OPZ_OJSVAR)
		    &&
		    nodep->opn_ojid != OPL_NOOUTER
		    &&
		    fattrp->opz_ojid == OPL_NOOUTER
		    &&
		    (fattrp->opz_ijmap
		    &&
		    BTtest((i4)nodep->opn_ojid, (char *)fattrp->opz_ijmap)
		    &&
		    !(outerp->opl_mask & OPL_BOJCARTPROD)))
		{
		    OPZ_IATTS		attno;
		    bool		allinrlmap = TRUE;
		    OPE_EQCLIST		*eqclsp;

		    eqclsp = subquery->ops_eclass.ope_base->ope_eqclist[eqcls];
		    for (attno = -1;  (attno = BTnext((i4)attno,
			(PTR)&eqclsp->ope_attrmap,
			(i4)subquery->ops_attrs.opz_av)) != -1; )
		    {
			if (!BTtest((i4)abase->opz_attnums[attno]->opz_varnm,
						    (char *)&nodep->opn_rlmap))
			{
			    allinrlmap = FALSE;
			    break;
			}
		    }
		    if (allinrlmap)
			return(FALSE);
		}
		if ((fattrp->opz_type != OPZ_MVAR)
		    && !(fattrp->opz_type == OPZ_SVAR &&
			 fattrp->opz_mask & OPZ_OJSVAR &&
			 fattrp->opz_ojid == nodep->opn_ojid)
		    ||
		    (fattrp->opz_mask & OPZ_OJFA))
		    continue;			/* only multi-variable 
						** functions are assigned here 
						** (and SVARs in ON clauses
						** of OJs eval'd at this node)
						** since others where assigned
                                                ** earlier, ... also outer join
						** special eqc were assigned 
						** prior to this loop */
		if (fattrp->opz_type == OPZ_SVAR)
		{
		    /* Must be ON clause ref'ed SVAR. Set bit in whichever
		    ** child node covers the SVAR eqcmap. */
		    if (BTsubset((char *)&fattrp->opz_eqcm,
			(char *)&nodep->opn_child[1]->opn_eqm,
			(i4)BITS_IN(nodep->opn_eqm)))
		     BTset((i4)eqcls, (char *)&nodep->opn_child[1]->opn_eqm);
		    else if (BTsubset((char *)&fattrp->opz_eqcm,
			(char *)&nodep->opn_child[0]->opn_eqm,
			(i4)BITS_IN(nodep->opn_eqm)))
		     BTset((i4)eqcls, (char *)&nodep->opn_child[0]->opn_eqm);
						/* set fattr eqcls bit in 
						** proper child opn_eqm */
		    continue;
		}
		if (BTtest( (i4)eqcls, (char *)&nodep->opn_eqm))
			continue;		/* if function attribute has
                                                ** been added then
                                                ** continue */
		if (BTsubset((char *)&fattrp->opz_eqcm,
			     (char *)&nodep->opn_eqm,
			     (i4)BITS_IN(nodep->opn_eqm))
		    )
		    BTset((i4)eqcls, (char *)&nodep->opn_eqm); /* set bit if all 
                                                ** the required equivalence 
                                                ** classes are available 
                                                ** for the function attribute
                                                */
	    }
	}
    }
    return(TRUE);
}