6c92f85d10
Bring the Nexus/Praxis/Hexis integration in line with MAVEN_ECOSYSTEM_ARCHITECTURE.md: - Praxis over HTTP: drop the in-process praxis.db open (praxisstore/ praxistools) and call praxisd's /api/v1/tools/* API via a new praxisClient. Honors the "no component reads another's DB" invariant (AC#12). PraxisConfig.DBPath -> URL. - Hexis confirmation gate: mutating capabilities (ReadOnly=false) now park a bound pendingHexis confirmation and require a spoken "да" before executing; read-only run immediately (AC#7, no auto attention->action). - Capability safety: >1 verb match is ambiguous -> ask instead of firing the first; ambiguous Nexus resolution asks for clarification (AC#2). - Correlation IDs on Hexis execute, recorded in the cross-service trace. - Bug: importance arrives as JSON float64 over HTTP, not int. - Tests: confirm-gate, decline, read-only, and ambiguity paths. Build: vendor/ bakes in the hexis client (replace-directed at a sibling repo outside the Docker context); Dockerfile builds from vendor and no longer `go mod download`s the unreachable replace paths. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
31655 lines
1.3 MiB
Plaintext
31655 lines
1.3 MiB
Plaintext
// Code generated by modernc.org/undup from the per-target sqlite_*.go files; DO NOT EDIT.
|
|
|
|
//go:build (darwin && amd64) || (darwin && arm64) || (freebsd && amd64) || (freebsd && arm64) || (linux && amd64) || (linux && arm64) || (linux && loong64) || (linux && ppc64le) || (linux && riscv64) || (linux && s390x) || (netbsd && amd64) || (openbsd && amd64) || (openbsd && arm64)
|
|
|
|
package sqlite3
|
|
|
|
import (
|
|
"unsafe"
|
|
|
|
"modernc.org/libc"
|
|
)
|
|
|
|
type Tldiv_t = struct {
|
|
Fquot int64
|
|
Frem int64
|
|
}
|
|
|
|
type Ttm = struct {
|
|
Ftm_sec int32
|
|
Ftm_min int32
|
|
Ftm_hour int32
|
|
Ftm_mday int32
|
|
Ftm_mon int32
|
|
Ftm_year int32
|
|
Ftm_wday int32
|
|
Ftm_yday int32
|
|
Ftm_isdst int32
|
|
Ftm_gmtoff int64
|
|
Ftm_zone uintptr
|
|
}
|
|
|
|
type Tu_long = uint64
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Copy nPage pages from the source b-tree to the destination.
|
|
// */
|
|
func Xsqlite3_backup_step(tls *libc.TLS, p uintptr, nPage int32) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var bCloseTrans, destMode, ii, nDestTruncate, nSrcPage, pgszDest, pgszSrc, ratio, rc, v2 int32
|
|
var iEnd, iOff, iSize Ti64
|
|
var iPg, iSrcPg, iSrcPg1 TPgno
|
|
var pDest, pDestPager, pFile, pSrcPager, zData, v1 uintptr
|
|
var v3 bool
|
|
var v6 int64
|
|
var _ /* nDstPage at bp+8 */ int32
|
|
var _ /* pPg at bp+16 */ uintptr
|
|
var _ /* pSrcPg at bp+0 */ uintptr
|
|
var _ /* pSrcPg at bp+24 */ uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = bCloseTrans, destMode, iEnd, iOff, iPg, iSize, iSrcPg, iSrcPg1, ii, nDestTruncate, nSrcPage, pDest, pDestPager, pFile, pSrcPager, pgszDest, pgszSrc, ratio, rc, zData, v1, v2, v3, v6
|
|
destMode = 0 /* Destination journal mode */
|
|
pgszSrc = 0 /* Source page size */
|
|
pgszDest = 0 /* Destination page size */
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer((*Tsqlite3_backup)(unsafe.Pointer(p)).FpSrcDb)).Fmutex)
|
|
_sqlite3BtreeEnter(tls, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpSrc)
|
|
if (*Tsqlite3_backup)(unsafe.Pointer(p)).FpDestDb != 0 {
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer((*Tsqlite3_backup)(unsafe.Pointer(p)).FpDestDb)).Fmutex)
|
|
}
|
|
rc = (*Tsqlite3_backup)(unsafe.Pointer(p)).Frc
|
|
if !(_isFatalError(tls, rc) != 0) {
|
|
pSrcPager = _sqlite3BtreePager(tls, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpSrc) /* Source pager */
|
|
pDest = uintptr(0) /* Dest btree */
|
|
pDestPager = uintptr(0) /* Iterator variable */
|
|
nSrcPage = -int32(1) /* Size of source db in pages */
|
|
bCloseTrans = 0 /* True if src db requires unlocking */
|
|
/* If the source pager is currently in a write-transaction, return
|
|
** SQLITE_BUSY immediately.
|
|
*/
|
|
if (*Tsqlite3_backup)(unsafe.Pointer(p)).FpDestDb != 0 && libc.Int32FromUint8((*TBtShared)(unsafe.Pointer((*TBtree)(unsafe.Pointer((*Tsqlite3_backup)(unsafe.Pointer(p)).FpSrc)).FpBt)).FinTransaction) == int32(TRANS_WRITE) {
|
|
rc = int32(SQLITE_BUSY)
|
|
} else {
|
|
rc = SQLITE_OK
|
|
}
|
|
/* If there is no open read-transaction on the source database, open
|
|
** one now. If a transaction is opened here, then it will be closed
|
|
** before this function exits.
|
|
*/
|
|
if rc == SQLITE_OK && SQLITE_TXN_NONE == _sqlite3BtreeTxnState(tls, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpSrc) {
|
|
rc = _sqlite3BtreeBeginTrans(tls, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpSrc, 0, uintptr(0))
|
|
bCloseTrans = int32(1)
|
|
}
|
|
/* Locate the destination btree and pager. */
|
|
v1 = (*Tsqlite3_backup)(unsafe.Pointer(p)).FpDest
|
|
pDest = v1
|
|
if v1 == uintptr(0) {
|
|
pDest = _findBtree(tls, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpDestDb, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpDestDb, (*Tsqlite3_backup)(unsafe.Pointer(p)).FzDestDb)
|
|
}
|
|
if pDest == uintptr(0) {
|
|
rc = int32(SQLITE_ERROR)
|
|
} else {
|
|
pDestPager = _sqlite3BtreePager(tls, pDest)
|
|
}
|
|
/* If the destination database has not yet been locked (i.e. if this
|
|
** is the first call to backup_step() for the current backup operation),
|
|
** try to set its page size to the same as the source database. This
|
|
** is especially important on ZipVFS systems, as in that case it is
|
|
** not possible to create a database file that uses one page size by
|
|
** writing to it with another. */
|
|
if (*Tsqlite3_backup)(unsafe.Pointer(p)).FbDestLocked == 0 && rc == SQLITE_OK && _setDestPgsz(tls, pDest, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpSrc) == int32(SQLITE_NOMEM) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
}
|
|
/* Lock the destination database, if it is not locked already. */
|
|
if v3 = SQLITE_OK == rc && (*Tsqlite3_backup)(unsafe.Pointer(p)).FbDestLocked == 0; v3 {
|
|
v2 = _sqlite3BtreeBeginTrans(tls, pDest, int32(2), p+24)
|
|
rc = v2
|
|
}
|
|
if v3 && SQLITE_OK == v2 {
|
|
(*Tsqlite3_backup)(unsafe.Pointer(p)).FbDestLocked = int32(1)
|
|
(*Tsqlite3_backup)(unsafe.Pointer(p)).FpDest = pDest
|
|
}
|
|
/* Do not allow backup if the destination database is in WAL mode
|
|
** and the page sizes are different between source and destination */
|
|
if rc == SQLITE_OK {
|
|
pgszSrc = _sqlite3BtreeGetPageSize(tls, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpSrc)
|
|
pgszDest = _sqlite3BtreeGetPageSize(tls, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpDest)
|
|
destMode = _sqlite3PagerGetJournalMode(tls, _sqlite3BtreePager(tls, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpDest))
|
|
if (destMode == int32(PAGER_JOURNALMODE_WAL) || _sqlite3PagerIsMemdb(tls, pDestPager) != 0) && pgszSrc != pgszDest {
|
|
rc = int32(SQLITE_READONLY)
|
|
}
|
|
}
|
|
/* Now that there is a read-lock on the source database, query the
|
|
** source pager for the number of pages in the database.
|
|
*/
|
|
nSrcPage = libc.Int32FromUint32(_sqlite3BtreeLastPage(tls, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpSrc))
|
|
ii = 0
|
|
for {
|
|
if !((nPage < 0 || ii < nPage) && (*Tsqlite3_backup)(unsafe.Pointer(p)).FiNext <= libc.Uint32FromInt32(nSrcPage) && !(rc != 0)) {
|
|
break
|
|
}
|
|
iSrcPg = (*Tsqlite3_backup)(unsafe.Pointer(p)).FiNext /* Source page number */
|
|
if iSrcPg != libc.Uint32FromInt32(_sqlite3PendingByte)/(*TBtShared)(unsafe.Pointer((*TBtree)(unsafe.Pointer((*Tsqlite3_backup)(unsafe.Pointer(p)).FpSrc)).FpBt)).FpageSize+libc.Uint32FromInt32(1) { /* Source page object */
|
|
rc = _sqlite3PagerGet(tls, pSrcPager, iSrcPg, bp, int32(PAGER_GET_READONLY))
|
|
if rc == SQLITE_OK {
|
|
rc = _backupOnePage(tls, p, iSrcPg, _sqlite3PagerGetData(tls, **(**uintptr)(__ccgo_up(bp))), 0)
|
|
_sqlite3PagerUnref(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
}
|
|
}
|
|
(*Tsqlite3_backup)(unsafe.Pointer(p)).FiNext = (*Tsqlite3_backup)(unsafe.Pointer(p)).FiNext + 1
|
|
goto _4
|
|
_4:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
if rc == SQLITE_OK {
|
|
(*Tsqlite3_backup)(unsafe.Pointer(p)).FnPagecount = libc.Uint32FromInt32(nSrcPage)
|
|
(*Tsqlite3_backup)(unsafe.Pointer(p)).FnRemaining = libc.Uint32FromInt32(nSrcPage+int32(1)) - (*Tsqlite3_backup)(unsafe.Pointer(p)).FiNext
|
|
if (*Tsqlite3_backup)(unsafe.Pointer(p)).FiNext > libc.Uint32FromInt32(nSrcPage) {
|
|
rc = int32(SQLITE_DONE)
|
|
} else {
|
|
if !((*Tsqlite3_backup)(unsafe.Pointer(p)).FisAttached != 0) {
|
|
_attachBackupObject(tls, p)
|
|
}
|
|
}
|
|
}
|
|
/* Update the schema version field in the destination database. This
|
|
** is to make sure that the schema-version really does change in
|
|
** the case where the source and destination databases have the
|
|
** same schema version.
|
|
*/
|
|
if rc == int32(SQLITE_DONE) {
|
|
if nSrcPage == 0 {
|
|
rc = _sqlite3BtreeNewDb(tls, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpDest)
|
|
nSrcPage = int32(1)
|
|
}
|
|
if rc == SQLITE_OK || rc == int32(SQLITE_DONE) {
|
|
rc = _sqlite3BtreeUpdateMeta(tls, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpDest, int32(1), (*Tsqlite3_backup)(unsafe.Pointer(p)).FiDestSchema+uint32(1))
|
|
}
|
|
if rc == SQLITE_OK {
|
|
if (*Tsqlite3_backup)(unsafe.Pointer(p)).FpDestDb != 0 {
|
|
_sqlite3ResetAllSchemasOfConnection(tls, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpDestDb)
|
|
}
|
|
if destMode == int32(PAGER_JOURNALMODE_WAL) {
|
|
rc = _sqlite3BtreeSetVersion(tls, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpDest, int32(2))
|
|
}
|
|
}
|
|
if rc == SQLITE_OK {
|
|
/* Set nDestTruncate to the final number of pages in the destination
|
|
** database. The complication here is that the destination page
|
|
** size may be different to the source page size.
|
|
**
|
|
** If the source page size is smaller than the destination page size,
|
|
** round up. In this case the call to sqlite3OsTruncate() below will
|
|
** fix the size of the file. However it is important to call
|
|
** sqlite3PagerTruncateImage() here so that any pages in the
|
|
** destination file that lie beyond the nDestTruncate page mark are
|
|
** journalled by PagerCommitPhaseOne() before they are destroyed
|
|
** by the file truncation.
|
|
*/
|
|
if pgszSrc < pgszDest {
|
|
ratio = pgszDest / pgszSrc
|
|
nDestTruncate = (nSrcPage + ratio - int32(1)) / ratio
|
|
if nDestTruncate == libc.Int32FromUint32(libc.Uint32FromInt32(_sqlite3PendingByte)/(*TBtShared)(unsafe.Pointer((*TBtree)(unsafe.Pointer((*Tsqlite3_backup)(unsafe.Pointer(p)).FpDest)).FpBt)).FpageSize+libc.Uint32FromInt32(1)) {
|
|
nDestTruncate = nDestTruncate - 1
|
|
}
|
|
} else {
|
|
nDestTruncate = nSrcPage * (pgszSrc / pgszDest)
|
|
}
|
|
if pgszSrc < pgszDest {
|
|
/* If the source page-size is smaller than the destination page-size,
|
|
** two extra things may need to happen:
|
|
**
|
|
** * The destination may need to be truncated, and
|
|
**
|
|
** * Data stored on the pages immediately following the
|
|
** pending-byte page in the source database may need to be
|
|
** copied into the destination database.
|
|
*/
|
|
iSize = int64(pgszSrc) * int64(nSrcPage)
|
|
pFile = _sqlite3PagerFile(tls, pDestPager)
|
|
/* This block ensures that all data required to recreate the original
|
|
** database has been stored in the journal for pDestPager and the
|
|
** journal synced to disk. So at this point we may safely modify
|
|
** the database file in any way, knowing that if a power failure
|
|
** occurs, the original database will be reconstructed from the
|
|
** journal file. */
|
|
_sqlite3PagerPagecount(tls, pDestPager, bp+8)
|
|
iPg = libc.Uint32FromInt32(nDestTruncate)
|
|
for {
|
|
if !(rc == SQLITE_OK && iPg <= libc.Uint32FromInt32(**(**int32)(__ccgo_up(bp + 8)))) {
|
|
break
|
|
}
|
|
if iPg != libc.Uint32FromInt32(_sqlite3PendingByte)/(*TBtShared)(unsafe.Pointer((*TBtree)(unsafe.Pointer((*Tsqlite3_backup)(unsafe.Pointer(p)).FpDest)).FpBt)).FpageSize+libc.Uint32FromInt32(1) {
|
|
rc = _sqlite3PagerGet(tls, pDestPager, iPg, bp+16, 0)
|
|
if rc == SQLITE_OK {
|
|
rc = _sqlite3PagerWrite(tls, **(**uintptr)(__ccgo_up(bp + 16)))
|
|
_sqlite3PagerUnref(tls, **(**uintptr)(__ccgo_up(bp + 16)))
|
|
}
|
|
}
|
|
goto _5
|
|
_5:
|
|
;
|
|
iPg = iPg + 1
|
|
}
|
|
if rc == SQLITE_OK {
|
|
rc = _sqlite3PagerCommitPhaseOne(tls, pDestPager, uintptr(0), int32(1))
|
|
}
|
|
/* Write the extra pages and truncate the database file as required */
|
|
if int64(_sqlite3PendingByte+pgszDest) < iSize {
|
|
v6 = int64(_sqlite3PendingByte + pgszDest)
|
|
} else {
|
|
v6 = iSize
|
|
}
|
|
iEnd = v6
|
|
iOff = int64(_sqlite3PendingByte + pgszSrc)
|
|
for {
|
|
if !(rc == SQLITE_OK && iOff < iEnd) {
|
|
break
|
|
}
|
|
**(**uintptr)(__ccgo_up(bp + 24)) = uintptr(0)
|
|
iSrcPg1 = libc.Uint32FromInt64(iOff/int64(pgszSrc) + libc.Int64FromInt32(1))
|
|
rc = _sqlite3PagerGet(tls, pSrcPager, iSrcPg1, bp+24, 0)
|
|
if rc == SQLITE_OK {
|
|
zData = _sqlite3PagerGetData(tls, **(**uintptr)(__ccgo_up(bp + 24)))
|
|
rc = _sqlite3OsWrite(tls, pFile, zData, pgszSrc, iOff)
|
|
}
|
|
_sqlite3PagerUnref(tls, **(**uintptr)(__ccgo_up(bp + 24)))
|
|
goto _7
|
|
_7:
|
|
;
|
|
iOff = iOff + int64(pgszSrc)
|
|
}
|
|
if rc == SQLITE_OK {
|
|
rc = _backupTruncateFile(tls, pFile, iSize)
|
|
}
|
|
/* Sync the database file to disk. */
|
|
if rc == SQLITE_OK {
|
|
rc = _sqlite3PagerSync(tls, pDestPager, uintptr(0))
|
|
}
|
|
} else {
|
|
_sqlite3PagerTruncateImage(tls, pDestPager, libc.Uint32FromInt32(nDestTruncate))
|
|
rc = _sqlite3PagerCommitPhaseOne(tls, pDestPager, uintptr(0), 0)
|
|
}
|
|
/* Finish committing the transaction to the destination database. */
|
|
if v3 = SQLITE_OK == rc; v3 {
|
|
v2 = _sqlite3BtreeCommitPhaseTwo(tls, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpDest, 0)
|
|
rc = v2
|
|
}
|
|
if v3 && SQLITE_OK == v2 {
|
|
rc = int32(SQLITE_DONE)
|
|
}
|
|
}
|
|
}
|
|
/* If bCloseTrans is true, then this function opened a read transaction
|
|
** on the source database. Close the read transaction here. There is
|
|
** no need to check the return values of the btree methods here, as
|
|
** "committing" a read-only transaction cannot fail.
|
|
*/
|
|
if bCloseTrans != 0 {
|
|
_sqlite3BtreeCommitPhaseOne(tls, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpSrc, uintptr(0))
|
|
_sqlite3BtreeCommitPhaseTwo(tls, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpSrc, 0)
|
|
}
|
|
if rc == libc.Int32FromInt32(SQLITE_IOERR)|libc.Int32FromInt32(12)<<libc.Int32FromInt32(8) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
}
|
|
(*Tsqlite3_backup)(unsafe.Pointer(p)).Frc = rc
|
|
}
|
|
if (*Tsqlite3_backup)(unsafe.Pointer(p)).FpDestDb != 0 {
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer((*Tsqlite3_backup)(unsafe.Pointer(p)).FpDestDb)).Fmutex)
|
|
}
|
|
_sqlite3BtreeLeave(tls, (*Tsqlite3_backup)(unsafe.Pointer(p)).FpSrc)
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer((*Tsqlite3_backup)(unsafe.Pointer(p)).FpSrcDb)).Fmutex)
|
|
return rc
|
|
}
|
|
|
|
func Xsqlite3_bind_double(tls *libc.TLS, pStmt uintptr, i int32, rValue float64) (r int32) {
|
|
var p uintptr
|
|
var rc int32
|
|
_, _ = p, rc
|
|
p = pStmt
|
|
rc = _vdbeUnbind(tls, p, libc.Uint32FromInt32(i-libc.Int32FromInt32(1)))
|
|
if rc == SQLITE_OK {
|
|
/* tag-20240917-01 */
|
|
_sqlite3VdbeMemSetDouble(tls, (*TVdbe)(unsafe.Pointer(p)).FaVar+uintptr(i-int32(1))*56, rValue)
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer((*TVdbe)(unsafe.Pointer(p)).Fdb)).Fmutex)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
func Xsqlite3_bind_int64(tls *libc.TLS, pStmt uintptr, i int32, iValue Tsqlite_int64) (r int32) {
|
|
var p uintptr
|
|
var rc int32
|
|
_, _ = p, rc
|
|
p = pStmt
|
|
rc = _vdbeUnbind(tls, p, libc.Uint32FromInt32(i-libc.Int32FromInt32(1)))
|
|
if rc == SQLITE_OK {
|
|
/* tag-20240917-01 */
|
|
_sqlite3VdbeMemSetInt64(tls, (*TVdbe)(unsafe.Pointer(p)).FaVar+uintptr(i-int32(1))*56, iValue)
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer((*TVdbe)(unsafe.Pointer(p)).Fdb)).Fmutex)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
func Xsqlite3_bind_pointer(tls *libc.TLS, pStmt uintptr, i int32, pPtr uintptr, zPTtype uintptr, __ccgo_fp_xDestructor uintptr) (r int32) {
|
|
var p uintptr
|
|
var rc int32
|
|
_, _ = p, rc
|
|
p = pStmt
|
|
rc = _vdbeUnbind(tls, p, libc.Uint32FromInt32(i-libc.Int32FromInt32(1)))
|
|
if rc == SQLITE_OK {
|
|
/* tag-20240917-01 */
|
|
_sqlite3VdbeMemSetPointer(tls, (*TVdbe)(unsafe.Pointer(p)).FaVar+uintptr(i-int32(1))*56, pPtr, zPTtype, __ccgo_fp_xDestructor)
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer((*TVdbe)(unsafe.Pointer(p)).Fdb)).Fmutex)
|
|
} else {
|
|
if __ccgo_fp_xDestructor != 0 {
|
|
(*(*func(*libc.TLS, uintptr))(unsafe.Pointer(&struct{ uintptr }{__ccgo_fp_xDestructor})))(tls, pPtr)
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
func Xsqlite3_bind_zeroblob(tls *libc.TLS, pStmt uintptr, i int32, n int32) (r int32) {
|
|
var p uintptr
|
|
var rc int32
|
|
_, _ = p, rc
|
|
p = pStmt
|
|
rc = _vdbeUnbind(tls, p, libc.Uint32FromInt32(i-libc.Int32FromInt32(1)))
|
|
if rc == SQLITE_OK {
|
|
/* tag-20240917-01 */
|
|
_sqlite3VdbeMemSetZeroBlob(tls, (*TVdbe)(unsafe.Pointer(p)).FaVar+uintptr(i-int32(1))*56, n)
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer((*TVdbe)(unsafe.Pointer(p)).Fdb)).Fmutex)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
func Xsqlite3_bind_zeroblob64(tls *libc.TLS, pStmt uintptr, i int32, n Tsqlite3_uint64) (r int32) {
|
|
var p uintptr
|
|
var rc int32
|
|
_, _ = p, rc
|
|
p = pStmt
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer((*TVdbe)(unsafe.Pointer(p)).Fdb)).Fmutex)
|
|
if n > libc.Uint64FromInt32(**(**int32)(__ccgo_up((*TVdbe)(unsafe.Pointer(p)).Fdb + 136))) {
|
|
rc = int32(SQLITE_TOOBIG)
|
|
} else {
|
|
rc = Xsqlite3_bind_zeroblob(tls, pStmt, i, libc.Int32FromUint64(n))
|
|
}
|
|
rc = _sqlite3ApiExit(tls, (*TVdbe)(unsafe.Pointer(p)).Fdb, rc)
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer((*TVdbe)(unsafe.Pointer(p)).Fdb)).Fmutex)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Cancel a prior call to sqlite3_auto_extension. Remove xInit from the
|
|
// ** set of routines that is invoked for each new database connection, if it
|
|
// ** is currently on the list. If xInit is not on the list, then this
|
|
// ** routine is a no-op.
|
|
// **
|
|
// ** Return 1 if xInit was found on the list and removed. Return 0 if xInit
|
|
// ** was not on the list.
|
|
// */
|
|
func Xsqlite3_cancel_auto_extension(tls *libc.TLS, __ccgo_fp_xInit uintptr) (r int32) {
|
|
var i, n int32
|
|
var mutex uintptr
|
|
_, _, _ = i, mutex, n
|
|
mutex = _sqlite3MutexAlloc(tls, int32(SQLITE_MUTEX_STATIC_MAIN))
|
|
n = 0
|
|
Xsqlite3_mutex_enter(tls, mutex)
|
|
i = libc.Int32FromUint32(_sqlite3Autoext.FnExt) - int32(1)
|
|
for {
|
|
if !(i >= 0) {
|
|
break
|
|
}
|
|
if **(**uintptr)(__ccgo_up(_sqlite3Autoext.FaExt + uintptr(i)*8)) == __ccgo_fp_xInit {
|
|
_sqlite3Autoext.FnExt = _sqlite3Autoext.FnExt - 1
|
|
**(**uintptr)(__ccgo_up(_sqlite3Autoext.FaExt + uintptr(i)*8)) = **(**uintptr)(__ccgo_up(_sqlite3Autoext.FaExt + uintptr(_sqlite3Autoext.FnExt)*8))
|
|
n = n + 1
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i - 1
|
|
}
|
|
Xsqlite3_mutex_leave(tls, mutex)
|
|
return n
|
|
}
|
|
|
|
func Xsqlite3_column_value(tls *libc.TLS, pStmt uintptr, i int32) (r uintptr) {
|
|
var pOut, v1 uintptr
|
|
_, _ = pOut, v1
|
|
pOut = _columnMem(tls, pStmt, i)
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pOut)).Fflags)&int32(MEM_Static) != 0 {
|
|
v1 = pOut + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) & ^libc.Int32FromInt32(MEM_Static))
|
|
v1 = pOut + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(MEM_Ephem))
|
|
}
|
|
_columnMallocFailure(tls, pStmt)
|
|
return pOut
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Configuration settings for an individual database connection
|
|
// */
|
|
func Xsqlite3_db_config(tls *libc.TLS, db uintptr, op int32, va uintptr) (r int32) {
|
|
var ap Tva_list
|
|
var cnt, nIn, onoff, rc, sz int32
|
|
var i uint32
|
|
var oldFlags Tu64
|
|
var pBuf, pOut, pRes uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _ = ap, cnt, i, nIn, oldFlags, onoff, pBuf, pOut, pRes, rc, sz
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
ap = va
|
|
switch op {
|
|
case int32(SQLITE_DBCONFIG_MAINDBNAME):
|
|
/* IMP: R-06824-28531 */
|
|
/* IMP: R-36257-52125 */
|
|
(**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb))).FzDbSName = libc.VaUintptr(&ap)
|
|
rc = SQLITE_OK
|
|
case int32(SQLITE_DBCONFIG_LOOKASIDE):
|
|
pBuf = libc.VaUintptr(&ap) /* IMP: R-26835-10964 */
|
|
sz = libc.VaInt32(&ap) /* IMP: R-47871-25994 */
|
|
cnt = libc.VaInt32(&ap) /* IMP: R-04460-53386 */
|
|
rc = _setupLookaside(tls, db, pBuf, sz, cnt)
|
|
case int32(SQLITE_DBCONFIG_FP_DIGITS):
|
|
nIn = libc.VaInt32(&ap)
|
|
pOut = libc.VaUintptr(&ap)
|
|
if nIn > int32(3) && nIn < int32(24) {
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FnFpDigit = libc.Uint8FromInt32(nIn)
|
|
}
|
|
if pOut != 0 {
|
|
**(**int32)(__ccgo_up(pOut)) = libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).FnFpDigit)
|
|
}
|
|
rc = SQLITE_OK
|
|
default:
|
|
rc = int32(SQLITE_ERROR) /* IMP: R-42790-23372 */
|
|
i = uint32(0)
|
|
for {
|
|
if !(i < libc.Uint32FromInt32(libc.Int32FromUint64(libc.Uint64FromInt64(336)/libc.Uint64FromInt64(16)))) {
|
|
break
|
|
}
|
|
if _aFlagOp[i].Fop == op {
|
|
onoff = libc.VaInt32(&ap)
|
|
pRes = libc.VaUintptr(&ap)
|
|
oldFlags = (*Tsqlite3)(unsafe.Pointer(db)).Fflags
|
|
if onoff > 0 {
|
|
**(**Tu64)(__ccgo_up(db + 48)) |= _aFlagOp[i].Fmask
|
|
} else {
|
|
if onoff == 0 {
|
|
**(**Tu64)(__ccgo_up(db + 48)) &= ^_aFlagOp[i].Fmask
|
|
}
|
|
}
|
|
if oldFlags != (*Tsqlite3)(unsafe.Pointer(db)).Fflags {
|
|
_sqlite3ExpirePreparedStatements(tls, db, 0)
|
|
}
|
|
if pRes != 0 {
|
|
**(**int32)(__ccgo_up(pRes)) = libc.BoolInt32((*Tsqlite3)(unsafe.Pointer(db)).Fflags&_aFlagOp[i].Fmask != uint64(0))
|
|
}
|
|
rc = SQLITE_OK
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
break
|
|
}
|
|
_ = ap
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Query status information for a single database connection
|
|
// */
|
|
func Xsqlite3_db_status64(tls *libc.TLS, db uintptr, op int32, pCurrent uintptr, pHighwtr uintptr, resetFlag int32) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var i, i1, i2, nByte, rc int32
|
|
var p, p1, pBt, pPager, pPager1, pPager2, pSchema, pVdbe uintptr
|
|
var totalUsed Tsqlite3_int64
|
|
var _ /* H at bp+0 */ int32
|
|
var _ /* nByte at bp+4 */ int32
|
|
var _ /* nByte at bp+8 */ int32
|
|
var _ /* nRet at bp+16 */ Tu64
|
|
var _ /* nRet at bp+24 */ Tu64
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _ = i, i1, i2, nByte, p, p1, pBt, pPager, pPager1, pPager2, pSchema, pVdbe, rc, totalUsed
|
|
rc = SQLITE_OK /* Return code */
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
switch op {
|
|
case SQLITE_DBSTATUS_LOOKASIDE_USED:
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
**(**Tsqlite3_int64)(__ccgo_up(pCurrent)) = int64(_sqlite3LookasideUsed(tls, db, bp))
|
|
**(**Tsqlite3_int64)(__ccgo_up(pHighwtr)) = int64(**(**int32)(__ccgo_up(bp)))
|
|
if resetFlag != 0 {
|
|
p = (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpFree
|
|
if p != 0 {
|
|
for (*TLookasideSlot)(unsafe.Pointer(p)).FpNext != 0 {
|
|
p = (*TLookasideSlot)(unsafe.Pointer(p)).FpNext
|
|
}
|
|
(*TLookasideSlot)(unsafe.Pointer(p)).FpNext = (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpInit
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpInit = (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpFree
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpFree = uintptr(0)
|
|
}
|
|
p = (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpSmallFree
|
|
if p != 0 {
|
|
for (*TLookasideSlot)(unsafe.Pointer(p)).FpNext != 0 {
|
|
p = (*TLookasideSlot)(unsafe.Pointer(p)).FpNext
|
|
}
|
|
(*TLookasideSlot)(unsafe.Pointer(p)).FpNext = (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpSmallInit
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpSmallInit = (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpSmallFree
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpSmallFree = uintptr(0)
|
|
}
|
|
}
|
|
case int32(SQLITE_DBSTATUS_LOOKASIDE_HIT):
|
|
fallthrough
|
|
case int32(SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE):
|
|
fallthrough
|
|
case int32(SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL):
|
|
**(**Tsqlite3_int64)(__ccgo_up(pCurrent)) = 0
|
|
**(**Tsqlite3_int64)(__ccgo_up(pHighwtr)) = libc.Int64FromUint32(**(**Tu32)(__ccgo_up(db + 440 + 16 + uintptr(op-int32(SQLITE_DBSTATUS_LOOKASIDE_HIT))*4)))
|
|
if resetFlag != 0 {
|
|
**(**Tu32)(__ccgo_up(db + 440 + 16 + uintptr(op-int32(SQLITE_DBSTATUS_LOOKASIDE_HIT))*4)) = uint32(0)
|
|
}
|
|
break
|
|
/*
|
|
** Return an approximation for the amount of memory currently used
|
|
** by all pagers associated with the given database connection. The
|
|
** highwater mark is meaningless and is returned as zero.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_DBSTATUS_CACHE_USED_SHARED):
|
|
fallthrough
|
|
case int32(SQLITE_DBSTATUS_CACHE_USED):
|
|
totalUsed = 0
|
|
_sqlite3BtreeEnterAll(tls, db)
|
|
i = 0
|
|
for {
|
|
if !(i < (*Tsqlite3)(unsafe.Pointer(db)).FnDb) {
|
|
break
|
|
}
|
|
pBt = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(i)*32))).FpBt
|
|
if pBt != 0 {
|
|
pPager = _sqlite3BtreePager(tls, pBt)
|
|
nByte = _sqlite3PagerMemUsed(tls, pPager)
|
|
if op == int32(SQLITE_DBSTATUS_CACHE_USED_SHARED) {
|
|
nByte = nByte / _sqlite3BtreeConnectionCount(tls, pBt)
|
|
}
|
|
totalUsed = totalUsed + int64(nByte)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_sqlite3BtreeLeaveAll(tls, db)
|
|
**(**Tsqlite3_int64)(__ccgo_up(pCurrent)) = totalUsed
|
|
**(**Tsqlite3_int64)(__ccgo_up(pHighwtr)) = 0
|
|
break
|
|
/*
|
|
** *pCurrent gets an accurate estimate of the amount of memory used
|
|
** to store the schema for all databases (main, temp, and any ATTACHed
|
|
** databases. *pHighwtr is set to zero.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_DBSTATUS_SCHEMA_USED): /* Used to iterate through schemas */
|
|
**(**int32)(__ccgo_up(bp + 4)) = 0 /* Used to accumulate return value */
|
|
_sqlite3BtreeEnterAll(tls, db)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FpnBytesFreed = bp + 4
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpEnd = (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpStart
|
|
i1 = 0
|
|
for {
|
|
if !(i1 < (*Tsqlite3)(unsafe.Pointer(db)).FnDb) {
|
|
break
|
|
}
|
|
pSchema = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(i1)*32))).FpSchema
|
|
if pSchema != uintptr(0) {
|
|
**(**int32)(__ccgo_up(bp + 4)) = libc.Int32FromUint32(uint32(**(**int32)(__ccgo_up(bp + 4))) + libc.Uint32FromInt32((*(*func(*libc.TLS, int32) int32)(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.Fm.FxRoundup})))(tls, int32(40)))*((*TSchema)(unsafe.Pointer(pSchema)).FtblHash.Fcount+(*TSchema)(unsafe.Pointer(pSchema)).FtrigHash.Fcount+(*TSchema)(unsafe.Pointer(pSchema)).FidxHash.Fcount+(*TSchema)(unsafe.Pointer(pSchema)).FfkeyHash.Fcount))
|
|
**(**int32)(__ccgo_up(bp + 4)) = libc.Int32FromUint64(uint64(**(**int32)(__ccgo_up(bp + 4))) + Xsqlite3_msize(tls, (*TSchema)(unsafe.Pointer(pSchema)).FtblHash.Fht))
|
|
**(**int32)(__ccgo_up(bp + 4)) = libc.Int32FromUint64(uint64(**(**int32)(__ccgo_up(bp + 4))) + Xsqlite3_msize(tls, (*TSchema)(unsafe.Pointer(pSchema)).FtrigHash.Fht))
|
|
**(**int32)(__ccgo_up(bp + 4)) = libc.Int32FromUint64(uint64(**(**int32)(__ccgo_up(bp + 4))) + Xsqlite3_msize(tls, (*TSchema)(unsafe.Pointer(pSchema)).FidxHash.Fht))
|
|
**(**int32)(__ccgo_up(bp + 4)) = libc.Int32FromUint64(uint64(**(**int32)(__ccgo_up(bp + 4))) + Xsqlite3_msize(tls, (*TSchema)(unsafe.Pointer(pSchema)).FfkeyHash.Fht))
|
|
p1 = (*THash)(unsafe.Pointer(pSchema + 56)).Ffirst
|
|
for {
|
|
if !(p1 != 0) {
|
|
break
|
|
}
|
|
_sqlite3DeleteTrigger(tls, db, (*THashElem)(unsafe.Pointer(p1)).Fdata)
|
|
goto _3
|
|
_3:
|
|
;
|
|
p1 = (*THashElem)(unsafe.Pointer(p1)).Fnext
|
|
}
|
|
p1 = (*THash)(unsafe.Pointer(pSchema + 8)).Ffirst
|
|
for {
|
|
if !(p1 != 0) {
|
|
break
|
|
}
|
|
_sqlite3DeleteTable(tls, db, (*THashElem)(unsafe.Pointer(p1)).Fdata)
|
|
goto _4
|
|
_4:
|
|
;
|
|
p1 = (*THashElem)(unsafe.Pointer(p1)).Fnext
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i1 = i1 + 1
|
|
}
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FpnBytesFreed = uintptr(0)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpEnd = (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpTrueEnd
|
|
_sqlite3BtreeLeaveAll(tls, db)
|
|
**(**Tsqlite3_int64)(__ccgo_up(pHighwtr)) = 0
|
|
**(**Tsqlite3_int64)(__ccgo_up(pCurrent)) = int64(**(**int32)(__ccgo_up(bp + 4)))
|
|
break
|
|
/*
|
|
** *pCurrent gets an accurate estimate of the amount of memory used
|
|
** to store all prepared statements.
|
|
** *pHighwtr is set to zero.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_DBSTATUS_STMT_USED): /* Used to iterate through VMs */
|
|
**(**int32)(__ccgo_up(bp + 8)) = 0 /* Used to accumulate return value */
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FpnBytesFreed = bp + 8
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpEnd = (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpStart
|
|
pVdbe = (*Tsqlite3)(unsafe.Pointer(db)).FpVdbe
|
|
for {
|
|
if !(pVdbe != 0) {
|
|
break
|
|
}
|
|
_sqlite3VdbeDelete(tls, pVdbe)
|
|
goto _5
|
|
_5:
|
|
;
|
|
pVdbe = (*TVdbe)(unsafe.Pointer(pVdbe)).FpVNext
|
|
}
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpEnd = (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpTrueEnd
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FpnBytesFreed = uintptr(0)
|
|
**(**Tsqlite3_int64)(__ccgo_up(pHighwtr)) = 0 /* IMP: R-64479-57858 */
|
|
**(**Tsqlite3_int64)(__ccgo_up(pCurrent)) = int64(**(**int32)(__ccgo_up(bp + 8)))
|
|
break
|
|
/*
|
|
** Set *pCurrent to the total cache hits or misses encountered by all
|
|
** pagers the database handle is connected to. *pHighwtr is always set
|
|
** to zero.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_DBSTATUS_CACHE_SPILL):
|
|
op = libc.Int32FromInt32(SQLITE_DBSTATUS_CACHE_WRITE) + libc.Int32FromInt32(1)
|
|
fallthrough
|
|
case int32(SQLITE_DBSTATUS_CACHE_HIT):
|
|
fallthrough
|
|
case int32(SQLITE_DBSTATUS_CACHE_MISS):
|
|
fallthrough
|
|
case int32(SQLITE_DBSTATUS_CACHE_WRITE):
|
|
**(**Tu64)(__ccgo_up(bp + 16)) = uint64(0)
|
|
i2 = 0
|
|
for {
|
|
if !(i2 < (*Tsqlite3)(unsafe.Pointer(db)).FnDb) {
|
|
break
|
|
}
|
|
if (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(i2)*32))).FpBt != 0 {
|
|
pPager1 = _sqlite3BtreePager(tls, (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(i2)*32))).FpBt)
|
|
_sqlite3PagerCacheStat(tls, pPager1, op, resetFlag, bp+16)
|
|
}
|
|
goto _6
|
|
_6:
|
|
;
|
|
i2 = i2 + 1
|
|
}
|
|
**(**Tsqlite3_int64)(__ccgo_up(pHighwtr)) = 0 /* IMP: R-42420-56072 */
|
|
/* IMP: R-54100-20147 */
|
|
/* IMP: R-29431-39229 */
|
|
**(**Tsqlite3_int64)(__ccgo_up(pCurrent)) = libc.Int64FromUint64(**(**Tu64)(__ccgo_up(bp + 16)))
|
|
break
|
|
/* Set *pCurrent to the number of bytes that the db database connection
|
|
** has spilled to the filesystem in temporary files that could have been
|
|
** stored in memory, had sufficient memory been available.
|
|
** The *pHighwater is always set to zero.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_DBSTATUS_TEMPBUF_SPILL):
|
|
**(**Tu64)(__ccgo_up(bp + 24)) = uint64(0)
|
|
if (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + 1*32))).FpBt != 0 {
|
|
pPager2 = _sqlite3BtreePager(tls, (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + 1*32))).FpBt)
|
|
_sqlite3PagerCacheStat(tls, pPager2, int32(SQLITE_DBSTATUS_CACHE_WRITE), resetFlag, bp+24)
|
|
**(**Tu64)(__ccgo_up(bp + 24)) = **(**Tu64)(__ccgo_up(bp + 24)) * libc.Uint64FromInt32(_sqlite3BtreeGetPageSize(tls, (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + 1*32))).FpBt))
|
|
}
|
|
**(**Tu64)(__ccgo_up(bp + 24)) = **(**Tu64)(__ccgo_up(bp + 24)) + (*Tsqlite3)(unsafe.Pointer(db)).FnSpill
|
|
if resetFlag != 0 {
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FnSpill = uint64(0)
|
|
}
|
|
**(**Tsqlite3_int64)(__ccgo_up(pHighwtr)) = 0
|
|
**(**Tsqlite3_int64)(__ccgo_up(pCurrent)) = libc.Int64FromUint64(**(**Tu64)(__ccgo_up(bp + 24)))
|
|
break
|
|
/* Set *pCurrent to non-zero if there are unresolved deferred foreign
|
|
** key constraints. Set *pCurrent to zero if all foreign key constraints
|
|
** have been satisfied. The *pHighwtr is always set to zero.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_DBSTATUS_DEFERRED_FKS):
|
|
**(**Tsqlite3_int64)(__ccgo_up(pHighwtr)) = 0 /* IMP: R-11967-56545 */
|
|
**(**Tsqlite3_int64)(__ccgo_up(pCurrent)) = libc.BoolInt64((*Tsqlite3)(unsafe.Pointer(db)).FnDeferredImmCons > 0 || (*Tsqlite3)(unsafe.Pointer(db)).FnDeferredCons > 0)
|
|
default:
|
|
rc = int32(SQLITE_ERROR)
|
|
}
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Enable or disable extension loading. Extension loading is disabled by
|
|
// ** default so as not to open security holes in older applications.
|
|
// */
|
|
func Xsqlite3_enable_load_extension(tls *libc.TLS, db uintptr, onoff int32) (r int32) {
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
if onoff != 0 {
|
|
**(**Tu64)(__ccgo_up(db + 48)) |= libc.Uint64FromInt32(libc.Int32FromInt32(SQLITE_LoadExtension) | libc.Int32FromInt32(SQLITE_LoadExtFunc))
|
|
} else {
|
|
**(**Tu64)(__ccgo_up(db + 48)) &= ^libc.Uint64FromInt32(libc.Int32FromInt32(SQLITE_LoadExtension) | libc.Int32FromInt32(SQLITE_LoadExtFunc))
|
|
}
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called from within a pre-update callback to retrieve
|
|
// ** a field of the row currently being updated or inserted.
|
|
// */
|
|
func Xsqlite3_preupdate_new(tls *libc.TLS, db uintptr, iIdx int32, ppValue uintptr) (r int32) {
|
|
var iStore, rc, v1 int32
|
|
var p, pData, pMem, pUnpack uintptr
|
|
_, _, _, _, _, _, _ = iStore, p, pData, pMem, pUnpack, rc, v1
|
|
rc = SQLITE_OK
|
|
iStore = 0
|
|
p = (*Tsqlite3)(unsafe.Pointer(db)).FpPreUpdate
|
|
if !(p != 0) || (*TPreUpdate)(unsafe.Pointer(p)).Fop == int32(SQLITE_DELETE) {
|
|
rc = _sqlite3MisuseError(tls, int32(96071))
|
|
goto preupdate_new_out
|
|
}
|
|
if (*TPreUpdate)(unsafe.Pointer(p)).FpPk != 0 && (*TPreUpdate)(unsafe.Pointer(p)).Fop != int32(SQLITE_UPDATE) {
|
|
iStore = _sqlite3TableColumnToIndex(tls, (*TPreUpdate)(unsafe.Pointer(p)).FpPk, iIdx)
|
|
} else {
|
|
if iIdx >= int32((*TTable)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).FpTab)).FnCol) {
|
|
return _sqlite3MisuseError(tls, int32(96077))
|
|
} else {
|
|
iStore = int32(_sqlite3TableColumnToStorage(tls, (*TPreUpdate)(unsafe.Pointer(p)).FpTab, int16(iIdx)))
|
|
}
|
|
}
|
|
if iStore >= int32((*TVdbeCursor)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).FpCsr)).FnField) || iStore < 0 {
|
|
rc = int32(SQLITE_RANGE)
|
|
goto preupdate_new_out
|
|
}
|
|
if (*TPreUpdate)(unsafe.Pointer(p)).Fop == int32(SQLITE_INSERT) {
|
|
/* For an INSERT, memory cell p->iNewReg contains the serialized record
|
|
** that is being inserted. Deserialize it. */
|
|
pUnpack = (*TPreUpdate)(unsafe.Pointer(p)).FpNewUnpacked
|
|
if !(pUnpack != 0) {
|
|
pData = (*TVdbe)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).Fv)).FaMem + uintptr((*TPreUpdate)(unsafe.Pointer(p)).FiNewReg)*56
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pData)).Fflags)&int32(MEM_Zero) != 0 {
|
|
v1 = _sqlite3VdbeMemExpandBlob(tls, pData)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
rc = v1
|
|
if rc != SQLITE_OK {
|
|
goto preupdate_new_out
|
|
}
|
|
pUnpack = _vdbeUnpackRecord(tls, (*TPreUpdate)(unsafe.Pointer(p)).FpKeyinfo, (*TMem)(unsafe.Pointer(pData)).Fn, (*TMem)(unsafe.Pointer(pData)).Fz)
|
|
if !(pUnpack != 0) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
goto preupdate_new_out
|
|
}
|
|
(*TPreUpdate)(unsafe.Pointer(p)).FpNewUnpacked = pUnpack
|
|
}
|
|
pMem = (*TUnpackedRecord)(unsafe.Pointer(pUnpack)).FaMem + uintptr(iStore)*56
|
|
if iIdx == int32((*TTable)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).FpTab)).FiPKey) {
|
|
_sqlite3VdbeMemSetInt64(tls, pMem, (*TPreUpdate)(unsafe.Pointer(p)).FiKey2)
|
|
} else {
|
|
if iStore >= libc.Int32FromUint16((*TUnpackedRecord)(unsafe.Pointer(pUnpack)).FnField) {
|
|
pMem = _columnNullValue(tls)
|
|
}
|
|
}
|
|
} else {
|
|
/* For an UPDATE, memory cell (p->iNewReg+1+iStore) contains the required
|
|
** value. Make a copy of the cell contents and return a pointer to it.
|
|
** It is not safe to return a pointer to the memory cell itself as the
|
|
** caller may modify the value text encoding.
|
|
*/
|
|
if !((*TPreUpdate)(unsafe.Pointer(p)).FaNew != 0) {
|
|
(*TPreUpdate)(unsafe.Pointer(p)).FaNew = _sqlite3DbMallocZero(tls, db, uint64(uint64(56)*libc.Uint64FromInt16((*TVdbeCursor)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).FpCsr)).FnField)))
|
|
if !((*TPreUpdate)(unsafe.Pointer(p)).FaNew != 0) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
goto preupdate_new_out
|
|
}
|
|
}
|
|
pMem = (*TPreUpdate)(unsafe.Pointer(p)).FaNew + uintptr(iStore)*56
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags) == 0 {
|
|
if iIdx == int32((*TTable)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).FpTab)).FiPKey) {
|
|
_sqlite3VdbeMemSetInt64(tls, pMem, (*TPreUpdate)(unsafe.Pointer(p)).FiKey2)
|
|
} else {
|
|
rc = _sqlite3VdbeMemCopy(tls, pMem, (*TVdbe)(unsafe.Pointer((*TPreUpdate)(unsafe.Pointer(p)).Fv)).FaMem+uintptr((*TPreUpdate)(unsafe.Pointer(p)).FiNewReg+int32(1)+iStore)*56)
|
|
if rc != SQLITE_OK {
|
|
goto preupdate_new_out
|
|
}
|
|
}
|
|
}
|
|
}
|
|
**(**uintptr)(__ccgo_up(ppValue)) = pMem
|
|
goto preupdate_new_out
|
|
preupdate_new_out:
|
|
;
|
|
_sqlite3Error(tls, db, rc)
|
|
return _sqlite3ApiExit(tls, db, rc)
|
|
}
|
|
|
|
/************** End of vdbeapi.c *********************************************/
|
|
/************** Begin file vdbetrace.c ***************************************/
|
|
/*
|
|
** 2009 November 25
|
|
**
|
|
** The author disclaims copyright to this source code. In place of
|
|
** a legal notice, here is a blessing:
|
|
**
|
|
** May you do good and not evil.
|
|
** May you find forgiveness for yourself and forgive others.
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
*************************************************************************
|
|
**
|
|
** This file contains code used to insert the values of host parameters
|
|
** (aka "wildcards") into the SQL text output by sqlite3_trace().
|
|
**
|
|
** The Vdbe parse-tree explainer is also found here.
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
/* #include "vdbeInt.h" */
|
|
|
|
func Xsqlite3_result_zeroblob64(tls *libc.TLS, pCtx uintptr, n Tu64) (r int32) {
|
|
var pOut uintptr
|
|
_ = pOut
|
|
pOut = (*Tsqlite3_context)(unsafe.Pointer(pCtx)).FpOut
|
|
if n > libc.Uint64FromInt32(**(**int32)(__ccgo_up((*TMem)(unsafe.Pointer(pOut)).Fdb + 136))) {
|
|
Xsqlite3_result_error_toobig(tls, pCtx)
|
|
return int32(SQLITE_TOOBIG)
|
|
}
|
|
_sqlite3VdbeMemSetZeroBlob(tls, (*Tsqlite3_context)(unsafe.Pointer(pCtx)).FpOut, libc.Int32FromUint64(n))
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Obtain a snapshot handle for the snapshot of database zDb currently
|
|
// ** being read by handle db.
|
|
// */
|
|
func Xsqlite3_snapshot_get(tls *libc.TLS, db uintptr, zDb uintptr, ppSnapshot uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iDb, rc int32
|
|
var pBt, pPager uintptr
|
|
var _ /* dummy at bp+0 */ Ti64
|
|
_, _, _, _ = iDb, pBt, pPager, rc
|
|
rc = int32(SQLITE_ERROR)
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
if libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).FautoCommit) == 0 {
|
|
iDb = _sqlite3FindDbName(tls, db, zDb)
|
|
if iDb == 0 || iDb > int32(1) {
|
|
pBt = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(iDb)*32))).FpBt
|
|
if int32(SQLITE_TXN_WRITE) != _sqlite3BtreeTxnState(tls, pBt) {
|
|
pPager = _sqlite3BtreePager(tls, pBt)
|
|
**(**Ti64)(__ccgo_up(bp)) = 0
|
|
_sqlite3PagerSnapshotOpen(tls, pPager, bp)
|
|
rc = _sqlite3BtreeBeginTrans(tls, pBt, 0, uintptr(0))
|
|
_sqlite3PagerSnapshotOpen(tls, pPager, uintptr(0))
|
|
if rc == SQLITE_OK {
|
|
rc = _sqlite3PagerSnapshotGet(tls, _sqlite3BtreePager(tls, pBt), ppSnapshot)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Open a read-transaction on the snapshot identified by pSnapshot.
|
|
// */
|
|
func Xsqlite3_snapshot_open(tls *libc.TLS, db uintptr, zDb uintptr, pSnapshot uintptr) (r int32) {
|
|
var bUnlock, iDb, rc int32
|
|
var pBt, pPager uintptr
|
|
_, _, _, _, _ = bUnlock, iDb, pBt, pPager, rc
|
|
rc = int32(SQLITE_ERROR)
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
if libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).FautoCommit) == 0 {
|
|
iDb = _sqlite3FindDbName(tls, db, zDb)
|
|
if iDb == 0 || iDb > int32(1) {
|
|
pBt = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(iDb)*32))).FpBt
|
|
if _sqlite3BtreeTxnState(tls, pBt) != int32(SQLITE_TXN_WRITE) {
|
|
pPager = _sqlite3BtreePager(tls, pBt)
|
|
bUnlock = 0
|
|
if _sqlite3BtreeTxnState(tls, pBt) != SQLITE_TXN_NONE {
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FnVdbeActive == 0 {
|
|
rc = _sqlite3PagerSnapshotCheck(tls, pPager, pSnapshot)
|
|
if rc == SQLITE_OK {
|
|
bUnlock = int32(1)
|
|
rc = _sqlite3BtreeCommit(tls, pBt)
|
|
}
|
|
}
|
|
} else {
|
|
rc = SQLITE_OK
|
|
}
|
|
if rc == SQLITE_OK {
|
|
rc = _sqlite3PagerSnapshotOpen(tls, pPager, pSnapshot)
|
|
}
|
|
if rc == SQLITE_OK {
|
|
rc = _sqlite3BtreeBeginTrans(tls, pBt, 0, uintptr(0))
|
|
_sqlite3PagerSnapshotOpen(tls, pPager, uintptr(0))
|
|
}
|
|
if bUnlock != 0 {
|
|
_sqlite3PagerSnapshotUnlock(tls, pPager)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Query status information.
|
|
// */
|
|
func Xsqlite3_status64(tls *libc.TLS, op int32, pCurrent uintptr, pHighwater uintptr, resetFlag int32) (r int32) {
|
|
var pMutex, v1 uintptr
|
|
_, _ = pMutex, v1
|
|
if op < 0 || op >= libc.Int32FromUint64(libc.Uint64FromInt64(80)/libc.Uint64FromInt64(8)) {
|
|
return _sqlite3MisuseError(tls, int32(25154))
|
|
}
|
|
if _statMutex[op] != 0 {
|
|
v1 = _sqlite3Pcache1Mutex(tls)
|
|
} else {
|
|
v1 = _sqlite3MallocMutex(tls)
|
|
}
|
|
pMutex = v1
|
|
Xsqlite3_mutex_enter(tls, pMutex)
|
|
**(**Tsqlite3_int64)(__ccgo_up(pCurrent)) = **(**Tsqlite3StatValueType)(__ccgo_up(uintptr(unsafe.Pointer(&_sqlite3Stat)) + uintptr(op)*8))
|
|
**(**Tsqlite3_int64)(__ccgo_up(pHighwater)) = **(**Tsqlite3StatValueType)(__ccgo_up(uintptr(unsafe.Pointer(&_sqlite3Stat)) + 80 + uintptr(op)*8))
|
|
if resetFlag != 0 {
|
|
**(**Tsqlite3StatValueType)(__ccgo_up(uintptr(unsafe.Pointer(&_sqlite3Stat)) + 80 + uintptr(op)*8)) = **(**Tsqlite3StatValueType)(__ccgo_up(uintptr(unsafe.Pointer(&_sqlite3Stat)) + uintptr(op)*8))
|
|
}
|
|
Xsqlite3_mutex_leave(tls, pMutex)
|
|
_ = pMutex /* Prevent warning when SQLITE_THREADSAFE=0 */
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the explain mode for a statement.
|
|
// */
|
|
func Xsqlite3_stmt_explain(tls *libc.TLS, pStmt uintptr, eMode int32) (r int32) {
|
|
var rc int32
|
|
var v uintptr
|
|
_, _ = rc, v
|
|
v = pStmt
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer((*TVdbe)(unsafe.Pointer(v)).Fdb)).Fmutex)
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(v + 200))&0xc>>2)) == eMode {
|
|
rc = SQLITE_OK
|
|
} else {
|
|
if eMode < 0 || eMode > int32(2) {
|
|
rc = int32(SQLITE_ERROR)
|
|
} else {
|
|
if libc.Int32FromUint8((*TVdbe)(unsafe.Pointer(v)).FprepFlags)&int32(SQLITE_PREPARE_SAVESQL) == 0 {
|
|
rc = int32(SQLITE_ERROR)
|
|
} else {
|
|
if libc.Int32FromUint8((*TVdbe)(unsafe.Pointer(v)).FeVdbeState) != int32(VDBE_READY_STATE) {
|
|
rc = int32(SQLITE_BUSY)
|
|
} else {
|
|
if (*TVdbe)(unsafe.Pointer(v)).FnMem >= int32(10) && (eMode != int32(2) || int32(Tbft(*(*uint16)(unsafe.Pointer(v + 200))&0x100>>8)) != 0) {
|
|
/* No reprepare necessary */
|
|
libc.SetBitFieldPtr16Uint32(v+200, libc.Uint32FromInt32(eMode), 2, 0xc)
|
|
rc = SQLITE_OK
|
|
} else {
|
|
libc.SetBitFieldPtr16Uint32(v+200, libc.Uint32FromInt32(eMode), 2, 0xc)
|
|
rc = _sqlite3Reprepare(tls, v)
|
|
libc.SetBitFieldPtr16Uint32(v+200, libc.BoolUint32(eMode == libc.Int32FromInt32(2)), 8, 0x100)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(v + 200))&0xc>>2)) != 0 {
|
|
(*TVdbe)(unsafe.Pointer(v)).FnResColumn = libc.Uint16FromInt32(int32(12) - int32(4)*int32(Tbft(*(*uint16)(unsafe.Pointer(v + 200))&0xc>>2)))
|
|
} else {
|
|
(*TVdbe)(unsafe.Pointer(v)).FnResColumn = (*TVdbe)(unsafe.Pointer(v)).FnResAlloc
|
|
}
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer((*TVdbe)(unsafe.Pointer(v)).Fdb)).Fmutex)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the value of a status counter for a prepared statement
|
|
// */
|
|
func Xsqlite3_stmt_status(tls *libc.TLS, pStmt uintptr, op int32, resetFlag int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var db, pVdbe uintptr
|
|
var _ /* v at bp+0 */ Tu32
|
|
_, _ = db, pVdbe
|
|
pVdbe = pStmt
|
|
if op == int32(SQLITE_STMTSTATUS_MEMUSED) {
|
|
db = (*TVdbe)(unsafe.Pointer(pVdbe)).Fdb
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(0)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FpnBytesFreed = bp
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpEnd = (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpStart
|
|
_sqlite3VdbeDelete(tls, pVdbe)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FpnBytesFreed = uintptr(0)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpEnd = (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpTrueEnd
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
} else {
|
|
**(**Tu32)(__ccgo_up(bp)) = **(**Tu32)(__ccgo_up(pVdbe + 212 + uintptr(op)*4))
|
|
if resetFlag != 0 {
|
|
**(**Tu32)(__ccgo_up(pVdbe + 212 + uintptr(op)*4)) = uint32(0)
|
|
}
|
|
}
|
|
return libc.Int32FromUint32(**(**Tu32)(__ccgo_up(bp)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Reset an StrAccum string. Reclaim all malloced memory.
|
|
// */
|
|
func Xsqlite3_str_reset(tls *libc.TLS, p uintptr) {
|
|
var v1 uintptr
|
|
_ = v1
|
|
if libc.Int32FromUint8((*TStrAccum)(unsafe.Pointer(p)).FprintfFlags)&int32(SQLITE_PRINTF_MALLOCED) != 0 {
|
|
_sqlite3DbFree(tls, (*TStrAccum)(unsafe.Pointer(p)).Fdb, (*TStrAccum)(unsafe.Pointer(p)).FzText)
|
|
v1 = p + 29
|
|
*(*Tu8)(unsafe.Pointer(v1)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v1))) & ^libc.Int32FromInt32(SQLITE_PRINTF_MALLOCED))
|
|
}
|
|
(*TStrAccum)(unsafe.Pointer(p)).FnAlloc = uint32(0)
|
|
(*TStrAccum)(unsafe.Pointer(p)).FnChar = uint32(0)
|
|
(*TStrAccum)(unsafe.Pointer(p)).FzText = uintptr(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Interface to the testing logic.
|
|
// */
|
|
func Xsqlite3_test_control(tls *libc.TLS, op int32, va uintptr) (r int32) {
|
|
var aProg, db, db1, db2, db3, db4, db5, db6, db7, pCtx, pI1, pI2, pN, pR, pU64, pn, ptr, xBenignBegin, xBenignEnd, z uintptr
|
|
var ap Tva_list
|
|
var b, iDb, opTrace, rc, sz, x, x1, x2, y, v1 int32
|
|
var newVal uint32
|
|
var rIn float64
|
|
var rLogEst TLogEst
|
|
var v2 bool
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = aProg, ap, b, db, db1, db2, db3, db4, db5, db6, db7, iDb, newVal, opTrace, pCtx, pI1, pI2, pN, pR, pU64, pn, ptr, rIn, rLogEst, rc, sz, x, x1, x2, xBenignBegin, xBenignEnd, y, z, v1, v2
|
|
rc = 0
|
|
ap = va
|
|
switch op {
|
|
/*
|
|
** Save the current state of the PRNG.
|
|
*/
|
|
case int32(SQLITE_TESTCTRL_PRNG_SAVE):
|
|
_sqlite3PrngSaveState(tls)
|
|
break
|
|
/*
|
|
** Restore the state of the PRNG to the last state saved using
|
|
** PRNG_SAVE. If PRNG_SAVE has never before been called, then
|
|
** this verb acts like PRNG_RESET.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_PRNG_RESTORE):
|
|
_sqlite3PrngRestoreState(tls)
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SEED, int x, sqlite3 *db);
|
|
**
|
|
** Control the seed for the pseudo-random number generator (PRNG) that
|
|
** is built into SQLite. Cases:
|
|
**
|
|
** x!=0 && db!=0 Seed the PRNG to the current value of the
|
|
** schema cookie in the main database for db, or
|
|
** x if the schema cookie is zero. This case
|
|
** is convenient to use with database fuzzers
|
|
** as it allows the fuzzer some control over the
|
|
** the PRNG seed.
|
|
**
|
|
** x!=0 && db==0 Seed the PRNG to the value of x.
|
|
**
|
|
** x==0 && db==0 Revert to default behavior of using the
|
|
** xRandomness method on the primary VFS.
|
|
**
|
|
** This test-control also resets the PRNG so that the new seed will
|
|
** be used for the next call to sqlite3_randomness().
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_PRNG_SEED):
|
|
x = libc.VaInt32(&ap)
|
|
db = libc.VaUintptr(&ap)
|
|
if v2 = db != 0; v2 {
|
|
v1 = (*TSchema)(unsafe.Pointer((**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb))).FpSchema)).Fschema_cookie
|
|
y = v1
|
|
}
|
|
if v2 && v1 != 0 {
|
|
x = y
|
|
}
|
|
_sqlite3Config.FiPrngSeed = libc.Uint32FromInt32(x)
|
|
Xsqlite3_randomness(tls, 0, uintptr(0))
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_FK_NO_ACTION, sqlite3 *db, int b);
|
|
**
|
|
** If b is true, then activate the SQLITE_FkNoAction setting. If b is
|
|
** false then clear that setting. If the SQLITE_FkNoAction setting is
|
|
** enabled, all foreign key ON DELETE and ON UPDATE actions behave as if
|
|
** they were NO ACTION, regardless of how they are defined.
|
|
**
|
|
** NB: One must usually run "PRAGMA writable_schema=RESET" after
|
|
** using this test-control, before it will take full effect. failing
|
|
** to reset the schema can result in some unexpected behavior.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_FK_NO_ACTION):
|
|
db1 = libc.VaUintptr(&ap)
|
|
b = libc.VaInt32(&ap)
|
|
if b != 0 {
|
|
**(**Tu64)(__ccgo_up(db1 + 48)) |= libc.Uint64FromInt32(libc.Int32FromInt32(0x00008)) << libc.Int32FromInt32(32)
|
|
} else {
|
|
**(**Tu64)(__ccgo_up(db1 + 48)) &= ^(libc.Uint64FromInt32(libc.Int32FromInt32(0x00008)) << libc.Int32FromInt32(32))
|
|
}
|
|
break
|
|
/*
|
|
** sqlite3_test_control(BITVEC_TEST, size, program)
|
|
**
|
|
** Run a test against a Bitvec object of size. The program argument
|
|
** is an array of integers that defines the test. Return -1 on a
|
|
** memory allocation error, 0 on success, or non-zero for an error.
|
|
** See the sqlite3BitvecBuiltinTest() for additional information.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_BITVEC_TEST):
|
|
sz = libc.VaInt32(&ap)
|
|
aProg = libc.VaUintptr(&ap)
|
|
rc = _sqlite3BitvecBuiltinTest(tls, sz, aProg)
|
|
break
|
|
/*
|
|
** sqlite3_test_control(FAULT_INSTALL, xCallback)
|
|
**
|
|
** Arrange to invoke xCallback() whenever sqlite3FaultSim() is called,
|
|
** if xCallback is not NULL.
|
|
**
|
|
** As a test of the fault simulator mechanism itself, sqlite3FaultSim(0)
|
|
** is called immediately after installing the new callback and the return
|
|
** value from sqlite3FaultSim(0) becomes the return from
|
|
** sqlite3_test_control().
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_FAULT_INSTALL):
|
|
_sqlite3Config.FxTestCallback = libc.VaUintptr(&ap)
|
|
rc = _sqlite3FaultSim(tls, 0)
|
|
break
|
|
/*
|
|
** sqlite3_test_control(BENIGN_MALLOC_HOOKS, xBegin, xEnd)
|
|
**
|
|
** Register hooks to call to indicate which malloc() failures
|
|
** are benign.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS):
|
|
xBenignBegin = libc.VaUintptr(&ap)
|
|
xBenignEnd = libc.VaUintptr(&ap)
|
|
_sqlite3BenignMallocHooks(tls, xBenignBegin, xBenignEnd)
|
|
break
|
|
/*
|
|
** sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE, unsigned int X)
|
|
**
|
|
** Set the PENDING byte to the value in the argument, if X>0.
|
|
** Make no changes if X==0. Return the value of the pending byte
|
|
** as it existing before this routine was called.
|
|
**
|
|
** IMPORTANT: Changing the PENDING byte from 0x40000000 results in
|
|
** an incompatible database file format. Changing the PENDING byte
|
|
** while any database connection is open results in undefined and
|
|
** deleterious behavior.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_PENDING_BYTE):
|
|
rc = _sqlite3PendingByte
|
|
newVal = libc.VaUint32(&ap)
|
|
if newVal != 0 {
|
|
_sqlite3PendingByte = libc.Int32FromUint32(newVal)
|
|
}
|
|
break
|
|
/*
|
|
** sqlite3_test_control(SQLITE_TESTCTRL_ASSERT, int X)
|
|
**
|
|
** This action provides a run-time test to see whether or not
|
|
** assert() was enabled at compile-time. If X is true and assert()
|
|
** is enabled, then the return value is true. If X is true and
|
|
** assert() is disabled, then the return value is zero. If X is
|
|
** false and assert() is enabled, then the assertion fires and the
|
|
** process aborts. If X is false and assert() is disabled, then the
|
|
** return value is zero.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_ASSERT):
|
|
x1 = 0
|
|
rc = x1
|
|
break
|
|
/*
|
|
** sqlite3_test_control(SQLITE_TESTCTRL_ALWAYS, int X)
|
|
**
|
|
** This action provides a run-time test to see how the ALWAYS and
|
|
** NEVER macros were defined at compile-time.
|
|
**
|
|
** The return value is ALWAYS(X) if X is true, or 0 if X is false.
|
|
**
|
|
** The recommended test is X==2. If the return value is 2, that means
|
|
** ALWAYS() and NEVER() are both no-op pass-through macros, which is the
|
|
** default setting. If the return value is 1, then ALWAYS() is either
|
|
** hard-coded to true or else it asserts if its argument is false.
|
|
** The first behavior (hard-coded to true) is the case if
|
|
** SQLITE_TESTCTRL_ASSERT shows that assert() is disabled and the second
|
|
** behavior (assert if the argument to ALWAYS() is false) is the case if
|
|
** SQLITE_TESTCTRL_ASSERT shows that assert() is enabled.
|
|
**
|
|
** The run-time test procedure might look something like this:
|
|
**
|
|
** if( sqlite3_test_control(SQLITE_TESTCTRL_ALWAYS, 2)==2 ){
|
|
** // ALWAYS() and NEVER() are no-op pass-through macros
|
|
** }else if( sqlite3_test_control(SQLITE_TESTCTRL_ASSERT, 1) ){
|
|
** // ALWAYS(x) asserts that x is true. NEVER(x) asserts x is false.
|
|
** }else{
|
|
** // ALWAYS(x) is a constant 1. NEVER(x) is a constant 0.
|
|
** }
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_ALWAYS):
|
|
x2 = libc.VaInt32(&ap)
|
|
if x2 != 0 {
|
|
v1 = x2
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
rc = v1
|
|
break
|
|
/*
|
|
** sqlite3_test_control(SQLITE_TESTCTRL_BYTEORDER);
|
|
**
|
|
** The integer returned reveals the byte-order of the computer on which
|
|
** SQLite is running:
|
|
**
|
|
** 1 big-endian, determined at run-time
|
|
** 10 little-endian, determined at run-time
|
|
** 432101 big-endian, determined at compile-time
|
|
** 123410 little-endian, determined at compile-time
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_BYTEORDER):
|
|
rc = libc.Int32FromInt32(SQLITE_BYTEORDER)*libc.Int32FromInt32(100) + libc.Int32FromInt32(SQLITE_LITTLEENDIAN)*libc.Int32FromInt32(10) + libc.Int32FromInt32(SQLITE_BIGENDIAN)
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, sqlite3 *db, int N)
|
|
**
|
|
** Enable or disable various optimizations for testing purposes. The
|
|
** argument N is a bitmask of optimizations to be disabled. For normal
|
|
** operation N should be 0. The idea is that a test program (like the
|
|
** SQL Logic Test or SLT test module) can run the same SQL multiple times
|
|
** with various optimizations disabled to verify that the same answer
|
|
** is obtained in every case.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_OPTIMIZATIONS):
|
|
db2 = libc.VaUintptr(&ap)
|
|
(*Tsqlite3)(unsafe.Pointer(db2)).FdbOptFlags = libc.VaUint32(&ap)
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_GETOPT, sqlite3 *db, int *N)
|
|
**
|
|
** Write the current optimization settings into *N. A zero bit means that
|
|
** the optimization is on, and a 1 bit means that the optimization is off.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_GETOPT):
|
|
db3 = libc.VaUintptr(&ap)
|
|
pN = libc.VaUintptr(&ap)
|
|
**(**int32)(__ccgo_up(pN)) = libc.Int32FromUint32((*Tsqlite3)(unsafe.Pointer(db3)).FdbOptFlags)
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, onoff, xAlt);
|
|
**
|
|
** If parameter onoff is 1, subsequent calls to localtime() fail.
|
|
** If 2, then invoke xAlt() instead of localtime(). If 0, normal
|
|
** processing.
|
|
**
|
|
** xAlt arguments are void pointers, but they really want to be:
|
|
**
|
|
** int xAlt(const time_t*, struct tm*);
|
|
**
|
|
** xAlt should write results in to struct tm object of its 2nd argument
|
|
** and return zero on success, or return non-zero on failure.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_LOCALTIME_FAULT):
|
|
_sqlite3Config.FbLocaltimeFault = libc.VaInt32(&ap)
|
|
if _sqlite3Config.FbLocaltimeFault == int32(2) {
|
|
_sqlite3Config.FxAltLocaltime = libc.VaUintptr(&ap)
|
|
} else {
|
|
_sqlite3Config.FxAltLocaltime = uintptr(0)
|
|
}
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, sqlite3*);
|
|
**
|
|
** Toggle the ability to use internal functions on or off for
|
|
** the database connection given in the argument.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_INTERNAL_FUNCTIONS):
|
|
db4 = libc.VaUintptr(&ap)
|
|
**(**Tu32)(__ccgo_up(db4 + 44)) ^= uint32(DBFLAG_InternalFunc)
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, int);
|
|
**
|
|
** Set or clear a flag that indicates that the database file is always well-
|
|
** formed and never corrupt. This flag is clear by default, indicating that
|
|
** database files might have arbitrary corruption. Setting the flag during
|
|
** testing causes certain assert() statements in the code to be activated
|
|
** that demonstrate invariants on well-formed database files.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_NEVER_CORRUPT):
|
|
_sqlite3Config.FneverCorrupt = libc.VaInt32(&ap)
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS, int);
|
|
**
|
|
** Set or clear a flag that causes SQLite to verify that type, name,
|
|
** and tbl_name fields of the sqlite_schema table. This is normally
|
|
** on, but it is sometimes useful to turn it off for testing.
|
|
**
|
|
** 2020-07-22: Disabling EXTRA_SCHEMA_CHECKS also disables the
|
|
** verification of rootpage numbers when parsing the schema. This
|
|
** is useful to make it easier to reach strange internal error states
|
|
** during testing. The EXTRA_SCHEMA_CHECKS setting is always enabled
|
|
** in production.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS):
|
|
_sqlite3Config.FbExtraSchemaChecks = libc.Uint8FromInt32(libc.VaInt32(&ap))
|
|
break
|
|
/* Set the threshold at which OP_Once counters reset back to zero.
|
|
** By default this is 0x7ffffffe (over 2 billion), but that value is
|
|
** too big to test in a reasonable amount of time, so this control is
|
|
** provided to set a small and easily reachable reset value.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD):
|
|
_sqlite3Config.FiOnceResetThreshold = libc.VaInt32(&ap)
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, xCallback, ptr);
|
|
**
|
|
** Set the VDBE coverage callback function to xCallback with context
|
|
** pointer ptr.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_VDBE_COVERAGE):
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, nMax); */
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_SORTER_MMAP):
|
|
db5 = libc.VaUintptr(&ap)
|
|
(*Tsqlite3)(unsafe.Pointer(db5)).FnMaxSorterMmap = libc.VaInt32(&ap)
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_ISINIT);
|
|
**
|
|
** Return SQLITE_OK if SQLite has been initialized and SQLITE_ERROR if
|
|
** not.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_ISINIT):
|
|
if libc.AtomicLoadPInt32(uintptr(unsafe.Pointer(&_sqlite3Config))+340) == 0 {
|
|
rc = int32(SQLITE_ERROR)
|
|
}
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, mode, tnum);
|
|
**
|
|
** This test control is used to create imposter tables. "db" is a pointer
|
|
** to the database connection. dbName is the database name (ex: "main" or
|
|
** "temp") which will receive the imposter. "mode" turns imposter mode on
|
|
** or off. mode==0 means imposter mode is off. mode==1 means imposter mode
|
|
** is on. mode==2 means imposter mode is on but results in an imposter
|
|
** table that is read-only unless writable_schema is on. "tnum" is the
|
|
** root page of the b-tree to which the imposter table should connect.
|
|
**
|
|
** Enable imposter mode only when the schema has already been parsed. Then
|
|
** run a single CREATE TABLE statement to construct the imposter table in
|
|
** the parsed schema. Then turn imposter mode back off again.
|
|
**
|
|
** If onOff==0 and tnum>0 then reset the schema for all databases, causing
|
|
** the schema to be reparsed the next time it is needed. This has the
|
|
** effect of erasing all imposter tables.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_IMPOSTER):
|
|
db6 = libc.VaUintptr(&ap)
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer(db6)).Fmutex)
|
|
iDb = _sqlite3FindDbName(tls, db6, libc.VaUintptr(&ap))
|
|
if iDb >= 0 {
|
|
(*Tsqlite3)(unsafe.Pointer(db6)).Finit1.FiDb = libc.Uint8FromInt32(iDb)
|
|
(*Tsqlite3)(unsafe.Pointer(db6)).Finit1.Fbusy = uint8(libc.AssignBitFieldPtr8Uint32(db6+192+8, libc.Uint32FromInt32(libc.VaInt32(&ap)), 2, 1, 0x6))
|
|
(*Tsqlite3)(unsafe.Pointer(db6)).Finit1.FnewTnum = libc.Uint32FromInt32(libc.VaInt32(&ap))
|
|
if libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db6)).Finit1.Fbusy) == 0 && (*Tsqlite3)(unsafe.Pointer(db6)).Finit1.FnewTnum > uint32(0) {
|
|
_sqlite3ResetAllSchemasOfConnection(tls, db6)
|
|
}
|
|
}
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer(db6)).Fmutex)
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_RESULT_INTREAL, sqlite3_context*);
|
|
**
|
|
** This test-control causes the most recent sqlite3_result_int64() value
|
|
** to be interpreted as a MEM_IntReal instead of as an MEM_Int. Normally,
|
|
** MEM_IntReal values only arise during an INSERT operation of integer
|
|
** values into a REAL column, so they can be challenging to test. This
|
|
** test-control enables us to write an intreal() SQL function that can
|
|
** inject an intreal() value at arbitrary places in an SQL statement,
|
|
** for testing purposes.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_RESULT_INTREAL):
|
|
pCtx = libc.VaUintptr(&ap)
|
|
_sqlite3ResultIntReal(tls, pCtx)
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_SEEK_COUNT,
|
|
** sqlite3 *db, // Database connection
|
|
** u64 *pnSeek // Write seek count here
|
|
** );
|
|
**
|
|
** This test-control queries the seek-counter on the "main" database
|
|
** file. The seek-counter is written into *pnSeek and is then reset.
|
|
** The seek-count is only available if compiled with SQLITE_DEBUG.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_SEEK_COUNT):
|
|
db7 = libc.VaUintptr(&ap)
|
|
pn = libc.VaUintptr(&ap)
|
|
**(**Tu64)(__ccgo_up(pn)) = uint64(0)
|
|
_ = db7 /* Silence harmless unused variable warning */
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, op, ptr)
|
|
**
|
|
** "ptr" is a pointer to a u32.
|
|
**
|
|
** op==0 Store the current sqlite3TreeTrace in *ptr
|
|
** op==1 Set sqlite3TreeTrace to the value *ptr
|
|
** op==2 Store the current sqlite3WhereTrace in *ptr
|
|
** op==3 Set sqlite3WhereTrace to the value *ptr
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_TRACEFLAGS):
|
|
opTrace = libc.VaInt32(&ap)
|
|
ptr = libc.VaUintptr(&ap)
|
|
switch opTrace {
|
|
case 0:
|
|
**(**Tu32)(__ccgo_up(ptr)) = _sqlite3TreeTrace
|
|
case int32(1):
|
|
_sqlite3TreeTrace = **(**Tu32)(__ccgo_up(ptr))
|
|
case int32(2):
|
|
**(**Tu32)(__ccgo_up(ptr)) = _sqlite3WhereTrace
|
|
case int32(3):
|
|
_sqlite3WhereTrace = **(**Tu32)(__ccgo_up(ptr))
|
|
break
|
|
}
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_LOGEST,
|
|
** double fIn, // Input value
|
|
** int *pLogEst, // sqlite3LogEstFromDouble(fIn)
|
|
** u64 *pInt, // sqlite3LogEstToInt(*pLogEst)
|
|
** int *pLogEst2 // sqlite3LogEst(*pInt)
|
|
** );
|
|
**
|
|
** Test access for the LogEst conversion routines.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_LOGEST):
|
|
rIn = libc.VaFloat64(&ap)
|
|
rLogEst = _sqlite3LogEstFromDouble(tls, rIn)
|
|
pI1 = libc.VaUintptr(&ap)
|
|
pU64 = libc.VaUintptr(&ap)
|
|
pI2 = libc.VaUintptr(&ap)
|
|
**(**int32)(__ccgo_up(pI1)) = int32(rLogEst)
|
|
**(**Tu64)(__ccgo_up(pU64)) = _sqlite3LogEstToInt(tls, rLogEst)
|
|
**(**int32)(__ccgo_up(pI2)) = int32(_sqlite3LogEst(tls, **(**Tu64)(__ccgo_up(pU64))))
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_ATOF, const char *z, double *p);
|
|
**
|
|
** Test access to the sqlite3AtoF() routine.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_ATOF):
|
|
z = libc.VaUintptr(&ap)
|
|
pR = libc.VaUintptr(&ap)
|
|
rc = _sqlite3AtoF(tls, z, pR)
|
|
break
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_JSON_SELFCHECK, &onOff);
|
|
**
|
|
** Activate or deactivate validation of JSONB that is generated from
|
|
** text. Off by default, as the validation is slow. Validation is
|
|
** only available if compiled using SQLITE_DEBUG.
|
|
**
|
|
** If onOff is initially 1, then turn it on. If onOff is initially
|
|
** off, turn it off. If onOff is initially -1, then change onOff
|
|
** to be the current setting.
|
|
*/
|
|
fallthrough
|
|
case int32(SQLITE_TESTCTRL_JSON_SELFCHECK):
|
|
break
|
|
}
|
|
_ = ap
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Register a trace function. The pArg from the previously registered trace
|
|
// ** is returned.
|
|
// **
|
|
// ** A NULL trace function means that no tracing is executes. A non-NULL
|
|
// ** trace is a pointer to a function that is invoked at the start of each
|
|
// ** SQL statement.
|
|
// */
|
|
func Xsqlite3_trace(tls *libc.TLS, db uintptr, __ccgo_fp_xTrace uintptr, pArg uintptr) (r uintptr) {
|
|
var pOld uintptr
|
|
var v1 int32
|
|
_, _ = pOld, v1
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
pOld = (*Tsqlite3)(unsafe.Pointer(db)).FpTraceArg
|
|
if __ccgo_fp_xTrace != 0 {
|
|
v1 = int32(SQLITE_TRACE_LEGACY)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FmTrace = libc.Uint8FromInt32(v1)
|
|
*(*uintptr)(unsafe.Pointer(db + 248)) = __ccgo_fp_xTrace
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FpTraceArg = pArg
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
return pOld
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /**************************** sqlite3_value_ *******************************
|
|
// ** The following routines extract information from a Mem or sqlite3_value
|
|
// ** structure.
|
|
// */
|
|
func Xsqlite3_value_blob(tls *libc.TLS, pVal uintptr) (r uintptr) {
|
|
var p, v2 uintptr
|
|
var v1 int32
|
|
_, _, _ = p, v1, v2
|
|
p = pVal
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&(libc.Int32FromInt32(MEM_Blob)|libc.Int32FromInt32(MEM_Str)) != 0 {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&int32(MEM_Zero) != 0 {
|
|
v1 = _sqlite3VdbeMemExpandBlob(tls, p)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
if v1 != SQLITE_OK {
|
|
return uintptr(0)
|
|
}
|
|
v2 = p + 20
|
|
*(*Tu16)(unsafe.Pointer(v2)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v2))) | libc.Int32FromInt32(MEM_Blob))
|
|
if (*TMem)(unsafe.Pointer(p)).Fn != 0 {
|
|
v2 = (*TMem)(unsafe.Pointer(p)).Fz
|
|
} else {
|
|
v2 = uintptr(0)
|
|
}
|
|
return v2
|
|
} else {
|
|
return Xsqlite3_value_text(tls, pVal)
|
|
}
|
|
return r
|
|
}
|
|
|
|
func Xsqlite3_value_pointer(tls *libc.TLS, pVal uintptr, zPType uintptr) (r uintptr) {
|
|
var p uintptr
|
|
_ = p
|
|
p = pVal
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&(libc.Int32FromInt32(MEM_TypeMask)|libc.Int32FromInt32(MEM_Term)|libc.Int32FromInt32(MEM_Subtype)) == libc.Int32FromInt32(MEM_Null)|libc.Int32FromInt32(MEM_Term)|libc.Int32FromInt32(MEM_Subtype) && zPType != uintptr(0) && libc.Int32FromUint8((*TMem)(unsafe.Pointer(p)).FeSubtype) == int32('p') && libc.Xstrcmp(tls, *(*uintptr)(unsafe.Pointer(p)), zPType) == 0 {
|
|
return (*TMem)(unsafe.Pointer(p)).Fz
|
|
} else {
|
|
return uintptr(0)
|
|
}
|
|
return r
|
|
}
|
|
|
|
const _LP64 = 1
|
|
|
|
const __LONG_MAX__ = 9223372036854775807
|
|
|
|
const __LONG_WIDTH__ = 64
|
|
|
|
const __LP64__ = 1
|
|
|
|
const __SIZEOF_LONG__ = 8
|
|
|
|
func _addOp4IntSlow(tls *libc.TLS, p uintptr, op int32, p1 int32, p2 int32, p3 int32, p4 int32) (r int32) {
|
|
var addr int32
|
|
var pOp uintptr
|
|
_, _ = addr, pOp
|
|
addr = _sqlite3VdbeAddOp3(tls, p, op, p1, p2, p3)
|
|
if libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer((*TVdbe)(unsafe.Pointer(p)).Fdb)).FmallocFailed) == 0 {
|
|
pOp = (*TVdbe)(unsafe.Pointer(p)).FaOp + uintptr(addr)*24
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp4type = int8(-libc.Int32FromInt32(3))
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp4.Fi = p4
|
|
}
|
|
return addr
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The pOrderBy->a[].u.x.iOrderByCol values might be incorrect because
|
|
// ** columns might have been rearranged in the result set. This routine
|
|
// ** fixes them up.
|
|
// **
|
|
// ** pEList is the new result set. The pEList->a[].u.x.iOrderByCol values
|
|
// ** contain the *old* locations of each expression. This is a temporary
|
|
// ** use of u.x.iOrderByCol, not its intended use. The caller must reset
|
|
// ** u.x.iOrderByCol back to zero for all entries in pEList before the
|
|
// ** caller returns.
|
|
// **
|
|
// ** This routine changes pOrderBy->a[].u.x.iOrderByCol values from
|
|
// ** pEList->a[N].u.x.iOrderByCol into N+1. (The "+1" is because of the 1-based
|
|
// ** indexing used by iOrderByCol.) Or if no match, iOrderByCol is set to zero.
|
|
// */
|
|
func _adjustOrderByCol(tls *libc.TLS, pOrderBy uintptr, pEList uintptr) {
|
|
var i, j, t int32
|
|
_, _, _ = i, j, t
|
|
if pOrderBy == uintptr(0) {
|
|
return
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(pOrderBy)).FnExpr) {
|
|
break
|
|
}
|
|
t = libc.Int32FromUint16(*(*Tu16)(unsafe.Pointer(pOrderBy + 8 + uintptr(i)*32 + 24)))
|
|
if t == 0 {
|
|
goto _1
|
|
}
|
|
j = 0
|
|
for {
|
|
if !(j < (*TExprList)(unsafe.Pointer(pEList)).FnExpr) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint16(*(*Tu16)(unsafe.Pointer(pEList + 8 + uintptr(j)*32 + 24))) == t {
|
|
*(*Tu16)(unsafe.Pointer(pOrderBy + 8 + uintptr(i)*32 + 24)) = libc.Uint16FromInt32(j + int32(1))
|
|
break
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
j = j + 1
|
|
}
|
|
if j >= (*TExprList)(unsafe.Pointer(pEList)).FnExpr {
|
|
*(*Tu16)(unsafe.Pointer(pOrderBy + 8 + uintptr(i)*32 + 24)) = uint16(0)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is a Walker expression node callback.
|
|
// **
|
|
// ** For Expr nodes that contain pAggInfo pointers, make sure the AggInfo
|
|
// ** object that is referenced does not refer directly to the Expr. If
|
|
// ** it does, make a copy. This is done because the pExpr argument is
|
|
// ** subject to change.
|
|
// **
|
|
// ** The copy is scheduled for deletion using the sqlite3ExprDeferredDelete()
|
|
// ** which builds on the sqlite3ParserAddCleanup() mechanism.
|
|
// */
|
|
func _agginfoPersistExprCb(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var db, pAggInfo, pParse uintptr
|
|
var iAgg int32
|
|
_, _, _, _ = db, iAgg, pAggInfo, pParse
|
|
if !((*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_TokenOnly)|libc.Int32FromInt32(EP_Reduced)) != libc.Uint32FromInt32(0)) && (*TExpr)(unsafe.Pointer(pExpr)).FpAggInfo != uintptr(0) {
|
|
pAggInfo = (*TExpr)(unsafe.Pointer(pExpr)).FpAggInfo
|
|
iAgg = int32((*TExpr)(unsafe.Pointer(pExpr)).FiAgg)
|
|
pParse = (*TWalker)(unsafe.Pointer(pWalker)).FpParse
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) != int32(TK_AGG_FUNCTION) {
|
|
if iAgg < (*TAggInfo)(unsafe.Pointer(pAggInfo)).FnColumn && (**(**TAggInfo_col)(__ccgo_up((*TAggInfo)(unsafe.Pointer(pAggInfo)).FaCol + uintptr(iAgg)*32))).FpCExpr == pExpr {
|
|
pExpr = _sqlite3ExprDup(tls, db, pExpr, 0)
|
|
if pExpr != 0 && !(_sqlite3ExprDeferredDelete(tls, pParse, pExpr) != 0) {
|
|
(**(**TAggInfo_col)(__ccgo_up((*TAggInfo)(unsafe.Pointer(pAggInfo)).FaCol + uintptr(iAgg)*32))).FpCExpr = pExpr
|
|
}
|
|
}
|
|
} else {
|
|
if iAgg < (*TAggInfo)(unsafe.Pointer(pAggInfo)).FnFunc && (**(**TAggInfo_func)(__ccgo_up((*TAggInfo)(unsafe.Pointer(pAggInfo)).FaFunc + uintptr(iAgg)*32))).FpFExpr == pExpr {
|
|
pExpr = _sqlite3ExprDup(tls, db, pExpr, 0)
|
|
if pExpr != 0 && !(_sqlite3ExprDeferredDelete(tls, pParse, pExpr) != 0) {
|
|
(**(**TAggInfo_func)(__ccgo_up((*TAggInfo)(unsafe.Pointer(pAggInfo)).FaFunc + uintptr(iAgg)*32))).FpFExpr = pExpr
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Walker callback for aggregateConvertIndexedExprRefToColumn().
|
|
// */
|
|
func _aggregateIdxEprRefToColCallback(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var pAggInfo, pCol uintptr
|
|
_, _ = pAggInfo, pCol
|
|
_ = pWalker
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).FpAggInfo == uintptr(0) {
|
|
return WRC_Continue
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_AGG_COLUMN) {
|
|
return WRC_Continue
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_AGG_FUNCTION) {
|
|
return WRC_Continue
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_IF_NULL_ROW) {
|
|
return WRC_Continue
|
|
}
|
|
pAggInfo = (*TExpr)(unsafe.Pointer(pExpr)).FpAggInfo
|
|
if int32((*TExpr)(unsafe.Pointer(pExpr)).FiAgg) >= (*TAggInfo)(unsafe.Pointer(pAggInfo)).FnColumn {
|
|
return WRC_Continue
|
|
}
|
|
pCol = (*TAggInfo)(unsafe.Pointer(pAggInfo)).FaCol + uintptr((*TExpr)(unsafe.Pointer(pExpr)).FiAgg)*32
|
|
(*TExpr)(unsafe.Pointer(pExpr)).Fop = uint8(TK_AGG_COLUMN)
|
|
(*TExpr)(unsafe.Pointer(pExpr)).FiTable = (*TAggInfo_col)(unsafe.Pointer(pCol)).FiTable
|
|
(*TExpr)(unsafe.Pointer(pExpr)).FiColumn = int16((*TAggInfo_col)(unsafe.Pointer(pCol)).FiColumn)
|
|
**(**Tu32)(__ccgo_up(pExpr + 4)) &= ^libc.Uint32FromInt32(libc.Int32FromInt32(EP_Skip) | libc.Int32FromInt32(EP_Collate) | libc.Int32FromInt32(EP_Unlikely))
|
|
return int32(WRC_Prune)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate nByte bytes of space from within the B-Tree page passed
|
|
// ** as the first argument. Write into *pIdx the index into pPage->aData[]
|
|
// ** of the first byte of allocated space. Return either SQLITE_OK or
|
|
// ** an error code (usually SQLITE_CORRUPT).
|
|
// **
|
|
// ** The caller guarantees that there is sufficient space to make the
|
|
// ** allocation. This routine might need to defragment in order to bring
|
|
// ** all the space together, however. This routine will avoid using
|
|
// ** the first two bytes past the cell pointer area since presumably this
|
|
// ** allocation is being made in order to insert a new cell, so we will
|
|
// ** also end up needing a new cell pointer.
|
|
// */
|
|
func _allocateSpace(tls *libc.TLS, pPage uintptr, nByte int32, pIdx uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var data, pSpace, pTmp uintptr
|
|
var g2, gap, hdr, top, v1 int32
|
|
var _ /* rc at bp+0 */ int32
|
|
_, _, _, _, _, _, _, _ = data, g2, gap, hdr, pSpace, pTmp, top, v1
|
|
hdr = libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pPage)).FhdrOffset) /* Local cache of pPage->hdrOffset */
|
|
data = (*TMemPage)(unsafe.Pointer(pPage)).FaData /* First byte of cell content area */
|
|
**(**int32)(__ccgo_up(bp)) = SQLITE_OK /* First byte of gap between cell pointers and cell content */
|
|
/* Minimum cell size is 4 */
|
|
gap = libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FcellOffset) + int32(2)*libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell)
|
|
/* EVIDENCE-OF: R-29356-02391 If the database uses a 65536-byte page size
|
|
** and the reserved space is zero (the usual value for reserved space)
|
|
** then the cell content offset of an empty page wants to be 65536.
|
|
** However, that integer is too large to be stored in a 2-byte unsigned
|
|
** integer, so a value of 0 is used in its place. */
|
|
pTmp = data + uintptr(hdr+int32(5))
|
|
top = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pTmp)))<<int32(8) | libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pTmp + 1)))
|
|
if gap > top {
|
|
if top == 0 && (*TBtShared)(unsafe.Pointer((*TMemPage)(unsafe.Pointer(pPage)).FpBt)).FusableSize == uint32(65536) {
|
|
top = int32(65536)
|
|
} else {
|
|
return _sqlite3CorruptError(tls, int32(75075))
|
|
}
|
|
} else {
|
|
if top > libc.Int32FromUint32((*TBtShared)(unsafe.Pointer((*TMemPage)(unsafe.Pointer(pPage)).FpBt)).FusableSize) {
|
|
return _sqlite3CorruptError(tls, int32(75078))
|
|
}
|
|
}
|
|
/* If there is enough space between gap and top for one more cell pointer,
|
|
** and if the freelist is not empty, then search the
|
|
** freelist looking for a slot big enough to satisfy the request.
|
|
*/
|
|
if (**(**Tu8)(__ccgo_up(data + uintptr(hdr+int32(2)))) != 0 || **(**Tu8)(__ccgo_up(data + uintptr(hdr+int32(1)))) != 0) && gap+int32(2) <= top {
|
|
pSpace = _pageFindSlot(tls, pPage, nByte, bp)
|
|
if pSpace != 0 {
|
|
v1 = int32(int64(pSpace) - int64(data))
|
|
g2 = v1
|
|
**(**int32)(__ccgo_up(pIdx)) = v1
|
|
if g2 <= gap {
|
|
return _sqlite3CorruptError(tls, int32(75095))
|
|
} else {
|
|
return SQLITE_OK
|
|
}
|
|
} else {
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
}
|
|
}
|
|
/* The request could not be fulfilled using a freelist slot. Check
|
|
** to see if defragmentation is necessary.
|
|
*/
|
|
if gap+int32(2)+nByte > top {
|
|
if int32(4) < (*TMemPage)(unsafe.Pointer(pPage)).FnFree-(int32(2)+nByte) {
|
|
v1 = int32(4)
|
|
} else {
|
|
v1 = (*TMemPage)(unsafe.Pointer(pPage)).FnFree - (int32(2) + nByte)
|
|
}
|
|
**(**int32)(__ccgo_up(bp)) = _defragmentPage(tls, pPage, v1)
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
top = (libc.Int32FromUint8(**(**Tu8)(__ccgo_up(data + uintptr(hdr+int32(5)))))<<libc.Int32FromInt32(8)|libc.Int32FromUint8(**(**Tu8)(__ccgo_up(data + uintptr(hdr+int32(5)) + 1)))-int32(1))&int32(0xffff) + int32(1)
|
|
}
|
|
/* Allocate memory from the gap in between the cell pointer array
|
|
** and the cell content area. The btreeComputeFreeSpace() call has already
|
|
** validated the freelist. Given that the freelist is valid, there
|
|
** is no way that the allocation can extend off the end of the page.
|
|
** The assert() below verifies the previous sentence.
|
|
*/
|
|
top = top - nByte
|
|
**(**Tu8)(__ccgo_up(data + uintptr(hdr+int32(5)))) = libc.Uint8FromInt32(top >> libc.Int32FromInt32(8))
|
|
**(**Tu8)(__ccgo_up(data + uintptr(hdr+int32(5)) + 1)) = libc.Uint8FromInt32(top)
|
|
**(**int32)(__ccgo_up(pIdx)) = top
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This callback is invoked once for each index when reading the
|
|
// ** sqlite_stat1 table.
|
|
// **
|
|
// ** argv[0] = name of the table
|
|
// ** argv[1] = name of the index (might be NULL)
|
|
// ** argv[2] = results of analysis - on integer for each column
|
|
// **
|
|
// ** Entries for which argv[1]==NULL simply record the number of rows in
|
|
// ** the table.
|
|
// */
|
|
func _analysisLoader(tls *libc.TLS, pData uintptr, argc int32, argv uintptr, NotUsed uintptr) (r int32) {
|
|
bp := tls.Alloc(160)
|
|
defer tls.Free(160)
|
|
var aiRowEst, pIndex, pInfo, pTable, z uintptr
|
|
var nCol int32
|
|
var _ /* fakeIdx at bp+0 */ TIndex
|
|
_, _, _, _, _, _ = aiRowEst, nCol, pIndex, pInfo, pTable, z
|
|
pInfo = pData
|
|
_ = NotUsed
|
|
_ = argc
|
|
if argv == uintptr(0) || **(**uintptr)(__ccgo_up(argv)) == uintptr(0) || **(**uintptr)(__ccgo_up(argv + 2*8)) == uintptr(0) {
|
|
return 0
|
|
}
|
|
pTable = _sqlite3FindTable(tls, (*TanalysisInfo)(unsafe.Pointer(pInfo)).Fdb, **(**uintptr)(__ccgo_up(argv)), (*TanalysisInfo)(unsafe.Pointer(pInfo)).FzDatabase)
|
|
if pTable == uintptr(0) {
|
|
return 0
|
|
}
|
|
if **(**uintptr)(__ccgo_up(argv + 1*8)) == uintptr(0) {
|
|
pIndex = uintptr(0)
|
|
} else {
|
|
if Xsqlite3_stricmp(tls, **(**uintptr)(__ccgo_up(argv)), **(**uintptr)(__ccgo_up(argv + 1*8))) == 0 {
|
|
pIndex = _sqlite3PrimaryKeyIndex(tls, pTable)
|
|
} else {
|
|
pIndex = _sqlite3FindIndex(tls, (*TanalysisInfo)(unsafe.Pointer(pInfo)).Fdb, **(**uintptr)(__ccgo_up(argv + 1*8)), (*TanalysisInfo)(unsafe.Pointer(pInfo)).FzDatabase)
|
|
}
|
|
}
|
|
z = **(**uintptr)(__ccgo_up(argv + 2*8))
|
|
if pIndex != 0 {
|
|
aiRowEst = uintptr(0)
|
|
nCol = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIndex)).FnKeyCol) + int32(1)
|
|
/* Index.aiRowEst may already be set here if there are duplicate
|
|
** sqlite_stat1 entries for this index. In that case just clobber
|
|
** the old data with the new instead of allocating a new array. */
|
|
if (*TIndex)(unsafe.Pointer(pIndex)).FaiRowEst == uintptr(0) {
|
|
(*TIndex)(unsafe.Pointer(pIndex)).FaiRowEst = _sqlite3MallocZero(tls, uint64(uint64(8)*libc.Uint64FromInt32(nCol)))
|
|
if (*TIndex)(unsafe.Pointer(pIndex)).FaiRowEst == uintptr(0) {
|
|
_sqlite3OomFault(tls, (*TanalysisInfo)(unsafe.Pointer(pInfo)).Fdb)
|
|
}
|
|
}
|
|
aiRowEst = (*TIndex)(unsafe.Pointer(pIndex)).FaiRowEst
|
|
libc.SetBitFieldPtr16Uint32(pIndex+100, libc.Uint32FromInt32(0), 2, 0x4)
|
|
_decodeIntArray(tls, z, nCol, aiRowEst, (*TIndex)(unsafe.Pointer(pIndex)).FaiRowLogEst, pIndex)
|
|
libc.SetBitFieldPtr16Uint32(pIndex+100, libc.Uint32FromInt32(1), 7, 0x80)
|
|
if (*TIndex)(unsafe.Pointer(pIndex)).FpPartIdxWhere == uintptr(0) {
|
|
(*TTable)(unsafe.Pointer(pTable)).FnRowLogEst = **(**TLogEst)(__ccgo_up((*TIndex)(unsafe.Pointer(pIndex)).FaiRowLogEst))
|
|
**(**Tu32)(__ccgo_up(pTable + 48)) |= uint32(TF_HasStat1)
|
|
}
|
|
} else {
|
|
(**(**TIndex)(__ccgo_up(bp))).FszIdxRow = (*TTable)(unsafe.Pointer(pTable)).FszTabRow
|
|
_decodeIntArray(tls, z, int32(1), uintptr(0), pTable+58, bp)
|
|
(*TTable)(unsafe.Pointer(pTable)).FszTabRow = (**(**TIndex)(__ccgo_up(bp))).FszIdxRow
|
|
**(**Tu32)(__ccgo_up(pTable + 48)) |= uint32(TF_HasStat1)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Analyze the arguments to aggregate functions. Create new pAggInfo->aCol[]
|
|
// ** entries for columns that are arguments to aggregate functions but which
|
|
// ** are not otherwise used.
|
|
// **
|
|
// ** The aCol[] entries in AggInfo prior to nAccumulator are columns that
|
|
// ** are referenced outside of aggregate functions. These might be columns
|
|
// ** that are part of the GROUP by clause, for example. Other database engines
|
|
// ** would throw an error if there is a column reference that is not in the
|
|
// ** GROUP BY clause and that is not part of an aggregate function argument.
|
|
// ** But SQLite allows this.
|
|
// **
|
|
// ** The aCol[] entries beginning with the aCol[nAccumulator] and following
|
|
// ** are column references that are used exclusively as arguments to
|
|
// ** aggregate functions. This routine is responsible for computing
|
|
// ** (or recomputing) those aCol[] entries.
|
|
// */
|
|
func _analyzeAggFuncArgs(tls *libc.TLS, pAggInfo uintptr, pNC uintptr) {
|
|
var i int32
|
|
var pExpr uintptr
|
|
_, _ = i, pExpr
|
|
**(**int32)(__ccgo_up(pNC + 40)) |= int32(NC_InAggFunc)
|
|
i = 0
|
|
for {
|
|
if !(i < (*TAggInfo)(unsafe.Pointer(pAggInfo)).FnFunc) {
|
|
break
|
|
}
|
|
pExpr = (**(**TAggInfo_func)(__ccgo_up((*TAggInfo)(unsafe.Pointer(pAggInfo)).FaFunc + uintptr(i)*32))).FpFExpr
|
|
_sqlite3ExprAnalyzeAggList(tls, pNC, *(*uintptr)(unsafe.Pointer(pExpr + 32)))
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).FpLeft != 0 {
|
|
_sqlite3ExprAnalyzeAggList(tls, pNC, *(*uintptr)(unsafe.Pointer((*TExpr)(unsafe.Pointer(pExpr)).FpLeft + 32)))
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_WinFunc)) != uint32(0) {
|
|
_sqlite3ExprAnalyzeAggregates(tls, pNC, (*TWindow)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 64)))).FpFilter)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
**(**int32)(__ccgo_up(pNC + 40)) &= ^libc.Int32FromInt32(NC_InAggFunc)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Locate or create an AutoincInfo structure associated with table pTab
|
|
// ** which is in database iDb. Return the register number for the register
|
|
// ** that holds the maximum rowid. Return zero if pTab is not an AUTOINCREMENT
|
|
// ** table. (Also return zero when doing a VACUUM since we do not want to
|
|
// ** update the AUTOINCREMENT counters during a VACUUM.)
|
|
// **
|
|
// ** There is at most one AutoincInfo structure per table even if the
|
|
// ** same table is autoincremented multiple times due to inserts within
|
|
// ** triggers. A new AutoincInfo structure is created if this is the
|
|
// ** first use of table pTab. On 2nd and subsequent uses, the original
|
|
// ** AutoincInfo structure is used.
|
|
// **
|
|
// ** Four consecutive registers are allocated:
|
|
// **
|
|
// ** (1) The name of the pTab table.
|
|
// ** (2) The maximum ROWID of pTab.
|
|
// ** (3) The rowid in sqlite_sequence of pTab
|
|
// ** (4) The original value of the max ROWID in pTab, or NULL if none
|
|
// **
|
|
// ** The 2nd register is the one that is returned. That is all the
|
|
// ** insert routine needs to know about.
|
|
// */
|
|
func _autoIncBegin(tls *libc.TLS, pParse uintptr, iDb int32, pTab uintptr) (r int32) {
|
|
var memId, v2 int32
|
|
var pInfo, pSeqTab, pToplevel, v1 uintptr
|
|
_, _, _, _, _, _ = memId, pInfo, pSeqTab, pToplevel, v1, v2
|
|
memId = 0 /* Register holding maximum rowid */
|
|
if (*TTable)(unsafe.Pointer(pTab)).FtabFlags&uint32(TF_Autoincrement) != uint32(0) && (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).FmDbFlags&uint32(DBFLAG_Vacuum) == uint32(0) {
|
|
if (*TParse)(unsafe.Pointer(pParse)).FpToplevel != 0 {
|
|
v1 = (*TParse)(unsafe.Pointer(pParse)).FpToplevel
|
|
} else {
|
|
v1 = pParse
|
|
}
|
|
pToplevel = v1
|
|
pSeqTab = (*TSchema)(unsafe.Pointer((**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).FaDb + uintptr(iDb)*32))).FpSchema)).FpSeqTab
|
|
/* Verify that the sqlite_sequence table exists and is an ordinary
|
|
** rowid table with exactly two columns.
|
|
** Ticket d8dc2b3a58cd5dc2918a1d4acb 2018-05-23 */
|
|
if pSeqTab == uintptr(0) || !((*TTable)(unsafe.Pointer(pSeqTab)).FtabFlags&libc.Uint32FromInt32(TF_WithoutRowid) == libc.Uint32FromInt32(0)) || libc.Int32FromUint8((*TTable)(unsafe.Pointer(pSeqTab)).FeTabType) == int32(TABTYP_VTAB) || int32((*TTable)(unsafe.Pointer(pSeqTab)).FnCol) != int32(2) {
|
|
(*TParse)(unsafe.Pointer(pParse)).FnErr = (*TParse)(unsafe.Pointer(pParse)).FnErr + 1
|
|
(*TParse)(unsafe.Pointer(pParse)).Frc = libc.Int32FromInt32(SQLITE_CORRUPT) | libc.Int32FromInt32(2)<<libc.Int32FromInt32(8)
|
|
return 0
|
|
}
|
|
pInfo = (*TParse)(unsafe.Pointer(pToplevel)).FpAinc
|
|
for pInfo != 0 && (*TAutoincInfo)(unsafe.Pointer(pInfo)).FpTab != pTab {
|
|
pInfo = (*TAutoincInfo)(unsafe.Pointer(pInfo)).FpNext
|
|
}
|
|
if pInfo == uintptr(0) {
|
|
pInfo = _sqlite3DbMallocRawNN(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, uint64(24))
|
|
_sqlite3ParserAddCleanup(tls, pToplevel, __ccgo_fp(_sqlite3DbFree), pInfo)
|
|
if (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).FmallocFailed != 0 {
|
|
return 0
|
|
}
|
|
(*TAutoincInfo)(unsafe.Pointer(pInfo)).FpNext = (*TParse)(unsafe.Pointer(pToplevel)).FpAinc
|
|
(*TParse)(unsafe.Pointer(pToplevel)).FpAinc = pInfo
|
|
(*TAutoincInfo)(unsafe.Pointer(pInfo)).FpTab = pTab
|
|
(*TAutoincInfo)(unsafe.Pointer(pInfo)).FiDb = iDb
|
|
(*TParse)(unsafe.Pointer(pToplevel)).FnMem = (*TParse)(unsafe.Pointer(pToplevel)).FnMem + 1 /* Register to hold name of table */
|
|
v1 = pToplevel + 60
|
|
*(*int32)(unsafe.Pointer(v1)) = *(*int32)(unsafe.Pointer(v1)) + 1
|
|
v2 = *(*int32)(unsafe.Pointer(v1))
|
|
(*TAutoincInfo)(unsafe.Pointer(pInfo)).FregCtr = v2 /* Max rowid register */
|
|
**(**int32)(__ccgo_up(pToplevel + 60)) += int32(2) /* Rowid in sqlite_sequence + orig max val */
|
|
}
|
|
memId = (*TAutoincInfo)(unsafe.Pointer(pInfo)).FregCtr
|
|
}
|
|
return memId
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine generates the code needed to write autoincrement
|
|
// ** maximum rowid values back into the sqlite_sequence register.
|
|
// ** Every statement that might do an INSERT into an autoincrement
|
|
// ** table (either directly or through triggers) needs to call this
|
|
// ** routine just before the "exit" code.
|
|
// */
|
|
func _autoIncrementEnd(tls *libc.TLS, pParse uintptr) {
|
|
var aOp, db, p, pDb, v uintptr
|
|
var iRec, memId int32
|
|
_, _, _, _, _, _, _ = aOp, db, iRec, memId, p, pDb, v
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
p = (*TParse)(unsafe.Pointer(pParse)).FpAinc
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
pDb = (*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr((*TAutoincInfo)(unsafe.Pointer(p)).FiDb)*32
|
|
memId = (*TAutoincInfo)(unsafe.Pointer(p)).FregCtr
|
|
iRec = _sqlite3GetTempReg(tls, pParse)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Le), memId+int32(2), _sqlite3VdbeCurrentAddr(tls, v)+int32(7), memId)
|
|
_sqlite3OpenTable(tls, pParse, 0, (*TAutoincInfo)(unsafe.Pointer(p)).FiDb, (*TSchema)(unsafe.Pointer((*TDb)(unsafe.Pointer(pDb)).FpSchema)).FpSeqTab, int32(OP_OpenWrite))
|
|
aOp = _sqlite3VdbeAddOpList(tls, v, libc.Int32FromUint64(libc.Uint64FromInt64(20)/libc.Uint64FromInt64(4)), uintptr(unsafe.Pointer(&_autoIncEnd)), _iLn2)
|
|
if aOp == uintptr(0) {
|
|
break
|
|
}
|
|
(**(**TVdbeOp)(__ccgo_up(aOp))).Fp1 = memId + int32(1)
|
|
(**(**TVdbeOp)(__ccgo_up(aOp + 1*24))).Fp2 = memId + int32(1)
|
|
(**(**TVdbeOp)(__ccgo_up(aOp + 2*24))).Fp1 = memId - int32(1)
|
|
(**(**TVdbeOp)(__ccgo_up(aOp + 2*24))).Fp3 = iRec
|
|
(**(**TVdbeOp)(__ccgo_up(aOp + 3*24))).Fp2 = iRec
|
|
(**(**TVdbeOp)(__ccgo_up(aOp + 3*24))).Fp3 = memId + int32(1)
|
|
(**(**TVdbeOp)(__ccgo_up(aOp + 3*24))).Fp5 = uint16(OPFLAG_APPEND)
|
|
_sqlite3ReleaseTempReg(tls, pParse, iRec)
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = (*TAutoincInfo)(unsafe.Pointer(p)).FpNext
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine is called prior to sqlite3PagerCommit when a transaction
|
|
// ** is committed for an auto-vacuum database.
|
|
// */
|
|
func _autoVacuumCommit(tls *libc.TLS, p uintptr) (r int32) {
|
|
var db, pBt, pPager uintptr
|
|
var iDb, rc int32
|
|
var iFree, nFin, nFree, nOrig, nVac TPgno
|
|
_, _, _, _, _, _, _, _, _, _ = db, iDb, iFree, nFin, nFree, nOrig, nVac, pBt, pPager, rc
|
|
rc = SQLITE_OK
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt
|
|
pPager = (*TBtShared)(unsafe.Pointer(pBt)).FpPager
|
|
_invalidateAllOverflowCache(tls, pBt)
|
|
if !((*TBtShared)(unsafe.Pointer(pBt)).FincrVacuum != 0) { /* Database size before freeing */
|
|
nOrig = _btreePagecount(tls, pBt)
|
|
if _ptrmapPageno(tls, pBt, nOrig) == nOrig || nOrig == libc.Uint32FromInt32(_sqlite3PendingByte)/(*TBtShared)(unsafe.Pointer(pBt)).FpageSize+libc.Uint32FromInt32(1) {
|
|
/* It is not possible to create a database for which the final page
|
|
** is either a pointer-map page or the pending-byte page. If one
|
|
** is encountered, this indicates corruption.
|
|
*/
|
|
return _sqlite3CorruptError(tls, int32(77456))
|
|
}
|
|
nFree = _sqlite3Get4byte(tls, (*TMemPage)(unsafe.Pointer((*TBtShared)(unsafe.Pointer(pBt)).FpPage1)).FaData+36)
|
|
db = (*TBtree)(unsafe.Pointer(p)).Fdb
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FxAutovacPages != 0 {
|
|
iDb = 0
|
|
for {
|
|
if !(iDb < (*Tsqlite3)(unsafe.Pointer(db)).FnDb) {
|
|
break
|
|
}
|
|
if (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(iDb)*32))).FpBt == p {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
iDb = iDb + 1
|
|
}
|
|
nVac = (*(*func(*libc.TLS, uintptr, uintptr, Tu32, Tu32, Tu32) uint32)(unsafe.Pointer(&struct{ uintptr }{(*Tsqlite3)(unsafe.Pointer(db)).FxAutovacPages})))(tls, (*Tsqlite3)(unsafe.Pointer(db)).FpAutovacPagesArg, (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(iDb)*32))).FzDbSName, nOrig, nFree, (*TBtShared)(unsafe.Pointer(pBt)).FpageSize)
|
|
if nVac > nFree {
|
|
nVac = nFree
|
|
}
|
|
if nVac == uint32(0) {
|
|
return SQLITE_OK
|
|
}
|
|
} else {
|
|
nVac = nFree
|
|
}
|
|
nFin = _finalDbSize(tls, pBt, nOrig, nVac)
|
|
if nFin > nOrig {
|
|
return _sqlite3CorruptError(tls, int32(77483))
|
|
}
|
|
if nFin < nOrig {
|
|
rc = _saveAllCursors(tls, pBt, uint32(0), uintptr(0))
|
|
}
|
|
iFree = nOrig
|
|
for {
|
|
if !(iFree > nFin && rc == SQLITE_OK) {
|
|
break
|
|
}
|
|
rc = _incrVacuumStep(tls, pBt, nFin, iFree, libc.BoolInt32(nVac == nFree))
|
|
goto _2
|
|
_2:
|
|
;
|
|
iFree = iFree - 1
|
|
}
|
|
if (rc == int32(SQLITE_DONE) || rc == SQLITE_OK) && nFree > uint32(0) {
|
|
rc = _sqlite3PagerWrite(tls, (*TMemPage)(unsafe.Pointer((*TBtShared)(unsafe.Pointer(pBt)).FpPage1)).FpDbPage)
|
|
if nVac == nFree {
|
|
_sqlite3Put4byte(tls, (*TMemPage)(unsafe.Pointer((*TBtShared)(unsafe.Pointer(pBt)).FpPage1)).FaData+32, uint32(0))
|
|
_sqlite3Put4byte(tls, (*TMemPage)(unsafe.Pointer((*TBtShared)(unsafe.Pointer(pBt)).FpPage1)).FaData+36, uint32(0))
|
|
}
|
|
_sqlite3Put4byte(tls, (*TMemPage)(unsafe.Pointer((*TBtShared)(unsafe.Pointer(pBt)).FpPage1)).FaData+28, nFin)
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FbDoTruncate = uint8(1)
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FnPage = nFin
|
|
}
|
|
if rc != SQLITE_OK {
|
|
_sqlite3PagerRollback(tls, pPager)
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The page that pCur currently points to has just been modified in
|
|
// ** some way. This function figures out if this modification means the
|
|
// ** tree needs to be balanced, and if so calls the appropriate balancing
|
|
// ** routine. Balancing routines are:
|
|
// **
|
|
// ** balance_quick()
|
|
// ** balance_deeper()
|
|
// ** balance_nonroot()
|
|
// */
|
|
func _balance(tls *libc.TLS, pCur uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iIdx, iPage, rc, v1, v2 int32
|
|
var pFree, pPage, pParent, pSpace uintptr
|
|
var v3 bool
|
|
var _ /* aBalanceQuickSpace at bp+0 */ [13]Tu8
|
|
_, _, _, _, _, _, _, _, _, _ = iIdx, iPage, pFree, pPage, pParent, pSpace, rc, v1, v2, v3
|
|
rc = SQLITE_OK
|
|
pFree = uintptr(0)
|
|
for cond := true; cond; cond = rc == SQLITE_OK {
|
|
pPage = (*TBtCursor)(unsafe.Pointer(pCur)).FpPage
|
|
if (*TMemPage)(unsafe.Pointer(pPage)).FnFree < 0 && _btreeComputeFreeSpace(tls, pPage) != 0 {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pPage)).FnOverflow) == 0 && (*TMemPage)(unsafe.Pointer(pPage)).FnFree*int32(3) <= libc.Int32FromUint32((*TBtShared)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpBt)).FusableSize)*int32(2) {
|
|
/* No rebalance required as long as:
|
|
** (1) There are no overflow cells
|
|
** (2) The amount of free space on the page is less than 2/3rds of
|
|
** the total usable space on the page. */
|
|
break
|
|
} else {
|
|
v1 = int32((*TBtCursor)(unsafe.Pointer(pCur)).FiPage)
|
|
iPage = v1
|
|
if v1 == 0 {
|
|
if v3 = (*TMemPage)(unsafe.Pointer(pPage)).FnOverflow != 0; v3 {
|
|
v2 = _anotherValidCursor(tls, pCur)
|
|
rc = v2
|
|
}
|
|
if v3 && v2 == SQLITE_OK {
|
|
/* The root page of the b-tree is overfull. In this case call the
|
|
** balance_deeper() function to create a new child for the root-page
|
|
** and copy the current contents of the root-page to it. The
|
|
** next iteration of the do-loop will balance the child page.
|
|
*/
|
|
rc = _balance_deeper(tls, pPage, pCur+144+1*8)
|
|
if rc == SQLITE_OK {
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FiPage = int8(1)
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).Fix = uint16(0)
|
|
**(**Tu16)(__ccgo_up(pCur + 88)) = uint16(0)
|
|
**(**uintptr)(__ccgo_up(pCur + 144)) = pPage
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FpPage = **(**uintptr)(__ccgo_up(pCur + 144 + 1*8))
|
|
}
|
|
} else {
|
|
break
|
|
}
|
|
} else {
|
|
if _sqlite3PagerPageRefcount(tls, (*TMemPage)(unsafe.Pointer(pPage)).FpDbPage) > int32(1) {
|
|
/* The page being written is not a root page, and there is currently
|
|
** more than one reference to it. This only happens if the page is one
|
|
** of its own ancestor pages. Corruption. */
|
|
rc = _sqlite3CorruptError(tls, int32(82400))
|
|
} else {
|
|
pParent = **(**uintptr)(__ccgo_up(pCur + 144 + uintptr(iPage-int32(1))*8))
|
|
iIdx = libc.Int32FromUint16(**(**Tu16)(__ccgo_up(pCur + 88 + uintptr(iPage-int32(1))*2)))
|
|
rc = _sqlite3PagerWrite(tls, (*TMemPage)(unsafe.Pointer(pParent)).FpDbPage)
|
|
if rc == SQLITE_OK && (*TMemPage)(unsafe.Pointer(pParent)).FnFree < 0 {
|
|
rc = _btreeComputeFreeSpace(tls, pParent)
|
|
}
|
|
if rc == SQLITE_OK {
|
|
if (*TMemPage)(unsafe.Pointer(pPage)).FintKeyLeaf != 0 && libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pPage)).FnOverflow) == int32(1) && libc.Int32FromUint16(**(**Tu16)(__ccgo_up(pPage + 28))) == libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell) && (*TMemPage)(unsafe.Pointer(pParent)).Fpgno != uint32(1) && libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pParent)).FnCell) == iIdx {
|
|
/* Call balance_quick() to create a new sibling of pPage on which
|
|
** to store the overflow cell. balance_quick() inserts a new cell
|
|
** into pParent, which may cause pParent overflow. If this
|
|
** happens, the next iteration of the do-loop will balance pParent
|
|
** use either balance_nonroot() or balance_deeper(). Until this
|
|
** happens, the overflow cell is stored in the aBalanceQuickSpace[]
|
|
** buffer.
|
|
**
|
|
** The purpose of the following assert() is to check that only a
|
|
** single call to balance_quick() is made for each call to this
|
|
** function. If this were not verified, a subtle bug involving reuse
|
|
** of the aBalanceQuickSpace[] might sneak in.
|
|
*/
|
|
rc = _balance_quick(tls, pParent, pPage, bp)
|
|
} else {
|
|
/* In this case, call balance_nonroot() to redistribute cells
|
|
** between pPage and up to 2 of its sibling pages. This involves
|
|
** modifying the contents of pParent, which may cause pParent to
|
|
** become overfull or underfull. The next iteration of the do-loop
|
|
** will balance the parent page to correct this.
|
|
**
|
|
** If the parent page becomes overfull, the overflow cell or cells
|
|
** are stored in the pSpace buffer allocated immediately below.
|
|
** A subsequent iteration of the do-loop will deal with this by
|
|
** calling balance_nonroot() (balance_deeper() may be called first,
|
|
** but it doesn't deal with overflow cells - just moves them to a
|
|
** different page). Once this subsequent call to balance_nonroot()
|
|
** has completed, it is safe to release the pSpace buffer used by
|
|
** the previous call, as the overflow cell data will have been
|
|
** copied either into the body of a database page or into the new
|
|
** pSpace buffer passed to the latter call to balance_nonroot().
|
|
*/
|
|
pSpace = _sqlite3PageMalloc(tls, libc.Int32FromUint32((*TBtShared)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpBt)).FpageSize))
|
|
rc = _balance_nonroot(tls, pParent, iIdx, pSpace, libc.BoolInt32(iPage == int32(1)), libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).Fhints)&int32(BTREE_BULKLOAD))
|
|
if pFree != 0 {
|
|
/* If pFree is not NULL, it points to the pSpace buffer used
|
|
** by a previous call to balance_nonroot(). Its contents are
|
|
** now stored either on real database pages or within the
|
|
** new pSpace buffer, so it may be safely freed here. */
|
|
_sqlite3PageFree(tls, pFree)
|
|
}
|
|
/* The pSpace buffer will be freed after the next call to
|
|
** balance_nonroot(), or just before this function returns, whichever
|
|
** comes first. */
|
|
pFree = pSpace
|
|
}
|
|
}
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FnOverflow = uint8(0)
|
|
/* The next iteration of the do-loop balances the parent page. */
|
|
_releasePage(tls, pPage)
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FiPage = (*TBtCursor)(unsafe.Pointer(pCur)).FiPage - 1
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FpPage = **(**uintptr)(__ccgo_up(pCur + 144 + uintptr((*TBtCursor)(unsafe.Pointer(pCur)).FiPage)*8))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if pFree != 0 {
|
|
_sqlite3PageFree(tls, pFree)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is the default collating function named "BINARY" which is always
|
|
// ** available.
|
|
// */
|
|
func _binCollFunc(tls *libc.TLS, NotUsed uintptr, nKey1 int32, pKey1 uintptr, nKey2 int32, pKey2 uintptr) (r int32) {
|
|
var n, rc, v1 int32
|
|
_, _, _ = n, rc, v1
|
|
_ = NotUsed
|
|
if nKey1 < nKey2 {
|
|
v1 = nKey1
|
|
} else {
|
|
v1 = nKey2
|
|
}
|
|
n = v1
|
|
/* EVIDENCE-OF: R-65033-28449 The built-in BINARY collation compares
|
|
** strings byte by byte using the memcmp() function from the standard C
|
|
** library. */
|
|
rc = libc.Xmemcmp(tls, pKey1, pKey2, libc.Uint64FromInt32(n))
|
|
if rc == 0 {
|
|
rc = nKey1 - nKey2
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Bind a text or BLOB value.
|
|
// */
|
|
func _bindText(tls *libc.TLS, pStmt uintptr, i int32, zData uintptr, nData Ti64, __ccgo_fp_xDel uintptr, encoding Tu8) (r int32) {
|
|
var p, pVar, v1 uintptr
|
|
var rc int32
|
|
_, _, _, _ = p, pVar, rc, v1
|
|
p = pStmt
|
|
rc = _vdbeUnbind(tls, p, libc.Uint32FromInt32(i-libc.Int32FromInt32(1)))
|
|
if rc == SQLITE_OK {
|
|
/* tag-20240917-01 */
|
|
if zData != uintptr(0) {
|
|
pVar = (*TVdbe)(unsafe.Pointer(p)).FaVar + uintptr(i-int32(1))*56
|
|
if libc.Int32FromUint8(encoding) == int32(SQLITE_UTF8) {
|
|
rc = _sqlite3VdbeMemSetText(tls, pVar, zData, nData, __ccgo_fp_xDel)
|
|
} else {
|
|
if libc.Int32FromUint8(encoding) == int32(SQLITE_UTF8_ZT) {
|
|
/* It is usually consider improper to assert() on an input.
|
|
** However, the following assert() is checking for inputs
|
|
** that are documented to result in undefined behavior. */
|
|
rc = _sqlite3VdbeMemSetText(tls, pVar, zData, nData, __ccgo_fp_xDel)
|
|
v1 = pVar + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(MEM_Term))
|
|
} else {
|
|
rc = _sqlite3VdbeMemSetStr(tls, pVar, zData, nData, encoding, __ccgo_fp_xDel)
|
|
if libc.Int32FromUint8(encoding) == 0 {
|
|
(*TMem)(unsafe.Pointer(pVar)).Fenc = (*Tsqlite3)(unsafe.Pointer((*TVdbe)(unsafe.Pointer(p)).Fdb)).Fenc
|
|
}
|
|
}
|
|
}
|
|
if rc == SQLITE_OK && libc.Int32FromUint8(encoding) != 0 {
|
|
rc = _sqlite3VdbeChangeEncoding(tls, pVar, libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer((*TVdbe)(unsafe.Pointer(p)).Fdb)).Fenc))
|
|
}
|
|
if rc != 0 {
|
|
_sqlite3Error(tls, (*TVdbe)(unsafe.Pointer(p)).Fdb, rc)
|
|
rc = _sqlite3ApiExit(tls, (*TVdbe)(unsafe.Pointer(p)).Fdb, rc)
|
|
}
|
|
}
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer((*TVdbe)(unsafe.Pointer(p)).Fdb)).Fmutex)
|
|
} else {
|
|
if __ccgo_fp_xDel != libc.UintptrFromInt32(0) && __ccgo_fp_xDel != uintptr(-libc.Int32FromInt32(1)) {
|
|
(*(*func(*libc.TLS, uintptr))(unsafe.Pointer(&struct{ uintptr }{__ccgo_fp_xDel})))(tls, zData)
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Attempt to start a new transaction. A write-transaction
|
|
// ** is started if the second argument is nonzero, otherwise a read-
|
|
// ** transaction. If the second argument is 2 or more and exclusive
|
|
// ** transaction is started, meaning that no other process is allowed
|
|
// ** to access the database. A preexisting transaction may not be
|
|
// ** upgraded to exclusive by calling this routine a second time - the
|
|
// ** exclusivity flag only works for a new transaction.
|
|
// **
|
|
// ** A write-transaction must be started before attempting any
|
|
// ** changes to the database. None of the following routines
|
|
// ** will work unless a transaction is started first:
|
|
// **
|
|
// ** sqlite3BtreeCreateTable()
|
|
// ** sqlite3BtreeCreateIndex()
|
|
// ** sqlite3BtreeClearTable()
|
|
// ** sqlite3BtreeDropTable()
|
|
// ** sqlite3BtreeInsert()
|
|
// ** sqlite3BtreeDelete()
|
|
// ** sqlite3BtreeUpdateMeta()
|
|
// **
|
|
// ** If an initial attempt to acquire the lock fails because of lock contention
|
|
// ** and the database was previously unlocked, then invoke the busy handler
|
|
// ** if there is one. But if there was previously a read-lock, do not
|
|
// ** invoke the busy handler - just return SQLITE_BUSY. SQLITE_BUSY is
|
|
// ** returned when there is already a read-lock in order to avoid a deadlock.
|
|
// **
|
|
// ** Suppose there are two processes A and B. A has a read lock and B has
|
|
// ** a reserved lock. B tries to promote to exclusive but is blocked because
|
|
// ** of A's read lock. A tries to promote to reserved but is blocked by B.
|
|
// ** One or the other of the two processes must give way or there can be
|
|
// ** no progress. By returning SQLITE_BUSY and not invoking the busy callback
|
|
// ** when A already has a read lock, we encourage A to give up and let B
|
|
// ** proceed.
|
|
// */
|
|
func _btreeBeginTrans(tls *libc.TLS, p uintptr, wrflag int32, pSchemaVersion uintptr) (r int32) {
|
|
var pBlock, pBt, pIter, pPage1, pPager, v1 uintptr
|
|
var rc, v5 int32
|
|
var v6 bool
|
|
_, _, _, _, _, _, _, _, _ = pBlock, pBt, pIter, pPage1, pPager, rc, v1, v5, v6
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt
|
|
pPager = (*TBtShared)(unsafe.Pointer(pBt)).FpPager
|
|
rc = SQLITE_OK
|
|
_sqlite3BtreeEnter(tls, p)
|
|
/* If the btree is already in a write-transaction, or it
|
|
** is already in a read-transaction and a read-transaction
|
|
** is requested, this is a no-op.
|
|
*/
|
|
if libc.Int32FromUint8((*TBtree)(unsafe.Pointer(p)).FinTrans) == int32(TRANS_WRITE) || libc.Int32FromUint8((*TBtree)(unsafe.Pointer(p)).FinTrans) == int32(TRANS_READ) && !(wrflag != 0) {
|
|
goto trans_begun
|
|
}
|
|
if (*Tsqlite3)(unsafe.Pointer((*TBtree)(unsafe.Pointer(p)).Fdb)).Fflags&uint64(SQLITE_ResetDatabase) != 0 && libc.Int32FromUint8(_sqlite3PagerIsreadonly(tls, pPager)) == 0 {
|
|
v1 = pBt + 40
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) & ^libc.Int32FromInt32(BTS_READ_ONLY))
|
|
}
|
|
/* Write transactions are not possible on a read-only database */
|
|
if libc.Int32FromUint16((*TBtShared)(unsafe.Pointer(pBt)).FbtsFlags)&int32(BTS_READ_ONLY) != 0 && wrflag != 0 {
|
|
rc = int32(SQLITE_READONLY)
|
|
goto trans_begun
|
|
}
|
|
pBlock = uintptr(0)
|
|
/* If another database handle has already opened a write transaction
|
|
** on this shared-btree structure and a second write transaction is
|
|
** requested, return SQLITE_LOCKED.
|
|
*/
|
|
if wrflag != 0 && libc.Int32FromUint8((*TBtShared)(unsafe.Pointer(pBt)).FinTransaction) == int32(TRANS_WRITE) || libc.Int32FromUint16((*TBtShared)(unsafe.Pointer(pBt)).FbtsFlags)&int32(BTS_PENDING) != 0 {
|
|
pBlock = (*TBtree)(unsafe.Pointer((*TBtShared)(unsafe.Pointer(pBt)).FpWriter)).Fdb
|
|
} else {
|
|
if wrflag > int32(1) {
|
|
pIter = (*TBtShared)(unsafe.Pointer(pBt)).FpLock
|
|
for {
|
|
if !(pIter != 0) {
|
|
break
|
|
}
|
|
if (*TBtLock)(unsafe.Pointer(pIter)).FpBtree != p {
|
|
pBlock = (*TBtree)(unsafe.Pointer((*TBtLock)(unsafe.Pointer(pIter)).FpBtree)).Fdb
|
|
break
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
pIter = (*TBtLock)(unsafe.Pointer(pIter)).FpNext
|
|
}
|
|
}
|
|
}
|
|
if pBlock != 0 {
|
|
_sqlite3ConnectionBlocked(tls, (*TBtree)(unsafe.Pointer(p)).Fdb, pBlock)
|
|
rc = libc.Int32FromInt32(SQLITE_LOCKED) | libc.Int32FromInt32(1)<<libc.Int32FromInt32(8)
|
|
goto trans_begun
|
|
}
|
|
/* Any read-only or read-write transaction implies a read-lock on
|
|
** page 1. So if some other shared-cache client already has a write-lock
|
|
** on page 1, the transaction cannot be opened. */
|
|
rc = _querySharedCacheTableLock(tls, p, uint32(SCHEMA_ROOT), uint8(READ_LOCK))
|
|
if SQLITE_OK != rc {
|
|
goto trans_begun
|
|
}
|
|
v1 = pBt + 40
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) & ^libc.Int32FromInt32(BTS_INITIALLY_EMPTY))
|
|
if (*TBtShared)(unsafe.Pointer(pBt)).FnPage == uint32(0) {
|
|
v1 = pBt + 40
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(BTS_INITIALLY_EMPTY))
|
|
}
|
|
for cond := true; cond; cond = rc&int32(0xFF) == int32(SQLITE_BUSY) && libc.Int32FromUint8((*TBtShared)(unsafe.Pointer(pBt)).FinTransaction) == TRANS_NONE && _btreeInvokeBusyHandler(tls, pBt) != 0 {
|
|
/* Call lockBtree() until either pBt->pPage1 is populated or
|
|
** lockBtree() returns something other than SQLITE_OK. lockBtree()
|
|
** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after
|
|
** reading page 1 it discovers that the page-size of the database
|
|
** file is not pBt->pageSize. In this case lockBtree() will update
|
|
** pBt->pageSize to the page-size of the file on disk.
|
|
*/
|
|
for {
|
|
if v6 = (*TBtShared)(unsafe.Pointer(pBt)).FpPage1 == uintptr(0); v6 {
|
|
v5 = _lockBtree(tls, pBt)
|
|
rc = v5
|
|
}
|
|
if !(v6 && SQLITE_OK == v5) {
|
|
break
|
|
}
|
|
}
|
|
if rc == SQLITE_OK && wrflag != 0 {
|
|
if libc.Int32FromUint16((*TBtShared)(unsafe.Pointer(pBt)).FbtsFlags)&int32(BTS_READ_ONLY) != 0 {
|
|
rc = int32(SQLITE_READONLY)
|
|
} else {
|
|
rc = _sqlite3PagerBegin(tls, pPager, libc.BoolInt32(wrflag > int32(1)), _sqlite3TempInMemory(tls, (*TBtree)(unsafe.Pointer(p)).Fdb))
|
|
if rc == SQLITE_OK {
|
|
rc = _newDatabase(tls, pBt)
|
|
} else {
|
|
if rc == libc.Int32FromInt32(SQLITE_BUSY)|libc.Int32FromInt32(2)<<libc.Int32FromInt32(8) && libc.Int32FromUint8((*TBtShared)(unsafe.Pointer(pBt)).FinTransaction) == TRANS_NONE {
|
|
/* if there was no transaction opened when this function was
|
|
** called and SQLITE_BUSY_SNAPSHOT is returned, change the error
|
|
** code to SQLITE_BUSY. */
|
|
rc = int32(SQLITE_BUSY)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if rc != SQLITE_OK {
|
|
_ = SQLITE_OK
|
|
_unlockBtreeIfUnused(tls, pBt)
|
|
}
|
|
}
|
|
if rc == SQLITE_OK {
|
|
if libc.Int32FromUint8((*TBtree)(unsafe.Pointer(p)).FinTrans) == TRANS_NONE {
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FnTransaction = (*TBtShared)(unsafe.Pointer(pBt)).FnTransaction + 1
|
|
if (*TBtree)(unsafe.Pointer(p)).Fsharable != 0 {
|
|
(*TBtree)(unsafe.Pointer(p)).Flock.FeLock = uint8(READ_LOCK)
|
|
(*TBtree)(unsafe.Pointer(p)).Flock.FpNext = (*TBtShared)(unsafe.Pointer(pBt)).FpLock
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FpLock = p + 48
|
|
}
|
|
}
|
|
if wrflag != 0 {
|
|
v5 = int32(TRANS_WRITE)
|
|
} else {
|
|
v5 = int32(TRANS_READ)
|
|
}
|
|
(*TBtree)(unsafe.Pointer(p)).FinTrans = libc.Uint8FromInt32(v5)
|
|
if libc.Int32FromUint8((*TBtree)(unsafe.Pointer(p)).FinTrans) > libc.Int32FromUint8((*TBtShared)(unsafe.Pointer(pBt)).FinTransaction) {
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FinTransaction = (*TBtree)(unsafe.Pointer(p)).FinTrans
|
|
}
|
|
if wrflag != 0 {
|
|
pPage1 = (*TBtShared)(unsafe.Pointer(pBt)).FpPage1
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FpWriter = p
|
|
v1 = pBt + 40
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) & ^libc.Int32FromInt32(BTS_EXCLUSIVE))
|
|
if wrflag > int32(1) {
|
|
v1 = pBt + 40
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(BTS_EXCLUSIVE))
|
|
}
|
|
/* If the db-size header field is incorrect (as it may be if an old
|
|
** client has been writing the database file), update it now. Doing
|
|
** this sooner rather than later means the database size can safely
|
|
** re-read the database size from page 1 if a savepoint or transaction
|
|
** rollback occurs within the transaction.
|
|
*/
|
|
if (*TBtShared)(unsafe.Pointer(pBt)).FnPage != _sqlite3Get4byte(tls, (*TMemPage)(unsafe.Pointer(pPage1)).FaData+28) {
|
|
rc = _sqlite3PagerWrite(tls, (*TMemPage)(unsafe.Pointer(pPage1)).FpDbPage)
|
|
if rc == SQLITE_OK {
|
|
_sqlite3Put4byte(tls, (*TMemPage)(unsafe.Pointer(pPage1)).FaData+28, (*TBtShared)(unsafe.Pointer(pBt)).FnPage)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
goto trans_begun
|
|
trans_begun:
|
|
;
|
|
if rc == SQLITE_OK {
|
|
if pSchemaVersion != 0 {
|
|
**(**int32)(__ccgo_up(pSchemaVersion)) = libc.Int32FromUint32(_sqlite3Get4byte(tls, (*TMemPage)(unsafe.Pointer((*TBtShared)(unsafe.Pointer(pBt)).FpPage1)).FaData+40))
|
|
}
|
|
if wrflag != 0 {
|
|
/* This call makes sure that the pager has the correct number of
|
|
** open savepoints. If the second parameter is greater than 0 and
|
|
** the sub-journal is not already open, then it will be opened here.
|
|
*/
|
|
rc = _sqlite3PagerOpenSavepoint(tls, pPager, (*Tsqlite3)(unsafe.Pointer((*TBtree)(unsafe.Pointer(p)).Fdb)).FnSavepoint)
|
|
}
|
|
}
|
|
_sqlite3BtreeLeave(tls, p)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Create a new BTree table. Write into *piTable the page
|
|
// ** number for the root page of the new table.
|
|
// **
|
|
// ** The type of type is determined by the flags parameter. Only the
|
|
// ** following values of flags are currently in use. Other values for
|
|
// ** flags might not work:
|
|
// **
|
|
// ** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys
|
|
// ** BTREE_ZERODATA Used for SQL indices
|
|
// */
|
|
func _btreeCreateTable(tls *libc.TLS, p uintptr, piTable uintptr, createTabFlags int32) (r int32) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var pBt uintptr
|
|
var ptfFlags int32
|
|
var _ /* eType at bp+32 */ Tu8
|
|
var _ /* iPtrPage at bp+36 */ TPgno
|
|
var _ /* pPageMove at bp+24 */ uintptr
|
|
var _ /* pRoot at bp+0 */ uintptr
|
|
var _ /* pgnoMove at bp+16 */ TPgno
|
|
var _ /* pgnoRoot at bp+8 */ TPgno
|
|
var _ /* rc at bp+12 */ int32
|
|
_, _ = pBt, ptfFlags
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt /* Page-type flags for the root page of new table */
|
|
if (*TBtShared)(unsafe.Pointer(pBt)).FautoVacuum != 0 { /* The page to move to. */
|
|
/* Creating a new table may probably require moving an existing database
|
|
** to make room for the new tables root page. In case this page turns
|
|
** out to be an overflow page, delete all overflow page-map caches
|
|
** held by open cursors.
|
|
*/
|
|
_invalidateAllOverflowCache(tls, pBt)
|
|
/* Read the value of meta[3] from the database to determine where the
|
|
** root page of the new table should go. meta[3] is the largest root-page
|
|
** created so far, so the new root-page is (meta[3]+1).
|
|
*/
|
|
_sqlite3BtreeGetMeta(tls, p, int32(BTREE_LARGEST_ROOT_PAGE), bp+8)
|
|
if **(**TPgno)(__ccgo_up(bp + 8)) > _btreePagecount(tls, pBt) {
|
|
return _sqlite3CorruptError(tls, int32(83314))
|
|
}
|
|
**(**TPgno)(__ccgo_up(bp + 8)) = **(**TPgno)(__ccgo_up(bp + 8)) + 1
|
|
/* The new root-page may not be allocated on a pointer-map page, or the
|
|
** PENDING_BYTE page.
|
|
*/
|
|
for **(**TPgno)(__ccgo_up(bp + 8)) == _ptrmapPageno(tls, pBt, **(**TPgno)(__ccgo_up(bp + 8))) || **(**TPgno)(__ccgo_up(bp + 8)) == libc.Uint32FromInt32(_sqlite3PendingByte)/(*TBtShared)(unsafe.Pointer(pBt)).FpageSize+libc.Uint32FromInt32(1) {
|
|
**(**TPgno)(__ccgo_up(bp + 8)) = **(**TPgno)(__ccgo_up(bp + 8)) + 1
|
|
}
|
|
/* Allocate a page. The page that currently resides at pgnoRoot will
|
|
** be moved to the allocated page (unless the allocated page happens
|
|
** to reside at pgnoRoot).
|
|
*/
|
|
**(**int32)(__ccgo_up(bp + 12)) = _allocateBtreePage(tls, pBt, bp+24, bp+16, **(**TPgno)(__ccgo_up(bp + 8)), uint8(BTALLOC_EXACT))
|
|
if **(**int32)(__ccgo_up(bp + 12)) != SQLITE_OK {
|
|
return **(**int32)(__ccgo_up(bp + 12))
|
|
}
|
|
if **(**TPgno)(__ccgo_up(bp + 16)) != **(**TPgno)(__ccgo_up(bp + 8)) {
|
|
/* pgnoRoot is the page that will be used for the root-page of
|
|
** the new table (assuming an error did not occur). But we were
|
|
** allocated pgnoMove. If required (i.e. if it was not allocated
|
|
** by extending the file), the current page at position pgnoMove
|
|
** is already journaled.
|
|
*/
|
|
**(**Tu8)(__ccgo_up(bp + 32)) = uint8(0)
|
|
**(**TPgno)(__ccgo_up(bp + 36)) = uint32(0)
|
|
/* Save the positions of any open cursors. This is required in
|
|
** case they are holding a reference to an xFetch reference
|
|
** corresponding to page pgnoRoot. */
|
|
**(**int32)(__ccgo_up(bp + 12)) = _saveAllCursors(tls, pBt, uint32(0), uintptr(0))
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp + 24)))
|
|
if **(**int32)(__ccgo_up(bp + 12)) != SQLITE_OK {
|
|
return **(**int32)(__ccgo_up(bp + 12))
|
|
}
|
|
/* Move the page currently at pgnoRoot to pgnoMove. */
|
|
**(**int32)(__ccgo_up(bp + 12)) = _btreeGetPage(tls, pBt, **(**TPgno)(__ccgo_up(bp + 8)), bp, 0)
|
|
if **(**int32)(__ccgo_up(bp + 12)) != SQLITE_OK {
|
|
return **(**int32)(__ccgo_up(bp + 12))
|
|
}
|
|
**(**int32)(__ccgo_up(bp + 12)) = _ptrmapGet(tls, pBt, **(**TPgno)(__ccgo_up(bp + 8)), bp+32, bp+36)
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(bp + 32))) == int32(PTRMAP_ROOTPAGE) || libc.Int32FromUint8(**(**Tu8)(__ccgo_up(bp + 32))) == int32(PTRMAP_FREEPAGE) {
|
|
**(**int32)(__ccgo_up(bp + 12)) = _sqlite3CorruptError(tls, int32(83362))
|
|
}
|
|
if **(**int32)(__ccgo_up(bp + 12)) != SQLITE_OK {
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
return **(**int32)(__ccgo_up(bp + 12))
|
|
}
|
|
**(**int32)(__ccgo_up(bp + 12)) = _relocatePage(tls, pBt, **(**uintptr)(__ccgo_up(bp)), **(**Tu8)(__ccgo_up(bp + 32)), **(**TPgno)(__ccgo_up(bp + 36)), **(**TPgno)(__ccgo_up(bp + 16)), 0)
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
/* Obtain the page at pgnoRoot */
|
|
if **(**int32)(__ccgo_up(bp + 12)) != SQLITE_OK {
|
|
return **(**int32)(__ccgo_up(bp + 12))
|
|
}
|
|
**(**int32)(__ccgo_up(bp + 12)) = _btreeGetPage(tls, pBt, **(**TPgno)(__ccgo_up(bp + 8)), bp, 0)
|
|
if **(**int32)(__ccgo_up(bp + 12)) != SQLITE_OK {
|
|
return **(**int32)(__ccgo_up(bp + 12))
|
|
}
|
|
**(**int32)(__ccgo_up(bp + 12)) = _sqlite3PagerWrite(tls, (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FpDbPage)
|
|
if **(**int32)(__ccgo_up(bp + 12)) != SQLITE_OK {
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
return **(**int32)(__ccgo_up(bp + 12))
|
|
}
|
|
} else {
|
|
**(**uintptr)(__ccgo_up(bp)) = **(**uintptr)(__ccgo_up(bp + 24))
|
|
}
|
|
/* Update the pointer-map and meta-data with the new root-page number. */
|
|
_ptrmapPut(tls, pBt, **(**TPgno)(__ccgo_up(bp + 8)), uint8(PTRMAP_ROOTPAGE), uint32(0), bp+12)
|
|
if **(**int32)(__ccgo_up(bp + 12)) != 0 {
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
return **(**int32)(__ccgo_up(bp + 12))
|
|
}
|
|
/* When the new root page was allocated, page 1 was made writable in
|
|
** order either to increase the database filesize, or to decrement the
|
|
** freelist count. Hence, the sqlite3BtreeUpdateMeta() call cannot fail.
|
|
*/
|
|
**(**int32)(__ccgo_up(bp + 12)) = _sqlite3BtreeUpdateMeta(tls, p, int32(4), **(**TPgno)(__ccgo_up(bp + 8)))
|
|
if **(**int32)(__ccgo_up(bp + 12)) != 0 {
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
return **(**int32)(__ccgo_up(bp + 12))
|
|
}
|
|
} else {
|
|
**(**int32)(__ccgo_up(bp + 12)) = _allocateBtreePage(tls, pBt, bp, bp+8, uint32(1), uint8(0))
|
|
if **(**int32)(__ccgo_up(bp + 12)) != 0 {
|
|
return **(**int32)(__ccgo_up(bp + 12))
|
|
}
|
|
}
|
|
if createTabFlags&int32(BTREE_INTKEY) != 0 {
|
|
ptfFlags = libc.Int32FromInt32(PTF_INTKEY) | libc.Int32FromInt32(PTF_LEAFDATA) | libc.Int32FromInt32(PTF_LEAF)
|
|
} else {
|
|
ptfFlags = libc.Int32FromInt32(PTF_ZERODATA) | libc.Int32FromInt32(PTF_LEAF)
|
|
}
|
|
_zeroPage(tls, **(**uintptr)(__ccgo_up(bp)), ptfFlags)
|
|
_sqlite3PagerUnref(tls, (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FpDbPage)
|
|
**(**TPgno)(__ccgo_up(piTable)) = **(**TPgno)(__ccgo_up(bp + 8))
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Erase all information in a table and add the root of the table to
|
|
// ** the freelist. Except, the root of the principle table (the one on
|
|
// ** page 1) is never added to the freelist.
|
|
// **
|
|
// ** This routine will fail with SQLITE_LOCKED if there are any open
|
|
// ** cursors on the table.
|
|
// **
|
|
// ** If AUTOVACUUM is enabled and the page at iTable is not the last
|
|
// ** root page in the database file, then the last root page
|
|
// ** in the database file is moved into the slot formerly occupied by
|
|
// ** iTable and that last slot formerly occupied by the last root page
|
|
// ** is added to the freelist instead of iTable. In this say, all
|
|
// ** root pages are kept at the beginning of the database file, which
|
|
// ** is necessary for AUTOVACUUM to work right. *piMoved is set to the
|
|
// ** page number that used to be the last root page in the file before
|
|
// ** the move. If no page gets moved, *piMoved is set to 0.
|
|
// ** The last root page is recorded in meta[3] and the value of
|
|
// ** meta[3] is updated by this procedure.
|
|
// */
|
|
func _btreeDropTable(tls *libc.TLS, p uintptr, iTable TPgno, piMoved uintptr) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var pBt uintptr
|
|
var _ /* maxRootPgno at bp+16 */ TPgno
|
|
var _ /* pMove at bp+24 */ uintptr
|
|
var _ /* pPage at bp+8 */ uintptr
|
|
var _ /* rc at bp+0 */ int32
|
|
_ = pBt
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = uintptr(0)
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt
|
|
if iTable > _btreePagecount(tls, pBt) {
|
|
return _sqlite3CorruptError(tls, int32(83563))
|
|
}
|
|
**(**int32)(__ccgo_up(bp)) = _sqlite3BtreeClearTable(tls, p, libc.Int32FromUint32(iTable), uintptr(0))
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
**(**int32)(__ccgo_up(bp)) = _btreeGetPage(tls, pBt, iTable, bp+8, 0)
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp + 8)))
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
**(**int32)(__ccgo_up(piMoved)) = 0
|
|
if (*TBtShared)(unsafe.Pointer(pBt)).FautoVacuum != 0 {
|
|
_sqlite3BtreeGetMeta(tls, p, int32(BTREE_LARGEST_ROOT_PAGE), bp+16)
|
|
if iTable == **(**TPgno)(__ccgo_up(bp + 16)) {
|
|
/* If the table being dropped is the table with the largest root-page
|
|
** number in the database, put the root page on the free list.
|
|
*/
|
|
_freePage(tls, **(**uintptr)(__ccgo_up(bp + 8)), bp)
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp + 8)))
|
|
if **(**int32)(__ccgo_up(bp)) != SQLITE_OK {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
} else {
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp + 8)))
|
|
**(**int32)(__ccgo_up(bp)) = _btreeGetPage(tls, pBt, **(**TPgno)(__ccgo_up(bp + 16)), bp+24, 0)
|
|
if **(**int32)(__ccgo_up(bp)) != SQLITE_OK {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
**(**int32)(__ccgo_up(bp)) = _relocatePage(tls, pBt, **(**uintptr)(__ccgo_up(bp + 24)), uint8(PTRMAP_ROOTPAGE), uint32(0), iTable, 0)
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp + 24)))
|
|
if **(**int32)(__ccgo_up(bp)) != SQLITE_OK {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
**(**uintptr)(__ccgo_up(bp + 24)) = uintptr(0)
|
|
**(**int32)(__ccgo_up(bp)) = _btreeGetPage(tls, pBt, **(**TPgno)(__ccgo_up(bp + 16)), bp+24, 0)
|
|
_freePage(tls, **(**uintptr)(__ccgo_up(bp + 24)), bp)
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp + 24)))
|
|
if **(**int32)(__ccgo_up(bp)) != SQLITE_OK {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
**(**int32)(__ccgo_up(piMoved)) = libc.Int32FromUint32(**(**TPgno)(__ccgo_up(bp + 16)))
|
|
}
|
|
/* Set the new 'max-root-page' value in the database header. This
|
|
** is the old value less one, less one more if that happens to
|
|
** be a root-page number, less one again if that is the
|
|
** PENDING_BYTE_PAGE.
|
|
*/
|
|
**(**TPgno)(__ccgo_up(bp + 16)) = **(**TPgno)(__ccgo_up(bp + 16)) - 1
|
|
for **(**TPgno)(__ccgo_up(bp + 16)) == libc.Uint32FromInt32(_sqlite3PendingByte)/(*TBtShared)(unsafe.Pointer(pBt)).FpageSize+libc.Uint32FromInt32(1) || _ptrmapPageno(tls, pBt, **(**TPgno)(__ccgo_up(bp + 16))) == **(**TPgno)(__ccgo_up(bp + 16)) {
|
|
**(**TPgno)(__ccgo_up(bp + 16)) = **(**TPgno)(__ccgo_up(bp + 16)) - 1
|
|
}
|
|
**(**int32)(__ccgo_up(bp)) = _sqlite3BtreeUpdateMeta(tls, p, int32(4), **(**TPgno)(__ccgo_up(bp + 16)))
|
|
} else {
|
|
_freePage(tls, **(**uintptr)(__ccgo_up(bp + 8)), bp)
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp + 8)))
|
|
}
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Advance the cursor to the next entry in the database.
|
|
// ** Return value:
|
|
// **
|
|
// ** SQLITE_OK success
|
|
// ** SQLITE_DONE cursor is already pointing at the last element
|
|
// ** otherwise some kind of error occurred
|
|
// **
|
|
// ** The main entry point is sqlite3BtreeNext(). That routine is optimized
|
|
// ** for the common case of merely incrementing the cell counter BtCursor.aiIdx
|
|
// ** to the next cell on the current page. The (slower) btreeNext() helper
|
|
// ** routine is called when it is necessary to move to a different page or
|
|
// ** to restore the cursor.
|
|
// **
|
|
// ** If bit 0x01 of the F argument in sqlite3BtreeNext(C,F) is 1, then the
|
|
// ** cursor corresponds to an SQL index and this routine could have been
|
|
// ** skipped if the SQL index had been a unique index. The F argument
|
|
// ** is a hint to the implement. SQLite btree implementation does not use
|
|
// ** this hint, but COMDB2 does.
|
|
// */
|
|
func _btreeNext(tls *libc.TLS, pCur uintptr) (r int32) {
|
|
var idx, rc, v1 int32
|
|
var pPage, v3 uintptr
|
|
var v2 Tu16
|
|
_, _, _, _, _, _ = idx, pPage, rc, v1, v2, v3
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) != CURSOR_VALID {
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) >= int32(CURSOR_REQUIRESEEK) {
|
|
v1 = _btreeRestoreCursorPosition(tls, pCur)
|
|
} else {
|
|
v1 = SQLITE_OK
|
|
}
|
|
rc = v1
|
|
if rc != SQLITE_OK {
|
|
return rc
|
|
}
|
|
if int32(CURSOR_INVALID) == libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) {
|
|
return int32(SQLITE_DONE)
|
|
}
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) == int32(CURSOR_SKIPNEXT) {
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FeState = uint8(CURSOR_VALID)
|
|
if (*TBtCursor)(unsafe.Pointer(pCur)).FskipNext > 0 {
|
|
return SQLITE_OK
|
|
}
|
|
}
|
|
}
|
|
pPage = (*TBtCursor)(unsafe.Pointer(pCur)).FpPage
|
|
v3 = pCur + 86
|
|
*(*Tu16)(unsafe.Pointer(v3)) = *(*Tu16)(unsafe.Pointer(v3)) + 1
|
|
v2 = *(*Tu16)(unsafe.Pointer(v3))
|
|
idx = libc.Int32FromUint16(v2)
|
|
if _sqlite3FaultSim(tls, int32(412)) != 0 {
|
|
(*TMemPage)(unsafe.Pointer(pPage)).FisInit = uint8(0)
|
|
}
|
|
if !((*TMemPage)(unsafe.Pointer(pPage)).FisInit != 0) {
|
|
return _sqlite3CorruptError(tls, int32(79581))
|
|
}
|
|
if idx >= libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell) {
|
|
if !((*TMemPage)(unsafe.Pointer(pPage)).Fleaf != 0) {
|
|
rc = _moveToChild(tls, pCur, _sqlite3Get4byte(tls, (*TMemPage)(unsafe.Pointer(pPage)).FaData+uintptr(libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pPage)).FhdrOffset)+int32(8))))
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
return _moveToLeftmost(tls, pCur)
|
|
}
|
|
for cond := true; cond; cond = libc.Int32FromUint16((*TBtCursor)(unsafe.Pointer(pCur)).Fix) >= libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell) {
|
|
if int32((*TBtCursor)(unsafe.Pointer(pCur)).FiPage) == 0 {
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FeState = uint8(CURSOR_INVALID)
|
|
return int32(SQLITE_DONE)
|
|
}
|
|
_moveToParent(tls, pCur)
|
|
pPage = (*TBtCursor)(unsafe.Pointer(pCur)).FpPage
|
|
}
|
|
if (*TMemPage)(unsafe.Pointer(pPage)).FintKey != 0 {
|
|
return _sqlite3BtreeNext(tls, pCur, 0)
|
|
} else {
|
|
return SQLITE_OK
|
|
}
|
|
}
|
|
if (*TMemPage)(unsafe.Pointer(pPage)).Fleaf != 0 {
|
|
return SQLITE_OK
|
|
} else {
|
|
return _moveToLeftmost(tls, pCur)
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is common tail processing for btreeParseCellPtr() and
|
|
// ** btreeParseCellPtrIndex() for the case when the cell does not fit entirely
|
|
// ** on a single B-tree page. Make necessary adjustments to the CellInfo
|
|
// ** structure.
|
|
// */
|
|
func _btreeParseCellAdjustSizeForOverflow(tls *libc.TLS, pPage uintptr, pCell uintptr, pInfo uintptr) {
|
|
var maxLocal, minLocal, surplus int32
|
|
_, _, _ = maxLocal, minLocal, surplus /* Overflow payload available for local storage */
|
|
minLocal = libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FminLocal)
|
|
maxLocal = libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FmaxLocal)
|
|
surplus = libc.Int32FromUint32(libc.Uint32FromInt32(minLocal) + ((*TCellInfo)(unsafe.Pointer(pInfo)).FnPayload-libc.Uint32FromInt32(minLocal))%((*TBtShared)(unsafe.Pointer((*TMemPage)(unsafe.Pointer(pPage)).FpBt)).FusableSize-uint32(4)))
|
|
if surplus <= maxLocal {
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FnLocal = libc.Uint16FromInt32(surplus)
|
|
} else {
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FnLocal = libc.Uint16FromInt32(minLocal)
|
|
}
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FnSize = libc.Uint16FromInt32(libc.Int32FromUint16(libc.Uint16FromInt64(t__predefined_ptrdiff_t((*TCellInfo)(unsafe.Pointer(pInfo)).FpPayload+uintptr((*TCellInfo)(unsafe.Pointer(pInfo)).FnLocal))-int64(pCell))) + int32(4))
|
|
}
|
|
|
|
func _btreeParseCellPtr(tls *libc.TLS, pPage uintptr, pCell uintptr, pInfo uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var nPayload Tu64
|
|
var pEnd, pIter, v1 uintptr
|
|
var x, v2 Tu8
|
|
var _ /* iKey at bp+0 */ Tu64
|
|
_, _, _, _, _, _ = nPayload, pEnd, pIter, x, v1, v2 /* Extracted Key value */
|
|
pIter = pCell
|
|
/* The next block of code is equivalent to:
|
|
**
|
|
** pIter += getVarint32(pIter, nPayload);
|
|
**
|
|
** The code is inlined to avoid a function call.
|
|
*/
|
|
nPayload = uint64(**(**Tu8)(__ccgo_up(pIter)))
|
|
if nPayload >= uint64(0x80) {
|
|
pEnd = pIter + 8
|
|
nPayload = nPayload & uint64(0x7f)
|
|
for cond := true; cond; cond = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pIter))) >= int32(0x80) && pIter < pEnd {
|
|
pIter = pIter + 1
|
|
v1 = pIter
|
|
nPayload = nPayload<<libc.Int32FromInt32(7) | libc.Uint64FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v1)))&libc.Int32FromInt32(0x7f))
|
|
}
|
|
nPayload = nPayload & uint64(0xffffffff)
|
|
}
|
|
pIter = pIter + 1
|
|
/* The next block of code is equivalent to:
|
|
**
|
|
** pIter += getVarint(pIter, (u64*)&pInfo->nKey);
|
|
**
|
|
** The code is inlined and the loop is unrolled for performance.
|
|
** This routine is a high-runner.
|
|
*/
|
|
**(**Tu64)(__ccgo_up(bp)) = uint64(**(**Tu8)(__ccgo_up(pIter)))
|
|
if **(**Tu64)(__ccgo_up(bp)) >= uint64(0x80) {
|
|
pIter = pIter + 1
|
|
v1 = pIter
|
|
v2 = **(**Tu8)(__ccgo_up(v1))
|
|
x = v2
|
|
**(**Tu64)(__ccgo_up(bp)) = **(**Tu64)(__ccgo_up(bp))<<libc.Int32FromInt32(7) ^ uint64(v2)
|
|
if libc.Int32FromUint8(x) >= int32(0x80) {
|
|
pIter = pIter + 1
|
|
v1 = pIter
|
|
v2 = **(**Tu8)(__ccgo_up(v1))
|
|
x = v2
|
|
**(**Tu64)(__ccgo_up(bp)) = **(**Tu64)(__ccgo_up(bp))<<libc.Int32FromInt32(7) ^ uint64(v2)
|
|
if libc.Int32FromUint8(x) >= int32(0x80) {
|
|
pIter = pIter + 1
|
|
v1 = pIter
|
|
v2 = **(**Tu8)(__ccgo_up(v1))
|
|
x = v2
|
|
**(**Tu64)(__ccgo_up(bp)) = **(**Tu64)(__ccgo_up(bp))<<libc.Int32FromInt32(7) ^ uint64(0x10204000) ^ uint64(v2)
|
|
if libc.Int32FromUint8(x) >= int32(0x80) {
|
|
pIter = pIter + 1
|
|
v1 = pIter
|
|
v2 = **(**Tu8)(__ccgo_up(v1))
|
|
x = v2
|
|
**(**Tu64)(__ccgo_up(bp)) = **(**Tu64)(__ccgo_up(bp))<<libc.Int32FromInt32(7) ^ uint64(0x4000) ^ uint64(v2)
|
|
if libc.Int32FromUint8(x) >= int32(0x80) {
|
|
pIter = pIter + 1
|
|
v1 = pIter
|
|
v2 = **(**Tu8)(__ccgo_up(v1))
|
|
x = v2
|
|
**(**Tu64)(__ccgo_up(bp)) = **(**Tu64)(__ccgo_up(bp))<<libc.Int32FromInt32(7) ^ uint64(0x4000) ^ uint64(v2)
|
|
if libc.Int32FromUint8(x) >= int32(0x80) {
|
|
pIter = pIter + 1
|
|
v1 = pIter
|
|
v2 = **(**Tu8)(__ccgo_up(v1))
|
|
x = v2
|
|
**(**Tu64)(__ccgo_up(bp)) = **(**Tu64)(__ccgo_up(bp))<<libc.Int32FromInt32(7) ^ uint64(0x4000) ^ uint64(v2)
|
|
if libc.Int32FromUint8(x) >= int32(0x80) {
|
|
pIter = pIter + 1
|
|
v1 = pIter
|
|
v2 = **(**Tu8)(__ccgo_up(v1))
|
|
x = v2
|
|
**(**Tu64)(__ccgo_up(bp)) = **(**Tu64)(__ccgo_up(bp))<<libc.Int32FromInt32(7) ^ uint64(0x4000) ^ uint64(v2)
|
|
if libc.Int32FromUint8(x) >= int32(0x80) {
|
|
pIter = pIter + 1
|
|
v1 = pIter
|
|
**(**Tu64)(__ccgo_up(bp)) = **(**Tu64)(__ccgo_up(bp))<<libc.Int32FromInt32(8) ^ uint64(0x8000) ^ uint64(**(**Tu8)(__ccgo_up(v1)))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
**(**Tu64)(__ccgo_up(bp)) = **(**Tu64)(__ccgo_up(bp)) ^ uint64(0x204000)
|
|
}
|
|
} else {
|
|
**(**Tu64)(__ccgo_up(bp)) = **(**Tu64)(__ccgo_up(bp)) ^ uint64(0x4000)
|
|
}
|
|
}
|
|
pIter = pIter + 1
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FnKey = **(**Ti64)(__ccgo_up(bp))
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FnPayload = uint32(nPayload)
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FpPayload = pIter
|
|
if nPayload <= uint64((*TMemPage)(unsafe.Pointer(pPage)).FmaxLocal) {
|
|
/* This is the (easy) common case where the entire payload fits
|
|
** on the local page. No overflow is required.
|
|
*/
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FnSize = libc.Uint16FromInt32(libc.Int32FromUint16(uint16(nPayload)) + libc.Int32FromUint16(libc.Uint16FromInt64(int64(pIter)-int64(pCell))))
|
|
if libc.Int32FromUint16((*TCellInfo)(unsafe.Pointer(pInfo)).FnSize) < int32(4) {
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FnSize = uint16(4)
|
|
}
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FnLocal = uint16(nPayload)
|
|
} else {
|
|
_btreeParseCellAdjustSizeForOverflow(tls, pPage, pCell, pInfo)
|
|
}
|
|
}
|
|
|
|
func _btreeParseCellPtrIndex(tls *libc.TLS, pPage uintptr, pCell uintptr, pInfo uintptr) {
|
|
var nPayload Tu32
|
|
var pEnd, pIter, v1 uintptr
|
|
_, _, _, _ = nPayload, pEnd, pIter, v1 /* Number of bytes of cell payload */
|
|
pIter = pCell + uintptr((*TMemPage)(unsafe.Pointer(pPage)).FchildPtrSize)
|
|
nPayload = uint32(**(**Tu8)(__ccgo_up(pIter)))
|
|
if nPayload >= uint32(0x80) {
|
|
pEnd = pIter + 8
|
|
nPayload = nPayload & uint32(0x7f)
|
|
for cond := true; cond; cond = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pIter))) >= int32(0x80) && pIter < pEnd {
|
|
pIter = pIter + 1
|
|
v1 = pIter
|
|
nPayload = nPayload<<libc.Int32FromInt32(7) | libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v1)))&libc.Int32FromInt32(0x7f))
|
|
}
|
|
}
|
|
pIter = pIter + 1
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FnKey = libc.Int64FromUint32(nPayload)
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FnPayload = nPayload
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FpPayload = pIter
|
|
if nPayload <= uint32((*TMemPage)(unsafe.Pointer(pPage)).FmaxLocal) {
|
|
/* This is the (easy) common case where the entire payload fits
|
|
** on the local page. No overflow is required.
|
|
*/
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FnSize = libc.Uint16FromInt32(libc.Int32FromUint16(uint16(nPayload)) + libc.Int32FromUint16(libc.Uint16FromInt64(int64(pIter)-int64(pCell))))
|
|
if libc.Int32FromUint16((*TCellInfo)(unsafe.Pointer(pInfo)).FnSize) < int32(4) {
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FnSize = uint16(4)
|
|
}
|
|
(*TCellInfo)(unsafe.Pointer(pInfo)).FnLocal = uint16(nPayload)
|
|
} else {
|
|
_btreeParseCellAdjustSizeForOverflow(tls, pPage, pCell, pInfo)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The following routines are implementations of the MemPage.xCellSize
|
|
// ** method.
|
|
// **
|
|
// ** Compute the total number of bytes that a Cell needs in the cell
|
|
// ** data area of the btree-page. The return number includes the cell
|
|
// ** data header and the local payload, but not any overflow page or
|
|
// ** the space used by the cell pointer.
|
|
// **
|
|
// ** cellSizePtrNoPayload() => table internal nodes
|
|
// ** cellSizePtrTableLeaf() => table leaf nodes
|
|
// ** cellSizePtr() => index internal nodes
|
|
// ** cellSizeIdxLeaf() => index leaf nodes
|
|
// */
|
|
func _cellSizePtr(tls *libc.TLS, pPage uintptr, pCell uintptr) (r Tu16) {
|
|
var minLocal int32
|
|
var nSize Tu32
|
|
var pEnd, pIter, v1 uintptr
|
|
_, _, _, _, _ = minLocal, nSize, pEnd, pIter, v1
|
|
pIter = pCell + uintptr(4) /* Size value to return */
|
|
nSize = uint32(**(**Tu8)(__ccgo_up(pIter)))
|
|
if nSize >= uint32(0x80) {
|
|
pEnd = pIter + 8
|
|
nSize = nSize & uint32(0x7f)
|
|
for cond := true; cond; cond = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pIter))) >= int32(0x80) && pIter < pEnd {
|
|
pIter = pIter + 1
|
|
v1 = pIter
|
|
nSize = nSize<<libc.Int32FromInt32(7) | libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v1)))&libc.Int32FromInt32(0x7f))
|
|
}
|
|
}
|
|
pIter = pIter + 1
|
|
if nSize <= uint32((*TMemPage)(unsafe.Pointer(pPage)).FmaxLocal) {
|
|
nSize = nSize + libc.Uint32FromInt64(int64(pIter)-int64(pCell))
|
|
} else {
|
|
minLocal = libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FminLocal)
|
|
nSize = libc.Uint32FromInt32(minLocal) + (nSize-libc.Uint32FromInt32(minLocal))%((*TBtShared)(unsafe.Pointer((*TMemPage)(unsafe.Pointer(pPage)).FpBt)).FusableSize-uint32(4))
|
|
if nSize > uint32((*TMemPage)(unsafe.Pointer(pPage)).FmaxLocal) {
|
|
nSize = libc.Uint32FromInt32(minLocal)
|
|
}
|
|
nSize = nSize + libc.Uint32FromInt32(int32(4)+libc.Int32FromUint16(libc.Uint16FromInt64(int64(pIter)-int64(pCell))))
|
|
}
|
|
return uint16(nSize)
|
|
}
|
|
|
|
func _cellSizePtrIdxLeaf(tls *libc.TLS, pPage uintptr, pCell uintptr) (r Tu16) {
|
|
var minLocal int32
|
|
var nSize Tu32
|
|
var pEnd, pIter, v1 uintptr
|
|
_, _, _, _, _ = minLocal, nSize, pEnd, pIter, v1
|
|
pIter = pCell /* Size value to return */
|
|
nSize = uint32(**(**Tu8)(__ccgo_up(pIter)))
|
|
if nSize >= uint32(0x80) {
|
|
pEnd = pIter + 8
|
|
nSize = nSize & uint32(0x7f)
|
|
for cond := true; cond; cond = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pIter))) >= int32(0x80) && pIter < pEnd {
|
|
pIter = pIter + 1
|
|
v1 = pIter
|
|
nSize = nSize<<libc.Int32FromInt32(7) | libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v1)))&libc.Int32FromInt32(0x7f))
|
|
}
|
|
}
|
|
pIter = pIter + 1
|
|
if nSize <= uint32((*TMemPage)(unsafe.Pointer(pPage)).FmaxLocal) {
|
|
nSize = nSize + libc.Uint32FromInt64(int64(pIter)-int64(pCell))
|
|
if nSize < uint32(4) {
|
|
nSize = uint32(4)
|
|
}
|
|
} else {
|
|
minLocal = libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FminLocal)
|
|
nSize = libc.Uint32FromInt32(minLocal) + (nSize-libc.Uint32FromInt32(minLocal))%((*TBtShared)(unsafe.Pointer((*TMemPage)(unsafe.Pointer(pPage)).FpBt)).FusableSize-uint32(4))
|
|
if nSize > uint32((*TMemPage)(unsafe.Pointer(pPage)).FmaxLocal) {
|
|
nSize = libc.Uint32FromInt32(minLocal)
|
|
}
|
|
nSize = nSize + libc.Uint32FromInt32(int32(4)+libc.Int32FromUint16(libc.Uint16FromInt64(int64(pIter)-int64(pCell))))
|
|
}
|
|
return uint16(nSize)
|
|
}
|
|
|
|
func _cellSizePtrNoPayload(tls *libc.TLS, pPage uintptr, pCell uintptr) (r Tu16) {
|
|
var pEnd, pIter, v1 uintptr
|
|
_, _, _ = pEnd, pIter, v1
|
|
pIter = pCell + uintptr(4) /* End mark for a varint */
|
|
_ = pPage
|
|
pEnd = pIter + uintptr(9)
|
|
for {
|
|
v1 = pIter
|
|
pIter = pIter + 1
|
|
if !(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v1)))&int32(0x80) != 0 && pIter < pEnd) {
|
|
break
|
|
}
|
|
}
|
|
return libc.Uint16FromInt64(int64(pIter) - int64(pCell))
|
|
}
|
|
|
|
func _cellSizePtrTableLeaf(tls *libc.TLS, pPage uintptr, pCell uintptr) (r Tu16) {
|
|
var minLocal int32
|
|
var nSize Tu32
|
|
var pEnd, pIter, v1, v11, v13, v2, v3, v5, v7, v9 uintptr
|
|
var v10, v12, v14, v16, v4, v6, v8 bool
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = minLocal, nSize, pEnd, pIter, v1, v10, v11, v12, v13, v14, v16, v2, v3, v4, v5, v6, v7, v8, v9
|
|
pIter = pCell /* Size value to return */
|
|
nSize = uint32(**(**Tu8)(__ccgo_up(pIter)))
|
|
if nSize >= uint32(0x80) {
|
|
pEnd = pIter + 8
|
|
nSize = nSize & uint32(0x7f)
|
|
for cond := true; cond; cond = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pIter))) >= int32(0x80) && pIter < pEnd {
|
|
pIter = pIter + 1
|
|
v1 = pIter
|
|
nSize = nSize<<libc.Int32FromInt32(7) | libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v1)))&libc.Int32FromInt32(0x7f))
|
|
}
|
|
}
|
|
pIter = pIter + 1
|
|
/* pIter now points at the 64-bit integer key value, a variable length
|
|
** integer. The following block moves pIter to point at the first byte
|
|
** past the end of the key value. */
|
|
v1 = pIter
|
|
pIter = pIter + 1
|
|
if v4 = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v1)))&int32(0x80) != 0; v4 {
|
|
v2 = pIter
|
|
pIter = pIter + 1
|
|
}
|
|
if v6 = v4 && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v2)))&int32(0x80) != 0; v6 {
|
|
v3 = pIter
|
|
pIter = pIter + 1
|
|
}
|
|
if v8 = v6 && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v3)))&int32(0x80) != 0; v8 {
|
|
v5 = pIter
|
|
pIter = pIter + 1
|
|
}
|
|
if v10 = v8 && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v5)))&int32(0x80) != 0; v10 {
|
|
v7 = pIter
|
|
pIter = pIter + 1
|
|
}
|
|
if v12 = v10 && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v7)))&int32(0x80) != 0; v12 {
|
|
v9 = pIter
|
|
pIter = pIter + 1
|
|
}
|
|
if v14 = v12 && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v9)))&int32(0x80) != 0; v14 {
|
|
v11 = pIter
|
|
pIter = pIter + 1
|
|
}
|
|
if v16 = v14 && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v11)))&int32(0x80) != 0; v16 {
|
|
v13 = pIter
|
|
pIter = pIter + 1
|
|
}
|
|
if v16 && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v13)))&int32(0x80) != 0 {
|
|
pIter = pIter + 1
|
|
}
|
|
if nSize <= uint32((*TMemPage)(unsafe.Pointer(pPage)).FmaxLocal) {
|
|
nSize = nSize + libc.Uint32FromInt64(int64(pIter)-int64(pCell))
|
|
if nSize < uint32(4) {
|
|
nSize = uint32(4)
|
|
}
|
|
} else {
|
|
minLocal = libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FminLocal)
|
|
nSize = libc.Uint32FromInt32(minLocal) + (nSize-libc.Uint32FromInt32(minLocal))%((*TBtShared)(unsafe.Pointer((*TMemPage)(unsafe.Pointer(pPage)).FpBt)).FusableSize-uint32(4))
|
|
if nSize > uint32((*TMemPage)(unsafe.Pointer(pPage)).FmaxLocal) {
|
|
nSize = libc.Uint32FromInt32(minLocal)
|
|
}
|
|
nSize = nSize + libc.Uint32FromInt32(int32(4)+libc.Int32FromUint16(libc.Uint16FromInt64(int64(pIter)-int64(pCell))))
|
|
}
|
|
return uint16(nSize)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The char() function takes zero or more arguments, each of which is
|
|
// ** an integer. It constructs a string where each character of the string
|
|
// ** is the unicode character for the corresponding integer argument.
|
|
// */
|
|
func _charFunc(tls *libc.TLS, context uintptr, argc int32, argv uintptr) {
|
|
var c uint32
|
|
var i int32
|
|
var x Tsqlite3_int64
|
|
var z, zOut, v1 uintptr
|
|
_, _, _, _, _, _ = c, i, x, z, zOut, v1
|
|
v1 = Xsqlite3_malloc64(tls, libc.Uint64FromInt32(argc*int32(4)+int32(1)))
|
|
z = v1
|
|
zOut = v1
|
|
if z == uintptr(0) {
|
|
Xsqlite3_result_error_nomem(tls, context)
|
|
return
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < argc) {
|
|
break
|
|
}
|
|
x = Xsqlite3_value_int64(tls, **(**uintptr)(__ccgo_up(argv + uintptr(i)*8)))
|
|
if x < 0 || x > int64(0x10ffff) {
|
|
x = int64(0xfffd)
|
|
}
|
|
c = libc.Uint32FromInt64(x & libc.Int64FromInt32(0x1fffff))
|
|
if c < uint32(0x00080) {
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(c & libc.Uint32FromInt32(0xFF))
|
|
} else {
|
|
if c < uint32(0x00800) {
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0xC0) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x1F))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c&libc.Uint32FromInt32(0x3F))))
|
|
} else {
|
|
if c < uint32(0x10000) {
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0xE0) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(12)&libc.Uint32FromInt32(0x0F))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x3F))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c&libc.Uint32FromInt32(0x3F))))
|
|
} else {
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0xF0) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(18)&libc.Uint32FromInt32(0x07))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(12)&libc.Uint32FromInt32(0x3F))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x3F))))
|
|
v1 = zOut
|
|
zOut = zOut + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c&libc.Uint32FromInt32(0x3F))))
|
|
}
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
**(**uint8)(__ccgo_up(zOut)) = uint8(0)
|
|
Xsqlite3_result_text64(tls, context, z, libc.Uint64FromInt64(int64(zOut)-int64(z)), __ccgo_fp(Xsqlite3_free), uint8(SQLITE_UTF8_ZT))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* This is the Walker callback from sqlite3ExprReferencesUpdatedColumn().
|
|
// * Set bit 0x01 of pWalker->eCode if pWalker->eCode to 0 and if this
|
|
// ** expression node references any of the
|
|
// ** columns that are being modified by an UPDATE statement.
|
|
// */
|
|
func _checkConstraintExprNode(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var v1 uintptr
|
|
_ = v1
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_COLUMN) {
|
|
if int32((*TExpr)(unsafe.Pointer(pExpr)).FiColumn) >= 0 {
|
|
if **(**int32)(__ccgo_up(*(*uintptr)(unsafe.Pointer(pWalker + 40)) + uintptr((*TExpr)(unsafe.Pointer(pExpr)).FiColumn)*4)) >= 0 {
|
|
v1 = pWalker + 36
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(CKCNSTRNT_COLUMN))
|
|
}
|
|
} else {
|
|
v1 = pWalker + 36
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(CKCNSTRNT_ROWID))
|
|
}
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Free the overflow pages associated with the given Cell.
|
|
// */
|
|
func _clearCellOverflow(tls *libc.TLS, pPage uintptr, pCell uintptr, pInfo uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var nOvfl, rc, v1 int32
|
|
var ovflPageSize Tu32
|
|
var ovflPgno TPgno
|
|
var pBt, v2 uintptr
|
|
var v3 bool
|
|
var _ /* iNext at bp+0 */ TPgno
|
|
var _ /* pOvfl at bp+8 */ uintptr
|
|
_, _, _, _, _, _, _, _ = nOvfl, ovflPageSize, ovflPgno, pBt, rc, v1, v2, v3
|
|
if pCell+uintptr((*TCellInfo)(unsafe.Pointer(pInfo)).FnSize) > (*TMemPage)(unsafe.Pointer(pPage)).FaDataEnd {
|
|
/* Cell extends past end of page */
|
|
return _sqlite3CorruptError(tls, int32(80222))
|
|
}
|
|
ovflPgno = _sqlite3Get4byte(tls, pCell+uintptr((*TCellInfo)(unsafe.Pointer(pInfo)).FnSize)-uintptr(4))
|
|
pBt = (*TMemPage)(unsafe.Pointer(pPage)).FpBt
|
|
ovflPageSize = (*TBtShared)(unsafe.Pointer(pBt)).FusableSize - uint32(4)
|
|
nOvfl = libc.Int32FromUint32(((*TCellInfo)(unsafe.Pointer(pInfo)).FnPayload - uint32((*TCellInfo)(unsafe.Pointer(pInfo)).FnLocal) + ovflPageSize - uint32(1)) / ovflPageSize)
|
|
for {
|
|
v1 = nOvfl
|
|
nOvfl = nOvfl - 1
|
|
if !(v1 != 0) {
|
|
break
|
|
}
|
|
**(**TPgno)(__ccgo_up(bp)) = uint32(0)
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = uintptr(0)
|
|
if ovflPgno < uint32(2) || ovflPgno > _btreePagecount(tls, pBt) {
|
|
/* 0 is not a legal page number and page 1 cannot be an
|
|
** overflow page. Therefore if ovflPgno<2 or past the end of the
|
|
** file the database must be corrupt. */
|
|
return _sqlite3CorruptError(tls, int32(80239))
|
|
}
|
|
if nOvfl != 0 {
|
|
rc = _getOverflowPage(tls, pBt, ovflPgno, bp+8, bp)
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
}
|
|
if v3 = **(**uintptr)(__ccgo_up(bp + 8)) != 0; !v3 {
|
|
v2 = _btreePageLookup(tls, pBt, ovflPgno)
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = v2
|
|
}
|
|
if (v3 || v2 != uintptr(0)) && _sqlite3PagerPageRefcount(tls, (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp + 8)))).FpDbPage) != int32(1) {
|
|
/* There is no reason any cursor should have an outstanding reference
|
|
** to an overflow page belonging to a cell that is being deleted/updated.
|
|
** So if there exists more than one reference to this page, then it
|
|
** must not really be an overflow page and the database must be corrupt.
|
|
** It is helpful to detect this before calling freePage2(), as
|
|
** freePage2() may zero the page contents if secure-delete mode is
|
|
** enabled. If this 'overflow' page happens to be a page that the
|
|
** caller is iterating through or using in some other way, this
|
|
** can be problematic.
|
|
*/
|
|
rc = _sqlite3CorruptError(tls, int32(80259))
|
|
} else {
|
|
rc = _freePage2(tls, pBt, **(**uintptr)(__ccgo_up(bp + 8)), ovflPgno)
|
|
}
|
|
if **(**uintptr)(__ccgo_up(bp + 8)) != 0 {
|
|
_sqlite3PagerUnref(tls, (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp + 8)))).FpDbPage)
|
|
}
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
ovflPgno = **(**TPgno)(__ccgo_up(bp))
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
/* Call xParseCell to compute the size of a cell. If the cell contains
|
|
** overflow, then invoke cellClearOverflow to clear out that overflow.
|
|
** Store the result code (SQLITE_OK or some error code) in rc.
|
|
**
|
|
** Implemented as macro to force inlining for performance.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Cursor iCur is open on an intkey b-tree (a table). Register iRowid contains
|
|
// ** a rowid value just read from cursor iIdxCur, open on index pIdx. This
|
|
// ** function generates code to do a deferred seek of cursor iCur to the
|
|
// ** rowid stored in register iRowid.
|
|
// **
|
|
// ** Normally, this is just:
|
|
// **
|
|
// ** OP_DeferredSeek $iCur $iRowid
|
|
// **
|
|
// ** Which causes a seek on $iCur to the row with rowid $iRowid.
|
|
// **
|
|
// ** However, if the scan currently being coded is a branch of an OR-loop and
|
|
// ** the statement currently being coded is a SELECT, then additional information
|
|
// ** is added that might allow OP_Column to omit the seek and instead do its
|
|
// ** lookup on the index, thus avoiding an expensive seek operation. To
|
|
// ** enable this optimization, the P3 of OP_DeferredSeek is set to iIdxCur
|
|
// ** and P4 is set to an array of integers containing one entry for each column
|
|
// ** in the table. For each table column, if the column is the i'th
|
|
// ** column of the index, then the corresponding array entry is set to (i+1).
|
|
// ** If the column does not appear in the index at all, the array entry is set
|
|
// ** to 0. The OP_Column opcode can check this array to see if the column it
|
|
// ** wants is in the index and if it is, it will substitute the index cursor
|
|
// ** and column number and continue with those new values, rather than seeking
|
|
// ** the table cursor.
|
|
// */
|
|
func _codeDeferredSeek(tls *libc.TLS, pWInfo uintptr, pIdx uintptr, iCur int32, iIdxCur int32) {
|
|
var ai, pParse, pTab, v, v1 uintptr
|
|
var i, x1, x2 int32
|
|
var v2 bool
|
|
_, _, _, _, _, _, _, _, _ = ai, i, pParse, pTab, v, x1, x2, v1, v2
|
|
pParse = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpParse /* Parse context */
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe /* Vdbe to generate code within */
|
|
libc.SetBitFieldPtr8Uint32(pWInfo+68, libc.Uint32FromInt32(1), 0, 0x1)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_DeferredSeek), iIdxCur, 0, iCur)
|
|
if v2 = libc.Int32FromUint16((*TWhereInfo)(unsafe.Pointer(pWInfo)).FwctrlFlags)&(libc.Int32FromInt32(WHERE_OR_SUBCLAUSE)|libc.Int32FromInt32(WHERE_RIGHT_JOIN)) != 0; v2 {
|
|
if (*TParse)(unsafe.Pointer(pParse)).FpToplevel != 0 {
|
|
v1 = (*TParse)(unsafe.Pointer(pParse)).FpToplevel
|
|
} else {
|
|
v1 = pParse
|
|
}
|
|
}
|
|
if v2 && (*TParse)(unsafe.Pointer(v1)).FwriteMask == uint32(0) {
|
|
pTab = (*TIndex)(unsafe.Pointer(pIdx)).FpTable
|
|
ai = _sqlite3DbMallocZero(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, uint64(uint64(4)*libc.Uint64FromInt32(int32((*TTable)(unsafe.Pointer(pTab)).FnCol)+libc.Int32FromInt32(1))))
|
|
if ai != 0 {
|
|
**(**Tu32)(__ccgo_up(ai)) = libc.Uint32FromInt16((*TTable)(unsafe.Pointer(pTab)).FnCol)
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn)-int32(1)) {
|
|
break
|
|
}
|
|
x1 = int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(i)*2)))
|
|
x2 = int32(_sqlite3TableColumnToStorage(tls, pTab, int16(x1)))
|
|
if x1 >= 0 {
|
|
**(**Tu32)(__ccgo_up(ai + uintptr(x2+int32(1))*4)) = libc.Uint32FromInt32(i + int32(1))
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_sqlite3VdbeChangeP4(tls, v, -int32(1), ai, -int32(15))
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code for a single X IN (....) term of the WHERE clause.
|
|
// **
|
|
// ** This is a special-case of codeEqualityTerm() that works for IN operators
|
|
// ** only. It is broken out into a subroutine because this case is
|
|
// ** uncommon and by splitting it off into a subroutine, the common case
|
|
// ** runs faster.
|
|
// **
|
|
// ** The current value for the constraint is left in register iTarget.
|
|
// ** This routine sets up a loop that will iterate over all values of X.
|
|
// */
|
|
func _codeINTerm(tls *libc.TLS, pParse uintptr, pTerm uintptr, pLevel uintptr, iEq int32, bRev int32, iTarget int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var aiMap, db, pIn, pLoop, pX, pXMod, v uintptr
|
|
var eType, i, iCol, iMap, iOut, nEq, v3, v5 int32
|
|
var _ /* iTab at bp+0 */ int32
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = aiMap, db, eType, i, iCol, iMap, iOut, nEq, pIn, pLoop, pX, pXMod, v, v3, v5
|
|
pX = (*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr
|
|
eType = int32(IN_INDEX_NOOP)
|
|
pLoop = (*TWhereLevel)(unsafe.Pointer(pLevel)).FpWLoop
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
nEq = 0
|
|
aiMap = uintptr(0)
|
|
if (*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags&uint32(WHERE_VIRTUALTABLE) == uint32(0) && (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FpIndex != uintptr(0) && **(**Tu8)(__ccgo_up((*TIndex)(unsafe.Pointer((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FpIndex)).FaSortOrder + uintptr(iEq))) != 0 {
|
|
bRev = libc.BoolInt32(!(bRev != 0))
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < iEq) {
|
|
break
|
|
}
|
|
if **(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pLoop)).FaLTerm + uintptr(i)*8)) != 0 && (*TWhereTerm)(unsafe.Pointer(**(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pLoop)).FaLTerm + uintptr(i)*8)))).FpExpr == pX {
|
|
_disableTerm(tls, pLevel, pTerm)
|
|
return
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
i = iEq
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pLoop)).FnLTerm)) {
|
|
break
|
|
}
|
|
if (*TWhereTerm)(unsafe.Pointer(**(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pLoop)).FaLTerm + uintptr(i)*8)))).FpExpr == pX {
|
|
nEq = nEq + 1
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
if !((*TExpr)(unsafe.Pointer(pX)).Fflags&libc.Uint32FromInt32(EP_xIsSelect) != libc.Uint32FromInt32(0)) || (*TExprList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pX + 32)))).FpEList)).FnExpr == int32(1) {
|
|
eType = _sqlite3FindInIndex(tls, pParse, pX, uint32(IN_INDEX_LOOP), uintptr(0), uintptr(0), bp)
|
|
} else {
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
pXMod = _removeUnindexableInClauseTerms(tls, pParse, iEq, pLoop, pX)
|
|
if !((*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0) {
|
|
aiMap = _sqlite3DbMallocZero(tls, db, uint64(uint64(4)*libc.Uint64FromInt32(nEq)))
|
|
eType = _sqlite3FindInIndex(tls, pParse, pXMod, uint32(IN_INDEX_LOOP), uintptr(0), aiMap, bp)
|
|
}
|
|
_sqlite3ExprDelete(tls, db, pXMod)
|
|
}
|
|
if eType == int32(IN_INDEX_INDEX_DESC) {
|
|
bRev = libc.BoolInt32(!(bRev != 0))
|
|
}
|
|
if bRev != 0 {
|
|
v3 = int32(OP_Last)
|
|
} else {
|
|
v3 = int32(OP_Rewind)
|
|
}
|
|
_sqlite3VdbeAddOp2(tls, v, v3, **(**int32)(__ccgo_up(bp)), 0)
|
|
**(**Tu32)(__ccgo_up(pLoop + 48)) |= uint32(WHERE_IN_ABLE)
|
|
if (*(*struct {
|
|
FnIn int32
|
|
FaInLoop uintptr
|
|
})(unsafe.Pointer(pLevel + 80))).FnIn == 0 {
|
|
(*TWhereLevel)(unsafe.Pointer(pLevel)).FaddrNxt = _sqlite3VdbeMakeLabel(tls, pParse)
|
|
}
|
|
if iEq > 0 && (*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags&uint32(WHERE_IN_SEEKSCAN) == uint32(0) {
|
|
**(**Tu32)(__ccgo_up(pLoop + 48)) |= uint32(WHERE_IN_EARLYOUT)
|
|
}
|
|
i = (*(*struct {
|
|
FnIn int32
|
|
FaInLoop uintptr
|
|
})(unsafe.Pointer(pLevel + 80))).FnIn
|
|
(*(*struct {
|
|
FnIn int32
|
|
FaInLoop uintptr
|
|
})(unsafe.Pointer(pLevel + 80))).FnIn += nEq
|
|
(*(*struct {
|
|
FnIn int32
|
|
FaInLoop uintptr
|
|
})(unsafe.Pointer(pLevel + 80))).FaInLoop = _sqlite3WhereRealloc(tls, (*TWhereClause)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pTerm)).FpWC)).FpWInfo, (*(*struct {
|
|
FnIn int32
|
|
FaInLoop uintptr
|
|
})(unsafe.Pointer(pLevel + 80))).FaInLoop, uint64(uint64(20)*libc.Uint64FromInt32((*(*struct {
|
|
FnIn int32
|
|
FaInLoop uintptr
|
|
})(unsafe.Pointer(pLevel + 80))).FnIn)))
|
|
pIn = (*(*struct {
|
|
FnIn int32
|
|
FaInLoop uintptr
|
|
})(unsafe.Pointer(pLevel + 80))).FaInLoop
|
|
if pIn != 0 {
|
|
iMap = 0 /* Index in aiMap[] */
|
|
pIn = pIn + uintptr(i)*20
|
|
i = iEq
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pLoop)).FnLTerm)) {
|
|
break
|
|
}
|
|
if (*TWhereTerm)(unsafe.Pointer(**(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pLoop)).FaLTerm + uintptr(i)*8)))).FpExpr == pX {
|
|
iOut = iTarget + i - iEq
|
|
if eType == int32(IN_INDEX_ROWID) {
|
|
(*TInLoop)(unsafe.Pointer(pIn)).FaddrInTop = _sqlite3VdbeAddOp2(tls, v, int32(OP_Rowid), **(**int32)(__ccgo_up(bp)), iOut)
|
|
} else {
|
|
if aiMap != 0 {
|
|
v5 = iMap
|
|
iMap = iMap + 1
|
|
v3 = **(**int32)(__ccgo_up(aiMap + uintptr(v5)*4))
|
|
} else {
|
|
v3 = 0
|
|
}
|
|
iCol = v3
|
|
(*TInLoop)(unsafe.Pointer(pIn)).FaddrInTop = _sqlite3VdbeAddOp3(tls, v, int32(OP_Column), **(**int32)(__ccgo_up(bp)), iCol, iOut)
|
|
}
|
|
_sqlite3VdbeAddOp1(tls, v, int32(OP_IsNull), iOut)
|
|
if i == iEq {
|
|
(*TInLoop)(unsafe.Pointer(pIn)).FiCur = **(**int32)(__ccgo_up(bp))
|
|
if bRev != 0 {
|
|
v3 = int32(OP_Prev)
|
|
} else {
|
|
v3 = int32(OP_Next)
|
|
}
|
|
(*TInLoop)(unsafe.Pointer(pIn)).FeEndLoopOp = libc.Uint8FromInt32(v3)
|
|
if iEq > 0 {
|
|
(*TInLoop)(unsafe.Pointer(pIn)).FiBase = iTarget - i
|
|
(*TInLoop)(unsafe.Pointer(pIn)).FnPrefix = i
|
|
} else {
|
|
(*TInLoop)(unsafe.Pointer(pIn)).FnPrefix = 0
|
|
}
|
|
} else {
|
|
(*TInLoop)(unsafe.Pointer(pIn)).FeEndLoopOp = uint8(OP_Noop)
|
|
}
|
|
pIn += 20
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if iEq > 0 && (*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags&libc.Uint32FromInt32(libc.Int32FromInt32(WHERE_IN_SEEKSCAN)|libc.Int32FromInt32(WHERE_VIRTUALTABLE)) == uint32(0) {
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_SeekHit), (*TWhereLevel)(unsafe.Pointer(pLevel)).FiIdxCur, 0, iEq)
|
|
}
|
|
} else {
|
|
(*(*struct {
|
|
FnIn int32
|
|
FaInLoop uintptr
|
|
})(unsafe.Pointer(pLevel + 80))).FnIn = 0
|
|
}
|
|
_sqlite3DbFree(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, aiMap)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Code an OP_TableLock instruction for each table locked by the
|
|
// ** statement (configured by calls to sqlite3TableLock()).
|
|
// */
|
|
func _codeTableLocks(tls *libc.TLS, pParse uintptr) {
|
|
var i, p1 int32
|
|
var p, pVdbe uintptr
|
|
_, _, _, _ = i, p, p1, pVdbe
|
|
pVdbe = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
i = 0
|
|
for {
|
|
if !(i < (*TParse)(unsafe.Pointer(pParse)).FnTableLock) {
|
|
break
|
|
}
|
|
p = (*TParse)(unsafe.Pointer(pParse)).FaTableLock + uintptr(i)*24
|
|
p1 = (*TTableLock)(unsafe.Pointer(p)).FiDb
|
|
_sqlite3VdbeAddOp4(tls, pVdbe, int32(OP_TableLock), p1, libc.Int32FromUint32((*TTableLock)(unsafe.Pointer(p)).FiTab), libc.Int32FromUint8((*TTableLock)(unsafe.Pointer(p)).FisWriteLock), (*TTableLock)(unsafe.Pointer(p)).FzLockName, -int32(1))
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Return TRUE if the given yDbMask object is empty - if it contains no
|
|
** 1 bits. This routine is used by the DbMaskAllZero() and DbMaskNotZero()
|
|
** macros when SQLITE_MAX_ATTACHED is greater than 30.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if any column of pIndex uses the zColl collation
|
|
// */
|
|
func _collationMatch(tls *libc.TLS, zColl uintptr, pIndex uintptr) (r int32) {
|
|
var i int32
|
|
var z uintptr
|
|
_, _ = i, z
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIndex)).FnColumn)) {
|
|
break
|
|
}
|
|
z = **(**uintptr)(__ccgo_up((*TIndex)(unsafe.Pointer(pIndex)).FazColl + uintptr(i)*8))
|
|
if 0 == _sqlite3StrICmp(tls, z, zColl) {
|
|
return int32(1)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if column iCol of table pTab seem like it might be a
|
|
// ** good column to use as part of a query-time index.
|
|
// **
|
|
// ** Current algorithm (subject to improvement!):
|
|
// **
|
|
// ** 1. If iCol is already the left-most column of some other index,
|
|
// ** then return false.
|
|
// **
|
|
// ** 2. If iCol is part of an existing index that has an aiRowLogEst of
|
|
// ** more than 20, then return false.
|
|
// **
|
|
// ** 3. If no disqualifying conditions above are found, return true.
|
|
// **
|
|
// ** 2025-01-03: I experimented with a new rule that returns false if the
|
|
// ** the datatype of the column is "BOOLEAN". This did not improve
|
|
// ** performance on any queries at hand, but it did burn CPU cycles, so the
|
|
// ** idea was not committed.
|
|
// */
|
|
func _columnIsGoodIndexCandidate(tls *libc.TLS, pTab uintptr, iCol int32) (r int32) {
|
|
var j int32
|
|
var pIdx uintptr
|
|
_, _ = j, pIdx
|
|
pIdx = (*TTable)(unsafe.Pointer(pTab)).FpIndex
|
|
for {
|
|
if !(pIdx != uintptr(0)) {
|
|
break
|
|
}
|
|
j = 0
|
|
for {
|
|
if !(j < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol)) {
|
|
break
|
|
}
|
|
if int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(j)*2))) == iCol {
|
|
if j == 0 {
|
|
return 0
|
|
}
|
|
if int32(uint32(*(*uint16)(unsafe.Pointer(pIdx + 100))&0x80>>7)) != 0 && int32(**(**TLogEst)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiRowLogEst + uintptr(j+int32(1))*2))) > int32(20) {
|
|
return 0
|
|
}
|
|
break
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
j = j + 1
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
pIdx = (*TIndex)(unsafe.Pointer(pIdx)).FpNext
|
|
}
|
|
return int32(1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Check to see if column iCol of the given statement is valid. If
|
|
// ** it is, return a pointer to the Mem for the value of that column.
|
|
// ** If iCol is not valid, return a pointer to a Mem which has a value
|
|
// ** of NULL.
|
|
// */
|
|
func _columnMem(tls *libc.TLS, pStmt uintptr, i int32) (r uintptr) {
|
|
var pOut, pVm uintptr
|
|
_, _ = pOut, pVm
|
|
pVm = pStmt
|
|
if pVm == uintptr(0) {
|
|
return _columnNullValue(tls)
|
|
}
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer((*TVdbe)(unsafe.Pointer(pVm)).Fdb)).Fmutex)
|
|
if (*TVdbe)(unsafe.Pointer(pVm)).FpResultRow != uintptr(0) && i < libc.Int32FromUint16((*TVdbe)(unsafe.Pointer(pVm)).FnResColumn) && i >= 0 {
|
|
pOut = (*TVdbe)(unsafe.Pointer(pVm)).FpResultRow + uintptr(i)*56
|
|
} else {
|
|
_sqlite3Error(tls, (*TVdbe)(unsafe.Pointer(pVm)).Fdb, int32(SQLITE_RANGE))
|
|
pOut = _columnNullValue(tls)
|
|
}
|
|
return pOut
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Convert the N-th element of pStmt->pColName[] into a string using
|
|
// ** xFunc() then return that string. If N is out of range, return 0.
|
|
// **
|
|
// ** There are up to 5 names for each column. useType determines which
|
|
// ** name is returned. Here are the names:
|
|
// **
|
|
// ** 0 The column name as it should be displayed for output
|
|
// ** 1 The datatype name for the column
|
|
// ** 2 The name of the database that the column derives from
|
|
// ** 3 The name of the table that the column derives from
|
|
// ** 4 The name of the table column that the result column derives from
|
|
// **
|
|
// ** If the result is not a simple column reference (if it is an expression
|
|
// ** or a constant) then useTypes 2, 3, and 4 return NULL.
|
|
// */
|
|
func _columnName(tls *libc.TLS, pStmt uintptr, N int32, useUtf16 int32, useType int32) (r uintptr) {
|
|
var db, p, ret uintptr
|
|
var i, n, v1 int32
|
|
var prior_mallocFailed Tu8
|
|
_, _, _, _, _, _, _ = db, i, n, p, prior_mallocFailed, ret, v1
|
|
if N < 0 {
|
|
return uintptr(0)
|
|
}
|
|
ret = uintptr(0)
|
|
p = pStmt
|
|
db = (*TVdbe)(unsafe.Pointer(p)).Fdb
|
|
Xsqlite3_mutex_enter(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0xc>>2)) != 0 {
|
|
if useType > 0 {
|
|
goto columnName_end
|
|
}
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0xc>>2)) == int32(1) {
|
|
v1 = int32(8)
|
|
} else {
|
|
v1 = int32(4)
|
|
}
|
|
n = v1
|
|
if N >= n {
|
|
goto columnName_end
|
|
}
|
|
if useUtf16 != 0 {
|
|
i = libc.Int32FromUint8(_iExplainColNames16[N+int32(8)*int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0xc>>2))-int32(8)])
|
|
ret = uintptr(unsafe.Pointer(&_azExplainColNames16data)) + uintptr(i)*2
|
|
} else {
|
|
ret = _azExplainColNames8[N+int32(8)*int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0xc>>2))-int32(8)]
|
|
}
|
|
goto columnName_end
|
|
}
|
|
n = libc.Int32FromUint16((*TVdbe)(unsafe.Pointer(p)).FnResColumn)
|
|
if N < n {
|
|
prior_mallocFailed = (*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed
|
|
N = N + useType*n
|
|
if useUtf16 != 0 {
|
|
ret = Xsqlite3_value_text16(tls, (*TVdbe)(unsafe.Pointer(p)).FaColName+uintptr(N)*56)
|
|
} else {
|
|
ret = Xsqlite3_value_text(tls, (*TVdbe)(unsafe.Pointer(p)).FaColName+uintptr(N)*56)
|
|
}
|
|
/* A malloc may have failed inside of the _text() call. If this
|
|
** is the case, clear the mallocFailed flag and return NULL.
|
|
*/
|
|
if libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed) > libc.Int32FromUint8(prior_mallocFailed) {
|
|
_sqlite3OomClear(tls, db)
|
|
ret = uintptr(0)
|
|
}
|
|
}
|
|
goto columnName_end
|
|
columnName_end:
|
|
;
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
return ret
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compute the iLimit and iOffset fields of the SELECT based on the
|
|
// ** pLimit expressions. pLimit->pLeft and pLimit->pRight hold the expressions
|
|
// ** that appear in the original SQL statement after the LIMIT and OFFSET
|
|
// ** keywords. Or NULL if those keywords are omitted. iLimit and iOffset
|
|
// ** are the integer memory register numbers for counters used to compute
|
|
// ** the limit and offset. If there is no limit and/or offset, then
|
|
// ** iLimit and iOffset are negative.
|
|
// **
|
|
// ** This routine changes the values of iLimit and iOffset only if
|
|
// ** a limit or offset is defined by pLimit->pLeft and pLimit->pRight. iLimit
|
|
// ** and iOffset should have been preset to appropriate default values (zero)
|
|
// ** prior to calling this routine.
|
|
// **
|
|
// ** The iOffset register (if it exists) is initialized to the value
|
|
// ** of the OFFSET. The iLimit register is initialized to LIMIT. Register
|
|
// ** iOffset+1 is initialized to LIMIT+OFFSET.
|
|
// **
|
|
// ** Only if pLimit->pLeft!=0 do the limit registers get
|
|
// ** redefined. The UNION ALL operator uses this property to force
|
|
// ** the reuse of the same limit and offset registers across multiple
|
|
// ** SELECT statements.
|
|
// */
|
|
func _computeLimitRegisters(tls *libc.TLS, pParse uintptr, p uintptr, iBreak int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iLimit, iOffset, v1, v2 int32
|
|
var pLimit, v, v3 uintptr
|
|
var _ /* n at bp+0 */ int32
|
|
_, _, _, _, _, _, _ = iLimit, iOffset, pLimit, v, v1, v2, v3
|
|
v = uintptr(0)
|
|
iLimit = 0
|
|
pLimit = (*TSelect)(unsafe.Pointer(p)).FpLimit
|
|
if (*TSelect)(unsafe.Pointer(p)).FiLimit != 0 {
|
|
return
|
|
}
|
|
/*
|
|
** "LIMIT -1" always shows all rows. There is some
|
|
** controversy about what the correct behavior should be.
|
|
** The current implementation interprets "LIMIT 0" to mean
|
|
** no rows.
|
|
*/
|
|
if pLimit != 0 {
|
|
v3 = pParse + 60
|
|
*(*int32)(unsafe.Pointer(v3)) = *(*int32)(unsafe.Pointer(v3)) + 1
|
|
v2 = *(*int32)(unsafe.Pointer(v3))
|
|
v1 = v2
|
|
iLimit = v1
|
|
(*TSelect)(unsafe.Pointer(p)).FiLimit = v1
|
|
v = _sqlite3GetVdbe(tls, pParse)
|
|
if _sqlite3ExprIsInteger(tls, (*TExpr)(unsafe.Pointer(pLimit)).FpLeft, bp, pParse) != 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Integer), **(**int32)(__ccgo_up(bp)), iLimit)
|
|
if **(**int32)(__ccgo_up(bp)) == 0 {
|
|
_sqlite3VdbeGoto(tls, v, iBreak)
|
|
} else {
|
|
if **(**int32)(__ccgo_up(bp)) >= 0 && int32((*TSelect)(unsafe.Pointer(p)).FnSelectRow) > int32(_sqlite3LogEst(tls, libc.Uint64FromInt32(**(**int32)(__ccgo_up(bp))))) {
|
|
(*TSelect)(unsafe.Pointer(p)).FnSelectRow = _sqlite3LogEst(tls, libc.Uint64FromInt32(**(**int32)(__ccgo_up(bp))))
|
|
**(**Tu32)(__ccgo_up(p + 4)) |= uint32(SF_FixedLimit)
|
|
}
|
|
}
|
|
} else {
|
|
_sqlite3ExprCode(tls, pParse, (*TExpr)(unsafe.Pointer(pLimit)).FpLeft, iLimit)
|
|
_sqlite3VdbeAddOp1(tls, v, int32(OP_MustBeInt), iLimit)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_IfNot), iLimit, iBreak)
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pLimit)).FpRight != 0 {
|
|
v3 = pParse + 60
|
|
*(*int32)(unsafe.Pointer(v3)) = *(*int32)(unsafe.Pointer(v3)) + 1
|
|
v2 = *(*int32)(unsafe.Pointer(v3))
|
|
v1 = v2
|
|
iOffset = v1
|
|
(*TSelect)(unsafe.Pointer(p)).FiOffset = v1
|
|
(*TParse)(unsafe.Pointer(pParse)).FnMem = (*TParse)(unsafe.Pointer(pParse)).FnMem + 1 /* Allocate an extra register for limit+offset */
|
|
_sqlite3ExprCode(tls, pParse, (*TExpr)(unsafe.Pointer(pLimit)).FpRight, iOffset)
|
|
_sqlite3VdbeAddOp1(tls, v, int32(OP_MustBeInt), iOffset)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_OffsetLimit), iLimit, iOffset+int32(1), iOffset)
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compute the maximum number of paths in the solver algorithm, for
|
|
// ** queries that have three or more terms in the FROM clause. Queries with
|
|
// ** two or fewer FROM clause terms are handled by the caller.
|
|
// **
|
|
// ** Query planning is NP-hard. We must limit the number of paths at
|
|
// ** each step of the solver search algorithm to avoid exponential behavior.
|
|
// **
|
|
// ** The value returned is a tuning parameter. Currently the value is:
|
|
// **
|
|
// ** 18 for star queries
|
|
// ** 12 otherwise
|
|
// **
|
|
// ** For the purposes of this heuristic, a star-query is defined as a query
|
|
// ** with a central "fact" table that is joined against multiple
|
|
// ** "dimension" tables, subject to the following constraints:
|
|
// **
|
|
// ** (aa) Only a five-way or larger join is considered for this
|
|
// ** optimization. If there are fewer than four terms in the FROM
|
|
// ** clause, this heuristic does not apply.
|
|
// **
|
|
// ** (bb) The join between the fact table and the dimension tables must
|
|
// ** be an INNER join. CROSS and OUTER JOINs do not qualify.
|
|
// **
|
|
// ** (cc) A table must have 3 or more dimension tables in order to be
|
|
// ** considered a fact table. (Was 4 prior to 2026-02-10.)
|
|
// **
|
|
// ** (dd) A table that is a self-join cannot be a dimension table.
|
|
// ** Dimension tables are joined against fact tables.
|
|
// **
|
|
// ** SIDE EFFECT: (and really the whole point of this subroutine)
|
|
// **
|
|
// ** If pWInfo describes a star-query, then the cost for SCANs of dimension
|
|
// ** WhereLoops is increased to be slightly larger than the cost of a SCAN
|
|
// ** in the fact table. Only SCAN costs are increased. SEARCH costs are
|
|
// ** unchanged. This heuristic helps keep fact tables in outer loops. Without
|
|
// ** this heuristic, paths with fact tables in outer loops tend to get pruned
|
|
// ** by the mxChoice limit on the number of paths, resulting in poor query
|
|
// ** plans. See the starschema1.test test module for examples of queries
|
|
// ** that need this heuristic to find good query plans.
|
|
// **
|
|
// ** This heuristic can be completely disabled, so that no query is
|
|
// ** considered a star-query, using SQLITE_TESTCTRL_OPTIMIZATION to
|
|
// ** disable the SQLITE_StarQuery optimization. In the CLI, the command
|
|
// ** to do that is: ".testctrl opt -starquery".
|
|
// **
|
|
// ** HISTORICAL NOTES:
|
|
// **
|
|
// ** This optimization was first added on 2024-05-09 by check-in 38db9b5c83d.
|
|
// ** The original optimization reduced the cost and output size estimate for
|
|
// ** fact tables to help them move to outer loops. But months later (as people
|
|
// ** started upgrading) performance regression reports started caming in,
|
|
// ** including:
|
|
// **
|
|
// ** forum post b18ef983e68d06d1 (2024-12-21)
|
|
// ** forum post 0025389d0860af82 (2025-01-14)
|
|
// ** forum post d87570a145599033 (2025-01-17)
|
|
// **
|
|
// ** To address these, the criteria for a star-query was tightened to exclude
|
|
// ** cases where the fact and dimensions are separated by an outer join, and
|
|
// ** the affect of star-schema detection was changed to increase the rRun cost
|
|
// ** on just full table scans of dimension tables, rather than reducing costs
|
|
// ** in the all access methods of the fact table.
|
|
// */
|
|
func _computeMxChoice(tls *libc.TLS, pWInfo uintptr) (r int32) {
|
|
var aFromTabs, pFactTab, pStart, pWLoop uintptr
|
|
var iFromIdx, nDep, nLoop, v5 int32
|
|
var m, mSeen, mSelfJoin TBitmask
|
|
var mxRun TLogEst
|
|
_, _, _, _, _, _, _, _, _, _, _, _ = aFromTabs, iFromIdx, m, mSeen, mSelfJoin, mxRun, nDep, nLoop, pFactTab, pStart, pWLoop, v5
|
|
nLoop = libc.Int32FromUint8((*TWhereInfo)(unsafe.Pointer(pWInfo)).FnLevel) /* For looping over WhereLoops */
|
|
if nLoop >= int32(4) && !(int32(uint32(*(*uint8)(unsafe.Pointer(pWInfo + 68))&0x10>>4)) != 0) && (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer((*TWhereInfo)(unsafe.Pointer(pWInfo)).FpParse)).Fdb)).FdbOptFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_StarQuery)) == uint32(0) { /* Bitmask for candidate fact-table */
|
|
mSelfJoin = uint64(0) /* Where to start searching for dimension-tables */
|
|
libc.SetBitFieldPtr8Uint32(pWInfo+68, libc.Uint32FromInt32(1), 4, 0x10) /* Only do this computation once */
|
|
/* Look for fact tables with three or more dimensions where the
|
|
** dimension tables are not separately from the fact tables by an outer
|
|
** or cross join. Adjust cost weights if found.
|
|
*/
|
|
aFromTabs = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpTabList + 8
|
|
pStart = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpLoops
|
|
iFromIdx = 0
|
|
m = libc.Uint64FromInt32(1)
|
|
for {
|
|
if !(iFromIdx < nLoop) {
|
|
break
|
|
}
|
|
nDep = 0 /* Maximum SCAN cost of a fact table */
|
|
mSeen = uint64(0) /* The candidate fact table */
|
|
pFactTab = aFromTabs + uintptr(iFromIdx)*80
|
|
if libc.Int32FromUint8((*TSrcItem)(unsafe.Pointer(pFactTab)).Ffg.Fjointype)&(libc.Int32FromInt32(JT_OUTER)|libc.Int32FromInt32(JT_CROSS)) != 0 {
|
|
/* If the candidate fact-table is the right table of an outer join
|
|
** restrict the search for dimension-tables to be tables to the right
|
|
** of the fact-table. Constraint (bb) */
|
|
if iFromIdx+int32(3) > nLoop {
|
|
break /* ^-- Impossible to reach nDep>=2 - Constraint (cc) */
|
|
}
|
|
for pStart != 0 && libc.Int32FromUint8((*TWhereLoop)(unsafe.Pointer(pStart)).FiTab) <= iFromIdx {
|
|
pStart = (*TWhereLoop)(unsafe.Pointer(pStart)).FpNextLoop
|
|
}
|
|
}
|
|
pWLoop = pStart
|
|
for {
|
|
if !(pWLoop != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((**(**TSrcItem)(__ccgo_up(aFromTabs + uintptr((*TWhereLoop)(unsafe.Pointer(pWLoop)).FiTab)*80))).Ffg.Fjointype)&(libc.Int32FromInt32(JT_OUTER)|libc.Int32FromInt32(JT_CROSS)) != 0 {
|
|
break /* Constraint (bb) */
|
|
}
|
|
if (*TWhereLoop)(unsafe.Pointer(pWLoop)).Fprereq&m != uint64(0) && (*TWhereLoop)(unsafe.Pointer(pWLoop)).FmaskSelf&mSeen == uint64(0) && (*TWhereLoop)(unsafe.Pointer(pWLoop)).FmaskSelf&mSelfJoin == uint64(0) {
|
|
if (**(**TSrcItem)(__ccgo_up(aFromTabs + uintptr((*TWhereLoop)(unsafe.Pointer(pWLoop)).FiTab)*80))).FpSTab == (*TSrcItem)(unsafe.Pointer(pFactTab)).FpSTab {
|
|
mSelfJoin = mSelfJoin | m
|
|
} else {
|
|
nDep = nDep + 1
|
|
mSeen = mSeen | (*TWhereLoop)(unsafe.Pointer(pWLoop)).FmaskSelf
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
pWLoop = (*TWhereLoop)(unsafe.Pointer(pWLoop)).FpNextLoop
|
|
}
|
|
if nDep <= int32(2) {
|
|
goto _1 /* Constraint (cc) */
|
|
}
|
|
/* If we reach this point, it means that pFactTab is a fact table
|
|
** with four or more dimensions connected by inner joins. Proceed
|
|
** to make cost adjustments. */
|
|
libc.SetBitFieldPtr8Uint32(pWInfo+68, libc.Uint32FromInt32(1), 5, 0x20)
|
|
/* Compute the maximum cost of any WhereLoop for the
|
|
** fact table plus one epsilon */
|
|
mxRun = int16(-libc.Int32FromInt32(32768))
|
|
pWLoop = pStart
|
|
for {
|
|
if !(pWLoop != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((*TWhereLoop)(unsafe.Pointer(pWLoop)).FiTab) < iFromIdx {
|
|
goto _3
|
|
}
|
|
if libc.Int32FromUint8((*TWhereLoop)(unsafe.Pointer(pWLoop)).FiTab) > iFromIdx {
|
|
break
|
|
}
|
|
if int32((*TWhereLoop)(unsafe.Pointer(pWLoop)).FrRun) > int32(mxRun) {
|
|
mxRun = (*TWhereLoop)(unsafe.Pointer(pWLoop)).FrRun
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
pWLoop = (*TWhereLoop)(unsafe.Pointer(pWLoop)).FpNextLoop
|
|
}
|
|
if int32(mxRun) < int32(LOGEST_MAX) {
|
|
mxRun = mxRun + 1
|
|
}
|
|
/* Increase the cost of table scans for dimension tables to be
|
|
** slightly more than the maximum cost of the fact table */
|
|
pWLoop = pStart
|
|
for {
|
|
if !(pWLoop != 0) {
|
|
break
|
|
}
|
|
if (*TWhereLoop)(unsafe.Pointer(pWLoop)).FmaskSelf&mSeen == uint64(0) {
|
|
goto _4
|
|
}
|
|
if (*TWhereLoop)(unsafe.Pointer(pWLoop)).FnLTerm != 0 {
|
|
goto _4
|
|
}
|
|
if int32((*TWhereLoop)(unsafe.Pointer(pWLoop)).FrRun) < int32(mxRun) {
|
|
(*TWhereLoop)(unsafe.Pointer(pWLoop)).FrRun = mxRun
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
pWLoop = (*TWhereLoop)(unsafe.Pointer(pWLoop)).FpNextLoop
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
iFromIdx = iFromIdx + 1
|
|
m = m << uint64(1)
|
|
}
|
|
}
|
|
if int32(uint32(*(*uint8)(unsafe.Pointer(pWInfo + 68))&0x20>>5)) != 0 {
|
|
v5 = int32(18)
|
|
} else {
|
|
v5 = int32(12)
|
|
}
|
|
return v5
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** We know that pSrc is an operand of an outer join. Return true if
|
|
// ** pTerm is a constraint that is compatible with that join.
|
|
// **
|
|
// ** pTerm must be EP_OuterON if pSrc is the right operand of an
|
|
// ** outer join. pTerm can be either EP_OuterON or EP_InnerON if pSrc
|
|
// ** is the left operand of a RIGHT join.
|
|
// **
|
|
// ** See https://sqlite.org/forum/forumpost/206d99a16dd9212f
|
|
// ** for an example of a WHERE clause constraints that may not be used on
|
|
// ** the right table of a RIGHT JOIN because the constraint implies a
|
|
// ** not-NULL condition on the left table of the RIGHT JOIN.
|
|
// */
|
|
func _constraintCompatibleWithOuterJoin(tls *libc.TLS, pTerm uintptr, pSrc uintptr) (r int32) {
|
|
/* By caller */
|
|
if !((*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)|libc.Int32FromInt32(EP_InnerON)) != libc.Uint32FromInt32(0)) || *(*int32)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr + 52)) != (*TSrcItem)(unsafe.Pointer(pSrc)).FiCursor {
|
|
return 0
|
|
}
|
|
if libc.Int32FromUint8((*TSrcItem)(unsafe.Pointer(pSrc)).Ffg.Fjointype)&(libc.Int32FromInt32(JT_LEFT)|libc.Int32FromInt32(JT_RIGHT)) != 0 && (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_InnerON)) != uint32(0) {
|
|
return 0
|
|
}
|
|
return int32(1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate nByte bytes of space using sqlite3Malloc(). If the
|
|
// ** allocation fails, call sqlite3_result_error_nomem() to notify
|
|
// ** the database handle that malloc() has failed and return NULL.
|
|
// ** If nByte is larger than the maximum string or blob length, then
|
|
// ** raise an SQLITE_TOOBIG exception and return NULL.
|
|
// */
|
|
func _contextMalloc(tls *libc.TLS, context uintptr, nByte Ti64) (r uintptr) {
|
|
var db, z uintptr
|
|
_, _ = db, z
|
|
db = Xsqlite3_context_db_handle(tls, context)
|
|
if nByte > int64(**(**int32)(__ccgo_up(db + 136))) {
|
|
Xsqlite3_result_error_toobig(tls, context)
|
|
z = uintptr(0)
|
|
} else {
|
|
z = _sqlite3Malloc(tls, libc.Uint64FromInt64(nByte))
|
|
if !(z != 0) {
|
|
Xsqlite3_result_error_nomem(tls, context)
|
|
}
|
|
}
|
|
return z
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine runs at the end of parsing a CREATE TABLE statement that
|
|
// ** has a WITHOUT ROWID clause. The job of this routine is to convert both
|
|
// ** internal schema data structures and the generated VDBE code so that they
|
|
// ** are appropriate for a WITHOUT ROWID table instead of a rowid table.
|
|
// ** Changes include:
|
|
// **
|
|
// ** (1) Set all columns of the PRIMARY KEY schema object to be NOT NULL.
|
|
// ** (2) Convert P3 parameter of the OP_CreateBtree from BTREE_INTKEY
|
|
// ** into BTREE_BLOBKEY.
|
|
// ** (3) Bypass the creation of the sqlite_schema table entry
|
|
// ** for the PRIMARY KEY as the primary key index is now
|
|
// ** identified by the sqlite_schema table entry of the table itself.
|
|
// ** (4) Set the Index.tnum of the PRIMARY KEY Index object in the
|
|
// ** schema to the rootpage from the main table.
|
|
// ** (5) Add all table columns to the PRIMARY KEY Index object
|
|
// ** so that the PRIMARY KEY is a covering index. The surplus
|
|
// ** columns are part of KeyInfo.nAllField and are not used for
|
|
// ** sorting or lookup or uniqueness checks.
|
|
// ** (6) Replace the rowid tail on all automatically generated UNIQUE
|
|
// ** indices with the PRIMARY KEY columns.
|
|
// **
|
|
// ** For virtual tables, only (1) is performed.
|
|
// */
|
|
func _convertToWithoutRowidTable(tls *libc.TLS, pParse uintptr, pTab uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var db, pIdx, pList, pPk, v, zColl, v12 uintptr
|
|
var i, j, n, nExtra, nPk, v3 int32
|
|
var v5 Tu16
|
|
var _ /* ipkToken at bp+0 */ TToken
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _ = db, i, j, n, nExtra, nPk, pIdx, pList, pPk, v, zColl, v12, v3, v5
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
/* Mark every PRIMARY KEY column as NOT NULL (except for imposter tables)
|
|
*/
|
|
if !(int32(uint32(*(*uint8)(unsafe.Pointer(db + 192 + 8))&0x6>>1)) != 0) {
|
|
i = 0
|
|
for {
|
|
if !(i < int32((*TTable)(unsafe.Pointer(pTab)).FnCol)) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint16((**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(i)*16))).FcolFlags)&int32(COLFLAG_PRIMKEY) != 0 && int32(uint32(*(*uint8)(unsafe.Pointer((*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(i)*16 + 8))&0xf>>0)) == OE_None {
|
|
libc.SetBitFieldPtr8Uint32((*TTable)(unsafe.Pointer(pTab)).FaCol+uintptr(i)*16+8, libc.Uint32FromInt32(OE_Abort), 0, 0xf)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
**(**Tu32)(__ccgo_up(pTab + 48)) |= uint32(TF_HasNotNull)
|
|
}
|
|
/* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY
|
|
** into BTREE_BLOBKEY.
|
|
*/
|
|
if (*(*struct {
|
|
FaddrCrTab int32
|
|
FregRowid int32
|
|
FregRoot int32
|
|
FconstraintName TToken
|
|
})(unsafe.Pointer(pParse + 256))).FaddrCrTab != 0 {
|
|
_sqlite3VdbeChangeP3(tls, v, (*(*struct {
|
|
FaddrCrTab int32
|
|
FregRowid int32
|
|
FregRoot int32
|
|
FconstraintName TToken
|
|
})(unsafe.Pointer(pParse + 256))).FaddrCrTab, int32(BTREE_BLOBKEY))
|
|
}
|
|
/* Locate the PRIMARY KEY index. Or, if this table was originally
|
|
** an INTEGER PRIMARY KEY table, create a new PRIMARY KEY index.
|
|
*/
|
|
if int32((*TTable)(unsafe.Pointer(pTab)).FiPKey) >= 0 {
|
|
_sqlite3TokenInit(tls, bp, (**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr((*TTable)(unsafe.Pointer(pTab)).FiPKey)*16))).FzCnName)
|
|
pList = _sqlite3ExprListAppend(tls, pParse, uintptr(0), _sqlite3ExprAlloc(tls, db, int32(TK_ID), bp, 0))
|
|
if pList == uintptr(0) {
|
|
**(**Tu32)(__ccgo_up(pTab + 48)) &= libc.Uint32FromInt32(^libc.Int32FromInt32(TF_WithoutRowid))
|
|
return
|
|
}
|
|
if libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) >= int32(PARSE_MODE_RENAME) {
|
|
_sqlite3RenameTokenRemap(tls, pParse, (*(*TExprList_item)(unsafe.Pointer(pList + 8))).FpExpr, pTab+52)
|
|
}
|
|
(*(*TExprList_item)(unsafe.Pointer(pList + 8))).Ffg.FsortFlags = (*TParse)(unsafe.Pointer(pParse)).FiPkSortOrder
|
|
(*TTable)(unsafe.Pointer(pTab)).FiPKey = int16(-int32(1))
|
|
_sqlite3CreateIndex(tls, pParse, uintptr(0), uintptr(0), uintptr(0), pList, libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FkeyConf), uintptr(0), uintptr(0), 0, 0, uint8(SQLITE_IDXTYPE_PRIMARYKEY))
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr != 0 {
|
|
**(**Tu32)(__ccgo_up(pTab + 48)) &= libc.Uint32FromInt32(^libc.Int32FromInt32(TF_WithoutRowid))
|
|
return
|
|
}
|
|
pPk = _sqlite3PrimaryKeyIndex(tls, pTab)
|
|
} else {
|
|
pPk = _sqlite3PrimaryKeyIndex(tls, pTab)
|
|
/*
|
|
** Remove all redundant columns from the PRIMARY KEY. For example, change
|
|
** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later
|
|
** code assumes the PRIMARY KEY contains no repeated columns.
|
|
*/
|
|
v3 = libc.Int32FromInt32(1)
|
|
j = v3
|
|
i = v3
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pPk)).FnKeyCol)) {
|
|
break
|
|
}
|
|
if _isDupColumn(tls, pPk, j, pPk, i) != 0 {
|
|
(*TIndex)(unsafe.Pointer(pPk)).FnColumn = (*TIndex)(unsafe.Pointer(pPk)).FnColumn - 1
|
|
} else {
|
|
**(**uintptr)(__ccgo_up((*TIndex)(unsafe.Pointer(pPk)).FazColl + uintptr(j)*8)) = **(**uintptr)(__ccgo_up((*TIndex)(unsafe.Pointer(pPk)).FazColl + uintptr(i)*8))
|
|
**(**Tu8)(__ccgo_up((*TIndex)(unsafe.Pointer(pPk)).FaSortOrder + uintptr(j))) = **(**Tu8)(__ccgo_up((*TIndex)(unsafe.Pointer(pPk)).FaSortOrder + uintptr(i)))
|
|
v3 = j
|
|
j = j + 1
|
|
**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pPk)).FaiColumn + uintptr(v3)*2)) = **(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pPk)).FaiColumn + uintptr(i)*2))
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
(*TIndex)(unsafe.Pointer(pPk)).FnKeyCol = libc.Uint16FromInt32(j)
|
|
}
|
|
libc.SetBitFieldPtr16Uint32(pPk+100, libc.Uint32FromInt32(1), 5, 0x20)
|
|
if !(int32(uint32(*(*uint8)(unsafe.Pointer(db + 192 + 8))&0x6>>1)) != 0) {
|
|
libc.SetBitFieldPtr16Uint32(pPk+100, libc.Uint32FromInt32(1), 3, 0x8)
|
|
}
|
|
v5 = (*TIndex)(unsafe.Pointer(pPk)).FnKeyCol
|
|
(*TIndex)(unsafe.Pointer(pPk)).FnColumn = v5
|
|
nPk = libc.Int32FromUint16(v5)
|
|
/* Bypass the creation of the PRIMARY KEY btree and the sqlite_schema
|
|
** table entry. This is only required if currently generating VDBE
|
|
** code for a CREATE TABLE (not when parsing one as part of reading
|
|
** a database schema). */
|
|
if v != 0 && (*TIndex)(unsafe.Pointer(pPk)).Ftnum > uint32(0) {
|
|
_sqlite3VdbeChangeOpcode(tls, v, libc.Int32FromUint32((*TIndex)(unsafe.Pointer(pPk)).Ftnum), uint8(OP_Goto))
|
|
}
|
|
/* The root page of the PRIMARY KEY is the table root page */
|
|
(*TIndex)(unsafe.Pointer(pPk)).Ftnum = (*TTable)(unsafe.Pointer(pTab)).Ftnum
|
|
/* Update the in-memory representation of all UNIQUE indices by converting
|
|
** the final rowid column into one or more columns of the PRIMARY KEY.
|
|
*/
|
|
pIdx = (*TTable)(unsafe.Pointer(pTab)).FpIndex
|
|
for {
|
|
if !(pIdx != 0) {
|
|
break
|
|
}
|
|
if int32(uint32(*(*uint16)(unsafe.Pointer(pIdx + 100))&0x3>>0)) == int32(SQLITE_IDXTYPE_PRIMARYKEY) {
|
|
goto _6
|
|
}
|
|
v3 = libc.Int32FromInt32(0)
|
|
n = v3
|
|
i = v3
|
|
for {
|
|
if !(i < nPk) {
|
|
break
|
|
}
|
|
if !(_isDupColumn(tls, pIdx, libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol), pPk, i) != 0) {
|
|
n = n + 1
|
|
}
|
|
goto _7
|
|
_7:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if n == 0 {
|
|
/* This index is a superset of the primary key */
|
|
(*TIndex)(unsafe.Pointer(pIdx)).FnColumn = (*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol
|
|
goto _6
|
|
}
|
|
if _resizeIndexObject(tls, pParse, pIdx, libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol)+n) != 0 {
|
|
return
|
|
}
|
|
i = 0
|
|
j = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol)
|
|
for {
|
|
if !(i < nPk) {
|
|
break
|
|
}
|
|
if !(_isDupColumn(tls, pIdx, libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol), pPk, i) != 0) {
|
|
**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(j)*2)) = **(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pPk)).FaiColumn + uintptr(i)*2))
|
|
**(**uintptr)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FazColl + uintptr(j)*8)) = **(**uintptr)(__ccgo_up((*TIndex)(unsafe.Pointer(pPk)).FazColl + uintptr(i)*8))
|
|
if **(**Tu8)(__ccgo_up((*TIndex)(unsafe.Pointer(pPk)).FaSortOrder + uintptr(i))) != 0 {
|
|
/* See ticket https://sqlite.org/src/info/bba7b69f9849b5bf */
|
|
libc.SetBitFieldPtr16Uint32(pIdx+100, libc.Uint32FromInt32(1), 9, 0x200)
|
|
}
|
|
j = j + 1
|
|
}
|
|
goto _9
|
|
_9:
|
|
;
|
|
i = i + 1
|
|
}
|
|
goto _6
|
|
_6:
|
|
;
|
|
pIdx = (*TIndex)(unsafe.Pointer(pIdx)).FpNext
|
|
}
|
|
/* Add all table columns to the PRIMARY KEY index
|
|
*/
|
|
nExtra = 0
|
|
i = 0
|
|
for {
|
|
if !(i < int32((*TTable)(unsafe.Pointer(pTab)).FnCol)) {
|
|
break
|
|
}
|
|
if !(_hasColumn(tls, (*TIndex)(unsafe.Pointer(pPk)).FaiColumn, nPk, i) != 0) && libc.Int32FromUint16((**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(i)*16))).FcolFlags)&int32(COLFLAG_VIRTUAL) == 0 {
|
|
nExtra = nExtra + 1
|
|
}
|
|
goto _10
|
|
_10:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if _resizeIndexObject(tls, pParse, pPk, nPk+nExtra) != 0 {
|
|
return
|
|
}
|
|
i = 0
|
|
j = nPk
|
|
for {
|
|
if !(i < int32((*TTable)(unsafe.Pointer(pTab)).FnCol)) {
|
|
break
|
|
}
|
|
if !(_hasColumn(tls, (*TIndex)(unsafe.Pointer(pPk)).FaiColumn, j, i) != 0) && libc.Int32FromUint16((**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(i)*16))).FcolFlags)&int32(COLFLAG_VIRTUAL) == 0 {
|
|
zColl = _sqlite3ColumnColl(tls, (*TTable)(unsafe.Pointer(pTab)).FaCol+uintptr(i)*16)
|
|
**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pPk)).FaiColumn + uintptr(j)*2)) = int16(i)
|
|
if zColl != 0 {
|
|
v12 = zColl
|
|
} else {
|
|
v12 = uintptr(unsafe.Pointer(&_sqlite3StrBINARY))
|
|
}
|
|
**(**uintptr)(__ccgo_up((*TIndex)(unsafe.Pointer(pPk)).FazColl + uintptr(j)*8)) = v12
|
|
j = j + 1
|
|
}
|
|
goto _11
|
|
_11:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_recomputeColumnsNotIndexed(tls, pPk)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true (non-zero) if pCur is current pointing to the last
|
|
// ** page of a table.
|
|
// */
|
|
func _cursorOnLastPage(tls *libc.TLS, pCur uintptr) (r int32) {
|
|
var i int32
|
|
var pPage uintptr
|
|
_, _ = i, pPage
|
|
i = 0
|
|
for {
|
|
if !(i < int32((*TBtCursor)(unsafe.Pointer(pCur)).FiPage)) {
|
|
break
|
|
}
|
|
pPage = **(**uintptr)(__ccgo_up(pCur + 144 + uintptr(i)*8))
|
|
if libc.Int32FromUint16(**(**Tu16)(__ccgo_up(pCur + 88 + uintptr(i)*2))) < libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell) {
|
|
return 0
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return int32(1)
|
|
}
|
|
|
|
func _dbpageColumn(tls *libc.TLS, pCursor uintptr, ctx uintptr, i int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var db, pCsr uintptr
|
|
var rc int32
|
|
var _ /* pDbPage at bp+0 */ uintptr
|
|
_, _, _ = db, pCsr, rc
|
|
pCsr = pCursor
|
|
rc = SQLITE_OK
|
|
switch i {
|
|
case 0: /* pgno */
|
|
Xsqlite3_result_int64(tls, ctx, libc.Int64FromUint32((*TDbpageCursor)(unsafe.Pointer(pCsr)).Fpgno))
|
|
case int32(1): /* data */
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
if (*TDbpageCursor)(unsafe.Pointer(pCsr)).Fpgno == libc.Uint32FromInt32(_sqlite3PendingByte/(*TDbpageCursor)(unsafe.Pointer(pCsr)).FszPage+libc.Int32FromInt32(1)) {
|
|
/* The pending byte page. Assume it is zeroed out. Attempting to
|
|
** request this page from the page is an SQLITE_CORRUPT error. */
|
|
Xsqlite3_result_zeroblob(tls, ctx, (*TDbpageCursor)(unsafe.Pointer(pCsr)).FszPage)
|
|
} else {
|
|
rc = _sqlite3PagerGet(tls, (*TDbpageCursor)(unsafe.Pointer(pCsr)).FpPager, (*TDbpageCursor)(unsafe.Pointer(pCsr)).Fpgno, bp, 0)
|
|
if rc == SQLITE_OK {
|
|
Xsqlite3_result_blob(tls, ctx, _sqlite3PagerGetData(tls, **(**uintptr)(__ccgo_up(bp))), (*TDbpageCursor)(unsafe.Pointer(pCsr)).FszPage, uintptr(-libc.Int32FromInt32(1)))
|
|
}
|
|
_sqlite3PagerUnref(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
}
|
|
default: /* schema */
|
|
db = Xsqlite3_context_db_handle(tls, ctx)
|
|
Xsqlite3_result_text(tls, ctx, (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr((*TDbpageCursor)(unsafe.Pointer(pCsr)).FiDb)*32))).FzDbSName, -int32(1), libc.UintptrFromInt32(0))
|
|
break
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** idxNum:
|
|
// **
|
|
// ** 0 schema=main, full table scan
|
|
// ** 1 schema=main, pgno=?1
|
|
// ** 2 schema=?1, full table scan
|
|
// ** 3 schema=?1, pgno=?2
|
|
// **
|
|
// ** idxStr is not used
|
|
// */
|
|
func _dbpageFilter(tls *libc.TLS, pCursor uintptr, idxNum int32, idxStr uintptr, argc int32, argv uintptr) (r int32) {
|
|
var db, pBt, pCsr, pTab, zSchema uintptr
|
|
var iPg Ti64
|
|
var rc int32
|
|
_, _, _, _, _, _, _ = db, iPg, pBt, pCsr, pTab, rc, zSchema
|
|
pCsr = pCursor
|
|
pTab = (*Tsqlite3_vtab_cursor)(unsafe.Pointer(pCursor)).FpVtab
|
|
db = (*TDbpageTable)(unsafe.Pointer(pTab)).Fdb
|
|
_ = idxStr
|
|
_ = argc
|
|
/* Default setting is no rows of result */
|
|
(*TDbpageCursor)(unsafe.Pointer(pCsr)).Fpgno = uint32(1)
|
|
(*TDbpageCursor)(unsafe.Pointer(pCsr)).FmxPgno = uint32(0)
|
|
if idxNum&int32(2) != 0 {
|
|
zSchema = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
(*TDbpageCursor)(unsafe.Pointer(pCsr)).FiDb = _sqlite3FindDbName(tls, db, zSchema)
|
|
if (*TDbpageCursor)(unsafe.Pointer(pCsr)).FiDb < 0 {
|
|
return SQLITE_OK
|
|
}
|
|
} else {
|
|
(*TDbpageCursor)(unsafe.Pointer(pCsr)).FiDb = 0
|
|
}
|
|
pBt = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr((*TDbpageCursor)(unsafe.Pointer(pCsr)).FiDb)*32))).FpBt
|
|
if pBt == uintptr(0) {
|
|
return SQLITE_OK
|
|
}
|
|
(*TDbpageCursor)(unsafe.Pointer(pCsr)).FpPager = _sqlite3BtreePager(tls, pBt)
|
|
(*TDbpageCursor)(unsafe.Pointer(pCsr)).FszPage = _sqlite3BtreeGetPageSize(tls, pBt)
|
|
(*TDbpageCursor)(unsafe.Pointer(pCsr)).FmxPgno = _sqlite3BtreeLastPage(tls, pBt)
|
|
if idxNum&int32(1) != 0 {
|
|
iPg = Xsqlite3_value_int64(tls, **(**uintptr)(__ccgo_up(argv + uintptr(idxNum>>int32(1))*8)))
|
|
if iPg < int64(1) || iPg > libc.Int64FromUint32((*TDbpageCursor)(unsafe.Pointer(pCsr)).FmxPgno) {
|
|
(*TDbpageCursor)(unsafe.Pointer(pCsr)).Fpgno = uint32(1)
|
|
(*TDbpageCursor)(unsafe.Pointer(pCsr)).FmxPgno = uint32(0)
|
|
} else {
|
|
(*TDbpageCursor)(unsafe.Pointer(pCsr)).Fpgno = libc.Uint32FromInt64(iPg)
|
|
(*TDbpageCursor)(unsafe.Pointer(pCsr)).FmxPgno = (*TDbpageCursor)(unsafe.Pointer(pCsr)).Fpgno
|
|
}
|
|
} else {
|
|
}
|
|
if (*TDbpageCursor)(unsafe.Pointer(pCsr)).FpPage1 != 0 {
|
|
_sqlite3PagerUnrefPageOne(tls, (*TDbpageCursor)(unsafe.Pointer(pCsr)).FpPage1)
|
|
}
|
|
rc = _sqlite3PagerGet(tls, (*TDbpageCursor)(unsafe.Pointer(pCsr)).FpPager, uint32(1), pCsr+24, 0)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Remove the memory data structures associated with the given
|
|
// ** Table. No changes are made to disk by this routine.
|
|
// **
|
|
// ** This routine just deletes the data structure. It does not unlink
|
|
// ** the table data structure from the hash table. But it does destroy
|
|
// ** memory structures of the indices and foreign keys associated with
|
|
// ** the table.
|
|
// **
|
|
// ** The db parameter is optional. It is needed if the Table object
|
|
// ** contains lookaside memory. (Table objects in the schema do not use
|
|
// ** lookaside memory, but some ephemeral Table objects do.) Or the
|
|
// ** db parameter can be used with db->pnBytesFreed to measure the memory
|
|
// ** used by the Table object.
|
|
// */
|
|
func _deleteTable(tls *libc.TLS, db uintptr, pTable uintptr) {
|
|
var pIndex, pNext, zName uintptr
|
|
_, _, _ = pIndex, pNext, zName
|
|
/* Delete all indices associated with this table. */
|
|
pIndex = (*TTable)(unsafe.Pointer(pTable)).FpIndex
|
|
for {
|
|
if !(pIndex != 0) {
|
|
break
|
|
}
|
|
pNext = (*TIndex)(unsafe.Pointer(pIndex)).FpNext
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FpnBytesFreed == uintptr(0) && !(libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTable)).FeTabType) == libc.Int32FromInt32(TABTYP_VTAB)) {
|
|
zName = (*TIndex)(unsafe.Pointer(pIndex)).FzName
|
|
_sqlite3HashInsert(tls, (*TIndex)(unsafe.Pointer(pIndex)).FpSchema+32, zName, uintptr(0))
|
|
}
|
|
_sqlite3FreeIndex(tls, db, pIndex)
|
|
goto _1
|
|
_1:
|
|
;
|
|
pIndex = pNext
|
|
}
|
|
if libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTable)).FeTabType) == TABTYP_NORM {
|
|
_sqlite3FkDelete(tls, db, pTable)
|
|
} else {
|
|
if libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTable)).FeTabType) == int32(TABTYP_VTAB) {
|
|
_sqlite3VtabClear(tls, db, pTable)
|
|
} else {
|
|
_sqlite3SelectDelete(tls, db, (*(*struct {
|
|
FpSelect uintptr
|
|
})(unsafe.Pointer(&(*TTable)(unsafe.Pointer(pTable)).Fu))).FpSelect)
|
|
}
|
|
}
|
|
/* Delete the Table structure itself.
|
|
*/
|
|
_sqlite3DeleteColumnNames(tls, db, pTable)
|
|
_sqlite3DbFree(tls, db, (*TTable)(unsafe.Pointer(pTable)).FzName)
|
|
_sqlite3DbFree(tls, db, (*TTable)(unsafe.Pointer(pTable)).FzColAff)
|
|
_sqlite3ExprListDelete(tls, db, (*TTable)(unsafe.Pointer(pTable)).FpCheck)
|
|
_sqlite3DbFree(tls, db, pTable)
|
|
/* Verify that no lookaside memory was used by schema tables */
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Disable a term in the WHERE clause. Except, do not disable the term
|
|
// ** if it controls a LEFT OUTER JOIN and it did not originate in the ON
|
|
// ** or USING clause of that join.
|
|
// **
|
|
// ** Consider the term t2.z='ok' in the following queries:
|
|
// **
|
|
// ** (1) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x WHERE t2.z='ok'
|
|
// ** (2) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x AND t2.z='ok'
|
|
// ** (3) SELECT * FROM t1, t2 WHERE t1.a=t2.x AND t2.z='ok'
|
|
// **
|
|
// ** The t2.z='ok' is disabled in the in (2) because it originates
|
|
// ** in the ON clause. The term is disabled in (3) because it is not part
|
|
// ** of a LEFT OUTER JOIN. In (1), the term is not disabled.
|
|
// **
|
|
// ** Disabling a term causes that term to not be tested in the inner loop
|
|
// ** of the join. Disabling is an optimization. When terms are satisfied
|
|
// ** by indices, we disable them to prevent redundant tests in the inner
|
|
// ** loop. We would get the correct results if nothing were ever disabled,
|
|
// ** but joins might run a little slower. The trick is to disable as much
|
|
// ** as we can without disabling too much. If we disabled in (1), we'd get
|
|
// ** the wrong answer. See ticket #813.
|
|
// **
|
|
// ** If all the children of a term are disabled, then that term is also
|
|
// ** automatically disabled. In this way, terms get disabled if derived
|
|
// ** virtual terms are tested first. For example:
|
|
// **
|
|
// ** x GLOB 'abc*' AND x>='abc' AND x<'acd'
|
|
// ** \___________/ \______/ \_____/
|
|
// ** parent child1 child2
|
|
// **
|
|
// ** Only the parent term was in the original WHERE clause. The child1
|
|
// ** and child2 terms were added by the LIKE optimization. If both of
|
|
// ** the virtual child terms are valid, then testing of the parent can be
|
|
// ** skipped.
|
|
// **
|
|
// ** Usually the parent term is marked as TERM_CODED. But if the parent
|
|
// ** term was originally TERM_LIKE, then the parent gets TERM_LIKECOND instead.
|
|
// ** The TERM_LIKECOND marking indicates that the term should be coded inside
|
|
// ** a conditional such that is only evaluated on the second pass of a
|
|
// ** LIKE-optimization loop, when scanning BLOBs instead of strings.
|
|
// */
|
|
func _disableTerm(tls *libc.TLS, pLevel uintptr, pTerm uintptr) {
|
|
var nLoop int32
|
|
var v1 uintptr
|
|
_, _ = nLoop, v1
|
|
nLoop = 0
|
|
for libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FwtFlags)&int32(TERM_CODED) == 0 && ((*TWhereLevel)(unsafe.Pointer(pLevel)).FiLeftJoin == 0 || (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)) != uint32(0)) && (*TWhereLevel)(unsafe.Pointer(pLevel)).FnotReady&(*TWhereTerm)(unsafe.Pointer(pTerm)).FprereqAll == uint64(0) {
|
|
if nLoop != 0 && libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FwtFlags)&int32(TERM_LIKE) != 0 {
|
|
v1 = pTerm + 18
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(TERM_LIKECOND))
|
|
} else {
|
|
v1 = pTerm + 18
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(TERM_CODED))
|
|
}
|
|
if (*TWhereTerm)(unsafe.Pointer(pTerm)).FiParent < 0 {
|
|
break
|
|
}
|
|
pTerm = (*TWhereClause)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pTerm)).FpWC)).Fa + uintptr((*TWhereTerm)(unsafe.Pointer(pTerm)).FiParent)*56
|
|
(*TWhereTerm)(unsafe.Pointer(pTerm)).FnChild = (*TWhereTerm)(unsafe.Pointer(pTerm)).FnChild - 1
|
|
if libc.Int32FromUint8((*TWhereTerm)(unsafe.Pointer(pTerm)).FnChild) != 0 {
|
|
break
|
|
}
|
|
nLoop = nLoop + 1
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Check to see if a subquery contains result-set columns that are
|
|
// ** never used. If it does, change the value of those result-set columns
|
|
// ** to NULL so that they do not cause unnecessary work to compute.
|
|
// **
|
|
// ** Return the number of column that were changed to NULL.
|
|
// */
|
|
func _disableUnusedSubqueryResultColumns(tls *libc.TLS, pItem uintptr) (r int32) {
|
|
var colUsed, m TBitmask
|
|
var iCol Tu16
|
|
var j, nChng, nCol, v3 int32
|
|
var pList, pSub, pTab, pX, pY uintptr
|
|
var v5 uint64
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _ = colUsed, iCol, j, m, nChng, nCol, pList, pSub, pTab, pX, pY, v3, v5 /* Column number */
|
|
nChng = 0 /* Columns that may not be NULLed out */
|
|
if int32(*(*uint32)(unsafe.Pointer(pItem + 24 + 4))&0x10>>4) != 0 || int32(*(*uint32)(unsafe.Pointer(pItem + 24 + 4))&0x200>>9) != 0 {
|
|
return 0
|
|
}
|
|
pTab = (*TSrcItem)(unsafe.Pointer(pItem)).FpSTab
|
|
pSub = (*TSubquery)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pItem + 72)))).FpSelect
|
|
pX = pSub
|
|
for {
|
|
if !(pX != 0) {
|
|
break
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(pX)).FselFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SF_Distinct)|libc.Int32FromInt32(SF_Aggregate)) != uint32(0) {
|
|
return 0
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(pX)).FpPrior != 0 && libc.Int32FromUint8((*TSelect)(unsafe.Pointer(pX)).Fop) != int32(TK_ALL) {
|
|
/* This optimization does not work for compound subqueries that
|
|
** use UNION, INTERSECT, or EXCEPT. Only UNION ALL is allowed. */
|
|
return 0
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(pX)).FpWin != 0 {
|
|
/* This optimization does not work for subqueries that use window
|
|
** functions. */
|
|
return 0
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
pX = (*TSelect)(unsafe.Pointer(pX)).FpPrior
|
|
}
|
|
colUsed = (*TSrcItem)(unsafe.Pointer(pItem)).FcolUsed
|
|
if (*TSelect)(unsafe.Pointer(pSub)).FpOrderBy != 0 {
|
|
pList = (*TSelect)(unsafe.Pointer(pSub)).FpOrderBy
|
|
j = 0
|
|
for {
|
|
if !(j < (*TExprList)(unsafe.Pointer(pList)).FnExpr) {
|
|
break
|
|
}
|
|
iCol = *(*Tu16)(unsafe.Pointer(pList + 8 + uintptr(j)*32 + 24))
|
|
if libc.Int32FromUint16(iCol) > 0 {
|
|
iCol = iCol - 1
|
|
if libc.Int32FromUint16(iCol) >= libc.Int32FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(8)) {
|
|
v3 = libc.Int32FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(8)) - libc.Int32FromInt32(1)
|
|
} else {
|
|
v3 = libc.Int32FromUint16(iCol)
|
|
}
|
|
colUsed = colUsed | libc.Uint64FromInt32(1)<<v3
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
j = j + 1
|
|
}
|
|
}
|
|
nCol = int32((*TTable)(unsafe.Pointer(pTab)).FnCol)
|
|
j = 0
|
|
for {
|
|
if !(j < nCol) {
|
|
break
|
|
}
|
|
if j < libc.Int32FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(8))-libc.Int32FromInt32(1) {
|
|
v5 = libc.Uint64FromInt32(1) << j
|
|
} else {
|
|
v5 = libc.Uint64FromInt32(1) << (libc.Int32FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(8)) - libc.Int32FromInt32(1))
|
|
}
|
|
m = v5
|
|
if m&colUsed != uint64(0) {
|
|
goto _4
|
|
}
|
|
pX = pSub
|
|
for {
|
|
if !(pX != 0) {
|
|
break
|
|
}
|
|
pY = (*(*TExprList_item)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pX)).FpEList + 8 + uintptr(j)*32))).FpExpr
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pY)).Fop) == int32(TK_NULL) {
|
|
goto _6
|
|
}
|
|
(*TExpr)(unsafe.Pointer(pY)).Fop = uint8(TK_NULL)
|
|
**(**Tu32)(__ccgo_up(pY + 4)) &= ^libc.Uint32FromInt32(libc.Int32FromInt32(EP_Skip) | libc.Int32FromInt32(EP_Unlikely))
|
|
**(**Tu32)(__ccgo_up(pX + 4)) |= uint32(SF_PushDown)
|
|
nChng = nChng + 1
|
|
goto _6
|
|
_6:
|
|
;
|
|
pX = (*TSelect)(unsafe.Pointer(pX)).FpPrior
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
j = j + 1
|
|
}
|
|
return nChng
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Disconnect all sqlite3_vtab objects that belong to database connection
|
|
// ** db. This is called when db is being closed.
|
|
// */
|
|
func _disconnectAllVtab(tls *libc.TLS, db uintptr) {
|
|
var i int32
|
|
var p, pMod, pSchema, pTab uintptr
|
|
_, _, _, _, _ = i, p, pMod, pSchema, pTab
|
|
_sqlite3BtreeEnterAll(tls, db)
|
|
i = 0
|
|
for {
|
|
if !(i < (*Tsqlite3)(unsafe.Pointer(db)).FnDb) {
|
|
break
|
|
}
|
|
pSchema = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(i)*32))).FpSchema
|
|
if pSchema != 0 {
|
|
p = (*THash)(unsafe.Pointer(pSchema + 8)).Ffirst
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
pTab = (*THashElem)(unsafe.Pointer(p)).Fdata
|
|
if libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == int32(TABTYP_VTAB) {
|
|
_sqlite3VtabDisconnect(tls, db, pTab)
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
p = (*THashElem)(unsafe.Pointer(p)).Fnext
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
p = (*THash)(unsafe.Pointer(db + 576)).Ffirst
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
pMod = (*THashElem)(unsafe.Pointer(p)).Fdata
|
|
if (*TModule)(unsafe.Pointer(pMod)).FpEpoTab != 0 {
|
|
_sqlite3VtabDisconnect(tls, db, (*TModule)(unsafe.Pointer(pMod)).FpEpoTab)
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
p = (*THashElem)(unsafe.Pointer(p)).Fnext
|
|
}
|
|
_sqlite3VtabUnlockList(tls, db)
|
|
_sqlite3BtreeLeaveAll(tls, db)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function returns the space in bytes required to store the copy
|
|
// ** of the Expr structure and a copy of the Expr.u.zToken string (if that
|
|
// ** string is defined.)
|
|
// */
|
|
func _dupedExprNodeSize(tls *libc.TLS, p uintptr, flags int32) (r int32) {
|
|
var nByte int32
|
|
_ = nByte
|
|
nByte = _dupedExprStructSize(tls, p, flags) & int32(0xfff)
|
|
if !((*TExpr)(unsafe.Pointer(p)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_IntValue)) != libc.Uint32FromInt32(0)) && *(*uintptr)(unsafe.Pointer(p + 8)) != 0 {
|
|
nByte = libc.Int32FromUint64(uint64(nByte) + (libc.Xstrlen(tls, *(*uintptr)(unsafe.Pointer(p + 8)))&libc.Uint64FromInt32(0x3fffffff) + libc.Uint64FromInt32(1)))
|
|
}
|
|
return (nByte + int32(7)) & ^libc.Int32FromInt32(7)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The dupedExpr*Size() routines each return the number of bytes required
|
|
// ** to store a copy of an expression or expression tree. They differ in
|
|
// ** how much of the tree is measured.
|
|
// **
|
|
// ** dupedExprStructSize() Size of only the Expr structure
|
|
// ** dupedExprNodeSize() Size of Expr + space for token
|
|
// ** dupedExprSize() Expr + token + subtree components
|
|
// **
|
|
// ***************************************************************************
|
|
// **
|
|
// ** The dupedExprStructSize() function returns two values OR-ed together:
|
|
// ** (1) the space required for a copy of the Expr structure only and
|
|
// ** (2) the EP_xxx flags that indicate what the structure size should be.
|
|
// ** The return values is always one of:
|
|
// **
|
|
// ** EXPR_FULLSIZE
|
|
// ** EXPR_REDUCEDSIZE | EP_Reduced
|
|
// ** EXPR_TOKENONLYSIZE | EP_TokenOnly
|
|
// **
|
|
// ** The size of the structure can be found by masking the return value
|
|
// ** of this routine with 0xfff. The flags can be found by masking the
|
|
// ** return value with EP_Reduced|EP_TokenOnly.
|
|
// **
|
|
// ** Note that with flags==EXPRDUP_REDUCE, this routines works on full-size
|
|
// ** (unreduced) Expr objects as they or originally constructed by the parser.
|
|
// ** During expression analysis, extra information is computed and moved into
|
|
// ** later parts of the Expr object and that extra information might get chopped
|
|
// ** off if the expression is reduced. Note also that it does not work to
|
|
// ** make an EXPRDUP_REDUCE copy of a reduced expression. It is only legal
|
|
// ** to reduce a pristine expression tree from the parser. The implementation
|
|
// ** of dupedExprStructSize() contain multiple assert() statements that attempt
|
|
// ** to enforce this constraint.
|
|
// */
|
|
func _dupedExprStructSize(tls *libc.TLS, p uintptr, flags int32) (r int32) {
|
|
var nSize int32
|
|
_ = nSize
|
|
/* Only one flag value allowed */
|
|
if 0 == flags || (*TExpr)(unsafe.Pointer(p)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_FullSize)) != uint32(0) {
|
|
nSize = int32(72)
|
|
} else {
|
|
if (*TExpr)(unsafe.Pointer(p)).FpLeft != 0 || *(*uintptr)(unsafe.Pointer(p + 32)) != 0 {
|
|
nSize = libc.Int32FromUint64(uint64(libc.UintptrFromInt32(0)+44) | libc.Uint64FromInt32(EP_Reduced))
|
|
} else {
|
|
nSize = libc.Int32FromUint64(uint64(libc.UintptrFromInt32(0)+16) | libc.Uint64FromInt32(EP_TokenOnly))
|
|
}
|
|
}
|
|
return nSize
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Estimate the average size of a row for an index.
|
|
// */
|
|
func _estimateIndexWidth(tls *libc.TLS, pIdx uintptr) {
|
|
var aCol uintptr
|
|
var i, v2 int32
|
|
var wIndex uint32
|
|
var x Ti16
|
|
_, _, _, _, _ = aCol, i, wIndex, x, v2
|
|
wIndex = uint32(0)
|
|
aCol = (*TTable)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pIdx)).FpTable)).FaCol
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn)) {
|
|
break
|
|
}
|
|
x = **(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(i)*2))
|
|
if int32(x) < 0 {
|
|
v2 = int32(1)
|
|
} else {
|
|
v2 = libc.Int32FromUint8((**(**TColumn)(__ccgo_up(aCol + uintptr(x)*16))).FszEst)
|
|
}
|
|
wIndex = wIndex + libc.Uint32FromInt32(v2)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
(*TIndex)(unsafe.Pointer(pIdx)).FszIdxRow = _sqlite3LogEst(tls, uint64(wIndex*uint32(4)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Evaluate an expression (either a vector or a scalar expression) and store
|
|
// ** the result in contiguous temporary registers. Return the index of
|
|
// ** the first register used to store the result.
|
|
// **
|
|
// ** If the returned result register is a temporary scalar, then also write
|
|
// ** that register number into *piFreeable. If the returned result register
|
|
// ** is not a temporary or if the expression is a vector set *piFreeable
|
|
// ** to 0.
|
|
// */
|
|
func _exprCodeVector(tls *libc.TLS, pParse uintptr, p uintptr, piFreeable uintptr) (r int32) {
|
|
var i, iResult, nResult int32
|
|
_, _, _ = i, iResult, nResult
|
|
nResult = _sqlite3ExprVectorSize(tls, p)
|
|
if nResult == int32(1) {
|
|
iResult = _sqlite3ExprCodeTemp(tls, pParse, p, piFreeable)
|
|
} else {
|
|
**(**int32)(__ccgo_up(piFreeable)) = 0
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) == int32(TK_SELECT) {
|
|
iResult = _sqlite3CodeSubselect(tls, pParse, p)
|
|
} else {
|
|
iResult = (*TParse)(unsafe.Pointer(pParse)).FnMem + int32(1)
|
|
**(**int32)(__ccgo_up(pParse + 60)) += nResult
|
|
i = 0
|
|
for {
|
|
if !(i < nResult) {
|
|
break
|
|
}
|
|
_sqlite3ExprCodeFactorable(tls, pParse, (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(p + 32)) + 8 + uintptr(i)*32))).FpExpr, i+iResult)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
}
|
|
return iResult
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* This walker callback will compute the union of colFlags flags for all
|
|
// ** referenced columns in a CHECK constraint or generated column expression.
|
|
// */
|
|
func _exprColumnFlagUnion(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var v1 uintptr
|
|
_ = v1
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_COLUMN) && int32((*TExpr)(unsafe.Pointer(pExpr)).FiColumn) >= 0 {
|
|
v1 = pWalker + 36
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromUint16((**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pWalker + 40)))).FaCol + uintptr((*TExpr)(unsafe.Pointer(pExpr)).FiColumn)*16))).FcolFlags))
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Check to see if there are references to columns in table
|
|
// ** pWalker->u.pIdxCover->iCur can be satisfied using the index
|
|
// ** pWalker->u.pIdxCover->pIdx.
|
|
// */
|
|
func _exprIdxCover(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_COLUMN) && (*TExpr)(unsafe.Pointer(pExpr)).FiTable == (*TIdxCover)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pWalker + 40)))).FiCur && _sqlite3TableColumnToIndex(tls, (*TIdxCover)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pWalker + 40)))).FpIdx, int32((*TExpr)(unsafe.Pointer(pExpr)).FiColumn)) < 0 {
|
|
(*TWalker)(unsafe.Pointer(pWalker)).FeCode = uint16(1)
|
|
return int32(WRC_Abort)
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return non-zero if Expr p can only be true if pNN is not NULL.
|
|
// **
|
|
// ** Or if seenNot is true, return non-zero if Expr p can only be
|
|
// ** non-NULL if pNN is not NULL
|
|
// */
|
|
func _exprImpliesNotNull(tls *libc.TLS, pParse uintptr, p uintptr, pNN uintptr, iTab int32, seenNot int32) (r int32) {
|
|
var pList uintptr
|
|
_ = pList
|
|
if _sqlite3ExprCompare(tls, pParse, p, pNN, iTab) == 0 {
|
|
return libc.BoolInt32(libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pNN)).Fop) != int32(TK_NULL))
|
|
}
|
|
switch libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) {
|
|
case int32(TK_IN):
|
|
if seenNot != 0 && (*TExpr)(unsafe.Pointer(p)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_xIsSelect)) != uint32(0) {
|
|
return 0
|
|
}
|
|
return _exprImpliesNotNull(tls, pParse, (*TExpr)(unsafe.Pointer(p)).FpLeft, pNN, iTab, int32(1))
|
|
case int32(TK_BETWEEN):
|
|
pList = *(*uintptr)(unsafe.Pointer(p + 32))
|
|
if seenNot != 0 {
|
|
return 0
|
|
}
|
|
if _exprImpliesNotNull(tls, pParse, (*(*TExprList_item)(unsafe.Pointer(pList + 8))).FpExpr, pNN, iTab, int32(1)) != 0 || _exprImpliesNotNull(tls, pParse, (*(*TExprList_item)(unsafe.Pointer(pList + 8 + 1*32))).FpExpr, pNN, iTab, int32(1)) != 0 {
|
|
return int32(1)
|
|
}
|
|
return _exprImpliesNotNull(tls, pParse, (*TExpr)(unsafe.Pointer(p)).FpLeft, pNN, iTab, int32(1))
|
|
case int32(TK_EQ):
|
|
fallthrough
|
|
case int32(TK_NE):
|
|
fallthrough
|
|
case int32(TK_LT):
|
|
fallthrough
|
|
case int32(TK_LE):
|
|
fallthrough
|
|
case int32(TK_GT):
|
|
fallthrough
|
|
case int32(TK_GE):
|
|
fallthrough
|
|
case int32(TK_PLUS):
|
|
fallthrough
|
|
case int32(TK_MINUS):
|
|
fallthrough
|
|
case int32(TK_BITOR):
|
|
fallthrough
|
|
case int32(TK_LSHIFT):
|
|
fallthrough
|
|
case int32(TK_RSHIFT):
|
|
fallthrough
|
|
case int32(TK_CONCAT):
|
|
seenNot = int32(1)
|
|
fallthrough
|
|
case int32(TK_STAR):
|
|
fallthrough
|
|
case int32(TK_REM):
|
|
fallthrough
|
|
case int32(TK_BITAND):
|
|
fallthrough
|
|
case int32(TK_SLASH):
|
|
if _exprImpliesNotNull(tls, pParse, (*TExpr)(unsafe.Pointer(p)).FpRight, pNN, iTab, seenNot) != 0 {
|
|
return int32(1)
|
|
}
|
|
fallthrough
|
|
case int32(TK_SPAN):
|
|
fallthrough
|
|
case int32(TK_COLLATE):
|
|
fallthrough
|
|
case int32(TK_UPLUS):
|
|
fallthrough
|
|
case int32(TK_UMINUS):
|
|
return _exprImpliesNotNull(tls, pParse, (*TExpr)(unsafe.Pointer(p)).FpLeft, pNN, iTab, seenNot)
|
|
case int32(TK_TRUTH):
|
|
if seenNot != 0 {
|
|
return 0
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop2) != int32(TK_IS) {
|
|
return 0
|
|
}
|
|
return _exprImpliesNotNull(tls, pParse, (*TExpr)(unsafe.Pointer(p)).FpLeft, pNN, iTab, int32(1))
|
|
case int32(TK_BITNOT):
|
|
fallthrough
|
|
case int32(TK_NOT):
|
|
return _exprImpliesNotNull(tls, pParse, (*TExpr)(unsafe.Pointer(p)).FpLeft, pNN, iTab, int32(1))
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func _exprIsConst(tls *libc.TLS, pParse uintptr, p uintptr, initFlag int32) (r int32) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var _ /* w at bp+0 */ TWalker
|
|
(**(**TWalker)(__ccgo_up(bp))).FeCode = libc.Uint16FromInt32(initFlag)
|
|
(**(**TWalker)(__ccgo_up(bp))).FpParse = pParse
|
|
(**(**TWalker)(__ccgo_up(bp))).FxExprCallback = __ccgo_fp(_exprNodeIsConstant)
|
|
(**(**TWalker)(__ccgo_up(bp))).FxSelectCallback = __ccgo_fp(_sqlite3SelectWalkFail)
|
|
_sqlite3WalkExpr(tls, bp, p)
|
|
return libc.Int32FromUint16((**(**TWalker)(__ccgo_up(bp))).FeCode)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** pIdx is an index containing expressions. Check it see if any of the
|
|
// ** expressions in the index match the pExpr expression.
|
|
// */
|
|
func _exprIsCoveredByIndex(tls *libc.TLS, pExpr uintptr, pIdx uintptr, iTabCur int32) (r int32) {
|
|
var i int32
|
|
_ = i
|
|
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))) == -int32(2) && _sqlite3ExprCompare(tls, uintptr(0), pExpr, (*(*TExprList_item)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pIdx)).FaColExpr + 8 + uintptr(i)*32))).FpExpr, iTabCur) == 0 {
|
|
return int32(1)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Append a copy of each expression in expression-list pAppend to
|
|
// ** expression list pList. Return a pointer to the result list.
|
|
// */
|
|
func _exprListAppendList(tls *libc.TLS, pParse uintptr, pList uintptr, pAppend uintptr, bIntToNull int32) (r uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var db, pDup, pSub uintptr
|
|
var i, nInit, v1 int32
|
|
var _ /* iDummy at bp+0 */ int32
|
|
_, _, _, _, _, _ = db, i, nInit, pDup, pSub, v1
|
|
if pAppend != 0 {
|
|
if pList != 0 {
|
|
v1 = (*TExprList)(unsafe.Pointer(pList)).FnExpr
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
nInit = v1
|
|
i = 0
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(pAppend)).FnExpr) {
|
|
break
|
|
}
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
pDup = _sqlite3ExprDup(tls, db, (*(*TExprList_item)(unsafe.Pointer(pAppend + 8 + uintptr(i)*32))).FpExpr, 0)
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0 {
|
|
_sqlite3ExprDelete(tls, db, pDup)
|
|
break
|
|
}
|
|
if bIntToNull != 0 {
|
|
pSub = _sqlite3ExprSkipCollateAndLikely(tls, pDup)
|
|
if _sqlite3ExprIsInteger(tls, pSub, bp, uintptr(0)) != 0 {
|
|
(*TExpr)(unsafe.Pointer(pSub)).Fop = uint8(TK_NULL)
|
|
**(**Tu32)(__ccgo_up(pSub + 4)) &= libc.Uint32FromInt32(^(libc.Int32FromInt32(EP_IntValue) | libc.Int32FromInt32(EP_IsTrue) | libc.Int32FromInt32(EP_IsFalse)))
|
|
*(*uintptr)(unsafe.Pointer(pSub + 8)) = uintptr(0)
|
|
}
|
|
}
|
|
pList = _sqlite3ExprListAppend(tls, pParse, pList, pDup)
|
|
if pList != 0 {
|
|
(*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(nInit+i)*32))).Ffg.FsortFlags = (*(*TExprList_item)(unsafe.Pointer(pAppend + 8 + uintptr(i)*32))).Ffg.FsortFlags
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
return pList
|
|
}
|
|
|
|
func _exprMightBeIndexed(tls *libc.TLS, pFrom uintptr, aiCurCol uintptr, pExpr uintptr, op int32) (r int32) {
|
|
var i int32
|
|
var pIdx uintptr
|
|
_, _ = i, pIdx
|
|
/* If this expression is a vector to the left or right of a
|
|
** inequality constraint (>, <, >= or <=), perform the processing
|
|
** on the first element of the vector. */
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_VECTOR) && (op >= int32(TK_GT) && op <= int32(TK_GE)) {
|
|
pExpr = (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)) + 8))).FpExpr
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_COLUMN) {
|
|
**(**int32)(__ccgo_up(aiCurCol)) = (*TExpr)(unsafe.Pointer(pExpr)).FiTable
|
|
**(**int32)(__ccgo_up(aiCurCol + 1*4)) = int32((*TExpr)(unsafe.Pointer(pExpr)).FiColumn)
|
|
return int32(1)
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < (*TSrcList)(unsafe.Pointer(pFrom)).FnSrc) {
|
|
break
|
|
}
|
|
pIdx = (*TTable)(unsafe.Pointer((*(*TSrcItem)(unsafe.Pointer(pFrom + 8 + uintptr(i)*80))).FpSTab)).FpIndex
|
|
for {
|
|
if !(pIdx != 0) {
|
|
break
|
|
}
|
|
if (*TIndex)(unsafe.Pointer(pIdx)).FaColExpr != 0 {
|
|
return _exprMightBeIndexed2(tls, pFrom, aiCurCol, pExpr, i)
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
pIdx = (*TIndex)(unsafe.Pointer(pIdx)).FpNext
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Expression pExpr is one operand of a comparison operator that might
|
|
// ** be useful for indexing. This routine checks to see if pExpr appears
|
|
// ** in any index. Return TRUE (1) if pExpr is an indexed term and return
|
|
// ** FALSE (0) if not. If TRUE is returned, also set aiCurCol[0] to the cursor
|
|
// ** number of the table that is indexed and aiCurCol[1] to the column number
|
|
// ** of the column that is indexed, or XN_EXPR (-2) if an expression is being
|
|
// ** indexed.
|
|
// **
|
|
// ** If pExpr is a TK_COLUMN column reference, then this routine always returns
|
|
// ** true even if that particular column is not indexed, because the column
|
|
// ** might be added to an automatic index later.
|
|
// */
|
|
func _exprMightBeIndexed2(tls *libc.TLS, pFrom uintptr, aiCurCol uintptr, pExpr uintptr, j int32) (r int32) {
|
|
var i, iCur, v1 int32
|
|
var pIdx uintptr
|
|
_, _, _, _ = i, iCur, pIdx, v1
|
|
for {
|
|
iCur = (*(*TSrcItem)(unsafe.Pointer(pFrom + 8 + uintptr(j)*80))).FiCursor
|
|
pIdx = (*TTable)(unsafe.Pointer((*(*TSrcItem)(unsafe.Pointer(pFrom + 8 + uintptr(j)*80))).FpSTab)).FpIndex
|
|
for {
|
|
if !(pIdx != 0) {
|
|
break
|
|
}
|
|
if (*TIndex)(unsafe.Pointer(pIdx)).FaColExpr == uintptr(0) {
|
|
goto _3
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol)) {
|
|
break
|
|
}
|
|
if int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(i)*2))) != -int32(2) {
|
|
goto _4
|
|
}
|
|
if _sqlite3ExprCompareSkip(tls, pExpr, (*(*TExprList_item)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pIdx)).FaColExpr + 8 + uintptr(i)*32))).FpExpr, iCur) == 0 && !(_sqlite3ExprIsConstant(tls, uintptr(0), (*(*TExprList_item)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pIdx)).FaColExpr + 8 + uintptr(i)*32))).FpExpr) != 0) {
|
|
**(**int32)(__ccgo_up(aiCurCol)) = iCur
|
|
**(**int32)(__ccgo_up(aiCurCol + 1*4)) = -int32(2)
|
|
return int32(1)
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
i = i + 1
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
pIdx = (*TIndex)(unsafe.Pointer(pIdx)).FpNext
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
j = j + 1
|
|
v1 = j
|
|
if !(v1 < (*TSrcList)(unsafe.Pointer(pFrom)).FnSrc) {
|
|
break
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Expression Node callback for sqlite3ExprCanReturnSubtype(). If
|
|
// ** pExpr is able to return a subtype, set pWalker->eCode and abort
|
|
// ** the search. If pExpr can never return a subtype, prune search.
|
|
// **
|
|
// ** The only expressions that can return a subtype are:
|
|
// **
|
|
// ** 1. A function
|
|
// ** 2. The no-op "+" operator
|
|
// ** 3. A CASE...END expression
|
|
// ** 4. A CAST() expression
|
|
// ** 5. A "expr COLLATE colseq" expression.
|
|
// **
|
|
// ** For any other kind of expression, prune the search.
|
|
// **
|
|
// ** For case 1, the expression can yield a subtype if the function has
|
|
// ** the SQLITE_RESULT_SUBTYPE property. Functions can also return
|
|
// ** a subtype (via sqlite3_result_value()) if any of the arguments can
|
|
// ** return a subtype.
|
|
// **
|
|
// ** In all cases 1 through 5, the expression might also return a subtype
|
|
// ** if any operand can return a subtype.
|
|
// */
|
|
func _exprNodeCanReturnSubtype(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var db, pDef uintptr
|
|
var n, v1 int32
|
|
_, _, _, _ = db, n, pDef, v1
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_CASE) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_UPLUS) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_COLLATE) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_CAST) {
|
|
return WRC_Continue
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) != int32(TK_FUNCTION) {
|
|
return int32(WRC_Prune)
|
|
}
|
|
db = (*TParse)(unsafe.Pointer((*TWalker)(unsafe.Pointer(pWalker)).FpParse)).Fdb
|
|
if *(*uintptr)(unsafe.Pointer(pExpr + 32)) != 0 {
|
|
v1 = (*TExprList)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)))).FnExpr
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
n = v1
|
|
pDef = _sqlite3FindFunction(tls, db, *(*uintptr)(unsafe.Pointer(pExpr + 8)), n, (*Tsqlite3)(unsafe.Pointer(db)).Fenc, uint8(0))
|
|
if pDef == uintptr(0) || (*TFuncDef)(unsafe.Pointer(pDef)).FfuncFlags&uint32(SQLITE_RESULT_SUBTYPE) != uint32(0) {
|
|
(*TWalker)(unsafe.Pointer(pWalker)).FeCode = uint16(1)
|
|
return int32(WRC_Abort)
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** These routines are Walker callbacks used to check expressions to
|
|
// ** see if they are "constant" for some definition of constant. The
|
|
// ** Walker.eCode value determines the type of "constant" we are looking
|
|
// ** for.
|
|
// **
|
|
// ** These callback routines are used to implement the following:
|
|
// **
|
|
// ** sqlite3ExprIsConstant() pWalker->eCode==1
|
|
// ** sqlite3ExprIsConstantNotJoin() pWalker->eCode==2
|
|
// ** sqlite3ExprIsTableConstant() pWalker->eCode==3
|
|
// ** sqlite3ExprIsConstantOrFunction() pWalker->eCode==4 or 5
|
|
// **
|
|
// ** In all cases, the callbacks set Walker.eCode=0 and abort if the expression
|
|
// ** is found to not be a constant.
|
|
// **
|
|
// ** The sqlite3ExprIsConstantOrFunction() is used for evaluating DEFAULT
|
|
// ** expressions in a CREATE TABLE statement. The Walker.eCode value is 5
|
|
// ** when parsing an existing schema out of the sqlite_schema table and 4
|
|
// ** when processing a new CREATE TABLE statement. A bound parameter raises
|
|
// ** an error for new statements, but is silently converted
|
|
// ** to NULL for existing schemas. This allows sqlite_schema tables that
|
|
// ** contain a bound parameter because they were generated by older versions
|
|
// ** of SQLite to be parsed by newer versions of SQLite without raising a
|
|
// ** malformed schema error.
|
|
// */
|
|
func _exprNodeIsConstant(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
/* If pWalker->eCode is 2 then any term of the expression that comes from
|
|
** the ON or USING clauses of an outer join disqualifies the expression
|
|
** from being considered constant. */
|
|
if libc.Int32FromUint16((*TWalker)(unsafe.Pointer(pWalker)).FeCode) == int32(2) && (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)) != uint32(0) {
|
|
(*TWalker)(unsafe.Pointer(pWalker)).FeCode = uint16(0)
|
|
return int32(WRC_Abort)
|
|
}
|
|
switch libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) {
|
|
/* Consider functions to be constant if all their arguments are constant
|
|
** and either pWalker->eCode==4 or 5 or the function has the
|
|
** SQLITE_FUNC_CONST flag. */
|
|
case int32(TK_FUNCTION):
|
|
if (libc.Int32FromUint16((*TWalker)(unsafe.Pointer(pWalker)).FeCode) >= int32(4) || (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_ConstFunc)) != uint32(0)) && !((*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_WinFunc)) != libc.Uint32FromInt32(0)) {
|
|
if libc.Int32FromUint16((*TWalker)(unsafe.Pointer(pWalker)).FeCode) == int32(5) {
|
|
**(**Tu32)(__ccgo_up(pExpr + 4)) |= libc.Uint32FromInt32(libc.Int32FromInt32(EP_FromDDL))
|
|
}
|
|
return WRC_Continue
|
|
} else {
|
|
if (*TWalker)(unsafe.Pointer(pWalker)).FpParse != 0 {
|
|
return _exprNodeIsConstantFunction(tls, pWalker, pExpr)
|
|
} else {
|
|
(*TWalker)(unsafe.Pointer(pWalker)).FeCode = uint16(0)
|
|
return int32(WRC_Abort)
|
|
}
|
|
}
|
|
fallthrough
|
|
case int32(TK_ID):
|
|
/* Convert "true" or "false" in a DEFAULT clause into the
|
|
** appropriate TK_TRUEFALSE operator */
|
|
if _sqlite3ExprIdToTrueFalse(tls, pExpr) != 0 {
|
|
return int32(WRC_Prune)
|
|
}
|
|
fallthrough
|
|
case int32(TK_COLUMN):
|
|
fallthrough
|
|
case int32(TK_AGG_FUNCTION):
|
|
fallthrough
|
|
case int32(TK_AGG_COLUMN):
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_FixedCol)) != uint32(0) && libc.Int32FromUint16((*TWalker)(unsafe.Pointer(pWalker)).FeCode) != int32(2) {
|
|
return WRC_Continue
|
|
}
|
|
if libc.Int32FromUint16((*TWalker)(unsafe.Pointer(pWalker)).FeCode) == int32(3) && (*TExpr)(unsafe.Pointer(pExpr)).FiTable == *(*int32)(unsafe.Pointer(&(*TWalker)(unsafe.Pointer(pWalker)).Fu)) {
|
|
return WRC_Continue
|
|
}
|
|
fallthrough
|
|
case int32(TK_IF_NULL_ROW):
|
|
fallthrough
|
|
case int32(TK_REGISTER):
|
|
fallthrough
|
|
case int32(TK_DOT):
|
|
fallthrough
|
|
case int32(TK_RAISE):
|
|
(*TWalker)(unsafe.Pointer(pWalker)).FeCode = uint16(0)
|
|
return int32(WRC_Abort)
|
|
case int32(TK_VARIABLE):
|
|
if libc.Int32FromUint16((*TWalker)(unsafe.Pointer(pWalker)).FeCode) == int32(5) {
|
|
/* Silently convert bound parameters that appear inside of CREATE
|
|
** statements into a NULL when parsing the CREATE statement text out
|
|
** of the sqlite_schema table */
|
|
(*TExpr)(unsafe.Pointer(pExpr)).Fop = uint8(TK_NULL)
|
|
} else {
|
|
if libc.Int32FromUint16((*TWalker)(unsafe.Pointer(pWalker)).FeCode) == int32(4) {
|
|
/* A bound parameter in a CREATE statement that originates from
|
|
** sqlite3_prepare() causes an error */
|
|
(*TWalker)(unsafe.Pointer(pWalker)).FeCode = uint16(0)
|
|
return int32(WRC_Abort)
|
|
}
|
|
}
|
|
fallthrough
|
|
default:
|
|
/* sqlite3SelectWalkFail() disallows */
|
|
/* sqlite3SelectWalkFail() disallows */
|
|
return WRC_Continue
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** pExpr is a TK_FUNCTION node. Try to determine whether or not the
|
|
// ** function is a constant function. A function is constant if all of
|
|
// ** the following are true:
|
|
// **
|
|
// ** (1) It is a scalar function (not an aggregate or window function)
|
|
// ** (2) It has either the SQLITE_FUNC_CONSTANT or SQLITE_FUNC_SLOCHNG
|
|
// ** property.
|
|
// ** (3) All of its arguments are constants
|
|
// **
|
|
// ** This routine sets pWalker->eCode to 0 if pExpr is not a constant.
|
|
// ** It makes no changes to pWalker->eCode if pExpr is constant. In
|
|
// ** every case, it returns WRC_Abort.
|
|
// **
|
|
// ** Called as a service subroutine from exprNodeIsConstant().
|
|
// */
|
|
func _exprNodeIsConstantFunction(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var db, pDef, pList, v1 uintptr
|
|
var n int32
|
|
var v2 bool
|
|
_, _, _, _, _, _ = db, n, pDef, pList, v1, v2 /* The database */
|
|
if v2 = (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_TokenOnly)) != uint32(0); !v2 {
|
|
v1 = *(*uintptr)(unsafe.Pointer(pExpr + 32))
|
|
pList = v1
|
|
}
|
|
if v2 || v1 == uintptr(0) {
|
|
n = 0
|
|
} else {
|
|
n = (*TExprList)(unsafe.Pointer(pList)).FnExpr
|
|
_sqlite3WalkExprList(tls, pWalker, pList)
|
|
if libc.Int32FromUint16((*TWalker)(unsafe.Pointer(pWalker)).FeCode) == 0 {
|
|
return int32(WRC_Abort)
|
|
}
|
|
}
|
|
db = (*TParse)(unsafe.Pointer((*TWalker)(unsafe.Pointer(pWalker)).FpParse)).Fdb
|
|
pDef = _sqlite3FindFunction(tls, db, *(*uintptr)(unsafe.Pointer(pExpr + 8)), n, (*Tsqlite3)(unsafe.Pointer(db)).Fenc, uint8(0))
|
|
if pDef == uintptr(0) || (*TFuncDef)(unsafe.Pointer(pDef)).FxFinalize != uintptr(0) || (*TFuncDef)(unsafe.Pointer(pDef)).FfuncFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FUNC_CONSTANT)|libc.Int32FromInt32(SQLITE_FUNC_SLOCHNG)) == uint32(0) || (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_WinFunc)) != uint32(0) {
|
|
(*TWalker)(unsafe.Pointer(pWalker)).FeCode = uint16(0)
|
|
return int32(WRC_Abort)
|
|
}
|
|
return int32(WRC_Prune)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Callback for estLikePatternLength().
|
|
// **
|
|
// ** If this node is a string literal that is longer pWalker->sz, then set
|
|
// ** pWalker->sz to the byte length of that string literal.
|
|
// **
|
|
// ** pWalker->eCode indicates how to count characters:
|
|
// **
|
|
// ** eCode==0 Count as a GLOB pattern
|
|
// ** eCode==1 Count as a LIKE pattern
|
|
// */
|
|
func _exprNodePatternLengthEst(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var c, c1, c2, c3, v1 Tu8
|
|
var sz int32
|
|
var z, v2 uintptr
|
|
_, _, _, _, _, _, _, _ = c, c1, c2, c3, sz, z, v1, v2
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_STRING) {
|
|
sz = 0 /* Pattern size in bytes */
|
|
z = *(*uintptr)(unsafe.Pointer(pExpr + 8)) /* Wildcards */
|
|
if (*TWalker)(unsafe.Pointer(pWalker)).FeCode != 0 {
|
|
c1 = uint8('%')
|
|
c2 = uint8('_')
|
|
c3 = uint8(0)
|
|
} else {
|
|
c1 = uint8('*')
|
|
c2 = uint8('?')
|
|
c3 = uint8('[')
|
|
}
|
|
for {
|
|
v2 = z
|
|
z = z + 1
|
|
v1 = **(**Tu8)(__ccgo_up(v2))
|
|
c = v1
|
|
if !(libc.Int32FromUint8(v1) != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(c) == libc.Int32FromUint8(c3) {
|
|
if **(**Tu8)(__ccgo_up(z)) != 0 {
|
|
z = z + 1
|
|
}
|
|
for **(**Tu8)(__ccgo_up(z)) != 0 && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(z))) != int32(']') {
|
|
z = z + 1
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint8(c) != libc.Int32FromUint8(c1) && libc.Int32FromUint8(c) != libc.Int32FromUint8(c2) {
|
|
sz = sz + 1
|
|
}
|
|
}
|
|
}
|
|
if sz > *(*int32)(unsafe.Pointer(&(*TWalker)(unsafe.Pointer(pWalker)).Fu)) {
|
|
*(*int32)(unsafe.Pointer(&(*TWalker)(unsafe.Pointer(pWalker)).Fu)) = sz
|
|
}
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* This is the Walker EXPR callback for sqlite3ReferencesSrcList().
|
|
// **
|
|
// ** Set the 0x01 bit of pWalker->eCode if there is a reference to any
|
|
// ** of the tables shown in RefSrcList.pRef.
|
|
// **
|
|
// ** Set the 0x02 bit of pWalker->eCode if there is a reference to a
|
|
// ** table is in neither RefSrcList.pRef nor RefSrcList.aiExclude.
|
|
// */
|
|
func _exprRefToSrcList(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var i, nSrc, v1 int32
|
|
var p, pSrc, v3 uintptr
|
|
_, _, _, _, _, _ = i, nSrc, p, pSrc, v1, v3
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_COLUMN) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_AGG_COLUMN) {
|
|
p = *(*uintptr)(unsafe.Pointer(pWalker + 40))
|
|
pSrc = (*TRefSrcList)(unsafe.Pointer(p)).FpRef
|
|
if pSrc != 0 {
|
|
v1 = (*TSrcList)(unsafe.Pointer(pSrc)).FnSrc
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
nSrc = v1
|
|
i = 0
|
|
for {
|
|
if !(i < nSrc) {
|
|
break
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).FiTable == (*(*TSrcItem)(unsafe.Pointer(pSrc + 8 + uintptr(i)*80))).FiCursor {
|
|
v3 = pWalker + 36
|
|
*(*Tu16)(unsafe.Pointer(v3)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v3))) | libc.Int32FromInt32(1))
|
|
return WRC_Continue
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(int64(i) < (*TRefSrcList)(unsafe.Pointer(p)).FnExclude && **(**int32)(__ccgo_up((*TRefSrcList)(unsafe.Pointer(p)).FaiExclude + uintptr(i)*4)) != (*TExpr)(unsafe.Pointer(pExpr)).FiTable) {
|
|
break
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if int64(i) >= (*TRefSrcList)(unsafe.Pointer(p)).FnExclude {
|
|
v3 = pWalker + 36
|
|
*(*Tu16)(unsafe.Pointer(v3)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v3))) | libc.Int32FromInt32(2))
|
|
}
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the Expr.nHeight variable in the structure passed as an
|
|
// ** argument. An expression with no children, Expr.pList or
|
|
// ** Expr.pSelect member has a height of 1. Any other expression
|
|
// ** has a height equal to the maximum height of any other
|
|
// ** referenced Expr plus one.
|
|
// **
|
|
// ** Also propagate EP_Propagate flags up from Expr.x.pList to Expr.flags,
|
|
// ** if appropriate.
|
|
// */
|
|
func _exprSetHeight(tls *libc.TLS, p uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var v1 int32
|
|
var _ /* nHeight at bp+0 */ int32
|
|
_ = v1
|
|
if (*TExpr)(unsafe.Pointer(p)).FpLeft != 0 {
|
|
v1 = (*TExpr)(unsafe.Pointer((*TExpr)(unsafe.Pointer(p)).FpLeft)).FnHeight
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
**(**int32)(__ccgo_up(bp)) = v1
|
|
if (*TExpr)(unsafe.Pointer(p)).FpRight != 0 && (*TExpr)(unsafe.Pointer((*TExpr)(unsafe.Pointer(p)).FpRight)).FnHeight > **(**int32)(__ccgo_up(bp)) {
|
|
**(**int32)(__ccgo_up(bp)) = (*TExpr)(unsafe.Pointer((*TExpr)(unsafe.Pointer(p)).FpRight)).FnHeight
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(p)).Fflags&uint32(EP_xIsSelect) != uint32(0) {
|
|
_heightOfSelect(tls, *(*uintptr)(unsafe.Pointer(p + 32)), bp)
|
|
} else {
|
|
if *(*uintptr)(unsafe.Pointer(p + 32)) != 0 {
|
|
_heightOfExprList(tls, *(*uintptr)(unsafe.Pointer(p + 32)), bp)
|
|
**(**Tu32)(__ccgo_up(p + 4)) |= libc.Uint32FromInt32(libc.Int32FromInt32(EP_Collate)|libc.Int32FromInt32(EP_Subquery)|libc.Int32FromInt32(EP_HasFunc)) & _sqlite3ExprListFlags(tls, *(*uintptr)(unsafe.Pointer(p + 32)))
|
|
}
|
|
}
|
|
(*TExpr)(unsafe.Pointer(p)).FnHeight = **(**int32)(__ccgo_up(bp)) + int32(1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the number of bytes allocated for the expression structure
|
|
// ** passed as the first argument. This is always one of EXPR_FULLSIZE,
|
|
// ** EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE.
|
|
// */
|
|
func _exprStructSize(tls *libc.TLS, p uintptr) (r int32) {
|
|
if (*TExpr)(unsafe.Pointer(p)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_TokenOnly)) != uint32(0) {
|
|
return libc.Int32FromUint64(uint64(libc.UintptrFromInt32(0) + 16))
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(p)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Reduced)) != uint32(0) {
|
|
return libc.Int32FromUint64(uint64(libc.UintptrFromInt32(0) + 44))
|
|
}
|
|
return int32(72)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Argument pVector points to a vector expression - either a TK_VECTOR
|
|
// ** or TK_SELECT that returns more than one column. This function returns
|
|
// ** the register number of a register that contains the value of
|
|
// ** element iField of the vector.
|
|
// **
|
|
// ** If pVector is a TK_SELECT expression, then code for it must have
|
|
// ** already been generated using the exprCodeSubselect() routine. In this
|
|
// ** case parameter regSelect should be the first in an array of registers
|
|
// ** containing the results of the sub-select.
|
|
// **
|
|
// ** If pVector is of type TK_VECTOR, then code for the requested field
|
|
// ** is generated. In this case (*pRegFree) may be set to the number of
|
|
// ** a temporary register to be freed by the caller before returning.
|
|
// **
|
|
// ** Before returning, output parameter (*ppExpr) is set to point to the
|
|
// ** Expr object corresponding to element iElem of the vector.
|
|
// */
|
|
func _exprVectorRegister(tls *libc.TLS, pParse uintptr, pVector uintptr, iField int32, regSelect int32, ppExpr uintptr, pRegFree uintptr) (r int32) {
|
|
var op Tu8
|
|
_ = op
|
|
op = (*TExpr)(unsafe.Pointer(pVector)).Fop
|
|
if libc.Int32FromUint8(op) == int32(TK_REGISTER) {
|
|
**(**uintptr)(__ccgo_up(ppExpr)) = _sqlite3VectorFieldSubexpr(tls, pVector, iField)
|
|
return (*TExpr)(unsafe.Pointer(pVector)).FiTable + iField
|
|
}
|
|
if libc.Int32FromUint8(op) == int32(TK_SELECT) {
|
|
**(**uintptr)(__ccgo_up(ppExpr)) = (*(*TExprList_item)(unsafe.Pointer((*TSelect)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pVector + 32)))).FpEList + 8 + uintptr(iField)*32))).FpExpr
|
|
return regSelect + iField
|
|
}
|
|
if libc.Int32FromUint8(op) == int32(TK_VECTOR) {
|
|
**(**uintptr)(__ccgo_up(ppExpr)) = (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pVector + 32)) + 8 + uintptr(iField)*32))).FpExpr
|
|
return _sqlite3ExprCodeTemp(tls, pParse, **(**uintptr)(__ccgo_up(ppExpr)), pRegFree)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Create a new expression term for the column specified by pMatch and
|
|
// ** iColumn. Append this new expression term to the FULL JOIN Match set
|
|
// ** in *ppList. Create a new *ppList if this is the first term in the
|
|
// ** set.
|
|
// */
|
|
func _extendFJMatch(tls *libc.TLS, pParse uintptr, ppList uintptr, pMatch uintptr, iColumn Ti16) {
|
|
var pNew uintptr
|
|
_ = pNew
|
|
pNew = _sqlite3ExprAlloc(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, int32(TK_COLUMN), uintptr(0), 0)
|
|
if pNew != 0 {
|
|
(*TExpr)(unsafe.Pointer(pNew)).FiTable = (*TSrcItem)(unsafe.Pointer(pMatch)).FiCursor
|
|
(*TExpr)(unsafe.Pointer(pNew)).FiColumn = iColumn
|
|
*(*uintptr)(unsafe.Pointer(pNew + 64)) = (*TSrcItem)(unsafe.Pointer(pMatch)).FpSTab
|
|
**(**Tu32)(__ccgo_up(pNew + 4)) |= libc.Uint32FromInt32(libc.Int32FromInt32(EP_CanBeNull))
|
|
**(**uintptr)(__ccgo_up(ppList)) = _sqlite3ExprListAppend(tls, pParse, **(**uintptr)(__ccgo_up(ppList)), pNew)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return a pointer to payload information from the entry that the
|
|
// ** pCur cursor is pointing to. The pointer is to the beginning of
|
|
// ** the key if index btrees (pPage->intKey==0) and is the data for
|
|
// ** table btrees (pPage->intKey==1). The number of bytes of available
|
|
// ** key/data is written into *pAmt. If *pAmt==0, then the value
|
|
// ** returned will not be a valid pointer.
|
|
// **
|
|
// ** This routine is an optimization. It is common for the entire key
|
|
// ** and data to fit on the local page and for there to be no overflow
|
|
// ** pages. When that is so, this routine can be used to access the
|
|
// ** key and data without making a copy. If the key and/or data spills
|
|
// ** onto overflow pages, then accessPayload() must be used to reassemble
|
|
// ** the key/data and copy it into a preallocated buffer.
|
|
// **
|
|
// ** The pointer returned by this routine looks directly into the cached
|
|
// ** page of the database. The data might change or move the next time
|
|
// ** any btree routine is called.
|
|
// */
|
|
func _fetchPayload(tls *libc.TLS, pCur uintptr, pAmt uintptr) (r uintptr) {
|
|
var amt, v1 int32
|
|
_, _ = amt, v1
|
|
amt = libc.Int32FromUint16((*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnLocal)
|
|
if amt > int32(int64((*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).FaDataEnd)-int64((*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FpPayload)) {
|
|
/* There is too little space on the page for the expected amount
|
|
** of local content. Database must be corrupt. */
|
|
if 0 > int32(int64((*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).FaDataEnd)-int64((*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FpPayload)) {
|
|
v1 = 0
|
|
} else {
|
|
v1 = int32(int64((*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).FaDataEnd) - int64((*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FpPayload))
|
|
}
|
|
amt = v1
|
|
}
|
|
**(**Tu32)(__ccgo_up(pAmt)) = libc.Uint32FromInt32(amt)
|
|
return (*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FpPayload
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compute a bloom filter hash using pOp->p4.i registers from aMem[] beginning
|
|
// ** with pOp->p3. Return the hash.
|
|
// */
|
|
func _filterHash(tls *libc.TLS, aMem uintptr, pOp uintptr) (r Tu64) {
|
|
var h Tu64
|
|
var i, mx int32
|
|
var p uintptr
|
|
_, _, _, _ = h, i, mx, p
|
|
h = uint64(0)
|
|
i = (*TOp)(unsafe.Pointer(pOp)).Fp3
|
|
mx = i + (*TOp)(unsafe.Pointer(pOp)).Fp4.Fi
|
|
for {
|
|
if !(i < mx) {
|
|
break
|
|
}
|
|
p = aMem + uintptr(i)*56
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&(libc.Int32FromInt32(MEM_Int)|libc.Int32FromInt32(MEM_IntReal)) != 0 {
|
|
h = h + libc.Uint64FromInt64(*(*Ti64)(unsafe.Pointer(p)))
|
|
} else {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&int32(MEM_Real) != 0 {
|
|
h = h + libc.Uint64FromInt64(_sqlite3VdbeIntValue(tls, p))
|
|
} else {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&(libc.Int32FromInt32(MEM_Str)|libc.Int32FromInt32(MEM_Blob)) != 0 {
|
|
/* All strings have the same hash and all blobs have the same hash,
|
|
** though, at least, those hashes are different from each other and
|
|
** from NULL. */
|
|
h = h + libc.Uint64FromInt32(int32(4093)+libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&(libc.Int32FromInt32(MEM_Str)|libc.Int32FromInt32(MEM_Blob)))
|
|
}
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return h
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine is called right after An OP_Filter has been generated and
|
|
// ** before the corresponding index search has been performed. This routine
|
|
// ** checks to see if there are additional Bloom filters in inner loops that
|
|
// ** can be checked prior to doing the index lookup. If there are available
|
|
// ** inner-loop Bloom filters, then evaluate those filters now, before the
|
|
// ** index lookup. The idea is that a Bloom filter check is way faster than
|
|
// ** an index lookup, and the Bloom filter might return false, meaning that
|
|
// ** the index lookup can be skipped.
|
|
// **
|
|
// ** We know that an inner loop uses a Bloom filter because it has the
|
|
// ** WhereLevel.regFilter set. If an inner-loop Bloom filter is checked,
|
|
// ** then clear the WhereLevel.regFilter value to prevent the Bloom filter
|
|
// ** from being checked a second time when the inner loop is evaluated.
|
|
// */
|
|
func _filterPullDown(tls *libc.TLS, pParse uintptr, pWInfo uintptr, iLevel int32, addrNxt int32, notReady TBitmask) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var nEq Tu16
|
|
var pLevel, pLoop, pTerm uintptr
|
|
var r1, regRowid, saved_addrBrk, v1 int32
|
|
var _ /* zStartAff at bp+0 */ uintptr
|
|
_, _, _, _, _, _, _, _ = nEq, pLevel, pLoop, pTerm, r1, regRowid, saved_addrBrk, v1
|
|
for {
|
|
iLevel = iLevel + 1
|
|
v1 = iLevel
|
|
if !(v1 < libc.Int32FromUint8((*TWhereInfo)(unsafe.Pointer(pWInfo)).FnLevel)) {
|
|
break
|
|
}
|
|
pLevel = pWInfo + 856 + uintptr(iLevel)*112
|
|
pLoop = (*TWhereLevel)(unsafe.Pointer(pLevel)).FpWLoop
|
|
if (*TWhereLevel)(unsafe.Pointer(pLevel)).FregFilter == 0 {
|
|
continue
|
|
}
|
|
if (*TWhereLoop)(unsafe.Pointer((*TWhereLevel)(unsafe.Pointer(pLevel)).FpWLoop)).FnSkip != 0 {
|
|
continue
|
|
}
|
|
/* ,--- Because sqlite3ConstructBloomFilter() has will not have set
|
|
** vvvvv--' pLevel->regFilter if this were true. */
|
|
if (*TWhereLoop)(unsafe.Pointer(pLoop)).Fprereq¬Ready != 0 {
|
|
continue
|
|
}
|
|
saved_addrBrk = (*TWhereLevel)(unsafe.Pointer(pLevel)).FaddrBrk
|
|
(*TWhereLevel)(unsafe.Pointer(pLevel)).FaddrBrk = addrNxt
|
|
if (*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags&uint32(WHERE_IPK) != 0 {
|
|
pTerm = **(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pLoop)).FaLTerm))
|
|
regRowid = _sqlite3GetTempReg(tls, pParse)
|
|
regRowid = _codeEqualityTerm(tls, pParse, pTerm, pLevel, 0, 0, regRowid)
|
|
_sqlite3VdbeAddOp2(tls, (*TParse)(unsafe.Pointer(pParse)).FpVdbe, int32(OP_MustBeInt), regRowid, addrNxt)
|
|
_sqlite3VdbeAddOp4Int(tls, (*TParse)(unsafe.Pointer(pParse)).FpVdbe, int32(OP_Filter), (*TWhereLevel)(unsafe.Pointer(pLevel)).FregFilter, addrNxt, regRowid, int32(1))
|
|
} else {
|
|
nEq = (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FnEq
|
|
r1 = _codeAllEqualityTerms(tls, pParse, pLevel, 0, 0, bp)
|
|
_codeApplyAffinity(tls, pParse, r1, libc.Int32FromUint16(nEq), **(**uintptr)(__ccgo_up(bp)))
|
|
_sqlite3DbFree(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, **(**uintptr)(__ccgo_up(bp)))
|
|
_sqlite3VdbeAddOp4Int(tls, (*TParse)(unsafe.Pointer(pParse)).FpVdbe, int32(OP_Filter), (*TWhereLevel)(unsafe.Pointer(pLevel)).FregFilter, addrNxt, r1, libc.Int32FromUint16(nEq))
|
|
}
|
|
(*TWhereLevel)(unsafe.Pointer(pLevel)).FregFilter = 0
|
|
(*TWhereLevel)(unsafe.Pointer(pLevel)).FaddrBrk = saved_addrBrk
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Invoke the OP_AggFinalize opcode for every aggregate function
|
|
// ** in the AggInfo structure.
|
|
// */
|
|
func _finalizeAggFunctions(tls *libc.TLS, pParse uintptr, pAggInfo uintptr) {
|
|
var i, iBaseCol, iTop, j, nArg, nKey, regAgg, regSubtype, v4 int32
|
|
var pF, pList, v uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _, _ = i, iBaseCol, iTop, j, nArg, nKey, pF, pList, regAgg, regSubtype, v, v4
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
i = 0
|
|
pF = (*TAggInfo)(unsafe.Pointer(pAggInfo)).FaFunc
|
|
for {
|
|
if !(i < (*TAggInfo)(unsafe.Pointer(pAggInfo)).FnFunc) {
|
|
break
|
|
}
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr != 0 {
|
|
return
|
|
}
|
|
pList = *(*uintptr)(unsafe.Pointer((*TAggInfo_func)(unsafe.Pointer(pF)).FpFExpr + 32))
|
|
if (*TAggInfo_func)(unsafe.Pointer(pF)).FiOBTab >= 0 { /* Loop counter */
|
|
nArg = (*TExprList)(unsafe.Pointer(pList)).FnExpr
|
|
regAgg = _sqlite3GetTempRange(tls, pParse, nArg)
|
|
if libc.Int32FromUint8((*TAggInfo_func)(unsafe.Pointer(pF)).FbOBPayload) == 0 {
|
|
nKey = 0
|
|
} else {
|
|
nKey = (*TExprList)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer((*TExpr)(unsafe.Pointer((*TAggInfo_func)(unsafe.Pointer(pF)).FpFExpr)).FpLeft + 32)))).FnExpr
|
|
if !((*TAggInfo_func)(unsafe.Pointer(pF)).FbOBUnique != 0) {
|
|
nKey = nKey + 1
|
|
}
|
|
}
|
|
iTop = _sqlite3VdbeAddOp1(tls, v, int32(OP_Rewind), (*TAggInfo_func)(unsafe.Pointer(pF)).FiOBTab)
|
|
j = nArg - int32(1)
|
|
for {
|
|
if !(j >= 0) {
|
|
break
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Column), (*TAggInfo_func)(unsafe.Pointer(pF)).FiOBTab, nKey+j, regAgg+j)
|
|
goto _2
|
|
_2:
|
|
;
|
|
j = j - 1
|
|
}
|
|
if (*TAggInfo_func)(unsafe.Pointer(pF)).FbUseSubtype != 0 {
|
|
regSubtype = _sqlite3GetTempReg(tls, pParse)
|
|
iBaseCol = nKey + nArg + libc.BoolInt32(libc.Int32FromUint8((*TAggInfo_func)(unsafe.Pointer(pF)).FbOBPayload) == 0 && libc.Int32FromUint8((*TAggInfo_func)(unsafe.Pointer(pF)).FbOBUnique) == 0)
|
|
j = nArg - int32(1)
|
|
for {
|
|
if !(j >= 0) {
|
|
break
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Column), (*TAggInfo_func)(unsafe.Pointer(pF)).FiOBTab, iBaseCol+j, regSubtype)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_SetSubtype), regSubtype, regAgg+j)
|
|
goto _3
|
|
_3:
|
|
;
|
|
j = j - 1
|
|
}
|
|
_sqlite3ReleaseTempReg(tls, pParse, regSubtype)
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_AggStep), 0, regAgg, (*TAggInfo)(unsafe.Pointer(pAggInfo)).FiFirstReg+(*TAggInfo)(unsafe.Pointer(pAggInfo)).FnColumn+i)
|
|
_sqlite3VdbeAppendP4(tls, v, (*TAggInfo_func)(unsafe.Pointer(pF)).FpFunc, -int32(8))
|
|
_sqlite3VdbeChangeP5(tls, v, libc.Uint16FromInt32(nArg))
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Next), (*TAggInfo_func)(unsafe.Pointer(pF)).FiOBTab, iTop+int32(1))
|
|
_sqlite3VdbeJumpHere(tls, v, iTop)
|
|
_sqlite3ReleaseTempRange(tls, pParse, regAgg, nArg)
|
|
}
|
|
if pList != 0 {
|
|
v4 = (*TExprList)(unsafe.Pointer(pList)).FnExpr
|
|
} else {
|
|
v4 = 0
|
|
}
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_AggFinal), (*TAggInfo)(unsafe.Pointer(pAggInfo)).FiFirstReg+(*TAggInfo)(unsafe.Pointer(pAggInfo)).FnColumn+i, v4)
|
|
_sqlite3VdbeAppendP4(tls, v, (*TAggInfo_func)(unsafe.Pointer(pF)).FpFunc, -int32(8))
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
pF += 32
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Scan all previously generated bytecode looking for an OP_BeginSubrtn
|
|
// ** that is compatible with pExpr. If found, add the y.sub values
|
|
// ** to pExpr and return true. If not found, return false.
|
|
// */
|
|
func _findCompatibleInRhsSubrtn(tls *libc.TLS, pParse uintptr, pExpr uintptr, pNewSig uintptr) (r int32) {
|
|
var pEnd, pOp, pSig, v uintptr
|
|
_, _, _, _ = pEnd, pOp, pSig, v
|
|
if pNewSig == uintptr(0) {
|
|
return 0
|
|
}
|
|
if libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FmSubrtnSig)&(int32(1)<<((*TSubrtnSig)(unsafe.Pointer(pNewSig)).FselId&int32(7))) == 0 {
|
|
return 0
|
|
}
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
pOp = _sqlite3VdbeGetOp(tls, v, int32(1))
|
|
pEnd = _sqlite3VdbeGetLastOp(tls, v)
|
|
for {
|
|
if !(pOp < pEnd) {
|
|
break
|
|
}
|
|
if int32((*TVdbeOp)(unsafe.Pointer(pOp)).Fp4type) != -int32(18) {
|
|
goto _1
|
|
}
|
|
pSig = *(*uintptr)(unsafe.Pointer(pOp + 16))
|
|
if !((*TSubrtnSig)(unsafe.Pointer(pSig)).FbComplete != 0) {
|
|
goto _1
|
|
}
|
|
if (*TSubrtnSig)(unsafe.Pointer(pNewSig)).FselId != (*TSubrtnSig)(unsafe.Pointer(pSig)).FselId {
|
|
goto _1
|
|
}
|
|
if libc.Xstrcmp(tls, (*TSubrtnSig)(unsafe.Pointer(pNewSig)).FzAff, (*TSubrtnSig)(unsafe.Pointer(pSig)).FzAff) != 0 {
|
|
goto _1
|
|
}
|
|
(*(*struct {
|
|
FiAddr int32
|
|
FregReturn int32
|
|
})(unsafe.Pointer(pExpr + 64))).FiAddr = (*TSubrtnSig)(unsafe.Pointer(pSig)).FiAddr
|
|
(*(*struct {
|
|
FiAddr int32
|
|
FregReturn int32
|
|
})(unsafe.Pointer(pExpr + 64))).FregReturn = (*TSubrtnSig)(unsafe.Pointer(pSig)).FregReturn
|
|
(*TExpr)(unsafe.Pointer(pExpr)).FiTable = (*TSubrtnSig)(unsafe.Pointer(pSig)).FiTable
|
|
**(**Tu32)(__ccgo_up(pExpr + 4)) |= libc.Uint32FromInt32(libc.Int32FromInt32(EP_Subrtn))
|
|
return int32(1)
|
|
goto _1
|
|
_1:
|
|
;
|
|
pOp += 24
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function searches pList for an entry that matches the iCol-th column
|
|
// ** of index pIdx.
|
|
// **
|
|
// ** If such an expression is found, its index in pList->a[] is returned. If
|
|
// ** no expression is found, -1 is returned.
|
|
// */
|
|
func _findIndexCol(tls *libc.TLS, pParse uintptr, pList uintptr, iBase int32, pIdx uintptr, iCol int32) (r int32) {
|
|
var i int32
|
|
var p, pColl, zColl uintptr
|
|
_, _, _, _ = i, p, pColl, zColl
|
|
zColl = **(**uintptr)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FazColl + uintptr(iCol)*8))
|
|
i = 0
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(pList)).FnExpr) {
|
|
break
|
|
}
|
|
p = _sqlite3ExprSkipCollateAndLikely(tls, (*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(i)*32))).FpExpr)
|
|
if p != uintptr(0) && (libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) == int32(TK_COLUMN) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) == int32(TK_AGG_COLUMN)) && int32((*TExpr)(unsafe.Pointer(p)).FiColumn) == int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(iCol)*2))) && (*TExpr)(unsafe.Pointer(p)).FiTable == iBase {
|
|
pColl = _sqlite3ExprNNCollSeq(tls, pParse, (*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(i)*32))).FpExpr)
|
|
if 0 == _sqlite3StrICmp(tls, (*TCollSeq)(unsafe.Pointer(pColl)).FzName, zColl) {
|
|
return i
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return -int32(1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The second argument points to an FKey object representing a foreign key
|
|
// ** for which pTab is the parent table. An UPDATE statement against pTab
|
|
// ** is currently being processed. For each column of the table that is
|
|
// ** actually updated, the corresponding element in the aChange[] array
|
|
// ** is zero or greater (if a column is unmodified the corresponding element
|
|
// ** is set to -1). If the rowid column is modified by the UPDATE statement
|
|
// ** the bChngRowid argument is non-zero.
|
|
// **
|
|
// ** This function returns true if any of the columns that are part of the
|
|
// ** parent key for FK constraint *p are modified.
|
|
// */
|
|
func _fkParentIsModified(tls *libc.TLS, pTab uintptr, p uintptr, aChange uintptr, bChngRowid int32) (r int32) {
|
|
var i, iKey int32
|
|
var pCol, zKey uintptr
|
|
_, _, _, _ = i, iKey, pCol, zKey
|
|
i = 0
|
|
for {
|
|
if !(i < (*TFKey)(unsafe.Pointer(p)).FnCol) {
|
|
break
|
|
}
|
|
zKey = (*(*TsColMap)(unsafe.Pointer(p + 64 + uintptr(i)*16))).FzCol
|
|
iKey = 0
|
|
for {
|
|
if !(iKey < int32((*TTable)(unsafe.Pointer(pTab)).FnCol)) {
|
|
break
|
|
}
|
|
if **(**int32)(__ccgo_up(aChange + uintptr(iKey)*4)) >= 0 || iKey == int32((*TTable)(unsafe.Pointer(pTab)).FiPKey) && bChngRowid != 0 {
|
|
pCol = (*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(iKey)*16
|
|
if zKey != 0 {
|
|
if 0 == _sqlite3StrICmp(tls, (*TColumn)(unsafe.Pointer(pCol)).FzCnName, zKey) {
|
|
return int32(1)
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint16((*TColumn)(unsafe.Pointer(pCol)).FcolFlags)&int32(COLFLAG_PRIMKEY) != 0 {
|
|
return int32(1)
|
|
}
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
iKey = iKey + 1
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return TRUE (non-zero) if the i-th entry in the pTabList SrcList can
|
|
// ** be implemented as a co-routine. The i-th entry is guaranteed to be
|
|
// ** a subquery.
|
|
// **
|
|
// ** The subquery is implemented as a co-routine if all of the following are
|
|
// ** true:
|
|
// **
|
|
// ** (1) The subquery will likely be implemented in the outer loop of
|
|
// ** the query. This will be the case if any one of the following
|
|
// ** conditions hold:
|
|
// ** (a) The subquery is the only term in the FROM clause
|
|
// ** (b) The subquery is the left-most term and a CROSS JOIN or similar
|
|
// ** requires it to be the outer loop
|
|
// ** (c) All of the following are true:
|
|
// ** (i) The subquery is the left-most subquery in the FROM clause
|
|
// ** (ii) There is nothing that would prevent the subquery from
|
|
// ** being used as the outer loop if the sqlite3WhereBegin()
|
|
// ** routine nominates it to that position.
|
|
// ** (iii) The query is not a UPDATE ... FROM
|
|
// ** (2) The subquery is not a CTE that should be materialized because
|
|
// ** (a) the AS MATERIALIZED keyword is used, or
|
|
// ** (b) the CTE is used multiple times and does not have the
|
|
// ** NOT MATERIALIZED keyword
|
|
// ** (3) The subquery is not part of a left operand for a RIGHT JOIN
|
|
// ** (4) The SQLITE_Coroutine optimization disable flag is not set
|
|
// ** (5) The subquery is not self-joined
|
|
// */
|
|
func _fromClauseTermCanBeCoroutine(tls *libc.TLS, pParse uintptr, pTabList uintptr, i int32, selFlags int32) (r int32) {
|
|
var pCteUse, pItem uintptr
|
|
_, _ = pCteUse, pItem
|
|
pItem = pTabList + 8 + uintptr(i)*80
|
|
if int32(*(*uint32)(unsafe.Pointer(pItem + 24 + 4))&0x200>>9) != 0 {
|
|
pCteUse = *(*uintptr)(unsafe.Pointer(pItem + 56))
|
|
if libc.Int32FromUint8((*TCteUse)(unsafe.Pointer(pCteUse)).FeM10d) == M10d_Yes {
|
|
return 0
|
|
} /* (2a) */
|
|
if (*TCteUse)(unsafe.Pointer(pCteUse)).FnUse >= int32(2) && libc.Int32FromUint8((*TCteUse)(unsafe.Pointer(pCteUse)).FeM10d) != int32(M10d_No) {
|
|
return 0
|
|
} /* (2b) */
|
|
}
|
|
if libc.Int32FromUint8((*(*TSrcItem)(unsafe.Pointer(pTabList + 8))).Ffg.Fjointype)&int32(JT_LTORJ) != 0 {
|
|
return 0
|
|
} /* (3) */
|
|
if (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).FdbOptFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_Coroutines)) != uint32(0) {
|
|
return 0
|
|
} /* (4) */
|
|
if _isSelfJoinView(tls, pTabList, pItem, i+int32(1), (*TSrcList)(unsafe.Pointer(pTabList)).FnSrc) != uintptr(0) {
|
|
return 0 /* (5) */
|
|
}
|
|
if i == 0 {
|
|
if (*TSrcList)(unsafe.Pointer(pTabList)).FnSrc == int32(1) {
|
|
return int32(1)
|
|
} /* (1a) */
|
|
if libc.Int32FromUint8((*(*TSrcItem)(unsafe.Pointer(pTabList + 8 + 1*80))).Ffg.Fjointype)&int32(JT_CROSS) != 0 {
|
|
return int32(1)
|
|
} /* (1b) */
|
|
if selFlags&int32(SF_UpdateFrom) != 0 {
|
|
return 0
|
|
} /* (1c-iii) */
|
|
return int32(1)
|
|
}
|
|
if selFlags&int32(SF_UpdateFrom) != 0 {
|
|
return 0
|
|
} /* (1c-iii) */
|
|
for int32(1) != 0 {
|
|
if libc.Int32FromUint8((*TSrcItem)(unsafe.Pointer(pItem)).Ffg.Fjointype)&(libc.Int32FromInt32(JT_OUTER)|libc.Int32FromInt32(JT_CROSS)) != 0 {
|
|
return 0
|
|
} /* (1c-ii) */
|
|
if i == 0 {
|
|
break
|
|
}
|
|
i = i - 1
|
|
pItem -= 80
|
|
if int32(*(*uint32)(unsafe.Pointer(pItem + 24 + 4))&0x4>>2) != 0 {
|
|
return 0
|
|
} /* (1c-i) */
|
|
}
|
|
return int32(1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The xColumnLocale() API.
|
|
// */
|
|
func _fts5ApiColumnLocale(tls *libc.TLS, pCtx uintptr, iCol int32, pzLocale uintptr, pnLocale uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var pConfig, pCsr uintptr
|
|
var rc int32
|
|
var _ /* nDummy at bp+8 */ int32
|
|
var _ /* zDummy at bp+0 */ uintptr
|
|
_, _, _ = pConfig, pCsr, rc
|
|
rc = SQLITE_OK
|
|
pCsr = pCtx
|
|
pConfig = (*TFts5Table)(unsafe.Pointer((*TFts5Cursor)(unsafe.Pointer(pCsr)).Fbase.FpVtab)).FpConfig
|
|
**(**uintptr)(__ccgo_up(pzLocale)) = uintptr(0)
|
|
**(**int32)(__ccgo_up(pnLocale)) = 0
|
|
if iCol < 0 || iCol >= (*TFts5Config)(unsafe.Pointer(pConfig)).FnCol {
|
|
rc = int32(SQLITE_RANGE)
|
|
} else {
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Config)(unsafe.Pointer(pConfig)).FabUnindexed + uintptr(iCol)))) == 0 && 0 == _fts5IsContentless(tls, (*TFts5Cursor)(unsafe.Pointer(pCsr)).Fbase.FpVtab, int32(1)) && (*TFts5Config)(unsafe.Pointer(pConfig)).FbLocale != 0 {
|
|
rc = _fts5SeekCursor(tls, pCsr, 0)
|
|
if rc == SQLITE_OK {
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
**(**int32)(__ccgo_up(bp + 8)) = 0
|
|
rc = _fts5TextFromStmt(tls, pConfig, (*TFts5Cursor)(unsafe.Pointer(pCsr)).FpStmt, iCol, bp, bp+8)
|
|
if rc == SQLITE_OK {
|
|
**(**uintptr)(__ccgo_up(pzLocale)) = (*TFts5Config)(unsafe.Pointer(pConfig)).Ft.FpLocale
|
|
**(**int32)(__ccgo_up(pnLocale)) = (*TFts5Config)(unsafe.Pointer(pConfig)).Ft.FnLocale
|
|
}
|
|
_sqlite3Fts5ClearLocale(tls, pConfig)
|
|
}
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
func _fts5ApiColumnSize(tls *libc.TLS, pCtx uintptr, iCol int32, pnToken uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var i, i1, i2, rc int32
|
|
var iRowid Ti64
|
|
var pConfig, pCsr, pTab uintptr
|
|
var _ /* n at bp+8 */ int32
|
|
var _ /* z at bp+0 */ uintptr
|
|
_, _, _, _, _, _, _, _ = i, i1, i2, iRowid, pConfig, pCsr, pTab, rc
|
|
pCsr = pCtx
|
|
pTab = (*TFts5Cursor)(unsafe.Pointer(pCsr)).Fbase.FpVtab
|
|
pConfig = (*TFts5FullTable)(unsafe.Pointer(pTab)).Fp.FpConfig
|
|
rc = SQLITE_OK
|
|
if (*TFts5Cursor)(unsafe.Pointer(pCsr)).Fcsrflags&int32(FTS5CSR_REQUIRE_DOCSIZE) != 0 {
|
|
if (*TFts5Config)(unsafe.Pointer(pConfig)).FbColumnsize != 0 {
|
|
iRowid = _fts5CursorRowid(tls, pCsr)
|
|
rc = _sqlite3Fts5StorageDocsize(tls, (*TFts5FullTable)(unsafe.Pointer(pTab)).FpStorage, iRowid, (*TFts5Cursor)(unsafe.Pointer(pCsr)).FaColumnSize)
|
|
} else {
|
|
if !((*TFts5Config)(unsafe.Pointer(pConfig)).FzContent != 0) || (*TFts5Config)(unsafe.Pointer(pConfig)).FeContent == int32(FTS5_CONTENT_UNINDEXED) {
|
|
i = 0
|
|
for {
|
|
if !(i < (*TFts5Config)(unsafe.Pointer(pConfig)).FnCol) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Config)(unsafe.Pointer(pConfig)).FabUnindexed + uintptr(i)))) == 0 {
|
|
**(**int32)(__ccgo_up((*TFts5Cursor)(unsafe.Pointer(pCsr)).FaColumnSize + uintptr(i)*4)) = -int32(1)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
} else {
|
|
rc = _fts5SeekCursor(tls, pCsr, 0)
|
|
i1 = 0
|
|
for {
|
|
if !(rc == SQLITE_OK && i1 < (*TFts5Config)(unsafe.Pointer(pConfig)).FnCol) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Config)(unsafe.Pointer(pConfig)).FabUnindexed + uintptr(i1)))) == 0 {
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
**(**int32)(__ccgo_up(bp + 8)) = 0
|
|
**(**int32)(__ccgo_up((*TFts5Cursor)(unsafe.Pointer(pCsr)).FaColumnSize + uintptr(i1)*4)) = 0
|
|
rc = _fts5TextFromStmt(tls, pConfig, (*TFts5Cursor)(unsafe.Pointer(pCsr)).FpStmt, i1, bp, bp+8)
|
|
if rc == SQLITE_OK {
|
|
rc = _sqlite3Fts5Tokenize(tls, pConfig, int32(FTS5_TOKENIZE_AUX), **(**uintptr)(__ccgo_up(bp)), **(**int32)(__ccgo_up(bp + 8)), (*TFts5Cursor)(unsafe.Pointer(pCsr)).FaColumnSize+uintptr(i1)*4, __ccgo_fp(_fts5ColumnSizeCb))
|
|
}
|
|
_sqlite3Fts5ClearLocale(tls, pConfig)
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i1 = i1 + 1
|
|
}
|
|
}
|
|
}
|
|
**(**int32)(__ccgo_up(pCsr + 80)) &= ^libc.Int32FromInt32(FTS5CSR_REQUIRE_DOCSIZE)
|
|
}
|
|
if iCol < 0 {
|
|
**(**int32)(__ccgo_up(pnToken)) = 0
|
|
i2 = 0
|
|
for {
|
|
if !(i2 < (*TFts5Config)(unsafe.Pointer(pConfig)).FnCol) {
|
|
break
|
|
}
|
|
**(**int32)(__ccgo_up(pnToken)) += **(**int32)(__ccgo_up((*TFts5Cursor)(unsafe.Pointer(pCsr)).FaColumnSize + uintptr(i2)*4))
|
|
goto _3
|
|
_3:
|
|
;
|
|
i2 = i2 + 1
|
|
}
|
|
} else {
|
|
if iCol < (*TFts5Config)(unsafe.Pointer(pConfig)).FnCol {
|
|
**(**int32)(__ccgo_up(pnToken)) = **(**int32)(__ccgo_up((*TFts5Cursor)(unsafe.Pointer(pCsr)).FaColumnSize + uintptr(iCol)*4))
|
|
} else {
|
|
**(**int32)(__ccgo_up(pnToken)) = 0
|
|
rc = int32(SQLITE_RANGE)
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
func _fts5ApiPhraseFirstColumn(tls *libc.TLS, pCtx uintptr, iPhrase int32, pIter uintptr, piCol uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var i1, rc, v1 int32
|
|
var pConfig, pCsr, pSorter, v2 uintptr
|
|
var _ /* n at bp+0 */ int32
|
|
var _ /* n at bp+4 */ int32
|
|
_, _, _, _, _, _, _ = i1, pConfig, pCsr, pSorter, rc, v1, v2
|
|
rc = SQLITE_OK
|
|
pCsr = pCtx
|
|
pConfig = (*TFts5Table)(unsafe.Pointer((*TFts5Cursor)(unsafe.Pointer(pCsr)).Fbase.FpVtab)).FpConfig
|
|
if (*TFts5Config)(unsafe.Pointer(pConfig)).FeDetail == int32(FTS5_DETAIL_COLUMNS) {
|
|
pSorter = (*TFts5Cursor)(unsafe.Pointer(pCsr)).FpSorter
|
|
if pSorter != 0 {
|
|
if iPhrase == 0 {
|
|
v1 = 0
|
|
} else {
|
|
v1 = *(*int32)(unsafe.Pointer(pSorter + 28 + uintptr(iPhrase-int32(1))*4))
|
|
}
|
|
i1 = v1
|
|
**(**int32)(__ccgo_up(bp)) = *(*int32)(unsafe.Pointer(pSorter + 28 + uintptr(iPhrase)*4)) - i1
|
|
(*TFts5PhraseIter)(unsafe.Pointer(pIter)).Fa = (*TFts5Sorter)(unsafe.Pointer(pSorter)).FaPoslist + uintptr(i1)
|
|
} else {
|
|
rc = _sqlite3Fts5ExprPhraseCollist(tls, (*TFts5Cursor)(unsafe.Pointer(pCsr)).FpExpr, iPhrase, pIter, bp)
|
|
}
|
|
if rc == SQLITE_OK {
|
|
if (*TFts5PhraseIter)(unsafe.Pointer(pIter)).Fa != 0 {
|
|
v2 = (*TFts5PhraseIter)(unsafe.Pointer(pIter)).Fa + uintptr(**(**int32)(__ccgo_up(bp)))
|
|
} else {
|
|
v2 = uintptr(0)
|
|
}
|
|
(*TFts5PhraseIter)(unsafe.Pointer(pIter)).Fb = v2
|
|
**(**int32)(__ccgo_up(piCol)) = 0
|
|
_fts5ApiPhraseNextColumn(tls, pCtx, pIter, piCol)
|
|
}
|
|
} else {
|
|
rc = _fts5CsrPoslist(tls, pCsr, iPhrase, pIter, bp+4)
|
|
if rc == SQLITE_OK {
|
|
if (*TFts5PhraseIter)(unsafe.Pointer(pIter)).Fa != 0 {
|
|
v2 = (*TFts5PhraseIter)(unsafe.Pointer(pIter)).Fa + uintptr(**(**int32)(__ccgo_up(bp + 4)))
|
|
} else {
|
|
v2 = uintptr(0)
|
|
}
|
|
(*TFts5PhraseIter)(unsafe.Pointer(pIter)).Fb = v2
|
|
if **(**int32)(__ccgo_up(bp + 4)) <= 0 {
|
|
**(**int32)(__ccgo_up(piCol)) = -int32(1)
|
|
} else {
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up((*TFts5PhraseIter)(unsafe.Pointer(pIter)).Fa))) == int32(0x01) {
|
|
**(**uintptr)(__ccgo_up(pIter)) += uintptr(int32(1) + _sqlite3Fts5GetVarint32(tls, (*TFts5PhraseIter)(unsafe.Pointer(pIter)).Fa+1, piCol))
|
|
} else {
|
|
**(**int32)(__ccgo_up(piCol)) = 0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
func _fts5AppendRowid(tls *libc.TLS, p uintptr, iDelta Tu64, pUnused uintptr, pBuf uintptr) {
|
|
_ = pUnused
|
|
_sqlite3Fts5BufferAppendVarint(tls, p+60, pBuf, libc.Int64FromUint64(iDelta))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compare the contents of the two buffers using memcmp(). If one buffer
|
|
// ** is a prefix of the other, it is considered the lesser.
|
|
// **
|
|
// ** Return -ve if pLeft is smaller than pRight, 0 if they are equal or
|
|
// ** +ve if pRight is smaller than pLeft. In other words:
|
|
// **
|
|
// ** res = *pLeft - *pRight
|
|
// */
|
|
func _fts5BufferCompare(tls *libc.TLS, pLeft uintptr, pRight uintptr) (r int32) {
|
|
var nCmp, res, v1 int32
|
|
_, _, _ = nCmp, res, v1
|
|
if (*TFts5Buffer)(unsafe.Pointer(pLeft)).Fn < (*TFts5Buffer)(unsafe.Pointer(pRight)).Fn {
|
|
v1 = (*TFts5Buffer)(unsafe.Pointer(pLeft)).Fn
|
|
} else {
|
|
v1 = (*TFts5Buffer)(unsafe.Pointer(pRight)).Fn
|
|
}
|
|
nCmp = v1
|
|
if nCmp <= 0 {
|
|
v1 = 0
|
|
} else {
|
|
v1 = libc.Xmemcmp(tls, (*TFts5Buffer)(unsafe.Pointer(pLeft)).Fp, (*TFts5Buffer)(unsafe.Pointer(pRight)).Fp, libc.Uint64FromInt32(nCmp))
|
|
}
|
|
res = v1
|
|
if res == 0 {
|
|
v1 = (*TFts5Buffer)(unsafe.Pointer(pLeft)).Fn - (*TFts5Buffer)(unsafe.Pointer(pRight)).Fn
|
|
} else {
|
|
v1 = res
|
|
}
|
|
return v1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated
|
|
// ** correctly for the current view. Return SQLITE_OK if successful, or an
|
|
// ** SQLite error code otherwise.
|
|
// */
|
|
func _fts5CacheInstArray(tls *libc.TLS, pCsr uintptr) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var aInst, aIter uintptr
|
|
var i, iBest, nCol, nInst, nIter, nNewSize, v3 int32
|
|
var nByte Tsqlite3_int64
|
|
var _ /* a at bp+8 */ uintptr
|
|
var _ /* n at bp+16 */ int32
|
|
var _ /* rc at bp+0 */ int32
|
|
_, _, _, _, _, _, _, _, _, _ = aInst, aIter, i, iBest, nByte, nCol, nInst, nIter, nNewSize, v3
|
|
**(**int32)(__ccgo_up(bp)) = SQLITE_OK /* Number of iterators/phrases */
|
|
nCol = (*TFts5Config)(unsafe.Pointer((*TFts5Table)(unsafe.Pointer((*TFts5Cursor)(unsafe.Pointer(pCsr)).Fbase.FpVtab)).FpConfig)).FnCol
|
|
nIter = _sqlite3Fts5ExprPhraseCount(tls, (*TFts5Cursor)(unsafe.Pointer(pCsr)).FpExpr)
|
|
if (*TFts5Cursor)(unsafe.Pointer(pCsr)).FaInstIter == uintptr(0) {
|
|
nByte = libc.Int64FromUint64(uint64(32) * libc.Uint64FromInt32(nIter))
|
|
(*TFts5Cursor)(unsafe.Pointer(pCsr)).FaInstIter = _sqlite3Fts5MallocZero(tls, bp, nByte)
|
|
}
|
|
aIter = (*TFts5Cursor)(unsafe.Pointer(pCsr)).FaInstIter
|
|
if aIter != 0 {
|
|
nInst = 0
|
|
/* Initialize all iterators */
|
|
i = 0
|
|
for {
|
|
if !(i < nIter && **(**int32)(__ccgo_up(bp)) == SQLITE_OK) {
|
|
break
|
|
}
|
|
**(**int32)(__ccgo_up(bp)) = _fts5CsrPoslist(tls, pCsr, i, bp+8, bp+16)
|
|
if **(**int32)(__ccgo_up(bp)) == SQLITE_OK {
|
|
_sqlite3Fts5PoslistReaderInit(tls, **(**uintptr)(__ccgo_up(bp + 8)), **(**int32)(__ccgo_up(bp + 16)), aIter+uintptr(i)*32)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if **(**int32)(__ccgo_up(bp)) == SQLITE_OK {
|
|
for int32(1) != 0 {
|
|
iBest = -int32(1)
|
|
i = 0
|
|
for {
|
|
if !(i < nIter) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((**(**TFts5PoslistReader)(__ccgo_up(aIter + uintptr(i)*32))).FbEof) == 0 && (iBest < 0 || (**(**TFts5PoslistReader)(__ccgo_up(aIter + uintptr(i)*32))).FiPos < (**(**TFts5PoslistReader)(__ccgo_up(aIter + uintptr(iBest)*32))).FiPos) {
|
|
iBest = i
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if iBest < 0 {
|
|
break
|
|
}
|
|
nInst = nInst + 1
|
|
if nInst >= (*TFts5Cursor)(unsafe.Pointer(pCsr)).FnInstAlloc {
|
|
if (*TFts5Cursor)(unsafe.Pointer(pCsr)).FnInstAlloc != 0 {
|
|
v3 = (*TFts5Cursor)(unsafe.Pointer(pCsr)).FnInstAlloc * int32(2)
|
|
} else {
|
|
v3 = int32(32)
|
|
}
|
|
nNewSize = v3
|
|
aInst = Xsqlite3_realloc64(tls, (*TFts5Cursor)(unsafe.Pointer(pCsr)).FaInst, uint64(libc.Uint64FromInt32(nNewSize)*uint64(4)*uint64(3)))
|
|
if aInst != 0 {
|
|
(*TFts5Cursor)(unsafe.Pointer(pCsr)).FaInst = aInst
|
|
(*TFts5Cursor)(unsafe.Pointer(pCsr)).FnInstAlloc = nNewSize
|
|
} else {
|
|
nInst = nInst - 1
|
|
**(**int32)(__ccgo_up(bp)) = int32(SQLITE_NOMEM)
|
|
break
|
|
}
|
|
}
|
|
aInst = (*TFts5Cursor)(unsafe.Pointer(pCsr)).FaInst + uintptr(int32(3)*(nInst-int32(1)))*4
|
|
**(**int32)(__ccgo_up(aInst)) = iBest
|
|
**(**int32)(__ccgo_up(aInst + 1*4)) = int32((**(**TFts5PoslistReader)(__ccgo_up(aIter + uintptr(iBest)*32))).FiPos >> libc.Int32FromInt32(32) & libc.Int64FromInt32(0x7FFFFFFF))
|
|
**(**int32)(__ccgo_up(aInst + 2*4)) = int32((**(**TFts5PoslistReader)(__ccgo_up(aIter + uintptr(iBest)*32))).FiPos & libc.Int64FromInt32(0x7FFFFFFF))
|
|
if **(**int32)(__ccgo_up(aInst + 1*4)) >= nCol {
|
|
**(**int32)(__ccgo_up(bp)) = libc.Int32FromInt32(SQLITE_CORRUPT) | libc.Int32FromInt32(1)<<libc.Int32FromInt32(8)
|
|
break
|
|
}
|
|
_sqlite3Fts5PoslistReaderNext(tls, aIter+uintptr(iBest)*32)
|
|
}
|
|
}
|
|
(*TFts5Cursor)(unsafe.Pointer(pCsr)).FnInstCount = nInst
|
|
**(**int32)(__ccgo_up(pCsr + 80)) &= ^libc.Int32FromInt32(FTS5CSR_REQUIRE_INST)
|
|
}
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
|
|
func _fts5ConfigSetEnum(tls *libc.TLS, aEnum uintptr, zEnum uintptr, peVal uintptr) (r int32) {
|
|
var i, iVal, nEnum, v2 int32
|
|
_, _, _, _ = i, iVal, nEnum, v2
|
|
nEnum = libc.Int32FromUint64(libc.Xstrlen(tls, zEnum))
|
|
iVal = -int32(1)
|
|
i = 0
|
|
for {
|
|
if !((**(**TFts5Enum)(__ccgo_up(aEnum + uintptr(i)*16))).FzName != 0) {
|
|
break
|
|
}
|
|
if Xsqlite3_strnicmp(tls, (**(**TFts5Enum)(__ccgo_up(aEnum + uintptr(i)*16))).FzName, zEnum, nEnum) == 0 {
|
|
if iVal >= 0 {
|
|
return int32(SQLITE_ERROR)
|
|
}
|
|
iVal = (**(**TFts5Enum)(__ccgo_up(aEnum + uintptr(i)*16))).FeVal
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
**(**int32)(__ccgo_up(peVal)) = iVal
|
|
if iVal < 0 {
|
|
v2 = int32(SQLITE_ERROR)
|
|
} else {
|
|
v2 = SQLITE_OK
|
|
}
|
|
return v2
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Advance the iterator passed as the only argument. If the end of the
|
|
// ** doclist-index page is reached, return non-zero.
|
|
// */
|
|
func _fts5DlidxLvlNext(tls *libc.TLS, pLvl uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iOff int32
|
|
var pData, v2 uintptr
|
|
var _ /* iVal at bp+0 */ Tu64
|
|
_, _, _ = iOff, pData, v2
|
|
pData = (*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FpData
|
|
if (*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FiOff == 0 {
|
|
(*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FiOff = int32(1)
|
|
**(**int32)(__ccgo_up(pLvl + 8)) += _sqlite3Fts5GetVarint32(tls, (*TFts5Data)(unsafe.Pointer(pData)).Fp+1, pLvl+20)
|
|
**(**int32)(__ccgo_up(pLvl + 8)) += libc.Int32FromUint8(_sqlite3Fts5GetVarint(tls, (*TFts5Data)(unsafe.Pointer(pData)).Fp+uintptr((*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FiOff), pLvl+24))
|
|
(*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FiFirstOff = (*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FiOff
|
|
} else {
|
|
iOff = (*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FiOff
|
|
for {
|
|
if !(iOff < (*TFts5Data)(unsafe.Pointer(pData)).Fnn) {
|
|
break
|
|
}
|
|
if **(**Tu8)(__ccgo_up((*TFts5Data)(unsafe.Pointer(pData)).Fp + uintptr(iOff))) != 0 {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
iOff = iOff + 1
|
|
}
|
|
if iOff < (*TFts5Data)(unsafe.Pointer(pData)).Fnn {
|
|
**(**int32)(__ccgo_up(pLvl + 20)) += iOff - (*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FiOff + int32(1)
|
|
iOff = iOff + libc.Int32FromUint8(_sqlite3Fts5GetVarint(tls, (*TFts5Data)(unsafe.Pointer(pData)).Fp+uintptr(iOff), bp))
|
|
v2 = pLvl + 24
|
|
*(*Ti64)(unsafe.Pointer(v2)) = Ti64(uint64(*(*Ti64)(unsafe.Pointer(v2))) + **(**Tu64)(__ccgo_up(bp)))
|
|
(*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FiOff = iOff
|
|
} else {
|
|
(*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FbEof = int32(1)
|
|
}
|
|
}
|
|
return (*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FbEof
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Move the iterator passed as the only argument to the previous entry.
|
|
// */
|
|
func _fts5DlidxLvlPrev(tls *libc.TLS, pLvl uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var a, v1 uintptr
|
|
var iOff, ii, nZero int32
|
|
var _ /* delta at bp+0 */ Tu64
|
|
_, _, _, _, _ = a, iOff, ii, nZero, v1
|
|
iOff = (*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FiOff
|
|
if iOff <= (*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FiFirstOff {
|
|
(*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FbEof = int32(1)
|
|
} else {
|
|
a = (*TFts5Data)(unsafe.Pointer((*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FpData)).Fp
|
|
(*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FiOff = 0
|
|
_fts5DlidxLvlNext(tls, pLvl)
|
|
for int32(1) != 0 {
|
|
nZero = 0
|
|
ii = (*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FiOff
|
|
**(**Tu64)(__ccgo_up(bp)) = uint64(0)
|
|
for libc.Int32FromUint8(**(**Tu8)(__ccgo_up(a + uintptr(ii)))) == 0 {
|
|
nZero = nZero + 1
|
|
ii = ii + 1
|
|
}
|
|
ii = ii + libc.Int32FromUint8(_sqlite3Fts5GetVarint(tls, a+uintptr(ii), bp))
|
|
if ii >= iOff {
|
|
break
|
|
}
|
|
**(**int32)(__ccgo_up(pLvl + 20)) += nZero + int32(1)
|
|
v1 = pLvl + 24
|
|
*(*Ti64)(unsafe.Pointer(v1)) = Ti64(uint64(*(*Ti64)(unsafe.Pointer(v1))) + **(**Tu64)(__ccgo_up(bp)))
|
|
(*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FiOff = ii
|
|
}
|
|
}
|
|
return (*TFts5DlidxLvl)(unsafe.Pointer(pLvl)).FbEof
|
|
}
|
|
|
|
func _fts5ExprAssignXNext(tls *libc.TLS, pNode uintptr) {
|
|
var pNear uintptr
|
|
_ = pNear
|
|
switch (*TFts5ExprNode)(unsafe.Pointer(pNode)).FeType {
|
|
case int32(FTS5_STRING):
|
|
pNear = (*TFts5ExprNode)(unsafe.Pointer(pNode)).FpNear
|
|
if (*TFts5ExprNearset)(unsafe.Pointer(pNear)).FnPhrase == int32(1) && (*TFts5ExprPhrase)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pNear + 24)))).FnTerm == int32(1) && (*(*TFts5ExprTerm)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pNear + 24)) + 32))).FpSynonym == uintptr(0) && libc.Int32FromUint8((*(*TFts5ExprTerm)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pNear + 24)) + 32))).FbFirst) == 0 {
|
|
(*TFts5ExprNode)(unsafe.Pointer(pNode)).FeType = int32(FTS5_TERM)
|
|
(*TFts5ExprNode)(unsafe.Pointer(pNode)).FxNext = __ccgo_fp(_fts5ExprNodeNext_TERM)
|
|
} else {
|
|
(*TFts5ExprNode)(unsafe.Pointer(pNode)).FxNext = __ccgo_fp(_fts5ExprNodeNext_STRING)
|
|
}
|
|
case int32(FTS5_OR):
|
|
(*TFts5ExprNode)(unsafe.Pointer(pNode)).FxNext = __ccgo_fp(_fts5ExprNodeNext_OR)
|
|
case int32(FTS5_AND):
|
|
(*TFts5ExprNode)(unsafe.Pointer(pNode)).FxNext = __ccgo_fp(_fts5ExprNodeNext_AND)
|
|
default:
|
|
(*TFts5ExprNode)(unsafe.Pointer(pNode)).FxNext = __ccgo_fp(_fts5ExprNodeNext_NOT)
|
|
break
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Initialize all term iterators in the pNear object. If any term is found
|
|
// ** to match no documents at all, return immediately without initializing any
|
|
// ** further iterators.
|
|
// **
|
|
// ** If an error occurs, return an SQLite error code. Otherwise, return
|
|
// ** SQLITE_OK. It is not considered an error if some term matches zero
|
|
// ** documents.
|
|
// */
|
|
func _fts5ExprNearInitAll(tls *libc.TLS, pExpr uintptr, pNode uintptr) (r int32) {
|
|
var bHit, i, j, rc, v4, v5 int32
|
|
var p, pNear, pPhrase, pTerm uintptr
|
|
_, _, _, _, _, _, _, _, _, _ = bHit, i, j, p, pNear, pPhrase, pTerm, rc, v4, v5
|
|
pNear = (*TFts5ExprNode)(unsafe.Pointer(pNode)).FpNear
|
|
i = 0
|
|
for {
|
|
if !(i < (*TFts5ExprNearset)(unsafe.Pointer(pNear)).FnPhrase) {
|
|
break
|
|
}
|
|
pPhrase = *(*uintptr)(unsafe.Pointer(pNear + 24 + uintptr(i)*8))
|
|
if (*TFts5ExprPhrase)(unsafe.Pointer(pPhrase)).FnTerm == 0 {
|
|
(*TFts5ExprNode)(unsafe.Pointer(pNode)).FbEof = int32(1)
|
|
return SQLITE_OK
|
|
} else {
|
|
j = 0
|
|
for {
|
|
if !(j < (*TFts5ExprPhrase)(unsafe.Pointer(pPhrase)).FnTerm) {
|
|
break
|
|
}
|
|
pTerm = pPhrase + 32 + uintptr(j)*40
|
|
bHit = 0
|
|
p = pTerm
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
if (*TFts5ExprTerm)(unsafe.Pointer(p)).FpIter != 0 {
|
|
_sqlite3Fts5IterClose(tls, (*TFts5ExprTerm)(unsafe.Pointer(p)).FpIter)
|
|
(*TFts5ExprTerm)(unsafe.Pointer(p)).FpIter = uintptr(0)
|
|
}
|
|
if (*TFts5ExprTerm)(unsafe.Pointer(pTerm)).FbPrefix != 0 {
|
|
v4 = int32(FTS5INDEX_QUERY_PREFIX)
|
|
} else {
|
|
v4 = 0
|
|
}
|
|
if (*TFts5Expr)(unsafe.Pointer(pExpr)).FbDesc != 0 {
|
|
v5 = int32(FTS5INDEX_QUERY_DESC)
|
|
} else {
|
|
v5 = 0
|
|
}
|
|
rc = _sqlite3Fts5IndexQuery(tls, (*TFts5Expr)(unsafe.Pointer(pExpr)).FpIndex, (*TFts5ExprTerm)(unsafe.Pointer(p)).FpTerm, (*TFts5ExprTerm)(unsafe.Pointer(p)).FnQueryTerm, v4|v5, (*TFts5ExprNearset)(unsafe.Pointer(pNear)).FpColset, p+24)
|
|
if rc != SQLITE_OK {
|
|
return rc
|
|
}
|
|
if 0 == libc.Int32FromUint8((*TFts5IndexIter)(unsafe.Pointer((*TFts5ExprTerm)(unsafe.Pointer(p)).FpIter)).FbEof) {
|
|
bHit = int32(1)
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
p = (*TFts5ExprTerm)(unsafe.Pointer(p)).FpSynonym
|
|
}
|
|
if bHit == 0 {
|
|
(*TFts5ExprNode)(unsafe.Pointer(pNode)).FbEof = int32(1)
|
|
return SQLITE_OK
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
j = j + 1
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
(*TFts5ExprNode)(unsafe.Pointer(pNode)).FbEof = 0
|
|
return SQLITE_OK
|
|
}
|
|
|
|
func _fts5ExprNearTest(tls *libc.TLS, pRc uintptr, pExpr uintptr, pNode uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var i int32
|
|
var pIter, pIter1, pNear, pPhrase, pPhrase1, pTerm uintptr
|
|
var _ /* bMatch at bp+4 */ int32
|
|
var _ /* rc at bp+0 */ int32
|
|
_, _, _, _, _, _, _ = i, pIter, pIter1, pNear, pPhrase, pPhrase1, pTerm
|
|
pNear = (*TFts5ExprNode)(unsafe.Pointer(pNode)).FpNear
|
|
**(**int32)(__ccgo_up(bp)) = **(**int32)(__ccgo_up(pRc))
|
|
if (*TFts5Config)(unsafe.Pointer((*TFts5Expr)(unsafe.Pointer(pExpr)).FpConfig)).FeDetail != FTS5_DETAIL_FULL {
|
|
pPhrase = *(*uintptr)(unsafe.Pointer(pNear + 24))
|
|
(*TFts5ExprPhrase)(unsafe.Pointer(pPhrase)).Fposlist.Fn = 0
|
|
pTerm = pPhrase + 32
|
|
for {
|
|
if !(pTerm != 0) {
|
|
break
|
|
}
|
|
pIter = (*TFts5ExprTerm)(unsafe.Pointer(pTerm)).FpIter
|
|
if libc.Int32FromUint8((*TFts5IndexIter)(unsafe.Pointer(pIter)).FbEof) == 0 {
|
|
if (*TFts5IndexIter)(unsafe.Pointer(pIter)).FiRowid == (*TFts5ExprNode)(unsafe.Pointer(pNode)).FiRowid && (*TFts5IndexIter)(unsafe.Pointer(pIter)).FnData > 0 {
|
|
(*TFts5ExprPhrase)(unsafe.Pointer(pPhrase)).Fposlist.Fn = int32(1)
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
pTerm = (*TFts5ExprTerm)(unsafe.Pointer(pTerm)).FpSynonym
|
|
}
|
|
return (*TFts5ExprPhrase)(unsafe.Pointer(pPhrase)).Fposlist.Fn
|
|
} else {
|
|
/* Check that each phrase in the nearset matches the current row.
|
|
** Populate the pPhrase->poslist buffers at the same time. If any
|
|
** phrase is not a match, break out of the loop early. */
|
|
i = 0
|
|
for {
|
|
if !(**(**int32)(__ccgo_up(bp)) == SQLITE_OK && i < (*TFts5ExprNearset)(unsafe.Pointer(pNear)).FnPhrase) {
|
|
break
|
|
}
|
|
pPhrase1 = *(*uintptr)(unsafe.Pointer(pNear + 24 + uintptr(i)*8))
|
|
if (*TFts5ExprPhrase)(unsafe.Pointer(pPhrase1)).FnTerm > int32(1) || (*(*TFts5ExprTerm)(unsafe.Pointer(pPhrase1 + 32))).FpSynonym != 0 || (*TFts5ExprNearset)(unsafe.Pointer(pNear)).FpColset != 0 || (*(*TFts5ExprTerm)(unsafe.Pointer(pPhrase1 + 32))).FbFirst != 0 {
|
|
**(**int32)(__ccgo_up(bp + 4)) = 0
|
|
**(**int32)(__ccgo_up(bp)) = _fts5ExprPhraseIsMatch(tls, pNode, pPhrase1, bp+4)
|
|
if **(**int32)(__ccgo_up(bp + 4)) == 0 {
|
|
break
|
|
}
|
|
} else {
|
|
pIter1 = (*(*TFts5ExprTerm)(unsafe.Pointer(pPhrase1 + 32))).FpIter
|
|
_sqlite3Fts5BufferSet(tls, bp, pPhrase1+8, (*TFts5IndexIter)(unsafe.Pointer(pIter1)).FnData, (*TFts5IndexIter)(unsafe.Pointer(pIter1)).FpData)
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
**(**int32)(__ccgo_up(pRc)) = **(**int32)(__ccgo_up(bp))
|
|
if i == (*TFts5ExprNearset)(unsafe.Pointer(pNear)).FnPhrase && (i == int32(1) || _fts5ExprNearIsMatch(tls, pRc, pNear) != 0) {
|
|
return int32(1)
|
|
}
|
|
return 0
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Advance the first term iterator in the first phrase of pNear. Set output
|
|
// ** variable *pbEof to true if it reaches EOF or if an error occurs.
|
|
// **
|
|
// ** Return SQLITE_OK if successful, or an SQLite error code if an error
|
|
// ** occurs.
|
|
// */
|
|
func _fts5ExprNodeNext_STRING(tls *libc.TLS, pExpr uintptr, pNode uintptr, bFromValid int32, iFrom Ti64) (r int32) {
|
|
var bEof, rc int32
|
|
var iRowid, ii Ti64
|
|
var p, pIter, pTerm uintptr
|
|
_, _, _, _, _, _, _ = bEof, iRowid, ii, p, pIter, pTerm, rc
|
|
pTerm = *(*uintptr)(unsafe.Pointer((*TFts5ExprNode)(unsafe.Pointer(pNode)).FpNear + 24)) + 32
|
|
rc = SQLITE_OK
|
|
(*TFts5ExprNode)(unsafe.Pointer(pNode)).FbNomatch = 0
|
|
if (*TFts5ExprTerm)(unsafe.Pointer(pTerm)).FpSynonym != 0 {
|
|
bEof = int32(1)
|
|
/* Find the firstest rowid any synonym points to. */
|
|
iRowid = _fts5ExprSynonymRowid(tls, pTerm, (*TFts5Expr)(unsafe.Pointer(pExpr)).FbDesc, uintptr(0))
|
|
/* Advance each iterator that currently points to iRowid. Or, if iFrom
|
|
** is valid - each iterator that points to a rowid before iFrom. */
|
|
p = pTerm
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((*TFts5IndexIter)(unsafe.Pointer((*TFts5ExprTerm)(unsafe.Pointer(p)).FpIter)).FbEof) == 0 {
|
|
ii = (*TFts5IndexIter)(unsafe.Pointer((*TFts5ExprTerm)(unsafe.Pointer(p)).FpIter)).FiRowid
|
|
if ii == iRowid || bFromValid != 0 && ii != iFrom && libc.BoolInt32(ii > iFrom) == (*TFts5Expr)(unsafe.Pointer(pExpr)).FbDesc {
|
|
if bFromValid != 0 {
|
|
rc = _sqlite3Fts5IterNextFrom(tls, (*TFts5ExprTerm)(unsafe.Pointer(p)).FpIter, iFrom)
|
|
} else {
|
|
rc = _sqlite3Fts5IterNext(tls, (*TFts5ExprTerm)(unsafe.Pointer(p)).FpIter)
|
|
}
|
|
if rc != SQLITE_OK {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((*TFts5IndexIter)(unsafe.Pointer((*TFts5ExprTerm)(unsafe.Pointer(p)).FpIter)).FbEof) == 0 {
|
|
bEof = 0
|
|
}
|
|
} else {
|
|
bEof = 0
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = (*TFts5ExprTerm)(unsafe.Pointer(p)).FpSynonym
|
|
}
|
|
/* Set the EOF flag if either all synonym iterators are at EOF or an
|
|
** error has occurred. */
|
|
(*TFts5ExprNode)(unsafe.Pointer(pNode)).FbEof = libc.BoolInt32(rc != 0 || bEof != 0)
|
|
} else {
|
|
pIter = (*TFts5ExprTerm)(unsafe.Pointer(pTerm)).FpIter
|
|
if bFromValid != 0 {
|
|
rc = _sqlite3Fts5IterNextFrom(tls, pIter, iFrom)
|
|
} else {
|
|
rc = _sqlite3Fts5IterNext(tls, pIter)
|
|
}
|
|
(*TFts5ExprNode)(unsafe.Pointer(pNode)).FbEof = libc.BoolInt32(rc != 0 || (*TFts5IndexIter)(unsafe.Pointer(pIter)).FbEof != 0)
|
|
}
|
|
if (*TFts5ExprNode)(unsafe.Pointer(pNode)).FbEof == 0 {
|
|
rc = _fts5ExprNodeTest_STRING(tls, pExpr, pNode)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** xNext() method for a node of type FTS5_TERM.
|
|
// */
|
|
func _fts5ExprNodeNext_TERM(tls *libc.TLS, pExpr uintptr, pNode uintptr, bFromValid int32, iFrom Ti64) (r int32) {
|
|
var pIter uintptr
|
|
var rc int32
|
|
_, _ = pIter, rc
|
|
pIter = (*(*TFts5ExprTerm)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer((*TFts5ExprNode)(unsafe.Pointer(pNode)).FpNear + 24)) + 32))).FpIter
|
|
if bFromValid != 0 {
|
|
rc = _sqlite3Fts5IterNextFrom(tls, pIter, iFrom)
|
|
} else {
|
|
rc = _sqlite3Fts5IterNext(tls, pIter)
|
|
}
|
|
if rc == SQLITE_OK && libc.Int32FromUint8((*TFts5IndexIter)(unsafe.Pointer(pIter)).FbEof) == 0 {
|
|
rc = _fts5ExprNodeTest_TERM(tls, pExpr, pNode)
|
|
} else {
|
|
(*TFts5ExprNode)(unsafe.Pointer(pNode)).FbEof = int32(1)
|
|
(*TFts5ExprNode)(unsafe.Pointer(pNode)).FbNomatch = 0
|
|
}
|
|
return rc
|
|
}
|
|
|
|
func _fts5ExprPopulatePoslistsCb(tls *libc.TLS, pCtx uintptr, tflags int32, pToken uintptr, nToken int32, iUnused1 int32, iUnused2 int32) (r int32) {
|
|
var i, iCol, iTokOff, nQuery, rc int32
|
|
var iRowid Ti64
|
|
var p, pExpr, pT uintptr
|
|
_, _, _, _, _, _, _, _, _ = i, iCol, iRowid, iTokOff, nQuery, p, pExpr, pT, rc
|
|
p = pCtx
|
|
pExpr = (*TFts5ExprCtx)(unsafe.Pointer(p)).FpExpr
|
|
nQuery = nToken
|
|
iRowid = (*TFts5ExprNode)(unsafe.Pointer((*TFts5Expr)(unsafe.Pointer(pExpr)).FpRoot)).FiRowid
|
|
_ = iUnused1
|
|
_ = iUnused2
|
|
if nQuery > int32(FTS5_MAX_TOKEN_SIZE) {
|
|
nQuery = int32(FTS5_MAX_TOKEN_SIZE)
|
|
}
|
|
if (*TFts5Config)(unsafe.Pointer((*TFts5Expr)(unsafe.Pointer(pExpr)).FpConfig)).FbTokendata != 0 {
|
|
nQuery = _fts5QueryTerm(tls, pToken, nQuery)
|
|
}
|
|
if tflags&int32(FTS5_TOKEN_COLOCATED) == 0 {
|
|
(*TFts5ExprCtx)(unsafe.Pointer(p)).FiOff = (*TFts5ExprCtx)(unsafe.Pointer(p)).FiOff + 1
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < (*TFts5Expr)(unsafe.Pointer(pExpr)).FnPhrase) {
|
|
break
|
|
}
|
|
if (**(**TFts5PoslistPopulator)(__ccgo_up((*TFts5ExprCtx)(unsafe.Pointer(p)).FaPopulator + uintptr(i)*16))).FbOk == 0 {
|
|
goto _1
|
|
}
|
|
pT = **(**uintptr)(__ccgo_up((*TFts5Expr)(unsafe.Pointer(pExpr)).FapExprPhrase + uintptr(i)*8)) + 32
|
|
for {
|
|
if !(pT != 0) {
|
|
break
|
|
}
|
|
if ((*TFts5ExprTerm)(unsafe.Pointer(pT)).FnQueryTerm == nQuery || (*TFts5ExprTerm)(unsafe.Pointer(pT)).FnQueryTerm < nQuery && (*TFts5ExprTerm)(unsafe.Pointer(pT)).FbPrefix != 0) && libc.Xmemcmp(tls, (*TFts5ExprTerm)(unsafe.Pointer(pT)).FpTerm, pToken, libc.Uint64FromInt32((*TFts5ExprTerm)(unsafe.Pointer(pT)).FnQueryTerm)) == 0 {
|
|
rc = _sqlite3Fts5PoslistWriterAppend(tls, **(**uintptr)(__ccgo_up((*TFts5Expr)(unsafe.Pointer(pExpr)).FapExprPhrase + uintptr(i)*8))+8, (*TFts5ExprCtx)(unsafe.Pointer(p)).FaPopulator+uintptr(i)*16, (*TFts5ExprCtx)(unsafe.Pointer(p)).FiOff)
|
|
if rc == SQLITE_OK && ((*TFts5Config)(unsafe.Pointer((*TFts5Expr)(unsafe.Pointer(pExpr)).FpConfig)).FbTokendata != 0 || (*TFts5ExprTerm)(unsafe.Pointer(pT)).FbPrefix != 0) {
|
|
iCol = int32((*TFts5ExprCtx)(unsafe.Pointer(p)).FiOff >> int32(32))
|
|
iTokOff = int32((*TFts5ExprCtx)(unsafe.Pointer(p)).FiOff & int64(0x7FFFFFFF))
|
|
rc = _sqlite3Fts5IndexIterWriteTokendata(tls, (*TFts5ExprTerm)(unsafe.Pointer(pT)).FpIter, pToken, nToken, iRowid, iCol, iTokOff)
|
|
}
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
break
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
pT = (*TFts5ExprTerm)(unsafe.Pointer(pT)).FpSynonym
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Arguments pLeft and pRight point to linked-lists of hash-entry objects,
|
|
// ** each sorted in key order. This function merges the two lists into a
|
|
// ** single list and returns a pointer to its first element.
|
|
// */
|
|
func _fts5HashEntryMerge(tls *libc.TLS, pLeft uintptr, pRight uintptr) (r uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var cmp, nMin, v1 int32
|
|
var p1, p2, ppOut, zKey1, zKey2 uintptr
|
|
var _ /* pRet at bp+0 */ uintptr
|
|
_, _, _, _, _, _, _, _ = cmp, nMin, p1, p2, ppOut, zKey1, zKey2, v1
|
|
p1 = pLeft
|
|
p2 = pRight
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
ppOut = bp
|
|
for p1 != 0 || p2 != 0 {
|
|
if p1 == uintptr(0) {
|
|
**(**uintptr)(__ccgo_up(ppOut)) = p2
|
|
p2 = uintptr(0)
|
|
} else {
|
|
if p2 == uintptr(0) {
|
|
**(**uintptr)(__ccgo_up(ppOut)) = p1
|
|
p1 = uintptr(0)
|
|
} else {
|
|
zKey1 = p1 + 1*48
|
|
zKey2 = p2 + 1*48
|
|
if (*TFts5HashEntry)(unsafe.Pointer(p1)).FnKey < (*TFts5HashEntry)(unsafe.Pointer(p2)).FnKey {
|
|
v1 = (*TFts5HashEntry)(unsafe.Pointer(p1)).FnKey
|
|
} else {
|
|
v1 = (*TFts5HashEntry)(unsafe.Pointer(p2)).FnKey
|
|
}
|
|
nMin = v1
|
|
cmp = libc.Xmemcmp(tls, zKey1, zKey2, libc.Uint64FromInt32(nMin))
|
|
if cmp == 0 {
|
|
cmp = (*TFts5HashEntry)(unsafe.Pointer(p1)).FnKey - (*TFts5HashEntry)(unsafe.Pointer(p2)).FnKey
|
|
}
|
|
if cmp > 0 {
|
|
/* p2 is smaller */
|
|
**(**uintptr)(__ccgo_up(ppOut)) = p2
|
|
ppOut = p2 + 8
|
|
p2 = (*TFts5HashEntry)(unsafe.Pointer(p2)).FpScanNext
|
|
} else {
|
|
/* p1 is smaller */
|
|
**(**uintptr)(__ccgo_up(ppOut)) = p1
|
|
ppOut = p1 + 8
|
|
p1 = (*TFts5HashEntry)(unsafe.Pointer(p1)).FpScanNext
|
|
}
|
|
**(**uintptr)(__ccgo_up(ppOut)) = uintptr(0)
|
|
}
|
|
}
|
|
}
|
|
return **(**uintptr)(__ccgo_up(bp))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If this is not a contentless_delete=1 table, or if the 'deletemerge'
|
|
// ** configuration option is set to 0, then this function always returns -1.
|
|
// ** Otherwise, it searches the structure object passed as the second argument
|
|
// ** for a level suitable for merging due to having a large number of
|
|
// ** tombstones in the tombstone hash. If one is found, its index is returned.
|
|
// ** Otherwise, if there is no suitable level, -1.
|
|
// */
|
|
func _fts5IndexFindDeleteMerge(tls *libc.TLS, p uintptr, pStruct uintptr) (r int32) {
|
|
var iRet, iSeg, ii, nBest, nPercent int32
|
|
var nEntry, nTomb Ti64
|
|
var pConfig, pLvl uintptr
|
|
_, _, _, _, _, _, _, _, _ = iRet, iSeg, ii, nBest, nEntry, nPercent, nTomb, pConfig, pLvl
|
|
pConfig = (*TFts5Index)(unsafe.Pointer(p)).FpConfig
|
|
iRet = -int32(1)
|
|
if (*TFts5Config)(unsafe.Pointer(pConfig)).FbContentlessDelete != 0 && (*TFts5Config)(unsafe.Pointer(pConfig)).FnDeleteMerge > 0 {
|
|
nBest = 0
|
|
ii = 0
|
|
for {
|
|
if !(ii < (*TFts5Structure)(unsafe.Pointer(pStruct)).FnLevel) {
|
|
break
|
|
}
|
|
pLvl = pStruct + 32 + uintptr(ii)*16
|
|
nEntry = 0
|
|
nTomb = 0
|
|
iSeg = 0
|
|
for {
|
|
if !(iSeg < (*TFts5StructureLevel)(unsafe.Pointer(pLvl)).FnSeg) {
|
|
break
|
|
}
|
|
nEntry = libc.Int64FromUint64(uint64(nEntry) + (**(**TFts5StructureSegment)(__ccgo_up((*TFts5StructureLevel)(unsafe.Pointer(pLvl)).FaSeg + uintptr(iSeg)*56))).FnEntry)
|
|
nTomb = libc.Int64FromUint64(uint64(nTomb) + (**(**TFts5StructureSegment)(__ccgo_up((*TFts5StructureLevel)(unsafe.Pointer(pLvl)).FaSeg + uintptr(iSeg)*56))).FnEntryTombstone)
|
|
goto _2
|
|
_2:
|
|
;
|
|
iSeg = iSeg + 1
|
|
}
|
|
if nEntry > 0 {
|
|
nPercent = int32(nTomb * int64(100) / nEntry)
|
|
if nPercent >= (*TFts5Config)(unsafe.Pointer(pConfig)).FnDeleteMerge && nPercent > nBest {
|
|
iRet = ii
|
|
nBest = nPercent
|
|
}
|
|
}
|
|
/* If pLvl is already the input level to an ongoing merge, look no
|
|
** further for a merge candidate. The caller should be allowed to
|
|
** continue merging from pLvl first. */
|
|
if (*TFts5StructureLevel)(unsafe.Pointer(pLvl)).FnMerge != 0 {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
}
|
|
return iRet
|
|
}
|
|
|
|
func _fts5IndexOptimizeStruct(tls *libc.TLS, p uintptr, pStruct uintptr) (r uintptr) {
|
|
var i, iLvl, iSeg, iSegOut, nMerge, nSeg, nThis, v2 int32
|
|
var nByte Tsqlite3_int64
|
|
var pLvl, pNew uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _ = i, iLvl, iSeg, iSegOut, nByte, nMerge, nSeg, nThis, pLvl, pNew, v2
|
|
pNew = uintptr(0)
|
|
nByte = libc.Int64FromUint64(uint64(libc.UintptrFromInt32(0)+32) + libc.Uint64FromInt32(libc.Int32FromInt32(1))*libc.Uint64FromInt64(16))
|
|
nSeg = (*TFts5Structure)(unsafe.Pointer(pStruct)).FnSegment
|
|
/* Figure out if this structure requires optimization. A structure does
|
|
** not require optimization if either:
|
|
**
|
|
** 1. it consists of fewer than two segments, or
|
|
** 2. all segments are on the same level, or
|
|
** 3. all segments except one are currently inputs to a merge operation.
|
|
**
|
|
** In the first case, if there are no tombstone hash pages, return NULL. In
|
|
** the second, increment the ref-count on *pStruct and return a copy of the
|
|
** pointer to it.
|
|
*/
|
|
if nSeg == 0 {
|
|
return uintptr(0)
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < (*TFts5Structure)(unsafe.Pointer(pStruct)).FnLevel) {
|
|
break
|
|
}
|
|
nThis = (*(*TFts5StructureLevel)(unsafe.Pointer(pStruct + 32 + uintptr(i)*16))).FnSeg
|
|
nMerge = (*(*TFts5StructureLevel)(unsafe.Pointer(pStruct + 32 + uintptr(i)*16))).FnMerge
|
|
if nThis > 0 && (nThis == nSeg || nThis == nSeg-int32(1) && nMerge == nThis) {
|
|
if nSeg == int32(1) && nThis == int32(1) && (**(**TFts5StructureSegment)(__ccgo_up((*(*TFts5StructureLevel)(unsafe.Pointer(pStruct + 32 + uintptr(i)*16))).FaSeg))).FnPgTombstone == 0 {
|
|
return uintptr(0)
|
|
}
|
|
_fts5StructureRef(tls, pStruct)
|
|
return pStruct
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
nByte = libc.Int64FromUint64(uint64(nByte) + libc.Uint64FromInt64(int64((*TFts5Structure)(unsafe.Pointer(pStruct)).FnLevel)+libc.Int64FromInt32(1))*libc.Uint64FromInt64(16))
|
|
pNew = _sqlite3Fts5MallocZero(tls, p+60, nByte)
|
|
if pNew != 0 {
|
|
nByte = libc.Int64FromUint64(libc.Uint64FromInt32(nSeg) * uint64(56))
|
|
if (*TFts5Structure)(unsafe.Pointer(pStruct)).FnLevel+int32(1) < int32(FTS5_MAX_LEVEL) {
|
|
v2 = (*TFts5Structure)(unsafe.Pointer(pStruct)).FnLevel + int32(1)
|
|
} else {
|
|
v2 = int32(FTS5_MAX_LEVEL)
|
|
}
|
|
(*TFts5Structure)(unsafe.Pointer(pNew)).FnLevel = v2
|
|
(*TFts5Structure)(unsafe.Pointer(pNew)).FnRef = int32(1)
|
|
(*TFts5Structure)(unsafe.Pointer(pNew)).FnWriteCounter = (*TFts5Structure)(unsafe.Pointer(pStruct)).FnWriteCounter
|
|
(*TFts5Structure)(unsafe.Pointer(pNew)).FnOriginCntr = (*TFts5Structure)(unsafe.Pointer(pStruct)).FnOriginCntr
|
|
pLvl = pNew + 32 + uintptr((*TFts5Structure)(unsafe.Pointer(pNew)).FnLevel-int32(1))*16
|
|
(*TFts5StructureLevel)(unsafe.Pointer(pLvl)).FaSeg = _sqlite3Fts5MallocZero(tls, p+60, nByte)
|
|
if (*TFts5StructureLevel)(unsafe.Pointer(pLvl)).FaSeg != 0 {
|
|
iSegOut = 0
|
|
/* Iterate through all segments, from oldest to newest. Add them to
|
|
** the new Fts5Level object so that pLvl->aSeg[0] is the oldest
|
|
** segment in the data structure. */
|
|
iLvl = (*TFts5Structure)(unsafe.Pointer(pStruct)).FnLevel - int32(1)
|
|
for {
|
|
if !(iLvl >= 0) {
|
|
break
|
|
}
|
|
iSeg = 0
|
|
for {
|
|
if !(iSeg < (*(*TFts5StructureLevel)(unsafe.Pointer(pStruct + 32 + uintptr(iLvl)*16))).FnSeg) {
|
|
break
|
|
}
|
|
**(**TFts5StructureSegment)(__ccgo_up((*TFts5StructureLevel)(unsafe.Pointer(pLvl)).FaSeg + uintptr(iSegOut)*56)) = **(**TFts5StructureSegment)(__ccgo_up((*(*TFts5StructureLevel)(unsafe.Pointer(pStruct + 32 + uintptr(iLvl)*16))).FaSeg + uintptr(iSeg)*56))
|
|
iSegOut = iSegOut + 1
|
|
goto _4
|
|
_4:
|
|
;
|
|
iSeg = iSeg + 1
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
iLvl = iLvl - 1
|
|
}
|
|
v2 = nSeg
|
|
(*TFts5StructureLevel)(unsafe.Pointer(pLvl)).FnSeg = v2
|
|
(*TFts5Structure)(unsafe.Pointer(pNew)).FnSegment = v2
|
|
} else {
|
|
Xsqlite3_free(tls, pNew)
|
|
pNew = uintptr(0)
|
|
}
|
|
}
|
|
return pNew
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add a tombstone for rowid iRowid to segment pSeg.
|
|
// */
|
|
func _fts5IndexTombstoneAdd(tls *libc.TLS, p uintptr, pSeg uintptr, iRowid Tu64) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iPg, ii, szKey, v1, v2 int32
|
|
var iTombstoneRowid Ti64
|
|
var pPg uintptr
|
|
var _ /* apHash at bp+8 */ uintptr
|
|
var _ /* nHash at bp+0 */ int32
|
|
_, _, _, _, _, _, _ = iPg, iTombstoneRowid, ii, pPg, szKey, v1, v2
|
|
pPg = uintptr(0)
|
|
iPg = -int32(1)
|
|
szKey = 0
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = uintptr(0)
|
|
(*TFts5Index)(unsafe.Pointer(p)).FnContentlessDelete = (*TFts5Index)(unsafe.Pointer(p)).FnContentlessDelete + 1
|
|
if (*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FnPgTombstone > 0 {
|
|
iPg = libc.Int32FromUint64(iRowid % libc.Uint64FromInt32((*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FnPgTombstone))
|
|
pPg = _fts5DataRead(tls, p, int64((*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FiSegid+libc.Int32FromInt32(1)<<libc.Int32FromInt32(16))<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B)+libc.Int32FromInt32(FTS5_DATA_DLI_B))+int64(libc.Int32FromInt32(0))<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B))+int64(libc.Int32FromInt32(0))<<libc.Int32FromInt32(FTS5_DATA_PAGE_B)+int64(iPg))
|
|
if pPg == uintptr(0) {
|
|
return
|
|
}
|
|
if 0 == _fts5IndexTombstoneAddToPage(tls, pPg, 0, (*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FnPgTombstone, iRowid) {
|
|
_fts5DataWrite(tls, p, int64((*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FiSegid+libc.Int32FromInt32(1)<<libc.Int32FromInt32(16))<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B)+libc.Int32FromInt32(FTS5_DATA_DLI_B))+int64(libc.Int32FromInt32(0))<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B))+int64(libc.Int32FromInt32(0))<<libc.Int32FromInt32(FTS5_DATA_PAGE_B)+int64(iPg), (*TFts5Data)(unsafe.Pointer(pPg)).Fp, (*TFts5Data)(unsafe.Pointer(pPg)).Fnn)
|
|
_fts5DataRelease(tls, pPg)
|
|
return
|
|
}
|
|
}
|
|
/* Have to rebuild the hash table. First figure out the key-size (4 or 8). */
|
|
if pPg != 0 {
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Data)(unsafe.Pointer(pPg)).Fp))) == int32(4) {
|
|
v2 = int32(4)
|
|
} else {
|
|
v2 = int32(8)
|
|
}
|
|
v1 = v2
|
|
} else {
|
|
v1 = int32(4)
|
|
}
|
|
szKey = v1
|
|
if iRowid > uint64(0xFFFFFFFF) {
|
|
szKey = int32(8)
|
|
}
|
|
/* Rebuild the hash table */
|
|
_fts5IndexTombstoneRebuild(tls, p, pSeg, pPg, iPg, szKey, bp, bp+8)
|
|
/* If all has succeeded, write the new rowid into one of the new hash
|
|
** table pages, then write them all out to disk. */
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
ii = 0
|
|
_fts5IndexTombstoneAddToPage(tls, **(**uintptr)(__ccgo_up(**(**uintptr)(__ccgo_up(bp + 8)) + uintptr(iRowid%libc.Uint64FromInt32(**(**int32)(__ccgo_up(bp))))*8)), int32(1), **(**int32)(__ccgo_up(bp)), iRowid)
|
|
ii = 0
|
|
for {
|
|
if !(ii < **(**int32)(__ccgo_up(bp))) {
|
|
break
|
|
}
|
|
iTombstoneRowid = int64((*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FiSegid+libc.Int32FromInt32(1)<<libc.Int32FromInt32(16))<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B)+libc.Int32FromInt32(FTS5_DATA_DLI_B)) + int64(libc.Int32FromInt32(0))<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B)) + int64(libc.Int32FromInt32(0))<<libc.Int32FromInt32(FTS5_DATA_PAGE_B) + int64(ii)
|
|
_fts5DataWrite(tls, p, iTombstoneRowid, (*TFts5Data)(unsafe.Pointer(**(**uintptr)(__ccgo_up(**(**uintptr)(__ccgo_up(bp + 8)) + uintptr(ii)*8)))).Fp, (*TFts5Data)(unsafe.Pointer(**(**uintptr)(__ccgo_up(**(**uintptr)(__ccgo_up(bp + 8)) + uintptr(ii)*8)))).Fnn)
|
|
goto _3
|
|
_3:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
(*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FnPgTombstone = **(**int32)(__ccgo_up(bp))
|
|
_fts5StructureWrite(tls, p, (*TFts5Index)(unsafe.Pointer(p)).FpStruct)
|
|
}
|
|
_fts5DataRelease(tls, pPg)
|
|
_fts5IndexFreeArray(tls, **(**uintptr)(__ccgo_up(bp + 8)), **(**int32)(__ccgo_up(bp)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is called to rebuild the hash table belonging to segment pSeg.
|
|
// ** If parameter pData1 is not NULL, then one page of the existing hash table
|
|
// ** has already been loaded - pData1, which is page iPg1. The key-size for
|
|
// ** the new hash table is szKey (4 or 8).
|
|
// **
|
|
// ** If successful, the new hash table is not written to disk. Instead,
|
|
// ** output parameter (*pnOut) is set to the number of pages in the new
|
|
// ** hash table, and (*papOut) to point to an array of buffers containing
|
|
// ** the new page data.
|
|
// **
|
|
// ** If an error occurs, an error code is left in the Fts5Index object and
|
|
// ** both output parameters set to 0 before returning.
|
|
// */
|
|
func _fts5IndexTombstoneRebuild(tls *libc.TLS, p uintptr, pSeg uintptr, pData1 uintptr, iPg1 int32, szKey int32, pnOut uintptr, papOut uintptr) {
|
|
var MINSLOT, nSlotPerPage, res, v1 int32
|
|
var apOut, pNew uintptr
|
|
var ii, nOut, nSlot, szPage Ti64
|
|
var nElem Tu32
|
|
var v2 int64
|
|
_, _, _, _, _, _, _, _, _, _, _, _ = MINSLOT, apOut, ii, nElem, nOut, nSlot, nSlotPerPage, pNew, res, szPage, v1, v2
|
|
MINSLOT = int32(32)
|
|
if MINSLOT > ((*TFts5Config)(unsafe.Pointer((*TFts5Index)(unsafe.Pointer(p)).FpConfig)).Fpgsz-int32(8))/szKey {
|
|
v1 = MINSLOT
|
|
} else {
|
|
v1 = ((*TFts5Config)(unsafe.Pointer((*TFts5Index)(unsafe.Pointer(p)).FpConfig)).Fpgsz - int32(8)) / szKey
|
|
}
|
|
nSlotPerPage = v1
|
|
nSlot = 0 /* Number of slots in each output page */
|
|
nOut = 0
|
|
/* Figure out how many output pages (nOut) and how many slots per
|
|
** page (nSlot). There are three possibilities:
|
|
**
|
|
** 1. The hash table does not yet exist. In this case the new hash
|
|
** table will consist of a single page with MINSLOT slots.
|
|
**
|
|
** 2. The hash table exists but is currently a single page. In this
|
|
** case an attempt is made to grow the page to accommodate the new
|
|
** entry. The page is allowed to grow up to nSlotPerPage (see above)
|
|
** slots.
|
|
**
|
|
** 3. The hash table already consists of more than one page, or of
|
|
** a single page already so large that it cannot be grown. In this
|
|
** case the new hash consists of (nPg*2+1) pages of nSlotPerPage
|
|
** slots each, where nPg is the current number of pages in the
|
|
** hash table.
|
|
*/
|
|
if (*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FnPgTombstone == 0 {
|
|
/* Case 1. */
|
|
nOut = int64(1)
|
|
nSlot = int64(MINSLOT)
|
|
} else {
|
|
if (*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FnPgTombstone == int32(1) {
|
|
/* Case 2. */
|
|
nElem = _fts5GetU32(tls, (*TFts5Data)(unsafe.Pointer(pData1)).Fp+4)
|
|
if nElem > libc.Uint32FromInt32(nSlotPerPage)/uint32(4) {
|
|
nOut = 0
|
|
} else {
|
|
nOut = int64(1)
|
|
if libc.Int64FromUint32(nElem)*int64(4) > int64(MINSLOT) {
|
|
v2 = libc.Int64FromUint32(nElem) * int64(4)
|
|
} else {
|
|
v2 = int64(MINSLOT)
|
|
}
|
|
nSlot = v2
|
|
}
|
|
}
|
|
}
|
|
if nOut == 0 {
|
|
/* Case 3. */
|
|
nOut = int64((*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FnPgTombstone)*libc.Int64FromInt32(2) + libc.Int64FromInt32(1)
|
|
nSlot = int64(nSlotPerPage)
|
|
}
|
|
/* Allocate the required array and output pages */
|
|
for int32(1) != 0 {
|
|
res = 0
|
|
ii = 0
|
|
szPage = 0
|
|
apOut = uintptr(0)
|
|
/* Allocate space for the new hash table */
|
|
apOut = _sqlite3Fts5MallocZero(tls, p+60, libc.Int64FromUint64(uint64(8)*libc.Uint64FromInt64(nOut)))
|
|
szPage = int64(8) + nSlot*int64(szKey)
|
|
ii = 0
|
|
for {
|
|
if !(ii < nOut) {
|
|
break
|
|
}
|
|
pNew = _sqlite3Fts5MallocZero(tls, p+60, libc.Int64FromUint64(uint64(16)+libc.Uint64FromInt64(szPage)))
|
|
if pNew != 0 {
|
|
(*TFts5Data)(unsafe.Pointer(pNew)).Fnn = int32(szPage)
|
|
(*TFts5Data)(unsafe.Pointer(pNew)).Fp = pNew + 1*16
|
|
**(**uintptr)(__ccgo_up(apOut + uintptr(ii)*8)) = pNew
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
/* Rebuild the hash table. */
|
|
if (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
res = _fts5IndexTombstoneRehash(tls, p, pSeg, pData1, iPg1, szKey, int32(nOut), apOut)
|
|
}
|
|
if res == 0 {
|
|
if (*TFts5Index)(unsafe.Pointer(p)).Frc != 0 {
|
|
_fts5IndexFreeArray(tls, apOut, int32(nOut))
|
|
apOut = uintptr(0)
|
|
nOut = 0
|
|
}
|
|
**(**int32)(__ccgo_up(pnOut)) = int32(nOut)
|
|
**(**uintptr)(__ccgo_up(papOut)) = apOut
|
|
break
|
|
}
|
|
/* If control flows to here, it was not possible to rebuild the hash
|
|
** table. Free all buffers and then try again with more pages. */
|
|
_fts5IndexFreeArray(tls, apOut, int32(nOut))
|
|
nSlot = int64(nSlotPerPage)
|
|
nOut = nOut*int64(2) + int64(1)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function attempts to build a new hash containing all the keys
|
|
// ** currently in the tombstone hash table for segment pSeg. The new
|
|
// ** hash will be stored in the nOut buffers passed in array apOut[].
|
|
// ** All pages of the new hash use key-size szKey (4 or 8).
|
|
// **
|
|
// ** Return 0 if the hash is successfully rebuilt into the nOut pages.
|
|
// ** Or non-zero if it is not (because one page became overfull). In this
|
|
// ** case the caller should retry with a larger nOut parameter.
|
|
// **
|
|
// ** Parameter pData1 is page iPg1 of the hash table being rebuilt.
|
|
// */
|
|
func _fts5IndexTombstoneRehash(tls *libc.TLS, p uintptr, pSeg uintptr, pData1 uintptr, iPg1 int32, szKey int32, nOut int32, apOut uintptr) (r int32) {
|
|
var aSlot, aSlot1, pData, pFree, pPg, v3 uintptr
|
|
var iIn, ii, nSlotIn, res, szKeyIn, v4 int32
|
|
var iVal Tu64
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _ = aSlot, aSlot1, iIn, iVal, ii, nSlotIn, pData, pFree, pPg, res, szKeyIn, v3, v4
|
|
res = 0
|
|
/* Initialize the headers of all the output pages */
|
|
ii = 0
|
|
for {
|
|
if !(ii < nOut) {
|
|
break
|
|
}
|
|
**(**Tu8)(__ccgo_up((*TFts5Data)(unsafe.Pointer(**(**uintptr)(__ccgo_up(apOut + uintptr(ii)*8)))).Fp)) = libc.Uint8FromInt32(szKey)
|
|
_fts5PutU32(tls, (*TFts5Data)(unsafe.Pointer(**(**uintptr)(__ccgo_up(apOut + uintptr(ii)*8)))).Fp+4, uint32(0))
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
/* Loop through the current pages of the hash table. */
|
|
ii = 0
|
|
for {
|
|
if !(res == 0 && ii < (*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FnPgTombstone) {
|
|
break
|
|
}
|
|
pData = uintptr(0) /* Page ii of the current hash table */
|
|
pFree = uintptr(0) /* Free this at the end of the loop */
|
|
if iPg1 == ii {
|
|
pData = pData1
|
|
} else {
|
|
v3 = _fts5DataRead(tls, p, int64((*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FiSegid+libc.Int32FromInt32(1)<<libc.Int32FromInt32(16))<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B)+libc.Int32FromInt32(FTS5_DATA_DLI_B))+int64(libc.Int32FromInt32(0))<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B))+int64(libc.Int32FromInt32(0))<<libc.Int32FromInt32(FTS5_DATA_PAGE_B)+int64(ii))
|
|
pData = v3
|
|
pFree = v3
|
|
}
|
|
if pData != 0 {
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Data)(unsafe.Pointer(pData)).Fp))) == int32(4) {
|
|
v4 = int32(4)
|
|
} else {
|
|
v4 = int32(8)
|
|
}
|
|
szKeyIn = v4
|
|
nSlotIn = ((*TFts5Data)(unsafe.Pointer(pData)).Fnn - int32(8)) / szKeyIn
|
|
iIn = 0
|
|
for {
|
|
if !(iIn < nSlotIn) {
|
|
break
|
|
}
|
|
iVal = uint64(0)
|
|
/* Read the value from slot iIn of the input page into iVal. */
|
|
if szKeyIn == int32(4) {
|
|
aSlot = (*TFts5Data)(unsafe.Pointer(pData)).Fp + 8
|
|
if **(**Tu32)(__ccgo_up(aSlot + uintptr(iIn)*4)) != 0 {
|
|
iVal = uint64(_fts5GetU32(tls, aSlot+uintptr(iIn)*4))
|
|
}
|
|
} else {
|
|
aSlot1 = (*TFts5Data)(unsafe.Pointer(pData)).Fp + 8
|
|
if **(**Tu64)(__ccgo_up(aSlot1 + uintptr(iIn)*8)) != 0 {
|
|
iVal = _fts5GetU64(tls, aSlot1+uintptr(iIn)*8)
|
|
}
|
|
}
|
|
/* If iVal is not 0 at this point, insert it into the new hash table */
|
|
if iVal != 0 {
|
|
pPg = **(**uintptr)(__ccgo_up(apOut + uintptr(iVal%libc.Uint64FromInt32(nOut))*8))
|
|
res = _fts5IndexTombstoneAddToPage(tls, pPg, 0, nOut, iVal)
|
|
if res != 0 {
|
|
break
|
|
}
|
|
}
|
|
goto _5
|
|
_5:
|
|
;
|
|
iIn = iIn + 1
|
|
}
|
|
/* If this is page 0 of the old hash, copy the rowid-0-flag from the
|
|
** old hash to the new. */
|
|
if ii == 0 {
|
|
**(**Tu8)(__ccgo_up((*TFts5Data)(unsafe.Pointer(**(**uintptr)(__ccgo_up(apOut)))).Fp + 1)) = **(**Tu8)(__ccgo_up((*TFts5Data)(unsafe.Pointer(pData)).Fp + 1))
|
|
}
|
|
}
|
|
_fts5DataRelease(tls, pFree)
|
|
goto _2
|
|
_2:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
return res
|
|
}
|
|
|
|
func _fts5IntegrityCheckPgidx(tls *libc.TLS, p uintptr, iRowid Ti64, pLeaf uintptr) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var iOff, iTermOff Ti64
|
|
var ii, res int32
|
|
var _ /* buf1 at bp+0 */ TFts5Buffer
|
|
var _ /* buf2 at bp+16 */ TFts5Buffer
|
|
var _ /* nByte at bp+36 */ int32
|
|
var _ /* nByte at bp+44 */ int32
|
|
var _ /* nIncr at bp+32 */ int32
|
|
var _ /* nKeep at bp+40 */ int32
|
|
_, _, _, _ = iOff, iTermOff, ii, res
|
|
iTermOff = 0
|
|
**(**TFts5Buffer)(__ccgo_up(bp)) = TFts5Buffer{}
|
|
**(**TFts5Buffer)(__ccgo_up(bp + 16)) = TFts5Buffer{}
|
|
ii = (*TFts5Data)(unsafe.Pointer(pLeaf)).FszLeaf
|
|
for ii < (*TFts5Data)(unsafe.Pointer(pLeaf)).Fnn && (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
ii = ii + _sqlite3Fts5GetVarint32(tls, (*TFts5Data)(unsafe.Pointer(pLeaf)).Fp+uintptr(ii), bp+32)
|
|
iTermOff = iTermOff + int64(**(**int32)(__ccgo_up(bp + 32)))
|
|
iOff = iTermOff
|
|
if iOff >= int64((*TFts5Data)(unsafe.Pointer(pLeaf)).FszLeaf) {
|
|
_fts5IndexCorruptRowid(tls, p, iRowid)
|
|
} else {
|
|
if iTermOff == int64(**(**int32)(__ccgo_up(bp + 32))) {
|
|
iOff = iOff + int64(_sqlite3Fts5GetVarint32(tls, (*TFts5Data)(unsafe.Pointer(pLeaf)).Fp+uintptr(iOff), bp+36))
|
|
if iOff+int64(**(**int32)(__ccgo_up(bp + 36))) > int64((*TFts5Data)(unsafe.Pointer(pLeaf)).FszLeaf) {
|
|
_fts5IndexCorruptRowid(tls, p, iRowid)
|
|
} else {
|
|
_sqlite3Fts5BufferSet(tls, p+60, bp, **(**int32)(__ccgo_up(bp + 36)), (*TFts5Data)(unsafe.Pointer(pLeaf)).Fp+uintptr(iOff))
|
|
}
|
|
} else {
|
|
iOff = iOff + int64(_sqlite3Fts5GetVarint32(tls, (*TFts5Data)(unsafe.Pointer(pLeaf)).Fp+uintptr(iOff), bp+40))
|
|
iOff = iOff + int64(_sqlite3Fts5GetVarint32(tls, (*TFts5Data)(unsafe.Pointer(pLeaf)).Fp+uintptr(iOff), bp+44))
|
|
if **(**int32)(__ccgo_up(bp + 40)) > (**(**TFts5Buffer)(__ccgo_up(bp))).Fn || iOff+int64(**(**int32)(__ccgo_up(bp + 44))) > int64((*TFts5Data)(unsafe.Pointer(pLeaf)).FszLeaf) {
|
|
_fts5IndexCorruptRowid(tls, p, iRowid)
|
|
} else {
|
|
(**(**TFts5Buffer)(__ccgo_up(bp))).Fn = **(**int32)(__ccgo_up(bp + 40))
|
|
_sqlite3Fts5BufferAppendBlob(tls, p+60, bp, libc.Uint32FromInt32(**(**int32)(__ccgo_up(bp + 44))), (*TFts5Data)(unsafe.Pointer(pLeaf)).Fp+uintptr(iOff))
|
|
}
|
|
if (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
res = _fts5BufferCompare(tls, bp, bp+16)
|
|
if res <= 0 {
|
|
_fts5IndexCorruptRowid(tls, p, iRowid)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
_sqlite3Fts5BufferSet(tls, p+60, bp+16, (**(**TFts5Buffer)(__ccgo_up(bp))).Fn, (**(**TFts5Buffer)(__ccgo_up(bp))).Fp)
|
|
}
|
|
_sqlite3Fts5BufferFree(tls, bp)
|
|
_sqlite3Fts5BufferFree(tls, bp+16)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** pToken points to a buffer of size nToken bytes containing a search
|
|
// ** term, including the index number at the start, used on a tokendata=1
|
|
// ** table. This function returns true if the term in buffer pBuf matches
|
|
// ** token pToken/nToken.
|
|
// */
|
|
func _fts5IsTokendataPrefix(tls *libc.TLS, pBuf uintptr, pToken uintptr, nToken int32) (r int32) {
|
|
return libc.BoolInt32((*TFts5Buffer)(unsafe.Pointer(pBuf)).Fn >= nToken && 0 == libc.Xmemcmp(tls, (*TFts5Buffer)(unsafe.Pointer(pBuf)).Fp, pToken, libc.Uint64FromInt32(nToken)) && ((*TFts5Buffer)(unsafe.Pointer(pBuf)).Fn == nToken || libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Buffer)(unsafe.Pointer(pBuf)).Fp + uintptr(nToken)))) == 0x00))
|
|
}
|
|
|
|
func _fts5IterSetOutputCb(tls *libc.TLS, pRc uintptr, pIter uintptr) {
|
|
var pConfig uintptr
|
|
_ = pConfig
|
|
if **(**int32)(__ccgo_up(pRc)) == SQLITE_OK {
|
|
pConfig = (*TFts5Index)(unsafe.Pointer((*TFts5Iter)(unsafe.Pointer(pIter)).FpIndex)).FpConfig
|
|
if (*TFts5Config)(unsafe.Pointer(pConfig)).FeDetail == int32(FTS5_DETAIL_NONE) {
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).FxSetOutputs = __ccgo_fp(_fts5IterSetOutputs_None)
|
|
} else {
|
|
if (*TFts5Iter)(unsafe.Pointer(pIter)).FpColset == uintptr(0) {
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).FxSetOutputs = __ccgo_fp(_fts5IterSetOutputs_Nocolset)
|
|
} else {
|
|
if (*TFts5Colset)(unsafe.Pointer((*TFts5Iter)(unsafe.Pointer(pIter)).FpColset)).FnCol == 0 {
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).FxSetOutputs = __ccgo_fp(_fts5IterSetOutputs_ZeroColset)
|
|
} else {
|
|
if (*TFts5Config)(unsafe.Pointer(pConfig)).FeDetail == FTS5_DETAIL_FULL {
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).FxSetOutputs = __ccgo_fp(_fts5IterSetOutputs_Full)
|
|
} else {
|
|
if (*TFts5Config)(unsafe.Pointer(pConfig)).FnCol <= int32(100) {
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).FxSetOutputs = __ccgo_fp(_fts5IterSetOutputs_Col100)
|
|
_sqlite3Fts5BufferSize(tls, pRc, pIter+40, libc.Uint32FromInt32((*TFts5Config)(unsafe.Pointer(pConfig)).FnCol))
|
|
} else {
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).FxSetOutputs = __ccgo_fp(_fts5IterSetOutputs_Col)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The iterator passed as the only argument must be a tokendata=1 iterator
|
|
// ** (pIter->pTokenDataIter!=0). This function sets the iterator output
|
|
// ** variables (pIter->base.*) according to the contents of the current
|
|
// ** row.
|
|
// */
|
|
func _fts5IterSetOutputsTokendata(tls *libc.TLS, pIter uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var aNew, p, p1, pReader, pT uintptr
|
|
var eDetail, iMin, ii, nByte, nHit, nReader, v3 int32
|
|
var iMinPos, iRowid, nNew Ti64
|
|
var _ /* iPrev at bp+0 */ Ti64
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = aNew, eDetail, iMin, iMinPos, iRowid, ii, nByte, nHit, nNew, nReader, p, p1, pReader, pT, v3
|
|
nHit = 0
|
|
iRowid = int64(-libc.Int32FromInt32(1)) - (libc.Int64FromUint32(0xffffffff) | libc.Int64FromInt32(0x7fffffff)<<libc.Int32FromInt32(32))
|
|
iMin = 0
|
|
pT = (*TFts5Iter)(unsafe.Pointer(pIter)).FpTokenDataIter
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).Fbase.FnData = 0
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).Fbase.FpData = uintptr(0)
|
|
ii = 0
|
|
for {
|
|
if !(int64(ii) < (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnIter) {
|
|
break
|
|
}
|
|
p = *(*uintptr)(unsafe.Pointer(pT + 72 + uintptr(ii)*8))
|
|
if libc.Int32FromUint8((*TFts5Iter)(unsafe.Pointer(p)).Fbase.FbEof) == 0 {
|
|
if nHit == 0 || (*TFts5Iter)(unsafe.Pointer(p)).Fbase.FiRowid < iRowid {
|
|
iRowid = (*TFts5Iter)(unsafe.Pointer(p)).Fbase.FiRowid
|
|
nHit = int32(1)
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).Fbase.FpData = (*TFts5Iter)(unsafe.Pointer(p)).Fbase.FpData
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).Fbase.FnData = (*TFts5Iter)(unsafe.Pointer(p)).Fbase.FnData
|
|
iMin = ii
|
|
} else {
|
|
if (*TFts5Iter)(unsafe.Pointer(p)).Fbase.FiRowid == iRowid {
|
|
nHit = nHit + 1
|
|
}
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
if nHit == 0 {
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).Fbase.FbEof = uint8(1)
|
|
} else {
|
|
eDetail = (*TFts5Config)(unsafe.Pointer((*TFts5Index)(unsafe.Pointer((*TFts5Iter)(unsafe.Pointer(pIter)).FpIndex)).FpConfig)).FeDetail
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).Fbase.FbEof = uint8(0)
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).Fbase.FiRowid = iRowid
|
|
if nHit == int32(1) && eDetail == FTS5_DETAIL_FULL {
|
|
_fts5TokendataIterAppendMap(tls, (*TFts5Iter)(unsafe.Pointer(pIter)).FpIndex, pT, iMin, 0, iRowid, int64(-int32(1)))
|
|
} else {
|
|
if nHit > int32(1) && eDetail != int32(FTS5_DETAIL_NONE) {
|
|
nReader = 0
|
|
nByte = 0
|
|
**(**Ti64)(__ccgo_up(bp)) = 0
|
|
/* Allocate array of iterators if they are not already allocated. */
|
|
if (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaPoslistReader == uintptr(0) {
|
|
(*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaPoslistReader = _sqlite3Fts5MallocZero(tls, (*TFts5Iter)(unsafe.Pointer(pIter)).FpIndex+60, libc.Int64FromUint64(libc.Uint64FromInt64((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnIter)*uint64(libc.Uint64FromInt64(32)+libc.Uint64FromInt64(4))))
|
|
if (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaPoslistReader == uintptr(0) {
|
|
return
|
|
}
|
|
(*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaPoslistToIter = (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaPoslistReader + uintptr((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnIter)*32
|
|
}
|
|
/* Populate an iterator for each poslist that will be merged */
|
|
ii = 0
|
|
for {
|
|
if !(int64(ii) < (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnIter) {
|
|
break
|
|
}
|
|
p1 = *(*uintptr)(unsafe.Pointer(pT + 72 + uintptr(ii)*8))
|
|
if iRowid == (*TFts5Iter)(unsafe.Pointer(p1)).Fbase.FiRowid {
|
|
**(**int32)(__ccgo_up((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaPoslistToIter + uintptr(nReader)*4)) = ii
|
|
v3 = nReader
|
|
nReader = nReader + 1
|
|
_sqlite3Fts5PoslistReaderInit(tls, (*TFts5Iter)(unsafe.Pointer(p1)).Fbase.FpData, (*TFts5Iter)(unsafe.Pointer(p1)).Fbase.FnData, (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaPoslistReader+uintptr(v3)*32)
|
|
nByte = nByte + (*TFts5Iter)(unsafe.Pointer(p1)).Fbase.FnData
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
/* Ensure the output buffer is large enough */
|
|
if libc.Uint32FromInt32((*TFts5Buffer)(unsafe.Pointer(pIter+40)).Fn)+libc.Uint32FromInt32(nByte+nHit*libc.Int32FromInt32(10)) <= libc.Uint32FromInt32((*TFts5Buffer)(unsafe.Pointer(pIter+40)).FnSpace) {
|
|
v3 = 0
|
|
} else {
|
|
v3 = _sqlite3Fts5BufferSize(tls, (*TFts5Iter)(unsafe.Pointer(pIter)).FpIndex+60, pIter+40, libc.Uint32FromInt32(nByte+nHit*int32(10)+(*TFts5Buffer)(unsafe.Pointer(pIter+40)).Fn))
|
|
}
|
|
if v3 != 0 {
|
|
return
|
|
}
|
|
/* Ensure the token-mapping is large enough */
|
|
if eDetail == FTS5_DETAIL_FULL && (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMapAlloc < (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMap+int64(nByte) {
|
|
nNew = ((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMapAlloc + int64(nByte)) * int64(2)
|
|
aNew = Xsqlite3_realloc64(tls, (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaMap, libc.Uint64FromInt64(nNew)*uint64(24))
|
|
if aNew == uintptr(0) {
|
|
(*TFts5Index)(unsafe.Pointer((*TFts5Iter)(unsafe.Pointer(pIter)).FpIndex)).Frc = int32(SQLITE_NOMEM)
|
|
return
|
|
}
|
|
(*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaMap = aNew
|
|
(*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMapAlloc = nNew
|
|
}
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).Fposlist.Fn = 0
|
|
for int32(1) != 0 {
|
|
iMinPos = libc.Int64FromUint32(0xffffffff) | libc.Int64FromInt32(0x7fffffff)<<libc.Int32FromInt32(32)
|
|
/* Find smallest position */
|
|
iMin = 0
|
|
ii = 0
|
|
for {
|
|
if !(ii < nReader) {
|
|
break
|
|
}
|
|
pReader = (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaPoslistReader + uintptr(ii)*32
|
|
if libc.Int32FromUint8((*TFts5PoslistReader)(unsafe.Pointer(pReader)).FbEof) == 0 {
|
|
if (*TFts5PoslistReader)(unsafe.Pointer(pReader)).FiPos < iMinPos {
|
|
iMinPos = (*TFts5PoslistReader)(unsafe.Pointer(pReader)).FiPos
|
|
iMin = ii
|
|
}
|
|
}
|
|
goto _5
|
|
_5:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
/* If all readers were at EOF, break out of the loop. */
|
|
if iMinPos == libc.Int64FromUint32(0xffffffff)|libc.Int64FromInt32(0x7fffffff)<<libc.Int32FromInt32(32) {
|
|
break
|
|
}
|
|
_sqlite3Fts5PoslistSafeAppend(tls, pIter+40, bp, iMinPos)
|
|
_sqlite3Fts5PoslistReaderNext(tls, (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaPoslistReader+uintptr(iMin)*32)
|
|
if eDetail == FTS5_DETAIL_FULL {
|
|
(**(**TFts5TokenDataMap)(__ccgo_up((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaMap + uintptr((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMap)*24))).FiPos = iMinPos
|
|
(**(**TFts5TokenDataMap)(__ccgo_up((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaMap + uintptr((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMap)*24))).FiIter = **(**int32)(__ccgo_up((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaPoslistToIter + uintptr(iMin)*4))
|
|
(**(**TFts5TokenDataMap)(__ccgo_up((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaMap + uintptr((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMap)*24))).FiRowid = iRowid
|
|
(*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMap = (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMap + 1
|
|
}
|
|
}
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).Fbase.FpData = (*TFts5Iter)(unsafe.Pointer(pIter)).Fposlist.Fp
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).Fbase.FnData = (*TFts5Iter)(unsafe.Pointer(pIter)).Fposlist.Fn
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** xSetOutputs callback used when:
|
|
// **
|
|
// ** * detail=col,
|
|
// ** * there is a column filter, and
|
|
// ** * the table contains 100 or fewer columns.
|
|
// **
|
|
// ** The last point is to ensure all column numbers are stored as
|
|
// ** single-byte varints.
|
|
// */
|
|
func _fts5IterSetOutputs_Col100(tls *libc.TLS, pIter uintptr, pSeg uintptr) {
|
|
var a, aOut, aiCol, aiColEnd, pEnd, v1 uintptr
|
|
var iPrev, iPrevOut int32
|
|
_, _, _, _, _, _, _, _ = a, aOut, aiCol, aiColEnd, iPrev, iPrevOut, pEnd, v1
|
|
if (*TFts5SegIter)(unsafe.Pointer(pSeg)).FiLeafOffset+int64((*TFts5SegIter)(unsafe.Pointer(pSeg)).FnPos) > int64((*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pSeg)).FpLeaf)).FszLeaf) || (*TFts5SegIter)(unsafe.Pointer(pSeg)).FnPos > (*TFts5Config)(unsafe.Pointer((*TFts5Index)(unsafe.Pointer((*TFts5Iter)(unsafe.Pointer(pIter)).FpIndex)).FpConfig)).FnCol {
|
|
_fts5IterSetOutputs_Col(tls, pIter, pSeg)
|
|
} else {
|
|
a = (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pSeg)).FpLeaf)).Fp + uintptr((*TFts5SegIter)(unsafe.Pointer(pSeg)).FiLeafOffset)
|
|
pEnd = a + uintptr((*TFts5SegIter)(unsafe.Pointer(pSeg)).FnPos)
|
|
iPrev = 0
|
|
aiCol = (*TFts5Iter)(unsafe.Pointer(pIter)).FpColset + 4
|
|
aiColEnd = aiCol + uintptr((*TFts5Colset)(unsafe.Pointer((*TFts5Iter)(unsafe.Pointer(pIter)).FpColset)).FnCol)*4
|
|
aOut = (*TFts5Iter)(unsafe.Pointer(pIter)).Fposlist.Fp
|
|
iPrevOut = 0
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).Fbase.FiRowid = (*TFts5SegIter)(unsafe.Pointer(pSeg)).FiRowid
|
|
for a < pEnd {
|
|
v1 = a
|
|
a = a + 1
|
|
iPrev = iPrev + (libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v1))) - int32(2))
|
|
for **(**int32)(__ccgo_up(aiCol)) < iPrev {
|
|
aiCol += 4
|
|
if aiCol == aiColEnd {
|
|
goto setoutputs_col_out
|
|
}
|
|
}
|
|
if **(**int32)(__ccgo_up(aiCol)) == iPrev {
|
|
v1 = aOut
|
|
aOut = aOut + 1
|
|
**(**Tu8)(__ccgo_up(v1)) = libc.Uint8FromInt32(iPrev - iPrevOut + libc.Int32FromInt32(2))
|
|
iPrevOut = iPrev
|
|
}
|
|
}
|
|
goto setoutputs_col_out
|
|
setoutputs_col_out:
|
|
;
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).Fbase.FpData = (*TFts5Iter)(unsafe.Pointer(pIter)).Fposlist.Fp
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).Fbase.FnData = int32(int64(aOut) - int64((*TFts5Iter)(unsafe.Pointer(pIter)).Fposlist.Fp))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The iterator object passed as the second argument currently contains
|
|
// ** no valid values except for the Fts5SegIter.pLeaf member variable. This
|
|
// ** function searches the leaf page for a term matching (pTerm/nTerm).
|
|
// **
|
|
// ** If the specified term is found on the page, then the iterator is left
|
|
// ** pointing to it. If argument bGe is zero and the term is not found,
|
|
// ** the iterator is left pointing at EOF.
|
|
// **
|
|
// ** If bGe is non-zero and the specified term is not found, then the
|
|
// ** iterator is left pointing to the smallest term in the segment that
|
|
// ** is larger than the specified term, even if this term is not on the
|
|
// ** current page.
|
|
// */
|
|
func _fts5LeafSeek(tls *libc.TLS, p uintptr, bGe int32, pIter uintptr, pTerm uintptr, nTerm int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var a uintptr
|
|
var bEndOfPage int32
|
|
var i, iPgidx, n, nCmp, nMatch, v1 Tu32
|
|
var v2 uint32
|
|
var _ /* iOff at bp+0 */ Tu32
|
|
var _ /* iTermOff at bp+12 */ Tu32
|
|
var _ /* nExtra at bp+16 */ int32
|
|
var _ /* nKeep at bp+4 */ Tu32
|
|
var _ /* nNew at bp+8 */ Tu32
|
|
_, _, _, _, _, _, _, _, _ = a, bEndOfPage, i, iPgidx, n, nCmp, nMatch, v1, v2
|
|
a = (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp
|
|
n = libc.Uint32FromInt32((*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fnn)
|
|
nMatch = uint32(0)
|
|
**(**Tu32)(__ccgo_up(bp + 4)) = uint32(0)
|
|
**(**Tu32)(__ccgo_up(bp + 8)) = uint32(0) /* Current offset in pgidx */
|
|
bEndOfPage = 0
|
|
iPgidx = libc.Uint32FromInt32((*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).FszLeaf)
|
|
iPgidx = iPgidx + libc.Uint32FromInt32(_sqlite3Fts5GetVarint32(tls, a+uintptr(iPgidx), bp+12))
|
|
**(**Tu32)(__ccgo_up(bp)) = **(**Tu32)(__ccgo_up(bp + 12))
|
|
if **(**Tu32)(__ccgo_up(bp)) > n {
|
|
_fts5IndexCorruptIter(tls, p, pIter)
|
|
return
|
|
}
|
|
for int32(1) != 0 {
|
|
/* Figure out how many new bytes are in this term */
|
|
v1 = **(**Tu32)(__ccgo_up(bp))
|
|
**(**Tu32)(__ccgo_up(bp)) = **(**Tu32)(__ccgo_up(bp)) + 1
|
|
**(**Tu32)(__ccgo_up(bp + 8)) = uint32(**(**Tu8)(__ccgo_up(a + uintptr(v1))))
|
|
if **(**Tu32)(__ccgo_up(bp + 8))&uint32(0x80) != 0 {
|
|
**(**Tu32)(__ccgo_up(bp)) = **(**Tu32)(__ccgo_up(bp)) - 1
|
|
**(**Tu32)(__ccgo_up(bp)) = **(**Tu32)(__ccgo_up(bp)) + libc.Uint32FromInt32(_sqlite3Fts5GetVarint32(tls, a+uintptr(**(**Tu32)(__ccgo_up(bp))), bp+8))
|
|
}
|
|
if **(**Tu32)(__ccgo_up(bp + 4)) < nMatch {
|
|
goto search_failed
|
|
}
|
|
if **(**Tu32)(__ccgo_up(bp))+**(**Tu32)(__ccgo_up(bp + 8)) > n {
|
|
_fts5IndexCorruptIter(tls, p, pIter)
|
|
return
|
|
}
|
|
if **(**Tu32)(__ccgo_up(bp + 4)) == nMatch {
|
|
if **(**Tu32)(__ccgo_up(bp + 8)) < libc.Uint32FromInt32(nTerm)-nMatch {
|
|
v2 = **(**Tu32)(__ccgo_up(bp + 8))
|
|
} else {
|
|
v2 = libc.Uint32FromInt32(nTerm) - nMatch
|
|
}
|
|
nCmp = v2
|
|
i = uint32(0)
|
|
for {
|
|
if !(i < nCmp) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(a + uintptr(**(**Tu32)(__ccgo_up(bp))+i)))) != libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pTerm + uintptr(nMatch+i)))) {
|
|
break
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = i + 1
|
|
}
|
|
nMatch = nMatch + i
|
|
if libc.Uint32FromInt32(nTerm) == nMatch {
|
|
if i == **(**Tu32)(__ccgo_up(bp + 8)) {
|
|
goto search_success
|
|
} else {
|
|
goto search_failed
|
|
}
|
|
} else {
|
|
if i < **(**Tu32)(__ccgo_up(bp + 8)) && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(a + uintptr(**(**Tu32)(__ccgo_up(bp))+i)))) > libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pTerm + uintptr(nMatch)))) {
|
|
goto search_failed
|
|
}
|
|
}
|
|
}
|
|
if iPgidx >= n {
|
|
bEndOfPage = int32(1)
|
|
break
|
|
}
|
|
iPgidx = iPgidx + libc.Uint32FromInt32(_sqlite3Fts5GetVarint32(tls, a+uintptr(iPgidx), bp+4))
|
|
**(**Tu32)(__ccgo_up(bp + 12)) = **(**Tu32)(__ccgo_up(bp + 12)) + **(**Tu32)(__ccgo_up(bp + 4))
|
|
**(**Tu32)(__ccgo_up(bp)) = **(**Tu32)(__ccgo_up(bp + 12))
|
|
if **(**Tu32)(__ccgo_up(bp)) >= n {
|
|
_fts5IndexCorruptIter(tls, p, pIter)
|
|
return
|
|
}
|
|
/* Read the nKeep field of the next term. */
|
|
v1 = **(**Tu32)(__ccgo_up(bp))
|
|
**(**Tu32)(__ccgo_up(bp)) = **(**Tu32)(__ccgo_up(bp)) + 1
|
|
**(**Tu32)(__ccgo_up(bp + 4)) = uint32(**(**Tu8)(__ccgo_up(a + uintptr(v1))))
|
|
if **(**Tu32)(__ccgo_up(bp + 4))&uint32(0x80) != 0 {
|
|
**(**Tu32)(__ccgo_up(bp)) = **(**Tu32)(__ccgo_up(bp)) - 1
|
|
**(**Tu32)(__ccgo_up(bp)) = **(**Tu32)(__ccgo_up(bp)) + libc.Uint32FromInt32(_sqlite3Fts5GetVarint32(tls, a+uintptr(**(**Tu32)(__ccgo_up(bp))), bp+4))
|
|
}
|
|
}
|
|
goto search_failed
|
|
search_failed:
|
|
;
|
|
if bGe == 0 {
|
|
_fts5DataRelease(tls, (*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf = uintptr(0)
|
|
return
|
|
} else {
|
|
if bEndOfPage != 0 {
|
|
for cond := true; cond; cond = int32(1) != 0 {
|
|
_fts5SegIterNextPage(tls, p, pIter)
|
|
if (*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf == uintptr(0) {
|
|
return
|
|
}
|
|
a = (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp
|
|
if libc.BoolInt32((*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).FszLeaf >= (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fnn) == 0 {
|
|
iPgidx = libc.Uint32FromInt32((*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).FszLeaf)
|
|
iPgidx = iPgidx + libc.Uint32FromInt32(_sqlite3Fts5GetVarint32(tls, (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp+uintptr(iPgidx), bp))
|
|
if **(**Tu32)(__ccgo_up(bp)) < uint32(4) || libc.Int64FromUint32(**(**Tu32)(__ccgo_up(bp))) >= int64((*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).FszLeaf) {
|
|
_fts5IndexCorruptIter(tls, p, pIter)
|
|
return
|
|
} else {
|
|
**(**Tu32)(__ccgo_up(bp + 4)) = uint32(0)
|
|
**(**Tu32)(__ccgo_up(bp + 12)) = **(**Tu32)(__ccgo_up(bp))
|
|
n = libc.Uint32FromInt32((*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fnn)
|
|
**(**Tu32)(__ccgo_up(bp)) = **(**Tu32)(__ccgo_up(bp)) + libc.Uint32FromInt32(_sqlite3Fts5GetVarint32(tls, a+uintptr(**(**Tu32)(__ccgo_up(bp))), bp+8))
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
goto search_success
|
|
search_success:
|
|
;
|
|
if libc.Int64FromUint32(**(**Tu32)(__ccgo_up(bp)))+libc.Int64FromUint32(**(**Tu32)(__ccgo_up(bp + 8))) > libc.Int64FromUint32(n) || **(**Tu32)(__ccgo_up(bp + 8)) < uint32(1) {
|
|
_fts5IndexCorruptIter(tls, p, pIter)
|
|
return
|
|
}
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = libc.Int64FromUint32(**(**Tu32)(__ccgo_up(bp)) + **(**Tu32)(__ccgo_up(bp + 8)))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiTermLeafOffset = int32((*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset)
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiTermLeafPgno = (*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafPgno
|
|
_sqlite3Fts5BufferSet(tls, p+60, pIter+96, libc.Int32FromUint32(**(**Tu32)(__ccgo_up(bp + 4))), pTerm)
|
|
_sqlite3Fts5BufferAppendBlob(tls, p+60, pIter+96, **(**Tu32)(__ccgo_up(bp + 8)), a+uintptr(**(**Tu32)(__ccgo_up(bp))))
|
|
if iPgidx >= n {
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist = (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fnn + int32(1)
|
|
} else {
|
|
iPgidx = iPgidx + libc.Uint32FromInt32(_sqlite3Fts5GetVarint32(tls, a+uintptr(iPgidx), bp+16))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist = libc.Int32FromUint32(**(**Tu32)(__ccgo_up(bp + 12)) + libc.Uint32FromInt32(**(**int32)(__ccgo_up(bp + 16))))
|
|
}
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiPgidxOff = libc.Int32FromUint32(iPgidx)
|
|
_fts5SegIterLoadRowid(tls, p, pIter)
|
|
_fts5SegIterLoadNPos(tls, p, pIter)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Sub-iterator iChanged of iterator pIter has just been advanced. It still
|
|
// ** points to the same term though - just a different rowid. This function
|
|
// ** attempts to update the contents of the pIter->aFirst[] accordingly.
|
|
// ** If it does so successfully, 0 is returned. Otherwise 1.
|
|
// **
|
|
// ** If non-zero is returned, the caller should call fts5MultiIterAdvanced()
|
|
// ** on the iterator instead. That function does the same as this one, except
|
|
// ** that it deals with more complicated cases as well.
|
|
// */
|
|
func _fts5MultiIterAdvanceRowid(tls *libc.TLS, pIter uintptr, iChanged int32, ppFirst uintptr) (r int32) {
|
|
var i int32
|
|
var pNew, pOther, pRes uintptr
|
|
var v1 int64
|
|
_, _, _, _, _ = i, pNew, pOther, pRes, v1
|
|
pNew = pIter + 104 + uintptr(iChanged)*128
|
|
if (*TFts5SegIter)(unsafe.Pointer(pNew)).FiRowid == (*TFts5Iter)(unsafe.Pointer(pIter)).FiSwitchRowid || libc.BoolInt32((*TFts5SegIter)(unsafe.Pointer(pNew)).FiRowid < (*TFts5Iter)(unsafe.Pointer(pIter)).FiSwitchRowid) == (*TFts5Iter)(unsafe.Pointer(pIter)).FbRev {
|
|
pOther = pIter + 104 + uintptr(iChanged^int32(0x0001))*128
|
|
if (*TFts5Iter)(unsafe.Pointer(pIter)).FbRev != 0 {
|
|
v1 = int64(-libc.Int32FromInt32(1)) - (libc.Int64FromUint32(0xffffffff) | libc.Int64FromInt32(0x7fffffff)<<libc.Int32FromInt32(32))
|
|
} else {
|
|
v1 = libc.Int64FromUint32(0xffffffff) | libc.Int64FromInt32(0x7fffffff)<<libc.Int32FromInt32(32)
|
|
}
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).FiSwitchRowid = v1
|
|
i = ((*TFts5Iter)(unsafe.Pointer(pIter)).FnSeg + iChanged) / int32(2)
|
|
for {
|
|
if !(int32(1) != 0) {
|
|
break
|
|
}
|
|
pRes = (*TFts5Iter)(unsafe.Pointer(pIter)).FaFirst + uintptr(i)*4
|
|
if (*TFts5CResult)(unsafe.Pointer(pRes)).FbTermEq != 0 {
|
|
if (*TFts5SegIter)(unsafe.Pointer(pNew)).FiRowid == (*TFts5SegIter)(unsafe.Pointer(pOther)).FiRowid {
|
|
return int32(1)
|
|
} else {
|
|
if libc.BoolInt32((*TFts5SegIter)(unsafe.Pointer(pOther)).FiRowid > (*TFts5SegIter)(unsafe.Pointer(pNew)).FiRowid) == (*TFts5Iter)(unsafe.Pointer(pIter)).FbRev {
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).FiSwitchRowid = (*TFts5SegIter)(unsafe.Pointer(pOther)).FiRowid
|
|
pNew = pOther
|
|
} else {
|
|
if libc.BoolInt32((*TFts5SegIter)(unsafe.Pointer(pOther)).FiRowid > (*TFts5Iter)(unsafe.Pointer(pIter)).FiSwitchRowid) == (*TFts5Iter)(unsafe.Pointer(pIter)).FbRev {
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).FiSwitchRowid = (*TFts5SegIter)(unsafe.Pointer(pOther)).FiRowid
|
|
}
|
|
}
|
|
}
|
|
}
|
|
(*TFts5CResult)(unsafe.Pointer(pRes)).FiFirst = libc.Uint16FromInt64((int64(pNew) - t__predefined_ptrdiff_t(pIter+104)) / 128)
|
|
if i == int32(1) {
|
|
break
|
|
}
|
|
pOther = pIter + 104 + uintptr((**(**TFts5CResult)(__ccgo_up((*TFts5Iter)(unsafe.Pointer(pIter)).FaFirst + uintptr(i^int32(0x0001))*4))).FiFirst)*128
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i / int32(2)
|
|
}
|
|
}
|
|
**(**uintptr)(__ccgo_up(ppFirst)) = pNew
|
|
return 0
|
|
}
|
|
|
|
func _fts5MultiIterAlloc(tls *libc.TLS, p uintptr, nSeg int32) (r uintptr) {
|
|
var nSlot Ti64
|
|
var pNew uintptr
|
|
_, _ = nSlot, pNew /* Power of two >= nSeg */
|
|
nSlot = int64(2)
|
|
for {
|
|
if !(nSlot < int64(nSeg)) {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
nSlot = nSlot * int64(2)
|
|
}
|
|
pNew = _fts5IdxMalloc(tls, p, libc.Int64FromUint64(uint64(libc.UintptrFromInt32(0)+104)+libc.Uint64FromInt64(nSlot)*uint64(128)+uint64(4)*libc.Uint64FromInt64(nSlot)))
|
|
if pNew != 0 {
|
|
(*TFts5Iter)(unsafe.Pointer(pNew)).FnSeg = int32(nSlot)
|
|
(*TFts5Iter)(unsafe.Pointer(pNew)).FaFirst = pNew + 104 + uintptr(nSlot)*128
|
|
(*TFts5Iter)(unsafe.Pointer(pNew)).FpIndex = p
|
|
(*TFts5Iter)(unsafe.Pointer(pNew)).FxSetOutputs = __ccgo_fp(_fts5IterSetOutputs_Noop)
|
|
}
|
|
return pNew
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Do the comparison necessary to populate pIter->aFirst[iOut].
|
|
// **
|
|
// ** If the returned value is non-zero, then it is the index of an entry
|
|
// ** in the pIter->aSeg[] array that is (a) not at EOF, and (b) pointing
|
|
// ** to a key that is a duplicate of another, higher priority,
|
|
// ** segment-iterator in the pSeg->aSeg[] array.
|
|
// */
|
|
func _fts5MultiIterDoCompare(tls *libc.TLS, pIter uintptr, iOut int32) (r int32) {
|
|
var i1, i2, iRes, res, v1 int32
|
|
var p1, p2, pRes uintptr
|
|
_, _, _, _, _, _, _, _ = i1, i2, iRes, p1, p2, pRes, res, v1 /* Right-hand Fts5SegIter */
|
|
pRes = (*TFts5Iter)(unsafe.Pointer(pIter)).FaFirst + uintptr(iOut)*4
|
|
if iOut >= (*TFts5Iter)(unsafe.Pointer(pIter)).FnSeg/int32(2) {
|
|
i1 = (iOut - (*TFts5Iter)(unsafe.Pointer(pIter)).FnSeg/int32(2)) * int32(2)
|
|
i2 = i1 + int32(1)
|
|
} else {
|
|
i1 = libc.Int32FromUint16((**(**TFts5CResult)(__ccgo_up((*TFts5Iter)(unsafe.Pointer(pIter)).FaFirst + uintptr(iOut*int32(2))*4))).FiFirst)
|
|
i2 = libc.Int32FromUint16((**(**TFts5CResult)(__ccgo_up((*TFts5Iter)(unsafe.Pointer(pIter)).FaFirst + uintptr(iOut*int32(2)+int32(1))*4))).FiFirst)
|
|
}
|
|
p1 = pIter + 104 + uintptr(i1)*128
|
|
p2 = pIter + 104 + uintptr(i2)*128
|
|
(*TFts5CResult)(unsafe.Pointer(pRes)).FbTermEq = uint8(0)
|
|
if (*TFts5SegIter)(unsafe.Pointer(p1)).FpLeaf == uintptr(0) { /* If p1 is at EOF */
|
|
iRes = i2
|
|
} else {
|
|
if (*TFts5SegIter)(unsafe.Pointer(p2)).FpLeaf == uintptr(0) { /* If p2 is at EOF */
|
|
iRes = i1
|
|
} else {
|
|
res = _fts5BufferCompare(tls, p1+96, p2+96)
|
|
if res == 0 {
|
|
(*TFts5CResult)(unsafe.Pointer(pRes)).FbTermEq = uint8(1)
|
|
if (*TFts5SegIter)(unsafe.Pointer(p1)).FiRowid == (*TFts5SegIter)(unsafe.Pointer(p2)).FiRowid {
|
|
return i2
|
|
}
|
|
if libc.BoolInt32((*TFts5SegIter)(unsafe.Pointer(p1)).FiRowid > (*TFts5SegIter)(unsafe.Pointer(p2)).FiRowid) == (*TFts5Iter)(unsafe.Pointer(pIter)).FbRev {
|
|
v1 = -int32(1)
|
|
} else {
|
|
v1 = +libc.Int32FromInt32(1)
|
|
}
|
|
res = v1
|
|
}
|
|
if res < 0 {
|
|
iRes = i1
|
|
} else {
|
|
iRes = i2
|
|
}
|
|
}
|
|
}
|
|
(*TFts5CResult)(unsafe.Pointer(pRes)).FiFirst = libc.Uint16FromInt32(iRes)
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** All the component segment-iterators of pIter have been set up. This
|
|
// ** functions finishes setup for iterator pIter itself.
|
|
// */
|
|
func _fts5MultiIterFinishSetup(tls *libc.TLS, p uintptr, pIter uintptr) {
|
|
var iEq, iIter, v2 int32
|
|
var pSeg, pSeg1 uintptr
|
|
_, _, _, _, _ = iEq, iIter, pSeg, pSeg1, v2
|
|
iIter = (*TFts5Iter)(unsafe.Pointer(pIter)).FnSeg - int32(1)
|
|
for {
|
|
if !(iIter > 0) {
|
|
break
|
|
}
|
|
v2 = _fts5MultiIterDoCompare(tls, pIter, iIter)
|
|
iEq = v2
|
|
if v2 != 0 {
|
|
pSeg = pIter + 104 + uintptr(iEq)*128
|
|
if (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
(*(*func(*libc.TLS, uintptr, uintptr, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TFts5SegIter)(unsafe.Pointer(pSeg)).FxNext})))(tls, p, pSeg, uintptr(0))
|
|
}
|
|
_fts5MultiIterAdvanced(tls, p, pIter, iEq, iIter)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
iIter = iIter - 1
|
|
}
|
|
_fts5MultiIterSetEof(tls, pIter)
|
|
if (*TFts5Iter)(unsafe.Pointer(pIter)).FbSkipEmpty != 0 && _fts5MultiIterIsEmpty(tls, p, pIter) != 0 || _fts5MultiIterIsDeleted(tls, pIter) != 0 {
|
|
_fts5MultiIterNext(tls, p, pIter, 0, 0)
|
|
} else {
|
|
if libc.Int32FromUint8((*TFts5Iter)(unsafe.Pointer(pIter)).Fbase.FbEof) == 0 {
|
|
pSeg1 = pIter + 104 + uintptr((**(**TFts5CResult)(__ccgo_up((*TFts5Iter)(unsafe.Pointer(pIter)).FaFirst + 1*4))).FiFirst)*128
|
|
(*(*func(*libc.TLS, uintptr, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TFts5Iter)(unsafe.Pointer(pIter)).FxSetOutputs})))(tls, pIter, pSeg1)
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if the iterator passed as the only argument points
|
|
// ** to an segment entry for which there is a tombstone. Return false
|
|
// ** if there is no tombstone or if the iterator is already at EOF.
|
|
// */
|
|
func _fts5MultiIterIsDeleted(tls *libc.TLS, pIter uintptr) (r int32) {
|
|
var iFirst, iPg int32
|
|
var pArray, pSeg uintptr
|
|
_, _, _, _ = iFirst, iPg, pArray, pSeg
|
|
iFirst = libc.Int32FromUint16((**(**TFts5CResult)(__ccgo_up((*TFts5Iter)(unsafe.Pointer(pIter)).FaFirst + 1*4))).FiFirst)
|
|
pSeg = pIter + 104 + uintptr(iFirst)*128
|
|
pArray = (*TFts5SegIter)(unsafe.Pointer(pSeg)).FpTombArray
|
|
if (*TFts5SegIter)(unsafe.Pointer(pSeg)).FpLeaf != 0 && pArray != 0 {
|
|
/* Figure out which page the rowid might be present on. */
|
|
iPg = libc.Int32FromUint64(libc.Uint64FromInt64((*TFts5SegIter)(unsafe.Pointer(pSeg)).FiRowid) % libc.Uint64FromInt32((*TFts5TombstoneArray)(unsafe.Pointer(pArray)).FnTombstone))
|
|
/* If tombstone hash page iPg has not yet been loaded from the
|
|
** database, load it now. */
|
|
if *(*uintptr)(unsafe.Pointer(pArray + 8 + uintptr(iPg)*8)) == uintptr(0) {
|
|
*(*uintptr)(unsafe.Pointer(pArray + 8 + uintptr(iPg)*8)) = _fts5DataRead(tls, (*TFts5Iter)(unsafe.Pointer(pIter)).FpIndex, int64((*TFts5StructureSegment)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pSeg)).FpSeg)).FiSegid+libc.Int32FromInt32(1)<<libc.Int32FromInt32(16))<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B)+libc.Int32FromInt32(FTS5_DATA_DLI_B))+int64(libc.Int32FromInt32(0))<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B))+int64(libc.Int32FromInt32(0))<<libc.Int32FromInt32(FTS5_DATA_PAGE_B)+int64(iPg))
|
|
if *(*uintptr)(unsafe.Pointer(pArray + 8 + uintptr(iPg)*8)) == uintptr(0) {
|
|
return 0
|
|
}
|
|
}
|
|
return _fts5IndexTombstoneQuery(tls, *(*uintptr)(unsafe.Pointer(pArray + 8 + uintptr(iPg)*8)), (*TFts5TombstoneArray)(unsafe.Pointer(pArray)).FnTombstone, libc.Uint64FromInt64((*TFts5SegIter)(unsafe.Pointer(pSeg)).FiRowid))
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Create an Fts5Iter that iterates through the doclist provided
|
|
// ** as the second argument.
|
|
// */
|
|
func _fts5MultiIterNew2(tls *libc.TLS, p uintptr, pData uintptr, bDesc int32, ppOut uintptr) {
|
|
var pIter, pNew uintptr
|
|
_, _ = pIter, pNew
|
|
pNew = _fts5MultiIterAlloc(tls, p, int32(2))
|
|
if pNew != 0 {
|
|
pIter = pNew + 104 + 1*128
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).Fflags = int32(FTS5_SEGITER_ONETERM)
|
|
if (*TFts5Data)(unsafe.Pointer(pData)).FszLeaf > 0 {
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf = pData
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = libc.Int64FromUint8(_sqlite3Fts5GetVarint(tls, (*TFts5Data)(unsafe.Pointer(pData)).Fp, pIter+112))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist = (*TFts5Data)(unsafe.Pointer(pData)).Fnn
|
|
(**(**TFts5CResult)(__ccgo_up((*TFts5Iter)(unsafe.Pointer(pNew)).FaFirst + 1*4))).FiFirst = uint16(1)
|
|
if bDesc != 0 {
|
|
(*TFts5Iter)(unsafe.Pointer(pNew)).FbRev = int32(1)
|
|
**(**int32)(__ccgo_up(pIter + 8)) |= int32(FTS5_SEGITER_REVERSE)
|
|
_fts5SegIterReverseInitPage(tls, p, pIter)
|
|
} else {
|
|
_fts5SegIterLoadNPos(tls, p, pIter)
|
|
}
|
|
pData = uintptr(0)
|
|
} else {
|
|
(*TFts5Iter)(unsafe.Pointer(pNew)).Fbase.FbEof = uint8(1)
|
|
}
|
|
_fts5SegIterSetNext(tls, p, pIter)
|
|
**(**uintptr)(__ccgo_up(ppOut)) = pNew
|
|
}
|
|
_fts5DataRelease(tls, pData)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Move the iterator to the next entry.
|
|
// **
|
|
// ** If an error occurs, an error code is left in Fts5Index.rc. It is not
|
|
// ** considered an error if the iterator reaches EOF, or if it is already at
|
|
// ** EOF when this function is called.
|
|
// */
|
|
func _fts5MultiIterNext(tls *libc.TLS, p uintptr, pIter uintptr, bFrom int32, iFrom Ti64) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var bUseFrom, iFirst int32
|
|
var _ /* bNewTerm at bp+0 */ int32
|
|
var _ /* pSeg at bp+8 */ uintptr
|
|
_, _ = bUseFrom, iFirst
|
|
bUseFrom = bFrom
|
|
for (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
iFirst = libc.Int32FromUint16((**(**TFts5CResult)(__ccgo_up((*TFts5Iter)(unsafe.Pointer(pIter)).FaFirst + 1*4))).FiFirst)
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = pIter + 104 + uintptr(iFirst)*128
|
|
if bUseFrom != 0 && (*TFts5SegIter)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp + 8)))).FpDlidx != 0 {
|
|
_fts5SegIterNextFrom(tls, p, **(**uintptr)(__ccgo_up(bp + 8)), iFrom)
|
|
} else {
|
|
(*(*func(*libc.TLS, uintptr, uintptr, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TFts5SegIter)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp + 8)))).FxNext})))(tls, p, **(**uintptr)(__ccgo_up(bp + 8)), bp)
|
|
}
|
|
if (*TFts5SegIter)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp + 8)))).FpLeaf == uintptr(0) || **(**int32)(__ccgo_up(bp)) != 0 || _fts5MultiIterAdvanceRowid(tls, pIter, iFirst, bp+8) != 0 {
|
|
_fts5MultiIterAdvanced(tls, p, pIter, iFirst, int32(1))
|
|
_fts5MultiIterSetEof(tls, pIter)
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = pIter + 104 + uintptr((**(**TFts5CResult)(__ccgo_up((*TFts5Iter)(unsafe.Pointer(pIter)).FaFirst + 1*4))).FiFirst)*128
|
|
if (*TFts5SegIter)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp + 8)))).FpLeaf == uintptr(0) {
|
|
return
|
|
}
|
|
}
|
|
if (libc.Int32FromUint8((*TFts5Iter)(unsafe.Pointer(pIter)).FbSkipEmpty) == 0 || (*TFts5SegIter)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp + 8)))).FnPos != 0) && 0 == _fts5MultiIterIsDeleted(tls, pIter) {
|
|
(*(*func(*libc.TLS, uintptr, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TFts5Iter)(unsafe.Pointer(pIter)).FxSetOutputs})))(tls, pIter, **(**uintptr)(__ccgo_up(bp + 8)))
|
|
return
|
|
}
|
|
bUseFrom = 0
|
|
}
|
|
}
|
|
|
|
func _fts5MultiIterNext2(tls *libc.TLS, p uintptr, pIter uintptr, pbNewTerm uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iFirst int32
|
|
var _ /* bNewTerm at bp+8 */ int32
|
|
var _ /* pSeg at bp+0 */ uintptr
|
|
_ = iFirst
|
|
if (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
**(**int32)(__ccgo_up(pbNewTerm)) = 0
|
|
for cond := true; cond; cond = (_fts5MultiIterIsEmpty(tls, p, pIter) != 0 || _fts5MultiIterIsDeleted(tls, pIter) != 0) && (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
iFirst = libc.Int32FromUint16((**(**TFts5CResult)(__ccgo_up((*TFts5Iter)(unsafe.Pointer(pIter)).FaFirst + 1*4))).FiFirst)
|
|
**(**uintptr)(__ccgo_up(bp)) = pIter + 104 + uintptr(iFirst)*128
|
|
**(**int32)(__ccgo_up(bp + 8)) = 0
|
|
(*(*func(*libc.TLS, uintptr, uintptr, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TFts5SegIter)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FxNext})))(tls, p, **(**uintptr)(__ccgo_up(bp)), bp+8)
|
|
if (*TFts5SegIter)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FpLeaf == uintptr(0) || **(**int32)(__ccgo_up(bp + 8)) != 0 || _fts5MultiIterAdvanceRowid(tls, pIter, iFirst, bp) != 0 {
|
|
_fts5MultiIterAdvanced(tls, p, pIter, iFirst, int32(1))
|
|
_fts5MultiIterSetEof(tls, pIter)
|
|
**(**int32)(__ccgo_up(pbNewTerm)) = int32(1)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The second argument passed to this function may be NULL, or it may be
|
|
// ** an existing Fts5Colset object. This function returns a pointer to
|
|
// ** a new colset object containing the contents of (p) with new value column
|
|
// ** number iCol appended.
|
|
// **
|
|
// ** If an OOM error occurs, store an error code in pParse and return NULL.
|
|
// ** The old colset object (if any) is not freed in this case.
|
|
// */
|
|
func _fts5ParseColset(tls *libc.TLS, pParse uintptr, p uintptr, iCol int32) (r uintptr) {
|
|
var aiCol, pNew uintptr
|
|
var i, j, nCol, v1 int32
|
|
_, _, _, _, _, _ = aiCol, i, j, nCol, pNew, v1
|
|
if p != 0 {
|
|
v1 = (*TFts5Colset)(unsafe.Pointer(p)).FnCol
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
nCol = v1 /* New colset object to return */
|
|
pNew = Xsqlite3_realloc64(tls, p, uint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32((nCol+libc.Int32FromInt32(1)+libc.Int32FromInt32(2))/libc.Int32FromInt32(2))))
|
|
if pNew == uintptr(0) {
|
|
(*TFts5Parse)(unsafe.Pointer(pParse)).Frc = int32(SQLITE_NOMEM)
|
|
} else {
|
|
aiCol = pNew + 4
|
|
i = 0
|
|
for {
|
|
if !(i < nCol) {
|
|
break
|
|
}
|
|
if **(**int32)(__ccgo_up(aiCol + uintptr(i)*4)) == iCol {
|
|
return pNew
|
|
}
|
|
if **(**int32)(__ccgo_up(aiCol + uintptr(i)*4)) > iCol {
|
|
break
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
j = nCol
|
|
for {
|
|
if !(j > i) {
|
|
break
|
|
}
|
|
**(**int32)(__ccgo_up(aiCol + uintptr(j)*4)) = **(**int32)(__ccgo_up(aiCol + uintptr(j-int32(1))*4))
|
|
goto _3
|
|
_3:
|
|
;
|
|
j = j - 1
|
|
}
|
|
**(**int32)(__ccgo_up(aiCol + uintptr(i)*4)) = iCol
|
|
(*TFts5Colset)(unsafe.Pointer(pNew)).FnCol = nCol + int32(1)
|
|
}
|
|
return pNew
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is used when parsing LIKE or GLOB patterns against
|
|
// ** trigram indexes that specify either detail=column or detail=none.
|
|
// ** It converts a phrase:
|
|
// **
|
|
// ** abc + def + ghi
|
|
// **
|
|
// ** into an AND tree:
|
|
// **
|
|
// ** abc AND def AND ghi
|
|
// */
|
|
func _fts5ParsePhraseToAnd(tls *libc.TLS, pParse uintptr, pNear uintptr) (r uintptr) {
|
|
var ii, nByte, nTerm, v2 int32
|
|
var p, pPhrase, pRet, pTo, v3 uintptr
|
|
_, _, _, _, _, _, _, _, _ = ii, nByte, nTerm, p, pPhrase, pRet, pTo, v2, v3
|
|
nTerm = (*TFts5ExprPhrase)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pNear + 24)))).FnTerm
|
|
nByte = libc.Int32FromUint64(uint64(libc.UintptrFromInt32(0)+48) + libc.Uint64FromInt32(nTerm+libc.Int32FromInt32(1))*libc.Uint64FromInt64(8))
|
|
pRet = _sqlite3Fts5MallocZero(tls, pParse+16, int64(nByte))
|
|
if pRet != 0 {
|
|
(*TFts5ExprNode)(unsafe.Pointer(pRet)).FeType = int32(FTS5_AND)
|
|
(*TFts5ExprNode)(unsafe.Pointer(pRet)).FnChild = nTerm
|
|
(*TFts5ExprNode)(unsafe.Pointer(pRet)).FiHeight = int32(1)
|
|
_fts5ExprAssignXNext(tls, pRet)
|
|
(*TFts5Parse)(unsafe.Pointer(pParse)).FnPhrase = (*TFts5Parse)(unsafe.Pointer(pParse)).FnPhrase - 1
|
|
ii = 0
|
|
for {
|
|
if !(ii < nTerm) {
|
|
break
|
|
}
|
|
pPhrase = _sqlite3Fts5MallocZero(tls, pParse+16, libc.Int64FromUint64(uint64(libc.UintptrFromInt32(0)+32)+libc.Uint64FromInt32(libc.Int32FromInt32(1))*libc.Uint64FromInt64(40)))
|
|
if pPhrase != 0 {
|
|
if _parseGrowPhraseArray(tls, pParse) != 0 {
|
|
_fts5ExprPhraseFree(tls, pPhrase)
|
|
} else {
|
|
p = *(*uintptr)(unsafe.Pointer(pNear + 24)) + 32 + uintptr(ii)*40
|
|
pTo = pPhrase + 32
|
|
v3 = pParse + 20
|
|
v2 = *(*int32)(unsafe.Pointer(v3))
|
|
*(*int32)(unsafe.Pointer(v3)) = *(*int32)(unsafe.Pointer(v3)) + 1
|
|
**(**uintptr)(__ccgo_up((*TFts5Parse)(unsafe.Pointer(pParse)).FapPhrase + uintptr(v2)*8)) = pPhrase
|
|
(*TFts5ExprPhrase)(unsafe.Pointer(pPhrase)).FnTerm = int32(1)
|
|
(*TFts5ExprTerm)(unsafe.Pointer(pTo)).FpTerm = _sqlite3Fts5Strndup(tls, pParse+16, (*TFts5ExprTerm)(unsafe.Pointer(p)).FpTerm, (*TFts5ExprTerm)(unsafe.Pointer(p)).FnFullTerm)
|
|
(*TFts5ExprTerm)(unsafe.Pointer(pTo)).FnQueryTerm = (*TFts5ExprTerm)(unsafe.Pointer(p)).FnQueryTerm
|
|
(*TFts5ExprTerm)(unsafe.Pointer(pTo)).FnFullTerm = (*TFts5ExprTerm)(unsafe.Pointer(p)).FnFullTerm
|
|
*(*uintptr)(unsafe.Pointer(pRet + 48 + uintptr(ii)*8)) = _sqlite3Fts5ParseNode(tls, pParse, int32(FTS5_STRING), uintptr(0), uintptr(0), _sqlite3Fts5ParseNearset(tls, pParse, uintptr(0), pPhrase))
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
if (*TFts5Parse)(unsafe.Pointer(pParse)).Frc != 0 {
|
|
_sqlite3Fts5ParseNodeFree(tls, pRet)
|
|
pRet = uintptr(0)
|
|
} else {
|
|
_sqlite3Fts5ParseNearsetFree(tls, pNear)
|
|
}
|
|
}
|
|
return pRet
|
|
}
|
|
|
|
func _fts5PoslistOffsetsCallback(tls *libc.TLS, pUnused uintptr, pContext uintptr, pChunk uintptr, nChunk int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var i int32
|
|
var pCtx uintptr
|
|
var _ /* iVal at bp+0 */ int32
|
|
_, _ = i, pCtx
|
|
pCtx = pContext
|
|
_ = pUnused
|
|
if nChunk > 0 {
|
|
i = 0
|
|
for i < nChunk {
|
|
i = i + _sqlite3Fts5GetVarint32(tls, pChunk+uintptr(i), bp)
|
|
**(**int32)(__ccgo_up(bp)) = **(**int32)(__ccgo_up(bp)) + ((*TPoslistOffsetsCtx)(unsafe.Pointer(pCtx)).FiRead - int32(2))
|
|
(*TPoslistOffsetsCtx)(unsafe.Pointer(pCtx)).FiRead = **(**int32)(__ccgo_up(bp))
|
|
if _fts5IndexColsetTest(tls, (*TPoslistOffsetsCtx)(unsafe.Pointer(pCtx)).FpColset, **(**int32)(__ccgo_up(bp))) != 0 {
|
|
**(**int32)(__ccgo_up((*TPoslistOffsetsCtx)(unsafe.Pointer(pCtx)).FpBuf + 8)) += _sqlite3Fts5PutVarint(tls, (*TFts5Buffer)(unsafe.Pointer((*TPoslistOffsetsCtx)(unsafe.Pointer(pCtx)).FpBuf)).Fp+uintptr((*TFts5Buffer)(unsafe.Pointer((*TPoslistOffsetsCtx)(unsafe.Pointer(pCtx)).FpBuf)).Fn), libc.Uint64FromInt32(**(**int32)(__ccgo_up(bp))+libc.Int32FromInt32(2)-(*TPoslistOffsetsCtx)(unsafe.Pointer(pCtx)).FiWrite))
|
|
(*TPoslistOffsetsCtx)(unsafe.Pointer(pCtx)).FiWrite = **(**int32)(__ccgo_up(bp))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate a tombstone hash page array object (pIter->pTombArray) for
|
|
// ** the iterator passed as the second argument. If an OOM error occurs,
|
|
// ** leave an error in the Fts5Index object.
|
|
// */
|
|
func _fts5SegIterAllocTombstone(tls *libc.TLS, p uintptr, pIter uintptr) {
|
|
var nByte, nTomb Ti64
|
|
var pNew uintptr
|
|
_, _, _ = nByte, nTomb, pNew
|
|
nTomb = int64((*TFts5StructureSegment)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpSeg)).FnPgTombstone)
|
|
if nTomb > 0 {
|
|
nByte = libc.Int64FromUint64(uint64(libc.UintptrFromInt32(0)+8) + libc.Uint64FromInt64(nTomb+libc.Int64FromInt32(1))*libc.Uint64FromInt64(8))
|
|
pNew = _sqlite3Fts5MallocZero(tls, p+60, nByte)
|
|
if pNew != 0 {
|
|
(*TFts5TombstoneArray)(unsafe.Pointer(pNew)).FnTombstone = int32(nTomb)
|
|
(*TFts5TombstoneArray)(unsafe.Pointer(pNew)).FnRef = int32(1)
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FpTombArray = pNew
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Move the seg-iter so that it points to the first rowid on page iLeafPgno.
|
|
// ** It is an error if leaf iLeafPgno does not exist. Unless the db is
|
|
// ** a 'secure-delete' db, if it contains no rowids then this is also an error.
|
|
// */
|
|
func _fts5SegIterGotoPage(tls *libc.TLS, p uintptr, pIter uintptr, iLeafPgno int32) {
|
|
var a uintptr
|
|
var iOff, n int32
|
|
_, _, _ = a, iOff, n
|
|
if iLeafPgno > (*TFts5StructureSegment)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpSeg)).FpgnoLast {
|
|
_fts5IndexCorruptIdx(tls, p)
|
|
} else {
|
|
_fts5DataRelease(tls, (*TFts5SegIter)(unsafe.Pointer(pIter)).FpNextLeaf)
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FpNextLeaf = uintptr(0)
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafPgno = iLeafPgno - int32(1)
|
|
for (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
_fts5SegIterNextPage(tls, p, pIter)
|
|
if (*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf == uintptr(0) {
|
|
break
|
|
}
|
|
iOff = libc.Int32FromUint16(_fts5GetU16(tls, (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp))
|
|
if iOff > 0 {
|
|
a = (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp
|
|
n = (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).FszLeaf
|
|
if iOff < int32(4) || iOff >= n {
|
|
_fts5IndexCorruptIdx(tls, p)
|
|
} else {
|
|
iOff = iOff + libc.Int32FromUint8(_sqlite3Fts5GetVarint(tls, a+uintptr(iOff), pIter+112))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = int64(iOff)
|
|
_fts5SegIterLoadNPos(tls, p, pIter)
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Initialize the object pIter to point to term pTerm/nTerm within the
|
|
// ** in-memory hash table. If there is no such term in the hash-table, the
|
|
// ** iterator is set to EOF.
|
|
// **
|
|
// ** If an error occurs, Fts5Index.rc is set to an appropriate error code. If
|
|
// ** an error has already occurred when this function is called, it is a no-op.
|
|
// */
|
|
func _fts5SegIterHashInit(tls *libc.TLS, p uintptr, pTerm uintptr, nTerm int32, flags int32, pIter uintptr) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var v1 int32
|
|
var _ /* n at bp+16 */ int32
|
|
var _ /* nList at bp+0 */ int32
|
|
var _ /* pLeaf at bp+24 */ uintptr
|
|
var _ /* pList at bp+32 */ uintptr
|
|
var _ /* z at bp+8 */ uintptr
|
|
_ = v1
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = uintptr(0)
|
|
**(**int32)(__ccgo_up(bp + 16)) = 0
|
|
**(**uintptr)(__ccgo_up(bp + 24)) = uintptr(0)
|
|
if pTerm == uintptr(0) || flags&int32(FTS5INDEX_QUERY_SCAN) != 0 {
|
|
**(**uintptr)(__ccgo_up(bp + 32)) = uintptr(0)
|
|
(*TFts5Index)(unsafe.Pointer(p)).Frc = _sqlite3Fts5HashScanInit(tls, (*TFts5Index)(unsafe.Pointer(p)).FpHash, pTerm, nTerm)
|
|
_sqlite3Fts5HashScanEntry(tls, (*TFts5Index)(unsafe.Pointer(p)).FpHash, bp+8, bp+16, bp+32, bp)
|
|
if **(**uintptr)(__ccgo_up(bp + 32)) != 0 {
|
|
**(**uintptr)(__ccgo_up(bp + 24)) = _fts5IdxMalloc(tls, p, int64(16))
|
|
if **(**uintptr)(__ccgo_up(bp + 24)) != 0 {
|
|
(*TFts5Data)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp + 24)))).Fp = **(**uintptr)(__ccgo_up(bp + 32))
|
|
}
|
|
}
|
|
/* The call to sqlite3Fts5HashScanInit() causes the hash table to
|
|
** fill the size field of all existing position lists. This means they
|
|
** can no longer be appended to. Since the only scenario in which they
|
|
** can be appended to is if the previous operation on this table was
|
|
** a DELETE, by clearing the Fts5Index.bDelete flag we can avoid this
|
|
** possibility altogether. */
|
|
(*TFts5Index)(unsafe.Pointer(p)).FbDelete = 0
|
|
} else {
|
|
(*TFts5Index)(unsafe.Pointer(p)).Frc = _sqlite3Fts5HashQuery(tls, (*TFts5Index)(unsafe.Pointer(p)).FpHash, int32(16), pTerm, nTerm, bp+24, bp)
|
|
if **(**uintptr)(__ccgo_up(bp + 24)) != 0 {
|
|
(*TFts5Data)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp + 24)))).Fp = **(**uintptr)(__ccgo_up(bp + 24)) + 1*16
|
|
}
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = pTerm
|
|
**(**int32)(__ccgo_up(bp + 16)) = nTerm
|
|
**(**int32)(__ccgo_up(pIter + 8)) |= int32(FTS5_SEGITER_ONETERM)
|
|
}
|
|
if **(**uintptr)(__ccgo_up(bp + 24)) != 0 {
|
|
_sqlite3Fts5BufferSet(tls, p+60, pIter+96, **(**int32)(__ccgo_up(bp + 16)), **(**uintptr)(__ccgo_up(bp + 8)))
|
|
v1 = **(**int32)(__ccgo_up(bp))
|
|
(*TFts5Data)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp + 24)))).FszLeaf = v1
|
|
(*TFts5Data)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp + 24)))).Fnn = v1
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf = **(**uintptr)(__ccgo_up(bp + 24))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = libc.Int64FromUint8(_sqlite3Fts5GetVarint(tls, (*TFts5Data)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp + 24)))).Fp, pIter+112))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist = (*TFts5Data)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp + 24)))).Fnn
|
|
if flags&int32(FTS5INDEX_QUERY_DESC) != 0 {
|
|
**(**int32)(__ccgo_up(pIter + 8)) |= int32(FTS5_SEGITER_REVERSE)
|
|
_fts5SegIterReverseInitPage(tls, p, pIter)
|
|
} else {
|
|
_fts5SegIterLoadNPos(tls, p, pIter)
|
|
}
|
|
}
|
|
_fts5SegIterSetNext(tls, p, pIter)
|
|
}
|
|
|
|
func _fts5SegIterLoadRowid(tls *libc.TLS, p uintptr, pIter uintptr) {
|
|
var a uintptr
|
|
var iOff Ti64
|
|
_, _ = a, iOff
|
|
a = (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp /* Buffer to read data from */
|
|
iOff = (*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset
|
|
for iOff >= int64((*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).FszLeaf) {
|
|
_fts5SegIterNextPage(tls, p, pIter)
|
|
if (*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf == uintptr(0) {
|
|
if (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
_fts5IndexCorruptIter(tls, p, pIter)
|
|
}
|
|
return
|
|
}
|
|
iOff = int64(4)
|
|
a = (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp
|
|
}
|
|
iOff = iOff + libc.Int64FromUint8(_sqlite3Fts5GetVarint(tls, a+uintptr(iOff), pIter+112))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = iOff
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Fts5SegIter.iLeafOffset currently points to the first byte of the
|
|
// ** "nSuffix" field of a term. Function parameter nKeep contains the value
|
|
// ** of the "nPrefix" field (if there was one - it is passed 0 if this is
|
|
// ** the first term in the segment).
|
|
// **
|
|
// ** This function populates:
|
|
// **
|
|
// ** Fts5SegIter.term
|
|
// ** Fts5SegIter.rowid
|
|
// **
|
|
// ** accordingly and leaves (Fts5SegIter.iLeafOffset) set to the content of
|
|
// ** the first position list. The position list belonging to document
|
|
// ** (Fts5SegIter.iRowid).
|
|
// */
|
|
func _fts5SegIterLoadTerm(tls *libc.TLS, p uintptr, pIter uintptr, nKeep int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var a uintptr
|
|
var iOff Ti64
|
|
var _ /* nExtra at bp+4 */ int32
|
|
var _ /* nNew at bp+0 */ int32
|
|
_, _ = a, iOff
|
|
a = (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp /* Buffer to read data from */
|
|
iOff = (*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset /* Bytes of new data */
|
|
iOff = iOff + int64(_sqlite3Fts5GetVarint32(tls, a+uintptr(iOff), bp))
|
|
if iOff+int64(**(**int32)(__ccgo_up(bp))) > int64((*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).FszLeaf) || nKeep > (*TFts5SegIter)(unsafe.Pointer(pIter)).Fterm.Fn || **(**int32)(__ccgo_up(bp)) == 0 {
|
|
_fts5IndexCorruptIter(tls, p, pIter)
|
|
return
|
|
}
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).Fterm.Fn = nKeep
|
|
_sqlite3Fts5BufferAppendBlob(tls, p+60, pIter+96, libc.Uint32FromInt32(**(**int32)(__ccgo_up(bp))), a+uintptr(iOff))
|
|
iOff = iOff + int64(**(**int32)(__ccgo_up(bp)))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiTermLeafOffset = int32(iOff)
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiTermLeafPgno = (*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafPgno
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = iOff
|
|
if (*TFts5SegIter)(unsafe.Pointer(pIter)).FiPgidxOff >= (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fnn {
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist = (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fnn + int32(1)
|
|
} else {
|
|
**(**int32)(__ccgo_up(pIter + 64)) += _sqlite3Fts5GetVarint32(tls, a+uintptr((*TFts5SegIter)(unsafe.Pointer(pIter)).FiPgidxOff), bp+4)
|
|
**(**int32)(__ccgo_up(pIter + 68)) += **(**int32)(__ccgo_up(bp + 4))
|
|
}
|
|
_fts5SegIterLoadRowid(tls, p, pIter)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Advance iterator pIter to the next entry.
|
|
// **
|
|
// ** If an error occurs, Fts5Index.rc is set to an appropriate error code. It
|
|
// ** is not considered an error if the iterator reaches EOF. If an error has
|
|
// ** already occurred when this function is called, it is a no-op.
|
|
// */
|
|
func _fts5SegIterNext(tls *libc.TLS, p uintptr, pIter uintptr, pbNewTerm uintptr) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var a, pLeaf, v1 uintptr
|
|
var bNewTerm, n, v2 int32
|
|
var v3 Ti64
|
|
var _ /* iDelta at bp+8 */ Tu64
|
|
var _ /* iOff at bp+0 */ int32
|
|
var _ /* nKeep at bp+4 */ int32
|
|
var _ /* nList at bp+36 */ int32
|
|
var _ /* nSz at bp+40 */ int32
|
|
var _ /* nTerm at bp+32 */ int32
|
|
var _ /* pList at bp+16 */ uintptr
|
|
var _ /* zTerm at bp+24 */ uintptr
|
|
_, _, _, _, _, _, _ = a, bNewTerm, n, pLeaf, v1, v2, v3
|
|
pLeaf = (*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf
|
|
bNewTerm = 0
|
|
**(**int32)(__ccgo_up(bp + 4)) = 0
|
|
/* Search for the end of the position list within the current page. */
|
|
a = (*TFts5Data)(unsafe.Pointer(pLeaf)).Fp
|
|
n = (*TFts5Data)(unsafe.Pointer(pLeaf)).FszLeaf
|
|
**(**int32)(__ccgo_up(bp)) = int32((*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset + int64((*TFts5SegIter)(unsafe.Pointer(pIter)).FnPos))
|
|
if **(**int32)(__ccgo_up(bp)) < n {
|
|
/* The next entry is on the current page. */
|
|
if **(**int32)(__ccgo_up(bp)) >= (*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist {
|
|
bNewTerm = int32(1)
|
|
if **(**int32)(__ccgo_up(bp)) != _fts5LeafFirstTermOff(tls, pLeaf) {
|
|
**(**int32)(__ccgo_up(bp)) = **(**int32)(__ccgo_up(bp)) + _sqlite3Fts5GetVarint32(tls, a+uintptr(**(**int32)(__ccgo_up(bp))), bp+4)
|
|
}
|
|
} else {
|
|
**(**int32)(__ccgo_up(bp)) = **(**int32)(__ccgo_up(bp)) + libc.Int32FromUint8(_sqlite3Fts5GetVarint(tls, a+uintptr(**(**int32)(__ccgo_up(bp))), bp+8))
|
|
v1 = pIter + 112
|
|
*(*Ti64)(unsafe.Pointer(v1)) = Ti64(uint64(*(*Ti64)(unsafe.Pointer(v1))) + **(**Tu64)(__ccgo_up(bp + 8)))
|
|
}
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = int64(**(**int32)(__ccgo_up(bp)))
|
|
} else {
|
|
if (*TFts5SegIter)(unsafe.Pointer(pIter)).FpSeg == uintptr(0) {
|
|
**(**uintptr)(__ccgo_up(bp + 16)) = uintptr(0)
|
|
**(**uintptr)(__ccgo_up(bp + 24)) = uintptr(0)
|
|
**(**int32)(__ccgo_up(bp + 32)) = 0
|
|
**(**int32)(__ccgo_up(bp + 36)) = 0
|
|
if 0 == (*TFts5SegIter)(unsafe.Pointer(pIter)).Fflags&int32(FTS5_SEGITER_ONETERM) {
|
|
_sqlite3Fts5HashScanNext(tls, (*TFts5Index)(unsafe.Pointer(p)).FpHash)
|
|
_sqlite3Fts5HashScanEntry(tls, (*TFts5Index)(unsafe.Pointer(p)).FpHash, bp+24, bp+32, bp+16, bp+36)
|
|
}
|
|
if **(**uintptr)(__ccgo_up(bp + 16)) == uintptr(0) {
|
|
_fts5DataRelease(tls, (*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf = uintptr(0)
|
|
} else {
|
|
(*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp = **(**uintptr)(__ccgo_up(bp + 16))
|
|
(*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fnn = **(**int32)(__ccgo_up(bp + 36))
|
|
(*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).FszLeaf = **(**int32)(__ccgo_up(bp + 36))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist = **(**int32)(__ccgo_up(bp + 36)) + int32(1)
|
|
_sqlite3Fts5BufferSet(tls, p+60, pIter+96, **(**int32)(__ccgo_up(bp + 32)), **(**uintptr)(__ccgo_up(bp + 24)))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = libc.Int64FromUint8(_sqlite3Fts5GetVarint(tls, **(**uintptr)(__ccgo_up(bp + 16)), pIter+112))
|
|
**(**int32)(__ccgo_up(pbNewTerm)) = int32(1)
|
|
}
|
|
} else {
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
/* Next entry is not on the current page */
|
|
for **(**int32)(__ccgo_up(bp)) == 0 {
|
|
_fts5SegIterNextPage(tls, p, pIter)
|
|
pLeaf = (*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf
|
|
if pLeaf == uintptr(0) {
|
|
break
|
|
}
|
|
v2 = libc.Int32FromUint16(_fts5GetU16(tls, (*TFts5Data)(unsafe.Pointer(pLeaf)).Fp))
|
|
**(**int32)(__ccgo_up(bp)) = v2
|
|
if v2 != 0 && **(**int32)(__ccgo_up(bp)) < (*TFts5Data)(unsafe.Pointer(pLeaf)).FszLeaf {
|
|
**(**int32)(__ccgo_up(bp)) = **(**int32)(__ccgo_up(bp)) + libc.Int32FromUint8(_sqlite3Fts5GetVarint(tls, (*TFts5Data)(unsafe.Pointer(pLeaf)).Fp+uintptr(**(**int32)(__ccgo_up(bp))), pIter+112))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = int64(**(**int32)(__ccgo_up(bp)))
|
|
if (*TFts5Data)(unsafe.Pointer(pLeaf)).Fnn > (*TFts5Data)(unsafe.Pointer(pLeaf)).FszLeaf {
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiPgidxOff = (*TFts5Data)(unsafe.Pointer(pLeaf)).FszLeaf + _sqlite3Fts5GetVarint32(tls, (*TFts5Data)(unsafe.Pointer(pLeaf)).Fp+uintptr((*TFts5Data)(unsafe.Pointer(pLeaf)).FszLeaf), pIter+68)
|
|
}
|
|
} else {
|
|
if (*TFts5Data)(unsafe.Pointer(pLeaf)).Fnn > (*TFts5Data)(unsafe.Pointer(pLeaf)).FszLeaf {
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiPgidxOff = (*TFts5Data)(unsafe.Pointer(pLeaf)).FszLeaf + _sqlite3Fts5GetVarint32(tls, (*TFts5Data)(unsafe.Pointer(pLeaf)).Fp+uintptr((*TFts5Data)(unsafe.Pointer(pLeaf)).FszLeaf), bp)
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = int64(**(**int32)(__ccgo_up(bp)))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist = **(**int32)(__ccgo_up(bp))
|
|
bNewTerm = int32(1)
|
|
}
|
|
}
|
|
if **(**int32)(__ccgo_up(bp)) > (*TFts5Data)(unsafe.Pointer(pLeaf)).FszLeaf {
|
|
_fts5IndexCorruptIter(tls, p, pIter)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* Check if the iterator is now at EOF. If so, return early. */
|
|
if (*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf != 0 {
|
|
if bNewTerm != 0 {
|
|
if (*TFts5SegIter)(unsafe.Pointer(pIter)).Fflags&int32(FTS5_SEGITER_ONETERM) != 0 {
|
|
_fts5DataRelease(tls, (*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf = uintptr(0)
|
|
} else {
|
|
_fts5SegIterLoadTerm(tls, p, pIter, **(**int32)(__ccgo_up(bp + 4)))
|
|
_fts5SegIterLoadNPos(tls, p, pIter)
|
|
if pbNewTerm != 0 {
|
|
**(**int32)(__ccgo_up(pbNewTerm)) = int32(1)
|
|
}
|
|
}
|
|
} else {
|
|
v1 = pIter + 32
|
|
v3 = *(*Ti64)(unsafe.Pointer(v1))
|
|
*(*Ti64)(unsafe.Pointer(v1)) = *(*Ti64)(unsafe.Pointer(v1)) + 1
|
|
**(**int32)(__ccgo_up(bp + 40)) = libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp + uintptr(v3))))
|
|
if **(**int32)(__ccgo_up(bp + 40))&int32(0x80) != 0 {
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = (*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset - 1
|
|
**(**Ti64)(__ccgo_up(pIter + 32)) += int64(_sqlite3Fts5GetVarint32(tls, (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp+uintptr((*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset), bp+40))
|
|
}
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FbDel = libc.Uint8FromInt32(**(**int32)(__ccgo_up(bp + 40)) & libc.Int32FromInt32(0x0001))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FnPos = **(**int32)(__ccgo_up(bp + 40)) >> int32(1)
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Advance iterator pIter to the next entry.
|
|
// **
|
|
// ** This version of fts5SegIterNext() is only used if detail=none and the
|
|
// ** iterator is not a reverse direction iterator.
|
|
// */
|
|
func _fts5SegIterNext_None(tls *libc.TLS, p uintptr, pIter uintptr, pbNewTerm uintptr) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var iOff int32
|
|
var v1 uintptr
|
|
var _ /* iDelta at bp+0 */ Tu64
|
|
var _ /* nKeep at bp+8 */ int32
|
|
var _ /* nList at bp+36 */ int32
|
|
var _ /* nTerm at bp+32 */ int32
|
|
var _ /* pList at bp+16 */ uintptr
|
|
var _ /* zTerm at bp+24 */ uintptr
|
|
_, _ = iOff, v1
|
|
iOff = int32((*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset)
|
|
/* Next entry is on the next page */
|
|
for (*TFts5SegIter)(unsafe.Pointer(pIter)).FpSeg != 0 && iOff >= (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).FszLeaf {
|
|
_fts5SegIterNextPage(tls, p, pIter)
|
|
if (*TFts5Index)(unsafe.Pointer(p)).Frc != 0 || (*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf == uintptr(0) {
|
|
return
|
|
}
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiRowid = 0
|
|
iOff = int32(4)
|
|
}
|
|
if iOff < (*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist {
|
|
iOff = iOff + libc.Int32FromUint8(_sqlite3Fts5GetVarint(tls, (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp+uintptr(iOff), bp))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = int64(iOff)
|
|
v1 = pIter + 112
|
|
*(*Ti64)(unsafe.Pointer(v1)) = Ti64(uint64(*(*Ti64)(unsafe.Pointer(v1))) + **(**Tu64)(__ccgo_up(bp)))
|
|
} else {
|
|
if (*TFts5SegIter)(unsafe.Pointer(pIter)).Fflags&int32(FTS5_SEGITER_ONETERM) == 0 {
|
|
if (*TFts5SegIter)(unsafe.Pointer(pIter)).FpSeg != 0 {
|
|
**(**int32)(__ccgo_up(bp + 8)) = 0
|
|
if iOff != _fts5LeafFirstTermOff(tls, (*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf) {
|
|
iOff = iOff + _sqlite3Fts5GetVarint32(tls, (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp+uintptr(iOff), bp+8)
|
|
}
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = int64(iOff)
|
|
_fts5SegIterLoadTerm(tls, p, pIter, **(**int32)(__ccgo_up(bp + 8)))
|
|
} else {
|
|
**(**uintptr)(__ccgo_up(bp + 16)) = uintptr(0)
|
|
**(**uintptr)(__ccgo_up(bp + 24)) = uintptr(0)
|
|
**(**int32)(__ccgo_up(bp + 32)) = 0
|
|
_sqlite3Fts5HashScanNext(tls, (*TFts5Index)(unsafe.Pointer(p)).FpHash)
|
|
_sqlite3Fts5HashScanEntry(tls, (*TFts5Index)(unsafe.Pointer(p)).FpHash, bp+24, bp+32, bp+16, bp+36)
|
|
if **(**uintptr)(__ccgo_up(bp + 16)) == uintptr(0) {
|
|
goto next_none_eof
|
|
}
|
|
(*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp = **(**uintptr)(__ccgo_up(bp + 16))
|
|
(*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fnn = **(**int32)(__ccgo_up(bp + 36))
|
|
(*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).FszLeaf = **(**int32)(__ccgo_up(bp + 36))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist = **(**int32)(__ccgo_up(bp + 36))
|
|
_sqlite3Fts5BufferSet(tls, p+60, pIter+96, **(**int32)(__ccgo_up(bp + 32)), **(**uintptr)(__ccgo_up(bp + 24)))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = libc.Int64FromUint8(_sqlite3Fts5GetVarint(tls, **(**uintptr)(__ccgo_up(bp + 16)), pIter+112))
|
|
}
|
|
if pbNewTerm != 0 {
|
|
**(**int32)(__ccgo_up(pbNewTerm)) = int32(1)
|
|
}
|
|
} else {
|
|
goto next_none_eof
|
|
}
|
|
}
|
|
_fts5SegIterLoadNPos(tls, p, pIter)
|
|
return
|
|
goto next_none_eof
|
|
next_none_eof:
|
|
;
|
|
_fts5DataRelease(tls, (*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf = uintptr(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Iterator pIter currently points to the first rowid in a doclist. This
|
|
// ** function sets the iterator up so that iterates in reverse order through
|
|
// ** the doclist.
|
|
// */
|
|
func _fts5SegIterReverse(tls *libc.TLS, p uintptr, pIter uintptr) {
|
|
var bTermless, iEnd, iOff, iPoslist, iRowid, iSegid, pgno, pgnoLast, v1 int32
|
|
var iAbs Ti64
|
|
var pDlidx, pLast, pLeaf, pNew, pSeg, tmp uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = bTermless, iAbs, iEnd, iOff, iPoslist, iRowid, iSegid, pDlidx, pLast, pLeaf, pNew, pSeg, pgno, pgnoLast, tmp, v1
|
|
pDlidx = (*TFts5SegIter)(unsafe.Pointer(pIter)).FpDlidx
|
|
pLast = uintptr(0)
|
|
pgnoLast = 0
|
|
if pDlidx != 0 && (*TFts5Config)(unsafe.Pointer((*TFts5Index)(unsafe.Pointer(p)).FpConfig)).FiVersion == int32(FTS5_CURRENT_VERSION) {
|
|
iSegid = (*TFts5StructureSegment)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpSeg)).FiSegid
|
|
pgnoLast = _fts5DlidxIterPgno(tls, pDlidx)
|
|
pLast = _fts5LeafRead(tls, p, int64(iSegid)<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B)+libc.Int32FromInt32(FTS5_DATA_DLI_B))+int64(libc.Int32FromInt32(0))<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B))+int64(libc.Int32FromInt32(0))<<libc.Int32FromInt32(FTS5_DATA_PAGE_B)+int64(pgnoLast))
|
|
} else {
|
|
pLeaf = (*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf
|
|
if (*TFts5SegIter)(unsafe.Pointer(pIter)).FiTermLeafPgno == (*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafPgno {
|
|
iPoslist = (*TFts5SegIter)(unsafe.Pointer(pIter)).FiTermLeafOffset
|
|
} else {
|
|
iPoslist = int32(4)
|
|
}
|
|
iEnd = iPoslist + int32(9)
|
|
for {
|
|
v1 = iPoslist
|
|
iPoslist = iPoslist + 1
|
|
if !(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Data)(unsafe.Pointer(pLeaf)).Fp + uintptr(v1))))&int32(0x80) != 0 && iPoslist < iEnd) {
|
|
break
|
|
}
|
|
}
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = int64(iPoslist)
|
|
/* If this condition is true then the largest rowid for the current
|
|
** term may not be stored on the current page. So search forward to
|
|
** see where said rowid really is. */
|
|
if (*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist >= (*TFts5Data)(unsafe.Pointer(pLeaf)).FszLeaf {
|
|
pSeg = (*TFts5SegIter)(unsafe.Pointer(pIter)).FpSeg
|
|
/* The last rowid in the doclist may not be on the current page. Search
|
|
** forward to find the page containing the last rowid. */
|
|
pgno = (*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafPgno + int32(1)
|
|
for {
|
|
if !(!((*TFts5Index)(unsafe.Pointer(p)).Frc != 0) && pgno <= (*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FpgnoLast) {
|
|
break
|
|
}
|
|
iAbs = int64((*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FiSegid)<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B)+libc.Int32FromInt32(FTS5_DATA_DLI_B)) + int64(libc.Int32FromInt32(0))<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B)) + int64(libc.Int32FromInt32(0))<<libc.Int32FromInt32(FTS5_DATA_PAGE_B) + int64(pgno)
|
|
pNew = _fts5LeafRead(tls, p, iAbs)
|
|
if pNew != 0 {
|
|
iRowid = libc.Int32FromUint16(_fts5GetU16(tls, (*TFts5Data)(unsafe.Pointer(pNew)).Fp))
|
|
bTermless = libc.BoolInt32((*TFts5Data)(unsafe.Pointer(pNew)).FszLeaf >= (*TFts5Data)(unsafe.Pointer(pNew)).Fnn)
|
|
if iRowid != 0 {
|
|
tmp = pNew
|
|
pNew = pLast
|
|
pLast = tmp
|
|
pgnoLast = pgno
|
|
}
|
|
_fts5DataRelease(tls, pNew)
|
|
if bTermless == 0 {
|
|
break
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
pgno = pgno + 1
|
|
}
|
|
}
|
|
}
|
|
/* If pLast is NULL at this point, then the last rowid for this doclist
|
|
** lies on the page currently indicated by the iterator. In this case
|
|
** pIter->iLeafOffset is already set to point to the position-list size
|
|
** field associated with the first relevant rowid on the page.
|
|
**
|
|
** Or, if pLast is non-NULL, then it is the page that contains the last
|
|
** rowid. In this case configure the iterator so that it points to the
|
|
** first rowid on this page.
|
|
*/
|
|
if pLast != 0 {
|
|
_fts5DataRelease(tls, (*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf = pLast
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafPgno = pgnoLast
|
|
if (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
iOff = libc.Int32FromUint16(_fts5GetU16(tls, (*TFts5Data)(unsafe.Pointer(pLast)).Fp))
|
|
if iOff > (*TFts5Data)(unsafe.Pointer(pLast)).FszLeaf {
|
|
_fts5IndexCorruptIter(tls, p, pIter)
|
|
return
|
|
}
|
|
iOff = iOff + libc.Int32FromUint8(_sqlite3Fts5GetVarint(tls, (*TFts5Data)(unsafe.Pointer(pLast)).Fp+uintptr(iOff), pIter+112))
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = int64(iOff)
|
|
if (*TFts5Data)(unsafe.Pointer(pLast)).FszLeaf >= (*TFts5Data)(unsafe.Pointer(pLast)).Fnn {
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist = (*TFts5Data)(unsafe.Pointer(pLast)).Fnn + int32(1)
|
|
} else {
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist = _fts5LeafFirstTermOff(tls, pLast)
|
|
}
|
|
}
|
|
}
|
|
_fts5SegIterReverseInitPage(tls, p, pIter)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is only ever called on iterators created by calls to
|
|
// ** Fts5IndexQuery() with the FTS5INDEX_QUERY_DESC flag set.
|
|
// **
|
|
// ** The iterator is in an unusual state when this function is called: the
|
|
// ** Fts5SegIter.iLeafOffset variable is set to the offset of the start of
|
|
// ** the position-list size field for the first relevant rowid on the page.
|
|
// ** Fts5SegIter.rowid is set, but nPos and bDel are not.
|
|
// **
|
|
// ** This function advances the iterator so that it points to the last
|
|
// ** relevant rowid on the page and, if necessary, initializes the
|
|
// ** aRowidOffset[] and iRowidOffset variables. At this point the iterator
|
|
// ** is in its regular state - Fts5SegIter.iLeafOffset points to the first
|
|
// ** byte of the position list content associated with said rowid.
|
|
// */
|
|
func _fts5SegIterReverseInitPage(tls *libc.TLS, p uintptr, pIter uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var a, aNew, v1 uintptr
|
|
var eDetail, i, iRowidOffset, n, v2 int32
|
|
var nNew Ti64
|
|
var _ /* bDummy at bp+12 */ int32
|
|
var _ /* iDelta at bp+0 */ Tu64
|
|
var _ /* nPos at bp+8 */ int32
|
|
_, _, _, _, _, _, _, _, _ = a, aNew, eDetail, i, iRowidOffset, n, nNew, v1, v2
|
|
eDetail = (*TFts5Config)(unsafe.Pointer((*TFts5Index)(unsafe.Pointer(p)).FpConfig)).FeDetail
|
|
n = (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).FszLeaf
|
|
i = int32((*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset)
|
|
a = (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp
|
|
iRowidOffset = 0
|
|
if n > (*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist {
|
|
n = (*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist
|
|
}
|
|
for int32(1) != 0 {
|
|
**(**Tu64)(__ccgo_up(bp)) = uint64(0)
|
|
if i >= n {
|
|
break
|
|
}
|
|
if eDetail == int32(FTS5_DETAIL_NONE) {
|
|
/* todo */
|
|
if i < n && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(a + uintptr(i)))) == 0 {
|
|
i = i + 1
|
|
if i < n && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(a + uintptr(i)))) == 0 {
|
|
i = i + 1
|
|
}
|
|
}
|
|
} else {
|
|
i = i + _fts5GetPoslistSize(tls, a+uintptr(i), bp+8, bp+12)
|
|
i = i + **(**int32)(__ccgo_up(bp + 8))
|
|
}
|
|
if i >= n {
|
|
break
|
|
}
|
|
i = i + libc.Int32FromUint8(_sqlite3Fts5GetVarint(tls, a+uintptr(i), bp))
|
|
v1 = pIter + 112
|
|
*(*Ti64)(unsafe.Pointer(v1)) = Ti64(uint64(*(*Ti64)(unsafe.Pointer(v1))) + **(**Tu64)(__ccgo_up(bp)))
|
|
/* If necessary, grow the pIter->aRowidOffset[] array. */
|
|
if iRowidOffset >= (*TFts5SegIter)(unsafe.Pointer(pIter)).FnRowidOffset {
|
|
nNew = int64((*TFts5SegIter)(unsafe.Pointer(pIter)).FnRowidOffset + int32(8))
|
|
aNew = Xsqlite3_realloc64(tls, (*TFts5SegIter)(unsafe.Pointer(pIter)).FaRowidOffset, libc.Uint64FromInt64(nNew)*uint64(4))
|
|
if aNew == uintptr(0) {
|
|
(*TFts5Index)(unsafe.Pointer(p)).Frc = int32(SQLITE_NOMEM)
|
|
break
|
|
}
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FaRowidOffset = aNew
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FnRowidOffset = int32(nNew)
|
|
}
|
|
v2 = iRowidOffset
|
|
iRowidOffset = iRowidOffset + 1
|
|
**(**int32)(__ccgo_up((*TFts5SegIter)(unsafe.Pointer(pIter)).FaRowidOffset + uintptr(v2)*4)) = int32((*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset)
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = int64(i)
|
|
}
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiRowidOffset = iRowidOffset
|
|
_fts5SegIterLoadNPos(tls, p, pIter)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// **
|
|
// */
|
|
func _fts5SegIterReverseNewPage(tls *libc.TLS, p uintptr, pIter uintptr) {
|
|
var a, pNew uintptr
|
|
var iRowidOff int32
|
|
_, _, _ = a, iRowidOff, pNew
|
|
_fts5DataRelease(tls, (*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf = uintptr(0)
|
|
for (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK && (*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafPgno > (*TFts5SegIter)(unsafe.Pointer(pIter)).FiTermLeafPgno {
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafPgno = (*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafPgno - 1
|
|
pNew = _fts5LeafRead(tls, p, int64((*TFts5StructureSegment)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpSeg)).FiSegid)<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B)+libc.Int32FromInt32(FTS5_DATA_DLI_B))+int64(libc.Int32FromInt32(0))<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B))+int64(libc.Int32FromInt32(0))<<libc.Int32FromInt32(FTS5_DATA_PAGE_B)+int64((*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafPgno))
|
|
if pNew != 0 {
|
|
/* iTermLeafOffset may be equal to szLeaf if the term is the last
|
|
** thing on the page - i.e. the first rowid is on the following page.
|
|
** In this case leave pIter->pLeaf==0, this iterator is at EOF. */
|
|
if (*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafPgno == (*TFts5SegIter)(unsafe.Pointer(pIter)).FiTermLeafPgno {
|
|
if (*TFts5SegIter)(unsafe.Pointer(pIter)).FiTermLeafOffset < (*TFts5Data)(unsafe.Pointer(pNew)).FszLeaf {
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf = pNew
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = int64((*TFts5SegIter)(unsafe.Pointer(pIter)).FiTermLeafOffset)
|
|
}
|
|
} else {
|
|
iRowidOff = libc.Int32FromUint16(_fts5GetU16(tls, (*TFts5Data)(unsafe.Pointer(pNew)).Fp))
|
|
if iRowidOff != 0 {
|
|
if iRowidOff >= (*TFts5Data)(unsafe.Pointer(pNew)).FszLeaf {
|
|
_fts5IndexCorruptIter(tls, p, pIter)
|
|
} else {
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf = pNew
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset = int64(iRowidOff)
|
|
}
|
|
}
|
|
}
|
|
if (*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf != 0 {
|
|
a = (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fp + uintptr((*TFts5SegIter)(unsafe.Pointer(pIter)).FiLeafOffset)
|
|
**(**Ti64)(__ccgo_up(pIter + 32)) += libc.Int64FromUint8(_sqlite3Fts5GetVarint(tls, a, pIter+112))
|
|
break
|
|
} else {
|
|
_fts5DataRelease(tls, pNew)
|
|
}
|
|
}
|
|
}
|
|
if (*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf != 0 {
|
|
(*TFts5SegIter)(unsafe.Pointer(pIter)).FiEndofDoclist = (*TFts5Data)(unsafe.Pointer((*TFts5SegIter)(unsafe.Pointer(pIter)).FpLeaf)).Fnn + int32(1)
|
|
_fts5SegIterReverseInitPage(tls, p, pIter)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add an entry to the Fts5SFinder.aFirst[] array. Grow the array if
|
|
// ** necessary. Return SQLITE_OK if successful, or SQLITE_NOMEM if an
|
|
// ** error occurs.
|
|
// */
|
|
func _fts5SentenceFinderAdd(tls *libc.TLS, p uintptr, iAdd int32) (r int32) {
|
|
var aNew, v3 uintptr
|
|
var nNew, v1 int32
|
|
_, _, _, _ = aNew, nNew, v1, v3
|
|
if (*TFts5SFinder)(unsafe.Pointer(p)).FnFirstAlloc == (*TFts5SFinder)(unsafe.Pointer(p)).FnFirst {
|
|
if (*TFts5SFinder)(unsafe.Pointer(p)).FnFirstAlloc != 0 {
|
|
v1 = (*TFts5SFinder)(unsafe.Pointer(p)).FnFirstAlloc * int32(2)
|
|
} else {
|
|
v1 = int32(64)
|
|
}
|
|
nNew = v1
|
|
aNew = Xsqlite3_realloc64(tls, (*TFts5SFinder)(unsafe.Pointer(p)).FaFirst, uint64(libc.Uint64FromInt32(nNew)*uint64(4)))
|
|
if aNew == uintptr(0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
(*TFts5SFinder)(unsafe.Pointer(p)).FaFirst = aNew
|
|
(*TFts5SFinder)(unsafe.Pointer(p)).FnFirstAlloc = nNew
|
|
}
|
|
v3 = p + 8
|
|
v1 = *(*int32)(unsafe.Pointer(v3))
|
|
*(*int32)(unsafe.Pointer(v3)) = *(*int32)(unsafe.Pointer(v3)) + 1
|
|
**(**int32)(__ccgo_up((*TFts5SFinder)(unsafe.Pointer(p)).FaFirst + uintptr(v1)*4)) = iAdd
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If a row with rowid iDel is present in the %_content table, add the
|
|
// ** delete-markers to the FTS index necessary to delete it. Do not actually
|
|
// ** remove the %_content row at this time though.
|
|
// **
|
|
// ** If parameter bSaveRow is true, then Fts5Storage.pSavedRow is left
|
|
// ** pointing to a statement (FTS5_STMT_LOOKUP2) that may be used to access
|
|
// ** the original values of the row being deleted. This is used by UPDATE
|
|
// ** statements.
|
|
// */
|
|
func _fts5StorageDeleteFromIndex(tls *libc.TLS, p uintptr, iDel Ti64, apVal uintptr, bSaveRow int32) (r int32) {
|
|
bp := tls.Alloc(64)
|
|
defer tls.Free(64)
|
|
var iCol, rc, rc2 int32
|
|
var pConfig, pFree, pVal, v2 uintptr
|
|
var _ /* ctx at bp+8 */ TFts5InsertCtx
|
|
var _ /* nLoc at bp+48 */ int32
|
|
var _ /* nText at bp+32 */ int32
|
|
var _ /* pLoc at bp+40 */ uintptr
|
|
var _ /* pSeek at bp+0 */ uintptr
|
|
var _ /* pText at bp+24 */ uintptr
|
|
_, _, _, _, _, _, _ = iCol, pConfig, pFree, pVal, rc, rc2, v2
|
|
pConfig = (*TFts5Storage)(unsafe.Pointer(p)).FpConfig
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0) /* SELECT to read row iDel from %_data */
|
|
rc = SQLITE_OK
|
|
if apVal == uintptr(0) {
|
|
if (*TFts5Storage)(unsafe.Pointer(p)).FpSavedRow != 0 && bSaveRow != 0 {
|
|
**(**uintptr)(__ccgo_up(bp)) = (*TFts5Storage)(unsafe.Pointer(p)).FpSavedRow
|
|
(*TFts5Storage)(unsafe.Pointer(p)).FpSavedRow = uintptr(0)
|
|
} else {
|
|
rc = _fts5StorageGetStmt(tls, p, int32(FTS5_STMT_LOOKUP)+bSaveRow, bp, uintptr(0))
|
|
if rc != SQLITE_OK {
|
|
return rc
|
|
}
|
|
Xsqlite3_bind_int64(tls, **(**uintptr)(__ccgo_up(bp)), int32(1), iDel)
|
|
if Xsqlite3_step(tls, **(**uintptr)(__ccgo_up(bp))) != int32(SQLITE_ROW) {
|
|
return Xsqlite3_reset(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
}
|
|
}
|
|
}
|
|
(**(**TFts5InsertCtx)(__ccgo_up(bp + 8))).FpStorage = p
|
|
(**(**TFts5InsertCtx)(__ccgo_up(bp + 8))).FiCol = -int32(1)
|
|
iCol = int32(1)
|
|
for {
|
|
if !(rc == SQLITE_OK && iCol <= (*TFts5Config)(unsafe.Pointer(pConfig)).FnCol) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Config)(unsafe.Pointer(pConfig)).FabUnindexed + uintptr(iCol-int32(1))))) == 0 {
|
|
pVal = uintptr(0)
|
|
pFree = uintptr(0)
|
|
**(**uintptr)(__ccgo_up(bp + 24)) = uintptr(0)
|
|
**(**int32)(__ccgo_up(bp + 32)) = 0
|
|
**(**uintptr)(__ccgo_up(bp + 40)) = uintptr(0)
|
|
**(**int32)(__ccgo_up(bp + 48)) = 0
|
|
if **(**uintptr)(__ccgo_up(bp)) != 0 {
|
|
pVal = Xsqlite3_column_value(tls, **(**uintptr)(__ccgo_up(bp)), iCol)
|
|
} else {
|
|
pVal = **(**uintptr)(__ccgo_up(apVal + uintptr(iCol-int32(1))*8))
|
|
}
|
|
if (*TFts5Config)(unsafe.Pointer(pConfig)).FbLocale != 0 && _sqlite3Fts5IsLocaleValue(tls, pConfig, pVal) != 0 {
|
|
rc = _sqlite3Fts5DecodeLocaleValue(tls, pVal, bp+24, bp+32, bp+40, bp+48)
|
|
} else {
|
|
if Xsqlite3_value_type(tls, pVal) != int32(SQLITE_TEXT) {
|
|
/* Make a copy of the value to work with. This is because the call
|
|
** to sqlite3_value_text() below forces the type of the value to
|
|
** SQLITE_TEXT, and we may need to use it again later. */
|
|
v2 = Xsqlite3_value_dup(tls, pVal)
|
|
pVal = v2
|
|
pFree = v2
|
|
if pVal == uintptr(0) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
}
|
|
}
|
|
if rc == SQLITE_OK {
|
|
**(**uintptr)(__ccgo_up(bp + 24)) = Xsqlite3_value_text(tls, pVal)
|
|
**(**int32)(__ccgo_up(bp + 32)) = Xsqlite3_value_bytes(tls, pVal)
|
|
if (*TFts5Config)(unsafe.Pointer(pConfig)).FbLocale != 0 && **(**uintptr)(__ccgo_up(bp)) != 0 {
|
|
**(**uintptr)(__ccgo_up(bp + 40)) = Xsqlite3_column_text(tls, **(**uintptr)(__ccgo_up(bp)), iCol+(*TFts5Config)(unsafe.Pointer(pConfig)).FnCol)
|
|
**(**int32)(__ccgo_up(bp + 48)) = Xsqlite3_column_bytes(tls, **(**uintptr)(__ccgo_up(bp)), iCol+(*TFts5Config)(unsafe.Pointer(pConfig)).FnCol)
|
|
}
|
|
}
|
|
}
|
|
if rc == SQLITE_OK {
|
|
_sqlite3Fts5SetLocale(tls, pConfig, **(**uintptr)(__ccgo_up(bp + 40)), **(**int32)(__ccgo_up(bp + 48)))
|
|
(**(**TFts5InsertCtx)(__ccgo_up(bp + 8))).FszCol = 0
|
|
rc = _sqlite3Fts5Tokenize(tls, pConfig, int32(FTS5_TOKENIZE_DOCUMENT), **(**uintptr)(__ccgo_up(bp + 24)), **(**int32)(__ccgo_up(bp + 32)), bp+8, __ccgo_fp(_fts5StorageInsertCallback))
|
|
**(**Ti64)(__ccgo_up((*TFts5Storage)(unsafe.Pointer(p)).FaTotalSize + uintptr(iCol-int32(1))*8)) -= int64((**(**TFts5InsertCtx)(__ccgo_up(bp + 8))).FszCol)
|
|
if rc == SQLITE_OK && **(**Ti64)(__ccgo_up((*TFts5Storage)(unsafe.Pointer(p)).FaTotalSize + uintptr(iCol-int32(1))*8)) < 0 {
|
|
rc = libc.Int32FromInt32(SQLITE_CORRUPT) | libc.Int32FromInt32(1)<<libc.Int32FromInt32(8)
|
|
}
|
|
_sqlite3Fts5ClearLocale(tls, pConfig)
|
|
}
|
|
Xsqlite3_value_free(tls, pFree)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
iCol = iCol + 1
|
|
}
|
|
if rc == SQLITE_OK && (*TFts5Storage)(unsafe.Pointer(p)).FnTotalRow < int64(1) {
|
|
rc = libc.Int32FromInt32(SQLITE_CORRUPT) | libc.Int32FromInt32(1)<<libc.Int32FromInt32(8)
|
|
} else {
|
|
(*TFts5Storage)(unsafe.Pointer(p)).FnTotalRow = (*TFts5Storage)(unsafe.Pointer(p)).FnTotalRow - 1
|
|
}
|
|
if rc == SQLITE_OK && bSaveRow != 0 {
|
|
(*TFts5Storage)(unsafe.Pointer(p)).FpSavedRow = **(**uintptr)(__ccgo_up(bp))
|
|
} else {
|
|
rc2 = Xsqlite3_reset(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
if rc == SQLITE_OK {
|
|
rc = rc2
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Append a mapping to the token-map belonging to object pT.
|
|
// */
|
|
func _fts5TokendataIterAppendMap(tls *libc.TLS, p uintptr, pT uintptr, iIter int32, nByte int32, iRowid Ti64, iPos Ti64) {
|
|
var aNew uintptr
|
|
var nAlloc, nNew Ti64
|
|
var v1 int64
|
|
_, _, _, _ = aNew, nAlloc, nNew, v1
|
|
if (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
if (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMap == (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMapAlloc {
|
|
if (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMapAlloc != 0 {
|
|
v1 = (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMapAlloc * int64(2)
|
|
} else {
|
|
v1 = int64(64)
|
|
}
|
|
nNew = v1
|
|
nAlloc = libc.Int64FromUint64(libc.Uint64FromInt64(nNew) * uint64(24))
|
|
aNew = Xsqlite3_realloc64(tls, (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaMap, libc.Uint64FromInt64(nAlloc))
|
|
if aNew == uintptr(0) {
|
|
(*TFts5Index)(unsafe.Pointer(p)).Frc = int32(SQLITE_NOMEM)
|
|
return
|
|
}
|
|
(*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaMap = aNew
|
|
(*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMapAlloc = nNew
|
|
}
|
|
(**(**TFts5TokenDataMap)(__ccgo_up((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaMap + uintptr((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMap)*24))).FiRowid = iRowid
|
|
(**(**TFts5TokenDataMap)(__ccgo_up((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaMap + uintptr((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMap)*24))).FiPos = iPos
|
|
(**(**TFts5TokenDataMap)(__ccgo_up((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaMap + uintptr((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMap)*24))).FiIter = iIter
|
|
(**(**TFts5TokenDataMap)(__ccgo_up((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FaMap + uintptr((*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMap)*24))).FnByte = nByte
|
|
(*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMap = (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnMap + 1
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The iterator passed as the only argument must be a tokendata=1 iterator
|
|
// ** (pIter->pTokenDataIter!=0). This function advances the iterator. If
|
|
// ** argument bFrom is false, then the iterator is advanced to the next
|
|
// ** entry. Or, if bFrom is true, it is advanced to the first entry with
|
|
// ** a rowid of iFrom or greater.
|
|
// */
|
|
func _fts5TokendataIterNext(tls *libc.TLS, pIter uintptr, bFrom int32, iFrom Ti64) {
|
|
var ii int32
|
|
var p, pIndex, pT uintptr
|
|
_, _, _, _ = ii, p, pIndex, pT
|
|
pT = (*TFts5Iter)(unsafe.Pointer(pIter)).FpTokenDataIter
|
|
pIndex = (*TFts5Iter)(unsafe.Pointer(pIter)).FpIndex
|
|
ii = 0
|
|
for {
|
|
if !(int64(ii) < (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnIter) {
|
|
break
|
|
}
|
|
p = *(*uintptr)(unsafe.Pointer(pT + 72 + uintptr(ii)*8))
|
|
if libc.Int32FromUint8((*TFts5Iter)(unsafe.Pointer(p)).Fbase.FbEof) == 0 && ((*TFts5Iter)(unsafe.Pointer(p)).Fbase.FiRowid == (*TFts5Iter)(unsafe.Pointer(pIter)).Fbase.FiRowid || bFrom != 0 && (*TFts5Iter)(unsafe.Pointer(p)).Fbase.FiRowid < iFrom) {
|
|
_fts5MultiIterNext(tls, pIndex, p, bFrom, iFrom)
|
|
for bFrom != 0 && libc.Int32FromUint8((*TFts5Iter)(unsafe.Pointer(p)).Fbase.FbEof) == 0 && (*TFts5Iter)(unsafe.Pointer(p)).Fbase.FiRowid < iFrom && (*TFts5Index)(unsafe.Pointer(pIndex)).Frc == SQLITE_OK {
|
|
_fts5MultiIterNext(tls, pIndex, p, 0, 0)
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
if (*TFts5Index)(unsafe.Pointer(pIndex)).Frc == SQLITE_OK {
|
|
_fts5IterSetOutputsTokendata(tls, pIter)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if, for the purposes of tokenizing with the tokenizer
|
|
// ** passed as the first argument, codepoint iCode is considered a token
|
|
// ** character (not a separator).
|
|
// */
|
|
func _fts5UnicodeIsAlnum(tls *libc.TLS, p uintptr, iCode int32) (r int32) {
|
|
return libc.Int32FromUint8(**(**uint8)(__ccgo_up(p + 160 + uintptr(_sqlite3Fts5UnicodeCategory(tls, libc.Uint32FromInt32(iCode)))))) ^ _fts5UnicodeIsException(tls, p, iCode)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Iterate through a range of entries in the FTS index, invoking the xVisit
|
|
// ** callback for each of them.
|
|
// **
|
|
// ** Parameter pToken points to an nToken buffer containing an FTS index term
|
|
// ** (i.e. a document term with the preceding 1 byte index identifier -
|
|
// ** FTS5_MAIN_PREFIX or similar). If bPrefix is true, then the call visits
|
|
// ** all entries for terms that have pToken/nToken as a prefix. If bPrefix
|
|
// ** is false, then only entries with pToken/nToken as the entire key are
|
|
// ** visited.
|
|
// **
|
|
// ** If the current table is a tokendata=1 table, then if bPrefix is true then
|
|
// ** each index term is treated separately. However, if bPrefix is false, then
|
|
// ** all index terms corresponding to pToken/nToken are collapsed into a single
|
|
// ** term before the callback is invoked.
|
|
// **
|
|
// ** The callback invoked for each entry visited is specified by paramter xVisit.
|
|
// ** Each time it is invoked, it is passed a pointer to the Fts5Index object,
|
|
// ** a copy of the 7th paramter to this function (pCtx) and a pointer to the
|
|
// ** iterator that indicates the current entry. If the current entry is the
|
|
// ** first with a new term (i.e. different from that of the previous entry,
|
|
// ** including the very first term), then the final two parameters are passed
|
|
// ** a pointer to the term and its size in bytes, respectively. If the current
|
|
// ** entry is not the first associated with its term, these two parameters
|
|
// ** are passed 0.
|
|
// **
|
|
// ** If parameter pColset is not NULL, then it is used to filter entries before
|
|
// ** the callback is invoked.
|
|
// */
|
|
func _fts5VisitEntries(tls *libc.TLS, p uintptr, pColset uintptr, pToken uintptr, nToken int32, bPrefix int32, __ccgo_fp_xVisit uintptr, pCtx uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var flags, nNew, v1 int32
|
|
var pNew, pSeg, pStruct uintptr
|
|
var _ /* bNewTerm at bp+8 */ int32
|
|
var _ /* p1 at bp+0 */ uintptr
|
|
_, _, _, _, _, _ = flags, nNew, pNew, pSeg, pStruct, v1
|
|
if bPrefix != 0 {
|
|
v1 = int32(FTS5INDEX_QUERY_SCAN)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
flags = v1 | int32(FTS5INDEX_QUERY_SKIPEMPTY) | int32(FTS5INDEX_QUERY_NOOUTPUT)
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0) /* Iterator used to gather data from index */
|
|
**(**int32)(__ccgo_up(bp + 8)) = int32(1)
|
|
pStruct = _fts5StructureRead(tls, p)
|
|
_fts5MultiIterNew(tls, p, pStruct, flags, pColset, pToken, nToken, -int32(1), 0, bp)
|
|
_fts5IterSetOutputCb(tls, p+60, **(**uintptr)(__ccgo_up(bp)))
|
|
for {
|
|
if !(_fts5MultiIterEof(tls, p, **(**uintptr)(__ccgo_up(bp))) == 0) {
|
|
break
|
|
}
|
|
pSeg = **(**uintptr)(__ccgo_up(bp)) + 104 + uintptr((**(**TFts5CResult)(__ccgo_up((*TFts5Iter)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FaFirst + 1*4))).FiFirst)*128
|
|
nNew = 0
|
|
pNew = uintptr(0)
|
|
(*(*func(*libc.TLS, uintptr, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TFts5Iter)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FxSetOutputs})))(tls, **(**uintptr)(__ccgo_up(bp)), pSeg)
|
|
if (*TFts5Index)(unsafe.Pointer(p)).Frc != 0 {
|
|
break
|
|
}
|
|
if **(**int32)(__ccgo_up(bp + 8)) != 0 {
|
|
nNew = (*TFts5SegIter)(unsafe.Pointer(pSeg)).Fterm.Fn
|
|
pNew = (*TFts5SegIter)(unsafe.Pointer(pSeg)).Fterm.Fp
|
|
if nNew < nToken || libc.Xmemcmp(tls, pToken, pNew, libc.Uint64FromInt32(nToken)) != 0 {
|
|
break
|
|
}
|
|
}
|
|
(*(*func(*libc.TLS, uintptr, uintptr, uintptr, uintptr, int32))(unsafe.Pointer(&struct{ uintptr }{__ccgo_fp_xVisit})))(tls, p, pCtx, **(**uintptr)(__ccgo_up(bp)), pNew, nNew)
|
|
goto _2
|
|
_2:
|
|
;
|
|
_fts5MultiIterNext2(tls, p, **(**uintptr)(__ccgo_up(bp)), bp+8)
|
|
}
|
|
_fts5MultiIterFree(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
_fts5StructureRelease(tls, pStruct)
|
|
return (*TFts5Index)(unsafe.Pointer(p)).Frc
|
|
}
|
|
|
|
/* Size in bytes of an Fts5TokenDataIter object holding up to N iterators */
|
|
|
|
func _fts5VocabInstanceNewTerm(tls *libc.TLS, pCsr uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var bCmp, nCmp, v1 int32
|
|
var zTerm uintptr
|
|
var _ /* nTerm at bp+4 */ int32
|
|
var _ /* rc at bp+0 */ int32
|
|
_, _, _, _ = bCmp, nCmp, zTerm, v1
|
|
**(**int32)(__ccgo_up(bp)) = SQLITE_OK
|
|
if (*TFts5IndexIter)(unsafe.Pointer((*TFts5VocabCursor)(unsafe.Pointer(pCsr)).FpIter)).FbEof != 0 {
|
|
(*TFts5VocabCursor)(unsafe.Pointer(pCsr)).FbEof = int32(1)
|
|
} else {
|
|
zTerm = _sqlite3Fts5IterTerm(tls, (*TFts5VocabCursor)(unsafe.Pointer(pCsr)).FpIter, bp+4)
|
|
if (*TFts5VocabCursor)(unsafe.Pointer(pCsr)).FnLeTerm >= 0 {
|
|
if **(**int32)(__ccgo_up(bp + 4)) < (*TFts5VocabCursor)(unsafe.Pointer(pCsr)).FnLeTerm {
|
|
v1 = **(**int32)(__ccgo_up(bp + 4))
|
|
} else {
|
|
v1 = (*TFts5VocabCursor)(unsafe.Pointer(pCsr)).FnLeTerm
|
|
}
|
|
nCmp = v1
|
|
bCmp = libc.Xmemcmp(tls, (*TFts5VocabCursor)(unsafe.Pointer(pCsr)).FzLeTerm, zTerm, libc.Uint64FromInt32(nCmp))
|
|
if bCmp < 0 || bCmp == 0 && (*TFts5VocabCursor)(unsafe.Pointer(pCsr)).FnLeTerm < **(**int32)(__ccgo_up(bp + 4)) {
|
|
(*TFts5VocabCursor)(unsafe.Pointer(pCsr)).FbEof = int32(1)
|
|
}
|
|
}
|
|
_sqlite3Fts5BufferSet(tls, bp, pCsr+96, **(**int32)(__ccgo_up(bp + 4)), zTerm)
|
|
}
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
|
|
func _fts5WriteAppendPoslistData(tls *libc.TLS, p uintptr, pWriter uintptr, aData uintptr, nData int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var a, pPage uintptr
|
|
var n, nCopy, nReq int32
|
|
var _ /* dummy at bp+0 */ Ti64
|
|
_, _, _, _, _ = a, n, nCopy, nReq, pPage
|
|
pPage = pWriter + 8
|
|
a = aData
|
|
n = nData
|
|
for (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK && (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fbuf.Fn+(*TFts5PageWriter)(unsafe.Pointer(pPage)).Fpgidx.Fn+n >= (*TFts5Config)(unsafe.Pointer((*TFts5Index)(unsafe.Pointer(p)).FpConfig)).Fpgsz {
|
|
nReq = (*TFts5Config)(unsafe.Pointer((*TFts5Index)(unsafe.Pointer(p)).FpConfig)).Fpgsz - (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fbuf.Fn - (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fpgidx.Fn
|
|
nCopy = 0
|
|
for nCopy < nReq {
|
|
nCopy = nCopy + libc.Int32FromUint8(_sqlite3Fts5GetVarint(tls, a+uintptr(nCopy), bp))
|
|
}
|
|
_sqlite3Fts5BufferAppendBlob(tls, p+60, pPage+8, libc.Uint32FromInt32(nCopy), a)
|
|
a = a + uintptr(nCopy)
|
|
n = n - nCopy
|
|
_fts5WriteFlushLeaf(tls, p, pWriter)
|
|
}
|
|
if n > 0 {
|
|
_sqlite3Fts5BufferAppendBlob(tls, p+60, pPage+8, libc.Uint32FromInt32(n), a)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Append a rowid and position-list size field to the writers output.
|
|
// */
|
|
func _fts5WriteAppendRowid(tls *libc.TLS, p uintptr, pWriter uintptr, iRowid Ti64) {
|
|
var pPage uintptr
|
|
_ = pPage
|
|
if (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
pPage = pWriter + 8
|
|
if (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fbuf.Fn+(*TFts5PageWriter)(unsafe.Pointer(pPage)).Fpgidx.Fn >= (*TFts5Config)(unsafe.Pointer((*TFts5Index)(unsafe.Pointer(p)).FpConfig)).Fpgsz {
|
|
_fts5WriteFlushLeaf(tls, p, pWriter)
|
|
}
|
|
/* If this is to be the first rowid written to the page, set the
|
|
** rowid-pointer in the page-header. Also append a value to the dlidx
|
|
** buffer, in case a doclist-index is required. */
|
|
if (*TFts5SegWriter)(unsafe.Pointer(pWriter)).FbFirstRowidInPage != 0 {
|
|
_fts5PutU16(tls, (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fbuf.Fp, libc.Uint16FromInt32((*TFts5PageWriter)(unsafe.Pointer(pPage)).Fbuf.Fn))
|
|
_fts5WriteDlidxAppend(tls, p, pWriter, iRowid)
|
|
}
|
|
/* Write the rowid. */
|
|
if (*TFts5SegWriter)(unsafe.Pointer(pWriter)).FbFirstRowidInDoclist != 0 || (*TFts5SegWriter)(unsafe.Pointer(pWriter)).FbFirstRowidInPage != 0 {
|
|
_sqlite3Fts5BufferAppendVarint(tls, p+60, pPage+8, iRowid)
|
|
} else {
|
|
_sqlite3Fts5BufferAppendVarint(tls, p+60, pPage+8, libc.Int64FromUint64(libc.Uint64FromInt64(libc.Int64FromUint64(libc.Uint64FromInt64(iRowid)))-libc.Uint64FromInt64((*TFts5SegWriter)(unsafe.Pointer(pWriter)).FiPrevRowid)))
|
|
}
|
|
(*TFts5SegWriter)(unsafe.Pointer(pWriter)).FiPrevRowid = iRowid
|
|
(*TFts5SegWriter)(unsafe.Pointer(pWriter)).FbFirstRowidInDoclist = uint8(0)
|
|
(*TFts5SegWriter)(unsafe.Pointer(pWriter)).FbFirstRowidInPage = uint8(0)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Append term pTerm/nTerm to the segment being written by the writer passed
|
|
// ** as the second argument.
|
|
// **
|
|
// ** If an error occurs, set the Fts5Index.rc error code. If an error has
|
|
// ** already occurred, this function is a no-op.
|
|
// */
|
|
func _fts5WriteAppendTerm(tls *libc.TLS, p uintptr, pWriter uintptr, nTerm int32, pTerm uintptr) {
|
|
var n, nMin, nPrefix, v1 int32
|
|
var pPage, pPgidx uintptr
|
|
_, _, _, _, _, _ = n, nMin, nPrefix, pPage, pPgidx, v1 /* Bytes of prefix compression for term */
|
|
pPage = pWriter + 8
|
|
pPgidx = pWriter + 8 + 24
|
|
if (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fterm.Fn < nTerm {
|
|
v1 = (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fterm.Fn
|
|
} else {
|
|
v1 = nTerm
|
|
}
|
|
nMin = v1
|
|
/* If the current leaf page is full, flush it to disk. */
|
|
if (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fbuf.Fn+(*TFts5Buffer)(unsafe.Pointer(pPgidx)).Fn+nTerm+int32(2) >= (*TFts5Config)(unsafe.Pointer((*TFts5Index)(unsafe.Pointer(p)).FpConfig)).Fpgsz {
|
|
if (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fbuf.Fn > int32(4) {
|
|
_fts5WriteFlushLeaf(tls, p, pWriter)
|
|
if (*TFts5Index)(unsafe.Pointer(p)).Frc != SQLITE_OK {
|
|
return
|
|
}
|
|
}
|
|
if !(libc.Uint32FromInt32((*TFts5Buffer)(unsafe.Pointer(pPage+8)).Fn)+libc.Uint32FromInt32(nTerm+libc.Int32FromInt32(FTS5_DATA_PADDING)) <= libc.Uint32FromInt32((*TFts5Buffer)(unsafe.Pointer(pPage+8)).FnSpace)) {
|
|
_sqlite3Fts5BufferSize(tls, p+60, pPage+8, libc.Uint32FromInt32(nTerm+int32(FTS5_DATA_PADDING)+(*TFts5Buffer)(unsafe.Pointer(pPage+8)).Fn))
|
|
}
|
|
}
|
|
/* TODO1: Updating pgidx here. */
|
|
**(**int32)(__ccgo_up(pPgidx + 8)) += _sqlite3Fts5PutVarint(tls, (*TFts5Buffer)(unsafe.Pointer(pPgidx)).Fp+uintptr((*TFts5Buffer)(unsafe.Pointer(pPgidx)).Fn), libc.Uint64FromInt32((*TFts5PageWriter)(unsafe.Pointer(pPage)).Fbuf.Fn-(*TFts5PageWriter)(unsafe.Pointer(pPage)).FiPrevPgidx))
|
|
(*TFts5PageWriter)(unsafe.Pointer(pPage)).FiPrevPgidx = (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fbuf.Fn
|
|
if (*TFts5SegWriter)(unsafe.Pointer(pWriter)).FbFirstTermInPage != 0 {
|
|
nPrefix = 0
|
|
if (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fpgno != int32(1) {
|
|
/* This is the first term on a leaf that is not the leftmost leaf in
|
|
** the segment b-tree. In this case it is necessary to add a term to
|
|
** the b-tree hierarchy that is (a) larger than the largest term
|
|
** already written to the segment and (b) smaller than or equal to
|
|
** this term. In other words, a prefix of (pTerm/nTerm) that is one
|
|
** byte longer than the longest prefix (pTerm/nTerm) shares with the
|
|
** previous term.
|
|
**
|
|
** Usually, the previous term is available in pPage->term. The exception
|
|
** is if this is the first term written in an incremental-merge step.
|
|
** In this case the previous term is not available, so just write a
|
|
** copy of (pTerm/nTerm) into the parent node. This is slightly
|
|
** inefficient, but still correct. */
|
|
n = nTerm
|
|
if (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fterm.Fn != 0 {
|
|
n = int32(1) + _fts5PrefixCompress(tls, nMin, (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fterm.Fp, pTerm)
|
|
}
|
|
_fts5WriteBtreeTerm(tls, p, pWriter, n, pTerm)
|
|
if (*TFts5Index)(unsafe.Pointer(p)).Frc != SQLITE_OK {
|
|
return
|
|
}
|
|
pPage = pWriter + 8
|
|
}
|
|
} else {
|
|
nPrefix = _fts5PrefixCompress(tls, nMin, (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fterm.Fp, pTerm)
|
|
_sqlite3Fts5BufferAppendVarint(tls, p+60, pPage+8, int64(nPrefix))
|
|
}
|
|
/* Append the number of bytes of new data, then the term data itself
|
|
** to the page. */
|
|
_sqlite3Fts5BufferAppendVarint(tls, p+60, pPage+8, int64(nTerm)-int64(nPrefix))
|
|
_sqlite3Fts5BufferAppendBlob(tls, p+60, pPage+8, libc.Uint32FromInt32(nTerm-nPrefix), pTerm+uintptr(nPrefix))
|
|
/* Update the Fts5PageWriter.term field. */
|
|
_sqlite3Fts5BufferSet(tls, p+60, pPage+40, nTerm, pTerm)
|
|
(*TFts5SegWriter)(unsafe.Pointer(pWriter)).FbFirstTermInPage = uint8(0)
|
|
(*TFts5SegWriter)(unsafe.Pointer(pWriter)).FbFirstRowidInPage = uint8(0)
|
|
(*TFts5SegWriter)(unsafe.Pointer(pWriter)).FbFirstRowidInDoclist = uint8(1)
|
|
(**(**TFts5DlidxWriter)(__ccgo_up((*TFts5SegWriter)(unsafe.Pointer(pWriter)).FaDlidx))).Fpgno = (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fpgno
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Rowid iRowid has just been appended to the current leaf page. It is the
|
|
// ** first on the page. This function appends an appropriate entry to the current
|
|
// ** doclist-index.
|
|
// */
|
|
func _fts5WriteDlidxAppend(tls *libc.TLS, p uintptr, pWriter uintptr, iRowid Ti64) {
|
|
var bDone, i, v2 int32
|
|
var iFirst, iPgno, iVal Ti64
|
|
var pDlidx uintptr
|
|
_, _, _, _, _, _, _ = bDone, i, iFirst, iPgno, iVal, pDlidx, v2
|
|
bDone = 0
|
|
i = 0
|
|
for {
|
|
if !((*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK && bDone == 0) {
|
|
break
|
|
}
|
|
pDlidx = (*TFts5SegWriter)(unsafe.Pointer(pWriter)).FaDlidx + uintptr(i)*32
|
|
if (*TFts5DlidxWriter)(unsafe.Pointer(pDlidx)).Fbuf.Fn >= (*TFts5Config)(unsafe.Pointer((*TFts5Index)(unsafe.Pointer(p)).FpConfig)).Fpgsz {
|
|
/* The current doclist-index page is full. Write it to disk and push
|
|
** a copy of iRowid (which will become the first rowid on the next
|
|
** doclist-index leaf page) up into the next level of the b-tree
|
|
** hierarchy. If the node being flushed is currently the root node,
|
|
** also push its first rowid upwards. */
|
|
**(**Tu8)(__ccgo_up((*TFts5DlidxWriter)(unsafe.Pointer(pDlidx)).Fbuf.Fp)) = uint8(0x01) /* Not the root node */
|
|
_fts5DataWrite(tls, p, int64((*TFts5SegWriter)(unsafe.Pointer(pWriter)).FiSegid)<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B)+libc.Int32FromInt32(FTS5_DATA_DLI_B))+int64(libc.Int32FromInt32(1))<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B))+int64(i)<<libc.Int32FromInt32(FTS5_DATA_PAGE_B)+int64((*TFts5DlidxWriter)(unsafe.Pointer(pDlidx)).Fpgno), (*TFts5DlidxWriter)(unsafe.Pointer(pDlidx)).Fbuf.Fp, (*TFts5DlidxWriter)(unsafe.Pointer(pDlidx)).Fbuf.Fn)
|
|
_fts5WriteDlidxGrow(tls, p, pWriter, i+int32(2))
|
|
pDlidx = (*TFts5SegWriter)(unsafe.Pointer(pWriter)).FaDlidx + uintptr(i)*32
|
|
if (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK && (**(**TFts5DlidxWriter)(__ccgo_up(pDlidx + 1*32))).Fbuf.Fn == 0 {
|
|
iFirst = _fts5DlidxExtractFirstRowid(tls, pDlidx+16)
|
|
/* This was the root node. Push its first rowid up to the new root. */
|
|
(**(**TFts5DlidxWriter)(__ccgo_up(pDlidx + 1*32))).Fpgno = (*TFts5DlidxWriter)(unsafe.Pointer(pDlidx)).Fpgno
|
|
_sqlite3Fts5BufferAppendVarint(tls, p+60, pDlidx+1*32+16, 0)
|
|
_sqlite3Fts5BufferAppendVarint(tls, p+60, pDlidx+1*32+16, int64((*TFts5DlidxWriter)(unsafe.Pointer(pDlidx)).Fpgno))
|
|
_sqlite3Fts5BufferAppendVarint(tls, p+60, pDlidx+1*32+16, iFirst)
|
|
(**(**TFts5DlidxWriter)(__ccgo_up(pDlidx + 1*32))).FbPrevValid = int32(1)
|
|
(**(**TFts5DlidxWriter)(__ccgo_up(pDlidx + 1*32))).FiPrev = iFirst
|
|
}
|
|
_sqlite3Fts5BufferZero(tls, pDlidx+16)
|
|
(*TFts5DlidxWriter)(unsafe.Pointer(pDlidx)).FbPrevValid = 0
|
|
(*TFts5DlidxWriter)(unsafe.Pointer(pDlidx)).Fpgno = (*TFts5DlidxWriter)(unsafe.Pointer(pDlidx)).Fpgno + 1
|
|
} else {
|
|
bDone = int32(1)
|
|
}
|
|
if (*TFts5DlidxWriter)(unsafe.Pointer(pDlidx)).FbPrevValid != 0 {
|
|
iVal = libc.Int64FromUint64(libc.Uint64FromInt64(iRowid) - libc.Uint64FromInt64((*TFts5DlidxWriter)(unsafe.Pointer(pDlidx)).FiPrev))
|
|
} else {
|
|
if i == 0 {
|
|
v2 = (*TFts5SegWriter)(unsafe.Pointer(pWriter)).Fwriter.Fpgno
|
|
} else {
|
|
v2 = (**(**TFts5DlidxWriter)(__ccgo_up(pDlidx + uintptr(-libc.Int32FromInt32(1))*32))).Fpgno
|
|
}
|
|
iPgno = int64(v2)
|
|
_sqlite3Fts5BufferAppendVarint(tls, p+60, pDlidx+16, libc.BoolInt64(!(bDone != 0)))
|
|
_sqlite3Fts5BufferAppendVarint(tls, p+60, pDlidx+16, iPgno)
|
|
iVal = iRowid
|
|
}
|
|
_sqlite3Fts5BufferAppendVarint(tls, p+60, pDlidx+16, iVal)
|
|
(*TFts5DlidxWriter)(unsafe.Pointer(pDlidx)).FbPrevValid = int32(1)
|
|
(*TFts5DlidxWriter)(unsafe.Pointer(pDlidx)).FiPrev = iRowid
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
|
|
func _fts5WriteFlushLeaf(tls *libc.TLS, p uintptr, pWriter uintptr) {
|
|
var iRowid Ti64
|
|
var pPage uintptr
|
|
_, _ = iRowid, pPage
|
|
pPage = pWriter + 8
|
|
/* Set the szLeaf header field. */
|
|
_fts5PutU16(tls, (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fbuf.Fp+2, libc.Uint16FromInt32((*TFts5PageWriter)(unsafe.Pointer(pPage)).Fbuf.Fn))
|
|
if (*TFts5SegWriter)(unsafe.Pointer(pWriter)).FbFirstTermInPage != 0 {
|
|
/* No term was written to this page. */
|
|
_fts5WriteBtreeNoTerm(tls, p, pWriter)
|
|
} else {
|
|
/* Append the pgidx to the page buffer. Set the szLeaf header field. */
|
|
_sqlite3Fts5BufferAppendBlob(tls, p+60, pPage+8, libc.Uint32FromInt32((*TFts5PageWriter)(unsafe.Pointer(pPage)).Fpgidx.Fn), (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fpgidx.Fp)
|
|
}
|
|
/* Write the page out to disk */
|
|
iRowid = int64((*TFts5SegWriter)(unsafe.Pointer(pWriter)).FiSegid)<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B)+libc.Int32FromInt32(FTS5_DATA_DLI_B)) + int64(libc.Int32FromInt32(0))<<(libc.Int32FromInt32(FTS5_DATA_PAGE_B)+libc.Int32FromInt32(FTS5_DATA_HEIGHT_B)) + int64(libc.Int32FromInt32(0))<<libc.Int32FromInt32(FTS5_DATA_PAGE_B) + int64((*TFts5PageWriter)(unsafe.Pointer(pPage)).Fpgno)
|
|
_fts5DataWrite(tls, p, iRowid, (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fbuf.Fp, (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fbuf.Fn)
|
|
/* Initialize the next page. */
|
|
_sqlite3Fts5BufferZero(tls, pPage+8)
|
|
_sqlite3Fts5BufferZero(tls, pPage+24)
|
|
_sqlite3Fts5BufferAppendBlob(tls, p+60, pPage+8, uint32(4), uintptr(unsafe.Pointer(&_zero)))
|
|
(*TFts5PageWriter)(unsafe.Pointer(pPage)).FiPrevPgidx = 0
|
|
(*TFts5PageWriter)(unsafe.Pointer(pPage)).Fpgno = (*TFts5PageWriter)(unsafe.Pointer(pPage)).Fpgno + 1
|
|
/* Increase the leaves written counter */
|
|
(*TFts5SegWriter)(unsafe.Pointer(pWriter)).FnLeafWritten = (*TFts5SegWriter)(unsafe.Pointer(pWriter)).FnLeafWritten + 1
|
|
/* The new leaf holds no terms or rowids */
|
|
(*TFts5SegWriter)(unsafe.Pointer(pWriter)).FbFirstTermInPage = uint8(1)
|
|
(*TFts5SegWriter)(unsafe.Pointer(pWriter)).FbFirstRowidInPage = uint8(1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If the argument is a codepoint corresponding to a lowercase letter
|
|
// ** in the ASCII range with a diacritic added, return the codepoint
|
|
// ** of the ASCII letter only. For example, if passed 235 - "LATIN
|
|
// ** SMALL LETTER E WITH DIAERESIS" - return 65 ("LATIN SMALL LETTER
|
|
// ** E"). The resuls of passing a codepoint that corresponds to an
|
|
// ** uppercase letter are undefined.
|
|
// */
|
|
func _fts5_remove_diacritic(tls *libc.TLS, c int32, bComplex int32) (r int32) {
|
|
var aChar [126]uint8
|
|
var aDia [126]uint16
|
|
var iHi, iLo, iRes, iTest, v1 int32
|
|
var key uint32
|
|
_, _, _, _, _, _, _, _ = aChar, aDia, iHi, iLo, iRes, iTest, key, v1
|
|
aDia = [126]uint16{
|
|
1: uint16(1797),
|
|
2: uint16(1848),
|
|
3: uint16(1859),
|
|
4: uint16(1891),
|
|
5: uint16(1928),
|
|
6: uint16(1940),
|
|
7: uint16(1995),
|
|
8: uint16(2024),
|
|
9: uint16(2040),
|
|
10: uint16(2060),
|
|
11: uint16(2110),
|
|
12: uint16(2168),
|
|
13: uint16(2206),
|
|
14: uint16(2264),
|
|
15: uint16(2286),
|
|
16: uint16(2344),
|
|
17: uint16(2383),
|
|
18: uint16(2472),
|
|
19: uint16(2488),
|
|
20: uint16(2516),
|
|
21: uint16(2596),
|
|
22: uint16(2668),
|
|
23: uint16(2732),
|
|
24: uint16(2782),
|
|
25: uint16(2842),
|
|
26: uint16(2894),
|
|
27: uint16(2954),
|
|
28: uint16(2984),
|
|
29: uint16(3000),
|
|
30: uint16(3028),
|
|
31: uint16(3336),
|
|
32: uint16(3456),
|
|
33: uint16(3696),
|
|
34: uint16(3712),
|
|
35: uint16(3728),
|
|
36: uint16(3744),
|
|
37: uint16(3766),
|
|
38: uint16(3832),
|
|
39: uint16(3896),
|
|
40: uint16(3912),
|
|
41: uint16(3928),
|
|
42: uint16(3944),
|
|
43: uint16(3968),
|
|
44: uint16(4008),
|
|
45: uint16(4040),
|
|
46: uint16(4056),
|
|
47: uint16(4106),
|
|
48: uint16(4138),
|
|
49: uint16(4170),
|
|
50: uint16(4202),
|
|
51: uint16(4234),
|
|
52: uint16(4266),
|
|
53: uint16(4296),
|
|
54: uint16(4312),
|
|
55: uint16(4344),
|
|
56: uint16(4408),
|
|
57: uint16(4424),
|
|
58: uint16(4442),
|
|
59: uint16(4472),
|
|
60: uint16(4488),
|
|
61: uint16(4504),
|
|
62: uint16(6148),
|
|
63: uint16(6198),
|
|
64: uint16(6264),
|
|
65: uint16(6280),
|
|
66: uint16(6360),
|
|
67: uint16(6429),
|
|
68: uint16(6505),
|
|
69: uint16(6529),
|
|
70: uint16(61448),
|
|
71: uint16(61468),
|
|
72: uint16(61512),
|
|
73: uint16(61534),
|
|
74: uint16(61592),
|
|
75: uint16(61610),
|
|
76: uint16(61642),
|
|
77: uint16(61672),
|
|
78: uint16(61688),
|
|
79: uint16(61704),
|
|
80: uint16(61726),
|
|
81: uint16(61784),
|
|
82: uint16(61800),
|
|
83: uint16(61816),
|
|
84: uint16(61836),
|
|
85: uint16(61880),
|
|
86: uint16(61896),
|
|
87: uint16(61914),
|
|
88: uint16(61948),
|
|
89: uint16(61998),
|
|
90: uint16(62062),
|
|
91: uint16(62122),
|
|
92: uint16(62154),
|
|
93: uint16(62184),
|
|
94: uint16(62200),
|
|
95: uint16(62218),
|
|
96: uint16(62252),
|
|
97: uint16(62302),
|
|
98: uint16(62364),
|
|
99: uint16(62410),
|
|
100: uint16(62442),
|
|
101: uint16(62478),
|
|
102: uint16(62536),
|
|
103: uint16(62554),
|
|
104: uint16(62584),
|
|
105: uint16(62604),
|
|
106: uint16(62640),
|
|
107: uint16(62648),
|
|
108: uint16(62656),
|
|
109: uint16(62664),
|
|
110: uint16(62730),
|
|
111: uint16(62766),
|
|
112: uint16(62830),
|
|
113: uint16(62890),
|
|
114: uint16(62924),
|
|
115: uint16(62974),
|
|
116: uint16(63032),
|
|
117: uint16(63050),
|
|
118: uint16(63082),
|
|
119: uint16(63118),
|
|
120: uint16(63182),
|
|
121: uint16(63242),
|
|
122: uint16(63274),
|
|
123: uint16(63310),
|
|
124: uint16(63368),
|
|
125: uint16(63390),
|
|
}
|
|
aChar = [126]uint8{
|
|
1: uint8('a'),
|
|
2: uint8('c'),
|
|
3: uint8('e'),
|
|
4: uint8('i'),
|
|
5: uint8('n'),
|
|
6: uint8('o'),
|
|
7: uint8('u'),
|
|
8: uint8('y'),
|
|
9: uint8('y'),
|
|
10: uint8('a'),
|
|
11: uint8('c'),
|
|
12: uint8('d'),
|
|
13: uint8('e'),
|
|
14: uint8('e'),
|
|
15: uint8('g'),
|
|
16: uint8('h'),
|
|
17: uint8('i'),
|
|
18: uint8('j'),
|
|
19: uint8('k'),
|
|
20: uint8('l'),
|
|
21: uint8('n'),
|
|
22: uint8('o'),
|
|
23: uint8('r'),
|
|
24: uint8('s'),
|
|
25: uint8('t'),
|
|
26: uint8('u'),
|
|
27: uint8('u'),
|
|
28: uint8('w'),
|
|
29: uint8('y'),
|
|
30: uint8('z'),
|
|
31: uint8('o'),
|
|
32: uint8('u'),
|
|
33: uint8('a'),
|
|
34: uint8('i'),
|
|
35: uint8('o'),
|
|
36: uint8('u'),
|
|
37: libc.Uint8FromInt32(libc.Int32FromUint8('u') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
38: libc.Uint8FromInt32(libc.Int32FromUint8('a') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
39: uint8('g'),
|
|
40: uint8('k'),
|
|
41: uint8('o'),
|
|
42: libc.Uint8FromInt32(libc.Int32FromUint8('o') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
43: uint8('j'),
|
|
44: uint8('g'),
|
|
45: uint8('n'),
|
|
46: libc.Uint8FromInt32(libc.Int32FromUint8('a') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
47: uint8('a'),
|
|
48: uint8('e'),
|
|
49: uint8('i'),
|
|
50: uint8('o'),
|
|
51: uint8('r'),
|
|
52: uint8('u'),
|
|
53: uint8('s'),
|
|
54: uint8('t'),
|
|
55: uint8('h'),
|
|
56: uint8('a'),
|
|
57: uint8('e'),
|
|
58: libc.Uint8FromInt32(libc.Int32FromUint8('o') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
59: uint8('o'),
|
|
60: libc.Uint8FromInt32(libc.Int32FromUint8('o') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
61: uint8('y'),
|
|
70: uint8('a'),
|
|
71: uint8('b'),
|
|
72: libc.Uint8FromInt32(libc.Int32FromUint8('c') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
73: uint8('d'),
|
|
74: uint8('d'),
|
|
75: libc.Uint8FromInt32(libc.Int32FromUint8('e') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
76: uint8('e'),
|
|
77: libc.Uint8FromInt32(libc.Int32FromUint8('e') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
78: uint8('f'),
|
|
79: uint8('g'),
|
|
80: uint8('h'),
|
|
81: uint8('h'),
|
|
82: uint8('i'),
|
|
83: libc.Uint8FromInt32(libc.Int32FromUint8('i') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
84: uint8('k'),
|
|
85: uint8('l'),
|
|
86: libc.Uint8FromInt32(libc.Int32FromUint8('l') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
87: uint8('l'),
|
|
88: uint8('m'),
|
|
89: uint8('n'),
|
|
90: libc.Uint8FromInt32(libc.Int32FromUint8('o') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
91: uint8('p'),
|
|
92: uint8('r'),
|
|
93: libc.Uint8FromInt32(libc.Int32FromUint8('r') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
94: uint8('r'),
|
|
95: uint8('s'),
|
|
96: libc.Uint8FromInt32(libc.Int32FromUint8('s') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
97: uint8('t'),
|
|
98: uint8('u'),
|
|
99: libc.Uint8FromInt32(libc.Int32FromUint8('u') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
100: uint8('v'),
|
|
101: uint8('w'),
|
|
102: uint8('w'),
|
|
103: uint8('x'),
|
|
104: uint8('y'),
|
|
105: uint8('z'),
|
|
106: uint8('h'),
|
|
107: uint8('t'),
|
|
108: uint8('w'),
|
|
109: uint8('y'),
|
|
110: uint8('a'),
|
|
111: libc.Uint8FromInt32(libc.Int32FromUint8('a') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
112: libc.Uint8FromInt32(libc.Int32FromUint8('a') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
113: libc.Uint8FromInt32(libc.Int32FromUint8('a') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
114: uint8('e'),
|
|
115: libc.Uint8FromInt32(libc.Int32FromUint8('e') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
116: libc.Uint8FromInt32(libc.Int32FromUint8('e') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
117: uint8('i'),
|
|
118: uint8('o'),
|
|
119: libc.Uint8FromInt32(libc.Int32FromUint8('o') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
120: libc.Uint8FromInt32(libc.Int32FromUint8('o') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
121: libc.Uint8FromInt32(libc.Int32FromUint8('o') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
122: uint8('u'),
|
|
123: libc.Uint8FromInt32(libc.Int32FromUint8('u') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
124: libc.Uint8FromInt32(libc.Int32FromUint8('u') | libc.Int32FromUint8(libc.Uint8FromInt32(0x80))),
|
|
125: uint8('y'),
|
|
}
|
|
key = libc.Uint32FromInt32(c)<<int32(3) | uint32(0x00000007)
|
|
iRes = 0
|
|
iHi = libc.Int32FromUint64(libc.Uint64FromInt64(252)/libc.Uint64FromInt64(2) - libc.Uint64FromInt32(1))
|
|
iLo = 0
|
|
for iHi >= iLo {
|
|
iTest = (iHi + iLo) / int32(2)
|
|
if key >= uint32(aDia[iTest]) {
|
|
iRes = iTest
|
|
iLo = iTest + int32(1)
|
|
} else {
|
|
iHi = iTest - int32(1)
|
|
}
|
|
}
|
|
if bComplex == 0 && libc.Int32FromUint8(aChar[iRes])&int32(0x80) != 0 {
|
|
return c
|
|
}
|
|
if c > libc.Int32FromUint16(aDia[iRes])>>int32(3)+libc.Int32FromUint16(aDia[iRes])&int32(0x07) {
|
|
v1 = c
|
|
} else {
|
|
v1 = libc.Int32FromUint8(aChar[iRes]) & int32(0x7F)
|
|
}
|
|
return v1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Perform a reduce action and the shift that must immediately
|
|
// ** follow the reduce.
|
|
// **
|
|
// ** The fts5yyLookahead and fts5yyLookaheadToken parameters provide reduce actions
|
|
// ** access to the lookahead token (if any). The fts5yyLookahead will be fts5YYNOCODE
|
|
// ** if the lookahead token has already been consumed. As this procedure is
|
|
// ** only called from one place, optimizing compilers will in-line it, which
|
|
// ** means that the extra parameters have no performance impact.
|
|
// */
|
|
func _fts5yy_reduce(tls *libc.TLS, fts5yypParser uintptr, fts5yyruleno uint32, fts5yyLookahead int32, fts5yyLookaheadToken TFts5Token) (r uint8) {
|
|
var fts5yyact uint8
|
|
var fts5yygoto, fts5yysize int32
|
|
var fts5yylhsminor Tfts5YYMINORTYPE
|
|
var fts5yymsp, pParse uintptr
|
|
_, _, _, _, _, _ = fts5yyact, fts5yygoto, fts5yylhsminor, fts5yymsp, fts5yysize, pParse /* Amount to pop the stack */
|
|
pParse = (*Tfts5yyParser)(unsafe.Pointer(fts5yypParser)).FpParse
|
|
_ = fts5yyLookahead
|
|
_ = fts5yyLookaheadToken
|
|
fts5yymsp = (*Tfts5yyParser)(unsafe.Pointer(fts5yypParser)).Ffts5yytos
|
|
switch fts5yyruleno {
|
|
case uint32(0):
|
|
goto _1
|
|
case uint32(1):
|
|
goto _2
|
|
case uint32(2):
|
|
goto _3
|
|
case uint32(3):
|
|
goto _4
|
|
case uint32(4):
|
|
goto _5
|
|
case uint32(5):
|
|
goto _6
|
|
case uint32(6):
|
|
goto _7
|
|
case uint32(7):
|
|
goto _8
|
|
case uint32(8):
|
|
goto _9
|
|
case uint32(9):
|
|
goto _10
|
|
case uint32(10):
|
|
goto _11
|
|
case uint32(11):
|
|
goto _12
|
|
case uint32(13):
|
|
goto _13
|
|
case uint32(12):
|
|
goto _14
|
|
case uint32(14):
|
|
goto _15
|
|
case uint32(15):
|
|
goto _16
|
|
case uint32(16):
|
|
goto _17
|
|
case uint32(17):
|
|
goto _18
|
|
case uint32(18):
|
|
goto _19
|
|
case uint32(19):
|
|
goto _20
|
|
case uint32(20):
|
|
goto _21
|
|
case uint32(21):
|
|
goto _22
|
|
case uint32(22):
|
|
goto _23
|
|
case uint32(23):
|
|
goto _24
|
|
case uint32(24):
|
|
goto _25
|
|
case uint32(25):
|
|
goto _26
|
|
case uint32(26):
|
|
goto _27
|
|
case uint32(27):
|
|
goto _28
|
|
default:
|
|
goto _29
|
|
}
|
|
goto _30
|
|
_1:
|
|
; /* input ::= expr */
|
|
_sqlite3Fts5ParseFinished(tls, pParse, *(*uintptr)(unsafe.Pointer(fts5yymsp + 8)))
|
|
goto _30
|
|
_2:
|
|
; /* colset ::= MINUS LCP colsetlist RCP */
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(3))*24 + 8)) = _sqlite3Fts5ParseColsetInvert(tls, pParse, *(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(1))*24 + 8)))
|
|
goto _30
|
|
_3:
|
|
; /* colset ::= LCP colsetlist RCP */
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(2))*24 + 8)) = *(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(1))*24 + 8))
|
|
goto _30
|
|
_4:
|
|
; /* colset ::= STRING */
|
|
*(*uintptr)(unsafe.Pointer(&fts5yylhsminor)) = _sqlite3Fts5ParseColset(tls, pParse, uintptr(0), fts5yymsp+8)
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + 8)) = *(*uintptr)(unsafe.Pointer(&fts5yylhsminor))
|
|
goto _30
|
|
_5:
|
|
; /* colset ::= MINUS STRING */
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(1))*24 + 8)) = _sqlite3Fts5ParseColset(tls, pParse, uintptr(0), fts5yymsp+8)
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(1))*24 + 8)) = _sqlite3Fts5ParseColsetInvert(tls, pParse, *(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(1))*24 + 8)))
|
|
goto _30
|
|
_6:
|
|
; /* colsetlist ::= colsetlist STRING */
|
|
*(*uintptr)(unsafe.Pointer(&fts5yylhsminor)) = _sqlite3Fts5ParseColset(tls, pParse, *(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(1))*24 + 8)), fts5yymsp+8)
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(1))*24 + 8)) = *(*uintptr)(unsafe.Pointer(&fts5yylhsminor))
|
|
goto _30
|
|
_7:
|
|
; /* colsetlist ::= STRING */
|
|
*(*uintptr)(unsafe.Pointer(&fts5yylhsminor)) = _sqlite3Fts5ParseColset(tls, pParse, uintptr(0), fts5yymsp+8)
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + 8)) = *(*uintptr)(unsafe.Pointer(&fts5yylhsminor))
|
|
goto _30
|
|
_8:
|
|
; /* expr ::= expr AND expr */
|
|
*(*uintptr)(unsafe.Pointer(&fts5yylhsminor)) = _sqlite3Fts5ParseNode(tls, pParse, int32(FTS5_AND), *(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(2))*24 + 8)), *(*uintptr)(unsafe.Pointer(fts5yymsp + 8)), uintptr(0))
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(2))*24 + 8)) = *(*uintptr)(unsafe.Pointer(&fts5yylhsminor))
|
|
goto _30
|
|
_9:
|
|
; /* expr ::= expr OR expr */
|
|
*(*uintptr)(unsafe.Pointer(&fts5yylhsminor)) = _sqlite3Fts5ParseNode(tls, pParse, int32(FTS5_OR), *(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(2))*24 + 8)), *(*uintptr)(unsafe.Pointer(fts5yymsp + 8)), uintptr(0))
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(2))*24 + 8)) = *(*uintptr)(unsafe.Pointer(&fts5yylhsminor))
|
|
goto _30
|
|
_10:
|
|
; /* expr ::= expr NOT expr */
|
|
*(*uintptr)(unsafe.Pointer(&fts5yylhsminor)) = _sqlite3Fts5ParseNode(tls, pParse, int32(FTS5_NOT), *(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(2))*24 + 8)), *(*uintptr)(unsafe.Pointer(fts5yymsp + 8)), uintptr(0))
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(2))*24 + 8)) = *(*uintptr)(unsafe.Pointer(&fts5yylhsminor))
|
|
goto _30
|
|
_11:
|
|
; /* expr ::= colset COLON LP expr RP */
|
|
_sqlite3Fts5ParseSetColset(tls, pParse, *(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(1))*24 + 8)), *(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(4))*24 + 8)))
|
|
*(*uintptr)(unsafe.Pointer(&fts5yylhsminor)) = *(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(1))*24 + 8))
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(4))*24 + 8)) = *(*uintptr)(unsafe.Pointer(&fts5yylhsminor))
|
|
goto _30
|
|
_12:
|
|
; /* expr ::= LP expr RP */
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(2))*24 + 8)) = *(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(1))*24 + 8))
|
|
goto _30
|
|
_14:
|
|
; /* expr ::= exprlist */
|
|
_13:
|
|
;
|
|
*(*uintptr)(unsafe.Pointer(&fts5yylhsminor)) = *(*uintptr)(unsafe.Pointer(fts5yymsp + 8))
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + 8)) = *(*uintptr)(unsafe.Pointer(&fts5yylhsminor))
|
|
goto _30
|
|
_15:
|
|
; /* exprlist ::= exprlist cnearset */
|
|
*(*uintptr)(unsafe.Pointer(&fts5yylhsminor)) = _sqlite3Fts5ParseImplicitAnd(tls, pParse, *(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(1))*24 + 8)), *(*uintptr)(unsafe.Pointer(fts5yymsp + 8)))
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(1))*24 + 8)) = *(*uintptr)(unsafe.Pointer(&fts5yylhsminor))
|
|
goto _30
|
|
_16:
|
|
; /* cnearset ::= nearset */
|
|
*(*uintptr)(unsafe.Pointer(&fts5yylhsminor)) = _sqlite3Fts5ParseNode(tls, pParse, int32(FTS5_STRING), uintptr(0), uintptr(0), *(*uintptr)(unsafe.Pointer(fts5yymsp + 8)))
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + 8)) = *(*uintptr)(unsafe.Pointer(&fts5yylhsminor))
|
|
goto _30
|
|
_17:
|
|
; /* cnearset ::= colset COLON nearset */
|
|
*(*uintptr)(unsafe.Pointer(&fts5yylhsminor)) = _sqlite3Fts5ParseNode(tls, pParse, int32(FTS5_STRING), uintptr(0), uintptr(0), *(*uintptr)(unsafe.Pointer(fts5yymsp + 8)))
|
|
_sqlite3Fts5ParseSetColset(tls, pParse, *(*uintptr)(unsafe.Pointer(&fts5yylhsminor)), *(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(2))*24 + 8)))
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(2))*24 + 8)) = *(*uintptr)(unsafe.Pointer(&fts5yylhsminor))
|
|
goto _30
|
|
_18:
|
|
; /* nearset ::= phrase */
|
|
*(*uintptr)(unsafe.Pointer(&fts5yylhsminor)) = _sqlite3Fts5ParseNearset(tls, pParse, uintptr(0), *(*uintptr)(unsafe.Pointer(fts5yymsp + 8)))
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + 8)) = *(*uintptr)(unsafe.Pointer(&fts5yylhsminor))
|
|
goto _30
|
|
_19:
|
|
; /* nearset ::= CARET phrase */
|
|
_sqlite3Fts5ParseSetCaret(tls, *(*uintptr)(unsafe.Pointer(fts5yymsp + 8)))
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(1))*24 + 8)) = _sqlite3Fts5ParseNearset(tls, pParse, uintptr(0), *(*uintptr)(unsafe.Pointer(fts5yymsp + 8)))
|
|
goto _30
|
|
_20:
|
|
; /* nearset ::= STRING LP nearphrases neardist_opt RP */
|
|
_sqlite3Fts5ParseNear(tls, pParse, fts5yymsp+uintptr(-libc.Int32FromInt32(4))*24+8)
|
|
_sqlite3Fts5ParseSetDistance(tls, pParse, *(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(2))*24 + 8)), fts5yymsp+uintptr(-libc.Int32FromInt32(1))*24+8)
|
|
*(*uintptr)(unsafe.Pointer(&fts5yylhsminor)) = *(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(2))*24 + 8))
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(4))*24 + 8)) = *(*uintptr)(unsafe.Pointer(&fts5yylhsminor))
|
|
goto _30
|
|
_21:
|
|
; /* nearphrases ::= phrase */
|
|
*(*uintptr)(unsafe.Pointer(&fts5yylhsminor)) = _sqlite3Fts5ParseNearset(tls, pParse, uintptr(0), *(*uintptr)(unsafe.Pointer(fts5yymsp + 8)))
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + 8)) = *(*uintptr)(unsafe.Pointer(&fts5yylhsminor))
|
|
goto _30
|
|
_22:
|
|
; /* nearphrases ::= nearphrases phrase */
|
|
*(*uintptr)(unsafe.Pointer(&fts5yylhsminor)) = _sqlite3Fts5ParseNearset(tls, pParse, *(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(1))*24 + 8)), *(*uintptr)(unsafe.Pointer(fts5yymsp + 8)))
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(1))*24 + 8)) = *(*uintptr)(unsafe.Pointer(&fts5yylhsminor))
|
|
goto _30
|
|
_23:
|
|
; /* neardist_opt ::= */
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + 1*24 + 8)) = uintptr(0)
|
|
*(*int32)(unsafe.Pointer(fts5yymsp + 1*24 + 8 + 8)) = 0
|
|
goto _30
|
|
_24:
|
|
; /* neardist_opt ::= COMMA STRING */
|
|
*(*TFts5Token)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(1))*24 + 8)) = *(*TFts5Token)(unsafe.Pointer(fts5yymsp + 8))
|
|
goto _30
|
|
_25:
|
|
; /* phrase ::= phrase PLUS STRING star_opt */
|
|
*(*uintptr)(unsafe.Pointer(&fts5yylhsminor)) = _sqlite3Fts5ParseTerm(tls, pParse, *(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(3))*24 + 8)), fts5yymsp+uintptr(-libc.Int32FromInt32(1))*24+8, *(*int32)(unsafe.Pointer(fts5yymsp + 8)))
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(3))*24 + 8)) = *(*uintptr)(unsafe.Pointer(&fts5yylhsminor))
|
|
goto _30
|
|
_26:
|
|
; /* phrase ::= STRING star_opt */
|
|
*(*uintptr)(unsafe.Pointer(&fts5yylhsminor)) = _sqlite3Fts5ParseTerm(tls, pParse, uintptr(0), fts5yymsp+uintptr(-libc.Int32FromInt32(1))*24+8, *(*int32)(unsafe.Pointer(fts5yymsp + 8)))
|
|
*(*uintptr)(unsafe.Pointer(fts5yymsp + uintptr(-libc.Int32FromInt32(1))*24 + 8)) = *(*uintptr)(unsafe.Pointer(&fts5yylhsminor))
|
|
goto _30
|
|
_27:
|
|
; /* star_opt ::= STAR */
|
|
*(*int32)(unsafe.Pointer(fts5yymsp + 8)) = int32(1)
|
|
goto _30
|
|
_28:
|
|
; /* star_opt ::= */
|
|
*(*int32)(unsafe.Pointer(fts5yymsp + 1*24 + 8)) = 0
|
|
goto _30
|
|
_29:
|
|
;
|
|
goto _30
|
|
/********** End reduce actions ************************************************/
|
|
_30:
|
|
;
|
|
fts5yygoto = libc.Int32FromUint8(_fts5yyRuleInfoLhs[fts5yyruleno])
|
|
fts5yysize = int32(_fts5yyRuleInfoNRhs[fts5yyruleno])
|
|
fts5yyact = _fts5yy_find_reduce_action(tls, (**(**Tfts5yyStackEntry)(__ccgo_up(fts5yymsp + uintptr(fts5yysize)*24))).Fstateno, libc.Uint8FromInt32(fts5yygoto))
|
|
/* There are no SHIFTREDUCE actions on nonterminals because the table
|
|
** generator has simplified them to pure REDUCE actions. */
|
|
/* It is not possible for a REDUCE to be followed by an error */
|
|
fts5yymsp = fts5yymsp + uintptr(fts5yysize+int32(1))*24
|
|
(*Tfts5yyParser)(unsafe.Pointer(fts5yypParser)).Ffts5yytos = fts5yymsp
|
|
(*Tfts5yyStackEntry)(unsafe.Pointer(fts5yymsp)).Fstateno = fts5yyact
|
|
(*Tfts5yyStackEntry)(unsafe.Pointer(fts5yymsp)).Fmajor = libc.Uint8FromInt32(fts5yygoto)
|
|
return fts5yyact
|
|
}
|
|
|
|
/*
|
|
** The following code executes when the parse fails
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Perform a shift action.
|
|
// */
|
|
func _fts5yy_shift(tls *libc.TLS, fts5yypParser uintptr, fts5yyNewState uint8, fts5yyMajor uint8, fts5yyMinor TFts5Token) {
|
|
var fts5yytos uintptr
|
|
_ = fts5yytos
|
|
(*Tfts5yyParser)(unsafe.Pointer(fts5yypParser)).Ffts5yytos += 24
|
|
fts5yytos = (*Tfts5yyParser)(unsafe.Pointer(fts5yypParser)).Ffts5yytos
|
|
if fts5yytos > (*Tfts5yyParser)(unsafe.Pointer(fts5yypParser)).Ffts5yystackEnd {
|
|
if int32(1) != 0 {
|
|
(*Tfts5yyParser)(unsafe.Pointer(fts5yypParser)).Ffts5yytos -= 24
|
|
_fts5yyStackOverflow(tls, fts5yypParser)
|
|
return
|
|
}
|
|
fts5yytos = (*Tfts5yyParser)(unsafe.Pointer(fts5yypParser)).Ffts5yytos
|
|
}
|
|
if libc.Int32FromUint8(fts5yyNewState) > int32(fts5YY_MAX_SHIFT) {
|
|
fts5yyNewState = libc.Uint8FromInt32(int32(fts5yyNewState) + (libc.Int32FromInt32(fts5YY_MIN_REDUCE) - libc.Int32FromInt32(fts5YY_MIN_SHIFTREDUCE)))
|
|
}
|
|
(*Tfts5yyStackEntry)(unsafe.Pointer(fts5yytos)).Fstateno = fts5yyNewState
|
|
(*Tfts5yyStackEntry)(unsafe.Pointer(fts5yytos)).Fmajor = fts5yyMajor
|
|
*(*TFts5Token)(unsafe.Pointer(fts5yytos + 8)) = fts5yyMinor
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The gatherSelectWindows() procedure and its helper routine
|
|
// ** gatherSelectWindowsCallback() are used to scan all the expressions
|
|
// ** an a newly duplicated SELECT statement and gather all of the Window
|
|
// ** objects found there, assembling them onto the linked list at Select->pWin.
|
|
// */
|
|
func _gatherSelectWindowsCallback(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var pSelect, pWin uintptr
|
|
_, _ = pSelect, pWin
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_FUNCTION) && (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_WinFunc)) != uint32(0) {
|
|
pSelect = *(*uintptr)(unsafe.Pointer(pWalker + 40))
|
|
pWin = *(*uintptr)(unsafe.Pointer(pExpr + 64))
|
|
_sqlite3WindowLink(tls, pSelect, pWin)
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** GEOPOLY virtual table module xColumn method.
|
|
// */
|
|
func _geopolyColumn(tls *libc.TLS, cur uintptr, ctx uintptr, i int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var p, pCsr, pNode, pRtree uintptr
|
|
var _ /* rc at bp+0 */ int32
|
|
_, _, _, _ = p, pCsr, pNode, pRtree
|
|
pRtree = (*Tsqlite3_vtab_cursor)(unsafe.Pointer(cur)).FpVtab
|
|
pCsr = cur
|
|
p = _rtreeSearchPointFirst(tls, pCsr)
|
|
**(**int32)(__ccgo_up(bp)) = SQLITE_OK
|
|
pNode = _rtreeNodeOfFirstSearchPoint(tls, pCsr, bp)
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
if p == uintptr(0) {
|
|
return SQLITE_OK
|
|
}
|
|
if i == 0 && Xsqlite3_vtab_nochange(tls, ctx) != 0 {
|
|
return SQLITE_OK
|
|
}
|
|
if i <= libc.Int32FromUint16((*TRtree)(unsafe.Pointer(pRtree)).FnAux) {
|
|
if !((*TRtreeCursor)(unsafe.Pointer(pCsr)).FbAuxValid != 0) {
|
|
if (*TRtreeCursor)(unsafe.Pointer(pCsr)).FpReadAux == uintptr(0) {
|
|
**(**int32)(__ccgo_up(bp)) = Xsqlite3_prepare_v3(tls, (*TRtree)(unsafe.Pointer(pRtree)).Fdb, (*TRtree)(unsafe.Pointer(pRtree)).FzReadAuxSql, -int32(1), uint32(0), pCsr+56, uintptr(0))
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
}
|
|
Xsqlite3_bind_int64(tls, (*TRtreeCursor)(unsafe.Pointer(pCsr)).FpReadAux, int32(1), _nodeGetRowid(tls, pRtree, pNode, libc.Int32FromUint8((*TRtreeSearchPoint)(unsafe.Pointer(p)).FiCell)))
|
|
**(**int32)(__ccgo_up(bp)) = Xsqlite3_step(tls, (*TRtreeCursor)(unsafe.Pointer(pCsr)).FpReadAux)
|
|
if **(**int32)(__ccgo_up(bp)) == int32(SQLITE_ROW) {
|
|
(*TRtreeCursor)(unsafe.Pointer(pCsr)).FbAuxValid = uint8(1)
|
|
} else {
|
|
Xsqlite3_reset(tls, (*TRtreeCursor)(unsafe.Pointer(pCsr)).FpReadAux)
|
|
if **(**int32)(__ccgo_up(bp)) == int32(SQLITE_DONE) {
|
|
**(**int32)(__ccgo_up(bp)) = SQLITE_OK
|
|
}
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
}
|
|
Xsqlite3_result_value(tls, ctx, Xsqlite3_column_value(tls, (*TRtreeCursor)(unsafe.Pointer(pCsr)).FpReadAux, i+int32(2)))
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Make sure the BtCursor* given in the argument has a valid
|
|
// ** BtCursor.info structure. If it is not already valid, call
|
|
// ** btreeParseCell() to fill it in.
|
|
// **
|
|
// ** BtCursor.info is a cache of the information in the current cell.
|
|
// ** Using this cache reduces the number of calls to btreeParseCell().
|
|
// */
|
|
func _getCellInfo(tls *libc.TLS, pCur uintptr) {
|
|
var v1 uintptr
|
|
_ = v1
|
|
if libc.Int32FromUint16((*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnSize) == 0 {
|
|
v1 = pCur + 1
|
|
*(*Tu8)(unsafe.Pointer(v1)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v1))) | libc.Int32FromInt32(BTCF_ValidNKey))
|
|
_btreeParseCell(tls, (*TBtCursor)(unsafe.Pointer(pCur)).FpPage, libc.Int32FromUint16((*TBtCursor)(unsafe.Pointer(pCur)).Fix), pCur+48)
|
|
} else {
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Given the page number of an overflow page in the database (parameter
|
|
// ** ovfl), this function finds the page number of the next page in the
|
|
// ** linked list of overflow pages. If possible, it uses the auto-vacuum
|
|
// ** pointer-map data instead of reading the content of page ovfl to do so.
|
|
// **
|
|
// ** If an error occurs an SQLite error code is returned. Otherwise:
|
|
// **
|
|
// ** The page number of the next overflow page in the linked list is
|
|
// ** written to *pPgnoNext. If page ovfl is the last page in its linked
|
|
// ** list, *pPgnoNext is set to zero.
|
|
// **
|
|
// ** If ppPage is not NULL, and a reference to the MemPage object corresponding
|
|
// ** to page number pOvfl was obtained, then *ppPage is set to point to that
|
|
// ** reference. It is the responsibility of the caller to call releasePage()
|
|
// ** on *ppPage to free the reference. In no reference was obtained (because
|
|
// ** the pointer-map was used to obtain the value for *pPgnoNext), then
|
|
// ** *ppPage is set to zero.
|
|
// */
|
|
func _getOverflowPage(tls *libc.TLS, pBt uintptr, ovfl TPgno, ppPage uintptr, pPgnoNext uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iGuess, next TPgno
|
|
var rc, v1 int32
|
|
var _ /* eType at bp+12 */ Tu8
|
|
var _ /* pPage at bp+0 */ uintptr
|
|
var _ /* pgno at bp+8 */ TPgno
|
|
_, _, _, _ = iGuess, next, rc, v1
|
|
next = uint32(0)
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
rc = SQLITE_OK
|
|
/* Try to find the next page in the overflow list using the
|
|
** autovacuum pointer-map pages. Guess that the next page in
|
|
** the overflow list is page number (ovfl+1). If that guess turns
|
|
** out to be wrong, fall back to loading the data of page
|
|
** number ovfl to determine the next page number.
|
|
*/
|
|
if (*TBtShared)(unsafe.Pointer(pBt)).FautoVacuum != 0 {
|
|
iGuess = ovfl + uint32(1)
|
|
for _ptrmapPageno(tls, pBt, iGuess) == iGuess || iGuess == libc.Uint32FromInt32(_sqlite3PendingByte)/(*TBtShared)(unsafe.Pointer(pBt)).FpageSize+libc.Uint32FromInt32(1) {
|
|
iGuess = iGuess + 1
|
|
}
|
|
if iGuess <= _btreePagecount(tls, pBt) {
|
|
rc = _ptrmapGet(tls, pBt, iGuess, bp+12, bp+8)
|
|
if rc == SQLITE_OK && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(bp + 12))) == int32(PTRMAP_OVERFLOW2) && **(**TPgno)(__ccgo_up(bp + 8)) == ovfl {
|
|
next = iGuess
|
|
rc = int32(SQLITE_DONE)
|
|
}
|
|
}
|
|
}
|
|
if rc == SQLITE_OK {
|
|
if ppPage == uintptr(0) {
|
|
v1 = int32(PAGER_GET_READONLY)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
rc = _btreeGetPage(tls, pBt, ovfl, bp, v1)
|
|
if rc == SQLITE_OK {
|
|
next = _sqlite3Get4byte(tls, (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FaData)
|
|
}
|
|
}
|
|
**(**TPgno)(__ccgo_up(pPgnoNext)) = next
|
|
if ppPage != 0 {
|
|
**(**uintptr)(__ccgo_up(ppPage)) = **(**uintptr)(__ccgo_up(bp))
|
|
} else {
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
}
|
|
if rc == int32(SQLITE_DONE) {
|
|
v1 = SQLITE_OK
|
|
} else {
|
|
v1 = rc
|
|
}
|
|
return v1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Resize the Vdbe.aOp array so that it is at least nOp elements larger
|
|
// ** than its current size. nOp is guaranteed to be less than or equal
|
|
// ** to 1024/sizeof(Op).
|
|
// **
|
|
// ** If an out-of-memory error occurs while resizing the array, return
|
|
// ** SQLITE_NOMEM. In this case Vdbe.aOp and Vdbe.nOpAlloc remain
|
|
// ** unchanged (this is so that any opcodes already allocated can be
|
|
// ** correctly deallocated along with the rest of the Vdbe).
|
|
// */
|
|
func _growOpArray(tls *libc.TLS, v uintptr, nOp int32) (r int32) {
|
|
var nNew Tsqlite3_int64
|
|
var p, pNew uintptr
|
|
var v1 int64
|
|
var v2 int32
|
|
_, _, _, _, _ = nNew, p, pNew, v1, v2
|
|
p = (*TVdbe)(unsafe.Pointer(v)).FpParse
|
|
if (*TVdbe)(unsafe.Pointer(v)).FnOpAlloc != 0 {
|
|
v1 = int64(2) * int64((*TVdbe)(unsafe.Pointer(v)).FnOpAlloc)
|
|
} else {
|
|
v1 = libc.Int64FromUint64(libc.Uint64FromInt32(1024) / libc.Uint64FromInt64(24))
|
|
}
|
|
/* The SQLITE_TEST_REALLOC_STRESS compile-time option is designed to force
|
|
** more frequent reallocs and hence provide more opportunities for
|
|
** simulated OOM faults. SQLITE_TEST_REALLOC_STRESS is generally used
|
|
** during testing only. With SQLITE_TEST_REALLOC_STRESS grow the op array
|
|
** by the minimum* amount required until the size reaches 512. Normal
|
|
** operation (without SQLITE_TEST_REALLOC_STRESS) is to double the current
|
|
** size of the op array or add 1KB of space, whichever is smaller. */
|
|
nNew = v1
|
|
_ = nOp
|
|
/* Ensure that the size of a VDBE does not grow too large */
|
|
if nNew > int64(**(**int32)(__ccgo_up((*TParse)(unsafe.Pointer(p)).Fdb + 136 + 5*4))) {
|
|
_sqlite3OomFault(tls, (*TParse)(unsafe.Pointer(p)).Fdb)
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
pNew = _sqlite3DbRealloc(tls, (*TParse)(unsafe.Pointer(p)).Fdb, (*TVdbe)(unsafe.Pointer(v)).FaOp, libc.Uint64FromInt64(nNew)*uint64(24))
|
|
if pNew != 0 {
|
|
(*TParse)(unsafe.Pointer(p)).FszOpAlloc = _sqlite3DbMallocSize(tls, (*TParse)(unsafe.Pointer(p)).Fdb, pNew)
|
|
(*TVdbe)(unsafe.Pointer(v)).FnOpAlloc = libc.Int32FromUint64(libc.Uint64FromInt32((*TParse)(unsafe.Pointer(p)).FszOpAlloc) / uint64(24))
|
|
(*TVdbe)(unsafe.Pointer(v)).FaOp = pNew
|
|
}
|
|
if pNew != 0 {
|
|
v2 = SQLITE_OK
|
|
} else {
|
|
v2 = int32(SQLITE_NOMEM)
|
|
}
|
|
return v2
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** sqlite3WalkExpr() callback used by havingToWhere().
|
|
// **
|
|
// ** If the node passed to the callback is a TK_AND node, return
|
|
// ** WRC_Continue to tell sqlite3WalkExpr() to iterate through child nodes.
|
|
// **
|
|
// ** Otherwise, return WRC_Prune. In this case, also check if the
|
|
// ** sub-expression matches the criteria for being moved to the WHERE
|
|
// ** clause. If so, add it to the WHERE clause and replace the sub-expression
|
|
// ** within the HAVING expression with a constant "1".
|
|
// */
|
|
func _havingToWhereExprCb(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var db, pNew, pS, pWhere uintptr
|
|
var t TExpr
|
|
_, _, _, _, _ = db, pNew, pS, pWhere, t
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) != int32(TK_AND) {
|
|
pS = *(*uintptr)(unsafe.Pointer(pWalker + 40))
|
|
/* This routine is called before the HAVING clause of the current
|
|
** SELECT is analyzed for aggregates. So if pExpr->pAggInfo is set
|
|
** here, it indicates that the expression is a correlated reference to a
|
|
** column from an outer aggregate query, or an aggregate function that
|
|
** belongs to an outer query. Do not move the expression to the WHERE
|
|
** clause in this obscure case, as doing so may corrupt the outer Select
|
|
** statements AggInfo structure. */
|
|
if _sqlite3ExprIsConstantOrGroupBy(tls, (*TWalker)(unsafe.Pointer(pWalker)).FpParse, pExpr, (*TSelect)(unsafe.Pointer(pS)).FpGroupBy) != 0 && libc.BoolInt32((*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)|libc.Int32FromInt32(EP_IsFalse)) == uint32(EP_IsFalse)) == 0 && (*TExpr)(unsafe.Pointer(pExpr)).FpAggInfo == uintptr(0) {
|
|
db = (*TParse)(unsafe.Pointer((*TWalker)(unsafe.Pointer(pWalker)).FpParse)).Fdb
|
|
pNew = _sqlite3ExprInt32(tls, db, int32(1))
|
|
if pNew != 0 {
|
|
pWhere = (*TSelect)(unsafe.Pointer(pS)).FpWhere
|
|
t = **(**TExpr)(__ccgo_up(pNew))
|
|
**(**TExpr)(__ccgo_up(pNew)) = **(**TExpr)(__ccgo_up(pExpr))
|
|
**(**TExpr)(__ccgo_up(pExpr)) = t
|
|
pNew = _sqlite3ExprAnd(tls, (*TWalker)(unsafe.Pointer(pWalker)).FpParse, pWhere, pNew)
|
|
(*TSelect)(unsafe.Pointer(pS)).FpWhere = pNew
|
|
(*TWalker)(unsafe.Pointer(pWalker)).FeCode = uint16(1)
|
|
}
|
|
}
|
|
return int32(WRC_Prune)
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is the Expr node callback for sqlite3ExprImpliesNonNullRow().
|
|
// ** If the expression node requires that the table at pWalker->iCur
|
|
// ** have one or more non-NULL column, then set pWalker->eCode to 1 and abort.
|
|
// **
|
|
// ** pWalker->mWFlags is non-zero if this inquiry is being undertaking on
|
|
// ** behalf of a RIGHT JOIN (or FULL JOIN). That makes a difference when
|
|
// ** evaluating terms in the ON clause of an inner join.
|
|
// **
|
|
// ** This routine controls an optimization. False positives (setting
|
|
// ** pWalker->eCode to 1 when it should not be) are deadly, but false-negatives
|
|
// ** (never setting pWalker->eCode) is a harmless missed optimization.
|
|
// */
|
|
func _impliesNotNullRow(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var pLeft, pRight uintptr
|
|
_, _ = pLeft, pRight
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)) != uint32(0) {
|
|
return int32(WRC_Prune)
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_InnerON)) != uint32(0) && (*TWalker)(unsafe.Pointer(pWalker)).FmWFlags != 0 {
|
|
/* If iCur is used in an inner-join ON clause to the left of a
|
|
** RIGHT JOIN, that does *not* mean that the table must be non-null.
|
|
** But it is difficult to check for that condition precisely.
|
|
** To keep things simple, any use of iCur from any inner-join is
|
|
** ignored while attempting to simplify a RIGHT JOIN. */
|
|
return int32(WRC_Prune)
|
|
}
|
|
switch libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) {
|
|
case int32(TK_ISNOT):
|
|
fallthrough
|
|
case int32(TK_ISNULL):
|
|
fallthrough
|
|
case int32(TK_NOTNULL):
|
|
fallthrough
|
|
case int32(TK_IS):
|
|
fallthrough
|
|
case int32(TK_VECTOR):
|
|
fallthrough
|
|
case int32(TK_FUNCTION):
|
|
fallthrough
|
|
case int32(TK_TRUTH):
|
|
fallthrough
|
|
case int32(TK_CASE):
|
|
return int32(WRC_Prune)
|
|
case int32(TK_COLUMN):
|
|
if *(*int32)(unsafe.Pointer(&(*TWalker)(unsafe.Pointer(pWalker)).Fu)) == (*TExpr)(unsafe.Pointer(pExpr)).FiTable {
|
|
(*TWalker)(unsafe.Pointer(pWalker)).FeCode = uint16(1)
|
|
return int32(WRC_Abort)
|
|
}
|
|
return int32(WRC_Prune)
|
|
case int32(TK_OR):
|
|
fallthrough
|
|
case int32(TK_AND):
|
|
/* Both sides of an AND or OR must separately imply non-null-row.
|
|
** Consider these cases:
|
|
** 1. NOT (x AND y)
|
|
** 2. x OR y
|
|
** If only one of x or y is non-null-row, then the overall expression
|
|
** can be true if the other arm is false (case 1) or true (case 2).
|
|
*/
|
|
_bothImplyNotNullRow(tls, pWalker, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft, (*TExpr)(unsafe.Pointer(pExpr)).FpRight)
|
|
return int32(WRC_Prune)
|
|
case int32(TK_IN):
|
|
/* Beware of "x NOT IN ()" and "x NOT IN (SELECT 1 WHERE false)",
|
|
** both of which can be true. But apart from these cases, if
|
|
** the left-hand side of the IN is NULL then the IN itself will be
|
|
** NULL. */
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&uint32(EP_xIsSelect) == uint32(0) && (*TExprList)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)))).FnExpr > 0 {
|
|
_sqlite3WalkExpr(tls, pWalker, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft)
|
|
}
|
|
return int32(WRC_Prune)
|
|
case int32(TK_BETWEEN):
|
|
/* In "x NOT BETWEEN y AND z" either x must be non-null-row or else
|
|
** both y and z must be non-null row */
|
|
_sqlite3WalkExpr(tls, pWalker, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft)
|
|
_bothImplyNotNullRow(tls, pWalker, (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)) + 8))).FpExpr, (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)) + 8 + 1*32))).FpExpr)
|
|
return int32(WRC_Prune)
|
|
/* Virtual tables are allowed to use constraints like x=NULL. So
|
|
** a term of the form x=y does not prove that y is not null if x
|
|
** is the column of a virtual table */
|
|
fallthrough
|
|
case int32(TK_EQ):
|
|
fallthrough
|
|
case int32(TK_NE):
|
|
fallthrough
|
|
case int32(TK_LT):
|
|
fallthrough
|
|
case int32(TK_LE):
|
|
fallthrough
|
|
case int32(TK_GT):
|
|
fallthrough
|
|
case int32(TK_GE):
|
|
pLeft = (*TExpr)(unsafe.Pointer(pExpr)).FpLeft
|
|
pRight = (*TExpr)(unsafe.Pointer(pExpr)).FpRight
|
|
/* The y.pTab=0 assignment in wherecode.c always happens after the
|
|
** impliesNotNullRow() test */
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pLeft)).Fop) == int32(TK_COLUMN) && *(*uintptr)(unsafe.Pointer(pLeft + 64)) != uintptr(0) && libc.Int32FromUint8((*TTable)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pLeft + 64)))).FeTabType) == int32(TABTYP_VTAB) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pRight)).Fop) == int32(TK_COLUMN) && *(*uintptr)(unsafe.Pointer(pRight + 64)) != uintptr(0) && libc.Int32FromUint8((*TTable)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pRight + 64)))).FeTabType) == int32(TABTYP_VTAB) {
|
|
return int32(WRC_Prune)
|
|
}
|
|
fallthrough
|
|
default:
|
|
return WRC_Continue
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Walk the expression tree pExpr and increase the aggregate function
|
|
// ** depth (the Expr.op2 field) by N on every TK_AGG_FUNCTION node.
|
|
// ** This needs to occur when copying a TK_AGG_FUNCTION node from an
|
|
// ** outer query into an inner subquery.
|
|
// **
|
|
// ** incrAggFunctionDepth(pExpr,n) is the main routine. incrAggDepth(..)
|
|
// ** is a helper function - a callback for the tree walker.
|
|
// **
|
|
// ** See also the sqlite3WindowExtraAggFuncDepth() routine in window.c
|
|
// */
|
|
func _incrAggDepth(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var v1 uintptr
|
|
_ = v1
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_AGG_FUNCTION) {
|
|
v1 = pExpr + 2
|
|
*(*Tu8)(unsafe.Pointer(v1)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v1))) + *(*int32)(unsafe.Pointer(&(*TWalker)(unsafe.Pointer(pWalker)).Fu)))
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Perform a single step of an incremental-vacuum. If successful, return
|
|
// ** SQLITE_OK. If there is no work to do (and therefore no point in
|
|
// ** calling this function again), return SQLITE_DONE. Or, if an error
|
|
// ** occurs, return some other error code.
|
|
// **
|
|
// ** More specifically, this function attempts to re-organize the database so
|
|
// ** that the last page of the file currently in use is no longer in use.
|
|
// **
|
|
// ** Parameter nFin is the number of pages that this database would contain
|
|
// ** were this function called until it returns SQLITE_DONE.
|
|
// **
|
|
// ** If the bCommit parameter is non-zero, this function assumes that the
|
|
// ** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE
|
|
// ** or an error. bCommit is passed true for an auto-vacuum-on-commit
|
|
// ** operation, or false for an incremental vacuum.
|
|
// */
|
|
func _incrVacuumStep(tls *libc.TLS, pBt uintptr, nFin TPgno, iLastPg TPgno, bCommit int32) (r int32) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var dbSize, iNear, nFreeList TPgno
|
|
var eMode Tu8
|
|
var rc int32
|
|
var _ /* eType at bp+0 */ Tu8
|
|
var _ /* iFreePg at bp+24 */ TPgno
|
|
var _ /* iFreePg at bp+8 */ TPgno
|
|
var _ /* iPtrPage at bp+4 */ TPgno
|
|
var _ /* pFreePg at bp+16 */ uintptr
|
|
var _ /* pFreePg at bp+40 */ uintptr
|
|
var _ /* pLastPg at bp+32 */ uintptr
|
|
_, _, _, _, _ = dbSize, eMode, iNear, nFreeList, rc
|
|
if !(_ptrmapPageno(tls, pBt, iLastPg) == iLastPg) && iLastPg != libc.Uint32FromInt32(_sqlite3PendingByte)/(*TBtShared)(unsafe.Pointer(pBt)).FpageSize+libc.Uint32FromInt32(1) {
|
|
nFreeList = _sqlite3Get4byte(tls, (*TMemPage)(unsafe.Pointer((*TBtShared)(unsafe.Pointer(pBt)).FpPage1)).FaData+36)
|
|
if nFreeList == uint32(0) {
|
|
return int32(SQLITE_DONE)
|
|
}
|
|
rc = _ptrmapGet(tls, pBt, iLastPg, bp, bp+4)
|
|
if rc != SQLITE_OK {
|
|
return rc
|
|
}
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(bp))) == int32(PTRMAP_ROOTPAGE) {
|
|
return _sqlite3CorruptError(tls, int32(77285))
|
|
}
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(bp))) == int32(PTRMAP_FREEPAGE) {
|
|
if bCommit == 0 {
|
|
rc = _allocateBtreePage(tls, pBt, bp+16, bp+8, iLastPg, uint8(BTALLOC_EXACT))
|
|
if rc != SQLITE_OK {
|
|
return rc
|
|
}
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp + 16)))
|
|
}
|
|
} else {
|
|
eMode = uint8(BTALLOC_ANY) /* Mode parameter for allocateBtreePage() */
|
|
iNear = uint32(0) /* nearby parameter for allocateBtreePage() */
|
|
rc = _btreeGetPage(tls, pBt, iLastPg, bp+32, 0)
|
|
if rc != SQLITE_OK {
|
|
return rc
|
|
}
|
|
/* If bCommit is zero, this loop runs exactly once and page pLastPg
|
|
** is swapped with the first free page pulled off the free list.
|
|
**
|
|
** On the other hand, if bCommit is greater than zero, then keep
|
|
** looping until a free-page located within the first nFin pages
|
|
** of the file is found.
|
|
*/
|
|
if bCommit == 0 {
|
|
eMode = uint8(BTALLOC_LE)
|
|
iNear = nFin
|
|
}
|
|
for cond := true; cond; cond = bCommit != 0 && **(**TPgno)(__ccgo_up(bp + 24)) > nFin {
|
|
dbSize = _btreePagecount(tls, pBt)
|
|
rc = _allocateBtreePage(tls, pBt, bp+40, bp+24, iNear, eMode)
|
|
if rc != SQLITE_OK {
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp + 32)))
|
|
return rc
|
|
}
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp + 40)))
|
|
if **(**TPgno)(__ccgo_up(bp + 24)) > dbSize {
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp + 32)))
|
|
return _sqlite3CorruptError(tls, int32(77337))
|
|
}
|
|
}
|
|
rc = _relocatePage(tls, pBt, **(**uintptr)(__ccgo_up(bp + 32)), **(**Tu8)(__ccgo_up(bp)), **(**TPgno)(__ccgo_up(bp + 4)), **(**TPgno)(__ccgo_up(bp + 24)), bCommit)
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp + 32)))
|
|
if rc != SQLITE_OK {
|
|
return rc
|
|
}
|
|
}
|
|
}
|
|
if bCommit == 0 {
|
|
for cond := true; cond; cond = iLastPg == libc.Uint32FromInt32(_sqlite3PendingByte)/(*TBtShared)(unsafe.Pointer(pBt)).FpageSize+libc.Uint32FromInt32(1) || _ptrmapPageno(tls, pBt, iLastPg) == iLastPg {
|
|
iLastPg = iLastPg - 1
|
|
}
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FbDoTruncate = uint8(1)
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FnPage = iLastPg
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return True if it is possible that pIndex might be useful in
|
|
// ** implementing the ORDER BY clause in pBuilder.
|
|
// **
|
|
// ** Return False if pBuilder does not contain an ORDER BY clause or
|
|
// ** if there is no way for pIndex to be useful in implementing that
|
|
// ** ORDER BY clause.
|
|
// */
|
|
func _indexMightHelpWithOrderBy(tls *libc.TLS, pBuilder uintptr, pIndex uintptr, iCursor int32) (r int32) {
|
|
var aColExpr, pExpr, pOB, v1 uintptr
|
|
var ii, jj int32
|
|
_, _, _, _, _, _ = aColExpr, ii, jj, pExpr, pOB, v1
|
|
if int32(uint32(*(*uint16)(unsafe.Pointer(pIndex + 100))&0x4>>2)) != 0 {
|
|
return 0
|
|
}
|
|
v1 = (*TWhereInfo)(unsafe.Pointer((*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FpWInfo)).FpOrderBy
|
|
pOB = v1
|
|
if v1 == uintptr(0) {
|
|
return 0
|
|
}
|
|
ii = 0
|
|
for {
|
|
if !(ii < (*TExprList)(unsafe.Pointer(pOB)).FnExpr) {
|
|
break
|
|
}
|
|
pExpr = _sqlite3ExprSkipCollateAndLikely(tls, (*(*TExprList_item)(unsafe.Pointer(pOB + 8 + uintptr(ii)*32))).FpExpr)
|
|
if pExpr == uintptr(0) {
|
|
goto _2
|
|
}
|
|
if (libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_COLUMN) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_AGG_COLUMN)) && (*TExpr)(unsafe.Pointer(pExpr)).FiTable == iCursor {
|
|
if int32((*TExpr)(unsafe.Pointer(pExpr)).FiColumn) < 0 {
|
|
return int32(1)
|
|
}
|
|
jj = 0
|
|
for {
|
|
if !(jj < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIndex)).FnKeyCol)) {
|
|
break
|
|
}
|
|
if int32((*TExpr)(unsafe.Pointer(pExpr)).FiColumn) == int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIndex)).FaiColumn + uintptr(jj)*2))) {
|
|
return int32(1)
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
jj = jj + 1
|
|
}
|
|
} else {
|
|
v1 = (*TIndex)(unsafe.Pointer(pIndex)).FaColExpr
|
|
aColExpr = v1
|
|
if v1 != uintptr(0) {
|
|
jj = 0
|
|
for {
|
|
if !(jj < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIndex)).FnKeyCol)) {
|
|
break
|
|
}
|
|
if int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIndex)).FaiColumn + uintptr(jj)*2))) != -int32(2) {
|
|
goto _5
|
|
}
|
|
if _sqlite3ExprCompareSkip(tls, pExpr, (*(*TExprList_item)(unsafe.Pointer(aColExpr + 8 + uintptr(jj)*32))).FpExpr, iCursor) == 0 {
|
|
return int32(1)
|
|
}
|
|
goto _5
|
|
_5:
|
|
;
|
|
jj = jj + 1
|
|
}
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Populate the pIdx->aAvgEq[] array based on the samples currently
|
|
// ** stored in pIdx->aSample[].
|
|
// */
|
|
func _initAvgEq(tls *libc.TLS, pIdx uintptr) {
|
|
var aSample, pFinal uintptr
|
|
var avgEq, nRow, sumEq TtRowcnt
|
|
var i, iCol, nCol, nSample int32
|
|
var nDist100, nSum100 Ti64
|
|
_, _, _, _, _, _, _, _, _, _, _ = aSample, avgEq, i, iCol, nCol, nDist100, nRow, nSample, nSum100, pFinal, sumEq
|
|
if pIdx != 0 {
|
|
aSample = (*TIndex)(unsafe.Pointer(pIdx)).FaSample
|
|
pFinal = aSample + uintptr((*TIndex)(unsafe.Pointer(pIdx)).FnSample-int32(1))*40
|
|
nCol = int32(1)
|
|
if (*TIndex)(unsafe.Pointer(pIdx)).FnSampleCol > int32(1) {
|
|
/* If this is stat4 data, then calculate aAvgEq[] values for all
|
|
** sample columns except the last. The last is always set to 1, as
|
|
** once the trailing PK fields are considered all index keys are
|
|
** unique. */
|
|
nCol = (*TIndex)(unsafe.Pointer(pIdx)).FnSampleCol - int32(1)
|
|
**(**TtRowcnt)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaAvgEq + uintptr(nCol)*8)) = uint64(1)
|
|
}
|
|
iCol = 0
|
|
for {
|
|
if !(iCol < nCol) {
|
|
break
|
|
}
|
|
nSample = (*TIndex)(unsafe.Pointer(pIdx)).FnSample /* Used to iterate through samples */
|
|
sumEq = uint64(0) /* Sum of the nEq values */
|
|
avgEq = uint64(0) /* Number of rows in index */
|
|
nSum100 = 0 /* Number of distinct values in index */
|
|
if !((*TIndex)(unsafe.Pointer(pIdx)).FaiRowEst != 0) || iCol >= libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol) || **(**TtRowcnt)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiRowEst + uintptr(iCol+int32(1))*8)) == uint64(0) {
|
|
nRow = **(**TtRowcnt)(__ccgo_up((*TIndexSample)(unsafe.Pointer(pFinal)).FanLt + uintptr(iCol)*8))
|
|
nDist100 = libc.Int64FromUint64(libc.Uint64FromInt64(libc.Int64FromInt32(100)) * **(**TtRowcnt)(__ccgo_up((*TIndexSample)(unsafe.Pointer(pFinal)).FanDLt + uintptr(iCol)*8)))
|
|
nSample = nSample - 1
|
|
} else {
|
|
nRow = **(**TtRowcnt)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiRowEst))
|
|
nDist100 = libc.Int64FromUint64(libc.Uint64FromInt64(libc.Int64FromInt32(100)) * **(**TtRowcnt)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiRowEst)) / **(**TtRowcnt)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiRowEst + uintptr(iCol+int32(1))*8)))
|
|
}
|
|
(*TIndex)(unsafe.Pointer(pIdx)).FnRowEst0 = nRow
|
|
/* Set nSum to the number of distinct (iCol+1) field prefixes that
|
|
** occur in the stat4 table for this index. Set sumEq to the sum of
|
|
** the nEq values for column iCol for the same set (adding the value
|
|
** only once where there exist duplicate prefixes). */
|
|
i = 0
|
|
for {
|
|
if !(i < nSample) {
|
|
break
|
|
}
|
|
if i == (*TIndex)(unsafe.Pointer(pIdx)).FnSample-int32(1) || **(**TtRowcnt)(__ccgo_up((**(**TIndexSample)(__ccgo_up(aSample + uintptr(i)*40))).FanDLt + uintptr(iCol)*8)) != **(**TtRowcnt)(__ccgo_up((**(**TIndexSample)(__ccgo_up(aSample + uintptr(i+int32(1))*40))).FanDLt + uintptr(iCol)*8)) {
|
|
sumEq = sumEq + **(**TtRowcnt)(__ccgo_up((**(**TIndexSample)(__ccgo_up(aSample + uintptr(i)*40))).FanEq + uintptr(iCol)*8))
|
|
nSum100 = nSum100 + int64(100)
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if nDist100 > nSum100 && sumEq < nRow {
|
|
avgEq = libc.Uint64FromInt64(libc.Int64FromInt32(100)) * (nRow - sumEq) / libc.Uint64FromInt64(nDist100-nSum100)
|
|
}
|
|
if avgEq == uint64(0) {
|
|
avgEq = uint64(1)
|
|
}
|
|
**(**TtRowcnt)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaAvgEq + uintptr(iCol)*8)) = avgEq
|
|
goto _1
|
|
_1:
|
|
;
|
|
iCol = iCol + 1
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Implementation of the instr() function.
|
|
// **
|
|
// ** instr(haystack,needle) finds the first occurrence of needle
|
|
// ** in haystack and returns the number of previous characters plus 1,
|
|
// ** or 0 if needle does not occur within haystack.
|
|
// **
|
|
// ** If both haystack and needle are BLOBs, then the result is one more than
|
|
// ** the number of bytes in haystack prior to the first occurrence of needle,
|
|
// ** or 0 if needle never occurs in haystack.
|
|
// */
|
|
func _instrFunc(tls *libc.TLS, context uintptr, argc int32, argv uintptr) {
|
|
var N, isText, nHaystack, nNeedle, typeHaystack, typeNeedle int32
|
|
var firstChar uint8
|
|
var pC1, pC2, zHaystack, zNeedle uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _ = N, firstChar, isText, nHaystack, nNeedle, pC1, pC2, typeHaystack, typeNeedle, zHaystack, zNeedle
|
|
N = int32(1)
|
|
pC1 = uintptr(0)
|
|
pC2 = uintptr(0)
|
|
_ = argc
|
|
typeHaystack = Xsqlite3_value_type(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
typeNeedle = Xsqlite3_value_type(tls, **(**uintptr)(__ccgo_up(argv + 1*8)))
|
|
if typeHaystack == int32(SQLITE_NULL) || typeNeedle == int32(SQLITE_NULL) {
|
|
return
|
|
}
|
|
nHaystack = Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
nNeedle = Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(argv + 1*8)))
|
|
if nNeedle > 0 {
|
|
if typeHaystack == int32(SQLITE_BLOB) && typeNeedle == int32(SQLITE_BLOB) {
|
|
zHaystack = Xsqlite3_value_blob(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
zNeedle = Xsqlite3_value_blob(tls, **(**uintptr)(__ccgo_up(argv + 1*8)))
|
|
isText = 0
|
|
} else {
|
|
if typeHaystack != int32(SQLITE_BLOB) && typeNeedle != int32(SQLITE_BLOB) {
|
|
zHaystack = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
zNeedle = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv + 1*8)))
|
|
isText = int32(1)
|
|
} else {
|
|
pC1 = Xsqlite3_value_dup(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
zHaystack = Xsqlite3_value_text(tls, pC1)
|
|
if zHaystack == uintptr(0) {
|
|
goto endInstrOOM
|
|
}
|
|
nHaystack = Xsqlite3_value_bytes(tls, pC1)
|
|
pC2 = Xsqlite3_value_dup(tls, **(**uintptr)(__ccgo_up(argv + 1*8)))
|
|
zNeedle = Xsqlite3_value_text(tls, pC2)
|
|
if zNeedle == uintptr(0) {
|
|
goto endInstrOOM
|
|
}
|
|
nNeedle = Xsqlite3_value_bytes(tls, pC2)
|
|
isText = int32(1)
|
|
}
|
|
}
|
|
if zNeedle == uintptr(0) || nHaystack != 0 && zHaystack == uintptr(0) {
|
|
goto endInstrOOM
|
|
}
|
|
firstChar = **(**uint8)(__ccgo_up(zNeedle))
|
|
for nNeedle <= nHaystack && (libc.Int32FromUint8(**(**uint8)(__ccgo_up(zHaystack))) != libc.Int32FromUint8(firstChar) || libc.Xmemcmp(tls, zHaystack, zNeedle, libc.Uint64FromInt32(nNeedle)) != 0) {
|
|
N = N + 1
|
|
for cond := true; cond; cond = isText != 0 && libc.Int32FromUint8(**(**uint8)(__ccgo_up(zHaystack)))&int32(0xc0) == int32(0x80) {
|
|
nHaystack = nHaystack - 1
|
|
zHaystack = zHaystack + 1
|
|
}
|
|
}
|
|
if nNeedle > nHaystack {
|
|
N = 0
|
|
}
|
|
}
|
|
Xsqlite3_result_int(tls, context, N)
|
|
goto endInstr
|
|
endInstr:
|
|
;
|
|
Xsqlite3_value_free(tls, pC1)
|
|
Xsqlite3_value_free(tls, pC2)
|
|
return
|
|
goto endInstrOOM
|
|
endInstrOOM:
|
|
;
|
|
Xsqlite3_result_error_nomem(tls, context)
|
|
goto endInstr
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Check to see if the pExpr expression is a form that needs to be passed
|
|
// ** to the xBestIndex method of virtual tables. Forms of interest include:
|
|
// **
|
|
// ** Expression Virtual Table Operator
|
|
// ** ----------------------- ---------------------------------
|
|
// ** 1. column MATCH expr SQLITE_INDEX_CONSTRAINT_MATCH
|
|
// ** 2. column GLOB expr SQLITE_INDEX_CONSTRAINT_GLOB
|
|
// ** 3. column LIKE expr SQLITE_INDEX_CONSTRAINT_LIKE
|
|
// ** 4. column REGEXP expr SQLITE_INDEX_CONSTRAINT_REGEXP
|
|
// ** 5. column != expr SQLITE_INDEX_CONSTRAINT_NE
|
|
// ** 6. expr != column SQLITE_INDEX_CONSTRAINT_NE
|
|
// ** 7. column IS NOT expr SQLITE_INDEX_CONSTRAINT_ISNOT
|
|
// ** 8. expr IS NOT column SQLITE_INDEX_CONSTRAINT_ISNOT
|
|
// ** 9. column IS NOT NULL SQLITE_INDEX_CONSTRAINT_ISNOTNULL
|
|
// **
|
|
// ** In every case, "column" must be a column of a virtual table. If there
|
|
// ** is a match, set *ppLeft to the "column" expression, set *ppRight to the
|
|
// ** "expr" expression (even though in forms (6) and (8) the column is on the
|
|
// ** right and the expression is on the left). Also set *peOp2 to the
|
|
// ** appropriate virtual table operator. The return value is 1 or 2 if there
|
|
// ** is a match. The usual return is 1, but if the RHS is also a column
|
|
// ** of virtual table in forms (5) or (7) then return 2.
|
|
// **
|
|
// ** If the expression matches none of the patterns above, return 0.
|
|
// */
|
|
func _isAuxiliaryVtabOperator(tls *libc.TLS, db uintptr, pExpr uintptr, peOp2 uintptr, ppLeft uintptr, ppRight uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var i, res, v1 int32
|
|
var pCol, pLeft, pList, pMod, pRight, pVtab, t uintptr
|
|
var v2 bool
|
|
var _ /* pNotUsed at bp+8 */ uintptr
|
|
var _ /* xNotUsed at bp+0 */ uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _ = i, pCol, pLeft, pList, pMod, pRight, pVtab, res, t, v1, v2
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_FUNCTION) {
|
|
pList = *(*uintptr)(unsafe.Pointer(pExpr + 32))
|
|
if pList == uintptr(0) || (*TExprList)(unsafe.Pointer(pList)).FnExpr != int32(2) {
|
|
return 0
|
|
}
|
|
/* Built-in operators MATCH, GLOB, LIKE, and REGEXP attach to a
|
|
** virtual table on their second argument, which is the same as
|
|
** the left-hand side operand in their in-fix form.
|
|
**
|
|
** vtab_column MATCH expression
|
|
** MATCH(expression,vtab_column)
|
|
*/
|
|
pCol = (*(*TExprList_item)(unsafe.Pointer(pList + 8 + 1*32))).FpExpr
|
|
if v2 = libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pCol)).Fop) == int32(TK_COLUMN) && libc.Int32FromUint8((*TTable)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pCol + 64)))).FeTabType) == int32(TABTYP_VTAB); v2 {
|
|
v1 = _sqlite3ExprIsLikeOperator(tls, pExpr)
|
|
i = v1
|
|
}
|
|
if v2 && v1 != 0 {
|
|
**(**uint8)(__ccgo_up(peOp2)) = libc.Uint8FromInt32(i)
|
|
**(**uintptr)(__ccgo_up(ppRight)) = (*(*TExprList_item)(unsafe.Pointer(pList + 8))).FpExpr
|
|
**(**uintptr)(__ccgo_up(ppLeft)) = pCol
|
|
return int32(1)
|
|
}
|
|
/* We can also match against the first column of overloaded
|
|
** functions where xFindFunction returns a value of at least
|
|
** SQLITE_INDEX_CONSTRAINT_FUNCTION.
|
|
**
|
|
** OVERLOADED(vtab_column,expression)
|
|
**
|
|
** Historically, xFindFunction expected to see lower-case function
|
|
** names. But for this use case, xFindFunction is expected to deal
|
|
** with function names in an arbitrary case.
|
|
*/
|
|
pCol = (*(*TExprList_item)(unsafe.Pointer(pList + 8))).FpExpr
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pCol)).Fop) == int32(TK_COLUMN) && libc.Int32FromUint8((*TTable)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pCol + 64)))).FeTabType) == int32(TABTYP_VTAB) {
|
|
pVtab = (*TVTable)(unsafe.Pointer(_sqlite3GetVTable(tls, db, *(*uintptr)(unsafe.Pointer(pCol + 64))))).FpVtab
|
|
pMod = (*Tsqlite3_vtab)(unsafe.Pointer(pVtab)).FpModule
|
|
if (*Tsqlite3_module)(unsafe.Pointer(pMod)).FxFindFunction != uintptr(0) {
|
|
i = (*(*func(*libc.TLS, uintptr, int32, uintptr, uintptr, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{(*Tsqlite3_module)(unsafe.Pointer(pMod)).FxFindFunction})))(tls, pVtab, int32(2), *(*uintptr)(unsafe.Pointer(pExpr + 8)), bp, bp+8)
|
|
if i >= int32(SQLITE_INDEX_CONSTRAINT_FUNCTION) {
|
|
**(**uint8)(__ccgo_up(peOp2)) = libc.Uint8FromInt32(i)
|
|
**(**uintptr)(__ccgo_up(ppRight)) = (*(*TExprList_item)(unsafe.Pointer(pList + 8 + 1*32))).FpExpr
|
|
**(**uintptr)(__ccgo_up(ppLeft)) = pCol
|
|
return int32(1)
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) >= int32(TK_EQ) {
|
|
/* Comparison operators are a common case. Save a few comparisons for
|
|
** that common case by terminating early. */
|
|
return 0
|
|
} else {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_NE) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_ISNOT) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_NOTNULL) {
|
|
res = 0
|
|
pLeft = (*TExpr)(unsafe.Pointer(pExpr)).FpLeft
|
|
pRight = (*TExpr)(unsafe.Pointer(pExpr)).FpRight
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pLeft)).Fop) == int32(TK_COLUMN) && libc.Int32FromUint8((*TTable)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pLeft + 64)))).FeTabType) == int32(TABTYP_VTAB) {
|
|
res = res + 1
|
|
}
|
|
if pRight != 0 && (libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pRight)).Fop) == int32(TK_COLUMN) && libc.Int32FromUint8((*TTable)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pRight + 64)))).FeTabType) == int32(TABTYP_VTAB)) {
|
|
res = res + 1
|
|
t = pLeft
|
|
pLeft = pRight
|
|
pRight = t
|
|
}
|
|
**(**uintptr)(__ccgo_up(ppLeft)) = pLeft
|
|
**(**uintptr)(__ccgo_up(ppRight)) = pRight
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_NE) {
|
|
**(**uint8)(__ccgo_up(peOp2)) = uint8(SQLITE_INDEX_CONSTRAINT_NE)
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_ISNOT) {
|
|
**(**uint8)(__ccgo_up(peOp2)) = uint8(SQLITE_INDEX_CONSTRAINT_ISNOT)
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_NOTNULL) {
|
|
**(**uint8)(__ccgo_up(peOp2)) = uint8(SQLITE_INDEX_CONSTRAINT_ISNOTNULL)
|
|
}
|
|
return res
|
|
}
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** pX is the RHS of an IN operator. If pX is a SELECT statement
|
|
// ** that can be simplified to a direct table access, then return
|
|
// ** a pointer to the SELECT statement. If pX is not a SELECT statement,
|
|
// ** or if the SELECT statement needs to be materialized into a transient
|
|
// ** table, then return NULL.
|
|
// */
|
|
func _isCandidateForInOpt(tls *libc.TLS, pX uintptr) (r uintptr) {
|
|
var i int32
|
|
var p, pEList, pRes, pSrc, pTab uintptr
|
|
_, _, _, _, _, _ = i, p, pEList, pRes, pSrc, pTab
|
|
if !((*TExpr)(unsafe.Pointer(pX)).Fflags&libc.Uint32FromInt32(EP_xIsSelect) != libc.Uint32FromInt32(0)) {
|
|
return uintptr(0)
|
|
} /* Not a subquery */
|
|
if (*TExpr)(unsafe.Pointer(pX)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_VarSelect)) != uint32(0) {
|
|
return uintptr(0)
|
|
} /* Correlated subq */
|
|
p = *(*uintptr)(unsafe.Pointer(pX + 32))
|
|
if (*TSelect)(unsafe.Pointer(p)).FpPrior != 0 {
|
|
return uintptr(0)
|
|
} /* Not a compound SELECT */
|
|
if (*TSelect)(unsafe.Pointer(p)).FselFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SF_Distinct)|libc.Int32FromInt32(SF_Aggregate)) != 0 {
|
|
return uintptr(0) /* No DISTINCT keyword and no aggregate functions */
|
|
}
|
|
/* Has no GROUP BY clause */
|
|
if (*TSelect)(unsafe.Pointer(p)).FpLimit != 0 {
|
|
return uintptr(0)
|
|
} /* Has no LIMIT clause */
|
|
if (*TSelect)(unsafe.Pointer(p)).FpWhere != 0 {
|
|
return uintptr(0)
|
|
} /* Has no WHERE clause */
|
|
pSrc = (*TSelect)(unsafe.Pointer(p)).FpSrc
|
|
if (*TSrcList)(unsafe.Pointer(pSrc)).FnSrc != int32(1) {
|
|
return uintptr(0)
|
|
} /* Single term in FROM clause */
|
|
if int32(*(*uint32)(unsafe.Pointer(pSrc + 8 + 24 + 4))&0x4>>2) != 0 {
|
|
return uintptr(0)
|
|
} /* FROM is not a subquery or view */
|
|
pTab = (*(*TSrcItem)(unsafe.Pointer(pSrc + 8))).FpSTab
|
|
/* FROM clause is not a view */
|
|
if libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == int32(TABTYP_VTAB) {
|
|
return uintptr(0)
|
|
} /* FROM clause not a virtual table */
|
|
pEList = (*TSelect)(unsafe.Pointer(p)).FpEList
|
|
/* All SELECT results must be columns. */
|
|
i = 0
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(pEList)).FnExpr) {
|
|
break
|
|
}
|
|
pRes = (*(*TExprList_item)(unsafe.Pointer(pEList + 8 + uintptr(i)*32))).FpExpr
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pRes)).Fop) != int32(TK_COLUMN) {
|
|
return uintptr(0)
|
|
}
|
|
/* Not a correlated subquery */
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return p
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if the DISTINCT expression-list passed as the third argument
|
|
// ** is redundant.
|
|
// **
|
|
// ** A DISTINCT list is redundant if any subset of the columns in the
|
|
// ** DISTINCT list are collectively unique and individually non-null.
|
|
// */
|
|
func _isDistinctRedundant(tls *libc.TLS, pParse uintptr, pTabList uintptr, pWC uintptr, pDistinct uintptr) (r int32) {
|
|
var i, iBase int32
|
|
var p, pIdx, pTab uintptr
|
|
_, _, _, _, _ = i, iBase, p, pIdx, pTab
|
|
/* If there is more than one table or sub-select in the FROM clause of
|
|
** this query, then it will not be possible to show that the DISTINCT
|
|
** clause is redundant. */
|
|
if (*TSrcList)(unsafe.Pointer(pTabList)).FnSrc != int32(1) {
|
|
return 0
|
|
}
|
|
iBase = (*(*TSrcItem)(unsafe.Pointer(pTabList + 8))).FiCursor
|
|
pTab = (*(*TSrcItem)(unsafe.Pointer(pTabList + 8))).FpSTab
|
|
/* If any of the expressions is an IPK column on table iBase, then return
|
|
** true. Note: The (p->iTable==iBase) part of this test may be false if the
|
|
** current SELECT is a correlated sub-query.
|
|
*/
|
|
i = 0
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(pDistinct)).FnExpr) {
|
|
break
|
|
}
|
|
p = _sqlite3ExprSkipCollateAndLikely(tls, (*(*TExprList_item)(unsafe.Pointer(pDistinct + 8 + uintptr(i)*32))).FpExpr)
|
|
if p == uintptr(0) {
|
|
goto _1
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) != int32(TK_COLUMN) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) != int32(TK_AGG_COLUMN) {
|
|
goto _1
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(p)).FiTable == iBase && int32((*TExpr)(unsafe.Pointer(p)).FiColumn) < 0 {
|
|
return int32(1)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
/* Loop through all indices on the table, checking each to see if it makes
|
|
** the DISTINCT qualifier redundant. It does so if:
|
|
**
|
|
** 1. The index is itself UNIQUE, and
|
|
**
|
|
** 2. All of the columns in the index are either part of the pDistinct
|
|
** list, or else the WHERE clause contains a term of the form "col=X",
|
|
** where X is a constant value. The collation sequences of the
|
|
** comparison and select-list expressions must match those of the index.
|
|
**
|
|
** 3. All of those index columns for which the WHERE clause does not
|
|
** contain a "col=X" term are subject to a NOT NULL constraint.
|
|
*/
|
|
pIdx = (*TTable)(unsafe.Pointer(pTab)).FpIndex
|
|
for {
|
|
if !(pIdx != 0) {
|
|
break
|
|
}
|
|
if !(libc.Int32FromUint8((*TIndex)(unsafe.Pointer(pIdx)).FonError) != libc.Int32FromInt32(OE_None)) {
|
|
goto _2
|
|
}
|
|
if (*TIndex)(unsafe.Pointer(pIdx)).FpPartIdxWhere != 0 {
|
|
goto _2
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol)) {
|
|
break
|
|
}
|
|
if uintptr(0) == _sqlite3WhereFindTerm(tls, pWC, iBase, i, ^libc.Uint64FromInt32(0), uint32(WO_EQ), pIdx) {
|
|
if _findIndexCol(tls, pParse, pDistinct, iBase, pIdx, i) < 0 {
|
|
break
|
|
}
|
|
if _indexColumnNotNull(tls, pIdx, i) == 0 {
|
|
break
|
|
}
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if i == libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol) {
|
|
/* This index implies that the DISTINCT qualifier is redundant. */
|
|
return int32(1)
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
pIdx = (*TIndex)(unsafe.Pointer(pIdx)).FpNext
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if the parser passed as the first argument is being
|
|
// ** used to code a trigger that is really a "SET NULL" action belonging
|
|
// ** to trigger pFKey.
|
|
// */
|
|
func _isSetNullAction(tls *libc.TLS, pParse uintptr, pFKey uintptr) (r int32) {
|
|
var p, pTop, v1 uintptr
|
|
_, _, _ = p, pTop, v1
|
|
if (*TParse)(unsafe.Pointer(pParse)).FpToplevel != 0 {
|
|
v1 = (*TParse)(unsafe.Pointer(pParse)).FpToplevel
|
|
} else {
|
|
v1 = pParse
|
|
}
|
|
pTop = v1
|
|
if (*TParse)(unsafe.Pointer(pTop)).FpTriggerPrg != 0 {
|
|
p = (*TTriggerPrg)(unsafe.Pointer((*TParse)(unsafe.Pointer(pTop)).FpTriggerPrg)).FpTrigger
|
|
if p == **(**uintptr)(__ccgo_up(pFKey + 48)) && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pFKey + 45))) == int32(OE_SetNull) || p == **(**uintptr)(__ccgo_up(pFKey + 48 + 1*8)) && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pFKey + 45 + 1))) == int32(OE_SetNull) {
|
|
return int32(1)
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The select statement passed as the first argument is an aggregate query.
|
|
// ** The second argument is the associated aggregate-info object. This
|
|
// ** function tests if the SELECT is of the form:
|
|
// **
|
|
// ** SELECT count(*) FROM <tbl>
|
|
// **
|
|
// ** where table is a database table, not a sub-select or view. If the query
|
|
// ** does match this pattern, then a pointer to the Table object representing
|
|
// ** <tbl> is returned. Otherwise, NULL is returned.
|
|
// **
|
|
// ** This routine checks to see if it is safe to use the count optimization.
|
|
// ** A correct answer is still obtained (though perhaps more slowly) if
|
|
// ** this routine returns NULL when it could have returned a table pointer.
|
|
// ** But returning the pointer when NULL should have been returned can
|
|
// ** result in incorrect answers and/or crashes. So, when in doubt, return NULL.
|
|
// */
|
|
func _isSimpleCount(tls *libc.TLS, p uintptr, pAggInfo uintptr) (r uintptr) {
|
|
var pExpr, pTab uintptr
|
|
_, _ = pExpr, pTab
|
|
if (*TSelect)(unsafe.Pointer(p)).FpWhere != 0 || (*TExprList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(p)).FpEList)).FnExpr != int32(1) || (*TSrcList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(p)).FpSrc)).FnSrc != int32(1) || int32(*(*uint32)(unsafe.Pointer((*TSelect)(unsafe.Pointer(p)).FpSrc + 8 + 24 + 4))&0x4>>2) != 0 || (*TAggInfo)(unsafe.Pointer(pAggInfo)).FnFunc != int32(1) || (*TSelect)(unsafe.Pointer(p)).FpHaving != 0 {
|
|
return uintptr(0)
|
|
}
|
|
pTab = (*(*TSrcItem)(unsafe.Pointer((*TSelect)(unsafe.Pointer(p)).FpSrc + 8))).FpSTab
|
|
if !(libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == libc.Int32FromInt32(TABTYP_NORM)) {
|
|
return uintptr(0)
|
|
}
|
|
pExpr = (*(*TExprList_item)(unsafe.Pointer((*TSelect)(unsafe.Pointer(p)).FpEList + 8))).FpExpr
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) != int32(TK_AGG_FUNCTION) {
|
|
return uintptr(0)
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).FpAggInfo != pAggInfo {
|
|
return uintptr(0)
|
|
}
|
|
if (*TFuncDef)(unsafe.Pointer((**(**TAggInfo_func)(__ccgo_up((*TAggInfo)(unsafe.Pointer(pAggInfo)).FaFunc))).FpFunc)).FfuncFlags&uint32(SQLITE_FUNC_COUNT) == uint32(0) {
|
|
return uintptr(0)
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Distinct)|libc.Int32FromInt32(EP_WinFunc)) != uint32(0) {
|
|
return uintptr(0)
|
|
}
|
|
return pTab
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Edit the payload size of the element at iRoot by the amount in
|
|
// ** pParse->delta.
|
|
// */
|
|
func _jsonAfterEditSizeAdjust(tls *libc.TLS, pParse uintptr, iRoot Tu32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var nBlob Tu32
|
|
var _ /* sz at bp+0 */ Tu32
|
|
_ = nBlob
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(0)
|
|
nBlob = (*TJsonParse)(unsafe.Pointer(pParse)).FnBlob
|
|
(*TJsonParse)(unsafe.Pointer(pParse)).FnBlob = (*TJsonParse)(unsafe.Pointer(pParse)).FnBlobAlloc
|
|
_jsonbPayloadSize(tls, pParse, iRoot, bp)
|
|
(*TJsonParse)(unsafe.Pointer(pParse)).FnBlob = nBlob
|
|
**(**Tu32)(__ccgo_up(bp)) = **(**Tu32)(__ccgo_up(bp)) + libc.Uint32FromInt32((*TJsonParse)(unsafe.Pointer(pParse)).Fdelta)
|
|
**(**int32)(__ccgo_up(pParse + 52)) += _jsonBlobChangePayloadSize(tls, pParse, iRoot, **(**Tu32)(__ccgo_up(bp)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Expand pParse->aBlob and append one bytes.
|
|
// */
|
|
func _jsonBlobExpandAndAppendOneByte(tls *libc.TLS, pParse uintptr, c Tu8) {
|
|
var v1 Tu32
|
|
var v2 uintptr
|
|
_, _ = v1, v2
|
|
_jsonBlobExpand(tls, pParse, (*TJsonParse)(unsafe.Pointer(pParse)).FnBlob+uint32(1))
|
|
if libc.Int32FromUint8((*TJsonParse)(unsafe.Pointer(pParse)).Foom) == 0 {
|
|
v2 = pParse + 8
|
|
v1 = *(*Tu32)(unsafe.Pointer(v2))
|
|
*(*Tu32)(unsafe.Pointer(v2)) = *(*Tu32)(unsafe.Pointer(v2)) + 1
|
|
**(**Tu8)(__ccgo_up((*TJsonParse)(unsafe.Pointer(pParse)).FaBlob + uintptr(v1))) = c
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Advance the cursor to the next element for json_tree() */
|
|
func _jsonEachNext(tls *libc.TLS, cur uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var i, i1, iVal, n, n1 Tu32
|
|
var levelChange, x Tu8
|
|
var nNew Tu64
|
|
var p, pNew, pParent, pParent1 uintptr
|
|
var rc int32
|
|
var _ /* sz at bp+0 */ Tu32
|
|
var _ /* sz at bp+4 */ Tu32
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _ = i, i1, iVal, levelChange, n, n1, nNew, p, pNew, pParent, pParent1, rc, x
|
|
p = cur
|
|
rc = SQLITE_OK
|
|
if (*TJsonEachCursor)(unsafe.Pointer(p)).FbRecursive != 0 {
|
|
levelChange = uint8(0)
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(0)
|
|
i = libc.Uint32FromInt32(_jsonSkipLabel(tls, p))
|
|
x = libc.Uint8FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TJsonEachCursor)(unsafe.Pointer(p)).FsParse.FaBlob + uintptr(i)))) & int32(0x0f))
|
|
n = _jsonbPayloadSize(tls, p+192, i, bp)
|
|
if libc.Int32FromUint8(x) == int32(JSONB_OBJECT) || libc.Int32FromUint8(x) == int32(JSONB_ARRAY) {
|
|
if (*TJsonEachCursor)(unsafe.Pointer(p)).FnParent >= (*TJsonEachCursor)(unsafe.Pointer(p)).FnParentAlloc {
|
|
nNew = uint64((*TJsonEachCursor)(unsafe.Pointer(p)).FnParentAlloc*uint32(2) + uint32(3))
|
|
pNew = _sqlite3DbRealloc(tls, (*TJsonEachCursor)(unsafe.Pointer(p)).Fdb, (*TJsonEachCursor)(unsafe.Pointer(p)).FaParent, uint64(24)*nNew)
|
|
if pNew == uintptr(0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
(*TJsonEachCursor)(unsafe.Pointer(p)).FnParentAlloc = uint32(nNew)
|
|
(*TJsonEachCursor)(unsafe.Pointer(p)).FaParent = pNew
|
|
}
|
|
levelChange = uint8(1)
|
|
pParent = (*TJsonEachCursor)(unsafe.Pointer(p)).FaParent + uintptr((*TJsonEachCursor)(unsafe.Pointer(p)).FnParent)*24
|
|
(*TJsonParent)(unsafe.Pointer(pParent)).FiHead = (*TJsonEachCursor)(unsafe.Pointer(p)).Fi
|
|
(*TJsonParent)(unsafe.Pointer(pParent)).FiValue = i
|
|
(*TJsonParent)(unsafe.Pointer(pParent)).FiEnd = i + n + **(**Tu32)(__ccgo_up(bp))
|
|
(*TJsonParent)(unsafe.Pointer(pParent)).FiKey = int64(-int32(1))
|
|
(*TJsonParent)(unsafe.Pointer(pParent)).FnPath = uint32((*TJsonEachCursor)(unsafe.Pointer(p)).Fpath.FnUsed)
|
|
if (*TJsonEachCursor)(unsafe.Pointer(p)).FeType != 0 && (*TJsonEachCursor)(unsafe.Pointer(p)).FnParent != 0 {
|
|
_jsonAppendPathName(tls, p)
|
|
if (*TJsonEachCursor)(unsafe.Pointer(p)).Fpath.FeErr != 0 {
|
|
rc = int32(SQLITE_NOMEM)
|
|
}
|
|
}
|
|
(*TJsonEachCursor)(unsafe.Pointer(p)).FnParent = (*TJsonEachCursor)(unsafe.Pointer(p)).FnParent + 1
|
|
(*TJsonEachCursor)(unsafe.Pointer(p)).Fi = i + n
|
|
} else {
|
|
(*TJsonEachCursor)(unsafe.Pointer(p)).Fi = i + n + **(**Tu32)(__ccgo_up(bp))
|
|
}
|
|
for (*TJsonEachCursor)(unsafe.Pointer(p)).FnParent > uint32(0) && (*TJsonEachCursor)(unsafe.Pointer(p)).Fi >= (**(**TJsonParent)(__ccgo_up((*TJsonEachCursor)(unsafe.Pointer(p)).FaParent + uintptr((*TJsonEachCursor)(unsafe.Pointer(p)).FnParent-uint32(1))*24))).FiEnd {
|
|
(*TJsonEachCursor)(unsafe.Pointer(p)).FnParent = (*TJsonEachCursor)(unsafe.Pointer(p)).FnParent - 1
|
|
(*TJsonEachCursor)(unsafe.Pointer(p)).Fpath.FnUsed = uint64((**(**TJsonParent)(__ccgo_up((*TJsonEachCursor)(unsafe.Pointer(p)).FaParent + uintptr((*TJsonEachCursor)(unsafe.Pointer(p)).FnParent)*24))).FnPath)
|
|
levelChange = uint8(1)
|
|
}
|
|
if levelChange != 0 {
|
|
if (*TJsonEachCursor)(unsafe.Pointer(p)).FnParent > uint32(0) {
|
|
pParent1 = (*TJsonEachCursor)(unsafe.Pointer(p)).FaParent + uintptr((*TJsonEachCursor)(unsafe.Pointer(p)).FnParent-uint32(1))*24
|
|
iVal = (*TJsonParent)(unsafe.Pointer(pParent1)).FiValue
|
|
(*TJsonEachCursor)(unsafe.Pointer(p)).FeType = libc.Uint8FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TJsonEachCursor)(unsafe.Pointer(p)).FsParse.FaBlob + uintptr(iVal)))) & int32(0x0f))
|
|
} else {
|
|
(*TJsonEachCursor)(unsafe.Pointer(p)).FeType = uint8(0)
|
|
}
|
|
}
|
|
} else {
|
|
**(**Tu32)(__ccgo_up(bp + 4)) = uint32(0)
|
|
i1 = libc.Uint32FromInt32(_jsonSkipLabel(tls, p))
|
|
n1 = _jsonbPayloadSize(tls, p+192, i1, bp+4)
|
|
(*TJsonEachCursor)(unsafe.Pointer(p)).Fi = i1 + n1 + **(**Tu32)(__ccgo_up(bp + 4))
|
|
}
|
|
if libc.Int32FromUint8((*TJsonEachCursor)(unsafe.Pointer(p)).FeType) == int32(JSONB_ARRAY) && (*TJsonEachCursor)(unsafe.Pointer(p)).FnParent != 0 {
|
|
(**(**TJsonParent)(__ccgo_up((*TJsonEachCursor)(unsafe.Pointer(p)).FaParent + uintptr((*TJsonEachCursor)(unsafe.Pointer(p)).FnParent-uint32(1))*24))).FiKey = (**(**TJsonParent)(__ccgo_up((*TJsonEachCursor)(unsafe.Pointer(p)).FaParent + uintptr((*TJsonEachCursor)(unsafe.Pointer(p)).FnParent-uint32(1))*24))).FiKey + 1
|
|
}
|
|
(*TJsonEachCursor)(unsafe.Pointer(p)).FiRowid = (*TJsonEachCursor)(unsafe.Pointer(p)).FiRowid + 1
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Append formatted text (not to exceed N bytes) to the JsonString.
|
|
// */
|
|
func _jsonPrintf(tls *libc.TLS, N int32, p uintptr, zFormat uintptr, va uintptr) {
|
|
var ap Tva_list
|
|
_ = ap
|
|
if (*TJsonString)(unsafe.Pointer(p)).FnUsed+libc.Uint64FromInt32(N) >= (*TJsonString)(unsafe.Pointer(p)).FnAlloc && _jsonStringGrow(tls, p, libc.Uint32FromInt32(N)) != 0 {
|
|
return
|
|
}
|
|
ap = va
|
|
Xsqlite3_vsnprintf(tls, N, (*TJsonString)(unsafe.Pointer(p)).FzBuf+uintptr((*TJsonString)(unsafe.Pointer(p)).FnUsed), zFormat, ap)
|
|
_ = ap
|
|
**(**Tu64)(__ccgo_up(p + 24)) += libc.Uint64FromInt32(libc.Int32FromUint64(libc.Xstrlen(tls, (*TJsonString)(unsafe.Pointer(p)).FzBuf+uintptr((*TJsonString)(unsafe.Pointer(p)).FnUsed))))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Make the return value of a JSON function either the raw JSONB blob
|
|
// ** or make it JSON text, depending on whether the JSON_BLOB flag is
|
|
// ** set on the function.
|
|
// */
|
|
func _jsonReturnParse(tls *libc.TLS, ctx uintptr, p uintptr) {
|
|
bp := tls.Alloc(144)
|
|
defer tls.Free(144)
|
|
var flgs int32
|
|
var _ /* s at bp+0 */ TJsonString
|
|
_ = flgs
|
|
if (*TJsonParse)(unsafe.Pointer(p)).Foom != 0 {
|
|
Xsqlite3_result_error_nomem(tls, ctx)
|
|
return
|
|
}
|
|
flgs = int32(int64(Xsqlite3_user_data(tls, ctx)))
|
|
if flgs&int32(JSON_BLOB) != 0 {
|
|
if (*TJsonParse)(unsafe.Pointer(p)).FnBlobAlloc > uint32(0) && !((*TJsonParse)(unsafe.Pointer(p)).FbReadOnly != 0) {
|
|
Xsqlite3_result_blob(tls, ctx, (*TJsonParse)(unsafe.Pointer(p)).FaBlob, libc.Int32FromUint32((*TJsonParse)(unsafe.Pointer(p)).FnBlob), __ccgo_fp(_sqlite3RowSetClear))
|
|
(*TJsonParse)(unsafe.Pointer(p)).FnBlobAlloc = uint32(0)
|
|
} else {
|
|
Xsqlite3_result_blob(tls, ctx, (*TJsonParse)(unsafe.Pointer(p)).FaBlob, libc.Int32FromUint32((*TJsonParse)(unsafe.Pointer(p)).FnBlob), uintptr(-libc.Int32FromInt32(1)))
|
|
}
|
|
} else {
|
|
_jsonStringInit(tls, bp, ctx)
|
|
(*TJsonParse)(unsafe.Pointer(p)).Fdelta = 0
|
|
_jsonTranslateBlobToText(tls, p, uint32(0), bp)
|
|
_jsonReturnString(tls, bp, p, ctx)
|
|
Xsqlite3_result_subtype(tls, ctx, uint32(JSON_SUBTYPE))
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
** SQL functions used for testing and debugging
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
** Scalar SQL function implementations
|
|
****************************************************************************/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** json_set(JSON, PATH, VALUE, ...)
|
|
// **
|
|
// ** Set the value at PATH to VALUE. Create the PATH if it does not already
|
|
// ** exist. Overwrite existing values that do exist.
|
|
// ** If JSON or PATH is malformed, throw an error.
|
|
// **
|
|
// ** json_insert(JSON, PATH, VALUE, ...)
|
|
// **
|
|
// ** Create PATH and initialize it to VALUE. If PATH already exists, this
|
|
// ** routine is a no-op. If JSON or PATH is malformed, throw an error.
|
|
// */
|
|
func _jsonSetFunc(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr) {
|
|
var eInsType, flags int32
|
|
_, _ = eInsType, flags
|
|
flags = int32(int64(Xsqlite3_user_data(tls, ctx)))
|
|
eInsType = flags & int32(0xC) >> int32(2)
|
|
if argc < int32(1) {
|
|
return
|
|
}
|
|
if argc&int32(1) == 0 {
|
|
_jsonWrongNumArgs(tls, ctx, _azInsType[eInsType])
|
|
return
|
|
}
|
|
_jsonInsertIntoBlob(tls, ctx, argc, argv, libc.Int32FromUint8(_aEditType[eInsType]))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If the cursor is currently pointing at the label of a object entry,
|
|
// ** then return the index of the value. For all other cases, return the
|
|
// ** current pointer position, which is the value.
|
|
// */
|
|
func _jsonSkipLabel(tls *libc.TLS, p uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var n Tu32
|
|
var _ /* sz at bp+0 */ Tu32
|
|
_ = n
|
|
if libc.Int32FromUint8((*TJsonEachCursor)(unsafe.Pointer(p)).FeType) == int32(JSONB_OBJECT) {
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(0)
|
|
n = _jsonbPayloadSize(tls, p+192, (*TJsonEachCursor)(unsafe.Pointer(p)).Fi, bp)
|
|
return libc.Int32FromUint32((*TJsonEachCursor)(unsafe.Pointer(p)).Fi + n + **(**Tu32)(__ccgo_up(bp)))
|
|
} else {
|
|
return libc.Int32FromUint32((*TJsonEachCursor)(unsafe.Pointer(p)).Fi)
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Implementation of the length() function
|
|
// */
|
|
func _lengthFunc(tls *libc.TLS, context uintptr, argc int32, argv uintptr) {
|
|
var c, v1 uint8
|
|
var z, z0 uintptr
|
|
_, _, _, _ = c, z, z0, v1
|
|
_ = argc
|
|
switch Xsqlite3_value_type(tls, **(**uintptr)(__ccgo_up(argv))) {
|
|
case int32(SQLITE_BLOB):
|
|
fallthrough
|
|
case int32(SQLITE_INTEGER):
|
|
fallthrough
|
|
case int32(SQLITE_FLOAT):
|
|
Xsqlite3_result_int(tls, context, Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(argv))))
|
|
case int32(SQLITE_TEXT):
|
|
z = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
if z == uintptr(0) {
|
|
return
|
|
}
|
|
z0 = z
|
|
for {
|
|
v1 = **(**uint8)(__ccgo_up(z))
|
|
c = v1
|
|
if !(libc.Int32FromUint8(v1) != 0) {
|
|
break
|
|
}
|
|
z = z + 1
|
|
if libc.Int32FromUint8(c) >= int32(0xc0) {
|
|
for libc.Int32FromUint8(**(**uint8)(__ccgo_up(z)))&int32(0xc0) == int32(0x80) {
|
|
z = z + 1
|
|
z0 = z0 + 1
|
|
}
|
|
}
|
|
}
|
|
Xsqlite3_result_int(tls, context, int32(int64(z)-int64(z0)))
|
|
default:
|
|
Xsqlite3_result_null(tls, context)
|
|
break
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Record the fact that we want to lock a table at run-time.
|
|
// **
|
|
// ** The table to be locked has root page iTab and is found in database iDb.
|
|
// ** A read or a write lock can be taken depending on isWritelock.
|
|
// **
|
|
// ** This routine just records the fact that the lock is desired. The
|
|
// ** code to make the lock occur is generated by a later call to
|
|
// ** codeTableLocks() which occurs during sqlite3FinishCoding().
|
|
// */
|
|
func _lockTable(tls *libc.TLS, pParse uintptr, iDb int32, iTab TPgno, isWriteLock Tu8, zName uintptr) {
|
|
var i, nBytes, v3 int32
|
|
var p, pToplevel, v1 uintptr
|
|
_, _, _, _, _, _ = i, nBytes, p, pToplevel, v1, v3
|
|
if (*TParse)(unsafe.Pointer(pParse)).FpToplevel != 0 {
|
|
v1 = (*TParse)(unsafe.Pointer(pParse)).FpToplevel
|
|
} else {
|
|
v1 = pParse
|
|
}
|
|
pToplevel = v1
|
|
i = 0
|
|
for {
|
|
if !(i < (*TParse)(unsafe.Pointer(pToplevel)).FnTableLock) {
|
|
break
|
|
}
|
|
p = (*TParse)(unsafe.Pointer(pToplevel)).FaTableLock + uintptr(i)*24
|
|
if (*TTableLock)(unsafe.Pointer(p)).FiDb == iDb && (*TTableLock)(unsafe.Pointer(p)).FiTab == iTab {
|
|
(*TTableLock)(unsafe.Pointer(p)).FisWriteLock = libc.BoolUint8((*TTableLock)(unsafe.Pointer(p)).FisWriteLock != 0 || isWriteLock != 0)
|
|
return
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
nBytes = libc.Int32FromUint64(uint64(24) * libc.Uint64FromInt32((*TParse)(unsafe.Pointer(pToplevel)).FnTableLock+libc.Int32FromInt32(1)))
|
|
(*TParse)(unsafe.Pointer(pToplevel)).FaTableLock = _sqlite3DbReallocOrFree(tls, (*TParse)(unsafe.Pointer(pToplevel)).Fdb, (*TParse)(unsafe.Pointer(pToplevel)).FaTableLock, libc.Uint64FromInt32(nBytes))
|
|
if (*TParse)(unsafe.Pointer(pToplevel)).FaTableLock != 0 {
|
|
v1 = pToplevel + 140
|
|
v3 = *(*int32)(unsafe.Pointer(v1))
|
|
*(*int32)(unsafe.Pointer(v1)) = *(*int32)(unsafe.Pointer(v1)) + 1
|
|
p = (*TParse)(unsafe.Pointer(pToplevel)).FaTableLock + uintptr(v3)*24
|
|
(*TTableLock)(unsafe.Pointer(p)).FiDb = iDb
|
|
(*TTableLock)(unsafe.Pointer(p)).FiTab = iTab
|
|
(*TTableLock)(unsafe.Pointer(p)).FisWriteLock = isWriteLock
|
|
(*TTableLock)(unsafe.Pointer(p)).FzLockName = zName
|
|
} else {
|
|
(*TParse)(unsafe.Pointer(pToplevel)).FnTableLock = 0
|
|
_sqlite3OomFault(tls, (*TParse)(unsafe.Pointer(pToplevel)).Fdb)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Move the cursor down to a new child page. The newPgno argument is the
|
|
// ** page number of the child page to move to.
|
|
// **
|
|
// ** This function returns SQLITE_CORRUPT if the page-header flags field of
|
|
// ** the new child page does not match the flags field of the parent (i.e.
|
|
// ** if an intkey page appears to be the parent of a non-intkey page, or
|
|
// ** vice-versa).
|
|
// */
|
|
func _moveToChild(tls *libc.TLS, pCur uintptr, newPgno Tu32) (r int32) {
|
|
var rc int32
|
|
var v1 uintptr
|
|
var v2 Ti8
|
|
_, _, _ = rc, v1, v2
|
|
if int32((*TBtCursor)(unsafe.Pointer(pCur)).FiPage) >= libc.Int32FromInt32(BTCURSOR_MAX_DEPTH)-libc.Int32FromInt32(1) {
|
|
return _sqlite3CorruptError(tls, int32(78687))
|
|
}
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnSize = uint16(0)
|
|
v1 = pCur + 1
|
|
*(*Tu8)(unsafe.Pointer(v1)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v1))) & ^(libc.Int32FromInt32(BTCF_ValidNKey) | libc.Int32FromInt32(BTCF_ValidOvfl)))
|
|
**(**Tu16)(__ccgo_up(pCur + 88 + uintptr((*TBtCursor)(unsafe.Pointer(pCur)).FiPage)*2)) = (*TBtCursor)(unsafe.Pointer(pCur)).Fix
|
|
**(**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, newPgno, 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(78701))
|
|
}
|
|
if rc != 0 {
|
|
v1 = pCur + 84
|
|
*(*Ti8)(unsafe.Pointer(v1)) = *(*Ti8)(unsafe.Pointer(v1)) - 1
|
|
v2 = *(*Ti8)(unsafe.Pointer(v1))
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FpPage = **(**uintptr)(__ccgo_up(pCur + 144 + uintptr(v2)*8))
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Move the cursor to point to the root page of its b-tree structure.
|
|
// **
|
|
// ** If the table has a virtual root page, then the cursor is moved to point
|
|
// ** to the virtual root page instead of the actual root page. A table has a
|
|
// ** virtual root page when the actual root page contains no cells and a
|
|
// ** single child page. This can only happen with the table rooted at page 1.
|
|
// **
|
|
// ** If the b-tree structure is empty, the cursor state is set to
|
|
// ** CURSOR_INVALID and this routine returns SQLITE_EMPTY. Otherwise,
|
|
// ** the cursor is set to point to the first cell located on the root
|
|
// ** (or virtual root) page and the cursor state is set to CURSOR_VALID.
|
|
// **
|
|
// ** If this function returns successfully, it may be assumed that the
|
|
// ** page-header flags indicate that the [virtual] root-page is the expected
|
|
// ** kind of b-tree page (i.e. if when opening the cursor the caller did not
|
|
// ** specify a KeyInfo structure the flags byte is set to 0x05 or 0x0D,
|
|
// ** indicating a table b-tree, or if the caller did specify a KeyInfo
|
|
// ** structure the flags byte is set to 0x02 or 0x0A, indicating an index
|
|
// ** b-tree).
|
|
// */
|
|
func _moveToRoot(tls *libc.TLS, pCur uintptr) (r int32) {
|
|
var pRoot, v2 uintptr
|
|
var rc int32
|
|
var subpage TPgno
|
|
var v1 Ti8
|
|
_, _, _, _, _ = pRoot, rc, subpage, v1, v2
|
|
rc = SQLITE_OK
|
|
if int32((*TBtCursor)(unsafe.Pointer(pCur)).FiPage) >= 0 {
|
|
if (*TBtCursor)(unsafe.Pointer(pCur)).FiPage != 0 {
|
|
_releasePageNotNull(tls, (*TBtCursor)(unsafe.Pointer(pCur)).FpPage)
|
|
for {
|
|
v2 = pCur + 84
|
|
*(*Ti8)(unsafe.Pointer(v2)) = *(*Ti8)(unsafe.Pointer(v2)) - 1
|
|
v1 = *(*Ti8)(unsafe.Pointer(v2))
|
|
if !(v1 != 0) {
|
|
break
|
|
}
|
|
_releasePageNotNull(tls, **(**uintptr)(__ccgo_up(pCur + 144 + uintptr((*TBtCursor)(unsafe.Pointer(pCur)).FiPage)*8)))
|
|
}
|
|
v2 = **(**uintptr)(__ccgo_up(pCur + 144))
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FpPage = v2
|
|
pRoot = v2
|
|
goto skip_init
|
|
}
|
|
} else {
|
|
if (*TBtCursor)(unsafe.Pointer(pCur)).FpgnoRoot == uint32(0) {
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FeState = uint8(CURSOR_INVALID)
|
|
return int32(SQLITE_EMPTY)
|
|
} else {
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) >= int32(CURSOR_REQUIRESEEK) {
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) == int32(CURSOR_FAULT) {
|
|
return (*TBtCursor)(unsafe.Pointer(pCur)).FskipNext
|
|
}
|
|
_sqlite3BtreeClearCursor(tls, pCur)
|
|
}
|
|
rc = _getAndInitPage(tls, (*TBtCursor)(unsafe.Pointer(pCur)).FpBt, (*TBtCursor)(unsafe.Pointer(pCur)).FpgnoRoot, pCur+136, libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FcurPagerFlags))
|
|
if rc != SQLITE_OK {
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FeState = uint8(CURSOR_INVALID)
|
|
return rc
|
|
}
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FiPage = 0
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FcurIntKey = (*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).FintKey
|
|
}
|
|
}
|
|
pRoot = (*TBtCursor)(unsafe.Pointer(pCur)).FpPage
|
|
/* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor
|
|
** expected to open it on an index b-tree. Otherwise, if pKeyInfo is
|
|
** NULL, the caller expects a table b-tree. If this is not the case,
|
|
** return an SQLITE_CORRUPT error.
|
|
**
|
|
** Earlier versions of SQLite assumed that this test could not fail
|
|
** if the root page was already loaded when this function was called (i.e.
|
|
** if pCur->iPage>=0). But this is not so if the database is corrupted
|
|
** in such a way that page pRoot is linked into a second b-tree table
|
|
** (or the freelist). */
|
|
if libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pRoot)).FisInit) == 0 || libc.BoolInt32((*TBtCursor)(unsafe.Pointer(pCur)).FpKeyInfo == uintptr(0)) != libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pRoot)).FintKey) {
|
|
return _sqlite3CorruptError(tls, int32(78836))
|
|
}
|
|
goto skip_init
|
|
skip_init:
|
|
;
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).Fix = uint16(0)
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnSize = uint16(0)
|
|
v2 = pCur + 1
|
|
*(*Tu8)(unsafe.Pointer(v2)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v2))) & ^(libc.Int32FromInt32(BTCF_AtLast) | libc.Int32FromInt32(BTCF_ValidNKey) | libc.Int32FromInt32(BTCF_ValidOvfl)))
|
|
if libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pRoot)).FnCell) > 0 {
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FeState = uint8(CURSOR_VALID)
|
|
} else {
|
|
if !((*TMemPage)(unsafe.Pointer(pRoot)).Fleaf != 0) {
|
|
if (*TMemPage)(unsafe.Pointer(pRoot)).Fpgno != uint32(1) {
|
|
return _sqlite3CorruptError(tls, int32(78848))
|
|
}
|
|
subpage = _sqlite3Get4byte(tls, (*TMemPage)(unsafe.Pointer(pRoot)).FaData+uintptr(libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pRoot)).FhdrOffset)+int32(8)))
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FeState = uint8(CURSOR_VALID)
|
|
rc = _moveToChild(tls, pCur, subpage)
|
|
} else {
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).FeState = uint8(CURSOR_INVALID)
|
|
rc = int32(SQLITE_EMPTY)
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The select statement passed as the second parameter is a compound SELECT
|
|
// ** with an ORDER BY clause. This function allocates and returns a KeyInfo
|
|
// ** structure suitable for implementing the ORDER BY.
|
|
// **
|
|
// ** Space to hold the KeyInfo structure is obtained from malloc. The calling
|
|
// ** function is responsible for ensuring that this structure is eventually
|
|
// ** freed.
|
|
// */
|
|
func _multiSelectByMergeKeyInfo(tls *libc.TLS, pParse uintptr, p uintptr, nExtra int32) (r uintptr) {
|
|
var db, pColl, pItem, pOrderBy, pRet, pTerm uintptr
|
|
var i, nOrderBy, v1 int32
|
|
_, _, _, _, _, _, _, _, _ = db, i, nOrderBy, pColl, pItem, pOrderBy, pRet, pTerm, v1
|
|
pOrderBy = (*TSelect)(unsafe.Pointer(p)).FpOrderBy
|
|
if pOrderBy != uintptr(0) {
|
|
v1 = (*TExprList)(unsafe.Pointer(pOrderBy)).FnExpr
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
nOrderBy = v1
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
pRet = _sqlite3KeyInfoAlloc(tls, db, nOrderBy+nExtra, int32(1))
|
|
if pRet != 0 {
|
|
i = 0
|
|
for {
|
|
if !(i < nOrderBy) {
|
|
break
|
|
}
|
|
pItem = pOrderBy + 8 + uintptr(i)*32
|
|
pTerm = (*TExprList_item)(unsafe.Pointer(pItem)).FpExpr
|
|
if (*TExpr)(unsafe.Pointer(pTerm)).Fflags&uint32(EP_Collate) != 0 {
|
|
pColl = _sqlite3ExprCollSeq(tls, pParse, pTerm)
|
|
} else {
|
|
pColl = _multiSelectCollSeq(tls, pParse, p, libc.Int32FromUint16((*(*struct {
|
|
FiOrderByCol Tu16
|
|
FiAlias Tu16
|
|
})(unsafe.Pointer(pItem + 24))).FiOrderByCol)-int32(1))
|
|
if pColl == uintptr(0) {
|
|
pColl = (*Tsqlite3)(unsafe.Pointer(db)).FpDfltColl
|
|
}
|
|
(*(*TExprList_item)(unsafe.Pointer(pOrderBy + 8 + uintptr(i)*32))).FpExpr = _sqlite3ExprAddCollateString(tls, pParse, pTerm, (*TCollSeq)(unsafe.Pointer(pColl)).FzName)
|
|
}
|
|
*(*uintptr)(unsafe.Pointer(pRet + 32 + uintptr(i)*8)) = pColl
|
|
**(**Tu8)(__ccgo_up((*TKeyInfo)(unsafe.Pointer(pRet)).FaSortFlags + uintptr(i))) = (*(*TExprList_item)(unsafe.Pointer(pOrderBy + 8 + uintptr(i)*32))).Ffg.FsortFlags
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
return pRet
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add node pNode to the node hash table.
|
|
// */
|
|
func _nodeHashInsert(tls *libc.TLS, pRtree uintptr, pNode uintptr) {
|
|
var iHash int32
|
|
_ = iHash
|
|
iHash = libc.Int32FromUint32(_nodeHash(tls, (*TRtreeNode)(unsafe.Pointer(pNode)).FiNode))
|
|
(*TRtreeNode)(unsafe.Pointer(pNode)).FpNext = **(**uintptr)(__ccgo_up(pRtree + 200 + uintptr(iHash)*8))
|
|
**(**uintptr)(__ccgo_up(pRtree + 200 + uintptr(iHash)*8)) = pNode
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** An index on expressions is being used in the inner loop of an
|
|
// ** aggregate query with a GROUP BY clause. This routine attempts
|
|
// ** to adjust the AggInfo object to take advantage of index and to
|
|
// ** perhaps use the index as a covering index.
|
|
// **
|
|
// */
|
|
func _optimizeAggregateUseOfIndexedExpr(tls *libc.TLS, pParse uintptr, pSelect uintptr, pAggInfo uintptr, pNC uintptr) {
|
|
var j, k, mx int32
|
|
_, _, _ = j, k, mx
|
|
(*TAggInfo)(unsafe.Pointer(pAggInfo)).FnColumn = (*TAggInfo)(unsafe.Pointer(pAggInfo)).FnAccumulator
|
|
if (*TAggInfo)(unsafe.Pointer(pAggInfo)).FnSortingColumn > uint32(0) {
|
|
mx = (*TExprList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pSelect)).FpGroupBy)).FnExpr - int32(1)
|
|
j = 0
|
|
for {
|
|
if !(j < (*TAggInfo)(unsafe.Pointer(pAggInfo)).FnColumn) {
|
|
break
|
|
}
|
|
k = (**(**TAggInfo_col)(__ccgo_up((*TAggInfo)(unsafe.Pointer(pAggInfo)).FaCol + uintptr(j)*32))).FiSorterColumn
|
|
if k > mx {
|
|
mx = k
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
j = j + 1
|
|
}
|
|
(*TAggInfo)(unsafe.Pointer(pAggInfo)).FnSortingColumn = libc.Uint32FromInt32(mx + int32(1))
|
|
}
|
|
_analyzeAggFuncArgs(tls, pAggInfo, pNC)
|
|
_ = pSelect
|
|
_ = pParse
|
|
}
|
|
|
|
func _out2Prerelease(tls *libc.TLS, p uintptr, pOp uintptr) (r uintptr) {
|
|
var pOut uintptr
|
|
_ = pOut
|
|
pOut = (*TVdbe)(unsafe.Pointer(p)).FaMem + uintptr((*TVdbeOp)(unsafe.Pointer(pOp)).Fp2)*56
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pOut)).Fflags)&(libc.Int32FromInt32(MEM_Agg)|libc.Int32FromInt32(MEM_Dyn)) != 0 { /*OPTIMIZATION-IF-FALSE*/
|
|
return _out2PrereleaseWithClear(tls, pOut)
|
|
} else {
|
|
(*TMem)(unsafe.Pointer(pOut)).Fflags = uint16(MEM_Int)
|
|
return pOut
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The pCArray object contains pointers to b-tree cells and their sizes.
|
|
// **
|
|
// ** This function adds the space associated with each cell in the array
|
|
// ** that is currently stored within the body of pPg to the pPg free-list.
|
|
// ** The cell-pointers and other fields of the page are not updated.
|
|
// **
|
|
// ** This function returns the total number of cells added to the free-list.
|
|
// */
|
|
func _pageFreeArray(tls *libc.TLS, pPg uintptr, iFirst int32, nCell int32, pCArray uintptr) (r int32) {
|
|
var aAfter, aOfst [10]int32
|
|
var aData, pCell, pEnd, pStart uintptr
|
|
var i, iAfter, iEnd, iOfst, j, nFree, nRet, sz int32
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _ = aAfter, aData, aOfst, i, iAfter, iEnd, iOfst, j, nFree, nRet, pCell, pEnd, pStart, sz
|
|
aData = (*TMemPage)(unsafe.Pointer(pPg)).FaData
|
|
pEnd = aData + uintptr((*TBtShared)(unsafe.Pointer((*TMemPage)(unsafe.Pointer(pPg)).FpBt)).FusableSize)
|
|
pStart = aData + uintptr(libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pPg)).FhdrOffset)+int32(8)+libc.Int32FromUint8((*TMemPage)(unsafe.Pointer(pPg)).FchildPtrSize))
|
|
nRet = 0
|
|
iEnd = iFirst + nCell
|
|
nFree = 0
|
|
i = iFirst
|
|
for {
|
|
if !(i < iEnd) {
|
|
break
|
|
}
|
|
pCell = **(**uintptr)(__ccgo_up((*TCellArray)(unsafe.Pointer(pCArray)).FapCell + uintptr(i)*8))
|
|
if uint64(pCell) >= uint64(pStart) && uint64(pCell) < uint64(pEnd) {
|
|
/* No need to use cachedCellSize() here. The sizes of all cells that
|
|
** are to be freed have already been computing while deciding which
|
|
** cells need freeing */
|
|
sz = libc.Int32FromUint16(**(**Tu16)(__ccgo_up((*TCellArray)(unsafe.Pointer(pCArray)).FszCell + uintptr(i)*2)))
|
|
iOfst = libc.Int32FromUint16(libc.Uint16FromInt64(int64(pCell) - int64(aData)))
|
|
iAfter = iOfst + sz
|
|
j = 0
|
|
for {
|
|
if !(j < nFree) {
|
|
break
|
|
}
|
|
if aOfst[j] == iAfter {
|
|
aOfst[j] = iOfst
|
|
break
|
|
} else {
|
|
if aAfter[j] == iOfst {
|
|
aAfter[j] = iAfter
|
|
break
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
j = j + 1
|
|
}
|
|
if j >= nFree {
|
|
if nFree >= libc.Int32FromUint64(libc.Uint64FromInt64(40)/libc.Uint64FromInt64(4)) {
|
|
j = 0
|
|
for {
|
|
if !(j < nFree) {
|
|
break
|
|
}
|
|
_freeSpace(tls, pPg, aOfst[j], aAfter[j]-aOfst[j])
|
|
goto _3
|
|
_3:
|
|
;
|
|
j = j + 1
|
|
}
|
|
nFree = 0
|
|
}
|
|
aOfst[nFree] = iOfst
|
|
aAfter[nFree] = iAfter
|
|
if aData+uintptr(iAfter) > pEnd {
|
|
return 0
|
|
}
|
|
nFree = nFree + 1
|
|
}
|
|
nRet = nRet + 1
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
j = 0
|
|
for {
|
|
if !(j < nFree) {
|
|
break
|
|
}
|
|
_freeSpace(tls, pPg, aOfst[j], aAfter[j]-aOfst[j])
|
|
goto _4
|
|
_4:
|
|
;
|
|
j = j + 1
|
|
}
|
|
return nRet
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Call sqlite3WalOpen() to open the WAL handle. If the pager is in
|
|
// ** exclusive-locking mode when this function is called, take an EXCLUSIVE
|
|
// ** lock on the database file and use heap-memory to store the wal-index
|
|
// ** in. Otherwise, use the normal shared-memory.
|
|
// */
|
|
func _pagerOpenWal(tls *libc.TLS, pPager uintptr) (r int32) {
|
|
var rc int32
|
|
_ = rc
|
|
rc = SQLITE_OK
|
|
/* If the pager is already in exclusive-mode, the WAL module will use
|
|
** heap-memory for the wal-index instead of the VFS shared-memory
|
|
** implementation. Take the exclusive lock now, before opening the WAL
|
|
** file, to make sure this is safe.
|
|
*/
|
|
if (*TPager)(unsafe.Pointer(pPager)).FexclusiveMode != 0 {
|
|
rc = _pagerExclusiveLock(tls, pPager)
|
|
}
|
|
/* Open the connection to the log file. If this operation fails,
|
|
** (e.g. due to malloc() failure), return an error code.
|
|
*/
|
|
if rc == SQLITE_OK {
|
|
rc = _sqlite3WalOpen(tls, (*TPager)(unsafe.Pointer(pPager)).FpVfs, (*TPager)(unsafe.Pointer(pPager)).Ffd, (*TPager)(unsafe.Pointer(pPager)).FzWal, libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FexclusiveMode), (*TPager)(unsafe.Pointer(pPager)).FjournalSizeLimit, pPager+296)
|
|
}
|
|
_pagerFixMaplimit(tls, pPager)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Playback savepoint pSavepoint. Or, if pSavepoint==NULL, then playback
|
|
// ** the entire super-journal file. The case pSavepoint==NULL occurs when
|
|
// ** a ROLLBACK TO command is invoked on a SAVEPOINT that is a transaction
|
|
// ** savepoint.
|
|
// **
|
|
// ** When pSavepoint is not NULL (meaning a non-transaction savepoint is
|
|
// ** being rolled back), then the rollback consists of up to three stages,
|
|
// ** performed in the order specified:
|
|
// **
|
|
// ** * Pages are played back from the main journal starting at byte
|
|
// ** offset PagerSavepoint.iOffset and continuing to
|
|
// ** PagerSavepoint.iHdrOffset, or to the end of the main journal
|
|
// ** file if PagerSavepoint.iHdrOffset is zero.
|
|
// **
|
|
// ** * If PagerSavepoint.iHdrOffset is not zero, then pages are played
|
|
// ** back starting from the journal header immediately following
|
|
// ** PagerSavepoint.iHdrOffset to the end of the main journal file.
|
|
// **
|
|
// ** * Pages are then played back from the sub-journal file, starting
|
|
// ** with the PagerSavepoint.iSubRec and continuing to the end of
|
|
// ** the journal file.
|
|
// **
|
|
// ** Throughout the rollback process, each time a page is rolled back, the
|
|
// ** corresponding bit is set in a bitvec structure (variable pDone in the
|
|
// ** implementation below). This is used to ensure that a page is only
|
|
// ** rolled back the first time it is encountered in either journal.
|
|
// **
|
|
// ** If pSavepoint is NULL, then pages are only played back from the main
|
|
// ** journal file. There is no need for a bitvec in this case.
|
|
// **
|
|
// ** In either case, before playback commences the Pager.dbSize variable
|
|
// ** is reset to the value that it held at the start of the savepoint
|
|
// ** (or transaction). No page with a page-number greater than this value
|
|
// ** is played back. If one is encountered it is simply skipped.
|
|
// */
|
|
func _pagerPlaybackSavepoint(tls *libc.TLS, pPager uintptr, pSavepoint uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iHdrOff, szJ Ti64
|
|
var ii, ii1 Tu32
|
|
var pDone uintptr
|
|
var rc int32
|
|
var v1 uint32
|
|
var v2 int64
|
|
var _ /* dummy at bp+4 */ Tu32
|
|
var _ /* nJRec at bp+0 */ Tu32
|
|
var _ /* offset at bp+8 */ Ti64
|
|
_, _, _, _, _, _, _, _ = iHdrOff, ii, ii1, pDone, rc, szJ, v1, v2 /* End of first segment of main-journal records */
|
|
rc = SQLITE_OK /* Return code */
|
|
pDone = uintptr(0) /* Bitvec to ensure pages played back only once */
|
|
/* Allocate a bitvec to use to store the set of pages rolled back */
|
|
if pSavepoint != 0 {
|
|
pDone = _sqlite3BitvecCreate(tls, (*TPagerSavepoint)(unsafe.Pointer(pSavepoint)).FnOrig)
|
|
if !(pDone != 0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
}
|
|
/* Set the database size back to the value it was before the savepoint
|
|
** being reverted was opened.
|
|
*/
|
|
if pSavepoint != 0 {
|
|
v1 = (*TPagerSavepoint)(unsafe.Pointer(pSavepoint)).FnOrig
|
|
} else {
|
|
v1 = (*TPager)(unsafe.Pointer(pPager)).FdbOrigSize
|
|
}
|
|
(*TPager)(unsafe.Pointer(pPager)).FdbSize = v1
|
|
(*TPager)(unsafe.Pointer(pPager)).FchangeCountDone = (*TPager)(unsafe.Pointer(pPager)).FtempFile
|
|
if !(pSavepoint != 0) && (*TPager)(unsafe.Pointer(pPager)).FpWal != uintptr(0) {
|
|
return _pagerRollbackWal(tls, pPager)
|
|
}
|
|
/* Use pPager->journalOff as the effective size of the main rollback
|
|
** journal. The actual file might be larger than this in
|
|
** PAGER_JOURNALMODE_TRUNCATE or PAGER_JOURNALMODE_PERSIST. But anything
|
|
** past pPager->journalOff is off-limits to us.
|
|
*/
|
|
szJ = (*TPager)(unsafe.Pointer(pPager)).FjournalOff
|
|
/* Begin by rolling back records from the main journal starting at
|
|
** PagerSavepoint.iOffset and continuing to the next journal header.
|
|
** There might be records in the main journal that have a page number
|
|
** greater than the current database size (pPager->dbSize) but those
|
|
** will be skipped automatically. Pages are added to pDone as they
|
|
** are played back.
|
|
*/
|
|
if pSavepoint != 0 && !((*TPager)(unsafe.Pointer(pPager)).FpWal != libc.UintptrFromInt32(0)) {
|
|
if (*TPagerSavepoint)(unsafe.Pointer(pSavepoint)).FiHdrOffset != 0 {
|
|
v2 = (*TPagerSavepoint)(unsafe.Pointer(pSavepoint)).FiHdrOffset
|
|
} else {
|
|
v2 = szJ
|
|
}
|
|
iHdrOff = v2
|
|
(*TPager)(unsafe.Pointer(pPager)).FjournalOff = (*TPagerSavepoint)(unsafe.Pointer(pSavepoint)).FiOffset
|
|
for rc == SQLITE_OK && (*TPager)(unsafe.Pointer(pPager)).FjournalOff < iHdrOff {
|
|
rc = _pager_playback_one_page(tls, pPager, pPager+96, pDone, int32(1), int32(1))
|
|
}
|
|
} else {
|
|
(*TPager)(unsafe.Pointer(pPager)).FjournalOff = 0
|
|
}
|
|
/* Continue rolling back records out of the main journal starting at
|
|
** the first journal header seen and continuing until the effective end
|
|
** of the main journal file. Continue to skip out-of-range pages and
|
|
** continue adding pages rolled back to pDone.
|
|
*/
|
|
for rc == SQLITE_OK && (*TPager)(unsafe.Pointer(pPager)).FjournalOff < szJ { /* Loop counter */
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(0)
|
|
rc = _readJournalHdr(tls, pPager, 0, szJ, bp, bp+4)
|
|
/*
|
|
** The "pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff"
|
|
** test is related to ticket #2565. See the discussion in the
|
|
** pager_playback() function for additional information.
|
|
*/
|
|
if **(**Tu32)(__ccgo_up(bp)) == uint32(0) && (*TPager)(unsafe.Pointer(pPager)).FjournalHdr+libc.Int64FromUint32((*TPager)(unsafe.Pointer(pPager)).FsectorSize) == (*TPager)(unsafe.Pointer(pPager)).FjournalOff {
|
|
**(**Tu32)(__ccgo_up(bp)) = libc.Uint32FromInt64((szJ - (*TPager)(unsafe.Pointer(pPager)).FjournalOff) / ((*TPager)(unsafe.Pointer(pPager)).FpageSize + libc.Int64FromInt32(8)))
|
|
}
|
|
ii = uint32(0)
|
|
for {
|
|
if !(rc == SQLITE_OK && ii < **(**Tu32)(__ccgo_up(bp)) && (*TPager)(unsafe.Pointer(pPager)).FjournalOff < szJ) {
|
|
break
|
|
}
|
|
rc = _pager_playback_one_page(tls, pPager, pPager+96, pDone, int32(1), int32(1))
|
|
goto _3
|
|
_3:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
}
|
|
/* Finally, rollback pages from the sub-journal. Page that were
|
|
** previously rolled back out of the main journal (and are hence in pDone)
|
|
** will be skipped. Out-of-range pages are also skipped.
|
|
*/
|
|
if pSavepoint != 0 { /* Loop counter */
|
|
**(**Ti64)(__ccgo_up(bp + 8)) = libc.Int64FromUint32((*TPagerSavepoint)(unsafe.Pointer(pSavepoint)).FiSubRec) * (int64(4) + (*TPager)(unsafe.Pointer(pPager)).FpageSize)
|
|
if (*TPager)(unsafe.Pointer(pPager)).FpWal != uintptr(0) {
|
|
rc = _sqlite3WalSavepointUndo(tls, (*TPager)(unsafe.Pointer(pPager)).FpWal, pSavepoint+36)
|
|
}
|
|
ii1 = (*TPagerSavepoint)(unsafe.Pointer(pSavepoint)).FiSubRec
|
|
for {
|
|
if !(rc == SQLITE_OK && ii1 < (*TPager)(unsafe.Pointer(pPager)).FnSubRec) {
|
|
break
|
|
}
|
|
rc = _pager_playback_one_page(tls, pPager, bp+8, pDone, 0, int32(1))
|
|
goto _4
|
|
_4:
|
|
;
|
|
ii1 = ii1 + 1
|
|
}
|
|
}
|
|
_sqlite3BitvecDestroy(tls, pDone)
|
|
if rc == SQLITE_OK {
|
|
(*TPager)(unsafe.Pointer(pPager)).FjournalOff = szJ
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called by the pcache layer when it has reached some
|
|
// ** soft memory limit. The first argument is a pointer to a Pager object
|
|
// ** (cast as a void*). The pager is always 'purgeable' (not an in-memory
|
|
// ** database). The second argument is a reference to a page that is
|
|
// ** currently dirty but has no outstanding references. The page
|
|
// ** is always associated with the Pager object passed as the first
|
|
// ** argument.
|
|
// **
|
|
// ** The job of this function is to make pPg clean by writing its contents
|
|
// ** out to the database file, if possible. This may involve syncing the
|
|
// ** journal file.
|
|
// **
|
|
// ** If successful, sqlite3PcacheMakeClean() is called on the page and
|
|
// ** SQLITE_OK returned. If an IO error occurs while trying to make the
|
|
// ** page clean, the IO error code is returned. If the page cannot be
|
|
// ** made clean for some other reason, but no error occurs, then SQLITE_OK
|
|
// ** is returned by sqlite3PcacheMakeClean() is not called.
|
|
// */
|
|
func _pagerStress(tls *libc.TLS, p uintptr, pPg uintptr) (r int32) {
|
|
var pPager uintptr
|
|
var rc int32
|
|
_, _ = pPager, rc
|
|
pPager = p
|
|
rc = SQLITE_OK
|
|
/* The doNotSpill NOSYNC bit is set during times when doing a sync of
|
|
** journal (and adding a new header) is not allowed. This occurs
|
|
** during calls to sqlite3PagerWrite() while trying to journal multiple
|
|
** pages belonging to the same sector.
|
|
**
|
|
** The doNotSpill ROLLBACK and OFF bits inhibits all cache spilling
|
|
** regardless of whether or not a sync is required. This is set during
|
|
** a rollback or by user request, respectively.
|
|
**
|
|
** Spilling is also prohibited when in an error state since that could
|
|
** lead to database corruption. In the current implementation it
|
|
** is impossible for sqlite3PcacheFetch() to be called with createFlag==3
|
|
** while in the error state, hence it is impossible for this routine to
|
|
** be called in the error state. Nevertheless, we include a NEVER()
|
|
** test for the error state as a safeguard against future changes.
|
|
*/
|
|
if (*TPager)(unsafe.Pointer(pPager)).FerrCode != 0 {
|
|
return SQLITE_OK
|
|
}
|
|
if (*TPager)(unsafe.Pointer(pPager)).FdoNotSpill != 0 && (libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FdoNotSpill)&(libc.Int32FromInt32(SPILLFLAG_ROLLBACK)|libc.Int32FromInt32(SPILLFLAG_OFF)) != 0 || libc.Int32FromUint16((*TPgHdr)(unsafe.Pointer(pPg)).Fflags)&int32(PGHDR_NEED_SYNC) != 0) {
|
|
return SQLITE_OK
|
|
}
|
|
**(**Tu32)(__ccgo_up(pPager + 248 + 3*4)) = **(**Tu32)(__ccgo_up(pPager + 248 + 3*4)) + 1
|
|
(*TPgHdr)(unsafe.Pointer(pPg)).FpDirty = uintptr(0)
|
|
if (*TPager)(unsafe.Pointer(pPager)).FpWal != uintptr(0) {
|
|
/* Write a single frame for this page to the log. */
|
|
rc = _subjournalPageIfRequired(tls, pPg)
|
|
if rc == SQLITE_OK {
|
|
rc = _pagerWalFrames(tls, pPager, pPg, uint32(0), 0)
|
|
}
|
|
} else {
|
|
/* Sync the journal file if required. */
|
|
if libc.Int32FromUint16((*TPgHdr)(unsafe.Pointer(pPg)).Fflags)&int32(PGHDR_NEED_SYNC) != 0 || libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) == int32(PAGER_WRITER_CACHEMOD) {
|
|
rc = _syncJournal(tls, pPager, int32(1))
|
|
}
|
|
/* Write the contents of the page out to the database file. */
|
|
if rc == SQLITE_OK {
|
|
rc = _pager_write_pagelist(tls, pPager, pPg)
|
|
}
|
|
}
|
|
/* Mark the page as clean. */
|
|
if rc == SQLITE_OK {
|
|
_sqlite3PcacheMakeClean(tls, pPg)
|
|
}
|
|
return _pager_error(tls, pPager, rc)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is a wrapper around sqlite3WalFrames(). As well as logging
|
|
// ** the contents of the list of pages headed by pList (connected by pDirty),
|
|
// ** this function notifies any active backup processes that the pages have
|
|
// ** changed.
|
|
// **
|
|
// ** The list of pages passed into this routine is always sorted by page number.
|
|
// ** Hence, if page 1 appears anywhere on the list, it will be the first page.
|
|
// */
|
|
func _pagerWalFrames(tls *libc.TLS, pPager uintptr, _pList uintptr, nTruncate TPgno, isCommit int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
*(*uintptr)(unsafe.Pointer(bp)) = _pList
|
|
var nList, rc int32
|
|
var p, ppNext, v2 uintptr
|
|
_, _, _, _, _ = nList, p, ppNext, rc, v2 /* For looping over pages */
|
|
if isCommit != 0 {
|
|
/* If a WAL transaction is being committed, there is no point in writing
|
|
** any pages with page numbers greater than nTruncate into the WAL file.
|
|
** They will never be read by any client. So remove them from the pDirty
|
|
** list here. */
|
|
ppNext = bp
|
|
nList = 0
|
|
p = **(**uintptr)(__ccgo_up(bp))
|
|
for {
|
|
v2 = p
|
|
**(**uintptr)(__ccgo_up(ppNext)) = v2
|
|
if !(v2 != uintptr(0)) {
|
|
break
|
|
}
|
|
if (*TPgHdr)(unsafe.Pointer(p)).Fpgno <= nTruncate {
|
|
ppNext = p + 32
|
|
nList = nList + 1
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = (*TPgHdr)(unsafe.Pointer(p)).FpDirty
|
|
}
|
|
} else {
|
|
nList = int32(1)
|
|
}
|
|
**(**Tu32)(__ccgo_up(pPager + 248 + 2*4)) += libc.Uint32FromInt32(nList)
|
|
if (*TPgHdr)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).Fpgno == uint32(1) {
|
|
_pager_write_changecounter(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
}
|
|
rc = _sqlite3WalFrames(tls, (*TPager)(unsafe.Pointer(pPager)).FpWal, int32((*TPager)(unsafe.Pointer(pPager)).FpageSize), **(**uintptr)(__ccgo_up(bp)), nTruncate, isCommit, libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FwalSyncFlags))
|
|
if rc == SQLITE_OK && (*TPager)(unsafe.Pointer(pPager)).FpBackup != 0 {
|
|
p = **(**uintptr)(__ccgo_up(bp))
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
_sqlite3BackupUpdate(tls, (*TPager)(unsafe.Pointer(pPager)).FpBackup, (*TPgHdr)(unsafe.Pointer(p)).Fpgno, (*TPgHdr)(unsafe.Pointer(p)).FpData)
|
|
goto _3
|
|
_3:
|
|
;
|
|
p = (*TPgHdr)(unsafe.Pointer(p)).FpDirty
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is a variant of sqlite3PagerWrite() that runs when the sector size
|
|
// ** is larger than the page size. SQLite makes the (reasonable) assumption that
|
|
// ** all bytes of a sector are written together by hardware. Hence, all bytes of
|
|
// ** a sector need to be journalled in case of a power loss in the middle of
|
|
// ** a write.
|
|
// **
|
|
// ** Usually, the sector size is less than or equal to the page size, in which
|
|
// ** case pages can be individually written. This routine only runs in the
|
|
// ** exceptional case where the page size is smaller than the sector size.
|
|
// */
|
|
func _pagerWriteLargeSector(tls *libc.TLS, pPg uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var ii, nPage, needSync, rc int32
|
|
var nPageCount, nPagePerSector, pg, pg1 TPgno
|
|
var pPage1, pPager, v1 uintptr
|
|
var _ /* pPage at bp+0 */ uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _ = ii, nPage, nPageCount, nPagePerSector, needSync, pPage1, pPager, pg, pg1, rc, v1
|
|
rc = SQLITE_OK /* First page of the sector pPg is located on. */
|
|
nPage = 0 /* Loop counter */
|
|
needSync = 0 /* True if any page has PGHDR_NEED_SYNC */
|
|
pPager = (*TPgHdr)(unsafe.Pointer(pPg)).FpPager /* The pager that owns pPg */
|
|
nPagePerSector = libc.Uint32FromInt64(libc.Int64FromUint32((*TPager)(unsafe.Pointer(pPager)).FsectorSize) / (*TPager)(unsafe.Pointer(pPager)).FpageSize)
|
|
/* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow
|
|
** a journal header to be written between the pages journaled by
|
|
** this function.
|
|
*/
|
|
v1 = pPager + 25
|
|
*(*Tu8)(unsafe.Pointer(v1)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v1))) | libc.Int32FromInt32(SPILLFLAG_NOSYNC))
|
|
/* This trick assumes that both the page-size and sector-size are
|
|
** an integer power of 2. It sets variable pg1 to the identifier
|
|
** of the first page of the sector pPg is located on.
|
|
*/
|
|
pg1 = ((*TPgHdr)(unsafe.Pointer(pPg)).Fpgno-uint32(1)) & ^(nPagePerSector-libc.Uint32FromInt32(1)) + uint32(1)
|
|
nPageCount = (*TPager)(unsafe.Pointer(pPager)).FdbSize
|
|
if (*TPgHdr)(unsafe.Pointer(pPg)).Fpgno > nPageCount {
|
|
nPage = libc.Int32FromUint32((*TPgHdr)(unsafe.Pointer(pPg)).Fpgno - pg1 + uint32(1))
|
|
} else {
|
|
if pg1+nPagePerSector-uint32(1) > nPageCount {
|
|
nPage = libc.Int32FromUint32(nPageCount + uint32(1) - pg1)
|
|
} else {
|
|
nPage = libc.Int32FromUint32(nPagePerSector)
|
|
}
|
|
}
|
|
ii = 0
|
|
for {
|
|
if !(ii < nPage && rc == SQLITE_OK) {
|
|
break
|
|
}
|
|
pg = pg1 + libc.Uint32FromInt32(ii)
|
|
if pg == (*TPgHdr)(unsafe.Pointer(pPg)).Fpgno || !(_sqlite3BitvecTest(tls, (*TPager)(unsafe.Pointer(pPager)).FpInJournal, pg) != 0) {
|
|
if pg != (*TPager)(unsafe.Pointer(pPager)).FlckPgno {
|
|
rc = _sqlite3PagerGet(tls, pPager, pg, bp, 0)
|
|
if rc == SQLITE_OK {
|
|
rc = _pager_write(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
if libc.Int32FromUint16((*TPgHdr)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).Fflags)&int32(PGHDR_NEED_SYNC) != 0 {
|
|
needSync = int32(1)
|
|
}
|
|
_sqlite3PagerUnrefNotNull(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
}
|
|
}
|
|
} else {
|
|
v1 = _sqlite3PagerLookup(tls, pPager, pg)
|
|
**(**uintptr)(__ccgo_up(bp)) = v1
|
|
if v1 != uintptr(0) {
|
|
if libc.Int32FromUint16((*TPgHdr)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).Fflags)&int32(PGHDR_NEED_SYNC) != 0 {
|
|
needSync = int32(1)
|
|
}
|
|
_sqlite3PagerUnrefNotNull(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
/* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages
|
|
** starting at pg1, then it needs to be set for all of them. Because
|
|
** writing to any of these nPage pages may damage the others, the
|
|
** journal file must contain sync()ed copies of all of them
|
|
** before any of them can be written out to the database file.
|
|
*/
|
|
if rc == SQLITE_OK && needSync != 0 {
|
|
ii = 0
|
|
for {
|
|
if !(ii < nPage) {
|
|
break
|
|
}
|
|
pPage1 = _sqlite3PagerLookup(tls, pPager, pg1+libc.Uint32FromInt32(ii))
|
|
if pPage1 != 0 {
|
|
v1 = pPage1 + 52
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(PGHDR_NEED_SYNC))
|
|
_sqlite3PagerUnrefNotNull(tls, pPage1)
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
}
|
|
v1 = pPager + 25
|
|
*(*Tu8)(unsafe.Pointer(v1)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v1))) & ^libc.Int32FromInt32(SPILLFLAG_NOSYNC))
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Mark a single data page as writeable. The page is written into the
|
|
// ** main journal or sub-journal as required. If the page is written into
|
|
// ** one of the journals, the corresponding bit is set in the
|
|
// ** Pager.pInJournal bitvec and the PagerSavepoint.pInSavepoint bitvecs
|
|
// ** of any open savepoints as appropriate.
|
|
// */
|
|
func _pager_write(tls *libc.TLS, pPg uintptr) (r int32) {
|
|
var pPager, v1 uintptr
|
|
var rc int32
|
|
_, _, _ = pPager, rc, v1
|
|
pPager = (*TPgHdr)(unsafe.Pointer(pPg)).FpPager
|
|
rc = SQLITE_OK
|
|
/* This routine is not called unless a write-transaction has already
|
|
** been started. The journal file may or may not be open at this point.
|
|
** It is never called in the ERROR state.
|
|
*/
|
|
/* The journal file needs to be opened. Higher level routines have already
|
|
** obtained the necessary locks to begin the write-transaction, but the
|
|
** rollback journal might not yet be open. Open it now if this is the case.
|
|
**
|
|
** This is done before calling sqlite3PcacheMakeDirty() on the page.
|
|
** Otherwise, if it were done after calling sqlite3PcacheMakeDirty(), then
|
|
** an error might occur and the pager would end up in WRITER_LOCKED state
|
|
** with pages marked as dirty in the cache.
|
|
*/
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) == int32(PAGER_WRITER_LOCKED) {
|
|
rc = _pager_open_journal(tls, pPager)
|
|
if rc != SQLITE_OK {
|
|
return rc
|
|
}
|
|
}
|
|
/* Mark the page that is about to be modified as dirty. */
|
|
_sqlite3PcacheMakeDirty(tls, pPg)
|
|
/* If a rollback journal is in use, them make sure the page that is about
|
|
** to change is in the rollback journal, or if the page is a new page off
|
|
** then end of the file, make sure it is marked as PGHDR_NEED_SYNC.
|
|
*/
|
|
if (*TPager)(unsafe.Pointer(pPager)).FpInJournal != uintptr(0) && _sqlite3BitvecTestNotNull(tls, (*TPager)(unsafe.Pointer(pPager)).FpInJournal, (*TPgHdr)(unsafe.Pointer(pPg)).Fpgno) == 0 {
|
|
if (*TPgHdr)(unsafe.Pointer(pPg)).Fpgno <= (*TPager)(unsafe.Pointer(pPager)).FdbOrigSize {
|
|
rc = _pagerAddPageToRollbackJournal(tls, pPg)
|
|
if rc != SQLITE_OK {
|
|
return rc
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) != int32(PAGER_WRITER_DBMOD) {
|
|
v1 = pPg + 52
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(PGHDR_NEED_SYNC))
|
|
}
|
|
}
|
|
}
|
|
/* The PGHDR_DIRTY bit is set above when the page was added to the dirty-list
|
|
** and before writing the page into the rollback journal. Wait until now,
|
|
** after the page has been successfully journalled, before setting the
|
|
** PGHDR_WRITEABLE bit that indicates that the page can be safely modified.
|
|
*/
|
|
v1 = pPg + 52
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(PGHDR_WRITEABLE))
|
|
/* If the statement journal is open and the page is not in it,
|
|
** then write the page into the statement journal.
|
|
*/
|
|
if (*TPager)(unsafe.Pointer(pPager)).FnSavepoint > 0 {
|
|
rc = _subjournalPageIfRequired(tls, pPg)
|
|
}
|
|
/* Update the database size and return. */
|
|
if (*TPager)(unsafe.Pointer(pPager)).FdbSize < (*TPgHdr)(unsafe.Pointer(pPg)).Fpgno {
|
|
(*TPager)(unsafe.Pointer(pPager)).FdbSize = (*TPgHdr)(unsafe.Pointer(pPg)).Fpgno
|
|
}
|
|
return rc
|
|
}
|
|
|
|
func _parseGrowPhraseArray(tls *libc.TLS, pParse uintptr) (r int32) {
|
|
var apNew uintptr
|
|
var nByte Tsqlite3_int64
|
|
_, _ = apNew, nByte
|
|
if (*TFts5Parse)(unsafe.Pointer(pParse)).FnPhrase%int32(8) == 0 {
|
|
nByte = libc.Int64FromUint64(uint64(8) * libc.Uint64FromInt32((*TFts5Parse)(unsafe.Pointer(pParse)).FnPhrase+libc.Int32FromInt32(8)))
|
|
apNew = Xsqlite3_realloc64(tls, (*TFts5Parse)(unsafe.Pointer(pParse)).FapPhrase, libc.Uint64FromInt64(nByte))
|
|
if apNew == uintptr(0) {
|
|
(*TFts5Parse)(unsafe.Pointer(pParse)).Frc = int32(SQLITE_NOMEM)
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
(*TFts5Parse)(unsafe.Pointer(pParse)).FapPhrase = apNew
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Malloc function used within this file to allocate space from the buffer
|
|
// ** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no
|
|
// ** such buffer exists or there is no space left in it, this function falls
|
|
// ** back to sqlite3Malloc().
|
|
// **
|
|
// ** Multiple threads can run this routine at the same time. Global variables
|
|
// ** in pcache1 need to be protected via mutex.
|
|
// */
|
|
func _pcache1Alloc(tls *libc.TLS, nByte int32) (r uintptr) {
|
|
var p uintptr
|
|
var sz int32
|
|
_, _ = p, sz
|
|
p = uintptr(0)
|
|
if nByte <= _pcache1_g.FszSlot {
|
|
Xsqlite3_mutex_enter(tls, _pcache1_g.Fmutex)
|
|
p = _pcache1_g.FpFree
|
|
if p != 0 {
|
|
_pcache1_g.FpFree = (*TPgFreeslot)(unsafe.Pointer(_pcache1_g.FpFree)).FpNext
|
|
_pcache1_g.FnFreeSlot = _pcache1_g.FnFreeSlot - 1
|
|
libc.AtomicStoreNInt32(uintptr(unsafe.Pointer(&_pcache1_g))+140, libc.BoolInt32(_pcache1_g.FnFreeSlot < _pcache1_g.FnReserve), libc.Int32FromInt32(__ATOMIC_RELAXED))
|
|
_sqlite3StatusHighwater(tls, int32(SQLITE_STATUS_PAGECACHE_SIZE), nByte)
|
|
_sqlite3StatusUp(tls, int32(SQLITE_STATUS_PAGECACHE_USED), int32(1))
|
|
}
|
|
Xsqlite3_mutex_leave(tls, _pcache1_g.Fmutex)
|
|
}
|
|
if p == uintptr(0) {
|
|
/* Memory is not available in the SQLITE_CONFIG_PAGECACHE pool. Get
|
|
** it from sqlite3Malloc instead.
|
|
*/
|
|
p = _sqlite3Malloc(tls, libc.Uint64FromInt32(nByte))
|
|
if p != 0 {
|
|
sz = _sqlite3MallocSize(tls, p)
|
|
Xsqlite3_mutex_enter(tls, _pcache1_g.Fmutex)
|
|
_sqlite3StatusHighwater(tls, int32(SQLITE_STATUS_PAGECACHE_SIZE), nByte)
|
|
_sqlite3StatusUp(tls, int32(SQLITE_STATUS_PAGECACHE_OVERFLOW), sz)
|
|
Xsqlite3_mutex_leave(tls, _pcache1_g.Fmutex)
|
|
}
|
|
}
|
|
return p
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate a new page object initially associated with cache pCache.
|
|
// */
|
|
func _pcache1AllocPage(tls *libc.TLS, pCache uintptr, benignMalloc int32) (r uintptr) {
|
|
var p, pPg uintptr
|
|
_, _ = p, pPg
|
|
p = uintptr(0)
|
|
if (*TPCache1)(unsafe.Pointer(pCache)).FpFree != 0 || (*TPCache1)(unsafe.Pointer(pCache)).FnPage == uint32(0) && _pcache1InitBulk(tls, pCache) != 0 {
|
|
p = (*TPCache1)(unsafe.Pointer(pCache)).FpFree
|
|
(*TPCache1)(unsafe.Pointer(pCache)).FpFree = (*TPgHdr1)(unsafe.Pointer(p)).FpNext
|
|
(*TPgHdr1)(unsafe.Pointer(p)).FpNext = uintptr(0)
|
|
} else {
|
|
/* The group mutex must be released before pcache1Alloc() is called. This
|
|
** is because it might call sqlite3_release_memory(), which assumes that
|
|
** this mutex is not held. */
|
|
Xsqlite3_mutex_leave(tls, (*TPGroup)(unsafe.Pointer((*TPCache1)(unsafe.Pointer(pCache)).FpGroup)).Fmutex)
|
|
if benignMalloc != 0 {
|
|
_sqlite3BeginBenignMalloc(tls)
|
|
}
|
|
pPg = _pcache1Alloc(tls, (*TPCache1)(unsafe.Pointer(pCache)).FszAlloc)
|
|
if benignMalloc != 0 {
|
|
_sqlite3EndBenignMalloc(tls)
|
|
}
|
|
Xsqlite3_mutex_enter(tls, (*TPGroup)(unsafe.Pointer((*TPCache1)(unsafe.Pointer(pCache)).FpGroup)).Fmutex)
|
|
if pPg == uintptr(0) {
|
|
return uintptr(0)
|
|
}
|
|
p = pPg + uintptr((*TPCache1)(unsafe.Pointer(pCache)).FszPage)
|
|
(*TPgHdr1)(unsafe.Pointer(p)).Fpage.FpBuf = pPg
|
|
(*TPgHdr1)(unsafe.Pointer(p)).Fpage.FpExtra = p + uintptr((libc.Uint64FromInt64(56)+libc.Uint64FromInt32(7))&libc.Uint64FromInt32(^libc.Int32FromInt32(7)))
|
|
(*TPgHdr1)(unsafe.Pointer(p)).FisBulkLocal = uint16(0)
|
|
(*TPgHdr1)(unsafe.Pointer(p)).FisAnchor = uint16(0)
|
|
(*TPgHdr1)(unsafe.Pointer(p)).FpLruPrev = uintptr(0) /* Initializing this saves a valgrind error */
|
|
}
|
|
**(**uint32)(__ccgo_up((*TPCache1)(unsafe.Pointer(pCache)).FpnPurgeable)) = **(**uint32)(__ccgo_up((*TPCache1)(unsafe.Pointer(pCache)).FpnPurgeable)) + 1
|
|
return p
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Implementation of the sqlite3_pcache.xCachesize method.
|
|
// **
|
|
// ** Configure the cache_size limit for a cache.
|
|
// */
|
|
func _pcache1Cachesize(tls *libc.TLS, p uintptr, nMax int32) {
|
|
var n Tu32
|
|
var pCache, pGroup uintptr
|
|
_, _, _ = n, pCache, pGroup
|
|
pCache = p
|
|
if (*TPCache1)(unsafe.Pointer(pCache)).FbPurgeable != 0 {
|
|
pGroup = (*TPCache1)(unsafe.Pointer(pCache)).FpGroup
|
|
Xsqlite3_mutex_enter(tls, (*TPGroup)(unsafe.Pointer(pGroup)).Fmutex)
|
|
n = libc.Uint32FromInt32(nMax)
|
|
if n > uint32(0x7fff0000)-(*TPGroup)(unsafe.Pointer(pGroup)).FnMaxPage+(*TPCache1)(unsafe.Pointer(pCache)).FnMax {
|
|
n = uint32(0x7fff0000) - (*TPGroup)(unsafe.Pointer(pGroup)).FnMaxPage + (*TPCache1)(unsafe.Pointer(pCache)).FnMax
|
|
}
|
|
**(**uint32)(__ccgo_up(pGroup + 8)) += n - (*TPCache1)(unsafe.Pointer(pCache)).FnMax
|
|
(*TPGroup)(unsafe.Pointer(pGroup)).FmxPinned = (*TPGroup)(unsafe.Pointer(pGroup)).FnMaxPage + uint32(10) - (*TPGroup)(unsafe.Pointer(pGroup)).FnMinPage
|
|
(*TPCache1)(unsafe.Pointer(pCache)).FnMax = n
|
|
(*TPCache1)(unsafe.Pointer(pCache)).Fn90pct = (*TPCache1)(unsafe.Pointer(pCache)).FnMax * uint32(9) / uint32(10)
|
|
_pcache1EnforceMaxPage(tls, pCache)
|
|
Xsqlite3_mutex_leave(tls, (*TPGroup)(unsafe.Pointer(pGroup)).Fmutex)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Implementation of the sqlite3_pcache.xCreate method.
|
|
// **
|
|
// ** Allocate a new cache.
|
|
// */
|
|
func _pcache1Create(tls *libc.TLS, szPage int32, szExtra int32, bPurgeable int32) (r uintptr) {
|
|
var pCache, pGroup, v1 uintptr
|
|
var sz Ti64
|
|
var v2 int32
|
|
_, _, _, _, _ = pCache, pGroup, sz, v1, v2 /* Bytes of memory required to allocate the new cache */
|
|
sz = libc.Int64FromUint64(uint64(88) + uint64(80)*libc.Uint64FromInt32(_pcache1_g.FseparateCache))
|
|
pCache = _sqlite3MallocZero(tls, libc.Uint64FromInt64(sz))
|
|
if pCache != 0 {
|
|
if _pcache1_g.FseparateCache != 0 {
|
|
pGroup = pCache + 1*88
|
|
(*TPGroup)(unsafe.Pointer(pGroup)).FmxPinned = uint32(10)
|
|
} else {
|
|
pGroup = uintptr(unsafe.Pointer(&_pcache1_g))
|
|
}
|
|
Xsqlite3_mutex_enter(tls, (*TPGroup)(unsafe.Pointer(pGroup)).Fmutex)
|
|
if libc.Int32FromUint16((*TPGroup)(unsafe.Pointer(pGroup)).Flru.FisAnchor) == 0 {
|
|
(*TPGroup)(unsafe.Pointer(pGroup)).Flru.FisAnchor = uint16(1)
|
|
v1 = pGroup + 24
|
|
(*TPGroup)(unsafe.Pointer(pGroup)).Flru.FpLruNext = v1
|
|
(*TPGroup)(unsafe.Pointer(pGroup)).Flru.FpLruPrev = v1
|
|
}
|
|
(*TPCache1)(unsafe.Pointer(pCache)).FpGroup = pGroup
|
|
(*TPCache1)(unsafe.Pointer(pCache)).FszPage = szPage
|
|
(*TPCache1)(unsafe.Pointer(pCache)).FszExtra = szExtra
|
|
(*TPCache1)(unsafe.Pointer(pCache)).FszAlloc = libc.Int32FromUint64(libc.Uint64FromInt32(szPage+szExtra) + (libc.Uint64FromInt64(56)+libc.Uint64FromInt32(7))&libc.Uint64FromInt32(^libc.Int32FromInt32(7)))
|
|
if bPurgeable != 0 {
|
|
v2 = int32(1)
|
|
} else {
|
|
v2 = 0
|
|
}
|
|
(*TPCache1)(unsafe.Pointer(pCache)).FbPurgeable = v2
|
|
_pcache1ResizeHash(tls, pCache)
|
|
if bPurgeable != 0 {
|
|
(*TPCache1)(unsafe.Pointer(pCache)).FnMin = uint32(10)
|
|
**(**uint32)(__ccgo_up(pGroup + 12)) += (*TPCache1)(unsafe.Pointer(pCache)).FnMin
|
|
(*TPGroup)(unsafe.Pointer(pGroup)).FmxPinned = (*TPGroup)(unsafe.Pointer(pGroup)).FnMaxPage + uint32(10) - (*TPGroup)(unsafe.Pointer(pGroup)).FnMinPage
|
|
(*TPCache1)(unsafe.Pointer(pCache)).FpnPurgeable = pGroup + 20
|
|
} else {
|
|
(*TPCache1)(unsafe.Pointer(pCache)).FpnPurgeable = pCache + 48
|
|
}
|
|
Xsqlite3_mutex_leave(tls, (*TPGroup)(unsafe.Pointer(pGroup)).Fmutex)
|
|
if (*TPCache1)(unsafe.Pointer(pCache)).FnHash == uint32(0) {
|
|
_pcache1Destroy(tls, pCache)
|
|
pCache = uintptr(0)
|
|
}
|
|
}
|
|
return pCache
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Implement steps 3, 4, and 5 of the pcache1Fetch() algorithm described
|
|
// ** in the header of the pcache1Fetch() procedure.
|
|
// **
|
|
// ** This steps are broken out into a separate procedure because they are
|
|
// ** usually not needed, and by avoiding the stack initialization required
|
|
// ** for these steps, the main pcache1Fetch() procedure can run faster.
|
|
// */
|
|
func _pcache1FetchStage2(tls *libc.TLS, pCache uintptr, iKey uint32, createFlag int32) (r uintptr) {
|
|
var h, nPinned uint32
|
|
var pGroup, pOther, pPage uintptr
|
|
_, _, _, _, _ = h, nPinned, pGroup, pOther, pPage
|
|
pGroup = (*TPCache1)(unsafe.Pointer(pCache)).FpGroup
|
|
pPage = uintptr(0)
|
|
/* Step 3: Abort if createFlag is 1 but the cache is nearly full */
|
|
nPinned = (*TPCache1)(unsafe.Pointer(pCache)).FnPage - (*TPCache1)(unsafe.Pointer(pCache)).FnRecyclable
|
|
if createFlag == int32(1) && (nPinned >= (*TPGroup)(unsafe.Pointer(pGroup)).FmxPinned || nPinned >= (*TPCache1)(unsafe.Pointer(pCache)).Fn90pct || _pcache1UnderMemoryPressure(tls, pCache) != 0 && (*TPCache1)(unsafe.Pointer(pCache)).FnRecyclable < nPinned) {
|
|
return uintptr(0)
|
|
}
|
|
if (*TPCache1)(unsafe.Pointer(pCache)).FnPage >= (*TPCache1)(unsafe.Pointer(pCache)).FnHash {
|
|
_pcache1ResizeHash(tls, pCache)
|
|
}
|
|
/* Step 4. Try to recycle a page. */
|
|
if (*TPCache1)(unsafe.Pointer(pCache)).FbPurgeable != 0 && !((*TPgHdr1)(unsafe.Pointer((*TPGroup)(unsafe.Pointer(pGroup)).Flru.FpLruPrev)).FisAnchor != 0) && ((*TPCache1)(unsafe.Pointer(pCache)).FnPage+uint32(1) >= (*TPCache1)(unsafe.Pointer(pCache)).FnMax || _pcache1UnderMemoryPressure(tls, pCache) != 0) {
|
|
pPage = (*TPGroup)(unsafe.Pointer(pGroup)).Flru.FpLruPrev
|
|
_pcache1RemoveFromHash(tls, pPage, 0)
|
|
_pcache1PinPage(tls, pPage)
|
|
pOther = (*TPgHdr1)(unsafe.Pointer(pPage)).FpCache
|
|
if (*TPCache1)(unsafe.Pointer(pOther)).FszAlloc != (*TPCache1)(unsafe.Pointer(pCache)).FszAlloc {
|
|
_pcache1FreePage(tls, pPage)
|
|
pPage = uintptr(0)
|
|
} else {
|
|
**(**uint32)(__ccgo_up(pGroup + 20)) -= libc.Uint32FromInt32((*TPCache1)(unsafe.Pointer(pOther)).FbPurgeable - (*TPCache1)(unsafe.Pointer(pCache)).FbPurgeable)
|
|
}
|
|
}
|
|
/* Step 5. If a usable page buffer has still not been found,
|
|
** attempt to allocate a new one.
|
|
*/
|
|
if !(pPage != 0) {
|
|
pPage = _pcache1AllocPage(tls, pCache, libc.BoolInt32(createFlag == int32(1)))
|
|
}
|
|
if pPage != 0 {
|
|
h = iKey % (*TPCache1)(unsafe.Pointer(pCache)).FnHash
|
|
(*TPCache1)(unsafe.Pointer(pCache)).FnPage = (*TPCache1)(unsafe.Pointer(pCache)).FnPage + 1
|
|
(*TPgHdr1)(unsafe.Pointer(pPage)).FiKey = iKey
|
|
(*TPgHdr1)(unsafe.Pointer(pPage)).FpNext = **(**uintptr)(__ccgo_up((*TPCache1)(unsafe.Pointer(pCache)).FapHash + uintptr(h)*8))
|
|
(*TPgHdr1)(unsafe.Pointer(pPage)).FpCache = pCache
|
|
(*TPgHdr1)(unsafe.Pointer(pPage)).FpLruNext = uintptr(0)
|
|
/* pPage->pLruPrev = 0;
|
|
** No need to clear pLruPrev since it is not accessed when pLruNext==0 */
|
|
**(**uintptr)(__ccgo_up((*TPgHdr1)(unsafe.Pointer(pPage)).Fpage.FpExtra)) = uintptr(0)
|
|
**(**uintptr)(__ccgo_up((*TPCache1)(unsafe.Pointer(pCache)).FapHash + uintptr(h)*8)) = pPage
|
|
if iKey > (*TPCache1)(unsafe.Pointer(pCache)).FiMaxKey {
|
|
(*TPCache1)(unsafe.Pointer(pCache)).FiMaxKey = iKey
|
|
}
|
|
}
|
|
return pPage
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Try to initialize the pCache->pFree and pCache->pBulk fields. Return
|
|
// ** true if pCache->pFree ends up containing one or more free pages.
|
|
// */
|
|
func _pcache1InitBulk(tls *libc.TLS, pCache uintptr) (r int32) {
|
|
var nBulk, v2 int32
|
|
var pX, zBulk, v1 uintptr
|
|
var szBulk Ti64
|
|
_, _, _, _, _, _ = nBulk, pX, szBulk, zBulk, v1, v2
|
|
if _pcache1_g.FnInitPage == 0 {
|
|
return 0
|
|
}
|
|
/* Do not bother with a bulk allocation if the cache size very small */
|
|
if (*TPCache1)(unsafe.Pointer(pCache)).FnMax < uint32(3) {
|
|
return 0
|
|
}
|
|
_sqlite3BeginBenignMalloc(tls)
|
|
if _pcache1_g.FnInitPage > 0 {
|
|
szBulk = int64((*TPCache1)(unsafe.Pointer(pCache)).FszAlloc) * int64(_pcache1_g.FnInitPage)
|
|
} else {
|
|
szBulk = int64(-int32(1024)) * int64(_pcache1_g.FnInitPage)
|
|
}
|
|
if szBulk > int64((*TPCache1)(unsafe.Pointer(pCache)).FszAlloc)*libc.Int64FromUint32((*TPCache1)(unsafe.Pointer(pCache)).FnMax) {
|
|
szBulk = int64((*TPCache1)(unsafe.Pointer(pCache)).FszAlloc) * libc.Int64FromUint32((*TPCache1)(unsafe.Pointer(pCache)).FnMax)
|
|
}
|
|
if szBulk >= int64((*TPCache1)(unsafe.Pointer(pCache)).FszAlloc) {
|
|
v1 = _sqlite3Malloc(tls, libc.Uint64FromInt64(szBulk))
|
|
(*TPCache1)(unsafe.Pointer(pCache)).FpBulk = v1
|
|
zBulk = v1
|
|
_sqlite3EndBenignMalloc(tls)
|
|
if zBulk != 0 {
|
|
nBulk = _sqlite3MallocSize(tls, zBulk) / (*TPCache1)(unsafe.Pointer(pCache)).FszAlloc
|
|
for {
|
|
pX = zBulk + uintptr((*TPCache1)(unsafe.Pointer(pCache)).FszPage)
|
|
(*TPgHdr1)(unsafe.Pointer(pX)).Fpage.FpBuf = zBulk
|
|
(*TPgHdr1)(unsafe.Pointer(pX)).Fpage.FpExtra = pX + uintptr((libc.Uint64FromInt64(56)+libc.Uint64FromInt32(7))&libc.Uint64FromInt32(^libc.Int32FromInt32(7)))
|
|
(*TPgHdr1)(unsafe.Pointer(pX)).FisBulkLocal = uint16(1)
|
|
(*TPgHdr1)(unsafe.Pointer(pX)).FisAnchor = uint16(0)
|
|
(*TPgHdr1)(unsafe.Pointer(pX)).FpNext = (*TPCache1)(unsafe.Pointer(pCache)).FpFree
|
|
(*TPgHdr1)(unsafe.Pointer(pX)).FpLruPrev = uintptr(0) /* Initializing this saves a valgrind error */
|
|
(*TPCache1)(unsafe.Pointer(pCache)).FpFree = pX
|
|
zBulk = zBulk + uintptr((*TPCache1)(unsafe.Pointer(pCache)).FszAlloc)
|
|
goto _3
|
|
_3:
|
|
;
|
|
nBulk = nBulk - 1
|
|
v2 = nBulk
|
|
if !(v2 != 0) {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return libc.BoolInt32((*TPCache1)(unsafe.Pointer(pCache)).FpFree != uintptr(0))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Make sure the cell sizes at idx, idx+1, ..., idx+N-1 have been
|
|
// ** computed.
|
|
// */
|
|
func _populateCellCache(tls *libc.TLS, p uintptr, idx int32, N int32) {
|
|
var pRef, szCell uintptr
|
|
_, _ = pRef, szCell
|
|
pRef = (*TCellArray)(unsafe.Pointer(p)).FpRef
|
|
szCell = (*TCellArray)(unsafe.Pointer(p)).FszCell
|
|
for N > 0 {
|
|
if libc.Int32FromUint16(**(**Tu16)(__ccgo_up(szCell + uintptr(idx)*2))) == 0 {
|
|
**(**Tu16)(__ccgo_up(szCell + uintptr(idx)*2)) = (*(*func(*libc.TLS, uintptr, uintptr) Tu16)(unsafe.Pointer(&struct{ uintptr }{(*TMemPage)(unsafe.Pointer(pRef)).FxCellSize})))(tls, pRef, **(**uintptr)(__ccgo_up((*TCellArray)(unsafe.Pointer(p)).FapCell + uintptr(idx)*8)))
|
|
} else {
|
|
}
|
|
idx = idx + 1
|
|
N = N - 1
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* The xColumn method simply returns the corresponding column from
|
|
// ** the PRAGMA.
|
|
// */
|
|
func _pragmaVtabColumn(tls *libc.TLS, pVtabCursor uintptr, ctx uintptr, i int32) (r int32) {
|
|
var pCsr, pTab uintptr
|
|
_, _ = pCsr, pTab
|
|
pCsr = pVtabCursor
|
|
pTab = (*Tsqlite3_vtab_cursor)(unsafe.Pointer(pVtabCursor)).FpVtab
|
|
if i < libc.Int32FromUint8((*TPragmaVtab)(unsafe.Pointer(pTab)).FiHidden) {
|
|
Xsqlite3_result_value(tls, ctx, Xsqlite3_column_value(tls, (*TPragmaVtabCursor)(unsafe.Pointer(pCsr)).FpPragma, i))
|
|
} else {
|
|
Xsqlite3_result_text(tls, ctx, **(**uintptr)(__ccgo_up(pCsr + 24 + uintptr(i-libc.Int32FromUint8((*TPragmaVtab)(unsafe.Pointer(pTab)).FiHidden))*8)), -int32(1), uintptr(-libc.Int32FromInt32(1)))
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Clear all content from pragma virtual table cursor. */
|
|
func _pragmaVtabCursorClear(tls *libc.TLS, pCsr uintptr) {
|
|
var i int32
|
|
_ = i
|
|
Xsqlite3_finalize(tls, (*TPragmaVtabCursor)(unsafe.Pointer(pCsr)).FpPragma)
|
|
(*TPragmaVtabCursor)(unsafe.Pointer(pCsr)).FpPragma = uintptr(0)
|
|
(*TPragmaVtabCursor)(unsafe.Pointer(pCsr)).FiRowid = 0
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint64(libc.Uint64FromInt64(16)/libc.Uint64FromInt64(8))) {
|
|
break
|
|
}
|
|
Xsqlite3_free(tls, **(**uintptr)(__ccgo_up(pCsr + 24 + uintptr(i)*8)))
|
|
**(**uintptr)(__ccgo_up(pCsr + 24 + uintptr(i)*8)) = uintptr(0)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** fts5VisitEntries() callback used by fts5SetupPrefixIter()
|
|
// */
|
|
func _prefixIterSetupCb(tls *libc.TLS, p uintptr, pCtx uintptr, p1 uintptr, pNew uintptr, nNew int32) {
|
|
var i, i1, iStore, nMerge int32
|
|
var pSetup uintptr
|
|
_, _, _, _, _ = i, i1, iStore, nMerge, pSetup
|
|
pSetup = pCtx
|
|
nMerge = (*TPrefixSetupCtx)(unsafe.Pointer(pSetup)).FnMerge
|
|
if (*TFts5Iter)(unsafe.Pointer(p1)).Fbase.FnData > 0 {
|
|
if (*TFts5Iter)(unsafe.Pointer(p1)).Fbase.FiRowid <= (*TPrefixSetupCtx)(unsafe.Pointer(pSetup)).FiLastRowid && (*TPrefixSetupCtx)(unsafe.Pointer(pSetup)).Fdoclist.Fn > 0 {
|
|
i = 0
|
|
for {
|
|
if !((*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK && (*TPrefixSetupCtx)(unsafe.Pointer(pSetup)).Fdoclist.Fn != 0) {
|
|
break
|
|
}
|
|
i1 = i * nMerge
|
|
iStore = i1
|
|
for {
|
|
if !(iStore < i1+nMerge) {
|
|
break
|
|
}
|
|
if (**(**TFts5Buffer)(__ccgo_up((*TPrefixSetupCtx)(unsafe.Pointer(pSetup)).FaBuf + uintptr(iStore)*16))).Fn == 0 {
|
|
_fts5BufferSwap(tls, pSetup+48, (*TPrefixSetupCtx)(unsafe.Pointer(pSetup)).FaBuf+uintptr(iStore)*16)
|
|
_sqlite3Fts5BufferZero(tls, pSetup+48)
|
|
break
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
iStore = iStore + 1
|
|
}
|
|
if iStore == i1+nMerge {
|
|
(*(*func(*libc.TLS, uintptr, uintptr, int32, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TPrefixSetupCtx)(unsafe.Pointer(pSetup)).FxMerge})))(tls, p, pSetup+48, nMerge, (*TPrefixSetupCtx)(unsafe.Pointer(pSetup)).FaBuf+uintptr(i1)*16)
|
|
iStore = i1
|
|
for {
|
|
if !(iStore < i1+nMerge) {
|
|
break
|
|
}
|
|
_sqlite3Fts5BufferZero(tls, (*TPrefixSetupCtx)(unsafe.Pointer(pSetup)).FaBuf+uintptr(iStore)*16)
|
|
goto _3
|
|
_3:
|
|
;
|
|
iStore = iStore + 1
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
(*TPrefixSetupCtx)(unsafe.Pointer(pSetup)).FiLastRowid = 0
|
|
}
|
|
(*(*func(*libc.TLS, uintptr, Tu64, uintptr, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TPrefixSetupCtx)(unsafe.Pointer(pSetup)).FxAppend})))(tls, p, libc.Uint64FromInt64((*TFts5Iter)(unsafe.Pointer(p1)).Fbase.FiRowid)-libc.Uint64FromInt64((*TPrefixSetupCtx)(unsafe.Pointer(pSetup)).FiLastRowid), p1, pSetup+48)
|
|
(*TPrefixSetupCtx)(unsafe.Pointer(pSetup)).FiLastRowid = (*TFts5Iter)(unsafe.Pointer(p1)).Fbase.FiRowid
|
|
}
|
|
if (*TPrefixSetupCtx)(unsafe.Pointer(pSetup)).FpTokendata != 0 {
|
|
_prefixIterSetupTokendataCb(tls, p, (*TPrefixSetupCtx)(unsafe.Pointer(pSetup)).FpTokendata, p1, pNew, nNew)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** fts5VisitEntries() callback used by fts5SetupPrefixIterTokendata(). This
|
|
// ** callback adds an entry to the Fts5TokenDataIter.aMap[] array for each
|
|
// ** position in the current position-list. It doesn't matter that some of
|
|
// ** these may be out of order - they will be sorted later.
|
|
// */
|
|
func _prefixIterSetupTokendataCb(tls *libc.TLS, p uintptr, pCtx uintptr, p1 uintptr, pNew uintptr, nNew int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var pSetup uintptr
|
|
var _ /* iPos at bp+8 */ Ti64
|
|
var _ /* iPosOff at bp+0 */ int32
|
|
_ = pSetup
|
|
pSetup = pCtx
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
**(**Ti64)(__ccgo_up(bp + 8)) = 0
|
|
if pNew != 0 {
|
|
(*TTokendataSetupCtx)(unsafe.Pointer(pSetup)).FnTermByte = nNew - int32(1)
|
|
(*TTokendataSetupCtx)(unsafe.Pointer(pSetup)).FiTermOff = (*TFts5TokenDataIter)(unsafe.Pointer((*TTokendataSetupCtx)(unsafe.Pointer(pSetup)).FpT)).Fterms.Fn
|
|
_sqlite3Fts5BufferAppendBlob(tls, p+60, (*TTokendataSetupCtx)(unsafe.Pointer(pSetup)).FpT+24, libc.Uint32FromInt32(nNew-int32(1)), pNew+uintptr(1))
|
|
}
|
|
for 0 == _sqlite3Fts5PoslistNext64(tls, (*TFts5Iter)(unsafe.Pointer(p1)).Fbase.FpData, (*TFts5Iter)(unsafe.Pointer(p1)).Fbase.FnData, bp, bp+8) {
|
|
_fts5TokendataIterAppendMap(tls, p, (*TTokendataSetupCtx)(unsafe.Pointer(pSetup)).FpT, (*TTokendataSetupCtx)(unsafe.Pointer(pSetup)).FiTermOff, (*TTokendataSetupCtx)(unsafe.Pointer(pSetup)).FnTermByte, (*TFts5Iter)(unsafe.Pointer(p1)).Fbase.FiRowid, **(**Ti64)(__ccgo_up(bp + 8)))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Implementation of the printf() (a.k.a. format()) SQL function.
|
|
// */
|
|
func _printfFunc(tls *libc.TLS, context uintptr, argc int32, argv uintptr) {
|
|
bp := tls.Alloc(64)
|
|
defer tls.Free(64)
|
|
var db, zFormat, v1 uintptr
|
|
var n int32
|
|
var v2 bool
|
|
var _ /* str at bp+16 */ TStrAccum
|
|
var _ /* x at bp+0 */ TPrintfArguments
|
|
_, _, _, _, _ = db, n, zFormat, v1, v2
|
|
db = Xsqlite3_context_db_handle(tls, context)
|
|
if v2 = argc >= int32(1); v2 {
|
|
v1 = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
zFormat = v1
|
|
}
|
|
if v2 && v1 != uintptr(0) {
|
|
(**(**TPrintfArguments)(__ccgo_up(bp))).FnArg = argc - int32(1)
|
|
(**(**TPrintfArguments)(__ccgo_up(bp))).FnUsed = 0
|
|
(**(**TPrintfArguments)(__ccgo_up(bp))).FapArg = argv + uintptr(1)*8
|
|
_sqlite3StrAccumInit(tls, bp+16, db, uintptr(0), 0, **(**int32)(__ccgo_up(db + 136)))
|
|
(**(**TStrAccum)(__ccgo_up(bp + 16))).FprintfFlags = uint8(SQLITE_PRINTF_SQLFUNC)
|
|
Xsqlite3_str_appendf(tls, bp+16, zFormat, libc.VaList(bp+56, bp))
|
|
if libc.Int32FromUint8((**(**TStrAccum)(__ccgo_up(bp + 16))).FaccError) == SQLITE_OK {
|
|
n = libc.Int32FromUint32((**(**TStrAccum)(__ccgo_up(bp + 16))).FnChar)
|
|
Xsqlite3_result_text(tls, context, _sqlite3StrAccumFinish(tls, bp+16), n, __ccgo_fp(_sqlite3RowSetClear))
|
|
} else {
|
|
if libc.Int32FromUint8((**(**TStrAccum)(__ccgo_up(bp + 16))).FaccError) == int32(SQLITE_NOMEM) {
|
|
Xsqlite3_result_error_nomem(tls, context)
|
|
} else {
|
|
Xsqlite3_result_error_toobig(tls, context)
|
|
}
|
|
Xsqlite3_str_reset(tls, bp+16)
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The cell pCell is currently part of page pSrc but will ultimately be part
|
|
// ** of pPage. (pSrc and pPage are often the same.) If pCell contains a
|
|
// ** pointer to an overflow page, insert an entry into the pointer-map for
|
|
// ** the overflow page that will be valid after pCell has been moved to pPage.
|
|
// */
|
|
func _ptrmapPutOvflPtr(tls *libc.TLS, pPage uintptr, pSrc uintptr, pCell uintptr, pRC uintptr) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var ovfl TPgno
|
|
var _ /* info at bp+0 */ TCellInfo
|
|
_ = ovfl
|
|
if **(**int32)(__ccgo_up(pRC)) != 0 {
|
|
return
|
|
}
|
|
(*(*func(*libc.TLS, uintptr, uintptr, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TMemPage)(unsafe.Pointer(pPage)).FxParseCell})))(tls, pPage, pCell, bp)
|
|
if uint32((**(**TCellInfo)(__ccgo_up(bp))).FnLocal) < (**(**TCellInfo)(__ccgo_up(bp))).FnPayload {
|
|
if uint64(pCell) < uint64((*TMemPage)(unsafe.Pointer(pSrc)).FaDataEnd) && uint64(pCell+uintptr((**(**TCellInfo)(__ccgo_up(bp))).FnLocal)) > uint64((*TMemPage)(unsafe.Pointer(pSrc)).FaDataEnd) {
|
|
**(**int32)(__ccgo_up(pRC)) = _sqlite3CorruptError(tls, int32(74817))
|
|
return
|
|
}
|
|
ovfl = _sqlite3Get4byte(tls, pCell+uintptr(libc.Int32FromUint16((**(**TCellInfo)(__ccgo_up(bp))).FnSize)-int32(4)))
|
|
_ptrmapPut(tls, (*TMemPage)(unsafe.Pointer(pPage)).FpBt, ovfl, uint8(PTRMAP_OVERFLOW1), (*TMemPage)(unsafe.Pointer(pPage)).Fpgno, pRC)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Make copies of relevant WHERE clause terms of the outer query into
|
|
// ** the WHERE clause of subquery. Example:
|
|
// **
|
|
// ** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1) WHERE x=5 AND y=10;
|
|
// **
|
|
// ** Transformed into:
|
|
// **
|
|
// ** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1 WHERE a=5 AND c-d=10)
|
|
// ** WHERE x=5 AND y=10;
|
|
// **
|
|
// ** The hope is that the terms added to the inner query will make it more
|
|
// ** efficient.
|
|
// **
|
|
// ** NAME AMBIGUITY
|
|
// **
|
|
// ** This optimization is called the "WHERE-clause push-down optimization"
|
|
// ** or sometimes the "predicate push-down optimization".
|
|
// **
|
|
// ** Do not confuse this optimization with another unrelated optimization
|
|
// ** with a similar name: The "MySQL push-down optimization" causes WHERE
|
|
// ** clause terms that can be evaluated using only the index and without
|
|
// ** reference to the table are run first, so that if they are false,
|
|
// ** unnecessary table seeks are avoided.
|
|
// **
|
|
// ** RULES
|
|
// **
|
|
// ** Do not attempt this optimization if:
|
|
// **
|
|
// ** (1) (** This restriction was removed on 2017-09-29. We used to
|
|
// ** disallow this optimization for aggregate subqueries, but now
|
|
// ** it is allowed by putting the extra terms on the HAVING clause.
|
|
// ** The added HAVING clause is pointless if the subquery lacks
|
|
// ** a GROUP BY clause. But such a HAVING clause is also harmless
|
|
// ** so there does not appear to be any reason to add extra logic
|
|
// ** to suppress it. **)
|
|
// **
|
|
// ** (2) The inner query is the recursive part of a common table expression.
|
|
// **
|
|
// ** (3) The inner query has a LIMIT clause (since the changes to the WHERE
|
|
// ** clause would change the meaning of the LIMIT).
|
|
// **
|
|
// ** (4) The inner query is the right operand of a LEFT JOIN and the
|
|
// ** expression to be pushed down does not come from the ON clause
|
|
// ** on that LEFT JOIN.
|
|
// **
|
|
// ** (5) The WHERE clause expression originates in the ON or USING clause
|
|
// ** of a LEFT JOIN where iCursor is not the right-hand table of that
|
|
// ** left join. An example:
|
|
// **
|
|
// ** SELECT *
|
|
// ** FROM (SELECT 1 AS a1 UNION ALL SELECT 2) AS aa
|
|
// ** JOIN (SELECT 1 AS b2 UNION ALL SELECT 2) AS bb ON (a1=b2)
|
|
// ** LEFT JOIN (SELECT 8 AS c3 UNION ALL SELECT 9) AS cc ON (b2=2);
|
|
// **
|
|
// ** The correct answer is three rows: (1,1,NULL),(2,2,8),(2,2,9).
|
|
// ** But if the (b2=2) term were to be pushed down into the bb subquery,
|
|
// ** then the (1,1,NULL) row would be suppressed.
|
|
// **
|
|
// ** (6) Window functions make things tricky as changes to the WHERE clause
|
|
// ** of the inner query could change the window over which window
|
|
// ** functions are calculated. Therefore, do not attempt the optimization
|
|
// ** if:
|
|
// **
|
|
// ** (6a) The inner query uses multiple incompatible window partitions.
|
|
// **
|
|
// ** (6b) The inner query is a compound and uses window-functions.
|
|
// **
|
|
// ** (6c) The WHERE clause does not consist entirely of constants and
|
|
// ** copies of expressions found in the PARTITION BY clause of
|
|
// ** all window-functions used by the sub-query. It is safe to
|
|
// ** filter out entire partitions, as this does not change the
|
|
// ** window over which any window-function is calculated.
|
|
// **
|
|
// ** (7) The inner query is a Common Table Expression (CTE) that should
|
|
// ** be materialized. (This restriction is implemented in the calling
|
|
// ** routine.)
|
|
// **
|
|
// ** (8) If the subquery is a compound that uses UNION, INTERSECT,
|
|
// ** or EXCEPT, then all of the result set columns for all arms of
|
|
// ** the compound must use the BINARY collating sequence.
|
|
// **
|
|
// ** (9) All three of the following are true:
|
|
// **
|
|
// ** (9a) The WHERE clause expression originates in the ON or USING clause
|
|
// ** of a join (either an INNER or an OUTER join), and
|
|
// **
|
|
// ** (9b) The subquery is to the right of the ON/USING clause
|
|
// **
|
|
// ** (9c) There is a RIGHT JOIN (or FULL JOIN) in between the ON/USING
|
|
// ** clause and the subquery.
|
|
// **
|
|
// ** Without this restriction, the WHERE-clause push-down optimization
|
|
// ** might move the ON/USING filter expression from the left side of a
|
|
// ** RIGHT JOIN over to the right side, which leads to incorrect answers.
|
|
// ** See also restriction (6) in sqlite3ExprIsSingleTableConstraint().
|
|
// **
|
|
// ** (10) The inner query is not the right-hand table of a RIGHT JOIN.
|
|
// **
|
|
// ** (11) The subquery is not a VALUES clause
|
|
// **
|
|
// ** (12) The WHERE clause is not "rowid ISNULL" or the equivalent. This
|
|
// ** case only comes up if SQLite is compiled using
|
|
// ** SQLITE_ALLOW_ROWID_IN_VIEW.
|
|
// **
|
|
// ** Return 0 if no changes are made and non-zero if one or more WHERE clause
|
|
// ** terms are duplicated into the subquery.
|
|
// */
|
|
func _pushDownWhereTerms(tls *libc.TLS, pParse uintptr, pSubq uintptr, pWhere uintptr, pSrcList uintptr, iSrc int32) (r int32) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var ii, nChng, notUnionAll int32
|
|
var op Tu8
|
|
var pColl, pList, pNew, pSel, pSrc uintptr
|
|
var _ /* x at bp+0 */ TSubstContext
|
|
_, _, _, _, _, _, _, _, _ = ii, nChng, notUnionAll, op, pColl, pList, pNew, pSel, pSrc /* The subquery FROM term into which WHERE is pushed */
|
|
nChng = 0
|
|
pSrc = pSrcList + 8 + uintptr(iSrc)*80
|
|
if pWhere == uintptr(0) {
|
|
return 0
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(pSubq)).FselFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SF_Recursive)|libc.Int32FromInt32(SF_MultiPart)) != 0 {
|
|
return 0 /* restrictions (2) and (11) */
|
|
}
|
|
if libc.Int32FromUint8((*TSrcItem)(unsafe.Pointer(pSrc)).Ffg.Fjointype)&(libc.Int32FromInt32(JT_LTORJ)|libc.Int32FromInt32(JT_RIGHT)) != 0 {
|
|
return 0 /* restrictions (10) */
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(pSubq)).FpPrior != 0 {
|
|
notUnionAll = 0
|
|
pSel = pSubq
|
|
for {
|
|
if !(pSel != 0) {
|
|
break
|
|
}
|
|
op = (*TSelect)(unsafe.Pointer(pSel)).Fop
|
|
if libc.Int32FromUint8(op) != int32(TK_ALL) && libc.Int32FromUint8(op) != int32(TK_SELECT) {
|
|
notUnionAll = int32(1)
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(pSel)).FpWin != 0 {
|
|
return 0
|
|
} /* restriction (6b) */
|
|
goto _1
|
|
_1:
|
|
;
|
|
pSel = (*TSelect)(unsafe.Pointer(pSel)).FpPrior
|
|
}
|
|
if notUnionAll != 0 {
|
|
/* If any of the compound arms are connected using UNION, INTERSECT,
|
|
** or EXCEPT, then we must ensure that none of the columns use a
|
|
** non-BINARY collating sequence. */
|
|
pSel = pSubq
|
|
for {
|
|
if !(pSel != 0) {
|
|
break
|
|
}
|
|
pList = (*TSelect)(unsafe.Pointer(pSel)).FpEList
|
|
ii = 0
|
|
for {
|
|
if !(ii < (*TExprList)(unsafe.Pointer(pList)).FnExpr) {
|
|
break
|
|
}
|
|
pColl = _sqlite3ExprCollSeq(tls, pParse, (*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(ii)*32))).FpExpr)
|
|
if !(_sqlite3IsBinary(tls, pColl) != 0) {
|
|
return 0 /* Restriction (8) */
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
pSel = (*TSelect)(unsafe.Pointer(pSel)).FpPrior
|
|
}
|
|
}
|
|
} else {
|
|
if (*TSelect)(unsafe.Pointer(pSubq)).FpWin != 0 && (*TWindow)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pSubq)).FpWin)).FpPartition == uintptr(0) {
|
|
return 0
|
|
}
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(pSubq)).FpLimit != uintptr(0) {
|
|
return 0 /* restriction (3) */
|
|
}
|
|
for libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pWhere)).Fop) == int32(TK_AND) {
|
|
nChng = nChng + _pushDownWhereTerms(tls, pParse, pSubq, (*TExpr)(unsafe.Pointer(pWhere)).FpRight, pSrcList, iSrc)
|
|
pWhere = (*TExpr)(unsafe.Pointer(pWhere)).FpLeft
|
|
}
|
|
if _sqlite3ExprIsSingleTableConstraint(tls, pWhere, pSrcList, iSrc, int32(1)) != 0 {
|
|
nChng = nChng + 1
|
|
**(**Tu32)(__ccgo_up(pSubq + 4)) |= uint32(SF_PushDown)
|
|
for pSubq != 0 {
|
|
pNew = _sqlite3ExprDup(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pWhere, 0)
|
|
_unsetJoinExpr(tls, pNew, -int32(1), int32(1))
|
|
(**(**TSubstContext)(__ccgo_up(bp))).FpParse = pParse
|
|
(**(**TSubstContext)(__ccgo_up(bp))).FiTable = (*TSrcItem)(unsafe.Pointer(pSrc)).FiCursor
|
|
(**(**TSubstContext)(__ccgo_up(bp))).FiNewTable = (*TSrcItem)(unsafe.Pointer(pSrc)).FiCursor
|
|
(**(**TSubstContext)(__ccgo_up(bp))).FisOuterJoin = 0
|
|
(**(**TSubstContext)(__ccgo_up(bp))).FnSelDepth = 0
|
|
(**(**TSubstContext)(__ccgo_up(bp))).FpEList = (*TSelect)(unsafe.Pointer(pSubq)).FpEList
|
|
(**(**TSubstContext)(__ccgo_up(bp))).FpCList = _findLeftmostExprlist(tls, pSubq)
|
|
pNew = _substExpr(tls, bp, pNew)
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr == 0 && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pNew)).Fop) == int32(TK_IN) && (*TExpr)(unsafe.Pointer(pNew)).Fflags&uint32(EP_xIsSelect) != uint32(0) {
|
|
**(**Tu32)(__ccgo_up(*(*uintptr)(unsafe.Pointer(pNew + 32)) + 4)) |= uint32(SF_ClonedRhsIn)
|
|
**(**Tu32)(__ccgo_up(*(*uintptr)(unsafe.Pointer(pWhere + 32)) + 4)) |= uint32(SF_ClonedRhsIn)
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(pSubq)).FpWin != 0 && 0 == _pushDownWindowCheck(tls, pParse, pSubq, pNew) {
|
|
/* Restriction 6c has prevented push-down in this case */
|
|
_sqlite3ExprDelete(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pNew)
|
|
nChng = nChng - 1
|
|
break
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(pSubq)).FselFlags&uint32(SF_Aggregate) != 0 {
|
|
(*TSelect)(unsafe.Pointer(pSubq)).FpHaving = _sqlite3ExprAnd(tls, pParse, (*TSelect)(unsafe.Pointer(pSubq)).FpHaving, pNew)
|
|
} else {
|
|
(*TSelect)(unsafe.Pointer(pSubq)).FpWhere = _sqlite3ExprAnd(tls, pParse, (*TSelect)(unsafe.Pointer(pSubq)).FpWhere, pNew)
|
|
}
|
|
pSubq = (*TSelect)(unsafe.Pointer(pSubq)).FpPrior
|
|
}
|
|
}
|
|
return nChng
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Query to see if Btree handle p may obtain a lock of type eLock
|
|
// ** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return
|
|
// ** SQLITE_OK if the lock may be obtained (by calling
|
|
// ** setSharedCacheTableLock()), or SQLITE_LOCKED if not.
|
|
// */
|
|
func _querySharedCacheTableLock(tls *libc.TLS, p uintptr, iTab TPgno, eLock Tu8) (r int32) {
|
|
var pBt, pIter, v2 uintptr
|
|
_, _, _ = pBt, pIter, v2
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt
|
|
/* If requesting a write-lock, then the Btree must have an open write
|
|
** transaction on this file. And, obviously, for this to be so there
|
|
** must be an open write transaction on the file itself.
|
|
*/
|
|
/* This routine is a no-op if the shared-cache is not enabled */
|
|
if !((*TBtree)(unsafe.Pointer(p)).Fsharable != 0) {
|
|
return SQLITE_OK
|
|
}
|
|
/* If some other connection is holding an exclusive lock, the
|
|
** requested lock may not be obtained.
|
|
*/
|
|
if (*TBtShared)(unsafe.Pointer(pBt)).FpWriter != p && libc.Int32FromUint16((*TBtShared)(unsafe.Pointer(pBt)).FbtsFlags)&int32(BTS_EXCLUSIVE) != 0 {
|
|
_sqlite3ConnectionBlocked(tls, (*TBtree)(unsafe.Pointer(p)).Fdb, (*TBtree)(unsafe.Pointer((*TBtShared)(unsafe.Pointer(pBt)).FpWriter)).Fdb)
|
|
return libc.Int32FromInt32(SQLITE_LOCKED) | libc.Int32FromInt32(1)<<libc.Int32FromInt32(8)
|
|
}
|
|
pIter = (*TBtShared)(unsafe.Pointer(pBt)).FpLock
|
|
for {
|
|
if !(pIter != 0) {
|
|
break
|
|
}
|
|
/* The condition (pIter->eLock!=eLock) in the following if(...)
|
|
** statement is a simplification of:
|
|
**
|
|
** (eLock==WRITE_LOCK || pIter->eLock==WRITE_LOCK)
|
|
**
|
|
** since we know that if eLock==WRITE_LOCK, then no other connection
|
|
** may hold a WRITE_LOCK on any table in this file (since there can
|
|
** only be a single writer).
|
|
*/
|
|
if (*TBtLock)(unsafe.Pointer(pIter)).FpBtree != p && (*TBtLock)(unsafe.Pointer(pIter)).FiTable == iTab && libc.Int32FromUint8((*TBtLock)(unsafe.Pointer(pIter)).FeLock) != libc.Int32FromUint8(eLock) {
|
|
_sqlite3ConnectionBlocked(tls, (*TBtree)(unsafe.Pointer(p)).Fdb, (*TBtree)(unsafe.Pointer((*TBtLock)(unsafe.Pointer(pIter)).FpBtree)).Fdb)
|
|
if libc.Int32FromUint8(eLock) == int32(WRITE_LOCK) {
|
|
v2 = pBt + 40
|
|
*(*Tu16)(unsafe.Pointer(v2)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v2))) | libc.Int32FromInt32(BTS_PENDING))
|
|
}
|
|
return libc.Int32FromInt32(SQLITE_LOCKED) | libc.Int32FromInt32(1)<<libc.Int32FromInt32(8)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
pIter = (*TBtLock)(unsafe.Pointer(pIter)).FpNext
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Implementation of the QUOTE() function.
|
|
// **
|
|
// ** The quote(X) function returns the text of an SQL literal which is the
|
|
// ** value of its argument suitable for inclusion into an SQL statement.
|
|
// ** Strings are surrounded by single-quotes with escapes on interior quotes
|
|
// ** as needed. BLOBs are encoded as hexadecimal literals. Strings with
|
|
// ** embedded NUL characters cannot be represented as string literals in SQL
|
|
// ** and hence the returned string literal is truncated prior to the first NUL.
|
|
// **
|
|
// ** If sqlite3_user_data() is non-zero, then the UNISTR_QUOTE() function is
|
|
// ** implemented instead. The difference is that UNISTR_QUOTE() uses the
|
|
// ** UNISTR() function to escape control characters.
|
|
// */
|
|
func _quoteFunc(tls *libc.TLS, context uintptr, argc int32, argv uintptr) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var db uintptr
|
|
var _ /* str at bp+0 */ Tsqlite3_str
|
|
_ = db
|
|
db = Xsqlite3_context_db_handle(tls, context)
|
|
_ = argc
|
|
_sqlite3StrAccumInit(tls, bp, db, uintptr(0), 0, **(**int32)(__ccgo_up(db + 136)))
|
|
_sqlite3QuoteValue(tls, bp, **(**uintptr)(__ccgo_up(argv)), int32(int64(Xsqlite3_user_data(tls, context))))
|
|
Xsqlite3_result_text(tls, context, _sqlite3StrAccumFinish(tls, bp), libc.Int32FromUint32((**(**Tsqlite3_str)(__ccgo_up(bp))).FnChar), __ccgo_fp(_sqlite3RowSetClear))
|
|
if libc.Int32FromUint8((**(**Tsqlite3_str)(__ccgo_up(bp))).FaccError) != SQLITE_OK {
|
|
Xsqlite3_result_null(tls, context)
|
|
Xsqlite3_result_error_code(tls, context, libc.Int32FromUint8((**(**Tsqlite3_str)(__ccgo_up(bp))).FaccError))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate and zero the pIter->azTblCol[] and abTblPk[] arrays so that
|
|
// ** there is room for at least nCol elements. If an OOM occurs, store an
|
|
// ** error code in the RBU handle passed as the first argument.
|
|
// */
|
|
func _rbuAllocateIterArrays(tls *libc.TLS, p uintptr, pIter uintptr, nCol int32) {
|
|
var azNew uintptr
|
|
var nByte Tsqlite3_int64
|
|
_, _ = azNew, nByte
|
|
nByte = libc.Int64FromUint64((libc.Uint64FromInt32(2)*libc.Uint64FromInt64(8) + libc.Uint64FromInt64(4) + libc.Uint64FromInt32(3)*libc.Uint64FromInt64(1)) * libc.Uint64FromInt32(nCol))
|
|
azNew = _rbuMalloc(tls, p, nByte)
|
|
if azNew != 0 {
|
|
(*TRbuObjIter)(unsafe.Pointer(pIter)).FazTblCol = azNew
|
|
(*TRbuObjIter)(unsafe.Pointer(pIter)).FazTblType = azNew + uintptr(nCol)*8
|
|
(*TRbuObjIter)(unsafe.Pointer(pIter)).FaiSrcOrder = (*TRbuObjIter)(unsafe.Pointer(pIter)).FazTblType + uintptr(nCol)*8
|
|
(*TRbuObjIter)(unsafe.Pointer(pIter)).FabTblPk = (*TRbuObjIter)(unsafe.Pointer(pIter)).FaiSrcOrder + uintptr(nCol)*4
|
|
(*TRbuObjIter)(unsafe.Pointer(pIter)).FabNotNull = (*TRbuObjIter)(unsafe.Pointer(pIter)).FabTblPk + uintptr(nCol)
|
|
(*TRbuObjIter)(unsafe.Pointer(pIter)).FabIndexed = (*TRbuObjIter)(unsafe.Pointer(pIter)).FabNotNull + uintptr(nCol)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Called when iAmt bytes are read from offset iOff of the wal file while
|
|
// ** the rbu object is in capture mode. Record the frame number of the frame
|
|
// ** being read in the aFrame[] array.
|
|
// */
|
|
func _rbuCaptureWalRead(tls *libc.TLS, pRbu uintptr, iOff Ti64, iAmt int32) (r int32) {
|
|
var aNew uintptr
|
|
var iFrame, mReq Tu32
|
|
var nNew, v1 int32
|
|
_, _, _, _, _ = aNew, iFrame, mReq, nNew, v1
|
|
mReq = libc.Uint32FromInt32(libc.Int32FromInt32(1)<<libc.Int32FromInt32(WAL_LOCK_WRITE) | libc.Int32FromInt32(1)<<libc.Int32FromInt32(WAL_LOCK_CKPT) | libc.Int32FromInt32(1)<<libc.Int32FromInt32(WAL_LOCK_READ0))
|
|
if (*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FmLock != mReq {
|
|
(*Tsqlite3rbu)(unsafe.Pointer(pRbu)).Frc = int32(SQLITE_BUSY)
|
|
return libc.Int32FromInt32(SQLITE_NOTICE) | libc.Int32FromInt32(3)<<libc.Int32FromInt32(8)
|
|
}
|
|
(*Tsqlite3rbu)(unsafe.Pointer(pRbu)).Fpgsz = iAmt
|
|
if (*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FnFrame == (*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FnFrameAlloc {
|
|
if (*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FnFrameAlloc != 0 {
|
|
v1 = (*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FnFrameAlloc
|
|
} else {
|
|
v1 = int32(64)
|
|
}
|
|
nNew = v1 * int32(2)
|
|
aNew = Xsqlite3_realloc64(tls, (*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FaFrame, uint64(libc.Uint64FromInt32(nNew)*uint64(8)))
|
|
if aNew == uintptr(0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
(*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FaFrame = aNew
|
|
(*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FnFrameAlloc = nNew
|
|
}
|
|
iFrame = libc.Uint32FromInt64((iOff-libc.Int64FromInt32(32))/int64(iAmt+libc.Int32FromInt32(24))) + uint32(1)
|
|
if (*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FiMaxFrame < iFrame {
|
|
(*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FiMaxFrame = iFrame
|
|
}
|
|
(**(**TRbuFrame)(__ccgo_up((*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FaFrame + uintptr((*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FnFrame)*8))).FiWalFrame = iFrame
|
|
(**(**TRbuFrame)(__ccgo_up((*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FaFrame + uintptr((*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FnFrame)*8))).FiDbPage = uint32(0)
|
|
(*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FnFrame = (*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FnFrame + 1
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Read bytes from *pz and convert them into a positive integer. When
|
|
// ** finished, leave *pz pointing to the first character past the end of
|
|
// ** the integer. The *pLen parameter holds the length of the string
|
|
// ** in *pz and is decremented once for each character in the integer.
|
|
// */
|
|
func _rbuDeltaGetInt(tls *libc.TLS, pz uintptr, pLen uintptr) (r uint32) {
|
|
var c, v1 int32
|
|
var v uint32
|
|
var z, zEnd uintptr
|
|
var v2 bool
|
|
_, _, _, _, _, _ = c, v, z, zEnd, v1, v2
|
|
v = uint32(0)
|
|
z = **(**uintptr)(__ccgo_up(pz))
|
|
zEnd = z + uintptr(**(**int32)(__ccgo_up(pLen)))
|
|
for {
|
|
if v2 = z < zEnd; v2 {
|
|
v1 = int32(_zValue[**(**uint8)(__ccgo_up(z))])
|
|
c = v1
|
|
}
|
|
if !(v2 && v1 >= 0) {
|
|
break
|
|
}
|
|
v = v<<int32(6) + libc.Uint32FromInt32(c)
|
|
z = z + 1
|
|
}
|
|
**(**int32)(__ccgo_up(pLen)) -= int32(int64(z) - int64(**(**uintptr)(__ccgo_up(pz))))
|
|
**(**uintptr)(__ccgo_up(pz)) = z
|
|
return v
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Take or release a shared-memory lock.
|
|
// */
|
|
func _rbuVfsShmLock(tls *libc.TLS, pFile uintptr, ofst int32, n int32, flags int32) (r int32) {
|
|
var bCapture, rc int32
|
|
var p, pRbu uintptr
|
|
_, _, _, _ = bCapture, p, pRbu, rc
|
|
p = pFile
|
|
pRbu = (*Trbu_file)(unsafe.Pointer(p)).FpRbu
|
|
rc = SQLITE_OK
|
|
if pRbu != 0 && ((*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FeStage == int32(RBU_STAGE_OAL) || (*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FeStage == int32(RBU_STAGE_MOVE) || (*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FeStage == int32(RBU_STAGE_DONE)) {
|
|
/* Prevent SQLite from taking a shm-lock on the target file when it
|
|
** is supplying heap memory to the upper layer in place of *-shm
|
|
** segments. */
|
|
if ofst == int32(WAL_LOCK_CKPT) && n == int32(1) {
|
|
rc = int32(SQLITE_BUSY)
|
|
}
|
|
} else {
|
|
bCapture = 0
|
|
if pRbu != 0 && (*Tsqlite3rbu)(unsafe.Pointer(pRbu)).FeStage == int32(RBU_STAGE_CAPTURE) {
|
|
bCapture = int32(1)
|
|
}
|
|
if bCapture == 0 || 0 == flags&int32(SQLITE_SHM_UNLOCK) {
|
|
rc = (*(*func(*libc.TLS, uintptr, int32, int32, int32) int32)(unsafe.Pointer(&struct{ uintptr }{(*Tsqlite3_io_methods)(unsafe.Pointer((*Tsqlite3_file)(unsafe.Pointer((*Trbu_file)(unsafe.Pointer(p)).FpReal)).FpMethods)).FxShmLock})))(tls, (*Trbu_file)(unsafe.Pointer(p)).FpReal, ofst, n, flags)
|
|
if bCapture != 0 && rc == SQLITE_OK {
|
|
**(**Tu32)(__ccgo_up(pRbu + 340)) |= libc.Uint32FromInt32((int32(1)<<n - int32(1)) << ofst)
|
|
}
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The journal file must be open when this is called. A journal header file
|
|
// ** (JOURNAL_HDR_SZ bytes) is read from the current location in the journal
|
|
// ** file. The current location in the journal file is given by
|
|
// ** pPager->journalOff. See comments above function writeJournalHdr() for
|
|
// ** a description of the journal header format.
|
|
// **
|
|
// ** If the header is read successfully, *pNRec is set to the number of
|
|
// ** page records following this header and *pDbSize is set to the size of the
|
|
// ** database before the transaction began, in pages. Also, pPager->cksumInit
|
|
// ** is set to the value read from the journal header. SQLITE_OK is returned
|
|
// ** in this case.
|
|
// **
|
|
// ** If the journal header file appears to be corrupted, SQLITE_DONE is
|
|
// ** returned and *pNRec and *PDbSize are undefined. If JOURNAL_HDR_SZ bytes
|
|
// ** cannot be read from the journal file an error code is returned.
|
|
// */
|
|
func _readJournalHdr(tls *libc.TLS, pPager uintptr, isHot int32, journalSize Ti64, pNRec uintptr, pDbSize uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iHdrOff Ti64
|
|
var rc, v1, v2, v4 int32
|
|
var v3, v5 bool
|
|
var _ /* aMagic at bp+0 */ [8]uint8
|
|
var _ /* iPageSize at bp+8 */ Tu32
|
|
var _ /* iSectorSize at bp+12 */ Tu32
|
|
_, _, _, _, _, _, _ = iHdrOff, rc, v1, v2, v3, v4, v5 /* Offset of journal header being read */
|
|
/* Journal file must be open. */
|
|
/* Advance Pager.journalOff to the start of the next sector. If the
|
|
** journal file is too small for there to be a header stored at this
|
|
** point, return SQLITE_DONE.
|
|
*/
|
|
(*TPager)(unsafe.Pointer(pPager)).FjournalOff = _journalHdrOffset(tls, pPager)
|
|
if (*TPager)(unsafe.Pointer(pPager)).FjournalOff+libc.Int64FromUint32((*TPager)(unsafe.Pointer(pPager)).FsectorSize) > journalSize {
|
|
return int32(SQLITE_DONE)
|
|
}
|
|
iHdrOff = (*TPager)(unsafe.Pointer(pPager)).FjournalOff
|
|
/* Read in the first 8 bytes of the journal header. If they do not match
|
|
** the magic string found at the start of each journal header, return
|
|
** SQLITE_DONE. If an IO error occurs, return an error code. Otherwise,
|
|
** proceed.
|
|
*/
|
|
if isHot != 0 || iHdrOff != (*TPager)(unsafe.Pointer(pPager)).FjournalHdr {
|
|
rc = _sqlite3OsRead(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, bp, int32(8), iHdrOff)
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
if libc.Xmemcmp(tls, bp, uintptr(unsafe.Pointer(&_aJournalMagic)), uint64(8)) != 0 {
|
|
return int32(SQLITE_DONE)
|
|
}
|
|
}
|
|
/* Read the first three 32-bit fields of the journal header: The nRec
|
|
** field, the checksum-initializer and the database size at the start
|
|
** of the transaction. Return an error code if anything goes wrong.
|
|
*/
|
|
v1 = _read32bits(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, iHdrOff+int64(8), pNRec)
|
|
rc = v1
|
|
if v3 = SQLITE_OK != v1; !v3 {
|
|
v2 = _read32bits(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, iHdrOff+int64(12), pPager+56)
|
|
rc = v2
|
|
}
|
|
if v5 = v3 || SQLITE_OK != v2; !v5 {
|
|
v4 = _read32bits(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, iHdrOff+int64(16), pDbSize)
|
|
rc = v4
|
|
}
|
|
if v5 || SQLITE_OK != v4 {
|
|
return rc
|
|
}
|
|
if (*TPager)(unsafe.Pointer(pPager)).FjournalOff == 0 { /* Sector-size field of journal header */
|
|
/* Read the page-size and sector-size journal header fields. */
|
|
v1 = _read32bits(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, iHdrOff+int64(20), bp+12)
|
|
rc = v1
|
|
if v3 = SQLITE_OK != v1; !v3 {
|
|
v2 = _read32bits(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd, iHdrOff+int64(24), bp+8)
|
|
rc = v2
|
|
}
|
|
if v3 || SQLITE_OK != v2 {
|
|
return rc
|
|
}
|
|
/* Versions of SQLite prior to 3.5.8 set the page-size field of the
|
|
** journal header to zero. In this case, assume that the Pager.pageSize
|
|
** variable is already set to the correct page size.
|
|
*/
|
|
if **(**Tu32)(__ccgo_up(bp + 8)) == uint32(0) {
|
|
**(**Tu32)(__ccgo_up(bp + 8)) = libc.Uint32FromInt64((*TPager)(unsafe.Pointer(pPager)).FpageSize)
|
|
}
|
|
/* Check that the values read from the page-size and sector-size fields
|
|
** are within range. To be 'in range', both values need to be a power
|
|
** of two greater than or equal to 512 or 32, and not greater than their
|
|
** respective compile time maximum limits.
|
|
*/
|
|
if **(**Tu32)(__ccgo_up(bp + 8)) < uint32(512) || **(**Tu32)(__ccgo_up(bp + 12)) < uint32(32) || **(**Tu32)(__ccgo_up(bp + 8)) > uint32(SQLITE_MAX_PAGE_SIZE) || **(**Tu32)(__ccgo_up(bp + 12)) > uint32(MAX_SECTOR_SIZE) || (**(**Tu32)(__ccgo_up(bp + 8))-uint32(1))&**(**Tu32)(__ccgo_up(bp + 8)) != uint32(0) || (**(**Tu32)(__ccgo_up(bp + 12))-uint32(1))&**(**Tu32)(__ccgo_up(bp + 12)) != uint32(0) {
|
|
/* If the either the page-size or sector-size in the journal-header is
|
|
** invalid, then the process that wrote the journal-header must have
|
|
** crashed before the header was synced. In this case stop reading
|
|
** the journal file here.
|
|
*/
|
|
return int32(SQLITE_DONE)
|
|
}
|
|
/* Update the page-size to match the value read from the journal.
|
|
** Use a testcase() macro to make sure that malloc failure within
|
|
** PagerSetPagesize() is tested.
|
|
*/
|
|
rc = _sqlite3PagerSetPagesize(tls, pPager, bp+8, -int32(1))
|
|
/* Update the assumed sector-size to match the value used by
|
|
** the process that created this journal. If this journal was
|
|
** created by a process other than this one, then this routine
|
|
** is being called from within pager_playback(). The local value
|
|
** of Pager.sectorSize is restored at the end of that routine.
|
|
*/
|
|
(*TPager)(unsafe.Pointer(pPager)).FsectorSize = **(**Tu32)(__ccgo_up(bp + 12))
|
|
}
|
|
**(**Ti64)(__ccgo_up(pPager + 96)) += libc.Int64FromUint32((*TPager)(unsafe.Pointer(pPager)).FsectorSize)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Recompute the colNotIdxed field of the Index.
|
|
// **
|
|
// ** colNotIdxed is a bitmask that has a 0 bit representing each indexed
|
|
// ** columns that are within the first 63 columns of the table and a 1 for
|
|
// ** all other bits (all columns that are not in the index). The
|
|
// ** high-order bit of colNotIdxed is always 1. All unindexed columns
|
|
// ** of the table have a 1.
|
|
// **
|
|
// ** 2019-10-24: For the purpose of this computation, virtual columns are
|
|
// ** not considered to be covered by the index, even if they are in the
|
|
// ** index, because we do not trust the logic in whereIndexExprTrans() to be
|
|
// ** able to find all instances of a reference to the indexed table column
|
|
// ** and convert them into references to the index. Hence we always want
|
|
// ** the actual table at hand in order to recompute the virtual column, if
|
|
// ** necessary.
|
|
// **
|
|
// ** The colNotIdxed mask is AND-ed with the SrcList.a[].colUsed mask
|
|
// ** to determine if the index is covering index.
|
|
// */
|
|
func _recomputeColumnsNotIndexed(tls *libc.TLS, pIdx uintptr) {
|
|
var j, x int32
|
|
var m TBitmask
|
|
var pTab uintptr
|
|
_, _, _, _ = j, m, pTab, x
|
|
m = uint64(0)
|
|
pTab = (*TIndex)(unsafe.Pointer(pIdx)).FpTable
|
|
j = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn) - int32(1)
|
|
for {
|
|
if !(j >= 0) {
|
|
break
|
|
}
|
|
x = int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(j)*2)))
|
|
if x >= 0 && libc.Int32FromUint16((**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(x)*16))).FcolFlags)&int32(COLFLAG_VIRTUAL) == 0 {
|
|
if x < libc.Int32FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(8))-libc.Int32FromInt32(1) {
|
|
m = m | libc.Uint64FromInt32(1)<<x
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
j = j - 1
|
|
}
|
|
(*TIndex)(unsafe.Pointer(pIdx)).FcolNotIdxed = ^m
|
|
/* See note-20221022-a */
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** pSelect is a SELECT statement and pSrcItem is one item in the FROM
|
|
// ** clause of that SELECT.
|
|
// **
|
|
// ** This routine scans the entire SELECT statement and recomputes the
|
|
// ** pSrcItem->colUsed mask.
|
|
// */
|
|
func _recomputeColumnsUsedExpr(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var pItem uintptr
|
|
_ = pItem
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) != int32(TK_COLUMN) {
|
|
return WRC_Continue
|
|
}
|
|
pItem = *(*uintptr)(unsafe.Pointer(pWalker + 40))
|
|
if (*TSrcItem)(unsafe.Pointer(pItem)).FiCursor != (*TExpr)(unsafe.Pointer(pExpr)).FiTable {
|
|
return WRC_Continue
|
|
}
|
|
if int32((*TExpr)(unsafe.Pointer(pExpr)).FiColumn) < 0 {
|
|
return WRC_Continue
|
|
}
|
|
**(**TBitmask)(__ccgo_up(pItem + 40)) |= _sqlite3ExprColUsed(tls, pExpr)
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Release auxiliary memory held in an array of N Mem elements.
|
|
// **
|
|
// ** After this routine returns, all Mem elements in the array will still
|
|
// ** be valid. Those Mem elements that were not holding auxiliary resources
|
|
// ** will be unchanged. Mem elements which had something freed will be
|
|
// ** set to MEM_Undefined.
|
|
// */
|
|
func _releaseMemArray(tls *libc.TLS, p uintptr, N int32) {
|
|
var db, pEnd, v1 uintptr
|
|
_, _, _ = db, pEnd, v1
|
|
if p != 0 && N != 0 {
|
|
pEnd = p + uintptr(N)*56
|
|
db = (*TMem)(unsafe.Pointer(p)).Fdb
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FpnBytesFreed != 0 {
|
|
for {
|
|
if (*TMem)(unsafe.Pointer(p)).FszMalloc != 0 {
|
|
_sqlite3DbFree(tls, db, (*TMem)(unsafe.Pointer(p)).FzMalloc)
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
p += 56
|
|
v1 = p
|
|
if !(v1 < pEnd) {
|
|
break
|
|
}
|
|
}
|
|
return
|
|
}
|
|
for {
|
|
/* This block is really an inlined version of sqlite3VdbeMemRelease()
|
|
** that takes advantage of the fact that the memory cell value is
|
|
** being set to NULL after releasing any dynamic resources.
|
|
**
|
|
** The justification for duplicating code is that according to
|
|
** callgrind, this causes a certain test case to hit the CPU 4.7
|
|
** percent less (x86 linux, gcc version 4.1.2, -O6) than if
|
|
** sqlite3MemRelease() were called from here. With -O2, this jumps
|
|
** to 6.6 percent. The test case is inserting 1000 rows into a table
|
|
** with no indexes using a single prepared INSERT statement, bind()
|
|
** and reset(). Inserts are grouped into a transaction.
|
|
*/
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&(libc.Int32FromInt32(MEM_Agg)|libc.Int32FromInt32(MEM_Dyn)) != 0 {
|
|
_sqlite3VdbeMemRelease(tls, p)
|
|
(*TMem)(unsafe.Pointer(p)).Fflags = uint16(MEM_Undefined)
|
|
} else {
|
|
if (*TMem)(unsafe.Pointer(p)).FszMalloc != 0 {
|
|
_sqlite3DbNNFreeNN(tls, db, (*TMem)(unsafe.Pointer(p)).FzMalloc)
|
|
(*TMem)(unsafe.Pointer(p)).FszMalloc = 0
|
|
(*TMem)(unsafe.Pointer(p)).Fflags = uint16(MEM_Undefined)
|
|
}
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
p += 56
|
|
v1 = p
|
|
if !(v1 < pEnd) {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Move the open database page pDbPage to location iFreePage in the
|
|
// ** database. The pDbPage reference remains valid.
|
|
// **
|
|
// ** The isCommit flag indicates that there is no need to remember that
|
|
// ** the journal needs to be sync()ed before database page pDbPage->pgno
|
|
// ** can be written to. The caller has already promised not to write to that
|
|
// ** page.
|
|
// */
|
|
func _relocatePage(tls *libc.TLS, pBt uintptr, pDbPage uintptr, eType Tu8, iPtrPage TPgno, iFreePage TPgno, isCommit int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iDbPage, nextOvfl TPgno
|
|
var pPager uintptr
|
|
var _ /* pPtrPage at bp+0 */ uintptr
|
|
var _ /* rc at bp+8 */ int32
|
|
_, _, _ = iDbPage, nextOvfl, pPager /* The page that contains a pointer to pDbPage */
|
|
iDbPage = (*TMemPage)(unsafe.Pointer(pDbPage)).Fpgno
|
|
pPager = (*TBtShared)(unsafe.Pointer(pBt)).FpPager
|
|
if iDbPage < uint32(3) {
|
|
return _sqlite3CorruptError(tls, int32(77187))
|
|
}
|
|
/* Move page iDbPage from its current location to page number iFreePage */
|
|
**(**int32)(__ccgo_up(bp + 8)) = _sqlite3PagerMovepage(tls, pPager, (*TMemPage)(unsafe.Pointer(pDbPage)).FpDbPage, iFreePage, isCommit)
|
|
if **(**int32)(__ccgo_up(bp + 8)) != SQLITE_OK {
|
|
return **(**int32)(__ccgo_up(bp + 8))
|
|
}
|
|
(*TMemPage)(unsafe.Pointer(pDbPage)).Fpgno = iFreePage
|
|
/* If pDbPage was a btree-page, then it may have child pages and/or cells
|
|
** that point to overflow pages. The pointer map entries for all these
|
|
** pages need to be changed.
|
|
**
|
|
** If pDbPage is an overflow page, then the first 4 bytes may store a
|
|
** pointer to a subsequent overflow page. If this is the case, then
|
|
** the pointer map needs to be updated for the subsequent overflow page.
|
|
*/
|
|
if libc.Int32FromUint8(eType) == int32(PTRMAP_BTREE) || libc.Int32FromUint8(eType) == int32(PTRMAP_ROOTPAGE) {
|
|
**(**int32)(__ccgo_up(bp + 8)) = _setChildPtrmaps(tls, pDbPage)
|
|
if **(**int32)(__ccgo_up(bp + 8)) != SQLITE_OK {
|
|
return **(**int32)(__ccgo_up(bp + 8))
|
|
}
|
|
} else {
|
|
nextOvfl = _sqlite3Get4byte(tls, (*TMemPage)(unsafe.Pointer(pDbPage)).FaData)
|
|
if nextOvfl != uint32(0) {
|
|
_ptrmapPut(tls, pBt, nextOvfl, uint8(PTRMAP_OVERFLOW2), iFreePage, bp+8)
|
|
if **(**int32)(__ccgo_up(bp + 8)) != SQLITE_OK {
|
|
return **(**int32)(__ccgo_up(bp + 8))
|
|
}
|
|
}
|
|
}
|
|
/* Fix the database pointer on page iPtrPage that pointed at iDbPage so
|
|
** that it points at iFreePage. Also fix the pointer map entry for
|
|
** iPtrPage.
|
|
*/
|
|
if libc.Int32FromUint8(eType) != int32(PTRMAP_ROOTPAGE) {
|
|
**(**int32)(__ccgo_up(bp + 8)) = _btreeGetPage(tls, pBt, iPtrPage, bp, 0)
|
|
if **(**int32)(__ccgo_up(bp + 8)) != SQLITE_OK {
|
|
return **(**int32)(__ccgo_up(bp + 8))
|
|
}
|
|
**(**int32)(__ccgo_up(bp + 8)) = _sqlite3PagerWrite(tls, (*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FpDbPage)
|
|
if **(**int32)(__ccgo_up(bp + 8)) != SQLITE_OK {
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
return **(**int32)(__ccgo_up(bp + 8))
|
|
}
|
|
**(**int32)(__ccgo_up(bp + 8)) = _modifyPagePointer(tls, **(**uintptr)(__ccgo_up(bp)), iDbPage, iFreePage, eType)
|
|
_releasePage(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
if **(**int32)(__ccgo_up(bp + 8)) == SQLITE_OK {
|
|
_ptrmapPut(tls, pBt, iFreePage, eType, iPtrPage, bp+8)
|
|
}
|
|
}
|
|
return **(**int32)(__ccgo_up(bp + 8))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** pX is an expression of the form: (vector) IN (SELECT ...)
|
|
// ** In other words, it is a vector IN operator with a SELECT clause on the
|
|
// ** RHS. But not all terms in the vector are indexable and the terms might
|
|
// ** not be in the correct order for indexing.
|
|
// **
|
|
// ** This routine makes a copy of the input pX expression and then adjusts
|
|
// ** the vector on the LHS with corresponding changes to the SELECT so that
|
|
// ** the vector contains only index terms and those terms are in the correct
|
|
// ** order. The modified IN expression is returned. The caller is responsible
|
|
// ** for deleting the returned expression.
|
|
// **
|
|
// ** Example:
|
|
// **
|
|
// ** CREATE TABLE t1(a,b,c,d,e,f);
|
|
// ** CREATE INDEX t1x1 ON t1(e,c);
|
|
// ** SELECT * FROM t1 WHERE (a,b,c,d,e) IN (SELECT v,w,x,y,z FROM t2)
|
|
// ** \_______________________________________/
|
|
// ** The pX expression
|
|
// **
|
|
// ** Since only columns e and c can be used with the index, in that order,
|
|
// ** the modified IN expression that is returned will be:
|
|
// **
|
|
// ** (e,c) IN (SELECT z,x FROM t2)
|
|
// **
|
|
// ** The reduced pX is different from the original (obviously) and thus is
|
|
// ** only used for indexing, to improve performance. The original unaltered
|
|
// ** IN expression must also be run on each output row for correctness.
|
|
// */
|
|
func _removeUnindexableInClauseTerms(tls *libc.TLS, pParse uintptr, iEq int32, pLoop uintptr, pX uintptr) (r uintptr) {
|
|
var db, p, pLhs, pNew, pOrigLhs, pOrigRhs, pRhs, pSelect, v4 uintptr
|
|
var i, iField, v3 int32
|
|
_, _, _, _, _, _, _, _, _, _, _, _ = db, i, iField, p, pLhs, pNew, pOrigLhs, pOrigRhs, pRhs, pSelect, v3, v4
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
pNew = _sqlite3ExprDup(tls, db, pX, 0)
|
|
if libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed) == 0 {
|
|
pSelect = *(*uintptr)(unsafe.Pointer(pNew + 32))
|
|
for {
|
|
if !(pSelect != 0) {
|
|
break
|
|
} /* Original unmodified RHS */
|
|
pOrigLhs = uintptr(0) /* Original unmodified LHS */
|
|
pRhs = uintptr(0) /* New RHS after modifications */
|
|
pLhs = uintptr(0) /* Loop counter */
|
|
pOrigRhs = (*TSelect)(unsafe.Pointer(pSelect)).FpEList
|
|
if pSelect == *(*uintptr)(unsafe.Pointer(pNew + 32)) {
|
|
pOrigLhs = *(*uintptr)(unsafe.Pointer((*TExpr)(unsafe.Pointer(pNew)).FpLeft + 32))
|
|
}
|
|
i = iEq
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pLoop)).FnLTerm)) {
|
|
break
|
|
}
|
|
if (*TWhereTerm)(unsafe.Pointer(**(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pLoop)).FaLTerm + uintptr(i)*8)))).FpExpr == pX {
|
|
iField = (*(*struct {
|
|
FleftColumn int32
|
|
FiField int32
|
|
})(unsafe.Pointer(**(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pLoop)).FaLTerm + uintptr(i)*8)) + 32))).FiField - int32(1)
|
|
if (*(*TExprList_item)(unsafe.Pointer(pOrigRhs + 8 + uintptr(iField)*32))).FpExpr == uintptr(0) {
|
|
goto _2 /* Duplicate PK column */
|
|
}
|
|
pRhs = _sqlite3ExprListAppend(tls, pParse, pRhs, (*(*TExprList_item)(unsafe.Pointer(pOrigRhs + 8 + uintptr(iField)*32))).FpExpr)
|
|
(*(*TExprList_item)(unsafe.Pointer(pOrigRhs + 8 + uintptr(iField)*32))).FpExpr = uintptr(0)
|
|
if pRhs != 0 {
|
|
*(*Tu16)(unsafe.Pointer(pRhs + 8 + uintptr((*TExprList)(unsafe.Pointer(pRhs)).FnExpr-int32(1))*32 + 24)) = libc.Uint16FromInt32(iField + int32(1))
|
|
}
|
|
if pOrigLhs != 0 {
|
|
pLhs = _sqlite3ExprListAppend(tls, pParse, pLhs, (*(*TExprList_item)(unsafe.Pointer(pOrigLhs + 8 + uintptr(iField)*32))).FpExpr)
|
|
(*(*TExprList_item)(unsafe.Pointer(pOrigLhs + 8 + uintptr(iField)*32))).FpExpr = uintptr(0)
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_sqlite3ExprListDelete(tls, db, pOrigRhs)
|
|
if pOrigLhs != 0 {
|
|
_sqlite3ExprListDelete(tls, db, pOrigLhs)
|
|
*(*uintptr)(unsafe.Pointer((*TExpr)(unsafe.Pointer(pNew)).FpLeft + 32)) = pLhs
|
|
}
|
|
(*TSelect)(unsafe.Pointer(pSelect)).FpEList = pRhs
|
|
v4 = pParse + 132
|
|
*(*int32)(unsafe.Pointer(v4)) = *(*int32)(unsafe.Pointer(v4)) + 1
|
|
v3 = *(*int32)(unsafe.Pointer(v4))
|
|
(*TSelect)(unsafe.Pointer(pSelect)).FselId = libc.Uint32FromInt32(v3) /* Req'd for SubrtnSig validity */
|
|
if pLhs != 0 && (*TExprList)(unsafe.Pointer(pLhs)).FnExpr == int32(1) {
|
|
/* Take care here not to generate a TK_VECTOR containing only a
|
|
** single value. Since the parser never creates such a vector, some
|
|
** of the subroutines do not handle this case. */
|
|
p = (*(*TExprList_item)(unsafe.Pointer(pLhs + 8))).FpExpr
|
|
(*(*TExprList_item)(unsafe.Pointer(pLhs + 8))).FpExpr = uintptr(0)
|
|
_sqlite3ExprDelete(tls, db, (*TExpr)(unsafe.Pointer(pNew)).FpLeft)
|
|
(*TExpr)(unsafe.Pointer(pNew)).FpLeft = p
|
|
}
|
|
/* If either the ORDER BY clause or the GROUP BY clause contains
|
|
** references to result-set columns, those references might now be
|
|
** obsolete. So fix them up.
|
|
*/
|
|
if pRhs != 0 {
|
|
_adjustOrderByCol(tls, (*TSelect)(unsafe.Pointer(pSelect)).FpOrderBy, pRhs)
|
|
_adjustOrderByCol(tls, (*TSelect)(unsafe.Pointer(pSelect)).FpGroupBy, pRhs)
|
|
i = 0
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(pRhs)).FnExpr) {
|
|
break
|
|
}
|
|
*(*Tu16)(unsafe.Pointer(pRhs + 8 + uintptr(i)*32 + 24)) = uint16(0)
|
|
goto _5
|
|
_5:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
pSelect = (*TSelect)(unsafe.Pointer(pSelect)).FpPrior
|
|
}
|
|
}
|
|
return pNew
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is a Walker expression callback.
|
|
// **
|
|
// ** For every TK_COLUMN node in the expression tree, search to see
|
|
// ** if the column being references is the column being renamed by an
|
|
// ** ALTER TABLE statement. If it is, then attach its associated
|
|
// ** RenameToken object to the list of RenameToken objects being
|
|
// ** constructed in RenameCtx object at pWalker->u.pRename.
|
|
// */
|
|
func _renameColumnExprCb(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var p uintptr
|
|
_ = p
|
|
p = *(*uintptr)(unsafe.Pointer(pWalker + 40))
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_TRIGGER) && int32((*TExpr)(unsafe.Pointer(pExpr)).FiColumn) == (*TRenameCtx)(unsafe.Pointer(p)).FiCol && (*TParse)(unsafe.Pointer((*TWalker)(unsafe.Pointer(pWalker)).FpParse)).FpTriggerTab == (*TRenameCtx)(unsafe.Pointer(p)).FpTab {
|
|
_renameTokenFind(tls, (*TWalker)(unsafe.Pointer(pWalker)).FpParse, p, pExpr)
|
|
} else {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_COLUMN) && int32((*TExpr)(unsafe.Pointer(pExpr)).FiColumn) == (*TRenameCtx)(unsafe.Pointer(p)).FiCol && (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_WinFunc)|libc.Int32FromInt32(EP_Subrtn)) == uint32(0) && (*TRenameCtx)(unsafe.Pointer(p)).FpTab == *(*uintptr)(unsafe.Pointer(pExpr + 64)) {
|
|
_renameTokenFind(tls, (*TWalker)(unsafe.Pointer(pWalker)).FpParse, p, pExpr)
|
|
}
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
func _renameQuotefixExprCb(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_STRING) && (*TExpr)(unsafe.Pointer(pExpr)).Fflags&uint32(EP_DblQuoted) != 0 {
|
|
_renameTokenFind(tls, (*TWalker)(unsafe.Pointer(pWalker)).FpParse, *(*uintptr)(unsafe.Pointer(pWalker + 40)), pExpr)
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set all pEList->a[].fg.eEName fields in the expression-list to val.
|
|
// */
|
|
func _renameSetENames(tls *libc.TLS, pEList uintptr, val int32) {
|
|
var i int32
|
|
_ = i
|
|
if pEList != 0 {
|
|
i = 0
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(pEList)).FnExpr) {
|
|
break
|
|
}
|
|
libc.SetBitFieldPtr16Uint32(pEList+8+uintptr(i)*32+16+4, libc.Uint32FromInt32(val&libc.Int32FromInt32(0x3)), 0, 0x3)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Walker expression callback used by "RENAME TABLE".
|
|
// */
|
|
func _renameTableExprCb(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var p uintptr
|
|
_ = p
|
|
p = *(*uintptr)(unsafe.Pointer(pWalker + 40))
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_COLUMN) && (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_WinFunc)|libc.Int32FromInt32(EP_Subrtn)) == uint32(0) && (*TRenameCtx)(unsafe.Pointer(p)).FpTab == *(*uintptr)(unsafe.Pointer(pExpr + 64)) {
|
|
_renameTokenFind(tls, (*TWalker)(unsafe.Pointer(pWalker)).FpParse, p, pExpr+64)
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Walker select callback used by "RENAME TABLE".
|
|
// */
|
|
func _renameTableSelectCb(tls *libc.TLS, pWalker uintptr, pSelect uintptr) (r int32) {
|
|
var i int32
|
|
var p, pItem, pSrc uintptr
|
|
_, _, _, _ = i, p, pItem, pSrc
|
|
p = *(*uintptr)(unsafe.Pointer(pWalker + 40))
|
|
pSrc = (*TSelect)(unsafe.Pointer(pSelect)).FpSrc
|
|
if (*TSelect)(unsafe.Pointer(pSelect)).FselFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SF_View)|libc.Int32FromInt32(SF_CopyCte)) != 0 {
|
|
return int32(WRC_Prune)
|
|
}
|
|
if pSrc == uintptr(0) {
|
|
return int32(WRC_Abort)
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < (*TSrcList)(unsafe.Pointer(pSrc)).FnSrc) {
|
|
break
|
|
}
|
|
pItem = pSrc + 8 + uintptr(i)*80
|
|
if (*TSrcItem)(unsafe.Pointer(pItem)).FpSTab == (*TRenameCtx)(unsafe.Pointer(p)).FpTab {
|
|
_renameTokenFind(tls, (*TWalker)(unsafe.Pointer(pWalker)).FpParse, p, (*TSrcItem)(unsafe.Pointer(pItem)).FzName)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_renameWalkWith(tls, pWalker, pSelect)
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Walker callback used by sqlite3RenameExprUnmap().
|
|
// */
|
|
func _renameUnmapExprCb(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var pParse uintptr
|
|
_ = pParse
|
|
pParse = (*TWalker)(unsafe.Pointer(pWalker)).FpParse
|
|
_sqlite3RenameTokenRemap(tls, pParse, uintptr(0), pExpr)
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_WinFunc)|libc.Int32FromInt32(EP_Subrtn)) == uint32(0) {
|
|
_sqlite3RenameTokenRemap(tls, pParse, uintptr(0), pExpr+64)
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Walker callback used by sqlite3RenameExprUnmap().
|
|
// */
|
|
func _renameUnmapSelectCb(tls *libc.TLS, pWalker uintptr, p uintptr) (r int32) {
|
|
var i int32
|
|
var pList, pParse, pSrc uintptr
|
|
_, _, _, _ = i, pList, pParse, pSrc
|
|
pParse = (*TWalker)(unsafe.Pointer(pWalker)).FpParse
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr != 0 {
|
|
return int32(WRC_Abort)
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(p)).FselFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SF_View)|libc.Int32FromInt32(SF_CopyCte)) != 0 {
|
|
return int32(WRC_Prune)
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(p)).FpEList != 0 {
|
|
pList = (*TSelect)(unsafe.Pointer(p)).FpEList
|
|
i = 0
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(pList)).FnExpr) {
|
|
break
|
|
}
|
|
if (*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(i)*32))).FzEName != 0 && int32(uint32(*(*uint16)(unsafe.Pointer(pList + 8 + uintptr(i)*32 + 16 + 4))&0x3>>0)) == ENAME_NAME {
|
|
_sqlite3RenameTokenRemap(tls, pParse, uintptr(0), (*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(i)*32))).FzEName)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(p)).FpSrc != 0 { /* Every Select as a SrcList, even if it is empty */
|
|
pSrc = (*TSelect)(unsafe.Pointer(p)).FpSrc
|
|
i = 0
|
|
for {
|
|
if !(i < (*TSrcList)(unsafe.Pointer(pSrc)).FnSrc) {
|
|
break
|
|
}
|
|
_sqlite3RenameTokenRemap(tls, pParse, uintptr(0), (*(*TSrcItem)(unsafe.Pointer(pSrc + 8 + uintptr(i)*80))).FzName)
|
|
if int32(*(*uint32)(unsafe.Pointer(pSrc + 8 + uintptr(i)*80 + 24 + 4))&0x800>>11) == 0 {
|
|
_sqlite3WalkExpr(tls, pWalker, *(*uintptr)(unsafe.Pointer(pSrc + 8 + uintptr(i)*80 + 64)))
|
|
} else {
|
|
_unmapColumnIdlistNames(tls, pParse, *(*uintptr)(unsafe.Pointer(pSrc + 8 + uintptr(i)*80 + 64)))
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
_renameWalkWith(tls, pWalker, p)
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Expression walker callback used by renumberCursors() to update
|
|
// ** Expr objects to match newly assigned cursor numbers.
|
|
// */
|
|
func _renumberCursorsCb(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var op int32
|
|
_ = op
|
|
op = libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop)
|
|
if op == int32(TK_COLUMN) || op == int32(TK_IF_NULL_ROW) {
|
|
_renumberCursorDoMapping(tls, pWalker, pExpr+44)
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)) != uint32(0) {
|
|
_renumberCursorDoMapping(tls, pWalker, pExpr+52)
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Resolve label "x" to be the address of the next instruction to
|
|
// ** be inserted. The parameter "x" must have been obtained from
|
|
// ** a prior call to sqlite3VdbeMakeLabel().
|
|
// */
|
|
func _resizeResolveLabel(tls *libc.TLS, p uintptr, v uintptr, j int32) {
|
|
var nNewSize int32
|
|
_ = nNewSize
|
|
nNewSize = int32(10) - (*TParse)(unsafe.Pointer(p)).FnLabel
|
|
(*TParse)(unsafe.Pointer(p)).FaLabel = _sqlite3DbReallocOrFree(tls, (*TParse)(unsafe.Pointer(p)).Fdb, (*TParse)(unsafe.Pointer(p)).FaLabel, uint64(libc.Uint64FromInt32(nNewSize)*uint64(4)))
|
|
if (*TParse)(unsafe.Pointer(p)).FaLabel == uintptr(0) {
|
|
(*TParse)(unsafe.Pointer(p)).FnLabelAlloc = 0
|
|
} else {
|
|
if nNewSize >= int32(100) && nNewSize/int32(100) > (*TParse)(unsafe.Pointer(p)).FnLabelAlloc/int32(100) {
|
|
_sqlite3ProgressCheck(tls, p)
|
|
}
|
|
(*TParse)(unsafe.Pointer(p)).FnLabelAlloc = nNewSize
|
|
**(**int32)(__ccgo_up((*TParse)(unsafe.Pointer(p)).FaLabel + uintptr(j)*4)) = (*TVdbe)(unsafe.Pointer(v)).FnOp
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** pEList is a list of expressions which are really the result set of the
|
|
// ** a SELECT statement. pE is a term in an ORDER BY or GROUP BY clause.
|
|
// ** This routine checks to see if pE is a simple identifier which corresponds
|
|
// ** to the AS-name of one of the terms of the expression list. If it is,
|
|
// ** this routine return an integer between 1 and N where N is the number of
|
|
// ** elements in pEList, corresponding to the matching entry. If there is
|
|
// ** no match, or if pE is not a simple identifier, then this routine
|
|
// ** return 0.
|
|
// **
|
|
// ** pEList has been resolved. pE has not.
|
|
// */
|
|
func _resolveAsName(tls *libc.TLS, pParse uintptr, pEList uintptr, pE uintptr) (r int32) {
|
|
var i int32
|
|
var zCol uintptr
|
|
_, _ = i, zCol /* Loop counter */
|
|
_ = pParse
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pE)).Fop) == int32(TK_ID) {
|
|
zCol = *(*uintptr)(unsafe.Pointer(pE + 8))
|
|
i = 0
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(pEList)).FnExpr) {
|
|
break
|
|
}
|
|
if int32(uint32(*(*uint16)(unsafe.Pointer(pEList + 8 + uintptr(i)*32 + 16 + 4))&0x3>>0)) == ENAME_NAME && Xsqlite3_stricmp(tls, (*(*TExprList_item)(unsafe.Pointer(pEList + 8 + uintptr(i)*32))).FzEName, zCol) == 0 {
|
|
return i + int32(1)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine is called after all opcodes have been inserted. It loops
|
|
// ** through all the opcodes and fixes up some details.
|
|
// **
|
|
// ** (1) For each jump instruction with a negative P2 value (a label)
|
|
// ** resolve the P2 value to an actual address.
|
|
// **
|
|
// ** (2) Compute the maximum number of arguments used by the xUpdate/xFilter
|
|
// ** methods of any virtual table and store that value in *pMaxVtabArgs.
|
|
// **
|
|
// ** (3) Update the Vdbe.readOnly and Vdbe.bIsReader flags to accurately
|
|
// ** indicate what the prepared statement actually does.
|
|
// **
|
|
// ** (4) (discontinued)
|
|
// **
|
|
// ** (5) Reclaim the memory allocated for storing labels.
|
|
// **
|
|
// ** This routine will only function correctly if the mkopcodeh.tcl generator
|
|
// ** script numbers the opcodes correctly. Changes to this routine must be
|
|
// ** coordinated with changes to mkopcodeh.tcl.
|
|
// */
|
|
func _resolveP2Values(tls *libc.TLS, p uintptr, pMaxVtabArgs uintptr) {
|
|
var aLabel, pOp, pParse uintptr
|
|
var n, nMaxVtabArgs int32
|
|
_, _, _, _, _ = aLabel, n, nMaxVtabArgs, pOp, pParse
|
|
nMaxVtabArgs = **(**int32)(__ccgo_up(pMaxVtabArgs))
|
|
pParse = (*TVdbe)(unsafe.Pointer(p)).FpParse
|
|
aLabel = (*TParse)(unsafe.Pointer(pParse)).FaLabel
|
|
/* tag-20230419-1 */
|
|
libc.SetBitFieldPtr16Uint32(p+200, libc.Uint32FromInt32(1), 6, 0x40)
|
|
libc.SetBitFieldPtr16Uint32(p+200, libc.Uint32FromInt32(0), 7, 0x80)
|
|
pOp = (*TVdbe)(unsafe.Pointer(p)).FaOp + uintptr((*TVdbe)(unsafe.Pointer(p)).FnOp-int32(1))*24
|
|
for int32(1) != 0 {
|
|
/* Only JUMP opcodes and the short list of special opcodes in the switch
|
|
** below need to be considered. The mkopcodeh.tcl generator script groups
|
|
** all these opcodes together near the front of the opcode list. Skip
|
|
** any opcode that does not need processing by virtual of the fact that
|
|
** it is larger than SQLITE_MX_JUMP_OPCODE, as a performance optimization.
|
|
*/
|
|
if libc.Int32FromUint8((*TOp)(unsafe.Pointer(pOp)).Fopcode) <= int32(SQLITE_MX_JUMP_OPCODE) {
|
|
/* NOTE: Be sure to update mkopcodeh.tcl when adding or removing
|
|
** cases from this switch! */
|
|
switch libc.Int32FromUint8((*TOp)(unsafe.Pointer(pOp)).Fopcode) {
|
|
case int32(OP_Transaction):
|
|
if (*TOp)(unsafe.Pointer(pOp)).Fp2 != 0 {
|
|
libc.SetBitFieldPtr16Uint32(p+200, libc.Uint32FromInt32(0), 6, 0x40)
|
|
}
|
|
fallthrough
|
|
case int32(OP_AutoCommit):
|
|
fallthrough
|
|
case OP_Savepoint:
|
|
libc.SetBitFieldPtr16Uint32(p+200, libc.Uint32FromInt32(1), 7, 0x80)
|
|
case int32(OP_Checkpoint):
|
|
fallthrough
|
|
case int32(OP_Vacuum):
|
|
fallthrough
|
|
case int32(OP_JournalMode):
|
|
libc.SetBitFieldPtr16Uint32(p+200, libc.Uint32FromInt32(0), 6, 0x40)
|
|
libc.SetBitFieldPtr16Uint32(p+200, libc.Uint32FromInt32(1), 7, 0x80)
|
|
case int32(OP_Init):
|
|
goto resolve_p2_values_loop_exit
|
|
case int32(OP_VUpdate):
|
|
if (*TOp)(unsafe.Pointer(pOp)).Fp2 > nMaxVtabArgs {
|
|
nMaxVtabArgs = (*TOp)(unsafe.Pointer(pOp)).Fp2
|
|
}
|
|
case int32(OP_VFilter):
|
|
/* The instruction immediately prior to VFilter will be an
|
|
** OP_Integer that sets the "argc" value for the VFilter. See
|
|
** the code where OP_VFilter is generated at tag-20250207a. */
|
|
n = (**(**TOp)(__ccgo_up(pOp + uintptr(-libc.Int32FromInt32(1))*24))).Fp1
|
|
if n > nMaxVtabArgs {
|
|
nMaxVtabArgs = n
|
|
}
|
|
/* Fall through into the default case */
|
|
fallthrough
|
|
default:
|
|
if (*TOp)(unsafe.Pointer(pOp)).Fp2 < 0 {
|
|
/* The mkopcodeh.tcl script has so arranged things that the only
|
|
** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
|
|
** have non-negative values for P2. */
|
|
/* True because of tag-20230419-1 */
|
|
(*TOp)(unsafe.Pointer(pOp)).Fp2 = **(**int32)(__ccgo_up(aLabel + uintptr(^(*TOp)(unsafe.Pointer(pOp)).Fp2)*4))
|
|
}
|
|
/* OPFLG_JUMP opcodes never have P2==0, though OPFLG_JUMP0 opcodes
|
|
** might */
|
|
/* Jumps never go off the end of the bytecode array */
|
|
break
|
|
}
|
|
/* The mkopcodeh.tcl script has so arranged things that the only
|
|
** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
|
|
** have non-negative values for P2. */
|
|
}
|
|
pOp -= 24
|
|
}
|
|
goto resolve_p2_values_loop_exit
|
|
resolve_p2_values_loop_exit:
|
|
;
|
|
if aLabel != 0 {
|
|
_sqlite3DbNNFreeNN(tls, (*TVdbe)(unsafe.Pointer(p)).Fdb, (*TParse)(unsafe.Pointer(pParse)).FaLabel)
|
|
(*TParse)(unsafe.Pointer(pParse)).FaLabel = uintptr(0)
|
|
}
|
|
(*TParse)(unsafe.Pointer(pParse)).FnLabel = 0
|
|
**(**int32)(__ccgo_up(pMaxVtabArgs)) = nMaxVtabArgs
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Walker callback for windowRemoveExprFromSelect().
|
|
// */
|
|
func _resolveRemoveWindowsCb(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var pWin uintptr
|
|
_ = pWin
|
|
_ = pWalker
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_WinFunc)) != uint32(0) {
|
|
pWin = *(*uintptr)(unsafe.Pointer(pExpr + 64))
|
|
_sqlite3WindowUnlinkFromSelect(tls, pWin)
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the EP_SubtArg property on every expression inside of
|
|
// ** pList. If any subexpression is actually a subquery, then
|
|
// ** also set the EP_SubtArg property on the first result-set
|
|
// ** column of that subquery.
|
|
// */
|
|
func _resolveSetExprSubtypeArg(tls *libc.TLS, pList uintptr) {
|
|
var ii, nn, v1 int32
|
|
var pExpr uintptr
|
|
_, _, _, _ = ii, nn, pExpr, v1
|
|
if pList != 0 {
|
|
v1 = (*TExprList)(unsafe.Pointer(pList)).FnExpr
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
nn = v1
|
|
ii = 0
|
|
for {
|
|
if !(ii < nn) {
|
|
break
|
|
}
|
|
pExpr = (*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(ii)*32))).FpExpr
|
|
**(**Tu32)(__ccgo_up(pExpr + 4)) |= libc.Uint32FromUint32(EP_SubtArg)
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_SELECT) {
|
|
_resolveSetExprSubtypeArg(tls, (*TSelect)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)))).FpEList)
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate a new RowSetEntry object that is associated with the
|
|
// ** given RowSet. Return a pointer to the new and completely uninitialized
|
|
// ** object.
|
|
// **
|
|
// ** In an OOM situation, the RowSet.db->mallocFailed flag is set and this
|
|
// ** routine returns NULL.
|
|
// */
|
|
func _rowSetEntryAlloc(tls *libc.TLS, p uintptr) (r uintptr) {
|
|
var pNew, v1, v2 uintptr
|
|
_, _, _ = pNew, v1, v2
|
|
if libc.Int32FromUint16((*TRowSet)(unsafe.Pointer(p)).FnFresh) == 0 {
|
|
pNew = _sqlite3DbMallocRawNN(tls, (*TRowSet)(unsafe.Pointer(p)).Fdb, uint64(1016))
|
|
if pNew == uintptr(0) {
|
|
return uintptr(0)
|
|
}
|
|
(*TRowSetChunk)(unsafe.Pointer(pNew)).FpNextChunk = (*TRowSet)(unsafe.Pointer(p)).FpChunk
|
|
(*TRowSet)(unsafe.Pointer(p)).FpChunk = pNew
|
|
(*TRowSet)(unsafe.Pointer(p)).FpFresh = pNew + 8
|
|
(*TRowSet)(unsafe.Pointer(p)).FnFresh = uint16(libc.Uint64FromInt32(libc.Int32FromInt32(ROWSET_ALLOCATION_SIZE)-libc.Int32FromInt32(8)) / libc.Uint64FromInt64(24))
|
|
}
|
|
(*TRowSet)(unsafe.Pointer(p)).FnFresh = (*TRowSet)(unsafe.Pointer(p)).FnFresh - 1
|
|
v2 = p + 32
|
|
v1 = *(*uintptr)(unsafe.Pointer(v2))
|
|
*(*uintptr)(unsafe.Pointer(v2)) += 24
|
|
return v1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Rtree virtual table module xColumn method.
|
|
// */
|
|
func _rtreeColumn(tls *libc.TLS, cur uintptr, ctx uintptr, i int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var p, pCsr, pNode, pRtree uintptr
|
|
var _ /* c at bp+0 */ TRtreeCoord
|
|
var _ /* rc at bp+4 */ int32
|
|
_, _, _, _ = p, pCsr, pNode, pRtree
|
|
pRtree = (*Tsqlite3_vtab_cursor)(unsafe.Pointer(cur)).FpVtab
|
|
pCsr = cur
|
|
p = _rtreeSearchPointFirst(tls, pCsr)
|
|
**(**int32)(__ccgo_up(bp + 4)) = SQLITE_OK
|
|
pNode = _rtreeNodeOfFirstSearchPoint(tls, pCsr, bp+4)
|
|
if **(**int32)(__ccgo_up(bp + 4)) != 0 {
|
|
return **(**int32)(__ccgo_up(bp + 4))
|
|
}
|
|
if p == uintptr(0) {
|
|
return SQLITE_OK
|
|
}
|
|
if libc.Int32FromUint8((*TRtreeSearchPoint)(unsafe.Pointer(p)).FiCell) >= _readInt16(tls, (*TRtreeNode)(unsafe.Pointer(pNode)).FzData+2) {
|
|
return int32(SQLITE_ABORT)
|
|
}
|
|
if i == 0 {
|
|
Xsqlite3_result_int64(tls, ctx, _nodeGetRowid(tls, pRtree, pNode, libc.Int32FromUint8((*TRtreeSearchPoint)(unsafe.Pointer(p)).FiCell)))
|
|
} else {
|
|
if i <= libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnDim2) {
|
|
_nodeGetCoord(tls, pRtree, pNode, libc.Int32FromUint8((*TRtreeSearchPoint)(unsafe.Pointer(p)).FiCell), i-int32(1), bp)
|
|
if libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FeCoordType) == RTREE_COORD_REAL32 {
|
|
Xsqlite3_result_double(tls, ctx, float64(*(*TRtreeValue)(unsafe.Pointer(bp))))
|
|
} else {
|
|
Xsqlite3_result_int(tls, ctx, *(*int32)(unsafe.Pointer(bp)))
|
|
}
|
|
} else {
|
|
if !((*TRtreeCursor)(unsafe.Pointer(pCsr)).FbAuxValid != 0) {
|
|
if (*TRtreeCursor)(unsafe.Pointer(pCsr)).FpReadAux == uintptr(0) {
|
|
**(**int32)(__ccgo_up(bp + 4)) = Xsqlite3_prepare_v3(tls, (*TRtree)(unsafe.Pointer(pRtree)).Fdb, (*TRtree)(unsafe.Pointer(pRtree)).FzReadAuxSql, -int32(1), uint32(0), pCsr+56, uintptr(0))
|
|
if **(**int32)(__ccgo_up(bp + 4)) != 0 {
|
|
return **(**int32)(__ccgo_up(bp + 4))
|
|
}
|
|
}
|
|
Xsqlite3_bind_int64(tls, (*TRtreeCursor)(unsafe.Pointer(pCsr)).FpReadAux, int32(1), _nodeGetRowid(tls, pRtree, pNode, libc.Int32FromUint8((*TRtreeSearchPoint)(unsafe.Pointer(p)).FiCell)))
|
|
**(**int32)(__ccgo_up(bp + 4)) = Xsqlite3_step(tls, (*TRtreeCursor)(unsafe.Pointer(pCsr)).FpReadAux)
|
|
if **(**int32)(__ccgo_up(bp + 4)) == int32(SQLITE_ROW) {
|
|
(*TRtreeCursor)(unsafe.Pointer(pCsr)).FbAuxValid = uint8(1)
|
|
} else {
|
|
Xsqlite3_reset(tls, (*TRtreeCursor)(unsafe.Pointer(pCsr)).FpReadAux)
|
|
if **(**int32)(__ccgo_up(bp + 4)) == int32(SQLITE_DONE) {
|
|
**(**int32)(__ccgo_up(bp + 4)) = SQLITE_OK
|
|
}
|
|
return **(**int32)(__ccgo_up(bp + 4))
|
|
}
|
|
}
|
|
Xsqlite3_result_value(tls, ctx, Xsqlite3_column_value(tls, (*TRtreeCursor)(unsafe.Pointer(pCsr)).FpReadAux, i-libc.Int32FromUint8((*TRtree)(unsafe.Pointer(pRtree)).FnDim2)+int32(1)))
|
|
}
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Push a new element onto the priority queue
|
|
// */
|
|
func _rtreeEnqueue(tls *libc.TLS, pCur uintptr, rScore TRtreeDValue, iLevel Tu8) (r uintptr) {
|
|
var i, j, nNew, v1 int32
|
|
var pNew, pParent, v2 uintptr
|
|
_, _, _, _, _, _, _ = i, j, nNew, pNew, pParent, v1, v2
|
|
if (*TRtreeCursor)(unsafe.Pointer(pCur)).FnPoint >= (*TRtreeCursor)(unsafe.Pointer(pCur)).FnPointAlloc {
|
|
nNew = (*TRtreeCursor)(unsafe.Pointer(pCur)).FnPointAlloc*int32(2) + int32(8)
|
|
pNew = Xsqlite3_realloc64(tls, (*TRtreeCursor)(unsafe.Pointer(pCur)).FaPoint, uint64(libc.Uint64FromInt32(nNew)*uint64(24)))
|
|
if pNew == uintptr(0) {
|
|
return uintptr(0)
|
|
}
|
|
(*TRtreeCursor)(unsafe.Pointer(pCur)).FaPoint = pNew
|
|
(*TRtreeCursor)(unsafe.Pointer(pCur)).FnPointAlloc = nNew
|
|
}
|
|
v2 = pCur + 36
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
i = v1
|
|
pNew = (*TRtreeCursor)(unsafe.Pointer(pCur)).FaPoint + uintptr(i)*24
|
|
(*TRtreeSearchPoint)(unsafe.Pointer(pNew)).FrScore = rScore
|
|
(*TRtreeSearchPoint)(unsafe.Pointer(pNew)).FiLevel = iLevel
|
|
for i > 0 {
|
|
j = (i - int32(1)) / int32(2)
|
|
pParent = (*TRtreeCursor)(unsafe.Pointer(pCur)).FaPoint + uintptr(j)*24
|
|
if _rtreeSearchPointCompare(tls, pNew, pParent) >= 0 {
|
|
break
|
|
}
|
|
_rtreeSearchPointSwap(tls, pCur, j, i)
|
|
i = j
|
|
pNew = pParent
|
|
}
|
|
return pNew
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Get the RtreeNode for the search point with the lowest score.
|
|
// */
|
|
func _rtreeNodeOfFirstSearchPoint(tls *libc.TLS, pCur uintptr, pRC uintptr) (r uintptr) {
|
|
var id Tsqlite3_int64
|
|
var ii int32
|
|
var v1 int64
|
|
_, _, _ = id, ii, v1
|
|
ii = int32(1) - libc.Int32FromUint8((*TRtreeCursor)(unsafe.Pointer(pCur)).FbPoint)
|
|
if **(**uintptr)(__ccgo_up(pCur + 88 + uintptr(ii)*8)) == uintptr(0) {
|
|
if ii != 0 {
|
|
v1 = (**(**TRtreeSearchPoint)(__ccgo_up((*TRtreeCursor)(unsafe.Pointer(pCur)).FaPoint))).Fid
|
|
} else {
|
|
v1 = (*TRtreeCursor)(unsafe.Pointer(pCur)).FsPoint.Fid
|
|
}
|
|
id = v1
|
|
**(**int32)(__ccgo_up(pRC)) = _nodeAcquire(tls, (*TRtreeCursor)(unsafe.Pointer(pCur)).Fbase.FpVtab, id, uintptr(0), pCur+88+uintptr(ii)*8)
|
|
}
|
|
return **(**uintptr)(__ccgo_up(pCur + 88 + uintptr(ii)*8))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate a new RtreeSearchPoint and return a pointer to it. Return
|
|
// ** NULL if malloc fails.
|
|
// */
|
|
func _rtreeSearchPointNew(tls *libc.TLS, pCur uintptr, rScore TRtreeDValue, iLevel Tu8) (r uintptr) {
|
|
var ii int32
|
|
var pFirst, pNew uintptr
|
|
_, _, _ = ii, pFirst, pNew
|
|
pFirst = _rtreeSearchPointFirst(tls, pCur)
|
|
**(**Tu32)(__ccgo_up(pCur + 128 + uintptr(iLevel)*4)) = **(**Tu32)(__ccgo_up(pCur + 128 + uintptr(iLevel)*4)) + 1
|
|
if pFirst == uintptr(0) || (*TRtreeSearchPoint)(unsafe.Pointer(pFirst)).FrScore > rScore || (*TRtreeSearchPoint)(unsafe.Pointer(pFirst)).FrScore == rScore && libc.Int32FromUint8((*TRtreeSearchPoint)(unsafe.Pointer(pFirst)).FiLevel) > libc.Int32FromUint8(iLevel) {
|
|
if (*TRtreeCursor)(unsafe.Pointer(pCur)).FbPoint != 0 {
|
|
pNew = _rtreeEnqueue(tls, pCur, rScore, iLevel)
|
|
if pNew == uintptr(0) {
|
|
return uintptr(0)
|
|
}
|
|
ii = int32((int64(pNew)-int64((*TRtreeCursor)(unsafe.Pointer(pCur)).FaPoint))/24) + int32(1)
|
|
if ii < int32(RTREE_CACHE_SZ) {
|
|
**(**uintptr)(__ccgo_up(pCur + 88 + uintptr(ii)*8)) = **(**uintptr)(__ccgo_up(pCur + 88))
|
|
} else {
|
|
_nodeRelease(tls, (*TRtreeCursor)(unsafe.Pointer(pCur)).Fbase.FpVtab, **(**uintptr)(__ccgo_up(pCur + 88)))
|
|
}
|
|
**(**uintptr)(__ccgo_up(pCur + 88)) = uintptr(0)
|
|
**(**TRtreeSearchPoint)(__ccgo_up(pNew)) = (*TRtreeCursor)(unsafe.Pointer(pCur)).FsPoint
|
|
}
|
|
(*TRtreeCursor)(unsafe.Pointer(pCur)).FsPoint.FrScore = rScore
|
|
(*TRtreeCursor)(unsafe.Pointer(pCur)).FsPoint.FiLevel = iLevel
|
|
(*TRtreeCursor)(unsafe.Pointer(pCur)).FbPoint = uint8(1)
|
|
return pCur + 64
|
|
} else {
|
|
return _rtreeEnqueue(tls, pCur, rScore, iLevel)
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Remove the search point with the lowest current score.
|
|
// */
|
|
func _rtreeSearchPointPop(tls *libc.TLS, p uintptr) {
|
|
var i, j, k, n, v1 int32
|
|
var v2 uintptr
|
|
_, _, _, _, _, _ = i, j, k, n, v1, v2
|
|
i = int32(1) - libc.Int32FromUint8((*TRtreeCursor)(unsafe.Pointer(p)).FbPoint)
|
|
if **(**uintptr)(__ccgo_up(p + 88 + uintptr(i)*8)) != 0 {
|
|
_nodeRelease(tls, (*TRtreeCursor)(unsafe.Pointer(p)).Fbase.FpVtab, **(**uintptr)(__ccgo_up(p + 88 + uintptr(i)*8)))
|
|
**(**uintptr)(__ccgo_up(p + 88 + uintptr(i)*8)) = uintptr(0)
|
|
}
|
|
if (*TRtreeCursor)(unsafe.Pointer(p)).FbPoint != 0 {
|
|
**(**Tu32)(__ccgo_up(p + 128 + uintptr((*TRtreeCursor)(unsafe.Pointer(p)).FsPoint.FiLevel)*4)) = **(**Tu32)(__ccgo_up(p + 128 + uintptr((*TRtreeCursor)(unsafe.Pointer(p)).FsPoint.FiLevel)*4)) - 1
|
|
(*TRtreeCursor)(unsafe.Pointer(p)).FbPoint = uint8(0)
|
|
} else {
|
|
if (*TRtreeCursor)(unsafe.Pointer(p)).FnPoint != 0 {
|
|
**(**Tu32)(__ccgo_up(p + 128 + uintptr((**(**TRtreeSearchPoint)(__ccgo_up((*TRtreeCursor)(unsafe.Pointer(p)).FaPoint))).FiLevel)*4)) = **(**Tu32)(__ccgo_up(p + 128 + uintptr((**(**TRtreeSearchPoint)(__ccgo_up((*TRtreeCursor)(unsafe.Pointer(p)).FaPoint))).FiLevel)*4)) - 1
|
|
v2 = p + 36
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) - 1
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
n = v1
|
|
**(**TRtreeSearchPoint)(__ccgo_up((*TRtreeCursor)(unsafe.Pointer(p)).FaPoint)) = **(**TRtreeSearchPoint)(__ccgo_up((*TRtreeCursor)(unsafe.Pointer(p)).FaPoint + uintptr(n)*24))
|
|
if n < libc.Int32FromInt32(RTREE_CACHE_SZ)-libc.Int32FromInt32(1) {
|
|
**(**uintptr)(__ccgo_up(p + 88 + 1*8)) = **(**uintptr)(__ccgo_up(p + 88 + uintptr(n+int32(1))*8))
|
|
**(**uintptr)(__ccgo_up(p + 88 + uintptr(n+int32(1))*8)) = uintptr(0)
|
|
}
|
|
i = 0
|
|
for {
|
|
v1 = i*libc.Int32FromInt32(2) + libc.Int32FromInt32(1)
|
|
j = v1
|
|
if !(v1 < n) {
|
|
break
|
|
}
|
|
k = j + int32(1)
|
|
if k < n && _rtreeSearchPointCompare(tls, (*TRtreeCursor)(unsafe.Pointer(p)).FaPoint+uintptr(k)*24, (*TRtreeCursor)(unsafe.Pointer(p)).FaPoint+uintptr(j)*24) < 0 {
|
|
if _rtreeSearchPointCompare(tls, (*TRtreeCursor)(unsafe.Pointer(p)).FaPoint+uintptr(k)*24, (*TRtreeCursor)(unsafe.Pointer(p)).FaPoint+uintptr(i)*24) < 0 {
|
|
_rtreeSearchPointSwap(tls, p, i, k)
|
|
i = k
|
|
} else {
|
|
break
|
|
}
|
|
} else {
|
|
if _rtreeSearchPointCompare(tls, (*TRtreeCursor)(unsafe.Pointer(p)).FaPoint+uintptr(j)*24, (*TRtreeCursor)(unsafe.Pointer(p)).FaPoint+uintptr(i)*24) < 0 {
|
|
_rtreeSearchPointSwap(tls, p, i, j)
|
|
i = j
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Check schema cookies in all databases. If any cookie is out
|
|
// ** of date set pParse->rc to SQLITE_SCHEMA. If all schema cookies
|
|
// ** make no changes to pParse->rc.
|
|
// */
|
|
func _schemaIsValid(tls *libc.TLS, pParse uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var db, pBt uintptr
|
|
var iDb, openedTransaction, rc int32
|
|
var _ /* cookie at bp+0 */ int32
|
|
_, _, _, _, _ = db, iDb, openedTransaction, pBt, rc
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
iDb = 0
|
|
for {
|
|
if !(iDb < (*Tsqlite3)(unsafe.Pointer(db)).FnDb) {
|
|
break
|
|
}
|
|
openedTransaction = 0 /* True if a transaction is opened */
|
|
pBt = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(iDb)*32))).FpBt /* Btree database to read cookie from */
|
|
if pBt == uintptr(0) {
|
|
goto _1
|
|
}
|
|
/* If there is not already a read-only (or read-write) transaction opened
|
|
** on the b-tree database, open one now. If a transaction is opened, it
|
|
** will be closed immediately after reading the meta-value. */
|
|
if _sqlite3BtreeTxnState(tls, pBt) == SQLITE_TXN_NONE {
|
|
rc = _sqlite3BtreeBeginTrans(tls, pBt, 0, uintptr(0))
|
|
if rc == int32(SQLITE_NOMEM) || rc == libc.Int32FromInt32(SQLITE_IOERR)|libc.Int32FromInt32(12)<<libc.Int32FromInt32(8) {
|
|
_sqlite3OomFault(tls, db)
|
|
(*TParse)(unsafe.Pointer(pParse)).Frc = int32(SQLITE_NOMEM)
|
|
}
|
|
if rc != SQLITE_OK {
|
|
return
|
|
}
|
|
openedTransaction = int32(1)
|
|
}
|
|
/* Read the schema cookie from the database. If it does not match the
|
|
** value stored as part of the in-memory schema representation,
|
|
** set Parse.rc to SQLITE_SCHEMA. */
|
|
_sqlite3BtreeGetMeta(tls, pBt, int32(BTREE_SCHEMA_VERSION), bp)
|
|
if **(**int32)(__ccgo_up(bp)) != (*TSchema)(unsafe.Pointer((**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(iDb)*32))).FpSchema)).Fschema_cookie {
|
|
if libc.Int32FromUint16((*TSchema)(unsafe.Pointer((**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(iDb)*32))).FpSchema)).FschemaFlags)&int32(DB_SchemaLoaded) == int32(DB_SchemaLoaded) {
|
|
(*TParse)(unsafe.Pointer(pParse)).Frc = int32(SQLITE_SCHEMA)
|
|
}
|
|
_sqlite3ResetOneSchema(tls, db, iDb)
|
|
}
|
|
/* Close the transaction, if one was opened. */
|
|
if openedTransaction != 0 {
|
|
_sqlite3BtreeCommit(tls, pBt)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
iDb = iDb + 1
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Seek to the offset in id->offset then read cnt bytes into pBuf.
|
|
// ** Return the number of bytes actually read. Update the offset.
|
|
// **
|
|
// ** To avoid stomping the errno value on a failed write the lastErrno value
|
|
// ** is set before returning.
|
|
// */
|
|
func _seekAndWrite(tls *libc.TLS, id uintptr, offset Ti64, pBuf uintptr, cnt int32) (r int32) {
|
|
return _seekAndWriteFd(tls, (*TunixFile)(unsafe.Pointer(id)).Fh, offset, pBuf, cnt, id+32)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Walker SELECT callbacks for sqlite3ReferencesSrcList().
|
|
// **
|
|
// ** When entering a new subquery on the pExpr argument, add all FROM clause
|
|
// ** entries for that subquery to the exclude list.
|
|
// **
|
|
// ** When leaving the subquery, remove those entries from the exclude list.
|
|
// */
|
|
func _selectRefEnter(tls *libc.TLS, pWalker uintptr, pSelect uintptr) (r int32) {
|
|
var i, j Ti64
|
|
var p, pSrc, piNew uintptr
|
|
_, _, _, _, _ = i, j, p, pSrc, piNew
|
|
p = *(*uintptr)(unsafe.Pointer(pWalker + 40))
|
|
pSrc = (*TSelect)(unsafe.Pointer(pSelect)).FpSrc
|
|
if (*TSrcList)(unsafe.Pointer(pSrc)).FnSrc == 0 {
|
|
return WRC_Continue
|
|
}
|
|
j = (*TRefSrcList)(unsafe.Pointer(p)).FnExclude
|
|
**(**Ti64)(__ccgo_up(p + 16)) += int64((*TSrcList)(unsafe.Pointer(pSrc)).FnSrc)
|
|
piNew = _sqlite3DbRealloc(tls, (*TRefSrcList)(unsafe.Pointer(p)).Fdb, (*TRefSrcList)(unsafe.Pointer(p)).FaiExclude, libc.Uint64FromInt64((*TRefSrcList)(unsafe.Pointer(p)).FnExclude)*uint64(4))
|
|
if piNew == uintptr(0) {
|
|
(*TRefSrcList)(unsafe.Pointer(p)).FnExclude = 0
|
|
return int32(WRC_Abort)
|
|
} else {
|
|
(*TRefSrcList)(unsafe.Pointer(p)).FaiExclude = piNew
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < int64((*TSrcList)(unsafe.Pointer(pSrc)).FnSrc)) {
|
|
break
|
|
}
|
|
**(**int32)(__ccgo_up((*TRefSrcList)(unsafe.Pointer(p)).FaiExclude + uintptr(j)*4)) = (*(*TSrcItem)(unsafe.Pointer(pSrc + 8 + uintptr(i)*80))).FiCursor
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
j = j + 1
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Append a DELETE change to the buffer passed as the first argument. Use
|
|
// ** the changeset format if argument bPatchset is zero, or the patchset
|
|
// ** format otherwise.
|
|
// */
|
|
func _sessionAppendDelete(tls *libc.TLS, pBuf uintptr, bPatchset int32, p uintptr, nCol int32, abPK uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var a, pStart, v2 uintptr
|
|
var eType, i int32
|
|
var _ /* n at bp+4 */ int32
|
|
var _ /* rc at bp+0 */ int32
|
|
_, _, _, _, _ = a, eType, i, pStart, v2
|
|
**(**int32)(__ccgo_up(bp)) = SQLITE_OK
|
|
_sessionAppendByte(tls, pBuf, uint8(SQLITE_DELETE), bp)
|
|
_sessionAppendByte(tls, pBuf, (*TSessionChange)(unsafe.Pointer(p)).FbIndirect, bp)
|
|
if bPatchset == 0 {
|
|
_sessionAppendBlob(tls, pBuf, (*TSessionChange)(unsafe.Pointer(p)).FaRecord, (*TSessionChange)(unsafe.Pointer(p)).FnRecord, bp)
|
|
} else {
|
|
a = (*TSessionChange)(unsafe.Pointer(p)).FaRecord
|
|
i = 0
|
|
for {
|
|
if !(i < nCol) {
|
|
break
|
|
}
|
|
pStart = a
|
|
v2 = a
|
|
a = a + 1
|
|
eType = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(v2)))
|
|
switch eType {
|
|
case 0:
|
|
fallthrough
|
|
case int32(SQLITE_NULL):
|
|
case int32(SQLITE_FLOAT):
|
|
fallthrough
|
|
case int32(SQLITE_INTEGER):
|
|
a = a + uintptr(8)
|
|
default:
|
|
a = a + uintptr(_sessionVarintGet(tls, a, bp+4))
|
|
a = a + uintptr(**(**int32)(__ccgo_up(bp + 4)))
|
|
break
|
|
}
|
|
if **(**Tu8)(__ccgo_up(abPK + uintptr(i))) != 0 {
|
|
_sessionAppendBlob(tls, pBuf, pStart, int32(int64(a)-int64(pStart)), bp)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is a no-op if *pRc is set to other than SQLITE_OK when it
|
|
// ** is called. Otherwise, append a serialized table header (part of the binary
|
|
// ** changeset format) to buffer *pBuf. If an error occurs, set *pRc to an
|
|
// ** SQLite error code before returning.
|
|
// */
|
|
func _sessionAppendTableHdr(tls *libc.TLS, pBuf uintptr, bPatchset int32, pTab uintptr, pRc uintptr) {
|
|
var v1 int32
|
|
_ = v1
|
|
/* Write a table header */
|
|
if bPatchset != 0 {
|
|
v1 = int32('P')
|
|
} else {
|
|
v1 = int32('T')
|
|
}
|
|
_sessionAppendByte(tls, pBuf, libc.Uint8FromInt32(v1), pRc)
|
|
_sessionAppendVarint(tls, pBuf, (*TSessionTable)(unsafe.Pointer(pTab)).FnCol, pRc)
|
|
_sessionAppendBlob(tls, pBuf, (*TSessionTable)(unsafe.Pointer(pTab)).FabPK, (*TSessionTable)(unsafe.Pointer(pTab)).FnCol, pRc)
|
|
_sessionAppendBlob(tls, pBuf, (*TSessionTable)(unsafe.Pointer(pTab)).FzName, libc.Int32FromUint64(libc.Xstrlen(tls, (*TSessionTable)(unsafe.Pointer(pTab)).FzName))+int32(1), pRc)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Arguments aLeft and aRight are pointers to change records for table pTab.
|
|
// ** This function returns true if the two records apply to the same row (i.e.
|
|
// ** have the same values stored in the primary key columns), or false
|
|
// ** otherwise.
|
|
// */
|
|
func _sessionChangeEqual(tls *libc.TLS, pTab uintptr, bLeftPkOnly int32, aLeft uintptr, bRightPkOnly int32, aRight uintptr) (r int32) {
|
|
var a1, a2 uintptr
|
|
var iCol, n1, n2 int32
|
|
_, _, _, _, _ = a1, a2, iCol, n1, n2
|
|
a1 = aLeft /* Cursor to iterate through aLeft */
|
|
a2 = aRight /* Used to iterate through table columns */
|
|
iCol = 0
|
|
for {
|
|
if !(iCol < (*TSessionTable)(unsafe.Pointer(pTab)).FnCol) {
|
|
break
|
|
}
|
|
if **(**Tu8)(__ccgo_up((*TSessionTable)(unsafe.Pointer(pTab)).FabPK + uintptr(iCol))) != 0 {
|
|
n1 = _sessionSerialLen(tls, a1)
|
|
n2 = _sessionSerialLen(tls, a2)
|
|
if n1 != n2 || libc.Xmemcmp(tls, a1, a2, libc.Uint64FromInt32(n1)) != 0 {
|
|
return 0
|
|
}
|
|
a1 = a1 + uintptr(n1)
|
|
a2 = a2 + uintptr(n2)
|
|
} else {
|
|
if bLeftPkOnly == 0 {
|
|
a1 = a1 + uintptr(_sessionSerialLen(tls, a1))
|
|
}
|
|
if bRightPkOnly == 0 {
|
|
a2 = a2 + uintptr(_sessionSerialLen(tls, a2))
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
iCol = iCol + 1
|
|
}
|
|
return int32(1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Check if a changeset entry with nCol columns and the PK array passed
|
|
// ** as the final argument to this function is compatible with SessionTable
|
|
// ** pTab. If so, return 1. Otherwise, if they are incompatible in some way,
|
|
// ** return 0.
|
|
// */
|
|
func _sessionChangesetCheckCompat(tls *libc.TLS, pTab uintptr, nCol int32, abPK uintptr) (r int32) {
|
|
var bPK Tu8
|
|
var ii, v2 int32
|
|
_, _, _ = bPK, ii, v2
|
|
if (*TSessionTable)(unsafe.Pointer(pTab)).FazCol != 0 && nCol < (*TSessionTable)(unsafe.Pointer(pTab)).FnCol {
|
|
ii = 0
|
|
for {
|
|
if !(ii < (*TSessionTable)(unsafe.Pointer(pTab)).FnCol) {
|
|
break
|
|
}
|
|
if ii < nCol {
|
|
v2 = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(abPK + uintptr(ii))))
|
|
} else {
|
|
v2 = 0
|
|
}
|
|
bPK = libc.Uint8FromInt32(v2)
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TSessionTable)(unsafe.Pointer(pTab)).FabPK + uintptr(ii)))) != libc.Int32FromUint8(bPK) {
|
|
return 0
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
return int32(1)
|
|
}
|
|
return libc.BoolInt32((*TSessionTable)(unsafe.Pointer(pTab)).FnCol == nCol && 0 == libc.Xmemcmp(tls, abPK, (*TSessionTable)(unsafe.Pointer(pTab)).FabPK, libc.Uint64FromInt32(nCol)))
|
|
}
|
|
|
|
func _sessionChangesetExtendRecord(tls *libc.TLS, pGrp uintptr, pTab uintptr, nCol int32, op int32, aRec uintptr, nRec int32, pOut uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var eType, iOff, ii, n int32
|
|
var iVal Tsqlite3_int64
|
|
var rVal float64
|
|
var z, z1 uintptr
|
|
var _ /* rc at bp+0 */ int32
|
|
_, _, _, _, _, _, _, _ = eType, iOff, iVal, ii, n, rVal, z, z1
|
|
**(**int32)(__ccgo_up(bp)) = SQLITE_OK
|
|
ii = 0
|
|
(*TSessionBuffer)(unsafe.Pointer(pOut)).FnBuf = 0
|
|
if op == int32(SQLITE_INSERT) || op == int32(SQLITE_DELETE) && (*Tsqlite3_changegroup)(unsafe.Pointer(pGrp)).FbPatch == 0 {
|
|
/* Append the missing default column values to the record. */
|
|
_sessionAppendBlob(tls, pOut, aRec, nRec, bp)
|
|
if **(**int32)(__ccgo_up(bp)) == SQLITE_OK && (*TSessionTable)(unsafe.Pointer(pTab)).FpDfltStmt == uintptr(0) {
|
|
**(**int32)(__ccgo_up(bp)) = _sessionPrepareDfltStmt(tls, (*Tsqlite3_changegroup)(unsafe.Pointer(pGrp)).Fdb, pTab, pTab+80)
|
|
if **(**int32)(__ccgo_up(bp)) == SQLITE_OK && int32(SQLITE_ROW) != Xsqlite3_step(tls, (*TSessionTable)(unsafe.Pointer(pTab)).FpDfltStmt) {
|
|
**(**int32)(__ccgo_up(bp)) = Xsqlite3_errcode(tls, (*Tsqlite3_changegroup)(unsafe.Pointer(pGrp)).Fdb)
|
|
}
|
|
}
|
|
ii = nCol
|
|
for {
|
|
if !(**(**int32)(__ccgo_up(bp)) == SQLITE_OK && ii < (*TSessionTable)(unsafe.Pointer(pTab)).FnCol) {
|
|
break
|
|
}
|
|
eType = Xsqlite3_column_type(tls, (*TSessionTable)(unsafe.Pointer(pTab)).FpDfltStmt, ii)
|
|
_sessionAppendByte(tls, pOut, libc.Uint8FromInt32(eType), bp)
|
|
switch eType {
|
|
case int32(SQLITE_FLOAT):
|
|
fallthrough
|
|
case int32(SQLITE_INTEGER):
|
|
if SQLITE_OK == _sessionBufferGrow(tls, pOut, int64(8), bp) {
|
|
if eType == int32(SQLITE_INTEGER) {
|
|
iVal = Xsqlite3_column_int64(tls, (*TSessionTable)(unsafe.Pointer(pTab)).FpDfltStmt, ii)
|
|
_sessionPutI64(tls, (*TSessionBuffer)(unsafe.Pointer(pOut)).FaBuf+uintptr((*TSessionBuffer)(unsafe.Pointer(pOut)).FnBuf), iVal)
|
|
} else {
|
|
rVal = Xsqlite3_column_double(tls, (*TSessionTable)(unsafe.Pointer(pTab)).FpDfltStmt, ii)
|
|
_sessionPutDouble(tls, (*TSessionBuffer)(unsafe.Pointer(pOut)).FaBuf+uintptr((*TSessionBuffer)(unsafe.Pointer(pOut)).FnBuf), rVal)
|
|
}
|
|
**(**int32)(__ccgo_up(pOut + 8)) += int32(8)
|
|
}
|
|
case int32(SQLITE_BLOB):
|
|
fallthrough
|
|
case int32(SQLITE_TEXT):
|
|
n = Xsqlite3_column_bytes(tls, (*TSessionTable)(unsafe.Pointer(pTab)).FpDfltStmt, ii)
|
|
_sessionAppendVarint(tls, pOut, n, bp)
|
|
if eType == int32(SQLITE_TEXT) {
|
|
z = Xsqlite3_column_text(tls, (*TSessionTable)(unsafe.Pointer(pTab)).FpDfltStmt, ii)
|
|
_sessionAppendBlob(tls, pOut, z, n, bp)
|
|
} else {
|
|
z1 = Xsqlite3_column_blob(tls, (*TSessionTable)(unsafe.Pointer(pTab)).FpDfltStmt, ii)
|
|
_sessionAppendBlob(tls, pOut, z1, n, bp)
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
} else {
|
|
if op == int32(SQLITE_UPDATE) {
|
|
/* Append missing "undefined" entries to the old.* record. And, if this
|
|
** is an UPDATE, to the new.* record as well. */
|
|
iOff = 0
|
|
if (*Tsqlite3_changegroup)(unsafe.Pointer(pGrp)).FbPatch == 0 {
|
|
ii = 0
|
|
for {
|
|
if !(ii < nCol) {
|
|
break
|
|
}
|
|
iOff = iOff + _sessionSerialLen(tls, aRec+uintptr(iOff))
|
|
goto _2
|
|
_2:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
_sessionAppendBlob(tls, pOut, aRec, iOff, bp)
|
|
ii = 0
|
|
for {
|
|
if !(ii < (*TSessionTable)(unsafe.Pointer(pTab)).FnCol-nCol) {
|
|
break
|
|
}
|
|
_sessionAppendByte(tls, pOut, uint8(0x00), bp)
|
|
goto _3
|
|
_3:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
}
|
|
_sessionAppendBlob(tls, pOut, aRec+uintptr(iOff), nRec-iOff, bp)
|
|
ii = 0
|
|
for {
|
|
if !(ii < (*TSessionTable)(unsafe.Pointer(pTab)).FnCol-nCol) {
|
|
break
|
|
}
|
|
_sessionAppendByte(tls, pOut, uint8(0x00), bp)
|
|
goto _4
|
|
_4:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
} else {
|
|
_sessionAppendBlob(tls, pOut, aRec, nRec, bp)
|
|
}
|
|
}
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Invoke the conflict handler for the change that the changeset iterator
|
|
// ** currently points to.
|
|
// **
|
|
// ** Argument eType must be either CHANGESET_DATA or CHANGESET_CONFLICT.
|
|
// ** If argument pbReplace is NULL, then the type of conflict handler invoked
|
|
// ** depends solely on eType, as follows:
|
|
// **
|
|
// ** eType value Value passed to xConflict
|
|
// ** -------------------------------------------------
|
|
// ** CHANGESET_DATA CHANGESET_NOTFOUND
|
|
// ** CHANGESET_CONFLICT CHANGESET_CONSTRAINT
|
|
// **
|
|
// ** Or, if pbReplace is not NULL, then an attempt is made to find an existing
|
|
// ** record with the same primary key as the record about to be deleted, updated
|
|
// ** or inserted. If such a record can be found, it is available to the conflict
|
|
// ** handler as the "conflicting" record. In this case the type of conflict
|
|
// ** handler invoked is as follows:
|
|
// **
|
|
// ** eType value PK Record found? Value passed to xConflict
|
|
// ** ----------------------------------------------------------------
|
|
// ** CHANGESET_DATA Yes CHANGESET_DATA
|
|
// ** CHANGESET_DATA No CHANGESET_NOTFOUND
|
|
// ** CHANGESET_CONFLICT Yes CHANGESET_CONFLICT
|
|
// ** CHANGESET_CONFLICT No CHANGESET_CONSTRAINT
|
|
// **
|
|
// ** If pbReplace is not NULL, and a record with a matching PK is found, and
|
|
// ** the conflict handler function returns SQLITE_CHANGESET_REPLACE, *pbReplace
|
|
// ** is set to non-zero before returning SQLITE_OK.
|
|
// **
|
|
// ** If the conflict handler returns SQLITE_CHANGESET_ABORT, SQLITE_ABORT is
|
|
// ** returned. Or, if the conflict handler returns an invalid value,
|
|
// ** SQLITE_MISUSE. If the conflict handler returns SQLITE_CHANGESET_OMIT,
|
|
// ** this function returns SQLITE_OK.
|
|
// */
|
|
func _sessionConflictHandler(tls *libc.TLS, eType int32, p uintptr, pIter uintptr, __ccgo_fp_xConflict uintptr, pCtx uintptr, pbReplace uintptr) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var aBlob uintptr
|
|
var nBlob, res int32
|
|
var _ /* nCol at bp+4 */ int32
|
|
var _ /* op at bp+8 */ int32
|
|
var _ /* rc at bp+0 */ int32
|
|
var _ /* zDummy at bp+16 */ uintptr
|
|
_, _, _ = aBlob, nBlob, res
|
|
res = SQLITE_CHANGESET_OMIT
|
|
Xsqlite3changeset_op(tls, pIter, bp+16, bp+4, bp+8, uintptr(0))
|
|
/* Bind the new.* PRIMARY KEY values to the SELECT statement. */
|
|
if pbReplace != 0 {
|
|
**(**int32)(__ccgo_up(bp)) = _sessionSeekToRow(tls, pIter, p)
|
|
} else {
|
|
**(**int32)(__ccgo_up(bp)) = SQLITE_OK
|
|
}
|
|
if **(**int32)(__ccgo_up(bp)) == int32(SQLITE_ROW) {
|
|
/* There exists another row with the new.* primary key. */
|
|
if 0 == libc.Int32FromUint8((*TSessionApplyCtx)(unsafe.Pointer(p)).FbIgnoreNoop) || 0 == Xsqlite3_column_int(tls, (*TSessionApplyCtx)(unsafe.Pointer(p)).FpSelect, Xsqlite3_column_count(tls, (*TSessionApplyCtx)(unsafe.Pointer(p)).FpSelect)-int32(1)) {
|
|
(*Tsqlite3_changeset_iter)(unsafe.Pointer(pIter)).FpConflict = (*TSessionApplyCtx)(unsafe.Pointer(p)).FpSelect
|
|
res = (*(*func(*libc.TLS, uintptr, int32, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{__ccgo_fp_xConflict})))(tls, pCtx, eType, pIter)
|
|
(*Tsqlite3_changeset_iter)(unsafe.Pointer(pIter)).FpConflict = uintptr(0)
|
|
}
|
|
**(**int32)(__ccgo_up(bp)) = Xsqlite3_reset(tls, (*TSessionApplyCtx)(unsafe.Pointer(p)).FpSelect)
|
|
} else {
|
|
if **(**int32)(__ccgo_up(bp)) == SQLITE_OK {
|
|
if (*TSessionApplyCtx)(unsafe.Pointer(p)).FbDeferConstraints != 0 && eType == int32(SQLITE_CHANGESET_CONFLICT) {
|
|
/* Instead of invoking the conflict handler, append the change blob
|
|
** to the SessionApplyCtx.constraints buffer. */
|
|
aBlob = (*Tsqlite3_changeset_iter)(unsafe.Pointer(pIter)).Fin.FaData + uintptr((*Tsqlite3_changeset_iter)(unsafe.Pointer(pIter)).Fin.FiCurrent)
|
|
nBlob = (*Tsqlite3_changeset_iter)(unsafe.Pointer(pIter)).Fin.FiNext - (*Tsqlite3_changeset_iter)(unsafe.Pointer(pIter)).Fin.FiCurrent
|
|
_sessionAppendBlob(tls, p+88, aBlob, nBlob, bp)
|
|
return **(**int32)(__ccgo_up(bp))
|
|
} else {
|
|
if libc.Int32FromUint8((*TSessionApplyCtx)(unsafe.Pointer(p)).FbIgnoreNoop) == 0 || **(**int32)(__ccgo_up(bp + 8)) != int32(SQLITE_DELETE) || eType == int32(SQLITE_CHANGESET_CONFLICT) {
|
|
/* No other row with the new.* primary key. */
|
|
res = (*(*func(*libc.TLS, uintptr, int32, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{__ccgo_fp_xConflict})))(tls, pCtx, eType+int32(1), pIter)
|
|
if res == int32(SQLITE_CHANGESET_REPLACE) {
|
|
**(**int32)(__ccgo_up(bp)) = int32(SQLITE_MISUSE)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if **(**int32)(__ccgo_up(bp)) == SQLITE_OK {
|
|
switch res {
|
|
case int32(SQLITE_CHANGESET_REPLACE):
|
|
**(**int32)(__ccgo_up(pbReplace)) = int32(1)
|
|
case SQLITE_CHANGESET_OMIT:
|
|
case int32(SQLITE_CHANGESET_ABORT):
|
|
**(**int32)(__ccgo_up(bp)) = int32(SQLITE_ABORT)
|
|
default:
|
|
**(**int32)(__ccgo_up(bp)) = int32(SQLITE_MISUSE)
|
|
break
|
|
}
|
|
if **(**int32)(__ccgo_up(bp)) == SQLITE_OK {
|
|
**(**int32)(__ccgo_up(bp)) = _sessionRebaseAdd(tls, p, res, pIter)
|
|
}
|
|
}
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate and return a pointer to a buffer nByte bytes in size. If
|
|
// ** pSession is not NULL, increase the sqlite3_session.nMalloc variable
|
|
// ** by the number of bytes allocated.
|
|
// */
|
|
func _sessionMalloc64(tls *libc.TLS, pSession uintptr, nByte Ti64) (r uintptr) {
|
|
var pRet, v1 uintptr
|
|
_, _ = pRet, v1
|
|
pRet = Xsqlite3_malloc64(tls, libc.Uint64FromInt64(nByte))
|
|
if pSession != 0 {
|
|
v1 = pSession + 56
|
|
*(*Ti64)(unsafe.Pointer(v1)) = Ti64(uint64(*(*Ti64)(unsafe.Pointer(v1))) + Xsqlite3_msize(tls, pRet))
|
|
}
|
|
return pRet
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add a single change to the changegroup pGrp.
|
|
// */
|
|
func _sessionOneChangeToHash(tls *libc.TLS, pGrp uintptr, pTab uintptr, op int32, bIndirect int32, nCol int32, aRec uintptr, nRec int32, bRebase int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var bPkOnly1, bPkOnly2, iHash, rc int32
|
|
var pBuf, pExist, pp uintptr
|
|
var _ /* pChange at bp+0 */ uintptr
|
|
_, _, _, _, _, _, _ = bPkOnly1, bPkOnly2, iHash, pBuf, pExist, pp, rc
|
|
rc = SQLITE_OK
|
|
iHash = 0
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
pExist = uintptr(0)
|
|
pp = uintptr(0)
|
|
if nCol < (*TSessionTable)(unsafe.Pointer(pTab)).FnCol {
|
|
pBuf = pGrp + 16
|
|
rc = _sessionChangesetExtendRecord(tls, pGrp, pTab, nCol, op, aRec, nRec, pBuf)
|
|
aRec = (*TSessionBuffer)(unsafe.Pointer(pBuf)).FaBuf
|
|
nRec = (*TSessionBuffer)(unsafe.Pointer(pBuf)).FnBuf
|
|
}
|
|
if rc == SQLITE_OK && _sessionGrowHash(tls, uintptr(0), (*Tsqlite3_changegroup)(unsafe.Pointer(pGrp)).FbPatch, pTab) != 0 {
|
|
rc = int32(SQLITE_NOMEM)
|
|
}
|
|
if rc == SQLITE_OK {
|
|
/* Search for existing entry. If found, remove it from the hash table.
|
|
** Code below may link it back in. */
|
|
iHash = libc.Int32FromUint32(_sessionChangeHash(tls, pTab, libc.BoolInt32((*Tsqlite3_changegroup)(unsafe.Pointer(pGrp)).FbPatch != 0 && op == int32(SQLITE_DELETE)), aRec, (*TSessionTable)(unsafe.Pointer(pTab)).FnChange))
|
|
pp = (*TSessionTable)(unsafe.Pointer(pTab)).FapChange + uintptr(iHash)*8
|
|
for {
|
|
if !(**(**uintptr)(__ccgo_up(pp)) != 0) {
|
|
break
|
|
}
|
|
bPkOnly1 = 0
|
|
bPkOnly2 = 0
|
|
if (*Tsqlite3_changegroup)(unsafe.Pointer(pGrp)).FbPatch != 0 {
|
|
bPkOnly1 = libc.BoolInt32(libc.Int32FromUint8((*TSessionChange)(unsafe.Pointer(**(**uintptr)(__ccgo_up(pp)))).Fop) == int32(SQLITE_DELETE))
|
|
bPkOnly2 = libc.BoolInt32(op == int32(SQLITE_DELETE))
|
|
}
|
|
if _sessionChangeEqual(tls, pTab, bPkOnly1, (*TSessionChange)(unsafe.Pointer(**(**uintptr)(__ccgo_up(pp)))).FaRecord, bPkOnly2, aRec) != 0 {
|
|
pExist = **(**uintptr)(__ccgo_up(pp))
|
|
**(**uintptr)(__ccgo_up(pp)) = (*TSessionChange)(unsafe.Pointer(**(**uintptr)(__ccgo_up(pp)))).FpNext
|
|
(*TSessionTable)(unsafe.Pointer(pTab)).FnEntry = (*TSessionTable)(unsafe.Pointer(pTab)).FnEntry - 1
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
pp = **(**uintptr)(__ccgo_up(pp)) + 24
|
|
}
|
|
}
|
|
if rc == SQLITE_OK {
|
|
rc = _sessionChangeMerge(tls, pTab, bRebase, (*Tsqlite3_changegroup)(unsafe.Pointer(pGrp)).FbPatch, pExist, op, bIndirect, aRec, nRec, bp)
|
|
}
|
|
if rc == SQLITE_OK && **(**uintptr)(__ccgo_up(bp)) != 0 {
|
|
(*TSessionChange)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FpNext = **(**uintptr)(__ccgo_up((*TSessionTable)(unsafe.Pointer(pTab)).FapChange + uintptr(iHash)*8))
|
|
**(**uintptr)(__ccgo_up((*TSessionTable)(unsafe.Pointer(pTab)).FapChange + uintptr(iHash)*8)) = **(**uintptr)(__ccgo_up(bp))
|
|
(*TSessionTable)(unsafe.Pointer(pTab)).FnEntry = (*TSessionTable)(unsafe.Pointer(pTab)).FnEntry + 1
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called from within sqlite3changeset_apply_v2() when
|
|
// ** a conflict is encountered and resolved using conflict resolution
|
|
// ** mode eType (either SQLITE_CHANGESET_OMIT or SQLITE_CHANGESET_REPLACE)..
|
|
// ** It adds a conflict resolution record to the buffer in
|
|
// ** SessionApplyCtx.rebase, which will eventually be returned to the caller
|
|
// ** of apply_v2() as the "rebase" buffer.
|
|
// **
|
|
// ** Return SQLITE_OK if successful, or an SQLite error code otherwise.
|
|
// */
|
|
func _sessionRebaseAdd(tls *libc.TLS, p uintptr, eType int32, pIter uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var eOp, i, v1 int32
|
|
var zTab uintptr
|
|
var _ /* pVal at bp+8 */ uintptr
|
|
var _ /* rc at bp+0 */ int32
|
|
_, _, _, _ = eOp, i, zTab, v1
|
|
**(**int32)(__ccgo_up(bp)) = SQLITE_OK
|
|
if (*TSessionApplyCtx)(unsafe.Pointer(p)).FbRebase != 0 {
|
|
eOp = (*Tsqlite3_changeset_iter)(unsafe.Pointer(pIter)).Fop
|
|
if libc.Int32FromUint8((*TSessionApplyCtx)(unsafe.Pointer(p)).FbRebaseStarted) == 0 {
|
|
/* Append a table-header to the rebase buffer */
|
|
zTab = (*Tsqlite3_changeset_iter)(unsafe.Pointer(pIter)).FzTab
|
|
_sessionAppendByte(tls, p+104, uint8('T'), bp)
|
|
_sessionAppendVarint(tls, p+104, (*TSessionApplyCtx)(unsafe.Pointer(p)).FnCol, bp)
|
|
_sessionAppendBlob(tls, p+104, (*TSessionApplyCtx)(unsafe.Pointer(p)).FabPK, (*TSessionApplyCtx)(unsafe.Pointer(p)).FnCol, bp)
|
|
_sessionAppendBlob(tls, p+104, zTab, libc.Int32FromUint64(libc.Xstrlen(tls, zTab))+int32(1), bp)
|
|
(*TSessionApplyCtx)(unsafe.Pointer(p)).FbRebaseStarted = uint8(1)
|
|
}
|
|
if eOp == int32(SQLITE_DELETE) {
|
|
v1 = int32(SQLITE_DELETE)
|
|
} else {
|
|
v1 = int32(SQLITE_INSERT)
|
|
}
|
|
_sessionAppendByte(tls, p+104, libc.Uint8FromInt32(v1), bp)
|
|
_sessionAppendByte(tls, p+104, libc.BoolUint8(eType == libc.Int32FromInt32(SQLITE_CHANGESET_REPLACE)), bp)
|
|
i = 0
|
|
for {
|
|
if !(i < (*TSessionApplyCtx)(unsafe.Pointer(p)).FnCol) {
|
|
break
|
|
}
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = uintptr(0)
|
|
if eOp == int32(SQLITE_DELETE) || eOp == int32(SQLITE_UPDATE) && **(**Tu8)(__ccgo_up((*TSessionApplyCtx)(unsafe.Pointer(p)).FabPK + uintptr(i))) != 0 {
|
|
Xsqlite3changeset_old(tls, pIter, i, bp+8)
|
|
} else {
|
|
Xsqlite3changeset_new(tls, pIter, i, bp+8)
|
|
}
|
|
_sessionAppendValue(tls, p+104, **(**uintptr)(__ccgo_up(bp + 8)), bp)
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
return **(**int32)(__ccgo_up(bp))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Re-initialize table object pTab.
|
|
// */
|
|
func _sessionReinitTable(tls *libc.TLS, pSession uintptr, pTab uintptr) (r int32) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var a, v1 uintptr
|
|
var ii, nOldCol int32
|
|
var _ /* abPK at bp+32 */ uintptr
|
|
var _ /* aiIdx at bp+24 */ uintptr
|
|
var _ /* azCol at bp+8 */ uintptr
|
|
var _ /* azDflt at bp+16 */ uintptr
|
|
var _ /* bRowid at bp+40 */ int32
|
|
var _ /* nCol at bp+0 */ int32
|
|
var _ /* nTotalCol at bp+4 */ int32
|
|
_, _, _, _ = a, ii, nOldCol, v1
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
**(**int32)(__ccgo_up(bp + 4)) = 0
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = uintptr(0)
|
|
**(**uintptr)(__ccgo_up(bp + 16)) = uintptr(0)
|
|
**(**uintptr)(__ccgo_up(bp + 24)) = uintptr(0)
|
|
**(**uintptr)(__ccgo_up(bp + 32)) = uintptr(0)
|
|
**(**int32)(__ccgo_up(bp + 40)) = 0
|
|
if (*Tsqlite3_session)(unsafe.Pointer(pSession)).FbImplicitPK != 0 {
|
|
v1 = bp + 40
|
|
} else {
|
|
v1 = uintptr(0)
|
|
}
|
|
(*Tsqlite3_session)(unsafe.Pointer(pSession)).Frc = _sessionTableInfo(tls, pSession, (*Tsqlite3_session)(unsafe.Pointer(pSession)).Fdb, (*Tsqlite3_session)(unsafe.Pointer(pSession)).FzDb, (*TSessionTable)(unsafe.Pointer(pTab)).FzName, bp, bp+4, uintptr(0), bp+8, bp+16, bp+24, bp+32, v1)
|
|
if (*Tsqlite3_session)(unsafe.Pointer(pSession)).Frc == SQLITE_OK {
|
|
if (*TSessionTable)(unsafe.Pointer(pTab)).FnCol > **(**int32)(__ccgo_up(bp)) || (*TSessionTable)(unsafe.Pointer(pTab)).FbRowid != **(**int32)(__ccgo_up(bp + 40)) {
|
|
(*Tsqlite3_session)(unsafe.Pointer(pSession)).Frc = int32(SQLITE_SCHEMA)
|
|
} else {
|
|
nOldCol = (*TSessionTable)(unsafe.Pointer(pTab)).FnCol
|
|
ii = 0
|
|
for {
|
|
if !(ii < **(**int32)(__ccgo_up(bp))) {
|
|
break
|
|
}
|
|
if ii < (*TSessionTable)(unsafe.Pointer(pTab)).FnCol {
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TSessionTable)(unsafe.Pointer(pTab)).FabPK + uintptr(ii)))) != libc.Int32FromUint8(**(**Tu8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp + 32)) + uintptr(ii)))) {
|
|
(*Tsqlite3_session)(unsafe.Pointer(pSession)).Frc = int32(SQLITE_SCHEMA)
|
|
}
|
|
} else {
|
|
if **(**Tu8)(__ccgo_up(**(**uintptr)(__ccgo_up(bp + 32)) + uintptr(ii))) != 0 {
|
|
(*Tsqlite3_session)(unsafe.Pointer(pSession)).Frc = int32(SQLITE_SCHEMA)
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
if (*Tsqlite3_session)(unsafe.Pointer(pSession)).Frc == SQLITE_OK {
|
|
a = (*TSessionTable)(unsafe.Pointer(pTab)).FazCol
|
|
(*TSessionTable)(unsafe.Pointer(pTab)).FazCol = **(**uintptr)(__ccgo_up(bp + 8))
|
|
(*TSessionTable)(unsafe.Pointer(pTab)).FnCol = **(**int32)(__ccgo_up(bp))
|
|
(*TSessionTable)(unsafe.Pointer(pTab)).FnTotalCol = **(**int32)(__ccgo_up(bp + 4))
|
|
(*TSessionTable)(unsafe.Pointer(pTab)).FazDflt = **(**uintptr)(__ccgo_up(bp + 16))
|
|
(*TSessionTable)(unsafe.Pointer(pTab)).FabPK = **(**uintptr)(__ccgo_up(bp + 32))
|
|
(*TSessionTable)(unsafe.Pointer(pTab)).FaiIdx = **(**uintptr)(__ccgo_up(bp + 24))
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = a
|
|
}
|
|
if (*Tsqlite3_session)(unsafe.Pointer(pSession)).FbEnableSize != 0 {
|
|
**(**Ti64)(__ccgo_up(pSession + 64)) += int64(**(**int32)(__ccgo_up(bp)) - nOldCol)
|
|
**(**Ti64)(__ccgo_up(pSession + 64)) += int64(_sessionVarintLen(tls, **(**int32)(__ccgo_up(bp))))
|
|
**(**Ti64)(__ccgo_up(pSession + 64)) -= int64(_sessionVarintLen(tls, nOldCol))
|
|
}
|
|
}
|
|
}
|
|
Xsqlite3_free(tls, **(**uintptr)(__ccgo_up(bp + 8)))
|
|
return (*Tsqlite3_session)(unsafe.Pointer(pSession)).Frc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** SQL statement pSelect is as generated by the sessionSelectRow() function.
|
|
// ** This function binds the primary key values from the change that changeset
|
|
// ** iterator pIter points to to the SELECT and attempts to seek to the table
|
|
// ** entry. If a row is found, the SELECT statement left pointing at the row
|
|
// ** and SQLITE_ROW is returned. Otherwise, if no row is found and no error
|
|
// ** has occured, the statement is reset and SQLITE_OK is returned. If an
|
|
// ** error occurs, the statement is reset and an SQLite error code is returned.
|
|
// **
|
|
// ** If this function returns SQLITE_ROW, the caller must eventually reset()
|
|
// ** statement pSelect. If any other value is returned, the statement does
|
|
// ** not require a reset().
|
|
// **
|
|
// ** If the iterator currently points to an INSERT record, bind values from the
|
|
// ** new.* record to the SELECT statement. Or, if it points to a DELETE or
|
|
// ** UPDATE, bind values from the old.* record.
|
|
// */
|
|
func _sessionSeekToRow(tls *libc.TLS, pIter uintptr, p uintptr) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var ii, rc int32
|
|
var pSelect, v1 uintptr
|
|
var _ /* nCol at bp+0 */ int32
|
|
var _ /* op at bp+4 */ int32
|
|
var _ /* pVal at bp+16 */ uintptr
|
|
var _ /* zDummy at bp+8 */ uintptr
|
|
_, _, _, _ = ii, pSelect, rc, v1
|
|
pSelect = (*TSessionApplyCtx)(unsafe.Pointer(p)).FpSelect /* Unused */
|
|
Xsqlite3_clear_bindings(tls, pSelect)
|
|
Xsqlite3changeset_op(tls, pIter, bp+8, bp, bp+4, uintptr(0))
|
|
if **(**int32)(__ccgo_up(bp + 4)) == int32(SQLITE_INSERT) {
|
|
v1 = __ccgo_fp(Xsqlite3changeset_new)
|
|
} else {
|
|
v1 = __ccgo_fp(Xsqlite3changeset_old)
|
|
}
|
|
rc = _sessionBindRow(tls, pIter, v1, **(**int32)(__ccgo_up(bp)), (*TSessionApplyCtx)(unsafe.Pointer(p)).FabPK, pSelect)
|
|
if **(**int32)(__ccgo_up(bp + 4)) != int32(SQLITE_DELETE) && (*TSessionApplyCtx)(unsafe.Pointer(p)).FbIgnoreNoop != 0 {
|
|
ii = 0
|
|
for {
|
|
if !(rc == SQLITE_OK && ii < **(**int32)(__ccgo_up(bp))) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TSessionApplyCtx)(unsafe.Pointer(p)).FabPK + uintptr(ii)))) == 0 {
|
|
**(**uintptr)(__ccgo_up(bp + 16)) = uintptr(0)
|
|
Xsqlite3changeset_new(tls, pIter, ii, bp+16)
|
|
Xsqlite3_bind_int(tls, pSelect, ii+int32(1)+**(**int32)(__ccgo_up(bp)), libc.BoolInt32(**(**uintptr)(__ccgo_up(bp + 16)) == uintptr(0)))
|
|
if **(**uintptr)(__ccgo_up(bp + 16)) != 0 {
|
|
rc = _sessionBindValue(tls, pSelect, ii+int32(1), **(**uintptr)(__ccgo_up(bp + 16)))
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
}
|
|
if rc == SQLITE_OK {
|
|
rc = Xsqlite3_step(tls, pSelect)
|
|
if rc != int32(SQLITE_ROW) {
|
|
rc = Xsqlite3_reset(tls, pSelect)
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Table pTab has one or more existing change-records with old.* records
|
|
// ** with fewer than pTab->nCol columns. This function updates all such
|
|
// ** change-records with the default values for the missing columns.
|
|
// */
|
|
func _sessionUpdateChanges(tls *libc.TLS, pSession uintptr, pTab uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var ii int32
|
|
var pp uintptr
|
|
var _ /* pStmt at bp+0 */ uintptr
|
|
var _ /* rc at bp+8 */ int32
|
|
_, _ = ii, pp
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
**(**int32)(__ccgo_up(bp + 8)) = (*Tsqlite3_session)(unsafe.Pointer(pSession)).Frc
|
|
**(**int32)(__ccgo_up(bp + 8)) = _sessionPrepareDfltStmt(tls, (*Tsqlite3_session)(unsafe.Pointer(pSession)).Fdb, pTab, bp)
|
|
if **(**int32)(__ccgo_up(bp + 8)) == SQLITE_OK && int32(SQLITE_ROW) == Xsqlite3_step(tls, **(**uintptr)(__ccgo_up(bp))) {
|
|
ii = 0
|
|
pp = uintptr(0)
|
|
ii = 0
|
|
for {
|
|
if !(ii < (*TSessionTable)(unsafe.Pointer(pTab)).FnChange) {
|
|
break
|
|
}
|
|
pp = (*TSessionTable)(unsafe.Pointer(pTab)).FapChange + uintptr(ii)*8
|
|
for {
|
|
if !(**(**uintptr)(__ccgo_up(pp)) != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint16((*TSessionChange)(unsafe.Pointer(**(**uintptr)(__ccgo_up(pp)))).FnRecordField) != (*TSessionTable)(unsafe.Pointer(pTab)).FnCol {
|
|
_sessionUpdateOneChange(tls, pSession, bp+8, pp, (*TSessionTable)(unsafe.Pointer(pTab)).FnCol, **(**uintptr)(__ccgo_up(bp)))
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
pp = **(**uintptr)(__ccgo_up(pp)) + 24
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
}
|
|
_sessionFinalizeStmt(tls, **(**uintptr)(__ccgo_up(bp)), bp+8)
|
|
(*Tsqlite3_session)(unsafe.Pointer(pSession)).Frc = **(**int32)(__ccgo_up(bp + 8))
|
|
return (*Tsqlite3_session)(unsafe.Pointer(pSession)).Frc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /**************************** sqlite3_result_ *******************************
|
|
// ** The following routines are used by user-defined functions to specify
|
|
// ** the function result.
|
|
// **
|
|
// ** The setStrOrError() function calls sqlite3VdbeMemSetStr() to store the
|
|
// ** result as a string or blob. Appropriate errors are set if the string/blob
|
|
// ** is too big or if an OOM occurs.
|
|
// **
|
|
// ** The invokeValueDestructor(P,X) routine invokes destructor function X()
|
|
// ** on value P if P is not going to be used and need to be destroyed.
|
|
// */
|
|
func _setResultStrOrError(tls *libc.TLS, pCtx uintptr, z uintptr, n int32, enc Tu8, __ccgo_fp_xDel uintptr) {
|
|
var pOut, v1 uintptr
|
|
var rc int32
|
|
_, _, _ = pOut, rc, v1
|
|
pOut = (*Tsqlite3_context)(unsafe.Pointer(pCtx)).FpOut
|
|
if libc.Int32FromUint8(enc) == int32(SQLITE_UTF8) {
|
|
rc = _sqlite3VdbeMemSetText(tls, pOut, z, int64(n), __ccgo_fp_xDel)
|
|
} else {
|
|
if libc.Int32FromUint8(enc) == int32(SQLITE_UTF8_ZT) {
|
|
/* It is usually considered improper to assert() on an input. However,
|
|
** the following assert() is checking for inputs that are documented
|
|
** to result in undefined behavior. */
|
|
rc = _sqlite3VdbeMemSetText(tls, pOut, z, int64(n), __ccgo_fp_xDel)
|
|
v1 = pOut + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(MEM_Term))
|
|
} else {
|
|
rc = _sqlite3VdbeMemSetStr(tls, pOut, z, int64(n), enc, __ccgo_fp_xDel)
|
|
}
|
|
}
|
|
if rc != 0 {
|
|
if rc == int32(SQLITE_TOOBIG) {
|
|
Xsqlite3_result_error_toobig(tls, pCtx)
|
|
} else {
|
|
/* The only errors possible from sqlite3VdbeMemSetStr are
|
|
** SQLITE_TOOBIG and SQLITE_NOMEM */
|
|
Xsqlite3_result_error_nomem(tls, pCtx)
|
|
}
|
|
return
|
|
}
|
|
_sqlite3VdbeChangeEncoding(tls, pOut, libc.Int32FromUint8((*Tsqlite3_context)(unsafe.Pointer(pCtx)).Fenc))
|
|
if _sqlite3VdbeMemTooBig(tls, pOut) != 0 {
|
|
Xsqlite3_result_error_toobig(tls, pCtx)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add a lock on the table with root-page iTable to the shared-btree used
|
|
// ** by Btree handle p. Parameter eLock must be either READ_LOCK or
|
|
// ** WRITE_LOCK.
|
|
// **
|
|
// ** This function assumes the following:
|
|
// **
|
|
// ** (a) The specified Btree object p is connected to a sharable
|
|
// ** database (one with the BtShared.sharable flag set), and
|
|
// **
|
|
// ** (b) No other Btree objects hold a lock that conflicts
|
|
// ** with the requested lock (i.e. querySharedCacheTableLock() has
|
|
// ** already been called and returned SQLITE_OK).
|
|
// **
|
|
// ** SQLITE_OK is returned if the lock is added successfully. SQLITE_NOMEM
|
|
// ** is returned if a malloc attempt fails.
|
|
// */
|
|
func _setSharedCacheTableLock(tls *libc.TLS, p uintptr, iTable TPgno, eLock Tu8) (r int32) {
|
|
var pBt, pIter, pLock uintptr
|
|
_, _, _ = pBt, pIter, pLock
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt
|
|
pLock = uintptr(0)
|
|
/* A connection with the read-uncommitted flag set will never try to
|
|
** obtain a read-lock using this function. The only read-lock obtained
|
|
** by a connection in read-uncommitted mode is on the sqlite_schema
|
|
** table, and that lock is obtained in BtreeBeginTrans(). */
|
|
/* This function should only be called on a sharable b-tree after it
|
|
** has been determined that no other b-tree holds a conflicting lock. */
|
|
/* First search the list for an existing lock on this table. */
|
|
pIter = (*TBtShared)(unsafe.Pointer(pBt)).FpLock
|
|
for {
|
|
if !(pIter != 0) {
|
|
break
|
|
}
|
|
if (*TBtLock)(unsafe.Pointer(pIter)).FiTable == iTable && (*TBtLock)(unsafe.Pointer(pIter)).FpBtree == p {
|
|
pLock = pIter
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
pIter = (*TBtLock)(unsafe.Pointer(pIter)).FpNext
|
|
}
|
|
/* If the above search did not find a BtLock struct associating Btree p
|
|
** with table iTable, allocate one and link it into the list.
|
|
*/
|
|
if !(pLock != 0) {
|
|
pLock = _sqlite3MallocZero(tls, uint64(24))
|
|
if !(pLock != 0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
(*TBtLock)(unsafe.Pointer(pLock)).FiTable = iTable
|
|
(*TBtLock)(unsafe.Pointer(pLock)).FpBtree = p
|
|
(*TBtLock)(unsafe.Pointer(pLock)).FpNext = (*TBtShared)(unsafe.Pointer(pBt)).FpLock
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FpLock = pLock
|
|
}
|
|
/* Set the BtLock.eLock variable to the maximum of the current lock
|
|
** and the requested lock. This means if a write-lock was already held
|
|
** and a read-lock requested, we don't incorrectly downgrade the lock.
|
|
*/
|
|
if libc.Int32FromUint8(eLock) > libc.Int32FromUint8((*TBtLock)(unsafe.Pointer(pLock)).FeLock) {
|
|
(*TBtLock)(unsafe.Pointer(pLock)).FeLock = eLock
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set up the lookaside buffers for a database connection.
|
|
// ** Return SQLITE_OK on success.
|
|
// ** If lookaside is already active, return SQLITE_BUSY.
|
|
// **
|
|
// ** The sz parameter is the number of bytes in each lookaside slot.
|
|
// ** The cnt parameter is the number of slots. If pBuf is NULL the
|
|
// ** space for the lookaside memory is obtained from sqlite3_malloc()
|
|
// ** or similar. If pBuf is not NULL then it is sz*cnt bytes of memory
|
|
// ** to use for the lookaside memory.
|
|
// */
|
|
func _setupLookaside(tls *libc.TLS, db uintptr, pBuf uintptr, sz int32, cnt int32) (r int32) {
|
|
var i, nBig, nSm, v1 int32
|
|
var p, pStart uintptr
|
|
var szAlloc Tsqlite3_int64
|
|
_, _, _, _, _, _, _ = i, nBig, nSm, p, pStart, szAlloc, v1 /* Number smaller LOOKASIDE_SMALL-byte slots */
|
|
if _sqlite3LookasideUsed(tls, db, uintptr(0)) > 0 {
|
|
return int32(SQLITE_BUSY)
|
|
}
|
|
/* Free any existing lookaside buffer for this handle before
|
|
** allocating a new one so we don't have to have space for
|
|
** both at the same time.
|
|
*/
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FbMalloced != 0 {
|
|
Xsqlite3_free(tls, (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpStart)
|
|
}
|
|
/* The size of a lookaside slot after ROUNDDOWN8 needs to be larger
|
|
** than a pointer and small enough to fit in a u16.
|
|
*/
|
|
sz = sz & ^libc.Int32FromInt32(7)
|
|
if sz <= libc.Int32FromInt64(8) {
|
|
sz = 0
|
|
}
|
|
if sz > int32(65528) {
|
|
sz = int32(65528)
|
|
}
|
|
/* Count must be at least 1 to be useful, but not so large as to use
|
|
** more than 0x7fff0000 total bytes for lookaside. */
|
|
if cnt < int32(1) {
|
|
cnt = 0
|
|
}
|
|
if sz > 0 && cnt > int32(0x7fff0000)/sz {
|
|
cnt = int32(0x7fff0000) / sz
|
|
}
|
|
szAlloc = int64(sz) * int64(cnt)
|
|
if szAlloc == 0 {
|
|
sz = 0
|
|
pStart = uintptr(0)
|
|
} else {
|
|
if pBuf == uintptr(0) {
|
|
_sqlite3BeginBenignMalloc(tls)
|
|
pStart = _sqlite3Malloc(tls, libc.Uint64FromInt64(szAlloc))
|
|
_sqlite3EndBenignMalloc(tls)
|
|
if pStart != 0 {
|
|
szAlloc = int64(_sqlite3MallocSize(tls, pStart))
|
|
}
|
|
} else {
|
|
pStart = pBuf
|
|
}
|
|
}
|
|
if sz >= libc.Int32FromInt32(LOOKASIDE_SMALL)*libc.Int32FromInt32(3) {
|
|
nBig = int32(szAlloc / int64(libc.Int32FromInt32(3)*libc.Int32FromInt32(LOOKASIDE_SMALL)+sz))
|
|
nSm = int32((szAlloc - int64(sz)*int64(nBig)) / int64(LOOKASIDE_SMALL))
|
|
} else {
|
|
if sz >= libc.Int32FromInt32(LOOKASIDE_SMALL)*libc.Int32FromInt32(2) {
|
|
nBig = int32(szAlloc / int64(libc.Int32FromInt32(LOOKASIDE_SMALL)+sz))
|
|
nSm = int32((szAlloc - int64(sz)*int64(nBig)) / int64(LOOKASIDE_SMALL))
|
|
} else {
|
|
if sz > 0 {
|
|
nBig = int32(szAlloc / int64(sz))
|
|
nSm = 0
|
|
} else {
|
|
v1 = libc.Int32FromInt32(0)
|
|
nSm = v1
|
|
nBig = v1
|
|
}
|
|
}
|
|
}
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpStart = pStart
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpInit = uintptr(0)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpFree = uintptr(0)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.Fsz = libc.Uint16FromInt32(sz)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FszTrue = libc.Uint16FromInt32(sz)
|
|
if pStart != 0 {
|
|
p = pStart
|
|
i = 0
|
|
for {
|
|
if !(i < nBig) {
|
|
break
|
|
}
|
|
(*TLookasideSlot)(unsafe.Pointer(p)).FpNext = (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpInit
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpInit = p
|
|
p = p + uintptr(sz)
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpSmallInit = uintptr(0)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpSmallFree = uintptr(0)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpMiddle = p
|
|
i = 0
|
|
for {
|
|
if !(i < nSm) {
|
|
break
|
|
}
|
|
(*TLookasideSlot)(unsafe.Pointer(p)).FpNext = (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpSmallInit
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpSmallInit = p
|
|
p = p + 128
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = i + 1
|
|
}
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpEnd = p
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FbDisable = uint32(0)
|
|
if pBuf == uintptr(0) {
|
|
v1 = int32(1)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FbMalloced = libc.Uint8FromInt32(v1)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FnSlot = libc.Uint32FromInt32(nBig + nSm)
|
|
} else {
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpStart = uintptr(0)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpSmallInit = uintptr(0)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpSmallFree = uintptr(0)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpMiddle = uintptr(0)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpEnd = uintptr(0)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FbDisable = uint32(1)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.Fsz = uint16(0)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FbMalloced = uint8(0)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FnSlot = uint32(0)
|
|
}
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpTrueEnd = (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpEnd
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the collation function of the most recently parsed table column
|
|
// ** to the CollSeq given.
|
|
// */
|
|
func _sqlite3AddCollateType(tls *libc.TLS, pParse uintptr, pToken uintptr) {
|
|
var db, p, pIdx, zColl, v1 uintptr
|
|
var i int32
|
|
_, _, _, _, _, _ = db, i, p, pIdx, zColl, v1
|
|
v1 = (*TParse)(unsafe.Pointer(pParse)).FpNewTable
|
|
p = v1
|
|
if v1 == uintptr(0) || libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) >= int32(PARSE_MODE_RENAME) {
|
|
return
|
|
}
|
|
i = int32((*TTable)(unsafe.Pointer(p)).FnCol) - int32(1)
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
zColl = _sqlite3NameFromToken(tls, db, pToken)
|
|
if !(zColl != 0) {
|
|
return
|
|
}
|
|
if _sqlite3LocateCollSeq(tls, pParse, zColl) != 0 {
|
|
_sqlite3ColumnSetColl(tls, db, (*TTable)(unsafe.Pointer(p)).FaCol+uintptr(i)*16, zColl)
|
|
/* If the column is declared as "<name> PRIMARY KEY COLLATE <type>",
|
|
** then an index may have been created on this column before the
|
|
** collation type was added. Correct this if it is the case.
|
|
*/
|
|
pIdx = (*TTable)(unsafe.Pointer(p)).FpIndex
|
|
for {
|
|
if !(pIdx != 0) {
|
|
break
|
|
}
|
|
if int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn))) == i {
|
|
**(**uintptr)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FazColl)) = _sqlite3ColumnColl(tls, (*TTable)(unsafe.Pointer(p)).FaCol+uintptr(i)*16)
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
pIdx = (*TIndex)(unsafe.Pointer(pIdx)).FpNext
|
|
}
|
|
}
|
|
_sqlite3DbFree(tls, db, zColl)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine is called by the parser while in the middle of
|
|
// ** parsing a CREATE TABLE statement. A "NOT NULL" constraint has
|
|
// ** been seen on a column. This routine sets the notNull flag on
|
|
// ** the column currently under construction.
|
|
// */
|
|
func _sqlite3AddNotNull(tls *libc.TLS, pParse uintptr, onError int32) {
|
|
var p, pCol, pIdx uintptr
|
|
_, _, _ = p, pCol, pIdx
|
|
p = (*TParse)(unsafe.Pointer(pParse)).FpNewTable
|
|
if p == uintptr(0) || int32((*TTable)(unsafe.Pointer(p)).FnCol) < int32(1) {
|
|
return
|
|
}
|
|
pCol = (*TTable)(unsafe.Pointer(p)).FaCol + uintptr(int32((*TTable)(unsafe.Pointer(p)).FnCol)-int32(1))*16
|
|
libc.SetBitFieldPtr8Uint32(pCol+8, uint32(libc.Uint8FromInt32(onError)), 0, 0xf)
|
|
**(**Tu32)(__ccgo_up(p + 48)) |= uint32(TF_HasNotNull)
|
|
/* Set the uniqNotNull flag on any UNIQUE or PK indexes already created
|
|
** on this column. */
|
|
if libc.Int32FromUint16((*TColumn)(unsafe.Pointer(pCol)).FcolFlags)&int32(COLFLAG_UNIQUE) != 0 {
|
|
pIdx = (*TTable)(unsafe.Pointer(p)).FpIndex
|
|
for {
|
|
if !(pIdx != 0) {
|
|
break
|
|
}
|
|
if int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn))) == int32((*TTable)(unsafe.Pointer(p)).FnCol)-int32(1) {
|
|
libc.SetBitFieldPtr16Uint32(pIdx+100, libc.Uint32FromInt32(1), 3, 0x8)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
pIdx = (*TIndex)(unsafe.Pointer(pIdx)).FpNext
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate heap space to hold an Index object with nCol columns.
|
|
// **
|
|
// ** Increase the allocation size to provide an extra nExtra bytes
|
|
// ** of 8-byte aligned space after the Index object and return a
|
|
// ** pointer to this extra space in *ppExtra.
|
|
// */
|
|
func _sqlite3AllocateIndexObject(tls *libc.TLS, db uintptr, nCol int32, nExtra int32, ppExtra uintptr) (r uintptr) {
|
|
var nByte Ti64
|
|
var p, pExtra uintptr
|
|
_, _, _ = nByte, p, pExtra /* Bytes of space for Index object + arrays */
|
|
nByte = libc.Int64FromUint64((libc.Uint64FromInt64(160)+libc.Uint64FromInt32(7))&libc.Uint64FromInt32(^libc.Int32FromInt32(7)) + (uint64(8)*libc.Uint64FromInt32(nCol)+uint64(7))&libc.Uint64FromInt32(^libc.Int32FromInt32(7)) + (uint64(2)*libc.Uint64FromInt32(nCol+libc.Int32FromInt32(1))+uint64(2)*libc.Uint64FromInt32(nCol)+uint64(1)*libc.Uint64FromInt32(nCol)+uint64(7))&libc.Uint64FromInt32(^libc.Int32FromInt32(7))) /* Index.aSortOrder */
|
|
p = _sqlite3DbMallocZero(tls, db, libc.Uint64FromInt64(nByte+int64(nExtra)))
|
|
if p != 0 {
|
|
pExtra = p + uintptr((libc.Uint64FromInt64(160)+libc.Uint64FromInt32(7))&libc.Uint64FromInt32(^libc.Int32FromInt32(7)))
|
|
(*TIndex)(unsafe.Pointer(p)).FazColl = pExtra
|
|
pExtra = pExtra + uintptr((libc.Uint64FromInt64(8)*libc.Uint64FromInt32(nCol)+libc.Uint64FromInt32(7))&libc.Uint64FromInt32(^libc.Int32FromInt32(7)))
|
|
(*TIndex)(unsafe.Pointer(p)).FaiRowLogEst = pExtra
|
|
pExtra = pExtra + uintptr(uint64(2)*libc.Uint64FromInt32(nCol+libc.Int32FromInt32(1)))
|
|
(*TIndex)(unsafe.Pointer(p)).FaiColumn = pExtra
|
|
pExtra = pExtra + uintptr(uint64(2)*libc.Uint64FromInt32(nCol))
|
|
(*TIndex)(unsafe.Pointer(p)).FaSortOrder = pExtra
|
|
(*TIndex)(unsafe.Pointer(p)).FnColumn = libc.Uint16FromInt32(nCol)
|
|
(*TIndex)(unsafe.Pointer(p)).FnKeyCol = libc.Uint16FromInt32(nCol - libc.Int32FromInt32(1))
|
|
**(**uintptr)(__ccgo_up(ppExtra)) = p + uintptr(nByte)
|
|
}
|
|
return p
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Register built-in functions used to help implement ALTER TABLE
|
|
// */
|
|
func _sqlite3AlterFunctions(tls *libc.TLS) {
|
|
_sqlite3InsertBuiltinFuncs(tls, uintptr(unsafe.Pointer(&_aAlterTableFuncs)), libc.Int32FromUint64(libc.Uint64FromInt64(648)/libc.Uint64FromInt64(72)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code for the ANALYZE command. The parser calls this routine
|
|
// ** when it recognizes an ANALYZE command.
|
|
// **
|
|
// ** ANALYZE -- 1
|
|
// ** ANALYZE <database> -- 2
|
|
// ** ANALYZE ?<database>.?<tablename> -- 3
|
|
// **
|
|
// ** Form 1 causes all indices in all attached databases to be analyzed.
|
|
// ** Form 2 analyzes all indices the single database named.
|
|
// ** Form 3 analyzes all indices associated with the named table.
|
|
// */
|
|
func _sqlite3Analyze(tls *libc.TLS, pParse uintptr, pName1 uintptr, pName2 uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var db, pIdx, pTab, v, z, zDb, v4 uintptr
|
|
var i, iDb, v2 int32
|
|
var v3 bool
|
|
var _ /* pTableName at bp+0 */ uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _ = db, i, iDb, pIdx, pTab, v, z, zDb, v2, v3, v4
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
/* Read the database schema. If an error occurs, leave an error message
|
|
** and code in pParse and return NULL. */
|
|
if SQLITE_OK != _sqlite3ReadSchema(tls, pParse) {
|
|
return
|
|
}
|
|
if pName1 == uintptr(0) {
|
|
/* Form 1: Analyze everything */
|
|
i = 0
|
|
for {
|
|
if !(i < (*Tsqlite3)(unsafe.Pointer(db)).FnDb) {
|
|
break
|
|
}
|
|
if i == int32(1) {
|
|
goto _1
|
|
} /* Do not analyze the TEMP database */
|
|
_analyzeDatabase(tls, pParse, i)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
} else {
|
|
if v3 = (*TToken)(unsafe.Pointer(pName2)).Fn == uint32(0); v3 {
|
|
v2 = _sqlite3FindDb(tls, db, pName1)
|
|
iDb = v2
|
|
}
|
|
if v3 && v2 >= 0 {
|
|
/* Analyze the schema named as the argument */
|
|
_analyzeDatabase(tls, pParse, iDb)
|
|
} else {
|
|
/* Form 3: Analyze the table or index named as an argument */
|
|
iDb = _sqlite3TwoPartName(tls, pParse, pName1, pName2, bp)
|
|
if iDb >= 0 {
|
|
if (*TToken)(unsafe.Pointer(pName2)).Fn != 0 {
|
|
v4 = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(iDb)*32))).FzDbSName
|
|
} else {
|
|
v4 = uintptr(0)
|
|
}
|
|
zDb = v4
|
|
z = _sqlite3NameFromToken(tls, db, **(**uintptr)(__ccgo_up(bp)))
|
|
if z != 0 {
|
|
v4 = _sqlite3FindIndex(tls, db, z, zDb)
|
|
pIdx = v4
|
|
if v4 != uintptr(0) {
|
|
_analyzeTable(tls, pParse, (*TIndex)(unsafe.Pointer(pIdx)).FpTable, pIdx)
|
|
} else {
|
|
v4 = _sqlite3LocateTable(tls, pParse, uint32(0), z, zDb)
|
|
pTab = v4
|
|
if v4 != uintptr(0) {
|
|
_analyzeTable(tls, pParse, pTab, uintptr(0))
|
|
}
|
|
}
|
|
_sqlite3DbFree(tls, db, z)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if v3 = libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).FnSqlExec) == 0; v3 {
|
|
v4 = _sqlite3GetVdbe(tls, pParse)
|
|
v = v4
|
|
}
|
|
if v3 && v4 != uintptr(0) {
|
|
_sqlite3VdbeAddOp0(tls, v, int32(OP_Expire))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine generates code that will initialize all of the
|
|
// ** register used by the autoincrement tracker.
|
|
// */
|
|
func _sqlite3AutoincrementBegin(tls *libc.TLS, pParse uintptr) {
|
|
var aOp, db, p, pDb, v uintptr
|
|
var memId int32
|
|
_, _, _, _, _, _ = aOp, db, memId, p, pDb, v /* Information about an AUTOINCREMENT */
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb /* Register holding max rowid */
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe /* VDBE under construction */
|
|
/* This routine is never called during trigger-generation. It is
|
|
** only called from the top-level */
|
|
/* We failed long ago if this is not so */
|
|
p = (*TParse)(unsafe.Pointer(pParse)).FpAinc
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
pDb = (*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr((*TAutoincInfo)(unsafe.Pointer(p)).FiDb)*32
|
|
memId = (*TAutoincInfo)(unsafe.Pointer(p)).FregCtr
|
|
_sqlite3OpenTable(tls, pParse, 0, (*TAutoincInfo)(unsafe.Pointer(p)).FiDb, (*TSchema)(unsafe.Pointer((*TDb)(unsafe.Pointer(pDb)).FpSchema)).FpSeqTab, int32(OP_OpenRead))
|
|
_sqlite3VdbeLoadString(tls, v, memId-int32(1), (*TTable)(unsafe.Pointer((*TAutoincInfo)(unsafe.Pointer(p)).FpTab)).FzName)
|
|
aOp = _sqlite3VdbeAddOpList(tls, v, libc.Int32FromUint64(libc.Uint64FromInt64(48)/libc.Uint64FromInt64(4)), uintptr(unsafe.Pointer(&_autoInc)), _iLn1)
|
|
if aOp == uintptr(0) {
|
|
break
|
|
}
|
|
(**(**TVdbeOp)(__ccgo_up(aOp))).Fp2 = memId
|
|
(**(**TVdbeOp)(__ccgo_up(aOp))).Fp3 = memId + int32(2)
|
|
(**(**TVdbeOp)(__ccgo_up(aOp + 2*24))).Fp3 = memId
|
|
(**(**TVdbeOp)(__ccgo_up(aOp + 3*24))).Fp1 = memId - int32(1)
|
|
(**(**TVdbeOp)(__ccgo_up(aOp + 3*24))).Fp3 = memId
|
|
(**(**TVdbeOp)(__ccgo_up(aOp + 3*24))).Fp5 = uint16(SQLITE_JUMPIFNULL)
|
|
(**(**TVdbeOp)(__ccgo_up(aOp + 4*24))).Fp2 = memId + int32(1)
|
|
(**(**TVdbeOp)(__ccgo_up(aOp + 5*24))).Fp3 = memId
|
|
(**(**TVdbeOp)(__ccgo_up(aOp + 6*24))).Fp1 = memId
|
|
(**(**TVdbeOp)(__ccgo_up(aOp + 7*24))).Fp2 = memId + int32(2)
|
|
(**(**TVdbeOp)(__ccgo_up(aOp + 7*24))).Fp1 = memId
|
|
(**(**TVdbeOp)(__ccgo_up(aOp + 10*24))).Fp2 = memId
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnTab == 0 {
|
|
(*TParse)(unsafe.Pointer(pParse)).FnTab = int32(1)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = (*TAutoincInfo)(unsafe.Pointer(p)).FpNext
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Check to see if the i-th bit is set. Return true or false.
|
|
// ** If p is NULL (if the bitmap has not been created) or if
|
|
// ** i is out of range, then return false.
|
|
// */
|
|
func _sqlite3BitvecTestNotNull(tls *libc.TLS, p uintptr, i Tu32) (r int32) {
|
|
var bin, h, v1 Tu32
|
|
_, _, _ = bin, h, v1
|
|
i = i - 1
|
|
if i >= (*TBitvec)(unsafe.Pointer(p)).FiSize {
|
|
return 0
|
|
}
|
|
for (*TBitvec)(unsafe.Pointer(p)).FiDivisor != 0 {
|
|
bin = i / (*TBitvec)(unsafe.Pointer(p)).FiDivisor
|
|
i = i % (*TBitvec)(unsafe.Pointer(p)).FiDivisor
|
|
p = **(**uintptr)(__ccgo_up(p + 16 + uintptr(bin)*8))
|
|
if !(p != 0) {
|
|
return 0
|
|
}
|
|
}
|
|
if uint64((*TBitvec)(unsafe.Pointer(p)).FiSize) <= (libc.Uint64FromInt32(BITVEC_SZ)-libc.Uint64FromInt32(3)*libc.Uint64FromInt64(4))/libc.Uint64FromInt64(8)*libc.Uint64FromInt64(8)/libc.Uint64FromInt64(1)*libc.Uint64FromInt32(BITVEC_SZELEM) {
|
|
return libc.BoolInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(p + 16 + uintptr(i/uint32(BITVEC_SZELEM)))))&(int32(1)<<(i&libc.Uint32FromInt32(libc.Int32FromInt32(BITVEC_SZELEM)-libc.Int32FromInt32(1)))) != 0)
|
|
} else {
|
|
v1 = i
|
|
i = i + 1
|
|
h = uint32(uint64(v1*libc.Uint32FromInt32(1)) % ((libc.Uint64FromInt32(BITVEC_SZ) - libc.Uint64FromInt32(3)*libc.Uint64FromInt64(4)) / libc.Uint64FromInt64(8) * libc.Uint64FromInt64(8) / libc.Uint64FromInt64(4)))
|
|
for **(**Tu32)(__ccgo_up(p + 16 + uintptr(h)*4)) != 0 {
|
|
if **(**Tu32)(__ccgo_up(p + 16 + uintptr(h)*4)) == i {
|
|
return int32(1)
|
|
}
|
|
h = uint32(uint64(h+libc.Uint32FromInt32(1)) % ((libc.Uint64FromInt32(BITVEC_SZ) - libc.Uint64FromInt32(3)*libc.Uint64FromInt64(4)) / libc.Uint64FromInt64(8) * libc.Uint64FromInt64(8) / libc.Uint64FromInt64(4)))
|
|
}
|
|
return 0
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compare two blobs. Return negative, zero, or positive if the first
|
|
// ** is less than, equal to, or greater than the second, respectively.
|
|
// ** If one blob is a prefix of the other, then the shorter is the lessor.
|
|
// */
|
|
func _sqlite3BlobCompare(tls *libc.TLS, pB1 uintptr, pB2 uintptr) (r int32) {
|
|
var c, n1, n2, v1 int32
|
|
_, _, _, _ = c, n1, n2, v1
|
|
n1 = (*TMem)(unsafe.Pointer(pB1)).Fn
|
|
n2 = (*TMem)(unsafe.Pointer(pB2)).Fn
|
|
/* It is possible to have a Blob value that has some non-zero content
|
|
** followed by zero content. But that only comes up for Blobs formed
|
|
** by the OP_MakeRecord opcode, and such Blobs never get passed into
|
|
** sqlite3MemCompare(). */
|
|
if (libc.Int32FromUint16((*TMem)(unsafe.Pointer(pB1)).Fflags)|libc.Int32FromUint16((*TMem)(unsafe.Pointer(pB2)).Fflags))&int32(MEM_Zero) != 0 {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pB1)).Fflags)&libc.Int32FromUint16((*TMem)(unsafe.Pointer(pB2)).Fflags)&int32(MEM_Zero) != 0 {
|
|
return *(*int32)(unsafe.Pointer(&(*TMem)(unsafe.Pointer(pB1)).Fu)) - *(*int32)(unsafe.Pointer(&(*TMem)(unsafe.Pointer(pB2)).Fu))
|
|
} else {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pB1)).Fflags)&int32(MEM_Zero) != 0 {
|
|
if !(_isAllZero(tls, (*TMem)(unsafe.Pointer(pB2)).Fz, (*TMem)(unsafe.Pointer(pB2)).Fn) != 0) {
|
|
return -int32(1)
|
|
}
|
|
return *(*int32)(unsafe.Pointer(&(*TMem)(unsafe.Pointer(pB1)).Fu)) - n2
|
|
} else {
|
|
if !(_isAllZero(tls, (*TMem)(unsafe.Pointer(pB1)).Fz, (*TMem)(unsafe.Pointer(pB1)).Fn) != 0) {
|
|
return +libc.Int32FromInt32(1)
|
|
}
|
|
return n1 - *(*int32)(unsafe.Pointer(&(*TMem)(unsafe.Pointer(pB2)).Fu))
|
|
}
|
|
}
|
|
}
|
|
if n1 > n2 {
|
|
v1 = n2
|
|
} else {
|
|
v1 = n1
|
|
}
|
|
c = libc.Xmemcmp(tls, (*TMem)(unsafe.Pointer(pB1)).Fz, (*TMem)(unsafe.Pointer(pB2)).Fz, libc.Uint64FromInt32(v1))
|
|
if c != 0 {
|
|
return c
|
|
}
|
|
return n1 - n2
|
|
}
|
|
|
|
/* The following two functions are used only within testcase() to prove
|
|
** test coverage. These functions do no exist for production builds.
|
|
** We must use separate SQLITE_NOINLINE functions here, since otherwise
|
|
** optimizer code movement causes gcov to become very confused.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the size of a BtCursor object in bytes.
|
|
// **
|
|
// ** This interfaces is needed so that users of cursors can preallocate
|
|
// ** sufficient storage to hold a cursor. The BtCursor object is opaque
|
|
// ** to users so they cannot do the sizeof() themselves - they must call
|
|
// ** this routine.
|
|
// */
|
|
func _sqlite3BtreeCursorSize(tls *libc.TLS) (r int32) {
|
|
return libc.Int32FromUint64((libc.Uint64FromInt64(296) + libc.Uint64FromInt32(7)) & libc.Uint64FromInt32(^libc.Int32FromInt32(7)))
|
|
}
|
|
|
|
func _sqlite3BtreeNext(tls *libc.TLS, pCur uintptr, flags int32) (r int32) {
|
|
var pPage, v1 uintptr
|
|
var v2 Tu16
|
|
_, _, _ = pPage, v1, v2
|
|
_ = flags /* Used in COMDB2 but not native SQLite */
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FnSize = uint16(0)
|
|
v1 = pCur + 1
|
|
*(*Tu8)(unsafe.Pointer(v1)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v1))) & ^(libc.Int32FromInt32(BTCF_ValidNKey) | libc.Int32FromInt32(BTCF_ValidOvfl)))
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) != CURSOR_VALID {
|
|
return _btreeNext(tls, pCur)
|
|
}
|
|
pPage = (*TBtCursor)(unsafe.Pointer(pCur)).FpPage
|
|
v1 = pCur + 86
|
|
*(*Tu16)(unsafe.Pointer(v1)) = *(*Tu16)(unsafe.Pointer(v1)) + 1
|
|
v2 = *(*Tu16)(unsafe.Pointer(v1))
|
|
if libc.Int32FromUint16(v2) >= libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(pPage)).FnCell) {
|
|
(*TBtCursor)(unsafe.Pointer(pCur)).Fix = (*TBtCursor)(unsafe.Pointer(pCur)).Fix - 1
|
|
return _btreeNext(tls, pCur)
|
|
}
|
|
if (*TMemPage)(unsafe.Pointer(pPage)).Fleaf != 0 {
|
|
return SQLITE_OK
|
|
} else {
|
|
return _moveToLeftmost(tls, pCur)
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the offset into the database file for the start of the
|
|
// ** payload to which the cursor is pointing.
|
|
// */
|
|
func _sqlite3BtreeOffset(tls *libc.TLS, pCur uintptr) (r Ti64) {
|
|
_getCellInfo(tls, pCur)
|
|
return libc.Int64FromUint32((*TBtShared)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpBt)).FpageSize)*(libc.Int64FromUint32((*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).Fpgno)-int64(1)) + (int64((*TBtCursor)(unsafe.Pointer(pCur)).Finfo.FpPayload) - int64((*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).FaData))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return an estimate for the number of rows in the table that pCur is
|
|
// ** pointing to. Return a negative number if no estimate is currently
|
|
// ** available.
|
|
// */
|
|
func _sqlite3BtreeRowCountEst(tls *libc.TLS, pCur uintptr) (r Ti64) {
|
|
var i Tu8
|
|
var n Ti64
|
|
_, _ = i, n
|
|
/* Currently this interface is only called by the OP_IfSizeBetween
|
|
** opcode and the OP_Count opcode with P3=1. In either case,
|
|
** the cursor will always be valid unless the btree is empty. */
|
|
if libc.Int32FromUint8((*TBtCursor)(unsafe.Pointer(pCur)).FeState) != CURSOR_VALID {
|
|
return 0
|
|
}
|
|
if libc.Int32FromUint8((*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).Fleaf) == 0 {
|
|
return int64(-int32(1))
|
|
}
|
|
n = libc.Int64FromUint16((*TMemPage)(unsafe.Pointer((*TBtCursor)(unsafe.Pointer(pCur)).FpPage)).FnCell)
|
|
i = uint8(0)
|
|
for {
|
|
if !(libc.Int32FromUint8(i) < int32((*TBtCursor)(unsafe.Pointer(pCur)).FiPage)) {
|
|
break
|
|
}
|
|
n = n * int64(libc.Int32FromUint16((*TMemPage)(unsafe.Pointer(**(**uintptr)(__ccgo_up(pCur + 144 + uintptr(i)*8)))).FnCell)+int32(1))
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return n
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Change the values for the BTS_SECURE_DELETE and BTS_OVERWRITE flags:
|
|
// **
|
|
// ** newFlag==0 Both BTS_SECURE_DELETE and BTS_OVERWRITE are cleared
|
|
// ** newFlag==1 BTS_SECURE_DELETE set and BTS_OVERWRITE is cleared
|
|
// ** newFlag==2 BTS_SECURE_DELETE cleared and BTS_OVERWRITE is set
|
|
// ** newFlag==(-1) No changes
|
|
// **
|
|
// ** This routine acts as a query if newFlag is less than zero
|
|
// **
|
|
// ** With BTS_OVERWRITE set, deleted content is overwritten by zeros, but
|
|
// ** freelist leaf pages are not written back to the database. Thus in-page
|
|
// ** deleted content is cleared, but freelist deleted content is not.
|
|
// **
|
|
// ** With BTS_SECURE_DELETE, operation is like BTS_OVERWRITE with the addition
|
|
// ** that freelist leaf pages are written back into the database, increasing
|
|
// ** the amount of disk I/O.
|
|
// */
|
|
func _sqlite3BtreeSecureDelete(tls *libc.TLS, p uintptr, newFlag int32) (r int32) {
|
|
var b int32
|
|
var v1 uintptr
|
|
_, _ = b, v1
|
|
if p == uintptr(0) {
|
|
return 0
|
|
}
|
|
_sqlite3BtreeEnter(tls, p)
|
|
if newFlag >= 0 {
|
|
v1 = (*TBtree)(unsafe.Pointer(p)).FpBt + 40
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) & ^libc.Int32FromInt32(BTS_FAST_SECURE))
|
|
v1 = (*TBtree)(unsafe.Pointer(p)).FpBt + 40
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromUint16(libc.Uint16FromInt32(libc.Int32FromInt32(BTS_SECURE_DELETE)*newFlag)))
|
|
}
|
|
b = libc.Int32FromUint16((*TBtShared)(unsafe.Pointer((*TBtree)(unsafe.Pointer(p)).FpBt)).FbtsFlags) & int32(BTS_FAST_SECURE) / int32(BTS_SECURE_DELETE)
|
|
_sqlite3BtreeLeave(tls, p)
|
|
return b
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Change the default pages size and the number of reserved bytes per page.
|
|
// ** Or, if the page size has already been fixed, return SQLITE_READONLY
|
|
// ** without changing anything.
|
|
// **
|
|
// ** The page size must be a power of 2 between 512 and 65536. If the page
|
|
// ** size supplied does not meet this constraint then the page size is not
|
|
// ** changed.
|
|
// **
|
|
// ** Page sizes are constrained to be a power of two so that the region
|
|
// ** of the database file used for locking (beginning at PENDING_BYTE,
|
|
// ** the first byte past the 1GB boundary, 0x40000000) needs to occur
|
|
// ** at the beginning of a page.
|
|
// **
|
|
// ** If parameter nReserve is less than zero, then the number of reserved
|
|
// ** bytes per page is left unchanged.
|
|
// **
|
|
// ** If the iFix!=0 then the BTS_PAGESIZE_FIXED flag is set so that the page size
|
|
// ** and autovacuum mode can no longer be changed.
|
|
// */
|
|
func _sqlite3BtreeSetPageSize(tls *libc.TLS, p uintptr, pageSize int32, nReserve int32, iFix int32) (r int32) {
|
|
var pBt, v1 uintptr
|
|
var rc, x int32
|
|
_, _, _, _ = pBt, rc, x, v1
|
|
rc = SQLITE_OK
|
|
pBt = (*TBtree)(unsafe.Pointer(p)).FpBt
|
|
_sqlite3BtreeEnter(tls, p)
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FnReserveWanted = libc.Uint8FromInt32(nReserve)
|
|
x = libc.Int32FromUint32((*TBtShared)(unsafe.Pointer(pBt)).FpageSize - (*TBtShared)(unsafe.Pointer(pBt)).FusableSize)
|
|
if x == nReserve && (pageSize == 0 || libc.Uint32FromInt32(pageSize) == (*TBtShared)(unsafe.Pointer(pBt)).FpageSize) {
|
|
_sqlite3BtreeLeave(tls, p)
|
|
return SQLITE_OK
|
|
}
|
|
if nReserve < x {
|
|
nReserve = x
|
|
}
|
|
if libc.Int32FromUint16((*TBtShared)(unsafe.Pointer(pBt)).FbtsFlags)&int32(BTS_PAGESIZE_FIXED) != 0 {
|
|
_sqlite3BtreeLeave(tls, p)
|
|
return int32(SQLITE_READONLY)
|
|
}
|
|
if pageSize >= int32(512) && pageSize <= int32(SQLITE_MAX_PAGE_SIZE) && (pageSize-int32(1))&pageSize == 0 {
|
|
if nReserve > int32(32) && pageSize == int32(512) {
|
|
pageSize = int32(1024)
|
|
}
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FpageSize = libc.Uint32FromInt32(pageSize)
|
|
_freeTempSpace(tls, pBt)
|
|
}
|
|
rc = _sqlite3PagerSetPagesize(tls, (*TBtShared)(unsafe.Pointer(pBt)).FpPager, pBt+52, nReserve)
|
|
(*TBtShared)(unsafe.Pointer(pBt)).FusableSize = (*TBtShared)(unsafe.Pointer(pBt)).FpageSize - uint32(libc.Uint16FromInt32(nReserve))
|
|
if iFix != 0 {
|
|
v1 = pBt + 40
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(BTS_PAGESIZE_FIXED))
|
|
}
|
|
_sqlite3BtreeLeave(tls, p)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set both the "read version" (single byte at byte offset 18) and
|
|
// ** "write version" (single byte at byte offset 19) fields in the database
|
|
// ** header to iVersion.
|
|
// */
|
|
func _sqlite3BtreeSetVersion(tls *libc.TLS, pBtree uintptr, iVersion int32) (r int32) {
|
|
var aData, pBt, v1 uintptr
|
|
var rc int32
|
|
_, _, _, _ = aData, pBt, rc, v1
|
|
pBt = (*TBtree)(unsafe.Pointer(pBtree)).FpBt /* Return code */
|
|
/* If setting the version fields to 1, do not automatically open the
|
|
** WAL connection, even if the version fields are currently set to 2.
|
|
*/
|
|
v1 = pBt + 40
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) & ^libc.Int32FromInt32(BTS_NO_WAL))
|
|
if iVersion == int32(1) {
|
|
v1 = pBt + 40
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(BTS_NO_WAL))
|
|
}
|
|
rc = _sqlite3BtreeBeginTrans(tls, pBtree, 0, uintptr(0))
|
|
if rc == SQLITE_OK {
|
|
aData = (*TMemPage)(unsafe.Pointer((*TBtShared)(unsafe.Pointer(pBt)).FpPage1)).FaData
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aData + 18))) != libc.Int32FromUint8(libc.Uint8FromInt32(iVersion)) || libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aData + 19))) != libc.Int32FromUint8(libc.Uint8FromInt32(iVersion)) {
|
|
rc = _sqlite3BtreeBeginTrans(tls, pBtree, int32(2), uintptr(0))
|
|
if rc == SQLITE_OK {
|
|
rc = _sqlite3PagerWrite(tls, (*TMemPage)(unsafe.Pointer((*TBtShared)(unsafe.Pointer(pBt)).FpPage1)).FpDbPage)
|
|
if rc == SQLITE_OK {
|
|
**(**Tu8)(__ccgo_up(aData + 18)) = libc.Uint8FromInt32(iVersion)
|
|
**(**Tu8)(__ccgo_up(aData + 19)) = libc.Uint8FromInt32(iVersion)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
v1 = pBt + 40
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) & ^libc.Int32FromInt32(BTS_NO_WAL))
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code that will increment the schema cookie.
|
|
// **
|
|
// ** The schema cookie is used to determine when the schema for the
|
|
// ** database changes. After each schema change, the cookie value
|
|
// ** changes. When a process first reads the schema it records the
|
|
// ** cookie. Thereafter, whenever it goes to access the database,
|
|
// ** it checks the cookie to make sure the schema has not changed
|
|
// ** since it was last read.
|
|
// **
|
|
// ** This plan is not completely bullet-proof. It is possible for
|
|
// ** the schema to change multiple times and for the cookie to be
|
|
// ** set back to prior value. But schema changes are infrequent
|
|
// ** and the probability of hitting the same cookie value is only
|
|
// ** 1 chance in 2^32. So we're safe enough.
|
|
// **
|
|
// ** IMPLEMENTATION-OF: R-34230-56049 SQLite automatically increments
|
|
// ** the schema-version whenever the schema changes.
|
|
// */
|
|
func _sqlite3ChangeCookie(tls *libc.TLS, pParse uintptr, iDb int32) {
|
|
var db, v uintptr
|
|
_, _ = db, v
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_SetCookie), iDb, int32(BTREE_SCHEMA_VERSION), libc.Int32FromUint32(libc.Uint32FromInt32(1)+libc.Uint32FromInt32((*TSchema)(unsafe.Pointer((**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(iDb)*32))).FpSchema)).Fschema_cookie)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code for the trigger program associated with trigger p on
|
|
// ** table pTab. The reg, orconf and ignoreJump parameters passed to this
|
|
// ** function are the same as those described in the header function for
|
|
// ** sqlite3CodeRowTrigger()
|
|
// */
|
|
func _sqlite3CodeRowTriggerDirect(tls *libc.TLS, pParse uintptr, p uintptr, pTab uintptr, reg int32, orconf int32, ignoreJump int32) {
|
|
var bRecursive, v1 int32
|
|
var pPrg, v, v2 uintptr
|
|
_, _, _, _, _ = bRecursive, pPrg, v, v1, v2
|
|
v = _sqlite3GetVdbe(tls, pParse)
|
|
pPrg = _getRowTrigger(tls, pParse, p, pTab, orconf)
|
|
/* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program
|
|
** is a pointer to the sub-vdbe containing the trigger program. */
|
|
if pPrg != 0 {
|
|
bRecursive = libc.BoolInt32((*TTrigger)(unsafe.Pointer(p)).FzName != 0 && uint64(0) == (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).Fflags&uint64(SQLITE_RecTriggers))
|
|
v2 = pParse + 60
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
_sqlite3VdbeAddOp4(tls, v, int32(OP_Program), reg, ignoreJump, v1, (*TTriggerPrg)(unsafe.Pointer(pPrg)).FpProgram, -int32(4))
|
|
/* Set the P5 operand of the OP_Program instruction to non-zero if
|
|
** recursive invocation of this trigger program is disallowed. Recursive
|
|
** invocation is disallowed if (a) the sub-program is really a trigger,
|
|
** not a foreign key action, and (b) the flag to enable recursive triggers
|
|
** is clear. */
|
|
_sqlite3VdbeChangeP5(tls, v, libc.Uint16FromInt32(bRecursive))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the expression associated with a column. The expression might be
|
|
// ** the DEFAULT clause or the AS clause of a generated column.
|
|
// ** Return NULL if the column has no associated expression.
|
|
// */
|
|
func _sqlite3ColumnExpr(tls *libc.TLS, pTab uintptr, pCol uintptr) (r uintptr) {
|
|
if libc.Int32FromUint16((*TColumn)(unsafe.Pointer(pCol)).FiDflt) == 0 {
|
|
return uintptr(0)
|
|
}
|
|
if !(libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == libc.Int32FromInt32(TABTYP_NORM)) {
|
|
return uintptr(0)
|
|
}
|
|
if (*(*struct {
|
|
FaddColOffset int32
|
|
FpFKey uintptr
|
|
FpDfltList uintptr
|
|
})(unsafe.Pointer(pTab + 64))).FpDfltList == uintptr(0) {
|
|
return uintptr(0)
|
|
}
|
|
if (*TExprList)(unsafe.Pointer((*(*struct {
|
|
FaddColOffset int32
|
|
FpFKey uintptr
|
|
FpDfltList uintptr
|
|
})(unsafe.Pointer(pTab + 64))).FpDfltList)).FnExpr < libc.Int32FromUint16((*TColumn)(unsafe.Pointer(pCol)).FiDflt) {
|
|
return uintptr(0)
|
|
}
|
|
return (*(*TExprList_item)(unsafe.Pointer((*(*struct {
|
|
FaddColOffset int32
|
|
FpFKey uintptr
|
|
FpDfltList uintptr
|
|
})(unsafe.Pointer(pTab + 64))).FpDfltList + 8 + uintptr(libc.Int32FromUint16((*TColumn)(unsafe.Pointer(pCol)).FiDflt)-int32(1))*32))).FpExpr
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the index of a column in a table. Return -1 if the column
|
|
// ** is not contained in the table.
|
|
// */
|
|
func _sqlite3ColumnIndex(tls *libc.TLS, pTab uintptr, zCol uintptr) (r int32) {
|
|
var aCol uintptr
|
|
var h Tu8
|
|
var i, nCol int32
|
|
_, _, _, _ = aCol, h, i, nCol
|
|
h = _sqlite3StrIHash(tls, zCol)
|
|
aCol = (*TTable)(unsafe.Pointer(pTab)).FaCol
|
|
nCol = int32((*TTable)(unsafe.Pointer(pTab)).FnCol)
|
|
/* See if the aHx gives us a lucky match */
|
|
i = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pTab + 104 + uintptr(uint64(h)%uint64(16)))))
|
|
if libc.Int32FromUint8((**(**TColumn)(__ccgo_up(aCol + uintptr(i)*16))).FhName) == libc.Int32FromUint8(h) && _sqlite3StrICmp(tls, (**(**TColumn)(__ccgo_up(aCol + uintptr(i)*16))).FzCnName, zCol) == 0 {
|
|
return i
|
|
}
|
|
/* No lucky match from the hash table. Do a full search. */
|
|
i = 0
|
|
for int32(1) != 0 {
|
|
if libc.Int32FromUint8((**(**TColumn)(__ccgo_up(aCol + uintptr(i)*16))).FhName) == libc.Int32FromUint8(h) && _sqlite3StrICmp(tls, (**(**TColumn)(__ccgo_up(aCol + uintptr(i)*16))).FzCnName, zCol) == 0 {
|
|
return i
|
|
}
|
|
i = i + 1
|
|
if i >= nCol {
|
|
break
|
|
}
|
|
}
|
|
return -int32(1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the expression associated with a column. This is usually
|
|
// ** the DEFAULT value, but might also be the expression that computes
|
|
// ** the value for a generated column.
|
|
// */
|
|
func _sqlite3ColumnSetExpr(tls *libc.TLS, pParse uintptr, pTab uintptr, pCol uintptr, pExpr uintptr) {
|
|
var pList uintptr
|
|
var v1 int32
|
|
_, _ = pList, v1
|
|
pList = (*(*struct {
|
|
FaddColOffset int32
|
|
FpFKey uintptr
|
|
FpDfltList uintptr
|
|
})(unsafe.Pointer(pTab + 64))).FpDfltList
|
|
if libc.Int32FromUint16((*TColumn)(unsafe.Pointer(pCol)).FiDflt) == 0 || pList == uintptr(0) || (*TExprList)(unsafe.Pointer(pList)).FnExpr < libc.Int32FromUint16((*TColumn)(unsafe.Pointer(pCol)).FiDflt) {
|
|
if pList == uintptr(0) {
|
|
v1 = int32(1)
|
|
} else {
|
|
v1 = (*TExprList)(unsafe.Pointer(pList)).FnExpr + int32(1)
|
|
}
|
|
(*TColumn)(unsafe.Pointer(pCol)).FiDflt = libc.Uint16FromInt32(v1)
|
|
(*(*struct {
|
|
FaddColOffset int32
|
|
FpFKey uintptr
|
|
FpDfltList uintptr
|
|
})(unsafe.Pointer(pTab + 64))).FpDfltList = _sqlite3ExprListAppend(tls, pParse, pList, pExpr)
|
|
} else {
|
|
_sqlite3ExprDelete(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, (*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(libc.Int32FromUint16((*TColumn)(unsafe.Pointer(pCol)).FiDflt)-int32(1))*32))).FpExpr)
|
|
(*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(libc.Int32FromUint16((*TColumn)(unsafe.Pointer(pCol)).FiDflt)-int32(1))*32))).FpExpr = pExpr
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the declared type of a column. Or return zDflt if the column
|
|
// ** has no declared type.
|
|
// **
|
|
// ** The column type is an extra string stored after the zero-terminator on
|
|
// ** the column name if and only if the COLFLAG_HASTYPE flag is set.
|
|
// */
|
|
func _sqlite3ColumnType(tls *libc.TLS, pCol uintptr, zDflt uintptr) (r uintptr) {
|
|
if libc.Int32FromUint16((*TColumn)(unsafe.Pointer(pCol)).FcolFlags)&int32(COLFLAG_HASTYPE) != 0 {
|
|
return (*TColumn)(unsafe.Pointer(pCol)).FzCnName + uintptr(libc.Xstrlen(tls, (*TColumn)(unsafe.Pointer(pCol)).FzCnName)) + uintptr(1)
|
|
} else {
|
|
if int32(uint32(*(*uint8)(unsafe.Pointer(pCol + 8))&0xf0>>4)) != 0 {
|
|
return _sqlite3StdType[int32(uint32(*(*uint8)(unsafe.Pointer(pCol + 8))&0xf0>>4))-int32(1)]
|
|
} else {
|
|
return zDflt
|
|
}
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine is called when a commit occurs.
|
|
// */
|
|
func _sqlite3CommitInternalChanges(tls *libc.TLS, db uintptr) {
|
|
**(**Tu32)(__ccgo_up(db + 44)) &= libc.Uint32FromInt32(^libc.Int32FromInt32(DBFLAG_SchemaChange))
|
|
}
|
|
|
|
func _sqlite3CompileOptions(tls *libc.TLS, pnOpt uintptr) (r uintptr) {
|
|
**(**int32)(__ccgo_up(pnOpt)) = libc.Int32FromUint64(libc.Uint64FromInt64(448) / libc.Uint64FromInt64(8))
|
|
return uintptr(unsafe.Pointer(&_sqlite3azCompileOpt))
|
|
}
|
|
|
|
/************** End of ctime.c ***********************************************/
|
|
/************** Begin file global.c ******************************************/
|
|
/*
|
|
** 2008 June 13
|
|
**
|
|
** The author disclaims copyright to this source code. In place of
|
|
** a legal notice, here is a blessing:
|
|
**
|
|
** May you do good and not evil.
|
|
** May you find forgiveness for yourself and forgive others.
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
*************************************************************************
|
|
**
|
|
** This file contains definitions of global variables and constants.
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine generates code to finish the INSERT or UPDATE operation
|
|
// ** that was started by a prior call to sqlite3GenerateConstraintChecks.
|
|
// ** A consecutive range of registers starting at regNewData contains the
|
|
// ** rowid and the content to be inserted.
|
|
// **
|
|
// ** The arguments to this routine should be the same as the first six
|
|
// ** arguments to sqlite3GenerateConstraintChecks.
|
|
// */
|
|
func _sqlite3CompleteInsertion(tls *libc.TLS, pParse uintptr, pTab uintptr, iDataCur int32, iIdxCur int32, regNewData int32, aRegIdx uintptr, update_flags int32, appendBias int32, useSeekResult int32) {
|
|
var i, v2 int32
|
|
var pIdx, v uintptr
|
|
var pik_flags Tu8
|
|
_, _, _, _, _ = i, pIdx, pik_flags, v, v2 /* Loop counter */
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
/* This table is not a VIEW */
|
|
i = 0
|
|
pIdx = (*TTable)(unsafe.Pointer(pTab)).FpIndex
|
|
for {
|
|
if !(pIdx != 0) {
|
|
break
|
|
}
|
|
/* All REPLACE indexes are at the end of the list */
|
|
if **(**int32)(__ccgo_up(aRegIdx + uintptr(i)*4)) == 0 {
|
|
goto _1
|
|
}
|
|
if (*TIndex)(unsafe.Pointer(pIdx)).FpPartIdxWhere != 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_IsNull), **(**int32)(__ccgo_up(aRegIdx + uintptr(i)*4)), _sqlite3VdbeCurrentAddr(tls, v)+int32(2))
|
|
}
|
|
if useSeekResult != 0 {
|
|
v2 = int32(OPFLAG_USESEEKRESULT)
|
|
} else {
|
|
v2 = 0
|
|
}
|
|
pik_flags = libc.Uint8FromInt32(v2)
|
|
if int32(uint32(*(*uint16)(unsafe.Pointer(pIdx + 100))&0x3>>0)) == int32(SQLITE_IDXTYPE_PRIMARYKEY) && !((*TTable)(unsafe.Pointer(pTab)).FtabFlags&libc.Uint32FromInt32(TF_WithoutRowid) == libc.Uint32FromInt32(0)) {
|
|
pik_flags = libc.Uint8FromInt32(int32(pik_flags) | libc.Int32FromInt32(OPFLAG_NCHANGE))
|
|
pik_flags = libc.Uint8FromInt32(int32(pik_flags) | update_flags&libc.Int32FromInt32(OPFLAG_SAVEPOSITION))
|
|
if update_flags == 0 {
|
|
_codeWithoutRowidPreupdate(tls, pParse, pTab, iIdxCur+i, **(**int32)(__ccgo_up(aRegIdx + uintptr(i)*4)))
|
|
}
|
|
}
|
|
if int32(uint32(*(*uint16)(unsafe.Pointer(pIdx + 100))&0x8>>3)) != 0 {
|
|
v2 = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol)
|
|
} else {
|
|
v2 = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn)
|
|
}
|
|
_sqlite3VdbeAddOp4Int(tls, v, int32(OP_IdxInsert), iIdxCur+i, **(**int32)(__ccgo_up(aRegIdx + uintptr(i)*4)), **(**int32)(__ccgo_up(aRegIdx + uintptr(i)*4))+int32(1), v2)
|
|
_sqlite3VdbeChangeP5(tls, v, uint16(pik_flags))
|
|
goto _1
|
|
_1:
|
|
;
|
|
pIdx = (*TIndex)(unsafe.Pointer(pIdx)).FpNext
|
|
i = i + 1
|
|
}
|
|
if !((*TTable)(unsafe.Pointer(pTab)).FtabFlags&libc.Uint32FromInt32(TF_WithoutRowid) == libc.Uint32FromInt32(0)) {
|
|
return
|
|
}
|
|
if (*TParse)(unsafe.Pointer(pParse)).Fnested != 0 {
|
|
pik_flags = uint8(0)
|
|
} else {
|
|
pik_flags = uint8(OPFLAG_NCHANGE)
|
|
if update_flags != 0 {
|
|
v2 = update_flags
|
|
} else {
|
|
v2 = int32(OPFLAG_LASTROWID)
|
|
}
|
|
pik_flags = libc.Uint8FromInt32(int32(pik_flags) | v2)
|
|
}
|
|
if appendBias != 0 {
|
|
pik_flags = libc.Uint8FromInt32(int32(pik_flags) | libc.Int32FromInt32(OPFLAG_APPEND))
|
|
}
|
|
if useSeekResult != 0 {
|
|
pik_flags = libc.Uint8FromInt32(int32(pik_flags) | libc.Int32FromInt32(OPFLAG_USESEEKRESULT))
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Insert), iDataCur, **(**int32)(__ccgo_up(aRegIdx + uintptr(i)*4)), regNewData)
|
|
if !((*TParse)(unsafe.Pointer(pParse)).Fnested != 0) {
|
|
_sqlite3VdbeAppendP4(tls, v, pTab, -int32(5))
|
|
}
|
|
_sqlite3VdbeChangeP5(tls, v, uint16(pik_flags))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate bytecode that will initialize a Bloom filter that is appropriate
|
|
// ** for pLevel.
|
|
// **
|
|
// ** If there are inner loops within pLevel that have the WHERE_BLOOMFILTER
|
|
// ** flag set, initialize a Bloomfilter for them as well. Except don't do
|
|
// ** this recursive initialization if the SQLITE_BloomPulldown optimization has
|
|
// ** been turned off.
|
|
// **
|
|
// ** When the Bloom filter is initialized, the WHERE_BLOOMFILTER flag is cleared
|
|
// ** from the loop, but the regFilter value is set to a register that implements
|
|
// ** the Bloom filter. When regFilter is positive, the
|
|
// ** sqlite3WhereCodeOneLoopStart() will generate code to test the Bloom filter
|
|
// ** and skip the subsequence B-Tree seek if the Bloom filter indicates that
|
|
// ** no matching rows exist.
|
|
// **
|
|
// ** This routine may only be called if it has previously been determined that
|
|
// ** the loop would benefit from a Bloom filter, and the WHERE_BLOOMFILTER bit
|
|
// ** is set.
|
|
// */
|
|
func _sqlite3ConstructBloomFilter(tls *libc.TLS, pWInfo uintptr, iLevel int32, pLevel uintptr, notReady TBitmask) {
|
|
var addrCont, addrOnce, addrTop, iCur, iSrc, jj, n, r1, r11, v1 int32
|
|
var pExpr, pIdx, pItem, pLoop, pParse, pTab, pTabItem, pTabList, pTerm, pWCEnd, saved_pIdxEpr, saved_pIdxPartExpr, v, v2 uintptr
|
|
var sz Tu64
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = addrCont, addrOnce, addrTop, iCur, iSrc, jj, n, pExpr, pIdx, pItem, pLoop, pParse, pTab, pTabItem, pTabList, pTerm, pWCEnd, r1, r11, saved_pIdxEpr, saved_pIdxPartExpr, sz, v, v1, v2 /* Last WHERE clause term */
|
|
pParse = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpParse /* Parsing context */
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe /* VDBE under construction */
|
|
pLoop = (*TWhereLevel)(unsafe.Pointer(pLevel)).FpWLoop /* saved copy of Parse.pIdxPartExpr */
|
|
saved_pIdxEpr = (*TParse)(unsafe.Pointer(pParse)).FpIdxEpr
|
|
saved_pIdxPartExpr = (*TParse)(unsafe.Pointer(pParse)).FpIdxPartExpr
|
|
(*TParse)(unsafe.Pointer(pParse)).FpIdxEpr = uintptr(0)
|
|
(*TParse)(unsafe.Pointer(pParse)).FpIdxPartExpr = uintptr(0)
|
|
addrOnce = _sqlite3VdbeAddOp0(tls, v, int32(OP_Once))
|
|
for cond := true; cond; cond = iLevel < libc.Int32FromUint8((*TWhereInfo)(unsafe.Pointer(pWInfo)).FnLevel) {
|
|
_sqlite3WhereExplainBloomFilter(tls, pParse, pWInfo, pLevel)
|
|
addrCont = _sqlite3VdbeMakeLabel(tls, pParse)
|
|
iCur = (*TWhereLevel)(unsafe.Pointer(pLevel)).FiTabCur
|
|
v2 = pParse + 60
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
(*TWhereLevel)(unsafe.Pointer(pLevel)).FregFilter = v1
|
|
/* The Bloom filter is a Blob held in a register. Initialize it
|
|
** to zero-filled blob of at least 80K bits, but maybe more if the
|
|
** estimated size of the table is larger. We could actually
|
|
** measure the size of the table at run-time using OP_Count with
|
|
** P3==1 and use that value to initialize the blob. But that makes
|
|
** testing complicated. By basing the blob size on the value in the
|
|
** sqlite_stat1 table, testing is much easier.
|
|
*/
|
|
pTabList = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpTabList
|
|
iSrc = libc.Int32FromUint8((*TWhereLevel)(unsafe.Pointer(pLevel)).FiFrom)
|
|
pItem = pTabList + 8 + uintptr(iSrc)*80
|
|
pTab = (*TSrcItem)(unsafe.Pointer(pItem)).FpSTab
|
|
sz = _sqlite3LogEstToInt(tls, (*TTable)(unsafe.Pointer(pTab)).FnRowLogEst)
|
|
if sz < uint64(10000) {
|
|
sz = uint64(10000)
|
|
} else {
|
|
if sz > uint64(10000000) {
|
|
sz = uint64(10000000)
|
|
}
|
|
}
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Blob), libc.Int32FromUint64(sz), (*TWhereLevel)(unsafe.Pointer(pLevel)).FregFilter)
|
|
addrTop = _sqlite3VdbeAddOp1(tls, v, int32(OP_Rewind), iCur)
|
|
pWCEnd = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FsWC.Fa + uintptr((*TWhereInfo)(unsafe.Pointer(pWInfo)).FsWC.FnTerm)*56
|
|
pTerm = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FsWC.Fa
|
|
for {
|
|
if !(pTerm < pWCEnd) {
|
|
break
|
|
}
|
|
pExpr = (*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FwtFlags)&int32(TERM_VIRTUAL) == 0 && _sqlite3ExprIsSingleTableConstraint(tls, pExpr, pTabList, iSrc, 0) != 0 {
|
|
_sqlite3ExprIfFalse(tls, pParse, (*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr, addrCont, int32(SQLITE_JUMPIFNULL))
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
pTerm += 56
|
|
}
|
|
if (*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags&uint32(WHERE_IPK) != 0 {
|
|
r1 = _sqlite3GetTempReg(tls, pParse)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Rowid), iCur, r1)
|
|
_sqlite3VdbeAddOp4Int(tls, v, int32(OP_FilterAdd), (*TWhereLevel)(unsafe.Pointer(pLevel)).FregFilter, 0, r1, int32(1))
|
|
_sqlite3ReleaseTempReg(tls, pParse, r1)
|
|
} else {
|
|
pIdx = (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FpIndex
|
|
n = libc.Int32FromUint16((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FnEq)
|
|
r11 = _sqlite3GetTempRange(tls, pParse, n)
|
|
jj = 0
|
|
for {
|
|
if !(jj < n) {
|
|
break
|
|
}
|
|
_sqlite3ExprCodeLoadIndexColumn(tls, pParse, pIdx, iCur, jj, r11+jj)
|
|
goto _4
|
|
_4:
|
|
;
|
|
jj = jj + 1
|
|
}
|
|
_sqlite3VdbeAddOp4Int(tls, v, int32(OP_FilterAdd), (*TWhereLevel)(unsafe.Pointer(pLevel)).FregFilter, 0, r11, n)
|
|
_sqlite3ReleaseTempRange(tls, pParse, r11, n)
|
|
}
|
|
_sqlite3VdbeResolveLabel(tls, v, addrCont)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Next), (*TWhereLevel)(unsafe.Pointer(pLevel)).FiTabCur, addrTop+int32(1))
|
|
_sqlite3VdbeJumpHere(tls, v, addrTop)
|
|
**(**Tu32)(__ccgo_up(pLoop + 48)) &= libc.Uint32FromInt32(^libc.Int32FromInt32(WHERE_BLOOMFILTER))
|
|
if (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).FdbOptFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_BloomPulldown)) != uint32(0) {
|
|
break
|
|
}
|
|
for {
|
|
iLevel = iLevel + 1
|
|
v1 = iLevel
|
|
if !(v1 < libc.Int32FromUint8((*TWhereInfo)(unsafe.Pointer(pWInfo)).FnLevel)) {
|
|
break
|
|
}
|
|
pLevel = pWInfo + 856 + uintptr(iLevel)*112
|
|
pTabItem = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpTabList + 8 + uintptr((*TWhereLevel)(unsafe.Pointer(pLevel)).FiFrom)*80
|
|
if libc.Int32FromUint8((*TSrcItem)(unsafe.Pointer(pTabItem)).Ffg.Fjointype)&(libc.Int32FromInt32(JT_LEFT)|libc.Int32FromInt32(JT_LTORJ)) != 0 {
|
|
continue
|
|
}
|
|
pLoop = (*TWhereLevel)(unsafe.Pointer(pLevel)).FpWLoop
|
|
if pLoop == uintptr(0) {
|
|
continue
|
|
}
|
|
if (*TWhereLoop)(unsafe.Pointer(pLoop)).Fprereq¬Ready != 0 {
|
|
continue
|
|
}
|
|
if (*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags&libc.Uint32FromInt32(libc.Int32FromInt32(WHERE_BLOOMFILTER)|libc.Int32FromInt32(WHERE_COLUMN_IN)) == uint32(WHERE_BLOOMFILTER) {
|
|
/* This is a candidate for bloom-filter pull-down (early evaluation).
|
|
** The test that WHERE_COLUMN_IN is omitted is important, as we are
|
|
** not able to do early evaluation of bloom filters that make use of
|
|
** the IN operator */
|
|
break
|
|
}
|
|
}
|
|
}
|
|
_sqlite3VdbeJumpHere(tls, v, addrOnce)
|
|
(*TParse)(unsafe.Pointer(pParse)).FpIdxEpr = saved_pIdxEpr
|
|
(*TParse)(unsafe.Pointer(pParse)).FpIdxPartExpr = saved_pIdxPartExpr
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If p2 exists and p1 and p2 have the same number of terms, then change
|
|
// ** every term of p1 to have the same sort order as p2 and return true.
|
|
// **
|
|
// ** If p2 is NULL or p1 and p2 are different lengths, then make no changes
|
|
// ** and return false.
|
|
// **
|
|
// ** p1 must be non-NULL.
|
|
// */
|
|
func _sqlite3CopySortOrder(tls *libc.TLS, p1 uintptr, p2 uintptr) (r int32) {
|
|
var ii int32
|
|
var sortFlags Tu8
|
|
_, _ = ii, sortFlags
|
|
if p2 != 0 && (*TExprList)(unsafe.Pointer(p1)).FnExpr == (*TExprList)(unsafe.Pointer(p2)).FnExpr {
|
|
ii = 0
|
|
for {
|
|
if !(ii < (*TExprList)(unsafe.Pointer(p1)).FnExpr) {
|
|
break
|
|
}
|
|
sortFlags = libc.Uint8FromInt32(libc.Int32FromUint8((*(*TExprList_item)(unsafe.Pointer(p2 + 8 + uintptr(ii)*32))).Ffg.FsortFlags) & int32(KEYINFO_ORDER_DESC))
|
|
(*(*TExprList_item)(unsafe.Pointer(p1 + 8 + uintptr(ii)*32))).Ffg.FsortFlags = sortFlags
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
return int32(1)
|
|
} else {
|
|
return 0
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate and return a pointer to an expression to load the column iCol
|
|
// ** from datasource iSrc in SrcList pSrc.
|
|
// */
|
|
func _sqlite3CreateColumnExpr(tls *libc.TLS, db uintptr, pSrc uintptr, iSrc int32, iCol int32) (r uintptr) {
|
|
var p, pItem, pTab, v1 uintptr
|
|
var v2 uint64
|
|
var v3 int32
|
|
_, _, _, _, _, _ = p, pItem, pTab, v1, v2, v3
|
|
p = _sqlite3ExprAlloc(tls, db, int32(TK_COLUMN), uintptr(0), 0)
|
|
if p != 0 {
|
|
pItem = pSrc + 8 + uintptr(iSrc)*80
|
|
v1 = (*TSrcItem)(unsafe.Pointer(pItem)).FpSTab
|
|
*(*uintptr)(unsafe.Pointer(p + 64)) = v1
|
|
pTab = v1
|
|
(*TExpr)(unsafe.Pointer(p)).FiTable = (*TSrcItem)(unsafe.Pointer(pItem)).FiCursor
|
|
if int32((*TTable)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(p + 64)))).FiPKey) == iCol {
|
|
(*TExpr)(unsafe.Pointer(p)).FiColumn = int16(-int32(1))
|
|
} else {
|
|
(*TExpr)(unsafe.Pointer(p)).FiColumn = int16(iCol)
|
|
if (*TTable)(unsafe.Pointer(pTab)).FtabFlags&uint32(TF_HasGenerated) != uint32(0) && libc.Int32FromUint16((**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(iCol)*16))).FcolFlags)&int32(COLFLAG_GENERATED) != 0 {
|
|
if int32((*TTable)(unsafe.Pointer(pTab)).FnCol) >= int32(64) {
|
|
v2 = libc.Uint64FromInt32(-libc.Int32FromInt32(1))
|
|
} else {
|
|
v2 = libc.Uint64FromInt32(1)<<(*TTable)(unsafe.Pointer(pTab)).FnCol - uint64(1)
|
|
}
|
|
(*TSrcItem)(unsafe.Pointer(pItem)).FcolUsed = v2
|
|
} else {
|
|
if iCol >= libc.Int32FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(8)) {
|
|
v3 = libc.Int32FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(8)) - libc.Int32FromInt32(1)
|
|
} else {
|
|
v3 = iCol
|
|
}
|
|
**(**TBitmask)(__ccgo_up(pItem + 40)) |= libc.Uint64FromInt32(1) << v3
|
|
}
|
|
}
|
|
}
|
|
return p
|
|
}
|
|
|
|
func _sqlite3DbMallocSize(tls *libc.TLS, db uintptr, p uintptr) (r int32) {
|
|
if db != 0 {
|
|
if uint64(p) < uint64((*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpTrueEnd) {
|
|
if uint64(p) >= uint64((*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpMiddle) {
|
|
return int32(LOOKASIDE_SMALL)
|
|
}
|
|
if uint64(p) >= uint64((*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpStart) {
|
|
return libc.Int32FromUint16((*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FszTrue)
|
|
}
|
|
}
|
|
}
|
|
return (*(*func(*libc.TLS, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.Fm.FxSize})))(tls, p)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine is called when an INITIALLY IMMEDIATE or INITIALLY DEFERRED
|
|
// ** clause is seen as part of a foreign key definition. The isDeferred
|
|
// ** parameter is 1 for INITIALLY DEFERRED and 0 for INITIALLY IMMEDIATE.
|
|
// ** The behavior of the most recently created foreign key is adjusted
|
|
// ** accordingly.
|
|
// */
|
|
func _sqlite3DeferForeignKey(tls *libc.TLS, pParse uintptr, isDeferred int32) {
|
|
var pFKey, pTab, v1 uintptr
|
|
_, _, _ = pFKey, pTab, v1
|
|
v1 = (*TParse)(unsafe.Pointer(pParse)).FpNewTable
|
|
pTab = v1
|
|
if v1 == uintptr(0) {
|
|
return
|
|
}
|
|
if !(libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == libc.Int32FromInt32(TABTYP_NORM)) {
|
|
return
|
|
}
|
|
v1 = (*(*struct {
|
|
FaddColOffset int32
|
|
FpFKey uintptr
|
|
FpDfltList uintptr
|
|
})(unsafe.Pointer(pTab + 64))).FpFKey
|
|
pFKey = v1
|
|
if v1 == uintptr(0) {
|
|
return
|
|
}
|
|
/* EV: R-30323-21917 */
|
|
(*TFKey)(unsafe.Pointer(pFKey)).FisDeferred = libc.Uint8FromInt32(isDeferred)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Delete memory allocated for the column names of a table or view (the
|
|
// ** Table.aCol[] array).
|
|
// */
|
|
func _sqlite3DeleteColumnNames(tls *libc.TLS, db uintptr, pTable uintptr) {
|
|
var i int32
|
|
var pCol, v1 uintptr
|
|
_, _, _ = i, pCol, v1
|
|
v1 = (*TTable)(unsafe.Pointer(pTable)).FaCol
|
|
pCol = v1
|
|
if v1 != uintptr(0) {
|
|
i = 0
|
|
for {
|
|
if !(i < int32((*TTable)(unsafe.Pointer(pTable)).FnCol)) {
|
|
break
|
|
}
|
|
_sqlite3DbFree(tls, db, (*TColumn)(unsafe.Pointer(pCol)).FzCnName)
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
pCol += 16
|
|
}
|
|
_sqlite3DbNNFreeNN(tls, db, (*TTable)(unsafe.Pointer(pTable)).FaCol)
|
|
if libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTable)).FeTabType) == TABTYP_NORM {
|
|
_sqlite3ExprListDelete(tls, db, (*(*struct {
|
|
FaddColOffset int32
|
|
FpFKey uintptr
|
|
FpDfltList uintptr
|
|
})(unsafe.Pointer(pTable + 64))).FpDfltList)
|
|
}
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FpnBytesFreed == uintptr(0) {
|
|
(*TTable)(unsafe.Pointer(pTable)).FaCol = uintptr(0)
|
|
(*TTable)(unsafe.Pointer(pTable)).FnCol = 0
|
|
if libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTable)).FeTabType) == TABTYP_NORM {
|
|
(*(*struct {
|
|
FaddColOffset int32
|
|
FpFKey uintptr
|
|
FpDfltList uintptr
|
|
})(unsafe.Pointer(pTable + 64))).FpDfltList = uintptr(0)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* The input list pList is the list of result set terms from a RETURNING
|
|
// ** clause. The table that we are returning from is pTab.
|
|
// **
|
|
// ** This routine makes a copy of the pList, and at the same time expands
|
|
// ** any "*" wildcards to be the complete set of columns from pTab.
|
|
// */
|
|
func _sqlite3ExpandReturning(tls *libc.TLS, pParse uintptr, pList uintptr, pTab uintptr) (r uintptr) {
|
|
var db, pItem, pItem1, pNew, pNewExpr, pNewExpr1, pOldExpr uintptr
|
|
var i, jj int32
|
|
_, _, _, _, _, _, _, _, _ = db, i, jj, pItem, pItem1, pNew, pNewExpr, pNewExpr1, pOldExpr
|
|
pNew = uintptr(0)
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
i = 0
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(pList)).FnExpr) {
|
|
break
|
|
}
|
|
pOldExpr = (*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(i)*32))).FpExpr
|
|
if pOldExpr == uintptr(0) {
|
|
goto _1
|
|
}
|
|
if _isAsteriskTerm(tls, pParse, pOldExpr) != 0 {
|
|
jj = 0
|
|
for {
|
|
if !(jj < int32((*TTable)(unsafe.Pointer(pTab)).FnCol)) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint16((*TColumn)(unsafe.Pointer((*TTable)(unsafe.Pointer(pTab)).FaCol+uintptr(jj)*16)).FcolFlags)&int32(COLFLAG_HIDDEN) != 0 {
|
|
goto _2
|
|
}
|
|
pNewExpr = _sqlite3Expr(tls, db, int32(TK_ID), (**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(jj)*16))).FzCnName)
|
|
pNew = _sqlite3ExprListAppend(tls, pParse, pNew, pNewExpr)
|
|
if !((*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0) {
|
|
pItem = pNew + 8 + uintptr((*TExprList)(unsafe.Pointer(pNew)).FnExpr-int32(1))*32
|
|
(*TExprList_item)(unsafe.Pointer(pItem)).FzEName = _sqlite3DbStrDup(tls, db, (**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(jj)*16))).FzCnName)
|
|
libc.SetBitFieldPtr16Uint32(pItem+16+4, libc.Uint32FromInt32(ENAME_NAME), 0, 0x3)
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
jj = jj + 1
|
|
}
|
|
} else {
|
|
pNewExpr1 = _sqlite3ExprDup(tls, db, pOldExpr, 0)
|
|
pNew = _sqlite3ExprListAppend(tls, pParse, pNew, pNewExpr1)
|
|
if !((*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0) && (*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(i)*32))).FzEName != uintptr(0) {
|
|
pItem1 = pNew + 8 + uintptr((*TExprList)(unsafe.Pointer(pNew)).FnExpr-int32(1))*32
|
|
(*TExprList_item)(unsafe.Pointer(pItem1)).FzEName = _sqlite3DbStrDup(tls, db, (*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(i)*32))).FzEName)
|
|
libc.SetBitFieldPtr16Uint32(pItem1+16+4, libc.Uint32FromInt32(int32(uint32(*(*uint16)(unsafe.Pointer(pList + 8 + uintptr(i)*32 + 16 + 4))&0x3>>0))), 0, 0x3)
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return pNew
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Mark every prepared statement associated with a database connection
|
|
// ** as expired.
|
|
// **
|
|
// ** An expired statement means that recompilation of the statement is
|
|
// ** recommend. Statements expire when things happen that make their
|
|
// ** programs obsolete. Removing user-defined functions or collating
|
|
// ** sequences, or changing an authorization function are the types of
|
|
// ** things that make prepared statements obsolete.
|
|
// **
|
|
// ** If iCode is 1, then expiration is advisory. The statement should
|
|
// ** be reprepared before being restarted, but if it is already running
|
|
// ** it is allowed to run to completion.
|
|
// **
|
|
// ** Internally, this function just sets the Vdbe.expired flag on all
|
|
// ** prepared statements. The flag is set to 1 for an immediate expiration
|
|
// ** and set to 2 for an advisory expiration.
|
|
// */
|
|
func _sqlite3ExpirePreparedStatements(tls *libc.TLS, db uintptr, iCode int32) {
|
|
var p uintptr
|
|
_ = p
|
|
p = (*Tsqlite3)(unsafe.Pointer(db)).FpVdbe
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
libc.SetBitFieldPtr16Uint32(p+200, libc.Uint32FromInt32(iCode+libc.Int32FromInt32(1)), 0, 0x3)
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = (*TVdbe)(unsafe.Pointer(p)).FpVNext
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return FALSE if there is no chance that the expression can be NULL.
|
|
// **
|
|
// ** If the expression might be NULL or if the expression is too complex
|
|
// ** to tell return TRUE.
|
|
// **
|
|
// ** This routine is used as an optimization, to skip OP_IsNull opcodes
|
|
// ** when we know that a value cannot be NULL. Hence, a false positive
|
|
// ** (returning TRUE when in fact the expression can never be NULL) might
|
|
// ** be a small performance hit but is otherwise harmless. On the other
|
|
// ** hand, a false negative (returning FALSE when the result could be NULL)
|
|
// ** will likely result in an incorrect answer. So when in doubt, return
|
|
// ** TRUE.
|
|
// */
|
|
func _sqlite3ExprCanBeNull(tls *libc.TLS, p uintptr) (r int32) {
|
|
var op Tu8
|
|
_ = op
|
|
for libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) == int32(TK_UPLUS) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) == int32(TK_UMINUS) {
|
|
p = (*TExpr)(unsafe.Pointer(p)).FpLeft
|
|
}
|
|
op = (*TExpr)(unsafe.Pointer(p)).Fop
|
|
if libc.Int32FromUint8(op) == int32(TK_REGISTER) {
|
|
op = (*TExpr)(unsafe.Pointer(p)).Fop2
|
|
}
|
|
switch libc.Int32FromUint8(op) {
|
|
case int32(TK_INTEGER):
|
|
fallthrough
|
|
case int32(TK_STRING):
|
|
fallthrough
|
|
case int32(TK_FLOAT):
|
|
fallthrough
|
|
case int32(TK_BLOB):
|
|
return 0
|
|
case int32(TK_COLUMN):
|
|
return libc.BoolInt32((*TExpr)(unsafe.Pointer(p)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_CanBeNull)) != uint32(0) || *(*uintptr)(unsafe.Pointer(p + 64)) == uintptr(0) || int32((*TExpr)(unsafe.Pointer(p)).FiColumn) >= 0 && (*TTable)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(p + 64)))).FaCol != uintptr(0) && int32((*TExpr)(unsafe.Pointer(p)).FiColumn) < int32((*TTable)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(p + 64)))).FnCol) && int32(uint32(*(*uint8)(unsafe.Pointer((*TTable)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(p + 64)))).FaCol + uintptr((*TExpr)(unsafe.Pointer(p)).FiColumn)*16 + 8))&0xf>>0)) == 0)
|
|
default:
|
|
return int32(1)
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code that pushes the value of every element of the given
|
|
// ** expression list into a sequence of registers beginning at target.
|
|
// **
|
|
// ** Return the number of elements evaluated. The number returned will
|
|
// ** usually be pList->nExpr but might be reduced if SQLITE_ECEL_OMITREF
|
|
// ** is defined.
|
|
// **
|
|
// ** The SQLITE_ECEL_DUP flag prevents the arguments from being
|
|
// ** filled using OP_SCopy. OP_Copy must be used instead.
|
|
// **
|
|
// ** The SQLITE_ECEL_FACTOR argument allows constant arguments to be
|
|
// ** factored out into initialization code.
|
|
// **
|
|
// ** The SQLITE_ECEL_REF flag means that expressions in the list with
|
|
// ** ExprList.a[].u.x.iOrderByCol>0 have already been evaluated and stored
|
|
// ** in registers at srcReg, and so the value can be copied from there.
|
|
// ** If SQLITE_ECEL_OMITREF is also set, then the values with u.x.iOrderByCol>0
|
|
// ** are simply omitted rather than being copied from srcReg.
|
|
// */
|
|
func _sqlite3ExprCodeExprList(tls *libc.TLS, pParse uintptr, pList uintptr, target int32, srcReg int32, flags Tu8) (r int32) {
|
|
var copyOp Tu8
|
|
var i, inReg, j, n, v1 int32
|
|
var pExpr, pItem, pOp, v, v5 uintptr
|
|
var v4 bool
|
|
_, _, _, _, _, _, _, _, _, _, _, _ = copyOp, i, inReg, j, n, pExpr, pItem, pOp, v, v1, v4, v5
|
|
if libc.Int32FromUint8(flags)&int32(SQLITE_ECEL_DUP) != 0 {
|
|
v1 = int32(OP_Copy)
|
|
} else {
|
|
v1 = int32(OP_SCopy)
|
|
}
|
|
copyOp = libc.Uint8FromInt32(v1)
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
/* Never gets this far otherwise */
|
|
n = (*TExprList)(unsafe.Pointer(pList)).FnExpr
|
|
if !(int32(Tbft(*(*uint16)(unsafe.Pointer(pParse + 40))&0x80>>7)) != 0) {
|
|
flags = libc.Uint8FromInt32(int32(flags) & ^libc.Int32FromInt32(SQLITE_ECEL_FACTOR))
|
|
}
|
|
pItem = pList + 8
|
|
i = libc.Int32FromInt32(0)
|
|
for {
|
|
if !(i < n) {
|
|
break
|
|
}
|
|
pExpr = (*TExprList_item)(unsafe.Pointer(pItem)).FpExpr
|
|
if v4 = libc.Int32FromUint8(flags)&int32(SQLITE_ECEL_REF) != 0; v4 {
|
|
v1 = libc.Int32FromUint16((*(*struct {
|
|
FiOrderByCol Tu16
|
|
FiAlias Tu16
|
|
})(unsafe.Pointer(pItem + 24))).FiOrderByCol)
|
|
j = v1
|
|
}
|
|
if v4 && v1 > 0 {
|
|
if libc.Int32FromUint8(flags)&int32(SQLITE_ECEL_OMITREF) != 0 {
|
|
i = i - 1
|
|
n = n - 1
|
|
} else {
|
|
_sqlite3VdbeAddOp2(tls, v, libc.Int32FromUint8(copyOp), j+srcReg-int32(1), target+i)
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint8(flags)&int32(SQLITE_ECEL_FACTOR) != 0 && _sqlite3ExprIsConstantNotJoin(tls, pParse, pExpr) != 0 {
|
|
_sqlite3ExprCodeRunJustOnce(tls, pParse, pExpr, target+i)
|
|
} else {
|
|
inReg = _sqlite3ExprCodeTarget(tls, pParse, pExpr, target+i)
|
|
if inReg != target+i {
|
|
if v4 = libc.Int32FromUint8(copyOp) == int32(OP_Copy); v4 {
|
|
v5 = _sqlite3VdbeGetLastOp(tls, v)
|
|
pOp = v5
|
|
}
|
|
if v4 && libc.Int32FromUint8((*TVdbeOp)(unsafe.Pointer(v5)).Fopcode) == int32(OP_Copy) && (*TVdbeOp)(unsafe.Pointer(pOp)).Fp1+(*TVdbeOp)(unsafe.Pointer(pOp)).Fp3+int32(1) == inReg && (*TVdbeOp)(unsafe.Pointer(pOp)).Fp2+(*TVdbeOp)(unsafe.Pointer(pOp)).Fp3+int32(1) == target+i && libc.Int32FromUint16((*TVdbeOp)(unsafe.Pointer(pOp)).Fp5) == 0 {
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp3 = (*TVdbeOp)(unsafe.Pointer(pOp)).Fp3 + 1
|
|
} else {
|
|
_sqlite3VdbeAddOp2(tls, v, libc.Int32FromUint8(copyOp), inReg, target+i)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
pItem += 32
|
|
}
|
|
return n
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code that will evaluate expression pExpr just one time
|
|
// ** per prepared statement execution.
|
|
// **
|
|
// ** If the expression uses functions (that might throw an exception) then
|
|
// ** guard them with an OP_Once opcode to ensure that the code is only executed
|
|
// ** once. If no functions are involved, then factor the code out and put it at
|
|
// ** the end of the prepared statement in the initialization section.
|
|
// **
|
|
// ** If regDest>0 then the result is always stored in that register and the
|
|
// ** result is not reusable. If regDest<0 then this routine is free to
|
|
// ** store the value wherever it wants. The register where the expression
|
|
// ** is stored is returned. When regDest<0, two identical expressions might
|
|
// ** code to the same register, if they do not contain function calls and hence
|
|
// ** are factored out into the initialization section at the end of the
|
|
// ** prepared statement.
|
|
// */
|
|
func _sqlite3ExprCodeRunJustOnce(tls *libc.TLS, pParse uintptr, pExpr uintptr, regDest int32) (r int32) {
|
|
var addr, i, v2 int32
|
|
var p, pItem, pItem1, v, v3 uintptr
|
|
_, _, _, _, _, _, _, _ = addr, i, p, pItem, pItem1, v, v2, v3
|
|
p = (*TParse)(unsafe.Pointer(pParse)).FpConstExpr
|
|
if regDest < 0 && p != 0 {
|
|
pItem = p + 8
|
|
i = (*TExprList)(unsafe.Pointer(p)).FnExpr
|
|
for {
|
|
if !(i > 0) {
|
|
break
|
|
}
|
|
if int32(uint32(*(*uint16)(unsafe.Pointer(pItem + 16 + 4))&0x8>>3)) != 0 && _sqlite3ExprCompare(tls, uintptr(0), (*TExprList_item)(unsafe.Pointer(pItem)).FpExpr, pExpr, -int32(1)) == 0 {
|
|
return *(*int32)(unsafe.Pointer(pItem + 24))
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
pItem += 32
|
|
i = i - 1
|
|
}
|
|
}
|
|
pExpr = _sqlite3ExprDup(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pExpr, 0)
|
|
if pExpr != uintptr(0) && (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_HasFunc)) != uint32(0) {
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
addr = _sqlite3VdbeAddOp0(tls, v, int32(OP_Once))
|
|
libc.SetBitFieldPtr16Uint32(pParse+40, libc.Uint32FromInt32(0), 7, 0x80)
|
|
if !((*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).FmallocFailed != 0) {
|
|
if regDest < 0 {
|
|
v3 = pParse + 60
|
|
*(*int32)(unsafe.Pointer(v3)) = *(*int32)(unsafe.Pointer(v3)) + 1
|
|
v2 = *(*int32)(unsafe.Pointer(v3))
|
|
regDest = v2
|
|
}
|
|
_sqlite3ExprCode(tls, pParse, pExpr, regDest)
|
|
}
|
|
libc.SetBitFieldPtr16Uint32(pParse+40, libc.Uint32FromInt32(1), 7, 0x80)
|
|
_sqlite3ExprDelete(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pExpr)
|
|
_sqlite3VdbeJumpHere(tls, v, addr)
|
|
} else {
|
|
p = _sqlite3ExprListAppend(tls, pParse, p, pExpr)
|
|
if p != 0 {
|
|
pItem1 = p + 8 + uintptr((*TExprList)(unsafe.Pointer(p)).FnExpr-int32(1))*32
|
|
libc.SetBitFieldPtr16Uint32(pItem1+16+4, libc.BoolUint32(regDest < libc.Int32FromInt32(0)), 3, 0x8)
|
|
if regDest < 0 {
|
|
v3 = pParse + 60
|
|
*(*int32)(unsafe.Pointer(v3)) = *(*int32)(unsafe.Pointer(v3)) + 1
|
|
v2 = *(*int32)(unsafe.Pointer(v3))
|
|
regDest = v2
|
|
}
|
|
*(*int32)(unsafe.Pointer(pItem1 + 24)) = regDest
|
|
}
|
|
(*TParse)(unsafe.Pointer(pParse)).FpConstExpr = p
|
|
}
|
|
return regDest
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code to evaluate an expression and store the results
|
|
// ** into a register. Return the register number where the results
|
|
// ** are stored.
|
|
// **
|
|
// ** If the register is a temporary register that can be deallocated,
|
|
// ** then write its number into *pReg. If the result register is not
|
|
// ** a temporary, then set *pReg to zero.
|
|
// **
|
|
// ** If pExpr is a constant, then this routine might generate this
|
|
// ** code to fill the register in the initialization section of the
|
|
// ** VDBE program, in order to factor it out of the evaluation loop.
|
|
// */
|
|
func _sqlite3ExprCodeTemp(tls *libc.TLS, pParse uintptr, pExpr uintptr, pReg uintptr) (r int32) {
|
|
var r1, r2 int32
|
|
_, _ = r1, r2
|
|
pExpr = _sqlite3ExprSkipCollateAndLikely(tls, pExpr)
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(pParse + 40))&0x80>>7)) != 0 && pExpr != uintptr(0) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) != int32(TK_REGISTER) && _sqlite3ExprIsConstantNotJoin(tls, pParse, pExpr) != 0 {
|
|
**(**int32)(__ccgo_up(pReg)) = 0
|
|
r2 = _sqlite3ExprCodeRunJustOnce(tls, pParse, pExpr, -int32(1))
|
|
} else {
|
|
r1 = _sqlite3GetTempReg(tls, pParse)
|
|
r2 = _sqlite3ExprCodeTarget(tls, pParse, pExpr, r1)
|
|
if r2 == r1 {
|
|
**(**int32)(__ccgo_up(pReg)) = r1
|
|
} else {
|
|
_sqlite3ReleaseTempReg(tls, pParse, r1)
|
|
**(**int32)(__ccgo_up(pReg)) = 0
|
|
}
|
|
}
|
|
return r2
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The argument is guaranteed to be a non-NULL Expr node of type TK_COLUMN.
|
|
// ** return the appropriate colUsed mask.
|
|
// */
|
|
func _sqlite3ExprColUsed(tls *libc.TLS, pExpr uintptr) (r TBitmask) {
|
|
var n int32
|
|
var pExTab uintptr
|
|
var v1 uint64
|
|
_, _, _ = n, pExTab, v1
|
|
n = int32((*TExpr)(unsafe.Pointer(pExpr)).FiColumn)
|
|
pExTab = *(*uintptr)(unsafe.Pointer(pExpr + 64))
|
|
if (*TTable)(unsafe.Pointer(pExTab)).FtabFlags&uint32(TF_HasGenerated) != uint32(0) && libc.Int32FromUint16((**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pExTab)).FaCol + uintptr(n)*16))).FcolFlags)&int32(COLFLAG_GENERATED) != 0 {
|
|
if int32((*TTable)(unsafe.Pointer(pExTab)).FnCol) >= libc.Int32FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(8)) {
|
|
v1 = libc.Uint64FromInt32(-libc.Int32FromInt32(1))
|
|
} else {
|
|
v1 = libc.Uint64FromInt32(1)<<(*TTable)(unsafe.Pointer(pExTab)).FnCol - uint64(1)
|
|
}
|
|
return v1
|
|
} else {
|
|
if n >= libc.Int32FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(8)) {
|
|
n = libc.Int32FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(8)) - libc.Int32FromInt32(1)
|
|
}
|
|
return libc.Uint64FromInt32(1) << n
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Do a deep comparison of two expression trees. Return 0 if the two
|
|
// ** expressions are completely identical. Return 1 if they differ only
|
|
// ** by a COLLATE operator at the top level. Return 2 if there are differences
|
|
// ** other than the top-level COLLATE operator.
|
|
// **
|
|
// ** If any subelement of pB has Expr.iTable==(-1) then it is allowed
|
|
// ** to compare equal to an equivalent element in pA with Expr.iTable==iTab.
|
|
// **
|
|
// ** The pA side might be using TK_REGISTER. If that is the case and pB is
|
|
// ** not using TK_REGISTER but is otherwise equivalent, then still return 0.
|
|
// **
|
|
// ** Sometimes this routine will return 2 even if the two expressions
|
|
// ** really are equivalent. If we cannot prove that the expressions are
|
|
// ** identical, we return 2 just to be safe. So if this routine
|
|
// ** returns 2, then you do not really know for certain if the two
|
|
// ** expressions are the same. But if you get a 0 or 1 return, then you
|
|
// ** can be sure the expressions are the same. In the places where
|
|
// ** this routine is used, it does not hurt to get an extra 2 - that
|
|
// ** just might result in some slightly slower code. But returning
|
|
// ** an incorrect 0 or 1 could lead to a malfunction.
|
|
// **
|
|
// ** If pParse is not NULL and SQLITE_EnableQPSG is off then TK_VARIABLE
|
|
// ** terms in pA with bindings in pParse->pReprepare can be matched against
|
|
// ** literals in pB. The pParse->pVdbe->expmask bitmask is updated for
|
|
// ** each variable referenced.
|
|
// */
|
|
func _sqlite3ExprCompare(tls *libc.TLS, pParse uintptr, pA uintptr, pB uintptr, iTab int32) (r int32) {
|
|
var combinedFlags Tu32
|
|
var v1 int32
|
|
_, _ = combinedFlags, v1
|
|
if pA == uintptr(0) || pB == uintptr(0) {
|
|
if pB == pA {
|
|
v1 = 0
|
|
} else {
|
|
v1 = int32(2)
|
|
}
|
|
return v1
|
|
}
|
|
if pParse != 0 && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pA)).Fop) == int32(TK_VARIABLE) {
|
|
return _exprCompareVariable(tls, pParse, pA, pB)
|
|
}
|
|
combinedFlags = (*TExpr)(unsafe.Pointer(pA)).Fflags | (*TExpr)(unsafe.Pointer(pB)).Fflags
|
|
if combinedFlags&uint32(EP_IntValue) != 0 {
|
|
if (*TExpr)(unsafe.Pointer(pA)).Fflags&(*TExpr)(unsafe.Pointer(pB)).Fflags&uint32(EP_IntValue) != uint32(0) && *(*int32)(unsafe.Pointer(&(*TExpr)(unsafe.Pointer(pA)).Fu)) == *(*int32)(unsafe.Pointer(&(*TExpr)(unsafe.Pointer(pB)).Fu)) {
|
|
return 0
|
|
}
|
|
return int32(2)
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pA)).Fop) != libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pB)).Fop) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pA)).Fop) == int32(TK_RAISE) {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pA)).Fop) == int32(TK_COLLATE) && _sqlite3ExprCompare(tls, pParse, (*TExpr)(unsafe.Pointer(pA)).FpLeft, pB, iTab) < int32(2) {
|
|
return int32(1)
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pB)).Fop) == int32(TK_COLLATE) && _sqlite3ExprCompare(tls, pParse, pA, (*TExpr)(unsafe.Pointer(pB)).FpLeft, iTab) < int32(2) {
|
|
return int32(1)
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pA)).Fop) == int32(TK_AGG_COLUMN) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pB)).Fop) == int32(TK_COLUMN) && (*TExpr)(unsafe.Pointer(pB)).FiTable < 0 && (*TExpr)(unsafe.Pointer(pA)).FiTable == iTab {
|
|
/* fall through */
|
|
} else {
|
|
return int32(2)
|
|
}
|
|
}
|
|
if *(*uintptr)(unsafe.Pointer(pA + 8)) != 0 {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pA)).Fop) == int32(TK_FUNCTION) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pA)).Fop) == int32(TK_AGG_FUNCTION) {
|
|
if _sqlite3StrICmp(tls, *(*uintptr)(unsafe.Pointer(pA + 8)), *(*uintptr)(unsafe.Pointer(pB + 8))) != 0 {
|
|
return int32(2)
|
|
}
|
|
if libc.BoolInt32((*TExpr)(unsafe.Pointer(pA)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_WinFunc)) != uint32(0)) != libc.BoolInt32((*TExpr)(unsafe.Pointer(pB)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_WinFunc)) != uint32(0)) {
|
|
return int32(2)
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pA)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_WinFunc)) != uint32(0) {
|
|
if _sqlite3WindowCompare(tls, pParse, *(*uintptr)(unsafe.Pointer(pA + 64)), *(*uintptr)(unsafe.Pointer(pB + 64)), int32(1)) != 0 {
|
|
return int32(2)
|
|
}
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pA)).Fop) == int32(TK_NULL) {
|
|
return 0
|
|
} else {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pA)).Fop) == int32(TK_COLLATE) {
|
|
if Xsqlite3_stricmp(tls, *(*uintptr)(unsafe.Pointer(pA + 8)), *(*uintptr)(unsafe.Pointer(pB + 8))) != 0 {
|
|
return int32(2)
|
|
}
|
|
} else {
|
|
if *(*uintptr)(unsafe.Pointer(pB + 8)) != uintptr(0) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pA)).Fop) != int32(TK_COLUMN) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pA)).Fop) != int32(TK_AGG_COLUMN) && libc.Xstrcmp(tls, *(*uintptr)(unsafe.Pointer(pA + 8)), *(*uintptr)(unsafe.Pointer(pB + 8))) != 0 {
|
|
return int32(2)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pA)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Distinct)|libc.Int32FromInt32(EP_Commuted)) != (*TExpr)(unsafe.Pointer(pB)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Distinct)|libc.Int32FromInt32(EP_Commuted)) {
|
|
return int32(2)
|
|
}
|
|
if combinedFlags&uint32(EP_TokenOnly) == uint32(0) {
|
|
if combinedFlags&uint32(EP_xIsSelect) != 0 {
|
|
return int32(2)
|
|
}
|
|
if combinedFlags&uint32(EP_FixedCol) == uint32(0) && _sqlite3ExprCompare(tls, pParse, (*TExpr)(unsafe.Pointer(pA)).FpLeft, (*TExpr)(unsafe.Pointer(pB)).FpLeft, iTab) != 0 {
|
|
return int32(2)
|
|
}
|
|
if _sqlite3ExprCompare(tls, pParse, (*TExpr)(unsafe.Pointer(pA)).FpRight, (*TExpr)(unsafe.Pointer(pB)).FpRight, iTab) != 0 {
|
|
return int32(2)
|
|
}
|
|
if _sqlite3ExprListCompare(tls, *(*uintptr)(unsafe.Pointer(pA + 32)), *(*uintptr)(unsafe.Pointer(pB + 32)), iTab) != 0 {
|
|
return int32(2)
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pA)).Fop) != int32(TK_STRING) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pA)).Fop) != int32(TK_TRUEFALSE) && combinedFlags&uint32(EP_Reduced) == uint32(0) {
|
|
if int32((*TExpr)(unsafe.Pointer(pA)).FiColumn) != int32((*TExpr)(unsafe.Pointer(pB)).FiColumn) {
|
|
return int32(2)
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pA)).Fop2) != libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pB)).Fop2) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pA)).Fop) == int32(TK_TRUTH) {
|
|
return int32(2)
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pA)).Fop) != int32(TK_IN) && (*TExpr)(unsafe.Pointer(pA)).FiTable != (*TExpr)(unsafe.Pointer(pB)).FiTable && (*TExpr)(unsafe.Pointer(pA)).FiTable != iTab {
|
|
return int32(2)
|
|
}
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Recursively delete an expression tree.
|
|
// */
|
|
func _sqlite3ExprDeleteNN(tls *libc.TLS, db uintptr, p uintptr) {
|
|
var pLeft uintptr
|
|
_ = pLeft
|
|
goto exprDeleteRestart
|
|
exprDeleteRestart:
|
|
;
|
|
if !((*TExpr)(unsafe.Pointer(p)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_TokenOnly)|libc.Int32FromInt32(EP_Leaf)) != libc.Uint32FromInt32(0)) {
|
|
/* The Expr.x union is never used at the same time as Expr.pRight */
|
|
if (*TExpr)(unsafe.Pointer(p)).FpRight != 0 {
|
|
_sqlite3ExprDeleteNN(tls, db, (*TExpr)(unsafe.Pointer(p)).FpRight)
|
|
} else {
|
|
if (*TExpr)(unsafe.Pointer(p)).Fflags&uint32(EP_xIsSelect) != uint32(0) {
|
|
_sqlite3SelectDelete(tls, db, *(*uintptr)(unsafe.Pointer(p + 32)))
|
|
} else {
|
|
_sqlite3ExprListDelete(tls, db, *(*uintptr)(unsafe.Pointer(p + 32)))
|
|
if (*TExpr)(unsafe.Pointer(p)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_WinFunc)) != uint32(0) {
|
|
_sqlite3WindowDelete(tls, db, *(*uintptr)(unsafe.Pointer(p + 64)))
|
|
}
|
|
}
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(p)).FpLeft != 0 && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) != int32(TK_SELECT_COLUMN) {
|
|
pLeft = (*TExpr)(unsafe.Pointer(p)).FpLeft
|
|
if !((*TExpr)(unsafe.Pointer(p)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Static)) != libc.Uint32FromInt32(0)) && !((*TExpr)(unsafe.Pointer(pLeft)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Static)) != libc.Uint32FromInt32(0)) {
|
|
/* Avoid unnecessary recursion on unary operators */
|
|
_sqlite3DbNNFreeNN(tls, db, p)
|
|
p = pLeft
|
|
goto exprDeleteRestart
|
|
} else {
|
|
_sqlite3ExprDeleteNN(tls, db, pLeft)
|
|
}
|
|
}
|
|
}
|
|
if !((*TExpr)(unsafe.Pointer(p)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Static)) != libc.Uint32FromInt32(0)) {
|
|
_sqlite3DbNNFreeNN(tls, db, p)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compute and return a new Expr object which when passed to
|
|
// ** sqlite3ExprCode() will generate all necessary code to compute
|
|
// ** the iField-th column of the vector expression pVector.
|
|
// **
|
|
// ** It is ok for pVector to be a scalar (as long as iField==0).
|
|
// ** In that case, this routine works like sqlite3ExprDup().
|
|
// **
|
|
// ** The caller owns the returned Expr object and is responsible for
|
|
// ** ensuring that the returned value eventually gets freed.
|
|
// **
|
|
// ** The caller retains ownership of pVector. If pVector is a TK_SELECT,
|
|
// ** then the returned object will reference pVector and so pVector must remain
|
|
// ** valid for the life of the returned object. If pVector is a TK_VECTOR
|
|
// ** or a scalar expression, then it can be deleted as soon as this routine
|
|
// ** returns.
|
|
// **
|
|
// ** A trick to cause a TK_SELECT pVector to be deleted together with
|
|
// ** the returned Expr object is to attach the pVector to the pRight field
|
|
// ** of the returned TK_SELECT_COLUMN Expr object.
|
|
// */
|
|
func _sqlite3ExprForVectorField(tls *libc.TLS, pParse uintptr, pVector uintptr, iField int32, nField int32) (r uintptr) {
|
|
var pRet, ppVector uintptr
|
|
_, _ = pRet, ppVector
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pVector)).Fop) == int32(TK_SELECT) {
|
|
/* The TK_SELECT_COLUMN Expr node:
|
|
**
|
|
** pLeft: pVector containing TK_SELECT. Not deleted.
|
|
** pRight: not used. But recursively deleted.
|
|
** iColumn: Index of a column in pVector
|
|
** iTable: 0 or the number of columns on the LHS of an assignment
|
|
** pLeft->iTable: First in an array of register holding result, or 0
|
|
** if the result is not yet computed.
|
|
**
|
|
** sqlite3ExprDelete() specifically skips the recursive delete of
|
|
** pLeft on TK_SELECT_COLUMN nodes. But pRight is followed, so pVector
|
|
** can be attached to pRight to cause this node to take ownership of
|
|
** pVector. Typically there will be multiple TK_SELECT_COLUMN nodes
|
|
** with the same pLeft pointer to the pVector, but only one of them
|
|
** will own the pVector.
|
|
*/
|
|
pRet = _sqlite3PExpr(tls, pParse, int32(TK_SELECT_COLUMN), uintptr(0), uintptr(0))
|
|
if pRet != 0 {
|
|
**(**Tu32)(__ccgo_up(pRet + 4)) |= libc.Uint32FromInt32(libc.Int32FromInt32(EP_FullSize))
|
|
(*TExpr)(unsafe.Pointer(pRet)).FiTable = nField
|
|
(*TExpr)(unsafe.Pointer(pRet)).FiColumn = int16(iField)
|
|
(*TExpr)(unsafe.Pointer(pRet)).FpLeft = pVector
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pVector)).Fop) == int32(TK_VECTOR) {
|
|
ppVector = *(*uintptr)(unsafe.Pointer(pVector + 32)) + 8 + uintptr(iField)*32
|
|
pVector = **(**uintptr)(__ccgo_up(ppVector))
|
|
if libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) >= int32(PARSE_MODE_RENAME) {
|
|
/* This must be a vector UPDATE inside a trigger */
|
|
**(**uintptr)(__ccgo_up(ppVector)) = uintptr(0)
|
|
return pVector
|
|
}
|
|
}
|
|
pRet = _sqlite3ExprDup(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pVector, 0)
|
|
}
|
|
return pRet
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if we can prove the pE2 will always be true if pE1 is
|
|
// ** true. Return false if we cannot complete the proof or if pE2 might
|
|
// ** be false. Examples:
|
|
// **
|
|
// ** pE1: x==5 pE2: x==5 Result: true
|
|
// ** pE1: x>0 pE2: x==5 Result: false
|
|
// ** pE1: x=21 pE2: x=21 OR y=43 Result: true
|
|
// ** pE1: x!=123 pE2: x IS NOT NULL Result: true
|
|
// ** pE1: x!=?1 pE2: x IS NOT NULL Result: true
|
|
// ** pE1: x IS NULL pE2: x IS NOT NULL Result: false
|
|
// ** pE1: x IS ?2 pE2: x IS NOT NULL Result: false
|
|
// ** pE1: iif(x,y) pE2: x Result: true
|
|
// ** PE1: iif(x,y,0) pE2: x Result: true
|
|
// **
|
|
// ** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has
|
|
// ** Expr.iTable<0 then assume a table number given by iTab.
|
|
// **
|
|
// ** If pParse is not NULL, then the values of bound variables in pE1 are
|
|
// ** compared against literal values in pE2 and pParse->pVdbe->expmask is
|
|
// ** modified to record which bound variables are referenced. If pParse
|
|
// ** is NULL, then false will be returned if pE1 contains any bound variables.
|
|
// **
|
|
// ** When in doubt, return false. Returning true might give a performance
|
|
// ** improvement. Returning false might cause a performance reduction, but
|
|
// ** it will always give the correct answer and is hence always safe.
|
|
// */
|
|
func _sqlite3ExprImpliesExpr(tls *libc.TLS, pParse uintptr, pE1 uintptr, pE2 uintptr, iTab int32) (r int32) {
|
|
if _sqlite3ExprCompare(tls, pParse, pE1, pE2, iTab) == 0 {
|
|
return int32(1)
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pE2)).Fop) == int32(TK_OR) && (_sqlite3ExprImpliesExpr(tls, pParse, pE1, (*TExpr)(unsafe.Pointer(pE2)).FpLeft, iTab) != 0 || _sqlite3ExprImpliesExpr(tls, pParse, pE1, (*TExpr)(unsafe.Pointer(pE2)).FpRight, iTab) != 0) {
|
|
return int32(1)
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pE2)).Fop) == int32(TK_NOTNULL) && _exprImpliesNotNull(tls, pParse, pE1, (*TExpr)(unsafe.Pointer(pE2)).FpLeft, iTab, 0) != 0 {
|
|
return int32(1)
|
|
}
|
|
if _sqlite3ExprIsIIF(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pE1) != 0 {
|
|
return _sqlite3ExprImpliesExpr(tls, pParse, (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pE1 + 32)) + 8))).FpExpr, pE2, iTab)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true (non-zero) if expression p can only be true if at least
|
|
// ** one column of table iTab is non-null. In other words, return true
|
|
// ** if expression p will always be NULL or false if every column of iTab
|
|
// ** is NULL.
|
|
// **
|
|
// ** False negatives are acceptable. In other words, it is ok to return
|
|
// ** zero even if expression p will never be true of every column of iTab
|
|
// ** is NULL. A false negative is merely a missed optimization opportunity.
|
|
// **
|
|
// ** False positives are not allowed, however. A false positive may result
|
|
// ** in an incorrect answer.
|
|
// **
|
|
// ** Terms of p that are marked with EP_OuterON (and hence that come from
|
|
// ** the ON or USING clauses of OUTER JOINS) are excluded from the analysis.
|
|
// **
|
|
// ** This routine is used to check if a LEFT JOIN can be converted into
|
|
// ** an ordinary JOIN. The p argument is the WHERE clause. If the WHERE
|
|
// ** clause requires that some column of the right table of the LEFT JOIN
|
|
// ** be non-NULL, then the LEFT JOIN can be safely converted into an
|
|
// ** ordinary join.
|
|
// */
|
|
func _sqlite3ExprImpliesNonNullRow(tls *libc.TLS, p uintptr, iTab int32, isRJ int32) (r int32) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var _ /* w at bp+0 */ TWalker
|
|
p = _sqlite3ExprSkipCollateAndLikely(tls, p)
|
|
if p == uintptr(0) {
|
|
return 0
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) == int32(TK_NOTNULL) {
|
|
p = (*TExpr)(unsafe.Pointer(p)).FpLeft
|
|
} else {
|
|
for libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) == int32(TK_AND) {
|
|
if _sqlite3ExprImpliesNonNullRow(tls, (*TExpr)(unsafe.Pointer(p)).FpLeft, iTab, isRJ) != 0 {
|
|
return int32(1)
|
|
}
|
|
p = (*TExpr)(unsafe.Pointer(p)).FpRight
|
|
}
|
|
}
|
|
(**(**TWalker)(__ccgo_up(bp))).FxExprCallback = __ccgo_fp(_impliesNotNullRow)
|
|
(**(**TWalker)(__ccgo_up(bp))).FxSelectCallback = uintptr(0)
|
|
(**(**TWalker)(__ccgo_up(bp))).FxSelectCallback2 = uintptr(0)
|
|
(**(**TWalker)(__ccgo_up(bp))).FeCode = uint16(0)
|
|
(**(**TWalker)(__ccgo_up(bp))).FmWFlags = libc.BoolUint16(isRJ != 0)
|
|
*(*int32)(unsafe.Pointer(bp + 40)) = iTab
|
|
_sqlite3WalkExpr(tls, bp, p)
|
|
return libc.Int32FromUint16((**(**TWalker)(__ccgo_up(bp))).FeCode)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Walk the expression tree passed as the first argument. Return non-zero
|
|
// ** if the expression consists entirely of constants or copies of terms
|
|
// ** in pGroupBy that sort with the BINARY collation sequence.
|
|
// **
|
|
// ** This routine is used to determine if a term of the HAVING clause can
|
|
// ** be promoted into the WHERE clause. In order for such a promotion to work,
|
|
// ** the value of the HAVING clause term must be the same for all members of
|
|
// ** a "group". The requirement that the GROUP BY term must be BINARY
|
|
// ** assumes that no other collating sequence will have a finer-grained
|
|
// ** grouping than binary. In other words (A=B COLLATE binary) implies
|
|
// ** A=B in every other collating sequence. The requirement that the
|
|
// ** GROUP BY be BINARY is stricter than necessary. It would also work
|
|
// ** to promote HAVING clauses that use the same alternative collating
|
|
// ** sequence as the GROUP BY term, but that is much harder to check,
|
|
// ** alternative collating sequences are uncommon, and this is only an
|
|
// ** optimization, so we take the easy way out and simply require the
|
|
// ** GROUP BY to use the BINARY collating sequence.
|
|
// */
|
|
func _sqlite3ExprIsConstantOrGroupBy(tls *libc.TLS, pParse uintptr, p uintptr, pGroupBy uintptr) (r int32) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var _ /* w at bp+0 */ TWalker
|
|
(**(**TWalker)(__ccgo_up(bp))).FeCode = uint16(1)
|
|
(**(**TWalker)(__ccgo_up(bp))).FxExprCallback = __ccgo_fp(_exprNodeIsConstantOrGroupBy)
|
|
(**(**TWalker)(__ccgo_up(bp))).FxSelectCallback = uintptr(0)
|
|
*(*uintptr)(unsafe.Pointer(bp + 40)) = pGroupBy
|
|
(**(**TWalker)(__ccgo_up(bp))).FpParse = pParse
|
|
_sqlite3WalkExpr(tls, bp, p)
|
|
return libc.Int32FromUint16((**(**TWalker)(__ccgo_up(bp))).FeCode)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If the expression p codes a constant integer that is small enough
|
|
// ** to fit in a 32-bit integer, return 1 and put the value of the integer
|
|
// ** in *pValue. If the expression is not an integer or if it is too big
|
|
// ** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged.
|
|
// **
|
|
// ** If the pParse pointer is provided, then allow the expression p to be
|
|
// ** a parameter (TK_VARIABLE) that is bound to an integer.
|
|
// ** But if pParse is NULL, then p must be a pure integer literal.
|
|
// */
|
|
func _sqlite3ExprIsInteger(tls *libc.TLS, p uintptr, pValue uintptr, pParse uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var pVal uintptr
|
|
var rc int32
|
|
var vv Tsqlite3_int64
|
|
var _ /* v at bp+0 */ int32
|
|
_, _, _ = pVal, rc, vv
|
|
rc = 0
|
|
if p == uintptr(0) {
|
|
return 0
|
|
} /* Used to only happen following on OOM */
|
|
/* If an expression is an integer literal that fits in a signed 32-bit
|
|
** integer, then the EP_IntValue flag will have already been set */
|
|
if (*TExpr)(unsafe.Pointer(p)).Fflags&uint32(EP_IntValue) != 0 {
|
|
**(**int32)(__ccgo_up(pValue)) = *(*int32)(unsafe.Pointer(&(*TExpr)(unsafe.Pointer(p)).Fu))
|
|
return int32(1)
|
|
}
|
|
switch libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) {
|
|
case int32(TK_UPLUS):
|
|
rc = _sqlite3ExprIsInteger(tls, (*TExpr)(unsafe.Pointer(p)).FpLeft, pValue, uintptr(0))
|
|
case int32(TK_UMINUS):
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
if _sqlite3ExprIsInteger(tls, (*TExpr)(unsafe.Pointer(p)).FpLeft, bp, uintptr(0)) != 0 {
|
|
**(**int32)(__ccgo_up(pValue)) = -**(**int32)(__ccgo_up(bp))
|
|
rc = int32(1)
|
|
}
|
|
case int32(TK_VARIABLE):
|
|
if pParse == uintptr(0) {
|
|
break
|
|
}
|
|
if (*TParse)(unsafe.Pointer(pParse)).FpVdbe == uintptr(0) {
|
|
break
|
|
}
|
|
if (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).Fflags&uint64(SQLITE_EnableQPSG) != uint64(0) {
|
|
break
|
|
}
|
|
_sqlite3VdbeSetVarmask(tls, (*TParse)(unsafe.Pointer(pParse)).FpVdbe, int32((*TExpr)(unsafe.Pointer(p)).FiColumn))
|
|
pVal = _sqlite3VdbeGetBoundValue(tls, (*TParse)(unsafe.Pointer(pParse)).FpReprepare, int32((*TExpr)(unsafe.Pointer(p)).FiColumn), uint8(SQLITE_AFF_BLOB))
|
|
if pVal != 0 {
|
|
if Xsqlite3_value_type(tls, pVal) == int32(SQLITE_INTEGER) {
|
|
vv = Xsqlite3_value_int64(tls, pVal)
|
|
if vv == vv&int64(0x7fffffff) { /* non-negative numbers only */
|
|
**(**int32)(__ccgo_up(pValue)) = int32(vv)
|
|
rc = int32(1)
|
|
}
|
|
}
|
|
_sqlite3ValueFree(tls, pVal)
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If pExpr is one of "like", "glob", "match", or "regexp", then
|
|
// ** return the corresponding SQLITE_INDEX_CONSTRAINT_xxxx value.
|
|
// ** If not, return 0.
|
|
// **
|
|
// ** pExpr is guaranteed to be a TK_FUNCTION.
|
|
// */
|
|
func _sqlite3ExprIsLikeOperator(tls *libc.TLS, pExpr uintptr) (r int32) {
|
|
var i int32
|
|
_ = i
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint64(libc.Uint64FromInt64(64)/libc.Uint64FromInt64(16))) {
|
|
break
|
|
}
|
|
if _sqlite3StrICmp(tls, *(*uintptr)(unsafe.Pointer(pExpr + 8)), _aOp[i].FzOp) == 0 {
|
|
return libc.Int32FromUint8(_aOp[i].FeOp)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Check pExpr to see if it is an constraint on the single data source
|
|
// ** pSrc = &pSrcList->a[iSrc]. In other words, check to see if pExpr
|
|
// ** constrains pSrc but does not depend on any other tables or data
|
|
// ** sources anywhere else in the query. Return true (non-zero) if pExpr
|
|
// ** is a constraint on pSrc only.
|
|
// **
|
|
// ** This is an optimization. False negatives will perhaps cause slower
|
|
// ** queries, but false positives will yield incorrect answers. So when in
|
|
// ** doubt, return 0.
|
|
// **
|
|
// ** To be an single-source constraint, the following must be true:
|
|
// **
|
|
// ** (1) pExpr cannot refer to any table other than pSrc->iCursor.
|
|
// **
|
|
// ** (2a) pExpr cannot use subqueries unless the bAllowSubq parameter is
|
|
// ** true and the subquery is non-correlated
|
|
// **
|
|
// ** (2b) pExpr cannot use non-deterministic functions.
|
|
// **
|
|
// ** (3) pSrc cannot be part of the left operand for a RIGHT JOIN.
|
|
// ** (Is there some way to relax this constraint?)
|
|
// **
|
|
// ** (4) If pSrc is the right operand of a LEFT JOIN, then...
|
|
// ** (4a) pExpr must come from an ON clause..
|
|
// ** (4b) and specifically the ON clause associated with the LEFT JOIN.
|
|
// **
|
|
// ** (5) If pSrc is the right operand of a LEFT JOIN or the left
|
|
// ** operand of a RIGHT JOIN, then pExpr must be from the WHERE
|
|
// ** clause, not an ON clause.
|
|
// **
|
|
// ** (6) Either:
|
|
// **
|
|
// ** (6a) pExpr does not originate in an ON or USING clause, or
|
|
// **
|
|
// ** (6b) The ON or USING clause from which pExpr is derived is
|
|
// ** not to the left of a RIGHT JOIN (or FULL JOIN).
|
|
// **
|
|
// ** Without this restriction, accepting pExpr as a single-table
|
|
// ** constraint might move the the ON/USING filter expression
|
|
// ** from the left side of a RIGHT JOIN over to the right side,
|
|
// ** which leads to incorrect answers. See also restriction (9)
|
|
// ** on push-down.
|
|
// */
|
|
func _sqlite3ExprIsSingleTableConstraint(tls *libc.TLS, pExpr uintptr, pSrcList uintptr, iSrc int32, bAllowSubq int32) (r int32) {
|
|
var jj int32
|
|
var pSrc uintptr
|
|
_, _ = jj, pSrc
|
|
pSrc = pSrcList + 8 + uintptr(iSrc)*80
|
|
if libc.Int32FromUint8((*TSrcItem)(unsafe.Pointer(pSrc)).Ffg.Fjointype)&int32(JT_LTORJ) != 0 {
|
|
return 0 /* rule (3) */
|
|
}
|
|
if libc.Int32FromUint8((*TSrcItem)(unsafe.Pointer(pSrc)).Ffg.Fjointype)&int32(JT_LEFT) != 0 {
|
|
if !((*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)) != libc.Uint32FromInt32(0)) {
|
|
return 0
|
|
} /* rule (4a) */
|
|
if *(*int32)(unsafe.Pointer(pExpr + 52)) != (*TSrcItem)(unsafe.Pointer(pSrc)).FiCursor {
|
|
return 0
|
|
} /* rule (4b) */
|
|
} else {
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)) != uint32(0) {
|
|
return 0
|
|
} /* rule (5) */
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)|libc.Int32FromInt32(EP_InnerON)) != uint32(0) && libc.Int32FromUint8((*(*TSrcItem)(unsafe.Pointer(pSrcList + 8))).Ffg.Fjointype)&int32(JT_LTORJ) != 0 {
|
|
jj = 0
|
|
for {
|
|
if !(jj < iSrc) {
|
|
break
|
|
}
|
|
if *(*int32)(unsafe.Pointer(pExpr + 52)) == (*(*TSrcItem)(unsafe.Pointer(pSrcList + 8 + uintptr(jj)*80))).FiCursor {
|
|
if libc.Int32FromUint8((*(*TSrcItem)(unsafe.Pointer(pSrcList + 8 + uintptr(jj)*80))).Ffg.Fjointype)&int32(JT_LTORJ) != 0 {
|
|
return 0 /* restriction (6) */
|
|
}
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
jj = jj + 1
|
|
}
|
|
}
|
|
/* Rules (1), (2a), and (2b) handled by the following: */
|
|
return _sqlite3ExprIsTableConstant(tls, pExpr, (*TSrcItem)(unsafe.Pointer(pSrc)).FiCursor, bAllowSubq)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Walk an expression tree. Return non-zero if the expression is constant
|
|
// ** for any single row of the table with cursor iCur. In other words, the
|
|
// ** expression must not refer to any non-deterministic function nor any
|
|
// ** table other than iCur.
|
|
// **
|
|
// ** Consider uncorrelated subqueries to be constants if the bAllowSubq
|
|
// ** parameter is true.
|
|
// */
|
|
func _sqlite3ExprIsTableConstant(tls *libc.TLS, p uintptr, iCur int32, bAllowSubq int32) (r int32) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var _ /* w at bp+0 */ TWalker
|
|
(**(**TWalker)(__ccgo_up(bp))).FeCode = uint16(3)
|
|
(**(**TWalker)(__ccgo_up(bp))).FpParse = uintptr(0)
|
|
(**(**TWalker)(__ccgo_up(bp))).FxExprCallback = __ccgo_fp(_exprNodeIsConstant)
|
|
if bAllowSubq != 0 {
|
|
(**(**TWalker)(__ccgo_up(bp))).FxSelectCallback = __ccgo_fp(_exprSelectWalkTableConstant)
|
|
} else {
|
|
(**(**TWalker)(__ccgo_up(bp))).FxSelectCallback = __ccgo_fp(_sqlite3SelectWalkFail)
|
|
}
|
|
*(*int32)(unsafe.Pointer(bp + 40)) = iCur
|
|
_sqlite3WalkExpr(tls, bp, p)
|
|
return libc.Int32FromUint16((**(**TWalker)(__ccgo_up(bp))).FeCode)
|
|
}
|
|
|
|
func _sqlite3ExprListAppendGrow(tls *libc.TLS, db uintptr, pList uintptr, pExpr uintptr) (r uintptr) {
|
|
var pItem, pNew, v2 uintptr
|
|
var v1 int32
|
|
_, _, _, _ = pItem, pNew, v1, v2
|
|
**(**int32)(__ccgo_up(pList + 4)) *= int32(2)
|
|
pNew = _sqlite3DbRealloc(tls, db, pList, uint64(uint64(libc.UintptrFromInt32(0)+8)+libc.Uint64FromInt32((*TExprList)(unsafe.Pointer(pList)).FnAlloc)*libc.Uint64FromInt64(32)))
|
|
if pNew == uintptr(0) {
|
|
_sqlite3ExprListDelete(tls, db, pList)
|
|
_sqlite3ExprDelete(tls, db, pExpr)
|
|
return uintptr(0)
|
|
} else {
|
|
pList = pNew
|
|
}
|
|
v2 = pList
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
pItem = pList + 8 + uintptr(v1)*32
|
|
**(**TExprList_item)(__ccgo_up(pItem)) = _zeroItem
|
|
(*TExprList_item)(unsafe.Pointer(pItem)).FpExpr = pExpr
|
|
return pList
|
|
}
|
|
|
|
func _sqlite3ExprListAppendNew(tls *libc.TLS, db uintptr, pExpr uintptr) (r uintptr) {
|
|
var pItem, pList uintptr
|
|
_, _ = pItem, pList
|
|
pList = _sqlite3DbMallocRawNN(tls, db, uint64(uint64(libc.UintptrFromInt32(0)+8)+libc.Uint64FromInt32(libc.Int32FromInt32(4))*libc.Uint64FromInt64(32)))
|
|
if pList == uintptr(0) {
|
|
_sqlite3ExprDelete(tls, db, pExpr)
|
|
return uintptr(0)
|
|
}
|
|
(*TExprList)(unsafe.Pointer(pList)).FnAlloc = int32(4)
|
|
(*TExprList)(unsafe.Pointer(pList)).FnExpr = int32(1)
|
|
pItem = pList + 8
|
|
**(**TExprList_item)(__ccgo_up(pItem)) = _zeroItem
|
|
(*TExprList_item)(unsafe.Pointer(pItem)).FpExpr = pExpr
|
|
return pList
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compare two ExprList objects. Return 0 if they are identical, 1
|
|
// ** if they are certainly different, or 2 if it is not possible to
|
|
// ** determine if they are identical or not.
|
|
// **
|
|
// ** If any subelement of pB has Expr.iTable==(-1) then it is allowed
|
|
// ** to compare equal to an equivalent element in pA with Expr.iTable==iTab.
|
|
// **
|
|
// ** This routine might return non-zero for equivalent ExprLists. The
|
|
// ** only consequence will be disabled optimizations. But this routine
|
|
// ** must never return 0 if the two ExprList objects are different, or
|
|
// ** a malfunction will result.
|
|
// **
|
|
// ** Two NULL pointers are considered to be the same. But a NULL pointer
|
|
// ** always differs from a non-NULL pointer.
|
|
// */
|
|
func _sqlite3ExprListCompare(tls *libc.TLS, pA uintptr, pB uintptr, iTab int32) (r int32) {
|
|
var i, res, v2 int32
|
|
var pExprA, pExprB uintptr
|
|
_, _, _, _, _ = i, pExprA, pExprB, res, v2
|
|
if pA == uintptr(0) && pB == uintptr(0) {
|
|
return 0
|
|
}
|
|
if pA == uintptr(0) || pB == uintptr(0) {
|
|
return int32(1)
|
|
}
|
|
if (*TExprList)(unsafe.Pointer(pA)).FnExpr != (*TExprList)(unsafe.Pointer(pB)).FnExpr {
|
|
return int32(1)
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(pA)).FnExpr) {
|
|
break
|
|
}
|
|
pExprA = (*(*TExprList_item)(unsafe.Pointer(pA + 8 + uintptr(i)*32))).FpExpr
|
|
pExprB = (*(*TExprList_item)(unsafe.Pointer(pB + 8 + uintptr(i)*32))).FpExpr
|
|
if libc.Int32FromUint8((*(*TExprList_item)(unsafe.Pointer(pA + 8 + uintptr(i)*32))).Ffg.FsortFlags) != libc.Int32FromUint8((*(*TExprList_item)(unsafe.Pointer(pB + 8 + uintptr(i)*32))).Ffg.FsortFlags) {
|
|
return int32(1)
|
|
}
|
|
v2 = _sqlite3ExprCompare(tls, uintptr(0), pExprA, pExprB, iTab)
|
|
res = v2
|
|
if v2 != 0 {
|
|
return res
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func _sqlite3ExprListDup(tls *libc.TLS, db uintptr, p uintptr, flags int32) (r uintptr) {
|
|
var i int32
|
|
var pItem, pNew, pNewExpr, pOldExpr, pOldItem, pPriorSelectColNew, pPriorSelectColOld, v2 uintptr
|
|
var v3 bool
|
|
_, _, _, _, _, _, _, _, _, _ = i, pItem, pNew, pNewExpr, pOldExpr, pOldItem, pPriorSelectColNew, pPriorSelectColOld, v2, v3
|
|
pPriorSelectColOld = uintptr(0)
|
|
pPriorSelectColNew = uintptr(0)
|
|
if p == uintptr(0) {
|
|
return uintptr(0)
|
|
}
|
|
pNew = _sqlite3DbMallocRawNN(tls, db, libc.Uint64FromInt32(_sqlite3DbMallocSize(tls, db, p)))
|
|
if pNew == uintptr(0) {
|
|
return uintptr(0)
|
|
}
|
|
(*TExprList)(unsafe.Pointer(pNew)).FnExpr = (*TExprList)(unsafe.Pointer(p)).FnExpr
|
|
(*TExprList)(unsafe.Pointer(pNew)).FnAlloc = (*TExprList)(unsafe.Pointer(p)).FnAlloc
|
|
pItem = pNew + 8
|
|
pOldItem = p + 8
|
|
i = 0
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(p)).FnExpr) {
|
|
break
|
|
}
|
|
pOldExpr = (*TExprList_item)(unsafe.Pointer(pOldItem)).FpExpr
|
|
(*TExprList_item)(unsafe.Pointer(pItem)).FpExpr = _sqlite3ExprDup(tls, db, pOldExpr, flags)
|
|
if v3 = pOldExpr != 0 && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pOldExpr)).Fop) == int32(TK_SELECT_COLUMN); v3 {
|
|
v2 = (*TExprList_item)(unsafe.Pointer(pItem)).FpExpr
|
|
pNewExpr = v2
|
|
}
|
|
if v3 && v2 != uintptr(0) {
|
|
if (*TExpr)(unsafe.Pointer(pNewExpr)).FpRight != 0 {
|
|
pPriorSelectColOld = (*TExpr)(unsafe.Pointer(pOldExpr)).FpRight
|
|
pPriorSelectColNew = (*TExpr)(unsafe.Pointer(pNewExpr)).FpRight
|
|
(*TExpr)(unsafe.Pointer(pNewExpr)).FpLeft = (*TExpr)(unsafe.Pointer(pNewExpr)).FpRight
|
|
} else {
|
|
if (*TExpr)(unsafe.Pointer(pOldExpr)).FpLeft != pPriorSelectColOld {
|
|
pPriorSelectColOld = (*TExpr)(unsafe.Pointer(pOldExpr)).FpLeft
|
|
pPriorSelectColNew = _sqlite3ExprDup(tls, db, pPriorSelectColOld, flags)
|
|
(*TExpr)(unsafe.Pointer(pNewExpr)).FpRight = pPriorSelectColNew
|
|
}
|
|
(*TExpr)(unsafe.Pointer(pNewExpr)).FpLeft = pPriorSelectColNew
|
|
}
|
|
}
|
|
(*TExprList_item)(unsafe.Pointer(pItem)).FzEName = _sqlite3DbStrDup(tls, db, (*TExprList_item)(unsafe.Pointer(pOldItem)).FzEName)
|
|
(*TExprList_item)(unsafe.Pointer(pItem)).Ffg = (*TExprList_item)(unsafe.Pointer(pOldItem)).Ffg
|
|
(*TExprList_item)(unsafe.Pointer(pItem)).Fu = (*TExprList_item)(unsafe.Pointer(pOldItem)).Fu
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
pItem += 32
|
|
pOldItem += 32
|
|
}
|
|
return pNew
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the ExprList.a[].zEName element of the most recently added item
|
|
// ** on the expression list.
|
|
// **
|
|
// ** pList might be NULL following an OOM error. But pName should never be
|
|
// ** NULL. If a memory allocation fails, the pParse->db->mallocFailed flag
|
|
// ** is set.
|
|
// */
|
|
func _sqlite3ExprListSetName(tls *libc.TLS, pParse uintptr, pList uintptr, pName uintptr, dequote int32) {
|
|
var pItem uintptr
|
|
_ = pItem
|
|
if pList != 0 {
|
|
pItem = pList + 8 + uintptr((*TExprList)(unsafe.Pointer(pList)).FnExpr-int32(1))*32
|
|
(*TExprList_item)(unsafe.Pointer(pItem)).FzEName = _sqlite3DbStrNDup(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, (*TToken)(unsafe.Pointer(pName)).Fz, uint64((*TToken)(unsafe.Pointer(pName)).Fn))
|
|
if dequote != 0 {
|
|
/* If dequote==0, then pName->z does not point to part of a DDL
|
|
** statement handled by the parser. And so no token need be added
|
|
** to the token-map. */
|
|
_sqlite3Dequote(tls, (*TExprList_item)(unsafe.Pointer(pItem)).FzEName)
|
|
if libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) >= int32(PARSE_MODE_RENAME) {
|
|
_sqlite3RenameTokenMap(tls, pParse, (*TExprList_item)(unsafe.Pointer(pItem)).FzEName, pName)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the sort order for the last element on the given ExprList.
|
|
// */
|
|
func _sqlite3ExprListSetSortOrder(tls *libc.TLS, p uintptr, iSortOrder int32, eNulls int32) {
|
|
var pItem, v1 uintptr
|
|
_, _ = pItem, v1
|
|
if p == uintptr(0) {
|
|
return
|
|
}
|
|
pItem = p + 8 + uintptr((*TExprList)(unsafe.Pointer(p)).FnExpr-int32(1))*32
|
|
if iSortOrder == -int32(1) {
|
|
iSortOrder = SQLITE_SO_ASC
|
|
}
|
|
(*TExprList_item)(unsafe.Pointer(pItem)).Ffg.FsortFlags = libc.Uint8FromInt32(iSortOrder)
|
|
if eNulls != -int32(1) {
|
|
libc.SetBitFieldPtr16Uint32(pItem+16+4, libc.Uint32FromInt32(1), 5, 0x20)
|
|
if iSortOrder != eNulls {
|
|
v1 = pItem + 16
|
|
*(*Tu8)(unsafe.Pointer(v1)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v1))) | libc.Int32FromInt32(KEYINFO_ORDER_BIGNULL))
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the error offset for an Expr node, if possible.
|
|
// */
|
|
func _sqlite3ExprSetErrorOffset(tls *libc.TLS, pExpr uintptr, iOfst int32) {
|
|
if pExpr == uintptr(0) {
|
|
return
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_InnerON)|libc.Int32FromInt32(EP_OuterON)) != uint32(0) {
|
|
return
|
|
}
|
|
*(*int32)(unsafe.Pointer(pExpr + 52)) = iOfst
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Skip over any TK_COLLATE operators and/or any unlikely()
|
|
// ** or likelihood() or likely() functions at the root of an
|
|
// ** expression.
|
|
// */
|
|
func _sqlite3ExprSkipCollateAndLikely(tls *libc.TLS, pExpr uintptr) (r uintptr) {
|
|
for pExpr != 0 && (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Skip)|libc.Int32FromInt32(EP_Unlikely)) != uint32(0) {
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_Unlikely)) != uint32(0) {
|
|
pExpr = (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)) + 8))).FpExpr
|
|
} else {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_COLLATE) {
|
|
pExpr = (*TExpr)(unsafe.Pointer(pExpr)).FpLeft
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return pExpr
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If the expression passed as the only argument is of type TK_VECTOR
|
|
// ** return the number of expressions in the vector. Or, if the expression
|
|
// ** is a sub-select, return the number of columns in the sub-select. For
|
|
// ** any other type of expression, return 1.
|
|
// */
|
|
func _sqlite3ExprVectorSize(tls *libc.TLS, pExpr uintptr) (r int32) {
|
|
var op Tu8
|
|
_ = op
|
|
op = (*TExpr)(unsafe.Pointer(pExpr)).Fop
|
|
if libc.Int32FromUint8(op) == int32(TK_REGISTER) {
|
|
op = (*TExpr)(unsafe.Pointer(pExpr)).Fop2
|
|
}
|
|
if libc.Int32FromUint8(op) == int32(TK_VECTOR) {
|
|
return (*TExprList)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)))).FnExpr
|
|
} else {
|
|
if libc.Int32FromUint8(op) == int32(TK_SELECT) {
|
|
return (*TExprList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)))).FpEList)).FnExpr
|
|
} else {
|
|
return int32(1)
|
|
}
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Parameter zName points to a UTF-8 encoded string nName bytes long.
|
|
// ** Return the CollSeq* pointer for the collation sequence named zName
|
|
// ** for the encoding 'enc' from the database 'db'.
|
|
// **
|
|
// ** If the entry specified is not found and 'create' is true, then create a
|
|
// ** new entry. Otherwise return NULL.
|
|
// **
|
|
// ** A separate function sqlite3LocateCollSeq() is a wrapper around
|
|
// ** this routine. sqlite3LocateCollSeq() invokes the collation factory
|
|
// ** if necessary and generates an error message if the collating sequence
|
|
// ** cannot be found.
|
|
// **
|
|
// ** See also: sqlite3LocateCollSeq(), sqlite3GetCollSeq()
|
|
// */
|
|
func _sqlite3FindCollSeq(tls *libc.TLS, db uintptr, enc Tu8, zName uintptr, create int32) (r uintptr) {
|
|
var pColl uintptr
|
|
_ = pColl
|
|
if zName != 0 {
|
|
pColl = _findCollSeqEntry(tls, db, zName, create)
|
|
if pColl != 0 {
|
|
pColl = pColl + uintptr(libc.Int32FromUint8(enc)-int32(1))*40
|
|
}
|
|
} else {
|
|
pColl = (*Tsqlite3)(unsafe.Pointer(db)).FpDfltColl
|
|
}
|
|
return pColl
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine is called after a single SQL statement has been
|
|
// ** parsed and a VDBE program to execute that statement has been
|
|
// ** prepared. This routine puts the finishing touches on the
|
|
// ** VDBE program and resets the pParse structure for the next
|
|
// ** parse.
|
|
// **
|
|
// ** Note that if an error occurred, it might be the case that
|
|
// ** no VDBE code was generated.
|
|
// */
|
|
func _sqlite3FinishCoding(tls *libc.TLS, pParse uintptr) {
|
|
var addrRewind, i, iDb, reg, v2 int32
|
|
var db, pEL, pRet, pReturning, pSchema, v, vtab uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _, _ = addrRewind, db, i, iDb, pEL, pRet, pReturning, pSchema, reg, v, vtab, v2
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
if (*TParse)(unsafe.Pointer(pParse)).Fnested != 0 {
|
|
return
|
|
}
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr != 0 {
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0 {
|
|
(*TParse)(unsafe.Pointer(pParse)).Frc = int32(SQLITE_NOMEM)
|
|
}
|
|
return
|
|
}
|
|
/* Begin by generating some termination code at the end of the
|
|
** vdbe program
|
|
*/
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
if v == uintptr(0) {
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).Finit1.Fbusy != 0 {
|
|
(*TParse)(unsafe.Pointer(pParse)).Frc = int32(SQLITE_DONE)
|
|
return
|
|
}
|
|
v = _sqlite3GetVdbe(tls, pParse)
|
|
if v == uintptr(0) {
|
|
(*TParse)(unsafe.Pointer(pParse)).Frc = int32(SQLITE_ERROR)
|
|
}
|
|
}
|
|
if v != 0 {
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(pParse + 40))&0x8>>3)) != 0 {
|
|
pReturning = (*(*struct {
|
|
FpReturning uintptr
|
|
})(unsafe.Pointer(&(*TParse)(unsafe.Pointer(pParse)).Fu1))).FpReturning
|
|
if (*TReturning)(unsafe.Pointer(pReturning)).FnRetCol != 0 {
|
|
_sqlite3VdbeAddOp0(tls, v, int32(OP_FkCheck))
|
|
addrRewind = _sqlite3VdbeAddOp1(tls, v, int32(OP_Rewind), (*TReturning)(unsafe.Pointer(pReturning)).FiRetCur)
|
|
reg = (*TReturning)(unsafe.Pointer(pReturning)).FiRetReg
|
|
i = 0
|
|
for {
|
|
if !(i < (*TReturning)(unsafe.Pointer(pReturning)).FnRetCol) {
|
|
break
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Column), (*TReturning)(unsafe.Pointer(pReturning)).FiRetCur, i, reg+i)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_ResultRow), reg, i)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Next), (*TReturning)(unsafe.Pointer(pReturning)).FiRetCur, addrRewind+int32(1))
|
|
_sqlite3VdbeJumpHere(tls, v, addrRewind)
|
|
}
|
|
}
|
|
_sqlite3VdbeAddOp0(tls, v, int32(OP_Halt))
|
|
/* The cookie mask contains one bit for each database file open.
|
|
** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are
|
|
** set for each database that is used. Generate code to start a
|
|
** transaction on each used database and to verify the schema cookie
|
|
** on each used database.
|
|
*/
|
|
_sqlite3VdbeJumpHere(tls, v, 0)
|
|
iDb = 0
|
|
for {
|
|
if libc.BoolInt32((*TParse)(unsafe.Pointer(pParse)).FcookieMask&(libc.Uint32FromInt32(1)<<iDb) != uint32(0)) == 0 {
|
|
goto _3
|
|
}
|
|
_sqlite3VdbeUsesBtree(tls, v, iDb)
|
|
pSchema = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(iDb)*32))).FpSchema
|
|
_sqlite3VdbeAddOp4Int(tls, v, int32(OP_Transaction), iDb, libc.BoolInt32((*TParse)(unsafe.Pointer(pParse)).FwriteMask&(libc.Uint32FromInt32(1)<<iDb) != uint32(0)), (*TSchema)(unsafe.Pointer(pSchema)).Fschema_cookie, (*TSchema)(unsafe.Pointer(pSchema)).FiGeneration)
|
|
if libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).Finit1.Fbusy) == 0 {
|
|
_sqlite3VdbeChangeP5(tls, v, uint16(1))
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
iDb = iDb + 1
|
|
v2 = iDb
|
|
if !(v2 < (*Tsqlite3)(unsafe.Pointer(db)).FnDb) {
|
|
break
|
|
}
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < (*TParse)(unsafe.Pointer(pParse)).FnVtabLock) {
|
|
break
|
|
}
|
|
vtab = _sqlite3GetVTable(tls, db, **(**uintptr)(__ccgo_up((*TParse)(unsafe.Pointer(pParse)).FapVtabLock + uintptr(i)*8)))
|
|
_sqlite3VdbeAddOp4(tls, v, int32(OP_VBegin), 0, 0, 0, vtab, -int32(12))
|
|
goto _4
|
|
_4:
|
|
;
|
|
i = i + 1
|
|
}
|
|
(*TParse)(unsafe.Pointer(pParse)).FnVtabLock = 0
|
|
/* Once all the cookies have been verified and transactions opened,
|
|
** obtain the required table-locks. This is a no-op unless the
|
|
** shared-cache feature is enabled.
|
|
*/
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnTableLock != 0 {
|
|
_codeTableLocks(tls, pParse)
|
|
}
|
|
/* Initialize any AUTOINCREMENT data structures required.
|
|
*/
|
|
if (*TParse)(unsafe.Pointer(pParse)).FpAinc != 0 {
|
|
_sqlite3AutoincrementBegin(tls, pParse)
|
|
}
|
|
/* Code constant expressions that were factored out of inner loops.
|
|
*/
|
|
if (*TParse)(unsafe.Pointer(pParse)).FpConstExpr != 0 {
|
|
pEL = (*TParse)(unsafe.Pointer(pParse)).FpConstExpr
|
|
libc.SetBitFieldPtr16Uint32(pParse+40, libc.Uint32FromInt32(0), 7, 0x80)
|
|
i = 0
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(pEL)).FnExpr) {
|
|
break
|
|
}
|
|
_sqlite3ExprCode(tls, pParse, (*(*TExprList_item)(unsafe.Pointer(pEL + 8 + uintptr(i)*32))).FpExpr, *(*int32)(unsafe.Pointer(pEL + 8 + uintptr(i)*32 + 24)))
|
|
goto _5
|
|
_5:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(pParse + 40))&0x8>>3)) != 0 {
|
|
pRet = (*(*struct {
|
|
FpReturning uintptr
|
|
})(unsafe.Pointer(&(*TParse)(unsafe.Pointer(pParse)).Fu1))).FpReturning
|
|
if (*TReturning)(unsafe.Pointer(pRet)).FnRetCol != 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_OpenEphemeral), (*TReturning)(unsafe.Pointer(pRet)).FiRetCur, (*TReturning)(unsafe.Pointer(pRet)).FnRetCol)
|
|
}
|
|
}
|
|
/* Finally, jump back to the beginning of the executable code. */
|
|
_sqlite3VdbeGoto(tls, v, int32(1))
|
|
}
|
|
/* Get the VDBE program ready for execution
|
|
*/
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr == 0 {
|
|
/* A minimum of one cursor is required if autoincrement is used
|
|
* See ticket [a696379c1f08866] */
|
|
_sqlite3VdbeMakeReady(tls, v, pParse)
|
|
(*TParse)(unsafe.Pointer(pParse)).Frc = int32(SQLITE_DONE)
|
|
} else {
|
|
(*TParse)(unsafe.Pointer(pParse)).Frc = int32(SQLITE_ERROR)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called when inserting, deleting or updating a row of
|
|
// ** table pTab to generate VDBE code to perform foreign key constraint
|
|
// ** processing for the operation.
|
|
// **
|
|
// ** For a DELETE operation, parameter regOld is passed the index of the
|
|
// ** first register in an array of (pTab->nCol+1) registers containing the
|
|
// ** rowid of the row being deleted, followed by each of the column values
|
|
// ** of the row being deleted, from left to right. Parameter regNew is passed
|
|
// ** zero in this case.
|
|
// **
|
|
// ** For an INSERT operation, regOld is passed zero and regNew is passed the
|
|
// ** first register of an array of (pTab->nCol+1) registers containing the new
|
|
// ** row data.
|
|
// **
|
|
// ** For an UPDATE operation, this function is called twice. Once before
|
|
// ** the original record is deleted from the table using the calling convention
|
|
// ** described for DELETE. Then again after the original record is deleted
|
|
// ** but before the new record is inserted using the INSERT convention.
|
|
// */
|
|
func _sqlite3FkCheck(tls *libc.TLS, pParse uintptr, pTab uintptr, regOld int32, regNew int32, aChange uintptr, bChngRowid int32) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var aiCol, db, pFKey, pItem, pSrc, pTo, v, zCol, zDb, v7 uintptr
|
|
var bIgnore, eAction, i, iDb, iFromCol, iJump, iReg, isIgnoreErrors, rcauth, v4 int32
|
|
var _ /* aiCol at bp+32 */ uintptr
|
|
var _ /* aiFree at bp+8 */ uintptr
|
|
var _ /* iCol at bp+16 */ int32
|
|
var _ /* pIdx at bp+0 */ uintptr
|
|
var _ /* pIdx at bp+24 */ uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = aiCol, bIgnore, db, eAction, i, iDb, iFromCol, iJump, iReg, isIgnoreErrors, pFKey, pItem, pSrc, pTo, rcauth, v, zCol, zDb, v4, v7
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb /* Name of database containing pTab */
|
|
isIgnoreErrors = int32(Tbft(*(*uint16)(unsafe.Pointer(pParse + 40)) & 0x1 >> 0))
|
|
/* Exactly one of regOld and regNew should be non-zero. */
|
|
/* If foreign-keys are disabled, this function is a no-op. */
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).Fflags&uint64(SQLITE_ForeignKeys) == uint64(0) {
|
|
return
|
|
}
|
|
if !(libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == libc.Int32FromInt32(TABTYP_NORM)) {
|
|
return
|
|
}
|
|
iDb = _sqlite3SchemaToIndex(tls, db, (*TTable)(unsafe.Pointer(pTab)).FpSchema)
|
|
zDb = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(iDb)*32))).FzDbSName
|
|
/* Loop through all the foreign key constraints for which pTab is the
|
|
** child table (the table that the foreign key definition is part of). */
|
|
pFKey = (*(*struct {
|
|
FaddColOffset int32
|
|
FpFKey uintptr
|
|
FpDfltList uintptr
|
|
})(unsafe.Pointer(pTab + 64))).FpFKey
|
|
for {
|
|
if !(pFKey != 0) {
|
|
break
|
|
} /* Parent table of foreign key pFKey */
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0) /* Index on key columns in pTo */
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = uintptr(0)
|
|
bIgnore = 0
|
|
if aChange != 0 && Xsqlite3_stricmp(tls, (*TTable)(unsafe.Pointer(pTab)).FzName, (*TFKey)(unsafe.Pointer(pFKey)).FzTo) != 0 && _fkChildIsModified(tls, pTab, pFKey, aChange, bChngRowid) == 0 {
|
|
goto _1
|
|
}
|
|
/* Find the parent table of this foreign key. Also find a unique index
|
|
** on the parent key columns in the parent table. If either of these
|
|
** schema items cannot be located, set an error in pParse and return
|
|
** early. */
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(pParse + 40))&0x1>>0)) != 0 {
|
|
pTo = _sqlite3FindTable(tls, db, (*TFKey)(unsafe.Pointer(pFKey)).FzTo, zDb)
|
|
} else {
|
|
pTo = _sqlite3LocateTable(tls, pParse, uint32(0), (*TFKey)(unsafe.Pointer(pFKey)).FzTo, zDb)
|
|
}
|
|
if !(pTo != 0) || _sqlite3FkLocateIndex(tls, pParse, pTo, pFKey, bp, bp+8) != 0 {
|
|
if !(isIgnoreErrors != 0) || (*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0 {
|
|
return
|
|
}
|
|
if pTo == uintptr(0) {
|
|
/* If isIgnoreErrors is true, then a table is being dropped. In this
|
|
** case SQLite runs a "DELETE FROM xxx" on the table being dropped
|
|
** before actually dropping it in order to check FK constraints.
|
|
** If the parent table of an FK constraint on the current table is
|
|
** missing, behave as if it is empty. i.e. decrement the relevant
|
|
** FK counter for each row of the current table with non-NULL keys.
|
|
*/
|
|
v = _sqlite3GetVdbe(tls, pParse)
|
|
iJump = _sqlite3VdbeCurrentAddr(tls, v) + (*TFKey)(unsafe.Pointer(pFKey)).FnCol + int32(1)
|
|
i = 0
|
|
for {
|
|
if !(i < (*TFKey)(unsafe.Pointer(pFKey)).FnCol) {
|
|
break
|
|
}
|
|
iFromCol = (*(*TsColMap)(unsafe.Pointer(pFKey + 64 + uintptr(i)*16))).FiFrom
|
|
iReg = int32(_sqlite3TableColumnToStorage(tls, (*TFKey)(unsafe.Pointer(pFKey)).FpFrom, int16(iFromCol))) + regOld + int32(1)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_IsNull), iReg, iJump)
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_FkCounter), libc.Int32FromUint8((*TFKey)(unsafe.Pointer(pFKey)).FisDeferred), -int32(1))
|
|
}
|
|
goto _1
|
|
}
|
|
if **(**uintptr)(__ccgo_up(bp + 8)) != 0 {
|
|
aiCol = **(**uintptr)(__ccgo_up(bp + 8))
|
|
} else {
|
|
**(**int32)(__ccgo_up(bp + 16)) = (*(*TsColMap)(unsafe.Pointer(pFKey + 64))).FiFrom
|
|
aiCol = bp + 16
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < (*TFKey)(unsafe.Pointer(pFKey)).FnCol) {
|
|
break
|
|
}
|
|
if **(**int32)(__ccgo_up(aiCol + uintptr(i)*4)) == int32((*TTable)(unsafe.Pointer(pTab)).FiPKey) {
|
|
**(**int32)(__ccgo_up(aiCol + uintptr(i)*4)) = -int32(1)
|
|
}
|
|
/* Request permission to read the parent key columns. If the
|
|
** authorization callback returns SQLITE_IGNORE, behave as if any
|
|
** values read from the parent table are NULL. */
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FxAuth != 0 {
|
|
if **(**uintptr)(__ccgo_up(bp)) != 0 {
|
|
v4 = int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FaiColumn + uintptr(i)*2)))
|
|
} else {
|
|
v4 = int32((*TTable)(unsafe.Pointer(pTo)).FiPKey)
|
|
}
|
|
zCol = (**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pTo)).FaCol + uintptr(v4)*16))).FzCnName
|
|
rcauth = _sqlite3AuthReadCol(tls, pParse, (*TTable)(unsafe.Pointer(pTo)).FzName, zCol, iDb)
|
|
bIgnore = libc.BoolInt32(rcauth == int32(SQLITE_IGNORE))
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = i + 1
|
|
}
|
|
/* Take a shared-cache advisory read-lock on the parent table. Allocate
|
|
** a cursor to use to search the unique index on the parent key columns
|
|
** in the parent table. */
|
|
_sqlite3TableLock(tls, pParse, iDb, (*TTable)(unsafe.Pointer(pTo)).Ftnum, uint8(0), (*TTable)(unsafe.Pointer(pTo)).FzName)
|
|
(*TParse)(unsafe.Pointer(pParse)).FnTab = (*TParse)(unsafe.Pointer(pParse)).FnTab + 1
|
|
if regOld != 0 {
|
|
/* A row is being removed from the child table. Search for the parent.
|
|
** If the parent does not exist, removing the child row resolves an
|
|
** outstanding foreign key constraint violation. */
|
|
_fkLookupParent(tls, pParse, iDb, pTo, **(**uintptr)(__ccgo_up(bp)), pFKey, aiCol, regOld, -int32(1), bIgnore)
|
|
}
|
|
if regNew != 0 && !(_isSetNullAction(tls, pParse, pFKey) != 0) {
|
|
/* A row is being added to the child table. If a parent row cannot
|
|
** be found, adding the child row has violated the FK constraint.
|
|
**
|
|
** If this operation is being performed as part of a trigger program
|
|
** that is actually a "SET NULL" action belonging to this very
|
|
** foreign key, then omit this scan altogether. As all child key
|
|
** values are guaranteed to be NULL, it is not possible for adding
|
|
** this row to cause an FK violation. */
|
|
_fkLookupParent(tls, pParse, iDb, pTo, **(**uintptr)(__ccgo_up(bp)), pFKey, aiCol, regNew, +libc.Int32FromInt32(1), bIgnore)
|
|
}
|
|
_sqlite3DbFree(tls, db, **(**uintptr)(__ccgo_up(bp + 8)))
|
|
goto _1
|
|
_1:
|
|
;
|
|
pFKey = (*TFKey)(unsafe.Pointer(pFKey)).FpNextFrom
|
|
}
|
|
/* Loop through all the foreign key constraints that refer to this table.
|
|
** (the "child" constraints) */
|
|
pFKey = _sqlite3FkReferences(tls, pTab)
|
|
for {
|
|
if !(pFKey != 0) {
|
|
break
|
|
}
|
|
**(**uintptr)(__ccgo_up(bp + 24)) = uintptr(0)
|
|
**(**uintptr)(__ccgo_up(bp + 32)) = uintptr(0)
|
|
if aChange != 0 && _fkParentIsModified(tls, pTab, pFKey, aChange, bChngRowid) == 0 {
|
|
goto _5
|
|
}
|
|
if !((*TFKey)(unsafe.Pointer(pFKey)).FisDeferred != 0) && !((*Tsqlite3)(unsafe.Pointer(db)).Fflags&libc.Uint64FromInt32(SQLITE_DeferFKs) != 0) && !((*TParse)(unsafe.Pointer(pParse)).FpToplevel != 0) && !((*TParse)(unsafe.Pointer(pParse)).FisMultiWrite != 0) {
|
|
/* Inserting a single row into a parent table cannot cause (or fix)
|
|
** an immediate foreign key violation. So do nothing in this case. */
|
|
goto _5
|
|
}
|
|
if _sqlite3FkLocateIndex(tls, pParse, pTab, pFKey, bp+24, bp+32) != 0 {
|
|
if !(isIgnoreErrors != 0) || (*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0 {
|
|
return
|
|
}
|
|
goto _5
|
|
}
|
|
/* Create a SrcList structure containing the child table. We need the
|
|
** child table as a SrcList for sqlite3WhereBegin() */
|
|
pSrc = _sqlite3SrcListAppend(tls, pParse, uintptr(0), uintptr(0), uintptr(0))
|
|
if pSrc != 0 {
|
|
pItem = pSrc + 8
|
|
(*TSrcItem)(unsafe.Pointer(pItem)).FpSTab = (*TFKey)(unsafe.Pointer(pFKey)).FpFrom
|
|
(*TSrcItem)(unsafe.Pointer(pItem)).FzName = (*TTable)(unsafe.Pointer((*TFKey)(unsafe.Pointer(pFKey)).FpFrom)).FzName
|
|
(*TTable)(unsafe.Pointer((*TSrcItem)(unsafe.Pointer(pItem)).FpSTab)).FnTabRef = (*TTable)(unsafe.Pointer((*TSrcItem)(unsafe.Pointer(pItem)).FpSTab)).FnTabRef + 1
|
|
v7 = pParse + 56
|
|
v4 = *(*int32)(unsafe.Pointer(v7))
|
|
*(*int32)(unsafe.Pointer(v7)) = *(*int32)(unsafe.Pointer(v7)) + 1
|
|
(*TSrcItem)(unsafe.Pointer(pItem)).FiCursor = v4
|
|
if regNew != 0 {
|
|
_fkScanChildren(tls, pParse, pSrc, pTab, **(**uintptr)(__ccgo_up(bp + 24)), pFKey, **(**uintptr)(__ccgo_up(bp + 32)), regNew, -int32(1))
|
|
}
|
|
if regOld != 0 {
|
|
eAction = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pFKey + 45 + libc.BoolUintptr(aChange != uintptr(0)))))
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).Fflags&(libc.Uint64FromInt32(libc.Int32FromInt32(0x00008))<<libc.Int32FromInt32(32)) != 0 {
|
|
eAction = OE_None
|
|
}
|
|
_fkScanChildren(tls, pParse, pSrc, pTab, **(**uintptr)(__ccgo_up(bp + 24)), pFKey, **(**uintptr)(__ccgo_up(bp + 32)), regOld, int32(1))
|
|
/* If this is a deferred FK constraint, or a CASCADE or SET NULL
|
|
** action applies, then any foreign key violations caused by
|
|
** removing the parent key will be rectified by the action trigger.
|
|
** So do not set the "may-abort" flag in this case.
|
|
**
|
|
** Note 1: If the FK is declared "ON UPDATE CASCADE", then the
|
|
** may-abort flag will eventually be set on this statement anyway
|
|
** (when this function is called as part of processing the UPDATE
|
|
** within the action trigger).
|
|
**
|
|
** Note 2: At first glance it may seem like SQLite could simply omit
|
|
** all OP_FkCounter related scans when either CASCADE or SET NULL
|
|
** applies. The trouble starts if the CASCADE or SET NULL action
|
|
** trigger causes other triggers or action rules attached to the
|
|
** child table to fire. In these cases the fk constraint counters
|
|
** might be set incorrectly if any OP_FkCounter related scans are
|
|
** omitted. */
|
|
if !((*TFKey)(unsafe.Pointer(pFKey)).FisDeferred != 0) && eAction != int32(OE_Cascade) && eAction != int32(OE_SetNull) {
|
|
_sqlite3MayAbort(tls, pParse)
|
|
}
|
|
}
|
|
(*TSrcItem)(unsafe.Pointer(pItem)).FzName = uintptr(0)
|
|
_sqlite3SrcListDelete(tls, db, pSrc)
|
|
}
|
|
_sqlite3DbFree(tls, db, **(**uintptr)(__ccgo_up(bp + 32)))
|
|
goto _5
|
|
_5:
|
|
;
|
|
pFKey = (*TFKey)(unsafe.Pointer(pFKey)).FpNextTo
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Clear the apTrigger[] cache of CASCADE triggers for all foreign keys
|
|
// ** in a particular database. This needs to happen when the schema
|
|
// ** changes.
|
|
// */
|
|
func _sqlite3FkClearTriggerCache(tls *libc.TLS, db uintptr, iDb int32) {
|
|
var k, pFKey, pHash, pTab uintptr
|
|
_, _, _, _ = k, pFKey, pHash, pTab
|
|
pHash = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(iDb)*32))).FpSchema + 8
|
|
k = (*THash)(unsafe.Pointer(pHash)).Ffirst
|
|
for {
|
|
if !(k != 0) {
|
|
break
|
|
}
|
|
pTab = (*THashElem)(unsafe.Pointer(k)).Fdata
|
|
if !(libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == libc.Int32FromInt32(TABTYP_NORM)) {
|
|
goto _1
|
|
}
|
|
pFKey = (*(*struct {
|
|
FaddColOffset int32
|
|
FpFKey uintptr
|
|
FpDfltList uintptr
|
|
})(unsafe.Pointer(pTab + 64))).FpFKey
|
|
for {
|
|
if !(pFKey != 0) {
|
|
break
|
|
}
|
|
_fkTriggerDelete(tls, db, **(**uintptr)(__ccgo_up(pFKey + 48)))
|
|
**(**uintptr)(__ccgo_up(pFKey + 48)) = uintptr(0)
|
|
_fkTriggerDelete(tls, db, **(**uintptr)(__ccgo_up(pFKey + 48 + 1*8)))
|
|
**(**uintptr)(__ccgo_up(pFKey + 48 + 1*8)) = uintptr(0)
|
|
goto _2
|
|
_2:
|
|
;
|
|
pFKey = (*TFKey)(unsafe.Pointer(pFKey)).FpNextFrom
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
k = (*THashElem)(unsafe.Pointer(k)).Fnext
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called to generate code that runs when table pTab is
|
|
// ** being dropped from the database. The SrcList passed as the second argument
|
|
// ** to this function contains a single entry guaranteed to resolve to
|
|
// ** table pTab.
|
|
// **
|
|
// ** Normally, no code is required. However, if either
|
|
// **
|
|
// ** (a) The table is the parent table of a FK constraint, or
|
|
// ** (b) The table is the child table of a deferred FK constraint and it is
|
|
// ** determined at runtime that there are outstanding deferred FK
|
|
// ** constraint violations in the database,
|
|
// **
|
|
// ** then the equivalent of "DELETE FROM <tbl>" is executed before dropping
|
|
// ** the table from the database. Triggers are disabled while running this
|
|
// ** DELETE, but foreign key actions are not.
|
|
// */
|
|
func _sqlite3FkDropTable(tls *libc.TLS, pParse uintptr, pName uintptr, pTab uintptr) {
|
|
var db, p, v uintptr
|
|
var iSkip int32
|
|
_, _, _, _ = db, iSkip, p, v
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).Fflags&uint64(SQLITE_ForeignKeys) != 0 && libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == TABTYP_NORM {
|
|
iSkip = 0
|
|
v = _sqlite3GetVdbe(tls, pParse)
|
|
/* VDBE has already been allocated */
|
|
if _sqlite3FkReferences(tls, pTab) == uintptr(0) {
|
|
p = (*(*struct {
|
|
FaddColOffset int32
|
|
FpFKey uintptr
|
|
FpDfltList uintptr
|
|
})(unsafe.Pointer(pTab + 64))).FpFKey
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
if (*TFKey)(unsafe.Pointer(p)).FisDeferred != 0 || (*Tsqlite3)(unsafe.Pointer(db)).Fflags&uint64(SQLITE_DeferFKs) != 0 {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = (*TFKey)(unsafe.Pointer(p)).FpNextFrom
|
|
}
|
|
if !(p != 0) {
|
|
return
|
|
}
|
|
iSkip = _sqlite3VdbeMakeLabel(tls, pParse)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_FkIfZero), int32(1), iSkip)
|
|
}
|
|
libc.SetBitFieldPtr16Uint32(pParse+40, libc.Uint32FromInt32(1), 0, 0x1)
|
|
_sqlite3DeleteFrom(tls, pParse, _sqlite3SrcListDup(tls, db, pName, 0), uintptr(0), uintptr(0), uintptr(0))
|
|
libc.SetBitFieldPtr16Uint32(pParse+40, libc.Uint32FromInt32(0), 0, 0x1)
|
|
/* If the DELETE has generated immediate foreign key constraint
|
|
** violations, halt the VDBE and return an error at this point, before
|
|
** any modifications to the schema are made. This is because statement
|
|
** transactions are not able to rollback schema changes.
|
|
**
|
|
** If the SQLITE_DeferFKs flag is set, then this is not required, as
|
|
** the statement transaction will not be rolled back even if FK
|
|
** constraints are violated.
|
|
*/
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).Fflags&uint64(SQLITE_DeferFKs) == uint64(0) {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_FkIfZero), 0, _sqlite3VdbeCurrentAddr(tls, v)+int32(2))
|
|
_sqlite3HaltConstraint(tls, pParse, libc.Int32FromInt32(SQLITE_CONSTRAINT)|libc.Int32FromInt32(3)<<libc.Int32FromInt32(8), int32(OE_Abort), uintptr(0), int8(-libc.Int32FromInt32(1)), uint8(P5_ConstraintFK))
|
|
}
|
|
if iSkip != 0 {
|
|
_sqlite3VdbeResolveLabel(tls, v, iSkip)
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called before generating code to update or delete a
|
|
// ** row contained in table pTab.
|
|
// */
|
|
func _sqlite3FkOldmask(tls *libc.TLS, pParse uintptr, pTab uintptr) (r Tu32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var i int32
|
|
var mask Tu32
|
|
var p uintptr
|
|
var v3 uint32
|
|
var _ /* pIdx at bp+0 */ uintptr
|
|
_, _, _, _ = i, mask, p, v3
|
|
mask = uint32(0)
|
|
if (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).Fflags&uint64(SQLITE_ForeignKeys) != 0 && libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == TABTYP_NORM {
|
|
p = (*(*struct {
|
|
FaddColOffset int32
|
|
FpFKey uintptr
|
|
FpDfltList uintptr
|
|
})(unsafe.Pointer(pTab + 64))).FpFKey
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < (*TFKey)(unsafe.Pointer(p)).FnCol) {
|
|
break
|
|
}
|
|
if (*(*TsColMap)(unsafe.Pointer(p + 64 + uintptr(i)*16))).FiFrom > int32(31) {
|
|
v3 = uint32(0xffffffff)
|
|
} else {
|
|
v3 = libc.Uint32FromInt32(1) << (*(*TsColMap)(unsafe.Pointer(p + 64 + uintptr(i)*16))).FiFrom
|
|
}
|
|
mask = mask | v3
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = (*TFKey)(unsafe.Pointer(p)).FpNextFrom
|
|
}
|
|
p = _sqlite3FkReferences(tls, pTab)
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
_sqlite3FkLocateIndex(tls, pParse, pTab, p, bp, uintptr(0))
|
|
if **(**uintptr)(__ccgo_up(bp)) != 0 {
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FnKeyCol)) {
|
|
break
|
|
}
|
|
if int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FaiColumn + uintptr(i)*2))) > int32(31) {
|
|
v3 = uint32(0xffffffff)
|
|
} else {
|
|
v3 = libc.Uint32FromInt32(1) << **(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FaiColumn + uintptr(i)*2))
|
|
}
|
|
mask = mask | v3
|
|
goto _5
|
|
_5:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
p = (*TFKey)(unsafe.Pointer(p)).FpNextTo
|
|
}
|
|
}
|
|
return mask
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called before generating code to update or delete a
|
|
// ** row contained in table pTab. If the operation is a DELETE, then
|
|
// ** parameter aChange is passed a NULL value. For an UPDATE, aChange points
|
|
// ** to an array of size N, where N is the number of columns in table pTab.
|
|
// ** If the i'th column is not modified by the UPDATE, then the corresponding
|
|
// ** entry in the aChange[] array is set to -1. If the column is modified,
|
|
// ** the value is 0 or greater. Parameter chngRowid is set to true if the
|
|
// ** UPDATE statement modifies the rowid fields of the table.
|
|
// **
|
|
// ** If any foreign key processing will be required, this function returns
|
|
// ** non-zero. If there is no foreign key related processing, this function
|
|
// ** returns zero.
|
|
// **
|
|
// ** For an UPDATE, this function returns 2 if:
|
|
// **
|
|
// ** * There are any FKs for which pTab is the child and the parent table
|
|
// ** and any FK processing at all is required (even of a different FK), or
|
|
// **
|
|
// ** * the UPDATE modifies one or more parent keys for which the action is
|
|
// ** not "NO ACTION" (i.e. is CASCADE, SET DEFAULT or SET NULL).
|
|
// **
|
|
// ** Or, assuming some other foreign key processing is required, 1.
|
|
// */
|
|
func _sqlite3FkRequired(tls *libc.TLS, pParse uintptr, pTab uintptr, aChange uintptr, chngRowid int32) (r int32) {
|
|
var bHaveFK, eRet, v3 int32
|
|
var p uintptr
|
|
_, _, _, _ = bHaveFK, eRet, p, v3
|
|
eRet = int32(1) /* Value to return if bHaveFK is true */
|
|
bHaveFK = 0 /* If FK processing is required */
|
|
if (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).Fflags&uint64(SQLITE_ForeignKeys) != 0 && libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == TABTYP_NORM {
|
|
if !(aChange != 0) {
|
|
/* A DELETE operation. Foreign key processing is required if the
|
|
** table in question is either the child or parent table for any
|
|
** foreign key constraint. */
|
|
bHaveFK = libc.BoolInt32(_sqlite3FkReferences(tls, pTab) != 0 || (*(*struct {
|
|
FaddColOffset int32
|
|
FpFKey uintptr
|
|
FpDfltList uintptr
|
|
})(unsafe.Pointer(pTab + 64))).FpFKey != 0)
|
|
} else {
|
|
/* Check if any child key columns are being modified. */
|
|
p = (*(*struct {
|
|
FaddColOffset int32
|
|
FpFKey uintptr
|
|
FpDfltList uintptr
|
|
})(unsafe.Pointer(pTab + 64))).FpFKey
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
if _fkChildIsModified(tls, pTab, p, aChange, chngRowid) != 0 {
|
|
if 0 == Xsqlite3_stricmp(tls, (*TTable)(unsafe.Pointer(pTab)).FzName, (*TFKey)(unsafe.Pointer(p)).FzTo) {
|
|
eRet = int32(2)
|
|
}
|
|
bHaveFK = int32(1)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = (*TFKey)(unsafe.Pointer(p)).FpNextFrom
|
|
}
|
|
/* Check if any parent key columns are being modified. */
|
|
p = _sqlite3FkReferences(tls, pTab)
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
if _fkParentIsModified(tls, pTab, p, aChange, chngRowid) != 0 {
|
|
if (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).Fflags&(libc.Uint64FromInt32(libc.Int32FromInt32(0x00008))<<libc.Int32FromInt32(32)) == uint64(0) && libc.Int32FromUint8(**(**Tu8)(__ccgo_up(p + 45 + 1))) != OE_None {
|
|
return int32(2)
|
|
}
|
|
bHaveFK = int32(1)
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
p = (*TFKey)(unsafe.Pointer(p)).FpNextTo
|
|
}
|
|
}
|
|
}
|
|
if bHaveFK != 0 {
|
|
v3 = eRet
|
|
} else {
|
|
v3 = 0
|
|
}
|
|
return v3
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Append the nul-terminated string zStr to the buffer pBuf. This function
|
|
// ** ensures that the byte following the buffer data is set to 0x00, even
|
|
// ** though this byte is not included in the pBuf->n count.
|
|
// */
|
|
func _sqlite3Fts5BufferAppendString(tls *libc.TLS, pRc uintptr, pBuf uintptr, zStr uintptr) {
|
|
var nStr int32
|
|
_ = nStr
|
|
nStr = libc.Int32FromUint64(libc.Xstrlen(tls, zStr))
|
|
_sqlite3Fts5BufferAppendBlob(tls, pRc, pBuf, libc.Uint32FromInt32(nStr+int32(1)), zStr)
|
|
(*TFts5Buffer)(unsafe.Pointer(pBuf)).Fn = (*TFts5Buffer)(unsafe.Pointer(pBuf)).Fn - 1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Encode value iVal as an SQLite varint and append it to the buffer object
|
|
// ** pBuf. If an OOM error occurs, set the error code in p.
|
|
// */
|
|
func _sqlite3Fts5BufferAppendVarint(tls *libc.TLS, pRc uintptr, pBuf uintptr, iVal Ti64) {
|
|
var v1 int32
|
|
_ = v1
|
|
if libc.Uint32FromInt32((*TFts5Buffer)(unsafe.Pointer(pBuf)).Fn)+libc.Uint32FromInt32(libc.Int32FromInt32(9)) <= libc.Uint32FromInt32((*TFts5Buffer)(unsafe.Pointer(pBuf)).FnSpace) {
|
|
v1 = 0
|
|
} else {
|
|
v1 = _sqlite3Fts5BufferSize(tls, pRc, pBuf, libc.Uint32FromInt32(int32(9)+(*TFts5Buffer)(unsafe.Pointer(pBuf)).Fn))
|
|
}
|
|
if v1 != 0 {
|
|
return
|
|
}
|
|
**(**int32)(__ccgo_up(pBuf + 8)) += _sqlite3Fts5PutVarint(tls, (*TFts5Buffer)(unsafe.Pointer(pBuf)).Fp+uintptr((*TFts5Buffer)(unsafe.Pointer(pBuf)).Fn), libc.Uint64FromInt64(iVal))
|
|
}
|
|
|
|
func _sqlite3Fts5HashScanEntry(tls *libc.TLS, pHash uintptr, pzTerm uintptr, pnTerm uintptr, ppDoclist uintptr, pnDoclist uintptr) {
|
|
var nTerm int32
|
|
var p, zKey, v1 uintptr
|
|
_, _, _, _ = nTerm, p, zKey, v1
|
|
v1 = (*TFts5Hash)(unsafe.Pointer(pHash)).FpScan
|
|
p = v1
|
|
if v1 != 0 {
|
|
zKey = p + 1*48
|
|
nTerm = (*TFts5HashEntry)(unsafe.Pointer(p)).FnKey
|
|
_fts5HashAddPoslistSize(tls, pHash, p, uintptr(0))
|
|
**(**uintptr)(__ccgo_up(pzTerm)) = zKey
|
|
**(**int32)(__ccgo_up(pnTerm)) = nTerm
|
|
**(**uintptr)(__ccgo_up(ppDoclist)) = zKey + uintptr(nTerm)
|
|
**(**int32)(__ccgo_up(pnDoclist)) = libc.Int32FromUint64(libc.Uint64FromInt32((*TFts5HashEntry)(unsafe.Pointer(p)).FnData) - (uint64(48) + libc.Uint64FromInt32(nTerm)))
|
|
} else {
|
|
**(**uintptr)(__ccgo_up(pzTerm)) = uintptr(0)
|
|
**(**int32)(__ccgo_up(pnTerm)) = 0
|
|
**(**uintptr)(__ccgo_up(ppDoclist)) = uintptr(0)
|
|
**(**int32)(__ccgo_up(pnDoclist)) = 0
|
|
}
|
|
}
|
|
|
|
/*
|
|
** 2014 May 31
|
|
**
|
|
** The author disclaims copyright to this source code. In place of
|
|
** a legal notice, here is a blessing:
|
|
**
|
|
** May you do good and not evil.
|
|
** May you find forgiveness for yourself and forgive others.
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
******************************************************************************
|
|
**
|
|
** Low level access to the FTS index stored in the database file. The
|
|
** routines in this file file implement all read and write access to the
|
|
** %_data table. Other parts of the system access this functionality via
|
|
** the interface defined in fts5Int.h.
|
|
*/
|
|
|
|
/* #include "fts5Int.h" */
|
|
|
|
/*
|
|
** Overview:
|
|
**
|
|
** The %_data table contains all the FTS indexes for an FTS5 virtual table.
|
|
** As well as the main term index, there may be up to 31 prefix indexes.
|
|
** The format is similar to FTS3/4, except that:
|
|
**
|
|
** * all segment b-tree leaf data is stored in fixed size page records
|
|
** (e.g. 1000 bytes). A single doclist may span multiple pages. Care is
|
|
** taken to ensure it is possible to iterate in either direction through
|
|
** the entries in a doclist, or to seek to a specific entry within a
|
|
** doclist, without loading it into memory.
|
|
**
|
|
** * large doclists that span many pages have associated "doclist index"
|
|
** records that contain a copy of the first rowid on each page spanned by
|
|
** the doclist. This is used to speed up seek operations, and merges of
|
|
** large doclists with very small doclists.
|
|
**
|
|
** * extra fields in the "structure record" record the state of ongoing
|
|
** incremental merge operations.
|
|
**
|
|
*/
|
|
|
|
/*
|
|
** There are two versions of the format used for the structure record:
|
|
**
|
|
** 1. the legacy format, that may be read by all fts5 versions, and
|
|
**
|
|
** 2. the V2 format, which is used by contentless_delete=1 databases.
|
|
**
|
|
** Both begin with a 4-byte "configuration cookie" value. Then, a legacy
|
|
** format structure record contains a varint - the number of levels in
|
|
** the structure. Whereas a V2 structure record contains the constant
|
|
** 4 bytes [0xff 0x00 0x00 0x01]. This is unambiguous as the value of a
|
|
** varint has to be at least 16256 to begin with "0xFF". And the default
|
|
** maximum number of levels is 64.
|
|
**
|
|
** See below for more on structure record formats.
|
|
*/
|
|
|
|
/*
|
|
** Details:
|
|
**
|
|
** The %_data table managed by this module,
|
|
**
|
|
** CREATE TABLE %_data(id INTEGER PRIMARY KEY, block BLOB);
|
|
**
|
|
** , contains the following 6 types of records. See the comments surrounding
|
|
** the FTS5_*_ROWID macros below for a description of how %_data rowids are
|
|
** assigned to each fo them.
|
|
**
|
|
** 1. Structure Records:
|
|
**
|
|
** The set of segments that make up an index - the index structure - are
|
|
** recorded in a single record within the %_data table. The record consists
|
|
** of a single 32-bit configuration cookie value followed by a list of
|
|
** SQLite varints.
|
|
**
|
|
** If the structure record is a V2 record, the configuration cookie is
|
|
** followed by the following 4 bytes: [0xFF 0x00 0x00 0x01].
|
|
**
|
|
** Next, the record continues with three varints:
|
|
**
|
|
** + number of levels,
|
|
** + total number of segments on all levels,
|
|
** + value of write counter.
|
|
**
|
|
** Then, for each level from 0 to nMax:
|
|
**
|
|
** + number of input segments in ongoing merge.
|
|
** + total number of segments in level.
|
|
** + for each segment from oldest to newest:
|
|
** + segment id (always > 0)
|
|
** + first leaf page number (often 1, always greater than 0)
|
|
** + final leaf page number
|
|
**
|
|
** Then, for V2 structures only:
|
|
**
|
|
** + lower origin counter value,
|
|
** + upper origin counter value,
|
|
** + the number of tombstone hash pages.
|
|
**
|
|
** 2. The Averages Record:
|
|
**
|
|
** A single record within the %_data table. The data is a list of varints.
|
|
** The first value is the number of rows in the index. Then, for each column
|
|
** from left to right, the total number of tokens in the column for all
|
|
** rows of the table.
|
|
**
|
|
** 3. Segment leaves:
|
|
**
|
|
** TERM/DOCLIST FORMAT:
|
|
**
|
|
** Most of each segment leaf is taken up by term/doclist data. The
|
|
** general format of term/doclist, starting with the first term
|
|
** on the leaf page, is:
|
|
**
|
|
** varint : size of first term
|
|
** blob: first term data
|
|
** doclist: first doclist
|
|
** zero-or-more {
|
|
** varint: number of bytes in common with previous term
|
|
** varint: number of bytes of new term data (nNew)
|
|
** blob: nNew bytes of new term data
|
|
** doclist: next doclist
|
|
** }
|
|
**
|
|
** doclist format:
|
|
**
|
|
** varint: first rowid
|
|
** poslist: first poslist
|
|
** zero-or-more {
|
|
** varint: rowid delta (always > 0)
|
|
** poslist: next poslist
|
|
** }
|
|
**
|
|
** poslist format:
|
|
**
|
|
** varint: size of poslist in bytes multiplied by 2, not including
|
|
** this field. Plus 1 if this entry carries the "delete" flag.
|
|
** collist: collist for column 0
|
|
** zero-or-more {
|
|
** 0x01 byte
|
|
** varint: column number (I)
|
|
** collist: collist for column I
|
|
** }
|
|
**
|
|
** collist format:
|
|
**
|
|
** varint: first offset + 2
|
|
** zero-or-more {
|
|
** varint: offset delta + 2
|
|
** }
|
|
**
|
|
** PAGE FORMAT
|
|
**
|
|
** Each leaf page begins with a 4-byte header containing 2 16-bit
|
|
** unsigned integer fields in big-endian format. They are:
|
|
**
|
|
** * The byte offset of the first rowid on the page, if it exists
|
|
** and occurs before the first term (otherwise 0).
|
|
**
|
|
** * The byte offset of the start of the page footer. If the page
|
|
** footer is 0 bytes in size, then this field is the same as the
|
|
** size of the leaf page in bytes.
|
|
**
|
|
** The page footer consists of a single varint for each term located
|
|
** on the page. Each varint is the byte offset of the current term
|
|
** within the page, delta-compressed against the previous value. In
|
|
** other words, the first varint in the footer is the byte offset of
|
|
** the first term, the second is the byte offset of the second less that
|
|
** of the first, and so on.
|
|
**
|
|
** The term/doclist format described above is accurate if the entire
|
|
** term/doclist data fits on a single leaf page. If this is not the case,
|
|
** the format is changed in two ways:
|
|
**
|
|
** + if the first rowid on a page occurs before the first term, it
|
|
** is stored as a literal value:
|
|
**
|
|
** varint: first rowid
|
|
**
|
|
** + the first term on each page is stored in the same way as the
|
|
** very first term of the segment:
|
|
**
|
|
** varint : size of first term
|
|
** blob: first term data
|
|
**
|
|
** 5. Segment doclist indexes:
|
|
**
|
|
** Doclist indexes are themselves b-trees, however they usually consist of
|
|
** a single leaf record only. The format of each doclist index leaf page
|
|
** is:
|
|
**
|
|
** * Flags byte. Bits are:
|
|
** 0x01: Clear if leaf is also the root page, otherwise set.
|
|
**
|
|
** * Page number of fts index leaf page. As a varint.
|
|
**
|
|
** * First rowid on page indicated by previous field. As a varint.
|
|
**
|
|
** * A list of varints, one for each subsequent termless page. A
|
|
** positive delta if the termless page contains at least one rowid,
|
|
** or an 0x00 byte otherwise.
|
|
**
|
|
** Internal doclist index nodes are:
|
|
**
|
|
** * Flags byte. Bits are:
|
|
** 0x01: Clear for root page, otherwise set.
|
|
**
|
|
** * Page number of first child page. As a varint.
|
|
**
|
|
** * Copy of first rowid on page indicated by previous field. As a varint.
|
|
**
|
|
** * A list of delta-encoded varints - the first rowid on each subsequent
|
|
** child page.
|
|
**
|
|
** 6. Tombstone Hash Page
|
|
**
|
|
** These records are only ever present in contentless_delete=1 tables.
|
|
** There are zero or more of these associated with each segment. They
|
|
** are used to store the tombstone rowids for rows contained in the
|
|
** associated segments.
|
|
**
|
|
** The set of nHashPg tombstone hash pages associated with a single
|
|
** segment together form a single hash table containing tombstone rowids.
|
|
** To find the page of the hash on which a key might be stored:
|
|
**
|
|
** iPg = (rowid % nHashPg)
|
|
**
|
|
** Then, within page iPg, which has nSlot slots:
|
|
**
|
|
** iSlot = (rowid / nHashPg) % nSlot
|
|
**
|
|
** Each tombstone hash page begins with an 8 byte header:
|
|
**
|
|
** 1-byte: Key-size (the size in bytes of each slot). Either 4 or 8.
|
|
** 1-byte: rowid-0-tombstone flag. This flag is only valid on the
|
|
** first tombstone hash page for each segment (iPg=0). If set,
|
|
** the hash table contains rowid 0. If clear, it does not.
|
|
** Rowid 0 is handled specially.
|
|
** 2-bytes: unused.
|
|
** 4-bytes: Big-endian integer containing number of entries on page.
|
|
**
|
|
** Following this are nSlot 4 or 8 byte slots (depending on the key-size
|
|
** in the first byte of the page header). The number of slots may be
|
|
** determined based on the size of the page record and the key-size:
|
|
**
|
|
** nSlot = (nByte - 8) / key-size
|
|
*/
|
|
|
|
/*
|
|
** Rowids for the averages and structure records in the %_data table.
|
|
*/
|
|
|
|
/*
|
|
** Macros determining the rowids used by segment leaves and dlidx leaves
|
|
** and nodes. All nodes and leaves are stored in the %_data table with large
|
|
** positive rowids.
|
|
**
|
|
** Each segment has a unique non-zero 16-bit id.
|
|
**
|
|
** The rowid for each segment leaf is found by passing the segment id and
|
|
** the leaf page number to the FTS5_SEGMENT_ROWID macro. Leaves are numbered
|
|
** sequentially starting from 1.
|
|
*/
|
|
|
|
/*
|
|
** Each time a blob is read from the %_data table, it is padded with this
|
|
** many zero bytes. This makes it easier to decode the various record formats
|
|
** without overreading if the records are corrupt.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add iRowid to the tombstone list of the segment or segments that contain
|
|
// ** rows from origin iOrigin. Return SQLITE_OK if successful, or an SQLite
|
|
// ** error code otherwise.
|
|
// */
|
|
func _sqlite3Fts5IndexContentlessDelete(tls *libc.TLS, p uintptr, iOrigin Ti64, iRowid Ti64) (r int32) {
|
|
var bFound, iLvl, iSeg int32
|
|
var pSeg, pStruct uintptr
|
|
_, _, _, _, _ = bFound, iLvl, iSeg, pSeg, pStruct
|
|
pStruct = _fts5StructureRead(tls, p)
|
|
if pStruct != 0 {
|
|
bFound = 0
|
|
iLvl = (*TFts5Structure)(unsafe.Pointer(pStruct)).FnLevel - int32(1)
|
|
for {
|
|
if !(iLvl >= 0) {
|
|
break
|
|
}
|
|
iSeg = (*(*TFts5StructureLevel)(unsafe.Pointer(pStruct + 32 + uintptr(iLvl)*16))).FnSeg - int32(1)
|
|
for {
|
|
if !(iSeg >= 0) {
|
|
break
|
|
}
|
|
pSeg = (*(*TFts5StructureLevel)(unsafe.Pointer(pStruct + 32 + uintptr(iLvl)*16))).FaSeg + uintptr(iSeg)*56
|
|
if (*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FiOrigin1 <= libc.Uint64FromInt64(iOrigin) && (*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FiOrigin2 >= libc.Uint64FromInt64(iOrigin) {
|
|
if bFound == 0 {
|
|
(*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FnEntryTombstone = (*TFts5StructureSegment)(unsafe.Pointer(pSeg)).FnEntryTombstone + 1
|
|
bFound = int32(1)
|
|
}
|
|
_fts5IndexTombstoneAdd(tls, p, pSeg, libc.Uint64FromInt64(iRowid))
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
iSeg = iSeg - 1
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
iLvl = iLvl - 1
|
|
}
|
|
_fts5StructureRelease(tls, pStruct)
|
|
}
|
|
return _fts5IndexReturn(tls, p)
|
|
}
|
|
|
|
/*************************************************************************
|
|
**************************************************************************
|
|
** Below this point is the implementation of the integrity-check
|
|
** functionality.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set a token-mapping for the iterator passed as the first argument. This
|
|
// ** is used in detail=column or detail=none mode when a token is requested
|
|
// ** using the xInstToken() API. In this case the caller tokenizers the
|
|
// ** current row and configures the token-mapping via multiple calls to this
|
|
// ** function.
|
|
// */
|
|
func _sqlite3Fts5IndexIterWriteTokendata(tls *libc.TLS, pIndexIter uintptr, pToken uintptr, nToken int32, iRowid Ti64, iCol int32, iOff int32) (r int32) {
|
|
var iPos Ti64
|
|
var ii int32
|
|
var p, pIter, pT, pTerm uintptr
|
|
_, _, _, _, _, _ = iPos, ii, p, pIter, pT, pTerm
|
|
pIter = pIndexIter
|
|
pT = (*TFts5Iter)(unsafe.Pointer(pIter)).FpTokenDataIter
|
|
p = (*TFts5Iter)(unsafe.Pointer(pIter)).FpIndex
|
|
iPos = int64(iCol)<<libc.Int32FromInt32(32) + int64(iOff)
|
|
if (*TFts5Iter)(unsafe.Pointer(pIter)).FnSeg > 0 {
|
|
/* This is a prefix term iterator. */
|
|
if pT == uintptr(0) {
|
|
pT = _sqlite3Fts5MallocZero(tls, p+60, libc.Int64FromUint64(uint64(libc.UintptrFromInt32(0)+72)+libc.Uint64FromInt32(libc.Int32FromInt32(1))*libc.Uint64FromInt64(104)))
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).FpTokenDataIter = pT
|
|
}
|
|
if pT != 0 {
|
|
_fts5TokendataIterAppendMap(tls, p, pT, (*TFts5TokenDataIter)(unsafe.Pointer(pT)).Fterms.Fn, nToken, iRowid, iPos)
|
|
_sqlite3Fts5BufferAppendBlob(tls, p+60, pT+24, libc.Uint32FromInt32(nToken), pToken)
|
|
}
|
|
} else {
|
|
ii = 0
|
|
for {
|
|
if !(int64(ii) < (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnIter) {
|
|
break
|
|
}
|
|
pTerm = *(*uintptr)(unsafe.Pointer(pT + 72 + uintptr(ii)*8)) + 104 + 96
|
|
if nToken == (*TFts5Buffer)(unsafe.Pointer(pTerm)).Fn-int32(1) && libc.Xmemcmp(tls, pToken, (*TFts5Buffer)(unsafe.Pointer(pTerm)).Fp+uintptr(1), libc.Uint64FromInt32(nToken)) == 0 {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
if int64(ii) < (*TFts5TokenDataIter)(unsafe.Pointer(pT)).FnIter {
|
|
_fts5TokendataIterAppendMap(tls, p, pT, ii, 0, iRowid, iPos)
|
|
}
|
|
}
|
|
return _fts5IndexReturn(tls, p)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if the value passed as the only argument is an
|
|
// ** fts5_locale() value.
|
|
// */
|
|
func _sqlite3Fts5IsLocaleValue(tls *libc.TLS, pConfig uintptr, pVal uintptr) (r int32) {
|
|
var nBlob, ret int32
|
|
var pBlob uintptr
|
|
_, _, _ = nBlob, pBlob, ret
|
|
ret = 0
|
|
if Xsqlite3_value_type(tls, pVal) == int32(SQLITE_BLOB) {
|
|
/* Call sqlite3_value_bytes() after sqlite3_value_blob() in this case.
|
|
** If the blob was created using zeroblob(), then sqlite3_value_blob()
|
|
** may call malloc(). If this malloc() fails, then the values returned
|
|
** by both value_blob() and value_bytes() will be 0. If value_bytes() were
|
|
** called first, then the NULL pointer returned by value_blob() might
|
|
** be dereferenced. */
|
|
pBlob = Xsqlite3_value_blob(tls, pVal)
|
|
nBlob = Xsqlite3_value_bytes(tls, pVal)
|
|
if nBlob > libc.Int32FromInt64(16) && 0 == libc.Xmemcmp(tls, pBlob, (*TFts5Config)(unsafe.Pointer(pConfig)).FpGlobal+96, libc.Uint64FromInt32(libc.Int32FromInt64(16))) {
|
|
ret = int32(1)
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Move to the next matching term/rowid. Used by the fts5vocab module.
|
|
// */
|
|
func _sqlite3Fts5IterNextScan(tls *libc.TLS, pIndexIter uintptr) (r int32) {
|
|
var p, pIter, pSeg uintptr
|
|
_, _, _ = p, pIter, pSeg
|
|
pIter = pIndexIter
|
|
p = (*TFts5Iter)(unsafe.Pointer(pIter)).FpIndex
|
|
_fts5MultiIterNext(tls, p, pIter, 0, 0)
|
|
if (*TFts5Index)(unsafe.Pointer(p)).Frc == SQLITE_OK {
|
|
pSeg = pIter + 104 + uintptr((**(**TFts5CResult)(__ccgo_up((*TFts5Iter)(unsafe.Pointer(pIter)).FaFirst + 1*4))).FiFirst)*128
|
|
if (*TFts5SegIter)(unsafe.Pointer(pSeg)).FpLeaf != 0 && libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5SegIter)(unsafe.Pointer(pSeg)).Fterm.Fp))) != int32('0') {
|
|
_fts5DataRelease(tls, (*TFts5SegIter)(unsafe.Pointer(pSeg)).FpLeaf)
|
|
(*TFts5SegIter)(unsafe.Pointer(pSeg)).FpLeaf = uintptr(0)
|
|
(*TFts5Iter)(unsafe.Pointer(pIter)).Fbase.FbEof = uint8(1)
|
|
}
|
|
}
|
|
return _fts5IndexReturn(tls, (*TFts5Iter)(unsafe.Pointer(pIter)).FpIndex)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate and return an Fts5Colset object specifying the inverse of
|
|
// ** the colset passed as the second argument. Free the colset passed
|
|
// ** as the second argument before returning.
|
|
// */
|
|
func _sqlite3Fts5ParseColsetInvert(tls *libc.TLS, pParse uintptr, p uintptr) (r uintptr) {
|
|
var i, iOld, nCol, v2 int32
|
|
var pRet, v3 uintptr
|
|
_, _, _, _, _, _ = i, iOld, nCol, pRet, v2, v3
|
|
nCol = (*TFts5Config)(unsafe.Pointer((*TFts5Parse)(unsafe.Pointer(pParse)).FpConfig)).FnCol
|
|
pRet = _sqlite3Fts5MallocZero(tls, pParse+16, libc.Int64FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32((nCol+libc.Int32FromInt32(1)+libc.Int32FromInt32(2))/libc.Int32FromInt32(2))))
|
|
if pRet != 0 {
|
|
iOld = 0
|
|
i = 0
|
|
for {
|
|
if !(i < nCol) {
|
|
break
|
|
}
|
|
if iOld >= (*TFts5Colset)(unsafe.Pointer(p)).FnCol || *(*int32)(unsafe.Pointer(p + 4 + uintptr(iOld)*4)) != i {
|
|
v3 = pRet
|
|
v2 = *(*int32)(unsafe.Pointer(v3))
|
|
*(*int32)(unsafe.Pointer(v3)) = *(*int32)(unsafe.Pointer(v3)) + 1
|
|
*(*int32)(unsafe.Pointer(pRet + 4 + uintptr(v2)*4)) = i
|
|
} else {
|
|
iOld = iOld + 1
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
Xsqlite3_free(tls, p)
|
|
return pRet
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* The main parser program.
|
|
// ** The first argument is a pointer to a structure obtained from
|
|
// ** "sqlite3Fts5ParserAlloc" which describes the current state of the parser.
|
|
// ** The second argument is the major token number. The third is
|
|
// ** the minor token. The fourth optional argument is whatever the
|
|
// ** user wants (and specified in the grammar) and is available for
|
|
// ** use by the action routines.
|
|
// **
|
|
// ** Inputs:
|
|
// ** <ul>
|
|
// ** <li> A pointer to the parser (an opaque structure.)
|
|
// ** <li> The major token number.
|
|
// ** <li> The minor token number.
|
|
// ** <li> An option argument of a grammar-specified type.
|
|
// ** </ul>
|
|
// **
|
|
// ** Outputs:
|
|
// ** None.
|
|
// */
|
|
func _sqlite3Fts5Parser(tls *libc.TLS, fts5yyp uintptr, fts5yymajor int32, fts5yyminor TFts5Token, pParse uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var fts5yyact uint8
|
|
var fts5yypParser uintptr
|
|
var fts5yyruleno uint32
|
|
var _ /* fts5yyminorunion at bp+0 */ Tfts5YYMINORTYPE
|
|
_, _, _ = fts5yyact, fts5yypParser, fts5yyruleno /* The parser action. */
|
|
fts5yypParser = fts5yyp /* The parser */
|
|
(*Tfts5yyParser)(unsafe.Pointer(fts5yypParser)).FpParse = pParse
|
|
fts5yyact = (*Tfts5yyStackEntry)(unsafe.Pointer((*Tfts5yyParser)(unsafe.Pointer(fts5yypParser)).Ffts5yytos)).Fstateno
|
|
for int32(1) != 0 { /* Exit by "break" */
|
|
fts5yyact = _fts5yy_find_shift_action(tls, libc.Uint8FromInt32(fts5yymajor), fts5yyact)
|
|
if libc.Int32FromUint8(fts5yyact) >= int32(fts5YY_MIN_REDUCE) {
|
|
fts5yyruleno = libc.Uint32FromInt32(libc.Int32FromUint8(fts5yyact) - int32(fts5YY_MIN_REDUCE)) /* Reduce by this rule */
|
|
/* Check that the stack is large enough to grow by a single entry
|
|
** if the RHS of the rule is empty. This ensures that there is room
|
|
** enough on the stack to push the LHS value */
|
|
if int32(_fts5yyRuleInfoNRhs[fts5yyruleno]) == 0 {
|
|
if (*Tfts5yyParser)(unsafe.Pointer(fts5yypParser)).Ffts5yytos >= (*Tfts5yyParser)(unsafe.Pointer(fts5yypParser)).Ffts5yystackEnd {
|
|
if int32(1) != 0 {
|
|
_fts5yyStackOverflow(tls, fts5yypParser)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
fts5yyact = _fts5yy_reduce(tls, fts5yypParser, fts5yyruleno, fts5yymajor, fts5yyminor)
|
|
} else {
|
|
if libc.Int32FromUint8(fts5yyact) <= int32(fts5YY_MAX_SHIFTREDUCE) {
|
|
_fts5yy_shift(tls, fts5yypParser, fts5yyact, libc.Uint8FromInt32(fts5yymajor), fts5yyminor)
|
|
break
|
|
} else {
|
|
if libc.Int32FromUint8(fts5yyact) == int32(fts5YY_ACCEPT_ACTION) {
|
|
(*Tfts5yyParser)(unsafe.Pointer(fts5yypParser)).Ffts5yytos -= 24
|
|
_fts5yy_accept(tls, fts5yypParser)
|
|
return
|
|
} else {
|
|
*(*TFts5Token)(unsafe.Pointer(bp)) = fts5yyminor
|
|
/* If the fts5YYNOERRORRECOVERY macro is defined, then do not attempt to
|
|
** do any kind of error recovery. Instead, simply invoke the syntax
|
|
** error routine and continue going as if nothing had happened.
|
|
**
|
|
** Applications can set this macro (for example inside %include) if
|
|
** they intend to abandon the parse upon the first syntax error seen.
|
|
*/
|
|
_fts5yy_syntax_error(tls, fts5yypParser, fts5yymajor, fts5yyminor)
|
|
_fts5yy_destructor(tls, fts5yypParser, libc.Uint8FromInt32(fts5yymajor), bp)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Clear all secondary memory allocations from the parser
|
|
// */
|
|
func _sqlite3Fts5ParserFinalize(tls *libc.TLS, p uintptr) {
|
|
var fts5yytos, pParser uintptr
|
|
_, _ = fts5yytos, pParser
|
|
pParser = p
|
|
/* In-lined version of calling fts5yy_pop_parser_stack() for each
|
|
** element left in the stack */
|
|
fts5yytos = (*Tfts5yyParser)(unsafe.Pointer(pParser)).Ffts5yytos
|
|
for fts5yytos > (*Tfts5yyParser)(unsafe.Pointer(pParser)).Ffts5yystack {
|
|
if libc.Int32FromUint8((*Tfts5yyStackEntry)(unsafe.Pointer(fts5yytos)).Fmajor) >= int32(fts5YY_MIN_DSTRCTR) {
|
|
_fts5yy_destructor(tls, pParser, (*Tfts5yyStackEntry)(unsafe.Pointer(fts5yytos)).Fmajor, fts5yytos+8)
|
|
}
|
|
fts5yytos -= 24
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Advance the iterator object passed as the only argument. Return true
|
|
// ** if the iterator reaches EOF, or false otherwise.
|
|
// */
|
|
func _sqlite3Fts5PoslistReaderNext(tls *libc.TLS, pIter uintptr) (r int32) {
|
|
if _sqlite3Fts5PoslistNext64(tls, (*TFts5PoslistReader)(unsafe.Pointer(pIter)).Fa, (*TFts5PoslistReader)(unsafe.Pointer(pIter)).Fn, pIter+12, pIter+24) != 0 {
|
|
(*TFts5PoslistReader)(unsafe.Pointer(pIter)).FbEof = uint8(1)
|
|
}
|
|
return libc.Int32FromUint8((*TFts5PoslistReader)(unsafe.Pointer(pIter)).FbEof)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Append position iPos to the position list being accumulated in buffer
|
|
// ** pBuf, which must be already be large enough to hold the new data.
|
|
// ** The previous position written to this list is *piPrev. *piPrev is set
|
|
// ** to iPos before returning.
|
|
// */
|
|
func _sqlite3Fts5PoslistSafeAppend(tls *libc.TLS, pBuf uintptr, piPrev uintptr, iPos Ti64) {
|
|
var v1 int32
|
|
var v2 uintptr
|
|
_, _ = v1, v2
|
|
if iPos >= **(**Ti64)(__ccgo_up(piPrev)) {
|
|
if iPos&_colmask != **(**Ti64)(__ccgo_up(piPrev))&_colmask {
|
|
v2 = pBuf + 8
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
**(**Tu8)(__ccgo_up((*TFts5Buffer)(unsafe.Pointer(pBuf)).Fp + uintptr(v1))) = uint8(1)
|
|
**(**int32)(__ccgo_up(pBuf + 8)) += _sqlite3Fts5PutVarint(tls, (*TFts5Buffer)(unsafe.Pointer(pBuf)).Fp+uintptr((*TFts5Buffer)(unsafe.Pointer(pBuf)).Fn), libc.Uint64FromInt64(iPos>>libc.Int32FromInt32(32)))
|
|
**(**Ti64)(__ccgo_up(piPrev)) = iPos & _colmask
|
|
}
|
|
**(**int32)(__ccgo_up(pBuf + 8)) += _sqlite3Fts5PutVarint(tls, (*TFts5Buffer)(unsafe.Pointer(pBuf)).Fp+uintptr((*TFts5Buffer)(unsafe.Pointer(pBuf)).Fn), libc.Uint64FromInt64(iPos-**(**Ti64)(__ccgo_up(piPrev))+int64(2)))
|
|
**(**Ti64)(__ccgo_up(piPrev)) = iPos
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Close a handle opened by an earlier call to sqlite3Fts5StorageOpen().
|
|
// */
|
|
func _sqlite3Fts5StorageClose(tls *libc.TLS, p uintptr) (r int32) {
|
|
var i, rc int32
|
|
_, _ = i, rc
|
|
rc = SQLITE_OK
|
|
if p != 0 {
|
|
/* Finalize all SQL statements */
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint64(libc.Uint64FromInt64(96)/libc.Uint64FromInt64(8))) {
|
|
break
|
|
}
|
|
Xsqlite3_finalize(tls, **(**uintptr)(__ccgo_up(p + 48 + uintptr(i)*8)))
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
Xsqlite3_free(tls, p)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Insert a new row into the FTS content table.
|
|
// */
|
|
func _sqlite3Fts5StorageContentInsert(tls *libc.TLS, p uintptr, bReplace int32, apVal uintptr, piRowid uintptr) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var bUnindexed, i, iLoc, rc int32
|
|
var pConfig, pVal uintptr
|
|
var _ /* nLoc at bp+28 */ int32
|
|
var _ /* nText at bp+24 */ int32
|
|
var _ /* pInsert at bp+0 */ uintptr
|
|
var _ /* pLoc at bp+16 */ uintptr
|
|
var _ /* pText at bp+8 */ uintptr
|
|
_, _, _, _, _, _ = bUnindexed, i, iLoc, pConfig, pVal, rc
|
|
pConfig = (*TFts5Storage)(unsafe.Pointer(p)).FpConfig
|
|
rc = SQLITE_OK
|
|
/* Insert the new row into the %_content table. */
|
|
if (*TFts5Config)(unsafe.Pointer(pConfig)).FeContent != FTS5_CONTENT_NORMAL && (*TFts5Config)(unsafe.Pointer(pConfig)).FeContent != int32(FTS5_CONTENT_UNINDEXED) {
|
|
if Xsqlite3_value_type(tls, **(**uintptr)(__ccgo_up(apVal + 1*8))) == int32(SQLITE_INTEGER) {
|
|
**(**Ti64)(__ccgo_up(piRowid)) = Xsqlite3_value_int64(tls, **(**uintptr)(__ccgo_up(apVal + 1*8)))
|
|
} else {
|
|
rc = _fts5StorageNewRowid(tls, p, piRowid)
|
|
}
|
|
} else {
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0) /* Counter variable */
|
|
rc = _fts5StorageGetStmt(tls, p, int32(FTS5_STMT_INSERT_CONTENT)+bReplace, bp, uintptr(0))
|
|
if **(**uintptr)(__ccgo_up(bp)) != 0 {
|
|
Xsqlite3_clear_bindings(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
}
|
|
/* Bind the rowid value */
|
|
Xsqlite3_bind_value(tls, **(**uintptr)(__ccgo_up(bp)), int32(1), **(**uintptr)(__ccgo_up(apVal + 1*8)))
|
|
/* Loop through values for user-defined columns. i=2 is the leftmost
|
|
** user-defined column. As is column 1 of pSavedRow. */
|
|
i = int32(2)
|
|
for {
|
|
if !(rc == SQLITE_OK && i <= (*TFts5Config)(unsafe.Pointer(pConfig)).FnCol+int32(1)) {
|
|
break
|
|
}
|
|
bUnindexed = libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TFts5Config)(unsafe.Pointer(pConfig)).FabUnindexed + uintptr(i-int32(2)))))
|
|
if (*TFts5Config)(unsafe.Pointer(pConfig)).FeContent == FTS5_CONTENT_NORMAL || bUnindexed != 0 {
|
|
pVal = **(**uintptr)(__ccgo_up(apVal + uintptr(i)*8))
|
|
if Xsqlite3_value_nochange(tls, pVal) != 0 && (*TFts5Storage)(unsafe.Pointer(p)).FpSavedRow != 0 {
|
|
/* This is an UPDATE statement, and user-defined column (i-2) was not
|
|
** modified. Retrieve the value from Fts5Storage.pSavedRow. */
|
|
pVal = Xsqlite3_column_value(tls, (*TFts5Storage)(unsafe.Pointer(p)).FpSavedRow, i-int32(1))
|
|
if (*TFts5Config)(unsafe.Pointer(pConfig)).FbLocale != 0 && bUnindexed == 0 {
|
|
Xsqlite3_bind_value(tls, **(**uintptr)(__ccgo_up(bp)), (*TFts5Config)(unsafe.Pointer(pConfig)).FnCol+i, Xsqlite3_column_value(tls, (*TFts5Storage)(unsafe.Pointer(p)).FpSavedRow, (*TFts5Config)(unsafe.Pointer(pConfig)).FnCol+i-int32(1)))
|
|
}
|
|
} else {
|
|
if _sqlite3Fts5IsLocaleValue(tls, pConfig, pVal) != 0 {
|
|
**(**uintptr)(__ccgo_up(bp + 8)) = uintptr(0)
|
|
**(**uintptr)(__ccgo_up(bp + 16)) = uintptr(0)
|
|
**(**int32)(__ccgo_up(bp + 24)) = 0
|
|
**(**int32)(__ccgo_up(bp + 28)) = 0
|
|
rc = _sqlite3Fts5DecodeLocaleValue(tls, pVal, bp+8, bp+24, bp+16, bp+28)
|
|
if rc == SQLITE_OK {
|
|
Xsqlite3_bind_text(tls, **(**uintptr)(__ccgo_up(bp)), i, **(**uintptr)(__ccgo_up(bp + 8)), **(**int32)(__ccgo_up(bp + 24)), uintptr(-libc.Int32FromInt32(1)))
|
|
if bUnindexed == 0 {
|
|
iLoc = (*TFts5Config)(unsafe.Pointer(pConfig)).FnCol + i
|
|
Xsqlite3_bind_text(tls, **(**uintptr)(__ccgo_up(bp)), iLoc, **(**uintptr)(__ccgo_up(bp + 16)), **(**int32)(__ccgo_up(bp + 28)), uintptr(-libc.Int32FromInt32(1)))
|
|
}
|
|
}
|
|
goto _1
|
|
}
|
|
}
|
|
rc = Xsqlite3_bind_value(tls, **(**uintptr)(__ccgo_up(bp)), i, pVal)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if rc == SQLITE_OK {
|
|
Xsqlite3_step(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
rc = Xsqlite3_reset(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
}
|
|
**(**Ti64)(__ccgo_up(piRowid)) = Xsqlite3_last_insert_rowid(tls, (*TFts5Config)(unsafe.Pointer(pConfig)).Fdb)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
func _sqlite3Fts5TermsetFree(tls *libc.TLS, p uintptr) {
|
|
var i Tu32
|
|
var pDel, pEntry uintptr
|
|
_, _, _ = i, pDel, pEntry
|
|
if p != 0 {
|
|
i = uint32(0)
|
|
for {
|
|
if !(i < libc.Uint32FromInt32(libc.Int32FromUint64(libc.Uint64FromInt64(4096)/libc.Uint64FromInt64(8)))) {
|
|
break
|
|
}
|
|
pEntry = **(**uintptr)(__ccgo_up(p + uintptr(i)*8))
|
|
for pEntry != 0 {
|
|
pDel = pEntry
|
|
pEntry = (*TFts5TermsetEntry)(unsafe.Pointer(pEntry)).FpNext
|
|
Xsqlite3_free(tls, pDel)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
Xsqlite3_free(tls, p)
|
|
}
|
|
}
|
|
|
|
/*
|
|
** 2014 Jun 09
|
|
**
|
|
** The author disclaims copyright to this source code. In place of
|
|
** a legal notice, here is a blessing:
|
|
**
|
|
** May you do good and not evil.
|
|
** May you find forgiveness for yourself and forgive others.
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
******************************************************************************
|
|
**
|
|
** This is an SQLite module implementing full-text search.
|
|
*/
|
|
|
|
/* #include "fts5Int.h" */
|
|
|
|
/* Maximum allowed page size */
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Interpret the argument as a unicode codepoint. If the codepoint
|
|
// ** is an upper case character that has a lower case equivalent,
|
|
// ** return the codepoint corresponding to the lower case version.
|
|
// ** Otherwise, return a copy of the argument.
|
|
// **
|
|
// ** The results are undefined if the value passed to this function
|
|
// ** is less than zero.
|
|
// */
|
|
func _sqlite3Fts5UnicodeFold(tls *libc.TLS, c int32, eRemoveDiacritic int32) (r int32) {
|
|
var cmp, iHi, iLo, iRes, iTest, ret int32
|
|
var p uintptr
|
|
_, _, _, _, _, _, _ = cmp, iHi, iLo, iRes, iTest, p, ret
|
|
ret = c
|
|
if c < int32(128) {
|
|
if c >= int32('A') && c <= int32('Z') {
|
|
ret = c + (libc.Int32FromUint8('a') - libc.Int32FromUint8('A'))
|
|
}
|
|
} else {
|
|
if c < int32(65536) {
|
|
iHi = libc.Int32FromUint64(libc.Uint64FromInt64(652)/libc.Uint64FromInt64(4) - libc.Uint64FromInt32(1))
|
|
iLo = 0
|
|
iRes = -int32(1)
|
|
for iHi >= iLo {
|
|
iTest = (iHi + iLo) / int32(2)
|
|
cmp = c - libc.Int32FromUint16(_aEntry[iTest].FiCode)
|
|
if cmp >= 0 {
|
|
iRes = iTest
|
|
iLo = iTest + int32(1)
|
|
} else {
|
|
iHi = iTest - int32(1)
|
|
}
|
|
}
|
|
p = uintptr(unsafe.Pointer(&_aEntry)) + uintptr(iRes)*4
|
|
if c < libc.Int32FromUint16((*struct {
|
|
FiCode uint16
|
|
Fflags uint8
|
|
FnRange uint8
|
|
})(unsafe.Pointer(p)).FiCode)+libc.Int32FromUint8((*struct {
|
|
FiCode uint16
|
|
Fflags uint8
|
|
FnRange uint8
|
|
})(unsafe.Pointer(p)).FnRange) && 0 == int32(0x01)&libc.Int32FromUint8((*struct {
|
|
FiCode uint16
|
|
Fflags uint8
|
|
FnRange uint8
|
|
})(unsafe.Pointer(p)).Fflags)&(libc.Int32FromUint16((*struct {
|
|
FiCode uint16
|
|
Fflags uint8
|
|
FnRange uint8
|
|
})(unsafe.Pointer(p)).FiCode)^c) {
|
|
ret = (c + libc.Int32FromUint16(_aiOff[libc.Int32FromUint8((*struct {
|
|
FiCode uint16
|
|
Fflags uint8
|
|
FnRange uint8
|
|
})(unsafe.Pointer(p)).Fflags)>>int32(1)])) & int32(0x0000FFFF)
|
|
}
|
|
if eRemoveDiacritic != 0 {
|
|
ret = _fts5_remove_diacritic(tls, ret, libc.BoolInt32(eRemoveDiacritic == int32(2)))
|
|
}
|
|
} else {
|
|
if c >= int32(66560) && c < int32(66600) {
|
|
ret = c + int32(40)
|
|
}
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code that will assemble an index key and stores it in register
|
|
// ** regOut. The key with be for index pIdx which is an index on pTab.
|
|
// ** iCur is the index of a cursor open on the pTab table and pointing to
|
|
// ** the entry that needs indexing. If pTab is a WITHOUT ROWID table, then
|
|
// ** iCur must be the cursor of the PRIMARY KEY index.
|
|
// **
|
|
// ** Return a register number which is the first in a block of
|
|
// ** registers that holds the elements of the index key. The
|
|
// ** block of registers has already been deallocated by the time
|
|
// ** this routine returns.
|
|
// **
|
|
// ** If *piPartIdxLabel is not NULL, fill it in with a label and jump
|
|
// ** to that label if pIdx is a partial index that should be skipped.
|
|
// ** The label should be resolved using sqlite3ResolvePartIdxLabel().
|
|
// ** A partial index should be skipped if its WHERE clause evaluates
|
|
// ** to false or null. If pIdx is not a partial index, *piPartIdxLabel
|
|
// ** will be set to zero which is an empty label that is ignored by
|
|
// ** sqlite3ResolvePartIdxLabel().
|
|
// **
|
|
// ** The pPrior and regPrior parameters are used to implement a cache to
|
|
// ** avoid unnecessary register loads. If pPrior is not NULL, then it is
|
|
// ** a pointer to a different index for which an index key has just been
|
|
// ** computed into register regPrior. If the current pIdx index is generating
|
|
// ** its key into the same sequence of registers and if pPrior and pIdx share
|
|
// ** a column in common, then the register corresponding to that column already
|
|
// ** holds the correct value and the loading of that register is skipped.
|
|
// ** This optimization is helpful when doing a DELETE or an INTEGRITY_CHECK
|
|
// ** on a table with multiple indices, and especially with the ROWID or
|
|
// ** PRIMARY KEY columns of the index.
|
|
// */
|
|
func _sqlite3GenerateIndexKey(tls *libc.TLS, pParse uintptr, pIdx uintptr, iDataCur int32, regOut int32, prefixOnly int32, piPartIdxLabel uintptr, pPrior uintptr, regPrior int32) (r int32) {
|
|
var j, nCol, regBase, v1 int32
|
|
var v uintptr
|
|
_, _, _, _, _ = j, nCol, regBase, v, v1
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
if piPartIdxLabel != 0 {
|
|
if (*TIndex)(unsafe.Pointer(pIdx)).FpPartIdxWhere != 0 {
|
|
**(**int32)(__ccgo_up(piPartIdxLabel)) = _sqlite3VdbeMakeLabel(tls, pParse)
|
|
(*TParse)(unsafe.Pointer(pParse)).FiSelfTab = iDataCur + int32(1)
|
|
_sqlite3ExprIfFalseDup(tls, pParse, (*TIndex)(unsafe.Pointer(pIdx)).FpPartIdxWhere, **(**int32)(__ccgo_up(piPartIdxLabel)), int32(SQLITE_JUMPIFNULL))
|
|
(*TParse)(unsafe.Pointer(pParse)).FiSelfTab = 0
|
|
pPrior = uintptr(0) /* Ticket a9efb42811fa41ee 2019-11-02;
|
|
** pPartIdxWhere may have corrupted regPrior registers */
|
|
} else {
|
|
**(**int32)(__ccgo_up(piPartIdxLabel)) = 0
|
|
}
|
|
}
|
|
if prefixOnly != 0 && int32(uint32(*(*uint16)(unsafe.Pointer(pIdx + 100))&0x8>>3)) != 0 {
|
|
v1 = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol)
|
|
} else {
|
|
v1 = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn)
|
|
}
|
|
nCol = v1
|
|
regBase = _sqlite3GetTempRange(tls, pParse, nCol)
|
|
if pPrior != 0 && (regBase != regPrior || (*TIndex)(unsafe.Pointer(pPrior)).FpPartIdxWhere != 0) {
|
|
pPrior = uintptr(0)
|
|
}
|
|
j = 0
|
|
for {
|
|
if !(j < nCol) {
|
|
break
|
|
}
|
|
if pPrior != 0 && int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pPrior)).FaiColumn + uintptr(j)*2))) == int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(j)*2))) && int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pPrior)).FaiColumn + uintptr(j)*2))) != -int32(2) {
|
|
/* This column was already computed by the previous index */
|
|
goto _2
|
|
}
|
|
_sqlite3ExprCodeLoadIndexColumn(tls, pParse, pIdx, iDataCur, j, regBase+j)
|
|
if int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(j)*2))) >= 0 {
|
|
/* If the column affinity is REAL but the number is an integer, then it
|
|
** might be stored in the table as an integer (using a compact
|
|
** representation) then converted to REAL by an OP_RealAffinity opcode.
|
|
** But we are getting ready to store this value back into an index, where
|
|
** it should be converted by to INTEGER again. So omit the
|
|
** OP_RealAffinity opcode if it is present */
|
|
_sqlite3VdbeDeletePriorOpcode(tls, v, uint8(OP_RealAffinity))
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
j = j + 1
|
|
}
|
|
if regOut != 0 {
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_MakeRecord), regBase, nCol, regOut)
|
|
}
|
|
_sqlite3ReleaseTempRange(tls, pParse, regBase, nCol)
|
|
return regBase
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine generates VDBE code that causes the deletion of all
|
|
// ** index entries associated with a single row of a single table, pTab
|
|
// **
|
|
// ** Preconditions:
|
|
// **
|
|
// ** 1. A read/write cursor "iDataCur" must be open on the canonical storage
|
|
// ** btree for the table pTab. (This will be either the table itself
|
|
// ** for rowid tables or to the primary key index for WITHOUT ROWID
|
|
// ** tables.)
|
|
// **
|
|
// ** 2. Read/write cursors for all indices of pTab must be open as
|
|
// ** cursor number iIdxCur+i for the i-th index. (The pTab->pIndex
|
|
// ** index is the 0-th index.)
|
|
// **
|
|
// ** 3. The "iDataCur" cursor must be already be positioned on the row
|
|
// ** that is to be deleted.
|
|
// */
|
|
func _sqlite3GenerateRowIndexDelete(tls *libc.TLS, pParse uintptr, pTab uintptr, iDataCur int32, iIdxCur int32, aRegIdx uintptr, iIdxNoSeek int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var i, r1, v3 int32
|
|
var pIdx, pPk, pPrior, v, v1 uintptr
|
|
var _ /* iPartIdxLabel at bp+0 */ int32
|
|
_, _, _, _, _, _, _, _ = i, pIdx, pPk, pPrior, r1, v, v1, v3 /* Index loop counter */
|
|
r1 = -int32(1) /* Current index */
|
|
pPrior = uintptr(0) /* PRIMARY KEY index, or NULL for rowid tables */
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
if (*TTable)(unsafe.Pointer(pTab)).FtabFlags&uint32(TF_WithoutRowid) == uint32(0) {
|
|
v1 = uintptr(0)
|
|
} else {
|
|
v1 = _sqlite3PrimaryKeyIndex(tls, pTab)
|
|
}
|
|
pPk = v1
|
|
i = 0
|
|
pIdx = (*TTable)(unsafe.Pointer(pTab)).FpIndex
|
|
for {
|
|
if !(pIdx != 0) {
|
|
break
|
|
}
|
|
if aRegIdx != uintptr(0) && **(**int32)(__ccgo_up(aRegIdx + uintptr(i)*4)) == 0 {
|
|
goto _2
|
|
}
|
|
if pIdx == pPk {
|
|
goto _2
|
|
}
|
|
if iIdxCur+i == iIdxNoSeek {
|
|
goto _2
|
|
}
|
|
r1 = _sqlite3GenerateIndexKey(tls, pParse, pIdx, iDataCur, 0, int32(1), bp, pPrior, r1)
|
|
if int32(uint32(*(*uint16)(unsafe.Pointer(pIdx + 100))&0x8>>3)) != 0 {
|
|
v3 = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol)
|
|
} else {
|
|
v3 = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn)
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_IdxDelete), iIdxCur+i, r1, v3)
|
|
_sqlite3VdbeChangeP4(tls, v, -int32(1), pIdx, -int32(6))
|
|
_sqlite3ResolvePartIdxLabel(tls, pParse, **(**int32)(__ccgo_up(bp)))
|
|
pPrior = pIdx
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
pIdx = (*TIndex)(unsafe.Pointer(pIdx)).FpNext
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate a single new register for use to hold some intermediate result.
|
|
// */
|
|
func _sqlite3GetTempReg(tls *libc.TLS, pParse uintptr) (r int32) {
|
|
var v1 int32
|
|
var v2 uintptr
|
|
var v3 Tu8
|
|
_, _, _ = v1, v2, v3
|
|
if libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FnTempReg) == 0 {
|
|
v2 = pParse + 60
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
return v1
|
|
}
|
|
v2 = pParse + 31
|
|
*(*Tu8)(unsafe.Pointer(v2)) = *(*Tu8)(unsafe.Pointer(v2)) - 1
|
|
v3 = *(*Tu8)(unsafe.Pointer(v2))
|
|
return **(**int32)(__ccgo_up(pParse + 192 + uintptr(v3)*4))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Get a VDBE for the given parser context. Create a new one if necessary.
|
|
// ** If an error occurs, return NULL and leave a message in pParse.
|
|
// */
|
|
func _sqlite3GetVdbe(tls *libc.TLS, pParse uintptr) (r uintptr) {
|
|
if (*TParse)(unsafe.Pointer(pParse)).FpVdbe != 0 {
|
|
return (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
}
|
|
if (*TParse)(unsafe.Pointer(pParse)).FpToplevel == uintptr(0) && (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).FdbOptFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_FactorOutConst)) == uint32(0) {
|
|
libc.SetBitFieldPtr16Uint32(pParse+40, libc.Uint32FromInt32(1), 7, 0x80)
|
|
}
|
|
return _sqlite3VdbeCreate(tls, pParse)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the size of the header added to each page by this module.
|
|
// */
|
|
func _sqlite3HeaderSizeBtree(tls *libc.TLS) (r int32) {
|
|
return libc.Int32FromUint64((libc.Uint64FromInt64(136) + libc.Uint64FromInt32(7)) & libc.Uint64FromInt32(^libc.Int32FromInt32(7)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the size of the header added by this middleware layer
|
|
// ** in the page-cache hierarchy.
|
|
// */
|
|
func _sqlite3HeaderSizePcache(tls *libc.TLS) (r int32) {
|
|
return libc.Int32FromUint64((libc.Uint64FromInt64(80) + libc.Uint64FromInt32(7)) & libc.Uint64FromInt32(^libc.Int32FromInt32(7)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the size of the header on each page of this PCACHE implementation.
|
|
// */
|
|
func _sqlite3HeaderSizePcache1(tls *libc.TLS) (r int32) {
|
|
return libc.Int32FromUint64((libc.Uint64FromInt64(56) + libc.Uint64FromInt32(7)) & libc.Uint64FromInt32(^libc.Int32FromInt32(7)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Append a new element to the given IdList. Create a new IdList if
|
|
// ** need be.
|
|
// **
|
|
// ** A new IdList is returned, or NULL if malloc() fails.
|
|
// */
|
|
func _sqlite3IdListAppend(tls *libc.TLS, pParse uintptr, pList uintptr, pToken uintptr) (r uintptr) {
|
|
var db, pNew, v2 uintptr
|
|
var i, v1 int32
|
|
_, _, _, _, _ = db, i, pNew, v1, v2
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
if pList == uintptr(0) {
|
|
pList = _sqlite3DbMallocZero(tls, db, uint64(uint64(libc.UintptrFromInt32(0)+8)+libc.Uint64FromInt32(libc.Int32FromInt32(1))*libc.Uint64FromInt64(8)))
|
|
if pList == uintptr(0) {
|
|
return uintptr(0)
|
|
}
|
|
} else {
|
|
pNew = _sqlite3DbRealloc(tls, db, pList, uint64(uint64(libc.UintptrFromInt32(0)+8)+libc.Uint64FromInt32((*TIdList)(unsafe.Pointer(pList)).FnId+libc.Int32FromInt32(1))*libc.Uint64FromInt64(8)))
|
|
if pNew == uintptr(0) {
|
|
_sqlite3IdListDelete(tls, db, pList)
|
|
return uintptr(0)
|
|
}
|
|
pList = pNew
|
|
}
|
|
v2 = pList
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
i = v1
|
|
(*(*TIdList_item)(unsafe.Pointer(pList + 8 + uintptr(i)*8))).FzName = _sqlite3NameFromToken(tls, db, pToken)
|
|
if libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) >= int32(PARSE_MODE_RENAME) && (*(*TIdList_item)(unsafe.Pointer(pList + 8 + uintptr(i)*8))).FzName != 0 {
|
|
_sqlite3RenameTokenMap(tls, pParse, (*(*TIdList_item)(unsafe.Pointer(pList + 8 + uintptr(i)*8))).FzName, pToken)
|
|
}
|
|
return pList
|
|
}
|
|
|
|
func _sqlite3IdListDup(tls *libc.TLS, db uintptr, p uintptr) (r uintptr) {
|
|
var i int32
|
|
var pNew, pNewItem, pOldItem uintptr
|
|
_, _, _, _ = i, pNew, pNewItem, pOldItem
|
|
if p == uintptr(0) {
|
|
return uintptr(0)
|
|
}
|
|
pNew = _sqlite3DbMallocRawNN(tls, db, uint64(uint64(libc.UintptrFromInt32(0)+8)+libc.Uint64FromInt32((*TIdList)(unsafe.Pointer(p)).FnId)*libc.Uint64FromInt64(8)))
|
|
if pNew == uintptr(0) {
|
|
return uintptr(0)
|
|
}
|
|
(*TIdList)(unsafe.Pointer(pNew)).FnId = (*TIdList)(unsafe.Pointer(p)).FnId
|
|
i = 0
|
|
for {
|
|
if !(i < (*TIdList)(unsafe.Pointer(p)).FnId) {
|
|
break
|
|
}
|
|
pNewItem = pNew + 8 + uintptr(i)*8
|
|
pOldItem = p + 8 + uintptr(i)*8
|
|
(*TIdList_item)(unsafe.Pointer(pNewItem)).FzName = _sqlite3DbStrDup(tls, db, (*TIdList_item)(unsafe.Pointer(pOldItem)).FzName)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return pNew
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Initialize all database files - the main database file, the file
|
|
// ** used to store temporary tables, and any additional database files
|
|
// ** created using ATTACH statements. Return a success code. If an
|
|
// ** error occurs, write an error message into *pzErrMsg.
|
|
// **
|
|
// ** After a database is initialized, the DB_SchemaLoaded bit is set
|
|
// ** bit is set in the flags field of the Db structure.
|
|
// */
|
|
func _sqlite3Init(tls *libc.TLS, db uintptr, pzErrMsg uintptr) (r int32) {
|
|
var commit_internal, i, rc int32
|
|
_, _, _ = commit_internal, i, rc
|
|
commit_internal = libc.BoolInt32(!((*Tsqlite3)(unsafe.Pointer(db)).FmDbFlags&libc.Uint32FromInt32(DBFLAG_SchemaChange) != 0))
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Fenc = (*TSchema)(unsafe.Pointer((**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb))).FpSchema)).Fenc
|
|
/* Do the main schema first */
|
|
if !(libc.Int32FromUint16((*TSchema)(unsafe.Pointer((**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb))).FpSchema)).FschemaFlags)&libc.Int32FromInt32(DB_SchemaLoaded) == libc.Int32FromInt32(DB_SchemaLoaded)) {
|
|
rc = _sqlite3InitOne(tls, db, 0, pzErrMsg, uint32(0))
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
}
|
|
/* All other schemas after the main schema. The "temp" schema must be last */
|
|
i = (*Tsqlite3)(unsafe.Pointer(db)).FnDb - int32(1)
|
|
for {
|
|
if !(i > 0) {
|
|
break
|
|
}
|
|
if !(libc.Int32FromUint16((*TSchema)(unsafe.Pointer((**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(i)*32))).FpSchema)).FschemaFlags)&libc.Int32FromInt32(DB_SchemaLoaded) == libc.Int32FromInt32(DB_SchemaLoaded)) {
|
|
rc = _sqlite3InitOne(tls, db, i, pzErrMsg, uint32(0))
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i - 1
|
|
}
|
|
if commit_internal != 0 {
|
|
_sqlite3CommitInternalChanges(tls, db)
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Parameter eMode must be one of the PAGER_JOURNALMODE_XXX constants
|
|
// ** defined in pager.h. This function returns the associated lowercase
|
|
// ** journal-mode name.
|
|
// */
|
|
func _sqlite3JournalModename(tls *libc.TLS, eMode int32) (r uintptr) {
|
|
if eMode == libc.Int32FromUint64(libc.Uint64FromInt64(48)/libc.Uint64FromInt64(8)) {
|
|
return uintptr(0)
|
|
}
|
|
return _azModeName[eMode]
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return a KeyInfo structure that is appropriate for the given Index.
|
|
// **
|
|
// ** The caller should invoke sqlite3KeyInfoUnref() on the returned object
|
|
// ** when it has finished using it.
|
|
// */
|
|
func _sqlite3KeyInfoOfIndex(tls *libc.TLS, pParse uintptr, pIdx uintptr) (r uintptr) {
|
|
var i, nCol, nKey int32
|
|
var pKey, zColl, v2 uintptr
|
|
_, _, _, _, _, _ = i, nCol, nKey, pKey, zColl, v2
|
|
nCol = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn)
|
|
nKey = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol)
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr != 0 {
|
|
return uintptr(0)
|
|
}
|
|
if int32(uint32(*(*uint16)(unsafe.Pointer(pIdx + 100))&0x8>>3)) != 0 {
|
|
pKey = _sqlite3KeyInfoAlloc(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, nKey, nCol-nKey)
|
|
} else {
|
|
pKey = _sqlite3KeyInfoAlloc(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, nCol, 0)
|
|
}
|
|
if pKey != 0 {
|
|
i = 0
|
|
for {
|
|
if !(i < nCol) {
|
|
break
|
|
}
|
|
zColl = **(**uintptr)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FazColl + uintptr(i)*8))
|
|
if zColl == uintptr(unsafe.Pointer(&_sqlite3StrBINARY)) {
|
|
v2 = uintptr(0)
|
|
} else {
|
|
v2 = _sqlite3LocateCollSeq(tls, pParse, zColl)
|
|
}
|
|
*(*uintptr)(unsafe.Pointer(pKey + 32 + uintptr(i)*8)) = v2
|
|
**(**Tu8)(__ccgo_up((*TKeyInfo)(unsafe.Pointer(pKey)).FaSortFlags + uintptr(i))) = **(**Tu8)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaSortOrder + uintptr(i)))
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr != 0 {
|
|
if int32(uint32(*(*uint16)(unsafe.Pointer(pIdx + 100))&0x100>>8)) == 0 && _sqlite3HashFind(tls, (*TIndex)(unsafe.Pointer(pIdx)).FpSchema+32, (*TIndex)(unsafe.Pointer(pIdx)).FzName) != 0 {
|
|
/* Deactivate the index because it contains an unknown collating
|
|
** sequence. The only way to reactive the index is to reload the
|
|
** schema. Adding the missing collating sequence later does not
|
|
** reactive the index. The application had the chance to register
|
|
** the missing index using the collation-needed callback. For
|
|
** simplicity, SQLite will not give the application a second chance.
|
|
**
|
|
** Except, do not do this if the index is not in the schema hash
|
|
** table. In this case the index is currently being constructed
|
|
** by a CREATE INDEX statement, and retrying will not help. */
|
|
libc.SetBitFieldPtr16Uint32(pIdx+100, libc.Uint32FromInt32(1), 8, 0x100)
|
|
(*TParse)(unsafe.Pointer(pParse)).Frc = libc.Int32FromInt32(SQLITE_ERROR) | libc.Int32FromInt32(2)<<libc.Int32FromInt32(8)
|
|
}
|
|
_sqlite3KeyInfoUnref(tls, pKey)
|
|
pKey = uintptr(0)
|
|
}
|
|
}
|
|
return pKey
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Close the mutex on database connection db.
|
|
// **
|
|
// ** Furthermore, if database connection db is a zombie (meaning that there
|
|
// ** has been a prior call to sqlite3_close(db) or sqlite3_close_v2(db)) and
|
|
// ** every sqlite3_stmt has now been finalized and every sqlite3_backup has
|
|
// ** finished, then free all resources.
|
|
// */
|
|
func _sqlite3LeaveMutexAndCloseZombie(tls *libc.TLS, db uintptr) {
|
|
var i, p, pColl, pDb, pMod, pNext uintptr
|
|
var j int32
|
|
_, _, _, _, _, _, _ = i, j, p, pColl, pDb, pMod, pNext
|
|
/* If there are outstanding sqlite3_stmt or sqlite3_backup objects
|
|
** or if the connection has not yet been closed by sqlite3_close_v2(),
|
|
** then just leave the mutex and return.
|
|
*/
|
|
if libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).FeOpenState) != int32(SQLITE_STATE_ZOMBIE) || _connectionIsBusy(tls, db) != 0 {
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
return
|
|
}
|
|
/* If we reach this point, it means that the database connection has
|
|
** closed all sqlite3_stmt and sqlite3_backup objects and has been
|
|
** passed to sqlite3_close (meaning that it is a zombie). Therefore,
|
|
** go ahead and free all resources.
|
|
*/
|
|
/* If a transaction is open, roll it back. This also ensures that if
|
|
** any database schemas have been modified by an uncommitted transaction
|
|
** they are reset. And that the required b-tree mutex is held to make
|
|
** the pager rollback and schema reset an atomic operation. */
|
|
_sqlite3RollbackAll(tls, db, SQLITE_OK)
|
|
/* Free any outstanding Savepoint structures. */
|
|
_sqlite3CloseSavepoints(tls, db)
|
|
/* Close all database connections */
|
|
j = 0
|
|
for {
|
|
if !(j < (*Tsqlite3)(unsafe.Pointer(db)).FnDb) {
|
|
break
|
|
}
|
|
pDb = (*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(j)*32
|
|
if (*TDb)(unsafe.Pointer(pDb)).FpBt != 0 {
|
|
_sqlite3BtreeClose(tls, (*TDb)(unsafe.Pointer(pDb)).FpBt)
|
|
(*TDb)(unsafe.Pointer(pDb)).FpBt = uintptr(0)
|
|
if j != int32(1) {
|
|
(*TDb)(unsafe.Pointer(pDb)).FpSchema = uintptr(0)
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
j = j + 1
|
|
}
|
|
/* Clear the TEMP schema separately and last */
|
|
if (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + 1*32))).FpSchema != 0 {
|
|
_sqlite3SchemaClear(tls, (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + 1*32))).FpSchema)
|
|
}
|
|
_sqlite3VtabUnlockList(tls, db)
|
|
/* Free up the array of auxiliary databases */
|
|
_sqlite3CollapseDatabaseArray(tls, db)
|
|
/* Tell the code in notify.c that the connection no longer holds any
|
|
** locks and does not require any further unlock-notify callbacks.
|
|
*/
|
|
_sqlite3ConnectionClosed(tls, db)
|
|
i = (*THash)(unsafe.Pointer(db + 624)).Ffirst
|
|
for {
|
|
if !(i != 0) {
|
|
break
|
|
}
|
|
p = (*THashElem)(unsafe.Pointer(i)).Fdata
|
|
for cond := true; cond; cond = p != 0 {
|
|
_functionDestroy(tls, db, p)
|
|
pNext = (*TFuncDef)(unsafe.Pointer(p)).FpNext
|
|
_sqlite3DbFree(tls, db, p)
|
|
p = pNext
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = (*THashElem)(unsafe.Pointer(i)).Fnext
|
|
}
|
|
_sqlite3HashClear(tls, db+624)
|
|
i = (*THash)(unsafe.Pointer(db + 648)).Ffirst
|
|
for {
|
|
if !(i != 0) {
|
|
break
|
|
}
|
|
pColl = (*THashElem)(unsafe.Pointer(i)).Fdata
|
|
/* Invoke any destructors registered for collation sequence user data. */
|
|
j = 0
|
|
for {
|
|
if !(j < int32(3)) {
|
|
break
|
|
}
|
|
if (**(**TCollSeq)(__ccgo_up(pColl + uintptr(j)*40))).FxDel != 0 {
|
|
(*(*func(*libc.TLS, uintptr))(unsafe.Pointer(&struct{ uintptr }{(**(**TCollSeq)(__ccgo_up(pColl + uintptr(j)*40))).FxDel})))(tls, (**(**TCollSeq)(__ccgo_up(pColl + uintptr(j)*40))).FpUser)
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
j = j + 1
|
|
}
|
|
_sqlite3DbFree(tls, db, pColl)
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = (*THashElem)(unsafe.Pointer(i)).Fnext
|
|
}
|
|
_sqlite3HashClear(tls, db+648)
|
|
i = (*THash)(unsafe.Pointer(db + 576)).Ffirst
|
|
for {
|
|
if !(i != 0) {
|
|
break
|
|
}
|
|
pMod = (*THashElem)(unsafe.Pointer(i)).Fdata
|
|
_sqlite3VtabEponymousTableClear(tls, db, pMod)
|
|
_sqlite3VtabModuleUnref(tls, db, pMod)
|
|
goto _5
|
|
_5:
|
|
;
|
|
i = (*THashElem)(unsafe.Pointer(i)).Fnext
|
|
}
|
|
_sqlite3HashClear(tls, db+576)
|
|
_sqlite3Error(tls, db, SQLITE_OK) /* Deallocates any cached error strings. */
|
|
_sqlite3ValueFree(tls, (*Tsqlite3)(unsafe.Pointer(db)).FpErr)
|
|
_sqlite3CloseExtensions(tls, db)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FeOpenState = uint8(SQLITE_STATE_ERROR)
|
|
/* The temp-database schema is allocated differently from the other schema
|
|
** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()).
|
|
** So it needs to be freed here. Todo: Why not roll the temp schema into
|
|
** the same sqliteMalloc() as the one that allocates the database
|
|
** structure?
|
|
*/
|
|
_sqlite3DbFree(tls, db, (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + 1*32))).FpSchema)
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FxAutovacDestr != 0 {
|
|
(*(*func(*libc.TLS, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*Tsqlite3)(unsafe.Pointer(db)).FxAutovacDestr})))(tls, (*Tsqlite3)(unsafe.Pointer(db)).FpAutovacPagesArg)
|
|
}
|
|
Xsqlite3_mutex_leave(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FeOpenState = uint8(SQLITE_STATE_CLOSED)
|
|
Xsqlite3_mutex_free(tls, (*Tsqlite3)(unsafe.Pointer(db)).Fmutex)
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FbMalloced != 0 {
|
|
Xsqlite3_free(tls, (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FpStart)
|
|
}
|
|
Xsqlite3_free(tls, db)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine is called when the extension is loaded.
|
|
// ** Register the new VFS.
|
|
// */
|
|
func _sqlite3MemdbInit(tls *libc.TLS) (r int32) {
|
|
var pLower uintptr
|
|
var sz uint32
|
|
_, _ = pLower, sz
|
|
pLower = Xsqlite3_vfs_find(tls, uintptr(0))
|
|
if pLower == uintptr(0) {
|
|
return int32(SQLITE_ERROR)
|
|
}
|
|
sz = libc.Uint32FromInt32((*Tsqlite3_vfs)(unsafe.Pointer(pLower)).FszOsFile)
|
|
_memdb_vfs.FpAppData = pLower
|
|
/* The following conditional can only be true when compiled for
|
|
** Windows x86 and SQLITE_MAX_MMAP_SIZE=0. We always leave
|
|
** it in, to be safe, but it is marked as NO_TEST since there
|
|
** is no way to reach it under most builds. */
|
|
if uint64(sz) < uint64(24) {
|
|
sz = uint32(24)
|
|
} /*NO_TEST*/
|
|
_memdb_vfs.FszOsFile = libc.Int32FromUint32(sz)
|
|
return Xsqlite3_vfs_register(tls, uintptr(unsafe.Pointer(&_memdb_vfs)), 0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called by the parser for the second and subsequent
|
|
// ** rows of a multi-row VALUES clause. Argument pLeft is the part of
|
|
// ** the VALUES clause already parsed, argument pRow is the vector of values
|
|
// ** for the new row. The Select object returned represents the complete
|
|
// ** VALUES clause, including the new row.
|
|
// **
|
|
// ** There are two ways in which this may be achieved - by incremental
|
|
// ** coding of a co-routine (the "co-routine" method) or by returning a
|
|
// ** Select object equivalent to the following (the "UNION ALL" method):
|
|
// **
|
|
// ** "pLeft UNION ALL SELECT pRow"
|
|
// **
|
|
// ** If the VALUES clause contains a lot of rows, this compound Select
|
|
// ** object may consume a lot of memory.
|
|
// **
|
|
// ** When the co-routine method is used, each row that will be returned
|
|
// ** by the VALUES clause is coded into part of a co-routine as it is
|
|
// ** passed to this function. The returned Select object is equivalent to:
|
|
// **
|
|
// ** SELECT * FROM (
|
|
// ** Select object to read co-routine
|
|
// ** )
|
|
// **
|
|
// ** The co-routine method is used in most cases. Exceptions are:
|
|
// **
|
|
// ** a) If the current statement has a WITH clause. This is to avoid
|
|
// ** statements like:
|
|
// **
|
|
// ** WITH cte AS ( VALUES('x'), ('y') ... )
|
|
// ** SELECT * FROM cte AS a, cte AS b;
|
|
// **
|
|
// ** This will not work, as the co-routine uses a hard-coded register
|
|
// ** for its OP_Yield instructions, and so it is not possible for two
|
|
// ** cursors to iterate through it concurrently.
|
|
// **
|
|
// ** b) The schema is currently being parsed (i.e. the VALUES clause is part
|
|
// ** of a schema item like a VIEW or TRIGGER). In this case there is no VM
|
|
// ** being generated when parsing is taking place, and so generating
|
|
// ** a co-routine is not possible.
|
|
// **
|
|
// ** c) There are non-constant expressions in the VALUES clause (e.g.
|
|
// ** the VALUES clause is part of a correlated sub-query).
|
|
// **
|
|
// ** d) One or more of the values in the first row of the VALUES clause
|
|
// ** has an affinity (i.e. is a CAST expression). This causes problems
|
|
// ** because the complex rules SQLite uses (see function
|
|
// ** sqlite3SubqueryColumnTypes() in select.c) to determine the effective
|
|
// ** affinity of such a column for all rows require access to all values in
|
|
// ** the column simultaneously.
|
|
// */
|
|
func _sqlite3MultiValues(tls *libc.TLS, pParse uintptr, pLeft uintptr, pRow uintptr) (r uintptr) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var f, v1 int32
|
|
var p, pRet, pSelect, pSubq, pSubq1, v, v2 uintptr
|
|
var _ /* dest at bp+0 */ TSelectDest
|
|
_, _, _, _, _, _, _, _, _ = f, p, pRet, pSelect, pSubq, pSubq1, v, v1, v2
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(pParse + 40))&0x40>>6)) != 0 || (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).Finit1.Fbusy != 0 || _exprListIsConstant(tls, pParse, pRow) == 0 || (*TSrcList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pLeft)).FpSrc)).FnSrc == 0 && _exprListIsNoAffinity(tls, pParse, (*TSelect)(unsafe.Pointer(pLeft)).FpEList) == 0 || libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) != PARSE_MODE_NORMAL {
|
|
/* The co-routine method cannot be used. Fall back to UNION ALL. */
|
|
pSelect = uintptr(0)
|
|
f = libc.Int32FromInt32(SF_Values) | libc.Int32FromInt32(SF_MultiValue)
|
|
if (*TSrcList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pLeft)).FpSrc)).FnSrc != 0 {
|
|
_sqlite3MultiValuesEnd(tls, pParse, pLeft)
|
|
f = int32(SF_Values)
|
|
} else {
|
|
if (*TSelect)(unsafe.Pointer(pLeft)).FpPrior != 0 {
|
|
/* In this case set the SF_MultiValue flag only if it was set on pLeft */
|
|
f = libc.Int32FromUint32(libc.Uint32FromInt32(f) & (*TSelect)(unsafe.Pointer(pLeft)).FselFlags)
|
|
}
|
|
}
|
|
pSelect = _sqlite3SelectNew(tls, pParse, pRow, uintptr(0), uintptr(0), uintptr(0), uintptr(0), uintptr(0), libc.Uint32FromInt32(f), uintptr(0))
|
|
**(**Tu32)(__ccgo_up(pLeft + 4)) &= ^libc.Uint32FromInt32(SF_MultiValue)
|
|
if pSelect != 0 {
|
|
(*TSelect)(unsafe.Pointer(pSelect)).Fop = uint8(TK_ALL)
|
|
(*TSelect)(unsafe.Pointer(pSelect)).FpPrior = pLeft
|
|
pLeft = pSelect
|
|
}
|
|
} else {
|
|
p = uintptr(0) /* SrcItem that reads from co-routine */
|
|
if (*TSrcList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pLeft)).FpSrc)).FnSrc == 0 {
|
|
/* Co-routine has not yet been started and the special Select object
|
|
** that accesses the co-routine has not yet been created. This block
|
|
** does both those things. */
|
|
v = _sqlite3GetVdbe(tls, pParse)
|
|
pRet = _sqlite3SelectNew(tls, pParse, uintptr(0), uintptr(0), uintptr(0), uintptr(0), uintptr(0), uintptr(0), uint32(0), uintptr(0))
|
|
/* Ensure the database schema has been read. This is to ensure we have
|
|
** the correct text encoding. */
|
|
if (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).FmDbFlags&uint32(DBFLAG_SchemaKnownOk) == uint32(0) {
|
|
_sqlite3ReadSchema(tls, pParse)
|
|
}
|
|
if pRet != 0 {
|
|
(*TSrcList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pRet)).FpSrc)).FnSrc = int32(1)
|
|
(*TSelect)(unsafe.Pointer(pRet)).FpPrior = (*TSelect)(unsafe.Pointer(pLeft)).FpPrior
|
|
(*TSelect)(unsafe.Pointer(pRet)).Fop = (*TSelect)(unsafe.Pointer(pLeft)).Fop
|
|
if (*TSelect)(unsafe.Pointer(pRet)).FpPrior != 0 {
|
|
**(**Tu32)(__ccgo_up(pRet + 4)) |= uint32(SF_Values)
|
|
}
|
|
(*TSelect)(unsafe.Pointer(pLeft)).FpPrior = uintptr(0)
|
|
(*TSelect)(unsafe.Pointer(pLeft)).Fop = uint8(TK_SELECT)
|
|
p = (*TSelect)(unsafe.Pointer(pRet)).FpSrc + 8
|
|
libc.SetBitFieldPtr32Uint32(p+24+4, libc.Uint32FromInt32(1), 6, 0x40)
|
|
(*TSrcItem)(unsafe.Pointer(p)).FiCursor = -int32(1)
|
|
*(*Tu32)(unsafe.Pointer(&(*TSrcItem)(unsafe.Pointer(p)).Fu1)) = uint32(2)
|
|
if _sqlite3SrcItemAttachSubquery(tls, pParse, p, pLeft, 0) != 0 {
|
|
pSubq = *(*uintptr)(unsafe.Pointer(p + 72))
|
|
(*TSubquery)(unsafe.Pointer(pSubq)).FaddrFillSub = _sqlite3VdbeCurrentAddr(tls, v) + int32(1)
|
|
v2 = pParse + 60
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
(*TSubquery)(unsafe.Pointer(pSubq)).FregReturn = v1
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_InitCoroutine), (*TSubquery)(unsafe.Pointer(pSubq)).FregReturn, 0, (*TSubquery)(unsafe.Pointer(pSubq)).FaddrFillSub)
|
|
_sqlite3SelectDestInit(tls, bp, int32(SRT_Coroutine), (*TSubquery)(unsafe.Pointer(pSubq)).FregReturn)
|
|
/* Allocate registers for the output of the co-routine. Do so so
|
|
** that there are two unused registers immediately before those
|
|
** used by the co-routine. This allows the code in sqlite3Insert()
|
|
** to use these registers directly, instead of copying the output
|
|
** of the co-routine to a separate array for processing. */
|
|
(**(**TSelectDest)(__ccgo_up(bp))).FiSdst = (*TParse)(unsafe.Pointer(pParse)).FnMem + int32(3)
|
|
(**(**TSelectDest)(__ccgo_up(bp))).FnSdst = (*TExprList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(pLeft)).FpEList)).FnExpr
|
|
**(**int32)(__ccgo_up(pParse + 60)) += int32(2) + (**(**TSelectDest)(__ccgo_up(bp))).FnSdst
|
|
**(**Tu32)(__ccgo_up(pLeft + 4)) |= uint32(SF_MultiValue)
|
|
_sqlite3Select(tls, pParse, pLeft, bp)
|
|
(*TSubquery)(unsafe.Pointer(pSubq)).FregResult = (**(**TSelectDest)(__ccgo_up(bp))).FiSdst
|
|
}
|
|
pLeft = pRet
|
|
}
|
|
} else {
|
|
p = (*TSelect)(unsafe.Pointer(pLeft)).FpSrc + 8
|
|
*(*Tu32)(unsafe.Pointer(&(*TSrcItem)(unsafe.Pointer(p)).Fu1)) = *(*Tu32)(unsafe.Pointer(&(*TSrcItem)(unsafe.Pointer(p)).Fu1)) + 1
|
|
}
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr == 0 {
|
|
pSubq1 = *(*uintptr)(unsafe.Pointer(p + 72))
|
|
if (*TExprList)(unsafe.Pointer((*TSelect)(unsafe.Pointer((*TSubquery)(unsafe.Pointer(pSubq1)).FpSelect)).FpEList)).FnExpr != (*TExprList)(unsafe.Pointer(pRow)).FnExpr {
|
|
_sqlite3SelectWrongNumTermsError(tls, pParse, (*TSubquery)(unsafe.Pointer(pSubq1)).FpSelect)
|
|
} else {
|
|
_sqlite3ExprCodeExprList(tls, pParse, pRow, (*TSubquery)(unsafe.Pointer(pSubq1)).FregResult, 0, uint8(0))
|
|
_sqlite3VdbeAddOp1(tls, (*TParse)(unsafe.Pointer(pParse)).FpVdbe, int32(OP_Yield), (*TSubquery)(unsafe.Pointer(pSubq1)).FregReturn)
|
|
}
|
|
}
|
|
_sqlite3ExprListDelete(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pRow)
|
|
}
|
|
return pLeft
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine reactivates the memory allocator and clears the
|
|
// ** db->mallocFailed flag as necessary.
|
|
// **
|
|
// ** The memory allocator is not restarted if there are running
|
|
// ** VDBEs.
|
|
// */
|
|
func _sqlite3OomClear(tls *libc.TLS, db uintptr) {
|
|
var v1 int32
|
|
_ = v1
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0 && (*Tsqlite3)(unsafe.Pointer(db)).FnVdbeExec == 0 {
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed = uint8(0)
|
|
libc.AtomicStoreNInt32(db+432, libc.Int32FromInt32(0), libc.Int32FromInt32(__ATOMIC_RELAXED))
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FbDisable = (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FbDisable - 1
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FbDisable != 0 {
|
|
v1 = 0
|
|
} else {
|
|
v1 = libc.Int32FromUint16((*Tsqlite3)(unsafe.Pointer(db)).Flookaside.FszTrue)
|
|
}
|
|
(*Tsqlite3)(unsafe.Pointer(db)).Flookaside.Fsz = libc.Uint16FromInt32(v1)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate cursors for the pTab table and all its indices and generate
|
|
// ** code to open and initialized those cursors.
|
|
// **
|
|
// ** The cursor for the object that contains the complete data (normally
|
|
// ** the table itself, but the PRIMARY KEY index in the case of a WITHOUT
|
|
// ** ROWID table) is returned in *piDataCur. The first index cursor is
|
|
// ** returned in *piIdxCur. The number of indices is returned.
|
|
// **
|
|
// ** Use iBase as the first cursor (either the *piDataCur for rowid tables
|
|
// ** or the first index for WITHOUT ROWID tables) if it is non-negative.
|
|
// ** If iBase is negative, then allocate the next available cursor.
|
|
// **
|
|
// ** For a rowid table, *piDataCur will be exactly one less than *piIdxCur.
|
|
// ** For a WITHOUT ROWID table, *piDataCur will be somewhere in the range
|
|
// ** of *piIdxCurs, depending on where the PRIMARY KEY index appears on the
|
|
// ** pTab->pIndex list.
|
|
// **
|
|
// ** If pTab is a virtual table, then this routine is a no-op and the
|
|
// ** *piDataCur and *piIdxCur values are left uninitialized.
|
|
// */
|
|
func _sqlite3OpenTableAndIndices(tls *libc.TLS, pParse uintptr, pTab uintptr, op int32, p5 Tu8, iBase int32, aToOpen uintptr, piDataCur uintptr, piIdxCur uintptr) (r int32) {
|
|
var i, iDataCur, iDb, iIdxCur, v1 int32
|
|
var pIdx, v uintptr
|
|
_, _, _, _, _, _, _ = i, iDataCur, iDb, iIdxCur, pIdx, v, v1
|
|
if libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == int32(TABTYP_VTAB) {
|
|
/* This routine is a no-op for virtual tables. Leave the output
|
|
** variables *piDataCur and *piIdxCur set to illegal cursor numbers
|
|
** for improved error detection. */
|
|
v1 = -libc.Int32FromInt32(999)
|
|
**(**int32)(__ccgo_up(piIdxCur)) = v1
|
|
**(**int32)(__ccgo_up(piDataCur)) = v1
|
|
return 0
|
|
}
|
|
iDb = _sqlite3SchemaToIndex(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, (*TTable)(unsafe.Pointer(pTab)).FpSchema)
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
if iBase < 0 {
|
|
iBase = (*TParse)(unsafe.Pointer(pParse)).FnTab
|
|
}
|
|
v1 = iBase
|
|
iBase = iBase + 1
|
|
iDataCur = v1
|
|
**(**int32)(__ccgo_up(piDataCur)) = iDataCur
|
|
if (*TTable)(unsafe.Pointer(pTab)).FtabFlags&uint32(TF_WithoutRowid) == uint32(0) && (aToOpen == uintptr(0) || **(**Tu8)(__ccgo_up(aToOpen)) != 0) {
|
|
_sqlite3OpenTable(tls, pParse, iDataCur, iDb, pTab, op)
|
|
} else {
|
|
if libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).FnoSharedCache) == 0 {
|
|
_sqlite3TableLock(tls, pParse, iDb, (*TTable)(unsafe.Pointer(pTab)).Ftnum, libc.BoolUint8(op == int32(OP_OpenWrite)), (*TTable)(unsafe.Pointer(pTab)).FzName)
|
|
}
|
|
}
|
|
**(**int32)(__ccgo_up(piIdxCur)) = iBase
|
|
i = 0
|
|
pIdx = (*TTable)(unsafe.Pointer(pTab)).FpIndex
|
|
for {
|
|
if !(pIdx != 0) {
|
|
break
|
|
}
|
|
v1 = iBase
|
|
iBase = iBase + 1
|
|
iIdxCur = v1
|
|
if int32(uint32(*(*uint16)(unsafe.Pointer(pIdx + 100))&0x3>>0)) == int32(SQLITE_IDXTYPE_PRIMARYKEY) && !((*TTable)(unsafe.Pointer(pTab)).FtabFlags&libc.Uint32FromInt32(TF_WithoutRowid) == libc.Uint32FromInt32(0)) {
|
|
**(**int32)(__ccgo_up(piDataCur)) = iIdxCur
|
|
p5 = uint8(0)
|
|
}
|
|
if aToOpen == uintptr(0) || **(**Tu8)(__ccgo_up(aToOpen + uintptr(i+int32(1)))) != 0 {
|
|
_sqlite3VdbeAddOp3(tls, v, op, iIdxCur, libc.Int32FromUint32((*TIndex)(unsafe.Pointer(pIdx)).Ftnum), iDb)
|
|
_sqlite3VdbeSetP4KeyInfo(tls, pParse, pIdx)
|
|
_sqlite3VdbeChangeP5(tls, v, uint16(p5))
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
pIdx = (*TIndex)(unsafe.Pointer(pIdx)).FpNext
|
|
i = i + 1
|
|
}
|
|
if iBase > (*TParse)(unsafe.Pointer(pParse)).FnTab {
|
|
(*TParse)(unsafe.Pointer(pParse)).FnTab = iBase
|
|
}
|
|
return i
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add pSelect to the Expr.x.pSelect field. Or, if pExpr is NULL (due
|
|
// ** do a memory allocation failure) then delete the pSelect object.
|
|
// */
|
|
func _sqlite3PExprAddSelect(tls *libc.TLS, pParse uintptr, pExpr uintptr, pSelect uintptr) {
|
|
if pExpr != 0 {
|
|
*(*uintptr)(unsafe.Pointer(pExpr + 32)) = pSelect
|
|
**(**Tu32)(__ccgo_up(pExpr + 4)) |= libc.Uint32FromInt32(libc.Int32FromInt32(EP_xIsSelect) | libc.Int32FromInt32(EP_Subquery))
|
|
_sqlite3ExprSetHeightAndFlags(tls, pParse, pExpr)
|
|
} else {
|
|
_sqlite3SelectDelete(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pSelect)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** A call to this routine tells the pager that it is not necessary to
|
|
// ** write the information on page pPg back to the disk, even though
|
|
// ** that page might be marked as dirty. This happens, for example, when
|
|
// ** the page has been added as a leaf of the freelist and so its
|
|
// ** content no longer matters.
|
|
// **
|
|
// ** The overlying software layer calls this routine when all of the data
|
|
// ** on the given page is unused. The pager marks the page as clean so
|
|
// ** that it does not get written to disk.
|
|
// **
|
|
// ** Tests show that this optimization can quadruple the speed of large
|
|
// ** DELETE operations.
|
|
// **
|
|
// ** This optimization cannot be used with a temp-file, as the page may
|
|
// ** have been dirty at the start of the transaction. In that case, if
|
|
// ** memory pressure forces page pPg out of the cache, the data does need
|
|
// ** to be written out to disk so that it may be read back in if the
|
|
// ** current transaction is rolled back.
|
|
// */
|
|
func _sqlite3PagerDontWrite(tls *libc.TLS, pPg uintptr) {
|
|
var pPager, v1 uintptr
|
|
_, _ = pPager, v1
|
|
pPager = (*TPgHdr)(unsafe.Pointer(pPg)).FpPager
|
|
if !((*TPager)(unsafe.Pointer(pPager)).FtempFile != 0) && libc.Int32FromUint16((*TPgHdr)(unsafe.Pointer(pPg)).Fflags)&int32(PGHDR_DIRTY) != 0 && (*TPager)(unsafe.Pointer(pPager)).FnSavepoint == 0 {
|
|
v1 = pPg + 52
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(PGHDR_DONT_WRITE))
|
|
v1 = pPg + 52
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) & ^libc.Int32FromInt32(PGHDR_WRITEABLE))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the approximate number of bytes of memory currently
|
|
// ** used by the pager and its associated cache.
|
|
// */
|
|
func _sqlite3PagerMemUsed(tls *libc.TLS, pPager uintptr) (r int32) {
|
|
var perPageSize int32
|
|
_ = perPageSize
|
|
perPageSize = int32((*TPager)(unsafe.Pointer(pPager)).FpageSize + libc.Int64FromUint16((*TPager)(unsafe.Pointer(pPager)).FnExtra) + int64(libc.Int32FromUint64(libc.Uint64FromInt64(80)+libc.Uint64FromInt32(5)*libc.Uint64FromInt64(8))))
|
|
return int32(int64(perPageSize*_sqlite3PcachePagecount(tls, (*TPager)(unsafe.Pointer(pPager)).FpPCache)+_sqlite3MallocSize(tls, pPager)) + (*TPager)(unsafe.Pointer(pPager)).FpageSize)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Move the page pPg to location pgno in the file.
|
|
// **
|
|
// ** There must be no references to the page previously located at
|
|
// ** pgno (which we call pPgOld) though that page is allowed to be
|
|
// ** in cache. If the page previously located at pgno is not already
|
|
// ** in the rollback journal, it is not put there by by this routine.
|
|
// **
|
|
// ** References to the page pPg remain valid. Updating any
|
|
// ** meta-data associated with pPg (i.e. data stored in the nExtra bytes
|
|
// ** allocated along with the page) is the responsibility of the caller.
|
|
// **
|
|
// ** A transaction must be active when this routine is called. It used to be
|
|
// ** required that a statement transaction was not active, but this restriction
|
|
// ** has been removed (CREATE INDEX needs to move a page when a statement
|
|
// ** transaction is active).
|
|
// **
|
|
// ** If the fourth argument, isCommit, is non-zero, then this page is being
|
|
// ** moved as part of a database reorganization just before the transaction
|
|
// ** is being committed. In this case, it is guaranteed that the database page
|
|
// ** pPg refers to will not be written to again within this transaction.
|
|
// **
|
|
// ** This function may return SQLITE_NOMEM or an IO error code if an error
|
|
// ** occurs. Otherwise, it returns SQLITE_OK.
|
|
// */
|
|
func _sqlite3PagerMovepage(tls *libc.TLS, pPager uintptr, pPg uintptr, pgno TPgno, isCommit int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var needSyncPgno, origPgno TPgno
|
|
var pPgOld, v3 uintptr
|
|
var rc, v1 int32
|
|
var v2 bool
|
|
var _ /* pPgHdr at bp+0 */ uintptr
|
|
_, _, _, _, _, _, _ = needSyncPgno, origPgno, pPgOld, rc, v1, v2, v3 /* The page being overwritten. */
|
|
needSyncPgno = uint32(0) /* The original page number */
|
|
/* In order to be able to rollback, an in-memory database must journal
|
|
** the page we are moving from.
|
|
*/
|
|
if (*TPager)(unsafe.Pointer(pPager)).FtempFile != 0 {
|
|
rc = _sqlite3PagerWrite(tls, pPg)
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
}
|
|
/* If the page being moved is dirty and has not been saved by the latest
|
|
** savepoint, then save the current contents of the page into the
|
|
** sub-journal now. This is required to handle the following scenario:
|
|
**
|
|
** BEGIN;
|
|
** <journal page X, then modify it in memory>
|
|
** SAVEPOINT one;
|
|
** <Move page X to location Y>
|
|
** ROLLBACK TO one;
|
|
**
|
|
** If page X were not written to the sub-journal here, it would not
|
|
** be possible to restore its contents when the "ROLLBACK TO one"
|
|
** statement were is processed.
|
|
**
|
|
** subjournalPage() may need to allocate space to store pPg->pgno into
|
|
** one or more savepoint bitvecs. This is the reason this function
|
|
** may return SQLITE_NOMEM.
|
|
*/
|
|
if v2 = libc.Int32FromUint16((*TDbPage)(unsafe.Pointer(pPg)).Fflags)&int32(PGHDR_DIRTY) != 0; v2 {
|
|
v1 = _subjournalPageIfRequired(tls, pPg)
|
|
rc = v1
|
|
}
|
|
if v2 && SQLITE_OK != v1 {
|
|
return rc
|
|
}
|
|
/* If the journal needs to be sync()ed before page pPg->pgno can
|
|
** be written to, store pPg->pgno in local variable needSyncPgno.
|
|
**
|
|
** If the isCommit flag is set, there is no need to remember that
|
|
** the journal needs to be sync()ed before database page pPg->pgno
|
|
** can be written to. The caller has already promised not to write to it.
|
|
*/
|
|
if libc.Int32FromUint16((*TDbPage)(unsafe.Pointer(pPg)).Fflags)&int32(PGHDR_NEED_SYNC) != 0 && !(isCommit != 0) {
|
|
needSyncPgno = (*TDbPage)(unsafe.Pointer(pPg)).Fpgno
|
|
}
|
|
/* If the cache contains a page with page-number pgno, remove it
|
|
** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for
|
|
** page pgno before the 'move' operation, it needs to be retained
|
|
** for the page moved there.
|
|
*/
|
|
v3 = pPg + 52
|
|
*(*Tu16)(unsafe.Pointer(v3)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v3))) & ^libc.Int32FromInt32(PGHDR_NEED_SYNC))
|
|
pPgOld = _sqlite3PagerLookup(tls, pPager, pgno)
|
|
if pPgOld != 0 {
|
|
if (*TPgHdr)(unsafe.Pointer(pPgOld)).FnRef > int64(1) {
|
|
_sqlite3PagerUnrefNotNull(tls, pPgOld)
|
|
return _sqlite3CorruptError(tls, int32(66914))
|
|
}
|
|
v3 = pPg + 52
|
|
*(*Tu16)(unsafe.Pointer(v3)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v3))) | libc.Int32FromUint16((*TPgHdr)(unsafe.Pointer(pPgOld)).Fflags)&libc.Int32FromInt32(PGHDR_NEED_SYNC))
|
|
if (*TPager)(unsafe.Pointer(pPager)).FtempFile != 0 {
|
|
/* Do not discard pages from an in-memory database since we might
|
|
** need to rollback later. Just move the page out of the way. */
|
|
_sqlite3PcacheMove(tls, pPgOld, (*TPager)(unsafe.Pointer(pPager)).FdbSize+uint32(1))
|
|
} else {
|
|
_sqlite3PcacheDrop(tls, pPgOld)
|
|
}
|
|
}
|
|
origPgno = (*TDbPage)(unsafe.Pointer(pPg)).Fpgno
|
|
_sqlite3PcacheMove(tls, pPg, pgno)
|
|
_sqlite3PcacheMakeDirty(tls, pPg)
|
|
/* For an in-memory database, make sure the original page continues
|
|
** to exist, in case the transaction needs to roll back. Use pPgOld
|
|
** as the original page since it has already been allocated.
|
|
*/
|
|
if (*TPager)(unsafe.Pointer(pPager)).FtempFile != 0 && pPgOld != 0 {
|
|
_sqlite3PcacheMove(tls, pPgOld, origPgno)
|
|
_sqlite3PagerUnrefNotNull(tls, pPgOld)
|
|
}
|
|
if needSyncPgno != 0 {
|
|
rc = _sqlite3PagerGet(tls, pPager, needSyncPgno, bp, 0)
|
|
if rc != SQLITE_OK {
|
|
if needSyncPgno <= (*TPager)(unsafe.Pointer(pPager)).FdbOrigSize {
|
|
_sqlite3BitvecClear(tls, (*TPager)(unsafe.Pointer(pPager)).FpInJournal, needSyncPgno, (*TPager)(unsafe.Pointer(pPager)).FpTmpSpace)
|
|
}
|
|
return rc
|
|
}
|
|
v3 = **(**uintptr)(__ccgo_up(bp)) + 52
|
|
*(*Tu16)(unsafe.Pointer(v3)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v3))) | libc.Int32FromInt32(PGHDR_NEED_SYNC))
|
|
_sqlite3PcacheMakeDirty(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
_sqlite3PagerUnrefNotNull(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called to rollback or release (commit) a savepoint.
|
|
// ** The savepoint to release or rollback need not be the most recently
|
|
// ** created savepoint.
|
|
// **
|
|
// ** Parameter op is always either SAVEPOINT_ROLLBACK or SAVEPOINT_RELEASE.
|
|
// ** If it is SAVEPOINT_RELEASE, then release and destroy the savepoint with
|
|
// ** index iSavepoint. If it is SAVEPOINT_ROLLBACK, then rollback all changes
|
|
// ** that have occurred since the specified savepoint was created.
|
|
// **
|
|
// ** The savepoint to rollback or release is identified by parameter
|
|
// ** iSavepoint. A value of 0 means to operate on the outermost savepoint
|
|
// ** (the first created). A value of (Pager.nSavepoint-1) means operate
|
|
// ** on the most recently created savepoint. If iSavepoint is greater than
|
|
// ** (Pager.nSavepoint-1), then this function is a no-op.
|
|
// **
|
|
// ** If a negative value is passed to this function, then the current
|
|
// ** transaction is rolled back. This is different to calling
|
|
// ** sqlite3PagerRollback() because this function does not terminate
|
|
// ** the transaction or unlock the database, it just restores the
|
|
// ** contents of the database to its original state.
|
|
// **
|
|
// ** In any case, all savepoints with an index greater than iSavepoint
|
|
// ** are destroyed. If this is a release operation (op==SAVEPOINT_RELEASE),
|
|
// ** then savepoint iSavepoint is also destroyed.
|
|
// **
|
|
// ** This function may return SQLITE_NOMEM if a memory allocation fails,
|
|
// ** or an IO error code if an IO error occurs while rolling back a
|
|
// ** savepoint. If no errors occur, SQLITE_OK is returned.
|
|
// */
|
|
func _sqlite3PagerSavepoint(tls *libc.TLS, pPager uintptr, op int32, iSavepoint int32) (r int32) {
|
|
var ii, nNew, rc, v1 int32
|
|
var pRel, pSavepoint, v3 uintptr
|
|
var sz Ti64
|
|
_, _, _, _, _, _, _, _ = ii, nNew, pRel, pSavepoint, rc, sz, v1, v3
|
|
rc = (*TPager)(unsafe.Pointer(pPager)).FerrCode
|
|
if rc == SQLITE_OK && iSavepoint < (*TPager)(unsafe.Pointer(pPager)).FnSavepoint { /* Number of remaining savepoints after this op. */
|
|
/* Figure out how many savepoints will still be active after this
|
|
** operation. Store this value in nNew. Then free resources associated
|
|
** with any savepoints that are destroyed by this operation.
|
|
*/
|
|
if op == int32(SAVEPOINT_RELEASE) {
|
|
v1 = 0
|
|
} else {
|
|
v1 = int32(1)
|
|
}
|
|
nNew = iSavepoint + v1
|
|
ii = nNew
|
|
for {
|
|
if !(ii < (*TPager)(unsafe.Pointer(pPager)).FnSavepoint) {
|
|
break
|
|
}
|
|
_sqlite3BitvecDestroy(tls, (**(**TPagerSavepoint)(__ccgo_up((*TPager)(unsafe.Pointer(pPager)).FaSavepoint + uintptr(ii)*56))).FpInSavepoint)
|
|
goto _2
|
|
_2:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
(*TPager)(unsafe.Pointer(pPager)).FnSavepoint = nNew
|
|
/* Truncate the sub-journal so that it only includes the parts
|
|
** that are still in use. */
|
|
if op == int32(SAVEPOINT_RELEASE) {
|
|
pRel = (*TPager)(unsafe.Pointer(pPager)).FaSavepoint + uintptr(nNew)*56
|
|
if (*TPagerSavepoint)(unsafe.Pointer(pRel)).FbTruncateOnRelease != 0 && (*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Fsjfd)).FpMethods != uintptr(0) {
|
|
/* Only truncate if it is an in-memory sub-journal. */
|
|
if _sqlite3JournalIsInMemory(tls, (*TPager)(unsafe.Pointer(pPager)).Fsjfd) != 0 {
|
|
sz = ((*TPager)(unsafe.Pointer(pPager)).FpageSize + int64(4)) * libc.Int64FromUint32((*TPagerSavepoint)(unsafe.Pointer(pRel)).FiSubRec)
|
|
rc = _sqlite3OsTruncate(tls, (*TPager)(unsafe.Pointer(pPager)).Fsjfd, sz)
|
|
}
|
|
(*TPager)(unsafe.Pointer(pPager)).FnSubRec = (*TPagerSavepoint)(unsafe.Pointer(pRel)).FiSubRec
|
|
}
|
|
} else {
|
|
if (*TPager)(unsafe.Pointer(pPager)).FpWal != uintptr(0) || (*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Fjfd)).FpMethods != uintptr(0) {
|
|
if nNew == 0 {
|
|
v3 = uintptr(0)
|
|
} else {
|
|
v3 = (*TPager)(unsafe.Pointer(pPager)).FaSavepoint + uintptr(nNew-int32(1))*56
|
|
}
|
|
pSavepoint = v3
|
|
rc = _pagerPlaybackSavepoint(tls, pPager, pSavepoint)
|
|
}
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Adjust settings of the pager to those specified in the pgFlags parameter.
|
|
// **
|
|
// ** The "level" in pgFlags & PAGER_SYNCHRONOUS_MASK sets the robustness
|
|
// ** of the database to damage due to OS crashes or power failures by
|
|
// ** changing the number of syncs()s when writing the journals.
|
|
// ** There are four levels:
|
|
// **
|
|
// ** OFF sqlite3OsSync() is never called. This is the default
|
|
// ** for temporary and transient files.
|
|
// **
|
|
// ** NORMAL The journal is synced once before writes begin on the
|
|
// ** database. This is normally adequate protection, but
|
|
// ** it is theoretically possible, though very unlikely,
|
|
// ** that an inopertune power failure could leave the journal
|
|
// ** in a state which would cause damage to the database
|
|
// ** when it is rolled back.
|
|
// **
|
|
// ** FULL The journal is synced twice before writes begin on the
|
|
// ** database (with some additional information - the nRec field
|
|
// ** of the journal header - being written in between the two
|
|
// ** syncs). If we assume that writing a
|
|
// ** single disk sector is atomic, then this mode provides
|
|
// ** assurance that the journal will not be corrupted to the
|
|
// ** point of causing damage to the database during rollback.
|
|
// **
|
|
// ** EXTRA This is like FULL except that is also syncs the directory
|
|
// ** that contains the rollback journal after the rollback
|
|
// ** journal is unlinked.
|
|
// **
|
|
// ** The above is for a rollback-journal mode. For WAL mode, OFF continues
|
|
// ** to mean that no syncs ever occur. NORMAL means that the WAL is synced
|
|
// ** prior to the start of checkpoint and that the database file is synced
|
|
// ** at the conclusion of the checkpoint if the entire content of the WAL
|
|
// ** was written back into the database. But no sync operations occur for
|
|
// ** an ordinary commit in NORMAL mode with WAL. FULL means that the WAL
|
|
// ** file is synced following each commit operation, in addition to the
|
|
// ** syncs associated with NORMAL. There is no difference between FULL
|
|
// ** and EXTRA for WAL mode.
|
|
// **
|
|
// ** Do not confuse synchronous=FULL with SQLITE_SYNC_FULL. The
|
|
// ** SQLITE_SYNC_FULL macro means to use the MacOSX-style full-fsync
|
|
// ** using fcntl(F_FULLFSYNC). SQLITE_SYNC_NORMAL means to do an
|
|
// ** ordinary fsync() call. There is no difference between SQLITE_SYNC_FULL
|
|
// ** and SQLITE_SYNC_NORMAL on platforms other than MacOSX. But the
|
|
// ** synchronous=FULL versus synchronous=NORMAL setting determines when
|
|
// ** the xSync primitive is called and is relevant to all platforms.
|
|
// **
|
|
// ** Numeric values associated with these states are OFF==1, NORMAL=2,
|
|
// ** and FULL=3.
|
|
// */
|
|
func _sqlite3PagerSetFlags(tls *libc.TLS, pPager uintptr, pgFlags uint32) {
|
|
var level uint32
|
|
var v1 int32
|
|
var v2 uintptr
|
|
_, _, _ = level, v1, v2
|
|
level = pgFlags & uint32(PAGER_SYNCHRONOUS_MASK)
|
|
if (*TPager)(unsafe.Pointer(pPager)).FtempFile != 0 || level == uint32(PAGER_SYNCHRONOUS_OFF) {
|
|
(*TPager)(unsafe.Pointer(pPager)).FnoSync = uint8(1)
|
|
(*TPager)(unsafe.Pointer(pPager)).FfullSync = uint8(0)
|
|
(*TPager)(unsafe.Pointer(pPager)).FextraSync = uint8(0)
|
|
} else {
|
|
(*TPager)(unsafe.Pointer(pPager)).FnoSync = uint8(0)
|
|
if level >= uint32(PAGER_SYNCHRONOUS_FULL) {
|
|
v1 = int32(1)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
(*TPager)(unsafe.Pointer(pPager)).FfullSync = libc.Uint8FromInt32(v1)
|
|
/* Set Pager.extraSync if "PRAGMA synchronous=EXTRA" is requested, or
|
|
** if the file-system supports F2FS style atomic writes. If this flag
|
|
** is set, SQLite syncs the directory to disk immediately after deleting
|
|
** a journal file in "PRAGMA journal_mode=DELETE" mode. */
|
|
if level == uint32(PAGER_SYNCHRONOUS_EXTRA) {
|
|
(*TPager)(unsafe.Pointer(pPager)).FextraSync = uint8(1)
|
|
} else {
|
|
(*TPager)(unsafe.Pointer(pPager)).FextraSync = uint8(0)
|
|
}
|
|
}
|
|
if (*TPager)(unsafe.Pointer(pPager)).FnoSync != 0 {
|
|
(*TPager)(unsafe.Pointer(pPager)).FsyncFlags = uint8(0)
|
|
} else {
|
|
if pgFlags&uint32(PAGER_FULLFSYNC) != 0 {
|
|
(*TPager)(unsafe.Pointer(pPager)).FsyncFlags = uint8(SQLITE_SYNC_FULL)
|
|
} else {
|
|
(*TPager)(unsafe.Pointer(pPager)).FsyncFlags = uint8(SQLITE_SYNC_NORMAL)
|
|
}
|
|
}
|
|
(*TPager)(unsafe.Pointer(pPager)).FwalSyncFlags = libc.Uint8FromInt32(libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FsyncFlags) << libc.Int32FromInt32(2))
|
|
if (*TPager)(unsafe.Pointer(pPager)).FfullSync != 0 {
|
|
v2 = pPager + 15
|
|
*(*Tu8)(unsafe.Pointer(v2)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v2))) | libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FsyncFlags))
|
|
}
|
|
if pgFlags&uint32(PAGER_CKPT_FULLFSYNC) != 0 && !((*TPager)(unsafe.Pointer(pPager)).FnoSync != 0) {
|
|
v2 = pPager + 15
|
|
*(*Tu8)(unsafe.Pointer(v2)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v2))) | libc.Int32FromInt32(SQLITE_SYNC_FULL)<<libc.Int32FromInt32(2))
|
|
}
|
|
if pgFlags&uint32(PAGER_CACHESPILL) != 0 {
|
|
v2 = pPager + 25
|
|
*(*Tu8)(unsafe.Pointer(v2)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v2))) & ^libc.Int32FromInt32(SPILLFLAG_OFF))
|
|
} else {
|
|
v2 = pPager + 25
|
|
*(*Tu8)(unsafe.Pointer(v2)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v2))) | libc.Int32FromInt32(SPILLFLAG_OFF))
|
|
}
|
|
}
|
|
|
|
/*
|
|
** The following global variable is incremented whenever the library
|
|
** attempts to open a temporary file. This information is used for
|
|
** testing and analysis only.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /* The main parser program.
|
|
// ** The first argument is a pointer to a structure obtained from
|
|
// ** "sqlite3ParserAlloc" which describes the current state of the parser.
|
|
// ** The second argument is the major token number. The third is
|
|
// ** the minor token. The fourth optional argument is whatever the
|
|
// ** user wants (and specified in the grammar) and is available for
|
|
// ** use by the action routines.
|
|
// **
|
|
// ** Inputs:
|
|
// ** <ul>
|
|
// ** <li> A pointer to the parser (an opaque structure.)
|
|
// ** <li> The major token number.
|
|
// ** <li> The minor token number.
|
|
// ** <li> An option argument of a grammar-specified type.
|
|
// ** </ul>
|
|
// **
|
|
// ** Outputs:
|
|
// ** None.
|
|
// */
|
|
func _sqlite3Parser(tls *libc.TLS, yyp uintptr, yymajor int32, yyminor TToken) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var pParse, yypParser uintptr
|
|
var yyact uint16
|
|
var yyruleno uint32
|
|
var _ /* yyminorunion at bp+0 */ TYYMINORTYPE
|
|
_, _, _, _ = pParse, yyact, yypParser, yyruleno /* The parser action. */
|
|
yypParser = yyp /* The parser */
|
|
pParse = (*TyyParser)(unsafe.Pointer(yypParser)).FpParse
|
|
yyact = (*TyyStackEntry)(unsafe.Pointer((*TyyParser)(unsafe.Pointer(yypParser)).Fyytos)).Fstateno
|
|
for int32(1) != 0 { /* Exit by "break" */
|
|
yyact = _yy_find_shift_action(tls, libc.Uint16FromInt32(yymajor), yyact)
|
|
if libc.Int32FromUint16(yyact) >= int32(YY_MIN_REDUCE) {
|
|
yyruleno = libc.Uint32FromInt32(libc.Int32FromUint16(yyact) - int32(YY_MIN_REDUCE)) /* Reduce by this rule */
|
|
/* Check that the stack is large enough to grow by a single entry
|
|
** if the RHS of the rule is empty. This ensures that there is room
|
|
** enough on the stack to push the LHS value */
|
|
if int32(_yyRuleInfoNRhs[yyruleno]) == 0 {
|
|
if (*TyyParser)(unsafe.Pointer(yypParser)).Fyytos >= (*TyyParser)(unsafe.Pointer(yypParser)).FyystackEnd {
|
|
if _yyGrowStack(tls, yypParser) != 0 {
|
|
_yyStackOverflow(tls, yypParser)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
yyact = _yy_reduce(tls, yypParser, yyruleno, yymajor, yyminor, pParse)
|
|
} else {
|
|
if libc.Int32FromUint16(yyact) <= int32(YY_MAX_SHIFTREDUCE) {
|
|
_yy_shift(tls, yypParser, yyact, libc.Uint16FromInt32(yymajor), yyminor)
|
|
break
|
|
} else {
|
|
if libc.Int32FromUint16(yyact) == int32(YY_ACCEPT_ACTION) {
|
|
(*TyyParser)(unsafe.Pointer(yypParser)).Fyytos -= 24
|
|
_yy_accept(tls, yypParser)
|
|
return
|
|
} else {
|
|
*(*TToken)(unsafe.Pointer(bp)) = yyminor
|
|
/* If the YYNOERRORRECOVERY macro is defined, then do not attempt to
|
|
** do any kind of error recovery. Instead, simply invoke the syntax
|
|
** error routine and continue going as if nothing had happened.
|
|
**
|
|
** Applications can set this macro (for example inside %include) if
|
|
** they intend to abandon the parse upon the first syntax error seen.
|
|
*/
|
|
_yy_syntax_error(tls, yypParser, yymajor, yyminor)
|
|
_yy_destructor(tls, yypParser, libc.Uint16FromInt32(yymajor), bp)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Clear all secondary memory allocations from the parser
|
|
// */
|
|
func _sqlite3ParserFinalize(tls *libc.TLS, p uintptr) {
|
|
var pParser, yytos uintptr
|
|
_, _ = pParser, yytos
|
|
pParser = p
|
|
/* In-lined version of calling yy_pop_parser_stack() for each
|
|
** element left in the stack */
|
|
yytos = (*TyyParser)(unsafe.Pointer(pParser)).Fyytos
|
|
for yytos > (*TyyParser)(unsafe.Pointer(pParser)).Fyystack {
|
|
if libc.Int32FromUint16((*TyyStackEntry)(unsafe.Pointer(yytos)).Fmajor) >= int32(YY_MIN_DSTRCTR) {
|
|
_yy_destructor(tls, pParser, (*TyyStackEntry)(unsafe.Pointer(yytos)).Fmajor, yytos+8)
|
|
}
|
|
yytos -= 24
|
|
}
|
|
if (*TyyParser)(unsafe.Pointer(pParser)).Fyystack != pParser+32 {
|
|
_parserStackFree(tls, (*TyyParser)(unsafe.Pointer(pParser)).Fyystack, (*TyyParser)(unsafe.Pointer(pParser)).FpParse)
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Return the peak depth of the stack for a parser.
|
|
*/
|
|
|
|
/* This array of booleans keeps track of the parser statement
|
|
** coverage. The element yycoverage[X][Y] is set when the parser
|
|
** is in state X and has a lookahead token Y. In a well-tested
|
|
** systems, every element of this matrix should end up being set.
|
|
*/
|
|
|
|
/*
|
|
** Write into out a description of every state/lookahead combination that
|
|
**
|
|
** (1) has not been used by the parser, and
|
|
** (2) is not a syntax error.
|
|
**
|
|
** Return the number of missed state/lookahead combinations.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Make sure the page is marked as dirty. If it isn't dirty already,
|
|
// ** make it so.
|
|
// */
|
|
func _sqlite3PcacheMakeDirty(tls *libc.TLS, p uintptr) {
|
|
var v1 uintptr
|
|
_ = v1
|
|
if libc.Int32FromUint16((*TPgHdr)(unsafe.Pointer(p)).Fflags)&(libc.Int32FromInt32(PGHDR_CLEAN)|libc.Int32FromInt32(PGHDR_DONT_WRITE)) != 0 { /*OPTIMIZATION-IF-FALSE*/
|
|
v1 = p + 52
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) & ^libc.Int32FromInt32(PGHDR_DONT_WRITE))
|
|
if libc.Int32FromUint16((*TPgHdr)(unsafe.Pointer(p)).Fflags)&int32(PGHDR_CLEAN) != 0 {
|
|
v1 = p + 52
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) ^ (libc.Int32FromInt32(PGHDR_DIRTY) | libc.Int32FromInt32(PGHDR_CLEAN)))
|
|
_pcacheManageDirtyList(tls, p, uint8(PCACHE_DIRTYLIST_ADD))
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Decrement the reference count on a page. If the page is clean and the
|
|
// ** reference count drops to 0, then it is made eligible for recycling.
|
|
// */
|
|
func _sqlite3PcacheRelease(tls *libc.TLS, p uintptr) {
|
|
var v1 Ti64
|
|
var v2 uintptr
|
|
_, _ = v1, v2
|
|
(*TPCache)(unsafe.Pointer((*TPgHdr)(unsafe.Pointer(p)).FpCache)).FnRefSum = (*TPCache)(unsafe.Pointer((*TPgHdr)(unsafe.Pointer(p)).FpCache)).FnRefSum - 1
|
|
v2 = p + 56
|
|
*(*Ti64)(unsafe.Pointer(v2)) = *(*Ti64)(unsafe.Pointer(v2)) - 1
|
|
v1 = *(*Ti64)(unsafe.Pointer(v2))
|
|
if v1 == 0 {
|
|
if libc.Int32FromUint16((*TPgHdr)(unsafe.Pointer(p)).Fflags)&int32(PGHDR_CLEAN) != 0 {
|
|
_pcacheUnpin(tls, p)
|
|
} else {
|
|
_pcacheManageDirtyList(tls, p, uint8(PCACHE_DIRTYLIST_FRONT))
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Change the page size for PCache object. The caller must ensure that there
|
|
// ** are no outstanding page references when this function is called.
|
|
// */
|
|
func _sqlite3PcacheSetPageSize(tls *libc.TLS, pCache uintptr, szPage int32) (r int32) {
|
|
var pNew uintptr
|
|
_ = pNew
|
|
if (*TPCache)(unsafe.Pointer(pCache)).FszPage != 0 {
|
|
pNew = (*(*func(*libc.TLS, int32, int32, int32) uintptr)(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.Fpcache2.FxCreate})))(tls, szPage, libc.Int32FromUint64(libc.Uint64FromInt32((*TPCache)(unsafe.Pointer(pCache)).FszExtra)+(libc.Uint64FromInt64(80)+libc.Uint64FromInt32(7))&libc.Uint64FromInt32(^libc.Int32FromInt32(7))), libc.Int32FromUint8((*TPCache)(unsafe.Pointer(pCache)).FbPurgeable))
|
|
if pNew == uintptr(0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
(*(*func(*libc.TLS, uintptr, int32))(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.Fpcache2.FxCachesize})))(tls, pNew, _numberOfCachePages(tls, pCache))
|
|
if (*TPCache)(unsafe.Pointer(pCache)).FpCache != 0 {
|
|
(*(*func(*libc.TLS, uintptr))(unsafe.Pointer(&struct{ uintptr }{_sqlite3Config.Fpcache2.FxDestroy})))(tls, (*TPCache)(unsafe.Pointer(pCache)).FpCache)
|
|
}
|
|
(*TPCache)(unsafe.Pointer(pCache)).FpCache = pNew
|
|
(*TPCache)(unsafe.Pointer(pCache)).FszPage = szPage
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If pExpr has a byte offset for the start of a token, record that as
|
|
// ** as the error offset.
|
|
// */
|
|
func _sqlite3RecordErrorOffsetOfExpr(tls *libc.TLS, db uintptr, pExpr uintptr) {
|
|
for pExpr != 0 && ((*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)|libc.Int32FromInt32(EP_InnerON)) != uint32(0) || *(*int32)(unsafe.Pointer(pExpr + 52)) <= 0) {
|
|
pExpr = (*TExpr)(unsafe.Pointer(pExpr)).FpLeft
|
|
}
|
|
if pExpr == uintptr(0) {
|
|
return
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_FromDDL)) != uint32(0) {
|
|
return
|
|
}
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FerrByteOffset = *(*int32)(unsafe.Pointer(pExpr + 52))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code that will erase and refill index *pIdx. This is
|
|
// ** used to initialize a newly created index or to recompute the
|
|
// ** content of an index in response to a REINDEX command.
|
|
// **
|
|
// ** if memRootPage is not negative, it means that the index is newly
|
|
// ** created. The register specified by memRootPage contains the
|
|
// ** root page number of the index. If memRootPage is negative, then
|
|
// ** the index already exists and must be cleared before being refilled and
|
|
// ** the root page number of the index is taken from pIndex->tnum.
|
|
// */
|
|
func _sqlite3RefillIndex(tls *libc.TLS, pParse uintptr, pIndex uintptr, memRootPage int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var addr1, addr2, iDb, iIdx, iSorter, iTab, j2, regRecord, v1, v3 int32
|
|
var db, pKey, pTab, v, v2, v4 uintptr
|
|
var tnum TPgno
|
|
var _ /* iPartIdxLabel at bp+0 */ int32
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = addr1, addr2, db, iDb, iIdx, iSorter, iTab, j2, pKey, pTab, regRecord, tnum, v, v1, v2, v3, v4
|
|
pTab = (*TIndex)(unsafe.Pointer(pIndex)).FpTable
|
|
v2 = pParse + 56
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1 /* The table that is indexed */
|
|
iTab = v1
|
|
v4 = pParse + 56
|
|
v3 = *(*int32)(unsafe.Pointer(v4))
|
|
*(*int32)(unsafe.Pointer(v4)) = *(*int32)(unsafe.Pointer(v4)) + 1 /* Btree cursor used for pTab */
|
|
iIdx = v3 /* Register holding assembled index record */
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb /* The database connection */
|
|
iDb = _sqlite3SchemaToIndex(tls, db, (*TIndex)(unsafe.Pointer(pIndex)).FpSchema)
|
|
if _sqlite3AuthCheck(tls, pParse, int32(SQLITE_REINDEX), (*TIndex)(unsafe.Pointer(pIndex)).FzName, uintptr(0), (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(iDb)*32))).FzDbSName) != 0 {
|
|
return
|
|
}
|
|
/* Require a write-lock on the table to perform this operation */
|
|
_sqlite3TableLock(tls, pParse, iDb, (*TTable)(unsafe.Pointer(pTab)).Ftnum, uint8(1), (*TTable)(unsafe.Pointer(pTab)).FzName)
|
|
v = _sqlite3GetVdbe(tls, pParse)
|
|
if v == uintptr(0) {
|
|
return
|
|
}
|
|
if memRootPage >= 0 {
|
|
tnum = libc.Uint32FromInt32(memRootPage)
|
|
} else {
|
|
tnum = (*TIndex)(unsafe.Pointer(pIndex)).Ftnum
|
|
}
|
|
pKey = _sqlite3KeyInfoOfIndex(tls, pParse, pIndex)
|
|
/* Open the sorter cursor if we are to use one. */
|
|
v2 = pParse + 56
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
iSorter = v1
|
|
_sqlite3VdbeAddOp4(tls, v, int32(OP_SorterOpen), iSorter, 0, libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIndex)).FnKeyCol), _sqlite3KeyInfoRef(tls, pKey), -int32(9))
|
|
/* Open the table. Loop through all rows of the table, inserting index
|
|
** records into the sorter. */
|
|
_sqlite3OpenTable(tls, pParse, iTab, iDb, pTab, int32(OP_OpenRead))
|
|
addr1 = _sqlite3VdbeAddOp2(tls, v, int32(OP_Rewind), iTab, 0)
|
|
regRecord = _sqlite3GetTempReg(tls, pParse)
|
|
_sqlite3MultiWrite(tls, pParse)
|
|
_sqlite3GenerateIndexKey(tls, pParse, pIndex, iTab, regRecord, 0, bp, uintptr(0), 0)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_SorterInsert), iSorter, regRecord)
|
|
_sqlite3ResolvePartIdxLabel(tls, pParse, **(**int32)(__ccgo_up(bp)))
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Next), iTab, addr1+int32(1))
|
|
_sqlite3VdbeJumpHere(tls, v, addr1)
|
|
if memRootPage < 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Clear), libc.Int32FromUint32(tnum), iDb)
|
|
}
|
|
_sqlite3VdbeAddOp4(tls, v, int32(OP_OpenWrite), iIdx, libc.Int32FromUint32(tnum), iDb, pKey, -int32(9))
|
|
if memRootPage >= 0 {
|
|
v1 = int32(OPFLAG_P2ISREG)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
_sqlite3VdbeChangeP5(tls, v, libc.Uint16FromInt32(int32(OPFLAG_BULKCSR)|v1))
|
|
addr1 = _sqlite3VdbeAddOp2(tls, v, int32(OP_SorterSort), iSorter, 0)
|
|
if libc.Int32FromUint8((*TIndex)(unsafe.Pointer(pIndex)).FonError) != OE_None {
|
|
j2 = _sqlite3VdbeGoto(tls, v, int32(1))
|
|
addr2 = _sqlite3VdbeCurrentAddr(tls, v)
|
|
_sqlite3VdbeAddOp4Int(tls, v, int32(OP_SorterCompare), iSorter, j2, regRecord, libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIndex)).FnKeyCol))
|
|
_sqlite3UniqueConstraint(tls, pParse, int32(OE_Abort), pIndex)
|
|
_sqlite3VdbeJumpHere(tls, v, j2)
|
|
} else {
|
|
/* Most CREATE INDEX and REINDEX statements that are not UNIQUE can not
|
|
** abort. The exception is if one of the indexed expressions contains a
|
|
** user function that throws an exception when it is evaluated. But the
|
|
** overhead of adding a statement journal to a CREATE INDEX statement is
|
|
** very small (since most of the pages written do not contain content that
|
|
** needs to be restored if the statement aborts), so we call
|
|
** sqlite3MayAbort() for all CREATE INDEX statements. */
|
|
_sqlite3MayAbort(tls, pParse)
|
|
addr2 = _sqlite3VdbeCurrentAddr(tls, v)
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_SorterData), iSorter, regRecord, iIdx)
|
|
if !(int32(uint32(*(*uint16)(unsafe.Pointer(pIndex + 100))&0x200>>9)) != 0) {
|
|
/* This OP_SeekEnd opcode makes index insert for a REINDEX go much
|
|
** faster by avoiding unnecessary seeks. But the optimization does
|
|
** not work for UNIQUE constraint indexes on WITHOUT ROWID tables
|
|
** with DESC primary keys, since those indexes have there keys in
|
|
** a different order from the main table.
|
|
** See ticket: https://sqlite.org/src/info/bba7b69f9849b5bf
|
|
*/
|
|
_sqlite3VdbeAddOp1(tls, v, int32(OP_SeekEnd), iIdx)
|
|
}
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_IdxInsert), iIdx, regRecord)
|
|
_sqlite3VdbeChangeP5(tls, v, uint16(OPFLAG_USESEEKRESULT))
|
|
_sqlite3ReleaseTempReg(tls, pParse, regRecord)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_SorterNext), iSorter, addr2)
|
|
_sqlite3VdbeJumpHere(tls, v, addr1)
|
|
_sqlite3VdbeAddOp1(tls, v, int32(OP_Close), iTab)
|
|
_sqlite3VdbeAddOp1(tls, v, int32(OP_Close), iIdx)
|
|
_sqlite3VdbeAddOp1(tls, v, int32(OP_Close), iSorter)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** All of the FuncDef structures in the aBuiltinFunc[] array above
|
|
// ** to the global function hash table. This occurs at start-time (as
|
|
// ** a consequence of calling sqlite3_initialize()).
|
|
// **
|
|
// ** After this routine runs
|
|
// */
|
|
func _sqlite3RegisterBuiltinFunctions(tls *libc.TLS) {
|
|
_sqlite3AlterFunctions(tls)
|
|
_sqlite3WindowFunctions(tls)
|
|
_sqlite3RegisterDateTimeFunctions(tls)
|
|
_sqlite3RegisterJsonFunctions(tls)
|
|
_sqlite3InsertBuiltinFuncs(tls, uintptr(unsafe.Pointer(&_aBuiltinFunc)), libc.Int32FromUint64(libc.Uint64FromInt64(7632)/libc.Uint64FromInt64(72)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function registered all of the above C functions as SQL
|
|
// ** functions. This should be the only routine in this file with
|
|
// ** external linkage.
|
|
// */
|
|
func _sqlite3RegisterDateTimeFunctions(tls *libc.TLS) {
|
|
_sqlite3InsertBuiltinFuncs(tls, uintptr(unsafe.Pointer(&_aDateTimeFuncs)), libc.Int32FromUint64(libc.Uint64FromInt64(720)/libc.Uint64FromInt64(72)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Register JSON functions.
|
|
// */
|
|
func _sqlite3RegisterJsonFunctions(tls *libc.TLS) {
|
|
_sqlite3InsertBuiltinFuncs(tls, uintptr(unsafe.Pointer(&_aJsonFunc)), libc.Int32FromUint64(libc.Uint64FromInt64(2592)/libc.Uint64FromInt64(72)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Deallocate a register, making available for reuse for some other
|
|
// ** purpose.
|
|
// */
|
|
func _sqlite3ReleaseTempReg(tls *libc.TLS, pParse uintptr, iReg int32) {
|
|
var v1 Tu8
|
|
var v2 uintptr
|
|
_, _ = v1, v2
|
|
if iReg != 0 {
|
|
if libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FnTempReg) < libc.Int32FromUint64(libc.Uint64FromInt64(32)/libc.Uint64FromInt64(4)) {
|
|
v2 = pParse + 31
|
|
v1 = *(*Tu8)(unsafe.Pointer(v2))
|
|
*(*Tu8)(unsafe.Pointer(v2)) = *(*Tu8)(unsafe.Pointer(v2)) + 1
|
|
**(**int32)(__ccgo_up(pParse + 192 + uintptr(v1)*4)) = iReg
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Remember that the parser tree element pPtr was created using
|
|
// ** the token pToken.
|
|
// **
|
|
// ** In other words, construct a new RenameToken object and add it
|
|
// ** to the list of RenameToken objects currently being built up
|
|
// ** in pParse->pRename.
|
|
// **
|
|
// ** The pPtr argument is returned so that this routine can be used
|
|
// ** with tail recursion in tokenExpr() routine, for a small performance
|
|
// ** improvement.
|
|
// */
|
|
func _sqlite3RenameTokenMap(tls *libc.TLS, pParse uintptr, pPtr uintptr, pToken uintptr) (r uintptr) {
|
|
var pNew uintptr
|
|
_ = pNew
|
|
if libc.Int32FromUint8((*TParse)(unsafe.Pointer(pParse)).FeParseMode) != int32(PARSE_MODE_UNMAP) {
|
|
pNew = _sqlite3DbMallocZero(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, uint64(32))
|
|
if pNew != 0 {
|
|
(*TRenameToken)(unsafe.Pointer(pNew)).Fp = pPtr
|
|
(*TRenameToken)(unsafe.Pointer(pNew)).Ft = **(**TToken)(__ccgo_up(pToken))
|
|
(*TRenameToken)(unsafe.Pointer(pNew)).FpNext = (*TParse)(unsafe.Pointer(pParse)).FpRename
|
|
(*TParse)(unsafe.Pointer(pParse)).FpRename = pNew
|
|
}
|
|
}
|
|
return pPtr
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Erase all schema information from all attached databases (including
|
|
// ** "main" and "temp") for a single database connection.
|
|
// */
|
|
func _sqlite3ResetAllSchemasOfConnection(tls *libc.TLS, db uintptr) {
|
|
var i int32
|
|
var pDb, v2 uintptr
|
|
_, _, _ = i, pDb, v2
|
|
_sqlite3BtreeEnterAll(tls, db)
|
|
i = 0
|
|
for {
|
|
if !(i < (*Tsqlite3)(unsafe.Pointer(db)).FnDb) {
|
|
break
|
|
}
|
|
pDb = (*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(i)*32
|
|
if (*TDb)(unsafe.Pointer(pDb)).FpSchema != 0 {
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FnSchemaLock == uint32(0) {
|
|
_sqlite3SchemaClear(tls, (*TDb)(unsafe.Pointer(pDb)).FpSchema)
|
|
} else {
|
|
v2 = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(i)*32))).FpSchema + 114
|
|
*(*Tu16)(unsafe.Pointer(v2)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v2))) | libc.Int32FromInt32(DB_ResetWanted))
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
**(**Tu32)(__ccgo_up(db + 44)) &= libc.Uint32FromInt32(^(libc.Int32FromInt32(DBFLAG_SchemaChange) | libc.Int32FromInt32(DBFLAG_SchemaKnownOk)))
|
|
_sqlite3VtabUnlockList(tls, db)
|
|
_sqlite3BtreeLeaveAll(tls, db)
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FnSchemaLock == uint32(0) {
|
|
_sqlite3CollapseDatabaseArray(tls, db)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Reset the schema for the database at index iDb. Also reset the
|
|
// ** TEMP schema. The reset is deferred if db->nSchemaLock is not zero.
|
|
// ** Deferred resets may be run by calling with iDb<0.
|
|
// */
|
|
func _sqlite3ResetOneSchema(tls *libc.TLS, db uintptr, iDb int32) {
|
|
var i int32
|
|
var v1 uintptr
|
|
_, _ = i, v1
|
|
if iDb >= 0 {
|
|
v1 = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(iDb)*32))).FpSchema + 114
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(DB_ResetWanted))
|
|
v1 = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + 1*32))).FpSchema + 114
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(DB_ResetWanted))
|
|
**(**Tu32)(__ccgo_up(db + 44)) &= libc.Uint32FromInt32(^libc.Int32FromInt32(DBFLAG_SchemaKnownOk))
|
|
}
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FnSchemaLock == uint32(0) {
|
|
i = 0
|
|
for {
|
|
if !(i < (*Tsqlite3)(unsafe.Pointer(db)).FnDb) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint16((*TSchema)(unsafe.Pointer((**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(i)*32))).FpSchema)).FschemaFlags)&int32(DB_ResetWanted) == int32(DB_ResetWanted) {
|
|
_sqlite3SchemaClear(tls, (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(i)*32))).FpSchema)
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Resolve all names for all expression in an expression list. This is
|
|
// ** just like sqlite3ResolveExprNames() except that it works for an expression
|
|
// ** list rather than a single expression.
|
|
// **
|
|
// ** The return value is SQLITE_OK (0) for success or SQLITE_ERROR (1) for a
|
|
// ** failure.
|
|
// */
|
|
func _sqlite3ResolveExprListNames(tls *libc.TLS, pNC uintptr, pList uintptr) (r int32) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var i, savedHasAgg int32
|
|
var pExpr uintptr
|
|
var _ /* w at bp+0 */ TWalker
|
|
_, _, _ = i, pExpr, savedHasAgg
|
|
savedHasAgg = 0
|
|
if pList == uintptr(0) {
|
|
return SQLITE_OK
|
|
}
|
|
(**(**TWalker)(__ccgo_up(bp))).FpParse = (*TNameContext)(unsafe.Pointer(pNC)).FpParse
|
|
(**(**TWalker)(__ccgo_up(bp))).FxExprCallback = __ccgo_fp(_resolveExprStep)
|
|
(**(**TWalker)(__ccgo_up(bp))).FxSelectCallback = __ccgo_fp(_resolveSelectStep)
|
|
(**(**TWalker)(__ccgo_up(bp))).FxSelectCallback2 = uintptr(0)
|
|
*(*uintptr)(unsafe.Pointer(bp + 40)) = pNC
|
|
savedHasAgg = (*TNameContext)(unsafe.Pointer(pNC)).FncFlags & (libc.Int32FromInt32(NC_HasAgg) | libc.Int32FromInt32(NC_MinMaxAgg) | libc.Int32FromInt32(NC_HasWin) | libc.Int32FromInt32(NC_OrderAgg))
|
|
**(**int32)(__ccgo_up(pNC + 40)) &= ^(libc.Int32FromInt32(NC_HasAgg) | libc.Int32FromInt32(NC_MinMaxAgg) | libc.Int32FromInt32(NC_HasWin) | libc.Int32FromInt32(NC_OrderAgg))
|
|
i = 0
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(pList)).FnExpr) {
|
|
break
|
|
}
|
|
pExpr = (*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(i)*32))).FpExpr
|
|
if pExpr == uintptr(0) {
|
|
goto _1
|
|
}
|
|
**(**int32)(__ccgo_up((**(**TWalker)(__ccgo_up(bp))).FpParse + 316)) += (*TExpr)(unsafe.Pointer(pExpr)).FnHeight
|
|
if _sqlite3ExprCheckHeight(tls, (**(**TWalker)(__ccgo_up(bp))).FpParse, (*TParse)(unsafe.Pointer((**(**TWalker)(__ccgo_up(bp))).FpParse)).FnHeight) != 0 {
|
|
return int32(SQLITE_ERROR)
|
|
}
|
|
_sqlite3WalkExprNN(tls, bp, pExpr)
|
|
**(**int32)(__ccgo_up((**(**TWalker)(__ccgo_up(bp))).FpParse + 316)) -= (*TExpr)(unsafe.Pointer(pExpr)).FnHeight
|
|
if (*TNameContext)(unsafe.Pointer(pNC)).FncFlags&(libc.Int32FromInt32(NC_HasAgg)|libc.Int32FromInt32(NC_MinMaxAgg)|libc.Int32FromInt32(NC_HasWin)|libc.Int32FromInt32(NC_OrderAgg)) != 0 {
|
|
**(**Tu32)(__ccgo_up(pExpr + 4)) |= libc.Uint32FromInt32((*TNameContext)(unsafe.Pointer(pNC)).FncFlags & (libc.Int32FromInt32(NC_HasAgg) | libc.Int32FromInt32(NC_HasWin)))
|
|
savedHasAgg = savedHasAgg | (*TNameContext)(unsafe.Pointer(pNC)).FncFlags&(libc.Int32FromInt32(NC_HasAgg)|libc.Int32FromInt32(NC_MinMaxAgg)|libc.Int32FromInt32(NC_HasWin)|libc.Int32FromInt32(NC_OrderAgg))
|
|
**(**int32)(__ccgo_up(pNC + 40)) &= ^(libc.Int32FromInt32(NC_HasAgg) | libc.Int32FromInt32(NC_MinMaxAgg) | libc.Int32FromInt32(NC_HasWin) | libc.Int32FromInt32(NC_OrderAgg))
|
|
}
|
|
if (*TParse)(unsafe.Pointer((**(**TWalker)(__ccgo_up(bp))).FpParse)).FnErr > 0 {
|
|
return int32(SQLITE_ERROR)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
**(**int32)(__ccgo_up(pNC + 40)) |= savedHasAgg
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine walks an expression tree and resolves references to
|
|
// ** table columns and result-set columns. At the same time, do error
|
|
// ** checking on function usage and set a flag if any aggregate functions
|
|
// ** are seen.
|
|
// **
|
|
// ** To resolve table columns references we look for nodes (or subtrees) of the
|
|
// ** form X.Y.Z or Y.Z or just Z where
|
|
// **
|
|
// ** X: The name of a database. Ex: "main" or "temp" or
|
|
// ** the symbolic name assigned to an ATTACH-ed database.
|
|
// **
|
|
// ** Y: The name of a table in a FROM clause. Or in a trigger
|
|
// ** one of the special names "old" or "new".
|
|
// **
|
|
// ** Z: The name of a column in table Y.
|
|
// **
|
|
// ** The node at the root of the subtree is modified as follows:
|
|
// **
|
|
// ** Expr.op Changed to TK_COLUMN
|
|
// ** Expr.pTab Points to the Table object for X.Y
|
|
// ** Expr.iColumn The column index in X.Y. -1 for the rowid.
|
|
// ** Expr.iTable The VDBE cursor number for X.Y
|
|
// **
|
|
// **
|
|
// ** To resolve result-set references, look for expression nodes of the
|
|
// ** form Z (with no X and Y prefix) where the Z matches the right-hand
|
|
// ** size of an AS clause in the result-set of a SELECT. The Z expression
|
|
// ** is replaced by a copy of the left-hand side of the result-set expression.
|
|
// ** Table-name and function resolution occurs on the substituted expression
|
|
// ** tree. For example, in:
|
|
// **
|
|
// ** SELECT a+b AS x, c+d AS y FROM t1 ORDER BY x;
|
|
// **
|
|
// ** The "x" term of the order by is replaced by "a+b" to render:
|
|
// **
|
|
// ** SELECT a+b AS x, c+d AS y FROM t1 ORDER BY a+b;
|
|
// **
|
|
// ** Function calls are checked to make sure that the function is
|
|
// ** defined and that the correct number of arguments are specified.
|
|
// ** If the function is an aggregate function, then the NC_HasAgg flag is
|
|
// ** set and the opcode is changed from TK_FUNCTION to TK_AGG_FUNCTION.
|
|
// ** If an expression contains aggregate functions then the EP_Agg
|
|
// ** property on the expression is set.
|
|
// **
|
|
// ** An error message is left in pParse if anything is amiss. The number
|
|
// ** if errors is returned.
|
|
// */
|
|
func _sqlite3ResolveExprNames(tls *libc.TLS, pNC uintptr, pExpr uintptr) (r int32) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var savedHasAgg int32
|
|
var v1 uintptr
|
|
var _ /* w at bp+0 */ TWalker
|
|
_, _ = savedHasAgg, v1
|
|
if pExpr == uintptr(0) {
|
|
return SQLITE_OK
|
|
}
|
|
savedHasAgg = (*TNameContext)(unsafe.Pointer(pNC)).FncFlags & (libc.Int32FromInt32(NC_HasAgg) | libc.Int32FromInt32(NC_MinMaxAgg) | libc.Int32FromInt32(NC_HasWin) | libc.Int32FromInt32(NC_OrderAgg))
|
|
**(**int32)(__ccgo_up(pNC + 40)) &= ^(libc.Int32FromInt32(NC_HasAgg) | libc.Int32FromInt32(NC_MinMaxAgg) | libc.Int32FromInt32(NC_HasWin) | libc.Int32FromInt32(NC_OrderAgg))
|
|
(**(**TWalker)(__ccgo_up(bp))).FpParse = (*TNameContext)(unsafe.Pointer(pNC)).FpParse
|
|
(**(**TWalker)(__ccgo_up(bp))).FxExprCallback = __ccgo_fp(_resolveExprStep)
|
|
if (*TNameContext)(unsafe.Pointer(pNC)).FncFlags&int32(NC_NoSelect) != 0 {
|
|
v1 = uintptr(0)
|
|
} else {
|
|
v1 = __ccgo_fp(_resolveSelectStep)
|
|
}
|
|
(**(**TWalker)(__ccgo_up(bp))).FxSelectCallback = v1
|
|
(**(**TWalker)(__ccgo_up(bp))).FxSelectCallback2 = uintptr(0)
|
|
*(*uintptr)(unsafe.Pointer(bp + 40)) = pNC
|
|
**(**int32)(__ccgo_up((**(**TWalker)(__ccgo_up(bp))).FpParse + 316)) += (*TExpr)(unsafe.Pointer(pExpr)).FnHeight
|
|
if _sqlite3ExprCheckHeight(tls, (**(**TWalker)(__ccgo_up(bp))).FpParse, (*TParse)(unsafe.Pointer((**(**TWalker)(__ccgo_up(bp))).FpParse)).FnHeight) != 0 {
|
|
return int32(SQLITE_ERROR)
|
|
}
|
|
_sqlite3WalkExprNN(tls, bp, pExpr)
|
|
**(**int32)(__ccgo_up((**(**TWalker)(__ccgo_up(bp))).FpParse + 316)) -= (*TExpr)(unsafe.Pointer(pExpr)).FnHeight
|
|
**(**Tu32)(__ccgo_up(pExpr + 4)) |= libc.Uint32FromInt32((*TNameContext)(unsafe.Pointer(pNC)).FncFlags & (libc.Int32FromInt32(NC_HasAgg) | libc.Int32FromInt32(NC_HasWin)))
|
|
**(**int32)(__ccgo_up(pNC + 40)) |= savedHasAgg
|
|
return libc.BoolInt32((*TNameContext)(unsafe.Pointer(pNC)).FnNcErr > 0 || (*TParse)(unsafe.Pointer((**(**TWalker)(__ccgo_up(bp))).FpParse)).FnErr > 0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Force the INT64 value currently stored as the result to be
|
|
// ** a MEM_IntReal value. See the SQLITE_TESTCTRL_RESULT_INTREAL
|
|
// ** test-control.
|
|
// */
|
|
func _sqlite3ResultIntReal(tls *libc.TLS, pCtx uintptr) {
|
|
var v1 uintptr
|
|
_ = v1
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer((*Tsqlite3_context)(unsafe.Pointer(pCtx)).FpOut)).Fflags)&int32(MEM_Int) != 0 {
|
|
v1 = (*Tsqlite3_context)(unsafe.Pointer(pCtx)).FpOut + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) & ^libc.Int32FromInt32(MEM_Int))
|
|
v1 = (*Tsqlite3_context)(unsafe.Pointer(pCtx)).FpOut + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromInt32(MEM_IntReal))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* If the Expr node is a subquery or an EXISTS operator or an IN operator that
|
|
// ** uses a subquery, and if the subquery is SF_Correlated, then mark the
|
|
// ** expression as EP_VarSelect.
|
|
// */
|
|
func _sqlite3ReturningSubqueryVarSelect(tls *libc.TLS, NotUsed uintptr, pExpr uintptr) (r int32) {
|
|
_ = NotUsed
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&uint32(EP_xIsSelect) != uint32(0) && (*TSelect)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)))).FselFlags&uint32(SF_Correlated) != uint32(0) {
|
|
**(**Tu32)(__ccgo_up(pExpr + 4)) |= libc.Uint32FromInt32(libc.Int32FromInt32(EP_VarSelect))
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Rollback all database files. If tripCode is not SQLITE_OK, then
|
|
// ** any write cursors are invalidated ("tripped" - as in "tripping a circuit
|
|
// ** breaker") and made to return tripCode if there are any further
|
|
// ** attempts to use that cursor. Read cursors remain open and valid
|
|
// ** but are "saved" in case the table pages are moved around.
|
|
// */
|
|
func _sqlite3RollbackAll(tls *libc.TLS, db uintptr, tripCode int32) {
|
|
var i, inTrans, schemaChange int32
|
|
var p uintptr
|
|
_, _, _, _ = i, inTrans, p, schemaChange
|
|
inTrans = 0
|
|
_sqlite3BeginBenignMalloc(tls)
|
|
/* Obtain all b-tree mutexes before making any calls to BtreeRollback().
|
|
** This is important in case the transaction being rolled back has
|
|
** modified the database schema. If the b-tree mutexes are not taken
|
|
** here, then another shared-cache connection might sneak in between
|
|
** the database rollback and schema reset, which can cause false
|
|
** corruption reports in some cases. */
|
|
_sqlite3BtreeEnterAll(tls, db)
|
|
schemaChange = libc.BoolInt32((*Tsqlite3)(unsafe.Pointer(db)).FmDbFlags&uint32(DBFLAG_SchemaChange) != uint32(0) && libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).Finit1.Fbusy) == 0)
|
|
i = 0
|
|
for {
|
|
if !(i < (*Tsqlite3)(unsafe.Pointer(db)).FnDb) {
|
|
break
|
|
}
|
|
p = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(i)*32))).FpBt
|
|
if p != 0 {
|
|
if _sqlite3BtreeTxnState(tls, p) == int32(SQLITE_TXN_WRITE) {
|
|
inTrans = int32(1)
|
|
}
|
|
_sqlite3BtreeRollback(tls, p, tripCode, libc.BoolInt32(!(schemaChange != 0)))
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_sqlite3VtabRollback(tls, db)
|
|
_sqlite3EndBenignMalloc(tls)
|
|
if schemaChange != 0 {
|
|
_sqlite3ExpirePreparedStatements(tls, db, 0)
|
|
_sqlite3ResetAllSchemasOfConnection(tls, db)
|
|
}
|
|
_sqlite3BtreeLeaveAll(tls, db)
|
|
/* Any deferred constraint violations have now been resolved. */
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FnDeferredCons = 0
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FnDeferredImmCons = 0
|
|
**(**Tu64)(__ccgo_up(db + 48)) &= ^(libc.Uint64FromInt32(SQLITE_DeferFKs) | libc.Uint64FromInt32(libc.Int32FromInt32(0x00002))<<libc.Int32FromInt32(32))
|
|
/* If one has been configured, invoke the rollback-hook callback */
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FxRollbackCallback != 0 && (inTrans != 0 || !((*Tsqlite3)(unsafe.Pointer(db)).FautoCommit != 0)) {
|
|
(*(*func(*libc.TLS, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*Tsqlite3)(unsafe.Pointer(db)).FxRollbackCallback})))(tls, (*Tsqlite3)(unsafe.Pointer(db)).FpRollbackArg)
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Return a static string containing the name corresponding to the error code
|
|
** specified in the argument.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate a RowSet object. Return NULL if a memory allocation
|
|
// ** error occurs.
|
|
// */
|
|
func _sqlite3RowSetInit(tls *libc.TLS, db uintptr) (r uintptr) {
|
|
var N int32
|
|
var p uintptr
|
|
_, _ = N, p
|
|
p = _sqlite3DbMallocRawNN(tls, db, uint64(56))
|
|
if p != 0 {
|
|
N = _sqlite3DbMallocSize(tls, db, p)
|
|
(*TRowSet)(unsafe.Pointer(p)).FpChunk = uintptr(0)
|
|
(*TRowSet)(unsafe.Pointer(p)).Fdb = db
|
|
(*TRowSet)(unsafe.Pointer(p)).FpEntry = uintptr(0)
|
|
(*TRowSet)(unsafe.Pointer(p)).FpLast = uintptr(0)
|
|
(*TRowSet)(unsafe.Pointer(p)).FpForest = uintptr(0)
|
|
(*TRowSet)(unsafe.Pointer(p)).FpFresh = uintptr((libc.Uint64FromInt64(56)+libc.Uint64FromInt32(7))&libc.Uint64FromInt32(^libc.Int32FromInt32(7))) + p
|
|
(*TRowSet)(unsafe.Pointer(p)).FnFresh = uint16((libc.Uint64FromInt32(N) - (libc.Uint64FromInt64(56)+libc.Uint64FromInt32(7))&libc.Uint64FromInt32(^libc.Int32FromInt32(7))) / libc.Uint64FromInt64(24))
|
|
(*TRowSet)(unsafe.Pointer(p)).FrsFlags = uint16(ROWSET_SORTED)
|
|
(*TRowSet)(unsafe.Pointer(p)).FiBatch = 0
|
|
}
|
|
return p
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Extract the smallest element from the RowSet.
|
|
// ** Write the element into *pRowid. Return 1 on success. Return
|
|
// ** 0 if the RowSet is already empty.
|
|
// **
|
|
// ** After this routine has been called, the sqlite3RowSetInsert()
|
|
// ** routine may not be called again.
|
|
// **
|
|
// ** This routine may not be called after sqlite3RowSetTest() has
|
|
// ** been used. Older versions of RowSet allowed that, but as the
|
|
// ** capability was not used by the code generator, it was removed
|
|
// ** for code economy.
|
|
// */
|
|
func _sqlite3RowSetNext(tls *libc.TLS, p uintptr, pRowid uintptr) (r int32) {
|
|
var v1 uintptr
|
|
_ = v1
|
|
/* Cannot be used with sqlite3RowSetText() */
|
|
/* Merge the forest into a single sorted list on first call */
|
|
if libc.Int32FromUint16((*TRowSet)(unsafe.Pointer(p)).FrsFlags)&int32(ROWSET_NEXT) == 0 { /*OPTIMIZATION-IF-FALSE*/
|
|
if libc.Int32FromUint16((*TRowSet)(unsafe.Pointer(p)).FrsFlags)&int32(ROWSET_SORTED) == 0 { /*OPTIMIZATION-IF-FALSE*/
|
|
(*TRowSet)(unsafe.Pointer(p)).FpEntry = _rowSetEntrySort(tls, (*TRowSet)(unsafe.Pointer(p)).FpEntry)
|
|
}
|
|
v1 = p + 50
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | (libc.Int32FromInt32(ROWSET_SORTED) | libc.Int32FromInt32(ROWSET_NEXT)))
|
|
}
|
|
/* Return the next entry on the list */
|
|
if (*TRowSet)(unsafe.Pointer(p)).FpEntry != 0 {
|
|
**(**Ti64)(__ccgo_up(pRowid)) = (*TRowSetEntry)(unsafe.Pointer((*TRowSet)(unsafe.Pointer(p)).FpEntry)).Fv
|
|
(*TRowSet)(unsafe.Pointer(p)).FpEntry = (*TRowSetEntry)(unsafe.Pointer((*TRowSet)(unsafe.Pointer(p)).FpEntry)).FpRight
|
|
if (*TRowSet)(unsafe.Pointer(p)).FpEntry == uintptr(0) { /*OPTIMIZATION-IF-TRUE*/
|
|
/* Free memory immediately, rather than waiting on sqlite3_finalize() */
|
|
_sqlite3RowSetClear(tls, p)
|
|
}
|
|
return int32(1)
|
|
} else {
|
|
return 0
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Check to see if element iRowid was inserted into the rowset as
|
|
// ** part of any insert batch prior to iBatch. Return 1 or 0.
|
|
// **
|
|
// ** If this is the first test of a new batch and if there exist entries
|
|
// ** on pRowSet->pEntry, then sort those entries into the forest at
|
|
// ** pRowSet->pForest so that they can be tested.
|
|
// */
|
|
func _sqlite3RowSetTest(tls *libc.TLS, pRowSet uintptr, iBatch int32, iRowid Tsqlite3_int64) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var p, pTree, ppPrevTree, v2 uintptr
|
|
var _ /* pAux at bp+0 */ uintptr
|
|
var _ /* pTail at bp+8 */ uintptr
|
|
_, _, _, _ = p, pTree, ppPrevTree, v2
|
|
/* This routine is never called after sqlite3RowSetNext() */
|
|
/* Sort entries into the forest on the first test of a new batch.
|
|
** To save unnecessary work, only do this when the batch number changes.
|
|
*/
|
|
if iBatch != (*TRowSet)(unsafe.Pointer(pRowSet)).FiBatch { /*OPTIMIZATION-IF-FALSE*/
|
|
p = (*TRowSet)(unsafe.Pointer(pRowSet)).FpEntry
|
|
if p != 0 {
|
|
ppPrevTree = pRowSet + 40
|
|
if libc.Int32FromUint16((*TRowSet)(unsafe.Pointer(pRowSet)).FrsFlags)&int32(ROWSET_SORTED) == 0 { /*OPTIMIZATION-IF-FALSE*/
|
|
/* Only sort the current set of entries if they need it */
|
|
p = _rowSetEntrySort(tls, p)
|
|
}
|
|
pTree = (*TRowSet)(unsafe.Pointer(pRowSet)).FpForest
|
|
for {
|
|
if !(pTree != 0) {
|
|
break
|
|
}
|
|
ppPrevTree = pTree + 8
|
|
if (*TRowSetEntry)(unsafe.Pointer(pTree)).FpLeft == uintptr(0) {
|
|
(*TRowSetEntry)(unsafe.Pointer(pTree)).FpLeft = _rowSetListToTree(tls, p)
|
|
break
|
|
} else {
|
|
_rowSetTreeToList(tls, (*TRowSetEntry)(unsafe.Pointer(pTree)).FpLeft, bp, bp+8)
|
|
(*TRowSetEntry)(unsafe.Pointer(pTree)).FpLeft = uintptr(0)
|
|
p = _rowSetEntryMerge(tls, **(**uintptr)(__ccgo_up(bp)), p)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
pTree = (*TRowSetEntry)(unsafe.Pointer(pTree)).FpRight
|
|
}
|
|
if pTree == uintptr(0) {
|
|
v2 = _rowSetEntryAlloc(tls, pRowSet)
|
|
pTree = v2
|
|
**(**uintptr)(__ccgo_up(ppPrevTree)) = v2
|
|
if pTree != 0 {
|
|
(*TRowSetEntry)(unsafe.Pointer(pTree)).Fv = 0
|
|
(*TRowSetEntry)(unsafe.Pointer(pTree)).FpRight = uintptr(0)
|
|
(*TRowSetEntry)(unsafe.Pointer(pTree)).FpLeft = _rowSetListToTree(tls, p)
|
|
}
|
|
}
|
|
(*TRowSet)(unsafe.Pointer(pRowSet)).FpEntry = uintptr(0)
|
|
(*TRowSet)(unsafe.Pointer(pRowSet)).FpLast = uintptr(0)
|
|
v2 = pRowSet + 50
|
|
*(*Tu16)(unsafe.Pointer(v2)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v2))) | libc.Int32FromInt32(ROWSET_SORTED))
|
|
}
|
|
(*TRowSet)(unsafe.Pointer(pRowSet)).FiBatch = iBatch
|
|
}
|
|
/* Test to see if the iRowid value appears anywhere in the forest.
|
|
** Return 1 if it does and 0 if not.
|
|
*/
|
|
pTree = (*TRowSet)(unsafe.Pointer(pRowSet)).FpForest
|
|
for {
|
|
if !(pTree != 0) {
|
|
break
|
|
}
|
|
p = (*TRowSetEntry)(unsafe.Pointer(pTree)).FpLeft
|
|
for p != 0 {
|
|
if (*TRowSetEntry)(unsafe.Pointer(p)).Fv < iRowid {
|
|
p = (*TRowSetEntry)(unsafe.Pointer(p)).FpRight
|
|
} else {
|
|
if (*TRowSetEntry)(unsafe.Pointer(p)).Fv > iRowid {
|
|
p = (*TRowSetEntry)(unsafe.Pointer(p)).FpLeft
|
|
} else {
|
|
return int32(1)
|
|
}
|
|
}
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
pTree = (*TRowSetEntry)(unsafe.Pointer(pTree)).FpRight
|
|
}
|
|
return 0
|
|
}
|
|
|
|
/************** End of rowset.c **********************************************/
|
|
/************** Begin file pager.c *******************************************/
|
|
/*
|
|
** 2001 September 15
|
|
**
|
|
** The author disclaims copyright to this source code. In place of
|
|
** a legal notice, here is a blessing:
|
|
**
|
|
** May you do good and not evil.
|
|
** May you find forgiveness for yourself and forgive others.
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
*************************************************************************
|
|
** This is the implementation of the page cache subsystem or "pager".
|
|
**
|
|
** The pager is used to access a database disk file. It implements
|
|
** atomic commit and rollback through the use of a journal file that
|
|
** is separate from the database file. The pager also implements file
|
|
** locking to prevent two processes from writing the same database
|
|
** file simultaneously, or one process from reading the database while
|
|
** another is writing.
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
/************** Include wal.h in the middle of pager.c ***********************/
|
|
/************** Begin file wal.h *********************************************/
|
|
/*
|
|
** 2010 February 1
|
|
**
|
|
** The author disclaims copyright to this source code. In place of
|
|
** a legal notice, here is a blessing:
|
|
**
|
|
** May you do good and not evil.
|
|
** May you find forgiveness for yourself and forgive others.
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
*************************************************************************
|
|
** This header file defines the interface to the write-ahead logging
|
|
** system. Refer to the comments below and the header comment attached to
|
|
** the implementation of each function in log.c for further details.
|
|
*/
|
|
|
|
/* #include "sqliteInt.h" */
|
|
|
|
/* Macros for extracting appropriate sync flags for either transaction
|
|
** commits (WAL_SYNC_FLAGS(X)) or for checkpoint ops (CKPT_SYNC_FLAGS(X)):
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Find and return the schema associated with a BTree. Create
|
|
// ** a new one if necessary.
|
|
// */
|
|
func _sqlite3SchemaGet(tls *libc.TLS, db uintptr, pBt uintptr) (r uintptr) {
|
|
var p uintptr
|
|
_ = p
|
|
if pBt != 0 {
|
|
p = _sqlite3BtreeSchema(tls, pBt, int32(120), __ccgo_fp(_sqlite3SchemaClear))
|
|
} else {
|
|
p = _sqlite3DbMallocZero(tls, uintptr(0), uint64(120))
|
|
}
|
|
if !(p != 0) {
|
|
_sqlite3OomFault(tls, db)
|
|
} else {
|
|
if 0 == libc.Int32FromUint8((*TSchema)(unsafe.Pointer(p)).Ffile_format) {
|
|
_sqlite3HashInit(tls, p+8)
|
|
_sqlite3HashInit(tls, p+32)
|
|
_sqlite3HashInit(tls, p+56)
|
|
_sqlite3HashInit(tls, p+80)
|
|
(*TSchema)(unsafe.Pointer(p)).Fenc = uint8(SQLITE_UTF8)
|
|
}
|
|
}
|
|
return p
|
|
}
|
|
|
|
/************** End of callback.c ********************************************/
|
|
/************** Begin file delete.c ******************************************/
|
|
/*
|
|
** 2001 September 15
|
|
**
|
|
** The author disclaims copyright to this source code. In place of
|
|
** a legal notice, here is a blessing:
|
|
**
|
|
** May you do good and not evil.
|
|
** May you find forgiveness for yourself and forgive others.
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
*************************************************************************
|
|
** This file contains C code routines that are called by the parser
|
|
** in order to generate code for DELETE FROM statements.
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
|
|
func _sqlite3SelectDup(tls *libc.TLS, db uintptr, pDup uintptr, flags int32) (r uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var p, pNew, pNext, pp uintptr
|
|
var _ /* pRet at bp+0 */ uintptr
|
|
_, _, _, _ = p, pNew, pNext, pp
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
pNext = uintptr(0)
|
|
pp = bp
|
|
p = pDup
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
pNew = _sqlite3DbMallocRawNN(tls, db, uint64(120))
|
|
if pNew == uintptr(0) {
|
|
break
|
|
}
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpEList = _sqlite3ExprListDup(tls, db, (*TSelect)(unsafe.Pointer(p)).FpEList, flags)
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpSrc = _sqlite3SrcListDup(tls, db, (*TSelect)(unsafe.Pointer(p)).FpSrc, flags)
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpWhere = _sqlite3ExprDup(tls, db, (*TSelect)(unsafe.Pointer(p)).FpWhere, flags)
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpGroupBy = _sqlite3ExprListDup(tls, db, (*TSelect)(unsafe.Pointer(p)).FpGroupBy, flags)
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpHaving = _sqlite3ExprDup(tls, db, (*TSelect)(unsafe.Pointer(p)).FpHaving, flags)
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpOrderBy = _sqlite3ExprListDup(tls, db, (*TSelect)(unsafe.Pointer(p)).FpOrderBy, flags)
|
|
(*TSelect)(unsafe.Pointer(pNew)).Fop = (*TSelect)(unsafe.Pointer(p)).Fop
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpNext = pNext
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpPrior = uintptr(0)
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpLimit = _sqlite3ExprDup(tls, db, (*TSelect)(unsafe.Pointer(p)).FpLimit, flags)
|
|
(*TSelect)(unsafe.Pointer(pNew)).FiLimit = 0
|
|
(*TSelect)(unsafe.Pointer(pNew)).FiOffset = 0
|
|
(*TSelect)(unsafe.Pointer(pNew)).FselFlags = (*TSelect)(unsafe.Pointer(p)).FselFlags
|
|
(*TSelect)(unsafe.Pointer(pNew)).FnSelectRow = (*TSelect)(unsafe.Pointer(p)).FnSelectRow
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpWith = _sqlite3WithDup(tls, db, (*TSelect)(unsafe.Pointer(p)).FpWith)
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpWin = uintptr(0)
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpWinDefn = _sqlite3WindowListDup(tls, db, (*TSelect)(unsafe.Pointer(p)).FpWinDefn)
|
|
if (*TSelect)(unsafe.Pointer(p)).FpWin != 0 && libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed) == 0 {
|
|
_gatherSelectWindows(tls, pNew)
|
|
}
|
|
(*TSelect)(unsafe.Pointer(pNew)).FselId = (*TSelect)(unsafe.Pointer(p)).FselId
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0 {
|
|
/* Any prior OOM might have left the Select object incomplete.
|
|
** Delete the whole thing rather than allow an incomplete Select
|
|
** to be used by the code generator. */
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpNext = uintptr(0)
|
|
_sqlite3SelectDelete(tls, db, pNew)
|
|
break
|
|
}
|
|
**(**uintptr)(__ccgo_up(pp)) = pNew
|
|
pp = pNew + 72
|
|
pNext = pNew
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = (*TSelect)(unsafe.Pointer(p)).FpPrior
|
|
}
|
|
return **(**uintptr)(__ccgo_up(bp))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate a new Select structure and return a pointer to that
|
|
// ** structure.
|
|
// */
|
|
func _sqlite3SelectNew(tls *libc.TLS, pParse uintptr, pEList uintptr, pSrc uintptr, pWhere uintptr, pGroupBy uintptr, pHaving uintptr, pOrderBy uintptr, selFlags Tu32, pLimit uintptr) (r uintptr) {
|
|
bp := tls.Alloc(128)
|
|
defer tls.Free(128)
|
|
var pAllocated, pNew, v1 uintptr
|
|
var v2 int32
|
|
var _ /* standin at bp+0 */ TSelect
|
|
_, _, _, _ = pAllocated, pNew, v1, v2
|
|
v1 = _sqlite3DbMallocRawNN(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, uint64(120))
|
|
pNew = v1
|
|
pAllocated = v1
|
|
if pNew == uintptr(0) {
|
|
pNew = bp
|
|
}
|
|
if pEList == uintptr(0) {
|
|
pEList = _sqlite3ExprListAppend(tls, pParse, uintptr(0), _sqlite3Expr(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, int32(TK_ASTERISK), uintptr(0)))
|
|
}
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpEList = pEList
|
|
(*TSelect)(unsafe.Pointer(pNew)).Fop = uint8(TK_SELECT)
|
|
(*TSelect)(unsafe.Pointer(pNew)).FselFlags = selFlags
|
|
(*TSelect)(unsafe.Pointer(pNew)).FiLimit = 0
|
|
(*TSelect)(unsafe.Pointer(pNew)).FiOffset = 0
|
|
v1 = pParse + 132
|
|
*(*int32)(unsafe.Pointer(v1)) = *(*int32)(unsafe.Pointer(v1)) + 1
|
|
v2 = *(*int32)(unsafe.Pointer(v1))
|
|
(*TSelect)(unsafe.Pointer(pNew)).FselId = libc.Uint32FromInt32(v2)
|
|
(*TSelect)(unsafe.Pointer(pNew)).FnSelectRow = 0
|
|
if pSrc == uintptr(0) {
|
|
pSrc = _sqlite3DbMallocZero(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, uint64(uint64(libc.UintptrFromInt32(0)+8)+libc.Uint64FromInt64(80)))
|
|
}
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpSrc = pSrc
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpWhere = pWhere
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpGroupBy = pGroupBy
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpHaving = pHaving
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpOrderBy = pOrderBy
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpPrior = uintptr(0)
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpNext = uintptr(0)
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpLimit = pLimit
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpWith = uintptr(0)
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpWin = uintptr(0)
|
|
(*TSelect)(unsafe.Pointer(pNew)).FpWinDefn = uintptr(0)
|
|
if (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).FmallocFailed != 0 {
|
|
_clearSelect(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pNew, libc.BoolInt32(pNew != bp))
|
|
pAllocated = uintptr(0)
|
|
} else {
|
|
}
|
|
return pAllocated
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if zName is a shadow table name in the current database
|
|
// ** connection.
|
|
// **
|
|
// ** zName is temporarily modified while this routine is running, but is
|
|
// ** restored to its original value prior to this routine returning.
|
|
// */
|
|
func _sqlite3ShadowTableName(tls *libc.TLS, db uintptr, zName uintptr) (r int32) {
|
|
var pTab, zCopy, zTail, v1 uintptr
|
|
_, _, _, _ = pTab, zCopy, zTail, v1
|
|
zTail = libc.Xstrrchr(tls, zName, int32('_'))
|
|
if zTail == uintptr(0) {
|
|
return 0
|
|
}
|
|
zCopy = _sqlite3DbStrNDup(tls, db, zName, libc.Uint64FromInt32(int32(int64(zTail)-int64(zName))))
|
|
if zCopy != 0 {
|
|
v1 = _sqlite3FindTable(tls, db, zCopy, uintptr(0))
|
|
} else {
|
|
v1 = uintptr(0)
|
|
}
|
|
pTab = v1
|
|
_sqlite3DbFree(tls, db, zCopy)
|
|
if pTab == uintptr(0) {
|
|
return 0
|
|
}
|
|
if !(libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == libc.Int32FromInt32(TABTYP_VTAB)) {
|
|
return 0
|
|
}
|
|
return _sqlite3IsShadowTableOf(tls, db, pTab, zName)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** When building up a FROM clause in the parser, the join operator
|
|
// ** is initially attached to the left operand. But the code generator
|
|
// ** expects the join operator to be on the right operand. This routine
|
|
// ** Shifts all join operators from left to right for an entire FROM
|
|
// ** clause.
|
|
// **
|
|
// ** Example: Suppose the join is like this:
|
|
// **
|
|
// ** A natural cross join B
|
|
// **
|
|
// ** The operator is "natural cross join". The A and B operands are stored
|
|
// ** in p->a[0] and p->a[1], respectively. The parser initially stores the
|
|
// ** operator with A. This routine shifts that operator over to B.
|
|
// **
|
|
// ** Additional changes:
|
|
// **
|
|
// ** * All tables to the left of the right-most RIGHT JOIN are tagged with
|
|
// ** JT_LTORJ (mnemonic: Left Table Of Right Join) so that the
|
|
// ** code generator can easily tell that the table is part of
|
|
// ** the left operand of at least one RIGHT JOIN.
|
|
// */
|
|
func _sqlite3SrcListShiftJoinType(tls *libc.TLS, pParse uintptr, p uintptr) {
|
|
var allFlags, v3 Tu8
|
|
var i, v1 int32
|
|
var v7 uintptr
|
|
_, _, _, _, _ = allFlags, i, v1, v3, v7
|
|
_ = pParse
|
|
if p != 0 && (*TSrcList)(unsafe.Pointer(p)).FnSrc > int32(1) {
|
|
i = (*TSrcList)(unsafe.Pointer(p)).FnSrc - int32(1)
|
|
allFlags = uint8(0)
|
|
for {
|
|
v3 = (*(*TSrcItem)(unsafe.Pointer(p + 8 + uintptr(i-int32(1))*80))).Ffg.Fjointype
|
|
(*(*TSrcItem)(unsafe.Pointer(p + 8 + uintptr(i)*80))).Ffg.Fjointype = v3
|
|
allFlags = libc.Uint8FromInt32(int32(allFlags) | libc.Int32FromUint8(v3))
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i - 1
|
|
v1 = i
|
|
if !(v1 > 0) {
|
|
break
|
|
}
|
|
}
|
|
(*(*TSrcItem)(unsafe.Pointer(p + 8))).Ffg.Fjointype = uint8(0)
|
|
/* All terms to the left of a RIGHT JOIN should be tagged with the
|
|
** JT_LTORJ flags */
|
|
if libc.Int32FromUint8(allFlags)&int32(JT_RIGHT) != 0 {
|
|
i = (*TSrcList)(unsafe.Pointer(p)).FnSrc - int32(1)
|
|
for {
|
|
if !(i > 0 && libc.Int32FromUint8((*(*TSrcItem)(unsafe.Pointer(p + 8 + uintptr(i)*80))).Ffg.Fjointype)&int32(JT_RIGHT) == 0) {
|
|
break
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
i = i - 1
|
|
}
|
|
i = i - 1
|
|
for {
|
|
v7 = p + 8 + uintptr(i)*80 + 24
|
|
*(*Tu8)(unsafe.Pointer(v7)) = Tu8(int32(*(*Tu8)(unsafe.Pointer(v7))) | libc.Int32FromInt32(JT_LTORJ))
|
|
goto _6
|
|
_6:
|
|
;
|
|
i = i - 1
|
|
v1 = i
|
|
if !(v1 >= 0) {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Unless it is NULL, the argument must be an UnpackedRecord object returned
|
|
// ** by an earlier call to sqlite3Stat4ProbeSetValue(). This call deletes
|
|
// ** the object.
|
|
// */
|
|
func _sqlite3Stat4ProbeFree(tls *libc.TLS, pRec uintptr) {
|
|
var aMem, db uintptr
|
|
var i, nCol int32
|
|
_, _, _, _ = aMem, db, i, nCol
|
|
if pRec != 0 {
|
|
nCol = libc.Int32FromUint16((*TKeyInfo)(unsafe.Pointer((*TUnpackedRecord)(unsafe.Pointer(pRec)).FpKeyInfo)).FnAllField)
|
|
aMem = (*TUnpackedRecord)(unsafe.Pointer(pRec)).FaMem
|
|
db = (**(**TMem)(__ccgo_up(aMem))).Fdb
|
|
i = 0
|
|
for {
|
|
if !(i < nCol) {
|
|
break
|
|
}
|
|
_sqlite3VdbeMemRelease(tls, aMem+uintptr(i)*56)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_sqlite3KeyInfoUnref(tls, (*TUnpackedRecord)(unsafe.Pointer(pRec)).FpKeyInfo)
|
|
_sqlite3DbFreeNN(tls, db, pRec)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Execute the statement pStmt, either until a row of data is ready, the
|
|
// ** statement is completely executed or an error occurs.
|
|
// **
|
|
// ** This routine implements the bulk of the logic behind the sqlite_step()
|
|
// ** API. The only thing omitted is the automatic recompile if a
|
|
// ** schema change has occurred. That detail is handled by the
|
|
// ** outer sqlite3_step() wrapper procedure.
|
|
// */
|
|
func _sqlite3Step(tls *libc.TLS, p uintptr) (r int32) {
|
|
var db uintptr
|
|
var rc int32
|
|
_, _ = db, rc
|
|
db = (*TVdbe)(unsafe.Pointer(p)).Fdb
|
|
if libc.Int32FromUint8((*TVdbe)(unsafe.Pointer(p)).FeVdbeState) != int32(VDBE_RUN_STATE) {
|
|
goto restart_step
|
|
restart_step:
|
|
;
|
|
if libc.Int32FromUint8((*TVdbe)(unsafe.Pointer(p)).FeVdbeState) == int32(VDBE_READY_STATE) {
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0x3>>0)) != 0 {
|
|
(*TVdbe)(unsafe.Pointer(p)).Frc = int32(SQLITE_SCHEMA)
|
|
rc = int32(SQLITE_ERROR)
|
|
if libc.Int32FromUint8((*TVdbe)(unsafe.Pointer(p)).FprepFlags)&int32(SQLITE_PREPARE_SAVESQL) != 0 {
|
|
/* If this statement was prepared using saved SQL and an
|
|
** error has occurred, then return the error code in p->rc to the
|
|
** caller. Set the error code in the database handle to the same
|
|
** value.
|
|
*/
|
|
rc = _sqlite3VdbeTransferError(tls, p)
|
|
}
|
|
goto end_of_step
|
|
}
|
|
/* If there are no other statements currently running, then
|
|
** reset the interrupt flag. This prevents a call to sqlite3_interrupt
|
|
** from interrupting a statement that has not yet started.
|
|
*/
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FnVdbeActive == 0 {
|
|
libc.AtomicStoreNInt32(db+432, libc.Int32FromInt32(0), libc.Int32FromInt32(__ATOMIC_RELAXED))
|
|
}
|
|
if libc.Int32FromUint8((*Tsqlite3)(unsafe.Pointer(db)).FmTrace)&(libc.Int32FromInt32(SQLITE_TRACE_PROFILE)|libc.Int32FromInt32(SQLITE_TRACE_XPROFILE)) != 0 && !((*Tsqlite3)(unsafe.Pointer(db)).Finit1.Fbusy != 0) && (*TVdbe)(unsafe.Pointer(p)).FzSql != 0 {
|
|
_sqlite3OsCurrentTimeInt64(tls, (*Tsqlite3)(unsafe.Pointer(db)).FpVfs, p+184)
|
|
} else {
|
|
}
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FnVdbeActive = (*Tsqlite3)(unsafe.Pointer(db)).FnVdbeActive + 1
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0x40>>6)) == 0 {
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FnVdbeWrite = (*Tsqlite3)(unsafe.Pointer(db)).FnVdbeWrite + 1
|
|
}
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0x80>>7)) != 0 {
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FnVdbeRead = (*Tsqlite3)(unsafe.Pointer(db)).FnVdbeRead + 1
|
|
}
|
|
(*TVdbe)(unsafe.Pointer(p)).Fpc = 0
|
|
(*TVdbe)(unsafe.Pointer(p)).FeVdbeState = uint8(VDBE_RUN_STATE)
|
|
} else {
|
|
if libc.Int32FromUint8((*TVdbe)(unsafe.Pointer(p)).FeVdbeState) == int32(VDBE_HALT_STATE) {
|
|
/* We used to require that sqlite3_reset() be called before retrying
|
|
** sqlite3_step() after any error or after SQLITE_DONE. But beginning
|
|
** with version 3.7.0, we changed this so that sqlite3_reset() would
|
|
** be called automatically instead of throwing the SQLITE_MISUSE error.
|
|
** This "automatic-reset" change is not technically an incompatibility,
|
|
** since any application that receives an SQLITE_MISUSE is broken by
|
|
** definition.
|
|
**
|
|
** Nevertheless, some published applications that were originally written
|
|
** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE
|
|
** returns, and those were broken by the automatic-reset change. As a
|
|
** a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the
|
|
** legacy behavior of returning SQLITE_MISUSE for cases where the
|
|
** previous sqlite3_step() returned something other than a SQLITE_LOCKED
|
|
** or SQLITE_BUSY error.
|
|
*/
|
|
Xsqlite3_reset(tls, p)
|
|
goto restart_step
|
|
}
|
|
}
|
|
}
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0xc>>2)) != 0 {
|
|
rc = _sqlite3VdbeList(tls, p)
|
|
} else {
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FnVdbeExec = (*Tsqlite3)(unsafe.Pointer(db)).FnVdbeExec + 1
|
|
rc = _sqlite3VdbeExec(tls, p)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FnVdbeExec = (*Tsqlite3)(unsafe.Pointer(db)).FnVdbeExec - 1
|
|
}
|
|
if rc == int32(SQLITE_ROW) {
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FerrCode = int32(SQLITE_ROW)
|
|
return int32(SQLITE_ROW)
|
|
} else {
|
|
/* If the statement completed successfully, invoke the profile callback */
|
|
if (*TVdbe)(unsafe.Pointer(p)).FstartTime > 0 {
|
|
_invokeProfileCallback(tls, db, p)
|
|
}
|
|
(*TVdbe)(unsafe.Pointer(p)).FpResultRow = uintptr(0)
|
|
if rc == int32(SQLITE_DONE) && (*Tsqlite3)(unsafe.Pointer(db)).FautoCommit != 0 {
|
|
(*TVdbe)(unsafe.Pointer(p)).Frc = _doWalCallbacks(tls, db)
|
|
if (*TVdbe)(unsafe.Pointer(p)).Frc != SQLITE_OK {
|
|
rc = int32(SQLITE_ERROR)
|
|
}
|
|
} else {
|
|
if rc != int32(SQLITE_DONE) && libc.Int32FromUint8((*TVdbe)(unsafe.Pointer(p)).FprepFlags)&int32(SQLITE_PREPARE_SAVESQL) != 0 {
|
|
/* If this statement was prepared using saved SQL and an
|
|
** error has occurred, then return the error code in p->rc to the
|
|
** caller. Set the error code in the database handle to the same value.
|
|
*/
|
|
rc = _sqlite3VdbeTransferError(tls, p)
|
|
}
|
|
}
|
|
}
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FerrCode = rc
|
|
if int32(SQLITE_NOMEM) == _sqlite3ApiExit(tls, (*TVdbe)(unsafe.Pointer(p)).Fdb, (*TVdbe)(unsafe.Pointer(p)).Frc) {
|
|
(*TVdbe)(unsafe.Pointer(p)).Frc = int32(SQLITE_NOMEM)
|
|
if libc.Int32FromUint8((*TVdbe)(unsafe.Pointer(p)).FprepFlags)&int32(SQLITE_PREPARE_SAVESQL) != 0 {
|
|
rc = (*TVdbe)(unsafe.Pointer(p)).Frc
|
|
}
|
|
}
|
|
goto end_of_step
|
|
end_of_step:
|
|
;
|
|
/* There are only a limited number of result codes allowed from the
|
|
** statements prepared using the legacy sqlite3_prepare() interface */
|
|
return rc & (*Tsqlite3)(unsafe.Pointer(db)).FerrMask
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Convert a storage column number into a table column number.
|
|
// **
|
|
// ** The storage column number (0,1,2,....) is the index of the value
|
|
// ** as it appears in the record on disk. The true column number
|
|
// ** is the index (0,1,2,...) of the column in the CREATE TABLE statement.
|
|
// **
|
|
// ** The storage column number is less than the table column number if
|
|
// ** and only there are VIRTUAL columns to the left.
|
|
// **
|
|
// ** If SQLITE_OMIT_GENERATED_COLUMNS, this routine is a no-op macro.
|
|
// */
|
|
func _sqlite3StorageColumnToTable(tls *libc.TLS, pTab uintptr, iCol Ti16) (r Ti16) {
|
|
var i int32
|
|
_ = i
|
|
if (*TTable)(unsafe.Pointer(pTab)).FtabFlags&uint32(TF_HasVirtual) != 0 {
|
|
i = 0
|
|
for {
|
|
if !(i <= int32(iCol)) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint16((**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(i)*16))).FcolFlags)&int32(COLFLAG_VIRTUAL) != 0 {
|
|
iCol = iCol + 1
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
return iCol
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compute a string length that is limited to what can be stored in
|
|
// ** lower 30 bits of a 32-bit signed integer.
|
|
// **
|
|
// ** The value returned will never be negative. Nor will it ever be greater
|
|
// ** than the actual length of the string. For very long strings (greater
|
|
// ** than 1GiB) the value returned might be less than the true string length.
|
|
// */
|
|
func _sqlite3Strlen30(tls *libc.TLS, z uintptr) (r int32) {
|
|
if z == uintptr(0) {
|
|
return 0
|
|
}
|
|
return int32(0x3fffffff) & libc.Int32FromUint64(libc.Xstrlen(tls, z))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Make changes to the evolving bytecode to do affinity transformations
|
|
// ** of values that are about to be gathered into a row for table pTab.
|
|
// **
|
|
// ** For ordinary (legacy, non-strict) tables:
|
|
// ** -----------------------------------------
|
|
// **
|
|
// ** Compute the affinity string for table pTab, if it has not already been
|
|
// ** computed. As an optimization, omit trailing SQLITE_AFF_BLOB affinities.
|
|
// **
|
|
// ** If the affinity string is empty (because it was all SQLITE_AFF_BLOB entries
|
|
// ** which were then optimized out) then this routine becomes a no-op.
|
|
// **
|
|
// ** Otherwise if iReg>0 then code an OP_Affinity opcode that will set the
|
|
// ** affinities for register iReg and following. Or if iReg==0,
|
|
// ** then just set the P4 operand of the previous opcode (which should be
|
|
// ** an OP_MakeRecord) to the affinity string.
|
|
// **
|
|
// ** A column affinity string has one character per column:
|
|
// **
|
|
// ** Character Column affinity
|
|
// ** --------- ---------------
|
|
// ** 'A' BLOB
|
|
// ** 'B' TEXT
|
|
// ** 'C' NUMERIC
|
|
// ** 'D' INTEGER
|
|
// ** 'E' REAL
|
|
// **
|
|
// ** For STRICT tables:
|
|
// ** ------------------
|
|
// **
|
|
// ** Generate an appropriate OP_TypeCheck opcode that will verify the
|
|
// ** datatypes against the column definitions in pTab. If iReg==0, that
|
|
// ** means an OP_MakeRecord opcode has already been generated and should be
|
|
// ** the last opcode generated. The new OP_TypeCheck needs to be inserted
|
|
// ** before the OP_MakeRecord. The new OP_TypeCheck should use the same
|
|
// ** register set as the OP_MakeRecord. If iReg>0 then register iReg is
|
|
// ** the first of a series of registers that will form the new record.
|
|
// ** Apply the type checking to that array of registers.
|
|
// */
|
|
func _sqlite3TableAffinity(tls *libc.TLS, v uintptr, pTab uintptr, iReg int32) {
|
|
var i, p3 int32
|
|
var pPrev, zColAff uintptr
|
|
_, _, _, _ = i, p3, pPrev, zColAff
|
|
if (*TTable)(unsafe.Pointer(pTab)).FtabFlags&uint32(TF_Strict) != 0 {
|
|
if iReg == 0 {
|
|
_sqlite3VdbeAppendP4(tls, v, pTab, -int32(5))
|
|
pPrev = _sqlite3VdbeGetLastOp(tls, v)
|
|
(*TVdbeOp)(unsafe.Pointer(pPrev)).Fopcode = uint8(OP_TypeCheck)
|
|
p3 = (*TVdbeOp)(unsafe.Pointer(pPrev)).Fp3
|
|
(*TVdbeOp)(unsafe.Pointer(pPrev)).Fp3 = 0
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_MakeRecord), (*TVdbeOp)(unsafe.Pointer(pPrev)).Fp1, (*TVdbeOp)(unsafe.Pointer(pPrev)).Fp2, p3)
|
|
} else {
|
|
/* Insert an isolated OP_Typecheck */
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_TypeCheck), iReg, int32((*TTable)(unsafe.Pointer(pTab)).FnNVCol))
|
|
_sqlite3VdbeAppendP4(tls, v, pTab, -int32(5))
|
|
}
|
|
return
|
|
}
|
|
zColAff = (*TTable)(unsafe.Pointer(pTab)).FzColAff
|
|
if zColAff == uintptr(0) {
|
|
zColAff = _sqlite3TableAffinityStr(tls, uintptr(0), pTab)
|
|
if !(zColAff != 0) {
|
|
_sqlite3OomFault(tls, _sqlite3VdbeDb(tls, v))
|
|
return
|
|
}
|
|
(*TTable)(unsafe.Pointer(pTab)).FzColAff = zColAff
|
|
}
|
|
i = libc.Int32FromUint64(libc.Xstrlen(tls, zColAff) & libc.Uint64FromInt32(0x3fffffff))
|
|
if i != 0 {
|
|
if iReg != 0 {
|
|
_sqlite3VdbeAddOp4(tls, v, int32(OP_Affinity), iReg, i, 0, zColAff, i)
|
|
} else {
|
|
_sqlite3VdbeChangeP4(tls, v, -int32(1), zColAff, i)
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Convert a table column number into a storage column number.
|
|
// **
|
|
// ** The storage column number (0,1,2,....) is the index of the value
|
|
// ** as it appears in the record on disk. Or, if the input column is
|
|
// ** the N-th virtual column (zero-based) then the storage number is
|
|
// ** the number of non-virtual columns in the table plus N.
|
|
// **
|
|
// ** The true column number is the index (0,1,2,...) of the column in
|
|
// ** the CREATE TABLE statement.
|
|
// **
|
|
// ** If the input column is a VIRTUAL column, then it should not appear
|
|
// ** in storage. But the value sometimes is cached in registers that
|
|
// ** follow the range of registers used to construct storage. This
|
|
// ** avoids computing the same VIRTUAL column multiple times, and provides
|
|
// ** values for use by OP_Param opcodes in triggers. Hence, if the
|
|
// ** input column is a VIRTUAL table, put it after all the other columns.
|
|
// **
|
|
// ** In the following, N means "normal column", S means STORED, and
|
|
// ** V means VIRTUAL. Suppose the CREATE TABLE has columns like this:
|
|
// **
|
|
// ** CREATE TABLE ex(N,S,V,N,S,V,N,S,V);
|
|
// ** -- 0 1 2 3 4 5 6 7 8
|
|
// **
|
|
// ** Then the mapping from this function is as follows:
|
|
// **
|
|
// ** INPUTS: 0 1 2 3 4 5 6 7 8
|
|
// ** OUTPUTS: 0 1 6 2 3 7 4 5 8
|
|
// **
|
|
// ** So, in other words, this routine shifts all the virtual columns to
|
|
// ** the end.
|
|
// **
|
|
// ** If SQLITE_OMIT_GENERATED_COLUMNS then there are no virtual columns and
|
|
// ** this routine is a no-op macro. If the pTab does not have any virtual
|
|
// ** columns, then this routine is no-op that always return iCol. If iCol
|
|
// ** is negative (indicating the ROWID column) then this routine return iCol.
|
|
// */
|
|
func _sqlite3TableColumnToStorage(tls *libc.TLS, pTab uintptr, iCol Ti16) (r Ti16) {
|
|
var i int32
|
|
var n Ti16
|
|
_, _ = i, n
|
|
if (*TTable)(unsafe.Pointer(pTab)).FtabFlags&uint32(TF_HasVirtual) == uint32(0) || int32(iCol) < 0 {
|
|
return iCol
|
|
}
|
|
i = 0
|
|
n = libc.Int16FromInt32(0)
|
|
for {
|
|
if !(i < int32(iCol)) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint16((**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(i)*16))).FcolFlags)&int32(COLFLAG_VIRTUAL) == 0 {
|
|
n = n + 1
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if libc.Int32FromUint16((**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer(pTab)).FaCol + uintptr(i)*16))).FcolFlags)&int32(COLFLAG_VIRTUAL) != 0 {
|
|
/* iCol is a virtual column itself */
|
|
return int16(int32((*TTable)(unsafe.Pointer(pTab)).FnNVCol) + i - int32(n))
|
|
} else {
|
|
/* iCol is a normal or stored column */
|
|
return n
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Triggers may access values stored in the old.* or new.* pseudo-table.
|
|
// ** This function returns a 32-bit bitmask indicating which columns of the
|
|
// ** old.* or new.* tables actually are used by triggers. This information
|
|
// ** may be used by the caller, for example, to avoid having to load the entire
|
|
// ** old.* record into memory when executing an UPDATE or DELETE command.
|
|
// **
|
|
// ** Bit 0 of the returned mask is set if the left-most column of the
|
|
// ** table may be accessed using an [old|new].<col> reference. Bit 1 is set if
|
|
// ** the second leftmost column value is required, and so on. If there
|
|
// ** are more than 32 columns in the table, and at least one of the columns
|
|
// ** with an index greater than 32 may be accessed, 0xffffffff is returned.
|
|
// **
|
|
// ** It is not possible to determine if the old.rowid or new.rowid column is
|
|
// ** accessed by triggers. The caller must always assume that it is.
|
|
// **
|
|
// ** Parameter isNew must be either 1 or 0. If it is 0, then the mask returned
|
|
// ** applies to the old.* table. If 1, the new.* table.
|
|
// **
|
|
// ** Parameter tr_tm must be a mask with one or both of the TRIGGER_BEFORE
|
|
// ** and TRIGGER_AFTER bits set. Values accessed by BEFORE triggers are only
|
|
// ** included in the returned mask if the TRIGGER_BEFORE bit is set in the
|
|
// ** tr_tm parameter. Similarly, values accessed by AFTER triggers are only
|
|
// ** included in the returned mask if the TRIGGER_AFTER bit is set in tr_tm.
|
|
// */
|
|
func _sqlite3TriggerColmask(tls *libc.TLS, pParse uintptr, pTrigger uintptr, pChanges uintptr, isNew int32, tr_tm int32, pTab uintptr, orconf int32) (r Tu32) {
|
|
var mask Tu32
|
|
var op, v1 int32
|
|
var p, pPrg uintptr
|
|
_, _, _, _, _ = mask, op, p, pPrg, v1
|
|
if pChanges != 0 {
|
|
v1 = int32(TK_UPDATE)
|
|
} else {
|
|
v1 = int32(TK_DELETE)
|
|
}
|
|
op = v1
|
|
mask = uint32(0)
|
|
if libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == int32(TABTYP_VIEW) {
|
|
return uint32(0xffffffff)
|
|
}
|
|
p = pTrigger
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((*TTrigger)(unsafe.Pointer(p)).Fop) == op && tr_tm&libc.Int32FromUint8((*TTrigger)(unsafe.Pointer(p)).Ftr_tm) != 0 && _checkColumnOverlap(tls, (*TTrigger)(unsafe.Pointer(p)).FpColumns, pChanges) != 0 {
|
|
if (*TTrigger)(unsafe.Pointer(p)).FbReturning != 0 {
|
|
mask = uint32(0xffffffff)
|
|
} else {
|
|
pPrg = _getRowTrigger(tls, pParse, p, pTab, orconf)
|
|
if pPrg != 0 {
|
|
mask = mask | **(**Tu32)(__ccgo_up(pPrg + 28 + uintptr(isNew)*4))
|
|
}
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
p = (*TTrigger)(unsafe.Pointer(p)).FpNext
|
|
}
|
|
return mask
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Given table pTab, return a list of all the triggers attached to
|
|
// ** the table. The list is connected by Trigger.pNext pointers.
|
|
// **
|
|
// ** All of the triggers on pTab that are in the same database as pTab
|
|
// ** are already attached to pTab->pTrigger. But there might be additional
|
|
// ** triggers on pTab in the TEMP schema. This routine prepends all
|
|
// ** TEMP triggers on pTab to the beginning of the pTab->pTrigger list
|
|
// ** and returns the combined list.
|
|
// **
|
|
// ** To state it another way: This routine returns a list of all triggers
|
|
// ** that fire off of pTab. The list will include any TEMP triggers on
|
|
// ** pTab as well as the triggers lised in pTab->pTrigger.
|
|
// */
|
|
func _sqlite3TriggerList(tls *libc.TLS, pParse uintptr, pTab uintptr) (r uintptr) {
|
|
var p, pList, pTmpSchema, pTrig uintptr
|
|
_, _, _, _ = p, pList, pTmpSchema, pTrig /* Loop variable for TEMP triggers */
|
|
pTmpSchema = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).FaDb + 1*32))).FpSchema
|
|
p = (*THash)(unsafe.Pointer(pTmpSchema + 56)).Ffirst
|
|
pList = (*TTable)(unsafe.Pointer(pTab)).FpTrigger
|
|
for p != 0 {
|
|
pTrig = (*THashElem)(unsafe.Pointer(p)).Fdata
|
|
if (*TTrigger)(unsafe.Pointer(pTrig)).FpTabSchema == (*TTable)(unsafe.Pointer(pTab)).FpSchema && (*TTrigger)(unsafe.Pointer(pTrig)).Ftable != 0 && 0 == _sqlite3StrICmp(tls, (*TTrigger)(unsafe.Pointer(pTrig)).Ftable, (*TTable)(unsafe.Pointer(pTab)).FzName) && ((*TTrigger)(unsafe.Pointer(pTrig)).FpTabSchema != pTmpSchema || (*TTrigger)(unsafe.Pointer(pTrig)).FbReturning != 0) {
|
|
(*TTrigger)(unsafe.Pointer(pTrig)).FpNext = pList
|
|
pList = pTrig
|
|
} else {
|
|
if libc.Int32FromUint8((*TTrigger)(unsafe.Pointer(pTrig)).Fop) == int32(TK_RETURNING) {
|
|
(*TTrigger)(unsafe.Pointer(pTrig)).Ftable = (*TTable)(unsafe.Pointer(pTab)).FzName
|
|
(*TTrigger)(unsafe.Pointer(pTrig)).FpTabSchema = (*TTable)(unsafe.Pointer(pTab)).FpSchema
|
|
(*TTrigger)(unsafe.Pointer(pTrig)).FpNext = pList
|
|
pList = pTrig
|
|
}
|
|
}
|
|
p = (*THashElem)(unsafe.Pointer(p)).Fnext
|
|
}
|
|
return pList
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add an OP_Function or OP_PureFunc opcode.
|
|
// **
|
|
// ** The eCallCtx argument is information (typically taken from Expr.op2)
|
|
// ** that describes the calling context of the function. 0 means a general
|
|
// ** function call. NC_IsCheck means called by a check constraint,
|
|
// ** NC_IdxExpr means called as part of an index expression. NC_PartIdx
|
|
// ** means in the WHERE clause of a partial index. NC_GenCol means called
|
|
// ** while computing a generated column value. 0 is the usual case.
|
|
// */
|
|
func _sqlite3VdbeAddFunctionCall(tls *libc.TLS, pParse uintptr, p1 int32, p2 int32, p3 int32, nArg int32, pFunc uintptr, eCallCtx int32) (r int32) {
|
|
var addr, v1 int32
|
|
var pCtx, v uintptr
|
|
_, _, _, _ = addr, pCtx, v, v1
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
pCtx = _sqlite3DbMallocRawNN(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, uint64(uint64(libc.UintptrFromInt32(0)+48)+libc.Uint64FromInt32(nArg)*libc.Uint64FromInt64(8)))
|
|
if pCtx == uintptr(0) {
|
|
_freeEphemeralFunction(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pFunc)
|
|
return 0
|
|
}
|
|
(*Tsqlite3_context)(unsafe.Pointer(pCtx)).FpOut = uintptr(0)
|
|
(*Tsqlite3_context)(unsafe.Pointer(pCtx)).FpFunc = pFunc
|
|
(*Tsqlite3_context)(unsafe.Pointer(pCtx)).FpVdbe = uintptr(0)
|
|
(*Tsqlite3_context)(unsafe.Pointer(pCtx)).FisError = 0
|
|
(*Tsqlite3_context)(unsafe.Pointer(pCtx)).Fargc = libc.Uint16FromInt32(nArg)
|
|
(*Tsqlite3_context)(unsafe.Pointer(pCtx)).FiOp = _sqlite3VdbeCurrentAddr(tls, v)
|
|
if eCallCtx != 0 {
|
|
v1 = int32(OP_PureFunc)
|
|
} else {
|
|
v1 = int32(OP_Function)
|
|
}
|
|
addr = _sqlite3VdbeAddOp4(tls, v, v1, p1, p2, p3, pCtx, -int32(16))
|
|
_sqlite3VdbeChangeP5(tls, v, libc.Uint16FromInt32(eCallCtx&int32(NC_SelfRef)))
|
|
_sqlite3MayAbort(tls, pParse)
|
|
return addr
|
|
}
|
|
|
|
func _sqlite3VdbeAddOp3(tls *libc.TLS, p uintptr, op int32, p1 int32, p2 int32, p3 int32) (r int32) {
|
|
var i int32
|
|
var pOp uintptr
|
|
_, _ = i, pOp
|
|
i = (*TVdbe)(unsafe.Pointer(p)).FnOp
|
|
if (*TVdbe)(unsafe.Pointer(p)).FnOpAlloc <= i {
|
|
return _growOp3(tls, p, op, p1, p2, p3)
|
|
}
|
|
(*TVdbe)(unsafe.Pointer(p)).FnOp = (*TVdbe)(unsafe.Pointer(p)).FnOp + 1
|
|
pOp = (*TVdbe)(unsafe.Pointer(p)).FaOp + uintptr(i)*24
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fopcode = libc.Uint8FromInt32(op)
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp5 = uint16(0)
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp1 = p1
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp2 = p2
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp3 = p3
|
|
*(*uintptr)(unsafe.Pointer(pOp + 16)) = uintptr(0)
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp4type = P4_NOTUSED
|
|
/* Replicate this logic in sqlite3VdbeAddOp4Int()
|
|
** vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
|
|
/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
** Replicate in sqlite3VdbeAddOp4Int() */
|
|
return i
|
|
}
|
|
|
|
func _sqlite3VdbeAddOp4Int(tls *libc.TLS, p uintptr, op int32, p1 int32, p2 int32, p3 int32, p4 int32) (r int32) {
|
|
var i int32
|
|
var pOp uintptr
|
|
_, _ = i, pOp
|
|
i = (*TVdbe)(unsafe.Pointer(p)).FnOp
|
|
if (*TVdbe)(unsafe.Pointer(p)).FnOpAlloc <= i {
|
|
return _addOp4IntSlow(tls, p, op, p1, p2, p3, p4)
|
|
}
|
|
(*TVdbe)(unsafe.Pointer(p)).FnOp = (*TVdbe)(unsafe.Pointer(p)).FnOp + 1
|
|
pOp = (*TVdbe)(unsafe.Pointer(p)).FaOp + uintptr(i)*24
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fopcode = libc.Uint8FromInt32(op)
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp5 = uint16(0)
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp1 = p1
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp2 = p2
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp3 = p3
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp4.Fi = p4
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp4type = int8(-libc.Int32FromInt32(3))
|
|
/* Replicate this logic in sqlite3VdbeAddOp3()
|
|
** vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
|
|
/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
** Replicate in sqlite3VdbeAddOp3() */
|
|
return i
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add a whole list of operations to the operation stack. Return a
|
|
// ** pointer to the first operation inserted.
|
|
// **
|
|
// ** Non-zero P2 arguments to jump instructions are automatically adjusted
|
|
// ** so that the jump target is relative to the first operation inserted.
|
|
// */
|
|
func _sqlite3VdbeAddOpList(tls *libc.TLS, p uintptr, nOp int32, aOp uintptr, iLineno int32) (r uintptr) {
|
|
var i int32
|
|
var pFirst, pOut, v1 uintptr
|
|
_, _, _, _ = i, pFirst, pOut, v1
|
|
if (*TVdbe)(unsafe.Pointer(p)).FnOp+nOp > (*TVdbe)(unsafe.Pointer(p)).FnOpAlloc && _growOpArray(tls, p, nOp) != 0 {
|
|
return uintptr(0)
|
|
}
|
|
v1 = (*TVdbe)(unsafe.Pointer(p)).FaOp + uintptr((*TVdbe)(unsafe.Pointer(p)).FnOp)*24
|
|
pOut = v1
|
|
pFirst = v1
|
|
i = 0
|
|
for {
|
|
if !(i < nOp) {
|
|
break
|
|
}
|
|
(*TVdbeOp)(unsafe.Pointer(pOut)).Fopcode = (*TVdbeOpList)(unsafe.Pointer(aOp)).Fopcode
|
|
(*TVdbeOp)(unsafe.Pointer(pOut)).Fp1 = int32((*TVdbeOpList)(unsafe.Pointer(aOp)).Fp1)
|
|
(*TVdbeOp)(unsafe.Pointer(pOut)).Fp2 = int32((*TVdbeOpList)(unsafe.Pointer(aOp)).Fp2)
|
|
if libc.Int32FromUint8(_sqlite3OpcodeProperty[(*TVdbeOpList)(unsafe.Pointer(aOp)).Fopcode])&int32(OPFLG_JUMP) != 0 && int32((*TVdbeOpList)(unsafe.Pointer(aOp)).Fp2) > 0 {
|
|
**(**int32)(__ccgo_up(pOut + 8)) += (*TVdbe)(unsafe.Pointer(p)).FnOp
|
|
}
|
|
(*TVdbeOp)(unsafe.Pointer(pOut)).Fp3 = int32((*TVdbeOpList)(unsafe.Pointer(aOp)).Fp3)
|
|
(*TVdbeOp)(unsafe.Pointer(pOut)).Fp4type = P4_NOTUSED
|
|
*(*uintptr)(unsafe.Pointer(pOut + 16)) = uintptr(0)
|
|
(*TVdbeOp)(unsafe.Pointer(pOut)).Fp5 = uint16(0)
|
|
_ = iLineno
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
aOp += 4
|
|
pOut += 24
|
|
}
|
|
**(**int32)(__ccgo_up(p + 144)) += nOp
|
|
return pFirst
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate sufficient space for an UnpackedRecord structure large enough
|
|
// ** to hold a decoded index record for pKeyInfo.
|
|
// **
|
|
// ** The space is allocated using sqlite3DbMallocRaw(). If an OOM error
|
|
// ** occurs, NULL is returned.
|
|
// */
|
|
func _sqlite3VdbeAllocUnpackedRecord(tls *libc.TLS, pKeyInfo uintptr) (r uintptr) {
|
|
var nByte Tu64
|
|
var p uintptr
|
|
_, _ = nByte, p /* Number of bytes required for *p */
|
|
nByte = uint64(libc.Uint64FromInt64(40) + uint64(56)*libc.Uint64FromInt32(libc.Int32FromUint16((*TKeyInfo)(unsafe.Pointer(pKeyInfo)).FnKeyField)+libc.Int32FromInt32(1)))
|
|
p = _sqlite3DbMallocRaw(tls, (*TKeyInfo)(unsafe.Pointer(pKeyInfo)).Fdb, nByte)
|
|
if !(p != 0) {
|
|
return uintptr(0)
|
|
}
|
|
(*TUnpackedRecord)(unsafe.Pointer(p)).FaMem = p + uintptr(libc.Uint64FromInt64(40))
|
|
(*TUnpackedRecord)(unsafe.Pointer(p)).FpKeyInfo = pKeyInfo
|
|
(*TUnpackedRecord)(unsafe.Pointer(p)).FnField = libc.Uint16FromInt32(libc.Int32FromUint16((*TKeyInfo)(unsafe.Pointer(pKeyInfo)).FnKeyField) + int32(1))
|
|
return p
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If parameter iOp is less than zero, then invoke the destructor for
|
|
// ** all auxiliary data pointers currently cached by the VM passed as
|
|
// ** the first argument.
|
|
// **
|
|
// ** Or, if iOp is greater than or equal to zero, then the destructor is
|
|
// ** only invoked for those auxiliary data pointers created by the user
|
|
// ** function invoked by the OP_Function opcode at instruction iOp of
|
|
// ** VM pVdbe, and only then if:
|
|
// **
|
|
// ** * the associated function parameter is the 32nd or later (counting
|
|
// ** from left to right), or
|
|
// **
|
|
// ** * the corresponding bit in argument mask is clear (where the first
|
|
// ** function parameter corresponds to bit 0 etc.).
|
|
// */
|
|
func _sqlite3VdbeDeleteAuxData(tls *libc.TLS, db uintptr, pp uintptr, iOp int32, mask int32) {
|
|
var pAux uintptr
|
|
_ = pAux
|
|
for **(**uintptr)(__ccgo_up(pp)) != 0 {
|
|
pAux = **(**uintptr)(__ccgo_up(pp))
|
|
if iOp < 0 || (*TAuxData)(unsafe.Pointer(pAux)).FiAuxOp == iOp && (*TAuxData)(unsafe.Pointer(pAux)).FiAuxArg >= 0 && ((*TAuxData)(unsafe.Pointer(pAux)).FiAuxArg > int32(31) || !(libc.Uint32FromInt32(mask)&(libc.Uint32FromInt32(1)<<(*TAuxData)(unsafe.Pointer(pAux)).FiAuxArg) != 0)) {
|
|
if (*TAuxData)(unsafe.Pointer(pAux)).FxDeleteAux != 0 {
|
|
(*(*func(*libc.TLS, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TAuxData)(unsafe.Pointer(pAux)).FxDeleteAux})))(tls, (*TAuxData)(unsafe.Pointer(pAux)).FpAux)
|
|
}
|
|
**(**uintptr)(__ccgo_up(pp)) = (*TAuxData)(unsafe.Pointer(pAux)).FpNextAux
|
|
_sqlite3DbFree(tls, db, pAux)
|
|
} else {
|
|
pp = pAux + 24
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If the last opcode is "op" and it is not a jump destination,
|
|
// ** then remove it. Return true if and only if an opcode was removed.
|
|
// */
|
|
func _sqlite3VdbeDeletePriorOpcode(tls *libc.TLS, p uintptr, op Tu8) (r int32) {
|
|
if (*TVdbe)(unsafe.Pointer(p)).FnOp > 0 && libc.Int32FromUint8((**(**TOp)(__ccgo_up((*TVdbe)(unsafe.Pointer(p)).FaOp + uintptr((*TVdbe)(unsafe.Pointer(p)).FnOp-int32(1))*24))).Fopcode) == libc.Int32FromUint8(op) {
|
|
return _sqlite3VdbeChangeToNoop(tls, p, (*TVdbe)(unsafe.Pointer(p)).FnOp-int32(1))
|
|
} else {
|
|
return 0
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return a pointer to an sqlite3VdbeRecordCompare() compatible function
|
|
// ** suitable for comparing serialized records to the unpacked record passed
|
|
// ** as the only argument.
|
|
// */
|
|
func _sqlite3VdbeFindCompare(tls *libc.TLS, p uintptr) (r TRecordCompare) {
|
|
var flags int32
|
|
_ = flags
|
|
/* varintRecordCompareInt() and varintRecordCompareString() both assume
|
|
** that the size-of-header varint that occurs at the start of each record
|
|
** fits in a single byte (i.e. is 127 or less). varintRecordCompareInt()
|
|
** also assumes that it is safe to overread a buffer by at least the
|
|
** maximum possible legal header size plus 8 bytes. Because there is
|
|
** guaranteed to be at least 74 (but not 136) bytes of padding following each
|
|
** buffer passed to varintRecordCompareInt() this makes it convenient to
|
|
** limit the size of the header to 64 bytes in cases where the first field
|
|
** is an integer.
|
|
**
|
|
** The easiest way to enforce this limit is to consider only records with
|
|
** 13 fields or less. If the first field is an integer, the maximum legal
|
|
** header size is (12*5 + 1 + 1) bytes. */
|
|
if libc.Int32FromUint16((*TKeyInfo)(unsafe.Pointer((*TUnpackedRecord)(unsafe.Pointer(p)).FpKeyInfo)).FnAllField) <= int32(13) {
|
|
flags = libc.Int32FromUint16((**(**TMem)(__ccgo_up((*TUnpackedRecord)(unsafe.Pointer(p)).FaMem))).Fflags)
|
|
if **(**Tu8)(__ccgo_up((*TKeyInfo)(unsafe.Pointer((*TUnpackedRecord)(unsafe.Pointer(p)).FpKeyInfo)).FaSortFlags)) != 0 {
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TKeyInfo)(unsafe.Pointer((*TUnpackedRecord)(unsafe.Pointer(p)).FpKeyInfo)).FaSortFlags)))&int32(KEYINFO_ORDER_BIGNULL) != 0 {
|
|
return __ccgo_fp(_sqlite3VdbeRecordCompare)
|
|
}
|
|
(*TUnpackedRecord)(unsafe.Pointer(p)).Fr1 = int8(1)
|
|
(*TUnpackedRecord)(unsafe.Pointer(p)).Fr2 = int8(-int32(1))
|
|
} else {
|
|
(*TUnpackedRecord)(unsafe.Pointer(p)).Fr1 = int8(-int32(1))
|
|
(*TUnpackedRecord)(unsafe.Pointer(p)).Fr2 = int8(1)
|
|
}
|
|
if flags&int32(MEM_Int) != 0 {
|
|
*(*Ti64)(unsafe.Pointer(p + 16)) = *(*Ti64)(unsafe.Pointer((*TUnpackedRecord)(unsafe.Pointer(p)).FaMem))
|
|
return __ccgo_fp(_vdbeRecordCompareInt)
|
|
}
|
|
if flags&(libc.Int32FromInt32(MEM_Real)|libc.Int32FromInt32(MEM_IntReal)|libc.Int32FromInt32(MEM_Null)|libc.Int32FromInt32(MEM_Blob)) == 0 && *(*uintptr)(unsafe.Pointer((*TUnpackedRecord)(unsafe.Pointer(p)).FpKeyInfo + 32)) == uintptr(0) {
|
|
*(*uintptr)(unsafe.Pointer(p + 16)) = (**(**TMem)(__ccgo_up((*TUnpackedRecord)(unsafe.Pointer(p)).FaMem))).Fz
|
|
(*TUnpackedRecord)(unsafe.Pointer(p)).Fn = (**(**TMem)(__ccgo_up((*TUnpackedRecord)(unsafe.Pointer(p)).FaMem))).Fn
|
|
return __ccgo_fp(_vdbeRecordCompareString)
|
|
}
|
|
}
|
|
return __ccgo_fp(_sqlite3VdbeRecordCompare)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is called when the record in (*p) should be found in the index
|
|
// ** opened by cursor pCur, but was not. This may happen as part of a DELETE
|
|
// ** operation or an integrity check.
|
|
// **
|
|
// ** One reason that an exact match was not found may be the EIIB bug - that
|
|
// ** a text-to-float conversion may have caused a real value in record (*p)
|
|
// ** to be slightly different from its counterpart on disk. This function
|
|
// ** attempts to find the right index record. If it does find the right
|
|
// ** record, it leaves *pCur pointing to it and sets (*pRes) to 0 before
|
|
// ** returning. Otherwise, (*pRes) is set to non-zero and an SQLite error
|
|
// ** code returned.
|
|
// **
|
|
// ** The algorithm used to find the correct record is:
|
|
// **
|
|
// ** * Scan up to BTREE_FDK_RANGE entries either side of the current entry.
|
|
// ** If parameter bIntegrity is false, then all fields that are indexed
|
|
// ** expressions or virtual table columns are omitted from the comparison.
|
|
// ** If bIntegrity is true, then small differences in real values in
|
|
// ** such fields are overlooked, but they are not omitted from the comparison
|
|
// ** altogether.
|
|
// **
|
|
// ** * If the above fails to find an entry and bIntegrity is false, search
|
|
// ** the entire index.
|
|
// */
|
|
func _sqlite3VdbeFindIndexKey(tls *libc.TLS, pCur uintptr, pIdx uintptr, p uintptr, pRes uintptr, bIntegrity int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iCol, ii, nStep, rc, v2 int32
|
|
var mask TBitmask
|
|
var _ /* res at bp+0 */ int32
|
|
_, _, _, _, _, _ = iCol, ii, mask, nStep, rc, v2
|
|
nStep = 0
|
|
**(**int32)(__ccgo_up(bp)) = int32(1)
|
|
rc = SQLITE_OK
|
|
ii = 0
|
|
/* Calculate a mask based on the first 64 columns of the index. The mask
|
|
** bit is set if the corresponding index field is either an expression
|
|
** or a virtual column of the table. */
|
|
mask = uint64(0)
|
|
ii = 0
|
|
for {
|
|
if libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn) < libc.Int32FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(8)) {
|
|
v2 = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn)
|
|
} else {
|
|
v2 = libc.Int32FromUint64(libc.Uint64FromInt64(8) * libc.Uint64FromInt32(8))
|
|
}
|
|
if !(ii < v2) {
|
|
break
|
|
}
|
|
iCol = int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaiColumn + uintptr(ii)*2)))
|
|
if iCol == -int32(2) || iCol >= 0 && libc.Int32FromUint16((**(**TColumn)(__ccgo_up((*TTable)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pIdx)).FpTable)).FaCol + uintptr(iCol)*16))).FcolFlags)&int32(COLFLAG_VIRTUAL) != 0 {
|
|
mask = mask | libc.Uint64FromInt32(1)<<ii
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
/* If the mask is 0 at this point, then the index contains no expressions
|
|
** or virtual columns. So do not search for a match - return so that the
|
|
** caller may declare the db corrupt immediately. Or, if mask is non-zero,
|
|
** proceed. */
|
|
if mask != uint64(0) {
|
|
/* Move the cursor back BTREE_FDK_RANGE entries. If this hits an EOF,
|
|
** position the cursor at the first entry in the index and set nStep
|
|
** to -1 so that the first loop below scans the entire index. Otherwise,
|
|
** set nStep to BTREE_FDK_RANGE*2 so that the first loop below scans
|
|
** just that many entries. */
|
|
ii = 0
|
|
for {
|
|
if !(_sqlite3BtreeEof(tls, pCur) == 0 && ii < int32(BTREE_FDK_RANGE)) {
|
|
break
|
|
}
|
|
rc = _sqlite3BtreePrevious(tls, pCur, 0)
|
|
goto _3
|
|
_3:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
if rc == int32(SQLITE_DONE) {
|
|
rc = _sqlite3BtreeFirst(tls, pCur, bp)
|
|
nStep = -int32(1)
|
|
} else {
|
|
nStep = libc.Int32FromInt32(BTREE_FDK_RANGE) * libc.Int32FromInt32(2)
|
|
}
|
|
/* This loop runs at most twice to search for a key with matching PK
|
|
** fields in the index. The second iteration always searches the entire
|
|
** index. The first iteration searches nStep entries starting with the
|
|
** current cursor entry if (nStep>=0), or the entire index if (nStep<0). */
|
|
for _sqlite3BtreeCursorIsValidNN(tls, pCur) != 0 {
|
|
ii = 0
|
|
for {
|
|
if !(rc == SQLITE_OK && (ii < nStep || nStep < 0)) {
|
|
break
|
|
}
|
|
rc = _vdbeIsMatchingIndexKey(tls, pCur, bIntegrity, mask, p, bp)
|
|
if **(**int32)(__ccgo_up(bp)) == 0 || rc != SQLITE_OK {
|
|
break
|
|
}
|
|
rc = _sqlite3BtreeNext(tls, pCur, 0)
|
|
goto _4
|
|
_4:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
if rc == int32(SQLITE_DONE) {
|
|
rc = SQLITE_OK
|
|
}
|
|
if nStep < 0 || rc != SQLITE_OK || **(**int32)(__ccgo_up(bp)) == 0 || bIntegrity != 0 {
|
|
break
|
|
}
|
|
/* The first, non-exhaustive, search failed to find an entry with
|
|
** matching PK fields. So restart for an exhaustive search of the
|
|
** entire index. */
|
|
nStep = -int32(1)
|
|
rc = _sqlite3BtreeFirst(tls, pCur, bp)
|
|
}
|
|
}
|
|
**(**int32)(__ccgo_up(pRes)) = **(**int32)(__ccgo_up(bp))
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Delete a VdbeFrame object and its contents. VdbeFrame objects are
|
|
// ** allocated by the OP_Program opcode in sqlite3VdbeExec().
|
|
// */
|
|
func _sqlite3VdbeFrameDelete(tls *libc.TLS, p uintptr) {
|
|
var aMem, apCsr uintptr
|
|
var i int32
|
|
_, _, _ = aMem, apCsr, i
|
|
aMem = p + uintptr((libc.Uint64FromInt64(112)+libc.Uint64FromInt32(7))&libc.Uint64FromInt32(^libc.Int32FromInt32(7)))
|
|
apCsr = aMem + uintptr((*TVdbeFrame)(unsafe.Pointer(p)).FnChildMem)*56
|
|
i = 0
|
|
for {
|
|
if !(i < (*TVdbeFrame)(unsafe.Pointer(p)).FnChildCsr) {
|
|
break
|
|
}
|
|
if **(**uintptr)(__ccgo_up(apCsr + uintptr(i)*8)) != 0 {
|
|
_sqlite3VdbeFreeCursorNN(tls, (*TVdbeFrame)(unsafe.Pointer(p)).Fv, **(**uintptr)(__ccgo_up(apCsr + uintptr(i)*8)))
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_releaseMemArray(tls, aMem, (*TVdbeFrame)(unsafe.Pointer(p)).FnChildMem)
|
|
_sqlite3VdbeDeleteAuxData(tls, (*TVdbe)(unsafe.Pointer((*TVdbeFrame)(unsafe.Pointer(p)).Fv)).Fdb, p+64, -int32(1), 0)
|
|
_sqlite3DbFree(tls, (*TVdbe)(unsafe.Pointer((*TVdbeFrame)(unsafe.Pointer(p)).Fv)).Fdb, p)
|
|
}
|
|
|
|
func _sqlite3VdbeFreeCursorNN(tls *libc.TLS, p uintptr, pCx uintptr) {
|
|
var pModule, pVCur uintptr
|
|
_, _ = pModule, pVCur
|
|
if int32(TBool(*(*uint8)(unsafe.Pointer(pCx + 8))&0x10>>4)) != 0 {
|
|
_freeCursorWithCache(tls, p, pCx)
|
|
return
|
|
}
|
|
switch libc.Int32FromUint8((*TVdbeCursor)(unsafe.Pointer(pCx)).FeCurType) {
|
|
case int32(CURTYPE_SORTER):
|
|
_sqlite3VdbeSorterClose(tls, (*TVdbe)(unsafe.Pointer(p)).Fdb, pCx)
|
|
case CURTYPE_BTREE:
|
|
_sqlite3BtreeCloseCursor(tls, *(*uintptr)(unsafe.Pointer(pCx + 48)))
|
|
case int32(CURTYPE_VTAB):
|
|
pVCur = *(*uintptr)(unsafe.Pointer(pCx + 48))
|
|
pModule = (*Tsqlite3_vtab)(unsafe.Pointer((*Tsqlite3_vtab_cursor)(unsafe.Pointer(pVCur)).FpVtab)).FpModule
|
|
(*Tsqlite3_vtab)(unsafe.Pointer((*Tsqlite3_vtab_cursor)(unsafe.Pointer(pVCur)).FpVtab)).FnRef = (*Tsqlite3_vtab)(unsafe.Pointer((*Tsqlite3_vtab_cursor)(unsafe.Pointer(pVCur)).FpVtab)).FnRef - 1
|
|
(*(*func(*libc.TLS, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{(*Tsqlite3_module)(unsafe.Pointer(pModule)).FxClose})))(tls, pVCur)
|
|
break
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return a pointer to an sqlite3_value structure containing the value bound
|
|
// ** parameter iVar of VM v. Except, if the value is an SQL NULL, return
|
|
// ** 0 instead. Unless it is NULL, apply affinity aff (one of the SQLITE_AFF_*
|
|
// ** constants) to the value before returning it.
|
|
// **
|
|
// ** The returned value must be freed by the caller using sqlite3ValueFree().
|
|
// */
|
|
func _sqlite3VdbeGetBoundValue(tls *libc.TLS, v uintptr, iVar int32, aff Tu8) (r uintptr) {
|
|
var pMem, pRet uintptr
|
|
_, _ = pMem, pRet
|
|
if v != 0 {
|
|
pMem = (*TVdbe)(unsafe.Pointer(v)).FaVar + uintptr(iVar-int32(1))*56
|
|
if 0 == libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&int32(MEM_Null) {
|
|
pRet = _sqlite3ValueNew(tls, (*TVdbe)(unsafe.Pointer(v)).Fdb)
|
|
if pRet != 0 {
|
|
_sqlite3VdbeMemCopy(tls, pRet, pMem)
|
|
_sqlite3ValueApplyAffinity(tls, pRet, aff, uint8(SQLITE_UTF8))
|
|
}
|
|
return pRet
|
|
}
|
|
}
|
|
return uintptr(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine is called the when a VDBE tries to halt. If the VDBE
|
|
// ** has made changes and is in autocommit mode, then commit those
|
|
// ** changes. If a rollback is needed, then do the rollback.
|
|
// **
|
|
// ** This routine is the only way to move the sqlite3eOpenState of a VM from
|
|
// ** SQLITE_STATE_RUN to SQLITE_STATE_HALT. It is harmless to
|
|
// ** call this on a VM that is in the SQLITE_STATE_HALT state.
|
|
// **
|
|
// ** Return an error code. If the commit could not complete because of
|
|
// ** lock contention, return SQLITE_BUSY. If SQLITE_BUSY is returned, it
|
|
// ** means the close did not happen and needs to be repeated.
|
|
// */
|
|
func _sqlite3VdbeHalt(tls *libc.TLS, p uintptr) (r int32) {
|
|
var db uintptr
|
|
var eStatementOp, isSpecialError, mrc, rc, v1 int32
|
|
_, _, _, _, _, _ = db, eStatementOp, isSpecialError, mrc, rc, v1 /* Used to store transient return codes */
|
|
db = (*TVdbe)(unsafe.Pointer(p)).Fdb
|
|
/* This function contains the logic that determines if a statement or
|
|
** transaction will be committed or rolled back as a result of the
|
|
** execution of this virtual machine.
|
|
**
|
|
** If any of the following errors occur:
|
|
**
|
|
** SQLITE_NOMEM
|
|
** SQLITE_IOERR
|
|
** SQLITE_FULL
|
|
** SQLITE_INTERRUPT
|
|
**
|
|
** Then the internal cache might have been left in an inconsistent
|
|
** state. We need to rollback the statement transaction, if there is
|
|
** one, or the complete transaction if there is no statement transaction.
|
|
*/
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0 {
|
|
(*TVdbe)(unsafe.Pointer(p)).Frc = int32(SQLITE_NOMEM)
|
|
}
|
|
_closeAllCursors(tls, p)
|
|
/* No commit or rollback needed if the program never started or if the
|
|
** SQL statement does not read or write a database file. */
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0x80>>7)) != 0 { /* Primary error code from p->rc */
|
|
eStatementOp = 0 /* Set to true if a 'special' error */
|
|
/* Lock all btrees used by the statement */
|
|
_sqlite3VdbeEnter(tls, p)
|
|
/* Check for one of the special errors */
|
|
if (*TVdbe)(unsafe.Pointer(p)).Frc != 0 {
|
|
mrc = (*TVdbe)(unsafe.Pointer(p)).Frc & int32(0xff)
|
|
isSpecialError = libc.BoolInt32(mrc == int32(SQLITE_NOMEM) || mrc == int32(SQLITE_IOERR) || mrc == int32(SQLITE_INTERRUPT) || mrc == int32(SQLITE_FULL))
|
|
} else {
|
|
v1 = libc.Int32FromInt32(0)
|
|
isSpecialError = v1
|
|
mrc = v1
|
|
}
|
|
if isSpecialError != 0 {
|
|
/* If the query was read-only and the error code is SQLITE_INTERRUPT,
|
|
** no rollback is necessary. Otherwise, at least a savepoint
|
|
** transaction must be rolled back to restore the database to a
|
|
** consistent state.
|
|
**
|
|
** Even if the statement is read-only, it is important to perform
|
|
** a statement or transaction rollback operation. If the error
|
|
** occurred while writing to the journal, sub-journal or database
|
|
** file as part of an effort to free up cache space (see function
|
|
** pagerStress() in pager.c), the rollback is required to restore
|
|
** the pager to a consistent state.
|
|
*/
|
|
if !(int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0x40>>6)) != 0) || mrc != int32(SQLITE_INTERRUPT) {
|
|
if (mrc == int32(SQLITE_NOMEM) || mrc == int32(SQLITE_FULL)) && int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0x20>>5)) != 0 {
|
|
eStatementOp = int32(SAVEPOINT_ROLLBACK)
|
|
} else {
|
|
/* We are forced to roll back the active transaction. Before doing
|
|
** so, abort any other statements this handle currently has active.
|
|
*/
|
|
_sqlite3RollbackAll(tls, db, libc.Int32FromInt32(SQLITE_ABORT)|libc.Int32FromInt32(2)<<libc.Int32FromInt32(8))
|
|
_sqlite3CloseSavepoints(tls, db)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FautoCommit = uint8(1)
|
|
(*TVdbe)(unsafe.Pointer(p)).FnChange = 0
|
|
}
|
|
}
|
|
}
|
|
/* Check for immediate foreign key violations. */
|
|
if (*TVdbe)(unsafe.Pointer(p)).Frc == SQLITE_OK || libc.Int32FromUint8((*TVdbe)(unsafe.Pointer(p)).FerrorAction) == int32(OE_Fail) && !(isSpecialError != 0) {
|
|
_sqlite3VdbeCheckFkImmediate(tls, p)
|
|
}
|
|
/* If the auto-commit flag is set and this is the only active writer
|
|
** VM, then we do either a commit or rollback of the current transaction.
|
|
**
|
|
** Note: This block also runs if one of the special errors handled
|
|
** above has occurred.
|
|
*/
|
|
if !((*Tsqlite3)(unsafe.Pointer(db)).FnVTrans > 0 && (*Tsqlite3)(unsafe.Pointer(db)).FaVTrans == uintptr(0)) && (*Tsqlite3)(unsafe.Pointer(db)).FautoCommit != 0 && (*Tsqlite3)(unsafe.Pointer(db)).FnVdbeWrite == libc.BoolInt32(int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0x40>>6)) == 0) {
|
|
if (*TVdbe)(unsafe.Pointer(p)).Frc == SQLITE_OK || libc.Int32FromUint8((*TVdbe)(unsafe.Pointer(p)).FerrorAction) == int32(OE_Fail) && !(isSpecialError != 0) {
|
|
rc = _sqlite3VdbeCheckFkDeferred(tls, p)
|
|
if rc != SQLITE_OK {
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0x40>>6)) != 0 {
|
|
_sqlite3VdbeLeave(tls, p)
|
|
return int32(SQLITE_ERROR)
|
|
}
|
|
rc = libc.Int32FromInt32(SQLITE_CONSTRAINT) | libc.Int32FromInt32(3)<<libc.Int32FromInt32(8)
|
|
} else {
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).Fflags&(libc.Uint64FromInt32(libc.Int32FromInt32(0x00002))<<libc.Int32FromInt32(32)) != 0 {
|
|
rc = int32(SQLITE_CORRUPT)
|
|
**(**Tu64)(__ccgo_up(db + 48)) &= ^(libc.Uint64FromInt32(libc.Int32FromInt32(0x00002)) << libc.Int32FromInt32(32))
|
|
} else {
|
|
/* The auto-commit flag is true, the vdbe program was successful
|
|
** or hit an 'OR FAIL' constraint and there are no deferred foreign
|
|
** key constraints to hold up the transaction. This means a commit
|
|
** is required. */
|
|
rc = _vdbeCommit(tls, db, p)
|
|
}
|
|
}
|
|
if rc == int32(SQLITE_BUSY) && int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0x40>>6)) != 0 {
|
|
_sqlite3VdbeLeave(tls, p)
|
|
return int32(SQLITE_BUSY)
|
|
} else {
|
|
if rc != SQLITE_OK {
|
|
_sqlite3SystemError(tls, db, rc)
|
|
(*TVdbe)(unsafe.Pointer(p)).Frc = rc
|
|
_sqlite3RollbackAll(tls, db, SQLITE_OK)
|
|
(*TVdbe)(unsafe.Pointer(p)).FnChange = 0
|
|
} else {
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FnDeferredCons = 0
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FnDeferredImmCons = 0
|
|
**(**Tu64)(__ccgo_up(db + 48)) &= ^libc.Uint64FromInt32(SQLITE_DeferFKs)
|
|
_sqlite3CommitInternalChanges(tls, db)
|
|
}
|
|
}
|
|
} else {
|
|
if (*TVdbe)(unsafe.Pointer(p)).Frc == int32(SQLITE_SCHEMA) && (*Tsqlite3)(unsafe.Pointer(db)).FnVdbeActive > int32(1) {
|
|
(*TVdbe)(unsafe.Pointer(p)).FnChange = 0
|
|
} else {
|
|
_sqlite3RollbackAll(tls, db, SQLITE_OK)
|
|
(*TVdbe)(unsafe.Pointer(p)).FnChange = 0
|
|
}
|
|
}
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FnStatement = 0
|
|
} else {
|
|
if eStatementOp == 0 {
|
|
if (*TVdbe)(unsafe.Pointer(p)).Frc == SQLITE_OK || libc.Int32FromUint8((*TVdbe)(unsafe.Pointer(p)).FerrorAction) == int32(OE_Fail) {
|
|
eStatementOp = int32(SAVEPOINT_RELEASE)
|
|
} else {
|
|
if libc.Int32FromUint8((*TVdbe)(unsafe.Pointer(p)).FerrorAction) == int32(OE_Abort) {
|
|
eStatementOp = int32(SAVEPOINT_ROLLBACK)
|
|
} else {
|
|
_sqlite3RollbackAll(tls, db, libc.Int32FromInt32(SQLITE_ABORT)|libc.Int32FromInt32(2)<<libc.Int32FromInt32(8))
|
|
_sqlite3CloseSavepoints(tls, db)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FautoCommit = uint8(1)
|
|
(*TVdbe)(unsafe.Pointer(p)).FnChange = 0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* If eStatementOp is non-zero, then a statement transaction needs to
|
|
** be committed or rolled back. Call sqlite3VdbeCloseStatement() to
|
|
** do so. If this operation returns an error, and the current statement
|
|
** error code is SQLITE_OK or SQLITE_CONSTRAINT, then promote the
|
|
** current statement error code.
|
|
*/
|
|
if eStatementOp != 0 {
|
|
rc = _sqlite3VdbeCloseStatement(tls, p, eStatementOp)
|
|
if rc != 0 {
|
|
if (*TVdbe)(unsafe.Pointer(p)).Frc == SQLITE_OK || (*TVdbe)(unsafe.Pointer(p)).Frc&int32(0xff) == int32(SQLITE_CONSTRAINT) {
|
|
(*TVdbe)(unsafe.Pointer(p)).Frc = rc
|
|
_sqlite3DbFree(tls, db, (*TVdbe)(unsafe.Pointer(p)).FzErrMsg)
|
|
(*TVdbe)(unsafe.Pointer(p)).FzErrMsg = uintptr(0)
|
|
}
|
|
_sqlite3RollbackAll(tls, db, libc.Int32FromInt32(SQLITE_ABORT)|libc.Int32FromInt32(2)<<libc.Int32FromInt32(8))
|
|
_sqlite3CloseSavepoints(tls, db)
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FautoCommit = uint8(1)
|
|
(*TVdbe)(unsafe.Pointer(p)).FnChange = 0
|
|
}
|
|
}
|
|
/* If this was an INSERT, UPDATE or DELETE and no statement transaction
|
|
** has been rolled back, update the database connection change-counter.
|
|
*/
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0x10>>4)) != 0 {
|
|
if eStatementOp != int32(SAVEPOINT_ROLLBACK) {
|
|
_sqlite3VdbeSetChanges(tls, db, (*TVdbe)(unsafe.Pointer(p)).FnChange)
|
|
} else {
|
|
_sqlite3VdbeSetChanges(tls, db, 0)
|
|
}
|
|
(*TVdbe)(unsafe.Pointer(p)).FnChange = 0
|
|
}
|
|
/* Release the locks */
|
|
_sqlite3VdbeLeave(tls, p)
|
|
}
|
|
/* We have successfully halted and closed the VM. Record this fact. */
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FnVdbeActive = (*Tsqlite3)(unsafe.Pointer(db)).FnVdbeActive - 1
|
|
if !(int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0x40>>6)) != 0) {
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FnVdbeWrite = (*Tsqlite3)(unsafe.Pointer(db)).FnVdbeWrite - 1
|
|
}
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0x80>>7)) != 0 {
|
|
(*Tsqlite3)(unsafe.Pointer(db)).FnVdbeRead = (*Tsqlite3)(unsafe.Pointer(db)).FnVdbeRead - 1
|
|
}
|
|
(*TVdbe)(unsafe.Pointer(p)).FeVdbeState = uint8(VDBE_HALT_STATE)
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0 {
|
|
(*TVdbe)(unsafe.Pointer(p)).Frc = int32(SQLITE_NOMEM)
|
|
}
|
|
/* If the auto-commit flag is set to true, then any locks that were held
|
|
** by connection db have now been released. Call sqlite3ConnectionUnlocked()
|
|
** to invoke any required unlock-notify callbacks.
|
|
*/
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FautoCommit != 0 {
|
|
_sqlite3ConnectionUnlocked(tls, db)
|
|
}
|
|
if (*TVdbe)(unsafe.Pointer(p)).Frc == int32(SQLITE_BUSY) {
|
|
v1 = int32(SQLITE_BUSY)
|
|
} else {
|
|
v1 = SQLITE_OK
|
|
}
|
|
return v1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compare the key of the index entry that cursor pC is pointing to against
|
|
// ** the key string in pUnpacked. Write into *pRes a number
|
|
// ** that is negative, zero, or positive if pC is less than, equal to,
|
|
// ** or greater than pUnpacked. Return SQLITE_OK on success.
|
|
// **
|
|
// ** pUnpacked is either created without a rowid or is truncated so that it
|
|
// ** omits the rowid at the end. The rowid at the end of the index entry
|
|
// ** is ignored as well. Hence, this routine only compares the prefixes
|
|
// ** of the keys prior to the final rowid, not the entire key.
|
|
// */
|
|
func _sqlite3VdbeIdxKeyCompare(tls *libc.TLS, db uintptr, pC uintptr, pUnpacked uintptr, res uintptr) (r int32) {
|
|
bp := tls.Alloc(64)
|
|
defer tls.Free(64)
|
|
var nCellKey Ti64
|
|
var pCur uintptr
|
|
var rc int32
|
|
var _ /* m at bp+0 */ TMem
|
|
_, _, _ = nCellKey, pCur, rc
|
|
nCellKey = 0
|
|
pCur = *(*uintptr)(unsafe.Pointer(pC + 48))
|
|
nCellKey = libc.Int64FromUint32(_sqlite3BtreePayloadSize(tls, pCur))
|
|
/* nCellKey will always be between 0 and 0xffffffff because of the way
|
|
** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */
|
|
if nCellKey <= 0 || nCellKey > int64(0x7fffffff) {
|
|
**(**int32)(__ccgo_up(res)) = 0
|
|
return _sqlite3CorruptError(tls, int32(93164))
|
|
}
|
|
_sqlite3VdbeMemInit(tls, bp, db, uint16(0))
|
|
rc = _sqlite3VdbeMemFromBtreeZeroOffset(tls, pCur, libc.Uint32FromInt64(nCellKey), bp)
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
**(**int32)(__ccgo_up(res)) = _sqlite3VdbeRecordCompareWithSkip(tls, (**(**TMem)(__ccgo_up(bp))).Fn, (**(**TMem)(__ccgo_up(bp))).Fz, pUnpacked, 0)
|
|
_sqlite3VdbeMemReleaseMalloc(tls, bp)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** pCur points at an index entry created using the OP_MakeRecord opcode.
|
|
// ** Read the rowid (the last field in the record) and store it in *rowid.
|
|
// ** Return SQLITE_OK if everything works, or an error code otherwise.
|
|
// **
|
|
// ** pCur might be pointing to text obtained from a corrupt database file.
|
|
// ** So the content cannot be trusted. Do appropriate checks on the content.
|
|
// */
|
|
func _sqlite3VdbeIdxRowid(tls *libc.TLS, db uintptr, pCur uintptr, rowid uintptr) (r int32) {
|
|
bp := tls.Alloc(128)
|
|
defer tls.Free(128)
|
|
var lenRowid Tu32
|
|
var nCellKey Ti64
|
|
var rc int32
|
|
var _ /* m at bp+8 */ TMem
|
|
var _ /* szHdr at bp+0 */ Tu32
|
|
var _ /* typeRowid at bp+4 */ Tu32
|
|
var _ /* v at bp+64 */ TMem
|
|
_, _, _ = lenRowid, nCellKey, rc
|
|
nCellKey = 0
|
|
/* Get the size of the index entry. Only indices entries of less
|
|
** than 2GiB are support - anything large must be database corruption.
|
|
** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so
|
|
** this code can safely assume that nCellKey is 32-bits
|
|
*/
|
|
nCellKey = libc.Int64FromUint32(_sqlite3BtreePayloadSize(tls, pCur))
|
|
/* Read in the complete content of the index entry */
|
|
_sqlite3VdbeMemInit(tls, bp+8, db, uint16(0))
|
|
rc = _sqlite3VdbeMemFromBtreeZeroOffset(tls, pCur, libc.Uint32FromInt64(nCellKey), bp+8)
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
/* The index entry must begin with a header size */
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(**(**Tu8)(__ccgo_up((**(**TMem)(__ccgo_up(bp + 8))).Fz)))
|
|
if **(**Tu32)(__ccgo_up(bp)) >= uint32(0x80) {
|
|
_sqlite3GetVarint32(tls, (**(**TMem)(__ccgo_up(bp + 8))).Fz, bp)
|
|
}
|
|
if **(**Tu32)(__ccgo_up(bp)) < uint32(3) || **(**Tu32)(__ccgo_up(bp)) > libc.Uint32FromInt32((**(**TMem)(__ccgo_up(bp + 8))).Fn) {
|
|
goto idx_rowid_corruption
|
|
}
|
|
/* The last field of the index should be an integer - the ROWID.
|
|
** Verify that the last entry really is an integer. */
|
|
**(**Tu32)(__ccgo_up(bp + 4)) = uint32(**(**Tu8)(__ccgo_up((**(**TMem)(__ccgo_up(bp + 8))).Fz + uintptr(**(**Tu32)(__ccgo_up(bp))-uint32(1)))))
|
|
if **(**Tu32)(__ccgo_up(bp + 4)) >= uint32(0x80) {
|
|
_sqlite3GetVarint32(tls, (**(**TMem)(__ccgo_up(bp + 8))).Fz+uintptr(**(**Tu32)(__ccgo_up(bp))-uint32(1)), bp+4)
|
|
}
|
|
if **(**Tu32)(__ccgo_up(bp + 4)) < uint32(1) || **(**Tu32)(__ccgo_up(bp + 4)) > uint32(9) || **(**Tu32)(__ccgo_up(bp + 4)) == uint32(7) {
|
|
goto idx_rowid_corruption
|
|
}
|
|
lenRowid = uint32(_sqlite3SmallTypeSizes[**(**Tu32)(__ccgo_up(bp + 4))])
|
|
if libc.Uint32FromInt32((**(**TMem)(__ccgo_up(bp + 8))).Fn) < **(**Tu32)(__ccgo_up(bp))+lenRowid {
|
|
goto idx_rowid_corruption
|
|
}
|
|
/* Fetch the integer off the end of the index record */
|
|
_sqlite3VdbeSerialGet(tls, (**(**TMem)(__ccgo_up(bp + 8))).Fz+uintptr(libc.Uint32FromInt32((**(**TMem)(__ccgo_up(bp + 8))).Fn)-lenRowid), **(**Tu32)(__ccgo_up(bp + 4)), bp+64)
|
|
**(**Ti64)(__ccgo_up(rowid)) = *(*Ti64)(unsafe.Pointer(bp + 64))
|
|
_sqlite3VdbeMemReleaseMalloc(tls, bp+8)
|
|
return SQLITE_OK
|
|
/* Jump here if database corruption is detected after m has been
|
|
** allocated. Free the m object and return SQLITE_CORRUPT. */
|
|
goto idx_rowid_corruption
|
|
idx_rowid_corruption:
|
|
;
|
|
_sqlite3VdbeMemReleaseMalloc(tls, bp+8)
|
|
return _sqlite3CorruptError(tls, int32(93131))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Give a listing of the program in the virtual machine.
|
|
// **
|
|
// ** The interface is the same as sqlite3VdbeExec(). But instead of
|
|
// ** running the code, it invokes the callback once for each instruction.
|
|
// ** This feature is used to implement "EXPLAIN".
|
|
// **
|
|
// ** When p->explain==1, each instruction is listed. When
|
|
// ** p->explain==2, only OP_Explain instructions are listed and these
|
|
// ** are shown in a different format. p->explain==2 is used to implement
|
|
// ** EXPLAIN QUERY PLAN.
|
|
// ** 2018-04-24: In p->explain==2 mode, the OP_Init opcodes of triggers
|
|
// ** are also shown, so that the boundaries between the main program and
|
|
// ** each trigger are clear.
|
|
// **
|
|
// ** When p->explain==1, first the main program is listed, then each of
|
|
// ** the trigger subprograms are listed one by one.
|
|
// */
|
|
func _sqlite3VdbeList(tls *libc.TLS, p uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var bListSubprogs, rc int32
|
|
var db, pMem, pOp, pSub, zP4 uintptr
|
|
var _ /* aOp at bp+8 */ uintptr
|
|
var _ /* i at bp+0 */ int32
|
|
_, _, _, _, _, _, _ = bListSubprogs, db, pMem, pOp, pSub, rc, zP4
|
|
pSub = uintptr(0) /* Memory cell hold array of subprogs */
|
|
db = (*TVdbe)(unsafe.Pointer(p)).Fdb /* Loop counter */
|
|
rc = SQLITE_OK /* Return code */
|
|
pMem = (*TVdbe)(unsafe.Pointer(p)).FaMem + 1*56 /* First Mem of result set */
|
|
bListSubprogs = libc.BoolInt32(int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0xc>>2)) == int32(1) || (*Tsqlite3)(unsafe.Pointer(db)).Fflags&uint64(SQLITE_TriggerEQP) != uint64(0)) /* Current opcode */
|
|
/* Even though this opcode does not use dynamic strings for
|
|
** the result, result columns may become dynamic if the user calls
|
|
** sqlite3_column_text16(), causing a translation to UTF-16 encoding.
|
|
*/
|
|
_releaseMemArray(tls, pMem, int32(8))
|
|
if (*TVdbe)(unsafe.Pointer(p)).Frc == int32(SQLITE_NOMEM) {
|
|
/* This happens if a malloc() inside a call to sqlite3_column_text() or
|
|
** sqlite3_column_text16() failed. */
|
|
_sqlite3OomFault(tls, db)
|
|
return int32(SQLITE_ERROR)
|
|
}
|
|
if bListSubprogs != 0 {
|
|
/* The first 8 memory cells are used for the result set. So we will
|
|
** commandeer the 9th cell to use as storage for an array of pointers
|
|
** to trigger subprograms. The VDBE is guaranteed to have at least 9
|
|
** cells. */
|
|
pSub = (*TVdbe)(unsafe.Pointer(p)).FaMem + 9*56
|
|
} else {
|
|
pSub = uintptr(0)
|
|
}
|
|
/* Figure out which opcode is next to display */
|
|
rc = _sqlite3VdbeNextOpcode(tls, p, pSub, libc.BoolInt32(int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0xc>>2)) == int32(2)), p+48, bp, bp+8)
|
|
if rc == SQLITE_OK {
|
|
pOp = **(**uintptr)(__ccgo_up(bp + 8)) + uintptr(**(**int32)(__ccgo_up(bp)))*24
|
|
if libc.AtomicLoadNInt32(db+432, libc.Int32FromInt32(__ATOMIC_RELAXED)) != 0 {
|
|
(*TVdbe)(unsafe.Pointer(p)).Frc = int32(SQLITE_INTERRUPT)
|
|
rc = int32(SQLITE_ERROR)
|
|
_sqlite3VdbeError(tls, p, _sqlite3ErrStr(tls, (*TVdbe)(unsafe.Pointer(p)).Frc), 0)
|
|
} else {
|
|
zP4 = _sqlite3VdbeDisplayP4(tls, db, pOp)
|
|
if int32(Tbft(*(*uint16)(unsafe.Pointer(p + 200))&0xc>>2)) == int32(2) {
|
|
_sqlite3VdbeMemSetInt64(tls, pMem, int64((*TOp)(unsafe.Pointer(pOp)).Fp1))
|
|
_sqlite3VdbeMemSetInt64(tls, pMem+uintptr(1)*56, int64((*TOp)(unsafe.Pointer(pOp)).Fp2))
|
|
_sqlite3VdbeMemSetInt64(tls, pMem+uintptr(2)*56, int64((*TOp)(unsafe.Pointer(pOp)).Fp3))
|
|
_sqlite3VdbeMemSetStr(tls, pMem+uintptr(3)*56, zP4, int64(-int32(1)), uint8(SQLITE_UTF8), __ccgo_fp(Xsqlite3_free))
|
|
} else {
|
|
_sqlite3VdbeMemSetInt64(tls, pMem+uintptr(0)*56, int64(**(**int32)(__ccgo_up(bp))))
|
|
_sqlite3VdbeMemSetStr(tls, pMem+uintptr(1)*56, _sqlite3OpcodeName(tls, libc.Int32FromUint8((*TOp)(unsafe.Pointer(pOp)).Fopcode)), int64(-int32(1)), uint8(SQLITE_UTF8), libc.UintptrFromInt32(0))
|
|
_sqlite3VdbeMemSetInt64(tls, pMem+uintptr(2)*56, int64((*TOp)(unsafe.Pointer(pOp)).Fp1))
|
|
_sqlite3VdbeMemSetInt64(tls, pMem+uintptr(3)*56, int64((*TOp)(unsafe.Pointer(pOp)).Fp2))
|
|
_sqlite3VdbeMemSetInt64(tls, pMem+uintptr(4)*56, int64((*TOp)(unsafe.Pointer(pOp)).Fp3))
|
|
/* pMem+5 for p4 is done last */
|
|
_sqlite3VdbeMemSetInt64(tls, pMem+uintptr(6)*56, libc.Int64FromUint16((*TOp)(unsafe.Pointer(pOp)).Fp5))
|
|
_sqlite3VdbeMemSetNull(tls, pMem+uintptr(7)*56)
|
|
_sqlite3VdbeMemSetStr(tls, pMem+uintptr(5)*56, zP4, int64(-int32(1)), uint8(SQLITE_UTF8), __ccgo_fp(Xsqlite3_free))
|
|
}
|
|
(*TVdbe)(unsafe.Pointer(p)).FpResultRow = pMem
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0 {
|
|
(*TVdbe)(unsafe.Pointer(p)).Frc = int32(SQLITE_NOMEM)
|
|
rc = int32(SQLITE_ERROR)
|
|
} else {
|
|
(*TVdbe)(unsafe.Pointer(p)).Frc = SQLITE_OK
|
|
rc = int32(SQLITE_ROW)
|
|
}
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Cast the datatype of the value in pMem according to the affinity
|
|
// ** "aff". Casting is different from applying affinity in that a cast
|
|
// ** is forced. In other words, the value is converted into the desired
|
|
// ** affinity even if that results in loss of data. This routine is
|
|
// ** used (for example) to implement the SQL "cast()" operator.
|
|
// */
|
|
func _sqlite3VdbeMemCast(tls *libc.TLS, pMem uintptr, aff Tu8, encoding Tu8) (r int32) {
|
|
var rc int32
|
|
var v1 uintptr
|
|
_, _ = rc, v1
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&int32(MEM_Null) != 0 {
|
|
return SQLITE_OK
|
|
}
|
|
switch libc.Int32FromUint8(aff) {
|
|
case int32(SQLITE_AFF_BLOB): /* Really a cast to BLOB */
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&int32(MEM_Blob) == 0 {
|
|
_sqlite3ValueApplyAffinity(tls, pMem, uint8(SQLITE_AFF_TEXT), encoding)
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&int32(MEM_Str) != 0 {
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = libc.Uint16FromInt32(libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags) & ^(libc.Int32FromInt32(MEM_TypeMask)|libc.Int32FromInt32(MEM_Zero)) | int32(MEM_Blob))
|
|
}
|
|
} else {
|
|
v1 = pMem + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) & ^(libc.Int32FromInt32(MEM_TypeMask) & ^libc.Int32FromInt32(MEM_Blob)))
|
|
}
|
|
case int32(SQLITE_AFF_NUMERIC):
|
|
_sqlite3VdbeMemNumerify(tls, pMem)
|
|
case int32(SQLITE_AFF_INTEGER):
|
|
_sqlite3VdbeMemIntegerify(tls, pMem)
|
|
case int32(SQLITE_AFF_REAL):
|
|
_sqlite3VdbeMemRealify(tls, pMem)
|
|
default:
|
|
v1 = pMem + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&libc.Int32FromInt32(MEM_Blob)>>libc.Int32FromInt32(3))
|
|
_sqlite3ValueApplyAffinity(tls, pMem, uint8(SQLITE_AFF_TEXT), encoding)
|
|
v1 = pMem + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) & ^(libc.Int32FromInt32(MEM_Int) | libc.Int32FromInt32(MEM_Real) | libc.Int32FromInt32(MEM_IntReal) | libc.Int32FromInt32(MEM_Blob) | libc.Int32FromInt32(MEM_Zero)))
|
|
if libc.Int32FromUint8(encoding) != int32(SQLITE_UTF8) {
|
|
**(**int32)(__ccgo_up(pMem + 16)) &= ^libc.Int32FromInt32(1)
|
|
}
|
|
rc = _sqlite3VdbeChangeEncoding(tls, pMem, libc.Int32FromUint8(encoding))
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
_sqlite3VdbeMemZeroTerminateIfAble(tls, pMem)
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Change pMem so that its MEM_Str or MEM_Blob value is stored in
|
|
// ** MEM.zMalloc, where it can be safely written.
|
|
// **
|
|
// ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
|
|
// */
|
|
func _sqlite3VdbeMemMakeWriteable(tls *libc.TLS, pMem uintptr) (r int32) {
|
|
var rc, v1 int32
|
|
var v2 uintptr
|
|
_, _, _ = rc, v1, v2
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&(libc.Int32FromInt32(MEM_Str)|libc.Int32FromInt32(MEM_Blob)) != 0 {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&int32(MEM_Zero) != 0 {
|
|
v1 = _sqlite3VdbeMemExpandBlob(tls, pMem)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
if v1 != 0 {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
if (*TMem)(unsafe.Pointer(pMem)).FszMalloc == 0 || (*TMem)(unsafe.Pointer(pMem)).Fz != (*TMem)(unsafe.Pointer(pMem)).FzMalloc {
|
|
rc = _vdbeMemAddTerminator(tls, pMem)
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
}
|
|
}
|
|
v2 = pMem + 20
|
|
*(*Tu16)(unsafe.Pointer(v2)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v2))) & ^libc.Int32FromInt32(MEM_Ephem))
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Convert pMem so that it has type MEM_Real or MEM_Int.
|
|
// ** Invalidate any prior representations.
|
|
// **
|
|
// ** Every effort is made to force the conversion, even if the input
|
|
// ** is a string that does not look completely like a number. Convert
|
|
// ** as much of the string as we can and ignore the rest.
|
|
// */
|
|
func _sqlite3VdbeMemNumerify(tls *libc.TLS, pMem uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var rc int32
|
|
var v1 Tsqlite3_int64
|
|
var v2 bool
|
|
var v3 uintptr
|
|
var _ /* ix at bp+0 */ Tsqlite3_int64
|
|
_, _, _, _ = rc, v1, v2, v3
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&(libc.Int32FromInt32(MEM_Int)|libc.Int32FromInt32(MEM_Real)|libc.Int32FromInt32(MEM_IntReal)|libc.Int32FromInt32(MEM_Null)) == 0 {
|
|
rc = _sqlite3MemRealValueRC(tls, pMem, pMem)
|
|
if v2 = rc&int32(2) == 0 && _sqlite3Atoi64(tls, (*TMem)(unsafe.Pointer(pMem)).Fz, bp, (*TMem)(unsafe.Pointer(pMem)).Fn, (*TMem)(unsafe.Pointer(pMem)).Fenc) < int32(2); !v2 {
|
|
v1 = _sqlite3RealToI64(tls, *(*float64)(unsafe.Pointer(pMem)))
|
|
**(**Tsqlite3_int64)(__ccgo_up(bp)) = v1
|
|
}
|
|
if v2 || _sqlite3RealSameAsInt(tls, *(*float64)(unsafe.Pointer(pMem)), v1) != 0 {
|
|
*(*Ti64)(unsafe.Pointer(pMem)) = **(**Tsqlite3_int64)(__ccgo_up(bp))
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = libc.Uint16FromInt32(libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags) & ^(libc.Int32FromInt32(MEM_TypeMask)|libc.Int32FromInt32(MEM_Zero)) | int32(MEM_Int))
|
|
} else {
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = libc.Uint16FromInt32(libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags) & ^(libc.Int32FromInt32(MEM_TypeMask)|libc.Int32FromInt32(MEM_Zero)) | int32(MEM_Real))
|
|
}
|
|
}
|
|
v3 = pMem + 20
|
|
*(*Tu16)(unsafe.Pointer(v3)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v3))) & ^(libc.Int32FromInt32(MEM_Str) | libc.Int32FromInt32(MEM_Blob) | libc.Int32FromInt32(MEM_Zero)))
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add MEM_Str to the set of representations for the given Mem. This
|
|
// ** routine is only called if pMem is a number of some kind, not a NULL
|
|
// ** or a BLOB.
|
|
// **
|
|
// ** Existing representations MEM_Int, MEM_Real, or MEM_IntReal are invalidated
|
|
// ** if bForce is true but are retained if bForce is false.
|
|
// **
|
|
// ** A MEM_Null value will never be passed to this function. This function is
|
|
// ** used for converting values to text for returning to the user (i.e. via
|
|
// ** sqlite3_value_text()), or for ensuring that values to be used as btree
|
|
// ** keys are strings. In the former case a NULL pointer is returned the
|
|
// ** user and the latter is an internal programming error.
|
|
// */
|
|
func _sqlite3VdbeMemStringify(tls *libc.TLS, pMem uintptr, enc Tu8, bForce Tu8) (r int32) {
|
|
var nByte int32
|
|
var v1 uintptr
|
|
_, _ = nByte, v1
|
|
nByte = int32(32)
|
|
if _sqlite3VdbeMemClearAndResize(tls, pMem, nByte) != 0 {
|
|
(*TMem)(unsafe.Pointer(pMem)).Fenc = uint8(0)
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
_vdbeMemRenderNum(tls, nByte, (*TMem)(unsafe.Pointer(pMem)).Fz, pMem)
|
|
(*TMem)(unsafe.Pointer(pMem)).Fenc = uint8(SQLITE_UTF8)
|
|
v1 = pMem + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) | (libc.Int32FromInt32(MEM_Str) | libc.Int32FromInt32(MEM_Term)))
|
|
if bForce != 0 {
|
|
v1 = pMem + 20
|
|
*(*Tu16)(unsafe.Pointer(v1)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v1))) & ^(libc.Int32FromInt32(MEM_Int) | libc.Int32FromInt32(MEM_Real) | libc.Int32FromInt32(MEM_IntReal)))
|
|
}
|
|
_sqlite3VdbeChangeEncoding(tls, pMem, libc.Int32FromUint8(enc))
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return true if the Mem object contains a TEXT or BLOB that is
|
|
// ** too large - whose size exceeds SQLITE_MAX_LENGTH.
|
|
// */
|
|
func _sqlite3VdbeMemTooBig(tls *libc.TLS, p uintptr) (r int32) {
|
|
var n int32
|
|
_ = n
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&(libc.Int32FromInt32(MEM_Str)|libc.Int32FromInt32(MEM_Blob)) != 0 {
|
|
n = (*TMem)(unsafe.Pointer(p)).Fn
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&int32(MEM_Zero) != 0 {
|
|
n = n + *(*int32)(unsafe.Pointer(&(*TMem)(unsafe.Pointer(p)).Fu))
|
|
}
|
|
return libc.BoolInt32(n > **(**int32)(__ccgo_up((*TMem)(unsafe.Pointer(p)).Fdb + 136)))
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine transforms the internal text encoding used by pMem to
|
|
// ** desiredEnc. It is an error if the string is already of the desired
|
|
// ** encoding, or if *pMem does not contain a string value.
|
|
// */
|
|
func _sqlite3VdbeMemTranslate(tls *libc.TLS, pMem uintptr, desiredEnc Tu8) (r int32) {
|
|
var c uint32
|
|
var c2, c21, rc int32
|
|
var len1 Tsqlite3_int64
|
|
var temp Tu8
|
|
var z, zIn, zOut, zTerm, v1, v2 uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _, _ = c, c2, c21, len1, rc, temp, z, zIn, zOut, zTerm, v1, v2
|
|
/* If the translation is between UTF-16 little and big endian, then
|
|
** all that is required is to swap the byte order. This case is handled
|
|
** differently from the others.
|
|
*/
|
|
if libc.Int32FromUint8((*TMem)(unsafe.Pointer(pMem)).Fenc) != int32(SQLITE_UTF8) && libc.Int32FromUint8(desiredEnc) != int32(SQLITE_UTF8) {
|
|
rc = _sqlite3VdbeMemMakeWriteable(tls, pMem)
|
|
if rc != SQLITE_OK {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
zIn = (*TMem)(unsafe.Pointer(pMem)).Fz
|
|
zTerm = zIn + uintptr((*TMem)(unsafe.Pointer(pMem)).Fn & ^libc.Int32FromInt32(1))
|
|
for zIn < zTerm {
|
|
temp = **(**uint8)(__ccgo_up(zIn))
|
|
**(**uint8)(__ccgo_up(zIn)) = **(**uint8)(__ccgo_up(zIn + libc.UintptrFromInt32(1)))
|
|
zIn = zIn + 1
|
|
v1 = zIn
|
|
zIn = zIn + 1
|
|
**(**uint8)(__ccgo_up(v1)) = temp
|
|
}
|
|
(*TMem)(unsafe.Pointer(pMem)).Fenc = desiredEnc
|
|
goto translate_out
|
|
}
|
|
/* Set len to the maximum number of bytes required in the output buffer. */
|
|
if libc.Int32FromUint8(desiredEnc) == int32(SQLITE_UTF8) {
|
|
/* When converting from UTF-16, the maximum growth results from
|
|
** translating a 2-byte character to a 4-byte UTF-8 character.
|
|
** A single byte is required for the output string
|
|
** nul-terminator.
|
|
*/
|
|
**(**int32)(__ccgo_up(pMem + 16)) &= ^libc.Int32FromInt32(1)
|
|
len1 = int64(2)*int64((*TMem)(unsafe.Pointer(pMem)).Fn) + int64(1)
|
|
} else {
|
|
/* When converting from UTF-8 to UTF-16 the maximum growth is caused
|
|
** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16
|
|
** character. Two bytes are required in the output buffer for the
|
|
** nul-terminator.
|
|
*/
|
|
len1 = int64(2)*int64((*TMem)(unsafe.Pointer(pMem)).Fn) + int64(2)
|
|
}
|
|
/* Set zIn to point at the start of the input buffer and zTerm to point 1
|
|
** byte past the end.
|
|
**
|
|
** Variable zOut is set to point at the output buffer, space obtained
|
|
** from sqlite3_malloc().
|
|
*/
|
|
zIn = (*TMem)(unsafe.Pointer(pMem)).Fz
|
|
zTerm = zIn + uintptr((*TMem)(unsafe.Pointer(pMem)).Fn)
|
|
zOut = _sqlite3DbMallocRaw(tls, (*TMem)(unsafe.Pointer(pMem)).Fdb, libc.Uint64FromInt64(len1))
|
|
if !(zOut != 0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
z = zOut
|
|
if libc.Int32FromUint8((*TMem)(unsafe.Pointer(pMem)).Fenc) == int32(SQLITE_UTF8) {
|
|
if libc.Int32FromUint8(desiredEnc) == int32(SQLITE_UTF16LE) {
|
|
/* UTF-8 -> UTF-16 Little-endian */
|
|
for zIn < zTerm {
|
|
v1 = zIn
|
|
zIn = zIn + 1
|
|
c = uint32(**(**uint8)(__ccgo_up(v1)))
|
|
if c >= uint32(0xc0) {
|
|
c = uint32(_sqlite3Utf8Trans1[c-uint32(0xc0)])
|
|
for zIn < zTerm && libc.Int32FromUint8(**(**uint8)(__ccgo_up(zIn)))&int32(0xc0) == int32(0x80) {
|
|
v1 = zIn
|
|
zIn = zIn + 1
|
|
c = c<<int32(6) + libc.Uint32FromInt32(libc.Int32FromInt32(0x3f)&libc.Int32FromUint8(**(**uint8)(__ccgo_up(v1))))
|
|
}
|
|
if c < uint32(0x80) || c&uint32(0xFFFFF800) == uint32(0xD800) || c&uint32(0xFFFFFFFE) == uint32(0xFFFE) {
|
|
c = uint32(0xFFFD)
|
|
}
|
|
}
|
|
if c <= uint32(0xFFFF) {
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(c & libc.Uint32FromInt32(0x00FF))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(c >> libc.Int32FromInt32(8) & libc.Uint32FromInt32(0x00FF))
|
|
} else {
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(c>>libc.Int32FromInt32(10)&libc.Uint32FromInt32(0x003F) + (c-libc.Uint32FromInt32(0x10000))>>libc.Int32FromInt32(10)&libc.Uint32FromInt32(0x00C0))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(libc.Uint32FromInt32(0x00D8) + (c-libc.Uint32FromInt32(0x10000))>>libc.Int32FromInt32(18)&libc.Uint32FromInt32(0x03))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(c & libc.Uint32FromInt32(0x00FF))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(libc.Uint32FromInt32(0x00DC) + c>>libc.Int32FromInt32(8)&libc.Uint32FromInt32(0x03))
|
|
}
|
|
}
|
|
} else {
|
|
/* UTF-8 -> UTF-16 Big-endian */
|
|
for zIn < zTerm {
|
|
v1 = zIn
|
|
zIn = zIn + 1
|
|
c = uint32(**(**uint8)(__ccgo_up(v1)))
|
|
if c >= uint32(0xc0) {
|
|
c = uint32(_sqlite3Utf8Trans1[c-uint32(0xc0)])
|
|
for zIn < zTerm && libc.Int32FromUint8(**(**uint8)(__ccgo_up(zIn)))&int32(0xc0) == int32(0x80) {
|
|
v1 = zIn
|
|
zIn = zIn + 1
|
|
c = c<<int32(6) + libc.Uint32FromInt32(libc.Int32FromInt32(0x3f)&libc.Int32FromUint8(**(**uint8)(__ccgo_up(v1))))
|
|
}
|
|
if c < uint32(0x80) || c&uint32(0xFFFFF800) == uint32(0xD800) || c&uint32(0xFFFFFFFE) == uint32(0xFFFE) {
|
|
c = uint32(0xFFFD)
|
|
}
|
|
}
|
|
if c <= uint32(0xFFFF) {
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(c >> libc.Int32FromInt32(8) & libc.Uint32FromInt32(0x00FF))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(c & libc.Uint32FromInt32(0x00FF))
|
|
} else {
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(libc.Uint32FromInt32(0x00D8) + (c-libc.Uint32FromInt32(0x10000))>>libc.Int32FromInt32(18)&libc.Uint32FromInt32(0x03))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(c>>libc.Int32FromInt32(10)&libc.Uint32FromInt32(0x003F) + (c-libc.Uint32FromInt32(0x10000))>>libc.Int32FromInt32(10)&libc.Uint32FromInt32(0x00C0))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(libc.Uint32FromInt32(0x00DC) + c>>libc.Int32FromInt32(8)&libc.Uint32FromInt32(0x03))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(c & libc.Uint32FromInt32(0x00FF))
|
|
}
|
|
}
|
|
}
|
|
(*TMem)(unsafe.Pointer(pMem)).Fn = int32(int64(z) - int64(zOut))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(0)
|
|
} else {
|
|
if libc.Int32FromUint8((*TMem)(unsafe.Pointer(pMem)).Fenc) == int32(SQLITE_UTF16LE) {
|
|
/* UTF-16 Little-endian -> UTF-8 */
|
|
for zIn < zTerm {
|
|
v1 = zIn
|
|
zIn = zIn + 1
|
|
c = uint32(**(**uint8)(__ccgo_up(v1)))
|
|
v1 = zIn
|
|
zIn = zIn + 1
|
|
c = c + libc.Uint32FromInt32(libc.Int32FromUint8(**(**uint8)(__ccgo_up(v1)))<<int32(8))
|
|
if c >= uint32(0xd800) && c < uint32(0xe000) {
|
|
if zIn < zTerm {
|
|
v1 = zIn
|
|
zIn = zIn + 1
|
|
c2 = libc.Int32FromUint8(**(**uint8)(__ccgo_up(v1)))
|
|
v2 = zIn
|
|
zIn = zIn + 1
|
|
c2 = c2 + libc.Int32FromUint8(**(**uint8)(__ccgo_up(v2)))<<int32(8)
|
|
c = libc.Uint32FromInt32(c2&libc.Int32FromInt32(0x03FF)) + c&uint32(0x003F)<<int32(10) + (c&uint32(0x03C0)+uint32(0x0040))<<int32(10)
|
|
}
|
|
}
|
|
if c < uint32(0x00080) {
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(c & libc.Uint32FromInt32(0xFF))
|
|
} else {
|
|
if c < uint32(0x00800) {
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0xC0) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x1F))))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c&libc.Uint32FromInt32(0x3F))))
|
|
} else {
|
|
if c < uint32(0x10000) {
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0xE0) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(12)&libc.Uint32FromInt32(0x0F))))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x3F))))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c&libc.Uint32FromInt32(0x3F))))
|
|
} else {
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0xF0) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(18)&libc.Uint32FromInt32(0x07))))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(12)&libc.Uint32FromInt32(0x3F))))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x3F))))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c&libc.Uint32FromInt32(0x3F))))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
/* UTF-16 Big-endian -> UTF-8 */
|
|
for zIn < zTerm {
|
|
v1 = zIn
|
|
zIn = zIn + 1
|
|
c = libc.Uint32FromInt32(libc.Int32FromUint8(**(**uint8)(__ccgo_up(v1))) << int32(8))
|
|
v1 = zIn
|
|
zIn = zIn + 1
|
|
c = c + uint32(**(**uint8)(__ccgo_up(v1)))
|
|
if c >= uint32(0xd800) && c < uint32(0xe000) {
|
|
if zIn < zTerm {
|
|
v1 = zIn
|
|
zIn = zIn + 1
|
|
c21 = libc.Int32FromUint8(**(**uint8)(__ccgo_up(v1))) << int32(8)
|
|
v2 = zIn
|
|
zIn = zIn + 1
|
|
c21 = c21 + libc.Int32FromUint8(**(**uint8)(__ccgo_up(v2)))
|
|
c = libc.Uint32FromInt32(c21&libc.Int32FromInt32(0x03FF)) + c&uint32(0x003F)<<int32(10) + (c&uint32(0x03C0)+uint32(0x0040))<<int32(10)
|
|
}
|
|
}
|
|
if c < uint32(0x00080) {
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = uint8(c & libc.Uint32FromInt32(0xFF))
|
|
} else {
|
|
if c < uint32(0x00800) {
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0xC0) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x1F))))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c&libc.Uint32FromInt32(0x3F))))
|
|
} else {
|
|
if c < uint32(0x10000) {
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0xE0) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(12)&libc.Uint32FromInt32(0x0F))))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x3F))))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c&libc.Uint32FromInt32(0x3F))))
|
|
} else {
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0xF0) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(18)&libc.Uint32FromInt32(0x07))))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(12)&libc.Uint32FromInt32(0x3F))))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c>>libc.Int32FromInt32(6)&libc.Uint32FromInt32(0x3F))))
|
|
v1 = z
|
|
z = z + 1
|
|
**(**uint8)(__ccgo_up(v1)) = libc.Uint8FromInt32(int32(0x80) + libc.Int32FromUint8(uint8(c&libc.Uint32FromInt32(0x3F))))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
(*TMem)(unsafe.Pointer(pMem)).Fn = int32(int64(z) - int64(zOut))
|
|
}
|
|
**(**uint8)(__ccgo_up(z)) = uint8(0)
|
|
c = libc.Uint32FromInt32(libc.Int32FromInt32(MEM_Str) | libc.Int32FromInt32(MEM_Term) | libc.Int32FromUint16((*TMem)(unsafe.Pointer(pMem)).Fflags)&(libc.Int32FromInt32(MEM_AffMask)|libc.Int32FromInt32(MEM_Subtype)))
|
|
_sqlite3VdbeMemRelease(tls, pMem)
|
|
(*TMem)(unsafe.Pointer(pMem)).Fflags = uint16(c)
|
|
(*TMem)(unsafe.Pointer(pMem)).Fenc = desiredEnc
|
|
(*TMem)(unsafe.Pointer(pMem)).Fz = zOut
|
|
(*TMem)(unsafe.Pointer(pMem)).FzMalloc = (*TMem)(unsafe.Pointer(pMem)).Fz
|
|
(*TMem)(unsafe.Pointer(pMem)).FszMalloc = _sqlite3DbMallocSize(tls, (*TMem)(unsafe.Pointer(pMem)).Fdb, (*TMem)(unsafe.Pointer(pMem)).Fz)
|
|
goto translate_out
|
|
translate_out:
|
|
;
|
|
return SQLITE_OK
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Locate the next opcode to be displayed in EXPLAIN or EXPLAIN
|
|
// ** QUERY PLAN output.
|
|
// **
|
|
// ** Return SQLITE_ROW on success. Return SQLITE_DONE if there are no
|
|
// ** more opcodes to be displayed.
|
|
// */
|
|
func _sqlite3VdbeNextOpcode(tls *libc.TLS, p uintptr, pSub uintptr, eMode int32, piPc uintptr, piAddr uintptr, paOp uintptr) (r int32) {
|
|
var aOp, apSub uintptr
|
|
var i, iPc, j, j1, nByte, nRow, nSub, rc, v2 int32
|
|
_, _, _, _, _, _, _, _, _, _, _ = aOp, apSub, i, iPc, j, j1, nByte, nRow, nSub, rc, v2 /* Stop when row count reaches this */
|
|
nSub = 0 /* Number of sub-vdbes seen so far */
|
|
apSub = uintptr(0) /* Next instruction address */
|
|
rc = SQLITE_OK /* Result code */
|
|
aOp = uintptr(0) /* Rowid. Copy of value in *piPc */
|
|
/* When the number of output rows reaches nRow, that means the
|
|
** listing has finished and sqlite3_step() should return SQLITE_DONE.
|
|
** nRow is the sum of the number of rows in the main program, plus
|
|
** the sum of the number of rows in all trigger subprograms encountered
|
|
** so far. The nRow value will increase as new trigger subprograms are
|
|
** encountered, but p->pc will eventually catch up to nRow.
|
|
*/
|
|
nRow = (*TVdbe)(unsafe.Pointer(p)).FnOp
|
|
if pSub != uintptr(0) {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pSub)).Fflags)&int32(MEM_Blob) != 0 {
|
|
/* pSub is initiallly NULL. It is initialized to a BLOB by
|
|
** the P4_SUBPROGRAM processing logic below */
|
|
nSub = libc.Int32FromUint64(libc.Uint64FromInt32((*TMem)(unsafe.Pointer(pSub)).Fn) / uint64(8))
|
|
apSub = (*TMem)(unsafe.Pointer(pSub)).Fz
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < nSub) {
|
|
break
|
|
}
|
|
nRow = nRow + (*TSubProgram)(unsafe.Pointer(**(**uintptr)(__ccgo_up(apSub + uintptr(i)*8)))).FnOp
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
iPc = **(**int32)(__ccgo_up(piPc))
|
|
for int32(1) != 0 { /* Loop exits via break */
|
|
v2 = iPc
|
|
iPc = iPc + 1
|
|
i = v2
|
|
if i >= nRow {
|
|
(*TVdbe)(unsafe.Pointer(p)).Frc = SQLITE_OK
|
|
rc = int32(SQLITE_DONE)
|
|
break
|
|
}
|
|
if i < (*TVdbe)(unsafe.Pointer(p)).FnOp {
|
|
/* The rowid is small enough that we are still in the
|
|
** main program. */
|
|
aOp = (*TVdbe)(unsafe.Pointer(p)).FaOp
|
|
} else {
|
|
i = i - (*TVdbe)(unsafe.Pointer(p)).FnOp
|
|
j = 0
|
|
for {
|
|
if !(i >= (*TSubProgram)(unsafe.Pointer(**(**uintptr)(__ccgo_up(apSub + uintptr(j)*8)))).FnOp) {
|
|
break
|
|
}
|
|
i = i - (*TSubProgram)(unsafe.Pointer(**(**uintptr)(__ccgo_up(apSub + uintptr(j)*8)))).FnOp
|
|
goto _3
|
|
_3:
|
|
;
|
|
j = j + 1
|
|
}
|
|
aOp = (*TSubProgram)(unsafe.Pointer(**(**uintptr)(__ccgo_up(apSub + uintptr(j)*8)))).FaOp
|
|
}
|
|
/* When an OP_Program opcode is encounter (the only opcode that has
|
|
** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
|
|
** kept in p->aMem[9].z to hold the new program - assuming this subprogram
|
|
** has not already been seen.
|
|
*/
|
|
if pSub != uintptr(0) && int32((**(**TOp)(__ccgo_up(aOp + uintptr(i)*24))).Fp4type) == -int32(4) {
|
|
nByte = libc.Int32FromUint64(libc.Uint64FromInt32(nSub+libc.Int32FromInt32(1)) * uint64(8))
|
|
j1 = 0
|
|
for {
|
|
if !(j1 < nSub) {
|
|
break
|
|
}
|
|
if **(**uintptr)(__ccgo_up(apSub + uintptr(j1)*8)) == *(*uintptr)(unsafe.Pointer(aOp + uintptr(i)*24 + 16)) {
|
|
break
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
j1 = j1 + 1
|
|
}
|
|
if j1 == nSub {
|
|
(*TVdbe)(unsafe.Pointer(p)).Frc = _sqlite3VdbeMemGrow(tls, pSub, nByte, libc.BoolInt32(nSub != 0))
|
|
if (*TVdbe)(unsafe.Pointer(p)).Frc != SQLITE_OK {
|
|
rc = int32(SQLITE_ERROR)
|
|
break
|
|
}
|
|
apSub = (*TMem)(unsafe.Pointer(pSub)).Fz
|
|
v2 = nSub
|
|
nSub = nSub + 1
|
|
**(**uintptr)(__ccgo_up(apSub + uintptr(v2)*8)) = *(*uintptr)(unsafe.Pointer(aOp + uintptr(i)*24 + 16))
|
|
(*TMem)(unsafe.Pointer(pSub)).Fflags = libc.Uint16FromInt32(libc.Int32FromUint16((*TMem)(unsafe.Pointer(pSub)).Fflags) & ^(libc.Int32FromInt32(MEM_TypeMask)|libc.Int32FromInt32(MEM_Zero)) | int32(MEM_Blob))
|
|
(*TMem)(unsafe.Pointer(pSub)).Fn = libc.Int32FromUint64(libc.Uint64FromInt32(nSub) * uint64(8))
|
|
nRow = nRow + (*TSubProgram)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(aOp + uintptr(i)*24 + 16)))).FnOp
|
|
}
|
|
}
|
|
if eMode == 0 {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((**(**TOp)(__ccgo_up(aOp + uintptr(i)*24))).Fopcode) == int32(OP_Explain) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((**(**TOp)(__ccgo_up(aOp + uintptr(i)*24))).Fopcode) == int32(OP_Init) && iPc > int32(1) {
|
|
break
|
|
}
|
|
}
|
|
**(**int32)(__ccgo_up(piPc)) = iPc
|
|
**(**int32)(__ccgo_up(piAddr)) = i
|
|
**(**uintptr)(__ccgo_up(paOp)) = aOp
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function compares the two table rows or index records
|
|
// ** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero
|
|
// ** or positive integer if key1 is less than, equal to or
|
|
// ** greater than key2. The {nKey1, pKey1} key must be a blob
|
|
// ** created by the OP_MakeRecord opcode of the VDBE. The pPKey2
|
|
// ** key must be a parsed key such as obtained from
|
|
// ** sqlite3VdbeParseRecord.
|
|
// **
|
|
// ** If argument bSkip is non-zero, it is assumed that the caller has already
|
|
// ** determined that the first fields of the keys are equal.
|
|
// **
|
|
// ** Key1 and Key2 do not have to contain the same number of fields. If all
|
|
// ** fields that appear in both keys are equal, then pPKey2->default_rc is
|
|
// ** returned.
|
|
// **
|
|
// ** If database corruption is discovered, set pPKey2->errCode to
|
|
// ** SQLITE_CORRUPT and return 0. If an OOM error is encountered,
|
|
// ** pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the
|
|
// ** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db).
|
|
// */
|
|
func _sqlite3VdbeRecordCompareWithSkip(tls *libc.TLS, nKey1 int32, pKey1 uintptr, pPKey2 uintptr, bSkip int32) (r int32) {
|
|
bp := tls.Alloc(80)
|
|
defer tls.Free(80)
|
|
var aKey1, pKeyInfo, pRhs, v4 uintptr
|
|
var d1, idx1, v1 Tu32
|
|
var i, nCmp, nCmp1, nStr, rc, sortFlags, v2 int32
|
|
var lhs, rhs Ti64
|
|
var v5 bool
|
|
var _ /* mem1 at bp+8 */ TMem
|
|
var _ /* s1 at bp+64 */ Tu32
|
|
var _ /* serial_type at bp+68 */ Tu32
|
|
var _ /* szHdr1 at bp+0 */ Tu32
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = aKey1, d1, i, idx1, lhs, nCmp, nCmp1, nStr, pKeyInfo, pRhs, rc, rhs, sortFlags, v1, v2, v4, v5 /* Offset of first type in header */
|
|
rc = 0 /* Return value */
|
|
pRhs = (*TUnpackedRecord)(unsafe.Pointer(pPKey2)).FaMem
|
|
aKey1 = pKey1
|
|
/* If bSkip is true, then the caller has already determined that the first
|
|
** two elements in the keys are equal. Fix the various stack variables so
|
|
** that this routine begins comparing at the second field. */
|
|
if bSkip != 0 {
|
|
**(**Tu32)(__ccgo_up(bp + 64)) = uint32(**(**uint8)(__ccgo_up(aKey1 + 1)))
|
|
if **(**Tu32)(__ccgo_up(bp + 64)) < uint32(0x80) {
|
|
idx1 = uint32(2)
|
|
} else {
|
|
idx1 = libc.Uint32FromInt32(int32(1) + libc.Int32FromUint8(_sqlite3GetVarint32(tls, aKey1+1, bp+64)))
|
|
}
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(**(**uint8)(__ccgo_up(aKey1)))
|
|
d1 = **(**Tu32)(__ccgo_up(bp)) + _sqlite3VdbeSerialTypeLen(tls, **(**Tu32)(__ccgo_up(bp + 64)))
|
|
i = int32(1)
|
|
pRhs += 56
|
|
} else {
|
|
v1 = uint32(**(**uint8)(__ccgo_up(aKey1)))
|
|
**(**Tu32)(__ccgo_up(bp)) = v1
|
|
if v1 < uint32(0x80) {
|
|
idx1 = uint32(1)
|
|
} else {
|
|
idx1 = uint32(_sqlite3GetVarint32(tls, aKey1, bp))
|
|
}
|
|
d1 = **(**Tu32)(__ccgo_up(bp))
|
|
i = 0
|
|
}
|
|
if d1 > libc.Uint32FromInt32(nKey1) {
|
|
(*TUnpackedRecord)(unsafe.Pointer(pPKey2)).FerrCode = libc.Uint8FromInt32(_sqlite3CorruptError(tls, int32(92647)))
|
|
return 0 /* Corruption */
|
|
}
|
|
/* Only needed by assert() statements */
|
|
for int32(1) != 0 {
|
|
/* RHS is an integer */
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pRhs)).Fflags)&(libc.Int32FromInt32(MEM_Int)|libc.Int32FromInt32(MEM_IntReal)) != 0 {
|
|
**(**Tu32)(__ccgo_up(bp + 68)) = uint32(**(**uint8)(__ccgo_up(aKey1 + uintptr(idx1))))
|
|
if **(**Tu32)(__ccgo_up(bp + 68)) >= uint32(10) {
|
|
if **(**Tu32)(__ccgo_up(bp + 68)) == uint32(10) {
|
|
v2 = -int32(1)
|
|
} else {
|
|
v2 = +libc.Int32FromInt32(1)
|
|
}
|
|
rc = v2
|
|
} else {
|
|
if **(**Tu32)(__ccgo_up(bp + 68)) == uint32(0) {
|
|
rc = -int32(1)
|
|
} else {
|
|
if **(**Tu32)(__ccgo_up(bp + 68)) == uint32(7) {
|
|
_serialGet7(tls, aKey1+uintptr(d1), bp+8)
|
|
rc = -_sqlite3IntFloatCompare(tls, *(*Ti64)(unsafe.Pointer(pRhs)), *(*float64)(unsafe.Pointer(bp + 8)))
|
|
} else {
|
|
lhs = _vdbeRecordDecodeInt(tls, **(**Tu32)(__ccgo_up(bp + 68)), aKey1+uintptr(d1))
|
|
rhs = *(*Ti64)(unsafe.Pointer(pRhs))
|
|
if lhs < rhs {
|
|
rc = -int32(1)
|
|
} else {
|
|
if lhs > rhs {
|
|
rc = +libc.Int32FromInt32(1)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pRhs)).Fflags)&int32(MEM_Real) != 0 {
|
|
**(**Tu32)(__ccgo_up(bp + 68)) = uint32(**(**uint8)(__ccgo_up(aKey1 + uintptr(idx1))))
|
|
if **(**Tu32)(__ccgo_up(bp + 68)) >= uint32(10) {
|
|
/* Serial types 12 or greater are strings and blobs (greater than
|
|
** numbers). Types 10 and 11 are currently "reserved for future
|
|
** use", so it doesn't really matter what the results of comparing
|
|
** them to numeric values are. */
|
|
if **(**Tu32)(__ccgo_up(bp + 68)) == uint32(10) {
|
|
v2 = -int32(1)
|
|
} else {
|
|
v2 = +libc.Int32FromInt32(1)
|
|
}
|
|
rc = v2
|
|
} else {
|
|
if **(**Tu32)(__ccgo_up(bp + 68)) == uint32(0) {
|
|
rc = -int32(1)
|
|
} else {
|
|
if **(**Tu32)(__ccgo_up(bp + 68)) == uint32(7) {
|
|
if _serialGet7(tls, aKey1+uintptr(d1), bp+8) != 0 {
|
|
rc = -int32(1) /* mem1 is a NaN */
|
|
} else {
|
|
if *(*float64)(unsafe.Pointer(bp + 8)) < *(*float64)(unsafe.Pointer(pRhs)) {
|
|
rc = -int32(1)
|
|
} else {
|
|
if *(*float64)(unsafe.Pointer(bp + 8)) > *(*float64)(unsafe.Pointer(pRhs)) {
|
|
rc = +libc.Int32FromInt32(1)
|
|
} else {
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
_sqlite3VdbeSerialGet(tls, aKey1+uintptr(d1), **(**Tu32)(__ccgo_up(bp + 68)), bp+8)
|
|
rc = _sqlite3IntFloatCompare(tls, *(*Ti64)(unsafe.Pointer(bp + 8)), *(*float64)(unsafe.Pointer(pRhs)))
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pRhs)).Fflags)&int32(MEM_Str) != 0 {
|
|
**(**Tu32)(__ccgo_up(bp + 68)) = uint32(**(**uint8)(__ccgo_up(aKey1 + uintptr(idx1))))
|
|
if **(**Tu32)(__ccgo_up(bp + 68)) >= uint32(0x80) {
|
|
_sqlite3GetVarint32(tls, aKey1+uintptr(idx1), bp+68)
|
|
}
|
|
if **(**Tu32)(__ccgo_up(bp + 68)) < uint32(12) {
|
|
rc = -int32(1)
|
|
} else {
|
|
if !(**(**Tu32)(__ccgo_up(bp + 68))&libc.Uint32FromInt32(0x01) != 0) {
|
|
rc = +libc.Int32FromInt32(1)
|
|
} else {
|
|
(**(**TMem)(__ccgo_up(bp + 8))).Fn = libc.Int32FromUint32((**(**Tu32)(__ccgo_up(bp + 68)) - uint32(12)) / uint32(2))
|
|
if v5 = d1+libc.Uint32FromInt32((**(**TMem)(__ccgo_up(bp + 8))).Fn) > libc.Uint32FromInt32(nKey1); !v5 {
|
|
v4 = (*TUnpackedRecord)(unsafe.Pointer(pPKey2)).FpKeyInfo
|
|
pKeyInfo = v4
|
|
}
|
|
if v5 || libc.Int32FromUint16((*TKeyInfo)(unsafe.Pointer(v4)).FnAllField) <= i {
|
|
(*TUnpackedRecord)(unsafe.Pointer(pPKey2)).FerrCode = libc.Uint8FromInt32(_sqlite3CorruptError(tls, int32(92728)))
|
|
return 0 /* Corruption */
|
|
} else {
|
|
if *(*uintptr)(unsafe.Pointer(pKeyInfo + 32 + uintptr(i)*8)) != 0 {
|
|
(**(**TMem)(__ccgo_up(bp + 8))).Fenc = (*TKeyInfo)(unsafe.Pointer(pKeyInfo)).Fenc
|
|
(**(**TMem)(__ccgo_up(bp + 8))).Fdb = (*TKeyInfo)(unsafe.Pointer(pKeyInfo)).Fdb
|
|
(**(**TMem)(__ccgo_up(bp + 8))).Fflags = uint16(MEM_Str)
|
|
(**(**TMem)(__ccgo_up(bp + 8))).Fz = aKey1 + uintptr(d1)
|
|
rc = _vdbeCompareMemString(tls, bp+8, pRhs, *(*uintptr)(unsafe.Pointer(pKeyInfo + 32 + uintptr(i)*8)), pPKey2+31)
|
|
} else {
|
|
if (**(**TMem)(__ccgo_up(bp + 8))).Fn < (*TMem)(unsafe.Pointer(pRhs)).Fn {
|
|
v2 = (**(**TMem)(__ccgo_up(bp + 8))).Fn
|
|
} else {
|
|
v2 = (*TMem)(unsafe.Pointer(pRhs)).Fn
|
|
}
|
|
nCmp = v2
|
|
rc = libc.Xmemcmp(tls, aKey1+uintptr(d1), (*TMem)(unsafe.Pointer(pRhs)).Fz, libc.Uint64FromInt32(nCmp))
|
|
if rc == 0 {
|
|
rc = (**(**TMem)(__ccgo_up(bp + 8))).Fn - (*TMem)(unsafe.Pointer(pRhs)).Fn
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pRhs)).Fflags)&int32(MEM_Blob) != 0 {
|
|
**(**Tu32)(__ccgo_up(bp + 68)) = uint32(**(**uint8)(__ccgo_up(aKey1 + uintptr(idx1))))
|
|
if **(**Tu32)(__ccgo_up(bp + 68)) >= uint32(0x80) {
|
|
_sqlite3GetVarint32(tls, aKey1+uintptr(idx1), bp+68)
|
|
}
|
|
if **(**Tu32)(__ccgo_up(bp + 68)) < uint32(12) || **(**Tu32)(__ccgo_up(bp + 68))&uint32(0x01) != 0 {
|
|
rc = -int32(1)
|
|
} else {
|
|
nStr = libc.Int32FromUint32((**(**Tu32)(__ccgo_up(bp + 68)) - uint32(12)) / uint32(2))
|
|
if d1+libc.Uint32FromInt32(nStr) > libc.Uint32FromInt32(nKey1) {
|
|
(*TUnpackedRecord)(unsafe.Pointer(pPKey2)).FerrCode = libc.Uint8FromInt32(_sqlite3CorruptError(tls, int32(92758)))
|
|
return 0 /* Corruption */
|
|
} else {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(pRhs)).Fflags)&int32(MEM_Zero) != 0 {
|
|
if !(_isAllZero(tls, aKey1+uintptr(d1), nStr) != 0) {
|
|
rc = int32(1)
|
|
} else {
|
|
rc = nStr - *(*int32)(unsafe.Pointer(&(*TMem)(unsafe.Pointer(pRhs)).Fu))
|
|
}
|
|
} else {
|
|
if nStr < (*TMem)(unsafe.Pointer(pRhs)).Fn {
|
|
v2 = nStr
|
|
} else {
|
|
v2 = (*TMem)(unsafe.Pointer(pRhs)).Fn
|
|
}
|
|
nCmp1 = v2
|
|
rc = libc.Xmemcmp(tls, aKey1+uintptr(d1), (*TMem)(unsafe.Pointer(pRhs)).Fz, libc.Uint64FromInt32(nCmp1))
|
|
if rc == 0 {
|
|
rc = nStr - (*TMem)(unsafe.Pointer(pRhs)).Fn
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
**(**Tu32)(__ccgo_up(bp + 68)) = uint32(**(**uint8)(__ccgo_up(aKey1 + uintptr(idx1))))
|
|
if **(**Tu32)(__ccgo_up(bp + 68)) == uint32(0) || **(**Tu32)(__ccgo_up(bp + 68)) == uint32(10) || **(**Tu32)(__ccgo_up(bp + 68)) == uint32(7) && _serialGet7(tls, aKey1+uintptr(d1), bp+8) != 0 {
|
|
} else {
|
|
rc = int32(1)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if rc != 0 {
|
|
sortFlags = libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TKeyInfo)(unsafe.Pointer((*TUnpackedRecord)(unsafe.Pointer(pPKey2)).FpKeyInfo)).FaSortFlags + uintptr(i))))
|
|
if sortFlags != 0 {
|
|
if sortFlags&int32(KEYINFO_ORDER_BIGNULL) == 0 || sortFlags&int32(KEYINFO_ORDER_DESC) != libc.BoolInt32(**(**Tu32)(__ccgo_up(bp + 68)) == uint32(0) || libc.Int32FromUint16((*TMem)(unsafe.Pointer(pRhs)).Fflags)&int32(MEM_Null) != 0) {
|
|
rc = -rc
|
|
}
|
|
}
|
|
/* See comment below */
|
|
return rc
|
|
}
|
|
i = i + 1
|
|
if i == libc.Int32FromUint16((*TUnpackedRecord)(unsafe.Pointer(pPKey2)).FnField) {
|
|
break
|
|
}
|
|
pRhs += 56
|
|
d1 = d1 + _sqlite3VdbeSerialTypeLen(tls, **(**Tu32)(__ccgo_up(bp + 68)))
|
|
if d1 > libc.Uint32FromInt32(nKey1) {
|
|
break
|
|
}
|
|
idx1 = idx1 + libc.Uint32FromInt32(_sqlite3VarintLen(tls, uint64(**(**Tu32)(__ccgo_up(bp + 68)))))
|
|
if idx1 >= **(**Tu32)(__ccgo_up(bp)) {
|
|
(*TUnpackedRecord)(unsafe.Pointer(pPKey2)).FerrCode = libc.Uint8FromInt32(_sqlite3CorruptError(tls, int32(92809)))
|
|
return 0 /* Corrupt index */
|
|
}
|
|
}
|
|
/* No memory allocation is ever used on mem1. Prove this using
|
|
** the following assert(). If the assert() fails, it indicates a
|
|
** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). */
|
|
/* rc==0 here means that one or both of the keys ran out of fields and
|
|
** all the fields up to that point were equal. Return the default_rc
|
|
** value. */
|
|
(*TUnpackedRecord)(unsafe.Pointer(pPKey2)).FeqSeen = uint8(1)
|
|
return int32((*TUnpackedRecord)(unsafe.Pointer(pPKey2)).Fdefault_rc)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Given the nKey-byte encoding of a record in pKey[], populate the
|
|
// ** UnpackedRecord structure indicated by the fourth argument with the
|
|
// ** contents of the decoded record.
|
|
// */
|
|
func _sqlite3VdbeRecordUnpack(tls *libc.TLS, nKey int32, pKey uintptr, p uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var aKey, pKeyInfo, pMem uintptr
|
|
var d, idx Tu32
|
|
var u, v3 Tu16
|
|
var v1 int32
|
|
var _ /* serial_type at bp+4 */ Tu32
|
|
var _ /* szHdr at bp+0 */ Tu32
|
|
_, _, _, _, _, _, _, _ = aKey, d, idx, pKeyInfo, pMem, u, v1, v3
|
|
aKey = pKey
|
|
pMem = (*TUnpackedRecord)(unsafe.Pointer(p)).FaMem
|
|
pKeyInfo = (*TUnpackedRecord)(unsafe.Pointer(p)).FpKeyInfo
|
|
(*TUnpackedRecord)(unsafe.Pointer(p)).Fdefault_rc = 0
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(aKey))) < libc.Int32FromUint8(libc.Uint8FromInt32(0x80)) {
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(**(**uint8)(__ccgo_up(aKey)))
|
|
v1 = libc.Int32FromInt32(1)
|
|
} else {
|
|
v1 = libc.Int32FromUint8(_sqlite3GetVarint32(tls, aKey, bp))
|
|
}
|
|
idx = uint32(libc.Uint8FromInt32(v1))
|
|
d = **(**Tu32)(__ccgo_up(bp))
|
|
u = uint16(0)
|
|
for idx < **(**Tu32)(__ccgo_up(bp)) && d <= libc.Uint32FromInt32(nKey) {
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(aKey + uintptr(idx)))) < libc.Int32FromUint8(libc.Uint8FromInt32(0x80)) {
|
|
**(**Tu32)(__ccgo_up(bp + 4)) = uint32(**(**uint8)(__ccgo_up(aKey + uintptr(idx))))
|
|
v1 = libc.Int32FromInt32(1)
|
|
} else {
|
|
v1 = libc.Int32FromUint8(_sqlite3GetVarint32(tls, aKey+uintptr(idx), bp+4))
|
|
}
|
|
idx = idx + uint32(libc.Uint8FromInt32(v1))
|
|
(*TMem)(unsafe.Pointer(pMem)).Fenc = (*TKeyInfo)(unsafe.Pointer(pKeyInfo)).Fenc
|
|
(*TMem)(unsafe.Pointer(pMem)).Fdb = (*TKeyInfo)(unsafe.Pointer(pKeyInfo)).Fdb
|
|
/* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */
|
|
(*TMem)(unsafe.Pointer(pMem)).FszMalloc = 0
|
|
(*TMem)(unsafe.Pointer(pMem)).Fz = uintptr(0)
|
|
_sqlite3VdbeSerialGet(tls, aKey+uintptr(d), **(**Tu32)(__ccgo_up(bp + 4)), pMem)
|
|
d = d + _sqlite3VdbeSerialTypeLen(tls, **(**Tu32)(__ccgo_up(bp + 4)))
|
|
u = u + 1
|
|
v3 = u
|
|
if libc.Int32FromUint16(v3) >= libc.Int32FromUint16((*TUnpackedRecord)(unsafe.Pointer(p)).FnField) {
|
|
break
|
|
}
|
|
pMem += 56
|
|
}
|
|
if d > libc.Uint32FromInt32(nKey) && u != 0 {
|
|
/* In a corrupt record entry, the last pMem might have been set up using
|
|
** uninitialized memory. Overwrite its value with NULL, to prevent
|
|
** warnings from MSAN. */
|
|
_sqlite3VdbeMemSetNull(tls, pMem-libc.BoolUintptr(libc.Int32FromUint16(u) < libc.Int32FromUint16((*TUnpackedRecord)(unsafe.Pointer(p)).FnField))*56)
|
|
}
|
|
(*TUnpackedRecord)(unsafe.Pointer(p)).FnField = u
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Mark the VDBE as one that can be run multiple times.
|
|
// */
|
|
func _sqlite3VdbeReusable(tls *libc.TLS, p uintptr) {
|
|
var i int32
|
|
_ = i
|
|
i = int32(1)
|
|
for {
|
|
if !(i < (*TVdbe)(unsafe.Pointer(p)).FnOp) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((**(**TOp)(__ccgo_up((*TVdbe)(unsafe.Pointer(p)).FaOp + uintptr(i)*24))).Fopcode) == int32(OP_Expire) {
|
|
(**(**TOp)(__ccgo_up((*TVdbe)(unsafe.Pointer(p)).FaOp + 1*24))).Fopcode = uint8(OP_Noop)
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the name of the idx'th column to be returned by the SQL statement.
|
|
// ** zName must be a pointer to a nul terminated string.
|
|
// **
|
|
// ** This call must be made after a call to sqlite3VdbeSetNumCols().
|
|
// **
|
|
// ** The final parameter, xDel, must be one of SQLITE_DYNAMIC, SQLITE_STATIC
|
|
// ** or SQLITE_TRANSIENT. If it is SQLITE_DYNAMIC, then the buffer pointed
|
|
// ** to by zName will be freed by sqlite3DbFree() when the vdbe is destroyed.
|
|
// */
|
|
func _sqlite3VdbeSetColName(tls *libc.TLS, p uintptr, idx int32, var1 int32, zName uintptr, __ccgo_fp_xDel uintptr) (r int32) {
|
|
var pColName uintptr
|
|
var rc int32
|
|
_, _ = pColName, rc
|
|
if (*Tsqlite3)(unsafe.Pointer((*TVdbe)(unsafe.Pointer(p)).Fdb)).FmallocFailed != 0 {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
pColName = (*TVdbe)(unsafe.Pointer(p)).FaColName + uintptr(idx+var1*libc.Int32FromUint16((*TVdbe)(unsafe.Pointer(p)).FnResAlloc))*56
|
|
rc = _sqlite3VdbeMemSetText(tls, pColName, zName, int64(-int32(1)), __ccgo_fp_xDel)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the number of result columns that will be returned by this SQL
|
|
// ** statement. This is now set at compile time, rather than during
|
|
// ** execution of the vdbe program so that sqlite3_column_count() can
|
|
// ** be called on an SQL statement before sqlite3_step().
|
|
// */
|
|
func _sqlite3VdbeSetNumCols(tls *libc.TLS, p uintptr, nResColumn int32) {
|
|
var db uintptr
|
|
var n int32
|
|
var v1 Tu16
|
|
_, _, _ = db, n, v1
|
|
db = (*TVdbe)(unsafe.Pointer(p)).Fdb
|
|
if (*TVdbe)(unsafe.Pointer(p)).FnResAlloc != 0 {
|
|
_releaseMemArray(tls, (*TVdbe)(unsafe.Pointer(p)).FaColName, libc.Int32FromUint16((*TVdbe)(unsafe.Pointer(p)).FnResAlloc)*int32(COLNAME_N))
|
|
_sqlite3DbFree(tls, db, (*TVdbe)(unsafe.Pointer(p)).FaColName)
|
|
}
|
|
n = nResColumn * int32(COLNAME_N)
|
|
v1 = libc.Uint16FromInt32(nResColumn)
|
|
(*TVdbe)(unsafe.Pointer(p)).FnResAlloc = v1
|
|
(*TVdbe)(unsafe.Pointer(p)).FnResColumn = v1
|
|
(*TVdbe)(unsafe.Pointer(p)).FaColName = _sqlite3DbMallocRawNN(tls, db, uint64(uint64(56)*libc.Uint64FromInt32(n)))
|
|
if (*TVdbe)(unsafe.Pointer(p)).FaColName == uintptr(0) {
|
|
return
|
|
}
|
|
_initMemArray(tls, (*TVdbe)(unsafe.Pointer(p)).FaColName, n, db, uint16(MEM_Null))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Free any cursor components allocated by sqlite3VdbeSorterXXX routines.
|
|
// */
|
|
func _sqlite3VdbeSorterClose(tls *libc.TLS, db uintptr, pCsr uintptr) {
|
|
var ii int32
|
|
var pSorter uintptr
|
|
_, _ = ii, pSorter
|
|
pSorter = *(*uintptr)(unsafe.Pointer(pCsr + 48))
|
|
if pSorter != 0 {
|
|
ii = 0
|
|
for {
|
|
if !(ii < libc.Int32FromUint8((*TVdbeSorter)(unsafe.Pointer(pSorter)).FnTask)) {
|
|
break
|
|
}
|
|
**(**Tu64)(__ccgo_up(db + 816)) += (*(*TSortSubtask)(unsafe.Pointer(pSorter + 96 + uintptr(ii)*104))).FnSpill
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
_sqlite3VdbeSorterReset(tls, db, pSorter)
|
|
Xsqlite3_free(tls, (*TVdbeSorter)(unsafe.Pointer(pSorter)).Flist.FaMemory)
|
|
_sqlite3DbFree(tls, db, pSorter)
|
|
*(*uintptr)(unsafe.Pointer(pCsr + 48)) = uintptr(0)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compare the key in memory cell pVal with the key that the sorter cursor
|
|
// ** passed as the first argument currently points to. For the purposes of
|
|
// ** the comparison, ignore the rowid field at the end of each record.
|
|
// **
|
|
// ** If the sorter cursor key contains any NULL values, consider it to be
|
|
// ** less than pVal. Even if pVal also contains NULL values.
|
|
// **
|
|
// ** If an error occurs, return an SQLite error code (i.e. SQLITE_NOMEM).
|
|
// ** Otherwise, set *pRes to a negative, zero or positive value if the
|
|
// ** key in pVal is smaller than, equal to or larger than the current sorter
|
|
// ** key.
|
|
// **
|
|
// ** This routine forms the core of the OP_SorterCompare opcode, which in
|
|
// ** turn is used to verify uniqueness when constructing a UNIQUE INDEX.
|
|
// */
|
|
func _sqlite3VdbeSorterCompare(tls *libc.TLS, pCsr uintptr, pVal uintptr, nKeyCol int32, pRes uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var i int32
|
|
var pKey, pKeyInfo, pSorter, r2, v1 uintptr
|
|
var _ /* nKey at bp+0 */ int32
|
|
_, _, _, _, _, _ = i, pKey, pKeyInfo, pSorter, r2, v1 /* Sorter key to compare pVal with */
|
|
pSorter = *(*uintptr)(unsafe.Pointer(pCsr + 48))
|
|
r2 = (*TVdbeSorter)(unsafe.Pointer(pSorter)).FpUnpacked
|
|
pKeyInfo = (*TVdbeCursor)(unsafe.Pointer(pCsr)).FpKeyInfo
|
|
if r2 == uintptr(0) {
|
|
v1 = _sqlite3VdbeAllocUnpackedRecord(tls, pKeyInfo)
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).FpUnpacked = v1
|
|
r2 = v1
|
|
if r2 == uintptr(0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
(*TUnpackedRecord)(unsafe.Pointer(r2)).FnField = libc.Uint16FromInt32(nKeyCol)
|
|
}
|
|
pKey = _vdbeSorterRowkey(tls, pSorter, bp)
|
|
_sqlite3VdbeRecordUnpack(tls, **(**int32)(__ccgo_up(bp)), pKey, r2)
|
|
i = 0
|
|
for {
|
|
if !(i < nKeyCol) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint16((**(**TMem)(__ccgo_up((*TUnpackedRecord)(unsafe.Pointer(r2)).FaMem + uintptr(i)*56))).Fflags)&int32(MEM_Null) != 0 {
|
|
**(**int32)(__ccgo_up(pRes)) = -int32(1)
|
|
return SQLITE_OK
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
**(**int32)(__ccgo_up(pRes)) = _sqlite3VdbeRecordCompare(tls, (*TMem)(unsafe.Pointer(pVal)).Fn, (*TMem)(unsafe.Pointer(pVal)).Fz, r2)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
/************** End of vdbesort.c ********************************************/
|
|
/************** Begin file vdbevtab.c ****************************************/
|
|
/*
|
|
** 2020-03-23
|
|
**
|
|
** The author disclaims copyright to this source code. In place of
|
|
** a legal notice, here is a blessing:
|
|
**
|
|
** May you do good and not evil.
|
|
** May you find forgiveness for yourself and forgive others.
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
*************************************************************************
|
|
**
|
|
** This file implements virtual-tables for examining the bytecode content
|
|
** of a prepared statement.
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
|
|
/************** End of vdbevtab.c ********************************************/
|
|
/************** Begin file memjournal.c **************************************/
|
|
/*
|
|
** 2008 October 7
|
|
**
|
|
** The author disclaims copyright to this source code. In place of
|
|
** a legal notice, here is a blessing:
|
|
**
|
|
** May you do good and not evil.
|
|
** May you find forgiveness for yourself and forgive others.
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
*************************************************************************
|
|
**
|
|
** This file contains code use to implement an in-memory rollback journal.
|
|
** The in-memory rollback journal is used to journal transactions for
|
|
** ":memory:" databases and when the journal_mode=MEMORY pragma is used.
|
|
**
|
|
** Update: The in-memory journal is also used to temporarily cache
|
|
** smaller journals that are not critical for power-loss recovery.
|
|
** For example, statement journals that are not too big will be held
|
|
** entirely in memory, thus reducing the number of file I/O calls, and
|
|
** more importantly, reducing temporary file creation events. If these
|
|
** journals become too large for memory, they are spilled to disk. But
|
|
** in the common case, they are usually small and no file I/O needs to
|
|
** occur.
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Reset a sorting cursor back to its original empty state.
|
|
// */
|
|
func _sqlite3VdbeSorterReset(tls *libc.TLS, db uintptr, pSorter uintptr) {
|
|
var i int32
|
|
var pTask uintptr
|
|
_, _ = i, pTask
|
|
_vdbeSorterJoinAll(tls, pSorter, SQLITE_OK)
|
|
if (*TVdbeSorter)(unsafe.Pointer(pSorter)).FpReader != 0 {
|
|
_vdbePmaReaderClear(tls, (*TVdbeSorter)(unsafe.Pointer(pSorter)).FpReader)
|
|
_sqlite3DbFree(tls, db, (*TVdbeSorter)(unsafe.Pointer(pSorter)).FpReader)
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).FpReader = uintptr(0)
|
|
}
|
|
_vdbeMergeEngineFree(tls, (*TVdbeSorter)(unsafe.Pointer(pSorter)).FpMerger)
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).FpMerger = uintptr(0)
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint8((*TVdbeSorter)(unsafe.Pointer(pSorter)).FnTask)) {
|
|
break
|
|
}
|
|
pTask = pSorter + 96 + uintptr(i)*104
|
|
_vdbeSortSubtaskCleanup(tls, db, pTask)
|
|
(*TSortSubtask)(unsafe.Pointer(pTask)).FpSorter = pSorter
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if (*TVdbeSorter)(unsafe.Pointer(pSorter)).Flist.FaMemory == uintptr(0) {
|
|
_vdbeSorterRecordFree(tls, uintptr(0), (*TVdbeSorter)(unsafe.Pointer(pSorter)).Flist.FpList)
|
|
}
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).Flist.FpList = uintptr(0)
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).Flist.FszPMA = 0
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).FbUsePMA = uint8(0)
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).FiMemory = 0
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).FmxKeysize = 0
|
|
_sqlite3DbFree(tls, db, (*TVdbeSorter)(unsafe.Pointer(pSorter)).FpUnpacked)
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).FpUnpacked = uintptr(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Once the sorter has been populated by calls to sqlite3VdbeSorterWrite,
|
|
// ** this function is called to prepare for iterating through the records
|
|
// ** in sorted order.
|
|
// */
|
|
func _sqlite3VdbeSorterRewind(tls *libc.TLS, pCsr uintptr, pbEof uintptr) (r int32) {
|
|
var pSorter uintptr
|
|
var rc int32
|
|
_, _ = pSorter, rc
|
|
rc = SQLITE_OK /* Return code */
|
|
pSorter = *(*uintptr)(unsafe.Pointer(pCsr + 48))
|
|
/* If no data has been written to disk, then do not do so now. Instead,
|
|
** sort the VdbeSorter.pRecord list. The vdbe layer will read data directly
|
|
** from the in-memory list. */
|
|
if libc.Int32FromUint8((*TVdbeSorter)(unsafe.Pointer(pSorter)).FbUsePMA) == 0 {
|
|
if (*TVdbeSorter)(unsafe.Pointer(pSorter)).Flist.FpList != 0 {
|
|
**(**int32)(__ccgo_up(pbEof)) = 0
|
|
rc = _vdbeSorterSort(tls, pSorter+96, pSorter+56)
|
|
} else {
|
|
**(**int32)(__ccgo_up(pbEof)) = int32(1)
|
|
}
|
|
return rc
|
|
}
|
|
/* Write the current in-memory list to a PMA. When the VdbeSorterWrite()
|
|
** function flushes the contents of memory to disk, it immediately always
|
|
** creates a new list consisting of a single key immediately afterwards.
|
|
** So the list is never empty at this point. */
|
|
rc = _vdbeSorterFlushPMA(tls, pSorter)
|
|
/* Join all threads */
|
|
rc = _vdbeSorterJoinAll(tls, pSorter, rc)
|
|
/* Assuming no errors have occurred, set up a merger structure to
|
|
** incrementally read and merge all remaining PMAs. */
|
|
if rc == SQLITE_OK {
|
|
rc = _vdbeSorterSetupMerge(tls, pSorter)
|
|
**(**int32)(__ccgo_up(pbEof)) = 0
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return a pointer to a subexpression of pVector that is the i-th
|
|
// ** column of the vector (numbered starting with 0). The caller must
|
|
// ** ensure that i is within range.
|
|
// **
|
|
// ** If pVector is really a scalar (and "scalar" here includes subqueries
|
|
// ** that return a single column!) then return pVector unmodified.
|
|
// **
|
|
// ** pVector retains ownership of the returned subexpression.
|
|
// **
|
|
// ** If the vector is a (SELECT ...) then the expression returned is
|
|
// ** just the expression for the i-th term of the result set, and may
|
|
// ** not be ready for evaluation because the table cursor has not yet
|
|
// ** been positioned.
|
|
// */
|
|
func _sqlite3VectorFieldSubexpr(tls *libc.TLS, pVector uintptr, i int32) (r uintptr) {
|
|
if _sqlite3ExprIsVector(tls, pVector) != 0 {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pVector)).Fop) == int32(TK_SELECT) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pVector)).Fop2) == int32(TK_SELECT) {
|
|
return (*(*TExprList_item)(unsafe.Pointer((*TSelect)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pVector + 32)))).FpEList + 8 + uintptr(i)*32))).FpExpr
|
|
} else {
|
|
return (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pVector + 32)) + 8 + uintptr(i)*32))).FpExpr
|
|
}
|
|
}
|
|
return pVector
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The parser calls this routine for each token after the first token
|
|
// ** in an argument to the module name in a CREATE VIRTUAL TABLE statement.
|
|
// */
|
|
func _sqlite3VtabArgExtend(tls *libc.TLS, pParse uintptr, p uintptr) {
|
|
var pArg uintptr
|
|
_ = pArg
|
|
pArg = pParse + 384
|
|
if (*TToken)(unsafe.Pointer(pArg)).Fz == uintptr(0) {
|
|
(*TToken)(unsafe.Pointer(pArg)).Fz = (*TToken)(unsafe.Pointer(p)).Fz
|
|
(*TToken)(unsafe.Pointer(pArg)).Fn = (*TToken)(unsafe.Pointer(p)).Fn
|
|
} else {
|
|
(*TToken)(unsafe.Pointer(pArg)).Fn = libc.Uint32FromInt32(int32(t__predefined_ptrdiff_t((*TToken)(unsafe.Pointer(p)).Fz+uintptr((*TToken)(unsafe.Pointer(p)).Fn)) - int64((*TToken)(unsafe.Pointer(pArg)).Fz)))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The parser calls this routine when it first sees a CREATE VIRTUAL TABLE
|
|
// ** statement. The module name has been parsed, but the optional list
|
|
// ** of parameters that follow the module name are still pending.
|
|
// */
|
|
func _sqlite3VtabBeginParse(tls *libc.TLS, pParse uintptr, pName1 uintptr, pName2 uintptr, pModuleName uintptr, ifNotExists int32) {
|
|
var db, pTable uintptr
|
|
var iDb int32
|
|
_, _, _ = db, iDb, pTable /* Database connection */
|
|
_sqlite3StartTable(tls, pParse, pName1, pName2, 0, 0, int32(1), ifNotExists)
|
|
pTable = (*TParse)(unsafe.Pointer(pParse)).FpNewTable
|
|
if pTable == uintptr(0) {
|
|
return
|
|
}
|
|
(*TTable)(unsafe.Pointer(pTable)).FeTabType = uint8(TABTYP_VTAB)
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
_addModuleArgument(tls, pParse, pTable, _sqlite3NameFromToken(tls, db, pModuleName))
|
|
_addModuleArgument(tls, pParse, pTable, uintptr(0))
|
|
_addModuleArgument(tls, pParse, pTable, _sqlite3DbStrDup(tls, db, (*TTable)(unsafe.Pointer(pTable)).FzName))
|
|
(*TParse)(unsafe.Pointer(pParse)).FsNameToken.Fn = libc.Uint32FromInt32(int32(t__predefined_ptrdiff_t((*TToken)(unsafe.Pointer(pModuleName)).Fz+uintptr((*TToken)(unsafe.Pointer(pModuleName)).Fn)) - int64((*TParse)(unsafe.Pointer(pParse)).FsNameToken.Fz)))
|
|
/* Creating a virtual table invokes the authorization callback twice.
|
|
** The first invocation, to obtain permission to INSERT a row into the
|
|
** sqlite_schema table, has already been made by sqlite3StartTable().
|
|
** The second call, to obtain permission to create the table, is made now.
|
|
*/
|
|
if (*(*struct {
|
|
FnArg int32
|
|
FazArg uintptr
|
|
Fp uintptr
|
|
})(unsafe.Pointer(pTable + 64))).FazArg != 0 {
|
|
iDb = _sqlite3SchemaToIndex(tls, db, (*TTable)(unsafe.Pointer(pTable)).FpSchema)
|
|
/* The database the table is being created in */
|
|
_sqlite3AuthCheck(tls, pParse, int32(SQLITE_CREATE_VTABLE), (*TTable)(unsafe.Pointer(pTable)).FzName, **(**uintptr)(__ccgo_up((*(*struct {
|
|
FnArg int32
|
|
FazArg uintptr
|
|
Fp uintptr
|
|
})(unsafe.Pointer(pTable + 64))).FazArg)), (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).FaDb + uintptr(iDb)*32))).FzDbSName)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is invoked by the vdbe to call the xDestroy method
|
|
// ** of the virtual table named zTab in database iDb. This occurs
|
|
// ** when a DROP TABLE is mentioned.
|
|
// **
|
|
// ** This call is a no-op if zTab is not a virtual table.
|
|
// */
|
|
func _sqlite3VtabCallDestroy(tls *libc.TLS, db uintptr, iDb int32, zTab uintptr) (r int32) {
|
|
var p, pTab, xDestroy uintptr
|
|
var rc int32
|
|
_, _, _, _ = p, pTab, rc, xDestroy
|
|
rc = SQLITE_OK
|
|
pTab = _sqlite3FindTable(tls, db, zTab, (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(iDb)*32))).FzDbSName)
|
|
if pTab != uintptr(0) && libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == int32(TABTYP_VTAB) && (*(*struct {
|
|
FnArg int32
|
|
FazArg uintptr
|
|
Fp uintptr
|
|
})(unsafe.Pointer(pTab + 64))).Fp != uintptr(0) {
|
|
p = (*(*struct {
|
|
FnArg int32
|
|
FazArg uintptr
|
|
Fp uintptr
|
|
})(unsafe.Pointer(pTab + 64))).Fp
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
if (*Tsqlite3_vtab)(unsafe.Pointer((*TVTable)(unsafe.Pointer(p)).FpVtab)).FnRef > 0 {
|
|
return int32(SQLITE_LOCKED)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
p = (*TVTable)(unsafe.Pointer(p)).FpNext
|
|
}
|
|
p = _vtabDisconnectAll(tls, db, pTab)
|
|
xDestroy = (*Tsqlite3_module)(unsafe.Pointer((*TModule)(unsafe.Pointer((*TVTable)(unsafe.Pointer(p)).FpMod)).FpModule)).FxDestroy
|
|
if xDestroy == uintptr(0) {
|
|
xDestroy = (*Tsqlite3_module)(unsafe.Pointer((*TModule)(unsafe.Pointer((*TVTable)(unsafe.Pointer(p)).FpMod)).FpModule)).FxDisconnect
|
|
}
|
|
(*TTable)(unsafe.Pointer(pTab)).FnTabRef = (*TTable)(unsafe.Pointer(pTab)).FnTabRef + 1
|
|
rc = (*(*func(*libc.TLS, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{xDestroy})))(tls, (*TVTable)(unsafe.Pointer(p)).FpVtab)
|
|
/* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
|
|
if rc == SQLITE_OK {
|
|
(*TVTable)(unsafe.Pointer(p)).FpVtab = uintptr(0)
|
|
(*(*struct {
|
|
FnArg int32
|
|
FazArg uintptr
|
|
Fp uintptr
|
|
})(unsafe.Pointer(pTab + 64))).Fp = uintptr(0)
|
|
_sqlite3VtabUnlock(tls, p)
|
|
}
|
|
_sqlite3DeleteTable(tls, db, pTab)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Invoke the xCommit method of all virtual tables in the
|
|
// ** sqlite3.aVTrans array. Then clear the array itself.
|
|
// */
|
|
func _sqlite3VtabCommit(tls *libc.TLS, db uintptr) (r int32) {
|
|
_callFinaliser(tls, db, libc.Int32FromUint64(uint64(libc.UintptrFromInt32(0)+128)))
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Make sure virtual table pTab is contained in the pParse->apVirtualLock[]
|
|
// ** array so that an OP_VBegin will get generated for it. Add pTab to the
|
|
// ** array if it is missing. If pTab is already in the array, this routine
|
|
// ** is a no-op.
|
|
// */
|
|
func _sqlite3VtabMakeWritable(tls *libc.TLS, pParse uintptr, pTab uintptr) {
|
|
var apVtabLock, pToplevel, v1 uintptr
|
|
var i, n, v3 int32
|
|
_, _, _, _, _, _ = apVtabLock, i, n, pToplevel, v1, v3
|
|
if (*TParse)(unsafe.Pointer(pParse)).FpToplevel != 0 {
|
|
v1 = (*TParse)(unsafe.Pointer(pParse)).FpToplevel
|
|
} else {
|
|
v1 = pParse
|
|
}
|
|
pToplevel = v1
|
|
i = 0
|
|
for {
|
|
if !(i < (*TParse)(unsafe.Pointer(pToplevel)).FnVtabLock) {
|
|
break
|
|
}
|
|
if pTab == **(**uintptr)(__ccgo_up((*TParse)(unsafe.Pointer(pToplevel)).FapVtabLock + uintptr(i)*8)) {
|
|
return
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
n = libc.Int32FromUint64(libc.Uint64FromInt32((*TParse)(unsafe.Pointer(pToplevel)).FnVtabLock+libc.Int32FromInt32(1)) * uint64(8))
|
|
apVtabLock = _sqlite3Realloc(tls, (*TParse)(unsafe.Pointer(pToplevel)).FapVtabLock, libc.Uint64FromInt32(n))
|
|
if apVtabLock != 0 {
|
|
(*TParse)(unsafe.Pointer(pToplevel)).FapVtabLock = apVtabLock
|
|
v1 = pToplevel + 312
|
|
v3 = *(*int32)(unsafe.Pointer(v1))
|
|
*(*int32)(unsafe.Pointer(v1)) = *(*int32)(unsafe.Pointer(v1)) + 1
|
|
**(**uintptr)(__ccgo_up((*TParse)(unsafe.Pointer(pToplevel)).FapVtabLock + uintptr(v3)*8)) = pTab
|
|
} else {
|
|
_sqlite3OomFault(tls, (*TParse)(unsafe.Pointer(pToplevel)).Fdb)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Invoke the xRollback method of all virtual tables in the
|
|
// ** sqlite3.aVTrans array. Then clear the array itself.
|
|
// */
|
|
func _sqlite3VtabRollback(tls *libc.TLS, db uintptr) (r int32) {
|
|
_callFinaliser(tls, db, libc.Int32FromUint64(uint64(libc.UintptrFromInt32(0)+136)))
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Open a connection to the WAL file zWalName. The database file must
|
|
// ** already be opened on connection pDbFd. The buffer that zWalName points
|
|
// ** to must remain valid for the lifetime of the returned Wal* handle.
|
|
// **
|
|
// ** A SHARED lock should be held on the database file when this function
|
|
// ** is called. The purpose of this SHARED lock is to prevent any other
|
|
// ** client from unlinking the WAL or wal-index file. If another process
|
|
// ** were to do this just after this client opened one of these files, the
|
|
// ** system would be badly broken.
|
|
// **
|
|
// ** If the log file is successfully opened, SQLITE_OK is returned and
|
|
// ** *ppWal is set to point to a new WAL handle. If an error occurs,
|
|
// ** an SQLite error code is returned and *ppWal is left unmodified.
|
|
// */
|
|
func _sqlite3WalOpen(tls *libc.TLS, pVfs uintptr, pDbFd uintptr, zWalName uintptr, bNoShm int32, mxWalSize Ti64, ppWal uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var iDC, rc, v1 int32
|
|
var pRet uintptr
|
|
var _ /* flags at bp+0 */ int32
|
|
_, _, _, _ = iDC, pRet, rc, v1 /* Flags passed to OsOpen() */
|
|
/* Verify the values of various constants. Any changes to the values
|
|
** of these constants would result in an incompatible on-disk format
|
|
** for the -shm file. Any change that causes one of these asserts to
|
|
** fail is a backward compatibility problem, even if the change otherwise
|
|
** works.
|
|
**
|
|
** This table also serves as a helpful cross-reference when trying to
|
|
** interpret hex dumps of the -shm file.
|
|
*/
|
|
/* In the amalgamation, the os_unix.c and os_win.c source files come before
|
|
** this source file. Verify that the #defines of the locking byte offsets
|
|
** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.
|
|
** For that matter, if the lock offset ever changes from its initial design
|
|
** value of 120, we need to know that so there is an assert() to check it.
|
|
*/
|
|
/* Allocate an instance of struct Wal to return. */
|
|
**(**uintptr)(__ccgo_up(ppWal)) = uintptr(0)
|
|
pRet = _sqlite3MallocZero(tls, uint64(uint64(160)+libc.Uint64FromInt32((*Tsqlite3_vfs)(unsafe.Pointer(pVfs)).FszOsFile)))
|
|
if !(pRet != 0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
(*TWal)(unsafe.Pointer(pRet)).FpVfs = pVfs
|
|
(*TWal)(unsafe.Pointer(pRet)).FpWalFd = pRet + 1*160
|
|
(*TWal)(unsafe.Pointer(pRet)).FpDbFd = pDbFd
|
|
(*TWal)(unsafe.Pointer(pRet)).FreadLock = int16(-int32(1))
|
|
(*TWal)(unsafe.Pointer(pRet)).FmxWalSize = mxWalSize
|
|
(*TWal)(unsafe.Pointer(pRet)).FzWalName = zWalName
|
|
(*TWal)(unsafe.Pointer(pRet)).FsyncHeader = uint8(1)
|
|
(*TWal)(unsafe.Pointer(pRet)).FpadToSectorBoundary = uint8(1)
|
|
if bNoShm != 0 {
|
|
v1 = int32(WAL_HEAPMEMORY_MODE)
|
|
} else {
|
|
v1 = WAL_NORMAL_MODE
|
|
}
|
|
(*TWal)(unsafe.Pointer(pRet)).FexclusiveMode = libc.Uint8FromInt32(v1)
|
|
/* Open file handle on the write-ahead log file. */
|
|
**(**int32)(__ccgo_up(bp)) = libc.Int32FromInt32(SQLITE_OPEN_READWRITE) | libc.Int32FromInt32(SQLITE_OPEN_CREATE) | libc.Int32FromInt32(SQLITE_OPEN_WAL)
|
|
rc = _sqlite3OsOpen(tls, pVfs, zWalName, (*TWal)(unsafe.Pointer(pRet)).FpWalFd, **(**int32)(__ccgo_up(bp)), bp)
|
|
if rc == SQLITE_OK && **(**int32)(__ccgo_up(bp))&int32(SQLITE_OPEN_READONLY) != 0 {
|
|
(*TWal)(unsafe.Pointer(pRet)).FreadOnly = uint8(WAL_RDONLY)
|
|
}
|
|
if rc != SQLITE_OK {
|
|
_walIndexClose(tls, pRet, 0)
|
|
_sqlite3OsClose(tls, (*TWal)(unsafe.Pointer(pRet)).FpWalFd)
|
|
Xsqlite3_free(tls, pRet)
|
|
} else {
|
|
iDC = _sqlite3OsDeviceCharacteristics(tls, pDbFd)
|
|
if iDC&int32(SQLITE_IOCAP_SEQUENTIAL) != 0 {
|
|
(*TWal)(unsafe.Pointer(pRet)).FsyncHeader = uint8(0)
|
|
}
|
|
if iDC&int32(SQLITE_IOCAP_POWERSAFE_OVERWRITE) != 0 {
|
|
(*TWal)(unsafe.Pointer(pRet)).FpadToSectorBoundary = uint8(0)
|
|
}
|
|
**(**uintptr)(__ccgo_up(ppWal)) = pRet
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Walk an expression tree. Invoke the callback once for each node
|
|
// ** of the expression, while descending. (In other words, the callback
|
|
// ** is invoked before visiting children.)
|
|
// **
|
|
// ** The return value from the callback should be one of the WRC_*
|
|
// ** constants to specify how to proceed with the walk.
|
|
// **
|
|
// ** WRC_Continue Continue descending down the tree.
|
|
// **
|
|
// ** WRC_Prune Do not descend into child nodes, but allow
|
|
// ** the walk to continue with sibling nodes.
|
|
// **
|
|
// ** WRC_Abort Do no more callbacks. Unwind the stack and
|
|
// ** return from the top-level walk call.
|
|
// **
|
|
// ** The return value from this routine is WRC_Abort to abandon the tree walk
|
|
// ** and WRC_Continue to continue.
|
|
// */
|
|
func _sqlite3WalkExprNN(tls *libc.TLS, pWalker uintptr, pExpr uintptr) (r int32) {
|
|
var rc int32
|
|
_ = rc
|
|
for int32(1) != 0 {
|
|
rc = (*(*func(*libc.TLS, uintptr, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{(*TWalker)(unsafe.Pointer(pWalker)).FxExprCallback})))(tls, pWalker, pExpr)
|
|
if rc != 0 {
|
|
return rc & int32(WRC_Abort)
|
|
}
|
|
if !((*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_TokenOnly)|libc.Int32FromInt32(EP_Leaf)) != libc.Uint32FromInt32(0)) {
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).FpLeft != 0 && _sqlite3WalkExprNN(tls, pWalker, (*TExpr)(unsafe.Pointer(pExpr)).FpLeft) != 0 {
|
|
return int32(WRC_Abort)
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).FpRight != 0 {
|
|
pExpr = (*TExpr)(unsafe.Pointer(pExpr)).FpRight
|
|
continue
|
|
} else {
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&uint32(EP_xIsSelect) != uint32(0) {
|
|
if _sqlite3WalkSelect(tls, pWalker, *(*uintptr)(unsafe.Pointer(pExpr + 32))) != 0 {
|
|
return int32(WRC_Abort)
|
|
}
|
|
} else {
|
|
if *(*uintptr)(unsafe.Pointer(pExpr + 32)) != 0 {
|
|
if _sqlite3WalkExprList(tls, pWalker, *(*uintptr)(unsafe.Pointer(pExpr + 32))) != 0 {
|
|
return int32(WRC_Abort)
|
|
}
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_WinFunc)) != uint32(0) {
|
|
if _walkWindowList(tls, pWalker, *(*uintptr)(unsafe.Pointer(pExpr + 64)), int32(1)) != 0 {
|
|
return int32(WRC_Abort)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Possibly add terms corresponding to the LIMIT and OFFSET clauses of the
|
|
// ** SELECT statement passed as the second argument. These terms are only
|
|
// ** added if:
|
|
// **
|
|
// ** 1. The SELECT statement has a LIMIT clause, and
|
|
// ** 2. The SELECT statement is not an aggregate or DISTINCT query, and
|
|
// ** 3. The SELECT statement has exactly one object in its FROM clause, and
|
|
// ** that object is a virtual table, and
|
|
// ** 4. There are no terms in the WHERE clause that will not be passed
|
|
// ** to the virtual table xBestIndex method.
|
|
// ** 5. The ORDER BY clause, if any, will be made available to the xBestIndex
|
|
// ** method.
|
|
// **
|
|
// ** LIMIT and OFFSET terms are ignored by most of the planner code. They
|
|
// ** exist only so that they may be passed to the xBestIndex method of the
|
|
// ** single virtual table in the FROM clause of the SELECT.
|
|
// */
|
|
func _sqlite3WhereAddLimit(tls *libc.TLS, pWC uintptr, p uintptr) {
|
|
var iCsr, ii int32
|
|
var pExpr, pOrderBy, pParent uintptr
|
|
_, _, _, _, _ = iCsr, ii, pExpr, pOrderBy, pParent
|
|
/* 1 -- checked by caller */
|
|
if (*TSelect)(unsafe.Pointer(p)).FpGroupBy == uintptr(0) && (*TSelect)(unsafe.Pointer(p)).FselFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SF_Distinct)|libc.Int32FromInt32(SF_Aggregate)) == uint32(0) && ((*TSrcList)(unsafe.Pointer((*TSelect)(unsafe.Pointer(p)).FpSrc)).FnSrc == int32(1) && libc.Int32FromUint8((*TTable)(unsafe.Pointer((*(*TSrcItem)(unsafe.Pointer((*TSelect)(unsafe.Pointer(p)).FpSrc + 8))).FpSTab)).FeTabType) == int32(TABTYP_VTAB)) {
|
|
pOrderBy = (*TSelect)(unsafe.Pointer(p)).FpOrderBy
|
|
iCsr = (*(*TSrcItem)(unsafe.Pointer((*TSelect)(unsafe.Pointer(p)).FpSrc + 8))).FiCursor
|
|
/* Check condition (4). Return early if it is not met. */
|
|
ii = 0
|
|
for {
|
|
if !(ii < (*TWhereClause)(unsafe.Pointer(pWC)).FnTerm) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint16((**(**TWhereTerm)(__ccgo_up((*TWhereClause)(unsafe.Pointer(pWC)).Fa + uintptr(ii)*56))).FwtFlags)&int32(TERM_CODED) != 0 {
|
|
/* This term is a vector operation that has been decomposed into
|
|
** other, subsequent terms. It can be ignored. See tag-20220128a */
|
|
goto _1
|
|
}
|
|
if (**(**TWhereTerm)(__ccgo_up((*TWhereClause)(unsafe.Pointer(pWC)).Fa + uintptr(ii)*56))).FnChild != 0 {
|
|
/* If this term has child terms, then they are also part of the
|
|
** pWC->a[] array. So this term can be ignored, as a LIMIT clause
|
|
** will only be added if each of the child terms passes the
|
|
** (leftCursor==iCsr) test below. */
|
|
goto _1
|
|
}
|
|
if (**(**TWhereTerm)(__ccgo_up((*TWhereClause)(unsafe.Pointer(pWC)).Fa + uintptr(ii)*56))).FleftCursor == iCsr && (**(**TWhereTerm)(__ccgo_up((*TWhereClause)(unsafe.Pointer(pWC)).Fa + uintptr(ii)*56))).FprereqRight == uint64(0) {
|
|
goto _1
|
|
}
|
|
/* If this term has a parent with exactly one child, and the parent will
|
|
** be passed through to xBestIndex, then this term can be ignored. */
|
|
if (**(**TWhereTerm)(__ccgo_up((*TWhereClause)(unsafe.Pointer(pWC)).Fa + uintptr(ii)*56))).FiParent >= 0 {
|
|
pParent = (*TWhereClause)(unsafe.Pointer(pWC)).Fa + uintptr((**(**TWhereTerm)(__ccgo_up((*TWhereClause)(unsafe.Pointer(pWC)).Fa + uintptr(ii)*56))).FiParent)*56
|
|
if (*TWhereTerm)(unsafe.Pointer(pParent)).FleftCursor == iCsr && (*TWhereTerm)(unsafe.Pointer(pParent)).FprereqRight == uint64(0) && libc.Int32FromUint8((*TWhereTerm)(unsafe.Pointer(pParent)).FnChild) == int32(1) {
|
|
goto _1
|
|
}
|
|
}
|
|
/* This term will not be passed through. Do not add a LIMIT clause. */
|
|
return
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
/* Check condition (5). Return early if it is not met. */
|
|
if pOrderBy != 0 {
|
|
ii = 0
|
|
for {
|
|
if !(ii < (*TExprList)(unsafe.Pointer(pOrderBy)).FnExpr) {
|
|
break
|
|
}
|
|
pExpr = (*(*TExprList_item)(unsafe.Pointer(pOrderBy + 8 + uintptr(ii)*32))).FpExpr
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) != int32(TK_COLUMN) {
|
|
return
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).FiTable != iCsr {
|
|
return
|
|
}
|
|
if libc.Int32FromUint8((*(*TExprList_item)(unsafe.Pointer(pOrderBy + 8 + uintptr(ii)*32))).Ffg.FsortFlags)&int32(KEYINFO_ORDER_BIGNULL) != 0 {
|
|
return
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
}
|
|
/* All conditions are met. Add the terms to the where-clause object. */
|
|
if (*TSelect)(unsafe.Pointer(p)).FiOffset != 0 && (*TSelect)(unsafe.Pointer(p)).FselFlags&uint32(SF_Compound) == uint32(0) {
|
|
_whereAddLimitExpr(tls, pWC, (*TSelect)(unsafe.Pointer(p)).FiOffset, (*TExpr)(unsafe.Pointer((*TSelect)(unsafe.Pointer(p)).FpLimit)).FpRight, iCsr, int32(SQLITE_INDEX_CONSTRAINT_OFFSET))
|
|
}
|
|
if (*TSelect)(unsafe.Pointer(p)).FiOffset == 0 || (*TSelect)(unsafe.Pointer(p)).FselFlags&uint32(SF_Compound) == uint32(0) {
|
|
_whereAddLimitExpr(tls, pWC, (*TSelect)(unsafe.Pointer(p)).FiLimit, (*TExpr)(unsafe.Pointer((*TSelect)(unsafe.Pointer(p)).FpLimit)).FpLeft, iCsr, int32(SQLITE_INDEX_CONSTRAINT_LIMIT))
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Deallocate a WhereClause structure. The WhereClause structure
|
|
// ** itself is not freed. This routine is the inverse of
|
|
// ** sqlite3WhereClauseInit().
|
|
// */
|
|
func _sqlite3WhereClauseClear(tls *libc.TLS, pWC uintptr) {
|
|
var a, aLast, db uintptr
|
|
_, _, _ = a, aLast, db
|
|
db = (*TParse)(unsafe.Pointer((*TWhereInfo)(unsafe.Pointer((*TWhereClause)(unsafe.Pointer(pWC)).FpWInfo)).FpParse)).Fdb
|
|
if (*TWhereClause)(unsafe.Pointer(pWC)).FnTerm > 0 {
|
|
a = (*TWhereClause)(unsafe.Pointer(pWC)).Fa
|
|
aLast = (*TWhereClause)(unsafe.Pointer(pWC)).Fa + uintptr((*TWhereClause)(unsafe.Pointer(pWC)).FnTerm-int32(1))*56
|
|
for int32(1) != 0 {
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(a)).FwtFlags)&int32(TERM_DYNAMIC) != 0 {
|
|
_sqlite3ExprDelete(tls, db, (*TWhereTerm)(unsafe.Pointer(a)).FpExpr)
|
|
}
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(a)).FwtFlags)&(libc.Int32FromInt32(TERM_ORINFO)|libc.Int32FromInt32(TERM_ANDINFO)) != 0 {
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(a)).FwtFlags)&int32(TERM_ORINFO) != 0 {
|
|
_whereOrInfoDelete(tls, db, *(*uintptr)(unsafe.Pointer(a + 32)))
|
|
} else {
|
|
_whereAndInfoDelete(tls, db, *(*uintptr)(unsafe.Pointer(a + 32)))
|
|
}
|
|
}
|
|
if a == aLast {
|
|
break
|
|
}
|
|
a += 56
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Initialize a preallocated WhereClause structure.
|
|
// */
|
|
func _sqlite3WhereClauseInit(tls *libc.TLS, pWC uintptr, pWInfo uintptr) {
|
|
(*TWhereClause)(unsafe.Pointer(pWC)).FpWInfo = pWInfo
|
|
(*TWhereClause)(unsafe.Pointer(pWC)).FhasOr = uint8(0)
|
|
(*TWhereClause)(unsafe.Pointer(pWC)).FpOuter = uintptr(0)
|
|
(*TWhereClause)(unsafe.Pointer(pWC)).FnTerm = 0
|
|
(*TWhereClause)(unsafe.Pointer(pWC)).FnBase = 0
|
|
(*TWhereClause)(unsafe.Pointer(pWC)).FnSlot = libc.Int32FromUint64(libc.Uint64FromInt64(448) / libc.Uint64FromInt64(56))
|
|
(*TWhereClause)(unsafe.Pointer(pWC)).Fa = pWC + 40
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** These routines walk (recursively) an expression tree and generate
|
|
// ** a bitmask indicating which tables are used in that expression
|
|
// ** tree.
|
|
// **
|
|
// ** sqlite3WhereExprUsage(MaskSet, Expr) ->
|
|
// **
|
|
// ** Return a Bitmask of all tables referenced by Expr. Expr can be
|
|
// ** be NULL, in which case 0 is returned.
|
|
// **
|
|
// ** sqlite3WhereExprUsageNN(MaskSet, Expr) ->
|
|
// **
|
|
// ** Same as sqlite3WhereExprUsage() except that Expr must not be
|
|
// ** NULL. The "NN" suffix on the name stands for "Not Null".
|
|
// **
|
|
// ** sqlite3WhereExprListUsage(MaskSet, ExprList) ->
|
|
// **
|
|
// ** Return a Bitmask of all tables referenced by every expression
|
|
// ** in the expression list ExprList. ExprList can be NULL, in which
|
|
// ** case 0 is returned.
|
|
// **
|
|
// ** sqlite3WhereExprUsageFull(MaskSet, ExprList) ->
|
|
// **
|
|
// ** Internal use only. Called only by sqlite3WhereExprUsageNN() for
|
|
// ** complex expressions that require pushing register values onto
|
|
// ** the stack. Many calls to sqlite3WhereExprUsageNN() do not need
|
|
// ** the more complex analysis done by this routine. Hence, the
|
|
// ** computations done by this routine are broken out into a separate
|
|
// ** "no-inline" function to avoid the stack push overhead in the
|
|
// ** common case where it is not needed.
|
|
// */
|
|
func _sqlite3WhereExprUsageFull(tls *libc.TLS, pMaskSet uintptr, p uintptr) (r TBitmask) {
|
|
var mask TBitmask
|
|
var v1 uint64
|
|
_, _ = mask, v1
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) == int32(TK_IF_NULL_ROW) {
|
|
v1 = _sqlite3WhereGetMask(tls, pMaskSet, (*TExpr)(unsafe.Pointer(p)).FiTable)
|
|
} else {
|
|
v1 = uint64(0)
|
|
}
|
|
mask = v1
|
|
if (*TExpr)(unsafe.Pointer(p)).FpLeft != 0 {
|
|
mask = mask | _sqlite3WhereExprUsageNN(tls, pMaskSet, (*TExpr)(unsafe.Pointer(p)).FpLeft)
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(p)).FpRight != 0 {
|
|
mask = mask | _sqlite3WhereExprUsageNN(tls, pMaskSet, (*TExpr)(unsafe.Pointer(p)).FpRight)
|
|
} else {
|
|
if (*TExpr)(unsafe.Pointer(p)).Fflags&uint32(EP_xIsSelect) != uint32(0) {
|
|
if (*TExpr)(unsafe.Pointer(p)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_VarSelect)) != uint32(0) {
|
|
(*TWhereMaskSet)(unsafe.Pointer(pMaskSet)).FbVarSelect = int32(1)
|
|
}
|
|
mask = mask | _exprSelectUsage(tls, pMaskSet, *(*uintptr)(unsafe.Pointer(p + 32)))
|
|
} else {
|
|
if *(*uintptr)(unsafe.Pointer(p + 32)) != 0 {
|
|
mask = mask | _sqlite3WhereExprListUsage(tls, pMaskSet, *(*uintptr)(unsafe.Pointer(p + 32)))
|
|
}
|
|
}
|
|
}
|
|
if (libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) == int32(TK_FUNCTION) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) == int32(TK_AGG_FUNCTION)) && (*TExpr)(unsafe.Pointer(p)).Fflags&uint32(EP_WinFunc) != uint32(0) {
|
|
mask = mask | _sqlite3WhereExprListUsage(tls, pMaskSet, (*TWindow)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(p + 64)))).FpPartition)
|
|
mask = mask | _sqlite3WhereExprListUsage(tls, pMaskSet, (*TWindow)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(p + 64)))).FpOrderBy)
|
|
mask = mask | _sqlite3WhereExprUsage(tls, pMaskSet, (*TWindow)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(p + 64)))).FpFilter)
|
|
}
|
|
return mask
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Search for a term in the WHERE clause that is of the form "X <op> <expr>"
|
|
// ** where X is a reference to the iColumn of table iCur or of index pIdx
|
|
// ** if pIdx!=0 and <op> is one of the WO_xx operator codes specified by
|
|
// ** the op parameter. Return a pointer to the term. Return 0 if not found.
|
|
// **
|
|
// ** If pIdx!=0 then it must be one of the indexes of table iCur.
|
|
// ** Search for terms matching the iColumn-th column of pIdx
|
|
// ** rather than the iColumn-th column of table iCur.
|
|
// **
|
|
// ** The term returned might by Y=<expr> if there is another constraint in
|
|
// ** the WHERE clause that specifies that X=Y. Any such constraints will be
|
|
// ** identified by the WO_EQUIV bit in the pTerm->eOperator field. The
|
|
// ** aiCur[]/iaColumn[] arrays hold X and all its equivalents. There are 11
|
|
// ** slots in aiCur[]/aiColumn[] so that means we can look for X plus up to 10
|
|
// ** other equivalent values. Hence a search for X will return <expr> if X=A1
|
|
// ** and A1=A2 and A2=A3 and ... and A9=A10 and A10=<expr>.
|
|
// **
|
|
// ** If there are multiple terms in the WHERE clause of the form "X <op> <expr>"
|
|
// ** then try for the one with no dependencies on <expr> - in other words where
|
|
// ** <expr> is a constant expression of some kind. Only return entries of
|
|
// ** the form "X <op> Y" where Y is a column in another table if no terms of
|
|
// ** the form "X <op> <const-expr>" exist. If no terms with a constant RHS
|
|
// ** exist, try to return a term that does not use WO_EQUIV.
|
|
// */
|
|
func _sqlite3WhereFindTerm(tls *libc.TLS, pWC uintptr, iCur int32, iColumn int32, notReady TBitmask, op Tu32, pIdx uintptr) (r uintptr) {
|
|
bp := tls.Alloc(112)
|
|
defer tls.Free(112)
|
|
var p, pResult uintptr
|
|
var _ /* scan at bp+0 */ TWhereScan
|
|
_, _ = p, pResult
|
|
pResult = uintptr(0)
|
|
p = _whereScanInit(tls, bp, pWC, iCur, iColumn, op, pIdx)
|
|
op = op & libc.Uint32FromInt32(libc.Int32FromInt32(WO_EQ)|libc.Int32FromInt32(WO_IS))
|
|
for p != 0 {
|
|
if (*TWhereTerm)(unsafe.Pointer(p)).FprereqRight¬Ready == uint64(0) {
|
|
if (*TWhereTerm)(unsafe.Pointer(p)).FprereqRight == uint64(0) && uint32((*TWhereTerm)(unsafe.Pointer(p)).FeOperator)&op != uint32(0) {
|
|
return p
|
|
}
|
|
if pResult == uintptr(0) {
|
|
pResult = p
|
|
}
|
|
}
|
|
p = _whereScanNext(tls, bp)
|
|
}
|
|
return pResult
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** While generating code for the min/max optimization, after handling
|
|
// ** the aggregate-step call to min() or max(), check to see if any
|
|
// ** additional looping is required. If the output order is such that
|
|
// ** we are certain that the correct answer has already been found, then
|
|
// ** code an OP_Goto to by pass subsequent processing.
|
|
// **
|
|
// ** Any extra OP_Goto that is coded here is an optimization. The
|
|
// ** correct answer should be obtained regardless. This OP_Goto just
|
|
// ** makes the answer appear faster.
|
|
// */
|
|
func _sqlite3WhereMinMaxOptEarlyOut(tls *libc.TLS, v uintptr, pWInfo uintptr) {
|
|
var i int32
|
|
var pInner uintptr
|
|
_, _ = i, pInner
|
|
if !(int32(uint32(*(*uint8)(unsafe.Pointer(pWInfo + 68))&0x4>>2)) != 0) {
|
|
return
|
|
}
|
|
if int32((*TWhereInfo)(unsafe.Pointer(pWInfo)).FnOBSat) == 0 {
|
|
return
|
|
}
|
|
i = libc.Int32FromUint8((*TWhereInfo)(unsafe.Pointer(pWInfo)).FnLevel) - int32(1)
|
|
for {
|
|
if !(i >= 0) {
|
|
break
|
|
}
|
|
pInner = pWInfo + 856 + uintptr(i)*112
|
|
if (*TWhereLoop)(unsafe.Pointer((*TWhereLevel)(unsafe.Pointer(pInner)).FpWLoop)).FwsFlags&uint32(WHERE_COLUMN_IN) != uint32(0) {
|
|
_sqlite3VdbeGoto(tls, v, (*TWhereLevel)(unsafe.Pointer(pInner)).FaddrNxt)
|
|
return
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i - 1
|
|
}
|
|
_sqlite3VdbeGoto(tls, v, (*TWhereInfo)(unsafe.Pointer(pWInfo)).FiBreak)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** In the ORDER BY LIMIT optimization, if the inner-most loop is known
|
|
// ** to emit rows in increasing order, and if the last row emitted by the
|
|
// ** inner-most loop did not fit within the sorter, then we can skip all
|
|
// ** subsequent rows for the current iteration of the inner loop (because they
|
|
// ** will not fit in the sorter either) and continue with the second inner
|
|
// ** loop - the loop immediately outside the inner-most.
|
|
// **
|
|
// ** When a row does not fit in the sorter (because the sorter already
|
|
// ** holds LIMIT+OFFSET rows that are smaller), then a jump is made to the
|
|
// ** label returned by this function.
|
|
// **
|
|
// ** If the ORDER BY LIMIT optimization applies, the jump destination should
|
|
// ** be the continuation for the second-inner-most loop. If the ORDER BY
|
|
// ** LIMIT optimization does not apply, then the jump destination should
|
|
// ** be the continuation for the inner-most loop.
|
|
// **
|
|
// ** It is always safe for this routine to return the continuation of the
|
|
// ** inner-most loop, in the sense that a correct answer will result.
|
|
// ** Returning the continuation the second inner loop is an optimization
|
|
// ** that might make the code run a little faster, but should not change
|
|
// ** the final answer.
|
|
// */
|
|
func _sqlite3WhereOrderByLimitOptLabel(tls *libc.TLS, pWInfo uintptr) (r int32) {
|
|
var pInner uintptr
|
|
var v1 int32
|
|
_, _ = pInner, v1
|
|
if !(int32(uint32(*(*uint8)(unsafe.Pointer(pWInfo + 68))&0x4>>2)) != 0) {
|
|
/* The ORDER BY LIMIT optimization does not apply. Jump to the
|
|
** continuation of the inner-most loop. */
|
|
return (*TWhereInfo)(unsafe.Pointer(pWInfo)).FiContinue
|
|
}
|
|
pInner = pWInfo + 856 + uintptr(libc.Int32FromUint8((*TWhereInfo)(unsafe.Pointer(pWInfo)).FnLevel)-int32(1))*112
|
|
if (*TWhereLevel)(unsafe.Pointer(pInner)).FpRJ != 0 {
|
|
v1 = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FiContinue
|
|
} else {
|
|
v1 = (*TWhereLevel)(unsafe.Pointer(pInner)).FaddrNxt
|
|
}
|
|
return v1
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Register those built-in window functions that are not also aggregates.
|
|
// */
|
|
func _sqlite3WindowFunctions(tls *libc.TLS) {
|
|
_sqlite3InsertBuiltinFuncs(tls, uintptr(unsafe.Pointer(&_aWindowFuncs)), libc.Int32FromUint64(libc.Uint64FromInt64(1080)/libc.Uint64FromInt64(72)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Create and return a deep copy of the object passed as the second
|
|
// ** argument. If an OOM condition is encountered, NULL is returned
|
|
// ** and the db->mallocFailed flag set.
|
|
// */
|
|
func _sqlite3WithDup(tls *libc.TLS, db uintptr, p uintptr) (r uintptr) {
|
|
var i int32
|
|
var nByte Tsqlite3_int64
|
|
var pRet uintptr
|
|
_, _, _ = i, nByte, pRet
|
|
pRet = uintptr(0)
|
|
if p != 0 {
|
|
nByte = libc.Int64FromUint64(uint64(libc.UintptrFromInt32(0)+16) + libc.Uint64FromInt32((*TWith)(unsafe.Pointer(p)).FnCte)*libc.Uint64FromInt64(48))
|
|
pRet = _sqlite3DbMallocZero(tls, db, libc.Uint64FromInt64(nByte))
|
|
if pRet != 0 {
|
|
(*TWith)(unsafe.Pointer(pRet)).FnCte = (*TWith)(unsafe.Pointer(p)).FnCte
|
|
i = 0
|
|
for {
|
|
if !(i < (*TWith)(unsafe.Pointer(p)).FnCte) {
|
|
break
|
|
}
|
|
(*(*TCte)(unsafe.Pointer(pRet + 16 + uintptr(i)*48))).FpSelect = _sqlite3SelectDup(tls, db, (*(*TCte)(unsafe.Pointer(p + 16 + uintptr(i)*48))).FpSelect, 0)
|
|
(*(*TCte)(unsafe.Pointer(pRet + 16 + uintptr(i)*48))).FpCols = _sqlite3ExprListDup(tls, db, (*(*TCte)(unsafe.Pointer(p + 16 + uintptr(i)*48))).FpCols, 0)
|
|
(*(*TCte)(unsafe.Pointer(pRet + 16 + uintptr(i)*48))).FzName = _sqlite3DbStrDup(tls, db, (*(*TCte)(unsafe.Pointer(p + 16 + uintptr(i)*48))).FzName)
|
|
(*(*TCte)(unsafe.Pointer(pRet + 16 + uintptr(i)*48))).FeM10d = (*(*TCte)(unsafe.Pointer(p + 16 + uintptr(i)*48))).FeM10d
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
}
|
|
return pRet
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine implements a busy callback that sleeps and tries
|
|
// ** again until a timeout value is reached. The timeout value is
|
|
// ** an integer number of milliseconds passed in as the first
|
|
// ** argument.
|
|
// **
|
|
// ** Return non-zero to retry the lock. Return zero to stop trying
|
|
// ** and cause SQLite to return SQLITE_BUSY.
|
|
// */
|
|
func _sqliteDefaultBusyCallback(tls *libc.TLS, ptr uintptr, count int32) (r int32) {
|
|
var db uintptr
|
|
var delay, prior, tmout int32
|
|
_, _, _, _ = db, delay, prior, tmout
|
|
db = ptr
|
|
tmout = (*Tsqlite3)(unsafe.Pointer(db)).FbusyTimeout
|
|
if count < libc.Int32FromUint64(libc.Uint64FromInt64(12)/libc.Uint64FromInt64(1)) {
|
|
delay = libc.Int32FromUint8(_delays[count])
|
|
prior = libc.Int32FromUint8(_totals[count])
|
|
} else {
|
|
delay = libc.Int32FromUint8(_delays[libc.Int32FromUint64(libc.Uint64FromInt64(12)/libc.Uint64FromInt64(1))-libc.Int32FromInt32(1)])
|
|
prior = libc.Int32FromUint8(_totals[libc.Int32FromUint64(libc.Uint64FromInt64(12)/libc.Uint64FromInt64(1))-libc.Int32FromInt32(1)]) + delay*(count-(libc.Int32FromUint64(libc.Uint64FromInt64(12)/libc.Uint64FromInt64(1))-libc.Int32FromInt32(1)))
|
|
}
|
|
if prior+delay > tmout {
|
|
delay = tmout - prior
|
|
if delay <= 0 {
|
|
return 0
|
|
}
|
|
}
|
|
_sqlite3OsSleep(tls, (*Tsqlite3)(unsafe.Pointer(db)).FpVfs, delay*int32(1000))
|
|
return int32(1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Clear the column names from every VIEW in database idx.
|
|
// */
|
|
func _sqliteViewResetAll(tls *libc.TLS, db uintptr, idx int32) {
|
|
var i, pTab, v2 uintptr
|
|
_, _, _ = i, pTab, v2
|
|
if !(libc.Int32FromUint16((*TSchema)(unsafe.Pointer((**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(idx)*32))).FpSchema)).FschemaFlags)&libc.Int32FromInt32(DB_UnresetViews) == libc.Int32FromInt32(DB_UnresetViews)) {
|
|
return
|
|
}
|
|
i = (*THash)(unsafe.Pointer((**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(idx)*32))).FpSchema + 8)).Ffirst
|
|
for {
|
|
if !(i != 0) {
|
|
break
|
|
}
|
|
pTab = (*THashElem)(unsafe.Pointer(i)).Fdata
|
|
if libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == int32(TABTYP_VIEW) {
|
|
_sqlite3DeleteColumnNames(tls, db, pTab)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = (*THashElem)(unsafe.Pointer(i)).Fnext
|
|
}
|
|
v2 = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(idx)*32))).FpSchema + 114
|
|
*(*Tu16)(unsafe.Pointer(v2)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v2))) & ^libc.Int32FromInt32(DB_UnresetViews))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Attempt to extract a value from pExpr and use it to construct *ppVal.
|
|
// **
|
|
// ** If pAlloc is not NULL, then an UnpackedRecord object is created for
|
|
// ** pAlloc if one does not exist and the new value is added to the
|
|
// ** UnpackedRecord object.
|
|
// **
|
|
// ** A value is extracted in the following cases:
|
|
// **
|
|
// ** * (pExpr==0). In this case the value is assumed to be an SQL NULL,
|
|
// **
|
|
// ** * The expression is a bound variable, and this is a reprepare, or
|
|
// **
|
|
// ** * The expression is a literal value.
|
|
// **
|
|
// ** On success, *ppVal is made to point to the extracted value. The caller
|
|
// ** is responsible for ensuring that the value is eventually freed.
|
|
// */
|
|
func _stat4ValueFromExpr(tls *libc.TLS, pParse uintptr, pExpr uintptr, affinity Tu8, pAlloc uintptr, ppVal uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var db, v, v1 uintptr
|
|
var iBindVar, rc int32
|
|
var _ /* pVal at bp+0 */ uintptr
|
|
_, _, _, _, _ = db, iBindVar, rc, v, v1
|
|
rc = SQLITE_OK
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
/* Skip over any TK_COLLATE nodes */
|
|
pExpr = _sqlite3ExprSkipCollate(tls, pExpr)
|
|
if !(pExpr != 0) {
|
|
**(**uintptr)(__ccgo_up(bp)) = _valueNew(tls, db, pAlloc)
|
|
if **(**uintptr)(__ccgo_up(bp)) != 0 {
|
|
_sqlite3VdbeMemSetNull(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_VARIABLE) && (*Tsqlite3)(unsafe.Pointer(db)).Fflags&uint64(SQLITE_EnableQPSG) == uint64(0) {
|
|
iBindVar = int32((*TExpr)(unsafe.Pointer(pExpr)).FiColumn)
|
|
_sqlite3VdbeSetVarmask(tls, (*TParse)(unsafe.Pointer(pParse)).FpVdbe, iBindVar)
|
|
v1 = (*TParse)(unsafe.Pointer(pParse)).FpReprepare
|
|
v = v1
|
|
if v1 != uintptr(0) {
|
|
**(**uintptr)(__ccgo_up(bp)) = _valueNew(tls, db, pAlloc)
|
|
if **(**uintptr)(__ccgo_up(bp)) != 0 {
|
|
rc = _sqlite3VdbeMemCopy(tls, **(**uintptr)(__ccgo_up(bp)), (*TVdbe)(unsafe.Pointer(v)).FaVar+uintptr(iBindVar-int32(1))*56)
|
|
_sqlite3ValueApplyAffinity(tls, **(**uintptr)(__ccgo_up(bp)), affinity, (*Tsqlite3)(unsafe.Pointer(db)).Fenc)
|
|
(*Tsqlite3_value)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).Fdb = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
}
|
|
}
|
|
} else {
|
|
rc = _valueFromExpr(tls, db, pExpr, (*Tsqlite3)(unsafe.Pointer(db)).Fenc, affinity, bp, pAlloc)
|
|
}
|
|
}
|
|
**(**uintptr)(__ccgo_up(ppVal)) = **(**uintptr)(__ccgo_up(bp))
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Compute the best query strategy and return the result in idxNum.
|
|
// **
|
|
// ** idxNum-Bit Meaning
|
|
// ** ---------- ----------------------------------------------
|
|
// ** 0x01 There is a schema=? term in the WHERE clause
|
|
// ** 0x02 There is a name=? term in the WHERE clause
|
|
// ** 0x04 There is an aggregate=? term in the WHERE clause
|
|
// ** 0x08 Output should be ordered by name and path
|
|
// */
|
|
func _statBestIndex(tls *libc.TLS, tab uintptr, pIdxInfo uintptr) (r int32) {
|
|
var i, iAgg, iName, iSchema, v2 int32
|
|
_, _, _, _, _ = i, iAgg, iName, iSchema, v2
|
|
iSchema = -int32(1)
|
|
iName = -int32(1)
|
|
iAgg = -int32(1)
|
|
_ = tab
|
|
/* Look for a valid schema=? constraint. If found, change the idxNum to
|
|
** 1 and request the value of that constraint be sent to xFilter. And
|
|
** lower the cost estimate to encourage the constrained version to be
|
|
** used.
|
|
*/
|
|
i = 0
|
|
for {
|
|
if !(i < (*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FnConstraint) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((**(**Tsqlite3_index_constraint)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraint + uintptr(i)*12))).Fop) != int32(SQLITE_INDEX_CONSTRAINT_EQ) {
|
|
goto _1
|
|
}
|
|
if libc.Int32FromUint8((**(**Tsqlite3_index_constraint)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraint + uintptr(i)*12))).Fusable) == 0 {
|
|
/* Force DBSTAT table should always be the right-most table in a join */
|
|
return int32(SQLITE_CONSTRAINT)
|
|
}
|
|
switch (**(**Tsqlite3_index_constraint)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraint + uintptr(i)*12))).FiColumn {
|
|
case 0: /* name */
|
|
iName = i
|
|
case int32(10): /* schema */
|
|
iSchema = i
|
|
case int32(11): /* aggregate */
|
|
iAgg = i
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
i = 0
|
|
if iSchema >= 0 {
|
|
i = i + 1
|
|
v2 = i
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraintUsage + uintptr(iSchema)*8))).FargvIndex = v2
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraintUsage + uintptr(iSchema)*8))).Fomit = uint8(1)
|
|
**(**int32)(__ccgo_up(pIdxInfo + 40)) |= int32(0x01)
|
|
}
|
|
if iName >= 0 {
|
|
i = i + 1
|
|
v2 = i
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraintUsage + uintptr(iName)*8))).FargvIndex = v2
|
|
**(**int32)(__ccgo_up(pIdxInfo + 40)) |= int32(0x02)
|
|
}
|
|
if iAgg >= 0 {
|
|
i = i + 1
|
|
v2 = i
|
|
(**(**Tsqlite3_index_constraint_usage)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaConstraintUsage + uintptr(iAgg)*8))).FargvIndex = v2
|
|
**(**int32)(__ccgo_up(pIdxInfo + 40)) |= int32(0x04)
|
|
}
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FestimatedCost = float64(1)
|
|
/* Records are always returned in ascending order of (name, path).
|
|
** If this will satisfy the client, set the orderByConsumed flag so that
|
|
** SQLite does not do an external sort.
|
|
*/
|
|
if (*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FnOrderBy == int32(1) && (**(**Tsqlite3_index_orderby)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaOrderBy))).FiColumn == 0 && libc.Int32FromUint8((**(**Tsqlite3_index_orderby)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaOrderBy))).Fdesc) == 0 || (*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FnOrderBy == int32(2) && (**(**Tsqlite3_index_orderby)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaOrderBy))).FiColumn == 0 && libc.Int32FromUint8((**(**Tsqlite3_index_orderby)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaOrderBy))).Fdesc) == 0 && (**(**Tsqlite3_index_orderby)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaOrderBy + 1*8))).FiColumn == int32(1) && libc.Int32FromUint8((**(**Tsqlite3_index_orderby)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).FaOrderBy + 1*8))).Fdesc) == 0 {
|
|
(*Tsqlite3_index_info)(unsafe.Pointer(pIdxInfo)).ForderByConsumed = int32(1)
|
|
**(**int32)(__ccgo_up(pIdxInfo + 40)) |= int32(0x08)
|
|
}
|
|
**(**int32)(__ccgo_up(pIdxInfo + 80)) |= int32(SQLITE_INDEX_SCAN_HEX)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
func _statColumn(tls *libc.TLS, pCursor uintptr, ctx uintptr, i int32) (r int32) {
|
|
var db, pCsr uintptr
|
|
var iDb int32
|
|
_, _, _ = db, iDb, pCsr
|
|
pCsr = pCursor
|
|
switch i {
|
|
case 0: /* name */
|
|
Xsqlite3_result_text(tls, ctx, (*TStatCursor)(unsafe.Pointer(pCsr)).FzName, -int32(1), uintptr(-libc.Int32FromInt32(1)))
|
|
case int32(1): /* path */
|
|
if !((*TStatCursor)(unsafe.Pointer(pCsr)).FisAgg != 0) {
|
|
Xsqlite3_result_text(tls, ctx, (*TStatCursor)(unsafe.Pointer(pCsr)).FzPath, -int32(1), uintptr(-libc.Int32FromInt32(1)))
|
|
}
|
|
case int32(2): /* pageno */
|
|
if (*TStatCursor)(unsafe.Pointer(pCsr)).FisAgg != 0 {
|
|
Xsqlite3_result_int64(tls, ctx, int64((*TStatCursor)(unsafe.Pointer(pCsr)).FnPage))
|
|
} else {
|
|
Xsqlite3_result_int64(tls, ctx, libc.Int64FromUint32((*TStatCursor)(unsafe.Pointer(pCsr)).FiPageno))
|
|
}
|
|
case int32(3): /* pagetype */
|
|
if !((*TStatCursor)(unsafe.Pointer(pCsr)).FisAgg != 0) {
|
|
Xsqlite3_result_text(tls, ctx, (*TStatCursor)(unsafe.Pointer(pCsr)).FzPagetype, -int32(1), libc.UintptrFromInt32(0))
|
|
}
|
|
case int32(4): /* ncell */
|
|
Xsqlite3_result_int64(tls, ctx, int64((*TStatCursor)(unsafe.Pointer(pCsr)).FnCell))
|
|
case int32(5): /* payload */
|
|
Xsqlite3_result_int64(tls, ctx, (*TStatCursor)(unsafe.Pointer(pCsr)).FnPayload)
|
|
case int32(6): /* unused */
|
|
Xsqlite3_result_int64(tls, ctx, (*TStatCursor)(unsafe.Pointer(pCsr)).FnUnused)
|
|
case int32(7): /* mx_payload */
|
|
Xsqlite3_result_int64(tls, ctx, int64((*TStatCursor)(unsafe.Pointer(pCsr)).FnMxPayload))
|
|
case int32(8): /* pgoffset */
|
|
if !((*TStatCursor)(unsafe.Pointer(pCsr)).FisAgg != 0) {
|
|
Xsqlite3_result_int64(tls, ctx, (*TStatCursor)(unsafe.Pointer(pCsr)).FiOffset)
|
|
}
|
|
case int32(9): /* pgsize */
|
|
Xsqlite3_result_int64(tls, ctx, (*TStatCursor)(unsafe.Pointer(pCsr)).FszPage)
|
|
case int32(10): /* schema */
|
|
db = Xsqlite3_context_db_handle(tls, ctx)
|
|
iDb = (*TStatCursor)(unsafe.Pointer(pCsr)).FiDb
|
|
Xsqlite3_result_text(tls, ctx, (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer(db)).FaDb + uintptr(iDb)*32))).FzDbSName, -int32(1), libc.UintptrFromInt32(0))
|
|
default: /* aggregate */
|
|
Xsqlite3_result_int(tls, ctx, libc.Int32FromUint8((*TStatCursor)(unsafe.Pointer(pCsr)).FisAgg))
|
|
break
|
|
}
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Implementation of the stat_init(N,K,C,L) SQL function. The four parameters
|
|
// ** are:
|
|
// ** N: The number of columns in the index including the rowid/pk (note 1)
|
|
// ** K: The number of columns in the index excluding the rowid/pk.
|
|
// ** C: Estimated number of rows in the index
|
|
// ** L: A limit on the number of rows to scan, or 0 for no-limit
|
|
// **
|
|
// ** Note 1: In the special case of the covering index that implements a
|
|
// ** WITHOUT ROWID table, N is the number of PRIMARY KEY columns, not the
|
|
// ** total number of columns in the table.
|
|
// **
|
|
// ** For indexes on ordinary rowid tables, N==K+1. But for indexes on
|
|
// ** WITHOUT ROWID tables, N=K+P where P is the number of columns in the
|
|
// ** PRIMARY KEY of the table. The covering index that implements the
|
|
// ** original WITHOUT ROWID table as N==K as a special case.
|
|
// **
|
|
// ** This routine allocates the StatAccum object in heap memory. The return
|
|
// ** value is a pointer to the StatAccum object. The datatype of the
|
|
// ** return value is BLOB, but it is really just a pointer to the StatAccum
|
|
// ** object.
|
|
// */
|
|
func _statInit(tls *libc.TLS, context uintptr, argc int32, argv uintptr) {
|
|
var db, p, pSpace uintptr
|
|
var i, mxSample, nCol, nColUp, nKeyCol, v1 int32
|
|
var n Ti64
|
|
_, _, _, _, _, _, _, _, _, _ = db, i, mxSample, n, nCol, nColUp, nKeyCol, p, pSpace, v1 /* Bytes of space to allocate */
|
|
db = Xsqlite3_context_db_handle(tls, context)
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FdbOptFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_Stat4)) == uint32(0) {
|
|
v1 = int32(SQLITE_STAT4_SAMPLES)
|
|
} else {
|
|
v1 = 0
|
|
} /* Database connection */
|
|
/* Maximum number of samples. 0 if STAT4 data is not collected */
|
|
mxSample = v1
|
|
/* Decode the three function arguments */
|
|
_ = argc
|
|
nCol = Xsqlite3_value_int(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
nColUp = nCol
|
|
nKeyCol = Xsqlite3_value_int(tls, **(**uintptr)(__ccgo_up(argv + 1*8)))
|
|
/* Allocate the space required for the StatAccum object */
|
|
n = libc.Int64FromUint64(uint64(136) + uint64(8)*libc.Uint64FromInt32(nColUp)) /* StatAccum.anDLt */
|
|
n = libc.Int64FromUint64(uint64(n) + uint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(nColUp))) /* StatAccum.anEq */
|
|
if mxSample != 0 {
|
|
n = libc.Int64FromUint64(uint64(n) + uint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(nColUp)+libc.Uint64FromInt64(48)*libc.Uint64FromInt32(nCol+mxSample)+libc.Uint64FromInt64(8)*libc.Uint64FromInt32(3)*libc.Uint64FromInt32(nColUp)*libc.Uint64FromInt32(nCol+mxSample)))
|
|
}
|
|
p = _sqlite3DbMallocZero(tls, db, libc.Uint64FromInt64(n))
|
|
if p == uintptr(0) {
|
|
Xsqlite3_result_error_nomem(tls, context)
|
|
return
|
|
}
|
|
(*TStatAccum)(unsafe.Pointer(p)).Fdb = db
|
|
(*TStatAccum)(unsafe.Pointer(p)).FnEst = libc.Uint64FromInt64(Xsqlite3_value_int64(tls, **(**uintptr)(__ccgo_up(argv + 2*8))))
|
|
(*TStatAccum)(unsafe.Pointer(p)).FnRow = uint64(0)
|
|
(*TStatAccum)(unsafe.Pointer(p)).FnLimit = Xsqlite3_value_int(tls, **(**uintptr)(__ccgo_up(argv + 3*8)))
|
|
(*TStatAccum)(unsafe.Pointer(p)).FnCol = nCol
|
|
(*TStatAccum)(unsafe.Pointer(p)).FnKeyCol = nKeyCol
|
|
(*TStatAccum)(unsafe.Pointer(p)).FnSkipAhead = uint8(0)
|
|
(*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FanDLt = p + 1*136
|
|
(*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FanEq = (*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FanDLt + uintptr(nColUp)*8
|
|
if (*TStatAccum)(unsafe.Pointer(p)).FnLimit == 0 {
|
|
v1 = mxSample
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
(*TStatAccum)(unsafe.Pointer(p)).FmxSample = v1
|
|
if mxSample != 0 { /* Used to iterate through p->aSample[] */
|
|
(*TStatAccum)(unsafe.Pointer(p)).FiGet = -int32(1)
|
|
(*TStatAccum)(unsafe.Pointer(p)).FnPSample = (*TStatAccum)(unsafe.Pointer(p)).FnEst/libc.Uint64FromInt32(mxSample/libc.Int32FromInt32(3)+libc.Int32FromInt32(1)) + libc.Uint64FromInt32(1)
|
|
(*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FanLt = (*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FanEq + uintptr(nColUp)*8
|
|
(*TStatAccum)(unsafe.Pointer(p)).FiPrn = uint32(0x689e962d)*libc.Uint32FromInt32(nCol) ^ uint32(0xd0944565)*libc.Uint32FromInt32(Xsqlite3_value_int(tls, **(**uintptr)(__ccgo_up(argv + 2*8))))
|
|
/* Set up the StatAccum.a[] and aBest[] arrays */
|
|
(*TStatAccum)(unsafe.Pointer(p)).Fa = (*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FanLt + uintptr(nColUp)*8
|
|
(*TStatAccum)(unsafe.Pointer(p)).FaBest = (*TStatAccum)(unsafe.Pointer(p)).Fa + uintptr(mxSample)*48
|
|
pSpace = (*TStatAccum)(unsafe.Pointer(p)).Fa + uintptr(mxSample+nCol)*48
|
|
i = 0
|
|
for {
|
|
if !(i < mxSample+nCol) {
|
|
break
|
|
}
|
|
(**(**TStatSample)(__ccgo_up((*TStatAccum)(unsafe.Pointer(p)).Fa + uintptr(i)*48))).FanEq = pSpace
|
|
pSpace = pSpace + uintptr(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(nColUp))
|
|
(**(**TStatSample)(__ccgo_up((*TStatAccum)(unsafe.Pointer(p)).Fa + uintptr(i)*48))).FanLt = pSpace
|
|
pSpace = pSpace + uintptr(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(nColUp))
|
|
(**(**TStatSample)(__ccgo_up((*TStatAccum)(unsafe.Pointer(p)).Fa + uintptr(i)*48))).FanDLt = pSpace
|
|
pSpace = pSpace + uintptr(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(nColUp))
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = i + 1
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < nCol) {
|
|
break
|
|
}
|
|
(**(**TStatSample)(__ccgo_up((*TStatAccum)(unsafe.Pointer(p)).FaBest + uintptr(i)*48))).FiCol = i
|
|
goto _4
|
|
_4:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
/* Return a pointer to the allocated object to the caller. Note that
|
|
** only the pointer (the 2nd parameter) matters. The size of the object
|
|
** (given by the 3rd parameter) is never used and can be any positive
|
|
** value. */
|
|
Xsqlite3_result_blob(tls, context, p, int32(136), __ccgo_fp(_statAccumDestructor))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Implementation of the stat_push SQL function: stat_push(P,C,R)
|
|
// ** Arguments:
|
|
// **
|
|
// ** P Pointer to the StatAccum object created by stat_init()
|
|
// ** C Index of left-most column to differ from previous row
|
|
// ** R Rowid for the current row. Might be a key record for
|
|
// ** WITHOUT ROWID tables.
|
|
// **
|
|
// ** The purpose of this routine is to collect statistical data and/or
|
|
// ** samples from the index being analyzed into the StatAccum object.
|
|
// ** The stat_get() SQL function will be used afterwards to
|
|
// ** retrieve the information gathered.
|
|
// **
|
|
// ** This SQL function usually returns NULL, but might return an integer
|
|
// ** if it wants the byte-code to do special processing.
|
|
// **
|
|
// ** The R parameter is only used for STAT4
|
|
// */
|
|
func _statPush(tls *libc.TLS, context uintptr, argc int32, argv uintptr) {
|
|
var i, iChng int32
|
|
var nLt TtRowcnt
|
|
var p uintptr
|
|
var v4 Tu32
|
|
_, _, _, _, _ = i, iChng, nLt, p, v4
|
|
/* The three function arguments */
|
|
p = Xsqlite3_value_blob(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
iChng = Xsqlite3_value_int(tls, **(**uintptr)(__ccgo_up(argv + 1*8)))
|
|
_ = argc
|
|
_ = context
|
|
if (*TStatAccum)(unsafe.Pointer(p)).FnRow == uint64(0) {
|
|
/* This is the first call to this function. Do initialization. */
|
|
i = 0
|
|
for {
|
|
if !(i < (*TStatAccum)(unsafe.Pointer(p)).FnCol) {
|
|
break
|
|
}
|
|
**(**TtRowcnt)(__ccgo_up((*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FanEq + uintptr(i)*8)) = uint64(1)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
} else {
|
|
/* Second and subsequent calls get processed here */
|
|
if (*TStatAccum)(unsafe.Pointer(p)).FmxSample != 0 {
|
|
_samplePushPrevious(tls, p, iChng)
|
|
}
|
|
/* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
|
|
** to the current row of the index. */
|
|
i = 0
|
|
for {
|
|
if !(i < iChng) {
|
|
break
|
|
}
|
|
**(**TtRowcnt)(__ccgo_up((*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FanEq + uintptr(i)*8)) = **(**TtRowcnt)(__ccgo_up((*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FanEq + uintptr(i)*8)) + 1
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
i = iChng
|
|
for {
|
|
if !(i < (*TStatAccum)(unsafe.Pointer(p)).FnCol) {
|
|
break
|
|
}
|
|
**(**TtRowcnt)(__ccgo_up((*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FanDLt + uintptr(i)*8)) = **(**TtRowcnt)(__ccgo_up((*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FanDLt + uintptr(i)*8)) + 1
|
|
if (*TStatAccum)(unsafe.Pointer(p)).FmxSample != 0 {
|
|
**(**TtRowcnt)(__ccgo_up((*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FanLt + uintptr(i)*8)) += **(**TtRowcnt)(__ccgo_up((*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FanEq + uintptr(i)*8))
|
|
}
|
|
**(**TtRowcnt)(__ccgo_up((*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FanEq + uintptr(i)*8)) = uint64(1)
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
(*TStatAccum)(unsafe.Pointer(p)).FnRow = (*TStatAccum)(unsafe.Pointer(p)).FnRow + 1
|
|
if (*TStatAccum)(unsafe.Pointer(p)).FmxSample != 0 {
|
|
if Xsqlite3_value_type(tls, **(**uintptr)(__ccgo_up(argv + 2*8))) == int32(SQLITE_INTEGER) {
|
|
_sampleSetRowidInt64(tls, (*TStatAccum)(unsafe.Pointer(p)).Fdb, p+40, Xsqlite3_value_int64(tls, **(**uintptr)(__ccgo_up(argv + 2*8))))
|
|
} else {
|
|
_sampleSetRowid(tls, (*TStatAccum)(unsafe.Pointer(p)).Fdb, p+40, Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(argv + 2*8))), Xsqlite3_value_blob(tls, **(**uintptr)(__ccgo_up(argv + 2*8))))
|
|
}
|
|
v4 = (*TStatAccum)(unsafe.Pointer(p)).FiPrn*libc.Uint32FromInt32(1103515245) + libc.Uint32FromInt32(12345)
|
|
(*TStatAccum)(unsafe.Pointer(p)).FiPrn = v4
|
|
(*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FiHash = v4
|
|
nLt = **(**TtRowcnt)(__ccgo_up((*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FanLt + uintptr((*TStatAccum)(unsafe.Pointer(p)).FnCol-int32(1))*8))
|
|
/* Check if this is to be a periodic sample. If so, add it. */
|
|
if nLt/(*TStatAccum)(unsafe.Pointer(p)).FnPSample != (nLt+uint64(1))/(*TStatAccum)(unsafe.Pointer(p)).FnPSample {
|
|
(*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FisPSample = uint8(1)
|
|
(*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FiCol = 0
|
|
_sampleInsert(tls, p, p+40, (*TStatAccum)(unsafe.Pointer(p)).FnCol-int32(1))
|
|
(*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FisPSample = uint8(0)
|
|
}
|
|
/* Update the aBest[] array. */
|
|
i = 0
|
|
for {
|
|
if !(i < (*TStatAccum)(unsafe.Pointer(p)).FnCol-int32(1)) {
|
|
break
|
|
}
|
|
(*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FiCol = i
|
|
if i >= iChng || _sampleIsBetterPost(tls, p, p+40, (*TStatAccum)(unsafe.Pointer(p)).FaBest+uintptr(i)*48) != 0 {
|
|
_sampleCopy(tls, p, (*TStatAccum)(unsafe.Pointer(p)).FaBest+uintptr(i)*48, p+40)
|
|
}
|
|
goto _5
|
|
_5:
|
|
;
|
|
i = i + 1
|
|
}
|
|
} else {
|
|
if (*TStatAccum)(unsafe.Pointer(p)).FnLimit != 0 && (*TStatAccum)(unsafe.Pointer(p)).FnRow > libc.Uint64FromInt32((*TStatAccum)(unsafe.Pointer(p)).FnLimit)*libc.Uint64FromInt32(libc.Int32FromUint8((*TStatAccum)(unsafe.Pointer(p)).FnSkipAhead)+libc.Int32FromInt32(1)) {
|
|
(*TStatAccum)(unsafe.Pointer(p)).FnSkipAhead = (*TStatAccum)(unsafe.Pointer(p)).FnSkipAhead + 1
|
|
Xsqlite3_result_int(tls, context, libc.BoolInt32(**(**TtRowcnt)(__ccgo_up((*TStatAccum)(unsafe.Pointer(p)).Fcurrent.FanDLt)) > uint64(0)))
|
|
}
|
|
}
|
|
}
|
|
|
|
func _statResetCsr(tls *libc.TLS, pCsr uintptr) {
|
|
var i int32
|
|
_ = i
|
|
/* In some circumstances, specifically if an OOM has occurred, the call
|
|
** to sqlite3_reset() may cause the pager to be reset (emptied). It is
|
|
** important that statClearPage() is called to free any page refs before
|
|
** this happens. dbsqlfuzz 9ed3e4e3816219d3509d711636c38542bf3f40b1. */
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint64(libc.Uint64FromInt64(2048)/libc.Uint64FromInt64(64))) {
|
|
break
|
|
}
|
|
_statClearPage(tls, pCsr+24+uintptr(i)*64)
|
|
Xsqlite3_free(tls, (**(**TStatPage)(__ccgo_up(pCsr + 24 + uintptr(i)*64))).FaPg)
|
|
(**(**TStatPage)(__ccgo_up(pCsr + 24 + uintptr(i)*64))).FaPg = uintptr(0)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
Xsqlite3_reset(tls, (*TStatCursor)(unsafe.Pointer(pCsr)).FpStmt)
|
|
(*TStatCursor)(unsafe.Pointer(pCsr)).FiPage = 0
|
|
Xsqlite3_free(tls, (*TStatCursor)(unsafe.Pointer(pCsr)).FzPath)
|
|
(*TStatCursor)(unsafe.Pointer(pCsr)).FzPath = uintptr(0)
|
|
(*TStatCursor)(unsafe.Pointer(pCsr)).FisEof = uint8(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on
|
|
// ** the current value of pCsr->iPageno.
|
|
// */
|
|
func _statSizeAndOffset(tls *libc.TLS, pCsr uintptr) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var fd, pBt, pPager, pTab uintptr
|
|
var _ /* x at bp+0 */ [2]Tsqlite3_int64
|
|
_, _, _, _ = fd, pBt, pPager, pTab
|
|
pTab = (*Tsqlite3_vtab_cursor)(unsafe.Pointer(pCsr)).FpVtab
|
|
pBt = (**(**TDb)(__ccgo_up((*Tsqlite3)(unsafe.Pointer((*TStatTable)(unsafe.Pointer(pTab)).Fdb)).FaDb + uintptr((*TStatTable)(unsafe.Pointer(pTab)).FiDb)*32))).FpBt
|
|
pPager = _sqlite3BtreePager(tls, pBt)
|
|
/* If connected to a ZIPVFS backend, find the page size and
|
|
** offset from ZIPVFS.
|
|
*/
|
|
fd = _sqlite3PagerFile(tls, pPager)
|
|
(**(**[2]Tsqlite3_int64)(__ccgo_up(bp)))[0] = libc.Int64FromUint32((*TStatCursor)(unsafe.Pointer(pCsr)).FiPageno)
|
|
if _sqlite3OsFileControl(tls, fd, int32(230440), bp) == SQLITE_OK {
|
|
(*TStatCursor)(unsafe.Pointer(pCsr)).FiOffset = (**(**[2]Tsqlite3_int64)(__ccgo_up(bp)))[0]
|
|
**(**Ti64)(__ccgo_up(pCsr + 2144)) += (**(**[2]Tsqlite3_int64)(__ccgo_up(bp)))[int32(1)]
|
|
} else {
|
|
/* Not ZIPVFS: The default page size and offset */
|
|
**(**Ti64)(__ccgo_up(pCsr + 2144)) += int64(_sqlite3BtreeGetPageSize(tls, pBt))
|
|
(*TStatCursor)(unsafe.Pointer(pCsr)).FiOffset = (*TStatCursor)(unsafe.Pointer(pCsr)).FszPage * libc.Int64FromUint32((*TStatCursor)(unsafe.Pointer(pCsr)).FiPageno-libc.Uint32FromInt32(1))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Implementation of the substr() function.
|
|
// **
|
|
// ** substr(x,p1,p2) returns p2 characters of x[] beginning with p1.
|
|
// ** p1 is 1-indexed. So substr(x,1,1) returns the first character
|
|
// ** of x. If x is text, then we actually count UTF-8 characters.
|
|
// ** If x is a blob, then we count bytes.
|
|
// **
|
|
// ** If p1 is negative, then we begin abs(p1) from the end of x[].
|
|
// **
|
|
// ** If p2 is negative, return the p2 characters preceding p1.
|
|
// */
|
|
func _substrFunc(tls *libc.TLS, context uintptr, argc int32, argv uintptr) {
|
|
var len1, p0type int32
|
|
var p1, p2, v6 Ti64
|
|
var z, z2, v2 uintptr
|
|
_, _, _, _, _, _, _, _ = len1, p0type, p1, p2, z, z2, v2, v6
|
|
p0type = Xsqlite3_value_type(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
p1 = Xsqlite3_value_int64(tls, **(**uintptr)(__ccgo_up(argv + 1*8)))
|
|
if p0type == int32(SQLITE_BLOB) {
|
|
len1 = Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
z = Xsqlite3_value_blob(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
if z == uintptr(0) {
|
|
return
|
|
}
|
|
} else {
|
|
z = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
if z == uintptr(0) {
|
|
return
|
|
}
|
|
len1 = 0
|
|
if p1 < 0 {
|
|
z2 = z
|
|
for {
|
|
if !(**(**uint8)(__ccgo_up(z2)) != 0) {
|
|
break
|
|
}
|
|
v2 = z2
|
|
z2 = z2 + 1
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(v2))) >= int32(0xc0) {
|
|
for libc.Int32FromUint8(**(**uint8)(__ccgo_up(z2)))&int32(0xc0) == int32(0x80) {
|
|
z2 = z2 + 1
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
len1 = len1 + 1
|
|
}
|
|
}
|
|
}
|
|
if argc == int32(3) {
|
|
p2 = Xsqlite3_value_int64(tls, **(**uintptr)(__ccgo_up(argv + 2*8)))
|
|
if p2 == 0 && Xsqlite3_value_type(tls, **(**uintptr)(__ccgo_up(argv + 2*8))) == int32(SQLITE_NULL) {
|
|
return
|
|
}
|
|
} else {
|
|
p2 = int64(**(**int32)(__ccgo_up(Xsqlite3_context_db_handle(tls, context) + 136)))
|
|
}
|
|
if p1 == 0 {
|
|
if Xsqlite3_value_type(tls, **(**uintptr)(__ccgo_up(argv + 1*8))) == int32(SQLITE_NULL) {
|
|
return
|
|
}
|
|
}
|
|
if p1 < 0 {
|
|
p1 = p1 + int64(len1)
|
|
if p1 < 0 {
|
|
if p2 < 0 {
|
|
p2 = 0
|
|
} else {
|
|
p2 = p2 + p1
|
|
}
|
|
p1 = 0
|
|
}
|
|
} else {
|
|
if p1 > 0 {
|
|
p1 = p1 - 1
|
|
} else {
|
|
if p2 > 0 {
|
|
p2 = p2 - 1
|
|
}
|
|
}
|
|
}
|
|
if p2 < 0 {
|
|
if p2 < -p1 {
|
|
p2 = p1
|
|
} else {
|
|
p2 = -p2
|
|
}
|
|
p1 = p1 - p2
|
|
}
|
|
if p0type != int32(SQLITE_BLOB) {
|
|
for **(**uint8)(__ccgo_up(z)) != 0 && p1 != 0 {
|
|
v2 = z
|
|
z = z + 1
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(v2))) >= int32(0xc0) {
|
|
for libc.Int32FromUint8(**(**uint8)(__ccgo_up(z)))&int32(0xc0) == int32(0x80) {
|
|
z = z + 1
|
|
}
|
|
}
|
|
p1 = p1 - 1
|
|
}
|
|
z2 = z
|
|
for {
|
|
if !(**(**uint8)(__ccgo_up(z2)) != 0 && p2 != 0) {
|
|
break
|
|
}
|
|
v2 = z2
|
|
z2 = z2 + 1
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(v2))) >= int32(0xc0) {
|
|
for libc.Int32FromUint8(**(**uint8)(__ccgo_up(z2)))&int32(0xc0) == int32(0x80) {
|
|
z2 = z2 + 1
|
|
}
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
p2 = p2 - 1
|
|
}
|
|
Xsqlite3_result_text64(tls, context, z, libc.Uint64FromInt64(int64(z2)-int64(z)), uintptr(-libc.Int32FromInt32(1)), uint8(SQLITE_UTF8))
|
|
} else {
|
|
if p1 >= int64(len1) {
|
|
v6 = libc.Int64FromInt32(0)
|
|
p2 = v6
|
|
p1 = v6
|
|
} else {
|
|
if p2 > int64(len1)-p1 {
|
|
p2 = int64(len1) - p1
|
|
}
|
|
}
|
|
Xsqlite3_result_blob64(tls, context, z+uintptr(p1), libc.Uint64FromInt64(p2), uintptr(-libc.Int32FromInt32(1)))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Search the tables iStart..iEnd (inclusive) in pSrc, looking for a
|
|
// ** table that has a column named zCol. The search is left-to-right.
|
|
// ** The first match found is returned.
|
|
// **
|
|
// ** When found, set *piTab and *piCol to the table index and column index
|
|
// ** of the matching column and return TRUE.
|
|
// **
|
|
// ** If not found, return FALSE.
|
|
// */
|
|
func _tableAndColumnIndex(tls *libc.TLS, pSrc uintptr, iStart int32, iEnd int32, zCol uintptr, piTab uintptr, piCol uintptr, bIgnoreHidden int32) (r int32) {
|
|
var i, iCol int32
|
|
_, _ = i, iCol /* Index of column matching zCol */
|
|
/* Both or neither are NULL */
|
|
i = iStart
|
|
for {
|
|
if !(i <= iEnd) {
|
|
break
|
|
}
|
|
iCol = _sqlite3ColumnIndex(tls, (*(*TSrcItem)(unsafe.Pointer(pSrc + 8 + uintptr(i)*80))).FpSTab, zCol)
|
|
if iCol >= 0 && (bIgnoreHidden == 0 || libc.BoolInt32(libc.Int32FromUint16((*TColumn)(unsafe.Pointer((*TTable)(unsafe.Pointer((*(*TSrcItem)(unsafe.Pointer(pSrc + 8 + uintptr(i)*80))).FpSTab)).FaCol+uintptr(iCol)*16)).FcolFlags)&int32(COLFLAG_HIDDEN) != 0) == 0) {
|
|
if piTab != 0 {
|
|
_sqlite3SrcItemColumnUsed(tls, pSrc+8+uintptr(i)*80, iCol)
|
|
**(**int32)(__ccgo_up(piTab)) = i
|
|
**(**int32)(__ccgo_up(piCol)) = iCol
|
|
}
|
|
return int32(1)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If the pBase expression originated in the ON or USING clause of
|
|
// ** a join, then transfer the appropriate markings over to derived.
|
|
// */
|
|
func _transferJoinMarkings(tls *libc.TLS, pDerived uintptr, pBase uintptr) {
|
|
if pDerived != 0 && (*TExpr)(unsafe.Pointer(pBase)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)|libc.Int32FromInt32(EP_InnerON)) != uint32(0) {
|
|
**(**Tu32)(__ccgo_up(pDerived + 4)) |= (*TExpr)(unsafe.Pointer(pBase)).Fflags & libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)|libc.Int32FromInt32(EP_InnerON))
|
|
*(*int32)(unsafe.Pointer(pDerived + 52)) = *(*int32)(unsafe.Pointer(pBase + 52))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Convert OP_Column opcodes to OP_Copy in previously generated code.
|
|
// **
|
|
// ** This routine runs over generated VDBE code and translates OP_Column
|
|
// ** opcodes into OP_Copy when the table is being accessed via co-routine
|
|
// ** instead of via table lookup.
|
|
// **
|
|
// ** If the iAutoidxCur is not zero, then any OP_Rowid instructions on
|
|
// ** cursor iTabCur are transformed into OP_Sequence opcode for the
|
|
// ** iAutoidxCur cursor, in order to generate unique rowids for the
|
|
// ** automatic index being generated.
|
|
// */
|
|
func _translateColumnToCopy(tls *libc.TLS, pParse uintptr, iStart int32, iTabCur int32, iRegister int32, iAutoidxCur int32) {
|
|
var iEnd int32
|
|
var pOp, v uintptr
|
|
_, _, _ = iEnd, pOp, v
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
pOp = _sqlite3VdbeGetOp(tls, v, iStart)
|
|
iEnd = _sqlite3VdbeCurrentAddr(tls, v)
|
|
if (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).FmallocFailed != 0 {
|
|
return
|
|
}
|
|
for {
|
|
if !(iStart < iEnd) {
|
|
break
|
|
}
|
|
if (*TVdbeOp)(unsafe.Pointer(pOp)).Fp1 != iTabCur {
|
|
goto _1
|
|
}
|
|
if libc.Int32FromUint8((*TVdbeOp)(unsafe.Pointer(pOp)).Fopcode) == int32(OP_Column) {
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fopcode = uint8(OP_Copy)
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp1 = (*TVdbeOp)(unsafe.Pointer(pOp)).Fp2 + iRegister
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp2 = (*TVdbeOp)(unsafe.Pointer(pOp)).Fp3
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp3 = 0
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp5 = uint16(2) /* Cause the MEM_Subtype flag to be cleared */
|
|
} else {
|
|
if libc.Int32FromUint8((*TVdbeOp)(unsafe.Pointer(pOp)).Fopcode) == int32(OP_Rowid) {
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fopcode = uint8(OP_Sequence)
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp1 = iAutoidxCur
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
iStart = iStart + 1
|
|
pOp += 24
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Two routines for printing the content of an sqlite3_index_info
|
|
** structure. Used for testing and debugging only. If neither
|
|
** SQLITE_TEST or SQLITE_DEBUG are defined, then these routines
|
|
** are no-ops.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Implementation of the TRIM(), LTRIM(), and RTRIM() functions.
|
|
// ** The userdata is 0x1 for left trim, 0x2 for right trim, 0x3 for both.
|
|
// */
|
|
func _trimFunc(tls *libc.TLS, context uintptr, argc int32, argv uintptr) {
|
|
var aLen, azChar, z, zCharSet, zIn, v1 uintptr
|
|
var flags, i, nChar int32
|
|
var len1, len11, nIn uint32
|
|
_, _, _, _, _, _, _, _, _, _, _, _ = aLen, azChar, flags, i, len1, len11, nChar, nIn, z, zCharSet, zIn, v1 /* Loop counter */
|
|
aLen = uintptr(0) /* Length of each character in zCharSet */
|
|
azChar = uintptr(0) /* Number of characters in zCharSet */
|
|
if Xsqlite3_value_type(tls, **(**uintptr)(__ccgo_up(argv))) == int32(SQLITE_NULL) {
|
|
return
|
|
}
|
|
zIn = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv)))
|
|
if zIn == uintptr(0) {
|
|
return
|
|
}
|
|
nIn = libc.Uint32FromInt32(Xsqlite3_value_bytes(tls, **(**uintptr)(__ccgo_up(argv))))
|
|
if argc == int32(1) {
|
|
nChar = int32(1)
|
|
aLen = uintptr(unsafe.Pointer(&_lenOne))
|
|
azChar = uintptr(unsafe.Pointer(&_azOne))
|
|
zCharSet = uintptr(0)
|
|
} else {
|
|
v1 = Xsqlite3_value_text(tls, **(**uintptr)(__ccgo_up(argv + 1*8)))
|
|
zCharSet = v1
|
|
if v1 == uintptr(0) {
|
|
return
|
|
} else {
|
|
z = zCharSet
|
|
nChar = libc.Int32FromInt32(0)
|
|
for {
|
|
if !(**(**uint8)(__ccgo_up(z)) != 0) {
|
|
break
|
|
}
|
|
v1 = z
|
|
z = z + 1
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(v1))) >= int32(0xc0) {
|
|
for libc.Int32FromUint8(**(**uint8)(__ccgo_up(z)))&int32(0xc0) == int32(0x80) {
|
|
z = z + 1
|
|
}
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
nChar = nChar + 1
|
|
}
|
|
if nChar > 0 {
|
|
azChar = _contextMalloc(tls, context, libc.Int64FromUint64(libc.Uint64FromInt64(int64(nChar))*uint64(libc.Uint64FromInt64(8)+libc.Uint64FromInt64(4))))
|
|
if azChar == uintptr(0) {
|
|
return
|
|
}
|
|
aLen = azChar + uintptr(nChar)*8
|
|
z = zCharSet
|
|
nChar = libc.Int32FromInt32(0)
|
|
for {
|
|
if !(**(**uint8)(__ccgo_up(z)) != 0) {
|
|
break
|
|
}
|
|
**(**uintptr)(__ccgo_up(azChar + uintptr(nChar)*8)) = z
|
|
v1 = z
|
|
z = z + 1
|
|
if libc.Int32FromUint8(**(**uint8)(__ccgo_up(v1))) >= int32(0xc0) {
|
|
for libc.Int32FromUint8(**(**uint8)(__ccgo_up(z)))&int32(0xc0) == int32(0x80) {
|
|
z = z + 1
|
|
}
|
|
}
|
|
**(**uint32)(__ccgo_up(aLen + uintptr(nChar)*4)) = libc.Uint32FromInt64(int64(z) - int64(**(**uintptr)(__ccgo_up(azChar + uintptr(nChar)*8))))
|
|
goto _4
|
|
_4:
|
|
;
|
|
nChar = nChar + 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if nChar > 0 {
|
|
flags = int32(int64(Xsqlite3_user_data(tls, context)))
|
|
if flags&int32(1) != 0 {
|
|
for nIn > uint32(0) {
|
|
len1 = uint32(0)
|
|
i = 0
|
|
for {
|
|
if !(i < nChar) {
|
|
break
|
|
}
|
|
len1 = **(**uint32)(__ccgo_up(aLen + uintptr(i)*4))
|
|
if len1 <= nIn && libc.Xmemcmp(tls, zIn, **(**uintptr)(__ccgo_up(azChar + uintptr(i)*8)), uint64(len1)) == 0 {
|
|
break
|
|
}
|
|
goto _6
|
|
_6:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if i >= nChar {
|
|
break
|
|
}
|
|
zIn = zIn + uintptr(len1)
|
|
nIn = nIn - len1
|
|
}
|
|
}
|
|
if flags&int32(2) != 0 {
|
|
for nIn > uint32(0) {
|
|
len11 = uint32(0)
|
|
i = 0
|
|
for {
|
|
if !(i < nChar) {
|
|
break
|
|
}
|
|
len11 = **(**uint32)(__ccgo_up(aLen + uintptr(i)*4))
|
|
if len11 <= nIn && libc.Xmemcmp(tls, zIn+uintptr(nIn-len11), **(**uintptr)(__ccgo_up(azChar + uintptr(i)*8)), uint64(len11)) == 0 {
|
|
break
|
|
}
|
|
goto _7
|
|
_7:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if i >= nChar {
|
|
break
|
|
}
|
|
nIn = nIn - len11
|
|
}
|
|
}
|
|
if zCharSet != 0 {
|
|
Xsqlite3_free(tls, azChar)
|
|
}
|
|
}
|
|
Xsqlite3_result_text(tls, context, zIn, libc.Int32FromUint32(nIn), uintptr(-libc.Int32FromInt32(1)))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the value of a system call. Return NULL if zName is not a
|
|
// ** recognized system call name. NULL is also returned if the system call
|
|
// ** is currently undefined.
|
|
// */
|
|
func _unixGetSystemCall(tls *libc.TLS, pNotUsed uintptr, zName uintptr) (r Tsqlite3_syscall_ptr) {
|
|
var i uint32
|
|
_ = i
|
|
_ = pNotUsed
|
|
i = uint32(0)
|
|
for {
|
|
if !(uint64(i) < libc.Uint64FromInt64(696)/libc.Uint64FromInt64(24)) {
|
|
break
|
|
}
|
|
if libc.Xstrcmp(tls, zName, _aSyscall[i].FzName) == 0 {
|
|
return _aSyscall[i].FpCurrent
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return uintptr(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If *pArg is initially negative then this is a query. Set *pArg to
|
|
// ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
|
|
// **
|
|
// ** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
|
|
// */
|
|
func _unixModeBit(tls *libc.TLS, pFile uintptr, mask uint8, pArg uintptr) {
|
|
var v1 uintptr
|
|
_ = v1
|
|
if **(**int32)(__ccgo_up(pArg)) < 0 {
|
|
**(**int32)(__ccgo_up(pArg)) = libc.BoolInt32(libc.Int32FromUint16((*TunixFile)(unsafe.Pointer(pFile)).FctrlFlags)&libc.Int32FromUint8(mask) != 0)
|
|
} else {
|
|
if **(**int32)(__ccgo_up(pArg)) == 0 {
|
|
v1 = pFile + 30
|
|
*(*uint16)(unsafe.Pointer(v1)) = uint16(int32(*(*uint16)(unsafe.Pointer(v1))) & ^libc.Int32FromUint8(mask))
|
|
} else {
|
|
v1 = pFile + 30
|
|
*(*uint16)(unsafe.Pointer(v1)) = uint16(int32(*(*uint16)(unsafe.Pointer(v1))) | libc.Int32FromUint8(mask))
|
|
}
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the name of the first system call after zName. If zName==NULL
|
|
// ** then return the name of the first system call. Return NULL if zName
|
|
// ** is the last system call or if zName is not the name of a valid
|
|
// ** system call.
|
|
// */
|
|
func _unixNextSystemCall(tls *libc.TLS, p uintptr, zName uintptr) (r uintptr) {
|
|
var i int32
|
|
_ = i
|
|
i = -int32(1)
|
|
_ = p
|
|
if zName != 0 {
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint64(libc.Uint64FromInt64(696)/libc.Uint64FromInt64(24))-libc.Int32FromInt32(1)) {
|
|
break
|
|
}
|
|
if libc.Xstrcmp(tls, zName, _aSyscall[i].FzName) == 0 {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
i = i + 1
|
|
for {
|
|
if !(i < libc.Int32FromUint64(libc.Uint64FromInt64(696)/libc.Uint64FromInt64(24))) {
|
|
break
|
|
}
|
|
if _aSyscall[i].FpCurrent != uintptr(0) {
|
|
return _aSyscall[i].FzName
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
return uintptr(0)
|
|
}
|
|
|
|
/*
|
|
** Do not accept any file descriptor less than this value, in order to avoid
|
|
** opening database file using file descriptors that are commonly used for
|
|
** standard input, output, and error.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This is the xSetSystemCall() method of sqlite3_vfs for all of the
|
|
// ** "unix" VFSes. Return SQLITE_OK upon successfully updating the
|
|
// ** system call pointer, or SQLITE_NOTFOUND if there is no configurable
|
|
// ** system call named zName.
|
|
// */
|
|
func _unixSetSystemCall(tls *libc.TLS, pNotUsed uintptr, zName uintptr, __ccgo_fp_pNewFunc Tsqlite3_syscall_ptr) (r int32) {
|
|
var i uint32
|
|
var rc int32
|
|
_, _ = i, rc
|
|
rc = int32(SQLITE_NOTFOUND)
|
|
_ = pNotUsed
|
|
if zName == uintptr(0) {
|
|
/* If no zName is given, restore all system calls to their default
|
|
** settings and return NULL
|
|
*/
|
|
rc = SQLITE_OK
|
|
i = uint32(0)
|
|
for {
|
|
if !(uint64(i) < libc.Uint64FromInt64(696)/libc.Uint64FromInt64(24)) {
|
|
break
|
|
}
|
|
if _aSyscall[i].FpDefault != 0 {
|
|
_aSyscall[i].FpCurrent = _aSyscall[i].FpDefault
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
} else {
|
|
/* If zName is specified, operate on only the one system call
|
|
** specified.
|
|
*/
|
|
i = uint32(0)
|
|
for {
|
|
if !(uint64(i) < libc.Uint64FromInt64(696)/libc.Uint64FromInt64(24)) {
|
|
break
|
|
}
|
|
if libc.Xstrcmp(tls, zName, _aSyscall[i].FzName) == 0 {
|
|
if _aSyscall[i].FpDefault == uintptr(0) {
|
|
_aSyscall[i].FpDefault = _aSyscall[i].FpCurrent
|
|
}
|
|
rc = SQLITE_OK
|
|
if __ccgo_fp_pNewFunc == uintptr(0) {
|
|
__ccgo_fp_pNewFunc = _aSyscall[i].FpDefault
|
|
}
|
|
_aSyscall[i].FpCurrent = __ccgo_fp_pNewFunc
|
|
break
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0.
|
|
// **
|
|
// ** This is not a VFS shared-memory method; it is a utility function called
|
|
// ** by VFS shared-memory methods.
|
|
// */
|
|
func _unixShmPurge(tls *libc.TLS, pFd uintptr) {
|
|
var i, nShmPerMap int32
|
|
var p uintptr
|
|
_, _, _ = i, nShmPerMap, p
|
|
p = (*TunixInodeInfo)(unsafe.Pointer((*TunixFile)(unsafe.Pointer(pFd)).FpInode)).FpShmNode
|
|
if p != 0 && (*TunixShmNode)(unsafe.Pointer(p)).FnRef == 0 {
|
|
nShmPerMap = _unixShmRegionPerMap(tls)
|
|
Xsqlite3_mutex_free(tls, (*TunixShmNode)(unsafe.Pointer(p)).FpShmMutex)
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TunixShmNode)(unsafe.Pointer(p)).FnRegion)) {
|
|
break
|
|
}
|
|
if (*TunixShmNode)(unsafe.Pointer(p)).FhShm >= 0 {
|
|
(*(*func(*libc.TLS, uintptr, Tsize_t) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(23)].FpCurrent})))(tls, **(**uintptr)(__ccgo_up((*TunixShmNode)(unsafe.Pointer(p)).FapRegion + uintptr(i)*8)), libc.Uint64FromInt32((*TunixShmNode)(unsafe.Pointer(p)).FszRegion))
|
|
} else {
|
|
Xsqlite3_free(tls, **(**uintptr)(__ccgo_up((*TunixShmNode)(unsafe.Pointer(p)).FapRegion + uintptr(i)*8)))
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + nShmPerMap
|
|
}
|
|
Xsqlite3_free(tls, (*TunixShmNode)(unsafe.Pointer(p)).FapRegion)
|
|
if (*TunixShmNode)(unsafe.Pointer(p)).FhShm >= 0 {
|
|
_robust_close(tls, pFd, (*TunixShmNode)(unsafe.Pointer(p)).FhShm, int32(45030))
|
|
(*TunixShmNode)(unsafe.Pointer(p)).FhShm = -int32(1)
|
|
}
|
|
(*TunixInodeInfo)(unsafe.Pointer((*TunixShmNode)(unsafe.Pointer(p)).FpInode)).FpShmNode = uintptr(0)
|
|
Xsqlite3_free(tls, p)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Close a connection to shared-memory. Delete the underlying
|
|
// ** storage if deleteFlag is true.
|
|
// **
|
|
// ** If there is no shared memory associated with the connection then this
|
|
// ** routine is a harmless no-op.
|
|
// */
|
|
func _unixShmUnmap(tls *libc.TLS, fd uintptr, deleteFlag int32) (r int32) {
|
|
var p, pDbFd, pShmNode, pp uintptr
|
|
_, _, _, _ = p, pDbFd, pShmNode, pp /* The underlying database file */
|
|
pDbFd = fd
|
|
p = (*TunixFile)(unsafe.Pointer(pDbFd)).FpShm
|
|
if p == uintptr(0) {
|
|
return SQLITE_OK
|
|
}
|
|
pShmNode = (*TunixShm)(unsafe.Pointer(p)).FpShmNode
|
|
/* Remove connection p from the set of connections associated
|
|
** with pShmNode */
|
|
Xsqlite3_mutex_enter(tls, (*TunixShmNode)(unsafe.Pointer(pShmNode)).FpShmMutex)
|
|
pp = pShmNode + 56
|
|
for {
|
|
if !(**(**uintptr)(__ccgo_up(pp)) != p) {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
pp = **(**uintptr)(__ccgo_up(pp)) + 8
|
|
}
|
|
**(**uintptr)(__ccgo_up(pp)) = (*TunixShm)(unsafe.Pointer(p)).FpNext
|
|
/* Free the connection p */
|
|
Xsqlite3_free(tls, p)
|
|
(*TunixFile)(unsafe.Pointer(pDbFd)).FpShm = uintptr(0)
|
|
Xsqlite3_mutex_leave(tls, (*TunixShmNode)(unsafe.Pointer(pShmNode)).FpShmMutex)
|
|
/* If pShmNode->nRef has reached 0, then close the underlying
|
|
** shared-memory file, too */
|
|
_unixEnterMutex(tls)
|
|
(*TunixShmNode)(unsafe.Pointer(pShmNode)).FnRef = (*TunixShmNode)(unsafe.Pointer(pShmNode)).FnRef - 1
|
|
if (*TunixShmNode)(unsafe.Pointer(pShmNode)).FnRef == 0 {
|
|
if deleteFlag != 0 && (*TunixShmNode)(unsafe.Pointer(pShmNode)).FhShm >= 0 {
|
|
(*(*func(*libc.TLS, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(16)].FpCurrent})))(tls, (*TunixShmNode)(unsafe.Pointer(pShmNode)).FzFilename)
|
|
}
|
|
_unixShmPurge(tls, pDbFd)
|
|
}
|
|
_unixLeaveMutex(tls)
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Sleep for a little while. Return the amount of time slept.
|
|
// ** The argument is the number of microseconds we want to sleep.
|
|
// ** The return value is the number of microseconds of sleep actually
|
|
// ** requested from the underlying operating system, a number which
|
|
// ** might be greater than or equal to the argument, but not less
|
|
// ** than the argument.
|
|
// */
|
|
func _unixSleep(tls *libc.TLS, NotUsed uintptr, microseconds int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var _ /* sp at bp+0 */ Ttimespec
|
|
(**(**Ttimespec)(__ccgo_up(bp))).Ftv_sec = int64(microseconds / int32(1000000))
|
|
(**(**Ttimespec)(__ccgo_up(bp))).Ftv_nsec = int64(microseconds % int32(1000000) * int32(1000))
|
|
/* Almost all modern unix systems support nanosleep(). But if you are
|
|
** compiling for one of the rare exceptions, you can use
|
|
** -DHAVE_NANOSLEEP=0 (perhaps in conjunction with -DHAVE_USLEEP if
|
|
** usleep() is available) in order to bypass the use of nanosleep() */
|
|
libc.Xnanosleep(tls, bp, libc.UintptrFromInt32(0))
|
|
_ = NotUsed
|
|
return microseconds
|
|
}
|
|
|
|
/*
|
|
** The following variable, if set to a non-zero value, is interpreted as
|
|
** the number of seconds since 1970 and is used to set the result of
|
|
** sqlite3OsCurrentTime() during testing.
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /* Undo the work of sqlite3SetJoinExpr(). This is used when a LEFT JOIN
|
|
// ** is simplified into an ordinary JOIN, and when an ON expression is
|
|
// ** "pushed down" into the WHERE clause of a subquery.
|
|
// **
|
|
// ** Convert every term that is marked with EP_OuterON and w.iJoin==iTable into
|
|
// ** an ordinary term that omits the EP_OuterON mark. Or if iTable<0, then
|
|
// ** just clear every EP_OuterON and EP_InnerON mark from the expression tree.
|
|
// **
|
|
// ** If nullable is true, that means that Expr p might evaluate to NULL even
|
|
// ** if it is a reference to a NOT NULL column. This can happen, for example,
|
|
// ** if the table that p references is on the left side of a RIGHT JOIN.
|
|
// ** If nullable is true, then take care to not remove the EP_CanBeNull bit.
|
|
// ** See forum thread https://sqlite.org/forum/forumpost/b40696f50145d21c
|
|
// */
|
|
func _unsetJoinExpr(tls *libc.TLS, p uintptr, iTable int32, nullable int32) {
|
|
var i int32
|
|
_ = i
|
|
for p != 0 {
|
|
if iTable < 0 || (*TExpr)(unsafe.Pointer(p)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)) != uint32(0) && *(*int32)(unsafe.Pointer(p + 52)) == iTable {
|
|
**(**Tu32)(__ccgo_up(p + 4)) &= ^libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON) | libc.Int32FromInt32(EP_InnerON))
|
|
if iTable >= 0 {
|
|
**(**Tu32)(__ccgo_up(p + 4)) |= libc.Uint32FromInt32(libc.Int32FromInt32(EP_InnerON))
|
|
}
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) == int32(TK_COLUMN) && (*TExpr)(unsafe.Pointer(p)).FiTable == iTable && !(nullable != 0) {
|
|
**(**Tu32)(__ccgo_up(p + 4)) &= ^libc.Uint32FromInt32(libc.Int32FromInt32(EP_CanBeNull))
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(p)).Fop) == int32(TK_FUNCTION) {
|
|
if *(*uintptr)(unsafe.Pointer(p + 32)) != 0 {
|
|
i = 0
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(p + 32)))).FnExpr) {
|
|
break
|
|
}
|
|
_unsetJoinExpr(tls, (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(p + 32)) + 8 + uintptr(i)*32))).FpExpr, iTable, nullable)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
}
|
|
_unsetJoinExpr(tls, (*TExpr)(unsafe.Pointer(p)).FpLeft, iTable, nullable)
|
|
p = (*TExpr)(unsafe.Pointer(p)).FpRight
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code that will update the accumulator memory cells for an
|
|
// ** aggregate based on the current cursor position.
|
|
// **
|
|
// ** If regAcc is non-zero and there are no min() or max() aggregates
|
|
// ** in pAggInfo, then only populate the pAggInfo->nAccumulator accumulator
|
|
// ** registers if register regAcc contains 0. The caller will take care
|
|
// ** of setting and clearing regAcc.
|
|
// **
|
|
// ** For an ORDER BY aggregate, the actual accumulator memory cell update
|
|
// ** is deferred until after all input rows have been received, so that they
|
|
// ** can be run in the requested order. In that case, instead of invoking
|
|
// ** OP_AggStep to update the accumulator, just add the arguments that would
|
|
// ** have been passed into OP_AggStep into the sorting ephemeral table
|
|
// ** (along with the appropriate sort key).
|
|
// */
|
|
func _updateAccumulator(tls *libc.TLS, pParse uintptr, regAcc int32, pAggInfo uintptr, eDistinctType int32) {
|
|
var addrHitTest, addrNext, i, j, jj, kk, nArg, regAgg, regAggSz, regBase, regDistinct, regHit, v2 int32
|
|
var pC, pColl, pF, pFilter, pItem, pList, pOBList, v, v3 uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = addrHitTest, addrNext, i, j, jj, kk, nArg, pC, pColl, pF, pFilter, pItem, pList, pOBList, regAgg, regAggSz, regBase, regDistinct, regHit, v, v2, v3
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe
|
|
regHit = 0
|
|
addrHitTest = 0
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr != 0 {
|
|
return
|
|
}
|
|
(*TAggInfo)(unsafe.Pointer(pAggInfo)).FdirectMode = uint8(1)
|
|
i = 0
|
|
pF = (*TAggInfo)(unsafe.Pointer(pAggInfo)).FaFunc
|
|
for {
|
|
if !(i < (*TAggInfo)(unsafe.Pointer(pAggInfo)).FnFunc) {
|
|
break
|
|
}
|
|
addrNext = 0
|
|
regAggSz = 0
|
|
regDistinct = 0
|
|
pList = *(*uintptr)(unsafe.Pointer((*TAggInfo_func)(unsafe.Pointer(pF)).FpFExpr + 32))
|
|
if (*TExpr)(unsafe.Pointer((*TAggInfo_func)(unsafe.Pointer(pF)).FpFExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_WinFunc)) != uint32(0) {
|
|
pFilter = (*TWindow)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer((*TAggInfo_func)(unsafe.Pointer(pF)).FpFExpr + 64)))).FpFilter
|
|
if (*TAggInfo)(unsafe.Pointer(pAggInfo)).FnAccumulator != 0 && (*TFuncDef)(unsafe.Pointer((*TAggInfo_func)(unsafe.Pointer(pF)).FpFunc)).FfuncFlags&uint32(SQLITE_FUNC_NEEDCOLL) != 0 && regAcc != 0 {
|
|
/* If regAcc==0, there there exists some min() or max() function
|
|
** without a FILTER clause that will ensure the magnet registers
|
|
** are populated. */
|
|
if regHit == 0 {
|
|
v3 = pParse + 60
|
|
*(*int32)(unsafe.Pointer(v3)) = *(*int32)(unsafe.Pointer(v3)) + 1
|
|
v2 = *(*int32)(unsafe.Pointer(v3))
|
|
regHit = v2
|
|
}
|
|
/* If this is the first row of the group (regAcc contains 0), clear the
|
|
** "magnet" register regHit so that the accumulator registers
|
|
** are populated if the FILTER clause jumps over the the
|
|
** invocation of min() or max() altogether. Or, if this is not
|
|
** the first row (regAcc contains 1), set the magnet register so that
|
|
** the accumulators are not populated unless the min()/max() is invoked
|
|
** and indicates that they should be. */
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Copy), regAcc, regHit)
|
|
}
|
|
addrNext = _sqlite3VdbeMakeLabel(tls, pParse)
|
|
_sqlite3ExprIfFalse(tls, pParse, pFilter, addrNext, int32(SQLITE_JUMPIFNULL))
|
|
}
|
|
if (*TAggInfo_func)(unsafe.Pointer(pF)).FiOBTab >= 0 { /* The ORDER BY clause */
|
|
nArg = (*TExprList)(unsafe.Pointer(pList)).FnExpr
|
|
pOBList = *(*uintptr)(unsafe.Pointer((*TExpr)(unsafe.Pointer((*TAggInfo_func)(unsafe.Pointer(pF)).FpFExpr)).FpLeft + 32))
|
|
regAggSz = (*TExprList)(unsafe.Pointer(pOBList)).FnExpr
|
|
if !((*TAggInfo_func)(unsafe.Pointer(pF)).FbOBUnique != 0) {
|
|
regAggSz = regAggSz + 1 /* One register for OP_Sequence */
|
|
}
|
|
if (*TAggInfo_func)(unsafe.Pointer(pF)).FbOBPayload != 0 {
|
|
regAggSz = regAggSz + nArg
|
|
}
|
|
if (*TAggInfo_func)(unsafe.Pointer(pF)).FbUseSubtype != 0 {
|
|
regAggSz = regAggSz + nArg
|
|
}
|
|
regAggSz = regAggSz + 1 /* One extra register to hold result of MakeRecord */
|
|
regAgg = _sqlite3GetTempRange(tls, pParse, regAggSz)
|
|
regDistinct = regAgg
|
|
_sqlite3ExprCodeExprList(tls, pParse, pOBList, regAgg, 0, uint8(SQLITE_ECEL_DUP))
|
|
jj = (*TExprList)(unsafe.Pointer(pOBList)).FnExpr
|
|
if !((*TAggInfo_func)(unsafe.Pointer(pF)).FbOBUnique != 0) {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Sequence), (*TAggInfo_func)(unsafe.Pointer(pF)).FiOBTab, regAgg+jj)
|
|
jj = jj + 1
|
|
}
|
|
if (*TAggInfo_func)(unsafe.Pointer(pF)).FbOBPayload != 0 {
|
|
regDistinct = regAgg + jj
|
|
_sqlite3ExprCodeExprList(tls, pParse, pList, regDistinct, 0, uint8(SQLITE_ECEL_DUP))
|
|
jj = jj + nArg
|
|
}
|
|
if (*TAggInfo_func)(unsafe.Pointer(pF)).FbUseSubtype != 0 {
|
|
if (*TAggInfo_func)(unsafe.Pointer(pF)).FbOBPayload != 0 {
|
|
v2 = regDistinct
|
|
} else {
|
|
v2 = regAgg
|
|
}
|
|
regBase = v2
|
|
kk = 0
|
|
for {
|
|
if !(kk < nArg) {
|
|
break
|
|
}
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_GetSubtype), regBase+kk, regAgg+jj)
|
|
goto _5
|
|
_5:
|
|
;
|
|
kk = kk + 1
|
|
jj = jj + 1
|
|
}
|
|
}
|
|
} else {
|
|
if pList != 0 {
|
|
nArg = (*TExprList)(unsafe.Pointer(pList)).FnExpr
|
|
regAgg = _sqlite3GetTempRange(tls, pParse, nArg)
|
|
regDistinct = regAgg
|
|
_sqlite3ExprCodeExprList(tls, pParse, pList, regAgg, 0, uint8(SQLITE_ECEL_DUP))
|
|
} else {
|
|
nArg = 0
|
|
regAgg = 0
|
|
}
|
|
}
|
|
if (*TAggInfo_func)(unsafe.Pointer(pF)).FiDistinct >= 0 && pList != 0 {
|
|
if addrNext == 0 {
|
|
addrNext = _sqlite3VdbeMakeLabel(tls, pParse)
|
|
}
|
|
(*TAggInfo_func)(unsafe.Pointer(pF)).FiDistinct = _codeDistinct(tls, pParse, eDistinctType, (*TAggInfo_func)(unsafe.Pointer(pF)).FiDistinct, addrNext, pList, regDistinct)
|
|
}
|
|
if (*TAggInfo_func)(unsafe.Pointer(pF)).FiOBTab >= 0 {
|
|
/* Insert a new record into the ORDER BY table */
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_MakeRecord), regAgg, regAggSz-int32(1), regAgg+regAggSz-int32(1))
|
|
_sqlite3VdbeAddOp4Int(tls, v, int32(OP_IdxInsert), (*TAggInfo_func)(unsafe.Pointer(pF)).FiOBTab, regAgg+regAggSz-int32(1), regAgg, regAggSz-int32(1))
|
|
_sqlite3ReleaseTempRange(tls, pParse, regAgg, regAggSz)
|
|
} else {
|
|
/* Invoke the AggStep function */
|
|
if (*TFuncDef)(unsafe.Pointer((*TAggInfo_func)(unsafe.Pointer(pF)).FpFunc)).FfuncFlags&uint32(SQLITE_FUNC_NEEDCOLL) != 0 {
|
|
pColl = uintptr(0)
|
|
/* pList!=0 if pF->pFunc has NEEDCOLL */
|
|
j = 0
|
|
pItem = pList + 8
|
|
for {
|
|
if !(!(pColl != 0) && j < nArg) {
|
|
break
|
|
}
|
|
pColl = _sqlite3ExprCollSeq(tls, pParse, (*TExprList_item)(unsafe.Pointer(pItem)).FpExpr)
|
|
goto _6
|
|
_6:
|
|
;
|
|
j = j + 1
|
|
pItem += 32
|
|
}
|
|
if !(pColl != 0) {
|
|
pColl = (*Tsqlite3)(unsafe.Pointer((*TParse)(unsafe.Pointer(pParse)).Fdb)).FpDfltColl
|
|
}
|
|
if regHit == 0 && (*TAggInfo)(unsafe.Pointer(pAggInfo)).FnAccumulator != 0 {
|
|
v3 = pParse + 60
|
|
*(*int32)(unsafe.Pointer(v3)) = *(*int32)(unsafe.Pointer(v3)) + 1
|
|
v2 = *(*int32)(unsafe.Pointer(v3))
|
|
regHit = v2
|
|
}
|
|
_sqlite3VdbeAddOp4(tls, v, int32(OP_CollSeq), regHit, 0, 0, pColl, -int32(2))
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_AggStep), 0, regAgg, (*TAggInfo)(unsafe.Pointer(pAggInfo)).FiFirstReg+(*TAggInfo)(unsafe.Pointer(pAggInfo)).FnColumn+i)
|
|
_sqlite3VdbeAppendP4(tls, v, (*TAggInfo_func)(unsafe.Pointer(pF)).FpFunc, -int32(8))
|
|
_sqlite3VdbeChangeP5(tls, v, libc.Uint16FromInt32(nArg))
|
|
_sqlite3ReleaseTempRange(tls, pParse, regAgg, nArg)
|
|
}
|
|
if addrNext != 0 {
|
|
_sqlite3VdbeResolveLabel(tls, v, addrNext)
|
|
}
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr != 0 {
|
|
return
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
pF += 32
|
|
}
|
|
if regHit == 0 && (*TAggInfo)(unsafe.Pointer(pAggInfo)).FnAccumulator != 0 {
|
|
regHit = regAcc
|
|
}
|
|
if regHit != 0 {
|
|
addrHitTest = _sqlite3VdbeAddOp1(tls, v, int32(OP_If), regHit)
|
|
}
|
|
i = 0
|
|
pC = (*TAggInfo)(unsafe.Pointer(pAggInfo)).FaCol
|
|
for {
|
|
if !(i < (*TAggInfo)(unsafe.Pointer(pAggInfo)).FnAccumulator) {
|
|
break
|
|
}
|
|
_sqlite3ExprCode(tls, pParse, (*TAggInfo_col)(unsafe.Pointer(pC)).FpCExpr, (*TAggInfo)(unsafe.Pointer(pAggInfo)).FiFirstReg+i)
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr != 0 {
|
|
return
|
|
}
|
|
goto _9
|
|
_9:
|
|
;
|
|
i = i + 1
|
|
pC += 32
|
|
}
|
|
(*TAggInfo)(unsafe.Pointer(pAggInfo)).FdirectMode = uint8(0)
|
|
if addrHitTest != 0 {
|
|
_sqlite3VdbeJumpHereOrPopInst(tls, v, addrHitTest)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Assuming both the pLimit and pOrderBy parameters are NULL, this function
|
|
// ** generates VM code to run the query:
|
|
// **
|
|
// ** SELECT <other-columns>, pChanges FROM pTabList WHERE pWhere
|
|
// **
|
|
// ** and write the results to the ephemeral table already opened as cursor
|
|
// ** iEph. None of pChanges, pTabList or pWhere are modified or consumed by
|
|
// ** this function, they must be deleted by the caller.
|
|
// **
|
|
// ** Or, if pLimit and pOrderBy are not NULL, and pTab is not a view:
|
|
// **
|
|
// ** SELECT <other-columns>, pChanges FROM pTabList
|
|
// ** WHERE pWhere
|
|
// ** GROUP BY <other-columns>
|
|
// ** ORDER BY pOrderBy LIMIT pLimit
|
|
// **
|
|
// ** If pTab is a view, the GROUP BY clause is omitted.
|
|
// **
|
|
// ** Exactly how results are written to table iEph, and exactly what
|
|
// ** the <other-columns> in the query above are is determined by the type
|
|
// ** of table pTabList->a[0].pTab.
|
|
// **
|
|
// ** If the table is a WITHOUT ROWID table, then argument pPk must be its
|
|
// ** PRIMARY KEY. In this case <other-columns> are the primary key columns
|
|
// ** of the table, in order. The results of the query are written to ephemeral
|
|
// ** table iEph as index keys, using OP_IdxInsert.
|
|
// **
|
|
// ** If the table is actually a view, then <other-columns> are all columns of
|
|
// ** the view. The results are written to the ephemeral table iEph as records
|
|
// ** with automatically assigned integer keys.
|
|
// **
|
|
// ** If the table is a virtual or ordinary intkey table, then <other-columns>
|
|
// ** is its rowid. For a virtual table, the results are written to iEph as
|
|
// ** records with automatically assigned integer keys For intkey tables, the
|
|
// ** rowid value in <other-columns> is used as the integer key, and the
|
|
// ** remaining fields make up the table record.
|
|
// */
|
|
func _updateFromSelect(tls *libc.TLS, pParse uintptr, iEph int32, pPk uintptr, pChanges uintptr, pTabList uintptr, pWhere uintptr, pOrderBy uintptr, pLimit uintptr) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var db, pGrp, pLimit2, pList, pNew, pOrderBy2, pSelect, pSrc, pTab, pWhere2 uintptr
|
|
var eDest, i, v2 int32
|
|
var _ /* dest at bp+0 */ TSelectDest
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _ = db, eDest, i, pGrp, pLimit2, pList, pNew, pOrderBy2, pSelect, pSrc, pTab, pWhere2, v2
|
|
pSelect = uintptr(0)
|
|
pList = uintptr(0)
|
|
pGrp = uintptr(0)
|
|
pLimit2 = uintptr(0)
|
|
pOrderBy2 = uintptr(0)
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
pTab = (*(*TSrcItem)(unsafe.Pointer(pTabList + 8))).FpSTab
|
|
_ = pOrderBy
|
|
_ = pLimit
|
|
pSrc = _sqlite3SrcListDup(tls, db, pTabList, 0)
|
|
pWhere2 = _sqlite3ExprDup(tls, db, pWhere, 0)
|
|
if pSrc != 0 {
|
|
(*(*TSrcItem)(unsafe.Pointer(pSrc + 8))).FiCursor = -int32(1)
|
|
(*TTable)(unsafe.Pointer((*(*TSrcItem)(unsafe.Pointer(pSrc + 8))).FpSTab)).FnTabRef = (*TTable)(unsafe.Pointer((*(*TSrcItem)(unsafe.Pointer(pSrc + 8))).FpSTab)).FnTabRef - 1
|
|
(*(*TSrcItem)(unsafe.Pointer(pSrc + 8))).FpSTab = uintptr(0)
|
|
}
|
|
if pPk != 0 {
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pPk)).FnKeyCol)) {
|
|
break
|
|
}
|
|
pNew = _exprRowColumn(tls, pParse, int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pPk)).FaiColumn + uintptr(i)*2))))
|
|
pList = _sqlite3ExprListAppend(tls, pParse, pList, pNew)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == int32(TABTYP_VTAB) {
|
|
v2 = int32(SRT_Table)
|
|
} else {
|
|
v2 = int32(SRT_Upfrom)
|
|
}
|
|
eDest = v2
|
|
} else {
|
|
if libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == int32(TABTYP_VIEW) {
|
|
i = 0
|
|
for {
|
|
if !(i < int32((*TTable)(unsafe.Pointer(pTab)).FnCol)) {
|
|
break
|
|
}
|
|
pList = _sqlite3ExprListAppend(tls, pParse, pList, _exprRowColumn(tls, pParse, i))
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = i + 1
|
|
}
|
|
eDest = int32(SRT_Table)
|
|
} else {
|
|
if libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == int32(TABTYP_VTAB) {
|
|
v2 = int32(SRT_Table)
|
|
} else {
|
|
v2 = int32(SRT_Upfrom)
|
|
}
|
|
eDest = v2
|
|
pList = _sqlite3ExprListAppend(tls, pParse, uintptr(0), _sqlite3PExpr(tls, pParse, int32(TK_ROW), uintptr(0), uintptr(0)))
|
|
}
|
|
}
|
|
if pChanges != 0 {
|
|
i = 0
|
|
for {
|
|
if !(i < (*TExprList)(unsafe.Pointer(pChanges)).FnExpr) {
|
|
break
|
|
}
|
|
pList = _sqlite3ExprListAppend(tls, pParse, pList, _sqlite3ExprDup(tls, db, (*(*TExprList_item)(unsafe.Pointer(pChanges + 8 + uintptr(i)*32))).FpExpr, 0))
|
|
goto _5
|
|
_5:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
pSelect = _sqlite3SelectNew(tls, pParse, pList, pSrc, pWhere2, pGrp, uintptr(0), pOrderBy2, libc.Uint32FromInt32(libc.Int32FromInt32(SF_UFSrcCheck)|libc.Int32FromInt32(SF_IncludeHidden)|libc.Int32FromInt32(SF_UpdateFrom)), pLimit2)
|
|
if pSelect != 0 {
|
|
**(**Tu32)(__ccgo_up(pSelect + 4)) |= uint32(SF_OrderByReqd)
|
|
}
|
|
_sqlite3SelectDestInit(tls, bp, eDest, iEph)
|
|
if pPk != 0 {
|
|
v2 = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pPk)).FnKeyCol)
|
|
} else {
|
|
v2 = -int32(1)
|
|
}
|
|
(**(**TSelectDest)(__ccgo_up(bp))).FiSDParm2 = v2
|
|
_sqlite3Select(tls, pParse, pSelect, bp)
|
|
_sqlite3SelectDelete(tls, db, pSelect)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate code for an UPDATE of a virtual table.
|
|
// **
|
|
// ** There are two possible strategies - the default and the special
|
|
// ** "onepass" strategy. Onepass is only used if the virtual table
|
|
// ** implementation indicates that pWhere may match at most one row.
|
|
// **
|
|
// ** The default strategy is to create an ephemeral table that contains
|
|
// ** for each row to be changed:
|
|
// **
|
|
// ** (A) The original rowid of that row.
|
|
// ** (B) The revised rowid for the row.
|
|
// ** (C) The content of every column in the row.
|
|
// **
|
|
// ** Then loop through the contents of this ephemeral table executing a
|
|
// ** VUpdate for each row. When finished, drop the ephemeral table.
|
|
// **
|
|
// ** The "onepass" strategy does not use an ephemeral table. Instead, it
|
|
// ** stores the same values (A, B and C above) in a register array and
|
|
// ** makes a single invocation of VUpdate.
|
|
// */
|
|
func _updateVirtualTable(tls *libc.TLS, pParse uintptr, pSrc uintptr, pTab uintptr, pChanges uintptr, pRowid uintptr, aXRef uintptr, pWhere uintptr, onError int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var addr, eOnePass, ephemTab, i, iCsr, nArg, regArg, regRec, regRowid, v1 int32
|
|
var db, pList, pPk, pPk1, pRow, pRowExpr, pVTab, pWInfo, v, v2 uintptr
|
|
var iPk, iPk1 Ti16
|
|
var _ /* aDummy at bp+0 */ [2]int32
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = addr, db, eOnePass, ephemTab, i, iCsr, iPk, iPk1, nArg, pList, pPk, pPk1, pRow, pRowExpr, pVTab, pWInfo, regArg, regRec, regRowid, v, v1, v2
|
|
v = (*TParse)(unsafe.Pointer(pParse)).FpVdbe /* Loop counter */
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb /* Database connection */
|
|
pVTab = _sqlite3GetVTable(tls, db, pTab)
|
|
pWInfo = uintptr(0)
|
|
nArg = int32(2) + int32((*TTable)(unsafe.Pointer(pTab)).FnCol) /* Register for ephemeral table rowid */
|
|
iCsr = (*(*TSrcItem)(unsafe.Pointer(pSrc + 8))).FiCursor /* Address of OP_OpenEphemeral */
|
|
/* Allocate nArg registers in which to gather the arguments for VUpdate. Then
|
|
** create and open the ephemeral table in which the records created from
|
|
** these arguments will be temporarily stored. */
|
|
v2 = pParse + 56
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
ephemTab = v1
|
|
addr = _sqlite3VdbeAddOp2(tls, v, int32(OP_OpenEphemeral), ephemTab, nArg)
|
|
regArg = (*TParse)(unsafe.Pointer(pParse)).FnMem + int32(1)
|
|
**(**int32)(__ccgo_up(pParse + 60)) += nArg
|
|
if (*TSrcList)(unsafe.Pointer(pSrc)).FnSrc > int32(1) {
|
|
pPk = uintptr(0)
|
|
if (*TTable)(unsafe.Pointer(pTab)).FtabFlags&uint32(TF_WithoutRowid) == uint32(0) {
|
|
if pRowid != 0 {
|
|
pRow = _sqlite3ExprDup(tls, db, pRowid, 0)
|
|
} else {
|
|
pRow = _sqlite3PExpr(tls, pParse, int32(TK_ROW), uintptr(0), uintptr(0))
|
|
}
|
|
} else { /* PRIMARY KEY column */
|
|
pPk = _sqlite3PrimaryKeyIndex(tls, pTab)
|
|
iPk = **(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pPk)).FaiColumn))
|
|
if **(**int32)(__ccgo_up(aXRef + uintptr(iPk)*4)) >= 0 {
|
|
pRow = _sqlite3ExprDup(tls, db, (*(*TExprList_item)(unsafe.Pointer(pChanges + 8 + uintptr(**(**int32)(__ccgo_up(aXRef + uintptr(iPk)*4)))*32))).FpExpr, 0)
|
|
} else {
|
|
pRow = _exprRowColumn(tls, pParse, int32(iPk))
|
|
}
|
|
}
|
|
pList = _sqlite3ExprListAppend(tls, pParse, uintptr(0), pRow)
|
|
i = 0
|
|
for {
|
|
if !(i < int32((*TTable)(unsafe.Pointer(pTab)).FnCol)) {
|
|
break
|
|
}
|
|
if **(**int32)(__ccgo_up(aXRef + uintptr(i)*4)) >= 0 {
|
|
pList = _sqlite3ExprListAppend(tls, pParse, pList, _sqlite3ExprDup(tls, db, (*(*TExprList_item)(unsafe.Pointer(pChanges + 8 + uintptr(**(**int32)(__ccgo_up(aXRef + uintptr(i)*4)))*32))).FpExpr, 0))
|
|
} else {
|
|
pRowExpr = _exprRowColumn(tls, pParse, i)
|
|
if pRowExpr != 0 {
|
|
(*TExpr)(unsafe.Pointer(pRowExpr)).Fop2 = uint8(OPFLAG_NOCHNG)
|
|
}
|
|
pList = _sqlite3ExprListAppend(tls, pParse, pList, pRowExpr)
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = i + 1
|
|
}
|
|
_updateFromSelect(tls, pParse, ephemTab, pPk, pList, pSrc, pWhere, uintptr(0), uintptr(0))
|
|
_sqlite3ExprListDelete(tls, db, pList)
|
|
eOnePass = ONEPASS_OFF
|
|
} else {
|
|
v2 = pParse + 60
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
regRec = v1
|
|
v2 = pParse + 60
|
|
*(*int32)(unsafe.Pointer(v2)) = *(*int32)(unsafe.Pointer(v2)) + 1
|
|
v1 = *(*int32)(unsafe.Pointer(v2))
|
|
regRowid = v1
|
|
/* Start scanning the virtual table */
|
|
pWInfo = _sqlite3WhereBegin(tls, pParse, pSrc, pWhere, uintptr(0), uintptr(0), uintptr(0), uint16(WHERE_ONEPASS_DESIRED), 0)
|
|
if pWInfo == uintptr(0) {
|
|
return
|
|
}
|
|
/* Populate the argument registers. */
|
|
i = 0
|
|
for {
|
|
if !(i < int32((*TTable)(unsafe.Pointer(pTab)).FnCol)) {
|
|
break
|
|
}
|
|
if **(**int32)(__ccgo_up(aXRef + uintptr(i)*4)) >= 0 {
|
|
_sqlite3ExprCode(tls, pParse, (*(*TExprList_item)(unsafe.Pointer(pChanges + 8 + uintptr(**(**int32)(__ccgo_up(aXRef + uintptr(i)*4)))*32))).FpExpr, regArg+int32(2)+i)
|
|
} else {
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_VColumn), iCsr, i, regArg+int32(2)+i)
|
|
_sqlite3VdbeChangeP5(tls, v, uint16(OPFLAG_NOCHNG)) /* For sqlite3_vtab_nochange() */
|
|
}
|
|
goto _8
|
|
_8:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if (*TTable)(unsafe.Pointer(pTab)).FtabFlags&uint32(TF_WithoutRowid) == uint32(0) {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Rowid), iCsr, regArg)
|
|
if pRowid != 0 {
|
|
_sqlite3ExprCode(tls, pParse, pRowid, regArg+int32(1))
|
|
} else {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Rowid), iCsr, regArg+int32(1))
|
|
}
|
|
} else { /* PRIMARY KEY column */
|
|
pPk1 = _sqlite3PrimaryKeyIndex(tls, pTab)
|
|
iPk1 = **(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pPk1)).FaiColumn))
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_VColumn), iCsr, int32(iPk1), regArg)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_SCopy), regArg+int32(2)+int32(iPk1), regArg+int32(1))
|
|
}
|
|
eOnePass = _sqlite3WhereOkOnePass(tls, pWInfo, bp)
|
|
/* There is no ONEPASS_MULTI on virtual tables */
|
|
if eOnePass != 0 {
|
|
/* If using the onepass strategy, no-op out the OP_OpenEphemeral coded
|
|
** above. */
|
|
_sqlite3VdbeChangeToNoop(tls, v, addr)
|
|
_sqlite3VdbeAddOp1(tls, v, int32(OP_Close), iCsr)
|
|
} else {
|
|
/* Create a record from the argument register contents and insert it into
|
|
** the ephemeral table. */
|
|
_sqlite3MultiWrite(tls, pParse)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_MakeRecord), regArg, nArg, regRec)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_NewRowid), ephemTab, regRowid)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Insert), ephemTab, regRec, regRowid)
|
|
}
|
|
}
|
|
if eOnePass == ONEPASS_OFF {
|
|
/* End the virtual table scan */
|
|
if (*TSrcList)(unsafe.Pointer(pSrc)).FnSrc == int32(1) {
|
|
_sqlite3WhereEnd(tls, pWInfo)
|
|
}
|
|
/* Begin scanning through the ephemeral table. */
|
|
addr = _sqlite3VdbeAddOp1(tls, v, int32(OP_Rewind), ephemTab)
|
|
/* Extract arguments from the current row of the ephemeral table and
|
|
** invoke the VUpdate method. */
|
|
i = 0
|
|
for {
|
|
if !(i < nArg) {
|
|
break
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Column), ephemTab, i, regArg+i)
|
|
goto _9
|
|
_9:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
_sqlite3VtabMakeWritable(tls, pParse, pTab)
|
|
_sqlite3VdbeAddOp4(tls, v, int32(OP_VUpdate), 0, nArg, regArg, pVTab, -int32(12))
|
|
if onError == int32(OE_Default) {
|
|
v1 = int32(OE_Abort)
|
|
} else {
|
|
v1 = onError
|
|
}
|
|
_sqlite3VdbeChangeP5(tls, v, libc.Uint16FromInt32(v1))
|
|
_sqlite3MayAbort(tls, pParse)
|
|
/* End of the ephemeral table scan. Or, if using the onepass strategy,
|
|
** jump to here if the scan visited zero rows. */
|
|
if eOnePass == ONEPASS_OFF {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Next), ephemTab, addr+int32(1))
|
|
_sqlite3VdbeJumpHere(tls, v, addr)
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_Close), ephemTab, 0)
|
|
} else {
|
|
_sqlite3WhereEnd(tls, pWInfo)
|
|
}
|
|
}
|
|
|
|
/************** End of update.c **********************************************/
|
|
/************** Begin file upsert.c ******************************************/
|
|
/*
|
|
** 2018-04-12
|
|
**
|
|
** The author disclaims copyright to this source code. In place of
|
|
** a legal notice, here is a blessing:
|
|
**
|
|
** May you do good and not evil.
|
|
** May you find forgiveness for yourself and forgive others.
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
*************************************************************************
|
|
** This file contains code to implement various aspects of UPSERT
|
|
** processing and handling of the Upsert object.
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate and return a pointer to a new sqlite3_value object. If
|
|
// ** the second argument to this function is NULL, the object is allocated
|
|
// ** by calling sqlite3ValueNew().
|
|
// **
|
|
// ** Otherwise, if the second argument is non-zero, then this function is
|
|
// ** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not
|
|
// ** already been allocated, allocate the UnpackedRecord structure that
|
|
// ** that function will return to its caller here. Then return a pointer to
|
|
// ** an sqlite3_value within the UnpackedRecord.a[] array.
|
|
// */
|
|
func _valueNew(tls *libc.TLS, db uintptr, p uintptr) (r uintptr) {
|
|
var i, nCol int32
|
|
var nByte Ti64
|
|
var pIdx, pRec uintptr
|
|
_, _, _, _, _ = i, nByte, nCol, pIdx, pRec
|
|
if p != 0 {
|
|
pRec = **(**uintptr)(__ccgo_up((*TValueNewStat4Ctx)(unsafe.Pointer(p)).FppRec))
|
|
if pRec == uintptr(0) {
|
|
pIdx = (*TValueNewStat4Ctx)(unsafe.Pointer(p)).FpIdx /* Counter variable */
|
|
nCol = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn) /* Number of index columns including rowid */
|
|
nByte = libc.Int64FromUint64(uint64(56)*libc.Uint64FromInt32(nCol) + (libc.Uint64FromInt64(40)+libc.Uint64FromInt32(7))&libc.Uint64FromInt32(^libc.Int32FromInt32(7)))
|
|
pRec = _sqlite3DbMallocZero(tls, db, libc.Uint64FromInt64(nByte))
|
|
if pRec != 0 {
|
|
(*TUnpackedRecord)(unsafe.Pointer(pRec)).FpKeyInfo = _sqlite3KeyInfoOfIndex(tls, (*TValueNewStat4Ctx)(unsafe.Pointer(p)).FpParse, pIdx)
|
|
if (*TUnpackedRecord)(unsafe.Pointer(pRec)).FpKeyInfo != 0 {
|
|
(*TUnpackedRecord)(unsafe.Pointer(pRec)).FaMem = pRec + uintptr((libc.Uint64FromInt64(40)+libc.Uint64FromInt32(7))&libc.Uint64FromInt32(^libc.Int32FromInt32(7)))
|
|
i = 0
|
|
for {
|
|
if !(i < nCol) {
|
|
break
|
|
}
|
|
(**(**TMem)(__ccgo_up((*TUnpackedRecord)(unsafe.Pointer(pRec)).FaMem + uintptr(i)*56))).Fflags = uint16(MEM_Null)
|
|
(**(**TMem)(__ccgo_up((*TUnpackedRecord)(unsafe.Pointer(pRec)).FaMem + uintptr(i)*56))).Fdb = db
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
} else {
|
|
_sqlite3DbFreeNN(tls, db, pRec)
|
|
pRec = uintptr(0)
|
|
}
|
|
}
|
|
if pRec == uintptr(0) {
|
|
return uintptr(0)
|
|
}
|
|
**(**uintptr)(__ccgo_up((*TValueNewStat4Ctx)(unsafe.Pointer(p)).FppRec)) = pRec
|
|
}
|
|
(*TUnpackedRecord)(unsafe.Pointer(pRec)).FnField = libc.Uint16FromInt32((*TValueNewStat4Ctx)(unsafe.Pointer(p)).FiVal + int32(1))
|
|
_sqlite3VdbeMemSetNull(tls, (*TUnpackedRecord)(unsafe.Pointer(pRec)).FaMem+uintptr((*TValueNewStat4Ctx)(unsafe.Pointer(p)).FiVal)*56)
|
|
return (*TUnpackedRecord)(unsafe.Pointer(pRec)).FaMem + uintptr((*TValueNewStat4Ctx)(unsafe.Pointer(p)).FiVal)*56
|
|
}
|
|
return _sqlite3ValueNew(tls, db)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The pVal argument is known to be a value other than NULL.
|
|
// ** Convert it into a string with encoding enc and return a pointer
|
|
// ** to a zero-terminated version of that string.
|
|
// */
|
|
func _valueToText(tls *libc.TLS, pVal uintptr, enc Tu8) (r uintptr) {
|
|
var v1 int32
|
|
var v2 uintptr
|
|
_, _ = v1, v2
|
|
if libc.Int32FromUint16((*Tsqlite3_value)(unsafe.Pointer(pVal)).Fflags)&(libc.Int32FromInt32(MEM_Blob)|libc.Int32FromInt32(MEM_Str)) != 0 {
|
|
if libc.Int32FromUint16((*Tsqlite3_value)(unsafe.Pointer(pVal)).Fflags)&int32(MEM_Zero) != 0 {
|
|
v1 = _sqlite3VdbeMemExpandBlob(tls, pVal)
|
|
} else {
|
|
v1 = 0
|
|
}
|
|
if v1 != 0 {
|
|
return uintptr(0)
|
|
}
|
|
v2 = pVal + 20
|
|
*(*Tu16)(unsafe.Pointer(v2)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v2))) | libc.Int32FromInt32(MEM_Str))
|
|
if libc.Int32FromUint8((*Tsqlite3_value)(unsafe.Pointer(pVal)).Fenc) != libc.Int32FromUint8(enc) & ^libc.Int32FromInt32(SQLITE_UTF16_ALIGNED) {
|
|
_sqlite3VdbeChangeEncoding(tls, pVal, libc.Int32FromUint8(enc) & ^libc.Int32FromInt32(SQLITE_UTF16_ALIGNED))
|
|
}
|
|
if libc.Int32FromUint8(enc)&int32(SQLITE_UTF16_ALIGNED) != 0 && int32(1) == int32(1)&int32(int64((*Tsqlite3_value)(unsafe.Pointer(pVal)).Fz)) {
|
|
if _sqlite3VdbeMemMakeWriteable(tls, pVal) != SQLITE_OK {
|
|
return uintptr(0)
|
|
}
|
|
}
|
|
_sqlite3VdbeMemNulTerminate(tls, pVal) /* IMP: R-31275-44060 */
|
|
} else {
|
|
_sqlite3VdbeMemStringify(tls, pVal, enc, uint8(0))
|
|
}
|
|
if libc.Int32FromUint8((*Tsqlite3_value)(unsafe.Pointer(pVal)).Fenc) == libc.Int32FromUint8(enc) & ^libc.Int32FromInt32(SQLITE_UTF16_ALIGNED) {
|
|
return (*Tsqlite3_value)(unsafe.Pointer(pVal)).Fz
|
|
} else {
|
|
return uintptr(0)
|
|
}
|
|
return r
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Change the value of the P4 operand for a specific instruction.
|
|
// ** This routine is useful when a large program is loaded from a
|
|
// ** static array using sqlite3VdbeAddOpList but we want to make a
|
|
// ** few minor changes to the program.
|
|
// **
|
|
// ** If n>=0 then the P4 operand is dynamic, meaning that a copy of
|
|
// ** the string is made into memory obtained from sqlite3_malloc().
|
|
// ** A value of n==0 means copy bytes of zP4 up to and including the
|
|
// ** first null byte. If n>0 then copy n+1 bytes of zP4.
|
|
// **
|
|
// ** Other values of n (P4_STATIC, P4_COLLSEQ etc.) indicate that zP4 points
|
|
// ** to a string or structure that is guaranteed to exist for the lifetime of
|
|
// ** the Vdbe. In these cases we can just copy the pointer.
|
|
// **
|
|
// ** If addr<0 then change P4 on the most recently inserted instruction.
|
|
// */
|
|
func _vdbeChangeP4Full(tls *libc.TLS, p uintptr, pOp uintptr, zP4 uintptr, n int32) {
|
|
if (*TOp)(unsafe.Pointer(pOp)).Fp4type != 0 {
|
|
(*TOp)(unsafe.Pointer(pOp)).Fp4type = 0
|
|
*(*uintptr)(unsafe.Pointer(pOp + 16)) = uintptr(0)
|
|
}
|
|
if n < 0 {
|
|
_sqlite3VdbeChangeP4(tls, p, int32((int64(pOp)-int64((*TVdbe)(unsafe.Pointer(p)).FaOp))/24), zP4, n)
|
|
} else {
|
|
if n == 0 {
|
|
n = _sqlite3Strlen30(tls, zP4)
|
|
}
|
|
*(*uintptr)(unsafe.Pointer(pOp + 16)) = _sqlite3DbStrNDup(tls, (*TVdbe)(unsafe.Pointer(p)).Fdb, zP4, libc.Uint64FromInt32(n))
|
|
(*TOp)(unsafe.Pointer(pOp)).Fp4type = int8(-libc.Int32FromInt32(7))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Read keys from pIncr->pMerger and populate pIncr->aFile[1]. The format
|
|
// ** of the data stored in aFile[1] is the same as that used by regular PMAs,
|
|
// ** except that the number-of-bytes varint is omitted from the start.
|
|
// */
|
|
func _vdbeIncrPopulate(tls *libc.TLS, pIncr uintptr) (r int32) {
|
|
bp := tls.Alloc(64)
|
|
defer tls.Free(64)
|
|
var iEof, iStart Ti64
|
|
var nKey, rc, rc2 int32
|
|
var pMerger, pOut, pReader, pTask uintptr
|
|
var _ /* dummy at bp+56 */ int32
|
|
var _ /* writer at bp+0 */ TPmaWriter
|
|
_, _, _, _, _, _, _, _, _ = iEof, iStart, nKey, pMerger, pOut, pReader, pTask, rc, rc2
|
|
rc = SQLITE_OK
|
|
iStart = (*TIncrMerger)(unsafe.Pointer(pIncr)).FiStartOff
|
|
pOut = pIncr + 40 + 1*16
|
|
pTask = (*TIncrMerger)(unsafe.Pointer(pIncr)).FpTask
|
|
pMerger = (*TIncrMerger)(unsafe.Pointer(pIncr)).FpMerger
|
|
_vdbePmaWriterInit(tls, (*TSorterFile)(unsafe.Pointer(pOut)).FpFd, bp, (*TVdbeSorter)(unsafe.Pointer((*TSortSubtask)(unsafe.Pointer(pTask)).FpSorter)).Fpgsz, iStart)
|
|
for rc == SQLITE_OK {
|
|
pReader = (*TMergeEngine)(unsafe.Pointer(pMerger)).FaReadr + uintptr(**(**int32)(__ccgo_up((*TMergeEngine)(unsafe.Pointer(pMerger)).FaTree + 1*4)))*80
|
|
nKey = (*TPmaReader)(unsafe.Pointer(pReader)).FnKey
|
|
iEof = (**(**TPmaWriter)(__ccgo_up(bp))).FiWriteOff + int64((**(**TPmaWriter)(__ccgo_up(bp))).FiBufEnd)
|
|
/* Check if the output file is full or if the input has been exhausted.
|
|
** In either case exit the loop. */
|
|
if (*TPmaReader)(unsafe.Pointer(pReader)).FpFd == uintptr(0) {
|
|
break
|
|
}
|
|
if iEof+int64(nKey)+int64(_sqlite3VarintLen(tls, libc.Uint64FromInt32(nKey))) > iStart+int64((*TIncrMerger)(unsafe.Pointer(pIncr)).FmxSz) {
|
|
break
|
|
}
|
|
/* Write the next key to the output. */
|
|
_vdbePmaWriteVarint(tls, bp, libc.Uint64FromInt32(nKey))
|
|
_vdbePmaWriteBlob(tls, bp, (*TPmaReader)(unsafe.Pointer(pReader)).FaKey, nKey)
|
|
rc = _vdbeMergeEngineStep(tls, (*TIncrMerger)(unsafe.Pointer(pIncr)).FpMerger, bp+56)
|
|
}
|
|
rc2 = _vdbePmaWriterFinish(tls, bp, pOut+8, pTask+96)
|
|
if rc == SQLITE_OK {
|
|
rc = rc2
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** If the memory cell contains a value that must be freed by
|
|
// ** invoking the external callback in Mem.xDel, then this routine
|
|
// ** will free that value. It also sets Mem.flags to MEM_Null.
|
|
// **
|
|
// ** This is a helper routine for sqlite3VdbeMemSetNull() and
|
|
// ** for sqlite3VdbeMemRelease(). Use those other routines as the
|
|
// ** entry point for releasing Mem resources.
|
|
// */
|
|
func _vdbeMemClearExternAndSetNull(tls *libc.TLS, p uintptr) {
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&int32(MEM_Agg) != 0 {
|
|
_sqlite3VdbeMemFinalize(tls, p, *(*uintptr)(unsafe.Pointer(p)))
|
|
}
|
|
if libc.Int32FromUint16((*TMem)(unsafe.Pointer(p)).Fflags)&int32(MEM_Dyn) != 0 {
|
|
(*(*func(*libc.TLS, uintptr))(unsafe.Pointer(&struct{ uintptr }{(*TMem)(unsafe.Pointer(p)).FxDel})))(tls, (*TMem)(unsafe.Pointer(p)).Fz)
|
|
}
|
|
(*TMem)(unsafe.Pointer(p)).Fflags = uint16(MEM_Null)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Initialize the MergeEngine object passed as the second argument. Once this
|
|
// ** function returns, the first key of merged data may be read from the
|
|
// ** MergeEngine object in the usual fashion.
|
|
// **
|
|
// ** If argument eMode is INCRINIT_ROOT, then it is assumed that any IncrMerge
|
|
// ** objects attached to the PmaReader objects that the merger reads from have
|
|
// ** already been populated, but that they have not yet populated aFile[0] and
|
|
// ** set the PmaReader objects up to read from it. In this case all that is
|
|
// ** required is to call vdbePmaReaderNext() on each PmaReader to point it at
|
|
// ** its first key.
|
|
// **
|
|
// ** Otherwise, if eMode is any value other than INCRINIT_ROOT, then use
|
|
// ** vdbePmaReaderIncrMergeInit() to initialize each PmaReader that feeds data
|
|
// ** to pMerger.
|
|
// **
|
|
// ** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
|
|
// */
|
|
func _vdbeMergeEngineInit(tls *libc.TLS, pTask uintptr, pMerger uintptr, eMode int32) (r int32) {
|
|
var i, nTree, rc int32
|
|
_, _, _ = i, nTree, rc
|
|
rc = SQLITE_OK /* Number of subtrees to merge */
|
|
/* Failure to allocate the merge would have been detected prior to
|
|
** invoking this routine */
|
|
/* eMode is always INCRINIT_NORMAL in single-threaded mode */
|
|
/* Verify that the MergeEngine is assigned to a single thread */
|
|
(*TMergeEngine)(unsafe.Pointer(pMerger)).FpTask = pTask
|
|
nTree = (*TMergeEngine)(unsafe.Pointer(pMerger)).FnTree
|
|
i = 0
|
|
for {
|
|
if !(i < nTree) {
|
|
break
|
|
}
|
|
if libc.Bool(int32(SQLITE_MAX_WORKER_THREADS) > 0) && eMode == int32(INCRINIT_ROOT) {
|
|
/* PmaReaders should be normally initialized in order, as if they are
|
|
** reading from the same temp file this makes for more linear file IO.
|
|
** However, in the INCRINIT_ROOT case, if PmaReader aReadr[nTask-1] is
|
|
** in use it will block the vdbePmaReaderNext() call while it uses
|
|
** the main thread to fill its buffer. So calling PmaReaderNext()
|
|
** on this PmaReader before any of the multi-threaded PmaReaders takes
|
|
** better advantage of multi-processor hardware. */
|
|
rc = _vdbePmaReaderNext(tls, (*TMergeEngine)(unsafe.Pointer(pMerger)).FaReadr+uintptr(nTree-i-int32(1))*80)
|
|
} else {
|
|
rc = _vdbePmaReaderIncrInit(tls, (*TMergeEngine)(unsafe.Pointer(pMerger)).FaReadr+uintptr(i)*80, INCRINIT_NORMAL)
|
|
}
|
|
if rc != SQLITE_OK {
|
|
return rc
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
i = (*TMergeEngine)(unsafe.Pointer(pMerger)).FnTree - int32(1)
|
|
for {
|
|
if !(i > 0) {
|
|
break
|
|
}
|
|
_vdbeMergeEngineCompare(tls, pMerger, i)
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i - 1
|
|
}
|
|
return libc.Int32FromUint8((*TUnpackedRecord)(unsafe.Pointer((*TSortSubtask)(unsafe.Pointer(pTask)).FpUnpacked)).FerrCode)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Allocate a new MergeEngine object capable of handling up to
|
|
// ** nReader PmaReader inputs.
|
|
// **
|
|
// ** nReader is automatically rounded up to the next power of two.
|
|
// ** nReader may not exceed SORTER_MAX_MERGE_COUNT even after rounding up.
|
|
// */
|
|
func _vdbeMergeEngineNew(tls *libc.TLS, nReader int32) (r uintptr) {
|
|
var N int32
|
|
var nByte Ti64
|
|
var pNew, v1 uintptr
|
|
_, _, _, _ = N, nByte, pNew, v1
|
|
N = int32(2) /* Pointer to allocated object to return */
|
|
for N < nReader {
|
|
N = N + N
|
|
}
|
|
nByte = libc.Int64FromUint64(uint64(32) + libc.Uint64FromInt32(N)*(libc.Uint64FromInt64(4)+libc.Uint64FromInt64(80)))
|
|
if _sqlite3FaultSim(tls, int32(100)) != 0 {
|
|
v1 = uintptr(0)
|
|
} else {
|
|
v1 = _sqlite3MallocZero(tls, libc.Uint64FromInt64(nByte))
|
|
}
|
|
pNew = v1
|
|
if pNew != 0 {
|
|
(*TMergeEngine)(unsafe.Pointer(pNew)).FnTree = N
|
|
(*TMergeEngine)(unsafe.Pointer(pNew)).FpTask = uintptr(0)
|
|
(*TMergeEngine)(unsafe.Pointer(pNew)).FaReadr = pNew + 1*32
|
|
(*TMergeEngine)(unsafe.Pointer(pNew)).FaTree = (*TMergeEngine)(unsafe.Pointer(pNew)).FaReadr + uintptr(N)*80
|
|
}
|
|
return pNew
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Advance the MergeEngine to its next entry.
|
|
// ** Set *pbEof to true there is no next entry because
|
|
// ** the MergeEngine has reached the end of all its inputs.
|
|
// **
|
|
// ** Return SQLITE_OK if successful or an error code if an error occurs.
|
|
// */
|
|
func _vdbeMergeEngineStep(tls *libc.TLS, pMerger uintptr, pbEof uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var i, iPrev, iRes, rc, v2 int32
|
|
var pReadr1, pReadr2, pTask uintptr
|
|
var _ /* bCached at bp+0 */ int32
|
|
_, _, _, _, _, _, _, _ = i, iPrev, iRes, pReadr1, pReadr2, pTask, rc, v2
|
|
iPrev = **(**int32)(__ccgo_up((*TMergeEngine)(unsafe.Pointer(pMerger)).FaTree + 1*4)) /* Index of PmaReader to advance */
|
|
pTask = (*TMergeEngine)(unsafe.Pointer(pMerger)).FpTask
|
|
/* Advance the current PmaReader */
|
|
rc = _vdbePmaReaderNext(tls, (*TMergeEngine)(unsafe.Pointer(pMerger)).FaReadr+uintptr(iPrev)*80)
|
|
/* Update contents of aTree[] */
|
|
if rc == SQLITE_OK { /* Second PmaReader to compare */
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
/* Find the first two PmaReaders to compare. The one that was just
|
|
** advanced (iPrev) and the one next to it in the array. */
|
|
pReadr1 = (*TMergeEngine)(unsafe.Pointer(pMerger)).FaReadr + uintptr(iPrev&libc.Int32FromInt32(0xFFFE))*80
|
|
pReadr2 = (*TMergeEngine)(unsafe.Pointer(pMerger)).FaReadr + uintptr(iPrev|libc.Int32FromInt32(0x0001))*80
|
|
i = ((*TMergeEngine)(unsafe.Pointer(pMerger)).FnTree + iPrev) / int32(2)
|
|
for {
|
|
if !(i > 0) {
|
|
break
|
|
}
|
|
if (*TPmaReader)(unsafe.Pointer(pReadr1)).FpFd == uintptr(0) {
|
|
iRes = +libc.Int32FromInt32(1)
|
|
} else {
|
|
if (*TPmaReader)(unsafe.Pointer(pReadr2)).FpFd == uintptr(0) {
|
|
iRes = -int32(1)
|
|
} else {
|
|
iRes = (*(*func(*libc.TLS, uintptr, uintptr, uintptr, int32, uintptr, int32) int32)(unsafe.Pointer(&struct{ uintptr }{(*TSortSubtask)(unsafe.Pointer(pTask)).FxCompare})))(tls, pTask, bp, (*TPmaReader)(unsafe.Pointer(pReadr1)).FaKey, (*TPmaReader)(unsafe.Pointer(pReadr1)).FnKey, (*TPmaReader)(unsafe.Pointer(pReadr2)).FaKey, (*TPmaReader)(unsafe.Pointer(pReadr2)).FnKey)
|
|
}
|
|
}
|
|
/* If pReadr1 contained the smaller value, set aTree[i] to its index.
|
|
** Then set pReadr2 to the next PmaReader to compare to pReadr1. In this
|
|
** case there is no cache of pReadr2 in pTask->pUnpacked, so set
|
|
** pKey2 to point to the record belonging to pReadr2.
|
|
**
|
|
** Alternatively, if pReadr2 contains the smaller of the two values,
|
|
** set aTree[i] to its index and update pReadr1. If vdbeSorterCompare()
|
|
** was actually called above, then pTask->pUnpacked now contains
|
|
** a value equivalent to pReadr2. So set pKey2 to NULL to prevent
|
|
** vdbeSorterCompare() from decoding pReadr2 again.
|
|
**
|
|
** If the two values were equal, then the value from the oldest
|
|
** PMA should be considered smaller. The VdbeSorter.aReadr[] array
|
|
** is sorted from oldest to newest, so pReadr1 contains older values
|
|
** than pReadr2 iff (pReadr1<pReadr2). */
|
|
if iRes < 0 || iRes == 0 && pReadr1 < pReadr2 {
|
|
**(**int32)(__ccgo_up((*TMergeEngine)(unsafe.Pointer(pMerger)).FaTree + uintptr(i)*4)) = int32((int64(pReadr1) - int64((*TMergeEngine)(unsafe.Pointer(pMerger)).FaReadr)) / 80)
|
|
pReadr2 = (*TMergeEngine)(unsafe.Pointer(pMerger)).FaReadr + uintptr(**(**int32)(__ccgo_up((*TMergeEngine)(unsafe.Pointer(pMerger)).FaTree + uintptr(i^int32(0x0001))*4)))*80
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
} else {
|
|
if (*TPmaReader)(unsafe.Pointer(pReadr1)).FpFd != 0 {
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
}
|
|
**(**int32)(__ccgo_up((*TMergeEngine)(unsafe.Pointer(pMerger)).FaTree + uintptr(i)*4)) = int32((int64(pReadr2) - int64((*TMergeEngine)(unsafe.Pointer(pMerger)).FaReadr)) / 80)
|
|
pReadr1 = (*TMergeEngine)(unsafe.Pointer(pMerger)).FaReadr + uintptr(**(**int32)(__ccgo_up((*TMergeEngine)(unsafe.Pointer(pMerger)).FaTree + uintptr(i^int32(0x0001))*4)))*80
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i / int32(2)
|
|
}
|
|
**(**int32)(__ccgo_up(pbEof)) = libc.BoolInt32((**(**TPmaReader)(__ccgo_up((*TMergeEngine)(unsafe.Pointer(pMerger)).FaReadr + uintptr(**(**int32)(__ccgo_up((*TMergeEngine)(unsafe.Pointer(pMerger)).FaTree + 1*4)))*80))).FpFd == uintptr(0))
|
|
}
|
|
if rc == SQLITE_OK {
|
|
v2 = libc.Int32FromUint8((*TUnpackedRecord)(unsafe.Pointer((*TSortSubtask)(unsafe.Pointer(pTask)).FpUnpacked)).FerrCode)
|
|
} else {
|
|
v2 = rc
|
|
}
|
|
return v2
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Advance PmaReader pReadr to the next key in its PMA. Return SQLITE_OK if
|
|
// ** no error occurs, or an SQLite error code if one does.
|
|
// */
|
|
func _vdbePmaReaderNext(tls *libc.TLS, pReadr uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var bEof, rc int32
|
|
var pIncr uintptr
|
|
var _ /* nRec at bp+0 */ Tu64
|
|
_, _, _ = bEof, pIncr, rc
|
|
rc = SQLITE_OK /* Return Code */
|
|
**(**Tu64)(__ccgo_up(bp)) = uint64(0) /* Size of record in bytes */
|
|
if (*TPmaReader)(unsafe.Pointer(pReadr)).FiReadOff >= (*TPmaReader)(unsafe.Pointer(pReadr)).FiEof {
|
|
pIncr = (*TPmaReader)(unsafe.Pointer(pReadr)).FpIncr
|
|
bEof = int32(1)
|
|
if pIncr != 0 {
|
|
rc = _vdbeIncrSwap(tls, pIncr)
|
|
if rc == SQLITE_OK && (*TIncrMerger)(unsafe.Pointer(pIncr)).FbEof == 0 {
|
|
rc = _vdbePmaReaderSeek(tls, (*TIncrMerger)(unsafe.Pointer(pIncr)).FpTask, pReadr, pIncr+40, (*TIncrMerger)(unsafe.Pointer(pIncr)).FiStartOff)
|
|
bEof = 0
|
|
}
|
|
}
|
|
if bEof != 0 {
|
|
/* This is an EOF condition */
|
|
_vdbePmaReaderClear(tls, pReadr)
|
|
return rc
|
|
}
|
|
}
|
|
if rc == SQLITE_OK {
|
|
rc = _vdbePmaReadVarint(tls, pReadr, bp)
|
|
}
|
|
if rc == SQLITE_OK {
|
|
(*TPmaReader)(unsafe.Pointer(pReadr)).FnKey = libc.Int32FromUint64(**(**Tu64)(__ccgo_up(bp)))
|
|
rc = _vdbePmaReadBlob(tls, pReadr, libc.Int32FromUint64(**(**Tu64)(__ccgo_up(bp))), pReadr+40)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Attach PmaReader pReadr to file pFile (if it is not already attached to
|
|
// ** that file) and seek it to offset iOff within the file. Return SQLITE_OK
|
|
// ** if successful, or an SQLite error code if an error occurs.
|
|
// */
|
|
func _vdbePmaReaderSeek(tls *libc.TLS, pTask uintptr, pReadr uintptr, pFile uintptr, iOff Ti64) (r int32) {
|
|
var iBuf, nRead, pgsz, rc int32
|
|
_, _, _, _ = iBuf, nRead, pgsz, rc
|
|
rc = SQLITE_OK
|
|
if _sqlite3FaultSim(tls, int32(201)) != 0 {
|
|
return libc.Int32FromInt32(SQLITE_IOERR) | libc.Int32FromInt32(1)<<libc.Int32FromInt32(8)
|
|
}
|
|
if (*TPmaReader)(unsafe.Pointer(pReadr)).FaMap != 0 {
|
|
_sqlite3OsUnfetch(tls, (*TPmaReader)(unsafe.Pointer(pReadr)).FpFd, 0, (*TPmaReader)(unsafe.Pointer(pReadr)).FaMap)
|
|
(*TPmaReader)(unsafe.Pointer(pReadr)).FaMap = uintptr(0)
|
|
}
|
|
(*TPmaReader)(unsafe.Pointer(pReadr)).FiReadOff = iOff
|
|
(*TPmaReader)(unsafe.Pointer(pReadr)).FiEof = (*TSorterFile)(unsafe.Pointer(pFile)).FiEof
|
|
(*TPmaReader)(unsafe.Pointer(pReadr)).FpFd = (*TSorterFile)(unsafe.Pointer(pFile)).FpFd
|
|
rc = _vdbeSorterMapFile(tls, pTask, pFile, pReadr+64)
|
|
if rc == SQLITE_OK && (*TPmaReader)(unsafe.Pointer(pReadr)).FaMap == uintptr(0) {
|
|
pgsz = (*TVdbeSorter)(unsafe.Pointer((*TSortSubtask)(unsafe.Pointer(pTask)).FpSorter)).Fpgsz
|
|
iBuf = int32((*TPmaReader)(unsafe.Pointer(pReadr)).FiReadOff % int64(pgsz))
|
|
if (*TPmaReader)(unsafe.Pointer(pReadr)).FaBuffer == uintptr(0) {
|
|
(*TPmaReader)(unsafe.Pointer(pReadr)).FaBuffer = _sqlite3Malloc(tls, libc.Uint64FromInt32(pgsz))
|
|
if (*TPmaReader)(unsafe.Pointer(pReadr)).FaBuffer == uintptr(0) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
}
|
|
(*TPmaReader)(unsafe.Pointer(pReadr)).FnBuffer = pgsz
|
|
}
|
|
if rc == SQLITE_OK && iBuf != 0 {
|
|
nRead = pgsz - iBuf
|
|
if (*TPmaReader)(unsafe.Pointer(pReadr)).FiReadOff+int64(nRead) > (*TPmaReader)(unsafe.Pointer(pReadr)).FiEof {
|
|
nRead = int32((*TPmaReader)(unsafe.Pointer(pReadr)).FiEof - (*TPmaReader)(unsafe.Pointer(pReadr)).FiReadOff)
|
|
}
|
|
rc = _sqlite3OsRead(tls, (*TPmaReader)(unsafe.Pointer(pReadr)).FpFd, (*TPmaReader)(unsafe.Pointer(pReadr)).FaBuffer+uintptr(iBuf), nRead, (*TPmaReader)(unsafe.Pointer(pReadr)).FiReadOff)
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is an optimized version of sqlite3VdbeRecordCompare()
|
|
// ** that (a) the first field of pPKey2 is an integer, and (b) the
|
|
// ** size-of-header varint at the start of (pKey1/nKey1) fits in a single
|
|
// ** byte (i.e. is less than 128).
|
|
// **
|
|
// ** To avoid concerns about buffer overreads, this routine is only used
|
|
// ** on schemas where the maximum valid header size is 63 bytes or less.
|
|
// */
|
|
func _vdbeRecordCompareInt(tls *libc.TLS, nKey1 int32, pKey1 uintptr, pPKey2 uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var aKey uintptr
|
|
var lhs, v Ti64
|
|
var res, serial_type int32
|
|
var _ /* x at bp+8 */ Tu64
|
|
var _ /* y at bp+0 */ Tu32
|
|
_, _, _, _, _ = aKey, lhs, res, serial_type, v
|
|
aKey = pKey1 + uintptr(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pKey1)))&int32(0x3F))
|
|
serial_type = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(pKey1 + 1)))
|
|
switch serial_type {
|
|
case int32(1): /* 1-byte signed integer */
|
|
lhs = int64(libc.Int8FromUint8(**(**Tu8)(__ccgo_up(aKey))))
|
|
case int32(2): /* 2-byte signed integer */
|
|
lhs = int64(libc.Int32FromInt32(256)*int32(libc.Int8FromUint8(**(**Tu8)(__ccgo_up(aKey)))) | libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aKey + 1))))
|
|
case int32(3): /* 3-byte signed integer */
|
|
lhs = int64(libc.Int32FromInt32(65536)*int32(libc.Int8FromUint8(**(**Tu8)(__ccgo_up(aKey)))) | libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aKey + 1)))<<libc.Int32FromInt32(8) | libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aKey + 2))))
|
|
case int32(4): /* 4-byte signed integer */
|
|
**(**Tu32)(__ccgo_up(bp)) = uint32(**(**Tu8)(__ccgo_up(aKey)))<<libc.Int32FromInt32(24) | libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aKey + 1)))<<libc.Int32FromInt32(16)) | libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aKey + 2)))<<libc.Int32FromInt32(8)) | uint32(**(**Tu8)(__ccgo_up(aKey + 3)))
|
|
lhs = int64(**(**int32)(__ccgo_up(bp)))
|
|
case int32(5): /* 6-byte signed integer */
|
|
lhs = libc.Int64FromUint32(uint32(**(**Tu8)(__ccgo_up(aKey + libc.UintptrFromInt32(2))))<<libc.Int32FromInt32(24)|libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aKey + libc.UintptrFromInt32(2) + 1)))<<libc.Int32FromInt32(16))|libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aKey + libc.UintptrFromInt32(2) + 2)))<<libc.Int32FromInt32(8))|uint32(**(**Tu8)(__ccgo_up(aKey + libc.UintptrFromInt32(2) + 3)))) + libc.Int64FromInt32(1)<<libc.Int32FromInt32(32)*int64(libc.Int32FromInt32(256)*int32(libc.Int8FromUint8(**(**Tu8)(__ccgo_up(aKey))))|libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aKey + 1))))
|
|
case int32(6): /* 8-byte signed integer */
|
|
**(**Tu64)(__ccgo_up(bp + 8)) = uint64(uint32(**(**Tu8)(__ccgo_up(aKey)))<<libc.Int32FromInt32(24) | libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aKey + 1)))<<libc.Int32FromInt32(16)) | libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aKey + 2)))<<libc.Int32FromInt32(8)) | uint32(**(**Tu8)(__ccgo_up(aKey + 3))))
|
|
**(**Tu64)(__ccgo_up(bp + 8)) = **(**Tu64)(__ccgo_up(bp + 8))<<libc.Int32FromInt32(32) | uint64(uint32(**(**Tu8)(__ccgo_up(aKey + libc.UintptrFromInt32(4))))<<libc.Int32FromInt32(24)|libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aKey + libc.UintptrFromInt32(4) + 1)))<<libc.Int32FromInt32(16))|libc.Uint32FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aKey + libc.UintptrFromInt32(4) + 2)))<<libc.Int32FromInt32(8))|uint32(**(**Tu8)(__ccgo_up(aKey + libc.UintptrFromInt32(4) + 3))))
|
|
lhs = **(**Ti64)(__ccgo_up(bp + 8))
|
|
case int32(8):
|
|
lhs = 0
|
|
case int32(9):
|
|
lhs = int64(1)
|
|
break
|
|
/* This case could be removed without changing the results of running
|
|
** this code. Including it causes gcc to generate a faster switch
|
|
** statement (since the range of switch targets now starts at zero and
|
|
** is contiguous) but does not cause any duplicate code to be generated
|
|
** (as gcc is clever enough to combine the two like cases). Other
|
|
** compilers might be similar. */
|
|
fallthrough
|
|
case 0:
|
|
fallthrough
|
|
case int32(7):
|
|
return _sqlite3VdbeRecordCompare(tls, nKey1, pKey1, pPKey2)
|
|
default:
|
|
return _sqlite3VdbeRecordCompare(tls, nKey1, pKey1, pPKey2)
|
|
}
|
|
v = *(*Ti64)(unsafe.Pointer(pPKey2 + 16))
|
|
if v > lhs {
|
|
res = int32((*TUnpackedRecord)(unsafe.Pointer(pPKey2)).Fr1)
|
|
} else {
|
|
if v < lhs {
|
|
res = int32((*TUnpackedRecord)(unsafe.Pointer(pPKey2)).Fr2)
|
|
} else {
|
|
if libc.Int32FromUint16((*TUnpackedRecord)(unsafe.Pointer(pPKey2)).FnField) > int32(1) {
|
|
/* The first fields of the two keys are equal. Compare the trailing
|
|
** fields. */
|
|
res = _sqlite3VdbeRecordCompareWithSkip(tls, nKey1, pKey1, pPKey2, int32(1))
|
|
} else {
|
|
/* The first fields of the two keys are equal and there are no trailing
|
|
** fields. Return pPKey2->default_rc in this case. */
|
|
res = int32((*TUnpackedRecord)(unsafe.Pointer(pPKey2)).Fdefault_rc)
|
|
(*TUnpackedRecord)(unsafe.Pointer(pPKey2)).FeqSeen = uint8(1)
|
|
}
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is an optimized version of sqlite3VdbeRecordCompare()
|
|
// ** that (a) the first field of pPKey2 is a string, that (b) the first field
|
|
// ** uses the collation sequence BINARY and (c) that the size-of-header varint
|
|
// ** at the start of (pKey1/nKey1) fits in a single byte.
|
|
// */
|
|
func _vdbeRecordCompareString(tls *libc.TLS, nKey1 int32, pKey1 uintptr, pPKey2 uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var aKey1 uintptr
|
|
var nCmp, nStr, res, szHdr, v1 int32
|
|
var _ /* serial_type at bp+0 */ int32
|
|
_, _, _, _, _, _ = aKey1, nCmp, nStr, res, szHdr, v1
|
|
aKey1 = pKey1
|
|
**(**int32)(__ccgo_up(bp)) = int32(libc.Int8FromUint8(**(**Tu8)(__ccgo_up(aKey1 + 1))))
|
|
goto vrcs_restart
|
|
vrcs_restart:
|
|
;
|
|
if **(**int32)(__ccgo_up(bp)) < int32(12) {
|
|
if **(**int32)(__ccgo_up(bp)) < 0 {
|
|
_sqlite3GetVarint32(tls, aKey1+1, bp)
|
|
if **(**int32)(__ccgo_up(bp)) >= int32(12) {
|
|
goto vrcs_restart
|
|
}
|
|
}
|
|
res = int32((*TUnpackedRecord)(unsafe.Pointer(pPKey2)).Fr1) /* (pKey1/nKey1) is a number or a null */
|
|
} else {
|
|
if !(**(**int32)(__ccgo_up(bp))&libc.Int32FromInt32(0x01) != 0) {
|
|
res = int32((*TUnpackedRecord)(unsafe.Pointer(pPKey2)).Fr2) /* (pKey1/nKey1) is a blob */
|
|
} else {
|
|
szHdr = libc.Int32FromUint8(**(**Tu8)(__ccgo_up(aKey1)))
|
|
nStr = (**(**int32)(__ccgo_up(bp)) - int32(12)) / int32(2)
|
|
if szHdr+nStr > nKey1 {
|
|
(*TUnpackedRecord)(unsafe.Pointer(pPKey2)).FerrCode = libc.Uint8FromInt32(_sqlite3CorruptError(tls, int32(92972)))
|
|
return 0 /* Corruption */
|
|
}
|
|
if (*TUnpackedRecord)(unsafe.Pointer(pPKey2)).Fn < nStr {
|
|
v1 = (*TUnpackedRecord)(unsafe.Pointer(pPKey2)).Fn
|
|
} else {
|
|
v1 = nStr
|
|
}
|
|
nCmp = v1
|
|
res = libc.Xmemcmp(tls, aKey1+uintptr(szHdr), *(*uintptr)(unsafe.Pointer(pPKey2 + 16)), libc.Uint64FromInt32(nCmp))
|
|
if res > 0 {
|
|
res = int32((*TUnpackedRecord)(unsafe.Pointer(pPKey2)).Fr2)
|
|
} else {
|
|
if res < 0 {
|
|
res = int32((*TUnpackedRecord)(unsafe.Pointer(pPKey2)).Fr1)
|
|
} else {
|
|
res = nStr - (*TUnpackedRecord)(unsafe.Pointer(pPKey2)).Fn
|
|
if res == 0 {
|
|
if libc.Int32FromUint16((*TUnpackedRecord)(unsafe.Pointer(pPKey2)).FnField) > int32(1) {
|
|
res = _sqlite3VdbeRecordCompareWithSkip(tls, nKey1, pKey1, pPKey2, int32(1))
|
|
} else {
|
|
res = int32((*TUnpackedRecord)(unsafe.Pointer(pPKey2)).Fdefault_rc)
|
|
(*TUnpackedRecord)(unsafe.Pointer(pPKey2)).FeqSeen = uint8(1)
|
|
}
|
|
} else {
|
|
if res > 0 {
|
|
res = int32((*TUnpackedRecord)(unsafe.Pointer(pPKey2)).Fr2)
|
|
} else {
|
|
res = int32((*TUnpackedRecord)(unsafe.Pointer(pPKey2)).Fr1)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** A specially optimized version of vdbeSorterCompare() that assumes that
|
|
// ** the first field of each key is a TEXT value and that the collation
|
|
// ** sequence to compare them with is BINARY.
|
|
// */
|
|
func _vdbeSorterCompareText(tls *libc.TLS, pTask uintptr, pbKey2Cached uintptr, pKey1 uintptr, nKey1 int32, pKey2 uintptr, nKey2 int32) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var p1, p2, v1, v2 uintptr
|
|
var res, v11 int32
|
|
var _ /* n1 at bp+0 */ int32
|
|
var _ /* n2 at bp+4 */ int32
|
|
_, _, _, _, _, _ = p1, p2, res, v1, v2, v11
|
|
p1 = pKey1
|
|
p2 = pKey2
|
|
v1 = p1 + uintptr(**(**Tu8)(__ccgo_up(p1))) /* Pointer to value 1 */
|
|
v2 = p2 + uintptr(**(**Tu8)(__ccgo_up(p2)))
|
|
**(**int32)(__ccgo_up(bp)) = libc.Int32FromUint32(uint32(**(**Tu8)(__ccgo_up(p1 + 1))))
|
|
if **(**int32)(__ccgo_up(bp)) >= int32(0x80) {
|
|
_sqlite3GetVarint32(tls, p1+1, bp)
|
|
}
|
|
**(**int32)(__ccgo_up(bp + 4)) = libc.Int32FromUint32(uint32(**(**Tu8)(__ccgo_up(p2 + 1))))
|
|
if **(**int32)(__ccgo_up(bp + 4)) >= int32(0x80) {
|
|
_sqlite3GetVarint32(tls, p2+1, bp+4)
|
|
}
|
|
if **(**int32)(__ccgo_up(bp)) < **(**int32)(__ccgo_up(bp + 4)) {
|
|
v11 = **(**int32)(__ccgo_up(bp))
|
|
} else {
|
|
v11 = **(**int32)(__ccgo_up(bp + 4))
|
|
}
|
|
res = libc.Xmemcmp(tls, v1, v2, libc.Uint64FromInt32((v11-int32(13))/int32(2)))
|
|
if res == 0 {
|
|
res = **(**int32)(__ccgo_up(bp)) - **(**int32)(__ccgo_up(bp + 4))
|
|
}
|
|
if res == 0 {
|
|
if libc.Int32FromUint16((*TKeyInfo)(unsafe.Pointer((*TVdbeSorter)(unsafe.Pointer((*TSortSubtask)(unsafe.Pointer(pTask)).FpSorter)).FpKeyInfo)).FnKeyField) > int32(1) {
|
|
res = _vdbeSorterCompareTail(tls, pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2)
|
|
}
|
|
} else {
|
|
if **(**Tu8)(__ccgo_up((*TKeyInfo)(unsafe.Pointer((*TVdbeSorter)(unsafe.Pointer((*TSortSubtask)(unsafe.Pointer(pTask)).FpSorter)).FpKeyInfo)).FaSortFlags)) != 0 {
|
|
res = res * -int32(1)
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Flush the current contents of VdbeSorter.list to a new PMA, possibly
|
|
// ** using a background thread.
|
|
// */
|
|
func _vdbeSorterFlushPMA(tls *libc.TLS, pSorter uintptr) (r int32) {
|
|
var aMem, pCtx, pTask uintptr
|
|
var i, iTest, nWorker, rc int32
|
|
_, _, _, _, _, _, _ = aMem, i, iTest, nWorker, pCtx, pTask, rc
|
|
rc = SQLITE_OK
|
|
pTask = uintptr(0) /* Thread context used to create new PMA */
|
|
nWorker = libc.Int32FromUint8((*TVdbeSorter)(unsafe.Pointer(pSorter)).FnTask) - int32(1)
|
|
/* Set the flag to indicate that at least one PMA has been written.
|
|
** Or will be, anyhow. */
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).FbUsePMA = uint8(1)
|
|
/* Select a sub-task to sort and flush the current list of in-memory
|
|
** records to disk. If the sorter is running in multi-threaded mode,
|
|
** round-robin between the first (pSorter->nTask-1) tasks. Except, if
|
|
** the background thread from a sub-tasks previous turn is still running,
|
|
** skip it. If the first (pSorter->nTask-1) sub-tasks are all still busy,
|
|
** fall back to using the final sub-task. The first (pSorter->nTask-1)
|
|
** sub-tasks are preferred as they use background threads - the final
|
|
** sub-task uses the main thread. */
|
|
i = 0
|
|
for {
|
|
if !(i < nWorker) {
|
|
break
|
|
}
|
|
iTest = (libc.Int32FromUint8((*TVdbeSorter)(unsafe.Pointer(pSorter)).FiPrev) + i + int32(1)) % nWorker
|
|
pTask = pSorter + 96 + uintptr(iTest)*104
|
|
if (*TSortSubtask)(unsafe.Pointer(pTask)).FbDone != 0 {
|
|
rc = _vdbeSorterJoinThread(tls, pTask)
|
|
}
|
|
if rc != SQLITE_OK || (*TSortSubtask)(unsafe.Pointer(pTask)).FpThread == uintptr(0) {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if rc == SQLITE_OK {
|
|
if i == nWorker {
|
|
/* Use the foreground thread for this operation */
|
|
rc = _vdbeSorterListToPMA(tls, pSorter+96+uintptr(nWorker)*104, pSorter+56)
|
|
} else {
|
|
aMem = (*TSortSubtask)(unsafe.Pointer(pTask)).Flist.FaMemory
|
|
pCtx = pTask
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).FiPrev = libc.Uint8FromInt64((int64(pTask) - t__predefined_ptrdiff_t(pSorter+96)) / 104)
|
|
(*TSortSubtask)(unsafe.Pointer(pTask)).Flist = (*TVdbeSorter)(unsafe.Pointer(pSorter)).Flist
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).Flist.FpList = uintptr(0)
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).Flist.FszPMA = 0
|
|
if aMem != 0 {
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).Flist.FaMemory = aMem
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).FnMemory = _sqlite3MallocSize(tls, aMem)
|
|
} else {
|
|
if (*TVdbeSorter)(unsafe.Pointer(pSorter)).Flist.FaMemory != 0 {
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).Flist.FaMemory = _sqlite3Malloc(tls, libc.Uint64FromInt32((*TVdbeSorter)(unsafe.Pointer(pSorter)).FnMemory))
|
|
if !((*TVdbeSorter)(unsafe.Pointer(pSorter)).Flist.FaMemory != 0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
}
|
|
}
|
|
rc = _vdbeSorterCreateThread(tls, pTask, __ccgo_fp(_vdbeSorterFlushThread), pCtx)
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Join all outstanding threads launched by SorterWrite() to create
|
|
// ** level-0 PMAs.
|
|
// */
|
|
func _vdbeSorterJoinAll(tls *libc.TLS, pSorter uintptr, rcin int32) (r int32) {
|
|
var i, rc, rc2 int32
|
|
var pTask uintptr
|
|
_, _, _, _ = i, pTask, rc, rc2
|
|
rc = rcin
|
|
/* This function is always called by the main user thread.
|
|
**
|
|
** If this function is being called after SorterRewind() has been called,
|
|
** it is possible that thread pSorter->aTask[pSorter->nTask-1].pThread
|
|
** is currently attempt to join one of the other threads. To avoid a race
|
|
** condition where this thread also attempts to join the same object, join
|
|
** thread pSorter->aTask[pSorter->nTask-1].pThread first. */
|
|
i = libc.Int32FromUint8((*TVdbeSorter)(unsafe.Pointer(pSorter)).FnTask) - int32(1)
|
|
for {
|
|
if !(i >= 0) {
|
|
break
|
|
}
|
|
pTask = pSorter + 96 + uintptr(i)*104
|
|
rc2 = _vdbeSorterJoinThread(tls, pTask)
|
|
if rc == SQLITE_OK {
|
|
rc = rc2
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i - 1
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called as part of a SorterRewind() operation on a sorter
|
|
// ** that has already written two or more level-0 PMAs to one or more temp
|
|
// ** files. It builds a tree of MergeEngine/IncrMerger/PmaReader objects that
|
|
// ** can be used to incrementally merge all PMAs on disk.
|
|
// **
|
|
// ** If successful, SQLITE_OK is returned and *ppOut set to point to the
|
|
// ** MergeEngine object at the root of the tree before returning. Or, if an
|
|
// ** error occurs, an SQLite error code is returned and the final value
|
|
// ** of *ppOut is undefined.
|
|
// */
|
|
func _vdbeSorterMergeTreeBuild(tls *libc.TLS, pSorter uintptr, ppOut uintptr) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var i, iSeq, iTask, nDepth, nReader, rc, v3 int32
|
|
var pMain, pTask uintptr
|
|
var _ /* iReadOff at bp+8 */ Ti64
|
|
var _ /* pMerger at bp+16 */ uintptr
|
|
var _ /* pRoot at bp+0 */ uintptr
|
|
_, _, _, _, _, _, _, _, _ = i, iSeq, iTask, nDepth, nReader, pMain, pTask, rc, v3
|
|
pMain = uintptr(0)
|
|
rc = SQLITE_OK
|
|
/* If the sorter uses more than one task, then create the top-level
|
|
** MergeEngine here. This MergeEngine will read data from exactly
|
|
** one PmaReader per sub-task. */
|
|
if libc.Int32FromUint8((*TVdbeSorter)(unsafe.Pointer(pSorter)).FnTask) > int32(1) {
|
|
pMain = _vdbeMergeEngineNew(tls, libc.Int32FromUint8((*TVdbeSorter)(unsafe.Pointer(pSorter)).FnTask))
|
|
if pMain == uintptr(0) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
}
|
|
}
|
|
iTask = 0
|
|
for {
|
|
if !(rc == SQLITE_OK && iTask < libc.Int32FromUint8((*TVdbeSorter)(unsafe.Pointer(pSorter)).FnTask)) {
|
|
break
|
|
}
|
|
pTask = pSorter + 96 + uintptr(iTask)*104
|
|
if libc.Bool(false) || (*TSortSubtask)(unsafe.Pointer(pTask)).FnPMA != 0 {
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0) /* Root node of tree for this task */
|
|
nDepth = _vdbeSorterTreeDepth(tls, (*TSortSubtask)(unsafe.Pointer(pTask)).FnPMA)
|
|
**(**Ti64)(__ccgo_up(bp + 8)) = 0
|
|
if (*TSortSubtask)(unsafe.Pointer(pTask)).FnPMA <= int32(SORTER_MAX_MERGE_COUNT) {
|
|
rc = _vdbeMergeEngineLevel0(tls, pTask, (*TSortSubtask)(unsafe.Pointer(pTask)).FnPMA, bp+8, bp)
|
|
} else {
|
|
iSeq = 0
|
|
**(**uintptr)(__ccgo_up(bp)) = _vdbeMergeEngineNew(tls, int32(SORTER_MAX_MERGE_COUNT))
|
|
if **(**uintptr)(__ccgo_up(bp)) == uintptr(0) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < (*TSortSubtask)(unsafe.Pointer(pTask)).FnPMA && rc == SQLITE_OK) {
|
|
break
|
|
}
|
|
**(**uintptr)(__ccgo_up(bp + 16)) = uintptr(0) /* Number of level-0 PMAs to merge */
|
|
if (*TSortSubtask)(unsafe.Pointer(pTask)).FnPMA-i < int32(SORTER_MAX_MERGE_COUNT) {
|
|
v3 = (*TSortSubtask)(unsafe.Pointer(pTask)).FnPMA - i
|
|
} else {
|
|
v3 = int32(SORTER_MAX_MERGE_COUNT)
|
|
}
|
|
nReader = v3
|
|
rc = _vdbeMergeEngineLevel0(tls, pTask, nReader, bp+8, bp+16)
|
|
if rc == SQLITE_OK {
|
|
v3 = iSeq
|
|
iSeq = iSeq + 1
|
|
rc = _vdbeSorterAddToTree(tls, pTask, nDepth, v3, **(**uintptr)(__ccgo_up(bp)), **(**uintptr)(__ccgo_up(bp + 16)))
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + int32(SORTER_MAX_MERGE_COUNT)
|
|
}
|
|
}
|
|
if rc == SQLITE_OK {
|
|
if pMain != uintptr(0) {
|
|
rc = _vdbeIncrMergerNew(tls, pTask, **(**uintptr)(__ccgo_up(bp)), (*TMergeEngine)(unsafe.Pointer(pMain)).FaReadr+uintptr(iTask)*80+72)
|
|
} else {
|
|
pMain = **(**uintptr)(__ccgo_up(bp))
|
|
}
|
|
} else {
|
|
_vdbeMergeEngineFree(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
iTask = iTask + 1
|
|
}
|
|
if rc != SQLITE_OK {
|
|
_vdbeMergeEngineFree(tls, pMain)
|
|
pMain = uintptr(0)
|
|
}
|
|
**(**uintptr)(__ccgo_up(ppOut)) = pMain
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called as part of an sqlite3VdbeSorterRewind() operation
|
|
// ** on a sorter that has written two or more PMAs to temporary files. It sets
|
|
// ** up either VdbeSorter.pMerger (for single threaded sorters) or pReader
|
|
// ** (for multi-threaded sorters) so that it can be used to iterate through
|
|
// ** all records stored in the sorter.
|
|
// **
|
|
// ** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
|
|
// */
|
|
func _vdbeSorterSetupMerge(tls *libc.TLS, pSorter uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var db, p, pIncr, pLast, pReadr, pTask0, v3 uintptr
|
|
var i, iTask, rc int32
|
|
var xCompare TSorterCompare
|
|
var _ /* pMain at bp+0 */ uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _ = db, i, iTask, p, pIncr, pLast, pReadr, pTask0, rc, xCompare, v3 /* Return code */
|
|
pTask0 = pSorter + 96
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
db = (*TVdbeSorter)(unsafe.Pointer((*TSortSubtask)(unsafe.Pointer(pTask0)).FpSorter)).Fdb
|
|
xCompare = _vdbeSorterGetCompare(tls, pSorter)
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint8((*TVdbeSorter)(unsafe.Pointer(pSorter)).FnTask)) {
|
|
break
|
|
}
|
|
(*(*TSortSubtask)(unsafe.Pointer(pSorter + 96 + uintptr(i)*104))).FxCompare = xCompare
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
rc = _vdbeSorterMergeTreeBuild(tls, pSorter, bp)
|
|
if rc == SQLITE_OK {
|
|
if (*TVdbeSorter)(unsafe.Pointer(pSorter)).FbUseThreads != 0 {
|
|
pReadr = uintptr(0)
|
|
pLast = pSorter + 96 + uintptr(libc.Int32FromUint8((*TVdbeSorter)(unsafe.Pointer(pSorter)).FnTask)-int32(1))*104
|
|
rc = _vdbeSortAllocUnpacked(tls, pLast)
|
|
if rc == SQLITE_OK {
|
|
pReadr = _sqlite3DbMallocZero(tls, db, uint64(80))
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).FpReader = pReadr
|
|
if pReadr == uintptr(0) {
|
|
rc = int32(SQLITE_NOMEM)
|
|
}
|
|
}
|
|
if rc == SQLITE_OK {
|
|
rc = _vdbeIncrMergerNew(tls, pLast, **(**uintptr)(__ccgo_up(bp)), pReadr+72)
|
|
if rc == SQLITE_OK {
|
|
_vdbeIncrMergerSetThreads(tls, (*TPmaReader)(unsafe.Pointer(pReadr)).FpIncr)
|
|
iTask = 0
|
|
for {
|
|
if !(iTask < libc.Int32FromUint8((*TVdbeSorter)(unsafe.Pointer(pSorter)).FnTask)-int32(1)) {
|
|
break
|
|
}
|
|
v3 = (**(**TPmaReader)(__ccgo_up((*TMergeEngine)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FaReadr + uintptr(iTask)*80))).FpIncr
|
|
pIncr = v3
|
|
if v3 != 0 {
|
|
_vdbeIncrMergerSetThreads(tls, pIncr)
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
iTask = iTask + 1
|
|
}
|
|
iTask = 0
|
|
for {
|
|
if !(rc == SQLITE_OK && iTask < libc.Int32FromUint8((*TVdbeSorter)(unsafe.Pointer(pSorter)).FnTask)) {
|
|
break
|
|
}
|
|
/* Check that:
|
|
**
|
|
** a) The incremental merge object is configured to use the
|
|
** right task, and
|
|
** b) If it is using task (nTask-1), it is configured to run
|
|
** in single-threaded mode. This is important, as the
|
|
** root merge (INCRINIT_ROOT) will be using the same task
|
|
** object.
|
|
*/
|
|
p = (*TMergeEngine)(unsafe.Pointer(**(**uintptr)(__ccgo_up(bp)))).FaReadr + uintptr(iTask)*80
|
|
rc = _vdbePmaReaderIncrInit(tls, p, int32(INCRINIT_TASK))
|
|
goto _4
|
|
_4:
|
|
;
|
|
iTask = iTask + 1
|
|
}
|
|
}
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
}
|
|
if rc == SQLITE_OK {
|
|
rc = _vdbePmaReaderIncrMergeInit(tls, pReadr, int32(INCRINIT_ROOT))
|
|
}
|
|
} else {
|
|
rc = _vdbeMergeEngineInit(tls, pTask0, **(**uintptr)(__ccgo_up(bp)), INCRINIT_NORMAL)
|
|
(*TVdbeSorter)(unsafe.Pointer(pSorter)).FpMerger = **(**uintptr)(__ccgo_up(bp))
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0)
|
|
}
|
|
}
|
|
if rc != SQLITE_OK {
|
|
_vdbeMergeEngineFree(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Copy as much content as we can from the WAL back into the database file
|
|
// ** in response to an sqlite3_wal_checkpoint() request or the equivalent.
|
|
// **
|
|
// ** The amount of information copies from WAL to database might be limited
|
|
// ** by active readers. This routine will never overwrite a database page
|
|
// ** that a concurrent reader might be using.
|
|
// **
|
|
// ** All I/O barrier operations (a.k.a fsyncs) occur in this routine when
|
|
// ** SQLite is in WAL-mode in synchronous=NORMAL. That means that if
|
|
// ** checkpoints are always run by a background thread or background
|
|
// ** process, foreground threads will never block on a lengthy fsync call.
|
|
// **
|
|
// ** Fsync is called on the WAL before writing content out of the WAL and
|
|
// ** into the database. This ensures that if the new content is persistent
|
|
// ** in the WAL and can be recovered following a power-loss or hard reset.
|
|
// **
|
|
// ** Fsync is also called on the database file if (and only if) the entire
|
|
// ** WAL content is copied into the database file. This second fsync makes
|
|
// ** it safe to delete the WAL since the new content will persist in the
|
|
// ** database file.
|
|
// **
|
|
// ** This routine uses and updates the nBackfill field of the wal-index header.
|
|
// ** This is the only routine that will increase the value of nBackfill.
|
|
// ** (A WAL reset or recovery will revert nBackfill to zero, but not increase
|
|
// ** its value.)
|
|
// **
|
|
// ** The caller must be holding sufficient locks to ensure that no other
|
|
// ** checkpoint is running (in any other thread or process) at the same
|
|
// ** time.
|
|
// */
|
|
func _walCheckpoint(tls *libc.TLS, pWal uintptr, db uintptr, eMode int32, __ccgo_fp_xBusy uintptr, pBusyArg uintptr, sync_flags int32, zBuf uintptr) (r int32) {
|
|
bp := tls.Alloc(48)
|
|
defer tls.Free(48)
|
|
var bChg, i, rc, szPage, v3 int32
|
|
var iMark, mxPage, mxSafeFrame, nBackfill, y Tu32
|
|
var iOffset, szDb Ti64
|
|
var pInfo, pLive uintptr
|
|
var v2 uint32
|
|
var v4 bool
|
|
var _ /* iDbpage at bp+8 */ Tu32
|
|
var _ /* iFrame at bp+12 */ Tu32
|
|
var _ /* nReq at bp+16 */ Ti64
|
|
var _ /* nSize at bp+24 */ Ti64
|
|
var _ /* pIter at bp+0 */ uintptr
|
|
var _ /* salt1 at bp+32 */ Tu32
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = bChg, i, iMark, iOffset, mxPage, mxSafeFrame, nBackfill, pInfo, pLive, rc, szDb, szPage, y, v2, v3, v4
|
|
rc = SQLITE_OK /* Database page-size */
|
|
**(**uintptr)(__ccgo_up(bp)) = uintptr(0) /* Wal iterator context */
|
|
**(**Tu32)(__ccgo_up(bp + 8)) = uint32(0) /* Next database page to write */
|
|
**(**Tu32)(__ccgo_up(bp + 12)) = uint32(0) /* The checkpoint status information */
|
|
szPage = _walPagesize(tls, pWal)
|
|
pInfo = _walCkptInfo(tls, pWal)
|
|
if (*TWalCkptInfo)(unsafe.Pointer(pInfo)).FnBackfill < (*TWal)(unsafe.Pointer(pWal)).Fhdr.FmxFrame {
|
|
/* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
|
|
** in the SQLITE_CHECKPOINT_PASSIVE mode. */
|
|
/* Compute in mxSafeFrame the index of the last frame of the WAL that is
|
|
** safe to write into the database. Frames beyond mxSafeFrame might
|
|
** overwrite database pages that are in use by active readers and thus
|
|
** cannot be backfilled from the WAL.
|
|
*/
|
|
mxSafeFrame = (*TWal)(unsafe.Pointer(pWal)).Fhdr.FmxFrame
|
|
mxPage = (*TWal)(unsafe.Pointer(pWal)).Fhdr.FnPage
|
|
i = int32(1)
|
|
for {
|
|
if !(i < libc.Int32FromInt32(SQLITE_SHM_NLOCK)-libc.Int32FromInt32(3)) {
|
|
break
|
|
}
|
|
y = libc.AtomicLoadNUint32(pInfo+4+uintptr(i)*4, libc.Int32FromInt32(__ATOMIC_RELAXED))
|
|
if mxSafeFrame > y {
|
|
rc = _walBusyLock(tls, pWal, __ccgo_fp_xBusy, pBusyArg, int32(3)+i, int32(1))
|
|
if rc == SQLITE_OK {
|
|
if i == int32(1) {
|
|
v2 = mxSafeFrame
|
|
} else {
|
|
v2 = uint32(READMARK_NOT_USED)
|
|
}
|
|
iMark = v2
|
|
libc.AtomicStoreNUint32(pInfo+4+uintptr(i)*4, iMark, libc.Int32FromInt32(__ATOMIC_RELAXED))
|
|
_walUnlockExclusive(tls, pWal, int32(3)+i, int32(1))
|
|
} else {
|
|
if rc == int32(SQLITE_BUSY) {
|
|
mxSafeFrame = y
|
|
__ccgo_fp_xBusy = uintptr(0)
|
|
} else {
|
|
goto walcheckpoint_out
|
|
}
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
/* Allocate the iterator */
|
|
if (*TWalCkptInfo)(unsafe.Pointer(pInfo)).FnBackfill < mxSafeFrame {
|
|
rc = _walIteratorInit(tls, pWal, (*TWalCkptInfo)(unsafe.Pointer(pInfo)).FnBackfill, bp)
|
|
}
|
|
if v4 = **(**uintptr)(__ccgo_up(bp)) != 0; v4 {
|
|
v3 = _walBusyLock(tls, pWal, __ccgo_fp_xBusy, pBusyArg, libc.Int32FromInt32(3)+libc.Int32FromInt32(0), int32(1))
|
|
rc = v3
|
|
}
|
|
if v4 && v3 == SQLITE_OK {
|
|
nBackfill = (*TWalCkptInfo)(unsafe.Pointer(pInfo)).FnBackfill
|
|
pLive = _walIndexHdr(tls, pWal)
|
|
/* Now that read-lock slot 0 is locked, check that the wal has not been
|
|
** wrapped since the header was read for this checkpoint. If it was, then
|
|
** there was no work to do anyway. In this case the
|
|
** (pInfo->nBackfill<pWal->hdr.mxFrame) test above only passed because
|
|
** pInfo->nBackfill had already been set to 0 by the writer that wrapped
|
|
** the wal file. It would also be dangerous to proceed, as there may be
|
|
** fewer than pWal->hdr.mxFrame valid frames in the wal file. */
|
|
bChg = libc.Xmemcmp(tls, pLive+32, pWal+72+32, uint64(8))
|
|
if 0 == bChg {
|
|
(*TWalCkptInfo)(unsafe.Pointer(pInfo)).FnBackfillAttempted = mxSafeFrame
|
|
/* Sync the WAL to disk */
|
|
rc = _sqlite3OsSync(tls, (*TWal)(unsafe.Pointer(pWal)).FpWalFd, sync_flags>>int32(2)&int32(0x03))
|
|
/* If the database may grow as a result of this checkpoint, hint
|
|
** about the eventual size of the db file to the VFS layer.
|
|
*/
|
|
if rc == SQLITE_OK {
|
|
**(**Ti64)(__ccgo_up(bp + 16)) = libc.Int64FromUint32(mxPage) * int64(szPage) /* Current size of database file */
|
|
_sqlite3OsFileControl(tls, (*TWal)(unsafe.Pointer(pWal)).FpDbFd, int32(SQLITE_FCNTL_CKPT_START), uintptr(0))
|
|
rc = _sqlite3OsFileSize(tls, (*TWal)(unsafe.Pointer(pWal)).FpDbFd, bp+24)
|
|
if rc == SQLITE_OK && **(**Ti64)(__ccgo_up(bp + 24)) < **(**Ti64)(__ccgo_up(bp + 16)) {
|
|
if **(**Ti64)(__ccgo_up(bp + 24))+int64(65536)+libc.Int64FromUint32((*TWal)(unsafe.Pointer(pWal)).Fhdr.FmxFrame)*int64(szPage) < **(**Ti64)(__ccgo_up(bp + 16)) {
|
|
/* If the size of the final database is larger than the current
|
|
** database plus the amount of data in the wal file, plus the
|
|
** maximum size of the pending-byte page (65536 bytes), then
|
|
** must be corruption somewhere. */
|
|
rc = _sqlite3CorruptError(tls, int32(69812))
|
|
} else {
|
|
_sqlite3OsFileControlHint(tls, (*TWal)(unsafe.Pointer(pWal)).FpDbFd, int32(SQLITE_FCNTL_SIZE_HINT), bp+16)
|
|
}
|
|
}
|
|
}
|
|
/* Iterate through the contents of the WAL, copying data to the
|
|
** db file */
|
|
for rc == SQLITE_OK && 0 == _walIteratorNext(tls, **(**uintptr)(__ccgo_up(bp)), bp+8, bp+12) {
|
|
if libc.AtomicLoadNInt32(db+432, libc.Int32FromInt32(__ATOMIC_RELAXED)) != 0 {
|
|
if (*Tsqlite3)(unsafe.Pointer(db)).FmallocFailed != 0 {
|
|
v3 = int32(SQLITE_NOMEM)
|
|
} else {
|
|
v3 = int32(SQLITE_INTERRUPT)
|
|
}
|
|
rc = v3
|
|
break
|
|
}
|
|
if **(**Tu32)(__ccgo_up(bp + 12)) <= nBackfill || **(**Tu32)(__ccgo_up(bp + 12)) > mxSafeFrame || **(**Tu32)(__ccgo_up(bp + 8)) > mxPage {
|
|
continue
|
|
}
|
|
iOffset = int64(WAL_HDRSIZE) + libc.Int64FromUint32(**(**Tu32)(__ccgo_up(bp + 12))-libc.Uint32FromInt32(1))*int64(szPage+libc.Int32FromInt32(WAL_FRAME_HDRSIZE)) + int64(WAL_FRAME_HDRSIZE)
|
|
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
|
|
rc = _sqlite3OsRead(tls, (*TWal)(unsafe.Pointer(pWal)).FpWalFd, zBuf, szPage, iOffset)
|
|
if rc != SQLITE_OK {
|
|
break
|
|
}
|
|
iOffset = libc.Int64FromUint32(**(**Tu32)(__ccgo_up(bp + 8))-libc.Uint32FromInt32(1)) * int64(szPage)
|
|
rc = _sqlite3OsWrite(tls, (*TWal)(unsafe.Pointer(pWal)).FpDbFd, zBuf, szPage, iOffset)
|
|
if rc != SQLITE_OK {
|
|
break
|
|
}
|
|
}
|
|
_sqlite3OsFileControl(tls, (*TWal)(unsafe.Pointer(pWal)).FpDbFd, int32(SQLITE_FCNTL_CKPT_DONE), uintptr(0))
|
|
/* If work was actually accomplished... */
|
|
if rc == SQLITE_OK {
|
|
if mxSafeFrame == (*TWalIndexHdr)(unsafe.Pointer(_walIndexHdr(tls, pWal))).FmxFrame {
|
|
szDb = libc.Int64FromUint32((*TWal)(unsafe.Pointer(pWal)).Fhdr.FnPage) * int64(szPage)
|
|
rc = _sqlite3OsTruncate(tls, (*TWal)(unsafe.Pointer(pWal)).FpDbFd, szDb)
|
|
if rc == SQLITE_OK {
|
|
rc = _sqlite3OsSync(tls, (*TWal)(unsafe.Pointer(pWal)).FpDbFd, sync_flags>>int32(2)&int32(0x03))
|
|
}
|
|
}
|
|
if rc == SQLITE_OK {
|
|
libc.AtomicStoreNUint32(pInfo, mxSafeFrame, libc.Int32FromInt32(__ATOMIC_RELAXED))
|
|
}
|
|
}
|
|
}
|
|
/* Release the reader lock held while backfilling */
|
|
_walUnlockExclusive(tls, pWal, libc.Int32FromInt32(3)+libc.Int32FromInt32(0), int32(1))
|
|
}
|
|
if rc == int32(SQLITE_BUSY) {
|
|
/* Reset the return code so as not to report a checkpoint failure
|
|
** just because there are active readers. */
|
|
rc = SQLITE_OK
|
|
}
|
|
}
|
|
/* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the
|
|
** entire wal file has been copied into the database file, then block
|
|
** until all readers have finished using the wal file. This ensures that
|
|
** the next process to write to the database restarts the wal file.
|
|
*/
|
|
if rc == SQLITE_OK && eMode != SQLITE_CHECKPOINT_PASSIVE {
|
|
if (*TWalCkptInfo)(unsafe.Pointer(pInfo)).FnBackfill < (*TWal)(unsafe.Pointer(pWal)).Fhdr.FmxFrame {
|
|
rc = int32(SQLITE_BUSY)
|
|
} else {
|
|
if eMode >= int32(SQLITE_CHECKPOINT_RESTART) {
|
|
Xsqlite3_randomness(tls, int32(4), bp+32)
|
|
rc = _walBusyLock(tls, pWal, __ccgo_fp_xBusy, pBusyArg, libc.Int32FromInt32(3)+libc.Int32FromInt32(1), libc.Int32FromInt32(SQLITE_SHM_NLOCK)-libc.Int32FromInt32(3)-libc.Int32FromInt32(1))
|
|
if rc == SQLITE_OK {
|
|
if eMode == int32(SQLITE_CHECKPOINT_TRUNCATE) {
|
|
/* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as
|
|
** SQLITE_CHECKPOINT_RESTART with the addition that it also
|
|
** truncates the log file to zero bytes just prior to a
|
|
** successful return.
|
|
**
|
|
** In theory, it might be safe to do this without updating the
|
|
** wal-index header in shared memory, as all subsequent reader or
|
|
** writer clients should see that the entire log file has been
|
|
** checkpointed and behave accordingly. This seems unsafe though,
|
|
** as it would leave the system in a state where the contents of
|
|
** the wal-index header do not match the contents of the
|
|
** file-system. To avoid this, update the wal-index header to
|
|
** indicate that the log file contains zero valid frames. */
|
|
_walRestartHdr(tls, pWal, **(**Tu32)(__ccgo_up(bp + 32)))
|
|
rc = _sqlite3OsTruncate(tls, (*TWal)(unsafe.Pointer(pWal)).FpWalFd, 0)
|
|
}
|
|
_walUnlockExclusive(tls, pWal, libc.Int32FromInt32(3)+libc.Int32FromInt32(1), libc.Int32FromInt32(SQLITE_SHM_NLOCK)-libc.Int32FromInt32(3)-libc.Int32FromInt32(1))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
goto walcheckpoint_out
|
|
walcheckpoint_out:
|
|
;
|
|
_walIteratorFree(tls, **(**uintptr)(__ccgo_up(bp)))
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Search the wal file for page pgno. If found, set *piRead to the frame that
|
|
// ** contains the page. Otherwise, if pgno is not in the wal file, set *piRead
|
|
// ** to zero.
|
|
// **
|
|
// ** Return SQLITE_OK if successful, or an error code if an error occurs. If an
|
|
// ** error does occur, the final value of *piRead is undefined.
|
|
// */
|
|
func _walFindFrame(tls *libc.TLS, pWal uintptr, pgno TPgno, piRead uintptr) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var iFrame, iH, iLast, iRead, v2 Tu32
|
|
var iHash, iKey, iMinHash, nCollide, rc, v3 int32
|
|
var _ /* sLoc at bp+0 */ TWalHashLoc
|
|
_, _, _, _, _, _, _, _, _, _, _ = iFrame, iH, iHash, iKey, iLast, iMinHash, iRead, nCollide, rc, v2, v3
|
|
iRead = uint32(0) /* If !=0, WAL frame to return data from */
|
|
iLast = (*TWal)(unsafe.Pointer(pWal)).Fhdr.FmxFrame
|
|
/* This routine is only be called from within a read transaction. */
|
|
/* If the "last page" field of the wal-index header snapshot is 0, then
|
|
** no data will be read from the wal under any circumstances. Return early
|
|
** in this case as an optimization. Likewise, if pWal->readLock==0,
|
|
** then the WAL is ignored by the reader so return early, as if the
|
|
** WAL were empty.
|
|
*/
|
|
if iLast == uint32(0) || int32((*TWal)(unsafe.Pointer(pWal)).FreadLock) == 0 && libc.Int32FromUint8((*TWal)(unsafe.Pointer(pWal)).FbShmUnreliable) == 0 {
|
|
**(**Tu32)(__ccgo_up(piRead)) = uint32(0)
|
|
return SQLITE_OK
|
|
}
|
|
/* Search the hash table or tables for an entry matching page number
|
|
** pgno. Each iteration of the following for() loop searches one
|
|
** hash table (each hash table indexes up to HASHTABLE_NPAGE frames).
|
|
**
|
|
** This code might run concurrently to the code in walIndexAppend()
|
|
** that adds entries to the wal-index (and possibly to this hash
|
|
** table). This means the value just read from the hash
|
|
** slot (aHash[iKey]) may have been added before or after the
|
|
** current read transaction was opened. Values added after the
|
|
** read transaction was opened may have been written incorrectly -
|
|
** i.e. these slots may contain garbage data. However, we assume
|
|
** that any slots written before the current read transaction was
|
|
** opened remain unmodified.
|
|
**
|
|
** For the reasons above, the if(...) condition featured in the inner
|
|
** loop of the following block is more stringent that would be required
|
|
** if we had exclusive access to the hash-table:
|
|
**
|
|
** (aPgno[iFrame]==pgno):
|
|
** This condition filters out normal hash-table collisions.
|
|
**
|
|
** (iFrame<=iLast):
|
|
** This condition filters out entries that were added to the hash
|
|
** table after the current read-transaction had started.
|
|
*/
|
|
iMinHash = _walFramePage(tls, (*TWal)(unsafe.Pointer(pWal)).FminFrame)
|
|
iHash = _walFramePage(tls, iLast)
|
|
for {
|
|
if !(iHash >= iMinHash) {
|
|
break
|
|
}
|
|
rc = _walHashGet(tls, pWal, iHash, bp)
|
|
if rc != SQLITE_OK {
|
|
return rc
|
|
}
|
|
nCollide = libc.Int32FromInt32(HASHTABLE_NPAGE) * libc.Int32FromInt32(2)
|
|
iKey = _walHash(tls, pgno)
|
|
for {
|
|
v2 = uint32(libc.AtomicLoadNUint16((**(**TWalHashLoc)(__ccgo_up(bp))).FaHash+uintptr(iKey)*2, libc.Int32FromInt32(__ATOMIC_RELAXED)))
|
|
iH = v2
|
|
if !(v2 != uint32(0)) {
|
|
break
|
|
}
|
|
iFrame = iH + (**(**TWalHashLoc)(__ccgo_up(bp))).FiZero
|
|
if iFrame <= iLast && iFrame >= (*TWal)(unsafe.Pointer(pWal)).FminFrame && **(**Tu32)(__ccgo_up((**(**TWalHashLoc)(__ccgo_up(bp))).FaPgno + uintptr((iH-uint32(1))&libc.Uint32FromInt32(libc.Int32FromInt32(HASHTABLE_NPAGE)-libc.Int32FromInt32(1)))*4)) == pgno {
|
|
iRead = iFrame
|
|
}
|
|
v3 = nCollide
|
|
nCollide = nCollide - 1
|
|
if v3 == 0 {
|
|
**(**Tu32)(__ccgo_up(piRead)) = uint32(0)
|
|
return _sqlite3CorruptError(tls, int32(71119))
|
|
}
|
|
iKey = _walNextHash(tls, iKey)
|
|
}
|
|
if iRead != 0 {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
iHash = iHash - 1
|
|
}
|
|
**(**Tu32)(__ccgo_up(piRead)) = iRead
|
|
return SQLITE_OK
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the number of the wal-index page that contains the hash-table
|
|
// ** and page-number array that contain entries corresponding to WAL frame
|
|
// ** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages
|
|
// ** are numbered starting from 0.
|
|
// */
|
|
func _walFramePage(tls *libc.TLS, iFrame Tu32) (r int32) {
|
|
var iHash int32
|
|
_ = iHash
|
|
iHash = libc.Int32FromUint64((uint64(iFrame+uint32(HASHTABLE_NPAGE)) - (libc.Uint64FromInt32(HASHTABLE_NPAGE) - (libc.Uint64FromInt64(48)*libc.Uint64FromInt32(2)+libc.Uint64FromInt64(40))/libc.Uint64FromInt64(4)) - uint64(1)) / uint64(HASHTABLE_NPAGE))
|
|
return iHash
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return pointers to the hash table and page number array stored on
|
|
// ** page iHash of the wal-index. The wal-index is broken into 32KB pages
|
|
// ** numbered starting from 0.
|
|
// **
|
|
// ** Set output variable pLoc->aHash to point to the start of the hash table
|
|
// ** in the wal-index file. Set pLoc->iZero to one less than the frame
|
|
// ** number of the first frame indexed by this hash table. If a
|
|
// ** slot in the hash table is set to N, it refers to frame number
|
|
// ** (pLoc->iZero+N) in the log.
|
|
// **
|
|
// ** Finally, set pLoc->aPgno so that pLoc->aPgno[0] is the page number of the
|
|
// ** first frame indexed by the hash table, frame (pLoc->iZero).
|
|
// */
|
|
func _walHashGet(tls *libc.TLS, pWal uintptr, iHash int32, pLoc uintptr) (r int32) {
|
|
var rc int32
|
|
_ = rc /* Return code */
|
|
rc = _walIndexPage(tls, pWal, iHash, pLoc+8)
|
|
if (*TWalHashLoc)(unsafe.Pointer(pLoc)).FaPgno != 0 {
|
|
(*TWalHashLoc)(unsafe.Pointer(pLoc)).FaHash = (*TWalHashLoc)(unsafe.Pointer(pLoc)).FaPgno + 4096*4
|
|
if iHash == 0 {
|
|
(*TWalHashLoc)(unsafe.Pointer(pLoc)).FaPgno = (*TWalHashLoc)(unsafe.Pointer(pLoc)).FaPgno + uintptr((libc.Uint64FromInt64(48)*libc.Uint64FromInt32(2)+libc.Uint64FromInt64(40))/libc.Uint64FromInt64(4))*4
|
|
(*TWalHashLoc)(unsafe.Pointer(pLoc)).FiZero = uint32(0)
|
|
} else {
|
|
(*TWalHashLoc)(unsafe.Pointer(pLoc)).FiZero = uint32(libc.Uint64FromInt32(HASHTABLE_NPAGE) - (libc.Uint64FromInt64(48)*libc.Uint64FromInt32(2)+libc.Uint64FromInt64(40))/libc.Uint64FromInt64(4) + libc.Uint64FromInt32((iHash-int32(1))*int32(HASHTABLE_NPAGE)))
|
|
}
|
|
} else {
|
|
if rc == SQLITE_OK {
|
|
rc = int32(SQLITE_ERROR)
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Close an open wal-index.
|
|
// */
|
|
func _walIndexClose(tls *libc.TLS, pWal uintptr, isDelete int32) {
|
|
var i int32
|
|
_ = i
|
|
if libc.Int32FromUint8((*TWal)(unsafe.Pointer(pWal)).FexclusiveMode) == int32(WAL_HEAPMEMORY_MODE) || (*TWal)(unsafe.Pointer(pWal)).FbShmUnreliable != 0 {
|
|
i = 0
|
|
for {
|
|
if !(i < (*TWal)(unsafe.Pointer(pWal)).FnWiData) {
|
|
break
|
|
}
|
|
Xsqlite3_free(tls, **(**uintptr)(__ccgo_up((*TWal)(unsafe.Pointer(pWal)).FapWiData + uintptr(i)*8)))
|
|
**(**uintptr)(__ccgo_up((*TWal)(unsafe.Pointer(pWal)).FapWiData + uintptr(i)*8)) = uintptr(0)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
if libc.Int32FromUint8((*TWal)(unsafe.Pointer(pWal)).FexclusiveMode) != int32(WAL_HEAPMEMORY_MODE) {
|
|
_sqlite3OsShmUnmap(tls, (*TWal)(unsafe.Pointer(pWal)).FpDbFd, isDelete)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Find the smallest page number out of all pages held in the WAL that
|
|
// ** has not been returned by any prior invocation of this method on the
|
|
// ** same WalIterator object. Write into *piFrame the frame index where
|
|
// ** that page was last written into the WAL. Write into *piPage the page
|
|
// ** number.
|
|
// **
|
|
// ** Return 0 on success. If there are no pages in the WAL with a page
|
|
// ** number larger than *piPage, then return 1.
|
|
// */
|
|
func _walIteratorNext(tls *libc.TLS, p uintptr, piPage uintptr, piFrame uintptr) (r int32) {
|
|
var i int32
|
|
var iMin, iPg, iRet, v2 Tu32
|
|
var pSegment uintptr
|
|
_, _, _, _, _, _ = i, iMin, iPg, iRet, pSegment, v2 /* Result pgno must be greater than iMin */
|
|
iRet = uint32(0xFFFFFFFF) /* For looping through segments */
|
|
iMin = (*TWalIterator)(unsafe.Pointer(p)).FiPrior
|
|
i = (*TWalIterator)(unsafe.Pointer(p)).FnSegment - int32(1)
|
|
for {
|
|
if !(i >= 0) {
|
|
break
|
|
}
|
|
pSegment = p + 8 + uintptr(i)*32
|
|
for (*TWalSegment)(unsafe.Pointer(pSegment)).FiNext < (*TWalSegment)(unsafe.Pointer(pSegment)).FnEntry {
|
|
iPg = **(**Tu32)(__ccgo_up((*TWalSegment)(unsafe.Pointer(pSegment)).FaPgno + uintptr(**(**Tht_slot)(__ccgo_up((*TWalSegment)(unsafe.Pointer(pSegment)).FaIndex + uintptr((*TWalSegment)(unsafe.Pointer(pSegment)).FiNext)*2)))*4))
|
|
if iPg > iMin {
|
|
if iPg < iRet {
|
|
iRet = iPg
|
|
**(**Tu32)(__ccgo_up(piFrame)) = libc.Uint32FromInt32((*TWalSegment)(unsafe.Pointer(pSegment)).FiZero + libc.Int32FromUint16(**(**Tht_slot)(__ccgo_up((*TWalSegment)(unsafe.Pointer(pSegment)).FaIndex + uintptr((*TWalSegment)(unsafe.Pointer(pSegment)).FiNext)*2))))
|
|
}
|
|
break
|
|
}
|
|
(*TWalSegment)(unsafe.Pointer(pSegment)).FiNext = (*TWalSegment)(unsafe.Pointer(pSegment)).FiNext + 1
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i - 1
|
|
}
|
|
v2 = iRet
|
|
(*TWalIterator)(unsafe.Pointer(p)).FiPrior = v2
|
|
**(**Tu32)(__ccgo_up(piPage)) = v2
|
|
return libc.BoolInt32(iRet == uint32(0xFFFFFFFF))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function is called as part of committing a transaction within which
|
|
// ** one or more frames have been overwritten. It updates the checksums for
|
|
// ** all frames written to the wal file by the current transaction starting
|
|
// ** with the earliest to have been overwritten.
|
|
// **
|
|
// ** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
|
|
// */
|
|
func _walRewriteChecksums(tls *libc.TLS, pWal uintptr, iLast Tu32) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var aBuf uintptr
|
|
var iCksumOff, iOff Ti64
|
|
var iPgno, iRead, nDbSize Tu32
|
|
var rc, szPage int32
|
|
var _ /* aFrame at bp+0 */ [24]Tu8
|
|
_, _, _, _, _, _, _, _ = aBuf, iCksumOff, iOff, iPgno, iRead, nDbSize, rc, szPage
|
|
szPage = libc.Int32FromUint32((*TWal)(unsafe.Pointer(pWal)).FszPage) /* Database page size */
|
|
rc = SQLITE_OK
|
|
aBuf = Xsqlite3_malloc(tls, szPage+int32(WAL_FRAME_HDRSIZE))
|
|
if aBuf == uintptr(0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
/* Find the checksum values to use as input for the recalculating the
|
|
** first checksum. If the first frame is frame 1 (implying that the current
|
|
** transaction restarted the wal file), these values must be read from the
|
|
** wal-file header. Otherwise, read them from the frame header of the
|
|
** previous frame. */
|
|
if (*TWal)(unsafe.Pointer(pWal)).FiReCksum == uint32(1) {
|
|
iCksumOff = int64(24)
|
|
} else {
|
|
iCksumOff = int64(WAL_HDRSIZE) + libc.Int64FromUint32((*TWal)(unsafe.Pointer(pWal)).FiReCksum-libc.Uint32FromInt32(1)-libc.Uint32FromInt32(1))*int64(szPage+libc.Int32FromInt32(WAL_FRAME_HDRSIZE)) + int64(16)
|
|
}
|
|
rc = _sqlite3OsRead(tls, (*TWal)(unsafe.Pointer(pWal)).FpWalFd, aBuf, libc.Int32FromUint64(libc.Uint64FromInt64(4)*libc.Uint64FromInt32(2)), iCksumOff)
|
|
**(**Tu32)(__ccgo_up(pWal + 72 + 24)) = _sqlite3Get4byte(tls, aBuf)
|
|
**(**Tu32)(__ccgo_up(pWal + 72 + 24 + 1*4)) = _sqlite3Get4byte(tls, aBuf+uintptr(4))
|
|
iRead = (*TWal)(unsafe.Pointer(pWal)).FiReCksum
|
|
(*TWal)(unsafe.Pointer(pWal)).FiReCksum = uint32(0)
|
|
for {
|
|
if !(rc == SQLITE_OK && iRead <= iLast) {
|
|
break
|
|
}
|
|
iOff = libc.Int64FromInt32(WAL_HDRSIZE) + libc.Int64FromUint32(iRead-libc.Uint32FromInt32(1))*int64(szPage+libc.Int32FromInt32(WAL_FRAME_HDRSIZE))
|
|
rc = _sqlite3OsRead(tls, (*TWal)(unsafe.Pointer(pWal)).FpWalFd, aBuf, szPage+int32(WAL_FRAME_HDRSIZE), iOff)
|
|
if rc == SQLITE_OK {
|
|
iPgno = _sqlite3Get4byte(tls, aBuf)
|
|
nDbSize = _sqlite3Get4byte(tls, aBuf+4)
|
|
_walEncodeFrame(tls, pWal, iPgno, nDbSize, aBuf+24, bp)
|
|
rc = _sqlite3OsWrite(tls, (*TWal)(unsafe.Pointer(pWal)).FpWalFd, bp, int32(24), iOff)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
iRead = iRead + 1
|
|
}
|
|
Xsqlite3_free(tls, aBuf)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This function does the work of sqlite3WalSnapshotRecover().
|
|
// */
|
|
func _walSnapshotRecover(tls *libc.TLS, pWal uintptr, pBuf1 uintptr, pBuf2 uintptr) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var i, pgno Tu32
|
|
var iDbOff, iWalOff Ti64
|
|
var pInfo uintptr
|
|
var rc, szPage int32
|
|
var _ /* sLoc at bp+8 */ TWalHashLoc
|
|
var _ /* szDb at bp+0 */ Ti64
|
|
_, _, _, _, _, _, _ = i, iDbOff, iWalOff, pInfo, pgno, rc, szPage
|
|
szPage = libc.Int32FromUint32((*TWal)(unsafe.Pointer(pWal)).FszPage) /* Size of db file in bytes */
|
|
rc = _sqlite3OsFileSize(tls, (*TWal)(unsafe.Pointer(pWal)).FpDbFd, bp)
|
|
if rc == SQLITE_OK {
|
|
pInfo = _walCkptInfo(tls, pWal)
|
|
i = (*TWalCkptInfo)(unsafe.Pointer(pInfo)).FnBackfillAttempted
|
|
i = (*TWalCkptInfo)(unsafe.Pointer(pInfo)).FnBackfillAttempted
|
|
for {
|
|
if !(i > libc.AtomicLoadNUint32(pInfo, libc.Int32FromInt32(__ATOMIC_RELAXED))) {
|
|
break
|
|
} /* Offset of wal file entry */
|
|
rc = _walHashGet(tls, pWal, _walFramePage(tls, i), bp+8)
|
|
if rc != SQLITE_OK {
|
|
break
|
|
}
|
|
pgno = **(**Tu32)(__ccgo_up((**(**TWalHashLoc)(__ccgo_up(bp + 8))).FaPgno + uintptr(i-(**(**TWalHashLoc)(__ccgo_up(bp + 8))).FiZero-uint32(1))*4))
|
|
iDbOff = libc.Int64FromUint32(pgno-libc.Uint32FromInt32(1)) * int64(szPage)
|
|
if iDbOff+int64(szPage) <= **(**Ti64)(__ccgo_up(bp)) {
|
|
iWalOff = int64(WAL_HDRSIZE) + libc.Int64FromUint32(i-libc.Uint32FromInt32(1))*int64(szPage+libc.Int32FromInt32(WAL_FRAME_HDRSIZE)) + int64(WAL_FRAME_HDRSIZE)
|
|
rc = _sqlite3OsRead(tls, (*TWal)(unsafe.Pointer(pWal)).FpWalFd, pBuf1, szPage, iWalOff)
|
|
if rc == SQLITE_OK {
|
|
rc = _sqlite3OsRead(tls, (*TWal)(unsafe.Pointer(pWal)).FpDbFd, pBuf2, szPage, iDbOff)
|
|
}
|
|
if rc != SQLITE_OK || 0 == libc.Xmemcmp(tls, pBuf1, pBuf2, libc.Uint64FromInt32(szPage)) {
|
|
break
|
|
}
|
|
}
|
|
(*TWalCkptInfo)(unsafe.Pointer(pInfo)).FnBackfillAttempted = i - uint32(1)
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i - 1
|
|
}
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Attempt to start a read transaction. This might fail due to a race or
|
|
// ** other transient condition. When that happens, it returns WAL_RETRY to
|
|
// ** indicate to the caller that it is safe to retry immediately.
|
|
// **
|
|
// ** On success return SQLITE_OK. On a permanent failure (such an
|
|
// ** I/O error or an SQLITE_BUSY because another process is running
|
|
// ** recovery) return a positive error code.
|
|
// **
|
|
// ** The useWal parameter is true to force the use of the WAL and disable
|
|
// ** the case where the WAL is bypassed because it has been completely
|
|
// ** checkpointed. If useWal==0 then this routine calls walIndexReadHdr()
|
|
// ** to make a copy of the wal-index header into pWal->hdr. If the
|
|
// ** wal-index header has changed, *pChanged is set to 1 (as an indication
|
|
// ** to the caller that the local page cache is obsolete and needs to be
|
|
// ** flushed.) When useWal==1, the wal-index header is assumed to already
|
|
// ** be loaded and the pChanged parameter is unused.
|
|
// **
|
|
// ** The caller must set the cnt parameter to the number of prior calls to
|
|
// ** this routine during the current read attempt that returned WAL_RETRY.
|
|
// ** This routine will start taking more aggressive measures to clear the
|
|
// ** race conditions after multiple WAL_RETRY returns, and after an excessive
|
|
// ** number of errors will ultimately return SQLITE_PROTOCOL. The
|
|
// ** SQLITE_PROTOCOL return indicates that some other process has gone rogue
|
|
// ** and is not honoring the locking protocol. There is a vanishingly small
|
|
// ** chance that SQLITE_PROTOCOL could be returned because of a run of really
|
|
// ** bad luck when there is lots of contention for the wal-index, but that
|
|
// ** possibility is so small that it can be safely neglected, we believe.
|
|
// **
|
|
// ** On success, this routine obtains a read lock on
|
|
// ** WAL_READ_LOCK(pWal->readLock). The pWal->readLock integer is
|
|
// ** in the range 0 <= pWal->readLock < WAL_NREADER. If pWal->readLock==(-1)
|
|
// ** that means the Wal does not hold any read lock. The reader must not
|
|
// ** access any database page that is modified by a WAL frame up to and
|
|
// ** including frame number aReadMark[pWal->readLock]. The reader will
|
|
// ** use WAL frames up to and including pWal->hdr.mxFrame if pWal->readLock>0
|
|
// ** Or if pWal->readLock==0, then the reader will ignore the WAL
|
|
// ** completely and get all content directly from the database file.
|
|
// ** If the useWal parameter is 1 then the WAL will never be ignored and
|
|
// ** this routine will always set pWal->readLock>0 on success.
|
|
// ** When the read transaction is completed, the caller must release the
|
|
// ** lock on WAL_READ_LOCK(pWal->readLock) and set pWal->readLock to -1.
|
|
// **
|
|
// ** This routine uses the nBackfill and aReadMark[] fields of the header
|
|
// ** to select a particular WAL_READ_LOCK() that strives to let the
|
|
// ** checkpoint process do as much work as possible. This routine might
|
|
// ** update values of the aReadMark[] array in the header, but if it does
|
|
// ** so it takes care to hold an exclusive lock on the corresponding
|
|
// ** WAL_READ_LOCK() while changing values.
|
|
// */
|
|
func _walTryBeginRead(tls *libc.TLS, pWal uintptr, pChanged uintptr, useWal int32, pCnt uintptr) (r int32) {
|
|
var cnt, i, mxI, nDelay, rc, v1 int32
|
|
var mxFrame, mxReadMark, thisMark Tu32
|
|
var pInfo uintptr
|
|
_, _, _, _, _, _, _, _, _, _ = cnt, i, mxFrame, mxI, mxReadMark, nDelay, pInfo, rc, thisMark, v1 /* Checkpoint information in wal-index */
|
|
rc = SQLITE_OK /* Return code */
|
|
/* Not currently locked */
|
|
/* useWal may only be set for read/write connections */
|
|
/* Take steps to avoid spinning forever if there is a protocol error.
|
|
**
|
|
** Circumstances that cause a RETRY should only last for the briefest
|
|
** instances of time. No I/O or other system calls are done while the
|
|
** locks are held, so the locks should not be held for very long. But
|
|
** if we are unlucky, another process that is holding a lock might get
|
|
** paged out or take a page-fault that is time-consuming to resolve,
|
|
** during the few nanoseconds that it is holding the lock. In that case,
|
|
** it might take longer than normal for the lock to free.
|
|
**
|
|
** After 5 RETRYs, we begin calling sqlite3OsSleep(). The first few
|
|
** calls to sqlite3OsSleep() have a delay of 1 microsecond. Really this
|
|
** is more of a scheduler yield than an actual delay. But on the 10th
|
|
** an subsequent retries, the delays start becoming longer and longer,
|
|
** so that on the 100th (and last) RETRY we delay for 323 milliseconds.
|
|
** The total delay time before giving up is less than 10 seconds.
|
|
*/
|
|
**(**int32)(__ccgo_up(pCnt)) = **(**int32)(__ccgo_up(pCnt)) + 1
|
|
if **(**int32)(__ccgo_up(pCnt)) > int32(5) {
|
|
nDelay = int32(1) /* Pause time in microseconds */
|
|
cnt = **(**int32)(__ccgo_up(pCnt)) & ^libc.Int32FromInt32(WAL_RETRY_BLOCKED_MASK)
|
|
if cnt > int32(WAL_RETRY_PROTOCOL_LIMIT) {
|
|
return int32(SQLITE_PROTOCOL)
|
|
}
|
|
if **(**int32)(__ccgo_up(pCnt)) >= int32(10) {
|
|
nDelay = (cnt - int32(9)) * (cnt - int32(9)) * int32(39)
|
|
}
|
|
_sqlite3OsSleep(tls, (*TWal)(unsafe.Pointer(pWal)).FpVfs, nDelay)
|
|
**(**int32)(__ccgo_up(pCnt)) &= ^libc.Int32FromInt32(WAL_RETRY_BLOCKED_MASK)
|
|
}
|
|
if !(useWal != 0) {
|
|
if libc.Int32FromUint8((*TWal)(unsafe.Pointer(pWal)).FbShmUnreliable) == 0 {
|
|
rc = _walIndexReadHdr(tls, pWal, pChanged)
|
|
}
|
|
if rc == int32(SQLITE_BUSY) {
|
|
/* If there is not a recovery running in another thread or process
|
|
** then convert BUSY errors to WAL_RETRY. If recovery is known to
|
|
** be running, convert BUSY to BUSY_RECOVERY. There is a race here
|
|
** which might cause WAL_RETRY to be returned even if BUSY_RECOVERY
|
|
** would be technically correct. But the race is benign since with
|
|
** WAL_RETRY this routine will be called again and will probably be
|
|
** right on the second iteration.
|
|
*/
|
|
if **(**uintptr)(__ccgo_up((*TWal)(unsafe.Pointer(pWal)).FapWiData)) == uintptr(0) {
|
|
/* This branch is taken when the xShmMap() method returns SQLITE_BUSY.
|
|
** We assume this is a transient condition, so return WAL_RETRY. The
|
|
** xShmMap() implementation used by the default unix and win32 VFS
|
|
** modules may return SQLITE_BUSY due to a race condition in the
|
|
** code that determines whether or not the shared-memory region
|
|
** must be zeroed before the requested page is returned.
|
|
*/
|
|
rc = -int32(1)
|
|
} else {
|
|
v1 = _walLockShared(tls, pWal, int32(WAL_RECOVER_LOCK))
|
|
rc = v1
|
|
if SQLITE_OK == v1 {
|
|
_walUnlockShared(tls, pWal, int32(WAL_RECOVER_LOCK))
|
|
rc = -int32(1)
|
|
} else {
|
|
if rc == int32(SQLITE_BUSY) {
|
|
rc = libc.Int32FromInt32(SQLITE_BUSY) | libc.Int32FromInt32(1)<<libc.Int32FromInt32(8)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if rc != SQLITE_OK {
|
|
return rc
|
|
} else {
|
|
if (*TWal)(unsafe.Pointer(pWal)).FbShmUnreliable != 0 {
|
|
return _walBeginShmUnreliable(tls, pWal, pChanged)
|
|
}
|
|
}
|
|
}
|
|
pInfo = _walCkptInfo(tls, pWal)
|
|
/* Wal frame to lock to */
|
|
if !(useWal != 0) && libc.AtomicLoadNUint32(pInfo, libc.Int32FromInt32(__ATOMIC_RELAXED)) == (*TWal)(unsafe.Pointer(pWal)).Fhdr.FmxFrame && ((*TWal)(unsafe.Pointer(pWal)).FbGetSnapshot == 0 && (*TWal)(unsafe.Pointer(pWal)).FpSnapshot == uintptr(0) || (*TWal)(unsafe.Pointer(pWal)).Fhdr.FmxFrame == uint32(0)) {
|
|
/* The WAL has been completely backfilled (or it is empty).
|
|
** and can be safely ignored.
|
|
*/
|
|
rc = _walLockShared(tls, pWal, libc.Int32FromInt32(3)+libc.Int32FromInt32(0))
|
|
_walShmBarrier(tls, pWal)
|
|
if rc == SQLITE_OK {
|
|
if libc.Xmemcmp(tls, _walIndexHdr(tls, pWal), pWal+72, uint64(48)) != 0 {
|
|
/* It is not safe to allow the reader to continue here if frames
|
|
** may have been appended to the log before READ_LOCK(0) was obtained.
|
|
** When holding READ_LOCK(0), the reader ignores the entire log file,
|
|
** which implies that the database file contains a trustworthy
|
|
** snapshot. Since holding READ_LOCK(0) prevents a checkpoint from
|
|
** happening, this is usually correct.
|
|
**
|
|
** However, if frames have been appended to the log (or if the log
|
|
** is wrapped and written for that matter) before the READ_LOCK(0)
|
|
** is obtained, that is not necessarily true. A checkpointer may
|
|
** have started to backfill the appended frames but crashed before
|
|
** it finished. Leaving a corrupt image in the database file.
|
|
*/
|
|
_walUnlockShared(tls, pWal, libc.Int32FromInt32(3)+libc.Int32FromInt32(0))
|
|
return -int32(1)
|
|
}
|
|
(*TWal)(unsafe.Pointer(pWal)).FreadLock = 0
|
|
return SQLITE_OK
|
|
} else {
|
|
if rc != int32(SQLITE_BUSY) {
|
|
return rc
|
|
}
|
|
}
|
|
}
|
|
/* If we get this far, it means that the reader will want to use
|
|
** the WAL to get at content from recent commits. The job now is
|
|
** to select one of the aReadMark[] entries that is closest to
|
|
** but not exceeding pWal->hdr.mxFrame and lock that entry.
|
|
*/
|
|
mxReadMark = uint32(0)
|
|
mxI = 0
|
|
mxFrame = (*TWal)(unsafe.Pointer(pWal)).Fhdr.FmxFrame
|
|
if (*TWal)(unsafe.Pointer(pWal)).FpSnapshot != 0 && (*TWalIndexHdr)(unsafe.Pointer((*TWal)(unsafe.Pointer(pWal)).FpSnapshot)).FmxFrame < mxFrame {
|
|
mxFrame = (*TWalIndexHdr)(unsafe.Pointer((*TWal)(unsafe.Pointer(pWal)).FpSnapshot)).FmxFrame
|
|
}
|
|
i = int32(1)
|
|
for {
|
|
if !(i < libc.Int32FromInt32(SQLITE_SHM_NLOCK)-libc.Int32FromInt32(3)) {
|
|
break
|
|
}
|
|
thisMark = libc.AtomicLoadNUint32(pInfo+4+uintptr(i)*4, libc.Int32FromInt32(__ATOMIC_RELAXED))
|
|
if mxReadMark <= thisMark && thisMark <= mxFrame {
|
|
mxReadMark = thisMark
|
|
mxI = i
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if libc.Int32FromUint8((*TWal)(unsafe.Pointer(pWal)).FreadOnly)&int32(WAL_SHM_RDONLY) == 0 && (mxReadMark < mxFrame || mxI == 0) {
|
|
i = int32(1)
|
|
for {
|
|
if !(i < libc.Int32FromInt32(SQLITE_SHM_NLOCK)-libc.Int32FromInt32(3)) {
|
|
break
|
|
}
|
|
rc = _walLockExclusive(tls, pWal, int32(3)+i, int32(1))
|
|
if rc == SQLITE_OK {
|
|
libc.AtomicStoreNUint32(pInfo+4+uintptr(i)*4, mxFrame, libc.Int32FromInt32(__ATOMIC_RELAXED))
|
|
mxReadMark = mxFrame
|
|
mxI = i
|
|
_walUnlockExclusive(tls, pWal, int32(3)+i, int32(1))
|
|
break
|
|
} else {
|
|
if rc != int32(SQLITE_BUSY) {
|
|
return rc
|
|
}
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
if mxI == 0 {
|
|
if rc == int32(SQLITE_BUSY) {
|
|
v1 = -int32(1)
|
|
} else {
|
|
v1 = libc.Int32FromInt32(SQLITE_READONLY) | libc.Int32FromInt32(5)<<libc.Int32FromInt32(8)
|
|
}
|
|
return v1
|
|
}
|
|
rc = _walLockShared(tls, pWal, int32(3)+mxI)
|
|
if rc != 0 {
|
|
if rc&int32(0xFF) == int32(SQLITE_BUSY) {
|
|
v1 = -int32(1)
|
|
} else {
|
|
v1 = rc
|
|
}
|
|
return v1
|
|
}
|
|
/* Now that the read-lock has been obtained, check that neither the
|
|
** value in the aReadMark[] array or the contents of the wal-index
|
|
** header have changed.
|
|
**
|
|
** It is necessary to check that the wal-index header did not change
|
|
** between the time it was read and when the shared-lock was obtained
|
|
** on WAL_READ_LOCK(mxI) was obtained to account for the possibility
|
|
** that the log file may have been wrapped by a writer, or that frames
|
|
** that occur later in the log than pWal->hdr.mxFrame may have been
|
|
** copied into the database by a checkpointer. If either of these things
|
|
** happened, then reading the database with the current value of
|
|
** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry
|
|
** instead.
|
|
**
|
|
** Before checking that the live wal-index header has not changed
|
|
** since it was read, set Wal.minFrame to the first frame in the wal
|
|
** file that has not yet been checkpointed. This client will not need
|
|
** to read any frames earlier than minFrame from the wal file - they
|
|
** can be safely read directly from the database file.
|
|
**
|
|
** Because a ShmBarrier() call is made between taking the copy of
|
|
** nBackfill and checking that the wal-header in shared-memory still
|
|
** matches the one cached in pWal->hdr, it is guaranteed that the
|
|
** checkpointer that set nBackfill was not working with a wal-index
|
|
** header newer than that cached in pWal->hdr. If it were, that could
|
|
** cause a problem. The checkpointer could omit to checkpoint
|
|
** a version of page X that lies before pWal->minFrame (call that version
|
|
** A) on the basis that there is a newer version (version B) of the same
|
|
** page later in the wal file. But if version B happens to like past
|
|
** frame pWal->hdr.mxFrame - then the client would incorrectly assume
|
|
** that it can read version A from the database file. However, since
|
|
** we can guarantee that the checkpointer that set nBackfill could not
|
|
** see any pages past pWal->hdr.mxFrame, this problem does not come up.
|
|
*/
|
|
(*TWal)(unsafe.Pointer(pWal)).FminFrame = libc.Uint32FromInt32(libc.Int32FromUint32(libc.AtomicLoadNUint32(pInfo, libc.Int32FromInt32(__ATOMIC_RELAXED))) + int32(1))
|
|
_walShmBarrier(tls, pWal)
|
|
if libc.AtomicLoadNUint32(pInfo+4+uintptr(mxI)*4, libc.Int32FromInt32(__ATOMIC_RELAXED)) != mxReadMark || libc.Xmemcmp(tls, _walIndexHdr(tls, pWal), pWal+72, uint64(48)) != 0 {
|
|
_walUnlockShared(tls, pWal, int32(3)+mxI)
|
|
return -int32(1)
|
|
} else {
|
|
(*TWal)(unsafe.Pointer(pWal)).FreadLock = int16(mxI)
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Write out a single frame of the WAL
|
|
// */
|
|
func _walWriteOneFrame(tls *libc.TLS, p uintptr, pPage uintptr, nTruncate int32, iOffset Tsqlite3_int64) (r int32) {
|
|
bp := tls.Alloc(32)
|
|
defer tls.Free(32)
|
|
var pData uintptr
|
|
var rc int32
|
|
var _ /* aFrame at bp+0 */ [24]Tu8
|
|
_, _ = pData, rc /* Buffer to assemble frame-header in */
|
|
pData = (*TPgHdr)(unsafe.Pointer(pPage)).FpData
|
|
_walEncodeFrame(tls, (*TWalWriter)(unsafe.Pointer(p)).FpWal, (*TPgHdr)(unsafe.Pointer(pPage)).Fpgno, libc.Uint32FromInt32(nTruncate), pData, bp)
|
|
rc = _walWriteToLog(tls, p, bp, int32(24), iOffset)
|
|
if rc != 0 {
|
|
return rc
|
|
}
|
|
/* Write the page data */
|
|
rc = _walWriteToLog(tls, p, pData, (*TWalWriter)(unsafe.Pointer(p)).FszPage, libc.Int64FromUint64(libc.Uint64FromInt64(iOffset)+uint64(24)))
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add either a LIMIT (if eMatchOp==SQLITE_INDEX_CONSTRAINT_LIMIT) or
|
|
// ** OFFSET (if eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET) term to the
|
|
// ** where-clause passed as the first argument. The value for the term
|
|
// ** is found in register iReg.
|
|
// **
|
|
// ** In the common case where the value is a simple integer
|
|
// ** (example: "LIMIT 5 OFFSET 10") then the expression codes as a
|
|
// ** TK_INTEGER so that it will be available to sqlite3_vtab_rhs_value().
|
|
// ** If not, then it codes as a TK_REGISTER expression.
|
|
// */
|
|
func _whereAddLimitExpr(tls *libc.TLS, pWC uintptr, iReg int32, pExpr uintptr, iCsr int32, eMatchOp int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var db, pNew, pParse, pTerm, pVal, pVal1 uintptr
|
|
var idx int32
|
|
var _ /* iVal at bp+0 */ int32
|
|
_, _, _, _, _, _, _ = db, idx, pNew, pParse, pTerm, pVal, pVal1
|
|
pParse = (*TWhereInfo)(unsafe.Pointer((*TWhereClause)(unsafe.Pointer(pWC)).FpWInfo)).FpParse
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
if _sqlite3ExprIsInteger(tls, pExpr, bp, pParse) != 0 && **(**int32)(__ccgo_up(bp)) >= 0 {
|
|
pVal = _sqlite3ExprInt32(tls, db, **(**int32)(__ccgo_up(bp)))
|
|
if pVal == uintptr(0) {
|
|
return
|
|
}
|
|
pNew = _sqlite3PExpr(tls, pParse, int32(TK_MATCH), uintptr(0), pVal)
|
|
} else {
|
|
pVal1 = _sqlite3ExprAlloc(tls, db, int32(TK_REGISTER), uintptr(0), 0)
|
|
if pVal1 == uintptr(0) {
|
|
return
|
|
}
|
|
(*TExpr)(unsafe.Pointer(pVal1)).FiTable = iReg
|
|
pNew = _sqlite3PExpr(tls, pParse, int32(TK_MATCH), uintptr(0), pVal1)
|
|
}
|
|
if pNew != 0 {
|
|
idx = _whereClauseInsert(tls, pWC, pNew, libc.Uint16FromInt32(libc.Int32FromInt32(TERM_DYNAMIC)|libc.Int32FromInt32(TERM_VIRTUAL)))
|
|
pTerm = (*TWhereClause)(unsafe.Pointer(pWC)).Fa + uintptr(idx)*56
|
|
(*TWhereTerm)(unsafe.Pointer(pTerm)).FleftCursor = iCsr
|
|
(*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator = uint16(WO_AUX)
|
|
(*TWhereTerm)(unsafe.Pointer(pTerm)).FeMatchOp = libc.Uint8FromInt32(eMatchOp)
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** The pTruth expression is always true because it is the WHERE clause
|
|
// ** a partial index that is driving a query loop. Look through all of the
|
|
// ** WHERE clause terms on the query, and if any of those terms must be
|
|
// ** true because pTruth is true, then mark those WHERE clause terms as
|
|
// ** coded.
|
|
// */
|
|
func _whereApplyPartialIndexConstraints(tls *libc.TLS, pTruth uintptr, iTabCur int32, pWC uintptr) {
|
|
var i int32
|
|
var pExpr, pTerm, v2 uintptr
|
|
_, _, _, _ = i, pExpr, pTerm, v2
|
|
for libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pTruth)).Fop) == int32(TK_AND) {
|
|
_whereApplyPartialIndexConstraints(tls, (*TExpr)(unsafe.Pointer(pTruth)).FpLeft, iTabCur, pWC)
|
|
pTruth = (*TExpr)(unsafe.Pointer(pTruth)).FpRight
|
|
}
|
|
i = 0
|
|
pTerm = (*TWhereClause)(unsafe.Pointer(pWC)).Fa
|
|
for {
|
|
if !(i < (*TWhereClause)(unsafe.Pointer(pWC)).FnTerm) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FwtFlags)&int32(TERM_CODED) != 0 {
|
|
goto _1
|
|
}
|
|
pExpr = (*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr
|
|
if _sqlite3ExprCompare(tls, uintptr(0), pExpr, pTruth, iTabCur) == 0 {
|
|
v2 = pTerm + 18
|
|
*(*Tu16)(unsafe.Pointer(v2)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v2))) | libc.Int32FromInt32(TERM_CODED))
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
pTerm += 56
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Check to see if there are any SEARCH loops that might benefit from
|
|
// ** using a Bloom filter. Consider a Bloom filter if:
|
|
// **
|
|
// ** (1) The SEARCH happens more than N times where N is the number
|
|
// ** of rows in the table that is being considered for the Bloom
|
|
// ** filter.
|
|
// ** (2) Some searches are expected to find zero rows. (This is determined
|
|
// ** by the WHERE_SELFCULL flag on the term.)
|
|
// ** (3) Bloom-filter processing is not disabled. (Checked by the
|
|
// ** caller.)
|
|
// ** (4) The size of the table being searched is known by ANALYZE.
|
|
// **
|
|
// ** This block of code merely checks to see if a Bloom filter would be
|
|
// ** appropriate, and if so sets the WHERE_BLOOMFILTER flag on the
|
|
// ** WhereLoop. The implementation of the Bloom filter comes further
|
|
// ** down where the code for each WhereLoop is generated.
|
|
// */
|
|
func _whereCheckIfBloomFilterIsUseful(tls *libc.TLS, pWInfo uintptr) {
|
|
var i int32
|
|
var nSearch TLogEst
|
|
var pItem, pLoop, pTab uintptr
|
|
var reqFlags uint32
|
|
_, _, _, _, _, _ = i, nSearch, pItem, pLoop, pTab, reqFlags
|
|
nSearch = 0
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint8((*TWhereInfo)(unsafe.Pointer(pWInfo)).FnLevel)) {
|
|
break
|
|
}
|
|
pLoop = (*(*TWhereLevel)(unsafe.Pointer(pWInfo + 856 + uintptr(i)*112))).FpWLoop
|
|
reqFlags = libc.Uint32FromInt32(libc.Int32FromInt32(WHERE_SELFCULL) | libc.Int32FromInt32(WHERE_COLUMN_EQ))
|
|
pItem = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpTabList + 8 + uintptr((*TWhereLoop)(unsafe.Pointer(pLoop)).FiTab)*80
|
|
pTab = (*TSrcItem)(unsafe.Pointer(pItem)).FpSTab
|
|
if (*TTable)(unsafe.Pointer(pTab)).FtabFlags&uint32(TF_HasStat1) == uint32(0) {
|
|
break
|
|
}
|
|
**(**Tu32)(__ccgo_up(pTab + 48)) |= uint32(TF_MaybeReanalyze)
|
|
if i >= int32(1) && (*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags&reqFlags == reqFlags && (*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags&libc.Uint32FromInt32(libc.Int32FromInt32(WHERE_IPK)|libc.Int32FromInt32(WHERE_INDEXED)) != uint32(0) {
|
|
if int32(nSearch) > int32((*TTable)(unsafe.Pointer(pTab)).FnRowLogEst) {
|
|
**(**Tu32)(__ccgo_up(pLoop + 48)) |= uint32(WHERE_BLOOMFILTER)
|
|
**(**Tu32)(__ccgo_up(pLoop + 48)) &= libc.Uint32FromInt32(^libc.Int32FromInt32(WHERE_IDX_ONLY))
|
|
}
|
|
}
|
|
nSearch = int16(int32(nSearch) + int32((*TWhereLoop)(unsafe.Pointer(pLoop)).FnOut))
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Estimate the number of rows that will be returned based on
|
|
// ** an IN constraint where the right-hand side of the IN operator
|
|
// ** is a list of values. Example:
|
|
// **
|
|
// ** WHERE x IN (1,2,3,4)
|
|
// **
|
|
// ** Write the estimated row count into *pnRow and return SQLITE_OK.
|
|
// ** If unable to make an estimate, leave *pnRow unchanged and return
|
|
// ** non-zero.
|
|
// **
|
|
// ** This routine can fail if it is unable to load a collating sequence
|
|
// ** required for string comparison, or if unable to allocate memory
|
|
// ** for a UTF conversion required for comparison. The error is stored
|
|
// ** in the pParse structure.
|
|
// */
|
|
func _whereInScanEst(tls *libc.TLS, pParse uintptr, pBuilder uintptr, pList uintptr, pnRow uintptr) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var i, nRecValid, rc int32
|
|
var nRow0 Ti64
|
|
var nRowEst TtRowcnt
|
|
var p uintptr
|
|
var _ /* nEst at bp+0 */ TtRowcnt
|
|
_, _, _, _, _, _ = i, nRecValid, nRow0, nRowEst, p, rc
|
|
p = (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer((*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FpNew + 24))).FpIndex
|
|
nRow0 = libc.Int64FromUint64(_sqlite3LogEstToInt(tls, **(**TLogEst)(__ccgo_up((*TIndex)(unsafe.Pointer(p)).FaiRowLogEst))))
|
|
nRecValid = (*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FnRecValid
|
|
rc = SQLITE_OK /* Number of rows for a single term */
|
|
nRowEst = uint64(0) /* Loop counter */
|
|
i = 0
|
|
for {
|
|
if !(rc == SQLITE_OK && i < (*TExprList)(unsafe.Pointer(pList)).FnExpr) {
|
|
break
|
|
}
|
|
**(**TtRowcnt)(__ccgo_up(bp)) = libc.Uint64FromInt64(nRow0)
|
|
rc = _whereEqualScanEst(tls, pParse, pBuilder, (*(*TExprList_item)(unsafe.Pointer(pList + 8 + uintptr(i)*32))).FpExpr, bp)
|
|
nRowEst = nRowEst + **(**TtRowcnt)(__ccgo_up(bp))
|
|
(*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FnRecValid = nRecValid
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if rc == SQLITE_OK {
|
|
if nRowEst > libc.Uint64FromInt64(nRow0) {
|
|
nRowEst = libc.Uint64FromInt64(nRow0)
|
|
}
|
|
**(**TtRowcnt)(__ccgo_up(pnRow)) = nRowEst
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** This routine implements a heuristic designed to improve query planning.
|
|
// ** This routine is called in between the first and second call to
|
|
// ** wherePathSolver(). Hence the name "Interstage" "Heuristic".
|
|
// **
|
|
// ** The first call to wherePathSolver() (hereafter just "solver()") computes
|
|
// ** the best path without regard to the order of the outputs. The second call
|
|
// ** to the solver() builds upon the first call to try to find an alternative
|
|
// ** path that satisfies the ORDER BY clause.
|
|
// **
|
|
// ** This routine looks at the results of the first solver() run, and for
|
|
// ** every FROM clause term in the resulting query plan that uses an equality
|
|
// ** constraint against an index, disable other WhereLoops for that same
|
|
// ** FROM clause term that would try to do a full-table scan. This prevents
|
|
// ** an index search from being converted into a full-table scan in order to
|
|
// ** satisfy an ORDER BY clause, since even though we might get slightly better
|
|
// ** performance using the full-scan without sorting if the output size
|
|
// ** estimates are very precise, we might also get severe performance
|
|
// ** degradation using the full-scan if the output size estimate is too large.
|
|
// ** It is better to err on the side of caution.
|
|
// **
|
|
// ** Except, if the first solver() call generated a full-table scan in an outer
|
|
// ** loop then stop this analysis at the first full-scan, since the second
|
|
// ** solver() run might try to swap that full-scan for another in order to
|
|
// ** get the output into the correct order. In other words, we allow a
|
|
// ** rewrite like this:
|
|
// **
|
|
// ** First Solver() Second Solver()
|
|
// ** |-- SCAN t1 |-- SCAN t2
|
|
// ** |-- SEARCH t2 `-- SEARCH t1
|
|
// ** `-- SORT USING B-TREE
|
|
// **
|
|
// ** The purpose of this routine is to disallow rewrites such as:
|
|
// **
|
|
// ** First Solver() Second Solver()
|
|
// ** |-- SEARCH t1 |-- SCAN t2 <--- bad!
|
|
// ** |-- SEARCH t2 `-- SEARCH t1
|
|
// ** `-- SORT USING B-TREE
|
|
// **
|
|
// ** See test cases in test/whereN.test for the real-world query that
|
|
// ** originally provoked this heuristic.
|
|
// */
|
|
func _whereInterstageHeuristic(tls *libc.TLS, pWInfo uintptr) {
|
|
var i int32
|
|
var iTab Tu8
|
|
var p, pLoop uintptr
|
|
_, _, _, _ = i, iTab, p, pLoop
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint8((*TWhereInfo)(unsafe.Pointer(pWInfo)).FnLevel)) {
|
|
break
|
|
}
|
|
p = (*(*TWhereLevel)(unsafe.Pointer(pWInfo + 856 + uintptr(i)*112))).FpWLoop
|
|
if p == uintptr(0) {
|
|
break
|
|
}
|
|
if (*TWhereLoop)(unsafe.Pointer(p)).FwsFlags&uint32(WHERE_VIRTUALTABLE) != uint32(0) {
|
|
/* Treat a vtab scan as similar to a full-table scan */
|
|
break
|
|
}
|
|
if (*TWhereLoop)(unsafe.Pointer(p)).FwsFlags&libc.Uint32FromInt32(libc.Int32FromInt32(WHERE_COLUMN_EQ)|libc.Int32FromInt32(WHERE_COLUMN_NULL)|libc.Int32FromInt32(WHERE_COLUMN_IN)) != uint32(0) {
|
|
iTab = (*TWhereLoop)(unsafe.Pointer(p)).FiTab
|
|
pLoop = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpLoops
|
|
for {
|
|
if !(pLoop != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((*TWhereLoop)(unsafe.Pointer(pLoop)).FiTab) != libc.Int32FromUint8(iTab) {
|
|
goto _2
|
|
}
|
|
if (*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags&libc.Uint32FromInt32(libc.Int32FromInt32(WHERE_CONSTRAINT)|libc.Int32FromInt32(WHERE_AUTO_INDEX)) != uint32(0) {
|
|
/* Auto-index and index-constrained loops allowed to remain */
|
|
goto _2
|
|
}
|
|
(*TWhereLoop)(unsafe.Pointer(pLoop)).Fprereq = libc.Uint64FromInt32(-libc.Int32FromInt32(1)) /* Prevent 2nd solver() from using this one */
|
|
goto _2
|
|
_2:
|
|
;
|
|
pLoop = (*TWhereLoop)(unsafe.Pointer(pLoop)).FpNextLoop
|
|
}
|
|
} else {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Information passed in is pWalk->u.pCovIdxCk. Call it pCk.
|
|
// **
|
|
// ** If the Expr node references the table with cursor pCk->iTabCur, then
|
|
// ** make sure that column is covered by the index pCk->pIdx. We know that
|
|
// ** all columns less than 63 (really BMS-1) are covered, so we don't need
|
|
// ** to check them. But we do need to check any column at 63 or greater.
|
|
// **
|
|
// ** If the index does not cover the column, then set pWalk->eCode to
|
|
// ** non-zero and return WRC_Abort to stop the search.
|
|
// **
|
|
// ** If this node does not disprove that the index can be a covering index,
|
|
// ** then just return WRC_Continue, to continue the search.
|
|
// **
|
|
// ** If pCk->pIdx contains indexed expressions and one of those expressions
|
|
// ** matches pExpr, then prune the search.
|
|
// */
|
|
func _whereIsCoveringIndexWalkCallback(tls *libc.TLS, pWalk uintptr, pExpr uintptr) (r int32) {
|
|
var aiColumn, pCk, pIdx uintptr
|
|
var i int32
|
|
var nColumn Tu16
|
|
_, _, _, _, _ = aiColumn, i, nColumn, pCk, pIdx /* Info about this search */
|
|
pCk = *(*uintptr)(unsafe.Pointer(pWalk + 40))
|
|
pIdx = (*TCoveringIndexCheck)(unsafe.Pointer(pCk)).FpIdx
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_COLUMN) || libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pExpr)).Fop) == int32(TK_AGG_COLUMN) {
|
|
/* if( pExpr->iColumn<(BMS-1) && pIdx->bHasExpr==0 ) return WRC_Continue;*/
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).FiTable != (*TCoveringIndexCheck)(unsafe.Pointer(pCk)).FiTabCur {
|
|
return WRC_Continue
|
|
}
|
|
pIdx = (*TCoveringIndexCheck)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pWalk + 40)))).FpIdx
|
|
aiColumn = (*TIndex)(unsafe.Pointer(pIdx)).FaiColumn
|
|
nColumn = (*TIndex)(unsafe.Pointer(pIdx)).FnColumn
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint16(nColumn)) {
|
|
break
|
|
}
|
|
if int32(**(**Ti16)(__ccgo_up(aiColumn + uintptr(i)*2))) == int32((*TExpr)(unsafe.Pointer(pExpr)).FiColumn) {
|
|
return WRC_Continue
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
(*TCoveringIndexCheck)(unsafe.Pointer(pCk)).FbUnidx = uint8(1)
|
|
return int32(WRC_Abort)
|
|
} else {
|
|
if int32(uint32(*(*uint16)(unsafe.Pointer(pIdx + 100))&0x800>>11)) != 0 && _exprIsCoveredByIndex(tls, pExpr, pIdx, (*TCoveringIndexCheck)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pWalk + 40)))).FiTabCur) != 0 {
|
|
(*TCoveringIndexCheck)(unsafe.Pointer(pCk)).FbExpr = uint8(1)
|
|
return int32(WRC_Prune)
|
|
}
|
|
}
|
|
return WRC_Continue
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Estimate the location of a particular key among all keys in an
|
|
// ** index. Store the results in aStat as follows:
|
|
// **
|
|
// ** aStat[0] Est. number of rows less than pRec
|
|
// ** aStat[1] Est. number of rows equal to pRec
|
|
// **
|
|
// ** Return the index of the sample that is the smallest sample that
|
|
// ** is greater than or equal to pRec. Note that this index is not an index
|
|
// ** into the aSample[] array - it is an index into a virtual set of samples
|
|
// ** based on the contents of aSample[] and the number of fields in record
|
|
// ** pRec.
|
|
// */
|
|
func _whereKeyStats(tls *libc.TLS, pParse uintptr, pIdx uintptr, pRec uintptr, roundUp int32, aStat uintptr) (r int32) {
|
|
var aSample uintptr
|
|
var i, iCol, iMin, iSamp, iSample, iTest, n, nField, res, v1 int32
|
|
var iGap, iLower, iUpper TtRowcnt
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _ = aSample, i, iCol, iGap, iLower, iMin, iSamp, iSample, iTest, iUpper, n, nField, res, v1
|
|
aSample = (*TIndex)(unsafe.Pointer(pIdx)).FaSample /* Smallest sample larger than or equal to pRec */
|
|
iMin = 0 /* Number of fields in pRec */
|
|
iLower = uint64(0) /* anLt[] + anEq[] of largest sample pRec is > */
|
|
_ = pParse
|
|
/* Do a binary search to find the first sample greater than or equal
|
|
** to pRec. If pRec contains a single field, the set of samples to search
|
|
** is simply the aSample[] array. If the samples in aSample[] contain more
|
|
** than one fields, all fields following the first are ignored.
|
|
**
|
|
** If pRec contains N fields, where N is more than one, then as well as the
|
|
** samples in aSample[] (truncated to N fields), the search also has to
|
|
** consider prefixes of those samples. For example, if the set of samples
|
|
** in aSample is:
|
|
**
|
|
** aSample[0] = (a, 5)
|
|
** aSample[1] = (a, 10)
|
|
** aSample[2] = (b, 5)
|
|
** aSample[3] = (c, 100)
|
|
** aSample[4] = (c, 105)
|
|
**
|
|
** Then the search space should ideally be the samples above and the
|
|
** unique prefixes [a], [b] and [c]. But since that is hard to organize,
|
|
** the code actually searches this set:
|
|
**
|
|
** 0: (a)
|
|
** 1: (a, 5)
|
|
** 2: (a, 10)
|
|
** 3: (a, 10)
|
|
** 4: (b)
|
|
** 5: (b, 5)
|
|
** 6: (c)
|
|
** 7: (c, 100)
|
|
** 8: (c, 105)
|
|
** 9: (c, 105)
|
|
**
|
|
** For each sample in the aSample[] array, N samples are present in the
|
|
** effective sample array. In the above, samples 0 and 1 are based on
|
|
** sample aSample[0]. Samples 2 and 3 on aSample[1] etc.
|
|
**
|
|
** Often, sample i of each block of N effective samples has (i+1) fields.
|
|
** Except, each sample may be extended to ensure that it is greater than or
|
|
** equal to the previous sample in the array. For example, in the above,
|
|
** sample 2 is the first sample of a block of N samples, so at first it
|
|
** appears that it should be 1 field in size. However, that would make it
|
|
** smaller than sample 1, so the binary search would not work. As a result,
|
|
** it is extended to two fields. The duplicates that this creates do not
|
|
** cause any problems.
|
|
*/
|
|
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) {
|
|
nField = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol)
|
|
} else {
|
|
nField = libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnColumn)
|
|
}
|
|
if libc.Int32FromUint16((*TUnpackedRecord)(unsafe.Pointer(pRec)).FnField) < nField {
|
|
v1 = libc.Int32FromUint16((*TUnpackedRecord)(unsafe.Pointer(pRec)).FnField)
|
|
} else {
|
|
v1 = nField
|
|
}
|
|
nField = v1
|
|
iCol = 0
|
|
iSample = (*TIndex)(unsafe.Pointer(pIdx)).FnSample * nField
|
|
for cond := true; cond; cond = res != 0 && iMin < iSample { /* Number of fields in test sample */
|
|
iTest = (iMin + iSample) / int32(2)
|
|
iSamp = iTest / nField
|
|
if iSamp > 0 {
|
|
/* The proposed effective sample is a prefix of sample aSample[iSamp].
|
|
** Specifically, the shortest prefix of at least (1 + iTest%nField)
|
|
** fields that is greater than the previous effective sample. */
|
|
n = iTest%nField + int32(1)
|
|
for {
|
|
if !(n < nField) {
|
|
break
|
|
}
|
|
if **(**TtRowcnt)(__ccgo_up((**(**TIndexSample)(__ccgo_up(aSample + uintptr(iSamp-int32(1))*40))).FanLt + uintptr(n-int32(1))*8)) != **(**TtRowcnt)(__ccgo_up((**(**TIndexSample)(__ccgo_up(aSample + uintptr(iSamp)*40))).FanLt + uintptr(n-int32(1))*8)) {
|
|
break
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
n = n + 1
|
|
}
|
|
} else {
|
|
n = iTest + int32(1)
|
|
}
|
|
(*TUnpackedRecord)(unsafe.Pointer(pRec)).FnField = libc.Uint16FromInt32(n)
|
|
res = _sqlite3VdbeRecordCompare(tls, (**(**TIndexSample)(__ccgo_up(aSample + uintptr(iSamp)*40))).Fn, (**(**TIndexSample)(__ccgo_up(aSample + uintptr(iSamp)*40))).Fp, pRec)
|
|
if res < 0 {
|
|
iLower = **(**TtRowcnt)(__ccgo_up((**(**TIndexSample)(__ccgo_up(aSample + uintptr(iSamp)*40))).FanLt + uintptr(n-int32(1))*8)) + **(**TtRowcnt)(__ccgo_up((**(**TIndexSample)(__ccgo_up(aSample + uintptr(iSamp)*40))).FanEq + uintptr(n-int32(1))*8))
|
|
iMin = iTest + int32(1)
|
|
} else {
|
|
if res == 0 && n < nField {
|
|
iLower = **(**TtRowcnt)(__ccgo_up((**(**TIndexSample)(__ccgo_up(aSample + uintptr(iSamp)*40))).FanLt + uintptr(n-int32(1))*8))
|
|
iMin = iTest + int32(1)
|
|
res = -int32(1)
|
|
} else {
|
|
iSample = iTest
|
|
iCol = n - int32(1)
|
|
}
|
|
}
|
|
}
|
|
i = iSample / nField
|
|
if res == 0 {
|
|
/* Record pRec is equal to sample i */
|
|
**(**TtRowcnt)(__ccgo_up(aStat)) = **(**TtRowcnt)(__ccgo_up((**(**TIndexSample)(__ccgo_up(aSample + uintptr(i)*40))).FanLt + uintptr(iCol)*8))
|
|
**(**TtRowcnt)(__ccgo_up(aStat + 1*8)) = **(**TtRowcnt)(__ccgo_up((**(**TIndexSample)(__ccgo_up(aSample + uintptr(i)*40))).FanEq + uintptr(iCol)*8))
|
|
} else {
|
|
if i >= (*TIndex)(unsafe.Pointer(pIdx)).FnSample {
|
|
iUpper = (*TIndex)(unsafe.Pointer(pIdx)).FnRowEst0
|
|
} else {
|
|
iUpper = **(**TtRowcnt)(__ccgo_up((**(**TIndexSample)(__ccgo_up(aSample + uintptr(i)*40))).FanLt + uintptr(iCol)*8))
|
|
}
|
|
if iLower >= iUpper {
|
|
iGap = uint64(0)
|
|
} else {
|
|
iGap = iUpper - iLower
|
|
}
|
|
if roundUp != 0 {
|
|
iGap = iGap * uint64(2) / uint64(3)
|
|
} else {
|
|
iGap = iGap / uint64(3)
|
|
}
|
|
**(**TtRowcnt)(__ccgo_up(aStat)) = iLower + iGap
|
|
**(**TtRowcnt)(__ccgo_up(aStat + 1*8)) = **(**TtRowcnt)(__ccgo_up((*TIndex)(unsafe.Pointer(pIdx)).FaAvgEq + uintptr(nField-int32(1))*8))
|
|
}
|
|
/* Restore the pRec->nField value before returning. */
|
|
(*TUnpackedRecord)(unsafe.Pointer(pRec)).FnField = libc.Uint16FromInt32(nField)
|
|
return i
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** We have so far matched pBuilder->pNew->u.btree.nEq terms of the
|
|
// ** index pIndex. Try to match one more.
|
|
// **
|
|
// ** When this function is called, pBuilder->pNew->nOut contains the
|
|
// ** number of rows expected to be visited by filtering using the nEq
|
|
// ** terms only. If it is modified, this value is restored before this
|
|
// ** function returns.
|
|
// **
|
|
// ** If pProbe->idxType==SQLITE_IDXTYPE_IPK, that means pIndex is
|
|
// ** a fake index used for the INTEGER PRIMARY KEY.
|
|
// */
|
|
func _whereLoopAddBtreeIndex(tls *libc.TLS, pBuilder uintptr, pSrc uintptr, pProbe uintptr, nInMul TLogEst) (r int32) {
|
|
bp := tls.Alloc(128)
|
|
defer tls.Free(128)
|
|
var M, logK, nIter, nOutUnadjusted, rCostIdx, rLogSize, rSize, saved_nOut, x TLogEst
|
|
var bRedundant, i, iCol, nEq, nIn, nRecValid, nVecLen, opMask, rc, v21 int32
|
|
var db, pBtm, pExpr, pExpr1, pNew, pParse, pTerm, pTop, pWInfo, v2 uintptr
|
|
var eOp, saved_nBtm, saved_nEq, saved_nLTerm, saved_nSkip, saved_nTop, v4 Tu16
|
|
var saved_prereq TBitmask
|
|
var saved_wsFlags Tu32
|
|
var v22 bool
|
|
var _ /* nOut at bp+112 */ TtRowcnt
|
|
var _ /* scan at bp+0 */ TWhereScan
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = M, bRedundant, db, eOp, i, iCol, logK, nEq, nIn, nIter, nOutUnadjusted, nRecValid, nVecLen, opMask, pBtm, pExpr, pExpr1, pNew, pParse, pTerm, pTop, pWInfo, rCostIdx, rLogSize, rSize, rc, saved_nBtm, saved_nEq, saved_nLTerm, saved_nOut, saved_nSkip, saved_nTop, saved_prereq, saved_wsFlags, x, v2, v21, v22, v4
|
|
pWInfo = (*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FpWInfo /* WHERE analyze context */
|
|
pParse = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpParse /* Parsing context */
|
|
db = (*TParse)(unsafe.Pointer(pParse)).Fdb /* Original value of pNew->nOut */
|
|
rc = SQLITE_OK /* Logarithm of table size */
|
|
pTop = uintptr(0)
|
|
pBtm = uintptr(0) /* Top and bottom range constraints */
|
|
pNew = (*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FpNew
|
|
if (*TParse)(unsafe.Pointer(pParse)).FnErr != 0 {
|
|
return (*TParse)(unsafe.Pointer(pParse)).Frc
|
|
}
|
|
if (*TWhereLoop)(unsafe.Pointer(pNew)).FwsFlags&uint32(WHERE_BTM_LIMIT) != 0 {
|
|
opMask = libc.Int32FromInt32(WO_EQ)<<(libc.Int32FromInt32(TK_LT)-libc.Int32FromInt32(TK_EQ)) | libc.Int32FromInt32(WO_EQ)<<(libc.Int32FromInt32(TK_LE)-libc.Int32FromInt32(TK_EQ))
|
|
} else {
|
|
opMask = libc.Int32FromInt32(WO_EQ) | libc.Int32FromInt32(WO_IN) | libc.Int32FromInt32(WO_EQ)<<(libc.Int32FromInt32(TK_GT)-libc.Int32FromInt32(TK_EQ)) | libc.Int32FromInt32(WO_EQ)<<(libc.Int32FromInt32(TK_GE)-libc.Int32FromInt32(TK_EQ)) | libc.Int32FromInt32(WO_EQ)<<(libc.Int32FromInt32(TK_LT)-libc.Int32FromInt32(TK_EQ)) | libc.Int32FromInt32(WO_EQ)<<(libc.Int32FromInt32(TK_LE)-libc.Int32FromInt32(TK_EQ)) | libc.Int32FromInt32(WO_ISNULL) | libc.Int32FromInt32(WO_IS)
|
|
}
|
|
if int32(uint32(*(*uint16)(unsafe.Pointer(pProbe + 100))&0x4>>2)) != 0 {
|
|
opMask = opMask & ^(libc.Int32FromInt32(WO_EQ)<<(libc.Int32FromInt32(TK_GT)-libc.Int32FromInt32(TK_EQ)) | libc.Int32FromInt32(WO_EQ)<<(libc.Int32FromInt32(TK_GE)-libc.Int32FromInt32(TK_EQ)) | libc.Int32FromInt32(WO_EQ)<<(libc.Int32FromInt32(TK_LT)-libc.Int32FromInt32(TK_EQ)) | libc.Int32FromInt32(WO_EQ)<<(libc.Int32FromInt32(TK_LE)-libc.Int32FromInt32(TK_EQ)))
|
|
}
|
|
saved_nEq = (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnEq
|
|
saved_nBtm = (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnBtm
|
|
saved_nTop = (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnTop
|
|
saved_nSkip = (*TWhereLoop)(unsafe.Pointer(pNew)).FnSkip
|
|
saved_nLTerm = (*TWhereLoop)(unsafe.Pointer(pNew)).FnLTerm
|
|
saved_wsFlags = (*TWhereLoop)(unsafe.Pointer(pNew)).FwsFlags
|
|
saved_prereq = (*TWhereLoop)(unsafe.Pointer(pNew)).Fprereq
|
|
saved_nOut = (*TWhereLoop)(unsafe.Pointer(pNew)).FnOut
|
|
pTerm = _whereScanInit(tls, bp, (*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FpWC, (*TSrcItem)(unsafe.Pointer(pSrc)).FiCursor, libc.Int32FromUint16(saved_nEq), libc.Uint32FromInt32(opMask), pProbe)
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FrSetup = 0
|
|
rSize = **(**TLogEst)(__ccgo_up((*TIndex)(unsafe.Pointer(pProbe)).FaiRowLogEst))
|
|
rLogSize = _estLog(tls, rSize)
|
|
for {
|
|
if !(rc == SQLITE_OK && pTerm != uintptr(0)) {
|
|
break
|
|
}
|
|
eOp = (*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator /* nOut before IN() and WHERE adjustments */
|
|
nIn = 0
|
|
nRecValid = (*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FnRecValid
|
|
if (libc.Int32FromUint16(eOp) == int32(WO_ISNULL) || libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FwtFlags)&int32(TERM_VNULL) != 0) && _indexColumnNotNull(tls, pProbe, libc.Int32FromUint16(saved_nEq)) != 0 {
|
|
goto _1 /* ignore IS [NOT] NULL constraints on NOT NULL columns */
|
|
}
|
|
if (*TWhereTerm)(unsafe.Pointer(pTerm)).FprereqRight&(*TWhereLoop)(unsafe.Pointer(pNew)).FmaskSelf != 0 {
|
|
goto _1
|
|
}
|
|
/* Do not allow the upper bound of a LIKE optimization range constraint
|
|
** to mix with a lower range bound from some other source */
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FwtFlags)&int32(TERM_LIKEOPT) != 0 && libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator) == libc.Int32FromInt32(WO_EQ)<<(libc.Int32FromInt32(TK_LT)-libc.Int32FromInt32(TK_EQ)) {
|
|
goto _1
|
|
}
|
|
if libc.Int32FromUint8((*TSrcItem)(unsafe.Pointer(pSrc)).Ffg.Fjointype)&(libc.Int32FromInt32(JT_LEFT)|libc.Int32FromInt32(JT_LTORJ)|libc.Int32FromInt32(JT_RIGHT)) != 0 && !(_constraintCompatibleWithOuterJoin(tls, pTerm, pSrc) != 0) {
|
|
goto _1
|
|
}
|
|
if libc.Int32FromUint8((*TIndex)(unsafe.Pointer(pProbe)).FonError) != OE_None && libc.Int32FromUint16(saved_nEq) == libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pProbe)).FnKeyCol)-int32(1) {
|
|
v2 = pBuilder + 44
|
|
*(*uint8)(unsafe.Pointer(v2)) = uint8(int32(*(*uint8)(unsafe.Pointer(v2))) | libc.Int32FromInt32(SQLITE_BLDF1_UNIQUE))
|
|
} else {
|
|
v2 = pBuilder + 44
|
|
*(*uint8)(unsafe.Pointer(v2)) = uint8(int32(*(*uint8)(unsafe.Pointer(v2))) | libc.Int32FromInt32(SQLITE_BLDF1_INDEXED))
|
|
}
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FwsFlags = saved_wsFlags
|
|
(*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnEq = saved_nEq
|
|
(*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnBtm = saved_nBtm
|
|
(*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnTop = saved_nTop
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FnLTerm = saved_nLTerm
|
|
if libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pNew)).FnLTerm) >= libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pNew)).FnLSlot) && _whereLoopResize(tls, db, pNew, libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pNew)).FnLTerm)+int32(1)) != 0 {
|
|
break /* OOM while trying to enlarge the pNew->aLTerm array */
|
|
}
|
|
v2 = pNew + 52
|
|
v4 = *(*Tu16)(unsafe.Pointer(v2))
|
|
*(*Tu16)(unsafe.Pointer(v2)) = *(*Tu16)(unsafe.Pointer(v2)) + 1
|
|
**(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pNew)).FaLTerm + uintptr(v4)*8)) = pTerm
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).Fprereq = (saved_prereq | (*TWhereTerm)(unsafe.Pointer(pTerm)).FprereqRight) & ^(*TWhereLoop)(unsafe.Pointer(pNew)).FmaskSelf
|
|
if libc.Int32FromUint16(eOp)&int32(WO_IN) != 0 {
|
|
pExpr = (*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr
|
|
if (*TExpr)(unsafe.Pointer(pExpr)).Fflags&uint32(EP_xIsSelect) != uint32(0) {
|
|
bRedundant = 0
|
|
nIn = int32(46)
|
|
/* The expression may actually be of the form (x, y) IN (SELECT...).
|
|
** In this case there is a separate term for each of (x) and (y).
|
|
** However, the nIn multiplier should only be applied once, not once
|
|
** for each such term. The following loop checks that pTerm is the
|
|
** first such term in use, and sets nIn back to 0 if it is not. */
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pNew)).FnLTerm)-int32(1)) {
|
|
break
|
|
}
|
|
if **(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pNew)).FaLTerm + uintptr(i)*8)) != 0 && (*TWhereTerm)(unsafe.Pointer(**(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pNew)).FaLTerm + uintptr(i)*8)))).FpExpr == pExpr {
|
|
nIn = 0
|
|
if (*(*struct {
|
|
FleftColumn int32
|
|
FiField int32
|
|
})(unsafe.Pointer(**(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pNew)).FaLTerm + uintptr(i)*8)) + 32))).FiField == (*(*struct {
|
|
FleftColumn int32
|
|
FiField int32
|
|
})(unsafe.Pointer(pTerm + 32))).FiField {
|
|
/* Detect when two or more columns of an index match the same
|
|
** column of a vector IN operater, and avoid adding the column
|
|
** to the WhereLoop more than once. See tag-20250707-01
|
|
** in test/rowvalue.test */
|
|
bRedundant = int32(1)
|
|
}
|
|
}
|
|
goto _6
|
|
_6:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if bRedundant != 0 {
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FnLTerm = (*TWhereLoop)(unsafe.Pointer(pNew)).FnLTerm - 1
|
|
goto _1
|
|
}
|
|
} else {
|
|
if *(*uintptr)(unsafe.Pointer(pExpr + 32)) != 0 && (*TExprList)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)))).FnExpr != 0 {
|
|
/* "x IN (value, value, ...)" */
|
|
nIn = int32(_sqlite3LogEst(tls, libc.Uint64FromInt32((*TExprList)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pExpr + 32)))).FnExpr)))
|
|
}
|
|
}
|
|
if int32(uint32(*(*uint16)(unsafe.Pointer(pProbe + 100))&0x80>>7)) != 0 && int32(rLogSize) >= int32(10) {
|
|
/* Let:
|
|
** N = the total number of rows in the table
|
|
** K = the number of entries on the RHS of the IN operator
|
|
** M = the number of rows in the table that match terms to the
|
|
** to the left in the same index. If the IN operator is on
|
|
** the left-most index column, M==N.
|
|
**
|
|
** Given the definitions above, it is better to omit the IN operator
|
|
** from the index lookup and instead do a scan of the M elements,
|
|
** testing each scanned row against the IN operator separately, if:
|
|
**
|
|
** M*log(K) < K*log(N)
|
|
**
|
|
** Our estimates for M, K, and N might be inaccurate, so we build in
|
|
** a safety margin of 2 (LogEst: 10) that favors using the IN operator
|
|
** with the index, as using an index has better worst-case behavior.
|
|
** If we do not have real sqlite_stat1 data, always prefer to use
|
|
** the index. Do not bother with this optimization on very small
|
|
** tables (less than 2 rows) as it is pointless in that case.
|
|
*/
|
|
M = **(**TLogEst)(__ccgo_up((*TIndex)(unsafe.Pointer(pProbe)).FaiRowLogEst + uintptr(saved_nEq)*2))
|
|
logK = _estLog(tls, int16(nIn))
|
|
/* TUNING v----- 10 to bias toward indexed IN */
|
|
x = int16(int32(M) + int32(logK) + int32(10) - (nIn + int32(rLogSize)))
|
|
if int32(x) >= 0 {
|
|
} else {
|
|
if int32(nInMul) < int32(2) && (*Tsqlite3)(unsafe.Pointer(db)).FdbOptFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_SeekScan)) == uint32(0) {
|
|
**(**Tu32)(__ccgo_up(pNew + 48)) |= uint32(WHERE_IN_SEEKSCAN)
|
|
} else {
|
|
goto _1
|
|
}
|
|
}
|
|
}
|
|
**(**Tu32)(__ccgo_up(pNew + 48)) |= uint32(WHERE_COLUMN_IN)
|
|
} else {
|
|
if libc.Int32FromUint16(eOp)&(libc.Int32FromInt32(WO_EQ)|libc.Int32FromInt32(WO_IS)) != 0 {
|
|
iCol = int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pProbe)).FaiColumn + uintptr(saved_nEq)*2)))
|
|
**(**Tu32)(__ccgo_up(pNew + 48)) |= uint32(WHERE_COLUMN_EQ)
|
|
if iCol == -int32(1) || iCol >= 0 && int32(nInMul) == 0 && libc.Int32FromUint16(saved_nEq) == libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pProbe)).FnKeyCol)-int32(1) {
|
|
if iCol == -int32(1) || int32(uint32(*(*uint16)(unsafe.Pointer(pProbe + 100))&0x8>>3)) != 0 || libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pProbe)).FnKeyCol) == int32(1) && (*TIndex)(unsafe.Pointer(pProbe)).FonError != 0 && libc.Int32FromUint16(eOp)&int32(WO_EQ) != 0 {
|
|
**(**Tu32)(__ccgo_up(pNew + 48)) |= uint32(WHERE_ONEROW)
|
|
} else {
|
|
**(**Tu32)(__ccgo_up(pNew + 48)) |= uint32(WHERE_UNQ_WANTED)
|
|
}
|
|
}
|
|
if libc.Int32FromUint8((**(**TWhereScan)(__ccgo_up(bp))).FiEquiv) > int32(1) {
|
|
**(**Tu32)(__ccgo_up(pNew + 48)) |= uint32(WHERE_TRANSCONS)
|
|
}
|
|
} else {
|
|
if libc.Int32FromUint16(eOp)&int32(WO_ISNULL) != 0 {
|
|
**(**Tu32)(__ccgo_up(pNew + 48)) |= uint32(WHERE_COLUMN_NULL)
|
|
} else {
|
|
nVecLen = _whereRangeVectorLen(tls, pParse, (*TSrcItem)(unsafe.Pointer(pSrc)).FiCursor, pProbe, libc.Int32FromUint16(saved_nEq), pTerm)
|
|
if libc.Int32FromUint16(eOp)&(libc.Int32FromInt32(WO_EQ)<<(libc.Int32FromInt32(TK_GT)-libc.Int32FromInt32(TK_EQ))|libc.Int32FromInt32(WO_EQ)<<(libc.Int32FromInt32(TK_GE)-libc.Int32FromInt32(TK_EQ))) != 0 {
|
|
**(**Tu32)(__ccgo_up(pNew + 48)) |= libc.Uint32FromInt32(libc.Int32FromInt32(WHERE_COLUMN_RANGE) | libc.Int32FromInt32(WHERE_BTM_LIMIT))
|
|
(*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnBtm = libc.Uint16FromInt32(nVecLen)
|
|
pBtm = pTerm
|
|
pTop = uintptr(0)
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FwtFlags)&int32(TERM_LIKEOPT) != 0 {
|
|
/* Range constraints that come from the LIKE optimization are
|
|
** always used in pairs. */
|
|
pTop = pTerm + 1*56
|
|
if _whereLoopResize(tls, db, pNew, libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pNew)).FnLTerm)+int32(1)) != 0 {
|
|
break
|
|
} /* OOM */
|
|
v2 = pNew + 52
|
|
v4 = *(*Tu16)(unsafe.Pointer(v2))
|
|
*(*Tu16)(unsafe.Pointer(v2)) = *(*Tu16)(unsafe.Pointer(v2)) + 1
|
|
**(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pNew)).FaLTerm + uintptr(v4)*8)) = pTop
|
|
**(**Tu32)(__ccgo_up(pNew + 48)) |= uint32(WHERE_TOP_LIMIT)
|
|
(*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnTop = uint16(1)
|
|
}
|
|
} else {
|
|
**(**Tu32)(__ccgo_up(pNew + 48)) |= libc.Uint32FromInt32(libc.Int32FromInt32(WHERE_COLUMN_RANGE) | libc.Int32FromInt32(WHERE_TOP_LIMIT))
|
|
(*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnTop = libc.Uint16FromInt32(nVecLen)
|
|
pTop = pTerm
|
|
if (*TWhereLoop)(unsafe.Pointer(pNew)).FwsFlags&uint32(WHERE_BTM_LIMIT) != uint32(0) {
|
|
v2 = **(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pNew)).FaLTerm + uintptr(libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pNew)).FnLTerm)-int32(2))*8))
|
|
} else {
|
|
v2 = uintptr(0)
|
|
}
|
|
pBtm = v2
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* At this point pNew->nOut is set to the number of rows expected to
|
|
** be visited by the index scan before considering term pTerm, or the
|
|
** values of nIn and nInMul. In other words, assuming that all
|
|
** "x IN(...)" terms are replaced with "x = ?". This block updates
|
|
** the value of pNew->nOut to account for pTerm (but not nIn/nInMul). */
|
|
if (*TWhereLoop)(unsafe.Pointer(pNew)).FwsFlags&uint32(WHERE_COLUMN_RANGE) != 0 {
|
|
/* Adjust nOut using stat4 data. Or, if there is no stat4
|
|
** data, using some other estimate. */
|
|
_whereRangeScanEst(tls, pParse, pBuilder, pBtm, pTop, pNew)
|
|
} else {
|
|
v2 = pNew + 24
|
|
*(*Tu16)(unsafe.Pointer(v2)) = *(*Tu16)(unsafe.Pointer(v2)) + 1
|
|
v4 = *(*Tu16)(unsafe.Pointer(v2))
|
|
nEq = libc.Int32FromUint16(v4)
|
|
if int32((*TWhereTerm)(unsafe.Pointer(pTerm)).FtruthProb) <= 0 && int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pProbe)).FaiColumn + uintptr(saved_nEq)*2))) >= 0 {
|
|
v2 = pNew + 22
|
|
*(*TLogEst)(unsafe.Pointer(v2)) = TLogEst(int32(*(*TLogEst)(unsafe.Pointer(v2))) + int32((*TWhereTerm)(unsafe.Pointer(pTerm)).FtruthProb))
|
|
v2 = pNew + 22
|
|
*(*TLogEst)(unsafe.Pointer(v2)) = TLogEst(int32(*(*TLogEst)(unsafe.Pointer(v2))) - nIn)
|
|
} else {
|
|
**(**TtRowcnt)(__ccgo_up(bp + 112)) = uint64(0)
|
|
if int32(nInMul) == 0 && (*TIndex)(unsafe.Pointer(pProbe)).FnSample != 0 && libc.Int32FromUint16((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnEq) <= (*TIndex)(unsafe.Pointer(pProbe)).FnSampleCol && (libc.Int32FromUint16(eOp)&int32(WO_IN) == 0 || (*TExpr)(unsafe.Pointer((*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr)).Fflags&uint32(EP_xIsSelect) == uint32(0)) && (*Tsqlite3)(unsafe.Pointer(db)).FdbOptFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_Stat4)) == uint32(0) {
|
|
pExpr1 = (*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr
|
|
if libc.Int32FromUint16(eOp)&(libc.Int32FromInt32(WO_EQ)|libc.Int32FromInt32(WO_ISNULL)|libc.Int32FromInt32(WO_IS)) != 0 {
|
|
rc = _whereEqualScanEst(tls, pParse, pBuilder, (*TExpr)(unsafe.Pointer(pExpr1)).FpRight, bp+112)
|
|
} else {
|
|
rc = _whereInScanEst(tls, pParse, pBuilder, *(*uintptr)(unsafe.Pointer(pExpr1 + 32)), bp+112)
|
|
}
|
|
if rc == int32(SQLITE_NOTFOUND) {
|
|
rc = SQLITE_OK
|
|
}
|
|
if rc != SQLITE_OK {
|
|
break
|
|
} /* Jump out of the pTerm loop */
|
|
if **(**TtRowcnt)(__ccgo_up(bp + 112)) != 0 {
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FnOut = _sqlite3LogEst(tls, **(**TtRowcnt)(__ccgo_up(bp + 112)))
|
|
if nEq == int32(1) && int32((*TWhereLoop)(unsafe.Pointer(pNew)).FnOut)+int32(10) > int32(**(**TLogEst)(__ccgo_up((*TIndex)(unsafe.Pointer(pProbe)).FaiRowLogEst))) {
|
|
v2 = pTerm + 18
|
|
*(*Tu16)(unsafe.Pointer(v2)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v2))) | libc.Int32FromInt32(TERM_HIGHTRUTH))
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FwtFlags)&int32(TERM_HEURTRUTH) != 0 {
|
|
/* If the term has previously been used with an assumption of
|
|
** higher selectivity, then set the flag to rerun the
|
|
** loop computations. */
|
|
v2 = pBuilder + 45
|
|
*(*uint8)(unsafe.Pointer(v2)) = uint8(int32(*(*uint8)(unsafe.Pointer(v2))) | libc.Int32FromInt32(SQLITE_BLDF2_2NDPASS))
|
|
}
|
|
}
|
|
if int32((*TWhereLoop)(unsafe.Pointer(pNew)).FnOut) > int32(saved_nOut) {
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FnOut = saved_nOut
|
|
}
|
|
v2 = pNew + 22
|
|
*(*TLogEst)(unsafe.Pointer(v2)) = TLogEst(int32(*(*TLogEst)(unsafe.Pointer(v2))) - nIn)
|
|
}
|
|
}
|
|
if **(**TtRowcnt)(__ccgo_up(bp + 112)) == uint64(0) {
|
|
v2 = pNew + 22
|
|
*(*TLogEst)(unsafe.Pointer(v2)) = TLogEst(int32(*(*TLogEst)(unsafe.Pointer(v2))) + (int32(**(**TLogEst)(__ccgo_up((*TIndex)(unsafe.Pointer(pProbe)).FaiRowLogEst + uintptr(nEq)*2))) - int32(**(**TLogEst)(__ccgo_up((*TIndex)(unsafe.Pointer(pProbe)).FaiRowLogEst + uintptr(nEq-int32(1))*2)))))
|
|
if libc.Int32FromUint16(eOp)&int32(WO_ISNULL) != 0 {
|
|
/* TUNING: If there is no likelihood() value, assume that a
|
|
** "col IS NULL" expression matches twice as many rows
|
|
** as (col=?). */
|
|
v2 = pNew + 22
|
|
*(*TLogEst)(unsafe.Pointer(v2)) = TLogEst(int32(*(*TLogEst)(unsafe.Pointer(v2))) + libc.Int32FromInt32(10))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* Set rCostIdx to the estimated cost of visiting selected rows in the
|
|
** index. The estimate is the sum of two values:
|
|
** 1. The cost of doing one search-by-key to find the first matching
|
|
** entry
|
|
** 2. Stepping forward in the index pNew->nOut times to find all
|
|
** additional matching entries.
|
|
*/
|
|
if int32(uint32(*(*uint16)(unsafe.Pointer(pProbe + 100))&0x3>>0)) == int32(SQLITE_IDXTYPE_IPK) {
|
|
/* The pProbe->szIdxRow is low for an IPK table since the interior
|
|
** pages are small. Thus szIdxRow gives a good estimate of seek cost.
|
|
** But the leaf pages are full-size, so pProbe->szIdxRow would badly
|
|
** under-estimate the scanning cost. */
|
|
rCostIdx = int16(int32((*TWhereLoop)(unsafe.Pointer(pNew)).FnOut) + int32(16))
|
|
} else {
|
|
rCostIdx = int16(int32((*TWhereLoop)(unsafe.Pointer(pNew)).FnOut) + int32(1) + int32(15)*int32((*TIndex)(unsafe.Pointer(pProbe)).FszIdxRow)/int32((*TTable)(unsafe.Pointer((*TSrcItem)(unsafe.Pointer(pSrc)).FpSTab)).FszTabRow))
|
|
}
|
|
rCostIdx = _sqlite3LogEstAdd(tls, rLogSize, rCostIdx)
|
|
/* Estimate the cost of running the loop. If all data is coming
|
|
** from the index, then this is just the cost of doing the index
|
|
** lookup and scan. But if some data is coming out of the main table,
|
|
** we also have to add in the cost of doing pNew->nOut searches to
|
|
** locate the row in the main table that corresponds to the index entry.
|
|
*/
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FrRun = rCostIdx
|
|
if (*TWhereLoop)(unsafe.Pointer(pNew)).FwsFlags&libc.Uint32FromInt32(libc.Int32FromInt32(WHERE_IDX_ONLY)|libc.Int32FromInt32(WHERE_IPK)|libc.Int32FromInt32(WHERE_EXPRIDX)) == uint32(0) {
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FrRun = _sqlite3LogEstAdd(tls, (*TWhereLoop)(unsafe.Pointer(pNew)).FrRun, int16(int32((*TWhereLoop)(unsafe.Pointer(pNew)).FnOut)+int32(16)))
|
|
}
|
|
nOutUnadjusted = (*TWhereLoop)(unsafe.Pointer(pNew)).FnOut
|
|
v2 = pNew + 20
|
|
*(*TLogEst)(unsafe.Pointer(v2)) = TLogEst(int32(*(*TLogEst)(unsafe.Pointer(v2))) + (int32(nInMul) + nIn))
|
|
v2 = pNew + 22
|
|
*(*TLogEst)(unsafe.Pointer(v2)) = TLogEst(int32(*(*TLogEst)(unsafe.Pointer(v2))) + (int32(nInMul) + nIn))
|
|
_whereLoopOutputAdjust(tls, (*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FpWC, pNew, rSize)
|
|
if int32(*(*uint32)(unsafe.Pointer(pSrc + 24 + 4))&0x40000>>18) != 0 {
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FnOut = 0
|
|
}
|
|
rc = _whereLoopInsert(tls, pBuilder, pNew)
|
|
if (*TWhereLoop)(unsafe.Pointer(pNew)).FwsFlags&uint32(WHERE_COLUMN_RANGE) != 0 {
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FnOut = saved_nOut
|
|
} else {
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FnOut = nOutUnadjusted
|
|
}
|
|
if (*TWhereLoop)(unsafe.Pointer(pNew)).FwsFlags&uint32(WHERE_TOP_LIMIT) == uint32(0) && libc.Int32FromUint16((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnEq) < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pProbe)).FnColumn) && (libc.Int32FromUint16((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnEq) < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pProbe)).FnKeyCol) || int32(uint32(*(*uint16)(unsafe.Pointer(pProbe + 100))&0x3>>0)) != int32(SQLITE_IDXTYPE_PRIMARYKEY)) {
|
|
if libc.Int32FromUint16((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnEq) > int32(3) {
|
|
_sqlite3ProgressCheck(tls, pParse)
|
|
}
|
|
_whereLoopAddBtreeIndex(tls, pBuilder, pSrc, pProbe, int16(int32(nInMul)+nIn))
|
|
}
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FnOut = saved_nOut
|
|
(*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FnRecValid = nRecValid
|
|
goto _1
|
|
_1:
|
|
;
|
|
pTerm = _whereScanNext(tls, bp)
|
|
}
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).Fprereq = saved_prereq
|
|
(*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnEq = saved_nEq
|
|
(*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnBtm = saved_nBtm
|
|
(*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnTop = saved_nTop
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FnSkip = saved_nSkip
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FwsFlags = saved_wsFlags
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FnOut = saved_nOut
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FnLTerm = saved_nLTerm
|
|
/* Consider using a skip-scan if there are no WHERE clause constraints
|
|
** available for the left-most terms of the index, and if the average
|
|
** number of repeats in the left-most terms is at least 18.
|
|
**
|
|
** The magic number 18 is selected on the basis that scanning 17 rows
|
|
** is almost always quicker than an index seek (even though if the index
|
|
** contains fewer than 2^17 rows we assume otherwise in other parts of
|
|
** the code). And, even if it is not, it should not be too much slower.
|
|
** On the other hand, the extra seeks could end up being significantly
|
|
** more expensive. */
|
|
if v22 = libc.Int32FromUint16(saved_nEq) == libc.Int32FromUint16(saved_nSkip) && libc.Int32FromUint16(saved_nEq)+int32(1) < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pProbe)).FnKeyCol) && libc.Int32FromUint16(saved_nEq) == libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pNew)).FnLTerm) && int32(uint32(*(*uint16)(unsafe.Pointer(pProbe + 100))&0x40>>6)) == 0 && int32(uint32(*(*uint16)(unsafe.Pointer(pProbe + 100))&0x80>>7)) != 0 && (*Tsqlite3)(unsafe.Pointer(db)).FdbOptFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_SkipScan)) == uint32(0) && int32(**(**TLogEst)(__ccgo_up((*TIndex)(unsafe.Pointer(pProbe)).FaiRowLogEst + uintptr(libc.Int32FromUint16(saved_nEq)+int32(1))*2))) >= int32(42) && int32(*(*uint32)(unsafe.Pointer(pSrc + 24 + 4))&0x40000>>18) == 0; v22 {
|
|
v21 = _whereLoopResize(tls, db, pNew, libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pNew)).FnLTerm)+int32(1))
|
|
rc = v21
|
|
}
|
|
if v22 && v21 == SQLITE_OK {
|
|
(*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnEq = (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnEq + 1
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FnSkip = (*TWhereLoop)(unsafe.Pointer(pNew)).FnSkip + 1
|
|
v2 = pNew + 52
|
|
v4 = *(*Tu16)(unsafe.Pointer(v2))
|
|
*(*Tu16)(unsafe.Pointer(v2)) = *(*Tu16)(unsafe.Pointer(v2)) + 1
|
|
**(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pNew)).FaLTerm + uintptr(v4)*8)) = uintptr(0)
|
|
**(**Tu32)(__ccgo_up(pNew + 48)) |= uint32(WHERE_SKIPSCAN)
|
|
nIter = int16(int32(**(**TLogEst)(__ccgo_up((*TIndex)(unsafe.Pointer(pProbe)).FaiRowLogEst + uintptr(saved_nEq)*2))) - int32(**(**TLogEst)(__ccgo_up((*TIndex)(unsafe.Pointer(pProbe)).FaiRowLogEst + uintptr(libc.Int32FromUint16(saved_nEq)+int32(1))*2))))
|
|
v2 = pNew + 22
|
|
*(*TLogEst)(unsafe.Pointer(v2)) = TLogEst(int32(*(*TLogEst)(unsafe.Pointer(v2))) - int32(nIter))
|
|
/* TUNING: Because uncertainties in the estimates for skip-scan queries,
|
|
** add a 1.375 fudge factor to make skip-scan slightly less likely. */
|
|
nIter = int16(int32(nIter) + libc.Int32FromInt32(5))
|
|
_whereLoopAddBtreeIndex(tls, pBuilder, pSrc, pProbe, int16(int32(nIter)+int32(nInMul)))
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FnOut = saved_nOut
|
|
(*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pNew + 24))).FnEq = saved_nEq
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FnSkip = saved_nSkip
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FwsFlags = saved_wsFlags
|
|
}
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Add all WhereLoop objects for a table of the join identified by
|
|
// ** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table.
|
|
// **
|
|
// ** If there are no LEFT or CROSS JOIN joins in the query, both mPrereq and
|
|
// ** mUnusable are set to 0. Otherwise, mPrereq is a mask of all FROM clause
|
|
// ** entries that occur before the virtual table in the FROM clause and are
|
|
// ** separated from it by at least one LEFT or CROSS JOIN. Similarly, the
|
|
// ** mUnusable mask contains all FROM clause entries that occur after the
|
|
// ** virtual table and are separated from it by at least one LEFT or
|
|
// ** CROSS JOIN.
|
|
// **
|
|
// ** For example, if the query were:
|
|
// **
|
|
// ** ... FROM t1, t2 LEFT JOIN t3, t4, vt CROSS JOIN t5, t6;
|
|
// **
|
|
// ** then mPrereq corresponds to (t1, t2) and mUnusable to (t5, t6).
|
|
// **
|
|
// ** All the tables in mPrereq must be scanned before the current virtual
|
|
// ** table. So any terms for which all prerequisites are satisfied by
|
|
// ** mPrereq may be specified as "usable" in all calls to xBestIndex.
|
|
// ** Conversely, all tables in mUnusable must be scanned after the current
|
|
// ** virtual table, so any terms for which the prerequisites overlap with
|
|
// ** mUnusable should always be configured as "not-usable" for xBestIndex.
|
|
// */
|
|
func _whereLoopAddVirtual(tls *libc.TLS, pBuilder uintptr, mPrereq TBitmask, mUnusable TBitmask) (r int32) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var i, iTerm, nConstraint, rc, seenZero, seenZeroNoIN int32
|
|
var mBest, mBestNoIn, mNext, mPrev, mThis, v1 TBitmask
|
|
var p, pNew, pParse, pSrc, pWC, pWInfo uintptr
|
|
var v2 bool
|
|
var _ /* bIn at bp+0 */ int32
|
|
var _ /* bRetry at bp+8 */ int32
|
|
var _ /* mNoOmit at bp+4 */ Tu16
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = i, iTerm, mBest, mBestNoIn, mNext, mPrev, mThis, nConstraint, p, pNew, pParse, pSrc, pWC, pWInfo, rc, seenZero, seenZeroNoIN, v1, v2
|
|
rc = SQLITE_OK
|
|
**(**int32)(__ccgo_up(bp + 8)) = 0 /* True to retry with LIMIT/OFFSET disabled */
|
|
pWInfo = (*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FpWInfo
|
|
pParse = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpParse
|
|
pWC = (*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FpWC
|
|
pNew = (*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FpNew
|
|
pSrc = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpTabList + 8 + uintptr((*TWhereLoop)(unsafe.Pointer(pNew)).FiTab)*80
|
|
p = _allocateIndexInfo(tls, pWInfo, pWC, mUnusable, pSrc, bp+4)
|
|
if p == uintptr(0) {
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FrSetup = 0
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FwsFlags = uint32(WHERE_VIRTUALTABLE)
|
|
(*TWhereLoop)(unsafe.Pointer(pNew)).FnLTerm = uint16(0)
|
|
libc.SetBitFieldPtr8Uint32(pNew+24+4, libc.Uint32FromInt32(0), 0, 0x1)
|
|
nConstraint = (*Tsqlite3_index_info)(unsafe.Pointer(p)).FnConstraint
|
|
if _whereLoopResize(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, pNew, nConstraint) != 0 {
|
|
_freeIndexInfo(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, p)
|
|
return int32(SQLITE_NOMEM)
|
|
}
|
|
/* First call xBestIndex() with all constraints usable. */
|
|
rc = _whereLoopAddVirtualOne(tls, pBuilder, mPrereq, libc.Uint64FromInt32(-libc.Int32FromInt32(1)), uint16(0), p, **(**Tu16)(__ccgo_up(bp + 4)), bp, bp+8)
|
|
if **(**int32)(__ccgo_up(bp + 8)) != 0 {
|
|
rc = _whereLoopAddVirtualOne(tls, pBuilder, mPrereq, libc.Uint64FromInt32(-libc.Int32FromInt32(1)), uint16(0), p, **(**Tu16)(__ccgo_up(bp + 4)), bp, uintptr(0))
|
|
}
|
|
/* If the call to xBestIndex() with all terms enabled produced a plan
|
|
** that does not require any source tables (IOW: a plan with mBest==0)
|
|
** and does not use an IN(...) operator, then there is no point in making
|
|
** any further calls to xBestIndex() since they will all return the same
|
|
** result (if the xBestIndex() implementation is sane). */
|
|
if v2 = rc == SQLITE_OK; v2 {
|
|
v1 = (*TWhereLoop)(unsafe.Pointer(pNew)).Fprereq & ^mPrereq
|
|
mBest = v1
|
|
}
|
|
if v2 && (v1 != uint64(0) || **(**int32)(__ccgo_up(bp)) != 0) {
|
|
seenZero = 0 /* True if a plan with no prereqs seen */
|
|
seenZeroNoIN = 0 /* Plan with no prereqs and no IN(...) seen */
|
|
mPrev = uint64(0)
|
|
mBestNoIn = uint64(0)
|
|
/* If the plan produced by the earlier call uses an IN(...) term, call
|
|
** xBestIndex again, this time with IN(...) terms disabled. */
|
|
if **(**int32)(__ccgo_up(bp)) != 0 {
|
|
rc = _whereLoopAddVirtualOne(tls, pBuilder, mPrereq, libc.Uint64FromInt32(-libc.Int32FromInt32(1)), uint16(WO_IN), p, **(**Tu16)(__ccgo_up(bp + 4)), bp, uintptr(0))
|
|
mBestNoIn = (*TWhereLoop)(unsafe.Pointer(pNew)).Fprereq & ^mPrereq
|
|
if mBestNoIn == uint64(0) {
|
|
seenZero = int32(1)
|
|
seenZeroNoIN = int32(1)
|
|
}
|
|
}
|
|
/* Call xBestIndex once for each distinct value of (prereqRight & ~mPrereq)
|
|
** in the set of terms that apply to the current virtual table. */
|
|
for rc == SQLITE_OK {
|
|
mNext = libc.Uint64FromInt32(-libc.Int32FromInt32(1))
|
|
i = 0
|
|
for {
|
|
if !(i < nConstraint) {
|
|
break
|
|
}
|
|
iTerm = (**(**Tsqlite3_index_constraint)(__ccgo_up((*Tsqlite3_index_info)(unsafe.Pointer(p)).FaConstraint + uintptr(i)*12))).FiTermOffset
|
|
mThis = (*TWhereTerm)(unsafe.Pointer(_termFromWhereClause(tls, pWC, iTerm))).FprereqRight & ^mPrereq
|
|
if mThis > mPrev && mThis < mNext {
|
|
mNext = mThis
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = i + 1
|
|
}
|
|
mPrev = mNext
|
|
if mNext == libc.Uint64FromInt32(-libc.Int32FromInt32(1)) {
|
|
break
|
|
}
|
|
if mNext == mBest || mNext == mBestNoIn {
|
|
continue
|
|
}
|
|
rc = _whereLoopAddVirtualOne(tls, pBuilder, mPrereq, mNext|mPrereq, uint16(0), p, **(**Tu16)(__ccgo_up(bp + 4)), bp, uintptr(0))
|
|
if (*TWhereLoop)(unsafe.Pointer(pNew)).Fprereq == mPrereq {
|
|
seenZero = int32(1)
|
|
if **(**int32)(__ccgo_up(bp)) == 0 {
|
|
seenZeroNoIN = int32(1)
|
|
}
|
|
}
|
|
}
|
|
/* If the calls to xBestIndex() in the above loop did not find a plan
|
|
** that requires no source tables at all (i.e. one guaranteed to be
|
|
** usable), make a call here with all source tables disabled */
|
|
if rc == SQLITE_OK && seenZero == 0 {
|
|
rc = _whereLoopAddVirtualOne(tls, pBuilder, mPrereq, mPrereq, uint16(0), p, **(**Tu16)(__ccgo_up(bp + 4)), bp, uintptr(0))
|
|
if **(**int32)(__ccgo_up(bp)) == 0 {
|
|
seenZeroNoIN = int32(1)
|
|
}
|
|
}
|
|
/* If the calls to xBestIndex() have so far failed to find a plan
|
|
** that requires no source tables at all and does not use an IN(...)
|
|
** operator, make a final call to obtain one here. */
|
|
if rc == SQLITE_OK && seenZeroNoIN == 0 {
|
|
rc = _whereLoopAddVirtualOne(tls, pBuilder, mPrereq, mPrereq, uint16(WO_IN), p, **(**Tu16)(__ccgo_up(bp + 4)), bp, uintptr(0))
|
|
}
|
|
}
|
|
_freeIndexInfo(tls, (*TParse)(unsafe.Pointer(pParse)).Fdb, p)
|
|
return rc
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return TRUE if X is a proper subset of Y but is of equal or less cost.
|
|
// ** In other words, return true if all constraints of X are also part of Y
|
|
// ** and Y has additional constraints that might speed the search that X lacks
|
|
// ** but the cost of running X is not more than the cost of running Y.
|
|
// **
|
|
// ** In other words, return true if the cost relationship between X and Y
|
|
// ** is inverted and needs to be adjusted.
|
|
// **
|
|
// ** Case 1:
|
|
// **
|
|
// ** (1a) X and Y use the same index.
|
|
// ** (1b) X has fewer == terms than Y
|
|
// ** (1c) Neither X nor Y use skip-scan
|
|
// ** (1d) X does not have a a greater cost than Y
|
|
// **
|
|
// ** Case 2:
|
|
// **
|
|
// ** (2a) X has the same or lower cost, or returns the same or fewer rows,
|
|
// ** than Y.
|
|
// ** (2b) X uses fewer WHERE clause terms than Y
|
|
// ** (2c) Every WHERE clause term used by X is also used by Y
|
|
// ** (2d) X skips at least as many columns as Y
|
|
// ** (2e) If X is a covering index, than Y is too
|
|
// */
|
|
func _whereLoopCheaperProperSubset(tls *libc.TLS, pX uintptr, pY uintptr) (r int32) {
|
|
var i, j int32
|
|
_, _ = i, j
|
|
if int32((*TWhereLoop)(unsafe.Pointer(pX)).FrRun) > int32((*TWhereLoop)(unsafe.Pointer(pY)).FrRun) && int32((*TWhereLoop)(unsafe.Pointer(pX)).FnOut) > int32((*TWhereLoop)(unsafe.Pointer(pY)).FnOut) {
|
|
return 0
|
|
} /* (1d) and (2a) */
|
|
if libc.Int32FromUint16((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pX + 24))).FnEq) < libc.Int32FromUint16((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pY + 24))).FnEq) && (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pX + 24))).FpIndex == (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pY + 24))).FpIndex && libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pX)).FnSkip) == 0 && libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pY)).FnSkip) == 0 {
|
|
return int32(1) /* Case 1 is true */
|
|
}
|
|
if libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pX)).FnLTerm)-libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pX)).FnSkip) >= libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pY)).FnLTerm)-libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pY)).FnSkip) {
|
|
return 0 /* (2b) */
|
|
}
|
|
if libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pY)).FnSkip) > libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pX)).FnSkip) {
|
|
return 0
|
|
} /* (2d) */
|
|
i = libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pX)).FnLTerm) - int32(1)
|
|
for {
|
|
if !(i >= 0) {
|
|
break
|
|
}
|
|
if **(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pX)).FaLTerm + uintptr(i)*8)) == uintptr(0) {
|
|
goto _1
|
|
}
|
|
j = libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pY)).FnLTerm) - int32(1)
|
|
for {
|
|
if !(j >= 0) {
|
|
break
|
|
}
|
|
if **(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pY)).FaLTerm + uintptr(j)*8)) == **(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pX)).FaLTerm + uintptr(i)*8)) {
|
|
break
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
j = j - 1
|
|
}
|
|
if j < 0 {
|
|
return 0
|
|
} /* (2c) */
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i - 1
|
|
}
|
|
if (*TWhereLoop)(unsafe.Pointer(pX)).FwsFlags&uint32(WHERE_IDX_ONLY) != uint32(0) && (*TWhereLoop)(unsafe.Pointer(pY)).FwsFlags&uint32(WHERE_IDX_ONLY) == uint32(0) {
|
|
return 0 /* (2e) */
|
|
}
|
|
return int32(1) /* Case 2 is true */
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Deallocate internal memory used by a WhereLoop object. Leave the
|
|
// ** object in an initialized state, as if it had been newly allocated.
|
|
// */
|
|
func _whereLoopClear(tls *libc.TLS, db uintptr, p uintptr) {
|
|
if (*TWhereLoop)(unsafe.Pointer(p)).FaLTerm != p+80 {
|
|
_sqlite3DbFreeNN(tls, db, (*TWhereLoop)(unsafe.Pointer(p)).FaLTerm)
|
|
(*TWhereLoop)(unsafe.Pointer(p)).FaLTerm = p + 80
|
|
(*TWhereLoop)(unsafe.Pointer(p)).FnLSlot = libc.Uint16FromInt32(libc.Int32FromUint64(libc.Uint64FromInt64(24) / libc.Uint64FromInt64(8)))
|
|
}
|
|
_whereLoopClearUnion(tls, db, p)
|
|
(*TWhereLoop)(unsafe.Pointer(p)).FnLTerm = uint16(0)
|
|
(*TWhereLoop)(unsafe.Pointer(p)).FwsFlags = uint32(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Search the list of WhereLoops in *ppPrev looking for one that can be
|
|
// ** replaced by pTemplate.
|
|
// **
|
|
// ** Return NULL if pTemplate does not belong on the WhereLoop list.
|
|
// ** In other words if pTemplate ought to be dropped from further consideration.
|
|
// **
|
|
// ** If pX is a WhereLoop that pTemplate can replace, then return the
|
|
// ** link that points to pX.
|
|
// **
|
|
// ** If pTemplate cannot replace any existing element of the list but needs
|
|
// ** to be added to the list as a new entry, then return a pointer to the
|
|
// ** tail of the list.
|
|
// */
|
|
func _whereLoopFindLesser(tls *libc.TLS, ppPrev uintptr, pTemplate uintptr) (r uintptr) {
|
|
var p uintptr
|
|
_ = p
|
|
p = **(**uintptr)(__ccgo_up(ppPrev))
|
|
for {
|
|
if !(p != 0) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint8((*TWhereLoop)(unsafe.Pointer(p)).FiTab) != libc.Int32FromUint8((*TWhereLoop)(unsafe.Pointer(pTemplate)).FiTab) || libc.Int32FromUint8((*TWhereLoop)(unsafe.Pointer(p)).FiSortIdx) != libc.Int32FromUint8((*TWhereLoop)(unsafe.Pointer(pTemplate)).FiSortIdx) {
|
|
/* If either the iTab or iSortIdx values for two WhereLoop are different
|
|
** then those WhereLoops need to be considered separately. Neither is
|
|
** a candidate to replace the other. */
|
|
goto _1
|
|
}
|
|
/* In the current implementation, the rSetup value is either zero
|
|
** or the cost of building an automatic index (NlogN) and the NlogN
|
|
** is the same for compatible WhereLoops. */
|
|
/* whereLoopAddBtree() always generates and inserts the automatic index
|
|
** case first. Hence compatible candidate WhereLoops never have a larger
|
|
** rSetup. Call this SETUP-INVARIANT */
|
|
/* Any loop using an application-defined index (or PRIMARY KEY or
|
|
** UNIQUE constraint) with one or more == constraints is better
|
|
** than an automatic index. Unless it is a skip-scan. */
|
|
if (*TWhereLoop)(unsafe.Pointer(p)).FwsFlags&uint32(WHERE_AUTO_INDEX) != uint32(0) && libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pTemplate)).FnSkip) == 0 && (*TWhereLoop)(unsafe.Pointer(pTemplate)).FwsFlags&uint32(WHERE_INDEXED) != uint32(0) && (*TWhereLoop)(unsafe.Pointer(pTemplate)).FwsFlags&uint32(WHERE_COLUMN_EQ) != uint32(0) && (*TWhereLoop)(unsafe.Pointer(p)).Fprereq&(*TWhereLoop)(unsafe.Pointer(pTemplate)).Fprereq == (*TWhereLoop)(unsafe.Pointer(pTemplate)).Fprereq {
|
|
break
|
|
}
|
|
/* If existing WhereLoop p is better than pTemplate, pTemplate can be
|
|
** discarded. WhereLoop p is better if:
|
|
** (1) p has no more dependencies than pTemplate, and
|
|
** (2) p has an equal or lower cost than pTemplate
|
|
*/
|
|
if (*TWhereLoop)(unsafe.Pointer(p)).Fprereq&(*TWhereLoop)(unsafe.Pointer(pTemplate)).Fprereq == (*TWhereLoop)(unsafe.Pointer(p)).Fprereq && int32((*TWhereLoop)(unsafe.Pointer(p)).FrSetup) <= int32((*TWhereLoop)(unsafe.Pointer(pTemplate)).FrSetup) && int32((*TWhereLoop)(unsafe.Pointer(p)).FrRun) <= int32((*TWhereLoop)(unsafe.Pointer(pTemplate)).FrRun) && int32((*TWhereLoop)(unsafe.Pointer(p)).FnOut) <= int32((*TWhereLoop)(unsafe.Pointer(pTemplate)).FnOut) {
|
|
return uintptr(0) /* Discard pTemplate */
|
|
}
|
|
/* If pTemplate is always better than p, then cause p to be overwritten
|
|
** with pTemplate. pTemplate is better than p if:
|
|
** (1) pTemplate has no more dependencies than p, and
|
|
** (2) pTemplate has an equal or lower cost than p.
|
|
*/
|
|
if (*TWhereLoop)(unsafe.Pointer(p)).Fprereq&(*TWhereLoop)(unsafe.Pointer(pTemplate)).Fprereq == (*TWhereLoop)(unsafe.Pointer(pTemplate)).Fprereq && int32((*TWhereLoop)(unsafe.Pointer(p)).FrRun) >= int32((*TWhereLoop)(unsafe.Pointer(pTemplate)).FrRun) && int32((*TWhereLoop)(unsafe.Pointer(p)).FnOut) >= int32((*TWhereLoop)(unsafe.Pointer(pTemplate)).FnOut) {
|
|
/* SETUP-INVARIANT above */
|
|
break /* Cause p to be overwritten by pTemplate */
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
ppPrev = p + 72
|
|
p = **(**uintptr)(__ccgo_up(ppPrev))
|
|
}
|
|
return ppPrev
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Convert bulk memory into a valid WhereLoop that can be passed
|
|
// ** to whereLoopClear harmlessly.
|
|
// */
|
|
func _whereLoopInit(tls *libc.TLS, p uintptr) {
|
|
(*TWhereLoop)(unsafe.Pointer(p)).FaLTerm = p + 80
|
|
(*TWhereLoop)(unsafe.Pointer(p)).FnLTerm = uint16(0)
|
|
(*TWhereLoop)(unsafe.Pointer(p)).FnLSlot = libc.Uint16FromInt32(libc.Int32FromUint64(libc.Uint64FromInt64(24) / libc.Uint64FromInt64(8)))
|
|
(*TWhereLoop)(unsafe.Pointer(p)).FwsFlags = uint32(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Loop pLoop is a WHERE_INDEXED level that uses at least one IN(...)
|
|
// ** operator. Return true if level pLoop is guaranteed to visit only one
|
|
// ** row for each key generated for the index.
|
|
// */
|
|
func _whereLoopIsOneRow(tls *libc.TLS, pLoop uintptr) (r int32) {
|
|
var ii int32
|
|
_ = ii
|
|
if (*TIndex)(unsafe.Pointer((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FpIndex)).FonError != 0 && libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pLoop)).FnSkip) == 0 && libc.Int32FromUint16((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FnEq) == libc.Int32FromUint16((*TIndex)(unsafe.Pointer((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FpIndex)).FnKeyCol) {
|
|
ii = 0
|
|
for {
|
|
if !(ii < libc.Int32FromUint16((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FnEq)) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(**(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pLoop)).FaLTerm + uintptr(ii)*8)))).FeOperator)&(libc.Int32FromInt32(WO_IS)|libc.Int32FromInt32(WO_ISNULL)) != 0 {
|
|
return 0
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
return int32(1)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Adjust the WhereLoop.nOut value downward to account for terms of the
|
|
// ** WHERE clause that reference the loop but which are not used by an
|
|
// ** index.
|
|
// *
|
|
// ** For every WHERE clause term that is not used by the index
|
|
// ** and which has a truth probability assigned by one of the likelihood(),
|
|
// ** likely(), or unlikely() SQL functions, reduce the estimated number
|
|
// ** of output rows by the probability specified.
|
|
// **
|
|
// ** TUNING: For every WHERE clause term that is not used by the index
|
|
// ** and which does not have an assigned truth probability, heuristics
|
|
// ** described below are used to try to estimate the truth probability.
|
|
// ** TODO --> Perhaps this is something that could be improved by better
|
|
// ** table statistics.
|
|
// **
|
|
// ** Heuristic 1: Estimate the truth probability as 93.75%. The 93.75%
|
|
// ** value corresponds to -1 in LogEst notation, so this means decrement
|
|
// ** the WhereLoop.nOut field for every such WHERE clause term.
|
|
// **
|
|
// ** Heuristic 2: If there exists one or more WHERE clause terms of the
|
|
// ** form "x==EXPR" and EXPR is not a constant 0 or 1, then make sure the
|
|
// ** final output row estimate is no greater than 1/4 of the total number
|
|
// ** of rows in the table. In other words, assume that x==EXPR will filter
|
|
// ** out at least 3 out of 4 rows. If EXPR is -1 or 0 or 1, then maybe the
|
|
// ** "x" column is boolean or else -1 or 0 or 1 is a common default value
|
|
// ** on the "x" column and so in that case only cap the output row estimate
|
|
// ** at 1/2 instead of 1/4.
|
|
// **
|
|
// ** Heuristic 3: If there is a LIKE or GLOB (or REGEXP or MATCH) operator
|
|
// ** with a large constant pattern, then reduce the size of the search
|
|
// ** space according to the length of the pattern, under the theory that
|
|
// ** longer patterns are less likely to match. This heuristic was added
|
|
// ** to give better output-row count estimates when preparing queries for
|
|
// ** the Join-Order Benchmarks. See forum thread 2026-01-30T09:57:54z
|
|
// */
|
|
func _whereLoopOutputAdjust(tls *libc.TLS, pWC uintptr, pLoop uintptr, nRow TLogEst) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var eOp, i, j, szPattern int32
|
|
var iReduce TLogEst
|
|
var notAllowed TBitmask
|
|
var pOpExpr, pRHS, pRight, pTerm, pX, v3 uintptr
|
|
var _ /* k at bp+0 */ int32
|
|
_, _, _, _, _, _, _, _, _, _, _, _ = eOp, i, iReduce, j, notAllowed, pOpExpr, pRHS, pRight, pTerm, pX, szPattern, v3
|
|
notAllowed = ^((*TWhereLoop)(unsafe.Pointer(pLoop)).Fprereq | (*TWhereLoop)(unsafe.Pointer(pLoop)).FmaskSelf)
|
|
iReduce = 0 /* pLoop->nOut should not exceed nRow-iReduce */
|
|
i = (*TWhereClause)(unsafe.Pointer(pWC)).FnBase
|
|
pTerm = (*TWhereClause)(unsafe.Pointer(pWC)).Fa
|
|
for {
|
|
if !(i > 0) {
|
|
break
|
|
}
|
|
if (*TWhereTerm)(unsafe.Pointer(pTerm)).FprereqAll¬Allowed != uint64(0) {
|
|
goto _1
|
|
}
|
|
if (*TWhereTerm)(unsafe.Pointer(pTerm)).FprereqAll&(*TWhereLoop)(unsafe.Pointer(pLoop)).FmaskSelf == uint64(0) {
|
|
goto _1
|
|
}
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FwtFlags)&int32(TERM_VIRTUAL) != 0 {
|
|
goto _1
|
|
}
|
|
j = libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pLoop)).FnLTerm) - int32(1)
|
|
for {
|
|
if !(j >= 0) {
|
|
break
|
|
}
|
|
pX = **(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pLoop)).FaLTerm + uintptr(j)*8))
|
|
if pX == uintptr(0) {
|
|
goto _2
|
|
}
|
|
if pX == pTerm {
|
|
break
|
|
}
|
|
if (*TWhereTerm)(unsafe.Pointer(pX)).FiParent >= 0 && (*TWhereClause)(unsafe.Pointer(pWC)).Fa+uintptr((*TWhereTerm)(unsafe.Pointer(pX)).FiParent)*56 == pTerm {
|
|
break
|
|
}
|
|
goto _2
|
|
_2:
|
|
;
|
|
j = j - 1
|
|
}
|
|
if j < 0 {
|
|
_sqlite3ProgressCheck(tls, (*TWhereInfo)(unsafe.Pointer((*TWhereClause)(unsafe.Pointer(pWC)).FpWInfo)).FpParse)
|
|
if (*TWhereLoop)(unsafe.Pointer(pLoop)).FmaskSelf == (*TWhereTerm)(unsafe.Pointer(pTerm)).FprereqAll {
|
|
/* If there are extra terms in the WHERE clause not used by an index
|
|
** that depend only on the table being scanned, and that will tend to
|
|
** cause many rows to be omitted, then mark that table as
|
|
** "self-culling".
|
|
**
|
|
** 2022-03-24: Self-culling only applies if either the extra terms
|
|
** are straight comparison operators that are non-true with NULL
|
|
** operand, or if the loop is not an OUTER JOIN.
|
|
*/
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator)&int32(0x3f) != 0 || libc.Int32FromUint8((*(*TSrcItem)(unsafe.Pointer((*TWhereInfo)(unsafe.Pointer((*TWhereClause)(unsafe.Pointer(pWC)).FpWInfo)).FpTabList + 8 + uintptr((*TWhereLoop)(unsafe.Pointer(pLoop)).FiTab)*80))).Ffg.Fjointype)&(libc.Int32FromInt32(JT_LEFT)|libc.Int32FromInt32(JT_LTORJ)) == 0 {
|
|
**(**Tu32)(__ccgo_up(pLoop + 48)) |= uint32(WHERE_SELFCULL)
|
|
}
|
|
}
|
|
if int32((*TWhereTerm)(unsafe.Pointer(pTerm)).FtruthProb) <= 0 {
|
|
/* If a truth probability is specified using the likelihood() hints,
|
|
** then use the probability provided by the application. */
|
|
v3 = pLoop + 22
|
|
*(*TLogEst)(unsafe.Pointer(v3)) = TLogEst(int32(*(*TLogEst)(unsafe.Pointer(v3))) + int32((*TWhereTerm)(unsafe.Pointer(pTerm)).FtruthProb))
|
|
} else {
|
|
/* In the absence of explicit truth probabilities, use heuristics to
|
|
** guess a reasonable truth probability. */
|
|
pOpExpr = (*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr
|
|
(*TWhereLoop)(unsafe.Pointer(pLoop)).FnOut = (*TWhereLoop)(unsafe.Pointer(pLoop)).FnOut - 1
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator)&(libc.Int32FromInt32(WO_EQ)|libc.Int32FromInt32(WO_IS)) != 0 && libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FwtFlags)&int32(TERM_HIGHTRUTH) == 0 {
|
|
pRight = (*TExpr)(unsafe.Pointer(pOpExpr)).FpRight
|
|
**(**int32)(__ccgo_up(bp)) = 0
|
|
if _sqlite3ExprIsInteger(tls, pRight, bp, uintptr(0)) != 0 && **(**int32)(__ccgo_up(bp)) >= -int32(1) && **(**int32)(__ccgo_up(bp)) <= int32(1) {
|
|
**(**int32)(__ccgo_up(bp)) = int32(10)
|
|
} else {
|
|
**(**int32)(__ccgo_up(bp)) = int32(20)
|
|
}
|
|
if int32(iReduce) < **(**int32)(__ccgo_up(bp)) {
|
|
v3 = pTerm + 18
|
|
*(*Tu16)(unsafe.Pointer(v3)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v3))) | libc.Int32FromInt32(TERM_HEURTRUTH))
|
|
iReduce = int16(**(**int32)(__ccgo_up(bp)))
|
|
}
|
|
} else {
|
|
if (*TExpr)(unsafe.Pointer(pOpExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_InfixFunc)) != uint32(0) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pOpExpr)).Fop) == int32(TK_FUNCTION) {
|
|
eOp = _sqlite3ExprIsLikeOperator(tls, pOpExpr)
|
|
if eOp > 0 {
|
|
pRHS = (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pOpExpr + 32)) + 8))).FpExpr
|
|
eOp = libc.BoolInt32(eOp == int32(SQLITE_INDEX_CONSTRAINT_LIKE))
|
|
szPattern = _estLikePatternLength(tls, pRHS, libc.Uint16FromInt32(eOp))
|
|
if szPattern > 0 {
|
|
v3 = pLoop + 22
|
|
*(*TLogEst)(unsafe.Pointer(v3)) = TLogEst(int32(*(*TLogEst)(unsafe.Pointer(v3))) - szPattern*libc.Int32FromInt32(2))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i - 1
|
|
pTerm += 56
|
|
}
|
|
if int32((*TWhereLoop)(unsafe.Pointer(pLoop)).FnOut) > int32(nRow)-int32(iReduce) {
|
|
(*TWhereLoop)(unsafe.Pointer(pLoop)).FnOut = int16(int32(nRow) - int32(iReduce))
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Return the N-th AND-connected subterm of pTerm. Or if pTerm is not
|
|
// ** a conjunction, then return just pTerm when N==0. If N is exceeds
|
|
// ** the number of available subterms, return NULL.
|
|
// */
|
|
func _whereNthSubterm(tls *libc.TLS, pTerm uintptr, N int32) (r uintptr) {
|
|
var v1 uintptr
|
|
_ = v1
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator) != int32(WO_AND) {
|
|
if N == 0 {
|
|
v1 = pTerm
|
|
} else {
|
|
v1 = uintptr(0)
|
|
}
|
|
return v1
|
|
}
|
|
if N < (*TWhereAndInfo)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pTerm + 32)))).Fwc.FnTerm {
|
|
return (*TWhereAndInfo)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pTerm + 32)))).Fwc.Fa + uintptr(N)*56
|
|
}
|
|
return uintptr(0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Implementation of the order-by-subquery optimization:
|
|
// **
|
|
// ** WhereLoop pLoop, which the iLoop-th term of the nested loop, is really
|
|
// ** a subquery or CTE that has an ORDER BY clause. See if any of the terms
|
|
// ** in the subquery ORDER BY clause will satisfy pOrderBy from the outer
|
|
// ** query. Mark off all satisfied terms (by setting bits in *pOBSat) and
|
|
// ** return TRUE if they do. If not, return false.
|
|
// **
|
|
// ** Example:
|
|
// **
|
|
// ** CREATE TABLE t1(a,b,c, PRIMARY KEY(a,b));
|
|
// ** CREATE TABLE t2(x,y);
|
|
// ** WITH t3(p,q) AS MATERIALIZED (SELECT x+y, x-y FROM t2 ORDER BY x+y)
|
|
// ** SELECT * FROM t3 JOIN t1 ON a=q ORDER BY p, b;
|
|
// **
|
|
// ** The CTE named "t3" comes out in the natural order of "p", so the first
|
|
// ** first them of "ORDER BY p,b" is satisfied by a sequential scan of "t3"
|
|
// ** and sorting only needs to occur on the second term "b".
|
|
// **
|
|
// ** Limitations:
|
|
// **
|
|
// ** (1) The optimization is not applied if the outer ORDER BY contains
|
|
// ** a COLLATE clause. The optimization might be applied if the
|
|
// ** outer ORDER BY uses NULLS FIRST, NULLS LAST, ASC, and/or DESC as
|
|
// ** long as the subquery ORDER BY does the same. But if the
|
|
// ** outer ORDER BY uses COLLATE, even a redundant COLLATE, the
|
|
// ** optimization is bypassed.
|
|
// **
|
|
// ** (2) The subquery ORDER BY terms must exactly match subquery result
|
|
// ** columns, including any COLLATE annotations. This routine relies
|
|
// ** on iOrderByCol to do matching between order by terms and result
|
|
// ** columns, and iOrderByCol will not be set if the result column
|
|
// ** and ORDER BY collations differ.
|
|
// **
|
|
// ** (3) The subquery and outer ORDER BY can be in opposite directions as
|
|
// ** long as the subquery is materialized. If the subquery is
|
|
// ** implemented as a co-routine, the sort orders must be in the same
|
|
// ** direction because there is no way to run a co-routine backwards.
|
|
// */
|
|
func _wherePathMatchSubqueryOB(tls *libc.TLS, pWInfo uintptr, pLoop uintptr, iLoop int32, iCur int32, pOrderBy uintptr, pRevMask uintptr, pOBSat uintptr) (r int32) {
|
|
var iOB, jSub int32
|
|
var pOBExpr, pSubOB uintptr
|
|
var rev, revIdx, sfOB, sfSub Tu8
|
|
_, _, _, _, _, _, _, _ = iOB, jSub, pOBExpr, pSubOB, rev, revIdx, sfOB, sfSub /* Index into pSubOB->a[] */
|
|
rev = uint8(0) /* True if iOB and jSub sort in opposite directions */
|
|
revIdx = uint8(0) /* Complete ORDER BY on the subquery */
|
|
pSubOB = (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FpOrderBy
|
|
iOB = 0
|
|
for {
|
|
if !(libc.Uint64FromInt32(1)<<iOB&**(**TBitmask)(__ccgo_up(pOBSat)) != uint64(0)) {
|
|
break
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
iOB = iOB + 1
|
|
}
|
|
jSub = 0
|
|
for {
|
|
if !(jSub < (*TExprList)(unsafe.Pointer(pSubOB)).FnExpr && iOB < (*TExprList)(unsafe.Pointer(pOrderBy)).FnExpr) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint16(*(*Tu16)(unsafe.Pointer(pSubOB + 8 + uintptr(jSub)*32 + 24))) == 0 {
|
|
break
|
|
}
|
|
pOBExpr = (*(*TExprList_item)(unsafe.Pointer(pOrderBy + 8 + uintptr(iOB)*32))).FpExpr
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pOBExpr)).Fop) != int32(TK_COLUMN) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pOBExpr)).Fop) != int32(TK_AGG_COLUMN) {
|
|
break
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pOBExpr)).FiTable != iCur {
|
|
break
|
|
}
|
|
if int32((*TExpr)(unsafe.Pointer(pOBExpr)).FiColumn) != libc.Int32FromUint16(*(*Tu16)(unsafe.Pointer(pSubOB + 8 + uintptr(jSub)*32 + 24)))-int32(1) {
|
|
break
|
|
}
|
|
if libc.Int32FromUint16((*TWhereInfo)(unsafe.Pointer(pWInfo)).FwctrlFlags)&int32(WHERE_GROUPBY) == 0 {
|
|
sfOB = (*(*TExprList_item)(unsafe.Pointer(pOrderBy + 8 + uintptr(iOB)*32))).Ffg.FsortFlags /* sortFlags for iOB */
|
|
sfSub = (*(*TExprList_item)(unsafe.Pointer(pSubOB + 8 + uintptr(jSub)*32))).Ffg.FsortFlags /* sortFlags for jSub */
|
|
if libc.Int32FromUint8(sfSub)&int32(KEYINFO_ORDER_BIGNULL) != libc.Int32FromUint8(sfOB)&int32(KEYINFO_ORDER_BIGNULL) {
|
|
break
|
|
}
|
|
revIdx = libc.Uint8FromInt32(libc.Int32FromUint8(sfSub) & int32(KEYINFO_ORDER_DESC))
|
|
if jSub > 0 {
|
|
if libc.Int32FromUint8(rev)^libc.Int32FromUint8(revIdx) != libc.Int32FromUint8(sfOB)&int32(KEYINFO_ORDER_DESC) {
|
|
break
|
|
}
|
|
} else {
|
|
rev = libc.Uint8FromInt32(libc.Int32FromUint8(revIdx) ^ libc.Int32FromUint8(sfOB)&int32(KEYINFO_ORDER_DESC))
|
|
if rev != 0 {
|
|
if (*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags&uint32(WHERE_COROUTINE) != uint32(0) {
|
|
/* Cannot run a co-routine in reverse order */
|
|
break
|
|
}
|
|
**(**TBitmask)(__ccgo_up(pRevMask)) |= libc.Uint64FromInt32(1) << iLoop
|
|
}
|
|
}
|
|
}
|
|
**(**TBitmask)(__ccgo_up(pOBSat)) |= libc.Uint64FromInt32(1) << iOB
|
|
goto _2
|
|
_2:
|
|
;
|
|
jSub = jSub + 1
|
|
iOB = iOB + 1
|
|
}
|
|
return libc.BoolInt32(jSub > 0)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Examine a WherePath (with the addition of the extra WhereLoop of the 6th
|
|
// ** parameters) to see if it outputs rows in the requested ORDER BY
|
|
// ** (or GROUP BY) without requiring a separate sort operation. Return N:
|
|
// **
|
|
// ** N>0: N terms of the ORDER BY clause are satisfied
|
|
// ** N==0: No terms of the ORDER BY clause are satisfied
|
|
// ** N<0: Unknown yet how many terms of ORDER BY might be satisfied.
|
|
// **
|
|
// ** Note that processing for WHERE_GROUPBY and WHERE_DISTINCTBY is not as
|
|
// ** strict. With GROUP BY and DISTINCT the only requirement is that
|
|
// ** equivalent rows appear immediately adjacent to one another. GROUP BY
|
|
// ** and DISTINCT do not require rows to appear in any particular order as long
|
|
// ** as equivalent rows are grouped together. Thus for GROUP BY and DISTINCT
|
|
// ** the pOrderBy terms can be matched in any order. With ORDER BY, the
|
|
// ** pOrderBy terms must be matched in strict left-to-right order.
|
|
// */
|
|
func _wherePathSatisfiesOrderBy(tls *libc.TLS, pWInfo uintptr, pOrderBy uintptr, pPath uintptr, wctrlFlags Tu16, nLoop Tu16, pLast uintptr, pRevMask uintptr) (r Ti8) {
|
|
bp := tls.Alloc(16)
|
|
defer tls.Free(16)
|
|
var bOnce, distinctColumns, isMatch, isOrderDistinct, rev, revIdx, revSet, v5 Tu8
|
|
var db, p, pColl, pColl1, pColl2, pIndex, pIxExpr, pLoop, pOBExpr, pParse, pTerm, pX, v4 uintptr
|
|
var eOp, eqOpMask, nColumn, nKeyCol, nOrderBy Tu16
|
|
var i, iColumn, iCur, iLoop, j int32
|
|
var m, mTerm, obDone, orderDistinctMask, ready TBitmask
|
|
var v11 uint64
|
|
var _ /* obSat at bp+0 */ TBitmask
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = bOnce, db, distinctColumns, eOp, eqOpMask, i, iColumn, iCur, iLoop, isMatch, isOrderDistinct, j, m, mTerm, nColumn, nKeyCol, nOrderBy, obDone, orderDistinctMask, p, pColl, pColl1, pColl2, pIndex, pIxExpr, pLoop, pOBExpr, pParse, pTerm, pX, ready, rev, revIdx, revSet, v11, v4, v5 /* A column number within table iCur */
|
|
pLoop = uintptr(0) /* The index associated with pLoop */
|
|
db = (*TParse)(unsafe.Pointer((*TWhereInfo)(unsafe.Pointer(pWInfo)).FpParse)).Fdb /* Database connection */
|
|
**(**TBitmask)(__ccgo_up(bp)) = uint64(0) /* Mask of inner loops */
|
|
/*
|
|
** We say the WhereLoop is "one-row" if it generates no more than one
|
|
** row of output. A WhereLoop is one-row if all of the following are true:
|
|
** (a) All index columns match with WHERE_COLUMN_EQ.
|
|
** (b) The index is unique
|
|
** Any WhereLoop with an WHERE_COLUMN_EQ constraint on the rowid is one-row.
|
|
** Every one-row WhereLoop will have the WHERE_ONEROW bit set in wsFlags.
|
|
**
|
|
** We say the WhereLoop is "order-distinct" if the set of columns from
|
|
** that WhereLoop that are in the ORDER BY clause are different for every
|
|
** row of the WhereLoop. Every one-row WhereLoop is automatically
|
|
** order-distinct. A WhereLoop that has no columns in the ORDER BY clause
|
|
** is not order-distinct. To be order-distinct is not quite the same as being
|
|
** UNIQUE since a UNIQUE column or index can have multiple rows that
|
|
** are NULL and NULL values are equivalent for the purpose of order-distinct.
|
|
** To be order-distinct, the columns must be UNIQUE and NOT NULL.
|
|
**
|
|
** The rowid for a table is always UNIQUE and NOT NULL so whenever the
|
|
** rowid appears in the ORDER BY clause, the corresponding WhereLoop is
|
|
** automatically order-distinct.
|
|
*/
|
|
if nLoop != 0 && (*Tsqlite3)(unsafe.Pointer(db)).FdbOptFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_OrderByIdxJoin)) != uint32(0) {
|
|
return 0
|
|
}
|
|
nOrderBy = libc.Uint16FromInt32((*TExprList)(unsafe.Pointer(pOrderBy)).FnExpr)
|
|
if libc.Int32FromUint16(nOrderBy) > libc.Int32FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(8))-libc.Int32FromInt32(1) {
|
|
return 0
|
|
} /* Cannot optimize overly large ORDER BYs */
|
|
isOrderDistinct = uint8(1)
|
|
obDone = libc.Uint64FromInt32(1)<<nOrderBy - uint64(1)
|
|
orderDistinctMask = uint64(0)
|
|
ready = uint64(0)
|
|
eqOpMask = libc.Uint16FromInt32(libc.Int32FromInt32(WO_EQ) | libc.Int32FromInt32(WO_IS) | libc.Int32FromInt32(WO_ISNULL))
|
|
if libc.Int32FromUint16(wctrlFlags)&(libc.Int32FromInt32(WHERE_ORDERBY_LIMIT)|libc.Int32FromInt32(WHERE_ORDERBY_MAX)|libc.Int32FromInt32(WHERE_ORDERBY_MIN)) != 0 {
|
|
eqOpMask = libc.Uint16FromInt32(int32(eqOpMask) | libc.Int32FromInt32(WO_IN))
|
|
}
|
|
iLoop = 0
|
|
for {
|
|
if !(isOrderDistinct != 0 && **(**TBitmask)(__ccgo_up(bp)) < obDone && iLoop <= libc.Int32FromUint16(nLoop)) {
|
|
break
|
|
}
|
|
if iLoop > 0 {
|
|
ready = ready | (*TWhereLoop)(unsafe.Pointer(pLoop)).FmaskSelf
|
|
}
|
|
if iLoop < libc.Int32FromUint16(nLoop) {
|
|
pLoop = **(**uintptr)(__ccgo_up((*TWherePath)(unsafe.Pointer(pPath)).FaLoop + uintptr(iLoop)*8))
|
|
if libc.Int32FromUint16(wctrlFlags)&int32(WHERE_ORDERBY_LIMIT) != 0 {
|
|
goto _1
|
|
}
|
|
} else {
|
|
pLoop = pLast
|
|
}
|
|
if (*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags&uint32(WHERE_VIRTUALTABLE) != 0 {
|
|
if (*(*struct {
|
|
FidxNum int32
|
|
F__ccgo4 uint8
|
|
FisOrdered Ti8
|
|
FomitMask Tu16
|
|
FidxStr uintptr
|
|
FmHandleIn Tu32
|
|
})(unsafe.Pointer(pLoop + 24))).FisOrdered != 0 && (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpOrderBy == pOrderBy {
|
|
**(**TBitmask)(__ccgo_up(bp)) = obDone
|
|
} else {
|
|
/* No further ORDER BY terms may be matched. So this call should
|
|
** return >=0, not -1. Clear isOrderDistinct to ensure it does so. */
|
|
isOrderDistinct = uint8(0)
|
|
}
|
|
break
|
|
}
|
|
iCur = (*(*TSrcItem)(unsafe.Pointer((*TWhereInfo)(unsafe.Pointer(pWInfo)).FpTabList + 8 + uintptr((*TWhereLoop)(unsafe.Pointer(pLoop)).FiTab)*80))).FiCursor
|
|
/* Mark off any ORDER BY term X that is a column in the table of
|
|
** the current loop for which there is term in the WHERE
|
|
** clause of the form X IS NULL or X=? that reference only outer
|
|
** loops.
|
|
*/
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint16(nOrderBy)) {
|
|
break
|
|
}
|
|
if libc.Uint64FromInt32(1)<<i&**(**TBitmask)(__ccgo_up(bp)) != 0 {
|
|
goto _2
|
|
}
|
|
pOBExpr = _sqlite3ExprSkipCollateAndLikely(tls, (*(*TExprList_item)(unsafe.Pointer(pOrderBy + 8 + uintptr(i)*32))).FpExpr)
|
|
if pOBExpr == uintptr(0) {
|
|
goto _2
|
|
}
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pOBExpr)).Fop) != int32(TK_COLUMN) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pOBExpr)).Fop) != int32(TK_AGG_COLUMN) {
|
|
goto _2
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pOBExpr)).FiTable != iCur {
|
|
goto _2
|
|
}
|
|
pTerm = _sqlite3WhereFindTerm(tls, pWInfo+104, iCur, int32((*TExpr)(unsafe.Pointer(pOBExpr)).FiColumn), ^ready, uint32(eqOpMask), uintptr(0))
|
|
if pTerm == uintptr(0) {
|
|
goto _2
|
|
}
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator) == int32(WO_IN) {
|
|
/* IN terms are only valid for sorting in the ORDER BY LIMIT
|
|
** optimization, and then only if they are actually used
|
|
** by the query plan */
|
|
j = 0
|
|
for {
|
|
if !(j < libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pLoop)).FnLTerm) && pTerm != **(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pLoop)).FaLTerm + uintptr(j)*8))) {
|
|
break
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
j = j + 1
|
|
}
|
|
if j >= libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pLoop)).FnLTerm) {
|
|
goto _2
|
|
}
|
|
}
|
|
if libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FeOperator)&(libc.Int32FromInt32(WO_EQ)|libc.Int32FromInt32(WO_IS)) != 0 && int32((*TExpr)(unsafe.Pointer(pOBExpr)).FiColumn) >= 0 {
|
|
pParse = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpParse
|
|
pColl1 = _sqlite3ExprNNCollSeq(tls, pParse, (*(*TExprList_item)(unsafe.Pointer(pOrderBy + 8 + uintptr(i)*32))).FpExpr)
|
|
pColl2 = _sqlite3ExprCompareCollSeq(tls, pParse, (*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr)
|
|
if pColl2 == uintptr(0) || _sqlite3StrICmp(tls, (*TCollSeq)(unsafe.Pointer(pColl1)).FzName, (*TCollSeq)(unsafe.Pointer(pColl2)).FzName) != 0 {
|
|
goto _2
|
|
}
|
|
}
|
|
**(**TBitmask)(__ccgo_up(bp)) = **(**TBitmask)(__ccgo_up(bp)) | libc.Uint64FromInt32(1)<<i
|
|
goto _2
|
|
_2:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if (*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags&uint32(WHERE_ONEROW) == uint32(0) {
|
|
if (*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags&uint32(WHERE_IPK) != 0 {
|
|
if (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FpOrderBy != 0 && (*Tsqlite3)(unsafe.Pointer(db)).FdbOptFlags&libc.Uint32FromInt32(libc.Int32FromInt32(SQLITE_OrderBySubq)) == uint32(0) && _wherePathMatchSubqueryOB(tls, pWInfo, pLoop, iLoop, iCur, pOrderBy, pRevMask, bp) != 0 {
|
|
nColumn = uint16(0)
|
|
isOrderDistinct = uint8(0)
|
|
} else {
|
|
nColumn = uint16(1)
|
|
}
|
|
pIndex = uintptr(0)
|
|
nKeyCol = uint16(0)
|
|
} else {
|
|
v4 = (*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FpIndex
|
|
pIndex = v4
|
|
if v4 == uintptr(0) || int32(uint32(*(*uint16)(unsafe.Pointer(pIndex + 100))&0x4>>2)) != 0 {
|
|
return 0
|
|
} else {
|
|
nKeyCol = (*TIndex)(unsafe.Pointer(pIndex)).FnKeyCol
|
|
nColumn = (*TIndex)(unsafe.Pointer(pIndex)).FnColumn
|
|
/* All relevant terms of the index must also be non-NULL in order
|
|
** for isOrderDistinct to be true. So the isOrderDistinct value
|
|
** computed here might be a false positive. Corrections will be
|
|
** made at tag-20210426-1 below */
|
|
isOrderDistinct = libc.BoolUint8(libc.Int32FromUint8((*TIndex)(unsafe.Pointer(pIndex)).FonError) != OE_None && (*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags&uint32(WHERE_SKIPSCAN) == uint32(0))
|
|
}
|
|
}
|
|
/* Loop through all columns of the index and deal with the ones
|
|
** that are not constrained by == or IN.
|
|
*/
|
|
v5 = libc.Uint8FromInt32(0)
|
|
revSet = v5
|
|
rev = v5
|
|
distinctColumns = uint8(0)
|
|
j = 0
|
|
for {
|
|
if !(j < libc.Int32FromUint16(nColumn)) {
|
|
break
|
|
}
|
|
bOnce = uint8(1) /* True to run the ORDER BY search loop */
|
|
if j < libc.Int32FromUint16((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FnEq) && j >= libc.Int32FromUint16((*TWhereLoop)(unsafe.Pointer(pLoop)).FnSkip) {
|
|
eOp = (*TWhereTerm)(unsafe.Pointer(**(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pLoop)).FaLTerm + uintptr(j)*8)))).FeOperator
|
|
/* Skip over == and IS and ISNULL terms. (Also skip IN terms when
|
|
** doing WHERE_ORDERBY_LIMIT processing). Except, IS and ISNULL
|
|
** terms imply that the index is not UNIQUE NOT NULL in which case
|
|
** the loop need to be marked as not order-distinct because it can
|
|
** have repeated NULL rows.
|
|
**
|
|
** If the current term is a column of an ((?,?) IN (SELECT...))
|
|
** expression for which the SELECT returns more than one column,
|
|
** check that it is the only column used by this loop. Otherwise,
|
|
** if it is one of two or more, none of the columns can be
|
|
** considered to match an ORDER BY term.
|
|
*/
|
|
if libc.Int32FromUint16(eOp)&libc.Int32FromUint16(eqOpMask) != 0 {
|
|
if libc.Int32FromUint16(eOp)&(libc.Int32FromInt32(WO_ISNULL)|libc.Int32FromInt32(WO_IS)) != 0 {
|
|
isOrderDistinct = uint8(0)
|
|
}
|
|
goto _6
|
|
} else {
|
|
if libc.Int32FromUint16(eOp)&int32(WO_IN) != 0 {
|
|
/* ALWAYS() justification: eOp is an equality operator due to the
|
|
** j<pLoop->u.btree.nEq constraint above. Any equality other
|
|
** than WO_IN is captured by the previous "if". So this one
|
|
** always has to be WO_IN. */
|
|
pX = (*TWhereTerm)(unsafe.Pointer(**(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pLoop)).FaLTerm + uintptr(j)*8)))).FpExpr
|
|
i = j + int32(1)
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FnEq)) {
|
|
break
|
|
}
|
|
if (*TWhereTerm)(unsafe.Pointer(**(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pLoop)).FaLTerm + uintptr(i)*8)))).FpExpr == pX {
|
|
bOnce = uint8(0)
|
|
break
|
|
}
|
|
goto _7
|
|
_7:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* Get the column number in the table (iColumn) and sort order
|
|
** (revIdx) for the j-th column of the index.
|
|
*/
|
|
if pIndex != 0 {
|
|
iColumn = int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pIndex)).FaiColumn + uintptr(j)*2)))
|
|
revIdx = libc.Uint8FromInt32(libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TIndex)(unsafe.Pointer(pIndex)).FaSortOrder + uintptr(j)))) & int32(KEYINFO_ORDER_DESC))
|
|
if iColumn == int32((*TTable)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pIndex)).FpTable)).FiPKey) {
|
|
iColumn = -int32(1)
|
|
}
|
|
} else {
|
|
iColumn = -int32(1)
|
|
revIdx = uint8(0)
|
|
}
|
|
/* An unconstrained column that might be NULL means that this
|
|
** WhereLoop is not well-ordered. tag-20210426-1
|
|
*/
|
|
if isOrderDistinct != 0 {
|
|
if iColumn >= 0 && j >= libc.Int32FromUint16((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FnEq) && int32(uint32(*(*uint8)(unsafe.Pointer((*TTable)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pIndex)).FpTable)).FaCol + uintptr(iColumn)*16 + 8))&0xf>>0)) == 0 {
|
|
isOrderDistinct = uint8(0)
|
|
}
|
|
if iColumn == -int32(2) {
|
|
isOrderDistinct = uint8(0)
|
|
}
|
|
}
|
|
/* Find the ORDER BY term that corresponds to the j-th column
|
|
** of the index and mark that ORDER BY term having been satisfied.
|
|
*/
|
|
isMatch = uint8(0)
|
|
i = 0
|
|
for {
|
|
if !(bOnce != 0 && i < libc.Int32FromUint16(nOrderBy)) {
|
|
break
|
|
}
|
|
if libc.Uint64FromInt32(1)<<i&**(**TBitmask)(__ccgo_up(bp)) != 0 {
|
|
goto _8
|
|
}
|
|
pOBExpr = _sqlite3ExprSkipCollateAndLikely(tls, (*(*TExprList_item)(unsafe.Pointer(pOrderBy + 8 + uintptr(i)*32))).FpExpr)
|
|
if pOBExpr == uintptr(0) {
|
|
goto _8
|
|
}
|
|
if libc.Int32FromUint16(wctrlFlags)&(libc.Int32FromInt32(WHERE_GROUPBY)|libc.Int32FromInt32(WHERE_DISTINCTBY)) == 0 {
|
|
bOnce = uint8(0)
|
|
}
|
|
if iColumn >= -int32(1) {
|
|
if libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pOBExpr)).Fop) != int32(TK_COLUMN) && libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pOBExpr)).Fop) != int32(TK_AGG_COLUMN) {
|
|
goto _8
|
|
}
|
|
if (*TExpr)(unsafe.Pointer(pOBExpr)).FiTable != iCur {
|
|
goto _8
|
|
}
|
|
if int32((*TExpr)(unsafe.Pointer(pOBExpr)).FiColumn) != iColumn {
|
|
goto _8
|
|
}
|
|
} else {
|
|
pIxExpr = (*(*TExprList_item)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pIndex)).FaColExpr + 8 + uintptr(j)*32))).FpExpr
|
|
if _sqlite3ExprCompareSkip(tls, pOBExpr, pIxExpr, iCur) != 0 {
|
|
goto _8
|
|
}
|
|
}
|
|
if iColumn != -int32(1) {
|
|
pColl = _sqlite3ExprNNCollSeq(tls, (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpParse, (*(*TExprList_item)(unsafe.Pointer(pOrderBy + 8 + uintptr(i)*32))).FpExpr)
|
|
if _sqlite3StrICmp(tls, (*TCollSeq)(unsafe.Pointer(pColl)).FzName, **(**uintptr)(__ccgo_up((*TIndex)(unsafe.Pointer(pIndex)).FazColl + uintptr(j)*8))) != 0 {
|
|
goto _8
|
|
}
|
|
}
|
|
if libc.Int32FromUint16(wctrlFlags)&int32(WHERE_DISTINCTBY) != 0 {
|
|
(*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FnDistinctCol = libc.Uint16FromInt32(j + int32(1))
|
|
}
|
|
isMatch = uint8(1)
|
|
break
|
|
goto _8
|
|
_8:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if isMatch != 0 && libc.Int32FromUint16(wctrlFlags)&int32(WHERE_GROUPBY) == 0 {
|
|
/* Make sure the sort order is compatible in an ORDER BY clause.
|
|
** Sort order is irrelevant for a GROUP BY clause. */
|
|
if revSet != 0 {
|
|
if libc.Int32FromUint8(rev)^libc.Int32FromUint8(revIdx) != libc.Int32FromUint8((*(*TExprList_item)(unsafe.Pointer(pOrderBy + 8 + uintptr(i)*32))).Ffg.FsortFlags)&int32(KEYINFO_ORDER_DESC) {
|
|
isMatch = uint8(0)
|
|
}
|
|
} else {
|
|
rev = libc.Uint8FromInt32(libc.Int32FromUint8(revIdx) ^ libc.Int32FromUint8((*(*TExprList_item)(unsafe.Pointer(pOrderBy + 8 + uintptr(i)*32))).Ffg.FsortFlags)&int32(KEYINFO_ORDER_DESC))
|
|
if rev != 0 {
|
|
**(**TBitmask)(__ccgo_up(pRevMask)) |= libc.Uint64FromInt32(1) << iLoop
|
|
}
|
|
revSet = uint8(1)
|
|
}
|
|
}
|
|
if isMatch != 0 && libc.Int32FromUint8((*(*TExprList_item)(unsafe.Pointer(pOrderBy + 8 + uintptr(i)*32))).Ffg.FsortFlags)&int32(KEYINFO_ORDER_BIGNULL) != 0 {
|
|
if j == libc.Int32FromUint16((*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FnEq) {
|
|
**(**Tu32)(__ccgo_up(pLoop + 48)) |= uint32(WHERE_BIGNULL_SORT)
|
|
} else {
|
|
isMatch = uint8(0)
|
|
}
|
|
}
|
|
if isMatch != 0 {
|
|
if iColumn == -int32(1) {
|
|
distinctColumns = uint8(1)
|
|
}
|
|
**(**TBitmask)(__ccgo_up(bp)) = **(**TBitmask)(__ccgo_up(bp)) | libc.Uint64FromInt32(1)<<i
|
|
} else {
|
|
/* No match found */
|
|
if j == 0 || j < libc.Int32FromUint16(nKeyCol) {
|
|
isOrderDistinct = uint8(0)
|
|
}
|
|
break
|
|
}
|
|
goto _6
|
|
_6:
|
|
;
|
|
j = j + 1
|
|
} /* end Loop over all index columns */
|
|
if distinctColumns != 0 {
|
|
isOrderDistinct = uint8(1)
|
|
}
|
|
} /* end-if not one-row */
|
|
/* Mark off any other ORDER BY terms that reference pLoop */
|
|
if isOrderDistinct != 0 {
|
|
orderDistinctMask = orderDistinctMask | (*TWhereLoop)(unsafe.Pointer(pLoop)).FmaskSelf
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint16(nOrderBy)) {
|
|
break
|
|
}
|
|
if libc.Uint64FromInt32(1)<<i&**(**TBitmask)(__ccgo_up(bp)) != 0 {
|
|
goto _9
|
|
}
|
|
p = (*(*TExprList_item)(unsafe.Pointer(pOrderBy + 8 + uintptr(i)*32))).FpExpr
|
|
mTerm = _sqlite3WhereExprUsage(tls, pWInfo+592, p)
|
|
if mTerm == uint64(0) && !(_sqlite3ExprIsConstant(tls, uintptr(0), p) != 0) {
|
|
goto _9
|
|
}
|
|
if mTerm & ^orderDistinctMask == uint64(0) {
|
|
**(**TBitmask)(__ccgo_up(bp)) = **(**TBitmask)(__ccgo_up(bp)) | libc.Uint64FromInt32(1)<<i
|
|
}
|
|
goto _9
|
|
_9:
|
|
;
|
|
i = i + 1
|
|
}
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
iLoop = iLoop + 1
|
|
} /* End the loop over all WhereLoops from outer-most down to inner-most */
|
|
if **(**TBitmask)(__ccgo_up(bp)) == obDone {
|
|
return libc.Int8FromUint16(nOrderBy)
|
|
}
|
|
if !(isOrderDistinct != 0) {
|
|
i = libc.Int32FromUint16(nOrderBy) - int32(1)
|
|
for {
|
|
if !(i > 0) {
|
|
break
|
|
}
|
|
if i < libc.Int32FromUint64(libc.Uint64FromInt64(8)*libc.Uint64FromInt32(8)) {
|
|
v11 = libc.Uint64FromInt32(1)<<i - uint64(1)
|
|
} else {
|
|
v11 = uint64(0)
|
|
}
|
|
m = v11
|
|
if **(**TBitmask)(__ccgo_up(bp))&m == m {
|
|
return int8(i)
|
|
}
|
|
goto _10
|
|
_10:
|
|
;
|
|
i = i - 1
|
|
}
|
|
return 0
|
|
}
|
|
return int8(-int32(1))
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Set the reverse-scan order mask to one for all tables in the query
|
|
// ** with the exception of MATERIALIZED common table expressions that have
|
|
// ** their own internal ORDER BY clauses.
|
|
// **
|
|
// ** This implements the PRAGMA reverse_unordered_selects=ON setting.
|
|
// ** (Also SQLITE_DBCONFIG_REVERSE_SCANORDER).
|
|
// */
|
|
func _whereReverseScanOrder(tls *libc.TLS, pWInfo uintptr) {
|
|
var ii int32
|
|
var pItem uintptr
|
|
_, _ = ii, pItem
|
|
ii = 0
|
|
for {
|
|
if !(ii < (*TSrcList)(unsafe.Pointer((*TWhereInfo)(unsafe.Pointer(pWInfo)).FpTabList)).FnSrc) {
|
|
break
|
|
}
|
|
pItem = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpTabList + 8 + uintptr(ii)*80
|
|
if !(int32(*(*uint32)(unsafe.Pointer(pItem + 24 + 4))&0x200>>9) != 0) || libc.Int32FromUint8((*TCteUse)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pItem + 56)))).FeM10d) != M10d_Yes || int32(*(*uint32)(unsafe.Pointer(pItem + 24 + 4))&0x4>>2) == 0 || (*TSelect)(unsafe.Pointer((*TSubquery)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(pItem + 72)))).FpSelect)).FpOrderBy == uintptr(0) {
|
|
**(**TBitmask)(__ccgo_up(pWInfo + 96)) |= libc.Uint64FromInt32(1) << ii
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
ii = ii + 1
|
|
}
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Most queries use only a single table (they are not joins) and have
|
|
// ** simple == constraints against indexed fields. This routine attempts
|
|
// ** to plan those simple cases using much less ceremony than the
|
|
// ** general-purpose query planner, and thereby yield faster sqlite3_prepare()
|
|
// ** times for the common case.
|
|
// **
|
|
// ** Return non-zero on success, if this query can be handled by this
|
|
// ** no-frills query planner. Return zero if this query needs the
|
|
// ** general-purpose query planner.
|
|
// */
|
|
func _whereShortCut(tls *libc.TLS, pBuilder uintptr) (r int32) {
|
|
bp := tls.Alloc(112)
|
|
defer tls.Free(112)
|
|
var iCur, j, opMask, v2 int32
|
|
var pIdx, pItem, pLoop, pTab, pTerm, pWC, pWInfo uintptr
|
|
var _ /* scan at bp+0 */ TWhereScan
|
|
_, _, _, _, _, _, _, _, _, _, _ = iCur, j, opMask, pIdx, pItem, pLoop, pTab, pTerm, pWC, pWInfo, v2
|
|
pWInfo = (*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FpWInfo
|
|
if libc.Int32FromUint16((*TWhereInfo)(unsafe.Pointer(pWInfo)).FwctrlFlags)&int32(WHERE_OR_SUBCLAUSE) != 0 {
|
|
return 0
|
|
}
|
|
pItem = (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpTabList + 8
|
|
pTab = (*TSrcItem)(unsafe.Pointer(pItem)).FpSTab
|
|
if libc.Int32FromUint8((*TTable)(unsafe.Pointer(pTab)).FeTabType) == int32(TABTYP_VTAB) {
|
|
return 0
|
|
}
|
|
if int32(*(*uint32)(unsafe.Pointer(pItem + 24 + 4))&0x2>>1) != 0 || int32(*(*uint32)(unsafe.Pointer(pItem + 24 + 4))&0x1>>0) != 0 {
|
|
return 0
|
|
}
|
|
iCur = (*TSrcItem)(unsafe.Pointer(pItem)).FiCursor
|
|
pWC = pWInfo + 104
|
|
pLoop = (*TWhereLoopBuilder)(unsafe.Pointer(pBuilder)).FpNew
|
|
(*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags = uint32(0)
|
|
(*TWhereLoop)(unsafe.Pointer(pLoop)).FnSkip = uint16(0)
|
|
pTerm = _whereScanInit(tls, bp, pWC, iCur, -int32(1), libc.Uint32FromInt32(libc.Int32FromInt32(WO_EQ)|libc.Int32FromInt32(WO_IS)), uintptr(0))
|
|
for pTerm != 0 && (*TWhereTerm)(unsafe.Pointer(pTerm)).FprereqRight != 0 {
|
|
pTerm = _whereScanNext(tls, bp)
|
|
}
|
|
if pTerm != 0 {
|
|
(*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags = libc.Uint32FromInt32(libc.Int32FromInt32(WHERE_COLUMN_EQ) | libc.Int32FromInt32(WHERE_IPK) | libc.Int32FromInt32(WHERE_ONEROW))
|
|
**(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pLoop)).FaLTerm)) = pTerm
|
|
(*TWhereLoop)(unsafe.Pointer(pLoop)).FnLTerm = uint16(1)
|
|
(*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FnEq = uint16(1)
|
|
/* TUNING: Cost of a rowid lookup is 10 */
|
|
(*TWhereLoop)(unsafe.Pointer(pLoop)).FrRun = int16(33) /* 33==sqlite3LogEst(10) */
|
|
} else {
|
|
pIdx = (*TTable)(unsafe.Pointer(pTab)).FpIndex
|
|
for {
|
|
if !(pIdx != 0) {
|
|
break
|
|
}
|
|
if !(libc.Int32FromUint8((*TIndex)(unsafe.Pointer(pIdx)).FonError) != libc.Int32FromInt32(OE_None)) || (*TIndex)(unsafe.Pointer(pIdx)).FpPartIdxWhere != uintptr(0) || libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol) > libc.Int32FromUint64(libc.Uint64FromInt64(24)/libc.Uint64FromInt64(8)) {
|
|
goto _1
|
|
}
|
|
if int32(uint32(*(*uint16)(unsafe.Pointer(pIdx + 100))&0x8>>3)) != 0 {
|
|
v2 = libc.Int32FromInt32(WO_EQ) | libc.Int32FromInt32(WO_IS)
|
|
} else {
|
|
v2 = int32(WO_EQ)
|
|
}
|
|
opMask = v2
|
|
j = 0
|
|
for {
|
|
if !(j < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol)) {
|
|
break
|
|
}
|
|
pTerm = _whereScanInit(tls, bp, pWC, iCur, j, libc.Uint32FromInt32(opMask), pIdx)
|
|
for pTerm != 0 && (*TWhereTerm)(unsafe.Pointer(pTerm)).FprereqRight != 0 {
|
|
pTerm = _whereScanNext(tls, bp)
|
|
}
|
|
if pTerm == uintptr(0) {
|
|
break
|
|
}
|
|
**(**uintptr)(__ccgo_up((*TWhereLoop)(unsafe.Pointer(pLoop)).FaLTerm + uintptr(j)*8)) = pTerm
|
|
goto _3
|
|
_3:
|
|
;
|
|
j = j + 1
|
|
}
|
|
if j != libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pIdx)).FnKeyCol) {
|
|
goto _1
|
|
}
|
|
(*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags = libc.Uint32FromInt32(libc.Int32FromInt32(WHERE_COLUMN_EQ) | libc.Int32FromInt32(WHERE_ONEROW) | libc.Int32FromInt32(WHERE_INDEXED))
|
|
if int32(uint32(*(*uint16)(unsafe.Pointer(pIdx + 100))&0x20>>5)) != 0 || (*TSrcItem)(unsafe.Pointer(pItem)).FcolUsed&(*TIndex)(unsafe.Pointer(pIdx)).FcolNotIdxed == uint64(0) {
|
|
**(**Tu32)(__ccgo_up(pLoop + 48)) |= uint32(WHERE_IDX_ONLY)
|
|
}
|
|
(*TWhereLoop)(unsafe.Pointer(pLoop)).FnLTerm = libc.Uint16FromInt32(j)
|
|
(*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FnEq = libc.Uint16FromInt32(j)
|
|
(*(*struct {
|
|
FnEq Tu16
|
|
FnBtm Tu16
|
|
FnTop Tu16
|
|
FnDistinctCol Tu16
|
|
FpIndex uintptr
|
|
FpOrderBy uintptr
|
|
})(unsafe.Pointer(pLoop + 24))).FpIndex = pIdx
|
|
/* TUNING: Cost of a unique index lookup is 15 */
|
|
(*TWhereLoop)(unsafe.Pointer(pLoop)).FrRun = int16(39) /* 39==sqlite3LogEst(15) */
|
|
break
|
|
goto _1
|
|
_1:
|
|
;
|
|
pIdx = (*TIndex)(unsafe.Pointer(pIdx)).FpNext
|
|
}
|
|
}
|
|
if (*TWhereLoop)(unsafe.Pointer(pLoop)).FwsFlags != 0 {
|
|
(*TWhereLoop)(unsafe.Pointer(pLoop)).FnOut = libc.Int16FromInt32(1)
|
|
(*(*TWhereLevel)(unsafe.Pointer(pWInfo + 856))).FpWLoop = pLoop
|
|
(*TWhereLoop)(unsafe.Pointer(pLoop)).FmaskSelf = uint64(1) /* sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); */
|
|
(*(*TWhereLevel)(unsafe.Pointer(pWInfo + 856))).FiTabCur = iCur
|
|
(*TWhereInfo)(unsafe.Pointer(pWInfo)).FnRowOut = int16(1)
|
|
if (*TWhereInfo)(unsafe.Pointer(pWInfo)).FpOrderBy != 0 {
|
|
(*TWhereInfo)(unsafe.Pointer(pWInfo)).FnOBSat = int8((*TExprList)(unsafe.Pointer((*TWhereInfo)(unsafe.Pointer(pWInfo)).FpOrderBy)).FnExpr)
|
|
}
|
|
if libc.Int32FromUint16((*TWhereInfo)(unsafe.Pointer(pWInfo)).FwctrlFlags)&int32(WHERE_WANT_DISTINCT) != 0 {
|
|
(*TWhereInfo)(unsafe.Pointer(pWInfo)).FeDistinct = uint8(WHERE_DISTINCT_UNIQUE)
|
|
}
|
|
if libc.Int32FromUint8((**(**TWhereScan)(__ccgo_up(bp))).FiEquiv) > int32(1) {
|
|
**(**Tu32)(__ccgo_up(pLoop + 48)) |= uint32(WHERE_TRANSCONS)
|
|
}
|
|
return int32(1)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /* Check to see if a partial index with pPartIndexWhere can be used
|
|
// ** in the current query. Return true if it can be and false if not.
|
|
// */
|
|
func _whereUsablePartialIndex(tls *libc.TLS, iTab int32, jointype Tu8, pWC uintptr, pWhere uintptr) (r int32) {
|
|
var i int32
|
|
var pExpr, pParse, pTerm uintptr
|
|
_, _, _, _ = i, pExpr, pParse, pTerm
|
|
if libc.Int32FromUint8(jointype)&int32(JT_LTORJ) != 0 {
|
|
return 0
|
|
}
|
|
pParse = (*TWhereInfo)(unsafe.Pointer((*TWhereClause)(unsafe.Pointer(pWC)).FpWInfo)).FpParse
|
|
for libc.Int32FromUint8((*TExpr)(unsafe.Pointer(pWhere)).Fop) == int32(TK_AND) {
|
|
if !(_whereUsablePartialIndex(tls, iTab, jointype, pWC, (*TExpr)(unsafe.Pointer(pWhere)).FpLeft) != 0) {
|
|
return 0
|
|
}
|
|
pWhere = (*TExpr)(unsafe.Pointer(pWhere)).FpRight
|
|
}
|
|
i = 0
|
|
pTerm = (*TWhereClause)(unsafe.Pointer(pWC)).Fa
|
|
for {
|
|
if !(i < (*TWhereClause)(unsafe.Pointer(pWC)).FnTerm) {
|
|
break
|
|
}
|
|
pExpr = (*TWhereTerm)(unsafe.Pointer(pTerm)).FpExpr
|
|
if (!((*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)) != libc.Uint32FromInt32(0)) || *(*int32)(unsafe.Pointer(pExpr + 52)) == iTab) && (libc.Int32FromUint8(jointype)&int32(JT_OUTER) == 0 || (*TExpr)(unsafe.Pointer(pExpr)).Fflags&libc.Uint32FromInt32(libc.Int32FromInt32(EP_OuterON)) != uint32(0)) && _sqlite3ExprImpliesExpr(tls, pParse, pExpr, pWhere, iTab) != 0 && !(_sqlite3ExprImpliesExpr(tls, pParse, pExpr, pWhere, -int32(1)) != 0) && libc.Int32FromUint16((*TWhereTerm)(unsafe.Pointer(pTerm)).FwtFlags)&int32(TERM_VNULL) == 0 {
|
|
return int32(1)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
pTerm += 56
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Generate VM code to invoke either xStep() (if bInverse is 0) or
|
|
// ** xInverse (if bInverse is non-zero) for each window function in the
|
|
// ** linked list starting at pMWin. Or, for built-in window functions
|
|
// ** that do not use the standard function API, generate the required
|
|
// ** inline VM code.
|
|
// **
|
|
// ** If argument csr is greater than or equal to 0, then argument reg is
|
|
// ** the first register in an array of registers guaranteed to be large
|
|
// ** enough to hold the array of arguments for each function. In this case
|
|
// ** the arguments are extracted from the current row of csr into the
|
|
// ** array of registers before invoking OP_AggStep or OP_AggInverse
|
|
// **
|
|
// ** Or, if csr is less than zero, then the array of registers at reg is
|
|
// ** already populated with all columns from the current row of the sub-query.
|
|
// **
|
|
// ** If argument regPartSize is non-zero, then it is a register containing the
|
|
// ** number of rows in the current partition.
|
|
// */
|
|
func _windowAggStep(tls *libc.TLS, p uintptr, pMWin uintptr, csr int32, bInverse int32, reg int32) {
|
|
var addrIf, addrIsNull, i, iEnd, iOp, nArg, regArg, regTmp, v2 int32
|
|
var pColl, pFunc, pOp, pParse, pWin, v uintptr
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = addrIf, addrIsNull, i, iEnd, iOp, nArg, pColl, pFunc, pOp, pParse, pWin, regArg, regTmp, v, v2
|
|
pParse = (*TWindowCodeArg)(unsafe.Pointer(p)).FpParse
|
|
v = _sqlite3GetVdbe(tls, pParse)
|
|
pWin = pMWin
|
|
for {
|
|
if !(pWin != 0) {
|
|
break
|
|
}
|
|
pFunc = (*TWindow)(unsafe.Pointer(pWin)).FpWFunc
|
|
if (*TWindow)(unsafe.Pointer(pWin)).FbExprArgs != 0 {
|
|
v2 = 0
|
|
} else {
|
|
v2 = _windowArgCount(tls, pWin)
|
|
}
|
|
nArg = v2
|
|
addrIf = 0
|
|
/* All OVER clauses in the same window function aggregate step must
|
|
** be the same. */
|
|
i = 0
|
|
for {
|
|
if !(i < nArg) {
|
|
break
|
|
}
|
|
if i != int32(1) || (*TFuncDef)(unsafe.Pointer(pFunc)).FzName != uintptr(unsafe.Pointer(&_nth_valueName)) {
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Column), csr, (*TWindow)(unsafe.Pointer(pWin)).FiArgCol+i, reg+i)
|
|
} else {
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Column), (*TWindow)(unsafe.Pointer(pMWin)).FiEphCsr, (*TWindow)(unsafe.Pointer(pWin)).FiArgCol+i, reg+i)
|
|
}
|
|
goto _3
|
|
_3:
|
|
;
|
|
i = i + 1
|
|
}
|
|
regArg = reg
|
|
if (*TWindow)(unsafe.Pointer(pWin)).FpFilter != 0 {
|
|
regTmp = _sqlite3GetTempReg(tls, pParse)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_Column), csr, (*TWindow)(unsafe.Pointer(pWin)).FiArgCol+nArg, regTmp)
|
|
addrIf = _sqlite3VdbeAddOp3(tls, v, int32(OP_IfNot), regTmp, 0, int32(1))
|
|
_sqlite3ReleaseTempReg(tls, pParse, regTmp)
|
|
}
|
|
if (*TWindow)(unsafe.Pointer(pMWin)).FregStartRowid == 0 && (*TFuncDef)(unsafe.Pointer(pFunc)).FfuncFlags&uint32(SQLITE_FUNC_MINMAX) != 0 && libc.Int32FromUint8((*TWindow)(unsafe.Pointer(pWin)).FeStart) != int32(TK_UNBOUNDED) {
|
|
addrIsNull = _sqlite3VdbeAddOp1(tls, v, int32(OP_IsNull), regArg)
|
|
if bInverse == 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_AddImm), (*TWindow)(unsafe.Pointer(pWin)).FregApp+int32(1), int32(1))
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_SCopy), regArg, (*TWindow)(unsafe.Pointer(pWin)).FregApp)
|
|
_sqlite3VdbeAddOp3(tls, v, int32(OP_MakeRecord), (*TWindow)(unsafe.Pointer(pWin)).FregApp, int32(2), (*TWindow)(unsafe.Pointer(pWin)).FregApp+int32(2))
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_IdxInsert), (*TWindow)(unsafe.Pointer(pWin)).FcsrApp, (*TWindow)(unsafe.Pointer(pWin)).FregApp+int32(2))
|
|
} else {
|
|
_sqlite3VdbeAddOp4Int(tls, v, int32(OP_SeekGE), (*TWindow)(unsafe.Pointer(pWin)).FcsrApp, 0, regArg, int32(1))
|
|
_sqlite3VdbeAddOp1(tls, v, int32(OP_Delete), (*TWindow)(unsafe.Pointer(pWin)).FcsrApp)
|
|
_sqlite3VdbeJumpHere(tls, v, _sqlite3VdbeCurrentAddr(tls, v)-int32(2))
|
|
}
|
|
_sqlite3VdbeJumpHere(tls, v, addrIsNull)
|
|
} else {
|
|
if (*TWindow)(unsafe.Pointer(pWin)).FregApp != 0 {
|
|
_sqlite3VdbeAddOp2(tls, v, int32(OP_AddImm), (*TWindow)(unsafe.Pointer(pWin)).FregApp+int32(1)-bInverse, int32(1))
|
|
} else {
|
|
if (*TFuncDef)(unsafe.Pointer(pFunc)).FxSFunc != __ccgo_fp(_noopStepFunc) {
|
|
if (*TWindow)(unsafe.Pointer(pWin)).FbExprArgs != 0 {
|
|
iOp = _sqlite3VdbeCurrentAddr(tls, v)
|
|
nArg = (*TExprList)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer((*TWindow)(unsafe.Pointer(pWin)).FpOwner + 32)))).FnExpr
|
|
regArg = _sqlite3GetTempRange(tls, pParse, nArg)
|
|
_sqlite3ExprCodeExprList(tls, pParse, *(*uintptr)(unsafe.Pointer((*TWindow)(unsafe.Pointer(pWin)).FpOwner + 32)), regArg, 0, uint8(0))
|
|
iEnd = _sqlite3VdbeCurrentAddr(tls, v)
|
|
for {
|
|
if !(iOp < iEnd) {
|
|
break
|
|
}
|
|
pOp = _sqlite3VdbeGetOp(tls, v, iOp)
|
|
if libc.Int32FromUint8((*TVdbeOp)(unsafe.Pointer(pOp)).Fopcode) == int32(OP_Column) && (*TVdbeOp)(unsafe.Pointer(pOp)).Fp1 == (*TWindow)(unsafe.Pointer(pMWin)).FiEphCsr {
|
|
(*TVdbeOp)(unsafe.Pointer(pOp)).Fp1 = csr
|
|
}
|
|
goto _4
|
|
_4:
|
|
;
|
|
iOp = iOp + 1
|
|
}
|
|
}
|
|
if (*TFuncDef)(unsafe.Pointer(pFunc)).FfuncFlags&uint32(SQLITE_FUNC_NEEDCOLL) != 0 {
|
|
pColl = _sqlite3ExprNNCollSeq(tls, pParse, (*(*TExprList_item)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer((*TWindow)(unsafe.Pointer(pWin)).FpOwner + 32)) + 8))).FpExpr)
|
|
_sqlite3VdbeAddOp4(tls, v, int32(OP_CollSeq), 0, 0, 0, pColl, -int32(2))
|
|
}
|
|
if bInverse != 0 {
|
|
v2 = int32(OP_AggInverse)
|
|
} else {
|
|
v2 = int32(OP_AggStep)
|
|
}
|
|
_sqlite3VdbeAddOp3(tls, v, v2, bInverse, regArg, (*TWindow)(unsafe.Pointer(pWin)).FregAccum)
|
|
_sqlite3VdbeAppendP4(tls, v, pFunc, -int32(8))
|
|
_sqlite3VdbeChangeP5(tls, v, libc.Uint16FromInt32(nArg))
|
|
if (*TWindow)(unsafe.Pointer(pWin)).FbExprArgs != 0 {
|
|
_sqlite3ReleaseTempRange(tls, pParse, regArg, nArg)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if addrIf != 0 {
|
|
_sqlite3VdbeJumpHere(tls, v, addrIf)
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
pWin = (*TWindow)(unsafe.Pointer(pWin)).FpNextWin
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Values that may be passed as the second argument to windowCodeOp().
|
|
*/
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Check to see if index pSrc is compatible as a source of data
|
|
// ** for index pDest in an insert transfer optimization. The rules
|
|
// ** for a compatible index:
|
|
// **
|
|
// ** * The index is over the same set of columns
|
|
// ** * The same DESC and ASC markings occurs on all columns
|
|
// ** * The same onError processing (OE_Abort, OE_Ignore, etc)
|
|
// ** * The same collating sequence on each column
|
|
// ** * The index has the exact same WHERE clause
|
|
// */
|
|
func _xferCompatibleIndex(tls *libc.TLS, pDest uintptr, pSrc uintptr) (r int32) {
|
|
var i int32
|
|
_ = i
|
|
if libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pDest)).FnKeyCol) != libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pSrc)).FnKeyCol) || libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pDest)).FnColumn) != libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pSrc)).FnColumn) {
|
|
return 0 /* Different number of columns */
|
|
}
|
|
if libc.Int32FromUint8((*TIndex)(unsafe.Pointer(pDest)).FonError) != libc.Int32FromUint8((*TIndex)(unsafe.Pointer(pSrc)).FonError) {
|
|
return 0 /* Different conflict resolution strategies */
|
|
}
|
|
i = 0
|
|
for {
|
|
if !(i < libc.Int32FromUint16((*TIndex)(unsafe.Pointer(pSrc)).FnKeyCol)) {
|
|
break
|
|
}
|
|
if int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pSrc)).FaiColumn + uintptr(i)*2))) != int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pDest)).FaiColumn + uintptr(i)*2))) {
|
|
return 0 /* Different columns indexed */
|
|
}
|
|
if int32(**(**Ti16)(__ccgo_up((*TIndex)(unsafe.Pointer(pSrc)).FaiColumn + uintptr(i)*2))) == -int32(2) {
|
|
if _sqlite3ExprCompare(tls, uintptr(0), (*(*TExprList_item)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pSrc)).FaColExpr + 8 + uintptr(i)*32))).FpExpr, (*(*TExprList_item)(unsafe.Pointer((*TIndex)(unsafe.Pointer(pDest)).FaColExpr + 8 + uintptr(i)*32))).FpExpr, -int32(1)) != 0 {
|
|
return 0 /* Different expressions in the index */
|
|
}
|
|
}
|
|
if libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TIndex)(unsafe.Pointer(pSrc)).FaSortOrder + uintptr(i)))) != libc.Int32FromUint8(**(**Tu8)(__ccgo_up((*TIndex)(unsafe.Pointer(pDest)).FaSortOrder + uintptr(i)))) {
|
|
return 0 /* Different sort orders */
|
|
}
|
|
if Xsqlite3_stricmp(tls, **(**uintptr)(__ccgo_up((*TIndex)(unsafe.Pointer(pSrc)).FazColl + uintptr(i)*8)), **(**uintptr)(__ccgo_up((*TIndex)(unsafe.Pointer(pDest)).FazColl + uintptr(i)*8))) != 0 {
|
|
return 0 /* Different collating sequences */
|
|
}
|
|
goto _1
|
|
_1:
|
|
;
|
|
i = i + 1
|
|
}
|
|
if _sqlite3ExprCompare(tls, uintptr(0), (*TIndex)(unsafe.Pointer(pSrc)).FpPartIdxWhere, (*TIndex)(unsafe.Pointer(pDest)).FpPartIdxWhere, -int32(1)) != 0 {
|
|
return 0 /* Different WHERE clauses */
|
|
}
|
|
/* If no test above fails then the indices must be compatible */
|
|
return int32(1)
|
|
}
|
|
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// ** Perform a shift action.
|
|
// */
|
|
func _yy_shift(tls *libc.TLS, yypParser uintptr, yyNewState uint16, yyMajor uint16, yyMinor TToken) {
|
|
var yytos uintptr
|
|
_ = yytos
|
|
(*TyyParser)(unsafe.Pointer(yypParser)).Fyytos += 24
|
|
yytos = (*TyyParser)(unsafe.Pointer(yypParser)).Fyytos
|
|
if yytos > (*TyyParser)(unsafe.Pointer(yypParser)).FyystackEnd {
|
|
if _yyGrowStack(tls, yypParser) != 0 {
|
|
(*TyyParser)(unsafe.Pointer(yypParser)).Fyytos -= 24
|
|
_yyStackOverflow(tls, yypParser)
|
|
return
|
|
}
|
|
yytos = (*TyyParser)(unsafe.Pointer(yypParser)).Fyytos
|
|
}
|
|
if libc.Int32FromUint16(yyNewState) > int32(YY_MAX_SHIFT) {
|
|
yyNewState = libc.Uint16FromInt32(int32(yyNewState) + (libc.Int32FromInt32(YY_MIN_REDUCE) - libc.Int32FromInt32(YY_MIN_SHIFTREDUCE)))
|
|
}
|
|
(*TyyStackEntry)(unsafe.Pointer(yytos)).Fstateno = yyNewState
|
|
(*TyyStackEntry)(unsafe.Pointer(yytos)).Fmajor = yyMajor
|
|
*(*TToken)(unsafe.Pointer(yytos + 8)) = yyMinor
|
|
}
|
|
|
|
func init() {
|
|
p := unsafe.Pointer(&_dotlockIoMethods)
|
|
*(*uintptr)(unsafe.Add(p, 8)) = __ccgo_fp(_dotlockClose)
|
|
*(*uintptr)(unsafe.Add(p, 16)) = __ccgo_fp(_unixRead)
|
|
*(*uintptr)(unsafe.Add(p, 24)) = __ccgo_fp(_unixWrite)
|
|
*(*uintptr)(unsafe.Add(p, 32)) = __ccgo_fp(_unixTruncate)
|
|
*(*uintptr)(unsafe.Add(p, 40)) = __ccgo_fp(_unixSync)
|
|
*(*uintptr)(unsafe.Add(p, 48)) = __ccgo_fp(_unixFileSize)
|
|
*(*uintptr)(unsafe.Add(p, 56)) = __ccgo_fp(_dotlockLock)
|
|
*(*uintptr)(unsafe.Add(p, 64)) = __ccgo_fp(_dotlockUnlock)
|
|
*(*uintptr)(unsafe.Add(p, 72)) = __ccgo_fp(_dotlockCheckReservedLock)
|
|
*(*uintptr)(unsafe.Add(p, 80)) = __ccgo_fp(_unixFileControl)
|
|
*(*uintptr)(unsafe.Add(p, 88)) = __ccgo_fp(_unixSectorSize)
|
|
*(*uintptr)(unsafe.Add(p, 96)) = __ccgo_fp(_unixDeviceCharacteristics)
|
|
*(*uintptr)(unsafe.Add(p, 112)) = __ccgo_fp(_unixShmLock)
|
|
*(*uintptr)(unsafe.Add(p, 120)) = __ccgo_fp(_unixShmBarrier)
|
|
*(*uintptr)(unsafe.Add(p, 128)) = __ccgo_fp(_unixShmUnmap)
|
|
*(*uintptr)(unsafe.Add(p, 136)) = __ccgo_fp(_unixFetch)
|
|
*(*uintptr)(unsafe.Add(p, 144)) = __ccgo_fp(_unixUnfetch)
|
|
}
|
|
|
|
func init() {
|
|
p := unsafe.Pointer(&_posixIoMethods)
|
|
*(*uintptr)(unsafe.Add(p, 8)) = __ccgo_fp(_unixClose)
|
|
*(*uintptr)(unsafe.Add(p, 16)) = __ccgo_fp(_unixRead)
|
|
*(*uintptr)(unsafe.Add(p, 24)) = __ccgo_fp(_unixWrite)
|
|
*(*uintptr)(unsafe.Add(p, 32)) = __ccgo_fp(_unixTruncate)
|
|
*(*uintptr)(unsafe.Add(p, 40)) = __ccgo_fp(_unixSync)
|
|
*(*uintptr)(unsafe.Add(p, 48)) = __ccgo_fp(_unixFileSize)
|
|
*(*uintptr)(unsafe.Add(p, 56)) = __ccgo_fp(_unixLock)
|
|
*(*uintptr)(unsafe.Add(p, 64)) = __ccgo_fp(_unixUnlock)
|
|
*(*uintptr)(unsafe.Add(p, 72)) = __ccgo_fp(_unixCheckReservedLock)
|
|
*(*uintptr)(unsafe.Add(p, 80)) = __ccgo_fp(_unixFileControl)
|
|
*(*uintptr)(unsafe.Add(p, 88)) = __ccgo_fp(_unixSectorSize)
|
|
*(*uintptr)(unsafe.Add(p, 96)) = __ccgo_fp(_unixDeviceCharacteristics)
|
|
*(*uintptr)(unsafe.Add(p, 104)) = __ccgo_fp(_unixShmMap)
|
|
*(*uintptr)(unsafe.Add(p, 112)) = __ccgo_fp(_unixShmLock)
|
|
*(*uintptr)(unsafe.Add(p, 120)) = __ccgo_fp(_unixShmBarrier)
|
|
*(*uintptr)(unsafe.Add(p, 128)) = __ccgo_fp(_unixShmUnmap)
|
|
*(*uintptr)(unsafe.Add(p, 136)) = __ccgo_fp(_unixFetch)
|
|
*(*uintptr)(unsafe.Add(p, 144)) = __ccgo_fp(_unixUnfetch)
|
|
}
|
|
|
|
func init() {
|
|
p := unsafe.Pointer(&_nolockIoMethods)
|
|
*(*uintptr)(unsafe.Add(p, 8)) = __ccgo_fp(_nolockClose)
|
|
*(*uintptr)(unsafe.Add(p, 16)) = __ccgo_fp(_unixRead)
|
|
*(*uintptr)(unsafe.Add(p, 24)) = __ccgo_fp(_unixWrite)
|
|
*(*uintptr)(unsafe.Add(p, 32)) = __ccgo_fp(_unixTruncate)
|
|
*(*uintptr)(unsafe.Add(p, 40)) = __ccgo_fp(_unixSync)
|
|
*(*uintptr)(unsafe.Add(p, 48)) = __ccgo_fp(_unixFileSize)
|
|
*(*uintptr)(unsafe.Add(p, 56)) = __ccgo_fp(_nolockLock)
|
|
*(*uintptr)(unsafe.Add(p, 64)) = __ccgo_fp(_nolockUnlock)
|
|
*(*uintptr)(unsafe.Add(p, 72)) = __ccgo_fp(_nolockCheckReservedLock)
|
|
*(*uintptr)(unsafe.Add(p, 80)) = __ccgo_fp(_unixFileControl)
|
|
*(*uintptr)(unsafe.Add(p, 88)) = __ccgo_fp(_unixSectorSize)
|
|
*(*uintptr)(unsafe.Add(p, 96)) = __ccgo_fp(_unixDeviceCharacteristics)
|
|
*(*uintptr)(unsafe.Add(p, 112)) = __ccgo_fp(_unixShmLock)
|
|
*(*uintptr)(unsafe.Add(p, 120)) = __ccgo_fp(_unixShmBarrier)
|
|
*(*uintptr)(unsafe.Add(p, 128)) = __ccgo_fp(_unixShmUnmap)
|
|
*(*uintptr)(unsafe.Add(p, 136)) = __ccgo_fp(_unixFetch)
|
|
*(*uintptr)(unsafe.Add(p, 144)) = __ccgo_fp(_unixUnfetch)
|
|
}
|