예제 #1
0
  /**
   * Remove the i-th cell from pPage. This routine effects pPage only. The cell content is not freed
   * or deallocated. It is assumed that the cell content has been copied someplace else. This
   * routine just removes the reference to the cell from pPage.
   *
   * <p>"sz" must be the number of bytes in the cell.
   *
   * @param idx
   * @param sz
   * @throws SqlJetException
   */
  public void dropCell(int idx, int sz) throws SqlJetException {

    final SqlJetMemPage pPage = this;

    int pc; /* Offset to cell content of cell being deleted */
    ISqlJetMemoryPointer data; /* pPage->aData */
    ISqlJetMemoryPointer ptr; /* Used to move bytes around within data[] */

    assert (idx >= 0 && idx < pPage.nCell);
    assert (sz == pPage.cellSize(idx));
    assert (pPage.pBt.mutex.held());
    data = pPage.aData;
    ptr = pointer(data, pPage.cellOffset + 2 * idx);
    pc = get2byte(ptr);
    if ((pc < pPage.hdrOffset + 6 + (pPage.leaf ? 0 : 4)) || (pc + sz > pPage.pBt.usableSize)) {
      throw new SqlJetException(SqlJetErrorCode.CORRUPT);
    }
    pPage.freeSpace(pc, sz);
    final ISqlJetMemoryPointer endPtr = pointer(data, pPage.cellOffset + 2 * pPage.nCell - 2);
    while (ptr.getPointer() < endPtr.getPointer()) {
      put2byte(ptr, get2byte(ptr, 2));
      movePtr(ptr, 2);
    }
    // put2byte(endPtr, 0);
    pPage.nCell--;
    put2byte(data, pPage.hdrOffset + 3, pPage.nCell);
    pPage.nFree += 2;
  }
