Esempio n. 1
0
        // was:btreeMoveto
        private RC BtreeMoveTo(byte[] key, long nKey, bool biasRight, ref int pRes)
        {
            Btree.UnpackedRecord pIdxKey; // Unpacked index key
            var aSpace = new Btree.UnpackedRecord();

            if (key != null)
            {
                Debug.Assert(nKey == (long)(int)nKey);
                pIdxKey = Btree._vdbe.sqlite3VdbeRecordUnpack(this.KeyInfo, (int)nKey, key, aSpace, 16);
            }
            else
            {
                pIdxKey = null;
            }
            var rc = MoveToUnpacked(pIdxKey, nKey, biasRight, ref pRes);

            if (key != null)
            {
                Btree._vdbe.sqlite3VdbeDeleteUnpackedRecord(pIdxKey);
            }
            return(rc);
        }
Esempio n. 2
0
        // was:sqlite3BtreeMovetoUnpacked
        public RC MoveToUnpacked(Btree.UnpackedRecord idxKey, long intKey, bool biasRight, ref int pRes)
        {
            Debug.Assert(HoldsMutex());
            Debug.Assert(MutexEx.Held(Tree.DB.Mutex));
            Debug.Assert((idxKey == null) == (KeyInfo == null));
            // If the cursor is already positioned at the point we are trying to move to, then just return without doing any work
            if (State == CursorState.VALID && ValidNKey && Pages[0].HasIntKey)
            {
                if (Info.nKey == intKey)
                {
                    pRes = 0;
                    return(RC.OK);
                }
                if (AtLast && Info.nKey < intKey)
                {
                    pRes = -1;
                    return(RC.OK);
                }
            }
            var rc = MoveToRoot();

            if (rc != RC.OK)
            {
                return(rc);
            }
            Debug.Assert(Pages[PageID] != null);
            Debug.Assert(Pages[PageID].HasInit);
            Debug.Assert(Pages[PageID].Cells > 0 || State == CursorState.INVALID);
            if (State == CursorState.INVALID)
            {
                pRes = -1;
                Debug.Assert(Pages[PageID].Cells == 0);
                return(RC.OK);
            }
            Debug.Assert(Pages[0].HasIntKey || idxKey != null);
            for (; ;)
            {
                var page = Pages[PageID];
                // pPage.nCell must be greater than zero. If this is the root-page the cursor would have been INVALID above and this for(;;) loop
                // not run. If this is not the root-page, then the moveToChild() routine would have already detected db corruption. Similarly, pPage must
                // be the right kind (index or table) of b-tree page. Otherwise a moveToChild() or moveToRoot() call would have detected corruption.
                Debug.Assert(page.Cells > 0);
                Debug.Assert(page.HasIntKey == (idxKey == null));
                var lwr = 0;
                var upr = page.Cells - 1;
                int idx;
                PagesIndexs[PageID] = (ushort)(biasRight ? (idx = upr) : (idx = (upr + lwr) / 2));
                int c;
                for (; ;)
                {
                    Debug.Assert(idx == PagesIndexs[PageID]);
                    Info.nSize = 0;
                    var cell = page.FindCell(idx) + page.ChildPtrSize; // Pointer to current cell in pPage
                    if (page.HasIntKey)
                    {
                        var nCellKey = 0L;
                        if (page.HasData != 0)
                        {
                            uint dummy0;
                            cell += ConvertEx.GetVariant4(page.Data, (uint)cell, out dummy0);
                        }
                        ConvertEx.GetVariant9L(page.Data, (uint)cell, out nCellKey);
                        if (nCellKey == intKey)
                        {
                            c = 0;
                        }
                        else if (nCellKey < intKey)
                        {
                            c = -1;
                        }
                        else
                        {
                            Debug.Assert(nCellKey > intKey);
                            c = 1;
                        }
                        ValidNKey = true;
                        Info.nKey = nCellKey;
                    }
                    else
                    {
                        // The maximum supported page-size is 65536 bytes. This means that the maximum number of record bytes stored on an index B-Tree
                        // page is less than 16384 bytes and may be stored as a 2-byte varint. This information is used to attempt to avoid parsing
                        // the entire cell by checking for the cases where the record is stored entirely within the b-tree page by inspecting the first
                        // 2 bytes of the cell.
                        var nCell = (int)page.Data[cell + 0];
                        if (0 == (nCell & 0x80) && nCell <= page.MaxLocal)
                        {
                            // This branch runs if the record-size field of the cell is a single byte varint and the record fits entirely on the main b-tree page.
                            c = Btree._vdbe.sqlite3VdbeRecordCompare(nCell, page.Data, cell + 1, idxKey);
                        }
                        else if (0 == (page.Data[cell + 1] & 0x80) && (nCell = ((nCell & 0x7f) << 7) + page.Data[cell + 1]) <= page.MaxLocal)
                        {
                            // The record-size field is a 2 byte varint and the record fits entirely on the main b-tree page.
                            c = Btree._vdbe.sqlite3VdbeRecordCompare(nCell, page.Data, cell + 2, idxKey);
                        }
                        else
                        {
                            // The record flows over onto one or more overflow pages. In this case the whole cell needs to be parsed, a buffer allocated
                            // and accessPayload() used to retrieve the record into the buffer before VdbeRecordCompare() can be called.
                            var pCellBody = new byte[page.Data.Length - cell + page.ChildPtrSize];
                            Buffer.BlockCopy(page.Data, cell - page.ChildPtrSize, pCellBody, 0, pCellBody.Length);
                            page.btreeParseCellPtr(pCellBody, ref Info);
                            nCell = (int)Info.nKey;
                            var pCellKey = MallocEx.sqlite3Malloc(nCell);
                            rc = AccessPayload(0, (uint)nCell, pCellKey, false);
                            if (rc != RC.OK)
                            {
                                pCellKey = null;
                                goto moveto_finish;
                            }
                            c        = Btree._vdbe.sqlite3VdbeRecordCompare(nCell, pCellKey, idxKey);
                            pCellKey = null;
                        }
                    }
                    if (c == 0)
                    {
                        if (page.HasIntKey && 0 == page.Leaf)
                        {
                            lwr = idx;
                            upr = lwr - 1;
                            break;
                        }
                        else
                        {
                            pRes = 0;
                            rc   = RC.OK;
                            goto moveto_finish;
                        }
                    }
                    if (c < 0)
                    {
                        lwr = idx + 1;
                    }
                    else
                    {
                        upr = idx - 1;
                    }
                    if (lwr > upr)
                    {
                        break;
                    }
                    PagesIndexs[PageID] = (ushort)(idx = (lwr + upr) / 2);
                }
                Debug.Assert(lwr == upr + 1);
                Debug.Assert(page.HasInit);
                Pgno chldPg;
                if (page.Leaf != 0)
                {
                    chldPg = 0;
                }
                else if (lwr >= page.Cells)
                {
                    chldPg = ConvertEx.Get4(page.Data, page.HeaderOffset + 8);
                }
                else
                {
                    chldPg = ConvertEx.Get4(page.Data, page.FindCell(lwr));
                }
                if (chldPg == 0)
                {
                    Debug.Assert(PagesIndexs[PageID] < Pages[PageID].Cells);
                    pRes = c;
                    rc   = RC.OK;
                    goto moveto_finish;
                }
                PagesIndexs[PageID] = (ushort)lwr;
                Info.nSize          = 0;
                ValidNKey           = false;
                rc = MoveToChild(chldPg);
                if (rc != RC.OK)
                {
                    goto moveto_finish;
                }
            }
moveto_finish:
            return(rc);
        }