static bool DynamicIndexScan_ReMapColumns(DynamicIndexScanState *scanState, Oid newOid) { Assert(OidIsValid(newOid)); IndexScan *indexScan = (IndexScan *) scanState->indexScanState.ss.ps.plan; if (!isDynamicScan(&indexScan->scan)) { return false; } Oid oldOid = scanState->columnLayoutOid; if (!OidIsValid(oldOid)) { /* Very first partition */ oldOid = rel_partition_get_root(newOid); } Assert(OidIsValid(oldOid)); if (oldOid == newOid) { /* * If we have only one partition and we are rescanning * then we can have this scenario. */ return false; } AttrNumber *attMap = IndexScan_GetColumnMapping(oldOid, newOid); scanState->columnLayoutOid = newOid; if (attMap) { IndexScan_MapLogicalIndexInfo(indexScan->logicalIndexInfo, attMap, indexScan->scan.scanrelid); change_varattnos_of_a_varno((Node*)indexScan->scan.plan.targetlist, attMap, indexScan->scan.scanrelid); change_varattnos_of_a_varno((Node*)indexScan->scan.plan.qual, attMap, indexScan->scan.scanrelid); change_varattnos_of_a_varno((Node*)indexScan->indexqual, attMap, indexScan->scan.scanrelid); pfree(attMap); return true; } else { return false; } }
/* * DynamicScan_InitNextRelation * Initializes states to process the next relation (if any). * For partitioned scan we advance the iterator and prepare * the next partition to scan. For non-partitioned case, we * just start with the *only* relation, if we haven't * already processed that relation. * * Returns false if we don't have any more partition to iterate. */ static bool DynamicScan_InitNextRelation(ScanState *scanState, PartitionInitMethod *partitionInitMethod, PartitionEndMethod *partitionEndMethod, PartitionReScanMethod *partitionReScanMethod) { Assert(T_BitmapTableScanState == scanState->ps.type); Scan *scan = (Scan *)scanState->ps.plan; if (isDynamicScan(scan)) { return DynamicScan_InitNextPartition(scanState, partitionInitMethod, partitionEndMethod, partitionReScanMethod); } return DynamicScan_InitSingleRelation(scanState, partitionInitMethod, partitionReScanMethod); }
/* * DynamicScan_Controller * Controller function to transition from one scan status to another. * * This function does not handle SCAN_END, which is exclusively controlled * by the DynamicScan_End method */ static ScanStatus DynamicScan_Controller(ScanState *scanState, ScanStatus desiredState, PartitionInitMethod *partitionInitMethod, PartitionEndMethod *partitionEndMethod, PartitionReScanMethod *partitionReScanMethod) { ScanStatus startState = scanState->scan_state; /* Controller doesn't handle any state transition related to SCAN_END */ if (SCAN_END == desiredState || SCAN_END == startState) { DynamicScan_StateTransitionError(startState, desiredState); } if (SCAN_SCAN == desiredState && (SCAN_INIT == startState || SCAN_NEXT == startState || SCAN_RESCAN == startState)) { Assert(SCAN_DONE != startState || SCAN_END != startState); if (SCAN_INIT == startState || SCAN_RESCAN == startState) { DynamicScan_RewindIterator(scanState); } if (DynamicScan_InitNextRelation(scanState, partitionInitMethod, partitionEndMethod, partitionReScanMethod)) { scanState->scan_state = SCAN_SCAN; } else { scanState->scan_state = SCAN_DONE; } } else if (SCAN_RESCAN == desiredState && SCAN_END != startState) { Assert(SCAN_END != startState); /* RESCAN shouldn't affect INIT, as nothing to rewind yet */ if (SCAN_INIT != startState) { scanState->scan_state = SCAN_RESCAN; } } else if (SCAN_NEXT == desiredState && SCAN_SCAN == startState) { scanState->scan_state = isDynamicScan((Scan *)scanState->ps.plan) ? SCAN_NEXT : SCAN_DONE; } else { DynamicScan_StateTransitionError(scanState->scan_state, desiredState); } return scanState->scan_state; }
/* * DynamicScan_GetIterator * Returns the current iterator for the scanState's partIndex. */ DynamicPartitionIterator* DynamicScan_GetIterator(ScanState *scanState) { Assert(isDynamicScan((Scan *)scanState->ps.plan)); Assert(NULL != scanState->ps.state->dynamicTableScanInfo); int partIndex = ((Scan*)scanState->ps.plan)->partIndex; Assert(partIndex <= scanState->ps.state->dynamicTableScanInfo->numScans); DynamicPartitionIterator *iterator = scanState->ps.state->dynamicTableScanInfo->iterators[partIndex - 1]; Assert(NULL != iterator); return iterator; }
/* * DynamicScan_MapRelationColumns * Returns dropped column mapping between two relations. Returns NULL if * no mapping is necessary. */ static AttrNumber* DynamicScan_MapRelationColumns(ScanState *scanState, Relation oldRelation, Relation newRelation) { AttrNumber *attMap = NULL; if (isDynamicScan((Scan *)scanState->ps.plan) && (oldRelation != newRelation)) { TupleDesc oldTupDesc = RelationGetDescr(oldRelation); TupleDesc newTupDesc = RelationGetDescr(newRelation); attMap = varattnos_map(oldTupDesc, newTupDesc); } return attMap; }
/* * DynamicScan_RemapExpression * Re-maps the expression using the provided attMap. */ bool DynamicScan_RemapExpression(ScanState *scanState, AttrNumber *attMap, Node *expr) { if (!isDynamicScan((Scan *)scanState->ps.plan)) { return false; } if (NULL != attMap) { change_varattnos_of_a_varno((Node*)expr, attMap, ((Scan *)scanState->ps.plan)->scanrelid); return true; } return false; }
/* * DynamicScan_RewindIterator * Rewinds the iterator for a new scan of all the parts */ static void DynamicScan_RewindIterator(ScanState *scanState) { if (!isDynamicScan((Scan *)scanState->ps.plan)) { return; } /* * For EXPLAIN of a plan, we may never finish the initialization, * and end up calling the End method directly.In such cases, we * don't have any iterator to end. */ if (SCAN_INIT == scanState->scan_state) { DynamicScan_CreateIterator(scanState, (Scan *)scanState->ps.plan); return; } Scan *scan = (Scan *)scanState->ps.plan; DynamicTableScanInfo *partitionInfo = scanState->ps.state->dynamicTableScanInfo; Assert(partitionInfo->numScans >= scan->partIndex); DynamicPartitionIterator *iterator = partitionInfo->iterators[scan->partIndex - 1]; Assert(NULL != iterator); if (iterator->shouldCallHashSeqTerm) { hash_seq_term(iterator->partitionIterator); } pfree(iterator->partitionIterator); iterator->partitionOids = partitionInfo->pidIndexes[scan->partIndex - 1]; Assert(iterator->partitionOids != NULL); iterator->shouldCallHashSeqTerm = true; HASH_SEQ_STATUS *partitionIterator = palloc(sizeof(HASH_SEQ_STATUS)); hash_seq_init(partitionIterator, iterator->partitionOids); iterator->partitionIterator = partitionIterator; Assert(iterator == partitionInfo->iterators[scan->partIndex - 1]); }
/* * DynamicScan_InitSingleRelation * Prepares a single relation for scanning by calling various * helper methods to open relation, initialize expressions etc. * * Note: this is for the non-partitioned relations. * * Returns true upon success. */ static bool DynamicScan_InitSingleRelation(ScanState *scanState, PartitionInitMethod *partitionInitMethod, PartitionReScanMethod *partitionReScanMethod) { Assert(!isDynamicScan((Scan *)scanState->ps.plan)); if (NULL == scanState->ss_currentRelation) { /* Open the relation and initalize the expressions (targetlist, qual etc.) */ InitScanStateRelationDetails(scanState, scanState->ps.plan, scanState->ps.state); partitionInitMethod(scanState, NULL /* No dropped column mapping */); } else { Insist(scanState->scan_state == SCAN_RESCAN); partitionReScanMethod(scanState); } return true; }
/* * DynamicScan_GetTableOid * Returns the Oid of the table/partition to scan. * * For partitioned case this method returns InvalidOid * if the partition iterator hasn't been initialized yet. */ Oid DynamicScan_GetTableOid(ScanState *scanState) { /* For non-partitioned scan, just lookup the RTE */ if (!isDynamicScan((Scan *)scanState->ps.plan)) { return getrelid(((Scan *)scanState->ps.plan)->scanrelid, scanState->ps.state->es_range_table); } /* We are yet to initialize the iterator, so return InvalidOid */ if (SCAN_INIT == scanState->scan_state) { return InvalidOid; } /* Get the iterator and look up the oid of the current relation */ DynamicPartitionIterator *iterator = DynamicScan_GetIterator(scanState); Assert(NULL != iterator); Assert(OidIsValid(iterator->curRelOid)); return iterator->curRelOid; }
/* * DynamicScan_GetPartitionMemoryContext * Returns the current partition's (if any) memory context. */ MemoryContext DynamicScan_GetPartitionMemoryContext(ScanState *scanState) { Assert(T_BitmapTableScanState == scanState->ps.type || T_BitmapIndexScanState == scanState->ps.type); Scan *scan = (Scan *)scanState->ps.plan; /* * TODO rahmaf2 05/08/2014 [JIRA: MPP-23513] We currently * return NULL memory context during initialization. So, * for partitioned case, we will leak memory for all the * expression initialization allocations during ExecInit. */ if (!isDynamicScan(scan) || SCAN_INIT == scanState->scan_state) { return NULL; } DynamicPartitionIterator *iterator = DynamicScan_GetIterator(scanState); Assert(NULL != iterator); return iterator->partitionMemoryContext; }
/* * DynamicScan_End * Ends partition/relation iteration/scanning and cleans up everything. */ void DynamicScan_End(ScanState *scanState, PartitionEndMethod *partitionEndMethod) { Assert(NULL != scanState); Assert(T_BitmapTableScanState == scanState->ps.type); if (SCAN_END == scanState->scan_state) { return; } Scan *scan = (Scan *)scanState->ps.plan; DynamicScan_CleanupOneRelation(scanState, scanState->ss_currentRelation, partitionEndMethod); if (isDynamicScan(scan)) { DynamicScan_EndIterator(scanState); } FreeScanRelationInternal(scanState, false /* Do not close the relation. We closed it in DynamicScan_CleanupOneRelation */); scanState->scan_state = SCAN_END; }
/* * DynamicScan_InitNextPartition * Prepares the next partition for scanning by calling various * helper methods to open relation, map dropped attributes, * initialize expressions etc. */ static bool DynamicScan_InitNextPartition(ScanState *scanState, PartitionInitMethod *partitionInitMethod, PartitionEndMethod *partitionEndMethod, PartitionReScanMethod *partitionReScanMethod) { Assert(isDynamicScan((Scan *)scanState->ps.plan)); AssertImply(scanState->scan_state != SCAN_INIT, NULL != scanState->ss_currentRelation); Scan *scan = (Scan *)scanState->ps.plan; DynamicTableScanInfo *partitionInfo = scanState->ps.state->dynamicTableScanInfo; Assert(partitionInfo->numScans >= scan->partIndex); int32 numSelectors = list_nth_int(partitionInfo->numSelectorsPerScanId, scan->partIndex); Oid newOid = DynamicScan_AdvanceIterator(scanState, numSelectors); if (!OidIsValid(newOid)) { return false; } Relation oldRelation = NULL; Relation newRelation = NULL; DynamicScan_ObtainRelations(scanState, newOid, &oldRelation, &newRelation); /* Either we have a new relation or this is the first relation */ if (oldRelation != newRelation || NULL == scanState->ss_currentRelation) { AttrNumber *attMap = DynamicScan_MapRelationColumns(scanState, oldRelation, newRelation); DynamicScan_RemapExpression(scanState, attMap, (Node*)scanState->ps.plan->qual); DynamicScan_RemapExpression(scanState, attMap, (Node*)scanState->ps.plan->targetlist); /* * We only initialize expression if this is the first partition * or if the column mapping changes between two partitions. * Otherwise, we reuse the previously initialized expression. */ bool initExpressions = (NULL != attMap || SCAN_INIT == scanState->scan_state); if (newRelation != oldRelation) { /* Close the old relation */ DynamicScan_CleanupOneRelation(scanState, oldRelation, partitionEndMethod); } DynamicScan_UpdateScanStateForNewPart(scanState, newRelation); if (initExpressions) { DynamicScan_InitExpr(scanState); } partitionInitMethod(scanState, attMap); if (NULL != attMap) { pfree(attMap); attMap = NULL; } } else { /* Rescan of the same part */ partitionReScanMethod(scanState); } /* Collect number of partitions scanned in EXPLAIN ANALYZE */ if(NULL != scanState->ps.instrument) { Instrumentation *instr = scanState->ps.instrument; instr->numPartScanned ++; } return true; }