//--------------------------------------------------------------------------- // @function: // CXformLeftSemiJoin2InnerJoin::Transform // // @doc: // actual transformation // //--------------------------------------------------------------------------- void CXformLeftSemiJoin2InnerJoin::Transform ( CXformContext *pxfctxt, CXformResult *pxfres, CExpression *pexpr ) const { GPOS_ASSERT(NULL != pxfctxt); GPOS_ASSERT(FPromising(pxfctxt->Pmp(), this, pexpr)); GPOS_ASSERT(FCheckPattern(pexpr)); IMemoryPool *mp = pxfctxt->Pmp(); // extract components CExpression *pexprOuter = (*pexpr)[0]; CExpression *pexprInner = (*pexpr)[1]; CExpression *pexprScalar = (*pexpr)[2]; pexprOuter->AddRef(); pexprInner->AddRef(); pexprScalar->AddRef(); // construct grouping columns by collecting used columns in the join predicate // that come from join's inner child CColRefSet *pcrsOuterOutput = CDrvdPropRelational::GetRelationalProperties(pexprOuter->PdpDerive())->PcrsOutput(); CColRefSet *pcrsUsed = CDrvdPropScalar::GetDrvdScalarProps(pexprScalar->PdpDerive())->PcrsUsed(); CColRefSet *pcrsGb = GPOS_NEW(mp) CColRefSet(mp); pcrsGb->Include(pcrsUsed); pcrsGb->Difference(pcrsOuterOutput); GPOS_ASSERT(0 < pcrsGb->Size()); CKeyCollection *pkc = CDrvdPropRelational::GetRelationalProperties(pexprInner->PdpDerive())->Pkc(); if (NULL == pkc || (NULL != pkc && !pkc->FKey(pcrsGb, false /*fExactMatch*/))) { // grouping columns do not cover a key on the inner side, // we need to create a group by on inner side CColRefArray *colref_array = pcrsGb->Pdrgpcr(mp); CExpression *pexprGb = GPOS_NEW(mp) CExpression ( mp, GPOS_NEW(mp) CLogicalGbAgg(mp, colref_array, COperator::EgbaggtypeGlobal /*egbaggtype*/), pexprInner, GPOS_NEW(mp) CExpression(mp, GPOS_NEW(mp) CScalarProjectList(mp)) ); pexprInner = pexprGb; } CExpression *pexprInnerJoin = CUtils::PexprLogicalJoin<CLogicalInnerJoin>(mp, pexprOuter, pexprInner, pexprScalar); pcrsGb->Release(); pxfres->Add(pexprInnerJoin); }