//--------------------------------------------------------------------------- // @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; }