/* * DynamicScan_ObtainRelations * Returns old and new relations for a new part oid */ static void DynamicScan_ObtainRelations(ScanState *scanState, Oid newOid, Relation *outOldRelation, Relation *outNewRelation) { Relation oldRelation = NULL; Relation newRelation = NULL; Oid oldOid = InvalidOid; if (NULL != scanState->ss_currentRelation) { oldOid = RelationGetRelid(scanState->ss_currentRelation); oldRelation = scanState->ss_currentRelation; } else { /* Must be the initial state */ Assert(SCAN_INIT == scanState->scan_state); oldOid = DynamicScan_GetOriginalRelationOid(scanState); Assert(OidIsValid(oldOid)); oldRelation = OpenScanRelationByOid(oldOid); } if (oldOid == newOid) { newRelation = oldRelation; } else { newRelation = OpenScanRelationByOid(newOid); } Assert(NULL != oldRelation); Assert(NULL != newRelation); *outOldRelation = oldRelation; *outNewRelation = newRelation; }
/* * This function initializes a part and returns true if a new index has been prepared for scanning. */ static bool initNextIndexToScan(DynamicIndexScanState *node) { IndexScanState *indexState = &(node->indexScanState); DynamicIndexScan *dynamicIndexScan = (DynamicIndexScan *)node->indexScanState.ss.ps.plan; /* Load new index when the scanning of the previous index is done. */ if (indexState->ss.scan_state == SCAN_INIT || indexState->ss.scan_state == SCAN_DONE) { /* This is the oid of a partition of the table (*not* index) */ Oid *pid = hash_seq_search(&node->pidxStatus); if (pid == NULL) { /* Return if all parts have been scanned. */ node->shouldCallHashSeqTerm = false; return false; } /* Collect number of partitions scanned in EXPLAIN ANALYZE */ if(NULL != indexState->ss.ps.instrument) { Instrumentation *instr = indexState->ss.ps.instrument; instr->numPartScanned ++; } DynamicIndexScan_ReMapColumns(node, *pid); /* * The is the oid of the partition of an *index*. Note: a partitioned table * has a root and a set of partitions (may be multi-level). An index * on a partitioned table also has a root and a set of index partitions. * We started at table level, and now we are fetching the oid of an index * partition. */ Oid pindex = getPhysicalIndexRelid(dynamicIndexScan->logicalIndexInfo, *pid); Assert(OidIsValid(pindex)); Relation currentRelation = OpenScanRelationByOid(*pid); indexState->ss.ss_currentRelation = currentRelation; for (int i=0; i < DYNAMICINDEXSCAN_NSLOTS; i++) { indexState->ss.ss_ScanTupleSlot[i].tts_tableOid = *pid; } ExecAssignScanType(&indexState->ss, RelationGetDescr(currentRelation)); ScanState *scanState = (ScanState *)node; MemoryContextReset(node->partitionMemoryContext); MemoryContext oldCxt = MemoryContextSwitchTo(node->partitionMemoryContext); /* Initialize child expressions */ scanState->ps.qual = (List *)ExecInitExpr((Expr *)scanState->ps.plan->qual, (PlanState*)scanState); scanState->ps.targetlist = (List *)ExecInitExpr((Expr *)scanState->ps.plan->targetlist, (PlanState*)scanState); ExecAssignScanProjectionInfo(scanState); EState *estate = indexState->ss.ps.state; indexState->iss_RelationDesc = OpenIndexRelation(estate, pindex, *pid); /* * build the index scan keys from the index qualification */ ExecIndexBuildScanKeys((PlanState *) indexState, indexState->iss_RelationDesc, dynamicIndexScan->indexqual, dynamicIndexScan->indexstrategy, dynamicIndexScan->indexsubtype, &indexState->iss_ScanKeys, &indexState->iss_NumScanKeys, &indexState->iss_RuntimeKeys, &indexState->iss_NumRuntimeKeys, NULL, NULL); MemoryContextSwitchTo(oldCxt); ExprContext *econtext = indexState->iss_RuntimeContext; /* context for runtime keys */ if (indexState->iss_NumRuntimeKeys != 0) { ExecIndexEvalRuntimeKeys(econtext, indexState->iss_RuntimeKeys, indexState->iss_NumRuntimeKeys); } indexState->iss_RuntimeKeysReady = true; /* * Initialize result tuple type and projection info. */ TupleDesc td = indexState->ss.ps.ps_ResultTupleSlot->tts_tupleDescriptor; if (td) { pfree(td); td = NULL; } ExecAssignResultTypeFromTL(&indexState->ss.ps); ExecAssignScanProjectionInfo(&indexState->ss); indexState->iss_ScanDesc = index_beginscan(currentRelation, indexState->iss_RelationDesc, estate->es_snapshot, indexState->iss_NumScanKeys, indexState->iss_ScanKeys); indexState->ss.scan_state = SCAN_SCAN; } return true; }
/* * initNextTableToScan * Find the next table to scan and initiate the scan if the previous table * is finished. * * If scanning on the current table is not finished, or a new table is found, * this function returns true. * If no more table is found, this function returns false. */ static bool initNextTableToScan(DynamicTableScanState *node) { ScanState *scanState = (ScanState *)node; if (scanState->scan_state == SCAN_INIT || scanState->scan_state == SCAN_DONE) { Oid *pid = hash_seq_search(&node->pidStatus); if (pid == NULL) { node->shouldCallHashSeqTerm = false; return false; } /* Collect number of partitions scanned in EXPLAIN ANALYZE */ if (NULL != scanState->ps.instrument) { Instrumentation *instr = scanState->ps.instrument; instr->numPartScanned ++; } /* * Inside ExecInitScanTupleSlot() we set the tuple table slot's oid * to range table entry's relid, which for partitioned table always set * to parent table's oid. In queries where we need to read table oids * (MPP-20736) we use the tuple table slot's saved oid (refer to slot_getsysattr()). * This wrongly returns parent oid, instead of partition oid. Therefore, * to return correct partition oid, we need to update * our tuple table slot's oid to reflect the partition oid. */ scanState->ss_ScanTupleSlot->tts_tableOid = *pid; scanState->ss_currentRelation = OpenScanRelationByOid(*pid); Relation lastScannedRel = OpenScanRelationByOid(node->lastRelOid); TupleDesc lastTupDesc = RelationGetDescr(lastScannedRel); CloseScanRelation(lastScannedRel); TupleDesc partTupDesc = RelationGetDescr(scanState->ss_currentRelation); ExecAssignScanType(scanState, partTupDesc); AttrNumber *attMap = NULL; attMap = varattnos_map(lastTupDesc, partTupDesc); /* If attribute remapping is not necessary, then do not change the varattno */ if (attMap) { change_varattnos_of_a_varno((Node*)scanState->ps.plan->qual, attMap, node->scanrelid); change_varattnos_of_a_varno((Node*)scanState->ps.plan->targetlist, attMap, node->scanrelid); /* * Now that the varattno mapping has been changed, change the relation that * the new varnos correspond to */ node->lastRelOid = *pid; } /* * For the very first partition, the targetlist of planstate is set to null. So, we must * initialize quals and targetlist, regardless of remapping requirements. For later * partitions, we only initialize quals and targetlist if a column re-mapping is necessary. */ if (attMap || node->firstPartition) { node->firstPartition = false; MemoryContextReset(node->partitionMemoryContext); MemoryContext oldCxt = MemoryContextSwitchTo(node->partitionMemoryContext); /* Initialize child expressions */ scanState->ps.qual = (List *)ExecInitExpr((Expr *)scanState->ps.plan->qual, (PlanState*)scanState); scanState->ps.targetlist = (List *)ExecInitExpr((Expr *)scanState->ps.plan->targetlist, (PlanState*)scanState); MemoryContextSwitchTo(oldCxt); } if (attMap) { pfree(attMap); } ExecAssignScanProjectionInfo(scanState); scanState->tableType = getTableType(scanState->ss_currentRelation); BeginTableScanRelation(scanState); } return true; }