BTREE_TEMPLATE_ARGUMENT void BTREE_TEMPLATE_TYPE::Scan(const std::vector<common::Value *> &value_list, const std::vector<oid_t> &tuple_column_id_list, const std::vector<ExpressionType> &expr_list, const ScanDirectionType &scan_direction, std::vector<ValueType> &result, const ConjunctionScanPredicate *csp_p) { // First make sure all three components of the scan predicate are // of the same length // Since there is a 1-to-1 correspondense between these three vectors PL_ASSERT(tuple_column_id_list.size() == expr_list.size()); PL_ASSERT(tuple_column_id_list.size() == value_list.size()); // This is a hack - we do not support backward scan if (scan_direction == SCAN_DIRECTION_TYPE_INVALID) { throw Exception("Invalid scan direction \n"); } LOG_TRACE("Point Query = %d; Full Scan = %d ", csp_p->IsPointQuery(), csp_p->IsFullIndexScan()); index_lock.ReadLock(); if (csp_p->IsPointQuery() == true) { // For point query we construct the key and use equal_range const storage::Tuple *point_query_key_p = csp_p->GetPointQueryKey(); KeyType point_query_key; point_query_key.SetFromKey(point_query_key_p); // Use equal_range to mark two ends of the scan auto scan_itr_pair = container.equal_range(point_query_key); auto scan_begin_itr = scan_itr_pair.first; auto scan_end_itr = scan_itr_pair.second; for (auto scan_itr = scan_begin_itr; scan_itr != scan_end_itr; scan_itr++) { auto scan_current_key = scan_itr->first; auto tuple = scan_current_key.GetTupleForComparison(metadata->GetKeySchema()); if (Compare(tuple, tuple_column_id_list, expr_list, value_list) == true) { result.push_back(scan_itr->second); } } } else if (csp_p->IsFullIndexScan() == true) { // If it is a full index scan, then just do the scan for (auto scan_itr = container.begin(); scan_itr != container.end(); scan_itr++) { // Unpack the key as a standard tuple for comparison auto scan_current_key = scan_itr->first; auto tuple = scan_current_key.GetTupleForComparison(metadata->GetKeySchema()); // Compare whether the current key satisfies the predicate // since we just narrowed down search range using low key and // high key for scan, it is still possible that there are tuples // for which the predicate is not true if (Compare(tuple, tuple_column_id_list, expr_list, value_list) == true) { result.push_back(scan_itr->second); } } // for it from begin() to end() } else { const storage::Tuple *low_key_p = csp_p->GetLowKey(); const storage::Tuple *high_key_p = csp_p->GetHighKey(); // Construct low key and high key in KeyType form, rather than // the standard in-memory tuple KeyType index_low_key; KeyType index_high_key; index_low_key.SetFromKey(low_key_p); index_high_key.SetFromKey(high_key_p); // It is good that we have equal_range auto scan_begin_itr = container.equal_range(index_low_key).first; auto scan_end_itr = container.equal_range(index_high_key).second; for (auto scan_itr = scan_begin_itr; scan_itr != scan_end_itr; scan_itr++) { auto scan_current_key = scan_itr->first; auto tuple = scan_current_key.GetTupleForComparison(metadata->GetKeySchema()); if (Compare(tuple, tuple_column_id_list, expr_list, value_list) == true) { result.push_back(scan_itr->second); } } } // if is full scan index_lock.Unlock(); if (FLAGS_stats_mode != STATS_TYPE_INVALID) { stats::BackendStatsContext::GetInstance().IncrementIndexReads(result.size(), metadata); } return; }
std::vector<ItemPointer> BTreeIndex<KeyType, ValueType, KeyComparator, KeyEqualityChecker>::Scan( const std::vector<Value> &values, const std::vector<oid_t> &key_column_ids, const std::vector<ExpressionType> &expr_types, const ScanDirectionType& scan_direction) { std::vector<ItemPointer> result; KeyType index_key; { index_lock.ReadLock(); // Check if we have leading (leftmost) column equality // refer : http://www.postgresql.org/docs/8.2/static/indexes-multicolumn.html oid_t leading_column_id = 0; auto key_column_ids_itr = std::find( key_column_ids.begin(), key_column_ids.end(), leading_column_id); // SPECIAL CASE : leading column id is one of the key column ids // and is involved in a equality constraint bool special_case = false; if (key_column_ids_itr != key_column_ids.end()) { auto offset = std::distance(key_column_ids.begin(), key_column_ids_itr); if (expr_types[offset] == EXPRESSION_TYPE_COMPARE_EQUAL) { special_case = true; } } LOG_TRACE("Special case : %d ", special_case); auto scan_begin_itr = container.begin(); std::unique_ptr<storage::Tuple> start_key; bool all_constraints_are_equal = false; // If it is a special case, we can figure out the range to scan in the index if (special_case == true) { start_key.reset(new storage::Tuple(metadata->GetKeySchema(), true)); index_key.SetFromKey(start_key.get()); // Construct the lower bound key tuple all_constraints_are_equal = ConstructLowerBoundTuple(start_key.get(), values, key_column_ids, expr_types); LOG_TRACE("All constraints are equal : %d ", all_constraints_are_equal); // Set scan begin iterator scan_begin_itr = container.equal_range(index_key).first; } switch(scan_direction){ case SCAN_DIRECTION_TYPE_FORWARD: case SCAN_DIRECTION_TYPE_BACKWARD: { // Scan the index entries in forward direction for (auto scan_itr = scan_begin_itr; scan_itr != container.end(); scan_itr++) { auto scan_current_key = scan_itr->first; auto tuple = scan_current_key.GetTupleForComparison(metadata->GetKeySchema()); // Compare the current key in the scan with "values" based on "expression types" // For instance, "5" EXPR_GREATER_THAN "2" is true if (Compare(tuple, key_column_ids, expr_types, values) == true) { ItemPointer location = scan_itr->second; result.push_back(location); } else { // We can stop scanning if we know that all constraints are equal if(all_constraints_are_equal == true) { break; } } } } break; case SCAN_DIRECTION_TYPE_INVALID: default: throw Exception("Invalid scan direction \n"); break; } index_lock.Unlock(); } return result; }