RC deleteKey(BTreeHandle *tree, Value *key) {
	RC rc;

	// get root page
	PageNumber rootPage;
	rc = -99;
	rc = getRootPage(tree, &rootPage);

	if (rc != RC_OK) {
		return rc;
	}

	RID result;
	BT_KeyPosition *kp;
	rc = -99;
	rc = searchKeyFromRoot(tree, key, &result, kp);

	if (rc == RC_KEY_SCOPE_FOUND) {
		return RC_IM_KEY_NOT_FOUND;
	} else if (rc != RC_OK) {
		return rc;
	}

	// the key is found, delete it

	// get N
	int n;
	rc = -99;
	rc = getN(tree, &n);

	if (rc != RC_OK) {
		return rc;
	}

	// get current keys
	int currentKeys;

	rc = -99;
	rc = getCurrentKeys(tree, kp->nodePage, &currentKeys);

	if (rc != RC_OK) {
		return rc;
	}

	// if current node is full, split it into two nodes
	if (currentKeys >= (int) ceil((double) n / 2.0f)) {
		rc = -99;
		rc = deleteOldKey(tree, kp);

		if (rc != RC_OK) {
			return rc;
		}
	} else {
		// combine
		combineNode();
	}
	return RC_OK;
}
Ejemplo n.º 2
0
static int recoverOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
  Recover *pRecover = (Recover*)pVTab;
  u32 iRootPage;                   
  int iEncoding;                   
  unsigned nPageSize;              
  Pager *pPager;                   
  RecoverLeafCursor *pLeafCursor;  
  RecoverCursor *pCursor;          
  int rc;

  FNENTRY();

  iRootPage = 0;
  rc = getRootPage(pRecover->db, pRecover->zDb, pRecover->zTable,
                   &iRootPage);
  if( rc!=SQLITE_OK ){
    return rc;
  }

  iEncoding = 0;
  rc = getEncoding(pRecover->db, pRecover->zDb, &iEncoding);
  if( rc!=SQLITE_OK ){
    return rc;
  }

  rc = GetPager(pRecover->db, pRecover->zDb, &pPager, &nPageSize);
  if( rc!=SQLITE_OK ){
    return rc;
  }

  rc = leafCursorCreate(pPager, nPageSize, iRootPage, &pLeafCursor);
  if( rc!=SQLITE_OK ){
    return rc;
  }

  pCursor = sqlite3_malloc(sizeof(RecoverCursor));
  if( !pCursor ){
    leafCursorDestroy(pLeafCursor);
    return SQLITE_NOMEM;
  }
  memset(pCursor, 0, sizeof(*pCursor));
  pCursor->base.pVtab = pVTab;
  pCursor->pLeafCursor = pLeafCursor;
  pCursor->iEncoding = iEncoding;

  
  pCursor->bEOF = (pLeafCursor->pPage==NULL);

  *ppCursor = (sqlite3_vtab_cursor*)pCursor;
  return SQLITE_OK;
}
/**************************************************************************************
 * Function Name: findKey
 *
 * Description:
 *		Get the RID the search key in given B+ Tree
 *		If not exist, return RC_IM_KEY_NOT_FOUND
 *
 * Parameters:
 * 		BTreeHandle *tree: Entry to the B+ Tree
 * 		Value *key: search key
 * 		RID *result: the RID for the key we found
 *
 * Return:
 *		RC: return code
 *
 * Author:
 *		Xiaolang Wang <*****@*****.**>
 *
 * History:
 *		Date        Name                                      Content
 *		----------  ----------------------------------------  ------------------------
 *		2015-04-27  Xiaolang Wang <*****@*****.**>     Initialization.
 **************************************************************************************/
