Files
sift/vendor/modernc.org/sqlite/lib/sqlite_g_000000000001dea8.go
T
kyle 2f9d3d97e6 p2: digest with in-sift FIFO, SQLite caches, Honcho context, recover
Dixie is capped (max_inflight 2, queue_depth 8, queue_wait 20s) and
never queued on llama-server. Streaming chat, thinking off, 45s
fallback to clean. Digest and chunk-embedding caches are
content-addressed SQLite (Honcho context is not cached). Recover
uses the guarded Fetcher. guardian-star is refused in code.
2026-09-22 23:54:49 -07:00

3108 lines
149 KiB
Go

// Code generated by modernc.org/undup from the per-target sqlite_*.go files; DO NOT EDIT.
//go:build (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 routine redistributes cells on the iParentIdx'th child of pParent
// ** (hereafter "the page") and up to 2 siblings so that all pages have about the
// ** same amount of free space. Usually a single sibling on either side of the
// ** page are used in the balancing, though both siblings might come from one
// ** side if the page is the first or last child of its parent. If the page
// ** has fewer than 2 siblings (something which can only happen if the page
// ** is a root page or a child of a root page) then all available siblings
// ** participate in the balancing.
// **
// ** The number of siblings of the page might be increased or decreased by
// ** one or two in an effort to keep pages nearly full but not over full.
// **
// ** Note that when this routine is called, some of the cells on the page
// ** might not actually be stored in MemPage.aData[]. This can happen
// ** if the page is overfull. This routine ensures that all cells allocated
// ** to the page and its siblings fit into MemPage.aData[] before returning.
// **
// ** In the course of balancing the page and its siblings, cells may be
// ** inserted into or removed from the parent page (pParent). Doing so
// ** may cause the parent page to become overfull or underfull. If this
// ** happens, it is the responsibility of the caller to invoke the correct
// ** balancing routine to fix this problem (see the balance() routine).
// **
// ** If this routine fails for any reason, it might leave the database
// ** in a corrupted state. So if this routine fails, the database should
// ** be rolled back.
// **
// ** The third argument to this function, aOvflSpace, is a pointer to a
// ** buffer big enough to hold one page. If while inserting cells into the parent
// ** page (pParent) the parent page becomes overfull, this buffer is
// ** used to store the parent's overflow cells. Because this function inserts
// ** a maximum of four divider cells into the parent page, and the maximum
// ** size of a cell stored within an internal node is always less than 1/4
// ** of the page-size, the aOvflSpace[] buffer is guaranteed to be large
// ** enough for all overflow cells.
// **
// ** If aOvflSpace is set to a null pointer, this function returns
// ** SQLITE_NOMEM.
// */
func _balance_nonroot(tls *libc.TLS, pParent uintptr, iParentIdx int32, aOvflSpace uintptr, isRoot int32, bBulk int32) (r1 int32) {
bp := tls.Alloc(208)
defer tls.Free(208)
var aData, aSpace1, p, pBt, pCell, pCell1, pNew1, pNew2, pOld, pOld1, pOld2, pRight, pSrcEnd, pTemp, pTemp1, piCell, piEnd, v17 uintptr
var aPgno [5]TPgno
var apDiv [2]uintptr
var apNew [5]uintptr
var cntNew, cntOld [5]int32
var cntOldNext, d, i, iB, iNew, iNew1, iOff, iOld, iOld1, iOvflSpace, iPg, iSpace1, j, k, leafData, limit, nMaxCells, nNew, nNewCell, nOld, nxDiv, pageFlags, r, sz1, sz2, szD, szLeft, szR, szRight, usableSpace, v1 int32
var fgA, fgB, leafCorrection, maskPage, sz Tu16
var key Tu32
var pgnoA, pgnoB, pgnoTemp TPgno
var szScratch Tu64
var v13, v14 bool
var v18 uint32
var _ /* abDone at bp+60 */ [5]Tu8
var _ /* apOld at bp+8 */ [3]uintptr
var _ /* b at bp+72 */ TCellArray
var _ /* info at bp+184 */ TCellInfo
var _ /* pNew at bp+176 */ uintptr
var _ /* pgno at bp+52 */ TPgno
var _ /* rc at bp+0 */ int32
var _ /* szNew at bp+32 */ [5]int32
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = aData, aPgno, aSpace1, apDiv, apNew, cntNew, cntOld, cntOldNext, d, fgA, fgB, i, iB, iNew, iNew1, iOff, iOld, iOld1, iOvflSpace, iPg, iSpace1, j, k, key, leafCorrection, leafData, limit, maskPage, nMaxCells, nNew, nNewCell, nOld, nxDiv, p, pBt, pCell, pCell1, pNew1, pNew2, pOld, pOld1, pOld2, pRight, pSrcEnd, pTemp, pTemp1, pageFlags, pgnoA, pgnoB, pgnoTemp, piCell, piEnd, r, sz, sz1, sz2, szD, szLeft, szR, szRight, szScratch, usableSpace, v1, v13, v14, v17, v18 /* The whole database */
nMaxCells = 0 /* Allocated size of apCell, szCell, aFrom. */
nNew = 0 /* Next divider slot in pParent->aCell[] */
**(**int32)(__ccgo_up(bp)) = SQLITE_OK /* Value of pPage->aData[0] */
iSpace1 = 0 /* First unused byte of aSpace1[] */
iOvflSpace = 0 /* Parsed information on cells being balanced */
libc.Xmemset(tls, bp+60, 0, uint64(5))
libc.Xmemset(tls, bp+72, 0, libc.Uint64FromInt64(104)-libc.Uint64FromInt64(4))
**(**int32)(__ccgo_up(bp + 72 + 80 + uintptr(libc.Int32FromInt32(NB)*libc.Int32FromInt32(2)-libc.Int32FromInt32(1))*4)) = int32(0x7fffffff)
pBt = (*TMemPage)(unsafe.Pointer(pParent)).FpBt
/* At this point pParent may have at most one overflow cell. And if
** this overflow cell is present, it must be the cell with
** index iParentIdx. This scenario comes about when this function
** is called (indirectly) from sqlite3BtreeDelete().
*/
if !(aOvflSpace != 0) {
return int32(SQLITE_NOMEM)
}
/* Find the sibling pages to balance. Also locate the cells in pParent
** that divide the siblings. An attempt is made to find NN siblings on
** either side of pPage. More siblings are taken from one side, however,
** if there are fewer than NN siblings on the other side. If pParent
** has NB or fewer children then all children of pParent are taken.
**
** This loop also drops the divider cells from the parent page. This
** way, the remainder of the function does not have to deal with any
** overflow cells in the parent page, since if any existed they will
** have already been removed.
*/
i = libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pParent)).FnOverflow) + libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pParent)).FnCell)
if i < int32(2) {
nxDiv = 0
} else {
if iParentIdx == 0 {
nxDiv = 0
} else {
if iParentIdx == i {
nxDiv = i - int32(2) + bBulk
} else {
nxDiv = iParentIdx - int32(1)
}
}
i = int32(2) - bBulk
}
nOld = i + int32(1)
if i+nxDiv-libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pParent)).FnOverflow) == libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pParent)).FnCell) {
pRight = (*TMemPage)(unsafe.Pointer(pParent)).FaData + uintptr(libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pParent)).FhdrOffset)+int32(8))
} else {
pRight = (*TMemPage)(unsafe.Pointer(pParent)).FaData + uintptr(libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pParent)).FmaskPage)&(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(pParent)).FaCellIdx + uintptr(int32(2)*(i+nxDiv-libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pParent)).FnOverflow))))))<<libc.Int32FromInt32(8)|libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(pParent)).FaCellIdx + uintptr(int32(2)*(i+nxDiv-libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pParent)).FnOverflow))) + 1)))))
}
**(**TPgno)(__ccgo_up(bp + 52)) = _sqlite3Get4byte(tls, pRight)
for int32(1) != 0 {
if **(**int32)(__ccgo_up(bp)) == SQLITE_OK {
**(**int32)(__ccgo_up(bp)) = _getAndInitPage(tls, pBt, **(**TPgno)(__ccgo_up(bp + 52)), bp+8+uintptr(i)*8, 0)
}
if **(**int32)(__ccgo_up(bp)) != 0 {
libc.Xmemset(tls, bp+8, 0, libc.Uint64FromInt32(i+libc.Int32FromInt32(1))*uint64(8))
goto balance_cleanup
}
if (*TMemPage)(unsafe.Pointer((**(**[3]uintptr)(__ccgo_up(bp + 8)))[i])).FnFree < 0 {
**(**int32)(__ccgo_up(bp)) = _btreeComputeFreeSpace(tls, (**(**[3]uintptr)(__ccgo_up(bp + 8)))[i])
if **(**int32)(__ccgo_up(bp)) != 0 {
libc.Xmemset(tls, bp+8, 0, libc.Uint64FromInt32(i)*uint64(8))
goto balance_cleanup
}
}
nMaxCells = nMaxCells + (libc.Int32FromUint16((*TMemPage)(unsafe.Pointer((**(**[3]uintptr)(__ccgo_up(bp + 8)))[i])).FnCell) + libc.Int32FromUint64(libc.Uint64FromInt64(32)/libc.Uint64FromInt64(8)))
v1 = i
i = i - 1
if v1 == 0 {
break
}
if (*TMemPage)(unsafe.Pointer(pParent)).FnOverflow != 0 && i+nxDiv == libc.Int32FromUint16(**(**Tu16)(__ccgo_up(pParent + 28))) {
apDiv[i] = **(**uintptr)(__ccgo_up(pParent + 40))
**(**TPgno)(__ccgo_up(bp + 52)) = _sqlite3Get4byte(tls, apDiv[i])
(**(**[5]int32)(__ccgo_up(bp + 32)))[i] = libc.Int32FromUint16((*(*func(*libc.TLS, uintptr, uintptr) Tu16)(unsafe.Pointer(&struct{ uintptr }{(*TMemPage)(unsafe.Pointer(pParent)).FxCellSize})))(tls, pParent, apDiv[i]))
(*TMemPage)(unsafe.Pointer(pParent)).FnOverflow = uint8(0)
} else {
apDiv[i] = (*TMemPage)(unsafe.Pointer(pParent)).FaData + uintptr(libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pParent)).FmaskPage)&(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(pParent)).FaCellIdx + uintptr(int32(2)*(i+nxDiv-libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pParent)).FnOverflow))))))<<libc.Int32FromInt32(8)|libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(pParent)).FaCellIdx + uintptr(int32(2)*(i+nxDiv-libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pParent)).FnOverflow))) + 1)))))
**(**TPgno)(__ccgo_up(bp + 52)) = _sqlite3Get4byte(tls, apDiv[i])
(**(**[5]int32)(__ccgo_up(bp + 32)))[i] = libc.Int32FromUint16((*(*func(*libc.TLS, uintptr, uintptr) Tu16)(unsafe.Pointer(&struct{ uintptr }{(*TMemPage)(unsafe.Pointer(pParent)).FxCellSize})))(tls, pParent, apDiv[i]))
/* Drop the cell from the parent page. apDiv[i] still points to
** the cell within the parent, even though it has been dropped.
** This is safe because dropping a cell only overwrites the first
** four bytes of it, and this function does not need the first
** four bytes of the divider cell. So the pointer is safe to use
** later on.
**
** But not if we are in secure-delete mode. In secure-delete mode,
** the dropCell() routine will overwrite the entire cell with zeroes.
** In this case, temporarily copy the cell into the aOvflSpace[]
** buffer. It will be copied out again as soon as the aSpace[] buffer
** is allocated. */
if libc.Int32FromUint16((*TBtShared)(unsafe.Pointer(pBt)).FbtsFlags)&int32(BTS_FAST_SECURE) != 0 {
/* If the following if() condition is not true, the db is corrupted.
** The call to dropCell() below will detect this. */
iOff = int32(int64(apDiv[i])) - int32(int64((*TMemPage)(unsafe.Pointer(pParent)).FaData))
if iOff+(**(**[5]int32)(__ccgo_up(bp + 32)))[i] <= libc.Int32FromUint32((*TBtShared)(unsafe.Pointer(pBt)).FusableSize) {
libc.Xmemcpy(tls, aOvflSpace+uintptr(iOff), apDiv[i], libc.Uint64FromInt32((**(**[5]int32)(__ccgo_up(bp + 32)))[i]))
apDiv[i] = aOvflSpace + uintptr(int64(apDiv[i])-int64((*TMemPage)(unsafe.Pointer(pParent)).FaData))
}
}
_dropCell(tls, pParent, i+nxDiv-libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pParent)).FnOverflow), (**(**[5]int32)(__ccgo_up(bp + 32)))[i], bp)
}
}
/* Make nMaxCells a multiple of 4 in order to preserve 8-byte
** alignment */
nMaxCells = (nMaxCells + int32(3)) & ^libc.Int32FromInt32(3)
/*
** Allocate space for memory structures
*/
szScratch = uint64(libc.Uint64FromInt32(nMaxCells)*uint64(8) + libc.Uint64FromInt32(nMaxCells)*uint64(2) + uint64((*TBtShared)(unsafe.Pointer(pBt)).FpageSize)) /* aSpace1 */
(**(**TCellArray)(__ccgo_up(bp + 72))).FapCell = _sqlite3DbMallocRaw(tls, uintptr(0), szScratch)
if (**(**TCellArray)(__ccgo_up(bp + 72))).FapCell == uintptr(0) {
**(**int32)(__ccgo_up(bp)) = int32(SQLITE_NOMEM)
goto balance_cleanup
}
(**(**TCellArray)(__ccgo_up(bp + 72))).FszCell = (**(**TCellArray)(__ccgo_up(bp + 72))).FapCell + uintptr(nMaxCells)*8
aSpace1 = (**(**TCellArray)(__ccgo_up(bp + 72))).FszCell + uintptr(nMaxCells)*2
/*
** Load pointers to all cells on sibling pages and the divider cells
** into the local b.apCell[] array. Make copies of the divider cells
** into space obtained from aSpace1[]. The divider cells have already
** been removed from pParent.
**
** If the siblings are on leaf pages, then the child pointers of the
** divider cells are stripped from the cells before they are copied
** into aSpace1[]. In this way, all cells in b.apCell[] are without
** child pointers. If siblings are not leaves, then all cell in
** b.apCell[] include child pointers. Either way, all cells in b.apCell[]
** are alike.
**
** leafCorrection: 4 if pPage is a leaf. 0 if pPage is not a leaf.
** leafData: 1 if pPage holds key+data and pParent holds only keys.
*/
(**(**TCellArray)(__ccgo_up(bp + 72))).FpRef = (**(**[3]uintptr)(__ccgo_up(bp + 8)))[0]
leafCorrection = libc.Uint16FromInt32(libc.Int32FromUint8((*TMemPage)(unsafe.Pointer((**(**TCellArray)(__ccgo_up(bp + 72))).FpRef)).Fleaf) * int32(4))
leafData = libc.Int32FromUint8((*TMemPage)(unsafe.Pointer((**(**TCellArray)(__ccgo_up(bp + 72))).FpRef)).FintKeyLeaf)
i = 0
for {
if !(i < nOld) {
break
}
pOld = (**(**[3]uintptr)(__ccgo_up(bp + 8)))[i]
limit = libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pOld)).FnCell)
aData = (*TMemPage)(unsafe.Pointer(pOld)).FaData
maskPage = (*TMemPage)(unsafe.Pointer(pOld)).FmaskPage
piCell = aData + uintptr((*TMemPage)(unsafe.Pointer(pOld)).FcellOffset)
/* Verify that all sibling pages are of the same "type" (table-leaf,
** table-interior, index-leaf, or index-interior).
*/
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(pOld)).FaData))) != libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer((**(**[3]uintptr)(__ccgo_up(bp + 8)))[0])).FaData))) {
**(**int32)(__ccgo_up(bp)) = _sqlite3CorruptError(tls, int32(81816))
goto balance_cleanup
}
/* Load b.apCell[] with pointers to all cells in pOld. If pOld
** contains overflow cells, include them in the b.apCell[] array
** in the correct spot.
**
** Note that when there are multiple overflow cells, it is always the
** case that they are sequential and adjacent. This invariant arises
** because multiple overflows can only occurs when inserting divider
** cells into a parent on a prior balance, and divider cells are always
** adjacent and are inserted in order. There is an assert() tagged
** with "NOTE 1" in the overflow cell insertion loop to prove this
** invariant.
**
** This must be done in advance. Once the balance starts, the cell
** offset section of the btree page will be overwritten and we will no
** long be able to find the cells if a pointer to each cell is not saved
** first.
*/
libc.Xmemset(tls, (**(**TCellArray)(__ccgo_up(bp + 72))).FszCell+uintptr((**(**TCellArray)(__ccgo_up(bp + 72))).FnCell)*2, 0, uint64(2)*libc.Uint64FromInt32(limit+libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pOld)).FnOverflow)))
if libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pOld)).FnOverflow) > 0 {
if limit < libc.Int32FromUint16(**(**Tu16)(__ccgo_up(pOld + 28))) {
**(**int32)(__ccgo_up(bp)) = _sqlite3CorruptError(tls, int32(81840))
goto balance_cleanup
}
limit = libc.Int32FromUint16(**(**Tu16)(__ccgo_up(pOld + 28)))
j = 0
for {
if !(j < limit) {
break
}
**(**uintptr)(__ccgo_up((**(**TCellArray)(__ccgo_up(bp + 72))).FapCell + uintptr((**(**TCellArray)(__ccgo_up(bp + 72))).FnCell)*8)) = aData + uintptr(libc.Int32FromUint16(maskPage)&(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(piCell)))<<libc.Int32FromInt32(8)|libc.Int32FromUint8(**(**Tu8)(__ccgo_up(piCell + 1)))))
piCell = piCell + uintptr(2)
(**(**TCellArray)(__ccgo_up(bp + 72))).FnCell = (**(**TCellArray)(__ccgo_up(bp + 72))).FnCell + 1
goto _3
_3:
;
j = j + 1
}
k = 0
for {
if !(k < libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pOld)).FnOverflow)) {
break
}
/* NOTE 1 */
**(**uintptr)(__ccgo_up((**(**TCellArray)(__ccgo_up(bp + 72))).FapCell + uintptr((**(**TCellArray)(__ccgo_up(bp + 72))).FnCell)*8)) = **(**uintptr)(__ccgo_up(pOld + 40 + uintptr(k)*8))
(**(**TCellArray)(__ccgo_up(bp + 72))).FnCell = (**(**TCellArray)(__ccgo_up(bp + 72))).FnCell + 1
goto _4
_4:
;
k = k + 1
}
}
piEnd = aData + uintptr((*TMemPage)(unsafe.Pointer(pOld)).FcellOffset) + uintptr(int32(2)*libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pOld)).FnCell))
for piCell < piEnd {
**(**uintptr)(__ccgo_up((**(**TCellArray)(__ccgo_up(bp + 72))).FapCell + uintptr((**(**TCellArray)(__ccgo_up(bp + 72))).FnCell)*8)) = aData + uintptr(libc.Int32FromUint16(maskPage)&(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(piCell)))<<libc.Int32FromInt32(8)|libc.Int32FromUint8(**(**Tu8)(__ccgo_up(piCell + 1)))))
piCell = piCell + uintptr(2)
(**(**TCellArray)(__ccgo_up(bp + 72))).FnCell = (**(**TCellArray)(__ccgo_up(bp + 72))).FnCell + 1
}
cntOld[i] = (**(**TCellArray)(__ccgo_up(bp + 72))).FnCell
if i < nOld-int32(1) && !(leafData != 0) {
sz = libc.Uint16FromInt32((**(**[5]int32)(__ccgo_up(bp + 32)))[i])
**(**Tu16)(__ccgo_up((**(**TCellArray)(__ccgo_up(bp + 72))).FszCell + uintptr((**(**TCellArray)(__ccgo_up(bp + 72))).FnCell)*2)) = sz
pTemp = aSpace1 + uintptr(iSpace1)
iSpace1 = iSpace1 + libc.Int32FromUint16(sz)
libc.Xmemcpy(tls, pTemp, apDiv[i], uint64(sz))
**(**uintptr)(__ccgo_up((**(**TCellArray)(__ccgo_up(bp + 72))).FapCell + uintptr((**(**TCellArray)(__ccgo_up(bp + 72))).FnCell)*8)) = pTemp + uintptr(leafCorrection)
**(**Tu16)(__ccgo_up((**(**TCellArray)(__ccgo_up(bp + 72))).FszCell + uintptr((**(**TCellArray)(__ccgo_up(bp + 72))).FnCell)*2)) = libc.Uint16FromInt32(libc.Int32FromUint16(**(**Tu16)(__ccgo_up((**(**TCellArray)(__ccgo_up(bp + 72))).FszCell + uintptr((**(**TCellArray)(__ccgo_up(bp + 72))).FnCell)*2))) - libc.Int32FromUint16(leafCorrection))
if !((*TMemPage)(unsafe.Pointer(pOld)).Fleaf != 0) {
/* The right pointer of the child page pOld becomes the left
** pointer of the divider cell */
libc.Xmemcpy(tls, **(**uintptr)(__ccgo_up((**(**TCellArray)(__ccgo_up(bp + 72))).FapCell + uintptr((**(**TCellArray)(__ccgo_up(bp + 72))).FnCell)*8)), (*TMemPage)(unsafe.Pointer(pOld)).FaData+8, uint64(4))
} else {
for libc.Int32FromUint16(**(**Tu16)(__ccgo_up((**(**TCellArray)(__ccgo_up(bp + 72))).FszCell + uintptr((**(**TCellArray)(__ccgo_up(bp + 72))).FnCell)*2))) < int32(4) {
/* Do not allow any cells smaller than 4 bytes. If a smaller cell
** does exist, pad it with 0x00 bytes. */
v1 = iSpace1
iSpace1 = iSpace1 + 1
**(**Tu8)(__ccgo_up(aSpace1 + uintptr(v1))) = uint8(0x00)
**(**Tu16)(__ccgo_up((**(**TCellArray)(__ccgo_up(bp + 72))).FszCell + uintptr((**(**TCellArray)(__ccgo_up(bp + 72))).FnCell)*2)) = **(**Tu16)(__ccgo_up((**(**TCellArray)(__ccgo_up(bp + 72))).FszCell + uintptr((**(**TCellArray)(__ccgo_up(bp + 72))).FnCell)*2)) + 1
}
}
(**(**TCellArray)(__ccgo_up(bp + 72))).FnCell = (**(**TCellArray)(__ccgo_up(bp + 72))).FnCell + 1
}
goto _2
_2:
;
i = i + 1
}
/*
** Figure out the number of pages needed to hold all b.nCell cells.
** Store this number in "k". Also compute szNew[] which is the total
** size of all cells on the i-th page and cntNew[] which is the index
** in b.apCell[] of the cell that divides page i from page i+1.
** cntNew[k] should equal b.nCell.
**
** Values computed by this block:
**
** k: The total number of sibling pages
** szNew[i]: Spaced used on the i-th sibling page.
** cntNew[i]: Index in b.apCell[] and b.szCell[] for the first cell to
** the right of the i-th sibling page.
** usableSpace: Number of bytes of space available on each sibling.
**
*/
usableSpace = libc.Int32FromUint32((*TBtShared)(unsafe.Pointer(pBt)).FusableSize - uint32(12) + uint32(leafCorrection))
v1 = libc.Int32FromInt32(0)
k = v1
i = v1
for {
if !(i < nOld) {
break
}
p = (**(**[3]uintptr)(__ccgo_up(bp + 8)))[i]
**(**uintptr)(__ccgo_up(bp + 72 + 32 + uintptr(k)*8)) = (*TMemPage)(unsafe.Pointer(p)).FaDataEnd
**(**int32)(__ccgo_up(bp + 72 + 80 + uintptr(k)*4)) = cntOld[i]
if k != 0 && **(**int32)(__ccgo_up(bp + 72 + 80 + uintptr(k)*4)) == **(**int32)(__ccgo_up(bp + 72 + 80 + uintptr(k-int32(1))*4)) {
k = k - 1 /* Omit b.ixNx[] entry for child pages with no cells */
}
if !(leafData != 0) {
k = k + 1
**(**uintptr)(__ccgo_up(bp + 72 + 32 + uintptr(k)*8)) = (*TMemPage)(unsafe.Pointer(pParent)).FaDataEnd
**(**int32)(__ccgo_up(bp + 72 + 80 + uintptr(k)*4)) = cntOld[i] + int32(1)
}
(**(**[5]int32)(__ccgo_up(bp + 32)))[i] = usableSpace - (*TMemPage)(unsafe.Pointer(p)).FnFree
j = 0
for {
if !(j < libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(p)).FnOverflow)) {
break
}
**(**int32)(__ccgo_up(bp + 32 + uintptr(i)*4)) += int32(2) + libc.Int32FromUint16((*(*func(*libc.TLS, uintptr, uintptr) Tu16)(unsafe.Pointer(&struct{ uintptr }{(*TMemPage)(unsafe.Pointer(p)).FxCellSize})))(tls, p, **(**uintptr)(__ccgo_up(p + 40 + uintptr(j)*8))))
goto _8
_8:
;
j = j + 1
}
cntNew[i] = cntOld[i]
goto _6
_6:
;
i = i + 1
k = k + 1
}
k = nOld
i = 0
for {
if !(i < k) {
break
}
for (**(**[5]int32)(__ccgo_up(bp + 32)))[i] > usableSpace {
if i+int32(1) >= k {
k = i + int32(2)
if k > libc.Int32FromInt32(NB)+libc.Int32FromInt32(2) {
**(**int32)(__ccgo_up(bp)) = _sqlite3CorruptError(tls, int32(81941))
goto balance_cleanup
}
(**(**[5]int32)(__ccgo_up(bp + 32)))[k-int32(1)] = 0
cntNew[k-int32(1)] = (**(**TCellArray)(__ccgo_up(bp + 72))).FnCell
}
sz1 = int32(2) + libc.Int32FromUint16(_cachedCellSize(tls, bp+72, cntNew[i]-int32(1)))
**(**int32)(__ccgo_up(bp + 32 + uintptr(i)*4)) -= sz1
if !(leafData != 0) {
if cntNew[i] < (**(**TCellArray)(__ccgo_up(bp + 72))).FnCell {
sz1 = int32(2) + libc.Int32FromUint16(_cachedCellSize(tls, bp+72, cntNew[i]))
} else {
sz1 = 0
}
}
**(**int32)(__ccgo_up(bp + 32 + uintptr(i+int32(1))*4)) += sz1
cntNew[i] = cntNew[i] - 1
}
for cntNew[i] < (**(**TCellArray)(__ccgo_up(bp + 72))).FnCell {
sz1 = int32(2) + libc.Int32FromUint16(_cachedCellSize(tls, bp+72, cntNew[i]))
if (**(**[5]int32)(__ccgo_up(bp + 32)))[i]+sz1 > usableSpace {
break
}
**(**int32)(__ccgo_up(bp + 32 + uintptr(i)*4)) += sz1
cntNew[i] = cntNew[i] + 1
if !(leafData != 0) {
if cntNew[i] < (**(**TCellArray)(__ccgo_up(bp + 72))).FnCell {
sz1 = int32(2) + libc.Int32FromUint16(_cachedCellSize(tls, bp+72, cntNew[i]))
} else {
sz1 = 0
}
}
**(**int32)(__ccgo_up(bp + 32 + uintptr(i+int32(1))*4)) -= sz1
}
if cntNew[i] >= (**(**TCellArray)(__ccgo_up(bp + 72))).FnCell {
k = i + int32(1)
} else {
if i > 0 {
v1 = cntNew[i-int32(1)]
} else {
v1 = 0
}
if cntNew[i] <= v1 {
**(**int32)(__ccgo_up(bp)) = _sqlite3CorruptError(tls, int32(81974))
goto balance_cleanup
}
}
goto _9
_9:
;
i = i + 1
}
/*
** The packing computed by the previous block is biased toward the siblings
** on the left side (siblings with smaller keys). The left siblings are
** always nearly full, while the right-most sibling might be nearly empty.
** The next block of code attempts to adjust the packing of siblings to
** get a better balance.
**
** This adjustment is more than an optimization. The packing above might
** be so out of balance as to be illegal. For example, the right-most
** sibling might be completely empty. This adjustment is not optional.
*/
i = k - int32(1)
for {
if !(i > 0) {
break
}
szRight = (**(**[5]int32)(__ccgo_up(bp + 32)))[i] /* Size of sibling on the right */
szLeft = (**(**[5]int32)(__ccgo_up(bp + 32)))[i-int32(1)] /* Index of first cell to the left of right sibling */
r = cntNew[i-int32(1)] - int32(1)
d = r + int32(1) - leafData
_cachedCellSize(tls, bp+72, d)
for cond := true; cond; cond = r >= 0 {
szR = libc.Int32FromUint16(_cachedCellSize(tls, bp+72, r))
szD = libc.Int32FromUint16(**(**Tu16)(__ccgo_up((**(**TCellArray)(__ccgo_up(bp + 72))).FszCell + uintptr(d)*2)))
if v14 = szRight != 0; v14 {
if v13 = bBulk != 0; !v13 {
if i == k-int32(1) {
v1 = 0
} else {
v1 = int32(2)
}
}
}
if v14 && (v13 || szRight+szD+int32(2) > szLeft-(szR+v1)) {
break
}
szRight = szRight + (szD + int32(2))
szLeft = szLeft - (szR + int32(2))
cntNew[i-int32(1)] = r
r = r - 1
d = d - 1
}
(**(**[5]int32)(__ccgo_up(bp + 32)))[i] = szRight
(**(**[5]int32)(__ccgo_up(bp + 32)))[i-int32(1)] = szLeft
if i > int32(1) {
v1 = cntNew[i-int32(2)]
} else {
v1 = 0
}
if cntNew[i-int32(1)] <= v1 {
**(**int32)(__ccgo_up(bp)) = _sqlite3CorruptError(tls, int32(82018))
goto balance_cleanup
}
goto _11
_11:
;
i = i - 1
}
/* Sanity check: For a non-corrupt database file one of the following
** must be true:
** (1) We found one or more cells (cntNew[0])>0), or
** (2) pPage is a virtual root page. A virtual root page is when
** the real root page is page 1 and we are the only child of
** that page.
*/
/*
** Allocate k new pages. Reuse old pages where possible.
*/
pageFlags = libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer((**(**[3]uintptr)(__ccgo_up(bp + 8)))[0])).FaData)))
i = 0
for {
if !(i < k) {
break
}
if i < nOld {
v17 = (**(**[3]uintptr)(__ccgo_up(bp + 8)))[i]
apNew[i] = v17
**(**uintptr)(__ccgo_up(bp + 176)) = v17
(**(**[3]uintptr)(__ccgo_up(bp + 8)))[i] = uintptr(0)
**(**int32)(__ccgo_up(bp)) = _sqlite3PagerWrite(tls, (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp + 176)))).FpDbPage)
nNew = nNew + 1
if _sqlite3PagerPageRefcount(tls, (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp + 176)))).FpDbPage) != int32(1)+libc.BoolInt32(i == iParentIdx-nxDiv) && **(**int32)(__ccgo_up(bp)) == SQLITE_OK {
**(**int32)(__ccgo_up(bp)) = _sqlite3CorruptError(tls, int32(82051))
}
if **(**int32)(__ccgo_up(bp)) != 0 {
goto balance_cleanup
}
} else {
if bBulk != 0 {
v18 = uint32(1)
} else {
v18 = **(**TPgno)(__ccgo_up(bp + 52))
}
**(**int32)(__ccgo_up(bp)) = _allocateBtreePage(tls, pBt, bp+176, bp+52, v18, uint8(0))
if **(**int32)(__ccgo_up(bp)) != 0 {
goto balance_cleanup
}
_zeroPage(tls, **(**uintptr)(__ccgo_up(bp + 176)), pageFlags)
apNew[i] = **(**uintptr)(__ccgo_up(bp + 176))
nNew = nNew + 1
cntOld[i] = (**(**TCellArray)(__ccgo_up(bp + 72))).FnCell
/* Set the pointer-map entry for the new sibling page. */
if (*TBtShared)(unsafe.Pointer(pBt)).FautoVacuum != 0 {
_ptrmapPut(tls, pBt, (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp + 176)))).Fpgno, uint8(PTRMAP_BTREE), (*TMemPage)(unsafe.Pointer(pParent)).Fpgno, bp)
if **(**int32)(__ccgo_up(bp)) != SQLITE_OK {
goto balance_cleanup
}
}
}
goto _16
_16:
;
i = i + 1
}
/*
** Reassign page numbers so that the new pages are in ascending order.
** This helps to keep entries in the disk file in order so that a scan
** of the table is closer to a linear scan through the file. That in turn
** helps the operating system to deliver pages from the disk more rapidly.
**
** An O(N*N) sort algorithm is used, but since N is never more than NB+2
** (5), that is not a performance concern.
**
** When NB==3, this one optimization makes the database about 25% faster
** for large insertions and deletions.
*/
i = 0
for {
if !(i < nNew) {
break
}
aPgno[i] = (*TMemPage)(unsafe.Pointer(apNew[i])).Fpgno
goto _19
_19:
;
i = i + 1
}
i = 0
for {
if !(i < nNew-int32(1)) {
break
}
iB = i
j = i + int32(1)
for {
if !(j < nNew) {
break
}
if (*TMemPage)(unsafe.Pointer(apNew[j])).Fpgno < (*TMemPage)(unsafe.Pointer(apNew[iB])).Fpgno {
iB = j
}
goto _21
_21:
;
j = j + 1
}
/* If apNew[i] has a page number that is bigger than any of the
** subsequence apNew[i] entries, then swap apNew[i] with the subsequent
** entry that has the smallest page number (which we know to be
** entry apNew[iB]).
*/
if iB != i {
pgnoA = (*TMemPage)(unsafe.Pointer(apNew[i])).Fpgno
pgnoB = (*TMemPage)(unsafe.Pointer(apNew[iB])).Fpgno
pgnoTemp = libc.Uint32FromInt32(_sqlite3PendingByte)/(*TBtShared)(unsafe.Pointer(pBt)).FpageSize + uint32(1)
fgA = (*TDbPage)(unsafe.Pointer((*TMemPage)(unsafe.Pointer(apNew[i])).FpDbPage)).Fflags
fgB = (*TDbPage)(unsafe.Pointer((*TMemPage)(unsafe.Pointer(apNew[iB])).FpDbPage)).Fflags
_sqlite3PagerRekey(tls, (*TMemPage)(unsafe.Pointer(apNew[i])).FpDbPage, pgnoTemp, fgB)
_sqlite3PagerRekey(tls, (*TMemPage)(unsafe.Pointer(apNew[iB])).FpDbPage, pgnoA, fgA)
_sqlite3PagerRekey(tls, (*TMemPage)(unsafe.Pointer(apNew[i])).FpDbPage, pgnoB, fgB)
(*TMemPage)(unsafe.Pointer(apNew[i])).Fpgno = pgnoB
(*TMemPage)(unsafe.Pointer(apNew[iB])).Fpgno = pgnoA
}
goto _20
_20:
;
i = i + 1
}
_sqlite3Put4byte(tls, pRight, (*TMemPage)(unsafe.Pointer(apNew[nNew-int32(1)])).Fpgno)
/* If the sibling pages are not leaves, ensure that the right-child pointer
** of the right-most new sibling page is set to the value that was
** originally in the same field of the right-most old sibling page. */
if pageFlags&int32(PTF_LEAF) == 0 && nOld != nNew {
if nNew > nOld {
pOld1 = apNew[nOld-int32(1)]
} else {
pOld1 = (**(**[3]uintptr)(__ccgo_up(bp + 8)))[nOld-int32(1)]
}
libc.Xmemcpy(tls, (*TMemPage)(unsafe.Pointer(apNew[nNew-int32(1)])).FaData+8, (*TMemPage)(unsafe.Pointer(pOld1)).FaData+8, uint64(4))
}
/* Make any required updates to pointer map entries associated with
** cells stored on sibling pages following the balance operation. Pointer
** map entries associated with divider cells are set by the insertCell()
** routine. The associated pointer map entries are:
**
** a) if the cell contains a reference to an overflow chain, the
** entry associated with the first page in the overflow chain, and
**
** b) if the sibling pages are not leaves, the child page associated
** with the cell.
**
** If the sibling pages are not leaves, then the pointer map entry
** associated with the right-child of each sibling may also need to be
** updated. This happens below, after the sibling pages have been
** populated, not here.
*/
if (*TBtShared)(unsafe.Pointer(pBt)).FautoVacuum != 0 {
v17 = apNew[0]
pOld2 = v17
pNew1 = v17
cntOldNext = libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pNew1)).FnCell) + libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pNew1)).FnOverflow)
iNew = 0
iOld = 0
i = 0
for {
if !(i < (**(**TCellArray)(__ccgo_up(bp + 72))).FnCell) {
break
}
pCell = **(**uintptr)(__ccgo_up((**(**TCellArray)(__ccgo_up(bp + 72))).FapCell + uintptr(i)*8))
for i == cntOldNext {
iOld = iOld + 1
if iOld < nNew {
v17 = apNew[iOld]
} else {
v17 = (**(**[3]uintptr)(__ccgo_up(bp + 8)))[iOld]
}
pOld2 = v17
cntOldNext = cntOldNext + (libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pOld2)).FnCell) + libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pOld2)).FnOverflow) + libc.BoolInt32(!(leafData != 0)))
}
if i == cntNew[iNew] {
iNew = iNew + 1
v1 = iNew
pNew1 = apNew[v1]
if !(leafData != 0) {
goto _23
}
}
/* Cell pCell is destined for new sibling page pNew. Originally, it
** was either part of sibling page iOld (possibly an overflow cell),
** or else the divider cell to the left of sibling page iOld. So,
** if sibling page iOld had the same page number as pNew, and if
** pCell really was a part of sibling page iOld (not a divider or
** overflow cell), we can skip updating the pointer map entries. */
if iOld >= nNew || (*TMemPage)(unsafe.Pointer(pNew1)).Fpgno != aPgno[iOld] || !(uint64(pCell) >= uint64((*TMemPage)(unsafe.Pointer(pOld2)).FaData) && uint64(pCell) < uint64((*TMemPage)(unsafe.Pointer(pOld2)).FaDataEnd)) {
if !(leafCorrection != 0) {
_ptrmapPut(tls, pBt, _sqlite3Get4byte(tls, pCell), uint8(PTRMAP_BTREE), (*TMemPage)(unsafe.Pointer(pNew1)).Fpgno, bp)
}
if libc.Int32FromUint16(_cachedCellSize(tls, bp+72, i)) > libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pNew1)).FminLocal) {
_ptrmapPutOvflPtr(tls, pNew1, pOld2, pCell, bp)
}
if **(**int32)(__ccgo_up(bp)) != 0 {
goto balance_cleanup
}
}
goto _23
_23:
;
i = i + 1
}
}
/* Insert new divider cells into pParent. */
i = 0
for {
if !(i < nNew-int32(1)) {
break
}
pNew2 = apNew[i]
j = cntNew[i]
pCell1 = **(**uintptr)(__ccgo_up((**(**TCellArray)(__ccgo_up(bp + 72))).FapCell + uintptr(j)*8))
sz2 = libc.Int32FromUint16(**(**Tu16)(__ccgo_up((**(**TCellArray)(__ccgo_up(bp + 72))).FszCell + uintptr(j)*2))) + libc.Int32FromUint16(leafCorrection)
pTemp1 = aOvflSpace + uintptr(iOvflSpace)
if !((*TMemPage)(unsafe.Pointer(pNew2)).Fleaf != 0) {
libc.Xmemcpy(tls, (*TMemPage)(unsafe.Pointer(pNew2)).FaData+8, pCell1, uint64(4))
} else {
if leafData != 0 {
j = j - 1
(*(*func(*libc.TLS, uintptr, uintptr, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TMemPage)(unsafe.Pointer(pNew2)).FxParseCell})))(tls, pNew2, **(**uintptr)(__ccgo_up((**(**TCellArray)(__ccgo_up(bp + 72))).FapCell + uintptr(j)*8)), bp+184)
pCell1 = pTemp1
sz2 = int32(4) + _sqlite3PutVarint(tls, pCell1+4, libc.Uint64FromInt64((**(**TCellInfo)(__ccgo_up(bp + 184))).FnKey))
pTemp1 = uintptr(0)
} else {
pCell1 = pCell1 - uintptr(4)
/* Obscure case for non-leaf-data trees: If the cell at pCell was
** previously stored on a leaf node, and its reported size was 4
** bytes, then it may actually be smaller than this
** (see btreeParseCellPtr(), 4 bytes is the minimum size of
** any cell). But it is important to pass the correct size to
** insertCell(), so reparse the cell now.
**
** This can only happen for b-trees used to evaluate "IN (SELECT ...)"
** and WITHOUT ROWID tables with exactly one column which is the
** primary key.
*/
if libc.Int32FromUint16(**(**Tu16)(__ccgo_up((**(**TCellArray)(__ccgo_up(bp + 72))).FszCell + uintptr(j)*2))) == int32(4) {
sz2 = libc.Int32FromUint16((*(*func(*libc.TLS, uintptr, uintptr) Tu16)(unsafe.Pointer(&struct{ uintptr }{(*TMemPage)(unsafe.Pointer(pParent)).FxCellSize})))(tls, pParent, pCell1))
}
}
}
iOvflSpace = iOvflSpace + sz2
k = 0
for {
if !(**(**int32)(__ccgo_up(bp + 72 + 80 + uintptr(k)*4)) <= j) {
break
}
goto _27
_27:
;
k = k + 1
}
pSrcEnd = **(**uintptr)(__ccgo_up(bp + 72 + 32 + uintptr(k)*8))
if uint64(pCell1) < uint64(pSrcEnd) && uint64(pCell1+uintptr(sz2)) > uint64(pSrcEnd) {
**(**int32)(__ccgo_up(bp)) = _sqlite3CorruptError(tls, int32(82257))
goto balance_cleanup
}
**(**int32)(__ccgo_up(bp)) = _insertCell(tls, pParent, nxDiv+i, pCell1, sz2, pTemp1, (*TMemPage)(unsafe.Pointer(pNew2)).Fpgno)
if **(**int32)(__ccgo_up(bp)) != SQLITE_OK {
goto balance_cleanup
}
goto _26
_26:
;
i = i + 1
}
/* Now update the actual sibling pages. The order in which they are updated
** is important, as this code needs to avoid disrupting any page from which
** cells may still to be read. In practice, this means:
**
** (1) If cells are moving left (from apNew[iPg] to apNew[iPg-1])
** then it is not safe to update page apNew[iPg] until after
** the left-hand sibling apNew[iPg-1] has been updated.
**
** (2) If cells are moving right (from apNew[iPg] to apNew[iPg+1])
** then it is not safe to update page apNew[iPg] until after
** the right-hand sibling apNew[iPg+1] has been updated.
**
** If neither of the above apply, the page is safe to update.
**
** The iPg value in the following loop starts at nNew-1 goes down
** to 0, then back up to nNew-1 again, thus making two passes over
** the pages. On the initial downward pass, only condition (1) above
** needs to be tested because (2) will always be true from the previous
** step. On the upward pass, both conditions are always true, so the
** upwards pass simply processes pages that were missed on the downward
** pass.
*/
i = int32(1) - nNew
for {
if !(i < nNew) {
break
}
if i < 0 {
v1 = -i
} else {
v1 = i
}
iPg = v1
if (**(**[5]Tu8)(__ccgo_up(bp + 60)))[iPg] != 0 {
goto _28
} /* Skip pages already processed */
if i >= 0 || cntOld[iPg-int32(1)] >= cntNew[iPg-int32(1)] {
/* Verify condition (1): If cells are moving left, update iPg
** only after iPg-1 has already been updated. */
/* Verify condition (2): If cells are moving right, update iPg
** only after iPg+1 has already been updated. */
if iPg == 0 {
v1 = libc.Int32FromInt32(0)
iOld1 = v1
iNew1 = v1
nNewCell = cntNew[0]
} else {
if iPg < nOld {
v1 = cntOld[iPg-int32(1)] + libc.BoolInt32(!(leafData != 0))
} else {
v1 = (**(**TCellArray)(__ccgo_up(bp + 72))).FnCell
}
iOld1 = v1
iNew1 = cntNew[iPg-int32(1)] + libc.BoolInt32(!(leafData != 0))
nNewCell = cntNew[iPg] - iNew1
}
**(**int32)(__ccgo_up(bp)) = _editPage(tls, apNew[iPg], iOld1, iNew1, nNewCell, bp+72)
if **(**int32)(__ccgo_up(bp)) != 0 {
goto balance_cleanup
}
(**(**[5]Tu8)(__ccgo_up(bp + 60)))[iPg] = (**(**[5]Tu8)(__ccgo_up(bp + 60)))[iPg] + 1
(*TMemPage)(unsafe.Pointer(apNew[iPg])).FnFree = usableSpace - (**(**[5]int32)(__ccgo_up(bp + 32)))[iPg]
}
goto _28
_28:
;
i = i + 1
}
/* All pages have been processed exactly once */
if isRoot != 0 && libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pParent)).FnCell) == 0 && libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pParent)).FhdrOffset) <= (*TMemPage)(unsafe.Pointer(apNew[0])).FnFree {
/* The root page of the b-tree now contains no cells. The only sibling
** page is the right-child of the parent. Copy the contents of the
** child page into the parent, decreasing the overall height of the
** b-tree structure by one. This is described as the "balance-shallower"
** sub-algorithm in some documentation.
**
** If this is an auto-vacuum database, the call to copyNodeContent()
** sets all pointer-map entries corresponding to database image pages
** for which the pointer is stored within the content being copied.
**
** It is critical that the child page be defragmented before being
** copied into the parent, because if the parent is page 1 then it will
** by smaller than the child due to the database header, and so all the
** free space needs to be up front.
*/
**(**int32)(__ccgo_up(bp)) = _defragmentPage(tls, apNew[0], -int32(1))
_copyNodeContent(tls, apNew[0], pParent, bp)
_freePage(tls, apNew[0], bp)
} else {
if (*TBtShared)(unsafe.Pointer(pBt)).FautoVacuum != 0 && !(leafCorrection != 0) {
/* Fix the pointer map entries associated with the right-child of each
** sibling page. All other pointer map entries have already been taken
** care of. */
i = 0
for {
if !(i < nNew) {
break
}
key = _sqlite3Get4byte(tls, (*TMemPage)(unsafe.Pointer(apNew[i])).FaData+8)
_ptrmapPut(tls, pBt, key, uint8(PTRMAP_BTREE), (*TMemPage)(unsafe.Pointer(apNew[i])).Fpgno, bp)
goto _32
_32:
;
i = i + 1
}
}
}
/* Free any old pages that were not reused as new pages.
*/
i = nNew
for {
if !(i < nOld) {
break
}
_freePage(tls, (**(**[3]uintptr)(__ccgo_up(bp + 8)))[i], bp)
goto _33
_33:
;
i = i + 1
}
/*
** Cleanup before returning.
*/
goto balance_cleanup
balance_cleanup:
;
_sqlite3DbFree(tls, uintptr(0), (**(**TCellArray)(__ccgo_up(bp + 72))).FapCell)
i = 0
for {
if !(i < nOld) {
break
}
_releasePage(tls, (**(**[3]uintptr)(__ccgo_up(bp + 8)))[i])
goto _34
_34:
;
i = i + 1
}
i = 0
for {
if !(i < nNew) {
break
}
_releasePage(tls, apNew[i])
goto _35
_35:
;
i = i + 1
}
return **(**int32)(__ccgo_up(bp))
}
// C documentation
//
// /*
// ** Argument pWhere is the WHERE clause belonging to SELECT statement p. This
// ** function attempts to transform expressions of the form:
// **
// ** EXISTS (SELECT ...)
// **
// ** into joins. For example, given
// **
// ** CREATE TABLE sailors(sid INTEGER PRIMARY KEY, name TEXT);
// ** CREATE TABLE reserves(sid INT, day DATE, PRIMARY KEY(sid, day));
// **
// ** SELECT name FROM sailors AS S WHERE EXISTS (
// ** SELECT * FROM reserves AS R WHERE S.sid = R.sid AND R.day = '2022-10-25'
// ** );
// **
// ** the SELECT statement may be transformed as follows:
// **
// ** SELECT name FROM sailors AS S, reserves AS R
// ** WHERE S.sid = R.sid AND R.day = '2022-10-25';
// **
// ** **Approximately**. Really, we have to ensure that the FROM-clause term
// ** that was formerly inside the EXISTS is only executed once. This is handled
// ** by setting the SrcItem.fg.fromExists flag, which then causes code in
// ** the where.c file to exit the corresponding loop after the first successful
// ** match (if any).
// */
func _existsToJoin(tls *libc.TLS, pParse uintptr, p uintptr, pWhere uintptr) {
var aCsrMap, db, pRight, pSub, pSubWhere uintptr
_, _, _, _, _ = aCsrMap, db, pRight, pSub, pSubWhere
if (*TParse)(unsafe.Pointer(pParse)).FnErr == 0 && pWhere != uintptr(0) && !((*TExpr)(unsafe.Pointer(pWhere)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)|libc.Int32FromInt32(EP_InnerON)) != libc.Uint32FromInt32(0)) && (*TSelect)(unsafe.Pointer(p)).FpSrc != uintptr(0) && (*TSrcList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(p)).FpSrc)).FnSrc < libc.Int32FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(8)) && ((*TSelect)(unsafe.Pointer(p)).FpLimit == uintptr(0) || (*TExpr)(unsafe.Pointer((*TSelect)(unsafe.Pointer(p)).FpLimit)).FpRight == uintptr(0)) {
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pWhere)).Fop) == int32(TK_AND) {
pRight = (*TExpr)(unsafe.Pointer(pWhere)).FpRight
_existsToJoin(tls, pParse, p, (*TExpr)(unsafe.Pointer(pWhere)).FpLeft)
_existsToJoin(tls, pParse, p, pRight)
} else {
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pWhere)).Fop) == int32(TK_EXISTS) {
pSub = *(*uintptr)(unsafe.Pointer(pWhere + 32))
pSubWhere = (*TSelect)(unsafe.Pointer(pSub)).FpWhere
if (*TSrcList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pSub)).FpSrc)).FnSrc == int32(1) && (*TSelect)(unsafe.Pointer(pSub)).FselFlags&uint32(SF_Aggregate) == uint32(0) && !(int32(*(*uint32)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pSub)).FpSrc + 8 + 24 + 4))&0x4>>2) != 0) && (*TSelect)(unsafe.Pointer(pSub)).FpLimit == uintptr(0) && (*TSelect)(unsafe.Pointer(pSub)).FpPrior == uintptr(0) {
/* Before combining the sub-select with the parent, renumber the
** cursor used by the subselect. This is because the EXISTS expression
** might be a copy of another EXISTS expression from somewhere
** else in the tree, and in this case it is important that it use
** a unique cursor number. */
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
aCsrMap = _sqlite3DbMallocZero(tls, db, uint64(libc.Uint64FromInt32((*TParse)(unsafe.Pointer(pParse)).FnTab+libc.Int32FromInt32(2))*uint64(4)))
if aCsrMap == uintptr(0) {
return
}
**(**int32)(__ccgo_up(aCsrMap)) = (*TParse)(unsafe.Pointer(pParse)).FnTab + int32(1)
_renumberCursors(tls, pParse, pSub, -int32(1), aCsrMap)
_sqlite3DbFree(tls, db, aCsrMap)
libc.Xmemset(tls, pWhere, 0, uint64(72))
(*TExpr)(unsafe.Pointer(pWhere)).Fop = uint8(TK_INTEGER)
*(*int32)(unsafe.Pointer(&(*TExpr)(unsafe.Pointer(pWhere)).Fu)) = int32(1)
**(**Tu32)(__ccgo_up(pWhere + 4)) |= libc.Uint32FromInt32(libc.Int32FromInt32(EP_IntValue))
libc.SetBitFieldPtr32Uint32((*TSelect)(unsafe.Pointer(pSub)).FpSrc+8+24+4, libc.Uint32FromInt32(1), 18, 0x40000)
(*TSelect)(unsafe.Pointer(p)).FpSrc = _sqlite3SrcListAppendList(tls, pParse, (*TSelect)(unsafe.Pointer(p)).FpSrc, (*TSelect)(unsafe.Pointer(pSub)).FpSrc)
if pSubWhere != 0 {
(*TSelect)(unsafe.Pointer(p)).FpWhere = _sqlite3PExpr(tls, pParse, int32(TK_AND), (*TSelect)(unsafe.Pointer(p)).FpWhere, pSubWhere)
(*TSelect)(unsafe.Pointer(pSub)).FpWhere = uintptr(0)
}
(*TSelect)(unsafe.Pointer(pSub)).FpSrc = uintptr(0)
_sqlite3ParserAddCleanup(tls, pParse, __ccgo_fp(_sqlite3SelectDeleteGeneric), pSub)
}
}
}
}
}
// C documentation
//
// /*
// ** This routine attempts to flatten subqueries as a performance optimization.
// ** This routine returns 1 if it makes changes and 0 if no flattening occurs.
// **
// ** To understand the concept of flattening, consider the following
// ** query:
// **
// ** SELECT a FROM (SELECT x+y AS a FROM t1 WHERE z<100) WHERE a>5
// **
// ** The default way of implementing this query is to execute the
// ** subquery first and store the results in a temporary table, then
// ** run the outer query on that temporary table. This requires two
// ** passes over the data. Furthermore, because the temporary table
// ** has no indices, the WHERE clause on the outer query cannot be
// ** optimized.
// **
// ** This routine attempts to rewrite queries such as the above into
// ** a single flat select, like this:
// **
// ** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5
// **
// ** The code generated for this simplification gives the same result
// ** but only has to scan the data once. And because indices might
// ** exist on the table t1, a complete scan of the data might be
// ** avoided.
// **
// ** Flattening is subject to the following constraints:
// **
// ** (**) We no longer attempt to flatten aggregate subqueries. Was:
// ** The subquery and the outer query cannot both be aggregates.
// **
// ** (**) We no longer attempt to flatten aggregate subqueries. Was:
// ** (2) If the subquery is an aggregate then
// ** (2a) the outer query must not be a join and
// ** (2b) the outer query must not use subqueries
// ** other than the one FROM-clause subquery that is a candidate
// ** for flattening. (This is due to ticket [2f7170d73bf9abf80]
// ** from 2015-02-09.)
// **
// ** (3) If the subquery is the right operand of a LEFT JOIN then
// ** (3a) the subquery may not be a join
// ** (**) Was (3b): "the FROM clause of the subquery may not contain
// ** a virtual table"
// ** (**) Was: "The outer query may not have a GROUP BY." This case
// ** is now managed correctly
// ** (3d) the outer query may not be DISTINCT.
// ** See also (26) for restrictions on RIGHT JOIN.
// **
// ** (4) The subquery can not be DISTINCT.
// **
// ** (**) At one point restrictions (4) and (5) defined a subset of DISTINCT
// ** sub-queries that were excluded from this optimization. Restriction
// ** (4) has since been expanded to exclude all DISTINCT subqueries.
// **
// ** (**) We no longer attempt to flatten aggregate subqueries. Was:
// ** If the subquery is aggregate, the outer query may not be DISTINCT.
// **
// ** (7) The subquery must have a FROM clause. TODO: For subqueries without
// ** A FROM clause, consider adding a FROM clause with the special
// ** table sqlite_once that consists of a single row containing a
// ** single NULL.
// **
// ** (8) If the subquery uses LIMIT then the outer query may not be a join.
// **
// ** (9) If the subquery uses LIMIT then the outer query may not be aggregate.
// **
// ** (**) Restriction (10) was removed from the code on 2005-02-05 but we
// ** accidentally carried the comment forward until 2014-09-15. Original
// ** constraint: "If the subquery is aggregate then the outer query
// ** may not use LIMIT."
// **
// ** (11) The subquery and the outer query may not both have ORDER BY clauses.
// **
// ** (**) Not implemented. Subsumed into restriction (3). Was previously
// ** a separate restriction deriving from ticket #350.
// **
// ** (13) The subquery and outer query may not both use LIMIT.
// **
// ** (14) The subquery may not use OFFSET.
// **
// ** (15) If the outer query is part of a compound select, then the
// ** subquery may not use LIMIT.
// ** (See ticket #2339 and ticket [02a8e81d44]).
// **
// ** (16) If the outer query is aggregate, then the subquery may not
// ** use ORDER BY. (Ticket #2942) This used to not matter
// ** until we introduced the group_concat() function.
// **
// ** (17) If the subquery is a compound select, then
// ** (17a) all compound operators must be a UNION ALL, and
// ** (17b) no terms within the subquery compound may be aggregate
// ** or DISTINCT, and
// ** (17c) every term within the subquery compound must have a FROM clause
// ** (17d) the outer query may not be
// ** (17d1) aggregate, or
// ** (17d2) DISTINCT
// ** (17e) the subquery may not contain window functions, and
// ** (17f) the subquery must not be the RHS of a LEFT JOIN.
// ** (17g) either the subquery is the first element of the outer
// ** query or there are no RIGHT or FULL JOINs in any arm
// ** of the subquery. (This is a duplicate of condition (27b).)
// ** (17h) The corresponding result set expressions in all arms of the
// ** compound must have the same affinity.
// **
// ** The parent and sub-query may contain WHERE clauses. Subject to
// ** rules (11), (13) and (14), they may also contain ORDER BY,
// ** LIMIT and OFFSET clauses. The subquery cannot use any compound
// ** operator other than UNION ALL because all the other compound
// ** operators have an implied DISTINCT which is disallowed by
// ** restriction (4).
// **
// ** Also, each component of the sub-query must return the same number
// ** of result columns. This is actually a requirement for any compound
// ** SELECT statement, but all the code here does is make sure that no
// ** such (illegal) sub-query is flattened. The caller will detect the
// ** syntax error and return a detailed message.
// **
// ** (18) If the sub-query is a compound select, then all terms of the
// ** ORDER BY clause of the parent must be copies of a term returned
// ** by the parent query.
// **
// ** (19) If the subquery uses LIMIT then the outer query may not
// ** have a WHERE clause.
// **
// ** (20) If the sub-query is a compound select, then it must not use
// ** an ORDER BY clause. Ticket #3773. We could relax this constraint
// ** somewhat by saying that the terms of the ORDER BY clause must
// ** appear as unmodified result columns in the outer query. But we
// ** have other optimizations in mind to deal with that case.
// **
// ** (21) If the subquery uses LIMIT then the outer query may not be
// ** DISTINCT. (See ticket [752e1646fc]).
// **
// ** (22) The subquery may not be a recursive CTE.
// **
// ** (23) If the outer query is a recursive CTE, then the sub-query may not be
// ** a compound query. This restriction is because transforming the
// ** parent to a compound query confuses the code that handles
// ** recursive queries in multiSelect().
// **
// ** (**) We no longer attempt to flatten aggregate subqueries. Was:
// ** The subquery may not be an aggregate that uses the built-in min() or
// ** or max() functions. (Without this restriction, a query like:
// ** "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily
// ** return the value X for which Y was maximal.)
// **
// ** (25) If either the subquery or the parent query contains a window
// ** function in the select list or ORDER BY clause, flattening
// ** is not attempted.
// **
// ** (26) The subquery may not be the right operand of a RIGHT JOIN.
// ** See also (3) for restrictions on LEFT JOIN.
// **
// ** (27) The subquery may not contain a FULL or RIGHT JOIN unless it
// ** is the first element of the parent query. Two subcases:
// ** (27a) the subquery is not a compound query.
// ** (27b) the subquery is a compound query and the RIGHT JOIN occurs
// ** in any arm of the compound query. (See also (17g).)
// **
// ** (28) The subquery is not a MATERIALIZED CTE. (This is handled
// ** in the caller before ever reaching this routine.)
// **
// **
// ** In this routine, the "p" parameter is a pointer to the outer query.
// ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query
// ** uses aggregates.
// **
// ** If flattening is not attempted, this routine is a no-op and returns 0.
// ** If flattening is attempted this routine returns 1.
// **
// ** All of the expression analysis must occur on both the outer query and
// ** the subquery before this routine runs.
// */
func _flattenSubquery(tls *libc.TLS, pParse uintptr, p uintptr, iFrom int32, isAgg int32) (r int32) {
bp := tls.Alloc(96)
defer tls.Free(96)
var aCsrMap, db, pItem, pItemTab, pLimit, pNew, pOrderBy, pOrderBy1, pParent, pPrior, pSrc, pSub, pSub1, pSubSrc, pSubitem, pTabToDel, pToplevel, pWhere, zSavedAuthContext, v5 uintptr
var i, iNewParent, iParent, ii, isOuterJoin, nSubSrc, v4 int32
var jointype Tu8
var _ /* w at bp+0 */ TWalker
var _ /* x at bp+48 */ TSubstContext
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = aCsrMap, db, i, iNewParent, iParent, ii, isOuterJoin, jointype, nSubSrc, pItem, pItemTab, pLimit, pNew, pOrderBy, pOrderBy1, pParent, pPrior, pSrc, pSub, pSub1, pSubSrc, pSubitem, pTabToDel, pToplevel, pWhere, zSavedAuthContext, v4, v5
zSavedAuthContext = (*TParse)(unsafe.Pointer(pParse)).FzAuthContext /* VDBE cursor number of the pSub result set temp table */
iNewParent = -int32(1) /* Replacement table for iParent */
isOuterJoin = 0 /* The subquery */
db = (*TParse)(unsafe.Pointer(pParse)).Fdb /* Walker to persist agginfo data */
aCsrMap = uintptr(0)
/* Check to see if flattening is permitted. Return 0 if not.
*/
if (*Tsqlite3)(unsafe.Pointer(db)).FdbOptFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_QueryFlattener)) != uint32(0) {
return 0
}
pSrc = (*TSelect)(unsafe.Pointer(p)).FpSrc
pSubitem = pSrc + 8 + uintptr(iFrom)*80
iParent = (*TSrcItem)(unsafe.Pointer(pSubitem)).FiCursor
pSub = (*TSubquery)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pSubitem + 72)))).FpSelect
if (*TSelect)(unsafe.Pointer(p)).FpWin != 0 || (*TSelect)(unsafe.Pointer(pSub)).FpWin != 0 {
return 0
} /* Restriction (25) */
pSubSrc = (*TSelect)(unsafe.Pointer(pSub)).FpSrc
/* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
** not arbitrary expressions, we allowed some combining of LIMIT and OFFSET
** because they could be computed at compile-time. But when LIMIT and OFFSET
** became arbitrary expressions, we were forced to add restrictions (13)
** and (14). */
if (*TSelect)(unsafe.Pointer(pSub)).FpLimit != 0 && (*TSelect)(unsafe.Pointer(p)).FpLimit != 0 {
return 0
} /* Restriction (13) */
if (*TSelect)(unsafe.Pointer(pSub)).FpLimit != 0 && (*TExpr)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pSub)).FpLimit)).FpRight != 0 {
return 0
} /* Restriction (14) */
if (*TSelect)(unsafe.Pointer(p)).FselFlags&uint32(SF_Compound) != uint32(0) && (*TSelect)(unsafe.Pointer(pSub)).FpLimit != 0 {
return 0 /* Restriction (15) */
}
if (*TSrcList)(unsafe.Pointer(pSubSrc)).FnSrc == 0 {
return 0
} /* Restriction (7) */
if (*TSelect)(unsafe.Pointer(pSub)).FselFlags&uint32(SF_Distinct) != 0 {
return 0
} /* Restriction (4) */
if (*TSelect)(unsafe.Pointer(pSub)).FpLimit != 0 && ((*TSrcList)(unsafe.Pointer(pSrc)).FnSrc > int32(1) || isAgg != 0) {
return 0 /* Restrictions (8)(9) */
}
if (*TSelect)(unsafe.Pointer(p)).FpOrderBy != 0 && (*TSelect)(unsafe.Pointer(pSub)).FpOrderBy != 0 {
return 0 /* Restriction (11) */
}
if isAgg != 0 && (*TSelect)(unsafe.Pointer(pSub)).FpOrderBy != 0 {
return 0
} /* Restriction (16) */
if (*TSelect)(unsafe.Pointer(pSub)).FpLimit != 0 && (*TSelect)(unsafe.Pointer(p)).FpWhere != 0 {
return 0
} /* Restriction (19) */
if (*TSelect)(unsafe.Pointer(pSub)).FpLimit != 0 && (*TSelect)(unsafe.Pointer(p)).FselFlags&uint32(SF_Distinct) != uint32(0) {
return 0 /* Restriction (21) */
}
if (*TSelect)(unsafe.Pointer(pSub)).FselFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SF_Recursive)) != 0 {
return 0 /* Restrictions (22) */
}
/*
** If the subquery is the right operand of a LEFT JOIN, then the
** subquery may not be a join itself (3a). Example of why this is not
** allowed:
**
** t1 LEFT OUTER JOIN (t2 JOIN t3)
**
** If we flatten the above, we would get
**
** (t1 LEFT OUTER JOIN t2) JOIN t3
**
** which is not at all the same thing.
**
** See also tickets #306, #350, and #3300.
*/
if libc.Int32FromUint8((*TSrcItem)(unsafe.Pointer(pSubitem)).Ffg.Fjointype)&(libc.Int32FromInt32(JT_OUTER)|libc.Int32FromInt32(JT_LTORJ)) != 0 {
if (*TSrcList)(unsafe.Pointer(pSubSrc)).FnSrc > int32(1) || (*TSelect)(unsafe.Pointer(p)).FselFlags&uint32(SF_Distinct) != uint32(0) || libc.Int32FromUint8((*TSrcItem)(unsafe.Pointer(pSubitem)).Ffg.Fjointype)&int32(JT_RIGHT) != 0 {
return 0
}
isOuterJoin = int32(1)
}
/* True by restriction (7) */
if iFrom > 0 && libc.Int32FromUint8((*(*TSrcItem)(unsafe.Pointer(pSubSrc + 8))).Ffg.Fjointype)&int32(JT_LTORJ) != 0 {
return 0 /* Restriction (27a) */
}
/* Condition (28) is blocked by the caller */
/* Restriction (17): If the sub-query is a compound SELECT, then it must
** use only the UNION ALL operator. And none of the simple select queries
** that make up the compound SELECT are allowed to be aggregate or distinct
** queries.
*/
if (*TSelect)(unsafe.Pointer(pSub)).FpPrior != 0 {
if (*TSelect)(unsafe.Pointer(pSub)).FpOrderBy != 0 {
return 0 /* Restriction (20) */
}
if isAgg != 0 || (*TSelect)(unsafe.Pointer(p)).FselFlags&uint32(SF_Distinct) != uint32(0) || isOuterJoin > 0 {
return 0 /* (17d1), (17d2), or (17f) */
}
pSub1 = pSub
for {
if !(pSub1 != 0) {
break
}
if (*TSelect)(unsafe.Pointer(pSub1)).FselFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SF_Distinct)|libc.Int32FromInt32(SF_Aggregate)) != uint32(0) || (*TSelect)(unsafe.Pointer(pSub1)).FpPrior != 0 && libc.Int32FromUint8((*TSelect)(unsafe.Pointer(pSub1)).Fop) != int32(TK_ALL) || (*TSrcList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pSub1)).FpSrc)).FnSrc < int32(1) || (*TSelect)(unsafe.Pointer(pSub1)).FpWin != 0 {
return 0
}
if iFrom > 0 && libc.Int32FromUint8((*(*TSrcItem)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pSub1)).FpSrc + 8))).Ffg.Fjointype)&int32(JT_LTORJ) != 0 {
/* Without this restriction, the JT_LTORJ flag would end up being
** omitted on left-hand tables of the right join that is being
** flattened. */
return 0 /* Restrictions (17g), (27b) */
}
goto _1
_1:
;
pSub1 = (*TSelect)(unsafe.Pointer(pSub1)).FpPrior
}
/* Restriction (18). */
if (*TSelect)(unsafe.Pointer(p)).FpOrderBy != 0 {
ii = 0
for {
if !(ii < (*TExprList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(p)).FpOrderBy)).FnExpr) {
break
}
if libc.Int32FromUint16(*(*Tu16)(unsafe.Pointer((*TSelect)(unsafe.Pointer(p)).FpOrderBy + 8 + uintptr(ii)*32 + 24))) == 0 {
return 0
}
goto _2
_2:
;
ii = ii + 1
}
}
/* Restriction (23) */
if (*TSelect)(unsafe.Pointer(p)).FselFlags&uint32(SF_Recursive) != 0 {
return 0
}
/* Restriction (17h) */
if _compoundHasDifferentAffinities(tls, pSub) != 0 {
return 0
}
if (*TSrcList)(unsafe.Pointer(pSrc)).FnSrc > int32(1) {
if (*TParse)(unsafe.Pointer(pParse)).FnSelect > int32(500) {
return 0
}
if (*Tsqlite3)(unsafe.Pointer(db)).FdbOptFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FlttnUnionAll)) != uint32(0) {
return 0
}
aCsrMap = _sqlite3DbMallocZero(tls, db, libc.Uint64FromInt64(int64((*TParse)(unsafe.Pointer(pParse)).FnTab)+libc.Int64FromInt32(1))*uint64(4))
if aCsrMap != 0 {
**(**int32)(__ccgo_up(aCsrMap)) = (*TParse)(unsafe.Pointer(pParse)).FnTab
}
}
}
/***** If we reach this point, flattening is permitted. *****/
/* Authorize the subquery */
(*TParse)(unsafe.Pointer(pParse)).FzAuthContext = (*TSrcItem)(unsafe.Pointer(pSubitem)).FzName
_sqlite3AuthCheck(tls, pParse, int32(SQLITE_SELECT), uintptr(0), uintptr(0), uintptr(0))
(*TParse)(unsafe.Pointer(pParse)).FzAuthContext = zSavedAuthContext
/* Delete the transient structures associated with the subquery */
if int32(*(*uint32)(unsafe.Pointer(pSubitem + 24 + 4))&0x4>>2) != 0 {
pSub1 = _sqlite3SubqueryDetach(tls, db, pSubitem)
} else {
pSub1 = uintptr(0)
}
_sqlite3DbFree(tls, db, (*TSrcItem)(unsafe.Pointer(pSubitem)).FzName)
_sqlite3DbFree(tls, db, (*TSrcItem)(unsafe.Pointer(pSubitem)).FzAlias)
(*TSrcItem)(unsafe.Pointer(pSubitem)).FzName = uintptr(0)
(*TSrcItem)(unsafe.Pointer(pSubitem)).FzAlias = uintptr(0)
/* If the sub-query is a compound SELECT statement, then (by restrictions
** 17 and 18 above) it must be a UNION ALL and the parent query must
** be of the form:
**
** SELECT <expr-list> FROM (<sub-query>) <where-clause>
**
** followed by any ORDER BY, LIMIT and/or OFFSET clauses. This block
** creates N-1 copies of the parent query without any ORDER BY, LIMIT or
** OFFSET clauses and joins them to the left-hand-side of the original
** using UNION ALL operators. In this case N is the number of simple
** select statements in the compound sub-query.
**
** Example:
**
** SELECT a+1 FROM (
** SELECT x FROM tab
** UNION ALL
** SELECT y FROM tab
** UNION ALL
** SELECT abs(z*2) FROM tab2
** ) WHERE a!=5 ORDER BY 1
**
** Transformed into:
**
** SELECT x+1 FROM tab WHERE x+1!=5
** UNION ALL
** SELECT y+1 FROM tab WHERE y+1!=5
** UNION ALL
** SELECT abs(z*2)+1 FROM tab2 WHERE abs(z*2)+1!=5
** ORDER BY 1
**
** We call this the "compound-subquery flattening".
*/
pSub = (*TSelect)(unsafe.Pointer(pSub)).FpPrior
for {
if !(pSub != 0) {
break
}
pOrderBy = (*TSelect)(unsafe.Pointer(p)).FpOrderBy
pLimit = (*TSelect)(unsafe.Pointer(p)).FpLimit
pPrior = (*TSelect)(unsafe.Pointer(p)).FpPrior
pItemTab = (*TSrcItem)(unsafe.Pointer(pSubitem)).FpSTab
(*TSrcItem)(unsafe.Pointer(pSubitem)).FpSTab = uintptr(0)
(*TSelect)(unsafe.Pointer(p)).FpOrderBy = uintptr(0)
(*TSelect)(unsafe.Pointer(p)).FpPrior = uintptr(0)
(*TSelect)(unsafe.Pointer(p)).FpLimit = uintptr(0)
pNew = _sqlite3SelectDup(tls, db, p, 0)
(*TSelect)(unsafe.Pointer(p)).FpLimit = pLimit
(*TSelect)(unsafe.Pointer(p)).FpOrderBy = pOrderBy
(*TSelect)(unsafe.Pointer(p)).Fop = uint8(TK_ALL)
(*TSrcItem)(unsafe.Pointer(pSubitem)).FpSTab = pItemTab
if pNew == uintptr(0) {
(*TSelect)(unsafe.Pointer(p)).FpPrior = pPrior
} else {
v5 = pParse + 132
*(*int32)(unsafe.Pointer(v5)) = *(*int32)(unsafe.Pointer(v5)) + 1
v4 = *(*int32)(unsafe.Pointer(v5))
(*TSelect)(unsafe.Pointer(pNew)).FselId = libc.Uint32FromInt32(v4)
if aCsrMap != 0 && libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed) == 0 {
_renumberCursors(tls, pParse, pNew, iFrom, aCsrMap)
}
(*TSelect)(unsafe.Pointer(pNew)).FpPrior = pPrior
if pPrior != 0 {
(*TSelect)(unsafe.Pointer(pPrior)).FpNext = pNew
}
(*TSelect)(unsafe.Pointer(pNew)).FpNext = p
(*TSelect)(unsafe.Pointer(p)).FpPrior = pNew
}
goto _3
_3:
;
pSub = (*TSelect)(unsafe.Pointer(pSub)).FpPrior
}
_sqlite3DbFree(tls, db, aCsrMap)
if (*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0 {
_sqlite3SrcItemAttachSubquery(tls, pParse, pSubitem, pSub1, 0)
return int32(1)
}
/* Defer deleting the Table object associated with the
** subquery until code generation is
** complete, since there may still exist Expr.pTab entries that
** refer to the subquery even after flattening. Ticket #3346.
**
** pSubitem->pSTab is always non-NULL by test restrictions and tests above.
*/
if (*TSrcItem)(unsafe.Pointer(pSubitem)).FpSTab != uintptr(0) {
pTabToDel = (*TSrcItem)(unsafe.Pointer(pSubitem)).FpSTab
if (*TTable)(unsafe.Pointer(pTabToDel)).FnTabRef == uint32(1) {
if (*TParse)(unsafe.Pointer(pParse)).FpToplevel != 0 {
v5 = (*TParse)(unsafe.Pointer(pParse)).FpToplevel
} else {
v5 = pParse
}
pToplevel = v5
_sqlite3ParserAddCleanup(tls, pToplevel, __ccgo_fp(_sqlite3DeleteTableGeneric), pTabToDel)
} else {
(*TTable)(unsafe.Pointer(pTabToDel)).FnTabRef = (*TTable)(unsafe.Pointer(pTabToDel)).FnTabRef - 1
}
(*TSrcItem)(unsafe.Pointer(pSubitem)).FpSTab = uintptr(0)
}
/* The following loop runs once for each term in a compound-subquery
** flattening (as described above). If we are doing a different kind
** of flattening - a flattening other than a compound-subquery flattening -
** then this loop only runs once.
**
** This loop moves all of the FROM elements of the subquery into the
** the FROM clause of the outer query. Before doing this, remember
** the cursor number for the original outer query FROM element in
** iParent. The iParent cursor will never be used. Subsequent code
** will scan expressions looking for iParent references and replace
** those references with expressions that resolve to the subquery FROM
** elements we are now copying in.
*/
pSub = pSub1
pParent = p
for {
if !(pParent != 0) {
break
}
jointype = (*TSrcItem)(unsafe.Pointer(pSubitem)).Ffg.Fjointype
pSubSrc = (*TSelect)(unsafe.Pointer(pSub)).FpSrc /* FROM clause of subquery */
nSubSrc = (*TSrcList)(unsafe.Pointer(pSubSrc)).FnSrc /* Number of terms in subquery FROM clause */
pSrc = (*TSelect)(unsafe.Pointer(pParent)).FpSrc /* FROM clause of the outer query */
/* The subquery uses a single slot of the FROM clause of the outer
** query. If the subquery has more than one element in its FROM clause,
** then expand the outer query to make space for it to hold all elements
** of the subquery.
**
** Example:
**
** SELECT * FROM tabA, (SELECT * FROM sub1, sub2), tabB;
**
** The outer query has 3 slots in its FROM clause. One slot of the
** outer query (the middle slot) is used by the subquery. The next
** block of code will expand the outer query FROM clause to 4 slots.
** The middle slot is expanded to two slots in order to make space
** for the two elements in the FROM clause of the subquery.
*/
if nSubSrc > int32(1) {
pSrc = _sqlite3SrcListEnlarge(tls, pParse, pSrc, nSubSrc-int32(1), iFrom+int32(1))
if pSrc == uintptr(0) {
break
}
(*TSelect)(unsafe.Pointer(pParent)).FpSrc = pSrc
pSubitem = pSrc + 8 + uintptr(iFrom)*80
}
/* Transfer the FROM clause terms from the subquery into the
** outer query.
*/
iNewParent = (*(*TSrcItem)(unsafe.Pointer(pSubSrc + 8))).FiCursor
i = 0
for {
if !(i < nSubSrc) {
break
}
pItem = pSrc + 8 + uintptr(i+iFrom)*80
if int32(*(*uint32)(unsafe.Pointer(pItem + 24 + 4))&0x800>>11) != 0 {
_sqlite3IdListDelete(tls, db, *(*uintptr)(unsafe.Pointer(pItem + 64)))
}
**(**TSrcItem)(__ccgo_up(pItem)) = *(*TSrcItem)(unsafe.Pointer(pSubSrc + 8 + uintptr(i)*80))
v5 = pItem + 24
*(*Tu8)(unsafe.Pointer(v5)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v5))) | libc.Int32FromUint8(jointype)&libc.Int32FromInt32(JT_LTORJ))
libc.Xmemset(tls, pSubSrc+8+uintptr(i)*80, 0, uint64(80))
goto _8
_8:
;
i = i + 1
}
v5 = pSubitem + 24
*(*Tu8)(unsafe.Pointer(v5)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v5))) | libc.Int32FromUint8(jointype))
/* Begin substituting subquery result set expressions for
** references to the iParent in the outer query.
**
** Example:
**
** SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b;
** \ \_____________ subquery __________/ /
** \_____________________ outer query ______________________________/
**
** We look at every expression in the outer query and every place we see
** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
*/
if (*TSelect)(unsafe.Pointer(pSub)).FpOrderBy != 0 {
/* At this point, any non-zero iOrderByCol values indicate that the
** ORDER BY column expression is identical to the iOrderByCol'th
** expression returned by SELECT statement pSub. Since these values
** do not necessarily correspond to columns in SELECT statement pParent,
** zero them before transferring the ORDER BY clause.
**
** Not doing this may cause an error if a subsequent call to this
** function attempts to flatten a compound sub-query into pParent.
** See ticket [d11a6e908f].
*/
pOrderBy1 = (*TSelect)(unsafe.Pointer(pSub)).FpOrderBy
i = 0
for {
if !(i < (*TExprList)(unsafe.Pointer(pOrderBy1)).FnExpr) {
break
}
*(*Tu16)(unsafe.Pointer(pOrderBy1 + 8 + uintptr(i)*32 + 24)) = uint16(0)
goto _11
_11:
;
i = i + 1
}
(*TSelect)(unsafe.Pointer(pParent)).FpOrderBy = pOrderBy1
(*TSelect)(unsafe.Pointer(pSub)).FpOrderBy = uintptr(0)
}
pWhere = (*TSelect)(unsafe.Pointer(pSub)).FpWhere
(*TSelect)(unsafe.Pointer(pSub)).FpWhere = uintptr(0)
if isOuterJoin > 0 {
_sqlite3SetJoinExpr(tls, pWhere, iNewParent, uint32(EP_OuterON))
}
if pWhere != 0 {
if (*TSelect)(unsafe.Pointer(pParent)).FpWhere != 0 {
(*TSelect)(unsafe.Pointer(pParent)).FpWhere = _sqlite3PExpr(tls, pParse, int32(TK_AND), pWhere, (*TSelect)(unsafe.Pointer(pParent)).FpWhere)
} else {
(*TSelect)(unsafe.Pointer(pParent)).FpWhere = pWhere
}
}
if libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed) == 0 {
(**(**TSubstContext)(__ccgo_up(bp + 48))).FpParse = pParse
(**(**TSubstContext)(__ccgo_up(bp + 48))).FiTable = iParent
(**(**TSubstContext)(__ccgo_up(bp + 48))).FiNewTable = iNewParent
(**(**TSubstContext)(__ccgo_up(bp + 48))).FisOuterJoin = isOuterJoin
(**(**TSubstContext)(__ccgo_up(bp + 48))).FnSelDepth = 0
(**(**TSubstContext)(__ccgo_up(bp + 48))).FpEList = (*TSelect)(unsafe.Pointer(pSub)).FpEList
(**(**TSubstContext)(__ccgo_up(bp + 48))).FpCList = _findLeftmostExprlist(tls, pSub)
_substSelect(tls, bp+48, pParent, 0)
}
/* The flattened query is a compound if either the inner or the
** outer query is a compound. */
**(**Tu32)(__ccgo_up(pParent + 4)) |= (*TSelect)(unsafe.Pointer(pSub)).FselFlags & uint32(SF_Compound)
/* restriction (17b) */
/*
** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y;
**
** One is tempted to try to add a and b to combine the limits. But this
** does not work if either limit is negative.
*/
if (*TSelect)(unsafe.Pointer(pSub)).FpLimit != 0 {
(*TSelect)(unsafe.Pointer(pParent)).FpLimit = (*TSelect)(unsafe.Pointer(pSub)).FpLimit
(*TSelect)(unsafe.Pointer(pSub)).FpLimit = uintptr(0)
}
/* Recompute the SrcItem.colUsed masks for the flattened
** tables. */
i = 0
for {
if !(i < nSubSrc) {
break
}
_recomputeColumnsUsed(tls, pParent, pSrc+8+uintptr(i+iFrom)*80)
goto _12
_12:
;
i = i + 1
}
goto _7
_7:
;
pParent = (*TSelect)(unsafe.Pointer(pParent)).FpPrior
pSub = (*TSelect)(unsafe.Pointer(pSub)).FpPrior
}
/* Finally, delete what is left of the subquery and return success.
*/
_sqlite3AggInfoPersistWalkerInit(tls, bp, pParse)
_sqlite3WalkSelect(tls, bp, pSub1)
_sqlite3SelectDelete(tls, db, pSub1)
return int32(1)
}
// C documentation
//
// /*
// ** Load the content from either the sqlite_stat4
// ** into the relevant Index.aSample[] arrays.
// **
// ** Arguments zSql1 and zSql2 must point to SQL statements that return
// ** data equivalent to the following:
// **
// ** zSql1: SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx
// ** zSql2: SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4
// **
// ** where %Q is replaced with the database name before the SQL is executed.
// */
func _loadStatTbl(tls *libc.TLS, db uintptr, zSql1 uintptr, zSql2 uintptr, zDb uintptr) (r int32) {
bp := tls.Alloc(32)
defer tls.Free(32)
var i, nByte Ti64
var nCol, nIdxCol, nSample, rc int32
var pIdx, pIdx1, pPrevIdx, pPtr, pSample, pSpace, zIndex, zIndex1, zSql uintptr
var _ /* pStmt at bp+0 */ uintptr
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = i, nByte, nCol, nIdxCol, nSample, pIdx, pIdx1, pPrevIdx, pPtr, pSample, pSpace, rc, zIndex, zIndex1, zSql /* Result codes from subroutines */
**(**uintptr)(__ccgo_up(bp)) = uintptr(0) /* Text of the SQL statement */
pPrevIdx = uintptr(0) /* A slot in pIdx->aSample[] */
zSql = _sqlite3MPrintf(tls, db, zSql1, libc.VaList(bp+16, zDb))
if !(zSql != 0) {
return int32(SQLITE_NOMEM)
}
rc = Xsqlite3_prepare(tls, db, zSql, -int32(1), bp, uintptr(0))
_sqlite3DbFree(tls, db, zSql)
if rc != 0 {
return rc
}
for Xsqlite3_step(tls, **(**uintptr)(__ccgo_up(bp))) == int32(SQLITE_ROW) {
nIdxCol = int32(1) /* Available memory as a u8 for easier manipulation */
zIndex = Xsqlite3_column_text(tls, **(**uintptr)(__ccgo_up(bp)), 0)
if zIndex == uintptr(0) {
continue
}
nSample = Xsqlite3_column_int(tls, **(**uintptr)(__ccgo_up(bp)), int32(1))
pIdx = _findIndexOrPrimaryKey(tls, db, zIndex, zDb)
if pIdx == uintptr(0) {
continue
}
if (*TIndex)(unsafe.Pointer(pIdx)).FaSample != uintptr(0) {
/* The same index appears in sqlite_stat4 under multiple names */
continue
}
if !((*TTable)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pIdx)).FpTable)).FtabFlags&libc.Uint32FromInt32(TF_WithoutRowid) == libc.Uint32FromInt32(0)) && int32(uint32(*(*uint16)(unsafe.Pointer(pIdx + 100))&0x3>>0)) == int32(SQLITE_IDXTYPE_PRIMARYKEY) {
nIdxCol = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol)
} else {
nIdxCol = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn)
}
(*TIndex)(unsafe.Pointer(pIdx)).FnSampleCol = nIdxCol
(*TIndex)(unsafe.Pointer(pIdx)).FmxSample = nSample
nByte = (libc.Int64FromInt64(40)*int64(nSample) + libc.Int64FromInt32(7)) & int64(^libc.Int32FromInt32(7))
nByte = nByte + libc.Int64FromInt64(8)*int64(nIdxCol)*int64(3)*int64(nSample)
nByte = nByte + int64(nIdxCol)*libc.Int64FromInt64(8) /* Space for Index.aAvgEq[] */
(*TIndex)(unsafe.Pointer(pIdx)).FaSample = _sqlite3DbMallocZero(tls, db, libc.Uint64FromInt64(nByte))
if (*TIndex)(unsafe.Pointer(pIdx)).FaSample == uintptr(0) {
Xsqlite3_finalize(tls, **(**uintptr)(__ccgo_up(bp)))
return int32(SQLITE_NOMEM)
}
pPtr = (*TIndex)(unsafe.Pointer(pIdx)).FaSample
pPtr = pPtr + uintptr((int64(nSample)*libc.Int64FromInt64(40)+libc.Int64FromInt32(7))&int64(^libc.Int32FromInt32(7)))
pSpace = pPtr
(*TIndex)(unsafe.Pointer(pIdx)).FaAvgEq = pSpace
pSpace = pSpace + uintptr(nIdxCol)*8
**(**Tu32)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FpTable + 48)) |= uint32(TF_HasStat4)
i = 0
for {
if !(i < int64(nSample)) {
break
}
(**(**TIndexSample)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaSample + uintptr(i)*40))).FanEq = pSpace
pSpace = pSpace + uintptr(nIdxCol)*8
(**(**TIndexSample)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaSample + uintptr(i)*40))).FanLt = pSpace
pSpace = pSpace + uintptr(nIdxCol)*8
(**(**TIndexSample)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaSample + uintptr(i)*40))).FanDLt = pSpace
pSpace = pSpace + uintptr(nIdxCol)*8
goto _1
_1:
;
i = i + 1
}
}
rc = Xsqlite3_finalize(tls, **(**uintptr)(__ccgo_up(bp)))
if rc != 0 {
return rc
}
zSql = _sqlite3MPrintf(tls, db, zSql2, libc.VaList(bp+16, zDb))
if !(zSql != 0) {
return int32(SQLITE_NOMEM)
}
rc = Xsqlite3_prepare(tls, db, zSql, -int32(1), bp, uintptr(0))
_sqlite3DbFree(tls, db, zSql)
if rc != 0 {
return rc
}
for Xsqlite3_step(tls, **(**uintptr)(__ccgo_up(bp))) == int32(SQLITE_ROW) { /* Pointer to the index object */
nCol = int32(1) /* Number of columns in index */
zIndex1 = Xsqlite3_column_text(tls, **(**uintptr)(__ccgo_up(bp)), 0)
if zIndex1 == uintptr(0) {
continue
}
pIdx1 = _findIndexOrPrimaryKey(tls, db, zIndex1, zDb)
if pIdx1 == uintptr(0) {
continue
}
if (*TIndex)(unsafe.Pointer(pIdx1)).FnSample >= (*TIndex)(unsafe.Pointer(pIdx1)).FmxSample {
/* Too many slots used because the same index appears in
** sqlite_stat4 using multiple names */
continue
}
/* This next condition is true if data has already been loaded from
** the sqlite_stat4 table. */
nCol = (*TIndex)(unsafe.Pointer(pIdx1)).FnSampleCol
if pIdx1 != pPrevIdx {
_initAvgEq(tls, pPrevIdx)
pPrevIdx = pIdx1
}
pSample = (*TIndex)(unsafe.Pointer(pIdx1)).FaSample + uintptr((*TIndex)(unsafe.Pointer(pIdx1)).FnSample)*40
_decodeIntArray(tls, Xsqlite3_column_text(tls, **(**uintptr)(__ccgo_up(bp)), int32(1)), nCol, (*TIndexSample)(unsafe.Pointer(pSample)).FanEq, uintptr(0), uintptr(0))
_decodeIntArray(tls, Xsqlite3_column_text(tls, **(**uintptr)(__ccgo_up(bp)), int32(2)), nCol, (*TIndexSample)(unsafe.Pointer(pSample)).FanLt, uintptr(0), uintptr(0))
_decodeIntArray(tls, Xsqlite3_column_text(tls, **(**uintptr)(__ccgo_up(bp)), int32(3)), nCol, (*TIndexSample)(unsafe.Pointer(pSample)).FanDLt, uintptr(0), uintptr(0))
/* Take a copy of the sample. Add 8 extra 0x00 bytes the end of the buffer.
** This is in case the sample record is corrupted. In that case, the
** sqlite3VdbeRecordCompare() may read up to two varints past the
** end of the allocated buffer before it realizes it is dealing with
** a corrupt record. Or it might try to read a large integer from the
** buffer. In any case, eight 0x00 bytes prevents this from causing
** a buffer overread. */
(*TIndexSample)(unsafe.Pointer(pSample)).Fn = Xsqlite3_column_bytes(tls, **(**uintptr)(__ccgo_up(bp)), int32(4))
(*TIndexSample)(unsafe.Pointer(pSample)).Fp = _sqlite3DbMallocZero(tls, db, libc.Uint64FromInt32((*TIndexSample)(unsafe.Pointer(pSample)).Fn+int32(8)))
if (*TIndexSample)(unsafe.Pointer(pSample)).Fp == uintptr(0) {
Xsqlite3_finalize(tls, **(**uintptr)(__ccgo_up(bp)))
return int32(SQLITE_NOMEM)
}
if (*TIndexSample)(unsafe.Pointer(pSample)).Fn != 0 {
libc.Xmemcpy(tls, (*TIndexSample)(unsafe.Pointer(pSample)).Fp, Xsqlite3_column_blob(tls, **(**uintptr)(__ccgo_up(bp)), int32(4)), libc.Uint64FromInt32((*TIndexSample)(unsafe.Pointer(pSample)).Fn))
}
(*TIndex)(unsafe.Pointer(pIdx1)).FnSample = (*TIndex)(unsafe.Pointer(pIdx1)).FnSample + 1
}
rc = Xsqlite3_finalize(tls, **(**uintptr)(__ccgo_up(bp)))
if rc == SQLITE_OK {
_initAvgEq(tls, pPrevIdx)
}
return rc
}
// C documentation
//
// /*
// ** Resize an Index object to hold N columns total. Return SQLITE_OK
// ** on success and SQLITE_NOMEM on an OOM error.
// */
func _resizeIndexObject(tls *libc.TLS, pParse uintptr, pIdx uintptr, N int32) (r int32) {
var db, zExtra uintptr
var nByte Tu64
_, _, _ = db, nByte, zExtra
if libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn) >= N {
return SQLITE_OK
}
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
nByte = uint64(libc.Uint64FromInt64(8)+libc.Uint64FromInt64(2)+libc.Uint64FromInt64(2)+libc.Uint64FromInt32(1)) * libc.Uint64FromInt32(N)
zExtra = _sqlite3DbMallocZero(tls, db, nByte)
if zExtra == uintptr(0) {
return int32(SQLITE_NOMEM)
}
libc.Xmemcpy(tls, zExtra, (*TIndex)(unsafe.Pointer(pIdx)).FazColl, uint64(8)*uint64((*TIndex)(unsafe.Pointer(pIdx)).FnColumn))
(*TIndex)(unsafe.Pointer(pIdx)).FazColl = zExtra
zExtra = zExtra + uintptr(uint64(8)*libc.Uint64FromInt32(N))
libc.Xmemcpy(tls, zExtra, (*TIndex)(unsafe.Pointer(pIdx)).FaiRowLogEst, uint64(2)*libc.Uint64FromInt32(libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol)+libc.Int32FromInt32(1)))
(*TIndex)(unsafe.Pointer(pIdx)).FaiRowLogEst = zExtra
zExtra = zExtra + uintptr(uint64(2)*libc.Uint64FromInt32(N))
libc.Xmemcpy(tls, zExtra, (*TIndex)(unsafe.Pointer(pIdx)).FaiColumn, uint64(2)*uint64((*TIndex)(unsafe.Pointer(pIdx)).FnColumn))
(*TIndex)(unsafe.Pointer(pIdx)).FaiColumn = zExtra
zExtra = zExtra + uintptr(uint64(2)*libc.Uint64FromInt32(N))
libc.Xmemcpy(tls, zExtra, (*TIndex)(unsafe.Pointer(pIdx)).FaSortOrder, uint64((*TIndex)(unsafe.Pointer(pIdx)).FnColumn))
(*TIndex)(unsafe.Pointer(pIdx)).FaSortOrder = zExtra
(*TIndex)(unsafe.Pointer(pIdx)).FnColumn = libc.Uint16FromInt32(N) /* See tag-20250221-1 above for proof of safety */
libc.SetBitFieldPtr16Uint32(pIdx+100, libc.Uint32FromInt32(1), 4, 0x10)
return SQLITE_OK
}
// C documentation
//
// /* Move the cursor so that it points to an entry in an index table
// ** near the key pIdxKey. Return a success code.
// **
// ** If an exact match is not found, then the cursor is always
// ** left pointing at a leaf page which would hold the entry if it
// ** were present. The cursor might point to an entry that comes
// ** before or after the key.
// **
// ** An integer is written into *pRes which is the result of
// ** comparing the key with the entry to which the cursor is
// ** pointing. The meaning of the integer written into
// ** *pRes is as follows:
// **
// ** *pRes<0 The cursor is left pointing at an entry that
// ** is smaller than pIdxKey or if the table is empty
// ** and the cursor is therefore left point to nothing.
// **
// ** *pRes==0 The cursor is left pointing at an entry that
// ** exactly matches pIdxKey.
// **
// ** *pRes>0 The cursor is left pointing at an entry that
// ** is larger than pIdxKey.
// **
// ** The pIdxKey->eqSeen field is set to 1 if there
// ** exists an entry in the table that exactly matches pIdxKey.
// */
func _sqlite3BtreeIndexMoveto(tls *libc.TLS, pCur uintptr, pIdxKey uintptr, pRes uintptr) (r int32) {
var c, c1, idx, lwr, nCell, nOverrun, rc, upr, v1 int32
var chldPg TPgno
var pCell, pCellBody, pCellKey, pPage, v3 uintptr
var xRecordCompare TRecordCompare
var v10 Ti8
var v2 bool
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = c, c1, chldPg, idx, lwr, nCell, nOverrun, pCell, pCellBody, pCellKey, pPage, rc, upr, xRecordCompare, v1, v10, v2, v3
xRecordCompare = _sqlite3VdbeFindCompare(tls, pIdxKey)
(*TUnpackedRecord)(unsafe.Pointer(pIdxKey)).FerrCode = uint8(0)
/* Check to see if we can skip a lot of work. Two cases:
**
** (1) If the cursor is already pointing to the very last cell
** in the table and the pIdxKey search key is greater than or
** equal to that last cell, then no movement is required.
**
** (2) If the cursor is on the last page of the table and the first
** cell on that last page is less than or equal to the pIdxKey
** search key, then we can start the search on the current page
** without needing to go back to root.
*/
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) == CURSOR_VALID && (*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).Fleaf != 0 && _cursorOnLastPage(tls, pCur) != 0 {
if v2 = libc.Int32FromUint16((*TBtCursor)(unsafe.Pointer(pCur)).Fix) == libc.Int32FromUint16((*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).FnCell)-int32(1); v2 {
v1 = _indexCellCompare(tls, (*TBtCursor)(unsafe.Pointer(pCur)).FpPage, libc.Int32FromUint16((*TBtCursor)(unsafe.Pointer(pCur)).Fix), pIdxKey, xRecordCompare)
c = v1
}
if v2 && v1 <= 0 && libc.Int32FromUint8((*TUnpackedRecord)(unsafe.Pointer(pIdxKey)).FerrCode) == SQLITE_OK {
**(**int32)(__ccgo_up(pRes)) = c
return SQLITE_OK /* Cursor already pointing at the correct spot */
}
if int32((*TBtCursor)(unsafe.Pointer(pCur)).FiPage) > 0 && _indexCellCompare(tls, (*TBtCursor)(unsafe.Pointer(pCur)).FpPage, 0, pIdxKey, xRecordCompare) <= 0 && libc.Int32FromUint8((*TUnpackedRecord)(unsafe.Pointer(pIdxKey)).FerrCode) == SQLITE_OK {
v3 = pCur + 1
*(*Tu8)(unsafe.Pointer(v3)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v3))) & ^(libc.Int32FromInt32(BTCF_ValidOvfl) | libc.Int32FromInt32(BTCF_AtLast)))
if !((*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).FisInit != 0) {
return _sqlite3CorruptError(tls, int32(79465))
}
goto bypass_moveto_root /* Start search on the current page */
}
(*TUnpackedRecord)(unsafe.Pointer(pIdxKey)).FerrCode = uint8(SQLITE_OK)
}
rc = _moveToRoot(tls, pCur)
if rc != 0 {
if rc == int32(SQLITE_EMPTY) {
**(**int32)(__ccgo_up(pRes)) = -int32(1)
return SQLITE_OK
}
return rc
}
goto bypass_moveto_root
bypass_moveto_root:
;
for {
pPage = (*TBtCursor)(unsafe.Pointer(pCur)).FpPage /* Pointer to current cell in pPage */
/* 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. */
lwr = 0
upr = libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell) - int32(1)
idx = upr >> int32(1) /* idx = (lwr+upr)/2; */
for { /* Size of the pCell cell in bytes */
pCell = (*TMemPage)(unsafe.Pointer(pPage)).FaDataOfst + uintptr(libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FmaskPage)&(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(pPage)).FaCellIdx + uintptr(int32(2)*idx))))<<libc.Int32FromInt32(8)|libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(pPage)).FaCellIdx + uintptr(int32(2)*idx) + 1)))))
/* 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.
*/
nCell = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pCell)))
if nCell <= libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pPage)).Fmax1bytePayload) {
/* 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. */
if pCell+uintptr(nCell) >= (*TMemPage)(unsafe.Pointer(pPage)).FaDataEnd {
rc = _sqlite3CorruptError(tls, int32(79524))
goto moveto_index_finish
}
c1 = (*(*func(*libc.TLS, int32, uintptr, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{xRecordCompare})))(tls, nCell, pCell+1, pIdxKey)
} else {
if v2 = !(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pCell + 1)))&libc.Int32FromInt32(0x80) != 0); v2 {
v1 = nCell&libc.Int32FromInt32(0x7f)<<libc.Int32FromInt32(7) + libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pCell + 1)))
nCell = v1
}
if v2 && v1 <= libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FmaxLocal) && pCell+uintptr(nCell) < (*TMemPage)(unsafe.Pointer(pPage)).FaDataEnd {
/* The record-size field is a 2 byte varint and the record
** fits entirely on the main b-tree page. */
c1 = (*(*func(*libc.TLS, int32, uintptr, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{xRecordCompare})))(tls, nCell, pCell+2, pIdxKey)
} else {
pCellBody = pCell - uintptr((*TMemPage)(unsafe.Pointer(pPage)).FchildPtrSize)
nOverrun = int32(18) /* Size of the overrun padding */
(*(*func(*libc.TLS, uintptr, uintptr, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TMemPage)(unsafe.Pointer(pPage)).FxParseCell})))(tls, pPage, pCellBody, pCur+48)
nCell = int32((*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnKey)
/* True if key size is 2^32 or more */
/* Invalid key size: 0x80 0x80 0x00 */
/* Invalid key size: 0x80 0x80 0x01 */
/* Minimum legal index key size */
if nCell < int32(2) || libc.Uint32FromInt32(nCell)/(*TBtShared)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpBt)).FusableSize > (*TBtShared)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpBt)).FnPage {
rc = _sqlite3CorruptError(tls, int32(79555))
goto moveto_index_finish
}
pCellKey = _sqlite3Malloc(tls, libc.Uint64FromInt32(nCell)+libc.Uint64FromInt32(nOverrun))
if pCellKey == uintptr(0) {
rc = int32(SQLITE_NOMEM)
goto moveto_index_finish
}
(*TBtCursor)(unsafe.Pointer(pCur)).Fix = libc.Uint16FromInt32(idx)
rc = _accessPayload(tls, pCur, uint32(0), libc.Uint32FromInt32(nCell), pCellKey, 0)
libc.Xmemset(tls, pCellKey+uintptr(nCell), 0, libc.Uint64FromInt32(nOverrun)) /* Fix uninit warnings */
v3 = pCur + 1
*(*Tu8)(unsafe.Pointer(v3)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v3))) & ^libc.Int32FromInt32(BTCF_ValidOvfl))
if rc != 0 {
Xsqlite3_free(tls, pCellKey)
goto moveto_index_finish
}
c1 = _sqlite3VdbeRecordCompare(tls, nCell, pCellKey, pIdxKey)
Xsqlite3_free(tls, pCellKey)
}
}
if c1 < 0 {
lwr = idx + int32(1)
} else {
if c1 > 0 {
upr = idx - int32(1)
} else {
**(**int32)(__ccgo_up(pRes)) = 0
rc = SQLITE_OK
(*TBtCursor)(unsafe.Pointer(pCur)).Fix = libc.Uint16FromInt32(idx)
if (*TUnpackedRecord)(unsafe.Pointer(pIdxKey)).FerrCode != 0 {
rc = _sqlite3CorruptError(tls, int32(79587))
}
goto moveto_index_finish
}
}
if lwr > upr {
break
}
idx = (lwr + upr) >> int32(1) /* idx = (lwr+upr)/2 */
goto _5
_5:
}
if (*TMemPage)(unsafe.Pointer(pPage)).Fleaf != 0 {
(*TBtCursor)(unsafe.Pointer(pCur)).Fix = libc.Uint16FromInt32(idx)
**(**int32)(__ccgo_up(pRes)) = c1
rc = SQLITE_OK
goto moveto_index_finish
}
if lwr >= libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell) {
chldPg = _sqlite3Get4byte(tls, (*TMemPage)(unsafe.Pointer(pPage)).FaData+uintptr(libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pPage)).FhdrOffset)+int32(8)))
} else {
chldPg = _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)*lwr))))<<libc.Int32FromInt32(8)|libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(pPage)).FaCellIdx + uintptr(int32(2)*lwr) + 1))))))
}
/* This block is similar to an in-lined version of:
**
** pCur->ix = (u16)lwr;
** rc = moveToChild(pCur, chldPg);
** if( rc ) break;
*/
(*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnSize = uint16(0)
v3 = pCur + 1
*(*Tu8)(unsafe.Pointer(v3)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v3))) & ^(libc.Int32FromInt32(BTCF_ValidNKey) | libc.Int32FromInt32(BTCF_ValidOvfl)))
if int32((*TBtCursor)(unsafe.Pointer(pCur)).FiPage) >= libc.Int32FromInt32(BTCURSOR_MAX_DEPTH)-libc.Int32FromInt32(1) {
return _sqlite3CorruptError(tls, int32(79618))
}
**(**Tu16)(__ccgo_up(pCur + 88 + uintptr((*TBtCursor)(unsafe.Pointer(pCur)).FiPage)*2)) = libc.Uint16FromInt32(lwr)
**(**uintptr)(__ccgo_up(pCur + 144 + uintptr((*TBtCursor)(unsafe.Pointer(pCur)).FiPage)*8)) = (*TBtCursor)(unsafe.Pointer(pCur)).FpPage
(*TBtCursor)(unsafe.Pointer(pCur)).Fix = uint16(0)
(*TBtCursor)(unsafe.Pointer(pCur)).FiPage = (*TBtCursor)(unsafe.Pointer(pCur)).FiPage + 1
rc = _getAndInitPage(tls, (*TBtCursor)(unsafe.Pointer(pCur)).FpBt, chldPg, pCur+136, libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FcurPagerFlags))
if rc == SQLITE_OK && (libc.Int32FromUint16((*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).FnCell) < int32(1) || libc.Int32FromUint8((*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).FintKey) != libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FcurIntKey)) {
_releasePage(tls, (*TBtCursor)(unsafe.Pointer(pCur)).FpPage)
rc = _sqlite3CorruptError(tls, int32(79629))
}
if rc != 0 {
v3 = pCur + 84
*(*Ti8)(unsafe.Pointer(v3)) = *(*Ti8)(unsafe.Pointer(v3)) - 1
v10 = *(*Ti8)(unsafe.Pointer(v3))
(*TBtCursor)(unsafe.Pointer(pCur)).FpPage = **(**uintptr)(__ccgo_up(pCur + 144 + uintptr(v10)*8))
break
}
/*
***** End of in-lined moveToChild() call */
goto _4
_4:
}
goto moveto_index_finish
moveto_index_finish:
;
(*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnSize = uint16(0)
return rc
}
// C documentation
//
// /*
// ** Insert a new record into the BTree. The content of the new record
// ** is described by the pX object. The pCur cursor is used only to
// ** define what table the record should be inserted into, and is left
// ** pointing at a random location.
// **
// ** For a table btree (used for rowid tables), only the pX.nKey value of
// ** the key is used. The pX.pKey value must be NULL. The pX.nKey is the
// ** rowid or INTEGER PRIMARY KEY of the row. The pX.nData,pData,nZero fields
// ** hold the content of the row.
// **
// ** For an index btree (used for indexes and WITHOUT ROWID tables), the
// ** key is an arbitrary byte sequence stored in pX.pKey,nKey. The
// ** pX.pData,nData,nZero fields must be zero.
// **
// ** If the seekResult parameter is non-zero, then a successful call to
// ** sqlite3BtreeIndexMoveto() to seek cursor pCur to (pKey,nKey) has already
// ** been performed. In other words, if seekResult!=0 then the cursor
// ** is currently pointing to a cell that will be adjacent to the cell
// ** to be inserted. If seekResult<0 then pCur points to a cell that is
// ** smaller then (pKey,nKey). If seekResult>0 then pCur points to a cell
// ** that is larger than (pKey,nKey).
// **
// ** If seekResult==0, that means pCur is pointing at some unknown location.
// ** In that case, this routine must seek the cursor to the correct insertion
// ** point for (pKey,nKey) before doing the insertion. For index btrees,
// ** if pX->nMem is non-zero, then pX->aMem contains pointers to the unpacked
// ** key values and pX->aMem can be used instead of pX->pKey to avoid having
// ** to decode the key.
// */
func _sqlite3BtreeInsert(tls *libc.TLS, pCur uintptr, pX uintptr, flags int32, seekResult int32) (r int32) {
bp := tls.Alloc(160)
defer tls.Free(160)
var idx int32
var newCell, oldCell, p, pPage, v1 uintptr
var ovfl TPgno
var v2 Tu16
var _ /* info at bp+104 */ TCellInfo
var _ /* info at bp+128 */ TCellInfo
var _ /* loc at bp+4 */ int32
var _ /* r at bp+16 */ TUnpackedRecord
var _ /* rc at bp+0 */ int32
var _ /* szNew at bp+8 */ int32
var _ /* x2 at bp+56 */ TBtreePayload
_, _, _, _, _, _, _, _ = idx, newCell, oldCell, ovfl, p, pPage, v1, v2
**(**int32)(__ccgo_up(bp + 4)) = seekResult /* -1: before desired location +1: after */
**(**int32)(__ccgo_up(bp + 8)) = 0
p = (*TBtCursor)(unsafe.Pointer(pCur)).FpBtree
newCell = uintptr(0)
/* Save the positions of any other cursors open on this table.
**
** In some cases, the call to btreeMoveto() below is a no-op. For
** example, when inserting data into a table with auto-generated integer
** keys, the VDBE layer invokes sqlite3BtreeLast() to figure out the
** integer key to use. It then calls this function to actually insert the
** data into the intkey B-Tree. In this case btreeMoveto() recognizes
** that the cursor is already where it needs to be and returns without
** doing any work. To avoid thwarting these optimizations, it is important
** not to clear the cursor here.
*/
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FcurFlags)&int32(BTCF_Multiple) != 0 {
**(**int32)(__ccgo_up(bp)) = _saveAllCursors(tls, (*TBtree)(unsafe.Pointer(p)).FpBt, (*TBtCursor)(unsafe.Pointer(pCur)).FpgnoRoot, pCur)
if **(**int32)(__ccgo_up(bp)) != 0 {
return **(**int32)(__ccgo_up(bp))
}
if **(**int32)(__ccgo_up(bp + 4)) != 0 && int32((*TBtCursor)(unsafe.Pointer(pCur)).FiPage) < 0 {
/* This can only happen if the schema is corrupt such that there is more
** than one table or index with the same root page as used by the cursor.
** Which can only happen if the SQLITE_NoSchemaError flag was set when
** the schema was loaded. This cannot be asserted though, as a user might
** set the flag, load the schema, and then unset the flag. */
return _sqlite3CorruptError(tls, int32(82822))
}
}
/* Ensure that the cursor is not in the CURSOR_FAULT state and that it
** points to a valid cell.
*/
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) >= int32(CURSOR_REQUIRESEEK) {
**(**int32)(__ccgo_up(bp)) = _moveToRoot(tls, pCur)
if **(**int32)(__ccgo_up(bp)) != 0 && **(**int32)(__ccgo_up(bp)) != int32(SQLITE_EMPTY) {
return **(**int32)(__ccgo_up(bp))
}
}
/* Assert that the caller has been consistent. If this cursor was opened
** expecting an index b-tree, then the caller should be inserting blob
** keys with no associated data. If the cursor was opened expecting an
** intkey table, the caller should be inserting integer keys with a
** blob of associated data. */
if (*TBtCursor)(unsafe.Pointer(pCur)).FpKeyInfo == uintptr(0) {
/* If this is an insert into a table b-tree, invalidate any incrblob
** cursors open on the row being replaced */
if (*TBtree)(unsafe.Pointer(p)).FhasIncrblobCur != 0 {
_invalidateIncrblobCursors(tls, p, (*TBtCursor)(unsafe.Pointer(pCur)).FpgnoRoot, (*TBtreePayload)(unsafe.Pointer(pX)).FnKey, 0)
}
/* If BTREE_SAVEPOSITION is set, the cursor must already be pointing
** to a row with the same key as the new entry being inserted.
*/
/* On the other hand, BTREE_SAVEPOSITION==0 does not imply
** that the cursor is not pointing to a row to be overwritten.
** So do a complete check.
*/
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FcurFlags)&int32(BTCF_ValidNKey) != 0 && (*TBtreePayload)(unsafe.Pointer(pX)).FnKey == (*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnKey {
/* The cursor is pointing to the entry that is to be
** overwritten */
if libc.Int32FromUint16((*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnSize) != 0 && (*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnPayload == libc.Uint32FromInt32((*TBtreePayload)(unsafe.Pointer(pX)).FnData)+libc.Uint32FromInt32((*TBtreePayload)(unsafe.Pointer(pX)).FnZero) {
/* New entry is the same size as the old. Do an overwrite */
return _btreeOverwriteCell(tls, pCur, pX)
}
} else {
if **(**int32)(__ccgo_up(bp + 4)) == 0 {
/* The cursor is *not* pointing to the cell to be overwritten, nor
** to an adjacent cell. Move the cursor so that it is pointing either
** to the cell to be overwritten or an adjacent cell.
*/
**(**int32)(__ccgo_up(bp)) = _sqlite3BtreeTableMoveto(tls, pCur, (*TBtreePayload)(unsafe.Pointer(pX)).FnKey, libc.BoolInt32(flags&int32(BTREE_APPEND) != 0), bp+4)
if **(**int32)(__ccgo_up(bp)) != 0 {
return **(**int32)(__ccgo_up(bp))
}
}
}
} else {
/* This is an index or a WITHOUT ROWID table */
/* If BTREE_SAVEPOSITION is set, the cursor must already be pointing
** to a row with the same key as the new entry being inserted.
*/
/* If the cursor is not already pointing either to the cell to be
** overwritten, or if a new cell is being inserted, if the cursor is
** not pointing to an immediately adjacent cell, then move the cursor
** so that it does.
*/
if **(**int32)(__ccgo_up(bp + 4)) == 0 && flags&int32(BTREE_SAVEPOSITION) == 0 {
if (*TBtreePayload)(unsafe.Pointer(pX)).FnMem != 0 {
(**(**TUnpackedRecord)(__ccgo_up(bp + 16))).FpKeyInfo = (*TBtCursor)(unsafe.Pointer(pCur)).FpKeyInfo
(**(**TUnpackedRecord)(__ccgo_up(bp + 16))).FaMem = (*TBtreePayload)(unsafe.Pointer(pX)).FaMem
(**(**TUnpackedRecord)(__ccgo_up(bp + 16))).FnField = (*TBtreePayload)(unsafe.Pointer(pX)).FnMem
(**(**TUnpackedRecord)(__ccgo_up(bp + 16))).Fdefault_rc = 0
(**(**TUnpackedRecord)(__ccgo_up(bp + 16))).FeqSeen = uint8(0)
**(**int32)(__ccgo_up(bp)) = _sqlite3BtreeIndexMoveto(tls, pCur, bp+16, bp+4)
} else {
**(**int32)(__ccgo_up(bp)) = _btreeMoveto(tls, pCur, (*TBtreePayload)(unsafe.Pointer(pX)).FpKey, (*TBtreePayload)(unsafe.Pointer(pX)).FnKey, libc.BoolInt32(flags&int32(BTREE_APPEND) != 0), bp+4)
}
if **(**int32)(__ccgo_up(bp)) != 0 {
return **(**int32)(__ccgo_up(bp))
}
}
/* If the cursor is currently pointing to an entry to be overwritten
** and the new content is the same as as the old, then use the
** overwrite optimization.
*/
if **(**int32)(__ccgo_up(bp + 4)) == 0 {
_getCellInfo(tls, pCur)
if (*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnKey == (*TBtreePayload)(unsafe.Pointer(pX)).FnKey {
(**(**TBtreePayload)(__ccgo_up(bp + 56))).FpData = (*TBtreePayload)(unsafe.Pointer(pX)).FpKey
(**(**TBtreePayload)(__ccgo_up(bp + 56))).FnData = int32((*TBtreePayload)(unsafe.Pointer(pX)).FnKey)
(**(**TBtreePayload)(__ccgo_up(bp + 56))).FnZero = 0
return _btreeOverwriteCell(tls, pCur, bp+56)
}
}
}
pPage = (*TBtCursor)(unsafe.Pointer(pCur)).FpPage
if (*TMemPage)(unsafe.Pointer(pPage)).FnFree < 0 {
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) > int32(CURSOR_INVALID) {
/* ^^^^^--- due to the moveToRoot() call above */
**(**int32)(__ccgo_up(bp)) = _sqlite3CorruptError(tls, int32(82945))
} else {
**(**int32)(__ccgo_up(bp)) = _btreeComputeFreeSpace(tls, pPage)
}
if **(**int32)(__ccgo_up(bp)) != 0 {
return **(**int32)(__ccgo_up(bp))
}
}
newCell = (*TBtShared)(unsafe.Pointer((*TBtree)(unsafe.Pointer(p)).FpBt)).FpTmpSpace
if flags&int32(BTREE_PREFORMAT) != 0 {
**(**int32)(__ccgo_up(bp)) = SQLITE_OK
**(**int32)(__ccgo_up(bp + 8)) = (*TBtShared)(unsafe.Pointer((*TBtree)(unsafe.Pointer(p)).FpBt)).FnPreformatSize
if **(**int32)(__ccgo_up(bp + 8)) < int32(4) {
**(**int32)(__ccgo_up(bp + 8)) = int32(4)
**(**uint8)(__ccgo_up(newCell + 3)) = uint8(0)
}
if (*TBtShared)(unsafe.Pointer((*TBtree)(unsafe.Pointer(p)).FpBt)).FautoVacuum != 0 && **(**int32)(__ccgo_up(bp + 8)) > libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FmaxLocal) {
(*(*func(*libc.TLS, uintptr, uintptr, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TMemPage)(unsafe.Pointer(pPage)).FxParseCell})))(tls, pPage, newCell, bp+104)
if (**(**TCellInfo)(__ccgo_up(bp + 104))).FnPayload != uint32((**(**TCellInfo)(__ccgo_up(bp + 104))).FnLocal) {
ovfl = _sqlite3Get4byte(tls, newCell+uintptr(**(**int32)(__ccgo_up(bp + 8))-int32(4)))
_ptrmapPut(tls, (*TBtree)(unsafe.Pointer(p)).FpBt, ovfl, uint8(PTRMAP_OVERFLOW1), (*TMemPage)(unsafe.Pointer(pPage)).Fpgno, bp)
if **(**int32)(__ccgo_up(bp)) != 0 {
goto end_insert
}
}
}
} else {
**(**int32)(__ccgo_up(bp)) = _fillInCell(tls, pPage, newCell, pX, bp+8)
if **(**int32)(__ccgo_up(bp)) != 0 {
goto end_insert
}
}
idx = libc.Int32FromUint16((*TBtCursor)(unsafe.Pointer(pCur)).Fix)
(*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnSize = uint16(0)
if **(**int32)(__ccgo_up(bp + 4)) == 0 {
if idx >= libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell) {
return _sqlite3CorruptError(tls, int32(82987))
}
**(**int32)(__ccgo_up(bp)) = _sqlite3PagerWrite(tls, (*TMemPage)(unsafe.Pointer(pPage)).FpDbPage)
if **(**int32)(__ccgo_up(bp)) != 0 {
goto end_insert
}
oldCell = (*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)*idx))))<<libc.Int32FromInt32(8)|libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TMemPage)(unsafe.Pointer(pPage)).FaCellIdx + uintptr(int32(2)*idx) + 1)))))
if !((*TMemPage)(unsafe.Pointer(pPage)).Fleaf != 0) {
libc.Xmemcpy(tls, newCell, oldCell, uint64(4))
}
(*(*func(*libc.TLS, uintptr, uintptr, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TMemPage)(unsafe.Pointer(pPage)).FxParseCell})))(tls, pPage, oldCell, bp+128)
if uint32((**(**TCellInfo)(__ccgo_up(bp + 128))).FnLocal) != (**(**TCellInfo)(__ccgo_up(bp + 128))).FnPayload {
**(**int32)(__ccgo_up(bp)) = _clearCellOverflow(tls, pPage, oldCell, bp+128)
} else {
**(**int32)(__ccgo_up(bp)) = SQLITE_OK
}
v1 = pCur + 1
*(*Tu8)(unsafe.Pointer(v1)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v1))) & ^libc.Int32FromInt32(BTCF_ValidOvfl))
if libc.Int32FromUint16((**(**TCellInfo)(__ccgo_up(bp + 128))).FnSize) == **(**int32)(__ccgo_up(bp + 8)) && uint32((**(**TCellInfo)(__ccgo_up(bp + 128))).FnLocal) == (**(**TCellInfo)(__ccgo_up(bp + 128))).FnPayload && (!((*TBtShared)(unsafe.Pointer((*TBtree)(unsafe.Pointer(p)).FpBt)).FautoVacuum != 0) || **(**int32)(__ccgo_up(bp + 8)) < libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FminLocal)) {
/* Overwrite the old cell with the new if they are the same size.
** We could also try to do this if the old cell is smaller, then add
** the leftover space to the free list. But experiments show that
** doing that is no faster then skipping this optimization and just
** calling dropCell() and insertCell().
**
** This optimization cannot be used on an autovacuum database if the
** new entry uses overflow pages, as the insertCell() call below is
** necessary to add the PTRMAP_OVERFLOW1 pointer-map entry. */
/* clearCell never fails when nLocal==nPayload */
if oldCell < (*TMemPage)(unsafe.Pointer(pPage)).FaData+uintptr((*TMemPage)(unsafe.Pointer(pPage)).FhdrOffset)+uintptr(10) {
return _sqlite3CorruptError(tls, int32(83014))
}
if oldCell+uintptr(**(**int32)(__ccgo_up(bp + 8))) > (*TMemPage)(unsafe.Pointer(pPage)).FaDataEnd {
return _sqlite3CorruptError(tls, int32(83017))
}
libc.Xmemcpy(tls, oldCell, newCell, libc.Uint64FromInt32(**(**int32)(__ccgo_up(bp + 8))))
return SQLITE_OK
}
_dropCell(tls, pPage, idx, libc.Int32FromUint16((**(**TCellInfo)(__ccgo_up(bp + 128))).FnSize), bp)
if **(**int32)(__ccgo_up(bp)) != 0 {
goto end_insert
}
} else {
if **(**int32)(__ccgo_up(bp + 4)) < 0 && libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell) > 0 {
v1 = pCur + 86
*(*Tu16)(unsafe.Pointer(v1)) = *(*Tu16)(unsafe.Pointer(v1)) + 1
v2 = *(*Tu16)(unsafe.Pointer(v1))
idx = libc.Int32FromUint16(v2)
v1 = pCur + 1
*(*Tu8)(unsafe.Pointer(v1)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v1))) & ^(libc.Int32FromInt32(BTCF_ValidNKey) | libc.Int32FromInt32(BTCF_ValidOvfl)))
} else {
}
}
**(**int32)(__ccgo_up(bp)) = _insertCellFast(tls, pPage, idx, newCell, **(**int32)(__ccgo_up(bp + 8)))
/* If no error has occurred and pPage has an overflow cell, call balance()
** to redistribute the cells within the tree. Since balance() may move
** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey
** variables.
**
** Previous versions of SQLite called moveToRoot() to move the cursor
** back to the root page as balance() used to invalidate the contents
** of BtCursor.apPage[] and BtCursor.aiIdx[]. Instead of doing that,
** set the cursor state to "invalid". This makes common insert operations
** slightly faster.
**
** There is a subtle but important optimization here too. When inserting
** multiple records into an intkey b-tree using a single cursor (as can
** happen while processing an "INSERT INTO ... SELECT" statement), it
** is advantageous to leave the cursor pointing to the last entry in
** the b-tree if possible. If the cursor is left pointing to the last
** entry in the table, and the next row inserted has an integer key
** larger than the largest existing key, it is possible to insert the
** row without seeking the cursor. This can be a big performance boost.
*/
if (*TMemPage)(unsafe.Pointer(pPage)).FnOverflow != 0 {
v1 = pCur + 1
*(*Tu8)(unsafe.Pointer(v1)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v1))) & ^(libc.Int32FromInt32(BTCF_ValidNKey) | libc.Int32FromInt32(BTCF_ValidOvfl)))
**(**int32)(__ccgo_up(bp)) = _balance(tls, pCur)
/* Must make sure nOverflow is reset to zero even if the balance()
** fails. Internal data structure corruption will result otherwise.
** Also, set the cursor state to invalid. This stops saveCursorPosition()
** from trying to save the current position of the cursor. */
(*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).FnOverflow = uint8(0)
(*TBtCursor)(unsafe.Pointer(pCur)).FeState = uint8(CURSOR_INVALID)
if flags&int32(BTREE_SAVEPOSITION) != 0 && **(**int32)(__ccgo_up(bp)) == SQLITE_OK {
_btreeReleaseAllCursorPages(tls, pCur)
if (*TBtCursor)(unsafe.Pointer(pCur)).FpKeyInfo != 0 {
(*TBtCursor)(unsafe.Pointer(pCur)).FpKey = _sqlite3Malloc(tls, libc.Uint64FromInt64((*TBtreePayload)(unsafe.Pointer(pX)).FnKey))
if (*TBtCursor)(unsafe.Pointer(pCur)).FpKey == uintptr(0) {
**(**int32)(__ccgo_up(bp)) = int32(SQLITE_NOMEM)
} else {
libc.Xmemcpy(tls, (*TBtCursor)(unsafe.Pointer(pCur)).FpKey, (*TBtreePayload)(unsafe.Pointer(pX)).FpKey, libc.Uint64FromInt64((*TBtreePayload)(unsafe.Pointer(pX)).FnKey))
}
}
(*TBtCursor)(unsafe.Pointer(pCur)).FeState = uint8(CURSOR_REQUIRESEEK)
(*TBtCursor)(unsafe.Pointer(pCur)).FnKey = (*TBtreePayload)(unsafe.Pointer(pX)).FnKey
}
}
goto end_insert
end_insert:
;
return **(**int32)(__ccgo_up(bp))
return r
}
// C documentation
//
// /*
// ** Make arrangements to invoke OP_Null on a range of registers
// ** during initialization.
// */
func _sqlite3ExprNullRegisterRange(tls *libc.TLS, pParse uintptr, iReg int32, nReg int32) {
bp := tls.Alloc(80)
defer tls.Free(80)
var okConstFactor Tu8
var _ /* t at bp+0 */ TExpr
_ = okConstFactor
okConstFactor = libc.Uint8FromInt32(int32(Tbft(*(*uint16)(unsafe.Pointer(pParse + 40)) & 0x80 >> 7)))
libc.Xmemset(tls, bp, 0, uint64(72))
(**(**TExpr)(__ccgo_up(bp))).Fop = uint8(TK_NULLS)
*(*int32)(unsafe.Pointer(bp + 64)) = nReg
libc.SetBitFieldPtr16Uint32(pParse+40, libc.Uint32FromInt32(1), 7, 0x80)
_sqlite3ExprCodeRunJustOnce(tls, pParse, bp, iReg)
libc.SetBitFieldPtr16Uint32(pParse+40, uint32(okConstFactor), 7, 0x80)
}
// C documentation
//
// /*
// ** Check all ON clauses in pSelect to verify that they do not reference
// ** columns to the right.
// */
func _sqlite3SelectCheckOnClauses(tls *libc.TLS, pParse uintptr, pSelect uintptr) {
bp := tls.Alloc(80)
defer tls.Free(80)
var ii int32
var pItem uintptr
var _ /* sCtx at bp+48 */ TCheckOnCtx
var _ /* w at bp+0 */ TWalker
_, _ = ii, pItem
libc.Xmemset(tls, bp, 0, uint64(48))
(**(**TWalker)(__ccgo_up(bp))).FpParse = pParse
(**(**TWalker)(__ccgo_up(bp))).FxExprCallback = __ccgo_fp(_selectCheckOnClausesExpr)
(**(**TWalker)(__ccgo_up(bp))).FxSelectCallback = __ccgo_fp(_selectCheckOnClausesSelect)
*(*uintptr)(unsafe.Pointer(bp + 40)) = bp + 48
libc.Xmemset(tls, bp+48, 0, uint64(24))
(**(**TCheckOnCtx)(__ccgo_up(bp + 48))).FpSrc = (*TSelect)(unsafe.Pointer(pSelect)).FpSrc
_sqlite3WalkExpr(tls, bp, (*TSelect)(unsafe.Pointer(pSelect)).FpWhere)
**(**Tu32)(__ccgo_up(pSelect + 4)) &= libc.Uint32FromInt32(^libc.Int32FromInt32(SF_OnToWhere))
/* Check for any table-function args that are attached to virtual tables
** on the RHS of an outer join. They are subject to the same constraints
** as ON clauses. */
(**(**TCheckOnCtx)(__ccgo_up(bp + 48))).FbFuncArg = int32(1)
ii = 0
for {
if !(ii < (*TSrcList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pSelect)).FpSrc)).FnSrc) {
break
}
pItem = (*TSelect)(unsafe.Pointer(pSelect)).FpSrc + 8 + uintptr(ii)*80
if int32(*(*uint32)(unsafe.Pointer(pItem + 24 + 4))&0x8>>3) != 0 && libc.Int32FromUint8((*TSrcItem)(unsafe.Pointer(pItem)).Ffg.Fjointype)&int32(JT_OUTER) != 0 {
(**(**TCheckOnCtx)(__ccgo_up(bp + 48))).FiJoin = (*TSrcItem)(unsafe.Pointer(pItem)).FiCursor
_sqlite3WalkExprList(tls, bp, *(*uintptr)(unsafe.Pointer(pItem + 48)))
}
goto _1
_1:
;
ii = ii + 1
}
}
// C documentation
//
// /*
// ** If cursors, triggers, views and subqueries are all omitted from
// ** the build, then none of the following routines, except for
// ** sqlite3SelectDup(), can be called. sqlite3SelectDup() is sometimes
// ** called with a NULL argument.
// */
func _sqlite3SrcListDup(tls *libc.TLS, db uintptr, p uintptr, flags int32) (r uintptr) {
var i int32
var pNew, pNewItem, pNewSubq, pOldItem, pTab, v3 uintptr
var v1 Tu32
_, _, _, _, _, _, _, _ = i, pNew, pNewItem, pNewSubq, pOldItem, pTab, v1, v3
if p == uintptr(0) {
return uintptr(0)
}
pNew = _sqlite3DbMallocRawNN(tls, db, uint64(uint64(libc.UintptrFromInt32(0)+8)+libc.Uint64FromInt32((*TSrcList)(unsafe.Pointer(p)).FnSrc)*libc.Uint64FromInt64(80)))
if pNew == uintptr(0) {
return uintptr(0)
}
v1 = libc.Uint32FromInt32((*TSrcList)(unsafe.Pointer(p)).FnSrc)
(*TSrcList)(unsafe.Pointer(pNew)).FnAlloc = v1
(*TSrcList)(unsafe.Pointer(pNew)).FnSrc = libc.Int32FromUint32(v1)
i = 0
for {
if !(i < (*TSrcList)(unsafe.Pointer(p)).FnSrc) {
break
}
pNewItem = pNew + 8 + uintptr(i)*80
pOldItem = p + 8 + uintptr(i)*80
(*TSrcItem)(unsafe.Pointer(pNewItem)).Ffg = (*TSrcItem)(unsafe.Pointer(pOldItem)).Ffg
if int32(*(*uint32)(unsafe.Pointer(pOldItem + 24 + 4))&0x4>>2) != 0 {
pNewSubq = _sqlite3DbMallocRaw(tls, db, uint64(24))
if pNewSubq == uintptr(0) {
libc.SetBitFieldPtr32Uint32(pNewItem+24+4, libc.Uint32FromInt32(0), 2, 0x4)
} else {
libc.Xmemcpy(tls, pNewSubq, *(*uintptr)(unsafe.Pointer(pOldItem + 72)), uint64(24))
(*TSubquery)(unsafe.Pointer(pNewSubq)).FpSelect = _sqlite3SelectDup(tls, db, (*TSubquery)(unsafe.Pointer(pNewSubq)).FpSelect, flags)
if (*TSubquery)(unsafe.Pointer(pNewSubq)).FpSelect == uintptr(0) {
_sqlite3DbFree(tls, db, pNewSubq)
pNewSubq = uintptr(0)
libc.SetBitFieldPtr32Uint32(pNewItem+24+4, libc.Uint32FromInt32(0), 2, 0x4)
}
}
*(*uintptr)(unsafe.Pointer(pNewItem + 72)) = pNewSubq
} else {
if int32(*(*uint32)(unsafe.Pointer(pOldItem + 24 + 4))&0x10000>>16) != 0 {
*(*uintptr)(unsafe.Pointer(pNewItem + 72)) = *(*uintptr)(unsafe.Pointer(pOldItem + 72))
} else {
*(*uintptr)(unsafe.Pointer(pNewItem + 72)) = _sqlite3DbStrDup(tls, db, *(*uintptr)(unsafe.Pointer(pOldItem + 72)))
}
}
(*TSrcItem)(unsafe.Pointer(pNewItem)).FzName = _sqlite3DbStrDup(tls, db, (*TSrcItem)(unsafe.Pointer(pOldItem)).FzName)
(*TSrcItem)(unsafe.Pointer(pNewItem)).FzAlias = _sqlite3DbStrDup(tls, db, (*TSrcItem)(unsafe.Pointer(pOldItem)).FzAlias)
(*TSrcItem)(unsafe.Pointer(pNewItem)).FiCursor = (*TSrcItem)(unsafe.Pointer(pOldItem)).FiCursor
if int32(*(*uint32)(unsafe.Pointer(pNewItem + 24 + 4))&0x2>>1) != 0 {
*(*uintptr)(unsafe.Pointer(pNewItem + 48)) = _sqlite3DbStrDup(tls, db, *(*uintptr)(unsafe.Pointer(pOldItem + 48)))
} else {
if int32(*(*uint32)(unsafe.Pointer(pNewItem + 24 + 4))&0x8>>3) != 0 {
*(*uintptr)(unsafe.Pointer(pNewItem + 48)) = _sqlite3ExprListDup(tls, db, *(*uintptr)(unsafe.Pointer(pOldItem + 48)), flags)
} else {
*(*Tu32)(unsafe.Pointer(&(*TSrcItem)(unsafe.Pointer(pNewItem)).Fu1)) = *(*Tu32)(unsafe.Pointer(&(*TSrcItem)(unsafe.Pointer(pOldItem)).Fu1))
}
}
(*TSrcItem)(unsafe.Pointer(pNewItem)).Fu2 = (*TSrcItem)(unsafe.Pointer(pOldItem)).Fu2
if int32(*(*uint32)(unsafe.Pointer(pNewItem + 24 + 4))&0x200>>9) != 0 {
(*TCteUse)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pNewItem + 56)))).FnUse = (*TCteUse)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pNewItem + 56)))).FnUse + 1
}
v3 = (*TSrcItem)(unsafe.Pointer(pOldItem)).FpSTab
(*TSrcItem)(unsafe.Pointer(pNewItem)).FpSTab = v3
pTab = v3
if pTab != 0 {
(*TTable)(unsafe.Pointer(pTab)).FnTabRef = (*TTable)(unsafe.Pointer(pTab)).FnTabRef + 1
}
if int32(*(*uint32)(unsafe.Pointer(pOldItem + 24 + 4))&0x800>>11) != 0 {
*(*uintptr)(unsafe.Pointer(pNewItem + 64)) = _sqlite3IdListDup(tls, db, *(*uintptr)(unsafe.Pointer(pOldItem + 64)))
} else {
*(*uintptr)(unsafe.Pointer(pNewItem + 64)) = _sqlite3ExprDup(tls, db, *(*uintptr)(unsafe.Pointer(pOldItem + 64)), flags)
}
(*TSrcItem)(unsafe.Pointer(pNewItem)).FcolUsed = (*TSrcItem)(unsafe.Pointer(pOldItem)).FcolUsed
goto _2
_2:
;
i = i + 1
}
return pNew
}
// C documentation
//
// /*
// ** Prepare a virtual machine for execution for the first time after
// ** creating the virtual machine. This involves things such
// ** as allocating registers and initializing the program counter.
// ** After the VDBE has be prepped, it can be executed by one or more
// ** calls to sqlite3VdbeExec().
// **
// ** This function may be called exactly once on each virtual machine.
// ** After this routine is called the VM has been "packaged" and is ready
// ** to run. After this routine is called, further calls to
// ** sqlite3VdbeAddOp() functions are prohibited. This routine disconnects
// ** the Vdbe from the Parse object that helped generate it so that the
// ** the Vdbe becomes an independent entity and the Parse object can be
// ** destroyed.
// **
// ** Use the sqlite3VdbeRewind() procedure to restore a virtual machine back
// ** to its initial state after it has been run.
// */
func _sqlite3VdbeMakeReady(tls *libc.TLS, p uintptr, pParse uintptr) {
bp := tls.Alloc(32)
defer tls.Free(32)
var db, v1 uintptr
var n, nCursor, nMem, nVar int32
var _ /* nArg at bp+0 */ int32
var _ /* x at bp+8 */ TReusableSpace
_, _, _, _, _, _ = db, n, nCursor, nMem, nVar, v1 /* Reusable bulk memory */
(*TVdbe)(unsafe.Pointer(p)).FpVList = (*TParse)(unsafe.Pointer(pParse)).FpVList
(*TParse)(unsafe.Pointer(pParse)).FpVList = uintptr(0)
db = (*TVdbe)(unsafe.Pointer(p)).Fdb
nVar = int32((*TParse)(unsafe.Pointer(pParse)).FnVar)
nMem = (*TParse)(unsafe.Pointer(pParse)).FnMem
nCursor = (*TParse)(unsafe.Pointer(pParse)).FnTab
**(**int32)(__ccgo_up(bp)) = (*TParse)(unsafe.Pointer(pParse)).FnMaxArg
/* Each cursor uses a memory cell. The first cursor (cursor 0) can
** use aMem[0] which is not otherwise used by the VDBE program. Allocate
** space at the end of aMem[] for cursors 1 and greater.
** See also: allocateCursor().
*/
nMem = nMem + nCursor
if nCursor == 0 && nMem > 0 {
nMem = nMem + 1
} /* Space for aMem[0] even if not used */
/* Figure out how much reusable memory is available at the end of the
** opcode array. This extra memory will be reallocated for other elements
** of the prepared statement.
*/
n = libc.Int32FromUint64(libc.Uint64FromInt64(24) * libc.Uint64FromInt32((*TVdbe)(unsafe.Pointer(p)).FnOp)) /* Bytes of opcode memory used */
(**(**TReusableSpace)(__ccgo_up(bp + 8))).FpSpace = (*TVdbe)(unsafe.Pointer(p)).FaOp + uintptr(n) /* Unused opcode memory */
(**(**TReusableSpace)(__ccgo_up(bp + 8))).FnFree = int64(((*TParse)(unsafe.Pointer(pParse)).FszOpAlloc - n) & ^libc.Int32FromInt32(7)) /* Bytes of unused memory */
_resolveP2Values(tls, p, bp)
libc.SetBitFieldPtr16Uint32(p+200, uint32(libc.BoolUint8((*TParse)(unsafe.Pointer(pParse)).FisMultiWrite != 0 && int32(Tbft(*(*uint16)(unsafe.Pointer(pParse + 40))&0x2>>1)) != 0)), 5, 0x20)
if (*TParse)(unsafe.Pointer(pParse)).Fexplain != 0 {
if nMem < int32(10) {
nMem = int32(10)
}
libc.SetBitFieldPtr16Uint32(p+200, uint32((*TParse)(unsafe.Pointer(pParse)).Fexplain), 2, 0xc)
(*TVdbe)(unsafe.Pointer(p)).FnResColumn = libc.Uint16FromInt32(int32(12) - int32(4)*int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0xc>>2)))
}
libc.SetBitFieldPtr16Uint32(p+200, libc.Uint32FromInt32(0), 0, 0x3)
/* Memory for registers, parameters, cursor, etc, is allocated in one or two
** passes. On the first pass, we try to reuse unused memory at the
** end of the opcode array. If we are unable to satisfy all memory
** requirements by reusing the opcode array tail, then the second
** pass will fill in the remainder using a fresh memory allocation.
**
** This two-pass approach that reuses as much memory as possible from
** the leftover memory at the end of the opcode array. This can significantly
** reduce the amount of memory held by a prepared statement.
*/
(**(**TReusableSpace)(__ccgo_up(bp + 8))).FnNeeded = 0
(*TVdbe)(unsafe.Pointer(p)).FaMem = _allocSpace(tls, bp+8, uintptr(0), libc.Int64FromUint64(libc.Uint64FromInt32(nMem)*uint64(56)))
(*TVdbe)(unsafe.Pointer(p)).FaVar = _allocSpace(tls, bp+8, uintptr(0), libc.Int64FromUint64(libc.Uint64FromInt32(nVar)*uint64(56)))
(*TVdbe)(unsafe.Pointer(p)).FapArg = _allocSpace(tls, bp+8, uintptr(0), libc.Int64FromUint64(libc.Uint64FromInt32(**(**int32)(__ccgo_up(bp)))*uint64(8)))
(*TVdbe)(unsafe.Pointer(p)).FapCsr = _allocSpace(tls, bp+8, uintptr(0), libc.Int64FromUint64(libc.Uint64FromInt32(nCursor)*uint64(8)))
if (**(**TReusableSpace)(__ccgo_up(bp + 8))).FnNeeded != 0 {
v1 = _sqlite3DbMallocRawNN(tls, db, libc.Uint64FromInt64((**(**TReusableSpace)(__ccgo_up(bp + 8))).FnNeeded))
(*TVdbe)(unsafe.Pointer(p)).FpFree = v1
(**(**TReusableSpace)(__ccgo_up(bp + 8))).FpSpace = v1
(**(**TReusableSpace)(__ccgo_up(bp + 8))).FnFree = (**(**TReusableSpace)(__ccgo_up(bp + 8))).FnNeeded
if !((*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0) {
(*TVdbe)(unsafe.Pointer(p)).FaMem = _allocSpace(tls, bp+8, (*TVdbe)(unsafe.Pointer(p)).FaMem, libc.Int64FromUint64(libc.Uint64FromInt32(nMem)*uint64(56)))
(*TVdbe)(unsafe.Pointer(p)).FaVar = _allocSpace(tls, bp+8, (*TVdbe)(unsafe.Pointer(p)).FaVar, libc.Int64FromUint64(libc.Uint64FromInt32(nVar)*uint64(56)))
(*TVdbe)(unsafe.Pointer(p)).FapArg = _allocSpace(tls, bp+8, (*TVdbe)(unsafe.Pointer(p)).FapArg, libc.Int64FromUint64(libc.Uint64FromInt32(**(**int32)(__ccgo_up(bp)))*uint64(8)))
(*TVdbe)(unsafe.Pointer(p)).FapCsr = _allocSpace(tls, bp+8, (*TVdbe)(unsafe.Pointer(p)).FapCsr, libc.Int64FromUint64(libc.Uint64FromInt32(nCursor)*uint64(8)))
}
}
if (*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0 {
(*TVdbe)(unsafe.Pointer(p)).FnVar = 0
(*TVdbe)(unsafe.Pointer(p)).FnCursor = 0
(*TVdbe)(unsafe.Pointer(p)).FnMem = 0
} else {
(*TVdbe)(unsafe.Pointer(p)).FnCursor = nCursor
(*TVdbe)(unsafe.Pointer(p)).FnVar = int16(nVar)
_initMemArray(tls, (*TVdbe)(unsafe.Pointer(p)).FaVar, nVar, db, uint16(MEM_Null))
(*TVdbe)(unsafe.Pointer(p)).FnMem = nMem
_initMemArray(tls, (*TVdbe)(unsafe.Pointer(p)).FaMem, nMem, db, uint16(MEM_Undefined))
libc.Xmemset(tls, (*TVdbe)(unsafe.Pointer(p)).FapCsr, 0, libc.Uint64FromInt32(nCursor)*uint64(8))
}
_sqlite3VdbeRewind(tls, p)
}
// C documentation
//
// /*
// ** This function encodes a single frame header and writes it to a buffer
// ** supplied by the caller. A frame-header is made up of a series of
// ** 4-byte big-endian integers, as follows:
// **
// ** 0: Page number.
// ** 4: For commit records, the size of the database image in pages
// ** after the commit. For all other records, zero.
// ** 8: Salt-1 (copied from the wal-header)
// ** 12: Salt-2 (copied from the wal-header)
// ** 16: Checksum-1.
// ** 20: Checksum-2.
// */
func _walEncodeFrame(tls *libc.TLS, pWal uintptr, iPage Tu32, nTruncate Tu32, aData uintptr, aFrame uintptr) {
var aCksum uintptr
var nativeCksum int32
_, _ = aCksum, nativeCksum /* True for native byte-order checksums */
aCksum = pWal + 72 + 24
_sqlite3Put4byte(tls, aFrame, iPage)
_sqlite3Put4byte(tls, aFrame+4, nTruncate)
if (*TWal)(unsafe.Pointer(pWal)).FiReCksum == uint32(0) {
libc.Xmemcpy(tls, aFrame+8, pWal+72+32, uint64(8))
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)
_sqlite3Put4byte(tls, aFrame+16, **(**Tu32)(__ccgo_up(aCksum)))
_sqlite3Put4byte(tls, aFrame+20, **(**Tu32)(__ccgo_up(aCksum + 1*4)))
} else {
libc.Xmemset(tls, aFrame+8, 0, uint64(16))
}
}
// C documentation
//
// /*
// ** pIdx is an index that covers all of the low-number columns used by
// ** pWInfo->pSelect (columns from 0 through 62) or an index that has
// ** expressions terms. Hence, we cannot determine whether or not it is
// ** a covering index by using the colUsed bitmasks. We have to do a search
// ** to see if the index is covering. This routine does that search.
// **
// ** The return value is one of these:
// **
// ** 0 The index is definitely not a covering index
// **
// ** WHERE_IDX_ONLY The index is definitely a covering index
// **
// ** WHERE_EXPRIDX The index is likely a covering index, but it is
// ** difficult to determine precisely because of the
// ** expressions that are indexed. Score it as a
// ** covering index, but still keep the main table open
// ** just in case we need it.
// **
// ** This routine is an optimization. It is always safe to return zero.
// ** But returning one of the other two values when zero should have been
// ** returned can lead to incorrect bytecode and assertion faults.
// */
func _whereIsCoveringIndex(tls *libc.TLS, pWInfo uintptr, pIdx uintptr, iTabCur int32) (r Tu32) {
bp := tls.Alloc(64)
defer tls.Free(64)
var i, rc int32
var _ /* ck at bp+0 */ TCoveringIndexCheck
var _ /* w at bp+16 */ TWalker
_, _ = i, rc
if (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpSelect == uintptr(0) {
/* We don't have access to the full query, so we cannot check to see
** if pIdx is covering. Assume it is not. */
return uint32(0)
}
if int32(uint32(*(*uint16)(unsafe.Pointer(pIdx + 100))&0x800>>11)) == 0 {
i = 0
for {
if !(i < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn)) {
break
}
if int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(i)*2))) >= libc.Int32FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(8))-libc.Int32FromInt32(1) {
break
}
goto _1
_1:
;
i = i + 1
}
if i >= libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn) {
/* pIdx does not index any columns greater than 62, but we know from
** colMask that columns greater than 62 are used, so this is not a
** covering index */
return uint32(0)
}
}
(**(**TCoveringIndexCheck)(__ccgo_up(bp))).FpIdx = pIdx
(**(**TCoveringIndexCheck)(__ccgo_up(bp))).FiTabCur = iTabCur
(**(**TCoveringIndexCheck)(__ccgo_up(bp))).FbExpr = uint8(0)
(**(**TCoveringIndexCheck)(__ccgo_up(bp))).FbUnidx = uint8(0)
libc.Xmemset(tls, bp+16, 0, uint64(48))
(**(**TWalker)(__ccgo_up(bp + 16))).FxExprCallback = __ccgo_fp(_whereIsCoveringIndexWalkCallback)
(**(**TWalker)(__ccgo_up(bp + 16))).FxSelectCallback = __ccgo_fp(_sqlite3SelectWalkNoop)
*(*uintptr)(unsafe.Pointer(bp + 16 + 40)) = bp
_sqlite3WalkSelect(tls, bp+16, (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpSelect)
if (**(**TCoveringIndexCheck)(__ccgo_up(bp))).FbUnidx != 0 {
rc = 0
} else {
if (**(**TCoveringIndexCheck)(__ccgo_up(bp))).FbExpr != 0 {
rc = int32(WHERE_EXPRIDX)
} else {
rc = int32(WHERE_IDX_ONLY)
}
}
return libc.Uint32FromInt32(rc)
}
// C documentation
//
// /*
// ** Add all WhereLoop objects for a single table of the join where the table
// ** is identified by pBuilder->pNew->iTab. That table is guaranteed to be
// ** a b-tree table, not a virtual table.
// **
// ** The costs (WhereLoop.rRun) of the b-tree loops added by this function
// ** are calculated as follows:
// **
// ** For a full scan, assuming the table (or index) contains nRow rows:
// **
// ** cost = nRow * 3.0 // full-table scan
// ** cost = nRow * K // scan of covering index
// ** cost = nRow * (K+3.0) // scan of non-covering index
// **
// ** where K is a value between 1.1 and 3.0 set based on the relative
// ** estimated average size of the index and table records.
// **
// ** For an index scan, where nVisit is the number of index rows visited
// ** by the scan, and nSeek is the number of seek operations required on
// ** the index b-tree:
// **
// ** cost = nSeek * (log(nRow) + K * nVisit) // covering index
// ** cost = nSeek * (log(nRow) + (K+3.0) * nVisit) // non-covering index
// **
// ** Normally, nSeek is 1. nSeek values greater than 1 come about if the
// ** WHERE clause includes "x IN (....)" terms used in place of "x=?". Or when
// ** implicit "x IN (SELECT x FROM tbl)" terms are added for skip-scans.
// **
// ** The estimated values (nRow, nVisit, nSeek) often contain a large amount
// ** of uncertainty. For this reason, scoring is designed to pick plans that
// ** "do the least harm" if the estimates are inaccurate. For example, a
// ** log(nRow) factor is omitted from a non-covering index scan in order to
// ** bias the scoring in favor of using an index, since the worst-case
// ** performance of using an index is far better than the worst-case performance
// ** of a full table scan.
// */
func _whereLoopAddBtree(tls *libc.TLS, pBuilder uintptr, mPrereq TBitmask) (r int32) {
bp := tls.Alloc(176)
defer tls.Free(176)
var b, iCur, iSortIdx, ii, rc, v5 int32
var isCov Tu32
var nLookup, rLogSize, rSize TLogEst
var pFirst, pNew, pProbe, pSrc, pTab, pTabList, pTerm, pTerm1, pWC, pWC2, pWCEnd, pWInfo, v2 uintptr
var _ /* aiColumnPk at bp+164 */ Ti16
var _ /* aiRowEstPk at bp+160 */ [2]TLogEst
var _ /* m at bp+168 */ TBitmask
var _ /* sPk at bp+0 */ TIndex
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = b, iCur, iSortIdx, ii, isCov, nLookup, pFirst, pNew, pProbe, pSrc, pTab, pTabList, pTerm, pTerm1, pWC, pWC2, pWCEnd, pWInfo, rLogSize, rSize, rc, v2, v5 /* The aiRowLogEst[] value for the sPk index */
**(**Ti16)(__ccgo_up(bp + 164)) = int16(-int32(1)) /* Template WhereLoop object */
rc = SQLITE_OK /* Return code */
iSortIdx = int32(1) /* Table being queried */
pNew = (*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FpNew
pWInfo = (*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FpWInfo
pTabList = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpTabList
pSrc = pTabList + 8 + uintptr((*TWhereLoop)(unsafe.Pointer(pNew)).FiTab)*80
pTab = (*TSrcItem)(unsafe.Pointer(pSrc)).FpSTab
pWC = (*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FpWC
if int32(*(*uint32)(unsafe.Pointer(pSrc + 24 + 4))&0x2>>1) != 0 {
/* An INDEXED BY clause specifies a particular index to use */
pProbe = *(*uintptr)(unsafe.Pointer(pSrc + 56))
} else {
if !((*TTable)(unsafe.Pointer(pTab)).FtabFlags&libc.Uint32FromInt32(TF_WithoutRowid) == libc.Uint32FromInt32(0)) {
pProbe = (*TTable)(unsafe.Pointer(pTab)).FpIndex
} else { /* First of real indices on the table */
libc.Xmemset(tls, bp, 0, uint64(160))
(**(**TIndex)(__ccgo_up(bp))).FnKeyCol = uint16(1)
(**(**TIndex)(__ccgo_up(bp))).FnColumn = uint16(1)
(**(**TIndex)(__ccgo_up(bp))).FaiColumn = bp + 164
(**(**TIndex)(__ccgo_up(bp))).FaiRowLogEst = bp + 160
(**(**TIndex)(__ccgo_up(bp))).FonError = uint8(OE_Replace)
(**(**TIndex)(__ccgo_up(bp))).FpTable = pTab
(**(**TIndex)(__ccgo_up(bp))).FszIdxRow = int16(3) /* TUNING: Interior rows of IPK table are very small */
libc.SetBitFieldPtr16Uint32(bp+100, libc.Uint32FromInt32(SQLITE_IDXTYPE_IPK), 0, 0x3)
(**(**[2]TLogEst)(__ccgo_up(bp + 160)))[0] = (*TTable)(unsafe.Pointer(pTab)).FnRowLogEst
(**(**[2]TLogEst)(__ccgo_up(bp + 160)))[int32(1)] = 0
pFirst = (*TTable)(unsafe.Pointer((*TSrcItem)(unsafe.Pointer(pSrc)).FpSTab)).FpIndex
if int32(*(*uint32)(unsafe.Pointer(pSrc + 24 + 4))&0x1>>0) == 0 {
/* The real indices of the table are only considered if the
** NOT INDEXED qualifier is omitted from the FROM clause */
(**(**TIndex)(__ccgo_up(bp))).FpNext = pFirst
}
pProbe = bp
}
}
rSize = (*TTable)(unsafe.Pointer(pTab)).FnRowLogEst
/* Automatic indexes */
if !((*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FpOrSet != 0) && libc.Int32FromUint16((*TWhereInfo)(unsafe.Pointer(pWInfo)).FwctrlFlags)&(libc.Int32FromInt32(WHERE_RIGHT_JOIN)|libc.Int32FromInt32(WHERE_OR_SUBCLAUSE)) == 0 && (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer((*TWhereInfo)(unsafe.Pointer(pWInfo)).FpParse)).Fdb)).Fflags&uint64(SQLITE_AutoIndex) != uint64(0) && !(int32(*(*uint32)(unsafe.Pointer(pSrc + 24 + 4))&0x2>>1) != 0) && !(int32(*(*uint32)(unsafe.Pointer(pSrc + 24 + 4))&0x1>>0) != 0) && !(int32(*(*uint32)(unsafe.Pointer(pSrc + 24 + 4))&0x10>>4) != 0) && !(int32(*(*uint32)(unsafe.Pointer(pSrc + 24 + 4))&0x80>>7) != 0) && libc.Int32FromUint8((*TSrcItem)(unsafe.Pointer(pSrc)).Ffg.Fjointype)&int32(JT_RIGHT) == 0 {
pWCEnd = (*TWhereClause)(unsafe.Pointer(pWC)).Fa + uintptr((*TWhereClause)(unsafe.Pointer(pWC)).FnTerm)*56
rLogSize = _estLog(tls, rSize)
pTerm = (*TWhereClause)(unsafe.Pointer(pWC)).Fa
for {
if !(rc == SQLITE_OK && pTerm < pWCEnd) {
break
}
if (*TWhereTerm)(unsafe.Pointer(pTerm)).FprereqRight&(*TWhereLoop)(unsafe.Pointer(pNew)).FmaskSelf != 0 {
goto _1
}
if _termCanDriveIndex(tls, pTerm, pSrc, uint64(0)) != 0 {
(*(*struct {
FnEq Tu16
FnBtm Tu16
FnTop Tu16
FnDistinctCol Tu16
FpIndex uintptr
FpOrderBy uintptr
})(unsafe.Pointer(pNew + 24))).FnEq = uint16(1)
(*TWhereLoop)(unsafe.Pointer(pNew)).FnSkip = uint16(0)
(*(*struct {
FnEq Tu16
FnBtm Tu16
FnTop Tu16
FnDistinctCol Tu16
FpIndex uintptr
FpOrderBy uintptr
})(unsafe.Pointer(pNew + 24))).FpIndex = uintptr(0)
(*TWhereLoop)(unsafe.Pointer(pNew)).FnLTerm = uint16(1)
**(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pNew)).FaLTerm)) = pTerm
/* TUNING: One-time cost for computing the automatic index is
** estimated to be X*N*log2(N) where N is the number of rows in
** the table being indexed and where X is 7 (LogEst=28) for normal
** tables or 0.5 (LogEst=-10) for views and subqueries. The value
** of X is smaller for views and subqueries so that the query planner
** will be more aggressive about generating automatic indexes for
** those objects, since there is no opportunity to add schema
** indexes on subqueries and views. */
(*TWhereLoop)(unsafe.Pointer(pNew)).FrSetup = int16(int32(rLogSize) + int32(rSize))
if !(libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == libc.Int32FromInt32(TABTYP_VIEW)) && (*TTable)(unsafe.Pointer(pTab)).FtabFlags&uint32(TF_Ephemeral) == uint32(0) {
v2 = pNew + 18
*(*TLogEst)(unsafe.Pointer(v2)) = TLogEst(int32(*(*TLogEst)(unsafe.Pointer(v2))) + libc.Int32FromInt32(28))
} else {
v2 = pNew + 18
*(*TLogEst)(unsafe.Pointer(v2)) = TLogEst(int32(*(*TLogEst)(unsafe.Pointer(v2))) - libc.Int32FromInt32(25)) /* Greatly reduced setup cost for auto indexes
** on ephemeral materializations of views */
}
if int32((*TWhereLoop)(unsafe.Pointer(pNew)).FrSetup) < 0 {
(*TWhereLoop)(unsafe.Pointer(pNew)).FrSetup = 0
}
/* TUNING: Each index lookup yields 20 rows in the table. This
** is more than the usual guess of 10 rows, since we have no way
** of knowing how selective the index will ultimately be. It would
** not be unreasonable to make this value much larger. */
(*TWhereLoop)(unsafe.Pointer(pNew)).FnOut = int16(43)
(*TWhereLoop)(unsafe.Pointer(pNew)).FrRun = _sqlite3LogEstAdd(tls, rLogSize, (*TWhereLoop)(unsafe.Pointer(pNew)).FnOut)
(*TWhereLoop)(unsafe.Pointer(pNew)).FwsFlags = uint32(WHERE_AUTO_INDEX)
(*TWhereLoop)(unsafe.Pointer(pNew)).Fprereq = mPrereq | (*TWhereTerm)(unsafe.Pointer(pTerm)).FprereqRight
rc = _whereLoopInsert(tls, pBuilder, pNew)
}
goto _1
_1:
;
pTerm += 56
}
}
/* Loop over all indices. If there was an INDEXED BY clause, then only
** consider index pProbe. */
for {
if !(rc == SQLITE_OK && pProbe != 0) {
break
}
if (*TIndex)(unsafe.Pointer(pProbe)).FpPartIdxWhere != uintptr(0) && !(_whereUsablePartialIndex(tls, (*TSrcItem)(unsafe.Pointer(pSrc)).FiCursor, (*TSrcItem)(unsafe.Pointer(pSrc)).Ffg.Fjointype, pWC, (*TIndex)(unsafe.Pointer(pProbe)).FpPartIdxWhere) != 0) {
/* See ticket [98d973b8f5] */
goto _4 /* Partial index inappropriate for this query */
}
if int32(uint32(*(*uint16)(unsafe.Pointer(pProbe + 100))&0x100>>8)) != 0 {
goto _4
}
rSize = **(**TLogEst)(__ccgo_up((*TIndex)(unsafe.Pointer(pProbe)).FaiRowLogEst))
(*(*struct {
FnEq Tu16
FnBtm Tu16
FnTop Tu16
FnDistinctCol Tu16
FpIndex uintptr
FpOrderBy uintptr
})(unsafe.Pointer(pNew + 24))).FnEq = uint16(0)
(*(*struct {
FnEq Tu16
FnBtm Tu16
FnTop Tu16
FnDistinctCol Tu16
FpIndex uintptr
FpOrderBy uintptr
})(unsafe.Pointer(pNew + 24))).FnBtm = uint16(0)
(*(*struct {
FnEq Tu16
FnBtm Tu16
FnTop Tu16
FnDistinctCol Tu16
FpIndex uintptr
FpOrderBy uintptr
})(unsafe.Pointer(pNew + 24))).FnTop = uint16(0)
(*(*struct {
FnEq Tu16
FnBtm Tu16
FnTop Tu16
FnDistinctCol Tu16
FpIndex uintptr
FpOrderBy uintptr
})(unsafe.Pointer(pNew + 24))).FnDistinctCol = uint16(0)
(*TWhereLoop)(unsafe.Pointer(pNew)).FnSkip = uint16(0)
(*TWhereLoop)(unsafe.Pointer(pNew)).FnLTerm = uint16(0)
(*TWhereLoop)(unsafe.Pointer(pNew)).FiSortIdx = uint8(0)
(*TWhereLoop)(unsafe.Pointer(pNew)).FrSetup = 0
(*TWhereLoop)(unsafe.Pointer(pNew)).Fprereq = mPrereq
(*TWhereLoop)(unsafe.Pointer(pNew)).FnOut = rSize
(*(*struct {
FnEq Tu16
FnBtm Tu16
FnTop Tu16
FnDistinctCol Tu16
FpIndex uintptr
FpOrderBy uintptr
})(unsafe.Pointer(pNew + 24))).FpIndex = pProbe
(*(*struct {
FnEq Tu16
FnBtm Tu16
FnTop Tu16
FnDistinctCol Tu16
FpIndex uintptr
FpOrderBy uintptr
})(unsafe.Pointer(pNew + 24))).FpOrderBy = uintptr(0)
b = _indexMightHelpWithOrderBy(tls, pBuilder, pProbe, (*TSrcItem)(unsafe.Pointer(pSrc)).FiCursor)
/* The ONEPASS_DESIRED flags never occurs together with ORDER BY */
if int32(uint32(*(*uint16)(unsafe.Pointer(pProbe + 100))&0x3>>0)) == int32(SQLITE_IDXTYPE_IPK) {
/* Integer primary key index */
(*TWhereLoop)(unsafe.Pointer(pNew)).FwsFlags = uint32(WHERE_IPK)
/* Full table scan */
if b != 0 {
v5 = iSortIdx
} else {
v5 = 0
}
(*TWhereLoop)(unsafe.Pointer(pNew)).FiSortIdx = libc.Uint8FromInt32(v5)
/* TUNING: Cost of full table scan is 3.0*N. The 3.0 factor is an
** extra cost designed to discourage the use of full table scans,
** since index lookups have better worst-case performance if our
** stat guesses are wrong. Reduce the 3.0 penalty slightly
** (to 2.75) if we have valid STAT4 information for the table.
** At 2.75, a full table scan is preferred over using an index on
** a column with just two distinct values where each value has about
** an equal number of appearances. Without STAT4 data, we still want
** to use an index in that case, since the constraint might be for
** the scarcer of the two values, and in that case an index lookup is
** better.
*/
(*TWhereLoop)(unsafe.Pointer(pNew)).FrRun = int16(int32(rSize) + int32(16) - int32(2)*libc.BoolInt32((*TTable)(unsafe.Pointer(pTab)).FtabFlags&uint32(TF_HasStat4) != uint32(0)))
_whereLoopOutputAdjust(tls, pWC, pNew, rSize)
if int32(*(*uint32)(unsafe.Pointer(pSrc + 24 + 4))&0x4>>2) != 0 {
if int32(*(*uint32)(unsafe.Pointer(pSrc + 24 + 4))&0x40>>6) != 0 {
**(**Tu32)(__ccgo_up(pNew + 48)) |= uint32(WHERE_COROUTINE)
}
/* Do not set btree.pOrderBy for a recursive CTE. In this case
** the ORDER BY clause does not determine the overall order that
** rows are emitted from the CTE in. */
if (*TSelect)(unsafe.Pointer((*TSubquery)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pSrc + 72)))).FpSelect)).FselFlags&uint32(SF_Recursive) == uint32(0) {
(*(*struct {
FnEq Tu16
FnBtm Tu16
FnTop Tu16
FnDistinctCol Tu16
FpIndex uintptr
FpOrderBy uintptr
})(unsafe.Pointer(pNew + 24))).FpOrderBy = (*TSelect)(unsafe.Pointer((*TSubquery)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pSrc + 72)))).FpSelect)).FpOrderBy
}
} else {
if int32(*(*uint32)(unsafe.Pointer(pSrc + 24 + 4))&0x40000>>18) != 0 {
(*TWhereLoop)(unsafe.Pointer(pNew)).FnOut = 0
}
}
rc = _whereLoopInsert(tls, pBuilder, pNew)
(*TWhereLoop)(unsafe.Pointer(pNew)).FnOut = rSize
if rc != 0 {
break
}
} else {
if int32(uint32(*(*uint16)(unsafe.Pointer(pProbe + 100))&0x20>>5)) != 0 {
**(**TBitmask)(__ccgo_up(bp + 168)) = uint64(0)
(*TWhereLoop)(unsafe.Pointer(pNew)).FwsFlags = libc.Uint32FromInt32(libc.Int32FromInt32(WHERE_IDX_ONLY) | libc.Int32FromInt32(WHERE_INDEXED))
} else {
**(**TBitmask)(__ccgo_up(bp + 168)) = (*TSrcItem)(unsafe.Pointer(pSrc)).FcolUsed & (*TIndex)(unsafe.Pointer(pProbe)).FcolNotIdxed
if (*TIndex)(unsafe.Pointer(pProbe)).FpPartIdxWhere != 0 {
_wherePartIdxExpr(tls, (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpParse, pProbe, (*TIndex)(unsafe.Pointer(pProbe)).FpPartIdxWhere, bp+168, 0, uintptr(0))
}
(*TWhereLoop)(unsafe.Pointer(pNew)).FwsFlags = uint32(WHERE_INDEXED)
if **(**TBitmask)(__ccgo_up(bp + 168)) == libc.Uint64FromInt32(1)<<(libc.Int32FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(8))-libc.Int32FromInt32(1)) || int32(uint32(*(*uint16)(unsafe.Pointer(pProbe + 100))&0x800>>11)) != 0 && !(int32(uint32(*(*uint16)(unsafe.Pointer(pProbe + 100))&0x400>>10)) != 0) && **(**TBitmask)(__ccgo_up(bp + 168)) != uint64(0) {
isCov = _whereIsCoveringIndex(tls, pWInfo, pProbe, (*TSrcItem)(unsafe.Pointer(pSrc)).FiCursor)
if isCov == uint32(0) {
} else {
**(**TBitmask)(__ccgo_up(bp + 168)) = uint64(0)
**(**Tu32)(__ccgo_up(pNew + 48)) |= isCov
if isCov&uint32(WHERE_IDX_ONLY) != 0 {
} else {
}
}
} else {
if **(**TBitmask)(__ccgo_up(bp + 168)) == uint64(0) && ((*TTable)(unsafe.Pointer(pTab)).FtabFlags&uint32(TF_WithoutRowid) == uint32(0) || (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpSelect != uintptr(0) || _sqlite3FaultSim(tls, int32(700)) != 0) {
(*TWhereLoop)(unsafe.Pointer(pNew)).FwsFlags = libc.Uint32FromInt32(libc.Int32FromInt32(WHERE_IDX_ONLY) | libc.Int32FromInt32(WHERE_INDEXED))
}
}
}
/* Full scan via index */
if b != 0 || !((*TTable)(unsafe.Pointer(pTab)).FtabFlags&libc.Uint32FromInt32(TF_WithoutRowid) == libc.Uint32FromInt32(0)) || (*TIndex)(unsafe.Pointer(pProbe)).FpPartIdxWhere != uintptr(0) || int32(*(*uint32)(unsafe.Pointer(pSrc + 24 + 4))&0x2>>1) != 0 || **(**TBitmask)(__ccgo_up(bp + 168)) == uint64(0) && int32(uint32(*(*uint16)(unsafe.Pointer(pProbe + 100))&0x4>>2)) == 0 && int32((*TIndex)(unsafe.Pointer(pProbe)).FszIdxRow) < int32((*TTable)(unsafe.Pointer(pTab)).FszTabRow) && libc.Int32FromUint16((*TWhereInfo)(unsafe.Pointer(pWInfo)).FwctrlFlags)&int32(WHERE_ONEPASS_DESIRED) == 0 && _sqlite3Config.FbUseCis != 0 && (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer((*TWhereInfo)(unsafe.Pointer(pWInfo)).FpParse)).Fdb)).FdbOptFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_CoverIdxScan)) == uint32(0) {
if b != 0 {
v5 = iSortIdx
} else {
v5 = 0
}
(*TWhereLoop)(unsafe.Pointer(pNew)).FiSortIdx = libc.Uint8FromInt32(v5)
/* The cost of visiting the index rows is N*K, where K is
** between 1.1 and 3.0, depending on the relative sizes of the
** index and table rows. */
(*TWhereLoop)(unsafe.Pointer(pNew)).FrRun = int16(int32(rSize) + int32(1) + int32(15)*int32((*TIndex)(unsafe.Pointer(pProbe)).FszIdxRow)/int32((*TTable)(unsafe.Pointer(pTab)).FszTabRow))
if **(**TBitmask)(__ccgo_up(bp + 168)) != uint64(0) {
/* If this is a non-covering index scan, add in the cost of
** doing table lookups. The cost will be 3x the number of
** lookups. Take into account WHERE clause terms that can be
** satisfied using just the index, and that do not require a
** table lookup. */
nLookup = int16(int32(rSize) + int32(16))
iCur = (*TSrcItem)(unsafe.Pointer(pSrc)).FiCursor
pWC2 = pWInfo + 104
ii = 0
for {
if !(ii < (*TWhereClause)(unsafe.Pointer(pWC2)).FnTerm) {
break
}
pTerm1 = (*TWhereClause)(unsafe.Pointer(pWC2)).Fa + uintptr(ii)*56
if !(_sqlite3ExprCoveredByIndex(tls, (*TWhereTerm)(unsafe.Pointer(pTerm1)).FpExpr, iCur, pProbe) != 0) {
break
}
/* pTerm can be evaluated using just the index. So reduce
** the expected number of table lookups accordingly */
if int32((*TWhereTerm)(unsafe.Pointer(pTerm1)).FtruthProb) <= 0 {
nLookup = int16(int32(nLookup) + int32((*TWhereTerm)(unsafe.Pointer(pTerm1)).FtruthProb))
} else {
nLookup = nLookup - 1
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm1)).FeOperator)&(libc.Int32FromInt32(WO_EQ)|libc.Int32FromInt32(WO_IS)) != 0 {
nLookup = int16(int32(nLookup) - libc.Int32FromInt32(19))
}
}
goto _7
_7:
;
ii = ii + 1
}
(*TWhereLoop)(unsafe.Pointer(pNew)).FrRun = _sqlite3LogEstAdd(tls, (*TWhereLoop)(unsafe.Pointer(pNew)).FrRun, nLookup)
}
_whereLoopOutputAdjust(tls, pWC, pNew, rSize)
if libc.Int32FromUint8((*TSrcItem)(unsafe.Pointer(pSrc)).Ffg.Fjointype)&int32(JT_RIGHT) != 0 && (*TIndex)(unsafe.Pointer(pProbe)).FaColExpr != 0 {
/* Do not do an SCAN of a index-on-expression in a RIGHT JOIN
** because the cursor used to access the index might not be
** positioned to the correct row during the right-join no-match
** loop. */
} else {
if int32(*(*uint32)(unsafe.Pointer(pSrc + 24 + 4))&0x40000>>18) != 0 {
(*TWhereLoop)(unsafe.Pointer(pNew)).FnOut = 0
}
rc = _whereLoopInsert(tls, pBuilder, pNew)
}
(*TWhereLoop)(unsafe.Pointer(pNew)).FnOut = rSize
if rc != 0 {
break
}
}
}
(*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FbldFlags1 = uint8(0)
rc = _whereLoopAddBtreeIndex(tls, pBuilder, pSrc, pProbe, 0)
if libc.Int32FromUint8((*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FbldFlags1) == int32(SQLITE_BLDF1_INDEXED) {
/* If a non-unique index is used, or if a prefix of the key for
** unique index is used (making the index functionally non-unique)
** then the sqlite_stat1 data becomes important for scoring the
** plan */
**(**Tu32)(__ccgo_up(pTab + 48)) |= uint32(TF_MaybeReanalyze)
}
_sqlite3Stat4ProbeFree(tls, (*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FpRec)
(*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FnRecValid = 0
(*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FpRec = uintptr(0)
goto _4
_4:
;
if int32(*(*uint32)(unsafe.Pointer(pSrc + 24 + 4))&0x2>>1) != 0 {
v2 = uintptr(0)
} else {
v2 = (*TIndex)(unsafe.Pointer(pProbe)).FpNext
}
pProbe = v2
iSortIdx = iSortIdx + 1
}
return rc
}
// C documentation
//
// /*
// ** Transfer content from the second pLoop into the first.
// */
func _whereLoopXfer(tls *libc.TLS, db uintptr, pTo uintptr, pFrom uintptr) (r int32) {
_whereLoopClearUnion(tls, db, pTo)
if libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pFrom)).FnLTerm) > libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pTo)).FnLSlot) && _whereLoopResize(tls, db, pTo, libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pFrom)).FnLTerm)) != 0 {
libc.Xmemset(tls, pTo, 0, uint64(libc.UintptrFromInt32(0)+56))
return int32(SQLITE_NOMEM)
}
libc.Xmemcpy(tls, pTo, pFrom, uint64(libc.UintptrFromInt32(0)+56))
libc.Xmemcpy(tls, (*TWhereLoop)(unsafe.Pointer(pTo)).FaLTerm, (*TWhereLoop)(unsafe.Pointer(pFrom)).FaLTerm, uint64((*TWhereLoop)(unsafe.Pointer(pTo)).FnLTerm)*uint64(8))
if (*TWhereLoop)(unsafe.Pointer(pFrom)).FwsFlags&uint32(WHERE_VIRTUALTABLE) != 0 {
libc.SetBitFieldPtr8Uint32(pFrom+24+4, libc.Uint32FromInt32(0), 0, 0x1)
} else {
if (*TWhereLoop)(unsafe.Pointer(pFrom)).FwsFlags&uint32(WHERE_AUTO_INDEX) != uint32(0) {
(*(*struct {
FnEq Tu16
FnBtm Tu16
FnTop Tu16
FnDistinctCol Tu16
FpIndex uintptr
FpOrderBy uintptr
})(unsafe.Pointer(pFrom + 24))).FpIndex = uintptr(0)
}
}
return SQLITE_OK
}