6c92f85d10
Bring the Nexus/Praxis/Hexis integration in line with MAVEN_ECOSYSTEM_ARCHITECTURE.md: - Praxis over HTTP: drop the in-process praxis.db open (praxisstore/ praxistools) and call praxisd's /api/v1/tools/* API via a new praxisClient. Honors the "no component reads another's DB" invariant (AC#12). PraxisConfig.DBPath -> URL. - Hexis confirmation gate: mutating capabilities (ReadOnly=false) now park a bound pendingHexis confirmation and require a spoken "да" before executing; read-only run immediately (AC#7, no auto attention->action). - Capability safety: >1 verb match is ambiguous -> ask instead of firing the first; ambiguous Nexus resolution asks for clarification (AC#2). - Correlation IDs on Hexis execute, recorded in the cross-service trace. - Bug: importance arrives as JSON float64 over HTTP, not int. - Tests: confirm-gate, decline, read-only, and ambiguity paths. Build: vendor/ bakes in the hexis client (replace-directed at a sibling repo outside the Docker context); Dockerfile builds from vendor and no longer `go mod download`s the unreachable replace paths. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
583 lines
30 KiB
Go
583 lines
30 KiB
Go
// Code generated by modernc.org/undup from the per-target sqlite_*.go files; DO NOT EDIT.
|
|
|
|
//go:build (darwin && amd64) || (darwin && arm64) || (freebsd && amd64) || (freebsd && arm64) || (linux && amd64) || (linux && arm64) || (linux && loong64) || (linux && ppc64le) || (linux && riscv64) || (netbsd && amd64) || (openbsd && amd64) || (openbsd && arm64)
|
|
|
|
package sqlite3
|
|
|
|
import (
|
|
"unsafe"
|
|
|
|
"modernc.org/libc"
|
|
)
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This version of balance() handles the common special case where
|
|
// ** a new entry is being inserted on the extreme right-end of the
|
|
// ** tree, in other words, when the new entry will become the largest
|
|
// ** entry in the tree.
|
|
// **
|
|
// ** Instead of trying to balance the 3 right-most leaf pages, just add
|
|
// ** a new page to the right-hand side and put the one new entry in
|
|
// ** that page. This leaves the right side of the tree somewhat
|
|
// ** unbalanced. But odds are that we will be inserting new entries
|
|
// ** at the end soon afterwards so the nearly empty page will quickly
|
|
// ** fill up. On average.
|
|
// **
|
|
// ** pPage is the leaf page which is the right-most page in the tree.
|
|
// ** pParent is its parent. pPage must have a single overflow entry
|
|
// ** which is also the right-most entry on the page.
|
|
// **
|
|
// ** The pSpace buffer is used to store a temporary copy of the divider
|
|
// ** cell that will be inserted into pParent. Such a cell consists of a 4
|
|
// ** byte page number followed by a variable length integer. In other
|
|
// ** words, at most 13 bytes. Hence the pSpace buffer must be at
|
|
// ** least 13 bytes in size.
|
|
// */
|
|
func _balance_quick(tls *libc.TLS, pParent uintptr, pPage uintptr, pSpace uintptr) (r int32) {
|
|
bp := tls.Alloc(144)
|
|
defer tls.Free(144)
|
|
var pBt, pOut, pStop, v1, v3 uintptr
|
|
var v2 Tu8
|
|
var _ /* b at bp+32 */ TCellArray
|
|
var _ /* pCell at bp+16 */ uintptr
|
|
var _ /* pNew at bp+0 */ uintptr
|
|
var _ /* pgnoNew at bp+12 */ TPgno
|
|
var _ /* rc at bp+8 */ int32
|
|
var _ /* szCell at bp+24 */ Tu16
|
|
_, _, _, _, _, _ = pBt, pOut, pStop, v1, v2, v3
|
|
pBt = (*TMemPage)(unsafe.Pointer(pPage)).FpBt /* Page number of pNew */
|
|
if libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell) == 0 {
|
|
return _sqlite3CorruptError(tls, int32(81243))
|
|
} /* dbfuzz001.test */
|
|
/* Allocate a new page. This page will become the right-sibling of
|
|
** pPage. Make the parent page writable, so that the new divider cell
|
|
** may be inserted. If both these operations are successful, proceed.
|
|
*/
|
|
**(**int32)(__ccgo_up(bp + 8)) = _allocateBtreePage(tls, pBt, bp, bp+12, uint32(0), uint8(0))
|
|
if **(**int32)(__ccgo_up(bp + 8)) == SQLITE_OK {
|
|
pOut = pSpace + 4
|
|
**(**uintptr)(__ccgo_up(bp + 16)) = **(**uintptr)(__ccgo_up(pPage + 40))
|
|
**(**Tu16)(__ccgo_up(bp + 24)) = (*(*func(*libc.TLS, uintptr, uintptr) Tu16)(unsafe.Pointer(&struct{ uintptr }{(*TMemPage)(unsafe.Pointer(pPage)).FxCellSize})))(tls, pPage, **(**uintptr)(__ccgo_up(bp + 16)))
|
|
_zeroPage(tls, **(**uintptr)(__ccgo_up(bp)), libc.Int32FromInt32(PTF_INTKEY)|libc.Int32FromInt32(PTF_LEAFDATA)|libc.Int32FromInt32(PTF_LEAF))
|
|
(**(**TCellArray)(__ccgo_up(bp + 32))).FnCell = int32(1)
|
|
(**(**TCellArray)(__ccgo_up(bp + 32))).FpRef = pPage
|
|
(**(**TCellArray)(__ccgo_up(bp + 32))).FapCell = bp + 16
|
|
(**(**TCellArray)(__ccgo_up(bp + 32))).FszCell = bp + 24
|
|
**(**uintptr)(__ccgo_up(bp + 32 + 32)) = (*TMemPage)(unsafe.Pointer(pPage)).FaDataEnd
|
|
**(**int32)(__ccgo_up(bp + 32 + 80)) = int32(2)
|
|
**(**int32)(__ccgo_up(bp + 32 + 80 + uintptr(libc.Int32FromInt32(NB)*libc.Int32FromInt32(2)-libc.Int32FromInt32(1))*4)) = int32(0x7fffffff)
|
|
**(**int32)(__ccgo_up(bp + 8)) = _rebuildPage(tls, bp+32, 0, int32(1), **(**uintptr)(__ccgo_up(bp)))
|
|
if **(**int32)(__ccgo_up(bp + 8)) != 0 {
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
return **(**int32)(__ccgo_up(bp + 8))
|
|
}
|
|
(*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FnFree = libc.Int32FromUint32((*TBtShared)(unsafe.Pointer(pBt)).FusableSize - uint32((*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FcellOffset) - uint32(2) - uint32(**(**Tu16)(__ccgo_up(bp + 24))))
|
|
/* If this is an auto-vacuum database, update the pointer map
|
|
** with entries for the new page, and any pointer from the
|
|
** cell on the page to an overflow page. If either of these
|
|
** operations fails, the return code is set, but the contents
|
|
** of the parent page are still manipulated by the code below.
|
|
** That is Ok, at this point the parent page is guaranteed to
|
|
** be marked as dirty. Returning an error code will cause a
|
|
** rollback, undoing any changes made to the parent page.
|
|
*/
|
|
if (*TBtShared)(unsafe.Pointer(pBt)).FautoVacuum != 0 {
|
|
_ptrmapPut(tls, pBt, **(**TPgno)(__ccgo_up(bp + 12)), uint8(PTRMAP_BTREE), (*TMemPage)(unsafe.Pointer(pParent)).Fpgno, bp+8)
|
|
if libc.Int32FromUint16(**(**Tu16)(__ccgo_up(bp + 24))) > libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FminLocal) {
|
|
_ptrmapPutOvflPtr(tls, **(**uintptr)(__ccgo_up(bp)), **(**uintptr)(__ccgo_up(bp)), **(**uintptr)(__ccgo_up(bp + 16)), bp+8)
|
|
}
|
|
}
|
|
/* Create a divider cell to insert into pParent. The divider cell
|
|
** consists of a 4-byte page number (the page number of pPage) and
|
|
** a variable length key value (which must be the same value as the
|
|
** largest key on pPage).
|
|
**
|
|
** To find the largest key value on pPage, first find the right-most
|
|
** cell on pPage. The first two fields of this cell are the
|
|
** record-length (a variable length integer at most 32-bits in size)
|
|
** and the key value (a variable length integer, may have any value).
|
|
** The first of the while(...) loops below skips over the record-length
|
|
** field. The second while(...) loop copies the key value from the
|
|
** cell on pPage into the pSpace buffer.
|
|
*/
|
|
**(**uintptr)(__ccgo_up(bp + 16)) = (*TMemPage)(unsafe.Pointer(pPage)).FaData + uintptr(libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FmaskPage)&(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(pPage)).FaCellIdx + uintptr(int32(2)*(libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell)-int32(1))))))<<libc.Int32FromInt32(8)|libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(pPage)).FaCellIdx + uintptr(int32(2)*(libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell)-int32(1))) + 1)))))
|
|
pStop = **(**uintptr)(__ccgo_up(bp + 16)) + 9
|
|
for {
|
|
v1 = **(**uintptr)(__ccgo_up(bp + 16))
|
|
**(**uintptr)(__ccgo_up(bp + 16)) = **(**uintptr)(__ccgo_up(bp + 16)) + 1
|
|
if !(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v1)))&int32(0x80) != 0 && **(**uintptr)(__ccgo_up(bp + 16)) < pStop) {
|
|
break
|
|
}
|
|
}
|
|
pStop = **(**uintptr)(__ccgo_up(bp + 16)) + 9
|
|
for {
|
|
v1 = **(**uintptr)(__ccgo_up(bp + 16))
|
|
**(**uintptr)(__ccgo_up(bp + 16)) = **(**uintptr)(__ccgo_up(bp + 16)) + 1
|
|
v2 = **(**Tu8)(__ccgo_up(v1))
|
|
v3 = pOut
|
|
pOut = pOut + 1
|
|
**(**Tu8)(__ccgo_up(v3)) = v2
|
|
if !(libc.Int32FromUint8(v2)&int32(0x80) != 0 && **(**uintptr)(__ccgo_up(bp + 16)) < pStop) {
|
|
break
|
|
}
|
|
}
|
|
/* Insert the new divider cell into pParent. */
|
|
if **(**int32)(__ccgo_up(bp + 8)) == SQLITE_OK {
|
|
**(**int32)(__ccgo_up(bp + 8)) = _insertCell(tls, pParent, libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pParent)).FnCell), pSpace, int32(int64(pOut)-int64(pSpace)), uintptr(0), (*TMemPage)(unsafe.Pointer(pPage)).Fpgno)
|
|
}
|
|
/* Set the right-child pointer of pParent to point to the new page. */
|
|
_sqlite3Put4byte(tls, (*TMemPage)(unsafe.Pointer(pParent)).FaData+uintptr(libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pParent)).FhdrOffset)+int32(8)), **(**TPgno)(__ccgo_up(bp + 12)))
|
|
/* Release the reference to the new page. */
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
}
|
|
return **(**int32)(__ccgo_up(bp + 8))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Erase the given database page and all its children. Return
|
|
// ** the page to the freelist.
|
|
// */
|
|
func _clearDatabasePage(tls *libc.TLS, pBt uintptr, pgno TPgno, freePageFlag int32, pnChange uintptr) (r int32) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var hdr, i, v2 int32
|
|
var pCell uintptr
|
|
var _ /* info at bp+16 */ TCellInfo
|
|
var _ /* pPage at bp+0 */ uintptr
|
|
var _ /* rc at bp+8 */ int32
|
|
_, _, _, _ = hdr, i, pCell, v2
|
|
if pgno > _btreePagecount(tls, pBt) {
|
|
return _sqlite3CorruptError(tls, int32(83452))
|
|
}
|
|
**(**int32)(__ccgo_up(bp + 8)) = _getAndInitPage(tls, pBt, pgno, bp, 0)
|
|
if **(**int32)(__ccgo_up(bp + 8)) != 0 {
|
|
return **(**int32)(__ccgo_up(bp + 8))
|
|
}
|
|
if libc.Int32FromUint8((*TBtShared)(unsafe.Pointer(pBt)).FopenFlags)&int32(BTREE_SINGLE) == 0 && _sqlite3PagerPageRefcount(tls, (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FpDbPage) != int32(1)+libc.BoolInt32(pgno == uint32(1)) {
|
|
**(**int32)(__ccgo_up(bp + 8)) = _sqlite3CorruptError(tls, int32(83459))
|
|
goto cleardatabasepage_out
|
|
}
|
|
hdr = libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FhdrOffset)
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FnCell)) {
|
|
break
|
|
}
|
|
pCell = (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FaData + uintptr(libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FmaskPage)&(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FaCellIdx + uintptr(int32(2)*i))))<<libc.Int32FromInt32(8)|libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FaCellIdx + uintptr(int32(2)*i) + 1)))))
|
|
if !((*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).Fleaf != 0) {
|
|
**(**int32)(__ccgo_up(bp + 8)) = _clearDatabasePage(tls, pBt, _sqlite3Get4byte(tls, pCell), int32(1), pnChange)
|
|
if **(**int32)(__ccgo_up(bp + 8)) != 0 {
|
|
goto cleardatabasepage_out
|
|
}
|
|
}
|
|
(*(*func(*libc.TLS, uintptr, uintptr, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FxParseCell})))(tls, **(**uintptr)(__ccgo_up(bp)), pCell, bp+16)
|
|
if uint32((**(**TCellInfo)(__ccgo_up(bp + 16))).FnLocal) != (**(**TCellInfo)(__ccgo_up(bp + 16))).FnPayload {
|
|
**(**int32)(__ccgo_up(bp + 8)) = _clearCellOverflow(tls, **(**uintptr)(__ccgo_up(bp)), pCell, bp+16)
|
|
} else {
|
|
**(**int32)(__ccgo_up(bp + 8)) = SQLITE_OK
|
|
}
|
|
if **(**int32)(__ccgo_up(bp + 8)) != 0 {
|
|
goto cleardatabasepage_out
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if !((*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).Fleaf != 0) {
|
|
**(**int32)(__ccgo_up(bp + 8)) = _clearDatabasePage(tls, pBt, _sqlite3Get4byte(tls, (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FaData+uintptr(hdr+int32(8))), int32(1), pnChange)
|
|
if **(**int32)(__ccgo_up(bp + 8)) != 0 {
|
|
goto cleardatabasepage_out
|
|
}
|
|
if (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FintKey != 0 {
|
|
pnChange = uintptr(0)
|
|
}
|
|
}
|
|
if pnChange != 0 {
|
|
**(**Ti64)(__ccgo_up(pnChange)) += libc.Int64FromUint16((*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FnCell)
|
|
}
|
|
if freePageFlag != 0 {
|
|
_freePage(tls, **(**uintptr)(__ccgo_up(bp)), bp+8)
|
|
} else {
|
|
v2 = _sqlite3PagerWrite(tls, (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FpDbPage)
|
|
**(**int32)(__ccgo_up(bp + 8)) = v2
|
|
if v2 == 0 {
|
|
_zeroPage(tls, **(**uintptr)(__ccgo_up(bp)), libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FaData + uintptr(hdr))))|int32(PTF_LEAF))
|
|
}
|
|
}
|
|
goto cleardatabasepage_out
|
|
cleardatabasepage_out:
|
|
;
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
return **(**int32)(__ccgo_up(bp + 8))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The first argument, pCur, is a cursor opened on some b-tree. Count the
|
|
// ** number of entries in the b-tree and write the result to *pnEntry.
|
|
// **
|
|
// ** SQLITE_OK is returned if the operation is successfully executed.
|
|
// ** Otherwise, if an error is encountered (i.e. an IO error or database
|
|
// ** corruption) an SQLite error code is returned.
|
|
// */
|
|
func _sqlite3BtreeCount(tls *libc.TLS, db uintptr, pCur uintptr, pnEntry uintptr) (r int32) {
|
|
var iIdx, rc int32
|
|
var nEntry Ti64
|
|
var pPage uintptr
|
|
_, _, _, _ = iIdx, nEntry, pPage, rc
|
|
nEntry = 0 /* Return code */
|
|
rc = _moveToRoot(tls, pCur)
|
|
if rc == int32(SQLITE_EMPTY) {
|
|
**(**Ti64)(__ccgo_up(pnEntry)) = 0
|
|
return SQLITE_OK
|
|
}
|
|
/* Unless an error occurs, the following loop runs one iteration for each
|
|
** page in the B-Tree structure (not including overflow pages).
|
|
*/
|
|
for rc == SQLITE_OK && !(libc.AtomicLoadNInt32(db+432, libc.Int32FromInt32(__ATOMIC_RELAXED)) != 0) { /* Current page of the b-tree */
|
|
/* If this is a leaf page or the tree is not an int-key tree, then
|
|
** this page contains countable entries. Increment the entry counter
|
|
** accordingly.
|
|
*/
|
|
pPage = (*TBtCursor)(unsafe.Pointer(pCur)).FpPage
|
|
if (*TMemPage)(unsafe.Pointer(pPage)).Fleaf != 0 || !((*TMemPage)(unsafe.Pointer(pPage)).FintKey != 0) {
|
|
nEntry = nEntry + libc.Int64FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell)
|
|
}
|
|
/* pPage is a leaf node. This loop navigates the cursor so that it
|
|
** points to the first interior cell that it points to the parent of
|
|
** the next page in the tree that has not yet been visited. The
|
|
** pCur->aiIdx[pCur->iPage] value is set to the index of the parent cell
|
|
** of the page, or to the number of cells in the page if the next page
|
|
** to visit is the right-child of its parent.
|
|
**
|
|
** If all pages in the tree have been visited, return SQLITE_OK to the
|
|
** caller.
|
|
*/
|
|
if (*TMemPage)(unsafe.Pointer(pPage)).Fleaf != 0 {
|
|
for cond := true; cond; cond = libc.Int32FromUint16((*TBtCursor)(unsafe.Pointer(pCur)).Fix) >= libc.Int32FromUint16((*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).FnCell) {
|
|
if int32((*TBtCursor)(unsafe.Pointer(pCur)).FiPage) == 0 {
|
|
/* All pages of the b-tree have been visited. Return successfully. */
|
|
**(**Ti64)(__ccgo_up(pnEntry)) = nEntry
|
|
return _moveToRoot(tls, pCur)
|
|
}
|
|
_moveToParent(tls, pCur)
|
|
}
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).Fix = (*TBtCursor)(unsafe.Pointer(pCur)).Fix + 1
|
|
pPage = (*TBtCursor)(unsafe.Pointer(pCur)).FpPage
|
|
}
|
|
/* Descend to the child node of the cell that the cursor currently
|
|
** points at. This is the right-child if (iIdx==pPage->nCell).
|
|
*/
|
|
iIdx = libc.Int32FromUint16((*TBtCursor)(unsafe.Pointer(pCur)).Fix)
|
|
if iIdx == libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell) {
|
|
rc = _moveToChild(tls, pCur, _sqlite3Get4byte(tls, (*TMemPage)(unsafe.Pointer(pPage)).FaData+uintptr(libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pPage)).FhdrOffset)+int32(8))))
|
|
} else {
|
|
rc = _moveToChild(tls, pCur, _sqlite3Get4byte(tls, (*TMemPage)(unsafe.Pointer(pPage)).FaData+uintptr(libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FmaskPage)&(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(pPage)).FaCellIdx + uintptr(int32(2)*iIdx))))<<libc.Int32FromInt32(8)|libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(pPage)).FaCellIdx + uintptr(int32(2)*iIdx) + 1)))))))
|
|
}
|
|
}
|
|
/* An error has occurred. Return an error code. */
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Delete the entry that the cursor is pointing to.
|
|
// **
|
|
// ** If the BTREE_SAVEPOSITION bit of the flags parameter is zero, then
|
|
// ** the cursor is left pointing at an arbitrary location after the delete.
|
|
// ** But if that bit is set, then the cursor is left in a state such that
|
|
// ** the next call to BtreeNext() or BtreePrev() moves it to the same row
|
|
// ** as it would have been on if the call to BtreeDelete() had been omitted.
|
|
// **
|
|
// ** The BTREE_AUXDELETE bit of flags indicates that is one of several deletes
|
|
// ** associated with a single table entry and its indexes. Only one of those
|
|
// ** deletes is considered the "primary" delete. The primary delete occurs
|
|
// ** on a cursor that is not a BTREE_FORDELETE cursor. All but one delete
|
|
// ** operation on non-FORDELETE cursors is tagged with the AUXDELETE flag.
|
|
// ** The BTREE_AUXDELETE bit is a hint that is not used by this implementation,
|
|
// ** but which might be used by alternative storage engines.
|
|
// */
|
|
func _sqlite3BtreeDelete(tls *libc.TLS, pCur uintptr, flags Tu8) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var bPreserve Tu8
|
|
var iCellDepth, iCellIdx, nCell int32
|
|
var n TPgno
|
|
var p, pBt, pCell, pLeaf, pPage, pTmp, v2 uintptr
|
|
var v1 Ti8
|
|
var _ /* info at bp+8 */ TCellInfo
|
|
var _ /* rc at bp+0 */ int32
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _ = bPreserve, iCellDepth, iCellIdx, n, nCell, p, pBt, pCell, pLeaf, pPage, pTmp, v1, v2
|
|
p = (*TBtCursor)(unsafe.Pointer(pCur)).FpBtree
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt /* Keep cursor valid. 2 for CURSOR_SKIPNEXT */
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) != CURSOR_VALID {
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) >= int32(CURSOR_REQUIRESEEK) {
|
|
**(**int32)(__ccgo_up(bp)) = _btreeRestoreCursorPosition(tls, pCur)
|
|
if **(**int32)(__ccgo_up(bp)) != 0 || libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) != CURSOR_VALID {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
} else {
|
|
return _sqlite3CorruptError(tls, int32(83091))
|
|
}
|
|
}
|
|
iCellDepth = int32((*TBtCursor)(unsafe.Pointer(pCur)).FiPage)
|
|
iCellIdx = libc.Int32FromUint16((*TBtCursor)(unsafe.Pointer(pCur)).Fix)
|
|
pPage = (*TBtCursor)(unsafe.Pointer(pCur)).FpPage
|
|
if libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell) <= iCellIdx {
|
|
return _sqlite3CorruptError(tls, int32(83100))
|
|
}
|
|
pCell = (*TMemPage)(unsafe.Pointer(pPage)).FaData + uintptr(libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FmaskPage)&(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(pPage)).FaCellIdx + uintptr(int32(2)*iCellIdx))))<<libc.Int32FromInt32(8)|libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(pPage)).FaCellIdx + uintptr(int32(2)*iCellIdx) + 1)))))
|
|
if (*TMemPage)(unsafe.Pointer(pPage)).FnFree < 0 && _btreeComputeFreeSpace(tls, pPage) != 0 {
|
|
return _sqlite3CorruptError(tls, int32(83104))
|
|
}
|
|
if pCell < (*TMemPage)(unsafe.Pointer(pPage)).FaCellIdx+uintptr((*TMemPage)(unsafe.Pointer(pPage)).FnCell) {
|
|
return _sqlite3CorruptError(tls, int32(83107))
|
|
}
|
|
/* If the BTREE_SAVEPOSITION bit is on, then the cursor position must
|
|
** be preserved following this delete operation. If the current delete
|
|
** will cause a b-tree rebalance, then this is done by saving the cursor
|
|
** key and leaving the cursor in CURSOR_REQUIRESEEK state before
|
|
** returning.
|
|
**
|
|
** If the current delete will not cause a rebalance, then the cursor
|
|
** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
|
|
** before or after the deleted entry.
|
|
**
|
|
** The bPreserve value records which path is required:
|
|
**
|
|
** bPreserve==0 Not necessary to save the cursor position
|
|
** bPreserve==1 Use CURSOR_REQUIRESEEK to save the cursor position
|
|
** bPreserve==2 Cursor won't move. Set CURSOR_SKIPNEXT.
|
|
*/
|
|
bPreserve = libc.BoolUint8(libc.Int32FromUint8(flags)&int32(BTREE_SAVEPOSITION) != 0)
|
|
if bPreserve != 0 {
|
|
if !((*TMemPage)(unsafe.Pointer(pPage)).Fleaf != 0) || (*TMemPage)(unsafe.Pointer(pPage)).FnFree+libc.Int32FromUint16((*(*func(*libc.TLS, uintptr, uintptr) Tu16)(unsafe.Pointer(&struct{ uintptr }{(*TMemPage)(unsafe.Pointer(pPage)).FxCellSize})))(tls, pPage, pCell))+int32(2) > libc.Int32FromUint32((*TBtShared)(unsafe.Pointer(pBt)).FusableSize*libc.Uint32FromInt32(2)/libc.Uint32FromInt32(3)) || libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell) == int32(1) {
|
|
/* A b-tree rebalance will be required after deleting this entry.
|
|
** Save the cursor key. */
|
|
**(**int32)(__ccgo_up(bp)) = _saveCursorKey(tls, pCur)
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
} else {
|
|
bPreserve = uint8(2)
|
|
}
|
|
}
|
|
/* If the page containing the entry to delete is not a leaf page, move
|
|
** the cursor to the largest entry in the tree that is smaller than
|
|
** the entry being deleted. This cell will replace the cell being deleted
|
|
** from the internal node. The 'previous' entry is used for this instead
|
|
** of the 'next' entry, as the previous entry is always a part of the
|
|
** sub-tree headed by the child page of the cell being deleted. This makes
|
|
** balancing the tree following the delete operation easier. */
|
|
if !((*TMemPage)(unsafe.Pointer(pPage)).Fleaf != 0) {
|
|
**(**int32)(__ccgo_up(bp)) = _sqlite3BtreePrevious(tls, pCur, 0)
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
}
|
|
/* Save the positions of any other cursors open on this table before
|
|
** making any modifications. */
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FcurFlags)&int32(BTCF_Multiple) != 0 {
|
|
**(**int32)(__ccgo_up(bp)) = _saveAllCursors(tls, pBt, (*TBtCursor)(unsafe.Pointer(pCur)).FpgnoRoot, pCur)
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
}
|
|
/* If this is a delete operation to remove a row from a table b-tree,
|
|
** invalidate any incrblob cursors open on the row being deleted. */
|
|
if (*TBtCursor)(unsafe.Pointer(pCur)).FpKeyInfo == uintptr(0) && (*TBtree)(unsafe.Pointer(p)).FhasIncrblobCur != 0 {
|
|
_invalidateIncrblobCursors(tls, p, (*TBtCursor)(unsafe.Pointer(pCur)).FpgnoRoot, (*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnKey, 0)
|
|
}
|
|
/* Make the page containing the entry to be deleted writable. Then free any
|
|
** overflow pages associated with the entry and finally remove the cell
|
|
** itself from within the page. */
|
|
**(**int32)(__ccgo_up(bp)) = _sqlite3PagerWrite(tls, (*TMemPage)(unsafe.Pointer(pPage)).FpDbPage)
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
(*(*func(*libc.TLS, uintptr, uintptr, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TMemPage)(unsafe.Pointer(pPage)).FxParseCell})))(tls, pPage, pCell, bp+8)
|
|
if uint32((**(**TCellInfo)(__ccgo_up(bp + 8))).FnLocal) != (**(**TCellInfo)(__ccgo_up(bp + 8))).FnPayload {
|
|
**(**int32)(__ccgo_up(bp)) = _clearCellOverflow(tls, pPage, pCell, bp+8)
|
|
} else {
|
|
**(**int32)(__ccgo_up(bp)) = SQLITE_OK
|
|
}
|
|
_dropCell(tls, pPage, iCellIdx, libc.Int32FromUint16((**(**TCellInfo)(__ccgo_up(bp + 8))).FnSize), bp)
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
/* If the cell deleted was not located on a leaf page, then the cursor
|
|
** is currently pointing to the largest entry in the sub-tree headed
|
|
** by the child-page of the cell that was just deleted from an internal
|
|
** node. The cell from the leaf node needs to be moved to the internal
|
|
** node to replace the deleted cell. */
|
|
if !((*TMemPage)(unsafe.Pointer(pPage)).Fleaf != 0) {
|
|
pLeaf = (*TBtCursor)(unsafe.Pointer(pCur)).FpPage
|
|
if (*TMemPage)(unsafe.Pointer(pLeaf)).FnFree < 0 {
|
|
**(**int32)(__ccgo_up(bp)) = _btreeComputeFreeSpace(tls, pLeaf)
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
}
|
|
if iCellDepth < int32((*TBtCursor)(unsafe.Pointer(pCur)).FiPage)-int32(1) {
|
|
n = (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(pCur + 144 + uintptr(iCellDepth+int32(1))*8)))).Fpgno
|
|
} else {
|
|
n = (*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).Fpgno
|
|
}
|
|
pCell = (*TMemPage)(unsafe.Pointer(pLeaf)).FaData + uintptr(libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pLeaf)).FmaskPage)&(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(pLeaf)).FaCellIdx + uintptr(int32(2)*(libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pLeaf)).FnCell)-int32(1))))))<<libc.Int32FromInt32(8)|libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(pLeaf)).FaCellIdx + uintptr(int32(2)*(libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pLeaf)).FnCell)-int32(1))) + 1)))))
|
|
if pCell < (*TMemPage)(unsafe.Pointer(pLeaf)).FaData+4 {
|
|
return _sqlite3CorruptError(tls, int32(83198))
|
|
}
|
|
nCell = libc.Int32FromUint16((*(*func(*libc.TLS, uintptr, uintptr) Tu16)(unsafe.Pointer(&struct{ uintptr }{(*TMemPage)(unsafe.Pointer(pLeaf)).FxCellSize})))(tls, pLeaf, pCell))
|
|
pTmp = (*TBtShared)(unsafe.Pointer(pBt)).FpTmpSpace
|
|
**(**int32)(__ccgo_up(bp)) = _sqlite3PagerWrite(tls, (*TMemPage)(unsafe.Pointer(pLeaf)).FpDbPage)
|
|
if **(**int32)(__ccgo_up(bp)) == SQLITE_OK {
|
|
**(**int32)(__ccgo_up(bp)) = _insertCell(tls, pPage, iCellIdx, pCell-uintptr(4), nCell+int32(4), pTmp, n)
|
|
}
|
|
_dropCell(tls, pLeaf, libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pLeaf)).FnCell)-int32(1), nCell, bp)
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
}
|
|
/* Balance the tree. If the entry deleted was located on a leaf page,
|
|
** then the cursor still points to that page. In this case the first
|
|
** call to balance() repairs the tree, and the if(...) condition is
|
|
** never true.
|
|
**
|
|
** Otherwise, if the entry deleted was on an internal node page, then
|
|
** pCur is pointing to the leaf page from which a cell was removed to
|
|
** replace the cell deleted from the internal node. This is slightly
|
|
** tricky as the leaf node may be underfull, and the internal node may
|
|
** be either under or overfull. In this case run the balancing algorithm
|
|
** on the leaf node first. If the balance proceeds far enough up the
|
|
** tree that we can be sure that any problem in the internal node has
|
|
** been corrected, so be it. Otherwise, after balancing the leaf node,
|
|
** walk the cursor up the tree to the internal node and balance it as
|
|
** well. */
|
|
if (*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).FnFree*int32(3) <= libc.Int32FromUint32((*TBtShared)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpBt)).FusableSize)*int32(2) {
|
|
/* Optimization: If the free space is less than 2/3rds of the page,
|
|
** then balance() will always be a no-op. No need to invoke it. */
|
|
**(**int32)(__ccgo_up(bp)) = SQLITE_OK
|
|
} else {
|
|
**(**int32)(__ccgo_up(bp)) = _balance(tls, pCur)
|
|
}
|
|
if **(**int32)(__ccgo_up(bp)) == SQLITE_OK && int32((*TBtCursor)(unsafe.Pointer(pCur)).FiPage) > iCellDepth {
|
|
_releasePageNotNull(tls, (*TBtCursor)(unsafe.Pointer(pCur)).FpPage)
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FiPage = (*TBtCursor)(unsafe.Pointer(pCur)).FiPage - 1
|
|
for int32((*TBtCursor)(unsafe.Pointer(pCur)).FiPage) > iCellDepth {
|
|
v2 = pCur + 84
|
|
v1 = *(*Ti8)(unsafe.Pointer(v2))
|
|
*(*Ti8)(unsafe.Pointer(v2)) = *(*Ti8)(unsafe.Pointer(v2)) - 1
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(pCur + 144 + uintptr(v1)*8)))
|
|
}
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FpPage = **(**uintptr)(__ccgo_up(pCur + 144 + uintptr((*TBtCursor)(unsafe.Pointer(pCur)).FiPage)*8))
|
|
**(**int32)(__ccgo_up(bp)) = _balance(tls, pCur)
|
|
}
|
|
if **(**int32)(__ccgo_up(bp)) == SQLITE_OK {
|
|
if libc.Int32FromUint8(bPreserve) > int32(1) {
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FeState = uint8(CURSOR_SKIPNEXT)
|
|
if iCellIdx >= libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell) {
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FskipNext = -int32(1)
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).Fix = libc.Uint16FromInt32(libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell) - int32(1))
|
|
} else {
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FskipNext = int32(1)
|
|
}
|
|
} else {
|
|
**(**int32)(__ccgo_up(bp)) = _moveToRoot(tls, pCur)
|
|
if bPreserve != 0 {
|
|
_btreeReleaseAllCursorPages(tls, pCur)
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FeState = uint8(CURSOR_REQUIRESEEK)
|
|
}
|
|
if **(**int32)(__ccgo_up(bp)) == int32(SQLITE_EMPTY) {
|
|
**(**int32)(__ccgo_up(bp)) = SQLITE_OK
|
|
}
|
|
}
|
|
}
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** zIn is a UTF-16 encoded unicode string at least nByte bytes long.
|
|
// ** Return the number of bytes in the first nChar unicode characters
|
|
// ** in pZ. nChar must be non-negative. Surrogate pairs count as a single
|
|
// ** character.
|
|
// */
|
|
func _sqlite3Utf16ByteLen(tls *libc.TLS, zIn uintptr, nByte int32, nChar int32) (r int32) {
|
|
var c, n int32
|
|
var z, zEnd uintptr
|
|
_, _, _, _ = c, n, z, zEnd
|
|
z = zIn
|
|
zEnd = z + uintptr(nByte-int32(1))
|
|
n = 0
|
|
if true {
|
|
z = z + 1
|
|
}
|
|
for n < nChar && z <= zEnd {
|
|
c = libc.Int32FromUint8(**(**uint8)(__ccgo_up(z)))
|
|
z = z + uintptr(2)
|
|
if c >= int32(0xd8) && c < int32(0xdc) && z <= zEnd && libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) >= int32(0xdc) && libc.Int32FromUint8(**(**uint8)(__ccgo_up(z))) < int32(0xe0) {
|
|
z = z + uintptr(2)
|
|
}
|
|
n = n + 1
|
|
}
|
|
return int32(int64(z)-int64(zIn)) - libc.BoolInt32(true)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Check to see if the frame with header in aFrame[] and content
|
|
// ** in aData[] is valid. If it is a valid frame, fill *piPage and
|
|
// ** *pnTruncate and return true. Return if the frame is not valid.
|
|
// */
|
|
func _walDecodeFrame(tls *libc.TLS, pWal uintptr, piPage uintptr, pnTruncate uintptr, aData uintptr, aFrame uintptr) (r int32) {
|
|
var aCksum uintptr
|
|
var nativeCksum int32
|
|
var pgno Tu32
|
|
_, _, _ = aCksum, nativeCksum, pgno /* True for native byte-order checksums */
|
|
aCksum = pWal + 72 + 24 /* Page number of the frame */
|
|
/* A frame is only valid if the salt values in the frame-header
|
|
** match the salt values in the wal-header.
|
|
*/
|
|
if libc.Xmemcmp(tls, pWal+72+32, aFrame+8, uint64(8)) != 0 {
|
|
return 0
|
|
}
|
|
/* A frame is only valid if the page number is greater than zero.
|
|
*/
|
|
pgno = _sqlite3Get4byte(tls, aFrame)
|
|
if pgno == uint32(0) {
|
|
return 0
|
|
}
|
|
/* Need a valid page size
|
|
*/
|
|
if !((*TWal)(unsafe.Pointer(pWal)).FszPage != 0) {
|
|
return 0
|
|
}
|
|
/* A frame is only valid if a checksum of the WAL header,
|
|
** all prior frames, the first 16 bytes of this frame-header,
|
|
** and the frame-data matches the checksum in the last 8
|
|
** bytes of this frame-header.
|
|
*/
|
|
nativeCksum = libc.BoolInt32(libc.Int32FromUint8((*TWal)(unsafe.Pointer(pWal)).Fhdr.FbigEndCksum) == SQLITE_BIGENDIAN)
|
|
_walChecksumBytes(tls, nativeCksum, aFrame, int32(8), aCksum, aCksum)
|
|
_walChecksumBytes(tls, nativeCksum, aData, libc.Int32FromUint32((*TWal)(unsafe.Pointer(pWal)).FszPage), aCksum, aCksum)
|
|
if **(**Tu32)(__ccgo_up(aCksum)) != _sqlite3Get4byte(tls, aFrame+16) || **(**Tu32)(__ccgo_up(aCksum + 1*4)) != _sqlite3Get4byte(tls, aFrame+20) {
|
|
/* Checksum failed. */
|
|
return 0
|
|
}
|
|
/* If we reach this point, the frame is valid. Return the page number
|
|
** and the new database size.
|
|
*/
|
|
**(**Tu32)(__ccgo_up(piPage)) = pgno
|
|
**(**Tu32)(__ccgo_up(pnTruncate)) = _sqlite3Get4byte(tls, aFrame+4)
|
|
return int32(1)
|
|
}
|