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, ¤tKeys); 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; }
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, ¤tKeys); 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; }
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; }