//--------------------------------------------------------------------------- // @function: // CPhysicalStreamAgg::PosCovering // // @doc: // Construct order spec on grouping column so that it covers required // order spec, the function returns NULL if no covering order spec // can be created // //--------------------------------------------------------------------------- COrderSpec * CPhysicalStreamAgg::PosCovering ( IMemoryPool *mp, COrderSpec *posRequired, CColRefArray *pdrgpcrGrp ) const { GPOS_ASSERT(NULL != posRequired); if (0 == posRequired->UlSortColumns()) { // required order must be non-empty return NULL; } // create a set of required sort columns CColRefSet *pcrsReqd = posRequired->PcrsUsed(mp); COrderSpec *pos = NULL; CColRefSet *pcrsGrpCols = GPOS_NEW(mp) CColRefSet(mp, pdrgpcrGrp); if (pcrsGrpCols->ContainsAll(pcrsReqd)) { // required order columns are included in grouping columns, we can // construct a covering order spec pos = GPOS_NEW(mp) COrderSpec(mp); // extract order expressions from required order const ULONG ulReqdSortCols = posRequired->UlSortColumns(); for (ULONG ul = 0; ul < ulReqdSortCols; ul++) { CColRef *colref = const_cast<CColRef *>(posRequired->Pcr(ul)); IMDId *mdid = posRequired->GetMdIdSortOp(ul); COrderSpec::ENullTreatment ent = posRequired->Ent(ul); mdid->AddRef(); pos->Append(mdid, colref, ent); } // augment order with remaining grouping columns const ULONG size = pdrgpcrGrp->Size(); for (ULONG ul = 0; ul < size; ul++) { CColRef *colref = (*pdrgpcrGrp)[ul]; if (!pcrsReqd->FMember(colref)) { IMDId *mdid = colref->RetrieveType()->GetMdidForCmpType(IMDType::EcmptL); mdid->AddRef(); pos->Append(mdid, colref, COrderSpec::EntLast); } } } pcrsGrpCols->Release(); pcrsReqd->Release(); return pos; }
//--------------------------------------------------------------------------- // @function: // CPhysicalDML::PosComputeRequired // // @doc: // Compute required sort order based on the key information in the table // descriptor: // 1. If a table has no keys, no sort order is necessary. // // 2. If a table has keys, but they are not modified in the update, no sort // order is necessary. This relies on the fact that Split always produces // Delete tuples before Insert tuples, so we cannot have two versions of the // same tuple on the same time. Consider for example tuple (A: 1, B: 2), where // A is key and an update "set B=B+1". Since there cannot be any other tuple // with A=1, and the tuple (1,2) is deleted before tuple (1,3) gets inserted, // we don't need to enforce specific order of deletes and inserts. // // 3. If the update changes a key column, enforce order on the Action column // to deliver Delete tuples before Insert tuples. This is done to avoid a // conflict between a newly inserted tuple and an old tuple that is about to be // deleted. Consider table with tuples (A: 1),(A: 2), where A is key, and // update "set A=A+1". Split will generate tuples (1,"D"), (2,"I"), (2,"D"), (3,"I"). // If (2,"I") happens before (2,"D") we will have a violation of the key constraint. // Therefore we need to enforce sort order on Action to get all old tuples // tuples deleted before the new ones are inserted. // //--------------------------------------------------------------------------- COrderSpec * CPhysicalDML::PosComputeRequired ( IMemoryPool *pmp, CTableDescriptor *ptabdesc ) { COrderSpec *pos = GPOS_NEW(pmp) COrderSpec(pmp); const DrgPbs *pdrgpbsKeys = ptabdesc->PdrgpbsKeys(); if (1 < pdrgpbsKeys->UlLength() && CLogicalDML::EdmlUpdate == m_edmlop) { // if this is an update on the target table's keys, enforce order on // the action column, see explanation in function's comment const ULONG ulKeySets = pdrgpbsKeys->UlLength(); BOOL fNeedsSort = false; for (ULONG ul = 0; ul < ulKeySets && !fNeedsSort; ul++) { CBitSet *pbs = (*pdrgpbsKeys)[ul]; if (!pbs->FDisjoint(m_pbsModified)) { fNeedsSort = true; break; } } if (fNeedsSort) { IMDId *pmdid = m_pcrAction->Pmdtype()->PmdidCmp(IMDType::EcmptL); pmdid->AddRef(); pos->Append(pmdid, m_pcrAction, COrderSpec::EntAuto); } } else if (m_ptabdesc->FPartitioned()) { COptimizerConfig *poconf = COptCtxt::PoctxtFromTLS()->Poconf(); BOOL fInsertSortOnParquet = FInsertSortOnParquet(); BOOL fInsertSortOnRows = FInsertSortOnRows(poconf); if (fInsertSortOnParquet || fInsertSortOnRows) { GPOS_ASSERT(CLogicalDML::EdmlInsert == m_edmlop); m_fInputSorted = true; // if this is an INSERT over a partitioned Parquet or Row-oriented table, // sort tuples by their table oid IMDId *pmdid = m_pcrTableOid->Pmdtype()->PmdidCmp(IMDType::EcmptL); pmdid->AddRef(); pos->Append(pmdid, m_pcrTableOid, COrderSpec::EntAuto); } } return pos; }
//--------------------------------------------------------------------------- // @function: // CLogical::PosFromIndex // // @doc: // Compute an order spec based on an index // //--------------------------------------------------------------------------- COrderSpec * CLogical::PosFromIndex ( IMemoryPool *pmp, const IMDIndex *pmdindex, DrgPcr *pdrgpcr ) { // compute the order spec COrderSpec *pos = GPOS_NEW(pmp) COrderSpec(pmp); const ULONG ulLenIncludeCols = pmdindex->UlKeys(); for (ULONG ul = 0; ul < ulLenIncludeCols; ul++) { ULONG ulPos = pmdindex->UlKey(ul); CColRef *pcr = (*pdrgpcr)[ulPos]; IMDId *pmdid = pcr->Pmdtype()->PmdidCmp(IMDType::EcmptL); pmdid->AddRef(); // TODO: March 27th 2012; we hard-code NULL treatment // need to revisit pos->Append(pmdid, pcr, COrderSpec::EntLast); } return pos; }