예제 #2
0
  /**
   * Create the byte sequence used to represent a cell on page pPage and write that byte sequence
   * into pCell[]. Overflow pages are allocated and filled in as necessary. The calling procedure is
   * responsible for making sure sufficient space has been allocated for pCell[].
   *
   * <p>Note that pCell does not necessary need to point to the pPage->aData area. pCell might point
   * to some temporary storage. The cell will be constructed in this temporary area then copied into
   * pPage->aData later.
   *
   * @param pCell Complete text of the cell
   * @param pKey The key
   * @param nKey The key
   * @param pData The data
   * @param nData The data
   * @param nZero Extra zero bytes to append to pData
   * @return cell size
   * @throws SqlJetException
   */
  public int fillInCell(
      ISqlJetMemoryPointer pCell,
      ISqlJetMemoryPointer pKey,
      long nKey,
      ISqlJetMemoryPointer pData,
      int nData,
      int nZero)
      throws SqlJetException {

    final SqlJetMemPage pPage = this;
    int pnSize = 0;

    int nPayload;
    ISqlJetMemoryPointer pSrc;
    int nSrc, n;
    int spaceLeft;
    SqlJetMemPage pOvfl = null;
    SqlJetMemPage pToRelease = null;
    ISqlJetMemoryPointer pPrior;
    ISqlJetMemoryPointer pPayload;
    SqlJetBtreeShared pBt = pPage.pBt;
    int[] pgnoOvfl = {0};
    int nHeader;
    SqlJetBtreeCellInfo info;

    assert (pPage.pBt.mutex.held());

    /*
     * pPage is not necessarily writeable since pCell might be auxiliary*
     * buffer space that is separate from the pPage buffer area
     */
    assert (pCell.getBuffer() != pPage.aData.getBuffer() || pPage.pDbPage.isWriteable());

    /* Fill in the header. */
    nHeader = 0;
    if (!pPage.leaf) {
      nHeader += 4;
    }
    if (pPage.hasData) {
      nHeader += putVarint(pointer(pCell, nHeader), nData + nZero);
    } else {
      nData = nZero = 0;
    }
    nHeader += putVarint(pointer(pCell, nHeader), nKey);
    info = pPage.parseCellPtr(pCell);
    assert (info.nHeader == nHeader);
    assert (info.nKey == nKey);
    assert (info.nData == nData + nZero);

    /* Fill in the payload */
    nPayload = nData + nZero;
    if (pPage.intKey) {
      pSrc = pData;
      nSrc = nData;
      nData = 0;
    } else {
      /* TBD: Perhaps raise SQLITE_CORRUPT if nKey is larger than 31 bits? */
      nPayload += (int) nKey;
      pSrc = pKey;
      nSrc = (int) nKey;
    }
    pnSize = info.nSize;
    spaceLeft = info.nLocal;
    pPayload = pointer(pCell, nHeader);
    pPrior = pointer(pCell, info.iOverflow);

    while (nPayload > 0) {
      if (spaceLeft == 0) {
        int pgnoPtrmap = pgnoOvfl[0]; /*
                                               * Overflow page pointer-map entry
                                               * page
                                               */
        if (pBt.autoVacuum) {
          do {
            pgnoOvfl[0]++;
          } while (pBt.PTRMAP_ISPAGE(pgnoOvfl[0]) || pgnoOvfl[0] == pBt.PENDING_BYTE_PAGE());
        }
        try {
          pOvfl = pBt.allocatePage(pgnoOvfl, pgnoOvfl[0], false);
          /*
           * If the database supports auto-vacuum, and the second or
           * subsequent* overflow page is being allocated, add an
           * entry to the pointer-map* for that page now.** If this is
           * the first overflow page, then write a partial entry* to
           * the pointer-map. If we write nothing to this pointer-map
           * slot,* then the optimistic overflow chain processing in
           * clearCell()* may misinterpret the uninitialised values
           * and delete the* wrong pages from the database.
           */
          if (pBt.autoVacuum) {
            byte eType =
                (pgnoPtrmap != 0
                    ? SqlJetBtreeShared.PTRMAP_OVERFLOW2
                    : SqlJetBtreeShared.PTRMAP_OVERFLOW1);
            try {
              pBt.ptrmapPut(pgnoOvfl[0], eType, pgnoPtrmap);
            } catch (SqlJetException e) {
              releasePage(pOvfl);
            }
          }
        } catch (SqlJetException e) {
          releasePage(pToRelease);
          throw e;
        }

        /*
         * If pToRelease is not zero than pPrior points into the data
         * area* of pToRelease. Make sure pToRelease is still writeable.
         */
        assert (pToRelease == null || pToRelease.pDbPage.isWriteable());

        /*
         * If pPrior is part of the data area of pPage, then make sure
         * pPage* is still writeable
         */
        assert (pPrior.getBuffer() != pPage.aData.getBuffer() || pPage.pDbPage.isWriteable());

        put4byte(pPrior, pgnoOvfl[0]);
        releasePage(pToRelease);
        pToRelease = pOvfl;
        pPrior = pOvfl.aData;
        put4byte(pPrior, 0);
        pPayload = pointer(pOvfl.aData, 4);
        spaceLeft = pBt.usableSize - 4;
      }
      n = nPayload;
      if (n > spaceLeft) n = spaceLeft;

      /*
       * If pToRelease is not zero than pPayload points into the data area
       * * of pToRelease. Make sure pToRelease is still writeable.
       */
      assert (pToRelease == null || pToRelease.pDbPage.isWriteable());

      /*
       * If pPayload is part of the data area of pPage, then make sure
       * pPage* is still writeable
       */
      assert (pPayload.getBuffer() != pPage.aData.getBuffer() || pPage.pDbPage.isWriteable());

      if (nSrc > 0) {
        if (n > nSrc) n = nSrc;
        assert (pSrc != null);
        memcpy(pPayload, pSrc, n);
      } else {
        memset(pPayload, (byte) 0, n);
      }
      nPayload -= n;
      movePtr(pPayload, n);
      pSrc = pointer(pSrc, n);
      nSrc -= n;
      spaceLeft -= n;
      if (nSrc == 0) {
        nSrc = nData;
        pSrc = pData;
      }
    }
    releasePage(pToRelease);

    return pnSize;
  }