RC findKey(BTreeHandle *tree, Value *key, RID *result) {
	RC rc;

	// get root page
	PageNumber rootPage;
	rc = -99;
	rc = getRootPage(tree, &rootPage);

	if (rc != RC_OK) {
		return rc;
	}

	BT_KeyPosition *kp;
	rc = -99;
	rc = searchKey(tree, key, result, kp);

	if (rc != RC_OK) {
		return rc;
	}

	return RC_OK;
}
RC insertKey(BTreeHandle *tree, Value *key, RID rid) {
	RC rc;

	// get root page
	PageNumber rootPage;
	rc = -99;
	rc = getRootPage(tree, &rootPage);

	if (rc != RC_OK) {
		return rc;
	}

	RID result;
	BT_KeyPosition *kp;
	rc = -99;
	rc = searchKeyFromRoot(tree, key, &result, kp);

	// if return RC_OK, then the to-be inserted key is found, return RC_IM_KEY_ALREADY_EXISTS
	// else if return RC_IM_KEY_NOT_FOUND, then the to-be inserted key is not in the tree, insert it
	// else, some error happens, return rc
	if (rc == RC_OK) {
		return RC_IM_KEY_ALREADY_EXISTS;
	} else if (rc == RC_IM_KEY_NOT_FOUND) {
		// start to insert

		// get N
		int n;
		rc = -99;
		rc = getN(tree, &n);

		if (rc != RC_OK) {
			return rc;
		}

		// get current keys
		int currentKeys;

		rc = -99;
		rc = getCurrentKeys(tree, kp->nodePage, &currentKeys);

		if (rc != RC_OK) {
			return rc;
		}

		// if current node is full, split it into two nodes
		if (currentKeys == n) {
			// split
			splitNode();
		} else {
			rc = -99;
			rc = insertLeafNode(tree, kp, key, &rid);

			if (rc != RC_OK) {
				return rc;
			}
		}

		// increment # of entries by 1
		int numEntries;

		rc = -99;
		rc = getNumEntries(tree, kp->nodePage, &numEntries);

		if (rc != RC_OK) {
			return rc;
		}

		rc = -99;
		rc = setNumEntries(tree, kp->nodePage, ++numEntries);

		if (rc != RC_OK) {
			return rc;
		}

	} else {
		return rc;
	}

	return RC_OK;
}
RC splitNode(BTreeHandle *tree, BT_KeyPosition *kp, Value *key, RID *rid) {
	BM_PageHandle *page = (BM_PageHandle *) malloc(sizeof(BM_PageHandle));
	BM_PageHandle *newPage = (BM_PageHandle *) malloc(sizeof(BM_PageHandle));
	RC rc;
	// currently the node has n keys and would be filled one more
	// split the node first - create a new node

	// get total node pages
	int totalNodePages;
	getTotalNodePages(tree, &totalNodePages);

	int newNode = totalNodePages;

	// get root page
	int rootPage;
	getRootPage(tree, &rootPage);

	// get n
	int n;
	getN(tree, &n);

	// pin the page
	rc = pinPage(BM, page, kp->nodePage);

	if (rc != RC_OK) {
		return rc;
	}

	int *ip = (int *) page->data;

	// get node state
	int nodeState = ip[0];

	// get current keys
	int currentKeys = ip[1];

	// get parent
	int parent = ip[2];

	// get right sibling
	int rightSibling = ip[4 + n + 2 * n];

	// THE NODE IS A LEAF
	if (nodeState == 2) {
		// copy the keys and key pointer into temp arrays
		int *keys = (int *) calloc(n + 1, sizeof(int)); // index is 0..n
		int *keyPointers = (int *) calloc(2 * (n + 2), sizeof(int)); // index is 0..2(n+1)+1

		memcpy((char *) keys, page->data + 4 * sizeof(int), n * sizeof(int));
		memcpy((char *) keyPointers, page->data + (4 + n) * sizeof(int),
				(2 * (n + 1)) * sizeof(int));

		// if i comes to the end of the array, then insert the new key and key pointer into the end of the array
		if (kp->keyPos == n) {
			keys[n] = key->v.intV;
			keyPointers[2 * (n + 1)] = rid.page;
			keyPointers[2 * (n + 1) + 1] = rid.slot;
		} else if (key->v.intV < keys[kp->keyPos]) {
			int j;
			for (j = n; j > kp->keyPos; j--) {
				keys[j] = keys[j - 1];
				keyPointers[2 * (j + 1)] = keyPointers[2 * j];
				keyPointers[2 * (j + 1) + 1] = keyPointers[2 * j + 1];
			}

			// after the for loop, the j comes to i (j = i)
			// insert the new key and key pointer into the j spot
			keys[j] = key->v.intV;
			keyPointers[2 * (j + 1)] = rid->page;
			keyPointers[2 * (j + 1) + 1] = rid->slot;
		}

		// get the new number of keys in the split node
		int newCurrentKeys = (int) ceil((double) n / 2.0f);

		// copy the first half into the original node
		memcpy(page->data + 4 * sizeof(int), (char *) keys,
				newCurrentKeys * sizeof(int));
		memcpy(page->data + (4 + n) * sizeof(int), (char *) keyPointers,
				(2 * newCurrentKeys) * sizeof(int));

		// unset the rest keys and key pointers
		memset(page->data + (4 + newCurrentKeys) * sizeof(int), 0,
				(n - newCurrentKeys) * sizeof(int));
		memset(page->data + (4 + n + 2 * (newCurrentKeys)) * sizeof(int), 0,
				2 * (n + 1 - newCurrentKeys) * sizeof(int));

		// set right sibling to the new node page
		ip[4 + n + 2 * n] = newNode;

		// create the new node, the new node page number is totalNodePages
		createNodePage(tree, newNode, nodeState, parent, kp->nodePage,
				rightSibling);

		// init the new node page
		// pin the page
		rc = pinPage(BM, newPage, newNode);

		if (rc != RC_OK) {
			return rc;
		}

		int *nip = newPage->data;

		nip[1] = newCurrentKeys;

		memcpy(newPage->data + 4 * sizeof(int), (char *) keys,
				newCurrentKeys * sizeof(int));
		memcpy(newPage->data + (4 + n) * sizeof(int), (char *) keyPointers,
				(2 * newCurrentKeys) * sizeof(int));

		// unpin the page
		rc = -99;
		rc = unpinPage(BM, newPage);

		if (rc != RC_OK) {
			return rc;
		}

		int pCurrentKeys;
		getCurrentKeys(tree, parent, &pCurrentKeys);

		// insert the smallest key in the right node into the parent
		if (pCurrentKeys < n) {
			// case 1 - parent is not full
			insertInternalNode();
		} else if (pCurrentKeys == n) {
			BT_KeyPosition *newKp;
			newKp->nodePage = parent;
			newKp->keyPos = -1;

			RID *newRid;
			newRid->page = newNode;
			newRid->slot = -1;

			Value *newKey;
			newKey->dt = DT_INT;
			newKey->v->intV = keys[newCurrentKeys];

			splitNode(tree, newKp, newKey, newRid);
		}
	} else if (kp->nodePage != rootPage) {
		// case 2 - parent is full, parent is not root

	} else if (kp->nodePage == rootPage) {
		// case 3 - parent is full, parent is root
	}

	// unpin the page
	rc = -99;
	rc = unpinPage(BM, page);

	if (rc != RC_OK) {
		return rc;
	}

	free(page);

	return RC_OK;
}
Ejemplo n.º 6
0
static int recoverInit(
  sqlite3 *db,                        
  void *pAux,                         
  int argc, const char *const*argv,   
  sqlite3_vtab **ppVtab,              
  char **pzErr                        
){
  const unsigned kTypeCol = 4;  
  Recover *pRecover;            
  char *zDot;                   
  u32 iRootPage;                
  char *zCreateSql;             
  int rc;

  
  if( ascii_strcasecmp(argv[1], "temp")!=0 ){
    *pzErr = sqlite3_mprintf("recover table must be in temp database");
    return SQLITE_MISUSE;
  }

  
  if( argc<=kTypeCol ){
    *pzErr = sqlite3_mprintf("no columns specified");
    return SQLITE_MISUSE;
  }

  pRecover = sqlite3_malloc(sizeof(Recover));
  if( !pRecover ){
    return SQLITE_NOMEM;
  }
  memset(pRecover, 0, sizeof(*pRecover));
  pRecover->base.pModule = &recoverModule;
  pRecover->db = db;

  
  zDot = strchr(argv[3], '.');
  if( !zDot ){
    pRecover->zDb = sqlite3_strdup(db->aDb[0].zName);
    pRecover->zTable = sqlite3_strdup(argv[3]);
  }else if( zDot>argv[3] && zDot[1]!='\0' ){
    pRecover->zDb = sqlite3_strndup(argv[3], zDot - argv[3]);
    pRecover->zTable = sqlite3_strdup(zDot + 1);
  }else{
    
    *pzErr = sqlite3_mprintf("ill-formed table specifier");
    recoverRelease(pRecover);
    return SQLITE_ERROR;
  }

  pRecover->nCols = argc - kTypeCol;
  pRecover->pTypes = sqlite3_malloc(pRecover->nCols);
  if( !pRecover->zDb || !pRecover->zTable || !pRecover->pTypes ){
    recoverRelease(pRecover);
    return SQLITE_NOMEM;
  }

  
  rc = getRootPage(pRecover->db, pRecover->zDb, pRecover->zTable, &iRootPage);
  if( rc!=SQLITE_OK ){
    *pzErr = sqlite3_mprintf("unable to find backing table");
    recoverRelease(pRecover);
    return rc;
  }

  
  rc = ParseColumnsAndGenerateCreate(pRecover->nCols, argv + kTypeCol,
                                     &zCreateSql, pRecover->pTypes, pzErr);
  if( rc!=SQLITE_OK ){
    recoverRelease(pRecover);
    return rc;
  }

  rc = sqlite3_declare_vtab(db, zCreateSql);
  sqlite3_free(zCreateSql);
  if( rc!=SQLITE_OK ){
    recoverRelease(pRecover);
    return rc;
  }

  *ppVtab = (sqlite3_vtab *)pRecover;
  return SQLITE_OK;
}