示例#1
0
HeapFile* IndexNestedLoopJoin(JoinSpec specOfR, JoinSpec specOfS)
{
	Status status = OK;

	// Create a HeapFile for join results
	HeapFile* joinedFile = new HeapFile(NULL, status);
	if (OK != status)
	{
		cerr << "ERROR: cannot create a file for the joined relation.\n";
		return NULL;
	}

	int recLenR = specOfR.recLen;
	int recLenS = specOfS.recLen;
	int recLenJoined = recLenR + recLenS;

	char* recR = new char[recLenR];
	char* recS = new char[recLenS];
	char* recJoined = new char[recLenJoined];

	RecordID ridR, ridS, ridJoined;

	// Build the B+-tree index on the inner relation (S)
	Scan* scanS = specOfS.file->OpenScan(status);
	if (OK != status)
	{
		cerr << "ERROR: cannot open scan on the relation S heap file.\n";
		return NULL;
	}

	BTreeFile* bTree = new BTreeFile(status, "IJBT", ATTR_INT, sizeof(int));
	while (OK == scanS->GetNext(ridS, recS, recLenS))
	{
		bTree->Insert(recS + specOfS.offset, ridS);
	}
	delete scanS;

	// Iterate through the outer relation (R) and join
	Scan* scanR = specOfR.file->OpenScan(status);
	if (OK != status)
	{
		cerr << "ERROR: cannot open scan on the relation R heap file.\n";
		return NULL;
	}

	while (OK == scanR->GetNext(ridR, recR, recLenR))
	{
		int* joinArgR = (int*)&recR[specOfR.offset];

		BTreeFileScan* bTreeScan = (BTreeFileScan*)bTree->OpenSearchScan(joinArgR, joinArgR);
		int key;
		while (OK == bTreeScan->GetNext(ridS, &key))
		{
		    specOfS.file->GetRecord(ridS, recS, recLenS);

			MakeNewRecord(recJoined, recR, recS, recLenR, recLenS);
			joinedFile->InsertRecord(recJoined, recLenJoined, ridJoined);
		}
		delete bTreeScan;
	}

	// Release the allocated resources
	delete scanR;

	delete[] recR;
	delete[] recS;
	delete[] recJoined;

	delete bTree;

	return joinedFile;
}
示例#2
0
HeapFile* BlockNestedLoopJoin(JoinSpec specOfR, JoinSpec specOfS, int B)
{
	Status status = OK;

	// Create a HeapFile for join results
	HeapFile* joinedFile = new HeapFile(NULL, status);
	if (OK != status)
	{
		cerr << "ERROR: cannot create a file for the joined relation.\n";
		return NULL;
	}

	int recLenR = specOfR.recLen;
	int recLenS = specOfS.recLen;
	int recLenJoined = recLenR + recLenS;

	char* recBlockR = new char[B]; // Allocate memory for the block
	char* recS = new char[recLenS];
	char* recJoined = new char[recLenJoined];

	RecordID ridR, ridS, ridJoined;

	Scan* scanR = specOfR.file->OpenScan(status);
	if (OK != status)
	{
		cerr << "ERROR: cannot open scan on the relation R heap file.\n";
		return NULL;
	}

	const int recordsPerBlock = B / recLenR;

	bool lastBlock = false;
	while (!lastBlock)
	{
		// Fill the block
		int i;
		for (i = 0; i < recordsPerBlock; i++)
		{
			if (OK != scanR->GetNext(ridR, recBlockR + i*recLenR, recLenR))
			{
				lastBlock = true;
				break;
			}
		}
		int lastRecordIndex = i;

		Scan* scanS = specOfS.file->OpenScan(status);
		if (OK != status)
		{
			cerr << "ERROR: cannot open scan on the relation S heap file.\n";
			return NULL;
		}

		while (OK == scanS->GetNext(ridS, recS, recLenS))
		{
			int* joinArgS = (int*)&recS[specOfS.offset];

			for (int currentRecordIndex = 0; currentRecordIndex < lastRecordIndex; currentRecordIndex++)
			{
				char* currentRecordPtr = recBlockR + (currentRecordIndex * recLenR);
				int* joinArgR = (int*)(currentRecordPtr + specOfR.offset);

				if (*joinArgR == *joinArgS)
				{
					MakeNewRecord(recJoined, currentRecordPtr, recS, recLenR, recLenS);
					joinedFile->InsertRecord(recJoined, recLenJoined, ridJoined);
				}
			}
		}

		delete scanS;
	}

	// Release the allocated resources
	delete scanR;

	delete[] recBlockR;
	delete[] recS;
	delete[] recJoined;

	return joinedFile;
}
示例#3
0
//---------------------------------------------------------------
// TupleNestedLoop::Execute
//
// Input:   left  - The left relation to join. 
//          right - The right relation to join. 
// Output:  out   - The relation to hold the ouptut. 
// Return:  OK if join completed succesfully. FAIL otherwise. 
//          
// Purpose: Performs a nested loop join on relations left and right
//          a tuple a time. You can assume that left is the outer
//          relation and right is the inner relation. 
//---------------------------------------------------------------
Status TupleNestedLoops::Execute(JoinSpec& left, JoinSpec& right, JoinSpec& out) {
	JoinMethod::Execute(left, right, out);

	//	Create the temporary heapfile
	Status st;
	HeapFile *tmpHeap = new HeapFile(NULL, st);
	if (st != OK) {
		std::cerr << "Failed to create output heapfile." << std::endl;
		return FAIL;
	}

	//	Open scan on left relation
	Status leftStatus;
	Scan *leftScan = left.file->OpenScan(leftStatus);
	if (leftStatus != OK) {
		std::cerr << "Failed to open scan on left relation." << std::endl;
		return FAIL;
	}

	//	Loop over the left relation
	char *leftRec = new char[left.recLen];
	while (true) {
		RecordID leftRid;
		leftStatus = leftScan->GetNext(leftRid, leftRec, left.recLen);
		if (leftStatus == DONE) break;
		if (leftStatus != OK) return FAIL;

		//	The join attribute on left relation
		int *leftJoinValPtr = (int*)(leftRec + left.offset);

		//	Open scan on right relation
		Status rightStatus;
		Scan *rightScan = right.file->OpenScan(rightStatus);
		if (rightStatus != OK) {
			std::cerr << "Failed to open scan on right relation." << std::endl;
			return FAIL;
		}

		//	Loop over right relation
		char *rightRec = new char[right.recLen];
		while (true) {
			RecordID rightRid;
			rightStatus = rightScan->GetNext(rightRid, rightRec, right.recLen);
			if (rightStatus == DONE) break;
			if (rightStatus != OK) return FAIL;

			//	Compare join attribute
			int *rightJoinValPtr = (int*)(rightRec + right.offset);
			if (*leftJoinValPtr == *rightJoinValPtr) {
				//	Create the record and insert into tmpHeap...
				char *joinedRec = new char[out.recLen];
				MakeNewRecord(joinedRec, leftRec, rightRec, left, right);
				RecordID insertedRid;
				Status tmpStatus = tmpHeap->InsertRecord(joinedRec, out.recLen, insertedRid);

				if (tmpStatus != OK) {
					std::cerr << "Failed to insert tuple into output heapfile." << std::endl;
					return FAIL;
				}
				delete [] joinedRec;
			}
		}

		delete [] rightRec;
		delete rightScan;
	}

	out.file = tmpHeap;
	delete leftScan;
	delete [] leftRec;

	return OK;
}
示例#4
0
//---------------------------------------------------------------
// BlockNestedLoop::Execute
//
// Input:   left  - The left relation to join. 
//          right - The right relation to join. 
// Output:  out   - The relation to hold the ouptut. 
// Return:  OK if join completed succesfully. FAIL otherwise. 
//          
// Purpose: Performs a block nested loops join on the specified relations. 
// You can find a specification of this algorithm on page 455. You should 
// choose the smaller of the two relations to be the outer relation, but you 
// should make sure to concatenate the tuples in order <left, right> when 
// producing output. The block size can be specified in the constructor, 
// and is stored in the variable blockSize. 
//---------------------------------------------------------------
Status BlockNestedLoops::Execute(JoinSpec& left, JoinSpec& right, JoinSpec& out) {
	JoinMethod::Execute(left, right, out);
	
	Status s;
	HeapFile* tmpHeap = new HeapFile(NULL, s);
	if (s != OK) {
		std::cout << "Creating new Heap File Failed" << std::endl;
		return FAIL;
	}

	Scan * leftScan = left.file->OpenScan(s);
	if (s != OK) {
		std::cout << "Open scan left failed" << std::endl;
		return FAIL;
	}

	Scan * rightScan = right.file->OpenScan(s);
	if (s != OK) {
		std::cout << "Open scan left failed" << std::endl;
		return FAIL;
	}

	RecordID leftRid, rightRid, rightFirstRid, outRid;

	// array to hold the "block" in memory
	char* blockArray = new char[left.recLen * blockSize];
	int blockArraySize = 0; // size in case of half full block
	int* leftCurrRec = (int *)blockArray;
	int* leftRec = new int[left.numOfAttr];
	int* rightRec = new int[right.numOfAttr];
	int leftRecLen = left.recLen;
	int rightRecLen = right.recLen;

	char* newRec = new char[left.recLen + right.recLen];

	rightFirstRid = rightScan->currRid;

	Status st = OK;

	while (true) {
		// fill the block with as many records as possible
		if (blockArraySize < blockSize) {
			st = leftScan->GetNext(leftRid, (char *)leftRec, leftRecLen);
			if (st != DONE) {
				memcpy(blockArray + left.recLen * blockArraySize, leftRec, left.recLen);
				blockArraySize++;
				continue;
			}
		}

		// scan through the right, and scan the block in memory for joins
		while (rightScan->GetNext(rightRid, (char *)rightRec, rightRecLen) != DONE) {
			for (int j = 0; j < blockSize; j++) {
				if (j >= blockArraySize) {
					break;
				}
				leftCurrRec = (int *) (blockArray + left.recLen * j);
				if (leftCurrRec[left.joinAttr] == rightRec[right.joinAttr]) {
					MakeNewRecord(newRec, (char *)leftCurrRec, (char *)rightRec, left, right);
					tmpHeap->InsertRecord(newRec, left.recLen + right.recLen, outRid);
				}
			}
		}
		rightScan->MoveTo(rightFirstRid);
		blockArraySize = 0;

		if (st == DONE) {
			break;
		}
	}

	out.file = tmpHeap;
	//std::cout << "NUM BNL: " << tmpHeap->GetNumOfRecords() << std::endl;

	delete leftScan;
	delete rightScan;
	delete blockArray;
	delete leftRec;
	delete rightRec;
	delete newRec;

	return OK;
}